Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/pk11wrap/pk11util.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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_GetEnv("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 } /* for each mechanism */ | |
644 /* disable each slot if the defaultFlags say so */ | |
645 if (defaultMechanismFlags & PK11_DISABLE_FLAG) { | |
646 PK11_UserDisableSlot(slot); | |
647 } | |
648 } /* for each slot of this module */ | |
649 SECMOD_ReleaseReadLock(moduleLock); | |
650 | |
651 /* delete and re-add module in order to save changes | |
652 * to the module */ | |
653 result = SECMOD_UpdateModule(module); | |
654 } | |
655 } | |
656 } | |
657 SECMOD_DestroyModule(module); | |
658 return result; | |
659 } | |
660 | |
661 SECStatus | |
662 SECMOD_AddNewModule(const char* moduleName, const char* dllPath, | |
663 unsigned long defaultMechanismFlags, | |
664 unsigned long cipherEnableFlags) | |
665 { | |
666 return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags, | |
667 cipherEnableFlags, | |
668 NULL, NULL); /* don't pass module or nss params */ | |
669 } | |
670 | |
671 SECStatus | |
672 SECMOD_UpdateModule(SECMODModule *module) | |
673 { | |
674 SECStatus result; | |
675 | |
676 result = SECMOD_DeletePermDB(module); | |
677 | |
678 if (result == SECSuccess) { | |
679 result = SECMOD_AddPermDB(module); | |
680 } | |
681 return result; | |
682 } | |
683 | |
684 /* Public & Internal(Security Library) representation of | |
685 * encryption mechanism flags conversion */ | |
686 | |
687 /* Currently, the only difference is that internal representation | |
688 * puts RANDOM_FLAG at bit 31 (Most-significant bit), but | |
689 * public representation puts this bit at bit 28 | |
690 */ | |
691 unsigned long | |
692 SECMOD_PubMechFlagstoInternal(unsigned long publicFlags) | |
693 { | |
694 unsigned long internalFlags = publicFlags; | |
695 | |
696 if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) { | |
697 internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG; | |
698 internalFlags |= SECMOD_RANDOM_FLAG; | |
699 } | |
700 return internalFlags; | |
701 } | |
702 | |
703 unsigned long | |
704 SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) | |
705 { | |
706 unsigned long publicFlags = internalFlags; | |
707 | |
708 if (internalFlags & SECMOD_RANDOM_FLAG) { | |
709 publicFlags &= ~SECMOD_RANDOM_FLAG; | |
710 publicFlags |= PUBLIC_MECH_RANDOM_FLAG; | |
711 } | |
712 return publicFlags; | |
713 } | |
714 | |
715 | |
716 /* Public & Internal(Security Library) representation of */ | |
717 /* cipher flags conversion */ | |
718 /* Note: currently they are just stubs */ | |
719 unsigned long | |
720 SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) | |
721 { | |
722 return publicFlags; | |
723 } | |
724 | |
725 unsigned long | |
726 SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) | |
727 { | |
728 return internalFlags; | |
729 } | |
730 | |
731 /* Funtion reports true if module of modType is installed/configured */ | |
732 PRBool | |
733 SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ) | |
734 { | |
735 PRBool result = PR_FALSE; | |
736 SECMODModuleList *mods; | |
737 | |
738 if (!moduleLock) { | |
739 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
740 return result; | |
741 } | |
742 SECMOD_GetReadLock(moduleLock); | |
743 mods = SECMOD_GetDefaultModuleList(); | |
744 for ( ; mods != NULL; mods = mods->next) { | |
745 if (mods->module->ssl[0] & | |
746 SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) { | |
747 result = PR_TRUE; | |
748 } | |
749 } | |
750 | |
751 SECMOD_ReleaseReadLock(moduleLock); | |
752 return result; | |
753 } | |
754 | |
755 /* create a new ModuleListElement */ | |
756 SECMODModuleList *SECMOD_NewModuleListElement(void) | |
757 { | |
758 SECMODModuleList *newModList; | |
759 | |
760 newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList)); | |
761 if (newModList) { | |
762 newModList->next = NULL; | |
763 newModList->module = NULL; | |
764 } | |
765 return newModList; | |
766 } | |
767 | |
768 /* | |
769 * make a new reference to a module so It doesn't go away on us | |
770 */ | |
771 SECMODModule * | |
772 SECMOD_ReferenceModule(SECMODModule *module) | |
773 { | |
774 PZ_Lock(module->refLock); | |
775 PORT_Assert(module->refCount > 0); | |
776 | |
777 module->refCount++; | |
778 PZ_Unlock(module->refLock); | |
779 return module; | |
780 } | |
781 | |
782 | |
783 /* destroy an existing module */ | |
784 void | |
785 SECMOD_DestroyModule(SECMODModule *module) | |
786 { | |
787 PRBool willfree = PR_FALSE; | |
788 int slotCount; | |
789 int i; | |
790 | |
791 PZ_Lock(module->refLock); | |
792 if (module->refCount-- == 1) { | |
793 willfree = PR_TRUE; | |
794 } | |
795 PORT_Assert(willfree || (module->refCount > 0)); | |
796 PZ_Unlock(module->refLock); | |
797 | |
798 if (!willfree) { | |
799 return; | |
800 } | |
801 | |
802 if (module->parent != NULL) { | |
803 SECMODModule *parent = module->parent; | |
804 /* paranoia, don't loop forever if the modules are looped */ | |
805 module->parent = NULL; | |
806 SECMOD_DestroyModule(parent); | |
807 } | |
808 | |
809 /* slots can't really disappear until our module starts freeing them, | |
810 * so this check is safe */ | |
811 slotCount = module->slotCount; | |
812 if (slotCount == 0) { | |
813 SECMOD_SlotDestroyModule(module,PR_FALSE); | |
814 return; | |
815 } | |
816 | |
817 /* now free all out slots, when they are done, they will cause the | |
818 * module to disappear altogether */ | |
819 for (i=0 ; i < slotCount; i++) { | |
820 if (!module->slots[i]->disabled) { | |
821 PK11_ClearSlotList(module->slots[i]); | |
822 } | |
823 PK11_FreeSlot(module->slots[i]); | |
824 } | |
825 /* WARNING: once the last slot has been freed is it possible (even likely) | |
826 * that module is no more... touching it now is a good way to go south */ | |
827 } | |
828 | |
829 | |
830 /* we can only get here if we've destroyed the module, or some one has | |
831 * erroneously freed a slot that wasn't referenced. */ | |
832 void | |
833 SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) | |
834 { | |
835 PRBool willfree = PR_FALSE; | |
836 if (fromSlot) { | |
837 PORT_Assert(module->refCount == 0); | |
838 PZ_Lock(module->refLock); | |
839 if (module->slotCount-- == 1) { | |
840 willfree = PR_TRUE; | |
841 } | |
842 PORT_Assert(willfree || (module->slotCount > 0)); | |
843 PZ_Unlock(module->refLock); | |
844 if (!willfree) return; | |
845 } | |
846 | |
847 if (module == pendingModule) { | |
848 pendingModule = NULL; | |
849 } | |
850 | |
851 if (module->loaded) { | |
852 SECMOD_UnloadModule(module); | |
853 } | |
854 PZ_DestroyLock(module->refLock); | |
855 PORT_FreeArena(module->arena,PR_FALSE); | |
856 secmod_PrivateModuleCount--; | |
857 } | |
858 | |
859 /* destroy a list element | |
860 * this destroys a single element, and returns the next element | |
861 * on the chain. It makes it easy to implement for loops to delete | |
862 * the chain. It also make deleting a single element easy */ | |
863 SECMODModuleList * | |
864 SECMOD_DestroyModuleListElement(SECMODModuleList *element) | |
865 { | |
866 SECMODModuleList *next = element->next; | |
867 | |
868 if (element->module) { | |
869 SECMOD_DestroyModule(element->module); | |
870 element->module = NULL; | |
871 } | |
872 PORT_Free(element); | |
873 return next; | |
874 } | |
875 | |
876 | |
877 /* | |
878 * Destroy an entire module list | |
879 */ | |
880 void | |
881 SECMOD_DestroyModuleList(SECMODModuleList *list) | |
882 { | |
883 SECMODModuleList *lp; | |
884 | |
885 for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ; | |
886 } | |
887 | |
888 PRBool | |
889 SECMOD_CanDeleteInternalModule(void) | |
890 { | |
891 return (PRBool) (pendingModule == NULL); | |
892 } | |
893 | |
894 /* | |
895 * check to see if the module has added new slots. PKCS 11 v2.20 allows for | |
896 * modules to add new slots, but never remove them. Slots cannot be added | |
897 * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent | |
898 * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently | |
899 * grow on the caller. It is permissible for the slots to increase between | |
900 * successive calls with NULL to get the size. | |
901 */ | |
902 SECStatus | |
903 SECMOD_UpdateSlotList(SECMODModule *mod) | |
904 { | |
905 CK_RV crv; | |
906 CK_ULONG count; | |
907 CK_ULONG i, oldCount; | |
908 PRBool freeRef = PR_FALSE; | |
909 void *mark = NULL; | |
910 CK_ULONG *slotIDs = NULL; | |
911 PK11SlotInfo **newSlots = NULL; | |
912 PK11SlotInfo **oldSlots = NULL; | |
913 | |
914 if (!moduleLock) { | |
915 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
916 return SECFailure; | |
917 } | |
918 | |
919 /* C_GetSlotList is not a session function, make sure | |
920 * calls are serialized */ | |
921 PZ_Lock(mod->refLock); | |
922 freeRef = PR_TRUE; | |
923 /* see if the number of slots have changed */ | |
924 crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); | |
925 if (crv != CKR_OK) { | |
926 PORT_SetError(PK11_MapError(crv)); | |
927 goto loser; | |
928 } | |
929 /* nothing new, blow out early, we want this function to be quick | |
930 * and cheap in the normal case */ | |
931 if (count == mod->slotCount) { | |
932 PZ_Unlock(mod->refLock); | |
933 return SECSuccess; | |
934 } | |
935 if (count < (CK_ULONG)mod->slotCount) { | |
936 /* shouldn't happen with a properly functioning PKCS #11 module */ | |
937 PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); | |
938 goto loser; | |
939 } | |
940 | |
941 /* get the new slot list */ | |
942 slotIDs = PORT_NewArray(CK_SLOT_ID, count); | |
943 if (slotIDs == NULL) { | |
944 goto loser; | |
945 } | |
946 | |
947 crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); | |
948 if (crv != CKR_OK) { | |
949 PORT_SetError(PK11_MapError(crv)); | |
950 goto loser; | |
951 } | |
952 freeRef = PR_FALSE; | |
953 PZ_Unlock(mod->refLock); | |
954 mark = PORT_ArenaMark(mod->arena); | |
955 if (mark == NULL) { | |
956 goto loser; | |
957 } | |
958 newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); | |
959 | |
960 /* walk down the new slot ID list returned from the module. We keep | |
961 * the old slots which match a returned ID, and we initialize the new | |
962 * slots. */ | |
963 for (i=0; i < count; i++) { | |
964 PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); | |
965 | |
966 if (!slot) { | |
967 /* we have a new slot create a new slot data structure */ | |
968 slot = PK11_NewSlotInfo(mod); | |
969 if (!slot) { | |
970 goto loser; | |
971 } | |
972 PK11_InitSlot(mod, slotIDs[i], slot); | |
973 STAN_InitTokenForSlotInfo(NULL, slot); | |
974 } | |
975 newSlots[i] = slot; | |
976 } | |
977 STAN_ResetTokenInterator(NULL); | |
978 PORT_Free(slotIDs); | |
979 slotIDs = NULL; | |
980 PORT_ArenaUnmark(mod->arena, mark); | |
981 | |
982 /* until this point we're still using the old slot list. Now we update | |
983 * module slot list. We update the slots (array) first then the count, | |
984 * since we've already guarrenteed that count has increased (just in case | |
985 * someone is looking at the slots field of module without holding the | |
986 * moduleLock */ | |
987 SECMOD_GetWriteLock(moduleLock); | |
988 oldCount =mod->slotCount; | |
989 oldSlots = mod->slots; | |
990 mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is | |
991 * allocated out of the module arena and won't | |
992 * be freed until the module is freed */ | |
993 mod->slotCount = count; | |
994 SECMOD_ReleaseWriteLock(moduleLock); | |
995 /* free our old references before forgetting about oldSlot*/ | |
996 for (i=0; i < oldCount; i++) { | |
997 PK11_FreeSlot(oldSlots[i]); | |
998 } | |
999 return SECSuccess; | |
1000 | |
1001 loser: | |
1002 if (freeRef) { | |
1003 PZ_Unlock(mod->refLock); | |
1004 } | |
1005 if (slotIDs) { | |
1006 PORT_Free(slotIDs); | |
1007 } | |
1008 /* free all the slots we allocated. newSlots are part of the | |
1009 * mod arena. NOTE: the newSlots array contain both new and old | |
1010 * slots, but we kept a reference to the old slots when we built the new | |
1011 * array, so we need to free all the slots in newSlots array. */ | |
1012 if (newSlots) { | |
1013 for (i=0; i < count; i++) { | |
1014 if (newSlots[i] == NULL) { | |
1015 break; /* hit the last one */ | |
1016 } | |
1017 PK11_FreeSlot(newSlots[i]); | |
1018 } | |
1019 } | |
1020 /* must come after freeing newSlots */ | |
1021 if (mark) { | |
1022 PORT_ArenaRelease(mod->arena, mark); | |
1023 } | |
1024 return SECFailure; | |
1025 } | |
1026 | |
1027 /* | |
1028 * this handles modules that do not support C_WaitForSlotEvent(). | |
1029 * The internal flags are stored. Note that C_WaitForSlotEvent() does not | |
1030 * have a timeout, so we don't have one for handleWaitForSlotEvent() either. | |
1031 */ | |
1032 PK11SlotInfo * | |
1033 secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags, | |
1034 PRIntervalTime latency) | |
1035 { | |
1036 PRBool removableSlotsFound = PR_FALSE; | |
1037 int i; | |
1038 int error = SEC_ERROR_NO_EVENT; | |
1039 | |
1040 if (!moduleLock) { | |
1041 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
1042 return NULL; | |
1043 } | |
1044 PZ_Lock(mod->refLock); | |
1045 if (mod->evControlMask & SECMOD_END_WAIT) { | |
1046 mod->evControlMask &= ~SECMOD_END_WAIT; | |
1047 PZ_Unlock(mod->refLock); | |
1048 PORT_SetError(SEC_ERROR_NO_EVENT); | |
1049 return NULL; | |
1050 } | |
1051 mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT; | |
1052 while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) { | |
1053 PZ_Unlock(mod->refLock); | |
1054 /* now is a good time to see if new slots have been added */ | |
1055 SECMOD_UpdateSlotList(mod); | |
1056 | |
1057 /* loop through all the slots on a module */ | |
1058 SECMOD_GetReadLock(moduleLock); | |
1059 for (i=0; i < mod->slotCount; i++) { | |
1060 PK11SlotInfo *slot = mod->slots[i]; | |
1061 PRUint16 series; | |
1062 PRBool present; | |
1063 | |
1064 /* perm modules do not change */ | |
1065 if (slot->isPerm) { | |
1066 continue; | |
1067 } | |
1068 removableSlotsFound = PR_TRUE; | |
1069 /* simulate the PKCS #11 module flags. are the flags different | |
1070 * from the last time we called? */ | |
1071 series = slot->series; | |
1072 present = PK11_IsPresent(slot); | |
1073 if ((slot->flagSeries != series) || (slot->flagState != present)) { | |
1074 slot->flagState = present; | |
1075 slot->flagSeries = series; | |
1076 SECMOD_ReleaseReadLock(moduleLock); | |
1077 PZ_Lock(mod->refLock); | |
1078 mod->evControlMask &= ~SECMOD_END_WAIT; | |
1079 PZ_Unlock(mod->refLock); | |
1080 return PK11_ReferenceSlot(slot); | |
1081 } | |
1082 } | |
1083 SECMOD_ReleaseReadLock(moduleLock); | |
1084 /* if everything was perm modules, don't lock up forever */ | |
1085 if ((mod->slotCount !=0) && !removableSlotsFound) { | |
1086 error =SEC_ERROR_NO_SLOT_SELECTED; | |
1087 PZ_Lock(mod->refLock); | |
1088 break; | |
1089 } | |
1090 if (flags & CKF_DONT_BLOCK) { | |
1091 PZ_Lock(mod->refLock); | |
1092 break; | |
1093 } | |
1094 PR_Sleep(latency); | |
1095 PZ_Lock(mod->refLock); | |
1096 } | |
1097 mod->evControlMask &= ~SECMOD_END_WAIT; | |
1098 PZ_Unlock(mod->refLock); | |
1099 PORT_SetError(error); | |
1100 return NULL; | |
1101 } | |
1102 | |
1103 /* | |
1104 * this function waits for a token event on any slot of a given module | |
1105 * This function should not be called from more than one thread of the | |
1106 * same process (though other threads can make other library calls | |
1107 * on this module while this call is blocked). | |
1108 */ | |
1109 PK11SlotInfo * | |
1110 SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, | |
1111 PRIntervalTime latency) | |
1112 { | |
1113 CK_SLOT_ID id; | |
1114 CK_RV crv; | |
1115 PK11SlotInfo *slot; | |
1116 | |
1117 if (!pk11_getFinalizeModulesOption() || | |
1118 ((mod->cryptokiVersion.major == 2) && | |
1119 (mod->cryptokiVersion.minor < 1))) { | |
1120 /* if we are sharing the module with other software in our | |
1121 * address space, we can't reliably use C_WaitForSlotEvent(), | |
1122 * and if the module is version 2.0, C_WaitForSlotEvent() doesn't | |
1123 * exist */ | |
1124 return secmod_HandleWaitForSlotEvent(mod, flags, latency); | |
1125 } | |
1126 /* first the the PKCS #11 call */ | |
1127 PZ_Lock(mod->refLock); | |
1128 if (mod->evControlMask & SECMOD_END_WAIT) { | |
1129 goto end_wait; | |
1130 } | |
1131 mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT; | |
1132 PZ_Unlock(mod->refLock); | |
1133 crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL); | |
1134 PZ_Lock(mod->refLock); | |
1135 mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT; | |
1136 /* if we are in end wait, short circuit now, don't even risk | |
1137 * going into secmod_HandleWaitForSlotEvent */ | |
1138 if (mod->evControlMask & SECMOD_END_WAIT) { | |
1139 goto end_wait; | |
1140 } | |
1141 PZ_Unlock(mod->refLock); | |
1142 if (crv == CKR_FUNCTION_NOT_SUPPORTED) { | |
1143 /* module doesn't support that call, simulate it */ | |
1144 return secmod_HandleWaitForSlotEvent(mod, flags, latency); | |
1145 } | |
1146 if (crv != CKR_OK) { | |
1147 /* we can get this error if finalize was called while we were | |
1148 * still running. This is the only way to force a C_WaitForSlotEvent() | |
1149 * to return in PKCS #11. In this case, just return that there | |
1150 * was no event. */ | |
1151 if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) { | |
1152 PORT_SetError(SEC_ERROR_NO_EVENT); | |
1153 } else { | |
1154 PORT_SetError(PK11_MapError(crv)); | |
1155 } | |
1156 return NULL; | |
1157 } | |
1158 slot = SECMOD_FindSlotByID(mod, id); | |
1159 if (slot == NULL) { | |
1160 /* possibly a new slot that was added? */ | |
1161 SECMOD_UpdateSlotList(mod); | |
1162 slot = SECMOD_FindSlotByID(mod, id); | |
1163 } | |
1164 /* if we are in the delay period for the "isPresent" call, reset | |
1165 * the delay since we know things have probably changed... */ | |
1166 if (slot && slot->nssToken && slot->nssToken->slot) { | |
1167 nssSlot_ResetDelay(slot->nssToken->slot); | |
1168 } | |
1169 return slot; | |
1170 | |
1171 /* must be called with the lock on. */ | |
1172 end_wait: | |
1173 mod->evControlMask &= ~SECMOD_END_WAIT; | |
1174 PZ_Unlock(mod->refLock); | |
1175 PORT_SetError(SEC_ERROR_NO_EVENT); | |
1176 return NULL; | |
1177 } | |
1178 | |
1179 /* | |
1180 * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic | |
1181 * function, possibly bringing down the pkcs #11 module in question. This | |
1182 * should be OK because 1) it does reinitialize, and 2) it should only be | |
1183 * called when we are on our way to tear the whole system down anyway. | |
1184 */ | |
1185 SECStatus | |
1186 SECMOD_CancelWait(SECMODModule *mod) | |
1187 { | |
1188 unsigned long controlMask = mod->evControlMask; | |
1189 SECStatus rv = SECSuccess; | |
1190 CK_RV crv; | |
1191 | |
1192 PZ_Lock(mod->refLock); | |
1193 mod->evControlMask |= SECMOD_END_WAIT; | |
1194 controlMask = mod->evControlMask; | |
1195 if (controlMask & SECMOD_WAIT_PKCS11_EVENT) { | |
1196 if (!pk11_getFinalizeModulesOption()) { | |
1197 /* can't get here unless pk11_getFinalizeModulesOption is set */ | |
1198 PORT_Assert(0); | |
1199 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
1200 rv = SECFailure; | |
1201 goto loser; | |
1202 } | |
1203 /* NOTE: this call will drop all transient keys, in progress | |
1204 * operations, and any authentication. This is the only documented | |
1205 * way to get WaitForSlotEvent to return. Also note: for non-thread | |
1206 * safe tokens, we need to hold the module lock, this is not yet at | |
1207 * system shutdown/startup time, so we need to protect these calls */ | |
1208 crv = PK11_GETTAB(mod)->C_Finalize(NULL); | |
1209 /* ok, we slammed the module down, now we need to reinit it in case | |
1210 * we intend to use it again */ | |
1211 if (CKR_OK == crv) { | |
1212 PRBool alreadyLoaded; | |
1213 secmod_ModuleInit(mod, NULL, &alreadyLoaded); | |
1214 } else { | |
1215 /* Finalized failed for some reason, notify the application | |
1216 * so maybe it has a prayer of recovering... */ | |
1217 PORT_SetError(PK11_MapError(crv)); | |
1218 rv = SECFailure; | |
1219 } | |
1220 } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) { | |
1221 mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT; | |
1222 /* Simulated events will eventually timeout | |
1223 * and wake up in the loop */ | |
1224 } | |
1225 loser: | |
1226 PZ_Unlock(mod->refLock); | |
1227 return rv; | |
1228 } | |
1229 | |
1230 /* | |
1231 * check to see if the module has removable slots that we may need to | |
1232 * watch for. | |
1233 */ | |
1234 PRBool | |
1235 SECMOD_HasRemovableSlots(SECMODModule *mod) | |
1236 { | |
1237 int i; | |
1238 PRBool ret = PR_FALSE; | |
1239 | |
1240 if (!moduleLock) { | |
1241 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
1242 return ret; | |
1243 } | |
1244 SECMOD_GetReadLock(moduleLock); | |
1245 for (i=0; i < mod->slotCount; i++) { | |
1246 PK11SlotInfo *slot = mod->slots[i]; | |
1247 /* perm modules are not inserted or removed */ | |
1248 if (slot->isPerm) { | |
1249 continue; | |
1250 } | |
1251 ret = PR_TRUE; | |
1252 break; | |
1253 } | |
1254 if (mod->slotCount == 0 ) { | |
1255 ret = PR_TRUE; | |
1256 } | |
1257 SECMOD_ReleaseReadLock(moduleLock); | |
1258 return ret; | |
1259 } | |
1260 | |
1261 /* | |
1262 * helper function to actually create and destroy user defined slots | |
1263 */ | |
1264 static SECStatus | |
1265 secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass, | |
1266 const char *sendSpec) | |
1267 { | |
1268 CK_OBJECT_HANDLE dummy; | |
1269 CK_ATTRIBUTE template[2] ; | |
1270 CK_ATTRIBUTE *attrs = template; | |
1271 CK_RV crv; | |
1272 | |
1273 PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++; | |
1274 PK11_SETATTRS(attrs, CKA_NETSCAPE_MODULE_SPEC , (unsigned char *)sendSpec, | |
1275 strlen(sendSpec)+1); attrs++; | |
1276 | |
1277 PORT_Assert(attrs-template <= 2); | |
1278 | |
1279 | |
1280 PK11_EnterSlotMonitor(slot); | |
1281 crv = PK11_CreateNewObject(slot, slot->session, | |
1282 template, attrs-template, PR_FALSE, &dummy); | |
1283 PK11_ExitSlotMonitor(slot); | |
1284 | |
1285 if (crv != CKR_OK) { | |
1286 PORT_SetError(PK11_MapError(crv)); | |
1287 return SECFailure; | |
1288 } | |
1289 return SECMOD_UpdateSlotList(slot->module); | |
1290 } | |
1291 | |
1292 /* | |
1293 * return true if the selected slot ID is not present or doesn't exist | |
1294 */ | |
1295 static PRBool | |
1296 secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID) | |
1297 { | |
1298 PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID); | |
1299 if (slot) { | |
1300 PRBool present = PK11_IsPresent(slot); | |
1301 PK11_FreeSlot(slot); | |
1302 if (present) { | |
1303 return PR_FALSE; | |
1304 } | |
1305 } | |
1306 /* it doesn't exist or isn't present, it's available */ | |
1307 return PR_TRUE; | |
1308 } | |
1309 | |
1310 /* | |
1311 * Find an unused slot id in module. | |
1312 */ | |
1313 static CK_SLOT_ID | |
1314 secmod_FindFreeSlot(SECMODModule *mod) | |
1315 { | |
1316 CK_SLOT_ID i, minSlotID, maxSlotID; | |
1317 | |
1318 /* look for a free slot id on the internal module */ | |
1319 if (mod->internal && mod->isFIPS) { | |
1320 minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID; | |
1321 maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID; | |
1322 } else { | |
1323 minSlotID = SFTK_MIN_USER_SLOT_ID; | |
1324 maxSlotID = SFTK_MAX_USER_SLOT_ID; | |
1325 } | |
1326 for (i=minSlotID; i < maxSlotID; i++) { | |
1327 if (secmod_SlotIsEmpty(mod,i)) { | |
1328 return i; | |
1329 } | |
1330 } | |
1331 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); | |
1332 return (CK_SLOT_ID) -1; | |
1333 } | |
1334 | |
1335 /* | |
1336 * Attempt to open a new slot. | |
1337 * | |
1338 * This works the same os OpenUserDB except it can be called against | |
1339 * any module that understands the softoken protocol for opening new | |
1340 * slots, not just the softoken itself. If the selected module does not | |
1341 * understand the protocol, C_CreateObject will fail with | |
1342 * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set | |
1343 * SEC_ERROR_BAD_DATA. | |
1344 * | |
1345 * NewSlots can be closed with SECMOD_CloseUserDB(); | |
1346 * | |
1347 * Modulespec is module dependent. | |
1348 */ | |
1349 PK11SlotInfo * | |
1350 SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec) | |
1351 { | |
1352 CK_SLOT_ID slotID = 0; | |
1353 PK11SlotInfo *slot; | |
1354 char *escSpec; | |
1355 char *sendSpec; | |
1356 SECStatus rv; | |
1357 | |
1358 slotID = secmod_FindFreeSlot(mod); | |
1359 if (slotID == (CK_SLOT_ID) -1) { | |
1360 return NULL; | |
1361 } | |
1362 | |
1363 if (mod->slotCount == 0) { | |
1364 return NULL; | |
1365 } | |
1366 | |
1367 /* just grab the first slot in the module, any present slot should work */ | |
1368 slot = PK11_ReferenceSlot(mod->slots[0]); | |
1369 if (slot == NULL) { | |
1370 return NULL; | |
1371 } | |
1372 | |
1373 /* we've found the slot, now build the moduleSpec */ | |
1374 escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']'); | |
1375 if (escSpec == NULL) { | |
1376 PK11_FreeSlot(slot); | |
1377 return NULL; | |
1378 } | |
1379 sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec); | |
1380 PORT_Free(escSpec); | |
1381 | |
1382 if (sendSpec == NULL) { | |
1383 /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */ | |
1384 PK11_FreeSlot(slot); | |
1385 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
1386 return NULL; | |
1387 } | |
1388 rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec); | |
1389 PR_smprintf_free(sendSpec); | |
1390 PK11_FreeSlot(slot); | |
1391 if (rv != SECSuccess) { | |
1392 return NULL; | |
1393 } | |
1394 | |
1395 slot = SECMOD_FindSlotByID(mod, slotID); | |
1396 if (slot) { | |
1397 /* if we are in the delay period for the "isPresent" call, reset | |
1398 * the delay since we know things have probably changed... */ | |
1399 if (slot->nssToken && slot->nssToken->slot) { | |
1400 nssSlot_ResetDelay(slot->nssToken->slot); | |
1401 } | |
1402 /* force the slot info structures to properly reset */ | |
1403 (void)PK11_IsPresent(slot); | |
1404 } | |
1405 return slot; | |
1406 } | |
1407 | |
1408 /* | |
1409 * Open a new database using the softoken. The caller is responsible for making | |
1410 * sure the module spec is correct and usable. The caller should ask for one | |
1411 * new database per call if the caller wants to get meaningful information | |
1412 * about the new database. | |
1413 * | |
1414 * moduleSpec is the same data that you would pass to softoken at | |
1415 * initialization time under the 'tokens' options. For example, if you were | |
1416 * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']> | |
1417 * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your | |
1418 * module spec here. The slot ID will be calculated for you by | |
1419 * SECMOD_OpenUserDB(). | |
1420 * | |
1421 * Typical parameters here are configdir, tokenDescription and flags. | |
1422 * | |
1423 * a Full list is below: | |
1424 * | |
1425 * | |
1426 * configDir - The location of the databases for this token. If configDir is | |
1427 * not specified, and noCertDB and noKeyDB is not specified, the load | |
1428 * will fail. | |
1429 * certPrefix - Cert prefix for this token. | |
1430 * keyPrefix - Prefix for the key database for this token. (if not specified, | |
1431 * certPrefix will be used). | |
1432 * tokenDescription - The label value for this token returned in the | |
1433 * CK_TOKEN_INFO structure with an internationalize string (UTF8). | |
1434 * This value will be truncated at 32 bytes (no NULL, partial UTF8 | |
1435 * characters dropped). You should specify a user friendly name here | |
1436 * as this is the value the token will be referred to in most | |
1437 * application UI's. You should make sure tokenDescription is unique. | |
1438 * slotDescription - The slotDescription value for this token returned | |
1439 * in the CK_SLOT_INFO structure with an internationalize string | |
1440 * (UTF8). This value will be truncated at 64 bytes (no NULL, partial | |
1441 * UTF8 characters dropped). This name will not change after the | |
1442 * database is closed. It should have some number to make this unique. | |
1443 * minPWLen - minimum password length for this token. | |
1444 * flags - comma separated list of flag values, parsed case-insensitive. | |
1445 * Valid flags are: | |
1446 * readOnly - Databases should be opened read only. | |
1447 * noCertDB - Don't try to open a certificate database. | |
1448 * noKeyDB - Don't try to open a key database. | |
1449 * forceOpen - Don't fail to initialize the token if the | |
1450 * databases could not be opened. | |
1451 * passwordRequired - zero length passwords are not acceptable | |
1452 * (valid only if there is a keyDB). | |
1453 * optimizeSpace - allocate smaller hash tables and lock tables. | |
1454 * When this flag is not specified, Softoken will allocate | |
1455 * large tables to prevent lock contention. | |
1456 */ | |
1457 PK11SlotInfo * | |
1458 SECMOD_OpenUserDB(const char *moduleSpec) | |
1459 { | |
1460 SECMODModule *mod; | |
1461 | |
1462 if (moduleSpec == NULL) { | |
1463 return NULL; | |
1464 } | |
1465 | |
1466 /* NOTE: unlike most PK11 function, this does not return a reference | |
1467 * to the module */ | |
1468 mod = SECMOD_GetInternalModule(); | |
1469 if (!mod) { | |
1470 /* shouldn't happen */ | |
1471 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
1472 return NULL; | |
1473 } | |
1474 return SECMOD_OpenNewSlot(mod, moduleSpec); | |
1475 } | |
1476 | |
1477 | |
1478 /* | |
1479 * close an already opened user database. NOTE: the database must be | |
1480 * in the internal token, and must be one created with SECMOD_OpenUserDB(). | |
1481 * Once the database is closed, the slot will remain as an empty slot | |
1482 * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot(). | |
1483 */ | |
1484 SECStatus | |
1485 SECMOD_CloseUserDB(PK11SlotInfo *slot) | |
1486 { | |
1487 SECStatus rv; | |
1488 char *sendSpec; | |
1489 | |
1490 sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID); | |
1491 if (sendSpec == NULL) { | |
1492 /* PR_smprintf does not set no memory error */ | |
1493 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
1494 return SECFailure; | |
1495 } | |
1496 rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec); | |
1497 PR_smprintf_free(sendSpec); | |
1498 /* if we are in the delay period for the "isPresent" call, reset | |
1499 * the delay since we know things have probably changed... */ | |
1500 if (slot->nssToken && slot->nssToken->slot) { | |
1501 nssSlot_ResetDelay(slot->nssToken->slot); | |
1502 /* force the slot info structures to properly reset */ | |
1503 (void)PK11_IsPresent(slot); | |
1504 } | |
1505 return rv; | |
1506 } | |
1507 | |
1508 /* | |
1509 * Restart PKCS #11 modules after a fork(). See secmod.h for more information. | |
1510 */ | |
1511 SECStatus | |
1512 SECMOD_RestartModules(PRBool force) | |
1513 { | |
1514 SECMODModuleList *mlp; | |
1515 SECStatus rrv = SECSuccess; | |
1516 int lastError = 0; | |
1517 | |
1518 if (!moduleLock) { | |
1519 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
1520 return SECFailure; | |
1521 } | |
1522 | |
1523 /* Only need to restart the PKCS #11 modules that were initialized */ | |
1524 SECMOD_GetReadLock(moduleLock); | |
1525 for (mlp = modules; mlp != NULL; mlp = mlp->next) { | |
1526 SECMODModule *mod = mlp->module; | |
1527 CK_ULONG count; | |
1528 SECStatus rv; | |
1529 int i; | |
1530 | |
1531 /* If the module needs to be reset, do so */ | |
1532 if (force || (PK11_GETTAB(mod)-> | |
1533 C_GetSlotList(CK_FALSE, NULL, &count) != CKR_OK)) { | |
1534 PRBool alreadyLoaded; | |
1535 /* first call Finalize. This is not required by PKCS #11, but some | |
1536 * older modules require it, and it doesn't hurt (compliant modules | |
1537 * will return CKR_NOT_INITIALIZED */ | |
1538 (void) PK11_GETTAB(mod)->C_Finalize(NULL); | |
1539 /* now initialize the module, this function reinitializes | |
1540 * a module in place, preserving existing slots (even if they | |
1541 * no longer exist) */ | |
1542 rv = secmod_ModuleInit(mod, NULL, &alreadyLoaded); | |
1543 if (rv != SECSuccess) { | |
1544 /* save the last error code */ | |
1545 lastError = PORT_GetError(); | |
1546 rrv = rv; | |
1547 /* couldn't reinit the module, disable all its slots */ | |
1548 for (i=0; i < mod->slotCount; i++) { | |
1549 mod->slots[i]->disabled = PR_TRUE; | |
1550 mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; | |
1551 } | |
1552 continue; | |
1553 } | |
1554 for (i=0; i < mod->slotCount; i++) { | |
1555 /* get new token sessions, bump the series up so that | |
1556 * we refresh other old sessions. This will tell much of | |
1557 * NSS to flush cached handles it may hold as well */ | |
1558 rv = PK11_InitToken(mod->slots[i],PR_TRUE); | |
1559 /* PK11_InitToken could fail if the slot isn't present. | |
1560 * If it is present, though, something is wrong and we should | |
1561 * disable the slot and let the caller know. */ | |
1562 if (rv != SECSuccess && PK11_IsPresent(mod->slots[i])) { | |
1563 /* save the last error code */ | |
1564 lastError = PORT_GetError(); | |
1565 rrv = rv; | |
1566 /* disable the token */ | |
1567 mod->slots[i]->disabled = PR_TRUE; | |
1568 mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; | |
1569 } | |
1570 } | |
1571 } | |
1572 } | |
1573 SECMOD_ReleaseReadLock(moduleLock); | |
1574 | |
1575 /* | |
1576 * on multiple failures, we are only returning the lastError. The caller | |
1577 * can determine which slots are bad by calling PK11_IsDisabled(). | |
1578 */ | |
1579 if (rrv != SECSuccess) { | |
1580 /* restore the last error code */ | |
1581 PORT_SetError(lastError); | |
1582 } | |
1583 | |
1584 return rrv; | |
1585 } |