Bug 769288 - Part 1: Make PSM more amenable to storing concurrent private and non-private data. r=bsmith
authorJosh Matthews <josh@joshmatthews.net>
Thu, 06 Dec 2012 22:05:27 -0500
changeset 116053 919c713155aca583294ebc0ea29332e8e3cb6a8d
parent 116052 72cc10ffa8e2f31964f303925b1cc07abfbf4e54
child 116054 8d86cc44bcee2de928b0ae2e51ad4402f0de00e7
push id24035
push usereakhgari@mozilla.com
push dateFri, 14 Dec 2012 16:55:27 +0000
treeherdermozilla-central@2798371f1650 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmith
bugs769288
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 769288 - Part 1: Make PSM more amenable to storing concurrent private and non-private data. r=bsmith
security/manager/pki/resources/content/exceptionDialog.js
security/manager/ssl/public/nsIRecentBadCertsService.idl
security/manager/ssl/public/nsIX509CertDB.idl
security/manager/ssl/src/Makefile.in
security/manager/ssl/src/SSLServerCertVerification.cpp
security/manager/ssl/src/SharedSSLState.cpp
security/manager/ssl/src/SharedSSLState.h
security/manager/ssl/src/nsClientAuthRemember.cpp
security/manager/ssl/src/nsClientAuthRemember.h
security/manager/ssl/src/nsNSSCallbacks.cpp
security/manager/ssl/src/nsNSSCertificateDB.cpp
security/manager/ssl/src/nsNSSCertificateDB.h
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsNSSComponent.h
security/manager/ssl/src/nsNSSIOLayer.cpp
security/manager/ssl/src/nsNSSIOLayer.h
security/manager/ssl/src/nsNSSModule.cpp
security/manager/ssl/src/nsRecentBadCerts.cpp
security/manager/ssl/src/nsRecentBadCerts.h
--- a/security/manager/pki/resources/content/exceptionDialog.js
+++ b/security/manager/pki/resources/content/exceptionDialog.js
@@ -83,18 +83,21 @@ function initExceptionDialog() {
     // Set out parameter to false by default
     args[0].exceptionAdded = false; 
   }
 }
 
 // returns true if found and global status could be set
 function findRecentBadCert(uri) {
   try {
-    var recentCertsSvc = Components.classes["@mozilla.org/security/recentbadcerts;1"]
-                         .getService(Components.interfaces.nsIRecentBadCertsService);
+    var certDB = Components.classes["@mozilla.org/security/x509certdb;1"]
+                           .getService(Components.interfaces.nsIX509CertDB);
+    if (!certDB)
+      return false;
+    var recentCertsSvc = certDB.getRecentBadCertsService(inPrivateBrowsingMode());
     if (!recentCertsSvc)
       return false;
 
     var hostWithPort = uri.host + ":" + uri.port;
     gSSLStatus = recentCertsSvc.getRecentBadCert(hostWithPort);
     if (!gSSLStatus)
       return false;
 
--- a/security/manager/ssl/public/nsIRecentBadCertsService.idl
+++ b/security/manager/ssl/public/nsIRecentBadCertsService.idl
@@ -15,19 +15,18 @@ interface nsISSLStatus;
 %}
 
 /**
  * This represents a global list of recently seen bad ssl status
  * including the bad cert.
  * The implementation will decide how many entries it will hold,
  * the number is expected to be small.
  */
-[scriptable, uuid(a5ae8b05-a76e-408f-b0ba-02a831265749)]
-interface nsIRecentBadCertsService : nsISupports {
-
+[scriptable, uuid(0fed7784-d152-44d6-95a7-67a59024de0f)]
+interface nsIRecentBadCerts : nsISupports {
   /**
    *  Retrieve the recently seen bad ssl status for the given hostname:port.
    *  If no SSL cert was recently seen for the given hostname:port, return null.
    *  If a good cert was seen for the given hostname:port, return null.
    *
    *  @param aHostNameWithPort The host:port whose entry should be tested
    *  @return null or a recently seen bad ssl status with cert
    */
@@ -38,9 +37,14 @@ interface nsIRecentBadCertsService : nsI
    *  Will be added as the most recently seen cert.
    *  The service may forget older entries to make room for the new one.
    *
    *  @param aHostNameWithPort The host:port whose entry should be tested
    *  @param aCert The bad ssl status with certificate
    */
   void addBadCert(in AString aHostNameWithPort,
                   in nsISSLStatus aStatus);
+
+  /**
+   * Clear all stored cert data.
+   */
+  void resetStoredCerts();
 };
--- a/security/manager/ssl/public/nsIX509CertDB.idl
+++ b/security/manager/ssl/public/nsIX509CertDB.idl
@@ -7,16 +7,17 @@
 #include "nsISupports.idl"
 
 interface nsIArray;
 interface nsIX509Cert;
 interface nsIX509Cert3;
 interface nsIFile;
 interface nsIInterfaceRequestor;
 interface nsIZipReader;
+interface nsIRecentBadCerts;
 
 %{C++
 #define NS_X509CERTDB_CONTRACTID "@mozilla.org/security/x509certdb;1"
 %}
 
 [scriptable, function, uuid(48411e2d-85a9-4b16-bec8-e30cde801f9e)]
 interface nsIOpenSignedJARFileCallback : nsISupports
 {
@@ -24,17 +25,17 @@ interface nsIOpenSignedJARFileCallback :
                                  in nsIZipReader aZipReader,
                                  in nsIX509Cert3 aSignerCert);
 };
 
 /**
  * This represents a service to access and manipulate 
  * X.509 certificates stored in a database.
  */
-[scriptable, uuid(735d0363-e219-4387-b5c6-72e800c3ea0b)]
+[scriptable, uuid(a18df2a5-84a9-46cd-9140-3fdb3879d9ff)]
 interface nsIX509CertDB : nsISupports {
 
   /**
    *  Constants that define which usages a certificate
    *  is trusted for.
    */
   const unsigned long UNTRUSTED       =      0;
   const unsigned long TRUSTED_SSL     = 1 << 0;
@@ -259,16 +260,26 @@ interface nsIX509CertDB : nsISupports {
    *  Decode a raw data presentation and instantiate an object in memory.
    *
    *  @param base64 The raw representation of a certificate,
    *                encoded as Base 64.
    *  @return The new certificate object.
    */
   nsIX509Cert constructX509FromBase64(in string base64);
 
+  /*
+   *  Obtain a reference to the appropriate service for recent
+   *  bad certificates. May only be called on the main thread.
+   *
+   *  @param isPrivate True if the service for certs for private connections
+   *                   is desired, false otherwise.
+   *  @return The requested service.
+   */
+  nsIRecentBadCerts getRecentBadCerts(in boolean isPrivate);
+
   /**
    *  Verifies the signature on the given JAR file to verify that it has a
    *  valid signature.  To be considered valid, there must be exactly one
    *  signature on the JAR file and that signature must have signed every
    *  entry. Further, the signature must come from a certificate that
    *  is trusted for code signing.
    *
    *  On success, NS_OK, a nsIZipReader, and the trusted certificate that
--- a/security/manager/ssl/src/Makefile.in
+++ b/security/manager/ssl/src/Makefile.in
@@ -69,16 +69,17 @@ CPPSRCS = 				\
   nsIdentityChecking.cpp \
   nsDataSignatureVerifier.cpp \
   nsRandomGenerator.cpp \
   NSSErrorsService.cpp \
   nsNSSCertificateFakeTransport.cpp \
   PSMRunnable.cpp \
   nsNSSVersion.cpp \
   nsCertificatePrincipal.cpp \
+  SharedSSLState.cpp \
   $(NULL)
 
 ifdef MOZ_XUL
 CPPSRCS += nsCertTree.cpp
 endif
 
 CSRCS += md4.c
 
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/src/SSLServerCertVerification.cpp
@@ -107,16 +107,17 @@
 #include "mozilla/Assertions.h"
 #include "nsIThreadPool.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIConsoleService.h"
 #include "PSMRunnable.h"
 #include "ScopedNSSTypes.h"
+#include "SharedSSLState.h"
 
 #include "ssl.h"
 #include "secerr.h"
 #include "secport.h"
 #include "sslerr.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gPIPNSSLog;
@@ -233,39 +234,42 @@ class CertErrorRunnable : public SyncRun
  public:
   CertErrorRunnable(const void * fdForLogging,
                     nsIX509Cert * cert,
                     TransportSecurityInfo * infoObject,
                     PRErrorCode defaultErrorCodeToReport,
                     uint32_t collectedErrors,
                     PRErrorCode errorCodeTrust,
                     PRErrorCode errorCodeMismatch,
-                    PRErrorCode errorCodeExpired)
+                    PRErrorCode errorCodeExpired,
+                    uint32_t providerFlags)
     : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
       mDefaultErrorCodeToReport(defaultErrorCodeToReport),
       mCollectedErrors(collectedErrors),
       mErrorCodeTrust(errorCodeTrust),
       mErrorCodeMismatch(errorCodeMismatch),
-      mErrorCodeExpired(errorCodeExpired)
+      mErrorCodeExpired(errorCodeExpired),
+      mProviderFlags(providerFlags)
   {
   }
 
   virtual void RunOnTargetThread();
   RefPtr<SSLServerCertVerificationResult> mResult; // out
 private:
   SSLServerCertVerificationResult *CheckCertOverrides();
   
   const void * const mFdForLogging; // may become an invalid pointer; do not dereference
   const nsCOMPtr<nsIX509Cert> mCert;
   const RefPtr<TransportSecurityInfo> mInfoObject;
   const PRErrorCode mDefaultErrorCodeToReport;
   const uint32_t mCollectedErrors;
   const PRErrorCode mErrorCodeTrust;
   const PRErrorCode mErrorCodeMismatch;
   const PRErrorCode mErrorCodeExpired;
+  const uint32_t mProviderFlags;
 };
 
 SSLServerCertVerificationResult *
 CertErrorRunnable::CheckCertOverrides()
 {
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CheckCertOverrides\n",
                                     mFdForLogging, this));
 
@@ -291,22 +295,18 @@ CertErrorRunnable::CheckCertOverrides()
   // connections must be dropped when there are any certificate errors
   // (STS Spec section 7.3).
   bool strictTransportSecurityEnabled = false;
   nsCOMPtr<nsIStrictTransportSecurityService> stss
     = do_GetService(NS_STSSERVICE_CONTRACTID, &nsrv);
   if (NS_SUCCEEDED(nsrv)) {
     nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
       NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
-    uint32_t flags = 0;
-    if (sslSocketControl) {
-      sslSocketControl->GetProviderFlags(&flags);
-    }
     nsrv = stss->IsStsHost(mInfoObject->GetHostName(),
-                           flags,
+                           mProviderFlags,
                            &strictTransportSecurityEnabled);
   }
   if (NS_FAILED(nsrv)) {
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
   }
 
   if (!strictTransportSecurityEnabled) {
@@ -366,18 +366,22 @@ CertErrorRunnable::CheckCertOverrides()
           = static_cast<nsIInterfaceRequestor*>(mInfoObject);
         bool suppressMessage = false; // obsolete, ignored
         nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
                                       hostWithPortString, &suppressMessage);
       }
     }
   }
 
-  nsCOMPtr<nsIRecentBadCertsService> recentBadCertsService = 
-    do_GetService(NS_RECENTBADCERTS_CONTRACTID);
+  nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
+  nsCOMPtr<nsIRecentBadCerts> recentBadCertsService;
+  if (certdb) {
+    bool isPrivate = mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
+    certdb->GetRecentBadCerts(isPrivate, getter_AddRefs(recentBadCertsService));
+  }
  
   if (recentBadCertsService) {
     NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
     recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
                                       mInfoObject->SSLStatus());
   }
 
   // pick the error code to report by priority
@@ -413,17 +417,18 @@ CertErrorRunnable::RunOnTargetThread()
 }
 
 // Returns null with the error code (PR_GetError()) set if it does not create
 // the CertErrorRunnable.
 CertErrorRunnable *
 CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport,
                         TransportSecurityInfo * infoObject,
                         CERTCertificate * cert,
-                        const void * fdForLogging)
+                        const void * fdForLogging,
+                        uint32_t providerFlags)
 {
   MOZ_ASSERT(infoObject);
   MOZ_ASSERT(cert);
   
   // cert was revoked, don't do anything else
   if (defaultErrorCodeToReport == SEC_ERROR_REVOKED_CERTIFICATE) {
     PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
     return nullptr;
@@ -562,17 +567,18 @@ CreateCertErrorRunnable(PRErrorCode defa
   }
 
   infoObject->SetStatusErrorBits(*nssCert, collected_errors);
 
   return new CertErrorRunnable(fdForLogging, 
                                static_cast<nsIX509Cert*>(nssCert.get()),
                                infoObject, defaultErrorCodeToReport, 
                                collected_errors, errorCodeTrust, 
-                               errorCodeMismatch, errorCodeExpired);
+                               errorCodeMismatch, errorCodeExpired,
+                               providerFlags);
 }
 
 // When doing async cert processing, we dispatch one of these runnables to the
 // socket transport service thread, which blocks the socket transport
 // service thread while it waits for the inner CertErrorRunnable to execute
 // CheckCertOverrides on the main thread. CheckCertOverrides must block events
 // on both of these threads because it calls TransportSecurityInfo::GetInterface(), 
 // which may call nsHttpConnection::GetInterface() through
@@ -602,35 +608,39 @@ private:
 };
 
 class SSLServerCertVerificationJob : public nsRunnable
 {
 public:
   // Must be called only on the socket transport thread
   static SECStatus Dispatch(const void * fdForLogging,
                             TransportSecurityInfo * infoObject,
-                            CERTCertificate * serverCert);
+                            CERTCertificate * serverCert,
+                            uint32_t providerFlags);
 private:
   NS_DECL_NSIRUNNABLE
 
   // Must be called only on the socket transport thread
   SSLServerCertVerificationJob(const void * fdForLogging,
                                TransportSecurityInfo * infoObject, 
-                               CERTCertificate * cert);
+                               CERTCertificate * cert,
+                               uint32_t providerFlags);
   const void * const mFdForLogging;
   const RefPtr<TransportSecurityInfo> mInfoObject;
   const ScopedCERTCertificate mCert;
+  const uint32_t mProviderFlags;
 };
 
 SSLServerCertVerificationJob::SSLServerCertVerificationJob(
     const void * fdForLogging, TransportSecurityInfo * infoObject,
-    CERTCertificate * cert)
+    CERTCertificate * cert, uint32_t providerFlags)
   : mFdForLogging(fdForLogging)
   , mInfoObject(infoObject)
   , mCert(CERT_DupCertificate(cert))
+  , mProviderFlags(providerFlags)
 {
 }
 
 SECStatus
 PSM_SSL_PKIX_AuthCertificate(CERTCertificate *peerCert, void * pinarg,
                              const char * hostname)
 {
     SECStatus          rv;
@@ -972,27 +982,29 @@ AuthCertificate(TransportSecurityInfo * 
   }
 
   return rv;
 }
 
 /*static*/ SECStatus
 SSLServerCertVerificationJob::Dispatch(const void * fdForLogging,
                                        TransportSecurityInfo * infoObject,
-                                       CERTCertificate * serverCert)
+                                       CERTCertificate * serverCert,
+                                       uint32_t providerFlags)
 {
   // Runs on the socket transport thread
   if (!infoObject || !serverCert) {
     NS_ERROR("Invalid parameters for SSL server cert validation");
     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     return SECFailure;
   }
   
   RefPtr<SSLServerCertVerificationJob> job(
-    new SSLServerCertVerificationJob(fdForLogging, infoObject, serverCert));
+    new SSLServerCertVerificationJob(fdForLogging, infoObject, serverCert,
+                                     providerFlags));
 
   nsresult nrv;
   if (!gCertVerificationThreadPool) {
     nrv = NS_ERROR_NOT_INITIALIZED;
   } else {
     nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
   }
   if (NS_FAILED(nrv)) {
@@ -1037,17 +1049,17 @@ SSLServerCertVerificationJob::Run()
         new SSLServerCertVerificationResult(mInfoObject, 0));
       restart->Dispatch();
       return NS_OK;
     }
 
     error = PR_GetError();
     if (error != 0) {
       RefPtr<CertErrorRunnable> runnable(CreateCertErrorRunnable(
-        error, mInfoObject, mCert, mFdForLogging));
+        error, mInfoObject, mCert, mFdForLogging, mProviderFlags));
       if (!runnable) {
         // CreateCertErrorRunnable set a new error code
         error = PR_GetError(); 
       } else {
         // We must block the the socket transport service thread while the
         // main thread executes the CertErrorRunnable. The CertErrorRunnable
         // will dispatch the result asynchronously, so we don't have to block
         // this thread waiting for it.
@@ -1130,42 +1142,47 @@ AuthCertificateHook(void *arg, PRFileDes
     nrv = sts->IsOnCurrentThread(&onSTSThread);
   }
 
   if (NS_FAILED(nrv)) {
     NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
     PR_SetError(PR_UNKNOWN_ERROR, 0);
     return SECFailure;
   }
-  
+
+  uint32_t providerFlags = 0;
+  socketInfo->GetProviderFlags(&providerFlags);
+
   if (onSTSThread) {
+
     // We *must* do certificate verification on a background thread because
     // we need the socket transport thread to be free for our OCSP requests,
     // and we *want* to do certificate verification on a background thread
     // because of the performance benefits of doing so.
     socketInfo->SetCertVerificationWaiting();
     SECStatus rv = SSLServerCertVerificationJob::Dispatch(
-                        static_cast<const void *>(fd), socketInfo, serverCert);
+                           static_cast<const void *>(fd), socketInfo, serverCert,
+                           providerFlags);
     return rv;
   }
   
   // We can't do certificate verification on a background thread, because the
   // thread doing the network I/O may not interrupt its network I/O on receipt
   // of our SSLServerCertVerificationResult event, and/or it might not even be
   // a non-blocking socket.
   SECStatus rv = AuthCertificate(socketInfo, serverCert);
   if (rv == SECSuccess) {
     return SECSuccess;
   }
 
   PRErrorCode error = PR_GetError();
   if (error != 0) {
     RefPtr<CertErrorRunnable> runnable(CreateCertErrorRunnable(
                     error, socketInfo, serverCert,
-                    static_cast<const void *>(fd)));
+                    static_cast<const void *>(fd), providerFlags));
     if (!runnable) {
       // CreateCertErrorRunnable sets a new error code when it fails
       error = PR_GetError();
     } else {
       // We have to return SECSuccess or SECFailure based on the result of the
       // override processing, so we must block this thread waiting for it. The
       // CertErrorRunnable will NOT dispatch the result at all, since we passed
       // false for CreateCertErrorRunnable's async parameter
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/src/SharedSSLState.cpp
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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 "SharedSSLState.h"
+#include "nsClientAuthRemember.h"
+#include "nsComponentManagerUtils.h"
+#include "nsICertOverrideService.h"
+#include "nsIObserverService.h"
+#include "mozilla/Services.h"
+#include "nsThreadUtils.h"
+#include "nsCRT.h"
+
+namespace mozilla {
+namespace psm {
+
+namespace {
+class PrivateBrowsingObserver : public nsIObserver {
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+  PrivateBrowsingObserver(SharedSSLState* aOwner) : mOwner(aOwner) {}
+  virtual ~PrivateBrowsingObserver() {}
+private:
+  SharedSSLState* mOwner;
+};
+
+SharedSSLState* gPublicState;
+SharedSSLState* gPrivateState;
+} // anonymous namespace
+
+NS_IMPL_ISUPPORTS1(PrivateBrowsingObserver, nsIObserver)
+
+NS_IMETHODIMP
+PrivateBrowsingObserver::Observe(nsISupports     *aSubject,
+                                 const char      *aTopic,
+                                 const PRUnichar *aData)
+{
+  if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
+    mOwner->ResetStoredData();
+  }
+  return NS_OK;
+}
+
+SharedSSLState::SharedSSLState()
+: mClientAuthRemember(new nsClientAuthRememberService)
+{
+  mIOLayerHelpers.Init();
+  mClientAuthRemember->Init();
+}
+
+void
+SharedSSLState::NotePrivateBrowsingStatus()
+{
+  mObserver = new PrivateBrowsingObserver(this);
+  nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+  obsSvc->AddObserver(mObserver, "last-pb-context-exited", false);
+}
+
+void
+SharedSSLState::ResetStoredData()
+{
+  mClientAuthRemember->ClearRememberedDecisions();
+  mIOLayerHelpers.clearStoredData();
+}
+
+/*static*/ void
+SharedSSLState::GlobalInit()
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
+  gPublicState = new SharedSSLState();
+  gPrivateState = new SharedSSLState();
+  gPrivateState->NotePrivateBrowsingStatus();
+}
+
+/*static*/ void
+SharedSSLState::GlobalCleanup()
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
+
+  gPrivateState->Cleanup();
+  delete gPrivateState;
+  gPrivateState = nullptr;
+
+  gPublicState->Cleanup();
+  delete gPublicState;
+  gPublicState = nullptr;
+}
+
+void
+SharedSSLState::Cleanup()
+{
+  mIOLayerHelpers.Cleanup();
+}
+
+SharedSSLState*
+PublicSSLState()
+{
+  return gPublicState;
+}
+
+SharedSSLState*
+PrivateSSLState()
+{
+  return gPrivateState;
+}
+
+} // namespace psm
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/src/SharedSSLState.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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 SharedSSLState_h
+#define SharedSSLState_h
+
+#include "mozilla/RefPtr.h"
+#include "nsNSSIOLayer.h"
+
+class nsClientAuthRememberService;
+class nsIRecentBadCertsService;
+class nsICertOverrideService;
+class nsIObserver;
+
+namespace mozilla {
+namespace psm {
+
+class SharedSSLState {
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedSSLState)
+  SharedSSLState();
+
+  static void GlobalInit();
+  static void GlobalCleanup();
+
+  nsClientAuthRememberService* GetClientAuthRememberService() {
+    return mClientAuthRemember;
+  }
+
+  nsSSLIOLayerHelpers& IOLayerHelpers() {
+    return mIOLayerHelpers;
+  }
+
+  void ResetStoredData();
+  void NotePrivateBrowsingStatus();
+
+private:
+  void Cleanup();
+
+  nsCOMPtr<nsIObserver> mObserver;
+  RefPtr<nsClientAuthRememberService> mClientAuthRemember;
+  nsSSLIOLayerHelpers mIOLayerHelpers;
+};
+
+SharedSSLState* PublicSSLState();
+SharedSSLState* PrivateSSLState();
+
+} // namespace psm
+} // namespace mozilla
+
+#endif
--- a/security/manager/ssl/src/nsClientAuthRemember.cpp
+++ b/security/manager/ssl/src/nsClientAuthRemember.cpp
@@ -16,18 +16,20 @@
 #include "nsPromiseFlatString.h"
 #include "nsThreadUtils.h"
 #include "nsStringBuffer.h"
 #include "cert.h"
 #include "nspr.h"
 #include "pk11pub.h"
 #include "certdb.h"
 #include "sechash.h"
