summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/SharedSSLState.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--security/manager/ssl/SharedSSLState.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/security/manager/ssl/SharedSSLState.cpp b/security/manager/ssl/SharedSSLState.cpp
new file mode 100644
index 0000000000..9547383071
--- /dev/null
+++ b/security/manager/ssl/SharedSSLState.cpp
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SharedSSLState.h"
+#include "nsClientAuthRemember.h"
+#include "nsComponentManagerUtils.h"
+#include "nsICertOverrideService.h"
+#include "nsIObserverService.h"
+#include "mozilla/Services.h"
+#include "nsThreadUtils.h"
+#include "nsCRT.h"
+#include "nsServiceManagerUtils.h"
+#include "PSMRunnable.h"
+#include "PublicSSL.h"
+#include "ssl.h"
+#include "nsNetCID.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Unused.h"
+
+using mozilla::Atomic;
+using mozilla::Unused;
+using mozilla::psm::SyncRunnableBase;
+
+namespace {
+
+static Atomic<bool> sCertOverrideSvcExists(false);
+
+class MainThreadClearer : public SyncRunnableBase {
+ public:
+ MainThreadClearer() : mShouldClearSessionCache(false) {}
+
+ void RunOnTargetThread() override {
+ // In some cases it's possible to cause PSM/NSS to initialize while XPCOM
+ // shutdown is in progress. We want to avoid this, since they do not handle
+ // the situation well, hence the flags to avoid instantiating the services
+ // if they don't already exist.
+
+ bool certOverrideSvcExists = sCertOverrideSvcExists.exchange(false);
+ if (certOverrideSvcExists) {
+ sCertOverrideSvcExists = true;
+ nsCOMPtr<nsICertOverrideService> icos =
+ do_GetService(NS_CERTOVERRIDE_CONTRACTID);
+ if (icos) {
+ icos->ClearValidityOverride("all:temporary-certificates"_ns, 0,
+ OriginAttributes());
+ }
+ }
+
+ // This needs to be checked on the main thread to avoid racing with NSS
+ // initialization.
+ mShouldClearSessionCache = mozilla::psm::PrivateSSLState() &&
+ mozilla::psm::PrivateSSLState()->SocketCreated();
+ }
+ bool mShouldClearSessionCache;
+};
+
+} // namespace
+
+namespace mozilla {
+
+void ClearPrivateSSLState() {
+ // This only works if it is called on the socket transport
+ // service thread immediately after closing all private SSL
+ // connections.
+#ifdef DEBUG
+ nsresult rv;
+ nsCOMPtr<nsIEventTarget> sts =
+ do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ bool onSTSThread;
+ rv = sts->IsOnCurrentThread(&onSTSThread);
+ MOZ_ASSERT(NS_SUCCEEDED(rv) && onSTSThread);
+#endif
+
+ RefPtr<MainThreadClearer> runnable = new MainThreadClearer;
+ runnable->DispatchToMainThreadAndWait();
+
+ // If NSS isn't initialized, this throws an assertion. We guard it by checking
+ // if the session cache might even have anything worth clearing.
+ if (runnable->mShouldClearSessionCache) {
+ nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
+ }
+}
+
+namespace psm {
+
+namespace {
+class PrivateBrowsingObserver : public nsIObserver {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+ explicit PrivateBrowsingObserver(SharedSSLState* aOwner) : mOwner(aOwner) {}
+
+ protected:
+ virtual ~PrivateBrowsingObserver() = default;
+
+ private:
+ SharedSSLState* mOwner;
+};
+
+SharedSSLState* gPublicState;
+SharedSSLState* gPrivateState;
+} // namespace
+
+NS_IMPL_ISUPPORTS(PrivateBrowsingObserver, nsIObserver)
+
+NS_IMETHODIMP
+PrivateBrowsingObserver::Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData) {
+ if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
+ mOwner->ResetStoredData();
+ }
+ return NS_OK;
+}
+
+SharedSSLState::SharedSSLState(uint32_t aTlsFlags)
+ : mIOLayerHelpers(aTlsFlags),
+ mMutex("SharedSSLState::mMutex"),
+ mSocketCreated(false),
+ mOCSPStaplingEnabled(false),
+ mOCSPMustStapleEnabled(false),
+ mSignedCertTimestampsEnabled(false) {
+ mIOLayerHelpers.Init();
+}
+
+SharedSSLState::~SharedSSLState() = default;
+
+void SharedSSLState::NotePrivateBrowsingStatus() {
+ MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
+ mObserver = new PrivateBrowsingObserver(this);
+ nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+ obsSvc->AddObserver(mObserver, "last-pb-context-exited", false);
+}
+
+void SharedSSLState::ResetStoredData() {
+ MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
+ mIOLayerHelpers.clearStoredData();
+}
+
+void SharedSSLState::NoteSocketCreated() {
+ MutexAutoLock lock(mMutex);
+ mSocketCreated = true;
+}
+
+bool SharedSSLState::SocketCreated() {
+ MutexAutoLock lock(mMutex);
+ return mSocketCreated;
+}
+
+/*static*/
+void SharedSSLState::GlobalInit() {
+ MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
+ gPublicState = new SharedSSLState();
+ gPrivateState = new SharedSSLState();
+ gPrivateState->NotePrivateBrowsingStatus();
+}
+
+/*static*/
+void SharedSSLState::GlobalCleanup() {
+ MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
+
+ if (gPrivateState) {
+ gPrivateState->Cleanup();
+ delete gPrivateState;
+ gPrivateState = nullptr;
+ }
+
+ if (gPublicState) {
+ gPublicState->Cleanup();
+ delete gPublicState;
+ gPublicState = nullptr;
+ }
+}
+
+/*static*/
+void SharedSSLState::NoteCertOverrideServiceInstantiated() {
+ sCertOverrideSvcExists = true;
+}
+
+void SharedSSLState::Cleanup() { mIOLayerHelpers.Cleanup(); }
+
+SharedSSLState* PublicSSLState() { return gPublicState; }
+
+SharedSSLState* PrivateSSLState() { return gPrivateState; }
+
+} // namespace psm
+} // namespace mozilla