diff --git a/security/nss/lib/dev/dev.h b/security/nss/lib/dev/dev.h index 4157605fb207..a02df332e2b5 100644 --- a/security/nss/lib/dev/dev.h +++ b/security/nss/lib/dev/dev.h @@ -41,7 +41,7 @@ */ #ifdef DEBUG -static const char DEV_CVS_ID[] = "@(#) $RCSfile: dev.h,v $ $Revision: 1.25 $ $Date: 2002/04/19 23:06:39 $ $Name: $"; +static const char DEV_CVS_ID[] = "@(#) $RCSfile: dev.h,v $ $Revision: 1.26 $ $Date: 2002/04/26 14:33:59 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSCKT_H @@ -952,6 +952,16 @@ nssToken_NofifyCertsNotVisible NSSToken *tok ); +NSS_EXTERN PRStatus +nssToken_TraverseCertificates +( + NSSToken *token, + nssSession *sessionOpt, + nssTokenSearchType searchType, + PRStatus (* callback)(nssCryptokiObject *instance, void *arg), + void *arg +); + #endif PR_END_EXTERN_C diff --git a/security/nss/lib/dev/devtoken.c b/security/nss/lib/dev/devtoken.c index 7e06a70d4482..b30d5a7682e6 100644 --- a/security/nss/lib/dev/devtoken.c +++ b/security/nss/lib/dev/devtoken.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.20 $ $Date: 2002/04/25 20:49:49 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.21 $ $Date: 2002/04/26 14:33:59 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSCKEPV_H @@ -1547,3 +1547,113 @@ nssToken_IsPresent return nssSlot_IsTokenPresent(token->slot); } +/* Sigh. The methods to find objects declared above cause problems with + * the low-level object cache in the softoken -- the objects are found in + * toto, then one wave of GetAttributes is done, then another. Having a + * large number of objects causes the cache to be thrashed, as the objects + * are gone before there's any chance to ask for their attributes. + * So, for now, bringing back traversal methods for certs. This way all of + * the cert's attributes can be grabbed immediately after finding it, + * increasing the likelihood that the cache takes care of it. + */ +NSS_IMPLEMENT PRStatus +nssToken_TraverseCertificates +( + NSSToken *token, + nssSession *sessionOpt, + nssTokenSearchType searchType, + PRStatus (* callback)(nssCryptokiObject *instance, void *arg), + void *arg +) +{ + CK_RV ckrv; + CK_ULONG count; + CK_OBJECT_HANDLE *objectHandles; + CK_ATTRIBUTE_PTR attr; + CK_ATTRIBUTE cert_template[2]; + CK_ULONG ctsize; + NSSArena *arena; + PRStatus status; + PRUint32 arraySize, numHandles; + nssCryptokiObject **objects; + void *epv = nssToken_GetCryptokiEPV(token); + nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession; + + /* template for all certs */ + NSS_CK_TEMPLATE_START(cert_template, attr, ctsize); + 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_ITEM(attr, CKA_CLASS, &g_ck_class_cert); + NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize); + + /* the arena is only for the array of object handles */ + arena = nssArena_Create(); + if (!arena) { + return PR_FAILURE; + } + arraySize = OBJECT_STACK_SIZE; + numHandles = 0; + objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize); + if (!objectHandles) { + goto loser; + } + nssSession_EnterMonitor(session); /* ==== session lock === */ + /* Initialize the find with the template */ + ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, + cert_template, ctsize); + if (ckrv != CKR_OK) { + nssSession_ExitMonitor(session); + goto loser; + } + while (PR_TRUE) { + /* Issue the find for up to arraySize - numHandles objects */ + ckrv = CKAPI(epv)->C_FindObjects(session->handle, + objectHandles + numHandles, + arraySize - numHandles, + &count); + if (ckrv != CKR_OK) { + nssSession_ExitMonitor(session); + goto loser; + } + /* bump the number of found objects */ + numHandles += count; + if (numHandles < arraySize) { + break; + } + /* the array is filled, double it and continue */ + arraySize *= 2; + objectHandles = nss_ZREALLOCARRAY(objectHandles, + CK_OBJECT_HANDLE, + arraySize); + if (!objectHandles) { + nssSession_ExitMonitor(session); + goto loser; + } + } + ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle); + nssSession_ExitMonitor(session); /* ==== end session lock === */ + if (ckrv != CKR_OK) { + goto loser; + } + if (numHandles > 0) { + objects = create_objects_from_handles(token, session, + objectHandles, numHandles); + if (objects) { + nssCryptokiObject **op; + for (op = objects; *op; op++) { + status = (*callback)(*op, arg); + } + nss_ZFreeIf(objects); + } + } + nssArena_Destroy(arena); + return PR_SUCCESS; +loser: + nssArena_Destroy(arena); + return PR_FAILURE; +} + diff --git a/security/nss/lib/pki/pkibase.c b/security/nss/lib/pki/pkibase.c index a727c506a6ff..edd0611292d6 100644 --- a/security/nss/lib/pki/pkibase.c +++ b/security/nss/lib/pki/pkibase.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.4 $ $Date: 2002/04/18 19:26:17 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.5 $ $Date: 2002/04/26 14:34:04 $ $Name: $"; #endif /* DEBUG */ #ifndef DEV_H @@ -716,7 +716,7 @@ find_object_in_collection return (pkiObjectCollectionNode *)NULL; } -static PRStatus +static pkiObjectCollectionNode * add_object_instance ( nssPKIObjectCollection *collection, @@ -740,7 +740,7 @@ add_object_instance * are not using it, it must be destroyed. */ nssCryptokiObject_Destroy(instance); - return PR_SUCCESS; + return node; } mark = nssArena_Mark(collection->arena); if (!mark) { @@ -780,13 +780,13 @@ add_object_instance status = PR_SUCCESS; } nssArena_Unmark(collection->arena, mark); - return status; + return node; loser: if (mark) { nssArena_Release(collection->arena, mark); } nssCryptokiObject_Destroy(instance); - return PR_FAILURE; + return (pkiObjectCollectionNode *)NULL; } NSS_IMPLEMENT PRStatus @@ -799,13 +799,14 @@ nssPKIObjectCollection_AddInstances { PRStatus status = PR_SUCCESS; PRUint32 i = 0; + pkiObjectCollectionNode *node; if (instances) { for (; *instances; instances++, i++) { if (numInstances > 0 && i == numInstances) { break; } - status = add_object_instance(collection, *instances); - if (status != PR_SUCCESS) { + node = add_object_instance(collection, *instances); + if (node == NULL) { goto loser; } } @@ -891,6 +892,35 @@ nssPKIObjectCollection_Traverse return PR_SUCCESS; } +NSS_IMPLEMENT PRStatus +nssPKIObjectCollection_AddInstanceAsObject +( + nssPKIObjectCollection *collection, + nssCryptokiObject *instance +) +{ + pkiObjectCollectionNode *node; + node = add_object_instance(collection, instance); + if (node == NULL) { + return PR_FAILURE; + } + if (!node->haveObject) { + node->object = (*collection->createObject)(node->object); + node->haveObject = PR_TRUE; + } +#ifdef NSS_3_4_CODE + else { + /* The instance was added to a pre-existing node. This + * function is *only* being used for certificates, and having + * multiple instances of certs in 3.X requires updating the + * CERTCertificate. + */ + STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object); + } +#endif + return PR_SUCCESS; +} + /* * Certificate collections */ diff --git a/security/nss/lib/pki/pkim.h b/security/nss/lib/pki/pkim.h index 5d375f548410..d44340753fa2 100644 --- a/security/nss/lib/pki/pkim.h +++ b/security/nss/lib/pki/pkim.h @@ -35,7 +35,7 @@ #define PKIM_H #ifdef DEBUG -static const char PKIM_CVS_ID[] = "@(#) $RCSfile: pkim.h,v $ $Revision: 1.19 $ $Date: 2002/04/19 23:06:43 $ $Name: $"; +static const char PKIM_CVS_ID[] = "@(#) $RCSfile: pkim.h,v $ $Revision: 1.20 $ $Date: 2002/04/26 14:34:04 $ $Name: $"; #endif /* DEBUG */ #ifndef BASE_H @@ -496,6 +496,18 @@ nssPKIObjectCollection_Traverse nssPKIObjectCallback *callback ); +/* This function is being added for NSS 3.5. It corresponds to the function + * nssToken_TraverseCertificates. The idea is to use the collection during + * a traversal, creating certs each time a new instance is added for which + * a cert does not already exist. + */ +NSS_EXTERN PRStatus +nssPKIObjectCollection_AddInstanceAsObject +( + nssPKIObjectCollection *collection, + nssCryptokiObject *instance +); + /* nssPKIObjectCollection_GetCertificates * * Get all of the certificates in the collection. diff --git a/security/nss/lib/pki/trustdomain.c b/security/nss/lib/pki/trustdomain.c index 853673a1bc22..353a3cb4b1d2 100644 --- a/security/nss/lib/pki/trustdomain.c +++ b/security/nss/lib/pki/trustdomain.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.41 $ $Date: 2002/04/22 19:09:01 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.42 $ $Date: 2002/04/26 14:34:05 $ $Name: $"; #endif /* DEBUG */ #ifndef DEV_H @@ -1035,6 +1035,13 @@ NSSTrustDomain_FindUserCertificatesForEmailSigning return NULL; } +static PRStatus +collector(nssCryptokiObject *instance, void *arg) +{ + nssPKIObjectCollection *collection = (nssPKIObjectCollection *)arg; + return nssPKIObjectCollection_AddInstanceAsObject(collection, instance); +} + NSS_IMPLEMENT PRStatus * NSSTrustDomain_TraverseCertificates ( @@ -1052,6 +1059,7 @@ NSSTrustDomain_TraverseCertificates nssUpdateLevel updateLevel; NSSCertificate **cached = NULL; nssList *certList; + certList = nssList_Create(NULL, PR_FALSE); if (!certList) return NULL; (void *)nssTrustDomain_GetCertsFromCache(td, certList); @@ -1073,7 +1081,6 @@ NSSTrustDomain_TraverseCertificates token = nssSlot_GetToken(*slotp); if (token) { nssSession *session; - nssCryptokiObject **instances; nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; /* get a session for the token */ session = nssTrustDomain_GetSessionForToken(td, token); @@ -1082,21 +1089,15 @@ NSSTrustDomain_TraverseCertificates goto loser; } /* perform the traversal */ - instances = nssToken_FindCertificates(token, - session, - tokenOnly, - 0, &status); + status = nssToken_TraverseCertificates(token, + session, + tokenOnly, + collector, + collection); nssToken_Destroy(token); if (status != PR_SUCCESS) { goto loser; } - /* add the found certificates to the collection */ - status = nssPKIObjectCollection_AddInstances(collection, - instances, 0); - nss_ZFreeIf(instances); - if (status != PR_SUCCESS) { - goto loser; - } } }