1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 * Initialize the PCKS 11 subsystem
50 /* these are for displaying error messages */
52 static SECMODModuleList
*modules
= NULL
;
53 static SECMODModuleList
*modulesDB
= NULL
;
54 static SECMODModuleList
*modulesUnload
= NULL
;
55 static SECMODModule
*internalModule
= NULL
;
56 static SECMODModule
*defaultDBModule
= NULL
;
57 static SECMODModule
*pendingModule
= NULL
;
58 static SECMODListLock
*moduleLock
= NULL
;
60 int secmod_PrivateModuleCount
= 0;
62 extern PK11DefaultArrayEntry PK11_DefaultArray
[];
63 extern int num_pk11_default_mechanisms
;
69 /* don't initialize twice */
70 if (moduleLock
) return;
72 moduleLock
= SECMOD_NewListLock();
80 /* destroy the lock */
82 SECMOD_DestroyListLock(moduleLock
);
85 /* free the internal module */
87 SECMOD_DestroyModule(internalModule
);
88 internalModule
= NULL
;
91 /* free the default database module */
92 if (defaultDBModule
) {
93 SECMOD_DestroyModule(defaultDBModule
);
94 defaultDBModule
= NULL
;
97 /* destroy the list */
99 SECMOD_DestroyModuleList(modules
);
104 SECMOD_DestroyModuleList(modulesDB
);
109 SECMOD_DestroyModuleList(modulesUnload
);
110 modulesUnload
= NULL
;
113 /* make all the slots and the lists go away */
114 PK11_DestroySlotLists();
119 if (PR_GetEnv("NSS_STRICT_SHUTDOWN")) {
120 PORT_Assert(secmod_PrivateModuleCount
== 0);
123 if (secmod_PrivateModuleCount
) {
124 PORT_SetError(SEC_ERROR_BUSY
);
132 * retrieve the internal module
135 SECMOD_GetInternalModule(void)
137 return internalModule
;
142 secmod_AddModuleToList(SECMODModuleList
**moduleList
,SECMODModule
*newModule
)
144 SECMODModuleList
*mlp
, *newListElement
, *last
= NULL
;
146 newListElement
= SECMOD_NewModuleListElement();
147 if (newListElement
== NULL
) {
151 newListElement
->module
= SECMOD_ReferenceModule(newModule
);
153 SECMOD_GetWriteLock(moduleLock
);
154 /* Added it to the end (This is very inefficient, but Adding a module
155 * on the fly should happen maybe 2-3 times through the life this program
156 * on a given computer, and this list should be *SHORT*. */
157 for(mlp
= *moduleList
; mlp
!= NULL
; mlp
= mlp
->next
) {
162 *moduleList
= newListElement
;
164 SECMOD_AddList(last
,newListElement
,NULL
);
166 SECMOD_ReleaseWriteLock(moduleLock
);
171 SECMOD_AddModuleToList(SECMODModule
*newModule
)
173 if (newModule
->internal
&& !internalModule
) {
174 internalModule
= SECMOD_ReferenceModule(newModule
);
176 return secmod_AddModuleToList(&modules
,newModule
);
180 SECMOD_AddModuleToDBOnlyList(SECMODModule
*newModule
)
182 if (defaultDBModule
== NULL
) {
183 defaultDBModule
= SECMOD_ReferenceModule(newModule
);
185 return secmod_AddModuleToList(&modulesDB
,newModule
);
189 SECMOD_AddModuleToUnloadList(SECMODModule
*newModule
)
191 return secmod_AddModuleToList(&modulesUnload
,newModule
);
195 * get the list of PKCS11 modules that are available.
197 SECMODModuleList
* SECMOD_GetDefaultModuleList() { return modules
; }
198 SECMODModuleList
*SECMOD_GetDeadModuleList() { return modulesUnload
; }
199 SECMODModuleList
*SECMOD_GetDBModuleList() { return modulesDB
; }
202 * This lock protects the global module lists.
203 * it also protects changes to the slot array (module->slots[]) and slot count
204 * (module->slotCount) in each module. It is a read/write lock with multiple
205 * readers or one writer. Writes are uncommon.
206 * Because of legacy considerations protection of the slot array and count is
207 * only necessary in applications if the application calls
208 * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new
209 * applications are encouraged to acquire this lock when reading the
210 * slot array information directly.
212 SECMODListLock
*SECMOD_GetDefaultModuleListLock() { return moduleLock
; }
217 * find a module by name, and add a reference to it.
218 * return that module.
221 SECMOD_FindModule(const char *name
)
223 SECMODModuleList
*mlp
;
224 SECMODModule
*module
= NULL
;
226 SECMOD_GetReadLock(moduleLock
);
227 for(mlp
= modules
; mlp
!= NULL
; mlp
= mlp
->next
) {
228 if (PORT_Strcmp(name
,mlp
->module
->commonName
) == 0) {
229 module
= mlp
->module
;
230 SECMOD_ReferenceModule(module
);
237 for(mlp
= modulesUnload
; mlp
!= NULL
; mlp
= mlp
->next
) {
238 if (PORT_Strcmp(name
,mlp
->module
->commonName
) == 0) {
239 module
= mlp
->module
;
240 SECMOD_ReferenceModule(module
);
246 SECMOD_ReleaseReadLock(moduleLock
);
252 * find a module by ID, and add a reference to it.
253 * return that module.
256 SECMOD_FindModuleByID(SECMODModuleID id
)
258 SECMODModuleList
*mlp
;
259 SECMODModule
*module
= NULL
;
261 SECMOD_GetReadLock(moduleLock
);
262 for(mlp
= modules
; mlp
!= NULL
; mlp
= mlp
->next
) {
263 if (id
== mlp
->module
->moduleID
) {
264 module
= mlp
->module
;
265 SECMOD_ReferenceModule(module
);
269 SECMOD_ReleaseReadLock(moduleLock
);
270 if (module
== NULL
) {
271 PORT_SetError(SEC_ERROR_NO_MODULE
);
277 * Find the Slot based on ID and the module.
280 SECMOD_FindSlotByID(SECMODModule
*module
, CK_SLOT_ID slotID
)
283 PK11SlotInfo
*slot
= NULL
;
285 SECMOD_GetReadLock(moduleLock
);
286 for (i
=0; i
< module
->slotCount
; i
++) {
287 PK11SlotInfo
*cSlot
= module
->slots
[i
];
289 if (cSlot
->slotID
== slotID
) {
290 slot
= PK11_ReferenceSlot(cSlot
);
294 SECMOD_ReleaseReadLock(moduleLock
);
297 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED
);
303 * lookup the Slot module based on it's module ID and slot ID.
306 SECMOD_LookupSlot(SECMODModuleID moduleID
,CK_SLOT_ID slotID
)
308 SECMODModule
*module
;
311 module
= SECMOD_FindModuleByID(moduleID
);
312 if (module
== NULL
) return NULL
;
314 slot
= SECMOD_FindSlotByID(module
, slotID
);
315 SECMOD_DestroyModule(module
);
321 * find a module by name or module pointer and delete it off the module list.
322 * optionally remove it from secmod.db.
325 SECMOD_DeleteModuleEx(const char *name
, SECMODModule
*mod
,
326 int *type
, PRBool permdb
)
328 SECMODModuleList
*mlp
;
329 SECMODModuleList
**mlpp
;
330 SECStatus rv
= SECFailure
;
332 *type
= SECMOD_EXTERNAL
;
334 SECMOD_GetWriteLock(moduleLock
);
335 for (mlpp
= &modules
,mlp
= modules
;
336 mlp
!= NULL
; mlpp
= &mlp
->next
, mlp
= *mlpp
) {
337 if ((name
&& (PORT_Strcmp(name
,mlp
->module
->commonName
) == 0)) ||
338 mod
== mlp
->module
) {
339 /* don't delete the internal module */
340 if (!mlp
->module
->internal
) {
341 SECMOD_RemoveList(mlpp
,mlp
);
342 /* delete it after we release the lock */
343 rv
= STAN_RemoveModuleFromDefaultTrustDomain(mlp
->module
);
344 } else if (mlp
->module
->isFIPS
) {
347 *type
= SECMOD_INTERNAL
;
355 /* not on the internal list, check the unload list */
356 for (mlpp
= &modulesUnload
,mlp
= modulesUnload
;
357 mlp
!= NULL
; mlpp
= &mlp
->next
, mlp
= *mlpp
) {
358 if ((name
&& (PORT_Strcmp(name
,mlp
->module
->commonName
) == 0)) ||
359 mod
== mlp
->module
) {
360 /* don't delete the internal module */
361 if (!mlp
->module
->internal
) {
362 SECMOD_RemoveList(mlpp
,mlp
);
364 } else if (mlp
->module
->isFIPS
) {
367 *type
= SECMOD_INTERNAL
;
373 SECMOD_ReleaseWriteLock(moduleLock
);
376 if (rv
== SECSuccess
) {
378 SECMOD_DeletePermDB(mlp
->module
);
380 SECMOD_DestroyModuleListElement(mlp
);
386 * find a module by name and delete it off the module list
389 SECMOD_DeleteModule(const char *name
, int *type
)
391 return SECMOD_DeleteModuleEx(name
, NULL
, type
, PR_TRUE
);
395 * find a module by name and delete it off the module list
398 SECMOD_DeleteInternalModule(const char *name
)
400 SECMODModuleList
*mlp
;
401 SECMODModuleList
**mlpp
;
402 SECStatus rv
= SECFailure
;
405 PORT_SetError(SEC_ERROR_MODULE_STUCK
);
409 SECMOD_GetWriteLock(moduleLock
);
410 for(mlpp
= &modules
,mlp
= modules
;
411 mlp
!= NULL
; mlpp
= &mlp
->next
, mlp
= *mlpp
) {
412 if (PORT_Strcmp(name
,mlp
->module
->commonName
) == 0) {
413 /* don't delete the internal module */
414 if (mlp
->module
->internal
) {
415 SECMOD_RemoveList(mlpp
,mlp
);
416 rv
= STAN_RemoveModuleFromDefaultTrustDomain(mlp
->module
);
421 SECMOD_ReleaseWriteLock(moduleLock
);
423 if (rv
== SECSuccess
) {
424 SECMODModule
*newModule
,*oldModule
;
426 if (mlp
->module
->isFIPS
) {
427 newModule
= SECMOD_CreateModule(NULL
, SECMOD_INT_NAME
,
428 NULL
, SECMOD_INT_FLAGS
);
430 newModule
= SECMOD_CreateModule(NULL
, SECMOD_FIPS_NAME
,
431 NULL
, SECMOD_FIPS_FLAGS
);
434 newModule
->libraryParams
=
435 PORT_ArenaStrdup(newModule
->arena
,mlp
->module
->libraryParams
);
436 rv
= SECMOD_AddModule(newModule
);
437 if (rv
!= SECSuccess
) {
438 SECMOD_DestroyModule(newModule
);
442 if (newModule
== NULL
) {
443 SECMODModuleList
*last
= NULL
,*mlp2
;
444 /* we're in pretty deep trouble if this happens...Security
445 * not going to work well... try to put the old module back on
447 SECMOD_GetWriteLock(moduleLock
);
448 for(mlp2
= modules
; mlp2
!= NULL
; mlp2
= mlp
->next
) {
455 SECMOD_AddList(last
,mlp
,NULL
);
457 SECMOD_ReleaseWriteLock(moduleLock
);
460 pendingModule
= oldModule
= internalModule
;
461 internalModule
= NULL
;
462 SECMOD_DestroyModule(oldModule
);
463 SECMOD_DeletePermDB(mlp
->module
);
464 SECMOD_DestroyModuleListElement(mlp
);
465 internalModule
= newModule
; /* adopt the module */
471 SECMOD_AddModule(SECMODModule
*newModule
)
474 SECMODModule
*oldModule
;
476 /* Test if a module w/ the same name already exists */
477 /* and return SECWouldBlock if so. */
478 /* We should probably add a new return value such as */
479 /* SECDublicateModule, but to minimize ripples, I'll */
480 /* give SECWouldBlock a new meaning */
481 if ((oldModule
= SECMOD_FindModule(newModule
->commonName
)) != NULL
) {
482 SECMOD_DestroyModule(oldModule
);
483 return SECWouldBlock
;
484 /* module already exists. */
487 rv
= SECMOD_LoadPKCS11Module(newModule
);
488 if (rv
!= SECSuccess
) {
492 if (newModule
->parent
== NULL
) {
493 newModule
->parent
= SECMOD_ReferenceModule(defaultDBModule
);
496 SECMOD_AddPermDB(newModule
);
497 SECMOD_AddModuleToList(newModule
);
499 rv
= STAN_AddModuleToDefaultTrustDomain(newModule
);
505 SECMOD_FindSlot(SECMODModule
*module
,const char *name
)
509 PK11SlotInfo
*retSlot
= NULL
;
511 SECMOD_GetReadLock(moduleLock
);
512 for (i
=0; i
< module
->slotCount
; i
++) {
513 PK11SlotInfo
*slot
= module
->slots
[i
];
515 if (PK11_IsPresent(slot
)) {
516 string
= PK11_GetTokenName(slot
);
518 string
= PK11_GetSlotName(slot
);
520 if (PORT_Strcmp(name
,string
) == 0) {
521 retSlot
= PK11_ReferenceSlot(slot
);
525 SECMOD_ReleaseReadLock(moduleLock
);
527 if (retSlot
== NULL
) {
528 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED
);
534 PK11_GetModInfo(SECMODModule
*mod
,CK_INFO
*info
)
538 if (mod
->functionList
== NULL
) return SECFailure
;
539 crv
= PK11_GETTAB(mod
)->C_GetInfo(info
);
541 PORT_SetError(PK11_MapError(crv
));
543 return (crv
== CKR_OK
) ? SECSuccess
: SECFailure
;
546 /* Determine if we have the FIP's module loaded as the default
547 * module to trigger other bogus FIPS requirements in PKCS #12 and
553 SECMODModule
*mod
= SECMOD_GetInternalModule();
555 if (mod
&& mod
->internal
) {
562 /* combines NewModule() & AddModule */
563 /* give a string for the module name & the full-path for the dll, */
564 /* installs the PKCS11 module & update registry */
566 SECMOD_AddNewModuleEx(const char* moduleName
, const char* dllPath
,
567 unsigned long defaultMechanismFlags
,
568 unsigned long cipherEnableFlags
,
569 char* modparms
, char* nssparms
)
571 SECMODModule
*module
;
572 SECStatus result
= SECFailure
;
576 PR_SetErrorText(0, NULL
);
578 module
= SECMOD_CreateModule(dllPath
, moduleName
, modparms
, nssparms
);
580 if (module
== NULL
) {
584 if (module
->dllName
!= NULL
) {
585 if (module
->dllName
[0] != 0) {
586 result
= SECMOD_AddModule(module
);
587 if (result
== SECSuccess
) {
588 /* turn on SSL cipher enable flags */
589 module
->ssl
[0] = cipherEnableFlags
;
591 SECMOD_GetReadLock(moduleLock
);
592 /* check each slot to turn on appropriate mechanisms */
593 for (s
= 0; s
< module
->slotCount
; s
++) {
594 slot
= (module
->slots
)[s
];
595 /* for each possible mechanism */
596 for (i
=0; i
< num_pk11_default_mechanisms
; i
++) {
597 /* we are told to turn it on by default ? */
599 (PK11_DefaultArray
[i
].flag
& defaultMechanismFlags
) ?
601 result
= PK11_UpdateSlotAttribute(slot
,
602 &(PK11_DefaultArray
[i
]), add
);
603 } /* for each mechanism */
604 /* disable each slot if the defaultFlags say so */
605 if (defaultMechanismFlags
& PK11_DISABLE_FLAG
) {
606 PK11_UserDisableSlot(slot
);
608 } /* for each slot of this module */
609 SECMOD_ReleaseReadLock(moduleLock
);
611 /* delete and re-add module in order to save changes
613 result
= SECMOD_UpdateModule(module
);
617 SECMOD_DestroyModule(module
);
622 SECMOD_AddNewModule(const char* moduleName
, const char* dllPath
,
623 unsigned long defaultMechanismFlags
,
624 unsigned long cipherEnableFlags
)
626 return SECMOD_AddNewModuleEx(moduleName
, dllPath
, defaultMechanismFlags
,
628 NULL
, NULL
); /* don't pass module or nss params */
632 SECMOD_UpdateModule(SECMODModule
*module
)
636 result
= SECMOD_DeletePermDB(module
);
638 if (result
== SECSuccess
) {
639 result
= SECMOD_AddPermDB(module
);
644 /* Public & Internal(Security Library) representation of
645 * encryption mechanism flags conversion */
647 /* Currently, the only difference is that internal representation
648 * puts RANDOM_FLAG at bit 31 (Most-significant bit), but
649 * public representation puts this bit at bit 28
652 SECMOD_PubMechFlagstoInternal(unsigned long publicFlags
)
654 unsigned long internalFlags
= publicFlags
;
656 if (publicFlags
& PUBLIC_MECH_RANDOM_FLAG
) {
657 internalFlags
&= ~PUBLIC_MECH_RANDOM_FLAG
;
658 internalFlags
|= SECMOD_RANDOM_FLAG
;
660 return internalFlags
;
664 SECMOD_InternaltoPubMechFlags(unsigned long internalFlags
)
666 unsigned long publicFlags
= internalFlags
;
668 if (internalFlags
& SECMOD_RANDOM_FLAG
) {
669 publicFlags
&= ~SECMOD_RANDOM_FLAG
;
670 publicFlags
|= PUBLIC_MECH_RANDOM_FLAG
;
676 /* Public & Internal(Security Library) representation of */
677 /* cipher flags conversion */
678 /* Note: currently they are just stubs */
680 SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags
)
686 SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags
)
688 return internalFlags
;
691 /* Funtion reports true if module of modType is installed/configured */
693 SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags
)
695 PRBool result
= PR_FALSE
;
696 SECMODModuleList
*mods
= SECMOD_GetDefaultModuleList();
697 SECMOD_GetReadLock(moduleLock
);
700 for ( ; mods
!= NULL
; mods
= mods
->next
) {
701 if (mods
->module
->ssl
[0] &
702 SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags
)) {
707 SECMOD_ReleaseReadLock(moduleLock
);
711 /* create a new ModuleListElement */
712 SECMODModuleList
*SECMOD_NewModuleListElement(void)
714 SECMODModuleList
*newModList
;
716 newModList
= (SECMODModuleList
*) PORT_Alloc(sizeof(SECMODModuleList
));
718 newModList
->next
= NULL
;
719 newModList
->module
= NULL
;
725 * make a new reference to a module so It doesn't go away on us
728 SECMOD_ReferenceModule(SECMODModule
*module
)
730 PZ_Lock(module
->refLock
);
731 PORT_Assert(module
->refCount
> 0);
734 PZ_Unlock(module
->refLock
);
739 /* destroy an existing module */
741 SECMOD_DestroyModule(SECMODModule
*module
)
743 PRBool willfree
= PR_FALSE
;
747 PZ_Lock(module
->refLock
);
748 if (module
->refCount
-- == 1) {
751 PORT_Assert(willfree
|| (module
->refCount
> 0));
752 PZ_Unlock(module
->refLock
);
758 if (module
->parent
!= NULL
) {
759 SECMODModule
*parent
= module
->parent
;
760 /* paranoia, don't loop forever if the modules are looped */
761 module
->parent
= NULL
;
762 SECMOD_DestroyModule(parent
);
765 /* slots can't really disappear until our module starts freeing them,
766 * so this check is safe */
767 slotCount
= module
->slotCount
;
768 if (slotCount
== 0) {
769 SECMOD_SlotDestroyModule(module
,PR_FALSE
);
773 /* now free all out slots, when they are done, they will cause the
774 * module to disappear altogether */
775 for (i
=0 ; i
< slotCount
; i
++) {
776 if (!module
->slots
[i
]->disabled
) {
777 PK11_ClearSlotList(module
->slots
[i
]);
779 PK11_FreeSlot(module
->slots
[i
]);
781 /* WARNING: once the last slot has been freed is it possible (even likely)
782 * that module is no more... touching it now is a good way to go south */
786 /* we can only get here if we've destroyed the module, or some one has
787 * erroneously freed a slot that wasn't referenced. */
789 SECMOD_SlotDestroyModule(SECMODModule
*module
, PRBool fromSlot
)
791 PRBool willfree
= PR_FALSE
;
793 PORT_Assert(module
->refCount
== 0);
794 PZ_Lock(module
->refLock
);
795 if (module
->slotCount
-- == 1) {
798 PORT_Assert(willfree
|| (module
->slotCount
> 0));
799 PZ_Unlock(module
->refLock
);
800 if (!willfree
) return;
803 if (module
== pendingModule
) {
804 pendingModule
= NULL
;
807 if (module
->loaded
) {
808 SECMOD_UnloadModule(module
);
810 PZ_DestroyLock(module
->refLock
);
811 PORT_FreeArena(module
->arena
,PR_FALSE
);
812 secmod_PrivateModuleCount
--;
815 /* destroy a list element
816 * this destroys a single element, and returns the next element
817 * on the chain. It makes it easy to implement for loops to delete
818 * the chain. It also make deleting a single element easy */
820 SECMOD_DestroyModuleListElement(SECMODModuleList
*element
)
822 SECMODModuleList
*next
= element
->next
;
824 if (element
->module
) {
825 SECMOD_DestroyModule(element
->module
);
826 element
->module
= NULL
;
834 * Destroy an entire module list
837 SECMOD_DestroyModuleList(SECMODModuleList
*list
)
839 SECMODModuleList
*lp
;
841 for ( lp
= list
; lp
!= NULL
; lp
= SECMOD_DestroyModuleListElement(lp
)) ;
845 SECMOD_CanDeleteInternalModule(void)
847 return (PRBool
) (pendingModule
== NULL
);
851 * check to see if the module has added new slots. PKCS 11 v2.20 allows for
852 * modules to add new slots, but never remove them. Slots cannot be added
853 * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent
854 * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently
855 * grow on the caller. It is permissible for the slots to increase between
856 * successive calls with NULL to get the size.
859 SECMOD_UpdateSlotList(SECMODModule
*mod
)
863 CK_ULONG i
, oldCount
;
864 PRBool freeRef
= PR_FALSE
;
866 CK_ULONG
*slotIDs
= NULL
;
867 PK11SlotInfo
**newSlots
= NULL
;
868 PK11SlotInfo
**oldSlots
= NULL
;
870 /* C_GetSlotList is not a session function, make sure
871 * calls are serialized */
872 PZ_Lock(mod
->refLock
);
874 /* see if the number of slots have changed */
875 crv
= PK11_GETTAB(mod
)->C_GetSlotList(PR_FALSE
, NULL
, &count
);
877 PORT_SetError(PK11_MapError(crv
));
880 /* nothing new, blow out early, we want this function to be quick
881 * and cheap in the normal case */
882 if (count
== mod
->slotCount
) {
883 PZ_Unlock(mod
->refLock
);
886 if (count
< (CK_ULONG
)mod
->slotCount
) {
887 /* shouldn't happen with a properly functioning PKCS #11 module */
888 PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11
);
892 /* get the new slot list */
893 slotIDs
= PORT_NewArray(CK_SLOT_ID
, count
);
894 if (slotIDs
== NULL
) {
898 crv
= PK11_GETTAB(mod
)->C_GetSlotList(PR_FALSE
, slotIDs
, &count
);
900 PORT_SetError(PK11_MapError(crv
));
904 PZ_Unlock(mod
->refLock
);
905 mark
= PORT_ArenaMark(mod
->arena
);
909 newSlots
= PORT_ArenaZNewArray(mod
->arena
,PK11SlotInfo
*,count
);
911 /* walk down the new slot ID list returned from the module. We keep
912 * the old slots which match a returned ID, and we initialize the new
914 for (i
=0; i
< count
; i
++) {
915 PK11SlotInfo
*slot
= SECMOD_FindSlotByID(mod
,slotIDs
[i
]);
918 /* we have a new slot create a new slot data structure */
919 slot
= PK11_NewSlotInfo(mod
);
923 PK11_InitSlot(mod
, slotIDs
[i
], slot
);
924 STAN_InitTokenForSlotInfo(NULL
, slot
);
928 STAN_ResetTokenInterator(NULL
);
931 PORT_ArenaUnmark(mod
->arena
, mark
);
933 /* until this point we're still using the old slot list. Now we update
934 * module slot list. We update the slots (array) first then the count,
935 * since we've already guarrenteed that count has increased (just in case
936 * someone is looking at the slots field of module without holding the
938 SECMOD_GetWriteLock(moduleLock
);
939 oldCount
=mod
->slotCount
;
940 oldSlots
= mod
->slots
;
941 mod
->slots
= newSlots
; /* typical arena 'leak'... old mod->slots is
942 * allocated out of the module arena and won't
943 * be freed until the module is freed */
944 mod
->slotCount
= count
;
945 SECMOD_ReleaseWriteLock(moduleLock
);
946 /* free our old references before forgetting about oldSlot*/
947 for (i
=0; i
< oldCount
; i
++) {
948 PK11_FreeSlot(oldSlots
[i
]);
954 PZ_Unlock(mod
->refLock
);
959 /* free all the slots we allocated. newSlots are part of the
960 * mod arena. NOTE: the newSlots array contain both new and old
961 * slots, but we kept a reference to the old slots when we built the new
962 * array, so we need to free all the slots in newSlots array. */
964 for (i
=0; i
< count
; i
++) {
965 if (newSlots
[i
] == NULL
) {
966 break; /* hit the last one */
968 PK11_FreeSlot(newSlots
[i
]);
971 /* must come after freeing newSlots */
973 PORT_ArenaRelease(mod
->arena
, mark
);
979 * this handles modules that do not support C_WaitForSlotEvent().
980 * The internal flags are stored. Note that C_WaitForSlotEvent() does not
981 * have a timeout, so we don't have one for handleWaitForSlotEvent() either.
984 secmod_HandleWaitForSlotEvent(SECMODModule
*mod
, unsigned long flags
,
985 PRIntervalTime latency
)
987 PRBool removableSlotsFound
= PR_FALSE
;
989 int error
= SEC_ERROR_NO_EVENT
;
991 PZ_Lock(mod
->refLock
);
992 if (mod
->evControlMask
& SECMOD_END_WAIT
) {
993 mod
->evControlMask
&= ~SECMOD_END_WAIT
;
994 PZ_Unlock(mod
->refLock
);
995 PORT_SetError(SEC_ERROR_NO_EVENT
);
998 mod
->evControlMask
|= SECMOD_WAIT_SIMULATED_EVENT
;
999 while (mod
->evControlMask
& SECMOD_WAIT_SIMULATED_EVENT
) {
1000 PZ_Unlock(mod
->refLock
);
1001 /* now is a good time to see if new slots have been added */
1002 SECMOD_UpdateSlotList(mod
);
1004 /* loop through all the slots on a module */
1005 SECMOD_GetReadLock(moduleLock
);
1006 for (i
=0; i
< mod
->slotCount
; i
++) {
1007 PK11SlotInfo
*slot
= mod
->slots
[i
];
1011 /* perm modules do not change */
1015 removableSlotsFound
= PR_TRUE
;
1016 /* simulate the PKCS #11 module flags. are the flags different
1017 * from the last time we called? */
1018 series
= slot
->series
;
1019 present
= PK11_IsPresent(slot
);
1020 if ((slot
->flagSeries
!= series
) || (slot
->flagState
!= present
)) {
1021 slot
->flagState
= present
;
1022 slot
->flagSeries
= series
;
1023 SECMOD_ReleaseReadLock(moduleLock
);
1024 PZ_Lock(mod
->refLock
);
1025 mod
->evControlMask
&= ~SECMOD_END_WAIT
;
1026 PZ_Unlock(mod
->refLock
);
1027 return PK11_ReferenceSlot(slot
);
1030 SECMOD_ReleaseReadLock(moduleLock
);
1031 /* if everything was perm modules, don't lock up forever */
1032 if (!removableSlotsFound
) {
1033 error
=SEC_ERROR_NO_SLOT_SELECTED
;
1034 PZ_Lock(mod
->refLock
);
1037 if (flags
& CKF_DONT_BLOCK
) {
1038 PZ_Lock(mod
->refLock
);
1042 PZ_Lock(mod
->refLock
);
1044 mod
->evControlMask
&= ~SECMOD_END_WAIT
;
1045 PZ_Unlock(mod
->refLock
);
1046 PORT_SetError(error
);
1051 * this function waits for a token event on any slot of a given module
1052 * This function should not be called from more than one thread of the
1053 * same process (though other threads can make other library calls
1054 * on this module while this call is blocked).
1057 SECMOD_WaitForAnyTokenEvent(SECMODModule
*mod
, unsigned long flags
,
1058 PRIntervalTime latency
)
1064 if (!pk11_getFinalizeModulesOption() ||
1065 ((mod
->cryptokiVersion
.major
== 2) &&
1066 (mod
->cryptokiVersion
.minor
< 1))) {
1067 /* if we are sharing the module with other software in our
1068 * address space, we can't reliably use C_WaitForSlotEvent(),
1069 * and if the module is version 2.0, C_WaitForSlotEvent() doesn't
1071 return secmod_HandleWaitForSlotEvent(mod
, flags
, latency
);
1073 /* first the the PKCS #11 call */
1074 PZ_Lock(mod
->refLock
);
1075 if (mod
->evControlMask
& SECMOD_END_WAIT
) {
1078 mod
->evControlMask
|= SECMOD_WAIT_PKCS11_EVENT
;
1079 PZ_Unlock(mod
->refLock
);
1080 crv
= PK11_GETTAB(mod
)->C_WaitForSlotEvent(flags
, &id
, NULL
);
1081 PZ_Lock(mod
->refLock
);
1082 mod
->evControlMask
&= ~SECMOD_WAIT_PKCS11_EVENT
;
1083 /* if we are in end wait, short circuit now, don't even risk
1084 * going into secmod_HandleWaitForSlotEvent */
1085 if (mod
->evControlMask
& SECMOD_END_WAIT
) {
1088 PZ_Unlock(mod
->refLock
);
1089 if (crv
== CKR_FUNCTION_NOT_SUPPORTED
) {
1090 /* module doesn't support that call, simulate it */
1091 return secmod_HandleWaitForSlotEvent(mod
, flags
, latency
);
1093 if (crv
!= CKR_OK
) {
1094 /* we can get this error if finalize was called while we were
1095 * still running. This is the only way to force a C_WaitForSlotEvent()
1096 * to return in PKCS #11. In this case, just return that there
1098 if (crv
== CKR_CRYPTOKI_NOT_INITIALIZED
) {
1099 PORT_SetError(SEC_ERROR_NO_EVENT
);
1101 PORT_SetError(PK11_MapError(crv
));
1105 slot
= SECMOD_FindSlotByID(mod
, id
);
1107 /* possibly a new slot that was added? */
1108 SECMOD_UpdateSlotList(mod
);
1109 slot
= SECMOD_FindSlotByID(mod
, id
);
1111 /* if we are in the delay period for the "isPresent" call, reset
1112 * the delay since we know things have probably changed... */
1113 if (slot
&& slot
->nssToken
&& slot
->nssToken
->slot
) {
1114 nssSlot_ResetDelay(slot
->nssToken
->slot
);
1118 /* must be called with the lock on. */
1120 mod
->evControlMask
&= ~SECMOD_END_WAIT
;
1121 PZ_Unlock(mod
->refLock
);
1122 PORT_SetError(SEC_ERROR_NO_EVENT
);
1127 * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic
1128 * function, possibly bringing down the pkcs #11 module in question. This
1129 * should be OK because 1) it does reinitialize, and 2) it should only be
1130 * called when we are on our way to tear the whole system down anyway.
1133 SECMOD_CancelWait(SECMODModule
*mod
)
1135 unsigned long controlMask
= mod
->evControlMask
;
1136 SECStatus rv
= SECSuccess
;
1139 PZ_Lock(mod
->refLock
);
1140 mod
->evControlMask
|= SECMOD_END_WAIT
;
1141 controlMask
= mod
->evControlMask
;
1142 if (controlMask
& SECMOD_WAIT_PKCS11_EVENT
) {
1143 if (!pk11_getFinalizeModulesOption()) {
1144 /* can't get here unless pk11_getFinalizeModulesOption is set */
1146 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE
);
1150 /* NOTE: this call will drop all transient keys, in progress
1151 * operations, and any authentication. This is the only documented
1152 * way to get WaitForSlotEvent to return. Also note: for non-thread
1153 * safe tokens, we need to hold the module lock, this is not yet at
1154 * system shutdown/startup time, so we need to protect these calls */
1155 crv
= PK11_GETTAB(mod
)->C_Finalize(NULL
);
1156 /* ok, we slammed the module down, now we need to reinit it in case
1157 * we intend to use it again */
1158 if (CKR_OK
== crv
) {
1159 PRBool alreadyLoaded
;
1160 secmod_ModuleInit(mod
, &alreadyLoaded
);
1162 /* Finalized failed for some reason, notify the application
1163 * so maybe it has a prayer of recovering... */
1164 PORT_SetError(PK11_MapError(crv
));
1167 } else if (controlMask
& SECMOD_WAIT_SIMULATED_EVENT
) {
1168 mod
->evControlMask
&= ~SECMOD_WAIT_SIMULATED_EVENT
;
1169 /* Simulated events will eventually timeout
1170 * and wake up in the loop */
1173 PZ_Unlock(mod
->refLock
);
1178 * check to see if the module has removable slots that we may need to
1182 SECMOD_HasRemovableSlots(SECMODModule
*mod
)
1185 PRBool ret
= PR_FALSE
;
1187 SECMOD_GetReadLock(moduleLock
);
1188 for (i
=0; i
< mod
->slotCount
; i
++) {
1189 PK11SlotInfo
*slot
= mod
->slots
[i
];
1190 /* perm modules are not inserted or removed */
1197 SECMOD_ReleaseReadLock(moduleLock
);
1202 * helper function to actually create and destroy user defined slots
1205 secmod_UserDBOp(CK_OBJECT_CLASS objClass
, const char *sendSpec
)
1207 PK11SlotInfo
*slot
= PK11_GetInternalSlot();
1208 CK_OBJECT_HANDLE dummy
;
1209 CK_ATTRIBUTE
template[2] ;
1210 CK_ATTRIBUTE
*attrs
= template;
1214 PK11_SETATTRS(attrs
, CKA_CLASS
, &objClass
, sizeof(objClass
)); attrs
++;
1215 PK11_SETATTRS(attrs
, CKA_NETSCAPE_MODULE_SPEC
, (unsigned char *)sendSpec
,
1216 strlen(sendSpec
)+1); attrs
++;
1218 PORT_Assert(attrs
-template <= 2);
1221 PK11_EnterSlotMonitor(slot
);
1222 crv
= PK11_CreateNewObject(slot
, slot
->session
,
1223 template, attrs
-template, PR_FALSE
, &dummy
);
1224 PK11_ExitSlotMonitor(slot
);
1226 if (crv
!= CKR_OK
) {
1227 PK11_FreeSlot(slot
);
1228 PORT_SetError(PK11_MapError(crv
));
1231 rv
= SECMOD_UpdateSlotList(slot
->module
);
1232 PK11_FreeSlot(slot
);
1237 * add escapes to protect quote characters...
1240 nss_addEscape(const char *string
, char quote
)
1242 char *newString
= 0;
1243 int escapes
= 0, size
= 0;
1247 for (src
=string
; *src
; src
++) {
1248 if ((*src
== quote
) || (*src
== '\\')) escapes
++;
1252 newString
= PORT_ZAlloc(escapes
+size
+1);
1253 if (newString
== NULL
) {
1257 for (src
=string
, dest
=newString
; *src
; src
++,dest
++) {
1258 if ((*src
== '\\') || (*src
== quote
)) {
1268 nss_doubleEscape(const char *string
)
1270 char *round1
= NULL
;
1271 char *retValue
= NULL
;
1272 if (string
== NULL
) {
1275 round1
= nss_addEscape(string
,'>');
1277 retValue
= nss_addEscape(round1
,']');
1282 if (retValue
== NULL
) {
1283 retValue
= PORT_Strdup("");
1289 * Open a new database using the softoken. The caller is responsible for making
1290 * sure the module spec is correct and usable. The caller should ask for one
1291 * new database per call if the caller wants to get meaningful information
1292 * about the new database.
1294 * moduleSpec is the same data that you would pass to softoken at
1295 * initialization time under the 'tokens' options. For example, if you were
1296 * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']>
1297 * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your
1298 * module spec here. The slot ID will be calculated for you by
1299 * SECMOD_OpenUserDB().
1301 * Typical parameters here are configdir, tokenDescription and flags.
1303 * a Full list is below:
1306 * configDir - The location of the databases for this token. If configDir is
1307 * not specified, and noCertDB and noKeyDB is not specified, the load
1309 * certPrefix - Cert prefix for this token.
1310 * keyPrefix - Prefix for the key database for this token. (if not specified,
1311 * certPrefix will be used).
1312 * tokenDescription - The label value for this token returned in the
1313 * CK_TOKEN_INFO structure with an internationalize string (UTF8).
1314 * This value will be truncated at 32 bytes (no NULL, partial UTF8
1315 * characters dropped). You should specify a user friendly name here
1316 * as this is the value the token will be refered to in most
1317 * application UI's. You should make sure tokenDescription is unique.
1318 * slotDescription - The slotDescription value for this token returned
1319 * in the CK_SLOT_INFO structure with an internationalize string
1320 * (UTF8). This value will be truncated at 64 bytes (no NULL, partial
1321 * UTF8 characters dropped). This name will not change after the
1322 * database is closed. It should have some number to make this unique.
1323 * minPWLen - minimum password length for this token.
1324 * flags - comma separated list of flag values, parsed case-insensitive.
1326 * readOnly - Databases should be opened read only.
1327 * noCertDB - Don't try to open a certificate database.
1328 * noKeyDB - Don't try to open a key database.
1329 * forceOpen - Don't fail to initialize the token if the
1330 * databases could not be opened.
1331 * passwordRequired - zero length passwords are not acceptable
1332 * (valid only if there is a keyDB).
1333 * optimizeSpace - allocate smaller hash tables and lock tables.
1334 * When this flag is not specified, Softoken will allocate
1335 * large tables to prevent lock contention.
1338 SECMOD_OpenUserDB(const char *moduleSpec
)
1340 CK_SLOT_ID slotID
= 0;
1345 CK_SLOT_ID i
, minSlotID
, maxSlotID
;
1346 PRBool found
= PR_FALSE
;
1348 if (moduleSpec
== NULL
) {
1352 /* NOTE: unlike most PK11 function, this does not return a reference
1354 mod
= SECMOD_GetInternalModule();
1356 /* shouldn't happen */
1357 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE
);
1361 /* look for a free slot id on the internal module */
1363 minSlotID
= SFTK_MIN_FIPS_USER_SLOT_ID
;
1364 maxSlotID
= SFTK_MAX_FIPS_USER_SLOT_ID
;
1366 minSlotID
= SFTK_MIN_USER_SLOT_ID
;
1367 maxSlotID
= SFTK_MAX_USER_SLOT_ID
;
1369 for (i
=minSlotID
; i
< maxSlotID
; i
++) {
1370 PK11SlotInfo
*slot
= SECMOD_LookupSlot(mod
->moduleID
, i
);
1372 PRBool present
= PK11_IsPresent(slot
);
1373 PK11_FreeSlot(slot
);
1377 /* not present means it's available */
1379 /* it doesn't exist or isn't present, it's available */
1386 /* this could happen if we try to open too many slots */
1387 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED
);
1391 /* we've found the slot, now build the moduleSpec */
1393 escSpec
= nss_doubleEscape(moduleSpec
);
1394 if (escSpec
== NULL
) {
1397 sendSpec
= PR_smprintf("tokens=[0x%x=<%s>]", slotID
, escSpec
);
1400 if (sendSpec
== NULL
) {
1401 /* PR_smprintf does not set no memory error */
1402 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1405 rv
= secmod_UserDBOp(CKO_NETSCAPE_NEWSLOT
, sendSpec
);
1406 PR_smprintf_free(sendSpec
);
1407 if (rv
!= SECSuccess
) {
1411 return SECMOD_FindSlotByID(mod
, slotID
);
1415 * close an already opened user database. NOTE: the database must be
1416 * in the internal token, and must be one created with SECMOD_OpenUserDB().
1417 * Once the database is closed, the slot will remain as an empty slot
1418 * until it's used again with SECMOD_OpenUserDB().
1421 SECMOD_CloseUserDB(PK11SlotInfo
*slot
)
1426 if (!slot
->isInternal
) {
1427 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1431 sendSpec
= PR_smprintf("tokens=[0x%x=<>]", slot
->slotID
);
1432 if (sendSpec
== NULL
) {
1433 /* PR_smprintf does not set no memory error */
1434 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1437 rv
= secmod_UserDBOp(CKO_NETSCAPE_DELSLOT
, sendSpec
);
1438 PR_smprintf_free(sendSpec
);