bug 1339267 - re-work NSS initialization wrt thread/process etc. r?Cykesiopka,jcj draft
authorDavid Keeler <dkeeler@mozilla.com>
Thu, 09 Feb 2017 16:25:55 -0800
changeset 496059 dbd2015ac4faff4fa25b76fdf948b54902b550ae
parent 496010 56fbe9964a0bccccb6b75a2be4190f52f7a0a502
child 548537 19ef3189f280092ab6158680f667ba797941306b
push id48517
push userbmo:dkeeler@mozilla.com
push dateThu, 09 Mar 2017 19:27:20 +0000
reviewersCykesiopka, jcj
bugs1339267
milestone55.0a1
bug 1339267 - re-work NSS initialization wrt thread/process etc. r?Cykesiopka,jcj MozReview-Commit-ID: 2U4c8Xgf0bv
security/manager/ssl/moz.build
security/manager/ssl/nsCertOverrideService.cpp
security/manager/ssl/nsNSSCertificate.cpp
security/manager/ssl/nsNSSCertificate.h
security/manager/ssl/nsNSSCertificateFakeTransport.cpp
security/manager/ssl/nsNSSCertificateFakeTransport.h
security/manager/ssl/nsNSSComponent.cpp
security/manager/ssl/nsNSSComponent.h
security/manager/ssl/nsNSSModule.cpp
--- a/security/manager/ssl/moz.build
+++ b/security/manager/ssl/moz.build
@@ -106,17 +106,16 @@ UNIFIED_SOURCES += [
     'nsKeygenHandlerContent.cpp',
     'nsKeygenThread.cpp',
     'nsKeyModule.cpp',
     'nsNSSASN1Object.cpp',
     'nsNSSCallbacks.cpp',
     'nsNSSCertHelper.cpp',
     'nsNSSCertificate.cpp',
     'nsNSSCertificateDB.cpp',
-    'nsNSSCertificateFakeTransport.cpp',
     'nsNSSCertTrust.cpp',
     'nsNSSCertValidity.cpp',
     'nsNSSComponent.cpp',
     'nsNSSErrors.cpp',
     'nsNSSIOLayer.cpp',
     'nsNSSModule.cpp',
     'nsNSSShutDown.cpp',
     'nsNSSU2FToken.cpp',
--- a/security/manager/ssl/nsCertOverrideService.cpp
+++ b/security/manager/ssl/nsCertOverrideService.cpp
@@ -570,30 +570,34 @@ nsCertOverrideService::AddEntryToList(co
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCertOverrideService::ClearValidityOverride(const nsACString & aHostName, int32_t aPort)
 {
-  if (aPort == 0 &&
-      aHostName.EqualsLiteral("all:temporary-certificates")) {
+  if (!NS_IsMainThread()) {
+    return NS_ERROR_NOT_SAME_THREAD;
+  }
+
+  if (aPort == 0 && aHostName.EqualsLiteral("all:temporary-certificates")) {
     RemoveAllTemporaryOverrides();
     return NS_OK;
   }
   nsAutoCString hostPort;
   GetHostWithPort(aHostName, aPort, hostPort);
   {
     ReentrantMonitorAutoEnter lock(monitor);
     mSettingsTable.RemoveEntry(hostPort.get());
     Write();
   }
 
-  if (EnsureNSSInitialized(nssEnsure)) {
+  nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID));
+  if (nss) {
     SSL_ClearSessionCache();
   } else {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return NS_OK;
 }
 
--- a/security/manager/ssl/nsNSSCertificate.cpp
+++ b/security/manager/ssl/nsNSSCertificate.cpp
@@ -30,17 +30,16 @@
 #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
 #include "nsPK11TokenDB.h"
 #include "nsPKCS12Blob.h"
 #include "nsProxyRelease.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "nsUnicharUtils.h"
-#include "nsXULAppAPI.h"
 #include "nspr.h"
 #include "pkix/pkixnss.h"
 #include "pkix/pkixtypes.h"
 #include "pkix/Result.h"
 #include "prerror.h"
 #include "prmem.h"
 #include "secasn1.h"
 #include "secder.h"
@@ -67,33 +66,25 @@ NS_IMPL_ISUPPORTS(nsNSSCertificate,
                   nsISerializable,
                   nsIClassInfo)
 
 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
 
 /*static*/ nsNSSCertificate*
 nsNSSCertificate::Create(CERTCertificate* cert)
 {
-  if (GeckoProcessType_Default != XRE_GetProcessType()) {
-    NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
-    return nullptr;
-  }
   if (cert)
     return new nsNSSCertificate(cert);
   else
     return new nsNSSCertificate();
 }
 
 nsNSSCertificate*
 nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
 {
-  // On non-chrome process prevent instantiation
-  if (GeckoProcessType_Default != XRE_GetProcessType())
-    return nullptr;
-
   nsNSSCertificate* newObject = nsNSSCertificate::Create();
   if (newObject && !newObject->InitFromDER(certDER, derLen)) {
     delete newObject;
     newObject = nullptr;
   }
 
   return newObject;
 }
@@ -122,37 +113,30 @@ nsNSSCertificate::InitFromDER(char* cert
   return true;
 }
 
 nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert)
   : mCert(nullptr)
   , mPermDelete(false)
   , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
 {
-#if defined(DEBUG)
-  if (GeckoProcessType_Default != XRE_GetProcessType())
-    NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
-#endif
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return;
 
   if (cert) {
     mCert.reset(CERT_DupCertificate(cert));
   }
 }
 
 nsNSSCertificate::nsNSSCertificate()
   : mCert(nullptr)
   , mPermDelete(false)
   , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
 {
-  if (GeckoProcessType_Default != XRE_GetProcessType())
-    NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
 }
 
 nsNSSCertificate::~nsNSSCertificate()
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return;
   }
@@ -1533,17 +1517,16 @@ nsNSSCertListEnumerator::GetNext(nsISupp
   }
 
   nssCert.forget(_retval);
 
   CERT_RemoveCertListNode(node);
   return NS_OK;
 }
 
