Bug 1928997: Update tabs icon in Unified Search popup r=desktop-theme-reviewers,daleh...
[gecko.git] / security / manager / ssl / nsCertOverrideService.cpp
blob1b9f32fc97bf3c5000db95567eaab85b518fe03a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "nsCertOverrideService.h"
9 #include "NSSCertDBTrustDomain.h"
10 #include "mozilla/Assertions.h"
11 #include "mozilla/ScopeExit.h"
12 #include "mozilla/TaskQueue.h"
13 #include "mozilla/Telemetry.h"
14 #include "mozilla/TextUtils.h"
15 #include "mozilla/Tokenizer.h"
16 #include "mozilla/Unused.h"
17 #include "mozilla/dom/ToJSValue.h"
18 #include "nsAppDirectoryServiceDefs.h"
19 #include "nsCRT.h"
20 #include "nsILineInputStream.h"
21 #ifdef ENABLE_WEBDRIVER
22 # include "nsIMarionette.h"
23 #endif
24 #include "nsIObserver.h"
25 #include "nsIObserverService.h"
26 #include "nsIOutputStream.h"
27 #ifdef ENABLE_WEBDRIVER
28 # include "nsIRemoteAgent.h"
29 #endif
30 #include "nsISafeOutputStream.h"
31 #include "nsIX509Cert.h"
32 #include "nsNSSCertificate.h"
33 #include "nsNSSComponent.h"
34 #include "nsNetUtil.h"
35 #include "nsStreamUtils.h"
36 #include "nsThreadUtils.h"
38 using namespace mozilla;
39 using namespace mozilla::psm;
41 #define CERT_OVERRIDE_FILE_NAME "cert_override.txt"
43 class WriterRunnable : public Runnable {
44 public:
45 WriterRunnable(nsCertOverrideService* aService, nsCString& aData,
46 nsCOMPtr<nsIFile> aFile)
47 : Runnable("nsCertOverrideService::WriterRunnable"),
48 mCertOverrideService(aService),
49 mData(aData),
50 mFile(std::move(aFile)) {}
52 NS_IMETHOD
53 Run() override {
54 mCertOverrideService->AssertOnTaskQueue();
55 nsresult rv;
57 auto removeShutdownBlockerOnExit =
58 MakeScopeExit([certOverrideService = mCertOverrideService]() {
59 NS_DispatchToMainThread(NS_NewRunnableFunction(
60 "nsCertOverrideService::RemoveShutdownBlocker",
61 [certOverrideService] {
62 certOverrideService->RemoveShutdownBlocker();
63 }));
64 });
66 nsCOMPtr<nsIOutputStream> outputStream;
67 rv = NS_NewSafeLocalFileOutputStream(
68 getter_AddRefs(outputStream), mFile,
69 PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY);
70 NS_ENSURE_SUCCESS(rv, rv);
72 const char* ptr = mData.get();
73 uint32_t remaining = mData.Length();
74 uint32_t written = 0;
75 while (remaining > 0) {
76 rv = outputStream->Write(ptr, remaining, &written);
77 NS_ENSURE_SUCCESS(rv, rv);
78 remaining -= written;
79 ptr += written;
82 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outputStream);
83 MOZ_ASSERT(safeStream);
84 rv = safeStream->Finish();
85 NS_ENSURE_SUCCESS(rv, rv);
87 return NS_OK;
90 private:
91 const RefPtr<nsCertOverrideService> mCertOverrideService;
92 nsCString mData;
93 const nsCOMPtr<nsIFile> mFile;
96 NS_IMPL_ISUPPORTS(nsCertOverride, nsICertOverride)
98 NS_IMETHODIMP
99 nsCertOverride::GetAsciiHost(/*out*/ nsACString& aAsciiHost) {
100 aAsciiHost = mAsciiHost;
101 return NS_OK;
104 NS_IMETHODIMP
105 nsCertOverride::GetFingerprint(/*out*/ nsACString& aFingerprint) {
106 aFingerprint = mFingerprint;
107 return NS_OK;
110 NS_IMETHODIMP
111 nsCertOverride::GetPort(/*out*/ int32_t* aPort) {
112 *aPort = mPort;
113 return NS_OK;
116 NS_IMETHODIMP
117 nsCertOverride::GetHostPort(/*out*/ nsACString& aHostPort) {
118 nsCertOverrideService::GetHostWithPort(mAsciiHost, mPort, aHostPort);
119 return NS_OK;
122 NS_IMETHODIMP
123 nsCertOverride::GetOriginAttributes(
124 JSContext* aCtx, /*out*/ JS::MutableHandle<JS::Value> aValue) {
125 if (ToJSValue(aCtx, mOriginAttributes, aValue)) {
126 return NS_OK;
128 return NS_ERROR_FAILURE;
131 NS_IMPL_ISUPPORTS(nsCertOverrideService, nsICertOverrideService, nsIObserver,
132 nsISupportsWeakReference, nsIAsyncShutdownBlocker)
134 nsCertOverrideService::nsCertOverrideService()
135 : mMutex("nsCertOverrideService.mutex"),
136 mDisableAllSecurityCheck(false),
137 mPendingWriteCount(0) {
138 nsCOMPtr<nsIEventTarget> target =
139 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
140 MOZ_ASSERT(target);
142 mWriterTaskQueue = TaskQueue::Create(target.forget(), "CertOverrideService");
145 nsCertOverrideService::~nsCertOverrideService() = default;
147 static nsCOMPtr<nsIAsyncShutdownClient> GetShutdownBarrier() {
148 MOZ_ASSERT(NS_IsMainThread());
149 nsCOMPtr<nsIAsyncShutdownService> svc =
150 mozilla::services::GetAsyncShutdownService();
151 MOZ_RELEASE_ASSERT(svc);
153 nsCOMPtr<nsIAsyncShutdownClient> barrier;
154 nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(barrier));
156 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
157 MOZ_RELEASE_ASSERT(barrier);
158 return barrier;
161 nsresult nsCertOverrideService::Init() {
162 if (!NS_IsMainThread()) {
163 MOZ_ASSERT_UNREACHABLE("nsCertOverrideService initialized off main thread");
164 return NS_ERROR_NOT_SAME_THREAD;
167 nsCOMPtr<nsIObserverService> observerService =
168 mozilla::services::GetObserverService();
170 // If we cannot add ourselves as a profile change observer, then we will not
171 // attempt to read/write any settings file. Otherwise, we would end up
172 // reading/writing the wrong settings file after a profile change.
173 if (observerService) {
174 observerService->AddObserver(this, "last-pb-context-exited", false);
175 observerService->AddObserver(this, "profile-do-change", true);
176 // simulate a profile change so we read the current profile's settings file
177 Observe(nullptr, "profile-do-change", nullptr);
180 return NS_OK;
183 NS_IMETHODIMP
184 nsCertOverrideService::Observe(nsISupports*, const char* aTopic,
185 const char16_t* aData) {
186 if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
187 // The profile has already changed.
188 // Now read from the new profile location.
189 // we also need to update the cached file location
191 MutexAutoLock lock(mMutex);
193 nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
194 getter_AddRefs(mSettingsFile));
195 if (NS_SUCCEEDED(rv)) {
196 mSettingsFile->AppendNative(nsLiteralCString(CERT_OVERRIDE_FILE_NAME));
197 } else {
198 mSettingsFile = nullptr;
200 Read(lock);
201 CountPermanentOverrideTelemetry(lock);
202 } else if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
203 ClearValidityOverride("all:temporary-certificates"_ns, 0,
204 OriginAttributes());
207 return NS_OK;
210 void nsCertOverrideService::RemoveAllTemporaryOverrides() {
211 MutexAutoLock lock(mMutex);
212 bool removedAny = false;
213 for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
214 nsCertOverrideEntry* entry = iter.Get();
215 if (entry->mSettings->mIsTemporary) {
216 iter.Remove();
217 removedAny = true;
220 if (removedAny) {
221 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
222 if (os) {
223 os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr);
226 // no need to write, as temporaries are never written to disk
229 static const char sSHA256OIDString[] = "OID.2.16.840.1.101.3.4.2.1";
230 nsresult nsCertOverrideService::Read(const MutexAutoLock& aProofOfLock) {
231 mMutex.AssertCurrentThreadOwns();
232 // If we don't have a profile, then we won't try to read any settings file.
233 if (!mSettingsFile) return NS_OK;
235 nsresult rv;
236 nsCOMPtr<nsIInputStream> fileInputStream;
237 rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream),
238 mSettingsFile);
239 if (NS_FAILED(rv)) {
240 return rv;
243 nsCOMPtr<nsILineInputStream> lineInputStream =
244 do_QueryInterface(fileInputStream, &rv);
245 if (NS_FAILED(rv)) {
246 return rv;
249 nsAutoCString buffer;
250 bool isMore = true;
252 // Each line is of the form:
253 // host:port:originAttributes \t sSHA256OIDString \t fingerprint \t
254 // There may be some "bits" identifiers and "dbKey" after the `fingerprint`
255 // field in 'fingerprint \t \t dbKey' format, but these are now ignored.
256 // Lines that don't match this form are silently dropped.
258 while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
259 if (buffer.IsEmpty() || buffer.First() == '#') {
260 continue;
263 Tokenizer parser(buffer);
264 nsDependentCSubstring host;
265 if (parser.CheckChar('[')) { // this is a IPv6 address
266 if (!parser.ReadUntil(Tokenizer::Token::Char(']'), host) ||
267 host.Length() == 0 || !parser.CheckChar(':')) {
268 continue;
270 } else if (!parser.ReadUntil(Tokenizer::Token::Char(':'), host) ||
271 host.Length() == 0) {
272 continue;
274 int32_t port = -1;
275 if (!parser.ReadInteger(&port)) {
276 continue;
278 OriginAttributes attributes;
279 if (parser.CheckChar(':')) {
280 nsDependentCSubstring attributesString;
281 if (!parser.ReadUntil(Tokenizer::Token::Whitespace(), attributesString) ||
282 !attributes.PopulateFromSuffix(attributesString)) {
283 continue;
285 } else if (!parser.CheckWhite()) {
286 continue;
288 nsDependentCSubstring algorithm;
289 if (!parser.ReadUntil(Tokenizer::Token::Whitespace(), algorithm) ||
290 algorithm != sSHA256OIDString) {
291 continue;
293 nsDependentCSubstring fingerprint;
294 if (!parser.ReadUntil(Tokenizer::Token::Whitespace(), fingerprint) ||
295 fingerprint.Length() == 0) {
296 continue;
299 AddEntryToList(host, port, attributes,
300 false, // not temporary
301 fingerprint, aProofOfLock);
304 return NS_OK;
307 nsresult nsCertOverrideService::Write(const MutexAutoLock& aProofOfLock) {
308 mMutex.AssertCurrentThreadOwns();
309 MOZ_ASSERT(NS_IsMainThread());
310 if (!NS_IsMainThread()) {
311 return NS_ERROR_NOT_SAME_THREAD;
314 // If we don't have any profile, then we won't try to write any file
315 if (!mSettingsFile) {
316 return NS_OK;
319 nsCString output;
321 static const char kHeader[] =
322 "# PSM Certificate Override Settings file" NS_LINEBREAK
323 "# This is a generated file! Do not edit." NS_LINEBREAK;
325 /* see ::Read for file format */
327 output.Append(kHeader);
329 static const char kTab[] = "\t";
330 for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
331 nsCertOverrideEntry* entry = iter.Get();
333 RefPtr<nsCertOverride> settings = entry->mSettings;
334 if (settings->mIsTemporary) {
335 continue;
338 output.Append(entry->mKeyString);
339 output.Append(kTab);
340 output.Append(sSHA256OIDString);
341 output.Append(kTab);
342 output.Append(settings->mFingerprint);
343 output.Append(kTab);
344 // the "bits" string used to go here, but it no longer exists
345 // the "\t dbKey" string used to go here, but it no longer exists
346 output.Append(NS_LINEBREAK);
349 // Make a clone of the file to pass to the WriterRunnable.
350 nsCOMPtr<nsIFile> file;
351 nsresult rv;
352 rv = mSettingsFile->Clone(getter_AddRefs(file));
353 NS_ENSURE_SUCCESS(rv, rv);
355 nsCOMPtr<nsIRunnable> runnable = new WriterRunnable(this, output, file);
356 rv = mWriterTaskQueue->Dispatch(runnable.forget());
357 if (NS_FAILED(rv)) {
358 return rv;
360 mPendingWriteCount++;
362 if (mPendingWriteCount == 1) {
363 rv = GetShutdownBarrier()->AddBlocker(
364 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__,
365 u"nsCertOverrideService writing data"_ns);
366 NS_ENSURE_SUCCESS(rv, rv);
369 return NS_OK;
372 nsresult GetCertSha256Fingerprint(nsIX509Cert* aCert, nsCString& aResult) {
373 nsAutoString fpStrUTF16;
374 nsresult rv = aCert->GetSha256Fingerprint(fpStrUTF16);
375 if (NS_FAILED(rv)) {
376 return rv;
378 aResult.Assign(NS_ConvertUTF16toUTF8(fpStrUTF16));
379 return NS_OK;
382 NS_IMETHODIMP
383 nsCertOverrideService::RememberValidityOverride(
384 const nsACString& aHostName, int32_t aPort,
385 const OriginAttributes& aOriginAttributes, nsIX509Cert* aCert,
386 bool aTemporary) {
387 if (aHostName.IsEmpty() || !IsAscii(aHostName) || !aCert) {
388 return NS_ERROR_INVALID_ARG;
390 if (aPort < -1) {
391 return NS_ERROR_INVALID_ARG;
393 if (!NS_IsMainThread()) {
394 return NS_ERROR_NOT_SAME_THREAD;
397 nsAutoCString fpStr;
398 nsresult rv = GetCertSha256Fingerprint(aCert, fpStr);
399 if (NS_FAILED(rv)) {
400 return rv;
404 MutexAutoLock lock(mMutex);
405 AddEntryToList(aHostName, aPort, aOriginAttributes, aTemporary, fpStr,
406 lock);
407 if (!aTemporary) {
408 Write(lock);
412 return NS_OK;
415 NS_IMETHODIMP
416 nsCertOverrideService::RememberValidityOverrideScriptable(
417 const nsACString& aHostName, int32_t aPort,
418 JS::Handle<JS::Value> aOriginAttributes, nsIX509Cert* aCert,
419 bool aTemporary, JSContext* aCx) {
420 OriginAttributes attrs;
421 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
422 return NS_ERROR_INVALID_ARG;
425 return RememberValidityOverride(aHostName, aPort, attrs, aCert, aTemporary);
428 NS_IMETHODIMP
429 nsCertOverrideService::HasMatchingOverride(
430 const nsACString& aHostName, int32_t aPort,
431 const OriginAttributes& aOriginAttributes, nsIX509Cert* aCert,
432 bool* aIsTemporary, bool* aRetval) {
433 bool disableAllSecurityCheck = false;
435 MutexAutoLock lock(mMutex);
436 disableAllSecurityCheck = mDisableAllSecurityCheck;
438 if (disableAllSecurityCheck) {
439 *aIsTemporary = false;
440 *aRetval = true;
441 return NS_OK;
444 if (aHostName.IsEmpty() || !IsAscii(aHostName)) {
445 return NS_ERROR_INVALID_ARG;
447 if (aPort < -1) return NS_ERROR_INVALID_ARG;
449 NS_ENSURE_ARG_POINTER(aCert);
450 NS_ENSURE_ARG_POINTER(aIsTemporary);
451 NS_ENSURE_ARG_POINTER(aRetval);
452 *aRetval = false;
454 RefPtr<nsCertOverride> settings(
455 GetOverrideFor(aHostName, aPort, aOriginAttributes));
456 // If there is no corresponding override and the given OriginAttributes isn't
457 // the default, try to look up an override using the default OriginAttributes.
458 if (!settings && aOriginAttributes != OriginAttributes()) {
459 settings = GetOverrideFor(aHostName, aPort, OriginAttributes());
461 if (!settings) {
462 return NS_OK;
465 *aIsTemporary = settings->mIsTemporary;
467 nsAutoCString fpStr;
468 nsresult rv = GetCertSha256Fingerprint(aCert, fpStr);
469 if (NS_FAILED(rv)) {
470 return rv;
473 *aRetval = settings->mFingerprint.Equals(fpStr);
474 return NS_OK;
477 already_AddRefed<nsCertOverride> nsCertOverrideService::GetOverrideFor(
478 const nsACString& aHostName, int32_t aPort,
479 const OriginAttributes& aOriginAttributes) {
480 nsAutoCString keyString;
481 GetKeyString(aHostName, aPort, aOriginAttributes, keyString);
482 MutexAutoLock lock(mMutex);
483 nsCertOverrideEntry* entry = mSettingsTable.GetEntry(keyString.get());
484 if (!entry) {
485 return nullptr;
487 return do_AddRef(entry->mSettings);
490 NS_IMETHODIMP
491 nsCertOverrideService::HasMatchingOverrideScriptable(
492 const nsACString& aHostName, int32_t aPort,
493 JS::Handle<JS::Value> aOriginAttributes, nsIX509Cert* aCert,
494 bool* aIsTemporary, JSContext* aCx, bool* aRetval) {
495 OriginAttributes attrs;
496 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
497 return NS_ERROR_INVALID_ARG;
500 return HasMatchingOverride(aHostName, aPort, attrs, aCert, aIsTemporary,
501 aRetval);
504 nsresult nsCertOverrideService::AddEntryToList(
505 const nsACString& aHostName, int32_t aPort,
506 const OriginAttributes& aOriginAttributes, const bool aIsTemporary,
507 const nsACString& fingerprint, const MutexAutoLock& aProofOfLock) {
508 mMutex.AssertCurrentThreadOwns();
509 nsAutoCString keyString;
510 GetKeyString(aHostName, aPort, aOriginAttributes, keyString);
512 nsCertOverrideEntry* entry = mSettingsTable.PutEntry(keyString.get());
514 if (!entry) {
515 NS_ERROR("can't insert a null entry!");
516 return NS_ERROR_OUT_OF_MEMORY;
519 entry->mKeyString = keyString;
521 RefPtr<nsCertOverride> settings(new nsCertOverride());
523 settings->mAsciiHost = aHostName;
524 settings->mPort = aPort;
525 settings->mOriginAttributes = aOriginAttributes;
526 settings->mIsTemporary = aIsTemporary;
527 settings->mFingerprint = fingerprint;
528 entry->mSettings = settings;
530 return NS_OK;
533 NS_IMETHODIMP
534 nsCertOverrideService::ClearValidityOverride(
535 const nsACString& aHostName, int32_t aPort,
536 const OriginAttributes& aOriginAttributes) {
537 if (aHostName.IsEmpty() || !IsAscii(aHostName)) {
538 return NS_ERROR_INVALID_ARG;
540 if (!NS_IsMainThread()) {
541 return NS_ERROR_NOT_SAME_THREAD;
544 if (aPort == 0 && aHostName.EqualsLiteral("all:temporary-certificates")) {
545 RemoveAllTemporaryOverrides();
546 return NS_OK;
548 nsAutoCString keyString;
549 GetKeyString(aHostName, aPort, aOriginAttributes, keyString);
551 MutexAutoLock lock(mMutex);
552 mSettingsTable.RemoveEntry(keyString.get());
553 Write(lock);
556 nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID));
557 if (nss) {
558 nss->ClearSSLExternalAndInternalSessionCache();
559 } else {
560 return NS_ERROR_NOT_AVAILABLE;
563 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
564 if (os) {
565 os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr);
568 return NS_OK;
570 NS_IMETHODIMP
571 nsCertOverrideService::ClearValidityOverrideScriptable(
572 const nsACString& aHostName, int32_t aPort,
573 JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx) {
574 OriginAttributes attrs;
575 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
576 return NS_ERROR_INVALID_ARG;
579 return ClearValidityOverride(aHostName, aPort, attrs);
582 NS_IMETHODIMP
583 nsCertOverrideService::ClearAllOverrides() {
584 if (!NS_IsMainThread()) {
585 return NS_ERROR_NOT_SAME_THREAD;
589 MutexAutoLock lock(mMutex);
590 mSettingsTable.Clear();
591 Write(lock);
594 nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID));
595 if (nss) {
596 nss->ClearSSLExternalAndInternalSessionCache();
597 } else {
598 return NS_ERROR_NOT_AVAILABLE;
601 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
602 if (os) {
603 os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr);
606 return NS_OK;
609 void nsCertOverrideService::CountPermanentOverrideTelemetry(
610 const MutexAutoLock& aProofOfLock) {
611 mMutex.AssertCurrentThreadOwns();
612 uint32_t overrideCount = 0;
613 for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
614 if (!iter.Get()->mSettings->mIsTemporary) {
615 overrideCount++;
618 Telemetry::Accumulate(Telemetry::SSL_PERMANENT_CERT_ERROR_OVERRIDES,
619 overrideCount);
622 static bool IsDebugger() {
623 #ifdef ENABLE_WEBDRIVER
624 nsCOMPtr<nsIMarionette> marionette = do_GetService(NS_MARIONETTE_CONTRACTID);
625 if (marionette) {
626 bool marionetteRunning = false;
627 marionette->GetRunning(&marionetteRunning);
628 if (marionetteRunning) {
629 return true;
633 nsCOMPtr<nsIRemoteAgent> agent = do_GetService(NS_REMOTEAGENT_CONTRACTID);
634 if (agent) {
635 bool remoteAgentRunning = false;
636 agent->GetRunning(&remoteAgentRunning);
637 if (remoteAgentRunning) {
638 return true;
641 #endif
643 return false;
646 NS_IMETHODIMP
647 nsCertOverrideService::
648 SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(bool aDisable) {
649 if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
650 return NS_ERROR_NOT_AVAILABLE;
654 MutexAutoLock lock(mMutex);
655 mDisableAllSecurityCheck = aDisable;
658 nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID));
659 if (nss) {
660 nss->ClearSSLExternalAndInternalSessionCache();
661 } else {
662 return NS_ERROR_NOT_AVAILABLE;
665 return NS_OK;
668 NS_IMETHODIMP
669 nsCertOverrideService::GetSecurityCheckDisabled(bool* aDisabled) {
670 MutexAutoLock lock(mMutex);
671 *aDisabled = mDisableAllSecurityCheck;
672 return NS_OK;
675 NS_IMETHODIMP
676 nsCertOverrideService::GetOverrides(
677 /*out*/ nsTArray<RefPtr<nsICertOverride>>& retval) {
678 MutexAutoLock lock(mMutex);
679 for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
680 const RefPtr<nsICertOverride> settings = iter.Get()->mSettings;
682 retval.AppendElement(settings);
684 return NS_OK;
687 void nsCertOverrideService::GetHostWithPort(const nsACString& aHostName,
688 int32_t aPort,
689 nsACString& aRetval) {
690 nsAutoCString hostPort;
691 if (aHostName.Contains(':')) {
692 // if aHostName is an IPv6 address, add brackets to match the internal
693 // representation, which always stores IPv6 addresses with brackets
694 hostPort.Append('[');
695 hostPort.Append(aHostName);
696 hostPort.Append(']');
697 } else {
698 hostPort.Append(aHostName);
700 if (aPort == -1) {
701 aPort = 443;
703 if (!hostPort.IsEmpty()) {
704 hostPort.Append(':');
705 hostPort.AppendInt(aPort);
707 aRetval.Assign(hostPort);
710 void nsCertOverrideService::GetKeyString(
711 const nsACString& aHostName, int32_t aPort,
712 const OriginAttributes& aOriginAttributes, nsACString& aRetval) {
713 nsAutoCString keyString;
714 GetHostWithPort(aHostName, aPort, keyString);
715 keyString.Append(':');
716 OriginAttributes strippedAttributes(aOriginAttributes);
717 strippedAttributes.StripAttributes(
718 ~OriginAttributes::STRIP_PRIVATE_BROWSING_ID);
719 nsAutoCString attributeSuffix;
720 strippedAttributes.CreateSuffix(attributeSuffix);
721 keyString.Append(attributeSuffix);
722 aRetval.Assign(keyString);
725 // nsIAsyncShutdownBlocker implementation
726 NS_IMETHODIMP
727 nsCertOverrideService::GetName(nsAString& aName) {
728 aName = u"nsCertOverrideService: shutdown"_ns;
729 return NS_OK;
732 NS_IMETHODIMP
733 nsCertOverrideService::GetState(nsIPropertyBag** aState) {
734 if (!aState) {
735 return NS_ERROR_INVALID_ARG;
737 *aState = nullptr;
738 return NS_OK;
741 NS_IMETHODIMP
742 nsCertOverrideService::BlockShutdown(nsIAsyncShutdownClient*) { return NS_OK; }
744 void nsCertOverrideService::RemoveShutdownBlocker() {
745 MOZ_ASSERT(NS_IsMainThread());
746 MOZ_ASSERT(mPendingWriteCount > 0);
747 mPendingWriteCount--;
748 if (mPendingWriteCount == 0) {
749 nsresult rv = GetShutdownBarrier()->RemoveBlocker(this);
750 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));