/* * NSS utility functions * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. * # $Id$ */ #include #include "seccomon.h" #include "prinit.h" #include "prprf.h" #include "prmem.h" #include "cert.h" #include "key.h" #include "ssl.h" #include "sslproto.h" #include "secmod.h" #include "secmodi.h" #include "nss.h" #include "secrng.h" #include "cdbhdl.h" /* ??? */ #include "pk11func.h" #ifdef macintosh #define PATH_SEPARATOR ":" #define SECMOD_DB "Security Modules" #define CERT_DB_FMT "%sCertificates%s" #define KEY_DB_FMT "%sKey Database%s" #else #define PATH_SEPARATOR "/" #define SECMOD_DB "secmod.db" #define CERT_DB_FMT "%scert%s.db" #define KEY_DB_FMT "%skey%s.db" #endif static char *secmodname = NULL; static char * nss_certdb_name_cb(void *arg, int dbVersion) { const char *configdir = (const char *)arg; const char *dbver; switch (dbVersion) { case 7: dbver = "7"; break; case 6: dbver = "6"; break; case 5: dbver = "5"; break; case 4: default: dbver = ""; break; } return PR_smprintf(CERT_DB_FMT, configdir, dbver); } static char * nss_keydb_name_cb(void *arg, int dbVersion) { const char *configdir = (const char *)arg; const char *dbver; switch (dbVersion) { case 3: dbver = "3"; break; case 1: dbver = "1"; break; case 2: default: dbver = ""; break; } return PR_smprintf(KEY_DB_FMT, configdir, dbver); } static SECStatus nss_OpenCertDB(const char * configdir, const char *prefix, PRBool readOnly) { CERTCertDBHandle *certdb; SECStatus status; char * name = NULL; certdb = CERT_GetDefaultCertDB(); if (certdb) return SECSuccess; /* idempotency */ name = PR_smprintf("%s" PATH_SEPARATOR "%s",configdir,prefix); if (name == NULL) goto loser; certdb = (CERTCertDBHandle*)PORT_ZAlloc(sizeof(CERTCertDBHandle)); if (certdb == NULL) goto loser; status = CERT_OpenCertDB(certdb, readOnly, nss_certdb_name_cb, (void *)name); if (status == SECSuccess) CERT_SetDefaultCertDB(certdb); else { PR_Free(certdb); loser: status = SECFailure; } if (name) PORT_Free(name); return status; } static SECStatus nss_OpenKeyDB(const char * configdir, const char *prefix, PRBool readOnly) { SECKEYKeyDBHandle *keydb; char * name = NULL; keydb = SECKEY_GetDefaultKeyDB(); if (keydb) return SECSuccess; name = PR_smprintf("%s" PATH_SEPARATOR "%s",configdir,prefix); if (name == NULL) return SECFailure; keydb = SECKEY_OpenKeyDB(readOnly, nss_keydb_name_cb, (void *)name); if (keydb == NULL) return SECFailure; SECKEY_SetDefaultKeyDB(keydb); PORT_Free(name); return SECSuccess; } static SECStatus nss_OpenSecModDB(const char * configdir,const char *dbname) { /* XXX * For idempotency, this should check to see if the secmodDB is alredy open * but no function exists to make that determination. */ if (secmodname) return SECSuccess; secmodname = PR_smprintf("%s" PATH_SEPARATOR "%s", configdir,dbname); if (secmodname == NULL) return SECFailure; SECMOD_init(secmodname); return SECSuccess; } static CERTCertDBHandle certhandle = { 0 }; static PRBool isInitialized = PR_FALSE; static SECStatus nss_OpenVolatileCertDB() { SECStatus rv = SECSuccess; /* now we want to verify the signature */ /* Initialize the cert code */ rv = CERT_OpenVolatileCertDB(&certhandle); if (rv != SECSuccess) { return rv; } CERT_SetDefaultCertDB(&certhandle); return rv; } static SECStatus nss_OpenVolatileSecModDB() { SECStatus rv = SECSuccess; SECMODModule *module; PK11_InitSlotLists(); module = SECMOD_NewInternal(); if (module == NULL) { return SECFailure; } rv = SECMOD_LoadModule(module); if (rv != SECSuccess) { return rv; } SECMOD_SetInternalModule(module); return rv; } /* * OK there are now lots of options here, lets go through them all: * * configdir - base directory where all the cert, key, and module datbases live. * certPrefix - prefix added to the beginning of the cert database example: " * "https-server1-" * keyPrefix - prefix added to the beginning of the key database example: " * "https-server1-" * secmodName - name of the security module database (usually "secmod.db"). * readOnly - Boolean: true if the databases are to be openned read only. * nocertdb - Don't open the cert DB and key DB's, just initialize the * Volatile certdb. * nomoddb - Don't open the security module DB, just initialize the * PKCS #11 module. * forceOpen - Continue to force initializations even if the databases cannot * be opened. */ static SECStatus nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix, const char *secmodName, PRBool readOnly, PRBool noCertDB, PRBool noModDB, PRBool forceOpen) { SECStatus status; SECStatus rv = SECFailure; if( isInitialized ) { return SECSuccess; } status = RNG_RNGInit(); /* initialize random number generator */ if (status != SECSuccess) goto loser; RNG_SystemInfoForRNG(); if (noCertDB) { status = nss_OpenVolatileCertDB(); if (status != SECSuccess) { goto loser; } } else { status = nss_OpenCertDB(configdir, certPrefix, readOnly); if (status != SECSuccess) { if (!forceOpen) goto loser; status = nss_OpenVolatileCertDB(); if (status != SECSuccess) { goto loser; } } status = nss_OpenKeyDB(configdir, keyPrefix, readOnly); if (status != SECSuccess) { if (!forceOpen) goto loser; } } if (noModDB) { status = nss_OpenVolatileSecModDB(); if (status != SECSuccess) { goto loser; } } else { status = nss_OpenSecModDB(configdir, secmodName); if (status != SECSuccess) { if (!forceOpen) goto loser; status = nss_OpenVolatileSecModDB(); if (status != SECSuccess) { goto loser; } } } rv = SECSuccess; isInitialized = PR_TRUE; loser: if (rv != SECSuccess) NSS_Shutdown(); return rv; } SECStatus NSS_Init(const char *configdir) { return nss_Init(configdir, "", "", SECMOD_DB, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE); } SECStatus NSS_InitReadWrite(const char *configdir) { return nss_Init(configdir, "", "", SECMOD_DB, PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE); } /* * OK there are now lots of options here, lets go through them all: * * configdir - base directory where all the cert, key, and module datbases live. * certPrefix - prefix added to the beginning of the cert database example: " * "https-server1-" * keyPrefix - prefix added to the beginning of the key database example: " * "https-server1-" * secmodName - name of the security module database (usually "secmod.db"). * flags - change the open options of NSS_Initialize as follows: * NSS_INIT_READONLY - Open the databases read only. * NSS_INIT_NOCERTDB - Don't open the cert DB and key DB's, just * initialize the volatile certdb. * NSS_INIT_NOMODDB - Don't open the security module DB, just * initialize the PKCS #11 module. * NSS_INIT_FORCEOPEN - Continue to force initializations even if the * databases cannot be opened. */ SECStatus NSS_Initialize(const char *configdir, const char *certPrefix, const char *keyPrefix, const char *secmodName, PRUint32 flags) { return nss_Init(configdir, certPrefix, keyPrefix, secmodName, ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY), ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB), ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB), ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN)); } /* * initialize NSS without a creating cert db's, key db's, or secmod db's. */ SECStatus NSS_NoDB_Init(const char * configdir) { SECStatus rv = SECSuccess; if( isInitialized ) { return SECSuccess; } rv = RNG_RNGInit(); if (rv != SECSuccess) { return rv; } RNG_SystemInfoForRNG(); rv = nss_OpenVolatileCertDB(); if (rv != SECSuccess) { return rv; } rv = nss_OpenVolatileSecModDB(); isInitialized = PR_TRUE; return rv; } void NSS_Shutdown(void) { CERTCertDBHandle *certHandle; SECKEYKeyDBHandle *keyHandle; SECMOD_Shutdown(); PR_FREEIF(secmodname); certHandle = CERT_GetDefaultCertDB(); if (certHandle) CERT_ClosePermCertDB(certHandle); CERT_SetDefaultCertDB(NULL); keyHandle = SECKEY_GetDefaultKeyDB(); if (keyHandle) SECKEY_CloseKeyDB(keyHandle); SECKEY_SetDefaultKeyDB(NULL); isInitialized = PR_FALSE; } extern const char __nss_base_rcsid[]; extern const char __nss_base_sccsid[]; PRBool NSS_VersionCheck(const char *importedVersion) { /* * This is the secret handshake algorithm. * * This release has a simple version compatibility * check algorithm. This release is not backward * compatible with previous major releases. It is * not compatible with future major, minor, or * patch releases. */ int vmajor = 0, vminor = 0, vpatch = 0; const char *ptr = importedVersion; volatile char c; /* force a reference that won't get optimized away */ c = __nss_base_rcsid[0] + __nss_base_sccsid[0]; while (isdigit(*ptr)) { vmajor = 10 * vmajor + *ptr - '0'; ptr++; } if (*ptr == '.') { ptr++; while (isdigit(*ptr)) { vminor = 10 * vminor + *ptr - '0'; ptr++; } if (*ptr == '.') { ptr++; while (isdigit(*ptr)) { vpatch = 10 * vpatch + *ptr - '0'; ptr++; } } } if (vmajor != NSS_VMAJOR) { return PR_FALSE; } if (vmajor == NSS_VMAJOR && vminor > NSS_VMINOR) { return PR_FALSE; } if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR && vpatch > NSS_VPATCH) { return PR_FALSE; } /* Check dependent libraries */ if (PR_VersionCheck(PR_VERSION) == PR_FALSE) { return PR_FALSE; } return PR_TRUE; }