Back to index

lightning-sunbird  0.9+nobinonly
challcli.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 "secitem.h"
00041 #include "pk11func.h"
00042 #include "secder.h"
00043 #include "sechash.h"
00044 
00045 CMMFPOPODecKeyChallContent*
00046 CMMF_CreatePOPODecKeyChallContentFromDER(const char *buf, long len)
00047 {
00048     PRArenaPool                *poolp;
00049     CMMFPOPODecKeyChallContent *challContent;
00050     SECStatus                   rv;
00051 
00052     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
00053     if (poolp == NULL) {
00054         return NULL;
00055     }
00056     challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent);
00057     if (challContent == NULL) {
00058         goto loser;
00059     }
00060     challContent->poolp = poolp;
00061     rv = SEC_ASN1Decode(poolp, challContent, 
00062                      CMMFPOPODecKeyChallContentTemplate, buf, len);
00063     if (rv != SECSuccess) {
00064         goto loser;
00065     }
00066     if (challContent->challenges) {
00067       while (challContent->challenges[challContent->numChallenges] != NULL) {
00068          challContent->numChallenges++;
00069       }
00070       challContent->numAllocated = challContent->numChallenges;
00071     }
00072     return challContent;
00073  loser:
00074     if (poolp != NULL) {
00075         PORT_FreeArena(poolp, PR_FALSE);
00076     }
00077     return NULL;
00078 }
00079 
00080 int
00081 CMMF_POPODecKeyChallContentGetNumChallenges 
00082                               (CMMFPOPODecKeyChallContent *inKeyChallCont)
00083 {
00084     PORT_Assert(inKeyChallCont != NULL);
00085     if (inKeyChallCont == NULL) {
00086         return 0;
00087     }
00088     return inKeyChallCont->numChallenges;
00089 }
00090 
00091 SECItem* 
00092 CMMF_POPODecKeyChallContentGetPublicValue
00093                                    (CMMFPOPODecKeyChallContent *inKeyChallCont,
00094                                 int                         inIndex)
00095 {
00096     PORT_Assert(inKeyChallCont != NULL);
00097     if (inKeyChallCont == NULL || (inIndex > inKeyChallCont->numChallenges-1)||
00098        inIndex < 0) {
00099         return NULL;
00100     }
00101     return SECITEM_DupItem(&inKeyChallCont->challenges[inIndex]->key);
00102 }
00103 
00104 static SECAlgorithmID*
00105 cmmf_get_owf(CMMFPOPODecKeyChallContent *inChalCont, 
00106             int                         inIndex)
00107 {
00108    int i;
00109    
00110    for (i=inIndex; i >= 0; i--) {
00111        if (inChalCont->challenges[i]->owf != NULL) {
00112           return inChalCont->challenges[i]->owf;
00113        }
00114    }
00115    return NULL;
00116 }
00117 
00118 SECStatus 
00119 CMMF_POPODecKeyChallContDecryptChallenge(CMMFPOPODecKeyChallContent *inChalCont,
00120                                     int                         inIndex,
00121                                     SECKEYPrivateKey           *inPrivKey)
00122 {
00123     CMMFChallenge  *challenge;
00124     SECItem        *decryptedRand=NULL;
00125     PRArenaPool    *poolp  = NULL;
00126     SECAlgorithmID *owf;
00127     SECStatus       rv     = SECFailure;
00128     SECOidTag       tag;
00129     CMMFRand        randStr;
00130     SECItem         hashItem;
00131     unsigned char   hash[HASH_LENGTH_MAX]; 
00132 
00133     PORT_Assert(inChalCont != NULL && inPrivKey != NULL);
00134     if (inChalCont == NULL || inIndex <0 || inIndex > inChalCont->numChallenges
00135        || inPrivKey == NULL){
00136         return SECFailure;
00137     }
00138 
00139     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
00140     if (poolp == NULL) {
00141         goto loser;
00142     }
00143 
00144     challenge = inChalCont->challenges[inIndex];
00145     decryptedRand = SECITEM_AllocItem(poolp, NULL, challenge->challenge.len);
00146     if (decryptedRand == NULL) {
00147         goto loser;
00148     }
00149     rv = PK11_PrivDecryptPKCS1(inPrivKey, decryptedRand->data, 
00150                      &decryptedRand->len, decryptedRand->len, 
00151                      challenge->challenge.data, challenge->challenge.len);
00152     if (rv != SECSuccess) {
00153         goto loser;
00154     }
00155 
00156     rv = SEC_ASN1DecodeItem(poolp, &randStr, CMMFRandTemplate,
00157                          decryptedRand); 
00158     if (rv != SECSuccess) {
00159         goto loser;
00160     }
00161     rv = SECFailure; /* Just so that when we do go to loser,
00162                     * I won't have to set it again.
00163                     */
00164     owf = cmmf_get_owf(inChalCont, inIndex);
00165     if (owf == NULL) {
00166         /* No hashing algorithm came with the challenges.  Can't verify */
00167         goto loser;
00168     }
00169     /* Verify the hashes in the challenge */
00170     tag = SECOID_FindOIDTag(&owf->algorithm);
00171     hashItem.len = HASH_ResultLenByOidTag(tag);
00172     if (!hashItem.len)
00173         goto loser;  /* error code has been set */
00174 
00175     rv = PK11_HashBuf(tag, hash, randStr.integer.data, randStr.integer.len);
00176     if (rv != SECSuccess) {
00177         goto loser;
00178     }
00179     hashItem.data = hash;
00180     if (SECITEM_CompareItem(&hashItem, &challenge->witness) != SECEqual) {
00181         /* The hash for the data we decrypted doesn't match the hash provided
00182         * in the challenge.  Bail out.
00183         */
00184        PORT_SetError(SEC_ERROR_BAD_DATA);
00185         rv = SECFailure;
00186        goto loser;
00187     }
00188     rv = PK11_HashBuf(tag, hash, challenge->senderDER.data, 
00189                     challenge->senderDER.len);
00190     if (rv != SECSuccess) {
00191         goto loser;
00192     }
00193     if (SECITEM_CompareItem(&hashItem, &randStr.senderHash) != SECEqual) {
00194         /* The hash for the data we decrypted doesn't match the hash provided
00195         * in the challenge.  Bail out.
00196         */
00197        PORT_SetError(SEC_ERROR_BAD_DATA);
00198         rv = SECFailure;
00199        goto loser;
00200     }
00201     /* All of the hashes have verified, so we can now store the integer away.*/
00202     rv = SECITEM_CopyItem(inChalCont->poolp, &challenge->randomNumber,
00203                        &randStr.integer);
00204  loser:
00205     if (poolp) {
00206        PORT_FreeArena(poolp, PR_FALSE);
00207     }
00208     return rv;
00209 }
00210 
00211 SECStatus
00212 CMMF_POPODecKeyChallContentGetRandomNumber
00213                                    (CMMFPOPODecKeyChallContent *inKeyChallCont,
00214                                 int                          inIndex,
00215                                 long                        *inDest)
00216 {
00217     CMMFChallenge *challenge;
00218     
00219     PORT_Assert(inKeyChallCont != NULL);
00220     if (inKeyChallCont == NULL || inIndex > 0 || inIndex >= 
00221        inKeyChallCont->numChallenges) {
00222         return SECFailure;
00223     }
00224     challenge = inKeyChallCont->challenges[inIndex];
00225     if (challenge->randomNumber.data == NULL) {
00226         /* There is no random number here, nothing to see. */
00227         return SECFailure;
00228     }
00229     *inDest = DER_GetInteger(&challenge->randomNumber);
00230     return (*inDest == -1) ? SECFailure : SECSuccess;
00231 }
00232 
00233 SECStatus 
00234 CMMF_EncodePOPODecKeyRespContent(long                     *inDecodedRand,
00235                              int                       inNumRand,
00236                              CRMFEncoderOutputCallback inCallback,
00237                              void                     *inArg)
00238 {
00239     PRArenaPool *poolp;
00240     CMMFPOPODecKeyRespContent *response;
00241     SECItem *currItem;
00242     SECStatus rv=SECFailure;
00243     int i;
00244 
00245     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
00246     if (poolp == NULL) {
00247         return SECFailure;
00248     }
00249     response = PORT_ArenaZNew(poolp, CMMFPOPODecKeyRespContent);
00250     if (response == NULL) {
00251         goto loser;
00252     }
00253     response->responses = PORT_ArenaZNewArray(poolp, SECItem*, inNumRand+1);
00254     if (response->responses == NULL) {
00255         goto loser;
00256     }
00257     for (i=0; i<inNumRand; i++) {
00258         currItem = response->responses[i] = PORT_ArenaZNew(poolp,SECItem);
00259        if (currItem == NULL) {
00260            goto loser;
00261        }
00262        currItem = SEC_ASN1EncodeInteger(poolp, currItem, inDecodedRand[i]);
00263        if (currItem == NULL) {
00264            goto loser;
00265        }
00266     }
00267     rv = cmmf_user_encode(response, inCallback, inArg,
00268                        CMMFPOPODecKeyRespContentTemplate);
00269  loser:
00270     if (poolp != NULL) {
00271         PORT_FreeArena(poolp, PR_FALSE);
00272     }
00273     return rv;
00274 }