diff nss/lib/dev/devutil.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/dev/devutil.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,1006 @@
+/* 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 DEVM_H
+#include "devm.h"
+#endif /* DEVM_H */
+
+#ifndef CKHELPER_H
+#include "ckhelper.h"
+#endif /* CKHELPER_H */
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssCryptokiObject_Create (
+  NSSToken *t, 
+  nssSession *session,
+  CK_OBJECT_HANDLE h
+)
+{
+    PRStatus status;
+    NSSSlot *slot;
+    nssCryptokiObject *object;
+    CK_BBOOL *isTokenObject;
+    CK_ATTRIBUTE cert_template[] = {
+	{ CKA_TOKEN, NULL, 0 },
+	{ CKA_LABEL, NULL, 0 }
+    };
+    slot = nssToken_GetSlot(t);
+    status = nssCKObject_GetAttributes(h, cert_template, 2,
+                                       NULL, session, slot);
+    nssSlot_Destroy(slot);
+    if (status != PR_SUCCESS) {
+	/* a failure here indicates a device error */
+	return (nssCryptokiObject *)NULL;
+    }
+    object = nss_ZNEW(NULL, nssCryptokiObject);
+    if (!object) {
+	return (nssCryptokiObject *)NULL;
+    }
+    object->handle = h;
+    object->token = nssToken_AddRef(t);
+    isTokenObject = (CK_BBOOL *)cert_template[0].pValue;
+    object->isTokenObject = *isTokenObject;
+    nss_ZFreeIf(isTokenObject);
+    NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label);
+    return object;
+}
+
+NSS_IMPLEMENT void
+nssCryptokiObject_Destroy (
+  nssCryptokiObject *object
+)
+{
+    if (object) {
+	nssToken_Destroy(object->token);
+	nss_ZFreeIf(object->label);
+	nss_ZFreeIf(object);
+    }
+}
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssCryptokiObject_Clone (
+  nssCryptokiObject *object
+)
+{
+    nssCryptokiObject *rvObject;
+    rvObject = nss_ZNEW(NULL, nssCryptokiObject);
+    if (rvObject) {
+	rvObject->handle = object->handle;
+	rvObject->token = nssToken_AddRef(object->token);
+	rvObject->isTokenObject = object->isTokenObject;
+	if (object->label) {
+	    rvObject->label = nssUTF8_Duplicate(object->label, NULL);
+	}
+    }
+    return rvObject;
+}
+
+NSS_EXTERN PRBool
+nssCryptokiObject_Equal (
+  nssCryptokiObject *o1,
+  nssCryptokiObject *o2
+)
+{
+    return (o1->token == o2->token && o1->handle == o2->handle);
+}
+
+NSS_IMPLEMENT PRUint32
+nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen)
+{
+    PRInt32 i;
+    for (i = bufLen - 1; i>=0; ) {
+	if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') break;
+	--i;
+    }
+    return (PRUint32)(i + 1);
+}
+
+/*
+ * Slot arrays
+ */
+
+NSS_IMPLEMENT NSSSlot **
+nssSlotArray_Clone (
+  NSSSlot **slots
+)
+{
+    NSSSlot **rvSlots = NULL;
+    NSSSlot **sp = slots;
+    PRUint32 count = 0;
+    while (sp && *sp) count++;
+    if (count > 0) {
+	rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
+	if (rvSlots) {
+	    for (sp = slots, count = 0; *sp; sp++) {
+		rvSlots[count++] = nssSlot_AddRef(*sp);
+	    }
+	}
+    }
+    return rvSlots;
+}
+
+NSS_IMPLEMENT void
+nssSlotArray_Destroy (
+  NSSSlot **slots
+)
+{
+    if (slots) {
+	NSSSlot **slotp;
+	for (slotp = slots; *slotp; slotp++) {
+	    nssSlot_Destroy(*slotp);
+	}
+	nss_ZFreeIf(slots);
+    }
+}
+
+NSS_IMPLEMENT void
+NSSSlotArray_Destroy (
+  NSSSlot **slots
+)
+{
+    nssSlotArray_Destroy(slots);
+}
+
+NSS_IMPLEMENT void
+nssTokenArray_Destroy (
+  NSSToken **tokens
+)
+{
+    if (tokens) {
+	NSSToken **tokenp;
+	for (tokenp = tokens; *tokenp; tokenp++) {
+	    nssToken_Destroy(*tokenp);
+	}
+	nss_ZFreeIf(tokens);
+    }
+}
+
+NSS_IMPLEMENT void
+NSSTokenArray_Destroy (
+  NSSToken **tokens
+)
+{
+    nssTokenArray_Destroy(tokens);
+}
+
+NSS_IMPLEMENT void
+nssCryptokiObjectArray_Destroy (
+  nssCryptokiObject **objects
+)
+{
+    if (objects) {
+	nssCryptokiObject **op;
+	for (op = objects; *op; op++) {
+	    nssCryptokiObject_Destroy(*op);
+	}
+	nss_ZFreeIf(objects);
+    }
+}
+
+/* object cache for token */
+
+typedef struct
+{
+  NSSArena *arena;
+  nssCryptokiObject *object;
+  CK_ATTRIBUTE_PTR attributes;
+  CK_ULONG numAttributes;
+}
+nssCryptokiObjectAndAttributes;
+
+enum {
+  cachedCerts = 0,
+  cachedTrust = 1,
+  cachedCRLs = 2
+} cachedObjectType;
+
+struct nssTokenObjectCacheStr
+{
+  NSSToken *token;
+  PZLock *lock;
+  PRBool loggedIn;
+  PRBool doObjectType[3];
+  PRBool searchedObjectType[3];
+  nssCryptokiObjectAndAttributes **objects[3];
+};
+
+NSS_IMPLEMENT nssTokenObjectCache *
+nssTokenObjectCache_Create (
+  NSSToken *token,
+  PRBool cacheCerts,
+  PRBool cacheTrust,
+  PRBool cacheCRLs
+)
+{
+    nssTokenObjectCache *rvCache;
+    rvCache = nss_ZNEW(NULL, nssTokenObjectCache);
+    if (!rvCache) {
+	goto loser;
+    }
+    rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */
+    if (!rvCache->lock) {
+	goto loser;
+    }
+    rvCache->doObjectType[cachedCerts] = cacheCerts;
+    rvCache->doObjectType[cachedTrust] = cacheTrust;
+    rvCache->doObjectType[cachedCRLs] = cacheCRLs;
+    rvCache->token = token; /* cache goes away with token */
+    return rvCache;
+loser:
+    nssTokenObjectCache_Destroy(rvCache);
+    return (nssTokenObjectCache *)NULL;
+}
+
+static void
+clear_cache (
+  nssTokenObjectCache *cache
+)
+{
+    nssCryptokiObjectAndAttributes **oa;
+    PRUint32 objectType;
+    for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) {
+	cache->searchedObjectType[objectType] = PR_FALSE;
+	if (!cache->objects[objectType]) {
+	    continue;
+	}
+	for (oa = cache->objects[objectType]; *oa; oa++) {
+	    /* prevent the token from being destroyed */
+	    (*oa)->object->token = NULL;
+	    nssCryptokiObject_Destroy((*oa)->object);
+	    nssArena_Destroy((*oa)->arena);
+	}
+	nss_ZFreeIf(cache->objects[objectType]);
+	cache->objects[objectType] = NULL;
+    }
+}
+
+NSS_IMPLEMENT void
+nssTokenObjectCache_Clear (
+  nssTokenObjectCache *cache
+)
+{
+    if (cache) {
+	PZ_Lock(cache->lock);
+	clear_cache(cache);
+	PZ_Unlock(cache->lock);
+    }
+}
+
+NSS_IMPLEMENT void
+nssTokenObjectCache_Destroy (
+  nssTokenObjectCache *cache
+)
+{
+    if (cache) {
+	clear_cache(cache);
+	if (cache->lock) {
+	    PZ_DestroyLock(cache->lock);
+	}
+	nss_ZFreeIf(cache);
+    }
+}
+
+NSS_IMPLEMENT PRBool
+nssTokenObjectCache_HaveObjectClass (
+  nssTokenObjectCache *cache,
+  CK_OBJECT_CLASS objclass
+)
+{
+    PRBool haveIt;
+    PZ_Lock(cache->lock);
+    switch (objclass) {
+    case CKO_CERTIFICATE:    haveIt = cache->doObjectType[cachedCerts]; break;
+    case CKO_NETSCAPE_TRUST: haveIt = cache->doObjectType[cachedTrust]; break;
+    case CKO_NETSCAPE_CRL:   haveIt = cache->doObjectType[cachedCRLs];  break;
+    default:                 haveIt = PR_FALSE;
+    }
+    PZ_Unlock(cache->lock);
+    return haveIt;
+}
+
+static nssCryptokiObjectAndAttributes **
+create_object_array (
+  nssCryptokiObject **objects,
+  PRBool *doObjects,
+  PRUint32 *numObjects,
+  PRStatus *status
+)
+{
+    nssCryptokiObjectAndAttributes **rvOandA = NULL;
+    *numObjects = 0;
+    /* There are no objects for this type */
+    if (!objects || !*objects) {
+	*status = PR_SUCCESS;
+	return rvOandA;
+    }
+    while (*objects++) (*numObjects)++;
+    if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) {
+	/* Hit the maximum allowed, so don't use a cache (there are
+	 * too many objects to make caching worthwhile, presumably, if
+	 * the token can handle that many objects, it can handle searching.
+	 */
+	*doObjects = PR_FALSE;
+	*status = PR_FAILURE;
+	*numObjects = 0;
+    } else {
+	rvOandA = nss_ZNEWARRAY(NULL, 
+	                        nssCryptokiObjectAndAttributes *, 
+	                        *numObjects + 1);
+	*status = rvOandA ? PR_SUCCESS : PR_FAILURE;
+    }
+    return rvOandA;
+}
+
+static nssCryptokiObjectAndAttributes *
+create_object (
+  nssCryptokiObject *object,
+  const CK_ATTRIBUTE_TYPE *types,
+  PRUint32 numTypes,
+  PRStatus *status
+)
+{
+    PRUint32 j;
+    NSSArena *arena = NULL;
+    NSSSlot *slot = NULL;
+    nssSession *session = NULL;
+    nssCryptokiObjectAndAttributes *rvCachedObject = NULL;
+
+    slot = nssToken_GetSlot(object->token);
+    if (!slot) {
+        nss_SetError(NSS_ERROR_INVALID_POINTER);
+        goto loser;
+    }
+    session = nssToken_GetDefaultSession(object->token);
+    if (!session) {
+        nss_SetError(NSS_ERROR_INVALID_POINTER);
+        goto loser;
+    }
+    arena = nssArena_Create();
+    if (!arena) {
+	goto loser;
+    }
+    rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes);
+    if (!rvCachedObject) {
+	goto loser;
+    }
+    rvCachedObject->arena = arena;
+    /* The cache is tied to the token, and therefore the objects
+     * in it should not hold references to the token.
+     */
+    nssToken_Destroy(object->token);
+    rvCachedObject->object = object;
+    rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
+    if (!rvCachedObject->attributes) {
+	goto loser;
+    }
+    for (j=0; j<numTypes; j++) {
+	rvCachedObject->attributes[j].type = types[j];
+    }
+    *status = nssCKObject_GetAttributes(object->handle,
+                                        rvCachedObject->attributes,
+                                        numTypes,
+                                        arena,
+                                        session,
+                                        slot);
+    if (*status != PR_SUCCESS) {
+	goto loser;
+    }
+    rvCachedObject->numAttributes = numTypes;
+    *status = PR_SUCCESS;
+    nssSlot_Destroy(slot);
+
+    return rvCachedObject;
+loser:
+    *status = PR_FAILURE;
+    if (slot) {
+	nssSlot_Destroy(slot);
+    }
+    if (arena)
+	nssArena_Destroy(arena);
+    return (nssCryptokiObjectAndAttributes *)NULL;
+}
+
+/*
+ *
+ * State diagram for cache:
+ *
+ *            token !present            token removed
+ *        +-------------------------+<----------------------+
+ *        |                         ^                       |
+ *        v                         |                       |
+ *  +----------+   slot friendly    |  token present   +----------+ 
+ *  |   cache  | -----------------> % ---------------> |   cache  |
+ *  | unloaded |                                       |  loaded  |
+ *  +----------+                                       +----------+
+ *    ^   |                                                 ^   |
+ *    |   |   slot !friendly           slot logged in       |   |
+ *    |   +-----------------------> % ----------------------+   |
+ *    |                             |                           |
+ *    | slot logged out             v  slot !friendly           |
+ *    +-----------------------------+<--------------------------+
+ *
+ */
+
+/* This function must not be called with cache->lock locked. */
+static PRBool
+token_is_present (
+  nssTokenObjectCache *cache
+)
+{
+    NSSSlot *slot = nssToken_GetSlot(cache->token);
+    PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
+    nssSlot_Destroy(slot);
+    return tokenPresent;
+}
+
+static PRBool
+search_for_objects (
+  nssTokenObjectCache *cache
+)
+{
+    PRBool doSearch = PR_FALSE;
+    NSSSlot *slot = nssToken_GetSlot(cache->token);
+    /* Handle non-friendly slots (slots which require login for objects) */
+    if (!nssSlot_IsFriendly(slot)) {
+	if (nssSlot_IsLoggedIn(slot)) {
+	    /* Either no state change, or went from !logged in -> logged in */
+	    cache->loggedIn = PR_TRUE;
+	    doSearch = PR_TRUE;
+	} else {
+	    if (cache->loggedIn) {
+		/* went from logged in -> !logged in, destroy cached objects */
+		clear_cache(cache);
+		cache->loggedIn = PR_FALSE;
+	    } /* else no state change, still not logged in, so exit */
+	}
+    } else {
+	/* slot is friendly, thus always available for search */
+	doSearch = PR_TRUE;
+    }
+    nssSlot_Destroy(slot);
+    return doSearch;
+}
+
+static nssCryptokiObjectAndAttributes *
+create_cert (
+  nssCryptokiObject *object,
+  PRStatus *status
+)
+{
+    static const CK_ATTRIBUTE_TYPE certAttr[] = {
+	CKA_CLASS,
+	CKA_TOKEN,
+	CKA_LABEL,
+	CKA_CERTIFICATE_TYPE,
+	CKA_ID,
+	CKA_VALUE,
+	CKA_ISSUER,
+	CKA_SERIAL_NUMBER,
+	CKA_SUBJECT,
+	CKA_NETSCAPE_EMAIL
+    };
+    static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
+    return create_object(object, certAttr, numCertAttr, status);
+}
+
+static nssCryptokiObjectAndAttributes *
+create_trust (
+  nssCryptokiObject *object,
+  PRStatus *status
+)
+{
+    static const CK_ATTRIBUTE_TYPE trustAttr[] = {
+	CKA_CLASS,
+	CKA_TOKEN,
+	CKA_LABEL,
+	CKA_CERT_SHA1_HASH,
+	CKA_CERT_MD5_HASH,
+	CKA_ISSUER,
+	CKA_SUBJECT,
+	CKA_TRUST_SERVER_AUTH,
+	CKA_TRUST_CLIENT_AUTH,
+	CKA_TRUST_EMAIL_PROTECTION,
+	CKA_TRUST_CODE_SIGNING
+    };
+    static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]);
+    return create_object(object, trustAttr, numTrustAttr, status);
+}
+
+static nssCryptokiObjectAndAttributes *
+create_crl (
+  nssCryptokiObject *object,
+  PRStatus *status
+)
+{
+    static const CK_ATTRIBUTE_TYPE crlAttr[] = {
+	CKA_CLASS,
+	CKA_TOKEN,
+	CKA_LABEL,
+	CKA_VALUE,
+	CKA_SUBJECT,
+	CKA_NETSCAPE_KRL,
+	CKA_NETSCAPE_URL
+    };
+    static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
+    return create_object(object, crlAttr, numCRLAttr, status);
+}
+
+/* Dispatch to the create function for the object type */
+static nssCryptokiObjectAndAttributes *
+create_object_of_type (
+  nssCryptokiObject *object,
+  PRUint32 objectType,
+  PRStatus *status
+)
+{
+    if (objectType == cachedCerts) {
+	return create_cert(object, status);
+    }
+    if (objectType == cachedTrust) {
+	return create_trust(object, status);
+    }
+    if (objectType == cachedCRLs) {
+	return create_crl(object, status);
+    }
+    return (nssCryptokiObjectAndAttributes *)NULL;
+}
+
+static PRStatus
+get_token_objects_for_cache (
+  nssTokenObjectCache *cache,
+  PRUint32 objectType,
+  CK_OBJECT_CLASS objclass
+)
+{
+    PRStatus status;
+    nssCryptokiObject **objects;
+    PRBool *doIt = &cache->doObjectType[objectType];
+    PRUint32 i, numObjects;
+
+    if (!search_for_objects(cache) || 
+         cache->searchedObjectType[objectType] || 
+        !cache->doObjectType[objectType]) 
+    {
+	/* Either there was a state change that prevents a search
+	 * (token logged out), or the search was already done,
+	 * or objects of this type are not being cached.
+	 */
+	return PR_SUCCESS;
+    }
+    objects = nssToken_FindObjects(cache->token, NULL, objclass,
+                                   nssTokenSearchType_TokenForced,
+                                   MAX_LOCAL_CACHE_OBJECTS, &status);
+    if (status != PR_SUCCESS) {
+	return status;
+    }
+    cache->objects[objectType] = create_object_array(objects,
+                                                     doIt,
+                                                     &numObjects,
+                                                     &status);
+    if (status != PR_SUCCESS) {
+	return status;
+    }
+    for (i=0; i<numObjects; i++) {
+	cache->objects[objectType][i] = create_object_of_type(objects[i],
+	                                                      objectType,
+	                                                      &status);
+	if (status != PR_SUCCESS) {
+	    break;
+	}
+    }
+    if (status == PR_SUCCESS) {
+	nss_ZFreeIf(objects);
+    } else {
+	PRUint32 j;
+	for (j=0; j<i; j++) {
+	    /* sigh */
+	    nssToken_AddRef(cache->objects[objectType][j]->object->token);
+	    nssArena_Destroy(cache->objects[objectType][j]->arena);
+	}
+	nss_ZFreeIf(cache->objects[objectType]);
+	cache->objects[objectType] = NULL;
+	nssCryptokiObjectArray_Destroy(objects);
+    }
+    cache->searchedObjectType[objectType] = PR_TRUE;
+    return status;
+}
+
+static CK_ATTRIBUTE_PTR
+find_attribute_in_object (
+  nssCryptokiObjectAndAttributes *obj,
+  CK_ATTRIBUTE_TYPE attrType
+)
+{
+    PRUint32 j;
+    for (j=0; j<obj->numAttributes; j++) {
+	if (attrType == obj->attributes[j].type) {
+	    return &obj->attributes[j];
+	}
+    }
+    return (CK_ATTRIBUTE_PTR)NULL;
+}
+
+/* Find all objects in the array that match the supplied template */
+static nssCryptokiObject **
+find_objects_in_array (
+  nssCryptokiObjectAndAttributes **objArray,
+  CK_ATTRIBUTE_PTR ot,
+  CK_ULONG otlen,
+  PRUint32 maximumOpt
+)
+{
+    PRIntn oi = 0;
+    PRUint32 i;
+    NSSArena *arena;
+    PRUint32 size = 8;
+    PRUint32 numMatches = 0;
+    nssCryptokiObject **objects = NULL;
+    nssCryptokiObjectAndAttributes **matches = NULL;
+    CK_ATTRIBUTE_PTR attr;
+
+    if (!objArray) {
+	return (nssCryptokiObject **)NULL;
+    }
+    arena = nssArena_Create();
+    if (!arena) {
+	return (nssCryptokiObject **)NULL;
+    }
+    matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
+    if (!matches) {
+	goto loser;
+    }
+    if (maximumOpt == 0) maximumOpt = ~0;
+    /* loop over the cached objects */
+    for (; *objArray && numMatches < maximumOpt; objArray++) {
+	nssCryptokiObjectAndAttributes *obj = *objArray;
+	/* loop over the test template */
+	for (i=0; i<otlen; i++) {
+	    /* see if the object has the attribute */
+	    attr = find_attribute_in_object(obj, ot[i].type);
+	    if (!attr) {
+		/* nope, match failed */
+		break;
+	    }
+	    /* compare the attribute against the test value */
+	    if (ot[i].ulValueLen != attr->ulValueLen ||
+	        !nsslibc_memequal(ot[i].pValue, 
+	                          attr->pValue,
+	                          attr->ulValueLen, NULL))
+	    {
+		/* nope, match failed */
+		break;
+	    }
+	}
+	if (i == otlen) {
+	    /* all of the attributes in the test template were found
+	     * in the object's template, and they all matched
+	     */
+	    matches[numMatches++] = obj;
+	    if (numMatches == size) {
+		size *= 2;
+		matches = nss_ZREALLOCARRAY(matches, 
+		                            nssCryptokiObjectAndAttributes *, 
+		                            size);
+		if (!matches) {
+		    goto loser;
+		}
+	    }
+	}
+    }
+    if (numMatches > 0) {
+	objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
+	if (!objects) {
+	    goto loser;
+	}
+	for (oi=0; oi<(PRIntn)numMatches; oi++) {
+	    objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
+	    if (!objects[oi]) {
+		goto loser;
+	    }
+	}
+    }
+    nssArena_Destroy(arena);
+    return objects;
+loser:
+    nssCryptokiObjectArray_Destroy(objects);
+    nssArena_Destroy(arena);
+    return (nssCryptokiObject **)NULL;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssTokenObjectCache_FindObjectsByTemplate (
+  nssTokenObjectCache *cache,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR otemplate,
+  CK_ULONG otlen,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    PRStatus status = PR_FAILURE;
+    nssCryptokiObject **rvObjects = NULL;
+    PRUint32 objectType;
+    if (!token_is_present(cache)) {
+	status = PR_SUCCESS;
+	goto finish;
+    }
+    switch (objclass) {
+    case CKO_CERTIFICATE:    objectType = cachedCerts; break;
+    case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
+    case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
+    default: goto finish;
+    }
+    PZ_Lock(cache->lock);
+    if (cache->doObjectType[objectType]) {
+	status = get_token_objects_for_cache(cache, objectType, objclass);
+	if (status == PR_SUCCESS) {
+	    rvObjects = find_objects_in_array(cache->objects[objectType], 
+	                                      otemplate, otlen, maximumOpt);
+	}
+    }
+    PZ_Unlock(cache->lock);
+finish:
+    if (statusOpt) {
+	*statusOpt = status;
+    }
+    return rvObjects;
+}
+
+static PRBool
+cache_available_for_object_type (
+  nssTokenObjectCache *cache,
+  PRUint32 objectType
+)
+{
+    if (!cache->doObjectType[objectType]) {
+	/* not caching this object kind */
+	return PR_FALSE;
+    }
+    if (!cache->searchedObjectType[objectType]) {
+	/* objects are not cached yet */
+	return PR_FALSE;
+    }
+    if (!search_for_objects(cache)) {
+	/* not logged in */
+	return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTokenObjectCache_GetObjectAttributes (
+  nssTokenObjectCache *cache,
+  NSSArena *arenaOpt,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR atemplate,
+  CK_ULONG atlen
+)
+{
+    PRUint32 i, j;
+    NSSArena *arena = NULL;
+    nssArenaMark *mark = NULL;
+    nssCryptokiObjectAndAttributes *cachedOA = NULL;
+    nssCryptokiObjectAndAttributes **oa = NULL;
+    PRUint32 objectType;
+    if (!token_is_present(cache)) {
+	return PR_FAILURE;
+    }
+    PZ_Lock(cache->lock);
+    switch (objclass) {
+    case CKO_CERTIFICATE:    objectType = cachedCerts; break;
+    case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
+    case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
+    default: goto loser;
+    }
+    if (!cache_available_for_object_type(cache, objectType)) {
+	goto loser;
+    }
+    oa = cache->objects[objectType];
+    if (!oa) {
+	goto loser;
+    }
+    for (; *oa; oa++) {
+	if (nssCryptokiObject_Equal((*oa)->object, object)) {
+	    cachedOA = *oa;
+	    break;
+	}
+    }
+    if (!cachedOA) {
+	goto loser; /* don't have this object */
+    }
+    if (arenaOpt) {
+	arena = arenaOpt;
+	mark = nssArena_Mark(arena);
+    }
+    for (i=0; i<atlen; i++) {
+	for (j=0; j<cachedOA->numAttributes; j++) {
+	    if (atemplate[i].type == cachedOA->attributes[j].type) {
+		CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
+		if (cachedOA->attributes[j].ulValueLen == 0 ||
+		    cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) 
+		{
+		    break; /* invalid attribute */
+		}
+		if (atemplate[i].ulValueLen > 0) {
+		    if (atemplate[i].pValue == NULL ||
+		        atemplate[i].ulValueLen < attr->ulValueLen) 
+		    {
+			goto loser;
+		    }
+		} else {
+		    atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
+		    if (!atemplate[i].pValue) {
+			goto loser;
+		    }
+		}
+		nsslibc_memcpy(atemplate[i].pValue,
+		               attr->pValue, attr->ulValueLen);
+		atemplate[i].ulValueLen = attr->ulValueLen;
+		break;
+	    }
+	}
+	if (j == cachedOA->numAttributes) {
+	    atemplate[i].ulValueLen = (CK_ULONG)-1;
+	}
+    }
+    PZ_Unlock(cache->lock);
+    if (mark) {
+	nssArena_Unmark(arena, mark);
+    }
+    return PR_SUCCESS;
+loser:
+    PZ_Unlock(cache->lock);
+    if (mark) {
+	nssArena_Release(arena, mark);
+    }
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTokenObjectCache_ImportObject (
+  nssTokenObjectCache *cache,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR ot,
+  CK_ULONG otlen
+)
+{
+    PRStatus status = PR_SUCCESS;
+    PRUint32 count;
+    nssCryptokiObjectAndAttributes **oa, ***otype;
+    PRUint32 objectType;
+    PRBool haveIt = PR_FALSE;
+
+    if (!token_is_present(cache)) {
+	return PR_SUCCESS; /* cache not active, ignored */
+    }
+    PZ_Lock(cache->lock);
+    switch (objclass) {
+    case CKO_CERTIFICATE:    objectType = cachedCerts; break;
+    case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
+    case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
+    default:
+	PZ_Unlock(cache->lock);
+	return PR_SUCCESS; /* don't need to import it here */
+    }
+    if (!cache_available_for_object_type(cache, objectType)) {
+	PZ_Unlock(cache->lock);
+	return PR_SUCCESS; /* cache not active, ignored */
+    }
+    count = 0;
+    otype = &cache->objects[objectType]; /* index into array of types */
+    oa = *otype; /* the array of objects for this type */
+    while (oa && *oa) {
+	if (nssCryptokiObject_Equal((*oa)->object, object)) {
+	    haveIt = PR_TRUE;
+	    break;
+	}
+	count++;
+	oa++;
+    }
+    if (haveIt) {
+	/* Destroy the old entry */
+	(*oa)->object->token = NULL;
+	nssCryptokiObject_Destroy((*oa)->object);
+	nssArena_Destroy((*oa)->arena);
+    } else {
+	/* Create space for a new entry */
+	if (count > 0) {
+	    *otype = nss_ZREALLOCARRAY(*otype,
+	                               nssCryptokiObjectAndAttributes *, 
+	                               count + 2);
+	} else {
+	    *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
+	}
+    }
+    if (*otype) {
+	nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
+	(*otype)[count] = create_object_of_type(copyObject, objectType,
+	                                        &status);
+    } else {
+	status = PR_FAILURE;
+    }
+    PZ_Unlock(cache->lock);
+    return status;
+}
+
+NSS_IMPLEMENT void
+nssTokenObjectCache_RemoveObject (
+  nssTokenObjectCache *cache,
+  nssCryptokiObject *object
+)
+{
+    PRUint32 oType;
+    nssCryptokiObjectAndAttributes **oa, **swp = NULL;
+    if (!token_is_present(cache)) {
+	return;
+    }
+    PZ_Lock(cache->lock);
+    for (oType=0; oType<3; oType++) {
+	if (!cache_available_for_object_type(cache, oType) ||
+	    !cache->objects[oType])
+	{
+	    continue;
+	}
+	for (oa = cache->objects[oType]; *oa; oa++) {
+	    if (nssCryptokiObject_Equal((*oa)->object, object)) {
+		swp = oa; /* the entry to remove */
+		while (oa[1]) oa++; /* go to the tail */
+		(*swp)->object->token = NULL;
+		nssCryptokiObject_Destroy((*swp)->object);
+		nssArena_Destroy((*swp)->arena); /* destroy it */
+		*swp = *oa; /* swap the last with the removed */
+		*oa = NULL; /* null-terminate the array */
+		break;
+	    }
+	}
+	if (swp) {
+	    break;
+	}
+    }
+    if ((oType <3) &&
+		cache->objects[oType] && cache->objects[oType][0] == NULL) {
+	nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
+	cache->objects[oType] = NULL;
+    }
+    PZ_Unlock(cache->lock);
+}
+
+/* These two hash algorithms are presently sufficient.
+** They are used for fingerprints of certs which are stored as the 
+** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
+** We don't need to add SHAxxx to these now.
+*/
+/* XXX of course this doesn't belong here */
+NSS_IMPLEMENT NSSAlgorithmAndParameters *
+NSSAlgorithmAndParameters_CreateSHA1Digest (
+  NSSArena *arenaOpt
+)
+{
+    NSSAlgorithmAndParameters *rvAP = NULL;
+    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
+    if (rvAP) {
+	rvAP->mechanism.mechanism = CKM_SHA_1;
+	rvAP->mechanism.pParameter = NULL;
+	rvAP->mechanism.ulParameterLen = 0;
+    }
+    return rvAP;
+}
+
+NSS_IMPLEMENT NSSAlgorithmAndParameters *
+NSSAlgorithmAndParameters_CreateMD5Digest (
+  NSSArena *arenaOpt
+)
+{
+    NSSAlgorithmAndParameters *rvAP = NULL;
+    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
+    if (rvAP) {
+	rvAP->mechanism.mechanism = CKM_MD5;
+	rvAP->mechanism.pParameter = NULL;
+	rvAP->mechanism.ulParameterLen = 0;
+    }
+    return rvAP;
+}
+
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)