Bug Summary

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