-// NB: This serialization must match that of nsNSSCertificateFakeTransport.
 NS_IMETHODIMP
 nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
 {
   NS_ENSURE_STATE(mCert);
   // This field used to be the cached EV status, but it is no longer necessary.
   nsresult rv = aStream->Write32(0);
   if (NS_FAILED(rv)) {
     return rv;
--- a/security/manager/ssl/nsNSSCertificate.h
+++ b/security/manager/ssl/nsNSSCertificate.h
@@ -30,18 +30,16 @@ class nsNSSCertificate final : public ns
                                public nsNSSShutDownObject
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIX509CERT
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
 
-  friend class nsNSSCertificateFakeTransport;
-
   explicit nsNSSCertificate(CERTCertificate* cert);
   nsNSSCertificate();
   static nsNSSCertificate* Create(CERTCertificate* cert = nullptr);
   static nsNSSCertificate* ConstructFromDER(char* certDER, int derLen);
 
   // This is a separate static method so nsNSSComponent can use it during NSS
   // initialization. Other code should probably not use it.
   static nsresult GetDbKey(const mozilla::UniqueCERTCertificate& cert,
deleted file mode 100644
--- a/security/manager/ssl/nsNSSCertificateFakeTransport.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/* -*- 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 "nsNSSCertificateFakeTransport.h"
-
-#include "mozilla/Assertions.h"
-#include "nsIClassInfoImpl.h"
-#include "nsIObjectInputStream.h"
-#include "nsIObjectOutputStream.h"
-#include "nsISupportsPrimitives.h"
-#include "nsNSSCertificate.h"
-#include "nsString.h"
-
-NS_IMPL_ISUPPORTS(nsNSSCertificateFakeTransport,
-                  nsIX509Cert,
-                  nsISerializable,
-                  nsIClassInfo)
-
-nsNSSCertificateFakeTransport::nsNSSCertificateFakeTransport()
-  : mCertSerialization(nullptr)
-{
-}
-
-nsNSSCertificateFakeTransport::~nsNSSCertificateFakeTransport()
-{
-  mCertSerialization = nullptr;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetDbKey(nsACString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetDisplayName(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetEmailAddress(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetEmailAddresses(uint32_t*, char16_t***)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::ContainsEmailAddress(const nsAString&, bool*)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetCommonName(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetOrganization(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetIssuerCommonName(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetIssuerOrganization(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetIssuerOrganizationUnit(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetIssuer(nsIX509Cert**)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetOrganizationalUnit(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetChain(nsIArray**)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetSubjectName(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetIssuerName(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetSerialNumber(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetSha256Fingerprint(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetSha1Fingerprint(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetTokenName(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetRawDER(uint32_t*, uint8_t**)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetValidity(nsIX509CertValidity**)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetKeyUsages(nsAString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetASN1Structure(nsIASN1Object**)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::Equals(nsIX509Cert*, bool*)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetSha256SubjectPublicKeyInfoDigest(nsACString&)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-// NB: This serialization must match that of nsNSSCertificate.
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::Write(nsIObjectOutputStream* aStream)
-{
-  // On a non-chrome process we don't have mCert because we lack
-  // nsNSSComponent. nsNSSCertificateFakeTransport object is used only to
-  // carry the certificate serialization.
-
-  // This serialization has to match that of nsNSSCertificate, so include this
-  // now-unused field.
-  nsresult rv = aStream->Write32(0);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  rv = aStream->Write32(mCertSerialization->len);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  return aStream->WriteByteArray(mCertSerialization->data,
-                                 mCertSerialization->len);
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::Read(nsIObjectInputStream* aStream)
-{
-  // This serialization has to match that of nsNSSCertificate, so read the (now
-  // unused) cachedEVStatus.
-  uint32_t unusedCachedEVStatus;
-  nsresult rv = aStream->Read32(&unusedCachedEVStatus);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  uint32_t len;
-  rv = aStream->Read32(&len);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsXPIDLCString str;
-  rv = aStream->ReadBytes(len, getter_Copies(str));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // On a non-chrome process we cannot instatiate mCert because we lack
-  // nsNSSComponent. nsNSSCertificateFakeTransport object is used only to
-  // carry the certificate serialization.
-  mCertSerialization =
-    mozilla::UniqueSECItem(SECITEM_AllocItem(nullptr, nullptr, len));
-  if (!mCertSerialization) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  PORT_Memcpy(mCertSerialization->data, str.Data(), len);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetInterfaces(uint32_t* count, nsIID*** array)
-{
-  *count = 0;
-  *array = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetScriptableHelper(nsIXPCScriptable** _retval)
-{
-  *_retval = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetContractID(char** aContractID)
-{
-  *aContractID = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetClassDescription(char** aClassDescription)
-{
-  *aClassDescription = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetClassID(nsCID** aClassID)
-{
-  *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
-  if (!*aClassID)
-    return NS_ERROR_OUT_OF_MEMORY;
-  return GetClassIDNoAlloc(*aClassID);
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetFlags(uint32_t* aFlags)
-{
-  *aFlags = nsIClassInfo::THREADSAFE;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
-{
-  static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
-
-  *aClassIDNoAlloc = kNSSCertificateCID;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetCertType(unsigned int*)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetIsSelfSigned(bool*)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetIsBuiltInRoot(bool*)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetAllTokenNames(unsigned int*, char16_t***)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-CERTCertificate*
-nsNSSCertificateFakeTransport::GetCert()
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return nullptr;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::ExportAsCMS(unsigned int,
-                                           unsigned int*,
-                                           unsigned char**)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertificateFakeTransport::MarkForPermDeletion()
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMPL_CLASSINFO(nsNSSCertListFakeTransport,
-                  nullptr,
-                  // inferred from nsIX509Cert
-                  nsIClassInfo::THREADSAFE,
-                  NS_X509CERTLIST_CID)
-
-NS_IMPL_ISUPPORTS_CI(nsNSSCertListFakeTransport,
-                     nsIX509CertList,
-                     nsISerializable)
-
-nsNSSCertListFakeTransport::nsNSSCertListFakeTransport()
-{
-}
-
-nsNSSCertListFakeTransport::~nsNSSCertListFakeTransport()
-{
-}
-
-NS_IMETHODIMP
-nsNSSCertListFakeTransport::AddCert(nsIX509Cert* aCert)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertListFakeTransport::DeleteCert(nsIX509Cert* aCert)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-CERTCertList*
-nsNSSCertListFakeTransport::GetRawCertList()
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return nullptr;
-}
-
-NS_IMETHODIMP
-nsNSSCertListFakeTransport::GetEnumerator(nsISimpleEnumerator**)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsNSSCertListFakeTransport::Equals(nsIX509CertList*, bool*)
-{
-  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-// NB: This serialization must match that of nsNSSCertList.
-NS_IMETHODIMP
-nsNSSCertListFakeTransport::Write(nsIObjectOutputStream* aStream)
-{
-  uint32_t certListLen = mFakeCertList.length();
-  // Write the length of the list
-  nsresult rv = aStream->Write32(certListLen);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  for (size_t i = 0; i < certListLen; i++) {
-    nsCOMPtr<nsIX509Cert> cert = mFakeCertList[i];
-    nsCOMPtr<nsISerializable> serializableCert = do_QueryInterface(cert);
-    rv = aStream->WriteCompoundObject(serializableCert,
-                                      NS_GET_IID(nsIX509Cert), true);
-    if (NS_FAILED(rv)) {
-      break;
-    }
-  }
-
-  return rv;
-}
-
-NS_IMETHODIMP
-nsNSSCertListFakeTransport::Read(nsIObjectInputStream* aStream)
-{
-  uint32_t certListLen;
-  nsresult rv = aStream->Read32(&certListLen);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  for (uint32_t i = 0; i < certListLen; i++) {
-    nsCOMPtr<nsISupports> certSupports;
-    rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
-    if (NS_FAILED(rv)) {
-      break;
-    }
-
-    nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
-    if (!mFakeCertList.append(cert)) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-  }
-
-  return rv;
-}
deleted file mode 100644
--- a/security/manager/ssl/nsNSSCertificateFakeTransport.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- 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/. */
-
-#ifndef nsNSSCertificateFakeTransport_h
-#define nsNSSCertificateFakeTransport_h
-
-#include "ScopedNSSTypes.h"
-#include "mozilla/Vector.h"
-#include "nsCOMPtr.h"
-#include "nsIClassInfo.h"
-#include "nsISerializable.h"
-#include "nsIX509Cert.h"
-#include "nsIX509CertList.h"
-#include "secitem.h"
-
-class nsNSSCertificateFakeTransport : public nsIX509Cert,
-                                      public nsISerializable,
-                                      public nsIClassInfo
-{
-public:
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSIX509CERT
-  NS_DECL_NSISERIALIZABLE
-  NS_DECL_NSICLASSINFO
-
-  nsNSSCertificateFakeTransport();
-
-protected:
-  virtual ~nsNSSCertificateFakeTransport();
-
-private:
-  mozilla::UniqueSECItem mCertSerialization;
-};
-
-class nsNSSCertListFakeTransport : public nsIX509CertList,
-                                   public nsISerializable
-{
-public:
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSIX509CERTLIST
-  NS_DECL_NSISERIALIZABLE
-
-  nsNSSCertListFakeTransport();
-
-protected:
-  virtual ~nsNSSCertListFakeTransport();
-
-private:
-  mozilla::Vector<nsCOMPtr<nsIX509Cert> > mFakeCertList;
-};
-
-#endif // nsNSSCertificateFakeTransport_h
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -74,28 +74,18 @@ using namespace mozilla::psm;
 LazyLogModule gPIPNSSLog("pipnss");
 
 int nsNSSComponent::mInstanceCount = 0;
 
 // This function can be called from chrome or content processes
 // to ensure that NSS is initialized.
 bool EnsureNSSInitializedChromeOrContent()
 {
-  nsresult rv;
-  if (XRE_IsParentProcess()) {
-    nsCOMPtr<nsISupports> nss = do_GetService(PSM_COMPONENT_CONTRACTID, &rv);
-    if (NS_FAILED(rv)) {
-      return false;
-    }
-
-    return true;
-  }
-
-  // If this is a content process and not the main thread (i.e. probably a
-  // worker) then forward this call to the main thread.
+  // If this is not the main thread (i.e. probably a worker) then forward this
+  // call to the main thread.
   if (!NS_IsMainThread()) {
     static Atomic<bool> initialized(false);
 
     // Cache the result to dispatch to the main thread only once per worker.
     if (initialized) {
       return true;
     }
 
@@ -110,110 +100,40 @@ bool EnsureNSSInitializedChromeOrContent
       new SyncRunnable(NS_NewRunnableFunction([]() {
         initialized = EnsureNSSInitializedChromeOrContent();
       }))
     );
 
     return initialized;
   }
 
+  if (XRE_IsParentProcess()) {
+    nsCOMPtr<nsISupports> nss = do_GetService(PSM_COMPONENT_CONTRACTID);
+    if (!nss) {
+      return false;
+    }
+    return true;
+  }
+
   if (NSS_IsInitialized()) {
     return true;
   }
 
   if (NSS_NoDB_Init(nullptr) != SECSuccess) {
     return false;
   }
 
   if (NS_FAILED(mozilla::psm::InitializeCipherSuite())) {
     return false;
   }
 
   mozilla::psm::DisableMD5();
   return true;
 }
 
-// We must ensure that the nsNSSComponent has been loaded before
-// creating any other components.
-bool EnsureNSSInitialized(EnsureNSSOperator op)
-{
-  if (GeckoProcessType_Default != XRE_GetProcessType())
-  {
-    if (op == nssEnsureOnChromeOnly)
-    {
-      // If the component needs PSM/NSS initialized only on the chrome process,
-      // pretend we successfully initiated it but in reality we bypass it.
-      // It's up to the programmer to check for process type in such components
-      // and take care not to call anything that needs NSS/PSM initiated.
-      return true;
-    }
-
-    NS_ERROR("Trying to initialize PSM/NSS in a non-chrome process!");
-    return false;
-  }
-
-  static bool loading = false;
-  static int32_t haveLoaded = 0;
-
-  switch (op)
-  {
-    // In following 4 cases we are protected by monitor of XPCOM component
-    // manager - we are inside of do_GetService call for nss component, so it is
-    // safe to move with the flags here.
-  case nssLoadingComponent:
-    if (loading)
-      return false; // We are reentered during nss component creation
-    loading = true;
-    return true;
-
-  case nssInitSucceeded:
-    MOZ_ASSERT(loading, "Bad call to EnsureNSSInitialized(nssInitSucceeded)");
-    loading = false;
-    PR_AtomicSet(&haveLoaded, 1);
-    return true;
-
-  case nssInitFailed:
-    MOZ_ASSERT(loading, "Bad call to EnsureNSSInitialized(nssInitFailed)");
-    loading = false;
-    MOZ_FALLTHROUGH;
-
-  case nssShutdown:
-    PR_AtomicSet(&haveLoaded, 0);
-    return false;
-
-    // In this case we are called from a component to ensure nss initilization.
-    // If the component has not yet been loaded and is not currently loading
-    // call do_GetService for nss component to ensure it.
-  case nssEnsure:
-  case nssEnsureOnChromeOnly:
-  case nssEnsureChromeOrContent:
-    // We are reentered during nss component creation or nss component is already up
-    if (PR_AtomicAdd(&haveLoaded, 0) || loading)
-      return true;
-
-    {
-    nsCOMPtr<nsINSSComponent> nssComponent
-      = do_GetService(PSM_COMPONENT_CONTRACTID);
-
-    // Nss component failed to initialize, inform the caller of that fact.
-    // Flags are appropriately set by component constructor itself.
-    if (!nssComponent)
-      return false;
-
-    bool isInitialized;
-    nsresult rv = nssComponent->IsNSSInitialized(&isInitialized);
-    return NS_SUCCEEDED(rv) && isInitialized;
-    }
-
-  default:
-    MOZ_ASSERT_UNREACHABLE("Bad operator to EnsureNSSInitialized");
-    return false;
-  }
-}
-
 static void
 GetRevocationBehaviorFromPrefs(/*out*/ CertVerifier::OcspDownloadConfig* odc,
                                /*out*/ CertVerifier::OcspStrictConfig* osc,
                                /*out*/ CertVerifier::OcspGetConfig* ogc,
                                /*out*/ uint32_t* certShortLifetimeInDays,
                                const MutexAutoLock& /*proofOfLock*/)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -274,20 +194,16 @@ nsNSSComponent::~nsNSSComponent()
   // All cleanup code requiring services needs to happen in xpcom_shutdown
 
   ShutdownNSS();
   SharedSSLState::GlobalCleanup();
   RememberCertErrorsTable::Cleanup();
   --mInstanceCount;
   nsNSSShutDownList::shutdown();
 
-  // We are being freed, drop the haveLoaded flag to re-enable
-  // potential nss initialization later.
-  EnsureNSSInitialized(nssShutdown);
-
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::dtor finished\n"));
 }
 
 NS_IMETHODIMP
 nsNSSComponent::PIPBundleFormatStringFromName(const char* name,
                                               const char16_t** params,
                                               uint32_t numParams,
                                               nsAString& outString)
@@ -1691,35 +1607,26 @@ GetNSSProfilePath(nsAutoCString& aProfil
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
           ("NSS profile at '%s'\n", aProfilePath.get()));
   return NS_OK;
 }
 
 nsresult
 nsNSSComponent::InitializeNSS()
 {
-  // Can be called both during init and profile change.
-  // Needs mutex protection.
-
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::InitializeNSS\n"));
 
   static_assert(nsINSSErrorsService::NSS_SEC_ERROR_BASE == SEC_ERROR_BASE &&
                 nsINSSErrorsService::NSS_SEC_ERROR_LIMIT == SEC_ERROR_LIMIT &&
                 nsINSSErrorsService::NSS_SSL_ERROR_BASE == SSL_ERROR_BASE &&
                 nsINSSErrorsService::NSS_SSL_ERROR_LIMIT == SSL_ERROR_LIMIT,
                 "You must update the values in nsINSSErrorsService.idl");
 
   MutexAutoLock lock(mutex);
 
-  if (mNSSInitialized) {
-    // We should never try to initialize NSS more than once in a process.
-    MOZ_ASSERT_UNREACHABLE("Trying to initialize NSS twice");
-    return NS_ERROR_FAILURE;
-  }
-
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization beginning\n"));
 
   // 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.
 
@@ -1780,18 +1687,16 @@ nsNSSComponent::InitializeNSS()
     MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("could not initialize NSS - panicking\n"));
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // ensure we have an initial value for the content signer root
   mContentSigningRootHash =
     Preferences::GetString("security.content.signature.root_hash");
 
