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