tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

challcli.c (7412B)


      1 /* -*- Mode: C; tab-width: 8 -*-*/
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "cmmf.h"
      7 #include "cmmfi.h"
      8 #include "secitem.h"
      9 #include "pk11func.h"
     10 #include "secder.h"
     11 #include "sechash.h"
     12 
     13 CMMFPOPODecKeyChallContent *
     14 CMMF_CreatePOPODecKeyChallContentFromDER(const char *buf, long len)
     15 {
     16    PLArenaPool *poolp;
     17    CMMFPOPODecKeyChallContent *challContent;
     18    SECStatus rv;
     19 
     20    poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
     21    if (poolp == NULL) {
     22        return NULL;
     23    }
     24    challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent);
     25    if (challContent == NULL) {
     26        goto loser;
     27    }
     28    challContent->poolp = poolp;
     29    rv = SEC_ASN1Decode(poolp, challContent,
     30                        CMMFPOPODecKeyChallContentTemplate, buf, len);
     31    if (rv != SECSuccess) {
     32        goto loser;
     33    }
     34    if (challContent->challenges) {
     35        while (challContent->challenges[challContent->numChallenges] != NULL) {
     36            challContent->numChallenges++;
     37        }
     38        challContent->numAllocated = challContent->numChallenges;
     39    }
     40    return challContent;
     41 loser:
     42    if (poolp != NULL) {
     43        PORT_FreeArena(poolp, PR_FALSE);
     44    }
     45    return NULL;
     46 }
     47 
     48 int
     49 CMMF_POPODecKeyChallContentGetNumChallenges(CMMFPOPODecKeyChallContent *inKeyChallCont)
     50 {
     51    PORT_Assert(inKeyChallCont != NULL);
     52    if (inKeyChallCont == NULL) {
     53        return 0;
     54    }
     55    return inKeyChallCont->numChallenges;
     56 }
     57 
     58 SECItem *
     59 CMMF_POPODecKeyChallContentGetPublicValue(CMMFPOPODecKeyChallContent *inKeyChallCont,
     60                                          int inIndex)
     61 {
     62    PORT_Assert(inKeyChallCont != NULL);
     63    if (inKeyChallCont == NULL || (inIndex > inKeyChallCont->numChallenges - 1) ||
     64        inIndex < 0) {
     65        return NULL;
     66    }
     67    return SECITEM_DupItem(&inKeyChallCont->challenges[inIndex]->key);
     68 }
     69 
     70 static SECAlgorithmID *
     71 cmmf_get_owf(CMMFPOPODecKeyChallContent *inChalCont,
     72             int inIndex)
     73 {
     74    int i;
     75 
     76    for (i = inIndex; i >= 0; i--) {
     77        if (inChalCont->challenges[i]->owf != NULL) {
     78            return inChalCont->challenges[i]->owf;
     79        }
     80    }
     81    return NULL;
     82 }
     83 
     84 SECStatus
     85 CMMF_POPODecKeyChallContDecryptChallenge(CMMFPOPODecKeyChallContent *inChalCont,
     86                                         int inIndex,
     87                                         SECKEYPrivateKey *inPrivKey)
     88 {
     89    CMMFChallenge *challenge;
     90    SECItem *decryptedRand = NULL;
     91    PLArenaPool *poolp = NULL;
     92    SECAlgorithmID *owf;
     93    SECStatus rv = SECFailure;
     94    SECOidTag tag;
     95    CMMFRand randStr;
     96    SECItem hashItem;
     97    unsigned char hash[HASH_LENGTH_MAX];
     98 
     99    PORT_Assert(inChalCont != NULL && inPrivKey != NULL);
    100    if (inChalCont == NULL || inIndex < 0 || inIndex > inChalCont->numChallenges ||
    101        inPrivKey == NULL) {
    102        return SECFailure;
    103    }
    104 
    105    poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
    106    if (poolp == NULL) {
    107        goto loser;
    108    }
    109 
    110    challenge = inChalCont->challenges[inIndex];
    111    decryptedRand = SECITEM_AllocItem(poolp, NULL, challenge->challenge.len);
    112    if (decryptedRand == NULL) {
    113        goto loser;
    114    }
    115    rv = PK11_PrivDecryptPKCS1(inPrivKey, decryptedRand->data,
    116                               &decryptedRand->len, decryptedRand->len,
    117                               challenge->challenge.data, challenge->challenge.len);
    118    if (rv != SECSuccess) {
    119        goto loser;
    120    }
    121 
    122    rv = SEC_ASN1DecodeItem(poolp, &randStr, CMMFRandTemplate,
    123                            decryptedRand);
    124    if (rv != SECSuccess) {
    125        goto loser;
    126    }
    127    rv = SECFailure; /* Just so that when we do go to loser,
    128                      * I won't have to set it again.
    129                      */
    130    owf = cmmf_get_owf(inChalCont, inIndex);
    131    if (owf == NULL) {
    132        /* No hashing algorithm came with the challenges.  Can't verify */
    133        goto loser;
    134    }
    135    /* Verify the hashes in the challenge */
    136    tag = SECOID_FindOIDTag(&owf->algorithm);
    137    hashItem.len = HASH_ResultLenByOidTag(tag);
    138    if (!hashItem.len)
    139        goto loser; /* error code has been set */
    140 
    141    rv = PK11_HashBuf(tag, hash, randStr.integer.data, randStr.integer.len);
    142    if (rv != SECSuccess) {
    143        goto loser;
    144    }
    145    hashItem.data = hash;
    146    if (SECITEM_CompareItem(&hashItem, &challenge->witness) != SECEqual) {
    147        /* The hash for the data we decrypted doesn't match the hash provided
    148         * in the challenge.  Bail out.
    149         */
    150        PORT_SetError(SEC_ERROR_BAD_DATA);
    151        rv = SECFailure;
    152        goto loser;
    153    }
    154    rv = PK11_HashBuf(tag, hash, challenge->senderDER.data,
    155                      challenge->senderDER.len);
    156    if (rv != SECSuccess) {
    157        goto loser;
    158    }
    159    if (SECITEM_CompareItem(&hashItem, &randStr.senderHash) != SECEqual) {
    160        /* The hash for the data we decrypted doesn't match the hash provided
    161         * in the challenge.  Bail out.
    162         */
    163        PORT_SetError(SEC_ERROR_BAD_DATA);
    164        rv = SECFailure;
    165        goto loser;
    166    }
    167    /* All of the hashes have verified, so we can now store the integer away.*/
    168    rv = SECITEM_CopyItem(inChalCont->poolp, &challenge->randomNumber,
    169                          &randStr.integer);
    170 loser:
    171    if (poolp) {
    172        PORT_FreeArena(poolp, PR_FALSE);
    173    }
    174    return rv;
    175 }
    176 
    177 SECStatus
    178 CMMF_POPODecKeyChallContentGetRandomNumber(CMMFPOPODecKeyChallContent *inKeyChallCont,
    179                                           int inIndex,
    180                                           long *inDest)
    181 {
    182    CMMFChallenge *challenge;
    183 
    184    PORT_Assert(inKeyChallCont != NULL);
    185    if (inKeyChallCont == NULL || inIndex > 0 || inIndex >= inKeyChallCont->numChallenges) {
    186        return SECFailure;
    187    }
    188    challenge = inKeyChallCont->challenges[inIndex];
    189    if (challenge->randomNumber.data == NULL) {
    190        /* There is no random number here, nothing to see. */
    191        return SECFailure;
    192    }
    193    *inDest = DER_GetInteger(&challenge->randomNumber);
    194    return (*inDest == -1) ? SECFailure : SECSuccess;
    195 }
    196 
    197 SECStatus
    198 CMMF_EncodePOPODecKeyRespContent(long *inDecodedRand,
    199                                 int inNumRand,
    200                                 CRMFEncoderOutputCallback inCallback,
    201                                 void *inArg)
    202 {
    203    PLArenaPool *poolp;
    204    CMMFPOPODecKeyRespContent *response;
    205    SECItem *currItem;
    206    SECStatus rv = SECFailure;
    207    int i;
    208 
    209    poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
    210    if (poolp == NULL) {
    211        return SECFailure;
    212    }
    213    response = PORT_ArenaZNew(poolp, CMMFPOPODecKeyRespContent);
    214    if (response == NULL) {
    215        goto loser;
    216    }
    217    response->responses = PORT_ArenaZNewArray(poolp, SECItem *, inNumRand + 1);
    218    if (response->responses == NULL) {
    219        goto loser;
    220    }
    221    for (i = 0; i < inNumRand; i++) {
    222        currItem = response->responses[i] = PORT_ArenaZNew(poolp, SECItem);
    223        if (currItem == NULL) {
    224            goto loser;
    225        }
    226        currItem = SEC_ASN1EncodeInteger(poolp, currItem, inDecodedRand[i]);
    227        if (currItem == NULL) {
    228            goto loser;
    229        }
    230    }
    231    rv = cmmf_user_encode(response, inCallback, inArg,
    232                          CMMFPOPODecKeyRespContentTemplate);
    233 loser:
    234    if (poolp != NULL) {
    235        PORT_FreeArena(poolp, PR_FALSE);
    236    }
    237    return rv;
    238 }