diff --git a/security/nss/lib/base/base.h b/security/nss/lib/base/base.h index 5d44b7df324..0970c3fed49 100644 --- a/security/nss/lib/base/base.h +++ b/security/nss/lib/base/base.h @@ -35,7 +35,7 @@ #define BASE_H #ifdef DEBUG -static const char BASE_CVS_ID[] = "@(#) $RCSfile: base.h,v $ $Revision: 1.9 $ $Date: 2001-10-15 17:13:31 $ $Name: $"; +static const char BASE_CVS_ID[] = "@(#) $RCSfile: base.h,v $ $Revision: 1.10 $ $Date: 2001-11-28 16:23:34 $ $Name: $"; #endif /* DEBUG */ /* @@ -562,6 +562,12 @@ nssItem_Create const void *data ); +NSS_EXTERN void +nssItem_Destroy +( + NSSItem *item +); + NSS_EXTERN NSSItem * nssItem_Duplicate ( @@ -831,8 +837,8 @@ nssList_Destroy nssList *list ); -NSS_EXTERN PRStatus -nssList_DestroyElements +NSS_EXTERN void +nssList_Clear ( nssList *list, nssListElementDestructorFunc destructor @@ -1004,6 +1010,16 @@ nssListIterator_Finish * */ +NSS_EXTERN nssHash * +nssHash_Create +( + NSSArena *arenaOpt, + PRUint32 numBuckets, + PLHashFunction keyHash, + PLHashComparator keyCompare, + PLHashComparator valueCompare +); + NSS_EXTERN nssHash * nssHash_CreatePointer ( diff --git a/security/nss/lib/base/hash.c b/security/nss/lib/base/hash.c index 2c70bfca9a4..9ce7f992ab0 100644 --- a/security/nss/lib/base/hash.c +++ b/security/nss/lib/base/hash.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: hash.c,v $ $Revision: 1.3 $ $Date: 2001-10-08 19:26:02 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: hash.c,v $ $Revision: 1.4 $ $Date: 2001-11-28 16:23:34 $ $Name: $"; #endif /* DEBUG */ /* @@ -112,7 +112,7 @@ nss_compare_items(const void *v1, const void *v2) * nssHash_create * */ -static nssHash * +NSS_IMPLEMENT nssHash * nssHash_Create ( NSSArena *arenaOpt, diff --git a/security/nss/lib/base/item.c b/security/nss/lib/base/item.c index 4eb77cb0028..f1c06571db7 100644 --- a/security/nss/lib/base/item.c +++ b/security/nss/lib/base/item.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: item.c,v $ $Revision: 1.1 $ $Date: 2000-03-31 19:50:14 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: item.c,v $ $Revision: 1.2 $ $Date: 2001-11-28 16:23:35 $ $Name: $"; #endif /* DEBUG */ /* @@ -116,6 +116,19 @@ nssItem_Create return (NSSItem *)NULL; } +NSS_IMPLEMENT void +nssItem_Destroy +( + NSSItem *item +) +{ + nss_ClearErrorStack(); + + nss_ZFreeIf(item->data); + nss_ZFreeIf(item); + +} + /* * nssItem_Duplicate * diff --git a/security/nss/lib/base/list.c b/security/nss/lib/base/list.c index e448af5eb7f..d6def1f95c7 100644 --- a/security/nss/lib/base/list.c +++ b/security/nss/lib/base/list.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: list.c,v $ $Revision: 1.7 $ $Date: 2001-11-16 19:36:43 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: list.c,v $ $Revision: 1.8 $ $Date: 2001-11-28 16:23:35 $ $Name: $"; #endif /* DEBUG */ /* @@ -138,8 +138,17 @@ nssList_Create NSS_IMPLEMENT PRStatus nssList_Destroy(nssList *list) { - if (list->lock) PZ_DestroyLock(list->lock); - NSSArena_Destroy(list->arena); + PZLock *lock = list->lock; + if (list->arena) { + NSSArena_Destroy(list->arena); + list = NULL; + } else { + nssList_Clear(list, NULL); + } + if (lock) { + PZ_DestroyLock(lock); + } + nss_ZFreeIf(list); return PR_SUCCESS; } @@ -162,22 +171,23 @@ nssList_GetCompareFunction(nssList *list) return list->compareFunc; } -NSS_IMPLEMENT PRStatus -nssList_DestroyElements(nssList *list, nssListElementDestructorFunc destructor) +NSS_IMPLEMENT void +nssList_Clear(nssList *list, nssListElementDestructorFunc destructor) { PRCList *link; - nssListElement *node; + nssListElement *node, *tmp; NSSLIST_LOCK_IF(list); node = list->head; while (node && list->count > 0) { - (*destructor)(node->data); + if (destructor) (*destructor)(node->data); link = &node->link; - node = (nssListElement *)PR_NEXT_LINK(link); + tmp = (nssListElement *)PR_NEXT_LINK(link); PR_REMOVE_LINK(link); + nss_ZFreeIf(node); + node = tmp; --list->count; } NSSLIST_UNLOCK_IF(list); - return nssList_Destroy(list); } static PRStatus @@ -271,7 +281,7 @@ nssList_Get(nssList *list, void *data) NSSLIST_LOCK_IF(list); node = nsslist_get_matching_element(list, data); NSSLIST_UNLOCK_IF(list); - return node->data; + return (node) ? node->data : NULL; } NSS_IMPLEMENT PRUint32 @@ -286,14 +296,14 @@ nssList_GetArray(nssList *list, void **rvArray, PRUint32 maxElements) nssListIterator *iter; void *el; PRUint32 i = 0; + PR_ASSERT(maxElements > 0); iter = nssList_CreateIterator(list); for (el = nssListIterator_Start(iter); el != NULL; el = nssListIterator_Next(iter)) { rvArray[i++] = el; - if (maxElements > 0 && i == maxElements) break; + if (i == maxElements) break; } - rvArray[i] = NULL; nssListIterator_Finish(iter); nssListIterator_Destroy(iter); return PR_SUCCESS; diff --git a/security/nss/lib/certdb/stanpcertdb.c b/security/nss/lib/certdb/stanpcertdb.c index 6010dd87507..c2986e323b7 100644 --- a/security/nss/lib/certdb/stanpcertdb.c +++ b/security/nss/lib/certdb/stanpcertdb.c @@ -116,8 +116,7 @@ CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert, /* XXX store it on a writeable token */ goto done; } else { - NSSCertificate *c = STAN_GetNSSCertificate(cert); - ret = STAN_ChangeCertTrust(c, trust); + ret = STAN_ChangeCertTrust(cert, trust); rv = (ret == PR_SUCCESS) ? SECSuccess : SECFailure; } done: @@ -141,7 +140,7 @@ __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, } if (c->nickname && strcmp(nickname, c->nickname) != 0) { nss_ZFreeIf(c->nickname); - c->nickname = nssUTF8_Duplicate((NSSUTF8 *)nickname, c->arena); + c->nickname = nssUTF8_Duplicate((NSSUTF8 *)nickname, c->object.arena); PORT_Free(cert->nickname); cert->nickname = PORT_Strdup(nickname); } @@ -168,6 +167,7 @@ __CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, char *nickname, PRBool isperm, PRBool copyDER) { NSSCertificate *c; + NSSCryptoContext *context; nssDecodedCert *dc; NSSArena *arena; CERTCertificate *cc; @@ -175,13 +175,19 @@ __CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, if (!arena) { return NULL; } - c = NSSCertificate_Create(arena); + c = nss_ZNEW(arena, NSSCertificate); if (!c) { goto loser; } NSSITEM_FROM_SECITEM(&c->encoding, derCert); + c->object.arena = arena; + c->object.refCount = 1; + c->object.instanceList = nssList_Create(arena, PR_TRUE); + c->object.instances = nssList_CreateIterator(c->object.instanceList); + /* Forces a decoding of the cert in order to obtain the parts used + * below + */ cc = STAN_GetCERTCertificate(c); - c->arena = arena; nssItem_Create(arena, &c->issuer, cc->derIssuer.len, cc->derIssuer.data); nssItem_Create(arena, @@ -200,12 +206,13 @@ __CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, (NSSUTF8 *)cc->emailAddr, PORT_Strlen(cc->emailAddr)); } - c->trustDomain = handle; - cc->dbhandle = handle; - nssTrustDomain_AddCertsToCache(handle, &c, 1); - cc->istemp = 1; - cc->isperm = 0; - + context = STAN_GetDefaultCryptoContext(); + NSSCryptoContext_ImportCertificate(context, c); + /* This is a hack to work around the fact that an instance of the cert + * doesn't really exist until the import + */ + cc->nssCertificate = NULL; + cc = STAN_GetCERTCertificate(c); return cc; loser: nssArena_Destroy(arena); @@ -363,10 +370,13 @@ CERT_DestroyCertificate(CERTCertificate *cert) CERT_UnlockCertRefCount(cert); if ( ( refCount == 0 ) && !cert->keepSession ) { PRArenaPool *arena = cert->arena; - if ( cert->istemp ) { - /* uncache the cert ? */ - } /* delete the NSSCertificate */ + NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); + NSSCertificate *tmp = STAN_GetNSSCertificate(cert); + if (tmp) { + nssTrustDomain_RemoveCertFromCache(td, tmp); + NSSCertificate_Destroy(tmp); + } /* zero cert before freeing. Any stale references to this cert * after this point will probably cause an exception. */ PORT_Memset(cert, 0, sizeof *cert); diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c index 107d9dd2bc9..bd43be1b449 100644 --- a/security/nss/lib/certhigh/certvfy.c +++ b/security/nss/lib/certhigh/certvfy.c @@ -417,9 +417,13 @@ loser: nss_ZFreeIf(nssTime); if (status == PR_SUCCESS) { /* if it's a root, the chain will only have one cert */ - NSSCertificate *issuer = chain[1] ? chain[1] : chain[0]; - CERTCertificate *rvc = STAN_GetCERTCertificate(issuer); - return rvc; + if (!chain[1]) { + /* need to dupe since caller expects new cert */ + return CERT_DupCertificate(cert); + } else { + /* this is the only instance */ + return STAN_GetCERTCertificate(chain[1]); + } } return NULL; #endif diff --git a/security/nss/lib/dev/ckhelper.c b/security/nss/lib/dev/ckhelper.c index 2ae197267dd..d0eae4eba3e 100644 --- a/security/nss/lib/dev/ckhelper.c +++ b/security/nss/lib/dev/ckhelper.c @@ -32,13 +32,9 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: ckhelper.c,v $ $Revision: 1.10 $ $Date: 2001-11-07 16:15:28 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: ckhelper.c,v $ $Revision: 1.11 $ $Date: 2001-11-28 16:23:38 $ $Name: $"; #endif /* DEBUG */ -#ifndef PKIT_H -#include "pkit.h" -#endif /* PKIT_H */ - #ifndef DEV_H #include "dev.h" #endif /* DEV_H */ diff --git a/security/nss/lib/dev/dev.h b/security/nss/lib/dev/dev.h index 29f892e0c21..af413ca7b9f 100644 --- a/security/nss/lib/dev/dev.h +++ b/security/nss/lib/dev/dev.h @@ -35,7 +35,7 @@ #define DEV_H #ifdef DEBUG -static const char DEV_CVS_ID[] = "@(#) $RCSfile: dev.h,v $ $Revision: 1.13 $ $Date: 2001-11-09 00:36:10 $ $Name: $"; +static const char DEV_CVS_ID[] = "@(#) $RCSfile: dev.h,v $ $Revision: 1.14 $ $Date: 2001-11-28 16:23:38 $ $Name: $"; #endif /* DEBUG */ #ifndef DEVT_H @@ -64,10 +64,6 @@ static const char DEV_CVS_ID[] = "@(#) $RCSfile: dev.h,v $ $Revision: 1.13 $ $Da * |-----------|---> NSSSlot <--> NSSToken */ -#ifndef DEVT_H -#include "devt.h" -#endif /* DEVT_H */ - PR_BEGIN_EXTERN_C NSS_EXTERN NSSModule * @@ -248,16 +244,24 @@ nssToken_GetName NSSToken *tok ); -/* Given a raw attribute template, import an object - * (certificate, public key, private key, symmetric key) - */ -NSS_EXTERN CK_OBJECT_HANDLE -nssToken_ImportObject +NSS_EXTERN PRStatus +nssToken_ImportCertificate ( NSSToken *tok, nssSession *sessionOpt, - CK_ATTRIBUTE_PTR objectTemplate, - CK_ULONG otsize + NSSCertificate *cert, + NSSTrustDomain *td, + NSSCryptoContext *cc +); + +NSS_EXTERN PRStatus +nssToken_ImportTrust +( + NSSToken *tok, + nssSession *sessionOpt, + NSSTrust *trust, + NSSTrustDomain *trustDomain, + NSSCryptoContext *cryptoContext ); NSS_EXTERN NSSPublicKey * @@ -280,30 +284,15 @@ nssToken_GenerateSymmetricKey NSS_EXTERN PRStatus nssToken_DeleteStoredObject ( - NSSToken *tok, - nssSession *sessionOpt, - CK_OBJECT_HANDLE object + nssCryptokiInstance *instance ); -NSS_EXTERN CK_OBJECT_HANDLE -nssToken_FindObjectByTemplate +NSS_EXTERN NSSTrust * +nssToken_FindTrustForCert ( - NSSToken *tok, + NSSToken *token, nssSession *sessionOpt, - CK_ATTRIBUTE_PTR cktemplate, - CK_ULONG ctsize -); - -NSS_EXTERN PRStatus -nssToken_TraverseCertificatesByTemplate -( - NSSToken *tok, - nssSession *sessionOpt, - nssList *cachedList, - CK_ATTRIBUTE_PTR cktemplate, - CK_ULONG ctsize, - PRStatus (*callback)(NSSCertificate *c, void *arg), - void *arg + NSSCertificate *c ); NSS_EXTERN PRStatus @@ -311,8 +300,95 @@ nssToken_TraverseCertificates ( NSSToken *tok, nssSession *sessionOpt, - PRStatus (*callback)(NSSCertificate *c, void *arg), - void *arg + nssTokenCertSearch *search +); + +NSS_EXTERN PRStatus +nssToken_TraverseCertificatesBySubject +( + NSSToken *token, + nssSession *sessionOpt, + NSSDER *subject, + nssTokenCertSearch *search +); + +NSS_EXTERN PRStatus +nssToken_TraverseCertificatesByNickname +( + NSSToken *token, + nssSession *sessionOpt, + NSSUTF8 *name, + nssTokenCertSearch *search +); + +NSS_EXTERN PRStatus +nssToken_TraverseCertificatesByEmail +( + NSSToken *token, + nssSession *sessionOpt, + NSSASCII7 *email, + nssTokenCertSearch *search +); + +NSS_EXTERN NSSCertificate * +nssToken_FindCertificateByIssuerAndSerialNumber +( + NSSToken *token, + nssSession *sessionOpt, + NSSDER *issuer, + NSSDER *serial +); + +NSS_EXTERN NSSCertificate * +nssToken_FindCertificateByEncodedCertificate +( + NSSToken *token, + nssSession *sessionOpt, + NSSBER *encodedCertificate +); + +NSS_EXTERN NSSTrust * +nssToken_FindTrustForCert +( + NSSToken *token, + nssSession *session, + NSSCertificate *c +); + +NSS_EXTERN NSSItem * +nssToken_Digest +( + NSSToken *tok, + nssSession *sessionOpt, + NSSAlgorithmAndParameters *ap, + NSSItem *data, + NSSItem *rvOpt, + NSSArena *arenaOpt +); + +NSS_EXTERN PRStatus +nssToken_BeginDigest +( + NSSToken *tok, + nssSession *sessionOpt, + NSSAlgorithmAndParameters *ap +); + +NSS_EXTERN PRStatus +nssToken_ContinueDigest +( + NSSToken *tok, + nssSession *sessionOpt, + NSSItem *item +); + +NSS_EXTERN NSSItem * +nssToken_FinishDigest +( + NSSToken *tok, + nssSession *sessionOpt, + NSSItem *rvOpt, + NSSArena *arenaOpt ); NSS_EXTERN PRStatus @@ -342,9 +418,17 @@ nssSession_IsReadWrite nssSession *s ); -#ifdef DEBUG -void nssModule_Debug(NSSModule *m); -#endif +NSS_EXTERN NSSAlgorithmAndParameters * +NSSAlgorithmAndParameters_CreateSHA1Digest +( + NSSArena *arenaOpt +); + +NSS_EXTERN NSSAlgorithmAndParameters * +NSSAlgorithmAndParameters_CreateMD5Digest +( + NSSArena *arenaOpt +); PR_END_EXTERN_C diff --git a/security/nss/lib/dev/devmod.c b/security/nss/lib/dev/devmod.c index 649e635f8b1..774b8d7a080 100644 --- a/security/nss/lib/dev/devmod.c +++ b/security/nss/lib/dev/devmod.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: devmod.c,v $ $Revision: 1.1 $ $Date: 2001-11-08 00:14:52 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: devmod.c,v $ $Revision: 1.2 $ $Date: 2001-11-28 16:23:39 $ $Name: $"; #endif /* DEBUG */ #include "nspr.h" @@ -367,12 +367,6 @@ nssModule_TraverseCertificates void *arg ) { - PRUint32 i; - for (i=0; inumSlots; i++) { - /* might as well skip straight to token, right? or is this slot? */ - nssToken_TraverseCertificates(mod->slots[i]->token, - NULL, callback, arg); - } return NULL; } diff --git a/security/nss/lib/dev/devobject.c b/security/nss/lib/dev/devobject.c new file mode 100644 index 00000000000..852a431f965 --- /dev/null +++ b/security/nss/lib/dev/devobject.c @@ -0,0 +1,950 @@ +/* + * 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: devobject.c,v $ $Revision: 1.1 $ $Date: 2001-11-28 16:23:39 $ $Name: $"; +#endif /* DEBUG */ + +#ifndef DEV_H +#include "dev.h" +#endif /* DEV_H */ + +#ifndef DEVM_H +#include "devm.h" +#endif /* DEVM_H */ + +#ifndef NSSCKEPV_H +#include "nssckepv.h" +#endif /* NSSCKEPV_H */ + +#ifndef CKHELPER_H +#include "ckhelper.h" +#endif /* CKHELPER_H */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +/* XXX */ +#ifndef PKIT_H +#include "pkit.h" +#endif /* PKIT_H */ + +#ifdef NSS_3_4_CODE +#include "pkim.h" /* for cert decoding */ +#endif + +/* The number of object handles to grab during each call to C_FindObjects */ +#define OBJECT_STACK_SIZE 16 + +NSS_IMPLEMENT PRStatus +nssToken_DeleteStoredObject +( + nssCryptokiInstance *instance +) +{ + CK_RV ckrv; + PRStatus nssrv; + PRBool createdSession; + NSSToken *token = instance->token; + nssSession *session = NULL; + if (nssCKObject_IsAttributeTrue(instance->handle, CKA_TOKEN, + token->defaultSession, + token->slot, &nssrv)) { + if (nssSession_IsReadWrite(token->defaultSession)) { + session = token->defaultSession; + } else { + session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE); + createdSession = PR_TRUE; + } + } + if (session == NULL) { + return PR_FAILURE; + } + nssSession_EnterMonitor(session); + ckrv = CKAPI(token)->C_DestroyObject(session->handle, instance->handle); + nssSession_ExitMonitor(session); + if (createdSession) { + nssSession_Destroy(session); + } + if (ckrv != CKR_OK) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static CK_OBJECT_HANDLE +import_object +( + NSSToken *tok, + nssSession *sessionOpt, + CK_ATTRIBUTE_PTR objectTemplate, + CK_ULONG otsize +) +{ + nssSession *session = NULL; + PRBool createdSession = PR_FALSE; + CK_OBJECT_HANDLE object; + CK_RV ckrv; + if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) { + if (sessionOpt) { + if (!nssSession_IsReadWrite(sessionOpt)) { + return CK_INVALID_HANDLE; + } else { + session = sessionOpt; + } + } else if (nssSession_IsReadWrite(tok->defaultSession)) { + session = tok->defaultSession; + } else { + session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE); + createdSession = PR_TRUE; + } + } else { + session = (sessionOpt) ? sessionOpt : tok->defaultSession; + } + if (session == NULL) { + return CK_INVALID_HANDLE; + } + nssSession_EnterMonitor(session); + ckrv = CKAPI(tok->slot)->C_CreateObject(session->handle, + objectTemplate, otsize, + &object); + nssSession_ExitMonitor(session); + if (createdSession) { + nssSession_Destroy(session); + } + if (ckrv != CKR_OK) { + return CK_INVALID_HANDLE; + } + return object; +} + +static CK_OBJECT_HANDLE +find_object_by_template +( + NSSToken *tok, + nssSession *sessionOpt, + CK_ATTRIBUTE_PTR cktemplate, + CK_ULONG ctsize +) +{ + CK_SESSION_HANDLE hSession; + CK_OBJECT_HANDLE rvObject; + CK_ULONG count; + CK_RV ckrv; + nssSession *session; + session = (sessionOpt) ? sessionOpt : tok->defaultSession; + hSession = session->handle; + nssSession_EnterMonitor(session); + ckrv = CKAPI(tok)->C_FindObjectsInit(hSession, cktemplate, ctsize); + if (ckrv != CKR_OK) { + nssSession_ExitMonitor(session); + return CK_INVALID_HANDLE; + } + ckrv = CKAPI(tok)->C_FindObjects(hSession, &rvObject, 1, &count); + if (ckrv != CKR_OK) { + nssSession_ExitMonitor(session); + return CK_INVALID_HANDLE; + } + ckrv = CKAPI(tok)->C_FindObjectsFinal(hSession); + nssSession_ExitMonitor(session); + if (ckrv != CKR_OK) { + return CK_INVALID_HANDLE; + } + return rvObject; +} + +static PRStatus +traverse_objects_by_template +( + NSSToken *tok, + nssSession *sessionOpt, + CK_ATTRIBUTE_PTR obj_template, + CK_ULONG otsize, + PRStatus (*callback)(NSSToken *t, nssSession *session, + CK_OBJECT_HANDLE h, void *arg), + void *arg +) +{ + NSSSlot *slot; + PRStatus cbrv; + PRUint32 i; + CK_RV ckrv; + CK_ULONG count; + CK_OBJECT_HANDLE *objectStack; + CK_OBJECT_HANDLE startOS[OBJECT_STACK_SIZE]; + CK_SESSION_HANDLE hSession; + NSSArena *objectArena = NULL; + nssSession *session; + nssList *objectList = NULL; + slot = tok->slot; + objectStack = startOS; + session = (sessionOpt) ? sessionOpt : tok->defaultSession; + hSession = session->handle; + nssSession_EnterMonitor(session); + ckrv = CKAPI(slot)->C_FindObjectsInit(hSession, obj_template, otsize); + if (ckrv != CKR_OK) { + nssSession_ExitMonitor(session); + goto loser; + } + while (PR_TRUE) { + ckrv = CKAPI(slot)->C_FindObjects(hSession, objectStack, + OBJECT_STACK_SIZE, &count); + if (ckrv != CKR_OK) { + nssSession_ExitMonitor(session); + goto loser; + } + if (count == OBJECT_STACK_SIZE) { + if (!objectList) { + objectArena = NSSArena_Create(); + objectList = nssList_Create(objectArena, PR_FALSE); + } + objectStack = nss_ZNEWARRAY(objectArena, CK_OBJECT_HANDLE, + OBJECT_STACK_SIZE); + nssList_Add(objectList, objectStack); + } else { + break; + } + } + ckrv = CKAPI(slot)->C_FindObjectsFinal(hSession); + nssSession_ExitMonitor(session); + if (ckrv != CKR_OK) { + goto loser; + } + if (objectList) { + nssListIterator *objects; + objects = nssList_CreateIterator(objectList); + for (objectStack = (CK_OBJECT_HANDLE *)nssListIterator_Start(objects); + objectStack != NULL; + objectStack = (CK_OBJECT_HANDLE *)nssListIterator_Next(objects)) { + for (i=0; iarena, nssPKIObjectInstance); + if (!oi) { + return PR_FAILURE; + } + oi->cryptoki.handle = h; + oi->cryptoki.token = t; + oi->trustDomain = td; + oi->cryptoContext = cc; + nssList_Add(object->instanceList, oi); + return PR_SUCCESS; +} + +#if 0 +#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 ? c->nickname : c->email; + if (!label) return; + 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 +#endif + +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; + } +} + +/* Create a certificate from an object handle. */ +static NSSCertificate * +get_token_cert +( + NSSToken *token, + nssSession *sessionOpt, + CK_OBJECT_HANDLE handle +) +{ + NSSCertificate *rvCert; + nssPKIObject *object; + NSSArena *arena; + nssSession *session; + PRStatus nssrv; + CK_ULONG template_size; + CK_ATTRIBUTE cert_template[] = { + { CKA_CERTIFICATE_TYPE, NULL, 0 }, + { CKA_ID, NULL, 0 }, + { CKA_VALUE, NULL, 0 }, + { CKA_ISSUER, NULL, 0 }, + { CKA_SERIAL_NUMBER, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, + { CKA_NETSCAPE_EMAIL, NULL, 0 } + }; + template_size = sizeof(cert_template) / sizeof(cert_template[0]); + session = (sessionOpt) ? sessionOpt : token->defaultSession; + arena = nssArena_Create(); + if (!arena) { + return NULL; + } + rvCert = nss_ZNEW(arena, NSSCertificate); + if (!rvCert) { + goto loser; + } + object = &rvCert->object; + object->arena = arena; + object->refCount = 1; + object->instanceList = nssList_Create(arena, PR_TRUE); + if (!object->instanceList) { + goto loser; + } + object->instances = nssList_CreateIterator(object->instanceList); + if (!object->instances) { + goto loser; + } + nssrv = nssCKObject_GetAttributes(handle, + cert_template, template_size, + arena, session, token->slot); + if (nssrv) { + goto loser; + } + 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_ITEM(&cert_template[3], &rvCert->issuer); + NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[4], &rvCert->serial); + NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[5], rvCert->nickname); + NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[6], &rvCert->subject); + NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[7], rvCert->email); +#ifdef NSS_3_4_CODE + /* nss 3.4 database doesn't associate email address with cert */ + if (!rvCert->email) { + nssDecodedCert *dc; + NSSASCII7 *email; + dc = nssCertificate_GetDecoding(rvCert); + email = dc->getEmailAddress(dc); + if (email) rvCert->email = nssUTF8_Duplicate(email, arena); + } + /*make_nss3_nickname(rvCert);*/ +#endif + return rvCert; +loser: + nssArena_Destroy(arena); + return (NSSCertificate *)NULL; +} + +NSS_IMPLEMENT PRStatus +nssToken_ImportCertificate +( + NSSToken *tok, + nssSession *sessionOpt, + NSSCertificate *cert, + NSSTrustDomain *td, + NSSCryptoContext *cc +) +{ + CK_CERTIFICATE_TYPE cert_type = CKC_X_509; + CK_OBJECT_HANDLE handle; + CK_ATTRIBUTE cert_tmpl[] = { + { CKA_TOKEN, NULL, 0 }, + { CKA_CLASS, NULL, 0 }, + { CKA_CERTIFICATE_TYPE, NULL, 0 }, + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_VALUE, NULL, 0 }, + { CKA_ISSUER, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, + { CKA_SERIAL_NUMBER, NULL, 0 } + }; + CK_ULONG ctsize = sizeof(cert_tmpl)/sizeof(cert_tmpl[0]); + if (td) { + /* trust domain == token object */ + NSS_CK_SET_ATTRIBUTE_ITEM(cert_tmpl, 0, &g_ck_true); + } else { + /* crypto context == session object */ + NSS_CK_SET_ATTRIBUTE_ITEM(cert_tmpl, 0, &g_ck_false); + } + NSS_CK_SET_ATTRIBUTE_ITEM(cert_tmpl, 1, &g_ck_class_cert); + NSS_CK_SET_ATTRIBUTE_VAR( cert_tmpl, 2, cert_type); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_tmpl, 3, &cert->id); + NSS_CK_SET_ATTRIBUTE_UTF8(cert_tmpl, 4, cert->nickname); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_tmpl, 5, &cert->encoding); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_tmpl, 6, &cert->issuer); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_tmpl, 7, &cert->subject); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_tmpl, 8, &cert->serial); + /* Import the certificate onto the token */ + handle = import_object(tok, sessionOpt, cert_tmpl, ctsize); + if (handle == CK_INVALID_HANDLE) { + return PR_FAILURE; + } + return add_object_instance(&cert->object, tok, handle, td, cc); +} + +struct cert_search_index_str +{ + NSSDER issuer; + NSSDER serial; +}; + +static PRBool +compare_cert_by_issuer_sn(void *a, void *b) +{ + NSSCertificate *c = (NSSCertificate *)a; + struct cert_search_index_str *csi = (struct cert_search_index_str *)b; + return (nssItem_Equal(&c->issuer, &csi->issuer, NULL) && + nssItem_Equal(&c->serial, &csi->serial, NULL)); +} + +static PRStatus +retrieve_cert(NSSToken *t, nssSession *session, CK_OBJECT_HANDLE h, void *arg) +{ + PRStatus nssrv; + PRBool found; + nssTokenCertSearch *search = (nssTokenCertSearch *)arg; + NSSCertificate *cert = NULL; + struct cert_search_index_str csi; + nssListIterator *instances; + nssPKIObjectInstance *oi; + CK_ATTRIBUTE issuersn_tmpl[] = { + { CKA_ISSUER, NULL, 0 }, + { CKA_SERIAL_NUMBER, NULL, 0 } + }; + CK_ULONG ist_size = sizeof(issuersn_tmpl) / sizeof(issuersn_tmpl[0]); + if (search->cached) { + nssrv = nssCKObject_GetAttributes(h, issuersn_tmpl, ist_size, + NULL, session, t->slot); + NSS_CK_ATTRIBUTE_TO_ITEM(&issuersn_tmpl[0], &csi.issuer); + NSS_CK_ATTRIBUTE_TO_ITEM(&issuersn_tmpl[1], &csi.serial); + cert = (NSSCertificate *)nssList_Get(search->cached, &csi); + nss_ZFreeIf(csi.issuer.data); + nss_ZFreeIf(csi.serial.data); + } + found = PR_FALSE; + if (cert) { + instances = cert->object.instances; + for (oi = (nssPKIObjectInstance *)nssListIterator_Start(instances); + oi != (nssPKIObjectInstance *)NULL; + oi = (nssPKIObjectInstance *)nssListIterator_Next(instances)) + { + if (oi->cryptoki.handle == h && oi->cryptoki.token == t) { + found = PR_TRUE; + break; + } + } + nssListIterator_Finish(instances); + } else { + cert = get_token_cert(t, session, h); + if (!cert) return PR_FAILURE; + } + if (!found) { + nssrv = add_object_instance(&cert->object, t, h, + search->trustDomain, + search->cryptoContext); + if (nssrv != PR_SUCCESS) { + return nssrv; + } + } + return (*search->callback)(cert, search->cbarg); +} + +/* traverse all certificates - this should only happen if the token + * has been marked as "traversable" + */ +NSS_IMPLEMENT PRStatus +nssToken_TraverseCertificates +( + NSSToken *token, + nssSession *sessionOpt, + nssTokenCertSearch *search +) +{ + PRStatus nssrv; + /* this is really traversal - the template is all certs */ + CK_ATTRIBUTE cert_template[] = { + { CKA_CLASS, NULL, 0 } + }; + CK_ULONG ctsize = sizeof(cert_template) / sizeof(cert_template[0]); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); + nssList_SetCompareFunction(search->cached, compare_cert_by_issuer_sn); + nssrv = traverse_objects_by_template(token, sessionOpt, + cert_template, ctsize, + retrieve_cert, search); + return nssrv; +} + +NSS_IMPLEMENT PRStatus +nssToken_TraverseCertificatesBySubject +( + NSSToken *token, + nssSession *sessionOpt, + NSSDER *subject, + nssTokenCertSearch *search +) +{ + PRStatus nssrv; + CK_ATTRIBUTE subj_tmpl[] = + { + { CKA_CLASS, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 } + }; + CK_ULONG stsize = (CK_ULONG)(sizeof(subj_tmpl) / sizeof(subj_tmpl[0])); + NSS_CK_SET_ATTRIBUTE_ITEM(subj_tmpl, 0, &g_ck_class_cert); + NSS_CK_SET_ATTRIBUTE_ITEM(subj_tmpl, 1, subject); + nssList_SetCompareFunction(search->cached, compare_cert_by_issuer_sn); + /* now traverse the token certs matching this template */ + nssrv = traverse_objects_by_template(token, sessionOpt, + subj_tmpl, stsize, + retrieve_cert, search); + return nssrv; +} + +NSS_IMPLEMENT PRStatus +nssToken_TraverseCertificatesByNickname +( + NSSToken *token, + nssSession *sessionOpt, + NSSUTF8 *name, + nssTokenCertSearch *search +) +{ + PRStatus nssrv; + CK_ATTRIBUTE nick_tmpl[] = + { + { CKA_CLASS, NULL, 0 }, + { CKA_LABEL, NULL, 0 } + }; + CK_ULONG ntsize = sizeof(nick_tmpl) / sizeof(nick_tmpl[0]); + /* set up the search template */ + NSS_CK_SET_ATTRIBUTE_ITEM(nick_tmpl, 0, &g_ck_class_cert); + nick_tmpl[1].pValue = (CK_VOID_PTR)name; + nick_tmpl[1].ulValueLen = (CK_ULONG)nssUTF8_Length(name, &nssrv); + nssList_SetCompareFunction(search->cached, compare_cert_by_issuer_sn); + /* now traverse the token certs matching this template */ + nssrv = traverse_objects_by_template(token, sessionOpt, + nick_tmpl, ntsize, + retrieve_cert, search); + if (nssrv != PR_SUCCESS) { + return nssrv; + } +#if 0 + /* This is to workaround the fact that PKCS#11 doesn't specify + * whether the '\0' should be included. XXX Is that still true? + * im - this is not needed by the current softoken. However, I'm + * leaving it in until I have surveyed more tokens to see if it needed. + */ + nick_tmpl[1].ulValueLen++; + nssrv = traverse_objects_by_template(token, sessionOpt, + nick_tmpl, ntsize, + retrieve_cert, search); +#endif + return nssrv; +} + +NSS_IMPLEMENT PRStatus +nssToken_TraverseCertificatesByEmail +( + NSSToken *token, + nssSession *sessionOpt, + NSSASCII7 *email, + nssTokenCertSearch *search +) +{ + PRStatus nssrv; + CK_ATTRIBUTE email_tmpl[] = + { + { CKA_CLASS, NULL, 0 }, + { CKA_NETSCAPE_EMAIL, NULL, 0 } + }; + CK_ULONG etsize = sizeof(email_tmpl) / sizeof(email_tmpl[0]); + /* set up the search template */ + NSS_CK_SET_ATTRIBUTE_ITEM(email_tmpl, 0, &g_ck_class_cert); + email_tmpl[1].pValue = (CK_VOID_PTR)email; + email_tmpl[1].ulValueLen = (CK_ULONG)nssUTF8_Length(email, &nssrv); + nssList_SetCompareFunction(search->cached, compare_cert_by_issuer_sn); + /* now traverse the token certs matching this template */ + nssrv = traverse_objects_by_template(token, sessionOpt, + email_tmpl, etsize, + retrieve_cert, search); + if (nssrv != PR_SUCCESS) { + return nssrv; + } +#if 0 + /* This is to workaround the fact that PKCS#11 doesn't specify + * whether the '\0' should be included. XXX Is that still true? + */ + email_tmpl[1].ulValueLen++; + nssrv = traverse_objects_by_template(token, sessionOpt, + email_tmpl, etsize, + retrieve_cert, search); +#endif + return nssrv; +} + +/* XXX these next two need to create instances as needed */ + +NSS_IMPLEMENT NSSCertificate * +nssToken_FindCertificateByIssuerAndSerialNumber +( + NSSToken *token, + nssSession *sessionOpt, + NSSDER *issuer, + NSSDER *serial +) +{ + NSSCertificate *rvCert = NULL; + nssSession *session; + PRBool tokenObject; + PRStatus nssrv; + CK_ULONG ctsize; + CK_OBJECT_HANDLE object; + CK_ATTRIBUTE cert_template[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_ISSUER, NULL, 0 }, + { CKA_SERIAL_NUMBER, NULL, 0 } + }; + ctsize = sizeof(cert_template) / sizeof(cert_template[0]); + /* Set the unique id */ + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 1, issuer); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 2, serial); + /* get the object handle */ + object = find_object_by_template(token, sessionOpt, cert_template, ctsize); + if (object == CK_INVALID_HANDLE) { + return NULL; + } + session = (sessionOpt) ? sessionOpt : token->defaultSession; + rvCert = get_token_cert(token, sessionOpt, object); + if (rvCert) { + NSSTrustDomain *td; + NSSCryptoContext *cc; + tokenObject = nssCKObject_IsAttributeTrue(object, CKA_TOKEN, + session, token->slot, + &nssrv); + if (tokenObject) { + td = token->trustDomain; + cc = NULL; + } else { + td = NULL; + cc = NULL; /* XXX how to recover the crypto context from + * the token? + */ + } + add_object_instance(&rvCert->object, token, object, td, cc); + } + return rvCert; +} + +NSS_IMPLEMENT NSSCertificate * +nssToken_FindCertificateByEncodedCertificate +( + NSSToken *token, + nssSession *sessionOpt, + NSSBER *encodedCertificate +) +{ + NSSCertificate *rvCert = NULL; + nssSession *session; + PRBool tokenObject; + PRStatus nssrv; + CK_ULONG ctsize; + CK_OBJECT_HANDLE object; + CK_ATTRIBUTE cert_template[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_VALUE, NULL, 0 } + }; + ctsize = sizeof(cert_template) / sizeof(cert_template[0]); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); + NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 1, encodedCertificate); + /* get the object handle */ + object = find_object_by_template(token, sessionOpt, cert_template, ctsize); + if (object == CK_INVALID_HANDLE) { + return NULL; + } + session = (sessionOpt) ? sessionOpt : token->defaultSession; + rvCert = get_token_cert(token, sessionOpt, object); + if (rvCert) { + NSSTrustDomain *td; + NSSCryptoContext *cc; + tokenObject = nssCKObject_IsAttributeTrue(object, CKA_TOKEN, + session, token->slot, + &nssrv); + if (tokenObject) { + td = token->trustDomain; + cc = NULL; + } else { + td = NULL; + cc = NULL; /* XXX how to recover the crypto context from + * the token? + */ + } + add_object_instance(&rvCert->object, token, object, td, cc); + } + return rvCert; +} + +static void +sha1_hash(NSSToken *token, NSSItem *input, NSSItem *output) +{ + NSSAlgorithmAndParameters *ap; + ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL); + (void)nssToken_Digest(token, NULL, ap, input, output, NULL); + nss_ZFreeIf(ap); +} + +static void +md5_hash(NSSToken *token, NSSItem *input, NSSItem *output) +{ + NSSAlgorithmAndParameters *ap; + ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL); + (void)nssToken_Digest(token, NULL, ap, input, output, NULL); + nss_ZFreeIf(ap); +} + +NSS_IMPLEMENT PRStatus +nssToken_ImportTrust +( + NSSToken *tok, + nssSession *sessionOpt, + NSSTrust *trust, + NSSTrustDomain *trustDomain, + NSSCryptoContext *cryptoContext +) +{ + PRStatus nssrv; + CK_OBJECT_HANDLE handle; + CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; + CK_ATTRIBUTE trust_tmpl[] = { + { CKA_TOKEN, NULL, 0 }, + { CKA_CLASS, NULL, 0 }, + { CKA_ISSUER, NULL, 0 }, + { CKA_SERIAL_NUMBER, NULL, 0 }, + { CKA_CERT_SHA1_HASH, NULL, 0 }, + { CKA_CERT_MD5_HASH, NULL, 0 }, + { CKA_TRUST_SERVER_AUTH, NULL, 0 }, + { CKA_TRUST_CLIENT_AUTH, NULL, 0 }, + { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 }, + { CKA_TRUST_CODE_SIGNING, NULL, 0 } + }; + CK_ULONG tsize = sizeof(trust_tmpl) / sizeof(trust_tmpl[0]); + PRUint8 sha1[20]; /* this is cheating... */ + PRUint8 md5[16]; + NSSItem sha1_result, md5_result; + NSSCertificate *c = trust->certificate; + sha1_result.data = sha1; sha1_result.size = sizeof sha1; + md5_result.data = md5; md5_result.size = sizeof md5; + sha1_hash(tok, &c->encoding, &sha1_result); + md5_hash(tok, &c->encoding, &md5_result); + if (trustDomain) { + NSS_CK_SET_ATTRIBUTE_ITEM(trust_tmpl, 0, &g_ck_true); + } else { + NSS_CK_SET_ATTRIBUTE_ITEM(trust_tmpl, 0, &g_ck_false); + } + NSS_CK_SET_ATTRIBUTE_VAR( trust_tmpl, 1, tobjc); + NSS_CK_SET_ATTRIBUTE_ITEM(trust_tmpl, 2, &c->issuer); + NSS_CK_SET_ATTRIBUTE_ITEM(trust_tmpl, 3, &c->serial); + NSS_CK_SET_ATTRIBUTE_ITEM(trust_tmpl, 4, &sha1_result); + NSS_CK_SET_ATTRIBUTE_ITEM(trust_tmpl, 5, &md5_result); + /* now set the trust values */ + NSS_CK_SET_ATTRIBUTE_VAR(trust_tmpl, 6, trust->serverAuth); + NSS_CK_SET_ATTRIBUTE_VAR(trust_tmpl, 7, trust->clientAuth); + NSS_CK_SET_ATTRIBUTE_VAR(trust_tmpl, 8, trust->emailProtection); + NSS_CK_SET_ATTRIBUTE_VAR(trust_tmpl, 9, trust->codeSigning); + /* import the trust object onto the token */ + handle = import_object(tok, NULL, trust_tmpl, tsize); + if (handle != CK_INVALID_HANDLE) { + nssrv = add_object_instance(&trust->object, tok, handle, + trustDomain, cryptoContext); + } else { + nssrv = PR_FAILURE; + } + return nssrv; +} + +static CK_OBJECT_HANDLE +get_cert_trust_handle +( + NSSToken *token, + nssSession *session, + NSSCertificate *c +) +{ + CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; + CK_ATTRIBUTE tobj_template[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_CERT_SHA1_HASH, NULL, 0 }, + { CKA_ISSUER, NULL, 0 }, + { CKA_SERIAL_NUMBER, NULL, 0 } + }; + CK_ULONG tobj_size = sizeof(tobj_template) / sizeof(tobj_template[0]); + PRUint8 sha1[20]; /* this is cheating... */ + NSSItem sha1_result; + sha1_result.data = sha1; sha1_result.size = sizeof sha1; + sha1_hash(token, &c->encoding, &sha1_result); + NSS_CK_SET_ATTRIBUTE_VAR( tobj_template, 0, tobjc); + NSS_CK_SET_ATTRIBUTE_ITEM(tobj_template, 1, &sha1_result); + NSS_CK_SET_ATTRIBUTE_ITEM(tobj_template, 2, &c->issuer); + NSS_CK_SET_ATTRIBUTE_ITEM(tobj_template, 3, &c->serial); +#ifdef NSS_3_4_CODE + if (PK11_HasRootCerts(token->pk11slot)) { + tobj_size -= 2; + } + /* + * we need to arrange for the built-in token to lose the bottom 2 + * attributes so that old built-in tokens will continue to work. + */ +#endif + return find_object_by_template(token, session, + tobj_template, tobj_size); +} + +NSS_IMPLEMENT NSSTrust * +nssToken_FindTrustForCert +( + NSSToken *token, + nssSession *sessionOpt, + NSSCertificate *c +) +{ + PRStatus nssrv; + NSSTrust *rvTrust; + nssSession *session; + NSSArena *arena; + nssPKIObject *object; + CK_TRUST saTrust, caTrust, epTrust, csTrust; + CK_OBJECT_HANDLE tobjID; + CK_ATTRIBUTE trust_template[] = { + { CKA_TRUST_SERVER_AUTH, NULL, 0 }, + { CKA_TRUST_CLIENT_AUTH, NULL, 0 }, + { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 }, + { CKA_TRUST_CODE_SIGNING, NULL, 0 } + }; + CK_ULONG trust_size = sizeof(trust_template) / sizeof(trust_template[0]); + session = (sessionOpt) ? sessionOpt : token->defaultSession; + tobjID = get_cert_trust_handle(token, session, c); + if (tobjID == CK_INVALID_HANDLE) { + return NULL; + } + /* Then use the trust object to find the trust settings */ + NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 0, saTrust); + NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 1, caTrust); + NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 2, epTrust); + NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 3, csTrust); + nssrv = nssCKObject_GetAttributes(tobjID, + trust_template, trust_size, + NULL, session, token->slot); + if (nssrv != PR_SUCCESS) { + return NULL; + } + arena = nssArena_Create(); + if (!arena) { + return NULL; + } + rvTrust = nss_ZNEW(arena, NSSTrust); + if (!rvTrust) { + nssArena_Destroy(arena); + return NULL; + } + object = &rvTrust->object; + object->arena = arena; + object->refCount = 1; + object->instanceList = nssList_Create(arena, PR_TRUE); + if (!object->instanceList) { + nssArena_Destroy(arena); + return NULL; + } + object->instances = nssList_CreateIterator(object->instanceList); + if (!object->instances) { + nssArena_Destroy(arena); + return NULL; + } + /* need to figure out trust domain and/or crypto context */ + nssrv = add_object_instance(object, token, tobjID, + token->trustDomain, NULL); + if (nssrv != PR_SUCCESS) { + nssArena_Destroy(arena); + return NULL; + } + rvTrust->serverAuth = saTrust; + rvTrust->clientAuth = caTrust; + rvTrust->emailProtection = epTrust; + rvTrust->codeSigning = csTrust; + return rvTrust; +} + diff --git a/security/nss/lib/dev/devt.h b/security/nss/lib/dev/devt.h index 5de332442f7..09281d03204 100644 --- a/security/nss/lib/dev/devt.h +++ b/security/nss/lib/dev/devt.h @@ -35,7 +35,7 @@ #define DEVT_H #ifdef DEBUG -static const char DEVT_CVS_ID[] = "@(#) $RCSfile: devt.h,v $ $Revision: 1.6 $ $Date: 2001-11-08 00:14:53 $ $Name: $"; +static const char DEVT_CVS_ID[] = "@(#) $RCSfile: devt.h,v $ $Revision: 1.7 $ $Date: 2001-11-28 16:23:39 $ $Name: $"; #endif /* DEBUG */ /* @@ -60,12 +60,18 @@ static const char DEVT_CVS_ID[] = "@(#) $RCSfile: devt.h,v $ $Revision: 1.6 $ $D #include "nssckt.h" #endif /* NSSCKT_H */ +#ifndef BASET_H +#include "baset.h" +#endif /* BASET_H */ + #ifdef NSS_3_4_CODE #include "secmodt.h" #endif /* NSS_3_4_CODE */ PR_BEGIN_EXTERN_C +typedef struct nssSessionStr nssSession; + /* The list of boolean flags used to describe properties of a * module. */ @@ -138,6 +144,47 @@ struct nssSessionStr PRBool isRW; }; +typedef enum { + NSSCertificateType_Unknown = 0, + NSSCertificateType_PKIX = 1 +} NSSCertificateType; + +#ifdef nodef +typedef enum { + nssTrustLevel_Unknown = 0, + nssTrustLevel_NotTrusted = 1, + nssTrustLevel_Trusted = 2, + nssTrustLevel_TrustedDelegator = 3, + nssTrustLevel_Valid = 4 +} nssTrustLevel; +#else +typedef CK_ULONG nssTrustLevel; /* for now */ +#endif + +typedef struct nssCryptokiInstanceStr nssCryptokiInstance; + +struct nssCryptokiInstanceStr +{ + CK_OBJECT_HANDLE handle; + NSSToken *token; +}; + +typedef struct nssTokenCertSearchStr nssTokenCertSearch; + +struct nssTokenCertSearchStr +{ + PRStatus (* callback)(NSSCertificate *c, void *arg); + void *cbarg; + nssList *cached; + NSSTrustDomain *trustDomain; + NSSCryptoContext *cryptoContext; +}; + +struct NSSAlgorithmAndParametersStr +{ + CK_MECHANISM mechanism; +}; + PR_END_EXTERN_C #endif /* DEVT_H */ diff --git a/security/nss/lib/dev/devtoken.c b/security/nss/lib/dev/devtoken.c index 32ea2977717..e42bba065d3 100644 --- a/security/nss/lib/dev/devtoken.c +++ b/security/nss/lib/dev/devtoken.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.2 $ $Date: 2001-11-09 00:36:12 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.3 $ $Date: 2001-11-28 16:23:39 $ $Name: $"; #endif /* DEBUG */ #ifndef DEV_H @@ -43,23 +43,10 @@ static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.2 $ $Da #include "devm.h" #endif /* DEVM_H */ -/* for the cache... */ -#ifndef PKI_H -#include "pki.h" -#endif /* PKI_H */ - #ifndef NSSCKEPV_H #include "nssckepv.h" #endif /* NSSCKEPV_H */ -#ifndef NSSPKI_H -#include "nsspki.h" -#endif /* NSSPKI_H */ - -#ifndef PKI_H -#include "pki.h" -#endif /* PKI_H */ - #ifndef CKHELPER_H #include "ckhelper.h" #endif /* CKHELPER_H */ @@ -207,330 +194,191 @@ nssToken_GetName return tok->name; } -NSS_IMPLEMENT PRStatus -nssToken_DeleteStoredObject +NSS_IMPLEMENT NSSItem * +nssToken_Digest ( NSSToken *tok, nssSession *sessionOpt, - CK_OBJECT_HANDLE object + NSSAlgorithmAndParameters *ap, + NSSItem *data, + NSSItem *rvOpt, + NSSArena *arenaOpt ) { - nssSession *session = NULL; - CK_RV ckrv; - PRStatus nssrv; - PRBool createdSession; - if (nssCKObject_IsAttributeTrue(object, CKA_TOKEN, tok->defaultSession, - tok->slot, &nssrv)) { - if (sessionOpt) { - if (!nssSession_IsReadWrite(sessionOpt)) { - return PR_FAILURE;; - } else { - session = sessionOpt; - } - } else if (nssSession_IsReadWrite(tok->defaultSession)) { - session = tok->defaultSession; - } else { - session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE); - createdSession = PR_TRUE; - } - } - - if (session == NULL) { - return PR_FAILURE; - } - - nssSession_EnterMonitor(session); - ckrv = CKAPI(tok->slot)->C_DestroyObject(session->handle, object); - nssSession_ExitMonitor(session); - if (createdSession) { - nssSession_Destroy(session); - } - if (ckrv != CKR_OK) { - return PR_FAILURE; - } - return PR_SUCCESS; -} - -NSS_IMPLEMENT CK_OBJECT_HANDLE -nssToken_ImportObject -( - NSSToken *tok, - nssSession *sessionOpt, - CK_ATTRIBUTE_PTR objectTemplate, - CK_ULONG otsize -) -{ - nssSession *session = NULL; - PRBool createdSession = PR_FALSE; - CK_OBJECT_HANDLE object; - CK_RV ckrv; - - if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) { - if (sessionOpt) { - if (!nssSession_IsReadWrite(sessionOpt)) { - return CK_INVALID_HANDLE; - } else { - session = sessionOpt; - } - } else if (nssSession_IsReadWrite(tok->defaultSession)) { - session = tok->defaultSession; - } else { - session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE); - createdSession = PR_TRUE; - } - } - if (session == NULL) { - return PR_FAILURE; - } - nssSession_EnterMonitor(session); - ckrv = CKAPI(tok->slot)->C_CreateObject(session->handle, - objectTemplate, otsize, - &object); - nssSession_ExitMonitor(session); - if (createdSession) { - nssSession_Destroy(session); - } - if (ckrv != CKR_OK) { - return CK_INVALID_HANDLE; - } - return object; -} - -NSS_IMPLEMENT CK_OBJECT_HANDLE -nssToken_FindObjectByTemplate -( - NSSToken *tok, - nssSession *sessionOpt, - CK_ATTRIBUTE_PTR cktemplate, - CK_ULONG ctsize -) -{ - CK_SESSION_HANDLE hSession; - CK_OBJECT_HANDLE rvObject; - CK_ULONG count; CK_RV ckrv; + CK_ULONG digestLen; + CK_BYTE_PTR digest; + NSSItem *rvItem = NULL; nssSession *session; session = (sessionOpt) ? sessionOpt : tok->defaultSession; - hSession = session->handle; nssSession_EnterMonitor(session); - ckrv = CKAPI(tok)->C_FindObjectsInit(hSession, cktemplate, ctsize); + ckrv = CKAPI(tok)->C_DigestInit(session->handle, &ap->mechanism); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); - return CK_INVALID_HANDLE; + return NULL; } - ckrv = CKAPI(tok)->C_FindObjects(hSession, &rvObject, 1, &count); +#if 0 + /* XXX the standard says this should work, but it doesn't */ + ckrv = CKAPI(tok)->C_Digest(session->handle, NULL, 0, NULL, &digestLen); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); - return CK_INVALID_HANDLE; + return NULL; } - ckrv = CKAPI(tok)->C_FindObjectsFinal(hSession); - nssSession_ExitMonitor(session); - if (ckrv != CKR_OK) { - return CK_INVALID_HANDLE; - } - return rvObject; -} - -extern const NSSError NSS_ERROR_MAXIMUM_FOUND; - -struct collect_arg_str -{ - NSSArena *arena; - nssList *list; - PRUint32 maximum; -}; - -static PRStatus -collect_certs_callback(NSSToken *t, nssSession *session, - CK_OBJECT_HANDLE h, void *arg) -{ - NSSCertificate *cert; - struct collect_arg_str *ca = (struct collect_arg_str *)arg; - cert = nssCertificate_CreateFromHandle(ca->arena, h, session, t->slot); - if (!cert) { - goto loser; - } - /* addref */ - nssList_Add(ca->list, (void *)cert); - 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; -loser: - return PR_FAILURE; -} - -struct cert_callback_str { - nssListIterator *cachedCerts; - PRStatus (*callback)(NSSCertificate *c, void *arg); - void *arg; -}; - -static PRStatus -retrieve_cert(NSSToken *t, nssSession *session, CK_OBJECT_HANDLE h, void *arg) -{ - NSSCertificate *cert = NULL; - NSSCertificate *c; - struct cert_callback_str *ccb = (struct cert_callback_str *)arg; - if (ccb->cachedCerts) { - for (c = (NSSCertificate *)nssListIterator_Start(ccb->cachedCerts); - c != (NSSCertificate *)NULL; - c = (NSSCertificate *)nssListIterator_Next(ccb->cachedCerts)) - { - if (c->handle == h && c->token == t) { - /* this is enough, right? */ - cert = c; - break; - } - } - nssListIterator_Finish(ccb->cachedCerts); - } - if (!cert) { - /* Could not find cert, so create it */ - cert = nssCertificate_CreateFromHandle(NULL, h, session, t->slot); - if (!cert) { - goto loser; - } - } - /* Got the cert, feed it to the callback */ - return (*ccb->callback)(cert, ccb->arg); -loser: - return PR_FAILURE; -} - -#define OBJECT_STACK_SIZE 16 - -static PRStatus -nsstoken_TraverseObjects -( - NSSToken *tok, - nssSession *session, - CK_ATTRIBUTE_PTR obj_template, - CK_ULONG otsize, - PRStatus (*callback)(NSSToken *t, nssSession *session, - CK_OBJECT_HANDLE h, void *arg), - void *arg -) -{ - NSSSlot *slot; - PRStatus cbrv; - PRUint32 i; - CK_RV ckrv; - CK_ULONG count; - CK_OBJECT_HANDLE *objectStack; - CK_OBJECT_HANDLE startOS[OBJECT_STACK_SIZE]; - CK_SESSION_HANDLE hSession; - NSSArena *objectArena = NULL; - nssList *objectList = NULL; - slot = tok->slot; - hSession = session->handle; - objectStack = startOS; - nssSession_EnterMonitor(session); - ckrv = CKAPI(slot)->C_FindObjectsInit(hSession, obj_template, otsize); - if (ckrv != CKR_OK) { - nssSession_ExitMonitor(session); - goto loser; - } - while (PR_TRUE) { - ckrv = CKAPI(slot)->C_FindObjects(hSession, objectStack, - OBJECT_STACK_SIZE, &count); - if (ckrv != CKR_OK) { +#endif + digestLen = 0; /* XXX for now */ + digest = NULL; + if (rvOpt) { + if (rvOpt->size > 0 && rvOpt->size < digestLen) { nssSession_ExitMonitor(session); - goto loser; + /* the error should be bad args */ + return NULL; } - if (count == OBJECT_STACK_SIZE) { - if (!objectList) { - objectArena = NSSArena_Create(); - objectList = nssList_Create(objectArena, PR_FALSE); - } - objectStack = nss_ZNEWARRAY(objectArena, CK_OBJECT_HANDLE, - OBJECT_STACK_SIZE); - nssList_Add(objectList, objectStack); - } else { - break; + if (rvOpt->data) { + digest = rvOpt->data; + } + digestLen = rvOpt->size; + } + if (!digest) { + digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen); + if (!digest) { + nssSession_ExitMonitor(session); + return NULL; } } - ckrv = CKAPI(slot)->C_FindObjectsFinal(hSession); + ckrv = CKAPI(tok)->C_Digest(session->handle, + (CK_BYTE_PTR)data->data, + (CK_ULONG)data->size, + (CK_BYTE_PTR)digest, + &digestLen); nssSession_ExitMonitor(session); if (ckrv != CKR_OK) { - goto loser; + nss_ZFreeIf(digest); + return NULL; } - if (objectList) { - nssListIterator *objects; - objects = nssList_CreateIterator(objectList); - for (objectStack = (CK_OBJECT_HANDLE *)nssListIterator_Start(objects); - objectStack != NULL; - objectStack = (CK_OBJECT_HANDLE *)nssListIterator_Next(objects)) { - for (i=0; idefaultSession; - /* this isn't really traversal, it's find by template ... */ - if (cachedList) { - ccb.cachedCerts = nssList_CreateIterator(cachedList); - } else { - ccb.cachedCerts = NULL; - } - ccb.callback = callback; - ccb.arg = arg; - rv = nsstoken_TraverseObjects(tok, session, - cktemplate, ctsize, - retrieve_cert, (void *)&ccb); - return rv; + nssSession_EnterMonitor(session); + ckrv = CKAPI(tok)->C_DigestInit(session->handle, &ap->mechanism); + nssSession_ExitMonitor(session); + return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; +} + +NSS_IMPLEMENT PRStatus +nssToken_ContinueDigest +( + NSSToken *tok, + nssSession *sessionOpt, + NSSItem *item +) +{ + CK_RV ckrv; + nssSession *session; + session = (sessionOpt) ? sessionOpt : tok->defaultSession; + nssSession_EnterMonitor(session); + ckrv = CKAPI(tok)->C_DigestUpdate(session->handle, + (CK_BYTE_PTR)item->data, + (CK_ULONG)item->size); + nssSession_ExitMonitor(session); + return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; +} + +NSS_IMPLEMENT NSSItem * +nssToken_FinishDigest +( + NSSToken *tok, + nssSession *sessionOpt, + NSSItem *rvOpt, + NSSArena *arenaOpt +) +{ + CK_RV ckrv; + CK_ULONG digestLen; + CK_BYTE_PTR digest; + NSSItem *rvItem = NULL; + nssSession *session; + session = (sessionOpt) ? sessionOpt : tok->defaultSession; + nssSession_EnterMonitor(session); + ckrv = CKAPI(tok)->C_DigestFinal(session->handle, NULL, &digestLen); + if (ckrv != CKR_OK || digestLen == 0) { + nssSession_ExitMonitor(session); + return NULL; + } + digest = NULL; + if (rvOpt) { + if (rvOpt->size > 0 && rvOpt->size < digestLen) { + nssSession_ExitMonitor(session); + /* the error should be bad args */ + return NULL; + } + if (rvOpt->data) { + digest = rvOpt->data; + } + digestLen = rvOpt->size; + } + if (!digest) { + digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen); + if (!digest) { + nssSession_ExitMonitor(session); + return NULL; + } + } + ckrv = CKAPI(tok)->C_DigestFinal(session->handle, digest, &digestLen); + nssSession_ExitMonitor(session); + if (ckrv != CKR_OK) { + nss_ZFreeIf(digest); + return NULL; + } + if (!rvOpt) { + rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest); + } + return rvItem; +} + +/* XXX of course this doesn't belong here */ +NSS_IMPLEMENT NSSAlgorithmAndParameters * +NSSAlgorithmAndParameters_CreateSHA1Digest +( + NSSArena *arenaOpt +) +{ + NSSAlgorithmAndParameters *rvAP = NULL; + rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); + if (rvAP) { + rvAP->mechanism.mechanism = CKM_SHA_1; + rvAP->mechanism.pParameter = NULL; + rvAP->mechanism.ulParameterLen = 0; + } + return rvAP; +} + +NSS_IMPLEMENT NSSAlgorithmAndParameters * +NSSAlgorithmAndParameters_CreateMD5Digest +( + NSSArena *arenaOpt +) +{ + NSSAlgorithmAndParameters *rvAP = NULL; + rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); + if (rvAP) { + rvAP->mechanism.mechanism = CKM_MD5; + rvAP->mechanism.pParameter = NULL; + rvAP->mechanism.ulParameterLen = 0; + } + return rvAP; } diff --git a/security/nss/lib/dev/manifest.mn b/security/nss/lib/dev/manifest.mn index 860c09cf040..c8397a5c6c6 100644 --- a/security/nss/lib/dev/manifest.mn +++ b/security/nss/lib/dev/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.3 $ $Date: 2001-11-08 00:14:53 $ $Name: $" +MANIFEST_CVS_ID = "@(#) $RCSfile: manifest.mn,v $ $Revision: 1.4 $ $Date: 2001-11-28 16:23:39 $ $Name: $" CORE_DEPTH = ../../.. @@ -48,9 +48,10 @@ MODULE = security CSRCS = \ devmod.c \ - devslot.c \ - devtoken.c \ - devutil.c \ + devslot.c \ + devobject.c \ + devtoken.c \ + devutil.c \ ckhelper.c \ $(NULL) diff --git a/security/nss/lib/dev/nssdevt.h b/security/nss/lib/dev/nssdevt.h index 2a056f2b718..24c2c05f2a4 100644 --- a/security/nss/lib/dev/nssdevt.h +++ b/security/nss/lib/dev/nssdevt.h @@ -35,7 +35,7 @@ #define NSSDEVT_H #ifdef DEBUG -static const char NSSDEVT_CVS_ID[] = "@(#) $RCSfile: nssdevt.h,v $ $Revision: 1.2 $ $Date: 2001-11-08 00:14:54 $ $Name: $"; +static const char NSSDEVT_CVS_ID[] = "@(#) $RCSfile: nssdevt.h,v $ $Revision: 1.3 $ $Date: 2001-11-28 16:23:39 $ $Name: $"; #endif /* DEBUG */ /* @@ -64,8 +64,6 @@ typedef struct NSSSlotStr NSSSlot; typedef struct NSSTokenStr NSSToken; -typedef struct nssSessionStr nssSession; - PR_END_EXTERN_C #endif /* NSSDEVT_H */ diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c index 339cf7d2eb3..b70ebea8627 100644 --- a/security/nss/lib/pk11wrap/pk11cert.c +++ b/security/nss/lib/pk11wrap/pk11cert.c @@ -58,8 +58,9 @@ #include "pki3hack.h" #include "dev3hack.h" -/*#include "dev.h" */ +#include "dev.h" #include "nsspki.h" +#include "pkim.h" #include "pkitm.h" #define PK11_SEARCH_CHUNKSIZE 10 @@ -1135,6 +1136,23 @@ PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr, return objID; } +static PRStatus +get_newest_cert(NSSCertificate *c, void *arg) +{ + nssDecodedCert *dc, *founddc; + NSSCertificate **cfound = (NSSCertificate **)arg; + if (!*cfound) { + *cfound = c; + return PR_SUCCESS; + } + dc = nssCertificate_GetDecoding(c); + founddc = nssCertificate_GetDecoding(*cfound); + if (!founddc->isNewerThan(founddc, dc)) { + *cfound = c; + } + return PR_SUCCESS; +} + CERTCertificate * PK11_FindCertFromNickname(char *nickname, void *wincx) { @@ -1167,19 +1185,34 @@ PK11_FindCertFromNickname(char *nickname, void *wincx) { /* find token by name */ token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName); if (token) { + nssTokenCertSearch search; + nssList *certList; + certList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, + nickname, + certList); + /* set the search criteria */ + search.callback = get_newest_cert; + search.cbarg = (void *)&cert; + search.cached = certList; + search.trustDomain = defaultTD; + search.cryptoContext = NULL; /* find best cert on token */ - cert = nssTrustDomain_FindBestCertificateByNicknameForToken( - defaultTD, - token, - (NSSUTF8 *)nickname, - NULL, - &usage, - NULL); + nssToken_TraverseCertificatesByNickname(token, NULL, + (NSSUTF8 *)nickname, + &search); + nssList_Destroy(certList); if (!cert) { - /* don't have a "for token" here yet... */ - cert = NSSTrustDomain_FindCertificateByEmail(defaultTD, - (NSSASCII7 *)nickname, - NULL, &usage, NULL); + certList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForEmailAddressFromCache( + defaultTD, + nickname, + certList); + search.cached = certList; + nssToken_TraverseCertificatesByNickname(token, NULL, + (NSSASCII7 *)nickname, + &search); + nssList_Destroy(certList); } } } else { @@ -1206,6 +1239,15 @@ PK11_FindCertFromNickname(char *nickname, void *wincx) { #endif } +static PRStatus +collect_certs(NSSCertificate *c, void *arg) +{ + nssList *list = (nssList *)arg; + /* Add the cert to the return list */ + nssList_AddUnique(list, (void *)c); + return PR_SUCCESS; +} + CERTCertList * PK11_FindCertsFromNickname(char *nickname, void *wincx) { #ifdef NSS_CLASSIC @@ -1233,11 +1275,13 @@ PK11_FindCertsFromNickname(char *nickname, void *wincx) { PORT_Free(certID); return certList; #else + PRStatus nssrv; char *delimit = NULL; char *tokenName; - CERTCertList *certList = CERT_NewCertList(); + int i; + CERTCertList *certList = NULL; NSSCertificate **foundCerts; - NSSCertificate **pCerts; + NSSCertificate *c; NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); if ((delimit = PORT_Strchr(nickname,':')) != NULL) { NSSToken *token; @@ -1247,14 +1291,25 @@ PK11_FindCertsFromNickname(char *nickname, void *wincx) { /* find token by name */ token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName); if (token) { - /* find best cert on token */ - foundCerts = nssTrustDomain_FindCertificatesByNicknameForToken( - defaultTD, - token, - (NSSUTF8 *)nickname, - NULL, - 0, - NULL); + nssTokenCertSearch search; + PRUint32 count; + nssList *nameList; + nameList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, + nickname, + nameList); + /* set the search criteria */ + search.callback = collect_certs; + search.cbarg = nameList; + search.cached = nameList; + search.trustDomain = defaultTD; + search.cryptoContext = NULL; + nssrv = nssToken_TraverseCertificatesByNickname(token, NULL, + nickname, &search); + count = nssList_Count(nameList); + foundCerts = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1); + nssList_GetArray(nameList, (void **)foundCerts, count); + nssList_Destroy(nameList); } *delimit = ':'; } else { @@ -1265,17 +1320,17 @@ PK11_FindCertsFromNickname(char *nickname, void *wincx) { 0, NULL); } - pCerts = foundCerts; - while (pCerts != NULL) { - NSSCertificate *c = *pCerts; - CERT_AddCertToListTail(certList, STAN_GetCERTCertificate(c)); - pCerts++; + if (foundCerts) { + certList = CERT_NewCertList(); + for (i=0, c = *foundCerts; c; c = foundCerts[++i]) { + CERT_AddCertToListTail(certList, STAN_GetCERTCertificate(c)); + } + if (CERT_LIST_HEAD(certList) == NULL) { + CERT_DestroyCertList(certList); + certList = NULL; + } + nss_ZFreeIf(foundCerts); } - if (CERT_LIST_HEAD(certList) == NULL) { - CERT_DestroyCertList(certList); - certList = NULL; - } - nss_ZFreeIf(foundCerts); return certList; #endif } @@ -1482,10 +1537,22 @@ PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, PORT_SetError( PK11_MapError(crv) ); } + if (!cert->nickname && nickname) { + cert->nickname = PORT_ArenaStrdup(cert->arena, nickname); + } + + cert->pkcs11ID = certID; + cert->dbhandle = STAN_GetDefaultTrustDomain(); if (cert->slot == NULL) { cert->slot = PK11_ReferenceSlot(slot); if (cert->nssCertificate) { - cert->nssCertificate->token = slot->nssToken; + nssPKIObjectInstance *instance; + NSSCertificate *c = cert->nssCertificate; + instance = nss_ZNEW(c->object.arena, nssPKIObjectInstance); + instance->cryptoki.token = slot->nssToken; + instance->cryptoki.handle = cert->pkcs11ID; + instance->trustDomain = cert->dbhandle; + nssList_Add(c->object.instanceList, instance); } else { cert->nssCertificate = STAN_GetNSSCertificate(cert); } @@ -2262,31 +2329,29 @@ PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot, return PK11_TraverseSlot(slot, &callarg); #else - /* Alas, stan isn't really made for this... perhaps collect all matching - * subject certs on the token and then pass the certs to the callback? - */ struct nss3_cert_cbstr pk11cb; PRStatus nssrv; - NSSToken *tok; - CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; - CK_ATTRIBUTE theTemplate[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_SUBJECT, NULL, 0 }, - }; - CK_ATTRIBUTE *attr = theTemplate; - CK_ULONG templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]); - PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++; - PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len); + NSSToken *token; + NSSDER subject; + NSSTrustDomain *td; + nssList *subjectList; + nssTokenCertSearch search; pk11cb.callback = callback; pk11cb.arg = arg; - tok = PK11Slot_GetNSSToken(slot); - if (tok) { - nssrv = nssToken_TraverseCertificatesByTemplate(tok, NULL, NULL, - theTemplate, templateSize, - convert_cert, &pk11cb); - } else { - return SECFailure; - } + td = STAN_GetDefaultTrustDomain(); + NSSITEM_FROM_SECITEM(&subject, &cert->derSubject); + subjectList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject, subjectList); + /* set the search criteria */ + search.callback = convert_cert; + search.cbarg = &pk11cb; + search.cached = subjectList; + search.trustDomain = td; + search.cryptoContext = NULL; + token = PK11Slot_GetNSSToken(slot); + nssrv = nssToken_TraverseCertificatesBySubject(token, NULL, + &subject, &search); + nssList_Destroy(subjectList); return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; #endif } @@ -2328,31 +2393,37 @@ PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot, return PK11_TraverseSlot(slot, &callarg); #else - /* Alas, stan isn't really made for this... perhaps collect all matching - * subject certs on the token and then pass the certs to the callback? - */ struct nss3_cert_cbstr pk11cb; PRStatus nssrv; - NSSToken *tok; - CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; - CK_ATTRIBUTE theTemplate[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_LABEL, NULL, 0 }, - }; - CK_ATTRIBUTE *attr = theTemplate; - CK_ULONG templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]); - PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++; - PK11_SETATTRS(attr,CKA_LABEL,nickname->data,nickname->len); + NSSToken *token; + NSSTrustDomain *td; + NSSUTF8 *nick; + PRBool created = PR_FALSE; + nssTokenCertSearch search; + nssList *nameList; pk11cb.callback = callback; pk11cb.arg = arg; - tok = PK11Slot_GetNSSToken(slot); - if (tok) { - nssrv = nssToken_TraverseCertificatesByTemplate(tok, NULL, NULL, - theTemplate, templateSize, - convert_cert, &pk11cb); + if (nickname->data[nickname->len-1] != '\0') { + nick = nssUTF8_Create(NULL, nssStringType_UTF8String, + nickname->data, nickname->len-1); + created = PR_TRUE; } else { - return SECFailure; + nick = (NSSUTF8 *)nickname->data; } + td = STAN_GetDefaultTrustDomain(); + nameList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList); + /* set the search criteria */ + search.callback = convert_cert; + search.cbarg = &pk11cb; + search.cached = nameList; + search.trustDomain = td; + search.cryptoContext = NULL; + token = PK11Slot_GetNSSToken(slot); + nssrv = nssToken_TraverseCertificatesByNickname(token, NULL, + nick, &search); + nssList_Destroy(nameList); + if (created) nss_ZFreeIf(nick); return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; #endif } @@ -2387,17 +2458,29 @@ PK11_TraverseCertsInSlot(PK11SlotInfo *slot, callarg.templateCount = templateSize; return PK11_TraverseSlot(slot, &callarg); #else + PRStatus nssrv; + NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); struct nss3_cert_cbstr pk11cb; NSSToken *tok; + nssList *certList = nssList_Create(NULL, PR_FALSE); + nssTokenCertSearch search; pk11cb.callback = callback; pk11cb.arg = arg; + (void *)nssTrustDomain_GetCertsFromCache(td, certList); + /* set the search criteria */ + search.callback = convert_cert; + search.cbarg = &pk11cb; + search.cached = certList; + search.trustDomain = td; + search.cryptoContext = NULL; tok = PK11Slot_GetNSSToken(slot); if (tok) { - return (SECStatus)nssToken_TraverseCertificates(tok, NULL, - convert_cert, &pk11cb); + nssrv = nssToken_TraverseCertificates(tok, NULL, &search); } else { - return SECFailure; + nssrv = PR_FAILURE; } + nssList_Destroy(certList); + return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; #endif } @@ -2441,12 +2524,11 @@ PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertificate *rvCert = NULL; NSSCertificate *c; NSSDER derCert; - derCert.data = (void *)cert->derCert.data; - derCert.size = (PRUint32)cert->derCert.len; + NSSToken *tok; + tok = PK11Slot_GetNSSToken(slot); + NSSITEM_FROM_SECITEM(&derCert, &cert->derCert); /* XXX login to slots */ - c = NSSTrustDomain_FindCertificateByEncodedCertificate( - STAN_GetDefaultTrustDomain(), - &derCert); + c = nssToken_FindCertificateByEncodedCertificate(tok, NULL, &derCert); if (c) { rvCert = STAN_GetCERTCertificate(c); } @@ -2803,7 +2885,11 @@ isOnList(CERTCertList *certList,CERTCertificate *cert) return PR_FALSE; } static SECStatus +#ifdef NSS_CLASSIC pk11ListCertCallback(CERTCertificate *cert, SECItem *derCert, void *arg) +#else +pk11ListCertCallback(CERTCertificate *cert, void *arg) +#endif { struct listCertsStr *listCertP = (struct listCertsStr *)arg; CERTCertificate *newCert = NULL; @@ -2821,11 +2907,15 @@ pk11ListCertCallback(CERTCertificate *cert, SECItem *derCert, void *arg) if (!isUnique && cert->nickname) { nickname = PORT_ArenaStrdup(listCertP->certList->arena,cert->nickname); } +#ifdef NSS_CLASSIC if (derCert == NULL) { newCert=CERT_DupCertificate(cert); } else { newCert=CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),&cert->derCert); } +#else + newCert=CERT_DupCertificate(cert); +#endif if (newCert == NULL) return SECSuccess; @@ -2870,13 +2960,6 @@ pk11ListCertCallback(CERTCertificate *cert, SECItem *derCert, void *arg) return SECSuccess; } -static SECStatus -pk11ListCertCallbackStub(CERTCertificate *cert, void *arg) -{ - return pk11ListCertCallback(cert, NULL, arg); -} - - CERTCertList * PK11_ListCerts(PK11CertListType type, void *pwarg) @@ -2904,8 +2987,7 @@ PK11_ListCerts(PK11CertListType type, void *pwarg) certList = CERT_NewCertList(); listCerts.type = type; listCerts.certList = certList; - /* XXX need to fix, this callback is of a different form */ - pk11cb.callback = pk11ListCertCallbackStub; + pk11cb.callback = pk11ListCertCallback; pk11cb.arg = &listCerts; NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb); return certList; diff --git a/security/nss/lib/pki/certificate.c b/security/nss/lib/pki/certificate.c index 1c2b871c838..a8c21e7be0e 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.16 $ $Date: 2001-11-20 18:28:46 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.17 $ $Date: 2001-11-28 16:23:43 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSPKI_H @@ -51,17 +51,9 @@ static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.16 $ #include "dev.h" #endif /* DEV_H */ -#ifndef CKHELPER_H -#include "ckhelper.h" -#endif /* CKHELPER_H */ - -#ifndef CKT_H #ifdef NSS_3_4_CODE #include "pki3hack.h" -#define NSSCKT_H #endif -#include "ckt.h" -#endif /* CKT_H */ #ifndef BASE_H #include "base.h" @@ -69,37 +61,6 @@ static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.16 $ extern const NSSError NSS_ERROR_NOT_FOUND; -/* Hm, sadly, I'm using PK11_HashBuf... Need to get crypto context going to - * get rid of that - */ -#ifndef NSS_3_4_CODE -#define NSS_3_4_CODE -#endif /* 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) - */ -NSS_IMPLEMENT NSSUTF8 * -NSSCertificate_GetLabel -( - NSSCertificate *c -) -{ - return c->nickname; -} - -NSS_IMPLEMENT NSSItem * -NSSCertificate_GetID -( - NSSCertificate *c -) -{ - return &c->id; -} - NSS_IMPLEMENT NSSCertificate * nssCertificate_AddRef ( @@ -107,350 +68,29 @@ nssCertificate_AddRef ) { #ifdef NSS_3_4_CODE + /* CERTCertificate *cc = STAN_GetCERTCertificate(c); CERT_DupCertificate(cc); + */ #else c->refCount++; #endif return c; } -/* NSS needs access to this function, but does anyone else? */ -/* XXX for the 3.4 hack anyway, yes */ -NSS_IMPLEMENT NSSCertificate * -NSSCertificate_Create -( - NSSArena *arenaOpt -) -{ - NSSArena *arena; - NSSCertificate *rvCert; - arena = (arenaOpt) ? arenaOpt : nssArena_Create(); - if (!arena) { - goto loser; - } - arena = NSSArena_Create(); - if(!arena) { - return (NSSCertificate *)NULL; - } - rvCert = nss_ZNEW(arena, NSSCertificate); - if (!rvCert) { - goto loser; - } - rvCert->refCount = 1; - if (!arenaOpt) { - rvCert->arena = arena; - } - rvCert->handle = CK_INVALID_HANDLE; - return rvCert; -loser: - if (!arenaOpt && arena) { - nssArena_Destroy(arena); - } - 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; - } -} - -static CK_OBJECT_HANDLE -get_cert_trust_handle -( - NSSCertificate *c, - nssSession *session -) -{ - CK_ULONG tobj_size; - CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; - CK_ATTRIBUTE tobj_template[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_CERT_SHA1_HASH, NULL, 0 }, - { CKA_ISSUER, NULL, 0 }, - { CKA_SERIAL_NUMBER, NULL, 0 } - }; - unsigned char sha1_hash[SHA1_LENGTH]; - tobj_size = sizeof(tobj_template) / sizeof(tobj_template[0]); - NSS_CK_SET_ATTRIBUTE_VAR(tobj_template, 0, tobjc); - /* 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 = (CK_VOID_PTR)sha1_hash; - tobj_template[1].ulValueLen = (CK_ULONG)SHA1_LENGTH; - NSS_CK_SET_ATTRIBUTE_ITEM(tobj_template, 2, &c->issuer); - NSS_CK_SET_ATTRIBUTE_ITEM(tobj_template, 3, &c->serial); -#ifdef NSS_3_4_CODE - if (PK11_HasRootCerts(c->token->pk11slot)) { - tobj_size -= 2; - } -#endif - - /* - * we need to arrange for the built-in token to loose the bottom 2 - * attributes so that old built-in tokens will continue to work. - */ - return nssToken_FindObjectByTemplate(c->token, session, - tobj_template, tobj_size); -} - -static PRStatus -nssCertificate_GetCertTrust -( - NSSCertificate *c, - nssSession *session -) -{ - PRStatus nssrv; - CK_TRUST saTrust, caTrust, epTrust, csTrust; - CK_OBJECT_HANDLE tobjID; - CK_ULONG trust_size; - CK_ATTRIBUTE trust_template[] = { - { CKA_TRUST_SERVER_AUTH, NULL, 0 }, - { CKA_TRUST_CLIENT_AUTH, NULL, 0 }, - { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 }, - { CKA_TRUST_CODE_SIGNING, NULL, 0 } - }; - trust_size = sizeof(trust_template) / sizeof(trust_template[0]); - tobjID = get_cert_trust_handle(c, session); - if (tobjID == CK_INVALID_HANDLE) { - return PR_FAILURE; - } - /* Then use the trust object to find the trust settings */ - NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 0, saTrust); - NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 1, caTrust); - NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 2, epTrust); - NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 3, csTrust); - nssrv = nssCKObject_GetAttributes(tobjID, - trust_template, trust_size, - NULL, session, c->slot); - c->trust.serverAuth = saTrust; - c->trust.clientAuth = caTrust; - c->trust.emailProtection = epTrust; - c->trust.codeSigning = csTrust; - 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 ? c->nickname : c->email; - if (!label) return; - 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 -( - NSSArena *arenaOpt, - CK_OBJECT_HANDLE object, - nssSession *session, - NSSSlot *slot -) -{ - NSSCertificate *rvCert; - PRStatus nssrv; - CK_ULONG template_size; - CK_ATTRIBUTE cert_template[] = { - { 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 }, - { CKA_NETSCAPE_EMAIL, NULL, 0 } - }; - template_size = sizeof(cert_template) / sizeof(cert_template[0]); - rvCert = NSSCertificate_Create(arenaOpt); - if (!rvCert) { - 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) { - /* okay, but if failed because one of the attributes could not be - * found, do it gracefully (i.e., catch the error). - */ - goto loser; - } - 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); - NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[7], rvCert->email); - nssCertificate_GetCertTrust(rvCert, session); -#ifdef NSS_3_4_CODE - /* nss 3.4 database doesn't associate email address with cert */ - if (!rvCert->email) { - nssDecodedCert *dc; - NSSASCII7 *email; - dc = nssCertificate_GetDecoding(rvCert); - email = dc->getEmailAddress(dc); - if (email) rvCert->email = nssUTF8_Duplicate(email, rvCert->arena); - } - make_nss3_nickname(rvCert); -#endif - return rvCert; -loser: - NSSCertificate_Destroy(rvCert); - return (NSSCertificate *)NULL; -} - -static CK_OBJECT_HANDLE -create_cert_trust_object -( - NSSCertificate *c, - NSSTrust *trust -) -{ - CK_ULONG tobj_size; - CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; - CK_ATTRIBUTE tobj_template[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_TOKEN, NULL, 0 }, - { CKA_ISSUER, NULL, 0 }, - { CKA_SERIAL_NUMBER, NULL, 0 }, - { CKA_CERT_SHA1_HASH, NULL, 0 }, - { CKA_CERT_MD5_HASH, NULL, 0 }, - { CKA_TRUST_SERVER_AUTH, NULL, 0 }, - { CKA_TRUST_CLIENT_AUTH, NULL, 0 }, - { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 }, - { CKA_TRUST_CODE_SIGNING, NULL, 0 } - }; - unsigned char sha1_hash[SHA1_LENGTH]; - unsigned char md5_hash[MD5_LENGTH]; - tobj_size = sizeof(tobj_template) / sizeof(tobj_template[0]); - NSS_CK_SET_ATTRIBUTE_VAR( tobj_template, 0, tobjc); - NSS_CK_SET_ATTRIBUTE_ITEM(tobj_template, 1, &g_ck_true); - NSS_CK_SET_ATTRIBUTE_ITEM(tobj_template, 2, &c->issuer); - NSS_CK_SET_ATTRIBUTE_ITEM(tobj_template, 3, &c->serial); - /* 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[4].pValue = (CK_VOID_PTR)sha1_hash; - tobj_template[4].ulValueLen = (CK_ULONG)SHA1_LENGTH; - PK11_HashBuf(SEC_OID_MD5, md5_hash, c->encoding.data, c->encoding.size); - tobj_template[5].pValue = (CK_VOID_PTR)md5_hash; - tobj_template[5].ulValueLen = (CK_ULONG)MD5_LENGTH; - /* now set the trust values */ - NSS_CK_SET_ATTRIBUTE_VAR(tobj_template, 6, trust->serverAuth); - NSS_CK_SET_ATTRIBUTE_VAR(tobj_template, 7, trust->clientAuth); - NSS_CK_SET_ATTRIBUTE_VAR(tobj_template, 8, trust->emailProtection); - NSS_CK_SET_ATTRIBUTE_VAR(tobj_template, 9, trust->codeSigning); - return nssToken_ImportObject(c->token, NULL, tobj_template, tobj_size); -} - -NSS_IMPLEMENT PRStatus -nssCertificate_SetCertTrust -( - NSSCertificate *c, - NSSTrust *trust -) -{ - PRStatus nssrv; - nssSession *session; - PRBool createdSession; - CK_OBJECT_HANDLE tobjID; - CK_ULONG trust_size; - CK_ATTRIBUTE trust_template[] = { - { CKA_TRUST_SERVER_AUTH, NULL, 0 }, - { CKA_TRUST_CLIENT_AUTH, NULL, 0 }, - { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 }, - { CKA_TRUST_CODE_SIGNING, NULL, 0 } - }; - trust_size = sizeof(trust_template) / sizeof(trust_template[0]); - if (!c->token) { - /* must live on a token already */ - return PR_FAILURE; - } - session = c->token->defaultSession; - tobjID = get_cert_trust_handle(c, session); - if (tobjID == CK_INVALID_HANDLE) { - /* trust object doesn't exist yet, create one */ - tobjID = create_cert_trust_object(c, trust); - if (tobjID == CK_INVALID_HANDLE) { - return PR_FAILURE; - } - c->trust.serverAuth = trust->serverAuth; - c->trust.clientAuth = trust->clientAuth; - c->trust.emailProtection = trust->emailProtection; - c->trust.codeSigning = trust->codeSigning; - return PR_SUCCESS; - } - NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 0, trust->serverAuth); - NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 1, trust->clientAuth); - NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 2, trust->emailProtection); - NSS_CK_SET_ATTRIBUTE_VAR(trust_template, 3, trust->codeSigning); - /* changing cert trust requires rw session XXX session objects */ - createdSession = PR_FALSE; - if (!nssSession_IsReadWrite(session)) { - createdSession = PR_TRUE; - session = nssSlot_CreateSession(c->slot, NULL, PR_TRUE); - } - nssrv = nssCKObject_SetAttributes(tobjID, - trust_template, trust_size, - session, c->slot); - if (createdSession) { - nssSession_Destroy(session); - } - if (nssrv == PR_FAILURE) { - return nssrv; - } - c->trust.serverAuth = trust->serverAuth; - c->trust.clientAuth = trust->clientAuth; - c->trust.emailProtection = trust->emailProtection; - c->trust.codeSigning = trust->codeSigning; - return PR_SUCCESS; -} - NSS_IMPLEMENT PRStatus NSSCertificate_Destroy ( NSSCertificate *c ) { +#ifdef NSS_3_4_CODE + return NSSArena_Destroy(c->object.arena); +#else if (--c->refCount == 0) { return NSSArena_Destroy(c->arena); } +#endif return PR_SUCCESS; } @@ -461,13 +101,24 @@ NSSCertificate_DeleteStoredObject NSSCallback *uhh ) { - /* 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. + /* this needs more thought on what will happen when there are multiple + * instances */ /* XXX use callback to log in if neccessary */ - return nssToken_DeleteStoredObject(c->token, NULL, c->handle); + PRStatus nssrv = PR_SUCCESS; + nssPKIObjectInstance *instance; + nssListIterator *instances = c->object.instances; + for (instance = (nssPKIObjectInstance *)nssListIterator_Start(instances); + instance != (nssPKIObjectInstance *)NULL; + instance = (nssPKIObjectInstance *)nssListIterator_Next(instances)) + { + nssrv = nssToken_DeleteStoredObject(&instance->cryptoki); + if (nssrv != PR_SUCCESS) { + break; + } + } + nssListIterator_Finish(instances); + return nssrv; } NSS_IMPLEMENT PRStatus @@ -538,10 +189,6 @@ nssCertificate_GetDecoding if (!c->decoding) { c->decoding = nssDecodedCert_Create(NULL, &c->encoding, c->type); } -#ifdef NSS_3_4_CODE - /* cause the trust bits to get updated in the encoded cert */ - (void) STAN_GetCERTCertificate(c); -#endif return c->decoding; } @@ -550,8 +197,10 @@ find_issuer_cert_for_identifier(NSSCertificate *c, NSSItem *id) { NSSCertificate *rvCert = NULL; NSSCertificate **subjectCerts; + NSSTrustDomain *td; + td = NSSCertificate_GetTrustDomain(c); /* Find all certs with this cert's issuer as the subject */ - subjectCerts = NSSTrustDomain_FindCertificatesBySubject(c->trustDomain, + subjectCerts = NSSTrustDomain_FindCertificatesBySubject(td, &c->issuer, NULL, 0, @@ -599,7 +248,17 @@ NSSCertificate_BuildChain nssList *chain; NSSItem *issuerID; NSSCertificate **rvChain; + NSSTrustDomain *td; nssDecodedCert *dc; + td = NSSCertificate_GetTrustDomain(c); +#ifdef NSS_3_4_CODE + /* This goes down as a 3.4 hack. This function will need to be able to + * search both crypto contexts and trust domains for the chain. + */ + if (!td) { + td = STAN_GetDefaultTrustDomain(); + } +#endif chain = nssList_Create(NULL, PR_FALSE); nssList_Add(chain, c); if (statusOpt) *statusOpt = PR_SUCCESS; @@ -620,7 +279,7 @@ NSSCertificate_BuildChain PRBool tmpca = usage->nss3lookingForCA; usage->nss3lookingForCA = PR_TRUE; #endif - c = NSSTrustDomain_FindBestCertificateBySubject(c->trustDomain, + c = NSSTrustDomain_FindBestCertificateBySubject(td, &c->issuer, timeOpt, usage, @@ -641,8 +300,8 @@ finish: if (rvOpt) { rvChain = rvOpt; } else { - rvChain = nss_ZNEWARRAY(arenaOpt, - NSSCertificate *, nssList_Count(chain) + 1); + rvLimit = nssList_Count(chain); + rvChain = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvLimit + 1); } nssList_GetArray(chain, (void **)rvChain, rvLimit); nssList_Destroy(chain); @@ -656,12 +315,15 @@ NSSCertificate_GetTrustDomain NSSCertificate *c ) { -#if 0 - if (c->trustDomain) { - return nssTrustDomain_AddRef(c->trustDomain); + PRStatus nssrv = PR_SUCCESS; + nssPKIObjectInstance *instance; + nssList *instances = c->object.instanceList; + nssrv = nssList_GetArray(instances, (void **)&instance, 1); + if (nssrv == PR_SUCCESS) { + return instance->trustDomain; + } else { + return (NSSTrustDomain *)NULL; } -#endif - return (NSSTrustDomain *)NULL; } NSS_IMPLEMENT NSSToken * @@ -671,9 +333,6 @@ NSSCertificate_GetToken PRStatus *statusOpt ) { - if (c->token) { - return nssToken_AddRef(c->token); - } return (NSSToken *)NULL; } @@ -684,11 +343,6 @@ NSSCertificate_GetSlot PRStatus *statusOpt ) { -#if 0 - if (c->token) { - return nssToken_GetSlot(c->token); - } -#endif return (NSSSlot *)NULL; } @@ -699,11 +353,6 @@ NSSCertificate_GetModule PRStatus *statusOpt ) { -#if 0 - if (c->token) { - return nssToken_GetModule(c->token); - } -#endif return (NSSModule *)NULL; } @@ -799,15 +448,14 @@ NSSCertificate_GetPublicKey NSSCertificate *c ) { +#if 0 CK_ATTRIBUTE pubktemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_ID, NULL, 0 }, { CKA_SUBJECT, NULL, 0 } }; -#if 0 PRStatus nssrv; CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]); -#endif NSS_CK_SET_ATTRIBUTE_ITEM(pubktemplate, 0, &g_ck_class_pubkey); if (c->id.size > 0) { /* CKA_ID */ @@ -824,7 +472,6 @@ NSSCertificate_GetPublicKey return (NSSPublicKey *)NULL; } /* Try the cert's token first */ -#if 0 if (c->token) { nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count); } diff --git a/security/nss/lib/pki/cryptocontext.c b/security/nss/lib/pki/cryptocontext.c index 20045b4287e..b735fa965b5 100644 --- a/security/nss/lib/pki/cryptocontext.c +++ b/security/nss/lib/pki/cryptocontext.c @@ -32,13 +32,26 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: cryptocontext.c,v $ $Revision: 1.4 $ $Date: 2001-10-11 18:41:50 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: cryptocontext.c,v $ $Revision: 1.5 $ $Date: 2001-11-28 16:23:43 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSPKI_H #include "nsspki.h" #endif /* NSSPKI_H */ +#ifndef PKIT_H +#include "pkit.h" +#endif /* PKIT_H */ + +#ifndef DEV_H +#include "dev.h" +#endif /* DEV_H */ + +#ifdef NSS_3_4_CODE +#include "pk11func.h" +#include "dev3hack.h" +#endif + extern const NSSError NSS_ERROR_NOT_FOUND; NSS_IMPLEMENT PRStatus @@ -91,8 +104,28 @@ NSSCryptoContext_ImportCertificate NSSCertificate *c ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return PR_FAILURE; + NSSToken *token; + nssSession *session = NULL; +#ifdef NSS_3_4_CODE + /* XXX hack alert - what this needs to do is find the preferred + * token for cert storage + */ + if (PR_TRUE) { + PK11SlotInfo *slot = PK11_GetInternalSlot(); + token = PK11Slot_GetNSSToken(slot); + } +#endif + /* + * question - are there multiple available tokens for the crypto context? + * in that case, it needs to store a session for each one + */ +#ifdef nodef + session = get_token_session(cc, tok); + if (!session) { + return PR_FAILURE; + } +#endif + return nssToken_ImportCertificate(token, session, c, NULL, cc); } NSS_IMPLEMENT NSSCertificate * @@ -428,10 +461,10 @@ struct token_session_str { nssSession *session; }; +#ifdef nodef 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; @@ -450,8 +483,8 @@ get_token_session(NSSCryptoContext *cc, NSSToken *tok) nssList_AddElement(cc->sessionList, (void *)ts); } return ts->session; -#endif } +#endif NSS_IMPLEMENT NSSItem * NSSCryptoContext_Decrypt @@ -516,6 +549,7 @@ NSSCryptoContext_Decrypt } return rvData; #endif + return NULL; } NSS_IMPLEMENT PRStatus @@ -864,8 +898,8 @@ NSSCryptoContext_Digest NSSArena *arenaOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + return nssToken_Digest(cc->token, cc->session, apOpt, + data, rvOpt, arenaOpt); } NSS_IMPLEMENT PRStatus @@ -876,8 +910,7 @@ NSSCryptoContext_BeginDigest NSSCallback *uhhOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return PR_FAILURE; + return nssToken_BeginDigest(cc->token, cc->session, apOpt); } NSS_IMPLEMENT PRStatus @@ -888,8 +921,12 @@ NSSCryptoContext_ContinueDigest NSSItem *item ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return PR_FAILURE; + /* + NSSAlgorithmAndParameters *ap; + ap = (apOpt) ? apOpt : cc->ap; + */ + /* why apOpt? can't change it at this point... */ + return nssToken_ContinueDigest(cc->token, cc->session, item); } NSS_IMPLEMENT NSSItem * @@ -900,8 +937,7 @@ NSSCryptoContext_FinishDigest NSSArena *arenaOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + return nssToken_FinishDigest(cc->token, cc->session, rvOpt, arenaOpt); } NSS_IMPLEMENT NSSCryptoContext * diff --git a/security/nss/lib/pki/pki.h b/security/nss/lib/pki/pki.h index a0da203c8bc..0c11b1d4c07 100644 --- a/security/nss/lib/pki/pki.h +++ b/security/nss/lib/pki/pki.h @@ -35,7 +35,7 @@ #define PKI_H #ifdef DEBUG -static const char PKI_CVS_ID[] = "@(#) $RCSfile: pki.h,v $ $Revision: 1.6 $ $Date: 2001-10-17 14:40:22 $ $Name: $"; +static const char PKI_CVS_ID[] = "@(#) $RCSfile: pki.h,v $ $Revision: 1.7 $ $Date: 2001-11-28 16:23:43 $ $Name: $"; #endif /* DEBUG */ #ifndef PKIT_H @@ -54,27 +54,6 @@ nssCertificate_AddRef NSSCertificate *c ); -NSS_EXTERN NSSCertificate * -nssCertificate_CreateFromHandle -( - NSSArena *arenaOpt, - CK_OBJECT_HANDLE object, - nssSession *session, - NSSSlot *slot -); - -NSS_EXTERN NSSUTF8 * -NSSCertificate_GetLabel -( - NSSCertificate *c -); - -NSS_EXTERN NSSItem * -NSSCertificate_GetID -( - NSSCertificate *c -); - PR_END_EXTERN_C #endif /* PKI_H */ diff --git a/security/nss/lib/pki/pki3hack.c b/security/nss/lib/pki/pki3hack.c index 43fdc2b5d31..1eab50aa455 100644 --- a/security/nss/lib/pki/pki3hack.c +++ b/security/nss/lib/pki/pki3hack.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.4 $ $Date: 2001-11-08 20:46:08 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.5 $ $Date: 2001-11-28 16:23:43 $ $Name: $"; #endif /* DEBUG */ /* @@ -51,10 +51,6 @@ static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.4 $ $Da #include "dev.h" #endif /* DEV_H */ -#ifndef CKHELPER_H -#include "ckhelper.h" -#endif /* CKHELPER_H */ - #ifndef DEVNSS3HACK_H #include "dev3hack.h" #endif /* DEVNSS3HACK_H */ @@ -71,12 +67,20 @@ static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.4 $ $Da NSSTrustDomain *g_default_trust_domain = NULL; +NSSCryptoContext *g_default_crypto_context = NULL; + NSSTrustDomain * STAN_GetDefaultTrustDomain() { return g_default_trust_domain; } +NSSCryptoContext * +STAN_GetDefaultCryptoContext() +{ + return g_default_crypto_context; +} + NSS_IMPLEMENT void STAN_LoadDefaultNSS3TrustDomain ( @@ -103,6 +107,7 @@ STAN_LoadDefaultNSS3TrustDomain } td->tokens = nssList_CreateIterator(td->tokenList); g_default_trust_domain = td; + g_default_crypto_context = NSSTrustDomain_CreateCryptoContext(td, NULL); } NSS_IMPLEMENT PRStatus @@ -136,7 +141,7 @@ STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der) return NULL; } secrv = CERT_KeyFromDERCert(arena, &secDER, &secKey); - if (!secrv) { + if (secrv != SECSuccess) { return NULL; } rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data); @@ -299,6 +304,28 @@ nssDecodedPKIXCertificate_Create return rvDC; } +static nssDecodedCert * +create_decoded_pkix_cert_from_nss3cert +( + NSSArena *arenaOpt, + CERTCertificate *cc +) +{ + nssDecodedCert *rvDC; + rvDC = nss_ZNEW(arenaOpt, nssDecodedCert); + rvDC->type = NSSCertificateType_PKIX; + rvDC->data = (void *)cc; + rvDC->getIdentifier = nss3certificate_getIdentifier; + rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; + rvDC->matchIdentifier = nss3certificate_matchIdentifier; + rvDC->getUsage = nss3certificate_getUsage; + rvDC->isValidAtTime = nss3certificate_isValidAtTime; + rvDC->isNewerThan = nss3certificate_isNewerThan; + rvDC->matchUsage = nss3certificate_matchUsage; + rvDC->getEmailAddress = nss3certificate_getEmailAddress; + return rvDC; +} + NSS_IMPLEMENT PRStatus nssDecodedPKIXCertificate_Destroy ( @@ -336,10 +363,15 @@ get_nss3trust_from_cktrust(CK_TRUST t) } static CERTCertTrust * -nssTrust_GetCERTCertTrust(NSSTrust *t, CERTCertificate *cc) +nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, NSSToken *token, + CERTCertificate *cc) { CERTCertTrust *rvTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust)); unsigned int client; + NSSTrust *t = nssToken_FindTrustForCert(token, NULL, c); + if (!t) { + return NULL; + } rvTrust->sslFlags = get_nss3trust_from_cktrust(t->serverAuth); client = get_nss3trust_from_cktrust(t->clientAuth); if (client & (CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA)) { @@ -357,26 +389,39 @@ nssTrust_GetCERTCertTrust(NSSTrust *t, CERTCertificate *cc) return rvTrust; } +static nssPKIObjectInstance * +get_cert_instance(NSSCertificate *c) +{ + nssPKIObjectInstance *instance; + instance = NULL; + nssList_GetArray(c->object.instanceList, (void **)&instance, 1); + return instance; +} + static void fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc) { + nssPKIObjectInstance *instance = get_cert_instance(c); /* fill other fields needed by NSS3 functions using CERTCertificate */ - /* handle */ - cc->pkcs11ID = c->handle; - /* nickname */ - cc->nickname = PL_strdup(c->nickname); - /* slot (ownSlot ?) (addref ?) */ - if (c->token) { - cc->slot = c->token->pk11slot; + if (!cc->nickname && c->nickname) { + PRStatus nssrv; + int len = nssUTF8_Size(c->nickname, &nssrv); + cc->nickname = PORT_ArenaAlloc(cc->arena, len); + memcpy(cc->nickname, c->nickname, len-1); + cc->nickname[len-1] = '\0'; } - /* trust */ - cc->trust = nssTrust_GetCERTCertTrust(&c->trust, cc); - cc->referenceCount++; + if (instance) { + nssCryptokiInstance *cryptoki = &instance->cryptoki; + /* slot (ownSlot ?) (addref ?) */ + cc->slot = cryptoki->token->pk11slot; + /* pkcs11ID */ + cc->pkcs11ID = cryptoki->handle; + /* trust */ + cc->trust = nssTrust_GetCERTCertTrustForCert(c, cryptoki->token, cc); + /* database handle is now the trust domain */ + cc->dbhandle = instance->trustDomain; + } /* subjectList ? */ - /* pkcs11ID */ - cc->pkcs11ID = c->handle; - /* database handle is now the trust domain */ - cc->dbhandle = c->trustDomain; /* pointer back */ cc->nssCertificate = c; } @@ -396,6 +441,11 @@ STAN_GetCERTCertificate(NSSCertificate *c) cc = (CERTCertificate *)dc->data; if (!cc->nssCertificate) { fill_CERTCertificateFields(c, cc); + } else if (!cc->trust) { + nssPKIObjectInstance *instance = get_cert_instance(c); + cc->trust = nssTrust_GetCERTCertTrustForCert(c, + instance->cryptoki.token, + cc); } return cc; } @@ -428,13 +478,13 @@ NSS_EXTERN NSSCertificate * STAN_GetNSSCertificate(CERTCertificate *cc) { NSSCertificate *c; + nssPKIObject *object; + nssPKIObjectInstance *instance; NSSArena *arena; - c = cc->nssCertificate; if (c) { return c; } - /* i don't think this should happen. but if it can, need to create * NSSCertificate from CERTCertificate values here. */ /* Yup, it can happen. */ @@ -442,24 +492,35 @@ STAN_GetNSSCertificate(CERTCertificate *cc) if (!arena) { return NULL; } - c = NSSCertificate_Create(arena); + c = nss_ZNEW(arena, NSSCertificate); if (!c) { goto loser; } + object = &c->object; NSSITEM_FROM_SECITEM(&c->encoding, &cc->derCert); c->type = NSSCertificateType_PKIX; - c->arena = arena; + object->arena = arena; + object->refCount = 1; + object->instanceList = nssList_Create(arena, PR_TRUE); + object->instances = nssList_CreateIterator(object->instanceList); nssItem_Create(arena, &c->issuer, cc->derIssuer.len, cc->derIssuer.data); nssItem_Create(arena, &c->subject, cc->derSubject.len, cc->derSubject.data); - nssItem_Create(arena, - &c->serial, cc->serialNumber.len, cc->serialNumber.data); + if (PR_TRUE) { + /* CERTCertificate stores serial numbers decoded. I need the DER + * here. sigh. + */ + SECItem derSerial; + CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); + nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data); + PORT_Free(derSerial.data); + } if (cc->nickname) { c->nickname = nssUTF8_Create(arena, - nssStringType_UTF8String, - (NSSUTF8 *)cc->nickname, - PORT_Strlen(cc->nickname)); + nssStringType_UTF8String, + (NSSUTF8 *)cc->nickname, + PORT_Strlen(cc->nickname)); } if (cc->emailAddr) { c->email = nssUTF8_Create(arena, @@ -467,19 +528,15 @@ STAN_GetNSSCertificate(CERTCertificate *cc) (NSSUTF8 *)cc->emailAddr, PORT_Strlen(cc->emailAddr)); } - c->trustDomain = (NSSTrustDomain *)cc->dbhandle; + instance = nss_ZNEW(arena, nssPKIObjectInstance); + instance->trustDomain = (NSSTrustDomain *)cc->dbhandle; if (cc->slot) { - c->token = PK11Slot_GetNSSToken(cc->slot); - c->slot = c->token->slot; + instance->cryptoki.token = PK11Slot_GetNSSToken(cc->slot); + instance->cryptoki.handle = cc->pkcs11ID; } + nssList_Add(object->instanceList, instance); + c->decoding = create_decoded_pkix_cert_from_nss3cert(arena, cc); cc->nssCertificate = c; - if (cc->trust) { - CERTCertTrust *trust = cc->trust; - c->trust.serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE); - c->trust.clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE); - c->trust.emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE); - c->trust.codeSigning= get_stan_trust(trust->objectSigningFlags, PR_FALSE); - } return c; loser: nssArena_Destroy(arena); @@ -487,47 +544,31 @@ loser: } NSS_EXTERN PRStatus -STAN_ChangeCertTrust(NSSCertificate *c, CERTCertTrust *trust) +STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust) { - CERTCertificate *cc = STAN_GetCERTCertificate(c); + PRStatus nssrv; + NSSCertificate *c = STAN_GetNSSCertificate(cc); + nssPKIObjectInstance *instance; NSSTrust nssTrust; /* Set the CERTCertificate's trust */ cc->trust = trust; /* Set the NSSCerticate's trust */ + nssTrust.certificate = c; + nssTrust.object.arena = nssArena_Create(); + nssTrust.object.instanceList = nssList_Create(nssTrust.object.arena, + PR_FALSE); + nssTrust.object.instances = nssList_CreateIterator( + nssTrust.object.instanceList); nssTrust.serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE); nssTrust.clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE); nssTrust.emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE); - nssTrust.codeSigning= get_stan_trust(trust->objectSigningFlags, PR_FALSE); - return nssCertificate_SetCertTrust(c, &nssTrust); -} - -/* This is here to replace CERT_Traverse calls */ -static PRStatus -traverse_certificates_by_template -( - NSSTrustDomain *td, - nssList *cachedList, - CK_ATTRIBUTE_PTR cktemplate, - CK_ULONG ctsize, - PRStatus (*callback)(NSSCertificate *c, void *arg), - void *arg -) -{ - PRStatus nssrv; - NSSToken *tok; - for (tok = (NSSToken *)nssListIterator_Start(td->tokens); - tok != (NSSToken *)NULL; - tok = (NSSToken *)nssListIterator_Next(td->tokens)) - { - nssrv = nssToken_TraverseCertificatesByTemplate(tok, NULL, cachedList, - cktemplate, ctsize, - callback, arg); - if (nssrv == PR_FAILURE) { - return PR_FAILURE; - } - } - nssListIterator_Finish(td->tokens); - return PR_SUCCESS; + nssTrust.codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE); + instance = get_cert_instance(c); + /* maybe GetDefaultTrustToken()? */ + nssrv = nssToken_ImportTrust(instance->cryptoki.token, NULL, &nssTrust, + instance->trustDomain, instance->cryptoContext); + nssArena_Destroy(nssTrust.object.arena); + return nssrv; } /* CERT_TraversePermCertsForSubject */ @@ -541,22 +582,20 @@ nssTrustDomain_TraverseCertificatesBySubject ) { PRStatus nssrv; - nssList *subjectList; - CK_ATTRIBUTE subj_template[] = - { - { CKA_CLASS, NULL, 0 }, - { CKA_SUBJECT, NULL, 0 } - }; - CK_ULONG ctsize; - ctsize = (CK_ULONG)(sizeof(subj_template) / sizeof(subj_template[0])); - NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 0, &g_ck_class_cert); - NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 1, subject); - subjectList = nssList_Create(NULL, PR_FALSE); - (void)nssTrustDomain_GetCertsForSubjectFromCache(td, subject, subjectList); - nssrv = traverse_certificates_by_template(td, subjectList, - subj_template, ctsize, - callback, arg); - nssList_Destroy(subjectList); + NSSArena *tmpArena; + NSSCertificate **subjectCerts; + NSSCertificate *c; + PRIntn i; + tmpArena = NSSArena_Create(); + subjectCerts = NSSTrustDomain_FindCertificatesBySubject(td, subject, NULL, + 0, tmpArena); + if (subjectCerts) { + for (i=0, c = subjectCerts[i]; c; i++) { + nssrv = callback(c, arg); + if (nssrv != PR_SUCCESS) break; + } + } + nssArena_Destroy(tmpArena); return nssrv; } @@ -571,23 +610,20 @@ nssTrustDomain_TraverseCertificatesByNickname ) { PRStatus nssrv; - nssList *nickCerts; - CK_ATTRIBUTE nick_template[] = - { - { CKA_CLASS, NULL, 0 }, - { CKA_LABEL, NULL, 0 } - }; - 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)nickname; - nick_template[1].ulValueLen = (CK_ULONG)nssUTF8_Length(nickname, &nssrv); - nickCerts = nssList_Create(NULL, PR_FALSE); - (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nickname, nickCerts); - nssrv = traverse_certificates_by_template(td, nickCerts, - nick_template, ctsize, - callback, arg); - nssList_Destroy(nickCerts); + NSSArena *tmpArena; + NSSCertificate **nickCerts; + NSSCertificate *c; + PRIntn i; + tmpArena = NSSArena_Create(); + nickCerts = NSSTrustDomain_FindCertificatesByNickname(td, nickname, NULL, + 0, tmpArena); + if (nickCerts) { + for (i=0, c = nickCerts[i]; c; i++) { + nssrv = callback(c, arg); + if (nssrv != PR_SUCCESS) break; + } + } + nssArena_Destroy(tmpArena); return nssrv; } @@ -601,23 +637,33 @@ nssTrustDomain_TraverseCertificates ) { PRStatus nssrv; + NSSToken *token; nssList *certList; - CK_ATTRIBUTE cert_template[] = - { - { CKA_CLASS, NULL, 0 }, - }; - CK_ULONG ctsize; - ctsize = (CK_ULONG)(sizeof(cert_template) / sizeof(cert_template[0])); - NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); + nssTokenCertSearch search; + /* grab all cache certs (XXX please only do this here...) + * the alternative is to provide a callback through search that allows + * the token to query the cache for the cert during traversal. + */ certList = nssList_Create(NULL, PR_FALSE); (void)nssTrustDomain_GetCertsFromCache(td, certList); - nssrv = traverse_certificates_by_template(td, certList, - cert_template, ctsize, - callback, arg); + /* set the search criteria */ + search.callback = callback; + search.cbarg = arg; + search.cached = certList; + search.trustDomain = td; + search.cryptoContext = NULL; + for (token = (NSSToken *)nssListIterator_Start(td->tokens); + token != (NSSToken *)NULL; + token = (NSSToken *)nssListIterator_Next(td->tokens)) + { + nssrv = nssToken_TraverseCertificates(token, NULL, &search); + } + nssListIterator_Finish(td->tokens); nssList_Destroy(certList); return nssrv; } +#if 0 static CK_CERTIFICATE_TYPE get_cert_type(NSSCertificateType nssType) { @@ -629,6 +675,7 @@ get_cert_type(NSSCertificateType nssType) * type CK_CERTIFICATE_TYPE */ } } +#endif NSS_IMPLEMENT NSSToken * STAN_GetInternalToken(void) @@ -643,6 +690,7 @@ nssTrustDomain_AddTempCertToPerm NSSCertificate *c ) { +#if 0 NSSToken *token; CK_CERTIFICATE_TYPE cert_type; CK_ATTRIBUTE cert_template[] = @@ -679,4 +727,6 @@ nssTrustDomain_AddTempCertToPerm c->slot = token->slot; /* Do the trust object */ return PR_SUCCESS; +#endif + return PR_FAILURE; } diff --git a/security/nss/lib/pki/pki3hack.h b/security/nss/lib/pki/pki3hack.h index c8ca1a452f5..d3c018a26cb 100644 --- a/security/nss/lib/pki/pki3hack.h +++ b/security/nss/lib/pki/pki3hack.h @@ -35,7 +35,7 @@ #define PKINSS3HACK_H #ifdef DEBUG -static const char PKINSS3HACK_CVS_ID[] = "@(#) $RCSfile: pki3hack.h,v $ $Revision: 1.1 $ $Date: 2001-11-08 00:15:20 $ $Name: $"; +static const char PKINSS3HACK_CVS_ID[] = "@(#) $RCSfile: pki3hack.h,v $ $Revision: 1.2 $ $Date: 2001-11-28 16:23:43 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSPKIT_H @@ -57,6 +57,9 @@ PR_BEGIN_EXTERN_C NSS_EXTERN NSSTrustDomain * STAN_GetDefaultTrustDomain(); +NSSCryptoContext * +STAN_GetDefaultCryptoContext(); + NSS_IMPLEMENT void STAN_LoadDefaultNSS3TrustDomain ( @@ -76,7 +79,7 @@ NSS_EXTERN NSSCertificate * STAN_GetNSSCertificate(CERTCertificate *c); NSS_EXTERN PRStatus -STAN_ChangeCertTrust(NSSCertificate *c, CERTCertTrust *trust); +STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust); /* exposing this */ NSS_EXTERN NSSCertificate * diff --git a/security/nss/lib/pki/pkim.h b/security/nss/lib/pki/pkim.h index d187ea30929..d2d8b1d29a3 100644 --- a/security/nss/lib/pki/pkim.h +++ b/security/nss/lib/pki/pkim.h @@ -35,7 +35,7 @@ #define PKIM_H #ifdef DEBUG -static const char PKIM_CVS_ID[] = "@(#) $RCSfile: pkim.h,v $ $Revision: 1.6 $ $Date: 2001-10-19 20:06:28 $ $Name: $"; +static const char PKIM_CVS_ID[] = "@(#) $RCSfile: pkim.h,v $ $Revision: 1.7 $ $Date: 2001-11-28 16:23:43 $ $Name: $"; #endif /* DEBUG */ #ifndef BASE_H @@ -129,13 +129,20 @@ nssTrustDomain_AddCertsToCache PRUint32 numCerts ); -NSS_EXTERN PRStatus +NSS_EXTERN void nssTrustDomain_RemoveCertFromCache ( NSSTrustDomain *td, NSSCertificate *cert ); +NSS_EXTERN void +nssTrustDomain_FlushCache +( + NSSTrustDomain *td, + PRFloat64 threshold +); + /* * Remove all certs for the given token from the cache. This is * needed if the token is removed. diff --git a/security/nss/lib/pki/pkit.h b/security/nss/lib/pki/pkit.h index f85325ad8b0..b5236a2ebc0 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.6 $ $Date: 2001-11-05 17:29:27 $ $Name: $"; +static const char PKIT_CVS_ID[] = "@(#) $RCSfile: pkit.h,v $ $Revision: 1.7 $ $Date: 2001-11-28 16:23:44 $ $Name: $"; #endif /* DEBUG */ /* @@ -55,12 +55,6 @@ static const char PKIT_CVS_ID[] = "@(#) $RCSfile: pkit.h,v $ $Revision: 1.6 $ $D #ifdef NSS_3_4_CODE #include "certt.h" #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 @@ -71,27 +65,46 @@ static const char PKIT_CVS_ID[] = "@(#) $RCSfile: pkit.h,v $ $Revision: 1.6 $ $D #include "nssdevt.h" #endif /* NSSDEVT_H */ -PR_BEGIN_EXTERN_C +#ifndef DEVT_H +#include "devt.h" +#endif /* DEVT_H */ -typedef enum { - NSSCertificateType_Unknown = 0, - NSSCertificateType_PKIX = 1 -} NSSCertificateType; +PR_BEGIN_EXTERN_C typedef struct nssDecodedCertStr nssDecodedCert; +typedef struct nssPKIObjectInstanceStr nssPKIObjectInstance; + +typedef struct nssPKIObjectStr nssPKIObject; + +struct nssPKIObjectInstanceStr +{ + nssCryptokiInstance cryptoki; + NSSTrustDomain *trustDomain; + NSSCryptoContext *cryptoContext; +}; + +struct nssPKIObjectStr +{ + PRInt32 refCount; + NSSArena *arena; + nssList *instanceList; /* list of nssPKIObjectInstance */ + nssListIterator *instances; +}; + struct NSSTrustStr { - CK_TRUST serverAuth; - CK_TRUST clientAuth; - CK_TRUST emailProtection; - CK_TRUST codeSigning; + struct nssPKIObjectStr object; + NSSCertificate *certificate; + nssTrustLevel serverAuth; + nssTrustLevel clientAuth; + nssTrustLevel emailProtection; + nssTrustLevel codeSigning; }; struct NSSCertificateStr { - PRInt32 refCount; - NSSArena *arena; + struct nssPKIObjectStr object; NSSCertificateType type; NSSItem id; NSSBER encoding; @@ -100,12 +113,6 @@ struct NSSCertificateStr NSSDER serial; NSSUTF8 *nickname; NSSASCII7 *email; - NSSSlot *slot; - NSSToken *token; - NSSTrustDomain *trustDomain; - NSSCryptoContext *cryptoContext; - NSSTrust trust; - CK_OBJECT_HANDLE handle; nssDecodedCert *decoding; }; @@ -134,6 +141,9 @@ struct NSSCryptoContextStr { PRInt32 refCount; NSSArena *arena; + NSSTrustDomain *td; + NSSToken *token; + nssSession *session; }; struct NSSTimeStr; diff --git a/security/nss/lib/pki/tdcache.c b/security/nss/lib/pki/tdcache.c index 6daddee9945..8207fe1d53d 100644 --- a/security/nss/lib/pki/tdcache.c +++ b/security/nss/lib/pki/tdcache.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.9 $ $Date: 2001-11-08 20:46:08 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.10 $ $Date: 2001-11-28 16:23:44 $ $Name: $"; #endif /* DEBUG */ #ifndef PKIM_H @@ -51,6 +51,39 @@ static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.9 $ $Dat #include "base.h" #endif /* BASE_H */ +#ifdef DEBUG +static PRLogModuleInfo *s_log = NULL; +#endif + +#ifdef DEBUG +static void log_item_dump(const char *msg, NSSItem *it) +{ + char buf[33]; + int i, j; + for (i=0; i<10 && isize; i++) { + sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[i]); + } + if (it->size>10) { + sprintf(&buf[2*i], ".."); + i += 1; + for (j=it->size-1; i<=16 && j>10; i++, j--) { + sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[j]); + } + } + PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, buf)); +} +#endif + +#ifdef DEBUG +static void log_cert_ref(const char *msg, NSSCertificate *c) +{ + PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, + (c->nickname) ? c->nickname : c->email)); + log_item_dump("\tserial", &c->serial); + log_item_dump("\tsubject", &c->subject); +} +#endif + /* Certificate cache routines */ /* XXX @@ -59,36 +92,66 @@ static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.9 $ $Dat */ /* should it live in its own arena? */ -struct nssTDCertificateCacheStr { - PZLock *lock; - nssHash *issuerAndSN; - nssHash *subject; - nssHash *nickname; - nssHash *email; +struct nssTDCertificateCacheStr +{ + PZLock *lock; + NSSArena *arena; + nssHash *issuerAndSN; + nssHash *subject; + nssHash *nickname; + nssHash *email; }; -static NSSItem * -get_issuer_and_serial_key(NSSArena *arena, NSSDER *issuer, NSSDER *serial) +struct cache_entry_str { - NSSItem *rvKey; - PRUint8 *buf; - rvKey = nss_ZNEW(arena, NSSItem); - rvKey->data = nss_ZAlloc(arena, issuer->size + serial->size); - rvKey->size = issuer->size + serial->size; - buf = (PRUint8 *)rvKey->data; - nsslibc_memcpy(buf, issuer->data, issuer->size); - nsslibc_memcpy(buf + issuer->size, serial->data, serial->size); - return rvKey; + union { + NSSCertificate *cert; + nssList *list; + void *value; + } entry; + PRUint32 hits; + PRTime lastHit; +}; + +typedef struct cache_entry_str cache_entry; + +static cache_entry * +new_cache_entry(NSSArena *arena, void *value) +{ + cache_entry *ce = nss_ZNEW(arena, cache_entry); + if (ce) { + ce->entry.value = value; + ce->hits = 1; + ce->lastHit = PR_Now(); + } + return ce; } -static PRBool cert_compare(void *v1, void *v2) +static PLHashNumber +nss_certificate_hash +( + const void *key +) { - PRStatus rv; + int i; + PLHashNumber h; + NSSCertificate *c = (NSSCertificate *)key; + h = 0; + for (i=0; iissuer.size; i++) + h = (h >> 28) ^ (h << 4) ^ ((unsigned char *)c->issuer.data)[i]; + for (i=0; iserial.size; i++) + h = (h >> 28) ^ (h << 4) ^ ((unsigned char *)c->serial.data)[i]; + return h; +} + +static int +nss_compare_certs(const void *v1, const void *v2) +{ + PRStatus ignore; 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)); + return (int)(nssItem_Equal(&c1->issuer, &c2->issuer, &ignore) && + nssItem_Equal(&c1->serial, &c2->serial, &ignore)); } /* sort the subject list from newest to oldest */ @@ -115,38 +178,66 @@ nssTrustDomain_InitializeCache PRUint32 cacheSize ) { - if (td->cache) { + NSSArena *arena; + nssTDCertificateCache *cache = td->cache; +#ifdef DEBUG + s_log = PR_NewLogModule("nss_cache"); + PR_ASSERT(s_log); +#endif + PR_ASSERT(!cache); + arena = nssArena_Create(); + if (!arena) { 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); + cache = nss_ZNEW(arena, nssTDCertificateCache); + if (!cache) { + nssArena_Destroy(arena); + return PR_FAILURE; + } + cache->lock = PZ_NewLock(nssILockCache); + if (!cache->lock) { + nssArena_Destroy(arena); + return PR_FAILURE; + } + PZ_Lock(cache->lock); /* Create the issuer and serial DER --> certificate hash */ - td->cache->issuerAndSN = nssHash_CreateItem(td->arena, cacheSize); - if (!td->cache->issuerAndSN) goto loser; + cache->issuerAndSN = nssHash_Create(arena, cacheSize, + nss_certificate_hash, + nss_compare_certs, + PL_CompareValues); + if (!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; + cache->subject = nssHash_CreateItem(arena, cacheSize); + if (!cache->subject) { + goto loser; + } /* Create the nickname --> subject list hash */ - td->cache->nickname = nssHash_CreateString(td->arena, cacheSize); - if (!td->cache->nickname) goto loser; + cache->nickname = nssHash_CreateString(arena, cacheSize); + if (!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); + cache->email = nssHash_CreateString(arena, cacheSize); + if (!cache->email) { + goto loser; + } + cache->arena = arena; + PZ_Unlock(cache->lock); + td->cache = cache; +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialized.")); +#endif 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); + PZ_Unlock(cache->lock); + PZ_DestroyLock(cache->lock); + nssArena_Destroy(arena); td->cache = NULL; +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialization failed.")); +#endif return PR_FAILURE; } @@ -156,142 +247,117 @@ 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); + nssArena_Destroy(td->cache->arena); td->cache = NULL; +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("Cache destroyed.")); +#endif 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); - nssList_SetSortFunction(subjectList, subject_list_sort); - 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 */ - if (cert->nickname) { - nickname = nssUTF8_Duplicate(cert->nickname, td->arena); - nssrv = nssHash_Add(td->cache->nickname, nickname, subjectList); - if (nssrv != PR_SUCCESS) goto loser; - } - /* email */ - 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); - 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 +remove_issuer_and_serial_entry ( - NSSTrustDomain *td, - NSSCertificate **certs, - PRUint32 numCerts + nssTDCertificateCache *cache, + NSSCertificate *cert ) { - PRUint32 i; - for (i=0; iissuerAndSN, cert); +#ifdef DEBUG + log_cert_ref("removed issuer/sn", cert); +#endif return PR_SUCCESS; } -static NSSItem * -get_static_ias(NSSItem *s_ias, NSSDER *issuer, NSSDER *serial) +static PRStatus +remove_subject_entry +( + nssTDCertificateCache *cache, + NSSCertificate *cert, + nssList **subjectList +) { - PRUint8 *buf; - if (issuer->size + serial->size < s_ias->size) { - buf = (PRUint8 *)s_ias->data; - nsslibc_memcpy(buf, issuer->data, issuer->size); - nsslibc_memcpy(buf + 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); + PRStatus nssrv; + cache_entry *ce; + *subjectList = NULL; + /* Get the subject list for the cert's subject */ + ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject); + if (ce) { + /* Remove the cert from the subject hash */ + nssList_Remove(ce->entry.list, cert); + *subjectList = ce->entry.list; + nssrv = PR_SUCCESS; +#ifdef DEBUG + log_cert_ref("removed cert", cert); + log_item_dump("from subject list", &cert->subject); +#endif + } else { + nssrv = PR_FAILURE; + } + return nssrv; } -NSS_IMPLEMENT PRStatus +static PRStatus +remove_nickname_entry +( + nssTDCertificateCache *cache, + NSSCertificate *cert, + nssList *subjectList +) +{ + PRStatus nssrv; + if (cert->nickname) { + nssHash_Remove(cache->nickname, cert->nickname); + nssrv = PR_SUCCESS; +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("removed nickname %s", cert->nickname)); +#endif + } else { + nssrv = PR_FAILURE; + } + return nssrv; +} + +static PRStatus +remove_email_entry +( + nssTDCertificateCache *cache, + NSSCertificate *cert, + nssList *subjectList +) +{ + PRStatus nssrv = PR_FAILURE; + cache_entry *ce; + /* Find the subject list in the email hash */ + if (cert->email) { + ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email); + if (ce) { + nssList *subjects = ce->entry.list; + /* Remove the subject list from the email hash */ + nssList_Remove(subjects, subjectList); +#ifdef DEBUG + log_item_dump("removed subject list", &cert->subject); + PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email)); +#endif + if (nssList_Count(subjects) == 0) { + /* No more subject lists for email, delete list and + * remove hash entry + */ + (void)nssList_Destroy(subjects); + nssHash_Remove(cache->email, cert->email); +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email)); +#endif + } + nssrv = PR_SUCCESS; + } + } + return nssrv; +} + +NSS_IMPLEMENT void nssTrustDomain_RemoveCertFromCache ( NSSTrustDomain *td, @@ -299,58 +365,61 @@ nssTrustDomain_RemoveCertFromCache ) { nssList *subjectList; - nssList *subjects; - NSSItem *ias; - unsigned char buf[128]; - NSSItem s_ias; - s_ias.data = (void *)buf; - s_ias.size = 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); + PRStatus nssrv; +#ifdef DEBUG + log_cert_ref("attempt to remove cert", cert); #endif - if (s_ias.size == 0) { - nss_ZFreeIf(ias); - } + PZ_Lock(td->cache->lock); + if (!nssHash_Exists(td->cache->issuerAndSN, cert)) { PZ_Unlock(td->cache->lock); - return PR_FAILURE; +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("but it wasn't in the cache")); +#endif + return; } - /* 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); + nssrv = remove_issuer_and_serial_entry(td->cache, cert); + if (nssrv != PR_SUCCESS) { + goto loser; + } + nssrv = remove_subject_entry(td->cache, cert, &subjectList); + if (nssrv != PR_SUCCESS) { + goto loser; + } + if (nssList_Count(subjectList) == 0) { + PRStatus nssrv2; + nssrv = remove_nickname_entry(td->cache, cert, subjectList); + nssrv2 = remove_email_entry(td->cache, cert, subjectList); +#ifndef NSS_3_4_CODE + /* XXX Again, 3.4 allows for certs w/o either nickname or email */ + if (nssrv != PR_SUCCESS && nssrv2 != PR_SUCCESS) { + goto loser; } - } - if (s_ias.size == 0) { - nss_ZFreeIf(ias); +#endif + (void)nssList_Destroy(subjectList); + nssHash_Remove(td->cache->subject, &cert->subject); } PZ_Unlock(td->cache->lock); - return PR_SUCCESS; + return; +loser: + /* if here, then the cache is inconsistent. For now, flush it. */ + PZ_Unlock(td->cache->lock); +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("remove cert failed, flushing")); +#endif + nssTrustDomain_FlushCache(td, -1.0); +} + +/* This is used to remove all certs below a certain threshold, where + * the value is determined by how many times the cert has been requested + * and when the last request was. + */ +NSS_IMPLEMENT void +nssTrustDomain_FlushCache +( + NSSTrustDomain *td, + PRFloat64 threshold +) +{ } struct token_cert_destructor { @@ -361,6 +430,7 @@ struct token_cert_destructor { static void remove_token_certs(const void *k, void *v, void *a) { +#if 0 struct NSSItem *identifier = (struct NSSItem *)k; NSSCertificate *c = (NSSCertificate *)v; struct token_cert_destructor *tcd = (struct token_cert_destructor *)a; @@ -368,6 +438,7 @@ remove_token_certs(const void *k, void *v, void *a) nssHash_Remove(tcd->cache->issuerAndSN, identifier); /* remove from the other hashes */ } +#endif } /* @@ -390,6 +461,254 @@ nssTrustDomain_RemoveTokenCertsFromCache return PR_SUCCESS; } +static PRStatus +add_issuer_and_serial_entry +( + NSSArena *arena, + nssTDCertificateCache *cache, + NSSCertificate *cert +) +{ + cache_entry *ce; + ce = new_cache_entry(arena, (void *)cert); +#ifdef DEBUG + log_cert_ref("added to issuer/sn", cert); +#endif + return nssHash_Add(cache->issuerAndSN, cert, (void *)ce); +} + +static PRStatus +add_subject_entry +( + NSSArena *arena, + nssTDCertificateCache *cache, + NSSCertificate *cert, + nssList **subjectList +) +{ + PRStatus nssrv; + nssList *list; + cache_entry *ce; + *subjectList = NULL; /* this is only set if a new one is created */ + ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject); + if (ce) { + ce->hits++; + ce->lastHit = PR_Now(); + /* The subject is already in, add this cert to the list */ + nssrv = nssList_AddUnique(ce->entry.list, cert); +#ifdef DEBUG + log_cert_ref("added to existing subject list", cert); +#endif + } else { + /* Create a new subject list for the subject */ + list = nssList_Create(arena, PR_FALSE); + if (!list) { + return PR_FAILURE; + } + ce = new_cache_entry(arena, (void *)list); + if (!ce) { + return PR_FAILURE; + } + nssList_SetSortFunction(list, subject_list_sort); + /* Add the cert entry to this list of subjects */ + nssrv = nssList_AddUnique(list, cert); + if (nssrv != PR_SUCCESS) { + return nssrv; + } + /* Add the subject list to the cache */ + nssrv = nssHash_Add(cache->subject, &cert->subject, ce); + if (nssrv != PR_SUCCESS) { + return nssrv; + } + *subjectList = list; +#ifdef DEBUG + log_cert_ref("created subject list", cert); +#endif + } + return nssrv; +} + +static PRStatus +add_nickname_entry +( + NSSArena *arena, + nssTDCertificateCache *cache, + NSSCertificate *cert, + nssList *subjectList +) +{ + PRStatus nssrv = PR_SUCCESS; + cache_entry *ce; + ce = (cache_entry *)nssHash_Lookup(cache->nickname, cert->nickname); + if (ce) { + /* This is a collision. A nickname entry already exists for this + * subject, but a subject entry didn't. This would imply there are + * two subjects using the same nickname, which is not allowed. + */ + return PR_FAILURE; + } else { + ce = new_cache_entry(arena, subjectList); + if (!ce) { + return PR_FAILURE; + } + nssrv = nssHash_Add(cache->nickname, cert->nickname, ce); +#ifdef DEBUG + log_cert_ref("created nickname for", cert); +#endif + } + return nssrv; +} + +static PRStatus +add_email_entry +( + NSSArena *arena, + nssTDCertificateCache *cache, + NSSCertificate *cert, + nssList *subjectList +) +{ + PRStatus nssrv = PR_SUCCESS; + nssList *subjects; + cache_entry *ce; + ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email); + if (ce) { + /* Already have an entry for this email address, but not subject */ + subjects = ce->entry.list; + nssrv = nssList_AddUnique(subjects, subjectList); + ce->hits++; + ce->lastHit = PR_Now(); +#ifdef DEBUG + log_cert_ref("added subject to email for", cert); +#endif + } else { + /* Create a new list of subject lists, add this subject */ + subjects = nssList_Create(arena, PR_TRUE); + if (!subjects) { + return PR_FAILURE; + } + /* Add the new subject to the list */ + nssrv = nssList_AddUnique(subjects, subjectList); + if (nssrv != PR_SUCCESS) { + return nssrv; + } + /* Add the new entry to the cache */ + ce = new_cache_entry(arena, (void *)subjects); + if (!ce) { + return PR_FAILURE; + } + nssrv = nssHash_Add(cache->email, &cert->email, ce); + if (nssrv != PR_SUCCESS) { + return nssrv; + } +#ifdef DEBUG + log_cert_ref("created email for", cert); +#endif + } + return nssrv; +} + +static PRStatus +add_cert_to_cache +( + NSSTrustDomain *td, + NSSCertificate *cert +) +{ + NSSArena *arena; + nssList *subjectList; + PRStatus nssrv; + PRUint32 added = 0; + arena = td->cache->arena; + PZ_Lock(td->cache->lock); + /* If it exists in the issuer/serial hash, it's already in all */ + if (nssHash_Exists(td->cache->issuerAndSN, cert)) { +#ifdef DEBUG + log_cert_ref("attempted to add cert already in cache", cert); +#endif + PZ_Unlock(td->cache->lock); + return PR_SUCCESS; + } + /* create a new cache entry for this cert */ + nssrv = add_issuer_and_serial_entry(arena, td->cache, cert); + if (nssrv != PR_SUCCESS) { + goto loser; + } + added++; + /* create a new subject list for this cert, or add to existing */ + nssrv = add_subject_entry(arena, td->cache, cert, &subjectList); + if (nssrv != PR_SUCCESS) { + goto loser; + } + added++; + /* If a new subject entry was created, also need nickname and/or email */ + if (subjectList != NULL) { + PRBool handle = PR_FALSE; + if (cert->nickname) { + nssrv = add_nickname_entry(arena, td->cache, cert, subjectList); + if (nssrv != PR_SUCCESS) { + goto loser; + } + handle = PR_TRUE; + added++; + } + if (cert->email) { + nssrv = add_email_entry(arena, td->cache, cert, subjectList); + if (nssrv != PR_SUCCESS) { + goto loser; + } + handle = PR_TRUE; + added += 2; + } +#ifdef nodef + /* I think either a nickname or email address must be associated + * with the cert. However, certs are passed to NewTemp without + * either. This worked in the old code, so it must work now. + */ + if (!handle) { + /* Require either nickname or email handle */ + nssrv = PR_FAILURE; + goto loser; + } +#endif + } + PZ_Unlock(td->cache->lock); + return nssrv; +loser: + /* Remove any handles that have been created */ + if (added >= 1) { + (void)remove_issuer_and_serial_entry(td->cache, cert); + } + if (added >= 2) { + (void)remove_subject_entry(td->cache, cert, &subjectList); + } + if (added == 3 || added == 5) { + (void)remove_nickname_entry(td->cache, cert, subjectList); + } + if (added >= 4) { + (void)remove_email_entry(td->cache, cert, subjectList); + } + PZ_Unlock(td->cache->lock); + return PR_FAILURE; +} + +NSS_IMPLEMENT PRStatus +nssTrustDomain_AddCertsToCache +( + NSSTrustDomain *td, + NSSCertificate **certs, + PRUint32 numCerts +) +{ + PRUint32 i; + for (i=0; icache->lock); - subjectList = (nssList *)nssHash_Lookup(td->cache->subject, - (void *)subject); + ce = (cache_entry *)nssHash_Lookup(td->cache->subject, subject); + if (ce) { + ce->hits++; + ce->lastHit = PR_Now(); +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits)); +#endif + } PZ_Unlock(td->cache->lock); - if (subjectList) { - rvArray = collect_subject_certs(subjectList, certListOpt); + if (ce) { + rvArray = collect_subject_certs(ce->entry.list, certListOpt); } return rvArray; } @@ -453,13 +783,22 @@ nssTrustDomain_GetCertsForNicknameFromCache ) { NSSCertificate **rvArray = NULL; - nssList *subjectList; + cache_entry *ce; +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by nick %s", nickname)); +#endif PZ_Lock(td->cache->lock); - subjectList = (nssList *)nssHash_Lookup(td->cache->nickname, - (void *)nickname); + ce = (cache_entry *)nssHash_Lookup(td->cache->nickname, nickname); + if (ce) { + ce->hits++; + ce->lastHit = PR_Now(); +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits)); +#endif + } PZ_Unlock(td->cache->lock); - if (subjectList) { - rvArray = collect_subject_certs(subjectList, certListOpt); + if (ce) { + rvArray = collect_subject_certs(ce->entry.list, certListOpt); } return rvArray; } @@ -476,13 +815,22 @@ nssTrustDomain_GetCertsForEmailAddressFromCache ) { NSSCertificate **rvArray = NULL; - nssList *listOfSubjectLists; + cache_entry *ce; nssList *collectList; +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by email %s", email)); +#endif PZ_Lock(td->cache->lock); - listOfSubjectLists = (nssList *)nssHash_Lookup(td->cache->email, - (void *)email); + ce = (cache_entry *)nssHash_Lookup(td->cache->email, email); + if (ce) { + ce->hits++; + ce->lastHit = PR_Now(); +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits)); +#endif + } PZ_Unlock(td->cache->lock); - if (listOfSubjectLists) { + if (ce) { nssListIterator *iter; nssList *subjectList; if (certListOpt) { @@ -490,7 +838,7 @@ nssTrustDomain_GetCertsForEmailAddressFromCache } else { collectList = nssList_Create(NULL, PR_FALSE); } - iter = nssList_CreateIterator(listOfSubjectLists); + iter = nssList_CreateIterator(ce->entry.list); for (subjectList = (nssList *)nssListIterator_Start(iter); subjectList != (nssList *)NULL; subjectList = (nssList *)nssListIterator_Next(iter)) { @@ -510,10 +858,6 @@ nssTrustDomain_GetCertsForEmailAddressFromCache return rvArray; } -#ifdef DEBUG -static void debug_cache(NSSTrustDomain *td); -#endif - /* * Look for a specific cert in the cache */ @@ -525,27 +869,59 @@ nssTrustDomain_GetCertForIssuerAndSNFromCache NSSDER *serial ) { - NSSCertificate *rvCert; - NSSItem *ias; - unsigned char buf[128]; - NSSItem s_ias; - s_ias.data = (void *)buf; - s_ias.size = sizeof(buf); - ias = get_static_ias(&s_ias, issuer, serial); + NSSCertificate certkey; + NSSCertificate *rvCert = NULL; + cache_entry *ce; + certkey.issuer.data = issuer->data; + certkey.issuer.size = issuer->size; + certkey.serial.data = serial->data; + certkey.serial.size = serial->size; #ifdef DEBUG - debug_cache(td); + log_item_dump("looking for cert by issuer/sn, issuer", issuer); + log_item_dump(" serial", serial); #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); + ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, &certkey); + if (ce) { + ce->hits++; + ce->lastHit = PR_Now(); + rvCert = ce->entry.cert; +#ifdef DEBUG + PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits)); +#endif } + PZ_Unlock(td->cache->lock); return rvCert; } -NSS_EXTERN NSSItem * -STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der); +#ifdef NSS_3_4_CODE +static PRStatus +issuer_and_serial_from_encoding +( + NSSBER *encoding, + NSSDER *issuer, + NSSDER *serial +) +{ + SECItem derCert, derIssuer, derSerial; + SECStatus secrv; + derCert.data = (unsigned char *)encoding->data; + derCert.len = encoding->size; + secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer); + if (secrv != SECSuccess) { + return PR_FAILURE; + } + secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial); + if (secrv != SECSuccess) { + return PR_FAILURE; + } + issuer->data = derIssuer.data; + issuer->size = derIssuer.len; + serial->data = derSerial.data; + serial->size = derSerial.len; + return PR_SUCCESS; +} +#endif /* * Look for a specific cert in the cache @@ -557,16 +933,24 @@ nssTrustDomain_GetCertByDERFromCache NSSDER *der ) { - NSSItem *identifier = NULL; - NSSCertificate *rvCert = NULL; + PRStatus nssrv = PR_FAILURE; + NSSDER issuer, serial; + NSSCertificate *rvCert; #ifdef NSS_3_4_CODE - identifier = STAN_GetCertIdentifierFromDER(NULL, der); + nssrv = issuer_and_serial_from_encoding(der, &issuer, &serial); #endif - if (identifier) { - rvCert = (NSSCertificate *)nssHash_Lookup(td->cache->issuerAndSN, - identifier); + if (nssrv != PR_SUCCESS) { + return NULL; } - nss_ZFreeIf(identifier); +#ifdef DEBUG + log_item_dump("looking for cert by DER", der); +#endif + rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td, + &issuer, &serial); +#ifdef NSS_3_4_CODE + PORT_Free(issuer.data); + PORT_Free(serial.data); +#endif return rvCert; } @@ -603,92 +987,3 @@ nssTrustDomain_GetCertsFromCache return rvArray; } -#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 bf942824eb7..c6d7c63b422 100644 --- a/security/nss/lib/pki/trustdomain.c +++ b/security/nss/lib/pki/trustdomain.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.16 $ $Date: 2001-11-20 18:28:47 $ $Name: $"; +static const char CVS_ID[] = "@(#) $RCSfile: trustdomain.c,v $ $Revision: 1.17 $ $Date: 2001-11-28 16:23:44 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSPKI_H @@ -114,7 +114,8 @@ NSSTrustDomain_Destroy if (--td->refCount == 0) { /* Destroy each token in the list of tokens */ if (td->tokens) { - nssList_DestroyElements(td->tokenList, token_destructor); + nssList_Clear(td->tokenList, token_destructor); + nssList_Destroy(td->tokenList); } /* Destroy the trust domain */ nssArena_Destroy(td->arena); @@ -354,12 +355,10 @@ NSSTrustDomain_ImportEncodedPublicKey } struct get_best_cert_arg_str { - NSSTrustDomain *td; NSSCertificate *cert; NSSTime *time; NSSUsage *usage; NSSPolicies *policies; - nssList *cached; }; static PRStatus @@ -400,59 +399,9 @@ get_best_cert(NSSCertificate *c, void *arg) return PR_SUCCESS; } -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 -) -{ - PRStatus nssrv; - NSSToken *tok; - if (token) { - nssrv = nssToken_TraverseCertificatesByTemplate(token, NULL, - best->cached, - cktemplate, ctsize, - get_best_cert, best); - } else { - /* we need to lock the iterator */ - for (tok = (NSSToken *)nssListIterator_Start(td->tokens); - tok != (NSSToken *)NULL; - tok = (NSSToken *)nssListIterator_Next(td->tokens)) - { - nssrv = nssToken_TraverseCertificatesByTemplate(tok, NULL, - best->cached, - cktemplate, ctsize, - get_best_cert, - best); - } - nssListIterator_Finish(td->tokens); - } - /* Cache the cert before returning */ - /*nssTrustDomain_AddCertsToCache(td, &best->cert, 1);*/ - /* rjr handle orphanned certs in cache for now. real fix will be Ian's - * crypto object */ - if (best->cert == NULL) { - if (nssList_Count(best->cached) >= 1) { - NSSCertificate * candidate; - - nssList_GetArray(best->cached,&candidate,1); - if (candidate) { - best->cert = nssCertificate_AddRef(candidate); - } - } - } - return best->cert; -} - struct collect_arg_str { nssList *list; PRUint32 maximum; - NSSArena *arena; - NSSCertificate **rvOpt; }; extern const NSSError NSS_ERROR_MAXIMUM_FOUND; @@ -471,105 +420,6 @@ collect_certs(NSSCertificate *c, void *arg) return PR_SUCCESS; } -static NSSCertificate ** -find_all_certs_for_template -( - NSSTrustDomain *td, - NSSToken *token, - struct collect_arg_str *ca, - CK_ATTRIBUTE_PTR cktemplate, - CK_ULONG ctsize -) -{ - NSSCertificate **certs = NULL; - PRStatus nssrv; - PRUint32 count; - NSSToken *tok; - if (token) { - nssrv = nssToken_TraverseCertificatesByTemplate(token, NULL, ca->list, - cktemplate, ctsize, - collect_certs, ca); - } else { - /* we need to lock the iterator */ - for (tok = (NSSToken *)nssListIterator_Start(td->tokens); - tok != (NSSToken *)NULL; - tok = (NSSToken *)nssListIterator_Next(td->tokens)) - { - nssrv = nssToken_TraverseCertificatesByTemplate(tok, NULL, - ca->list, - cktemplate, ctsize, - collect_certs, ca); - } - nssListIterator_Finish(td->tokens); - } - count = nssList_Count(ca->list); - if (ca->rvOpt) { - certs = ca->rvOpt; - } else { - certs = nss_ZNEWARRAY(ca->arena, NSSCertificate *, count + 1); - } - nssrv = nssList_GetArray(ca->list, (void **)certs, count); - /* 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 ( @@ -580,23 +430,12 @@ NSSTrustDomain_FindBestCertificateByNickname NSSPolicies *policiesOpt /* NULL for none */ ) { - NSSCertificate *rvCert = NULL; PRStatus nssrv; + NSSToken *token; + nssTokenCertSearch search; 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; @@ -604,62 +443,26 @@ NSSTrustDomain_FindBestCertificateByNickname /* 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, 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, 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[] = + /* set the search criteria */ + search.callback = get_best_cert; + search.cbarg = &best; + search.cached = nameList; + search.trustDomain = td; + search.cryptoContext = NULL; + /* traverse the tokens */ + for (token = (NSSToken *)nssListIterator_Start(td->tokens); + token != (NSSToken *)NULL; + token = (NSSToken *)nssListIterator_Next(td->tokens)) { - { 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); - (void)nssTrustDomain_GetCertsForNicknameFromCache(td, name, nickCerts); - 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; + nssrv = nssToken_TraverseCertificatesByNickname(token, NULL, + name, &search); + } + nssListIterator_Finish(td->tokens); + nssList_Destroy(nameList); + if (best.cert) { + nssTrustDomain_AddCertsToCache(td, &best.cert, 1); + } + return best.cert; } NSS_IMPLEMENT NSSCertificate ** @@ -673,28 +476,45 @@ NSSTrustDomain_FindCertificatesByNickname ) { NSSCertificate **rvCerts = NULL; + NSSToken *token; + PRUint32 count; PRStatus nssrv; - CK_ATTRIBUTE nick_template[] = - { - { CKA_CLASS, NULL, 0 }, - { CKA_LABEL, NULL, 0 } - }; - nssList *nickCerts; + nssList *nameList; 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); - (void)nssTrustDomain_GetCertsForNicknameFromCache(td, name, nickCerts); - ca.list = nickCerts; + nssTokenCertSearch search; + /* set up the collection */ + nameList = nssList_Create(NULL, PR_FALSE); + (void)nssTrustDomain_GetCertsForNicknameFromCache(td, name, nameList); + ca.list = nameList; ca.maximum = maximumOpt; - ca.arena = arenaOpt; - ca.rvOpt = rvOpt; - rvCerts = find_all_certs_for_template(td, NULL, - &ca, nick_template, ctsize); - nssList_Destroy(nickCerts); + /* set the search criteria */ + search.callback = collect_certs; + search.cbarg = &ca; + search.cached = nameList; + search.trustDomain = td; + search.cryptoContext = NULL; + /* traverse the tokens */ + for (token = (NSSToken *)nssListIterator_Start(td->tokens); + token != (NSSToken *)NULL; + token = (NSSToken *)nssListIterator_Next(td->tokens)) + { + nssrv = nssToken_TraverseCertificatesByNickname(token, NULL, + name, &search); + } + nssListIterator_Finish(td->tokens); + count = nssList_Count(nameList); + if (maximumOpt > 0 && count > maximumOpt) count = maximumOpt; + if (count > 0) { + if (rvOpt) { + nssList_GetArray(nameList, (void **)rvOpt, count); + rvOpt[count] = NULL; + } else { + rvCerts = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1); + nssList_GetArray(nameList, (void **)rvCerts, count); + } + nssTrustDomain_AddCertsToCache(td, rvCerts, count); + } + nssList_Destroy(nameList); return rvCerts; } @@ -708,44 +528,29 @@ NSSTrustDomain_FindCertificateByIssuerAndSerialNumber { NSSCertificate *rvCert = NULL; NSSToken *tok; - CK_ULONG ctsize; - CK_OBJECT_HANDLE object; - CK_ATTRIBUTE cert_template[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_ISSUER, NULL, 0 }, - { CKA_SERIAL_NUMBER, NULL, 0 } - }; - ctsize = sizeof(cert_template) / sizeof(cert_template[0]); - /* Set the unique id */ - NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); - NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 1, issuer); - NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 2, serialNumber); /* Try the cache */ rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td, issuer, serialNumber); - if (!rvCert) { - /* Not cached, look for it on tokens */ - for (tok = (NSSToken *)nssListIterator_Start(td->tokens); - tok != (NSSToken *)NULL; - tok = (NSSToken *)nssListIterator_Next(td->tokens)) - { - object = nssToken_FindObjectByTemplate(tok, NULL, - cert_template, ctsize); - if (object != CK_INVALID_HANDLE) { - /* Could not find cert, so create it */ - rvCert = nssCertificate_CreateFromHandle(NULL, object, - tok->defaultSession, - tok->slot); - if (rvCert) { - /* cache it */ - /*nssTrustDomain_AddCertsToCache(td, &rvCert, 1);*/ - } - break; - } - } - nssListIterator_Finish(td->tokens); + if (rvCert) { + return rvCert; } + /* Not cached, look for it on tokens */ + for (tok = (NSSToken *)nssListIterator_Start(td->tokens); + tok != (NSSToken *)NULL; + tok = (NSSToken *)nssListIterator_Next(td->tokens)) + { + rvCert = nssToken_FindCertificateByIssuerAndSerialNumber(tok, + NULL, + issuer, + serialNumber); + if (rvCert) { + /* cache it */ + nssTrustDomain_AddCertsToCache(td, &rvCert, 1); + break; + } + } + nssListIterator_Finish(td->tokens); return rvCert; } @@ -759,31 +564,39 @@ NSSTrustDomain_FindBestCertificateBySubject NSSPolicies *policiesOpt ) { - NSSCertificate *rvCert = NULL; + PRStatus nssrv; + NSSToken *token; nssList *subjectList; - CK_ATTRIBUTE subj_template[] = - { - { CKA_CLASS, NULL, 0 }, - { CKA_SUBJECT, NULL, 0 } - }; struct get_best_cert_arg_str best; - CK_ULONG ctsize; - ctsize = (CK_ULONG)(sizeof(subj_template) / sizeof(subj_template[0])); - NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 0, &g_ck_class_cert); - NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 1, subject); - best.td = td; + nssTokenCertSearch search; + /* set the criteria for determining the best cert */ best.cert = NULL; best.time = (timeOpt) ? timeOpt : NSSTime_Now(NULL); best.usage = usage; best.policies = policiesOpt; + /* find all matching certs in the cache */ subjectList = nssList_Create(NULL, PR_FALSE); (void)nssTrustDomain_GetCertsForSubjectFromCache(td, subject, subjectList); - best.cached = subjectList; - /* now find the best cert on tokens */ - rvCert = find_best_cert_for_template(td, NULL, - &best, subj_template, ctsize); + /* set the search criteria */ + search.callback = get_best_cert; + search.cbarg = &best; + search.cached = subjectList; + search.trustDomain = td; + search.cryptoContext = NULL; + /* traverse the tokens */ + for (token = (NSSToken *)nssListIterator_Start(td->tokens); + token != (NSSToken *)NULL; + token = (NSSToken *)nssListIterator_Next(td->tokens)) + { + nssrv = nssToken_TraverseCertificatesBySubject(token, NULL, + subject, &search); + } + nssListIterator_Finish(td->tokens); nssList_Destroy(subjectList); - return rvCert; + if (best.cert) { + nssTrustDomain_AddCertsToCache(td, &best.cert, 1); + } + return best.cert; } NSS_IMPLEMENT NSSCertificate ** @@ -796,26 +609,45 @@ NSSTrustDomain_FindCertificatesBySubject NSSArena *arenaOpt ) { + PRStatus nssrv; NSSCertificate **rvCerts = NULL; + NSSToken *token; + PRUint32 count; nssList *subjectList; struct collect_arg_str ca; - CK_ATTRIBUTE subj_template[] = - { - { CKA_CLASS, NULL, 0 }, - { CKA_SUBJECT, NULL, 0 } - }; - CK_ULONG ctsize; - ctsize = (CK_ULONG)(sizeof(subj_template) / sizeof(subj_template[0])); - NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 0, &g_ck_class_cert); - NSS_CK_SET_ATTRIBUTE_ITEM(subj_template, 1, subject); + nssTokenCertSearch search; + /* set up the collection */ subjectList = nssList_Create(NULL, PR_FALSE); (void)nssTrustDomain_GetCertsForSubjectFromCache(td, subject, subjectList); ca.list = subjectList; ca.maximum = maximumOpt; - ca.arena = arenaOpt; - ca.rvOpt = rvOpt; - rvCerts = find_all_certs_for_template(td, NULL, - &ca, subj_template, ctsize); + /* set the search criteria */ + search.callback = collect_certs; + search.cbarg = &ca; + search.cached = subjectList; + search.trustDomain = td; + search.cryptoContext = NULL; + /* traverse the tokens */ + for (token = (NSSToken *)nssListIterator_Start(td->tokens); + token != (NSSToken *)NULL; + token = (NSSToken *)nssListIterator_Next(td->tokens)) + { + nssrv = nssToken_TraverseCertificatesBySubject(token, NULL, + subject, &search); + } + nssListIterator_Finish(td->tokens); + count = nssList_Count(subjectList); + if (maximumOpt > 0 && count > maximumOpt) count = maximumOpt; + if (count > 0) { + if (rvOpt) { + nssList_GetArray(subjectList, (void **)rvOpt, count); + rvOpt[count] = NULL; + } else { + rvCerts = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1); + nssList_GetArray(subjectList, (void **)rvCerts, count); + } + nssTrustDomain_AddCertsToCache(td, rvCerts, count); + } nssList_Destroy(subjectList); return rvCerts; } @@ -857,39 +689,25 @@ NSSTrustDomain_FindCertificateByEncodedCertificate { NSSCertificate *rvCert = NULL; NSSToken *tok; - CK_ULONG ctsize; - CK_OBJECT_HANDLE object; - CK_ATTRIBUTE cert_template[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_VALUE, NULL, 0 } - }; - ctsize = sizeof(cert_template) / sizeof(cert_template[0]); - NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 0, &g_ck_class_cert); - NSS_CK_SET_ATTRIBUTE_ITEM(cert_template, 1, encodedCertificate); /* Try the cache */ rvCert = nssTrustDomain_GetCertByDERFromCache(td, encodedCertificate); - if (!rvCert) { - /* Not cached, look for it on tokens */ - for (tok = (NSSToken *)nssListIterator_Start(td->tokens); - tok != (NSSToken *)NULL; - tok = (NSSToken *)nssListIterator_Next(td->tokens)) - { - object = nssToken_FindObjectByTemplate(tok, NULL, - cert_template, ctsize); - if (object != CK_INVALID_HANDLE) { - /* found it */ - rvCert = nssCertificate_CreateFromHandle(NULL, object, - tok->defaultSession, - tok->slot); - if (rvCert) { - /* cache it */ - /*nssTrustDomain_AddCertsToCache(td, &rvCert, 1);*/ - } - break; - } - } - nssListIterator_Finish(td->tokens); + if (rvCert) { + return rvCert; } + /* Not cached, look for it on tokens */ + for (tok = (NSSToken *)nssListIterator_Start(td->tokens); + tok != (NSSToken *)NULL; + tok = (NSSToken *)nssListIterator_Next(td->tokens)) + { + rvCert = nssToken_FindCertificateByEncodedCertificate(tok, NULL, + encodedCertificate); + if (rvCert) { + /* cache it */ + nssTrustDomain_AddCertsToCache(td, &rvCert, 1); + break; + } + } + nssListIterator_Finish(td->tokens); return rvCert; } @@ -903,23 +721,12 @@ NSSTrustDomain_FindCertificateByEmail NSSPolicies *policiesOpt ) { - NSSCertificate *rvCert = NULL; PRStatus nssrv; + NSSToken *token; struct get_best_cert_arg_str best; - CK_ATTRIBUTE email_template[] = - { - { CKA_CLASS, NULL, 0 }, - { CKA_NETSCAPE_EMAIL, NULL, 0 } - }; - CK_ULONG ctsize; + nssTokenCertSearch search; nssList *emailList; - /* set up the search template */ - ctsize = (CK_ULONG)(sizeof(email_template) / sizeof(email_template[0])); - NSS_CK_SET_ATTRIBUTE_ITEM(email_template, 0, &g_ck_class_cert); - email_template[1].pValue = (CK_VOID_PTR)email; - email_template[1].ulValueLen = (CK_ULONG)nssUTF8_Length(email, &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; @@ -927,20 +734,26 @@ NSSTrustDomain_FindCertificateByEmail /* find all matching certs in the cache */ emailList = nssList_Create(NULL, PR_FALSE); (void)nssTrustDomain_GetCertsForEmailAddressFromCache(td, email, emailList); - best.cached = emailList; - /* now find the best cert on tokens */ - rvCert = find_best_cert_for_template(td, NULL, - &best, email_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? - */ - email_template[1].ulValueLen++; - rvCert = find_best_cert_for_template(td, NULL, - &best, email_template, ctsize); + /* set the search criteria */ + search.callback = get_best_cert; + search.cbarg = &best; + search.cached = emailList; + search.trustDomain = td; + search.cryptoContext = NULL; + /* traverse the tokens */ + for (token = (NSSToken *)nssListIterator_Start(td->tokens); + token != (NSSToken *)NULL; + token = (NSSToken *)nssListIterator_Next(td->tokens)) + { + nssrv = nssToken_TraverseCertificatesByEmail(token, NULL, + email, &search); } + nssListIterator_Finish(td->tokens); nssList_Destroy(emailList); - return rvCert; + if (best.cert) { + nssTrustDomain_AddCertsToCache(td, &best.cert, 1); + } + return best.cert; } NSS_IMPLEMENT NSSCertificate ** @@ -1072,17 +885,26 @@ NSSTrustDomain_TraverseCertificates ) { PRStatus nssrv; - NSSToken *tok; - - /* we need to lock the iterator */ - for (tok = (NSSToken *)nssListIterator_Start(td->tokens); - tok != (NSSToken *)NULL; - tok = (NSSToken *)nssListIterator_Next(td->tokens)) + NSSToken *token; + nssList *certList; + nssTokenCertSearch search; + (void *)nssTrustDomain_GetCertsFromCache(td, certList); + /* set the search criteria */ + search.callback = callback; + search.cbarg = arg; + search.cached = certList; + search.trustDomain = td; + search.cryptoContext = NULL; + /* traverse the tokens */ + for (token = (NSSToken *)nssListIterator_Start(td->tokens); + token != (NSSToken *)NULL; + token = (NSSToken *)nssListIterator_Next(td->tokens)) { - nssrv = nssToken_TraverseCertificates(tok, NULL, callback, arg); + nssrv = nssToken_TraverseCertificates(token, NULL, &search); } nssListIterator_Finish(td->tokens); - return NULL; /* should return array of nssrv's ? */ + nssList_Destroy(certList); + return NULL; } NSS_IMPLEMENT PRStatus @@ -1149,8 +971,18 @@ NSSTrustDomain_CreateCryptoContext NSSCallback *uhhOpt ) { - nss_SetError(NSS_ERROR_NOT_FOUND); - return NULL; + NSSArena *arena; + NSSCryptoContext *rvCC; + arena = NSSArena_Create(); + if (!arena) { + return NULL; + } + rvCC = nss_ZNEW(arena, NSSCryptoContext); + if (!rvCC) { + return NULL; + } + rvCC->td = td; + return rvCC; } NSS_IMPLEMENT NSSCryptoContext *