tor-browser

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

cmmfchal.c (9299B)


      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 "sechash.h"
      9 #include "genname.h"
     10 #include "pk11func.h"
     11 #include "cert.h"
     12 #include "secitem.h"
     13 #include "secmod.h"
     14 #include "keyhi.h"
     15 
     16 static int
     17 cmmf_create_witness_and_challenge(PLArenaPool *poolp,
     18                                  CMMFChallenge *challenge,
     19                                  long inRandom,
     20                                  SECItem *senderDER,
     21                                  SECKEYPublicKey *inPubKey,
     22                                  void *passwdArg)
     23 {
     24    SECItem *encodedRandNum;
     25    SECItem encodedRandStr = { siBuffer, NULL, 0 };
     26    SECItem *dummy;
     27    unsigned char *randHash, *senderHash, *encChal = NULL;
     28    unsigned modulusLen = 0;
     29    SECStatus rv = SECFailure;
     30    CMMFRand randStr = { { siBuffer, NULL, 0 }, { siBuffer, NULL, 0 } };
     31    PK11SlotInfo *slot;
     32    PK11SymKey *symKey = NULL;
     33    CERTSubjectPublicKeyInfo *spki = NULL;
     34 
     35    encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber,
     36                                           inRandom);
     37    if (!encodedRandNum) {
     38        goto loser;
     39    }
     40    randHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
     41    senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
     42    if (randHash == NULL) {
     43        goto loser;
     44    }
     45    rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data,
     46                      (PRUint32)encodedRandNum->len);
     47    if (rv != SECSuccess) {
     48        goto loser;
     49    }
     50    rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data,
     51                      (PRUint32)senderDER->len);
     52    if (rv != SECSuccess) {
     53        goto loser;
     54    }
     55    challenge->witness.data = randHash;
     56    challenge->witness.len = SHA1_LENGTH;
     57 
     58    randStr.integer = *encodedRandNum;
     59    randStr.senderHash.data = senderHash;
     60    randStr.senderHash.len = SHA1_LENGTH;
     61    dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr,
     62                               CMMFRandTemplate);
     63    if (dummy != &encodedRandStr) {
     64        rv = SECFailure;
     65        goto loser;
     66    }
     67    /* XXXX Now I have to encrypt encodedRandStr and stash it away. */
     68    modulusLen = SECKEY_PublicKeyStrength(inPubKey);
     69    encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen);
     70    if (encChal == NULL) {
     71        rv = SECFailure;
     72        goto loser;
     73    }
     74    slot = PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg);
     75    if (slot == NULL) {
     76        rv = SECFailure;
     77        goto loser;
     78    }
     79    (void)PK11_ImportPublicKey(slot, inPubKey, PR_FALSE);
     80    /* In order to properly encrypt the data, we import as a symmetric
     81     * key, and then wrap that key.  That in essence encrypts the data.
     82     * This is the method recommended in the PK11 world in order
     83     * to prevent threading issues as well as breaking any other semantics
     84     * the PK11 libraries depend on.
     85     */
     86    symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated,
     87                               CKA_VALUE, &encodedRandStr, passwdArg);
     88    if (symKey == NULL) {
     89        rv = SECFailure;
     90        goto loser;
     91    }
     92    challenge->challenge.data = encChal;
     93    challenge->challenge.len = modulusLen;
     94    rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey,
     95                            &challenge->challenge);
     96    PK11_FreeSlot(slot);
     97    if (rv != SECSuccess) {
     98        goto loser;
     99    }
    100    rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER);
    101    crmf_get_public_value(inPubKey, &challenge->key);
    102 /* Fall through */
    103 loser:
    104    if (spki != NULL) {
    105        SECKEY_DestroySubjectPublicKeyInfo(spki);
    106    }
    107    if (encodedRandStr.data != NULL) {
    108        PORT_Free(encodedRandStr.data);
    109    }
    110    if (encodedRandNum != NULL) {
    111        SECITEM_FreeItem(encodedRandNum, PR_TRUE);
    112    }
    113    if (symKey != NULL) {
    114        PK11_FreeSymKey(symKey);
    115    }
    116    return rv;
    117 }
    118 
    119 static SECStatus
    120 cmmf_create_first_challenge(CMMFPOPODecKeyChallContent *challContent,
    121                            long inRandom,
    122                            SECItem *senderDER,
    123                            SECKEYPublicKey *inPubKey,
    124                            void *passwdArg)
    125 {
    126    SECOidData *oidData;
    127    CMMFChallenge *challenge;
    128    SECAlgorithmID *algId;
    129    PLArenaPool *poolp;
    130    SECStatus rv;
    131 
    132    oidData = SECOID_FindOIDByTag(SEC_OID_SHA1);
    133    if (oidData == NULL) {
    134        return SECFailure;
    135    }
    136    poolp = challContent->poolp;
    137    challenge = PORT_ArenaZNew(poolp, CMMFChallenge);
    138    if (challenge == NULL) {
    139        return SECFailure;
    140    }
    141    algId = challenge->owf = PORT_ArenaZNew(poolp, SECAlgorithmID);
    142    if (algId == NULL) {
    143        return SECFailure;
    144    }
    145    rv = SECITEM_CopyItem(poolp, &algId->algorithm, &oidData->oid);
    146    if (rv != SECSuccess) {
    147        return SECFailure;
    148    }
    149    rv = cmmf_create_witness_and_challenge(poolp, challenge, inRandom,
    150                                           senderDER, inPubKey, passwdArg);
    151    challContent->challenges[0] = (rv == SECSuccess) ? challenge : NULL;
    152    challContent->numChallenges++;
    153    return rv;
    154 }
    155 
    156 CMMFPOPODecKeyChallContent *
    157 CMMF_CreatePOPODecKeyChallContent(void)
    158 {
    159    PLArenaPool *poolp;
    160    CMMFPOPODecKeyChallContent *challContent;
    161 
    162    poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
    163    if (poolp == NULL) {
    164        return NULL;
    165    }
    166    challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent);
    167    if (challContent == NULL) {
    168        PORT_FreeArena(poolp, PR_FALSE);
    169        return NULL;
    170    }
    171    challContent->poolp = poolp;
    172    return challContent;
    173 }
    174 
    175 SECStatus
    176 CMMF_POPODecKeyChallContentSetNextChallenge(CMMFPOPODecKeyChallContent *inDecKeyChall,
    177                                            long inRandom,
    178                                            CERTGeneralName *inSender,
    179                                            SECKEYPublicKey *inPubKey,
    180                                            void *passwdArg)
    181 {
    182    CMMFChallenge *curChallenge;
    183    PLArenaPool *genNamePool = NULL, *poolp;
    184    SECStatus rv;
    185    SECItem *genNameDER;
    186    void *mark;
    187 
    188    PORT_Assert(inDecKeyChall != NULL &&
    189                inSender != NULL &&
    190                inPubKey != NULL);
    191 
    192    if (inDecKeyChall == NULL ||
    193        inSender == NULL || inPubKey == NULL) {
    194        return SECFailure;
    195    }
    196    poolp = inDecKeyChall->poolp;
    197    mark = PORT_ArenaMark(poolp);
    198 
    199    genNamePool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
    200    genNameDER = CERT_EncodeGeneralName(inSender, NULL, genNamePool);
    201    if (genNameDER == NULL) {
    202        rv = SECFailure;
    203        goto loser;
    204    }
    205    if (inDecKeyChall->challenges == NULL) {
    206        inDecKeyChall->challenges =
    207            PORT_ArenaZNewArray(poolp, CMMFChallenge *, (CMMF_MAX_CHALLENGES + 1));
    208        inDecKeyChall->numAllocated = CMMF_MAX_CHALLENGES;
    209    }
    210 
    211    if (inDecKeyChall->numChallenges >= inDecKeyChall->numAllocated) {
    212        rv = SECFailure;
    213        goto loser;
    214    }
    215 
    216    if (inDecKeyChall->numChallenges == 0) {
    217        rv = cmmf_create_first_challenge(inDecKeyChall, inRandom,
    218                                         genNameDER, inPubKey, passwdArg);
    219    } else {
    220        curChallenge = PORT_ArenaZNew(poolp, CMMFChallenge);
    221        if (curChallenge == NULL) {
    222            rv = SECFailure;
    223            goto loser;
    224        }
    225        rv = cmmf_create_witness_and_challenge(poolp, curChallenge, inRandom,
    226                                               genNameDER, inPubKey,
    227                                               passwdArg);
    228        if (rv == SECSuccess) {
    229            inDecKeyChall->challenges[inDecKeyChall->numChallenges] =
    230                curChallenge;
    231            inDecKeyChall->numChallenges++;
    232        }
    233    }
    234    if (rv != SECSuccess) {
    235        goto loser;
    236    }
    237    PORT_ArenaUnmark(poolp, mark);
    238    PORT_FreeArena(genNamePool, PR_FALSE);
    239    return SECSuccess;
    240 
    241 loser:
    242    PORT_ArenaRelease(poolp, mark);
    243    if (genNamePool != NULL) {
    244        PORT_FreeArena(genNamePool, PR_FALSE);
    245    }
    246    PORT_Assert(rv != SECSuccess);
    247    return rv;
    248 }
    249 
    250 SECStatus
    251 CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp)
    252 {
    253    PORT_Assert(inDecKeyResp != NULL);
    254    if (inDecKeyResp != NULL && inDecKeyResp->poolp != NULL) {
    255        PORT_FreeArena(inDecKeyResp->poolp, PR_FALSE);
    256    }
    257    return SECSuccess;
    258 }
    259 
    260 int
    261 CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont)
    262 {
    263    int numResponses = 0;
    264 
    265    PORT_Assert(inRespCont != NULL);
    266    if (inRespCont == NULL) {
    267        return 0;
    268    }
    269 
    270    while (inRespCont->responses[numResponses] != NULL) {
    271        numResponses++;
    272    }
    273    return numResponses;
    274 }
    275 
    276 SECStatus
    277 CMMF_POPODecKeyRespContentGetResponse(CMMFPOPODecKeyRespContent *inRespCont,
    278                                      int inIndex,
    279                                      long *inDest)
    280 {
    281    PORT_Assert(inRespCont != NULL);
    282 
    283    if (inRespCont == NULL || inIndex < 0 ||
    284        inIndex >= CMMF_POPODecKeyRespContentGetNumResponses(inRespCont)) {
    285        return SECFailure;
    286    }
    287    *inDest = DER_GetInteger(inRespCont->responses[inIndex]);
    288    return (*inDest == -1) ? SECFailure : SECSuccess;
    289 }