tor-browser

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

cmsencdata.c (7988B)


      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 encryptedData methods.
      7 */
      8 
      9 #include "cmslocal.h"
     10 
     11 #include "keyhi.h"
     12 #include "secasn1.h"
     13 #include "secitem.h"
     14 #include "secoid.h"
     15 #include "pk11func.h"
     16 #include "prtime.h"
     17 #include "secerr.h"
     18 #include "secpkcs5.h"
     19 #include "smime.h"
     20 
     21 /*
     22 * NSS_CMSEncryptedData_Create - create an empty encryptedData object.
     23 *
     24 * "algorithm" specifies the bulk encryption algorithm to use.
     25 * "keysize" is the key size.
     26 *
     27 * An error results in a return value of NULL and an error set.
     28 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
     29 */
     30 NSSCMSEncryptedData *
     31 NSS_CMSEncryptedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm,
     32                            int keysize)
     33 {
     34    void *mark;
     35    NSSCMSEncryptedData *encd;
     36    PLArenaPool *poolp;
     37    SECAlgorithmID *pbe_algid;
     38    SECStatus rv;
     39 
     40    poolp = cmsg->poolp;
     41 
     42    mark = PORT_ArenaMark(poolp);
     43 
     44    encd = PORT_ArenaZNew(poolp, NSSCMSEncryptedData);
     45    if (encd == NULL)
     46        goto loser;
     47 
     48    encd->cmsg = cmsg;
     49 
     50    /* version is set in NSS_CMSEncryptedData_Encode_BeforeStart() */
     51 
     52    if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
     53        rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, &(encd->contentInfo),
     54                                                 algorithm, NULL, keysize);
     55    } else {
     56        /* Assume password-based-encryption.
     57         * Note: we can't generate pkcs5v2 from this interface.
     58         * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
     59         * non-PBE oids and assuming that they are pkcs5v2 oids, but
     60         * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
     61         * CMS encrypted data, so we can't tell NSS_CMS_EncryptedData_Create
     62         * to create pkcs5v2 PBEs */
     63        pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
     64        if (pbe_algid == NULL) {
     65            rv = SECFailure;
     66        } else {
     67            rv = NSS_CMSContentInfo_SetContentEncAlgID(poolp,
     68                                                       &(encd->contentInfo),
     69                                                       pbe_algid, keysize);
     70            SECOID_DestroyAlgorithmID(pbe_algid, PR_TRUE);
     71        }
     72    }
     73    if (rv != SECSuccess)
     74        goto loser;
     75 
     76    PORT_ArenaUnmark(poolp, mark);
     77    return encd;
     78 
     79 loser:
     80    PORT_ArenaRelease(poolp, mark);
     81    return NULL;
     82 }
     83 
     84 /*
     85 * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
     86 */
     87 void
     88 NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd)
     89 {
     90    /* everything's in a pool, so don't worry about the storage */
     91    if (encd != NULL) {
     92        NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
     93    }
     94    return;
     95 }
     96 
     97 /*
     98 * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
     99 */
    100 NSSCMSContentInfo *
    101 NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd)
    102 {
    103    return &(encd->contentInfo);
    104 }
    105 
    106 /*
    107 * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
    108 *     before encoding begins.
    109 *
    110 * In particular:
    111 *  - set the correct version value.
    112 *  - get the encryption key
    113 */
    114 SECStatus
    115 NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd)
    116 {
    117    int version;
    118    PK11SymKey *bulkkey = NULL;
    119    SECItem *dummy;
    120    NSSCMSContentInfo *cinfo = &(encd->contentInfo);
    121    SECAlgorithmID *algid = NULL;
    122 
    123    if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr))
    124        version = NSS_CMS_ENCRYPTED_DATA_VERSION;
    125    else
    126        version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
    127 
    128    dummy = SEC_ASN1EncodeInteger(encd->cmsg->poolp, &(encd->version), version);
    129    if (dummy == NULL)
    130        return SECFailure;
    131 
    132    /* now get content encryption key (bulk key) by using our cmsg callback */
    133    if (encd->cmsg->decrypt_key_cb) {
    134        algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
    135        bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, algid);
    136    }
    137    if ((bulkkey == NULL) || (algid == NULL))
    138        return SECFailure;
    139 
    140    /* store the bulk key in the contentInfo so that the encoder can find it */
    141    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
    142    PK11_FreeSymKey(bulkkey);
    143 
    144    return SECSuccess;
    145 }
    146 
    147 /*
    148 * NSS_CMSEncryptedData_Encode_BeforeData - set up encryption
    149 */
    150 SECStatus
    151 NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd)
    152 {
    153    NSSCMSContentInfo *cinfo;
    154    PK11SymKey *bulkkey = NULL;
    155    SECAlgorithmID *algid;
    156    SECStatus rv = SECFailure;
    157 
    158    cinfo = &(encd->contentInfo);
    159 
    160    /* find bulkkey and algorithm - must have been set by NSS_CMSEncryptedData_Encode_BeforeStart */
    161    bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
    162    if (bulkkey == NULL) {
    163        goto loser;
    164    }
    165 
    166    algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
    167    if (algid == NULL) {
    168        goto loser;
    169    }
    170 
    171    rv = NSS_CMSContentInfo_Private_Init(cinfo);
    172    if (rv != SECSuccess) {
    173        goto loser;
    174    }
    175 
    176    if (!NSS_SMIMEUtil_EncryptionAllowed(algid, bulkkey)) {
    177        goto loser;
    178    }
    179 
    180    /* this may modify algid (with IVs generated in a token).
    181     * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
    182     * not just to a copy */
    183    cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp,
    184                                                                   bulkkey, algid);
    185    if (cinfo->privateInfo->ciphcx == NULL)
    186        goto loser;
    187 
    188    rv = SECSuccess;
    189 
    190 loser:
    191    if (bulkkey) {
    192        PK11_FreeSymKey(bulkkey);
    193    }
    194    return rv;
    195 }
    196 
    197 /*
    198 * NSS_CMSEncryptedData_Encode_AfterData - finalize this encryptedData for encoding
    199 */
    200 SECStatus
    201 NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd)
    202 {
    203    if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
    204        NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
    205        encd->contentInfo.privateInfo->ciphcx = NULL;
    206    }
    207 
    208    /* nothing to do after data */
    209    return SECSuccess;
    210 }
    211 
    212 /*
    213 * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption
    214 */
    215 SECStatus
    216 NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd)
    217 {
    218    PK11SymKey *bulkkey = NULL;
    219    NSSCMSContentInfo *cinfo;
    220    SECAlgorithmID *bulkalg;
    221    SECStatus rv = SECFailure;
    222 
    223    cinfo = &(encd->contentInfo);
    224 
    225    bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
    226 
    227    if (encd->cmsg->decrypt_key_cb == NULL) /* no callback? no key../ */
    228        goto loser;
    229 
    230    bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
    231    if (bulkkey == NULL)
    232        /* no success finding a bulk key */
    233        goto loser;
    234 
    235    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
    236 
    237    rv = NSS_CMSContentInfo_Private_Init(cinfo);
    238    if (rv != SECSuccess) {
    239        goto loser;
    240    }
    241    rv = SECFailure;
    242 
    243    if (!NSS_SMIMEUtil_DecryptionAllowed(bulkalg, bulkkey)) {
    244        goto loser;
    245    }
    246 
    247    cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg);
    248    if (cinfo->privateInfo->ciphcx == NULL)
    249        goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */
    250    rv = SECSuccess;
    251 
    252 loser:
    253    if (bulkkey) {
    254        PK11_FreeSymKey(bulkkey);
    255    }
    256    return rv;
    257 }
    258 
    259 /*
    260 * NSS_CMSEncryptedData_Decode_AfterData - finish decrypting this encryptedData's content
    261 */
    262 SECStatus
    263 NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd)
    264 {
    265    if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
    266        NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
    267        encd->contentInfo.privateInfo->ciphcx = NULL;
    268    }
    269 
    270    return SECSuccess;
    271 }
    272 
    273 /*
    274 * NSS_CMSEncryptedData_Decode_AfterEnd - finish decoding this encryptedData
    275 */
    276 SECStatus
    277 NSS_CMSEncryptedData_Decode_AfterEnd(NSSCMSEncryptedData *encd)
    278 {
    279    /* apply final touches */
    280    return SECSuccess;
    281 }