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