-  mNSSInitialized = true;
-
   PK11_SetPasswordFunc(PK11PasswordPrompt);
 
   SharedSSLState::GlobalInit();
 
   // Register an observer so we can inform NSS when these prefs change
   Preferences::AddStrongObserver(this, "security.");
 
   SSL_OptionSetDefault(SSL_ENABLE_SSL2, false);
@@ -1852,60 +1757,37 @@ nsNSSComponent::InitializeNSS()
   // little excessive as there probably won't be that many clients connecting to
   // any TLSServerSockets the browser runs.)
   // Note that this must occur before any calls to SSL_ClearSessionCache
   // (otherwise memory will leak).
   if (SSL_ConfigServerSessionIDCache(1000, 0, 0, nullptr) != SECSuccess) {
     return NS_ERROR_FAILURE;
   }
 
-  // ensure the CertBlocklist is initialised
-  nsCOMPtr<nsICertBlocklist> certList = do_GetService(NS_CERTBLOCKLIST_CONTRACTID);
-  if (!certList) {
-    return NS_ERROR_FAILURE;
-  }
-
   // dynamic options from prefs
   setValidationOptions(true, lock);
 
 #ifndef MOZ_NO_SMART_CARDS
   LaunchSmartCardThreads();
 #endif
 
   mozilla::pkix::RegisterErrorTable();
 
