LCOV - code coverage report
Current view: top level - security/manager/ssl - nsNSSComponent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 209 685 30.5 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  *
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsNSSComponent.h"
       8             : 
       9             : #include "ExtendedValidation.h"
      10             : #include "NSSCertDBTrustDomain.h"
      11             : #include "PKCS11ModuleDB.h"
      12             : #include "ScopedNSSTypes.h"
      13             : #include "SharedSSLState.h"
      14             : #include "cert.h"
      15             : #include "certdb.h"
      16             : #include "mozilla/ArrayUtils.h"
      17             : #include "mozilla/Assertions.h"
      18             : #include "mozilla/Casting.h"
      19             : #include "mozilla/Preferences.h"
      20             : #include "mozilla/PodOperations.h"
      21             : #include "mozilla/PublicSSL.h"
      22             : #include "mozilla/Services.h"
      23             : #include "mozilla/StaticPtr.h"
      24             : #include "mozilla/SyncRunnable.h"
      25             : #include "mozilla/Telemetry.h"
      26             : #include "mozilla/TimeStamp.h"
      27             : #include "mozilla/Unused.h"
      28             : #include "mozilla/Vector.h"
      29             : #include "nsAppDirectoryServiceDefs.h"
      30             : #include "nsCRT.h"
      31             : #include "nsClientAuthRemember.h"
      32             : #include "nsComponentManagerUtils.h"
      33             : #include "nsDirectoryServiceDefs.h"
      34             : #include "nsICertOverrideService.h"
      35             : #include "nsIFile.h"
      36             : #include "nsILocalFileWin.h"
      37             : #include "nsIObserverService.h"
      38             : #include "nsIPrompt.h"
      39             : #include "nsIProperties.h"
      40             : #include "nsISiteSecurityService.h"
      41             : #include "nsITokenPasswordDialogs.h"
      42             : #include "nsIWindowWatcher.h"
      43             : #include "nsIXULRuntime.h"
      44             : #include "nsLiteralString.h"
      45             : #include "nsNSSCertificateDB.h"
      46             : #include "nsNSSHelper.h"
      47             : #include "nsPrintfCString.h"
      48             : #include "nsServiceManagerUtils.h"
      49             : #include "nsThreadUtils.h"
      50             : #include "nsXULAppAPI.h"
      51             : #include "nss.h"
      52             : #include "p12plcy.h"
      53             : #include "pkix/pkixnss.h"
      54             : #include "secerr.h"
      55             : #include "secmod.h"
      56             : #include "ssl.h"
      57             : #include "sslerr.h"
      58             : #include "sslproto.h"
      59             : #include "prmem.h"
      60             : 
      61             : #if defined(XP_LINUX) && !defined(ANDROID)
      62             : #include <linux/magic.h>
      63             : #include <sys/vfs.h>
      64             : #endif
      65             : 
      66             : #ifdef XP_WIN
      67             : #include "mozilla/WindowsVersion.h"
      68             : #include "nsILocalFileWin.h"
      69             : 
      70             : #include "windows.h" // this needs to be before the following includes
      71             : #include "lmcons.h"
      72             : #include "sddl.h"
      73             : #include "wincrypt.h"
      74             : #include "nsIWindowsRegKey.h"
      75             : #endif
      76             : 
      77             : using namespace mozilla;
      78             : using namespace mozilla::psm;
      79             : 
      80             : LazyLogModule gPIPNSSLog("pipnss");
      81             : 
      82             : int nsNSSComponent::mInstanceCount = 0;
      83             : 
      84             : // This function can be called from chrome or content processes
      85             : // to ensure that NSS is initialized.
      86           0 : bool EnsureNSSInitializedChromeOrContent()
      87             : {
      88             :   static Atomic<bool> initialized(false);
      89             : 
      90           0 :   if (initialized) {
      91             :     return true;
      92             :   }
      93             : 
      94             :   // If this is not the main thread (i.e. probably a worker) then forward this
      95             :   // call to the main thread.
      96           0 :   if (!NS_IsMainThread()) {
      97           0 :     nsCOMPtr<nsIThread> mainThread;
      98           0 :     nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
      99           0 :     if (NS_FAILED(rv)) {
     100             :       return false;
     101             :     }
     102             : 
     103             :     // Forward to the main thread synchronously.
     104           0 :     mozilla::SyncRunnable::DispatchToThread(
     105             :       mainThread,
     106             :       new SyncRunnable(
     107           0 :         NS_NewRunnableFunction("EnsureNSSInitializedChromeOrContent", []() {
     108           0 :           EnsureNSSInitializedChromeOrContent();
     109           0 :         })));
     110             : 
     111           0 :     return initialized;
     112             :   }
     113             : 
     114           0 :   if (XRE_IsParentProcess()) {
     115           0 :     nsCOMPtr<nsISupports> nss = do_GetService(PSM_COMPONENT_CONTRACTID);
     116           0 :     if (!nss) {
     117             :       return false;
     118             :     }
     119           0 :     initialized = true;
     120           0 :     return true;
     121             :   }
     122             : 
     123           0 :   if (NSS_IsInitialized()) {
     124           0 :     initialized = true;
     125           0 :     return true;
     126             :   }
     127             : 
     128           0 :   if (NSS_NoDB_Init(nullptr) != SECSuccess) {
     129             :     return false;
     130             :   }
     131             : 
     132           0 :   if (NS_FAILED(mozilla::psm::InitializeCipherSuite())) {
     133             :     return false;
     134             :   }
     135             : 
     136           0 :   mozilla::psm::DisableMD5();
     137           0 :   mozilla::pkix::RegisterErrorTable();
     138           0 :   initialized = true;
     139           0 :   return true;
     140             : }
     141             : 
     142             : static const uint32_t OCSP_TIMEOUT_MILLISECONDS_SOFT_DEFAULT = 2000;
     143             : static const uint32_t OCSP_TIMEOUT_MILLISECONDS_SOFT_MAX = 5000;
     144             : static const uint32_t OCSP_TIMEOUT_MILLISECONDS_HARD_DEFAULT = 10000;
     145             : static const uint32_t OCSP_TIMEOUT_MILLISECONDS_HARD_MAX = 20000;
     146             : 
     147             : static void
     148           0 : GetRevocationBehaviorFromPrefs(/*out*/ CertVerifier::OcspDownloadConfig* odc,
     149             :                                /*out*/ CertVerifier::OcspStrictConfig* osc,
     150             :                                /*out*/ uint32_t* certShortLifetimeInDays,
     151             :                                /*out*/ TimeDuration& softTimeout,
     152             :                                /*out*/ TimeDuration& hardTimeout,
     153             :                                const MutexAutoLock& /*proofOfLock*/)
     154             : {
     155           0 :   MOZ_ASSERT(NS_IsMainThread());
     156           0 :   MOZ_ASSERT(odc);
     157           0 :   MOZ_ASSERT(osc);
     158           0 :   MOZ_ASSERT(certShortLifetimeInDays);
     159             : 
     160             :   // 0 = disabled
     161             :   // 1 = enabled for everything (default)
     162             :   // 2 = enabled for EV certificates only
     163           0 :   int32_t ocspLevel = Preferences::GetInt("security.OCSP.enabled", 1);
     164           0 :   switch (ocspLevel) {
     165           0 :     case 0: *odc = CertVerifier::ocspOff; break;
     166           0 :     case 2: *odc = CertVerifier::ocspEVOnly; break;
     167           0 :     default: *odc = CertVerifier::ocspOn; break;
     168             :   }
     169             : 
     170           0 :   *osc = Preferences::GetBool("security.OCSP.require", false)
     171           0 :        ? CertVerifier::ocspStrict
     172             :        : CertVerifier::ocspRelaxed;
     173             : 
     174             :   // If we pass in just 0 as the second argument to Preferences::GetUint, there
     175             :   // are two function signatures that match (given that 0 can be intepreted as
     176             :   // a null pointer). Thus the compiler will complain without the cast.
     177           0 :   *certShortLifetimeInDays =
     178           0 :     Preferences::GetUint("security.pki.cert_short_lifetime_in_days",
     179             :                          static_cast<uint32_t>(0));
     180             : 
     181             :   uint32_t softTimeoutMillis =
     182           0 :     Preferences::GetUint("security.OCSP.timeoutMilliseconds.soft",
     183           0 :                          OCSP_TIMEOUT_MILLISECONDS_SOFT_DEFAULT);
     184           0 :   softTimeoutMillis = std::min(softTimeoutMillis,
     185           0 :                                OCSP_TIMEOUT_MILLISECONDS_SOFT_MAX);
     186           0 :   softTimeout = TimeDuration::FromMilliseconds(softTimeoutMillis);
     187             : 
     188             :   uint32_t hardTimeoutMillis =
     189           0 :     Preferences::GetUint("security.OCSP.timeoutMilliseconds.hard",
     190           0 :                          OCSP_TIMEOUT_MILLISECONDS_HARD_DEFAULT);
     191           0 :   hardTimeoutMillis = std::min(hardTimeoutMillis,
     192           0 :                                OCSP_TIMEOUT_MILLISECONDS_HARD_MAX);
     193           0 :   hardTimeout = TimeDuration::FromMilliseconds(hardTimeoutMillis);
     194             : 
     195           0 :   SSL_ClearSessionCache();
     196           0 : }
     197             : 
     198           0 : nsNSSComponent::nsNSSComponent()
     199             :   : mLoadableRootsLoadedMonitor("nsNSSComponent.mLoadableRootsLoadedMonitor")
     200             :   , mLoadableRootsLoaded(false)
     201             :   , mLoadableRootsLoadedResult(NS_ERROR_FAILURE)
     202             :   , mMutex("nsNSSComponent.mMutex")
     203           0 :   , mNSSInitialized(false)
     204             :   , mMitmDetecionEnabled(false)
     205           0 : {
     206           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::ctor\n"));
     207             :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
     208           0 : 
     209             :   MOZ_ASSERT(mInstanceCount == 0,
     210           0 :              "nsNSSComponent is a singleton, but instantiated multiple times!");
     211           0 :   ++mInstanceCount;
     212             : }
     213           0 : 
     214             : nsNSSComponent::~nsNSSComponent()
     215           0 : {
     216           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::dtor\n"));
     217             :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
     218             : 
     219             :   // All cleanup code requiring services needs to happen in xpcom_shutdown
     220           0 : 
     221           0 :   ShutdownNSS();
     222           0 :   SharedSSLState::GlobalCleanup();
     223           0 :   RememberCertErrorsTable::Cleanup();
     224             :   --mInstanceCount;
     225           0 : 
     226           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::dtor finished\n"));
     227             : }
     228             : 
     229             : #ifdef XP_WIN
     230             : static bool
     231             : GetUserSid(nsAString& sidString)
     232             : {
     233             :   // UNLEN is the maximum user name length (see Lmcons.h). +1 for the null
     234             :   // terminator.
     235             :   WCHAR lpAccountName[UNLEN + 1];
     236             :   DWORD lcAccountName = sizeof(lpAccountName) / sizeof(lpAccountName[0]);
     237             :   BOOL success = GetUserName(lpAccountName, &lcAccountName);
     238             :   if (!success) {
     239             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("GetUserName failed"));
     240             :     return false;
     241             :   }
     242             :   char sid_buffer[SECURITY_MAX_SID_SIZE];
     243             :   SID* sid = BitwiseCast<SID*, char*>(sid_buffer);
     244             :   DWORD cbSid = ArrayLength(sid_buffer);
     245             :   SID_NAME_USE eUse;
     246             :   // There doesn't appear to be a defined maximum length for the domain name
     247             :   // here. To deal with this, we start with a reasonable buffer length and
     248             :   // see if that works. If it fails and the error indicates insufficient length,
     249             :   // we use the indicated required length and try again.
     250             :   DWORD cchReferencedDomainName = 128;
     251             :   auto ReferencedDomainName(MakeUnique<WCHAR[]>(cchReferencedDomainName));
     252             :   success = LookupAccountName(nullptr, lpAccountName, sid, &cbSid,
     253             :                               ReferencedDomainName.get(),
     254             :                               &cchReferencedDomainName, &eUse);
     255             :   if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
     256             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("LookupAccountName failed"));
     257             :     return false;
     258             :   }
     259             :   if (!success) {
     260             :     ReferencedDomainName = MakeUnique<WCHAR[]>(cchReferencedDomainName);
     261             :     success = LookupAccountName(nullptr, lpAccountName, sid, &cbSid,
     262             :                                 ReferencedDomainName.get(),
     263             :                                 &cchReferencedDomainName, &eUse);
     264             :   }
     265             :   if (!success) {
     266             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("LookupAccountName failed"));
     267             :     return false;
     268             :   }
     269             :   LPTSTR StringSid;
     270             :   success = ConvertSidToStringSid(sid, &StringSid);
     271             :   if (!success) {
     272             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("ConvertSidToStringSid failed"));
     273             :     return false;
     274             :   }
     275             :   sidString.Assign(StringSid);
     276             :   LocalFree(StringSid);
     277             :   return true;
     278             : }
     279             : 
     280             : // This is a specialized helper function to read the value of a registry key
     281             : // that might not be present. If it is present, returns (via the output
     282             : // parameter) its value. Otherwise, returns the given default value.
     283             : // This function handles one level of nesting. That is, if the desired value
     284             : // is actually in a direct child of the given registry key (where the child
     285             : // and/or the value being sought may not actually be present), this function
     286             : // will handle that. In the normal case, though, optionalChildName will be
     287             : // null.
     288             : static nsresult
     289             : ReadRegKeyValueWithDefault(nsCOMPtr<nsIWindowsRegKey> regKey,
     290             :                            uint32_t flags,
     291             :                            wchar_t* optionalChildName,
     292             :                            wchar_t* valueName,
     293             :                            uint32_t defaultValue,
     294             :                            uint32_t& valueOut)
     295             : {
     296             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("ReadRegKeyValueWithDefault"));
     297             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     298             :           ("attempting to read '%S%s%S' with default '%u'",
     299             :            optionalChildName ? optionalChildName : L"",
     300             :            optionalChildName ? "\\" : "", valueName, defaultValue));
     301             :   if (optionalChildName) {
     302             :     nsDependentString childNameString(optionalChildName);
     303             :     bool hasChild;
     304             :     nsresult rv = regKey->HasChild(childNameString, &hasChild);
     305             :     if (NS_FAILED(rv)) {
     306             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     307             :               ("failed to determine if child key is present"));
     308             :       return rv;
     309             :     }
     310             :     if (!hasChild) {
     311             :       valueOut = defaultValue;
     312             :       return NS_OK;
     313             :     }
     314             :     nsCOMPtr<nsIWindowsRegKey> childRegKey;
     315             :     rv = regKey->OpenChild(childNameString, flags,
     316             :                            getter_AddRefs(childRegKey));
     317             :     if (NS_FAILED(rv)) {
     318             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open child key"));
     319             :       return rv;
     320             :     }
     321             :     return ReadRegKeyValueWithDefault(childRegKey, flags, nullptr, valueName,
     322             :                                       defaultValue, valueOut);
     323             :   }
     324             :   nsDependentString valueNameString(valueName);
     325             :   bool hasValue;
     326             :   nsresult rv = regKey->HasValue(valueNameString, &hasValue);
     327             :   if (NS_FAILED(rv)) {
     328             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     329             :             ("failed to determine if value is present"));
     330             :     return rv;
     331             :   }
     332             :   if (!hasValue) {
     333             :     valueOut = defaultValue;
     334             :     return NS_OK;
     335             :   }
     336             :   rv = regKey->ReadIntValue(valueNameString, &valueOut);
     337             :   if (NS_FAILED(rv)) {
     338             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to read value"));
     339             :     return rv;
     340             :   }
     341             :   return NS_OK;
     342             : }
     343             : 
     344             : static nsresult
     345             : AccountHasFamilySafetyEnabled(bool& enabled)
     346             : {
     347             :   enabled = false;
     348             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("AccountHasFamilySafetyEnabled?"));
     349             :   nsCOMPtr<nsIWindowsRegKey> parentalControlsKey(
     350             :     do_CreateInstance("@mozilla.org/windows-registry-key;1"));
     351             :   if (!parentalControlsKey) {
     352             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't create nsIWindowsRegKey"));
     353             :     return NS_ERROR_FAILURE;
     354             :   }
     355             :   uint32_t flags = nsIWindowsRegKey::ACCESS_READ | nsIWindowsRegKey::WOW64_64;
     356             :   NS_NAMED_LITERAL_STRING(familySafetyPath,
     357             :     "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Parental Controls");
     358             :   nsresult rv = parentalControlsKey->Open(
     359             :     nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, familySafetyPath, flags);
     360             :   if (NS_FAILED(rv)) {
     361             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open parentalControlsKey"));
     362             :     return rv;
     363             :   }
     364             :   NS_NAMED_LITERAL_STRING(usersString, "Users");
     365             :   bool hasUsers;
     366             :   rv = parentalControlsKey->HasChild(usersString, &hasUsers);
     367             :   if (NS_FAILED(rv)) {
     368             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("HasChild(Users) failed"));
     369             :     return rv;
     370             :   }
     371             :   if (!hasUsers) {
     372             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     373             :             ("Users subkey not present - Parental Controls not enabled"));
     374             :     return NS_OK;
     375             :   }
     376             :   nsCOMPtr<nsIWindowsRegKey> usersKey;
     377             :   rv = parentalControlsKey->OpenChild(usersString, flags,
     378             :                                       getter_AddRefs(usersKey));
     379             :   if (NS_FAILED(rv)) {
     380             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to open Users subkey"));
     381             :     return rv;
     382             :   }
     383             :   nsAutoString sid;
     384             :   if (!GetUserSid(sid)) {
     385             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get sid"));
     386             :     return NS_ERROR_FAILURE;
     387             :   }
     388             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("our sid is '%S'", sid.get()));
     389             :   bool hasSid;
     390             :   rv = usersKey->HasChild(sid, &hasSid);
     391             :   if (NS_FAILED(rv)) {
     392             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("HasChild(sid) failed"));
     393             :     return rv;
     394             :   }
     395             :   if (!hasSid) {
     396             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     397             :             ("sid not present in Family Safety Users"));
     398             :     return NS_OK;
     399             :   }
     400             :   nsCOMPtr<nsIWindowsRegKey> sidKey;
     401             :   rv = usersKey->OpenChild(sid, flags, getter_AddRefs(sidKey));
     402             :   if (NS_FAILED(rv)) {
     403             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open sid key"));
     404             :     return rv;
     405             :   }
     406             :   // There are three keys we're interested in: "Parental Controls On",
     407             :   // "Logging Required", and "Web\\Filter On". These keys will have value 0
     408             :   // or 1, indicating a particular feature is disabled or enabled,
     409             :   // respectively. So, if "Parental Controls On" is not 1, Family Safety is
     410             :   // disabled and we don't care about anything else. If both "Logging
     411             :   // Required" and "Web\\Filter On" are 0, the proxy will not be running,
     412             :   // so for our purposes we can consider Family Safety disabled in that
     413             :   // case.
     414             :   // By default, "Logging Required" is 1 and "Web\\Filter On" is 0,
     415             :   // reflecting the initial settings when Family Safety is enabled for an
     416             :   // account for the first time, However, these sub-keys are not created
     417             :   // unless they are switched away from the default value.
     418             :   uint32_t parentalControlsOn;
     419             :   rv = sidKey->ReadIntValue(NS_LITERAL_STRING("Parental Controls On"),
     420             :                             &parentalControlsOn);
     421             :   if (NS_FAILED(rv)) {
     422             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     423             :             ("couldn't read Parental Controls On"));
     424             :     return rv;
     425             :   }
     426             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     427             :           ("Parental Controls On: %u", parentalControlsOn));
     428             :   if (parentalControlsOn != 1) {
     429             :     return NS_OK;
     430             :   }
     431             :   uint32_t loggingRequired;
     432             :   rv = ReadRegKeyValueWithDefault(sidKey, flags, nullptr, L"Logging Required",
     433             :                                   1, loggingRequired);
     434             :   if (NS_FAILED(rv)) {
     435             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     436             :             ("failed to read value of Logging Required"));
     437             :     return rv;
     438             :   }
     439             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     440             :           ("Logging Required: %u", loggingRequired));
     441             :   uint32_t webFilterOn;
     442             :   rv = ReadRegKeyValueWithDefault(sidKey, flags, L"Web", L"Filter On", 0,
     443             :                                   webFilterOn);
     444             :   if (NS_FAILED(rv)) {
     445             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     446             :             ("failed to read value of Web\\Filter On"));
     447             :     return rv;
     448             :   }
     449             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Web\\Filter On: %u", webFilterOn));
     450             :   enabled = loggingRequired == 1 || webFilterOn == 1;
     451             :   return NS_OK;
     452             : }
     453             : 
     454             : // It would be convenient to just use nsIX509CertDB in the following code.
     455             : // However, since nsIX509CertDB depends on nsNSSComponent initialization (and
     456             : // since this code runs during that initialization), we can't use it. Instead,
     457             : // we can use NSS APIs directly (as long as we're called late enough in
     458             : // nsNSSComponent initialization such that those APIs are safe to use).
     459             : 
     460             : // Helper function to convert a PCCERT_CONTEXT (i.e. a certificate obtained via
     461             : // a Windows API) to a temporary CERTCertificate (i.e. a certificate for use
     462             : // with NSS APIs).
     463             : static UniqueCERTCertificate
     464             : PCCERT_CONTEXTToCERTCertificate(PCCERT_CONTEXT pccert)
     465             : {
     466             :   MOZ_ASSERT(pccert);
     467             :   if (!pccert) {
     468             :     return nullptr;
     469             :   }
     470             : 
     471             :   SECItem derCert = {
     472             :     siBuffer,
     473             :     pccert->pbCertEncoded,
     474             :     pccert->cbCertEncoded
     475             :   };
     476             :   return UniqueCERTCertificate(
     477             :     CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
     478             :                             nullptr, // nickname unnecessary
     479             :                             false, // not permanent
     480             :                             true)); // copy DER
     481             : }
     482             : 
     483             : static NS_NAMED_LITERAL_CSTRING(kMicrosoftFamilySafetyCN,
     484             :                                 "Microsoft Family Safety");
     485             : 
     486             : nsresult
     487             : nsNSSComponent::MaybeImportFamilySafetyRoot(PCCERT_CONTEXT certificate,
     488             :                                             bool& wasFamilySafetyRoot)
     489             : {
     490             :   MutexAutoLock lock(mMutex);
     491             :   MOZ_ASSERT(NS_IsMainThread());
     492             :   if (!NS_IsMainThread()) {
     493             :     return NS_ERROR_NOT_SAME_THREAD;
     494             :   }
     495             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("MaybeImportFamilySafetyRoot"));
     496             :   wasFamilySafetyRoot = false;
     497             : 
     498             :   UniqueCERTCertificate nssCertificate(
     499             :     PCCERT_CONTEXTToCERTCertificate(certificate));
     500             :   if (!nssCertificate) {
     501             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't decode certificate"));
     502             :     return NS_ERROR_FAILURE;
     503             :   }
     504             :   // Looking for a certificate with the common name 'Microsoft Family Safety'
     505             :   UniquePORTString subjectName(CERT_GetCommonName(&nssCertificate->subject));
     506             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     507             :           ("subject name is '%s'", subjectName.get()));
     508             :   if (kMicrosoftFamilySafetyCN.Equals(subjectName.get())) {
     509             :     wasFamilySafetyRoot = true;
     510             :     MOZ_ASSERT(!mFamilySafetyRoot);
     511             :     mFamilySafetyRoot = std::move(nssCertificate);
     512             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("added Family Safety root"));
     513             :   }
     514             :   return NS_OK;
     515             : }
     516             : 
     517             : // Because HCERTSTORE is just a typedef void*, we can't use any of the nice
     518             : // scoped or unique pointer templates. To elaborate, any attempt would
     519             : // instantiate those templates with T = void. When T gets used in the context
     520             : // of T&, this results in void&, which isn't legal.
     521             : class ScopedCertStore final
     522             : {
     523             : public:
     524             :   explicit ScopedCertStore(HCERTSTORE certstore) : certstore(certstore) {}
     525             : 
     526             :   ~ScopedCertStore()
     527             :   {
     528             :     CertCloseStore(certstore, 0);
     529             :   }
     530             : 
     531             :   HCERTSTORE get()
     532             :   {
     533             :     return certstore;
     534             :   }
     535             : 
     536             : private:
     537             :   ScopedCertStore(const ScopedCertStore&) = delete;
     538             :   ScopedCertStore& operator=(const ScopedCertStore&) = delete;
     539             :   HCERTSTORE certstore;
     540             : };
     541             : 
     542             : static const wchar_t* kWindowsDefaultRootStoreName = L"ROOT";
     543             : 
     544             : nsresult
     545             : nsNSSComponent::LoadFamilySafetyRoot()
     546             : {
     547             :   ScopedCertStore certstore(
     548             :     CertOpenSystemStore(0, kWindowsDefaultRootStoreName));
     549             :   if (!certstore.get()) {
     550             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     551             :             ("couldn't get certstore '%S'", kWindowsDefaultRootStoreName));
     552             :     return NS_ERROR_FAILURE;
     553             :   }
     554             :   // Any resources held by the certificate are released by the next call to
     555             :   // CertFindCertificateInStore.
     556             :   PCCERT_CONTEXT certificate = nullptr;
     557             :   while ((certificate = CertFindCertificateInStore(certstore.get(),
     558             :                                                    X509_ASN_ENCODING, 0,
     559             :                                                    CERT_FIND_ANY, nullptr,
     560             :                                                    certificate))) {
     561             :     bool wasFamilySafetyRoot = false;
     562             :     nsresult rv = MaybeImportFamilySafetyRoot(certificate,
     563             :                                               wasFamilySafetyRoot);
     564             :     if (NS_SUCCEEDED(rv) && wasFamilySafetyRoot) {
     565             :       return NS_OK; // We're done (we're only expecting one root).
     566             :     }
     567             :   }
     568             :   return NS_ERROR_FAILURE;
     569             : }
     570             : 
     571             : void
     572             : nsNSSComponent::UnloadFamilySafetyRoot()
     573             : {
     574             :   MutexAutoLock lock(mMutex);
     575             :   MOZ_ASSERT(NS_IsMainThread());
     576             :   if (!NS_IsMainThread()) {
     577             :     return;
     578             :   }
     579             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadFamilySafetyRoot"));
     580             :   if (!mFamilySafetyRoot) {
     581             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Family Safety Root wasn't present"));
     582             :     return;
     583             :   }
     584             :   // It would be intuitive to set the trust to { 0, 0, 0 } here. However, this
     585             :   // doesn't work for temporary certificates because CERT_ChangeCertTrust first
     586             :   // looks up the current trust settings in the permanent cert database, finds
     587             :   // that such trust doesn't exist, considers the current trust to be
     588             :   // { 0, 0, 0 }, and decides that it doesn't need to update the trust since
     589             :   // they're the same. To work around this, we set a non-zero flag to ensure
     590             :   // that the trust will get updated.
     591             :   CERTCertTrust trust = { CERTDB_USER, 0, 0 };
     592             :   if (ChangeCertTrustWithPossibleAuthentication(mFamilySafetyRoot, trust,
     593             :                                                 nullptr) != SECSuccess) {
     594             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     595             :             ("couldn't untrust certificate for TLS server auth"));
     596             :   }
     597             :   mFamilySafetyRoot = nullptr;
     598             : }
     599             : 
     600             : // The supported values of this pref are:
     601             : // 0: disable detecting Family Safety mode and importing the root
     602             : // 1: only attempt to detect Family Safety mode (don't import the root)
     603             : // 2: detect Family Safety mode and import the root
     604             : const char* kFamilySafetyModePref = "security.family_safety.mode";
     605             : 
     606             : // The telemetry gathered by this function is as follows:
     607             : // 0-2: the value of the Family Safety mode pref
     608             : // 3: detecting Family Safety mode failed
     609             : // 4: Family Safety was not enabled
     610             : // 5: Family Safety was enabled
     611             : // 6: failed to import the Family Safety root
     612             : // 7: successfully imported the root
     613             : void
     614             : nsNSSComponent::MaybeEnableFamilySafetyCompatibility()
     615             : {
     616             :   if (!(IsWin8Point1OrLater() && !IsWin10OrLater())) {
     617             :     return;
     618             :   }
     619             :   // Detect but don't import by default.
     620             :   uint32_t familySafetyMode = Preferences::GetUint(kFamilySafetyModePref, 1);
     621             :   if (familySafetyMode > 2) {
     622             :     familySafetyMode = 0;
     623             :   }
     624             :   if (familySafetyMode == 0) {
     625             :     return;
     626             :   }
     627             :   bool familySafetyEnabled;
     628             :   nsresult rv = AccountHasFamilySafetyEnabled(familySafetyEnabled);
     629             :   if (NS_FAILED(rv)) {
     630             :     return;
     631             :   }
     632             :   if (!familySafetyEnabled) {
     633             :     return;
     634             :   }
     635             :   if (familySafetyMode == 2) {
     636             :     rv = LoadFamilySafetyRoot();
     637             :     if (NS_FAILED(rv)) {
     638             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     639             :               ("failed to load Family Safety root"));
     640             :     }
     641             :   }
     642             : }
     643             : 
     644             : // Helper function to determine if the OS considers the given certificate to be
     645             : // a trust anchor for TLS server auth certificates. This is to be used in the
     646             : // context of importing what are presumed to be root certificates from the OS.
     647             : // If this function returns true but it turns out that the given certificate is
     648             : // in some way unsuitable to issue certificates, mozilla::pkix will never build
     649             : // a valid chain that includes the certificate, so importing it even if it
     650             : // isn't a valid CA poses no risk.
     651             : static bool
     652             : CertIsTrustAnchorForTLSServerAuth(PCCERT_CONTEXT certificate)
     653             : {
     654             :   MOZ_ASSERT(certificate);
     655             :   if (!certificate) {
     656             :     return false;
     657             :   }
     658             : 
     659             :   PCCERT_CHAIN_CONTEXT pChainContext = nullptr;
     660             :   CERT_ENHKEY_USAGE enhkeyUsage;
     661             :   memset(&enhkeyUsage, 0, sizeof(CERT_ENHKEY_USAGE));
     662             :   LPSTR identifiers[] = {
     663             :     "1.3.6.1.5.5.7.3.1", // id-kp-serverAuth
     664             :   };
     665             :   enhkeyUsage.cUsageIdentifier = ArrayLength(identifiers);
     666             :   enhkeyUsage.rgpszUsageIdentifier = identifiers;
     667             :   CERT_USAGE_MATCH certUsage;
     668             :   memset(&certUsage, 0, sizeof(CERT_USAGE_MATCH));
     669             :   certUsage.dwType = USAGE_MATCH_TYPE_AND;
     670             :   certUsage.Usage = enhkeyUsage;
     671             :   CERT_CHAIN_PARA chainPara;
     672             :   memset(&chainPara, 0, sizeof(CERT_CHAIN_PARA));
     673             :   chainPara.cbSize = sizeof(CERT_CHAIN_PARA);
     674             :   chainPara.RequestedUsage = certUsage;
     675             : 
     676             :   if (!CertGetCertificateChain(nullptr, certificate, nullptr, nullptr,
     677             :                                &chainPara, 0, nullptr, &pChainContext)) {
     678             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CertGetCertificateChain failed"));
     679             :     return false;
     680             :   }
     681             :   bool trusted = pChainContext->TrustStatus.dwErrorStatus ==
     682             :                  CERT_TRUST_NO_ERROR;
     683             :   bool isRoot = pChainContext->cChain == 1;
     684             :   CertFreeCertificateChain(pChainContext);
     685             :   if (trusted && isRoot) {
     686             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     687             :             ("certificate is trust anchor for TLS server auth"));
     688             :     return true;
     689             :   }
     690             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     691             :           ("certificate not trust anchor for TLS server auth"));
     692             :   return false;
     693             : }
     694             : 
     695             : void
     696             : nsNSSComponent::UnloadEnterpriseRoots()
     697             : {
     698             :   MutexAutoLock lock(mMutex);
     699             :   MOZ_ASSERT(NS_IsMainThread());
     700             :   if (!NS_IsMainThread()) {
     701             :     return;
     702             :   }
     703             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadEnterpriseRoots"));
     704             :   if (!mEnterpriseRoots) {
     705             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("no enterprise roots were present"));
     706             :     return;
     707             :   }
     708             :   // It would be intuitive to set the trust to { 0, 0, 0 } here. However, this
     709             :   // doesn't work for temporary certificates because CERT_ChangeCertTrust first
     710             :   // looks up the current trust settings in the permanent cert database, finds
     711             :   // that such trust doesn't exist, considers the current trust to be
     712             :   // { 0, 0, 0 }, and decides that it doesn't need to update the trust since
     713             :   // they're the same. To work around this, we set a non-zero flag to ensure
     714             :   // that the trust will get updated.
     715             :   CERTCertTrust trust = { CERTDB_USER, 0, 0 };
     716             :   for (CERTCertListNode* n = CERT_LIST_HEAD(mEnterpriseRoots.get());
     717             :        !CERT_LIST_END(n, mEnterpriseRoots.get()); n = CERT_LIST_NEXT(n)) {
     718             :     if (!n || !n->cert) {
     719             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     720             :               ("library failure: CERTCertListNode null or lacks cert"));
     721             :       continue;
     722             :     }
     723             :     UniqueCERTCertificate cert(CERT_DupCertificate(n->cert));
     724             :     if (ChangeCertTrustWithPossibleAuthentication(cert, trust, nullptr)
     725             :           != SECSuccess) {
     726             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     727             :               ("couldn't untrust certificate for TLS server auth"));
     728             :     }
     729             :   }
     730             :   mEnterpriseRoots = nullptr;
     731             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("unloaded enterprise roots"));
     732             : }
     733             : 
     734             : NS_IMETHODIMP
     735             : nsNSSComponent::GetEnterpriseRoots(nsIX509CertList** enterpriseRoots)
     736             : {
     737             :   MutexAutoLock nsNSSComponentLock(mMutex);
     738             :   MOZ_ASSERT(NS_IsMainThread());
     739             :   if (!NS_IsMainThread()) {
     740             :     return NS_ERROR_NOT_SAME_THREAD;
     741             :   }
     742             :   NS_ENSURE_ARG_POINTER(enterpriseRoots);
     743             : 
     744             :   if (!mEnterpriseRoots) {
     745             :     *enterpriseRoots = nullptr;
     746             :     return NS_OK;
     747             :   }
     748             :   UniqueCERTCertList enterpriseRootsCopy(
     749             :     nsNSSCertList::DupCertList(mEnterpriseRoots));
     750             :   if (!enterpriseRootsCopy) {
     751             :     return NS_ERROR_FAILURE;
     752             :   }
     753             :   nsCOMPtr<nsIX509CertList> enterpriseRootsCertList(
     754             :     new nsNSSCertList(std::move(enterpriseRootsCopy)));
     755             :   if (!enterpriseRootsCertList) {
     756             :     return NS_ERROR_FAILURE;
     757             :   }
     758             :   enterpriseRootsCertList.forget(enterpriseRoots);
     759             :   return NS_OK;
     760             : }
     761             : 
     762             : static const char* kEnterpriseRootModePref = "security.enterprise_roots.enabled";
     763             : 
     764             : void
     765             : nsNSSComponent::MaybeImportEnterpriseRoots()
     766             : {
     767             :   MutexAutoLock lock(mMutex);
     768             :   MOZ_ASSERT(NS_IsMainThread());
     769             :   if (!NS_IsMainThread()) {
     770             :     return;
     771             :   }
     772             :   bool importEnterpriseRoots = Preferences::GetBool(kEnterpriseRootModePref,
     773             :                                                     false);
     774             :   if (!importEnterpriseRoots) {
     775             :     return;
     776             :   }
     777             : 
     778             :   MOZ_ASSERT(!mEnterpriseRoots);
     779             :   mEnterpriseRoots.reset(CERT_NewCertList());
     780             :   if (!mEnterpriseRoots) {
     781             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     782             :             ("failed to allocate a new CERTCertList for mEnterpriseRoots"));
     783             :     return;
     784             :   }
     785             : 
     786             :   ImportEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE, lock);
     787             :   ImportEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY,
     788             :                                    lock);
     789             :   ImportEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
     790             :                                    lock);
     791             : }
     792             : 
     793             : // Loads the enterprise roots at the registry location corresponding to the
     794             : // given location flag.
     795             : // Supported flags are:
     796             : //   CERT_SYSTEM_STORE_LOCAL_MACHINE
     797             : //     (for HKLM\SOFTWARE\Microsoft\SystemCertificates)
     798             : //   CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
     799             : //     (for HKLM\SOFTWARE\Policies\Microsoft\SystemCertificates\Root\Certificates)
     800             : //   CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
     801             : //     (for HKLM\SOFTWARE\Microsoft\EnterpriseCertificates\Root\Certificates)
     802             : void
     803             : nsNSSComponent::ImportEnterpriseRootsForLocation(
     804             :   DWORD locationFlag, const MutexAutoLock& /*proof of lock*/)
     805             : {
     806             :   MOZ_ASSERT(NS_IsMainThread());
     807             :   if (!NS_IsMainThread()) {
     808             :     return;
     809             :   }
     810             :   MOZ_ASSERT(locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ||
     811             :              locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY ||
     812             :              locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
     813             :              "unexpected locationFlag for ImportEnterpriseRootsForLocation");
     814             :   if (!(locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ||
     815             :         locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY ||
     816             :         locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE)) {
     817             :     return;
     818             :   }
     819             : 
     820             :   DWORD flags = locationFlag |
     821             :                 CERT_STORE_OPEN_EXISTING_FLAG |
     822             :                 CERT_STORE_READONLY_FLAG;
     823             :   // The certificate store being opened should consist only of certificates
     824             :   // added by a user or administrator and not any certificates that are part
     825             :   // of Microsoft's root store program.
     826             :   // The 3rd parameter to CertOpenStore should be NULL according to
     827             :   // https://msdn.microsoft.com/en-us/library/windows/desktop/aa376559%28v=vs.85%29.aspx
     828             :   ScopedCertStore enterpriseRootStore(CertOpenStore(
     829             :     CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, NULL, flags,
     830             :     kWindowsDefaultRootStoreName));
     831             :   if (!enterpriseRootStore.get()) {
     832             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to open enterprise root store"));
     833             :     return;
     834             :   }
     835             :   PCCERT_CONTEXT certificate = nullptr;
     836             :   uint32_t numImported = 0;
     837             :   while ((certificate = CertFindCertificateInStore(enterpriseRootStore.get(),
     838             :                                                    X509_ASN_ENCODING, 0,
     839             :                                                    CERT_FIND_ANY, nullptr,
     840             :                                                    certificate))) {
     841             :     if (!CertIsTrustAnchorForTLSServerAuth(certificate)) {
     842             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     843             :               ("skipping cert not trust anchor for TLS server auth"));
     844             :       continue;
     845             :     }
     846             :     UniqueCERTCertificate nssCertificate(
     847             :       PCCERT_CONTEXTToCERTCertificate(certificate));
     848             :     if (!nssCertificate) {
     849             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't decode certificate"));
     850             :       continue;
     851             :     }
     852             :     // Don't import the Microsoft Family Safety root (this prevents the
     853             :     // Enterprise Roots feature from interacting poorly with the Family
     854             :     // Safety support).
     855             :     UniquePORTString subjectName(
     856             :       CERT_GetCommonName(&nssCertificate->subject));
     857             :     if (kMicrosoftFamilySafetyCN.Equals(subjectName.get())) {
     858             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("skipping Family Safety Root"));
     859             :       continue;
     860             :     }
     861             :     MOZ_ASSERT(mEnterpriseRoots, "mEnterpriseRoots unexpectedly NULL?");
     862             :     if (!mEnterpriseRoots) {
     863             :       return;
     864             :     }
     865             :     if (CERT_AddCertToListTail(mEnterpriseRoots.get(), nssCertificate.get())
     866             :           != SECSuccess) {
     867             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't add cert to list"));
     868             :       continue;
     869             :     }
     870             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Imported '%s'", subjectName.get()));
     871             :     numImported++;
     872             :     // now owned by mEnterpriseRoots
     873             :     Unused << nssCertificate.release();
     874             :   }
     875             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("imported %u roots", numImported));
     876             : }
     877             : 
     878             : NS_IMETHODIMP
     879             : nsNSSComponent::TrustLoaded3rdPartyRoots()
     880             : {
     881             :   MutexAutoLock lock(mMutex);
     882             : 
     883             :   CERTCertTrust trust = {
     884             :     CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER,
     885             :     0,
     886             :     0
     887             :   };
     888             :   if (mEnterpriseRoots) {
     889             :     for (CERTCertListNode* n = CERT_LIST_HEAD(mEnterpriseRoots.get());
     890             :          !CERT_LIST_END(n, mEnterpriseRoots.get()); n = CERT_LIST_NEXT(n)) {
     891             :       if (!n || !n->cert) {
     892             :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     893             :                 ("library failure: CERTCertListNode null or lacks cert"));
     894             :         continue;
     895             :       }
     896             :       UniqueCERTCertificate cert(CERT_DupCertificate(n->cert));
     897             :       if (ChangeCertTrustWithPossibleAuthentication(cert, trust, nullptr)
     898             :             != SECSuccess) {
     899             :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     900             :                 ("couldn't trust enterprise certificate for TLS server auth"));
     901             :       }
     902             :     }
     903             :   }
     904             :   if (mFamilySafetyRoot &&
     905             :       ChangeCertTrustWithPossibleAuthentication(mFamilySafetyRoot, trust,
     906             :                                                 nullptr) != SECSuccess) {
     907             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     908             :             ("couldn't trust family safety certificate for TLS server auth"));
     909             :   }
     910             :   return NS_OK;
     911             : }
     912             : #endif // XP_WIN
     913             : 
     914             : class LoadLoadableRootsTask final : public Runnable
     915             : {
     916           1 : public:
     917           1 :   explicit LoadLoadableRootsTask(nsNSSComponent* nssComponent)
     918           2 :     : Runnable("LoadLoadableRootsTask")
     919             :     , mNSSComponent(nssComponent)
     920           1 :   {
     921           1 :     MOZ_ASSERT(nssComponent);
     922             :   }
     923           3 : 
     924             :   ~LoadLoadableRootsTask() = default;
     925             : 
     926             :   nsresult Dispatch();
     927             : 
     928             : private:
     929             :   NS_IMETHOD Run() override;
     930             :   nsresult LoadLoadableRoots();
     931             :   RefPtr<nsNSSComponent> mNSSComponent;
     932             :   nsCOMPtr<nsIThread> mThread;
     933             : };
     934             : 
     935           1 : nsresult
     936             : LoadLoadableRootsTask::Dispatch()
     937             : {
     938           3 :   // Can't add 'this' as the event to run, since mThread may not be set yet
     939             :   nsresult rv = NS_NewNamedThread("LoadRoots", getter_AddRefs(mThread),
     940           1 :                                   nullptr,
     941           1 :                                   nsIThreadManager::DEFAULT_STACK_SIZE);
     942             :   if (NS_FAILED(rv)) {
     943             :     return rv;
     944             :   }
     945             : 
     946           1 :   // Note: event must not null out mThread!
     947             :   return mThread->Dispatch(this, NS_DISPATCH_NORMAL);
     948             : }
     949             : 
     950             : // NB: If anything in this function can cause an acquisition of
     951             : // nsNSSComponent::mMutex, this can potentially deadlock with
     952             : // nsNSSComponent::Shutdown.
     953           0 : NS_IMETHODIMP
     954             : LoadLoadableRootsTask::Run()
     955             : {
     956             :   // First we Run() on the "LoadRoots" thread, do our work, and then we Run()
     957             :   // again on the main thread so we can shut down the thread (since we don't
     958             :   // need it any more). We can't shut down the thread while we're *on* the
     959             :   // thread, which is why we do the dispatch to the main thread. CryptoTask.cpp
     960             :   // (which informs this code) says that we can't null out mThread. This appears
     961             :   // to be because its refcount could be decreased while this dispatch is being
     962             :   // processed, so it might get prematurely destroyed. I'm not sure this makes
     963             :   // sense but it'll get cleaned up in our destructor anyway, so it's fine to
     964             :   // not null it out here (as long as we don't run twice on the main thread,
     965           2 :   // which shouldn't be possible).
     966           0 :   if (NS_IsMainThread()) {
     967           1 :     if (mThread) {
     968             :       mThread->Shutdown();
     969             :     }
     970             :     return NS_OK;
     971             :   }
     972           1 : 
     973           1 :   nsresult rv = LoadLoadableRoots();
     974           0 :   if (NS_FAILED(rv)) {
     975             :     MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("LoadLoadableRoots failed"));
     976             :     // We don't return rv here because then BlockUntilLoadableRootsLoaded will
     977             :     // just wait forever. Instead we'll save its value (below) so we can inform
     978             :     // code that relies on the roots module being present that loading it
     979             :     // failed.
     980             :   }
     981           1 : 
     982           1 :   if (NS_SUCCEEDED(rv)) {
     983             :     if (NS_FAILED(LoadExtendedValidationInfo())) {
     984             :       // This isn't a show-stopper in the same way that failing to load the
     985           0 :       // roots module is.
     986             :       MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("failed to load EV info"));
     987             :     }
     988             :   }
     989           0 :   {
     990           0 :     MonitorAutoLock rootsLoadedLock(mNSSComponent->mLoadableRootsLoadedMonitor);
     991             :     mNSSComponent->mLoadableRootsLoaded = true;
     992             :     // Cache the result of LoadLoadableRoots so BlockUntilLoadableRootsLoaded
     993           1 :     // can return it to all callers later.
     994           2 :     mNSSComponent->mLoadableRootsLoadedResult = rv;
     995           0 :     rv = mNSSComponent->mLoadableRootsLoadedMonitor.NotifyAll();
     996           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     997             :       return rv;
     998             :     }
     999             :   }
    1000             : 
    1001           0 :   // Go back to the main thread to clean up this worker thread.
    1002             :   return NS_DispatchToMainThread(this);
    1003             : }
    1004             : 
    1005           0 : nsresult
    1006             : nsNSSComponent::HasActiveSmartCards(bool& result)
    1007           0 : {
    1008           0 :   MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
    1009             :   if (!NS_IsMainThread()) {
    1010             :     return NS_ERROR_NOT_SAME_THREAD;
    1011             :   }
    1012             : 
    1013           0 : #ifndef MOZ_NO_SMART_CARDS
    1014             :   MutexAutoLock nsNSSComponentLock(mMutex);
    1015           0 : 
    1016           0 :   AutoSECMODListReadLock secmodLock;
    1017           0 :   SECMODModuleList* list = SECMOD_GetDefaultModuleList();
    1018           0 :   while (list) {
    1019           0 :     if (SECMOD_HasRemovableSlots(list->module)) {
    1020           0 :       result = true;
    1021             :       return NS_OK;
    1022           0 :     }
    1023             :     list = list->next;
    1024             :   }
    1025           0 : #endif
    1026           0 :   result = false;
    1027             :   return NS_OK;
    1028             : }
    1029             : 
    1030           0 : nsresult
    1031             : nsNSSComponent::HasUserCertsInstalled(bool& result)
    1032           0 : {
    1033           0 :   MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
    1034             :   if (!NS_IsMainThread()) {
    1035             :     return NS_ERROR_NOT_SAME_THREAD;
    1036             :   }
    1037           0 : 
    1038             :   MutexAutoLock nsNSSComponentLock(mMutex);
    1039           0 : 
    1040             :   if (!mNSSInitialized) {
    1041             :     return NS_ERROR_NOT_INITIALIZED;
    1042             :   }
    1043           0 : 
    1044             :   result = false;
    1045             :   UniqueCERTCertList certList(
    1046           0 :     CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageSSLClient,
    1047           0 :                               false, true, nullptr));
    1048             :   if (!certList) {
    1049             :     return NS_OK;
    1050             :   }
    1051             : 
    1052           0 :   // check if the list is empty
    1053             :   if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
    1054             :     return NS_OK;
    1055             :   }
    1056             : 
    1057           0 :   // The list is not empty, meaning at least one cert is installed
    1058           0 :   result = true;
    1059             :   return NS_OK;
    1060             : }
    1061             : 
    1062           0 : nsresult
    1063             : nsNSSComponent::BlockUntilLoadableRootsLoaded()
    1064           0 : {
    1065           2 :   MonitorAutoLock rootsLoadedLock(mLoadableRootsLoadedMonitor);
    1066           0 :   while (!mLoadableRootsLoaded) {
    1067             :     rootsLoadedLock.Wait();
    1068           0 :   }
    1069             :   MOZ_ASSERT(mLoadableRootsLoaded);
    1070           4 : 
    1071             :   return mLoadableRootsLoadedResult;
    1072             : }
    1073             : 
    1074           1 : nsresult
    1075             : nsNSSComponent::CheckForSmartCardChanges()
    1076             : {
    1077           2 : #ifndef MOZ_NO_SMART_CARDS
    1078             :   MutexAutoLock nsNSSComponentLock(mMutex);
    1079           1 : 
    1080             :   if (!mNSSInitialized) {
    1081             :     return NS_ERROR_NOT_INITIALIZED;
    1082             :   }
    1083             : 
    1084             :   // SECMOD_UpdateSlotList attempts to acquire the list lock as well,
    1085             :   // so we have to do this in two steps. The lock protects the list itself, so
    1086             :   // if we get our own owned references to the modules we're interested in,
    1087           0 :   // there's no thread safety concern here.
    1088             :   Vector<UniqueSECMODModule> modulesWithRemovableSlots;
    1089           1 :   {
    1090           1 :     AutoSECMODListReadLock secmodLock;
    1091           5 :     SECMODModuleList* list = SECMOD_GetDefaultModuleList();
    1092           0 :     while (list) {
    1093           0 :       if (SECMOD_HasRemovableSlots(list->module)) {
    1094           0 :         UniqueSECMODModule module(SECMOD_ReferenceModule(list->module));
    1095           0 :         if (!modulesWithRemovableSlots.append(std::move(module))) {
    1096             :           return NS_ERROR_OUT_OF_MEMORY;
    1097             :         }
    1098           0 :       }
    1099             :       list = list->next;
    1100             :     }
    1101           0 :   }
    1102             :   for (auto& module : modulesWithRemovableSlots) {
    1103           0 :     // Best-effort.
    1104           0 :     Unused << SECMOD_UpdateSlotList(module.get());
    1105             :     for (int i = 0; i < module->slotCount; i++) {
    1106             :       // We actually don't care about the return value here - we just need to
    1107           0 :       // call this to get NSS to update its view of this slot.
    1108             :       Unused << PK11_IsPresent(module->slots[i]);
    1109             :     }
    1110             :   }
    1111             : #endif
    1112             : 
    1113             :   return NS_OK;
    1114             : }
    1115             : 
    1116             : // Returns by reference the path to the directory containing the file that has
    1117             : // been loaded as DLL_PREFIX nss3 DLL_SUFFIX.
    1118           1 : static nsresult
    1119             : GetNSS3Directory(nsCString& result)
    1120             : {
    1121             :   UniquePRString nss3Path(
    1122           0 :     PR_GetLibraryFilePathname(DLL_PREFIX "nss3" DLL_SUFFIX,
    1123           1 :                               reinterpret_cast<PRFuncPtr>(NSS_Initialize)));
    1124           0 :   if (!nss3Path) {
    1125             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nss not loaded?"));
    1126             :     return NS_ERROR_FAILURE;
    1127           0 :   }
    1128           0 :   nsCOMPtr<nsIFile> nss3File(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
    1129           0 :   if (!nss3File) {
    1130             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't create a file?"));
    1131             :     return NS_ERROR_FAILURE;
    1132           1 :   }
    1133           0 :   nsAutoCString nss3PathAsString(nss3Path.get());
    1134           0 :   nsresult rv = nss3File->InitWithNativePath(nss3PathAsString);
    1135           0 :   if (NS_FAILED(rv)) {
    1136             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1137             :             ("couldn't initialize file with path '%s'", nss3Path.get()));
    1138             :     return rv;
    1139           2 :   }
    1140           2 :   nsCOMPtr<nsIFile> nss3Directory;
    1141           1 :   rv = nss3File->GetParent(getter_AddRefs(nss3Directory));
    1142           0 :   if (NS_FAILED(rv)) {
    1143             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get parent directory?"));
    1144             :     return rv;
    1145             :   }
    1146             : #ifdef XP_WIN
    1147             :   // Native path will drop Unicode characters that cannot be mapped to system's
    1148             :   // codepage, using short (canonical) path as workaround.
    1149             :   nsCOMPtr<nsILocalFileWin> nss3DirectoryWin = do_QueryInterface(nss3Directory);
    1150             :   if (NS_FAILED(rv)) {
    1151             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
    1152             :     return rv;
    1153             :   }
    1154             :   return nss3DirectoryWin->GetNativeCanonicalPath(result);
    1155           1 : #else
    1156             :   return nss3Directory->GetNativePath(result);
    1157             : #endif
    1158             : }
    1159             : 
    1160             : // Returns by reference the path to the desired directory, based on the current
    1161             : // settings in the directory service.
    1162           2 : static nsresult
    1163             : GetDirectoryPath(const char* directoryKey, nsCString& result)
    1164             : {
    1165           0 :   nsCOMPtr<nsIProperties> directoryService(
    1166           0 :     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
    1167           0 :   if (!directoryService) {
    1168             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not get directory service"));
    1169             :     return NS_ERROR_FAILURE;
    1170           4 :   }
    1171           4 :   nsCOMPtr<nsIFile> directory;
    1172           6 :   nsresult rv = directoryService->Get(directoryKey, NS_GET_IID(nsIFile),
    1173           2 :                                       getter_AddRefs(directory));
    1174           0 :   if (NS_FAILED(rv)) {
    1175             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1176             :             ("could not get '%s' from directory service", directoryKey));
    1177             :     return rv;
    1178             :   }
    1179             : #ifdef XP_WIN
    1180             :   // Native path will drop Unicode characters that cannot be mapped to system's
    1181             :   // codepage, using short (canonical) path as workaround.
    1182             :   nsCOMPtr<nsILocalFileWin> directoryWin = do_QueryInterface(directory);
    1183             :   if (NS_FAILED(rv)) {
    1184             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
    1185             :     return rv;
    1186             :   }
    1187             :   return directoryWin->GetNativeCanonicalPath(result);
    1188           0 : #else
    1189             :   return directory->GetNativePath(result);
    1190             : #endif
    1191             : }
    1192             : 
    1193             : 
    1194           1 : nsresult
    1195             : LoadLoadableRootsTask::LoadLoadableRoots()
    1196             : {
    1197             :   // Find the best Roots module for our purposes.
    1198             :   // Prefer the application's installation directory,
    1199           0 :   // but also ensure the library is at least the version we expect.
    1200             :   Vector<nsCString> possibleCKBILocations;
    1201             :   // First try in the directory where we've already loaded
    1202           2 :   // DLL_PREFIX nss3 DLL_SUFFIX, since that's likely to be correct.
    1203           1 :   nsAutoCString nss3Dir;
    1204           1 :   nsresult rv = GetNSS3Directory(nss3Dir);
    1205           1 :   if (NS_SUCCEEDED(rv)) {
    1206             :     if (!possibleCKBILocations.append(std::move(nss3Dir))) {
    1207             :       return NS_ERROR_OUT_OF_MEMORY;
    1208             :     }
    1209             :   } else {
    1210             :     // For some reason this fails on android. In any case, we should try with
    1211           0 :     // the other potential locations we have.
    1212             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1213             :             ("could not determine where nss was loaded from"));
    1214           1 :   }
    1215           1 :   nsAutoCString currentProcessDir;
    1216           1 :   rv = GetDirectoryPath(NS_XPCOM_CURRENT_PROCESS_DIR, currentProcessDir);
    1217           1 :   if (NS_SUCCEEDED(rv)) {
    1218             :     if (!possibleCKBILocations.append(std::move(currentProcessDir))) {
    1219             :       return NS_ERROR_OUT_OF_MEMORY;
    1220             :     }
    1221           0 :   } else {
    1222             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1223             :             ("could not get current process directory"));
    1224           1 :   }
    1225           1 :   nsAutoCString greDir;
    1226           1 :   rv = GetDirectoryPath(NS_GRE_DIR, greDir);
    1227           1 :   if (NS_SUCCEEDED(rv)) {
    1228             :     if (!possibleCKBILocations.append(std::move(greDir))) {
    1229             :       return NS_ERROR_OUT_OF_MEMORY;
    1230             :     }
    1231           0 :   } else {
    1232             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not get gre directory"));
    1233             :   }
    1234             :   // As a last resort, this will cause the library loading code to use the OS'
    1235           0 :   // default library search path.
    1236           0 :   nsAutoCString emptyString;
    1237             :   if (!possibleCKBILocations.append(std::move(emptyString))) {
    1238             :     return NS_ERROR_OUT_OF_MEMORY;
    1239             :   }
    1240           1 : 
    1241           1 :   for (const auto& possibleCKBILocation : possibleCKBILocations) {
    1242           1 :     if (mozilla::psm::LoadLoadableRoots(possibleCKBILocation)) {
    1243             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("loaded CKBI from %s",
    1244             :                                             possibleCKBILocation.get()));
    1245             :       return NS_OK;
    1246             :     }
    1247           0 :   }
    1248             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not load loadable roots"));
    1249             :   return NS_ERROR_FAILURE;
    1250             : }
    1251             : 
    1252             : // Table of pref names and SSL cipher ID
    1253             : typedef struct {
    1254             :   const char* pref;
    1255             :   long id;
    1256             :   bool enabledByDefault;
    1257             : } CipherPref;
    1258             : 
    1259             : // Update the switch statement in AccumulateCipherSuite in nsNSSCallbacks.cpp
    1260             : // when you add/remove cipher suites here.
    1261             : static const CipherPref sCipherPrefs[] = {
    1262             :  { "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
    1263             :    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, true },
    1264             :  { "security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256",
    1265             :    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, true },
    1266             : 
    1267             :  { "security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256",
    1268             :    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, true },
    1269             :  { "security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256",
    1270             :    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, true },
    1271             : 
    1272             :  { "security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384",
    1273             :    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, true },
    1274             :  { "security.ssl3.ecdhe_rsa_aes_256_gcm_sha384",
    1275             :    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, true },
    1276             : 
    1277             :  { "security.ssl3.ecdhe_rsa_aes_128_sha",
    1278             :    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, true },
    1279             :  { "security.ssl3.ecdhe_ecdsa_aes_128_sha",
    1280             :    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, true },
    1281             : 
    1282             :  { "security.ssl3.ecdhe_rsa_aes_256_sha",
    1283             :    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, true },
    1284             :  { "security.ssl3.ecdhe_ecdsa_aes_256_sha",
    1285             :    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, true },
    1286             : 
    1287             :  { "security.ssl3.dhe_rsa_aes_128_sha",
    1288             :    TLS_DHE_RSA_WITH_AES_128_CBC_SHA, true },
    1289             : 
    1290             :  { "security.ssl3.dhe_rsa_aes_256_sha",
    1291             :    TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true },
    1292             : 
    1293             :  { "security.tls13.aes_128_gcm_sha256",
    1294             :    TLS_AES_128_GCM_SHA256, true },
    1295             :  { "security.tls13.chacha20_poly1305_sha256",
    1296             :    TLS_CHACHA20_POLY1305_SHA256, true },
    1297             :  { "security.tls13.aes_256_gcm_sha384",
    1298             :    TLS_AES_256_GCM_SHA384, true },
    1299             : 
    1300             :  { "security.ssl3.rsa_aes_128_sha",
    1301             :    TLS_RSA_WITH_AES_128_CBC_SHA, true }, // deprecated (RSA key exchange)
    1302             :  { "security.ssl3.rsa_aes_256_sha",
    1303             :    TLS_RSA_WITH_AES_256_CBC_SHA, true }, // deprecated (RSA key exchange)
    1304             :  { "security.ssl3.rsa_des_ede3_sha",
    1305             :    TLS_RSA_WITH_3DES_EDE_CBC_SHA, true }, // deprecated (RSA key exchange, 3DES)
    1306             : 
    1307             :  // All the rest are disabled
    1308             : 
    1309             :  { nullptr, 0 } // end marker
    1310             : };
    1311             : 
    1312             : // This function will convert from pref values like 1, 2, ...
    1313             : // to the internal values of SSL_LIBRARY_VERSION_TLS_1_0,
    1314             : // SSL_LIBRARY_VERSION_TLS_1_1, ...
    1315           3 : /*static*/ void
    1316             : nsNSSComponent::FillTLSVersionRange(SSLVersionRange& rangeOut,
    1317             :                                     uint32_t minFromPrefs,
    1318             :                                     uint32_t maxFromPrefs,
    1319             :                                     SSLVersionRange defaults)
    1320           3 : {
    1321             :   rangeOut = defaults;
    1322             :   // determine what versions are supported
    1323           3 :   SSLVersionRange supported;
    1324             :   if (SSL_VersionRangeGetSupported(ssl_variant_stream, &supported)
    1325           0 :         != SECSuccess) {
    1326             :     return;
    1327             :   }
    1328             : 
    1329             :   // Clip the defaults by what NSS actually supports to enable
    1330           6 :   // working with a system NSS with different ranges.
    1331           6 :   rangeOut.min = std::max(rangeOut.min, supported.min);
    1332             :   rangeOut.max = std::min(rangeOut.max, supported.max);
    1333             : 
    1334           3 :   // convert min/maxFromPrefs to the internal representation
    1335           3 :   minFromPrefs += SSL_LIBRARY_VERSION_3_0;
    1336             :   maxFromPrefs += SSL_LIBRARY_VERSION_3_0;
    1337           6 :   // if min/maxFromPrefs are invalid, use defaults
    1338           6 :   if (minFromPrefs > maxFromPrefs ||
    1339             :       minFromPrefs < supported.min || maxFromPrefs > supported.max ||
    1340             :       minFromPrefs < SSL_LIBRARY_VERSION_TLS_1_0) {
    1341             :     return;
    1342             :   }
    1343             : 
    1344           3 :   // fill out rangeOut
    1345           3 :   rangeOut.min = (uint16_t) minFromPrefs;
    1346             :   rangeOut.max = (uint16_t) maxFromPrefs;
    1347             : }
    1348             : 
    1349             : static const int32_t OCSP_ENABLED_DEFAULT = 1;
    1350             : static const bool REQUIRE_SAFE_NEGOTIATION_DEFAULT = false;
    1351             : static const bool FALSE_START_ENABLED_DEFAULT = true;
    1352             : static const bool ALPN_ENABLED_DEFAULT = false;
    1353             : static const bool ENABLED_0RTT_DATA_DEFAULT = false;
    1354             : 
    1355           1 : static void
    1356             : ConfigureTLSSessionIdentifiers()
    1357             : {
    1358           1 :   bool disableSessionIdentifiers =
    1359           1 :     Preferences::GetBool("security.ssl.disable_session_identifiers", false);
    1360           1 :   SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, !disableSessionIdentifiers);
    1361           1 :   SSL_OptionSetDefault(SSL_NO_CACHE, disableSessionIdentifiers);
    1362             : }
    1363             : 
    1364             : namespace {
    1365             : 
    1366             : class CipherSuiteChangeObserver : public nsIObserver
    1367             : {
    1368             : public:
    1369             :   NS_DECL_ISUPPORTS
    1370             :   NS_DECL_NSIOBSERVER
    1371             : 
    1372             :   static nsresult StartObserve();
    1373             : 
    1374           0 : protected:
    1375             :   virtual ~CipherSuiteChangeObserver() {}
    1376             : 
    1377             : private:
    1378           3 :   static StaticRefPtr<CipherSuiteChangeObserver> sObserver;
    1379             :   CipherSuiteChangeObserver() {}
    1380             : };
    1381          42 : 
    1382             : NS_IMPL_ISUPPORTS(CipherSuiteChangeObserver, nsIObserver)
    1383             : 
    1384           1 : // static
    1385             : StaticRefPtr<CipherSuiteChangeObserver> CipherSuiteChangeObserver::sObserver;
    1386             : 
    1387             : // static
    1388           0 : nsresult
    1389             : CipherSuiteChangeObserver::StartObserve()
    1390           1 : {
    1391             :   MOZ_ASSERT(NS_IsMainThread(),
    1392             :              "CipherSuiteChangeObserver::StartObserve() can only be accessed "
    1393           1 :              "on the main thread");
    1394           0 :   if (!sObserver) {
    1395           0 :     RefPtr<CipherSuiteChangeObserver> observer = new CipherSuiteChangeObserver();
    1396           1 :     nsresult rv = Preferences::AddStrongObserver(observer.get(), "security.");
    1397           0 :     if (NS_FAILED(rv)) {
    1398           0 :       sObserver = nullptr;
    1399             :       return rv;
    1400             :     }
    1401             : 
    1402           0 :     nsCOMPtr<nsIObserverService> observerService =
    1403           1 :       mozilla::services::GetObserverService();
    1404           2 :     observerService->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
    1405             :                                  false);
    1406           2 : 
    1407             :     sObserver = observer;
    1408             :   }
    1409             :   return NS_OK;
    1410             : }
    1411             : 
    1412           0 : nsresult
    1413             : CipherSuiteChangeObserver::Observe(nsISupports* /*aSubject*/,
    1414             :                                    const char* aTopic,
    1415             :                                    const char16_t* someData)
    1416           0 : {
    1417             :   MOZ_ASSERT(NS_IsMainThread(),
    1418             :              "CipherSuiteChangeObserver::Observe can only be accessed on main "
    1419           0 :              "thread");
    1420           0 :   if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
    1421             :     NS_ConvertUTF16toUTF8  prefName(someData);
    1422           0 :     // Look through the cipher table and set according to pref setting
    1423           0 :     const CipherPref* const cp = sCipherPrefs;
    1424           0 :     for (size_t i = 0; cp[i].pref; ++i) {
    1425           0 :       if (prefName.Equals(cp[i].pref)) {
    1426           0 :         bool cipherEnabled = Preferences::GetBool(cp[i].pref,
    1427           0 :                                                   cp[i].enabledByDefault);
    1428           0 :         SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled);
    1429           0 :         SSL_ClearSessionCache();
    1430             :         break;
    1431             :       }
    1432           0 :     }
    1433           0 :   } else if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
    1434           0 :     Preferences::RemoveObserver(this, "security.");
    1435           0 :     MOZ_ASSERT(sObserver.get() == this);
    1436             :     sObserver = nullptr;
    1437           0 :     nsCOMPtr<nsIObserverService> observerService =
    1438           0 :       mozilla::services::GetObserverService();
    1439             :     observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
    1440           0 :   }
    1441             :   return NS_OK;
    1442             : }
    1443             : 
    1444             : } // namespace
    1445           0 : 
    1446             : void nsNSSComponent::setValidationOptions(
    1447             :   bool isInitialSetting, const mozilla::MutexAutoLock& proofOfLock)
    1448             : {
    1449             :   // This preference controls whether we do OCSP fetching and does not affect
    1450             :   // OCSP stapling.
    1451             :   // 0 = disabled, 1 = enabled
    1452           0 :   int32_t ocspEnabled = Preferences::GetInt("security.OCSP.enabled",
    1453             :                                             OCSP_ENABLED_DEFAULT);
    1454           1 : 
    1455           1 :   bool ocspRequired = ocspEnabled &&
    1456             :     Preferences::GetBool("security.OCSP.require", false);
    1457             : 
    1458             :   // We measure the setting of the pref at startup only to minimize noise by
    1459           0 :   // addons that may muck with the settings, though it probably doesn't matter.
    1460           0 :   if (isInitialSetting) {
    1461           0 :     Telemetry::Accumulate(Telemetry::CERT_OCSP_ENABLED, ocspEnabled);
    1462             :     Telemetry::Accumulate(Telemetry::CERT_OCSP_REQUIRED, ocspRequired);
    1463             :   }
    1464             : 
    1465           1 :   bool ocspStaplingEnabled = Preferences::GetBool("security.ssl.enable_ocsp_stapling",
    1466           2 :                                                   true);
    1467           2 :   PublicSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);
    1468             :   PrivateSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);
    1469             : 
    1470           1 :   bool ocspMustStapleEnabled = Preferences::GetBool("security.ssl.enable_ocsp_must_staple",
    1471           2 :                                                     true);
    1472           2 :   PublicSSLState()->SetOCSPMustStapleEnabled(ocspMustStapleEnabled);
    1473             :   PrivateSSLState()->SetOCSPMustStapleEnabled(ocspMustStapleEnabled);
    1474             : 
    1475           1 :   const CertVerifier::CertificateTransparencyMode defaultCTMode =
    1476             :     CertVerifier::CertificateTransparencyMode::TelemetryOnly;
    1477             :   CertVerifier::CertificateTransparencyMode ctMode =
    1478             :     static_cast<CertVerifier::CertificateTransparencyMode>
    1479           0 :       (Preferences::GetInt("security.pki.certificate_transparency.mode",
    1480           0 :                            static_cast<int32_t>(defaultCTMode)));
    1481             :   switch (ctMode) {
    1482             :     case CertVerifier::CertificateTransparencyMode::Disabled:
    1483             :     case CertVerifier::CertificateTransparencyMode::TelemetryOnly:
    1484             :       break;
    1485           0 :     default:
    1486           0 :       ctMode = defaultCTMode;
    1487             :       break;
    1488             :   }
    1489           0 :   bool sctsEnabled =
    1490           0 :     ctMode != CertVerifier::CertificateTransparencyMode::Disabled;
    1491           0 :   PublicSSLState()->SetSignedCertTimestampsEnabled(sctsEnabled);
    1492             :   PrivateSSLState()->SetSignedCertTimestampsEnabled(sctsEnabled);
    1493             : 
    1494             :   CertVerifier::PinningMode pinningMode =
    1495           0 :     static_cast<CertVerifier::PinningMode>
    1496           1 :       (Preferences::GetInt("security.cert_pinning.enforcement_level",
    1497           0 :                            CertVerifier::pinningDisabled));
    1498           0 :   if (pinningMode > CertVerifier::pinningEnforceTestMode) {
    1499             :     pinningMode = CertVerifier::pinningDisabled;
    1500             :   }
    1501             : 
    1502             :   CertVerifier::SHA1Mode sha1Mode = static_cast<CertVerifier::SHA1Mode>
    1503           1 :       (Preferences::GetInt("security.pki.sha1_enforcement_level",
    1504           1 :                            static_cast<int32_t>(CertVerifier::SHA1Mode::Allowed)));
    1505             :   switch (sha1Mode) {
    1506             :     case CertVerifier::SHA1Mode::Allowed:
    1507             :     case CertVerifier::SHA1Mode::Forbidden:
    1508             :     case CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
    1509             :     case CertVerifier::SHA1Mode::ImportedRoot:
    1510             :     case CertVerifier::SHA1Mode::ImportedRootOrBefore2016:
    1511             :       break;
    1512           0 :     default:
    1513           0 :       sha1Mode = CertVerifier::SHA1Mode::Allowed;
    1514             :       break;
    1515             :   }
    1516             : 
    1517           0 :   // Convert a previously-available setting to a safe one.
    1518           0 :   if (sha1Mode == CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden) {
    1519             :     sha1Mode = CertVerifier::SHA1Mode::Forbidden;
    1520             :   }
    1521             : 
    1522             :   BRNameMatchingPolicy::Mode nameMatchingMode =
    1523             :     static_cast<BRNameMatchingPolicy::Mode>
    1524           0 :       (Preferences::GetInt("security.pki.name_matching_mode",
    1525           1 :                            static_cast<int32_t>(BRNameMatchingPolicy::Mode::DoNotEnforce)));
    1526             :   switch (nameMatchingMode) {
    1527             :     case BRNameMatchingPolicy::Mode::Enforce:
    1528             :     case BRNameMatchingPolicy::Mode::EnforceAfter23August2015:
    1529             :     case BRNameMatchingPolicy::Mode::EnforceAfter23August2016:
    1530             :     case BRNameMatchingPolicy::Mode::DoNotEnforce:
    1531             :       break;
    1532           0 :     default:
    1533           0 :       nameMatchingMode = BRNameMatchingPolicy::Mode::DoNotEnforce;
    1534             :       break;
    1535             :   }
    1536             : 
    1537             :   NetscapeStepUpPolicy netscapeStepUpPolicy =
    1538             :     static_cast<NetscapeStepUpPolicy>
    1539           1 :       (Preferences::GetUint("security.pki.netscape_step_up_policy",
    1540           1 :                             static_cast<uint32_t>(NetscapeStepUpPolicy::AlwaysMatch)));
    1541             :   switch (netscapeStepUpPolicy) {
    1542             :     case NetscapeStepUpPolicy::AlwaysMatch:
    1543             :     case NetscapeStepUpPolicy::MatchBefore23August2016:
    1544             :     case NetscapeStepUpPolicy::MatchBefore23August2015:
    1545             :     case NetscapeStepUpPolicy::NeverMatch:
    1546             :       break;
    1547           0 :     default:
    1548           0 :       netscapeStepUpPolicy = NetscapeStepUpPolicy::AlwaysMatch;
    1549             :       break;
    1550             :   }
    1551             : 
    1552           0 :   DistrustedCAPolicy defaultCAPolicyMode =
    1553             :     DistrustedCAPolicy::DistrustSymantecRoots;
    1554             :   DistrustedCAPolicy distrustedCAPolicy =
    1555             :     static_cast<DistrustedCAPolicy>
    1556           1 :       (Preferences::GetUint("security.pki.distrust_ca_policy",
    1557             :                             static_cast<uint32_t>(defaultCAPolicyMode)));
    1558             :   // If distrustedCAPolicy sets any bits larger than the maximum mask, fall back
    1559           1 :   // to the default.
    1560           0 :   if (distrustedCAPolicy & ~DistrustedCAPolicyMaxAllowedValueMask) {
    1561             :     distrustedCAPolicy = defaultCAPolicyMode;
    1562             :   }
    1563             : 
    1564             :   CertVerifier::OcspDownloadConfig odc;
    1565             :   CertVerifier::OcspStrictConfig osc;
    1566           1 :   uint32_t certShortLifetimeInDays;
    1567           1 :   TimeDuration softTimeout;
    1568             :   TimeDuration hardTimeout;
    1569             : 
    1570           1 :   GetRevocationBehaviorFromPrefs(&odc, &osc, &certShortLifetimeInDays,
    1571             :                                  softTimeout, hardTimeout, proofOfLock);
    1572             :   mDefaultCertVerifier = new SharedCertVerifier(odc, osc, softTimeout,
    1573             :                                                 hardTimeout,
    1574             :                                                 certShortLifetimeInDays,
    1575             :                                                 pinningMode, sha1Mode,
    1576             :                                                 nameMatchingMode,
    1577           3 :                                                 netscapeStepUpPolicy,
    1578           1 :                                                 ctMode, distrustedCAPolicy);
    1579             : }
    1580             : 
    1581             : // Enable the TLS versions given in the prefs, defaulting to TLS 1.0 (min) and
    1582             : // TLS 1.2 (max) when the prefs aren't set or set to invalid values.
    1583           1 : nsresult
    1584             : nsNSSComponent::setEnabledTLSVersions()
    1585             : {
    1586             :   // keep these values in sync with security-prefs.js
    1587             :   // 1 means TLS 1.0, 2 means TLS 1.1, etc.
    1588             :   static const uint32_t PSM_DEFAULT_MIN_TLS_VERSION = 1;
    1589             :   static const uint32_t PSM_DEFAULT_MAX_TLS_VERSION = 4;
    1590             : 
    1591           1 :   uint32_t minFromPrefs = Preferences::GetUint("security.tls.version.min",
    1592             :                                                PSM_DEFAULT_MIN_TLS_VERSION);
    1593           1 :   uint32_t maxFromPrefs = Preferences::GetUint("security.tls.version.max",
    1594             :                                                PSM_DEFAULT_MAX_TLS_VERSION);
    1595             : 
    1596             :   SSLVersionRange defaults = {
    1597             :     SSL_LIBRARY_VERSION_3_0 + PSM_DEFAULT_MIN_TLS_VERSION,
    1598           1 :     SSL_LIBRARY_VERSION_3_0 + PSM_DEFAULT_MAX_TLS_VERSION
    1599             :   };
    1600           1 :   SSLVersionRange filledInRange;
    1601             :   FillTLSVersionRange(filledInRange, minFromPrefs, maxFromPrefs, defaults);
    1602             : 
    1603           1 :   SECStatus srv =
    1604           1 :     SSL_VersionRangeSetDefault(ssl_variant_stream, &filledInRange);
    1605             :   if (srv != SECSuccess) {
    1606             :     return NS_ERROR_FAILURE;
    1607             :   }
    1608           1 : 
    1609             :   return NS_OK;
    1610             : }
    1611             : 
    1612             : #if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
    1613             : // If the profile directory is on a networked drive, we want to set the
    1614             : // environment variable NSS_SDB_USE_CACHE to yes (as long as it hasn't been set
    1615             : // before).
    1616           0 : static void
    1617             : SetNSSDatabaseCacheModeAsAppropriate()
    1618           2 : {
    1619           1 :   nsCOMPtr<nsIFile> profileFile;
    1620           2 :   nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
    1621           1 :                                        getter_AddRefs(profileFile));
    1622             :   if (NS_FAILED(rv)) {
    1623             :     // We're probably running without a profile directory, so this is
    1624           0 :     // irrelevant.
    1625             :     return;
    1626             :   }
    1627             : 
    1628             :   static const char sNSS_SDB_USE_CACHE[] = "NSS_SDB_USE_CACHE";
    1629           2 :   static const char sNSS_SDB_USE_CACHE_WITH_VALUE[] = "NSS_SDB_USE_CACHE=yes";
    1630             :   auto profilePath = profileFile->NativePath();
    1631             : 
    1632             : #if defined(XP_LINUX) && !defined(ANDROID)
    1633           3 :   struct statfs statfs_s;
    1634           0 :   if (statfs(profilePath.get(), &statfs_s) == 0 &&
    1635           0 :       statfs_s.f_type == NFS_SUPER_MAGIC &&
    1636           0 :       !PR_GetEnv(sNSS_SDB_USE_CACHE)) {
    1637             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1638             :             ("profile is remote (and NSS_SDB_USE_CACHE wasn't set): "
    1639           0 :              "setting NSS_SDB_USE_CACHE"));
    1640             :     PR_SetEnv(sNSS_SDB_USE_CACHE_WITH_VALUE);
    1641           1 :   } else {
    1642             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("not setting NSS_SDB_USE_CACHE"));
    1643             :   }
    1644             : #endif // defined(XP_LINUX) && !defined(ANDROID)
    1645             : 
    1646             : #ifdef XP_WIN
    1647             :   wchar_t volPath[MAX_PATH];
    1648             :   if (::GetVolumePathNameW(profilePath.get(), volPath, MAX_PATH) &&
    1649             :       ::GetDriveTypeW(volPath) == DRIVE_REMOTE &&
    1650             :       !PR_GetEnv(sNSS_SDB_USE_CACHE)) {
    1651             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1652             :             ("profile is remote (and NSS_SDB_USE_CACHE wasn't set): "
    1653             :              "setting NSS_SDB_USE_CACHE"));
    1654             :     PR_SetEnv(sNSS_SDB_USE_CACHE_WITH_VALUE);
    1655             :   } else {
    1656             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("not setting NSS_SDB_USE_CACHE"));
    1657             :   }
    1658             : #endif // XP_WIN
    1659             : }
    1660             : #endif // defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
    1661             : 
    1662           1 : static nsresult
    1663             : GetNSSProfilePath(nsAutoCString& aProfilePath)
    1664           1 : {
    1665           0 :   aProfilePath.Truncate();
    1666           1 :   nsCOMPtr<nsIFile> profileFile;
    1667           2 :   nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
    1668           1 :                                        getter_AddRefs(profileFile));
    1669             :   if (NS_FAILED(rv)) {
    1670           0 :     NS_WARNING("NSS will be initialized without a profile directory. "
    1671           0 :                "Some things may not work as expected.");
    1672             :     return NS_OK;
    1673             :   }
    1674             : 
    1675             : #if defined(XP_WIN)
    1676             :   // SQLite always takes UTF-8 file paths regardless of the current system
    1677             :   // code page.
    1678             :   nsCOMPtr<nsILocalFileWin> profileFileWin(do_QueryInterface(profileFile));
    1679             :   if (!profileFileWin) {
    1680             :     MOZ_LOG(gPIPNSSLog, LogLevel::Error,
    1681             :            ("Could not get nsILocalFileWin for profile directory.\n"));
    1682             :     return NS_ERROR_FAILURE;
    1683             :   }
    1684             :   nsAutoString u16ProfilePath;
    1685             :   rv = profileFileWin->GetCanonicalPath(u16ProfilePath);
    1686             :   CopyUTF16toUTF8(u16ProfilePath, aProfilePath);
    1687           1 : #else
    1688             :   rv = profileFile->GetNativePath(aProfilePath);
    1689           1 : #endif
    1690           0 :   if (NS_FAILED(rv)) {
    1691             :     MOZ_LOG(gPIPNSSLog, LogLevel::Error,
    1692             :            ("Could not get native path for profile directory.\n"));
    1693             :     return rv;
    1694             :   }
    1695           1 : 
    1696             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1697             :           ("NSS profile at '%s'\n", aProfilePath.get()));
    1698             :   return NS_OK;
    1699             : }
    1700             : 
    1701             : #ifndef ANDROID
    1702             : // Given a profile path, attempt to rename the PKCS#11 module DB to
    1703             : // "<original name>.fips". In the case of a catastrophic failure (e.g. out of
    1704             : // memory), returns a failing nsresult. If execution could conceivably proceed,
    1705             : // returns NS_OK even if renaming the file didn't work. This simplifies the
    1706             : // logic of the calling code.
    1707           0 : static nsresult
    1708             : AttemptToRenamePKCS11ModuleDB(const nsACString& profilePath,
    1709             :                               const nsACString& moduleDBFilename)
    1710           0 : {
    1711           0 :   nsAutoCString destModuleDBFilename(moduleDBFilename);
    1712           0 :   destModuleDBFilename.Append(".fips");
    1713           0 :   nsCOMPtr<nsIFile> dbFile = do_CreateInstance("@mozilla.org/file/local;1");
    1714             :   if (!dbFile) {
    1715             :     return NS_ERROR_FAILURE;
    1716           0 :   }
    1717           0 :   nsresult rv = dbFile->InitWithNativePath(profilePath);
    1718             :   if (NS_FAILED(rv)) {
    1719             :     return rv;
    1720           0 :   }
    1721           0 :   rv = dbFile->AppendNative(moduleDBFilename);
    1722             :   if (NS_FAILED(rv)) {
    1723             :     return rv;
    1724             :   }
    1725             :   // If the PKCS#11 module DB doesn't exist, renaming it won't help.
    1726           0 :   bool exists;
    1727           0 :   rv = dbFile->Exists(&exists);
    1728             :   if (NS_FAILED(rv)) {
    1729             :     return rv;
    1730             :   }
    1731           0 :   // This is strange, but not a catastrophic failure.
    1732           0 :   if (!exists) {
    1733             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1734             :             ("%s doesn't exist?", PromiseFlatCString(moduleDBFilename).get()));
    1735             :     return NS_OK;
    1736           0 :   }
    1737           0 :   nsCOMPtr<nsIFile> destDBFile = do_CreateInstance("@mozilla.org/file/local;1");
    1738             :   if (!destDBFile) {
    1739             :     return NS_ERROR_FAILURE;
    1740           0 :   }
    1741           0 :   rv = destDBFile->InitWithNativePath(profilePath);
    1742             :   if (NS_FAILED(rv)) {
    1743             :     return rv;
    1744           0 :   }
    1745           0 :   rv = destDBFile->AppendNative(destModuleDBFilename);
    1746             :   if (NS_FAILED(rv)) {
    1747             :     return rv;
    1748             :   }
    1749             :   // If the destination exists, presumably we've already tried this. Doing it
    1750           0 :   // again won't help.
    1751           0 :   rv = destDBFile->Exists(&exists);
    1752             :   if (NS_FAILED(rv)) {
    1753             :     return rv;
    1754             :   }
    1755           0 :   // Unfortunate, but not a catastrophic failure.
    1756           0 :   if (exists) {
    1757             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1758             :             ("%s already exists - not overwriting",
    1759             :              destModuleDBFilename.get()));
    1760             :     return NS_OK;
    1761             :   }
    1762           0 :   // Now do the actual move.
    1763           0 :   nsCOMPtr<nsIFile> profileDir = do_CreateInstance("@mozilla.org/file/local;1");
    1764             :   if (!profileDir) {
    1765             :     return NS_ERROR_FAILURE;
    1766           0 :   }
    1767           0 :   rv = profileDir->InitWithNativePath(profilePath);
    1768             :   if (NS_FAILED(rv)) {
    1769             :     return rv;
    1770             :   }
    1771             :   // This may fail on, e.g., a read-only file system. This would be unfortunate,
    1772             :   // but again it isn't catastropic and we would want to fall back to
    1773           0 :   // initializing NSS in no-DB mode.
    1774           0 :   Unused << dbFile->MoveToNative(profileDir, destModuleDBFilename);
    1775             :   return NS_OK;
    1776             : }
    1777             : 
    1778             : // The platform now only uses the sqlite-backed databases, so we'll try to
    1779             : // rename "pkcs11.txt". However, if we're upgrading from a version that used the
    1780             : // old format, we need to try to rename the old "secmod.db" as well (if we were
    1781             : // to only rename "pkcs11.txt", initializing NSS will still fail due to the old
    1782             : // database being in FIPS mode).
    1783           0 : static nsresult
    1784             : AttemptToRenameBothPKCS11ModuleDBVersions(const nsACString& profilePath)
    1785           0 : {
    1786           0 :   NS_NAMED_LITERAL_CSTRING(legacyModuleDBFilename, "secmod.db");
    1787             :   NS_NAMED_LITERAL_CSTRING(sqlModuleDBFilename, "pkcs11.txt");
    1788           0 :   nsresult rv = AttemptToRenamePKCS11ModuleDB(profilePath,
    1789           0 :                                               legacyModuleDBFilename);
    1790             :   if (NS_FAILED(rv)) {
    1791             :     return rv;
    1792           0 :   }
    1793             :   return AttemptToRenamePKCS11ModuleDB(profilePath, sqlModuleDBFilename);
    1794             : }
    1795             : #endif // ifndef ANDROID
    1796             : 
    1797             : // Given a profile directory, attempt to initialize NSS. If nocertdb is true,
    1798             : // (or if we don't have a profile directory) simply initialize NSS in no DB mode
    1799             : // and return. Otherwise, first attempt to initialize in read/write mode, and
    1800             : // then read-only mode if that fails. If both attempts fail, we may be failing
    1801             : // to initialize an NSS DB collection that has FIPS mode enabled. Attempt to
    1802             : // ascertain if this is the case, and if so, rename the offending PKCS#11 module
    1803             : // DB so we can (hopefully) initialize NSS in read-write mode. Again attempt
    1804             : // read-only mode if that fails. Finally, fall back to no DB mode. On Android
    1805             : // we can skip the FIPS workaround since it was never possible to enable FIPS
    1806             : // there anyway.
    1807           1 : static nsresult
    1808             : InitializeNSSWithFallbacks(const nsACString& profilePath, bool nocertdb,
    1809             :                            bool safeMode)
    1810           1 : {
    1811           0 :   if (nocertdb || profilePath.IsEmpty()) {
    1812             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1813           0 :             ("nocertdb mode or empty profile path -> NSS_NoDB_Init"));
    1814           0 :     SECStatus srv = NSS_NoDB_Init(nullptr);
    1815             :     return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
    1816             :   }
    1817             : 
    1818             : 
    1819             :   // Try read/write mode. If we're in safeMode, we won't load PKCS#11 modules.
    1820             : #ifndef ANDROID
    1821             :   PRErrorCode savedPRErrorCode1;
    1822           1 : #endif // ifndef ANDROID
    1823           1 :   SECStatus srv = ::mozilla::psm::InitializeNSS(profilePath, false, !safeMode);
    1824           1 :   if (srv == SECSuccess) {
    1825             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r/w mode"));
    1826             :     return NS_OK;
    1827             :   }
    1828           0 : #ifndef ANDROID
    1829             :   savedPRErrorCode1 = PR_GetError();
    1830             :   PRErrorCode savedPRErrorCode2;
    1831             : #endif // ifndef ANDROID
    1832           0 :   // That failed. Try read-only mode.
    1833           0 :   srv = ::mozilla::psm::InitializeNSS(profilePath, true, !safeMode);
    1834           0 :   if (srv == SECSuccess) {
    1835             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r-o mode"));
    1836             :     return NS_OK;
    1837             :   }
    1838           0 : #ifndef ANDROID
    1839             :   savedPRErrorCode2 = PR_GetError();
    1840           0 : 
    1841             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1842             :           ("failed to initialize NSS with codes %d %d", savedPRErrorCode1,
    1843             :            savedPRErrorCode2));
    1844             : #endif // ifndef ANDROID
    1845             : 
    1846             : #ifndef ANDROID
    1847             :   // That failed as well. Maybe we're trying to load a PKCS#11 module DB that is
    1848             :   // in FIPS mode, but we don't support FIPS? Test load NSS without PKCS#11
    1849           0 :   // modules. If that succeeds, that's probably what's going on.
    1850           0 :   if (!safeMode && (savedPRErrorCode1 == SEC_ERROR_LEGACY_DATABASE ||
    1851           0 :                     savedPRErrorCode2 == SEC_ERROR_LEGACY_DATABASE ||
    1852           0 :                     savedPRErrorCode1 == SEC_ERROR_PKCS11_DEVICE_ERROR ||
    1853           0 :                     savedPRErrorCode2 == SEC_ERROR_PKCS11_DEVICE_ERROR)) {
    1854             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("attempting no-module db init"));
    1855             :     // It would make sense to initialize NSS in read-only mode here since this
    1856             :     // is just a test to see if the PKCS#11 module DB being in FIPS mode is the
    1857             :     // problem, but for some reason the combination of read-only and no-moddb
    1858             :     // flags causes NSS initialization to fail, so unfortunately we have to use
    1859           0 :     // read-write mode.
    1860           0 :     srv = ::mozilla::psm::InitializeNSS(profilePath, false, false);
    1861           0 :     if (srv == SECSuccess) {
    1862             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("FIPS may be the problem"));
    1863           0 :       // Unload NSS so we can attempt to fix this situation for the user.
    1864           0 :       srv = NSS_Shutdown();
    1865             :       if (srv != SECSuccess) {
    1866             :         return NS_ERROR_FAILURE;
    1867           0 :       }
    1868             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trying to rename module db"));
    1869             :       // If this fails non-catastrophically, we'll attempt to initialize NSS
    1870             :       // again in r/w then r-o mode (both of which will fail), and then we'll
    1871           0 :       // fall back to NSS_NoDB_Init, which is the behavior we want.
    1872           0 :       nsresult rv = AttemptToRenameBothPKCS11ModuleDBVersions(profilePath);
    1873             :       if (NS_FAILED(rv)) {
    1874             :         return rv;
    1875           0 :       }
    1876           0 :       srv = ::mozilla::psm::InitializeNSS(profilePath, false, true);
    1877           0 :       if (srv == SECSuccess) {
    1878             :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r/w mode"));
    1879             :         return NS_OK;
    1880           0 :       }
    1881           0 :       srv = ::mozilla::psm::InitializeNSS(profilePath, true, true);
    1882           0 :       if (srv == SECSuccess) {
    1883             :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r-o mode"));
    1884             :         return NS_OK;
    1885             :       }
    1886             :     }
    1887             :   }
    1888             : #endif
    1889           0 : 
    1890           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("last-resort NSS_NoDB_Init"));
    1891           0 :   srv = NSS_NoDB_Init(nullptr);
    1892             :   return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
    1893             : }
    1894             : 
    1895           1 : nsresult
    1896             : nsNSSComponent::InitializeNSS()
    1897           1 : {
    1898             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::InitializeNSS\n"));
    1899             : 
    1900             :   static_assert(nsINSSErrorsService::NSS_SEC_ERROR_BASE == SEC_ERROR_BASE &&
    1901             :                 nsINSSErrorsService::NSS_SEC_ERROR_LIMIT == SEC_ERROR_LIMIT &&
    1902             :                 nsINSSErrorsService::NSS_SSL_ERROR_BASE == SSL_ERROR_BASE &&
    1903             :                 nsINSSErrorsService::NSS_SSL_ERROR_LIMIT == SSL_ERROR_LIMIT,
    1904             :                 "You must update the values in nsINSSErrorsService.idl");
    1905           1 : 
    1906             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization beginning\n"));
    1907           1 : 
    1908           1 :   nsAutoCString profileStr;
    1909           1 :   nsresult rv = GetNSSProfilePath(profileStr);
    1910             :   if (NS_FAILED(rv)) {
    1911             :     return NS_ERROR_NOT_AVAILABLE;
    1912             :   }
    1913             : 
    1914           1 : #if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
    1915             :   SetNSSDatabaseCacheModeAsAppropriate();
    1916             : #endif
    1917           1 : 
    1918           1 :   bool nocertdb = Preferences::GetBool("security.nocertdb", false);
    1919           2 :   bool inSafeMode = true;
    1920             :   nsCOMPtr<nsIXULRuntime> runtime(do_GetService("@mozilla.org/xre/runtime;1"));
    1921             :   // There might not be an nsIXULRuntime in embedded situations. This will
    1922             :   // default to assuming we are in safe mode (as a result, no external PKCS11
    1923           1 :   // modules will be loaded).
    1924           1 :   if (runtime) {
    1925           1 :     rv = runtime->GetInSafeMode(&inSafeMode);
    1926             :     if (NS_FAILED(rv)) {
    1927             :       return rv;
    1928             :     }
    1929           1 :   }
    1930             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("inSafeMode: %u\n", inSafeMode));
    1931           1 : 
    1932           1 :   rv = InitializeNSSWithFallbacks(profileStr, nocertdb, inSafeMode);
    1933           0 :   if (NS_FAILED(rv)) {
    1934             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to initialize NSS"));
    1935             :     return rv;
    1936             :   }
    1937           1 : 
    1938             :   PK11_SetPasswordFunc(PK11PasswordPrompt);
    1939           1 : 
    1940             :   SharedSSLState::GlobalInit();
    1941             : 
    1942           1 :   // Register an observer so we can inform NSS when these prefs change
    1943             :   Preferences::AddStrongObserver(this, "security.");
    1944           1 : 
    1945           1 :   SSL_OptionSetDefault(SSL_ENABLE_SSL2, false);
    1946             :   SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, false);
    1947           1 : 
    1948           1 :   rv = setEnabledTLSVersions();
    1949             :   if (NS_FAILED(rv)) {
    1950             :     return NS_ERROR_UNEXPECTED;
    1951             :   }
    1952           0 : 
    1953             :   DisableMD5();
    1954             : 
    1955             : #ifdef XP_WIN
    1956             :   // Note that these functions do not change the trust of any loaded 3rd party
    1957             :   // roots. Because we're initializing the nsNSSComponent, and because if the
    1958             :   // user has a master password set on the softoken it could cause the
    1959             :   // authentication dialog to come up, we could conceivably re-enter
    1960             :   // nsNSSComponent initialization, which would be bad. Instead, we schedule an
    1961             :   // event to set the trust after the component has been initialized (below).
    1962             :   MaybeEnableFamilySafetyCompatibility();
    1963             :   MaybeImportEnterpriseRoots();
    1964             : #endif // XP_WIN
    1965           1 : 
    1966             :   ConfigureTLSSessionIdentifiers();
    1967             : 
    1968             :   bool requireSafeNegotiation =
    1969           1 :     Preferences::GetBool("security.ssl.require_safe_negotiation",
    1970           0 :                          REQUIRE_SAFE_NEGOTIATION_DEFAULT);
    1971             :   SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation);
    1972           0 : 
    1973             :   SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_REQUIRES_XTN);
    1974           0 : 
    1975             :   SSL_OptionSetDefault(SSL_ENABLE_EXTENDED_MASTER_SECRET, true);
    1976           1 : 
    1977           1 :   SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,
    1978           1 :                        Preferences::GetBool("security.ssl.enable_false_start",
    1979             :                                             FALSE_START_ENABLED_DEFAULT));
    1980             : 
    1981             :   // SSL_ENABLE_ALPN also requires calling SSL_SetNextProtoNego in order for
    1982             :   // the extensions to be negotiated.
    1983             :   // WebRTC does not do that so it will not use ALPN even when this preference
    1984           0 :   // is true.
    1985           1 :   SSL_OptionSetDefault(SSL_ENABLE_ALPN,
    1986           1 :                        Preferences::GetBool("security.ssl.enable_alpn",
    1987             :                                             ALPN_ENABLED_DEFAULT));
    1988           0 : 
    1989           0 :   SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,
    1990           0 :                        Preferences::GetBool("security.tls.enable_0rtt_data",
    1991             :                                             ENABLED_0RTT_DATA_DEFAULT));
    1992           1 : 
    1993           0 :   if (NS_FAILED(InitializeCipherSuite())) {
    1994             :     MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("Unable to initialize cipher suite settings\n"));
    1995             :     return NS_ERROR_FAILURE;
    1996             :   }
    1997           0 : 
    1998             :   mozilla::pkix::RegisterErrorTable();
    1999           1 : 
    2000           0 :   if (PK11_IsFIPS()) {
    2001             :     Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
    2002             :   }
    2003             : 
    2004             :   // Gather telemetry on any PKCS#11 modules we have loaded. Note that because
    2005             :   // we load the built-in root module asynchronously after this, the telemetry
    2006             :   // will not include it.
    2007           0 :   { // Introduce scope for the AutoSECMODListReadLock.
    2008           2 :     AutoSECMODListReadLock lock;
    2009           0 :     for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
    2010           0 :          list = list->next) {
    2011           1 :       nsAutoString scalarKey;
    2012             :       GetModuleNameForTelemetry(list->module, scalarKey);
    2013             :       // Scalar keys must be between 0 and 70 characters (exclusive).
    2014             :       // GetModuleNameForTelemetry takes care of keys that are too long. If for
    2015             :       // some reason it couldn't come up with an appropriate name and returned
    2016             :       // an empty result, however, we need to not attempt to record this (it
    2017           0 :       // wouldn't give us anything useful anyway).
    2018             :       if (scalarKey.Length() > 0) {
    2019           1 :         Telemetry::ScalarSet(
    2020             :           Telemetry::ScalarID::SECURITY_PKCS11_MODULES_LOADED, scalarKey, true);
    2021             :       }
    2022             :     }
    2023             :   }
    2024           1 : 
    2025             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
    2026             : 
    2027           2 :   {
    2028             :     MutexAutoLock lock(mMutex);
    2029             : 
    2030             :     // ensure we have initial values for various root hashes
    2031           1 : #ifdef DEBUG
    2032             :     mTestBuiltInRootHash.Truncate();
    2033           1 :     Preferences::GetString("security.test.built_in_root_hash",
    2034             :                            mTestBuiltInRootHash);
    2035           0 : #endif
    2036             :     mContentSigningRootHash.Truncate();
    2037           0 :     Preferences::GetString("security.content.signature.root_hash",
    2038             :                            mContentSigningRootHash);
    2039           0 : 
    2040             :     mMitmCanaryIssuer.Truncate();
    2041           0 :     Preferences::GetString("security.pki.mitm_canary_issuer",
    2042           0 :                            mMitmCanaryIssuer);
    2043           0 :     mMitmDetecionEnabled =
    2044             :       Preferences::GetBool("security.pki.mitm_canary_issuer.enabled", true);
    2045             : 
    2046             : #ifdef XP_WIN
    2047             :     nsCOMPtr<nsINSSComponent> handle(this);
    2048             :     NS_DispatchToCurrentThread(NS_NewRunnableFunction("nsNSSComponent::TrustLoaded3rdPartyRoots",
    2049             :     [handle]() {
    2050             :       MOZ_ALWAYS_SUCCEEDS(handle->TrustLoaded3rdPartyRoots());
    2051             :     }));
    2052             : #endif // XP_WIN
    2053             : 
    2054             :     // TLSServerSocket may be run with the session cache enabled. It is
    2055             :     // necessary to call this once before that can happen. This specifies a
    2056             :     // maximum of 1000 cache entries (the default number of cache entries is
    2057             :     // 10000, which seems a little excessive as there probably won't be that
    2058             :     // many clients connecting to any TLSServerSockets the browser runs.) Note
    2059             :     // that this must occur before any calls to SSL_ClearSessionCache (otherwise
    2060           1 :     // memory will leak).
    2061             :     if (SSL_ConfigServerSessionIDCache(1000, 0, 0, nullptr) != SECSuccess) {
    2062             :       return NS_ERROR_FAILURE;
    2063             :     }
    2064             : 
    2065             :     // Set dynamic options from prefs. This has to run after
    2066           1 :     // SSL_ConfigServerSessionIDCache.
    2067             :     setValidationOptions(true, lock);
    2068             : 
    2069           2 :     RefPtr<LoadLoadableRootsTask> loadLoadableRootsTask(
    2070           1 :       new LoadLoadableRootsTask(this));
    2071           1 :     rv = loadLoadableRootsTask->Dispatch();
    2072             :     if (NS_FAILED(rv)) {
    2073             :       return rv;
    2074             :     }
    2075           0 : 
    2076           0 :     mNSSInitialized = true;
    2077             :     return NS_OK;
    2078             :   }
    2079             : }
    2080             : 
    2081           0 : void
    2082             : nsNSSComponent::ShutdownNSS()
    2083           0 : {
    2084           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::ShutdownNSS\n"));
    2085             :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
    2086           0 : 
    2087             :   MutexAutoLock lock(mMutex);
    2088             : 
    2089             :   // We have to block until the load loadable roots task has completed, because
    2090             :   // otherwise we might try to unload the loadable roots while the loadable
    2091             :   // roots loading thread is setting up EV information, which can cause
    2092             :   // it to fail to find the roots it is expecting. However, if initialization
    2093             :   // failed, we won't have dispatched the load loadable roots background task.
    2094           0 :   // In that case, we don't want to block on an event that will never happen.
    2095           0 :   if (mNSSInitialized) {
    2096             :     Unused << BlockUntilLoadableRootsLoaded();
    2097             : 
    2098             :     // We can only run SSL_ShutdownServerSessionIDCache once (the rest of
    2099           0 :     // these operations are idempotent).
    2100             :     SSL_ClearSessionCache();
    2101             :     // TLSServerSocket may be run with the session cache enabled. This ensures
    2102           0 :     // those resources are cleaned up.
    2103             :     Unused << SSL_ShutdownServerSessionIDCache();
    2104             :   }
    2105           0 : 
    2106             :   ::mozilla::psm::UnloadLoadableRoots();
    2107             : 
    2108             : #ifdef XP_WIN
    2109             :   mFamilySafetyRoot = nullptr;
    2110             :   mEnterpriseRoots = nullptr;
    2111             : #endif
    2112           0 : 
    2113             :   PK11_SetPasswordFunc((PK11PasswordFunc)nullptr);
    2114           0 : 
    2115             :   Preferences::RemoveObserver(this, "security.");
    2116             : 
    2117             :   // Release the default CertVerifier. This will cause any held NSS resources
    2118           0 :   // to be released.
    2119             :   mDefaultCertVerifier = nullptr;
    2120             :   // We don't actually shut down NSS - XPCOM does, after all threads have been
    2121             :   // joined and the component manager has been shut down (and so there shouldn't
    2122             :   // be any XPCOM objects holding NSS resources).
    2123           0 : 
    2124           0 :   mNSSInitialized = false;
    2125             : }
    2126             : 
    2127           1 : nsresult
    2128             : nsNSSComponent::Init()
    2129           1 : {
    2130           1 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
    2131             :   if (!NS_IsMainThread()) {
    2132             :     return NS_ERROR_NOT_SAME_THREAD;
    2133             :   }
    2134           0 : 
    2135           0 :   MOZ_ASSERT(XRE_IsParentProcess());
    2136             :   if (!XRE_IsParentProcess()) {
    2137             :     return NS_ERROR_NOT_AVAILABLE;
    2138             :   }
    2139           1 : 
    2140             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Beginning NSS initialization\n"));
    2141           0 : 
    2142           1 :   nsresult rv = InitializeNSS();
    2143           0 :   if (NS_FAILED(rv)) {
    2144             :     MOZ_LOG(gPIPNSSLog, LogLevel::Error,
    2145             :             ("nsNSSComponent::InitializeNSS() failed\n"));
    2146             :     return rv;
    2147             :   }
    2148           0 : 
    2149             :   RememberCertErrorsTable::Init();
    2150           1 : 
    2151             :   return RegisterObservers();
    2152             : }
    2153             : 
    2154          88 : // nsISupports Implementation for the class
    2155             : NS_IMPL_ISUPPORTS(nsNSSComponent,
    2156             :                   nsINSSComponent,
    2157             :                   nsIObserver)
    2158             : 
    2159             : static const char* const PROFILE_BEFORE_CHANGE_TOPIC = "profile-before-change";
    2160             : 
    2161           0 : NS_IMETHODIMP
    2162             : nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
    2163             :                         const char16_t* someData)
    2164             : {
    2165             :   // In some tests, we don't receive a "profile-before-change" topic. However,
    2166             :   // we still have to shut down before the storage service shuts down, because
    2167             :   // closing the sql-backed softoken requires sqlite still be available. Thus,
    2168           0 :   // we observe "xpcom-shutdown" just in case.
    2169           0 :   if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0 ||
    2170           0 :       nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
    2171             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    2172           0 :             ("receiving profile change or XPCOM shutdown notification"));
    2173           0 :     ShutdownNSS();
    2174           0 :   } else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
    2175           0 :     bool clearSessionCache = true;
    2176             :     NS_ConvertUTF16toUTF8  prefName(someData);
    2177           0 : 
    2178           0 :     if (prefName.EqualsLiteral("security.tls.version.min") ||
    2179           0 :         prefName.EqualsLiteral("security.tls.version.max")) {
    2180           0 :       (void) setEnabledTLSVersions();
    2181             :     } else if (prefName.EqualsLiteral("security.ssl.require_safe_negotiation")) {
    2182             :       bool requireSafeNegotiation =
    2183           0 :         Preferences::GetBool("security.ssl.require_safe_negotiation",
    2184           0 :                              REQUIRE_SAFE_NEGOTIATION_DEFAULT);
    2185           0 :       SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation);
    2186           0 :     } else if (prefName.EqualsLiteral("security.ssl.enable_false_start")) {
    2187           0 :       SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,
    2188           0 :                            Preferences::GetBool("security.ssl.enable_false_start",
    2189           0 :                                                 FALSE_START_ENABLED_DEFAULT));
    2190           0 :     } else if (prefName.EqualsLiteral("security.ssl.enable_alpn")) {
    2191           0 :       SSL_OptionSetDefault(SSL_ENABLE_ALPN,
    2192           0 :                            Preferences::GetBool("security.ssl.enable_alpn",
    2193           0 :                                                 ALPN_ENABLED_DEFAULT));
    2194           0 :     } else if (prefName.EqualsLiteral("security.tls.enable_0rtt_data")) {
    2195           0 :       SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,
    2196           0 :                            Preferences::GetBool("security.tls.enable_0rtt_data",
    2197           0 :                                                 ENABLED_0RTT_DATA_DEFAULT));
    2198           0 :     } else if (prefName.EqualsLiteral("security.ssl.disable_session_identifiers")) {
    2199           0 :       ConfigureTLSSessionIdentifiers();
    2200           0 :     } else if (prefName.EqualsLiteral("security.OCSP.enabled") ||
    2201           0 :                prefName.EqualsLiteral("security.OCSP.require") ||
    2202           0 :                prefName.EqualsLiteral("security.pki.cert_short_lifetime_in_days") ||
    2203           0 :                prefName.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
    2204           0 :                prefName.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
    2205           0 :                prefName.EqualsLiteral("security.pki.certificate_transparency.mode") ||
    2206           0 :                prefName.EqualsLiteral("security.cert_pinning.enforcement_level") ||
    2207           0 :                prefName.EqualsLiteral("security.pki.sha1_enforcement_level") ||
    2208           0 :                prefName.EqualsLiteral("security.pki.name_matching_mode") ||
    2209           0 :                prefName.EqualsLiteral("security.pki.netscape_step_up_policy") ||
    2210           0 :                prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.soft") ||
    2211           0 :                prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.hard") ||
    2212           0 :                prefName.EqualsLiteral("security.pki.distrust_ca_policy")) {
    2213           0 :       MutexAutoLock lock(mMutex);
    2214             :       setValidationOptions(false, lock);
    2215           0 : #ifdef DEBUG
    2216           0 :     } else if (prefName.EqualsLiteral("security.test.built_in_root_hash")) {
    2217           0 :       MutexAutoLock lock(mMutex);
    2218             :       mTestBuiltInRootHash.Truncate();
    2219           0 :       Preferences::GetString("security.test.built_in_root_hash",
    2220             :                              mTestBuiltInRootHash);
    2221             : #endif // DEBUG
    2222             : #ifdef XP_WIN
    2223             :     } else if (prefName.Equals(kFamilySafetyModePref)) {
    2224             :       // When the pref changes, it is safe to change the trust of 3rd party
    2225             :       // roots in the same event tick that they're loaded.
    2226             :       UnloadFamilySafetyRoot();
    2227             :       MaybeEnableFamilySafetyCompatibility();
    2228             :       TrustLoaded3rdPartyRoots();
    2229           0 : #endif // XP_WIN
    2230           0 :     } else if (prefName.EqualsLiteral("security.content.signature.root_hash")) {
    2231           0 :       MutexAutoLock lock(mMutex);
    2232             :       mContentSigningRootHash.Truncate();
    2233           0 :       Preferences::GetString("security.content.signature.root_hash",
    2234             :                              mContentSigningRootHash);
    2235             : #ifdef XP_WIN
    2236             :     } else if (prefName.Equals(kEnterpriseRootModePref)) {
    2237             :       // When the pref changes, it is safe to change the trust of 3rd party
    2238             :       // roots in the same event tick that they're loaded.
    2239             :       UnloadEnterpriseRoots();
    2240             :       MaybeImportEnterpriseRoots();
    2241             :       TrustLoaded3rdPartyRoots();
    2242           0 : #endif // XP_WIN
    2243           0 :     } else if (prefName.EqualsLiteral("security.pki.mitm_canary_issuer")) {
    2244           0 :       MutexAutoLock lock(mMutex);
    2245             :       mMitmCanaryIssuer.Truncate();
    2246           0 :       Preferences::GetString("security.pki.mitm_canary_issuer",
    2247           0 :                              mMitmCanaryIssuer);
    2248             :     } else if (prefName.EqualsLiteral(
    2249           0 :                  "security.pki.mitm_canary_issuer.enabled")) {
    2250           0 :       MutexAutoLock lock(mMutex);
    2251           0 :       mMitmDetecionEnabled =
    2252             :         Preferences::GetBool("security.pki.mitm_canary_issuer.enabled", true);
    2253             :     } else {
    2254             :       clearSessionCache = false;
    2255           0 :     }
    2256           0 :     if (clearSessionCache)
    2257             :       SSL_ClearSessionCache();
    2258             :   }
    2259           0 : 
    2260             :   return NS_OK;
    2261             : }
    2262             : 
    2263           0 : /*static*/ nsresult
    2264             : nsNSSComponent::GetNewPrompter(nsIPrompt** result)
    2265           0 : {
    2266           0 :   NS_ENSURE_ARG_POINTER(result);
    2267             :   *result = nullptr;
    2268           0 : 
    2269           0 :   if (!NS_IsMainThread()) {
    2270           0 :     NS_ERROR("nsSDRContext::GetNewPrompter called off the main thread");
    2271             :     return NS_ERROR_NOT_SAME_THREAD;
    2272             :   }
    2273             : 
    2274           0 :   nsresult rv;
    2275           0 :   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
    2276             :   NS_ENSURE_SUCCESS(rv, rv);
    2277           0 : 
    2278           0 :   rv = wwatch->GetNewPrompter(0, result);
    2279             :   NS_ENSURE_SUCCESS(rv, rv);
    2280             : 
    2281             :   return rv;
    2282             : }
    2283           0 : 
    2284             : nsresult nsNSSComponent::LogoutAuthenticatedPK11()
    2285             : {
    2286           0 :   nsCOMPtr<nsICertOverrideService> icos =
    2287           0 :     do_GetService("@mozilla.org/security/certoverride;1");
    2288           0 :   if (icos) {
    2289           0 :     icos->ClearValidityOverride(
    2290           0 :             NS_LITERAL_CSTRING("all:temporary-certificates"),
    2291             :             0);
    2292             :   }
    2293           0 : 
    2294             :   nsClientAuthRememberService::ClearAllRememberedDecisions();
    2295           0 : 
    2296           0 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    2297           0 :   if (os) {
    2298             :     os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr);
    2299             :   }
    2300           0 : 
    2301             :   return NS_OK;
    2302             : }
    2303             : 
    2304           0 : nsresult
    2305             : nsNSSComponent::RegisterObservers()
    2306             : {
    2307           2 :   nsCOMPtr<nsIObserverService> observerService(
    2308           1 :     do_GetService("@mozilla.org/observer-service;1"));
    2309           0 :   if (!observerService) {
    2310             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    2311             :             ("nsNSSComponent: couldn't get observer service\n"));
    2312             :     return NS_ERROR_FAILURE;
    2313             :   }
    2314           0 : 
    2315             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent: adding observers\n"));
    2316             :   // Using false for the ownsweak parameter means the observer service will
    2317             :   // keep a strong reference to this component. As a result, this will live at
    2318           0 :   // least as long as the observer service.
    2319           1 :   observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, false);
    2320             :   observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
    2321           0 : 
    2322             :   return NS_OK;
    2323             : }
    2324             : 
    2325             : #ifdef DEBUG
    2326           0 : NS_IMETHODIMP
    2327             : nsNSSComponent::IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result)
    2328           1 : {
    2329             :   result = false;
    2330           0 : 
    2331           1 :   RefPtr<nsNSSCertificate> nsc = nsNSSCertificate::Create(cert);
    2332             :   if (!nsc) {
    2333             :     return NS_ERROR_FAILURE;
    2334           0 :   }
    2335           1 :   nsAutoString certHash;
    2336           0 :   nsresult rv = nsc->GetSha256Fingerprint(certHash);
    2337             :   if (NS_FAILED(rv)) {
    2338             :     return rv;
    2339             :   }
    2340           1 : 
    2341           1 :   MutexAutoLock lock(mMutex);
    2342           1 :   MOZ_ASSERT(mNSSInitialized);
    2343             :   if (mTestBuiltInRootHash.IsEmpty()) {
    2344             :     return NS_OK;
    2345             :   }
    2346           0 : 
    2347           0 :   result = mTestBuiltInRootHash.Equals(certHash);
    2348             :   return NS_OK;
    2349             : }
    2350             : #endif // DEBUG
    2351             : 
    2352           0 : NS_IMETHODIMP
    2353             : nsNSSComponent::IsCertContentSigningRoot(CERTCertificate* cert, bool& result)
    2354           0 : {
    2355             :   result = false;
    2356           0 : 
    2357           0 :   RefPtr<nsNSSCertificate> nsc = nsNSSCertificate::Create(cert);
    2358           0 :   if (!nsc) {
    2359             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("creating nsNSSCertificate failed"));
    2360             :     return NS_ERROR_FAILURE;
    2361           0 :   }
    2362           0 :   nsAutoString certHash;
    2363           0 :   nsresult rv = nsc->GetSha256Fingerprint(certHash);
    2364           0 :   if (NS_FAILED(rv)) {
    2365             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("getting cert fingerprint failed"));
    2366             :     return rv;
    2367             :   }
    2368           0 : 
    2369           0 :   MutexAutoLock lock(mMutex);
    2370             :   MOZ_ASSERT(mNSSInitialized);
    2371           0 : 
    2372           0 :   if (mContentSigningRootHash.IsEmpty()) {
    2373             :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("mContentSigningRootHash is empty"));
    2374             :     return NS_ERROR_FAILURE;
    2375             :   }
    2376           0 : 
    2377           0 :   result = mContentSigningRootHash.Equals(certHash);
    2378             :   return NS_OK;
    2379             : }
    2380             : 
    2381           0 : NS_IMETHODIMP
    2382             : nsNSSComponent::IssuerMatchesMitmCanary(const char* aCertIssuer)
    2383           0 : {
    2384           0 :   MutexAutoLock lock(mMutex);
    2385           0 :   if (mMitmDetecionEnabled && !mMitmCanaryIssuer.IsEmpty()) {
    2386           0 :     nsString certIssuer = NS_ConvertUTF8toUTF16(aCertIssuer);
    2387           0 :     if (mMitmCanaryIssuer.Equals(certIssuer)) {
    2388             :       return NS_OK;
    2389             :     }
    2390             :   }
    2391             : 
    2392             :   return NS_ERROR_FAILURE;
    2393             : }
    2394           0 : 
    2395             : SharedCertVerifier::~SharedCertVerifier() { }
    2396             : 
    2397           0 : already_AddRefed<SharedCertVerifier>
    2398             : nsNSSComponent::GetDefaultCertVerifier()
    2399           0 : {
    2400           1 :   MutexAutoLock lock(mMutex);
    2401           0 :   MOZ_ASSERT(mNSSInitialized);
    2402           0 :   RefPtr<SharedCertVerifier> certVerifier(mDefaultCertVerifier);
    2403             :   return certVerifier.forget();
    2404             : }
    2405             : 
    2406             : namespace mozilla { namespace psm {
    2407             : 
    2408           1 : already_AddRefed<SharedCertVerifier>
    2409             : GetDefaultCertVerifier()
    2410             : {
    2411             :   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
    2412           0 : 
    2413           0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID));
    2414           1 :   if (nssComponent) {
    2415             :     return nssComponent->GetDefaultCertVerifier();
    2416             :   }
    2417             : 
    2418             :   return nullptr;
    2419             : }
    2420             : 
    2421             : } } // namespace mozilla::psm
    2422           0 : 
    2423             : NS_IMPL_ISUPPORTS(PipUIContext, nsIInterfaceRequestor)
    2424           0 : 
    2425             : PipUIContext::PipUIContext()
    2426           0 : {
    2427             : }
    2428           0 : 
    2429             : PipUIContext::~PipUIContext()
    2430           0 : {
    2431             : }
    2432             : 
    2433           0 : NS_IMETHODIMP
    2434             : PipUIContext::GetInterface(const nsIID& uuid, void** result)
    2435           0 : {
    2436           0 :   NS_ENSURE_ARG_POINTER(result);
    2437             :   *result = nullptr;
    2438           0 : 
    2439           0 :   if (!NS_IsMainThread()) {
    2440           0 :     NS_ERROR("PipUIContext::GetInterface called off the main thread");
    2441             :     return NS_ERROR_NOT_SAME_THREAD;
    2442             :   }
    2443           0 : 
    2444             :   if (!uuid.Equals(NS_GET_IID(nsIPrompt)))
    2445             :     return NS_ERROR_NO_INTERFACE;
    2446           0 : 
    2447           0 :   nsIPrompt* prompt = nullptr;
    2448           0 :   nsresult rv = nsNSSComponent::GetNewPrompter(&prompt);
    2449           0 :   *result = prompt;
    2450             :   return rv;
    2451             : }
    2452             : 
    2453           0 : nsresult
    2454             : getNSSDialogs(void** _result, REFNSIID aIID, const char* contract)
    2455           0 : {
    2456           0 :   if (!NS_IsMainThread()) {
    2457           0 :     NS_ERROR("getNSSDialogs called off the main thread");
    2458             :     return NS_ERROR_NOT_SAME_THREAD;
    2459             :   }
    2460             : 
    2461             :   nsresult rv;
    2462           0 : 
    2463           0 :   nsCOMPtr<nsISupports> svc = do_GetService(contract, &rv);
    2464             :   if (NS_FAILED(rv)) {
    2465             :     return rv;
    2466             :   }
    2467           0 : 
    2468             :   rv = svc->QueryInterface(aIID, _result);
    2469           0 : 
    2470             :   return rv;
    2471             : }
    2472             : 
    2473           0 : nsresult
    2474             : setPassword(PK11SlotInfo* slot, nsIInterfaceRequestor* ctx)
    2475           0 : {
    2476           0 :   MOZ_ASSERT(slot);
    2477             :   MOZ_ASSERT(ctx);
    2478             :   NS_ENSURE_ARG_POINTER(slot);
    2479             :   NS_ENSURE_ARG_POINTER(ctx);
    2480           0 : 
    2481           0 :   if (PK11_NeedUserInit(slot)) {
    2482           0 :     nsCOMPtr<nsITokenPasswordDialogs> dialogs;
    2483             :     nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
    2484           0 :                                 NS_GET_IID(nsITokenPasswordDialogs),
    2485           0 :                                 NS_TOKENPASSWORDSDIALOG_CONTRACTID);
    2486           0 :     if (NS_FAILED(rv)) {
    2487             :       return rv;
    2488             :     }
    2489             : 
    2490           0 :     bool canceled;
    2491           0 :     nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot);
    2492           0 :     rv = dialogs->SetPassword(ctx, token, &canceled);
    2493           0 :     if (NS_FAILED(rv)) {
    2494             :       return rv;
    2495             :     }
    2496           0 : 
    2497             :     if (canceled) {
    2498             :       return NS_ERROR_NOT_AVAILABLE;
    2499             :     }
    2500             :   }
    2501             : 
    2502             :   return NS_OK;
    2503             : }
    2504             : 
    2505             : // NSS will call this during PKCS12 export to potentially switch the endianness
    2506             : // of the characters of `inBuf` to big (network) endian. Since we already did
    2507             : // that in nsPKCS12Blob::stringToBigEndianBytes, we just perform a memcpy here.
    2508             : extern "C" {
    2509           0 : PRBool
    2510             : pkcs12StringEndiannessConversion(PRBool, unsigned char* inBuf,
    2511             :                                  unsigned int inBufLen, unsigned char* outBuf,
    2512             :                                  unsigned int, unsigned int* outBufLen, PRBool)
    2513           0 : {
    2514           0 :   *outBufLen = inBufLen;
    2515           0 :   memcpy(outBuf, inBuf, inBufLen);
    2516             :   return true;
    2517             : }
    2518             : }
    2519             : 
    2520             : namespace mozilla {
    2521             : namespace psm {
    2522             : 
    2523           1 : nsresult
    2524             : InitializeCipherSuite()
    2525           1 : {
    2526             :   MOZ_ASSERT(NS_IsMainThread(),
    2527             :              "InitializeCipherSuite() can only be accessed on the main thread");
    2528           1 : 
    2529             :   if (NSS_SetDomesticPolicy() != SECSuccess) {
    2530             :     return NS_ERROR_FAILURE;
    2531             :   }
    2532             : 
    2533           0 :   // Disable any ciphers that NSS might have enabled by default
    2534           0 :   for (uint16_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
    2535          71 :     uint16_t cipher_id = SSL_ImplementedCiphers[i];
    2536             :     SSL_CipherPrefSetDefault(cipher_id, false);
    2537             :   }
    2538             : 
    2539             :   // Now only set SSL/TLS ciphers we knew about at compile time
    2540           0 :   const CipherPref* const cp = sCipherPrefs;
    2541          18 :   for (size_t i = 0; cp[i].pref; ++i) {
    2542          36 :     bool cipherEnabled = Preferences::GetBool(cp[i].pref,
    2543          18 :                                               cp[i].enabledByDefault);
    2544             :     SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled);
    2545             :   }
    2546             : 
    2547           0 :   // Enable ciphers for PKCS#12
    2548           1 :   SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
    2549           1 :   SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
    2550           1 :   SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
    2551           0 :   SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
    2552           1 :   SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
    2553           1 :   SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
    2554           1 :   SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
    2555             :   PORT_SetUCS2_ASCIIConversionFunction(pkcs12StringEndiannessConversion);
    2556             : 
    2557             :   // PSM enforces a minimum RSA key size of 1024 bits, which is overridable.
    2558             :   // NSS has its own minimum, which is not overridable (the default is 1023
    2559             :   // bits). This sets the NSS minimum to 512 bits so users can still connect to
    2560             :   // devices like wifi routers with woefully small keys (they would have to add
    2561           1 :   // an override to do so, but they already do for such devices).
    2562             :   NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 512);
    2563             : 
    2564           1 :   // Observe preference change around cipher suite setting.
    2565             :   return CipherSuiteChangeObserver::StartObserve();
    2566             : }
    2567             : 
    2568           3 : } // namespace psm
    2569             : } // namespace mozilla

Generated by: LCOV version 1.13-14-ga5dd952