bug 1398932 - add a preference for enabling the sqlite-backed NSS databases r?Cykesiopka,jcj
In the future,
bug 1377940 will make the sqlite-backed databases the default,
but until we're sure this will stick we want to be able to control this with a
Firefox-only change. The use of a preference to configure which format to use
will hopefully allow us to restore the old behavior quickly and relatively
safely if necessary. Note that doing this should be done with care; any changes
made in the sqlite databases after upgrade migration will not be reflected if
we need to go back to the old database format. Thus, user data (imported CAs,
client certificates, and keys) can be lost.
MozReview-Commit-ID: tkovdiCU9v
--- a/security/certverifier/NSSCertDBTrustDomain.cpp
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -14,21 +14,23 @@
#include "OCSPVerificationTrustDomain.h"
#include "PublicKeyPinningService.h"
#include "cert.h"
#include "certdb.h"
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/Move.h"
#include "mozilla/PodOperations.h"
+#include "mozilla/Preferences.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Unused.h"
#include "nsCRTGlue.h"
#include "nsNSSCertificate.h"
#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
#include "nss.h"
#include "pk11pub.h"
#include "pkix/Result.h"
#include "pkix/pkix.h"
#include "pkix/pkixnss.h"
#include "prerror.h"
#include "secerr.h"
@@ -1223,33 +1225,46 @@ NSSCertDBTrustDomain::NoteAuxiliaryExten
}
if (out) {
SECItem extensionDataItem = UnsafeMapInputToSECItem(extensionData);
out->reset(SECITEM_DupItem(&extensionDataItem));
}
}
SECStatus
-InitializeNSS(const char* dir, bool readOnly, bool loadPKCS11Modules)
+InitializeNSS(const nsACString& dir, bool readOnly, bool loadPKCS11Modules)
{
+ MOZ_ASSERT(NS_IsMainThread());
+
// The NSS_INIT_NOROOTINIT flag turns off the loading of the root certs
// module by NSS_Initialize because we will load it in InstallLoadableRoots
// later. It also allows us to work around a bug in the system NSS in
// Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
// "/usr/lib/nss/libnssckbi.so".
uint32_t flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
if (readOnly) {
flags |= NSS_INIT_READONLY;
}
if (!loadPKCS11Modules) {
flags |= NSS_INIT_NOMODDB;
}
+ bool useSQLDB = Preferences::GetBool("security.use_sqldb", false);
+ nsAutoCString dbTypeAndDirectory;
+ // Don't change any behavior if the user has specified an alternative database
+ // location with MOZPSM_NSSDBDIR_OVERRIDE.
+ const char* dbDirOverride = getenv("MOZPSM_NSSDBDIR_OVERRIDE");
+ if (useSQLDB && (!dbDirOverride || strlen(dbDirOverride) == 0)) {
+ dbTypeAndDirectory.Append("sql:");
+ }
+ dbTypeAndDirectory.Append(dir);
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
- ("InitializeNSS(%s, %d, %d)", dir, readOnly, loadPKCS11Modules));
- SECStatus srv = NSS_Initialize(dir, "", "", SECMOD_DB, flags);
+ ("InitializeNSS(%s, %d, %d)", dbTypeAndDirectory.get(), readOnly,
+ loadPKCS11Modules));
+ SECStatus srv = NSS_Initialize(dbTypeAndDirectory.get(), "", "",
+ SECMOD_DB, flags);
if (srv != SECSuccess) {
return srv;
}
if (!readOnly) {
UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
if (!slot) {
return SECFailure;
--- a/security/certverifier/NSSCertDBTrustDomain.h
+++ b/security/certverifier/NSSCertDBTrustDomain.h
@@ -32,17 +32,18 @@ enum class ValidityCheckingMode {
// * Never match: the OID is never considered equivalent to serverAuth
enum class NetscapeStepUpPolicy : uint32_t {
AlwaysMatch = 0,
MatchBefore23August2016 = 1,
MatchBefore23August2015 = 2,
NeverMatch = 3,
};
-SECStatus InitializeNSS(const char* dir, bool readOnly, bool loadPKCS11Modules);
+SECStatus InitializeNSS(const nsACString& dir, bool readOnly,
+ bool loadPKCS11Modules);
void DisableMD5();
/**
* Loads root certificates from a module.
*
* @param dir
* The path to the directory containing the NSS builtin roots module.
--- a/security/certverifier/moz.build
+++ b/security/certverifier/moz.build
@@ -78,16 +78,21 @@ if CONFIG['_MSC_VER']:
# constructor required
'-wd4619', # pragma warning: there is no warning 'warning'
'-wd4623', # default constructor could not be generated because a base
# class default constructor is inaccessible or deleted
'-wd4625', # copy constructor could not be generated because a base
# class copy constructor is inaccessible or deleted
'-wd4626', # assignment operator could not be generated because a base
# class assignment operator is inaccessible or deleted
+ '-wd4628', # digraphs not supported with -Ze (nsThreadUtils.h includes
+ # what would be the digraph "<:" in the expression
+ # "mozilla::EnableIf<::detail::...". Since we don't want it
+ # interpreted as a digraph anyway, we can disable the
+ # warning.)
'-wd4640', # construction of local static object is not thread-safe
'-wd4710', # 'function': function not inlined
'-wd4711', # function 'function' selected for inline expansion
'-wd4820', # 'bytes' bytes padding added after construct 'member_name'
]
# MSVC 2010's headers trigger these
CXXFLAGS += [
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1881,33 +1881,31 @@ InitializeNSSWithFallbacks(const nsACStr
if (nocertdb || profilePath.IsEmpty()) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("nocertdb mode or empty profile path -> NSS_NoDB_Init"));
SECStatus srv = NSS_NoDB_Init(nullptr);
return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
}
- const nsCString& profilePathCStr = PromiseFlatCString(profilePath);
// Try read/write mode. If we're in safeMode, we won't load PKCS#11 modules.
#ifndef ANDROID
PRErrorCode savedPRErrorCode1;
#endif // ifndef ANDROID
- SECStatus srv = ::mozilla::psm::InitializeNSS(profilePathCStr.get(), false,
- !safeMode);
+ SECStatus srv = ::mozilla::psm::InitializeNSS(profilePath, false, !safeMode);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r/w mode"));
return NS_OK;
}
#ifndef ANDROID
savedPRErrorCode1 = PR_GetError();
PRErrorCode savedPRErrorCode2;
#endif // ifndef ANDROID
// That failed. Try read-only mode.
- srv = ::mozilla::psm::InitializeNSS(profilePathCStr.get(), true, !safeMode);
+ srv = ::mozilla::psm::InitializeNSS(profilePath, true, !safeMode);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r-o mode"));
return NS_OK;
}
#ifndef ANDROID
savedPRErrorCode2 = PR_GetError();
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
@@ -1924,38 +1922,38 @@ InitializeNSSWithFallbacks(const nsACStr
savedPRErrorCode1 == SEC_ERROR_PKCS11_DEVICE_ERROR ||
savedPRErrorCode2 == SEC_ERROR_PKCS11_DEVICE_ERROR)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("attempting no-module db init"));
// It would make sense to initialize NSS in read-only mode here since this
// is just a test to see if the PKCS#11 module DB being in FIPS mode is the
// problem, but for some reason the combination of read-only and no-moddb
// flags causes NSS initialization to fail, so unfortunately we have to use
// read-write mode.
- srv = ::mozilla::psm::InitializeNSS(profilePathCStr.get(), false, false);
+ srv = ::mozilla::psm::InitializeNSS(profilePath, false, false);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("FIPS may be the problem"));
// Unload NSS so we can attempt to fix this situation for the user.
srv = NSS_Shutdown();
if (srv != SECSuccess) {
return NS_ERROR_FAILURE;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trying to rename module db"));
// If this fails non-catastrophically, we'll attempt to initialize NSS
// again in r/w then r-o mode (both of which will fail), and then we'll
// fall back to NSS_NoDB_Init, which is the behavior we want.
nsresult rv = AttemptToRenameBothPKCS11ModuleDBVersions(profilePath);
if (NS_FAILED(rv)) {
return rv;
}
- srv = ::mozilla::psm::InitializeNSS(profilePathCStr.get(), false, true);
+ srv = ::mozilla::psm::InitializeNSS(profilePath, false, true);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r/w mode"));
return NS_OK;
}
- srv = ::mozilla::psm::InitializeNSS(profilePathCStr.get(), true, true);
+ srv = ::mozilla::psm::InitializeNSS(profilePath, true, true);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r-o mode"));
return NS_OK;
}
}
}
#endif
--- a/security/manager/ssl/security-prefs.js
+++ b/security/manager/ssl/security-prefs.js
@@ -38,16 +38,24 @@ pref("security.ssl3.rsa_des_ede3_sha", f
pref("security.content.signature.root_hash",
"97:E8:BA:9C:F1:2F:B3:DE:53:CC:42:A4:E6:57:7E:D6:4D:F4:93:C2:47:B4:14:FE:A0:36:81:8D:38:23:56:0E");
pref("security.default_personal_cert", "Ask Every Time");
pref("security.remember_cert_checkbox_default_setting", true);
pref("security.ask_for_password", 0);
pref("security.password_lifetime", 30);
+// If true, use the modern sqlite-backed certificate and key databases in NSS.
+// If false, use the default format. Currently the default in NSS is the old
+// BerkeleyDB format, but this will change in bug 1377940.
+// Changing this requires a restart to take effect.
+// Note that the environment variable MOZPSM_NSSDBDIR_OVERRIDE can override both
+// the behavior of this preference and the NSS default.
+pref("security.use_sqldb", false);
+
// The supported values of this pref are:
// 0: disable detecting Family Safety mode and importing the root
// 1: only attempt to detect Family Safety mode (don't import the root)
// 2: detect Family Safety mode and import the root
// (This is only relevant to Windows 8.1)
pref("security.family_safety.mode", 2);
pref("security.enterprise_roots.enabled", false);
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_db_format_pref_new.js
@@ -0,0 +1,23 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Tests that if "security.use_sqldb" is set to true when PSM initializes,
+// we create the sqlite-backed certificate and key databases.
+
+function run_test() {
+ let profileDir = do_get_profile();
+ Services.prefs.setBoolPref("security.use_sqldb", true);
+ let certificateDBFile = profileDir.clone();
+ certificateDBFile.append("cert9.db");
+ ok(!certificateDBFile.exists(), "cert9.db should not exist beforehand");
+ let keyDBFile = profileDir.clone();
+ keyDBFile.append("key4.db");
+ ok(!keyDBFile.exists(), "key4.db should not exist beforehand");
+ // This should start PSM.
+ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+ ok(certificateDBFile.exists(), "cert9.db should exist in the profile");
+ ok(keyDBFile.exists(), "key4.db should exist in the profile");
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_db_format_pref_old.js
@@ -0,0 +1,24 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Tests that if "security.use_sqldb" is set to false when PSM initializes,
+// we create the system-default certificate and key databases, which currently
+// use the old BerkeleyDB format. This will change in bug 1377940.
+
+function run_test() {
+ let profileDir = do_get_profile();
+ Services.prefs.setBoolPref("security.use_sqldb", false);
+ let certificateDBFile = profileDir.clone();
+ certificateDBFile.append("cert8.db");
+ ok(!certificateDBFile.exists(), "cert8.db should not exist beforehand");
+ let keyDBFile = profileDir.clone();
+ keyDBFile.append("key3.db");
+ ok(!keyDBFile.exists(), "key3.db should not exist beforehand");
+ // This should start PSM.
+ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+ ok(certificateDBFile.exists(), "cert8.db should exist in the profile");
+ ok(keyDBFile.exists(), "key3.db should exist in the profile");
+}
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -68,16 +68,22 @@ run-sequentially = hardcoded ports
skip-if = toolkit == 'android'
[test_constructX509FromBase64.js]
[test_content_signing.js]
[test_ct.js]
# Requires hard-coded debug-only data
skip-if = !debug
run-sequentially = hardcoded ports
[test_datasignatureverifier.js]
+# Android always has and always will use the new format, so
+# these two tests don't apply.
+[test_db_format_pref_new.js]
+skip-if = toolkit == 'android'
+[test_db_format_pref_old.js]
+skip-if = toolkit == 'android'
[test_der.js]
[test_enterprise_roots.js]
skip-if = os != 'win' # tests a Windows-specific feature
[test_ev_certs.js]
tags = blocklist
run-sequentially = hardcoded ports
[test_forget_about_site_security_headers.js]
skip-if = toolkit == 'android'