+#include "SharedSSLState.h"
 
 using namespace mozilla;
+using namespace mozilla::psm;
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(nsClientAuthRememberService, 
                               nsIObserver,
                               nsISupportsWeakReference)
 
 nsClientAuthRememberService::nsClientAuthRememberService()
   : monitor("nsClientAuthRememberService.monitor")
 {
@@ -75,16 +77,26 @@ nsClientAuthRememberService::Observe(nsI
 }
 
 void nsClientAuthRememberService::ClearRememberedDecisions()
 {
   ReentrantMonitorAutoEnter lock(monitor);
   RemoveAllFromMemory();
 }
 
+void nsClientAuthRememberService::ClearAllRememberedDecisions()
+{
+  RefPtr<nsClientAuthRememberService> svc =
+    PublicSSLState()->GetClientAuthRememberService();
+  svc->ClearRememberedDecisions();
+
+  svc = PrivateSSLState()->GetClientAuthRememberService();
+  svc->ClearRememberedDecisions();
+}
+
 void
 nsClientAuthRememberService::RemoveAllFromMemory()
 {
   mSettingsTable.Clear();
 }
 
 static nsresult
 GetCertFingerprintByOidTag(CERTCertificate* nsscert,
--- a/security/manager/ssl/src/nsClientAuthRemember.h
+++ b/security/manager/ssl/src/nsClientAuthRemember.h
@@ -123,16 +123,17 @@ public:
 
   nsresult RememberDecision(const nsACString & aHostName, 
                             CERTCertificate *aServerCert, CERTCertificate *aClientCert);
   nsresult HasRememberedDecision(const nsACString & aHostName, 
                                  CERTCertificate *aServerCert, 
                                  nsACString & aCertDBKey, bool *_retval);
 
   void ClearRememberedDecisions();
+  static void ClearAllRememberedDecisions();
 
 protected:
     mozilla::ReentrantMonitor monitor;
     nsTHashtable<nsClientAuthRememberEntry> mSettingsTable;
 
     void RemoveAllFromMemory();
     nsresult AddEntryToList(const nsACString &host, 
                             const nsACString &server_fingerprint,
--- a/security/manager/ssl/src/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/src/nsNSSCallbacks.cpp
@@ -18,16 +18,17 @@
 #include "nsThreadUtils.h"
 #include "nsIPrompt.h"
 #include "nsProxyRelease.h"
 #include "PSMRunnable.h"
 #include "ScopedNSSTypes.h"
 #include "nsIConsoleService.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsCRT.h"
+#include "SharedSSLState.h"
 
 #include "ssl.h"
 #include "sslproto.h"
 #include "ocsp.h"
 #include "nssb64.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
@@ -836,17 +837,18 @@ void HandshakeCallback(PRFileDesc* fd, v
 
   if (infoObject) {
     // This is the first callback on resumption handshakes
     infoObject->SetFirstServerHelloReceived();
   }
 
   // If the handshake completed, then we know the site is TLS tolerant (if this
   // was a TLS connection).
-  nsSSLIOLayerHelpers::rememberTolerantSite(infoObject);
+  nsSSLIOLayerHelpers& ioLayerHelpers = infoObject->SharedState().IOLayerHelpers();
+  ioLayerHelpers.rememberTolerantSite(infoObject);
 
   if (SECSuccess != SSL_SecurityStatus(fd, &sslStatus, &cipherName, &keyLength,
                                        &encryptBits, &signer, nullptr)) {
     return;
   }
 
   int32_t secStatus;
   if (sslStatus == SSL_SECURITY_STATUS_OFF)
@@ -854,33 +856,33 @@ void HandshakeCallback(PRFileDesc* fd, v
   else
     secStatus = nsIWebProgressListener::STATE_IS_SECURE
               | nsIWebProgressListener::STATE_SECURE_HIGH;
 
   PRBool siteSupportsSafeRenego;
   if (SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn, &siteSupportsSafeRenego) != SECSuccess
       || !siteSupportsSafeRenego) {
 
-    bool wantWarning = (nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746() > 0);
+    bool wantWarning = (ioLayerHelpers.getWarnLevelMissingRFC5746() > 0);
 
     nsCOMPtr<nsIConsoleService> console;
     if (infoObject && wantWarning) {
       console = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
       if (console) {
         nsXPIDLCString hostName;
         infoObject->GetHostName(getter_Copies(hostName));
 
         nsAutoString msg;
         msg.Append(NS_ConvertASCIItoUTF16(hostName));
         msg.Append(NS_LITERAL_STRING(" : server does not support RFC 5746, see CVE-2009-3555"));
 
         console->LogStringMessage(msg.get());
       }
     }
-    if (nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()) {
+    if (ioLayerHelpers.treatUnsafeNegotiationAsBroken()) {
       secStatus = nsIWebProgressListener::STATE_IS_BROKEN;
     }
   }
 
 
   ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
   const char* caName = nullptr; // caName is a pointer only, no ownership
   char* certOrgName = CERT_GetOrgName(&serverCert->issuer);
--- a/security/manager/ssl/src/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/src/nsNSSCertificateDB.cpp
@@ -26,16 +26,18 @@
 #include "nsArrayUtils.h"
 #include "nsNSSShutDown.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIPrompt.h"
 #include "nsThreadUtils.h"
 #include "ScopedNSSTypes.h"
+#include "nsIObserverService.h"
+#include "nsRecentBadCerts.h"
 
 #include "nspr.h"
 #include "certdb.h"
 #include "secerr.h"
 #include "nssb64.h"
 #include "secasn1.h"
 #include "secder.h"
 #include "ssl.h"
@@ -1639,8 +1641,27 @@ nsNSSCertificateDB::GetCerts(nsIX509Cert
   // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine.
   // (returns an empty list) 
   nssCertList = new nsNSSCertList(certList, true);
 
   *_retval = nssCertList;
   NS_ADDREF(*_retval);
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsNSSCertificateDB::GetRecentBadCerts(bool isPrivate, nsIRecentBadCerts** result)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "RecentBadCerts should only be obtained on the main thread");
+  if (isPrivate) {
+    if (!mPrivateRecentBadCerts) {
+      mPrivateRecentBadCerts = new nsRecentBadCerts;
+      mPrivateRecentBadCerts->InitPrivateBrowsingObserver();
+    }
+    NS_ADDREF(*result = mPrivateRecentBadCerts);
+  } else {
+    if (!mPublicRecentBadCerts) {
+      mPublicRecentBadCerts = new nsRecentBadCerts;
+    }
+    NS_ADDREF(*result = mPublicRecentBadCerts);
+  }
+  return NS_OK;
+}
--- a/security/manager/ssl/src/nsNSSCertificateDB.h
+++ b/security/manager/ssl/src/nsNSSCertificateDB.h
@@ -2,20 +2,22 @@
  * 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 __NSNSSCERTIFICATEDB_H__
 #define __NSNSSCERTIFICATEDB_H__
 
 #include "nsIX509CertDB.h"
 #include "nsIX509CertDB2.h"
+#include "mozilla/RefPtr.h"
 #include "certt.h"
 
 class nsCString;
 class nsIArray;
+class nsRecentBadCerts;
 
 class nsNSSCertificateDB : public nsIX509CertDB, public nsIX509CertDB2
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIX509CERTDB
   NS_DECL_NSIX509CERTDB2
 
@@ -43,16 +45,19 @@ private:
                     uint32_t      type, 
                     uint32_t     *_count,
                     PRUnichar  ***_certNameList);
 
   CERTDERCerts *getCertsFromPackage(PLArenaPool *arena, uint8_t *data, 
                                     uint32_t length);
   nsresult handleCACertDownload(nsIArray *x509Certs, 
                                 nsIInterfaceRequestor *ctx);
+
+  mozilla::RefPtr<nsRecentBadCerts> mPublicRecentBadCerts;
+  mozilla::RefPtr<nsRecentBadCerts> mPrivateRecentBadCerts;
 };
 
 #define NS_X509CERTDB_CID { /* fb0bbc5c-452e-4783-b32c-80124693d871 */ \
     0xfb0bbc5c,                                                        \
     0x452e,                                                            \
     0x4783,                                                            \
     {0xb3, 0x2c, 0x80, 0x12, 0x46, 0x93, 0xd8, 0x71}                   \
   }
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -55,16 +55,17 @@
 #include "nsIServiceManager.h"
 #include "nsIFile.h"
 #include "nsITokenPasswordDialogs.h"
 #include "nsICRLManager.h"
 #include "nsNSSShutDown.h"
 #include "nsSmartCardEvent.h"
 #include "nsIKeyModule.h"
 #include "ScopedNSSTypes.h"
+#include "SharedSSLState.h"
 
 #include "nss.h"
 #include "pk11func.h"
 #include "ssl.h"
 #include "sslproto.h"
 #include "secmod.h"
 #include "sechash.h"
 #include "secmime.h"
@@ -395,17 +396,17 @@ nsNSSComponent::~nsNSSComponent()
     }
 
     mUpdateTimerInitialized = false;
   }
 
   // All cleanup code requiring services needs to happen in xpcom_shutdown
 
   ShutdownNSS();