-  // Initialize the site security service
-  nsCOMPtr<nsISiteSecurityService> sssService =
-    do_GetService(NS_SSSERVICE_CONTRACTID);
-  if (!sssService) {
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Cannot initialize site security service\n"));
-    return NS_ERROR_FAILURE;
-  }
-
-  // Initialize the cert override service
-  nsCOMPtr<nsICertOverrideService> coService =
-    do_GetService(NS_CERTOVERRIDE_CONTRACTID);
-  if (!coService) {
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Cannot initialize cert override service\n"));
-    return NS_ERROR_FAILURE;
-  }
-
   if (PK11_IsFIPS()) {
     Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
   }
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
+  mNSSInitialized = true;
+
   return NS_OK;
 }
 
 void
 nsNSSComponent::ShutdownNSS()
 {
-  // Can be called both during init and profile change,
-  // needs mutex protection.
-
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::ShutdownNSS\n"));
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   MutexAutoLock lock(mutex);
 
   if (mNSSInitialized) {
     mNSSInitialized = false;
 
@@ -1927,38 +1809,40 @@ nsNSSComponent::ShutdownNSS()
     Unused << SSL_ShutdownServerSessionIDCache();
 
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("evaporating psm resources"));
     if (NS_FAILED(nsNSSShutDownList::evaporateAllNSSResources())) {
       MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("failed to evaporate resources"));
       return;
     }
     UnloadLoadableRoots();
