1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pk11wrap/pk11util.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1585 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * Initialize the PCKS 11 subsystem 1.9 + */ 1.10 +#include "seccomon.h" 1.11 +#include "secmod.h" 1.12 +#include "nssilock.h" 1.13 +#include "secmodi.h" 1.14 +#include "secmodti.h" 1.15 +#include "pk11func.h" 1.16 +#include "pki3hack.h" 1.17 +#include "secerr.h" 1.18 +#include "dev.h" 1.19 +#include "utilpars.h" 1.20 + 1.21 +/* these are for displaying error messages */ 1.22 + 1.23 +static SECMODModuleList *modules = NULL; 1.24 +static SECMODModuleList *modulesDB = NULL; 1.25 +static SECMODModuleList *modulesUnload = NULL; 1.26 +static SECMODModule *internalModule = NULL; 1.27 +static SECMODModule *defaultDBModule = NULL; 1.28 +static SECMODModule *pendingModule = NULL; 1.29 +static SECMODListLock *moduleLock = NULL; 1.30 + 1.31 +int secmod_PrivateModuleCount = 0; 1.32 + 1.33 +extern const PK11DefaultArrayEntry PK11_DefaultArray[]; 1.34 +extern const int num_pk11_default_mechanisms; 1.35 + 1.36 + 1.37 +void 1.38 +SECMOD_Init() 1.39 +{ 1.40 + /* don't initialize twice */ 1.41 + if (moduleLock) return; 1.42 + 1.43 + moduleLock = SECMOD_NewListLock(); 1.44 + PK11_InitSlotLists(); 1.45 +} 1.46 + 1.47 + 1.48 +SECStatus 1.49 +SECMOD_Shutdown() 1.50 +{ 1.51 + /* destroy the lock */ 1.52 + if (moduleLock) { 1.53 + SECMOD_DestroyListLock(moduleLock); 1.54 + moduleLock = NULL; 1.55 + } 1.56 + /* free the internal module */ 1.57 + if (internalModule) { 1.58 + SECMOD_DestroyModule(internalModule); 1.59 + internalModule = NULL; 1.60 + } 1.61 + 1.62 + /* free the default database module */ 1.63 + if (defaultDBModule) { 1.64 + SECMOD_DestroyModule(defaultDBModule); 1.65 + defaultDBModule = NULL; 1.66 + } 1.67 + 1.68 + /* destroy the list */ 1.69 + if (modules) { 1.70 + SECMOD_DestroyModuleList(modules); 1.71 + modules = NULL; 1.72 + } 1.73 + 1.74 + if (modulesDB) { 1.75 + SECMOD_DestroyModuleList(modulesDB); 1.76 + modulesDB = NULL; 1.77 + } 1.78 + 1.79 + if (modulesUnload) { 1.80 + SECMOD_DestroyModuleList(modulesUnload); 1.81 + modulesUnload = NULL; 1.82 + } 1.83 + 1.84 + /* make all the slots and the lists go away */ 1.85 + PK11_DestroySlotLists(); 1.86 + 1.87 + nss_DumpModuleLog(); 1.88 + 1.89 +#ifdef DEBUG 1.90 + if (PR_GetEnv("NSS_STRICT_SHUTDOWN")) { 1.91 + PORT_Assert(secmod_PrivateModuleCount == 0); 1.92 + } 1.93 +#endif 1.94 + if (secmod_PrivateModuleCount) { 1.95 + PORT_SetError(SEC_ERROR_BUSY); 1.96 + return SECFailure; 1.97 + } 1.98 + return SECSuccess; 1.99 +} 1.100 + 1.101 + 1.102 +/* 1.103 + * retrieve the internal module 1.104 + */ 1.105 +SECMODModule * 1.106 +SECMOD_GetInternalModule(void) 1.107 +{ 1.108 + return internalModule; 1.109 +} 1.110 + 1.111 + 1.112 +SECStatus 1.113 +secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule) 1.114 +{ 1.115 + SECMODModuleList *mlp, *newListElement, *last = NULL; 1.116 + 1.117 + newListElement = SECMOD_NewModuleListElement(); 1.118 + if (newListElement == NULL) { 1.119 + return SECFailure; 1.120 + } 1.121 + 1.122 + newListElement->module = SECMOD_ReferenceModule(newModule); 1.123 + 1.124 + SECMOD_GetWriteLock(moduleLock); 1.125 + /* Added it to the end (This is very inefficient, but Adding a module 1.126 + * on the fly should happen maybe 2-3 times through the life this program 1.127 + * on a given computer, and this list should be *SHORT*. */ 1.128 + for(mlp = *moduleList; mlp != NULL; mlp = mlp->next) { 1.129 + last = mlp; 1.130 + } 1.131 + 1.132 + if (last == NULL) { 1.133 + *moduleList = newListElement; 1.134 + } else { 1.135 + SECMOD_AddList(last,newListElement,NULL); 1.136 + } 1.137 + SECMOD_ReleaseWriteLock(moduleLock); 1.138 + return SECSuccess; 1.139 +} 1.140 + 1.141 +SECStatus 1.142 +SECMOD_AddModuleToList(SECMODModule *newModule) 1.143 +{ 1.144 + if (newModule->internal && !internalModule) { 1.145 + internalModule = SECMOD_ReferenceModule(newModule); 1.146 + } 1.147 + return secmod_AddModuleToList(&modules,newModule); 1.148 +} 1.149 + 1.150 +SECStatus 1.151 +SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule) 1.152 +{ 1.153 + if (defaultDBModule && SECMOD_GetDefaultModDBFlag(newModule)) { 1.154 + SECMOD_DestroyModule(defaultDBModule); 1.155 + defaultDBModule = SECMOD_ReferenceModule(newModule); 1.156 + } else if (defaultDBModule == NULL) { 1.157 + defaultDBModule = SECMOD_ReferenceModule(newModule); 1.158 + } 1.159 + return secmod_AddModuleToList(&modulesDB,newModule); 1.160 +} 1.161 + 1.162 +SECStatus 1.163 +SECMOD_AddModuleToUnloadList(SECMODModule *newModule) 1.164 +{ 1.165 + return secmod_AddModuleToList(&modulesUnload,newModule); 1.166 +} 1.167 + 1.168 +/* 1.169 + * get the list of PKCS11 modules that are available. 1.170 + */ 1.171 +SECMODModuleList * SECMOD_GetDefaultModuleList() { return modules; } 1.172 +SECMODModuleList *SECMOD_GetDeadModuleList() { return modulesUnload; } 1.173 +SECMODModuleList *SECMOD_GetDBModuleList() { return modulesDB; } 1.174 + 1.175 +/* 1.176 + * This lock protects the global module lists. 1.177 + * it also protects changes to the slot array (module->slots[]) and slot count 1.178 + * (module->slotCount) in each module. It is a read/write lock with multiple 1.179 + * readers or one writer. Writes are uncommon. 1.180 + * Because of legacy considerations protection of the slot array and count is 1.181 + * only necessary in applications if the application calls 1.182 + * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new 1.183 + * applications are encouraged to acquire this lock when reading the 1.184 + * slot array information directly. 1.185 + */ 1.186 +SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; } 1.187 + 1.188 + 1.189 + 1.190 +/* 1.191 + * find a module by name, and add a reference to it. 1.192 + * return that module. 1.193 + */ 1.194 +SECMODModule * 1.195 +SECMOD_FindModule(const char *name) 1.196 +{ 1.197 + SECMODModuleList *mlp; 1.198 + SECMODModule *module = NULL; 1.199 + 1.200 + if (!moduleLock) { 1.201 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.202 + return module; 1.203 + } 1.204 + SECMOD_GetReadLock(moduleLock); 1.205 + for(mlp = modules; mlp != NULL; mlp = mlp->next) { 1.206 + if (PORT_Strcmp(name,mlp->module->commonName) == 0) { 1.207 + module = mlp->module; 1.208 + SECMOD_ReferenceModule(module); 1.209 + break; 1.210 + } 1.211 + } 1.212 + if (module) { 1.213 + goto found; 1.214 + } 1.215 + for(mlp = modulesUnload; mlp != NULL; mlp = mlp->next) { 1.216 + if (PORT_Strcmp(name,mlp->module->commonName) == 0) { 1.217 + module = mlp->module; 1.218 + SECMOD_ReferenceModule(module); 1.219 + break; 1.220 + } 1.221 + } 1.222 + 1.223 +found: 1.224 + SECMOD_ReleaseReadLock(moduleLock); 1.225 + 1.226 + return module; 1.227 +} 1.228 + 1.229 +/* 1.230 + * find a module by ID, and add a reference to it. 1.231 + * return that module. 1.232 + */ 1.233 +SECMODModule * 1.234 +SECMOD_FindModuleByID(SECMODModuleID id) 1.235 +{ 1.236 + SECMODModuleList *mlp; 1.237 + SECMODModule *module = NULL; 1.238 + 1.239 + if (!moduleLock) { 1.240 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.241 + return module; 1.242 + } 1.243 + SECMOD_GetReadLock(moduleLock); 1.244 + for(mlp = modules; mlp != NULL; mlp = mlp->next) { 1.245 + if (id == mlp->module->moduleID) { 1.246 + module = mlp->module; 1.247 + SECMOD_ReferenceModule(module); 1.248 + break; 1.249 + } 1.250 + } 1.251 + SECMOD_ReleaseReadLock(moduleLock); 1.252 + if (module == NULL) { 1.253 + PORT_SetError(SEC_ERROR_NO_MODULE); 1.254 + } 1.255 + return module; 1.256 +} 1.257 + 1.258 +/* 1.259 + * find the function pointer. 1.260 + */ 1.261 +SECMODModule * 1.262 +secmod_FindModuleByFuncPtr(void *funcPtr) 1.263 +{ 1.264 + SECMODModuleList *mlp; 1.265 + SECMODModule *module = NULL; 1.266 + 1.267 + SECMOD_GetReadLock(moduleLock); 1.268 + for(mlp = modules; mlp != NULL; mlp = mlp->next) { 1.269 + /* paranoia, shouldn't ever happen */ 1.270 + if (!mlp->module) { 1.271 + continue; 1.272 + } 1.273 + if (funcPtr == mlp->module->functionList) { 1.274 + module = mlp->module; 1.275 + SECMOD_ReferenceModule(module); 1.276 + break; 1.277 + } 1.278 + } 1.279 + SECMOD_ReleaseReadLock(moduleLock); 1.280 + if (module == NULL) { 1.281 + PORT_SetError(SEC_ERROR_NO_MODULE); 1.282 + } 1.283 + return module; 1.284 +} 1.285 + 1.286 +/* 1.287 + * Find the Slot based on ID and the module. 1.288 + */ 1.289 +PK11SlotInfo * 1.290 +SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID) 1.291 +{ 1.292 + int i; 1.293 + PK11SlotInfo *slot = NULL; 1.294 + 1.295 + if (!moduleLock) { 1.296 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.297 + return slot; 1.298 + } 1.299 + SECMOD_GetReadLock(moduleLock); 1.300 + for (i=0; i < module->slotCount; i++) { 1.301 + PK11SlotInfo *cSlot = module->slots[i]; 1.302 + 1.303 + if (cSlot->slotID == slotID) { 1.304 + slot = PK11_ReferenceSlot(cSlot); 1.305 + break; 1.306 + } 1.307 + } 1.308 + SECMOD_ReleaseReadLock(moduleLock); 1.309 + 1.310 + if (slot == NULL) { 1.311 + PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); 1.312 + } 1.313 + return slot; 1.314 +} 1.315 + 1.316 +/* 1.317 + * lookup the Slot module based on it's module ID and slot ID. 1.318 + */ 1.319 +PK11SlotInfo * 1.320 +SECMOD_LookupSlot(SECMODModuleID moduleID,CK_SLOT_ID slotID) 1.321 +{ 1.322 + SECMODModule *module; 1.323 + PK11SlotInfo *slot; 1.324 + 1.325 + module = SECMOD_FindModuleByID(moduleID); 1.326 + if (module == NULL) return NULL; 1.327 + 1.328 + slot = SECMOD_FindSlotByID(module, slotID); 1.329 + SECMOD_DestroyModule(module); 1.330 + return slot; 1.331 +} 1.332 + 1.333 + 1.334 +/* 1.335 + * find a module by name or module pointer and delete it off the module list. 1.336 + * optionally remove it from secmod.db. 1.337 + */ 1.338 +SECStatus 1.339 +SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod, 1.340 + int *type, PRBool permdb) 1.341 +{ 1.342 + SECMODModuleList *mlp; 1.343 + SECMODModuleList **mlpp; 1.344 + SECStatus rv = SECFailure; 1.345 + 1.346 + if (!moduleLock) { 1.347 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.348 + return rv; 1.349 + } 1.350 + 1.351 + *type = SECMOD_EXTERNAL; 1.352 + 1.353 + SECMOD_GetWriteLock(moduleLock); 1.354 + for (mlpp = &modules,mlp = modules; 1.355 + mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { 1.356 + if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) || 1.357 + mod == mlp->module) { 1.358 + /* don't delete the internal module */ 1.359 + if (!mlp->module->internal) { 1.360 + SECMOD_RemoveList(mlpp,mlp); 1.361 + /* delete it after we release the lock */ 1.362 + rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module); 1.363 + } else if (mlp->module->isFIPS) { 1.364 + *type = SECMOD_FIPS; 1.365 + } else { 1.366 + *type = SECMOD_INTERNAL; 1.367 + } 1.368 + break; 1.369 + } 1.370 + } 1.371 + if (mlp) { 1.372 + goto found; 1.373 + } 1.374 + /* not on the internal list, check the unload list */ 1.375 + for (mlpp = &modulesUnload,mlp = modulesUnload; 1.376 + mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { 1.377 + if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) || 1.378 + mod == mlp->module) { 1.379 + /* don't delete the internal module */ 1.380 + if (!mlp->module->internal) { 1.381 + SECMOD_RemoveList(mlpp,mlp); 1.382 + rv = SECSuccess; 1.383 + } else if (mlp->module->isFIPS) { 1.384 + *type = SECMOD_FIPS; 1.385 + } else { 1.386 + *type = SECMOD_INTERNAL; 1.387 + } 1.388 + break; 1.389 + } 1.390 + } 1.391 +found: 1.392 + SECMOD_ReleaseWriteLock(moduleLock); 1.393 + 1.394 + 1.395 + if (rv == SECSuccess) { 1.396 + if (permdb) { 1.397 + SECMOD_DeletePermDB(mlp->module); 1.398 + } 1.399 + SECMOD_DestroyModuleListElement(mlp); 1.400 + } 1.401 + return rv; 1.402 +} 1.403 + 1.404 +/* 1.405 + * find a module by name and delete it off the module list 1.406 + */ 1.407 +SECStatus 1.408 +SECMOD_DeleteModule(const char *name, int *type) 1.409 +{ 1.410 + return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE); 1.411 +} 1.412 + 1.413 +/* 1.414 + * find a module by name and delete it off the module list 1.415 + */ 1.416 +SECStatus 1.417 +SECMOD_DeleteInternalModule(const char *name) 1.418 +{ 1.419 + SECMODModuleList *mlp; 1.420 + SECMODModuleList **mlpp; 1.421 + SECStatus rv = SECFailure; 1.422 + 1.423 + if (pendingModule) { 1.424 + PORT_SetError(SEC_ERROR_MODULE_STUCK); 1.425 + return rv; 1.426 + } 1.427 + if (!moduleLock) { 1.428 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.429 + return rv; 1.430 + } 1.431 + 1.432 + SECMOD_GetWriteLock(moduleLock); 1.433 + for(mlpp = &modules,mlp = modules; 1.434 + mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { 1.435 + if (PORT_Strcmp(name,mlp->module->commonName) == 0) { 1.436 + /* don't delete the internal module */ 1.437 + if (mlp->module->internal) { 1.438 + SECMOD_RemoveList(mlpp,mlp); 1.439 + rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module); 1.440 + } 1.441 + break; 1.442 + } 1.443 + } 1.444 + SECMOD_ReleaseWriteLock(moduleLock); 1.445 + 1.446 + if (rv == SECSuccess) { 1.447 + SECMODModule *newModule,*oldModule; 1.448 + 1.449 + if (mlp->module->isFIPS) { 1.450 + newModule = SECMOD_CreateModule(NULL, SECMOD_INT_NAME, 1.451 + NULL, SECMOD_INT_FLAGS); 1.452 + } else { 1.453 + newModule = SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME, 1.454 + NULL, SECMOD_FIPS_FLAGS); 1.455 + } 1.456 + if (newModule) { 1.457 + PK11SlotInfo *slot; 1.458 + newModule->libraryParams = 1.459 + PORT_ArenaStrdup(newModule->arena,mlp->module->libraryParams); 1.460 + /* if an explicit internal key slot has been set, reset it */ 1.461 + slot = pk11_SwapInternalKeySlot(NULL); 1.462 + if (slot) { 1.463 + secmod_SetInternalKeySlotFlag(newModule, PR_TRUE); 1.464 + } 1.465 + rv = SECMOD_AddModule(newModule); 1.466 + if (rv != SECSuccess) { 1.467 + /* load failed, restore the internal key slot */ 1.468 + pk11_SetInternalKeySlot(slot); 1.469 + SECMOD_DestroyModule(newModule); 1.470 + newModule = NULL; 1.471 + } 1.472 + /* free the old explicit internal key slot, we now have a new one */ 1.473 + if (slot) { 1.474 + PK11_FreeSlot(slot); 1.475 + } 1.476 + } 1.477 + if (newModule == NULL) { 1.478 + SECMODModuleList *last = NULL,*mlp2; 1.479 + /* we're in pretty deep trouble if this happens...Security 1.480 + * not going to work well... try to put the old module back on 1.481 + * the list */ 1.482 + SECMOD_GetWriteLock(moduleLock); 1.483 + for(mlp2 = modules; mlp2 != NULL; mlp2 = mlp->next) { 1.484 + last = mlp2; 1.485 + } 1.486 + 1.487 + if (last == NULL) { 1.488 + modules = mlp; 1.489 + } else { 1.490 + SECMOD_AddList(last,mlp,NULL); 1.491 + } 1.492 + SECMOD_ReleaseWriteLock(moduleLock); 1.493 + return SECFailure; 1.494 + } 1.495 + pendingModule = oldModule = internalModule; 1.496 + internalModule = NULL; 1.497 + SECMOD_DestroyModule(oldModule); 1.498 + SECMOD_DeletePermDB(mlp->module); 1.499 + SECMOD_DestroyModuleListElement(mlp); 1.500 + internalModule = newModule; /* adopt the module */ 1.501 + } 1.502 + return rv; 1.503 +} 1.504 + 1.505 +SECStatus 1.506 +SECMOD_AddModule(SECMODModule *newModule) 1.507 +{ 1.508 + SECStatus rv; 1.509 + SECMODModule *oldModule; 1.510 + 1.511 + /* Test if a module w/ the same name already exists */ 1.512 + /* and return SECWouldBlock if so. */ 1.513 + /* We should probably add a new return value such as */ 1.514 + /* SECDublicateModule, but to minimize ripples, I'll */ 1.515 + /* give SECWouldBlock a new meaning */ 1.516 + if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL) { 1.517 + SECMOD_DestroyModule(oldModule); 1.518 + return SECWouldBlock; 1.519 + /* module already exists. */ 1.520 + } 1.521 + 1.522 + rv = secmod_LoadPKCS11Module(newModule, NULL); 1.523 + if (rv != SECSuccess) { 1.524 + return rv; 1.525 + } 1.526 + 1.527 + if (newModule->parent == NULL) { 1.528 + newModule->parent = SECMOD_ReferenceModule(defaultDBModule); 1.529 + } 1.530 + 1.531 + SECMOD_AddPermDB(newModule); 1.532 + SECMOD_AddModuleToList(newModule); 1.533 + 1.534 + rv = STAN_AddModuleToDefaultTrustDomain(newModule); 1.535 + 1.536 + return rv; 1.537 +} 1.538 + 1.539 +PK11SlotInfo * 1.540 +SECMOD_FindSlot(SECMODModule *module,const char *name) 1.541 +{ 1.542 + int i; 1.543 + char *string; 1.544 + PK11SlotInfo *retSlot = NULL; 1.545 + 1.546 + if (!moduleLock) { 1.547 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.548 + return retSlot; 1.549 + } 1.550 + SECMOD_GetReadLock(moduleLock); 1.551 + for (i=0; i < module->slotCount; i++) { 1.552 + PK11SlotInfo *slot = module->slots[i]; 1.553 + 1.554 + if (PK11_IsPresent(slot)) { 1.555 + string = PK11_GetTokenName(slot); 1.556 + } else { 1.557 + string = PK11_GetSlotName(slot); 1.558 + } 1.559 + if (PORT_Strcmp(name,string) == 0) { 1.560 + retSlot = PK11_ReferenceSlot(slot); 1.561 + break; 1.562 + } 1.563 + } 1.564 + SECMOD_ReleaseReadLock(moduleLock); 1.565 + 1.566 + if (retSlot == NULL) { 1.567 + PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); 1.568 + } 1.569 + return retSlot; 1.570 +} 1.571 + 1.572 +SECStatus 1.573 +PK11_GetModInfo(SECMODModule *mod,CK_INFO *info) 1.574 +{ 1.575 + CK_RV crv; 1.576 + 1.577 + if (mod->functionList == NULL) return SECFailure; 1.578 + crv = PK11_GETTAB(mod)->C_GetInfo(info); 1.579 + if (crv != CKR_OK) { 1.580 + PORT_SetError(PK11_MapError(crv)); 1.581 + } 1.582 + return (crv == CKR_OK) ? SECSuccess : SECFailure; 1.583 +} 1.584 + 1.585 +/* Determine if we have the FIP's module loaded as the default 1.586 + * module to trigger other bogus FIPS requirements in PKCS #12 and 1.587 + * SSL 1.588 + */ 1.589 +PRBool 1.590 +PK11_IsFIPS(void) 1.591 +{ 1.592 + SECMODModule *mod = SECMOD_GetInternalModule(); 1.593 + 1.594 + if (mod && mod->internal) { 1.595 + return mod->isFIPS; 1.596 + } 1.597 + 1.598 + return PR_FALSE; 1.599 +} 1.600 + 1.601 +/* combines NewModule() & AddModule */ 1.602 +/* give a string for the module name & the full-path for the dll, */ 1.603 +/* installs the PKCS11 module & update registry */ 1.604 +SECStatus 1.605 +SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath, 1.606 + unsigned long defaultMechanismFlags, 1.607 + unsigned long cipherEnableFlags, 1.608 + char* modparms, char* nssparms) 1.609 +{ 1.610 + SECMODModule *module; 1.611 + SECStatus result = SECFailure; 1.612 + int s,i; 1.613 + PK11SlotInfo* slot; 1.614 + 1.615 + PR_SetErrorText(0, NULL); 1.616 + if (!moduleLock) { 1.617 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.618 + return result; 1.619 + } 1.620 + 1.621 + module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms); 1.622 + 1.623 + if (module == NULL) { 1.624 + return result; 1.625 + } 1.626 + 1.627 + if (module->dllName != NULL) { 1.628 + if (module->dllName[0] != 0) { 1.629 + result = SECMOD_AddModule(module); 1.630 + if (result == SECSuccess) { 1.631 + /* turn on SSL cipher enable flags */ 1.632 + module->ssl[0] = cipherEnableFlags; 1.633 + 1.634 + SECMOD_GetReadLock(moduleLock); 1.635 + /* check each slot to turn on appropriate mechanisms */ 1.636 + for (s = 0; s < module->slotCount; s++) { 1.637 + slot = (module->slots)[s]; 1.638 + /* for each possible mechanism */ 1.639 + for (i=0; i < num_pk11_default_mechanisms; i++) { 1.640 + /* we are told to turn it on by default ? */ 1.641 + PRBool add = 1.642 + (PK11_DefaultArray[i].flag & defaultMechanismFlags) ? 1.643 + PR_TRUE: PR_FALSE; 1.644 + result = PK11_UpdateSlotAttribute(slot, 1.645 + &(PK11_DefaultArray[i]), add); 1.646 + } /* for each mechanism */ 1.647 + /* disable each slot if the defaultFlags say so */ 1.648 + if (defaultMechanismFlags & PK11_DISABLE_FLAG) { 1.649 + PK11_UserDisableSlot(slot); 1.650 + } 1.651 + } /* for each slot of this module */ 1.652 + SECMOD_ReleaseReadLock(moduleLock); 1.653 + 1.654 + /* delete and re-add module in order to save changes 1.655 + * to the module */ 1.656 + result = SECMOD_UpdateModule(module); 1.657 + } 1.658 + } 1.659 + } 1.660 + SECMOD_DestroyModule(module); 1.661 + return result; 1.662 +} 1.663 + 1.664 +SECStatus 1.665 +SECMOD_AddNewModule(const char* moduleName, const char* dllPath, 1.666 + unsigned long defaultMechanismFlags, 1.667 + unsigned long cipherEnableFlags) 1.668 +{ 1.669 + return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags, 1.670 + cipherEnableFlags, 1.671 + NULL, NULL); /* don't pass module or nss params */ 1.672 +} 1.673 + 1.674 +SECStatus 1.675 +SECMOD_UpdateModule(SECMODModule *module) 1.676 +{ 1.677 + SECStatus result; 1.678 + 1.679 + result = SECMOD_DeletePermDB(module); 1.680 + 1.681 + if (result == SECSuccess) { 1.682 + result = SECMOD_AddPermDB(module); 1.683 + } 1.684 + return result; 1.685 +} 1.686 + 1.687 +/* Public & Internal(Security Library) representation of 1.688 + * encryption mechanism flags conversion */ 1.689 + 1.690 +/* Currently, the only difference is that internal representation 1.691 + * puts RANDOM_FLAG at bit 31 (Most-significant bit), but 1.692 + * public representation puts this bit at bit 28 1.693 + */ 1.694 +unsigned long 1.695 +SECMOD_PubMechFlagstoInternal(unsigned long publicFlags) 1.696 +{ 1.697 + unsigned long internalFlags = publicFlags; 1.698 + 1.699 + if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) { 1.700 + internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG; 1.701 + internalFlags |= SECMOD_RANDOM_FLAG; 1.702 + } 1.703 + return internalFlags; 1.704 +} 1.705 + 1.706 +unsigned long 1.707 +SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) 1.708 +{ 1.709 + unsigned long publicFlags = internalFlags; 1.710 + 1.711 + if (internalFlags & SECMOD_RANDOM_FLAG) { 1.712 + publicFlags &= ~SECMOD_RANDOM_FLAG; 1.713 + publicFlags |= PUBLIC_MECH_RANDOM_FLAG; 1.714 + } 1.715 + return publicFlags; 1.716 +} 1.717 + 1.718 + 1.719 +/* Public & Internal(Security Library) representation of */ 1.720 +/* cipher flags conversion */ 1.721 +/* Note: currently they are just stubs */ 1.722 +unsigned long 1.723 +SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) 1.724 +{ 1.725 + return publicFlags; 1.726 +} 1.727 + 1.728 +unsigned long 1.729 +SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) 1.730 +{ 1.731 + return internalFlags; 1.732 +} 1.733 + 1.734 +/* Funtion reports true if module of modType is installed/configured */ 1.735 +PRBool 1.736 +SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ) 1.737 +{ 1.738 + PRBool result = PR_FALSE; 1.739 + SECMODModuleList *mods; 1.740 + 1.741 + if (!moduleLock) { 1.742 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.743 + return result; 1.744 + } 1.745 + SECMOD_GetReadLock(moduleLock); 1.746 + mods = SECMOD_GetDefaultModuleList(); 1.747 + for ( ; mods != NULL; mods = mods->next) { 1.748 + if (mods->module->ssl[0] & 1.749 + SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) { 1.750 + result = PR_TRUE; 1.751 + } 1.752 + } 1.753 + 1.754 + SECMOD_ReleaseReadLock(moduleLock); 1.755 + return result; 1.756 +} 1.757 + 1.758 +/* create a new ModuleListElement */ 1.759 +SECMODModuleList *SECMOD_NewModuleListElement(void) 1.760 +{ 1.761 + SECMODModuleList *newModList; 1.762 + 1.763 + newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList)); 1.764 + if (newModList) { 1.765 + newModList->next = NULL; 1.766 + newModList->module = NULL; 1.767 + } 1.768 + return newModList; 1.769 +} 1.770 + 1.771 +/* 1.772 + * make a new reference to a module so It doesn't go away on us 1.773 + */ 1.774 +SECMODModule * 1.775 +SECMOD_ReferenceModule(SECMODModule *module) 1.776 +{ 1.777 + PZ_Lock(module->refLock); 1.778 + PORT_Assert(module->refCount > 0); 1.779 + 1.780 + module->refCount++; 1.781 + PZ_Unlock(module->refLock); 1.782 + return module; 1.783 +} 1.784 + 1.785 + 1.786 +/* destroy an existing module */ 1.787 +void 1.788 +SECMOD_DestroyModule(SECMODModule *module) 1.789 +{ 1.790 + PRBool willfree = PR_FALSE; 1.791 + int slotCount; 1.792 + int i; 1.793 + 1.794 + PZ_Lock(module->refLock); 1.795 + if (module->refCount-- == 1) { 1.796 + willfree = PR_TRUE; 1.797 + } 1.798 + PORT_Assert(willfree || (module->refCount > 0)); 1.799 + PZ_Unlock(module->refLock); 1.800 + 1.801 + if (!willfree) { 1.802 + return; 1.803 + } 1.804 + 1.805 + if (module->parent != NULL) { 1.806 + SECMODModule *parent = module->parent; 1.807 + /* paranoia, don't loop forever if the modules are looped */ 1.808 + module->parent = NULL; 1.809 + SECMOD_DestroyModule(parent); 1.810 + } 1.811 + 1.812 + /* slots can't really disappear until our module starts freeing them, 1.813 + * so this check is safe */ 1.814 + slotCount = module->slotCount; 1.815 + if (slotCount == 0) { 1.816 + SECMOD_SlotDestroyModule(module,PR_FALSE); 1.817 + return; 1.818 + } 1.819 + 1.820 + /* now free all out slots, when they are done, they will cause the 1.821 + * module to disappear altogether */ 1.822 + for (i=0 ; i < slotCount; i++) { 1.823 + if (!module->slots[i]->disabled) { 1.824 + PK11_ClearSlotList(module->slots[i]); 1.825 + } 1.826 + PK11_FreeSlot(module->slots[i]); 1.827 + } 1.828 + /* WARNING: once the last slot has been freed is it possible (even likely) 1.829 + * that module is no more... touching it now is a good way to go south */ 1.830 +} 1.831 + 1.832 + 1.833 +/* we can only get here if we've destroyed the module, or some one has 1.834 + * erroneously freed a slot that wasn't referenced. */ 1.835 +void 1.836 +SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) 1.837 +{ 1.838 + PRBool willfree = PR_FALSE; 1.839 + if (fromSlot) { 1.840 + PORT_Assert(module->refCount == 0); 1.841 + PZ_Lock(module->refLock); 1.842 + if (module->slotCount-- == 1) { 1.843 + willfree = PR_TRUE; 1.844 + } 1.845 + PORT_Assert(willfree || (module->slotCount > 0)); 1.846 + PZ_Unlock(module->refLock); 1.847 + if (!willfree) return; 1.848 + } 1.849 + 1.850 + if (module == pendingModule) { 1.851 + pendingModule = NULL; 1.852 + } 1.853 + 1.854 + if (module->loaded) { 1.855 + SECMOD_UnloadModule(module); 1.856 + } 1.857 + PZ_DestroyLock(module->refLock); 1.858 + PORT_FreeArena(module->arena,PR_FALSE); 1.859 + secmod_PrivateModuleCount--; 1.860 +} 1.861 + 1.862 +/* destroy a list element 1.863 + * this destroys a single element, and returns the next element 1.864 + * on the chain. It makes it easy to implement for loops to delete 1.865 + * the chain. It also make deleting a single element easy */ 1.866 +SECMODModuleList * 1.867 +SECMOD_DestroyModuleListElement(SECMODModuleList *element) 1.868 +{ 1.869 + SECMODModuleList *next = element->next; 1.870 + 1.871 + if (element->module) { 1.872 + SECMOD_DestroyModule(element->module); 1.873 + element->module = NULL; 1.874 + } 1.875 + PORT_Free(element); 1.876 + return next; 1.877 +} 1.878 + 1.879 + 1.880 +/* 1.881 + * Destroy an entire module list 1.882 + */ 1.883 +void 1.884 +SECMOD_DestroyModuleList(SECMODModuleList *list) 1.885 +{ 1.886 + SECMODModuleList *lp; 1.887 + 1.888 + for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ; 1.889 +} 1.890 + 1.891 +PRBool 1.892 +SECMOD_CanDeleteInternalModule(void) 1.893 +{ 1.894 + return (PRBool) (pendingModule == NULL); 1.895 +} 1.896 + 1.897 +/* 1.898 + * check to see if the module has added new slots. PKCS 11 v2.20 allows for 1.899 + * modules to add new slots, but never remove them. Slots cannot be added 1.900 + * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent 1.901 + * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently 1.902 + * grow on the caller. It is permissible for the slots to increase between 1.903 + * successive calls with NULL to get the size. 1.904 + */ 1.905 +SECStatus 1.906 +SECMOD_UpdateSlotList(SECMODModule *mod) 1.907 +{ 1.908 + CK_RV crv; 1.909 + CK_ULONG count; 1.910 + CK_ULONG i, oldCount; 1.911 + PRBool freeRef = PR_FALSE; 1.912 + void *mark = NULL; 1.913 + CK_ULONG *slotIDs = NULL; 1.914 + PK11SlotInfo **newSlots = NULL; 1.915 + PK11SlotInfo **oldSlots = NULL; 1.916 + 1.917 + if (!moduleLock) { 1.918 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.919 + return SECFailure; 1.920 + } 1.921 + 1.922 + /* C_GetSlotList is not a session function, make sure 1.923 + * calls are serialized */ 1.924 + PZ_Lock(mod->refLock); 1.925 + freeRef = PR_TRUE; 1.926 + /* see if the number of slots have changed */ 1.927 + crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); 1.928 + if (crv != CKR_OK) { 1.929 + PORT_SetError(PK11_MapError(crv)); 1.930 + goto loser; 1.931 + } 1.932 + /* nothing new, blow out early, we want this function to be quick 1.933 + * and cheap in the normal case */ 1.934 + if (count == mod->slotCount) { 1.935 + PZ_Unlock(mod->refLock); 1.936 + return SECSuccess; 1.937 + } 1.938 + if (count < (CK_ULONG)mod->slotCount) { 1.939 + /* shouldn't happen with a properly functioning PKCS #11 module */ 1.940 + PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); 1.941 + goto loser; 1.942 + } 1.943 + 1.944 + /* get the new slot list */ 1.945 + slotIDs = PORT_NewArray(CK_SLOT_ID, count); 1.946 + if (slotIDs == NULL) { 1.947 + goto loser; 1.948 + } 1.949 + 1.950 + crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); 1.951 + if (crv != CKR_OK) { 1.952 + PORT_SetError(PK11_MapError(crv)); 1.953 + goto loser; 1.954 + } 1.955 + freeRef = PR_FALSE; 1.956 + PZ_Unlock(mod->refLock); 1.957 + mark = PORT_ArenaMark(mod->arena); 1.958 + if (mark == NULL) { 1.959 + goto loser; 1.960 + } 1.961 + newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); 1.962 + 1.963 + /* walk down the new slot ID list returned from the module. We keep 1.964 + * the old slots which match a returned ID, and we initialize the new 1.965 + * slots. */ 1.966 + for (i=0; i < count; i++) { 1.967 + PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); 1.968 + 1.969 + if (!slot) { 1.970 + /* we have a new slot create a new slot data structure */ 1.971 + slot = PK11_NewSlotInfo(mod); 1.972 + if (!slot) { 1.973 + goto loser; 1.974 + } 1.975 + PK11_InitSlot(mod, slotIDs[i], slot); 1.976 + STAN_InitTokenForSlotInfo(NULL, slot); 1.977 + } 1.978 + newSlots[i] = slot; 1.979 + } 1.980 + STAN_ResetTokenInterator(NULL); 1.981 + PORT_Free(slotIDs); 1.982 + slotIDs = NULL; 1.983 + PORT_ArenaUnmark(mod->arena, mark); 1.984 + 1.985 + /* until this point we're still using the old slot list. Now we update 1.986 + * module slot list. We update the slots (array) first then the count, 1.987 + * since we've already guarrenteed that count has increased (just in case 1.988 + * someone is looking at the slots field of module without holding the 1.989 + * moduleLock */ 1.990 + SECMOD_GetWriteLock(moduleLock); 1.991 + oldCount =mod->slotCount; 1.992 + oldSlots = mod->slots; 1.993 + mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is 1.994 + * allocated out of the module arena and won't 1.995 + * be freed until the module is freed */ 1.996 + mod->slotCount = count; 1.997 + SECMOD_ReleaseWriteLock(moduleLock); 1.998 + /* free our old references before forgetting about oldSlot*/ 1.999 + for (i=0; i < oldCount; i++) { 1.1000 + PK11_FreeSlot(oldSlots[i]); 1.1001 + } 1.1002 + return SECSuccess; 1.1003 + 1.1004 +loser: 1.1005 + if (freeRef) { 1.1006 + PZ_Unlock(mod->refLock); 1.1007 + } 1.1008 + if (slotIDs) { 1.1009 + PORT_Free(slotIDs); 1.1010 + } 1.1011 + /* free all the slots we allocated. newSlots are part of the 1.1012 + * mod arena. NOTE: the newSlots array contain both new and old 1.1013 + * slots, but we kept a reference to the old slots when we built the new 1.1014 + * array, so we need to free all the slots in newSlots array. */ 1.1015 + if (newSlots) { 1.1016 + for (i=0; i < count; i++) { 1.1017 + if (newSlots[i] == NULL) { 1.1018 + break; /* hit the last one */ 1.1019 + } 1.1020 + PK11_FreeSlot(newSlots[i]); 1.1021 + } 1.1022 + } 1.1023 + /* must come after freeing newSlots */ 1.1024 + if (mark) { 1.1025 + PORT_ArenaRelease(mod->arena, mark); 1.1026 + } 1.1027 + return SECFailure; 1.1028 +} 1.1029 + 1.1030 +/* 1.1031 + * this handles modules that do not support C_WaitForSlotEvent(). 1.1032 + * The internal flags are stored. Note that C_WaitForSlotEvent() does not 1.1033 + * have a timeout, so we don't have one for handleWaitForSlotEvent() either. 1.1034 + */ 1.1035 +PK11SlotInfo * 1.1036 +secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags, 1.1037 + PRIntervalTime latency) 1.1038 +{ 1.1039 + PRBool removableSlotsFound = PR_FALSE; 1.1040 + int i; 1.1041 + int error = SEC_ERROR_NO_EVENT; 1.1042 + 1.1043 + if (!moduleLock) { 1.1044 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.1045 + return NULL; 1.1046 + } 1.1047 + PZ_Lock(mod->refLock); 1.1048 + if (mod->evControlMask & SECMOD_END_WAIT) { 1.1049 + mod->evControlMask &= ~SECMOD_END_WAIT; 1.1050 + PZ_Unlock(mod->refLock); 1.1051 + PORT_SetError(SEC_ERROR_NO_EVENT); 1.1052 + return NULL; 1.1053 + } 1.1054 + mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT; 1.1055 + while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) { 1.1056 + PZ_Unlock(mod->refLock); 1.1057 + /* now is a good time to see if new slots have been added */ 1.1058 + SECMOD_UpdateSlotList(mod); 1.1059 + 1.1060 + /* loop through all the slots on a module */ 1.1061 + SECMOD_GetReadLock(moduleLock); 1.1062 + for (i=0; i < mod->slotCount; i++) { 1.1063 + PK11SlotInfo *slot = mod->slots[i]; 1.1064 + PRUint16 series; 1.1065 + PRBool present; 1.1066 + 1.1067 + /* perm modules do not change */ 1.1068 + if (slot->isPerm) { 1.1069 + continue; 1.1070 + } 1.1071 + removableSlotsFound = PR_TRUE; 1.1072 + /* simulate the PKCS #11 module flags. are the flags different 1.1073 + * from the last time we called? */ 1.1074 + series = slot->series; 1.1075 + present = PK11_IsPresent(slot); 1.1076 + if ((slot->flagSeries != series) || (slot->flagState != present)) { 1.1077 + slot->flagState = present; 1.1078 + slot->flagSeries = series; 1.1079 + SECMOD_ReleaseReadLock(moduleLock); 1.1080 + PZ_Lock(mod->refLock); 1.1081 + mod->evControlMask &= ~SECMOD_END_WAIT; 1.1082 + PZ_Unlock(mod->refLock); 1.1083 + return PK11_ReferenceSlot(slot); 1.1084 + } 1.1085 + } 1.1086 + SECMOD_ReleaseReadLock(moduleLock); 1.1087 + /* if everything was perm modules, don't lock up forever */ 1.1088 + if ((mod->slotCount !=0) && !removableSlotsFound) { 1.1089 + error =SEC_ERROR_NO_SLOT_SELECTED; 1.1090 + PZ_Lock(mod->refLock); 1.1091 + break; 1.1092 + } 1.1093 + if (flags & CKF_DONT_BLOCK) { 1.1094 + PZ_Lock(mod->refLock); 1.1095 + break; 1.1096 + } 1.1097 + PR_Sleep(latency); 1.1098 + PZ_Lock(mod->refLock); 1.1099 + } 1.1100 + mod->evControlMask &= ~SECMOD_END_WAIT; 1.1101 + PZ_Unlock(mod->refLock); 1.1102 + PORT_SetError(error); 1.1103 + return NULL; 1.1104 +} 1.1105 + 1.1106 +/* 1.1107 + * this function waits for a token event on any slot of a given module 1.1108 + * This function should not be called from more than one thread of the 1.1109 + * same process (though other threads can make other library calls 1.1110 + * on this module while this call is blocked). 1.1111 + */ 1.1112 +PK11SlotInfo * 1.1113 +SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, 1.1114 + PRIntervalTime latency) 1.1115 +{ 1.1116 + CK_SLOT_ID id; 1.1117 + CK_RV crv; 1.1118 + PK11SlotInfo *slot; 1.1119 + 1.1120 + if (!pk11_getFinalizeModulesOption() || 1.1121 + ((mod->cryptokiVersion.major == 2) && 1.1122 + (mod->cryptokiVersion.minor < 1))) { 1.1123 + /* if we are sharing the module with other software in our 1.1124 + * address space, we can't reliably use C_WaitForSlotEvent(), 1.1125 + * and if the module is version 2.0, C_WaitForSlotEvent() doesn't 1.1126 + * exist */ 1.1127 + return secmod_HandleWaitForSlotEvent(mod, flags, latency); 1.1128 + } 1.1129 + /* first the the PKCS #11 call */ 1.1130 + PZ_Lock(mod->refLock); 1.1131 + if (mod->evControlMask & SECMOD_END_WAIT) { 1.1132 + goto end_wait; 1.1133 + } 1.1134 + mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT; 1.1135 + PZ_Unlock(mod->refLock); 1.1136 + crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL); 1.1137 + PZ_Lock(mod->refLock); 1.1138 + mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT; 1.1139 + /* if we are in end wait, short circuit now, don't even risk 1.1140 + * going into secmod_HandleWaitForSlotEvent */ 1.1141 + if (mod->evControlMask & SECMOD_END_WAIT) { 1.1142 + goto end_wait; 1.1143 + } 1.1144 + PZ_Unlock(mod->refLock); 1.1145 + if (crv == CKR_FUNCTION_NOT_SUPPORTED) { 1.1146 + /* module doesn't support that call, simulate it */ 1.1147 + return secmod_HandleWaitForSlotEvent(mod, flags, latency); 1.1148 + } 1.1149 + if (crv != CKR_OK) { 1.1150 + /* we can get this error if finalize was called while we were 1.1151 + * still running. This is the only way to force a C_WaitForSlotEvent() 1.1152 + * to return in PKCS #11. In this case, just return that there 1.1153 + * was no event. */ 1.1154 + if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) { 1.1155 + PORT_SetError(SEC_ERROR_NO_EVENT); 1.1156 + } else { 1.1157 + PORT_SetError(PK11_MapError(crv)); 1.1158 + } 1.1159 + return NULL; 1.1160 + } 1.1161 + slot = SECMOD_FindSlotByID(mod, id); 1.1162 + if (slot == NULL) { 1.1163 + /* possibly a new slot that was added? */ 1.1164 + SECMOD_UpdateSlotList(mod); 1.1165 + slot = SECMOD_FindSlotByID(mod, id); 1.1166 + } 1.1167 + /* if we are in the delay period for the "isPresent" call, reset 1.1168 + * the delay since we know things have probably changed... */ 1.1169 + if (slot && slot->nssToken && slot->nssToken->slot) { 1.1170 + nssSlot_ResetDelay(slot->nssToken->slot); 1.1171 + } 1.1172 + return slot; 1.1173 + 1.1174 + /* must be called with the lock on. */ 1.1175 +end_wait: 1.1176 + mod->evControlMask &= ~SECMOD_END_WAIT; 1.1177 + PZ_Unlock(mod->refLock); 1.1178 + PORT_SetError(SEC_ERROR_NO_EVENT); 1.1179 + return NULL; 1.1180 +} 1.1181 + 1.1182 +/* 1.1183 + * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic 1.1184 + * function, possibly bringing down the pkcs #11 module in question. This 1.1185 + * should be OK because 1) it does reinitialize, and 2) it should only be 1.1186 + * called when we are on our way to tear the whole system down anyway. 1.1187 + */ 1.1188 +SECStatus 1.1189 +SECMOD_CancelWait(SECMODModule *mod) 1.1190 +{ 1.1191 + unsigned long controlMask = mod->evControlMask; 1.1192 + SECStatus rv = SECSuccess; 1.1193 + CK_RV crv; 1.1194 + 1.1195 + PZ_Lock(mod->refLock); 1.1196 + mod->evControlMask |= SECMOD_END_WAIT; 1.1197 + controlMask = mod->evControlMask; 1.1198 + if (controlMask & SECMOD_WAIT_PKCS11_EVENT) { 1.1199 + if (!pk11_getFinalizeModulesOption()) { 1.1200 + /* can't get here unless pk11_getFinalizeModulesOption is set */ 1.1201 + PORT_Assert(0); 1.1202 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.1203 + rv = SECFailure; 1.1204 + goto loser; 1.1205 + } 1.1206 + /* NOTE: this call will drop all transient keys, in progress 1.1207 + * operations, and any authentication. This is the only documented 1.1208 + * way to get WaitForSlotEvent to return. Also note: for non-thread 1.1209 + * safe tokens, we need to hold the module lock, this is not yet at 1.1210 + * system shutdown/startup time, so we need to protect these calls */ 1.1211 + crv = PK11_GETTAB(mod)->C_Finalize(NULL); 1.1212 + /* ok, we slammed the module down, now we need to reinit it in case 1.1213 + * we intend to use it again */ 1.1214 + if (CKR_OK == crv) { 1.1215 + PRBool alreadyLoaded; 1.1216 + secmod_ModuleInit(mod, NULL, &alreadyLoaded); 1.1217 + } else { 1.1218 + /* Finalized failed for some reason, notify the application 1.1219 + * so maybe it has a prayer of recovering... */ 1.1220 + PORT_SetError(PK11_MapError(crv)); 1.1221 + rv = SECFailure; 1.1222 + } 1.1223 + } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) { 1.1224 + mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT; 1.1225 + /* Simulated events will eventually timeout 1.1226 + * and wake up in the loop */ 1.1227 + } 1.1228 +loser: 1.1229 + PZ_Unlock(mod->refLock); 1.1230 + return rv; 1.1231 +} 1.1232 + 1.1233 +/* 1.1234 + * check to see if the module has removable slots that we may need to 1.1235 + * watch for. 1.1236 + */ 1.1237 +PRBool 1.1238 +SECMOD_HasRemovableSlots(SECMODModule *mod) 1.1239 +{ 1.1240 + int i; 1.1241 + PRBool ret = PR_FALSE; 1.1242 + 1.1243 + if (!moduleLock) { 1.1244 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.1245 + return ret; 1.1246 + } 1.1247 + SECMOD_GetReadLock(moduleLock); 1.1248 + for (i=0; i < mod->slotCount; i++) { 1.1249 + PK11SlotInfo *slot = mod->slots[i]; 1.1250 + /* perm modules are not inserted or removed */ 1.1251 + if (slot->isPerm) { 1.1252 + continue; 1.1253 + } 1.1254 + ret = PR_TRUE; 1.1255 + break; 1.1256 + } 1.1257 + if (mod->slotCount == 0 ) { 1.1258 + ret = PR_TRUE; 1.1259 + } 1.1260 + SECMOD_ReleaseReadLock(moduleLock); 1.1261 + return ret; 1.1262 +} 1.1263 + 1.1264 +/* 1.1265 + * helper function to actually create and destroy user defined slots 1.1266 + */ 1.1267 +static SECStatus 1.1268 +secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass, 1.1269 + const char *sendSpec) 1.1270 +{ 1.1271 + CK_OBJECT_HANDLE dummy; 1.1272 + CK_ATTRIBUTE template[2] ; 1.1273 + CK_ATTRIBUTE *attrs = template; 1.1274 + CK_RV crv; 1.1275 + 1.1276 + PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++; 1.1277 + PK11_SETATTRS(attrs, CKA_NETSCAPE_MODULE_SPEC , (unsigned char *)sendSpec, 1.1278 + strlen(sendSpec)+1); attrs++; 1.1279 + 1.1280 + PORT_Assert(attrs-template <= 2); 1.1281 + 1.1282 + 1.1283 + PK11_EnterSlotMonitor(slot); 1.1284 + crv = PK11_CreateNewObject(slot, slot->session, 1.1285 + template, attrs-template, PR_FALSE, &dummy); 1.1286 + PK11_ExitSlotMonitor(slot); 1.1287 + 1.1288 + if (crv != CKR_OK) { 1.1289 + PORT_SetError(PK11_MapError(crv)); 1.1290 + return SECFailure; 1.1291 + } 1.1292 + return SECMOD_UpdateSlotList(slot->module); 1.1293 +} 1.1294 + 1.1295 +/* 1.1296 + * return true if the selected slot ID is not present or doesn't exist 1.1297 + */ 1.1298 +static PRBool 1.1299 +secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID) 1.1300 +{ 1.1301 + PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID); 1.1302 + if (slot) { 1.1303 + PRBool present = PK11_IsPresent(slot); 1.1304 + PK11_FreeSlot(slot); 1.1305 + if (present) { 1.1306 + return PR_FALSE; 1.1307 + } 1.1308 + } 1.1309 + /* it doesn't exist or isn't present, it's available */ 1.1310 + return PR_TRUE; 1.1311 +} 1.1312 + 1.1313 +/* 1.1314 + * Find an unused slot id in module. 1.1315 + */ 1.1316 +static CK_SLOT_ID 1.1317 +secmod_FindFreeSlot(SECMODModule *mod) 1.1318 +{ 1.1319 + CK_SLOT_ID i, minSlotID, maxSlotID; 1.1320 + 1.1321 + /* look for a free slot id on the internal module */ 1.1322 + if (mod->internal && mod->isFIPS) { 1.1323 + minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID; 1.1324 + maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID; 1.1325 + } else { 1.1326 + minSlotID = SFTK_MIN_USER_SLOT_ID; 1.1327 + maxSlotID = SFTK_MAX_USER_SLOT_ID; 1.1328 + } 1.1329 + for (i=minSlotID; i < maxSlotID; i++) { 1.1330 + if (secmod_SlotIsEmpty(mod,i)) { 1.1331 + return i; 1.1332 + } 1.1333 + } 1.1334 + PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); 1.1335 + return (CK_SLOT_ID) -1; 1.1336 +} 1.1337 + 1.1338 +/* 1.1339 + * Attempt to open a new slot. 1.1340 + * 1.1341 + * This works the same os OpenUserDB except it can be called against 1.1342 + * any module that understands the softoken protocol for opening new 1.1343 + * slots, not just the softoken itself. If the selected module does not 1.1344 + * understand the protocol, C_CreateObject will fail with 1.1345 + * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set 1.1346 + * SEC_ERROR_BAD_DATA. 1.1347 + * 1.1348 + * NewSlots can be closed with SECMOD_CloseUserDB(); 1.1349 + * 1.1350 + * Modulespec is module dependent. 1.1351 + */ 1.1352 +PK11SlotInfo * 1.1353 +SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec) 1.1354 +{ 1.1355 + CK_SLOT_ID slotID = 0; 1.1356 + PK11SlotInfo *slot; 1.1357 + char *escSpec; 1.1358 + char *sendSpec; 1.1359 + SECStatus rv; 1.1360 + 1.1361 + slotID = secmod_FindFreeSlot(mod); 1.1362 + if (slotID == (CK_SLOT_ID) -1) { 1.1363 + return NULL; 1.1364 + } 1.1365 + 1.1366 + if (mod->slotCount == 0) { 1.1367 + return NULL; 1.1368 + } 1.1369 + 1.1370 + /* just grab the first slot in the module, any present slot should work */ 1.1371 + slot = PK11_ReferenceSlot(mod->slots[0]); 1.1372 + if (slot == NULL) { 1.1373 + return NULL; 1.1374 + } 1.1375 + 1.1376 + /* we've found the slot, now build the moduleSpec */ 1.1377 + escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']'); 1.1378 + if (escSpec == NULL) { 1.1379 + PK11_FreeSlot(slot); 1.1380 + return NULL; 1.1381 + } 1.1382 + sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec); 1.1383 + PORT_Free(escSpec); 1.1384 + 1.1385 + if (sendSpec == NULL) { 1.1386 + /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */ 1.1387 + PK11_FreeSlot(slot); 1.1388 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1389 + return NULL; 1.1390 + } 1.1391 + rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec); 1.1392 + PR_smprintf_free(sendSpec); 1.1393 + PK11_FreeSlot(slot); 1.1394 + if (rv != SECSuccess) { 1.1395 + return NULL; 1.1396 + } 1.1397 + 1.1398 + slot = SECMOD_FindSlotByID(mod, slotID); 1.1399 + if (slot) { 1.1400 + /* if we are in the delay period for the "isPresent" call, reset 1.1401 + * the delay since we know things have probably changed... */ 1.1402 + if (slot->nssToken && slot->nssToken->slot) { 1.1403 + nssSlot_ResetDelay(slot->nssToken->slot); 1.1404 + } 1.1405 + /* force the slot info structures to properly reset */ 1.1406 + (void)PK11_IsPresent(slot); 1.1407 + } 1.1408 + return slot; 1.1409 +} 1.1410 + 1.1411 +/* 1.1412 + * Open a new database using the softoken. The caller is responsible for making 1.1413 + * sure the module spec is correct and usable. The caller should ask for one 1.1414 + * new database per call if the caller wants to get meaningful information 1.1415 + * about the new database. 1.1416 + * 1.1417 + * moduleSpec is the same data that you would pass to softoken at 1.1418 + * initialization time under the 'tokens' options. For example, if you were 1.1419 + * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']> 1.1420 + * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your 1.1421 + * module spec here. The slot ID will be calculated for you by 1.1422 + * SECMOD_OpenUserDB(). 1.1423 + * 1.1424 + * Typical parameters here are configdir, tokenDescription and flags. 1.1425 + * 1.1426 + * a Full list is below: 1.1427 + * 1.1428 + * 1.1429 + * configDir - The location of the databases for this token. If configDir is 1.1430 + * not specified, and noCertDB and noKeyDB is not specified, the load 1.1431 + * will fail. 1.1432 + * certPrefix - Cert prefix for this token. 1.1433 + * keyPrefix - Prefix for the key database for this token. (if not specified, 1.1434 + * certPrefix will be used). 1.1435 + * tokenDescription - The label value for this token returned in the 1.1436 + * CK_TOKEN_INFO structure with an internationalize string (UTF8). 1.1437 + * This value will be truncated at 32 bytes (no NULL, partial UTF8 1.1438 + * characters dropped). You should specify a user friendly name here 1.1439 + * as this is the value the token will be referred to in most 1.1440 + * application UI's. You should make sure tokenDescription is unique. 1.1441 + * slotDescription - The slotDescription value for this token returned 1.1442 + * in the CK_SLOT_INFO structure with an internationalize string 1.1443 + * (UTF8). This value will be truncated at 64 bytes (no NULL, partial 1.1444 + * UTF8 characters dropped). This name will not change after the 1.1445 + * database is closed. It should have some number to make this unique. 1.1446 + * minPWLen - minimum password length for this token. 1.1447 + * flags - comma separated list of flag values, parsed case-insensitive. 1.1448 + * Valid flags are: 1.1449 + * readOnly - Databases should be opened read only. 1.1450 + * noCertDB - Don't try to open a certificate database. 1.1451 + * noKeyDB - Don't try to open a key database. 1.1452 + * forceOpen - Don't fail to initialize the token if the 1.1453 + * databases could not be opened. 1.1454 + * passwordRequired - zero length passwords are not acceptable 1.1455 + * (valid only if there is a keyDB). 1.1456 + * optimizeSpace - allocate smaller hash tables and lock tables. 1.1457 + * When this flag is not specified, Softoken will allocate 1.1458 + * large tables to prevent lock contention. 1.1459 + */ 1.1460 +PK11SlotInfo * 1.1461 +SECMOD_OpenUserDB(const char *moduleSpec) 1.1462 +{ 1.1463 + SECMODModule *mod; 1.1464 + 1.1465 + if (moduleSpec == NULL) { 1.1466 + return NULL; 1.1467 + } 1.1468 + 1.1469 + /* NOTE: unlike most PK11 function, this does not return a reference 1.1470 + * to the module */ 1.1471 + mod = SECMOD_GetInternalModule(); 1.1472 + if (!mod) { 1.1473 + /* shouldn't happen */ 1.1474 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.1475 + return NULL; 1.1476 + } 1.1477 + return SECMOD_OpenNewSlot(mod, moduleSpec); 1.1478 +} 1.1479 + 1.1480 + 1.1481 +/* 1.1482 + * close an already opened user database. NOTE: the database must be 1.1483 + * in the internal token, and must be one created with SECMOD_OpenUserDB(). 1.1484 + * Once the database is closed, the slot will remain as an empty slot 1.1485 + * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot(). 1.1486 + */ 1.1487 +SECStatus 1.1488 +SECMOD_CloseUserDB(PK11SlotInfo *slot) 1.1489 +{ 1.1490 + SECStatus rv; 1.1491 + char *sendSpec; 1.1492 + 1.1493 + sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID); 1.1494 + if (sendSpec == NULL) { 1.1495 + /* PR_smprintf does not set no memory error */ 1.1496 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1497 + return SECFailure; 1.1498 + } 1.1499 + rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec); 1.1500 + PR_smprintf_free(sendSpec); 1.1501 + /* if we are in the delay period for the "isPresent" call, reset 1.1502 + * the delay since we know things have probably changed... */ 1.1503 + if (slot->nssToken && slot->nssToken->slot) { 1.1504 + nssSlot_ResetDelay(slot->nssToken->slot); 1.1505 + /* force the slot info structures to properly reset */ 1.1506 + (void)PK11_IsPresent(slot); 1.1507 + } 1.1508 + return rv; 1.1509 +} 1.1510 + 1.1511 +/* 1.1512 + * Restart PKCS #11 modules after a fork(). See secmod.h for more information. 1.1513 + */ 1.1514 +SECStatus 1.1515 +SECMOD_RestartModules(PRBool force) 1.1516 +{ 1.1517 + SECMODModuleList *mlp; 1.1518 + SECStatus rrv = SECSuccess; 1.1519 + int lastError = 0; 1.1520 + 1.1521 + if (!moduleLock) { 1.1522 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.1523 + return SECFailure; 1.1524 + } 1.1525 + 1.1526 + /* Only need to restart the PKCS #11 modules that were initialized */ 1.1527 + SECMOD_GetReadLock(moduleLock); 1.1528 + for (mlp = modules; mlp != NULL; mlp = mlp->next) { 1.1529 + SECMODModule *mod = mlp->module; 1.1530 + CK_ULONG count; 1.1531 + SECStatus rv; 1.1532 + int i; 1.1533 + 1.1534 + /* If the module needs to be reset, do so */ 1.1535 + if (force || (PK11_GETTAB(mod)-> 1.1536 + C_GetSlotList(CK_FALSE, NULL, &count) != CKR_OK)) { 1.1537 + PRBool alreadyLoaded; 1.1538 + /* first call Finalize. This is not required by PKCS #11, but some 1.1539 + * older modules require it, and it doesn't hurt (compliant modules 1.1540 + * will return CKR_NOT_INITIALIZED */ 1.1541 + (void) PK11_GETTAB(mod)->C_Finalize(NULL); 1.1542 + /* now initialize the module, this function reinitializes 1.1543 + * a module in place, preserving existing slots (even if they 1.1544 + * no longer exist) */ 1.1545 + rv = secmod_ModuleInit(mod, NULL, &alreadyLoaded); 1.1546 + if (rv != SECSuccess) { 1.1547 + /* save the last error code */ 1.1548 + lastError = PORT_GetError(); 1.1549 + rrv = rv; 1.1550 + /* couldn't reinit the module, disable all its slots */ 1.1551 + for (i=0; i < mod->slotCount; i++) { 1.1552 + mod->slots[i]->disabled = PR_TRUE; 1.1553 + mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; 1.1554 + } 1.1555 + continue; 1.1556 + } 1.1557 + for (i=0; i < mod->slotCount; i++) { 1.1558 + /* get new token sessions, bump the series up so that 1.1559 + * we refresh other old sessions. This will tell much of 1.1560 + * NSS to flush cached handles it may hold as well */ 1.1561 + rv = PK11_InitToken(mod->slots[i],PR_TRUE); 1.1562 + /* PK11_InitToken could fail if the slot isn't present. 1.1563 + * If it is present, though, something is wrong and we should 1.1564 + * disable the slot and let the caller know. */ 1.1565 + if (rv != SECSuccess && PK11_IsPresent(mod->slots[i])) { 1.1566 + /* save the last error code */ 1.1567 + lastError = PORT_GetError(); 1.1568 + rrv = rv; 1.1569 + /* disable the token */ 1.1570 + mod->slots[i]->disabled = PR_TRUE; 1.1571 + mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; 1.1572 + } 1.1573 + } 1.1574 + } 1.1575 + } 1.1576 + SECMOD_ReleaseReadLock(moduleLock); 1.1577 + 1.1578 + /* 1.1579 + * on multiple failures, we are only returning the lastError. The caller 1.1580 + * can determine which slots are bad by calling PK11_IsDisabled(). 1.1581 + */ 1.1582 + if (rrv != SECSuccess) { 1.1583 + /* restore the last error code */ 1.1584 + PORT_SetError(lastError); 1.1585 + } 1.1586 + 1.1587 + return rrv; 1.1588 +}