pkibase.c (35962B)
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 DEV_H 6 #include "dev.h" 7 #endif /* DEV_H */ 8 9 #ifndef PKIM_H 10 #include "pkim.h" 11 #endif /* PKIM_H */ 12 13 #include "pki3hack.h" 14 15 extern const NSSError NSS_ERROR_NOT_FOUND; 16 17 NSS_IMPLEMENT void 18 nssPKIObject_Lock(nssPKIObject *object) 19 { 20 switch (object->lockType) { 21 case nssPKIMonitor: 22 PZ_EnterMonitor(object->sync.mlock); 23 break; 24 case nssPKILock: 25 PZ_Lock(object->sync.lock); 26 break; 27 default: 28 PORT_Assert(0); 29 } 30 } 31 32 NSS_IMPLEMENT void 33 nssPKIObject_Unlock(nssPKIObject *object) 34 { 35 switch (object->lockType) { 36 case nssPKIMonitor: 37 PZ_ExitMonitor(object->sync.mlock); 38 break; 39 case nssPKILock: 40 PZ_Unlock(object->sync.lock); 41 break; 42 default: 43 PORT_Assert(0); 44 } 45 } 46 47 NSS_IMPLEMENT PRStatus 48 nssPKIObject_NewLock(nssPKIObject *object, nssPKILockType lockType) 49 { 50 object->lockType = lockType; 51 switch (lockType) { 52 case nssPKIMonitor: 53 object->sync.mlock = PZ_NewMonitor(nssILockSSL); 54 return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE); 55 case nssPKILock: 56 object->sync.lock = PZ_NewLock(nssILockSSL); 57 return (object->sync.lock ? PR_SUCCESS : PR_FAILURE); 58 default: 59 PORT_Assert(0); 60 return PR_FAILURE; 61 } 62 } 63 64 NSS_IMPLEMENT void 65 nssPKIObject_DestroyLock(nssPKIObject *object) 66 { 67 switch (object->lockType) { 68 case nssPKIMonitor: 69 PZ_DestroyMonitor(object->sync.mlock); 70 object->sync.mlock = NULL; 71 break; 72 case nssPKILock: 73 PZ_DestroyLock(object->sync.lock); 74 object->sync.lock = NULL; 75 break; 76 default: 77 PORT_Assert(0); 78 } 79 } 80 81 NSS_IMPLEMENT nssPKIObject * 82 nssPKIObject_Create( 83 NSSArena *arenaOpt, 84 nssCryptokiObject *instanceOpt, 85 NSSTrustDomain *td, 86 NSSCryptoContext *cc, 87 nssPKILockType lockType) 88 { 89 NSSArena *arena; 90 nssArenaMark *mark = NULL; 91 nssPKIObject *object; 92 if (arenaOpt) { 93 arena = arenaOpt; 94 mark = nssArena_Mark(arena); 95 } else { 96 arena = nssArena_Create(); 97 if (!arena) { 98 return (nssPKIObject *)NULL; 99 } 100 } 101 object = nss_ZNEW(arena, nssPKIObject); 102 if (!object) { 103 goto loser; 104 } 105 object->arena = arena; 106 object->trustDomain = td; /* XXX */ 107 object->cryptoContext = cc; 108 if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) { 109 goto loser; 110 } 111 if (instanceOpt) { 112 if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) { 113 goto loser; 114 } 115 } 116 PR_ATOMIC_INCREMENT(&object->refCount); 117 if (mark) { 118 nssArena_Unmark(arena, mark); 119 } 120 return object; 121 loser: 122 if (mark) { 123 nssArena_Release(arena, mark); 124 } else { 125 nssArena_Destroy(arena); 126 } 127 return (nssPKIObject *)NULL; 128 } 129 130 NSS_IMPLEMENT PRBool 131 nssPKIObject_Destroy( 132 nssPKIObject *object) 133 { 134 PRUint32 i; 135 PR_ASSERT(object->refCount > 0); 136 if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) { 137 for (i = 0; i < object->numInstances; i++) { 138 nssCryptokiObject_Destroy(object->instances[i]); 139 } 140 nssPKIObject_DestroyLock(object); 141 nssArena_Destroy(object->arena); 142 return PR_TRUE; 143 } 144 return PR_FALSE; 145 } 146 147 NSS_IMPLEMENT nssPKIObject * 148 nssPKIObject_AddRef( 149 nssPKIObject *object) 150 { 151 PR_ATOMIC_INCREMENT(&object->refCount); 152 return object; 153 } 154 155 NSS_IMPLEMENT PRStatus 156 nssPKIObject_AddInstance( 157 nssPKIObject *object, 158 nssCryptokiObject *instance) 159 { 160 nssCryptokiObject **newInstances = NULL; 161 162 nssPKIObject_Lock(object); 163 if (object->numInstances == 0) { 164 newInstances = nss_ZNEWARRAY(object->arena, 165 nssCryptokiObject *, 166 object->numInstances + 1); 167 } else { 168 PRBool found = PR_FALSE; 169 PRUint32 i; 170 for (i = 0; i < object->numInstances; i++) { 171 if (nssCryptokiObject_Equal(object->instances[i], instance)) { 172 found = PR_TRUE; 173 break; 174 } 175 } 176 if (found) { 177 /* The new instance is identical to one in the array, except 178 * perhaps that the label may be different. So replace 179 * the label in the array instance with the label from the 180 * new instance, and discard the new instance. 181 */ 182 nss_ZFreeIf(object->instances[i]->label); 183 object->instances[i]->label = instance->label; 184 nssPKIObject_Unlock(object); 185 instance->label = NULL; 186 nssCryptokiObject_Destroy(instance); 187 return PR_SUCCESS; 188 } 189 newInstances = nss_ZREALLOCARRAY(object->instances, 190 nssCryptokiObject *, 191 object->numInstances + 1); 192 } 193 if (newInstances) { 194 object->instances = newInstances; 195 newInstances[object->numInstances++] = instance; 196 } 197 nssPKIObject_Unlock(object); 198 return (newInstances ? PR_SUCCESS : PR_FAILURE); 199 } 200 201 NSS_IMPLEMENT PRBool 202 nssPKIObject_HasInstance( 203 nssPKIObject *object, 204 nssCryptokiObject *instance) 205 { 206 PRUint32 i; 207 PRBool hasIt = PR_FALSE; 208 ; 209 nssPKIObject_Lock(object); 210 for (i = 0; i < object->numInstances; i++) { 211 if (nssCryptokiObject_Equal(object->instances[i], instance)) { 212 hasIt = PR_TRUE; 213 break; 214 } 215 } 216 nssPKIObject_Unlock(object); 217 return hasIt; 218 } 219 220 NSS_IMPLEMENT PRStatus 221 nssPKIObject_RemoveInstanceForToken( 222 nssPKIObject *object, 223 NSSToken *token) 224 { 225 PRUint32 i; 226 nssCryptokiObject *instanceToRemove = NULL; 227 nssPKIObject_Lock(object); 228 if (object->numInstances == 0) { 229 nssPKIObject_Unlock(object); 230 return PR_SUCCESS; 231 } 232 for (i = 0; i < object->numInstances; i++) { 233 if (object->instances[i]->token == token) { 234 instanceToRemove = object->instances[i]; 235 object->instances[i] = object->instances[object->numInstances - 1]; 236 object->instances[object->numInstances - 1] = NULL; 237 break; 238 } 239 } 240 if (--object->numInstances > 0) { 241 nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances, 242 nssCryptokiObject *, 243 object->numInstances); 244 if (instances) { 245 object->instances = instances; 246 } 247 } else { 248 nss_ZFreeIf(object->instances); 249 } 250 nssCryptokiObject_Destroy(instanceToRemove); 251 nssPKIObject_Unlock(object); 252 return PR_SUCCESS; 253 } 254 255 /* this needs more thought on what will happen when there are multiple 256 * instances 257 */ 258 NSS_IMPLEMENT PRStatus 259 nssPKIObject_DeleteStoredObject( 260 nssPKIObject *object, 261 NSSCallback *uhh, 262 PRBool isFriendly) 263 { 264 PRUint32 i, numNotDestroyed; 265 PRStatus status = PR_SUCCESS; 266 numNotDestroyed = 0; 267 nssPKIObject_Lock(object); 268 for (i = 0; i < object->numInstances; i++) { 269 nssCryptokiObject *instance = object->instances[i]; 270 status = nssToken_DeleteStoredObject(instance); 271 object->instances[i] = NULL; 272 if (status == PR_SUCCESS) { 273 nssCryptokiObject_Destroy(instance); 274 } else { 275 object->instances[numNotDestroyed++] = instance; 276 } 277 } 278 if (numNotDestroyed == 0) { 279 nss_ZFreeIf(object->instances); 280 object->numInstances = 0; 281 } else { 282 object->numInstances = numNotDestroyed; 283 } 284 nssPKIObject_Unlock(object); 285 return status; 286 } 287 288 NSS_IMPLEMENT NSSToken ** 289 nssPKIObject_GetTokens( 290 nssPKIObject *object, 291 PRStatus *statusOpt) 292 { 293 NSSToken **tokens = NULL; 294 nssPKIObject_Lock(object); 295 if (object->numInstances > 0) { 296 tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1); 297 if (tokens) { 298 PRUint32 i; 299 for (i = 0; i < object->numInstances; i++) { 300 tokens[i] = nssToken_AddRef(object->instances[i]->token); 301 } 302 } 303 } 304 nssPKIObject_Unlock(object); 305 if (statusOpt) 306 *statusOpt = PR_SUCCESS; /* until more logic here */ 307 return tokens; 308 } 309 310 NSS_IMPLEMENT NSSUTF8 * 311 nssPKIObject_GetNicknameForToken( 312 nssPKIObject *object, 313 NSSToken *tokenOpt) 314 { 315 PRUint32 i; 316 NSSUTF8 *nickname = NULL; 317 nssPKIObject_Lock(object); 318 for (i = 0; i < object->numInstances; i++) { 319 if ((!tokenOpt && object->instances[i]->label) || 320 (object->instances[i]->token == tokenOpt)) { 321 /* Must copy, see bug 745548 */ 322 nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL); 323 break; 324 } 325 } 326 nssPKIObject_Unlock(object); 327 return nickname; 328 } 329 330 NSS_IMPLEMENT nssCryptokiObject ** 331 nssPKIObject_GetInstances( 332 nssPKIObject *object) 333 { 334 nssCryptokiObject **instances = NULL; 335 PRUint32 i; 336 337 nssPKIObject_Lock(object); 338 if (object->numInstances == 0) { 339 nssPKIObject_Unlock(object); 340 return (nssCryptokiObject **)NULL; 341 } 342 instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, 343 object->numInstances + 1); 344 if (instances) { 345 for (i = 0; i < object->numInstances; i++) { 346 instances[i] = nssCryptokiObject_Clone(object->instances[i]); 347 } 348 } 349 nssPKIObject_Unlock(object); 350 return instances; 351 } 352 353 NSS_IMPLEMENT void 354 nssCertificateArray_Destroy( 355 NSSCertificate **certs) 356 { 357 if (certs) { 358 NSSCertificate **certp; 359 for (certp = certs; *certp; certp++) { 360 if ((*certp)->decoding) { 361 CERTCertificate *cc = STAN_GetCERTCertificate(*certp); 362 if (cc) { 363 CERT_DestroyCertificate(cc); 364 } 365 continue; 366 } 367 nssCertificate_Destroy(*certp); 368 } 369 nss_ZFreeIf(certs); 370 } 371 } 372 373 NSS_IMPLEMENT void 374 NSSCertificateArray_Destroy( 375 NSSCertificate **certs) 376 { 377 nssCertificateArray_Destroy(certs); 378 } 379 380 NSS_IMPLEMENT NSSCertificate ** 381 nssCertificateArray_Join( 382 NSSCertificate **certs1, 383 NSSCertificate **certs2) 384 { 385 if (certs1 && certs2) { 386 NSSCertificate **certs, **cp; 387 PRUint32 count = 0; 388 PRUint32 count1 = 0; 389 cp = certs1; 390 while (*cp++) 391 count1++; 392 count = count1; 393 cp = certs2; 394 while (*cp++) 395 count++; 396 certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1); 397 if (!certs) { 398 nss_ZFreeIf(certs1); 399 nss_ZFreeIf(certs2); 400 return (NSSCertificate **)NULL; 401 } 402 for (cp = certs2; *cp; cp++, count1++) { 403 certs[count1] = *cp; 404 } 405 nss_ZFreeIf(certs2); 406 return certs; 407 } else if (certs1) { 408 return certs1; 409 } else { 410 return certs2; 411 } 412 } 413 414 NSS_IMPLEMENT NSSCertificate * 415 nssCertificateArray_FindBestCertificate( 416 NSSCertificate **certs, 417 NSSTime *timeOpt, 418 const NSSUsage *usage, 419 NSSPolicies *policiesOpt) 420 { 421 NSSCertificate *bestCert = NULL; 422 nssDecodedCert *bestdc = NULL; 423 NSSTime *time, sTime; 424 PRBool bestCertMatches = PR_FALSE; 425 PRBool thisCertMatches; 426 PRBool bestCertIsValidAtTime = PR_FALSE; 427 PRBool bestCertIsTrusted = PR_FALSE; 428 429 if (timeOpt) { 430 time = timeOpt; 431 } else { 432 NSSTime_Now(&sTime); 433 time = &sTime; 434 } 435 if (!certs) { 436 return (NSSCertificate *)NULL; 437 } 438 for (; *certs; certs++) { 439 nssDecodedCert *dc; 440 NSSCertificate *c = *certs; 441 dc = nssCertificate_GetDecoding(c); 442 if (!dc) 443 continue; 444 thisCertMatches = dc->matchUsage(dc, usage); 445 if (!bestCert) { 446 /* always take the first cert, but remember whether or not 447 * the usage matched 448 */ 449 bestCert = nssCertificate_AddRef(c); 450 bestCertMatches = thisCertMatches; 451 bestdc = dc; 452 continue; 453 } else { 454 if (bestCertMatches && !thisCertMatches) { 455 /* if already have a cert for this usage, and if this cert 456 * doesn't have the correct usage, continue 457 */ 458 continue; 459 } else if (!bestCertMatches && thisCertMatches) { 460 /* this one does match usage, replace the other */ 461 nssCertificate_Destroy(bestCert); 462 bestCert = nssCertificate_AddRef(c); 463 bestCertMatches = thisCertMatches; 464 bestdc = dc; 465 continue; 466 } 467 /* this cert match as well as any cert we've found so far, 468 * defer to time/policies 469 * */ 470 } 471 /* time */ 472 if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) { 473 /* The current best cert is valid at time */ 474 bestCertIsValidAtTime = PR_TRUE; 475 if (!dc->isValidAtTime(dc, time)) { 476 /* If the new cert isn't valid at time, it's not better */ 477 continue; 478 } 479 } else { 480 /* The current best cert is not valid at time */ 481 if (dc->isValidAtTime(dc, time)) { 482 /* If the new cert is valid at time, it's better */ 483 nssCertificate_Destroy(bestCert); 484 bestCert = nssCertificate_AddRef(c); 485 bestdc = dc; 486 bestCertIsValidAtTime = PR_TRUE; 487 continue; 488 } 489 } 490 /* Either they are both valid at time, or neither valid. 491 * If only one is trusted for this usage, take it. 492 */ 493 if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) { 494 bestCertIsTrusted = PR_TRUE; 495 if (!dc->isTrustedForUsage(dc, usage)) { 496 continue; 497 } 498 } else { 499 /* The current best cert is not trusted */ 500 if (dc->isTrustedForUsage(dc, usage)) { 501 /* If the new cert is trusted, it's better */ 502 nssCertificate_Destroy(bestCert); 503 bestCert = nssCertificate_AddRef(c); 504 bestdc = dc; 505 bestCertIsTrusted = PR_TRUE; 506 continue; 507 } 508 } 509 /* Otherwise, take the newer one. */ 510 if (!bestdc->isNewerThan(bestdc, dc)) { 511 nssCertificate_Destroy(bestCert); 512 bestCert = nssCertificate_AddRef(c); 513 bestdc = dc; 514 continue; 515 } 516 /* policies */ 517 /* XXX later -- defer to policies */ 518 } 519 return bestCert; 520 } 521 522 NSS_IMPLEMENT PRStatus 523 nssCertificateArray_Traverse( 524 NSSCertificate **certs, 525 PRStatus (*callback)(NSSCertificate *c, void *arg), 526 void *arg) 527 { 528 PRStatus status = PR_SUCCESS; 529 if (certs) { 530 NSSCertificate **certp; 531 for (certp = certs; *certp; certp++) { 532 status = (*callback)(*certp, arg); 533 if (status != PR_SUCCESS) { 534 break; 535 } 536 } 537 } 538 return status; 539 } 540 541 NSS_IMPLEMENT void 542 nssCRLArray_Destroy( 543 NSSCRL **crls) 544 { 545 if (crls) { 546 NSSCRL **crlp; 547 for (crlp = crls; *crlp; crlp++) { 548 nssCRL_Destroy(*crlp); 549 } 550 nss_ZFreeIf(crls); 551 } 552 } 553 554 /* 555 * Object collections 556 */ 557 558 typedef enum { 559 pkiObjectType_Certificate = 0, 560 pkiObjectType_CRL = 1, 561 pkiObjectType_PrivateKey = 2, 562 pkiObjectType_PublicKey = 3 563 } pkiObjectType; 564 565 /* Each object is defined by a set of items that uniquely identify it. 566 * Here are the uid sets: 567 * 568 * NSSCertificate ==> { issuer, serial } 569 * NSSPrivateKey 570 * (RSA) ==> { modulus, public exponent } 571 * 572 */ 573 #define MAX_ITEMS_FOR_UID 2 574 575 /* pkiObjectCollectionNode 576 * 577 * A node in the collection is the set of unique identifiers for a single 578 * object, along with either the actual object or a proto-object. 579 */ 580 typedef struct 581 { 582 PRCList link; 583 PRBool haveObject; 584 nssPKIObject *object; 585 NSSItem uid[MAX_ITEMS_FOR_UID]; 586 } pkiObjectCollectionNode; 587 588 /* nssPKIObjectCollection 589 * 590 * The collection is the set of all objects, plus the interfaces needed 591 * to manage the objects. 592 * 593 */ 594 struct nssPKIObjectCollectionStr { 595 NSSArena *arena; 596 NSSTrustDomain *td; 597 NSSCryptoContext *cc; 598 PRCList head; /* list of pkiObjectCollectionNode's */ 599 PRUint32 size; 600 pkiObjectType objectType; 601 void (*destroyObject)(nssPKIObject *o); 602 PRStatus (*getUIDFromObject)(nssPKIObject *o, NSSItem *uid); 603 PRStatus (*getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, 604 NSSArena *arena); 605 nssPKIObject *(*createObject)(nssPKIObject *o); 606 nssPKILockType lockType; /* type of lock to use for new proto-objects */ 607 }; 608 609 static nssPKIObjectCollection * 610 nssPKIObjectCollection_Create( 611 NSSTrustDomain *td, 612 NSSCryptoContext *ccOpt, 613 nssPKILockType lockType) 614 { 615 NSSArena *arena; 616 nssPKIObjectCollection *rvCollection = NULL; 617 arena = nssArena_Create(); 618 if (!arena) { 619 return (nssPKIObjectCollection *)NULL; 620 } 621 rvCollection = nss_ZNEW(arena, nssPKIObjectCollection); 622 if (!rvCollection) { 623 goto loser; 624 } 625 PR_INIT_CLIST(&rvCollection->head); 626 rvCollection->arena = arena; 627 rvCollection->td = td; /* XXX */ 628 rvCollection->cc = ccOpt; 629 rvCollection->lockType = lockType; 630 return rvCollection; 631 loser: 632 nssArena_Destroy(arena); 633 return (nssPKIObjectCollection *)NULL; 634 } 635 636 NSS_IMPLEMENT void 637 nssPKIObjectCollection_Destroy( 638 nssPKIObjectCollection *collection) 639 { 640 if (collection) { 641 PRCList *link; 642 pkiObjectCollectionNode *node; 643 /* first destroy any objects in the collection */ 644 link = PR_NEXT_LINK(&collection->head); 645 while (link != &collection->head) { 646 node = (pkiObjectCollectionNode *)link; 647 if (node->haveObject) { 648 (*collection->destroyObject)(node->object); 649 } else { 650 nssPKIObject_Destroy(node->object); 651 } 652 link = PR_NEXT_LINK(link); 653 } 654 /* then destroy it */ 655 nssArena_Destroy(collection->arena); 656 } 657 } 658 659 NSS_IMPLEMENT PRUint32 660 nssPKIObjectCollection_Count( 661 nssPKIObjectCollection *collection) 662 { 663 return collection->size; 664 } 665 666 NSS_IMPLEMENT PRStatus 667 nssPKIObjectCollection_AddObject( 668 nssPKIObjectCollection *collection, 669 nssPKIObject *object) 670 { 671 pkiObjectCollectionNode *node; 672 node = nss_ZNEW(collection->arena, pkiObjectCollectionNode); 673 if (!node) { 674 return PR_FAILURE; 675 } 676 node->haveObject = PR_TRUE; 677 node->object = nssPKIObject_AddRef(object); 678 (*collection->getUIDFromObject)(object, node->uid); 679 PR_INIT_CLIST(&node->link); 680 PR_INSERT_BEFORE(&node->link, &collection->head); 681 collection->size++; 682 return PR_SUCCESS; 683 } 684 685 static pkiObjectCollectionNode * 686 find_instance_in_collection( 687 nssPKIObjectCollection *collection, 688 nssCryptokiObject *instance) 689 { 690 PRCList *link; 691 pkiObjectCollectionNode *node; 692 link = PR_NEXT_LINK(&collection->head); 693 while (link != &collection->head) { 694 node = (pkiObjectCollectionNode *)link; 695 if (nssPKIObject_HasInstance(node->object, instance)) { 696 return node; 697 } 698 link = PR_NEXT_LINK(link); 699 } 700 return (pkiObjectCollectionNode *)NULL; 701 } 702 703 static pkiObjectCollectionNode * 704 find_object_in_collection( 705 nssPKIObjectCollection *collection, 706 NSSItem *uid) 707 { 708 PRUint32 i; 709 PRStatus status; 710 PRCList *link; 711 pkiObjectCollectionNode *node; 712 link = PR_NEXT_LINK(&collection->head); 713 while (link != &collection->head) { 714 node = (pkiObjectCollectionNode *)link; 715 for (i = 0; i < MAX_ITEMS_FOR_UID; i++) { 716 if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) { 717 break; 718 } 719 } 720 if (i == MAX_ITEMS_FOR_UID) { 721 return node; 722 } 723 link = PR_NEXT_LINK(link); 724 } 725 return (pkiObjectCollectionNode *)NULL; 726 } 727 728 static pkiObjectCollectionNode * 729 add_object_instance( 730 nssPKIObjectCollection *collection, 731 nssCryptokiObject *instance, 732 PRBool *foundIt) 733 { 734 PRUint32 i; 735 PRStatus status; 736 pkiObjectCollectionNode *node; 737 nssArenaMark *mark = NULL; 738 NSSItem uid[MAX_ITEMS_FOR_UID]; 739 nsslibc_memset(uid, 0, sizeof uid); 740 /* The list is traversed twice, first (here) looking to match the 741 * { token, handle } tuple, and if that is not found, below a search 742 * for unique identifier is done. Here, a match means this exact object 743 * instance is already in the collection, and we have nothing to do. 744 */ 745 *foundIt = PR_FALSE; 746 node = find_instance_in_collection(collection, instance); 747 if (node) { 748 /* The collection is assumed to take over the instance. Since we 749 * are not using it, it must be destroyed. 750 */ 751 nssCryptokiObject_Destroy(instance); 752 *foundIt = PR_TRUE; 753 return node; 754 } 755 mark = nssArena_Mark(collection->arena); 756 if (!mark) { 757 goto loser; 758 } 759 status = (*collection->getUIDFromInstance)(instance, uid, 760 collection->arena); 761 if (status != PR_SUCCESS) { 762 goto loser; 763 } 764 /* Search for unique identifier. A match here means the object exists 765 * in the collection, but does not have this instance, so the instance 766 * needs to be added. 767 */ 768 node = find_object_in_collection(collection, uid); 769 if (node) { 770 /* This is an object with multiple instances */ 771 status = nssPKIObject_AddInstance(node->object, instance); 772 } else { 773 /* This is a completely new object. Create a node for it. */ 774 node = nss_ZNEW(collection->arena, pkiObjectCollectionNode); 775 if (!node) { 776 goto loser; 777 } 778 node->object = nssPKIObject_Create(NULL, instance, 779 collection->td, collection->cc, 780 collection->lockType); 781 if (!node->object) { 782 goto loser; 783 } 784 for (i = 0; i < MAX_ITEMS_FOR_UID; i++) { 785 node->uid[i] = uid[i]; 786 } 787 node->haveObject = PR_FALSE; 788 PR_INIT_CLIST(&node->link); 789 PR_INSERT_BEFORE(&node->link, &collection->head); 790 collection->size++; 791 status = PR_SUCCESS; 792 } 793 nssArena_Unmark(collection->arena, mark); 794 return node; 795 loser: 796 if (mark) { 797 nssArena_Release(collection->arena, mark); 798 } 799 nssCryptokiObject_Destroy(instance); 800 return (pkiObjectCollectionNode *)NULL; 801 } 802 803 NSS_IMPLEMENT PRStatus 804 nssPKIObjectCollection_AddInstances( 805 nssPKIObjectCollection *collection, 806 nssCryptokiObject **instances, 807 PRUint32 numInstances) 808 { 809 PRStatus status = PR_SUCCESS; 810 PRUint32 i = 0; 811 PRBool foundIt; 812 pkiObjectCollectionNode *node; 813 if (instances) { 814 while ((!numInstances || i < numInstances) && *instances) { 815 if (status == PR_SUCCESS) { 816 node = add_object_instance(collection, *instances, &foundIt); 817 if (node == NULL) { 818 /* add_object_instance freed the current instance */ 819 /* free the remaining instances */ 820 status = PR_FAILURE; 821 } 822 } else { 823 nssCryptokiObject_Destroy(*instances); 824 } 825 instances++; 826 i++; 827 } 828 } 829 return status; 830 } 831 832 static void 833 nssPKIObjectCollection_RemoveNode( 834 nssPKIObjectCollection *collection, 835 pkiObjectCollectionNode *node) 836 { 837 PR_REMOVE_LINK(&node->link); 838 collection->size--; 839 } 840 841 static PRStatus 842 nssPKIObjectCollection_GetObjects( 843 nssPKIObjectCollection *collection, 844 nssPKIObject **rvObjects, 845 PRUint32 rvSize) 846 { 847 PRUint32 i = 0; 848 PRCList *link = PR_NEXT_LINK(&collection->head); 849 pkiObjectCollectionNode *node; 850 int error = 0; 851 while ((i < rvSize) && (link != &collection->head)) { 852 node = (pkiObjectCollectionNode *)link; 853 if (!node->haveObject) { 854 /* Convert the proto-object to an object */ 855 node->object = (*collection->createObject)(node->object); 856 if (!node->object) { 857 link = PR_NEXT_LINK(link); 858 /*remove bogus object from list*/ 859 nssPKIObjectCollection_RemoveNode(collection, node); 860 error++; 861 continue; 862 } 863 node->haveObject = PR_TRUE; 864 } 865 rvObjects[i++] = nssPKIObject_AddRef(node->object); 866 link = PR_NEXT_LINK(link); 867 } 868 if (!error && *rvObjects == NULL) { 869 nss_SetError(NSS_ERROR_NOT_FOUND); 870 } 871 return PR_SUCCESS; 872 } 873 874 NSS_IMPLEMENT PRStatus 875 nssPKIObjectCollection_Traverse( 876 nssPKIObjectCollection *collection, 877 nssPKIObjectCallback *callback) 878 { 879 PRCList *link = PR_NEXT_LINK(&collection->head); 880 pkiObjectCollectionNode *node; 881 while (link != &collection->head) { 882 node = (pkiObjectCollectionNode *)link; 883 if (!node->haveObject) { 884 node->object = (*collection->createObject)(node->object); 885 if (!node->object) { 886 link = PR_NEXT_LINK(link); 887 /*remove bogus object from list*/ 888 nssPKIObjectCollection_RemoveNode(collection, node); 889 continue; 890 } 891 node->haveObject = PR_TRUE; 892 } 893 switch (collection->objectType) { 894 case pkiObjectType_Certificate: 895 (void)(*callback->func.cert)((NSSCertificate *)node->object, 896 callback->arg); 897 break; 898 case pkiObjectType_CRL: 899 (void)(*callback->func.crl)((NSSCRL *)node->object, 900 callback->arg); 901 break; 902 case pkiObjectType_PrivateKey: 903 (void)(*callback->func.pvkey)((NSSPrivateKey *)node->object, 904 callback->arg); 905 break; 906 case pkiObjectType_PublicKey: 907 (void)(*callback->func.pbkey)((NSSPublicKey *)node->object, 908 callback->arg); 909 break; 910 } 911 link = PR_NEXT_LINK(link); 912 } 913 return PR_SUCCESS; 914 } 915 916 NSS_IMPLEMENT PRStatus 917 nssPKIObjectCollection_AddInstanceAsObject( 918 nssPKIObjectCollection *collection, 919 nssCryptokiObject *instance) 920 { 921 pkiObjectCollectionNode *node; 922 PRBool foundIt; 923 node = add_object_instance(collection, instance, &foundIt); 924 if (node == NULL) { 925 return PR_FAILURE; 926 } 927 if (!node->haveObject) { 928 nssPKIObject *original = node->object; 929 node->object = (*collection->createObject)(node->object); 930 if (!node->object) { 931 /*remove bogus object from list*/ 932 nssPKIObject_Destroy(original); 933 nssPKIObjectCollection_RemoveNode(collection, node); 934 return PR_FAILURE; 935 } 936 node->haveObject = PR_TRUE; 937 } else if (!foundIt) { 938 /* The instance was added to a pre-existing node. This 939 * function is *only* being used for certificates, and having 940 * multiple instances of certs in 3.X requires updating the 941 * CERTCertificate. 942 * But only do it if it was a new instance!!! If the same instance 943 * is encountered, we set *foundIt to true. Detect that here and 944 * ignore it. 945 */ 946 STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object); 947 } 948 return PR_SUCCESS; 949 } 950 951 /* 952 * Certificate collections 953 */ 954 955 static void 956 cert_destroyObject(nssPKIObject *o) 957 { 958 NSSCertificate *c = (NSSCertificate *)o; 959 if (c->decoding) { 960 CERTCertificate *cc = STAN_GetCERTCertificate(c); 961 if (cc) { 962 CERT_DestroyCertificate(cc); 963 return; 964 } /* else destroy it as NSSCertificate below */ 965 } 966 nssCertificate_Destroy(c); 967 } 968 969 static PRStatus 970 cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid) 971 { 972 NSSCertificate *c = (NSSCertificate *)o; 973 /* The builtins are still returning decoded serial numbers. Until 974 * this compatibility issue is resolved, use the full DER of the 975 * cert to uniquely identify it. 976 */ 977 NSSDER *derCert; 978 derCert = nssCertificate_GetEncoding(c); 979 uid[0].data = NULL; 980 uid[0].size = 0; 981 uid[1].data = NULL; 982 uid[1].size = 0; 983 if (derCert != NULL) { 984 uid[0] = *derCert; 985 } 986 return PR_SUCCESS; 987 } 988 989 static PRStatus 990 cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 991 NSSArena *arena) 992 { 993 /* The builtins are still returning decoded serial numbers. Until 994 * this compatibility issue is resolved, use the full DER of the 995 * cert to uniquely identify it. 996 */ 997 uid[1].data = NULL; 998 uid[1].size = 0; 999 return nssCryptokiCertificate_GetAttributes(instance, 1000 NULL, /* XXX sessionOpt */ 1001 arena, /* arena */ 1002 NULL, /* type */ 1003 NULL, /* id */ 1004 &uid[0], /* encoding */ 1005 NULL, /* issuer */ 1006 NULL, /* serial */ 1007 NULL); /* subject */ 1008 } 1009 1010 static nssPKIObject * 1011 cert_createObject(nssPKIObject *o) 1012 { 1013 NSSCertificate *cert; 1014 cert = nssCertificate_Create(o); 1015 /* if (STAN_GetCERTCertificate(cert) == NULL) { 1016 nssCertificate_Destroy(cert); 1017 return (nssPKIObject *)NULL; 1018 } */ 1019 /* In 3.4, have to maintain uniqueness of cert pointers by caching all 1020 * certs. Cache the cert here, before returning. If it is already 1021 * cached, take the cached entry. 1022 */ 1023 { 1024 NSSTrustDomain *td = o->trustDomain; 1025 nssTrustDomain_AddCertsToCache(td, &cert, 1); 1026 } 1027 return (nssPKIObject *)cert; 1028 } 1029 1030 NSS_IMPLEMENT nssPKIObjectCollection * 1031 nssCertificateCollection_Create( 1032 NSSTrustDomain *td, 1033 NSSCertificate **certsOpt) 1034 { 1035 nssPKIObjectCollection *collection; 1036 collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor); 1037 if (!collection) { 1038 return NULL; 1039 } 1040 collection->objectType = pkiObjectType_Certificate; 1041 collection->destroyObject = cert_destroyObject; 1042 collection->getUIDFromObject = cert_getUIDFromObject; 1043 collection->getUIDFromInstance = cert_getUIDFromInstance; 1044 collection->createObject = cert_createObject; 1045 if (certsOpt) { 1046 for (; *certsOpt; certsOpt++) { 1047 nssPKIObject *object = (nssPKIObject *)(*certsOpt); 1048 (void)nssPKIObjectCollection_AddObject(collection, object); 1049 } 1050 } 1051 return collection; 1052 } 1053 1054 NSS_IMPLEMENT NSSCertificate ** 1055 nssPKIObjectCollection_GetCertificates( 1056 nssPKIObjectCollection *collection, 1057 NSSCertificate **rvOpt, 1058 PRUint32 maximumOpt, 1059 NSSArena *arenaOpt) 1060 { 1061 PRStatus status; 1062 PRUint32 rvSize; 1063 PRBool allocated = PR_FALSE; 1064 if (collection->size == 0) { 1065 return (NSSCertificate **)NULL; 1066 } 1067 if (maximumOpt == 0) { 1068 rvSize = collection->size; 1069 } else { 1070 rvSize = PR_MIN(collection->size, maximumOpt); 1071 } 1072 if (!rvOpt) { 1073 rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1); 1074 if (!rvOpt) { 1075 return (NSSCertificate **)NULL; 1076 } 1077 allocated = PR_TRUE; 1078 } 1079 status = nssPKIObjectCollection_GetObjects(collection, 1080 (nssPKIObject **)rvOpt, 1081 rvSize); 1082 if (status != PR_SUCCESS) { 1083 if (allocated) { 1084 nss_ZFreeIf(rvOpt); 1085 } 1086 return (NSSCertificate **)NULL; 1087 } 1088 return rvOpt; 1089 } 1090 1091 /* 1092 * CRL/KRL collections 1093 */ 1094 1095 static void 1096 crl_destroyObject(nssPKIObject *o) 1097 { 1098 NSSCRL *crl = (NSSCRL *)o; 1099 nssCRL_Destroy(crl); 1100 } 1101 1102 static PRStatus 1103 crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid) 1104 { 1105 NSSCRL *crl = (NSSCRL *)o; 1106 NSSDER *encoding; 1107 encoding = nssCRL_GetEncoding(crl); 1108 if (!encoding) { 1109 nss_SetError(NSS_ERROR_INVALID_ARGUMENT); 1110 return PR_FALSE; 1111 } 1112 uid[0] = *encoding; 1113 uid[1].data = NULL; 1114 uid[1].size = 0; 1115 return PR_SUCCESS; 1116 } 1117 1118 static PRStatus 1119 crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 1120 NSSArena *arena) 1121 { 1122 return nssCryptokiCRL_GetAttributes(instance, 1123 NULL, /* XXX sessionOpt */ 1124 arena, /* arena */ 1125 &uid[0], /* encoding */ 1126 NULL, /* subject */ 1127 NULL, /* class */ 1128 NULL, /* url */ 1129 NULL); /* isKRL */ 1130 } 1131 1132 static nssPKIObject * 1133 crl_createObject(nssPKIObject *o) 1134 { 1135 return (nssPKIObject *)nssCRL_Create(o); 1136 } 1137 1138 NSS_IMPLEMENT nssPKIObjectCollection * 1139 nssCRLCollection_Create( 1140 NSSTrustDomain *td, 1141 NSSCRL **crlsOpt) 1142 { 1143 nssPKIObjectCollection *collection; 1144 collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock); 1145 if (!collection) { 1146 return NULL; 1147 } 1148 collection->objectType = pkiObjectType_CRL; 1149 collection->destroyObject = crl_destroyObject; 1150 collection->getUIDFromObject = crl_getUIDFromObject; 1151 collection->getUIDFromInstance = crl_getUIDFromInstance; 1152 collection->createObject = crl_createObject; 1153 if (crlsOpt) { 1154 for (; *crlsOpt; crlsOpt++) { 1155 nssPKIObject *object = (nssPKIObject *)(*crlsOpt); 1156 (void)nssPKIObjectCollection_AddObject(collection, object); 1157 } 1158 } 1159 return collection; 1160 } 1161 1162 NSS_IMPLEMENT NSSCRL ** 1163 nssPKIObjectCollection_GetCRLs( 1164 nssPKIObjectCollection *collection, 1165 NSSCRL **rvOpt, 1166 PRUint32 maximumOpt, 1167 NSSArena *arenaOpt) 1168 { 1169 PRStatus status; 1170 PRUint32 rvSize; 1171 PRBool allocated = PR_FALSE; 1172 if (collection->size == 0) { 1173 return (NSSCRL **)NULL; 1174 } 1175 if (maximumOpt == 0) { 1176 rvSize = collection->size; 1177 } else { 1178 rvSize = PR_MIN(collection->size, maximumOpt); 1179 } 1180 if (!rvOpt) { 1181 rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1); 1182 if (!rvOpt) { 1183 return (NSSCRL **)NULL; 1184 } 1185 allocated = PR_TRUE; 1186 } 1187 status = nssPKIObjectCollection_GetObjects(collection, 1188 (nssPKIObject **)rvOpt, 1189 rvSize); 1190 if (status != PR_SUCCESS) { 1191 if (allocated) { 1192 nss_ZFreeIf(rvOpt); 1193 } 1194 return (NSSCRL **)NULL; 1195 } 1196 return rvOpt; 1197 } 1198 1199 /* how bad would it be to have a static now sitting around, updated whenever 1200 * this was called? would avoid repeated allocs... 1201 */ 1202 NSS_IMPLEMENT NSSTime * 1203 NSSTime_Now(NSSTime *timeOpt) 1204 { 1205 return NSSTime_SetPRTime(timeOpt, PR_Now()); 1206 } 1207 1208 NSS_IMPLEMENT NSSTime * 1209 NSSTime_SetPRTime( 1210 NSSTime *timeOpt, 1211 PRTime prTime) 1212 { 1213 NSSTime *rvTime; 1214 rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime); 1215 if (rvTime) { 1216 rvTime->prTime = prTime; 1217 } 1218 return rvTime; 1219 } 1220 1221 NSS_IMPLEMENT PRTime 1222 NSSTime_GetPRTime( 1223 NSSTime *time) 1224 { 1225 return time->prTime; 1226 }