-    EnsureNSSInitialized(nssShutdown);
     if (SECSuccess != ::NSS_Shutdown()) {
       MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("NSS SHUTDOWN FAILURE"));
     } else {
       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS shutdown =====>> OK <<====="));
     }
   }
 }
 
 nsresult
 nsNSSComponent::Init()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (!NS_IsMainThread()) {
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
-  nsresult rv = NS_OK;
+  MOZ_ASSERT(XRE_IsParentProcess());
+  if (!XRE_IsParentProcess()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Beginning NSS initialization\n"));
 
-  rv = InitializePIPNSSBundle();
+  nsresult rv = InitializePIPNSSBundle();
   if (NS_FAILED(rv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("Unable to create pipnss bundle.\n"));
     return rv;
   }
 
   // Access our string bundles now, this prevents assertions from I/O
   // - nsStandardURL not thread-safe
   // - wrong thread: 'NS_IsMainThread()' in nsIOService.cpp
@@ -1993,17 +1877,17 @@ NS_IMPL_ISUPPORTS(nsNSSComponent,
 static const char* const PROFILE_BEFORE_CHANGE_TOPIC = "profile-before-change";
 
 NS_IMETHODIMP
 nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
                         const char16_t* someData)
 {
   if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("receiving profile change topic\n"));
-    DoProfileBeforeChange();
+    ShutdownNSS();
   } else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
     nsNSSShutDownPreventionLock locker;
     bool clearSessionCache = true;
     NS_ConvertUTF16toUTF8  prefName(someData);
 
     if (prefName.EqualsLiteral("security.tls.version.min") ||
         prefName.EqualsLiteral("security.tls.version.max")) {
       (void) setEnabledTLSVersions();
@@ -2141,45 +2025,16 @@ nsNSSComponent::RegisterObservers()
   // Using false for the ownsweak parameter means the observer service will
   // keep a strong reference to this component. As a result, this will live at
   // least as long as the observer service.
   observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, false);
 
   return NS_OK;
 }
 
