diff --git a/security/nss/lib/pki/certdecode.c b/security/nss/lib/pki/certdecode.c new file mode 100644 index 000000000000..e73cf2565c1d --- /dev/null +++ b/security/nss/lib/pki/certdecode.c @@ -0,0 +1,151 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile: certdecode.c,v $ $Revision: 1.1 $ $Date: 2001/10/11 16:34:44 $ $Name: $"; +#endif /* DEBUG */ + +#ifndef PKIT_H +#include "pkit.h" +#endif /* PKIT_H */ + +#ifndef PKIM_H +#include "pkim.h" +#endif /* PKIM_H */ + +#ifdef NSS_3_4_CODE +/* This is defined in nss3hack.c */ +NSS_EXTERN nssDecodedCert * +nssDecodedPKIXCertificate_Create +( + NSSArena *arenaOpt, + NSSDER *encoding +); + +NSS_IMPLEMENT PRStatus +nssDecodedPKIXCertificate_Destroy +( + nssDecodedCert *dc +); +#else /* NSS_4_0_CODE */ +/* This is where 4.0 PKIX code will handle the decoding */ +static nssDecodedCert * +nssDecodedPKIXCertificate_Create +( + NSSArena *arenaOpt, + NSSDER *encoding +) +{ + return (nssDecodedCert *)NULL; +} + +static PRStatus +nssDecodedPKIXCertificate_Destroy +( + nssDecodedCert *dc +) +{ + return PR_FAILURE; +} +#endif /* not NSS_3_4_CODE */ + +NSS_IMPLEMENT nssDecodedCert * +nssDecodedCert_Create +( + NSSArena *arenaOpt, + NSSDER *encoding, + NSSCertificateType type +) +{ + nssDecodedCert *rvDC = NULL; + switch(type) { + case NSSCertificateType_PKIX: + rvDC = nssDecodedPKIXCertificate_Create(arenaOpt, encoding); + break; + default: +#if 0 + nss_SetError(NSS_ERROR_INVALID_ARGUMENT); +#endif + return (nssDecodedCert *)NULL; + } + return rvDC; +} + +NSS_IMPLEMENT PRStatus +nssDecodedCert_Destroy +( + nssDecodedCert *dc +) +{ + switch(dc->type) { + case NSSCertificateType_PKIX: + return nssDecodedPKIXCertificate_Destroy(dc); + default: +#if 0 + nss_SetError(NSS_ERROR_INVALID_ARGUMENT); +#endif + return PR_FAILURE; + } + return PR_FAILURE; +} + +/* Of course none of this belongs here */ + +struct NSSTimeStr { + PRTime prTime; +}; + +/* how bad would it be to have a static now sitting around, updated whenever + * this was called? would avoid repeated allocs... + */ +NSS_IMPLEMENT NSSTime * +NSSTime_Now +( + NSSTime *timeOpt +) +{ + NSSTime *rvTime; + rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime); + rvTime->prTime = PR_Now(); + return rvTime; +} + +NSS_IMPLEMENT PRTime +NSSTime_GetPRTime +( + NSSTime *time +) +{ + return time->prTime; +} + diff --git a/security/nss/lib/pki/certificate.c b/security/nss/lib/pki/certificate.c index b0f7c35c3f96..a366d44fd75a 100644 --- a/security/nss/lib/pki/certificate.c +++ b/security/nss/lib/pki/certificate.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.4 $ $Date: 2001/09/20 20:40:03 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.5 $ $Date: 2001/10/11 16:34:44 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSPKI_H @@ -43,10 +43,36 @@ static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.4 $ #include "pkit.h" #endif /* PKIT_H */ +#ifndef PKIM_H +#include "pkim.h" +#endif /* PKIM_H */ + +#ifndef DEV_H +#include "dev.h" +#endif /* DEV_H */ + #ifndef CKHELPER_H #include "ckhelper.h" #endif /* CKHELPER_H */ +#ifndef CKT_H +#ifdef NSS_3_4_CODE +#define NSSCKT_H +#endif +#include "ckt.h" +#endif /* CKT_H */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +/* Hm, sadly, I'm using PK11_HashBuf... Need to get crypto context going to + * get rid of that + */ +#define NSS_3_4_CODE +#include "pk11func.h" +#include "hasht.h" + /* I assume the following accessors into cert fields will be needed. * We need to be able to return basic cert info, however, these are * really PKCS#11 fields, so maybe not these in particular (mcgreer) @@ -57,10 +83,7 @@ NSSCertificate_GetLabel NSSCertificate *c ) { - NSSUTF8 *rvStr; - rvStr = nssUTF8_Create(NULL, nssStringType_PrintableString, - c->label.data, c->label.size); - return rvStr; + return c->nickname; } NSS_IMPLEMENT NSSItem * @@ -72,6 +95,16 @@ NSSCertificate_GetID return &c->id; } +NSS_IMPLEMENT NSSCertificate * +nssCertificate_AddRef +( + NSSCertificate *c +) +{ + c->refCount++; + return c; +} + /* NSS needs access to this function, but does anyone else? */ static NSSCertificate * NSSCertificate_Create @@ -105,6 +138,65 @@ loser: return (NSSCertificate *)NULL; } +static NSSCertificateType +nss_cert_type_from_ck_attrib(CK_ATTRIBUTE_PTR attrib) +{ + CK_CERTIFICATE_TYPE ckCertType; + ckCertType = *((CK_ULONG *)attrib->pValue); + switch (ckCertType) { + case CKC_X_509: + return NSSCertificateType_PKIX; + break; + default: + return NSSCertificateType_Unknown; + } + return NSSCertificateType_Unknown; +} + +static PRStatus +nssCertificate_SetCertTrust +( + NSSCertificate *c, + nssSession *session +) +{ + PRStatus nssrv; + CK_TRUST saTrust, epTrust, csTrust; + CK_ULONG tobj_size, trust_size; + CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; + CK_OBJECT_HANDLE tobjID; + CK_ATTRIBUTE tobj_template[] = { + { CKA_CLASS, &tobjc, sizeof(CK_OBJECT_CLASS) }, + { CKA_CERT_SHA1_HASH, NULL, 0 } + }; + CK_ATTRIBUTE trust_template[] = { + { CKA_TRUST_SERVER_AUTH, &saTrust, sizeof(CK_TRUST) }, + { CKA_TRUST_EMAIL_PROTECTION, &epTrust, sizeof(CK_TRUST) }, + { CKA_TRUST_CODE_SIGNING, &csTrust, sizeof(CK_TRUST) } + }; + unsigned char sha1_hash[SHA1_LENGTH]; + tobj_size = sizeof(tobj_template) / sizeof(tobj_template[0]); + trust_size = sizeof(trust_template) / sizeof(trust_template[0]); + /* First, use the SHA-1 hash of the cert to locate the trust object */ + /* XXX get rid of this PK11_ call! */ + PK11_HashBuf(SEC_OID_SHA1, sha1_hash, c->encoding.data, c->encoding.size); + tobj_template[1].pValue = (void *)sha1_hash; + tobj_template[1].ulValueLen = SHA1_LENGTH; + tobjID = nssToken_FindObjectByTemplate(c->token, session, + tobj_template, tobj_size); + if (tobjID == CK_INVALID_KEY) { + return PR_FAILURE; + } + /* Then use the trust object to find the trust settings */ + nssrv = nssCKObject_GetAttributes(tobjID, + trust_template, trust_size, + NULL, session, c->slot); + c->trust.serverAuth = saTrust; + c->trust.emailProtection = epTrust; + c->trust.codeSigning = csTrust; + return PR_SUCCESS; +} + /* Create a certificate from an object handle. */ NSS_IMPLEMENT NSSCertificate * NSSCertificate_CreateFromHandle @@ -116,13 +208,16 @@ NSSCertificate_CreateFromHandle ) { NSSCertificate *rvCert; - NSSArena *arena; PRStatus nssrv; CK_ULONG template_size; CK_ATTRIBUTE cert_template[] = { - { CKA_ID, NULL, 0 }, - { CKA_VALUE, NULL, 0 }, - { CKA_LABEL, NULL, 0 }, + { CKA_CERTIFICATE_TYPE, NULL, 0 }, + { CKA_ID, NULL, 0 }, + { CKA_VALUE, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_ISSUER, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, + { CKA_SERIAL_NUMBER, NULL, 0 } }; template_size = sizeof(cert_template) / sizeof(cert_template[0]); rvCert = NSSCertificate_Create(arenaOpt); @@ -131,17 +226,24 @@ NSSCertificate_CreateFromHandle } rvCert->handle = object; rvCert->slot = slot; + rvCert->token = slot->token; nssrv = nssCKObject_GetAttributes(object, cert_template, template_size, - rvCert->arena, session, rvCert->slot); + rvCert->arena, session, slot); if (nssrv) { /* okay, but if failed because one of the attributes could not be * found, do it gracefully (i.e., catch the error). */ goto loser; } - NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[0], &rvCert->id); - NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[1], &rvCert->der); - NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[2], &rvCert->label); + rvCert->type = nss_cert_type_from_ck_attrib(&cert_template[0]); + NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[1], &rvCert->id); + NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[2], &rvCert->encoding); + NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[3], rvCert->nickname); + NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[4], &rvCert->issuer); + 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 */ + nssCertificate_SetCertTrust(rvCert, session); return rvCert; loser: NSSCertificate_Destroy(rvCert); @@ -167,8 +269,13 @@ NSSCertificate_DeleteStoredObject NSSCallback *uhh ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return PR_FAILURE; + /* delete it from storage, but leave it in memory */ + /* according to PKCS#11 2.11 section 13.2, the token must know how + * to handle deletion when there are multiple threads attempting to use + * the same object. + */ + /* XXX use callback to log in if neccessary */ + return nssToken_DeleteStoredObject(c->token, NULL, c->handle); } NSS_IMPLEMENT PRStatus @@ -226,8 +333,22 @@ NSSCertificate_Encode NSSArena *arenaOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + /* Item, DER, BER are all typedefs now... */ + return nssItem_Duplicate((NSSItem *)&c->encoding, arenaOpt, rvOpt); +} + +static nssDecodedCert * +nssCertificate_GetDecoding +( + NSSCertificate *c +) +{ + 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; } NSS_IMPLEMENT NSSCertificate ** @@ -242,8 +363,53 @@ NSSCertificate_BuildChain NSSArena *arenaOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + PRStatus nssrv; + nssList *chain; + NSSItem *issuerID; + NSSCertificate **rvChain; + nssDecodedCert *dc; + chain = nssList_Create(NULL, PR_FALSE); + nssList_Add(chain, c); + if (rvLimit == 1) goto finish; + while (!nssItem_Equal(&c->subject, &c->issuer, &nssrv)) { + dc = nssCertificate_GetDecoding(c); + issuerID = dc->getIssuerIdentifier(dc); + if (issuerID) { + c = nssTrustDomain_FindCertificateByIdentifier(c->trustDomain, + issuerID); + nss_ZFreeIf(issuerID); + if (!c) { +#if 0 + nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND); +#endif + goto finish; + } + } else { + c = NSSTrustDomain_FindBestCertificateBySubject(c->trustDomain, + &c->issuer, + timeOpt, + usage, + policiesOpt); + if (!c) { +#if 0 + nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND); +#endif + goto finish; + } + } + nssList_Add(chain, c); + if (nssList_Count(chain) == rvLimit) goto finish; + } +finish: + if (rvOpt) { + rvChain = rvOpt; + } else { + rvChain = nss_ZNEWARRAY(arenaOpt, + NSSCertificate *, nssList_Count(chain)); + } + nssList_GetArray(chain, (void **)rvChain, rvLimit); + nssList_Destroy(chain); + return rvChain; } NSS_IMPLEMENT NSSTrustDomain * @@ -252,8 +418,12 @@ NSSCertificate_GetTrustDomain NSSCertificate *c ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; +#if 0 + if (c->trustDomain) { + return nssTrustDomain_AddRef(c->trustDomain); + } +#endif + return (NSSTrustDomain *)NULL; } NSS_IMPLEMENT NSSToken * @@ -263,8 +433,10 @@ NSSCertificate_GetToken PRStatus *statusOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + if (c->token) { + return nssToken_AddRef(c->token); + } + return (NSSToken *)NULL; } NSS_IMPLEMENT NSSSlot * @@ -274,8 +446,12 @@ NSSCertificate_GetSlot PRStatus *statusOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; +#if 0 + if (c->token) { + return nssToken_GetSlot(c->token); + } +#endif + return (NSSSlot *)NULL; } NSS_IMPLEMENT NSSModule * @@ -285,8 +461,12 @@ NSSCertificate_GetModule PRStatus *statusOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; +#if 0 + if (c->token) { + return nssToken_GetModule(c->token); + } +#endif + return (NSSModule *)NULL; } NSS_IMPLEMENT NSSItem * @@ -381,8 +561,35 @@ NSSCertificate_GetPublicKey NSSCertificate *c ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + PRStatus nssrv; + CK_ATTRIBUTE pubktemplate[] = { + { CKA_CLASS, g_ck_class_pubkey.data, g_ck_class_pubkey.size }, + { CKA_ID, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 } + }; + CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]); + if (c->id.size > 0) { + /* CKA_ID */ + NSS_CK_ITEM_TO_ATTRIBUTE(&c->id, &pubktemplate[1]); + } else { + /* failure, yes? */ + return (NSSPublicKey *)NULL; + } + if (c->subject.size > 0) { + /* CKA_SUBJECT */ + NSS_CK_ITEM_TO_ATTRIBUTE(&c->subject, &pubktemplate[2]); + } else { + /* failure, yes? */ + return (NSSPublicKey *)NULL; + } + /* Try the cert's token first */ +#if 0 + if (c->token) { + nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count); + } +#endif + /* Try all other key tokens */ + return (NSSPublicKey *)NULL; } NSS_IMPLEMENT NSSPrivateKey * diff --git a/security/nss/lib/pki/cryptocontext.c b/security/nss/lib/pki/cryptocontext.c index 69dc9e6ec580..5a01a7f440a2 100644 --- a/security/nss/lib/pki/cryptocontext.c +++ b/security/nss/lib/pki/cryptocontext.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: cryptocontext.c,v $ $Revision: 1.2 $ $Date: 2001/09/13 22:16:21 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: cryptocontext.c,v $ $Revision: 1.3 $ $Date: 2001/10/11 16:34:44 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSPKI_H @@ -421,6 +421,36 @@ NSSCryptoContext_FindSymmetricKeyByAlgorithmAndKeyID return NULL; } +struct token_session_str { + NSSToken *token; + nssSession *session; +}; + +static nssSession * +get_token_session(NSSCryptoContext *cc, NSSToken *tok) +{ +#if 0 + struct token_session_str *ts; + for (ts = (struct token_session_str *)nssListIterator_Start(cc->sessions); + ts != (struct token_session_str *)NULL; + ts = (struct token_session_str *)nssListIterator_Next(cc->sessions)) + { + if (ts->token == tok) { /* will this need to be more general? */ + break; + } + } + nssListIterator_Finish(cc->sessions); + if (!ts) { + /* need to create a session for this token. */ + ts = nss_ZNEW(NULL, struct token_session_str); + ts->token = nssToken_AddRef(tok); + ts->session = nssSlot_CreateSession(tok->slot, cc->arena, PR_FALSE); + nssList_AddElement(cc->sessionList, (void *)ts); + } + return ts->session; +#endif +} + NSS_IMPLEMENT NSSItem * NSSCryptoContext_Decrypt ( @@ -432,8 +462,58 @@ NSSCryptoContext_Decrypt NSSArena *arenaOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; +#if 0 + NSSToken *tok; + nssSession *session; + NSSItem *rvData; + PRUint32 dataLen; + NSSAlgorithmAndParameters *ap; + CK_RV ckrv; + ap = (apOpt) ? apOpt : cc->defaultAlgorithm; + /* Get the token for this operation */ + tok = nssTrustDomain_GetCryptoToken(cc->trustDomain, ap); + if (!tok) { + return (NSSItem *)NULL; + } + /* Get the local session for this token */ + session = get_token_session(cc, tok); + /* Get the key needed to decrypt */ + keyHandle = get_decrypt_key(cc, ap); + /* Set up the decrypt operation */ + ckrv = CKAPI(tok)->C_DecryptInit(session->handle, + &ap->mechanism, keyHandle); + if (ckrv != CKR_OK) { + /* handle PKCS#11 error */ + return (NSSItem *)NULL; + } + /* Get the length of the output buffer */ + ckrv = CKAPI(tok)->C_Decrypt(session->handle, + (CK_BYTE_PTR)encryptedData->data, + (CK_ULONG)encryptedData->size, + (CK_BYTE_PTR)NULL, + (CK_ULONG_PTR)&dataLen); + if (ckrv != CKR_OK) { + /* handle PKCS#11 error */ + return (NSSItem *)NULL; + } + /* Alloc return value memory */ + rvData = nssItem_Create(NULL, NULL, dataLen, NULL); + if (!rvItem) { + return (NSSItem *)NULL; + } + /* Do the decryption */ + ckrv = CKAPI(tok)->C_Decrypt(cc->session->handle, + (CK_BYTE_PTR)encryptedData->data, + (CK_ULONG)encryptedData->size, + (CK_BYTE_PTR)rvData->data, + (CK_ULONG_PTR)&dataLen); + if (ckrv != CKR_OK) { + /* handle PKCS#11 error */ + nssItem_ZFreeIf(rvData); + return (NSSItem *)NULL; + } + return rvData; +#endif } NSS_IMPLEMENT PRStatus diff --git a/security/nss/lib/pki/manifest.mn b/security/nss/lib/pki/manifest.mn index aff7d96b6425..6c904d7de16f 100644 --- a/security/nss/lib/pki/manifest.mn +++ b/security/nss/lib/pki/manifest.mn @@ -30,7 +30,7 @@ # may use your version of this file under either the MPL or the # GPL. # -MANIFEST_CVS_ID = "@(#) $RCSfile: manifest.mn,v $ $Revision: 1.2 $ $Date: 2001/09/13 22:16:21 $ $Name: $" +MANIFEST_CVS_ID = "@(#) $RCSfile: manifest.mn,v $ $Revision: 1.3 $ $Date: 2001/10/11 16:34:44 $ $Name: $" CORE_DEPTH = ../../.. @@ -52,8 +52,16 @@ CSRCS = \ cryptocontext.c \ symmkey.c \ trustdomain.c \ + tdcache.c \ + certdecode.c \ $(NULL) +ifndef PURE_STAN_BUILD +CSRCS += nss3hack.c +PRIVATE_EXPORTS += pkinss3hack.h +DEFINES = -DNSS_3_4_CODE +endif + REQUIRES = security nspr LIBRARY_NAME = nsspki diff --git a/security/nss/lib/pki/nss3hack.c b/security/nss/lib/pki/nss3hack.c new file mode 100644 index 000000000000..91f82eeb0c02 --- /dev/null +++ b/security/nss/lib/pki/nss3hack.c @@ -0,0 +1,309 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile: nss3hack.c,v $ $Revision: 1.1 $ $Date: 2001/10/11 16:34:44 $ $Name: $"; +#endif /* DEBUG */ + +/* + * Hacks to integrate NSS 3.4 and NSS 4.0 certificates. + */ + +#ifndef NSSPKI_H +#include "nsspki.h" +#endif /* NSSPKI_H */ + +#ifndef PKIM_H +#include "pkim.h" +#endif /* PKIM_H */ + +#ifndef DEVT_H +#include "devt.h" +#endif /* DEVT_H */ + +#ifndef DEVNSS3HACK_H +#include "devnss3hack.h" +#endif /* DEVNSS3HACK_H */ + +#ifndef PKINSS3HACK_H +#include "pkinss3hack.h" +#endif /* PKINSS3HACK_H */ + +#include "secitem.h" +#include "certdb.h" +#include "certt.h" +#include "cert.h" +#include "pk11func.h" + +#define NSSITEM_FROM_SECITEM(nssit, secit) \ + (nssit)->data = (void *)(secit)->data; \ + (nssit)->size = (secit)->len; + +#define SECITEM_FROM_NSSITEM(secit, nssit) \ + (secit)->data = (unsigned char *)(nssit)->data; \ + (secit)->len = (nssit)->size; + +NSSTrustDomain *g_default_trust_domain = NULL; + +NSSTrustDomain * +STAN_GetDefaultTrustDomain() +{ + return g_default_trust_domain; +} + +NSS_IMPLEMENT void +STAN_LoadDefaultNSS3TrustDomain +( + void +) +{ + NSSTrustDomain *td; + NSSToken *token; + PK11SlotList *list; + PK11SlotListElement *le; + td = NSSTrustDomain_Create(NULL, NULL, NULL, NULL); + if (!td) { + /* um, some kind a fatal here */ + return; + } + td->tokenList = nssList_Create(td->arena, PR_TRUE); + list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, NULL); + if (list) { +#if 0 + /* 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); + PK11Slot_SetNSSToken(le->slot, token); + nssList_Add(td->tokenList, token); + } +#endif + } + td->tokens = nssList_CreateIterator(td->tokenList); + g_default_trust_domain = td; +} + +NSS_IMPLEMENT PRStatus +STAN_AddNewSlotToDefaultTD +( + PK11SlotInfo *sl +) +{ + NSSToken *token; + token = nssToken_CreateFromPK11SlotInfo(g_default_trust_domain, sl); + PK11Slot_SetNSSToken(sl, token); + nssList_Add(g_default_trust_domain->tokenList, token); + return PR_SUCCESS; +} + +/* this function should not be a hack; it will be needed in 4.0 (rename) */ +NSS_IMPLEMENT NSSItem * +STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der) +{ + NSSItem *rvKey; + SECItem secDER; + SECItem secKey = { 0 }; + SECStatus secrv; + SECITEM_FROM_NSSITEM(&secDER, der); + secrv = CERT_KeyFromDERCert(NULL, &secDER, &secKey); + rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data); + return rvKey; +} + +static NSSItem * +nss3certificate_getIdentifier(nssDecodedCert *dc) +{ + NSSItem *rvID; + CERTCertificate *c = (CERTCertificate *)dc->data; + rvID = nssItem_Create(NULL, NULL, c->certKey.len, c->certKey.data); + return rvID; +} + +static NSSItem * +nss3certificate_getIssuerIdentifier(nssDecodedCert *dc) +{ + CERTCertificate *c = (CERTCertificate *)dc->data; + CERTAuthKeyID *cAuthKeyID; + PRArenaPool *tmpArena = NULL; + SECItem issuerCertKey; + SECItem *identifier = NULL; + NSSItem *rvID = NULL; + SECStatus secrv; + tmpArena = PORT_NewArena(512); + cAuthKeyID = CERT_FindAuthKeyIDExten(tmpArena, c); + if (cAuthKeyID) { + if (cAuthKeyID->keyID.data) { + identifier = &cAuthKeyID->keyID; + } else if (cAuthKeyID->authCertIssuer) { + SECItem *caName; + caName = (SECItem *)CERT_GetGeneralNameByType( + cAuthKeyID->authCertIssuer, + certDirectoryName, PR_TRUE); + if (caName) { + secrv = CERT_KeyFromIssuerAndSN(tmpArena, caName, + &cAuthKeyID->authCertSerialNumber, + &issuerCertKey); + if (secrv == SECSuccess) { + identifier = &issuerCertKey; + } + } + } + } + if (identifier) { + rvID = nssItem_Create(NULL, NULL, identifier->len, identifier->data); + } + if (tmpArena) PORT_FreeArena(tmpArena, PR_FALSE); + return rvID; +} + +static NSSUsage * +nss3certificate_getUsage(nssDecodedCert *dc) +{ + CERTCertificate *c = (CERTCertificate *)dc->data; + return NULL; +} + +static PRBool +nss3certificate_isValidAtTime(nssDecodedCert *dc, NSSTime *time) +{ + SECCertTimeValidity validity; + CERTCertificate *c = (CERTCertificate *)dc->data; + validity = CERT_CheckCertValidTimes(c, NSSTime_GetPRTime(time), PR_TRUE); + if (validity == secCertTimeValid) { + return PR_TRUE; + } + return PR_FALSE; +} + +static PRBool +nss3certificate_isNewerThan(nssDecodedCert *dc, nssDecodedCert *cmpdc) +{ + /* I know this isn't right, but this is glue code anyway */ + if (cmpdc->type == dc->type) { + CERTCertificate *certa = (CERTCertificate *)dc->data; + CERTCertificate *certb = (CERTCertificate *)cmpdc->data; + return CERT_IsNewer(certa, certb); + } + return PR_FALSE; +} + +NSS_IMPLEMENT nssDecodedCert * +nssDecodedPKIXCertificate_Create +( + NSSArena *arenaOpt, + NSSDER *encoding +) +{ + nssDecodedCert *rvDC; + SECItem secDER; + rvDC = nss_ZNEW(arenaOpt, nssDecodedCert); + rvDC->type = NSSCertificateType_PKIX; + SECITEM_FROM_NSSITEM(&secDER, encoding); + rvDC->data = (void *)CERT_DecodeDERCertificate(&secDER, PR_TRUE, NULL); + rvDC->getIdentifier = nss3certificate_getIdentifier; + rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; + rvDC->getUsage = nss3certificate_getUsage; + rvDC->isValidAtTime = nss3certificate_isValidAtTime; + rvDC->isNewerThan = nss3certificate_isNewerThan; + return rvDC; +} + +NSS_IMPLEMENT PRStatus +nssDecodedPKIXCertificate_Destroy +( + nssDecodedCert *dc +) +{ + /*CERT_DestroyCertificate((CERTCertificate *)dc->data);*/ + nss_ZFreeIf(dc); + return PR_SUCCESS; +} + +/* see pk11cert.c:pk11_HandleTrustObject */ +static unsigned int +get_nss3trust_from_cktrust(CK_TRUST t) +{ + unsigned int rt = 0; + if (t & CKT_NETSCAPE_TRUSTED) { + rt |= CERTDB_VALID_PEER | CERTDB_TRUSTED; + } + if (t & CKT_NETSCAPE_TRUSTED_DELEGATOR) { + rt |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; + } + if (t & CKT_NETSCAPE_VALID) { + rt |= CERTDB_VALID_PEER; + } + if (t & CKT_NETSCAPE_VALID_DELEGATOR) { + rt |= CERTDB_VALID_CA; + } + /* user */ + return rt; +} + +static CERTCertTrust * +NSSTrust_GetCERTCertTrust(NSSTrust *t) +{ + CERTCertTrust *rvTrust = nss_ZNEW(NULL, 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); + return rvTrust; +} + +NSS_EXTERN CERTCertificate * +STAN_GetCERTCertificate(NSSCertificate *c) +{ + nssDecodedCert *dc; + CERTCertificate *cc; + if (!c->decoding) { + dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding); + c->decoding = dc; + /* decoded, so cache */ + } else { + dc = c->decoding; + } + /* 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; +} + diff --git a/security/nss/lib/pki/nsspki.h b/security/nss/lib/pki/nsspki.h index 908d9bdbcf8e..3ec2bb26b5cf 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.3 $ $Date: 2001/09/13 22:16:21 $ $Name: $"; +static const char NSSPKI_CVS_ID[] = "@(#) $RCSfile: nsspki.h,v $ $Revision: 1.4 $ $Date: 2001/10/11 16:34:44 $ $Name: $"; #endif /* DEBUG */ /* @@ -44,9 +44,9 @@ static const char NSSPKI_CVS_ID[] = "@(#) $RCSfile: nsspki.h,v $ $Revision: 1.3 * This file prototypes the methods of the top-level PKI objects. */ -#ifndef DEVT_H -#include "devt.h" -#endif /* DEVT_H */ +#ifndef NSSDEVT_H +#include "nssdevt.h" +#endif /* NSSDEVT_H */ #ifndef NSSPKIT_H #include "nsspkit.h" diff --git a/security/nss/lib/pki/pki.h b/security/nss/lib/pki/pki.h index adeb36d923e2..d3810a764e2f 100644 --- a/security/nss/lib/pki/pki.h +++ b/security/nss/lib/pki/pki.h @@ -35,14 +35,24 @@ #define PKI_H #ifdef DEBUG -static const char PKI_CVS_ID[] = "@(#) $RCSfile: pki.h,v $ $Revision: 1.3 $ $Date: 2001/09/20 20:40:03 $ $Name: $"; +static const char PKI_CVS_ID[] = "@(#) $RCSfile: pki.h,v $ $Revision: 1.4 $ $Date: 2001/10/11 16:34:44 $ $Name: $"; #endif /* DEBUG */ +#ifndef PKIT_H +#include "pkit.h" +#endif /* PKIT_H */ + +#ifndef NSSDEVT_H +#include "nssdevt.h" +#endif /* NSSDEVT_H */ + PR_BEGIN_EXTERN_C -#ifndef DEVT_H -#include "devt.h" -#endif /* DEVT_H */ +NSS_EXTERN NSSCertificate * +nssCertificate_AddRef +( + NSSCertificate *c +); NSS_EXTERN NSSCertificate * NSSCertificate_CreateFromHandle @@ -65,6 +75,17 @@ 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 new file mode 100644 index 000000000000..69446018b708 --- /dev/null +++ b/security/nss/lib/pki/pkim.h @@ -0,0 +1,251 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef PKIM_H +#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: $"; +#endif /* DEBUG */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +#ifndef PKITM_H +#include "pkitm.h" +#endif /* PKITM_H */ + +PR_BEGIN_EXTERN_C + +/* Token ordering routines */ + +/* + * Given a crypto algorithm, return the preferred token for performing + * the crypto operation. + */ +NSS_EXTERN NSSToken * +nssTrustDomain_GetCryptoToken +( + NSSTrustDomain *td, + NSSAlgorithmAndParameters *ap +); + +/* The following routines are used to obtain the preferred token on which + * to store particular objects. + */ + +/* + * Find the preferred token for storing user certificates. + */ +NSS_EXTERN NSSToken * +nssTrustDomain_GetUserCertToken +( + NSSTrustDomain *td +); + +/* + * Find the preferred token for storing email certificates. + */ +NSS_EXTERN NSSToken * +nssTrustDomain_GetEmailCertToken +( + NSSTrustDomain *td +); + +/* + * Find the preferred token for storing SSL certificates. + */ +NSS_EXTERN NSSToken * +nssTrustDomain_GetSSLCertToken +( + NSSTrustDomain *td +); + +/* + * Find the preferred token for storing root certificates. + */ +NSS_EXTERN NSSToken * +nssTrustDomain_GetRootCertToken +( + NSSTrustDomain *td +); + +/* + * Find the preferred token for storing private keys. + */ +NSS_EXTERN NSSToken * +nssTrustDomain_GetPrivateKeyToken +( + NSSTrustDomain *td +); + +/* + * Find the preferred token for storing symmetric keys. + */ +NSS_EXTERN NSSToken * +nssTrustDomain_GetSymmetricKeyToken +( + NSSTrustDomain *td +); + +NSS_EXTERN NSSCertificate * +nssTrustDomain_FindCertificateByIdentifier +( + NSSTrustDomain *td, + NSSItem *identifier +); + +/* Certificate cache routines */ + +NSS_EXTERN PRStatus +nssTrustDomain_AddCertsToCache +( + NSSTrustDomain *td, + NSSCertificate **certs, + PRUint32 numCerts +); + +NSS_EXTERN PRStatus +nssTrustDomain_RemoveCertFromCache +( + NSSTrustDomain *td, + NSSCertificate *cert +); + +/* + * Remove all certs for the given token from the cache. This is + * needed if the token is removed. + */ +NSS_EXTERN PRStatus +nssTrustDomain_RemoveTokenCertsFromCache +( + NSSTrustDomain *td, + NSSToken *token +); + +/* + * Find all cached certs with this nickname (label). + */ +NSS_EXTERN NSSCertificate ** +nssTrustDomain_GetCertsForNicknameFromCache +( + NSSTrustDomain *td, + NSSUTF8 *nickname, + nssList *certListOpt +); + +/* + * Find all cached certs with this email address. + */ +NSS_EXTERN NSSCertificate ** +nssTrustDomain_GetCertsForEmailAddressFromCache +( + NSSTrustDomain *td, + NSSASCII7 *email, + nssList *certListOpt +); + +/* + * Find all cached certs with this subject. + */ +NSS_EXTERN NSSCertificate ** +nssTrustDomain_GetCertsForSubjectFromCache +( + NSSTrustDomain *td, + NSSDER *subject, + nssList *certListOpt +); + +#if 0 +/* + * Look for a specific cert in the cache. + */ +NSS_EXTERN NSSCertificate * +nssTrustDomain_GetCertForIssuerAndSNFromCache +( + NSSTrustDomain *td, + NSSDER *issuer, + NSSDER *serialNum +); +#endif + +/* + * Look for a specific cert in the cache. + */ +NSS_EXTERN NSSCertificate * +nssTrustDomain_GetCertForIdentifierFromCache +( + NSSTrustDomain *td, + NSSItem *id +); + +/* + * Look for a specific cert in the cache. + */ +NSS_EXTERN NSSCertificate * +nssTrustDomain_GetCertByDERFromCache +( + NSSTrustDomain *td, + NSSDER *der +); + +NSS_IMPLEMENT nssDecodedCert * +nssDecodedCert_Create +( + NSSArena *arenaOpt, + NSSDER *encoding, + NSSCertificateType type +); + +NSS_IMPLEMENT PRStatus +nssDecodedCert_Destroy +( + nssDecodedCert *dc +); + +NSS_EXTERN NSSTime * +NSSTime_Now +( + NSSTime *timeOpt +); + +NSS_EXTERN PRTime +NSSTime_GetPRTime +( + NSSTime *time +); + +PR_END_EXTERN_C + +#endif /* PKIM_H */ diff --git a/security/nss/lib/pki/pkinss3hack.h b/security/nss/lib/pki/pkinss3hack.h new file mode 100644 index 000000000000..8b4490790de1 --- /dev/null +++ b/security/nss/lib/pki/pkinss3hack.h @@ -0,0 +1,69 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef PKINSS3HACK_H +#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: $"; +#endif /* DEBUG */ + +#ifndef NSSPKIT_H +#include "nsspkit.h" +#endif /* NSSPKIT_H */ + +#include "cert.h" + +PR_BEGIN_EXTERN_C + +NSS_EXTERN NSSTrustDomain * +STAN_GetDefaultTrustDomain(); + +NSS_IMPLEMENT void +STAN_LoadDefaultNSS3TrustDomain +( + void +); + +NSS_EXTERN PRStatus +STAN_AddNewSlotToDefaultTD +( + PK11SlotInfo *sl +); + +NSS_EXTERN CERTCertificate * +STAN_GetCERTCertificate(NSSCertificate *c); + +PR_END_EXTERN_C + +#endif /* PKINSS3HACK_H */ diff --git a/security/nss/lib/pki/pkit.h b/security/nss/lib/pki/pkit.h index 34f4b67ba133..8660261909fd 100644 --- a/security/nss/lib/pki/pkit.h +++ b/security/nss/lib/pki/pkit.h @@ -35,7 +35,7 @@ #define PKIT_H #ifdef DEBUG -static const char PKIT_CVS_ID[] = "@(#) $RCSfile: pkit.h,v $ $Revision: 1.2 $ $Date: 2001/09/20 20:40:03 $ $Name: $"; +static const char PKIT_CVS_ID[] = "@(#) $RCSfile: pkit.h,v $ $Revision: 1.3 $ $Date: 2001/10/11 16:34:46 $ $Name: $"; #endif /* DEBUG */ /* @@ -52,38 +52,59 @@ static const char PKIT_CVS_ID[] = "@(#) $RCSfile: pkit.h,v $ $Revision: 1.2 $ $D #include "baset.h" #endif /* BASET_H */ +#ifdef NSS_3_4_CODE +#include "pkcs11t.h" +#define NSSCKT_H +#include "ckt.h" +#else #ifndef NSSCKT_H #include "nssckt.h" #endif /* NSSCKT_H */ +#endif /* NSS_3_4_CODE */ #ifndef NSSPKIT_H #include "nsspkit.h" #endif /* NSSPKIT_H */ -#ifndef DEVT_H -#include "devt.h" -#endif /* DEVT_H */ - -#ifndef DEVT_H -#include "devt.h" -#endif /* DEVT_H */ +#ifndef NSSDEVT_H +#include "nssdevt.h" +#endif /* NSSDEVT_H */ PR_BEGIN_EXTERN_C -#define NSSPTR_ADD_REF(p) ((p)->refCount++) +typedef enum { + NSSCertificateType_Unknown = 0, + NSSCertificateType_PKIX = 1, +} NSSCertificateType; + +typedef struct nssDecodedCertStr nssDecodedCert; + +struct NSSTrustStr +{ + CK_TRUST serverAuth; + CK_TRUST emailProtection; + CK_TRUST codeSigning; +}; struct NSSCertificateStr { PRInt32 refCount; NSSArena *arena; + NSSCertificateType type; NSSItem id; - NSSItem der; - NSSItem label; - CK_OBJECT_HANDLE handle; + NSSBER encoding; + NSSDER issuer; + NSSDER subject; + NSSDER serial; + NSSUTF8 *nickname; + NSSASCII7 *email; NSSSlot *slot; + NSSToken *token; NSSTrustDomain *trustDomain; NSSCryptoContext *cryptoContext; - NSSTrust *trust; + NSSTrust trust; + CK_OBJECT_HANDLE handle; + nssDecodedCert *decoding; }; struct NSSPrivateKeyStr; @@ -92,13 +113,15 @@ struct NSSPublicKeyStr; struct NSSSymmetricKeyStr; +typedef struct nssTDCertificateCacheStr nssTDCertificateCache; + struct NSSTrustDomainStr { PRInt32 refCount; NSSArena *arena; NSSCallback defaultCallback; - nssList *moduleList; - nssListIterator *modules; - nssHash *certCache; + nssList *tokenList; + nssListIterator *tokens; + nssTDCertificateCache *cache; }; struct NSSCryptoContextStr @@ -109,16 +132,12 @@ struct NSSCryptoContextStr struct NSSTimeStr; -struct NSSTrustStr; - struct NSSUsageStr; struct NSSPoliciesStr; struct NSSAlgorithmAndParametersStr; -struct NSSCallbackStr; - struct NSSPKIXCertificateStr; PR_END_EXTERN_C diff --git a/security/nss/lib/pki/pkitm.h b/security/nss/lib/pki/pkitm.h new file mode 100644 index 000000000000..da2a8e849875 --- /dev/null +++ b/security/nss/lib/pki/pkitm.h @@ -0,0 +1,82 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef PKITM_H +#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: $"; +#endif /* DEBUG */ + +/* + * pkitm.h + * + * This file contains PKI-module specific types. + */ + +#ifndef BASET_H +#include "baset.h" +#endif /* BASET_H */ + +#ifndef PKIT_H +#include "pkit.h" +#endif /* PKIT_H */ + +PR_BEGIN_EXTERN_C + +/* + * nssDecodedCert + * + * This is an interface to allow the PKI module access to certificate + * information that can only be found by decoding. The interface is + * generic, allowing each certificate type its own way of providing + * the information + */ +struct nssDecodedCertStr { + NSSCertificateType type; + void *data; + /* returns the unique identifier for the cert (usually issuer + serial) */ + NSSItem * (*getIdentifier)(nssDecodedCert *dc); + /* returns the unique identifier for this cert's issuer */ + NSSItem * (*getIssuerIdentifier)(nssDecodedCert *dc); + /* returns the cert usage */ + NSSUsage * (*getUsage)(nssDecodedCert *dc); + /* is time within the validity period of the cert? */ + PRBool (*isValidAtTime)(nssDecodedCert *dc, NSSTime *time); + /* is the validity period of this cert newer than cmpdc? */ + PRBool (*isNewerThan)(nssDecodedCert *dc, nssDecodedCert *cmpdc); +}; + +PR_END_EXTERN_C + +#endif /* PKITM_H */ diff --git a/security/nss/lib/pki/tdcache.c b/security/nss/lib/pki/tdcache.c new file mode 100644 index 000000000000..625a05b1d7bd --- /dev/null +++ b/security/nss/lib/pki/tdcache.c @@ -0,0 +1,648 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.1 $ $Date: 2001/10/11 16:34:49 $ $Name: $"; +#endif /* DEBUG */ + +#ifndef PKIT_H +#include "pkit.h" +#endif /* PKIT_H */ + +#ifndef PKI_H +#include "pki.h" +#endif /* PKI_H */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +/* Certificate cache routines */ + +/* XXX + * Locking is not handled well at all. A single, global lock with sub-locks + * in the collection types. Cleanup needed. + */ + +/* should it live in its own arena? */ +struct nssTDCertificateCacheStr { + PZLock *lock; + nssHash *issuerAndSN; + nssHash *subject; + nssHash *nickname; + nssHash *email; +}; + +static NSSItem * +get_issuer_and_serial_key(NSSArena *arena, NSSDER *issuer, NSSDER *serial) +{ + NSSItem *rvKey; + rvKey = nss_ZNEW(arena, NSSItem); + rvKey->data = nss_ZAlloc(arena, issuer->size + serial->size); + rvKey->size = issuer->size + serial->size; + nsslibc_memcpy(rvKey->data, issuer->data, issuer->size); + nsslibc_memcpy(rvKey->data + issuer->size, serial->data, serial->size); + return rvKey; +} + +static PRBool cert_compare(void *v1, void *v2) +{ + PRStatus rv; + NSSCertificate *c1 = (NSSCertificate *)v1; + NSSCertificate *c2 = (NSSCertificate *)v2; + return + (nssItem_Equal((NSSItem *)&c1->issuer, (NSSItem *)&c2->issuer, &rv) && + nssItem_Equal((NSSItem *)&c1->serial, (NSSItem *)&c2->serial, &rv)); +} + +/* this should not be exposed in a header, but is here to keep the above + * types/functions static + */ +NSS_IMPLEMENT PRStatus +nssTrustDomain_InitializeCache +( + NSSTrustDomain *td, + PRUint32 cacheSize +) +{ + if (td->cache) { + return PR_FAILURE; + } + td->cache = nss_ZNEW(td->arena, nssTDCertificateCache); + td->cache->lock = PZ_NewLock(nssILockCache); + if (!td->cache->lock) return PR_FAILURE; + PZ_Lock(td->cache->lock); + /* Create the issuer and serial DER --> certificate hash */ + td->cache->issuerAndSN = nssHash_CreateItem(td->arena, cacheSize); + if (!td->cache->issuerAndSN) goto loser; + /* Create the subject DER --> subject list hash */ + td->cache->subject = nssHash_CreateItem(td->arena, cacheSize); + if (!td->cache->subject) goto loser; + /* Create the nickname --> subject list hash */ + td->cache->nickname = nssHash_CreateString(td->arena, cacheSize); + if (!td->cache->nickname) goto loser; + /* Create the email --> list of subject lists hash */ + td->cache->email = nssHash_CreateString(td->arena, cacheSize); + if (!td->cache->email) goto loser; + PZ_Unlock(td->cache->lock); + return PR_SUCCESS; +loser: + if (td->cache->issuerAndSN) + nssHash_Destroy(td->cache->issuerAndSN); + if (td->cache->subject) + nssHash_Destroy(td->cache->subject); + if (td->cache->nickname) + nssHash_Destroy(td->cache->nickname); + PZ_Unlock(td->cache->lock); + PZ_DestroyLock(td->cache->lock); + nss_ZFreeIf(td->cache); + td->cache = NULL; + return PR_FAILURE; +} + +NSS_IMPLEMENT PRStatus +nssTrustDomain_DestroyCache +( + NSSTrustDomain *td +) +{ + PZ_Lock(td->cache->lock); + nssHash_Destroy(td->cache->issuerAndSN); + nssHash_Destroy(td->cache->subject); + nssHash_Destroy(td->cache->nickname); + nssHash_Destroy(td->cache->email); + PZ_Unlock(td->cache->lock); + PZ_DestroyLock(td->cache->lock); + nss_ZFreeIf(td->cache); + td->cache = NULL; + return PR_SUCCESS; +} + +static PRStatus +add_cert_to_cache(NSSTrustDomain *td, NSSCertificate *cert) +{ + nssArenaMark *mark; + nssList *subjectList; + nssList *subjects; + NSSUTF8 *nickname = NULL; + NSSUTF8 *email = NULL; + NSSItem *ias = NULL; + PRStatus nssrv; + ias = get_issuer_and_serial_key(td->arena, &cert->issuer, &cert->serial); + PZ_Lock(td->cache->lock); + /* If it exists in the issuer/serial hash, it's already in all */ + if (nssHash_Exists(td->cache->issuerAndSN, ias)) { + PZ_Unlock(td->cache->lock); + nss_ZFreeIf(ias); + return PR_SUCCESS; + } + mark = nssArena_Mark(td->arena); + if (!mark) { + PZ_Unlock(td->cache->lock); + nss_ZFreeIf(ias); + return PR_FAILURE; + } + /* Add to issuer/serial hash */ + nssrv = nssHash_Add(td->cache->issuerAndSN, ias, + nssCertificate_AddRef(cert)); + if (nssrv != PR_SUCCESS) goto loser; + /* Add to subject hash */ + subjectList = (nssList *)nssHash_Lookup(td->cache->subject, &cert->subject); + if (subjectList) { + /* The subject is already in, add this cert to the list */ + nssrv = nssList_Add(subjectList, + nssCertificate_AddRef(cert)); + if (nssrv != PR_SUCCESS) goto loser; + } else { + /* Create a new subject list for the subject */ + subjectList = nssList_Create(td->arena, PR_TRUE); + if (!subjectList) goto loser; + /* To allow for different cert pointers, do list comparison by + * actual cert values. + */ + nssList_SetCompareFunction(subjectList, cert_compare); + nssrv = nssList_Add(subjectList, + nssCertificate_AddRef(cert)); + if (nssrv != PR_SUCCESS) goto loser; + /* Add the subject list to the cache */ + nssrv = nssHash_Add(td->cache->subject, &cert->subject, subjectList); + if (nssrv != PR_SUCCESS) goto loser; + /* Since subject list was created, note the entry in the nickname + * and email hashes. + */ + /* nickname */ + nickname = nssUTF8_Duplicate(cert->nickname, td->arena); + 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; + } + } + nssrv = nssArena_Unmark(td->arena, mark); + PZ_Unlock(td->cache->lock); + return PR_SUCCESS; +loser: + nss_ZFreeIf(ias); + nss_ZFreeIf(nickname); + nss_ZFreeIf(email); + nssArena_Release(td->arena, mark); + PZ_Unlock(td->cache->lock); + return PR_FAILURE; +} + +NSS_IMPLEMENT PRStatus +nssTrustDomain_AddCertsToCache +( + NSSTrustDomain *td, + NSSCertificate **certs, + PRUint32 numCerts +) +{ + PRUint32 i; + for (i=0; isize + serial->size < s_ias->size) { + nsslibc_memcpy(s_ias->data, issuer->data, issuer->size); + nsslibc_memcpy(s_ias->data + issuer->size, serial->data, serial->size); + s_ias->size = issuer->size + serial->size; + return s_ias; + } + s_ias->size = 0; + return get_issuer_and_serial_key(NULL, issuer, serial); +} + +NSS_IMPLEMENT PRStatus +nssTrustDomain_RemoveCertFromCache +( + NSSTrustDomain *td, + NSSCertificate *cert +) +{ + nssList *subjectList; + nssList *subjects; + NSSItem *ias; + unsigned char buf[128]; + NSSItem s_ias = { (void *)buf, sizeof(buf) }; + ias = get_static_ias(&s_ias, &cert->issuer, &cert->serial); + PZ_Lock(td->cache->lock); + if (nssHash_Exists(td->cache->issuerAndSN, &ias)) { + /* Whatchew talkin' bout, Willis? */ +#if 0 + nss_SetError(NSS_ERROR_CERTIFICATE_NOT_IN_CACHE); +#endif + if (s_ias.size == 0) { + nss_ZFreeIf(ias); + } + PZ_Unlock(td->cache->lock); + return PR_FAILURE; + } + /* Remove the cert from the issuer/serial hash */ + nssHash_Remove(td->cache->issuerAndSN, ias); + /* Get the subject list for the cert's subject */ + subjectList = (nssList *)nssHash_Lookup(td->cache->subject, &cert->subject); + if (subjectList) { + /* Remove the cert from the subject hash */ + nssList_Remove(subjectList, cert); + if (nssList_Count(subjectList) == 0) { + /* No more certs for subject ... */ + nssHash_Remove(td->cache->nickname, &cert->nickname); + /* Find the subject list in the email hash */ + subjects = (nssList *)nssHash_Lookup(td->cache->email, cert->email); + if (subjects) { + /* Remove the subject list from the email hash */ + nssList_Remove(subjects, subjectList); + if (nssList_Count(subjects) == 0) { + /* No more subject lists for email, delete list and + * remove hash entry + */ + nssList_Destroy(subjects); + nssHash_Remove(td->cache->email, cert->email); + } + } + /* ... so destroy the subject list and remove the hash entry */ + nssList_Destroy(subjectList); + nssHash_Remove(td->cache->subject, &cert->subject); + } + } + if (s_ias.size == 0) { + nss_ZFreeIf(ias); + } + PZ_Unlock(td->cache->lock); + return PR_SUCCESS; +} + +struct token_cert_destructor { + nssTDCertificateCache *cache; + NSSToken *token; +}; + +static void +remove_token_certs(const void *k, void *v, void *a) +{ + struct NSSItem *identifier = (struct NSSItem *)k; + NSSCertificate *c = (NSSCertificate *)v; + struct token_cert_destructor *tcd = (struct token_cert_destructor *)a; + if (c->token == tcd->token) { + nssHash_Remove(tcd->cache->issuerAndSN, identifier); + /* remove from the other hashes */ + } +} + +/* + * Remove all certs for the given token from the cache. This is + * needed if the token is removed. + */ +NSS_IMPLEMENT PRStatus +nssTrustDomain_RemoveTokenCertsFromCache +( + NSSTrustDomain *td, + NSSToken *token +) +{ + struct token_cert_destructor tcd; + tcd.cache = td->cache; + PZ_Lock(td->cache->lock); + nssHash_Iterate(td->cache->issuerAndSN, remove_token_certs, (void *)&tcd); + PZ_Unlock(td->cache->lock); + return PR_SUCCESS; +} + +static NSSCertificate ** +collect_subject_certs +( + nssList *subjectList, + nssList *rvCertListOpt +) +{ + NSSCertificate *c; + NSSCertificate **rvArray; + PRUint32 count; + if (rvCertListOpt) { + nssListIterator *iter = nssList_CreateIterator(subjectList); + for (c = (NSSCertificate *)nssListIterator_Start(iter); + c != (NSSCertificate *)NULL; + c = (NSSCertificate *)nssListIterator_Next(iter)) { + nssList_Add(rvCertListOpt, c); + } + nssListIterator_Finish(iter); + nssListIterator_Destroy(iter); + return (NSSCertificate **)NULL; + } else { + count = nssList_Count(subjectList); + rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count); + if (!rvArray) return (NSSCertificate **)NULL; + nssList_GetArray(subjectList, (void **)rvArray, count); + return rvArray; + } + return (NSSCertificate **)NULL; +} + +/* + * Find all cached certs with this subject. + */ +NSS_IMPLEMENT NSSCertificate ** +nssTrustDomain_GetCertsForSubjectFromCache +( + NSSTrustDomain *td, + NSSDER *subject, + nssList *certListOpt +) +{ + NSSCertificate **rvArray = NULL; + nssList *subjectList; + PZ_Lock(td->cache->lock); + subjectList = (nssList *)nssHash_Lookup(td->cache->subject, + (void *)subject); + PZ_Unlock(td->cache->lock); + if (subjectList) { + rvArray = collect_subject_certs(subjectList, certListOpt); + } + return rvArray; +} + +/* + * Find all cached certs with this label. + */ +NSS_IMPLEMENT NSSCertificate ** +nssTrustDomain_GetCertsForNicknameFromCache +( + NSSTrustDomain *td, + NSSUTF8 *nickname, + nssList *certListOpt +) +{ + NSSCertificate **rvArray = NULL; + nssList *subjectList; + PZ_Lock(td->cache->lock); + subjectList = (nssList *)nssHash_Lookup(td->cache->nickname, + (void *)nickname); + PZ_Unlock(td->cache->lock); + if (subjectList) { + rvArray = collect_subject_certs(subjectList, certListOpt); + } + return rvArray; +} + +/* + * Find all cached certs with this email address. + */ +NSS_IMPLEMENT NSSCertificate ** +nssTrustDomain_GetCertsForEmailAddressFromCache +( + NSSTrustDomain *td, + NSSASCII7 *email, + nssList *certListOpt +) +{ + NSSCertificate **rvArray = NULL; + nssList *listOfSubjectLists; + nssList *collectList; + PZ_Lock(td->cache->lock); + listOfSubjectLists = (nssList *)nssHash_Lookup(td->cache->email, + (void *)email); + PZ_Unlock(td->cache->lock); + if (listOfSubjectLists) { + nssListIterator *iter; + nssList *subjectList; + if (certListOpt) { + collectList = certListOpt; + } else { + collectList = nssList_Create(NULL, PR_FALSE); + } + iter = nssList_CreateIterator(listOfSubjectLists); + for (subjectList = (nssList *)nssListIterator_Start(iter); + subjectList != (nssList *)NULL; + subjectList = (nssList *)nssListIterator_Next(iter)) { + (void)collect_subject_certs(subjectList, collectList); + } + nssListIterator_Finish(iter); + nssListIterator_Destroy(iter); + } + if (!certListOpt) { + PRUint32 count = nssList_Count(collectList); + rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count); + if (rvArray) { + nssList_GetArray(collectList, (void **)rvArray, count); + } + nssList_Destroy(collectList); + } + return rvArray; +} + +#ifdef DEBUG +static void debug_cache(NSSTrustDomain *td); +#endif + +/* + * Look for a specific cert in the cache + */ +NSS_IMPLEMENT NSSCertificate * +nssTrustDomain_GetCertForIssuerAndSNFromCache +( + NSSTrustDomain *td, + NSSDER *issuer, + NSSDER *serial +) +{ + NSSCertificate *rvCert; + NSSItem *ias; + unsigned char buf[128]; + NSSItem s_ias = { (void *)buf, sizeof(buf) }; + ias = get_static_ias(&s_ias, issuer, serial); +#ifdef DEBUG + debug_cache(td); +#endif + PZ_Lock(td->cache->lock); + rvCert = (NSSCertificate *)nssHash_Lookup(td->cache->issuerAndSN, ias); + PZ_Unlock(td->cache->lock); + if (s_ias.size == 0) { + nss_ZFreeIf(ias); + } + return rvCert; +} + +/* + * Look for a specific cert in the cache + */ +NSS_IMPLEMENT NSSCertificate * +nssTrustDomain_GetCertForIdentifierFromCache +( + NSSTrustDomain *td, + NSSItem *id +) +{ + NSSCertificate *rvCert; + PZ_Lock(td->cache->lock); + rvCert = (NSSCertificate *)nssHash_Lookup(td->cache->issuerAndSN, id); + PZ_Unlock(td->cache->lock); + return rvCert; +} + +NSS_EXTERN NSSItem * +STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der); + +/* + * Look for a specific cert in the cache + */ +NSS_IMPLEMENT NSSCertificate * +nssTrustDomain_GetCertByDERFromCache +( + NSSTrustDomain *td, + NSSDER *der +) +{ + NSSItem *identifier; + NSSCertificate *rvCert = NULL; +#ifdef NSS_3_4_CODE + identifier = STAN_GetCertIdentifierFromDER(NULL, der); +#endif + if (identifier) { + rvCert = (NSSCertificate *)nssHash_Lookup(td->cache->issuerAndSN, + identifier); + } + nss_ZFreeIf(identifier); + return rvCert; +} + +#ifdef DEBUG +static int el_count = 0; + +static void ias_iter(const void *k, void *v, void *a) +{ + PRUint32 i; + NSSItem *ias = (NSSItem *)k; + fprintf(stderr, "[%3d]\n", el_count); + fprintf(stderr, "ISSUER AND SERIAL: "); + for (i=0; isize; i++) { + fprintf(stderr, "%02x", ((unsigned char *)ias->data)[i]); + } + fprintf(stderr, "\n"); + fprintf(stderr, "CERT: %p\n", v); + fprintf(stderr, "\n\n"); + el_count++; +} + +static void print_sub_list(nssList *l) +{ + NSSCertificate *c; + nssListIterator *iter = nssList_CreateIterator(l); + for (c = (NSSCertificate *)nssListIterator_Start(iter); + c != NULL; + c = (NSSCertificate *)nssListIterator_Next(iter)) { + fprintf(stderr, "CERT: %p\n", c); + } + nssListIterator_Finish(iter); + nssListIterator_Destroy(iter); +} + +static void sub_iter(const void *k, void *v, void *a) +{ + PRUint32 i; + NSSDER *sub = (NSSDER *)k; + fprintf(stderr, "[%3d]\n", el_count); + fprintf(stderr, "SUBJECT: "); + for (i=0; isize; i++) { + fprintf(stderr, "%02x", ((unsigned char *)sub->data)[i]); + } + fprintf(stderr, "\n"); + print_sub_list((nssList *)v); + fprintf(stderr, "\n\n"); +} + +static void nik_iter(const void *k, void *v, void *a) +{ + NSSUTF8 *nick = (NSSUTF8 *)k; + fprintf(stderr, "[%3d]\n", el_count); + fprintf(stderr, "NICKNAME: %s\n", (char *)nick); + fprintf(stderr, "SUBJECT_LIST: %p\n", v); + fprintf(stderr, "\n"); +} + +static void print_eml_list(nssList *l) +{ + nssList *s; + nssListIterator *iter = nssList_CreateIterator(l); + for (s = (nssList *)nssListIterator_Start(iter); + s != NULL; + s = (nssList *)nssListIterator_Next(iter)) { + fprintf(stderr, "LIST: %p\n", s); + } + nssListIterator_Finish(iter); + nssListIterator_Destroy(iter); +} + +static void eml_iter(const void *k, void *v, void *a) +{ + NSSASCII7 *email = (NSSASCII7 *)k; + fprintf(stderr, "[%3d]\n", el_count); + fprintf(stderr, "EMAIL: %s\n", (char *)email); + print_eml_list((nssList *)v); + fprintf(stderr, "\n"); +} + +static void debug_cache(NSSTrustDomain *td) +{ + el_count = 0; + nssHash_Iterate(td->cache->issuerAndSN, ias_iter, NULL); + el_count = 0; + nssHash_Iterate(td->cache->subject, sub_iter, NULL); + el_count = 0; + nssHash_Iterate(td->cache->nickname, nik_iter, NULL); + el_count = 0; + nssHash_Iterate(td->cache->email, eml_iter, NULL); +} +#endif + diff --git a/security/nss/lib/pki/trustdomain.c b/security/nss/lib/pki/trustdomain.c index 996b0e0c11fc..6eec476f06c4 100644 --- a/security/nss/lib/pki/trustdomain.c +++ b/security/nss/lib/pki/trustdomain.c @@ -32,16 +32,20 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.5 $ $Date: 2001/09/20 20:40:03 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.6 $ $Date: 2001/10/11 16:34:49 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSPKI_H #include "nsspki.h" #endif /* NSSPKI_H */ -#ifndef PKIT_H -#include "pkit.h" -#endif /* PKIT_H */ +#ifndef PKI_H +#include "pki.h" +#endif /* PKI_H */ + +#ifndef PKIM_H +#include "pkim.h" +#endif /* PKIM_H */ #ifndef DEV_H #include "dev.h" @@ -51,6 +55,15 @@ static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.5 $ #include "ckhelper.h" #endif /* CKHELPER_H */ +#define NSSTRUSTDOMAIN_DEFAULT_CACHE_SIZE 32 + +NSS_EXTERN PRStatus +nssTrustDomain_InitializeCache +( + NSSTrustDomain *td, + PRUint32 cacheSize +); + NSS_IMPLEMENT NSSTrustDomain * NSSTrustDomain_Create ( @@ -70,16 +83,9 @@ NSSTrustDomain_Create if (!rvTD) { goto loser; } - rvTD->moduleList = nssList_Create(arena, PR_TRUE); - if (!rvTD->moduleList) { - goto loser; - } - rvTD->modules = nssList_CreateIterator(rvTD->moduleList); - if (!rvTD->modules) { - goto loser; - } rvTD->arena = arena; rvTD->refCount = 1; + nssTrustDomain_InitializeCache(rvTD, NSSTRUSTDOMAIN_DEFAULT_CACHE_SIZE); return rvTD; loser: nssArena_Destroy(arena); @@ -92,12 +98,6 @@ token_destructor(void *tok) (void)nssToken_Destroy((NSSToken *)tok); } -static void -module_destructor(void *mod) -{ - (void)nssModule_Destroy((NSSModule *)mod); -} - NSS_IMPLEMENT PRStatus NSSTrustDomain_Destroy ( @@ -105,9 +105,9 @@ NSSTrustDomain_Destroy ) { if (--td->refCount == 0) { - /* Destroy each module in the list of modules */ - if (td->moduleList) { - nssList_DestroyElements(td->moduleList, module_destructor); + /* Destroy each token in the list of tokens */ + if (td->tokens) { + nssList_DestroyElements(td->tokenList, token_destructor); } /* Destroy the trust domain */ nssArena_Destroy(td->arena); @@ -148,19 +148,7 @@ NSSTrustDomain_LoadModule void *reserved ) { - NSSModule *module; - /* This is really just here for testing. I don't presume that it is - * correct. Therefore, I won't comment further. - */ - if (moduleOpt) { - module = nssModule_Create(moduleOpt, uriOpt, opaqueOpt, reserved); - nssModule_Load(module); - nssList_AddElement(td->moduleList, (void *)module); -#ifdef DEBUG - nssModule_Debug(module); -#endif - } - return PR_SUCCESS; + return PR_FAILURE; } NSS_IMPLEMENT PRStatus @@ -348,6 +336,29 @@ NSSTrustDomain_ImportEncodedPublicKey return NULL; } +struct get_best_cert_arg_str { + NSSTrustDomain *td; + NSSCertificate *cert; + NSSTime *time; + NSSUsage *usage; + NSSPolicies *policies; +}; + +static PRStatus +get_best_cert(NSSCertificate *c, void *arg) +{ + struct get_best_cert_arg_str *best = (struct get_best_cert_arg_str *)arg; + if (!best->cert) { + /* This is the first matching cert found, so it is the best so far */ + best->cert = c; + return PR_SUCCESS; + } + /* usage */ + /* time */ + /* policies */ + return PR_SUCCESS; +} + NSS_IMPLEMENT NSSCertificate * NSSTrustDomain_FindBestCertificateByNickname ( @@ -358,11 +369,68 @@ NSSTrustDomain_FindBestCertificateByNickname NSSPolicies *policiesOpt /* NULL for none */ ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + PRStatus nssrv; + NSSToken *tok; + CK_ATTRIBUTE cert_template[] = + { + { CKA_CLASS, g_ck_class_cert.data, g_ck_class_cert.size }, + { CKA_LABEL, NULL, 0 } + }; + struct get_best_cert_arg_str best; + CK_ULONG ctsize; + ctsize = (CK_ULONG)(sizeof(cert_template) / sizeof(cert_template[0])); + cert_template[1].pValue = (CK_VOID_PTR)name; + cert_template[1].ulValueLen = (CK_ULONG)nssUTF8_Length(name, &nssrv); + 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); + /* 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--; + } + 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; } -/* THIS IS A TEST IMPLEMENTATION ONLY */ NSS_IMPLEMENT NSSCertificate ** NSSTrustDomain_FindCertificatesByNickname ( @@ -374,51 +442,48 @@ NSSTrustDomain_FindCertificatesByNickname ) { PRStatus nssrv; - PRUint32 i, count; + PRUint32 count; NSSCertificate **certs; NSSToken *tok; - NSSModule *mod; nssList *foundCerts; CK_ATTRIBUTE cert_template[] = { { CKA_CLASS, g_ck_class_cert.data, g_ck_class_cert.size }, { CKA_LABEL, NULL, 0 } }; + struct collect_arg_str ca; CK_ULONG ctsize; ctsize = (CK_ULONG)(sizeof(cert_template) / sizeof(cert_template[0])); 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; + ca.maximum = maximumOpt; + ca.arena = arenaOpt; /* This will really be done through the search order, probably a * token array */ - for (mod = (NSSModule *)nssListIterator_Start(td->modules); - mod != (NSSModule *)NULL; - mod = (NSSModule *)nssListIterator_Next(td->modules)) + for (tok = (NSSToken *)nssListIterator_Start(td->tokens); + tok != (NSSToken *)NULL; + tok = (NSSToken *)nssListIterator_Next(td->tokens)) { - for (i=0; inumSlots; i++) { - /* XXX not right at all */ - tok = mod->slots[i]->token; - nssrv = nssToken_FindCertificatesByTemplate(tok, NULL, - foundCerts, maximumOpt, - arenaOpt, - cert_template, ctsize); - /* 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, - foundCerts, maximumOpt, - arenaOpt, - cert_template, ctsize); - cert_template[1].ulValueLen--; - } + 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->modules); + nssListIterator_Finish(td->tokens); + count = nssList_Count(foundCerts); if (rvOpt) { certs = rvOpt; } else { - count = nssList_Count(foundCerts); certs = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1); } nssrv = nssList_GetArray(foundCerts, (void **)certs, count); @@ -426,6 +491,23 @@ NSSTrustDomain_FindCertificatesByNickname return certs; } +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 ( @@ -647,16 +729,7 @@ NSSTrustDomain_TraverseCertificates void *arg ) { - NSSModule *mod; - /* Do module->slot->token, or just slotarray->tokens? */ - for (mod = (NSSModule *)nssListIterator_Start(td->modules); - mod != (NSSModule *)NULL; - mod = (NSSModule *)nssListIterator_Next(td->modules)) - { - nssModule_TraverseCertificates(mod, callback, arg); - } - nssListIterator_Finish(td->modules); - return PR_SUCCESS; + return NULL; } NSS_IMPLEMENT PRStatus