-  nsSSLIOLayerHelpers::Cleanup();
+  SharedSSLState::GlobalCleanup();
   RememberCertErrorsTable::Cleanup();
   --mInstanceCount;
   delete mShutdownObjectList;
 
   // We are being freed, drop the haveLoaded flag to re-enable
   // potential nss initialization later.
   EnsureNSSInitialized(nssShutdown);
 
@@ -1855,19 +1856,16 @@ nsNSSComponent::ShutdownNSS()
     UnregisterMyOCSPAIAInfoCallback();
 
     if (mPrefBranch) {
       mPrefBranch->RemoveObserver("security.", this);
     }
 
     ShutdownSmartCardThreads();
     SSL_ClearSessionCache();
-    if (mClientAuthRememberService) {
-      mClientAuthRememberService->ClearRememberedDecisions();
-    }
     UnloadLoadableRoots();
     CleanupIdentityInfo();
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("evaporating psm resources\n"));
     mShutdownObjectList->evaporateAllNSSResources();
     EnsureNSSInitialized(nssShutdown);
     if (SECSuccess != ::NSS_Shutdown()) {
       PR_LOG(gPIPNSSLog, PR_LOG_ALWAYS, ("NSS SHUTDOWN FAILURE\n"));
       rv = NS_ERROR_FAILURE;
@@ -1928,37 +1926,18 @@ nsNSSComponent::Init()
     PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to Initialize NSS.\n"));
 
     DeregisterObservers();
     mPIPNSSBundle = nullptr;
     return rv;
   }
 
   RememberCertErrorsTable::Init();
