diff options
Diffstat (limited to 'security/manager/ssl/SharedSSLState.cpp')
-rw-r--r-- | security/manager/ssl/SharedSSLState.cpp | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/security/manager/ssl/SharedSSLState.cpp b/security/manager/ssl/SharedSSLState.cpp new file mode 100644 index 000000000..c97687541 --- /dev/null +++ b/security/manager/ssl/SharedSSLState.cpp @@ -0,0 +1,218 @@ +/* -*- 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::psm::SyncRunnableBase; +using mozilla::Atomic; +using mozilla::Unused; + +namespace { + +static Atomic<bool> sCertOverrideSvcExists(false); + +class MainThreadClearer : public SyncRunnableBase +{ +public: + MainThreadClearer() : mShouldClearSessionCache(false) {} + + void RunOnTargetThread() { + // 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( + NS_LITERAL_CSTRING("all:temporary-certificates"), + 0); + } + } + + // 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) { + SSL_ClearSessionCache(); + } +} + +namespace psm { + +namespace { +class PrivateBrowsingObserver : public nsIObserver { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + explicit PrivateBrowsingObserver(SharedSSLState* aOwner) : mOwner(aOwner) {} +protected: + virtual ~PrivateBrowsingObserver() {} +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() +: mClientAuthRemember(new nsClientAuthRememberService) +, mMutex("SharedSSLState::mMutex") +, mSocketCreated(false) +, mOCSPStaplingEnabled(false) +, mOCSPMustStapleEnabled(false) +{ + mIOLayerHelpers.Init(); + mClientAuthRemember->Init(); +} + +SharedSSLState::~SharedSSLState() +{ +} + +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"); + mClientAuthRemember->ClearRememberedDecisions(); + 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 |