Bug 891066, Part 3: Move more initialization of NSS to security/certverifier, r=keeler
authorBrian Smith <brian@briansmith.org>
Mon, 20 Jan 2014 22:10:33 -0800
changeset 175498 95f848f55c90176dd061a54c6d8d9855dbfed258
parent 175497 2dc56ee0e0e51a35ac0573b57451ad79361e6d0d
child 175499 25ee011845e78981970578064ee408e6d11dd8dc
push idunknown
push userunknown
push dateunknown
reviewerskeeler
bugs891066
milestone29.0a1
Bug 891066, Part 3: Move more initialization of NSS to security/certverifier, r=keeler
security/certverifier/CertVerifier.cpp
security/certverifier/CertVerifier.h
security/certverifier/NSSCertDBTrustDomain.cpp
security/certverifier/NSSCertDBTrustDomain.h
security/certverifier/moz.build
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsNSSComponent.h
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "CertVerifier.h"
 #include "ExtendedValidation.h"
 #include "ScopedNSSTypes.h"
 #include "cert.h"
--- a/security/certverifier/CertVerifier.h
+++ b/security/certverifier/CertVerifier.h
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_psm__CertVerifier_h
 #define mozilla_psm__CertVerifier_h
 
 #include "certt.h"
new file mode 100644
--- /dev/null
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "NSSCertDBTrustDomain.h"
+
+#include <stdint.h>
+
+#include "insanity/ScopedPtr.h"
+#include "cert.h"
+#include "nss.h"
+#include "ocsp.h"
+#include "prerror.h"
+#include "prprf.h"
+#include "secerr.h"
+#include "secmod.h"
+
+using namespace insanity::pkix;
+
+namespace mozilla { namespace psm {
+
+const char BUILTIN_ROOTS_MODULE_DEFAULT_NAME[] = "Builtin Roots Module";
+
+namespace {
+
+inline void PORT_Free_string(char* str) { PORT_Free(str); }
+
+typedef ScopedPtr<SECMODModule, SECMOD_DestroyModule> ScopedSECMODModule;
+
+static char*
+nss_addEscape(const char* string, char quote)
+{
+    char* newString = 0;
+    int escapes = 0, size = 0;
+    const char* src;
+    char* dest;
+
+    for (src=string; *src ; src++) {
+        if ((*src == quote) || (*src == '\\')) {
+          escapes++;
+        }
+        size++;
+    }
+
+    newString = (char*)PORT_ZAlloc(escapes+size+1);
+    if (!newString) {
+        return nullptr;
+    }
+
+    for (src=string, dest=newString; *src; src++,dest++) {
+        if ((*src == quote) || (*src == '\\')) {
+            *dest++ = '\\';
+        }
+        *dest = *src;
+    }
+
+    return newString;
+}
+
+} // unnamed namespace
+
+SECStatus
+InitializeNSS(const char* dir, bool readOnly)
+{
+  // 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;
+  }
+  return ::NSS_Initialize(dir, "", "", SECMOD_DB, flags);
+}
+
+SECStatus
+LoadLoadableRoots(/*optional*/ const char* dir, const char* modNameUTF8)
+{
+  PR_ASSERT(modNameUTF8);
+
+  if (!modNameUTF8) {
+    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+    return SECFailure;
+  }
+
+  ScopedPtr<char, PR_FreeLibraryName> fullLibraryPath(
+    PR_GetLibraryName(dir, "nssckbi"));
+  if (!fullLibraryPath) {
+    return SECFailure;
+  }
+
+  ScopedPtr<char, PORT_Free_string> escaped_fullLibraryPath(
+    nss_addEscape(fullLibraryPath.get(), '\"'));
+  if (!escaped_fullLibraryPath) {
+    return SECFailure;
+  }
+
+  // If a module exists with the same name, delete it.
+  int modType;
+  SECMOD_DeleteModule(modNameUTF8, &modType);
+
+  ScopedPtr<char, PR_smprintf_free> pkcs11ModuleSpec(
+    PR_smprintf("name=\"%s\" library=\"%s\"", modNameUTF8,
+                escaped_fullLibraryPath.get()));
+  if (!pkcs11ModuleSpec) {
+    return SECFailure;
+  }
+
+  ScopedSECMODModule rootsModule(SECMOD_LoadUserModule(pkcs11ModuleSpec.get(),
+                                                       nullptr, false));
+  if (!rootsModule) {
+    return SECFailure;
+  }
+
+  if (!rootsModule->loaded) {
+    PR_SetError(PR_INVALID_STATE_ERROR, 0);
+    return SECFailure;
+  }
+
+  return SECSuccess;
+}
+
+void
+UnloadLoadableRoots(const char* modNameUTF8)
+{
+  PR_ASSERT(modNameUTF8);
+  ScopedSECMODModule rootsModule(SECMOD_FindModule(modNameUTF8));
+
+  if (rootsModule) {
+    SECMOD_UnloadUserModule(rootsModule.get());
+  }
+}
+
+void
+SetClassicOCSPBehavior(CertVerifier::ocsp_download_config enabled,
+                       CertVerifier::ocsp_strict_config strict,
+                       CertVerifier::ocsp_get_config get)
+{
+  CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
+  if (enabled == CertVerifier::ocsp_off) {
+    CERT_DisableOCSPChecking(CERT_GetDefaultCertDB());
+  } else {
+    CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
+  }
+
+  SEC_OcspFailureMode failureMode = strict == CertVerifier::ocsp_strict
+                                  ? ocspMode_FailureIsVerificationFailure
+                                  : ocspMode_FailureIsNotAVerificationFailure;
+  (void) CERT_SetOCSPFailureMode(failureMode);
+
+  CERT_ForcePostMethodForOCSP(get != CertVerifier::ocsp_get_enabled);
+
+  int OCSPTimeoutSeconds = 3;
+  if (strict == CertVerifier::ocsp_strict) {
+    OCSPTimeoutSeconds = 10;
+  }
+  CERT_SetOCSPTimeout(OCSPTimeoutSeconds);
+}
+
+} } // namespace mozilla::psm
new file mode 100644
--- /dev/null
+++ b/security/certverifier/NSSCertDBTrustDomain.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_psm__NSSCertDBTrustDomain_h
+#define mozilla_psm__NSSCertDBTrustDomain_h
+
+#include "secmodt.h"
+#include "CertVerifier.h"
+
+namespace mozilla { namespace psm {
+
+SECStatus InitializeNSS(const char* dir, bool readOnly);
+
+extern const char BUILTIN_ROOTS_MODULE_DEFAULT_NAME[];
+
+// The dir parameter is the path to the directory containing the NSS builtin
+// roots module. Usually this is the same as the path to the other NSS shared
+// libraries. If it is null then the (library) path will be searched.
+//
+// The modNameUTF8 parameter should usually be
+// BUILTIN_ROOTS_MODULE_DEFAULT_NAME.
+SECStatus LoadLoadableRoots(/*optional*/ const char* dir,
+                            const char* modNameUTF8);
+
+void UnloadLoadableRoots(const char* modNameUTF8);
+
+void
+SetClassicOCSPBehavior(CertVerifier::ocsp_download_config enabled,
+                       CertVerifier::ocsp_strict_config strict,
+                       CertVerifier::ocsp_get_config get);
+
+} } // namespace mozilla::psm
+
+#endif // mozilla_psm__NSSCertDBTrustDomain_h
--- a/security/certverifier/moz.build
+++ b/security/certverifier/moz.build
@@ -1,16 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 UNIFIED_SOURCES += [
     'CertVerifier.cpp',
+    'NSSCertDBTrustDomain.cpp',
 ]
 
 if not CONFIG['NSS_NO_LIBPKIX']:
     UNIFIED_SOURCES += [
         'ExtendedValidation.cpp',
     ]
 
 LOCAL_INCLUDES += [
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -6,16 +6,17 @@
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG 1
 #endif
 
 #include "nsNSSComponent.h"
 
 #include "ExtendedValidation.h"
+#include "NSSCertDBTrustDomain.h"
 #include "mozilla/Telemetry.h"
 #include "nsCertVerificationThread.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsICertOverrideService.h"
 #include "mozilla/Preferences.h"
 #include "nsThreadUtils.h"
@@ -201,16 +202,46 @@ bool EnsureNSSInitialized(EnsureNSSOpera
     }
 
   default:
     NS_ASSERTION(false, "Bad operator to EnsureNSSInitialized");
     return false;
   }
 }
 
