devutil.c (30731B)
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 #ifndef DEVM_H 6 #include "devm.h" 7 #endif /* DEVM_H */ 8 9 #ifndef CKHELPER_H 10 #include "ckhelper.h" 11 #endif /* CKHELPER_H */ 12 13 #include "pk11pub.h" 14 #include "dev3hack.h" 15 #include "secerr.h" 16 17 NSS_IMPLEMENT nssCryptokiObject * 18 nssCryptokiObject_Create( 19 NSSToken *t, 20 nssSession *session, 21 CK_OBJECT_HANDLE h) 22 { 23 PRStatus status; 24 NSSSlot *slot; 25 nssCryptokiObject *object; 26 CK_BBOOL *isTokenObject; 27 CK_ATTRIBUTE cert_template[] = { 28 { CKA_TOKEN, NULL, 0 }, 29 { CKA_LABEL, NULL, 0 } 30 }; 31 slot = nssToken_GetSlot(t); 32 status = nssCKObject_GetAttributes(h, cert_template, 2, 33 NULL, session, slot); 34 nssSlot_Destroy(slot); 35 if (status != PR_SUCCESS) { 36 /* a failure here indicates a device error */ 37 return (nssCryptokiObject *)NULL; 38 } 39 if (cert_template[0].ulValueLen == 0 || !cert_template[0].pValue) { 40 nss_ZFreeIf(cert_template[1].pValue); 41 return (nssCryptokiObject *)NULL; 42 } 43 object = nss_ZNEW(NULL, nssCryptokiObject); 44 if (!object) { 45 nss_ZFreeIf(cert_template[0].pValue); 46 nss_ZFreeIf(cert_template[1].pValue); 47 return (nssCryptokiObject *)NULL; 48 } 49 object->handle = h; 50 object->token = nssToken_AddRef(t); 51 isTokenObject = (CK_BBOOL *)cert_template[0].pValue; 52 object->isTokenObject = *isTokenObject; 53 object->trustType = CKM_INVALID_MECHANISM; 54 nss_ZFreeIf(cert_template[0].pValue); 55 NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label); 56 return object; 57 } 58 59 NSS_IMPLEMENT void 60 nssCryptokiObject_Destroy( 61 nssCryptokiObject *object) 62 { 63 if (object) { 64 (void)nssToken_Destroy(object->token); 65 nss_ZFreeIf(object->label); 66 nss_ZFreeIf(object); 67 } 68 } 69 70 NSS_IMPLEMENT nssCryptokiObject * 71 nssCryptokiObject_Clone( 72 nssCryptokiObject *object) 73 { 74 nssCryptokiObject *rvObject; 75 rvObject = nss_ZNEW(NULL, nssCryptokiObject); 76 if (rvObject) { 77 rvObject->handle = object->handle; 78 rvObject->token = nssToken_AddRef(object->token); 79 rvObject->isTokenObject = object->isTokenObject; 80 if (object->label) { 81 rvObject->label = nssUTF8_Duplicate(object->label, NULL); 82 } 83 } 84 return rvObject; 85 } 86 87 NSS_EXTERN PRBool 88 nssCryptokiObject_Equal( 89 nssCryptokiObject *o1, 90 nssCryptokiObject *o2) 91 { 92 return (o1->token == o2->token && o1->handle == o2->handle); 93 } 94 95 NSS_IMPLEMENT PRUint32 96 nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen) 97 { 98 PRInt32 i; 99 for (i = bufLen - 1; i >= 0;) { 100 if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') 101 break; 102 --i; 103 } 104 return (PRUint32)(i + 1); 105 } 106 107 /* 108 * Slot arrays 109 */ 110 111 NSS_IMPLEMENT NSSSlot ** 112 nssSlotArray_Clone( 113 NSSSlot **slots) 114 { 115 NSSSlot **rvSlots = NULL; 116 NSSSlot **sp = slots; 117 PRUint32 count = 0; 118 while (sp && *sp) 119 count++; 120 if (count > 0) { 121 rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1); 122 if (rvSlots) { 123 for (sp = slots, count = 0; *sp; sp++) { 124 rvSlots[count++] = nssSlot_AddRef(*sp); 125 } 126 } 127 } 128 return rvSlots; 129 } 130 131 NSS_IMPLEMENT void 132 nssSlotArray_Destroy( 133 NSSSlot **slots) 134 { 135 if (slots) { 136 NSSSlot **slotp; 137 for (slotp = slots; *slotp; slotp++) { 138 nssSlot_Destroy(*slotp); 139 } 140 nss_ZFreeIf(slots); 141 } 142 } 143 144 NSS_IMPLEMENT void 145 NSSSlotArray_Destroy( 146 NSSSlot **slots) 147 { 148 nssSlotArray_Destroy(slots); 149 } 150 151 NSS_IMPLEMENT void 152 nssTokenArray_Destroy( 153 NSSToken **tokens) 154 { 155 if (tokens) { 156 NSSToken **tokenp; 157 for (tokenp = tokens; *tokenp; tokenp++) { 158 (void)nssToken_Destroy(*tokenp); 159 } 160 nss_ZFreeIf(tokens); 161 } 162 } 163 164 NSS_IMPLEMENT void 165 nssCryptokiObjectArray_Destroy( 166 nssCryptokiObject **objects) 167 { 168 if (objects) { 169 nssCryptokiObject **op; 170 for (op = objects; *op; op++) { 171 nssCryptokiObject_Destroy(*op); 172 } 173 nss_ZFreeIf(objects); 174 } 175 } 176 177 /* object cache for token */ 178 179 typedef struct 180 { 181 NSSArena *arena; 182 nssCryptokiObject *object; 183 CK_ATTRIBUTE_PTR attributes; 184 CK_ULONG numAttributes; 185 } nssCryptokiObjectAndAttributes; 186 187 enum { 188 cachedCerts = 0, 189 cachedTrust = 1, 190 cachedCRLs = 2 191 } cachedObjectType; 192 193 struct nssTokenObjectCacheStr { 194 NSSToken *token; 195 PZLock *lock; 196 PRBool loggedIn; 197 PRBool doObjectType[3]; 198 PRBool searchedObjectType[3]; 199 nssCryptokiObjectAndAttributes **objects[3]; 200 }; 201 202 NSS_IMPLEMENT nssTokenObjectCache * 203 nssTokenObjectCache_Create( 204 NSSToken *token, 205 PRBool cacheCerts, 206 PRBool cacheTrust, 207 PRBool cacheCRLs) 208 { 209 nssTokenObjectCache *rvCache; 210 rvCache = nss_ZNEW(NULL, nssTokenObjectCache); 211 if (!rvCache) { 212 goto loser; 213 } 214 rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */ 215 if (!rvCache->lock) { 216 goto loser; 217 } 218 rvCache->doObjectType[cachedCerts] = cacheCerts; 219 rvCache->doObjectType[cachedTrust] = cacheTrust; 220 rvCache->doObjectType[cachedCRLs] = cacheCRLs; 221 rvCache->token = token; /* cache goes away with token */ 222 return rvCache; 223 loser: 224 nssTokenObjectCache_Destroy(rvCache); 225 return (nssTokenObjectCache *)NULL; 226 } 227 228 static void 229 clear_cache( 230 nssTokenObjectCache *cache) 231 { 232 nssCryptokiObjectAndAttributes **oa; 233 PRUint32 objectType; 234 for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) { 235 cache->searchedObjectType[objectType] = PR_FALSE; 236 if (!cache->objects[objectType]) { 237 continue; 238 } 239 for (oa = cache->objects[objectType]; *oa; oa++) { 240 /* prevent the token from being destroyed */ 241 (*oa)->object->token = NULL; 242 nssCryptokiObject_Destroy((*oa)->object); 243 nssArena_Destroy((*oa)->arena); 244 } 245 nss_ZFreeIf(cache->objects[objectType]); 246 cache->objects[objectType] = NULL; 247 } 248 } 249 250 NSS_IMPLEMENT void 251 nssTokenObjectCache_Clear( 252 nssTokenObjectCache *cache) 253 { 254 if (cache) { 255 PZ_Lock(cache->lock); 256 clear_cache(cache); 257 PZ_Unlock(cache->lock); 258 } 259 } 260 261 NSS_IMPLEMENT void 262 nssTokenObjectCache_Destroy( 263 nssTokenObjectCache *cache) 264 { 265 if (cache) { 266 clear_cache(cache); 267 if (cache->lock) { 268 PZ_DestroyLock(cache->lock); 269 } 270 nss_ZFreeIf(cache); 271 } 272 } 273 274 NSS_IMPLEMENT PRBool 275 nssTokenObjectCache_HaveObjectClass( 276 nssTokenObjectCache *cache, 277 CK_OBJECT_CLASS objclass) 278 { 279 PRBool haveIt; 280 PZ_Lock(cache->lock); 281 switch (objclass) { 282 case CKO_CERTIFICATE: 283 haveIt = cache->doObjectType[cachedCerts]; 284 break; 285 case CKO_NSS_TRUST: 286 case CKO_TRUST: 287 haveIt = cache->doObjectType[cachedTrust]; 288 break; 289 case CKO_NSS_CRL: 290 haveIt = cache->doObjectType[cachedCRLs]; 291 break; 292 default: 293 haveIt = PR_FALSE; 294 } 295 PZ_Unlock(cache->lock); 296 return haveIt; 297 } 298 299 static nssCryptokiObjectAndAttributes ** 300 create_object_array( 301 nssCryptokiObject **objects, 302 PRBool *doObjects, 303 PRUint32 *numObjects, 304 PRStatus *status) 305 { 306 nssCryptokiObjectAndAttributes **rvOandA = NULL; 307 *numObjects = 0; 308 /* There are no objects for this type */ 309 if (!objects || !*objects) { 310 *status = PR_SUCCESS; 311 return rvOandA; 312 } 313 while (*objects++) 314 (*numObjects)++; 315 if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) { 316 /* Hit the maximum allowed, so don't use a cache (there are 317 * too many objects to make caching worthwhile, presumably, if 318 * the token can handle that many objects, it can handle searching. 319 */ 320 *doObjects = PR_FALSE; 321 *status = PR_FAILURE; 322 *numObjects = 0; 323 } else { 324 rvOandA = nss_ZNEWARRAY(NULL, 325 nssCryptokiObjectAndAttributes *, 326 *numObjects + 1); 327 *status = rvOandA ? PR_SUCCESS : PR_FAILURE; 328 } 329 return rvOandA; 330 } 331 332 static nssCryptokiObjectAndAttributes * 333 create_object( 334 nssCryptokiObject *object, 335 const CK_ATTRIBUTE_TYPE *types, 336 PRUint32 numTypes, 337 PRStatus *status) 338 { 339 PRUint32 j; 340 NSSArena *arena = NULL; 341 NSSSlot *slot = NULL; 342 nssSession *session = NULL; 343 nssCryptokiObjectAndAttributes *rvCachedObject = NULL; 344 345 slot = nssToken_GetSlot(object->token); 346 if (!slot) { 347 nss_SetError(NSS_ERROR_INVALID_POINTER); 348 goto loser; 349 } 350 session = nssToken_GetDefaultSession(object->token); 351 if (!session) { 352 nss_SetError(NSS_ERROR_INVALID_POINTER); 353 goto loser; 354 } 355 arena = nssArena_Create(); 356 if (!arena) { 357 goto loser; 358 } 359 rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes); 360 if (!rvCachedObject) { 361 goto loser; 362 } 363 rvCachedObject->arena = arena; 364 /* The cache is tied to the token, and therefore the objects 365 * in it should not hold references to the token. 366 */ 367 (void)nssToken_Destroy(object->token); 368 rvCachedObject->object = object; 369 rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes); 370 if (!rvCachedObject->attributes) { 371 goto loser; 372 } 373 for (j = 0; j < numTypes; j++) { 374 rvCachedObject->attributes[j].type = types[j]; 375 } 376 *status = nssCKObject_GetAttributes(object->handle, 377 rvCachedObject->attributes, 378 numTypes, 379 arena, 380 session, 381 slot); 382 if (*status != PR_SUCCESS) { 383 goto loser; 384 } 385 rvCachedObject->numAttributes = numTypes; 386 *status = PR_SUCCESS; 387 nssSlot_Destroy(slot); 388 389 return rvCachedObject; 390 loser: 391 *status = PR_FAILURE; 392 if (slot) { 393 nssSlot_Destroy(slot); 394 } 395 if (arena) 396 nssArena_Destroy(arena); 397 return (nssCryptokiObjectAndAttributes *)NULL; 398 } 399 400 /* 401 * 402 * State diagram for cache: 403 * 404 * token !present token removed 405 * +-------------------------+<----------------------+ 406 * | ^ | 407 * v | | 408 * +----------+ slot friendly | token present +----------+ 409 * | cache | -----------------> % ---------------> | cache | 410 * | unloaded | | loaded | 411 * +----------+ +----------+ 412 * ^ | ^ | 413 * | | slot !friendly slot logged in | | 414 * | +-----------------------> % ----------------------+ | 415 * | | | 416 * | slot logged out v slot !friendly | 417 * +-----------------------------+<--------------------------+ 418 * 419 */ 420 421 /* This function must not be called with cache->lock locked. */ 422 static PRBool 423 token_is_present( 424 nssTokenObjectCache *cache) 425 { 426 NSSSlot *slot = nssToken_GetSlot(cache->token); 427 PRBool tokenPresent = nssSlot_IsTokenPresent(slot); 428 nssSlot_Destroy(slot); 429 return tokenPresent; 430 } 431 432 static PRBool 433 search_for_objects( 434 nssTokenObjectCache *cache) 435 { 436 PRBool doSearch = PR_FALSE; 437 NSSSlot *slot = nssToken_GetSlot(cache->token); 438 /* Handle non-friendly slots (slots which require login for objects) */ 439 if (!nssSlot_IsFriendly(slot)) { 440 if (nssSlot_IsLoggedIn(slot)) { 441 /* Either no state change, or went from !logged in -> logged in */ 442 cache->loggedIn = PR_TRUE; 443 doSearch = PR_TRUE; 444 } else { 445 if (cache->loggedIn) { 446 /* went from logged in -> !logged in, destroy cached objects */ 447 clear_cache(cache); 448 cache->loggedIn = PR_FALSE; 449 } /* else no state change, still not logged in, so exit */ 450 } 451 } else { 452 /* slot is friendly, thus always available for search */ 453 doSearch = PR_TRUE; 454 } 455 nssSlot_Destroy(slot); 456 return doSearch; 457 } 458 459 static nssCryptokiObjectAndAttributes * 460 create_cert( 461 nssCryptokiObject *object, 462 PRStatus *status) 463 { 464 static const CK_ATTRIBUTE_TYPE certAttr[] = { 465 CKA_CLASS, 466 CKA_TOKEN, 467 CKA_LABEL, 468 CKA_CERTIFICATE_TYPE, 469 CKA_ID, 470 CKA_VALUE, 471 CKA_ISSUER, 472 CKA_SERIAL_NUMBER, 473 CKA_SUBJECT, 474 CKA_NSS_EMAIL 475 }; 476 static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]); 477 return create_object(object, certAttr, numCertAttr, status); 478 } 479 480 static nssCryptokiObjectAndAttributes * 481 create_trust( 482 nssCryptokiObject *object, 483 PRStatus *status) 484 { 485 static const CK_ATTRIBUTE_TYPE nssTrustAttr[] = { 486 CKA_CLASS, 487 CKA_TOKEN, 488 CKA_LABEL, 489 CKA_NSS_CERT_SHA1_HASH, 490 CKA_NSS_CERT_MD5_HASH, 491 CKA_ISSUER, 492 CKA_SUBJECT, 493 CKA_NSS_TRUST_SERVER_AUTH, 494 CKA_NSS_TRUST_CLIENT_AUTH, 495 CKA_NSS_TRUST_EMAIL_PROTECTION, 496 CKA_NSS_TRUST_CODE_SIGNING 497 }; 498 static const CK_ATTRIBUTE_TYPE pkcsTrustAttr[] = { 499 CKA_CLASS, 500 CKA_TOKEN, 501 CKA_LABEL, 502 CKA_HASH_OF_CERTIFICATE, 503 CKA_NAME_HASH_ALGORITHM, 504 CKA_ISSUER, 505 CKA_SUBJECT, 506 CKA_PKCS_TRUST_SERVER_AUTH, 507 CKA_PKCS_TRUST_CLIENT_AUTH, 508 CKA_PKCS_TRUST_EMAIL_PROTECTION, 509 CKA_PKCS_TRUST_CODE_SIGNING 510 }; 511 static const PRUint32 numNSSTrustAttr = PR_ARRAY_SIZE(nssTrustAttr); 512 static const PRUint32 numPKCSTrustAttr = PR_ARRAY_SIZE(pkcsTrustAttr); 513 const CK_ATTRIBUTE_TYPE *trustAttr; 514 PRUint32 numTrustAttr; 515 516 trustAttr = (object->trustType == CKO_TRUST) ? pkcsTrustAttr 517 : nssTrustAttr; 518 numTrustAttr = (object->trustType == CKO_TRUST) ? numPKCSTrustAttr 519 : numNSSTrustAttr; 520 return create_object(object, trustAttr, numTrustAttr, status); 521 } 522 523 static nssCryptokiObjectAndAttributes * 524 create_crl( 525 nssCryptokiObject *object, 526 PRStatus *status) 527 { 528 static const CK_ATTRIBUTE_TYPE crlAttr[] = { 529 CKA_CLASS, 530 CKA_TOKEN, 531 CKA_LABEL, 532 CKA_VALUE, 533 CKA_SUBJECT, 534 CKA_NSS_KRL, 535 CKA_NSS_URL 536 }; 537 static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]); 538 return create_object(object, crlAttr, numCRLAttr, status); 539 } 540 541 /* Dispatch to the create function for the object type */ 542 static nssCryptokiObjectAndAttributes * 543 create_object_of_type( 544 nssCryptokiObject *object, 545 PRUint32 objectType, 546 PRStatus *status) 547 { 548 if (objectType == cachedCerts) { 549 return create_cert(object, status); 550 } 551 if (objectType == cachedTrust) { 552 return create_trust(object, status); 553 } 554 if (objectType == cachedCRLs) { 555 return create_crl(object, status); 556 } 557 return (nssCryptokiObjectAndAttributes *)NULL; 558 } 559 560 static PRStatus 561 get_token_objects_for_cache( 562 nssTokenObjectCache *cache, 563 PRUint32 objectType, 564 CK_OBJECT_CLASS objclass) 565 { 566 PRStatus status; 567 nssCryptokiObject **objects; 568 PRBool *doIt = &cache->doObjectType[objectType]; 569 PRUint32 i, numObjects; 570 571 if (!search_for_objects(cache) || 572 cache->searchedObjectType[objectType] || 573 !cache->doObjectType[objectType]) { 574 /* Either there was a state change that prevents a search 575 * (token logged out), or the search was already done, 576 * or objects of this type are not being cached. 577 */ 578 return PR_SUCCESS; 579 } 580 objects = nssToken_FindObjects(cache->token, NULL, objclass, 581 nssTokenSearchType_TokenForced, 582 MAX_LOCAL_CACHE_OBJECTS, &status); 583 if (status != PR_SUCCESS) { 584 return status; 585 } 586 cache->objects[objectType] = create_object_array(objects, 587 doIt, 588 &numObjects, 589 &status); 590 if (status != PR_SUCCESS) { 591 nssCryptokiObjectArray_Destroy(objects); 592 return status; 593 } 594 for (i = 0; i < numObjects; i++) { 595 cache->objects[objectType][i] = create_object_of_type(objects[i], 596 objectType, 597 &status); 598 if (status != PR_SUCCESS) { 599 break; 600 } 601 } 602 if (status == PR_SUCCESS) { 603 nss_ZFreeIf(objects); 604 } else { 605 PRUint32 j; 606 for (j = 0; j < i; j++) { 607 /* Objects that were successfully added to the cache do not own a 608 * token reference (they share a reference with the cache itself). 609 * Nulling out the pointer here prevents the token's refcount 610 * from being decremented in nssCryptokiObject_Destroy */ 611 cache->objects[objectType][j]->object->token = NULL; 612 nssArena_Destroy(cache->objects[objectType][j]->arena); 613 } 614 nss_ZFreeIf(cache->objects[objectType]); 615 cache->objects[objectType] = NULL; 616 nssCryptokiObjectArray_Destroy(objects); 617 } 618 cache->searchedObjectType[objectType] = PR_TRUE; 619 return status; 620 } 621 622 static CK_ATTRIBUTE_PTR 623 find_attribute_in_object( 624 nssCryptokiObjectAndAttributes *obj, 625 CK_ATTRIBUTE_TYPE attrType) 626 { 627 PRUint32 j; 628 for (j = 0; j < obj->numAttributes; j++) { 629 if (attrType == obj->attributes[j].type) { 630 return &obj->attributes[j]; 631 } 632 } 633 return (CK_ATTRIBUTE_PTR)NULL; 634 } 635 636 /* Find all objects in the array that match the supplied template */ 637 static nssCryptokiObject ** 638 find_objects_in_array( 639 nssCryptokiObjectAndAttributes **objArray, 640 CK_ATTRIBUTE_PTR ot, 641 CK_ULONG otlen, 642 PRUint32 maximumOpt) 643 { 644 PRIntn oi = 0; 645 PRUint32 i; 646 NSSArena *arena; 647 PRUint32 size = 8; 648 PRUint32 numMatches = 0; 649 nssCryptokiObject **objects = NULL; 650 nssCryptokiObjectAndAttributes **matches = NULL; 651 CK_ATTRIBUTE_PTR attr; 652 653 if (!objArray) { 654 return (nssCryptokiObject **)NULL; 655 } 656 arena = nssArena_Create(); 657 if (!arena) { 658 return (nssCryptokiObject **)NULL; 659 } 660 matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size); 661 if (!matches) { 662 goto loser; 663 } 664 if (maximumOpt == 0) 665 maximumOpt = ~0; 666 /* loop over the cached objects */ 667 for (; *objArray && numMatches < maximumOpt; objArray++) { 668 nssCryptokiObjectAndAttributes *obj = *objArray; 669 /* loop over the test template */ 670 for (i = 0; i < otlen; i++) { 671 /* see if the object has the attribute */ 672 attr = find_attribute_in_object(obj, ot[i].type); 673 if (!attr) { 674 /* nope, match failed */ 675 break; 676 } 677 /* compare the attribute against the test value */ 678 if (ot[i].ulValueLen != attr->ulValueLen || 679 !nsslibc_memequal(ot[i].pValue, 680 attr->pValue, 681 attr->ulValueLen, NULL)) { 682 /* nope, match failed */ 683 break; 684 } 685 } 686 if (i == otlen) { 687 /* all of the attributes in the test template were found 688 * in the object's template, and they all matched 689 */ 690 matches[numMatches++] = obj; 691 if (numMatches == size) { 692 size *= 2; 693 matches = nss_ZREALLOCARRAY(matches, 694 nssCryptokiObjectAndAttributes *, 695 size); 696 if (!matches) { 697 goto loser; 698 } 699 } 700 } 701 } 702 if (numMatches > 0) { 703 objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1); 704 if (!objects) { 705 goto loser; 706 } 707 for (oi = 0; oi < (PRIntn)numMatches; oi++) { 708 objects[oi] = nssCryptokiObject_Clone(matches[oi]->object); 709 if (!objects[oi]) { 710 goto loser; 711 } 712 } 713 } 714 nssArena_Destroy(arena); 715 return objects; 716 loser: 717 nssCryptokiObjectArray_Destroy(objects); 718 nssArena_Destroy(arena); 719 return (nssCryptokiObject **)NULL; 720 } 721 722 NSS_IMPLEMENT nssCryptokiObject ** 723 nssTokenObjectCache_FindObjectsByTemplate( 724 nssTokenObjectCache *cache, 725 CK_OBJECT_CLASS objclass, 726 CK_ATTRIBUTE_PTR otemplate, 727 CK_ULONG otlen, 728 PRUint32 maximumOpt, 729 PRStatus *statusOpt) 730 { 731 PRStatus status = PR_FAILURE; 732 nssCryptokiObject **rvObjects = NULL; 733 PRUint32 objectType; 734 if (!token_is_present(cache)) { 735 status = PR_SUCCESS; 736 goto finish; 737 } 738 switch (objclass) { 739 case CKO_CERTIFICATE: 740 objectType = cachedCerts; 741 break; 742 case CKO_NSS_TRUST: 743 case CKO_TRUST: 744 objectType = cachedTrust; 745 break; 746 case CKO_NSS_CRL: 747 objectType = cachedCRLs; 748 break; 749 default: 750 goto finish; 751 } 752 PZ_Lock(cache->lock); 753 if (cache->doObjectType[objectType]) { 754 status = get_token_objects_for_cache(cache, objectType, objclass); 755 if (status == PR_SUCCESS) { 756 rvObjects = find_objects_in_array(cache->objects[objectType], 757 otemplate, otlen, maximumOpt); 758 } 759 } 760 PZ_Unlock(cache->lock); 761 finish: 762 if (statusOpt) { 763 *statusOpt = status; 764 } 765 return rvObjects; 766 } 767 768 static PRBool 769 cache_available_for_object_type( 770 nssTokenObjectCache *cache, 771 PRUint32 objectType) 772 { 773 if (!cache->doObjectType[objectType]) { 774 /* not caching this object kind */ 775 return PR_FALSE; 776 } 777 if (!cache->searchedObjectType[objectType]) { 778 /* objects are not cached yet */ 779 return PR_FALSE; 780 } 781 if (!search_for_objects(cache)) { 782 /* not logged in */ 783 return PR_FALSE; 784 } 785 return PR_TRUE; 786 } 787 788 NSS_IMPLEMENT PRStatus 789 nssTokenObjectCache_GetObjectAttributes( 790 nssTokenObjectCache *cache, 791 NSSArena *arenaOpt, 792 nssCryptokiObject *object, 793 CK_OBJECT_CLASS objclass, 794 CK_ATTRIBUTE_PTR atemplate, 795 CK_ULONG atlen) 796 { 797 PRUint32 i, j; 798 NSSArena *arena = NULL; 799 nssArenaMark *mark = NULL; 800 nssCryptokiObjectAndAttributes *cachedOA = NULL; 801 nssCryptokiObjectAndAttributes **oa = NULL; 802 PRUint32 objectType; 803 if (!token_is_present(cache)) { 804 return PR_FAILURE; 805 } 806 PZ_Lock(cache->lock); 807 switch (objclass) { 808 case CKO_CERTIFICATE: 809 objectType = cachedCerts; 810 break; 811 case CKO_NSS_TRUST: 812 case CKO_TRUST: 813 objectType = cachedTrust; 814 break; 815 case CKO_NSS_CRL: 816 objectType = cachedCRLs; 817 break; 818 default: 819 goto loser; 820 } 821 if (!cache_available_for_object_type(cache, objectType)) { 822 goto loser; 823 } 824 oa = cache->objects[objectType]; 825 if (!oa) { 826 goto loser; 827 } 828 for (; *oa; oa++) { 829 if (nssCryptokiObject_Equal((*oa)->object, object)) { 830 cachedOA = *oa; 831 break; 832 } 833 } 834 if (!cachedOA) { 835 goto loser; /* don't have this object */ 836 } 837 if (arenaOpt) { 838 arena = arenaOpt; 839 mark = nssArena_Mark(arena); 840 } 841 for (i = 0; i < atlen; i++) { 842 for (j = 0; j < cachedOA->numAttributes; j++) { 843 if (atemplate[i].type == cachedOA->attributes[j].type) { 844 CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j]; 845 if (cachedOA->attributes[j].ulValueLen == 0 || 846 cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) { 847 break; /* invalid attribute */ 848 } 849 if (atemplate[i].ulValueLen > 0) { 850 if (atemplate[i].pValue == NULL || 851 atemplate[i].ulValueLen < attr->ulValueLen) { 852 goto loser; 853 } 854 } else { 855 atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen); 856 if (!atemplate[i].pValue) { 857 goto loser; 858 } 859 } 860 nsslibc_memcpy(atemplate[i].pValue, 861 attr->pValue, attr->ulValueLen); 862 atemplate[i].ulValueLen = attr->ulValueLen; 863 break; 864 } 865 } 866 if (j == cachedOA->numAttributes) { 867 atemplate[i].ulValueLen = (CK_ULONG)-1; 868 } 869 } 870 PZ_Unlock(cache->lock); 871 if (mark) { 872 nssArena_Unmark(arena, mark); 873 } 874 return PR_SUCCESS; 875 loser: 876 PZ_Unlock(cache->lock); 877 if (mark) { 878 nssArena_Release(arena, mark); 879 } 880 return PR_FAILURE; 881 } 882 883 NSS_IMPLEMENT PRStatus 884 nssTokenObjectCache_ImportObject( 885 nssTokenObjectCache *cache, 886 nssCryptokiObject *object, 887 CK_OBJECT_CLASS objclass, 888 CK_ATTRIBUTE_PTR ot, 889 CK_ULONG otlen) 890 { 891 PRStatus status = PR_SUCCESS; 892 PRUint32 count; 893 nssCryptokiObjectAndAttributes **oa, ***otype; 894 PRUint32 objectType; 895 PRBool haveIt = PR_FALSE; 896 897 if (!token_is_present(cache)) { 898 return PR_SUCCESS; /* cache not active, ignored */ 899 } 900 PZ_Lock(cache->lock); 901 switch (objclass) { 902 case CKO_CERTIFICATE: 903 objectType = cachedCerts; 904 break; 905 case CKO_NSS_TRUST: 906 case CKO_TRUST: 907 objectType = cachedTrust; 908 object->trustType = objclass; 909 break; 910 case CKO_NSS_CRL: 911 objectType = cachedCRLs; 912 break; 913 default: 914 PZ_Unlock(cache->lock); 915 return PR_SUCCESS; /* don't need to import it here */ 916 } 917 if (!cache_available_for_object_type(cache, objectType)) { 918 PZ_Unlock(cache->lock); 919 return PR_SUCCESS; /* cache not active, ignored */ 920 } 921 count = 0; 922 otype = &cache->objects[objectType]; /* index into array of types */ 923 oa = *otype; /* the array of objects for this type */ 924 while (oa && *oa) { 925 if (nssCryptokiObject_Equal((*oa)->object, object)) { 926 haveIt = PR_TRUE; 927 break; 928 } 929 count++; 930 oa++; 931 } 932 if (haveIt) { 933 /* Destroy the old entry */ 934 (*oa)->object->token = NULL; 935 nssCryptokiObject_Destroy((*oa)->object); 936 nssArena_Destroy((*oa)->arena); 937 } else { 938 /* Create space for a new entry */ 939 if (count > 0) { 940 *otype = nss_ZREALLOCARRAY(*otype, 941 nssCryptokiObjectAndAttributes *, 942 count + 2); 943 } else { 944 *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2); 945 } 946 } 947 if (*otype) { 948 nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object); 949 (*otype)[count] = create_object_of_type(copyObject, objectType, 950 &status); 951 } else { 952 status = PR_FAILURE; 953 } 954 PZ_Unlock(cache->lock); 955 return status; 956 } 957 958 NSS_IMPLEMENT void 959 nssTokenObjectCache_RemoveObject( 960 nssTokenObjectCache *cache, 961 nssCryptokiObject *object) 962 { 963 PRUint32 oType; 964 nssCryptokiObjectAndAttributes **oa, **swp = NULL; 965 if (!token_is_present(cache)) { 966 return; 967 } 968 PZ_Lock(cache->lock); 969 for (oType = 0; oType < 3; oType++) { 970 if (!cache_available_for_object_type(cache, oType) || 971 !cache->objects[oType]) { 972 continue; 973 } 974 for (oa = cache->objects[oType]; *oa; oa++) { 975 if (nssCryptokiObject_Equal((*oa)->object, object)) { 976 swp = oa; /* the entry to remove */ 977 while (oa[1]) 978 oa++; /* go to the tail */ 979 (*swp)->object->token = NULL; 980 nssCryptokiObject_Destroy((*swp)->object); 981 nssArena_Destroy((*swp)->arena); /* destroy it */ 982 *swp = *oa; /* swap the last with the removed */ 983 *oa = NULL; /* null-terminate the array */ 984 break; 985 } 986 } 987 if (swp) { 988 break; 989 } 990 } 991 if ((oType < 3) && 992 cache->objects[oType] && cache->objects[oType][0] == NULL) { 993 nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */ 994 cache->objects[oType] = NULL; 995 } 996 PZ_Unlock(cache->lock); 997 } 998 999 /* We need a general hash to support CKO_TRUST 1000 ** Replace the algorithm specific version used for 1001 ** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes. 1002 ** CKA_HASH_OF_CERTIFICATE uses the mechanism specified 1003 ** in CKA_NAME_HASH_ALGORITHM, with can be passed to this 1004 ** function. 1005 */ 1006 /* XXX of course this doesn't belong here */ 1007 NSS_IMPLEMENT NSSAlgorithmAndParameters * 1008 NSSAlgorithmAndParameters_CreateDigest( 1009 NSSArena *arenaOpt, CK_MECHANISM_TYPE hashMech) 1010 { 1011 NSSAlgorithmAndParameters *rvAP = NULL; 1012 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); 1013 if (rvAP) { 1014 rvAP->mechanism.mechanism = hashMech; 1015 rvAP->mechanism.pParameter = NULL; 1016 rvAP->mechanism.ulParameterLen = 0; 1017 } 1018 return rvAP; 1019 } 1020 1021 /* 1022 * we need a DigestBuf for both create and verify trust objects. 1023 * So put it here for now. We don't have any Stan based crypto operations 1024 * yet. 1025 */ 1026 NSS_IMPLEMENT PRStatus 1027 NSSAlgorithm_DigestBuf(CK_MECHANISM_TYPE type, NSSItem *input, NSSItem *output) 1028 { 1029 PRStatus ret = PR_FAILURE; 1030 NSSAlgorithmAndParameters *ap = NULL; 1031 PK11SlotInfo *internal = NULL; 1032 NSSToken *token = NULL; 1033 NSSItem *dummy = NULL; 1034 1035 internal = PK11_GetInternalSlot(); 1036 if (!internal) { 1037 goto done; 1038 } 1039 token = PK11Slot_GetNSSToken(internal); 1040 if (!token) { 1041 goto done; 1042 } 1043 ap = NSSAlgorithmAndParameters_CreateDigest(NULL, type); 1044 if (!token) { 1045 goto done; 1046 } 1047 1048 dummy = nssToken_Digest(token, NULL, ap, input, output, NULL); 1049 if (dummy) { 1050 ret = PR_SUCCESS; 1051 } 1052 1053 done: 1054 nss_ZFreeIf(ap); 1055 if (token) { 1056 (void)nssToken_Destroy(token); 1057 } 1058 if (internal) { 1059 PK11_FreeSlot(internal); 1060 } 1061 return ret; 1062 }