From 7ac4ac4a5302bbf740915932120483800c96624f Mon Sep 17 00:00:00 2001 From: "relyea%netscape.com" Date: Thu, 29 Jul 2004 23:38:14 +0000 Subject: Bugzilla Bug 252702 NSS needs to handle better token insertion and removal. Applied from patch to NSS 3.9 --- security/nss/lib/nss/nss.def | 9 + security/nss/lib/pk11wrap/pk11err.c | 2 + security/nss/lib/pk11wrap/pk11list.c | 88 ++---- security/nss/lib/pk11wrap/pk11load.c | 58 ++-- security/nss/lib/pk11wrap/pk11pars.c | 14 + security/nss/lib/pk11wrap/pk11util.c | 508 +++++++++++++++++++++++++++++++---- security/nss/lib/pk11wrap/secmod.h | 20 ++ security/nss/lib/pk11wrap/secmodi.h | 1 + security/nss/lib/pk11wrap/secmodt.h | 18 ++ security/nss/lib/pk11wrap/secmodti.h | 4 + security/nss/lib/pki/pki3hack.c | 63 ++++- security/nss/lib/pki/pki3hack.h | 21 +- security/nss/lib/pki/pkit.h | 5 + security/nss/lib/pki/trustdomain.c | 17 ++ security/nss/lib/util/secerr.h | 4 +- 15 files changed, 678 insertions(+), 154 deletions(-) diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def index 2533a0748..b3c027360 100644 --- a/security/nss/lib/nss/nss.def +++ b/security/nss/lib/nss/nss.def @@ -797,6 +797,15 @@ PK11_UnlinkGenericObject; ;+ local: ;+ *; ;+}; +;+NSS_3.9.3 { # NSS 3.9.3 release +;+ global: +SECMOD_CancelWait; +SECMOD_HasRemovableSlots; +SECMOD_UpdateSlotList; +SECMOD_WaitForAnyTokenEvent; +;+ local: +;+ *; +;+}; ;+NSS_3.10 { # NSS 3.10 release ;+ global: CERT_DecodeAltNameExtension; diff --git a/security/nss/lib/pk11wrap/pk11err.c b/security/nss/lib/pk11wrap/pk11err.c index e8ae32004..589ec8265 100644 --- a/security/nss/lib/pk11wrap/pk11err.c +++ b/security/nss/lib/pk11wrap/pk11err.c @@ -90,6 +90,7 @@ PK11_MapError(CK_RV rv) { MAPERROR(CKR_KEY_TYPE_INCONSISTENT, SEC_ERROR_INVALID_KEY) MAPERROR(CKR_MECHANISM_INVALID, SEC_ERROR_BAD_DATA) MAPERROR(CKR_MECHANISM_PARAM_INVALID, SEC_ERROR_BAD_DATA) + MAPERROR(CKR_NO_EVENT, SEC_ERROR_NO_EVENT) MAPERROR(CKR_OBJECT_HANDLE_INVALID, SEC_ERROR_BAD_DATA) MAPERROR(CKR_OPERATION_ACTIVE, SEC_ERROR_LIBRARY_FAILURE) MAPERROR(CKR_OPERATION_NOT_INITIALIZED,SEC_ERROR_LIBRARY_FAILURE ) @@ -124,6 +125,7 @@ PK11_MapError(CK_RV rv) { #ifdef PK11_ERROR_USE_ARRAY +}; int PK11_MapError(CK_RV rv) { diff --git a/security/nss/lib/pk11wrap/pk11list.c b/security/nss/lib/pk11wrap/pk11list.c index 364976540..3baaef921 100644 --- a/security/nss/lib/pk11wrap/pk11list.c +++ b/security/nss/lib/pk11wrap/pk11list.c @@ -43,37 +43,26 @@ #include "secmod.h" #include "secmodi.h" #include "secmodti.h" - -#define ISREADING 1 -#define ISWRITING 2 -#define WANTWRITE 4 -#define ISLOCKED 3 +#include "nssrwlk.h" /* * create a new lock for a Module List */ -SECMODListLock *SECMOD_NewListLock() { - SECMODListLock *modLock; - - modLock = (SECMODListLock*)PORT_Alloc(sizeof(SECMODListLock)); +SECMODListLock *SECMOD_NewListLock() +{ #ifdef PKCS11_USE_THREADS - modLock->mutex = NULL; - modLock->monitor = PZ_NewMonitor(nssILockList); + return (SECMODListLock *) NSSRWLock_New( 10, "moduleListLock"); #else - modLock->mutex = NULL; - modLock->monitor = NULL; + return (SECMODListLock *) 1; #endif - modLock->state = 0; - modLock->count = 0; - return modLock; } /* * destroy the lock */ -void SECMOD_DestroyListLock(SECMODListLock *lock) { - PK11_USE_THREADS(PZ_DestroyMonitor(lock->monitor);) - PORT_Free(lock); +void SECMOD_DestroyListLock(SECMODListLock *lock) +{ + PK11_USE_THREADS(NSSRWLock_Destroy((NSSRWLock *)lock);) } @@ -81,52 +70,26 @@ void SECMOD_DestroyListLock(SECMODListLock *lock) { * Lock the List for Read: NOTE: this assumes the reading isn't so common * the writing will be starved. */ -void SECMOD_GetReadLock(SECMODListLock *modLock) { -#ifdef PKCS11_USE_THREADS - if (modLock == NULL) return; - PZ_EnterMonitor(modLock->monitor); - while (modLock->state & ISWRITING) { - PZ_Wait(modLock->monitor,PR_INTERVAL_NO_TIMEOUT); /* wait until woken up */ - } - modLock->state |= ISREADING; - modLock->count++; - PZ_ExitMonitor(modLock->monitor); -#endif +void SECMOD_GetReadLock(SECMODListLock *modLock) +{ + PK11_USE_THREADS(NSSRWLock_LockRead((NSSRWLock *)modLock);) } /* * Release the Read lock */ -void SECMOD_ReleaseReadLock(SECMODListLock *modLock) { -#ifdef PKCS11_USE_THREADS - if (modLock == NULL) return; - PZ_EnterMonitor(modLock->monitor); - modLock->count--; - if (modLock->count == 0) { - modLock->state &= ~ISREADING; - if (modLock->state & WANTWRITE) { - PZ_Notify(modLock->monitor); /* only one writer at a time */ - } - } - PZ_ExitMonitor(modLock->monitor); -#endif +void SECMOD_ReleaseReadLock(SECMODListLock *modLock) +{ + PK11_USE_THREADS(NSSRWLock_UnlockRead((NSSRWLock *)modLock);) } /* * lock the list for Write */ -void SECMOD_GetWriteLock(SECMODListLock *modLock) { -#ifdef PKCS11_USE_THREADS - if (modLock == NULL) return; - PZ_EnterMonitor(modLock->monitor); - while (modLock->state & ISLOCKED) { - modLock->state |= WANTWRITE; - PZ_Wait(modLock->monitor,PR_INTERVAL_NO_TIMEOUT); /* wait until woken up */ - } - modLock->state = ISWRITING; - PZ_ExitMonitor(modLock->monitor); -#endif +void SECMOD_GetWriteLock(SECMODListLock *modLock) +{ + PK11_USE_THREADS(NSSRWLock_LockWrite((NSSRWLock *)modLock);) } @@ -134,14 +97,9 @@ void SECMOD_GetWriteLock(SECMODListLock *modLock) { * Release the Write Lock: NOTE, this code is pretty inefficient if you have * lots of write collisions. */ -void SECMOD_ReleaseWriteLock(SECMODListLock *modLock) { -#ifdef PKCS11_USE_THREADS - if (modLock == NULL) return; - PZ_EnterMonitor(modLock->monitor); - modLock->state = 0; - PR_NotifyAll(modLock->monitor); /* enable all the readers */ - PZ_ExitMonitor(modLock->monitor); -#endif +void SECMOD_ReleaseWriteLock(SECMODListLock *modLock) +{ + PK11_USE_THREADS(NSSRWLock_UnlockWrite((NSSRWLock *)modLock);) } @@ -149,7 +107,8 @@ void SECMOD_ReleaseWriteLock(SECMODListLock *modLock) { * must Hold the Write lock */ void -SECMOD_RemoveList(SECMODModuleList **parent, SECMODModuleList *child) { +SECMOD_RemoveList(SECMODModuleList **parent, SECMODModuleList *child) +{ *parent = child->next; child->next = NULL; } @@ -159,7 +118,8 @@ SECMOD_RemoveList(SECMODModuleList **parent, SECMODModuleList *child) { */ void SECMOD_AddList(SECMODModuleList *parent, SECMODModuleList *child, - SECMODListLock *lock) { + SECMODListLock *lock) +{ if (lock) { SECMOD_GetWriteLock(lock); } child->next = parent->next; diff --git a/security/nss/lib/pk11wrap/pk11load.c b/security/nss/lib/pk11wrap/pk11load.c index 602047c4f..a94e6cbf0 100644 --- a/security/nss/lib/pk11wrap/pk11load.c +++ b/security/nss/lib/pk11wrap/pk11load.c @@ -90,6 +90,41 @@ static const CK_C_INITIALIZE_ARGS secmodLockFunctions = { ,NULL }; +/* + * collect the steps we need to initialize a module in a single function + */ +SECStatus +secmod_ModuleInit(SECMODModule *mod) +{ + CK_C_INITIALIZE_ARGS moduleArgs; + CK_VOID_PTR pInitArgs; + CK_RV crv; + + if (mod->isThreadSafe == PR_FALSE) { + pInitArgs = NULL; + } else if (mod->libraryParams == NULL) { + pInitArgs = (void *) &secmodLockFunctions; + } else { + moduleArgs = secmodLockFunctions; + moduleArgs.LibraryParameters = (void *) mod->libraryParams; + pInitArgs = &moduleArgs; + } + crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs); + if (crv != CKR_OK) { + if (pInitArgs == NULL) { + PORT_SetError(PK11_MapError(crv)); + return SECFailure; + } + mod->isThreadSafe = PR_FALSE; + crv = PK11_GETTAB(mod)->C_Initialize(NULL); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + return SECFailure; + } + } + return SECSuccess; +} + /* * set the hasRootCerts flags in the module so it can be stored back * into the database. @@ -142,8 +177,7 @@ SECMOD_LoadPKCS11Module(SECMODModule *mod) { char * full_name; CK_INFO info; CK_ULONG slotCount = 0; - CK_C_INITIALIZE_ARGS moduleArgs; - CK_VOID_PTR pInitArgs; + SECStatus rv; if (mod->loaded) return SECSuccess; @@ -228,17 +262,11 @@ SECMOD_LoadPKCS11Module(SECMODModule *mod) { #endif mod->isThreadSafe = PR_TRUE; + /* Now we initialize the module */ - if (mod->libraryParams) { - moduleArgs = secmodLockFunctions; - moduleArgs.LibraryParameters = (void *) mod->libraryParams; - pInitArgs = &moduleArgs; - } else { - pInitArgs = (void *) &secmodLockFunctions; - } - if (PK11_GETTAB(mod)->C_Initialize(pInitArgs) != CKR_OK) { - mod->isThreadSafe = PR_FALSE; - if (PK11_GETTAB(mod)->C_Initialize(NULL) != CKR_OK) goto fail; + rv = secmod_ModuleInit(mod); + if (rv != SECSuccess) { + goto fail; } /* check the version number */ @@ -260,7 +288,7 @@ SECMOD_LoadPKCS11Module(SECMODModule *mod) { if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) { CK_SLOT_ID *slotIDs; int i; - CK_RV rv; + CK_RV crv; mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena, sizeof(PK11SlotInfo *) * slotCount); @@ -270,8 +298,8 @@ SECMOD_LoadPKCS11Module(SECMODModule *mod) { if (slotIDs == NULL) { goto fail2; } - rv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount); - if (rv != CKR_OK) { + crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount); + if (crv != CKR_OK) { PORT_Free(slotIDs); goto fail2; } diff --git a/security/nss/lib/pk11wrap/pk11pars.c b/security/nss/lib/pk11wrap/pk11pars.c index 28a1b45cb..9797d6084 100644 --- a/security/nss/lib/pk11wrap/pk11pars.c +++ b/security/nss/lib/pk11wrap/pk11pars.c @@ -97,6 +97,7 @@ secmod_NewModule(void) newMod->moduleDBOnly = PR_FALSE; newMod->trustOrder = 0; newMod->cipherOrder = 0; + newMod->evControlMask = 0; #ifdef PKCS11_USE_THREADS newMod->refLock = (void *)PZ_NewLock(nssILockRefLock); if (newMod->refLock == NULL) { @@ -163,9 +164,12 @@ pk11_mkModuleSpec(SECMODModule * module) { char *nss = NULL, *modSpec = NULL, **slotStrings = NULL; int slotCount, i, si; + SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); /* allocate target slot info strings */ slotCount = 0; + + SECMOD_GetReadLock(moduleLock); if (module->slotCount) { for (i=0; i < module->slotCount; i++) { if (module->slots[i]->defaultFlags !=0) { @@ -178,6 +182,7 @@ pk11_mkModuleSpec(SECMODModule * module) slotStrings = (char **)PORT_ZAlloc(slotCount*sizeof(char *)); if (slotStrings == NULL) { + SECMOD_ReleaseReadLock(moduleLock); goto loser; } @@ -208,6 +213,7 @@ pk11_mkModuleSpec(SECMODModule * module) } } + SECMOD_ReleaseReadLock(moduleLock); nss = pk11_mkNSS(slotStrings,slotCount,module->internal, module->isFIPS, module->isModuleDB, module->moduleDBOnly, module->isCritical, module->trustOrder,module->cipherOrder,module->ssl[0],module->ssl[1]); @@ -386,8 +392,12 @@ SECMOD_LoadUserModule(char *modulespec,SECMODModule *parent, PRBool recurse) { SECStatus rv = SECSuccess; SECMODModule * newmod = SECMOD_LoadModule(modulespec, parent, recurse); + SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); + if (newmod) { + SECMOD_GetReadLock(moduleLock); rv = STAN_AddModuleToDefaultTrustDomain(newmod); + SECMOD_ReleaseReadLock(moduleLock); if (SECSuccess != rv) { SECMOD_DestroyModule(newmod); return NULL; @@ -404,10 +414,14 @@ SECStatus SECMOD_UnloadUserModule(SECMODModule *mod) { SECStatus rv = SECSuccess; int atype = 0; + SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); if (!mod) { return SECFailure; } + + SECMOD_GetReadLock(moduleLock); rv = STAN_RemoveModuleFromDefaultTrustDomain(mod); + SECMOD_ReleaseReadLock(moduleLock); if (SECSuccess != rv) { return SECFailure; } diff --git a/security/nss/lib/pk11wrap/pk11util.c b/security/nss/lib/pk11wrap/pk11util.c index 5b40d5692..0ae6b83e5 100644 --- a/security/nss/lib/pk11wrap/pk11util.c +++ b/security/nss/lib/pk11wrap/pk11util.c @@ -62,7 +62,8 @@ extern int num_pk11_default_mechanisms; void -SECMOD_Init() { +SECMOD_Init() +{ /* don't initialize twice */ if (moduleLock) return; @@ -72,7 +73,8 @@ SECMOD_Init() { SECStatus -SECMOD_Shutdown() { +SECMOD_Shutdown() +{ /* destroy the lock */ if (moduleLock) { SECMOD_DestroyListLock(moduleLock); @@ -128,13 +130,15 @@ SECMOD_Shutdown() { * retrieve the internal module */ SECMODModule * -SECMOD_GetInternalModule(void) { +SECMOD_GetInternalModule(void) +{ return internalModule; } SECStatus -secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule) { +secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule) +{ SECMODModuleList *mlp, *newListElement, *last = NULL; newListElement = SECMOD_NewModuleListElement(); @@ -162,7 +166,8 @@ secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule) { } SECStatus -SECMOD_AddModuleToList(SECMODModule *newModule) { +SECMOD_AddModuleToList(SECMODModule *newModule) +{ if (newModule->internal && !internalModule) { internalModule = SECMOD_ReferenceModule(newModule); } @@ -170,7 +175,8 @@ SECMOD_AddModuleToList(SECMODModule *newModule) { } SECStatus -SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule) { +SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule) +{ if (defaultDBModule == NULL) { defaultDBModule = SECMOD_ReferenceModule(newModule); } @@ -178,16 +184,29 @@ SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule) { } SECStatus -SECMOD_AddModuleToUnloadList(SECMODModule *newModule) { +SECMOD_AddModuleToUnloadList(SECMODModule *newModule) +{ return secmod_AddModuleToList(&modulesUnload,newModule); } /* * get the list of PKCS11 modules that are available. */ -SECMODModuleList *SECMOD_GetDefaultModuleList() { return modules; } +SECMODModuleList * SECMOD_GetDefaultModuleList() { return modules; } SECMODModuleList *SECMOD_GetDeadModuleList() { return modulesUnload; } SECMODModuleList *SECMOD_GetDBModuleList() { return modulesDB; } + +/* + * This lock protects the global module lists. + * it also protects changes to the slot array (module->slots[]) and slot count + * (module->slotCount) in each module. It is a read/write lock with multiple + * readers or one writer. Writes are uncommon. + * Because of legacy considerations protection of the slot array and count is + * only necessary in applications if the application calls + * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new + * applications are encouraged to acquire this lock when reading the + * slot array information directly. + */ SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; } @@ -196,7 +215,9 @@ SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; } * find a module by name, and add a reference to it. * return that module. */ -SECMODModule *SECMOD_FindModule(const char *name) { +SECMODModule * +SECMOD_FindModule(const char *name) +{ SECMODModuleList *mlp; SECMODModule *module = NULL; @@ -229,7 +250,9 @@ found: * find a module by ID, and add a reference to it. * return that module. */ -SECMODModule *SECMOD_FindModuleByID(SECMODModuleID id) { +SECMODModule * +SECMOD_FindModuleByID(SECMODModuleID id) +{ SECMODModuleList *mlp; SECMODModule *module = NULL; @@ -242,30 +265,53 @@ SECMODModule *SECMOD_FindModuleByID(SECMODModuleID id) { } } SECMOD_ReleaseReadLock(moduleLock); - + if (module == NULL) { + PORT_SetError(SEC_ERROR_NO_MODULE); + } return module; } /* - * lookup the Slot module based on it's module ID and slot ID. + * Find the Slot based on ID and the module. */ -PK11SlotInfo *SECMOD_LookupSlot(SECMODModuleID moduleID,CK_SLOT_ID slotID) { +PK11SlotInfo * +SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID) +{ int i; - SECMODModule *module; - - module = SECMOD_FindModuleByID(moduleID); - if (module == NULL) return NULL; + PK11SlotInfo *slot = NULL; + SECMOD_GetReadLock(moduleLock); for (i=0; i < module->slotCount; i++) { - PK11SlotInfo *slot = module->slots[i]; + PK11SlotInfo *cSlot = module->slots[i]; - if (slot->slotID == slotID) { - SECMOD_DestroyModule(module); - return PK11_ReferenceSlot(slot); + if (cSlot->slotID == slotID) { + slot = PK11_ReferenceSlot(cSlot); + break; } } + SECMOD_ReleaseReadLock(moduleLock); + + if (slot == NULL) { + PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); + } + return slot; +} + +/* + * lookup the Slot module based on it's module ID and slot ID. + */ +PK11SlotInfo * +SECMOD_LookupSlot(SECMODModuleID moduleID,CK_SLOT_ID slotID) +{ + SECMODModule *module; + PK11SlotInfo *slot; + + module = SECMOD_FindModuleByID(moduleID); + if (module == NULL) return NULL; + + slot = SECMOD_FindSlotByID(module, slotID); SECMOD_DestroyModule(module); - return NULL; + return slot; } @@ -338,7 +384,8 @@ found: * find a module by name and delete it off the module list */ SECStatus -SECMOD_DeleteModule(const char *name, int *type) { +SECMOD_DeleteModule(const char *name, int *type) +{ return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE); } @@ -346,7 +393,8 @@ SECMOD_DeleteModule(const char *name, int *type) { * find a module by name and delete it off the module list */ SECStatus -SECMOD_DeleteInternalModule(const char *name) { +SECMOD_DeleteInternalModule(const char *name) +{ SECMODModuleList *mlp; SECMODModuleList **mlpp; SECStatus rv = SECFailure; @@ -418,7 +466,8 @@ SECMOD_DeleteInternalModule(const char *name) { } SECStatus -SECMOD_AddModule(SECMODModule *newModule) { +SECMOD_AddModule(SECMODModule *newModule) +{ SECStatus rv; SECMODModule *oldModule; @@ -450,10 +499,14 @@ SECMOD_AddModule(SECMODModule *newModule) { return rv; } -PK11SlotInfo *SECMOD_FindSlot(SECMODModule *module,const char *name) { +PK11SlotInfo * +SECMOD_FindSlot(SECMODModule *module,const char *name) +{ int i; char *string; + PK11SlotInfo *retSlot = NULL; + SECMOD_GetReadLock(moduleLock); for (i=0; i < module->slotCount; i++) { PK11SlotInfo *slot = module->slots[i]; @@ -463,10 +516,17 @@ PK11SlotInfo *SECMOD_FindSlot(SECMODModule *module,const char *name) { string = PK11_GetSlotName(slot); } if (PORT_Strcmp(name,string) == 0) { - return PK11_ReferenceSlot(slot); + retSlot = PK11_ReferenceSlot(slot); + break; } } + SECMOD_ReleaseReadLock(moduleLock); + + if (retSlot == NULL) { + PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); + } return NULL; + return retSlot; } SECStatus @@ -501,11 +561,12 @@ PK11_IsFIPS(void) /* combines NewModule() & AddModule */ /* give a string for the module name & the full-path for the dll, */ /* installs the PKCS11 module & update registry */ -SECStatus SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath, +SECStatus +SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath, unsigned long defaultMechanismFlags, unsigned long cipherEnableFlags, - char* modparms, - char* nssparms) { + char* modparms, char* nssparms) +{ SECMODModule *module; SECStatus result = SECFailure; int s,i; @@ -526,26 +587,28 @@ SECStatus SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath, /* turn on SSL cipher enable flags */ module->ssl[0] = cipherEnableFlags; + SECMOD_GetReadLock(moduleLock); /* check each slot to turn on appropriate mechanisms */ for (s = 0; s < module->slotCount; s++) { slot = (module->slots)[s]; /* for each possible mechanism */ for (i=0; i < num_pk11_default_mechanisms; i++) { /* we are told to turn it on by default ? */ - if (PK11_DefaultArray[i].flag & defaultMechanismFlags) { - /* it ignores if slot attribute update failes */ - result = PK11_UpdateSlotAttribute(slot, &(PK11_DefaultArray[i]), PR_TRUE); - } else { /* turn this mechanism of the slot off by default */ - result = PK11_UpdateSlotAttribute(slot, &(PK11_DefaultArray[i]), PR_FALSE); - } + PRBool add = + (PK11_DefaultArray[i].flag & defaultMechanismFlags) ? + PR_TRUE: PR_FALSE; + result = PK11_UpdateSlotAttribute(slot, + &(PK11_DefaultArray[i]), add); } /* for each mechanism */ /* disable each slot if the defaultFlags say so */ if (defaultMechanismFlags & PK11_DISABLE_FLAG) { PK11_UserDisableSlot(slot); } } /* for each slot of this module */ + SECMOD_ReleaseReadLock(moduleLock); - /* delete and re-add module in order to save changes to the module */ + /* delete and re-add module in order to save changes + * to the module */ result = SECMOD_UpdateModule(module); } } @@ -554,7 +617,8 @@ SECStatus SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath, return result; } -SECStatus SECMOD_AddNewModule(const char* moduleName, const char* dllPath, +SECStatus +SECMOD_AddNewModule(const char* moduleName, const char* dllPath, unsigned long defaultMechanismFlags, unsigned long cipherEnableFlags) { @@ -563,7 +627,8 @@ SECStatus SECMOD_AddNewModule(const char* moduleName, const char* dllPath, NULL, NULL); /* don't pass module or nss params */ } -SECStatus SECMOD_UpdateModule(SECMODModule *module) +SECStatus +SECMOD_UpdateModule(SECMODModule *module) { SECStatus result; @@ -582,7 +647,9 @@ SECStatus SECMOD_UpdateModule(SECMODModule *module) * puts RANDOM_FLAG at bit 31 (Most-significant bit), but * public representation puts this bit at bit 28 */ -unsigned long SECMOD_PubMechFlagstoInternal(unsigned long publicFlags) { +unsigned long +SECMOD_PubMechFlagstoInternal(unsigned long publicFlags) +{ unsigned long internalFlags = publicFlags; if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) { @@ -592,7 +659,9 @@ unsigned long SECMOD_PubMechFlagstoInternal(unsigned long publicFlags) { return internalFlags; } -unsigned long SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) { +unsigned long +SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) +{ unsigned long publicFlags = internalFlags; if (internalFlags & SECMOD_RANDOM_FLAG) { @@ -606,11 +675,15 @@ unsigned long SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) { /* Public & Internal(Security Library) representation of */ /* cipher flags conversion */ /* Note: currently they are just stubs */ -unsigned long SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) { +unsigned long +SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) +{ return publicFlags; } -unsigned long SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) { +unsigned long +SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) +{ return internalFlags; } @@ -624,7 +697,8 @@ SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ) for ( ; mods != NULL; mods = mods->next) { - if (mods->module->ssl[0] & SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) { + if (mods->module->ssl[0] & + SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) { result = PR_TRUE; } } @@ -634,7 +708,8 @@ SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ) } /* create a new ModuleListElement */ -SECMODModuleList *SECMOD_NewModuleListElement(void) { +SECMODModuleList *SECMOD_NewModuleListElement(void) +{ SECMODModuleList *newModList; newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList)); @@ -644,11 +719,13 @@ SECMODModuleList *SECMOD_NewModuleListElement(void) { } return newModList; } + /* * make a new reference to a module so It doesn't go away on us */ SECMODModule * -SECMOD_ReferenceModule(SECMODModule *module) { +SECMOD_ReferenceModule(SECMODModule *module) +{ PK11_USE_THREADS(PZ_Lock((PZLock *)module->refLock);) PORT_Assert(module->refCount > 0); @@ -660,7 +737,8 @@ SECMOD_ReferenceModule(SECMODModule *module) { /* destroy an existing module */ void -SECMOD_DestroyModule(SECMODModule *module) { +SECMOD_DestroyModule(SECMODModule *module) +{ PRBool willfree = PR_FALSE; int slotCount; int i; @@ -707,7 +785,8 @@ SECMOD_DestroyModule(SECMODModule *module) { /* we can only get here if we've destroyed the module, or some one has * erroneously freed a slot that wasn't referenced. */ void -SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) { +SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) +{ PRBool willfree = PR_FALSE; if (fromSlot) { PORT_Assert(module->refCount == 0); @@ -737,7 +816,8 @@ SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) { * on the chain. It makes it easy to implement for loops to delete * the chain. It also make deleting a single element easy */ SECMODModuleList * -SECMOD_DestroyModuleListElement(SECMODModuleList *element) { +SECMOD_DestroyModuleListElement(SECMODModuleList *element) +{ SECMODModuleList *next = element->next; if (element->module) { @@ -753,7 +833,8 @@ SECMOD_DestroyModuleListElement(SECMODModuleList *element) { * Destroy an entire module list */ void -SECMOD_DestroyModuleList(SECMODModuleList *list) { +SECMOD_DestroyModuleList(SECMODModuleList *list) +{ SECMODModuleList *lp; for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ; @@ -764,3 +845,330 @@ SECMOD_CanDeleteInternalModule(void) { return (PRBool) (pendingModule == NULL); } + +/* + * check to see if the module has added new slots. PKCS 11 v2.20 allows for + * modules to add new slots, but never remove them. Slots cannot be added + * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent + * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently + * grow on the caller. It is permissible for the slots to increase between + * successive calls with NULL to get the size. + */ +SECStatus +SECMOD_UpdateSlotList(SECMODModule *mod) +{ + CK_RV crv; + int count,i, oldCount; + PRBool freeRef = PR_FALSE; + void *mark; + CK_ULONG *slotIDs = NULL; + PK11SlotInfo **newSlots = NULL; + PK11SlotInfo **oldSlots = NULL; + + /* C_GetSlotList is not a session function, make sure + * calls are serialized */ + PZ_Lock(mod->refLock); + freeRef = PR_TRUE; + /* see if the number of slots have changed */ + crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + goto loser; + } + /* nothing new, blow out early, we want this function to be quick + * and cheap in the normal case */ + if (count == mod->slotCount) { + PZ_Unlock(mod->refLock); + return SECSuccess; + } + if (count < mod->slotCount) { + /* shouldn't happen with a properly functioning PKCS #11 module */ + PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); + goto loser; + } + + /* get the new slot list */ + slotIDs = PORT_NewArray(CK_SLOT_ID, count); + if (slotIDs == NULL) { + goto loser; + } + + crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + goto loser; + } + freeRef = PR_FALSE; + PZ_Unlock(mod->refLock); + mark = PORT_ArenaMark(mod->arena); + if (mark == NULL) { + goto loser; + } + newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); + + /* walk down the new slot ID list returned from the module. We keep + * the old slots which match a returned ID, and we initialize the new + * slots. */ + for (i=0; i < count; i++) { + PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); + + if (!slot) { + /* we have a new slot create a new slot data structure */ + slot = PK11_NewSlotInfo(mod); + if (!slot) { + goto loser; + } + PK11_InitSlot(mod, slotIDs[i], slot); + STAN_InitTokenForSlotInfo(NULL, slot); + } + newSlots[i] = slot; + } + STAN_ResetTokenInterator(NULL); + PORT_Free(slotIDs); + slotIDs = NULL; + PORT_ArenaUnmark(mod->arena, mark); + + /* until this point we're still using the old slot list. Now we update + * module slot list. We update the slots (array) first then the count, + * since we've already guarrenteed that count has increased (just in case + * someone is looking at the slots field of module without holding the + * moduleLock */ + SECMOD_GetWriteLock(moduleLock); + oldCount =mod->slotCount; + oldSlots = mod->slots; + mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is + * allocated out of the module arena and won't + * be freed until the module is freed */ + mod->slotCount = count; + SECMOD_ReleaseWriteLock(moduleLock); + /* free our old references before forgetting about oldSlot*/ + for (i=0; i < oldCount; i++) { + PK11_FreeSlot(oldSlots[i]); + } + return SECSuccess; + +loser: + if (freeRef) { + PZ_Unlock(mod->refLock); + } + if (slotIDs) { + PORT_Free(slotIDs); + } + /* free all the slots we allocated. newSlots are part of the + * mod arena. NOTE: the newSlots array contain both new and old + * slots, but we kept a reference to the old slots when we built the new + * array, so we need to free all the slots in newSlots array. */ + if (newSlots) { + for (i=0; i < count; i++) { + if (newSlots[i] == NULL) { + break; /* hit the last one */ + } + PK11_FreeSlot(newSlots[i]); + } + } + /* must come after freeing newSlots */ + if (mark) { + PORT_ArenaRelease(mod->arena, mark); + } + return SECFailure; +} + +/* + * this handles modules that do not support C_WaitForSlotEvent(). + * The internal flags are stored. Note that C_WaitForSlotEvent() does not + * have a timeout, so we don't have one for handleWaitForSlotEvent() either. + */ +PK11SlotInfo * +secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags, + PRIntervalTime latency) +{ + PRBool removableSlotsFound = PR_FALSE; + int i; + int error = SEC_ERROR_NO_EVENT; + + PZ_Lock(mod->refLock); + if (mod->evControlMask & SECMOD_END_WAIT) { + mod->evControlMask &= ~SECMOD_END_WAIT; + PZ_Unlock(mod->refLock); + PORT_SetError(SEC_ERROR_NO_EVENT); + return NULL; + } + mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT; + while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) { + PZ_Unlock(mod->refLock); + /* now is a good time to see if new slots have been added */ + SECMOD_UpdateSlotList(mod); + + /* loop through all the slots on a module */ + SECMOD_GetReadLock(moduleLock); + for (i=0; i < mod->slotCount; i++) { + PK11SlotInfo *slot = mod->slots[i]; + uint16 series; + PRBool present; + + /* perm modules do not change */ + if (slot->isPerm) { + continue; + } + removableSlotsFound = PR_TRUE; + /* simulate the PKCS #11 module flags. are the flags different + * from the last time we called? */ + series = slot->series; + present = PK11_IsPresent(slot); + if ((slot->flagSeries != series) || (slot->flagState != present)) { + slot->flagState = present; + slot->flagSeries = series; + SECMOD_ReleaseReadLock(moduleLock); + PZ_Lock(mod->refLock); + mod->evControlMask &= ~SECMOD_END_WAIT; + PZ_Unlock(mod->refLock); + return PK11_ReferenceSlot(slot); + } + } + SECMOD_ReleaseReadLock(moduleLock); + /* if everything was perm modules, don't lock up forever */ + if (!removableSlotsFound) { + error =SEC_ERROR_NO_SLOT_SELECTED; + PZ_Lock(mod->refLock); + break; + } + if (flags & CKF_DONT_BLOCK) { + PZ_Lock(mod->refLock); + break; + } + PR_Sleep(latency); + PZ_Lock(mod->refLock); + } + mod->evControlMask &= ~SECMOD_END_WAIT; + PZ_Unlock(mod->refLock); + PORT_SetError(error); + return NULL; +} + +/* + * this function waits for a token event on any slot of a given module + * This function should not be called from more than one thread of the + * same process (though other threads can make other library calls + * on this module while this call is blocked). + */ +PK11SlotInfo * +SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, + PRIntervalTime latency) +{ + CK_SLOT_ID id; + CK_RV crv; + PK11SlotInfo *slot; + + /* first the the PKCS #11 call */ + PZ_Lock(mod->refLock); + if (mod->evControlMask & SECMOD_END_WAIT) { + goto end_wait; + } + mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT; + PZ_Unlock(mod->refLock); + crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL); + PZ_Lock(mod->refLock); + mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT; + /* if we are in end wait, short circuit now, don't even risk + * going into secmod_HandleWaitForSlotEvent */ + if (mod->evControlMask & SECMOD_END_WAIT) { + goto end_wait; + } + PZ_Unlock(mod->refLock); + if (crv == CKR_FUNCTION_NOT_SUPPORTED) { + /* module doesn't support that call, simulate it */ + return secmod_HandleWaitForSlotEvent(mod, flags, latency); + } + if (crv != CKR_OK) { + /* we can get this error if finalize was called while we were + * still running. This is the only way to force a C_WaitForSlotEvent() + * to return in PKCS #11. In this case, just return that there + * was no event. */ + if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) { + PORT_SetError(SEC_ERROR_NO_EVENT); + } else { + PORT_SetError(PK11_MapError(crv)); + } + return NULL; + } + slot = SECMOD_FindSlotByID(mod, id); + if (slot == NULL) { + /* possibly a new slot that was added? */ + SECMOD_UpdateSlotList(mod); + slot = SECMOD_FindSlotByID(mod, id); + } + return slot; + + /* must be called with the lock on. */ +end_wait: + mod->evControlMask &= ~SECMOD_END_WAIT; + PZ_Unlock(mod->refLock); + PORT_SetError(SEC_ERROR_NO_EVENT); + return NULL; +} + +/* + * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic + * function, possibly bringing down the pkcs #11 module in question. This + * should be OK because 1) it does reinitialize, and 2) it should only be + * called when we are on our way to tear the whole system down anyway. + */ +SECStatus +SECMOD_CancelWait(SECMODModule *mod) +{ + unsigned long controlMask = mod->evControlMask; + SECStatus rv = SECSuccess; + CK_RV crv; + + PZ_Lock(mod->refLock); + mod->evControlMask |= SECMOD_END_WAIT; + controlMask = mod->evControlMask; + if (controlMask & SECMOD_WAIT_PKCS11_EVENT) { + /* NOTE: this call will drop all transient keys, in progress + * operations, and any authentication. This is the only documented + * way to get WaitForSlotEvent to return. Also note: for non-thread + * safe tokens, we need to hold the module lock, this is not yet at + * system shutdown/starup time, so we need to protect these calls */ + crv = PK11_GETTAB(mod)->C_Finalize(NULL); + /* ok, we slammed the module down, now we need to reinit it in case + * we intend to use it again */ + if (crv = CKR_OK) { + secmod_ModuleInit(mod); + } else { + /* Finalized failed for some reason, notify the application + * so maybe it has a prayer of recovering... */ + PORT_SetError(PK11_MapError(crv)); + rv = SECFailure; + } + } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) { + mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT; + /* Simulated events will eventually timeout + * and wake up in the loop */ + } + PZ_Unlock(mod->refLock); + return rv; +} + +/* + * check to see if the module has removable slots that we may need to + * watch for. + */ +PRBool +SECMOD_HasRemovableSlots(SECMODModule *mod) +{ + int i; + PRBool ret = PR_FALSE; + + SECMOD_GetReadLock(moduleLock); + for (i=0; i < mod->slotCount; i++) { + PK11SlotInfo *slot = mod->slots[i]; + /* perm modules are not inserted or removed */ + if (slot->isPerm) { + continue; + } + ret = PR_TRUE; + break; + } + SECMOD_ReleaseReadLock(moduleLock); + return ret; +} diff --git a/security/nss/lib/pk11wrap/secmod.h b/security/nss/lib/pk11wrap/secmod.h index 82ba316a4..18b737772 100644 --- a/security/nss/lib/pk11wrap/secmod.h +++ b/security/nss/lib/pk11wrap/secmod.h @@ -37,6 +37,7 @@ #define _SEDMOD_H_ #include "seccomon.h" #include "secmodt.h" +#include "prinrval.h" #define PKCS11_USE_THREADS @@ -148,6 +149,25 @@ PRBool SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ); extern unsigned long SECMOD_PubMechFlagstoInternal(unsigned long publicFlags); extern unsigned long SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags); +PRBool SECMOD_HasRemovableSlots(SECMODModule *mod); +PK11SlotInfo *SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, + unsigned long flags, PRIntervalTime latency); +/* + * Warning: the SECMOD_CancelWait function is highly destructive, potentially + * finalizing the module 'mod' (causing inprogress operations to fail, + * and session key material to disappear). It should only be called when + * shutting down the module. + */ +SECStatus SECMOD_CancelWait(SECMODModule *mod); +/* + * check to see if the module has added new slots. PKCS 11 v2.20 allows for + * modules to add new slots, but never remove them. Slots not be added between + * a call to C_GetSlotLlist(Flag, NULL, &count) and the corresponding + * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently + * grow on the caller. It is permissible for the slots to increase between + * corresponding calls with NULL to get the size. + */ +SECStatus SECMOD_UpdateSlotList(SECMODModule *mod); SEC_END_PROTOS #endif diff --git a/security/nss/lib/pk11wrap/secmodi.h b/security/nss/lib/pk11wrap/secmodi.h index 352f214a4..8dda6467f 100644 --- a/security/nss/lib/pk11wrap/secmodi.h +++ b/security/nss/lib/pk11wrap/secmodi.h @@ -65,6 +65,7 @@ void nss_DumpModuleLog(void); extern int secmod_PrivateModuleCount; extern void SECMOD_Init(void); +SECStatus secmod_ModuleInit(SECMODModule *mod); /* list managment */ extern SECStatus SECMOD_AddModuleToList(SECMODModule *newModule); diff --git a/security/nss/lib/pk11wrap/secmodt.h b/security/nss/lib/pk11wrap/secmodt.h index 987bb4582..a2c032ba4 100644 --- a/security/nss/lib/pk11wrap/secmodt.h +++ b/security/nss/lib/pk11wrap/secmodt.h @@ -93,8 +93,26 @@ struct SECMODModuleStr { PRBool moduleDBOnly; /* this module only has lists of PKCS #11 modules */ int trustOrder; /* order for this module's certificate trust rollup */ int cipherOrder; /* order for cipher operations */ + unsigned long evControlMask; /* control the running and shutdown of slot + * events (SECMOD_WaitForAnyTokenEvent) */ }; +/* evControlMask flags */ +/* + * These bits tell the current state of a SECMOD_WaitForAnyTokenEvent. + * + * SECMOD_WAIT_PKCS11_EVENT - we're waiting in the PKCS #11 module in + * C_WaitForSlotEvent(). + * SECMOD_WAIT_SIMULATED_EVENT - we're waiting in the NSS simulation code + * which polls for token insertion and removal events. + * SECMOD_END_WAIT - SECMOD_CancelWait has been called while the module is + * waiting in SECMOD_WaitForAnyTokenEvent. SECMOD_WaitForAnyTokenEvent + * should return immediately to it's caller. + */ +#define SECMOD_END_WAIT 0x01 +#define SECMOD_WAIT_SIMULATED_EVENT 0x02 +#define SECMOD_WAIT_PKCS11_EVENT 0x04 + struct SECMODModuleListStr { SECMODModuleList *next; SECMODModule *module; diff --git a/security/nss/lib/pk11wrap/secmodti.h b/security/nss/lib/pk11wrap/secmodti.h index 156d23338..679e2f51d 100644 --- a/security/nss/lib/pk11wrap/secmodti.h +++ b/security/nss/lib/pk11wrap/secmodti.h @@ -122,6 +122,10 @@ struct PK11SlotInfoStr { uint16 series; /* break up the slot info into various groups of * inserted tokens so that keys and certs can be * invalidated */ + uint16 flagSeries; /* record the last series for the last event + * returned for this slot */ + PRBool flagState; /* record the state of the last event returned for this + * slot. */ uint16 wrapKey; /* current wrapping key for SSL master secrets */ CK_MECHANISM_TYPE wrapMechanism; /* current wrapping mechanism for current wrapKey */ diff --git a/security/nss/lib/pki/pki3hack.c b/security/nss/lib/pki/pki3hack.c index 1ea7e2167..231bc0bee 100644 --- a/security/nss/lib/pki/pki3hack.c +++ b/security/nss/lib/pki/pki3hack.c @@ -93,13 +93,40 @@ STAN_GetDefaultCryptoContext() extern const NSSError NSS_ERROR_ALREADY_INITIALIZED; extern const NSSError NSS_ERROR_INTERNAL_ERROR; +NSS_IMPLEMENT PRStatus +STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot) +{ + NSSToken *token; + if (!td) { + td = g_default_trust_domain; + } + token = nssToken_CreateFromPK11SlotInfo(td, slot); + PK11Slot_SetNSSToken(slot, token); + NSSRWLock_LockWrite(td->tokensLock); + nssList_Add(td->tokenList, token); + NSSRWLock_UnlockWrite(td->tokensLock); + return PR_SUCCESS; +} + +NSS_IMPLEMENT PRStatus +STAN_ResetTokenInterator(NSSTrustDomain *td) +{ + if (!td) { + td = g_default_trust_domain; + } + NSSRWLock_LockWrite(td->tokensLock); + nssListIterator_Destroy(td->tokens); + td->tokens = nssList_CreateIterator(td->tokenList); + NSSRWLock_UnlockWrite(td->tokensLock); + return PR_SUCCESS; +} + NSS_IMPLEMENT PRStatus STAN_LoadDefaultNSS3TrustDomain ( void ) { NSSTrustDomain *td; - NSSToken *token; SECMODModuleList *mlp; SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); int i; @@ -113,41 +140,48 @@ STAN_LoadDefaultNSS3TrustDomain ( if (!td) { return PR_FAILURE; } - td->tokenList = nssList_Create(td->arena, PR_TRUE); + /* + * Deadlock warning: we should never acquire the moduleLock while + * we hold the tokensLock. We can use the NSSRWLock Rank feature to + * guarrentee this. tokensLock have a higher rank than module lock. + */ SECMOD_GetReadLock(moduleLock); + NSSRWLock_LockWrite(td->tokensLock); + td->tokenList = nssList_Create(td->arena, PR_TRUE); for (mlp = SECMOD_GetDefaultModuleList(); mlp != NULL; mlp=mlp->next) { for (i=0; i < mlp->module->slotCount; i++) { - token = nssToken_CreateFromPK11SlotInfo(td, mlp->module->slots[i]); - PK11Slot_SetNSSToken(mlp->module->slots[i], token); - nssList_Add(td->tokenList, token); + STAN_InitTokenForSlotInfo(td, mlp->module->slots[i]); } } - SECMOD_ReleaseReadLock(moduleLock); td->tokens = nssList_CreateIterator(td->tokenList); + NSSRWLock_UnlockWrite(td->tokensLock); + SECMOD_ReleaseReadLock(moduleLock); g_default_trust_domain = td; g_default_crypto_context = NSSTrustDomain_CreateCryptoContext(td, NULL); return PR_SUCCESS; } +/* + * must be called holding the ModuleListLock (either read or write). + */ NSS_IMPLEMENT SECStatus STAN_AddModuleToDefaultTrustDomain ( SECMODModule *module ) { - NSSToken *token; NSSTrustDomain *td; int i; td = STAN_GetDefaultTrustDomain(); for (i=0; islotCount; i++) { - token = nssToken_CreateFromPK11SlotInfo(td, module->slots[i]); - PK11Slot_SetNSSToken(module->slots[i], token); - nssList_Add(td->tokenList, token); + STAN_InitTokenForSlotInfo(td, module->slots[i]); } - nssListIterator_Destroy(td->tokens); - td->tokens = nssList_CreateIterator(td->tokenList); + STAN_ResetTokenInterator(td); return SECSuccess; } +/* + * must be called holding the ModuleListLock (either read or write). + */ NSS_IMPLEMENT SECStatus STAN_RemoveModuleFromDefaultTrustDomain ( SECMODModule *module @@ -157,6 +191,7 @@ STAN_RemoveModuleFromDefaultTrustDomain ( NSSTrustDomain *td; int i; td = STAN_GetDefaultTrustDomain(); + NSSRWLock_LockWrite(td->tokensLock); for (i=0; islotCount; i++) { token = PK11Slot_GetNSSToken(module->slots[i]); if (token) { @@ -168,6 +203,7 @@ STAN_RemoveModuleFromDefaultTrustDomain ( } nssListIterator_Destroy(td->tokens); td->tokens = nssList_CreateIterator(td->tokenList); + NSSRWLock_UnlockWrite(td->tokensLock); return SECSuccess; } @@ -1015,9 +1051,11 @@ STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust) tok = stan_GetTrustToken(c); moving_object = PR_FALSE; if (tok && PK11_IsReadOnly(tok->pk11slot)) { + NSSRWLock_LockRead(td->tokensLock); tokens = nssList_CreateIterator(td->tokenList); if (!tokens) { nssrv = PR_FAILURE; + NSSRWLock_UnlockRead(td->tokensLock); goto done; } for (tok = (NSSToken *)nssListIterator_Start(tokens); @@ -1028,6 +1066,7 @@ STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust) } nssListIterator_Finish(tokens); nssListIterator_Destroy(tokens); + NSSRWLock_UnlockRead(td->tokensLock); moving_object = PR_TRUE; } if (tok) { diff --git a/security/nss/lib/pki/pki3hack.h b/security/nss/lib/pki/pki3hack.h index 1e8fcc9f8..279e5056a 100644 --- a/security/nss/lib/pki/pki3hack.h +++ b/security/nss/lib/pki/pki3hack.h @@ -74,25 +74,22 @@ NSS_EXTERN NSSCryptoContext * STAN_GetDefaultCryptoContext(); NSS_EXTERN PRStatus -STAN_LoadDefaultNSS3TrustDomain -( - void -); +STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot); + +NSS_EXTERN PRStatus +STAN_ResetTokenInterator(NSSTrustDomain *td); + +NSS_EXTERN PRStatus +STAN_LoadDefaultNSS3TrustDomain(void); NSS_EXTERN PRStatus STAN_Shutdown(); NSS_EXTERN SECStatus -STAN_AddModuleToDefaultTrustDomain -( - SECMODModule *module -); +STAN_AddModuleToDefaultTrustDomain(SECMODModule *module); NSS_EXTERN SECStatus -STAN_RemoveModuleFromDefaultTrustDomain -( - SECMODModule *module -); +STAN_RemoveModuleFromDefaultTrustDomain(SECMODModule *module); NSS_EXTERN CERTCertificate * STAN_ForceCERTCertificateUpdate(NSSCertificate *c); diff --git a/security/nss/lib/pki/pkit.h b/security/nss/lib/pki/pkit.h index 6e14b4328..f16c67617 100644 --- a/security/nss/lib/pki/pkit.h +++ b/security/nss/lib/pki/pkit.h @@ -72,6 +72,10 @@ static const char PKIT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; #include "devt.h" #endif /* DEVT_H */ +#ifndef nssrwlkt_h__ +#include "nssrwlkt.h" +#endif /* nssrwlkt_h__ */ + PR_BEGIN_EXTERN_C /* @@ -174,6 +178,7 @@ struct NSSTrustDomainStr { nssList *tokenList; nssListIterator *tokens; nssTDCertificateCache *cache; + NSSRWLock *tokensLock; #ifdef NSS_3_4_CODE void *spkDigestInfo; CERTStatusConfig *statusConfig; diff --git a/security/nss/lib/pki/trustdomain.c b/security/nss/lib/pki/trustdomain.c index c3a3751f0..5c8a84583 100644 --- a/security/nss/lib/pki/trustdomain.c +++ b/security/nss/lib/pki/trustdomain.c @@ -55,6 +55,8 @@ static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; #include "pki3hack.h" #endif +#include "nssrwlk.h" + #define NSSTRUSTDOMAIN_DEFAULT_CACHE_SIZE 32 #ifdef PURE_STAN_BUILD @@ -93,6 +95,11 @@ NSSTrustDomain_Create ( if (!rvTD) { goto loser; } + /* protect the token list and the token iterator */ + rvTD->tokensLock = NSSRWLock_New(100, "tokens"); + if (!rvTD->tokensLock) { + goto loser; + } nssTrustDomain_InitializeCache(rvTD, NSSTRUSTDOMAIN_DEFAULT_CACHE_SIZE); rvTD->arena = arena; rvTD->refCount = 1; @@ -101,6 +108,9 @@ NSSTrustDomain_Create ( #endif return rvTD; loser: + if (rvTD && rvTD->tokensLock) { + NSSRWLock_Destroy(rvTD->tokensLock); + } nssArena_Destroy(arena); return (NSSTrustDomain *)NULL; } @@ -127,6 +137,7 @@ NSSTrustDomain_Destroy ( nssList_Clear(td->tokenList, token_destructor); nssList_Destroy(td->tokenList); } + NSSRWLock_Destroy(td->tokensLock); status = nssTrustDomain_DestroyCache(td); if (status == PR_FAILURE) { return status; @@ -148,17 +159,21 @@ nssTrustDomain_GetActiveSlots ( NSSSlot **slots = NULL; NSSToken **tp, **tokens; *updateLevel = 1; + NSSRWLock_LockRead(td->tokensLock); count = nssList_Count(td->tokenList); tokens = nss_ZNEWARRAY(NULL, NSSToken *, count + 1); if (!tokens) { + NSSRWLock_UnlockRead(td->tokensLock); return NULL; } slots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1); if (!slots) { + NSSRWLock_UnlockRead(td->tokensLock); nss_ZFreeIf(tokens); return NULL; } nssList_GetArray(td->tokenList, (void **)tokens, count); + NSSRWLock_UnlockRead(td->tokensLock); count = 0; for (tp = tokens; *tp; tp++) { slots[count++] = nssToken_GetSlot(*tp); @@ -275,6 +290,7 @@ NSSTrustDomain_FindTokenByName ( PRStatus nssrv; NSSUTF8 *myName; NSSToken *tok = NULL; + NSSRWLock_LockRead(td->tokensLock); for (tok = (NSSToken *)nssListIterator_Start(td->tokens); tok != (NSSToken *)NULL; tok = (NSSToken *)nssListIterator_Next(td->tokens)) @@ -285,6 +301,7 @@ NSSTrustDomain_FindTokenByName ( } } nssListIterator_Finish(td->tokens); + NSSRWLock_UnlockRead(td->tokensLock); return tok; } diff --git a/security/nss/lib/util/secerr.h b/security/nss/lib/util/secerr.h index db45149e7..c8ba5af5e 100644 --- a/security/nss/lib/util/secerr.h +++ b/security/nss/lib/util/secerr.h @@ -200,7 +200,9 @@ SEC_ERROR_REVOKED_CERTIFICATE_OCSP = (SEC_ERROR_BASE + 146), SEC_ERROR_CRL_INVALID_VERSION = (SEC_ERROR_BASE + 147), SEC_ERROR_CRL_V1_CRITICAL_EXTENSION = (SEC_ERROR_BASE + 148), SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION = (SEC_ERROR_BASE + 149), -SEC_ERROR_UNKNOWN_OBJECT_TYPE = (SEC_ERROR_BASE + 150) +SEC_ERROR_UNKNOWN_OBJECT_TYPE = (SEC_ERROR_BASE + 150), +SEC_ERROR_INCOMPATIBLE_PKCS11 = (SEC_ERROR_BASE + 151), +SEC_ERROR_NO_EVENT = (SEC_ERROR_BASE + 152) } SECErrorCodes; #endif /* NO_SECURITY_ERROR_ENUM */ -- cgit v1.2.1