nsCertOverrideService.cpp (23102B)
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/. */ 6 7 #include "nsCertOverrideService.h" 8 9 #include "NSSCertDBTrustDomain.h" 10 #include "mozilla/Assertions.h" 11 #include "mozilla/ScopeExit.h" 12 #include "mozilla/TaskQueue.h" 13 #include "mozilla/glean/SecurityManagerSslMetrics.h" 14 #include "mozilla/TextUtils.h" 15 #include "mozilla/Tokenizer.h" 16 #include "mozilla/dom/ToJSValue.h" 17 #include "nsAppDirectoryServiceDefs.h" 18 #include "nsCRT.h" 19 #include "nsILineInputStream.h" 20 #ifdef ENABLE_WEBDRIVER 21 # include "nsIMarionette.h" 22 #endif 23 #include "nsIObserver.h" 24 #include "nsIObserverService.h" 25 #include "nsIOutputStream.h" 26 #ifdef ENABLE_WEBDRIVER 27 # include "nsIRemoteAgent.h" 28 #endif 29 #include "nsISafeOutputStream.h" 30 #include "nsIX509Cert.h" 31 #include "nsNSSCertificate.h" 32 #include "nsNSSComponent.h" 33 #include "nsNetUtil.h" 34 #include "nsStreamUtils.h" 35 #include "nsThreadUtils.h" 36 37 using namespace mozilla; 38 using namespace mozilla::psm; 39 40 #define CERT_OVERRIDE_FILE_NAME "cert_override.txt" 41 42 class WriterRunnable : public Runnable { 43 public: 44 WriterRunnable(nsCertOverrideService* aService, nsCString& aData, 45 nsCOMPtr<nsIFile> aFile) 46 : Runnable("nsCertOverrideService::WriterRunnable"), 47 mCertOverrideService(aService), 48 mData(aData), 49 mFile(std::move(aFile)) {} 50 51 NS_IMETHOD 52 Run() override { 53 mCertOverrideService->AssertOnTaskQueue(); 54 nsresult rv; 55 56 auto removeShutdownBlockerOnExit = 57 MakeScopeExit([certOverrideService = mCertOverrideService]() { 58 NS_DispatchToMainThread(NS_NewRunnableFunction( 59 "nsCertOverrideService::RemoveShutdownBlocker", 60 [certOverrideService] { 61 certOverrideService->RemoveShutdownBlocker(); 62 })); 63 }); 64 65 nsCOMPtr<nsIOutputStream> outputStream; 66 rv = NS_NewSafeLocalFileOutputStream( 67 getter_AddRefs(outputStream), mFile, 68 PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY); 69 NS_ENSURE_SUCCESS(rv, rv); 70 71 const char* ptr = mData.get(); 72 uint32_t remaining = mData.Length(); 73 uint32_t written = 0; 74 while (remaining > 0) { 75 rv = outputStream->Write(ptr, remaining, &written); 76 NS_ENSURE_SUCCESS(rv, rv); 77 remaining -= written; 78 ptr += written; 79 } 80 81 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outputStream); 82 MOZ_ASSERT(safeStream); 83 rv = safeStream->Finish(); 84 NS_ENSURE_SUCCESS(rv, rv); 85 86 return NS_OK; 87 } 88 89 private: 90 const RefPtr<nsCertOverrideService> mCertOverrideService; 91 nsCString mData; 92 const nsCOMPtr<nsIFile> mFile; 93 }; 94 95 NS_IMPL_ISUPPORTS(nsCertOverride, nsICertOverride) 96 97 NS_IMETHODIMP 98 nsCertOverride::GetAsciiHost(/*out*/ nsACString& aAsciiHost) { 99 aAsciiHost = mAsciiHost; 100 return NS_OK; 101 } 102 103 NS_IMETHODIMP 104 nsCertOverride::GetFingerprint(/*out*/ nsACString& aFingerprint) { 105 aFingerprint = mFingerprint; 106 return NS_OK; 107 } 108 109 NS_IMETHODIMP 110 nsCertOverride::GetPort(/*out*/ int32_t* aPort) { 111 *aPort = mPort; 112 return NS_OK; 113 } 114 115 NS_IMETHODIMP 116 nsCertOverride::GetHostPort(/*out*/ nsACString& aHostPort) { 117 nsCertOverrideService::GetHostWithPort(mAsciiHost, mPort, aHostPort); 118 return NS_OK; 119 } 120 121 NS_IMETHODIMP 122 nsCertOverride::GetOriginAttributes( 123 JSContext* aCtx, /*out*/ JS::MutableHandle<JS::Value> aValue) { 124 if (ToJSValue(aCtx, mOriginAttributes, aValue)) { 125 return NS_OK; 126 } 127 return NS_ERROR_FAILURE; 128 } 129 130 NS_IMPL_ISUPPORTS(nsCertOverrideService, nsICertOverrideService, nsIObserver, 131 nsISupportsWeakReference, nsIAsyncShutdownBlocker) 132 133 nsCertOverrideService::nsCertOverrideService() 134 : mMutex("nsCertOverrideService.mutex"), 135 mDisableAllSecurityCheck(false), 136 mPendingWriteCount(0) { 137 nsCOMPtr<nsIEventTarget> target = 138 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); 139 MOZ_ASSERT(target); 140 141 mWriterTaskQueue = TaskQueue::Create(target.forget(), "CertOverrideService"); 142 } 143 144 nsCertOverrideService::~nsCertOverrideService() = default; 145 146 static nsCOMPtr<nsIAsyncShutdownClient> GetShutdownBarrier() { 147 MOZ_ASSERT(NS_IsMainThread()); 148 nsCOMPtr<nsIAsyncShutdownService> svc = 149 mozilla::services::GetAsyncShutdownService(); 150 MOZ_RELEASE_ASSERT(svc); 151 152 nsCOMPtr<nsIAsyncShutdownClient> barrier; 153 nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(barrier)); 154 155 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 156 MOZ_RELEASE_ASSERT(barrier); 157 return barrier; 158 } 159 160 nsresult nsCertOverrideService::Init() { 161 if (!NS_IsMainThread()) { 162 MOZ_ASSERT_UNREACHABLE("nsCertOverrideService initialized off main thread"); 163 return NS_ERROR_NOT_SAME_THREAD; 164 } 165 166 nsCOMPtr<nsIObserverService> observerService = 167 mozilla::services::GetObserverService(); 168 169 // If we cannot add ourselves as a profile change observer, then we will not 170 // attempt to read/write any settings file. Otherwise, we would end up 171 // reading/writing the wrong settings file after a profile change. 172 if (observerService) { 173 observerService->AddObserver(this, "last-pb-context-exited", false); 174 observerService->AddObserver(this, "profile-do-change", true); 175 // simulate a profile change so we read the current profile's settings file 176 Observe(nullptr, "profile-do-change", nullptr); 177 } 178 179 return NS_OK; 180 } 181 182 NS_IMETHODIMP 183 nsCertOverrideService::Observe(nsISupports*, const char* aTopic, 184 const char16_t* aData) { 185 if (!nsCRT::strcmp(aTopic, "profile-do-change")) { 186 // The profile has already changed. 187 // Now read from the new profile location. 188 // we also need to update the cached file location 189 190 MutexAutoLock lock(mMutex); 191 192 nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, 193 getter_AddRefs(mSettingsFile)); 194 if (NS_SUCCEEDED(rv)) { 195 mSettingsFile->AppendNative(nsLiteralCString(CERT_OVERRIDE_FILE_NAME)); 196 } else { 197 mSettingsFile = nullptr; 198 } 199 Read(lock); 200 CountPermanentOverrideTelemetry(lock); 201 } else if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) { 202 ClearValidityOverride("all:temporary-certificates"_ns, 0, 203 OriginAttributes()); 204 } 205 206 return NS_OK; 207 } 208 209 void nsCertOverrideService::RemoveAllTemporaryOverrides() { 210 MutexAutoLock lock(mMutex); 211 bool removedAny = false; 212 for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) { 213 nsCertOverrideEntry* entry = iter.Get(); 214 if (entry->mSettings->mIsTemporary) { 215 iter.Remove(); 216 removedAny = true; 217 } 218 } 219 if (removedAny) { 220 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 221 if (os) { 222 os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr); 223 } 224 } 225 // no need to write, as temporaries are never written to disk 226 } 227 228 static const char sSHA256OIDString[] = "OID.2.16.840.1.101.3.4.2.1"; 229 nsresult nsCertOverrideService::Read(const MutexAutoLock& aProofOfLock) { 230 mMutex.AssertCurrentThreadOwns(); 231 // If we don't have a profile, then we won't try to read any settings file. 232 if (!mSettingsFile) return NS_OK; 233 234 nsresult rv; 235 nsCOMPtr<nsIInputStream> fileInputStream; 236 rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), 237 mSettingsFile); 238 if (NS_FAILED(rv)) { 239 return rv; 240 } 241 242 nsCOMPtr<nsILineInputStream> lineInputStream = 243 do_QueryInterface(fileInputStream, &rv); 244 if (NS_FAILED(rv)) { 245 return rv; 246 } 247 248 nsAutoCString buffer; 249 bool isMore = true; 250 251 // Each line is of the form: 252 // host:port:originAttributes \t sSHA256OIDString \t fingerprint \t 253 // There may be some "bits" identifiers and "dbKey" after the `fingerprint` 254 // field in 'fingerprint \t \t dbKey' format, but these are now ignored. 255 // Lines that don't match this form are silently dropped. 256 257 while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) { 258 if (buffer.IsEmpty() || buffer.First() == '#') { 259 continue; 260 } 261 262 Tokenizer parser(buffer); 263 nsDependentCSubstring host; 264 if (parser.CheckChar('[')) { // this is a IPv6 address 265 if (!parser.ReadUntil(Tokenizer::Token::Char(']'), host) || 266 host.Length() == 0 || !parser.CheckChar(':')) { 267 continue; 268 } 269 } else if (!parser.ReadUntil(Tokenizer::Token::Char(':'), host) || 270 host.Length() == 0) { 271 continue; 272 } 273 int32_t port = -1; 274 if (!parser.ReadInteger(&port)) { 275 continue; 276 } 277 OriginAttributes attributes; 278 if (parser.CheckChar(':')) { 279 nsDependentCSubstring attributesString; 280 if (!parser.ReadUntil(Tokenizer::Token::Whitespace(), attributesString) || 281 !attributes.PopulateFromSuffix(attributesString)) { 282 continue; 283 } 284 } else if (!parser.CheckWhite()) { 285 continue; 286 } 287 nsDependentCSubstring algorithm; 288 if (!parser.ReadUntil(Tokenizer::Token::Whitespace(), algorithm) || 289 algorithm != sSHA256OIDString) { 290 continue; 291 } 292 nsDependentCSubstring fingerprint; 293 if (!parser.ReadUntil(Tokenizer::Token::Whitespace(), fingerprint) || 294 fingerprint.Length() == 0) { 295 continue; 296 } 297 298 AddEntryToList(host, port, attributes, 299 false, // not temporary 300 fingerprint, aProofOfLock); 301 } 302 303 return NS_OK; 304 } 305 306 nsresult nsCertOverrideService::Write(const MutexAutoLock& aProofOfLock) { 307 mMutex.AssertCurrentThreadOwns(); 308 MOZ_ASSERT(NS_IsMainThread()); 309 if (!NS_IsMainThread()) { 310 return NS_ERROR_NOT_SAME_THREAD; 311 } 312 313 // If we don't have any profile, then we won't try to write any file 314 if (!mSettingsFile) { 315 return NS_OK; 316 } 317 318 nsCString output; 319 320 static const char kHeader[] = 321 "# PSM Certificate Override Settings file" NS_LINEBREAK 322 "# This is a generated file! Do not edit." NS_LINEBREAK; 323 324 /* see ::Read for file format */ 325 326 output.Append(kHeader); 327 328 static const char kTab[] = "\t"; 329 for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) { 330 nsCertOverrideEntry* entry = iter.Get(); 331 332 RefPtr<nsCertOverride> settings = entry->mSettings; 333 if (settings->mIsTemporary) { 334 continue; 335 } 336 337 output.Append(entry->mKeyString); 338 output.Append(kTab); 339 output.Append(sSHA256OIDString); 340 output.Append(kTab); 341 output.Append(settings->mFingerprint); 342 output.Append(kTab); 343 // the "bits" string used to go here, but it no longer exists 344 // the "\t dbKey" string used to go here, but it no longer exists 345 output.Append(NS_LINEBREAK); 346 } 347 348 // Make a clone of the file to pass to the WriterRunnable. 349 nsCOMPtr<nsIFile> file; 350 nsresult rv; 351 rv = mSettingsFile->Clone(getter_AddRefs(file)); 352 NS_ENSURE_SUCCESS(rv, rv); 353 354 nsCOMPtr<nsIRunnable> runnable = new WriterRunnable(this, output, file); 355 rv = mWriterTaskQueue->Dispatch(runnable.forget()); 356 if (NS_FAILED(rv)) { 357 return rv; 358 } 359 mPendingWriteCount++; 360 361 if (mPendingWriteCount == 1) { 362 rv = GetShutdownBarrier()->AddBlocker( 363 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, 364 u"nsCertOverrideService writing data"_ns); 365 NS_ENSURE_SUCCESS(rv, rv); 366 } 367 368 return NS_OK; 369 } 370 371 nsresult GetCertSha256Fingerprint(nsIX509Cert* aCert, nsCString& aResult) { 372 nsAutoString fpStrUTF16; 373 nsresult rv = aCert->GetSha256Fingerprint(fpStrUTF16); 374 if (NS_FAILED(rv)) { 375 return rv; 376 } 377 aResult.Assign(NS_ConvertUTF16toUTF8(fpStrUTF16)); 378 return NS_OK; 379 } 380 381 NS_IMETHODIMP 382 nsCertOverrideService::RememberValidityOverride( 383 const nsACString& aHostName, int32_t aPort, 384 const OriginAttributes& aOriginAttributes, nsIX509Cert* aCert, 385 bool aTemporary) { 386 if (aHostName.IsEmpty() || !IsAscii(aHostName) || !aCert) { 387 return NS_ERROR_INVALID_ARG; 388 } 389 if (aPort < -1) { 390 return NS_ERROR_INVALID_ARG; 391 } 392 if (!NS_IsMainThread()) { 393 return NS_ERROR_NOT_SAME_THREAD; 394 } 395 396 nsAutoCString fpStr; 397 nsresult rv = GetCertSha256Fingerprint(aCert, fpStr); 398 if (NS_FAILED(rv)) { 399 return rv; 400 } 401 402 { 403 MutexAutoLock lock(mMutex); 404 AddEntryToList(aHostName, aPort, aOriginAttributes, aTemporary, fpStr, 405 lock); 406 if (!aTemporary) { 407 Write(lock); 408 } 409 } 410 411 return NS_OK; 412 } 413 414 NS_IMETHODIMP 415 nsCertOverrideService::RememberValidityOverrideScriptable( 416 const nsACString& aHostName, int32_t aPort, 417 JS::Handle<JS::Value> aOriginAttributes, nsIX509Cert* aCert, 418 bool aTemporary, JSContext* aCx) { 419 OriginAttributes attrs; 420 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 421 return NS_ERROR_INVALID_ARG; 422 } 423 424 return RememberValidityOverride(aHostName, aPort, attrs, aCert, aTemporary); 425 } 426 427 NS_IMETHODIMP 428 nsCertOverrideService::HasMatchingOverride( 429 const nsACString& aHostName, int32_t aPort, 430 const OriginAttributes& aOriginAttributes, nsIX509Cert* aCert, 431 bool* aIsTemporary, bool* aRetval) { 432 bool disableAllSecurityCheck = false; 433 { 434 MutexAutoLock lock(mMutex); 435 if (mUserContextIdsWithSecurityChecksOverride.has( 436 aOriginAttributes.mUserContextId)) { 437 auto p = mUserContextIdsWithSecurityChecksOverride.lookup( 438 aOriginAttributes.mUserContextId); 439 disableAllSecurityCheck = p->value(); 440 } else { 441 disableAllSecurityCheck = mDisableAllSecurityCheck; 442 } 443 } 444 if (disableAllSecurityCheck) { 445 *aIsTemporary = false; 446 *aRetval = true; 447 return NS_OK; 448 } 449 450 if (aHostName.IsEmpty() || !IsAscii(aHostName)) { 451 return NS_ERROR_INVALID_ARG; 452 } 453 if (aPort < -1) return NS_ERROR_INVALID_ARG; 454 455 NS_ENSURE_ARG_POINTER(aCert); 456 NS_ENSURE_ARG_POINTER(aIsTemporary); 457 NS_ENSURE_ARG_POINTER(aRetval); 458 *aRetval = false; 459 460 RefPtr<nsCertOverride> settings( 461 GetOverrideFor(aHostName, aPort, aOriginAttributes)); 462 // If there is no corresponding override and the given OriginAttributes isn't 463 // the default, try to look up an override using the default OriginAttributes. 464 if (!settings && aOriginAttributes != OriginAttributes()) { 465 settings = GetOverrideFor(aHostName, aPort, OriginAttributes()); 466 } 467 if (!settings) { 468 return NS_OK; 469 } 470 471 *aIsTemporary = settings->mIsTemporary; 472 473 nsAutoCString fpStr; 474 nsresult rv = GetCertSha256Fingerprint(aCert, fpStr); 475 if (NS_FAILED(rv)) { 476 return rv; 477 } 478 479 *aRetval = settings->mFingerprint.Equals(fpStr); 480 return NS_OK; 481 } 482 483 already_AddRefed<nsCertOverride> nsCertOverrideService::GetOverrideFor( 484 const nsACString& aHostName, int32_t aPort, 485 const OriginAttributes& aOriginAttributes) { 486 nsAutoCString keyString; 487 GetKeyString(aHostName, aPort, aOriginAttributes, keyString); 488 MutexAutoLock lock(mMutex); 489 nsCertOverrideEntry* entry = mSettingsTable.GetEntry(keyString.get()); 490 if (!entry) { 491 return nullptr; 492 } 493 return do_AddRef(entry->mSettings); 494 } 495 496 NS_IMETHODIMP 497 nsCertOverrideService::HasMatchingOverrideScriptable( 498 const nsACString& aHostName, int32_t aPort, 499 JS::Handle<JS::Value> aOriginAttributes, nsIX509Cert* aCert, 500 bool* aIsTemporary, JSContext* aCx, bool* aRetval) { 501 OriginAttributes attrs; 502 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 503 return NS_ERROR_INVALID_ARG; 504 } 505 506 return HasMatchingOverride(aHostName, aPort, attrs, aCert, aIsTemporary, 507 aRetval); 508 } 509 510 nsresult nsCertOverrideService::AddEntryToList( 511 const nsACString& aHostName, int32_t aPort, 512 const OriginAttributes& aOriginAttributes, const bool aIsTemporary, 513 const nsACString& fingerprint, const MutexAutoLock& aProofOfLock) { 514 mMutex.AssertCurrentThreadOwns(); 515 nsAutoCString keyString; 516 GetKeyString(aHostName, aPort, aOriginAttributes, keyString); 517 518 nsCertOverrideEntry* entry = mSettingsTable.PutEntry(keyString.get()); 519 520 if (!entry) { 521 NS_ERROR("can't insert a null entry!"); 522 return NS_ERROR_OUT_OF_MEMORY; 523 } 524 525 entry->mKeyString = keyString; 526 527 RefPtr<nsCertOverride> settings(new nsCertOverride()); 528 529 settings->mAsciiHost = aHostName; 530 settings->mPort = aPort; 531 settings->mOriginAttributes = aOriginAttributes; 532 settings->mIsTemporary = aIsTemporary; 533 settings->mFingerprint = fingerprint; 534 entry->mSettings = settings; 535 536 return NS_OK; 537 } 538 539 NS_IMETHODIMP 540 nsCertOverrideService::ClearValidityOverride( 541 const nsACString& aHostName, int32_t aPort, 542 const OriginAttributes& aOriginAttributes) { 543 if (aHostName.IsEmpty() || !IsAscii(aHostName)) { 544 return NS_ERROR_INVALID_ARG; 545 } 546 if (!NS_IsMainThread()) { 547 return NS_ERROR_NOT_SAME_THREAD; 548 } 549 550 if (aPort == 0 && aHostName.EqualsLiteral("all:temporary-certificates")) { 551 RemoveAllTemporaryOverrides(); 552 return NS_OK; 553 } 554 nsAutoCString keyString; 555 GetKeyString(aHostName, aPort, aOriginAttributes, keyString); 556 { 557 MutexAutoLock lock(mMutex); 558 mSettingsTable.RemoveEntry(keyString.get()); 559 Write(lock); 560 } 561 562 nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID)); 563 if (nss) { 564 nss->ClearSSLExternalAndInternalSessionCache(); 565 } else { 566 return NS_ERROR_NOT_AVAILABLE; 567 } 568 569 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 570 if (os) { 571 os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr); 572 } 573 574 return NS_OK; 575 } 576 NS_IMETHODIMP 577 nsCertOverrideService::ClearValidityOverrideScriptable( 578 const nsACString& aHostName, int32_t aPort, 579 JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx) { 580 OriginAttributes attrs; 581 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 582 return NS_ERROR_INVALID_ARG; 583 } 584 585 return ClearValidityOverride(aHostName, aPort, attrs); 586 } 587 588 NS_IMETHODIMP 589 nsCertOverrideService::ClearAllOverrides() { 590 if (!NS_IsMainThread()) { 591 return NS_ERROR_NOT_SAME_THREAD; 592 } 593 594 { 595 MutexAutoLock lock(mMutex); 596 mSettingsTable.Clear(); 597 Write(lock); 598 } 599 600 nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID)); 601 if (nss) { 602 nss->ClearSSLExternalAndInternalSessionCache(); 603 } else { 604 return NS_ERROR_NOT_AVAILABLE; 605 } 606 607 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 608 if (os) { 609 os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr); 610 } 611 612 return NS_OK; 613 } 614 615 void nsCertOverrideService::CountPermanentOverrideTelemetry( 616 const MutexAutoLock& aProofOfLock) { 617 mMutex.AssertCurrentThreadOwns(); 618 uint32_t overrideCount = 0; 619 for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) { 620 if (!iter.Get()->mSettings->mIsTemporary) { 621 overrideCount++; 622 } 623 } 624 glean::ssl::permanent_cert_error_overrides.AccumulateSingleSample( 625 overrideCount); 626 } 627 628 static bool IsDebugger() { 629 #ifdef ENABLE_WEBDRIVER 630 nsCOMPtr<nsIMarionette> marionette = do_GetService(NS_MARIONETTE_CONTRACTID); 631 if (marionette) { 632 bool marionetteRunning = false; 633 marionette->GetRunning(&marionetteRunning); 634 if (marionetteRunning) { 635 return true; 636 } 637 } 638 639 nsCOMPtr<nsIRemoteAgent> agent = do_GetService(NS_REMOTEAGENT_CONTRACTID); 640 if (agent) { 641 bool remoteAgentRunning = false; 642 agent->GetRunning(&remoteAgentRunning); 643 if (remoteAgentRunning) { 644 return true; 645 } 646 } 647 #endif 648 649 return false; 650 } 651 652 NS_IMETHODIMP 653 nsCertOverrideService:: 654 SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(bool aDisable) { 655 if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { 656 return NS_ERROR_NOT_AVAILABLE; 657 } 658 659 { 660 MutexAutoLock lock(mMutex); 661 mDisableAllSecurityCheck = aDisable; 662 } 663 664 nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID)); 665 if (nss) { 666 nss->ClearSSLExternalAndInternalSessionCache(); 667 } else { 668 return NS_ERROR_NOT_AVAILABLE; 669 } 670 671 return NS_OK; 672 } 673 674 NS_IMETHODIMP 675 nsCertOverrideService:: 676 SetDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext( 677 uint32_t aUserContextId, bool aDisable) { 678 if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { 679 return NS_ERROR_NOT_AVAILABLE; 680 } 681 682 { 683 MutexAutoLock lock(mMutex); 684 (void)mUserContextIdsWithSecurityChecksOverride.put(aUserContextId, 685 aDisable); 686 } 687 688 return NS_OK; 689 } 690 691 NS_IMETHODIMP 692 nsCertOverrideService:: 693 ResetDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext( 694 uint32_t aUserContextId) { 695 if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { 696 return NS_ERROR_NOT_AVAILABLE; 697 } 698 699 { 700 MutexAutoLock lock(mMutex); 701 mUserContextIdsWithSecurityChecksOverride.remove(aUserContextId); 702 } 703 704 return NS_OK; 705 } 706 707 NS_IMETHODIMP 708 nsCertOverrideService::GetSecurityCheckDisabled(bool* aDisabled) { 709 MutexAutoLock lock(mMutex); 710 *aDisabled = mDisableAllSecurityCheck; 711 return NS_OK; 712 } 713 714 NS_IMETHODIMP 715 nsCertOverrideService::GetOverrides( 716 /*out*/ nsTArray<RefPtr<nsICertOverride>>& retval) { 717 MutexAutoLock lock(mMutex); 718 for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) { 719 const RefPtr<nsICertOverride> settings = iter.Get()->mSettings; 720 721 retval.AppendElement(settings); 722 } 723 return NS_OK; 724 } 725 726 void nsCertOverrideService::GetHostWithPort(const nsACString& aHostName, 727 int32_t aPort, 728 nsACString& aRetval) { 729 nsAutoCString hostPort; 730 if (aHostName.Contains(':')) { 731 // if aHostName is an IPv6 address, add brackets to match the internal 732 // representation, which always stores IPv6 addresses with brackets 733 hostPort.Append('['); 734 hostPort.Append(aHostName); 735 hostPort.Append(']'); 736 } else { 737 hostPort.Append(aHostName); 738 } 739 if (aPort == -1) { 740 aPort = 443; 741 } 742 if (!hostPort.IsEmpty()) { 743 hostPort.Append(':'); 744 hostPort.AppendInt(aPort); 745 } 746 aRetval.Assign(hostPort); 747 } 748 749 void nsCertOverrideService::GetKeyString( 750 const nsACString& aHostName, int32_t aPort, 751 const OriginAttributes& aOriginAttributes, nsACString& aRetval) { 752 nsAutoCString keyString; 753 GetHostWithPort(aHostName, aPort, keyString); 754 keyString.Append(':'); 755 OriginAttributes strippedAttributes(aOriginAttributes); 756 strippedAttributes.StripAttributes( 757 ~OriginAttributes::STRIP_PRIVATE_BROWSING_ID); 758 nsAutoCString attributeSuffix; 759 strippedAttributes.CreateSuffix(attributeSuffix); 760 keyString.Append(attributeSuffix); 761 aRetval.Assign(keyString); 762 } 763 764 // nsIAsyncShutdownBlocker implementation 765 NS_IMETHODIMP 766 nsCertOverrideService::GetName(nsAString& aName) { 767 aName = u"nsCertOverrideService: shutdown"_ns; 768 return NS_OK; 769 } 770 771 NS_IMETHODIMP 772 nsCertOverrideService::GetState(nsIPropertyBag** aState) { 773 if (!aState) { 774 return NS_ERROR_INVALID_ARG; 775 } 776 *aState = nullptr; 777 return NS_OK; 778 } 779 780 NS_IMETHODIMP 781 nsCertOverrideService::BlockShutdown(nsIAsyncShutdownClient*) { return NS_OK; } 782 783 void nsCertOverrideService::RemoveShutdownBlocker() { 784 MOZ_ASSERT(NS_IsMainThread()); 785 MOZ_ASSERT(mPendingWriteCount > 0); 786 mPendingWriteCount--; 787 if (mPendingWriteCount == 0) { 788 nsresult rv = GetShutdownBarrier()->RemoveBlocker(this); 789 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 790 } 791 }