bug 783994 - add preference for and enable sqlite-backed NSS databases r?Cykesiopka,jcj draft
authorDavid Keeler <dkeeler@mozilla.com>
Wed, 06 Sep 2017 14:31:27 -0700
changeset 660892 60a6a4d9cd60448a507ad5cfe1e965570bf36b51
parent 660738 37b95547f0d27565452136d16b2df2857be840f6
child 730420 fe1f77ced3a1a99815d284e6542166090c8c5616
push id78596
push userbmo:dkeeler@mozilla.com
push dateThu, 07 Sep 2017 20:14:50 +0000
reviewersCykesiopka, jcj
bugs783994, 1377940
milestone57.0a1
bug 783994 - add preference for and enable 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 make this 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: E4ieLCo1e13
security/certverifier/NSSCertDBTrustDomain.cpp
security/certverifier/NSSCertDBTrustDomain.h
security/manager/ssl/nsNSSComponent.cpp
security/manager/ssl/security-prefs.js
--- 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.sqldb.enabled", 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/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,21 @@ 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 old BerkeleyDB format. Changing this requires a restart
+// to take effect.
+pref("security.sqldb.enabled", true);
+
 // 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);