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