-  nsSSLIOLayerHelpers::Init();
-  char *unrestricted_hosts=nullptr;
-  mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
-  if (unrestricted_hosts) {
-    nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
-    nsMemory::Free(unrestricted_hosts);
-    unrestricted_hosts=nullptr;
-  }
-
-  bool enabled = false;
-  mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
-  nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
-
-  int32_t warnLevel = 1;
-  mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
-  nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
+  SharedSSLState::GlobalInit();
   
-  mClientAuthRememberService = new nsClientAuthRememberService;
-  if (mClientAuthRememberService)
-    mClientAuthRememberService->Init();
-
   createBackgroundThreads();
   if (!mCertVerificationThread)
   {
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS init, could not create threads\n"));
 
     DeregisterObservers();
     mPIPNSSBundle = nullptr;
     return NS_ERROR_OUT_OF_MEMORY;
@@ -2266,30 +2245,16 @@ nsNSSComponent::Observe(nsISupports *aSu
       SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
     } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
       mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
       SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
     } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
       mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
       SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION, 
         enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
-    } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
-      char *unrestricted_hosts=nullptr;
-      mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
-      if (unrestricted_hosts) {
-        nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
-        nsMemory::Free(unrestricted_hosts);
-      }
-    } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
-      mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
-      nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
-    } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
-      int32_t warnLevel = 1;
-      mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
-      nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
 #ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8
     } else if (prefName.Equals("security.ssl.enable_false_start")) {
       mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
       SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
 #endif
     } else if (prefName.Equals("security.OCSP.enabled")
                || prefName.Equals("security.CRL_download.enabled")
                || prefName.Equals("security.fresh_revocation_info.require")
@@ -2382,19 +2347,17 @@ nsresult nsNSSComponent::LogoutAuthentic
   nsCOMPtr<nsICertOverrideService> icos =
     do_GetService("@mozilla.org/security/certoverride;1");
   if (icos) {
     icos->ClearValidityOverride(
             NS_LITERAL_CSTRING("all:temporary-certificates"),
             0);
   }
 
-  if (mClientAuthRememberService) {
-    mClientAuthRememberService->ClearRememberedDecisions();
-  }
+  nsClientAuthRememberService::ClearAllRememberedDecisions();
 
   return mShutdownObjectList->doPK11Logout();
 }
 
 nsresult
 nsNSSComponent::RegisterObservers()
 {
   // Happens once during init only, no mutex protection.
@@ -2564,24 +2527,16 @@ nsNSSComponent::DoProfileChangeNetRestor
 {
   /* XXX this doesn't work well, since nothing expects null pointers */
   deleteBackgroundThreads();
   createBackgroundThreads();
   mIsNetworkDown = false;
 }
 
 NS_IMETHODIMP
-nsNSSComponent::GetClientAuthRememberService(nsClientAuthRememberService **cars)
-{
-  NS_ENSURE_ARG_POINTER(cars);
-  NS_IF_ADDREF(*cars = mClientAuthRememberService);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsNSSComponent::IsNSSInitialized(bool *initialized)
 {
   MutexAutoLock lock(mutex);
   *initialized = mNSSInitialized;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/security/manager/ssl/src/nsNSSComponent.h
+++ b/security/manager/ssl/src/nsNSSComponent.h
@@ -149,18 +149,16 @@ class NS_NO_VTABLE nsINSSComponent : pub
   NS_IMETHOD LaunchSmartCardThread(SECMODModule *module) = 0;
 
   NS_IMETHOD ShutdownSmartCardThread(SECMODModule *module) = 0;
 
   NS_IMETHOD PostEvent(const nsAString &eventType, const nsAString &token) = 0;
 
   NS_IMETHOD DispatchEvent(const nsAString &eventType, const nsAString &token) = 0;
   
-  NS_IMETHOD GetClientAuthRememberService(nsClientAuthRememberService **cars) = 0;
-
   NS_IMETHOD EnsureIdentityInfoLoaded() = 0;
 
   NS_IMETHOD IsNSSInitialized(bool *initialized) = 0;
 
   NS_IMETHOD GetDefaultCERTValInParam(
                   mozilla::RefPtr<nsCERTValInParamWrapper> &out) = 0;
   NS_IMETHOD GetDefaultCERTValInParamLocalOnly(
                   mozilla::RefPtr<nsCERTValInParamWrapper> &out) = 0;
@@ -254,17 +252,16 @@ public:
   NS_IMETHOD LogoutAuthenticatedPK11();
   NS_IMETHOD DownloadCRLDirectly(nsAutoString, nsAutoString);
   NS_IMETHOD RememberCert(CERTCertificate *cert);
 
   NS_IMETHOD LaunchSmartCardThread(SECMODModule *module);
   NS_IMETHOD ShutdownSmartCardThread(SECMODModule *module);
   NS_IMETHOD PostEvent(const nsAString &eventType, const nsAString &token);
   NS_IMETHOD DispatchEvent(const nsAString &eventType, const nsAString &token);
-  NS_IMETHOD GetClientAuthRememberService(nsClientAuthRememberService **cars);
   NS_IMETHOD EnsureIdentityInfoLoaded();
   NS_IMETHOD IsNSSInitialized(bool *initialized);
 
   NS_IMETHOD GetDefaultCERTValInParam(
                   mozilla::RefPtr<nsCERTValInParamWrapper> &out);
   NS_IMETHOD GetDefaultCERTValInParamLocalOnly(
                   mozilla::RefPtr<nsCERTValInParamWrapper> &out);
 private:
@@ -322,17 +319,16 @@ private:
   SmartCardThreadList *mThreadList;
   bool mIsNetworkDown;
 
   void deleteBackgroundThreads();
   void createBackgroundThreads();
   nsCertVerificationThread *mCertVerificationThread;
 
   nsNSSHttpInterface mHttpForNSS;
-  mozilla::RefPtr<nsClientAuthRememberService> mClientAuthRememberService;
   mozilla::RefPtr<nsCERTValInParamWrapper> mDefaultCERTValInParam;
   mozilla::RefPtr<nsCERTValInParamWrapper> mDefaultCERTValInParamLocalOnly;
 
   static PRStatus IdentityInfoInit(void);
   PRCallOnceType mIdentityInfoCallOnce;
 
 public:
   static bool globalConstFlagUsePKIXVerification;
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -23,16 +23,18 @@
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsIConsoleService.h"
 #include "PSMRunnable.h"
 #include "ScopedNSSTypes.h"
+#include "SharedSSLState.h"
+#include "mozilla/Preferences.h"
 
 #include "ssl.h"
 #include "secerr.h"
 #include "sslerr.h"
 #include "secder.h"
 #include "keyhi.h"
 
 using namespace mozilla;
@@ -58,19 +60,20 @@ static NS_DEFINE_CID(kNSSComponentCID, N
 typedef enum {ASK, AUTO} SSM_UserCertChoice;
 
 } // unnamed namespace
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gPIPNSSLog;
 #endif
 
-nsNSSSocketInfo::nsNSSSocketInfo(uint32_t providerFlags)
+nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
   : mFd(nullptr),
     mCertVerificationState(before_cert_verification),
+    mSharedState(aState),
     mForSTARTTLS(false),
     mSSL3Enabled(false),
     mTLSEnabled(false),
     mHandshakePending(true),
     mHasCleartextPhase(false),
     mHandshakeInProgress(false),
     mAllowTLSIntoleranceTimeout(true),
     mRememberClientAuthCertificate(false),
@@ -452,16 +455,21 @@ void nsNSSSocketInfo::SetHandshakeInProg
   }
 }
 
 void nsNSSSocketInfo::SetAllowTLSIntoleranceTimeout(bool aAllow)
 {
   mAllowTLSIntoleranceTimeout = aAllow;
 }
 
+SharedSSLState& nsNSSSocketInfo::SharedState()
+{
+  return mSharedState;
+}
+
 bool nsNSSSocketInfo::HandshakeTimeout()
 {
   if (!mAllowTLSIntoleranceTimeout)
     return false;
 
   if (!mHandshakeInProgress)
     return false; // have not even sent client hello yet
 
@@ -909,17 +917,18 @@ int32_t checkHandshake(int32_t bytesTran
       if (PR_WOULD_BLOCK_ERROR == err) {
         socketInfo->SetHandshakeInProgress(true);
         return bytesTransfered;
       }
 
       if (!wantRetry // no decision yet
           && isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
       {
-        wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
+        nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
+        wantRetry = helpers.rememberPossibleTLSProblemSite(socketInfo);
       }
     }
     
     // This is the common place where we trigger non-cert-errors on a SSL
     // socket. This might be reached at any time of the connection.
     //
     // The socketInfo->GetErrorCode() check is here to ensure we don't try to
     // do the synchronous dispatch to the main thread unnecessarily after we've
@@ -937,18 +946,18 @@ int32_t checkHandshake(int32_t bytesTran
   }
   else if (wasReading && 0 == bytesTransfered) // zero bytes on reading, socket closed
   {
     if (handleHandshakeResultNow)
     {
       if (!wantRetry // no decision yet
           && !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
       {
-        wantRetry = 
-          nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
+        nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
+        wantRetry = helpers.rememberPossibleTLSProblemSite(socketInfo);
       }
     }
   }
 
   if (wantRetry) {
     // We want to cause the network layer to retry the connection.
     PR_SetError(PR_CONNECT_RESET_ERROR, 0);
     if (wasReading)
@@ -1026,22 +1035,26 @@ nsSSLIOLayerPoll(PRFileDesc * fd, int16_
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] poll SSL socket returned %d\n",
                                     (void*)fd, (int) result));
   return result;
 }
 
 bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
-Mutex *nsSSLIOLayerHelpers::mutex = nullptr;
-nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mTLSIntolerantSites = nullptr;
-nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mTLSTolerantSites = nullptr;
-nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mRenegoUnrestrictedSites = nullptr;
-bool nsSSLIOLayerHelpers::mTreatUnsafeNegotiationAsBroken = false;
-int32_t nsSSLIOLayerHelpers::mWarnLevelMissingRFC5746 = 1;
+
+nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
+: mutex(nullptr)
+, mTLSIntolerantSites(nullptr)
+, mTLSTolerantSites(nullptr)
+, mRenegoUnrestrictedSites(nullptr)
+, mTreatUnsafeNegotiationAsBroken(false)
+, mWarnLevelMissingRFC5746(1)
+{
+}
 
 static int _PSM_InvalidInt(void)
 {
     PR_ASSERT(!"I/O method is invalid");
     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     return -1;
 }
 
@@ -1185,16 +1198,63 @@ static int PSMAvailable(void)
 
 static int64_t PSMAvailable64(void)
 {
   // This is called through PR_Available(), but is not implemented in PSM
   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   return -1;
 }
 
+namespace {
+class PrefObserver : public nsIObserver {
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+  PrefObserver(nsSSLIOLayerHelpers* aOwner) : mOwner(aOwner) {}
+  virtual ~PrefObserver() {}
+private:
+  nsSSLIOLayerHelpers* mOwner;
+};
+} // namespace anonymous
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(PrefObserver, nsIObserver)
+
+NS_IMETHODIMP
+PrefObserver::Observe(nsISupports *aSubject, const char *aTopic, 
+                      const PRUnichar *someData)
+{
+  if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
+    NS_ConvertUTF16toUTF8 prefName(someData);
+
+    if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
+      nsCString unrestricted_hosts;
+      Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
+      if (!unrestricted_hosts.IsEmpty()) {
+        mOwner->setRenegoUnrestrictedSites(unrestricted_hosts);
+      }
+    } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
+      bool enabled;
+      Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
+      mOwner->setTreatUnsafeNegotiationAsBroken(enabled);
+    } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
+      int32_t warnLevel = 1;
+      Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
+      mOwner->setWarnLevelMissingRFC5746(warnLevel);
+    }
+  }
+  return NS_OK;
+}
+
+nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers()
+{
+  Preferences::RemoveObserver(mPrefObserver, "security.ssl.renego_unrestricted_hosts");
+  Preferences::RemoveObserver(mPrefObserver, "security.ssl.treat_unsafe_negotiation_as_broken");
+  Preferences::RemoveObserver(mPrefObserver, "security.ssl.warn_missing_rfc5746");
+}
+
 nsresult nsSSLIOLayerHelpers::Init()
 {
   if (!nsSSLIOLayerInitialized) {
     nsSSLIOLayerInitialized = true;
     nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
     nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
 
     nsSSLIOLayerMethods.available = (PRAvailableFN)PSMAvailable;
@@ -1239,33 +1299,60 @@ nsresult nsSSLIOLayerHelpers::Init()
   // Initialize the tolerant site hashtable to 16 items at the start seems
   // reasonable as most servers are TLS tolerant. We just want to lower 
   // the rate of hashtable array reallocation.
   mTLSTolerantSites->Init(16);
 
   mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
   mRenegoUnrestrictedSites->Init(1);
 
-  mTreatUnsafeNegotiationAsBroken = false;
-  
+  nsCString unrestricted_hosts;
+  Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
+  if (!unrestricted_hosts.IsEmpty()) {
+    setRenegoUnrestrictedSites(unrestricted_hosts);
+  }
+
+  bool enabled = false;
+  Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
+  setTreatUnsafeNegotiationAsBroken(enabled);
+
+  int32_t warnLevel = 1;
+  Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
+  setWarnLevelMissingRFC5746(warnLevel);
+
+  mPrefObserver = new PrefObserver(this);
+  Preferences::AddStrongObserver(mPrefObserver,
+                                 "security.ssl.renego_unrestricted_hosts");
+  Preferences::AddStrongObserver(mPrefObserver,
+                                 "security.ssl.treat_unsafe_negotiation_as_broken");
+  Preferences::AddStrongObserver(mPrefObserver,
+                                 "security.ssl.warn_missing_rfc5746");
+
   return NS_OK;
 }
 
+void nsSSLIOLayerHelpers::clearStoredData()
+{
+  mRenegoUnrestrictedSites->Clear();
+  mTLSTolerantSites->Clear();
+  mTLSIntolerantSites->Clear();
+}
+
 void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
 {
   MutexAutoLock lock(*mutex);
   // Remember intolerant site only if it is not known as tolerant
   if (!mTLSTolerantSites->Contains(str))
-    nsSSLIOLayerHelpers::mTLSIntolerantSites->PutEntry(str);
+    mTLSIntolerantSites->PutEntry(str);
 }
 
 void nsSSLIOLayerHelpers::removeIntolerantSite(const nsCString &str)
 {
   MutexAutoLock lock(*mutex);
-  nsSSLIOLayerHelpers::mTLSIntolerantSites->RemoveEntry(str);
+  mTLSIntolerantSites->RemoveEntry(str);
 }
 
 bool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
 {
   MutexAutoLock lock(*mutex);
   return mTLSIntolerantSites->Contains(str);
 }
 
@@ -1918,16 +2005,17 @@ void ClientAuthDataRunnable::RunOnTarget
   ScopedCERTCertList certList;
   CERTCertListNode* node;
   ScopedCERTCertNicknames nicknames;
   char* extracted = nullptr;
   int keyError = 0; /* used for private key retrieval error */
   SSM_UserCertChoice certChoice;
   int32_t NumberOfCerts = 0;
   void * wincx = mSocketInfo;
+  nsresult rv;
 
   /* create caNameStrings */
   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   if (!arena) {
     goto loser;
   }
 
   caNameStrings = (char**)PORT_ArenaAlloc(arena, 
@@ -2019,29 +2107,24 @@ void ClientAuthDataRunnable::RunOnTarget
     }
   }
   else { // Not Auto => ask
     /* Get the SSL Certificate */
 
     nsXPIDLCString hostname;
     mSocketInfo->GetHostName(getter_Copies(hostname));
 
-    nsresult rv;
-    NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
-    nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
-    RefPtr<nsClientAuthRememberService> cars;
-    if (nssComponent) {
-      nssComponent->GetClientAuthRememberService(byRef(cars));
-    }
+    RefPtr<nsClientAuthRememberService> cars =
+        mSocketInfo->SharedState().GetClientAuthRememberService();
 
     bool hasRemembered = false;
     nsCString rememberedDBKey;
     if (cars) {
       bool found;
-      nsresult rv = cars->HasRememberedDecision(hostname, mServerCert,
+      rv = cars->HasRememberedDecision(hostname, mServerCert,
                                                 rememberedDBKey, &found);
       if (NS_SUCCEEDED(rv) && found) {
         hasRemembered = true;
       }
     }
 
     bool canceled = false;
 
@@ -2214,19 +2297,19 @@ if (!hasRemembered)
         nsMemory::Free(certNicknameList[CertsToUse]);
         continue;
       }
 
       ++CertsToUse;
     }
 
     /* Throw up the client auth dialog and get back the index of the selected cert */
