tor-browser

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

cmsudf.c (11735B)


      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 User Define Types
      7 */
      8 
      9 #include "cmslocal.h"
     10 
     11 #include "prinit.h"
     12 #include "pk11func.h"
     13 #include "secitem.h"
     14 #include "secoid.h"
     15 #include "secerr.h"
     16 #include "nss.h"
     17 
     18 typedef struct nsscmstypeInfoStr nsscmstypeInfo;
     19 struct nsscmstypeInfoStr {
     20    SECOidTag type;
     21    SEC_ASN1Template *template;
     22    size_t size;
     23    PRBool isData;
     24    NSSCMSGenericWrapperDataDestroy destroy;
     25    NSSCMSGenericWrapperDataCallback decode_before;
     26    NSSCMSGenericWrapperDataCallback decode_after;
     27    NSSCMSGenericWrapperDataCallback decode_end;
     28    NSSCMSGenericWrapperDataCallback encode_start;
     29    NSSCMSGenericWrapperDataCallback encode_before;
     30    NSSCMSGenericWrapperDataCallback encode_after;
     31 };
     32 
     33 /* make sure the global tables are only initialized once */
     34 static PRCallOnceType nsscmstypeOnce;
     35 static PRCallOnceType nsscmstypeClearOnce;
     36 /* lock for adding a new entry */
     37 static PRLock *nsscmstypeAddLock;
     38 /* lock for the hash table */
     39 static PRLock *nsscmstypeHashLock;
     40 /* the hash table itself */
     41 static PLHashTable *nsscmstypeHash;
     42 /* arena to hold all the hash table data */
     43 static PLArenaPool *nsscmstypeArena;
     44 
     45 /*
     46 * clean up our global tables
     47 */
     48 SECStatus
     49 nss_cmstype_shutdown(void *appData, void *reserved)
     50 {
     51    if (nsscmstypeHashLock) {
     52        PR_Lock(nsscmstypeHashLock);
     53    }
     54    if (nsscmstypeHash) {
     55        PL_HashTableDestroy(nsscmstypeHash);
     56        nsscmstypeHash = NULL;
     57    }
     58    if (nsscmstypeArena) {
     59        PORT_FreeArena(nsscmstypeArena, PR_FALSE);
     60        nsscmstypeArena = NULL;
     61    }
     62    if (nsscmstypeAddLock) {
     63        PR_DestroyLock(nsscmstypeAddLock);
     64    }
     65    if (nsscmstypeHashLock) {
     66        PRLock *oldLock = nsscmstypeHashLock;
     67        nsscmstypeHashLock = NULL;
     68        PR_Unlock(oldLock);
     69        PR_DestroyLock(oldLock);
     70    }
     71 
     72    /* don't clear out the PR_ONCE data if we failed our inital call */
     73    if (appData == NULL) {
     74        nsscmstypeOnce = nsscmstypeClearOnce;
     75    }
     76    return SECSuccess;
     77 }
     78 
     79 static PLHashNumber
     80 nss_cmstype_hash_key(const void *key)
     81 {
     82    return (PLHashNumber)((char *)key - (char *)NULL);
     83 }
     84 
     85 static PRIntn
     86 nss_cmstype_compare_keys(const void *v1, const void *v2)
     87 {
     88    PLHashNumber value1 = nss_cmstype_hash_key(v1);
     89    PLHashNumber value2 = nss_cmstype_hash_key(v2);
     90 
     91    return (value1 == value2);
     92 }
     93 
     94 /*
     95 * initialize our hash tables, called once on the first attemat to register
     96 * a new SMIME type.
     97 */
     98 static PRStatus
     99 nss_cmstype_init(void)
    100 {
    101    SECStatus rv;
    102 
    103    nsscmstypeHashLock = PR_NewLock();
    104    if (nsscmstypeHashLock == NULL) {
    105        return PR_FAILURE;
    106    }
    107    nsscmstypeAddLock = PR_NewLock();
    108    if (nsscmstypeHashLock == NULL) {
    109        goto fail;
    110    }
    111    nsscmstypeHash = PL_NewHashTable(64, nss_cmstype_hash_key,
    112                                     nss_cmstype_compare_keys,
    113                                     PL_CompareValues, NULL, NULL);
    114    if (nsscmstypeHash == NULL) {
    115        goto fail;
    116    }
    117    nsscmstypeArena = PORT_NewArena(2048);
    118    if (nsscmstypeArena == NULL) {
    119        goto fail;
    120    }
    121    rv = NSS_RegisterShutdown(nss_cmstype_shutdown, NULL);
    122    if (rv != SECSuccess) {
    123        goto fail;
    124    }
    125    return PR_SUCCESS;
    126 
    127 fail:
    128    nss_cmstype_shutdown(&nsscmstypeOnce, NULL);
    129    return PR_FAILURE;
    130 }
    131 
    132 /*
    133 * look up and registered SIME type
    134 */
    135 static const nsscmstypeInfo *
    136 nss_cmstype_lookup(SECOidTag type)
    137 {
    138    nsscmstypeInfo *typeInfo = NULL;
    139    ;
    140    if (!nsscmstypeHash) {
    141        return NULL;
    142    }
    143    PR_Lock(nsscmstypeHashLock);
    144    if (nsscmstypeHash) {
    145        typeInfo = PL_HashTableLookupConst(nsscmstypeHash, (void *)type);
    146    }
    147    PR_Unlock(nsscmstypeHashLock);
    148    return typeInfo;
    149 }
    150 
    151 /*
    152 * add a new type to the SMIME type table
    153 */
    154 static SECStatus
    155 nss_cmstype_add(SECOidTag type, nsscmstypeInfo *typeinfo)
    156 {
    157    PLHashEntry *entry;
    158 
    159    if (!nsscmstypeHash) {
    160        /* assert? this shouldn't happen */
    161        return SECFailure;
    162    }
    163    PR_Lock(nsscmstypeHashLock);
    164    /* this is really paranoia. If we really are racing nsscmstypeHash, we'll
    165     * also be racing nsscmstypeHashLock... */
    166    if (!nsscmstypeHash) {
    167        PR_Unlock(nsscmstypeHashLock);
    168        return SECFailure;
    169    }
    170    entry = PL_HashTableAdd(nsscmstypeHash, (void *)type, typeinfo);
    171    PR_Unlock(nsscmstypeHashLock);
    172    return entry ? SECSuccess : SECFailure;
    173 }
    174 
    175 /* helper functions to manage new content types
    176 */
    177 
    178 PRBool
    179 NSS_CMSType_IsWrapper(SECOidTag type)
    180 {
    181    const nsscmstypeInfo *typeInfo = NULL;
    182 
    183    switch (type) {
    184        case SEC_OID_PKCS7_SIGNED_DATA:
    185        case SEC_OID_PKCS7_ENVELOPED_DATA:
    186        case SEC_OID_PKCS7_DIGESTED_DATA:
    187        case SEC_OID_PKCS7_ENCRYPTED_DATA:
    188            return PR_TRUE;
    189        default:
    190            typeInfo = nss_cmstype_lookup(type);
    191            if (typeInfo && !typeInfo->isData) {
    192                return PR_TRUE;
    193            }
    194    }
    195    return PR_FALSE;
    196 }
    197 
    198 PRBool
    199 NSS_CMSType_IsData(SECOidTag type)
    200 {
    201    const nsscmstypeInfo *typeInfo = NULL;
    202 
    203    switch (type) {
    204        case SEC_OID_PKCS7_DATA:
    205            return PR_TRUE;
    206        default:
    207            typeInfo = nss_cmstype_lookup(type);
    208            if (typeInfo && typeInfo->isData) {
    209                return PR_TRUE;
    210            }
    211    }
    212    return PR_FALSE;
    213 }
    214 
    215 const SEC_ASN1Template *
    216 NSS_CMSType_GetTemplate(SECOidTag type)
    217 {
    218    const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
    219 
    220    if (typeInfo && typeInfo->template) {
    221        return typeInfo->template;
    222    }
    223    return SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
    224 }
    225 
    226 size_t
    227 NSS_CMSType_GetContentSize(SECOidTag type)
    228 {
    229    const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
    230 
    231    if (typeInfo) {
    232        return typeInfo->size;
    233    }
    234    return sizeof(SECItem *);
    235 }
    236 
    237 void
    238 NSS_CMSGenericWrapperData_Destroy(SECOidTag type, NSSCMSGenericWrapperData *gd)
    239 {
    240    const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
    241 
    242    if (typeInfo && (typeInfo->destroy) && (gd != NULL)) {
    243        (*typeInfo->destroy)(gd);
    244    }
    245 }
    246 
    247 SECStatus
    248 NSS_CMSGenericWrapperData_Decode_BeforeData(SECOidTag type,
    249                                            NSSCMSGenericWrapperData *gd)
    250 {
    251    const nsscmstypeInfo *typeInfo;
    252 
    253    /* short cut common case */
    254    if (type == SEC_OID_PKCS7_DATA) {
    255        return SECSuccess;
    256    }
    257 
    258    typeInfo = nss_cmstype_lookup(type);
    259    if (typeInfo) {
    260        if (typeInfo->decode_before) {
    261            return (*typeInfo->decode_before)(gd);
    262        }
    263        /* decoder ops optional for data tags */
    264        if (typeInfo->isData) {
    265            return SECSuccess;
    266        }
    267    }
    268    /* expected a function, but none existed */
    269    return SECFailure;
    270 }
    271 
    272 SECStatus
    273 NSS_CMSGenericWrapperData_Decode_AfterData(SECOidTag type,
    274                                           NSSCMSGenericWrapperData *gd)
    275 {
    276    const nsscmstypeInfo *typeInfo;
    277 
    278    /* short cut common case */
    279    if (type == SEC_OID_PKCS7_DATA) {
    280        return SECSuccess;
    281    }
    282 
    283    typeInfo = nss_cmstype_lookup(type);
    284    if (typeInfo) {
    285        if (typeInfo->decode_after) {
    286            return (*typeInfo->decode_after)(gd);
    287        }
    288        /* decoder ops optional for data tags */
    289        if (typeInfo->isData) {
    290            return SECSuccess;
    291        }
    292    }
    293    /* expected a function, but none existed */
    294    return SECFailure;
    295 }
    296 
    297 SECStatus
    298 NSS_CMSGenericWrapperData_Decode_AfterEnd(SECOidTag type,
    299                                          NSSCMSGenericWrapperData *gd)
    300 {
    301    const nsscmstypeInfo *typeInfo;
    302 
    303    /* short cut common case */
    304    if (type == SEC_OID_PKCS7_DATA) {
    305        return SECSuccess;
    306    }
    307 
    308    typeInfo = nss_cmstype_lookup(type);
    309    if (typeInfo) {
    310        if (typeInfo->decode_end) {
    311            return (*typeInfo->decode_end)(gd);
    312        }
    313        /* decoder ops optional for data tags */
    314        if (typeInfo->isData) {
    315            return SECSuccess;
    316        }
    317    }
    318    /* expected a function, but none existed */
    319    return SECFailure;
    320 }
    321 
    322 SECStatus
    323 NSS_CMSGenericWrapperData_Encode_BeforeStart(SECOidTag type,
    324                                             NSSCMSGenericWrapperData *gd)
    325 {
    326    const nsscmstypeInfo *typeInfo;
    327 
    328    /* short cut common case */
    329    if (type == SEC_OID_PKCS7_DATA) {
    330        return SECSuccess;
    331    }
    332 
    333    typeInfo = nss_cmstype_lookup(type);
    334    if (typeInfo) {
    335        if (typeInfo->encode_start) {
    336            return (*typeInfo->encode_start)(gd);
    337        }
    338        /* decoder ops optional for data tags */
    339        if (typeInfo->isData) {
    340            return SECSuccess;
    341        }
    342    }
    343    /* expected a function, but none existed */
    344    return SECFailure;
    345 }
    346 
    347 SECStatus
    348 NSS_CMSGenericWrapperData_Encode_BeforeData(SECOidTag type,
    349                                            NSSCMSGenericWrapperData *gd)
    350 {
    351    const nsscmstypeInfo *typeInfo;
    352 
    353    /* short cut common case */
    354    if (type == SEC_OID_PKCS7_DATA) {
    355        return SECSuccess;
    356    }
    357 
    358    typeInfo = nss_cmstype_lookup(type);
    359    if (typeInfo) {
    360        if (typeInfo->encode_before) {
    361            return (*typeInfo->encode_before)(gd);
    362        }
    363        /* decoder ops optional for data tags */
    364        if (typeInfo->isData) {
    365            return SECSuccess;
    366        }
    367    }
    368    /* expected a function, but none existed */
    369    return SECFailure;
    370 }
    371 
    372 SECStatus
    373 NSS_CMSGenericWrapperData_Encode_AfterData(SECOidTag type,
    374                                           NSSCMSGenericWrapperData *gd)
    375 {
    376    const nsscmstypeInfo *typeInfo;
    377 
    378    /* short cut common case */
    379    if (type == SEC_OID_PKCS7_DATA) {
    380        return SECSuccess;
    381    }
    382 
    383    typeInfo = nss_cmstype_lookup(type);
    384    if (typeInfo) {
    385        if (typeInfo->encode_after) {
    386            return (*typeInfo->encode_after)(gd);
    387        }
    388        /* decoder ops optional for data tags */
    389        if (typeInfo->isData) {
    390            return SECSuccess;
    391        }
    392    }
    393    /* expected a function, but none existed */
    394    return SECFailure;
    395 }
    396 
    397 SECStatus
    398 NSS_CMSType_RegisterContentType(SECOidTag type,
    399                                SEC_ASN1Template *asn1Template, size_t size,
    400                                NSSCMSGenericWrapperDataDestroy destroy,
    401                                NSSCMSGenericWrapperDataCallback decode_before,
    402                                NSSCMSGenericWrapperDataCallback decode_after,
    403                                NSSCMSGenericWrapperDataCallback decode_end,
    404                                NSSCMSGenericWrapperDataCallback encode_start,
    405                                NSSCMSGenericWrapperDataCallback encode_before,
    406                                NSSCMSGenericWrapperDataCallback encode_after,
    407                                PRBool isData)
    408 {
    409    PRStatus rc;
    410    SECStatus rv;
    411    nsscmstypeInfo *typeInfo;
    412    const nsscmstypeInfo *exists;
    413 
    414    rc = PR_CallOnce(&nsscmstypeOnce, nss_cmstype_init);
    415    if (rc == PR_FAILURE) {
    416        return SECFailure;
    417    }
    418    PR_Lock(nsscmstypeAddLock);
    419    exists = nss_cmstype_lookup(type);
    420    if (exists) {
    421        PR_Unlock(nsscmstypeAddLock);
    422        /* already added */
    423        return SECSuccess;
    424    }
    425    typeInfo = PORT_ArenaNew(nsscmstypeArena, nsscmstypeInfo);
    426    typeInfo->type = type;
    427    typeInfo->size = size;
    428    typeInfo->isData = isData;
    429    typeInfo->template = asn1Template;
    430    typeInfo->destroy = destroy;
    431    typeInfo->decode_before = decode_before;
    432    typeInfo->decode_after = decode_after;
    433    typeInfo->decode_end = decode_end;
    434    typeInfo->encode_start = encode_start;
    435    typeInfo->encode_before = encode_before;
    436    typeInfo->encode_after = encode_after;
    437    rv = nss_cmstype_add(type, typeInfo);
    438    PR_Unlock(nsscmstypeAddLock);
    439    return rv;
    440 }