PageRenderTime 79ms CodeModel.GetById 7ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/lib/pki/pkibase.c

http://github.com/zpao/v8monkey
C | 1268 lines | 1062 code | 65 blank | 141 comment | 177 complexity | 8b6004d84e45ed6af1d6bff8079fa48e MD5 | raw file
   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   4 * The contents of this file are subject to the Mozilla Public License Version
   5 * 1.1 (the "License"); you may not use this file except in compliance with
   6 * the License. You may obtain a copy of the License at
   7 * http://www.mozilla.org/MPL/
   8 *
   9 * Software distributed under the License is distributed on an "AS IS" basis,
  10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11 * for the specific language governing rights and limitations under the
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  16 * The Initial Developer of the Original Code is
  17 * Netscape Communications Corporation.
  18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19 * the Initial Developer. All Rights Reserved.
  20 *
  21 * Contributor(s):
  22 *
  23 * Alternatively, the contents of this file may be used under the terms of
  24 * either the GNU General Public License Version 2 or later (the "GPL"), or
  25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26 * in which case the provisions of the GPL or the LGPL are applicable instead
  27 * of those above. If you wish to allow use of your version of this file only
  28 * under the terms of either the GPL or the LGPL, and not to allow others to
  29 * use your version of this file under the terms of the MPL, indicate your
  30 * decision by deleting the provisions above and replace them with the notice
  31 * and other provisions required by the GPL or the LGPL. If you do not delete
  32 * the provisions above, a recipient may use your version of this file under
  33 * the terms of any one of the MPL, the GPL or the LGPL.
  34 *
  35 * ***** END LICENSE BLOCK ***** */
  36
  37#ifdef DEBUG
  38static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.33 $ $Date: 2010/04/03 18:27:32 $";
  39#endif /* DEBUG */
  40
  41#ifndef DEV_H
  42#include "dev.h"
  43#endif /* DEV_H */
  44
  45#ifndef PKIM_H
  46#include "pkim.h"
  47#endif /* PKIM_H */
  48
  49#include "pki3hack.h"
  50
  51extern const NSSError NSS_ERROR_NOT_FOUND;
  52
  53NSS_IMPLEMENT void
  54nssPKIObject_Lock(nssPKIObject * object)
  55{
  56    switch (object->lockType) {
  57    case nssPKIMonitor:
  58        PZ_EnterMonitor(object->sync.mlock);
  59        break;
  60    case nssPKILock:
  61        PZ_Lock(object->sync.lock);
  62        break;
  63    default:
  64        PORT_Assert(0);
  65    }
  66}
  67
  68NSS_IMPLEMENT void
  69nssPKIObject_Unlock(nssPKIObject * object)
  70{
  71    switch (object->lockType) {
  72    case nssPKIMonitor:
  73        PZ_ExitMonitor(object->sync.mlock);
  74        break;
  75    case nssPKILock:
  76        PZ_Unlock(object->sync.lock);
  77        break;
  78    default:
  79        PORT_Assert(0);
  80    }
  81}
  82
  83NSS_IMPLEMENT PRStatus
  84nssPKIObject_NewLock(nssPKIObject * object, nssPKILockType lockType)
  85{
  86    object->lockType = lockType;
  87    switch (lockType) {
  88    case nssPKIMonitor:
  89        object->sync.mlock = PZ_NewMonitor(nssILockSSL);
  90        return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
  91    case nssPKILock:
  92        object->sync.lock = PZ_NewLock(nssILockSSL);
  93        return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
  94    default:
  95        PORT_Assert(0);
  96        return PR_FAILURE;
  97    }
  98}
  99
 100NSS_IMPLEMENT void
 101nssPKIObject_DestroyLock(nssPKIObject * object)
 102{
 103    switch (object->lockType) {
 104    case nssPKIMonitor:
 105        PZ_DestroyMonitor(object->sync.mlock);
 106        object->sync.mlock = NULL;
 107        break;
 108    case nssPKILock:
 109        PZ_DestroyLock(object->sync.lock);
 110        object->sync.lock = NULL;
 111        break;
 112    default:
 113        PORT_Assert(0);
 114    }
 115}
 116
 117
 118
 119NSS_IMPLEMENT nssPKIObject *
 120nssPKIObject_Create (
 121  NSSArena *arenaOpt,
 122  nssCryptokiObject *instanceOpt,
 123  NSSTrustDomain *td,
 124  NSSCryptoContext *cc,
 125  nssPKILockType lockType
 126)
 127{
 128    NSSArena *arena;
 129    nssArenaMark *mark = NULL;
 130    nssPKIObject *object;
 131    if (arenaOpt) {
 132	arena = arenaOpt;
 133	mark = nssArena_Mark(arena);
 134    } else {
 135	arena = nssArena_Create();
 136	if (!arena) {
 137	    return (nssPKIObject *)NULL;
 138	}
 139    }
 140    object = nss_ZNEW(arena, nssPKIObject);
 141    if (!object) {
 142	goto loser;
 143    }
 144    object->arena = arena;
 145    object->trustDomain = td; /* XXX */
 146    object->cryptoContext = cc;
 147    if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
 148	goto loser;
 149    }
 150    if (instanceOpt) {
 151	if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
 152	    goto loser;
 153	}
 154    }
 155    PR_ATOMIC_INCREMENT(&object->refCount);
 156    if (mark) {
 157	nssArena_Unmark(arena, mark);
 158    }
 159    return object;
 160loser:
 161    if (mark) {
 162	nssArena_Release(arena, mark);
 163    } else {
 164	nssArena_Destroy(arena);
 165    }
 166    return (nssPKIObject *)NULL;
 167}
 168
 169NSS_IMPLEMENT PRBool
 170nssPKIObject_Destroy (
 171  nssPKIObject *object
 172)
 173{
 174    PRUint32 i;
 175    PR_ASSERT(object->refCount > 0);
 176    if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) {
 177	for (i=0; i<object->numInstances; i++) {
 178	    nssCryptokiObject_Destroy(object->instances[i]);
 179	}
 180	nssPKIObject_DestroyLock(object);
 181	nssArena_Destroy(object->arena);
 182	return PR_TRUE;
 183    }
 184    return PR_FALSE;
 185}
 186
 187NSS_IMPLEMENT nssPKIObject *
 188nssPKIObject_AddRef (
 189  nssPKIObject *object
 190)
 191{
 192    PR_ATOMIC_INCREMENT(&object->refCount);
 193    return object;
 194}
 195
 196NSS_IMPLEMENT PRStatus
 197nssPKIObject_AddInstance (
 198  nssPKIObject *object,
 199  nssCryptokiObject *instance
 200)
 201{
 202    nssCryptokiObject **newInstances = NULL;
 203
 204    nssPKIObject_Lock(object);
 205    if (object->numInstances == 0) {
 206	newInstances = nss_ZNEWARRAY(object->arena,
 207				     nssCryptokiObject *,
 208				     object->numInstances + 1);
 209    } else {
 210	PRBool found = PR_FALSE;
 211	PRUint32 i;
 212	for (i=0; i<object->numInstances; i++) {
 213	    if (nssCryptokiObject_Equal(object->instances[i], instance)) {
 214		found = PR_TRUE;
 215		break;
 216	    }
 217	}
 218	if (found) {
 219	    /* The new instance is identical to one in the array, except
 220	     * perhaps that the label may be different.  So replace 
 221	     * the label in the array instance with the label from the 
 222	     * new instance, and discard the new instance.
 223	     */
 224	    nss_ZFreeIf(object->instances[i]->label);
 225	    object->instances[i]->label = instance->label;
 226	    nssPKIObject_Unlock(object);
 227	    instance->label = NULL;
 228	    nssCryptokiObject_Destroy(instance);
 229	    return PR_SUCCESS;
 230	}
 231	newInstances = nss_ZREALLOCARRAY(object->instances,
 232					 nssCryptokiObject *,
 233					 object->numInstances + 1);
 234    }
 235    if (newInstances) {
 236	object->instances = newInstances;
 237	newInstances[object->numInstances++] = instance;
 238    }
 239    nssPKIObject_Unlock(object);
 240    return (newInstances ? PR_SUCCESS : PR_FAILURE);
 241}
 242
 243NSS_IMPLEMENT PRBool
 244nssPKIObject_HasInstance (
 245  nssPKIObject *object,
 246  nssCryptokiObject *instance
 247)
 248{
 249    PRUint32 i;
 250    PRBool hasIt = PR_FALSE;;
 251    nssPKIObject_Lock(object);
 252    for (i=0; i<object->numInstances; i++) {
 253	if (nssCryptokiObject_Equal(object->instances[i], instance)) {
 254	    hasIt = PR_TRUE;
 255	    break;
 256	}
 257    }
 258    nssPKIObject_Unlock(object);
 259    return hasIt;
 260}
 261
 262NSS_IMPLEMENT PRStatus
 263nssPKIObject_RemoveInstanceForToken (
 264  nssPKIObject *object,
 265  NSSToken *token
 266)
 267{
 268    PRUint32 i;
 269    nssCryptokiObject *instanceToRemove = NULL;
 270    nssPKIObject_Lock(object);
 271    if (object->numInstances == 0) {
 272	nssPKIObject_Unlock(object);
 273	return PR_SUCCESS;
 274    }
 275    for (i=0; i<object->numInstances; i++) {
 276	if (object->instances[i]->token == token) {
 277	    instanceToRemove = object->instances[i];
 278	    object->instances[i] = object->instances[object->numInstances-1];
 279	    object->instances[object->numInstances-1] = NULL;
 280	    break;
 281	}
 282    }
 283    if (--object->numInstances > 0) {
 284	nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,
 285	                                      nssCryptokiObject *,
 286	                                      object->numInstances);
 287	if (instances) {
 288	    object->instances = instances;
 289	}
 290    } else {
 291	nss_ZFreeIf(object->instances);
 292    }
 293    nssCryptokiObject_Destroy(instanceToRemove);
 294    nssPKIObject_Unlock(object);
 295    return PR_SUCCESS;
 296}
 297
 298/* this needs more thought on what will happen when there are multiple
 299 * instances
 300 */
 301NSS_IMPLEMENT PRStatus
 302nssPKIObject_DeleteStoredObject (
 303  nssPKIObject *object,
 304  NSSCallback *uhh,
 305  PRBool isFriendly
 306)
 307{
 308    PRUint32 i, numNotDestroyed;
 309    PRStatus status = PR_SUCCESS;
 310    numNotDestroyed = 0;
 311    nssPKIObject_Lock(object);
 312    for (i=0; i<object->numInstances; i++) {
 313	nssCryptokiObject *instance = object->instances[i];
 314	status = nssToken_DeleteStoredObject(instance);
 315	object->instances[i] = NULL;
 316	if (status == PR_SUCCESS) {
 317	    nssCryptokiObject_Destroy(instance);
 318	} else {
 319	    object->instances[numNotDestroyed++] = instance;
 320	}
 321    }
 322    if (numNotDestroyed == 0) {
 323	nss_ZFreeIf(object->instances);
 324	object->numInstances = 0;
 325    } else {
 326	object->numInstances = numNotDestroyed;
 327    }
 328    nssPKIObject_Unlock(object);
 329    return status;
 330}
 331
 332NSS_IMPLEMENT NSSToken **
 333nssPKIObject_GetTokens (
 334  nssPKIObject *object,
 335  PRStatus *statusOpt
 336)
 337{
 338    NSSToken **tokens = NULL;
 339    nssPKIObject_Lock(object);
 340    if (object->numInstances > 0) {
 341	tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1);
 342	if (tokens) {
 343	    PRUint32 i;
 344	    for (i=0; i<object->numInstances; i++) {
 345		tokens[i] = nssToken_AddRef(object->instances[i]->token);
 346	    }
 347	}
 348    }
 349    nssPKIObject_Unlock(object);
 350    if (statusOpt) *statusOpt = PR_SUCCESS; /* until more logic here */
 351    return tokens;
 352}
 353
 354NSS_IMPLEMENT NSSUTF8 *
 355nssPKIObject_GetNicknameForToken (
 356  nssPKIObject *object,
 357  NSSToken *tokenOpt
 358)
 359{
 360    PRUint32 i;
 361    NSSUTF8 *nickname = NULL;
 362    nssPKIObject_Lock(object);
 363    for (i=0; i<object->numInstances; i++) {
 364	if ((!tokenOpt && object->instances[i]->label) ||
 365	    (object->instances[i]->token == tokenOpt)) 
 366	{
 367            /* XXX should be copy? safe as long as caller has reference */
 368	    nickname = object->instances[i]->label; 
 369	    break;
 370	}
 371    }
 372    nssPKIObject_Unlock(object);
 373    return nickname;
 374}
 375
 376NSS_IMPLEMENT nssCryptokiObject **
 377nssPKIObject_GetInstances (
 378  nssPKIObject *object
 379)
 380{
 381    nssCryptokiObject **instances = NULL;
 382    PRUint32 i;
 383    if (object->numInstances == 0) {
 384	return (nssCryptokiObject **)NULL;
 385    }
 386    nssPKIObject_Lock(object);
 387    instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, 
 388                              object->numInstances + 1);
 389    if (instances) {
 390	for (i=0; i<object->numInstances; i++) {
 391	    instances[i] = nssCryptokiObject_Clone(object->instances[i]);
 392	}
 393    }
 394    nssPKIObject_Unlock(object);
 395    return instances;
 396}
 397
 398NSS_IMPLEMENT void
 399nssCertificateArray_Destroy (
 400  NSSCertificate **certs
 401)
 402{
 403    if (certs) {
 404	NSSCertificate **certp;
 405	for (certp = certs; *certp; certp++) {
 406	    if ((*certp)->decoding) {
 407		CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
 408		if (cc) {
 409		    CERT_DestroyCertificate(cc);
 410		}
 411		continue;
 412	    }
 413	    nssCertificate_Destroy(*certp);
 414	}
 415	nss_ZFreeIf(certs);
 416    }
 417}
 418
 419NSS_IMPLEMENT void
 420NSSCertificateArray_Destroy (
 421  NSSCertificate **certs
 422)
 423{
 424    nssCertificateArray_Destroy(certs);
 425}
 426
 427NSS_IMPLEMENT NSSCertificate **
 428nssCertificateArray_Join (
 429  NSSCertificate **certs1,
 430  NSSCertificate **certs2
 431)
 432{
 433    if (certs1 && certs2) {
 434	NSSCertificate **certs, **cp;
 435	PRUint32 count = 0;
 436	PRUint32 count1 = 0;
 437	cp = certs1;
 438	while (*cp++) count1++;
 439	count = count1;
 440	cp = certs2;
 441	while (*cp++) count++;
 442	certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
 443	if (!certs) {
 444	    nss_ZFreeIf(certs1);
 445	    nss_ZFreeIf(certs2);
 446	    return (NSSCertificate **)NULL;
 447	}
 448	for (cp = certs2; *cp; cp++, count1++) {
 449	    certs[count1] = *cp;
 450	}
 451	nss_ZFreeIf(certs2);
 452	return certs;
 453    } else if (certs1) {
 454	return certs1;
 455    } else {
 456	return certs2;
 457    }
 458}
 459
 460NSS_IMPLEMENT NSSCertificate * 
 461nssCertificateArray_FindBestCertificate (
 462  NSSCertificate **certs, 
 463  NSSTime *timeOpt,
 464  const NSSUsage *usage,
 465  NSSPolicies *policiesOpt
 466)
 467{
 468    NSSCertificate *bestCert = NULL;
 469    NSSTime *time, sTime;
 470    PRBool haveUsageMatch = PR_FALSE;
 471    PRBool thisCertMatches;
 472
 473    if (timeOpt) {
 474	time = timeOpt;
 475    } else {
 476	NSSTime_Now(&sTime);
 477	time = &sTime;
 478    }
 479    if (!certs) {
 480	return (NSSCertificate *)NULL;
 481    }
 482    for (; *certs; certs++) {
 483	nssDecodedCert *dc, *bestdc;
 484	NSSCertificate *c = *certs;
 485	dc = nssCertificate_GetDecoding(c);
 486	if (!dc) continue;
 487	thisCertMatches = dc->matchUsage(dc, usage);
 488	if (!bestCert) {
 489	    /* always take the first cert, but remember whether or not
 490	     * the usage matched 
 491	     */
 492	    bestCert = nssCertificate_AddRef(c);
 493	    haveUsageMatch = thisCertMatches;
 494	    continue;
 495	} else {
 496	    if (haveUsageMatch && !thisCertMatches) {
 497		/* if already have a cert for this usage, and if this cert 
 498		 * doesn't have the correct usage, continue
 499		 */
 500		continue;
 501	    } else if (!haveUsageMatch && thisCertMatches) {
 502		/* this one does match usage, replace the other */
 503		nssCertificate_Destroy(bestCert);
 504		bestCert = nssCertificate_AddRef(c);
 505		haveUsageMatch = PR_TRUE;
 506		continue;
 507	    }
 508	    /* this cert match as well as any cert we've found so far, 
 509	     * defer to time/policies 
 510	     * */
 511	}
 512	bestdc = nssCertificate_GetDecoding(bestCert);
 513	if (!bestdc) {
 514	    nssCertificate_Destroy(bestCert);
 515	    bestCert = nssCertificate_AddRef(c);
 516	    continue;
 517	}
 518	/* time */
 519	if (bestdc->isValidAtTime(bestdc, time)) {
 520	    /* The current best cert is valid at time */
 521	    if (!dc->isValidAtTime(dc, time)) {
 522		/* If the new cert isn't valid at time, it's not better */
 523		continue;
 524	    }
 525	} else {
 526	    /* The current best cert is not valid at time */
 527	    if (dc->isValidAtTime(dc, time)) {
 528		/* If the new cert is valid at time, it's better */
 529		nssCertificate_Destroy(bestCert);
 530		bestCert = nssCertificate_AddRef(c);
 531	    }
 532	}
 533	/* either they are both valid at time, or neither valid; 
 534	 * take the newer one
 535	 */
 536	if (!bestdc->isNewerThan(bestdc, dc)) {
 537	    nssCertificate_Destroy(bestCert);
 538	    bestCert = nssCertificate_AddRef(c);
 539	}
 540	/* policies */
 541	/* XXX later -- defer to policies */
 542    }
 543    return bestCert;
 544}
 545
 546NSS_IMPLEMENT PRStatus
 547nssCertificateArray_Traverse (
 548  NSSCertificate **certs,
 549  PRStatus (* callback)(NSSCertificate *c, void *arg),
 550  void *arg
 551)
 552{
 553    PRStatus status = PR_SUCCESS;
 554    if (certs) {
 555	NSSCertificate **certp;
 556	for (certp = certs; *certp; certp++) {
 557	    status = (*callback)(*certp, arg);
 558	    if (status != PR_SUCCESS) {
 559		break;
 560	    }
 561	}
 562    }
 563    return status;
 564}
 565
 566
 567NSS_IMPLEMENT void
 568nssCRLArray_Destroy (
 569  NSSCRL **crls
 570)
 571{
 572    if (crls) {
 573	NSSCRL **crlp;
 574	for (crlp = crls; *crlp; crlp++) {
 575	    nssCRL_Destroy(*crlp);
 576	}
 577	nss_ZFreeIf(crls);
 578    }
 579}
 580
 581/*
 582 * Object collections
 583 */
 584
 585typedef enum
 586{
 587  pkiObjectType_Certificate = 0,
 588  pkiObjectType_CRL = 1,
 589  pkiObjectType_PrivateKey = 2,
 590  pkiObjectType_PublicKey = 3
 591} pkiObjectType;
 592
 593/* Each object is defined by a set of items that uniquely identify it.
 594 * Here are the uid sets:
 595 *
 596 * NSSCertificate ==>  { issuer, serial }
 597 * NSSPrivateKey
 598 *         (RSA) ==> { modulus, public exponent }
 599 *
 600 */
 601#define MAX_ITEMS_FOR_UID 2
 602
 603/* pkiObjectCollectionNode
 604 *
 605 * A node in the collection is the set of unique identifiers for a single
 606 * object, along with either the actual object or a proto-object.
 607 */
 608typedef struct
 609{
 610  PRCList link;
 611  PRBool haveObject;
 612  nssPKIObject *object;
 613  NSSItem uid[MAX_ITEMS_FOR_UID];
 614} 
 615pkiObjectCollectionNode;
 616
 617/* nssPKIObjectCollection
 618 *
 619 * The collection is the set of all objects, plus the interfaces needed
 620 * to manage the objects.
 621 *
 622 */
 623struct nssPKIObjectCollectionStr
 624{
 625  NSSArena *arena;
 626  NSSTrustDomain *td;
 627  NSSCryptoContext *cc;
 628  PRCList head; /* list of pkiObjectCollectionNode's */
 629  PRUint32 size;
 630  pkiObjectType objectType;
 631  void           (*      destroyObject)(nssPKIObject *o);
 632  PRStatus       (*   getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
 633  PRStatus       (* getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, 
 634                                        NSSArena *arena);
 635  nssPKIObject * (*       createObject)(nssPKIObject *o);
 636  nssPKILockType lockType; /* type of lock to use for new proto-objects */
 637};
 638
 639static nssPKIObjectCollection *
 640nssPKIObjectCollection_Create (
 641  NSSTrustDomain *td,
 642  NSSCryptoContext *ccOpt,
 643  nssPKILockType lockType
 644)
 645{
 646    NSSArena *arena;
 647    nssPKIObjectCollection *rvCollection = NULL;
 648    arena = nssArena_Create();
 649    if (!arena) {
 650	return (nssPKIObjectCollection *)NULL;
 651    }
 652    rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
 653    if (!rvCollection) {
 654	goto loser;
 655    }
 656    PR_INIT_CLIST(&rvCollection->head);
 657    rvCollection->arena = arena;
 658    rvCollection->td = td; /* XXX */
 659    rvCollection->cc = ccOpt;
 660    rvCollection->lockType = lockType;
 661    return rvCollection;
 662loser:
 663    nssArena_Destroy(arena);
 664    return (nssPKIObjectCollection *)NULL;
 665}
 666
 667NSS_IMPLEMENT void
 668nssPKIObjectCollection_Destroy (
 669  nssPKIObjectCollection *collection
 670)
 671{
 672    if (collection) {
 673	PRCList *link;
 674	pkiObjectCollectionNode *node;
 675	/* first destroy any objects in the collection */
 676	link = PR_NEXT_LINK(&collection->head);
 677	while (link != &collection->head) {
 678	    node = (pkiObjectCollectionNode *)link;
 679	    if (node->haveObject) {
 680		(*collection->destroyObject)(node->object);
 681	    } else {
 682		nssPKIObject_Destroy(node->object);
 683	    }
 684	    link = PR_NEXT_LINK(link);
 685	}
 686	/* then destroy it */
 687	nssArena_Destroy(collection->arena);
 688    }
 689}
 690
 691NSS_IMPLEMENT PRUint32
 692nssPKIObjectCollection_Count (
 693  nssPKIObjectCollection *collection
 694)
 695{
 696    return collection->size;
 697}
 698
 699NSS_IMPLEMENT PRStatus
 700nssPKIObjectCollection_AddObject (
 701  nssPKIObjectCollection *collection,
 702  nssPKIObject *object
 703)
 704{
 705    pkiObjectCollectionNode *node;
 706    node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
 707    if (!node) {
 708	return PR_FAILURE;
 709    }
 710    node->haveObject = PR_TRUE;
 711    node->object = nssPKIObject_AddRef(object);
 712    (*collection->getUIDFromObject)(object, node->uid);
 713    PR_INIT_CLIST(&node->link);
 714    PR_INSERT_BEFORE(&node->link, &collection->head);
 715    collection->size++;
 716    return PR_SUCCESS;
 717}
 718
 719static pkiObjectCollectionNode *
 720find_instance_in_collection (
 721  nssPKIObjectCollection *collection,
 722  nssCryptokiObject *instance
 723)
 724{
 725    PRCList *link;
 726    pkiObjectCollectionNode *node;
 727    link = PR_NEXT_LINK(&collection->head);
 728    while (link != &collection->head) {
 729	node = (pkiObjectCollectionNode *)link;
 730	if (nssPKIObject_HasInstance(node->object, instance)) {
 731	    return node;
 732	}
 733	link = PR_NEXT_LINK(link);
 734    }
 735    return (pkiObjectCollectionNode *)NULL;
 736}
 737
 738static pkiObjectCollectionNode *
 739find_object_in_collection (
 740  nssPKIObjectCollection *collection,
 741  NSSItem *uid
 742)
 743{
 744    PRUint32 i;
 745    PRStatus status;
 746    PRCList *link;
 747    pkiObjectCollectionNode *node;
 748    link = PR_NEXT_LINK(&collection->head);
 749    while (link != &collection->head) {
 750	node = (pkiObjectCollectionNode *)link;
 751	for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
 752	    if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
 753		break;
 754	    }
 755	}
 756	if (i == MAX_ITEMS_FOR_UID) {
 757	    return node;
 758	}
 759	link = PR_NEXT_LINK(link);
 760    }
 761    return (pkiObjectCollectionNode *)NULL;
 762}
 763
 764static pkiObjectCollectionNode *
 765add_object_instance (
 766  nssPKIObjectCollection *collection,
 767  nssCryptokiObject *instance,
 768  PRBool *foundIt
 769)
 770{
 771    PRUint32 i;
 772    PRStatus status;
 773    pkiObjectCollectionNode *node;
 774    nssArenaMark *mark = NULL;
 775    NSSItem uid[MAX_ITEMS_FOR_UID];
 776    nsslibc_memset(uid, 0, sizeof uid);
 777    /* The list is traversed twice, first (here) looking to match the
 778     * { token, handle } tuple, and if that is not found, below a search
 779     * for unique identifier is done.  Here, a match means this exact object
 780     * instance is already in the collection, and we have nothing to do.
 781     */
 782    *foundIt = PR_FALSE;
 783    node = find_instance_in_collection(collection, instance);
 784    if (node) {
 785	/* The collection is assumed to take over the instance.  Since we
 786	 * are not using it, it must be destroyed.
 787	 */
 788	nssCryptokiObject_Destroy(instance);
 789	*foundIt = PR_TRUE;
 790	return node;
 791    }
 792    mark = nssArena_Mark(collection