-    rv = getNSSDialogs((void**)&dialogs, 
-                       NS_GET_IID(nsIClientAuthDialogs),
-                       NS_CLIENTAUTHDIALOGS_CONTRACTID);
+    nsresult rv = getNSSDialogs((void**)&dialogs, 
+                                NS_GET_IID(nsIClientAuthDialogs),
+                                NS_CLIENTAUTHDIALOGS_CONTRACTID);
 
     if (NS_FAILED(rv)) {
       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
       goto loser;
     }
 
     {
@@ -2375,17 +2458,17 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, b
     infoObject->SetHasCleartextPhase(true);
   }
 
   // Let's see if we're trying to connect to a site we know is
   // TLS intolerant.
   nsAutoCString key;
   key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
 
-  if (nsSSLIOLayerHelpers::isKnownAsIntolerantSite(key)) {
+  if (infoObject->SharedState().IOLayerHelpers().isKnownAsIntolerantSite(key)) {
     if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, false))
       return NS_ERROR_FAILURE;
 
     infoObject->SetAllowTLSIntoleranceTimeout(false);
       
     // We assume that protocols that use the STARTTLS mechanism should support
     // modern hellos. For other protocols, if we suspect a site 
     // does not support TLS, let's also use V2 hellos.
@@ -2402,18 +2485,19 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, b
   if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_TLS, &enabled)) {
     return NS_ERROR_FAILURE;
   }
   infoObject->SetTLSEnabled(enabled);
 
   if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
     return NS_ERROR_FAILURE;
   }
