tor-browser

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

crmfdec.c (10008B)


      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 "crmf.h"
      7 #include "crmfi.h"
      8 #include "secitem.h"
      9 
     10 static CRMFPOPChoice
     11 crmf_get_popchoice_from_der(SECItem *derPOP)
     12 {
     13    CRMFPOPChoice retChoice;
     14 
     15    switch (derPOP->data[0] & 0x0f) {
     16        case 0:
     17            retChoice = crmfRAVerified;
     18            break;
     19        case 1:
     20            retChoice = crmfSignature;
     21            break;
     22        case 2:
     23            retChoice = crmfKeyEncipherment;
     24            break;
     25        case 3:
     26            retChoice = crmfKeyAgreement;
     27            break;
     28        default:
     29            retChoice = crmfNoPOPChoice;
     30            break;
     31    }
     32    return retChoice;
     33 }
     34 
     35 static SECStatus
     36 crmf_decode_process_raverified(CRMFCertReqMsg *inCertReqMsg)
     37 {
     38    CRMFProofOfPossession *pop;
     39    /* Just set up the structure so that the message structure
     40     * looks like one that was created using the API
     41     */
     42    pop = inCertReqMsg->pop;
     43    pop->popChoice.raVerified.data = NULL;
     44    pop->popChoice.raVerified.len = 0;
     45    return SECSuccess;
     46 }
     47 
     48 static SECStatus
     49 crmf_decode_process_signature(CRMFCertReqMsg *inCertReqMsg)
     50 {
     51    PORT_Assert(inCertReqMsg->poolp);
     52    if (!inCertReqMsg->poolp) {
     53        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     54        return SECFailure;
     55    }
     56    return SEC_ASN1Decode(inCertReqMsg->poolp,
     57                          &inCertReqMsg->pop->popChoice.signature,
     58                          CRMFPOPOSigningKeyTemplate,
     59                          (const char *)inCertReqMsg->derPOP.data,
     60                          inCertReqMsg->derPOP.len);
     61 }
     62 
     63 static CRMFPOPOPrivKeyChoice
     64 crmf_get_messagechoice_from_der(SECItem *derPOP)
     65 {
     66    CRMFPOPOPrivKeyChoice retChoice;
     67 
     68    switch (derPOP->data[2] & 0x0f) {
     69        case 0:
     70            retChoice = crmfThisMessage;
     71            break;
     72        case 1:
     73            retChoice = crmfSubsequentMessage;
     74            break;
     75        case 2:
     76            retChoice = crmfDHMAC;
     77            break;
     78        default:
     79            retChoice = crmfNoMessage;
     80    }
     81    return retChoice;
     82 }
     83 
     84 static SECStatus
     85 crmf_decode_process_popoprivkey(CRMFCertReqMsg *inCertReqMsg)
     86 {
     87    /* We've got a union, so a pointer to one POPOPrivKey
     88     * struct is the same as having a pointer to the other
     89     * one.
     90     */
     91    CRMFPOPOPrivKey *popoPrivKey =
     92        &inCertReqMsg->pop->popChoice.keyEncipherment;
     93    SECItem *derPOP, privKeyDer;
     94    SECStatus rv;
     95 
     96    derPOP = &inCertReqMsg->derPOP;
     97    popoPrivKey->messageChoice = crmf_get_messagechoice_from_der(derPOP);
     98    if (popoPrivKey->messageChoice == crmfNoMessage) {
     99        return SECFailure;
    100    }
    101    /* If we ever encounter BER encodings of this, we'll get in trouble*/
    102    switch (popoPrivKey->messageChoice) {
    103        case crmfThisMessage:
    104        case crmfDHMAC:
    105            privKeyDer.type = derPOP->type;
    106            privKeyDer.data = &derPOP->data[5];
    107            privKeyDer.len = derPOP->len - 5;
    108            break;
    109        case crmfSubsequentMessage:
    110            privKeyDer.type = derPOP->type;
    111            privKeyDer.data = &derPOP->data[4];
    112            privKeyDer.len = derPOP->len - 4;
    113            break;
    114        default:
    115            return SECFailure;
    116    }
    117 
    118    rv = SECITEM_CopyItem(inCertReqMsg->poolp,
    119                          &popoPrivKey->message.subsequentMessage,
    120                          &privKeyDer);
    121 
    122    if (rv != SECSuccess) {
    123        return rv;
    124    }
    125 
    126    if (popoPrivKey->messageChoice == crmfThisMessage ||
    127        popoPrivKey->messageChoice == crmfDHMAC) {
    128 
    129        popoPrivKey->message.thisMessage.len =
    130            CRMF_BYTES_TO_BITS(privKeyDer.len) - (int)derPOP->data[4];
    131    }
    132    return SECSuccess;
    133 }
    134 
    135 static SECStatus
    136 crmf_decode_process_keyagreement(CRMFCertReqMsg *inCertReqMsg)
    137 {
    138    return crmf_decode_process_popoprivkey(inCertReqMsg);
    139 }
    140 
    141 static SECStatus
    142 crmf_decode_process_keyencipherment(CRMFCertReqMsg *inCertReqMsg)
    143 {
    144    SECStatus rv;
    145 
    146    rv = crmf_decode_process_popoprivkey(inCertReqMsg);
    147    if (rv != SECSuccess) {
    148        return rv;
    149    }
    150    if (inCertReqMsg->pop->popChoice.keyEncipherment.messageChoice ==
    151        crmfDHMAC) {
    152        /* Key Encipherment can not use the dhMAC option for
    153         * POPOPrivKey.
    154         */
    155        return SECFailure;
    156    }
    157    return SECSuccess;
    158 }
    159 
    160 static SECStatus
    161 crmf_decode_process_pop(CRMFCertReqMsg *inCertReqMsg)
    162 {
    163    SECItem *derPOP;
    164    PLArenaPool *poolp;
    165    CRMFProofOfPossession *pop;
    166    void *mark;
    167    SECStatus rv;
    168 
    169    derPOP = &inCertReqMsg->derPOP;
    170    poolp = inCertReqMsg->poolp;
    171    if (derPOP->data == NULL) {
    172        /* There is no Proof of Possession field in this message. */
    173        return SECSuccess;
    174    }
    175    mark = PORT_ArenaMark(poolp);
    176    pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
    177    if (pop == NULL) {
    178        goto loser;
    179    }
    180    pop->popUsed = crmf_get_popchoice_from_der(derPOP);
    181    if (pop->popUsed == crmfNoPOPChoice) {
    182        /* A bad encoding of CRMF.  Not a valid tag was given to the
    183         * Proof Of Possession field.
    184         */
    185        goto loser;
    186    }
    187    inCertReqMsg->pop = pop;
    188    switch (pop->popUsed) {
    189        case crmfRAVerified:
    190            rv = crmf_decode_process_raverified(inCertReqMsg);
    191            break;
    192        case crmfSignature:
    193            rv = crmf_decode_process_signature(inCertReqMsg);
    194            break;
    195        case crmfKeyEncipherment:
    196            rv = crmf_decode_process_keyencipherment(inCertReqMsg);
    197            break;
    198        case crmfKeyAgreement:
    199            rv = crmf_decode_process_keyagreement(inCertReqMsg);
    200            break;
    201        default:
    202            rv = SECFailure;
    203    }
    204    if (rv != SECSuccess) {
    205        goto loser;
    206    }
    207    PORT_ArenaUnmark(poolp, mark);
    208    return SECSuccess;
    209 
    210 loser:
    211    PORT_ArenaRelease(poolp, mark);
    212    inCertReqMsg->pop = NULL;
    213    return SECFailure;
    214 }
    215 
    216 static SECStatus
    217 crmf_decode_process_single_control(PLArenaPool *poolp,
    218                                   CRMFControl *inControl)
    219 {
    220    const SEC_ASN1Template *asn1Template = NULL;
    221 
    222    inControl->tag = SECOID_FindOIDTag(&inControl->derTag);
    223    asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
    224 
    225    PORT_Assert(asn1Template != NULL);
    226    PORT_Assert(poolp != NULL);
    227    if (!asn1Template || !poolp) {
    228        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    229        return SECFailure;
    230    }
    231    /* We've got a union, so passing a pointer to one element of the
    232     * union is the same as passing a pointer to any of the other
    233     * members of the union.
    234     */
    235    return SEC_ASN1Decode(poolp, &inControl->value.archiveOptions,
    236                          asn1Template, (const char *)inControl->derValue.data,
    237                          inControl->derValue.len);
    238 }
    239 
    240 static SECStatus
    241 crmf_decode_process_controls(CRMFCertReqMsg *inCertReqMsg)
    242 {
    243    int i, numControls;
    244    SECStatus rv;
    245    PLArenaPool *poolp;
    246    CRMFControl **controls;
    247 
    248    numControls = CRMF_CertRequestGetNumControls(inCertReqMsg->certReq);
    249    controls = inCertReqMsg->certReq->controls;
    250    poolp = inCertReqMsg->poolp;
    251    for (i = 0; i < numControls; i++) {
    252        rv = crmf_decode_process_single_control(poolp, controls[i]);
    253        if (rv != SECSuccess) {
    254            return SECFailure;
    255        }
    256    }
    257    return SECSuccess;
    258 }
    259 
    260 static SECStatus
    261 crmf_decode_process_single_reqmsg(CRMFCertReqMsg *inCertReqMsg)
    262 {
    263    SECStatus rv;
    264 
    265    rv = crmf_decode_process_pop(inCertReqMsg);
    266    if (rv != SECSuccess) {
    267        goto loser;
    268    }
    269 
    270    rv = crmf_decode_process_controls(inCertReqMsg);
    271    if (rv != SECSuccess) {
    272        goto loser;
    273    }
    274    inCertReqMsg->certReq->certTemplate.numExtensions =
    275        CRMF_CertRequestGetNumberOfExtensions(inCertReqMsg->certReq);
    276    inCertReqMsg->isDecoded = PR_TRUE;
    277    rv = SECSuccess;
    278 loser:
    279    return rv;
    280 }
    281 
    282 CRMFCertReqMsg *
    283 CRMF_CreateCertReqMsgFromDER(const char *buf, long len)
    284 {
    285    PLArenaPool *poolp;
    286    CRMFCertReqMsg *certReqMsg;
    287    SECStatus rv;
    288 
    289    poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
    290    if (poolp == NULL) {
    291        goto loser;
    292    }
    293    certReqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
    294    if (certReqMsg == NULL) {
    295        goto loser;
    296    }
    297    certReqMsg->poolp = poolp;
    298    rv = SEC_ASN1Decode(poolp, certReqMsg, CRMFCertReqMsgTemplate, buf, len);
    299    if (rv != SECSuccess) {
    300        goto loser;
    301    }
    302 
    303    rv = crmf_decode_process_single_reqmsg(certReqMsg);
    304    if (rv != SECSuccess) {
    305        goto loser;
    306    }
    307 
    308    return certReqMsg;
    309 loser:
    310    if (poolp != NULL) {
    311        PORT_FreeArena(poolp, PR_FALSE);
    312    }
    313    return NULL;
    314 }
    315 
    316 CRMFCertReqMessages *
    317 CRMF_CreateCertReqMessagesFromDER(const char *buf, long len)
    318 {
    319    long arenaSize;
    320    int i;
    321    SECStatus rv;
    322    PLArenaPool *poolp;
    323    CRMFCertReqMessages *certReqMsgs;
    324 
    325    PORT_Assert(buf != NULL);
    326    /* Wanna make sure the arena is big enough to store all of the requests
    327     * coming in.  We'll guestimate according to the length of the buffer.
    328     */
    329    arenaSize = len + len / 2;
    330    poolp = PORT_NewArena(arenaSize);
    331    if (poolp == NULL) {
    332        return NULL;
    333    }
    334    certReqMsgs = PORT_ArenaZNew(poolp, CRMFCertReqMessages);
    335    if (certReqMsgs == NULL) {
    336        goto loser;
    337    }
    338    certReqMsgs->poolp = poolp;
    339    rv = SEC_ASN1Decode(poolp, certReqMsgs, CRMFCertReqMessagesTemplate,
    340                        buf, len);
    341    if (rv != SECSuccess) {
    342        goto loser;
    343    }
    344    for (i = 0; certReqMsgs->messages[i] != NULL; i++) {
    345        /* The sub-routines expect the individual messages to have
    346         * an arena.  We'll give them one temporarily.
    347         */
    348        certReqMsgs->messages[i]->poolp = poolp;
    349        rv = crmf_decode_process_single_reqmsg(certReqMsgs->messages[i]);
    350        if (rv != SECSuccess) {
    351            goto loser;
    352        }
    353        certReqMsgs->messages[i]->poolp = NULL;
    354    }
    355    return certReqMsgs;
    356 
    357 loser:
    358    PORT_FreeArena(poolp, PR_FALSE);
    359    return NULL;
    360 }