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