From ba36bf7bc61dbf002b7a7a77bed667b17600917c Mon Sep 17 00:00:00 2001 From: "ian.mcgreer%sun.com" Date: Wed, 17 Oct 2001 14:40:27 +0000 Subject: [PATCH] some more cert lookup methods; find cert issuer/chain; mimic nickname as "token name:nickname" git-svn-id: svn://10.0.0.236/trunk@105629 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/security/nss/lib/pki/certificate.c | 81 +++++++- mozilla/security/nss/lib/pki/nss3hack.c | 77 ++++++-- mozilla/security/nss/lib/pki/pki.h | 4 +- mozilla/security/nss/lib/pki/pkim.h | 9 +- mozilla/security/nss/lib/pki/pkinss3hack.h | 33 +++- mozilla/security/nss/lib/pki/pkitm.h | 6 +- mozilla/security/nss/lib/pki/tdcache.c | 34 ++-- mozilla/security/nss/lib/pki/trustdomain.c | 219 +++++++++++++++++---- 8 files changed, 369 insertions(+), 94 deletions(-) diff --git a/mozilla/security/nss/lib/pki/certificate.c b/mozilla/security/nss/lib/pki/certificate.c index 02d90e85ebd..12cd67a525a 100644 --- a/mozilla/security/nss/lib/pki/certificate.c +++ b/mozilla/security/nss/lib/pki/certificate.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.8 $ $Date: 2001-10-15 18:19:03 $ $Name: not supported by cvs2svn $"; +static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.9 $ $Date: 2001-10-17 14:40:20 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef NSSPKI_H @@ -204,9 +204,36 @@ nssCertificate_SetCertTrust return PR_SUCCESS; } +#ifdef NSS_3_4_CODE +static void make_nss3_nickname(NSSCertificate *c) +{ + /* In NSS 3.4, the semantic is that nickname = token name + label */ + PRStatus utf8rv; + NSSUTF8 *tokenName; + NSSUTF8 *label; + char *fullname; + PRUint32 len, tlen; + tokenName = nssToken_GetName(c->token); + label = c->nickname; + tlen = nssUTF8_Length(tokenName, &utf8rv); /* token name */ + tlen += 1; /* : */ + len = nssUTF8_Length(label, &utf8rv); /* label */ + len += 1; /* \0 */ + len += tlen; + fullname = nss_ZAlloc(c->arena, len); + utf8rv = nssUTF8_CopyIntoFixedBuffer(tokenName, fullname, tlen, ':'); + utf8rv = nssUTF8_CopyIntoFixedBuffer(label, fullname + tlen, + len - tlen, '\0'); + nss_ZFreeIf(c->nickname); + c->nickname = nssUTF8_Create(c->arena, + nssStringType_UTF8String, + fullname, len); +} +#endif + /* Create a certificate from an object handle. */ NSS_IMPLEMENT NSSCertificate * -NSSCertificate_CreateFromHandle +nssCertificate_CreateFromHandle ( NSSArena *arenaOpt, CK_OBJECT_HANDLE object, @@ -232,8 +259,10 @@ NSSCertificate_CreateFromHandle return (NSSCertificate *)NULL; } rvCert->handle = object; + /* clean this up */ rvCert->slot = slot; rvCert->token = slot->token; + rvCert->trustDomain = slot->token->trustDomain; nssrv = nssCKObject_GetAttributes(object, cert_template, template_size, rvCert->arena, session, slot); if (nssrv) { @@ -250,6 +279,9 @@ NSSCertificate_CreateFromHandle NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[5], &rvCert->subject); NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[6], &rvCert->serial); /* get the email from an attrib */ +#ifdef NSS_3_4_CODE + make_nss3_nickname(rvCert); +#endif nssCertificate_SetCertTrust(rvCert, session); return rvCert; loser: @@ -352,12 +384,47 @@ nssCertificate_GetDecoding { if (!c->decoding) { c->decoding = nssDecodedCert_Create(NULL, &c->encoding, c->type); - /* Now that it's decoded, make sure it's in the cache. */ - nssTrustDomain_AddCertsToCache(c->trustDomain, &c, 1); } return c->decoding; } +static NSSCertificate * +find_issuer_cert_for_identifier(NSSCertificate *c, NSSItem *id) +{ + NSSCertificate *rvCert = NULL; + NSSCertificate **subjectCerts; + /* Find all certs with this cert's issuer as the subject */ + subjectCerts = NSSTrustDomain_FindCertificatesBySubject(c->trustDomain, + &c->issuer, + NULL, + 0, + NULL); + if (subjectCerts) { + NSSCertificate *p; + nssDecodedCert *dcp; + int i = 0; + /* walk the subject certs */ + while ((p = subjectCerts[i++])) { + dcp = nssCertificate_GetDecoding(p); + if (dcp->hasThisIdentifier(dcp, id)) { + /* this cert has the correct identifier */ + rvCert = p; + /* now free all the remaining subject certs */ + while ((p = subjectCerts[++i])) { + NSSCertificate_Destroy(p); + } + /* and exit */ + break; + } else { + /* cert didn't have the correct identifier, so free it */ + NSSCertificate_Destroy(p); + } + } + nss_ZFreeIf(subjectCerts); + } + return rvCert; +} + NSS_IMPLEMENT NSSCertificate ** NSSCertificate_BuildChain ( @@ -382,8 +449,7 @@ NSSCertificate_BuildChain dc = nssCertificate_GetDecoding(c); issuerID = dc->getIssuerIdentifier(dc); if (issuerID) { - c = nssTrustDomain_FindCertificateByIdentifier(c->trustDomain, - issuerID); + c = find_issuer_cert_for_identifier(c, issuerID); nss_ZFreeIf(issuerID); if (!c) { #if 0 @@ -412,10 +478,11 @@ finish: rvChain = rvOpt; } else { rvChain = nss_ZNEWARRAY(arenaOpt, - NSSCertificate *, nssList_Count(chain)); + NSSCertificate *, nssList_Count(chain) + 1); } nssList_GetArray(chain, (void **)rvChain, rvLimit); nssList_Destroy(chain); + /* XXX now, the question is, cache all certs in the chain? */ return rvChain; } diff --git a/mozilla/security/nss/lib/pki/nss3hack.c b/mozilla/security/nss/lib/pki/nss3hack.c index e4f9fcef9eb..63856168283 100644 --- a/mozilla/security/nss/lib/pki/nss3hack.c +++ b/mozilla/security/nss/lib/pki/nss3hack.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: nss3hack.c,v $ $Revision: 1.1 $ $Date: 2001-10-11 16:34:44 $ $Name: not supported by cvs2svn $"; +static const char CVS_ID[] = "@(#) $RCSfile: nss3hack.c,v $ $Revision: 1.2 $ $Date: 2001-10-17 14:40:20 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ /* @@ -99,7 +99,7 @@ STAN_LoadDefaultNSS3TrustDomain td->tokenList = nssList_Create(td->arena, PR_TRUE); list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, NULL); if (list) { -#if 0 +#ifndef NSS_SOFTOKEN_MODULE_FOO /* XXX this doesn't work until softoken is a true PKCS#11 mod */ for (le = list->head; le; le = le->next) { token = nssToken_CreateFromPK11SlotInfo(td, le->slot); @@ -185,6 +185,19 @@ nss3certificate_getIssuerIdentifier(nssDecodedCert *dc) return rvID; } +static PRBool +nss3certificate_hasThisIdentifier(nssDecodedCert *dc, NSSItem *id) +{ + CERTCertificate *c = (CERTCertificate *)dc->data; + SECItem *subjectKeyID, authKeyID; + subjectKeyID = &c->subjectKeyID; + SECITEM_FROM_NSSITEM(&authKeyID, id); + if (SECITEM_CompareItem(subjectKeyID, &authKeyID) == SECEqual) { + return PR_TRUE; + } + return PR_FALSE; +} + static NSSUsage * nss3certificate_getUsage(nssDecodedCert *dc) { @@ -231,6 +244,7 @@ nssDecodedPKIXCertificate_Create rvDC->data = (void *)CERT_DecodeDERCertificate(&secDER, PR_TRUE, NULL); rvDC->getIdentifier = nss3certificate_getIdentifier; rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; + rvDC->hasThisIdentifier = nss3certificate_hasThisIdentifier; rvDC->getUsage = nss3certificate_getUsage; rvDC->isValidAtTime = nss3certificate_isValidAtTime; rvDC->isNewerThan = nss3certificate_isNewerThan; @@ -269,13 +283,22 @@ get_nss3trust_from_cktrust(CK_TRUST t) return rt; } +/* From pk11cert.c */ +extern PRBool +PK11_IsUserCert(PK11SlotInfo *, CERTCertificate *, CK_OBJECT_HANDLE); + static CERTCertTrust * -NSSTrust_GetCERTCertTrust(NSSTrust *t) +nssTrust_GetCERTCertTrust(NSSTrust *t, CERTCertificate *cc) { - CERTCertTrust *rvTrust = nss_ZNEW(NULL, CERTCertTrust); + CERTCertTrust *rvTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust)); rvTrust->sslFlags = get_nss3trust_from_cktrust(t->serverAuth); rvTrust->emailFlags = get_nss3trust_from_cktrust(t->emailProtection); rvTrust->objectSigningFlags = get_nss3trust_from_cktrust(t->codeSigning); + if (PK11_IsUserCert(cc->slot, cc, cc->pkcs11ID)) { + rvTrust->sslFlags |= CERTDB_USER; + rvTrust->emailFlags |= CERTDB_USER; + rvTrust->objectSigningFlags |= CERTDB_USER; + } return rvTrust; } @@ -287,23 +310,41 @@ STAN_GetCERTCertificate(NSSCertificate *c) if (!c->decoding) { dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding); c->decoding = dc; - /* decoded, so cache */ + cc = (CERTCertificate *)dc->data; + /* fill other fields needed by NSS3 functions using CERTCertificate */ + /* handle */ + cc->pkcs11ID = c->handle; + /* nickname */ + cc->nickname = PL_strdup(c->nickname); + /* emailAddr ??? */ + /* slot (ownSlot ?) (addref ?) */ + cc->slot = c->token->pk11slot; + /* trust */ + cc->trust = nssTrust_GetCERTCertTrust(&c->trust, cc); + /* referenceCount addref? */ + /* subjectList ? */ + /* pkcs11ID */ + cc->pkcs11ID = c->handle; + /* pointer back */ + cc->nssCertificate = c; } else { dc = c->decoding; + cc = (CERTCertificate *)dc->data; } - /* fill other fields needed by NSS3 functions using CERTCertificate */ - cc = (CERTCertificate *)dc->data; - /* nickname */ - cc->nickname = PL_strdup(c->nickname); - /* emailAddr ??? */ - /* slot */ - cc->slot = c->token->pk11slot; - /* trust */ - cc->trust = NSSTrust_GetCERTCertTrust(&c->trust); - /* referenceCount addref? */ - /* subjectList ? */ - /* pkcs11ID */ - cc->pkcs11ID = c->handle; return cc; } +NSS_EXTERN NSSCertificate * +STAN_GetNSSCertificate(CERTCertificate *cc) +{ + NSSCertificate *c; + c = cc->nssCertificate; + if (!c) { + /* i don't think this should happen. but if it can, need to create + * NSSCertificate from CERTCertificate values here. + */ + return NULL; + } + return c; +} + diff --git a/mozilla/security/nss/lib/pki/pki.h b/mozilla/security/nss/lib/pki/pki.h index 534da820ffe..2a980c143b4 100644 --- a/mozilla/security/nss/lib/pki/pki.h +++ b/mozilla/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.5 $ $Date: 2001-10-12 17:54:50 $ $Name: not supported by cvs2svn $"; +static const char PKI_CVS_ID[] = "@(#) $RCSfile: pki.h,v $ $Revision: 1.6 $ $Date: 2001-10-17 14:40:22 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef PKIT_H @@ -55,7 +55,7 @@ nssCertificate_AddRef ); NSS_EXTERN NSSCertificate * -NSSCertificate_CreateFromHandle +nssCertificate_CreateFromHandle ( NSSArena *arenaOpt, CK_OBJECT_HANDLE object, diff --git a/mozilla/security/nss/lib/pki/pkim.h b/mozilla/security/nss/lib/pki/pkim.h index 6218c95ecb7..9de6fc8e055 100644 --- a/mozilla/security/nss/lib/pki/pkim.h +++ b/mozilla/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.3 $ $Date: 2001-10-15 18:19:03 $ $Name: not supported by cvs2svn $"; +static const char PKIM_CVS_ID[] = "@(#) $RCSfile: pkim.h,v $ $Revision: 1.4 $ $Date: 2001-10-17 14:40:22 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef BASE_H @@ -119,13 +119,6 @@ nssTrustDomain_GetSymmetricKeyToken NSSTrustDomain *td ); -NSS_EXTERN NSSCertificate * -nssTrustDomain_FindCertificateByIdentifier -( - NSSTrustDomain *td, - NSSItem *identifier -); - /* Certificate cache routines */ NSS_EXTERN PRStatus diff --git a/mozilla/security/nss/lib/pki/pkinss3hack.h b/mozilla/security/nss/lib/pki/pkinss3hack.h index 3d1779d4ab3..9a36126166e 100644 --- a/mozilla/security/nss/lib/pki/pkinss3hack.h +++ b/mozilla/security/nss/lib/pki/pkinss3hack.h @@ -35,7 +35,7 @@ #define PKINSS3HACK_H #ifdef DEBUG -static const char PKINSS3HACK_CVS_ID[] = "@(#) $RCSfile: pkinss3hack.h,v $ $Revision: 1.1 $ $Date: 2001-10-11 16:34:46 $ $Name: not supported by cvs2svn $"; +static const char PKINSS3HACK_CVS_ID[] = "@(#) $RCSfile: pkinss3hack.h,v $ $Revision: 1.2 $ $Date: 2001-10-17 14:40:22 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef NSSPKIT_H @@ -64,6 +64,37 @@ STAN_AddNewSlotToDefaultTD NSS_EXTERN CERTCertificate * STAN_GetCERTCertificate(NSSCertificate *c); +NSS_EXTERN NSSCertificate * +STAN_GetNSSCertificate(CERTCertificate *c); + +/* This function is being put here because it is a hack for + * PK11_FindCertFromNickname. + */ +NSS_EXTERN NSSCertificate * +nssTrustDomain_FindBestCertificateByNicknameForToken +( + NSSTrustDomain *td, + NSSToken *token, + NSSUTF8 *name, + NSSTime *timeOpt, /* NULL for "now" */ + NSSUsage *usage, + NSSPolicies *policiesOpt /* NULL for none */ +); + +/* This function is being put here because it is a hack for + * PK11_FindCertsFromNickname. + */ +NSS_EXTERN NSSCertificate ** +nssTrustDomain_FindCertificatesByNicknameForToken +( + NSSTrustDomain *td, + NSSToken *token, + NSSUTF8 *name, + NSSCertificate *rvOpt[], + PRUint32 maximumOpt, /* 0 for no max */ + NSSArena *arenaOpt +); + PR_END_EXTERN_C #endif /* PKINSS3HACK_H */ diff --git a/mozilla/security/nss/lib/pki/pkitm.h b/mozilla/security/nss/lib/pki/pkitm.h index 82ff58d5b73..f313b5c6be8 100644 --- a/mozilla/security/nss/lib/pki/pkitm.h +++ b/mozilla/security/nss/lib/pki/pkitm.h @@ -35,7 +35,7 @@ #define PKITM_H #ifdef DEBUG -static const char PKITM_CVS_ID[] = "@(#) $RCSfile: pkitm.h,v $ $Revision: 1.1 $ $Date: 2001-10-11 16:34:49 $ $Name: not supported by cvs2svn $"; +static const char PKITM_CVS_ID[] = "@(#) $RCSfile: pkitm.h,v $ $Revision: 1.2 $ $Date: 2001-10-17 14:40:22 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ /* @@ -65,10 +65,12 @@ PR_BEGIN_EXTERN_C struct nssDecodedCertStr { NSSCertificateType type; void *data; - /* returns the unique identifier for the cert (usually issuer + serial) */ + /* returns the unique identifier for the cert */ NSSItem * (*getIdentifier)(nssDecodedCert *dc); /* returns the unique identifier for this cert's issuer */ NSSItem * (*getIssuerIdentifier)(nssDecodedCert *dc); + /* is id the identifier for this cert? */ + PRBool (*hasThisIdentifier)(nssDecodedCert *dc, NSSItem *id); /* returns the cert usage */ NSSUsage * (*getUsage)(nssDecodedCert *dc); /* is time within the validity period of the cert? */ diff --git a/mozilla/security/nss/lib/pki/tdcache.c b/mozilla/security/nss/lib/pki/tdcache.c index 8fff7870eab..996f97ea8b4 100644 --- a/mozilla/security/nss/lib/pki/tdcache.c +++ b/mozilla/security/nss/lib/pki/tdcache.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.4 $ $Date: 2001-10-15 17:18:06 $ $Name: not supported by cvs2svn $"; +static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.5 $ $Date: 2001-10-17 14:40:23 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef PKIM_H @@ -227,21 +227,23 @@ add_cert_to_cache(NSSTrustDomain *td, NSSCertificate *cert) nssrv = nssHash_Add(td->cache->nickname, nickname, subjectList); if (nssrv != PR_SUCCESS) goto loser; /* email */ - subjects = (nssList *)nssHash_Lookup(td->cache->email, cert->email); - if (subjects) { - /* The email address is already hashed, add this subject list */ - nssrv = nssList_Add(subjects, subjectList); - if (nssrv != PR_SUCCESS) goto loser; - } else { - /* Create a new list of subject lists, add this subject */ - subjects = nssList_Create(td->arena, PR_TRUE); - if (!subjects) goto loser; - nssrv = nssList_Add(subjects, subjectList); - if (nssrv != PR_SUCCESS) goto loser; - /* Add the list of subject lists to the hash */ - email = nssUTF8_Duplicate(cert->email, td->arena); - nssrv = nssHash_Add(td->cache->email, email, subjects); - if (nssrv != PR_SUCCESS) goto loser; + if (cert->email) { + subjects = (nssList *)nssHash_Lookup(td->cache->email, cert->email); + if (subjects) { + /* The email address is already hashed, add this subject list */ + nssrv = nssList_Add(subjects, subjectList); + if (nssrv != PR_SUCCESS) goto loser; + } else { + /* Create a new list of subject lists, add this subject */ + subjects = nssList_Create(td->arena, PR_TRUE); + if (!subjects) goto loser; + nssrv = nssList_Add(subjects, subjectList); + if (nssrv != PR_SUCCESS) goto loser; + /* Add the list of subject lists to the hash */ + email = nssUTF8_Duplicate(cert->email, td->arena); + nssrv = nssHash_Add(td->cache->email, email, subjects); + if (nssrv != PR_SUCCESS) goto loser; + } } } nssrv = nssArena_Unmark(td->arena, mark); diff --git a/mozilla/security/nss/lib/pki/trustdomain.c b/mozilla/security/nss/lib/pki/trustdomain.c index 2ec4c3d2679..2b8bd674031 100644 --- a/mozilla/security/nss/lib/pki/trustdomain.c +++ b/mozilla/security/nss/lib/pki/trustdomain.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.9 $ $Date: 2001-10-12 17:54:50 $ $Name: not supported by cvs2svn $"; +static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.10 $ $Date: 2001-10-17 14:40:27 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef NSSPKI_H @@ -211,8 +211,18 @@ NSSTrustDomain_FindTokenByName NSSUTF8 *tokenName ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + PRStatus nssrv; + NSSUTF8 *myName; + NSSToken *tok = NULL; + for (tok = (NSSToken *)nssListIterator_Start(td->tokens); + tok != (NSSToken *)NULL; + tok = (NSSToken *)nssListIterator_Next(td->tokens)) + { + myName = nssToken_GetName(tok); + if (nssUTF8_Equal(tokenName, myName, &nssrv)) break; + } + nssListIterator_Finish(td->tokens); + return tok; } NSS_IMPLEMENT NSSToken * @@ -356,13 +366,39 @@ static PRStatus get_best_cert(NSSCertificate *c, void *arg) { struct get_best_cert_arg_str *best = (struct get_best_cert_arg_str *)arg; + nssDecodedCert *dc, *bestdc; if (!best->cert) { /* This is the first matching cert found, so it is the best so far */ best->cert = c; return PR_SUCCESS; } + dc = nssCertificate_GetDecoding(c); + bestdc = nssCertificate_GetDecoding(best->cert); /* usage */ + /* XXX something like NSSUsage_MatchUsage() maybe? */ /* time */ + if (bestdc->isValidAtTime(bestdc, best->time)) { + /* The current best cert is valid at time */ + if (!dc->isValidAtTime(dc, best->time)) { + /* If the new cert isn't valid at time, it's not better */ + return PR_SUCCESS; + } + } else { + /* The current best cert is not valid at time */ + if (dc->isValidAtTime(dc, best->time)) { + /* If the new cert is valid at time, it's better */ + best->cert = c; + return PR_SUCCESS; + } + } + /* either they are both valid at time, or neither valid; take the newer */ + /* XXX later -- defer to policies */ + if (bestdc->isNewerThan(bestdc, dc)) { + return PR_SUCCESS; + } else { + best->cert = c; + return PR_SUCCESS; + } /* policies */ return PR_SUCCESS; } @@ -371,6 +407,7 @@ static NSSCertificate * find_best_cert_for_template ( NSSTrustDomain *td, + NSSToken *token, struct get_best_cert_arg_str *best, CK_ATTRIBUTE_PTR cktemplate, CK_ULONG ctsize @@ -378,15 +415,23 @@ find_best_cert_for_template { 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, + if (token) { + nssrv = nssToken_FindCertificatesByTemplate(token, NULL, best->cached, cktemplate, ctsize, - get_best_cert, &best); + get_best_cert, best); + } else { + 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); } - nssListIterator_Finish(td->tokens); + /* Cache the cert before returning */ + nssTrustDomain_AddCertsToCache(td, &best->cert, 1); return best->cert; } @@ -417,6 +462,7 @@ static NSSCertificate ** find_all_certs_for_template ( NSSTrustDomain *td, + NSSToken *token, struct collect_arg_str *ca, CK_ATTRIBUTE_PTR cktemplate, CK_ULONG ctsize @@ -426,15 +472,21 @@ find_all_certs_for_template 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, + if (token) { + nssrv = nssToken_FindCertificatesByTemplate(token, NULL, ca->list, cktemplate, ctsize, collect_certs, ca); + } else { + 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); } - nssListIterator_Finish(td->tokens); count = nssList_Count(ca->list); if (ca->rvOpt) { certs = ca->rvOpt; @@ -442,9 +494,67 @@ find_all_certs_for_template certs = nss_ZNEWARRAY(ca->arena, NSSCertificate *, count + 1); } nssrv = nssList_GetArray(ca->list, (void **)certs, count); + /* Cache the certs before returning */ + nssTrustDomain_AddCertsToCache(td, certs, count); return certs; } +/* XXX + * This is really a hack for PK11_ calls that want to specify the token to + * do lookups on (see PK11_FindCertFromNickname). I don't think this + * is something we want to keep. + */ +NSS_IMPLEMENT NSSCertificate * +nssTrustDomain_FindBestCertificateByNicknameForToken +( + NSSTrustDomain *td, + NSSToken *token, + NSSUTF8 *name, + NSSTime *timeOpt, /* NULL for "now" */ + NSSUsage *usage, + NSSPolicies *policiesOpt /* NULL for none */ +) +{ + NSSCertificate *rvCert = NULL; + PRStatus nssrv; + struct get_best_cert_arg_str best; + CK_ATTRIBUTE nick_template[] = + { + { CKA_CLASS, NULL, 0 }, + { CKA_LABEL, NULL, 0 } + }; + CK_ULONG ctsize; + 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; + /* 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, token, + &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? + */ + nick_template[1].ulValueLen++; + rvCert = find_best_cert_for_template(td, token, + &best, nick_template, ctsize); + } + nssList_Destroy(nameList); + return rvCert; +} + NSS_IMPLEMENT NSSCertificate * NSSTrustDomain_FindBestCertificateByNickname ( @@ -481,18 +591,61 @@ NSSTrustDomain_FindBestCertificateByNickname (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); + rvCert = find_best_cert_for_template(td, NULL, + &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? */ nick_template[1].ulValueLen++; - rvCert = find_best_cert_for_template(td, &best, nick_template, ctsize); + rvCert = find_best_cert_for_template(td, NULL, + &best, nick_template, ctsize); } nssList_Destroy(nameList); return rvCert; } +/* XXX + * This is really a hack for PK11_ calls that want to specify the token to + * do lookups on (see PK11_FindCertsFromNickname). I don't think this + * is something we want to keep. + */ +NSS_IMPLEMENT NSSCertificate ** +nssTrustDomain_FindCertificatesByNicknameForToken +( + NSSTrustDomain *td, + NSSToken *token, + NSSUTF8 *name, + NSSCertificate *rvOpt[], + PRUint32 maximumOpt, /* 0 for no max */ + NSSArena *arenaOpt +) +{ + NSSCertificate **rvCerts = NULL; + PRStatus nssrv; + 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(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; + ca.rvOpt = rvOpt; + rvCerts = find_all_certs_for_template(td, token, + &ca, nick_template, ctsize); + nssList_Destroy(nickCerts); + return rvCerts; +} + NSS_IMPLEMENT NSSCertificate ** NSSTrustDomain_FindCertificatesByNickname ( @@ -522,28 +675,12 @@ NSSTrustDomain_FindCertificatesByNickname ca.maximum = maximumOpt; ca.arena = arenaOpt; ca.rvOpt = rvOpt; - rvCerts = find_all_certs_for_template(td, &ca, nick_template, ctsize); + rvCerts = find_all_certs_for_template(td, NULL, + &ca, nick_template, ctsize); nssList_Destroy(nickCerts); return rvCerts; } -NSS_IMPLEMENT NSSCertificate * -nssTrustDomain_FindCertificateByIdentifier -( - NSSTrustDomain *td, - NSSItem *identifier -) -{ - NSSCertificate *rvCert; - /* Try the cache */ - rvCert = nssTrustDomain_GetCertForIdentifierFromCache(td, identifier); - if (!rvCert) { - /* uh, how to look up by id in PKCS#11? */ - rvCert = NULL; - } - return rvCert; -} - NSS_IMPLEMENT NSSCertificate * NSSTrustDomain_FindCertificateByIssuerAndSerialNumber ( @@ -580,7 +717,7 @@ NSSTrustDomain_FindCertificateByIssuerAndSerialNumber cert_template, ctsize); if (object != CK_INVALID_KEY) { /* Could not find cert, so create it */ - rvCert = NSSCertificate_CreateFromHandle(NULL, object, + rvCert = nssCertificate_CreateFromHandle(NULL, object, NULL, tok->slot); if (rvCert) { /* cache it */ @@ -625,7 +762,8 @@ NSSTrustDomain_FindBestCertificateBySubject (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); + rvCert = find_best_cert_for_template(td, NULL, + &best, subj_template, ctsize); nssList_Destroy(subjectList); return rvCert; } @@ -658,7 +796,8 @@ NSSTrustDomain_FindCertificatesBySubject ca.maximum = maximumOpt; ca.arena = arenaOpt; ca.rvOpt = rvOpt; - rvCerts = find_all_certs_for_template(td, &ca, subj_template, ctsize); + rvCerts = find_all_certs_for_template(td, NULL, + &ca, subj_template, ctsize); nssList_Destroy(subjectList); return rvCerts; } @@ -721,7 +860,7 @@ NSSTrustDomain_FindCertificateByEncodedCertificate cert_template, ctsize); if (object != CK_INVALID_KEY) { /* Could not find cert, so create it */ - rvCert = NSSCertificate_CreateFromHandle(NULL, object, + rvCert = nssCertificate_CreateFromHandle(NULL, object, NULL, tok->slot); if (rvCert) { /* cache it */