summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrelyea%netscape.com <devnull@localhost>2000-09-06 22:05:57 +0000
committerrelyea%netscape.com <devnull@localhost>2000-09-06 22:05:57 +0000
commit0b29cb1bf2875d3edcdd00d14d457c399c7bca89 (patch)
tree0dee7e0d5678878cfd0dca54b94391ecfcc90526
parent300d3954ba21706e7d163882da6f83a8d778775e (diff)
downloadnss-hg-0b29cb1bf2875d3edcdd00d14d457c399c7bca89.tar.gz
Add code to allow Trusted root certs to come from an externally loaded
pkcs #11 module.
-rw-r--r--security/nss/lib/pk11wrap/pk11cert.c131
-rw-r--r--security/nss/lib/pk11wrap/pk11db.c8
-rw-r--r--security/nss/lib/pk11wrap/pk11list.c4
-rw-r--r--security/nss/lib/pk11wrap/pk11load.c43
-rw-r--r--security/nss/lib/pk11wrap/pk11slot.c29
-rw-r--r--security/nss/lib/pk11wrap/pk11util.c68
-rw-r--r--security/nss/lib/pk11wrap/secmodti.h2
7 files changed, 283 insertions, 2 deletions
diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c
index 5304b1248..69953e3e9 100644
--- a/security/nss/lib/pk11wrap/pk11cert.c
+++ b/security/nss/lib/pk11wrap/pk11cert.c
@@ -52,6 +52,9 @@
#include "secerr.h"
#include "sslerr.h"
+#define NSSCKT_H /* we included pkcs11t.h, so block ckt.h from including nssckt.h */
+#include "ckt.h"
+
#define PK11_SEARCH_CHUNKSIZE 10
CK_OBJECT_HANDLE
@@ -396,6 +399,126 @@ CERTCertificate
return cert;
}
+CK_TRUST
+pk11_GetTrustField(PK11SlotInfo *slot, PRArenaPool *arena,
+ CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type)
+{
+ CK_TRUST rv = 0;
+ SECItem item;
+
+ item.data = NULL;
+ item.len = 0;
+
+ if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) {
+ PORT_Assert(item.len == sizeof(CK_TRUST));
+ PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST));
+ /* Damn, is there an endian problem here? */
+ return rv;
+ }
+
+ return 0;
+}
+
+PRBool
+pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust)
+{
+ PRArenaPool *arena;
+
+ CK_ATTRIBUTE tobjTemplate[] = {
+ { CKA_CLASS, NULL, 0 },
+ { CKA_CERT_SHA1_HASH, NULL, 0 },
+ };
+
+ CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
+ CK_OBJECT_HANDLE tobjID;
+ unsigned char sha1_hash[SHA1_LENGTH];
+
+ CK_TRUST digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment,
+ keyAgreement, keyCertSign, crlSign, serverAuth, clientAuth, codeSigning,
+ emailProtection, ipsecEndSystem, ipsecTunnel, ipsecUser, timeStamping;
+
+ SECItem item;
+
+ PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len);
+
+ PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc));
+ PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash,
+ SHA1_LENGTH);
+
+ tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate,
+ sizeof(tobjTemplate)/sizeof(tobjTemplate[0]));
+ if( CK_INVALID_KEY == tobjID ) {
+ return PR_FALSE;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if( NULL == arena ) return PR_FALSE;
+
+ /* Unfortunately, it seems that PK11_GetAttributes doesn't deal
+ * well with nonexistant attributes. I guess we have to check
+ * the trust info fields one at a time.
+ */
+
+ /* We could verify CKA_CERT_HASH here */
+
+ /* We could verify CKA_EXPIRES here */
+
+ /* "Usage" trust information */
+ /* digitalSignature = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_DIGITAL_SIGNATURE); */
+ /* nonRepudiation = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_NON_REPUDIATION); */
+ /* keyEncipherment = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_KEY_ENCIPHERMENT); */
+ /* dataEncipherment = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_DATA_ENCIPHERMENT); */
+ /* keyAgreement = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_KEY_AGREEMENT); */
+ /* keyCertSign = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_KEY_CERT_SIGN); */
+ /* crlSign = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CRL_SIGN); */
+
+ /* "Purpose" trust information */
+ serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH);
+ /* clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH); */
+ codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING);
+ emailProtection = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_EMAIL_PROTECTION);
+ /* ipsecEndSystem = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_IPSEC_END_SYSTEM); */
+ /* ipsecTunnel = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_IPSEC_TUNNEL); */
+ /* ipsecUser = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_IPSEC_USER); */
+ /* timeStamping = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_TIME_STAMPING); */
+
+ /* Here's where the fun logic happens. We have to map back from the key usage,
+ * extended key usage, purpose, and possibly other trust values into the old
+ * trust-flags bits.
+ */
+
+ /* First implementation: keep it simple for testing. We can study what other
+ * mappings would be appropriate and add them later.. fgmr 20000724 */
+
+ if( serverAuth & CKT_NETSCAPE_TRUSTED ) {
+ trust->sslFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
+ }
+
+ if( serverAuth & CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
+ trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
+ }
+
+ if( emailProtection & CKT_NETSCAPE_TRUSTED ) {
+ trust->emailFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
+ }
+
+ if( emailProtection & CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
+ trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
+ }
+
+ if( codeSigning & CKT_NETSCAPE_TRUSTED ) {
+ trust->objectSigningFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
+ }
+
+ if( codeSigning & CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
+ trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
+ }
+
+ /* There's certainly a lot more logic that can go here.. */
+
+ return PR_TRUE;
+}
+
/*
* Build an CERTCertificate structure from a PKCS#11 object ID.... certID
* Must be a CertObject. This code does not explicitly checks that.
@@ -442,6 +565,14 @@ PK11_MakeCertFromHandle(PK11SlotInfo *slot,CK_OBJECT_HANDLE certID,
PORT_Memset(trust,0, sizeof(CERTCertTrust));
cert->trust = trust;
/* build some cert trust flags */
+
+ /* First, see if there's a trust object for this cert. */
+ /* For the first implementation, we'll just check this slot
+ * and worry about overriding trust info later. */
+ if( pk11_HandleTrustObject(slot, cert, trust) ) {
+ ;
+ } else
+
if (CERT_IsCACert(cert, &type)) {
unsigned int trustflags = CERTDB_VALID_CA;
diff --git a/security/nss/lib/pk11wrap/pk11db.c b/security/nss/lib/pk11wrap/pk11db.c
index 1e073075e..4571371f6 100644
--- a/security/nss/lib/pk11wrap/pk11db.c
+++ b/security/nss/lib/pk11wrap/pk11db.c
@@ -118,7 +118,7 @@ SECMODModule *SECMOD_NewInternal(void) {
{ 1, SECMOD_RSA_FLAG|SECMOD_DSA_FLAG|SECMOD_RC2_FLAG|
SECMOD_RC4_FLAG|SECMOD_DES_FLAG|SECMOD_RANDOM_FLAG|
SECMOD_SHA1_FLAG|SECMOD_MD5_FLAG|SECMOD_MD2_FLAG|
- SECMOD_SSL_FLAG|SECMOD_TLS_FLAG, -1, 30 };
+ SECMOD_SSL_FLAG|SECMOD_TLS_FLAG, -1, 30, 0 };
intern = SECMOD_NewModule();
if (intern == NULL) {
@@ -310,7 +310,8 @@ struct secmodSlotDataStr {
unsigned char defaultFlags[4];
unsigned char timeout[4];
unsigned char askpw;
- unsigned char reserved[19]; /* this makes it a round 32 bytes */
+ unsigned char hasRootCerts;
+ unsigned char reserved[18]; /* this makes it a round 32 bytes */
};
#define SECMOD_DB_VERSION_MAJOR 0
@@ -399,6 +400,7 @@ static SECStatus secmod_EncodeData(DBT *data, SECMODModule * module) {
module->slots[i]->defaultFlags);
SECMOD_PUTLONG(slot[si].timeout,module->slots[i]->timeout);
slot[si].askpw = module->slots[i]->askpw;
+ slot[si].hasRootCerts = module->slots[i]->hasRootCerts;
PORT_Memset(slot[si].reserved, 0, sizeof(slot[si].reserved));
si++;
}
@@ -410,6 +412,7 @@ static SECStatus secmod_EncodeData(DBT *data, SECMODModule * module) {
module->slotInfo[i].defaultFlags);
SECMOD_PUTLONG(slot[i].timeout,module->slotInfo[i].timeout);
slot[i].askpw = module->slotInfo[i].askpw;
+ slot[i].hasRootCerts = module->slots[i]->hasRootCerts;
PORT_Memset(slot[i].reserved, 0, sizeof(slot[i].reserved));
}
}
@@ -492,6 +495,7 @@ static SECMODModule *secmod_DecodeData(DBT *data) {
}
module->slotInfo[i].timeout = SECMOD_GETLONG(slots[i].timeout);
module->slotInfo[i].askpw = slots[i].askpw;
+ module->slotInfo[i].hasRootCerts = slots[i].hasRootCerts;
if (module->slotInfo[i].askpw == 0xff) {
module->slotInfo[i].askpw = -1;
}
diff --git a/security/nss/lib/pk11wrap/pk11list.c b/security/nss/lib/pk11wrap/pk11list.c
index 35a68d8a2..f33c7b9f5 100644
--- a/security/nss/lib/pk11wrap/pk11list.c
+++ b/security/nss/lib/pk11wrap/pk11list.c
@@ -81,6 +81,7 @@ void SECMOD_DestroyListLock(SECMODListLock *lock) {
*/
void SECMOD_GetReadLock(SECMODListLock *modLock) {
#ifdef PKCS11_USE_THREADS
+ if (modLock == NULL) return;
PR_EnterMonitor(modLock->monitor);
while (modLock->state & ISWRITING) {
PR_Wait(modLock->monitor,PR_INTERVAL_NO_TIMEOUT); /* wait until woken up */
@@ -96,6 +97,7 @@ void SECMOD_GetReadLock(SECMODListLock *modLock) {
*/
void SECMOD_ReleaseReadLock(SECMODListLock *modLock) {
#ifdef PKCS11_USE_THREADS
+ if (modLock == NULL) return;
PR_EnterMonitor(modLock->monitor);
modLock->count--;
if (modLock->count == 0) {
@@ -114,6 +116,7 @@ void SECMOD_ReleaseReadLock(SECMODListLock *modLock) {
*/
void SECMOD_GetWriteLock(SECMODListLock *modLock) {
#ifdef PKCS11_USE_THREADS
+ if (modLock == NULL) return;
PR_EnterMonitor(modLock->monitor);
while (modLock->state & ISLOCKED) {
modLock->state |= WANTWRITE;
@@ -131,6 +134,7 @@ void SECMOD_GetWriteLock(SECMODListLock *modLock) {
*/
void SECMOD_ReleaseWriteLock(SECMODListLock *modLock) {
#ifdef PKCS11_USE_THREADS
+ if (modLock == NULL) return;
PR_EnterMonitor(modLock->monitor);
modLock->state = 0;
PR_NotifyAll(modLock->monitor); /* enable all the readers */
diff --git a/security/nss/lib/pk11wrap/pk11load.c b/security/nss/lib/pk11wrap/pk11load.c
index 65d898e6e..0a780e09a 100644
--- a/security/nss/lib/pk11wrap/pk11load.c
+++ b/security/nss/lib/pk11wrap/pk11load.c
@@ -77,6 +77,48 @@ static CK_C_INITIALIZE_ARGS secmodLockFunctions = {
};
/*
+ * set the hasRootCerts flags in the module so it can be stored back
+ * into the database.
+ */
+void
+SECMOD_SetRootCerts(PK11SlotInfo *slot, SECMODModule *mod) {
+ PK11PreSlotInfo *psi = NULL;
+ int i;
+
+ if (slot->hasRootCerts) {
+ for (i=0; i < mod->slotInfoCount; i++) {
+ if (slot->slotID == mod->slotInfo[i].slotID) {
+ psi = &mod->slotInfo[i];
+ break;
+ }
+ }
+ if (psi == NULL) {
+ /* allocate more slots */
+ PK11PreSlotInfo *psi_list = (PK11PreSlotInfo *)
+ PORT_ArenaAlloc(mod->arena,
+ (mod->slotInfoCount+1)* sizeof(PK11PreSlotInfo));
+ /* copy the old ones */
+ if (mod->slotInfoCount > 0) {
+ PORT_Memcpy(psi_list,mod->slotInfo,
+ (mod->slotInfoCount)*sizeof(PK11PreSlotInfo));
+ }
+ /* assign psi to the last new slot */
+ psi = &psi_list[mod->slotInfoCount];
+ psi->slotID = slot->slotID;
+ psi->askpw = 0;
+ psi->timeout = 0;
+ psi ->defaultFlags = 0;
+
+ /* increment module count & store new list */
+ mod->slotInfo = psi_list;
+ mod->slotInfoCount++;
+
+ }
+ psi->hasRootCerts = 1;
+ }
+}
+
+/*
* load a new module into our address space and initialize it.
*/
SECStatus
@@ -189,6 +231,7 @@ SECMOD_LoadModule(SECMODModule *mod) {
PK11_InitSlot(mod,slotIDs[i],mod->slots[i]);
/* look down the slot info table */
PK11_LoadSlotList(mod->slots[i],mod->slotInfo,mod->slotInfoCount);
+ SECMOD_SetRootCerts(mod->slots[i],mod);
}
mod->slotCount = slotCount;
mod->slotInfoCount = 0;
diff --git a/security/nss/lib/pk11wrap/pk11slot.c b/security/nss/lib/pk11wrap/pk11slot.c
index 6c7cb4296..18a36f4fb 100644
--- a/security/nss/lib/pk11wrap/pk11slot.c
+++ b/security/nss/lib/pk11wrap/pk11slot.c
@@ -48,6 +48,9 @@
#include "prtime.h"
#include "prlong.h"
#include "secerr.h"
+#define NSSCKT_H /* we included pkcs11t.h, so block ckt.h from including nssckt.h */
+#include "ckt.h"
+
/*************************************************************
* local static and global data
@@ -435,6 +438,7 @@ PK11_NewSlotInfo(void)
slot->authTime = LL_ZERO;
slot->minPassword = 0;
slot->maxPassword = 0;
+ slot->hasRootCerts = PR_FALSE;
return slot;
}
@@ -1211,6 +1215,7 @@ PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count)
slot->defaultFlags = psi[i].defaultFlags;
slot->askpw = psi[i].askpw;
slot->timeout = psi[i].timeout;
+ slot->hasRootCerts = psi[i].hasRootCerts;
/* if the slot is already disabled, don't load them into the
* default slot lists. We get here so we can save the default
@@ -1709,6 +1714,27 @@ PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts)
return SECSuccess;
}
+static PRBool
+pk11_isRootSlot(PK11SlotInfo *slot)
+{
+ CK_ATTRIBUTE findTemp[1];
+ CK_ATTRIBUTE *attrs;
+ CK_OBJECT_CLASS oclass = CKO_NETSCAPE_BUILTIN_ROOT_LIST;
+ int tsize;
+ CK_OBJECT_HANDLE handle;
+
+ attrs = findTemp;
+ PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass)); attrs++;
+ tsize = attrs - findTemp;
+ PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
+
+ handle = pk11_FindObjectByTemplate(slot,findTemp,tsize);
+ if (handle == CK_INVALID_KEY) {
+ return PR_FALSE;
+ }
+ return PR_TRUE;
+}
+
/*
* Initialize the slot :
* This initialization code is called on each slot a module supports when
@@ -1766,6 +1792,9 @@ PK11_InitSlot(SECMODModule *mod,CK_SLOT_ID slotID,PK11SlotInfo *slot)
slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
}
}
+ if (pk11_isRootSlot(slot)) {
+ slot->hasRootCerts= PR_TRUE;
+ }
}
diff --git a/security/nss/lib/pk11wrap/pk11util.c b/security/nss/lib/pk11wrap/pk11util.c
index 709bf32c8..67c10e36d 100644
--- a/security/nss/lib/pk11wrap/pk11util.c
+++ b/security/nss/lib/pk11wrap/pk11util.c
@@ -55,9 +55,70 @@ extern int XP_SEC_MODULE_NO_LIB;
extern PK11DefaultArrayEntry PK11_DefaultArray[];
extern int num_pk11_default_mechanisms;
+static PRBool secmod_ModuleHasRoots(SECMODModule *module)
+{
+ int i;
+
+ for (i=0; i < module->slotInfoCount; i++) {
+ if (module->slotInfo[i].hasRootCerts) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+}
+
+
+/*
+ * The following code is an attempt to automagically find the external root
+ * module. NOTE: This code should be checked out on the MAC! There must be
+ * some cross platform support out there to help out with this?
+ */
+
+static char *dllnames[]= {
+ "roots.dll", "libroots.so","libroots.sl","Root Certs",
+ "roots.dll", "libroots.so","libroots.sl","Root Certs",
+ "nssckbi.dll","libnssckbi.so","libnssckbi.sl","NSS Builtin Root Certs",
+ "mozckbi.dll","libmozckbi.so","libmozckbi.sl","Mozilla Builtin Root Certs",
+ "netckbi.dll","libnetckbi.so","libnetckbi.sl","Netscape Builtin Root Certs",
+ 0 };
+
+#define MAXDLLNAME 40
+
+/* Should we have platform ifdefs here??? */
+#define FILE_SEP '/'
+
+static void
+secmod_FindExternalRoot(char *dbname)
+{
+ char *path, *cp, **cur_name;
+ int len = PORT_Strlen(dbname);
+ int path_len;
+
+
+ path = PORT_Alloc(len+MAXDLLNAME);
+ if (path == NULL) return;
+
+ /* back up to the top of the directory */
+ for (cp = &dbname[len]; cp != dbname && (*cp != FILE_SEP); cp--) ;
+ path_len = cp-dbname;
+ PORT_Memcpy(path,dbname,path_len);
+ path[path_len++] = FILE_SEP;
+
+ /* now walk our tree of dll names looking for the file of interest. */
+ for (cur_name= dllnames; *cur_name != 0; cur_name++) {
+ PORT_Memcpy(&path[path_len],*cur_name,PORT_Strlen(*cur_name)+1);
+ if (SECMOD_AddNewModule("Root Certs",path, 0, 0) == SECSuccess) {
+ break;
+ }
+ }
+ PORT_Free(path);
+ return;
+}
+
void SECMOD_init(char *dbname) {
SECMODModuleList *thisModule;
int found=0;
+ int rootFound=0;
SECStatus rv = SECFailure;
@@ -80,6 +141,10 @@ void SECMOD_init(char *dbname) {
internalModule = SECMOD_ReferenceModule(thisModule->module);
break;
}
+ if (secmod_ModuleHasRoots(thisModule->module)) {
+ rootFound++;
+ break;
+ }
}
if (!found) {
@@ -98,6 +163,9 @@ void SECMOD_init(char *dbname) {
if( rv != SECSuccess )
internalModule = NULL;
+ if (! rootFound ) {
+ secmod_FindExternalRoot(dbname);
+ }
/* Load each new module */
for (thisModule = modules; thisModule ; thisModule = thisModule->next) {
if( !( thisModule->module->internal ) )
diff --git a/security/nss/lib/pk11wrap/secmodti.h b/security/nss/lib/pk11wrap/secmodti.h
index d97059a9b..7d7909ea1 100644
--- a/security/nss/lib/pk11wrap/secmodti.h
+++ b/security/nss/lib/pk11wrap/secmodti.h
@@ -116,6 +116,7 @@ struct PK11SlotInfoStr {
* allow them to become null terminated strings */
char slot_name[65];
char token_name[33];
+ PRBool hasRootCerts;
PRBool hasRSAInfo;
CK_FLAGS RSAInfoFlags;
};
@@ -129,6 +130,7 @@ struct PK11PreSlotInfoStr {
* provides */
int askpw; /* slot specific password bits */
long timeout; /* slot specific timeout value */
+ char hasRootCerts; /* is this the root cert PKCS #11 module? */
};
/* Symetric Key structure. Reference Counted */