Bug 1935611 - Fix libyuv/libpng link failed for loongarch64. r=glandium,tnikkel,ng
[gecko.git] / security / manager / ssl / nsNSSComponent.cpp
blob8d00ed734930c99717daaf538c94a9a307b4dfc9
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
7 #include "nsNSSComponent.h"
9 #include "BinaryPath.h"
10 #include "CryptoTask.h"
11 #include "EnterpriseRoots.h"
12 #include "ExtendedValidation.h"
13 #include "NSSCertDBTrustDomain.h"
14 #include "PKCS11ModuleDB.h"
15 #include "SSLTokensCache.h"
16 #include "ScopedNSSTypes.h"
17 #include "cert.h"
18 #include "cert_storage/src/cert_storage.h"
19 #include "certdb.h"
20 #include "mozilla/AppShutdown.h"
21 #include "mozilla/ArrayUtils.h"
22 #include "mozilla/Assertions.h"
23 #include "mozilla/Base64.h"
24 #include "mozilla/Casting.h"
25 #include "mozilla/EndianUtils.h"
26 #include "mozilla/FilePreferences.h"
27 #include "mozilla/PodOperations.h"
28 #include "mozilla/Preferences.h"
29 #include "mozilla/ProfilerLabels.h"
30 #include "mozilla/ProfilerMarkers.h"
31 #include "mozilla/PublicSSL.h"
32 #include "mozilla/ScopeExit.h"
33 #include "mozilla/Services.h"
34 #include "mozilla/StaticMutex.h"
35 #include "mozilla/StaticPrefs_security.h"
36 #include "mozilla/StaticPtr.h"
37 #include "mozilla/SyncRunnable.h"
38 #include "mozilla/Telemetry.h"
39 #include "mozilla/TimeStamp.h"
40 #include "mozilla/Unused.h"
41 #include "mozilla/Vector.h"
42 #include "mozilla/dom/Promise.h"
43 #include "mozilla/net/SocketProcessParent.h"
44 #include "mozpkix/pkixnss.h"
45 #include "nsAppDirectoryServiceDefs.h"
46 #include "nsCRT.h"
47 #include "nsClientAuthRemember.h"
48 #include "nsComponentManagerUtils.h"
49 #include "nsDirectoryServiceDefs.h"
50 #include "nsICertOverrideService.h"
51 #include "nsIFile.h"
52 #include "nsIOService.h"
53 #include "nsIObserverService.h"
54 #include "nsIPrompt.h"
55 #include "nsIProperties.h"
56 #include "nsISerialEventTarget.h"
57 #include "nsISiteSecurityService.h"
58 #include "nsITimer.h"
59 #include "nsITokenPasswordDialogs.h"
60 #include "nsIWindowWatcher.h"
61 #include "nsIXULRuntime.h"
62 #include "nsLiteralString.h"
63 #include "nsNSSHelper.h"
64 #include "nsNSSIOLayer.h"
65 #include "nsNetCID.h"
66 #include "nsPK11TokenDB.h"
67 #include "nsPrintfCString.h"
68 #include "nsServiceManagerUtils.h"
69 #include "nsThreadUtils.h"
70 #include "nsXULAppAPI.h"
71 #include "nss.h"
72 #include "p12plcy.h"
73 #include "pk11pub.h"
74 #include "prmem.h"
75 #include "secerr.h"
76 #include "secmod.h"
77 #include "ssl.h"
78 #include "sslerr.h"
79 #include "sslproto.h"
81 #if defined(XP_LINUX) && !defined(ANDROID)
82 # include <linux/magic.h>
83 # include <sys/vfs.h>
84 #endif
86 using namespace mozilla;
87 using namespace mozilla::psm;
89 LazyLogModule gPIPNSSLog("pipnss");
91 int nsNSSComponent::mInstanceCount = 0;
93 // Forward declaration.
94 nsresult CommonInit();
96 template <const glean::impl::QuantityMetric* metric>
97 class MOZ_RAII AutoGleanTimer {
98 public:
99 explicit AutoGleanTimer(TimeStamp aStart = TimeStamp::Now())
100 : mStart(aStart) {}
102 ~AutoGleanTimer() {
103 TimeStamp end = TimeStamp::Now();
104 uint32_t delta = static_cast<uint32_t>((end - mStart).ToMilliseconds());
105 metric->Set(delta);
108 private:
109 const TimeStamp mStart;
112 // Take an nsIFile and get a UTF-8-encoded c-string representation of the
113 // location of that file (encapsulated in an nsACString).
114 // This operation is generally to be avoided, except when interacting with
115 // third-party or legacy libraries that cannot handle `nsIFile`s (such as NSS).
116 // |result| is encoded in UTF-8.
117 nsresult FileToCString(const nsCOMPtr<nsIFile>& file, nsACString& result) {
118 #ifdef XP_WIN
119 nsAutoString path;
120 nsresult rv = file->GetPath(path);
121 if (NS_SUCCEEDED(rv)) {
122 CopyUTF16toUTF8(path, result);
124 return rv;
125 #else
126 return file->GetNativePath(result);
127 #endif
130 void TruncateFromLastDirectorySeparator(nsCString& path) {
131 static const nsAutoCString kSeparatorString(
132 mozilla::FilePreferences::kPathSeparator);
133 int32_t index = path.RFind(kSeparatorString);
134 if (index == kNotFound) {
135 return;
137 path.Truncate(index);
140 bool LoadIPCClientCerts() {
141 // This returns the path to the binary currently running, which in most
142 // cases is "plugin-container".
143 UniqueFreePtr<char> pluginContainerPath(BinaryPath::Get());
144 if (!pluginContainerPath) {
145 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
146 ("failed to get get plugin-container path"));
147 return false;
149 nsAutoCString ipcClientCertsDirString(pluginContainerPath.get());
150 // On most platforms, ipcclientcerts is in the same directory as
151 // plugin-container. To obtain the path to that directory, truncate from
152 // the last directory separator.
153 // On macOS, plugin-container is in
154 // Firefox.app/Contents/MacOS/plugin-container.app/Contents/MacOS/,
155 // whereas ipcclientcerts is in Firefox.app/Contents/MacOS/. Consequently,
156 // this truncation from the last directory separator has to happen 4 times
157 // total. Normally this would be done using nsIFile APIs, but due to when
158 // this is initialized in the socket process, those aren't available.
159 TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
160 #ifdef XP_MACOSX
161 TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
162 TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
163 TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
164 #endif
165 if (!LoadIPCClientCertsModule(ipcClientCertsDirString)) {
166 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
167 ("failed to load ipcclientcerts from '%s'",
168 ipcClientCertsDirString.get()));
169 return false;
171 return true;
174 // This function can be called from chrome or content or socket processes
175 // to ensure that NSS is initialized.
176 bool EnsureNSSInitializedChromeOrContent() {
177 static Atomic<bool> initialized(false);
179 if (initialized) {
180 return true;
183 // If this is not the main thread (i.e. probably a worker) then forward this
184 // call to the main thread.
185 if (!NS_IsMainThread()) {
186 nsCOMPtr<nsIThread> mainThread;
187 nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
188 if (NS_FAILED(rv)) {
189 return false;
192 // Forward to the main thread synchronously.
193 mozilla::SyncRunnable::DispatchToThread(
194 mainThread,
195 NS_NewRunnableFunction("EnsureNSSInitializedChromeOrContent", []() {
196 EnsureNSSInitializedChromeOrContent();
197 }));
199 return initialized;
202 if (XRE_IsParentProcess()) {
203 nsCOMPtr<nsISupports> nss = do_GetService(PSM_COMPONENT_CONTRACTID);
204 if (!nss) {
205 return false;
207 initialized = true;
208 return true;
211 if (NSS_IsInitialized()) {
212 initialized = true;
213 return true;
216 if (NSS_NoDB_Init(nullptr) != SECSuccess) {
217 return false;
220 if (XRE_IsSocketProcess()) {
221 if (NS_FAILED(CommonInit())) {
222 return false;
224 // If ipcclientcerts fails to load, client certificate authentication won't
225 // work (if networking is done on the socket process). This is preferable
226 // to stopping the program entirely, so treat this as best-effort.
227 Unused << NS_WARN_IF(!LoadIPCClientCerts());
228 initialized = true;
229 return true;
232 if (NS_FAILED(mozilla::psm::InitializeCipherSuite())) {
233 return false;
236 mozilla::psm::DisableMD5();
237 mozilla::pkix::RegisterErrorTable();
238 initialized = true;
239 return true;
242 static const uint32_t OCSP_TIMEOUT_MILLISECONDS_SOFT_MAX = 5000;
243 static const uint32_t OCSP_TIMEOUT_MILLISECONDS_HARD_MAX = 20000;
245 void nsNSSComponent::GetRevocationBehaviorFromPrefs(
246 /*out*/ CertVerifier::OcspDownloadConfig* odc,
247 /*out*/ CertVerifier::OcspStrictConfig* osc,
248 /*out*/ uint32_t* certShortLifetimeInDays,
249 /*out*/ TimeDuration& softTimeout,
250 /*out*/ TimeDuration& hardTimeout) {
251 MOZ_ASSERT(NS_IsMainThread());
252 MOZ_ASSERT(odc);
253 MOZ_ASSERT(osc);
254 MOZ_ASSERT(certShortLifetimeInDays);
256 // 0 = disabled
257 // 1 = enabled for everything (default)
258 // 2 = enabled for EV certificates only
259 uint32_t ocspLevel = StaticPrefs::security_OCSP_enabled();
260 switch (ocspLevel) {
261 case 0:
262 *odc = CertVerifier::ocspOff;
263 break;
264 case 2:
265 *odc = CertVerifier::ocspEVOnly;
266 break;
267 default:
268 *odc = CertVerifier::ocspOn;
269 break;
272 *osc = StaticPrefs::security_OCSP_require() ? CertVerifier::ocspStrict
273 : CertVerifier::ocspRelaxed;
275 *certShortLifetimeInDays =
276 StaticPrefs::security_pki_cert_short_lifetime_in_days();
278 uint32_t softTimeoutMillis =
279 StaticPrefs::security_OCSP_timeoutMilliseconds_soft();
280 softTimeoutMillis =
281 std::min(softTimeoutMillis, OCSP_TIMEOUT_MILLISECONDS_SOFT_MAX);
282 softTimeout = TimeDuration::FromMilliseconds(softTimeoutMillis);
284 uint32_t hardTimeoutMillis =
285 StaticPrefs::security_OCSP_timeoutMilliseconds_hard();
286 hardTimeoutMillis =
287 std::min(hardTimeoutMillis, OCSP_TIMEOUT_MILLISECONDS_HARD_MAX);
288 hardTimeout = TimeDuration::FromMilliseconds(hardTimeoutMillis);
291 nsNSSComponent::nsNSSComponent()
292 : mLoadableCertsLoadedMonitor("nsNSSComponent.mLoadableCertsLoadedMonitor"),
293 mLoadableCertsLoaded(false),
294 mLoadableCertsLoadedResult(NS_ERROR_FAILURE),
295 mMutex("nsNSSComponent.mMutex"),
296 mMitmDetecionEnabled(false) {
297 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::ctor\n"));
298 MOZ_RELEASE_ASSERT(NS_IsMainThread());
300 MOZ_ASSERT(mInstanceCount == 0,
301 "nsNSSComponent is a singleton, but instantiated multiple times!");
302 ++mInstanceCount;
305 nsNSSComponent::~nsNSSComponent() {
306 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::dtor\n"));
307 MOZ_RELEASE_ASSERT(NS_IsMainThread());
309 // All cleanup code requiring services needs to happen in xpcom_shutdown
311 PrepareForShutdown();
312 nsSSLIOLayerHelpers::GlobalCleanup();
313 --mInstanceCount;
315 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::dtor finished\n"));
318 void nsNSSComponent::UnloadEnterpriseRoots() {
319 MOZ_ASSERT(NS_IsMainThread());
320 if (!NS_IsMainThread()) {
321 return;
323 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadEnterpriseRoots"));
324 MutexAutoLock lock(mMutex);
325 mEnterpriseCerts.Clear();
326 setValidationOptions(false, lock);
327 ClearSSLExternalAndInternalSessionCache();
330 class BackgroundImportEnterpriseCertsTask final : public CryptoTask {
331 public:
332 explicit BackgroundImportEnterpriseCertsTask(nsNSSComponent* nssComponent)
333 : mNSSComponent(nssComponent) {}
335 private:
336 virtual nsresult CalculateResult() override {
337 mNSSComponent->ImportEnterpriseRoots();
338 mNSSComponent->UpdateCertVerifierWithEnterpriseRoots();
339 return NS_OK;
342 virtual void CallCallback(nsresult rv) override {
343 nsCOMPtr<nsIObserverService> observerService =
344 mozilla::services::GetObserverService();
345 if (observerService) {
346 observerService->NotifyObservers(nullptr, "psm:enterprise-certs-imported",
347 nullptr);
351 RefPtr<nsNSSComponent> mNSSComponent;
354 void nsNSSComponent::MaybeImportEnterpriseRoots() {
355 MOZ_ASSERT(NS_IsMainThread());
356 if (!NS_IsMainThread()) {
357 return;
359 bool importEnterpriseRoots = StaticPrefs::security_enterprise_roots_enabled();
360 if (importEnterpriseRoots) {
361 RefPtr<BackgroundImportEnterpriseCertsTask> task =
362 new BackgroundImportEnterpriseCertsTask(this);
363 Unused << task->Dispatch();
367 void nsNSSComponent::ImportEnterpriseRoots() {
368 MOZ_ASSERT(!NS_IsMainThread());
369 if (NS_IsMainThread()) {
370 return;
373 nsTArray<EnterpriseCert> enterpriseCerts;
374 nsresult rv = GatherEnterpriseCerts(enterpriseCerts);
375 if (NS_SUCCEEDED(rv)) {
376 MutexAutoLock lock(mMutex);
377 mEnterpriseCerts = std::move(enterpriseCerts);
378 } else {
379 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed gathering enterprise roots"));
383 nsresult nsNSSComponent::CommonGetEnterpriseCerts(
384 nsTArray<nsTArray<uint8_t>>& enterpriseCerts, bool getRoots) {
385 nsresult rv = BlockUntilLoadableCertsLoaded();
386 if (NS_FAILED(rv)) {
387 return rv;
390 enterpriseCerts.Clear();
391 MutexAutoLock nsNSSComponentLock(mMutex);
392 for (const auto& cert : mEnterpriseCerts) {
393 nsTArray<uint8_t> certCopy;
394 // mEnterpriseCerts includes both roots and intermediates.
395 if (cert.GetIsRoot() == getRoots) {
396 cert.CopyBytes(certCopy);
397 enterpriseCerts.AppendElement(std::move(certCopy));
400 return NS_OK;
403 NS_IMETHODIMP
404 nsNSSComponent::GetEnterpriseRoots(
405 nsTArray<nsTArray<uint8_t>>& enterpriseRoots) {
406 return CommonGetEnterpriseCerts(enterpriseRoots, true);
409 nsresult BytesArrayToPEM(const nsTArray<nsTArray<uint8_t>>& bytesArray,
410 nsACString& pemArray) {
411 for (const auto& bytes : bytesArray) {
412 nsAutoCString base64;
413 nsresult rv = Base64Encode(reinterpret_cast<const char*>(bytes.Elements()),
414 bytes.Length(), base64);
415 if (NS_FAILED(rv)) {
416 return rv;
418 if (!pemArray.IsEmpty()) {
419 pemArray.AppendLiteral("\n");
421 pemArray.AppendLiteral("-----BEGIN CERTIFICATE-----\n");
422 for (size_t i = 0; i < base64.Length() / 64; i++) {
423 pemArray.Append(Substring(base64, i * 64, 64));
424 pemArray.AppendLiteral("\n");
426 if (base64.Length() % 64 != 0) {
427 size_t chunks = base64.Length() / 64;
428 pemArray.Append(Substring(base64, chunks * 64));
429 pemArray.AppendLiteral("\n");
431 pemArray.AppendLiteral("-----END CERTIFICATE-----");
433 return NS_OK;
436 NS_IMETHODIMP
437 nsNSSComponent::GetEnterpriseRootsPEM(nsACString& enterpriseRootsPEM) {
438 nsTArray<nsTArray<uint8_t>> enterpriseRoots;
439 nsresult rv = GetEnterpriseRoots(enterpriseRoots);
440 if (NS_FAILED(rv)) {
441 return rv;
443 return BytesArrayToPEM(enterpriseRoots, enterpriseRootsPEM);
446 NS_IMETHODIMP
447 nsNSSComponent::GetEnterpriseIntermediates(
448 nsTArray<nsTArray<uint8_t>>& enterpriseIntermediates) {
449 return CommonGetEnterpriseCerts(enterpriseIntermediates, false);
452 NS_IMETHODIMP
453 nsNSSComponent::GetEnterpriseIntermediatesPEM(
454 nsACString& enterpriseIntermediatesPEM) {
455 nsTArray<nsTArray<uint8_t>> enterpriseIntermediates;
456 nsresult rv = GetEnterpriseIntermediates(enterpriseIntermediates);
457 if (NS_FAILED(rv)) {
458 return rv;
460 return BytesArrayToPEM(enterpriseIntermediates, enterpriseIntermediatesPEM);
463 NS_IMETHODIMP
464 nsNSSComponent::AddEnterpriseIntermediate(
465 const nsTArray<uint8_t>& intermediateBytes) {
466 nsresult rv = BlockUntilLoadableCertsLoaded();
467 if (NS_FAILED(rv)) {
468 return rv;
470 EnterpriseCert intermediate(intermediateBytes.Elements(),
471 intermediateBytes.Length(), false);
473 MutexAutoLock nsNSSComponentLock(mMutex);
474 mEnterpriseCerts.AppendElement(std::move(intermediate));
477 UpdateCertVerifierWithEnterpriseRoots();
478 return NS_OK;
481 class LoadLoadableCertsTask final : public Runnable {
482 public:
483 LoadLoadableCertsTask(nsNSSComponent* nssComponent,
484 bool importEnterpriseRoots,
485 Vector<nsCString>&& possibleLoadableRootsLocations,
486 Maybe<nsCString>&& osClientCertsModuleLocation)
487 : Runnable("LoadLoadableCertsTask"),
488 mNSSComponent(nssComponent),
489 mImportEnterpriseRoots(importEnterpriseRoots),
490 mPossibleLoadableRootsLocations(
491 std::move(possibleLoadableRootsLocations)),
492 mOSClientCertsModuleLocation(std::move(osClientCertsModuleLocation)) {
493 MOZ_ASSERT(nssComponent);
496 ~LoadLoadableCertsTask() = default;
498 nsresult Dispatch();
500 private:
501 NS_IMETHOD Run() override;
502 nsresult LoadLoadableRoots();
503 RefPtr<nsNSSComponent> mNSSComponent;
504 bool mImportEnterpriseRoots;
505 Vector<nsCString> mPossibleLoadableRootsLocations; // encoded in UTF-8
506 Maybe<nsCString> mOSClientCertsModuleLocation; // encoded in UTF-8
509 nsresult LoadLoadableCertsTask::Dispatch() {
510 // The stream transport service (note: not the socket transport service) can
511 // be used to perform background tasks or I/O that would otherwise block the
512 // main thread.
513 nsCOMPtr<nsIEventTarget> target(
514 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID));
515 if (!target) {
516 return NS_ERROR_FAILURE;
518 return target->Dispatch(this, NS_DISPATCH_NORMAL);
521 NS_IMETHODIMP
522 LoadLoadableCertsTask::Run() {
523 AutoGleanTimer<&glean::networking::loading_certs_task> timer;
525 nsresult loadLoadableRootsResult = LoadLoadableRoots();
526 if (NS_WARN_IF(NS_FAILED(loadLoadableRootsResult))) {
527 MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("LoadLoadableRoots failed"));
528 // We don't return loadLoadableRootsResult here because then
529 // BlockUntilLoadableCertsLoaded will just wait forever. Instead we'll save
530 // its value (below) so we can inform code that relies on the roots module
531 // being present that loading it failed.
534 // Loading EV information will only succeed if we've successfully loaded the
535 // loadable roots module.
536 if (NS_SUCCEEDED(loadLoadableRootsResult)) {
537 if (NS_FAILED(LoadExtendedValidationInfo())) {
538 // This isn't a show-stopper in the same way that failing to load the
539 // roots module is.
540 MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("failed to load EV info"));
544 if (mImportEnterpriseRoots) {
545 mNSSComponent->ImportEnterpriseRoots();
546 mNSSComponent->UpdateCertVerifierWithEnterpriseRoots();
548 if (mOSClientCertsModuleLocation.isSome()) {
549 bool success = LoadOSClientCertsModule(*mOSClientCertsModuleLocation);
550 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
551 ("loading OS client certs module %s",
552 success ? "succeeded" : "failed"));
555 MonitorAutoLock rootsLoadedLock(mNSSComponent->mLoadableCertsLoadedMonitor);
556 mNSSComponent->mLoadableCertsLoaded = true;
557 // Cache the result of LoadLoadableRoots so BlockUntilLoadableCertsLoaded
558 // can return it to all callers later (we use that particular result because
559 // if that operation fails, it's unlikely that any TLS connection will
560 // succeed whereas the browser may still be able to operate if the other
561 // tasks fail).
562 mNSSComponent->mLoadableCertsLoadedResult = loadLoadableRootsResult;
563 mNSSComponent->mLoadableCertsLoadedMonitor.NotifyAll();
565 return NS_OK;
568 // Returns by reference the path to the desired directory, based on the current
569 // settings in the directory service.
570 // |result| is encoded in UTF-8.
571 static nsresult GetDirectoryPath(const char* directoryKey, nsCString& result) {
572 MOZ_ASSERT(NS_IsMainThread());
574 nsCOMPtr<nsIProperties> directoryService(
575 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
576 if (!directoryService) {
577 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not get directory service"));
578 return NS_ERROR_FAILURE;
580 nsCOMPtr<nsIFile> directory;
581 nsresult rv = directoryService->Get(directoryKey, NS_GET_IID(nsIFile),
582 getter_AddRefs(directory));
583 if (NS_FAILED(rv)) {
584 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
585 ("could not get '%s' from directory service", directoryKey));
586 return rv;
588 return FileToCString(directory, result);
591 class BackgroundLoadOSClientCertsModuleTask final : public CryptoTask {
592 public:
593 explicit BackgroundLoadOSClientCertsModuleTask(const nsCString&& libraryDir)
594 : mLibraryDir(std::move(libraryDir)) {}
596 private:
597 virtual nsresult CalculateResult() override {
598 bool success = LoadOSClientCertsModule(mLibraryDir);
599 return success ? NS_OK : NS_ERROR_FAILURE;
602 virtual void CallCallback(nsresult rv) override {
603 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
604 ("loading OS client certs module %s",
605 NS_SUCCEEDED(rv) ? "succeeded" : "failed"));
606 nsCOMPtr<nsIObserverService> observerService =
607 mozilla::services::GetObserverService();
608 if (observerService) {
609 observerService->NotifyObservers(
610 nullptr, "psm:load-os-client-certs-module-task-ran", nullptr);
614 nsCString mLibraryDir;
617 void AsyncLoadOrUnloadOSClientCertsModule(bool load) {
618 if (load) {
619 nsCString libraryDir;
620 nsresult rv = GetDirectoryPath(NS_GRE_BIN_DIR, libraryDir);
621 if (NS_FAILED(rv)) {
622 return;
624 RefPtr<BackgroundLoadOSClientCertsModuleTask> task =
625 new BackgroundLoadOSClientCertsModuleTask(std::move(libraryDir));
626 Unused << task->Dispatch();
627 } else {
628 UniqueSECMODModule osClientCertsModule(
629 SECMOD_FindModule(kOSClientCertsModuleName.get()));
630 if (osClientCertsModule) {
631 SECMOD_UnloadUserModule(osClientCertsModule.get());
636 nsresult nsNSSComponent::BlockUntilLoadableCertsLoaded() {
637 MonitorAutoLock rootsLoadedLock(mLoadableCertsLoadedMonitor);
638 while (!mLoadableCertsLoaded) {
639 rootsLoadedLock.Wait();
641 MOZ_ASSERT(mLoadableCertsLoaded);
643 return mLoadableCertsLoadedResult;
646 #ifndef MOZ_NO_SMART_CARDS
647 static StaticMutex sCheckForSmartCardChangesMutex MOZ_UNANNOTATED;
648 MOZ_RUNINIT static TimeStamp sLastCheckedForSmartCardChanges = TimeStamp::Now();
649 #endif
651 nsresult nsNSSComponent::CheckForSmartCardChanges() {
652 #ifndef MOZ_NO_SMART_CARDS
654 StaticMutexAutoLock lock(sCheckForSmartCardChangesMutex);
655 // Do this at most once every 3 seconds.
656 TimeStamp now = TimeStamp::Now();
657 if (now - sLastCheckedForSmartCardChanges <
658 TimeDuration::FromSeconds(3.0)) {
659 return NS_OK;
661 sLastCheckedForSmartCardChanges = now;
664 // SECMOD_UpdateSlotList attempts to acquire the list lock as well, so we
665 // have to do this in three steps.
666 Vector<UniqueSECMODModule> modulesWithRemovableSlots;
668 AutoSECMODListReadLock secmodLock;
669 SECMODModuleList* list = SECMOD_GetDefaultModuleList();
670 while (list) {
671 if (SECMOD_LockedModuleHasRemovableSlots(list->module)) {
672 UniqueSECMODModule module(SECMOD_ReferenceModule(list->module));
673 if (!modulesWithRemovableSlots.append(std::move(module))) {
674 return NS_ERROR_OUT_OF_MEMORY;
677 list = list->next;
680 for (auto& module : modulesWithRemovableSlots) {
681 // Best-effort.
682 Unused << SECMOD_UpdateSlotList(module.get());
684 AutoSECMODListReadLock secmodLock;
685 for (auto& module : modulesWithRemovableSlots) {
686 for (int i = 0; i < module->slotCount; i++) {
687 // We actually don't care about the return value here - we just need to
688 // call this to get NSS to update its view of this slot.
689 Unused << PK11_IsPresent(module->slots[i]);
692 #endif
694 return NS_OK;
697 // Returns by reference the path to the directory containing the file that has
698 // been loaded as MOZ_DLL_PREFIX nss3 MOZ_DLL_SUFFIX.
699 // |result| is encoded in UTF-8.
700 static nsresult GetNSS3Directory(nsCString& result) {
701 MOZ_ASSERT(NS_IsMainThread());
703 UniquePRString nss3Path(
704 PR_GetLibraryFilePathname(MOZ_DLL_PREFIX "nss3" MOZ_DLL_SUFFIX,
705 reinterpret_cast<PRFuncPtr>(NSS_Initialize)));
706 if (!nss3Path) {
707 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nss not loaded?"));
708 return NS_ERROR_FAILURE;
710 nsCOMPtr<nsIFile> nss3File;
711 nsresult rv = NS_NewNativeLocalFile(nsDependentCString(nss3Path.get()),
712 getter_AddRefs(nss3File));
713 if (NS_FAILED(rv)) {
714 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
715 ("couldn't initialize file with path '%s'", nss3Path.get()));
716 return rv;
718 nsCOMPtr<nsIFile> nss3Directory;
719 rv = nss3File->GetParent(getter_AddRefs(nss3Directory));
720 if (NS_FAILED(rv)) {
721 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get parent directory?"));
722 return rv;
724 return FileToCString(nss3Directory, result);
727 // The loadable roots library is probably in the same directory we loaded the
728 // NSS shared library from, but in some cases it may be elsewhere. This function
729 // enumerates and returns the possible locations as nsCStrings.
730 // |possibleLoadableRootsLocations| is encoded in UTF-8.
731 static nsresult ListPossibleLoadableRootsLocations(
732 Vector<nsCString>& possibleLoadableRootsLocations) {
733 MOZ_ASSERT(NS_IsMainThread());
734 if (!NS_IsMainThread()) {
735 return NS_ERROR_NOT_SAME_THREAD;
738 // First try in the directory where we've already loaded
739 // MOZ_DLL_PREFIX nss3 MOZ_DLL_SUFFIX, since that's likely to be correct.
740 nsAutoCString nss3Dir;
741 nsresult rv = GetNSS3Directory(nss3Dir);
742 if (NS_SUCCEEDED(rv)) {
743 if (!possibleLoadableRootsLocations.append(std::move(nss3Dir))) {
744 return NS_ERROR_OUT_OF_MEMORY;
746 } else {
747 // For some reason this fails on android. In any case, we should try with
748 // the other potential locations we have.
749 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
750 ("could not determine where nss was loaded from"));
752 nsAutoCString currentProcessDir;
753 rv = GetDirectoryPath(NS_XPCOM_CURRENT_PROCESS_DIR, currentProcessDir);
754 if (NS_SUCCEEDED(rv)) {
755 if (!possibleLoadableRootsLocations.append(std::move(currentProcessDir))) {
756 return NS_ERROR_OUT_OF_MEMORY;
758 } else {
759 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
760 ("could not get current process directory"));
762 nsAutoCString greDir;
763 rv = GetDirectoryPath(NS_GRE_DIR, greDir);
764 if (NS_SUCCEEDED(rv)) {
765 if (!possibleLoadableRootsLocations.append(std::move(greDir))) {
766 return NS_ERROR_OUT_OF_MEMORY;
768 } else {
769 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not get gre directory"));
771 // As a last resort, this will cause the library loading code to use the OS'
772 // default library search path.
773 nsAutoCString emptyString;
774 if (!possibleLoadableRootsLocations.append(std::move(emptyString))) {
775 return NS_ERROR_OUT_OF_MEMORY;
778 return NS_OK;
781 nsresult LoadLoadableCertsTask::LoadLoadableRoots() {
782 for (const auto& possibleLocation : mPossibleLoadableRootsLocations) {
783 if (mozilla::psm::LoadLoadableRoots(possibleLocation)) {
784 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
785 ("loaded CKBI from %s", possibleLocation.get()));
786 return NS_OK;
789 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not load loadable roots"));
790 return NS_ERROR_FAILURE;
793 // Table of pref names and SSL cipher ID
794 typedef struct {
795 const char* pref;
796 int32_t id;
797 bool (*prefGetter)();
798 } CipherPref;
800 // Update the switch statement in AccumulateCipherSuite in nsNSSCallbacks.cpp
801 // when you add/remove cipher suites here.
802 static const CipherPref sCipherPrefs[] = {
803 {"security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
804 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
805 StaticPrefs::security_ssl3_ecdhe_rsa_aes_128_gcm_sha256},
806 {"security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256",
807 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
808 StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_128_gcm_sha256},
809 {"security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256",
810 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
811 StaticPrefs::security_ssl3_ecdhe_ecdsa_chacha20_poly1305_sha256},
812 {"security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256",
813 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
814 StaticPrefs::security_ssl3_ecdhe_rsa_chacha20_poly1305_sha256},
815 {"security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384",
816 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
817 StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_256_gcm_sha384},
818 {"security.ssl3.ecdhe_rsa_aes_256_gcm_sha384",
819 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
820 StaticPrefs::security_ssl3_ecdhe_rsa_aes_256_gcm_sha384},
821 {"security.ssl3.ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
822 StaticPrefs::security_ssl3_ecdhe_rsa_aes_128_sha},
823 {"security.ssl3.ecdhe_ecdsa_aes_128_sha",
824 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
825 StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_128_sha},
826 {"security.ssl3.ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
827 StaticPrefs::security_ssl3_ecdhe_rsa_aes_256_sha},
828 {"security.ssl3.ecdhe_ecdsa_aes_256_sha",
829 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
830 StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_256_sha},
831 {"security.ssl3.dhe_rsa_aes_128_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
832 StaticPrefs::security_ssl3_dhe_rsa_aes_128_sha},
833 {"security.ssl3.dhe_rsa_aes_256_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
834 StaticPrefs::security_ssl3_dhe_rsa_aes_256_sha},
835 {"security.tls13.aes_128_gcm_sha256", TLS_AES_128_GCM_SHA256,
836 StaticPrefs::security_tls13_aes_128_gcm_sha256},
837 {"security.tls13.chacha20_poly1305_sha256", TLS_CHACHA20_POLY1305_SHA256,
838 StaticPrefs::security_tls13_chacha20_poly1305_sha256},
839 {"security.tls13.aes_256_gcm_sha384", TLS_AES_256_GCM_SHA384,
840 StaticPrefs::security_tls13_aes_256_gcm_sha384},
841 {"security.ssl3.rsa_aes_128_gcm_sha256", TLS_RSA_WITH_AES_128_GCM_SHA256,
842 StaticPrefs::security_ssl3_rsa_aes_128_gcm_sha256},
843 {"security.ssl3.rsa_aes_256_gcm_sha384", TLS_RSA_WITH_AES_256_GCM_SHA384,
844 StaticPrefs::security_ssl3_rsa_aes_256_gcm_sha384},
845 {"security.ssl3.rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA,
846 StaticPrefs::security_ssl3_rsa_aes_128_sha},
847 {"security.ssl3.rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA,
848 StaticPrefs::security_ssl3_rsa_aes_256_sha},
851 // These ciphersuites can only be enabled if deprecated versions of TLS are
852 // also enabled (via the preference "security.tls.version.enable-deprecated").
853 static const CipherPref sDeprecatedTLS1CipherPrefs[] = {
854 {"security.ssl3.deprecated.rsa_des_ede3_sha", TLS_RSA_WITH_3DES_EDE_CBC_SHA,
855 StaticPrefs::security_ssl3_deprecated_rsa_des_ede3_sha},
858 // This function will convert from pref values like 1, 2, ...
859 // to the internal values of SSL_LIBRARY_VERSION_TLS_1_0,
860 // SSL_LIBRARY_VERSION_TLS_1_1, ...
861 /*static*/
862 void nsNSSComponent::FillTLSVersionRange(SSLVersionRange& rangeOut,
863 uint32_t minFromPrefs,
864 uint32_t maxFromPrefs,
865 SSLVersionRange defaults) {
866 rangeOut = defaults;
867 // determine what versions are supported
868 SSLVersionRange supported;
869 if (SSL_VersionRangeGetSupported(ssl_variant_stream, &supported) !=
870 SECSuccess) {
871 return;
874 // Clip the defaults by what NSS actually supports to enable
875 // working with a system NSS with different ranges.
876 rangeOut.min = std::max(rangeOut.min, supported.min);
877 rangeOut.max = std::min(rangeOut.max, supported.max);
879 // convert min/maxFromPrefs to the internal representation
880 minFromPrefs += SSL_LIBRARY_VERSION_3_0;
881 maxFromPrefs += SSL_LIBRARY_VERSION_3_0;
882 // if min/maxFromPrefs are invalid, use defaults
883 if (minFromPrefs > maxFromPrefs || minFromPrefs < supported.min ||
884 maxFromPrefs > supported.max ||
885 minFromPrefs < SSL_LIBRARY_VERSION_TLS_1_0) {
886 return;
889 // fill out rangeOut
890 rangeOut.min = (uint16_t)minFromPrefs;
891 rangeOut.max = (uint16_t)maxFromPrefs;
894 static void ConfigureTLSSessionIdentifiers() {
895 bool disableSessionIdentifiers =
896 StaticPrefs::security_ssl_disable_session_identifiers();
897 SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, !disableSessionIdentifiers);
898 SSL_OptionSetDefault(SSL_NO_CACHE, disableSessionIdentifiers);
901 nsresult CommonInit() {
902 SSL_OptionSetDefault(SSL_ENABLE_SSL2, false);
903 SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, false);
905 nsresult rv = nsNSSComponent::SetEnabledTLSVersions();
906 if (NS_FAILED(rv)) {
907 return rv;
910 ConfigureTLSSessionIdentifiers();
912 SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION,
913 StaticPrefs::security_ssl_require_safe_negotiation());
914 SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_REQUIRES_XTN);
915 SSL_OptionSetDefault(SSL_ENABLE_EXTENDED_MASTER_SECRET, true);
916 SSL_OptionSetDefault(SSL_ENABLE_HELLO_DOWNGRADE_CHECK,
917 StaticPrefs::security_tls_hello_downgrade_check());
918 SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,
919 StaticPrefs::security_ssl_enable_false_start());
920 // SSL_ENABLE_ALPN also requires calling SSL_SetNextProtoNego in order for
921 // the extensions to be negotiated.
922 // WebRTC does not do that so it will not use ALPN even when this preference
923 // is true.
924 SSL_OptionSetDefault(SSL_ENABLE_ALPN,
925 StaticPrefs::security_ssl_enable_alpn());
926 SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,
927 StaticPrefs::security_tls_enable_0rtt_data());
928 SSL_OptionSetDefault(SSL_ENABLE_POST_HANDSHAKE_AUTH,
929 StaticPrefs::security_tls_enable_post_handshake_auth());
930 SSL_OptionSetDefault(
931 SSL_ENABLE_DELEGATED_CREDENTIALS,
932 StaticPrefs::security_tls_enable_delegated_credentials());
934 rv = InitializeCipherSuite();
935 if (NS_FAILED(rv)) {
936 MOZ_LOG(gPIPNSSLog, LogLevel::Error,
937 ("Unable to initialize cipher suite settings\n"));
938 return rv;
941 DisableMD5();
943 mozilla::pkix::RegisterErrorTable();
944 nsSSLIOLayerHelpers::GlobalInit();
946 return NS_OK;
949 void PrepareForShutdownInSocketProcess() {
950 MOZ_ASSERT(XRE_IsSocketProcess());
951 nsSSLIOLayerHelpers::GlobalCleanup();
954 bool HandleTLSPrefChange(const nsCString& prefName) {
955 // Note that the code in this function should be kept in sync with
956 // gCallbackSecurityPrefs in nsIOService.cpp.
957 bool prefFound = true;
958 if (prefName.EqualsLiteral("security.tls.version.min") ||
959 prefName.EqualsLiteral("security.tls.version.max") ||
960 prefName.EqualsLiteral("security.tls.version.enable-deprecated")) {
961 Unused << nsNSSComponent::SetEnabledTLSVersions();
962 } else if (prefName.EqualsLiteral("security.tls.hello_downgrade_check")) {
963 SSL_OptionSetDefault(SSL_ENABLE_HELLO_DOWNGRADE_CHECK,
964 StaticPrefs::security_tls_hello_downgrade_check());
965 } else if (prefName.EqualsLiteral("security.ssl.require_safe_negotiation")) {
966 SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION,
967 StaticPrefs::security_ssl_require_safe_negotiation());
968 } else if (prefName.EqualsLiteral("security.ssl.enable_false_start")) {
969 SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,
970 StaticPrefs::security_ssl_enable_false_start());
971 } else if (prefName.EqualsLiteral("security.ssl.enable_alpn")) {
972 SSL_OptionSetDefault(SSL_ENABLE_ALPN,
973 StaticPrefs::security_ssl_enable_alpn());
974 } else if (prefName.EqualsLiteral("security.tls.enable_0rtt_data")) {
975 SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,
976 StaticPrefs::security_tls_enable_0rtt_data());
977 } else if (prefName.EqualsLiteral(
978 "security.tls.enable_post_handshake_auth")) {
979 SSL_OptionSetDefault(
980 SSL_ENABLE_POST_HANDSHAKE_AUTH,
981 StaticPrefs::security_tls_enable_post_handshake_auth());
982 } else if (prefName.EqualsLiteral(
983 "security.tls.enable_delegated_credentials")) {
984 SSL_OptionSetDefault(
985 SSL_ENABLE_DELEGATED_CREDENTIALS,
986 StaticPrefs::security_tls_enable_delegated_credentials());
987 } else if (prefName.EqualsLiteral(
988 "security.ssl.disable_session_identifiers")) {
989 ConfigureTLSSessionIdentifiers();
990 } else {
991 prefFound = false;
993 return prefFound;
996 namespace {
998 class CipherSuiteChangeObserver : public nsIObserver {
999 public:
1000 NS_DECL_ISUPPORTS
1001 NS_DECL_NSIOBSERVER
1003 static nsresult StartObserve();
1005 protected:
1006 virtual ~CipherSuiteChangeObserver() = default;
1008 private:
1009 static StaticRefPtr<CipherSuiteChangeObserver> sObserver;
1010 CipherSuiteChangeObserver() = default;
1013 NS_IMPL_ISUPPORTS(CipherSuiteChangeObserver, nsIObserver)
1015 // static
1016 StaticRefPtr<CipherSuiteChangeObserver> CipherSuiteChangeObserver::sObserver;
1018 // static
1019 nsresult CipherSuiteChangeObserver::StartObserve() {
1020 MOZ_ASSERT(NS_IsMainThread(),
1021 "CipherSuiteChangeObserver::StartObserve() can only be accessed "
1022 "on the main thread");
1023 if (!sObserver) {
1024 RefPtr<CipherSuiteChangeObserver> observer =
1025 new CipherSuiteChangeObserver();
1026 nsresult rv = Preferences::AddStrongObserver(observer.get(), "security.");
1027 if (NS_FAILED(rv)) {
1028 sObserver = nullptr;
1029 return rv;
1032 nsCOMPtr<nsIObserverService> observerService =
1033 mozilla::services::GetObserverService();
1034 observerService->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
1035 false);
1037 sObserver = observer;
1039 return NS_OK;
1042 // Enables or disabled ciphersuites from deprecated versions of TLS as
1043 // appropriate. If security.tls.version.enable-deprecated is true, these
1044 // ciphersuites may be enabled, if the corresponding preference is true.
1045 // Otherwise, these ciphersuites will be disabled.
1046 void SetDeprecatedTLS1CipherPrefs() {
1047 if (StaticPrefs::security_tls_version_enable_deprecated()) {
1048 for (const auto& deprecatedTLS1CipherPref : sDeprecatedTLS1CipherPrefs) {
1049 SSL_CipherPrefSetDefault(deprecatedTLS1CipherPref.id,
1050 deprecatedTLS1CipherPref.prefGetter());
1052 } else {
1053 for (const auto& deprecatedTLS1CipherPref : sDeprecatedTLS1CipherPrefs) {
1054 SSL_CipherPrefSetDefault(deprecatedTLS1CipherPref.id, false);
1059 // static
1060 void SetKyberPolicy() {
1061 if (StaticPrefs::security_tls_enable_kyber()) {
1062 NSS_SetAlgorithmPolicy(SEC_OID_MLKEM768X25519, NSS_USE_ALG_IN_SSL_KX, 0);
1063 } else {
1064 NSS_SetAlgorithmPolicy(SEC_OID_MLKEM768X25519, 0, NSS_USE_ALG_IN_SSL_KX);
1068 nsresult CipherSuiteChangeObserver::Observe(nsISupports* /*aSubject*/,
1069 const char* aTopic,
1070 const char16_t* someData) {
1071 MOZ_ASSERT(NS_IsMainThread(),
1072 "CipherSuiteChangeObserver::Observe can only be accessed on main "
1073 "thread");
1074 if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
1075 NS_ConvertUTF16toUTF8 prefName(someData);
1076 // Look through the cipher table and set according to pref setting
1077 for (const auto& cipherPref : sCipherPrefs) {
1078 if (prefName.Equals(cipherPref.pref)) {
1079 SSL_CipherPrefSetDefault(cipherPref.id, cipherPref.prefGetter());
1080 break;
1083 SetDeprecatedTLS1CipherPrefs();
1084 SetKyberPolicy();
1085 nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
1086 } else if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
1087 Preferences::RemoveObserver(this, "security.");
1088 MOZ_ASSERT(sObserver.get() == this);
1089 sObserver = nullptr;
1090 nsCOMPtr<nsIObserverService> observerService =
1091 mozilla::services::GetObserverService();
1092 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
1094 return NS_OK;
1097 } // namespace
1099 void nsNSSComponent::setValidationOptions(
1100 bool isInitialSetting, const mozilla::MutexAutoLock& proofOfLock) {
1101 // We access prefs so this must be done on the main thread.
1102 mMutex.AssertCurrentThreadOwns();
1103 MOZ_ASSERT(NS_IsMainThread());
1104 if (NS_WARN_IF(!NS_IsMainThread())) {
1105 return;
1108 CertVerifier::CertificateTransparencyMode ctMode =
1109 GetCertificateTransparencyMode();
1110 nsCString skipCTForHosts;
1111 Preferences::GetCString(
1112 "security.pki.certificate_transparency.disable_for_hosts",
1113 skipCTForHosts);
1114 nsAutoCString skipCTForSPKIHashesBase64;
1115 Preferences::GetCString(
1116 "security.pki.certificate_transparency.disable_for_spki_hashes",
1117 skipCTForSPKIHashesBase64);
1118 nsTArray<CopyableTArray<uint8_t>> skipCTForSPKIHashes;
1119 for (const auto& spkiHashBase64 : skipCTForSPKIHashesBase64.Split(',')) {
1120 nsAutoCString spkiHashString;
1121 if (NS_SUCCEEDED(Base64Decode(spkiHashBase64, spkiHashString))) {
1122 nsTArray<uint8_t> spkiHash(spkiHashString.Data(),
1123 spkiHashString.Length());
1124 skipCTForSPKIHashes.AppendElement(std::move(spkiHash));
1127 CertVerifier::CertificateTransparencyConfig ctConfig(
1128 ctMode, std::move(skipCTForHosts), std::move(skipCTForSPKIHashes));
1130 // This preference controls whether we do OCSP fetching and does not affect
1131 // OCSP stapling.
1132 // 0 = disabled, 1 = enabled, 2 = only enabled for EV
1133 uint32_t ocspEnabled = StaticPrefs::security_OCSP_enabled();
1135 bool ocspRequired = ocspEnabled > 0 && StaticPrefs::security_OCSP_require();
1137 // We measure the setting of the pref at startup only to minimize noise by
1138 // addons that may muck with the settings, though it probably doesn't matter.
1139 if (isInitialSetting) {
1140 Telemetry::Accumulate(Telemetry::CERT_OCSP_ENABLED, ocspEnabled);
1141 Telemetry::Accumulate(Telemetry::CERT_OCSP_REQUIRED, ocspRequired);
1144 NetscapeStepUpPolicy netscapeStepUpPolicy = static_cast<NetscapeStepUpPolicy>(
1145 StaticPrefs::security_pki_netscape_step_up_policy());
1146 switch (netscapeStepUpPolicy) {
1147 case NetscapeStepUpPolicy::AlwaysMatch:
1148 case NetscapeStepUpPolicy::MatchBefore23August2016:
1149 case NetscapeStepUpPolicy::MatchBefore23August2015:
1150 case NetscapeStepUpPolicy::NeverMatch:
1151 break;
1152 default:
1153 netscapeStepUpPolicy = NetscapeStepUpPolicy::AlwaysMatch;
1154 break;
1157 CRLiteMode defaultCRLiteMode = CRLiteMode::Disabled;
1158 CRLiteMode crliteMode =
1159 static_cast<CRLiteMode>(StaticPrefs::security_pki_crlite_mode());
1160 switch (crliteMode) {
1161 case CRLiteMode::Disabled:
1162 case CRLiteMode::TelemetryOnly:
1163 case CRLiteMode::Enforce:
1164 case CRLiteMode::ConfirmRevocations:
1165 break;
1166 default:
1167 crliteMode = defaultCRLiteMode;
1168 break;
1171 CertVerifier::OcspDownloadConfig odc;
1172 CertVerifier::OcspStrictConfig osc;
1173 uint32_t certShortLifetimeInDays;
1174 TimeDuration softTimeout;
1175 TimeDuration hardTimeout;
1177 GetRevocationBehaviorFromPrefs(&odc, &osc, &certShortLifetimeInDays,
1178 softTimeout, hardTimeout);
1180 mDefaultCertVerifier = new SharedCertVerifier(
1181 odc, osc, softTimeout, hardTimeout, certShortLifetimeInDays,
1182 netscapeStepUpPolicy, std::move(ctConfig), crliteMode, mEnterpriseCerts);
1185 void nsNSSComponent::UpdateCertVerifierWithEnterpriseRoots() {
1186 MutexAutoLock lock(mMutex);
1187 if (!mDefaultCertVerifier) {
1188 return;
1191 RefPtr<SharedCertVerifier> oldCertVerifier = mDefaultCertVerifier;
1192 nsCString skipCTForHosts(oldCertVerifier->mCTConfig.mSkipForHosts);
1193 CertVerifier::CertificateTransparencyConfig ctConfig(
1194 oldCertVerifier->mCTConfig.mMode, std::move(skipCTForHosts),
1195 oldCertVerifier->mCTConfig.mSkipForSPKIHashes.Clone());
1196 mDefaultCertVerifier = new SharedCertVerifier(
1197 oldCertVerifier->mOCSPDownloadConfig,
1198 oldCertVerifier->mOCSPStrict ? CertVerifier::ocspStrict
1199 : CertVerifier::ocspRelaxed,
1200 oldCertVerifier->mOCSPTimeoutSoft, oldCertVerifier->mOCSPTimeoutHard,
1201 oldCertVerifier->mCertShortLifetimeInDays,
1202 oldCertVerifier->mNetscapeStepUpPolicy, std::move(ctConfig),
1203 oldCertVerifier->mCRLiteMode, mEnterpriseCerts);
1206 // Enable the TLS versions given in the prefs, defaulting to TLS 1.0 (min) and
1207 // TLS 1.2 (max) when the prefs aren't set or set to invalid values.
1208 nsresult nsNSSComponent::SetEnabledTLSVersions() {
1209 // Keep these values in sync with all.js.
1210 // 1 means TLS 1.0, 2 means TLS 1.1, etc.
1211 static const uint32_t PSM_DEFAULT_MIN_TLS_VERSION = 3;
1212 static const uint32_t PSM_DEFAULT_MAX_TLS_VERSION = 4;
1213 static const uint32_t PSM_DEPRECATED_TLS_VERSION = 1;
1215 uint32_t minFromPrefs = StaticPrefs::security_tls_version_min();
1216 uint32_t maxFromPrefs = StaticPrefs::security_tls_version_max();
1218 // This override should be removed some time after
1219 // PSM_DEFAULT_MIN_TLS_VERSION is increased to 3.
1220 bool enableDeprecated = StaticPrefs::security_tls_version_enable_deprecated();
1221 if (enableDeprecated) {
1222 minFromPrefs = std::min(minFromPrefs, PSM_DEPRECATED_TLS_VERSION);
1225 SSLVersionRange defaults = {
1226 SSL_LIBRARY_VERSION_3_0 + PSM_DEFAULT_MIN_TLS_VERSION,
1227 SSL_LIBRARY_VERSION_3_0 + PSM_DEFAULT_MAX_TLS_VERSION};
1228 SSLVersionRange filledInRange;
1229 FillTLSVersionRange(filledInRange, minFromPrefs, maxFromPrefs, defaults);
1231 SECStatus srv =
1232 SSL_VersionRangeSetDefault(ssl_variant_stream, &filledInRange);
1233 if (srv != SECSuccess) {
1234 return NS_ERROR_FAILURE;
1237 return NS_OK;
1240 #if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
1241 // If the profile directory is on a networked drive, we want to set the
1242 // environment variable NSS_SDB_USE_CACHE to yes (as long as it hasn't been set
1243 // before).
1244 static void SetNSSDatabaseCacheModeAsAppropriate() {
1245 MOZ_ASSERT(NS_IsMainThread());
1247 nsCOMPtr<nsIFile> profileFile;
1248 nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
1249 getter_AddRefs(profileFile));
1250 if (NS_FAILED(rv)) {
1251 // We're probably running without a profile directory, so this is
1252 // irrelevant.
1253 return;
1256 static const char sNSS_SDB_USE_CACHE[] = "NSS_SDB_USE_CACHE";
1257 static const char sNSS_SDB_USE_CACHE_WITH_VALUE[] = "NSS_SDB_USE_CACHE=yes";
1258 auto profilePath = profileFile->NativePath();
1260 # if defined(XP_LINUX) && !defined(ANDROID)
1261 struct statfs statfs_s;
1262 if (statfs(profilePath.get(), &statfs_s) == 0 &&
1263 statfs_s.f_type == NFS_SUPER_MAGIC && !PR_GetEnv(sNSS_SDB_USE_CACHE)) {
1264 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1265 ("profile is remote (and NSS_SDB_USE_CACHE wasn't set): "
1266 "setting NSS_SDB_USE_CACHE"));
1267 PR_SetEnv(sNSS_SDB_USE_CACHE_WITH_VALUE);
1268 } else {
1269 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("not setting NSS_SDB_USE_CACHE"));
1271 # endif // defined(XP_LINUX) && !defined(ANDROID)
1273 # ifdef XP_WIN
1274 wchar_t volPath[MAX_PATH];
1275 if (::GetVolumePathNameW(profilePath.get(), volPath, MAX_PATH) &&
1276 ::GetDriveTypeW(volPath) == DRIVE_REMOTE &&
1277 !PR_GetEnv(sNSS_SDB_USE_CACHE)) {
1278 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1279 ("profile is remote (and NSS_SDB_USE_CACHE wasn't set): "
1280 "setting NSS_SDB_USE_CACHE"));
1281 PR_SetEnv(sNSS_SDB_USE_CACHE_WITH_VALUE);
1282 } else {
1283 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("not setting NSS_SDB_USE_CACHE"));
1285 # endif // XP_WIN
1287 #endif // defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
1289 static nsresult GetNSSProfilePath(nsAutoCString& aProfilePath) {
1290 aProfilePath.Truncate();
1291 nsCOMPtr<nsIFile> profileFile;
1292 nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
1293 getter_AddRefs(profileFile));
1294 if (NS_FAILED(rv)) {
1295 NS_WARNING(
1296 "NSS will be initialized without a profile directory. "
1297 "Some things may not work as expected.");
1298 return NS_OK;
1301 #if defined(XP_WIN)
1302 // SQLite always takes UTF-8 file paths regardless of the current system
1303 // code page.
1304 nsAutoString u16ProfilePath;
1305 rv = profileFile->GetPath(u16ProfilePath);
1306 CopyUTF16toUTF8(u16ProfilePath, aProfilePath);
1307 #else
1308 rv = profileFile->GetNativePath(aProfilePath);
1309 #endif
1310 if (NS_FAILED(rv)) {
1311 MOZ_LOG(gPIPNSSLog, LogLevel::Error,
1312 ("Could not get native path for profile directory.\n"));
1313 return rv;
1316 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1317 ("NSS profile at '%s'\n", aProfilePath.get()));
1318 return NS_OK;
1321 #ifndef ANDROID
1322 // Given a profile path, attempt to rename the PKCS#11 module DB to
1323 // "pkcs11.txt.fips". In the case of a catastrophic failure (e.g. out of
1324 // memory), returns a failing nsresult. If execution could conceivably proceed,
1325 // returns NS_OK even if renaming the file didn't work. This simplifies the
1326 // logic of the calling code.
1327 // |profilePath| is encoded in UTF-8.
1328 static nsresult AttemptToRenamePKCS11ModuleDB(const nsACString& profilePath) {
1329 nsCOMPtr<nsIFile> profileDir;
1330 // |profilePath| is encoded in UTF-8 because SQLite always takes UTF-8 file
1331 // paths regardless of the current system code page.
1332 MOZ_TRY(NS_NewUTF8LocalFile(profilePath, getter_AddRefs(profileDir)));
1333 const char* moduleDBFilename = "pkcs11.txt";
1334 nsAutoCString destModuleDBFilename(moduleDBFilename);
1335 destModuleDBFilename.Append(".fips");
1336 nsCOMPtr<nsIFile> dbFile;
1337 nsresult rv = profileDir->Clone(getter_AddRefs(dbFile));
1338 if (NS_FAILED(rv) || !dbFile) {
1339 return NS_ERROR_FAILURE;
1341 rv = dbFile->AppendNative(nsAutoCString(moduleDBFilename));
1342 if (NS_FAILED(rv)) {
1343 return rv;
1345 // If the PKCS#11 module DB doesn't exist, renaming it won't help.
1346 bool exists;
1347 rv = dbFile->Exists(&exists);
1348 if (NS_FAILED(rv)) {
1349 return rv;
1351 // This is strange, but not a catastrophic failure.
1352 if (!exists) {
1353 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1354 ("%s doesn't exist?", moduleDBFilename));
1355 return NS_OK;
1357 nsCOMPtr<nsIFile> destDBFile;
1358 rv = profileDir->Clone(getter_AddRefs(destDBFile));
1359 if (NS_FAILED(rv) || !destDBFile) {
1360 return NS_ERROR_FAILURE;
1362 rv = destDBFile->AppendNative(destModuleDBFilename);
1363 if (NS_FAILED(rv)) {
1364 return rv;
1366 // If the destination exists, presumably we've already tried this. Doing it
1367 // again won't help.
1368 rv = destDBFile->Exists(&exists);
1369 if (NS_FAILED(rv)) {
1370 return rv;
1372 // Unfortunate, but not a catastrophic failure.
1373 if (exists) {
1374 MOZ_LOG(
1375 gPIPNSSLog, LogLevel::Debug,
1376 ("%s already exists - not overwriting", destModuleDBFilename.get()));
1377 return NS_OK;
1379 // Now do the actual move.
1380 // This may fail on, e.g., a read-only file system. This would be unfortunate,
1381 // but again it isn't catastropic and we would want to fall back to
1382 // initializing NSS in no-DB mode.
1383 Unused << dbFile->MoveToNative(profileDir, destModuleDBFilename);
1384 return NS_OK;
1386 #endif // ifndef ANDROID
1388 // Given a profile directory, attempt to initialize NSS. If nocertdb is true,
1389 // (or if we don't have a profile directory) simply initialize NSS in no DB mode
1390 // and return. Otherwise, first attempt to initialize in read/write mode, and
1391 // then read-only mode if that fails. If both attempts fail, we may be failing
1392 // to initialize an NSS DB collection that has FIPS mode enabled. Attempt to
1393 // ascertain if this is the case, and if so, rename the offending PKCS#11 module
1394 // DB so we can (hopefully) initialize NSS in read-write mode. Again attempt
1395 // read-only mode if that fails. Finally, fall back to no DB mode. On Android
1396 // we can skip the FIPS workaround since it was never possible to enable FIPS
1397 // there anyway.
1398 // |profilePath| is encoded in UTF-8.
1399 static nsresult InitializeNSSWithFallbacks(const nsACString& profilePath,
1400 bool nocertdb, bool safeMode) {
1401 if (nocertdb || profilePath.IsEmpty()) {
1402 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1403 ("nocertdb mode or empty profile path -> NSS_NoDB_Init"));
1404 SECStatus srv = NSS_NoDB_Init(nullptr);
1405 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1406 if (srv != SECSuccess) {
1407 MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %d",
1408 PR_GetError());
1410 #endif
1411 return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
1414 // Try read/write mode. If we're in safeMode, we won't load PKCS#11 modules.
1415 #ifndef ANDROID
1416 PRErrorCode savedPRErrorCode1;
1417 #endif // ifndef ANDROID
1418 PKCS11DBConfig safeModeDBConfig =
1419 safeMode ? PKCS11DBConfig::DoNotLoadModules : PKCS11DBConfig::LoadModules;
1420 SECStatus srv = ::mozilla::psm::InitializeNSS(
1421 profilePath, NSSDBConfig::ReadWrite, safeModeDBConfig);
1422 if (srv == SECSuccess) {
1423 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r/w mode"));
1424 return NS_OK;
1426 #ifndef ANDROID
1427 savedPRErrorCode1 = PR_GetError();
1428 PRErrorCode savedPRErrorCode2;
1429 #endif // ifndef ANDROID
1430 // That failed. Try read-only mode.
1431 srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadOnly,
1432 safeModeDBConfig);
1433 if (srv == SECSuccess) {
1434 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r-o mode"));
1435 return NS_OK;
1437 #ifndef ANDROID
1438 savedPRErrorCode2 = PR_GetError();
1440 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1441 ("failed to initialize NSS with codes %d %d", savedPRErrorCode1,
1442 savedPRErrorCode2));
1443 #endif // ifndef ANDROID
1445 #ifndef ANDROID
1446 // That failed as well. Maybe we're trying to load a PKCS#11 module DB that is
1447 // in FIPS mode, but we don't support FIPS? Test load NSS without PKCS#11
1448 // modules. If that succeeds, that's probably what's going on.
1449 if (!safeMode && (savedPRErrorCode1 == SEC_ERROR_LEGACY_DATABASE ||
1450 savedPRErrorCode2 == SEC_ERROR_LEGACY_DATABASE ||
1451 savedPRErrorCode1 == SEC_ERROR_PKCS11_DEVICE_ERROR ||
1452 savedPRErrorCode2 == SEC_ERROR_PKCS11_DEVICE_ERROR)) {
1453 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("attempting no-module db init"));
1454 // It would make sense to initialize NSS in read-only mode here since this
1455 // is just a test to see if the PKCS#11 module DB being in FIPS mode is the
1456 // problem, but for some reason the combination of read-only and no-moddb
1457 // flags causes NSS initialization to fail, so unfortunately we have to use
1458 // read-write mode.
1459 srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadWrite,
1460 PKCS11DBConfig::DoNotLoadModules);
1461 if (srv == SECSuccess) {
1462 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("FIPS may be the problem"));
1463 // Unload NSS so we can attempt to fix this situation for the user.
1464 srv = NSS_Shutdown();
1465 if (srv != SECSuccess) {
1466 # ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1467 MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %d",
1468 PR_GetError());
1469 # endif
1470 return NS_ERROR_FAILURE;
1472 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trying to rename module db"));
1473 // If this fails non-catastrophically, we'll attempt to initialize NSS
1474 // again in r/w then r-o mode (both of which will fail), and then we'll
1475 // fall back to NSS_NoDB_Init, which is the behavior we want.
1476 nsresult rv = AttemptToRenamePKCS11ModuleDB(profilePath);
1477 if (NS_FAILED(rv)) {
1478 # ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1479 // An nsresult is a uint32_t, but at least one of our compilers doesn't
1480 // like this format string unless we include the cast. <shruggie emoji>
1481 MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %u",
1482 (uint32_t)rv);
1483 # endif
1484 return rv;
1486 srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadWrite,
1487 PKCS11DBConfig::LoadModules);
1488 if (srv == SECSuccess) {
1489 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r/w mode"));
1490 return NS_OK;
1492 srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadOnly,
1493 PKCS11DBConfig::LoadModules);
1494 if (srv == SECSuccess) {
1495 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r-o mode"));
1496 return NS_OK;
1500 #endif
1502 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("last-resort NSS_NoDB_Init"));
1503 srv = NSS_NoDB_Init(nullptr);
1504 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1505 if (srv != SECSuccess) {
1506 MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %d",
1507 PR_GetError());
1509 #endif
1510 return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
1513 #if defined(NIGHTLY_BUILD) && !defined(ANDROID)
1514 // dbType is either "cert9.db" or "key4.db"
1515 void UnmigrateOneCertDB(const nsCOMPtr<nsIFile>& profileDirectory,
1516 const nsACString& dbType) {
1517 nsCOMPtr<nsIFile> dbFile;
1518 nsresult rv = profileDirectory->Clone(getter_AddRefs(dbFile));
1519 if (NS_FAILED(rv)) {
1520 return;
1522 rv = dbFile->AppendNative(dbType);
1523 if (NS_FAILED(rv)) {
1524 return;
1526 bool exists;
1527 rv = dbFile->Exists(&exists);
1528 if (NS_FAILED(rv)) {
1529 return;
1531 // If the unprefixed DB already exists, don't overwrite it.
1532 if (exists) {
1533 return;
1535 nsCOMPtr<nsIFile> prefixedDBFile;
1536 rv = profileDirectory->Clone(getter_AddRefs(prefixedDBFile));
1537 if (NS_FAILED(rv)) {
1538 return;
1540 nsAutoCString prefixedDBName("gecko-no-share-");
1541 prefixedDBName.Append(dbType);
1542 rv = prefixedDBFile->AppendNative(prefixedDBName);
1543 if (NS_FAILED(rv)) {
1544 return;
1546 Unused << prefixedDBFile->MoveToNative(nullptr, dbType);
1549 void UnmigrateFromPrefixedCertDBs() {
1550 nsCOMPtr<nsIFile> profileDirectory;
1551 nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
1552 getter_AddRefs(profileDirectory));
1553 if (NS_FAILED(rv)) {
1554 return;
1556 UnmigrateOneCertDB(profileDirectory, "cert9.db"_ns);
1557 UnmigrateOneCertDB(profileDirectory, "key4.db"_ns);
1559 #endif // defined(NIGHTLY_BUILD) && !defined(ANDROID)
1561 nsresult nsNSSComponent::InitializeNSS() {
1562 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::InitializeNSS\n"));
1563 AUTO_PROFILER_LABEL("nsNSSComponent::InitializeNSS", OTHER);
1564 AUTO_PROFILER_TRACING_MARKER("NSS", "nsNSSComponent::InitializeNSS", OTHER);
1566 static_assert(
1567 nsINSSErrorsService::NSS_SEC_ERROR_BASE == SEC_ERROR_BASE &&
1568 nsINSSErrorsService::NSS_SEC_ERROR_LIMIT == SEC_ERROR_LIMIT &&
1569 nsINSSErrorsService::NSS_SSL_ERROR_BASE == SSL_ERROR_BASE &&
1570 nsINSSErrorsService::NSS_SSL_ERROR_LIMIT == SSL_ERROR_LIMIT,
1571 "You must update the values in nsINSSErrorsService.idl");
1573 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization beginning\n"));
1575 nsAutoCString profileStr;
1576 nsresult rv = GetNSSProfilePath(profileStr);
1577 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
1578 if (NS_FAILED(rv)) {
1579 return NS_ERROR_NOT_AVAILABLE;
1582 #if defined(NIGHTLY_BUILD) && !defined(ANDROID)
1583 if (!profileStr.IsEmpty()) {
1584 UnmigrateFromPrefixedCertDBs();
1586 #endif
1588 #if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
1589 SetNSSDatabaseCacheModeAsAppropriate();
1590 #endif
1592 bool nocertdb = StaticPrefs::security_nocertdb_AtStartup();
1593 bool inSafeMode = true;
1594 nsCOMPtr<nsIXULRuntime> runtime(do_GetService("@mozilla.org/xre/runtime;1"));
1595 // There might not be an nsIXULRuntime in embedded situations. This will
1596 // default to assuming we are in safe mode (as a result, no external PKCS11
1597 // modules will be loaded).
1598 if (runtime) {
1599 rv = runtime->GetInSafeMode(&inSafeMode);
1600 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
1601 if (NS_FAILED(rv)) {
1602 return rv;
1605 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("inSafeMode: %u\n", inSafeMode));
1607 rv = InitializeNSSWithFallbacks(profileStr, nocertdb, inSafeMode);
1608 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
1609 if (NS_FAILED(rv)) {
1610 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to initialize NSS"));
1611 return rv;
1614 PK11_SetPasswordFunc(PK11PasswordPrompt);
1616 // Register an observer so we can inform NSS when these prefs change
1617 Preferences::AddStrongObserver(this, "security.");
1619 rv = CommonInit();
1621 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
1622 if (NS_FAILED(rv)) {
1623 return NS_ERROR_UNEXPECTED;
1626 nsCOMPtr<nsICertOverrideService> certOverrideService(
1627 do_GetService(NS_CERTOVERRIDE_CONTRACTID));
1628 nsCOMPtr<nsIClientAuthRememberService> clientAuthRememberService(
1629 do_GetService(NS_CLIENTAUTHREMEMBERSERVICE_CONTRACTID));
1630 nsCOMPtr<nsISiteSecurityService> siteSecurityService(
1631 do_GetService(NS_SSSERVICE_CONTRACTID));
1632 nsCOMPtr<nsICertStorage> certStorage(do_GetService(NS_CERT_STORAGE_CID));
1634 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
1637 MutexAutoLock lock(mMutex);
1639 // ensure we have initial values for various root hashes
1640 #ifdef DEBUG
1641 mTestBuiltInRootHash.Truncate();
1642 Preferences::GetCString("security.test.built_in_root_hash",
1643 mTestBuiltInRootHash);
1644 #endif
1645 mMitmCanaryIssuer.Truncate();
1646 Preferences::GetString("security.pki.mitm_canary_issuer",
1647 mMitmCanaryIssuer);
1648 mMitmDetecionEnabled =
1649 Preferences::GetBool("security.pki.mitm_canary_issuer.enabled", true);
1651 // Set dynamic options from prefs.
1652 setValidationOptions(true, lock);
1654 bool importEnterpriseRoots =
1655 StaticPrefs::security_enterprise_roots_enabled();
1656 Vector<nsCString> possibleLoadableRootsLocations;
1657 rv = ListPossibleLoadableRootsLocations(possibleLoadableRootsLocations);
1658 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
1659 if (NS_FAILED(rv)) {
1660 return rv;
1663 bool loadOSClientCertsModule =
1664 StaticPrefs::security_osclientcerts_autoload();
1665 Maybe<nsCString> maybeOSClientCertsModuleLocation;
1666 if (loadOSClientCertsModule) {
1667 nsAutoCString libraryDir;
1668 if (NS_SUCCEEDED(GetDirectoryPath(NS_GRE_BIN_DIR, libraryDir))) {
1669 maybeOSClientCertsModuleLocation.emplace(libraryDir);
1672 RefPtr<LoadLoadableCertsTask> loadLoadableCertsTask(
1673 new LoadLoadableCertsTask(this, importEnterpriseRoots,
1674 std::move(possibleLoadableRootsLocations),
1675 std::move(maybeOSClientCertsModuleLocation)));
1676 rv = loadLoadableCertsTask->Dispatch();
1677 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
1678 if (NS_FAILED(rv)) {
1679 return rv;
1682 return NS_OK;
1686 void nsNSSComponent::PrepareForShutdown() {
1687 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::PrepareForShutdown"));
1688 MOZ_RELEASE_ASSERT(NS_IsMainThread());
1690 PK11_SetPasswordFunc((PK11PasswordFunc) nullptr);
1692 Preferences::RemoveObserver(this, "security.");
1694 // Release the default CertVerifier. This will cause any held NSS resources
1695 // to be released.
1696 MutexAutoLock lock(mMutex);
1697 mDefaultCertVerifier = nullptr;
1698 // We don't actually shut down NSS - XPCOM does, after all threads have been
1699 // joined and the component manager has been shut down (and so there shouldn't
1700 // be any XPCOM objects holding NSS resources).
1703 nsresult nsNSSComponent::Init() {
1704 MOZ_RELEASE_ASSERT(NS_IsMainThread());
1705 if (!NS_IsMainThread()) {
1706 return NS_ERROR_NOT_SAME_THREAD;
1709 MOZ_ASSERT(XRE_IsParentProcess());
1710 if (!XRE_IsParentProcess()) {
1711 return NS_ERROR_NOT_AVAILABLE;
1714 AutoGleanTimer<&glean::networking::nss_initialization> timer;
1716 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Beginning NSS initialization\n"));
1718 nsresult rv = InitializeNSS();
1719 if (NS_FAILED(rv)) {
1720 MOZ_LOG(gPIPNSSLog, LogLevel::Error,
1721 ("nsNSSComponent::InitializeNSS() failed\n"));
1722 return rv;
1725 rv = RegisterObservers();
1726 if (NS_FAILED(rv)) {
1727 return rv;
1730 return NS_OK;
1733 // nsISupports Implementation for the class
1734 NS_IMPL_ISUPPORTS(nsNSSComponent, nsINSSComponent, nsIObserver)
1736 static const char* const PROFILE_BEFORE_CHANGE_TOPIC = "profile-before-change";
1738 NS_IMETHODIMP
1739 nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
1740 const char16_t* someData) {
1741 // In some tests, we don't receive a "profile-before-change" topic. However,
1742 // we still have to shut down before the storage service shuts down, because
1743 // closing the sql-backed softoken requires sqlite still be available. Thus,
1744 // we observe "xpcom-shutdown" just in case.
1745 if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0 ||
1746 nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
1747 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1748 ("receiving profile change or XPCOM shutdown notification"));
1749 PrepareForShutdown();
1750 } else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
1751 bool clearSessionCache = true;
1752 NS_ConvertUTF16toUTF8 prefName(someData);
1754 if (HandleTLSPrefChange(prefName)) {
1755 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("HandleTLSPrefChange done"));
1756 } else if (
1757 prefName.EqualsLiteral("security.OCSP.enabled") ||
1758 prefName.EqualsLiteral("security.OCSP.require") ||
1759 prefName.EqualsLiteral("security.pki.cert_short_lifetime_in_days") ||
1760 prefName.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
1761 prefName.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
1762 prefName.EqualsLiteral("security.pki.certificate_transparency.mode") ||
1763 prefName.EqualsLiteral(
1764 "security.pki.certificate_transparency.disable_for_hosts") ||
1765 prefName.EqualsLiteral(
1766 "security.pki.certificate_transparency.disable_for_spki_hashes") ||
1767 prefName.EqualsLiteral("security.pki.netscape_step_up_policy") ||
1768 prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.soft") ||
1769 prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.hard") ||
1770 prefName.EqualsLiteral("security.pki.crlite_mode")) {
1771 MutexAutoLock lock(mMutex);
1772 setValidationOptions(false, lock);
1773 #ifdef DEBUG
1774 } else if (prefName.EqualsLiteral("security.test.built_in_root_hash")) {
1775 MutexAutoLock lock(mMutex);
1776 mTestBuiltInRootHash.Truncate();
1777 Preferences::GetCString("security.test.built_in_root_hash",
1778 mTestBuiltInRootHash);
1779 #endif // DEBUG
1780 } else if (prefName.Equals("security.enterprise_roots.enabled")) {
1781 UnloadEnterpriseRoots();
1782 MaybeImportEnterpriseRoots();
1783 } else if (prefName.Equals("security.osclientcerts.autoload")) {
1784 bool loadOSClientCertsModule =
1785 StaticPrefs::security_osclientcerts_autoload();
1786 AsyncLoadOrUnloadOSClientCertsModule(loadOSClientCertsModule);
1787 } else if (prefName.EqualsLiteral("security.pki.mitm_canary_issuer")) {
1788 MutexAutoLock lock(mMutex);
1789 mMitmCanaryIssuer.Truncate();
1790 Preferences::GetString("security.pki.mitm_canary_issuer",
1791 mMitmCanaryIssuer);
1792 } else if (prefName.EqualsLiteral(
1793 "security.pki.mitm_canary_issuer.enabled")) {
1794 MutexAutoLock lock(mMutex);
1795 mMitmDetecionEnabled =
1796 Preferences::GetBool("security.pki.mitm_canary_issuer.enabled", true);
1797 } else {
1798 clearSessionCache = false;
1800 if (clearSessionCache) {
1801 ClearSSLExternalAndInternalSessionCache();
1803 } else if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
1804 nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
1807 return NS_OK;
1810 /*static*/
1811 nsresult nsNSSComponent::GetNewPrompter(nsIPrompt** result) {
1812 NS_ENSURE_ARG_POINTER(result);
1813 *result = nullptr;
1815 if (!NS_IsMainThread()) {
1816 NS_ERROR("nsSDRContext::GetNewPrompter called off the main thread");
1817 return NS_ERROR_NOT_SAME_THREAD;
1820 nsresult rv;
1821 nsCOMPtr<nsIWindowWatcher> wwatch(
1822 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
1823 NS_ENSURE_SUCCESS(rv, rv);
1825 rv = wwatch->GetNewPrompter(0, result);
1826 NS_ENSURE_SUCCESS(rv, rv);
1828 return rv;
1831 nsresult nsNSSComponent::LogoutAuthenticatedPK11() {
1832 ClearSSLExternalAndInternalSessionCache();
1834 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1835 if (os) {
1836 os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr);
1839 return NS_OK;
1842 nsresult nsNSSComponent::RegisterObservers() {
1843 nsCOMPtr<nsIObserverService> observerService(
1844 do_GetService("@mozilla.org/observer-service;1"));
1845 if (!observerService) {
1846 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1847 ("nsNSSComponent: couldn't get observer service\n"));
1848 return NS_ERROR_FAILURE;
1851 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent: adding observers\n"));
1852 // Using false for the ownsweak parameter means the observer service will
1853 // keep a strong reference to this component. As a result, this will live at
1854 // least as long as the observer service.
1855 observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, false);
1856 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
1857 observerService->AddObserver(this, "last-pb-context-exited", false);
1859 return NS_OK;
1862 nsresult DoesCertMatchFingerprint(const nsTArray<uint8_t>& cert,
1863 const nsCString& fingerprint, bool& result) {
1864 result = false;
1866 if (cert.Length() > std::numeric_limits<uint32_t>::max()) {
1867 return NS_ERROR_INVALID_ARG;
1869 nsTArray<uint8_t> digestArray;
1870 nsresult rv = Digest::DigestBuf(SEC_OID_SHA256, cert.Elements(),
1871 cert.Length(), digestArray);
1872 if (NS_FAILED(rv)) {
1873 return rv;
1875 SECItem digestItem = {siBuffer, digestArray.Elements(),
1876 static_cast<unsigned int>(digestArray.Length())};
1877 UniquePORTString certFingerprint(
1878 CERT_Hexify(&digestItem, true /* use colon delimiters */));
1879 if (!certFingerprint) {
1880 return NS_ERROR_FAILURE;
1883 result = fingerprint.Equals(certFingerprint.get());
1884 return NS_OK;
1887 NS_IMETHODIMP
1888 nsNSSComponent::IsCertTestBuiltInRoot(const nsTArray<uint8_t>& cert,
1889 bool* result) {
1890 NS_ENSURE_ARG_POINTER(result);
1891 *result = false;
1893 #ifdef DEBUG
1894 MutexAutoLock lock(mMutex);
1895 nsresult rv = DoesCertMatchFingerprint(cert, mTestBuiltInRootHash, *result);
1896 if (NS_FAILED(rv)) {
1897 return rv;
1899 #endif // DEBUG
1901 return NS_OK;
1904 NS_IMETHODIMP
1905 nsNSSComponent::IssuerMatchesMitmCanary(const char* aCertIssuer) {
1906 MutexAutoLock lock(mMutex);
1907 if (mMitmDetecionEnabled && !mMitmCanaryIssuer.IsEmpty()) {
1908 nsString certIssuer = NS_ConvertUTF8toUTF16(aCertIssuer);
1909 if (mMitmCanaryIssuer.Equals(certIssuer)) {
1910 return NS_OK;
1914 return NS_ERROR_FAILURE;
1917 SharedCertVerifier::~SharedCertVerifier() = default;
1919 NS_IMETHODIMP
1920 nsNSSComponent::GetDefaultCertVerifier(SharedCertVerifier** result) {
1921 MutexAutoLock lock(mMutex);
1922 NS_ENSURE_ARG_POINTER(result);
1923 RefPtr<SharedCertVerifier> certVerifier(mDefaultCertVerifier);
1924 certVerifier.forget(result);
1925 return NS_OK;
1928 // static
1929 void nsNSSComponent::DoClearSSLExternalAndInternalSessionCache() {
1930 SSL_ClearSessionCache();
1931 mozilla::net::SSLTokensCache::Clear();
1934 NS_IMETHODIMP
1935 nsNSSComponent::ClearSSLExternalAndInternalSessionCache() {
1936 MOZ_ASSERT(XRE_IsParentProcess());
1937 if (!XRE_IsParentProcess()) {
1938 return NS_ERROR_NOT_AVAILABLE;
1941 if (mozilla::net::nsIOService::UseSocketProcess()) {
1942 if (mozilla::net::gIOService) {
1943 mozilla::net::gIOService->CallOrWaitForSocketProcess([]() {
1944 RefPtr<mozilla::net::SocketProcessParent> socketParent =
1945 mozilla::net::SocketProcessParent::GetSingleton();
1946 Unused << socketParent->SendClearSessionCache();
1950 DoClearSSLExternalAndInternalSessionCache();
1951 return NS_OK;
1954 NS_IMETHODIMP
1955 nsNSSComponent::AsyncClearSSLExternalAndInternalSessionCache(
1956 JSContext* aCx, ::mozilla::dom::Promise** aPromise) {
1957 MOZ_ASSERT(XRE_IsParentProcess());
1958 if (!XRE_IsParentProcess()) {
1959 return NS_ERROR_NOT_AVAILABLE;
1962 nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
1963 if (NS_WARN_IF(!globalObject)) {
1964 return NS_ERROR_FAILURE;
1967 ErrorResult result;
1968 RefPtr<mozilla::dom::Promise> promise =
1969 mozilla::dom::Promise::Create(globalObject, result);
1970 if (NS_WARN_IF(result.Failed())) {
1971 return result.StealNSResult();
1974 if (mozilla::net::nsIOService::UseSocketProcess() &&
1975 mozilla::net::gIOService) {
1976 mozilla::net::gIOService->CallOrWaitForSocketProcess([p = RefPtr{
1977 promise}]() {
1978 RefPtr<mozilla::net::SocketProcessParent> socketParent =
1979 mozilla::net::SocketProcessParent::GetSingleton();
1980 Unused << socketParent->SendClearSessionCache()->Then(
1981 GetCurrentSerialEventTarget(), __func__,
1982 [promise = RefPtr{p}] { promise->MaybeResolveWithUndefined(); },
1983 [promise = RefPtr{p}] { promise->MaybeReject(NS_ERROR_UNEXPECTED); });
1985 } else {
1986 promise->MaybeResolveWithUndefined();
1988 DoClearSSLExternalAndInternalSessionCache();
1989 promise.forget(aPromise);
1990 return NS_OK;
1993 namespace mozilla {
1994 namespace psm {
1996 already_AddRefed<SharedCertVerifier> GetDefaultCertVerifier() {
1997 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
1999 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID));
2000 if (!nssComponent) {
2001 return nullptr;
2003 nsresult rv = nssComponent->BlockUntilLoadableCertsLoaded();
2004 if (NS_FAILED(rv)) {
2005 return nullptr;
2007 RefPtr<SharedCertVerifier> result;
2008 rv = nssComponent->GetDefaultCertVerifier(getter_AddRefs(result));
2009 if (NS_FAILED(rv)) {
2010 return nullptr;
2012 return result.forget();
2015 // Helper for FindClientCertificatesWithPrivateKeys. Copies all
2016 // CERTCertificates from `from` to `to`.
2017 static inline void CopyCertificatesTo(UniqueCERTCertList& from,
2018 UniqueCERTCertList& to) {
2019 MOZ_ASSERT(from);
2020 MOZ_ASSERT(to);
2021 for (CERTCertListNode* n = CERT_LIST_HEAD(from.get());
2022 !CERT_LIST_END(n, from.get()); n = CERT_LIST_NEXT(n)) {
2023 UniqueCERTCertificate cert(CERT_DupCertificate(n->cert));
2024 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2025 (" provisionally adding '%s'", n->cert->subjectName));
2026 if (CERT_AddCertToListTail(to.get(), cert.get()) == SECSuccess) {
2027 Unused << cert.release();
2032 // Lists all private keys on all modules and returns a list of any corresponding
2033 // client certificates. Returns null if no such certificates can be found. Also
2034 // returns null if an error is encountered, because this is called as part of
2035 // the client auth data callback, and NSS ignores any errors returned by the
2036 // callback.
2037 UniqueCERTCertList FindClientCertificatesWithPrivateKeys() {
2038 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2039 ("FindClientCertificatesWithPrivateKeys"));
2041 (void)BlockUntilLoadableCertsLoaded();
2042 (void)CheckForSmartCardChanges();
2044 UniqueCERTCertList certsWithPrivateKeys(CERT_NewCertList());
2045 if (!certsWithPrivateKeys) {
2046 return nullptr;
2049 UniquePK11SlotInfo internalSlot(PK11_GetInternalKeySlot());
2051 AutoSECMODListReadLock secmodLock;
2052 SECMODModuleList* list = SECMOD_GetDefaultModuleList();
2053 while (list) {
2054 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2055 (" module '%s'", list->module->commonName));
2056 for (int i = 0; i < list->module->slotCount; i++) {
2057 PK11SlotInfo* slot = list->module->slots[i];
2058 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2059 (" slot '%s'", PK11_GetSlotName(slot)));
2060 // If this is the internal certificate/key slot or the slot on the
2061 // builtin roots module, there may be many more certificates than private
2062 // keys, so search by private keys (PK11_HasRootCerts will be true if the
2063 // slot contains an object with the vendor-specific CK_CLASS
2064 // CKO_NSS_BUILTIN_ROOT_LIST, which should only be the case for the NSS
2065 // builtin roots module).
2066 if (internalSlot.get() == slot || PK11_HasRootCerts(slot)) {
2067 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2068 (" (looking at internal/builtin slot)"));
2069 if (PK11_Authenticate(slot, true, nullptr) != SECSuccess) {
2070 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, (" (couldn't authenticate)"));
2071 continue;
2073 UniqueSECKEYPrivateKeyList privateKeys(
2074 PK11_ListPrivKeysInSlot(slot, nullptr, nullptr));
2075 if (!privateKeys) {
2076 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, (" (no private keys)"));
2077 continue;
2079 for (SECKEYPrivateKeyListNode* node = PRIVKEY_LIST_HEAD(privateKeys);
2080 !PRIVKEY_LIST_END(node, privateKeys);
2081 node = PRIVKEY_LIST_NEXT(node)) {
2082 UniqueCERTCertList certs(PK11_GetCertsMatchingPrivateKey(node->key));
2083 if (!certs) {
2084 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2085 (" PK11_GetCertsMatchingPrivateKey encountered an "
2086 "error "));
2087 continue;
2089 if (CERT_LIST_EMPTY(certs)) {
2090 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, (" (no certs for key)"));
2091 continue;
2093 CopyCertificatesTo(certs, certsWithPrivateKeys);
2095 } else {
2096 // ... otherwise, optimistically assume that searching by certificate
2097 // won't take too much time. Since "friendly" slots expose certificates
2098 // without needing to be authenticated to, this results in fewer PIN
2099 // dialogs shown to the user.
2100 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2101 (" (looking at non-internal slot)"));
2103 if (!PK11_IsPresent(slot)) {
2104 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, (" (not present)"));
2105 continue;
2107 // If this isn't a "friendly" slot, authenticate to expose certificates.
2108 if (!PK11_IsFriendly(slot) &&
2109 PK11_Authenticate(slot, true, nullptr) != SECSuccess) {
2110 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, (" (couldn't authenticate)"));
2111 continue;
2113 UniqueCERTCertList certsInSlot(PK11_ListCertsInSlot(slot));
2114 if (!certsInSlot) {
2115 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2116 (" (couldn't list certs in slot)"));
2117 continue;
2119 // When NSS decodes a certificate, if that certificate has a
2120 // corresponding private key (or public key, if the slot it's on hasn't
2121 // been logged into), it notes it as a "user cert".
2122 if (CERT_FilterCertListForUserCerts(certsInSlot.get()) != SECSuccess) {
2123 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2124 (" (couldn't filter certs)"));
2125 continue;
2127 CopyCertificatesTo(certsInSlot, certsWithPrivateKeys);
2130 list = list->next;
2133 if (CERT_FilterCertListByUsage(certsWithPrivateKeys.get(), certUsageSSLClient,
2134 false) != SECSuccess) {
2135 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2136 (" CERT_FilterCertListByUsage encountered an error - returning"));
2137 return nullptr;
2140 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gPIPNSSLog, LogLevel::Debug))) {
2141 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, (" returning:"));
2142 for (CERTCertListNode* n = CERT_LIST_HEAD(certsWithPrivateKeys);
2143 !CERT_LIST_END(n, certsWithPrivateKeys); n = CERT_LIST_NEXT(n)) {
2144 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, (" %s", n->cert->subjectName));
2148 if (CERT_LIST_EMPTY(certsWithPrivateKeys)) {
2149 return nullptr;
2152 return certsWithPrivateKeys;
2155 CertVerifier::CertificateTransparencyMode GetCertificateTransparencyMode() {
2156 const CertVerifier::CertificateTransparencyMode defaultCTMode =
2157 CertVerifier::CertificateTransparencyMode::TelemetryOnly;
2158 CertVerifier::CertificateTransparencyMode ctMode =
2159 static_cast<CertVerifier::CertificateTransparencyMode>(
2160 StaticPrefs::security_pki_certificate_transparency_mode());
2161 switch (ctMode) {
2162 case CertVerifier::CertificateTransparencyMode::Disabled:
2163 case CertVerifier::CertificateTransparencyMode::TelemetryOnly:
2164 case CertVerifier::CertificateTransparencyMode::Enforce:
2165 break;
2166 default:
2167 ctMode = defaultCTMode;
2168 break;
2170 return ctMode;
2173 } // namespace psm
2174 } // namespace mozilla
2176 NS_IMPL_ISUPPORTS(PipUIContext, nsIInterfaceRequestor)
2178 PipUIContext::PipUIContext() = default;
2180 PipUIContext::~PipUIContext() = default;
2182 NS_IMETHODIMP
2183 PipUIContext::GetInterface(const nsIID& uuid, void** result) {
2184 NS_ENSURE_ARG_POINTER(result);
2185 *result = nullptr;
2187 if (!NS_IsMainThread()) {
2188 NS_ERROR("PipUIContext::GetInterface called off the main thread");
2189 return NS_ERROR_NOT_SAME_THREAD;
2192 if (!uuid.Equals(NS_GET_IID(nsIPrompt))) return NS_ERROR_NO_INTERFACE;
2194 nsIPrompt* prompt = nullptr;
2195 nsresult rv = nsNSSComponent::GetNewPrompter(&prompt);
2196 *result = prompt;
2197 return rv;
2200 nsresult getNSSDialogs(void** _result, REFNSIID aIID, const char* contract) {
2201 if (!NS_IsMainThread()) {
2202 NS_ERROR("getNSSDialogs called off the main thread");
2203 return NS_ERROR_NOT_SAME_THREAD;
2206 nsresult rv;
2208 nsCOMPtr<nsISupports> svc = do_GetService(contract, &rv);
2209 if (NS_FAILED(rv)) {
2210 return rv;
2213 rv = svc->QueryInterface(aIID, _result);
2215 return rv;
2218 nsresult setPassword(PK11SlotInfo* slot, nsIInterfaceRequestor* ctx) {
2219 MOZ_ASSERT(slot);
2220 MOZ_ASSERT(ctx);
2221 NS_ENSURE_ARG_POINTER(slot);
2222 NS_ENSURE_ARG_POINTER(ctx);
2224 if (PK11_NeedUserInit(slot)) {
2225 nsCOMPtr<nsITokenPasswordDialogs> dialogs;
2226 nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
2227 NS_GET_IID(nsITokenPasswordDialogs),
2228 NS_TOKENPASSWORDSDIALOG_CONTRACTID);
2229 if (NS_FAILED(rv)) {
2230 return rv;
2233 bool canceled;
2234 nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot);
2235 rv = dialogs->SetPassword(ctx, token, &canceled);
2236 if (NS_FAILED(rv)) {
2237 return rv;
2240 if (canceled) {
2241 return NS_ERROR_NOT_AVAILABLE;
2245 return NS_OK;
2248 static PRBool ConvertBetweenUCS2andASCII(PRBool toUnicode, unsigned char* inBuf,
2249 unsigned int inBufLen,
2250 unsigned char* outBuf,
2251 unsigned int maxOutBufLen,
2252 unsigned int* outBufLen,
2253 PRBool swapBytes) {
2254 std::unique_ptr<unsigned char[]> inBufDup(new unsigned char[inBufLen]);
2255 if (!inBufDup) {
2256 return PR_FALSE;
2258 std::memcpy(inBufDup.get(), inBuf, inBufLen * sizeof(unsigned char));
2260 // If converting Unicode to ASCII, swap bytes before conversion as neccessary.
2261 if (!toUnicode && swapBytes) {
2262 if (inBufLen % 2 != 0) {
2263 return PR_FALSE;
2265 mozilla::NativeEndian::swapFromLittleEndianInPlace(
2266 reinterpret_cast<char16_t*>(inBufDup.get()), inBufLen / 2);
2268 return PORT_UCS2_UTF8Conversion(toUnicode, inBufDup.get(), inBufLen, outBuf,
2269 maxOutBufLen, outBufLen);
2272 namespace mozilla {
2273 namespace psm {
2275 nsresult InitializeCipherSuite() {
2276 MOZ_ASSERT(NS_IsMainThread(),
2277 "InitializeCipherSuite() can only be accessed on the main thread");
2279 if (NSS_SetDomesticPolicy() != SECSuccess) {
2280 return NS_ERROR_FAILURE;
2283 // Disable any ciphers that NSS might have enabled by default
2284 for (uint16_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
2285 uint16_t cipher_id = SSL_ImplementedCiphers[i];
2286 SSL_CipherPrefSetDefault(cipher_id, false);
2289 // Now only set SSL/TLS ciphers we knew about at compile time
2290 for (const auto& cipherPref : sCipherPrefs) {
2291 SSL_CipherPrefSetDefault(cipherPref.id, cipherPref.prefGetter());
2294 SetDeprecatedTLS1CipherPrefs();
2296 // Enable ciphers for PKCS#12
2297 SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
2298 SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
2299 SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
2300 SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
2301 SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
2302 SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
2303 SEC_PKCS12EnableCipher(PKCS12_AES_CBC_128, 1);
2304 SEC_PKCS12EnableCipher(PKCS12_AES_CBC_192, 1);
2305 SEC_PKCS12EnableCipher(PKCS12_AES_CBC_256, 1);
2306 SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
2307 PORT_SetUCS2_ASCIIConversionFunction(ConvertBetweenUCS2andASCII);
2309 // PSM enforces a minimum RSA key size of 1024 bits, which is overridable.
2310 // NSS has its own minimum, which is not overridable (the default is 1023
2311 // bits). This sets the NSS minimum to 512 bits so users can still connect to
2312 // devices like wifi routers with woefully small keys (they would have to add
2313 // an override to do so, but they already do for such devices).
2314 NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 512);
2316 SetKyberPolicy();
2318 // Observe preference change around cipher suite setting.
2319 return CipherSuiteChangeObserver::StartObserve();
2322 } // namespace psm
2323 } // namespace mozilla