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