Bug 769288 - Part 1: Make PSM more amenable to storing concurrent private and non-private data. r=bsmith

This commit is contained in:
Josh Matthews 2012-12-06 22:05:27 -05:00
parent 68eb09e802
commit 4d1d76ebee
19 changed files with 471 additions and 151 deletions

View File

@ -88,8 +88,11 @@ function initExceptionDialog() {
// returns true if found and global status could be set
function findRecentBadCert(uri) {
try {
var recentCertsSvc = Components.classes["@mozilla.org/security/recentbadcerts;1"]
.getService(Components.interfaces.nsIRecentBadCertsService);
var certDB = Components.classes["@mozilla.org/security/x509certdb;1"]
.getService(Components.interfaces.nsIX509CertDB);
if (!certDB)
return false;
var recentCertsSvc = certDB.getRecentBadCertsService(inPrivateBrowsingMode());
if (!recentCertsSvc)
return false;

View File

@ -20,9 +20,8 @@ interface nsISSLStatus;
* The implementation will decide how many entries it will hold,
* the number is expected to be small.
*/
[scriptable, uuid(a5ae8b05-a76e-408f-b0ba-02a831265749)]
interface nsIRecentBadCertsService : nsISupports {
[scriptable, uuid(0fed7784-d152-44d6-95a7-67a59024de0f)]
interface nsIRecentBadCerts : nsISupports {
/**
* Retrieve the recently seen bad ssl status for the given hostname:port.
* If no SSL cert was recently seen for the given hostname:port, return null.
@ -43,4 +42,9 @@ interface nsIRecentBadCertsService : nsISupports {
*/
void addBadCert(in AString aHostNameWithPort,
in nsISSLStatus aStatus);
/**
* Clear all stored cert data.
*/
void resetStoredCerts();
};

View File

@ -12,6 +12,7 @@ interface nsIX509Cert3;
interface nsIFile;
interface nsIInterfaceRequestor;
interface nsIZipReader;
interface nsIRecentBadCerts;
%{C++
#define NS_X509CERTDB_CONTRACTID "@mozilla.org/security/x509certdb;1"
@ -29,7 +30,7 @@ interface nsIOpenSignedJARFileCallback : nsISupports
* This represents a service to access and manipulate
* X.509 certificates stored in a database.
*/
[scriptable, uuid(735d0363-e219-4387-b5c6-72e800c3ea0b)]
[scriptable, uuid(a18df2a5-84a9-46cd-9140-3fdb3879d9ff)]
interface nsIX509CertDB : nsISupports {
/**
@ -264,6 +265,16 @@ interface nsIX509CertDB : nsISupports {
*/
nsIX509Cert constructX509FromBase64(in string base64);
/*
* Obtain a reference to the appropriate service for recent
* bad certificates. May only be called on the main thread.
*
* @param isPrivate True if the service for certs for private connections
* is desired, false otherwise.
* @return The requested service.
*/
nsIRecentBadCerts getRecentBadCerts(in boolean isPrivate);
/**
* Verifies the signature on the given JAR file to verify that it has a
* valid signature. To be considered valid, there must be exactly one

View File

@ -74,6 +74,7 @@ CPPSRCS = \
PSMRunnable.cpp \
nsNSSVersion.cpp \
nsCertificatePrincipal.cpp \
SharedSSLState.cpp \
$(NULL)
ifdef MOZ_XUL

View File

@ -112,6 +112,7 @@
#include "nsIConsoleService.h"
#include "PSMRunnable.h"
#include "ScopedNSSTypes.h"
#include "SharedSSLState.h"
#include "ssl.h"
#include "secerr.h"
@ -238,13 +239,15 @@ class CertErrorRunnable : public SyncRunnableBase
uint32_t collectedErrors,
PRErrorCode errorCodeTrust,
PRErrorCode errorCodeMismatch,
PRErrorCode errorCodeExpired)
PRErrorCode errorCodeExpired,
uint32_t providerFlags)
: mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
mDefaultErrorCodeToReport(defaultErrorCodeToReport),
mCollectedErrors(collectedErrors),
mErrorCodeTrust(errorCodeTrust),
mErrorCodeMismatch(errorCodeMismatch),
mErrorCodeExpired(errorCodeExpired)
mErrorCodeExpired(errorCodeExpired),
mProviderFlags(providerFlags)
{
}
@ -261,6 +264,7 @@ private:
const PRErrorCode mErrorCodeTrust;
const PRErrorCode mErrorCodeMismatch;
const PRErrorCode mErrorCodeExpired;
const uint32_t mProviderFlags;
};
SSLServerCertVerificationResult *
@ -296,12 +300,8 @@ CertErrorRunnable::CheckCertOverrides()
if (NS_SUCCEEDED(nsrv)) {
nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
uint32_t flags = 0;
if (sslSocketControl) {
sslSocketControl->GetProviderFlags(&flags);
}
nsrv = stss->IsStsHost(mInfoObject->GetHostName(),
flags,
mProviderFlags,
&strictTransportSecurityEnabled);
}
if (NS_FAILED(nsrv)) {
@ -371,8 +371,12 @@ CertErrorRunnable::CheckCertOverrides()
}
}
nsCOMPtr<nsIRecentBadCertsService> recentBadCertsService =
do_GetService(NS_RECENTBADCERTS_CONTRACTID);
nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
nsCOMPtr<nsIRecentBadCerts> recentBadCertsService;
if (certdb) {
bool isPrivate = mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
certdb->GetRecentBadCerts(isPrivate, getter_AddRefs(recentBadCertsService));
}
if (recentBadCertsService) {
NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
@ -418,7 +422,8 @@ CertErrorRunnable *
CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport,
TransportSecurityInfo * infoObject,
CERTCertificate * cert,
const void * fdForLogging)
const void * fdForLogging,
uint32_t providerFlags)
{
MOZ_ASSERT(infoObject);
MOZ_ASSERT(cert);
@ -567,7 +572,8 @@ CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport,
static_cast<nsIX509Cert*>(nssCert.get()),
infoObject, defaultErrorCodeToReport,
collected_errors, errorCodeTrust,
errorCodeMismatch, errorCodeExpired);
errorCodeMismatch, errorCodeExpired,
providerFlags);
}
// When doing async cert processing, we dispatch one of these runnables to the
@ -607,25 +613,29 @@ public:
// Must be called only on the socket transport thread
static SECStatus Dispatch(const void * fdForLogging,
TransportSecurityInfo * infoObject,
CERTCertificate * serverCert);
CERTCertificate * serverCert,
uint32_t providerFlags);
private:
NS_DECL_NSIRUNNABLE
// Must be called only on the socket transport thread
SSLServerCertVerificationJob(const void * fdForLogging,
TransportSecurityInfo * infoObject,
CERTCertificate * cert);
CERTCertificate * cert,
uint32_t providerFlags);
const void * const mFdForLogging;
const RefPtr<TransportSecurityInfo> mInfoObject;
const ScopedCERTCertificate mCert;
const uint32_t mProviderFlags;
};
SSLServerCertVerificationJob::SSLServerCertVerificationJob(
const void * fdForLogging, TransportSecurityInfo * infoObject,
CERTCertificate * cert)
CERTCertificate * cert, uint32_t providerFlags)
: mFdForLogging(fdForLogging)
, mInfoObject(infoObject)
, mCert(CERT_DupCertificate(cert))
, mProviderFlags(providerFlags)
{
}
@ -977,7 +987,8 @@ AuthCertificate(TransportSecurityInfo * infoObject, CERTCertificate * cert)
/*static*/ SECStatus
SSLServerCertVerificationJob::Dispatch(const void * fdForLogging,
TransportSecurityInfo * infoObject,
CERTCertificate * serverCert)
CERTCertificate * serverCert,
uint32_t providerFlags)
{
// Runs on the socket transport thread
if (!infoObject || !serverCert) {
@ -987,7 +998,8 @@ SSLServerCertVerificationJob::Dispatch(const void * fdForLogging,
}
RefPtr<SSLServerCertVerificationJob> job(
new SSLServerCertVerificationJob(fdForLogging, infoObject, serverCert));
new SSLServerCertVerificationJob(fdForLogging, infoObject, serverCert,
providerFlags));
nsresult nrv;
if (!gCertVerificationThreadPool) {
@ -1042,7 +1054,7 @@ SSLServerCertVerificationJob::Run()
error = PR_GetError();
if (error != 0) {
RefPtr<CertErrorRunnable> runnable(CreateCertErrorRunnable(
error, mInfoObject, mCert, mFdForLogging));
error, mInfoObject, mCert, mFdForLogging, mProviderFlags));
if (!runnable) {
// CreateCertErrorRunnable set a new error code
error = PR_GetError();
@ -1135,15 +1147,20 @@ AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
PR_SetError(PR_UNKNOWN_ERROR, 0);
return SECFailure;
}
uint32_t providerFlags = 0;
socketInfo->GetProviderFlags(&providerFlags);
if (onSTSThread) {
// We *must* do certificate verification on a background thread because
// we need the socket transport thread to be free for our OCSP requests,
// and we *want* to do certificate verification on a background thread
// because of the performance benefits of doing so.
socketInfo->SetCertVerificationWaiting();
SECStatus rv = SSLServerCertVerificationJob::Dispatch(
static_cast<const void *>(fd), socketInfo, serverCert);
static_cast<const void *>(fd), socketInfo, serverCert,
providerFlags);
return rv;
}
@ -1160,7 +1177,7 @@ AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
if (error != 0) {
RefPtr<CertErrorRunnable> runnable(CreateCertErrorRunnable(
error, socketInfo, serverCert,
static_cast<const void *>(fd)));
static_cast<const void *>(fd), providerFlags));
if (!runnable) {
// CreateCertErrorRunnable sets a new error code when it fails
error = PR_GetError();

View File

@ -0,0 +1,111 @@
/* -*- 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"
namespace mozilla {
namespace psm {
namespace {
class PrivateBrowsingObserver : public nsIObserver {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
PrivateBrowsingObserver(SharedSSLState* aOwner) : mOwner(aOwner) {}
virtual ~PrivateBrowsingObserver() {}
private:
SharedSSLState* mOwner;
};
SharedSSLState* gPublicState;
SharedSSLState* gPrivateState;
} // anonymous namespace
NS_IMPL_ISUPPORTS1(PrivateBrowsingObserver, nsIObserver)
NS_IMETHODIMP
PrivateBrowsingObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
mOwner->ResetStoredData();
}
return NS_OK;
}
SharedSSLState::SharedSSLState()
: mClientAuthRemember(new nsClientAuthRememberService)
{
mIOLayerHelpers.Init();
mClientAuthRemember->Init();
}
void
SharedSSLState::NotePrivateBrowsingStatus()
{
mObserver = new PrivateBrowsingObserver(this);
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
obsSvc->AddObserver(mObserver, "last-pb-context-exited", false);
}
void
SharedSSLState::ResetStoredData()
{
mClientAuthRemember->ClearRememberedDecisions();
mIOLayerHelpers.clearStoredData();
}
/*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");
gPrivateState->Cleanup();
delete gPrivateState;
gPrivateState = nullptr;
gPublicState->Cleanup();
delete gPublicState;
gPublicState = nullptr;
}
void
SharedSSLState::Cleanup()
{
mIOLayerHelpers.Cleanup();
}
SharedSSLState*
PublicSSLState()
{
return gPublicState;
}
SharedSSLState*
PrivateSSLState()
{
return gPrivateState;
}
} // namespace psm
} // namespace mozilla

View File

@ -0,0 +1,54 @@
/* -*- 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/. */
#ifndef SharedSSLState_h
#define SharedSSLState_h
#include "mozilla/RefPtr.h"
#include "nsNSSIOLayer.h"
class nsClientAuthRememberService;
class nsIRecentBadCertsService;
class nsICertOverrideService;
class nsIObserver;
namespace mozilla {
namespace psm {
class SharedSSLState {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedSSLState)
SharedSSLState();
static void GlobalInit();
static void GlobalCleanup();
nsClientAuthRememberService* GetClientAuthRememberService() {
return mClientAuthRemember;
}
nsSSLIOLayerHelpers& IOLayerHelpers() {
return mIOLayerHelpers;
}
void ResetStoredData();
void NotePrivateBrowsingStatus();
private:
void Cleanup();
nsCOMPtr<nsIObserver> mObserver;
RefPtr<nsClientAuthRememberService> mClientAuthRemember;
nsSSLIOLayerHelpers mIOLayerHelpers;
};
SharedSSLState* PublicSSLState();
SharedSSLState* PrivateSSLState();
} // namespace psm
} // namespace mozilla
#endif

View File

@ -21,8 +21,10 @@
#include "pk11pub.h"
#include "certdb.h"
#include "sechash.h"
#include "SharedSSLState.h"
using namespace mozilla;
using namespace mozilla::psm;
NS_IMPL_THREADSAFE_ISUPPORTS2(nsClientAuthRememberService,
nsIObserver,
@ -80,6 +82,16 @@ void nsClientAuthRememberService::ClearRememberedDecisions()
RemoveAllFromMemory();
}
void nsClientAuthRememberService::ClearAllRememberedDecisions()
{
RefPtr<nsClientAuthRememberService> svc =
PublicSSLState()->GetClientAuthRememberService();
svc->ClearRememberedDecisions();
svc = PrivateSSLState()->GetClientAuthRememberService();
svc->ClearRememberedDecisions();
}
void
nsClientAuthRememberService::RemoveAllFromMemory()
{

View File

@ -128,6 +128,7 @@ public:
nsACString & aCertDBKey, bool *_retval);
void ClearRememberedDecisions();
static void ClearAllRememberedDecisions();
protected:
mozilla::ReentrantMonitor monitor;

View File

@ -23,6 +23,7 @@
#include "nsIConsoleService.h"
#include "nsIHttpChannelInternal.h"
#include "nsCRT.h"
#include "SharedSSLState.h"
#include "ssl.h"
#include "sslproto.h"
@ -841,7 +842,8 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
// If the handshake completed, then we know the site is TLS tolerant (if this
// was a TLS connection).
nsSSLIOLayerHelpers::rememberTolerantSite(infoObject);
nsSSLIOLayerHelpers& ioLayerHelpers = infoObject->SharedState().IOLayerHelpers();
ioLayerHelpers.rememberTolerantSite(infoObject);
if (SECSuccess != SSL_SecurityStatus(fd, &sslStatus, &cipherName, &keyLength,
&encryptBits, &signer, nullptr)) {
@ -859,7 +861,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
if (SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn, &siteSupportsSafeRenego) != SECSuccess
|| !siteSupportsSafeRenego) {
bool wantWarning = (nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746() > 0);
bool wantWarning = (ioLayerHelpers.getWarnLevelMissingRFC5746() > 0);
nsCOMPtr<nsIConsoleService> console;
if (infoObject && wantWarning) {
@ -875,7 +877,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
console->LogStringMessage(msg.get());
}
}
if (nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()) {
if (ioLayerHelpers.treatUnsafeNegotiationAsBroken()) {
secStatus = nsIWebProgressListener::STATE_IS_BROKEN;
}
}

View File

@ -31,6 +31,8 @@
#include "nsIPrompt.h"
#include "nsThreadUtils.h"
#include "ScopedNSSTypes.h"
#include "nsIObserverService.h"
#include "nsRecentBadCerts.h"
#include "nspr.h"
#include "certdb.h"
@ -1644,3 +1646,22 @@ nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval)
NS_ADDREF(*_retval);
return NS_OK;
}
NS_IMETHODIMP
nsNSSCertificateDB::GetRecentBadCerts(bool isPrivate, nsIRecentBadCerts** result)
{
MOZ_ASSERT(NS_IsMainThread(), "RecentBadCerts should only be obtained on the main thread");
if (isPrivate) {
if (!mPrivateRecentBadCerts) {
mPrivateRecentBadCerts = new nsRecentBadCerts;
mPrivateRecentBadCerts->InitPrivateBrowsingObserver();
}
NS_ADDREF(*result = mPrivateRecentBadCerts);
} else {
if (!mPublicRecentBadCerts) {
mPublicRecentBadCerts = new nsRecentBadCerts;
}
NS_ADDREF(*result = mPublicRecentBadCerts);
}
return NS_OK;
}

View File

@ -7,10 +7,12 @@
#include "nsIX509CertDB.h"
#include "nsIX509CertDB2.h"
#include "mozilla/RefPtr.h"
#include "certt.h"
class nsCString;
class nsIArray;
class nsRecentBadCerts;
class nsNSSCertificateDB : public nsIX509CertDB, public nsIX509CertDB2
{
@ -48,6 +50,9 @@ private:
uint32_t length);
nsresult handleCACertDownload(nsIArray *x509Certs,
nsIInterfaceRequestor *ctx);
mozilla::RefPtr<nsRecentBadCerts> mPublicRecentBadCerts;
mozilla::RefPtr<nsRecentBadCerts> mPrivateRecentBadCerts;
};
#define NS_X509CERTDB_CID { /* fb0bbc5c-452e-4783-b32c-80124693d871 */ \

View File

@ -60,6 +60,7 @@
#include "nsSmartCardEvent.h"
#include "nsIKeyModule.h"
#include "ScopedNSSTypes.h"
#include "SharedSSLState.h"
#include "nss.h"
#include "pk11func.h"
@ -400,7 +401,7 @@ nsNSSComponent::~nsNSSComponent()
// All cleanup code requiring services needs to happen in xpcom_shutdown
ShutdownNSS();
nsSSLIOLayerHelpers::Cleanup();
SharedSSLState::GlobalCleanup();
RememberCertErrorsTable::Cleanup();
--mInstanceCount;
delete mShutdownObjectList;
@ -1860,9 +1861,6 @@ nsNSSComponent::ShutdownNSS()
ShutdownSmartCardThreads();
SSL_ClearSessionCache();
if (mClientAuthRememberService) {
mClientAuthRememberService->ClearRememberedDecisions();
}
UnloadLoadableRoots();
CleanupIdentityInfo();
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("evaporating psm resources\n"));
@ -1933,27 +1931,8 @@ nsNSSComponent::Init()
}
RememberCertErrorsTable::Init();
nsSSLIOLayerHelpers::Init();
char *unrestricted_hosts=nullptr;
mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
if (unrestricted_hosts) {
nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
nsMemory::Free(unrestricted_hosts);
unrestricted_hosts=nullptr;
}
bool enabled = false;
mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
int32_t warnLevel = 1;
mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
SharedSSLState::GlobalInit();
mClientAuthRememberService = new nsClientAuthRememberService;
if (mClientAuthRememberService)
mClientAuthRememberService->Init();
createBackgroundThreads();
if (!mCertVerificationThread)
{
@ -2271,20 +2250,6 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
} else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
char *unrestricted_hosts=nullptr;
mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
if (unrestricted_hosts) {
nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
nsMemory::Free(unrestricted_hosts);
}
} else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
} else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
int32_t warnLevel = 1;
mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
#ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8
} else if (prefName.Equals("security.ssl.enable_false_start")) {
mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
@ -2387,9 +2352,7 @@ nsresult nsNSSComponent::LogoutAuthenticatedPK11()
0);
}
if (mClientAuthRememberService) {
mClientAuthRememberService->ClearRememberedDecisions();
}
nsClientAuthRememberService::ClearAllRememberedDecisions();
return mShutdownObjectList->doPK11Logout();
}
@ -2568,14 +2531,6 @@ nsNSSComponent::DoProfileChangeNetRestore()
mIsNetworkDown = false;
}
NS_IMETHODIMP
nsNSSComponent::GetClientAuthRememberService(nsClientAuthRememberService **cars)
{
NS_ENSURE_ARG_POINTER(cars);
NS_IF_ADDREF(*cars = mClientAuthRememberService);
return NS_OK;
}
NS_IMETHODIMP
nsNSSComponent::IsNSSInitialized(bool *initialized)
{

View File

@ -154,8 +154,6 @@ class NS_NO_VTABLE nsINSSComponent : public nsISupports {
NS_IMETHOD DispatchEvent(const nsAString &eventType, const nsAString &token) = 0;
NS_IMETHOD GetClientAuthRememberService(nsClientAuthRememberService **cars) = 0;
NS_IMETHOD EnsureIdentityInfoLoaded() = 0;
NS_IMETHOD IsNSSInitialized(bool *initialized) = 0;
@ -259,7 +257,6 @@ public:
NS_IMETHOD ShutdownSmartCardThread(SECMODModule *module);
NS_IMETHOD PostEvent(const nsAString &eventType, const nsAString &token);
NS_IMETHOD DispatchEvent(const nsAString &eventType, const nsAString &token);
NS_IMETHOD GetClientAuthRememberService(nsClientAuthRememberService **cars);
NS_IMETHOD EnsureIdentityInfoLoaded();
NS_IMETHOD IsNSSInitialized(bool *initialized);
@ -327,7 +324,6 @@ private:
nsCertVerificationThread *mCertVerificationThread;
nsNSSHttpInterface mHttpForNSS;
mozilla::RefPtr<nsClientAuthRememberService> mClientAuthRememberService;
mozilla::RefPtr<nsCERTValInParamWrapper> mDefaultCERTValInParam;
mozilla::RefPtr<nsCERTValInParamWrapper> mDefaultCERTValInParamLocalOnly;

View File

@ -28,6 +28,8 @@
#include "nsIConsoleService.h"
#include "PSMRunnable.h"
#include "ScopedNSSTypes.h"
#include "SharedSSLState.h"
#include "mozilla/Preferences.h"
#include "ssl.h"
#include "secerr.h"
@ -63,9 +65,10 @@ typedef enum {ASK, AUTO} SSM_UserCertChoice;
extern PRLogModuleInfo* gPIPNSSLog;
#endif
nsNSSSocketInfo::nsNSSSocketInfo(uint32_t providerFlags)
nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
: mFd(nullptr),
mCertVerificationState(before_cert_verification),
mSharedState(aState),
mForSTARTTLS(false),
mSSL3Enabled(false),
mTLSEnabled(false),
@ -457,6 +460,11 @@ void nsNSSSocketInfo::SetAllowTLSIntoleranceTimeout(bool aAllow)
mAllowTLSIntoleranceTimeout = aAllow;
}
SharedSSLState& nsNSSSocketInfo::SharedState()
{
return mSharedState;
}
bool nsNSSSocketInfo::HandshakeTimeout()
{
if (!mAllowTLSIntoleranceTimeout)
@ -914,7 +922,8 @@ int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
if (!wantRetry // no decision yet
&& isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
{
wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
wantRetry = helpers.rememberPossibleTLSProblemSite(socketInfo);
}
}
@ -942,8 +951,8 @@ int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
if (!wantRetry // no decision yet
&& !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
{
wantRetry =
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
wantRetry = helpers.rememberPossibleTLSProblemSite(socketInfo);
}
}
}
@ -1031,12 +1040,16 @@ nsSSLIOLayerPoll(PRFileDesc * fd, int16_t in_flags, int16_t *out_flags)
bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
Mutex *nsSSLIOLayerHelpers::mutex = nullptr;
nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mTLSIntolerantSites = nullptr;
nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mTLSTolerantSites = nullptr;
nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mRenegoUnrestrictedSites = nullptr;
bool nsSSLIOLayerHelpers::mTreatUnsafeNegotiationAsBroken = false;
int32_t nsSSLIOLayerHelpers::mWarnLevelMissingRFC5746 = 1;
nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
: mutex(nullptr)
, mTLSIntolerantSites(nullptr)
, mTLSTolerantSites(nullptr)
, mRenegoUnrestrictedSites(nullptr)
, mTreatUnsafeNegotiationAsBroken(false)
, mWarnLevelMissingRFC5746(1)
{
}
static int _PSM_InvalidInt(void)
{
@ -1190,6 +1203,53 @@ static int64_t PSMAvailable64(void)
return -1;
}
namespace {
class PrefObserver : public nsIObserver {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
PrefObserver(nsSSLIOLayerHelpers* aOwner) : mOwner(aOwner) {}
virtual ~PrefObserver() {}
private:
nsSSLIOLayerHelpers* mOwner;
};
} // namespace anonymous
NS_IMPL_THREADSAFE_ISUPPORTS1(PrefObserver, nsIObserver)
NS_IMETHODIMP
PrefObserver::Observe(nsISupports *aSubject, const char *aTopic,
const PRUnichar *someData)
{
if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
NS_ConvertUTF16toUTF8 prefName(someData);
if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
nsCString unrestricted_hosts;
Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
if (!unrestricted_hosts.IsEmpty()) {
mOwner->setRenegoUnrestrictedSites(unrestricted_hosts);
}
} else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
bool enabled;
Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
mOwner->setTreatUnsafeNegotiationAsBroken(enabled);
} else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
int32_t warnLevel = 1;
Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
mOwner->setWarnLevelMissingRFC5746(warnLevel);
}
}
return NS_OK;
}
nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers()
{
Preferences::RemoveObserver(mPrefObserver, "security.ssl.renego_unrestricted_hosts");
Preferences::RemoveObserver(mPrefObserver, "security.ssl.treat_unsafe_negotiation_as_broken");
Preferences::RemoveObserver(mPrefObserver, "security.ssl.warn_missing_rfc5746");
}
nsresult nsSSLIOLayerHelpers::Init()
{
if (!nsSSLIOLayerInitialized) {
@ -1244,23 +1304,50 @@ nsresult nsSSLIOLayerHelpers::Init()
mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
mRenegoUnrestrictedSites->Init(1);
mTreatUnsafeNegotiationAsBroken = false;
nsCString unrestricted_hosts;
Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
if (!unrestricted_hosts.IsEmpty()) {
setRenegoUnrestrictedSites(unrestricted_hosts);
}
bool enabled = false;
Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
setTreatUnsafeNegotiationAsBroken(enabled);
int32_t warnLevel = 1;
Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
setWarnLevelMissingRFC5746(warnLevel);
mPrefObserver = new PrefObserver(this);
Preferences::AddStrongObserver(mPrefObserver,
"security.ssl.renego_unrestricted_hosts");
Preferences::AddStrongObserver(mPrefObserver,
"security.ssl.treat_unsafe_negotiation_as_broken");
Preferences::AddStrongObserver(mPrefObserver,
"security.ssl.warn_missing_rfc5746");
return NS_OK;
}
void nsSSLIOLayerHelpers::clearStoredData()
{
mRenegoUnrestrictedSites->Clear();
mTLSTolerantSites->Clear();
mTLSIntolerantSites->Clear();
}
void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
{
MutexAutoLock lock(*mutex);
// Remember intolerant site only if it is not known as tolerant
if (!mTLSTolerantSites->Contains(str))
nsSSLIOLayerHelpers::mTLSIntolerantSites->PutEntry(str);
mTLSIntolerantSites->PutEntry(str);
}
void nsSSLIOLayerHelpers::removeIntolerantSite(const nsCString &str)
{
MutexAutoLock lock(*mutex);
nsSSLIOLayerHelpers::mTLSIntolerantSites->RemoveEntry(str);
mTLSIntolerantSites->RemoveEntry(str);
}
bool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
@ -1923,6 +2010,7 @@ void ClientAuthDataRunnable::RunOnTargetThread()
SSM_UserCertChoice certChoice;
int32_t NumberOfCerts = 0;
void * wincx = mSocketInfo;
nsresult rv;
/* create caNameStrings */
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
@ -2024,19 +2112,14 @@ void ClientAuthDataRunnable::RunOnTargetThread()
nsXPIDLCString hostname;
mSocketInfo->GetHostName(getter_Copies(hostname));
nsresult rv;
NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
RefPtr<nsClientAuthRememberService> cars;
if (nssComponent) {
nssComponent->GetClientAuthRememberService(byRef(cars));
}
RefPtr<nsClientAuthRememberService> cars =
mSocketInfo->SharedState().GetClientAuthRememberService();
bool hasRemembered = false;
nsCString rememberedDBKey;
if (cars) {
bool found;
nsresult rv = cars->HasRememberedDecision(hostname, mServerCert,
rv = cars->HasRememberedDecision(hostname, mServerCert,
rememberedDBKey, &found);
if (NS_SUCCEEDED(rv) && found) {
hasRemembered = true;
@ -2219,9 +2302,9 @@ if (!hasRemembered)
}
/* Throw up the client auth dialog and get back the index of the selected cert */
rv = getNSSDialogs((void**)&dialogs,
NS_GET_IID(nsIClientAuthDialogs),
NS_CLIENTAUTHDIALOGS_CONTRACTID);
nsresult rv = getNSSDialogs((void**)&dialogs,
NS_GET_IID(nsIClientAuthDialogs),
NS_CLIENTAUTHDIALOGS_CONTRACTID);
if (NS_FAILED(rv)) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
@ -2380,7 +2463,7 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, bool forSTARTTLS,
nsAutoCString key;
key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
if (nsSSLIOLayerHelpers::isKnownAsIntolerantSite(key)) {
if (infoObject->SharedState().IOLayerHelpers().isKnownAsIntolerantSite(key)) {
if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, false))
return NS_ERROR_FAILURE;
@ -2407,8 +2490,9 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, bool forSTARTTLS,
if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
return NS_ERROR_FAILURE;
}
if (nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(nsDependentCString(host))) {
nsSSLIOLayerHelpers& ioHelpers = infoObject->SharedState().IOLayerHelpers();
if (ioHelpers.isRenegoUnrestrictedSite(nsDependentCString(host))) {
if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, false)) {
return NS_ERROR_FAILURE;
}
@ -2450,7 +2534,9 @@ nsSSLIOLayerAddToSocket(int32_t family,
nsresult rv;
PRStatus stat;
nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(providerFlags);
SharedSSLState* sharedState =
providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ? PrivateSSLState() : PublicSSLState();
nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags);
if (!infoObject) return NS_ERROR_FAILURE;
NS_ADDREF(infoObject);

View File

@ -15,12 +15,20 @@
#include "nsTHashtable.h"
#include "mozilla/TimeStamp.h"
namespace mozilla {
namespace psm {
class SharedSSLState;
}
}
class nsIObserver;
class nsNSSSocketInfo : public mozilla::psm::TransportSecurityInfo,
public nsISSLSocketControl,
public nsIClientAuthUserDecision
{
public:
nsNSSSocketInfo(uint32_t providerFlags);
nsNSSSocketInfo(mozilla::psm::SharedSSLState& aState, uint32_t providerFlags);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSISSLSOCKETCONTROL
@ -56,6 +64,8 @@ public:
bool GetJoined() { return mJoined; }
void SetSentClientCert() { mSentClientCert = true; }
mozilla::psm::SharedSSLState& SharedState();
// XXX: These are only used on for diagnostic purposes
enum CertVerificationState {
before_cert_verification,
@ -83,6 +93,7 @@ private:
CertVerificationState mCertVerificationState;
mozilla::psm::SharedSSLState& mSharedState;
bool mForSTARTTLS;
bool mSSL3Enabled;
bool mTLSEnabled;
@ -109,37 +120,44 @@ private:
class nsSSLIOLayerHelpers
{
public:
static nsresult Init();
static void Cleanup();
nsSSLIOLayerHelpers();
~nsSSLIOLayerHelpers();
nsresult Init();
void Cleanup();
static bool nsSSLIOLayerInitialized;
static PRDescIdentity nsSSLIOLayerIdentity;
static PRIOMethods nsSSLIOLayerMethods;
static mozilla::Mutex *mutex;
static nsTHashtable<nsCStringHashKey> *mTLSIntolerantSites;
static nsTHashtable<nsCStringHashKey> *mTLSTolerantSites;
mozilla::Mutex *mutex;
nsTHashtable<nsCStringHashKey> *mTLSIntolerantSites;
nsTHashtable<nsCStringHashKey> *mTLSTolerantSites;
static nsTHashtable<nsCStringHashKey> *mRenegoUnrestrictedSites;
static bool mTreatUnsafeNegotiationAsBroken;
static int32_t mWarnLevelMissingRFC5746;
nsTHashtable<nsCStringHashKey> *mRenegoUnrestrictedSites;
bool mTreatUnsafeNegotiationAsBroken;
int32_t mWarnLevelMissingRFC5746;
static void setTreatUnsafeNegotiationAsBroken(bool broken);
static bool treatUnsafeNegotiationAsBroken();
void setTreatUnsafeNegotiationAsBroken(bool broken);
bool treatUnsafeNegotiationAsBroken();
static void setWarnLevelMissingRFC5746(int32_t level);
static int32_t getWarnLevelMissingRFC5746();
void setWarnLevelMissingRFC5746(int32_t level);
int32_t getWarnLevelMissingRFC5746();
static void getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key);
static bool rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo);
static void rememberTolerantSite(nsNSSSocketInfo *socketInfo);
bool rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo);
void rememberTolerantSite(nsNSSSocketInfo *socketInfo);
static void addIntolerantSite(const nsCString &str);
static void removeIntolerantSite(const nsCString &str);
static bool isKnownAsIntolerantSite(const nsCString &str);
void addIntolerantSite(const nsCString &str);
void removeIntolerantSite(const nsCString &str);
bool isKnownAsIntolerantSite(const nsCString &str);
static void setRenegoUnrestrictedSites(const nsCString &str);
static bool isRenegoUnrestrictedSite(const nsCString &str);
void setRenegoUnrestrictedSites(const nsCString &str);
bool isRenegoUnrestrictedSite(const nsCString &str);
void clearStoredData();
private:
nsCOMPtr<nsIObserver> mPrefObserver;
};
nsresult nsSSLIOLayerNewSocket(int32_t family,

View File

@ -38,7 +38,6 @@
#include "nsDataSignatureVerifier.h"
#include "nsCertOverrideService.h"
#include "nsRandomGenerator.h"
#include "nsRecentBadCerts.h"
#include "nsSSLStatus.h"
#include "TransportSecurityInfo.h"
#include "NSSErrorsService.h"
@ -204,7 +203,6 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObjectFactory)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsDataSignatureVerifier)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsCertOverrideService, Init)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsRandomGenerator)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsRecentBadCertsService, Init)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, nsSSLStatus)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, TransportSecurityInfo)
@ -243,7 +241,6 @@ NS_DEFINE_NAMED_CID(NS_KEYMODULEOBJECTFACTORY_CID);
NS_DEFINE_NAMED_CID(NS_DATASIGNATUREVERIFIER_CID);
NS_DEFINE_NAMED_CID(NS_CERTOVERRIDE_CID);
NS_DEFINE_NAMED_CID(NS_RANDOMGENERATOR_CID);
NS_DEFINE_NAMED_CID(NS_RECENTBADCERTS_CID);
NS_DEFINE_NAMED_CID(NS_SSLSTATUS_CID);
NS_DEFINE_NAMED_CID(TRANSPORTSECURITYINFO_CID);
NS_DEFINE_NAMED_CID(NS_NSSERRORSSERVICE_CID);
@ -281,7 +278,6 @@ static const mozilla::Module::CIDEntry kNSSCIDs[] = {
{ &kNS_DATASIGNATUREVERIFIER_CID, false, nullptr, nsDataSignatureVerifierConstructor },
{ &kNS_CERTOVERRIDE_CID, false, nullptr, nsCertOverrideServiceConstructor },
{ &kNS_RANDOMGENERATOR_CID, false, nullptr, nsRandomGeneratorConstructor },
{ &kNS_RECENTBADCERTS_CID, false, nullptr, nsRecentBadCertsServiceConstructor },
{ &kNS_SSLSTATUS_CID, false, nullptr, nsSSLStatusConstructor },
{ &kTRANSPORTSECURITYINFO_CID, false, nullptr, TransportSecurityInfoConstructor },
{ &kNS_NSSERRORSSERVICE_CID, false, nullptr, NSSErrorsServiceConstructor },
@ -324,7 +320,6 @@ static const mozilla::Module::ContractIDEntry kNSSContracts[] = {
{ NS_DATASIGNATUREVERIFIER_CONTRACTID, &kNS_DATASIGNATUREVERIFIER_CID },
{ NS_CERTOVERRIDE_CONTRACTID, &kNS_CERTOVERRIDE_CID },
{ NS_RANDOMGENERATOR_CONTRACTID, &kNS_RANDOMGENERATOR_CID },
{ NS_RECENTBADCERTS_CONTRACTID, &kNS_RECENTBADCERTS_CID },
{ nullptr }
};

View File

@ -6,7 +6,9 @@
#include "nsRecentBadCerts.h"
#include "nsIX509Cert.h"
#include "nsIObserverService.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Services.h"
#include "nsSSLStatus.h"
#include "nsCOMPtr.h"
#include "nsNSSCertificate.h"
@ -20,28 +22,41 @@
using namespace mozilla;
NS_IMPL_THREADSAFE_ISUPPORTS1(nsRecentBadCertsService,
nsIRecentBadCertsService)
NS_IMPL_THREADSAFE_ISUPPORTS2(nsRecentBadCerts,
nsIRecentBadCerts,
nsIObserver)
nsRecentBadCertsService::nsRecentBadCertsService()
:monitor("nsRecentBadCertsService.monitor")
nsRecentBadCerts::nsRecentBadCerts()
:monitor("nsRecentBadCerts.monitor")
,mNextStorePosition(0)
{
}
nsRecentBadCertsService::~nsRecentBadCertsService()
nsRecentBadCerts::~nsRecentBadCerts()
{
}
nsresult
nsRecentBadCertsService::Init()
void
nsRecentBadCerts::InitPrivateBrowsingObserver()
{
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
obsSvc->AddObserver(this, "last-pb-context-exited", false);
}
NS_IMETHODIMP
nsRecentBadCerts::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
ResetStoredCerts();
}
return NS_OK;
}
NS_IMETHODIMP
nsRecentBadCertsService::GetRecentBadCert(const nsAString & aHostNameWithPort,
nsISSLStatus **aStatus)
nsRecentBadCerts::GetRecentBadCert(const nsAString & aHostNameWithPort,
nsISSLStatus **aStatus)
{
NS_ENSURE_ARG_POINTER(aStatus);
if (!aHostNameWithPort.Length())
@ -101,7 +116,7 @@ nsRecentBadCertsService::GetRecentBadCert(const nsAString & aHostNameWithPort,
}
NS_IMETHODIMP
nsRecentBadCertsService::AddBadCert(const nsAString &hostWithPort,
nsRecentBadCerts::AddBadCert(const nsAString &hostWithPort,
nsISSLStatus *aStatus)
{
NS_ENSURE_ARG(aStatus);
@ -146,3 +161,13 @@ nsRecentBadCertsService::AddBadCert(const nsAString &hostWithPort,
return NS_OK;
}
NS_IMETHODIMP
nsRecentBadCerts::ResetStoredCerts()
{
for (size_t i = 0; i < const_recently_seen_list_size; ++i) {
RecentBadCert &entry = mCerts[i];
entry.Clear();
}
return NS_OK;
}

View File

@ -11,6 +11,7 @@
#include "mozilla/ReentrantMonitor.h"
#include "nsIRecentBadCertsService.h"
#include "nsIObserver.h"
#include "nsTHashtable.h"
#include "nsString.h"
#include "cert.h"
@ -54,16 +55,18 @@ private:
RecentBadCert &operator=(const RecentBadCert &other) MOZ_DELETE;
};
class nsRecentBadCertsService MOZ_FINAL : public nsIRecentBadCertsService
class nsRecentBadCerts MOZ_FINAL : public nsIRecentBadCerts
, public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRECENTBADCERTSSERVICE
NS_DECL_NSIRECENTBADCERTS
NS_DECL_NSIOBSERVER
nsRecentBadCertsService();
~nsRecentBadCertsService();
nsRecentBadCerts();
~nsRecentBadCerts();
nsresult Init();
void InitPrivateBrowsingObserver();
protected:
mozilla::ReentrantMonitor monitor;