-void
-nsNSSComponent::DoProfileBeforeChange()
-{
-  bool needsCleanup = true;
-
-  {
-    MutexAutoLock lock(mutex);
-
-    if (!mNSSInitialized) {
-      // Make sure we don't try to cleanup if we have already done so.
-      // This makes sure we behave safely, in case we are notified
-      // multiple times.
-      needsCleanup = false;
-    }
-  }
-
-  if (needsCleanup) {
-    ShutdownNSS();
-  }
-}
-
-NS_IMETHODIMP
-nsNSSComponent::IsNSSInitialized(bool* initialized)
-{
-  MutexAutoLock lock(mutex);
-  *initialized = mNSSInitialized;
-  return NS_OK;
-}
-
 #ifdef DEBUG
 NS_IMETHODIMP
 nsNSSComponent::IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result)
 {
   MutexAutoLock lock(mutex);
   MOZ_ASSERT(mNSSInitialized);
 
   result = false;
--- a/security/manager/ssl/nsNSSComponent.h
+++ b/security/manager/ssl/nsNSSComponent.h
@@ -42,31 +42,18 @@ MOZ_MUST_USE
 {0x4cb64dfd, 0xca98, 0x4e24, {0xbe, 0xfd, 0x0d, 0x92, 0x85, 0xa3, 0x3b, 0xcb}}
 
 #define PSM_COMPONENT_CONTRACTID "@mozilla.org/psm;1"
 
 #define NS_INSSCOMPONENT_IID \
   { 0xa0a8f52b, 0xea18, 0x4abc, \
     { 0xa3, 0xca, 0xec, 0xcf, 0x70, 0x4f, 0xfe, 0x63 } }
 
-enum EnsureNSSOperator
-{
-  nssLoadingComponent = 0,
-  nssInitSucceeded = 1,
-  nssInitFailed = 2,
-  nssShutdown = 3,
-  nssEnsure = 100,
-  nssEnsureOnChromeOnly = 101,
-  nssEnsureChromeOrContent = 102,
-};
-
 extern bool EnsureNSSInitializedChromeOrContent();
 
-extern bool EnsureNSSInitialized(EnsureNSSOperator op);
-
 class NS_NO_VTABLE nsINSSComponent : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_INSSCOMPONENT_IID)
 
   NS_IMETHOD ShowAlertFromStringBundle(const char* messageID) = 0;
 
   NS_IMETHOD GetPIPNSSBundleString(const char* name,
@@ -82,18 +69,16 @@ public:
   NS_IMETHOD LogoutAuthenticatedPK11() = 0;
 
 #ifndef MOZ_NO_SMART_CARDS
   NS_IMETHOD LaunchSmartCardThread(SECMODModule* module) = 0;
 
   NS_IMETHOD ShutdownSmartCardThread(SECMODModule* module) = 0;
 #endif
 
-  NS_IMETHOD IsNSSInitialized(bool* initialized) = 0;
-
 #ifdef DEBUG
   NS_IMETHOD IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result) = 0;
 #endif
 
   NS_IMETHOD IsCertContentSigningRoot(CERTCertificate* cert, bool& result) = 0;
 
 #ifdef XP_WIN
   NS_IMETHOD GetEnterpriseRoots(nsIX509CertList** enterpriseRoots) = 0;
@@ -139,18 +124,16 @@ public:
   NS_IMETHOD ShutdownSmartCardThread(SECMODModule* module) override;
   void LaunchSmartCardThreads();
   void ShutdownSmartCardThreads();
   nsresult DispatchEventToWindow(nsIDOMWindow* domWin,
                                  const nsAString& eventType,
                                  const nsAString& token);
 #endif
 
-  NS_IMETHOD IsNSSInitialized(bool* initialized) override;
-
 #ifdef DEBUG
   NS_IMETHOD IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result) override;
 #endif
 
   NS_IMETHOD IsCertContentSigningRoot(CERTCertificate* cert, bool& result) override;
 
 #ifdef XP_WIN
   NS_IMETHOD GetEnterpriseRoots(nsIX509CertList** enterpriseRoots) override;
@@ -179,18 +162,16 @@ private:
   void UnloadLoadableRoots();
   void setValidationOptions(bool isInitialSetting,
                             const mozilla::MutexAutoLock& lock);
   nsresult setEnabledTLSVersions();
   nsresult InitializePIPNSSBundle();
   nsresult ConfigureInternalPKCS11Token();
   nsresult RegisterObservers();
 
-  void DoProfileBeforeChange();
-
   void MaybeEnableFamilySafetyCompatibility();
   void MaybeImportEnterpriseRoots();
 #ifdef XP_WIN
   void ImportEnterpriseRootsForLocation(DWORD locationFlag);
   nsresult MaybeImportFamilySafetyRoot(PCCERT_CONTEXT certificate,
                                        bool& wasFamilySafetyRoot);
   nsresult LoadFamilySafetyRoot();
   void UnloadFamilySafetyRoot();
--- a/security/manager/ssl/nsNSSModule.cpp
+++ b/security/manager/ssl/nsNSSModule.cpp
@@ -17,17 +17,16 @@
 #include "nsCryptoHash.h"
 #include "nsDOMCID.h" // For the NS_CRYPTO_CONTRACTID define
 #include "nsDataSignatureVerifier.h"
 #include "nsICategoryManager.h"
 #include "nsKeyModule.h"
 #include "nsKeygenHandler.h"
 #include "nsNSSCertificate.h"
 #include "nsNSSCertificateDB.h"
-#include "nsNSSCertificateFakeTransport.h"
 #include "nsNSSComponent.h"
 #include "nsNSSU2FToken.h"
 #include "nsNSSVersion.h"
 #include "nsNTLMAuthModule.h"
 #include "nsNetCID.h"
 #include "nsPK11TokenDB.h"
 #include "nsPKCS11Slot.h"
 #include "nsRandomGenerator.h"
