tor-browser

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

p7common.c (19796B)


      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 * PKCS7 implementation -- the exported parts that are used whether
      7 * creating or decoding.
      8 */
      9 
     10 #include "p7local.h"
     11 
     12 #include "cert.h"
     13 #include "secitem.h"
     14 #include "secoid.h"
     15 #include "pk11func.h"
     16 
     17 /*
     18 * Find out (saving pointer to lookup result for future reference)
     19 * and return the inner content type.
     20 */
     21 SECOidTag
     22 SEC_PKCS7ContentType(SEC_PKCS7ContentInfo *cinfo)
     23 {
     24    if (cinfo->contentTypeTag == NULL)
     25        cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
     26 
     27    if (cinfo->contentTypeTag == NULL)
     28        return SEC_OID_UNKNOWN;
     29 
     30    return cinfo->contentTypeTag->offset;
     31 }
     32 
     33 /*
     34 * Destroy a PKCS7 contentInfo and all of its sub-pieces.
     35 */
     36 void
     37 SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo)
     38 {
     39    SECOidTag kind;
     40    CERTCertificate **certs;
     41    CERTCertificateList **certlists;
     42    SEC_PKCS7SignerInfo **signerinfos;
     43    SEC_PKCS7RecipientInfo **recipientinfos;
     44 
     45    PORT_Assert(cinfo->refCount > 0);
     46    if (cinfo->refCount <= 0)
     47        return;
     48 
     49    cinfo->refCount--;
     50    if (cinfo->refCount > 0)
     51        return;
     52 
     53    certs = NULL;
     54    certlists = NULL;
     55    recipientinfos = NULL;
     56    signerinfos = NULL;
     57 
     58    kind = SEC_PKCS7ContentType(cinfo);
     59    switch (kind) {
     60        case SEC_OID_PKCS7_ENVELOPED_DATA: {
     61            SEC_PKCS7EnvelopedData *edp;
     62 
     63            edp = cinfo->content.envelopedData;
     64            if (edp != NULL) {
     65                recipientinfos = edp->recipientInfos;
     66            }
     67        } break;
     68        case SEC_OID_PKCS7_SIGNED_DATA: {
     69            SEC_PKCS7SignedData *sdp;
     70 
     71            sdp = cinfo->content.signedData;
     72            if (sdp != NULL) {
     73                certs = sdp->certs;
     74                certlists = sdp->certLists;
     75                signerinfos = sdp->signerInfos;
     76            }
     77        } break;
     78        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
     79            SEC_PKCS7SignedAndEnvelopedData *saedp;
     80 
     81            saedp = cinfo->content.signedAndEnvelopedData;
     82            if (saedp != NULL) {
     83                certs = saedp->certs;
     84                certlists = saedp->certLists;
     85                recipientinfos = saedp->recipientInfos;
     86                signerinfos = saedp->signerInfos;
     87                if (saedp->sigKey != NULL)
     88                    PK11_FreeSymKey(saedp->sigKey);
     89            }
     90        } break;
     91        default:
     92            /* XXX Anything else that needs to be "manually" freed/destroyed? */
     93            break;
     94    }
     95 
     96    if (certs != NULL) {
     97        CERTCertificate *cert;
     98 
     99        while ((cert = *certs++) != NULL) {
    100            CERT_DestroyCertificate(cert);
    101        }
    102    }
    103 
    104    if (certlists != NULL) {
    105        CERTCertificateList *certlist;
    106 
    107        while ((certlist = *certlists++) != NULL) {
    108            CERT_DestroyCertificateList(certlist);
    109        }
    110    }
    111 
    112    if (recipientinfos != NULL) {
    113        SEC_PKCS7RecipientInfo *ri;
    114 
    115        while ((ri = *recipientinfos++) != NULL) {
    116            if (ri->cert != NULL)
    117                CERT_DestroyCertificate(ri->cert);
    118        }
    119    }
    120 
    121    if (signerinfos != NULL) {
    122        SEC_PKCS7SignerInfo *si;
    123 
    124        while ((si = *signerinfos++) != NULL) {
    125            if (si->cert != NULL)
    126                CERT_DestroyCertificate(si->cert);
    127            if (si->certList != NULL)
    128                CERT_DestroyCertificateList(si->certList);
    129        }
    130    }
    131 
    132    if (cinfo->poolp != NULL) {
    133        PORT_FreeArena(cinfo->poolp, PR_FALSE); /* XXX clear it? */
    134    }
    135 }
    136 
    137 /*
    138 * Return a copy of the given contentInfo.  The copy may be virtual
    139 * or may be real -- either way, the result needs to be passed to
    140 * SEC_PKCS7DestroyContentInfo later (as does the original).
    141 */
    142 SEC_PKCS7ContentInfo *
    143 SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *cinfo)
    144 {
    145    if (cinfo == NULL)
    146        return NULL;
    147 
    148    PORT_Assert(cinfo->refCount > 0);
    149 
    150    if (cinfo->created) {
    151        /*
    152         * Want to do a real copy of these; otherwise subsequent
    153         * changes made to either copy are likely to be a surprise.
    154         * XXX I suspect that this will not actually be called for yet,
    155         * which is why the assert, so to notice if it is...
    156         */
    157        PORT_Assert(0);
    158        /*
    159         * XXX Create a new pool here, and copy everything from
    160         * within.  For cert stuff, need to call the appropriate
    161         * copy functions, etc.
    162         */
    163    }
    164 
    165    cinfo->refCount++;
    166    return cinfo;
    167 }
    168 
    169 /*
    170 * Return a pointer to the actual content.  In the case of those types
    171 * which are encrypted, this returns the *plain* content.
    172 * XXX Needs revisiting if/when we handle nested encrypted types.
    173 */
    174 SECItem *
    175 SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo)
    176 {
    177    SECOidTag kind;
    178 
    179    kind = SEC_PKCS7ContentType(cinfo);
    180    switch (kind) {
    181        case SEC_OID_PKCS7_DATA:
    182            return cinfo->content.data;
    183        case SEC_OID_PKCS7_DIGESTED_DATA: {
    184            SEC_PKCS7DigestedData *digd;
    185 
    186            digd = cinfo->content.digestedData;
    187            if (digd == NULL)
    188                break;
    189            return SEC_PKCS7GetContent(&(digd->contentInfo));
    190        }
    191        case SEC_OID_PKCS7_ENCRYPTED_DATA: {
    192            SEC_PKCS7EncryptedData *encd;
    193 
    194            encd = cinfo->content.encryptedData;
    195            if (encd == NULL)
    196                break;
    197            return &(encd->encContentInfo.plainContent);
    198        }
    199        case SEC_OID_PKCS7_ENVELOPED_DATA: {
    200            SEC_PKCS7EnvelopedData *envd;
    201 
    202            envd = cinfo->content.envelopedData;
    203            if (envd == NULL)
    204                break;
    205            return &(envd->encContentInfo.plainContent);
    206        }
    207        case SEC_OID_PKCS7_SIGNED_DATA: {
    208            SEC_PKCS7SignedData *sigd;
    209 
    210            sigd = cinfo->content.signedData;
    211            if (sigd == NULL)
    212                break;
    213            return SEC_PKCS7GetContent(&(sigd->contentInfo));
    214        }
    215        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
    216            SEC_PKCS7SignedAndEnvelopedData *saed;
    217 
    218            saed = cinfo->content.signedAndEnvelopedData;
    219            if (saed == NULL)
    220                break;
    221            return &(saed->encContentInfo.plainContent);
    222        }
    223        default:
    224            PORT_Assert(0);
    225            break;
    226    }
    227 
    228    return NULL;
    229 }
    230 
    231 /*
    232 * XXX Fix the placement and formatting of the
    233 * following routines (i.e. make them consistent with the rest of
    234 * the pkcs7 code -- I think some/many belong in other files and
    235 * they all need a formatting/style rehaul)
    236 */
    237 
    238 /* retrieve the algorithm identifier for encrypted data.
    239 * the identifier returned is a copy of the algorithm identifier
    240 * in the content info and needs to be freed after being used.
    241 *
    242 *   cinfo is the content info for which to retrieve the
    243 *     encryption algorithm.
    244 *
    245 * if the content info is not encrypted data or an error
    246 * occurs NULL is returned.
    247 */
    248 SECAlgorithmID *
    249 SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo)
    250 {
    251    SECAlgorithmID *alg = 0;
    252    switch (SEC_PKCS7ContentType(cinfo)) {
    253        case SEC_OID_PKCS7_ENCRYPTED_DATA:
    254            alg = &cinfo->content.encryptedData->encContentInfo.contentEncAlg;
    255            break;
    256        case SEC_OID_PKCS7_ENVELOPED_DATA:
    257            alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg;
    258            break;
    259        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
    260            alg = &cinfo->content.signedAndEnvelopedData
    261                       ->encContentInfo.contentEncAlg;
    262            break;
    263        default:
    264            alg = 0;
    265            break;
    266    }
    267 
    268    return alg;
    269 }
    270 
    271 /* set the content of the content info.  For data content infos,
    272 * the data is set.  For encrytped content infos, the plainContent
    273 * is set, and is expected to be encrypted later.
    274 *
    275 * cinfo is the content info where the data will be set
    276 *
    277 * buf is a buffer of the data to set
    278 *
    279 * len is the length of the data being set.
    280 *
    281 * in the event of an error, SECFailure is returned.  SECSuccess
    282 * indicates the content was successfully set.
    283 */
    284 SECStatus
    285 SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
    286                    const char *buf,
    287                    unsigned long len)
    288 {
    289    SECOidTag cinfo_type;
    290    SECStatus rv;
    291    SECItem content;
    292    SECOidData *contentTypeTag = NULL;
    293 
    294    content.type = siBuffer;
    295    content.data = (unsigned char *)buf;
    296    content.len = len;
    297 
    298    cinfo_type = SEC_PKCS7ContentType(cinfo);
    299 
    300    /* set inner content */
    301    switch (cinfo_type) {
    302        case SEC_OID_PKCS7_SIGNED_DATA:
    303            if (content.len > 0) {
    304                /* we "leak" the old content here, but as it's all in the pool */
    305                /* it does not really matter */
    306 
    307                /* create content item if necessary */
    308                if (cinfo->content.signedData->contentInfo.content.data == NULL)
    309                    cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0);
    310                rv = SECITEM_CopyItem(cinfo->poolp,
    311                                      cinfo->content.signedData->contentInfo.content.data,
    312                                      &content);
    313            } else {
    314                cinfo->content.signedData->contentInfo.content.data->data = NULL;
    315                cinfo->content.signedData->contentInfo.content.data->len = 0;
    316                rv = SECSuccess;
    317            }
    318            if (rv == SECFailure)
    319                goto loser;
    320 
    321            break;
    322        case SEC_OID_PKCS7_ENCRYPTED_DATA:
    323            /* XXX this forces the inner content type to be "data" */
    324            /* do we really want to override without asking or reason? */
    325            contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
    326            if (contentTypeTag == NULL)
    327                goto loser;
    328            rv = SECITEM_CopyItem(cinfo->poolp,
    329                                  &(cinfo->content.encryptedData->encContentInfo.contentType),
    330                                  &(contentTypeTag->oid));
    331            if (rv == SECFailure)
    332                goto loser;
    333            if (content.len > 0) {
    334                rv = SECITEM_CopyItem(cinfo->poolp,
    335                                      &(cinfo->content.encryptedData->encContentInfo.plainContent),
    336                                      &content);
    337            } else {
    338                cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL;
    339                cinfo->content.encryptedData->encContentInfo.encContent.data = NULL;
    340                cinfo->content.encryptedData->encContentInfo.plainContent.len = 0;
    341                cinfo->content.encryptedData->encContentInfo.encContent.len = 0;
    342                rv = SECSuccess;
    343            }
    344            if (rv == SECFailure)
    345                goto loser;
    346            break;
    347        case SEC_OID_PKCS7_DATA:
    348            cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp,
    349                                                              sizeof(SECItem));
    350            if (cinfo->content.data == NULL)
    351                goto loser;
    352            if (content.len > 0) {
    353                rv = SECITEM_CopyItem(cinfo->poolp,
    354                                      cinfo->content.data, &content);
    355            } else {
    356                /* handle case with NULL content */
    357                rv = SECSuccess;
    358            }
    359            if (rv == SECFailure)
    360                goto loser;
    361            break;
    362        default:
    363            goto loser;
    364    }
    365 
    366    return SECSuccess;
    367 
    368 loser:
    369 
    370    return SECFailure;
    371 }
    372 
    373 /* the content of an encrypted data content info is encrypted.
    374 * it is assumed that for encrypted data, that the data has already
    375 * been set and is in the "plainContent" field of the content info.
    376 *
    377 * cinfo is the content info to encrypt
    378 *
    379 * key is the key with which to perform the encryption.  if the
    380 *     algorithm is a password based encryption algorithm, the
    381 *     key is actually a password which will be processed per
    382 *     PKCS #5.
    383 *
    384 * in the event of an error, SECFailure is returned.  SECSuccess
    385 * indicates a success.
    386 */
    387 SECStatus
    388 SEC_PKCS7EncryptContents(PLArenaPool *poolp,
    389                         SEC_PKCS7ContentInfo *cinfo,
    390                         SECItem *key,
    391                         void *wincx)
    392 {
    393    SECAlgorithmID *algid = NULL;
    394    SECItem *src;
    395    SECItem *dest;
    396    SECItem *blocked_data = NULL;
    397    void *mark;
    398    void *cx;
    399    PK11SymKey *eKey = NULL;
    400    PK11SlotInfo *slot = NULL;
    401 
    402    CK_MECHANISM_TYPE cryptoMechType;
    403    int bs;
    404    SECStatus rv = SECFailure;
    405    SECItem *c_param = NULL;
    406 
    407    if ((cinfo == NULL) || (key == NULL))
    408        return SECFailure;
    409 
    410    if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
    411        return SECFailure;
    412 
    413    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
    414    if (algid == NULL)
    415        return SECFailure;
    416 
    417    if (poolp == NULL)
    418        poolp = cinfo->poolp;
    419 
    420    mark = PORT_ArenaMark(poolp);
    421 
    422    src = &cinfo->content.encryptedData->encContentInfo.plainContent;
    423    dest = &cinfo->content.encryptedData->encContentInfo.encContent;
    424    dest->data = (unsigned char *)PORT_ArenaZAlloc(poolp, (src->len + 64));
    425    dest->len = (src->len + 64);
    426    if (dest->data == NULL) {
    427        rv = SECFailure;
    428        goto loser;
    429    }
    430 
    431    slot = PK11_GetInternalKeySlot();
    432    if (slot == NULL) {
    433        rv = SECFailure;
    434        goto loser;
    435    }
    436 
    437    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
    438    if (eKey == NULL) {
    439        rv = SECFailure;
    440        goto loser;
    441    }
    442 
    443    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
    444    if (cryptoMechType == CKM_INVALID_MECHANISM) {
    445        rv = SECFailure;
    446        goto loser;
    447    }
    448 
    449    /* block according to PKCS 8 */
    450    bs = PK11_GetBlockSize(cryptoMechType, c_param);
    451    rv = SECSuccess;
    452    if (bs) {
    453        char pad_char;
    454        pad_char = (char)(bs - (src->len % bs));
    455        if (src->len % bs) {
    456            rv = SECSuccess;
    457            blocked_data = PK11_BlockData(src, bs);
    458            if (blocked_data) {
    459                PORT_Memset((blocked_data->data + blocked_data->len - (int)pad_char),
    460                            pad_char, (int)pad_char);
    461            } else {
    462                rv = SECFailure;
    463                goto loser;
    464            }
    465        } else {
    466            blocked_data = SECITEM_DupItem(src);
    467            if (blocked_data) {
    468                blocked_data->data = (unsigned char *)PORT_Realloc(
    469                    blocked_data->data,
    470                    blocked_data->len + bs);
    471                if (blocked_data->data) {
    472                    blocked_data->len += bs;
    473                    PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
    474                } else {
    475                    rv = SECFailure;
    476                    goto loser;
    477                }
    478            } else {
    479                rv = SECFailure;
    480                goto loser;
    481            }
    482        }
    483    } else {
    484        blocked_data = SECITEM_DupItem(src);
    485        if (!blocked_data) {
    486            rv = SECFailure;
    487            goto loser;
    488        }
    489    }
    490 
    491    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
    492                                    eKey, c_param);
    493    if (cx == NULL) {
    494        rv = SECFailure;
    495        goto loser;
    496    }
    497 
    498    rv = PK11_CipherOp((PK11Context *)cx, dest->data, (int *)(&dest->len),
    499                       (int)(src->len + 64), blocked_data->data,
    500                       (int)blocked_data->len);
    501    PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
    502 
    503 loser:
    504    /* let success fall through */
    505    if (blocked_data != NULL)
    506        SECITEM_ZfreeItem(blocked_data, PR_TRUE);
    507 
    508    if (rv == SECFailure)
    509        PORT_ArenaRelease(poolp, mark);
    510    else
    511        PORT_ArenaUnmark(poolp, mark);
    512 
    513    if (eKey != NULL)
    514        PK11_FreeSymKey(eKey);
    515 
    516    if (slot != NULL)
    517        PK11_FreeSlot(slot);
    518 
    519    if (c_param != NULL)
    520        SECITEM_ZfreeItem(c_param, PR_TRUE);
    521 
    522    return rv;
    523 }
    524 
    525 /* the content of an encrypted data content info is decrypted.
    526 * it is assumed that for encrypted data, that the data has already
    527 * been set and is in the "encContent" field of the content info.
    528 *
    529 * cinfo is the content info to decrypt
    530 *
    531 * key is the key with which to perform the decryption.  if the
    532 *     algorithm is a password based encryption algorithm, the
    533 *     key is actually a password which will be processed per
    534 *     PKCS #5.
    535 *
    536 * in the event of an error, SECFailure is returned.  SECSuccess
    537 * indicates a success.
    538 */
    539 SECStatus
    540 SEC_PKCS7DecryptContents(PLArenaPool *poolp,
    541                         SEC_PKCS7ContentInfo *cinfo,
    542                         SECItem *key,
    543                         void *wincx)
    544 {
    545    SECAlgorithmID *algid = NULL;
    546    SECStatus rv = SECFailure;
    547    SECItem *dest, *src;
    548    void *mark;
    549 
    550    PK11SymKey *eKey = NULL;
    551    PK11SlotInfo *slot = NULL;
    552    CK_MECHANISM_TYPE cryptoMechType;
    553    void *cx;
    554    SECItem *c_param = NULL;
    555    int bs;
    556 
    557    if ((cinfo == NULL) || (key == NULL))
    558        return SECFailure;
    559 
    560    if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
    561        return SECFailure;
    562 
    563    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
    564    if (algid == NULL)
    565        return SECFailure;
    566 
    567    if (poolp == NULL)
    568        poolp = cinfo->poolp;
    569 
    570    mark = PORT_ArenaMark(poolp);
    571 
    572    src = &cinfo->content.encryptedData->encContentInfo.encContent;
    573    dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
    574    dest->data = (unsigned char *)PORT_ArenaZAlloc(poolp, (src->len + 64));
    575    dest->len = (src->len + 64);
    576    if (dest->data == NULL) {
    577        rv = SECFailure;
    578        goto loser;
    579    }
    580 
    581    slot = PK11_GetInternalKeySlot();
    582    if (slot == NULL) {
    583        rv = SECFailure;
    584        goto loser;
    585    }
    586 
    587    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
    588    if (eKey == NULL) {
    589        rv = SECFailure;
    590        goto loser;
    591    }
    592 
    593    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
    594    if (cryptoMechType == CKM_INVALID_MECHANISM) {
    595        rv = SECFailure;
    596        goto loser;
    597    }
    598 
    599    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
    600                                    eKey, c_param);
    601    if (cx == NULL) {
    602        rv = SECFailure;
    603        goto loser;
    604    }
    605 
    606    rv = PK11_CipherOp((PK11Context *)cx, dest->data, (int *)(&dest->len),
    607                       (int)(src->len + 64), src->data, (int)src->len);
    608    PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
    609 
    610    bs = PK11_GetBlockSize(cryptoMechType, c_param);
    611    if (bs) {
    612        /* check for proper badding in block algorithms.  this assumes
    613         * RC2 cbc or a DES cbc variant.  and the padding is thus defined
    614         */
    615        if (((int)dest->data[dest->len - 1] <= bs) &&
    616            ((int)dest->data[dest->len - 1] > 0)) {
    617            dest->len -= (int)dest->data[dest->len - 1];
    618        } else {
    619            rv = SECFailure;
    620            /* set an error ? */
    621        }
    622    }
    623 
    624 loser:
    625    /* let success fall through */
    626    if (rv == SECFailure)
    627        PORT_ArenaRelease(poolp, mark);
    628    else
    629        PORT_ArenaUnmark(poolp, mark);
    630 
    631    if (eKey != NULL)
    632        PK11_FreeSymKey(eKey);
    633 
    634    if (slot != NULL)
    635        PK11_FreeSlot(slot);
    636 
    637    if (c_param != NULL)
    638        SECITEM_ZfreeItem(c_param, PR_TRUE);
    639 
    640    return rv;
    641 }
    642 
    643 SECItem **
    644 SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo)
    645 {
    646    switch (SEC_PKCS7ContentType(cinfo)) {
    647        case SEC_OID_PKCS7_SIGNED_DATA:
    648            return cinfo->content.signedData->rawCerts;
    649            break;
    650        default:
    651            return NULL;
    652            break;
    653    }
    654 }
    655 
    656 int
    657 SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo)
    658 {
    659    if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA)
    660        return cinfo->content.envelopedData->encContentInfo.keysize;
    661    else
    662        return 0;
    663 }