+static void
+SetClassicOCSPBehaviorFromPrefs(/*out*/ CertVerifier::ocsp_download_config* odc,
+                                /*out*/ CertVerifier::ocsp_strict_config* osc,
+                                /*out*/ CertVerifier::ocsp_get_config* ogc,
+                                const MutexAutoLock& /*proofOfLock*/)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(odc);
+  MOZ_ASSERT(osc);
+  MOZ_ASSERT(ogc);
+
+  // 0 = disabled, otherwise enabled
+  *odc = Preferences::GetInt("security.OCSP.enabled", 1)
+       ? CertVerifier::ocsp_on
+       : CertVerifier::ocsp_off;
+
+  *osc = Preferences::GetBool("security.OCSP.require", false)
+       ? CertVerifier::ocsp_strict
+       : CertVerifier::ocsp_relaxed;
+
+  // XXX: Always use POST for OCSP; see bug 871954 for undoing this.
+  *ogc = Preferences::GetBool("security.OCSP.GET.enabled", false)
+       ? CertVerifier::ocsp_get_enabled
+       : CertVerifier::ocsp_get_disabled;
+
+  SetClassicOCSPBehavior(*odc, *osc, *ogc);
+
+  SSL_ClearSessionCache();
+}
+
 nsNSSComponent::nsNSSComponent()
   :mutex("nsNSSComponent.mutex"),
    mNSSInitialized(false),
 #ifndef MOZ_DISABLE_CRYPTOLEGACY
    mThreadList(nullptr),
 #endif
    mCertVerificationThread(nullptr)
 {
@@ -527,48 +558,18 @@ nsNSSComponent::ShutdownSmartCardThread(
 void
 nsNSSComponent::ShutdownSmartCardThreads()
 {
   delete mThreadList;
   mThreadList = nullptr;
 }
 #endif // MOZ_DISABLE_CRYPTOLEGACY
 
-static char*
-nss_addEscape(const char* string, char quote)
-{
-    char* newString = 0;
-    int escapes = 0, size = 0;
-    const char* src;
-    char* dest;
-
-    for (src=string; *src ; src++) {
-        if ((*src == quote) || (*src == '\\')) {
-          escapes++;
-        }
-        size++;
-    }
-
-    newString = (char*)PORT_ZAlloc(escapes+size+1);
-    if (!newString) {
-        return nullptr;
-    }
-
-    for (src=string, dest=newString; *src; src++,dest++) {
-        if ((*src == quote) || (*src == '\\')) {
-            *dest++ = '\\';
-        }
-        *dest = *src;
-    }
-
-    return newString;
-}
-
 void
-nsNSSComponent::InstallLoadableRoots()
+nsNSSComponent::LoadLoadableRoots()
 {
   nsNSSShutDownPreventionLock locker;
   SECMODModule* RootsModule = nullptr;
 
   // In the past we used SECMOD_AddNewModule to load our module containing
   // root CA certificates. This caused problems, refer to bug 176501.
   // On startup, we fix our database and clean any stored module reference,
   // and will use SECMOD_LoadUserModule to temporarily load it
@@ -633,25 +634,20 @@ nsNSSComponent::InstallLoadableRoots()
     NS_XPCOM_CURRENT_PROCESS_DIR,
     NS_GRE_DIR,
     0 // This special value means:
       //   search for ckbi in the directories on the shared
       //   library/DLL search path
   };
 
   for (size_t il = 0; il < sizeof(possible_ckbi_locations)/sizeof(const char*); ++il) {
-    nsCOMPtr<nsIFile> mozFile;
-    char* fullLibraryPath = nullptr;
+    nsAutoCString libDir;
 
-    if (!possible_ckbi_locations[il])
-    {
-      fullLibraryPath = PR_GetLibraryName(nullptr, "nssckbi");
-    }
-    else
-    {
+    if (possible_ckbi_locations[il]) {
+      nsCOMPtr<nsIFile> mozFile;
       if (possible_ckbi_locations[il] == nss_lib) {
         // Get the location of the nss3 library.
         char* nss_path = PR_GetLibraryFilePathname(DLL_PREFIX "nss3" DLL_SUFFIX,
                                                    (PRFuncPtr) NSS_Initialize);
         if (!nss_path) {
           continue;
         }
         // Get the directory containing the nss3 library.
@@ -671,79 +667,40 @@ nsNSSComponent::InstallLoadableRoots()
                                NS_GET_IID(nsIFile),
                                getter_AddRefs(mozFile));
       }
 
       if (!mozFile) {
         continue;
       }
 
-      nsAutoCString processDir;
-      mozFile->GetNativePath(processDir);
-      fullLibraryPath = PR_GetLibraryName(processDir.get(), "nssckbi");
-    }
-
-    if (!fullLibraryPath) {
-      continue;
-    }
-
-    char* escaped_fullLibraryPath = nss_addEscape(fullLibraryPath, '\"');
-    if (!escaped_fullLibraryPath) {
-      PR_FreeLibraryName(fullLibraryPath); // allocated by NSPR
-      continue;
+      if (NS_FAILED(mozFile->GetNativePath(libDir))) {
+        continue;
+      }
     }
 
-    // If a module exists with the same name, delete it.
     NS_ConvertUTF16toUTF8 modNameUTF8(modName);
-    int modType;
-    SECMOD_DeleteModule(const_cast<char*>(modNameUTF8.get()), &modType);
-
-    nsCString pkcs11moduleSpec;
-    pkcs11moduleSpec.Append(NS_LITERAL_CSTRING("name=\""));
-    pkcs11moduleSpec.Append(modNameUTF8.get());
-    pkcs11moduleSpec.Append(NS_LITERAL_CSTRING("\" library=\""));
-    pkcs11moduleSpec.Append(escaped_fullLibraryPath);
-    pkcs11moduleSpec.Append(NS_LITERAL_CSTRING("\""));
-
-    PR_FreeLibraryName(fullLibraryPath); // allocated by NSPR
-    PORT_Free(escaped_fullLibraryPath);
-
-    RootsModule =
-      SECMOD_LoadUserModule(const_cast<char*>(pkcs11moduleSpec.get()),
-                            nullptr, // no parent
-                            false); // do not recurse
-
-    if (RootsModule) {
-      bool found = (RootsModule->loaded);
-
-      SECMOD_DestroyModule(RootsModule);
-      RootsModule = nullptr;
-
-      if (found) {
-        break;
-      }
+    if (mozilla::psm::LoadLoadableRoots(
+            libDir.Length() > 0 ? libDir.get() : nullptr,
+            modNameUTF8.get()) == SECSuccess) {
+      break;
     }
   }
 }
 
 void
 nsNSSComponent::UnloadLoadableRoots()
 {
   nsresult rv;
   nsAutoString modName;
   rv = GetPIPNSSBundleString("RootCertModuleName", modName);
   if (NS_FAILED(rv)) return;
 
   NS_ConvertUTF16toUTF8 modNameUTF8(modName);
-  SECMODModule* RootsModule = SECMOD_FindModule(modNameUTF8.get());
-
-  if (RootsModule) {
-    SECMOD_UnloadUserModule(RootsModule);
-    SECMOD_DestroyModule(RootsModule);
-  }
+  ::mozilla::psm::UnloadLoadableRoots(modNameUTF8.get());
 }
 
 nsresult
 nsNSSComponent::ConfigureInternalPKCS11Token()
 {
   nsNSSShutDownPreventionLock locker;
   nsAutoString manufacturerID;
   nsAutoString libraryDescription;
@@ -889,29 +846,16 @@ static const CipherPref sCipherPrefs[] =
  { "security.ssl3.dhe_dss_camellia_128_sha",
    TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, false },
  { "security.ssl3.rsa_seed_sha",
    TLS_RSA_WITH_SEED_CBC_SHA, false },
 
  { nullptr, 0 } // end marker
 };
 
-static void
-setNonPkixOcspEnabled(int32_t ocspEnabled)
-{
-  // Note: this preference is numeric vs boolean because previously we
-  // supported more than two options.
-  CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
-  if (!ocspEnabled) {
-    CERT_DisableOCSPChecking(CERT_GetDefaultCertDB());
-  } else {
-    CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
-  }
-}
-
 static const int32_t OCSP_ENABLED_DEFAULT = 1;
 static const bool REQUIRE_SAFE_NEGOTIATION_DEFAULT = false;
 static const bool ALLOW_UNRESTRICTED_RENEGO_DEFAULT = false;
 static const bool FALSE_START_ENABLED_DEFAULT = true;
 static const bool NPN_ENABLED_DEFAULT = true;
 static const bool ALPN_ENABLED_DEFAULT = false;
 
 namespace {
@@ -988,20 +932,19 @@ CipherSuiteChangeObserver::Observe(nsISu
     }
   }
   return NS_OK;
 }
 
 } // anonymous namespace
 
 // Caller must hold a lock on nsNSSComponent::mutex when calling this function
