tor-browser

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

ckhelper.c (19649B)


      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 #include "pkcs11.h"
      6 
      7 #ifndef DEVM_H
      8 #include "devm.h"
      9 #endif /* DEVM_H */
     10 
     11 #ifndef CKHELPER_H
     12 #include "ckhelper.h"
     13 #endif /* CKHELPER_H */
     14 
     15 extern const NSSError NSS_ERROR_DEVICE_ERROR;
     16 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
     17 
     18 static const CK_BBOOL s_true = CK_TRUE;
     19 NSS_IMPLEMENT_DATA const NSSItem
     20    g_ck_true = { (CK_VOID_PTR)&s_true, sizeof(s_true) };
     21 
     22 static const CK_BBOOL s_false = CK_FALSE;
     23 NSS_IMPLEMENT_DATA const NSSItem
     24    g_ck_false = { (CK_VOID_PTR)&s_false, sizeof(s_false) };
     25 
     26 static const CK_OBJECT_CLASS s_class_cert = CKO_CERTIFICATE;
     27 NSS_IMPLEMENT_DATA const NSSItem
     28    g_ck_class_cert = { (CK_VOID_PTR)&s_class_cert, sizeof(s_class_cert) };
     29 
     30 static const CK_OBJECT_CLASS s_class_pubkey = CKO_PUBLIC_KEY;
     31 NSS_IMPLEMENT_DATA const NSSItem
     32    g_ck_class_pubkey = { (CK_VOID_PTR)&s_class_pubkey, sizeof(s_class_pubkey) };
     33 
     34 static const CK_OBJECT_CLASS s_class_privkey = CKO_PRIVATE_KEY;
     35 NSS_IMPLEMENT_DATA const NSSItem
     36    g_ck_class_privkey = { (CK_VOID_PTR)&s_class_privkey, sizeof(s_class_privkey) };
     37 
     38 static PRBool
     39 is_string_attribute(
     40    CK_ATTRIBUTE_TYPE aType)
     41 {
     42    PRBool isString;
     43    switch (aType) {
     44        case CKA_LABEL:
     45        case CKA_NSS_EMAIL:
     46            isString = PR_TRUE;
     47            break;
     48        default:
     49            isString = PR_FALSE;
     50            break;
     51    }
     52    return isString;
     53 }
     54 
     55 NSS_IMPLEMENT PRStatus
     56 nssCKObject_GetAttributes(
     57    CK_OBJECT_HANDLE object,
     58    CK_ATTRIBUTE_PTR obj_template,
     59    CK_ULONG count,
     60    NSSArena *arenaOpt,
     61    nssSession *session,
     62    NSSSlot *slot)
     63 {
     64    nssArenaMark *mark = NULL;
     65    CK_SESSION_HANDLE hSession;
     66    CK_ULONG i = 0;
     67    CK_RV ckrv;
     68    PRStatus nssrv;
     69    PRBool alloced = PR_FALSE;
     70    void *epv = nssSlot_GetCryptokiEPV(slot);
     71    hSession = session->handle;
     72    if (arenaOpt) {
     73        mark = nssArena_Mark(arenaOpt);
     74        if (!mark) {
     75            goto loser;
     76        }
     77    }
     78    nssSession_EnterMonitor(session);
     79    /* XXX kinda hacky, if the storage size is already in the first template
     80     * item, then skip the alloc portion
     81     */
     82    if (obj_template[0].ulValueLen == 0) {
     83        /* Get the storage size needed for each attribute */
     84        ckrv = CKAPI(epv)->C_GetAttributeValue(hSession,
     85                                               object, obj_template, count);
     86        if (ckrv != CKR_OK &&
     87            ckrv != CKR_ATTRIBUTE_TYPE_INVALID &&
     88            ckrv != CKR_ATTRIBUTE_SENSITIVE) {
     89            nssSession_ExitMonitor(session);
     90            nss_SetError(NSS_ERROR_DEVICE_ERROR);
     91            goto loser;
     92        }
     93        /* Allocate memory for each attribute. */
     94        for (i = 0; i < count; i++) {
     95            CK_ULONG ulValueLen = obj_template[i].ulValueLen;
     96            if (ulValueLen == 0 || ulValueLen == (CK_ULONG)-1) {
     97                obj_template[i].pValue = NULL;
     98                obj_template[i].ulValueLen = 0;
     99                continue;
    100            }
    101            if (is_string_attribute(obj_template[i].type)) {
    102                ulValueLen++;
    103            }
    104            obj_template[i].pValue = nss_ZAlloc(arenaOpt, ulValueLen);
    105            if (!obj_template[i].pValue) {
    106                nssSession_ExitMonitor(session);
    107                goto loser;
    108            }
    109        }
    110        alloced = PR_TRUE;
    111    }
    112    /* Obtain the actual attribute values. */
    113    ckrv = CKAPI(epv)->C_GetAttributeValue(hSession,
    114                                           object, obj_template, count);
    115    nssSession_ExitMonitor(session);
    116    if (ckrv != CKR_OK &&
    117        ckrv != CKR_ATTRIBUTE_TYPE_INVALID &&
    118        ckrv != CKR_ATTRIBUTE_SENSITIVE) {
    119        nss_SetError(NSS_ERROR_DEVICE_ERROR);
    120        goto loser;
    121    }
    122    if (alloced && arenaOpt) {
    123        nssrv = nssArena_Unmark(arenaOpt, mark);
    124        if (nssrv != PR_SUCCESS) {
    125            goto loser;
    126        }
    127    }
    128 
    129    if (count > 1 && ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
    130                      (ckrv == CKR_ATTRIBUTE_SENSITIVE))) {
    131        /* old tokens would keep the length of '0' and not deal with any
    132         * of the attributes we passed. For those tokens read them one at
    133         * a time */
    134        for (i = 0; i < count; i++) {
    135            if ((obj_template[i].ulValueLen == 0) ||
    136                (obj_template[i].ulValueLen == -1)) {
    137                obj_template[i].ulValueLen = 0;
    138                (void)nssCKObject_GetAttributes(object, &obj_template[i], 1,
    139                                                arenaOpt, session, slot);
    140            }
    141        }
    142    }
    143    return PR_SUCCESS;
    144 loser:
    145    if (alloced) {
    146        if (arenaOpt) {
    147            /* release all arena memory allocated before the failure. */
    148            (void)nssArena_Release(arenaOpt, mark);
    149        } else {
    150            CK_ULONG j;
    151            /* free each heap object that was allocated before the failure. */
    152            for (j = 0; j < i; j++) {
    153                nss_ZFreeIf(obj_template[j].pValue);
    154            }
    155        }
    156    }
    157    return PR_FAILURE;
    158 }
    159 
    160 NSS_IMPLEMENT PRStatus
    161 nssCKObject_GetAttributeItem(
    162    CK_OBJECT_HANDLE object,
    163    CK_ATTRIBUTE_TYPE attribute,
    164    NSSArena *arenaOpt,
    165    nssSession *session,
    166    NSSSlot *slot,
    167    NSSItem *rvItem)
    168 {
    169    CK_ATTRIBUTE attr = { 0, NULL, 0 };
    170    PRStatus nssrv;
    171    attr.type = attribute;
    172    nssrv = nssCKObject_GetAttributes(object, &attr, 1,
    173                                      arenaOpt, session, slot);
    174    if (nssrv != PR_SUCCESS) {
    175        return nssrv;
    176    }
    177    rvItem->data = (void *)attr.pValue;
    178    rvItem->size = (PRUint32)attr.ulValueLen;
    179    return PR_SUCCESS;
    180 }
    181 
    182 NSS_IMPLEMENT PRBool
    183 nssCKObject_IsAttributeTrue(
    184    CK_OBJECT_HANDLE object,
    185    CK_ATTRIBUTE_TYPE attribute,
    186    nssSession *session,
    187    NSSSlot *slot,
    188    PRStatus *rvStatus)
    189 {
    190    CK_BBOOL bool;
    191    CK_ATTRIBUTE_PTR attr;
    192    CK_ATTRIBUTE atemplate = { 0, NULL, 0 };
    193    CK_RV ckrv;
    194    void *epv = nssSlot_GetCryptokiEPV(slot);
    195    attr = &atemplate;
    196    NSS_CK_SET_ATTRIBUTE_VAR(attr, attribute, bool);
    197    nssSession_EnterMonitor(session);
    198    ckrv = CKAPI(epv)->C_GetAttributeValue(session->handle, object,
    199                                           &atemplate, 1);
    200    nssSession_ExitMonitor(session);
    201    if (ckrv != CKR_OK) {
    202        *rvStatus = PR_FAILURE;
    203        return PR_FALSE;
    204    }
    205    *rvStatus = PR_SUCCESS;
    206    return (PRBool)(bool == CK_TRUE);
    207 }
    208 
    209 NSS_IMPLEMENT PRStatus
    210 nssCKObject_SetAttributes(
    211    CK_OBJECT_HANDLE object,
    212    CK_ATTRIBUTE_PTR obj_template,
    213    CK_ULONG count,
    214    nssSession *session,
    215    NSSSlot *slot)
    216 {
    217    CK_RV ckrv;
    218    void *epv = nssSlot_GetCryptokiEPV(slot);
    219    nssSession_EnterMonitor(session);
    220    ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle, object,
    221                                           obj_template, count);
    222    nssSession_ExitMonitor(session);
    223    if (ckrv == CKR_OK) {
    224        return PR_SUCCESS;
    225    } else {
    226        return PR_FAILURE;
    227    }
    228 }
    229 
    230 NSS_IMPLEMENT PRBool
    231 nssCKObject_IsTokenObjectTemplate(
    232    CK_ATTRIBUTE_PTR objectTemplate,
    233    CK_ULONG otsize)
    234 {
    235    CK_ULONG ul;
    236    for (ul = 0; ul < otsize; ul++) {
    237        if (objectTemplate[ul].type == CKA_TOKEN) {
    238            return (*((CK_BBOOL *)objectTemplate[ul].pValue) == CK_TRUE);
    239        }
    240    }
    241    return PR_FALSE;
    242 }
    243 
    244 static NSSCertificateType
    245 nss_cert_type_from_ck_attrib(CK_ATTRIBUTE_PTR attrib)
    246 {
    247    CK_CERTIFICATE_TYPE ckCertType;
    248    if (!attrib->pValue) {
    249        /* default to PKIX */
    250        return NSSCertificateType_PKIX;
    251    }
    252    ckCertType = *((CK_ULONG *)attrib->pValue);
    253    switch (ckCertType) {
    254        case CKC_X_509:
    255            return NSSCertificateType_PKIX;
    256        default:
    257            break;
    258    }
    259    return NSSCertificateType_Unknown;
    260 }
    261 
    262 /* incoming pointers must be valid */
    263 NSS_IMPLEMENT PRStatus
    264 nssCryptokiCertificate_GetAttributes(
    265    nssCryptokiObject *certObject,
    266    nssSession *sessionOpt,
    267    NSSArena *arenaOpt,
    268    NSSCertificateType *certTypeOpt,
    269    NSSItem *idOpt,
    270    NSSDER *encodingOpt,
    271    NSSDER *issuerOpt,
    272    NSSDER *serialOpt,
    273    NSSDER *subjectOpt)
    274 {
    275    PRStatus status;
    276    PRUint32 i;
    277    nssSession *session;
    278    NSSSlot *slot;
    279    CK_ULONG template_size;
    280    CK_ATTRIBUTE_PTR attr;
    281    CK_ATTRIBUTE cert_template[6];
    282    /* Set up a template of all options chosen by caller */
    283    NSS_CK_TEMPLATE_START(cert_template, attr, template_size);
    284    if (certTypeOpt) {
    285        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CERTIFICATE_TYPE);
    286    }
    287    if (idOpt) {
    288        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ID);
    289    }
    290    if (encodingOpt) {
    291        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
    292    }
    293    if (issuerOpt) {
    294        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ISSUER);
    295    }
    296    if (serialOpt) {
    297        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SERIAL_NUMBER);
    298    }
    299    if (subjectOpt) {
    300        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT);
    301    }
    302    NSS_CK_TEMPLATE_FINISH(cert_template, attr, template_size);
    303    if (template_size == 0) {
    304        /* caller didn't want anything */
    305        return PR_SUCCESS;
    306    }
    307 
    308    status = nssToken_GetCachedObjectAttributes(certObject->token, arenaOpt,
    309                                                certObject, CKO_CERTIFICATE,
    310                                                cert_template, template_size);
    311    if (status != PR_SUCCESS) {
    312 
    313        session = sessionOpt ? sessionOpt
    314                             : nssToken_GetDefaultSession(certObject->token);
    315        if (!session) {
    316            nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
    317            return PR_FAILURE;
    318        }
    319 
    320        slot = nssToken_GetSlot(certObject->token);
    321        status = nssCKObject_GetAttributes(certObject->handle,
    322                                           cert_template, template_size,
    323                                           arenaOpt, session, slot);
    324        nssSlot_Destroy(slot);
    325        if (status != PR_SUCCESS) {
    326            return status;
    327        }
    328    }
    329 
    330    i = 0;
    331    if (certTypeOpt) {
    332        *certTypeOpt = nss_cert_type_from_ck_attrib(&cert_template[i]);
    333        i++;
    334    }
    335    if (idOpt) {
    336        NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], idOpt);
    337        i++;
    338    }
    339    if (encodingOpt) {
    340        NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], encodingOpt);
    341        i++;
    342    }
    343    if (issuerOpt) {
    344        NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], issuerOpt);
    345        i++;
    346    }
    347    if (serialOpt) {
    348        NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], serialOpt);
    349        i++;
    350    }
    351    if (subjectOpt) {
    352        NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], subjectOpt);
    353        i++;
    354    }
    355    return PR_SUCCESS;
    356 }
    357 
    358 static nssTrustLevel
    359 get_nss_trust(
    360    CK_TRUST ckt)
    361 {
    362    nssTrustLevel t;
    363    switch (ckt) {
    364        case CKT_NSS_NOT_TRUSTED:
    365        case CKT_NOT_TRUSTED:
    366            t = nssTrustLevel_NotTrusted;
    367            break;
    368        case CKT_NSS_TRUSTED_DELEGATOR:
    369        case CKT_TRUST_ANCHOR:
    370            t = nssTrustLevel_TrustedDelegator;
    371            break;
    372        case CKT_NSS_VALID_DELEGATOR:
    373            t = nssTrustLevel_ValidDelegator;
    374            break;
    375        case CKT_NSS_TRUSTED:
    376        case CKT_TRUSTED:
    377            t = nssTrustLevel_Trusted;
    378            break;
    379        case CKT_NSS_MUST_VERIFY_TRUST:
    380        case CKT_TRUST_MUST_VERIFY_TRUST:
    381            t = nssTrustLevel_MustVerify;
    382            break;
    383        case CKT_NSS_TRUST_UNKNOWN:
    384        case CKT_TRUST_UNKNOWN:
    385        default:
    386            t = nssTrustLevel_Unknown;
    387            break;
    388    }
    389    return t;
    390 }
    391 
    392 NSS_IMPLEMENT PRStatus
    393 nssCryptokiTrust_GetAttributes(
    394    nssCryptokiObject *trustObject,
    395    nssSession *sessionOpt,
    396    NSSItem *hash,
    397    CK_MECHANISM_TYPE *hashMech,
    398    nssTrustLevel *serverAuth,
    399    nssTrustLevel *clientAuth,
    400    nssTrustLevel *codeSigning,
    401    nssTrustLevel *emailProtection,
    402    PRBool *stepUpApproved)
    403 {
    404    PRStatus status;
    405    NSSSlot *slot;
    406    nssSession *session;
    407    CK_BBOOL isToken = PR_FALSE;
    408    /* default values if the trust is record does not exist. In the highly
    409     * unlikely case that these change, be sure to update softoken's
    410     * 'sftkdb_isNullTrust()' function */
    411    CK_BBOOL stepUp = PR_FALSE;
    412    CK_TRUST saTrust = CKT_TRUST_UNKNOWN;
    413    CK_TRUST caTrust = CKT_TRUST_UNKNOWN;
    414    CK_TRUST epTrust = CKT_TRUST_UNKNOWN;
    415    CK_TRUST csTrust = CKT_TRUST_UNKNOWN;
    416    CK_ATTRIBUTE_PTR attr;
    417    CK_ATTRIBUTE trust_template[7];
    418    CK_ATTRIBUTE_PTR hash_attr;
    419    CK_ULONG trust_size;
    420 
    421    /* Use the trust object to find the trust settings */
    422    NSS_CK_TEMPLATE_START(trust_template, attr, trust_size);
    423    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TOKEN, isToken);
    424    switch (trustObject->trustType) {
    425        case CKO_TRUST:
    426            *hashMech = CKM_INVALID_MECHANISM;
    427            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_SERVER_AUTH, saTrust);
    428            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_CLIENT_AUTH, caTrust);
    429            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_EMAIL_PROTECTION, epTrust);
    430            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_CODE_SIGNING, csTrust);
    431            hash_attr = attr;
    432            NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_HASH_OF_CERTIFICATE, hash);
    433            NSS_CK_SET_ATTRIBUTE_FIXED_PTR(attr, CKA_NAME_HASH_ALGORITHM, hashMech);
    434            break;
    435        case CKO_NSS_TRUST:
    436            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_SERVER_AUTH, saTrust);
    437            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_CLIENT_AUTH, caTrust);
    438            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_EMAIL_PROTECTION, epTrust);
    439            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_CODE_SIGNING, csTrust);
    440            NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_STEP_UP_APPROVED, stepUp);
    441            hash_attr = attr;
    442            NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_CERT_SHA1_HASH, hash);
    443            *hashMech = CKM_SHA_1;
    444            break;
    445        default:
    446            /* shouldn't happen, crash on debug builds if it does */
    447            PORT_Assert(0 || trustObject->trustType);
    448            nss_SetError(NSS_ERROR_INTERNAL_ERROR);
    449            return PR_FAILURE;
    450    }
    451    NSS_CK_TEMPLATE_FINISH(trust_template, attr, trust_size);
    452 
    453    status = nssToken_GetCachedObjectAttributes(trustObject->token, NULL,
    454                                                trustObject,
    455                                                trustObject->trustType,
    456                                                trust_template, trust_size);
    457    if (status != PR_SUCCESS) {
    458        session = sessionOpt ? sessionOpt
    459                             : nssToken_GetDefaultSession(trustObject->token);
    460        if (!session) {
    461            nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
    462            return PR_FAILURE;
    463        }
    464 
    465        slot = nssToken_GetSlot(trustObject->token);
    466        status = nssCKObject_GetAttributes(trustObject->handle,
    467                                           trust_template, trust_size,
    468                                           NULL, session, slot);
    469        nssSlot_Destroy(slot);
    470        if (status != PR_SUCCESS) {
    471            return status;
    472        }
    473    }
    474 
    475    if (hash_attr->ulValueLen == -1) {
    476        /* The trust object does not have the certificate hash attribute. */
    477        hash_attr->ulValueLen = 0;
    478    }
    479    hash->size = hash_attr->ulValueLen;
    480    *serverAuth = get_nss_trust(saTrust);
    481    *clientAuth = get_nss_trust(caTrust);
    482    *emailProtection = get_nss_trust(epTrust);
    483    *codeSigning = get_nss_trust(csTrust);
    484    *stepUpApproved = stepUp;
    485    return PR_SUCCESS;
    486 }
    487 
    488 NSS_IMPLEMENT PRStatus
    489 nssCryptokiCRL_GetAttributes(
    490    nssCryptokiObject *crlObject,
    491    nssSession *sessionOpt,
    492    NSSArena *arenaOpt,
    493    NSSItem *encodingOpt,
    494    NSSItem *subjectOpt,
    495    CK_ULONG *crl_class,
    496    NSSUTF8 **urlOpt,
    497    PRBool *isKRLOpt)
    498 {
    499    PRStatus status;
    500    NSSSlot *slot;
    501    nssSession *session;
    502    CK_ATTRIBUTE_PTR attr;
    503    CK_ATTRIBUTE crl_template[7];
    504    CK_ULONG crl_size;
    505    PRUint32 i;
    506 
    507    NSS_CK_TEMPLATE_START(crl_template, attr, crl_size);
    508    if (crl_class) {
    509        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CLASS);
    510    }
    511    if (encodingOpt) {
    512        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
    513    }
    514    if (urlOpt) {
    515        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NSS_URL);
    516    }
    517    if (isKRLOpt) {
    518        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NSS_KRL);
    519    }
    520    if (subjectOpt) {
    521        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT);
    522    }
    523    NSS_CK_TEMPLATE_FINISH(crl_template, attr, crl_size);
    524 
    525    status = nssToken_GetCachedObjectAttributes(crlObject->token, NULL,
    526                                                crlObject,
    527                                                CKO_NSS_CRL,
    528                                                crl_template, crl_size);
    529    if (status != PR_SUCCESS) {
    530        session = sessionOpt ? sessionOpt
    531                             : nssToken_GetDefaultSession(crlObject->token);
    532        if (session == NULL) {
    533            nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
    534            return PR_FAILURE;
    535        }
    536 
    537        slot = nssToken_GetSlot(crlObject->token);
    538        status = nssCKObject_GetAttributes(crlObject->handle,
    539                                           crl_template, crl_size,
    540                                           arenaOpt, session, slot);
    541        nssSlot_Destroy(slot);
    542        if (status != PR_SUCCESS) {
    543            return status;
    544        }
    545    }
    546 
    547    i = 0;
    548    if (crl_class) {
    549        NSS_CK_ATTRIBUTE_TO_ULONG(&crl_template[i], *crl_class);
    550        i++;
    551    }
    552    if (encodingOpt) {
    553        NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], encodingOpt);
    554        i++;
    555    }
    556    if (urlOpt) {
    557        NSS_CK_ATTRIBUTE_TO_UTF8(&crl_template[i], *urlOpt);
    558        i++;
    559    }
    560    if (isKRLOpt) {
    561        NSS_CK_ATTRIBUTE_TO_BOOL(&crl_template[i], *isKRLOpt);
    562        i++;
    563    }
    564    if (subjectOpt) {
    565        NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], subjectOpt);
    566        i++;
    567    }
    568    return PR_SUCCESS;
    569 }
    570 
    571 NSS_IMPLEMENT PRStatus
    572 nssCryptokiPrivateKey_SetCertificate(
    573    nssCryptokiObject *keyObject,
    574    nssSession *sessionOpt,
    575    const NSSUTF8 *nickname,
    576    NSSItem *id,
    577    NSSDER *subject)
    578 {
    579    CK_RV ckrv;
    580    CK_ATTRIBUTE_PTR attr;
    581    CK_ATTRIBUTE key_template[3];
    582    CK_ULONG key_size;
    583    void *epv = nssToken_GetCryptokiEPV(keyObject->token);
    584    nssSession *session;
    585    NSSToken *token = keyObject->token;
    586    nssSession *defaultSession = nssToken_GetDefaultSession(token);
    587    PRBool createdSession = PR_FALSE;
    588 
    589    NSS_CK_TEMPLATE_START(key_template, attr, key_size);
    590    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
    591    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
    592    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
    593    NSS_CK_TEMPLATE_FINISH(key_template, attr, key_size);
    594 
    595    if (sessionOpt) {
    596        if (!nssSession_IsReadWrite(sessionOpt)) {
    597            return PR_FAILURE;
    598        }
    599        session = sessionOpt;
    600    } else if (defaultSession && nssSession_IsReadWrite(defaultSession)) {
    601        session = defaultSession;
    602    } else {
    603        NSSSlot *slot = nssToken_GetSlot(token);
    604        session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
    605        nssSlot_Destroy(slot);
    606        if (!session) {
    607            return PR_FAILURE;
    608        }
    609        createdSession = PR_TRUE;
    610    }
    611 
    612    ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle,
    613                                           keyObject->handle,
    614                                           key_template,
    615                                           key_size);
    616 
    617    if (createdSession) {
    618        nssSession_Destroy(session);
    619    }
    620 
    621    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
    622 }