/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1994-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifdef DEBUG static const char CVS_ID[] = "@(#) $RCSfile: devutil.c,v $ $Revision: 1.29 $ $Date: 2007/11/16 05:29:25 $"; #endif /* DEBUG */ #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) { sp = slots; count = 0; for (sp = slots; *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: 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); 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; 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); 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; jattributes[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 PRStatus get_token_certs_for_cache ( nssTokenObjectCache *cache ) { PRStatus status; nssCryptokiObject **objects; PRBool *doIt = &cache->doObjectType[cachedCerts]; PRUint32 i, numObjects; if (!search_for_objects(cache) || cache->searchedObjectType[cachedCerts] || !cache->doObjectType[cachedCerts]) { /* Either there was a state change that prevents a search * (token logged out), or the search was already done, * or certs are not being cached. */ return PR_SUCCESS; } objects = nssToken_FindCertificates(cache->token, NULL, nssTokenSearchType_TokenForced, MAX_LOCAL_CACHE_OBJECTS, &status); if (status != PR_SUCCESS) { return status; } cache->objects[cachedCerts] = create_object_array(objects, doIt, &numObjects, &status); if (status != PR_SUCCESS) { return status; } for (i=0; iobjects[cachedCerts][i] = create_cert(objects[i], &status); if (status != PR_SUCCESS) { break; } } if (status == PR_SUCCESS) { nss_ZFreeIf(objects); } else { PRUint32 j; for (j=0; jobjects[cachedCerts][j]->object->token); nssArena_Destroy(cache->objects[cachedCerts][j]->arena); } nssCryptokiObjectArray_Destroy(objects); } cache->searchedObjectType[cachedCerts] = PR_TRUE; return 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 PRStatus get_token_trust_for_cache ( nssTokenObjectCache *cache ) { PRStatus status; nssCryptokiObject **objects; PRBool *doIt = &cache->doObjectType[cachedTrust]; PRUint32 i, numObjects; if (!search_for_objects(cache) || cache->searchedObjectType[cachedTrust] || !cache->doObjectType[cachedTrust]) { /* Either there was a state change that prevents a search * (token logged out), or the search was already done, * or trust is not being cached. */ return PR_SUCCESS; } objects = nssToken_FindTrustObjects(cache->token, NULL, nssTokenSearchType_TokenForced, MAX_LOCAL_CACHE_OBJECTS, &status); if (status != PR_SUCCESS) { return status; } cache->objects[cachedTrust] = create_object_array(objects, doIt, &numObjects, &status); if (status != PR_SUCCESS) { return status; } for (i=0; iobjects[cachedTrust][i] = create_trust(objects[i], &status); if (status != PR_SUCCESS) { break; } } if (status == PR_SUCCESS) { nss_ZFreeIf(objects); } else { PRUint32 j; for (j=0; jobjects[cachedTrust][j]->object->token); nssArena_Destroy(cache->objects[cachedTrust][j]->arena); } nssCryptokiObjectArray_Destroy(objects); } cache->searchedObjectType[cachedTrust] = PR_TRUE; return 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); } static PRStatus get_token_crls_for_cache ( nssTokenObjectCache *cache ) { PRStatus status; nssCryptokiObject **objects; PRBool *doIt = &cache->doObjectType[cachedCRLs]; PRUint32 i, numObjects; if (!search_for_objects(cache) || cache->searchedObjectType[cachedCRLs] || !cache->doObjectType[cachedCRLs]) { /* Either there was a state change that prevents a search * (token logged out), or the search was already done, * or CRLs are not being cached. */ return PR_SUCCESS; } objects = nssToken_FindCRLs(cache->token, NULL, nssTokenSearchType_TokenForced, MAX_LOCAL_CACHE_OBJECTS, &status); if (status != PR_SUCCESS) { return status; } cache->objects[cachedCRLs] = create_object_array(objects, doIt, &numObjects, &status); if (status != PR_SUCCESS) { return status; } for (i=0; iobjects[cachedCRLs][i] = create_crl(objects[i], &status); if (status != PR_SUCCESS) { break; } } if (status == PR_SUCCESS) { nss_ZFreeIf(objects); } else { PRUint32 j; for (j=0; jobjects[cachedCRLs][j]->object->token); nssArena_Destroy(cache->objects[cachedCRLs][j]->arena); } nssCryptokiObjectArray_Destroy(objects); } cache->searchedObjectType[cachedCRLs] = PR_TRUE; return status; } static CK_ATTRIBUTE_PTR find_attribute_in_object ( nssCryptokiObjectAndAttributes *obj, CK_ATTRIBUTE_TYPE attrType ) { PRUint32 j; for (j=0; jnumAttributes; 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; iulValueLen || !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: if (objects) { for (--oi; oi>=0; --oi) { nssCryptokiObject_Destroy(objects[oi]); } } 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; if (!token_is_present(cache)) { status = PR_SUCCESS; goto finish; } PZ_Lock(cache->lock); switch (objclass) { case CKO_CERTIFICATE: if (cache->doObjectType[cachedCerts]) { status = get_token_certs_for_cache(cache); if (status != PR_SUCCESS) { goto unlock; } rvObjects = find_objects_in_array(cache->objects[cachedCerts], otemplate, otlen, maximumOpt); } break; case CKO_NETSCAPE_TRUST: if (cache->doObjectType[cachedTrust]) { status = get_token_trust_for_cache(cache); if (status != PR_SUCCESS) { goto unlock; } rvObjects = find_objects_in_array(cache->objects[cachedTrust], otemplate, otlen, maximumOpt); } break; case CKO_NETSCAPE_CRL: if (cache->doObjectType[cachedCRLs]) { status = get_token_crls_for_cache(cache); if (status != PR_SUCCESS) { goto unlock; } rvObjects = find_objects_in_array(cache->objects[cachedCRLs], otemplate, otlen, maximumOpt); } break; default: break; } unlock: 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; inumAttributes; 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); if (objectType == cachedCerts) { (*otype)[count] = create_cert(copyObject, &status); } else if (objectType == cachedTrust) { (*otype)[count] = create_trust(copyObject, &status); } else if (objectType == cachedCRLs) { (*otype)[count] = create_crl(copyObject, &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; }