/* 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; } if (cert_template[0].ulValueLen == 0 || !cert_template[0].pValue) { nss_ZFreeIf(cert_template[1].pValue); return (nssCryptokiObject *)NULL; } object = nss_ZNEW(NULL, nssCryptokiObject); if (!object) { nss_ZFreeIf(cert_template[0].pValue); nss_ZFreeIf(cert_template[1].pValue); return (nssCryptokiObject *)NULL; } object->handle = h; object->token = nssToken_AddRef(t); isTokenObject = (CK_BBOOL *)cert_template[0].pValue; object->isTokenObject = *isTokenObject; nss_ZFreeIf(cert_template[0].pValue); NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label); return object; } NSS_IMPLEMENT void nssCryptokiObject_Destroy( nssCryptokiObject *object) { if (object) { (void)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++) { (void)nssToken_Destroy(*tokenp); } nss_ZFreeIf(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_NSS_TRUST: haveIt = cache->doObjectType[cachedTrust]; break; case CKO_NSS_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. */ (void)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_NSS_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_NSS_KRL, CKA_NSS_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) { nssCryptokiObjectArray_Destroy(objects); 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++) { /* Any token references that were removed in successful loop iterations * need to be restored before we call nssCryptokiObjectArray_Destroy */ 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_NSS_TRUST: objectType = cachedTrust; break; case CKO_NSS_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_NSS_TRUST: objectType = cachedTrust; break; case CKO_NSS_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_NSS_TRUST: objectType = cachedTrust; break; case CKO_NSS_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; }