-  
-  if (nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(nsDependentCString(host))) {
+
+  nsSSLIOLayerHelpers& ioHelpers = infoObject->SharedState().IOLayerHelpers();
+  if (ioHelpers.isRenegoUnrestrictedSite(nsDependentCString(host))) {
     if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, false)) {
       return NS_ERROR_FAILURE;
     }
     if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED)) {
       return NS_ERROR_FAILURE;
     }
   }
 
@@ -2445,17 +2529,19 @@ nsSSLIOLayerAddToSocket(int32_t family,
                         bool forSTARTTLS,
                         uint32_t providerFlags)
 {
   nsNSSShutDownPreventionLock locker;
   PRFileDesc* layer = nullptr;
   nsresult rv;
   PRStatus stat;
 
-  nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(providerFlags);
+  SharedSSLState* sharedState =
+    providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ? PrivateSSLState() : PublicSSLState();
+  nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags);
   if (!infoObject) return NS_ERROR_FAILURE;
   
   NS_ADDREF(infoObject);
   infoObject->SetForSTARTTLS(forSTARTTLS);
   infoObject->SetHostName(host);
   infoObject->SetPort(port);
 
   bool anonymousLoad = providerFlags & nsISocketProvider::ANONYMOUS_CONNECT;
--- a/security/manager/ssl/src/nsNSSIOLayer.h
+++ b/security/manager/ssl/src/nsNSSIOLayer.h
@@ -10,22 +10,30 @@
 #include "TransportSecurityInfo.h"
 #include "nsISSLSocketControl.h"
 #include "nsIClientAuthDialogs.h"
 #include "nsNSSCertificate.h"
 #include "nsDataHashtable.h"
 #include "nsTHashtable.h"
 #include "mozilla/TimeStamp.h"
 