-void nsNSSComponent::setValidationOptions(bool isInitialSetting)
+void nsNSSComponent::setValidationOptions(bool isInitialSetting,
+                                          const MutexAutoLock& lock)
 {
-  nsNSSShutDownPreventionLock locker;
-
   bool crlDownloading = Preferences::GetBool("security.CRL_download.enabled",
                                              false);
 
   // This preference controls whether we do OCSP fetching and does not affect
   // OCSP stapling.
   // 0 = disabled, 1 = enabled
   int32_t ocspEnabled = Preferences::GetInt("security.OCSP.enabled",
                                             OCSP_ENABLED_DEFAULT);
@@ -1019,53 +962,38 @@ void nsNSSComponent::setValidationOption
   bool aiaDownloadEnabled = Preferences::GetBool("security.missing_cert_download.enabled",
                                                  false);
 
   bool ocspStaplingEnabled = Preferences::GetBool("security.ssl.enable_ocsp_stapling",
                                                   true);
   PublicSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);
   PrivateSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);
 
-  setNonPkixOcspEnabled(ocspEnabled);
-
-  CERT_SetOCSPFailureMode( ocspRequired ?
-                           ocspMode_FailureIsVerificationFailure
-                           : ocspMode_FailureIsNotAVerificationFailure);
-
-  int OCSPTimeoutSeconds = 3;
-  if (ocspRequired) {
-    OCSPTimeoutSeconds = 10;
-  }
-  CERT_SetOCSPTimeout(OCSPTimeoutSeconds);
-
-  // XXX: Always use POST for OCSP; see bug 871954 for undoing this.
-  bool ocspGetEnabled = Preferences::GetBool("security.OCSP.GET.enabled", false);
-  CERT_ForcePostMethodForOCSP(!ocspGetEnabled);
-
   CertVerifier::implementation_config certVerifierImplementation
     = CertVerifier::classic;
 
 #ifndef NSS_NO_LIBPKIX
   if (Preferences::GetBool("security.use_libpkix_verification", false)) {
     certVerifierImplementation = CertVerifier::libpkix;
   }
 #endif
 
