Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: mozilla/security/nss/lib/pk11wrap/pk11load.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5 * The following handles the loading, unloading and management of
6 * various PCKS #11 modules
7 */
8 #define FORCE_PR_LOG 1
9 #include "seccomon.h"
10 #include "pkcs11.h"
11 #include "secmod.h"
12 #include "prlink.h"
13 #include "pk11func.h"
14 #include "secmodi.h"
15 #include "secmodti.h"
16 #include "nssilock.h"
17 #include "secerr.h"
18 #include "prenv.h"
19 #include "utilparst.h"
20
21 #define DEBUG_MODULE 1
22
23 #ifdef DEBUG_MODULE
24 static char *modToDBG = NULL;
25
26 #include "debug_module.c"
27 #endif
28
29 /* build the PKCS #11 2.01 lock files */
30 CK_RV PR_CALLBACK secmodCreateMutext(CK_VOID_PTR_PTR pmutex) {
31 *pmutex = (CK_VOID_PTR) PZ_NewLock(nssILockOther);
32 if ( *pmutex ) return CKR_OK;
33 return CKR_HOST_MEMORY;
34 }
35
36 CK_RV PR_CALLBACK secmodDestroyMutext(CK_VOID_PTR mutext) {
37 PZ_DestroyLock((PZLock *)mutext);
38 return CKR_OK;
39 }
40
41 CK_RV PR_CALLBACK secmodLockMutext(CK_VOID_PTR mutext) {
42 PZ_Lock((PZLock *)mutext);
43 return CKR_OK;
44 }
45
46 CK_RV PR_CALLBACK secmodUnlockMutext(CK_VOID_PTR mutext) {
47 PZ_Unlock((PZLock *)mutext);
48 return CKR_OK;
49 }
50
51 static SECMODModuleID nextModuleID = 1;
52 static const CK_C_INITIALIZE_ARGS secmodLockFunctions = {
53 secmodCreateMutext, secmodDestroyMutext, secmodLockMutext,
54 secmodUnlockMutext, CKF_LIBRARY_CANT_CREATE_OS_THREADS|
55 CKF_OS_LOCKING_OK
56 ,NULL
57 };
58
59 static PRBool loadSingleThreadedModules = PR_TRUE;
60 static PRBool enforceAlreadyInitializedError = PR_TRUE;
61 static PRBool finalizeModules = PR_TRUE;
62
63 /* set global options for NSS PKCS#11 module loader */
64 SECStatus pk11_setGlobalOptions(PRBool noSingleThreadedModules,
65 PRBool allowAlreadyInitializedModules,
66 PRBool dontFinalizeModules)
67 {
68 if (noSingleThreadedModules) {
69 loadSingleThreadedModules = PR_FALSE;
70 } else {
71 loadSingleThreadedModules = PR_TRUE;
72 }
73 if (allowAlreadyInitializedModules) {
74 enforceAlreadyInitializedError = PR_FALSE;
75 } else {
76 enforceAlreadyInitializedError = PR_TRUE;
77 }
78 if (dontFinalizeModules) {
79 finalizeModules = PR_FALSE;
80 } else {
81 finalizeModules = PR_TRUE;
82 }
83 return SECSuccess;
84 }
85
86 PRBool pk11_getFinalizeModulesOption(void)
87 {
88 return finalizeModules;
89 }
90
91 /*
92 * Allow specification loading the same module more than once at init time.
93 * This enables 2 things.
94 *
95 * 1) we can load additional databases by manipulating secmod.db/pkcs11.txt.
96 * 2) we can handle the case where some library has already initialized NSS
97 * before the main application.
98 *
99 * oldModule is the module we have already initialized.
100 * char *modulespec is the full module spec for the library we want to
101 * initialize.
102 */
103 static SECStatus
104 secmod_handleReload(SECMODModule *oldModule, SECMODModule *newModule)
105 {
106 PK11SlotInfo *slot;
107 char *modulespec;
108 char *newModuleSpec;
109 char **children;
110 CK_SLOT_ID *ids;
111 SECMODConfigList *conflist = NULL;
112 SECStatus rv = SECFailure;
113 int count = 0;
114
115 /* first look for tokens= key words from the module spec */
116 modulespec = newModule->libraryParams;
117 newModuleSpec = secmod_ParseModuleSpecForTokens(PR_TRUE,
118 newModule->isFIPS, modulespec, &children, &ids);
119 if (!newModuleSpec) {
120 return SECFailure;
121 }
122
123 /*
124 * We are now trying to open a new slot on an already loaded module.
125 * If that slot represents a cert/key database, we don't want to open
126 * multiple copies of that same database. Unfortunately we understand
127 * the softoken flags well enough to be able to do this, so we can only get
128 * the list of already loaded databases if we are trying to open another
129 * internal module.
130 */
131 if (oldModule->internal) {
132 conflist = secmod_GetConfigList(oldModule->isFIPS,
133 oldModule->libraryParams, &count);
134 }
135
136
137 /* don't open multiple of the same db */
138 if (conflist && secmod_MatchConfigList(newModuleSpec, conflist, count)) {
139 rv = SECSuccess;
140 goto loser;
141 }
142 slot = SECMOD_OpenNewSlot(oldModule, newModuleSpec);
143 if (slot) {
144 int newID;
145 char **thisChild;
146 CK_SLOT_ID *thisID;
147 char *oldModuleSpec;
148
149 if (secmod_IsInternalKeySlot(newModule)) {
150 pk11_SetInternalKeySlotIfFirst(slot);
151 }
152 newID = slot->slotID;
153 PK11_FreeSlot(slot);
154 for (thisChild=children, thisID=ids; thisChild && *thisChild;
155 thisChild++,thisID++) {
156 if (conflist &&
157 secmod_MatchConfigList(*thisChild, conflist, count)) {
158 *thisID = (CK_SLOT_ID) -1;
159 continue;
160 }
161 slot = SECMOD_OpenNewSlot(oldModule, *thisChild);
162 if (slot) {
163 *thisID = slot->slotID;
164 PK11_FreeSlot(slot);
165 } else {
166 *thisID = (CK_SLOT_ID) -1;
167 }
168 }
169
170 /* update the old module initialization string in case we need to
171 * shutdown and reinit the whole mess (this is rare, but can happen
172 * when trying to stop smart card insertion/removal threads)... */
173 oldModuleSpec = secmod_MkAppendTokensList(oldModule->arena,
174 oldModule->libraryParams, newModuleSpec, newID,
175 children, ids);
176 if (oldModuleSpec) {
177 oldModule->libraryParams = oldModuleSpec;
178 }
179
180 rv = SECSuccess;
181 }
182
183 loser:
184 secmod_FreeChildren(children, ids);
185 PORT_Free(newModuleSpec);
186 if (conflist) {
187 secmod_FreeConfigList(conflist, count);
188 }
189 return rv;
190 }
191
192 /*
193 * collect the steps we need to initialize a module in a single function
194 */
195 SECStatus
196 secmod_ModuleInit(SECMODModule *mod, SECMODModule **reload,
197 PRBool* alreadyLoaded)
198 {
199 CK_C_INITIALIZE_ARGS moduleArgs;
200 CK_VOID_PTR pInitArgs;
201 CK_RV crv;
202
203 if (reload) {
204 *reload = NULL;
205 }
206
207 if (!mod || !alreadyLoaded) {
208 PORT_SetError(SEC_ERROR_INVALID_ARGS);
209 return SECFailure;
210 }
211
212 if (mod->isThreadSafe == PR_FALSE) {
213 pInitArgs = NULL;
214 } else if (mod->libraryParams == NULL) {
215 pInitArgs = (void *) &secmodLockFunctions;
216 } else {
217 moduleArgs = secmodLockFunctions;
218 moduleArgs.LibraryParameters = (void *) mod->libraryParams;
219 pInitArgs = &moduleArgs;
220 }
221 crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
222 if (CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) {
223 SECMODModule *oldModule = NULL;
224
225 /* Library has already been loaded once, if caller expects it, and it
226 * has additional configuration, try reloading it as well. */
227 if (reload != NULL && mod->libraryParams) {
228 oldModule = secmod_FindModuleByFuncPtr(mod->functionList);
229 }
230 /* Library has been loaded by NSS. It means it may be capable of
231 * reloading */
232 if (oldModule) {
233 SECStatus rv;
234 rv = secmod_handleReload(oldModule, mod);
235 if (rv == SECSuccess) {
236 /* This module should go away soon, since we've
237 * simply expanded the slots on the old module.
238 * When it goes away, it should not Finalize since
239 * that will close our old module as well. Setting
240 * the function list to NULL will prevent that close */
241 mod->functionList = NULL;
242 *reload = oldModule;
243 return SECSuccess;
244 }
245 SECMOD_DestroyModule(oldModule);
246 }
247 /* reload not possible, fall back to old semantics */
248 if (!enforceAlreadyInitializedError) {
249 *alreadyLoaded = PR_TRUE;
250 return SECSuccess;
251 }
252 }
253 if (crv != CKR_OK) {
254 if (pInitArgs == NULL ||
255 crv == CKR_NETSCAPE_CERTDB_FAILED ||
256 crv == CKR_NETSCAPE_KEYDB_FAILED) {
257 PORT_SetError(PK11_MapError(crv));
258 return SECFailure;
259 }
260 if (!loadSingleThreadedModules) {
261 PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
262 return SECFailure;
263 }
264 mod->isThreadSafe = PR_FALSE;
265 crv = PK11_GETTAB(mod)->C_Initialize(NULL);
266 if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) &&
267 (!enforceAlreadyInitializedError)) {
268 *alreadyLoaded = PR_TRUE;
269 return SECSuccess;
270 }
271 if (crv != CKR_OK) {
272 PORT_SetError(PK11_MapError(crv));
273 return SECFailure;
274 }
275 }
276 return SECSuccess;
277 }
278
279 /*
280 * set the hasRootCerts flags in the module so it can be stored back
281 * into the database.
282 */
283 void
284 SECMOD_SetRootCerts(PK11SlotInfo *slot, SECMODModule *mod) {
285 PK11PreSlotInfo *psi = NULL;
286 int i;
287
288 if (slot->hasRootCerts) {
289 for (i=0; i < mod->slotInfoCount; i++) {
290 if (slot->slotID == mod->slotInfo[i].slotID) {
291 psi = &mod->slotInfo[i];
292 break;
293 }
294 }
295 if (psi == NULL) {
296 /* allocate more slots */
297 PK11PreSlotInfo *psi_list = (PK11PreSlotInfo *)
298 PORT_ArenaAlloc(mod->arena,
299 (mod->slotInfoCount+1)* sizeof(PK11PreSlotInfo));
300 /* copy the old ones */
301 if (mod->slotInfoCount > 0) {
302 PORT_Memcpy(psi_list,mod->slotInfo,
303 (mod->slotInfoCount)*sizeof(PK11PreSlotInfo));
304 }
305 /* assign psi to the last new slot */
306 psi = &psi_list[mod->slotInfoCount];
307 psi->slotID = slot->slotID;
308 psi->askpw = 0;
309 psi->timeout = 0;
310 psi ->defaultFlags = 0;
311
312 /* increment module count & store new list */
313 mod->slotInfo = psi_list;
314 mod->slotInfoCount++;
315
316 }
317 psi->hasRootCerts = 1;
318 }
319 }
320
321 #ifdef NSS_STATIC
322 extern CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList);
323 extern CK_RV FC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList);
324 extern char **NSC_ModuleDBFunc(unsigned long function,char *parameters, void *ar gs);
325 extern CK_RV builtinsC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList);
326 #else
327 static const char* my_shlib_name =
328 SHLIB_PREFIX"nss"SHLIB_VERSION"."SHLIB_SUFFIX;
329 static const char* softoken_shlib_name =
330 SHLIB_PREFIX"softokn"SOFTOKEN_SHLIB_VERSION"."SHLIB_SUFFIX;
331 static const PRCallOnceType pristineCallOnce;
332 static PRCallOnceType loadSoftokenOnce;
333 static PRLibrary* softokenLib;
334 static PRInt32 softokenLoadCount;
335 #endif /* NSS_STATIC */
336
337 #include "prio.h"
338 #include "prprf.h"
339 #include <stdio.h>
340 #include "prsystem.h"
341
342 #ifndef NSS_STATIC
343 /* This function must be run only once. */
344 /* determine if hybrid platform, then actually load the DSO. */
345 static PRStatus
346 softoken_LoadDSO( void )
347 {
348 PRLibrary * handle;
349
350 handle = PORT_LoadLibraryFromOrigin(my_shlib_name,
351 (PRFuncPtr) &softoken_LoadDSO,
352 softoken_shlib_name);
353 if (handle) {
354 softokenLib = handle;
355 return PR_SUCCESS;
356 }
357 return PR_FAILURE;
358 }
359 #endif /* !NSS_STATIC */
360
361 /*
362 * load a new module into our address space and initialize it.
363 */
364 SECStatus
365 secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule) {
366 PRLibrary *library = NULL;
367 CK_C_GetFunctionList entry = NULL;
368 CK_INFO info;
369 CK_ULONG slotCount = 0;
370 SECStatus rv;
371 PRBool alreadyLoaded = PR_FALSE;
372 char *disableUnload = NULL;
373
374 if (mod->loaded) return SECSuccess;
375
376 /* intenal modules get loaded from their internal list */
377 if (mod->internal && (mod->dllName == NULL)) {
378 #ifdef NSS_STATIC
379 if (mod->isFIPS) {
380 entry = FC_GetFunctionList;
381 } else {
382 entry = NSC_GetFunctionList;
383 }
384 if (mod->isModuleDB) {
385 mod->moduleDBFunc = NSC_ModuleDBFunc;
386 }
387 #else
388 /*
389 * Loads softoken as a dynamic library,
390 * even though the rest of NSS assumes this as the "internal" module.
391 */
392 if (!softokenLib &&
393 PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO))
394 return SECFailure;
395
396 PR_ATOMIC_INCREMENT(&softokenLoadCount);
397
398 if (mod->isFIPS) {
399 entry = (CK_C_GetFunctionList)
400 PR_FindSymbol(softokenLib, "FC_GetFunctionList");
401 } else {
402 entry = (CK_C_GetFunctionList)
403 PR_FindSymbol(softokenLib, "NSC_GetFunctionList");
404 }
405
406 if (!entry)
407 return SECFailure;
408
409 if (mod->isModuleDB) {
410 mod->moduleDBFunc = (CK_C_GetFunctionList)
411 PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc");
412 }
413 #endif
414
415 if (mod->moduleDBOnly) {
416 mod->loaded = PR_TRUE;
417 return SECSuccess;
418 }
419 } else {
420 /* Not internal, load the DLL and look up C_GetFunctionList */
421 if (mod->dllName == NULL) {
422 return SECFailure;
423 }
424 #if defined(NSS_STATIC) && !defined(NSS_DISABLE_ROOT_CERTS)
425 if (strstr(mod->dllName, "nssckbi") != NULL) {
426 mod->library = NULL;
427 PORT_Assert(!mod->moduleDBOnly);
428 entry = builtinsC_GetFunctionList;
429 PORT_Assert(!mod->isModuleDB);
430 goto library_loaded;
431 }
432 #endif
433
434 /* load the library. If this succeeds, then we have to remember to
435 * unload the library if anything goes wrong from here on out...
436 */
437 library = PR_LoadLibrary(mod->dllName);
438 mod->library = (void *)library;
439
440 if (library == NULL) {
441 return SECFailure;
442 }
443
444 /*
445 * now we need to get the entry point to find the function pointers
446 */
447 if (!mod->moduleDBOnly) {
448 entry = (CK_C_GetFunctionList)
449 PR_FindSymbol(library, "C_GetFunctionList");
450 }
451 if (mod->isModuleDB) {
452 mod->moduleDBFunc = (void *)
453 PR_FindSymbol(library, "NSS_ReturnModuleSpecData");
454 }
455 #if defined(NSS_STATIC) && !defined(NSS_DISABLE_ROOT_CERTS)
456 library_loaded:
457 #endif
458 if (mod->moduleDBFunc == NULL) mod->isModuleDB = PR_FALSE;
459 if (entry == NULL) {
460 if (mod->isModuleDB) {
461 mod->loaded = PR_TRUE;
462 mod->moduleDBOnly = PR_TRUE;
463 return SECSuccess;
464 }
465 PR_UnloadLibrary(library);
466 return SECFailure;
467 }
468 }
469
470 /*
471 * We need to get the function list
472 */
473 if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK)
474 goto fail;
475
476 #ifdef DEBUG_MODULE
477 if (PR_TRUE) {
478 modToDBG = PR_GetEnv("NSS_DEBUG_PKCS11_MODULE");
479 if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
480 mod->functionList = (void *)nss_InsertDeviceLog(
481 (CK_FUNCTION_LIST_PTR)mod->functionList);
482 }
483 }
484 #endif
485
486 mod->isThreadSafe = PR_TRUE;
487
488 /* Now we initialize the module */
489 rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded);
490 if (rv != SECSuccess) {
491 goto fail;
492 }
493
494 /* module has been reloaded, this module itself is done,
495 * return to the caller */
496 if (mod->functionList == NULL) {
497 mod->loaded = PR_TRUE; /* technically the module is loaded.. */
498 return SECSuccess;
499 }
500
501 /* check the version number */
502 if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK) goto fail2;
503 if (info.cryptokiVersion.major != 2) goto fail2;
504 /* all 2.0 are a priori *not* thread safe */
505 if (info.cryptokiVersion.minor < 1) {
506 if (!loadSingleThreadedModules) {
507 PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
508 goto fail2;
509 } else {
510 mod->isThreadSafe = PR_FALSE;
511 }
512 }
513 mod->cryptokiVersion = info.cryptokiVersion;
514
515 /* If we don't have a common name, get it from the PKCS 11 module */
516 if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) {
517 mod->commonName = PK11_MakeString(mod->arena,NULL,
518 (char *)info.libraryDescription, sizeof(info.libraryDescription));
519 if (mod->commonName == NULL) goto fail2;
520 }
521
522
523 /* initialize the Slots */
524 if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) {
525 CK_SLOT_ID *slotIDs;
526 int i;
527 CK_RV crv;
528
529 mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena,
530 sizeof(PK11SlotInfo *) * slotCount);
531 if (mod->slots == NULL) goto fail2;
532
533 slotIDs = (CK_SLOT_ID *) PORT_Alloc(sizeof(CK_SLOT_ID)*slotCount);
534 if (slotIDs == NULL) {
535 goto fail2;
536 }
537 crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount);
538 if (crv != CKR_OK) {
539 PORT_Free(slotIDs);
540 goto fail2;
541 }
542
543 /* Initialize each slot */
544 for (i=0; i < (int)slotCount; i++) {
545 mod->slots[i] = PK11_NewSlotInfo(mod);
546 PK11_InitSlot(mod,slotIDs[i],mod->slots[i]);
547 /* look down the slot info table */
548 PK11_LoadSlotList(mod->slots[i],mod->slotInfo,mod->slotInfoCount);
549 SECMOD_SetRootCerts(mod->slots[i],mod);
550 /* explicitly mark the internal slot as such if IsInternalKeySlot()
551 * is set */
552 if (secmod_IsInternalKeySlot(mod) && (i == (mod->isFIPS ? 0 : 1))) {
553 pk11_SetInternalKeySlotIfFirst(mod->slots[i]);
554 }
555 }
556 mod->slotCount = slotCount;
557 mod->slotInfoCount = 0;
558 PORT_Free(slotIDs);
559 }
560
561 mod->loaded = PR_TRUE;
562 mod->moduleID = nextModuleID++;
563 return SECSuccess;
564 fail2:
565 if (enforceAlreadyInitializedError || (!alreadyLoaded)) {
566 PK11_GETTAB(mod)->C_Finalize(NULL);
567 }
568 fail:
569 mod->functionList = NULL;
570 disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
571 if (library && !disableUnload) {
572 PR_UnloadLibrary(library);
573 }
574 return SECFailure;
575 }
576
577 SECStatus
578 SECMOD_UnloadModule(SECMODModule *mod) {
579 PRLibrary *library;
580 char *disableUnload = NULL;
581
582 if (!mod->loaded) {
583 return SECFailure;
584 }
585 if (finalizeModules) {
586 if (mod->functionList &&!mod->moduleDBOnly) {
587 PK11_GETTAB(mod)->C_Finalize(NULL);
588 }
589 }
590 mod->moduleID = 0;
591 mod->loaded = PR_FALSE;
592
593 /* do we want the semantics to allow unloading the internal library?
594 * if not, we should change this to SECFailure and move it above the
595 * mod->loaded = PR_FALSE; */
596 if (mod->internal && (mod->dllName == NULL)) {
597 #ifndef NSS_STATIC
598 if (0 == PR_ATOMIC_DECREMENT(&softokenLoadCount)) {
599 if (softokenLib) {
600 disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
601 if (!disableUnload) {
602 PRStatus status = PR_UnloadLibrary(softokenLib);
603 PORT_Assert(PR_SUCCESS == status);
604 }
605 softokenLib = NULL;
606 }
607 loadSoftokenOnce = pristineCallOnce;
608 }
609 #endif
610 return SECSuccess;
611 }
612
613 library = (PRLibrary *)mod->library;
614 /* paranoia */
615 if (library == NULL) {
616 #if defined(NSS_STATIC) && !defined(NSS_DISABLE_ROOT_CERTS)
617 if (strstr(mod->dllName, "nssckbi") != NULL) {
618 return SECSuccess;
619 }
620 #endif
621 return SECFailure;
622 }
623
624 disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
625 if (!disableUnload) {
626 PR_UnloadLibrary(library);
627 }
628 return SECSuccess;
629 }
630
631 void
632 nss_DumpModuleLog(void)
633 {
634 #ifdef DEBUG_MODULE
635 if (modToDBG) {
636 print_final_statistics();
637 }
638 #endif
639 }
OLDNEW
« no previous file with comments | « mozilla/security/nss/lib/pk11wrap/pk11list.c ('k') | mozilla/security/nss/lib/pk11wrap/pk11mech.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698