+namespace mozilla {
+namespace psm {
+class SharedSSLState;
+}
+}
+
+class nsIObserver;
+
 class nsNSSSocketInfo : public mozilla::psm::TransportSecurityInfo,
                         public nsISSLSocketControl,
                         public nsIClientAuthUserDecision
 {
 public:
-  nsNSSSocketInfo(uint32_t providerFlags);
+  nsNSSSocketInfo(mozilla::psm::SharedSSLState& aState, uint32_t providerFlags);
   
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSISSLSOCKETCONTROL
   NS_DECL_NSICLIENTAUTHUSERDECISION
  
   nsresult SetForSTARTTLS(bool aForSTARTTLS);
   nsresult GetForSTARTTLS(bool *aForSTARTTLS);
 
@@ -51,16 +59,18 @@ public:
                 const nsNSSShutDownPreventionLock & proofOfLock);
   
   void SetNegotiatedNPN(const char *value, uint32_t length);
   void SetHandshakeCompleted();
 
   bool GetJoined() { return mJoined; }
   void SetSentClientCert() { mSentClientCert = true; }
   
+  mozilla::psm::SharedSSLState& SharedState();
+
   // XXX: These are only used on for diagnostic purposes
   enum CertVerificationState {
     before_cert_verification,
     waiting_for_cert_verification,
     after_cert_verification
   };
   void SetCertVerificationWaiting();
   // Use errorCode == 0 to indicate success; in that case, errorMessageType is
@@ -78,16 +88,17 @@ public:
   void SetSSL3Enabled(bool enabled) { mSSL3Enabled = enabled; }
   bool IsTLSEnabled() const { return mTLSEnabled; }
   void SetTLSEnabled(bool enabled) { mTLSEnabled = enabled; }
 private:
   PRFileDesc* mFd;
 
   CertVerificationState mCertVerificationState;
 
+  mozilla::psm::SharedSSLState& mSharedState;
   bool mForSTARTTLS;
   bool mSSL3Enabled;
   bool mTLSEnabled;
   bool mHandshakePending;
   bool mHasCleartextPhase;
   bool mHandshakeInProgress;
   bool mAllowTLSIntoleranceTimeout;
   bool mRememberClientAuthCertificate;
@@ -104,47 +115,54 @@ private:
 
   uint32_t mProviderFlags;
   mozilla::TimeStamp mSocketCreationTimestamp;
 };
 
 class nsSSLIOLayerHelpers
 {
 public:
-  static nsresult Init();
-  static void Cleanup();
+  nsSSLIOLayerHelpers();
+  ~nsSSLIOLayerHelpers();
+
+  nsresult Init();
+  void Cleanup();
 
   static bool nsSSLIOLayerInitialized;
   static PRDescIdentity nsSSLIOLayerIdentity;
   static PRIOMethods nsSSLIOLayerMethods;
 
-  static mozilla::Mutex *mutex;
-  static nsTHashtable<nsCStringHashKey> *mTLSIntolerantSites;
-  static nsTHashtable<nsCStringHashKey> *mTLSTolerantSites;
+  mozilla::Mutex *mutex;
+  nsTHashtable<nsCStringHashKey> *mTLSIntolerantSites;
+  nsTHashtable<nsCStringHashKey> *mTLSTolerantSites;
 
-  static nsTHashtable<nsCStringHashKey> *mRenegoUnrestrictedSites;
-  static bool mTreatUnsafeNegotiationAsBroken;
-  static int32_t mWarnLevelMissingRFC5746;
+  nsTHashtable<nsCStringHashKey> *mRenegoUnrestrictedSites;
+  bool mTreatUnsafeNegotiationAsBroken;
+  int32_t mWarnLevelMissingRFC5746;
 
-  static void setTreatUnsafeNegotiationAsBroken(bool broken);
-  static bool treatUnsafeNegotiationAsBroken();
+  void setTreatUnsafeNegotiationAsBroken(bool broken);
+  bool treatUnsafeNegotiationAsBroken();
 
-  static void setWarnLevelMissingRFC5746(int32_t level);
-  static int32_t getWarnLevelMissingRFC5746();
+  void setWarnLevelMissingRFC5746(int32_t level);
+  int32_t getWarnLevelMissingRFC5746();
 
   static void getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key);
-  static bool rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo);
-  static void rememberTolerantSite(nsNSSSocketInfo *socketInfo);
+  bool rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo);
+  void rememberTolerantSite(nsNSSSocketInfo *socketInfo);
+
+  void addIntolerantSite(const nsCString &str);
+  void removeIntolerantSite(const nsCString &str);
+  bool isKnownAsIntolerantSite(const nsCString &str);
 
-  static void addIntolerantSite(const nsCString &str);
-  static void removeIntolerantSite(const nsCString &str);
-  static bool isKnownAsIntolerantSite(const nsCString &str);
+  void setRenegoUnrestrictedSites(const nsCString &str);
+  bool isRenegoUnrestrictedSite(const nsCString &str);
 
-  static void setRenegoUnrestrictedSites(const nsCString &str);
-  static bool isRenegoUnrestrictedSite(const nsCString &str);
+  void clearStoredData();
+private:
+  nsCOMPtr<nsIObserver> mPrefObserver;
 };
 
 nsresult nsSSLIOLayerNewSocket(int32_t family,
                                const char *host,
                                int32_t port,
                                const char *proxyHost,
                                int32_t proxyPort,
                                PRFileDesc **fd,
--- a/security/manager/ssl/src/nsNSSModule.cpp
+++ b/security/manager/ssl/src/nsNSSModule.cpp
@@ -33,17 +33,16 @@
 #include "nsICategoryManager.h"
 #include "nsCRLManager.h"
 #include "nsNTLMAuthModule.h"
 #include "nsStreamCipher.h"
 #include "nsKeyModule.h"
 #include "nsDataSignatureVerifier.h"
 #include "nsCertOverrideService.h"
 #include "nsRandomGenerator.h"
-#include "nsRecentBadCerts.h"
 #include "nsSSLStatus.h"
 #include "TransportSecurityInfo.h"
 #include "NSSErrorsService.h"
 #include "nsNSSVersion.h"
 
 #include "nsXULAppAPI.h"
 #define NS_IS_PROCESS_DEFAULT                                                 \
     (GeckoProcessType_Default == XRE_GetProcessType())
@@ -199,17 +198,16 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHash)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHMAC)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsStreamCipher)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObject)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObjectFactory)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsDataSignatureVerifier)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsCertOverrideService, Init)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsRandomGenerator)
-NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsRecentBadCertsService, Init)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, nsSSLStatus)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, TransportSecurityInfo)
 
 typedef mozilla::psm::NSSErrorsService NSSErrorsService;
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NSSErrorsService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSVersion)
 
 NS_DEFINE_NAMED_CID(NS_NSSCOMPONENT_CID);
@@ -238,17 +236,16 @@ NS_DEFINE_NAMED_CID(NS_CERT_PICKER_CID);
 NS_DEFINE_NAMED_CID(NS_CRLMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_NTLMAUTHMODULE_CID);
 NS_DEFINE_NAMED_CID(NS_STREAMCIPHER_CID);
 NS_DEFINE_NAMED_CID(NS_KEYMODULEOBJECT_CID);
 NS_DEFINE_NAMED_CID(NS_KEYMODULEOBJECTFACTORY_CID);
 NS_DEFINE_NAMED_CID(NS_DATASIGNATUREVERIFIER_CID);
 NS_DEFINE_NAMED_CID(NS_CERTOVERRIDE_CID);
 NS_DEFINE_NAMED_CID(NS_RANDOMGENERATOR_CID);
