tor-browser

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

cmsmessage.c (8983B)


      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 message methods.
      7 */
      8 
      9 #include "cmslocal.h"
     10 
     11 #include "cert.h"
     12 #include "secasn1.h"
     13 #include "secitem.h"
     14 #include "secoid.h"
     15 #include "pk11func.h"
     16 #include "secerr.h"
     17 
     18 /*
     19 * NSS_CMSMessage_Create - create a CMS message object
     20 *
     21 * "poolp" - arena to allocate memory from, or NULL if new arena should be created
     22 */
     23 NSSCMSMessage *
     24 NSS_CMSMessage_Create(PLArenaPool *poolp)
     25 {
     26    void *mark = NULL;
     27    NSSCMSMessage *cmsg;
     28    PRBool poolp_is_ours = PR_FALSE;
     29 
     30    if (poolp == NULL) {
     31        poolp = PORT_NewArena(1024); /* XXX what is right value? */
     32        if (poolp == NULL) {
     33            return NULL;
     34        }
     35        poolp_is_ours = PR_TRUE;
     36    }
     37 
     38    if (!poolp_is_ours)
     39        mark = PORT_ArenaMark(poolp);
     40 
     41    cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSMessage));
     42    if (cmsg == NULL ||
     43        NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo)) != SECSuccess) {
     44        if (!poolp_is_ours) {
     45            if (mark) {
     46                PORT_ArenaRelease(poolp, mark);
     47            }
     48        } else {
     49            PORT_FreeArena(poolp, PR_FALSE);
     50        }
     51        return NULL;
     52    }
     53 
     54    cmsg->poolp = poolp;
     55    cmsg->poolp_is_ours = poolp_is_ours;
     56    cmsg->refCount = 1;
     57 
     58    if (mark) {
     59        PORT_ArenaUnmark(poolp, mark);
     60    }
     61 
     62    return cmsg;
     63 }
     64 
     65 /*
     66 * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding
     67 *
     68 * "cmsg" - message object
     69 * "pwfn", pwfn_arg" - callback function for getting token password
     70 * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
     71 * "detached_digestalgs", "detached_digests" - digests from detached content
     72 */
     73 void
     74 NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
     75                                 PK11PasswordFunc pwfn, void *pwfn_arg,
     76                                 NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
     77                                 SECAlgorithmID **detached_digestalgs, SECItem **detached_digests)
     78 {
     79    if (cmsg == NULL) {
     80        return;
     81    }
     82    if (pwfn) {
     83        PK11_SetPasswordFunc(pwfn);
     84    }
     85 
     86    cmsg->pwfn_arg = pwfn_arg;
     87    cmsg->decrypt_key_cb = decrypt_key_cb;
     88    cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg;
     89    cmsg->detached_digestalgs = detached_digestalgs;
     90    cmsg->detached_digests = detached_digests;
     91 }
     92 
     93 /*
     94 * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces.
     95 */
     96 void
     97 NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
     98 {
     99    if (cmsg == NULL)
    100        return;
    101 
    102    PORT_Assert(cmsg->refCount > 0);
    103    if (cmsg->refCount <= 0) { /* oops */
    104        return;
    105    }
    106 
    107    cmsg->refCount--; /* thread safety? */
    108    if (cmsg->refCount > 0) {
    109        return;
    110    }
    111 
    112    NSS_CMSContentInfo_Destroy(&(cmsg->contentInfo));
    113 
    114    /* if poolp is not NULL, cmsg is the owner of its arena */
    115    if (cmsg->poolp_is_ours) {
    116        PORT_FreeArena(cmsg->poolp, PR_FALSE); /* XXX clear it? */
    117    }
    118 }
    119 
    120 /*
    121 * NSS_CMSMessage_Copy - return a copy of the given message.
    122 *
    123 * The copy may be virtual or may be real -- either way, the result needs
    124 * to be passed to NSS_CMSMessage_Destroy later (as does the original).
    125 */
    126 NSSCMSMessage *
    127 NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
    128 {
    129    if (cmsg == NULL) {
    130        return NULL;
    131    }
    132 
    133    PORT_Assert(cmsg->refCount > 0);
    134 
    135    cmsg->refCount++; /* XXX chrisk thread safety? */
    136    return cmsg;
    137 }
    138 
    139 /*
    140 * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool
    141 */
    142 PLArenaPool *
    143 NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
    144 {
    145    if (cmsg == NULL) {
    146        return NULL;
    147    }
    148 
    149    return cmsg->poolp;
    150 }
    151 
    152 /*
    153 * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo
    154 */
    155 NSSCMSContentInfo *
    156 NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
    157 {
    158    if (cmsg == NULL) {
    159        return NULL;
    160    }
    161 
    162    return &(cmsg->contentInfo);
    163 }
    164 
    165 /*
    166 * Return a pointer to the actual content.
    167 * In the case of those types which are encrypted, this returns the *plain* content.
    168 * In case of nested contentInfos, this descends and retrieves the innermost content.
    169 */
    170 SECItem *
    171 NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg)
    172 {
    173    if (cmsg == NULL) {
    174        return NULL;
    175    }
    176 
    177    /* this is a shortcut */
    178    NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
    179    SECItem *pItem = NSS_CMSContentInfo_GetInnerContent(cinfo);
    180    return pItem;
    181 }
    182 
    183 /*
    184 * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message
    185 *
    186 * CMS data content objects do not count.
    187 */
    188 int
    189 NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg)
    190 {
    191    int count = 0;
    192    NSSCMSContentInfo *cinfo;
    193 
    194    if (cmsg == NULL) {
    195        return 0;
    196    }
    197 
    198    /* walk down the chain of contentinfos */
    199    for (cinfo = &(cmsg->contentInfo); cinfo != NULL;) {
    200        count++;
    201        cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo);
    202    }
    203    return count;
    204 }
    205 
    206 /*
    207 * NSS_CMSMessage_ContentLevel - find content level #n
    208 *
    209 * CMS data content objects do not count.
    210 */
    211 NSSCMSContentInfo *
    212 NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n)
    213 {
    214    int count = 0;
    215    NSSCMSContentInfo *cinfo;
    216 
    217    if (cmsg == NULL) {
    218        return NULL;
    219    }
    220 
    221    /* walk down the chain of contentinfos */
    222    for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n;
    223         cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
    224        count++;
    225    }
    226 
    227    return cinfo;
    228 }
    229 
    230 /*
    231 * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way
    232 */
    233 PRBool
    234 NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg)
    235 {
    236    NSSCMSContentInfo *cinfo;
    237 
    238    if (cmsg == NULL) {
    239        return PR_FALSE;
    240    }
    241 
    242    /* descend into CMS message */
    243    for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
    244         cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
    245        SECOidTag tag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
    246        if (tag != SEC_OID_PKCS7_SIGNED_DATA)
    247            continue; /* next level */
    248 
    249        if (NSS_CMSSignedData_ContainsCertsOrCrls(NSS_CMSContentInfo_GetContent(cinfo)))
    250            return PR_TRUE;
    251        /* callback here for generic wrappers? */
    252    }
    253    return PR_FALSE;
    254 }
    255 
    256 /*
    257 * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage
    258 */
    259 PRBool
    260 NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg)
    261 {
    262    NSSCMSContentInfo *cinfo;
    263 
    264    if (cmsg == NULL) {
    265        return PR_FALSE;
    266    }
    267 
    268    /* walk down the chain of contentinfos */
    269    for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
    270         cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
    271        switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
    272            case SEC_OID_PKCS7_ENVELOPED_DATA:
    273            case SEC_OID_PKCS7_ENCRYPTED_DATA:
    274                return PR_TRUE;
    275            default:
    276                /* callback here for generic wrappers? */
    277                break;
    278        }
    279    }
    280    return PR_FALSE;
    281 }
    282 
    283 /*
    284 * NSS_CMSMessage_IsSigned - see if message contains a signed submessage
    285 *
    286 * If the CMS message has a SignedData with a signature (not just a SignedData)
    287 * return true; false otherwise.  This can/should be called before calling
    288 * VerifySignature, which will always indicate failure if no signature is
    289 * present, but that does not mean there even was a signature!
    290 * Note that the content itself can be empty (detached content was sent
    291 * another way); it is the presence of the signature that matters.
    292 */
    293 PRBool
    294 NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg)
    295 {
    296    NSSCMSContentInfo *cinfo;
    297 
    298    if (cmsg == NULL) {
    299        return PR_FALSE;
    300    }
    301 
    302    /* walk down the chain of contentinfos */
    303    for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
    304         cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
    305        switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
    306            case SEC_OID_PKCS7_SIGNED_DATA:
    307                if (cinfo->content.signedData == NULL) {
    308                    return PR_FALSE;
    309                }
    310                if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos)) {
    311                    return PR_TRUE;
    312                }
    313                break;
    314            default:
    315                /* callback here for generic wrappers? */
    316                break;
    317        }
    318    }
    319    return PR_FALSE;
    320 }
    321 
    322 /*
    323 * NSS_CMSMessage_IsContentEmpty - see if content is empty
    324 *
    325 * returns PR_TRUE is innermost content length is < minLen
    326 * XXX need the encrypted content length (why?)
    327 */
    328 PRBool
    329 NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen)
    330 {
    331    SECItem *item = NULL;
    332 
    333    if (cmsg == NULL) {
    334        return PR_TRUE;
    335    }
    336 
    337    item = NSS_CMSContentInfo_GetContent(NSS_CMSMessage_GetContentInfo(cmsg));
    338 
    339    if (!item) {
    340        return PR_TRUE;
    341    } else if (item->len <= minLen) {
    342        return PR_TRUE;
    343    }
    344 
    345    return PR_FALSE;
    346 }