@@ -39,102 +38,105 @@
 #include "nsXULAppAPI.h"
 
 #ifdef MOZ_XUL
 #include "nsCertTree.h"
 #endif
 
 namespace mozilla { namespace psm {
 
-MOZ_ALWAYS_INLINE static bool IsProcessDefault()
-{
-  return XRE_GetProcessType() == GeckoProcessType_Default;
-}
+// Many of the implementations in this module call NSS functions and as a result
+// require that PSM has successfully initialized NSS before being used.
+// Additionally, some of the implementations have various restrictions on which
+// process and threads they can be used on (e.g. some can only be used in the
+// parent process and some must be initialized only on the main thread).
+// The following initialization framework allows these requirements to be
+// succinctly expressed and implemented.
 
 template<class InstanceClass, nsresult (InstanceClass::*InitMethod)()>
 MOZ_ALWAYS_INLINE static nsresult
 Instantiate(REFNSIID aIID, void** aResult)
 {
   InstanceClass* inst = new InstanceClass();
   NS_ADDREF(inst);
   nsresult rv = InitMethod != nullptr ? (inst->*InitMethod)() : NS_OK;
   if (NS_SUCCEEDED(rv)) {
     rv = inst->QueryInterface(aIID, aResult);
   }
   NS_RELEASE(inst);
   return rv;
 }
 
-template<EnsureNSSOperator ensureOperator, class InstanceClass,
-         nsresult (InstanceClass::*InitMethod)() = nullptr>
+enum class ThreadRestriction {
+  // must be initialized on the main thread (but can be used on any thread)
+  MainThreadOnly,
+  // can be initialized and used on any thread
+  AnyThread,
+};
+
+enum class ProcessRestriction {
+  ParentProcessOnly,
+  AnyProcess,
+};
+
+template<class InstanceClass, nsresult (InstanceClass::*InitMethod)() = nullptr,
+         ProcessRestriction processRestriction = ProcessRestriction::ParentProcessOnly,
+         ThreadRestriction threadRestriction = ThreadRestriction::AnyThread>
 static nsresult
 Constructor(nsISupports* aOuter, REFNSIID aIID, void** aResult)
 {
   *aResult = nullptr;
   if (aOuter != nullptr) {
     return NS_ERROR_NO_AGGREGATION;
   }
 
-  if (ensureOperator == nssEnsureChromeOrContent &&
-      !IsProcessDefault()) {
-    if (!EnsureNSSInitializedChromeOrContent()) {
-      return NS_ERROR_FAILURE;
-    }
-  } else if (!EnsureNSSInitialized(ensureOperator)) {
+  if (processRestriction == ProcessRestriction::ParentProcessOnly &&
+      !XRE_IsParentProcess()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if (!EnsureNSSInitializedChromeOrContent()) {
     return NS_ERROR_FAILURE;
   }
 
-  nsresult rv = Instantiate<InstanceClass, InitMethod>(aIID, aResult);
+  if (threadRestriction == ThreadRestriction::MainThreadOnly &&
+      !NS_IsMainThread()) {
+
+    nsCOMPtr<nsIThread> mainThread;
+    nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
 
-  if (ensureOperator == nssLoadingComponent) {
-    if (NS_SUCCEEDED(rv)) {
-      EnsureNSSInitialized(nssInitSucceeded);
-    } else {
-      EnsureNSSInitialized(nssInitFailed);
-    }
+    // Forward to the main thread synchronously.
+    mozilla::SyncRunnable::DispatchToThread(mainThread,
+      new SyncRunnable(NS_NewRunnableFunction([&]() {
+        rv = Instantiate<InstanceClass, InitMethod>(aIID, aResult);
+      }))
+    );
+
+    return rv;
   }
 
-  return rv;
-}
-
-template<class InstanceClassChrome, class InstanceClassContent>
-MOZ_ALWAYS_INLINE static nsresult
-Constructor(nsISupports* aOuter, REFNSIID aIID, void** aResult)
-{
-  if (IsProcessDefault()) {
-    return Constructor<nssEnsureOnChromeOnly,
-                       InstanceClassChrome>(aOuter, aIID, aResult);
-  }
-
-  return Constructor<nssEnsureOnChromeOnly,
-                     InstanceClassContent>(aOuter, aIID, aResult);
-}
-
-template<class InstanceClass>
-MOZ_ALWAYS_INLINE static nsresult
-Constructor(nsISupports* aOuter, REFNSIID aIID, void** aResult)
-{
-  return Constructor<nssEnsure, InstanceClass>(aOuter, aIID, aResult);
+  return Instantiate<InstanceClass, InitMethod>(aIID, aResult);
 }
 
 } } // namespace mozilla::psm
 
 using namespace mozilla::psm;
 
 namespace {
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(PSMContentListener, init)
 
 typedef mozilla::psm::NSSErrorsService NSSErrorsService;
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NSSErrorsService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSVersion)
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCertOverrideService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSecureBrowserUIImpl)
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(CertBlocklist, Init)
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSiteSecurityService, Init)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNSSComponent, Init)
 
 NS_DEFINE_NAMED_CID(NS_NSSCOMPONENT_CID);
 NS_DEFINE_NAMED_CID(NS_SSLSOCKETPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_STARTTLSSOCKETPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_SECRETDECODERRING_CID);
 NS_DEFINE_NAMED_CID(NS_PK11TOKENDB_CID);
 NS_DEFINE_NAMED_CID(NS_PKCS11MODULEDB_CID);
 NS_DEFINE_NAMED_CID(NS_PSMCONTENTLISTEN_CID);
@@ -159,75 +161,75 @@ NS_DEFINE_NAMED_CID(NS_NSSU2FTOKEN_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);
 NS_DEFINE_NAMED_CID(NS_SECURE_BROWSER_UI_CID);
 NS_DEFINE_NAMED_CID(NS_SITE_SECURITY_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_CERT_BLOCKLIST_CID);
 
