From ee48e4329a2ef8796d1d4582b377fd503a70206b Mon Sep 17 00:00:00 2001 From: "ian.mcgreer%sun.com" Date: Fri, 12 Oct 2001 17:54:50 +0000 Subject: [PATCH] check in cert lookup functions using the cache --- security/nss/lib/dev/dev.h | 3 +- security/nss/lib/dev/token.c | 49 ++-- security/nss/lib/pki/nsspki.h | 6 +- security/nss/lib/pki/pki.h | 13 +- security/nss/lib/pki/pkim.h | 4 +- security/nss/lib/pki/trustdomain.c | 346 ++++++++++++++++++++--------- 6 files changed, 276 insertions(+), 145 deletions(-) diff --git a/security/nss/lib/dev/dev.h b/security/nss/lib/dev/dev.h index 59a46f861eb..b067b712a7d 100644 --- a/security/nss/lib/dev/dev.h +++ b/security/nss/lib/dev/dev.h @@ -35,7 +35,7 @@ #define DEV_H #ifdef DEBUG -static const char DEV_CVS_ID[] = "@(#) $RCSfile: dev.h,v $ $Revision: 1.8 $ $Date: 2001-10-11 16:33:38 $ $Name: $"; +static const char DEV_CVS_ID[] = "@(#) $RCSfile: dev.h,v $ $Revision: 1.9 $ $Date: 2001-10-12 17:54:47 $ $Name: $"; #endif /* DEBUG */ #ifndef DEVT_H @@ -298,6 +298,7 @@ nssToken_FindCertificatesByTemplate ( NSSToken *tok, nssSession *sessionOpt, + nssList *cachedList, CK_ATTRIBUTE_PTR cktemplate, CK_ULONG ctsize, PRStatus (*callback)(NSSCertificate *c, void *arg), diff --git a/security/nss/lib/dev/token.c b/security/nss/lib/dev/token.c index b684e92a2da..8654544638c 100644 --- a/security/nss/lib/dev/token.c +++ b/security/nss/lib/dev/token.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: token.c,v $ $Revision: 1.9 $ $Date: 2001-10-11 18:40:31 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: token.c,v $ $Revision: 1.10 $ $Date: 2001-10-12 17:54:48 $ $Name: $"; #endif /* DEBUG */ #ifndef DEV_H @@ -313,37 +313,30 @@ loser: } struct cert_callback_str { + nssListIterator *cachedCerts; PRStatus (*callback)(NSSCertificate *c, void *arg); void *arg; }; -/* Parts of this (cache lookup, creating a cert) should be passed up to - * a higher level through a callback, but left here for now - */ static PRStatus retrieve_cert(NSSToken *t, nssSession *session, CK_OBJECT_HANDLE h, void *arg) { - PRStatus nssrv; - NSSCertificate *cert; - NSSDER issuer, serial; - CK_ULONG template_size; - /* Set up the unique id */ - CK_ATTRIBUTE cert_template[] = { - { CKA_ISSUER, NULL, 0 }, - { CKA_SERIAL_NUMBER, NULL, 0 } - }; + NSSCertificate *cert = NULL; + NSSCertificate *c; struct cert_callback_str *ccb = (struct cert_callback_str *)arg; - template_size = sizeof(cert_template) / sizeof(cert_template[0]); - /* Get the unique id */ - nssrv = nssCKObject_GetAttributes(h, cert_template, template_size, - NULL, session, t->slot); - NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[0], &issuer); - NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[1], &serial); - /* Look in the cert's trust domain cache first */ - cert = nssTrustDomain_GetCertForIssuerAndSNFromCache(t->trustDomain, - &issuer, &serial); - nss_ZFreeIf(issuer.data); - nss_ZFreeIf(serial.data); + if (ccb->cachedCerts) { + for (c = (NSSCertificate *)nssListIterator_Start(ccb->cachedCerts); + c != (NSSCertificate *)NULL; + c = (NSSCertificate *)nssListIterator_Next(ccb->cachedCerts)) + { + if (c->handle == h && c->token == t) { + /* this is enough, right? */ + cert = c; + break; + } + } + nssListIterator_Finish(ccb->cachedCerts); + } if (!cert) { /* Could not find cert, so create it */ cert = NSSCertificate_CreateFromHandle(NULL, h, session, t->slot); @@ -455,7 +448,7 @@ nssToken_TraverseCertificates }; CK_ULONG ctsize = sizeof(cert_template) / sizeof(cert_template[0]); NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); - nssrv = nssToken_FindCertificatesByTemplate(tok, sessionOpt, + nssrv = nssToken_FindCertificatesByTemplate(tok, sessionOpt, NULL, cert_template, ctsize, callback, arg); return NULL; /* XXX */ @@ -466,6 +459,7 @@ nssToken_FindCertificatesByTemplate ( NSSToken *tok, nssSession *sessionOpt, + nssList *cachedList, CK_ATTRIBUTE_PTR cktemplate, CK_ULONG ctsize, PRStatus (*callback)(NSSCertificate *c, void *arg), @@ -477,6 +471,11 @@ nssToken_FindCertificatesByTemplate struct cert_callback_str ccb; session = (sessionOpt) ? sessionOpt : tok->defaultSession; /* this isn't really traversal, it's find by template ... */ + if (cachedList) { + ccb.cachedCerts = nssList_CreateIterator(cachedList); + } else { + ccb.cachedCerts = NULL; + } ccb.callback = callback; ccb.arg = arg; rvstack = nsstoken_TraverseObjects(tok, session, diff --git a/security/nss/lib/pki/nsspki.h b/security/nss/lib/pki/nsspki.h index 6b72748f91d..541d5ea6d08 100644 --- a/security/nss/lib/pki/nsspki.h +++ b/security/nss/lib/pki/nsspki.h @@ -35,7 +35,7 @@ #define NSSPKI_H #ifdef DEBUG -static const char NSSPKI_CVS_ID[] = "@(#) $RCSfile: nsspki.h,v $ $Revision: 1.4 $ $Date: 2001-10-11 16:34:44 $ $Name: $"; +static const char NSSPKI_CVS_ID[] = "@(#) $RCSfile: nsspki.h,v $ $Revision: 1.5 $ $Date: 2001-10-12 17:54:50 $ $Name: $"; #endif /* DEBUG */ /* @@ -1747,7 +1747,7 @@ NSS_EXTERN NSSCertificate * NSSTrustDomain_FindBestCertificateBySubject ( NSSTrustDomain *td, - NSSUTF8 *subject, + NSSDER /*NSSUTF8*/ *subject, NSSTime *timeOpt, NSSUsage *usage, NSSPolicies *policiesOpt @@ -1763,7 +1763,7 @@ NSS_EXTERN NSSCertificate ** NSSTrustDomain_FindCertificatesBySubject ( NSSTrustDomain *td, - NSSUTF8 *subject, + NSSDER /*NSSUTF8*/ *subject, NSSCertificate *rvOpt[], PRUint32 maximumOpt, /* 0 for no max */ NSSArena *arenaOpt diff --git a/security/nss/lib/pki/pki.h b/security/nss/lib/pki/pki.h index 0136066eca3..68d9523496f 100644 --- a/security/nss/lib/pki/pki.h +++ b/security/nss/lib/pki/pki.h @@ -35,7 +35,7 @@ #define PKI_H #ifdef DEBUG -static const char PKI_CVS_ID[] = "@(#) $RCSfile: pki.h,v $ $Revision: 1.4 $ $Date: 2001-10-11 16:34:44 $ $Name: $"; +static const char PKI_CVS_ID[] = "@(#) $RCSfile: pki.h,v $ $Revision: 1.5 $ $Date: 2001-10-12 17:54:50 $ $Name: $"; #endif /* DEBUG */ #ifndef PKIT_H @@ -75,17 +75,6 @@ NSSCertificate_GetID NSSCertificate *c ); -/* - * Look for a specific cert in the cache. - */ -NSS_EXTERN NSSCertificate * -nssTrustDomain_GetCertForIssuerAndSNFromCache -( - NSSTrustDomain *td, - NSSDER *issuer, - NSSDER *serialNum -); - PR_END_EXTERN_C #endif /* PKI_H */ diff --git a/security/nss/lib/pki/pkim.h b/security/nss/lib/pki/pkim.h index c8c14d11ec5..18d71a6e215 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.1 $ $Date: 2001-10-11 16:34:44 $ $Name: $"; +static const char PKIM_CVS_ID[] = "@(#) $RCSfile: pkim.h,v $ $Revision: 1.2 $ $Date: 2001-10-12 17:54:50 $ $Name: $"; #endif /* DEBUG */ #ifndef BASE_H @@ -187,7 +187,6 @@ nssTrustDomain_GetCertsForSubjectFromCache nssList *certListOpt ); -#if 0 /* * Look for a specific cert in the cache. */ @@ -198,7 +197,6 @@ nssTrustDomain_GetCertForIssuerAndSNFromCache NSSDER *issuer, NSSDER *serialNum ); -#endif /* * Look for a specific cert in the cache. diff --git a/security/nss/lib/pki/trustdomain.c b/security/nss/lib/pki/trustdomain.c index 7d0bbd0f41e..11aca3d1a12 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.8 $ $Date: 2001-10-11 18:41:51 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.9 $ $Date: 2001-10-12 17:54:50 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSPKI_H @@ -95,9 +95,14 @@ loser: } static void -token_destructor(void *tok) +token_destructor(void *t) { - (void)nssToken_Destroy((NSSToken *)tok); + NSSToken *tok = (NSSToken *)t; +#ifdef NSS_3_4_CODE + /* in 3.4, also destroy the slot (managed separately) */ + (void)nssSlot_Destroy(tok->slot); +#endif + (void)nssToken_Destroy(tok); } NSS_IMPLEMENT PRStatus @@ -344,6 +349,7 @@ struct get_best_cert_arg_str { NSSTime *time; NSSUsage *usage; NSSPolicies *policies; + nssList *cached; }; static PRStatus @@ -361,6 +367,84 @@ get_best_cert(NSSCertificate *c, void *arg) return PR_SUCCESS; } +static NSSCertificate * +find_best_cert_for_template +( + NSSTrustDomain *td, + struct get_best_cert_arg_str *best, + CK_ATTRIBUTE_PTR cktemplate, + CK_ULONG ctsize +) +{ + PRStatus nssrv; + NSSToken *tok; + for (tok = (NSSToken *)nssListIterator_Start(td->tokens); + tok != (NSSToken *)NULL; + tok = (NSSToken *)nssListIterator_Next(td->tokens)) + { + nssrv = nssToken_FindCertificatesByTemplate(tok, NULL, best->cached, + cktemplate, ctsize, + get_best_cert, &best); + } + nssListIterator_Finish(td->tokens); + return best->cert; +} + +struct collect_arg_str { + nssList *list; + PRUint32 maximum; + NSSArena *arena; + NSSCertificate **rvOpt; +}; + +extern const NSSError NSS_ERROR_MAXIMUM_FOUND; + +static PRStatus +collect_certs(NSSCertificate *c, void *arg) +{ + struct collect_arg_str *ca = (struct collect_arg_str *)arg; + /* Add the cert to the return list */ + nssList_AddUnique(ca->list, (void *)c); + if (ca->maximum > 0 && nssList_Count(ca->list) >= ca->maximum) { + /* signal the end of collection) */ + nss_SetError(NSS_ERROR_MAXIMUM_FOUND); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static NSSCertificate ** +find_all_certs_for_template +( + NSSTrustDomain *td, + struct collect_arg_str *ca, + CK_ATTRIBUTE_PTR cktemplate, + CK_ULONG ctsize +) +{ + NSSCertificate **certs = NULL; + PRStatus nssrv; + PRUint32 count; + NSSToken *tok; + for (tok = (NSSToken *)nssListIterator_Start(td->tokens); + tok != (NSSToken *)NULL; + tok = (NSSToken *)nssListIterator_Next(td->tokens)) + { + nssrv = nssToken_FindCertificatesByTemplate(tok, NULL, ca->list, + cktemplate, ctsize, + collect_certs, ca); + } + nssListIterator_Finish(td->tokens); + count = nssList_Count(ca->list); + if (ca->rvOpt) { + certs = ca->rvOpt; + } else { + certs = nss_ZNEWARRAY(ca->arena, NSSCertificate *, count + 1); + } + nssrv = nssList_GetArray(ca->list, (void **)certs, count); + return certs; +} + NSS_IMPLEMENT NSSCertificate * NSSTrustDomain_FindBestCertificateByNickname ( @@ -371,67 +455,42 @@ NSSTrustDomain_FindBestCertificateByNickname NSSPolicies *policiesOpt /* NULL for none */ ) { + NSSCertificate *rvCert = NULL; PRStatus nssrv; - NSSToken *tok; - CK_ATTRIBUTE cert_template[] = + struct get_best_cert_arg_str best; + CK_ATTRIBUTE nick_template[] = { { CKA_CLASS, NULL, 0 }, { CKA_LABEL, NULL, 0 } }; - struct get_best_cert_arg_str best; CK_ULONG ctsize; - ctsize = (CK_ULONG)(sizeof(cert_template) / sizeof(cert_template[0])); - NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); - cert_template[1].pValue = (CK_VOID_PTR)name; - cert_template[1].ulValueLen = (CK_ULONG)nssUTF8_Length(name, &nssrv); + nssList *nameList; + /* set up the search template */ + ctsize = (CK_ULONG)(sizeof(nick_template) / sizeof(nick_template[0])); + NSS_CK_SET_ATTRIBUTE_ITEM(nick_template, 0, &g_ck_class_cert); + nick_template[1].pValue = (CK_VOID_PTR)name; + nick_template[1].ulValueLen = (CK_ULONG)nssUTF8_Length(name, &nssrv); + /* set the criteria for determining the best cert */ best.td = td; best.cert = NULL; best.time = (timeOpt) ? timeOpt : NSSTime_Now(NULL); best.usage = usage; best.policies = policiesOpt; - /* This will really be done through the search order, probably a - * token array - */ - for (tok = (NSSToken *)nssListIterator_Start(td->tokens); - tok != (NSSToken *)NULL; - tok = (NSSToken *)nssListIterator_Next(td->tokens)) - { - nssrv = nssToken_FindCertificatesByTemplate(tok, NULL, - cert_template, ctsize, - get_best_cert, &best); + /* find all matching certs in the cache */ + nameList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForNicknameFromCache(td, name, nameList); + best.cached = nameList; + /* now find the best cert on tokens */ + rvCert = find_best_cert_for_template(td, &best, nick_template, ctsize); + if (!rvCert) { /* This is to workaround the fact that PKCS#11 doesn't specify - * whether the '\0' should be included. XXX Is that still true? - */ - cert_template[1].ulValueLen++; - nssrv = nssToken_FindCertificatesByTemplate(tok, NULL, - cert_template, ctsize, - get_best_cert, &best); - cert_template[1].ulValueLen--; + * whether the '\0' should be included. XXX Is that still true? + */ + nick_template[1].ulValueLen++; + rvCert = find_best_cert_for_template(td, &best, nick_template, ctsize); } - nssListIterator_Finish(td->tokens); - return best.cert; -} - -struct collect_arg_str { - nssList *list; - PRUint32 maximum; - NSSArena *arena; -}; - -extern const NSSError NSS_ERROR_MAXIMUM_FOUND; - -static PRStatus -collect_certs(NSSCertificate *c, void *arg) -{ - struct collect_arg_str *ca = (struct collect_arg_str *)arg; - /* Add the cert to the return list */ - nssList_Add(ca->list, (void *)c); - if (ca->maximum > 0 && nssList_Count(ca->list) >= ca->maximum) { - /* signal the end of collection) */ - nss_SetError(NSS_ERROR_MAXIMUM_FOUND); - return PR_FAILURE; - } - return PR_SUCCESS; + nssList_Destroy(nameList); + return rvCert; } NSS_IMPLEMENT NSSCertificate ** @@ -444,55 +503,28 @@ NSSTrustDomain_FindCertificatesByNickname NSSArena *arenaOpt ) { + NSSCertificate **rvCerts = NULL; PRStatus nssrv; - PRUint32 count; - NSSCertificate **certs; - NSSToken *tok; - nssList *foundCerts; - CK_ATTRIBUTE cert_template[] = + CK_ATTRIBUTE nick_template[] = { { CKA_CLASS, NULL, 0 }, { CKA_LABEL, NULL, 0 } }; + nssList *nickCerts; struct collect_arg_str ca; CK_ULONG ctsize; - ctsize = (CK_ULONG)(sizeof(cert_template) / sizeof(cert_template[0])); - NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); - cert_template[1].pValue = (CK_VOID_PTR)name; - cert_template[1].ulValueLen = (CK_ULONG)nssUTF8_Length(name, &nssrv); - foundCerts = nssList_Create(NULL, PR_FALSE); - ca.list = foundCerts; + ctsize = (CK_ULONG)(sizeof(nick_template) / sizeof(nick_template[0])); + NSS_CK_SET_ATTRIBUTE_ITEM(nick_template, 0, &g_ck_class_cert); + nick_template[1].pValue = (CK_VOID_PTR)name; + nick_template[1].ulValueLen = (CK_ULONG)nssUTF8_Length(name, &nssrv); + nickCerts = nssList_Create(NULL, PR_FALSE); + ca.list = nickCerts; ca.maximum = maximumOpt; ca.arena = arenaOpt; - /* This will really be done through the search order, probably a - * token array - */ - for (tok = (NSSToken *)nssListIterator_Start(td->tokens); - tok != (NSSToken *)NULL; - tok = (NSSToken *)nssListIterator_Next(td->tokens)) - { - nssrv = nssToken_FindCertificatesByTemplate(tok, NULL, - cert_template, ctsize, - collect_certs, &ca); - /* This is to workaround the fact that PKCS#11 doesn't specify - * whether the '\0' should be included. XXX Is that still true? - */ - cert_template[1].ulValueLen++; - nssrv = nssToken_FindCertificatesByTemplate(tok, NULL, - cert_template, ctsize, - collect_certs, &ca); - cert_template[1].ulValueLen--; - } - nssListIterator_Finish(td->tokens); - count = nssList_Count(foundCerts); - if (rvOpt) { - certs = rvOpt; - } else { - certs = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1); - } - nssrv = nssList_GetArray(foundCerts, (void **)certs, count); - nssList_Destroy(foundCerts); - return certs; + ca.rvOpt = rvOpt; + rvCerts = find_all_certs_for_template(td, &ca, nick_template, ctsize); + nssList_Destroy(nickCerts); + return rvCerts; } NSS_IMPLEMENT NSSCertificate * @@ -520,36 +552,115 @@ NSSTrustDomain_FindCertificateByIssuerAndSerialNumber NSSDER *serialNumber ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + NSSCertificate *rvCert = NULL; + NSSToken *tok; + CK_ULONG ctsize; + CK_OBJECT_HANDLE object; + CK_ATTRIBUTE cert_template[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_ISSUER, NULL, 0 }, + { CKA_SERIAL_NUMBER, NULL, 0 } + }; + ctsize = sizeof(cert_template) / sizeof(cert_template[0]); + /* Set the unique id */ + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, issuer); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 1, serialNumber); + /* Try the cache */ + rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td, + issuer, + serialNumber); + if (!rvCert) { + /* Not cached, look for it on tokens */ + for (tok = (NSSToken *)nssListIterator_Start(td->tokens); + tok != (NSSToken *)NULL; + tok = (NSSToken *)nssListIterator_Next(td->tokens)) + { + object = nssToken_FindObjectByTemplate(tok, NULL, + cert_template, ctsize); + if (object != CK_INVALID_KEY) { + /* Could not find cert, so create it */ + rvCert = NSSCertificate_CreateFromHandle(NULL, object, + NULL, tok->slot); + if (rvCert) { + /* cache it */ + nssTrustDomain_AddCertsToCache(td, &rvCert, 1); + } + break; + } + } + nssListIterator_Finish(td->tokens); + } + return rvCert; } NSS_IMPLEMENT NSSCertificate * NSSTrustDomain_FindBestCertificateBySubject ( NSSTrustDomain *td, - NSSUTF8 *subject, + NSSDER *subject, NSSTime *timeOpt, NSSUsage *usage, NSSPolicies *policiesOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + NSSCertificate *rvCert = NULL; + nssList *subjectList; + CK_ATTRIBUTE subj_template[] = + { + { CKA_CLASS, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 } + }; + struct get_best_cert_arg_str best; + CK_ULONG ctsize; + ctsize = (CK_ULONG)(sizeof(subj_template) / sizeof(subj_template[0])); + NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 0, &g_ck_class_cert); + NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 1, subject); + best.td = td; + best.cert = NULL; + best.time = (timeOpt) ? timeOpt : NSSTime_Now(NULL); + best.usage = usage; + best.policies = policiesOpt; + subjectList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForSubjectFromCache(td, subject, subjectList); + best.cached = subjectList; + /* now find the best cert on tokens */ + rvCert = find_best_cert_for_template(td, &best, subj_template, ctsize); + nssList_Destroy(subjectList); + return rvCert; } NSS_IMPLEMENT NSSCertificate ** NSSTrustDomain_FindCertificatesBySubject ( NSSTrustDomain *td, - NSSUTF8 *subject, + NSSDER *subject, NSSCertificate *rvOpt[], PRUint32 maximumOpt, /* 0 for no max */ NSSArena *arenaOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + NSSCertificate **rvCerts = NULL; + nssList *subjectList; + struct collect_arg_str ca; + CK_ATTRIBUTE subj_template[] = + { + { CKA_CLASS, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 } + }; + CK_ULONG ctsize; + ctsize = (CK_ULONG)(sizeof(subj_template) / sizeof(subj_template[0])); + NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 0, &g_ck_class_cert); + NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 1, subject); + subjectList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForSubjectFromCache(td, subject, subjectList); + ca.list = subjectList; + ca.maximum = maximumOpt; + ca.arena = arenaOpt; + ca.rvOpt = rvOpt; + rvCerts = find_all_certs_for_template(td, &ca, subj_template, ctsize); + nssList_Destroy(subjectList); + return rvCerts; } NSS_IMPLEMENT NSSCertificate * @@ -587,8 +698,41 @@ NSSTrustDomain_FindCertificateByEncodedCertificate NSSBER *encodedCertificate ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + NSSCertificate *rvCert = NULL; + NSSToken *tok; + CK_ULONG ctsize; + CK_OBJECT_HANDLE object; + CK_ATTRIBUTE cert_template[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_VALUE, NULL, 0 } + }; + ctsize = sizeof(cert_template) / sizeof(cert_template[0]); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 1, encodedCertificate); + /* Try the cache */ + rvCert = nssTrustDomain_GetCertByDERFromCache(td, encodedCertificate); + if (!rvCert) { + /* Not cached, look for it on tokens */ + for (tok = (NSSToken *)nssListIterator_Start(td->tokens); + tok != (NSSToken *)NULL; + tok = (NSSToken *)nssListIterator_Next(td->tokens)) + { + object = nssToken_FindObjectByTemplate(tok, NULL, + cert_template, ctsize); + if (object != CK_INVALID_KEY) { + /* Could not find cert, so create it */ + rvCert = NSSCertificate_CreateFromHandle(NULL, object, + NULL, tok->slot); + if (rvCert) { + /* cache it */ + nssTrustDomain_AddCertsToCache(td, &rvCert, 1); + } + break; + } + } + nssListIterator_Finish(td->tokens); + } + return rvCert; } NSS_IMPLEMENT NSSCertificate *