security/nss/lib/pki/pkibase.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial