Back to index

lightning-sunbird  0.9+nobinonly
cmmfchal.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8 -*-*/
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape security libraries.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "cmmf.h"
00039 #include "cmmfi.h"
00040 #include "sechash.h"
00041 #include "genname.h"
00042 #include "pk11func.h"
00043 #include "cert.h"
00044 #include "secitem.h"
00045 #include "secmod.h"
00046 #include "keyhi.h"
00047 
00048 static int
00049 cmmf_create_witness_and_challenge(PRArenaPool     *poolp,
00050                               CMMFChallenge   *challenge,
00051                               long             inRandom,
00052                               SECItem         *senderDER,
00053                               SECKEYPublicKey *inPubKey,
00054                               void            *passwdArg)
00055 {
00056     SECItem       *encodedRandNum;
00057     SECItem        encodedRandStr = {siBuffer, NULL, 0};
00058     SECItem       *dummy;
00059     unsigned char *randHash, *senderHash, *encChal=NULL;
00060     unsigned       modulusLen = 0;
00061     SECStatus      rv = SECFailure;
00062     CMMFRand       randStr= { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}};
00063     PK11SlotInfo  *slot;
00064     PK11SymKey    *symKey = NULL;
00065     CK_OBJECT_HANDLE id;
00066     CERTSubjectPublicKeyInfo *spki = NULL;
00067 
00068     
00069     encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber,
00070                                       inRandom);
00071     encodedRandNum = &challenge->randomNumber;
00072     randHash   = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
00073     senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
00074     if (randHash == NULL) {
00075         goto loser;
00076     }
00077     rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data, 
00078                     (uint32)encodedRandNum->len);
00079     if (rv != SECSuccess) {
00080         goto loser;
00081     }
00082     rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data,
00083                     (uint32)senderDER->len);
00084     if (rv != SECSuccess) {
00085         goto loser;
00086     }
00087     challenge->witness.data = randHash;
00088     challenge->witness.len  = SHA1_LENGTH;
00089 
00090     randStr.integer    = *encodedRandNum;
00091     randStr.senderHash.data = senderHash;
00092     randStr.senderHash.len  = SHA1_LENGTH;
00093     dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr, 
00094                             CMMFRandTemplate);
00095     if (dummy != &encodedRandStr) {
00096         rv = SECFailure;
00097         goto loser;
00098     }
00099     /* XXXX Now I have to encrypt encodedRandStr and stash it away. */
00100     modulusLen = SECKEY_PublicKeyStrength(inPubKey);
00101     encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen);
00102     if (encChal == NULL) {
00103         rv = SECFailure;
00104         goto loser;
00105     }
00106     slot =PK11_GetBestSlot(CKM_RSA_PKCS, passwdArg);
00107     if (slot == NULL) {
00108         rv = SECFailure;
00109         goto loser;
00110     }
00111     id = PK11_ImportPublicKey(slot, inPubKey, PR_FALSE);
00112     /* In order to properly encrypt the data, we import as a symmetric
00113      * key, and then wrap that key.  That in essence encrypts the data.
00114      * This is the method recommended in the PK11 world in order
00115      * to prevent threading issues as well as breaking any other semantics
00116      * the PK11 libraries depend on.
00117      */
00118     symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated,
00119                             CKA_VALUE, &encodedRandStr, passwdArg);
00120     if (symKey == NULL) {
00121         rv = SECFailure;
00122        goto loser;
00123     }
00124     challenge->challenge.data = encChal;
00125     challenge->challenge.len  = modulusLen;
00126     rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey, 
00127                          &challenge->challenge);
00128     PK11_FreeSlot(slot);
00129     if (rv != SECSuccess) {
00130        goto loser;
00131     }
00132     rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER);
00133     crmf_get_public_value(inPubKey, &challenge->key);
00134     /* Fall through */
00135  loser:
00136     if (spki != NULL) {
00137         SECKEY_DestroySubjectPublicKeyInfo(spki);
00138     }
00139     if (encodedRandStr.data != NULL) {
00140         PORT_Free(encodedRandStr.data);
00141     }
00142     if (encodedRandNum != NULL) {
00143         SECITEM_FreeItem(encodedRandNum, PR_TRUE);
00144     }
00145     if (symKey != NULL) {
00146         PK11_FreeSymKey(symKey);
00147     }
00148     return rv;
00149 }
00150 
00151 static SECStatus
00152 cmmf_create_first_challenge(CMMFPOPODecKeyChallContent *challContent, 
00153                          long                        inRandom, 
00154                          SECItem                    *senderDER, 
00155                          SECKEYPublicKey            *inPubKey,
00156                          void                       *passwdArg)
00157 {
00158     SECOidData     *oidData;
00159     CMMFChallenge  *challenge;
00160     SECAlgorithmID *algId;
00161     PRArenaPool    *poolp;
00162     SECStatus       rv;
00163 
00164     oidData = SECOID_FindOIDByTag(SEC_OID_SHA1);
00165     if (oidData == NULL) {
00166         return SECFailure;
00167     }
00168     poolp = challContent->poolp;
00169     challenge = PORT_ArenaZNew(poolp, CMMFChallenge);
00170     if (challenge == NULL) {
00171         return SECFailure;
00172     }
00173     algId = challenge->owf = PORT_ArenaZNew(poolp, SECAlgorithmID);
00174     if (algId == NULL) {
00175         return SECFailure;
00176     }
00177     rv = SECITEM_CopyItem(poolp, &algId->algorithm, &oidData->oid);
00178     if (rv != SECSuccess) {
00179         return SECFailure;
00180     }
00181     rv = cmmf_create_witness_and_challenge(poolp, challenge, inRandom, 
00182                                       senderDER, inPubKey, passwdArg);
00183     challContent->challenges[0] = (rv == SECSuccess) ? challenge : NULL;
00184     challContent->numChallenges++;
00185     return rv ;
00186 }
00187 
00188 CMMFPOPODecKeyChallContent*
00189 CMMF_CreatePOPODecKeyChallContent (void)
00190 {
00191     PRArenaPool *poolp;
00192     CMMFPOPODecKeyChallContent *challContent;
00193 
00194     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
00195     if (poolp == NULL) {
00196         return NULL;
00197     }
00198     challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent);
00199     if (challContent == NULL) {
00200         PORT_FreeArena(poolp, PR_FALSE);
00201        return NULL;
00202     }
00203     challContent->poolp = poolp;
00204     return challContent;
00205 }
00206 
00207 SECStatus
00208 CMMF_POPODecKeyChallContentSetNextChallenge
00209                                     (CMMFPOPODecKeyChallContent *inDecKeyChall,
00210                                  long                        inRandom,
00211                                  CERTGeneralName            *inSender,
00212                                  SECKEYPublicKey            *inPubKey,
00213                                  void                       *passwdArg)
00214 {
00215     CMMFChallenge               *curChallenge;
00216     PRArenaPool                 *genNamePool = NULL, *poolp;
00217     SECStatus                    rv;
00218     SECItem                     *genNameDER;
00219     void                        *mark;
00220 
00221     PORT_Assert (inDecKeyChall != NULL &&
00222                inSender      != NULL &&
00223                inPubKey      != NULL);
00224 
00225     if (inDecKeyChall == NULL || 
00226        inSender      == NULL || inPubKey == NULL) {
00227         return SECFailure;
00228     }
00229     poolp = inDecKeyChall->poolp;
00230     mark = PORT_ArenaMark(poolp);
00231 
00232     genNamePool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
00233     genNameDER = CERT_EncodeGeneralName(inSender, NULL, genNamePool);
00234     if (genNameDER == NULL) {
00235         rv = SECFailure;
00236         goto loser;
00237     }
00238     if (inDecKeyChall->challenges == NULL) {
00239         inDecKeyChall->challenges =
00240            PORT_ArenaZNewArray(poolp, CMMFChallenge*,(CMMF_MAX_CHALLENGES+1));
00241        inDecKeyChall->numAllocated = CMMF_MAX_CHALLENGES;
00242     }
00243 
00244     if (inDecKeyChall->numChallenges >= inDecKeyChall->numAllocated) {
00245         rv = SECFailure;
00246         goto loser;
00247     }
00248 
00249     if (inDecKeyChall->numChallenges == 0) {
00250         rv = cmmf_create_first_challenge(inDecKeyChall, inRandom, 
00251                                     genNameDER, inPubKey, passwdArg);
00252     } else {
00253         curChallenge = PORT_ArenaZNew(poolp, CMMFChallenge);
00254        if (curChallenge == NULL) {
00255            rv = SECFailure;
00256            goto loser;
00257        }
00258        rv = cmmf_create_witness_and_challenge(poolp, curChallenge, inRandom, 
00259                                           genNameDER, inPubKey, 
00260                                           passwdArg);
00261        if (rv == SECSuccess) {
00262            inDecKeyChall->challenges[inDecKeyChall->numChallenges] =
00263                curChallenge;
00264            inDecKeyChall->numChallenges++;
00265        }
00266     }
00267     if (rv != SECSuccess) {
00268         goto loser;
00269     }
00270     PORT_ArenaUnmark(poolp, mark);
00271     PORT_FreeArena(genNamePool, PR_FALSE);
00272     return SECSuccess;
00273 
00274  loser:
00275     PORT_ArenaRelease(poolp, mark);
00276     if (genNamePool != NULL) {
00277         PORT_FreeArena(genNamePool, PR_FALSE);
00278     }
00279     PORT_Assert(rv != SECSuccess);
00280     return rv;
00281 }
00282 
00283 SECStatus
00284 CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp)
00285 {
00286     PORT_Assert(inDecKeyResp != NULL);
00287     if (inDecKeyResp != NULL && inDecKeyResp->poolp != NULL) {
00288         PORT_FreeArena(inDecKeyResp->poolp, PR_FALSE);
00289     }
00290     return SECSuccess;
00291 }
00292 
00293 int 
00294 CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont)
00295 {
00296     int numResponses = 0;
00297 
00298     PORT_Assert(inRespCont != NULL);
00299     if (inRespCont == NULL) {
00300         return 0;
00301     }
00302 
00303     while (inRespCont->responses[numResponses] != NULL) {
00304         numResponses ++;
00305     }
00306     return numResponses;
00307 }
00308 
00309 SECStatus
00310 CMMF_POPODecKeyRespContentGetResponse (CMMFPOPODecKeyRespContent *inRespCont,
00311                                    int                        inIndex,
00312                                    long                      *inDest)
00313 {
00314     PORT_Assert(inRespCont != NULL);
00315     
00316     if (inRespCont == NULL || inIndex < 0 || 
00317        inIndex >= CMMF_POPODecKeyRespContentGetNumResponses(inRespCont)) {
00318         return SECFailure;
00319     }
00320     *inDest = DER_GetInteger(inRespCont->responses[inIndex]);
00321     return (*inDest == -1) ? SECFailure : SECSuccess;
00322 }