Coverage Report

Created: 2026-10-13 06:23

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