From 1d40d354bd5ebd908f9c0c1176cea39571f83db9 Mon Sep 17 00:00:00 2001 From: Dragana Damjanovic Date: Wed, 25 Sep 2019 20:23:56 +0000 Subject: [PATCH] Bug 1577643 - Implement a security info class for the quic transport. r=keeler Differential Revision: https://phabricator.services.mozilla.com/D44073 --HG-- extra : moz-landing-system : lando --- netwerk/protocol/http/QuicSocketControl.cpp | 104 +++++++ netwerk/protocol/http/QuicSocketControl.h | 59 ++++ netwerk/protocol/http/moz.build | 1 + security/manager/ssl/CommonSocketControl.cpp | 277 +++++++++++++++++++ security/manager/ssl/CommonSocketControl.h | 40 +++ security/manager/ssl/TransportSecurityInfo.h | 2 +- security/manager/ssl/moz.build | 3 + security/manager/ssl/nsNSSCallbacks.cpp | 8 +- security/manager/ssl/nsNSSCallbacks.h | 6 + security/manager/ssl/nsNSSIOLayer.cpp | 181 +----------- security/manager/ssl/nsNSSIOLayer.h | 40 +-- 11 files changed, 519 insertions(+), 202 deletions(-) create mode 100644 netwerk/protocol/http/QuicSocketControl.cpp create mode 100644 netwerk/protocol/http/QuicSocketControl.h create mode 100644 security/manager/ssl/CommonSocketControl.cpp create mode 100644 security/manager/ssl/CommonSocketControl.h diff --git a/netwerk/protocol/http/QuicSocketControl.cpp b/netwerk/protocol/http/QuicSocketControl.cpp new file mode 100644 index 000000000000..481a4b4038c3 --- /dev/null +++ b/netwerk/protocol/http/QuicSocketControl.cpp @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 "QuicSocketControl.h" +#include "SharedCertVerifier.h" +#include "nsNSSComponent.h" +#include "nsWeakReference.h" +#include "sslt.h" +#include "ssl.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ISUPPORTS_INHERITED(QuicSocketControl, TransportSecurityInfo, + nsISSLSocketControl, QuicSocketControl) + +QuicSocketControl::QuicSocketControl(uint32_t aProviderFlags) + : CommonSocketControl(aProviderFlags) {} + +void QuicSocketControl::SetCertVerificationResult(PRErrorCode errorCode) { + if (errorCode) { + mFailedVerification = true; + SetCanceled(errorCode); + } + + if (OnSocketThread()) { + CallAuthenticated(); + } else { + DebugOnly rv = gSocketTransportService->Dispatch( + NewRunnableMethod("QuicSocketControl::CallAuthenticated", this, + &QuicSocketControl::CallAuthenticated), + NS_DISPATCH_NORMAL); + } +} + +NS_IMETHODIMP +QuicSocketControl::GetSSLVersionOffered(int16_t* aSSLVersionOffered) { + *aSSLVersionOffered = nsISSLSocketControl::TLS_VERSION_1_3; + return NS_OK; +} + +void QuicSocketControl::CallAuthenticated() { + // // Will be added when Http3 lands + /* if (mHttp3Session) { + RefPtr http3Session = do_QueryReferent(mHttp3Session); + http3Session->Authenticated(GetErrorCode()); + } + mHttp3Session = nullptr;*/ +} + +// Will be added when Http3 lands +// void QuicSocketControl::SetAuthenticationCallback(Http3Session +// *aHttp3Session) { +// mHttp3Session = do_GetWeakReference( +// static_cast(aHttp3Session)); +//} + +void QuicSocketControl::HandshakeCompleted() { + psm::RememberCertErrorsTable::GetInstance().LookupCertErrorBits(this); + + uint32_t state = nsIWebProgressListener::STATE_IS_SECURE; + + bool distrustImminent; + nsresult srv = + IsCertificateDistrustImminent(mSucceededCertChain, distrustImminent); + if (NS_SUCCEEDED(srv) && distrustImminent) { + state |= nsIWebProgressListener::STATE_CERT_DISTRUST_IMMINENT; + } + + // If we're here, the TLS handshake has succeeded. Thus if any of these + // booleans are true, the user has added an override for a certificate error. + if (mIsDomainMismatch || mIsUntrusted || mIsNotValidAtThisTime) { + state |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN; + } + + SetSecurityState(state); + mHandshakeCompleted = true; +} + +void QuicSocketControl::SetNegotiatedNPN(const nsACString& aValue) { + mNegotiatedNPN = aValue; + mNPNCompleted = true; +} + +void QuicSocketControl::SetInfo(uint16_t aCipherSuite, + uint16_t aProtocolVersion, + uint16_t aKeaGroup, + uint16_t aSignatureScheme) { + SSLCipherSuiteInfo cipherInfo; + if (SSL_GetCipherSuiteInfo(aCipherSuite, &cipherInfo, sizeof cipherInfo) == + SECSuccess) { + mHaveCipherSuiteAndProtocol = true; + mCipherSuite = aCipherSuite; + mProtocolVersion = aProtocolVersion & 0xFF; + mKeaGroup = getKeaGroupName(aKeaGroup); + mSignatureSchemeName = getSignatureName(aSignatureScheme); + } +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/QuicSocketControl.h b/netwerk/protocol/http/QuicSocketControl.h new file mode 100644 index 000000000000..e7f69137e9ea --- /dev/null +++ b/netwerk/protocol/http/QuicSocketControl.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 QuicSocketControl_h +#define QuicSocketControl_h + +#include "CommonSocketControl.h" + +namespace mozilla { +namespace net { + +// Will be added when Http3 lands. +// class Http3Session; + +// IID for the QuicSocketControl interface +#define NS_QUICSOCKETCONTROL_IID \ + { \ + 0xdbc67fd0, 0x1ac6, 0x457b, { \ + 0x91, 0x4e, 0x4c, 0x86, 0x60, 0xff, 0x00, 0x69 \ + } \ + } + +class QuicSocketControl final : public CommonSocketControl { + public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_QUICSOCKETCONTROL_IID) + + NS_DECL_ISUPPORTS_INHERITED + + NS_IMETHOD GetSSLVersionOffered(int16_t* aSSLVersionOffered) override; + + explicit QuicSocketControl(uint32_t providerFlags); + + void SetNegotiatedNPN(const nsACString& aValue); + void SetInfo(uint16_t aCipherSuite, uint16_t aProtocolVersion, + uint16_t aKeaGroup, uint16_t aSignatureScheme); + + // Will be added when Http3 lands. + // void SetAuthenticationCallback(Http3Session *aHttp3Session); + void CallAuthenticated(); + + void HandshakeCompleted(); + void SetCertVerificationResult(PRErrorCode errorCode) override; + + private: + ~QuicSocketControl() = default; + + // For Authentication done callback. + nsWeakPtr mHttp3Session; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(QuicSocketControl, NS_QUICSOCKETCONTROL_IID) + +} // namespace net +} // namespace mozilla + +#endif // QuicSocketControl_h diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build index 64e21578775b..568a3b4a678e 100644 --- a/netwerk/protocol/http/moz.build +++ b/netwerk/protocol/http/moz.build @@ -108,6 +108,7 @@ UNIFIED_SOURCES += [ 'NullHttpChannel.cpp', 'NullHttpTransaction.cpp', 'ParentChannelListener.cpp', + 'QuicSocketControl.cpp', 'TunnelUtils.cpp', ] diff --git a/security/manager/ssl/CommonSocketControl.cpp b/security/manager/ssl/CommonSocketControl.cpp new file mode 100644 index 000000000000..92f48d611227 --- /dev/null +++ b/security/manager/ssl/CommonSocketControl.cpp @@ -0,0 +1,277 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 "CommonSocketControl.h" +#include "SharedCertVerifier.h" +#include "nsNSSComponent.h" +#include "sslt.h" +#include "ssl.h" + +using namespace mozilla; + +NS_IMPL_ISUPPORTS_INHERITED(CommonSocketControl, TransportSecurityInfo, + nsISSLSocketControl) + +CommonSocketControl::CommonSocketControl(uint32_t aProviderFlags) + : mNPNCompleted(false), + mHandshakeCompleted(false), + mJoined(false), + mSentClientCert(false), + mFailedVerification(false), + mResumed(false), + mSSLVersionUsed(nsISSLSocketControl::SSL_VERSION_UNKNOWN), + mProviderFlags(aProviderFlags) {} + +NS_IMETHODIMP +CommonSocketControl::GetNotificationCallbacks( + nsIInterfaceRequestor** aCallbacks) { + *aCallbacks = mCallbacks; + NS_IF_ADDREF(*aCallbacks); + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::SetNotificationCallbacks( + nsIInterfaceRequestor* aCallbacks) { + mCallbacks = aCallbacks; + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::ProxyStartSSL(void) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::StartTLS(void) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::SetNPNList(nsTArray & aNPNList) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::GetNegotiatedNPN(nsACString& aNegotiatedNPN) { + if (!mNPNCompleted) { + return NS_ERROR_NOT_CONNECTED; + } + + aNegotiatedNPN = mNegotiatedNPN; + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::GetAlpnEarlySelection(nsACString& _retval) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::GetEarlyDataAccepted(bool *aEarlyDataAccepted) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::DriveHandshake(void) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::JoinConnection(const nsACString& npnProtocol, + const nsACString& hostname, int32_t port, + bool* _retval) { + nsresult rv = TestJoinConnection(npnProtocol, hostname, port, _retval); + if (NS_SUCCEEDED(rv) && *_retval) { + // All tests pass - this is joinable + mJoined = true; + } + return rv; +} + +NS_IMETHODIMP +CommonSocketControl::TestJoinConnection(const nsACString& npnProtocol, + const nsACString& hostname, + int32_t port, bool* _retval) { + *_retval = false; + + // Different ports may not be joined together + if (port != GetPort()) return NS_OK; + + // Make sure NPN has been completed and matches requested npnProtocol + if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol)) return NS_OK; + + IsAcceptableForHost(hostname, _retval); // sets _retval + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::IsAcceptableForHost(const nsACString& hostname, + bool* _retval) { + NS_ENSURE_ARG(_retval); + + *_retval = false; + + // If this is the same hostname then the certicate status does not + // need to be considered. They are joinable. + if (hostname.Equals(GetHostName())) { + *_retval = true; + return NS_OK; + } + + // Before checking the server certificate we need to make sure the + // handshake has completed. + if (!mHandshakeCompleted || !HasServerCert()) { + return NS_OK; + } + + // If the cert has error bits (e.g. it is untrusted) then do not join. + // The value of mHaveCertErrorBits is only reliable because we know that + // the handshake completed. + if (mHaveCertErrorBits) { + return NS_OK; + } + + // If the connection is using client certificates then do not join + // because the user decides on whether to send client certs to hosts on a + // per-domain basis. + if (mSentClientCert) return NS_OK; + + // Ensure that the server certificate covers the hostname that would + // like to join this connection + + UniqueCERTCertificate nssCert; + + nsCOMPtr cert; + if (NS_FAILED(GetServerCert(getter_AddRefs(cert)))) { + return NS_OK; + } + if (cert) { + nssCert.reset(cert->GetCert()); + } + + if (!nssCert) { + return NS_OK; + } + + // Attempt to verify the joinee's certificate using the joining hostname. + // This ensures that any hostname-specific verification logic (e.g. key + // pinning) is satisfied by the joinee's certificate chain. + // This verification only uses local information; since we're on the network + // thread, we would be blocking on ourselves if we attempted any network i/o. + // TODO(bug 1056935): The certificate chain built by this verification may be + // different than the certificate chain originally built during the joined + // connection's TLS handshake. Consequently, we may report a wrong and/or + // misleading certificate chain for HTTP transactions coalesced onto this + // connection. This may become problematic in the future. For example, + // if/when we begin relying on intermediate certificates being stored in the + // securityInfo of a cached HTTPS response, that cached certificate chain may + // actually be the wrong chain. We should consider having JoinConnection + // return the certificate chain built here, so that the calling Necko code + // can associate the correct certificate chain with the HTTP transactions it + // is trying to join onto this connection. + RefPtr certVerifier(psm::GetDefaultCertVerifier()); + if (!certVerifier) { + return NS_OK; + } + psm::CertVerifier::Flags flags = psm::CertVerifier::FLAG_LOCAL_ONLY; + UniqueCERTCertList unusedBuiltChain; + mozilla::pkix::Result result = certVerifier->VerifySSLServerCert( + nssCert, + Maybe>(), // stapledOCSPResponse + Maybe>(), // sctsFromTLSExtension + mozilla::pkix::Now(), + nullptr, // pinarg + hostname, unusedBuiltChain, + false, // save intermediates + flags); + if (result != mozilla::pkix::Success) { + return NS_OK; + } + + // All tests pass + *_retval = true; + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::GetKEAUsed(int16_t *aKEAUsed) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::GetKEAKeyBits(uint32_t *aKEAKeyBits) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::GetProviderFlags(uint32_t* aProviderFlags) { + *aProviderFlags = mProviderFlags; + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::GetProviderTlsFlags(uint32_t *aProviderTlsFlags) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::GetSSLVersionUsed(int16_t* aSSLVersionUsed) { + *aSSLVersionUsed = mSSLVersionUsed; + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::GetSSLVersionOffered(int16_t* aSSLVersionOffered) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::GetMACAlgorithmUsed(int16_t *aMACAlgorithmUsed) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +bool CommonSocketControl::GetDenyClientCert() { return true; } + +void CommonSocketControl::SetDenyClientCert(bool aDenyClientCert) {} + +NS_IMETHODIMP +CommonSocketControl::GetClientCert(nsIX509Cert **aClientCert) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::SetClientCert(nsIX509Cert *aClientCert) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::GetClientCertSent(bool* arg) { + *arg = mSentClientCert; + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::GetFailedVerification(bool* arg) { + *arg = mFailedVerification; + return NS_OK; +} + +NS_IMETHODIMP +CommonSocketControl::GetEsniTxt(nsACString& aEsniTxt) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::SetEsniTxt(const nsACString& aEsniTxt) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +CommonSocketControl::GetResumed(bool* aResumed) { + *aResumed = mResumed; + return NS_OK; +} diff --git a/security/manager/ssl/CommonSocketControl.h b/security/manager/ssl/CommonSocketControl.h new file mode 100644 index 000000000000..9dc6726f2655 --- /dev/null +++ b/security/manager/ssl/CommonSocketControl.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 CommonSocketControl_h +#define CommonSocketControl_h + +#include "nsISSLSocketControl.h" +#include "TransportSecurityInfo.h" + +class CommonSocketControl : public mozilla::psm::TransportSecurityInfo, + public nsISSLSocketControl { + public: + + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSISSLSOCKETCONTROL + + explicit CommonSocketControl(uint32_t providerFlags); + + uint32_t GetProviderFlags() const { return mProviderFlags; } + void SetSSLVersionUsed(int16_t version) { mSSLVersionUsed = version; } + void SetResumed(bool aResumed) { mResumed = aResumed; } + + protected: + ~CommonSocketControl() = default; + nsCString mNegotiatedNPN; + bool mNPNCompleted; + bool mHandshakeCompleted; + bool mJoined; + bool mSentClientCert; + bool mFailedVerification; + mozilla::Atomic mResumed; + uint16_t mSSLVersionUsed; + uint32_t mProviderFlags; +}; + +#endif // CommonSocketControl_h diff --git a/security/manager/ssl/TransportSecurityInfo.h b/security/manager/ssl/TransportSecurityInfo.h index bc9146fd0ab9..2ef9779367db 100644 --- a/security/manager/ssl/TransportSecurityInfo.h +++ b/security/manager/ssl/TransportSecurityInfo.h @@ -116,6 +116,7 @@ class TransportSecurityInfo : public nsITransportSecurityInfo, protected: nsCOMPtr mCallbacks; + nsCOMPtr mSucceededCertChain; private: uint32_t mSecurityState; @@ -127,7 +128,6 @@ class TransportSecurityInfo : public nsITransportSecurityInfo, OriginAttributes mOriginAttributes; nsCOMPtr mServerCert; - nsCOMPtr mSucceededCertChain; /* Peer cert chain for failed connections (for error reporting) */ nsCOMPtr mFailedCertChain; diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build index 3e88751043fd..be1d75fcedcc 100644 --- a/security/manager/ssl/moz.build +++ b/security/manager/ssl/moz.build @@ -59,6 +59,7 @@ EXTRA_JS_MODULES.psm += [ ] EXPORTS += [ + 'CommonSocketControl.h', 'CryptoTask.h', 'EnterpriseRoots.h', 'nsClientAuthRemember.h', @@ -74,6 +75,7 @@ EXPORTS += [ 'RootCertificateTelemetryUtils.h', 'ScopedNSSTypes.h', 'SharedCertVerifier.h', + 'TransportSecurityInfo.h', ] EXPORTS.mozilla += [ @@ -92,6 +94,7 @@ EXPORTS.ipc += [ ] UNIFIED_SOURCES += [ + 'CommonSocketControl.cpp', 'ContentSignatureVerifier.cpp', 'CryptoTask.cpp', 'CSTrustDomain.cpp', diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp index 4978e97fa005..f4d8ad3250d3 100644 --- a/security/manager/ssl/nsNSSCallbacks.cpp +++ b/security/manager/ssl/nsNSSCallbacks.cpp @@ -594,7 +594,7 @@ char* PK11PasswordPrompt(PK11SlotInfo* slot, PRBool /*retry*/, void* arg) { return runnable->mResult; } -static nsCString getKeaGroupName(uint32_t aKeaGroup) { +nsCString getKeaGroupName(uint32_t aKeaGroup) { nsCString groupName; switch (aKeaGroup) { case ssl_grp_ec_secp256r1: @@ -631,7 +631,7 @@ static nsCString getKeaGroupName(uint32_t aKeaGroup) { return groupName; } -static nsCString getSignatureName(uint32_t aSignatureScheme) { +nsCString getSignatureName(uint32_t aSignatureScheme) { nsCString signatureName; switch (aSignatureScheme) { case ssl_sig_none: @@ -1107,8 +1107,8 @@ static void RebuildVerifiedCertificateInformation(PRFileDesc* fd, } } -static nsresult IsCertificateDistrustImminent(nsIX509CertList* aCertList, - /* out */ bool& isDistrusted) { +nsresult IsCertificateDistrustImminent(nsIX509CertList* aCertList, + /* out */ bool& isDistrusted) { if (!aCertList) { return NS_ERROR_INVALID_POINTER; } diff --git a/security/manager/ssl/nsNSSCallbacks.h b/security/manager/ssl/nsNSSCallbacks.h index b9fa2ee3666b..b7b1af25e552 100644 --- a/security/manager/ssl/nsNSSCallbacks.h +++ b/security/manager/ssl/nsNSSCallbacks.h @@ -22,6 +22,7 @@ using mozilla::TimeDuration; using mozilla::Vector; class nsILoadGroup; +class nsIX509CertList; char* PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg); @@ -35,4 +36,9 @@ mozilla::pkix::Result DoOCSPRequest( size_t ocspRequestLength, TimeDuration timeout, /*out*/ Vector& result); +nsCString getKeaGroupName(uint32_t aKeaGroup); +nsCString getSignatureName(uint32_t aSignatureScheme); +nsresult IsCertificateDistrustImminent(nsIX509CertList* aCertList, + /* out */ bool& isDistrusted); + #endif // nsNSSCallbacks_h diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp index 2659a82317b2..a2e35893b119 100644 --- a/security/manager/ssl/nsNSSIOLayer.cpp +++ b/security/manager/ssl/nsNSSIOLayer.cpp @@ -111,32 +111,25 @@ extern LazyLogModule gPIPNSSLog; nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags, uint32_t providerTlsFlags) - : mFd(nullptr), + : CommonSocketControl(providerFlags), + mFd(nullptr), mCertVerificationState(before_cert_verification), mSharedState(aState), mForSTARTTLS(false), mHandshakePending(true), mPreliminaryHandshakeDone(false), - mNPNCompleted(false), mEarlyDataAccepted(false), mDenyClientCert(false), mFalseStartCallbackCalled(false), mFalseStarted(false), mIsFullHandshake(false), - mHandshakeCompleted(false), - mJoined(false), - mSentClientCert(false), mNotedTimeUntilReady(false), - mFailedVerification(false), - mResumed(false), mIsShortWritePending(false), mShortWritePendingByte(0), mShortWriteOriginalAmount(-1), mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN), mKEAKeyBits(0), - mSSLVersionUsed(nsISSLSocketControl::SSL_VERSION_UNKNOWN), mMACAlgorithmUsed(nsISSLSocketControl::SSL_MAC_UNKNOWN), - mProviderFlags(providerFlags), mProviderTlsFlags(providerTlsFlags), mSocketCreationTimestamp(TimeStamp::Now()), mPlaintextBytesRead(0), @@ -150,12 +143,6 @@ nsNSSSocketInfo::~nsNSSSocketInfo() {} NS_IMPL_ISUPPORTS_INHERITED(nsNSSSocketInfo, TransportSecurityInfo, nsISSLSocketControl) -NS_IMETHODIMP -nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags) { - *aProviderFlags = mProviderFlags; - return NS_OK; -} - NS_IMETHODIMP nsNSSSocketInfo::GetProviderTlsFlags(uint32_t* aProviderTlsFlags) { *aProviderTlsFlags = mProviderTlsFlags; @@ -174,12 +161,6 @@ nsNSSSocketInfo::GetKEAKeyBits(uint32_t* aKeyBits) { return NS_OK; } -NS_IMETHODIMP -nsNSSSocketInfo::GetSSLVersionUsed(int16_t* aSSLVersionUsed) { - *aSSLVersionUsed = mSSLVersionUsed; - return NS_OK; -} - NS_IMETHODIMP nsNSSSocketInfo::GetSSLVersionOffered(int16_t* aSSLVersionOffered) { *aSSLVersionOffered = mTLSVersionRange.max; @@ -206,31 +187,6 @@ nsNSSSocketInfo::SetClientCert(nsIX509Cert* aClientCert) { return NS_OK; } -NS_IMETHODIMP -nsNSSSocketInfo::GetClientCertSent(bool* arg) { - *arg = mSentClientCert; - return NS_OK; -} - -NS_IMETHODIMP -nsNSSSocketInfo::GetFailedVerification(bool* arg) { - *arg = mFailedVerification; - return NS_OK; -} - -NS_IMETHODIMP -nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks) { - nsCOMPtr ir(mCallbacks); - ir.forget(aCallbacks); - return NS_OK; -} - -NS_IMETHODIMP -nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) { - mCallbacks = aCallbacks; - return NS_OK; -} - void nsNSSSocketInfo::NoteTimeUntilReady() { if (mNotedTimeUntilReady) return; @@ -302,14 +258,6 @@ void nsNSSSocketInfo::SetNegotiatedNPN(const char* value, uint32_t length) { mNPNCompleted = true; } -NS_IMETHODIMP -nsNSSSocketInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN) { - if (!mNPNCompleted) return NS_ERROR_NOT_CONNECTED; - - aNegotiatedNPN = mNegotiatedNPN; - return NS_OK; -} - NS_IMETHODIMP nsNSSSocketInfo::GetAlpnEarlySelection(nsACString& aAlpnSelected) { aAlpnSelected.Truncate(); @@ -348,14 +296,6 @@ void nsNSSSocketInfo::SetEarlyDataAccepted(bool aAccepted) { mEarlyDataAccepted = aAccepted; } -NS_IMETHODIMP -nsNSSSocketInfo::GetResumed(bool* aResumed) { - *aResumed = mResumed; - return NS_OK; -} - -void nsNSSSocketInfo::SetResumed(bool aResumed) { mResumed = aResumed; } - bool nsNSSSocketInfo::GetDenyClientCert() { return mDenyClientCert; } void nsNSSSocketInfo::SetDenyClientCert(bool aDenyClientCert) { @@ -386,123 +326,6 @@ nsNSSSocketInfo::DriveHandshake() { return NS_OK; } -NS_IMETHODIMP -nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, - bool* _retval) { - NS_ENSURE_ARG(_retval); - - *_retval = false; - - // If this is the same hostname then the certicate status does not - // need to be considered. They are joinable. - if (hostname.Equals(GetHostName())) { - *_retval = true; - return NS_OK; - } - - // Before checking the server certificate we need to make sure the - // handshake has completed. - if (!mHandshakeCompleted || !HasServerCert()) { - return NS_OK; - } - - // If the cert has error bits (e.g. it is untrusted) then do not join. - // The value of mHaveCertErrorBits is only reliable because we know that - // the handshake completed. - if (mHaveCertErrorBits) { - return NS_OK; - } - - // If the connection is using client certificates then do not join - // because the user decides on whether to send client certs to hosts on a - // per-domain basis. - if (mSentClientCert) return NS_OK; - - // Ensure that the server certificate covers the hostname that would - // like to join this connection - - UniqueCERTCertificate nssCert; - - nsCOMPtr cert; - if (NS_FAILED(GetServerCert(getter_AddRefs(cert)))) { - return NS_OK; - } - if (cert) { - nssCert.reset(cert->GetCert()); - } - - if (!nssCert) { - return NS_OK; - } - - // Attempt to verify the joinee's certificate using the joining hostname. - // This ensures that any hostname-specific verification logic (e.g. key - // pinning) is satisfied by the joinee's certificate chain. - // This verification only uses local information; since we're on the network - // thread, we would be blocking on ourselves if we attempted any network i/o. - // TODO(bug 1056935): The certificate chain built by this verification may be - // different than the certificate chain originally built during the joined - // connection's TLS handshake. Consequently, we may report a wrong and/or - // misleading certificate chain for HTTP transactions coalesced onto this - // connection. This may become problematic in the future. For example, - // if/when we begin relying on intermediate certificates being stored in the - // securityInfo of a cached HTTPS response, that cached certificate chain may - // actually be the wrong chain. We should consider having JoinConnection - // return the certificate chain built here, so that the calling Necko code - // can associate the correct certificate chain with the HTTP transactions it - // is trying to join onto this connection. - RefPtr certVerifier(GetDefaultCertVerifier()); - if (!certVerifier) { - return NS_OK; - } - CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY; - UniqueCERTCertList unusedBuiltChain; - mozilla::pkix::Result result = certVerifier->VerifySSLServerCert( - nssCert, - Maybe>(), // stapledOCSPResponse - Maybe>(), // sctsFromTLSExtension - mozilla::pkix::Now(), - nullptr, // pinarg - hostname, unusedBuiltChain, - false, // save intermediates - flags); - if (result != mozilla::pkix::Success) { - return NS_OK; - } - - // All tests pass - *_retval = true; - return NS_OK; -} - -NS_IMETHODIMP -nsNSSSocketInfo::TestJoinConnection(const nsACString& npnProtocol, - const nsACString& hostname, int32_t port, - bool* _retval) { - *_retval = false; - - // Different ports may not be joined together - if (port != GetPort()) return NS_OK; - - // Make sure NPN has been completed and matches requested npnProtocol - if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol)) return NS_OK; - - IsAcceptableForHost(hostname, _retval); // sets _retval - return NS_OK; -} - -NS_IMETHODIMP -nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol, - const nsACString& hostname, int32_t port, - bool* _retval) { - nsresult rv = TestJoinConnection(npnProtocol, hostname, port, _retval); - if (NS_SUCCEEDED(rv) && *_retval) { - // All tests pass - this is joinable - mJoined = true; - } - return rv; -} - bool nsNSSSocketInfo::GetForSTARTTLS() { return mForSTARTTLS; } void nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS) { diff --git a/security/manager/ssl/nsNSSIOLayer.h b/security/manager/ssl/nsNSSIOLayer.h index f14e9b3ebb83..c59bc39a369b 100644 --- a/security/manager/ssl/nsNSSIOLayer.h +++ b/security/manager/ssl/nsNSSIOLayer.h @@ -7,7 +7,7 @@ #ifndef nsNSSIOLayer_h #define nsNSSIOLayer_h -#include "TransportSecurityInfo.h" +#include "CommonSocketControl.h" #include "mozilla/Assertions.h" #include "mozilla/TimeStamp.h" #include "mozilla/UniquePtr.h" @@ -31,14 +31,12 @@ using mozilla::OriginAttributes; class nsIObserver; -class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo, - public nsISSLSocketControl { +class nsNSSSocketInfo final : public CommonSocketControl { public: nsNSSSocketInfo(mozilla::psm::SharedSSLState& aState, uint32_t providerFlags, uint32_t providerTlsFlags); NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSISSLSOCKETCONTROL void SetForSTARTTLS(bool aForSTARTTLS); bool GetForSTARTTLS(); @@ -52,13 +50,31 @@ class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo, void SetTLSVersionRange(SSLVersionRange range) { mTLSVersionRange = range; } SSLVersionRange GetTLSVersionRange() const { return mTLSVersionRange; }; + // From nsISSLSocketControl. + NS_IMETHOD ProxyStartSSL(void) override; + NS_IMETHOD StartTLS(void) override; + NS_IMETHOD SetNPNList(nsTArray & aNPNList) override; + NS_IMETHOD GetAlpnEarlySelection(nsACString& _retval) override; + NS_IMETHOD GetEarlyDataAccepted(bool *aEarlyDataAccepted) override; + NS_IMETHOD DriveHandshake(void) override; + using nsISSLSocketControl::GetKEAUsed; + NS_IMETHOD GetKEAUsed(int16_t *aKEAUsed) override; + NS_IMETHOD GetKEAKeyBits(uint32_t *aKEAKeyBits) override; + NS_IMETHOD GetProviderTlsFlags(uint32_t *aProviderTlsFlags) override; + NS_IMETHOD GetSSLVersionOffered(int16_t* aSSLVersionOffered) override; + NS_IMETHOD GetMACAlgorithmUsed(int16_t *aMACAlgorithmUsed) override; + bool GetDenyClientCert() override; + void SetDenyClientCert(bool aDenyClientCert) override; + NS_IMETHOD GetClientCert(nsIX509Cert **aClientCert) override; + NS_IMETHOD SetClientCert(nsIX509Cert *aClientCert) override; + NS_IMETHOD GetEsniTxt(nsACString& aEsniTxt) override; + NS_IMETHOD SetEsniTxt(const nsACString& aEsniTxt) override; + PRStatus CloseSocketAndDestroy(); void SetNegotiatedNPN(const char* value, uint32_t length); void SetEarlyDataAccepted(bool aAccepted); - void SetResumed(bool aResumed); - void SetHandshakeCompleted(); bool IsHandshakeCompleted() const { return mHandshakeCompleted; } void NoteTimeUntilReady(); @@ -74,7 +90,6 @@ class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo, bool GetJoined() { return mJoined; } void SetSentClientCert() { mSentClientCert = true; } - uint32_t GetProviderFlags() const { return mProviderFlags; } uint32_t GetProviderTlsFlags() const { return mProviderTlsFlags; } mozilla::psm::SharedSSLState& SharedState(); @@ -102,8 +117,6 @@ class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo, void SetKEAKeyBits(uint32_t keaBits) { mKEAKeyBits = keaBits; } - void SetSSLVersionUsed(int16_t version) { mSSLVersionUsed = version; } - void SetMACAlgorithmUsed(int16_t mac) { mMACAlgorithmUsed = mac; } void SetShortWritePending(int32_t amount, unsigned char data) { @@ -161,20 +174,13 @@ class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo, nsresult ActivateSSL(); - nsCString mNegotiatedNPN; nsCString mEsniTxt; - bool mNPNCompleted; bool mEarlyDataAccepted; bool mDenyClientCert; bool mFalseStartCallbackCalled; bool mFalseStarted; bool mIsFullHandshake; - bool mHandshakeCompleted; - bool mJoined; - bool mSentClientCert; bool mNotedTimeUntilReady; - bool mFailedVerification; - mozilla::Atomic mResumed; // True when SSL layer has indicated an "SSL short write", i.e. need // to call on send one or more times to push all pending data to write. @@ -198,10 +204,8 @@ class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo, // Values are from nsISSLSocketControl int16_t mKEAUsed; uint32_t mKEAKeyBits; - int16_t mSSLVersionUsed; int16_t mMACAlgorithmUsed; - uint32_t mProviderFlags; uint32_t mProviderTlsFlags; mozilla::TimeStamp mSocketCreationTimestamp; uint64_t mPlaintextBytesRead;