summaryrefslogtreecommitdiff
path: root/security/nss/lib/pk11wrap/pk11util.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/pk11wrap/pk11util.c')
-rw-r--r--security/nss/lib/pk11wrap/pk11util.c1440
1 files changed, 0 insertions, 1440 deletions
diff --git a/security/nss/lib/pk11wrap/pk11util.c b/security/nss/lib/pk11wrap/pk11util.c
deleted file mode 100644
index e4edaf2e6..000000000
--- a/security/nss/lib/pk11wrap/pk11util.c
+++ /dev/null
@@ -1,1440 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1994-2000
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-/*
- * Initialize the PCKS 11 subsystem
- */
-#include "seccomon.h"
-#include "secmod.h"
-#include "nssilock.h"
-#include "secmodi.h"
-#include "secmodti.h"
-#include "pk11func.h"
-#include "pki3hack.h"
-#include "secerr.h"
-#include "dev.h"
-#include "pkcs11ni.h"
-
-/* these are for displaying error messages */
-
-static SECMODModuleList *modules = NULL;
-static SECMODModuleList *modulesDB = NULL;
-static SECMODModuleList *modulesUnload = NULL;
-static SECMODModule *internalModule = NULL;
-static SECMODModule *defaultDBModule = NULL;
-static SECMODModule *pendingModule = NULL;
-static SECMODListLock *moduleLock = NULL;
-
-int secmod_PrivateModuleCount = 0;
-
-extern PK11DefaultArrayEntry PK11_DefaultArray[];
-extern int num_pk11_default_mechanisms;
-
-
-void
-SECMOD_Init()
-{
- /* don't initialize twice */
- if (moduleLock) return;
-
- moduleLock = SECMOD_NewListLock();
- PK11_InitSlotLists();
-}
-
-
-SECStatus
-SECMOD_Shutdown()
-{
- /* destroy the lock */
- if (moduleLock) {
- SECMOD_DestroyListLock(moduleLock);
- moduleLock = NULL;
- }
- /* free the internal module */
- if (internalModule) {
- SECMOD_DestroyModule(internalModule);
- internalModule = NULL;
- }
-
- /* free the default database module */
- if (defaultDBModule) {
- SECMOD_DestroyModule(defaultDBModule);
- defaultDBModule = NULL;
- }
-
- /* destroy the list */
- if (modules) {
- SECMOD_DestroyModuleList(modules);
- modules = NULL;
- }
-
- if (modulesDB) {
- SECMOD_DestroyModuleList(modulesDB);
- modulesDB = NULL;
- }
-
- if (modulesUnload) {
- SECMOD_DestroyModuleList(modulesUnload);
- modulesUnload = NULL;
- }
-
- /* make all the slots and the lists go away */
- PK11_DestroySlotLists();
-
- nss_DumpModuleLog();
-
-#ifdef DEBUG
- if (PR_GetEnv("NSS_STRICT_SHUTDOWN")) {
- PORT_Assert(secmod_PrivateModuleCount == 0);
- }
-#endif
- if (secmod_PrivateModuleCount) {
- PORT_SetError(SEC_ERROR_BUSY);
- return SECFailure;
- }
- return SECSuccess;
-}
-
-
-/*
- * retrieve the internal module
- */
-SECMODModule *
-SECMOD_GetInternalModule(void)
-{
- return internalModule;
-}
-
-
-SECStatus
-secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule)
-{
- SECMODModuleList *mlp, *newListElement, *last = NULL;
-
- newListElement = SECMOD_NewModuleListElement();
- if (newListElement == NULL) {
- return SECFailure;
- }
-
- newListElement->module = SECMOD_ReferenceModule(newModule);
-
- SECMOD_GetWriteLock(moduleLock);
- /* Added it to the end (This is very inefficient, but Adding a module
- * on the fly should happen maybe 2-3 times through the life this program
- * on a given computer, and this list should be *SHORT*. */
- for(mlp = *moduleList; mlp != NULL; mlp = mlp->next) {
- last = mlp;
- }
-
- if (last == NULL) {
- *moduleList = newListElement;
- } else {
- SECMOD_AddList(last,newListElement,NULL);
- }
- SECMOD_ReleaseWriteLock(moduleLock);
- return SECSuccess;
-}
-
-SECStatus
-SECMOD_AddModuleToList(SECMODModule *newModule)
-{
- if (newModule->internal && !internalModule) {
- internalModule = SECMOD_ReferenceModule(newModule);
- }
- return secmod_AddModuleToList(&modules,newModule);
-}
-
-SECStatus
-SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule)
-{
- if (defaultDBModule == NULL) {
- defaultDBModule = SECMOD_ReferenceModule(newModule);
- }
- return secmod_AddModuleToList(&modulesDB,newModule);
-}
-
-SECStatus
-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_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; }
-
-
-
-/*
- * find a module by name, and add a reference to it.
- * return that module.
- */
-SECMODModule *
-SECMOD_FindModule(const char *name)
-{
- SECMODModuleList *mlp;
- SECMODModule *module = NULL;
-
- SECMOD_GetReadLock(moduleLock);
- for(mlp = modules; mlp != NULL; mlp = mlp->next) {
- if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
- module = mlp->module;
- SECMOD_ReferenceModule(module);
- break;
- }
- }
- if (module) {
- goto found;
- }
- for(mlp = modulesUnload; mlp != NULL; mlp = mlp->next) {
- if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
- module = mlp->module;
- SECMOD_ReferenceModule(module);
- break;
- }
- }
-
-found:
- SECMOD_ReleaseReadLock(moduleLock);
-
- return module;
-}
-
-/*
- * find a module by ID, and add a reference to it.
- * return that module.
- */
-SECMODModule *
-SECMOD_FindModuleByID(SECMODModuleID id)
-{
- SECMODModuleList *mlp;
- SECMODModule *module = NULL;
-
- SECMOD_GetReadLock(moduleLock);
- for(mlp = modules; mlp != NULL; mlp = mlp->next) {
- if (id == mlp->module->moduleID) {
- module = mlp->module;
- SECMOD_ReferenceModule(module);
- break;
- }
- }
- SECMOD_ReleaseReadLock(moduleLock);
- if (module == NULL) {
- PORT_SetError(SEC_ERROR_NO_MODULE);
- }
- return module;
-}
-
-/*
- * Find the Slot based on ID and the module.
- */
-PK11SlotInfo *
-SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID)
-{
- int i;
- PK11SlotInfo *slot = NULL;
-
- SECMOD_GetReadLock(moduleLock);
- for (i=0; i < module->slotCount; i++) {
- PK11SlotInfo *cSlot = module->slots[i];
-
- 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 slot;
-}
-
-
-/*
- * find a module by name or module pointer and delete it off the module list.
- * optionally remove it from secmod.db.
- */
-SECStatus
-SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod,
- int *type, PRBool permdb)
-{
- SECMODModuleList *mlp;
- SECMODModuleList **mlpp;
- SECStatus rv = SECFailure;
-
- *type = SECMOD_EXTERNAL;
-
- SECMOD_GetWriteLock(moduleLock);
- for (mlpp = &modules,mlp = modules;
- mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
- if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) ||
- mod == mlp->module) {
- /* don't delete the internal module */
- if (!mlp->module->internal) {
- SECMOD_RemoveList(mlpp,mlp);
- /* delete it after we release the lock */
- rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
- } else if (mlp->module->isFIPS) {
- *type = SECMOD_FIPS;
- } else {
- *type = SECMOD_INTERNAL;
- }
- break;
- }
- }
- if (mlp) {
- goto found;
- }
- /* not on the internal list, check the unload list */
- for (mlpp = &modulesUnload,mlp = modulesUnload;
- mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
- if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) ||
- mod == mlp->module) {
- /* don't delete the internal module */
- if (!mlp->module->internal) {
- SECMOD_RemoveList(mlpp,mlp);
- rv = SECSuccess;
- } else if (mlp->module->isFIPS) {
- *type = SECMOD_FIPS;
- } else {
- *type = SECMOD_INTERNAL;
- }
- break;
- }
- }
-found:
- SECMOD_ReleaseWriteLock(moduleLock);
-
-
- if (rv == SECSuccess) {
- if (permdb) {
- SECMOD_DeletePermDB(mlp->module);
- }
- SECMOD_DestroyModuleListElement(mlp);
- }
- return rv;
-}
-
-/*
- * find a module by name and delete it off the module list
- */
-SECStatus
-SECMOD_DeleteModule(const char *name, int *type)
-{
- return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE);
-}
-
-/*
- * find a module by name and delete it off the module list
- */
-SECStatus
-SECMOD_DeleteInternalModule(const char *name)
-{
- SECMODModuleList *mlp;
- SECMODModuleList **mlpp;
- SECStatus rv = SECFailure;
-
- if (pendingModule) {
- PORT_SetError(SEC_ERROR_MODULE_STUCK);
- return rv;
- }
-
- SECMOD_GetWriteLock(moduleLock);
- for(mlpp = &modules,mlp = modules;
- mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
- if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
- /* don't delete the internal module */
- if (mlp->module->internal) {
- SECMOD_RemoveList(mlpp,mlp);
- rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
- }
- break;
- }
- }
- SECMOD_ReleaseWriteLock(moduleLock);
-
- if (rv == SECSuccess) {
- SECMODModule *newModule,*oldModule;
-
- if (mlp->module->isFIPS) {
- newModule = SECMOD_CreateModule(NULL, SECMOD_INT_NAME,
- NULL, SECMOD_INT_FLAGS);
- } else {
- newModule = SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME,
- NULL, SECMOD_FIPS_FLAGS);
- }
- if (newModule) {
- newModule->libraryParams =
- PORT_ArenaStrdup(newModule->arena,mlp->module->libraryParams);
- rv = SECMOD_AddModule(newModule);
- if (rv != SECSuccess) {
- SECMOD_DestroyModule(newModule);
- newModule = NULL;
- }
- }
- if (newModule == NULL) {
- SECMODModuleList *last = NULL,*mlp2;
- /* we're in pretty deep trouble if this happens...Security
- * not going to work well... try to put the old module back on
- * the list */
- SECMOD_GetWriteLock(moduleLock);
- for(mlp2 = modules; mlp2 != NULL; mlp2 = mlp->next) {
- last = mlp2;
- }
-
- if (last == NULL) {
- modules = mlp;
- } else {
- SECMOD_AddList(last,mlp,NULL);
- }
- SECMOD_ReleaseWriteLock(moduleLock);
- return SECFailure;
- }
- pendingModule = oldModule = internalModule;
- internalModule = NULL;
- SECMOD_DestroyModule(oldModule);
- SECMOD_DeletePermDB(mlp->module);
- SECMOD_DestroyModuleListElement(mlp);
- internalModule = newModule; /* adopt the module */
- }
- return rv;
-}
-
-SECStatus
-SECMOD_AddModule(SECMODModule *newModule)
-{
- SECStatus rv;
- SECMODModule *oldModule;
-
- /* Test if a module w/ the same name already exists */
- /* and return SECWouldBlock if so. */
- /* We should probably add a new return value such as */
- /* SECDublicateModule, but to minimize ripples, I'll */
- /* give SECWouldBlock a new meaning */
- if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL) {
- SECMOD_DestroyModule(oldModule);
- return SECWouldBlock;
- /* module already exists. */
- }
-
- rv = SECMOD_LoadPKCS11Module(newModule);
- if (rv != SECSuccess) {
- return rv;
- }
-
- if (newModule->parent == NULL) {
- newModule->parent = SECMOD_ReferenceModule(defaultDBModule);
- }
-
- SECMOD_AddPermDB(newModule);
- SECMOD_AddModuleToList(newModule);
-
- rv = STAN_AddModuleToDefaultTrustDomain(newModule);
-
- return rv;
-}
-
-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];
-
- if (PK11_IsPresent(slot)) {
- string = PK11_GetTokenName(slot);
- } else {
- string = PK11_GetSlotName(slot);
- }
- if (PORT_Strcmp(name,string) == 0) {
- retSlot = PK11_ReferenceSlot(slot);
- break;
- }
- }
- SECMOD_ReleaseReadLock(moduleLock);
-
- if (retSlot == NULL) {
- PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
- }
- return retSlot;
-}
-
-SECStatus
-PK11_GetModInfo(SECMODModule *mod,CK_INFO *info)
-{
- CK_RV crv;
-
- if (mod->functionList == NULL) return SECFailure;
- crv = PK11_GETTAB(mod)->C_GetInfo(info);
- if (crv != CKR_OK) {
- PORT_SetError(PK11_MapError(crv));
- }
- return (crv == CKR_OK) ? SECSuccess : SECFailure;
-}
-
-/* Determine if we have the FIP's module loaded as the default
- * module to trigger other bogus FIPS requirements in PKCS #12 and
- * SSL
- */
-PRBool
-PK11_IsFIPS(void)
-{
- SECMODModule *mod = SECMOD_GetInternalModule();
-
- if (mod && mod->internal) {
- return mod->isFIPS;
- }
-
- return PR_FALSE;
-}
-
-/* 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,
- unsigned long defaultMechanismFlags,
- unsigned long cipherEnableFlags,
- char* modparms, char* nssparms)
-{
- SECMODModule *module;
- SECStatus result = SECFailure;
- int s,i;
- PK11SlotInfo* slot;
-
- PR_SetErrorText(0, NULL);
-
- module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms);
-
- if (module == NULL) {
- return result;
- }
-
- if (module->dllName != NULL) {
- if (module->dllName[0] != 0) {
- result = SECMOD_AddModule(module);
- if (result == SECSuccess) {
- /* 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 ? */
- 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 */
- result = SECMOD_UpdateModule(module);
- }
- }
- }
- SECMOD_DestroyModule(module);
- return result;
-}
-
-SECStatus
-SECMOD_AddNewModule(const char* moduleName, const char* dllPath,
- unsigned long defaultMechanismFlags,
- unsigned long cipherEnableFlags)
-{
- return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags,
- cipherEnableFlags,
- NULL, NULL); /* don't pass module or nss params */
-}
-
-SECStatus
-SECMOD_UpdateModule(SECMODModule *module)
-{
- SECStatus result;
-
- result = SECMOD_DeletePermDB(module);
-
- if (result == SECSuccess) {
- result = SECMOD_AddPermDB(module);
- }
- return result;
-}
-
-/* Public & Internal(Security Library) representation of
- * encryption mechanism flags conversion */
-
-/* Currently, the only difference is that internal representation
- * 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 internalFlags = publicFlags;
-
- if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) {
- internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG;
- internalFlags |= SECMOD_RANDOM_FLAG;
- }
- return internalFlags;
-}
-
-unsigned long
-SECMOD_InternaltoPubMechFlags(unsigned long internalFlags)
-{
- unsigned long publicFlags = internalFlags;
-
- if (internalFlags & SECMOD_RANDOM_FLAG) {
- publicFlags &= ~SECMOD_RANDOM_FLAG;
- publicFlags |= PUBLIC_MECH_RANDOM_FLAG;
- }
- return publicFlags;
-}
-
-
-/* Public & Internal(Security Library) representation of */
-/* cipher flags conversion */
-/* Note: currently they are just stubs */
-unsigned long
-SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags)
-{
- return publicFlags;
-}
-
-unsigned long
-SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags)
-{
- return internalFlags;
-}
-
-/* Funtion reports true if module of modType is installed/configured */
-PRBool
-SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags )
-{
- PRBool result = PR_FALSE;
- SECMODModuleList *mods = SECMOD_GetDefaultModuleList();
- SECMOD_GetReadLock(moduleLock);
-
-
- for ( ; mods != NULL; mods = mods->next) {
- if (mods->module->ssl[0] &
- SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) {
- result = PR_TRUE;
- }
- }
-
- SECMOD_ReleaseReadLock(moduleLock);
- return result;
-}
-
-/* create a new ModuleListElement */
-SECMODModuleList *SECMOD_NewModuleListElement(void)
-{
- SECMODModuleList *newModList;
-
- newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList));
- if (newModList) {
- newModList->next = NULL;
- newModList->module = NULL;
- }
- return newModList;
-}
-
-/*
- * make a new reference to a module so It doesn't go away on us
- */
-SECMODModule *
-SECMOD_ReferenceModule(SECMODModule *module)
-{
- PZ_Lock(module->refLock);
- PORT_Assert(module->refCount > 0);
-
- module->refCount++;
- PZ_Unlock(module->refLock);
- return module;
-}
-
-
-/* destroy an existing module */
-void
-SECMOD_DestroyModule(SECMODModule *module)
-{
- PRBool willfree = PR_FALSE;
- int slotCount;
- int i;
-
- PZ_Lock(module->refLock);
- if (module->refCount-- == 1) {
- willfree = PR_TRUE;
- }
- PORT_Assert(willfree || (module->refCount > 0));
- PZ_Unlock(module->refLock);
-
- if (!willfree) {
- return;
- }
-
- if (module->parent != NULL) {
- SECMODModule *parent = module->parent;
- /* paranoia, don't loop forever if the modules are looped */
- module->parent = NULL;
- SECMOD_DestroyModule(parent);
- }
-
- /* slots can't really disappear until our module starts freeing them,
- * so this check is safe */
- slotCount = module->slotCount;
- if (slotCount == 0) {
- SECMOD_SlotDestroyModule(module,PR_FALSE);
- return;
- }
-
- /* now free all out slots, when they are done, they will cause the
- * module to disappear altogether */
- for (i=0 ; i < slotCount; i++) {
- if (!module->slots[i]->disabled) {
- PK11_ClearSlotList(module->slots[i]);
- }
- PK11_FreeSlot(module->slots[i]);
- }
- /* WARNING: once the last slot has been freed is it possible (even likely)
- * that module is no more... touching it now is a good way to go south */
-}
-
-
-/* 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)
-{
- PRBool willfree = PR_FALSE;
- if (fromSlot) {
- PORT_Assert(module->refCount == 0);
- PZ_Lock(module->refLock);
- if (module->slotCount-- == 1) {
- willfree = PR_TRUE;
- }
- PORT_Assert(willfree || (module->slotCount > 0));
- PZ_Unlock(module->refLock);
- if (!willfree) return;
- }
-
- if (module == pendingModule) {
- pendingModule = NULL;
- }
-
- if (module->loaded) {
- SECMOD_UnloadModule(module);
- }
- PZ_DestroyLock(module->refLock);
- PORT_FreeArena(module->arena,PR_FALSE);
- secmod_PrivateModuleCount--;
-}
-
-/* destroy a list element
- * this destroys a single element, and returns the next element
- * 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)
-{
- SECMODModuleList *next = element->next;
-
- if (element->module) {
- SECMOD_DestroyModule(element->module);
- element->module = NULL;
- }
- PORT_Free(element);
- return next;
-}
-
-
-/*
- * Destroy an entire module list
- */
-void
-SECMOD_DestroyModuleList(SECMODModuleList *list)
-{
- SECMODModuleList *lp;
-
- for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ;
-}
-
-PRBool
-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;
- CK_ULONG count;
- CK_ULONG i, oldCount;
- PRBool freeRef = PR_FALSE;
- void *mark = NULL;
- 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 < (CK_ULONG)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;
-
- if (!pk11_getFinalizeModulesOption() ||
- ((mod->cryptokiVersion.major == 2) &&
- (mod->cryptokiVersion.minor < 1))) {
- /* if we are sharing the module with other software in our
- * address space, we can't reliably use C_WaitForSlotEvent(),
- * and if the module is version 2.0, C_WaitForSlotEvent() doesn't
- * exist */
- return secmod_HandleWaitForSlotEvent(mod, flags, latency);
- }
- /* 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);
- }
- /* if we are in the delay period for the "isPresent" call, reset
- * the delay since we know things have probably changed... */
- if (slot && slot->nssToken && slot->nssToken->slot) {
- nssSlot_ResetDelay(slot->nssToken->slot);
- }
- 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) {
- if (!pk11_getFinalizeModulesOption()) {
- /* can't get here unless pk11_getFinalizeModulesOption is set */
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- rv = SECFailure;
- goto loser;
- }
- /* 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/startup 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 (CKR_OK == crv) {
- PRBool alreadyLoaded;
- secmod_ModuleInit(mod, &alreadyLoaded);
- } 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 */
- }
-loser:
- 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;
-}
-
-/*
- * helper function to actually create and destroy user defined slots
- */
-static SECStatus
-secmod_UserDBOp(CK_OBJECT_CLASS objClass, const char *sendSpec)
-{
- PK11SlotInfo *slot = PK11_GetInternalSlot();
- CK_OBJECT_HANDLE dummy;
- CK_ATTRIBUTE template[2] ;
- CK_ATTRIBUTE *attrs = template;
- SECStatus rv;
- CK_RV crv;
-
- PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++;
- PK11_SETATTRS(attrs, CKA_NETSCAPE_MODULE_SPEC , (unsigned char *)sendSpec,
- strlen(sendSpec)+1); attrs++;
-
- PORT_Assert(attrs-template <= 2);
-
-
- PK11_EnterSlotMonitor(slot);
- crv = PK11_CreateNewObject(slot, slot->session,
- template, attrs-template, PR_FALSE, &dummy);
- PK11_ExitSlotMonitor(slot);
-
- if (crv != CKR_OK) {
- PK11_FreeSlot(slot);
- PORT_SetError(PK11_MapError(crv));
- return SECFailure;
- }
- rv = SECMOD_UpdateSlotList(slot->module);
- PK11_FreeSlot(slot);
- return rv;
-}
-
-/*
- * add escapes to protect quote characters...
- */
-static char *
-nss_addEscape(const char *string, char quote)
-{
- char *newString = 0;
- int escapes = 0, size = 0;
- const char *src;
- char *dest;
-
- for (src=string; *src ; src++) {
- if ((*src == quote) || (*src == '\\')) escapes++;
- size++;
- }
-
- newString = PORT_ZAlloc(escapes+size+1);
- if (newString == NULL) {
- return NULL;
- }
-
- for (src=string, dest=newString; *src; src++,dest++) {
- if ((*src == '\\') || (*src == quote)) {
- *dest++ = '\\';
- }
- *dest = *src;
- }
-
- return newString;
-}
-
-static char *
-nss_doubleEscape(const char *string)
-{
- char *round1 = NULL;
- char *retValue = NULL;
- if (string == NULL) {
- goto done;
- }
- round1 = nss_addEscape(string,'>');
- if (round1) {
- retValue = nss_addEscape(round1,']');
- PORT_Free(round1);
- }
-
-done:
- if (retValue == NULL) {
- retValue = PORT_Strdup("");
- }
- return retValue;
-}
-
-/*
- * Open a new database using the softoken. The caller is responsible for making
- * sure the module spec is correct and usable. The caller should ask for one
- * new database per call if the caller wants to get meaningful information
- * about the new database.
- *
- * moduleSpec is the same data that you would pass to softoken at
- * initialization time under the 'tokens' options. For example, if you were
- * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']>
- * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your
- * module spec here. The slot ID will be calculated for you by
- * SECMOD_OpenUserDB().
- *
- * Typical parameters here are configdir, tokenDescription and flags.
- *
- * a Full list is below:
- *
- *
- * configDir - The location of the databases for this token. If configDir is
- * not specified, and noCertDB and noKeyDB is not specified, the load
- * will fail.
- * certPrefix - Cert prefix for this token.
- * keyPrefix - Prefix for the key database for this token. (if not specified,
- * certPrefix will be used).
- * tokenDescription - The label value for this token returned in the
- * CK_TOKEN_INFO structure with an internationalize string (UTF8).
- * This value will be truncated at 32 bytes (no NULL, partial UTF8
- * characters dropped). You should specify a user friendly name here
- * as this is the value the token will be refered to in most
- * application UI's. You should make sure tokenDescription is unique.
- * slotDescription - The slotDescription value for this token returned
- * in the CK_SLOT_INFO structure with an internationalize string
- * (UTF8). This value will be truncated at 64 bytes (no NULL, partial
- * UTF8 characters dropped). This name will not change after the
- * database is closed. It should have some number to make this unique.
- * minPWLen - minimum password length for this token.
- * flags - comma separated list of flag values, parsed case-insensitive.
- * Valid flags are:
- * readOnly - Databases should be opened read only.
- * noCertDB - Don't try to open a certificate database.
- * noKeyDB - Don't try to open a key database.
- * forceOpen - Don't fail to initialize the token if the
- * databases could not be opened.
- * passwordRequired - zero length passwords are not acceptable
- * (valid only if there is a keyDB).
- * optimizeSpace - allocate smaller hash tables and lock tables.
- * When this flag is not specified, Softoken will allocate
- * large tables to prevent lock contention.
- */
-PK11SlotInfo *
-SECMOD_OpenUserDB(const char *moduleSpec)
-{
- CK_SLOT_ID slotID = 0;
- char *escSpec;
- char *sendSpec;
- SECStatus rv;
- SECMODModule *mod;
- CK_SLOT_ID i, minSlotID, maxSlotID;
- PRBool found = PR_FALSE;
-
- if (moduleSpec == NULL) {
- return NULL;
- }
-
- /* NOTE: unlike most PK11 function, this does not return a reference
- * to the module */
- mod = SECMOD_GetInternalModule();
- if (!mod) {
- /* shouldn't happen */
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return NULL;
- }
-
- /* look for a free slot id on the internal module */
- if (mod->isFIPS) {
- minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID;
- maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID;
- } else {
- minSlotID = SFTK_MIN_USER_SLOT_ID;
- maxSlotID = SFTK_MAX_USER_SLOT_ID;
- }
- for (i=minSlotID; i < maxSlotID; i++) {
- PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, i);
- if (slot) {
- PRBool present = PK11_IsPresent(slot);
- PK11_FreeSlot(slot);
- if (present) {
- continue;
- }
- /* not present means it's available */
- }
- /* it doesn't exist or isn't present, it's available */
- slotID = i;
- found = PR_TRUE;
- break;
- }
-
- if (!found) {
- /* this could happen if we try to open too many slots */
- PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
- return NULL;
- }
-
- /* we've found the slot, now build the moduleSpec */
-
- escSpec = nss_doubleEscape(moduleSpec);
- if (escSpec == NULL) {
- return NULL;
- }
- sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec);
- PORT_Free(escSpec);
-
- if (sendSpec == NULL) {
- /* PR_smprintf does not set no memory error */
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- rv = secmod_UserDBOp(CKO_NETSCAPE_NEWSLOT, sendSpec);
- PR_smprintf_free(sendSpec);
- if (rv != SECSuccess) {
- return NULL;
- }
-
- return SECMOD_FindSlotByID(mod, slotID);
-}
-
-/*
- * close an already opened user database. NOTE: the database must be
- * in the internal token, and must be one created with SECMOD_OpenUserDB().
- * Once the database is closed, the slot will remain as an empty slot
- * until it's used again with SECMOD_OpenUserDB().
- */
-SECStatus
-SECMOD_CloseUserDB(PK11SlotInfo *slot)
-{
- SECStatus rv;
- char *sendSpec;
-
- if (!slot->isInternal) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID);
- if (sendSpec == NULL) {
- /* PR_smprintf does not set no memory error */
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- rv = secmod_UserDBOp(CKO_NETSCAPE_DELSLOT, sendSpec);
- PR_smprintf_free(sendSpec);
- return rv;
-}