Bug Summary

File:s/lib/pk11wrap/pk11util.c
Warning:line 375, column 18
Access to field 'internal' results in a dereference of a null pointer (loaded from field 'module')

Annotated Source Code

Press '?' to see keyboard shortcuts

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