tor-browser

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

crmfcont.c (33346B)


      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 "pk11func.h"
      9 #include "keyhi.h"
     10 #include "secoid.h"
     11 
     12 static SECStatus
     13 crmf_modify_control_array(CRMFCertRequest *inCertReq, int count)
     14 {
     15    if (count > 0) {
     16        void *dummy = PORT_Realloc(inCertReq->controls,
     17                                   sizeof(CRMFControl *) * (count + 2));
     18        if (dummy == NULL) {
     19            return SECFailure;
     20        }
     21        inCertReq->controls = dummy;
     22    } else {
     23        inCertReq->controls = PORT_ZNewArray(CRMFControl *, 2);
     24    }
     25    return (inCertReq->controls == NULL) ? SECFailure : SECSuccess;
     26 }
     27 
     28 static SECStatus
     29 crmf_add_new_control(CRMFCertRequest *inCertReq, SECOidTag inTag,
     30                     CRMFControl **destControl)
     31 {
     32    SECOidData *oidData;
     33    SECStatus rv;
     34    PLArenaPool *poolp;
     35    int numControls = 0;
     36    CRMFControl *newControl;
     37    CRMFControl **controls;
     38    void *mark;
     39 
     40    poolp = inCertReq->poolp;
     41    if (poolp == NULL) {
     42        return SECFailure;
     43    }
     44    mark = PORT_ArenaMark(poolp);
     45    if (inCertReq->controls != NULL) {
     46        while (inCertReq->controls[numControls] != NULL)
     47            numControls++;
     48    }
     49    rv = crmf_modify_control_array(inCertReq, numControls);
     50    if (rv != SECSuccess) {
     51        goto loser;
     52    }
     53    controls = inCertReq->controls;
     54    oidData = SECOID_FindOIDByTag(inTag);
     55    newControl = *destControl = PORT_ArenaZNew(poolp, CRMFControl);
     56    if (newControl == NULL) {
     57        goto loser;
     58    }
     59    rv = SECITEM_CopyItem(poolp, &newControl->derTag, &oidData->oid);
     60    if (rv != SECSuccess) {
     61        goto loser;
     62    }
     63    newControl->tag = inTag;
     64    controls[numControls] = newControl;
     65    controls[numControls + 1] = NULL;
     66    PORT_ArenaUnmark(poolp, mark);
     67    return SECSuccess;
     68 
     69 loser:
     70    PORT_ArenaRelease(poolp, mark);
     71    *destControl = NULL;
     72    return SECFailure;
     73 }
     74 
     75 static SECStatus
     76 crmf_add_secitem_control(CRMFCertRequest *inCertReq, SECItem *value,
     77                         SECOidTag inTag)
     78 {
     79    SECStatus rv;
     80    CRMFControl *newControl;
     81    void *mark;
     82 
     83    rv = crmf_add_new_control(inCertReq, inTag, &newControl);
     84    if (rv != SECSuccess) {
     85        return rv;
     86    }
     87    mark = PORT_ArenaMark(inCertReq->poolp);
     88    rv = SECITEM_CopyItem(inCertReq->poolp, &newControl->derValue, value);
     89    if (rv != SECSuccess) {
     90        PORT_ArenaRelease(inCertReq->poolp, mark);
     91        return rv;
     92    }
     93    PORT_ArenaUnmark(inCertReq->poolp, mark);
     94    return SECSuccess;
     95 }
     96 
     97 SECStatus
     98 CRMF_CertRequestSetRegTokenControl(CRMFCertRequest *inCertReq, SECItem *value)
     99 {
    100    return crmf_add_secitem_control(inCertReq, value,
    101                                    SEC_OID_PKIX_REGCTRL_REGTOKEN);
    102 }
    103 
    104 SECStatus
    105 CRMF_CertRequestSetAuthenticatorControl(CRMFCertRequest *inCertReq,
    106                                        SECItem *value)
    107 {
    108    return crmf_add_secitem_control(inCertReq, value,
    109                                    SEC_OID_PKIX_REGCTRL_AUTHENTICATOR);
    110 }
    111 
    112 SECStatus
    113 crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue, PRBool freeit)
    114 {
    115    if (inEncrValue != NULL) {
    116        if (inEncrValue->intendedAlg) {
    117            SECOID_DestroyAlgorithmID(inEncrValue->intendedAlg, PR_TRUE);
    118            inEncrValue->intendedAlg = NULL;
    119        }
    120        if (inEncrValue->symmAlg) {
    121            SECOID_DestroyAlgorithmID(inEncrValue->symmAlg, PR_TRUE);
    122            inEncrValue->symmAlg = NULL;
    123        }
    124        if (inEncrValue->encSymmKey.data) {
    125            PORT_Free(inEncrValue->encSymmKey.data);
    126            inEncrValue->encSymmKey.data = NULL;
    127        }
    128        if (inEncrValue->keyAlg) {
    129            SECOID_DestroyAlgorithmID(inEncrValue->keyAlg, PR_TRUE);
    130            inEncrValue->keyAlg = NULL;
    131        }
    132        if (inEncrValue->valueHint.data) {
    133            PORT_Free(inEncrValue->valueHint.data);
    134            inEncrValue->valueHint.data = NULL;
    135        }
    136        if (inEncrValue->encValue.data) {
    137            PORT_Free(inEncrValue->encValue.data);
    138            inEncrValue->encValue.data = NULL;
    139        }
    140        if (freeit) {
    141            PORT_Free(inEncrValue);
    142        }
    143    }
    144    return SECSuccess;
    145 }
    146 
    147 SECStatus
    148 CRMF_DestroyEncryptedValue(CRMFEncryptedValue *inEncrValue)
    149 {
    150    return crmf_destroy_encrypted_value(inEncrValue, PR_TRUE);
    151 }
    152 
    153 SECStatus
    154 crmf_copy_encryptedvalue_secalg(PLArenaPool *poolp,
    155                                SECAlgorithmID *srcAlgId,
    156                                SECAlgorithmID **destAlgId)
    157 {
    158    SECAlgorithmID *newAlgId;
    159    SECStatus rv;
    160 
    161    newAlgId = (poolp != NULL) ? PORT_ArenaZNew(poolp, SECAlgorithmID) : PORT_ZNew(SECAlgorithmID);
    162    if (newAlgId == NULL) {
    163        return SECFailure;
    164    }
    165 
    166    rv = SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId);
    167    if (rv != SECSuccess) {
    168        if (!poolp) {
    169            SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE);
    170        }
    171        return rv;
    172    }
    173    *destAlgId = newAlgId;
    174 
    175    return rv;
    176 }
    177 
    178 SECStatus
    179 crmf_copy_encryptedvalue(PLArenaPool *poolp,
    180                         CRMFEncryptedValue *srcValue,
    181                         CRMFEncryptedValue *destValue)
    182 {
    183    SECStatus rv;
    184 
    185    if (srcValue->intendedAlg != NULL) {
    186        rv = crmf_copy_encryptedvalue_secalg(poolp,
    187                                             srcValue->intendedAlg,
    188                                             &destValue->intendedAlg);
    189        if (rv != SECSuccess) {
    190            goto loser;
    191        }
    192    }
    193    if (srcValue->symmAlg != NULL) {
    194        rv = crmf_copy_encryptedvalue_secalg(poolp,
    195                                             srcValue->symmAlg,
    196                                             &destValue->symmAlg);
    197        if (rv != SECSuccess) {
    198            goto loser;
    199        }
    200    }
    201    if (srcValue->encSymmKey.data != NULL) {
    202        rv = crmf_make_bitstring_copy(poolp,
    203                                      &destValue->encSymmKey,
    204                                      &srcValue->encSymmKey);
    205        if (rv != SECSuccess) {
    206            goto loser;
    207        }
    208    }
    209    if (srcValue->keyAlg != NULL) {
    210        rv = crmf_copy_encryptedvalue_secalg(poolp,
    211                                             srcValue->keyAlg,
    212                                             &destValue->keyAlg);
    213        if (rv != SECSuccess) {
    214            goto loser;
    215        }
    216    }
    217    if (srcValue->valueHint.data != NULL) {
    218        rv = SECITEM_CopyItem(poolp,
    219                              &destValue->valueHint,
    220                              &srcValue->valueHint);
    221        if (rv != SECSuccess) {
    222            goto loser;
    223        }
    224    }
    225    if (srcValue->encValue.data != NULL) {
    226        rv = crmf_make_bitstring_copy(poolp,
    227                                      &destValue->encValue,
    228                                      &srcValue->encValue);
    229        if (rv != SECSuccess) {
    230            goto loser;
    231        }
    232    }
    233    return SECSuccess;
    234 loser:
    235    if (poolp == NULL && destValue != NULL) {
    236        crmf_destroy_encrypted_value(destValue, PR_FALSE);
    237    }
    238    return SECFailure;
    239 }
    240 
    241 SECStatus
    242 crmf_copy_encryptedkey(PLArenaPool *poolp,
    243                       CRMFEncryptedKey *srcEncrKey,
    244                       CRMFEncryptedKey *destEncrKey)
    245 {
    246    SECStatus rv;
    247    void *mark = NULL;
    248 
    249    if (poolp != NULL) {
    250        mark = PORT_ArenaMark(poolp);
    251    }
    252 
    253    switch (srcEncrKey->encKeyChoice) {
    254        case crmfEncryptedValueChoice:
    255            rv = crmf_copy_encryptedvalue(poolp,
    256                                          &srcEncrKey->value.encryptedValue,
    257                                          &destEncrKey->value.encryptedValue);
    258            break;
    259        case crmfEnvelopedDataChoice:
    260            destEncrKey->value.envelopedData =
    261                SEC_PKCS7CopyContentInfo(srcEncrKey->value.envelopedData);
    262            rv = (destEncrKey->value.envelopedData != NULL) ? SECSuccess : SECFailure;
    263            break;
    264        default:
    265            rv = SECFailure;
    266    }
    267    if (rv != SECSuccess) {
    268        goto loser;
    269    }
    270    destEncrKey->encKeyChoice = srcEncrKey->encKeyChoice;
    271    if (mark) {
    272        PORT_ArenaUnmark(poolp, mark);
    273    }
    274    return SECSuccess;
    275 
    276 loser:
    277    if (mark) {
    278        PORT_ArenaRelease(poolp, mark);
    279    }
    280    return SECFailure;
    281 }
    282 
    283 static CRMFPKIArchiveOptions *
    284 crmf_create_encr_pivkey_option(CRMFEncryptedKey *inEncryptedKey)
    285 {
    286    CRMFPKIArchiveOptions *newArchOpt;
    287    SECStatus rv;
    288 
    289    newArchOpt = PORT_ZNew(CRMFPKIArchiveOptions);
    290    if (newArchOpt == NULL) {
    291        goto loser;
    292    }
    293 
    294    rv = crmf_copy_encryptedkey(NULL, inEncryptedKey,
    295                                &newArchOpt->option.encryptedKey);
    296 
    297    if (rv != SECSuccess) {
    298        goto loser;
    299    }
    300    newArchOpt->archOption = crmfEncryptedPrivateKey;
    301    return newArchOpt;
    302 loser:
    303    if (newArchOpt != NULL) {
    304        CRMF_DestroyPKIArchiveOptions(newArchOpt);
    305    }
    306    return NULL;
    307 }
    308 
    309 static CRMFPKIArchiveOptions *
    310 crmf_create_keygen_param_option(SECItem *inKeyGenParams)
    311 {
    312    CRMFPKIArchiveOptions *newArchOptions;
    313    SECStatus rv;
    314 
    315    newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
    316    if (newArchOptions == NULL) {
    317        goto loser;
    318    }
    319    newArchOptions->archOption = crmfKeyGenParameters;
    320    rv = SECITEM_CopyItem(NULL, &newArchOptions->option.keyGenParameters,
    321                          inKeyGenParams);
    322    if (rv != SECSuccess) {
    323        goto loser;
    324    }
    325    return newArchOptions;
    326 loser:
    327    if (newArchOptions != NULL) {
    328        CRMF_DestroyPKIArchiveOptions(newArchOptions);
    329    }
    330    return NULL;
    331 }
    332 
    333 static CRMFPKIArchiveOptions *
    334 crmf_create_arch_rem_gen_privkey(PRBool archiveRemGenPrivKey)
    335 {
    336    unsigned char value;
    337    SECItem *dummy;
    338    CRMFPKIArchiveOptions *newArchOptions;
    339 
    340    value = (archiveRemGenPrivKey) ? hexTrue : hexFalse;
    341    newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
    342    if (newArchOptions == NULL) {
    343        goto loser;
    344    }
    345    dummy = SEC_ASN1EncodeItem(NULL,
    346                               &newArchOptions->option.archiveRemGenPrivKey,
    347                               &value, SEC_ASN1_GET(SEC_BooleanTemplate));
    348    PORT_Assert(dummy == &newArchOptions->option.archiveRemGenPrivKey);
    349    if (dummy != &newArchOptions->option.archiveRemGenPrivKey) {
    350        SECITEM_FreeItem(dummy, PR_TRUE);
    351        goto loser;
    352    }
    353    newArchOptions->archOption = crmfArchiveRemGenPrivKey;
    354    return newArchOptions;
    355 loser:
    356    if (newArchOptions != NULL) {
    357        CRMF_DestroyPKIArchiveOptions(newArchOptions);
    358    }
    359    return NULL;
    360 }
    361 
    362 CRMFPKIArchiveOptions *
    363 CRMF_CreatePKIArchiveOptions(CRMFPKIArchiveOptionsType inType, void *data)
    364 {
    365    CRMFPKIArchiveOptions *retOptions;
    366 
    367    PORT_Assert(data != NULL);
    368    if (data == NULL) {
    369        return NULL;
    370    }
    371    switch (inType) {
    372        case crmfEncryptedPrivateKey:
    373            retOptions = crmf_create_encr_pivkey_option((CRMFEncryptedKey *)data);
    374            break;
    375        case crmfKeyGenParameters:
    376            retOptions = crmf_create_keygen_param_option((SECItem *)data);
    377            break;
    378        case crmfArchiveRemGenPrivKey:
    379            retOptions = crmf_create_arch_rem_gen_privkey(*(PRBool *)data);
    380            break;
    381        default:
    382            retOptions = NULL;
    383    }
    384    return retOptions;
    385 }
    386 
    387 static SECStatus
    388 crmf_destroy_encrypted_key(CRMFEncryptedKey *inEncrKey, PRBool freeit)
    389 {
    390    PORT_Assert(inEncrKey != NULL);
    391    if (inEncrKey != NULL) {
    392        switch (inEncrKey->encKeyChoice) {
    393            case crmfEncryptedValueChoice:
    394                crmf_destroy_encrypted_value(&inEncrKey->value.encryptedValue,
    395                                             PR_FALSE);
    396                break;
    397            case crmfEnvelopedDataChoice:
    398                SEC_PKCS7DestroyContentInfo(inEncrKey->value.envelopedData);
    399                break;
    400            default:
    401                break;
    402        }
    403        if (freeit) {
    404            PORT_Free(inEncrKey);
    405        }
    406    }
    407    return SECSuccess;
    408 }
    409 
    410 SECStatus
    411 crmf_destroy_pkiarchiveoptions(CRMFPKIArchiveOptions *inArchOptions,
    412                               PRBool freeit)
    413 {
    414    PORT_Assert(inArchOptions != NULL);
    415    if (inArchOptions != NULL) {
    416        switch (inArchOptions->archOption) {
    417            case crmfEncryptedPrivateKey:
    418                crmf_destroy_encrypted_key(&inArchOptions->option.encryptedKey,
    419                                           PR_FALSE);
    420                break;
    421            case crmfKeyGenParameters:
    422            case crmfArchiveRemGenPrivKey:
    423                /* This is a union, so having a pointer to one is like
    424                 * having a pointer to both.
    425                 */
    426                SECITEM_FreeItem(&inArchOptions->option.keyGenParameters,
    427                                 PR_FALSE);
    428                break;
    429            case crmfNoArchiveOptions:
    430                break;
    431        }
    432        if (freeit) {
    433            PORT_Free(inArchOptions);
    434        }
    435    }
    436    return SECSuccess;
    437 }
    438 
    439 SECStatus
    440 CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inArchOptions)
    441 {
    442    return crmf_destroy_pkiarchiveoptions(inArchOptions, PR_TRUE);
    443 }
    444 
    445 static CK_MECHANISM_TYPE
    446 crmf_get_non_pad_mechanism(CK_MECHANISM_TYPE type)
    447 {
    448    switch (type) {
    449        case CKM_DES3_CBC_PAD:
    450            return CKM_DES3_CBC;
    451        case CKM_CAST5_CBC_PAD:
    452            return CKM_CAST5_CBC;
    453        case CKM_DES_CBC_PAD:
    454            return CKM_DES_CBC;
    455        case CKM_IDEA_CBC_PAD:
    456            return CKM_IDEA_CBC;
    457        case CKM_CAST3_CBC_PAD:
    458            return CKM_CAST3_CBC;
    459        case CKM_CAST_CBC_PAD:
    460            return CKM_CAST_CBC;
    461        case CKM_RC5_CBC_PAD:
    462            return CKM_RC5_CBC;
    463        case CKM_RC2_CBC_PAD:
    464            return CKM_RC2_CBC;
    465        case CKM_CDMF_CBC_PAD:
    466            return CKM_CDMF_CBC;
    467    }
    468    return type;
    469 }
    470 
    471 static CK_MECHANISM_TYPE
    472 crmf_get_pad_mech_from_tag(SECOidTag oidTag)
    473 {
    474    CK_MECHANISM_TYPE mechType;
    475    SECOidData *oidData;
    476 
    477    oidData = SECOID_FindOIDByTag(oidTag);
    478    mechType = (CK_MECHANISM_TYPE)oidData->mechanism;
    479    return PK11_GetPadMechanism(mechType);
    480 }
    481 
    482 static CK_MECHANISM_TYPE
    483 crmf_get_best_privkey_wrap_mechanism(PK11SlotInfo *slot)
    484 {
    485    CK_MECHANISM_TYPE privKeyPadMechs[] = { CKM_DES3_CBC_PAD,
    486                                            CKM_CAST5_CBC_PAD,
    487                                            CKM_DES_CBC_PAD,
    488                                            CKM_IDEA_CBC_PAD,
    489                                            CKM_CAST3_CBC_PAD,
    490                                            CKM_CAST_CBC_PAD,
    491                                            CKM_RC5_CBC_PAD,
    492                                            CKM_RC2_CBC_PAD,
    493                                            CKM_CDMF_CBC_PAD };
    494    int mechCount = sizeof(privKeyPadMechs) / sizeof(privKeyPadMechs[0]);
    495    int i;
    496 
    497    for (i = 0; i < mechCount; i++) {
    498        if (PK11_DoesMechanism(slot, privKeyPadMechs[i])) {
    499            return privKeyPadMechs[i];
    500        }
    501    }
    502    return CKM_INVALID_MECHANISM;
    503 }
    504 
    505 CK_MECHANISM_TYPE
    506 CRMF_GetBestWrapPadMechanism(PK11SlotInfo *slot)
    507 {
    508    return crmf_get_best_privkey_wrap_mechanism(slot);
    509 }
    510 
    511 static SECItem *
    512 crmf_get_iv(CK_MECHANISM_TYPE mechType)
    513 {
    514    int iv_size = PK11_GetIVLength(mechType);
    515    SECItem *iv;
    516    SECStatus rv;
    517 
    518    iv = PORT_ZNew(SECItem);
    519    if (iv == NULL) {
    520        return NULL;
    521    }
    522    if (iv_size == 0) {
    523        iv->data = NULL;
    524        iv->len = 0;
    525        return iv;
    526    }
    527    iv->data = PORT_NewArray(unsigned char, iv_size);
    528    if (iv->data == NULL) {
    529        iv->len = 0;
    530        return iv;
    531    }
    532    iv->len = iv_size;
    533    rv = PK11_GenerateRandom(iv->data, iv->len);
    534    if (rv != SECSuccess) {
    535        PORT_Free(iv->data);
    536        iv->data = NULL;
    537        iv->len = 0;
    538    }
    539    return iv;
    540 }
    541 
    542 SECItem *
    543 CRMF_GetIVFromMechanism(CK_MECHANISM_TYPE mechType)
    544 {
    545    return crmf_get_iv(mechType);
    546 }
    547 
    548 CK_MECHANISM_TYPE
    549 crmf_get_mechanism_from_public_key(SECKEYPublicKey *inPubKey)
    550 {
    551    CERTSubjectPublicKeyInfo *spki = NULL;
    552    SECOidTag tag;
    553 
    554    spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey);
    555    if (spki == NULL) {
    556        return CKM_INVALID_MECHANISM;
    557    }
    558    tag = SECOID_FindOIDTag(&spki->algorithm.algorithm);
    559    SECKEY_DestroySubjectPublicKeyInfo(spki);
    560    spki = NULL;
    561    return PK11_AlgtagToMechanism(tag);
    562 }
    563 
    564 SECItem *
    565 crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest)
    566 {
    567    const SECItem *src = PK11_GetPublicValueFromPublicKey(pubKey);
    568 
    569    if (!src) {
    570        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    571        return NULL;
    572    }
    573 
    574    if (dest != NULL) {
    575        SECStatus rv = SECITEM_CopyItem(NULL, dest, src);
    576        if (rv != SECSuccess) {
    577            dest = NULL;
    578        }
    579    } else {
    580        dest = SECITEM_ArenaDupItem(NULL, src);
    581    }
    582    return dest;
    583 }
    584 
    585 static SECItem *
    586 crmf_decode_params(SECItem *inParams)
    587 {
    588    SECItem *params;
    589    SECStatus rv = SECFailure;
    590    PLArenaPool *poolp;
    591 
    592    poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
    593    if (poolp == NULL) {
    594        return NULL;
    595    }
    596 
    597    params = PORT_ArenaZNew(poolp, SECItem);
    598    if (params) {
    599        rv = SEC_ASN1DecodeItem(poolp, params,
    600                                SEC_ASN1_GET(SEC_OctetStringTemplate),
    601                                inParams);
    602    }
    603    params = (rv == SECSuccess) ? SECITEM_ArenaDupItem(NULL, params) : NULL;
    604    PORT_FreeArena(poolp, PR_FALSE);
    605    return params;
    606 }
    607 
    608 static int
    609 crmf_get_key_size_from_mech(CK_MECHANISM_TYPE mechType)
    610 {
    611    CK_MECHANISM_TYPE keyGen = PK11_GetKeyGen(mechType);
    612 
    613    switch (keyGen) {
    614        case CKM_CDMF_KEY_GEN:
    615        case CKM_DES_KEY_GEN:
    616            return 8;
    617        case CKM_DES2_KEY_GEN:
    618            return 16;
    619        case CKM_DES3_KEY_GEN:
    620            return 24;
    621    }
    622    return 0;
    623 }
    624 
    625 SECStatus
    626 crmf_encrypted_value_unwrap_priv_key(PLArenaPool *poolp,
    627                                     CRMFEncryptedValue *encValue,
    628                                     SECKEYPrivateKey *privKey,
    629                                     SECKEYPublicKey *newPubKey,
    630                                     SECItem *nickname,
    631                                     PK11SlotInfo *slot,
    632                                     unsigned char keyUsage,
    633                                     SECKEYPrivateKey **unWrappedKey,
    634                                     void *wincx)
    635 {
    636    PK11SymKey *wrappingKey = NULL;
    637    CK_MECHANISM_TYPE wrapMechType;
    638    SECOidTag oidTag;
    639    SECItem *params = NULL, *publicValue = NULL;
    640    int keySize, origLen;
    641 
    642    oidTag = SECOID_GetAlgorithmTag(encValue->symmAlg);
    643    wrapMechType = crmf_get_pad_mech_from_tag(oidTag);
    644    keySize = crmf_get_key_size_from_mech(wrapMechType);
    645    wrappingKey = PK11_PubUnwrapSymKey(privKey, &encValue->encSymmKey,
    646                                       wrapMechType, CKA_UNWRAP, keySize);
    647    if (wrappingKey == NULL) {
    648        goto loser;
    649    } /* Make the length a byte length instead of bit length*/
    650    params = (encValue->symmAlg != NULL) ? crmf_decode_params(&encValue->symmAlg->parameters)
    651                                         : NULL;
    652    origLen = encValue->encValue.len;
    653    encValue->encValue.len = CRMF_BITS_TO_BYTES(origLen);
    654    publicValue = crmf_get_public_value(newPubKey, NULL);
    655 
    656    *unWrappedKey = PK11_UnwrapPrivKeyByKeyType(slot, wrappingKey,
    657                                                wrapMechType, params,
    658                                                &encValue->encValue,
    659                                                nickname, publicValue,
    660                                                PR_TRUE, PR_TRUE,
    661                                                newPubKey->keyType,
    662                                                keyUsage, wincx);
    663    encValue->encValue.len = origLen;
    664    if (*unWrappedKey == NULL) {
    665        goto loser;
    666    }
    667    SECITEM_FreeItem(publicValue, PR_TRUE);
    668    if (params != NULL) {
    669        SECITEM_FreeItem(params, PR_TRUE);
    670    }
    671    PK11_FreeSymKey(wrappingKey);
    672    return SECSuccess;
    673 loser:
    674    *unWrappedKey = NULL;
    675    return SECFailure;
    676 }
    677 
    678 CRMFEncryptedValue *
    679 crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey,
    680                                            SECKEYPublicKey *inCAKey,
    681                                            CRMFEncryptedValue *destValue)
    682 {
    683    SECItem wrappedPrivKey, wrappedSymKey;
    684    SECItem encodedParam, *dummy;
    685    SECStatus rv;
    686    CK_MECHANISM_TYPE pubMechType, symKeyType;
    687    unsigned char *wrappedSymKeyBits;
    688    unsigned char *wrappedPrivKeyBits;
    689    SECItem *iv = NULL;
    690    SECOidTag tag;
    691    PK11SymKey *symKey;
    692    PK11SlotInfo *slot;
    693    SECAlgorithmID *symmAlg;
    694    CRMFEncryptedValue *myEncrValue = NULL;
    695 
    696    encodedParam.data = NULL;
    697    wrappedSymKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
    698    wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
    699    if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) {
    700        goto loser;
    701    }
    702    if (destValue == NULL) {
    703        myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue);
    704        if (destValue == NULL) {
    705            goto loser;
    706        }
    707    }
    708 
    709    pubMechType = crmf_get_mechanism_from_public_key(inCAKey);
    710    if (pubMechType == CKM_INVALID_MECHANISM) {
    711        /* XXX I should probably do something here for non-RSA
    712         *     keys that are in certs. (ie DSA)
    713         * XXX or at least SET AN ERROR CODE.
    714         */
    715        goto loser;
    716    }
    717    slot = inPrivKey->pkcs11Slot;
    718    PORT_Assert(slot != NULL);
    719    symKeyType = crmf_get_best_privkey_wrap_mechanism(slot);
    720    symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL);
    721    if (symKey == NULL) {
    722        goto loser;
    723    }
    724 
    725    wrappedSymKey.data = wrappedSymKeyBits;
    726    wrappedSymKey.len = MAX_WRAPPED_KEY_LEN;
    727    rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey);
    728    if (rv != SECSuccess) {
    729        goto loser;
    730    }
    731    /* Make the length of the result a Bit String length. */
    732    wrappedSymKey.len <<= 3;
    733 
    734    wrappedPrivKey.data = wrappedPrivKeyBits;
    735    wrappedPrivKey.len = MAX_WRAPPED_KEY_LEN;
    736    iv = crmf_get_iv(symKeyType);
    737    rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv,
    738                          &wrappedPrivKey, NULL);
    739    PK11_FreeSymKey(symKey);
    740    if (rv != SECSuccess) {
    741        goto loser;
    742    }
    743    /* Make the length of the result a Bit String length. */
    744    wrappedPrivKey.len <<= 3;
    745    rv = crmf_make_bitstring_copy(NULL,
    746                                  &destValue->encValue,
    747                                  &wrappedPrivKey);
    748    if (rv != SECSuccess) {
    749        goto loser;
    750    }
    751 
    752    rv = crmf_make_bitstring_copy(NULL,
    753                                  &destValue->encSymmKey,
    754                                  &wrappedSymKey);
    755    if (rv != SECSuccess) {
    756        goto loser;
    757    }
    758    destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID);
    759    if (symmAlg == NULL) {
    760        goto loser;
    761    }
    762 
    763    dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv,
    764                               SEC_ASN1_GET(SEC_OctetStringTemplate));
    765    if (dummy != &encodedParam) {
    766        SECITEM_FreeItem(dummy, PR_TRUE);
    767        goto loser;
    768    }
    769 
    770    symKeyType = crmf_get_non_pad_mechanism(symKeyType);
    771    tag = PK11_MechanismToAlgtag(symKeyType);
    772    rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam);
    773    if (rv != SECSuccess) {
    774        goto loser;
    775    }
    776    SECITEM_FreeItem(&encodedParam, PR_FALSE);
    777    PORT_Free(wrappedPrivKeyBits);
    778    PORT_Free(wrappedSymKeyBits);
    779    SECITEM_FreeItem(iv, PR_TRUE);
    780    return destValue;
    781 loser:
    782    if (iv != NULL) {
    783        SECITEM_FreeItem(iv, PR_TRUE);
    784    }
    785    if (myEncrValue != NULL) {
    786        crmf_destroy_encrypted_value(myEncrValue, PR_TRUE);
    787    }
    788    if (wrappedSymKeyBits != NULL) {
    789        PORT_Free(wrappedSymKeyBits);
    790    }
    791    if (wrappedPrivKeyBits != NULL) {
    792        PORT_Free(wrappedPrivKeyBits);
    793    }
    794    if (encodedParam.data != NULL) {
    795        SECITEM_FreeItem(&encodedParam, PR_FALSE);
    796    }
    797    return NULL;
    798 }
    799 
    800 CRMFEncryptedKey *
    801 CRMF_CreateEncryptedKeyWithEncryptedValue(SECKEYPrivateKey *inPrivKey,
    802                                          CERTCertificate *inCACert)
    803 {
    804    SECKEYPublicKey *caPubKey = NULL;
    805    CRMFEncryptedKey *encKey = NULL;
    806 
    807    PORT_Assert(inPrivKey != NULL && inCACert != NULL);
    808    if (inPrivKey == NULL || inCACert == NULL) {
    809        return NULL;
    810    }
    811 
    812    caPubKey = CERT_ExtractPublicKey(inCACert);
    813    if (caPubKey == NULL) {
    814        goto loser;
    815    }
    816 
    817    encKey = PORT_ZNew(CRMFEncryptedKey);
    818    if (encKey == NULL) {
    819        goto loser;
    820    }
    821 #ifdef DEBUG
    822    {
    823        CRMFEncryptedValue *dummy =
    824            crmf_create_encrypted_value_wrapped_privkey(
    825                inPrivKey, caPubKey, &encKey->value.encryptedValue);
    826        PORT_Assert(dummy == &encKey->value.encryptedValue);
    827    }
    828 #else
    829    crmf_create_encrypted_value_wrapped_privkey(
    830        inPrivKey, caPubKey, &encKey->value.encryptedValue);
    831 #endif
    832    /* We won't add the der value here, but rather when it
    833     * becomes part of a certificate request.
    834     */
    835    SECKEY_DestroyPublicKey(caPubKey);
    836    encKey->encKeyChoice = crmfEncryptedValueChoice;
    837    return encKey;
    838 loser:
    839    if (encKey != NULL) {
    840        CRMF_DestroyEncryptedKey(encKey);
    841    }
    842    if (caPubKey != NULL) {
    843        SECKEY_DestroyPublicKey(caPubKey);
    844    }
    845    return NULL;
    846 }
    847 
    848 SECStatus
    849 CRMF_DestroyEncryptedKey(CRMFEncryptedKey *inEncrKey)
    850 {
    851    return crmf_destroy_encrypted_key(inEncrKey, PR_TRUE);
    852 }
    853 
    854 SECStatus
    855 crmf_copy_pkiarchiveoptions(PLArenaPool *poolp,
    856                            CRMFPKIArchiveOptions *destOpt,
    857                            CRMFPKIArchiveOptions *srcOpt)
    858 {
    859    SECStatus rv;
    860    destOpt->archOption = srcOpt->archOption;
    861    switch (srcOpt->archOption) {
    862        case crmfEncryptedPrivateKey:
    863            rv = crmf_copy_encryptedkey(poolp,
    864                                        &srcOpt->option.encryptedKey,
    865                                        &destOpt->option.encryptedKey);
    866            break;
    867        case crmfKeyGenParameters:
    868        case crmfArchiveRemGenPrivKey:
    869            /* We've got a union, so having a pointer to one is just
    870             * like having a pointer to the other one.
    871             */
    872            rv = SECITEM_CopyItem(poolp,
    873                                  &destOpt->option.keyGenParameters,
    874                                  &srcOpt->option.keyGenParameters);
    875            break;
    876        default:
    877            rv = SECFailure;
    878    }
    879    return rv;
    880 }
    881 
    882 static SECStatus
    883 crmf_check_and_adjust_archoption(CRMFControl *inControl)
    884 {
    885    CRMFPKIArchiveOptions *options;
    886 
    887    options = &inControl->value.archiveOptions;
    888    if (options->archOption == crmfNoArchiveOptions) {
    889        /* It hasn't been set, so figure it out from the
    890         * der.
    891         */
    892        switch (inControl->derValue.data[0] & 0x0f) {
    893            case 0:
    894                options->archOption = crmfEncryptedPrivateKey;
    895                break;
    896            case 1:
    897                options->archOption = crmfKeyGenParameters;
    898                break;
    899            case 2:
    900                options->archOption = crmfArchiveRemGenPrivKey;
    901                break;
    902            default:
    903                /* We've got bad DER.  Return an error. */
    904                return SECFailure;
    905        }
    906    }
    907    return SECSuccess;
    908 }
    909 
    910 static const SEC_ASN1Template *
    911 crmf_get_pkiarchive_subtemplate(CRMFControl *inControl)
    912 {
    913    const SEC_ASN1Template *retTemplate;
    914    SECStatus rv;
    915    /*
    916     * We could be in the process of decoding, in which case the
    917     * archOption field will not be set.  Let's check it and set
    918     * it accordingly.
    919     */
    920 
    921    rv = crmf_check_and_adjust_archoption(inControl);
    922    if (rv != SECSuccess) {
    923        return NULL;
    924    }
    925 
    926    switch (inControl->value.archiveOptions.archOption) {
    927        case crmfEncryptedPrivateKey:
    928            retTemplate = CRMFEncryptedKeyWithEncryptedValueTemplate;
    929            inControl->value.archiveOptions.option.encryptedKey.encKeyChoice =
    930                crmfEncryptedValueChoice;
    931            break;
    932        default:
    933            retTemplate = NULL;
    934    }
    935    return retTemplate;
    936 }
    937 
    938 const SEC_ASN1Template *
    939 crmf_get_pkiarchiveoptions_subtemplate(CRMFControl *inControl)
    940 {
    941    const SEC_ASN1Template *retTemplate;
    942 
    943    switch (inControl->tag) {
    944        case SEC_OID_PKIX_REGCTRL_REGTOKEN:
    945        case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
    946            retTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
    947            break;
    948        case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
    949            retTemplate = crmf_get_pkiarchive_subtemplate(inControl);
    950            break;
    951        case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
    952        case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
    953        case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
    954            /* We don't support these controls, so we fail for now.*/
    955            retTemplate = NULL;
    956            break;
    957        default:
    958            retTemplate = NULL;
    959    }
    960    return retTemplate;
    961 }
    962 
    963 static SECStatus
    964 crmf_encode_pkiarchiveoptions(PLArenaPool *poolp, CRMFControl *inControl)
    965 {
    966    const SEC_ASN1Template *asn1Template;
    967 
    968    asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
    969    /* We've got a union, so passing a pointer to one element of the
    970     * union, is the same as passing a pointer to any of the other
    971     * members of the union.
    972     */
    973    SEC_ASN1EncodeItem(poolp, &inControl->derValue,
    974                       &inControl->value.archiveOptions, asn1Template);
    975 
    976    if (inControl->derValue.data == NULL) {
    977        goto loser;
    978    }
    979    return SECSuccess;
    980 loser:
    981    return SECFailure;
    982 }
    983 
    984 SECStatus
    985 CRMF_CertRequestSetPKIArchiveOptions(CRMFCertRequest *inCertReq,
    986                                     CRMFPKIArchiveOptions *inOptions)
    987 {
    988    CRMFControl *newControl;
    989    PLArenaPool *poolp;
    990    SECStatus rv;
    991    void *mark;
    992 
    993    PORT_Assert(inCertReq != NULL && inOptions != NULL);
    994    if (inCertReq == NULL || inOptions == NULL) {
    995        return SECFailure;
    996    }
    997    poolp = inCertReq->poolp;
    998    mark = PORT_ArenaMark(poolp);
    999    rv = crmf_add_new_control(inCertReq,
   1000                              SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS,
   1001                              &newControl);
   1002    if (rv != SECSuccess) {
   1003        goto loser;
   1004    }
   1005 
   1006    rv = crmf_copy_pkiarchiveoptions(poolp,
   1007                                     &newControl->value.archiveOptions,
   1008                                     inOptions);
   1009    if (rv != SECSuccess) {
   1010        goto loser;
   1011    }
   1012 
   1013    rv = crmf_encode_pkiarchiveoptions(poolp, newControl);
   1014    if (rv != SECSuccess) {
   1015        goto loser;
   1016    }
   1017    PORT_ArenaUnmark(poolp, mark);
   1018    return SECSuccess;
   1019 loser:
   1020    PORT_ArenaRelease(poolp, mark);
   1021    return SECFailure;
   1022 }
   1023 
   1024 static SECStatus
   1025 crmf_destroy_control(CRMFControl *inControl, PRBool freeit)
   1026 {
   1027    PORT_Assert(inControl != NULL);
   1028    if (inControl != NULL) {
   1029        SECITEM_FreeItem(&inControl->derTag, PR_FALSE);
   1030        SECITEM_FreeItem(&inControl->derValue, PR_FALSE);
   1031        /* None of the other tags require special processing at
   1032         * the moment when freeing because they are not supported,
   1033         * but if/when they are, add the necessary routines here.
   1034         * If all controls are supported, then every member of the
   1035         * union inControl->value will have a case that deals with
   1036         * it in the following switch statement.
   1037         */
   1038        switch (inControl->tag) {
   1039            case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
   1040                crmf_destroy_pkiarchiveoptions(&inControl->value.archiveOptions,
   1041                                               PR_FALSE);
   1042                break;
   1043            default:
   1044                /* Put this here to get rid of all those annoying warnings.*/
   1045                break;
   1046        }
   1047        if (freeit) {
   1048            PORT_Free(inControl);
   1049        }
   1050    }
   1051    return SECSuccess;
   1052 }
   1053 
   1054 SECStatus
   1055 CRMF_DestroyControl(CRMFControl *inControl)
   1056 {
   1057    return crmf_destroy_control(inControl, PR_TRUE);
   1058 }
   1059 
   1060 static SECOidTag
   1061 crmf_controltype_to_tag(CRMFControlType inControlType)
   1062 {
   1063    SECOidTag retVal;
   1064 
   1065    switch (inControlType) {
   1066        case crmfRegTokenControl:
   1067            retVal = SEC_OID_PKIX_REGCTRL_REGTOKEN;
   1068            break;
   1069        case crmfAuthenticatorControl:
   1070            retVal = SEC_OID_PKIX_REGCTRL_AUTHENTICATOR;
   1071            break;
   1072        case crmfPKIPublicationInfoControl:
   1073            retVal = SEC_OID_PKIX_REGCTRL_PKIPUBINFO;
   1074            break;
   1075        case crmfPKIArchiveOptionsControl:
   1076            retVal = SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS;
   1077            break;
   1078        case crmfOldCertIDControl:
   1079            retVal = SEC_OID_PKIX_REGCTRL_OLD_CERT_ID;
   1080            break;
   1081        case crmfProtocolEncrKeyControl:
   1082            retVal = SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY;
   1083            break;
   1084        default:
   1085            retVal = SEC_OID_UNKNOWN;
   1086            break;
   1087    }
   1088    return retVal;
   1089 }
   1090 
   1091 PRBool
   1092 CRMF_CertRequestIsControlPresent(CRMFCertRequest *inCertReq,
   1093                                 CRMFControlType inControlType)
   1094 {
   1095    SECOidTag controlTag;
   1096    int i;
   1097 
   1098    PORT_Assert(inCertReq != NULL);
   1099    if (inCertReq == NULL || inCertReq->controls == NULL) {
   1100        return PR_FALSE;
   1101    }
   1102    controlTag = crmf_controltype_to_tag(inControlType);
   1103    for (i = 0; inCertReq->controls[i] != NULL; i++) {
   1104        if (inCertReq->controls[i]->tag == controlTag) {
   1105            return PR_TRUE;
   1106        }
   1107    }
   1108    return PR_FALSE;
   1109 }