-// Use the special factory constructor for everything this module implements,
-// because all code could potentially require the NSS library.
-// Our factory constructor takes an optional EnsureNSSOperator template
-// parameter.
-// Only for the nsNSSComponent, set this to nssLoadingComponent.
-// For classes available from a content process, set this to
-// nssEnsureOnChromeOnly.
-// All other classes must have this set to nssEnsure (default).
-
 static const mozilla::Module::CIDEntry kNSSCIDs[] = {
-  { &kNS_NSSCOMPONENT_CID, false, nullptr,
-    Constructor<nssLoadingComponent, nsNSSComponent, &nsNSSComponent::Init> },
+  { &kNS_NSSCOMPONENT_CID, false, nullptr, nsNSSComponentConstructor },
   { &kNS_SSLSOCKETPROVIDER_CID, false, nullptr,
     Constructor<nsSSLSocketProvider> },
   { &kNS_STARTTLSSOCKETPROVIDER_CID, false, nullptr,
     Constructor<nsTLSSocketProvider> },
   { &kNS_SECRETDECODERRING_CID, false, nullptr,
     Constructor<SecretDecoderRing> },
   { &kNS_PK11TOKENDB_CID, false, nullptr, Constructor<nsPK11TokenDB> },
   { &kNS_PKCS11MODULEDB_CID, false, nullptr, Constructor<nsPKCS11ModuleDB> },
   { &kNS_PSMCONTENTLISTEN_CID, false, nullptr, PSMContentListenerConstructor },
   { &kNS_X509CERT_CID, false, nullptr,
-    Constructor<nsNSSCertificate, nsNSSCertificateFakeTransport> },
+    Constructor<nsNSSCertificate, nullptr, ProcessRestriction::AnyProcess> },
   { &kNS_X509CERTDB_CID, false, nullptr, Constructor<nsNSSCertificateDB> },
   { &kNS_X509CERTLIST_CID, false, nullptr,
-    Constructor<nsNSSCertList, nsNSSCertListFakeTransport> },
+    Constructor<nsNSSCertList, nullptr, ProcessRestriction::AnyProcess> },
   { &kNS_FORMPROCESSOR_CID, false, nullptr, nsKeygenFormProcessor::Create },
 #ifdef MOZ_XUL
   { &kNS_CERTTREE_CID, false, nullptr, Constructor<nsCertTree> },
 #endif
   { &kNS_PKCS11_CID, false, nullptr, Constructor<nsPkcs11> },
   { &kNS_CRYPTO_HASH_CID, false, nullptr,
-    Constructor<nssEnsureChromeOrContent, nsCryptoHash> },
+    Constructor<nsCryptoHash, nullptr, ProcessRestriction::AnyProcess> },
   { &kNS_CRYPTO_HMAC_CID, false, nullptr,
-    Constructor<nssEnsureChromeOrContent, nsCryptoHMAC> },
+    Constructor<nsCryptoHMAC, nullptr, ProcessRestriction::AnyProcess> },
   { &kNS_NTLMAUTHMODULE_CID, false, nullptr,
-    Constructor<nssEnsure, nsNTLMAuthModule, &nsNTLMAuthModule::InitTest> },
+    Constructor<nsNTLMAuthModule, &nsNTLMAuthModule::InitTest> },
   { &kNS_KEYMODULEOBJECT_CID, false, nullptr,
-    Constructor<nssEnsureChromeOrContent, nsKeyObject> },
+    Constructor<nsKeyObject, nullptr, ProcessRestriction::AnyProcess> },
   { &kNS_KEYMODULEOBJECTFACTORY_CID, false, nullptr,
-    Constructor<nssEnsureChromeOrContent, nsKeyObjectFactory> },
+    Constructor<nsKeyObjectFactory, nullptr, ProcessRestriction::AnyProcess> },
   { &kNS_DATASIGNATUREVERIFIER_CID, false, nullptr,
     Constructor<nsDataSignatureVerifier> },
   { &kNS_CONTENTSIGNATUREVERIFIER_CID, false, nullptr,
     Constructor<ContentSignatureVerifier> },
-  { &kNS_CERTOVERRIDE_CID, false, nullptr, nsCertOverrideServiceConstructor },
+  { &kNS_CERTOVERRIDE_CID, false, nullptr,
+    Constructor<nsCertOverrideService, &nsCertOverrideService::Init,
+                ProcessRestriction::ParentProcessOnly,
+                ThreadRestriction::MainThreadOnly> },
   { &kNS_RANDOMGENERATOR_CID, false, nullptr,
-    Constructor<nssEnsureChromeOrContent, nsRandomGenerator> },
+    Constructor<nsRandomGenerator, nullptr, ProcessRestriction::AnyProcess> },
   { &kNS_NSSU2FTOKEN_CID, false, nullptr,
-    Constructor<nssEnsure, nsNSSU2FToken, &nsNSSU2FToken::Init> },
+    Constructor<nsNSSU2FToken, &nsNSSU2FToken::Init> },
   { &kNS_SSLSTATUS_CID, false, nullptr,
-    Constructor<nssEnsureOnChromeOnly, nsSSLStatus> },
+    Constructor<nsSSLStatus, nullptr, ProcessRestriction::AnyProcess> },
   { &kTRANSPORTSECURITYINFO_CID, false, nullptr,
-    Constructor<nssEnsureOnChromeOnly, TransportSecurityInfo> },
+    Constructor<TransportSecurityInfo, nullptr,
+                ProcessRestriction::AnyProcess> },
   { &kNS_NSSERRORSSERVICE_CID, false, nullptr, NSSErrorsServiceConstructor },
   { &kNS_NSSVERSION_CID, false, nullptr, nsNSSVersionConstructor },
   { &kNS_SECURE_BROWSER_UI_CID, false, nullptr, nsSecureBrowserUIImplConstructor },
-  { &kNS_SITE_SECURITY_SERVICE_CID, false, nullptr, nsSiteSecurityServiceConstructor },
-  { &kNS_CERT_BLOCKLIST_CID, false, nullptr, CertBlocklistConstructor},
+  { &kNS_SITE_SECURITY_SERVICE_CID, false, nullptr,
+    Constructor<nsSiteSecurityService, &nsSiteSecurityService::Init,
+                ProcessRestriction::AnyProcess,
+                ThreadRestriction::MainThreadOnly> },
+  { &kNS_CERT_BLOCKLIST_CID, false, nullptr,
+    Constructor<CertBlocklist, &CertBlocklist::Init,
+                ProcessRestriction::ParentProcessOnly,
+                ThreadRestriction::MainThreadOnly> },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kNSSContracts[] = {
   { PSM_COMPONENT_CONTRACTID, &kNS_NSSCOMPONENT_CID },
   { NS_NSS_ERRORS_SERVICE_CONTRACTID, &kNS_NSSERRORSSERVICE_CID },
   { NS_NSSVERSION_CONTRACTID, &kNS_NSSVERSION_CID },
   { NS_SSLSOCKETPROVIDER_CONTRACTID, &kNS_SSLSOCKETPROVIDER_CID },