| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 /* | |
| 5 * Initialize the PCKS 11 subsystem | |
| 6 */ | |
| 7 #include "seccomon.h" | |
| 8 #include "secmod.h" | |
| 9 #include "nssilock.h" | |
| 10 #include "secmodi.h" | |
| 11 #include "secmodti.h" | |
| 12 #include "pk11func.h" | |
| 13 #include "pki3hack.h" | |
| 14 #include "secerr.h" | |
| 15 #include "dev.h" | |
| 16 #include "utilpars.h" | |
| 17 | |
| 18 /* these are for displaying error messages */ | |
| 19 | |
| 20 static SECMODModuleList *modules = NULL; | |
| 21 static SECMODModuleList *modulesDB = NULL; | |
| 22 static SECMODModuleList *modulesUnload = NULL; | |
| 23 static SECMODModule *internalModule = NULL; | |
| 24 static SECMODModule *defaultDBModule = NULL; | |
| 25 static SECMODModule *pendingModule = NULL; | |
| 26 static SECMODListLock *moduleLock = NULL; | |
| 27 | |
| 28 int secmod_PrivateModuleCount = 0; | |
| 29 | |
| 30 extern const PK11DefaultArrayEntry PK11_DefaultArray[]; | |
| 31 extern const int num_pk11_default_mechanisms; | |
| 32 | |
| 33 | |
| 34 void | |
| 35 SECMOD_Init() | |
| 36 { | |
| 37 /* don't initialize twice */ | |
| 38 if (moduleLock) return; | |
| 39 | |
| 40 moduleLock = SECMOD_NewListLock(); | |
| 41 PK11_InitSlotLists(); | |
| 42 } | |
| 43 | |
| 44 | |
| 45 SECStatus | |
| 46 SECMOD_Shutdown() | |
| 47 { | |
| 48 /* destroy the lock */ | |
| 49 if (moduleLock) { | |
| 50 SECMOD_DestroyListLock(moduleLock); | |
| 51 moduleLock = NULL; | |
| 52 } | |
| 53 /* free the internal module */ | |
| 54 if (internalModule) { | |
| 55 SECMOD_DestroyModule(internalModule); | |
| 56 internalModule = NULL; | |
| 57 } | |
| 58 | |
| 59 /* free the default database module */ | |
| 60 if (defaultDBModule) { | |
| 61 SECMOD_DestroyModule(defaultDBModule); | |
| 62 defaultDBModule = NULL; | |
| 63 } | |
| 64 | |
| 65 /* destroy the list */ | |
| 66 if (modules) { | |
| 67 SECMOD_DestroyModuleList(modules); | |
| 68 modules = NULL; | |
| 69 } | |
| 70 | |
| 71 if (modulesDB) { | |
| 72 SECMOD_DestroyModuleList(modulesDB); | |
| 73 modulesDB = NULL; | |
| 74 } | |
| 75 | |
| 76 if (modulesUnload) { | |
| 77 SECMOD_DestroyModuleList(modulesUnload); | |
| 78 modulesUnload = NULL; | |
| 79 } | |
| 80 | |
| 81 /* make all the slots and the lists go away */ | |
| 82 PK11_DestroySlotLists(); | |
| 83 | |
| 84 nss_DumpModuleLog(); | |
| 85 | |
| 86 #ifdef DEBUG | |
| 87 if (PR_GetEnvSecure("NSS_STRICT_SHUTDOWN")) { | |
| 88 PORT_Assert(secmod_PrivateModuleCount == 0); | |
| 89 } | |
| 90 #endif | |
| 91 if (secmod_PrivateModuleCount) { | |
| 92 PORT_SetError(SEC_ERROR_BUSY); | |
| 93 return SECFailure; | |
| 94 } | |
| 95 return SECSuccess; | |
| 96 } | |
| 97 | |
| 98 | |
| 99 /* | |
| 100 * retrieve the internal module | |
| 101 */ | |
| 102 SECMODModule * | |
| 103 SECMOD_GetInternalModule(void) | |
| 104 { | |
| 105 return internalModule; | |
| 106 } | |
| 107 | |
| 108 | |
| 109 SECStatus | |
| 110 secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule) | |
| 111 { | |
| 112 SECMODModuleList *mlp, *newListElement, *last = NULL; | |
| 113 | |
| 114 newListElement = SECMOD_NewModuleListElement(); | |
| 115 if (newListElement == NULL) { | |
| 116 return SECFailure; | |
| 117 } | |
| 118 | |
| 119 newListElement->module = SECMOD_ReferenceModule(newModule); | |
| 120 | |
| 121 SECMOD_GetWriteLock(moduleLock); | |
| 122 /* Added it to the end (This is very inefficient, but Adding a module | |
| 123 * on the fly should happen maybe 2-3 times through the life this program | |
| 124 * on a given computer, and this list should be *SHORT*. */ | |
| 125 for(mlp = *moduleList; mlp != NULL; mlp = mlp->next) { | |
| 126 last = mlp; | |
| 127 } | |
| 128 | |
| 129 if (last == NULL) { | |
| 130 *moduleList = newListElement; | |
| 131 } else { | |
| 132 SECMOD_AddList(last,newListElement,NULL); | |
| 133 } | |
| 134 SECMOD_ReleaseWriteLock(moduleLock); | |
| 135 return SECSuccess; | |
| 136 } | |
| 137 | |
| 138 SECStatus | |
| 139 SECMOD_AddModuleToList(SECMODModule *newModule) | |
| 140 { | |
| 141 if (newModule->internal && !internalModule) { | |
| 142 internalModule = SECMOD_ReferenceModule(newModule); | |
| 143 } | |
| 144 return secmod_AddModuleToList(&modules,newModule); | |
| 145 } | |
| 146 | |
| 147 SECStatus | |
| 148 SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule) | |
| 149 { | |
| 150 if (defaultDBModule && SECMOD_GetDefaultModDBFlag(newModule)) { | |
| 151 SECMOD_DestroyModule(defaultDBModule); | |
| 152 defaultDBModule = SECMOD_ReferenceModule(newModule); | |
| 153 } else if (defaultDBModule == NULL) { | |
| 154 defaultDBModule = SECMOD_ReferenceModule(newModule); | |
| 155 } | |
| 156 return secmod_AddModuleToList(&modulesDB,newModule); | |
| 157 } | |
| 158 | |
| 159 SECStatus | |
| 160 SECMOD_AddModuleToUnloadList(SECMODModule *newModule) | |
| 161 { | |
| 162 return secmod_AddModuleToList(&modulesUnload,newModule); | |
| 163 } | |
| 164 | |
| 165 /* | |
| 166 * get the list of PKCS11 modules that are available. | |
| 167 */ | |
| 168 SECMODModuleList * SECMOD_GetDefaultModuleList() { return modules; } | |
| 169 SECMODModuleList *SECMOD_GetDeadModuleList() { return modulesUnload; } | |
| 170 SECMODModuleList *SECMOD_GetDBModuleList() { return modulesDB; } | |
| 171 | |
| 172 /* | |
| 173 * This lock protects the global module lists. | |
| 174 * it also protects changes to the slot array (module->slots[]) and slot count | |
| 175 * (module->slotCount) in each module. It is a read/write lock with multiple | |
| 176 * readers or one writer. Writes are uncommon. | |
| 177 * Because of legacy considerations protection of the slot array and count is | |
| 178 * only necessary in applications if the application calls | |
| 179 * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new | |
| 180 * applications are encouraged to acquire this lock when reading the | |
| 181 * slot array information directly. | |
| 182 */ | |
| 183 SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; } | |
| 184 | |
| 185 | |
| 186 | |
| 187 /* | |
| 188 * find a module by name, and add a reference to it. | |
| 189 * return that module. | |
| 190 */ | |
| 191 SECMODModule * | |
| 192 SECMOD_FindModule(const char *name) | |
| 193 { | |
| 194 SECMODModuleList *mlp; | |
| 195 SECMODModule *module = NULL; | |
| 196 | |
| 197 if (!moduleLock) { | |
| 198 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 199 return module; | |
| 200 } | |
| 201 SECMOD_GetReadLock(moduleLock); | |
| 202 for(mlp = modules; mlp != NULL; mlp = mlp->next) { | |
| 203 if (PORT_Strcmp(name,mlp->module->commonName) == 0) { | |
| 204 module = mlp->module; | |
| 205 SECMOD_ReferenceModule(module); | |
| 206 break; | |
| 207 } | |
| 208 } | |
| 209 if (module) { | |
| 210 goto found; | |
| 211 } | |
| 212 for(mlp = modulesUnload; mlp != NULL; mlp = mlp->next) { | |
| 213 if (PORT_Strcmp(name,mlp->module->commonName) == 0) { | |
| 214 module = mlp->module; | |
| 215 SECMOD_ReferenceModule(module); | |
| 216 break; | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 found: | |
| 221 SECMOD_ReleaseReadLock(moduleLock); | |
| 222 | |
| 223 return module; | |
| 224 } | |
| 225 | |
| 226 /* | |
| 227 * find a module by ID, and add a reference to it. | |
| 228 * return that module. | |
| 229 */ | |
| 230 SECMODModule * | |
| 231 SECMOD_FindModuleByID(SECMODModuleID id) | |
| 232 { | |
| 233 SECMODModuleList *mlp; | |
| 234 SECMODModule *module = NULL; | |
| 235 | |
| 236 if (!moduleLock) { | |
| 237 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 238 return module; | |
| 239 } | |
| 240 SECMOD_GetReadLock(moduleLock); | |
| 241 for(mlp = modules; mlp != NULL; mlp = mlp->next) { | |
| 242 if (id == mlp->module->moduleID) { | |
| 243 module = mlp->module; | |
| 244 SECMOD_ReferenceModule(module); | |
| 245 break; | |
| 246 } | |
| 247 } | |
| 248 SECMOD_ReleaseReadLock(moduleLock); | |
| 249 if (module == NULL) { | |
| 250 PORT_SetError(SEC_ERROR_NO_MODULE); | |
| 251 } | |
| 252 return module; | |
| 253 } | |
| 254 | |
| 255 /* | |
| 256 * find the function pointer. | |
| 257 */ | |
| 258 SECMODModule * | |
| 259 secmod_FindModuleByFuncPtr(void *funcPtr) | |
| 260 { | |
| 261 SECMODModuleList *mlp; | |
| 262 SECMODModule *module = NULL; | |
| 263 | |
| 264 SECMOD_GetReadLock(moduleLock); | |
| 265 for(mlp = modules; mlp != NULL; mlp = mlp->next) { | |
| 266 /* paranoia, shouldn't ever happen */ | |
| 267 if (!mlp->module) { | |
| 268 continue; | |
| 269 } | |
| 270 if (funcPtr == mlp->module->functionList) { | |
| 271 module = mlp->module; | |
| 272 SECMOD_ReferenceModule(module); | |
| 273 break; | |
| 274 } | |
| 275 } | |
| 276 SECMOD_ReleaseReadLock(moduleLock); | |
| 277 if (module == NULL) { | |
| 278 PORT_SetError(SEC_ERROR_NO_MODULE); | |
| 279 } | |
| 280 return module; | |
| 281 } | |
| 282 | |
| 283 /* | |
| 284 * Find the Slot based on ID and the module. | |
| 285 */ | |
| 286 PK11SlotInfo * | |
| 287 SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID) | |
| 288 { | |
| 289 int i; | |
| 290 PK11SlotInfo *slot = NULL; | |
| 291 | |
| 292 if (!moduleLock) { | |
| 293 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 294 return slot; | |
| 295 } | |
| 296 SECMOD_GetReadLock(moduleLock); | |
| 297 for (i=0; i < module->slotCount; i++) { | |
| 298 PK11SlotInfo *cSlot = module->slots[i]; | |
| 299 | |
| 300 if (cSlot->slotID == slotID) { | |
| 301 slot = PK11_ReferenceSlot(cSlot); | |
| 302 break; | |
| 303 } | |
| 304 } | |
| 305 SECMOD_ReleaseReadLock(moduleLock); | |
| 306 | |
| 307 if (slot == NULL) { | |
| 308 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); | |
| 309 } | |
| 310 return slot; | |
| 311 } | |
| 312 | |
| 313 /* | |
| 314 * lookup the Slot module based on it's module ID and slot ID. | |
| 315 */ | |
| 316 PK11SlotInfo * | |
| 317 SECMOD_LookupSlot(SECMODModuleID moduleID,CK_SLOT_ID slotID) | |
| 318 { | |
| 319 SECMODModule *module; | |
| 320 PK11SlotInfo *slot; | |
| 321 | |
| 322 module = SECMOD_FindModuleByID(moduleID); | |
| 323 if (module == NULL) return NULL; | |
| 324 | |
| 325 slot = SECMOD_FindSlotByID(module, slotID); | |
| 326 SECMOD_DestroyModule(module); | |
| 327 return slot; | |
| 328 } | |
| 329 | |
| 330 | |
| 331 /* | |
| 332 * find a module by name or module pointer and delete it off the module list. | |
| 333 * optionally remove it from secmod.db. | |
| 334 */ | |
| 335 SECStatus | |
| 336 SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod, | |
| 337 int *type, PRBool permdb) | |
| 338 { | |
| 339 SECMODModuleList *mlp; | |
| 340 SECMODModuleList **mlpp; | |
| 341 SECStatus rv = SECFailure; | |
| 342 | |
| 343 if (!moduleLock) { | |
| 344 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 345 return rv; | |
| 346 } | |
| 347 | |
| 348 *type = SECMOD_EXTERNAL; | |
| 349 | |
| 350 SECMOD_GetWriteLock(moduleLock); | |
| 351 for (mlpp = &modules,mlp = modules; | |
| 352 mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { | |
| 353 if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) || | |
| 354 mod == mlp->module) { | |
| 355 /* don't delete the internal module */ | |
| 356 if (!mlp->module->internal) { | |
| 357 SECMOD_RemoveList(mlpp,mlp); | |
| 358 /* delete it after we release the lock */ | |
| 359 rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module); | |
| 360 } else if (mlp->module->isFIPS) { | |
| 361 *type = SECMOD_FIPS; | |
| 362 } else { | |
| 363 *type = SECMOD_INTERNAL; | |
| 364 } | |
| 365 break; | |
| 366 } | |
| 367 } | |
| 368 if (mlp) { | |
| 369 goto found; | |
| 370 } | |
| 371 /* not on the internal list, check the unload list */ | |
| 372 for (mlpp = &modulesUnload,mlp = modulesUnload; | |
| 373 mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { | |
| 374 if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) || | |
| 375 mod == mlp->module) { | |
| 376 /* don't delete the internal module */ | |
| 377 if (!mlp->module->internal) { | |
| 378 SECMOD_RemoveList(mlpp,mlp); | |
| 379 rv = SECSuccess; | |
| 380 } else if (mlp->module->isFIPS) { | |
| 381 *type = SECMOD_FIPS; | |
| 382 } else { | |
| 383 *type = SECMOD_INTERNAL; | |
| 384 } | |
| 385 break; | |
| 386 } | |
| 387 } | |
| 388 found: | |
| 389 SECMOD_ReleaseWriteLock(moduleLock); | |
| 390 | |
| 391 | |
| 392 if (rv == SECSuccess) { | |
| 393 if (permdb) { | |
| 394 SECMOD_DeletePermDB(mlp->module); | |
| 395 } | |
| 396 SECMOD_DestroyModuleListElement(mlp); | |
| 397 } | |
| 398 return rv; | |
| 399 } | |
| 400 | |
| 401 /* | |
| 402 * find a module by name and delete it off the module list | |
| 403 */ | |
| 404 SECStatus | |
| 405 SECMOD_DeleteModule(const char *name, int *type) | |
| 406 { | |
| 407 return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE); | |
| 408 } | |
| 409 | |
| 410 /* | |
| 411 * find a module by name and delete it off the module list | |
| 412 */ | |
| 413 SECStatus | |
| 414 SECMOD_DeleteInternalModule(const char *name) | |
| 415 { | |
| 416 SECMODModuleList *mlp; | |
| 417 SECMODModuleList **mlpp; | |
| 418 SECStatus rv = SECFailure; | |
| 419 | |
| 420 if (pendingModule) { | |
| 421 PORT_SetError(SEC_ERROR_MODULE_STUCK); | |
| 422 return rv; | |
| 423 } | |
| 424 if (!moduleLock) { | |
| 425 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 426 return rv; | |
| 427 } | |
| 428 | |
| 429 SECMOD_GetWriteLock(moduleLock); | |
| 430 for(mlpp = &modules,mlp = modules; | |
| 431 mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { | |
| 432 if (PORT_Strcmp(name,mlp->module->commonName) == 0) { | |
| 433 /* don't delete the internal module */ | |
| 434 if (mlp->module->internal) { | |
| 435 SECMOD_RemoveList(mlpp,mlp); | |
| 436 rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module); | |
| 437 } | |
| 438 break; | |
| 439 } | |
| 440 } | |
| 441 SECMOD_ReleaseWriteLock(moduleLock); | |
| 442 | |
| 443 if (rv == SECSuccess) { | |
| 444 SECMODModule *newModule,*oldModule; | |
| 445 | |
| 446 if (mlp->module->isFIPS) { | |
| 447 newModule = SECMOD_CreateModule(NULL, SECMOD_INT_NAME, | |
| 448 NULL, SECMOD_INT_FLAGS); | |
| 449 } else { | |
| 450 newModule = SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME, | |
| 451 NULL, SECMOD_FIPS_FLAGS); | |
| 452 } | |
| 453 if (newModule) { | |
| 454 PK11SlotInfo *slot; | |
| 455 newModule->libraryParams = | |
| 456 PORT_ArenaStrdup(newModule->arena,mlp->module->libraryParams); | |
| 457 /* if an explicit internal key slot has been set, reset it */ | |
| 458 slot = pk11_SwapInternalKeySlot(NULL); | |
| 459 if (slot) { | |
| 460 secmod_SetInternalKeySlotFlag(newModule, PR_TRUE); | |
| 461 } | |
| 462 rv = SECMOD_AddModule(newModule); | |
| 463 if (rv != SECSuccess) { | |
| 464 /* load failed, restore the internal key slot */ | |
| 465 pk11_SetInternalKeySlot(slot); | |
| 466 SECMOD_DestroyModule(newModule); | |
| 467 newModule = NULL; | |
| 468 } | |
| 469 /* free the old explicit internal key slot, we now have a new one */ | |
| 470 if (slot) { | |
| 471 PK11_FreeSlot(slot); | |
| 472 } | |
| 473 } | |
| 474 if (newModule == NULL) { | |
| 475 SECMODModuleList *last = NULL,*mlp2; | |
| 476 /* we're in pretty deep trouble if this happens...Security | |
| 477 * not going to work well... try to put the old module back on | |
| 478 * the list */ | |
| 479 SECMOD_GetWriteLock(moduleLock); | |
| 480 for(mlp2 = modules; mlp2 != NULL; mlp2 = mlp->next) { | |
| 481 last = mlp2; | |
| 482 } | |
| 483 | |
| 484 if (last == NULL) { | |
| 485 modules = mlp; | |
| 486 } else { | |
| 487 SECMOD_AddList(last,mlp,NULL); | |
| 488 } | |
| 489 SECMOD_ReleaseWriteLock(moduleLock); | |
| 490 return SECFailure; | |
| 491 } | |
| 492 pendingModule = oldModule = internalModule; | |
| 493 internalModule = NULL; | |
| 494 SECMOD_DestroyModule(oldModule); | |
| 495 SECMOD_DeletePermDB(mlp->module); | |
| 496 SECMOD_DestroyModuleListElement(mlp); | |
| 497 internalModule = newModule; /* adopt the module */ | |
| 498 } | |
| 499 return rv; | |
| 500 } | |
| 501 | |
| 502 SECStatus | |
| 503 SECMOD_AddModule(SECMODModule *newModule) | |
| 504 { | |
| 505 SECStatus rv; | |
| 506 SECMODModule *oldModule; | |
| 507 | |
| 508 /* Test if a module w/ the same name already exists */ | |
| 509 /* and return SECWouldBlock if so. */ | |
| 510 /* We should probably add a new return value such as */ | |
| 511 /* SECDublicateModule, but to minimize ripples, I'll */ | |
| 512 /* give SECWouldBlock a new meaning */ | |
| 513 if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL) { | |
| 514 SECMOD_DestroyModule(oldModule); | |
| 515 return SECWouldBlock; | |
| 516 /* module already exists. */ | |
| 517 } | |
| 518 | |
| 519 rv = secmod_LoadPKCS11Module(newModule, NULL); | |
| 520 if (rv != SECSuccess) { | |
| 521 return rv; | |
| 522 } | |
| 523 | |
| 524 if (newModule->parent == NULL) { | |
| 525 newModule->parent = SECMOD_ReferenceModule(defaultDBModule); | |
| 526 } | |
| 527 | |
| 528 SECMOD_AddPermDB(newModule); | |
| 529 SECMOD_AddModuleToList(newModule); | |
| 530 | |
| 531 rv = STAN_AddModuleToDefaultTrustDomain(newModule); | |
| 532 | |
| 533 return rv; | |
| 534 } | |
| 535 | |
| 536 PK11SlotInfo * | |
| 537 SECMOD_FindSlot(SECMODModule *module,const char *name) | |
| 538 { | |
| 539 int i; | |
| 540 char *string; | |
| 541 PK11SlotInfo *retSlot = NULL; | |
| 542 | |
| 543 if (!moduleLock) { | |
| 544 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 545 return retSlot; | |
| 546 } | |
| 547 SECMOD_GetReadLock(moduleLock); | |
| 548 for (i=0; i < module->slotCount; i++) { | |
| 549 PK11SlotInfo *slot = module->slots[i]; | |
| 550 | |
| 551 if (PK11_IsPresent(slot)) { | |
| 552 string = PK11_GetTokenName(slot); | |
| 553 } else { | |
| 554 string = PK11_GetSlotName(slot); | |
| 555 } | |
| 556 if (PORT_Strcmp(name,string) == 0) { | |
| 557 retSlot = PK11_ReferenceSlot(slot); | |
| 558 break; | |
| 559 } | |
| 560 } | |
| 561 SECMOD_ReleaseReadLock(moduleLock); | |
| 562 | |
| 563 if (retSlot == NULL) { | |
| 564 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); | |
| 565 } | |
| 566 return retSlot; | |
| 567 } | |
| 568 | |
| 569 SECStatus | |
| 570 PK11_GetModInfo(SECMODModule *mod,CK_INFO *info) | |
| 571 { | |
| 572 CK_RV crv; | |
| 573 | |
| 574 if (mod->functionList == NULL) return SECFailure; | |
| 575 crv = PK11_GETTAB(mod)->C_GetInfo(info); | |
| 576 if (crv != CKR_OK) { | |
| 577 PORT_SetError(PK11_MapError(crv)); | |
| 578 } | |
| 579 return (crv == CKR_OK) ? SECSuccess : SECFailure; | |
| 580 } | |
| 581 | |
| 582 /* Determine if we have the FIP's module loaded as the default | |
| 583 * module to trigger other bogus FIPS requirements in PKCS #12 and | |
| 584 * SSL | |
| 585 */ | |
| 586 PRBool | |
| 587 PK11_IsFIPS(void) | |
| 588 { | |
| 589 SECMODModule *mod = SECMOD_GetInternalModule(); | |
| 590 | |
| 591 if (mod && mod->internal) { | |
| 592 return mod->isFIPS; | |
| 593 } | |
| 594 | |
| 595 return PR_FALSE; | |
| 596 } | |
| 597 | |
| 598 /* combines NewModule() & AddModule */ | |
| 599 /* give a string for the module name & the full-path for the dll, */ | |
| 600 /* installs the PKCS11 module & update registry */ | |
| 601 SECStatus | |
| 602 SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath, | |
| 603 unsigned long defaultMechanismFlags, | |
| 604 unsigned long cipherEnableFlags, | |
| 605 char* modparms, char* nssparms) | |
| 606 { | |
| 607 SECMODModule *module; | |
| 608 SECStatus result = SECFailure; | |
| 609 int s,i; | |
| 610 PK11SlotInfo* slot; | |
| 611 | |
| 612 PR_SetErrorText(0, NULL); | |
| 613 if (!moduleLock) { | |
| 614 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 615 return result; | |
| 616 } | |
| 617 | |
| 618 module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms); | |
| 619 | |
| 620 if (module == NULL) { | |
| 621 return result; | |
| 622 } | |
| 623 | |
| 624 if (module->dllName != NULL) { | |
| 625 if (module->dllName[0] != 0) { | |
| 626 result = SECMOD_AddModule(module); | |
| 627 if (result == SECSuccess) { | |
| 628 /* turn on SSL cipher enable flags */ | |
| 629 module->ssl[0] = cipherEnableFlags; | |
| 630 | |
| 631 SECMOD_GetReadLock(moduleLock); | |
| 632 /* check each slot to turn on appropriate mechanisms */ | |
| 633 for (s = 0; s < module->slotCount; s++) { | |
| 634 slot = (module->slots)[s]; | |
| 635 /* for each possible mechanism */ | |
| 636 for (i=0; i < num_pk11_default_mechanisms; i++) { | |
| 637 /* we are told to turn it on by default ? */ | |
| 638 PRBool add = | |
| 639 (PK11_DefaultArray[i].flag & defaultMechanismFlags) ? | |
| 640 PR_TRUE: PR_FALSE; | |
| 641 result = PK11_UpdateSlotAttribute(slot, | |
| 642 &(PK11_DefaultArray[i]), add); | |
| 643 if (result != SECSuccess) { | |
| 644 SECMOD_ReleaseReadLock(moduleLock); | |
| 645 SECMOD_DestroyModule(module); | |
| 646 return result; | |
| 647 } | |
| 648 } /* for each mechanism */ | |
| 649 /* disable each slot if the defaultFlags say so */ | |
| 650 if (defaultMechanismFlags & PK11_DISABLE_FLAG) { | |
| 651 PK11_UserDisableSlot(slot); | |
| 652 } | |
| 653 } /* for each slot of this module */ | |
| 654 SECMOD_ReleaseReadLock(moduleLock); | |
| 655 | |
| 656 /* delete and re-add module in order to save changes | |
| 657 * to the module */ | |
| 658 result = SECMOD_UpdateModule(module); | |
| 659 } | |
| 660 } | |
| 661 } | |
| 662 SECMOD_DestroyModule(module); | |
| 663 return result; | |
| 664 } | |
| 665 | |
| 666 SECStatus | |
| 667 SECMOD_AddNewModule(const char* moduleName, const char* dllPath, | |
| 668 unsigned long defaultMechanismFlags, | |
| 669 unsigned long cipherEnableFlags) | |
| 670 { | |
| 671 return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags, | |
| 672 cipherEnableFlags, | |
| 673 NULL, NULL); /* don't pass module or nss params */ | |
| 674 } | |
| 675 | |
| 676 SECStatus | |
| 677 SECMOD_UpdateModule(SECMODModule *module) | |
| 678 { | |
| 679 SECStatus result; | |
| 680 | |
| 681 result = SECMOD_DeletePermDB(module); | |
| 682 | |
| 683 if (result == SECSuccess) { | |
| 684 result = SECMOD_AddPermDB(module); | |
| 685 } | |
| 686 return result; | |
| 687 } | |
| 688 | |
| 689 /* Public & Internal(Security Library) representation of | |
| 690 * encryption mechanism flags conversion */ | |
| 691 | |
| 692 /* Currently, the only difference is that internal representation | |
| 693 * puts RANDOM_FLAG at bit 31 (Most-significant bit), but | |
| 694 * public representation puts this bit at bit 28 | |
| 695 */ | |
| 696 unsigned long | |
| 697 SECMOD_PubMechFlagstoInternal(unsigned long publicFlags) | |
| 698 { | |
| 699 unsigned long internalFlags = publicFlags; | |
| 700 | |
| 701 if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) { | |
| 702 internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG; | |
| 703 internalFlags |= SECMOD_RANDOM_FLAG; | |
| 704 } | |
| 705 return internalFlags; | |
| 706 } | |
| 707 | |
| 708 unsigned long | |
| 709 SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) | |
| 710 { | |
| 711 unsigned long publicFlags = internalFlags; | |
| 712 | |
| 713 if (internalFlags & SECMOD_RANDOM_FLAG) { | |
| 714 publicFlags &= ~SECMOD_RANDOM_FLAG; | |
| 715 publicFlags |= PUBLIC_MECH_RANDOM_FLAG; | |
| 716 } | |
| 717 return publicFlags; | |
| 718 } | |
| 719 | |
| 720 | |
| 721 /* Public & Internal(Security Library) representation of */ | |
| 722 /* cipher flags conversion */ | |
| 723 /* Note: currently they are just stubs */ | |
| 724 unsigned long | |
| 725 SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) | |
| 726 { | |
| 727 return publicFlags; | |
| 728 } | |
| 729 | |
| 730 unsigned long | |
| 731 SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) | |
| 732 { | |
| 733 return internalFlags; | |
| 734 } | |
| 735 | |
| 736 /* Funtion reports true if module of modType is installed/configured */ | |
| 737 PRBool | |
| 738 SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ) | |
| 739 { | |
| 740 PRBool result = PR_FALSE; | |
| 741 SECMODModuleList *mods; | |
| 742 | |
| 743 if (!moduleLock) { | |
| 744 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 745 return result; | |
| 746 } | |
| 747 SECMOD_GetReadLock(moduleLock); | |
| 748 mods = SECMOD_GetDefaultModuleList(); | |
| 749 for ( ; mods != NULL; mods = mods->next) { | |
| 750 if (mods->module->ssl[0] & | |
| 751 SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) { | |
| 752 result = PR_TRUE; | |
| 753 } | |
| 754 } | |
| 755 | |
| 756 SECMOD_ReleaseReadLock(moduleLock); | |
| 757 return result; | |
| 758 } | |
| 759 | |
| 760 /* create a new ModuleListElement */ | |
| 761 SECMODModuleList *SECMOD_NewModuleListElement(void) | |
| 762 { | |
| 763 SECMODModuleList *newModList; | |
| 764 | |
| 765 newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList)); | |
| 766 if (newModList) { | |
| 767 newModList->next = NULL; | |
| 768 newModList->module = NULL; | |
| 769 } | |
| 770 return newModList; | |
| 771 } | |
| 772 | |
| 773 /* | |
| 774 * make a new reference to a module so It doesn't go away on us | |
| 775 */ | |
| 776 SECMODModule * | |
| 777 SECMOD_ReferenceModule(SECMODModule *module) | |
| 778 { | |
| 779 PZ_Lock(module->refLock); | |
| 780 PORT_Assert(module->refCount > 0); | |
| 781 | |
| 782 module->refCount++; | |
| 783 PZ_Unlock(module->refLock); | |
| 784 return module; | |
| 785 } | |
| 786 | |
| 787 | |
| 788 /* destroy an existing module */ | |
| 789 void | |
| 790 SECMOD_DestroyModule(SECMODModule *module) | |
| 791 { | |
| 792 PRBool willfree = PR_FALSE; | |
| 793 int slotCount; | |
| 794 int i; | |
| 795 | |
| 796 PZ_Lock(module->refLock); | |
| 797 if (module->refCount-- == 1) { | |
| 798 willfree = PR_TRUE; | |
| 799 } | |
| 800 PORT_Assert(willfree || (module->refCount > 0)); | |
| 801 PZ_Unlock(module->refLock); | |
| 802 | |
| 803 if (!willfree) { | |
| 804 return; | |
| 805 } | |
| 806 | |
| 807 if (module->parent != NULL) { | |
| 808 SECMODModule *parent = module->parent; | |
| 809 /* paranoia, don't loop forever if the modules are looped */ | |
| 810 module->parent = NULL; | |
| 811 SECMOD_DestroyModule(parent); | |
| 812 } | |
| 813 | |
| 814 /* slots can't really disappear until our module starts freeing them, | |
| 815 * so this check is safe */ | |
| 816 slotCount = module->slotCount; | |
| 817 if (slotCount == 0) { | |
| 818 SECMOD_SlotDestroyModule(module,PR_FALSE); | |
| 819 return; | |
| 820 } | |
| 821 | |
| 822 /* now free all out slots, when they are done, they will cause the | |
| 823 * module to disappear altogether */ | |
| 824 for (i=0 ; i < slotCount; i++) { | |
| 825 if (!module->slots[i]->disabled) { | |
| 826 PK11_ClearSlotList(module->slots[i]); | |
| 827 } | |
| 828 PK11_FreeSlot(module->slots[i]); | |
| 829 } | |
| 830 /* WARNING: once the last slot has been freed is it possible (even likely) | |
| 831 * that module is no more... touching it now is a good way to go south */ | |
| 832 } | |
| 833 | |
| 834 | |
| 835 /* we can only get here if we've destroyed the module, or some one has | |
| 836 * erroneously freed a slot that wasn't referenced. */ | |
| 837 void | |
| 838 SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) | |
| 839 { | |
| 840 PRBool willfree = PR_FALSE; | |
| 841 if (fromSlot) { | |
| 842 PORT_Assert(module->refCount == 0); | |
| 843 PZ_Lock(module->refLock); | |
| 844 if (module->slotCount-- == 1) { | |
| 845 willfree = PR_TRUE; | |
| 846 } | |
| 847 PORT_Assert(willfree || (module->slotCount > 0)); | |
| 848 PZ_Unlock(module->refLock); | |
| 849 if (!willfree) return; | |
| 850 } | |
| 851 | |
| 852 if (module == pendingModule) { | |
| 853 pendingModule = NULL; | |
| 854 } | |
| 855 | |
| 856 if (module->loaded) { | |
| 857 SECMOD_UnloadModule(module); | |
| 858 } | |
| 859 PZ_DestroyLock(module->refLock); | |
| 860 PORT_FreeArena(module->arena,PR_FALSE); | |
| 861 secmod_PrivateModuleCount--; | |
| 862 } | |
| 863 | |
| 864 /* destroy a list element | |
| 865 * this destroys a single element, and returns the next element | |
| 866 * on the chain. It makes it easy to implement for loops to delete | |
| 867 * the chain. It also make deleting a single element easy */ | |
| 868 SECMODModuleList * | |
| 869 SECMOD_DestroyModuleListElement(SECMODModuleList *element) | |
| 870 { | |
| 871 SECMODModuleList *next = element->next; | |
| 872 | |
| 873 if (element->module) { | |
| 874 SECMOD_DestroyModule(element->module); | |
| 875 element->module = NULL; | |
| 876 } | |
| 877 PORT_Free(element); | |
| 878 return next; | |
| 879 } | |
| 880 | |
| 881 | |
| 882 /* | |
| 883 * Destroy an entire module list | |
| 884 */ | |
| 885 void | |
| 886 SECMOD_DestroyModuleList(SECMODModuleList *list) | |
| 887 { | |
| 888 SECMODModuleList *lp; | |
| 889 | |
| 890 for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ; | |
| 891 } | |
| 892 | |
| 893 PRBool | |
| 894 SECMOD_CanDeleteInternalModule(void) | |
| 895 { | |
| 896 return (PRBool) (pendingModule == NULL); | |
| 897 } | |
| 898 | |
| 899 /* | |
| 900 * check to see if the module has added new slots. PKCS 11 v2.20 allows for | |
| 901 * modules to add new slots, but never remove them. Slots cannot be added | |
| 902 * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent | |
| 903 * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently | |
| 904 * grow on the caller. It is permissible for the slots to increase between | |
| 905 * successive calls with NULL to get the size. | |
| 906 */ | |
| 907 SECStatus | |
| 908 SECMOD_UpdateSlotList(SECMODModule *mod) | |
| 909 { | |
| 910 CK_RV crv; | |
| 911 CK_ULONG count; | |
| 912 CK_ULONG i, oldCount; | |
| 913 PRBool freeRef = PR_FALSE; | |
| 914 void *mark = NULL; | |
| 915 CK_ULONG *slotIDs = NULL; | |
| 916 PK11SlotInfo **newSlots = NULL; | |
| 917 PK11SlotInfo **oldSlots = NULL; | |
| 918 | |
| 919 if (!moduleLock) { | |
| 920 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 921 return SECFailure; | |
| 922 } | |
| 923 | |
| 924 /* C_GetSlotList is not a session function, make sure | |
| 925 * calls are serialized */ | |
| 926 PZ_Lock(mod->refLock); | |
| 927 freeRef = PR_TRUE; | |
| 928 /* see if the number of slots have changed */ | |
| 929 crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); | |
| 930 if (crv != CKR_OK) { | |
| 931 PORT_SetError(PK11_MapError(crv)); | |
| 932 goto loser; | |
| 933 } | |
| 934 /* nothing new, blow out early, we want this function to be quick | |
| 935 * and cheap in the normal case */ | |
| 936 if (count == mod->slotCount) { | |
| 937 PZ_Unlock(mod->refLock); | |
| 938 return SECSuccess; | |
| 939 } | |
| 940 if (count < (CK_ULONG)mod->slotCount) { | |
| 941 /* shouldn't happen with a properly functioning PKCS #11 module */ | |
| 942 PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); | |
| 943 goto loser; | |
| 944 } | |
| 945 | |
| 946 /* get the new slot list */ | |
| 947 slotIDs = PORT_NewArray(CK_SLOT_ID, count); | |
| 948 if (slotIDs == NULL) { | |
| 949 goto loser; | |
| 950 } | |
| 951 | |
| 952 crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); | |
| 953 if (crv != CKR_OK) { | |
| 954 PORT_SetError(PK11_MapError(crv)); | |
| 955 goto loser; | |
| 956 } | |
| 957 freeRef = PR_FALSE; | |
| 958 PZ_Unlock(mod->refLock); | |
| 959 mark = PORT_ArenaMark(mod->arena); | |
| 960 if (mark == NULL) { | |
| 961 goto loser; | |
| 962 } | |
| 963 newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); | |
| 964 | |
| 965 /* walk down the new slot ID list returned from the module. We keep | |
| 966 * the old slots which match a returned ID, and we initialize the new | |
| 967 * slots. */ | |
| 968 for (i=0; i < count; i++) { | |
| 969 PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); | |
| 970 | |
| 971 if (!slot) { | |
| 972 /* we have a new slot create a new slot data structure */ | |
| 973 slot = PK11_NewSlotInfo(mod); | |
| 974 if (!slot) { | |
| 975 goto loser; | |
| 976 } | |
| 977 PK11_InitSlot(mod, slotIDs[i], slot); | |
| 978 STAN_InitTokenForSlotInfo(NULL, slot); | |
| 979 } | |
| 980 newSlots[i] = slot; | |
| 981 } | |
| 982 STAN_ResetTokenInterator(NULL); | |
| 983 PORT_Free(slotIDs); | |
| 984 slotIDs = NULL; | |
| 985 PORT_ArenaUnmark(mod->arena, mark); | |
| 986 | |
| 987 /* until this point we're still using the old slot list. Now we update | |
| 988 * module slot list. We update the slots (array) first then the count, | |
| 989 * since we've already guarrenteed that count has increased (just in case | |
| 990 * someone is looking at the slots field of module without holding the | |
| 991 * moduleLock */ | |
| 992 SECMOD_GetWriteLock(moduleLock); | |
| 993 oldCount =mod->slotCount; | |
| 994 oldSlots = mod->slots; | |
| 995 mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is | |
| 996 * allocated out of the module arena and won't | |
| 997 * be freed until the module is freed */ | |
| 998 mod->slotCount = count; | |
| 999 SECMOD_ReleaseWriteLock(moduleLock); | |
| 1000 /* free our old references before forgetting about oldSlot*/ | |
| 1001 for (i=0; i < oldCount; i++) { | |
| 1002 PK11_FreeSlot(oldSlots[i]); | |
| 1003 } | |
| 1004 return SECSuccess; | |
| 1005 | |
| 1006 loser: | |
| 1007 if (freeRef) { | |
| 1008 PZ_Unlock(mod->refLock); | |
| 1009 } | |
| 1010 if (slotIDs) { | |
| 1011 PORT_Free(slotIDs); | |
| 1012 } | |
| 1013 /* free all the slots we allocated. newSlots are part of the | |
| 1014 * mod arena. NOTE: the newSlots array contain both new and old | |
| 1015 * slots, but we kept a reference to the old slots when we built the new | |
| 1016 * array, so we need to free all the slots in newSlots array. */ | |
| 1017 if (newSlots) { | |
| 1018 for (i=0; i < count; i++) { | |
| 1019 if (newSlots[i] == NULL) { | |
| 1020 break; /* hit the last one */ | |
| 1021 } | |
| 1022 PK11_FreeSlot(newSlots[i]); | |
| 1023 } | |
| 1024 } | |
| 1025 /* must come after freeing newSlots */ | |
| 1026 if (mark) { | |
| 1027 PORT_ArenaRelease(mod->arena, mark); | |
| 1028 } | |
| 1029 return SECFailure; | |
| 1030 } | |
| 1031 | |
| 1032 /* | |
| 1033 * this handles modules that do not support C_WaitForSlotEvent(). | |
| 1034 * The internal flags are stored. Note that C_WaitForSlotEvent() does not | |
| 1035 * have a timeout, so we don't have one for handleWaitForSlotEvent() either. | |
| 1036 */ | |
| 1037 PK11SlotInfo * | |
| 1038 secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags, | |
| 1039 PRIntervalTime latency) | |
| 1040 { | |
| 1041 PRBool removableSlotsFound = PR_FALSE; | |
| 1042 int i; | |
| 1043 int error = SEC_ERROR_NO_EVENT; | |
| 1044 | |
| 1045 if (!moduleLock) { | |
| 1046 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 1047 return NULL; | |
| 1048 } | |
| 1049 PZ_Lock(mod->refLock); | |
| 1050 if (mod->evControlMask & SECMOD_END_WAIT) { | |
| 1051 mod->evControlMask &= ~SECMOD_END_WAIT; | |
| 1052 PZ_Unlock(mod->refLock); | |
| 1053 PORT_SetError(SEC_ERROR_NO_EVENT); | |
| 1054 return NULL; | |
| 1055 } | |
| 1056 mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT; | |
| 1057 while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) { | |
| 1058 PZ_Unlock(mod->refLock); | |
| 1059 /* now is a good time to see if new slots have been added */ | |
| 1060 SECMOD_UpdateSlotList(mod); | |
| 1061 | |
| 1062 /* loop through all the slots on a module */ | |
| 1063 SECMOD_GetReadLock(moduleLock); | |
| 1064 for (i=0; i < mod->slotCount; i++) { | |
| 1065 PK11SlotInfo *slot = mod->slots[i]; | |
| 1066 PRUint16 series; | |
| 1067 PRBool present; | |
| 1068 | |
| 1069 /* perm modules do not change */ | |
| 1070 if (slot->isPerm) { | |
| 1071 continue; | |
| 1072 } | |
| 1073 removableSlotsFound = PR_TRUE; | |
| 1074 /* simulate the PKCS #11 module flags. are the flags different | |
| 1075 * from the last time we called? */ | |
| 1076 series = slot->series; | |
| 1077 present = PK11_IsPresent(slot); | |
| 1078 if ((slot->flagSeries != series) || (slot->flagState != present)) { | |
| 1079 slot->flagState = present; | |
| 1080 slot->flagSeries = series; | |
| 1081 SECMOD_ReleaseReadLock(moduleLock); | |
| 1082 PZ_Lock(mod->refLock); | |
| 1083 mod->evControlMask &= ~SECMOD_END_WAIT; | |
| 1084 PZ_Unlock(mod->refLock); | |
| 1085 return PK11_ReferenceSlot(slot); | |
| 1086 } | |
| 1087 } | |
| 1088 SECMOD_ReleaseReadLock(moduleLock); | |
| 1089 /* if everything was perm modules, don't lock up forever */ | |
| 1090 if ((mod->slotCount !=0) && !removableSlotsFound) { | |
| 1091 error =SEC_ERROR_NO_SLOT_SELECTED; | |
| 1092 PZ_Lock(mod->refLock); | |
| 1093 break; | |
| 1094 } | |
| 1095 if (flags & CKF_DONT_BLOCK) { | |
| 1096 PZ_Lock(mod->refLock); | |
| 1097 break; | |
| 1098 } | |
| 1099 PR_Sleep(latency); | |
| 1100 PZ_Lock(mod->refLock); | |
| 1101 } | |
| 1102 mod->evControlMask &= ~SECMOD_END_WAIT; | |
| 1103 PZ_Unlock(mod->refLock); | |
| 1104 PORT_SetError(error); | |
| 1105 return NULL; | |
| 1106 } | |
| 1107 | |
| 1108 /* | |
| 1109 * this function waits for a token event on any slot of a given module | |
| 1110 * This function should not be called from more than one thread of the | |
| 1111 * same process (though other threads can make other library calls | |
| 1112 * on this module while this call is blocked). | |
| 1113 */ | |
| 1114 PK11SlotInfo * | |
| 1115 SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, | |
| 1116 PRIntervalTime latency) | |
| 1117 { | |
| 1118 CK_SLOT_ID id; | |
| 1119 CK_RV crv; | |
| 1120 PK11SlotInfo *slot; | |
| 1121 | |
| 1122 if (!pk11_getFinalizeModulesOption() || | |
| 1123 ((mod->cryptokiVersion.major == 2) && | |
| 1124 (mod->cryptokiVersion.minor < 1))) { | |
| 1125 /* if we are sharing the module with other software in our | |
| 1126 * address space, we can't reliably use C_WaitForSlotEvent(), | |
| 1127 * and if the module is version 2.0, C_WaitForSlotEvent() doesn't | |
| 1128 * exist */ | |
| 1129 return secmod_HandleWaitForSlotEvent(mod, flags, latency); | |
| 1130 } | |
| 1131 /* first the the PKCS #11 call */ | |
| 1132 PZ_Lock(mod->refLock); | |
| 1133 if (mod->evControlMask & SECMOD_END_WAIT) { | |
| 1134 goto end_wait; | |
| 1135 } | |
| 1136 mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT; | |
| 1137 PZ_Unlock(mod->refLock); | |
| 1138 crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL); | |
| 1139 PZ_Lock(mod->refLock); | |
| 1140 mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT; | |
| 1141 /* if we are in end wait, short circuit now, don't even risk | |
| 1142 * going into secmod_HandleWaitForSlotEvent */ | |
| 1143 if (mod->evControlMask & SECMOD_END_WAIT) { | |
| 1144 goto end_wait; | |
| 1145 } | |
| 1146 PZ_Unlock(mod->refLock); | |
| 1147 if (crv == CKR_FUNCTION_NOT_SUPPORTED) { | |
| 1148 /* module doesn't support that call, simulate it */ | |
| 1149 return secmod_HandleWaitForSlotEvent(mod, flags, latency); | |
| 1150 } | |
| 1151 if (crv != CKR_OK) { | |
| 1152 /* we can get this error if finalize was called while we were | |
| 1153 * still running. This is the only way to force a C_WaitForSlotEvent() | |
| 1154 * to return in PKCS #11. In this case, just return that there | |
| 1155 * was no event. */ | |
| 1156 if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) { | |
| 1157 PORT_SetError(SEC_ERROR_NO_EVENT); | |
| 1158 } else { | |
| 1159 PORT_SetError(PK11_MapError(crv)); | |
| 1160 } | |
| 1161 return NULL; | |
| 1162 } | |
| 1163 slot = SECMOD_FindSlotByID(mod, id); | |
| 1164 if (slot == NULL) { | |
| 1165 /* possibly a new slot that was added? */ | |
| 1166 SECMOD_UpdateSlotList(mod); | |
| 1167 slot = SECMOD_FindSlotByID(mod, id); | |
| 1168 } | |
| 1169 /* if we are in the delay period for the "isPresent" call, reset | |
| 1170 * the delay since we know things have probably changed... */ | |
| 1171 if (slot && slot->nssToken && slot->nssToken->slot) { | |
| 1172 nssSlot_ResetDelay(slot->nssToken->slot); | |
| 1173 } | |
| 1174 return slot; | |
| 1175 | |
| 1176 /* must be called with the lock on. */ | |
| 1177 end_wait: | |
| 1178 mod->evControlMask &= ~SECMOD_END_WAIT; | |
| 1179 PZ_Unlock(mod->refLock); | |
| 1180 PORT_SetError(SEC_ERROR_NO_EVENT); | |
| 1181 return NULL; | |
| 1182 } | |
| 1183 | |
| 1184 /* | |
| 1185 * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic | |
| 1186 * function, possibly bringing down the pkcs #11 module in question. This | |
| 1187 * should be OK because 1) it does reinitialize, and 2) it should only be | |
| 1188 * called when we are on our way to tear the whole system down anyway. | |
| 1189 */ | |
| 1190 SECStatus | |
| 1191 SECMOD_CancelWait(SECMODModule *mod) | |
| 1192 { | |
| 1193 unsigned long controlMask; | |
| 1194 SECStatus rv = SECSuccess; | |
| 1195 CK_RV crv; | |
| 1196 | |
| 1197 PZ_Lock(mod->refLock); | |
| 1198 mod->evControlMask |= SECMOD_END_WAIT; | |
| 1199 controlMask = mod->evControlMask; | |
| 1200 if (controlMask & SECMOD_WAIT_PKCS11_EVENT) { | |
| 1201 if (!pk11_getFinalizeModulesOption()) { | |
| 1202 /* can't get here unless pk11_getFinalizeModulesOption is set */ | |
| 1203 PORT_Assert(0); | |
| 1204 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
| 1205 rv = SECFailure; | |
| 1206 goto loser; | |
| 1207 } | |
| 1208 /* NOTE: this call will drop all transient keys, in progress | |
| 1209 * operations, and any authentication. This is the only documented | |
| 1210 * way to get WaitForSlotEvent to return. Also note: for non-thread | |
| 1211 * safe tokens, we need to hold the module lock, this is not yet at | |
| 1212 * system shutdown/startup time, so we need to protect these calls */ | |
| 1213 crv = PK11_GETTAB(mod)->C_Finalize(NULL); | |
| 1214 /* ok, we slammed the module down, now we need to reinit it in case | |
| 1215 * we intend to use it again */ | |
| 1216 if (CKR_OK == crv) { | |
| 1217 PRBool alreadyLoaded; | |
| 1218 secmod_ModuleInit(mod, NULL, &alreadyLoaded); | |
| 1219 } else { | |
| 1220 /* Finalized failed for some reason, notify the application | |
| 1221 * so maybe it has a prayer of recovering... */ | |
| 1222 PORT_SetError(PK11_MapError(crv)); | |
| 1223 rv = SECFailure; | |
| 1224 } | |
| 1225 } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) { | |
| 1226 mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT; | |
| 1227 /* Simulated events will eventually timeout | |
| 1228 * and wake up in the loop */ | |
| 1229 } | |
| 1230 loser: | |
| 1231 PZ_Unlock(mod->refLock); | |
| 1232 return rv; | |
| 1233 } | |
| 1234 | |
| 1235 /* | |
| 1236 * check to see if the module has removable slots that we may need to | |
| 1237 * watch for. | |
| 1238 */ | |
| 1239 PRBool | |
| 1240 SECMOD_HasRemovableSlots(SECMODModule *mod) | |
| 1241 { | |
| 1242 int i; | |
| 1243 PRBool ret = PR_FALSE; | |
| 1244 | |
| 1245 if (!moduleLock) { | |
| 1246 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 1247 return ret; | |
| 1248 } | |
| 1249 SECMOD_GetReadLock(moduleLock); | |
| 1250 for (i=0; i < mod->slotCount; i++) { | |
| 1251 PK11SlotInfo *slot = mod->slots[i]; | |
| 1252 /* perm modules are not inserted or removed */ | |
| 1253 if (slot->isPerm) { | |
| 1254 continue; | |
| 1255 } | |
| 1256 ret = PR_TRUE; | |
| 1257 break; | |
| 1258 } | |
| 1259 if (mod->slotCount == 0 ) { | |
| 1260 ret = PR_TRUE; | |
| 1261 } | |
| 1262 SECMOD_ReleaseReadLock(moduleLock); | |
| 1263 return ret; | |
| 1264 } | |
| 1265 | |
| 1266 /* | |
| 1267 * helper function to actually create and destroy user defined slots | |
| 1268 */ | |
| 1269 static SECStatus | |
| 1270 secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass, | |
| 1271 const char *sendSpec) | |
| 1272 { | |
| 1273 CK_OBJECT_HANDLE dummy; | |
| 1274 CK_ATTRIBUTE template[2] ; | |
| 1275 CK_ATTRIBUTE *attrs = template; | |
| 1276 CK_RV crv; | |
| 1277 | |
| 1278 PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++; | |
| 1279 PK11_SETATTRS(attrs, CKA_NETSCAPE_MODULE_SPEC , (unsigned char *)sendSpec, | |
| 1280 strlen(sendSpec)+1); attrs++; | |
| 1281 | |
| 1282 PORT_Assert(attrs-template <= 2); | |
| 1283 | |
| 1284 | |
| 1285 PK11_EnterSlotMonitor(slot); | |
| 1286 crv = PK11_CreateNewObject(slot, slot->session, | |
| 1287 template, attrs-template, PR_FALSE, &dummy); | |
| 1288 PK11_ExitSlotMonitor(slot); | |
| 1289 | |
| 1290 if (crv != CKR_OK) { | |
| 1291 PORT_SetError(PK11_MapError(crv)); | |
| 1292 return SECFailure; | |
| 1293 } | |
| 1294 return SECMOD_UpdateSlotList(slot->module); | |
| 1295 } | |
| 1296 | |
| 1297 /* | |
| 1298 * return true if the selected slot ID is not present or doesn't exist | |
| 1299 */ | |
| 1300 static PRBool | |
| 1301 secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID) | |
| 1302 { | |
| 1303 PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID); | |
| 1304 if (slot) { | |
| 1305 PRBool present = PK11_IsPresent(slot); | |
| 1306 PK11_FreeSlot(slot); | |
| 1307 if (present) { | |
| 1308 return PR_FALSE; | |
| 1309 } | |
| 1310 } | |
| 1311 /* it doesn't exist or isn't present, it's available */ | |
| 1312 return PR_TRUE; | |
| 1313 } | |
| 1314 | |
| 1315 /* | |
| 1316 * Find an unused slot id in module. | |
| 1317 */ | |
| 1318 static CK_SLOT_ID | |
| 1319 secmod_FindFreeSlot(SECMODModule *mod) | |
| 1320 { | |
| 1321 CK_SLOT_ID i, minSlotID, maxSlotID; | |
| 1322 | |
| 1323 /* look for a free slot id on the internal module */ | |
| 1324 if (mod->internal && mod->isFIPS) { | |
| 1325 minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID; | |
| 1326 maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID; | |
| 1327 } else { | |
| 1328 minSlotID = SFTK_MIN_USER_SLOT_ID; | |
| 1329 maxSlotID = SFTK_MAX_USER_SLOT_ID; | |
| 1330 } | |
| 1331 for (i=minSlotID; i < maxSlotID; i++) { | |
| 1332 if (secmod_SlotIsEmpty(mod,i)) { | |
| 1333 return i; | |
| 1334 } | |
| 1335 } | |
| 1336 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); | |
| 1337 return (CK_SLOT_ID) -1; | |
| 1338 } | |
| 1339 | |
| 1340 /* | |
| 1341 * Attempt to open a new slot. | |
| 1342 * | |
| 1343 * This works the same os OpenUserDB except it can be called against | |
| 1344 * any module that understands the softoken protocol for opening new | |
| 1345 * slots, not just the softoken itself. If the selected module does not | |
| 1346 * understand the protocol, C_CreateObject will fail with | |
| 1347 * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set | |
| 1348 * SEC_ERROR_BAD_DATA. | |
| 1349 * | |
| 1350 * NewSlots can be closed with SECMOD_CloseUserDB(); | |
| 1351 * | |
| 1352 * Modulespec is module dependent. | |
| 1353 */ | |
| 1354 PK11SlotInfo * | |
| 1355 SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec) | |
| 1356 { | |
| 1357 CK_SLOT_ID slotID = 0; | |
| 1358 PK11SlotInfo *slot; | |
| 1359 char *escSpec; | |
| 1360 char *sendSpec; | |
| 1361 SECStatus rv; | |
| 1362 | |
| 1363 slotID = secmod_FindFreeSlot(mod); | |
| 1364 if (slotID == (CK_SLOT_ID) -1) { | |
| 1365 return NULL; | |
| 1366 } | |
| 1367 | |
| 1368 if (mod->slotCount == 0) { | |
| 1369 return NULL; | |
| 1370 } | |
| 1371 | |
| 1372 /* just grab the first slot in the module, any present slot should work */ | |
| 1373 slot = PK11_ReferenceSlot(mod->slots[0]); | |
| 1374 if (slot == NULL) { | |
| 1375 return NULL; | |
| 1376 } | |
| 1377 | |
| 1378 /* we've found the slot, now build the moduleSpec */ | |
| 1379 escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']'); | |
| 1380 if (escSpec == NULL) { | |
| 1381 PK11_FreeSlot(slot); | |
| 1382 return NULL; | |
| 1383 } | |
| 1384 sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec); | |
| 1385 PORT_Free(escSpec); | |
| 1386 | |
| 1387 if (sendSpec == NULL) { | |
| 1388 /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */ | |
| 1389 PK11_FreeSlot(slot); | |
| 1390 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 1391 return NULL; | |
| 1392 } | |
| 1393 rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec); | |
| 1394 PR_smprintf_free(sendSpec); | |
| 1395 PK11_FreeSlot(slot); | |
| 1396 if (rv != SECSuccess) { | |
| 1397 return NULL; | |
| 1398 } | |
| 1399 | |
| 1400 slot = SECMOD_FindSlotByID(mod, slotID); | |
| 1401 if (slot) { | |
| 1402 /* if we are in the delay period for the "isPresent" call, reset | |
| 1403 * the delay since we know things have probably changed... */ | |
| 1404 if (slot->nssToken && slot->nssToken->slot) { | |
| 1405 nssSlot_ResetDelay(slot->nssToken->slot); | |
| 1406 } | |
| 1407 /* force the slot info structures to properly reset */ | |
| 1408 (void)PK11_IsPresent(slot); | |
| 1409 } | |
| 1410 return slot; | |
| 1411 } | |
| 1412 | |
| 1413 /* | |
| 1414 * Open a new database using the softoken. The caller is responsible for making | |
| 1415 * sure the module spec is correct and usable. The caller should ask for one | |
| 1416 * new database per call if the caller wants to get meaningful information | |
| 1417 * about the new database. | |
| 1418 * | |
| 1419 * moduleSpec is the same data that you would pass to softoken at | |
| 1420 * initialization time under the 'tokens' options. For example, if you were | |
| 1421 * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']> | |
| 1422 * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your | |
| 1423 * module spec here. The slot ID will be calculated for you by | |
| 1424 * SECMOD_OpenUserDB(). | |
| 1425 * | |
| 1426 * Typical parameters here are configdir, tokenDescription and flags. | |
| 1427 * | |
| 1428 * a Full list is below: | |
| 1429 * | |
| 1430 * | |
| 1431 * configDir - The location of the databases for this token. If configDir is | |
| 1432 * not specified, and noCertDB and noKeyDB is not specified, the load | |
| 1433 * will fail. | |
| 1434 * certPrefix - Cert prefix for this token. | |
| 1435 * keyPrefix - Prefix for the key database for this token. (if not specified, | |
| 1436 * certPrefix will be used). | |
| 1437 * tokenDescription - The label value for this token returned in the | |
| 1438 * CK_TOKEN_INFO structure with an internationalize string (UTF8). | |
| 1439 * This value will be truncated at 32 bytes (no NULL, partial UTF8 | |
| 1440 * characters dropped). You should specify a user friendly name here | |
| 1441 * as this is the value the token will be referred to in most | |
| 1442 * application UI's. You should make sure tokenDescription is unique. | |
| 1443 * slotDescription - The slotDescription value for this token returned | |
| 1444 * in the CK_SLOT_INFO structure with an internationalize string | |
| 1445 * (UTF8). This value will be truncated at 64 bytes (no NULL, partial | |
| 1446 * UTF8 characters dropped). This name will not change after the | |
| 1447 * database is closed. It should have some number to make this unique. | |
| 1448 * minPWLen - minimum password length for this token. | |
| 1449 * flags - comma separated list of flag values, parsed case-insensitive. | |
| 1450 * Valid flags are: | |
| 1451 * readOnly - Databases should be opened read only. | |
| 1452 * noCertDB - Don't try to open a certificate database. | |
| 1453 * noKeyDB - Don't try to open a key database. | |
| 1454 * forceOpen - Don't fail to initialize the token if the | |
| 1455 * databases could not be opened. | |
| 1456 * passwordRequired - zero length passwords are not acceptable | |
| 1457 * (valid only if there is a keyDB). | |
| 1458 * optimizeSpace - allocate smaller hash tables and lock tables. | |
| 1459 * When this flag is not specified, Softoken will allocate | |
| 1460 * large tables to prevent lock contention. | |
| 1461 */ | |
| 1462 PK11SlotInfo * | |
| 1463 SECMOD_OpenUserDB(const char *moduleSpec) | |
| 1464 { | |
| 1465 SECMODModule *mod; | |
| 1466 | |
| 1467 if (moduleSpec == NULL) { | |
| 1468 return NULL; | |
| 1469 } | |
| 1470 | |
| 1471 /* NOTE: unlike most PK11 function, this does not return a reference | |
| 1472 * to the module */ | |
| 1473 mod = SECMOD_GetInternalModule(); | |
| 1474 if (!mod) { | |
| 1475 /* shouldn't happen */ | |
| 1476 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
| 1477 return NULL; | |
| 1478 } | |
| 1479 return SECMOD_OpenNewSlot(mod, moduleSpec); | |
| 1480 } | |
| 1481 | |
| 1482 | |
| 1483 /* | |
| 1484 * close an already opened user database. NOTE: the database must be | |
| 1485 * in the internal token, and must be one created with SECMOD_OpenUserDB(). | |
| 1486 * Once the database is closed, the slot will remain as an empty slot | |
| 1487 * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot(). | |
| 1488 */ | |
| 1489 SECStatus | |
| 1490 SECMOD_CloseUserDB(PK11SlotInfo *slot) | |
| 1491 { | |
| 1492 SECStatus rv; | |
| 1493 char *sendSpec; | |
| 1494 | |
| 1495 sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID); | |
| 1496 if (sendSpec == NULL) { | |
| 1497 /* PR_smprintf does not set no memory error */ | |
| 1498 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 1499 return SECFailure; | |
| 1500 } | |
| 1501 rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec); | |
| 1502 PR_smprintf_free(sendSpec); | |
| 1503 /* if we are in the delay period for the "isPresent" call, reset | |
| 1504 * the delay since we know things have probably changed... */ | |
| 1505 if (slot->nssToken && slot->nssToken->slot) { | |
| 1506 nssSlot_ResetDelay(slot->nssToken->slot); | |
| 1507 /* force the slot info structures to properly reset */ | |
| 1508 (void)PK11_IsPresent(slot); | |
| 1509 } | |
| 1510 return rv; | |
| 1511 } | |
| 1512 | |
| 1513 /* | |
| 1514 * Restart PKCS #11 modules after a fork(). See secmod.h for more information. | |
| 1515 */ | |
| 1516 SECStatus | |
| 1517 SECMOD_RestartModules(PRBool force) | |
| 1518 { | |
| 1519 SECMODModuleList *mlp; | |
| 1520 SECStatus rrv = SECSuccess; | |
| 1521 int lastError = 0; | |
| 1522 | |
| 1523 if (!moduleLock) { | |
| 1524 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
| 1525 return SECFailure; | |
| 1526 } | |
| 1527 | |
| 1528 /* Only need to restart the PKCS #11 modules that were initialized */ | |
| 1529 SECMOD_GetReadLock(moduleLock); | |
| 1530 for (mlp = modules; mlp != NULL; mlp = mlp->next) { | |
| 1531 SECMODModule *mod = mlp->module; | |
| 1532 CK_ULONG count; | |
| 1533 SECStatus rv; | |
| 1534 int i; | |
| 1535 | |
| 1536 /* If the module needs to be reset, do so */ | |
| 1537 if (force || (PK11_GETTAB(mod)-> | |
| 1538 C_GetSlotList(CK_FALSE, NULL, &count) != CKR_OK)) { | |
| 1539 PRBool alreadyLoaded; | |
| 1540 /* first call Finalize. This is not required by PKCS #11, but some | |
| 1541 * older modules require it, and it doesn't hurt (compliant modules | |
| 1542 * will return CKR_NOT_INITIALIZED */ | |
| 1543 (void) PK11_GETTAB(mod)->C_Finalize(NULL); | |
| 1544 /* now initialize the module, this function reinitializes | |
| 1545 * a module in place, preserving existing slots (even if they | |
| 1546 * no longer exist) */ | |
| 1547 rv = secmod_ModuleInit(mod, NULL, &alreadyLoaded); | |
| 1548 if (rv != SECSuccess) { | |
| 1549 /* save the last error code */ | |
| 1550 lastError = PORT_GetError(); | |
| 1551 rrv = rv; | |
| 1552 /* couldn't reinit the module, disable all its slots */ | |
| 1553 for (i=0; i < mod->slotCount; i++) { | |
| 1554 mod->slots[i]->disabled = PR_TRUE; | |
| 1555 mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; | |
| 1556 } | |
| 1557 continue; | |
| 1558 } | |
| 1559 for (i=0; i < mod->slotCount; i++) { | |
| 1560 /* get new token sessions, bump the series up so that | |
| 1561 * we refresh other old sessions. This will tell much of | |
| 1562 * NSS to flush cached handles it may hold as well */ | |
| 1563 rv = PK11_InitToken(mod->slots[i],PR_TRUE); | |
| 1564 /* PK11_InitToken could fail if the slot isn't present. | |
| 1565 * If it is present, though, something is wrong and we should | |
| 1566 * disable the slot and let the caller know. */ | |
| 1567 if (rv != SECSuccess && PK11_IsPresent(mod->slots[i])) { | |
| 1568 /* save the last error code */ | |
| 1569 lastError = PORT_GetError(); | |
| 1570 rrv = rv; | |
| 1571 /* disable the token */ | |
| 1572 mod->slots[i]->disabled = PR_TRUE; | |
| 1573 mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; | |
| 1574 } | |
| 1575 } | |
| 1576 } | |
| 1577 } | |
| 1578 SECMOD_ReleaseReadLock(moduleLock); | |
| 1579 | |
| 1580 /* | |
| 1581 * on multiple failures, we are only returning the lastError. The caller | |
| 1582 * can determine which slots are bad by calling PK11_IsDisabled(). | |
| 1583 */ | |
| 1584 if (rrv != SECSuccess) { | |
| 1585 /* restore the last error code */ | |
| 1586 PORT_SetError(lastError); | |
| 1587 } | |
| 1588 | |
| 1589 return rrv; | |
| 1590 } | |
| OLD | NEW |