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;