diff options
author | ian.mcgreer%sun.com <devnull@localhost> | 2002-02-27 22:41:56 +0000 |
---|---|---|
committer | ian.mcgreer%sun.com <devnull@localhost> | 2002-02-27 22:41:56 +0000 |
commit | 915a5725c6289c4e8d32c5d6851678982a4e11ac (patch) | |
tree | 91b175bd7f6e4ceb1b5c0497db5b8d162065d307 | |
parent | 99ed6c467a621110f05b88aa424a491ea9d4ea0b (diff) | |
download | nss-hg-915a5725c6289c4e8d32c5d6851678982a4e11ac.tar.gz |
bug 125808, smart card cache fixes
-rw-r--r-- | security/nss/lib/pk11wrap/dev3hack.h | 3 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11cert.c | 26 | ||||
-rw-r--r-- | security/nss/lib/pki/pki3hack.c | 91 | ||||
-rw-r--r-- | security/nss/lib/pki/pki3hack.h | 14 | ||||
-rw-r--r-- | security/nss/lib/pki/trustdomain.c | 104 |
5 files changed, 199 insertions, 39 deletions
diff --git a/security/nss/lib/pk11wrap/dev3hack.h b/security/nss/lib/pk11wrap/dev3hack.h index 3b8f1abf8..0f096e3e8 100644 --- a/security/nss/lib/pk11wrap/dev3hack.h +++ b/security/nss/lib/pk11wrap/dev3hack.h @@ -52,9 +52,6 @@ void PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst); NSSToken * PK11Slot_GetNSSToken(PK11SlotInfo *sl); -NSS_EXTERN void -nssToken_DestroyCertList(NSSToken *token); - NSS_IMPLEMENT PRStatus nssToken_LoadCerts(NSSToken *token); diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c index 1ef758328..6cd9dfa53 100644 --- a/security/nss/lib/pk11wrap/pk11cert.c +++ b/security/nss/lib/pk11wrap/pk11cert.c @@ -1400,7 +1400,7 @@ PK11_FindCertFromNickname(char *nickname, void *wincx) { } } /* find best cert on token */ - if (!nssToken_SearchCerts(token)) { + if (!nssToken_SearchCerts(token, NULL)) { /* token certs are in cache, filter the list of token certs to * match the nickname */ @@ -1443,7 +1443,7 @@ PK11_FindCertFromNickname(char *nickname, void *wincx) { } /* if it wasn't found, repeat the process for email address */ if (!cert) { - if (!nssToken_SearchCerts(token)) { + if (!nssToken_SearchCerts(token, NULL)) { certList = filter_token_certs_email(token, nickname); if (certList) { nssCertificateList_DoCallback(certList, @@ -1540,7 +1540,11 @@ PK11_FindCertsFromNickname(char *nickname, void *wincx) { *delimit = '\0'; /* find token by name */ token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName); - slot = PK11_ReferenceSlot(token->pk11slot); + if (token) { + slot = PK11_ReferenceSlot(token->pk11slot); + } else { + slot = NULL; + } *delimit = ':'; } else { slot = PK11_GetInternalKeySlot(); @@ -1556,7 +1560,7 @@ PK11_FindCertsFromNickname(char *nickname, void *wincx) { return NULL; } } - if (!nssToken_SearchCerts(token)) { + if (!nssToken_SearchCerts(token, NULL)) { nameList = filter_token_certs_nickname(token, nickname); } else { nameList = nssList_Create(NULL, PR_FALSE); @@ -2716,7 +2720,7 @@ PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot, td = STAN_GetDefaultTrustDomain(); NSSITEM_FROM_SECITEM(&subject, &cert->derSubject); token = PK11Slot_GetNSSToken(slot); - if (!nssToken_SearchCerts(token)) { + if (!nssToken_SearchCerts(token, NULL)) { subjectList = filter_token_certs_subject(token, &subject); if (subjectList) { nssrv = nssCertificateList_DoCallback(subjectList, @@ -2807,7 +2811,7 @@ PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot, } td = STAN_GetDefaultTrustDomain(); token = PK11Slot_GetNSSToken(slot); - if (!nssToken_SearchCerts(token)) { + if (!nssToken_SearchCerts(token, NULL)) { nameList = filter_token_certs_nickname(token, nick); if (nameList) { nssrv = nssCertificateList_DoCallback(nameList, @@ -2878,7 +2882,7 @@ PK11_TraverseCertsInSlot(PK11SlotInfo *slot, pk11cb.callback = callback; pk11cb.arg = arg; tok = PK11Slot_GetNSSToken(slot); - if (!nssToken_SearchCerts(tok)) { + if (!nssToken_SearchCerts(tok, NULL)) { certList = tok->certList; nssrv = nssCertificateList_DoCallback(certList, convert_cert, &pk11cb); } else { @@ -2973,7 +2977,13 @@ PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert, NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); tok = PK11Slot_GetNSSToken(slot); NSSITEM_FROM_SECITEM(&derCert, &cert->derCert); - if (!nssToken_SearchCerts(tok)) { + if (!PK11_IsFriendly(slot)) { + if (PK11_Authenticate(slot, PR_TRUE, wincx) != SECSuccess) { + PK11_FreeSlot(slot); + return NULL; + } + } + if (!nssToken_SearchCerts(tok, NULL)) { c = filter_token_certs_DER(tok, &derCert); } else { c = nssTrustDomain_GetCertByDERFromCache(td, &derCert); diff --git a/security/nss/lib/pki/pki3hack.c b/security/nss/lib/pki/pki3hack.c index 4d8d273d9..cc55218e2 100644 --- a/security/nss/lib/pki/pki3hack.c +++ b/security/nss/lib/pki/pki3hack.c @@ -108,12 +108,16 @@ cache_token_cert(NSSCertificate *c, void *arg) { NSSToken *token = (NSSToken *)arg; NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); + NSSCertificate *cp = nssCertificate_AddRef(c); if (nssList_Count(token->certList) > NSSTOKEN_MAX_LOCAL_CERTS) { nssToken_DestroyCertList(token); /* terminate the traversal */ return PR_FAILURE; } nssTrustDomain_AddCertsToCache(td, &c, 1); + if (cp == c) { + NSSCertificate_Destroy(cp); + } /* This list reference persists with the token */ nssList_Add(token->certList, nssCertificate_AddRef(c)); /* The cert needs to become external (made into a CERTCertificate) @@ -123,11 +127,77 @@ cache_token_cert(NSSCertificate *c, void *arg) return PR_SUCCESS; } -static void cert_destructor(void *el) +static void remove_token_instance(NSSCertificate *c, NSSToken *token) +{ + nssListIterator *instances; + nssCryptokiInstance *instance, *rmInstance = NULL; + instances = c->object.instances; + for (instance = (nssCryptokiInstance *)nssListIterator_Start(instances); + instance != (nssCryptokiInstance *)NULL; + instance = (nssCryptokiInstance *)nssListIterator_Next(instances)) + { + if (instance->token == token) { + rmInstance = instance; + break; + } + } + nssListIterator_Finish(instances); + if (rmInstance) { + nssList_Remove(c->object.instanceList, rmInstance); + nssListIterator_Destroy(instances); + c->object.instances = nssList_CreateIterator(c->object.instanceList); + } +} + +static PRBool instance_destructor(NSSCertificate *c, NSSToken *token) { - NSSCertificate *c = (NSSCertificate *)el; CERTCertificate *cert = STAN_GetCERTCertificate(c); - CERT_DestroyCertificate(cert); + remove_token_instance(c, token); + if (nssList_Count(c->object.instanceList) == 0) { + return PR_TRUE; + } + return PR_FALSE; +} + +NSS_IMPLEMENT void +nssCertificateList_DestroyTokenCerts(nssList *certList, NSSToken *token) +{ + nssListIterator *certs; + NSSCertificate *cert; + PRBool removeIt; + certs = nssList_CreateIterator(certList); + for (cert = (NSSCertificate *)nssListIterator_Start(certs); + cert != (NSSCertificate *)NULL; + cert = (NSSCertificate *)nssListIterator_Next(certs)) + { + removeIt = instance_destructor(cert, token); + if (removeIt) { + nssList_Remove(certList, cert); + CERT_DestroyCertificate(STAN_GetCERTCertificate(cert)); + } + } + nssListIterator_Finish(certs); + nssListIterator_Destroy(certs); +} + +NSS_IMPLEMENT void +nssCertificateList_RemoveTokenCerts(nssList *certList, NSSToken *token) +{ + nssListIterator *certs; + NSSCertificate *cert; + PRBool removeIt; + certs = nssList_CreateIterator(certList); + for (cert = (NSSCertificate *)nssListIterator_Start(certs); + cert != (NSSCertificate *)NULL; + cert = (NSSCertificate *)nssListIterator_Next(certs)) + { + removeIt = instance_destructor(cert, token); + if (removeIt) { + nssList_Remove(certList, cert); + } + } + nssListIterator_Finish(certs); + nssListIterator_Destroy(certs); } /* destroy the list of certs on a token */ @@ -137,9 +207,9 @@ nssToken_DestroyCertList(NSSToken *token) if (!token->certList) { return; } - nssList_Clear(token->certList, cert_destructor); - nssList_Destroy(token->certList); - token->certList = NULL; + nssCertificateList_DestroyTokenCerts(token->certList, token); + nssList_Clear(token->certList, NULL); + /* leave the list non-null to prevent it from being searched */ } /* create a list of local cert references for certain tokens */ @@ -183,11 +253,18 @@ nssToken_LoadCerts(NSSToken *token) NSS_IMPLEMENT PRBool nssToken_SearchCerts ( - NSSToken *token + NSSToken *token, + PRBool *notPresentOpt ) { + if (notPresentOpt) { + *notPresentOpt = PR_FALSE; + } if (!nssToken_IsPresent(token)) { nssToken_DestroyCertList(token); /* will free cached certs */ + if (notPresentOpt) { + *notPresentOpt = PR_TRUE; + } } else if (token->certList && nssList_Count(token->certList) == 0 && !token->loggedIn) { diff --git a/security/nss/lib/pki/pki3hack.h b/security/nss/lib/pki/pki3hack.h index df4010285..3bbe62716 100644 --- a/security/nss/lib/pki/pki3hack.h +++ b/security/nss/lib/pki/pki3hack.h @@ -42,6 +42,8 @@ static const char PKINSS3HACK_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name #include "nsspkit.h" #endif /* NSSPKIT_H */ +#include "base.h" + #include "cert.h" PR_BEGIN_EXTERN_C @@ -75,9 +77,19 @@ STAN_DestroyNSSToken(NSSToken *token); NSS_EXTERN PRBool nssToken_SearchCerts ( - NSSToken *token + NSSToken *token, + PRBool *notPresentOpt ); +NSS_EXTERN void +nssToken_DestroyCertList(NSSToken *token); + +NSS_EXTERN void +nssCertificateList_DestroyTokenCerts(nssList *certList, NSSToken *token); + +NSS_EXTERN void +nssCertificateList_RemoveTokenCerts(nssList *certList, NSSToken *token); + NSS_EXTERN SECStatus STAN_AddModuleToDefaultTrustDomain ( diff --git a/security/nss/lib/pki/trustdomain.c b/security/nss/lib/pki/trustdomain.c index ad0429da8..0d33e086d 100644 --- a/security/nss/lib/pki/trustdomain.c +++ b/security/nss/lib/pki/trustdomain.c @@ -411,6 +411,7 @@ NSSTrustDomain_FindBestCertificateByNickname nssTokenCertSearch search; nssBestCertificateCB best; nssList *nameList; + PRBool notPresent; /* set the criteria for determining the best cert */ nssBestCertificate_SetArgs(&best, timeOpt, usage, policiesOpt); /* find all matching certs in the cache */ @@ -421,19 +422,21 @@ NSSTrustDomain_FindBestCertificateByNickname search.cbarg = &best; search.cached = nameList; search.searchType = nssTokenSearchType_TokenOnly; - nssCertificateList_DoCallback(nameList, - nssBestCertificate_Callback, &best); /* traverse the tokens */ for (token = (NSSToken *)nssListIterator_Start(td->tokens); token != (NSSToken *)NULL; token = (NSSToken *)nssListIterator_Next(td->tokens)) { - if (nssToken_SearchCerts(token)) { + if (nssToken_SearchCerts(token, ¬Present)) { nssrv = nssToken_TraverseCertificatesByNickname(token, NULL, name, &search); } + if (notPresent) { + nssCertificateList_DestroyTokenCerts(nameList, token); + } } nssListIterator_Finish(td->tokens); + nssCertificateList_DoCallback(nameList, nssBestCertificate_Callback, &best); nssList_Clear(nameList, cert_destructor); nssList_Destroy(nameList); if (best.cert) { @@ -457,8 +460,9 @@ NSSTrustDomain_FindCertificatesByNickname PRUint32 count; PRStatus nssrv; nssList *nameList; - struct collect_arg_str ca; nssTokenCertSearch search; + struct collect_arg_str ca; + PRBool notPresent; /* set up the collection */ nameList = nssList_Create(NULL, PR_FALSE); (void)nssTrustDomain_GetCertsForNicknameFromCache(td, name, nameList); @@ -474,10 +478,13 @@ NSSTrustDomain_FindCertificatesByNickname token != (NSSToken *)NULL; token = (NSSToken *)nssListIterator_Next(td->tokens)) { - if (nssToken_SearchCerts(token)) { + if (nssToken_SearchCerts(token, ¬Present)) { nssrv = nssToken_TraverseCertificatesByNickname(token, NULL, name, &search); } + if (notPresent) { + nssCertificateList_DestroyTokenCerts(nameList, token); + } } nssListIterator_Finish(td->tokens); count = nssList_Count(nameList); @@ -497,6 +504,32 @@ NSSTrustDomain_FindCertificatesByNickname return rvCerts; } +static PRBool cert_token_not_present(NSSCertificate *c) +{ + nssListIterator *instances; + nssCryptokiInstance *instance; + PRBool freeIt = PR_TRUE; + instances = nssList_CreateIterator(c->object.instanceList); + for (instance = (nssCryptokiInstance *)nssListIterator_Start(instances); + instance != (nssCryptokiInstance *)NULL; + instance = (nssCryptokiInstance *)nssListIterator_Next(instances)) + { + if (!nssToken_IsPresent(instance->token)) { + nssToken_DestroyCertList(instance->token); + nssList_Remove(c->object.instanceList, instance); + } else { + freeIt = PR_FALSE; + } + } + nssListIterator_Finish(instances); + nssListIterator_Destroy(instances); + if (!freeIt) { + nssListIterator_Destroy(c->object.instances); + c->object.instances = nssList_CreateIterator(c->object.instanceList); + } + return freeIt; +} + NSS_IMPLEMENT NSSCertificate * NSSTrustDomain_FindCertificateByIssuerAndSerialNumber ( @@ -512,6 +545,10 @@ NSSTrustDomain_FindCertificateByIssuerAndSerialNumber issuer, serialNumber); if (rvCert) { + if (cert_token_not_present(rvCert)) { + CERT_DestroyCertificate(STAN_GetCERTCertificate(rvCert)); + rvCert = NULL; + } return rvCert; } /* Not cached, look for it on tokens */ @@ -519,7 +556,7 @@ NSSTrustDomain_FindCertificateByIssuerAndSerialNumber tok != (NSSToken *)NULL; tok = (NSSToken *)nssListIterator_Next(td->tokens)) { - if (nssToken_SearchCerts(tok)) { + if (nssToken_SearchCerts(tok, NULL)) { rvCert = nssToken_FindCertificateByIssuerAndSerialNumber(tok, NULL, issuer, @@ -541,7 +578,7 @@ NSSTrustDomain_FindCertificateByIssuerAndSerialNumber if (secrv == SECSuccess) { decodedSerial.data = ds.data; decodedSerial.size = ds.len; - if (nssToken_SearchCerts(tok)) { + if (nssToken_SearchCerts(tok, NULL)) { rvCert = nssToken_FindCertificateByIssuerAndSerialNumber( tok, NULL, @@ -578,6 +615,7 @@ NSSTrustDomain_FindBestCertificateBySubject nssList *subjectList; nssBestCertificateCB best; nssTokenCertSearch search; + PRBool notPresent; /* set the criteria for determining the best cert */ nssBestCertificate_SetArgs(&best, timeOpt, usage, policiesOpt); /* find all matching certs in the cache */ @@ -588,19 +626,22 @@ NSSTrustDomain_FindBestCertificateBySubject search.cbarg = &best; search.cached = subjectList; search.searchType = nssTokenSearchType_TokenOnly; - nssCertificateList_DoCallback(subjectList, - nssBestCertificate_Callback, &best); /* traverse the tokens */ for (token = (NSSToken *)nssListIterator_Start(td->tokens); token != (NSSToken *)NULL; token = (NSSToken *)nssListIterator_Next(td->tokens)) { - if (nssToken_SearchCerts(token)) { + if (nssToken_SearchCerts(token, ¬Present)) { nssrv = nssToken_TraverseCertificatesBySubject(token, NULL, subject, &search); } + if (notPresent) { + nssCertificateList_DestroyTokenCerts(subjectList, token); + } } nssListIterator_Finish(td->tokens); + nssCertificateList_DoCallback(subjectList, + nssBestCertificate_Callback, &best); nssList_Clear(subjectList, cert_destructor); nssList_Destroy(subjectList); if (best.cert) { @@ -626,6 +667,7 @@ NSSTrustDomain_FindCertificatesBySubject nssList *subjectList; struct collect_arg_str ca; nssTokenCertSearch search; + PRBool notPresent; /* set up the collection */ subjectList = nssList_Create(NULL, PR_FALSE); (void)nssTrustDomain_GetCertsForSubjectFromCache(td, subject, subjectList); @@ -641,10 +683,13 @@ NSSTrustDomain_FindCertificatesBySubject token != (NSSToken *)NULL; token = (NSSToken *)nssListIterator_Next(td->tokens)) { - if (nssToken_SearchCerts(token)) { + if (nssToken_SearchCerts(token, ¬Present)) { nssrv = nssToken_TraverseCertificatesBySubject(token, NULL, subject, &search); } + if (notPresent) { + nssCertificateList_DestroyTokenCerts(subjectList, token); + } } nssListIterator_Finish(td->tokens); count = nssList_Count(subjectList); @@ -704,6 +749,10 @@ NSSTrustDomain_FindCertificateByEncodedCertificate /* Try the cache */ rvCert = nssTrustDomain_GetCertByDERFromCache(td, encodedCertificate); if (rvCert) { + if (cert_token_not_present(rvCert)) { + CERT_DestroyCertificate(STAN_GetCERTCertificate(rvCert)); + rvCert = NULL; + } return rvCert; } /* Not cached, look for it on tokens */ @@ -711,7 +760,7 @@ NSSTrustDomain_FindCertificateByEncodedCertificate tok != (NSSToken *)NULL; tok = (NSSToken *)nssListIterator_Next(td->tokens)) { - if (nssToken_SearchCerts(tok)) { + if (nssToken_SearchCerts(tok, NULL)) { rvCert = nssToken_FindCertificateByEncodedCertificate(tok, NULL, encodedCertificate, nssTokenSearchType_TokenOnly); @@ -741,6 +790,7 @@ NSSTrustDomain_FindCertificateByEmail nssBestCertificateCB best; nssTokenCertSearch search; nssList *emailList; + PRBool notPresent; /* set the criteria for determining the best cert */ nssBestCertificate_SetArgs(&best, timeOpt, usage, policiesOpt); /* find all matching certs in the cache */ @@ -751,19 +801,22 @@ NSSTrustDomain_FindCertificateByEmail search.cbarg = &best; search.cached = emailList; search.searchType = nssTokenSearchType_TokenOnly; - nssCertificateList_DoCallback(emailList, - nssBestCertificate_Callback, &best); /* traverse the tokens */ for (token = (NSSToken *)nssListIterator_Start(td->tokens); token != (NSSToken *)NULL; token = (NSSToken *)nssListIterator_Next(td->tokens)) { - if (nssToken_SearchCerts(token)) { + if (nssToken_SearchCerts(token, ¬Present)) { nssrv = nssToken_TraverseCertificatesByEmail(token, NULL, email, &search); } + if (notPresent) { + nssCertificateList_DestroyTokenCerts(emailList, token); + } } nssListIterator_Finish(td->tokens); + nssCertificateList_DoCallback(emailList, + nssBestCertificate_Callback, &best); nssList_Clear(emailList, cert_destructor); nssList_Destroy(emailList); if (best.cert) { @@ -946,7 +999,7 @@ static void cert_destructor_with_cache(void *el) CERT_DestroyCertificate(cert); } #endif - + NSS_IMPLEMENT PRStatus * NSSTrustDomain_TraverseCertificates ( @@ -957,13 +1010,18 @@ NSSTrustDomain_TraverseCertificates { PRStatus nssrv; NSSToken *token; - nssList *certList; + nssList *certList, *cacheList; nssTokenCertSearch search; struct traverse_arg ta; nssListIterator *tokens; + PRBool notPresent; certList = nssList_Create(NULL, PR_FALSE); if (!certList) return NULL; (void *)nssTrustDomain_GetCertsFromCache(td, certList); + cacheList = nssList_Clone(certList); + if (!cacheList) { + goto cleanup; + } /* set traverse args */ ta.callback = callback; ta.cached = certList; @@ -973,8 +1031,6 @@ NSSTrustDomain_TraverseCertificates search.cbarg = &ta; search.cached = certList; search.searchType = nssTokenSearchType_TokenOnly; - nssCertificateList_DoCallback(certList, - traverse_callback, &ta); /* Must create a local copy of the token list, because the callback * above may want to traverse the tokens as well. */ @@ -987,12 +1043,20 @@ NSSTrustDomain_TraverseCertificates token != (NSSToken *)NULL; token = (NSSToken *)nssListIterator_Next(tokens)) { - if (nssToken_SearchCerts(token)) { + if (nssToken_SearchCerts(token, ¬Present)) { nssrv = nssToken_TraverseCertificates(token, NULL, &search); } + if (notPresent) { + nssCertificateList_RemoveTokenCerts(cacheList, token); + } } nssListIterator_Finish(tokens); nssListIterator_Destroy(tokens); + /* now do the callback on the cached certs, + * sans certs from removed tokens + */ + nssCertificateList_DoCallback(cacheList, callback, arg); + nssList_Destroy(cacheList); cleanup: #ifdef NSS_3_4_CODE nssList_Clear(certList, cert_destructor_with_cache); |