+  CertVerifier::ocsp_download_config odc;
+  CertVerifier::ocsp_strict_config osc;
+  CertVerifier::ocsp_get_config ogc;
+
+  SetClassicOCSPBehaviorFromPrefs(&odc, &osc, &ogc, lock);
   mDefaultCertVerifier = new SharedCertVerifier(
       certVerifierImplementation,
       aiaDownloadEnabled ?
         CertVerifier::missing_cert_download_on : CertVerifier::missing_cert_download_off,
       crlDownloading ?
         CertVerifier::crl_download_allowed : CertVerifier::crl_local_only,
-      ocspEnabled ?
-        CertVerifier::ocsp_on : CertVerifier::ocsp_off,
-      ocspRequired ?
-        CertVerifier::ocsp_strict : CertVerifier::ocsp_relaxed,
-      ocspGetEnabled ?
-        CertVerifier::ocsp_get_enabled : CertVerifier::ocsp_get_disabled);
+      odc, osc, ogc);
+
 }
 
 // Enable the TLS versions given in the prefs, defaulting to SSL 3.0 (min
 // version) and TLS 1.2 (max version) when the prefs aren't set or set to
 // invalid values.
 nsresult
 nsNSSComponent::setEnabledTLSVersions()
 {
@@ -1106,25 +1034,25 @@ nsNSSComponent::SkipOcsp()
 
   SECStatus rv = CERT_DisableOCSPChecking(certdb);
   return (rv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsNSSComponent::SkipOcspOff()
 {
-  nsNSSShutDownPreventionLock locker;
-  // 0 = disabled, 1 = enabled
-  int32_t ocspEnabled = Preferences::GetInt("security.OCSP.enabled",
-                                            OCSP_ENABLED_DEFAULT);
+  MutexAutoLock lock(mutex);
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mNSSInitialized);
+  NS_ENSURE_TRUE(mNSSInitialized, NS_ERROR_NOT_INITIALIZED);
 
-  setNonPkixOcspEnabled(ocspEnabled);
-
-  if (ocspEnabled)
-    SSL_ClearSessionCache();
+  CertVerifier::ocsp_download_config odc; // ignored
+  CertVerifier::ocsp_strict_config osc; // ignored
+  CertVerifier::ocsp_get_config ogc; // ignored
+  SetClassicOCSPBehaviorFromPrefs(&odc, &osc, &ogc, lock);
 
   return NS_OK;
 }
 
 nsresult
 nsNSSComponent::InitializeNSS()
 {
   // Can be called both during init and profile change.
@@ -1195,33 +1123,22 @@ nsNSSComponent::InitializeNSS()
     // The call to ConfigureInternalPKCS11Token needs to be done before NSS is initialized,
     // but affects only static data.
     // If we could assume i18n will not change between profiles, one call per application
     // run were sufficient. As I can't predict what happens in the future, let's repeat
     // this call for every re-init of NSS.
 
     ConfigureInternalPKCS11Token();
 
-    // 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 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
-    SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
-                                         SECMOD_DB, init_flags);
-
+    SECStatus init_rv = ::mozilla::psm::InitializeNSS(profileStr.get(), false);
     if (init_rv != SECSuccess) {
       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
 
       // try to init r/o
-      init_flags |= NSS_INIT_READONLY;
-      init_rv = ::NSS_Initialize(profileStr.get(), "", "",
-                                 SECMOD_DB, init_flags);
-
+      init_rv = ::mozilla::psm::InitializeNSS(profileStr.get(), true);
       if (init_rv != SECSuccess) {
         PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init in r/o either\n"));
 
         init_rv = NSS_NoDB_Init(profileStr.get());
         if (init_rv != SECSuccess) {
           nsPSMInitPanic::SetPanic();
           return NS_ERROR_NOT_AVAILABLE;
         }
@@ -1245,16 +1162,17 @@ nsNSSComponent::InitializeNSS()
 
     rv = setEnabledTLSVersions();
     if (NS_FAILED(rv)) {
       nsPSMInitPanic::SetPanic();
       return NS_ERROR_UNEXPECTED;
     }
 
     DisableMD5();
+    LoadLoadableRoots();
 
     SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, true);
 
     bool requireSafeNegotiation =
       Preferences::GetBool("security.ssl.require_safe_negotiation",
                            REQUIRE_SAFE_NEGOTIATION_DEFAULT);
     SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation);
 
@@ -1282,23 +1200,21 @@ nsNSSComponent::InitializeNSS()
                                               ALPN_ENABLED_DEFAULT));
 
     if (NS_FAILED(InitializeCipherSuite())) {
       PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to initialize cipher suite settings\n"));
       return NS_ERROR_FAILURE;
     }
 
     // dynamic options from prefs
