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