diff options
Diffstat (limited to 'security/nss/lib/dev')
-rw-r--r-- | security/nss/lib/dev/ckhelper.c | 95 | ||||
-rw-r--r-- | security/nss/lib/dev/ckhelper.h | 9 | ||||
-rw-r--r-- | security/nss/lib/dev/dev.h | 56 | ||||
-rw-r--r-- | security/nss/lib/dev/devm.h | 72 | ||||
-rw-r--r-- | security/nss/lib/dev/devslot.c | 12 | ||||
-rw-r--r-- | security/nss/lib/dev/devt.h | 7 | ||||
-rw-r--r-- | security/nss/lib/dev/devtm.h | 2 | ||||
-rw-r--r-- | security/nss/lib/dev/devtoken.c | 139 | ||||
-rw-r--r-- | security/nss/lib/dev/devutil.c | 769 | ||||
-rw-r--r-- | security/nss/lib/dev/manifest.mn | 1 |
10 files changed, 1006 insertions, 156 deletions
diff --git a/security/nss/lib/dev/ckhelper.c b/security/nss/lib/dev/ckhelper.c index c07afd649..3e3c41ce3 100644 --- a/security/nss/lib/dev/ckhelper.c +++ b/security/nss/lib/dev/ckhelper.c @@ -357,14 +357,10 @@ nssCryptokiCertificate_GetAttributes return PR_SUCCESS; } -#ifdef PURE_STAN_BUILD status = nssToken_GetCachedObjectAttributes(certObject->token, arenaOpt, certObject, CKO_CERTIFICATE, cert_template, template_size); if (status != PR_SUCCESS) { -#else - if (PR_TRUE) { -#endif session = sessionOpt ? sessionOpt : @@ -577,15 +573,11 @@ nssCryptokiTrust_GetAttributes NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, csTrust); NSS_CK_TEMPLATE_FINISH(trust_template, attr, trust_size); -#ifdef PURE_STAN_BUILD status = nssToken_GetCachedObjectAttributes(trustObject->token, NULL, trustObject, CKO_NETSCAPE_TRUST, trust_template, trust_size); if (status != PR_SUCCESS) { -#else - if (PR_TRUE) { -#endif session = sessionOpt ? sessionOpt : nssToken_GetDefaultSession(trustObject->token); @@ -607,16 +599,15 @@ nssCryptokiTrust_GetAttributes return PR_SUCCESS; } -#ifdef PURE_STAN_BUILD NSS_IMPLEMENT PRStatus nssCryptokiCRL_GetAttributes ( nssCryptokiObject *crlObject, nssSession *sessionOpt, NSSArena *arenaOpt, - NSSItem *crl, - NSSItem *krl, - NSSItem *url + NSSItem *encodingOpt, + NSSUTF8 **urlOpt, + PRBool *isKRLOpt ) { PRStatus status; @@ -626,12 +617,19 @@ nssCryptokiCRL_GetAttributes CK_ATTRIBUTE_PTR attr; CK_ATTRIBUTE crl_template[5]; CK_ULONG crl_size; + PRUint32 i; NSS_CK_TEMPLATE_START(crl_template, attr, crl_size); NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TOKEN, isToken); - NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE); - NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NETSCAPE_KRL); - NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NETSCAPE_URL); + if (encodingOpt) { + NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE); + } + if (urlOpt) { + NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NETSCAPE_URL); + } + if (isKRLOpt) { + NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NETSCAPE_KRL); + } NSS_CK_TEMPLATE_FINISH(crl_template, attr, crl_size); status = nssToken_GetCachedObjectAttributes(crlObject->token, NULL, @@ -653,10 +651,69 @@ nssCryptokiCRL_GetAttributes } } - NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[0], crl); - NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[1], krl); - NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[2], url); + i=0; + if (encodingOpt) { + NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], encodingOpt); i++; + } + if (urlOpt) { + NSS_CK_ATTRIBUTE_TO_UTF8(&crl_template[i], *urlOpt); i++; + } + if (isKRLOpt) { + NSS_CK_ATTRIBUTE_TO_BOOL(&crl_template[i], *isKRLOpt); i++; + } return PR_SUCCESS; } -#endif /* PURE_STAN_BUILD */ + +NSS_IMPLEMENT PRStatus +nssCryptokiPrivateKey_SetCertificate +( + nssCryptokiObject *keyObject, + nssSession *sessionOpt, + NSSUTF8 *nickname, + NSSItem *id, + NSSDER *subject +) +{ + CK_RV ckrv; + CK_ATTRIBUTE_PTR attr; + CK_ATTRIBUTE key_template[3]; + CK_ULONG key_size; + void *epv = nssToken_GetCryptokiEPV(keyObject->token); + nssSession *session; + NSSToken *token = keyObject->token; + nssSession *defaultSession = nssToken_GetDefaultSession(token); + PRBool createdSession = PR_FALSE; + + NSS_CK_TEMPLATE_START(key_template, attr, key_size); + NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname); + NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id); + NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); + NSS_CK_TEMPLATE_FINISH(key_template, attr, key_size); + + if (sessionOpt) { + if (!nssSession_IsReadWrite(sessionOpt)) { + return PR_FAILURE; + } else { + session = sessionOpt; + } + } else if (nssSession_IsReadWrite(defaultSession)) { + session = defaultSession; + } else { + NSSSlot *slot = nssToken_GetSlot(token); + session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE); + createdSession = PR_TRUE; + nssSlot_Destroy(slot); + } + + ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle, + keyObject->handle, + key_template, + key_size); + + if (createdSession) { + nssSession_Destroy(session); + } + + return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; +} diff --git a/security/nss/lib/dev/ckhelper.h b/security/nss/lib/dev/ckhelper.h index fc64ea9b7..9beab920d 100644 --- a/security/nss/lib/dev/ckhelper.h +++ b/security/nss/lib/dev/ckhelper.h @@ -109,6 +109,15 @@ NSS_EXTERN_DATA const NSSItem g_ck_class_privkey; (item)->size = 0; \ } +#define NSS_CK_ATTRIBUTE_TO_BOOL(attrib, boolvar) \ + if ((attrib)->ulValueLen > 0) { \ + if (*((CK_BBOOL*)(attrib)->pValue) == CK_TRUE) { \ + boolvar = PR_TRUE; \ + } else { \ + boolvar = PR_FALSE; \ + } \ + } + /* NSS_CK_ATTRIBUTE_TO_UTF8(attrib, str) * * Convert a CK_ATTRIBUTE to a string. diff --git a/security/nss/lib/dev/dev.h b/security/nss/lib/dev/dev.h index 2e7bc4cdd..612c0c018 100644 --- a/security/nss/lib/dev/dev.h +++ b/security/nss/lib/dev/dev.h @@ -377,6 +377,7 @@ nssSlot_CreateSession * nssToken_FindTrustObjects * nssToken_FindTrustForCertificate * nssToken_FindCRLs + * nssToken_FindCRLsBySubject * nssToken_FindPrivateKeys * nssToken_FindPrivateKeyByID * nssToken_Digest @@ -577,6 +578,17 @@ nssToken_FindCRLs ); NSS_EXTERN nssCryptokiObject ** +nssToken_FindCRLsBySubject +( + NSSToken *token, + nssSession *sessionOpt, + NSSDER *subject, + nssTokenSearchType searchType, + PRUint32 maximumOpt, + PRStatus *statusOpt +); + +NSS_EXTERN nssCryptokiObject ** nssToken_FindPrivateKeys ( NSSToken *token, @@ -740,9 +752,23 @@ nssCryptokiCRL_GetAttributes nssCryptokiObject *crlObject, nssSession *sessionOpt, NSSArena *arenaOpt, - NSSItem *crl, - NSSItem *krl, - NSSItem *url + NSSItem *encodingOpt, + NSSUTF8 **urlOpt, + PRBool *isKRLOpt +); + +/* I'm including this to handle import of certificates in NSS 3.5. This + * function will set the cert-related attributes of a key, in order to + * associate it with a cert. Does it stay like this for 4.0? + */ +NSS_EXTERN PRStatus +nssCryptokiPrivateKey_SetCertificate +( + nssCryptokiObject *keyObject, + nssSession *sessionOpt, + NSSUTF8 *nickname, + NSSItem *id, + NSSDER *subject ); NSS_EXTERN void @@ -915,30 +941,6 @@ nssToken_GetDefaultSession ); NSS_EXTERN PRStatus -nssToken_SetTrustCache -( - NSSToken *tok -); - -NSS_EXTERN PRStatus -nssToken_SetCrlCache -( - NSSToken *tok -); - -NSS_EXTERN PRBool -nssToken_HasCrls -( - NSSToken *tok -); - -NSS_EXTERN PRStatus -nssToken_SetHasCrls -( - NSSToken *tok -); - -NSS_EXTERN PRStatus nssToken_GetTrustOrder ( NSSToken *tok diff --git a/security/nss/lib/dev/devm.h b/security/nss/lib/dev/devm.h index 9b2bf6c8c..9e62df1a1 100644 --- a/security/nss/lib/dev/devm.h +++ b/security/nss/lib/dev/devm.h @@ -142,6 +142,78 @@ nssCryptokiObject_Create CK_OBJECT_HANDLE h ); +NSS_EXTERN nssTokenObjectCache * +nssTokenObjectCache_Create +( + NSSToken *token, + PRBool cacheCerts, + PRBool cacheTrust, + PRBool cacheCRLs +); + +NSS_EXTERN void +nssTokenObjectCache_Destroy +( + nssTokenObjectCache *cache +); + +NSS_EXTERN PRBool +nssTokenObjectCache_HaveObjectClass +( + nssTokenObjectCache *cache, + CK_OBJECT_CLASS objclass +); + +NSS_EXTERN nssCryptokiObject ** +nssTokenObjectCache_FindObjectsByTemplate +( + nssTokenObjectCache *cache, + CK_OBJECT_CLASS objclass, + CK_ATTRIBUTE_PTR otemplate, + CK_ULONG otlen, + PRUint32 maximumOpt +); + +NSS_EXTERN PRStatus +nssTokenObjectCache_GetObjectAttributes +( + nssTokenObjectCache *cache, + NSSArena *arenaOpt, + nssCryptokiObject *object, + CK_OBJECT_CLASS objclass, + CK_ATTRIBUTE_PTR atemplate, + CK_ULONG atlen +); + +NSS_EXTERN PRStatus +nssTokenObjectCache_ImportObject +( + nssTokenObjectCache *cache, + nssCryptokiObject *object, + CK_OBJECT_CLASS objclass, + CK_ATTRIBUTE_PTR ot, + CK_ULONG otlen +); + +NSS_EXTERN PRStatus +nssTokenObjectCache_RemoveObject +( + nssTokenObjectCache *cache, + nssCryptokiObject *object +); + +/* XXX allows peek back into token */ +NSS_EXTERN PRStatus +nssToken_GetCachedObjectAttributes +( + NSSToken *token, + NSSArena *arenaOpt, + nssCryptokiObject *object, + CK_OBJECT_CLASS objclass, + CK_ATTRIBUTE_PTR atemplate, + CK_ULONG atlen +); + /* PKCS#11 stores strings in a fixed-length buffer padded with spaces. This * function gets the length of the actual string. */ diff --git a/security/nss/lib/dev/devslot.c b/security/nss/lib/dev/devslot.c index 9ee9e4e1f..6950256ad 100644 --- a/security/nss/lib/dev/devslot.c +++ b/security/nss/lib/dev/devslot.c @@ -177,11 +177,13 @@ nssSlot_Destroy ) { #ifdef PURE_STAN_BUILD - PR_AtomicDecrement(&slot->base.refCount); - if (slot->base.refCount == 0) { - nssToken_Destroy(slot->token); - nssModule_DestroyFromSlot(slot->module, slot); - return nssArena_Destroy(slot->base.arena); + if (slot) { + PR_AtomicDecrement(&slot->base.refCount); + if (slot->base.refCount == 0) { + nssToken_Destroy(slot->token); + nssModule_DestroyFromSlot(slot->module, slot); + return nssArena_Destroy(slot->base.arena); + } } #endif return PR_SUCCESS; diff --git a/security/nss/lib/dev/devt.h b/security/nss/lib/dev/devt.h index 4d7b2feaf..10a7978c3 100644 --- a/security/nss/lib/dev/devt.h +++ b/security/nss/lib/dev/devt.h @@ -82,6 +82,8 @@ struct nssDeviceBaseStr PRUint32 flags; }; +typedef struct nssTokenObjectCacheStr nssTokenObjectCache; + /* XXX until devobject.c goes away */ struct NSSTokenStr { @@ -93,12 +95,9 @@ struct NSSTokenStr nssSession *defaultSession; NSSTrustDomain *trustDomain; PRIntervalTime lastTime; - PRBool hasNoTrust; - PRBool hasNoCrls; + nssTokenObjectCache *cache; #ifdef NSS_3_4_CODE PK11SlotInfo *pk11slot; - nssList *certList; /* local cache of certs for slow tokens */ - PRBool loggedIn; #endif }; diff --git a/security/nss/lib/dev/devtm.h b/security/nss/lib/dev/devtm.h index c2f5df580..5e48c5d80 100644 --- a/security/nss/lib/dev/devtm.h +++ b/security/nss/lib/dev/devtm.h @@ -53,8 +53,6 @@ PR_BEGIN_EXTERN_C #define MAX_LOCAL_CACHE_OBJECTS 10 -typedef struct nssTokenObjectCacheStr nssTokenObjectCache; - PR_END_EXTERN_C #endif /* DEVTM_H */ diff --git a/security/nss/lib/dev/devtoken.c b/security/nss/lib/dev/devtoken.c index 52c3b9c4c..44a577f45 100644 --- a/security/nss/lib/dev/devtoken.c +++ b/security/nss/lib/dev/devtoken.c @@ -150,13 +150,13 @@ nssToken_Destroy NSSToken *tok ) { -#ifdef PURE_STAN_BUILD - PR_AtomicDecrement(&tok->base.refCount); - if (tok->base.refCount == 0) { - nssTokenObjectCache_Destroy(tok->cache); - return nssArena_Destroy(tok->base.arena); + if (tok) { + PR_AtomicDecrement(&tok->base.refCount); + if (tok->base.refCount == 0) { + nssTokenObjectCache_Destroy(tok->cache); + return nssArena_Destroy(tok->base.arena); + } } -#endif return PR_SUCCESS; } @@ -268,11 +268,9 @@ nssToken_DeleteStoredObject NSSToken *token = instance->token; nssSession *session = NULL; void *epv = nssToken_GetCryptokiEPV(instance->token); -#ifdef PURE_STAN_BUILD if (token->cache) { status = nssTokenObjectCache_RemoveObject(token->cache, instance); } -#endif if (instance->isTokenObject) { if (nssSession_IsReadWrite(token->defaultSession)) { session = token->defaultSession; @@ -476,7 +474,6 @@ find_objects_by_template CK_OBJECT_CLASS objclass; nssCryptokiObject **objects = NULL; PRUint32 i; -#ifdef PURE_STAN_BUILD for (i=0; i<otsize; i++) { if (obj_template[i].type == CKA_CLASS) { objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue; @@ -495,7 +492,6 @@ find_objects_by_template maximumOpt); if (statusOpt) *statusOpt = PR_SUCCESS; } -#endif /* PURE_STAN_BUILD */ /* Either they are not cached, or cache failed; look on token. */ if (!objects) { objects = find_objects(token, sessionOpt, @@ -547,13 +543,11 @@ nssToken_ImportCertificate NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize); /* Import the certificate onto the token */ rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize); -#ifdef PURE_STAN_BUILD if (rvObject && tok->cache) { nssTokenObjectCache_ImportObject(tok->cache, rvObject, CKO_CERTIFICATE, cert_tmpl, ctsize); } -#endif return rvObject; } @@ -1022,13 +1016,11 @@ nssToken_ImportTrust NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize); /* import the trust object onto the token */ object = import_object(tok, sessionOpt, trust_tmpl, tsize); -#ifdef PURE_STAN_BUILD if (object && tok->cache) { nssTokenObjectCache_ImportObject(tok->cache, object, CKO_CERTIFICATE, trust_tmpl, tsize); } -#endif return object; } @@ -1162,13 +1154,11 @@ nssToken_ImportCRL /* import the crl object onto the token */ object = import_object(token, sessionOpt, crl_tmpl, crlsize); -#ifdef PURE_STAN_BUILD if (object && token->cache) { nssTokenObjectCache_ImportObject(token->cache, object, CKO_CERTIFICATE, crl_tmpl, crlsize); } -#endif return object; } @@ -1211,7 +1201,41 @@ nssToken_FindCRLs return objects; } -#ifdef PURE_STAN_BUILD +NSS_IMPLEMENT nssCryptokiObject ** +nssToken_FindCRLsBySubject +( + NSSToken *token, + nssSession *sessionOpt, + NSSDER *subject, + nssTokenSearchType searchType, + PRUint32 maximumOpt, + PRStatus *statusOpt +) +{ + CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL; + CK_ATTRIBUTE_PTR attr; + CK_ATTRIBUTE crlobj_template[3]; + CK_ULONG crlobj_size; + nssCryptokiObject **objects; + nssSession *session = sessionOpt ? sessionOpt : token->defaultSession; + + NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size); + if (searchType == nssTokenSearchType_SessionOnly) { + NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); + } else if (searchType == nssTokenSearchType_TokenOnly || + searchType == nssTokenSearchType_TokenForced) { + NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); + } + NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc); + NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); + NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size); + + objects = find_objects_by_template(token, session, + crlobj_template, crlobj_size, + maximumOpt, statusOpt); + return objects; +} + NSS_IMPLEMENT PRStatus nssToken_GetCachedObjectAttributes ( @@ -1230,7 +1254,6 @@ nssToken_GetCachedObjectAttributes object, objclass, atemplate, atlen); } -#endif NSS_IMPLEMENT NSSItem * nssToken_Digest @@ -1391,85 +1414,6 @@ nssToken_FinishDigest return rvItem; } -#ifdef NSS_3_4_CODE - -NSS_IMPLEMENT PRStatus -nssToken_SetTrustCache -( - NSSToken *token -) -{ - CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; - CK_ATTRIBUTE_PTR attr; - CK_ATTRIBUTE tobj_template[2]; - CK_ULONG tobj_size; - nssCryptokiObject **objects; - nssSession *session = token->defaultSession; - - NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size); - NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc); - NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); - NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size); - - objects = find_objects_by_template(token, session, - tobj_template, tobj_size, 1, NULL); - token->hasNoTrust = PR_FALSE; - if (objects) { - nssCryptokiObjectArray_Destroy(objects); - } else { - token->hasNoTrust = PR_TRUE; - } - return PR_SUCCESS; -} - -NSS_IMPLEMENT PRStatus -nssToken_SetCrlCache -( - NSSToken *token -) -{ - CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_CRL; - CK_ATTRIBUTE_PTR attr; - CK_ATTRIBUTE tobj_template[2]; - CK_ULONG tobj_size; - nssCryptokiObject **objects; - nssSession *session = token->defaultSession; - - NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size); - NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc); - NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); - NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size); - - objects = find_objects_by_template(token, session, - tobj_template, tobj_size, 1, NULL); - token->hasNoCrls = PR_TRUE; - if (objects) { - nssCryptokiObjectArray_Destroy(objects); - } else { - token->hasNoCrls = PR_TRUE; - } - return PR_SUCCESS; -} - -NSS_IMPLEMENT PRBool -nssToken_HasCrls -( - NSSToken *tok -) -{ - return !tok->hasNoCrls; -} - -NSS_IMPLEMENT PRStatus -nssToken_SetHasCrls -( - NSSToken *tok -) -{ - tok->hasNoCrls = PR_FALSE; - return PR_SUCCESS; -} - NSS_IMPLEMENT PRBool nssToken_IsPresent ( @@ -1478,5 +1422,4 @@ nssToken_IsPresent { return nssSlot_IsTokenPresent(token->slot); } -#endif diff --git a/security/nss/lib/dev/devutil.c b/security/nss/lib/dev/devutil.c index fb97287e3..45ea9883d 100644 --- a/security/nss/lib/dev/devutil.c +++ b/security/nss/lib/dev/devutil.c @@ -539,9 +539,776 @@ nssSlotList_FindTokenByName PZ_Unlock(slotList->lock); return rvToken; } - #endif /* PURE_STAN_BUILD */ +/* 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++) { + 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; + cache->searchedObjectType[objectType] = PR_FALSE; + } +} + +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 ** +get_object_and_attributes +( + nssCryptokiObject **objects, + CK_ATTRIBUTE_TYPE *types, + PRUint32 numTypes, + PRBool *doObjects, + PRStatus *status +) +{ + PRUint32 i, j, numObjects = 0; + nssCryptokiObject **op = objects; + nssCryptokiObjectAndAttributes **rvOandA = NULL; + NSSSlot *slot = NULL; + nssSession *session = NULL; + if (!objects) { + return (nssCryptokiObjectAndAttributes **)NULL; + } + while (*op++) 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; + } else { + if (numObjects == 0) { + /* The fact that there are no objects is cached, done */ + return (nssCryptokiObjectAndAttributes **)NULL; + } + rvOandA = nss_ZNEWARRAY(NULL, + nssCryptokiObjectAndAttributes *, + numObjects + 1); + if (!rvOandA) { + goto loser; + } + slot = nssToken_GetSlot(objects[0]->token); + session = nssToken_GetDefaultSession(objects[0]->token); + for (i=0; i<numObjects; i++) { + NSSArena *arena; + arena = nssArena_Create(); + if (!arena) { + goto loser; + } + rvOandA[i] = nss_ZNEW(arena, nssCryptokiObjectAndAttributes); + if (!rvOandA[i]) { + goto loser; + } + rvOandA[i]->arena = arena; + /* The cache is tied to the token, and therefore the objects + * in it should not hold references to the token. + */ + nssToken_Destroy(objects[i]->token); + rvOandA[i]->object = objects[i]; + rvOandA[i]->attributes = nss_ZNEWARRAY(arena, + CK_ATTRIBUTE, numTypes); + if (!rvOandA[i]->attributes) { + goto loser; + } + for (j=0; j<numTypes; j++) { + rvOandA[i]->attributes[j].type = types[j]; + } + *status = nssCKObject_GetAttributes(objects[i]->handle, + rvOandA[i]->attributes, + numTypes, + arena, + session, + slot); + if (*status != PR_SUCCESS) { + goto loser; + } + rvOandA[i]->numAttributes = numTypes; + } + } + *status = PR_SUCCESS; + if (slot) { + nssSlot_Destroy(slot); + } + return rvOandA; +loser: + *status = PR_FAILURE; + if (slot) { + nssSlot_Destroy(slot); + } + if (rvOandA) { + for (i=0; i<numObjects; i++) { + if (rvOandA[i]) { + nssArena_Destroy(rvOandA[i]->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 | + * +-----------------------------+<--------------------------+ + * + */ +static PRBool +search_for_objects +( + nssTokenObjectCache *cache +) +{ + PRBool doSearch = PR_FALSE; + NSSSlot *slot = nssToken_GetSlot(cache->token); + if (!nssSlot_IsTokenPresent(slot)) { + /* The token is no longer present, destroy any cached objects */ + clear_cache(cache); + nssSlot_Destroy(slot); + return PR_FALSE; + } + /* 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 PRStatus +get_token_certs_for_cache +( + nssTokenObjectCache *cache +) +{ + PRStatus status; + nssCryptokiObject **objects; + 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 + }; + PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]); + if (!search_for_objects(cache) || + cache->searchedObjectType[cachedCerts] || + !cache->doObjectType[cachedCerts]) + { + /* Either there was a state change that prevents a search + * (token removed or 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) { + PRBool *doIt = &cache->doObjectType[cachedCerts]; + cache->objects[cachedCerts] = get_object_and_attributes(objects, + certAttr, + numCertAttr, + doIt, + &status); + if (status == PR_SUCCESS) { + nss_ZFreeIf(objects); + } else { + nssCryptokiObjectArray_Destroy(objects); + } + } else { + return status; + } + cache->searchedObjectType[cachedCerts] = PR_TRUE; + return PR_SUCCESS; +} + +static PRStatus +get_token_trust_for_cache +( + nssTokenObjectCache *cache +) +{ + PRStatus status; + nssCryptokiObject **objects; + 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 + }; + PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]); + if (!search_for_objects(cache) || + cache->searchedObjectType[cachedTrust] || + !cache->doObjectType[cachedTrust]) + { + /* Either there was a state change that prevents a search + * (token removed or 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) { + PRBool *doIt = &cache->doObjectType[cachedTrust]; + cache->objects[cachedTrust] = get_object_and_attributes(objects, + trustAttr, + numTrustAttr, + doIt, + &status); + if (status == PR_SUCCESS) { + nss_ZFreeIf(objects); + } else { + nssCryptokiObjectArray_Destroy(objects); + } + } else { + return status; + } + cache->searchedObjectType[cachedTrust] = PR_TRUE; + return PR_SUCCESS; +} + +static PRStatus +get_token_crls_for_cache +( + nssTokenObjectCache *cache +) +{ + PRStatus status; + nssCryptokiObject **objects; + CK_ATTRIBUTE_TYPE crlAttr[] = { + CKA_CLASS, + CKA_TOKEN, + CKA_LABEL, + CKA_VALUE, + CKA_SUBJECT, + CKA_NETSCAPE_KRL, + CKA_NETSCAPE_URL + }; + PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]); + if (!search_for_objects(cache) || + cache->searchedObjectType[cachedCRLs] || + !cache->doObjectType[cachedCRLs]) + { + /* Either there was a state change that prevents a search + * (token removed or 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) { + PRBool *doIt = &cache->doObjectType[cachedCRLs]; + cache->objects[cachedCRLs] = get_object_and_attributes(objects, + crlAttr, + numCRLAttr, + doIt, + &status); + if (status == PR_SUCCESS) { + nss_ZFreeIf(objects); + } else { + nssCryptokiObjectArray_Destroy(objects); + } + } else { + return status; + } + cache->searchedObjectType[cachedCRLs] = PR_TRUE; + return PR_SUCCESS; +} + +static nssCryptokiObject ** +find_objects_in_array +( + nssCryptokiObjectAndAttributes **objArray, + CK_ATTRIBUTE_PTR ot, + CK_ULONG otlen, + PRUint32 maximumOpt +) +{ + PRIntn oi; + PRUint32 i, j; + PRBool match; + NSSArena *arena; + PRUint32 size = 8; + PRUint32 numMatches = 0; + nssCryptokiObject **objects = NULL; + nssCryptokiObjectAndAttributes **matches = NULL; + 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; + for (; *objArray && numMatches < maximumOpt; objArray++) { + nssCryptokiObjectAndAttributes *obj = *objArray; + for (i=0; i<otlen; i++) { + for (j=0; j<obj->numAttributes; j++) { + if (ot[i].type == obj->attributes[j].type) { + if (ot[i].ulValueLen == obj->attributes[j].ulValueLen && + nsslibc_memequal(ot[i].pValue, + obj->attributes[j].pValue, + ot[i].ulValueLen, NULL)) + { + match = PR_TRUE; + } else { + match = PR_FALSE; + } + break; + } + } + if (j == obj->numAttributes || !match) { + break; + } + } + if (match) { + 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 status = PR_FAILURE; + nssCryptokiObject **rvObjects = NULL; + 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 finish; + } + 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 finish; + } + 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 finish; + } + rvObjects = find_objects_in_array(cache->objects[cachedCRLs], + otemplate, otlen, maximumOpt); + } + break; + default: break; + } +finish: + PZ_Unlock(cache->lock); + return rvObjects; +} + +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; + PZ_Lock(cache->lock); + switch (objclass) { + case CKO_CERTIFICATE: oa = cache->objects[cachedCerts]; break; + case CKO_NETSCAPE_TRUST: oa = cache->objects[cachedTrust]; break; + case CKO_NETSCAPE_CRL: oa = cache->objects[cachedCRLs]; break; + default: goto loser; + } + 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; +} + +static nssCryptokiObjectAndAttributes * +make_object_and_attr +( + nssCryptokiObject *object, + CK_ATTRIBUTE_PTR ot, + CK_ULONG otlen +) +{ + PRUint32 i; + NSSArena *arena; + nssCryptokiObjectAndAttributes *oa; + arena = nssArena_Create(); + if (!arena) { + return (nssCryptokiObjectAndAttributes *)NULL; + } + oa = nss_ZNEW(arena, nssCryptokiObjectAndAttributes); + if (!oa) { + goto loser; + } + oa->object = object; + oa->arena = arena; + nssToken_Destroy(object->token); + oa->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, otlen); + if (!oa->attributes) { + goto loser; + } + for (i=0; i<otlen; i++) { + oa->attributes[i].pValue = nss_ZAlloc(arena, ot[i].ulValueLen); + if (!oa->attributes[i].pValue) { + goto loser; + } + nsslibc_memcpy(oa->attributes[i].pValue, ot[i].pValue, + ot[i].ulValueLen); + oa->attributes[i].ulValueLen = ot[i].ulValueLen; + } + oa->numAttributes = otlen; + return oa; +loser: + nssArena_Destroy(arena); + return (nssCryptokiObjectAndAttributes *)NULL; +} + +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; + 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: status = PR_FAILURE; + } + if (status != PR_SUCCESS || /* failed */ + !cache->doObjectType[objectType] || /* not caching this kind */ + !cache->searchedObjectType[objectType]) /* not cached yet anyway */ + { + PZ_Unlock(cache->lock); + return status; + } + count = 0; + otype = &cache->objects[objectType]; /* index into array of types */ + oa = *otype; /* the array of objects for this type */ + while (oa && *oa++) count++; + 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] = make_object_and_attr(copyObject, ot, otlen); + status = ((*otype)[count] != NULL) ? PR_SUCCESS : PR_FAILURE; + } else { + status = PR_FAILURE; + } + PZ_Unlock(cache->lock); + return status; +} + +NSS_IMPLEMENT PRStatus +nssTokenObjectCache_RemoveObject +( + nssTokenObjectCache *cache, + nssCryptokiObject *object +) +{ + PRUint32 oType; + nssCryptokiObjectAndAttributes **oa, **swp = NULL; + PZ_Lock(cache->lock); + for (oType=0; oType<3; oType++) { + if (!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; + } + } + PZ_Unlock(cache->lock); + if (swp && *swp == NULL) { + nss_ZFreeIf(swp); /* the only entry */ + cache->objects[oType] = NULL; + } + return PR_SUCCESS; +} + /* XXX of course this doesn't belong here */ NSS_IMPLEMENT NSSAlgorithmAndParameters * NSSAlgorithmAndParameters_CreateSHA1Digest diff --git a/security/nss/lib/dev/manifest.mn b/security/nss/lib/dev/manifest.mn index df0151ef2..effab4805 100644 --- a/security/nss/lib/dev/manifest.mn +++ b/security/nss/lib/dev/manifest.mn @@ -58,6 +58,7 @@ CSRCS = \ # here is where the 3.4 glue code is added ifndef PURE_STAN_BUILD DEFINES = -DNSS_3_4_CODE +PRIVATE_EXPORTS += devm.h devtm.h endif REQUIRES = security nspr |