summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrelyea%netscape.com <devnull@localhost>2004-07-29 23:38:14 +0000
committerrelyea%netscape.com <devnull@localhost>2004-07-29 23:38:14 +0000
commit7ac4ac4a5302bbf740915932120483800c96624f (patch)
tree938c9b5ca229fbd6e9e24f9a71b400c5e62bf416
parent067f12004b5def4f6c645da8c7a0713876f7234c (diff)
downloadnss-hg-7ac4ac4a5302bbf740915932120483800c96624f.tar.gz
Bugzilla Bug 252702
NSS needs to handle better token insertion and removal. Applied from patch to NSS 3.9
-rw-r--r--security/nss/lib/nss/nss.def9
-rw-r--r--security/nss/lib/pk11wrap/pk11err.c2
-rw-r--r--security/nss/lib/pk11wrap/pk11list.c88
-rw-r--r--security/nss/lib/pk11wrap/pk11load.c58
-rw-r--r--security/nss/lib/pk11wrap/pk11pars.c14
-rw-r--r--security/nss/lib/pk11wrap/pk11util.c508
-rw-r--r--security/nss/lib/pk11wrap/secmod.h20
-rw-r--r--security/nss/lib/pk11wrap/secmodi.h1
-rw-r--r--security/nss/lib/pk11wrap/secmodt.h18
-rw-r--r--security/nss/lib/pk11wrap/secmodti.h4
-rw-r--r--security/nss/lib/pki/pki3hack.c63
-rw-r--r--security/nss/lib/pki/pki3hack.h21
-rw-r--r--security/nss/lib/pki/pkit.h5
-rw-r--r--security/nss/lib/pki/trustdomain.c17
-rw-r--r--security/nss/lib/util/secerr.h4
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
@@ -91,6 +91,41 @@ static const CK_C_INITIALIZE_ARGS secmodLockFunctions = {
};
/*
+ * 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
@@ -94,12 +94,39 @@ 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; i<module->slotCount; 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; i<module->slotCount; 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 */