diff --git a/netwerk/base/public/security-prefs.js b/netwerk/base/public/security-prefs.js index e03792562d39..43571dc9bcfd 100644 --- a/netwerk/base/public/security-prefs.js +++ b/netwerk/base/public/security-prefs.js @@ -13,6 +13,7 @@ pref("security.ssl.treat_unsafe_negotiation_as_broken", false); pref("security.ssl.require_safe_negotiation", false); pref("security.ssl.warn_missing_rfc5746", 1); pref("security.ssl.enable_false_start", false); +pref("security.ssl.enable_ocsp_stapling", true); pref("security.ssl3.rsa_rc4_128_md5", true); pref("security.ssl3.rsa_rc4_128_sha", true); diff --git a/security/manager/ssl/src/SSLServerCertVerification.cpp b/security/manager/ssl/src/SSLServerCertVerification.cpp index c112a25d5498..185f022c2267 100644 --- a/security/manager/ssl/src/SSLServerCertVerification.cpp +++ b/security/manager/ssl/src/SSLServerCertVerification.cpp @@ -120,6 +120,7 @@ #include "secerr.h" #include "secport.h" #include "sslerr.h" +#include "ocsp.h" #ifdef PR_LOGGING extern PRLogModuleInfo* gPIPNSSLog; @@ -443,7 +444,8 @@ CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport, TransportSecurityInfo * infoObject, CERTCertificate * cert, const void * fdForLogging, - uint32_t providerFlags) + uint32_t providerFlags, + PRTime now) { MOZ_ASSERT(infoObject); MOZ_ASSERT(cert); @@ -476,8 +478,6 @@ CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport, return nullptr; } - PRTime now = PR_Now(); - PLArenaPool *log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); PLArenaPoolCleanerFalseParam log_arena_cleaner(log_arena); if (!log_arena) { @@ -1085,7 +1085,7 @@ SSLServerCertVerificationJob::Run() } if (error != 0) { RefPtr runnable(CreateCertErrorRunnable( - error, mInfoObject, mCert, mFdForLogging, mProviderFlags)); + error, mInfoObject, mCert, mFdForLogging, mProviderFlags, PR_Now())); if (!runnable) { // CreateCertErrorRunnable set a new error code error = PR_GetError(); @@ -1161,7 +1161,28 @@ AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) PR_SetError(PR_INVALID_STATE_ERROR, 0); return SECFailure; } - + + // This value of "now" is used both here for OCSP stapling and later + // when calling CreateCertErrorRunnable. + PRTime now = PR_Now(); + PRBool enabled; + if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_OCSP_STAPLING, &enabled)) { + return SECFailure; + } + if (enabled) { + // no ownership + const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd); + // we currently only support single stapled responses + if (csa && csa->len == 1) { + CERTCertDBHandle *handle = CERT_GetDefaultCertDB(); + SECStatus cacheResult = CERT_CacheOCSPResponseFromSideChannel( + handle, serverCert, now, &csa->items[0], arg); + if (cacheResult != SECSuccess) { + return SECFailure; + } + } + } + if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess) return SECFailure; @@ -1208,7 +1229,7 @@ AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) if (error != 0) { RefPtr runnable(CreateCertErrorRunnable( error, socketInfo, serverCert, - static_cast(fd), providerFlags)); + static_cast(fd), providerFlags, now)); if (!runnable) { // CreateCertErrorRunnable sets a new error code when it fails error = PR_GetError(); diff --git a/security/manager/ssl/src/SharedSSLState.cpp b/security/manager/ssl/src/SharedSSLState.cpp index 01415c7a1135..69b83053ff92 100644 --- a/security/manager/ssl/src/SharedSSLState.cpp +++ b/security/manager/ssl/src/SharedSSLState.cpp @@ -133,6 +133,7 @@ SharedSSLState::SharedSSLState() : mClientAuthRemember(new nsClientAuthRememberService) , mMutex("SharedSSLState::mMutex") , mSocketCreated(false) +, mOCSPStaplingEnabled(false) { mIOLayerHelpers.Init(); mClientAuthRemember->Init(); diff --git a/security/manager/ssl/src/SharedSSLState.h b/security/manager/ssl/src/SharedSSLState.h index d9266d5ba42d..57f4d4fa07ff 100644 --- a/security/manager/ssl/src/SharedSSLState.h +++ b/security/manager/ssl/src/SharedSSLState.h @@ -36,12 +36,14 @@ public: // Main-thread only void ResetStoredData(); void NotePrivateBrowsingStatus(); + void SetOCSPStaplingEnabled(bool enabled) { mOCSPStaplingEnabled = enabled; } // The following methods may be called from any thread bool SocketCreated(); void NoteSocketCreated(); static void NoteCertOverrideServiceInstantiated(); static void NoteCertDBServiceInstantiated(); + bool IsOCSPStaplingEnabled() const { return mOCSPStaplingEnabled; } private: void Cleanup(); @@ -55,6 +57,7 @@ private: // reading/writing. Mutex mMutex; bool mSocketCreated; + bool mOCSPStaplingEnabled; }; SharedSSLState* PublicSSLState(); diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp index 0e5630fca733..4f6ad873883b 100644 --- a/security/manager/ssl/src/nsNSSComponent.cpp +++ b/security/manager/ssl/src/nsNSSComponent.cpp @@ -984,6 +984,7 @@ setNonPkixOcspEnabled(int32_t ocspEnabled, nsIPrefBranch * pref) #define MISSING_CERT_DOWNLOAD_DEFAULT false #define FIRST_REVO_METHOD_DEFAULT "ocsp" #define USE_NSS_LIBPKIX_DEFAULT false +#define OCSP_STAPLING_ENABLED_DEFAULT true // Caller must hold a lock on nsNSSComponent::mutex when calling this function void nsNSSComponent::setValidationOptions(nsIPrefBranch * pref) @@ -1022,6 +1023,17 @@ void nsNSSComponent::setValidationOptions(nsIPrefBranch * pref) rv = pref->GetCharPref("security.first_network_revocation_method", getter_Copies(firstNetworkRevo)); if (NS_FAILED(rv)) firstNetworkRevo = FIRST_REVO_METHOD_DEFAULT; + + bool ocspStaplingEnabled; + rv = pref->GetBoolPref("security.ssl.enable_ocsp_stapling", &ocspStaplingEnabled); + if (NS_FAILED(rv)) { + ocspStaplingEnabled = OCSP_STAPLING_ENABLED_DEFAULT; + } + if (!ocspEnabled) { + ocspStaplingEnabled = false; + } + PublicSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled); + PrivateSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled); setNonPkixOcspEnabled(ocspEnabled, pref); @@ -1550,6 +1562,8 @@ nsNSSComponent::InitializeNSS(bool showWarningBox) PK11_SetPasswordFunc(PK11PasswordPrompt); + SharedSSLState::GlobalInit(); + // Register an observer so we can inform NSS when these prefs change mPrefBranch->AddObserver("security.", this, false); @@ -1742,7 +1756,6 @@ nsNSSComponent::Init() } RememberCertErrorsTable::Init(); - SharedSSLState::GlobalInit(); createBackgroundThreads(); if (!mCertVerificationThread) @@ -2042,7 +2055,8 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic, || prefName.Equals("security.fresh_revocation_info.require") || prefName.Equals("security.missing_cert_download.enabled") || prefName.Equals("security.first_network_revocation_method") - || prefName.Equals("security.OCSP.require")) { + || prefName.Equals("security.OCSP.require") + || prefName.Equals("security.ssl.enable_ocsp_stapling")) { MutexAutoLock lock(mutex); setValidationOptions(mPrefBranch); } else if (prefName.Equals("network.ntlm.send-lm-response")) { diff --git a/security/manager/ssl/src/nsNSSIOLayer.cpp b/security/manager/ssl/src/nsNSSIOLayer.cpp index efd71176e953..29e28aa5e628 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -2552,6 +2552,11 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, bool forSTARTTLS, } infoObject->SetTLSEnabled(enabled); + enabled = infoObject->SharedState().IsOCSPStaplingEnabled(); + if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_OCSP_STAPLING, enabled)) { + return NS_ERROR_FAILURE; + } + if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) { return NS_ERROR_FAILURE; }