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-10-17-231001-351276-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
805/* Funtion reports true if module of modType is installed/configured */
806PRBool
807SECMOD_IsModulePresent(unsigned long int pubCipherEnableFlags)
808{
809 PRBool result = PR_FALSE0;
810 SECMODModuleList *mods;
811
812 if (!moduleLock) {
813 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED);
814 return result;
815 }
816 SECMOD_GetReadLock(moduleLock);
817 mods = SECMOD_GetDefaultModuleList();
818 for (; mods != NULL((void*)0); mods = mods->next) {
819 if (mods->module->ssl[0] &
820 SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) {
821 result = PR_TRUE1;
822 }
823 }
824
825 SECMOD_ReleaseReadLock(moduleLock);
826 return result;
827}
828
829/* create a new ModuleListElement */
830SECMODModuleList *
831SECMOD_NewModuleListElement(void)
832{
833 SECMODModuleList *newModList;
834
835 newModList = (SECMODModuleList *)PORT_AllocPORT_Alloc_Util(sizeof(SECMODModuleList));
836 if (newModList) {
837 newModList->next = NULL((void*)0);
838 newModList->module = NULL((void*)0);
839 }
840 return newModList;
841}
842
843/*
844 * make a new reference to a module so It doesn't go away on us
845 */
846SECMODModule *
847SECMOD_ReferenceModule(SECMODModule *module)
848{
849 PR_Lock(module->refLock);
850 PORT_ReleaseAssert(module->refCount > 0)((module->refCount > 0) ? ((void)0) : PR_Assert("module->refCount > 0"
, "/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c",
850))
;
851
852 module->refCount++;
853 PR_Unlock(module->refLock);
854 return module;
855}
856
857/* destroy an existing module */
858void
859SECMOD_DestroyModule(SECMODModule *module)
860{
861 PRBool willfree = PR_FALSE0;
862 int slotCount;
863 int i;
864
865 PR_Lock(module->refLock);
866 PORT_ReleaseAssert(module->refCount > 0)((module->refCount > 0) ? ((void)0) : PR_Assert("module->refCount > 0"
, "/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c",
866))
;
867 if (module->refCount-- == 1) {
868 willfree = PR_TRUE1;
869 }
870 PR_Unlock(module->refLock);
871
872 if (!willfree) {
873 return;
874 }
875
876 if (module->parent != NULL((void*)0)) {
877 SECMODModule *parent = module->parent;
878 /* paranoia, don't loop forever if the modules are looped */
879 module->parent = NULL((void*)0);
880 SECMOD_DestroyModule(parent);
881 }
882
883 /* slots can't really disappear until our module starts freeing them,
884 * so this check is safe */
885 slotCount = module->slotCount;
886 if (slotCount == 0) {
887 SECMOD_SlotDestroyModule(module, PR_FALSE0);
888 return;
889 }
890
891 /* now free all out slots, when they are done, they will cause the
892 * module to disappear altogether */
893 for (i = 0; i < slotCount; i++) {
894 if (!module->slots[i]->disabled) {
895 PK11_ClearSlotList(module->slots[i]);
896 }
897 PK11_FreeSlot(module->slots[i]);
898 }
899 /* WARNING: once the last slot has been freed is it possible (even likely)
900 * that module is no more... touching it now is a good way to go south */
901}
902
903/* we can only get here if we've destroyed the module, or some one has
904 * erroneously freed a slot that wasn't referenced. */
905void
906SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot)
907{
908 PRBool willfree = PR_FALSE0;
909 if (fromSlot) {
910 PORT_Assert(module->refCount == 0)((module->refCount == 0) ? ((void)0) : PR_Assert("module->refCount == 0"
, "/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c",
910))
;
911 PR_Lock(module->refLock);
912 if (module->slotCount-- == 1) {
913 willfree = PR_TRUE1;
914 }
915 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"
, 915))
;
916 PR_Unlock(module->refLock);
917 if (!willfree)
918 return;
919 }
920
921 if (module == pendingModule) {
922 pendingModule = NULL((void*)0);
923 }
924
925 if (module->loaded) {
926 SECMOD_UnloadModule(module);
927 }
928 PR_DestroyLock(module->refLock);
929 PORT_FreeArenaPORT_FreeArena_Util(module->arena, PR_FALSE0);
930 secmod_PrivateModuleCount--;
931}
932
933/* destroy a list element
934 * this destroys a single element, and returns the next element
935 * on the chain. It makes it easy to implement for loops to delete
936 * the chain. It also make deleting a single element easy */
937SECMODModuleList *
938SECMOD_DestroyModuleListElement(SECMODModuleList *element)
939{
940 SECMODModuleList *next = element->next;
941
942 if (element->module) {
943 SECMOD_DestroyModule(element->module);
944 element->module = NULL((void*)0);
945 }
946 PORT_FreePORT_Free_Util(element);
947 return next;
948}
949
950/*
951 * Destroy an entire module list
952 */
953void
954SECMOD_DestroyModuleList(SECMODModuleList *list)
955{
956 SECMODModuleList *lp;
957
958 for (lp = list; lp != NULL((void*)0); lp = SECMOD_DestroyModuleListElement(lp))
959 ;
960}
961
962PRBool
963SECMOD_CanDeleteInternalModule(void)
964{
965#ifdef NSS_FIPS_DISABLED1
966 return PR_FALSE0;
967#else
968 return (PRBool)((pendingModule == NULL((void*)0)) && !SECMOD_GetSystemFIPSEnabled());
969#endif
970}
971
972/*
973 * check to see if the module has added new slots. PKCS 11 v2.20 allows for
974 * modules to add new slots, but never remove them. Slots cannot be added
975 * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent
976 * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently
977 * grow on the caller. It is permissible for the slots to increase between
978 * successive calls with NULL to get the size.
979 *
980 * Caller must not hold a module list read lock.
981 */
982SECStatus
983SECMOD_UpdateSlotList(SECMODModule *mod)
984{
985 CK_RV crv;
986 CK_ULONG count;
987 CK_ULONG i, oldCount;
988 PRBool freeRef = PR_FALSE0;
989 void *mark = NULL((void*)0);
990 CK_ULONG *slotIDs = NULL((void*)0);
991 PK11SlotInfo **newSlots = NULL((void*)0);
992 PK11SlotInfo **oldSlots = NULL((void*)0);
993
994 if (!moduleLock) {
995 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED);
996 return SECFailure;
997 }
998
999 /* C_GetSlotList is not a session function, make sure
1000 * calls are serialized */
1001 PR_Lock(mod->refLock);
1002 freeRef = PR_TRUE1;
1003 /* see if the number of slots have changed */
1004 crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_2_PTR)((mod)->functionList))->C_GetSlotList(PR_FALSE0, NULL((void*)0), &count);
1005 if (crv != CKR_OK0x00000000UL) {
1006 PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv));
1007 goto loser;
1008 }
1009 /* nothing new, blow out early, we want this function to be quick
1010 * and cheap in the normal case */
1011 if (count == mod->slotCount) {
1012 PR_Unlock(mod->refLock);
1013 return SECSuccess;
1014 }
1015 if (count < (CK_ULONG)mod->slotCount) {
1016 /* shouldn't happen with a properly functioning PKCS #11 module */
1017 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INCOMPATIBLE_PKCS11);
1018 goto loser;
1019 }
1020
1021 /* get the new slot list */
1022 slotIDs = PORT_NewArray(CK_SLOT_ID, count)(CK_SLOT_ID *)PORT_Alloc_Util(sizeof(CK_SLOT_ID) * (count));
1023 if (slotIDs == NULL((void*)0)) {
1024 goto loser;
1025 }
1026
1027 crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_2_PTR)((mod)->functionList))->C_GetSlotList(PR_FALSE0, slotIDs, &count);
1028 if (crv != CKR_OK0x00000000UL) {
1029 PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv));
1030 goto loser;
1031 }
1032 freeRef = PR_FALSE0;
1033 PR_Unlock(mod->refLock);
1034 mark = PORT_ArenaMarkPORT_ArenaMark_Util(mod->arena);
1035 if (mark == NULL((void*)0)) {
1036 goto loser;
1037 }
1038 newSlots = PORT_ArenaZNewArray(mod->arena, PK11SlotInfo *, count)(PK11SlotInfo * *)PORT_ArenaZAlloc_Util(mod->arena, sizeof
(PK11SlotInfo *) * (count))
;
1039
1040 /* walk down the new slot ID list returned from the module. We keep
1041 * the old slots which match a returned ID, and we initialize the new
1042 * slots. */
1043 for (i = 0; i < count; i++) {
1044 PK11SlotInfo *slot = SECMOD_FindSlotByID(mod, slotIDs[i]);
1045
1046 if (!slot) {
1047 /* we have a new slot create a new slot data structure */
1048 slot = PK11_NewSlotInfo(mod);
1049 if (!slot) {
1050 goto loser;
1051 }
1052 PK11_InitSlot(mod, slotIDs[i], slot);
1053 STAN_InitTokenForSlotInfo(NULL((void*)0), slot);
1054 }
1055 newSlots[i] = slot;
1056 }
1057 STAN_ResetTokenInterator(NULL((void*)0));
1058 PORT_FreePORT_Free_Util(slotIDs);
1059 slotIDs = NULL((void*)0);
1060 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(mod->arena, mark);
1061
1062 /* until this point we're still using the old slot list. Now we update
1063 * module slot list. We update the slots (array) first then the count,
1064 * since we've already guarrenteed that count has increased (just in case
1065 * someone is looking at the slots field of module without holding the
1066 * moduleLock */
1067 SECMOD_GetWriteLock(moduleLock);
1068 oldCount = mod->slotCount;
1069 oldSlots = mod->slots;
1070 mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is
1071 * allocated out of the module arena and won't
1072 * be freed until the module is freed */
1073 mod->slotCount = count;
1074 SECMOD_ReleaseWriteLock(moduleLock);
1075 /* free our old references before forgetting about oldSlot*/
1076 for (i = 0; i < oldCount; i++) {
1077 PK11_FreeSlot(oldSlots[i]);
1078 }
1079 return SECSuccess;
1080
1081loser:
1082 if (freeRef) {
1083 PR_Unlock(mod->refLock);
1084 }
1085 if (slotIDs) {
1086 PORT_FreePORT_Free_Util(slotIDs);
1087 }
1088 /* free all the slots we allocated. newSlots are part of the
1089 * mod arena. NOTE: the newSlots array contain both new and old
1090 * slots, but we kept a reference to the old slots when we built the new
1091 * array, so we need to free all the slots in newSlots array. */
1092 if (newSlots) {
1093 for (i = 0; i < count; i++) {
1094 if (newSlots[i] == NULL((void*)0)) {
1095 break; /* hit the last one */
1096 }
1097 PK11_FreeSlot(newSlots[i]);
1098 }
1099 }
1100 /* must come after freeing newSlots */
1101 if (mark) {
1102 PORT_ArenaReleasePORT_ArenaRelease_Util(mod->arena, mark);
1103 }
1104 return SECFailure;
1105}
1106
1107/*
1108 * this handles modules that do not support C_WaitForSlotEvent().
1109 * The internal flags are stored. Note that C_WaitForSlotEvent() does not
1110 * have a timeout, so we don't have one for handleWaitForSlotEvent() either.
1111 */
1112PK11SlotInfo *
1113secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags,
1114 PRIntervalTime latency)
1115{
1116 PRBool removableSlotsFound = PR_FALSE0;
1117 int i;
1118 int error = SEC_ERROR_NO_EVENT;
1119
1120 if (!moduleLock) {
1121 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED);
1122 return NULL((void*)0);
1123 }
1124 PR_Lock(mod->refLock);
1125 if (mod->evControlMask & SECMOD_END_WAIT0x01) {
1126 mod->evControlMask &= ~SECMOD_END_WAIT0x01;
1127 PR_Unlock(mod->refLock);
1128 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_EVENT);
1129 return NULL((void*)0);
1130 }
1131 mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT0x02;
1132 while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT0x02) {
1133 PR_Unlock(mod->refLock);
1134 /* now is a good time to see if new slots have been added */
1135 SECMOD_UpdateSlotList(mod);
1136
1137 /* loop through all the slots on a module */
1138 SECMOD_GetReadLock(moduleLock);
1139 for (i = 0; i < mod->slotCount; i++) {
1140 PK11SlotInfo *slot = mod->slots[i];
1141 PRUint16 series;
1142 PRBool present;
1143
1144 /* perm modules do not change */
1145 if (slot->isPerm) {
1146 continue;
1147 }
1148 removableSlotsFound = PR_TRUE1;
1149 /* simulate the PKCS #11 module flags. are the flags different
1150 * from the last time we called? */
1151 series = slot->series;
1152 present = PK11_IsPresent(slot);
1153 if ((slot->flagSeries != series) || (slot->flagState != present)) {
1154 slot->flagState = present;
1155 slot->flagSeries = series;
1156 SECMOD_ReleaseReadLock(moduleLock);
1157 PR_Lock(mod->refLock);
1158 mod->evControlMask &= ~SECMOD_END_WAIT0x01;
1159 PR_Unlock(mod->refLock);
1160 return PK11_ReferenceSlot(slot);
1161 }
1162 }
1163 SECMOD_ReleaseReadLock(moduleLock);
1164 /* if everything was perm modules, don't lock up forever */
1165 if ((mod->slotCount != 0) && !removableSlotsFound) {
1166 error = SEC_ERROR_NO_SLOT_SELECTED;
1167 PR_Lock(mod->refLock);
1168 break;
1169 }
1170 if (flags & CKF_DONT_BLOCK1) {
1171 PR_Lock(mod->refLock);
1172 break;
1173 }
1174 PR_Sleep(latency);
1175 PR_Lock(mod->refLock);
1176 }
1177 mod->evControlMask &= ~SECMOD_END_WAIT0x01;
1178 PR_Unlock(mod->refLock);
1179 PORT_SetErrorPORT_SetError_Util(error);
1180 return NULL((void*)0);
1181}
1182
1183/*
1184 * this function waits for a token event on any slot of a given module
1185 * This function should not be called from more than one thread of the
1186 * same process (though other threads can make other library calls
1187 * on this module while this call is blocked).
1188 */
1189PK11SlotInfo *
1190SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags,
1191 PRIntervalTime latency)
1192{
1193 CK_SLOT_ID id;
1194 CK_RV crv;
1195 PK11SlotInfo *slot;
1196
1197 if (!pk11_getFinalizeModulesOption() ||
1198 ((mod->cryptokiVersion.major == 2) &&
1199 (mod->cryptokiVersion.minor < 1))) {
1200 /* if we are sharing the module with other software in our
1201 * address space, we can't reliably use C_WaitForSlotEvent(),
1202 * and if the module is version 2.0, C_WaitForSlotEvent() doesn't
1203 * exist */
1204 return secmod_HandleWaitForSlotEvent(mod, flags, latency);
1205 }
1206 /* first the the PKCS #11 call */
1207 PR_Lock(mod->refLock);
1208 if (mod->evControlMask & SECMOD_END_WAIT0x01) {
1209 goto end_wait;
1210 }
1211 mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT0x04;
1212 PR_Unlock(mod->refLock);
1213 crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_2_PTR)((mod)->functionList))->C_WaitForSlotEvent(flags, &id, NULL((void*)0));
1214 PR_Lock(mod->refLock);
1215 mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT0x04;
1216 /* if we are in end wait, short circuit now, don't even risk
1217 * going into secmod_HandleWaitForSlotEvent */
1218 if (mod->evControlMask & SECMOD_END_WAIT0x01) {
1219 goto end_wait;
1220 }
1221 PR_Unlock(mod->refLock);
1222 if (crv == CKR_FUNCTION_NOT_SUPPORTED0x00000054UL) {
1223 /* module doesn't support that call, simulate it */
1224 return secmod_HandleWaitForSlotEvent(mod, flags, latency);
1225 }
1226 if (crv != CKR_OK0x00000000UL) {
1227 /* we can get this error if finalize was called while we were
1228 * still running. This is the only way to force a C_WaitForSlotEvent()
1229 * to return in PKCS #11. In this case, just return that there
1230 * was no event. */
1231 if (crv == CKR_CRYPTOKI_NOT_INITIALIZED0x00000190UL) {
1232 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_EVENT);
1233 } else {
1234 PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv));
1235 }
1236 return NULL((void*)0);
1237 }
1238 slot = SECMOD_FindSlotByID(mod, id);
1239 if (slot == NULL((void*)0)) {
1240 /* possibly a new slot that was added? */
1241 SECMOD_UpdateSlotList(mod);
1242 slot = SECMOD_FindSlotByID(mod, id);
1243 }
1244 /* if we are in the delay period for the "isPresent" call, reset
1245 * the delay since we know things have probably changed... */
1246 if (slot) {
1247 NSSToken *nssToken = PK11Slot_GetNSSToken(slot);
1248 if (nssToken) {
1249 if (nssToken->slot) {
1250 nssSlot_ResetDelay(nssToken->slot);
1251 }
1252 (void)nssToken_Destroy(nssToken);
1253 }
1254 }
1255 return slot;
1256
1257/* must be called with the lock on. */
1258end_wait:
1259 mod->evControlMask &= ~SECMOD_END_WAIT0x01;
1260 PR_Unlock(mod->refLock);
1261 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_EVENT);
1262 return NULL((void*)0);
1263}
1264
1265/*
1266 * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic
1267 * function, possibly bringing down the pkcs #11 module in question. This
1268 * should be OK because 1) it does reinitialize, and 2) it should only be
1269 * called when we are on our way to tear the whole system down anyway.
1270 */
1271SECStatus
1272SECMOD_CancelWait(SECMODModule *mod)
1273{
1274 unsigned long controlMask;
1275 SECStatus rv = SECSuccess;
1276 CK_RV crv;
1277
1278 PR_Lock(mod->refLock);
1279 mod->evControlMask |= SECMOD_END_WAIT0x01;
1280 controlMask = mod->evControlMask;
1281 if (controlMask & SECMOD_WAIT_PKCS11_EVENT0x04) {
1282 if (!pk11_getFinalizeModulesOption()) {
1283 /* can't get here unless pk11_getFinalizeModulesOption is set */
1284 PORT_Assert(0)((0) ? ((void)0) : PR_Assert("0", "/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c"
, 1284))
;
1285 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1286 rv = SECFailure;
1287 goto loser;
1288 }
1289 /* NOTE: this call will drop all transient keys, in progress
1290 * operations, and any authentication. This is the only documented
1291 * way to get WaitForSlotEvent to return. Also note: for non-thread
1292 * safe tokens, we need to hold the module lock, this is not yet at
1293 * system shutdown/startup time, so we need to protect these calls */
1294 crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_2_PTR)((mod)->functionList))->C_Finalize(NULL((void*)0));
1295 /* ok, we slammed the module down, now we need to reinit it in case
1296 * we intend to use it again */
1297 if (CKR_OK0x00000000UL == crv) {
1298 PRBool alreadyLoaded;
1299 secmod_ModuleInit(mod, NULL((void*)0), &alreadyLoaded);
1300 } else {
1301 /* Finalized failed for some reason, notify the application
1302 * so maybe it has a prayer of recovering... */
1303 PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv));
1304 rv = SECFailure;
1305 }
1306 } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT0x02) {
1307 mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT0x02;
1308 /* Simulated events will eventually timeout
1309 * and wake up in the loop */
1310 }
1311loser:
1312 PR_Unlock(mod->refLock);
1313 return rv;
1314}
1315
1316/*
1317 * check to see if the module has removable slots that we may need to
1318 * watch for.
1319 */
1320PRBool
1321SECMOD_HasRemovableSlots(SECMODModule *mod)
1322{
1323 PRBool ret = PR_FALSE0;
1324 if (!moduleLock) {
1325 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED);
1326 return ret;
1327 }
1328 SECMOD_GetReadLock(moduleLock);
1329 ret = SECMOD_LockedModuleHasRemovableSlots(mod);
1330 SECMOD_ReleaseReadLock(moduleLock);
1331 return ret;
1332}
1333
1334PRBool
1335SECMOD_LockedModuleHasRemovableSlots(SECMODModule *mod)
1336{
1337 int i;
1338 PRBool ret;
1339 if (mod->slotCount == 0) {
1340 return PR_TRUE1;
1341 }
1342
1343 ret = PR_FALSE0;
1344 for (i = 0; i < mod->slotCount; i++) {
1345 PK11SlotInfo *slot = mod->slots[i];
1346 /* perm modules are not inserted or removed */
1347 if (slot->isPerm) {
1348 continue;
1349 }
1350 ret = PR_TRUE1;
1351 break;
1352 }
1353 return ret;
1354}
1355
1356/*
1357 * helper function to actually create and destroy user defined slots
1358 */
1359static SECStatus
1360secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass,
1361 const char *sendSpec)
1362{
1363 CK_OBJECT_HANDLE dummy;
1364 CK_ATTRIBUTE template[2];
1365 CK_ATTRIBUTE *attrs = template;
1366 CK_RV crv;
1367
1368 PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass))(attrs)->type = (0x00000000UL); (attrs)->pValue = (&
objClass); (attrs)->ulValueLen = (sizeof(objClass));
;
1369 attrs++;
1370 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);
1371 strlen(sendSpec) + 1)(attrs)->type = (((0x80000000UL | 0x4E534350) + 24)); (attrs
)->pValue = ((unsigned char *)sendSpec); (attrs)->ulValueLen
= (strlen(sendSpec) + 1);
;
1372 attrs++;
1373
1374 PORT_Assert(attrs - template <= 2)((attrs - template <= 2) ? ((void)0) : PR_Assert("attrs - template <= 2"
, "/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c",
1374))
;
1375
1376 PK11_EnterSlotMonitor(slot);
1377 crv = PK11_CreateNewObject(slot, slot->session,
1378 template, attrs - template, PR_FALSE0, &dummy);
1379 PK11_ExitSlotMonitor(slot);
1380
1381 if (crv != CKR_OK0x00000000UL) {
1382 PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv));
1383 return SECFailure;
1384 }
1385 return SECMOD_UpdateSlotList(slot->module);
1386}
1387
1388/*
1389 * return true if the selected slot ID is not present or doesn't exist
1390 */
1391static PRBool
1392secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID)
1393{
1394 PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID);
1395 if (slot) {
1396 PRBool present = PK11_IsPresent(slot);
1397 PK11_FreeSlot(slot);
1398 if (present) {
1399 return PR_FALSE0;
1400 }
1401 }
1402 /* it doesn't exist or isn't present, it's available */
1403 return PR_TRUE1;
1404}
1405
1406/*
1407 * Find an unused slot id in module.
1408 */
1409static CK_SLOT_ID
1410secmod_FindFreeSlot(SECMODModule *mod)
1411{
1412 CK_SLOT_ID i, minSlotID, maxSlotID;
1413
1414 /* look for a free slot id on the internal module */
1415 if (mod->internal && mod->isFIPS) {
1416 minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID101;
1417 maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID127;
1418 } else {
1419 minSlotID = SFTK_MIN_USER_SLOT_ID4;
1420 maxSlotID = SFTK_MAX_USER_SLOT_ID100;
1421 }
1422 for (i = minSlotID; i < maxSlotID; i++) {
1423 if (secmod_SlotIsEmpty(mod, i)) {
1424 return i;
1425 }
1426 }
1427 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_SLOT_SELECTED);
1428 return (CK_SLOT_ID)-1;
1429}
1430
1431/*
1432 * Attempt to open a new slot.
1433 *
1434 * This works the same os OpenUserDB except it can be called against
1435 * any module that understands the softoken protocol for opening new
1436 * slots, not just the softoken itself. If the selected module does not
1437 * understand the protocol, C_CreateObject will fail with
1438 * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set
1439 * SEC_ERROR_BAD_DATA.
1440 *
1441 * NewSlots can be closed with SECMOD_CloseUserDB();
1442 *
1443 * Modulespec is module dependent.
1444 */
1445PK11SlotInfo *
1446SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec)
1447{
1448 CK_SLOT_ID slotID = 0;
1449 PK11SlotInfo *slot;
1450 char *escSpec;
1451 char *sendSpec;
1452 SECStatus rv;
1453
1454 slotID = secmod_FindFreeSlot(mod);
1455 if (slotID == (CK_SLOT_ID)-1) {
1456 return NULL((void*)0);
1457 }
1458
1459 if (mod->slotCount == 0) {
1460 return NULL((void*)0);
1461 }
1462
1463 /* just grab the first slot in the module, any present slot should work */
1464 slot = PK11_ReferenceSlot(mod->slots[0]);
1465 if (slot == NULL((void*)0)) {
1466 return NULL((void*)0);
1467 }
1468
1469 /* we've found the slot, now build the moduleSpec */
1470 escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']');
1471 if (escSpec == NULL((void*)0)) {
1472 PK11_FreeSlot(slot);
1473 return NULL((void*)0);
1474 }
1475 sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec);
1476 PORT_FreePORT_Free_Util(escSpec);
1477
1478 if (sendSpec == NULL((void*)0)) {
1479 /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */
1480 PK11_FreeSlot(slot);
1481 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1482 return NULL((void*)0);
1483 }
1484 rv = secmod_UserDBOp(slot, CKO_NSS_NEWSLOT((0x80000000UL | 0x4E534350) + 5), sendSpec);
1485 PR_smprintf_free(sendSpec);
1486 PK11_FreeSlot(slot);
1487 if (rv != SECSuccess) {
1488 return NULL((void*)0);
1489 }
1490
1491 slot = SECMOD_FindSlotByID(mod, slotID);
1492 if (slot) {
1493 /* if we are in the delay period for the "isPresent" call, reset
1494 * the delay since we know things have probably changed... */
1495 NSSToken *nssToken = PK11Slot_GetNSSToken(slot);
1496 if (nssToken) {
1497 if (nssToken->slot) {
1498 nssSlot_ResetDelay(nssToken->slot);
1499 }
1500 (void)nssToken_Destroy(nssToken);
1501 }
1502 /* force the slot info structures to properly reset */
1503 (void)PK11_IsPresent(slot);
1504 }
1505 return slot;
1506}
1507
1508/*
1509 * given a module spec, find the slot in the module for it.
1510 */
1511PK11SlotInfo *
1512secmod_FindSlotFromModuleSpec(const char *moduleSpec, SECMODModule *module)
1513{
1514 CK_SLOT_ID slot_id = secmod_GetSlotIDFromModuleSpec(moduleSpec, module);
1515 if (slot_id == -1) {
1516 return NULL((void*)0);
1517 }
1518
1519 return SECMOD_FindSlotByID(module, slot_id);
1520}
1521
1522/*
1523 * Open a new database using the softoken. The caller is responsible for making
1524 * sure the module spec is correct and usable. The caller should ask for one
1525 * new database per call if the caller wants to get meaningful information
1526 * about the new database.
1527 *
1528 * moduleSpec is the same data that you would pass to softoken at
1529 * initialization time under the 'tokens' options. For example, if you were
1530 * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']>
1531 * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your
1532 * module spec here. The slot ID will be calculated for you by
1533 * SECMOD_OpenUserDB().
1534 *
1535 * Typical parameters here are configdir, tokenDescription and flags.
1536 *
1537 * a Full list is below:
1538 *
1539 *
1540 * configDir - The location of the databases for this token. If configDir is
1541 * not specified, and noCertDB and noKeyDB is not specified, the load
1542 * will fail.
1543 * certPrefix - Cert prefix for this token.
1544 * keyPrefix - Prefix for the key database for this token. (if not specified,
1545 * certPrefix will be used).
1546 * tokenDescription - The label value for this token returned in the
1547 * CK_TOKEN_INFO structure with an internationalize string (UTF8).
1548 * This value will be truncated at 32 bytes (no NULL, partial UTF8
1549 * characters dropped). You should specify a user friendly name here
1550 * as this is the value the token will be referred to in most
1551 * application UI's. You should make sure tokenDescription is unique.
1552 * slotDescription - The slotDescription value for this token returned
1553 * in the CK_SLOT_INFO structure with an internationalize string
1554 * (UTF8). This value will be truncated at 64 bytes (no NULL, partial
1555 * UTF8 characters dropped). This name will not change after the
1556 * database is closed. It should have some number to make this unique.
1557 * minPWLen - minimum password length for this token.
1558 * flags - comma separated list of flag values, parsed case-insensitive.
1559 * Valid flags are:
1560 * readOnly - Databases should be opened read only.
1561 * noCertDB - Don't try to open a certificate database.
1562 * noKeyDB - Don't try to open a key database.
1563 * forceOpen - Don't fail to initialize the token if the
1564 * databases could not be opened.
1565 * passwordRequired - zero length passwords are not acceptable
1566 * (valid only if there is a keyDB).
1567 * optimizeSpace - allocate smaller hash tables and lock tables.
1568 * When this flag is not specified, Softoken will allocate
1569 * large tables to prevent lock contention.
1570 */
1571PK11SlotInfo *
1572SECMOD_OpenUserDB(const char *moduleSpec)
1573{
1574 SECMODModule *mod;
1575 SECMODConfigList *conflist = NULL((void*)0);
1576 int count = 0;
1577
1578 if (moduleSpec == NULL((void*)0)) {
1579 return NULL((void*)0);
1580 }
1581
1582 /* NOTE: unlike most PK11 function, this does not return a reference
1583 * to the module */
1584 mod = SECMOD_GetInternalModule();
1585 if (!mod) {
1586 /* shouldn't happen */
1587 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1588 return NULL((void*)0);
1589 }
1590
1591 /* make sure we don't open the same database twice. We only understand
1592 * the moduleSpec for internal databases well enough to do this, so only
1593 * do this in OpenUserDB */
1594 conflist = secmod_GetConfigList(mod->isFIPS, mod->libraryParams, &count);
1595 if (conflist) {
1596 PK11SlotInfo *slot = NULL((void*)0);
1597 if (secmod_MatchConfigList(moduleSpec, conflist, count)) {
1598 slot = secmod_FindSlotFromModuleSpec(moduleSpec, mod);
1599 }
1600 secmod_FreeConfigList(conflist, count);
1601 if (slot) {
1602 return slot;
1603 }
1604 }
1605 return SECMOD_OpenNewSlot(mod, moduleSpec);
1606}
1607
1608/*
1609 * close an already opened user database. NOTE: the database must be
1610 * in the internal token, and must be one created with SECMOD_OpenUserDB().
1611 * Once the database is closed, the slot will remain as an empty slot
1612 * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot().
1613 */
1614SECStatus
1615SECMOD_CloseUserDB(PK11SlotInfo *slot)
1616{
1617 SECStatus rv;
1618 char *sendSpec;
1619
1620 sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID);
1621 if (sendSpec == NULL((void*)0)) {
1622 /* PR_smprintf does not set no memory error */
1623 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1624 return SECFailure;
1625 }
1626 rv = secmod_UserDBOp(slot, CKO_NSS_DELSLOT((0x80000000UL | 0x4E534350) + 6), sendSpec);
1627 PR_smprintf_free(sendSpec);
1628 /* if we are in the delay period for the "isPresent" call, reset
1629 * the delay since we know things have probably changed... */
1630 NSSToken *nssToken = PK11Slot_GetNSSToken(slot);
1631 if (nssToken) {
1632 if (nssToken->slot) {
1633 nssSlot_ResetDelay(nssToken->slot);
1634 }
1635 (void)nssToken_Destroy(nssToken);
1636 /* force the slot info structures to properly reset */
1637 (void)PK11_IsPresent(slot);
1638 }
1639 return rv;
1640}
1641
1642/*
1643 * Restart PKCS #11 modules after a fork(). See secmod.h for more information.
1644 */
1645SECStatus
1646SECMOD_RestartModules(PRBool force)
1647{
1648 SECMODModuleList *mlp;
1649 SECStatus rrv = SECSuccess;
1650 int lastError = 0;
1651
1652 if (!moduleLock) {
1653 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED);
1654 return SECFailure;
1655 }
1656
1657 /* Only need to restart the PKCS #11 modules that were initialized */
1658 SECMOD_GetReadLock(moduleLock);
1659 for (mlp = modules; mlp != NULL((void*)0); mlp = mlp->next) {
1660 SECMODModule *mod = mlp->module;
1661 CK_ULONG count;
1662 SECStatus rv;
1663 int i;
1664
1665 /* If the module needs to be reset, do so */
1666 if (force || (PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_2_PTR)((mod)->functionList))->C_GetSlotList(CK_FALSE0, NULL((void*)0), &count) != CKR_OK0x00000000UL)) {
1667 PRBool alreadyLoaded;
1668 /* first call Finalize. This is not required by PKCS #11, but some
1669 * older modules require it, and it doesn't hurt (compliant modules
1670 * will return CKR_NOT_INITIALIZED */
1671 (void)PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_2_PTR)((mod)->functionList))->C_Finalize(NULL((void*)0));
1672 /* now initialize the module, this function reinitializes
1673 * a module in place, preserving existing slots (even if they
1674 * no longer exist) */
1675 rv = secmod_ModuleInit(mod, NULL((void*)0), &alreadyLoaded);
1676 if (rv != SECSuccess) {
1677 /* save the last error code */
1678 lastError = PORT_GetErrorPORT_GetError_Util();
1679 rrv = rv;
1680 /* couldn't reinit the module, disable all its slots */
1681 for (i = 0; i < mod->slotCount; i++) {
1682 mod->slots[i]->disabled = PR_TRUE1;
1683 mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
1684 }
1685 continue;
1686 }
1687 for (i = 0; i < mod->slotCount; i++) {
1688 /* get new token sessions, bump the series up so that
1689 * we refresh other old sessions. This will tell much of
1690 * NSS to flush cached handles it may hold as well */
1691 rv = PK11_InitToken(mod->slots[i], PR_TRUE1);
1692 /* PK11_InitToken could fail if the slot isn't present.
1693 * If it is present, though, something is wrong and we should
1694 * disable the slot and let the caller know. */
1695 if (rv != SECSuccess && PK11_IsPresent(mod->slots[i])) {
1696 /* save the last error code */
1697 lastError = PORT_GetErrorPORT_GetError_Util();
1698 rrv = rv;
1699 /* disable the token */
1700 mod->slots[i]->disabled = PR_TRUE1;
1701 mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
1702 }
1703 }
1704 }
1705 }
1706 SECMOD_ReleaseReadLock(moduleLock);
1707
1708 /*
1709 * on multiple failures, we are only returning the lastError. The caller
1710 * can determine which slots are bad by calling PK11_IsDisabled().
1711 */
1712 if (rrv != SECSuccess) {
1713 /* restore the last error code */
1714 PORT_SetErrorPORT_SetError_Util(lastError);
1715 }
1716
1717 return rrv;
1718}