tor-browser

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

pk11nobj.c (21777B)


      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 * This file manages Netscape specific PKCS #11 objects (CRLs, Trust objects,
      6 * etc).
      7 */
      8 
      9 #include <stddef.h>
     10 
     11 #include "secport.h"
     12 #include "seccomon.h"
     13 #include "secmod.h"
     14 #include "secmodi.h"
     15 #include "secmodti.h"
     16 #include "pkcs11.h"
     17 #include "pk11func.h"
     18 #include "cert.h"
     19 #include "certi.h"
     20 #include "secitem.h"
     21 #include "sechash.h"
     22 #include "secoid.h"
     23 
     24 #include "certdb.h"
     25 #include "secerr.h"
     26 
     27 #include "pki3hack.h"
     28 #include "dev3hack.h"
     29 
     30 #include "devm.h"
     31 #include "pki.h"
     32 #include "pkim.h"
     33 
     34 extern const NSSError NSS_ERROR_NOT_FOUND;
     35 
     36 PRBool
     37 pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust)
     38 {
     39    return nssTrust_HandleTrustForCERTCert(cert, trust);
     40 }
     41 
     42 static SECStatus
     43 pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg)
     44 {
     45    SECItem derCrl;
     46    CERTCrlHeadNode *head = (CERTCrlHeadNode *)arg;
     47    CERTCrlNode *new_node = NULL;
     48    CK_ATTRIBUTE fetchCrl[3] = {
     49        { CKA_VALUE, NULL, 0 },
     50        { CKA_NSS_KRL, NULL, 0 },
     51        { CKA_NSS_URL, NULL, 0 },
     52    };
     53    const int fetchCrlSize = sizeof(fetchCrl) / sizeof(fetchCrl[2]);
     54    CK_RV crv;
     55    SECStatus rv = SECFailure;
     56 
     57    crv = PK11_GetAttributes(head->arena, slot, crlID, fetchCrl, fetchCrlSize);
     58    if (CKR_OK != crv) {
     59        PORT_SetError(PK11_MapError(crv));
     60        goto loser;
     61    }
     62 
     63    if (!fetchCrl[1].pValue) {
     64        PORT_SetError(SEC_ERROR_CRL_INVALID);
     65        goto loser;
     66    }
     67 
     68    new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
     69    if (new_node == NULL) {
     70        goto loser;
     71    }
     72 
     73    if (*((CK_BBOOL *)fetchCrl[1].pValue))
     74        new_node->type = SEC_KRL_TYPE;
     75    else
     76        new_node->type = SEC_CRL_TYPE;
     77 
     78    derCrl.type = siBuffer;
     79    derCrl.data = (unsigned char *)fetchCrl[0].pValue;
     80    derCrl.len = fetchCrl[0].ulValueLen;
     81    new_node->crl = CERT_DecodeDERCrl(head->arena, &derCrl, new_node->type);
     82    if (new_node->crl == NULL) {
     83        goto loser;
     84    }
     85 
     86    if (fetchCrl[2].pValue) {
     87        int nnlen = fetchCrl[2].ulValueLen;
     88        new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen + 1);
     89        if (!new_node->crl->url) {
     90            goto loser;
     91        }
     92        PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
     93        new_node->crl->url[nnlen] = 0;
     94    } else {
     95        new_node->crl->url = NULL;
     96    }
     97 
     98    new_node->next = NULL;
     99    if (head->last) {
    100        head->last->next = new_node;
    101        head->last = new_node;
    102    } else {
    103        head->first = head->last = new_node;
    104    }
    105    rv = SECSuccess;
    106 
    107 loser:
    108    return (rv);
    109 }
    110 
    111 /*
    112 * Return a list of all the CRLs .
    113 * CRLs are allocated in the list's arena.
    114 */
    115 SECStatus
    116 PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx)
    117 {
    118    pk11TraverseSlot creater;
    119    CK_ATTRIBUTE theTemplate[2];
    120    CK_ATTRIBUTE *attrs;
    121    CK_OBJECT_CLASS certClass = CKO_NSS_CRL;
    122    CK_BBOOL isKrl = CK_FALSE;
    123 
    124    attrs = theTemplate;
    125    PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
    126    attrs++;
    127    if (type != -1) {
    128        isKrl = (CK_BBOOL)(type == SEC_KRL_TYPE);
    129        PK11_SETATTRS(attrs, CKA_NSS_KRL, &isKrl, sizeof(isKrl));
    130        attrs++;
    131    }
    132 
    133    creater.callback = pk11_CollectCrls;
    134    creater.callbackArg = (void *)nodes;
    135    creater.findTemplate = theTemplate;
    136    creater.templateCount = (attrs - theTemplate);
    137 
    138    return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
    139 }
    140 
    141 struct crlOptionsStr {
    142    CERTCrlHeadNode *head;
    143    PRInt32 decodeOptions;
    144 };
    145 
    146 typedef struct crlOptionsStr crlOptions;
    147 
    148 static SECStatus
    149 pk11_RetrieveCrlsCallback(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID,
    150                          void *arg)
    151 {
    152    SECItem *derCrl = NULL;
    153    crlOptions *options = (crlOptions *)arg;
    154    CERTCrlHeadNode *head = options->head;
    155    CERTCrlNode *new_node = NULL;
    156    CK_ATTRIBUTE fetchCrl[3] = {
    157        { CKA_VALUE, NULL, 0 },
    158        { CKA_NSS_KRL, NULL, 0 },
    159        { CKA_NSS_URL, NULL, 0 },
    160    };
    161    const int fetchCrlSize = sizeof(fetchCrl) / sizeof(fetchCrl[2]);
    162    CK_RV crv;
    163    SECStatus rv = SECFailure;
    164    PRBool adopted = PR_FALSE; /* whether the CRL adopted the DER memory
    165                                  successfully */
    166    int i;
    167 
    168    crv = PK11_GetAttributes(NULL, slot, crlID, fetchCrl, fetchCrlSize);
    169    if (CKR_OK != crv) {
    170        PORT_SetError(PK11_MapError(crv));
    171        goto loser;
    172    }
    173 
    174    if (!fetchCrl[1].pValue) {
    175        /* reject KRLs */
    176        PORT_SetError(SEC_ERROR_CRL_INVALID);
    177        goto loser;
    178    }
    179 
    180    new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena,
    181                                              sizeof(CERTCrlNode));
    182    if (new_node == NULL) {
    183        goto loser;
    184    }
    185 
    186    new_node->type = SEC_CRL_TYPE;
    187 
    188    derCrl = SECITEM_AllocItem(NULL, NULL, 0);
    189    if (!derCrl) {
    190        goto loser;
    191    }
    192    derCrl->type = siBuffer;
    193    derCrl->data = (unsigned char *)fetchCrl[0].pValue;
    194    derCrl->len = fetchCrl[0].ulValueLen;
    195    new_node->crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, new_node->type,
    196                                               options->decodeOptions);
    197    if (new_node->crl == NULL) {
    198        goto loser;
    199    }
    200    adopted = PR_TRUE; /* now that the CRL has adopted the DER memory,
    201                          we won't need to free it upon exit */
    202 
    203    if (fetchCrl[2].pValue && fetchCrl[2].ulValueLen) {
    204        /* copy the URL if there is one */
    205        int nnlen = fetchCrl[2].ulValueLen;
    206        new_node->crl->url = (char *)PORT_ArenaAlloc(new_node->crl->arena,
    207                                                     nnlen + 1);
    208        if (!new_node->crl->url) {
    209            goto loser;
    210        }
    211        PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
    212        new_node->crl->url[nnlen] = 0;
    213    } else {
    214        new_node->crl->url = NULL;
    215    }
    216 
    217    new_node->next = NULL;
    218    if (head->last) {
    219        head->last->next = new_node;
    220        head->last = new_node;
    221    } else {
    222        head->first = head->last = new_node;
    223    }
    224    rv = SECSuccess;
    225    new_node->crl->slot = PK11_ReferenceSlot(slot);
    226    new_node->crl->pkcs11ID = crlID;
    227 
    228 loser:
    229    /* free attributes that weren't adopted by the CRL */
    230    for (i = 1; i < fetchCrlSize; i++) {
    231        if (fetchCrl[i].pValue) {
    232            PORT_Free(fetchCrl[i].pValue);
    233        }
    234    }
    235    /* free the DER if the CRL object didn't adopt it */
    236    if (fetchCrl[0].pValue && PR_FALSE == adopted) {
    237        PORT_Free(fetchCrl[0].pValue);
    238    }
    239    if (derCrl && !adopted) {
    240        /* clear the data fields, which we already took care of above */
    241        derCrl->data = NULL;
    242        derCrl->len = 0;
    243        /* free the memory for the SECItem structure itself */
    244        SECITEM_FreeItem(derCrl, PR_TRUE);
    245    }
    246    return (rv);
    247 }
    248 
    249 /*
    250 * Return a list of CRLs matching specified issuer and type
    251 * CRLs are not allocated in the list's arena, but rather in their own,
    252 * arena, so that they can be used individually in the CRL cache .
    253 * CRLs are always partially decoded for efficiency.
    254 */
    255 SECStatus
    256 pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem *issuer,
    257                  void *wincx)
    258 {
    259    pk11TraverseSlot creater;
    260    CK_ATTRIBUTE theTemplate[2];
    261    CK_ATTRIBUTE *attrs;
    262    CK_OBJECT_CLASS crlClass = CKO_NSS_CRL;
    263    crlOptions options;
    264 
    265    attrs = theTemplate;
    266    PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass));
    267    attrs++;
    268 
    269    options.head = nodes;
    270 
    271    /* - do a partial decoding - we don't need to decode the entries while fetching
    272       - don't copy the DER for optimal performance - CRL can be very large
    273       - have the CRL objects adopt the DER, so SEC_DestroyCrl will free it
    274       - keep bad CRL objects. The CRL cache is interested in them, for
    275         security purposes. Bad CRL objects are a sign of something amiss.
    276     */
    277 
    278    options.decodeOptions = CRL_DECODE_SKIP_ENTRIES | CRL_DECODE_DONT_COPY_DER |
    279                            CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_KEEP_BAD_CRL;
    280    if (issuer) {
    281        PK11_SETATTRS(attrs, CKA_SUBJECT, issuer->data, issuer->len);
    282        attrs++;
    283    }
    284 
    285    creater.callback = pk11_RetrieveCrlsCallback;
    286    creater.callbackArg = (void *)&options;
    287    creater.findTemplate = theTemplate;
    288    creater.templateCount = (attrs - theTemplate);
    289 
    290    return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
    291 }
    292 
    293 /*
    294 * return the crl associated with a derSubjectName
    295 */
    296 SECItem *
    297 PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle,
    298                   SECItem *name, int type, char **pUrl)
    299 {
    300    NSSCRL **crls, **crlp, *crl = NULL;
    301    NSSDER subject;
    302    SECItem *rvItem;
    303    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
    304    char *url = NULL;
    305 
    306    PORT_SetError(0);
    307    NSSITEM_FROM_SECITEM(&subject, name);
    308    if (*slot) {
    309        nssCryptokiObject **instances;
    310        nssPKIObjectCollection *collection;
    311        nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
    312        NSSToken *token = PK11Slot_GetNSSToken(*slot);
    313        if (!token) {
    314            goto loser;
    315        }
    316        collection = nssCRLCollection_Create(td, NULL);
    317        if (!collection) {
    318            (void)nssToken_Destroy(token);
    319            goto loser;
    320        }
    321        instances = nssToken_FindCRLsBySubject(token, NULL, &subject,
    322                                               tokenOnly, 0, NULL);
    323        (void)nssToken_Destroy(token);
    324        nssPKIObjectCollection_AddInstances(collection, instances, 0);
    325        nss_ZFreeIf(instances);
    326        crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL);
    327        nssPKIObjectCollection_Destroy(collection);
    328    } else {
    329        crls = nssTrustDomain_FindCRLsBySubject(td, &subject);
    330    }
    331    if ((!crls) || (*crls == NULL)) {
    332        if (crls) {
    333            nssCRLArray_Destroy(crls);
    334        }
    335        if (NSS_GetError() == NSS_ERROR_NOT_FOUND) {
    336            PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
    337        }
    338        goto loser;
    339    }
    340    for (crlp = crls; *crlp; crlp++) {
    341        if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) ||
    342            ((*crlp)->isKRL && type != SEC_CRL_TYPE)) {
    343            crl = nssCRL_AddRef(*crlp);
    344            break;
    345        }
    346    }
    347    nssCRLArray_Destroy(crls);
    348    if (!crl) {
    349        /* CRL collection was found, but no interesting CRL's were on it.
    350         * Not an error */
    351        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
    352        goto loser;
    353    }
    354    if (crl->url) {
    355        url = PORT_Strdup(crl->url);
    356        if (!url) {
    357            goto loser;
    358        }
    359    }
    360    rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size);
    361    if (!rvItem) {
    362        goto loser;
    363    }
    364    memcpy(rvItem->data, crl->encoding.data, crl->encoding.size);
    365    *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot);
    366    *crlHandle = crl->object.instances[0]->handle;
    367    *pUrl = url;
    368    nssCRL_Destroy(crl);
    369    return rvItem;
    370 
    371 loser:
    372    if (url)
    373        PORT_Free(url);
    374    if (crl)
    375        nssCRL_Destroy(crl);
    376    if (PORT_GetError() == 0) {
    377        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
    378    }
    379    return NULL;
    380 }
    381 
    382 CK_OBJECT_HANDLE
    383 PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name,
    384            char *url, int type)
    385 {
    386    NSSItem derCRL, derSubject;
    387    NSSToken *token;
    388    nssCryptokiObject *object;
    389    PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE;
    390    CK_OBJECT_HANDLE rvH;
    391 
    392    NSSITEM_FROM_SECITEM(&derSubject, name);
    393    NSSITEM_FROM_SECITEM(&derCRL, crl);
    394    token = PK11Slot_GetNSSToken(slot);
    395    if (!token) {
    396        PORT_SetError(SEC_ERROR_NO_TOKEN);
    397        return CK_INVALID_HANDLE;
    398    }
    399    object = nssToken_ImportCRL(token, NULL,
    400                                &derSubject, &derCRL, isKRL, url, PR_TRUE);
    401    (void)nssToken_Destroy(token);
    402 
    403    if (object) {
    404        rvH = object->handle;
    405        nssCryptokiObject_Destroy(object);
    406    } else {
    407        rvH = CK_INVALID_HANDLE;
    408        PORT_SetError(SEC_ERROR_CRL_IMPORT_FAILED);
    409    }
    410    return rvH;
    411 }
    412 
    413 /*
    414 * delete a crl.
    415 */
    416 SECStatus
    417 SEC_DeletePermCRL(CERTSignedCrl *crl)
    418 {
    419    PRStatus status;
    420    nssCryptokiObject *object;
    421    NSSToken *token;
    422    PK11SlotInfo *slot = crl->slot;
    423 
    424    if (slot == NULL) {
    425        PORT_Assert(slot);
    426        /* shouldn't happen */
    427        PORT_SetError(SEC_ERROR_CRL_INVALID);
    428        return SECFailure;
    429    }
    430 
    431    token = PK11Slot_GetNSSToken(slot);
    432    if (!token) {
    433        return SECFailure;
    434    }
    435    object = nss_ZNEW(NULL, nssCryptokiObject);
    436    if (!object) {
    437        (void)nssToken_Destroy(token);
    438        return SECFailure;
    439    }
    440    object->token = token; /* object takes ownership */
    441    object->handle = crl->pkcs11ID;
    442    object->isTokenObject = PR_TRUE;
    443 
    444    status = nssToken_DeleteStoredObject(object);
    445 
    446    nssCryptokiObject_Destroy(object);
    447    return (status == PR_SUCCESS) ? SECSuccess : SECFailure;
    448 }
    449 
    450 /* search with email with and without NULL
    451 * The sql database accepts the email with a NULL as it's written,
    452 * the dbm database strips the NULL on write so won't match if
    453 * it's there on find */
    454 static CK_OBJECT_HANDLE
    455 pk11_FindSMimeObjectByTemplate(PK11SlotInfo *slot,
    456                               CK_ATTRIBUTE *theTemplate, size_t tsize)
    457 {
    458    CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
    459    CK_ATTRIBUTE *last;
    460 
    461    PORT_Assert(tsize != 0);
    462 
    463    smimeh = pk11_FindObjectByTemplate(slot, theTemplate, (int)tsize);
    464    if (smimeh != CK_INVALID_HANDLE) {
    465        return smimeh;
    466    }
    467    last = &theTemplate[tsize - 1];
    468    if ((last->type == CKA_NSS_EMAIL) && (last->ulValueLen != 0)) {
    469        CK_ULONG save_len = last->ulValueLen;
    470        last->ulValueLen--;
    471        smimeh = pk11_FindObjectByTemplate(slot, theTemplate, (int)tsize);
    472        last->ulValueLen = save_len; /* restore the original */
    473        return smimeh;
    474    }
    475    return CK_INVALID_HANDLE;
    476 }
    477 
    478 /*
    479 * return the certificate associated with a derCert
    480 */
    481 SECItem *
    482 PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr,
    483                      SECItem *name, SECItem **profileTime)
    484 {
    485    CK_OBJECT_CLASS smimeClass = CKO_NSS_SMIME;
    486    CK_ATTRIBUTE theTemplate[] = {
    487        { CKA_CLASS, NULL, 0 },
    488        { CKA_SUBJECT, NULL, 0 },
    489        { CKA_NSS_EMAIL, NULL, 0 },
    490    };
    491    CK_ATTRIBUTE smimeData[] = {
    492        { CKA_SUBJECT, NULL, 0 },
    493        { CKA_VALUE, NULL, 0 },
    494    };
    495    /* if you change the array, change the variable below as well */
    496    const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
    497    CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
    498    CK_ATTRIBUTE *attrs = theTemplate;
    499    CK_RV crv;
    500    SECItem *emailProfile = NULL;
    501 
    502    if (!emailAddr || !emailAddr[0]) {
    503        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    504        return NULL;
    505    }
    506 
    507    PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass));
    508    attrs++;
    509    PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len);
    510    attrs++;
    511    PK11_SETATTRS(attrs, CKA_NSS_EMAIL, emailAddr, strlen(emailAddr) + 1);
    512    attrs++;
    513 
    514    if (*slot) {
    515        smimeh = pk11_FindSMimeObjectByTemplate(*slot, theTemplate, tsize);
    516    } else {
    517        PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
    518                                               PR_FALSE, PR_TRUE, NULL);
    519        PK11SlotListElement *le;
    520 
    521        if (!list) {
    522            return NULL;
    523        }
    524        /* loop through all the slots */
    525        for (le = list->head; le; le = le->next) {
    526            smimeh = pk11_FindSMimeObjectByTemplate(le->slot, theTemplate, tsize);
    527            if (smimeh != CK_INVALID_HANDLE) {
    528                *slot = PK11_ReferenceSlot(le->slot);
    529                break;
    530            }
    531        }
    532        PK11_FreeSlotList(list);
    533    }
    534 
    535    if (smimeh == CK_INVALID_HANDLE) {
    536        PORT_SetError(SEC_ERROR_NO_KRL);
    537        return NULL;
    538    }
    539 
    540    if (profileTime) {
    541        PK11_SETATTRS(smimeData, CKA_NSS_SMIME_TIMESTAMP, NULL, 0);
    542    }
    543 
    544    crv = PK11_GetAttributes(NULL, *slot, smimeh, smimeData, 2);
    545    if (crv != CKR_OK) {
    546        PORT_SetError(PK11_MapError(crv));
    547        goto loser;
    548    }
    549 
    550    if (!profileTime) {
    551        SECItem profileSubject;
    552 
    553        profileSubject.data = (unsigned char *)smimeData[0].pValue;
    554        profileSubject.len = smimeData[0].ulValueLen;
    555        if (!SECITEM_ItemsAreEqual(&profileSubject, name)) {
    556            goto loser;
    557        }
    558    }
    559 
    560    emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
    561    if (emailProfile == NULL) {
    562        goto loser;
    563    }
    564 
    565    emailProfile->data = (unsigned char *)smimeData[1].pValue;
    566    emailProfile->len = smimeData[1].ulValueLen;
    567 
    568    if (profileTime) {
    569        *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
    570        if (*profileTime) {
    571            (*profileTime)->data = (unsigned char *)smimeData[0].pValue;
    572            (*profileTime)->len = smimeData[0].ulValueLen;
    573        }
    574    }
    575 
    576 loser:
    577    if (emailProfile == NULL) {
    578        if (smimeData[1].pValue) {
    579            PORT_Free(smimeData[1].pValue);
    580        }
    581    }
    582    if (profileTime == NULL || *profileTime == NULL) {
    583        if (smimeData[0].pValue) {
    584            PORT_Free(smimeData[0].pValue);
    585        }
    586    }
    587    return emailProfile;
    588 }
    589 
    590 SECStatus
    591 PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj,
    592                      SECItem *emailProfile, SECItem *profileTime)
    593 {
    594    CK_OBJECT_CLASS smimeClass = CKO_NSS_SMIME;
    595    CK_BBOOL ck_true = CK_TRUE;
    596    CK_ATTRIBUTE theTemplate[] = {
    597        { CKA_CLASS, NULL, 0 },
    598        { CKA_TOKEN, NULL, 0 },
    599        { CKA_SUBJECT, NULL, 0 },
    600        { CKA_NSS_EMAIL, NULL, 0 },
    601        { CKA_NSS_SMIME_TIMESTAMP, NULL, 0 },
    602        { CKA_VALUE, NULL, 0 }
    603    };
    604    /* if you change the array, change the variable below as well */
    605    int realSize = 0;
    606    CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
    607    CK_ATTRIBUTE *attrs = theTemplate;
    608    CK_SESSION_HANDLE rwsession;
    609    PK11SlotInfo *free_slot = NULL;
    610    CK_RV crv;
    611 #ifdef DEBUG
    612    int tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
    613 #endif
    614 
    615    PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass));
    616    attrs++;
    617    PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true));
    618    attrs++;
    619    PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len);
    620    attrs++;
    621    PK11_SETATTRS(attrs, CKA_NSS_EMAIL,
    622                  emailAddr, PORT_Strlen(emailAddr) + 1);
    623    attrs++;
    624    if (profileTime) {
    625        PK11_SETATTRS(attrs, CKA_NSS_SMIME_TIMESTAMP, profileTime->data,
    626                      profileTime->len);
    627        attrs++;
    628        PK11_SETATTRS(attrs, CKA_VALUE, emailProfile->data,
    629                      emailProfile->len);
    630        attrs++;
    631    }
    632    realSize = attrs - theTemplate;
    633    PORT_Assert(realSize <= tsize);
    634 
    635    if (slot == NULL) {
    636        free_slot = slot = PK11_GetInternalKeySlot();
    637        /* we need to free the key slot in the end!!! */
    638    }
    639 
    640    rwsession = PK11_GetRWSession(slot);
    641    if (rwsession == CK_INVALID_HANDLE) {
    642        PORT_SetError(SEC_ERROR_READ_ONLY);
    643        if (free_slot) {
    644            PK11_FreeSlot(free_slot);
    645        }
    646        return SECFailure;
    647    }
    648 
    649    crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, theTemplate, realSize, &smimeh);
    650    if (crv != CKR_OK) {
    651        PORT_SetError(PK11_MapError(crv));
    652    }
    653 
    654    PK11_RestoreROSession(slot, rwsession);
    655 
    656    if (free_slot) {
    657        PK11_FreeSlot(free_slot);
    658    }
    659    return SECSuccess;
    660 }
    661 
    662 CERTSignedCrl *crl_storeCRL(PK11SlotInfo *slot, char *url,
    663                            CERTSignedCrl *newCrl, SECItem *derCrl, int type);
    664 
    665 /* import the CRL into the token */
    666 
    667 CERTSignedCrl *
    668 PK11_ImportCRL(PK11SlotInfo *slot, SECItem *derCRL, char *url,
    669               int type, void *wincx, PRInt32 importOptions, PLArenaPool *arena,
    670               PRInt32 decodeoptions)
    671 {
    672    CERTSignedCrl *newCrl, *crl;
    673    SECStatus rv;
    674    CERTCertificate *caCert = NULL;
    675 
    676    newCrl = crl = NULL;
    677 
    678    do {
    679        newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type,
    680                                            decodeoptions);
    681        if (newCrl == NULL) {
    682            if (type == SEC_CRL_TYPE) {
    683                /* only promote error when the error code is too generic */
    684                if (PORT_GetError() == SEC_ERROR_BAD_DER)
    685                    PORT_SetError(SEC_ERROR_CRL_INVALID);
    686            } else {
    687                PORT_SetError(SEC_ERROR_KRL_INVALID);
    688            }
    689            break;
    690        }
    691 
    692        if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)) {
    693            CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
    694            PR_ASSERT(handle != NULL);
    695            caCert = CERT_FindCertByName(handle,
    696                                         &newCrl->crl.derName);
    697            if (caCert == NULL) {
    698                PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
    699                break;
    700            }
    701 
    702            /* If caCert is a v3 certificate, make sure that it can be used for
    703               crl signing purpose */
    704            rv = CERT_CheckCertUsage(caCert, KU_CRL_SIGN);
    705            if (rv != SECSuccess) {
    706                break;
    707            }
    708 
    709            rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert,
    710                                       PR_Now(), wincx);
    711            if (rv != SECSuccess) {
    712                if (type == SEC_CRL_TYPE) {
    713                    PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
    714                } else {
    715                    PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
    716                }
    717                break;
    718            }
    719        }
    720 
    721        crl = crl_storeCRL(slot, url, newCrl, derCRL, type);
    722 
    723    } while (0);
    724 
    725    if (crl == NULL) {
    726        SEC_DestroyCrl(newCrl);
    727    }
    728    if (caCert) {
    729        CERT_DestroyCertificate(caCert);
    730    }
    731    return (crl);
    732 }