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 }