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
This commit is contained in:
Dragana Damjanovic 2019-09-25 20:23:56 +00:00
Родитель 5f2cea9512
Коммит 1d40d354bd
11 изменённых файлов: 519 добавлений и 202 удалений

Просмотреть файл

@ -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<nsresult> 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> 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<nsISupportsWeakReference*>(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

Просмотреть файл

@ -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

Просмотреть файл

@ -108,6 +108,7 @@ UNIFIED_SOURCES += [
'NullHttpChannel.cpp',
'NullHttpTransaction.cpp',
'ParentChannelListener.cpp',
'QuicSocketControl.cpp',
'TunnelUtils.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<nsCString> & 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<nsIX509Cert> 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<psm::SharedCertVerifier> 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<nsTArray<uint8_t>>(), // stapledOCSPResponse
Maybe<nsTArray<uint8_t>>(), // 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;
}

Просмотреть файл

@ -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<bool, mozilla::Relaxed> mResumed;
uint16_t mSSLVersionUsed;
uint32_t mProviderFlags;
};
#endif // CommonSocketControl_h

Просмотреть файл

@ -116,6 +116,7 @@ class TransportSecurityInfo : public nsITransportSecurityInfo,
protected:
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsIX509CertList> mSucceededCertChain;
private:
uint32_t mSecurityState;
@ -127,7 +128,6 @@ class TransportSecurityInfo : public nsITransportSecurityInfo,
OriginAttributes mOriginAttributes;
nsCOMPtr<nsIX509Cert> mServerCert;
nsCOMPtr<nsIX509CertList> mSucceededCertChain;
/* Peer cert chain for failed connections (for error reporting) */
nsCOMPtr<nsIX509CertList> mFailedCertChain;

Просмотреть файл

@ -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',

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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<uint8_t>& result);
nsCString getKeaGroupName(uint32_t aKeaGroup);
nsCString getSignatureName(uint32_t aSignatureScheme);
nsresult IsCertificateDistrustImminent(nsIX509CertList* aCertList,
/* out */ bool& isDistrusted);
#endif // nsNSSCallbacks_h

Просмотреть файл

@ -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<nsIInterfaceRequestor> 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<nsIX509Cert> 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<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
if (!certVerifier) {
return NS_OK;
}
CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY;
UniqueCERTCertList unusedBuiltChain;
mozilla::pkix::Result result = certVerifier->VerifySSLServerCert(
nssCert,
Maybe<nsTArray<uint8_t>>(), // stapledOCSPResponse
Maybe<nsTArray<uint8_t>>(), // 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) {

Просмотреть файл

@ -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<nsCString> & 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<bool, mozilla::Relaxed> 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;