diff nss/lib/pki/pkibase.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/pki/pkibase.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,1254 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#include "pki3hack.h"
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+NSS_IMPLEMENT void
+nssPKIObject_Lock(nssPKIObject * object)
+{
+    switch (object->lockType) {
+    case nssPKIMonitor:
+        PZ_EnterMonitor(object->sync.mlock);
+        break;
+    case nssPKILock:
+        PZ_Lock(object->sync.lock);
+        break;
+    default:
+        PORT_Assert(0);
+    }
+}
+
+NSS_IMPLEMENT void
+nssPKIObject_Unlock(nssPKIObject * object)
+{
+    switch (object->lockType) {
+    case nssPKIMonitor:
+        PZ_ExitMonitor(object->sync.mlock);
+        break;
+    case nssPKILock:
+        PZ_Unlock(object->sync.lock);
+        break;
+    default:
+        PORT_Assert(0);
+    }
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_NewLock(nssPKIObject * object, nssPKILockType lockType)
+{
+    object->lockType = lockType;
+    switch (lockType) {
+    case nssPKIMonitor:
+        object->sync.mlock = PZ_NewMonitor(nssILockSSL);
+        return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
+    case nssPKILock:
+        object->sync.lock = PZ_NewLock(nssILockSSL);
+        return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
+    default:
+        PORT_Assert(0);
+        return PR_FAILURE;
+    }
+}
+
+NSS_IMPLEMENT void
+nssPKIObject_DestroyLock(nssPKIObject * object)
+{
+    switch (object->lockType) {
+    case nssPKIMonitor:
+        PZ_DestroyMonitor(object->sync.mlock);
+        object->sync.mlock = NULL;
+        break;
+    case nssPKILock:
+        PZ_DestroyLock(object->sync.lock);
+        object->sync.lock = NULL;
+        break;
+    default:
+        PORT_Assert(0);
+    }
+}
+
+
+
+NSS_IMPLEMENT nssPKIObject *
+nssPKIObject_Create (
+  NSSArena *arenaOpt,
+  nssCryptokiObject *instanceOpt,
+  NSSTrustDomain *td,
+  NSSCryptoContext *cc,
+  nssPKILockType lockType
+)
+{
+    NSSArena *arena;
+    nssArenaMark *mark = NULL;
+    nssPKIObject *object;
+    if (arenaOpt) {
+	arena = arenaOpt;
+	mark = nssArena_Mark(arena);
+    } else {
+	arena = nssArena_Create();
+	if (!arena) {
+	    return (nssPKIObject *)NULL;
+	}
+    }
+    object = nss_ZNEW(arena, nssPKIObject);
+    if (!object) {
+	goto loser;
+    }
+    object->arena = arena;
+    object->trustDomain = td; /* XXX */
+    object->cryptoContext = cc;
+    if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
+	goto loser;
+    }
+    if (instanceOpt) {
+	if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
+	    goto loser;
+	}
+    }
+    PR_ATOMIC_INCREMENT(&object->refCount);
+    if (mark) {
+	nssArena_Unmark(arena, mark);
+    }
+    return object;
+loser:
+    if (mark) {
+	nssArena_Release(arena, mark);
+    } else {
+	nssArena_Destroy(arena);
+    }
+    return (nssPKIObject *)NULL;
+}
+
+NSS_IMPLEMENT PRBool
+nssPKIObject_Destroy (
+  nssPKIObject *object
+)
+{
+    PRUint32 i;
+    PR_ASSERT(object->refCount > 0);
+    if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) {
+	for (i=0; i<object->numInstances; i++) {
+	    nssCryptokiObject_Destroy(object->instances[i]);
+	}
+	nssPKIObject_DestroyLock(object);
+	nssArena_Destroy(object->arena);
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+NSS_IMPLEMENT nssPKIObject *
+nssPKIObject_AddRef (
+  nssPKIObject *object
+)
+{
+    PR_ATOMIC_INCREMENT(&object->refCount);
+    return object;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_AddInstance (
+  nssPKIObject *object,
+  nssCryptokiObject *instance
+)
+{
+    nssCryptokiObject **newInstances = NULL;
+
+    nssPKIObject_Lock(object);
+    if (object->numInstances == 0) {
+	newInstances = nss_ZNEWARRAY(object->arena,
+				     nssCryptokiObject *,
+				     object->numInstances + 1);
+    } else {
+	PRBool found = PR_FALSE;
+	PRUint32 i;
+	for (i=0; i<object->numInstances; i++) {
+	    if (nssCryptokiObject_Equal(object->instances[i], instance)) {
+		found = PR_TRUE;
+		break;
+	    }
+	}
+	if (found) {
+	    /* The new instance is identical to one in the array, except
+	     * perhaps that the label may be different.  So replace 
+	     * the label in the array instance with the label from the 
+	     * new instance, and discard the new instance.
+	     */
+	    nss_ZFreeIf(object->instances[i]->label);
+	    object->instances[i]->label = instance->label;
+	    nssPKIObject_Unlock(object);
+	    instance->label = NULL;
+	    nssCryptokiObject_Destroy(instance);
+	    return PR_SUCCESS;
+	}
+	newInstances = nss_ZREALLOCARRAY(object->instances,
+					 nssCryptokiObject *,
+					 object->numInstances + 1);
+    }
+    if (newInstances) {
+	object->instances = newInstances;
+	newInstances[object->numInstances++] = instance;
+    }
+    nssPKIObject_Unlock(object);
+    return (newInstances ? PR_SUCCESS : PR_FAILURE);
+}
+
+NSS_IMPLEMENT PRBool
+nssPKIObject_HasInstance (
+  nssPKIObject *object,
+  nssCryptokiObject *instance
+)
+{
+    PRUint32 i;
+    PRBool hasIt = PR_FALSE;;
+    nssPKIObject_Lock(object);
+    for (i=0; i<object->numInstances; i++) {
+	if (nssCryptokiObject_Equal(object->instances[i], instance)) {
+	    hasIt = PR_TRUE;
+	    break;
+	}
+    }
+    nssPKIObject_Unlock(object);
+    return hasIt;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_RemoveInstanceForToken (
+  nssPKIObject *object,
+  NSSToken *token
+)
+{
+    PRUint32 i;
+    nssCryptokiObject *instanceToRemove = NULL;
+    nssPKIObject_Lock(object);
+    if (object->numInstances == 0) {
+	nssPKIObject_Unlock(object);
+	return PR_SUCCESS;
+    }
+    for (i=0; i<object->numInstances; i++) {
+	if (object->instances[i]->token == token) {
+	    instanceToRemove = object->instances[i];
+	    object->instances[i] = object->instances[object->numInstances-1];
+	    object->instances[object->numInstances-1] = NULL;
+	    break;
+	}
+    }
+    if (--object->numInstances > 0) {
+	nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,
+	                                      nssCryptokiObject *,
+	                                      object->numInstances);
+	if (instances) {
+	    object->instances = instances;
+	}
+    } else {
+	nss_ZFreeIf(object->instances);
+    }
+    nssCryptokiObject_Destroy(instanceToRemove);
+    nssPKIObject_Unlock(object);
+    return PR_SUCCESS;
+}
+
+/* this needs more thought on what will happen when there are multiple
+ * instances
+ */
+NSS_IMPLEMENT PRStatus
+nssPKIObject_DeleteStoredObject (
+  nssPKIObject *object,
+  NSSCallback *uhh,
+  PRBool isFriendly
+)
+{
+    PRUint32 i, numNotDestroyed;
+    PRStatus status = PR_SUCCESS;
+    numNotDestroyed = 0;
+    nssPKIObject_Lock(object);
+    for (i=0; i<object->numInstances; i++) {
+	nssCryptokiObject *instance = object->instances[i];
+	status = nssToken_DeleteStoredObject(instance);
+	object->instances[i] = NULL;
+	if (status == PR_SUCCESS) {
+	    nssCryptokiObject_Destroy(instance);
+	} else {
+	    object->instances[numNotDestroyed++] = instance;
+	}
+    }
+    if (numNotDestroyed == 0) {
+	nss_ZFreeIf(object->instances);
+	object->numInstances = 0;
+    } else {
+	object->numInstances = numNotDestroyed;
+    }
+    nssPKIObject_Unlock(object);
+    return status;
+}
+
+NSS_IMPLEMENT NSSToken **
+nssPKIObject_GetTokens (
+  nssPKIObject *object,
+  PRStatus *statusOpt
+)
+{
+    NSSToken **tokens = NULL;
+    nssPKIObject_Lock(object);
+    if (object->numInstances > 0) {
+	tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1);
+	if (tokens) {
+	    PRUint32 i;
+	    for (i=0; i<object->numInstances; i++) {
+		tokens[i] = nssToken_AddRef(object->instances[i]->token);
+	    }
+	}
+    }
+    nssPKIObject_Unlock(object);
+    if (statusOpt) *statusOpt = PR_SUCCESS; /* until more logic here */
+    return tokens;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+nssPKIObject_GetNicknameForToken (
+  nssPKIObject *object,
+  NSSToken *tokenOpt
+)
+{
+    PRUint32 i;
+    NSSUTF8 *nickname = NULL;
+    nssPKIObject_Lock(object);
+    for (i=0; i<object->numInstances; i++) {
+	if ((!tokenOpt && object->instances[i]->label) ||
+	    (object->instances[i]->token == tokenOpt)) 
+	{
+            /* Must copy, see bug 745548 */
+	    nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL);
+	    break;
+	}
+    }
+    nssPKIObject_Unlock(object);
+    return nickname;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssPKIObject_GetInstances (
+  nssPKIObject *object
+)
+{
+    nssCryptokiObject **instances = NULL;
+    PRUint32 i;
+    if (object->numInstances == 0) {
+	return (nssCryptokiObject **)NULL;
+    }
+    nssPKIObject_Lock(object);
+    instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, 
+                              object->numInstances + 1);
+    if (instances) {
+	for (i=0; i<object->numInstances; i++) {
+	    instances[i] = nssCryptokiObject_Clone(object->instances[i]);
+	}
+    }
+    nssPKIObject_Unlock(object);
+    return instances;
+}
+
+NSS_IMPLEMENT void
+nssCertificateArray_Destroy (
+  NSSCertificate **certs
+)
+{
+    if (certs) {
+	NSSCertificate **certp;
+	for (certp = certs; *certp; certp++) {
+	    if ((*certp)->decoding) {
+		CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
+		if (cc) {
+		    CERT_DestroyCertificate(cc);
+		}
+		continue;
+	    }
+	    nssCertificate_Destroy(*certp);
+	}
+	nss_ZFreeIf(certs);
+    }
+}
+
+NSS_IMPLEMENT void
+NSSCertificateArray_Destroy (
+  NSSCertificate **certs
+)
+{
+    nssCertificateArray_Destroy(certs);
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssCertificateArray_Join (
+  NSSCertificate **certs1,
+  NSSCertificate **certs2
+)
+{
+    if (certs1 && certs2) {
+	NSSCertificate **certs, **cp;
+	PRUint32 count = 0;
+	PRUint32 count1 = 0;
+	cp = certs1;
+	while (*cp++) count1++;
+	count = count1;
+	cp = certs2;
+	while (*cp++) count++;
+	certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
+	if (!certs) {
+	    nss_ZFreeIf(certs1);
+	    nss_ZFreeIf(certs2);
+	    return (NSSCertificate **)NULL;
+	}
+	for (cp = certs2; *cp; cp++, count1++) {
+	    certs[count1] = *cp;
+	}
+	nss_ZFreeIf(certs2);
+	return certs;
+    } else if (certs1) {
+	return certs1;
+    } else {
+	return certs2;
+    }
+}
+
+NSS_IMPLEMENT NSSCertificate * 
+nssCertificateArray_FindBestCertificate (
+  NSSCertificate **certs, 
+  NSSTime *timeOpt,
+  const NSSUsage *usage,
+  NSSPolicies *policiesOpt
+)
+{
+    NSSCertificate *bestCert = NULL;
+    nssDecodedCert *bestdc = NULL;
+    NSSTime *time, sTime;
+    PRBool bestCertMatches = PR_FALSE;
+    PRBool thisCertMatches;
+    PRBool bestCertIsValidAtTime = PR_FALSE;
+    PRBool bestCertIsTrusted = PR_FALSE;
+
+    if (timeOpt) {
+	time = timeOpt;
+    } else {
+	NSSTime_Now(&sTime);
+	time = &sTime;
+    }
+    if (!certs) {
+	return (NSSCertificate *)NULL;
+    }
+    for (; *certs; certs++) {
+	nssDecodedCert *dc;
+	NSSCertificate *c = *certs;
+	dc = nssCertificate_GetDecoding(c);
+	if (!dc) continue;
+	thisCertMatches = dc->matchUsage(dc, usage);
+	if (!bestCert) {
+	    /* always take the first cert, but remember whether or not
+	     * the usage matched 
+	     */
+	    bestCert = nssCertificate_AddRef(c);
+	    bestCertMatches = thisCertMatches;
+	    bestdc = dc;
+	    continue;
+	} else {
+	    if (bestCertMatches && !thisCertMatches) {
+		/* if already have a cert for this usage, and if this cert 
+		 * doesn't have the correct usage, continue
+		 */
+		continue;
+	    } else if (!bestCertMatches && thisCertMatches) {
+		/* this one does match usage, replace the other */
+		nssCertificate_Destroy(bestCert);
+		bestCert = nssCertificate_AddRef(c);
+		bestCertMatches = thisCertMatches;
+		bestdc = dc;
+		continue;
+	    }
+	    /* this cert match as well as any cert we've found so far, 
+	     * defer to time/policies 
+	     * */
+	}
+	/* time */
+	if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) {
+	    /* The current best cert is valid at time */
+	    bestCertIsValidAtTime = PR_TRUE;
+	    if (!dc->isValidAtTime(dc, time)) {
+		/* If the new cert isn't valid at time, it's not better */
+		continue;
+	    }
+	} else {
+	    /* The current best cert is not valid at time */
+	    if (dc->isValidAtTime(dc, time)) {
+		/* If the new cert is valid at time, it's better */
+		nssCertificate_Destroy(bestCert);
+		bestCert = nssCertificate_AddRef(c);
+		bestdc = dc;
+		bestCertIsValidAtTime = PR_TRUE;
+		continue;
+	    }
+	}
+	/* Either they are both valid at time, or neither valid.
+	 * If only one is trusted for this usage, take it.
+	 */
+	if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) {
+	    bestCertIsTrusted = PR_TRUE;
+	    if (!dc->isTrustedForUsage(dc, usage)) {
+	        continue;
+	    }
+	} else {
+	    /* The current best cert is not trusted */
+	    if (dc->isTrustedForUsage(dc, usage)) {
+		/* If the new cert is trusted, it's better */
+		nssCertificate_Destroy(bestCert);
+		bestCert = nssCertificate_AddRef(c);
+		bestdc = dc;
+		bestCertIsTrusted = PR_TRUE;
+	        continue;
+	    }
+	}
+	/* Otherwise, take the newer one. */
+	if (!bestdc->isNewerThan(bestdc, dc)) {
+	    nssCertificate_Destroy(bestCert);
+	    bestCert = nssCertificate_AddRef(c);
+	    bestdc = dc;
+	    continue;
+	}
+	/* policies */
+	/* XXX later -- defer to policies */
+    }
+    return bestCert;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCertificateArray_Traverse (
+  NSSCertificate **certs,
+  PRStatus (* callback)(NSSCertificate *c, void *arg),
+  void *arg
+)
+{
+    PRStatus status = PR_SUCCESS;
+    if (certs) {
+	NSSCertificate **certp;
+	for (certp = certs; *certp; certp++) {
+	    status = (*callback)(*certp, arg);
+	    if (status != PR_SUCCESS) {
+		break;
+	    }
+	}
+    }
+    return status;
+}
+
+
+NSS_IMPLEMENT void
+nssCRLArray_Destroy (
+  NSSCRL **crls
+)
+{
+    if (crls) {
+	NSSCRL **crlp;
+	for (crlp = crls; *crlp; crlp++) {
+	    nssCRL_Destroy(*crlp);
+	}
+	nss_ZFreeIf(crls);
+    }
+}
+
+/*
+ * Object collections
+ */
+
+typedef enum
+{
+  pkiObjectType_Certificate = 0,
+  pkiObjectType_CRL = 1,
+  pkiObjectType_PrivateKey = 2,
+  pkiObjectType_PublicKey = 3
+} pkiObjectType;
+
+/* Each object is defined by a set of items that uniquely identify it.
+ * Here are the uid sets:
+ *
+ * NSSCertificate ==>  { issuer, serial }
+ * NSSPrivateKey
+ *         (RSA) ==> { modulus, public exponent }
+ *
+ */
+#define MAX_ITEMS_FOR_UID 2
+
+/* pkiObjectCollectionNode
+ *
+ * A node in the collection is the set of unique identifiers for a single
+ * object, along with either the actual object or a proto-object.
+ */
+typedef struct
+{
+  PRCList link;
+  PRBool haveObject;
+  nssPKIObject *object;
+  NSSItem uid[MAX_ITEMS_FOR_UID];
+} 
+pkiObjectCollectionNode;
+
+/* nssPKIObjectCollection
+ *
+ * The collection is the set of all objects, plus the interfaces needed
+ * to manage the objects.
+ *
+ */
+struct nssPKIObjectCollectionStr
+{
+  NSSArena *arena;
+  NSSTrustDomain *td;
+  NSSCryptoContext *cc;
+  PRCList head; /* list of pkiObjectCollectionNode's */
+  PRUint32 size;
+  pkiObjectType objectType;
+  void           (*      destroyObject)(nssPKIObject *o);
+  PRStatus       (*   getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
+  PRStatus       (* getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, 
+                                        NSSArena *arena);
+  nssPKIObject * (*       createObject)(nssPKIObject *o);
+  nssPKILockType lockType; /* type of lock to use for new proto-objects */
+};
+
+static nssPKIObjectCollection *
+nssPKIObjectCollection_Create (
+  NSSTrustDomain *td,
+  NSSCryptoContext *ccOpt,
+  nssPKILockType lockType
+)
+{
+    NSSArena *arena;
+    nssPKIObjectCollection *rvCollection = NULL;
+    arena = nssArena_Create();
+    if (!arena) {
+	return (nssPKIObjectCollection *)NULL;
+    }
+    rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
+    if (!rvCollection) {
+	goto loser;
+    }
+    PR_INIT_CLIST(&rvCollection->head);
+    rvCollection->arena = arena;
+    rvCollection->td = td; /* XXX */
+    rvCollection->cc = ccOpt;
+    rvCollection->lockType = lockType;
+    return rvCollection;
+loser:
+    nssArena_Destroy(arena);
+    return (nssPKIObjectCollection *)NULL;
+}
+
+NSS_IMPLEMENT void
+nssPKIObjectCollection_Destroy (
+  nssPKIObjectCollection *collection
+)
+{
+    if (collection) {
+	PRCList *link;
+	pkiObjectCollectionNode *node;
+	/* first destroy any objects in the collection */
+	link = PR_NEXT_LINK(&collection->head);
+	while (link != &collection->head) {
+	    node = (pkiObjectCollectionNode *)link;
+	    if (node->haveObject) {
+		(*collection->destroyObject)(node->object);
+	    } else {
+		nssPKIObject_Destroy(node->object);
+	    }
+	    link = PR_NEXT_LINK(link);
+	}
+	/* then destroy it */
+	nssArena_Destroy(collection->arena);
+    }
+}
+
+NSS_IMPLEMENT PRUint32
+nssPKIObjectCollection_Count (
+  nssPKIObjectCollection *collection
+)
+{
+    return collection->size;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddObject (
+  nssPKIObjectCollection *collection,
+  nssPKIObject *object
+)
+{
+    pkiObjectCollectionNode *node;
+    node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
+    if (!node) {
+	return PR_FAILURE;
+    }
+    node->haveObject = PR_TRUE;
+    node->object = nssPKIObject_AddRef(object);
+    (*collection->getUIDFromObject)(object, node->uid);
+    PR_INIT_CLIST(&node->link);
+    PR_INSERT_BEFORE(&node->link, &collection->head);
+    collection->size++;
+    return PR_SUCCESS;
+}
+
+static pkiObjectCollectionNode *
+find_instance_in_collection (
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject *instance
+)
+{
+    PRCList *link;
+    pkiObjectCollectionNode *node;
+    link = PR_NEXT_LINK(&collection->head);
+    while (link != &collection->head) {
+	node = (pkiObjectCollectionNode *)link;
+	if (nssPKIObject_HasInstance(node->object, instance)) {
+	    return node;
+	}
+	link = PR_NEXT_LINK(link);
+    }
+    return (pkiObjectCollectionNode *)NULL;
+}
+
+static pkiObjectCollectionNode *
+find_object_in_collection (
+  nssPKIObjectCollection *collection,
+  NSSItem *uid
+)
+{
+    PRUint32 i;
+    PRStatus status;
+    PRCList *link;
+    pkiObjectCollectionNode *node;
+    link = PR_NEXT_LINK(&collection->head);
+    while (link != &collection->head) {
+	node = (pkiObjectCollectionNode *)link;
+	for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
+	    if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
+		break;
+	    }
+	}
+	if (i == MAX_ITEMS_FOR_UID) {
+	    return node;
+	}
+	link = PR_NEXT_LINK(link);
+    }
+    return (pkiObjectCollectionNode *)NULL;
+}
+
+static pkiObjectCollectionNode *
+add_object_instance (
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject *instance,
+  PRBool *foundIt
+)
+{
+    PRUint32 i;
+    PRStatus status;
+    pkiObjectCollectionNode *node;
+    nssArenaMark *mark = NULL;
+    NSSItem uid[MAX_ITEMS_FOR_UID];
+    nsslibc_memset(uid, 0, sizeof uid);
+    /* The list is traversed twice, first (here) looking to match the
+     * { token, handle } tuple, and if that is not found, below a search
+     * for unique identifier is done.  Here, a match means this exact object
+     * instance is already in the collection, and we have nothing to do.
+     */
+    *foundIt = PR_FALSE;
+    node = find_instance_in_collection(collection, instance);
+    if (node) {
+	/* The collection is assumed to take over the instance.  Since we
+	 * are not using it, it must be destroyed.
+	 */
+	nssCryptokiObject_Destroy(instance);
+	*foundIt = PR_TRUE;
+	return node;
+    }
+    mark = nssArena_Mark(collection->arena);
+    if (!mark) {
+	goto loser;
+    }
+    status = (*collection->getUIDFromInstance)(instance, uid, 
+                                               collection->arena);
+    if (status != PR_SUCCESS) {
+	goto loser;
+    }
+    /* Search for unique identifier.  A match here means the object exists 
+     * in the collection, but does not have this instance, so the instance 
+     * needs to be added.
+     */
+    node = find_object_in_collection(collection, uid);
+    if (node) {
+	/* This is an object with multiple instances */
+	status = nssPKIObject_AddInstance(node->object, instance);
+    } else {
+	/* This is a completely new object.  Create a node for it. */
+	node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
+	if (!node) {
+	    goto loser;
+	}
+	node->object = nssPKIObject_Create(NULL, instance, 
+	                                   collection->td, collection->cc,
+                                           collection->lockType);
+	if (!node->object) {
+	    goto loser;
+	}
+	for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
+	    node->uid[i] = uid[i];
+	}
+	node->haveObject = PR_FALSE;
+	PR_INIT_CLIST(&node->link);
+	PR_INSERT_BEFORE(&node->link, &collection->head);
+	collection->size++;
+	status = PR_SUCCESS;
+    }
+    nssArena_Unmark(collection->arena, mark);
+    return node;
+loser:
+    if (mark) {
+	nssArena_Release(collection->arena, mark);
+    }
+    nssCryptokiObject_Destroy(instance);
+    return (pkiObjectCollectionNode *)NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddInstances (
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject **instances,
+  PRUint32 numInstances
+)
+{
+    PRStatus status = PR_SUCCESS;
+    PRUint32 i = 0;
+    PRBool foundIt;
+    pkiObjectCollectionNode *node;
+    if (instances) {
+	while ((!numInstances || i < numInstances) && *instances) {
+	    if (status == PR_SUCCESS) {
+		node = add_object_instance(collection, *instances, &foundIt);
+		if (node == NULL) {
+		    /* add_object_instance freed the current instance */
+		    /* free the remaining instances */
+		    status = PR_FAILURE;
+		}
+	    } else {
+		nssCryptokiObject_Destroy(*instances);
+	    }
+	    instances++;
+	    i++;
+	}
+    }
+    return status;
+}
+
+static void
+nssPKIObjectCollection_RemoveNode (
+   nssPKIObjectCollection *collection,
+   pkiObjectCollectionNode *node
+)
+{
+    PR_REMOVE_LINK(&node->link); 
+    collection->size--;
+}
+
+static PRStatus
+nssPKIObjectCollection_GetObjects (
+  nssPKIObjectCollection *collection,
+  nssPKIObject **rvObjects,
+  PRUint32 rvSize
+)
+{
+    PRUint32 i = 0;
+    PRCList *link = PR_NEXT_LINK(&collection->head);
+    pkiObjectCollectionNode *node;
+    int error=0;
+    while ((i < rvSize) && (link != &collection->head)) {
+	node = (pkiObjectCollectionNode *)link;
+	if (!node->haveObject) {
+	    /* Convert the proto-object to an object */
+	    node->object = (*collection->createObject)(node->object);
+	    if (!node->object) {
+		link = PR_NEXT_LINK(link);
+		/*remove bogus object from list*/
+		nssPKIObjectCollection_RemoveNode(collection,node);
+		error++;
+		continue;
+	    }
+	    node->haveObject = PR_TRUE;
+	}
+	rvObjects[i++] = nssPKIObject_AddRef(node->object);
+	link = PR_NEXT_LINK(link);
+    }
+    if (!error && *rvObjects == NULL) {
+	nss_SetError(NSS_ERROR_NOT_FOUND);
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_Traverse (
+  nssPKIObjectCollection *collection,
+  nssPKIObjectCallback *callback
+)
+{
+    PRStatus status;
+    PRCList *link = PR_NEXT_LINK(&collection->head);
+    pkiObjectCollectionNode *node;
+    while (link != &collection->head) {
+	node = (pkiObjectCollectionNode *)link;
+	if (!node->haveObject) {
+	    node->object = (*collection->createObject)(node->object);
+	    if (!node->object) {
+		link = PR_NEXT_LINK(link);
+		/*remove bogus object from list*/
+		nssPKIObjectCollection_RemoveNode(collection,node);
+		continue;
+	    }
+	    node->haveObject = PR_TRUE;
+	}
+	switch (collection->objectType) {
+	case pkiObjectType_Certificate: 
+	    status = (*callback->func.cert)((NSSCertificate *)node->object, 
+	                                    callback->arg);
+	    break;
+	case pkiObjectType_CRL: 
+	    status = (*callback->func.crl)((NSSCRL *)node->object, 
+	                                   callback->arg);
+	    break;
+	case pkiObjectType_PrivateKey: 
+	    status = (*callback->func.pvkey)((NSSPrivateKey *)node->object, 
+	                                     callback->arg);
+	    break;
+	case pkiObjectType_PublicKey: 
+	    status = (*callback->func.pbkey)((NSSPublicKey *)node->object, 
+	                                     callback->arg);
+	    break;
+	}
+	link = PR_NEXT_LINK(link);
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddInstanceAsObject (
+  nssPKIObjectCollection *collection,
+  nssCryptokiObject *instance
+)
+{
+    pkiObjectCollectionNode *node;
+    PRBool foundIt;
+    node = add_object_instance(collection, instance, &foundIt);
+    if (node == NULL) {
+	return PR_FAILURE;
+    }
+    if (!node->haveObject) {
+	node->object = (*collection->createObject)(node->object);
+	if (!node->object) {
+	    /*remove bogus object from list*/
+	    nssPKIObjectCollection_RemoveNode(collection,node);
+	    return PR_FAILURE;
+	}
+	node->haveObject = PR_TRUE;
+    } else if (!foundIt) {
+	/* The instance was added to a pre-existing node.  This
+	 * function is *only* being used for certificates, and having
+	 * multiple instances of certs in 3.X requires updating the
+	 * CERTCertificate.
+	 * But only do it if it was a new instance!!!  If the same instance
+	 * is encountered, we set *foundIt to true.  Detect that here and
+	 * ignore it.
+	 */
+	STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
+    }
+    return PR_SUCCESS;
+}
+
+/*
+ * Certificate collections
+ */
+
+static void
+cert_destroyObject(nssPKIObject *o)
+{
+    NSSCertificate *c = (NSSCertificate *)o;
+    if (c->decoding) {
+	CERTCertificate *cc = STAN_GetCERTCertificate(c);
+	if (cc) {
+	    CERT_DestroyCertificate(cc);
+	    return;
+	} /* else destroy it as NSSCertificate below */
+    }
+    nssCertificate_Destroy(c);
+}
+
+static PRStatus
+cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
+{
+    NSSCertificate *c = (NSSCertificate *)o;
+    /* The builtins are still returning decoded serial numbers.  Until
+     * this compatibility issue is resolved, use the full DER of the
+     * cert to uniquely identify it.
+     */
+    NSSDER *derCert;
+    derCert = nssCertificate_GetEncoding(c);
+    uid[0].data = NULL; uid[0].size = 0;
+    uid[1].data = NULL; uid[1].size = 0;
+    if (derCert != NULL) {
+	uid[0] = *derCert;
+    }
+    return PR_SUCCESS;
+}
+
+static PRStatus
+cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
+                        NSSArena *arena)
+{
+    /* The builtins are still returning decoded serial numbers.  Until
+     * this compatibility issue is resolved, use the full DER of the
+     * cert to uniquely identify it.
+     */
+    uid[1].data = NULL; uid[1].size = 0;
+    return nssCryptokiCertificate_GetAttributes(instance,
+                                                NULL,  /* XXX sessionOpt */
+                                                arena, /* arena    */
+                                                NULL,  /* type     */
+                                                NULL,  /* id       */
+                                                &uid[0], /* encoding */
+                                                NULL,  /* issuer   */
+                                                NULL,  /* serial   */
+                                                NULL);  /* subject  */
+}
+
+static nssPKIObject *
+cert_createObject(nssPKIObject *o)
+{
+    NSSCertificate *cert;
+    cert = nssCertificate_Create(o);
+/*    if (STAN_GetCERTCertificate(cert) == NULL) {
+	nssCertificate_Destroy(cert);
+	return (nssPKIObject *)NULL;
+    } */
+    /* In 3.4, have to maintain uniqueness of cert pointers by caching all
+     * certs.  Cache the cert here, before returning.  If it is already
+     * cached, take the cached entry.
+     */
+    {
+	NSSTrustDomain *td = o->trustDomain;
+	nssTrustDomain_AddCertsToCache(td, &cert, 1);
+    }
+    return (nssPKIObject *)cert;
+}
+
+NSS_IMPLEMENT nssPKIObjectCollection *
+nssCertificateCollection_Create (
+  NSSTrustDomain *td,
+  NSSCertificate **certsOpt
+)
+{
+    PRStatus status;
+    nssPKIObjectCollection *collection;
+    collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
+    collection->objectType = pkiObjectType_Certificate;
+    collection->destroyObject = cert_destroyObject;
+    collection->getUIDFromObject = cert_getUIDFromObject;
+    collection->getUIDFromInstance = cert_getUIDFromInstance;
+    collection->createObject = cert_createObject;
+    if (certsOpt) {
+	for (; *certsOpt; certsOpt++) {
+	    nssPKIObject *object = (nssPKIObject *)(*certsOpt);
+	    status = nssPKIObjectCollection_AddObject(collection, object);
+	}
+    }
+    return collection;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssPKIObjectCollection_GetCertificates (
+  nssPKIObjectCollection *collection,
+  NSSCertificate **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    PRStatus status;
+    PRUint32 rvSize;
+    PRBool allocated = PR_FALSE;
+    if (collection->size == 0) {
+	return (NSSCertificate **)NULL;
+    }
+    if (maximumOpt == 0) {
+	rvSize = collection->size;
+    } else {
+	rvSize = PR_MIN(collection->size, maximumOpt);
+    }
+    if (!rvOpt) {
+	rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1);
+	if (!rvOpt) {
+	    return (NSSCertificate **)NULL;
+	}
+	allocated = PR_TRUE;
+    }
+    status = nssPKIObjectCollection_GetObjects(collection, 
+                                               (nssPKIObject **)rvOpt, 
+                                               rvSize);
+    if (status != PR_SUCCESS) {
+	if (allocated) {
+	    nss_ZFreeIf(rvOpt);
+	}
+	return (NSSCertificate **)NULL;
+    }
+    return rvOpt;
+}
+
+/*
+ * CRL/KRL collections
+ */
+
+static void
+crl_destroyObject(nssPKIObject *o)
+{
+    NSSCRL *crl = (NSSCRL *)o;
+    nssCRL_Destroy(crl);
+}
+
+static PRStatus
+crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
+{
+    NSSCRL *crl = (NSSCRL *)o;
+    NSSDER *encoding;
+    encoding = nssCRL_GetEncoding(crl);
+    if (!encoding) {
+        nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+        return PR_FALSE;
+    }
+    uid[0] = *encoding;
+    uid[1].data = NULL; uid[1].size = 0;
+    return PR_SUCCESS;
+}
+
+static PRStatus
+crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
+                       NSSArena *arena)
+{
+    return nssCryptokiCRL_GetAttributes(instance,
+                                        NULL,    /* XXX sessionOpt */
+                                        arena,   /* arena    */
+                                        &uid[0], /* encoding */
+                                        NULL,    /* subject  */
+                                        NULL,    /* class    */
+                                        NULL,    /* url      */
+                                        NULL);   /* isKRL    */
+}
+
+static nssPKIObject *
+crl_createObject(nssPKIObject *o)
+{
+    return (nssPKIObject *)nssCRL_Create(o);
+}
+
+NSS_IMPLEMENT nssPKIObjectCollection *
+nssCRLCollection_Create (
+  NSSTrustDomain *td,
+  NSSCRL **crlsOpt
+)
+{
+    PRStatus status;
+    nssPKIObjectCollection *collection;
+    collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
+    collection->objectType = pkiObjectType_CRL;
+    collection->destroyObject = crl_destroyObject;
+    collection->getUIDFromObject = crl_getUIDFromObject;
+    collection->getUIDFromInstance = crl_getUIDFromInstance;
+    collection->createObject = crl_createObject;
+    if (crlsOpt) {
+	for (; *crlsOpt; crlsOpt++) {
+	    nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
+	    status = nssPKIObjectCollection_AddObject(collection, object);
+	}
+    }
+    return collection;
+}
+
+NSS_IMPLEMENT NSSCRL **
+nssPKIObjectCollection_GetCRLs (
+  nssPKIObjectCollection *collection,
+  NSSCRL **rvOpt,
+  PRUint32 maximumOpt,
+  NSSArena *arenaOpt
+)
+{
+    PRStatus status;
+    PRUint32 rvSize;
+    PRBool allocated = PR_FALSE;
+    if (collection->size == 0) {
+	return (NSSCRL **)NULL;
+    }
+    if (maximumOpt == 0) {
+	rvSize = collection->size;
+    } else {
+	rvSize = PR_MIN(collection->size, maximumOpt);
+    }
+    if (!rvOpt) {
+	rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1);
+	if (!rvOpt) {
+	    return (NSSCRL **)NULL;
+	}
+	allocated = PR_TRUE;
+    }
+    status = nssPKIObjectCollection_GetObjects(collection, 
+                                               (nssPKIObject **)rvOpt, 
+                                               rvSize);
+    if (status != PR_SUCCESS) {
+	if (allocated) {
+	    nss_ZFreeIf(rvOpt);
+	}
+	return (NSSCRL **)NULL;
+    }
+    return rvOpt;
+}
+
+/* how bad would it be to have a static now sitting around, updated whenever
+ * this was called?  would avoid repeated allocs...
+ */
+NSS_IMPLEMENT NSSTime *
+NSSTime_Now (
+  NSSTime *timeOpt
+)
+{
+    return NSSTime_SetPRTime(timeOpt, PR_Now());
+}
+
+NSS_IMPLEMENT NSSTime *
+NSSTime_SetPRTime (
+  NSSTime *timeOpt,
+  PRTime prTime
+)
+{
+    NSSTime *rvTime;
+    rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime);
+    if (rvTime) {
+        rvTime->prTime = prTime;
+    }
+    return rvTime;
+}
+
+NSS_IMPLEMENT PRTime
+NSSTime_GetPRTime (
+  NSSTime *time
+)
+{
+  return time->prTime;
+}
+
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)