-NS_DEFINE_NAMED_CID(NS_RECENTBADCERTS_CID);
 NS_DEFINE_NAMED_CID(NS_SSLSTATUS_CID);
 NS_DEFINE_NAMED_CID(TRANSPORTSECURITYINFO_CID);
 NS_DEFINE_NAMED_CID(NS_NSSERRORSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_NSSVERSION_CID);
 
 static const mozilla::Module::CIDEntry kNSSCIDs[] = {
   { &kNS_NSSCOMPONENT_CID, false, nullptr, nsNSSComponentConstructor },
   { &kNS_SSLSOCKETPROVIDER_CID, false, nullptr, nsSSLSocketProviderConstructor },
@@ -276,17 +273,16 @@ static const mozilla::Module::CIDEntry k
   { &kNS_CRLMANAGER_CID, false, nullptr, nsCRLManagerConstructor },
   { &kNS_NTLMAUTHMODULE_CID, false, nullptr, nsNTLMAuthModuleConstructor },
   { &kNS_STREAMCIPHER_CID, false, nullptr, nsStreamCipherConstructor },
   { &kNS_KEYMODULEOBJECT_CID, false, nullptr, nsKeyObjectConstructor },
   { &kNS_KEYMODULEOBJECTFACTORY_CID, false, nullptr, nsKeyObjectFactoryConstructor },
   { &kNS_DATASIGNATUREVERIFIER_CID, false, nullptr, nsDataSignatureVerifierConstructor },
   { &kNS_CERTOVERRIDE_CID, false, nullptr, nsCertOverrideServiceConstructor },
   { &kNS_RANDOMGENERATOR_CID, false, nullptr, nsRandomGeneratorConstructor },
-  { &kNS_RECENTBADCERTS_CID, false, nullptr, nsRecentBadCertsServiceConstructor },
   { &kNS_SSLSTATUS_CID, false, nullptr, nsSSLStatusConstructor },
   { &kTRANSPORTSECURITYINFO_CID, false, nullptr, TransportSecurityInfoConstructor },
   { &kNS_NSSERRORSSERVICE_CID, false, nullptr, NSSErrorsServiceConstructor },
   { &kNS_NSSVERSION_CID, false, nullptr, nsNSSVersionConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kNSSContracts[] = {
@@ -319,17 +315,16 @@ static const mozilla::Module::ContractID
   { NS_CRYPTO_FIPSINFO_SERVICE_CONTRACTID, &kNS_PKCS11MODULEDB_CID },
   { NS_NTLMAUTHMODULE_CONTRACTID, &kNS_NTLMAUTHMODULE_CID },
   { NS_STREAMCIPHER_CONTRACTID, &kNS_STREAMCIPHER_CID },
   { NS_KEYMODULEOBJECT_CONTRACTID, &kNS_KEYMODULEOBJECT_CID },
   { NS_KEYMODULEOBJECTFACTORY_CONTRACTID, &kNS_KEYMODULEOBJECTFACTORY_CID },
   { NS_DATASIGNATUREVERIFIER_CONTRACTID, &kNS_DATASIGNATUREVERIFIER_CID },
   { NS_CERTOVERRIDE_CONTRACTID, &kNS_CERTOVERRIDE_CID },
   { NS_RANDOMGENERATOR_CONTRACTID, &kNS_RANDOMGENERATOR_CID },
-  { NS_RECENTBADCERTS_CONTRACTID, &kNS_RECENTBADCERTS_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kNSSCategories[] = {
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-ca-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-server-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-user-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-email-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
--- a/security/manager/ssl/src/nsRecentBadCerts.cpp
+++ b/security/manager/ssl/src/nsRecentBadCerts.cpp
@@ -1,52 +1,67 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
 
 #include "nsRecentBadCerts.h"
 #include "nsIX509Cert.h"
+#include "nsIObserverService.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/Services.h"
 #include "nsSSLStatus.h"
 #include "nsCOMPtr.h"
 #include "nsNSSCertificate.h"
 #include "nsCRT.h"
 #include "nsPromiseFlatString.h"
 #include "nsStringBuffer.h"
 #include "nspr.h"
 #include "pk11pub.h"
 #include "certdb.h"
 #include "sechash.h"
 
 using namespace mozilla;
 
-NS_IMPL_THREADSAFE_ISUPPORTS1(nsRecentBadCertsService, 
-                              nsIRecentBadCertsService)
+NS_IMPL_THREADSAFE_ISUPPORTS2(nsRecentBadCerts,
+                              nsIRecentBadCerts,
+                              nsIObserver)
 
-nsRecentBadCertsService::nsRecentBadCertsService()
-:monitor("nsRecentBadCertsService.monitor")
+nsRecentBadCerts::nsRecentBadCerts()
+:monitor("nsRecentBadCerts.monitor")
 ,mNextStorePosition(0)
 {
 }
 
-nsRecentBadCertsService::~nsRecentBadCertsService()
+nsRecentBadCerts::~nsRecentBadCerts()
 {
 }
 
-nsresult
-nsRecentBadCertsService::Init()
+void
+nsRecentBadCerts::InitPrivateBrowsingObserver()
 {
+  nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+  obsSvc->AddObserver(this, "last-pb-context-exited", false);
+}
+
+NS_IMETHODIMP
+nsRecentBadCerts::Observe(nsISupports     *aSubject,
+                          const char      *aTopic,
+                          const PRUnichar *aData)
+{
+  if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
+    ResetStoredCerts();
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsRecentBadCertsService::GetRecentBadCert(const nsAString & aHostNameWithPort, 
-                                          nsISSLStatus **aStatus)
+nsRecentBadCerts::GetRecentBadCert(const nsAString & aHostNameWithPort, 
+                                   nsISSLStatus **aStatus)
 {
   NS_ENSURE_ARG_POINTER(aStatus);
   if (!aHostNameWithPort.Length())
     return NS_ERROR_INVALID_ARG;
 
   *aStatus = nullptr;
   RefPtr<nsSSLStatus> status(new nsSSLStatus());
 
@@ -96,17 +111,17 @@ nsRecentBadCertsService::GetRecentBadCer
     *aStatus = status;
     NS_IF_ADDREF(*aStatus);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsRecentBadCertsService::AddBadCert(const nsAString &hostWithPort, 
+nsRecentBadCerts::AddBadCert(const nsAString &hostWithPort, 
                                     nsISSLStatus *aStatus)
 {
   NS_ENSURE_ARG(aStatus);
 
   nsCOMPtr<nsIX509Cert> cert;
   nsresult rv;
   rv = aStatus->GetServerCert(getter_AddRefs(cert));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -141,8 +156,18 @@ nsRecentBadCertsService::AddBadCert(cons
     updatedEntry.mDERCert = tempItem; // consume
     updatedEntry.isDomainMismatch = isDomainMismatch;
     updatedEntry.isNotValidAtThisTime = isNotValidAtThisTime;
     updatedEntry.isUntrusted = isUntrusted;
   }
 
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsRecentBadCerts::ResetStoredCerts()
+{
+  for (size_t i = 0; i < const_recently_seen_list_size; ++i) {
+    RecentBadCert &entry = mCerts[i];
+    entry.Clear();
+  }
+  return NS_OK;
+}
--- a/security/manager/ssl/src/nsRecentBadCerts.h
+++ b/security/manager/ssl/src/nsRecentBadCerts.h
@@ -6,16 +6,17 @@
 
 #ifndef __RECENTBADCERTS_H__
 #define __RECENTBADCERTS_H__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ReentrantMonitor.h"
 
 #include "nsIRecentBadCertsService.h"
+#include "nsIObserver.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 #include "cert.h"
 #include "secitem.h"
 
 class RecentBadCert
 {
 public:
@@ -49,26 +50,28 @@ public:
   bool isNotValidAtThisTime;
   bool isUntrusted;
 
 private:
   RecentBadCert(const RecentBadCert &other) MOZ_DELETE;
   RecentBadCert &operator=(const RecentBadCert &other) MOZ_DELETE;
 };
 
-class nsRecentBadCertsService MOZ_FINAL : public nsIRecentBadCertsService
+class nsRecentBadCerts MOZ_FINAL : public nsIRecentBadCerts
+                                 , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
-  NS_DECL_NSIRECENTBADCERTSSERVICE
+  NS_DECL_NSIRECENTBADCERTS
+  NS_DECL_NSIOBSERVER
 
-  nsRecentBadCertsService();
-  ~nsRecentBadCertsService();
+  nsRecentBadCerts();
+  ~nsRecentBadCerts();
 
-  nsresult Init();
+  void InitPrivateBrowsingObserver();
 
 protected:
     mozilla::ReentrantMonitor monitor;
 
     enum {const_recently_seen_list_size = 5};
     RecentBadCert mCerts[const_recently_seen_list_size];
 
     // will be in the range of 0 to list_size-1