2 * NSS utility functions
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is the Netscape security libraries.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1994-2000
22 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
39 /* $Id: nssinit.c,v 1.114 2011/10/18 19:03:31 wtc%google.com Exp $ */
60 #include "pkix_tools.h"
69 * On Windows nss3.dll needs to export the symbol 'mktemp' to be
70 * fully backward compatible with the nss3.dll in NSS 3.2.x and
71 * 3.3.x. This symbol was unintentionally exported and its
72 * definition (in DBM) was moved from nss3.dll to softokn3.dll
73 * in NSS 3.4. See bug 142575.
75 #ifdef WIN32_NSS3_DLL_COMPAT
78 /* exported as 'mktemp' */
80 nss_mktemp(char *path)
86 #define NSS_MAX_FLAG_SIZE sizeof("readOnly")+sizeof("noCertDB")+ \
87 sizeof("noModDB")+sizeof("forceOpen")+sizeof("passwordRequired")+ \
88 sizeof ("optimizeSpace")
89 #define NSS_DEFAULT_MOD_NAME "NSS Internal Module"
92 nss_makeFlags(PRBool readOnly, PRBool noCertDB,
93 PRBool noModDB, PRBool forceOpen,
94 PRBool passwordRequired, PRBool optimizeSpace)
96 char *flags = (char *)PORT_Alloc(NSS_MAX_FLAG_SIZE);
97 PRBool first = PR_TRUE;
99 PORT_Memset(flags,0,NSS_MAX_FLAG_SIZE);
101 PORT_Strcat(flags,"readOnly");
105 if (!first) PORT_Strcat(flags,",");
106 PORT_Strcat(flags,"noCertDB");
110 if (!first) PORT_Strcat(flags,",");
111 PORT_Strcat(flags,"noModDB");
115 if (!first) PORT_Strcat(flags,",");
116 PORT_Strcat(flags,"forceOpen");
119 if (passwordRequired) {
120 if (!first) PORT_Strcat(flags,",");
121 PORT_Strcat(flags,"passwordRequired");
125 if (!first) PORT_Strcat(flags,",");
126 PORT_Strcat(flags,"optimizeSpace");
134 * build config string from individual internationalized strings
137 nss_MkConfigString(const char *man, const char *libdesc, const char *tokdesc,
138 const char *ptokdesc, const char *slotdesc, const char *pslotdesc,
139 const char *fslotdesc, const char *fpslotdesc, int minPwd)
141 char *strings = NULL;
144 /* make sure the internationalization was done correctly... */
145 strings = PR_smprintf("");
146 if (strings == NULL) return NULL;
149 newStrings = PR_smprintf("%s manufacturerID='%s'",strings,man);
150 PR_smprintf_free(strings);
151 strings = newStrings;
153 if (strings == NULL) return NULL;
156 newStrings = PR_smprintf("%s libraryDescription='%s'",strings,libdesc);
157 PR_smprintf_free(strings);
158 strings = newStrings;
160 if (strings == NULL) return NULL;
163 newStrings = PR_smprintf("%s cryptoTokenDescription='%s'",strings,
165 PR_smprintf_free(strings);
166 strings = newStrings;
168 if (strings == NULL) return NULL;
171 newStrings = PR_smprintf("%s dbTokenDescription='%s'",strings,ptokdesc);
172 PR_smprintf_free(strings);
173 strings = newStrings;
175 if (strings == NULL) return NULL;
178 newStrings = PR_smprintf("%s cryptoSlotDescription='%s'",strings,
180 PR_smprintf_free(strings);
181 strings = newStrings;
183 if (strings == NULL) return NULL;
186 newStrings = PR_smprintf("%s dbSlotDescription='%s'",strings,pslotdesc);
187 PR_smprintf_free(strings);
188 strings = newStrings;
190 if (strings == NULL) return NULL;
193 newStrings = PR_smprintf("%s FIPSSlotDescription='%s'",
195 PR_smprintf_free(strings);
196 strings = newStrings;
198 if (strings == NULL) return NULL;
201 newStrings = PR_smprintf("%s FIPSTokenDescription='%s'",
203 PR_smprintf_free(strings);
204 strings = newStrings;
206 if (strings == NULL) return NULL;
208 newStrings = PR_smprintf("%s minPS=%d", strings, minPwd);
209 PR_smprintf_free(strings);
210 strings = newStrings;
216 * statics to remember the PK11_ConfigurePKCS11()
219 static char * pk11_config_strings = NULL;
220 static char * pk11_config_name = NULL;
221 static PRBool pk11_password_required = PR_FALSE;
224 * this is a legacy configuration function which used to be part of
225 * the PKCS #11 internal token.
228 PK11_ConfigurePKCS11(const char *man, const char *libdesc, const char *tokdesc,
229 const char *ptokdesc, const char *slotdesc, const char *pslotdesc,
230 const char *fslotdesc, const char *fpslotdesc, int minPwd,
235 strings = nss_MkConfigString(man,libdesc,tokdesc,ptokdesc,slotdesc,
236 pslotdesc,fslotdesc,fpslotdesc,minPwd);
237 if (strings == NULL) {
242 if (pk11_config_name != NULL) {
243 PORT_Free(pk11_config_name);
245 pk11_config_name = PORT_Strdup(libdesc);
248 if (pk11_config_strings != NULL) {
249 PR_smprintf_free(pk11_config_strings);
251 pk11_config_strings = strings;
252 pk11_password_required = pwRequired;
257 void PK11_UnconfigurePKCS11(void)
259 if (pk11_config_strings != NULL) {
260 PR_smprintf_free(pk11_config_strings);
261 pk11_config_strings = NULL;
263 if (pk11_config_name) {
264 PORT_Free(pk11_config_name);
265 pk11_config_name = NULL;
270 * The following code is an attempt to automagically find the external root
272 * Note: Keep the #if-defined chunks in order. HPUX must select before UNIX.
275 static const char *dllname =
276 #if defined(XP_WIN32) || defined(XP_OS2)
278 #elif defined(HPUX) && !defined(__ia64) /* HP-UX PA-RISC */
280 #elif defined(DARWIN)
282 #elif defined(XP_UNIX) || defined(XP_BEOS)
285 #error "Uh! Oh! I don't know about this platform."
288 /* Should we have platform ifdefs here??? */
291 static void nss_FindExternalRootPaths(const char *dbpath,
292 const char* secmodprefix,
293 char** retoldpath, char** retnewpath)
295 char *path, *oldpath = NULL, *lastsep;
296 int len, path_len, secmod_len, dll_len;
298 path_len = PORT_Strlen(dbpath);
299 secmod_len = secmodprefix ? PORT_Strlen(secmodprefix) : 0;
300 dll_len = PORT_Strlen(dllname);
301 len = path_len + secmod_len + dll_len + 2; /* FILE_SEP + NULL */
303 path = PORT_Alloc(len);
304 if (path == NULL) return;
306 /* back up to the top of the directory */
307 PORT_Memcpy(path,dbpath,path_len);
308 if (path[path_len-1] != FILE_SEP) {
309 path[path_len++] = FILE_SEP;
311 PORT_Strcpy(&path[path_len],dllname);
312 if (secmod_len > 0) {
313 lastsep = PORT_Strrchr(secmodprefix, FILE_SEP);
315 int secmoddir_len = lastsep-secmodprefix+1; /* FILE_SEP */
316 oldpath = PORT_Alloc(len);
317 if (oldpath == NULL) {
321 PORT_Memcpy(oldpath,path,path_len);
322 PORT_Memcpy(&oldpath[path_len],secmodprefix,secmoddir_len);
323 PORT_Strcpy(&oldpath[path_len+secmoddir_len],dllname);
326 *retoldpath = oldpath;
331 static void nss_FreeExternalRootPaths(char* oldpath, char* path)
342 nss_FindExternalRoot(const char *dbpath, const char* secmodprefix)
345 char *oldpath = NULL;
346 PRBool hasrootcerts = PR_FALSE;
349 * 'oldpath' is the external root path in NSS 3.3.x or older.
350 * For backward compatibility we try to load the root certs
351 * module with the old path first.
353 nss_FindExternalRootPaths(dbpath, secmodprefix, &oldpath, &path);
355 (void) SECMOD_AddNewModule("Root Certs",oldpath, 0, 0);
356 hasrootcerts = SECMOD_HasRootCerts();
358 if (path && !hasrootcerts) {
359 (void) SECMOD_AddNewModule("Root Certs",path, 0, 0);
361 nss_FreeExternalRootPaths(oldpath, path);
366 * see nss_Init for definitions of the various options.
368 * this function builds a moduleSpec string from the options and previously
369 * set statics (from PKCS11_Configure, for instance), and uses it to kick off
370 * the loading of the various PKCS #11 modules.
373 nss_InitModules(const char *configdir, const char *certPrefix,
374 const char *keyPrefix, const char *secmodName,
375 const char *updateDir, const char *updCertPrefix,
376 const char *updKeyPrefix, const char *updateID,
377 const char *updateName, char *configName, char *configStrings,
378 PRBool pwRequired, PRBool readOnly, PRBool noCertDB,
379 PRBool noModDB, PRBool forceOpen, PRBool optimizeSpace,
380 PRBool isContextInit)
382 SECStatus rv = SECFailure;
383 char *moduleSpec = NULL;
385 char *lconfigdir = NULL;
386 char *lcertPrefix = NULL;
387 char *lkeyPrefix = NULL;
388 char *lsecmodName = NULL;
389 char *lupdateDir = NULL;
390 char *lupdCertPrefix = NULL;
391 char *lupdKeyPrefix = NULL;
392 char *lupdateID = NULL;
393 char *lupdateName = NULL;
395 if (NSS_InitializePRErrorTable() != SECSuccess) {
396 PORT_SetError(SEC_ERROR_NO_MEMORY);
400 flags = nss_makeFlags(readOnly,noCertDB,noModDB,forceOpen,
401 pwRequired, optimizeSpace);
402 if (flags == NULL) return rv;
405 * configdir is double nested, and Windows uses the same character
406 * for file seps as we use for escapes! (sigh).
408 lconfigdir = secmod_DoubleEscape(configdir, '\'', '\"');
409 if (lconfigdir == NULL) {
412 lcertPrefix = secmod_DoubleEscape(certPrefix, '\'', '\"');
413 if (lcertPrefix == NULL) {
416 lkeyPrefix = secmod_DoubleEscape(keyPrefix, '\'', '\"');
417 if (lkeyPrefix == NULL) {
420 lsecmodName = secmod_DoubleEscape(secmodName, '\'', '\"');
421 if (lsecmodName == NULL) {
424 lupdateDir = secmod_DoubleEscape(updateDir, '\'', '\"');
425 if (lupdateDir == NULL) {
428 lupdCertPrefix = secmod_DoubleEscape(updCertPrefix, '\'', '\"');
429 if (lupdCertPrefix == NULL) {
432 lupdKeyPrefix = secmod_DoubleEscape(updKeyPrefix, '\'', '\"');
433 if (lupdKeyPrefix == NULL) {
436 lupdateID = secmod_DoubleEscape(updateID, '\'', '\"');
437 if (lupdateID == NULL) {
440 lupdateName = secmod_DoubleEscape(updateName, '\'', '\"');
441 if (lupdateName == NULL) {
445 moduleSpec = PR_smprintf(
446 "name=\"%s\" parameters=\"configdir='%s' certPrefix='%s' keyPrefix='%s' "
447 "secmod='%s' flags=%s updatedir='%s' updateCertPrefix='%s' "
448 "updateKeyPrefix='%s' updateid='%s' updateTokenDescription='%s' %s\" "
449 "NSS=\"flags=internal,moduleDB,moduleDBOnly,critical%s\"",
450 configName ? configName : NSS_DEFAULT_MOD_NAME,
451 lconfigdir,lcertPrefix,lkeyPrefix,lsecmodName,flags,
452 lupdateDir, lupdCertPrefix, lupdKeyPrefix, lupdateID,
453 lupdateName, configStrings ? configStrings : "",
454 isContextInit ? "" : ",defaultModDB,internalKeySlot");
458 if (lconfigdir) PORT_Free(lconfigdir);
459 if (lcertPrefix) PORT_Free(lcertPrefix);
460 if (lkeyPrefix) PORT_Free(lkeyPrefix);
461 if (lsecmodName) PORT_Free(lsecmodName);
462 if (lupdateDir) PORT_Free(lupdateDir);
463 if (lupdCertPrefix) PORT_Free(lupdCertPrefix);
464 if (lupdKeyPrefix) PORT_Free(lupdKeyPrefix);
465 if (lupdateID) PORT_Free(lupdateID);
466 if (lupdateName) PORT_Free(lupdateName);
469 SECMODModule *module = SECMOD_LoadModule(moduleSpec,NULL,PR_TRUE);
470 PR_smprintf_free(moduleSpec);
472 if (module->loaded) rv=SECSuccess;
473 SECMOD_DestroyModule(module);
480 * OK there are now lots of options here, lets go through them all:
482 * configdir - base directory where all the cert, key, and module datbases live.
483 * certPrefix - prefix added to the beginning of the cert database example: "
485 * keyPrefix - prefix added to the beginning of the key database example: "
487 * secmodName - name of the security module database (usually "secmod.db").
488 * updateDir - used in initMerge, old directory to update from.
489 * updateID - used in initMerge, unique ID to represent the updated directory.
490 * updateName - used in initMerge, token name when updating.
491 * initContextPtr - used in initContext, pointer to return a unique context
493 * readOnly - Boolean: true if the databases are to be opened read only.
494 * nocertdb - Don't open the cert DB and key DB's, just initialize the
496 * nomoddb - Don't open the security module DB, just initialize the
498 * forceOpen - Continue to force initializations even if the databases cannot
500 * noRootInit - don't try to automatically load the root cert store if one is
502 * optimizeSpace - tell NSS to use fewer hash table buckets.
504 * The next three options are used in an attempt to share PKCS #11 modules
505 * with other loaded, running libraries. PKCS #11 was not designed with this
506 * sort of sharing in mind, so use of these options may lead to questionable
507 * results. These options are may be incompatible with NSS_LoadContext() calls.
509 * noSingleThreadedModules - don't load modules that are not thread safe (many
510 * smart card tokens will not work).
511 * allowAlreadyInitializedModules - if a module has already been loaded and
512 * initialize try to use it.
513 * don'tFinalizeModules - dont shutdown modules we may have loaded.
516 static PRBool nssIsInitted = PR_FALSE;
517 static NSSInitContext *nssInitContextList = NULL;
518 static void* plContext = NULL;
520 struct NSSInitContextStr {
521 NSSInitContext *next;
525 #define NSS_INIT_MAGIC 0x1413A91C
526 static SECStatus nss_InitShutdownList(void);
529 static CERTCertificate dummyCert;
532 /* All initialized to zero in BSS */
533 static PRCallOnceType nssInitOnce;
534 static PZLock *nssInitLock;
535 static PZCondVar *nssInitCondition;
536 static int nssIsInInit;
541 nssInitLock = PZ_NewLock(nssILockOther);
542 if (nssInitLock == NULL) {
545 nssInitCondition = PZ_NewCondVar(nssInitLock);
546 if (nssInitCondition == NULL) {
554 nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
555 const char *secmodName, const char *updateDir,
556 const char *updCertPrefix, const char *updKeyPrefix,
557 const char *updateID, const char *updateName,
558 NSSInitContext ** initContextPtr,
559 NSSInitParameters *initParams,
560 PRBool readOnly, PRBool noCertDB,
561 PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
562 PRBool optimizeSpace, PRBool noSingleThreadedModules,
563 PRBool allowAlreadyInitializedModules,
564 PRBool dontFinalizeModules)
566 SECStatus rv = SECFailure;
567 PKIX_UInt32 actualMinorVersion = 0;
568 PKIX_Error *pkixError = NULL;
569 PRBool isReallyInitted;
570 char *configStrings = NULL;
571 char *configName = NULL;
572 PRBool passwordRequired = PR_FALSE;
574 /* if we are trying to init with a traditional NSS_Init call, maintain
575 * the traditional idempotent behavior. */
576 if (!initContextPtr && nssIsInitted) {
580 /* make sure our lock and condition variable are initialized one and only
582 if (PR_CallOnce(&nssInitOnce, nss_doLockInit) != PR_SUCCESS) {
587 * if we haven't done basic initialization, single thread the
590 PZ_Lock(nssInitLock);
591 isReallyInitted = NSS_IsInitialized();
592 if (!isReallyInitted) {
593 while (!isReallyInitted && nssIsInInit) {
594 PZ_WaitCondVar(nssInitCondition,PR_INTERVAL_NO_TIMEOUT);
595 isReallyInitted = NSS_IsInitialized();
597 /* once we've completed basic initialization, we can allow more than
598 * one process initialize NSS at a time. */
601 PZ_Unlock(nssInitLock);
603 /* this tells us whether or not some library has already initialized us.
604 * if so, we don't want to double call some of the basic initialization
607 if (!isReallyInitted) {
608 /* New option bits must not change the size of CERTCertificate. */
609 PORT_Assert(sizeof(dummyCert.options) == sizeof(void *));
611 if (SECSuccess != cert_InitLocks()) {
615 if (SECSuccess != InitCRLCache()) {
619 if (SECSuccess != OCSP_InitGlobal()) {
624 if (noSingleThreadedModules || allowAlreadyInitializedModules ||
625 dontFinalizeModules) {
626 pk11_setGlobalOptions(noSingleThreadedModules,
627 allowAlreadyInitializedModules,
628 dontFinalizeModules);
631 if (initContextPtr) {
632 *initContextPtr = PORT_ZNew(NSSInitContext);
633 if (*initContextPtr == NULL) {
637 * For traditional NSS_Init, we used the PK11_Configure() call to set
638 * globals. with InitContext, we pass those strings in as parameters.
640 * This allows old NSS_Init calls to work as before, while at the same
641 * time new calls and old calls will not interfere with each other.
644 if (initParams->length < sizeof(NSSInitParameters)) {
645 PORT_SetError(SEC_ERROR_INVALID_ARGS);
648 configStrings = nss_MkConfigString(initParams->manufactureID,
649 initParams->libraryDescription,
650 initParams->cryptoTokenDescription,
651 initParams->dbTokenDescription,
652 initParams->cryptoSlotDescription,
653 initParams->dbSlotDescription,
654 initParams->FIPSSlotDescription,
655 initParams->FIPSTokenDescription,
656 initParams->minPWLen);
657 if (configStrings == NULL) {
658 PORT_SetError(SEC_ERROR_NO_MEMORY);
661 configName = initParams->libraryDescription;
662 passwordRequired = initParams->passwordRequired;
665 configStrings = pk11_config_strings;
666 configName = pk11_config_name;
667 passwordRequired = pk11_password_required;
670 /* we always try to initialize the modules */
671 rv = nss_InitModules(configdir, certPrefix, keyPrefix, secmodName,
672 updateDir, updCertPrefix, updKeyPrefix, updateID,
673 updateName, configName, configStrings, passwordRequired,
674 readOnly, noCertDB, noModDB, forceOpen, optimizeSpace,
675 (initContextPtr != NULL));
677 if (rv != SECSuccess) {
682 /* finish up initialization */
683 if (!isReallyInitted) {
684 if (SECOID_Init() != SECSuccess) {
687 if (STAN_LoadDefaultNSS3TrustDomain() != PR_SUCCESS) {
690 if (nss_InitShutdownList() != SECSuccess) {
693 CERT_SetDefaultCertDB((CERTCertDBHandle *)
694 STAN_GetDefaultTrustDomain());
695 if ((!noModDB) && (!noCertDB) && (!noRootInit)) {
696 if (!SECMOD_HasRootCerts()) {
697 const char *dbpath = configdir;
698 /* handle supported database modifiers */
699 if (strncmp(dbpath, "sql:", 4) == 0) {
701 } else if(strncmp(dbpath, "dbm:", 4) == 0) {
703 } else if(strncmp(dbpath, "extern:", 7) == 0) {
705 } else if(strncmp(dbpath, "rdb:", 4) == 0) {
706 /* if rdb: is specified, the configdir isn't really a
711 nss_FindExternalRoot(dbpath, secmodName);
717 cert_CreateSubjectKeyIDHashTable();
719 pkixError = PKIX_Initialize
720 (PKIX_FALSE, PKIX_MAJOR_VERSION, PKIX_MINOR_VERSION,
721 PKIX_MINOR_VERSION, &actualMinorVersion, &plContext);
723 if (pkixError != NULL) {
726 char *ev = getenv("NSS_ENABLE_PKIX_VERIFY");
728 CERT_SetUsePKIXForValidation(PR_TRUE);
736 * Now mark the appropriate init state. If initContextPtr was passed
737 * in, then return the new context pointer and add it to the
738 * nssInitContextList. Otherwise set the global nss_isInitted flag
740 PZ_Lock(nssInitLock);
741 if (!initContextPtr) {
742 nssIsInitted = PR_TRUE;
744 (*initContextPtr)->magic = NSS_INIT_MAGIC;
745 (*initContextPtr)->next = nssInitContextList;
746 nssInitContextList = (*initContextPtr);
749 /* now that we are inited, all waiters can move forward */
750 PZ_NotifyAllCondVar(nssInitCondition);
751 PZ_Unlock(nssInitLock);
756 if (initContextPtr && *initContextPtr) {
757 PORT_Free(*initContextPtr);
758 *initContextPtr = NULL;
760 PR_smprintf_free(configStrings);
763 PZ_Lock(nssInitLock);
765 /* We failed to init, allow one to move forward */
766 PZ_NotifyCondVar(nssInitCondition);
767 PZ_Unlock(nssInitLock);
773 NSS_Init(const char *configdir)
775 return nss_Init(configdir, "", "", SECMOD_DB, "", "", "", "", "", NULL,
776 NULL, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE,
777 PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
781 NSS_InitReadWrite(const char *configdir)
783 return nss_Init(configdir, "", "", SECMOD_DB, "", "", "", "", "", NULL,
784 NULL, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE,
785 PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
789 * OK there are now lots of options here, lets go through them all:
791 * configdir - base directory where all the cert, key, and module datbases live.
792 * certPrefix - prefix added to the beginning of the cert database example: "
794 * keyPrefix - prefix added to the beginning of the key database example: "
796 * secmodName - name of the security module database (usually "secmod.db").
797 * flags - change the open options of NSS_Initialize as follows:
798 * NSS_INIT_READONLY - Open the databases read only.
799 * NSS_INIT_NOCERTDB - Don't open the cert DB and key DB's, just
800 * initialize the volatile certdb.
801 * NSS_INIT_NOMODDB - Don't open the security module DB, just
802 * initialize the PKCS #11 module.
803 * NSS_INIT_FORCEOPEN - Continue to force initializations even if the
804 * databases cannot be opened.
805 * NSS_INIT_PK11THREADSAFE - only load PKCS#11 modules that are
806 * thread-safe, ie. that support locking - either OS
807 * locking or NSS-provided locks . If a PKCS#11
808 * module isn't thread-safe, don't serialize its
809 * calls; just don't load it instead. This is necessary
810 * if another piece of code is using the same PKCS#11
811 * modules that NSS is accessing without going through
812 * NSS, for example the Java SunPKCS11 provider.
813 * NSS_INIT_PK11RELOAD - ignore the CKR_CRYPTOKI_ALREADY_INITIALIZED
814 * error when loading PKCS#11 modules. This is necessary
815 * if another piece of code is using the same PKCS#11
816 * modules that NSS is accessing without going through
817 * NSS, for example Java SunPKCS11 provider.
818 * NSS_INIT_NOPK11FINALIZE - never call C_Finalize on any
819 * PKCS#11 module. This may be necessary in order to
820 * ensure continuous operation and proper shutdown
821 * sequence if another piece of code is using the same
822 * PKCS#11 modules that NSS is accessing without going
823 * through NSS, for example Java SunPKCS11 provider.
824 * The following limitation applies when this is set :
825 * SECMOD_WaitForAnyTokenEvent will not use
826 * C_WaitForSlotEvent, in order to prevent the need for
827 * C_Finalize. This call will be emulated instead.
828 * NSS_INIT_RESERVED - Currently has no effect, but may be used in the
829 * future to trigger better cooperation between PKCS#11
830 * modules used by both NSS and the Java SunPKCS11
831 * provider. This should occur after a new flag is defined
832 * for C_Initialize by the PKCS#11 working group.
833 * NSS_INIT_COOPERATE - Sets 4 recommended options for applications that
834 * use both NSS and the Java SunPKCS11 provider.
837 NSS_Initialize(const char *configdir, const char *certPrefix,
838 const char *keyPrefix, const char *secmodName, PRUint32 flags)
840 return nss_Init(configdir, certPrefix, keyPrefix, secmodName,
841 "", "", "", "", "", NULL, NULL,
842 ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
843 ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
844 ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
845 ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
846 ((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
847 ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
848 ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
849 ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
850 ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
854 NSS_InitContext(const char *configdir, const char *certPrefix,
855 const char *keyPrefix, const char *secmodName,
856 NSSInitParameters *initParams, PRUint32 flags)
859 NSSInitContext *context;
861 rv = nss_Init(configdir, certPrefix, keyPrefix, secmodName,
862 "", "", "", "", "", &context, initParams,
863 ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
864 ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
865 ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
866 ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN), PR_TRUE,
867 ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
868 ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
869 ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
870 ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
871 return (rv == SECSuccess) ? context : NULL;
875 NSS_InitWithMerge(const char *configdir, const char *certPrefix,
876 const char *keyPrefix, const char *secmodName,
877 const char *updateDir, const char *updCertPrefix,
878 const char *updKeyPrefix, const char *updateID,
879 const char *updateName, PRUint32 flags)
881 return nss_Init(configdir, certPrefix, keyPrefix, secmodName,
882 updateDir, updCertPrefix, updKeyPrefix, updateID, updateName,
884 ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
885 ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
886 ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
887 ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
888 ((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
889 ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
890 ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
891 ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
892 ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
896 * initialize NSS without a creating cert db's, key db's, or secmod db's.
899 NSS_NoDB_Init(const char * configdir)
901 return nss_Init("","","","", "", "", "", "", "", NULL, NULL,
902 PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,
903 PR_FALSE,PR_FALSE,PR_FALSE);
907 #define NSS_SHUTDOWN_STEP 10
909 struct NSSShutdownFuncPair {
910 NSS_ShutdownFunc func;
914 static struct NSSShutdownListStr {
918 struct NSSShutdownFuncPair *funcs;
919 } nssShutdownList = { 0 };
922 * find and existing shutdown function
925 nss_GetShutdownEntry(NSS_ShutdownFunc sFunc, void *appData)
928 count = nssShutdownList.peakFuncs;
930 for (i=0; i < count; i++) {
931 if ((nssShutdownList.funcs[i].func == sFunc) &&
932 (nssShutdownList.funcs[i].appData == appData)){
940 * register a callback to be called when NSS shuts down
943 NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
947 PZ_Lock(nssInitLock);
948 if (!NSS_IsInitialized()) {
949 PZ_Unlock(nssInitLock);
950 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
953 PZ_Unlock(nssInitLock);
955 PORT_SetError(SEC_ERROR_INVALID_ARGS);
959 PORT_Assert(nssShutdownList.lock);
960 PZ_Lock(nssShutdownList.lock);
962 /* make sure we don't have a duplicate */
963 i = nss_GetShutdownEntry(sFunc, appData);
965 PZ_Unlock(nssShutdownList.lock);
966 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
969 /* find an empty slot */
970 i = nss_GetShutdownEntry(NULL, NULL);
972 nssShutdownList.funcs[i].func = sFunc;
973 nssShutdownList.funcs[i].appData = appData;
974 PZ_Unlock(nssShutdownList.lock);
977 if (nssShutdownList.allocatedFuncs == nssShutdownList.peakFuncs) {
978 struct NSSShutdownFuncPair *funcs =
979 (struct NSSShutdownFuncPair *)PORT_Realloc
980 (nssShutdownList.funcs,
981 (nssShutdownList.allocatedFuncs + NSS_SHUTDOWN_STEP)
982 *sizeof(struct NSSShutdownFuncPair));
984 PZ_Unlock(nssShutdownList.lock);
987 nssShutdownList.funcs = funcs;
988 nssShutdownList.allocatedFuncs += NSS_SHUTDOWN_STEP;
990 nssShutdownList.funcs[nssShutdownList.peakFuncs].func = sFunc;
991 nssShutdownList.funcs[nssShutdownList.peakFuncs].appData = appData;
992 nssShutdownList.peakFuncs++;
993 PZ_Unlock(nssShutdownList.lock);
998 * unregister a callback so it won't get called on shutdown.
1001 NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
1005 PZ_Lock(nssInitLock);
1006 if (!NSS_IsInitialized()) {
1007 PZ_Unlock(nssInitLock);
1008 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1011 PZ_Unlock(nssInitLock);
1013 PORT_Assert(nssShutdownList.lock);
1014 PZ_Lock(nssShutdownList.lock);
1015 i = nss_GetShutdownEntry(sFunc, appData);
1017 nssShutdownList.funcs[i].func = NULL;
1018 nssShutdownList.funcs[i].appData = NULL;
1020 PZ_Unlock(nssShutdownList.lock);
1023 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1030 * bring up and shutdown the shutdown list
1033 nss_InitShutdownList(void)
1035 if (nssShutdownList.lock != NULL) {
1038 nssShutdownList.lock = PZ_NewLock(nssILockOther);
1039 if (nssShutdownList.lock == NULL) {
1042 nssShutdownList.funcs = PORT_ZNewArray(struct NSSShutdownFuncPair,
1044 if (nssShutdownList.funcs == NULL) {
1045 PZ_DestroyLock(nssShutdownList.lock);
1046 nssShutdownList.lock = NULL;
1049 nssShutdownList.allocatedFuncs = NSS_SHUTDOWN_STEP;
1050 nssShutdownList.peakFuncs = 0;
1056 nss_ShutdownShutdownList(void)
1058 SECStatus rv = SECSuccess;
1061 /* call all the registerd functions first */
1062 for (i=0; i < nssShutdownList.peakFuncs; i++) {
1063 struct NSSShutdownFuncPair *funcPair = &nssShutdownList.funcs[i];
1064 if (funcPair->func) {
1065 if ((*funcPair->func)(funcPair->appData,NULL) != SECSuccess) {
1071 nssShutdownList.peakFuncs = 0;
1072 nssShutdownList.allocatedFuncs = 0;
1073 PORT_Free(nssShutdownList.funcs);
1074 nssShutdownList.funcs = NULL;
1075 if (nssShutdownList.lock) {
1076 PZ_DestroyLock(nssShutdownList.lock);
1078 nssShutdownList.lock = NULL;
1083 extern const NSSError NSS_ERROR_BUSY;
1088 SECStatus shutdownRV = SECSuccess;
1091 NSSInitContext *temp;
1093 rv = nss_ShutdownShutdownList();
1094 if (rv != SECSuccess) {
1095 shutdownRV = SECFailure;
1097 cert_DestroyLocks();
1099 OCSP_ShutdownGlobal();
1100 PKIX_Shutdown(plContext);
1102 status = STAN_Shutdown();
1103 cert_DestroySubjectKeyIDHashTable();
1104 pk11_SetInternalKeySlot(NULL);
1105 rv = SECMOD_Shutdown();
1106 if (rv != SECSuccess) {
1107 shutdownRV = SECFailure;
1111 * A thread's error stack is automatically destroyed when the thread
1112 * terminates, except for the primordial thread, whose error stack is
1113 * destroyed by PR_Cleanup. Since NSS is usually shut down by the
1114 * primordial thread and many NSS-based apps don't call PR_Cleanup,
1115 * we destroy the calling thread's error stack here.
1117 nss_DestroyErrorStack();
1118 nssArena_Shutdown();
1119 if (status == PR_FAILURE) {
1120 if (NSS_GetError() == NSS_ERROR_BUSY) {
1121 PORT_SetError(SEC_ERROR_BUSY);
1123 shutdownRV = SECFailure;
1125 nssIsInitted = PR_FALSE;
1126 temp = nssInitContextList;
1127 nssInitContextList = NULL;
1128 /* free the old list. This is necessary when we are called from
1129 * NSS_Shutdown(). */
1131 NSSInitContext *next = temp->next;
1143 PZ_Lock(nssInitLock);
1145 if (!nssIsInitted) {
1146 PZ_Unlock(nssInitLock);
1147 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1151 /* If one or more threads are in the middle of init, wait for them
1153 while (nssIsInInit) {
1154 PZ_WaitCondVar(nssInitCondition,PR_INTERVAL_NO_TIMEOUT);
1156 rv = nss_Shutdown();
1157 PZ_Unlock(nssInitLock);
1162 * remove the context from a list. return true if found, false if not
1165 nss_RemoveList(NSSInitContext *context) {
1166 NSSInitContext *this = nssInitContextList;
1167 NSSInitContext **last = &nssInitContextList;
1170 if (this == context) {
1183 * This form of shutdown is safe in the case where we may have multiple
1184 * entities using NSS in a single process. Each entity calls shutdown with
1185 * it's own context. The application (which doesn't get a context), calls
1186 * shutdown with NULL. Once all users have 'checked in' NSS will shutdown.
1187 * This is different than NSS_Shutdown, where calling it will shutdown NSS
1188 * irreguardless of who else may have NSS open.
1191 NSS_ShutdownContext(NSSInitContext *context)
1193 SECStatus rv = SECSuccess;
1195 PZ_Lock(nssInitLock);
1196 /* If one or more threads are in the middle of init, wait for them
1198 while (nssIsInInit) {
1199 PZ_WaitCondVar(nssInitCondition,PR_INTERVAL_NO_TIMEOUT);
1202 /* OK, we are the only thread now either initializing or shutting down */
1205 if (!nssIsInitted) {
1206 PZ_Unlock(nssInitLock);
1207 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1211 } else if (! nss_RemoveList(context)) {
1212 PZ_Unlock(nssInitLock);
1213 /* context was already freed or wasn't valid */
1214 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1217 if ((nssIsInitted == 0) && (nssInitContextList == NULL)) {
1218 rv = nss_Shutdown();
1221 /* NOTE: we don't try to free the nssInitLocks to prevent races against
1222 * the locks. There may be a thread, right now, waiting in NSS_Init for us
1223 * to free the lock below. If we delete the locks, bad things would happen
1225 PZ_Unlock(nssInitLock);
1231 NSS_IsInitialized(void)
1233 return (nssIsInitted) || (nssInitContextList != NULL);
1237 extern const char __nss_base_rcsid[];
1238 extern const char __nss_base_sccsid[];
1241 NSS_VersionCheck(const char *importedVersion)
1244 * This is the secret handshake algorithm.
1246 * This release has a simple version compatibility
1247 * check algorithm. This release is not backward
1248 * compatible with previous major releases. It is
1249 * not compatible with future major, minor, or
1250 * patch releases or builds.
1252 int vmajor = 0, vminor = 0, vpatch = 0, vbuild = 0;
1253 const char *ptr = importedVersion;
1254 volatile char c; /* force a reference that won't get optimized away */
1256 c = __nss_base_rcsid[0] + __nss_base_sccsid[0];
1258 while (isdigit(*ptr)) {
1259 vmajor = 10 * vmajor + *ptr - '0';
1264 while (isdigit(*ptr)) {
1265 vminor = 10 * vminor + *ptr - '0';
1270 while (isdigit(*ptr)) {
1271 vpatch = 10 * vpatch + *ptr - '0';
1276 while (isdigit(*ptr)) {
1277 vbuild = 10 * vbuild + *ptr - '0';
1284 if (vmajor != NSS_VMAJOR) {
1287 if (vmajor == NSS_VMAJOR && vminor > NSS_VMINOR) {
1290 if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR && vpatch > NSS_VPATCH) {
1293 if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR &&
1294 vpatch == NSS_VPATCH && vbuild > NSS_VBUILD) {
1297 /* Check dependent libraries */
1298 if (PR_VersionCheck(PR_VERSION) == PR_FALSE) {
1305 NSS_GetVersion(void)