devtoken.c (53438B)
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 #include "pk11func.h" 16 #include "dev3hack.h" 17 #include "secerr.h" 18 19 extern const NSSError NSS_ERROR_NOT_FOUND; 20 extern const NSSError NSS_ERROR_INVALID_ARGUMENT; 21 extern const NSSError NSS_ERROR_PKCS11; 22 23 /* The number of object handles to grab during each call to C_FindObjects */ 24 #define OBJECT_STACK_SIZE 16 25 26 NSS_IMPLEMENT PRStatus 27 nssToken_Destroy( 28 NSSToken *tok) 29 { 30 if (tok) { 31 if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) { 32 PK11_FreeSlot(tok->pk11slot); 33 PZ_DestroyLock(tok->base.lock); 34 nssTokenObjectCache_Destroy(tok->cache); 35 (void)nssSlot_Destroy(tok->slot); 36 return nssArena_Destroy(tok->base.arena); 37 } 38 } 39 return PR_SUCCESS; 40 } 41 42 NSS_IMPLEMENT void 43 nssToken_Remove( 44 NSSToken *tok) 45 { 46 nssTokenObjectCache_Clear(tok->cache); 47 } 48 49 NSS_IMPLEMENT NSSToken * 50 nssToken_AddRef( 51 NSSToken *tok) 52 { 53 PR_ATOMIC_INCREMENT(&tok->base.refCount); 54 return tok; 55 } 56 57 NSS_IMPLEMENT NSSSlot * 58 nssToken_GetSlot( 59 NSSToken *tok) 60 { 61 return nssSlot_AddRef(tok->slot); 62 } 63 64 NSS_IMPLEMENT void * 65 nssToken_GetCryptokiEPV( 66 NSSToken *token) 67 { 68 return nssSlot_GetCryptokiEPV(token->slot); 69 } 70 71 NSS_IMPLEMENT nssSession * 72 nssToken_GetDefaultSession( 73 NSSToken *token) 74 { 75 return token->defaultSession; 76 } 77 78 NSS_IMPLEMENT NSSUTF8 * 79 nssToken_GetName( 80 NSSToken *tok) 81 { 82 if (tok == NULL) { 83 return ""; 84 } 85 if (tok->base.name[0] == 0) { 86 (void)nssSlot_IsTokenPresent(tok->slot); 87 } 88 return tok->base.name; 89 } 90 91 NSS_IMPLEMENT NSSUTF8 * 92 NSSToken_GetName( 93 NSSToken *token) 94 { 95 return nssToken_GetName(token); 96 } 97 98 NSS_IMPLEMENT PRBool 99 nssToken_IsLoginRequired( 100 NSSToken *token) 101 { 102 return (token->ckFlags & CKF_LOGIN_REQUIRED); 103 } 104 105 NSS_IMPLEMENT PRBool 106 nssToken_NeedsPINInitialization( 107 NSSToken *token) 108 { 109 return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED)); 110 } 111 112 NSS_IMPLEMENT PRStatus 113 nssToken_DeleteStoredObject( 114 nssCryptokiObject *instance) 115 { 116 CK_RV ckrv; 117 PRStatus status; 118 PRBool createdSession = PR_FALSE; 119 NSSToken *token = instance->token; 120 nssSession *session = NULL; 121 void *epv = nssToken_GetCryptokiEPV(instance->token); 122 if (token->cache) { 123 nssTokenObjectCache_RemoveObject(token->cache, instance); 124 } 125 if (instance->isTokenObject) { 126 if (token->defaultSession && 127 nssSession_IsReadWrite(token->defaultSession)) { 128 session = token->defaultSession; 129 } else { 130 session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE); 131 createdSession = PR_TRUE; 132 } 133 } 134 if (session == NULL) { 135 return PR_FAILURE; 136 } 137 nssSession_EnterMonitor(session); 138 ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle); 139 nssSession_ExitMonitor(session); 140 if (createdSession) { 141 nssSession_Destroy(session); 142 } 143 status = PR_SUCCESS; 144 if (ckrv != CKR_OK) { 145 status = PR_FAILURE; 146 /* use the error stack to pass the PKCS #11 error out */ 147 nss_SetError(ckrv); 148 nss_SetError(NSS_ERROR_PKCS11); 149 } 150 return status; 151 } 152 153 static nssCryptokiObject * 154 import_object( 155 NSSToken *tok, 156 nssSession *sessionOpt, 157 CK_ATTRIBUTE_PTR objectTemplate, 158 CK_ULONG otsize) 159 { 160 nssSession *session = NULL; 161 PRBool createdSession = PR_FALSE; 162 nssCryptokiObject *object = NULL; 163 CK_OBJECT_HANDLE handle; 164 CK_RV ckrv; 165 void *epv = nssToken_GetCryptokiEPV(tok); 166 if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) { 167 if (sessionOpt) { 168 if (!nssSession_IsReadWrite(sessionOpt)) { 169 nss_SetError(NSS_ERROR_INVALID_ARGUMENT); 170 return NULL; 171 } 172 session = sessionOpt; 173 } else if (tok->defaultSession && 174 nssSession_IsReadWrite(tok->defaultSession)) { 175 session = tok->defaultSession; 176 } else { 177 session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE); 178 createdSession = PR_TRUE; 179 } 180 } else { 181 session = (sessionOpt) ? sessionOpt : tok->defaultSession; 182 } 183 if (session == NULL) { 184 nss_SetError(NSS_ERROR_INVALID_ARGUMENT); 185 return NULL; 186 } 187 nssSession_EnterMonitor(session); 188 ckrv = CKAPI(epv)->C_CreateObject(session->handle, 189 objectTemplate, otsize, 190 &handle); 191 nssSession_ExitMonitor(session); 192 if (ckrv == CKR_OK) { 193 object = nssCryptokiObject_Create(tok, session, handle); 194 } else { 195 nss_SetError(ckrv); 196 nss_SetError(NSS_ERROR_PKCS11); 197 } 198 if (createdSession) { 199 nssSession_Destroy(session); 200 } 201 return object; 202 } 203 204 static nssCryptokiObject ** 205 create_objects_from_handles( 206 NSSToken *tok, 207 nssSession *session, 208 CK_OBJECT_HANDLE *handles, 209 PRUint32 numH) 210 { 211 nssCryptokiObject **objects; 212 if (numH == PR_UINT32_MAX) { 213 return NULL; /* avoid overflow in ZNEWARRAY */ 214 } 215 objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1); 216 if (!objects) { 217 return NULL; 218 } 219 for (PRUint32 i = 0; i < numH; i++) { 220 objects[i] = nssCryptokiObject_Create(tok, session, handles[i]); 221 if (!objects[i]) { 222 for (; i > 0; --i) { 223 nssCryptokiObject_Destroy(objects[i - 1]); 224 } 225 nss_ZFreeIf(objects); 226 return NULL; 227 } 228 } 229 return objects; 230 } 231 232 static nssCryptokiObject ** 233 find_objects( 234 NSSToken *tok, 235 nssSession *sessionOpt, 236 CK_ATTRIBUTE_PTR obj_template, 237 CK_ULONG otsize, 238 PRUint32 maximumOpt, 239 PRStatus *statusOpt) 240 { 241 CK_RV ckrv = CKR_OK; 242 CK_ULONG count; 243 CK_OBJECT_HANDLE *objectHandles = NULL; 244 CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE]; 245 PRUint32 arraySize, numHandles; 246 void *epv = nssToken_GetCryptokiEPV(tok); 247 nssCryptokiObject **objects; 248 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; 249 250 /* Don't ask the module to use an invalid session handle. */ 251 if (!session || session->handle == CK_INVALID_HANDLE) { 252 ckrv = CKR_SESSION_HANDLE_INVALID; 253 goto loser; 254 } 255 256 /* the arena is only for the array of object handles */ 257 if (maximumOpt > 0) { 258 arraySize = maximumOpt; 259 } else { 260 arraySize = OBJECT_STACK_SIZE; 261 } 262 numHandles = 0; 263 if (arraySize <= OBJECT_STACK_SIZE) { 264 objectHandles = staticObjects; 265 } else { 266 objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize); 267 } 268 if (!objectHandles) { 269 ckrv = CKR_HOST_MEMORY; 270 goto loser; 271 } 272 nssSession_EnterMonitor(session); /* ==== session lock === */ 273 /* Initialize the find with the template */ 274 ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 275 obj_template, otsize); 276 if (ckrv != CKR_OK) { 277 nssSession_ExitMonitor(session); 278 goto loser; 279 } 280 while (PR_TRUE) { 281 /* Issue the find for up to arraySize - numHandles objects */ 282 ckrv = CKAPI(epv)->C_FindObjects(session->handle, 283 objectHandles + numHandles, 284 arraySize - numHandles, 285 &count); 286 if (ckrv != CKR_OK) { 287 nssSession_ExitMonitor(session); 288 goto loser; 289 } 290 /* bump the number of found objects */ 291 numHandles += count; 292 if (maximumOpt > 0 || numHandles < arraySize) { 293 /* When a maximum is provided, the search is done all at once, 294 * so the search is finished. If the number returned was less 295 * than the number sought, the search is finished. 296 */ 297 break; 298 } 299 /* the array is filled, double it and continue */ 300 arraySize *= 2; 301 if (objectHandles == staticObjects) { 302 objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize); 303 if (objectHandles) { 304 PORT_Memcpy(objectHandles, staticObjects, 305 OBJECT_STACK_SIZE * sizeof(objectHandles[1])); 306 } 307 } else { 308 objectHandles = nss_ZREALLOCARRAY(objectHandles, 309 CK_OBJECT_HANDLE, 310 arraySize); 311 } 312 if (!objectHandles) { 313 nssSession_ExitMonitor(session); 314 ckrv = CKR_HOST_MEMORY; 315 goto loser; 316 } 317 } 318 ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle); 319 nssSession_ExitMonitor(session); /* ==== end session lock === */ 320 if (ckrv != CKR_OK) { 321 goto loser; 322 } 323 if (numHandles > 0) { 324 objects = create_objects_from_handles(tok, session, 325 objectHandles, numHandles); 326 } else { 327 nss_SetError(NSS_ERROR_NOT_FOUND); 328 objects = NULL; 329 } 330 if (objectHandles && objectHandles != staticObjects) { 331 nss_ZFreeIf(objectHandles); 332 } 333 if (statusOpt) 334 *statusOpt = PR_SUCCESS; 335 return objects; 336 loser: 337 if (objectHandles && objectHandles != staticObjects) { 338 nss_ZFreeIf(objectHandles); 339 } 340 /* 341 * These errors should be treated the same as if the objects just weren't 342 * found.. 343 */ 344 if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) || 345 (ckrv == CKR_ATTRIBUTE_VALUE_INVALID) || 346 (ckrv == CKR_DATA_INVALID) || 347 (ckrv == CKR_DATA_LEN_RANGE) || 348 (ckrv == CKR_FUNCTION_NOT_SUPPORTED) || 349 (ckrv == CKR_TEMPLATE_INCOMPLETE) || 350 (ckrv == CKR_TEMPLATE_INCONSISTENT)) { 351 352 nss_SetError(NSS_ERROR_NOT_FOUND); 353 if (statusOpt) 354 *statusOpt = PR_SUCCESS; 355 } else { 356 nss_SetError(ckrv); 357 nss_SetError(NSS_ERROR_PKCS11); 358 if (statusOpt) 359 *statusOpt = PR_FAILURE; 360 } 361 return (nssCryptokiObject **)NULL; 362 } 363 364 NSS_IMPLEMENT nssCryptokiObject ** 365 nssToken_FindObjectsByTemplate( 366 NSSToken *token, 367 nssSession *sessionOpt, 368 CK_ATTRIBUTE_PTR obj_template, 369 CK_ULONG otsize, 370 PRUint32 maximumOpt, 371 PRStatus *statusOpt) 372 { 373 CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1; 374 nssCryptokiObject **objects = NULL; 375 PRUint32 i; 376 377 if (!token) { 378 PORT_SetError(SEC_ERROR_NO_TOKEN); 379 if (statusOpt) 380 *statusOpt = PR_FAILURE; 381 return NULL; 382 } 383 for (i = 0; i < otsize; i++) { 384 if (obj_template[i].type == CKA_CLASS) { 385 objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue; 386 break; 387 } 388 } 389 PR_ASSERT(i < otsize); 390 if (i == otsize) { 391 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 392 if (statusOpt) 393 *statusOpt = PR_FAILURE; 394 return NULL; 395 } 396 /* If these objects are being cached, try looking there first */ 397 if (token->cache && 398 nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) { 399 PRStatus status; 400 objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache, 401 objclass, 402 obj_template, 403 otsize, 404 maximumOpt, 405 &status); 406 if (status == PR_SUCCESS) { 407 if (statusOpt) 408 *statusOpt = status; 409 return objects; 410 } 411 } 412 /* Either they are not cached, or cache failed; look on token. */ 413 objects = find_objects(token, sessionOpt, 414 obj_template, otsize, 415 maximumOpt, statusOpt); 416 return objects; 417 } 418 419 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; 420 421 NSS_IMPLEMENT nssCryptokiObject * 422 nssToken_ImportCertificate( 423 NSSToken *tok, 424 nssSession *sessionOpt, 425 NSSCertificateType certType, 426 NSSItem *id, 427 const NSSUTF8 *nickname, 428 NSSDER *encoding, 429 NSSDER *issuer, 430 NSSDER *subject, 431 NSSDER *serial, 432 NSSASCII7 *email, 433 PRBool asTokenObject) 434 { 435 PRStatus status; 436 CK_CERTIFICATE_TYPE cert_type; 437 CK_ATTRIBUTE_PTR attr; 438 CK_ATTRIBUTE cert_tmpl[10]; 439 CK_ULONG ctsize; 440 nssTokenSearchType searchType; 441 nssCryptokiObject *rvObject = NULL; 442 443 if (!tok) { 444 PORT_SetError(SEC_ERROR_NO_TOKEN); 445 return NULL; 446 } 447 if (certType == NSSCertificateType_PKIX) { 448 cert_type = CKC_X_509; 449 } else { 450 return (nssCryptokiObject *)NULL; 451 } 452 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize); 453 if (asTokenObject) { 454 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 455 searchType = nssTokenSearchType_TokenOnly; 456 } else { 457 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 458 searchType = nssTokenSearchType_SessionOnly; 459 } 460 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); 461 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CERTIFICATE_TYPE, cert_type); 462 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id); 463 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname); 464 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding); 465 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer); 466 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); 467 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial); 468 if (email) { 469 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email); 470 } 471 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize); 472 /* see if the cert is already there */ 473 rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok, 474 sessionOpt, 475 issuer, 476 serial, 477 searchType, 478 NULL); 479 if (rvObject) { 480 NSSItem existingDER; 481 NSSSlot *slot = nssToken_GetSlot(tok); 482 nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE); 483 if (!session) { 484 nssCryptokiObject_Destroy(rvObject); 485 nssSlot_Destroy(slot); 486 return (nssCryptokiObject *)NULL; 487 } 488 /* Reject any attempt to import a new cert that has the same 489 * issuer/serial as an existing cert, but does not have the 490 * same encoding 491 */ 492 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize); 493 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE); 494 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize); 495 status = nssCKObject_GetAttributes(rvObject->handle, 496 cert_tmpl, ctsize, NULL, 497 session, slot); 498 NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER); 499 if (status == PR_SUCCESS) { 500 if (!nssItem_Equal(encoding, &existingDER, NULL)) { 501 nss_SetError(NSS_ERROR_INVALID_CERTIFICATE); 502 status = PR_FAILURE; 503 } 504 nss_ZFreeIf(existingDER.data); 505 } 506 if (status == PR_FAILURE) { 507 nssCryptokiObject_Destroy(rvObject); 508 nssSession_Destroy(session); 509 nssSlot_Destroy(slot); 510 return (nssCryptokiObject *)NULL; 511 } 512 /* according to PKCS#11, label, ID, issuer, and serial number 513 * may change after the object has been created. For PKIX, the 514 * last two attributes can't change, so for now we'll only worry 515 * about the first two. 516 */ 517 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize); 518 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id); 519 if (!rvObject->label && nickname) { 520 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname); 521 } 522 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize); 523 /* reset the mutable attributes on the token */ 524 nssCKObject_SetAttributes(rvObject->handle, 525 cert_tmpl, ctsize, 526 session, slot); 527 if (!rvObject->label && nickname) { 528 rvObject->label = nssUTF8_Duplicate(nickname, NULL); 529 } 530 nssSession_Destroy(session); 531 nssSlot_Destroy(slot); 532 } else { 533 /* Import the certificate onto the token */ 534 rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize); 535 } 536 if (rvObject && tok->cache) { 537 /* The cache will overwrite the attributes if the object already 538 * exists. 539 */ 540 nssTokenObjectCache_ImportObject(tok->cache, rvObject, 541 CKO_CERTIFICATE, 542 cert_tmpl, ctsize); 543 } 544 return rvObject; 545 } 546 547 /* traverse all objects of the given class - this should only happen 548 * if the token has been marked as "traversable" 549 */ 550 NSS_IMPLEMENT nssCryptokiObject ** 551 nssToken_FindObjects( 552 NSSToken *token, 553 nssSession *sessionOpt, 554 CK_OBJECT_CLASS objclass, 555 nssTokenSearchType searchType, 556 PRUint32 maximumOpt, 557 PRStatus *statusOpt) 558 { 559 CK_ATTRIBUTE_PTR attr; 560 CK_ATTRIBUTE obj_template[2]; 561 CK_ULONG obj_size; 562 nssCryptokiObject **objects; 563 NSS_CK_TEMPLATE_START(obj_template, attr, obj_size); 564 /* Set the search to token/session only if provided */ 565 if (searchType == nssTokenSearchType_SessionOnly) { 566 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 567 } else if (searchType == nssTokenSearchType_TokenOnly || 568 searchType == nssTokenSearchType_TokenForced) { 569 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 570 } 571 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, objclass); 572 NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size); 573 574 if (searchType == nssTokenSearchType_TokenForced) { 575 objects = find_objects(token, sessionOpt, 576 obj_template, obj_size, 577 maximumOpt, statusOpt); 578 } else { 579 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 580 obj_template, obj_size, 581 maximumOpt, statusOpt); 582 } 583 return objects; 584 } 585 586 NSS_IMPLEMENT nssCryptokiObject ** 587 nssToken_FindCertificatesBySubject( 588 NSSToken *token, 589 nssSession *sessionOpt, 590 NSSDER *subject, 591 nssTokenSearchType searchType, 592 PRUint32 maximumOpt, 593 PRStatus *statusOpt) 594 { 595 CK_ATTRIBUTE_PTR attr; 596 CK_ATTRIBUTE subj_template[3]; 597 CK_ULONG stsize; 598 nssCryptokiObject **objects; 599 NSS_CK_TEMPLATE_START(subj_template, attr, stsize); 600 /* Set the search to token/session only if provided */ 601 if (searchType == nssTokenSearchType_SessionOnly) { 602 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 603 } else if (searchType == nssTokenSearchType_TokenOnly) { 604 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 605 } 606 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); 607 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); 608 NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize); 609 /* now locate the token certs matching this template */ 610 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 611 subj_template, stsize, 612 maximumOpt, statusOpt); 613 return objects; 614 } 615 616 NSS_IMPLEMENT nssCryptokiObject ** 617 nssToken_FindCertificatesByNickname( 618 NSSToken *token, 619 nssSession *sessionOpt, 620 const NSSUTF8 *name, 621 nssTokenSearchType searchType, 622 PRUint32 maximumOpt, 623 PRStatus *statusOpt) 624 { 625 CK_ATTRIBUTE_PTR attr; 626 CK_ATTRIBUTE nick_template[3]; 627 CK_ULONG ntsize; 628 nssCryptokiObject **objects; 629 NSS_CK_TEMPLATE_START(nick_template, attr, ntsize); 630 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name); 631 /* Set the search to token/session only if provided */ 632 if (searchType == nssTokenSearchType_SessionOnly) { 633 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 634 } else if (searchType == nssTokenSearchType_TokenOnly) { 635 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 636 } 637 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); 638 NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize); 639 /* now locate the token certs matching this template */ 640 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 641 nick_template, ntsize, 642 maximumOpt, statusOpt); 643 if (!objects) { 644 /* This is to workaround the fact that PKCS#11 doesn't specify 645 * whether the '\0' should be included. XXX Is that still true? 646 * im - this is not needed by the current softoken. However, I'm 647 * leaving it in until I have surveyed more tokens to see if it needed. 648 * well, its needed by the builtin token... 649 */ 650 nick_template[0].ulValueLen++; 651 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 652 nick_template, ntsize, 653 maximumOpt, statusOpt); 654 } 655 return objects; 656 } 657 658 /* XXX 659 * This function *does not* use the token object cache, because not even 660 * the softoken will return a value for CKA_NSS_EMAIL from a call 661 * to GetAttributes. The softoken does allow searches with that attribute, 662 * it just won't return a value for it. 663 */ 664 NSS_IMPLEMENT nssCryptokiObject ** 665 nssToken_FindCertificatesByEmail( 666 NSSToken *token, 667 nssSession *sessionOpt, 668 NSSASCII7 *email, 669 nssTokenSearchType searchType, 670 PRUint32 maximumOpt, 671 PRStatus *statusOpt) 672 { 673 CK_ATTRIBUTE_PTR attr; 674 CK_ATTRIBUTE email_template[3]; 675 CK_ULONG etsize; 676 nssCryptokiObject **objects; 677 NSS_CK_TEMPLATE_START(email_template, attr, etsize); 678 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email); 679 /* Set the search to token/session only if provided */ 680 if (searchType == nssTokenSearchType_SessionOnly) { 681 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 682 } else if (searchType == nssTokenSearchType_TokenOnly) { 683 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 684 } 685 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); 686 NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize); 687 /* now locate the token certs matching this template */ 688 objects = find_objects(token, sessionOpt, 689 email_template, etsize, 690 maximumOpt, statusOpt); 691 if (!objects) { 692 /* This is to workaround the fact that PKCS#11 doesn't specify 693 * whether the '\0' should be included. XXX Is that still true? 694 * im - this is not needed by the current softoken. However, I'm 695 * leaving it in until I have surveyed more tokens to see if it needed. 696 * well, its needed by the builtin token... 697 */ 698 email_template[0].ulValueLen++; 699 objects = find_objects(token, sessionOpt, 700 email_template, etsize, 701 maximumOpt, statusOpt); 702 } 703 return objects; 704 } 705 706 NSS_IMPLEMENT nssCryptokiObject ** 707 nssToken_FindCertificatesByID( 708 NSSToken *token, 709 nssSession *sessionOpt, 710 NSSItem *id, 711 nssTokenSearchType searchType, 712 PRUint32 maximumOpt, 713 PRStatus *statusOpt) 714 { 715 CK_ATTRIBUTE_PTR attr; 716 CK_ATTRIBUTE id_template[3]; 717 CK_ULONG idtsize; 718 nssCryptokiObject **objects; 719 NSS_CK_TEMPLATE_START(id_template, attr, idtsize); 720 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id); 721 /* Set the search to token/session only if provided */ 722 if (searchType == nssTokenSearchType_SessionOnly) { 723 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 724 } else if (searchType == nssTokenSearchType_TokenOnly) { 725 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 726 } 727 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); 728 NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize); 729 /* now locate the token certs matching this template */ 730 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 731 id_template, idtsize, 732 maximumOpt, statusOpt); 733 return objects; 734 } 735 736 /* 737 * decode the serial item and return our result. 738 * NOTE serialDecode's data is really stored in serial. Don't free it. 739 */ 740 static PRStatus 741 nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode) 742 { 743 unsigned char *data = (unsigned char *)serial->data; 744 int data_left, data_len, index; 745 746 if ((serial->size >= 3) && (data[0] == 0x2)) { 747 /* remove the der encoding of the serial number before generating the 748 * key.. */ 749 data_left = serial->size - 2; 750 data_len = data[1]; 751 index = 2; 752 753 /* extended length ? (not very likely for a serial number) */ 754 if (data_len & 0x80) { 755 int len_count = data_len & 0x7f; 756 757 data_len = 0; 758 data_left -= len_count; 759 if (data_left > 0) { 760 while (len_count--) { 761 data_len = (data_len << 8) | data[index++]; 762 } 763 } 764 } 765 /* XXX leaving any leading zeros on the serial number for backwards 766 * compatibility 767 */ 768 /* not a valid der, must be just an unlucky serial number value */ 769 if (data_len == data_left) { 770 serialDecode->size = data_len; 771 serialDecode->data = &data[index]; 772 return PR_SUCCESS; 773 } 774 } 775 return PR_FAILURE; 776 } 777 778 NSS_IMPLEMENT nssCryptokiObject * 779 nssToken_FindCertificateByIssuerAndSerialNumber( 780 NSSToken *token, 781 nssSession *sessionOpt, 782 NSSDER *issuer, 783 NSSDER *serial, 784 nssTokenSearchType searchType, 785 PRStatus *statusOpt) 786 { 787 CK_ATTRIBUTE_PTR attr; 788 CK_ATTRIBUTE_PTR serialAttr; 789 CK_ATTRIBUTE cert_template[4]; 790 CK_ULONG ctsize; 791 nssCryptokiObject **objects; 792 nssCryptokiObject *rvObject = NULL; 793 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize); 794 795 if (!token) { 796 PORT_SetError(SEC_ERROR_NO_TOKEN); 797 if (statusOpt) 798 *statusOpt = PR_FAILURE; 799 return NULL; 800 } 801 /* Set the search to token/session only if provided */ 802 if (searchType == nssTokenSearchType_SessionOnly) { 803 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 804 } else if ((searchType == nssTokenSearchType_TokenOnly) || 805 (searchType == nssTokenSearchType_TokenForced)) { 806 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 807 } 808 /* Set the unique id */ 809 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); 810 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer); 811 serialAttr = attr; 812 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial); 813 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize); 814 /* get the object handle */ 815 if (searchType == nssTokenSearchType_TokenForced) { 816 objects = find_objects(token, sessionOpt, 817 cert_template, ctsize, 818 1, statusOpt); 819 } else { 820 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 821 cert_template, ctsize, 822 1, statusOpt); 823 } 824 if (objects) { 825 rvObject = objects[0]; 826 nss_ZFreeIf(objects); 827 } 828 829 /* 830 * Some smart cards incorrectly store serial numbers in their decoded form. 831 */ 832 if (!objects) { 833 NSSItem serialDecode; 834 PRStatus status; 835 836 status = nssToken_decodeSerialItem(serial, &serialDecode); 837 if (status != PR_SUCCESS) { 838 return NULL; 839 } 840 NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr, CKA_SERIAL_NUMBER, &serialDecode); 841 if (searchType == nssTokenSearchType_TokenForced) { 842 objects = find_objects(token, sessionOpt, 843 cert_template, ctsize, 844 1, statusOpt); 845 } else { 846 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 847 cert_template, ctsize, 848 1, statusOpt); 849 } 850 if (objects) { 851 rvObject = objects[0]; 852 nss_ZFreeIf(objects); 853 } 854 } 855 return rvObject; 856 } 857 858 NSS_IMPLEMENT nssCryptokiObject * 859 nssToken_FindCertificateByEncodedCertificate( 860 NSSToken *token, 861 nssSession *sessionOpt, 862 NSSBER *encodedCertificate, 863 nssTokenSearchType searchType, 864 PRStatus *statusOpt) 865 { 866 CK_ATTRIBUTE_PTR attr; 867 CK_ATTRIBUTE cert_template[3]; 868 CK_ULONG ctsize; 869 nssCryptokiObject **objects; 870 nssCryptokiObject *rvObject = NULL; 871 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize); 872 /* Set the search to token/session only if provided */ 873 if (searchType == nssTokenSearchType_SessionOnly) { 874 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 875 } else if (searchType == nssTokenSearchType_TokenOnly) { 876 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 877 } 878 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); 879 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate); 880 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize); 881 /* get the object handle */ 882 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 883 cert_template, ctsize, 884 1, statusOpt); 885 if (objects) { 886 rvObject = objects[0]; 887 nss_ZFreeIf(objects); 888 } 889 return rvObject; 890 } 891 892 NSS_IMPLEMENT nssCryptokiObject ** 893 nssToken_FindPrivateKeys( 894 NSSToken *token, 895 nssSession *sessionOpt, 896 nssTokenSearchType searchType, 897 PRUint32 maximumOpt, 898 PRStatus *statusOpt) 899 { 900 CK_ATTRIBUTE_PTR attr; 901 CK_ATTRIBUTE key_template[2]; 902 CK_ULONG ktsize; 903 nssCryptokiObject **objects; 904 905 NSS_CK_TEMPLATE_START(key_template, attr, ktsize); 906 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey); 907 if (searchType == nssTokenSearchType_SessionOnly) { 908 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 909 } else if (searchType == nssTokenSearchType_TokenOnly) { 910 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 911 } 912 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize); 913 914 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 915 key_template, ktsize, 916 maximumOpt, statusOpt); 917 return objects; 918 } 919 920 /* XXX ?there are no session cert objects, so only search token objects */ 921 NSS_IMPLEMENT nssCryptokiObject * 922 nssToken_FindPrivateKeyByID( 923 NSSToken *token, 924 nssSession *sessionOpt, 925 NSSItem *keyID) 926 { 927 CK_ATTRIBUTE_PTR attr; 928 CK_ATTRIBUTE key_template[3]; 929 CK_ULONG ktsize; 930 nssCryptokiObject **objects; 931 nssCryptokiObject *rvKey = NULL; 932 933 NSS_CK_TEMPLATE_START(key_template, attr, ktsize); 934 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey); 935 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 936 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID); 937 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize); 938 939 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 940 key_template, ktsize, 941 1, NULL); 942 if (objects) { 943 rvKey = objects[0]; 944 nss_ZFreeIf(objects); 945 } 946 return rvKey; 947 } 948 949 /* XXX ?there are no session cert objects, so only search token objects */ 950 NSS_IMPLEMENT nssCryptokiObject * 951 nssToken_FindPublicKeyByID( 952 NSSToken *token, 953 nssSession *sessionOpt, 954 NSSItem *keyID) 955 { 956 CK_ATTRIBUTE_PTR attr; 957 CK_ATTRIBUTE key_template[3]; 958 CK_ULONG ktsize; 959 nssCryptokiObject **objects; 960 nssCryptokiObject *rvKey = NULL; 961 962 NSS_CK_TEMPLATE_START(key_template, attr, ktsize); 963 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey); 964 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 965 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID); 966 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize); 967 968 objects = nssToken_FindObjectsByTemplate(token, sessionOpt, 969 key_template, ktsize, 970 1, NULL); 971 if (objects) { 972 rvKey = objects[0]; 973 nss_ZFreeIf(objects); 974 } 975 return rvKey; 976 } 977 978 static PRBool 979 nss_TokenUsePKCS11Trust(NSSToken *tok) 980 { 981 void *evp = nssToken_GetCryptokiEPV(tok); 982 CK_VERSION vers; 983 984 if (!evp) { 985 return PR_FALSE; 986 } 987 vers = CKAPI(evp)->version; 988 if (vers.major < 3) { 989 return PR_FALSE; 990 } 991 if ((vers.major == 3) && (vers.minor < 2)) { 992 return PR_FALSE; 993 } 994 /* force the use of either PKCS11 trust or NSS trust */ 995 /* this only affects output, input always accepts both trust 996 * types */ 997 char *envp = PR_GetEnvSecure("NSS_TRUST_TYPE"); 998 if (envp) { 999 if (PORT_Strcasecmp(envp, "PKCS11") == 0) { 1000 return PR_TRUE; 1001 } 1002 if (PORT_Strcasecmp(envp, "NSS") == 0) { 1003 return PR_FALSE; 1004 } 1005 } 1006 return PR_TRUE; 1007 } 1008 1009 static CK_TRUST 1010 get_ck_trust( 1011 nssTrustLevel nssTrust, PRBool isPKCSTrust) 1012 { 1013 CK_TRUST t; 1014 switch (nssTrust) { 1015 case nssTrustLevel_NotTrusted: 1016 t = isPKCSTrust ? CKT_NOT_TRUSTED : CKT_NSS_NOT_TRUSTED; 1017 break; 1018 case nssTrustLevel_TrustedDelegator: 1019 t = isPKCSTrust ? CKT_TRUST_ANCHOR : CKT_NSS_TRUSTED_DELEGATOR; 1020 break; 1021 case nssTrustLevel_ValidDelegator: 1022 t = isPKCSTrust ? CKT_TRUST_MUST_VERIFY_TRUST : CKT_NSS_VALID_DELEGATOR; 1023 break; 1024 case nssTrustLevel_Trusted: 1025 t = isPKCSTrust ? CKT_TRUSTED : CKT_NSS_TRUSTED; 1026 break; 1027 case nssTrustLevel_MustVerify: 1028 t = isPKCSTrust ? CKT_TRUST_MUST_VERIFY_TRUST : CKT_NSS_MUST_VERIFY_TRUST; 1029 break; 1030 case nssTrustLevel_Unknown: 1031 default: 1032 t = isPKCSTrust ? CKT_TRUST_UNKNOWN : CKT_NSS_TRUST_UNKNOWN; 1033 break; 1034 } 1035 return t; 1036 } 1037 1038 NSS_IMPLEMENT nssCryptokiObject * 1039 nssToken_ImportTrust( 1040 NSSToken *tok, 1041 nssSession *sessionOpt, 1042 NSSDER *certEncoding, 1043 NSSDER *certIssuer, 1044 NSSDER *certSerial, 1045 nssTrustLevel serverAuth, 1046 nssTrustLevel clientAuth, 1047 nssTrustLevel codeSigning, 1048 nssTrustLevel emailProtection, 1049 PRBool stepUpApproved, 1050 PRBool asTokenObject) 1051 { 1052 nssCryptokiObject *object; 1053 CK_OBJECT_CLASS tobjc; 1054 CK_TRUST ckSA, ckCA, ckCS, ckEP; 1055 CK_ATTRIBUTE_PTR attr; 1056 CK_ATTRIBUTE trust_tmpl[11]; 1057 CK_ULONG tsize; 1058 PRBool usePKCS11TrustToken = nss_TokenUsePKCS11Trust(tok); 1059 PRUint8 hashBuf[HASH_LENGTH_MAX]; 1060 PRUint8 hashBuf2[HASH_LENGTH_MAX]; 1061 CK_MECHANISM_TYPE hashMech; 1062 1063 tobjc = usePKCS11TrustToken ? CKO_TRUST : CKO_NSS_TRUST; 1064 ckSA = get_ck_trust(serverAuth, usePKCS11TrustToken); 1065 ckCA = get_ck_trust(clientAuth, usePKCS11TrustToken); 1066 ckCS = get_ck_trust(codeSigning, usePKCS11TrustToken); 1067 ckEP = get_ck_trust(emailProtection, usePKCS11TrustToken); 1068 hashMech = usePKCS11TrustToken ? CKM_SHA256 : CKM_SHA_1; 1069 1070 NSSItem hash_result, hash2_result; 1071 hash_result.data = hashBuf; 1072 hash_result.size = sizeof(hashBuf); 1073 NSSAlgorithm_DigestBuf(hashMech, certEncoding, &hash_result); 1074 if (!usePKCS11TrustToken) { 1075 hash2_result.data = hashBuf2; 1076 hash2_result.size = sizeof(hashBuf2); 1077 NSSAlgorithm_DigestBuf(CKM_MD5, certEncoding, &hash2_result); 1078 } 1079 1080 NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize); 1081 if (asTokenObject) { 1082 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 1083 } else { 1084 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 1085 } 1086 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc); 1087 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer); 1088 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial); 1089 if (usePKCS11TrustToken) { 1090 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_HASH_OF_CERTIFICATE, &hash_result); 1091 NSS_CK_SET_ATTRIBUTE_FIXED_PTR(attr, CKA_NAME_HASH_ALGORITHM, &hashMech); 1092 /* now set the trust values */ 1093 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_SERVER_AUTH, ckSA); 1094 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_CLIENT_AUTH, ckCA); 1095 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_CODE_SIGNING, ckCS); 1096 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_EMAIL_PROTECTION, ckEP); 1097 } else { 1098 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_CERT_SHA1_HASH, &hash_result); 1099 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_CERT_MD5_HASH, &hash2_result); 1100 /* now set the trust values */ 1101 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_SERVER_AUTH, ckSA); 1102 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_CLIENT_AUTH, ckCA); 1103 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_CODE_SIGNING, ckCS); 1104 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_EMAIL_PROTECTION, ckEP); 1105 if (stepUpApproved) { 1106 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_TRUST_STEP_UP_APPROVED, 1107 &g_ck_true); 1108 } else { 1109 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_TRUST_STEP_UP_APPROVED, 1110 &g_ck_false); 1111 } 1112 } 1113 NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize); 1114 /* import the trust object onto the token */ 1115 object = import_object(tok, sessionOpt, trust_tmpl, tsize); 1116 if (object && tok->cache) { 1117 nssTokenObjectCache_ImportObject(tok->cache, object, tobjc, 1118 trust_tmpl, tsize); 1119 } 1120 return object; 1121 } 1122 1123 NSS_IMPLEMENT nssCryptokiObject * 1124 nssToken_FindTrustForCertificate( 1125 NSSToken *token, 1126 nssSession *sessionOpt, 1127 NSSDER *certEncoding, 1128 NSSDER *certIssuer, 1129 NSSDER *certSerial, 1130 nssTokenSearchType searchType) 1131 { 1132 CK_OBJECT_CLASS tobjc = CKO_TRUST; 1133 CK_ATTRIBUTE_PTR attr; 1134 CK_ATTRIBUTE tobj_template[5]; 1135 CK_ULONG tobj_size; 1136 nssSession *session = sessionOpt ? sessionOpt : token->defaultSession; 1137 nssCryptokiObject *object = NULL, **objects; 1138 1139 /* Don't ask the module to use an invalid session handle. */ 1140 if (!session || session->handle == CK_INVALID_HANDLE) { 1141 PORT_SetError(SEC_ERROR_NO_TOKEN); 1142 return object; 1143 } 1144 1145 NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size); 1146 if (searchType == nssTokenSearchType_TokenOnly) { 1147 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 1148 } 1149 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc); 1150 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer); 1151 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial); 1152 NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size); 1153 objects = nssToken_FindObjectsByTemplate(token, session, 1154 tobj_template, tobj_size, 1155 1, NULL); 1156 if (!objects) { 1157 tobjc = CKO_NSS_TRUST; 1158 objects = nssToken_FindObjectsByTemplate(token, session, 1159 tobj_template, tobj_size, 1160 1, NULL); 1161 } 1162 1163 if (objects) { 1164 object = objects[0]; 1165 object->trustType = tobjc; 1166 nss_ZFreeIf(objects); 1167 } 1168 return object; 1169 } 1170 1171 NSS_IMPLEMENT nssCryptokiObject * 1172 nssToken_ImportCRL( 1173 NSSToken *token, 1174 nssSession *sessionOpt, 1175 NSSDER *subject, 1176 NSSDER *encoding, 1177 PRBool isKRL, 1178 NSSUTF8 *url, 1179 PRBool asTokenObject) 1180 { 1181 nssCryptokiObject *object; 1182 CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL; 1183 CK_ATTRIBUTE_PTR attr; 1184 CK_ATTRIBUTE crl_tmpl[6]; 1185 CK_ULONG crlsize; 1186 1187 NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize); 1188 if (asTokenObject) { 1189 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 1190 } else { 1191 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 1192 } 1193 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc); 1194 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); 1195 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding); 1196 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url); 1197 if (isKRL) { 1198 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true); 1199 } else { 1200 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false); 1201 } 1202 NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize); 1203 1204 /* import the crl object onto the token */ 1205 object = import_object(token, sessionOpt, crl_tmpl, crlsize); 1206 if (object && token->cache) { 1207 nssTokenObjectCache_ImportObject(token->cache, object, crlobjc, 1208 crl_tmpl, crlsize); 1209 } 1210 return object; 1211 } 1212 1213 NSS_IMPLEMENT nssCryptokiObject ** 1214 nssToken_FindCRLsBySubject( 1215 NSSToken *token, 1216 nssSession *sessionOpt, 1217 NSSDER *subject, 1218 nssTokenSearchType searchType, 1219 PRUint32 maximumOpt, 1220 PRStatus *statusOpt) 1221 { 1222 CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL; 1223 CK_ATTRIBUTE_PTR attr; 1224 CK_ATTRIBUTE crlobj_template[3]; 1225 CK_ULONG crlobj_size; 1226 nssCryptokiObject **objects = NULL; 1227 nssSession *session = sessionOpt ? sessionOpt : token->defaultSession; 1228 1229 /* Don't ask the module to use an invalid session handle. */ 1230 if (!session || session->handle == CK_INVALID_HANDLE) { 1231 PORT_SetError(SEC_ERROR_NO_TOKEN); 1232 return objects; 1233 } 1234 1235 NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size); 1236 if (searchType == nssTokenSearchType_SessionOnly) { 1237 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 1238 } else if (searchType == nssTokenSearchType_TokenOnly || 1239 searchType == nssTokenSearchType_TokenForced) { 1240 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 1241 } 1242 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc); 1243 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); 1244 NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size); 1245 1246 objects = nssToken_FindObjectsByTemplate(token, session, 1247 crlobj_template, crlobj_size, 1248 maximumOpt, statusOpt); 1249 return objects; 1250 } 1251 1252 NSS_IMPLEMENT PRStatus 1253 nssToken_GetCachedObjectAttributes( 1254 NSSToken *token, 1255 NSSArena *arenaOpt, 1256 nssCryptokiObject *object, 1257 CK_OBJECT_CLASS objclass, 1258 CK_ATTRIBUTE_PTR atemplate, 1259 CK_ULONG atlen) 1260 { 1261 if (!token->cache) { 1262 return PR_FAILURE; 1263 } 1264 return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt, 1265 object, objclass, 1266 atemplate, atlen); 1267 } 1268 1269 NSS_IMPLEMENT NSSItem * 1270 nssToken_Digest( 1271 NSSToken *tok, 1272 nssSession *sessionOpt, 1273 NSSAlgorithmAndParameters *ap, 1274 NSSItem *data, 1275 NSSItem *rvOpt, 1276 NSSArena *arenaOpt) 1277 { 1278 CK_RV ckrv; 1279 CK_ULONG digestLen; 1280 CK_BYTE_PTR digest; 1281 NSSItem *rvItem = NULL; 1282 void *epv = nssToken_GetCryptokiEPV(tok); 1283 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; 1284 1285 /* Don't ask the module to use an invalid session handle. */ 1286 if (!session || session->handle == CK_INVALID_HANDLE) { 1287 PORT_SetError(SEC_ERROR_NO_TOKEN); 1288 return rvItem; 1289 } 1290 1291 nssSession_EnterMonitor(session); 1292 ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism); 1293 if (ckrv != CKR_OK) { 1294 nssSession_ExitMonitor(session); 1295 return NULL; 1296 } 1297 #if 0 1298 /* XXX the standard says this should work, but it doesn't */ 1299 ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen); 1300 if (ckrv != CKR_OK) { 1301 nssSession_ExitMonitor(session); 1302 return NULL; 1303 } 1304 #endif 1305 digestLen = 0; /* XXX for now */ 1306 digest = NULL; 1307 if (rvOpt) { 1308 if (rvOpt->size > 0 && rvOpt->size < digestLen) { 1309 nssSession_ExitMonitor(session); 1310 /* the error should be bad args */ 1311 return NULL; 1312 } 1313 if (rvOpt->data) { 1314 digest = rvOpt->data; 1315 } 1316 digestLen = rvOpt->size; 1317 } 1318 if (!digest) { 1319 digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen); 1320 if (!digest) { 1321 nssSession_ExitMonitor(session); 1322 return NULL; 1323 } 1324 } 1325 ckrv = CKAPI(epv)->C_Digest(session->handle, 1326 (CK_BYTE_PTR)data->data, 1327 (CK_ULONG)data->size, 1328 (CK_BYTE_PTR)digest, 1329 &digestLen); 1330 nssSession_ExitMonitor(session); 1331 if (ckrv != CKR_OK) { 1332 nss_ZFreeIf(digest); 1333 return NULL; 1334 } 1335 if (!rvOpt) { 1336 rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest); 1337 } else { 1338 rvOpt->size = digestLen; 1339 rvItem = rvOpt; 1340 } 1341 return rvItem; 1342 } 1343 1344 NSS_IMPLEMENT PRStatus 1345 nssToken_BeginDigest( 1346 NSSToken *tok, 1347 nssSession *sessionOpt, 1348 NSSAlgorithmAndParameters *ap) 1349 { 1350 CK_RV ckrv; 1351 void *epv = nssToken_GetCryptokiEPV(tok); 1352 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; 1353 1354 /* Don't ask the module to use an invalid session handle. */ 1355 if (!session || session->handle == CK_INVALID_HANDLE) { 1356 PORT_SetError(SEC_ERROR_NO_TOKEN); 1357 return PR_FAILURE; 1358 } 1359 1360 nssSession_EnterMonitor(session); 1361 ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism); 1362 nssSession_ExitMonitor(session); 1363 return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; 1364 } 1365 1366 NSS_IMPLEMENT PRStatus 1367 nssToken_ContinueDigest( 1368 NSSToken *tok, 1369 nssSession *sessionOpt, 1370 NSSItem *item) 1371 { 1372 CK_RV ckrv; 1373 void *epv = nssToken_GetCryptokiEPV(tok); 1374 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; 1375 1376 /* Don't ask the module to use an invalid session handle. */ 1377 if (!session || session->handle == CK_INVALID_HANDLE) { 1378 PORT_SetError(SEC_ERROR_NO_TOKEN); 1379 return PR_FAILURE; 1380 } 1381 1382 nssSession_EnterMonitor(session); 1383 ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, 1384 (CK_BYTE_PTR)item->data, 1385 (CK_ULONG)item->size); 1386 nssSession_ExitMonitor(session); 1387 return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; 1388 } 1389 1390 NSS_IMPLEMENT NSSItem * 1391 nssToken_FinishDigest( 1392 NSSToken *tok, 1393 nssSession *sessionOpt, 1394 NSSItem *rvOpt, 1395 NSSArena *arenaOpt) 1396 { 1397 CK_RV ckrv; 1398 CK_ULONG digestLen; 1399 CK_BYTE_PTR digest; 1400 NSSItem *rvItem = NULL; 1401 void *epv = nssToken_GetCryptokiEPV(tok); 1402 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; 1403 1404 /* Don't ask the module to use an invalid session handle. */ 1405 if (!session || session->handle == CK_INVALID_HANDLE) { 1406 PORT_SetError(SEC_ERROR_NO_TOKEN); 1407 return NULL; 1408 } 1409 1410 nssSession_EnterMonitor(session); 1411 ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen); 1412 if (ckrv != CKR_OK || digestLen == 0) { 1413 nssSession_ExitMonitor(session); 1414 return NULL; 1415 } 1416 digest = NULL; 1417 if (rvOpt) { 1418 if (rvOpt->size > 0 && rvOpt->size < digestLen) { 1419 nssSession_ExitMonitor(session); 1420 /* the error should be bad args */ 1421 return NULL; 1422 } 1423 if (rvOpt->data) { 1424 digest = rvOpt->data; 1425 } 1426 digestLen = rvOpt->size; 1427 } 1428 if (!digest) { 1429 digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen); 1430 if (!digest) { 1431 nssSession_ExitMonitor(session); 1432 return NULL; 1433 } 1434 } 1435 ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen); 1436 nssSession_ExitMonitor(session); 1437 if (ckrv != CKR_OK) { 1438 nss_ZFreeIf(digest); 1439 return NULL; 1440 } 1441 if (!rvOpt) { 1442 rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest); 1443 } 1444 return rvItem; 1445 } 1446 1447 NSS_IMPLEMENT PRBool 1448 nssToken_IsPresent( 1449 NSSToken *token) 1450 { 1451 return nssSlot_IsTokenPresent(token->slot); 1452 } 1453 1454 /* Sigh. The methods to find objects declared above cause problems with 1455 * the low-level object cache in the softoken -- the objects are found in 1456 * toto, then one wave of GetAttributes is done, then another. Having a 1457 * large number of objects causes the cache to be thrashed, as the objects 1458 * are gone before there's any chance to ask for their attributes. 1459 * So, for now, bringing back traversal methods for certs. This way all of 1460 * the cert's attributes can be grabbed immediately after finding it, 1461 * increasing the likelihood that the cache takes care of it. 1462 */ 1463 NSS_IMPLEMENT PRStatus 1464 nssToken_TraverseCertificates( 1465 NSSToken *token, 1466 nssSession *sessionOpt, 1467 nssTokenSearchType searchType, 1468 PRStatus (*callback)(nssCryptokiObject *instance, void *arg), 1469 void *arg) 1470 { 1471 CK_RV ckrv; 1472 CK_ULONG count; 1473 CK_OBJECT_HANDLE *objectHandles; 1474 CK_ATTRIBUTE_PTR attr; 1475 CK_ATTRIBUTE cert_template[2]; 1476 CK_ULONG ctsize; 1477 NSSArena *arena; 1478 PRUint32 arraySize, numHandles; 1479 nssCryptokiObject **objects; 1480 void *epv = nssToken_GetCryptokiEPV(token); 1481 nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession; 1482 1483 /* Don't ask the module to use an invalid session handle. */ 1484 if (!session || session->handle == CK_INVALID_HANDLE) { 1485 PORT_SetError(SEC_ERROR_NO_TOKEN); 1486 return PR_FAILURE; 1487 } 1488 1489 /* template for all certs */ 1490 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize); 1491 if (searchType == nssTokenSearchType_SessionOnly) { 1492 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); 1493 } else if (searchType == nssTokenSearchType_TokenOnly || 1494 searchType == nssTokenSearchType_TokenForced) { 1495 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); 1496 } 1497 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); 1498 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize); 1499 1500 /* the arena is only for the array of object handles */ 1501 arena = nssArena_Create(); 1502 if (!arena) { 1503 return PR_FAILURE; 1504 } 1505 arraySize = OBJECT_STACK_SIZE; 1506 numHandles = 0; 1507 objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize); 1508 if (!objectHandles) { 1509 goto loser; 1510 } 1511 nssSession_EnterMonitor(session); /* ==== session lock === */ 1512 /* Initialize the find with the template */ 1513 ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 1514 cert_template, ctsize); 1515 if (ckrv != CKR_OK) { 1516 nssSession_ExitMonitor(session); 1517 goto loser; 1518 } 1519 while (PR_TRUE) { 1520 /* Issue the find for up to arraySize - numHandles objects */ 1521 ckrv = CKAPI(epv)->C_FindObjects(session->handle, 1522 objectHandles + numHandles, 1523 arraySize - numHandles, 1524 &count); 1525 if (ckrv != CKR_OK) { 1526 nssSession_ExitMonitor(session); 1527 goto loser; 1528 } 1529 /* bump the number of found objects */ 1530 numHandles += count; 1531 if (numHandles < arraySize) { 1532 break; 1533 } 1534 /* the array is filled, double it and continue */ 1535 arraySize *= 2; 1536 objectHandles = nss_ZREALLOCARRAY(objectHandles, 1537 CK_OBJECT_HANDLE, 1538 arraySize); 1539 if (!objectHandles) { 1540 nssSession_ExitMonitor(session); 1541 goto loser; 1542 } 1543 } 1544 ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle); 1545 nssSession_ExitMonitor(session); /* ==== end session lock === */ 1546 if (ckrv != CKR_OK) { 1547 goto loser; 1548 } 1549 if (numHandles > 0) { 1550 objects = create_objects_from_handles(token, session, 1551 objectHandles, numHandles); 1552 if (objects) { 1553 nssCryptokiObject **op; 1554 for (op = objects; *op; op++) { 1555 (void)(*callback)(*op, arg); 1556 } 1557 nss_ZFreeIf(objects); 1558 } 1559 } 1560 nssArena_Destroy(arena); 1561 return PR_SUCCESS; 1562 loser: 1563 nssArena_Destroy(arena); 1564 return PR_FAILURE; 1565 } 1566 1567 NSS_IMPLEMENT PRBool 1568 nssToken_IsPrivateKeyAvailable( 1569 NSSToken *token, 1570 NSSCertificate *c, 1571 nssCryptokiObject *instance) 1572 { 1573 CK_OBJECT_CLASS theClass; 1574 1575 if (token == NULL) 1576 return PR_FALSE; 1577 if (c == NULL) 1578 return PR_FALSE; 1579 1580 theClass = CKO_PRIVATE_KEY; 1581 if (!nssSlot_IsLoggedIn(token->slot)) { 1582 theClass = CKO_PUBLIC_KEY; 1583 } 1584 if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) != 1585 CK_INVALID_HANDLE) { 1586 return PR_TRUE; 1587 } 1588 return PR_FALSE; 1589 }