tor-browser

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

cmsrecinfo.c (26276B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /*
      6 * CMS recipientInfo methods.
      7 */
      8 
      9 #include "cmslocal.h"
     10 
     11 #include "cert.h"
     12 #include "keyhi.h"
     13 #include "secasn1.h"
     14 #include "secitem.h"
     15 #include "secoid.h"
     16 #include "pk11func.h"
     17 #include "secerr.h"
     18 #include "smime.h"
     19 
     20 PRBool
     21 nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri)
     22 {
     23    if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) {
     24        NSSCMSRecipientIdentifier *rid;
     25        rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
     26        if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) {
     27            return PR_TRUE;
     28        }
     29    }
     30    return PR_FALSE;
     31 }
     32 
     33 /*
     34 * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier
     35 * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have
     36 * been exported, and we would have added an ordinary enum to handle this
     37 * check. Unfortunatly wo don't have that luxury so we are overloading the
     38 * contentTypeTag field. NO code should every try to interpret this content tag
     39 * as a real OID tag, or use any fields other than pwfn_arg or poolp of this
     40 * CMSMessage for that matter */
     41 static const SECOidData fakeContent;
     42 NSSCMSRecipientInfo *
     43 nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg,
     44                            NSSCMSRecipientIDSelector type,
     45                            CERTCertificate *cert,
     46                            SECKEYPublicKey *pubKey,
     47                            SECItem *subjKeyID,
     48                            void *pwfn_arg,
     49                            SECItem *DERinput)
     50 {
     51    NSSCMSRecipientInfo *ri;
     52    void *mark;
     53    SECOidTag certalgtag;
     54    SECStatus rv = SECSuccess;
     55    NSSCMSRecipientEncryptedKey *rek;
     56    NSSCMSOriginatorIdentifierOrKey *oiok;
     57    unsigned long version;
     58    SECItem *dummy;
     59    PLArenaPool *poolp;
     60    CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
     61    NSSCMSRecipientIdentifier *rid;
     62    extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
     63 
     64    if (!cmsg) {
     65        /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc
     66         * and a private arena pool */
     67        cmsg = NSS_CMSMessage_Create(NULL);
     68        cmsg->pwfn_arg = pwfn_arg;
     69        /* mark it as a special cms message */
     70        cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent;
     71    }
     72 
     73    poolp = cmsg->poolp;
     74 
     75    mark = PORT_ArenaMark(poolp);
     76 
     77    ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo));
     78    if (ri == NULL)
     79        goto loser;
     80 
     81    ri->cmsg = cmsg;
     82 
     83    if (DERinput) {
     84        /* decode everything from DER */
     85        SECItem newinput;
     86        rv = SECITEM_CopyItem(poolp, &newinput, DERinput);
     87        if (SECSuccess != rv)
     88            goto loser;
     89        rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput);
     90        if (SECSuccess != rv)
     91            goto loser;
     92    }
     93 
     94    switch (type) {
     95        case NSSCMSRecipientID_IssuerSN: {
     96            ri->cert = CERT_DupCertificate(cert);
     97            if (NULL == ri->cert)
     98                goto loser;
     99            spki = &(cert->subjectPublicKeyInfo);
    100            break;
    101        }
    102 
    103        case NSSCMSRecipientID_SubjectKeyID: {
    104            PORT_Assert(pubKey);
    105            spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
    106            break;
    107        }
    108 
    109        case NSSCMSRecipientID_BrandNew:
    110            goto done;
    111            break;
    112 
    113        default:
    114            /* unkown type */
    115            goto loser;
    116            break;
    117    }
    118 
    119    certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
    120 
    121    rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
    122 
    123    // This switch must match the switch in NSS_CMSRecipient_IsSupported.
    124    switch (certalgtag) {
    125        case SEC_OID_PKCS1_RSA_ENCRYPTION:
    126            ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;
    127            rid->identifierType = type;
    128            if (type == NSSCMSRecipientID_IssuerSN) {
    129                rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
    130                if (rid->id.issuerAndSN == NULL) {
    131                    break;
    132                }
    133            } else if (type == NSSCMSRecipientID_SubjectKeyID) {
    134                NSSCMSKeyTransRecipientInfoEx *riExtra;
    135 
    136                rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
    137                if (rid->id.subjectKeyID == NULL) {
    138                    rv = SECFailure;
    139                    PORT_SetError(SEC_ERROR_NO_MEMORY);
    140                    break;
    141                }
    142                rv = SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
    143                if (rv != SECSuccess || rid->id.subjectKeyID->data == NULL) {
    144                    rv = SECFailure;
    145                    PORT_SetError(SEC_ERROR_NO_MEMORY);
    146                    break;
    147                }
    148                riExtra = &ri->ri.keyTransRecipientInfoEx;
    149                riExtra->version = 0;
    150                riExtra->pubKey = SECKEY_CopyPublicKey(pubKey);
    151                if (riExtra->pubKey == NULL) {
    152                    rv = SECFailure;
    153                    PORT_SetError(SEC_ERROR_NO_MEMORY);
    154                    break;
    155                }
    156            } else {
    157                PORT_SetError(SEC_ERROR_INVALID_ARGS);
    158                rv = SECFailure;
    159            }
    160            break;
    161        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
    162            PORT_Assert(type == NSSCMSRecipientID_IssuerSN);
    163            if (type != NSSCMSRecipientID_IssuerSN) {
    164                rv = SECFailure;
    165                break;
    166            }
    167            /* a key agreement op */
    168            ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree;
    169 
    170            /* we do not support the case where multiple recipients
    171             * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
    172             * in this case, we would need to walk all the recipientInfos, take the
    173             * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
    174             * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
    175 
    176            /* only epheremal-static Diffie-Hellman is supported for now
    177             * this is the only form of key agreement that provides potential anonymity
    178             * of the sender, plus we do not have to include certs in the message */
    179 
    180            /* force single recipientEncryptedKey for now */
    181            if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) {
    182                rv = SECFailure;
    183                break;
    184            }
    185 
    186            /* hardcoded IssuerSN choice for now */
    187            rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN;
    188            if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
    189                rv = SECFailure;
    190                break;
    191            }
    192 
    193            oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
    194 
    195            /* see RFC2630 12.3.1.1 */
    196            oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey;
    197 
    198            rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
    199                                  (void *)rek);
    200 
    201            break;
    202        default:
    203            /* other algorithms not supported yet */
    204            /* NOTE that we do not support any KEK algorithm */
    205            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    206            rv = SECFailure;
    207            break;
    208    }
    209 
    210    if (rv == SECFailure)
    211        goto loser;
    212 
    213    /* set version */
    214    switch (ri->recipientInfoType) {
    215        case NSSCMSRecipientInfoID_KeyTrans:
    216            if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN)
    217                version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
    218            else
    219                version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
    220            dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
    221            if (dummy == NULL)
    222                goto loser;
    223            break;
    224        case NSSCMSRecipientInfoID_KeyAgree:
    225            dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
    226                                          NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
    227            if (dummy == NULL)
    228                goto loser;
    229            break;
    230        case NSSCMSRecipientInfoID_KEK:
    231            /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
    232            dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
    233                                          NSS_CMS_KEK_RECIPIENT_INFO_VERSION);
    234            if (dummy == NULL)
    235                goto loser;
    236            break;
    237    }
    238 
    239 done:
    240    PORT_ArenaUnmark(poolp, mark);
    241    if (freeSpki)
    242        SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
    243    return ri;
    244 
    245 loser:
    246    if (ri && ri->cert) {
    247        CERT_DestroyCertificate(ri->cert);
    248    }
    249    if (freeSpki) {
    250        SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
    251    }
    252    PORT_ArenaRelease(poolp, mark);
    253    if (cmsg->contentInfo.contentTypeTag == &fakeContent) {
    254        NSS_CMSMessage_Destroy(cmsg);
    255    }
    256    return NULL;
    257 }
    258 
    259 /*
    260 * NSS_CMSRecipient_IsSupported - checks for a support certificate
    261 *
    262 * Use this function to confirm that the given certificate will be
    263 * accepted by NSS_CMSRecipientInfo_Create, which means that the
    264 * certificate can be used with a supported encryption algorithm.
    265 */
    266 PRBool
    267 NSS_CMSRecipient_IsSupported(CERTCertificate *cert)
    268 {
    269    CERTSubjectPublicKeyInfo *spki = &(cert->subjectPublicKeyInfo);
    270    SECOidTag certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
    271 
    272    switch (certalgtag) {
    273        case SEC_OID_PKCS1_RSA_ENCRYPTION:
    274        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
    275            return PR_TRUE;
    276        default:
    277            return PR_FALSE;
    278    }
    279 }
    280 
    281 /*
    282 * NSS_CMSRecipientInfo_Create - create a recipientinfo
    283 *
    284 * we currently do not create KeyAgreement recipientinfos with multiple
    285 * recipientEncryptedKeys the certificate is supposed to have been
    286 * verified by the caller
    287 */
    288 NSSCMSRecipientInfo *
    289 NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
    290 {
    291    return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert,
    292                                       NULL, NULL, NULL, NULL);
    293 }
    294 
    295 NSSCMSRecipientInfo *
    296 NSS_CMSRecipientInfo_CreateNew(void *pwfn_arg)
    297 {
    298    return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL,
    299                                       NULL, NULL, pwfn_arg, NULL);
    300 }
    301 
    302 NSSCMSRecipientInfo *
    303 NSS_CMSRecipientInfo_CreateFromDER(SECItem *input, void *pwfn_arg)
    304 {
    305    return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL,
    306                                       NULL, NULL, pwfn_arg, input);
    307 }
    308 
    309 NSSCMSRecipientInfo *
    310 NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg,
    311                                         SECItem *subjKeyID,
    312                                         SECKEYPublicKey *pubKey)
    313 {
    314    return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID,
    315                                       NULL, pubKey, subjKeyID, NULL, NULL);
    316 }
    317 
    318 NSSCMSRecipientInfo *
    319 NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg,
    320                                                 CERTCertificate *cert)
    321 {
    322    SECKEYPublicKey *pubKey = NULL;
    323    SECItem subjKeyID = { siBuffer, NULL, 0 };
    324    NSSCMSRecipientInfo *retVal = NULL;
    325 
    326    if (!cmsg || !cert) {
    327        return NULL;
    328    }
    329    pubKey = CERT_ExtractPublicKey(cert);
    330    if (!pubKey) {
    331        goto done;
    332    }
    333    if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
    334        subjKeyID.data == NULL) {
    335        goto done;
    336    }
    337    retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey);
    338 done:
    339    if (pubKey)
    340        SECKEY_DestroyPublicKey(pubKey);
    341 
    342    if (subjKeyID.data)
    343        SECITEM_FreeItem(&subjKeyID, PR_FALSE);
    344 
    345    return retVal;
    346 }
    347 
    348 void
    349 NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri)
    350 {
    351    if (!ri) {
    352        return;
    353    }
    354    /* version was allocated on the pool, so no need to destroy it */
    355    /* issuerAndSN was allocated on the pool, so no need to destroy it */
    356    if (ri->cert != NULL)
    357        CERT_DestroyCertificate(ri->cert);
    358 
    359    if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
    360        NSSCMSKeyTransRecipientInfoEx *extra;
    361        extra = &ri->ri.keyTransRecipientInfoEx;
    362        if (extra->pubKey)
    363            SECKEY_DestroyPublicKey(extra->pubKey);
    364    }
    365    if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) {
    366        NSS_CMSMessage_Destroy(ri->cmsg);
    367    }
    368 
    369    /* we're done. */
    370 }
    371 
    372 int
    373 NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri)
    374 {
    375    unsigned long version;
    376    SECItem *versionitem = NULL;
    377 
    378    switch (ri->recipientInfoType) {
    379        case NSSCMSRecipientInfoID_KeyTrans:
    380            /* ignore subIndex */
    381            versionitem = &(ri->ri.keyTransRecipientInfo.version);
    382            break;
    383        case NSSCMSRecipientInfoID_KEK:
    384            /* ignore subIndex */
    385            versionitem = &(ri->ri.kekRecipientInfo.version);
    386            break;
    387        case NSSCMSRecipientInfoID_KeyAgree:
    388            versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
    389            break;
    390    }
    391 
    392    PORT_Assert(versionitem);
    393    if (versionitem == NULL)
    394        return 0;
    395 
    396    /* always take apart the SECItem */
    397    if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
    398        return 0;
    399    else
    400        return (int)version;
    401 }
    402 
    403 SECItem *
    404 NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex)
    405 {
    406    SECItem *enckey = NULL;
    407 
    408    switch (ri->recipientInfoType) {
    409        case NSSCMSRecipientInfoID_KeyTrans:
    410            /* ignore subIndex */
    411            enckey = &(ri->ri.keyTransRecipientInfo.encKey);
    412            break;
    413        case NSSCMSRecipientInfoID_KEK:
    414            /* ignore subIndex */
    415            enckey = &(ri->ri.kekRecipientInfo.encKey);
    416            break;
    417        case NSSCMSRecipientInfoID_KeyAgree:
    418            enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
    419            break;
    420    }
    421    return enckey;
    422 }
    423 
    424 SECOidTag
    425 NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri)
    426 {
    427    SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
    428 
    429    switch (ri->recipientInfoType) {
    430        case NSSCMSRecipientInfoID_KeyTrans:
    431            encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
    432            break;
    433        case NSSCMSRecipientInfoID_KeyAgree:
    434            encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
    435            break;
    436        case NSSCMSRecipientInfoID_KEK:
    437            encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
    438            break;
    439    }
    440    return encalgtag;
    441 }
    442 
    443 SECStatus
    444 NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
    445                                 SECOidTag bulkalgtag)
    446 {
    447    CERTCertificate *cert;
    448    SECOidTag certalgtag;
    449    SECStatus rv = SECSuccess;
    450    NSSCMSRecipientEncryptedKey *rek;
    451    NSSCMSOriginatorIdentifierOrKey *oiok;
    452    CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
    453    PLArenaPool *poolp;
    454    NSSCMSKeyTransRecipientInfoEx *extra = NULL;
    455    PRBool usesSubjKeyID;
    456    void *wincx = NULL;
    457 
    458    poolp = ri->cmsg->poolp;
    459    cert = ri->cert;
    460    usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
    461    if (cert) {
    462        spki = &cert->subjectPublicKeyInfo;
    463    } else if (usesSubjKeyID) {
    464        extra = &ri->ri.keyTransRecipientInfoEx;
    465        /* sanity check */
    466        PORT_Assert(extra->pubKey);
    467        if (!extra->pubKey) {
    468            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    469            return SECFailure;
    470        }
    471        spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey);
    472    } else {
    473        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    474        return SECFailure;
    475    }
    476 
    477    /* XXX set ri->recipientInfoType to the proper value here */
    478    /* or should we look if it's been set already ? */
    479 
    480    certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
    481    if (!NSS_SMIMEUtil_KeyEncodingAllowed(&spki->algorithm, cert, extra ? extra->pubKey : NULL)) {
    482        PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
    483        rv = SECFailure;
    484        goto loser;
    485    }
    486    switch (certalgtag) {
    487        case SEC_OID_PKCS1_RSA_ENCRYPTION:
    488            /* wrap the symkey */
    489            if (cert) {
    490                rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey,
    491                                                   &ri->ri.keyTransRecipientInfo.encKey);
    492                if (rv != SECSuccess)
    493                    break;
    494            } else if (usesSubjKeyID) {
    495                PORT_Assert(extra != NULL);
    496                rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey,
    497                                                         bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
    498                if (rv != SECSuccess)
    499                    break;
    500            }
    501 
    502            rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
    503            break;
    504        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
    505            rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
    506            if (rek == NULL) {
    507                rv = SECFailure;
    508                break;
    509            }
    510 
    511            oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
    512            PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey);
    513 
    514            /* see RFC2630 12.3.1.1 */
    515            if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
    516                                      certalgtag, NULL) != SECSuccess) {
    517                rv = SECFailure;
    518                break;
    519            }
    520 
    521            /* this will generate a key pair, compute the shared secret, */
    522            /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
    523            /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
    524            switch (certalgtag) {
    525                case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
    526                    if (ri->cmsg) {
    527                        wincx = ri->cmsg->pwfn_arg;
    528                    } else {
    529                        wincx = PK11_GetWindow(bulkkey);
    530                    }
    531                    rv = NSS_CMSUtil_EncryptSymKey_ESECDH(poolp, cert, bulkkey,
    532                                                          &rek->encKey,
    533                                                          PR_TRUE,
    534                                                          &ri->ri.keyAgreeRecipientInfo.ukm,
    535                                                          &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
    536                                                          &oiok->id.originatorPublicKey.publicKey,
    537                                                          wincx);
    538                    break;
    539 
    540                default:
    541                    /* Not reached. Added to silence enum warnings. */
    542                    PORT_Assert(0);
    543                    break;
    544            }
    545            break;
    546        default:
    547            /* other algorithms not supported yet */
    548            /* NOTE that we do not support any KEK algorithm */
    549            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    550            rv = SECFailure;
    551    }
    552 loser:
    553    if (freeSpki)
    554        SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
    555 
    556    return rv;
    557 }
    558 
    559 PK11SymKey *
    560 NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex,
    561                                   CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag)
    562 {
    563    PK11SymKey *bulkkey = NULL;
    564    SECAlgorithmID *algid;
    565    SECOidTag encalgtag;
    566    SECItem *enckey = NULL, *ukm = NULL, *parameters = NULL;
    567    NSSCMSOriginatorIdentifierOrKey *oiok = NULL;
    568    int error;
    569    void *wincx = NULL;
    570 
    571    ri->cert = CERT_DupCertificate(cert);
    572    /* mark the recipientInfo so we can find it later */
    573 
    574    switch (ri->recipientInfoType) {
    575        case NSSCMSRecipientInfoID_KeyTrans:
    576            algid = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
    577            parameters = &(ri->ri.keyTransRecipientInfo.keyEncAlg.parameters);
    578            enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
    579            break;
    580        case NSSCMSRecipientInfoID_KeyAgree:
    581            algid = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
    582            parameters = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg.parameters);
    583            enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
    584            oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
    585            ukm = &(ri->ri.keyAgreeRecipientInfo.ukm);
    586            break;
    587        case NSSCMSRecipientInfoID_KEK:
    588            algid = &(ri->ri.kekRecipientInfo.keyEncAlg);
    589            parameters = &(ri->ri.kekRecipientInfo.keyEncAlg.parameters);
    590            enckey = &(ri->ri.kekRecipientInfo.encKey);
    591            /* not supported yet */
    592        default:
    593            error = SEC_ERROR_UNSUPPORTED_KEYALG;
    594            goto loser;
    595            break;
    596    }
    597    if (!NSS_SMIMEUtil_KeyDecodingAllowed(algid, privkey)) {
    598        error = SEC_ERROR_BAD_EXPORT_ALGORITHM;
    599        goto loser;
    600    }
    601    encalgtag = SECOID_GetAlgorithmTag(algid);
    602    switch (encalgtag) {
    603        case SEC_OID_PKCS1_RSA_ENCRYPTION:
    604            /* RSA encryption algorithm: */
    605            if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyTrans) {
    606                error = SEC_ERROR_UNSUPPORTED_KEYALG;
    607                goto loser;
    608            }
    609            /* get the symmetric (bulk) key by unwrapping it using our private key */
    610            bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag);
    611            break;
    612        case SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION:
    613            /* RSA OAEP encryption algorithm: */
    614            if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyTrans) {
    615                error = SEC_ERROR_UNSUPPORTED_KEYALG;
    616                goto loser;
    617            }
    618            /* get the symmetric (bulk) key by unwrapping it using our private key */
    619            bulkkey = NSS_CMSUtil_DecryptSymKey_RSA_OAEP(privkey, parameters, enckey,
    620                                                         bulkalgtag);
    621            break;
    622        case SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME:
    623        case SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME:
    624        case SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME:
    625        case SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME:
    626        case SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME:
    627        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME:
    628        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME:
    629        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME:
    630        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME:
    631        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME:
    632            if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyAgree) {
    633                error = SEC_ERROR_UNSUPPORTED_KEYALG;
    634                goto loser;
    635            }
    636            if (ri->cmsg) {
    637                wincx = ri->cmsg->pwfn_arg;
    638            }
    639            bulkkey = NSS_CMSUtil_DecryptSymKey_ECDH(privkey, enckey, algid,
    640                                                     bulkalgtag, ukm, oiok, wincx);
    641            break;
    642        default:
    643            error = SEC_ERROR_UNSUPPORTED_KEYALG;
    644            goto loser;
    645    }
    646    /* XXXX continue here */
    647    return bulkkey;
    648 
    649 loser:
    650    PORT_SetError(error);
    651    return NULL;
    652 }
    653 
    654 SECStatus
    655 NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri,
    656                                   CERTCertificate **retcert,
    657                                   SECKEYPrivateKey **retkey)
    658 {
    659    CERTCertificate *cert = NULL;
    660    NSSCMSRecipient **recipients = NULL;
    661    NSSCMSRecipientInfo *recipientInfos[2];
    662    SECStatus rv = SECSuccess;
    663    SECKEYPrivateKey *key = NULL;
    664 
    665    if (!ri)
    666        return SECFailure;
    667 
    668    if (!retcert && !retkey) {
    669        /* nothing requested, nothing found, success */
    670        return SECSuccess;
    671    }
    672 
    673    if (retcert) {
    674        *retcert = NULL;
    675    }
    676    if (retkey) {
    677        *retkey = NULL;
    678    }
    679 
    680    if (ri->cert) {
    681        cert = CERT_DupCertificate(ri->cert);
    682        if (!cert) {
    683            rv = SECFailure;
    684        }
    685    }
    686    if (SECSuccess == rv && !cert) {
    687        /* we don't have the cert, we have to look for it */
    688        /* first build an NSS_CMSRecipient */
    689        recipientInfos[0] = ri;
    690        recipientInfos[1] = NULL;
    691 
    692        recipients = nss_cms_recipient_list_create(recipientInfos);
    693        if (recipients) {
    694            /* now look for the cert and key */
    695            if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients,
    696                                                           ri->cmsg->pwfn_arg)) {
    697                cert = CERT_DupCertificate(recipients[0]->cert);
    698                key = SECKEY_CopyPrivateKey(recipients[0]->privkey);
    699            } else {
    700                rv = SECFailure;
    701            }
    702 
    703            nss_cms_recipient_list_destroy(recipients);
    704        } else {
    705            rv = SECFailure;
    706        }
    707    } else if (SECSuccess == rv && cert && retkey) {
    708        /* we have the cert, we just need the key now */
    709        key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg);
    710    }
    711    if (retcert) {
    712        *retcert = cert;
    713    } else {
    714        if (cert) {
    715            CERT_DestroyCertificate(cert);
    716        }
    717    }
    718    if (retkey) {
    719        *retkey = key;
    720    } else {
    721        if (key) {
    722            SECKEY_DestroyPrivateKey(key);
    723        }
    724    }
    725 
    726    return rv;
    727 }
    728 
    729 SECStatus
    730 NSS_CMSRecipientInfo_Encode(PLArenaPool *poolp,
    731                            const NSSCMSRecipientInfo *src,
    732                            SECItem *returned)
    733 {
    734    extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
    735    SECStatus rv = SECFailure;
    736    if (!src || !returned) {
    737        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    738    } else if (SEC_ASN1EncodeItem(poolp, returned, src,
    739                                  NSSCMSRecipientInfoTemplate)) {
    740        rv = SECSuccess;
    741    }
    742    return rv;
    743 }