diff options
author | relyea%netscape.com <devnull@localhost> | 2000-09-06 22:05:57 +0000 |
---|---|---|
committer | relyea%netscape.com <devnull@localhost> | 2000-09-06 22:05:57 +0000 |
commit | 0b29cb1bf2875d3edcdd00d14d457c399c7bca89 (patch) | |
tree | 0dee7e0d5678878cfd0dca54b94391ecfcc90526 | |
parent | 300d3954ba21706e7d163882da6f83a8d778775e (diff) | |
download | nss-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.c | 131 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11db.c | 8 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11list.c | 4 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11load.c | 43 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11slot.c | 29 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11util.c | 68 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/secmodti.h | 2 |
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 */ |