/* -*- 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 "mozilla/OriginAttributes.h" #include "nsNSSComponent.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 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 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 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 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 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