-    setValidationOptions(true);
+    setValidationOptions(true, lock);
 
     mHttpForNSS.initTable();
     mHttpForNSS.registerHttpClient();
 
-    InstallLoadableRoots();
-
 #ifndef MOZ_DISABLE_CRYPTOLEGACY
     LaunchSmartCardThreads();
 #endif
 
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS Initialization done\n"));
   }
   return NS_OK;
 }
@@ -1688,17 +1604,17 @@ nsNSSComponent::Observe(nsISupports* aSu
     } else if (prefName.Equals("security.OCSP.enabled")
                || prefName.Equals("security.CRL_download.enabled")
                || prefName.Equals("security.fresh_revocation_info.require")
                || prefName.Equals("security.missing_cert_download.enabled")
                || prefName.Equals("security.OCSP.require")
                || prefName.Equals("security.OCSP.GET.enabled")
                || prefName.Equals("security.ssl.enable_ocsp_stapling")) {
       MutexAutoLock lock(mutex);
-      setValidationOptions(false);
+      setValidationOptions(false, lock);
     } else if (prefName.Equals("network.ntlm.send-lm-response")) {
       bool sendLM = Preferences::GetBool("network.ntlm.send-lm-response",
                                          SEND_LM_DEFAULT);
       nsNTLMAuthModule::SetSendLM(sendLM);
       clearSessionCache = false;
     } else {
       clearSessionCache = false;
     }
--- a/security/manager/ssl/src/nsNSSComponent.h
+++ b/security/manager/ssl/src/nsNSSComponent.h
@@ -175,19 +175,20 @@ public:
 
   ::mozilla::TemporaryRef<mozilla::psm::SharedCertVerifier>
     GetDefaultCertVerifier() MOZ_OVERRIDE;
 
 private:
   nsresult InitializeNSS();
   void ShutdownNSS();
 
-  void InstallLoadableRoots();
+  void LoadLoadableRoots();
   void UnloadLoadableRoots();
-  void setValidationOptions(bool isInitialSetting);
+  void setValidationOptions(bool isInitialSetting,
+                            const mozilla::MutexAutoLock& lock);
   nsresult setEnabledTLSVersions();
   nsresult InitializePIPNSSBundle();
   nsresult ConfigureInternalPKCS11Token();
   nsresult RegisterObservers();
   nsresult DeregisterObservers();
 
   // Methods that we use to handle the profile change notifications (and to
   // synthesize a full profile change when we're just doing a profile startup):