Bug 1439105 - Ban H2 Client Certs Post Handshake
MozReview-Commit-ID: Dfx5bB5NOBp
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -268,24 +268,27 @@ nsHttpConnection::Start0RTTSpdy(uint8_t
"transactions rv=%" PRIx32 , this, static_cast<uint32_t>(rv)));
return;
}
mTransaction = mSpdySession;
}
void
-nsHttpConnection::StartSpdy(uint8_t spdyVersion)
+nsHttpConnection::StartSpdy(nsISSLSocketControl *sslControl, uint8_t spdyVersion)
{
LOG(("nsHttpConnection::StartSpdy [this=%p, mDid0RTTSpdy=%d]\n", this, mDid0RTTSpdy));
MOZ_ASSERT(!mSpdySession || mDid0RTTSpdy);
mUsingSpdyVersion = spdyVersion;
mEverUsedSpdy = true;
+ if (sslControl) {
+ sslControl->SetDenyClientCert(true);
+ }
if (!mDid0RTTSpdy) {
mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport,
false);
}
if (!mReportedSpdy) {
mReportedSpdy = true;
@@ -539,28 +542,28 @@ nsHttpConnection::EnsureNPNComplete(nsre
mBootstrappedTimings.secureConnectionStart =
mTransaction->QueryNullTransaction()->GetSecureConnectionStart();
mBootstrappedTimings.tcpConnectEnd =
mTransaction->QueryNullTransaction()->GetTcpConnectEnd();
}
uint32_t infoIndex;
const SpdyInformation *info = gHttpHandler->SpdyInfo();
if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) {
- StartSpdy(info->Version[infoIndex]);
+ StartSpdy(ssl, info->Version[infoIndex]);
}
} else {
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - %" PRId64 " bytes "
"has been sent during 0RTT.", this, mContentBytesWritten0RTT));
mContentBytesWritten = mContentBytesWritten0RTT;
if (mSpdySession) {
// We had already started 0RTT-spdy, now we need to fully set up
// spdy, since we know we're sticking with it.
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - finishing "
"StartSpdy for 0rtt spdy session %p", this, mSpdySession.get()));
- StartSpdy(mSpdySession->SpdyVersion());
+ StartSpdy(ssl, mSpdySession->SpdyVersion());
}
}
Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
}
npnComplete:
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] setting complete to true", this));
--- a/netwerk/protocol/http/nsHttpConnection.h
+++ b/netwerk/protocol/http/nsHttpConnection.h
@@ -267,17 +267,17 @@ private:
// Makes certain the SSL handshake is complete and NPN negotiation
// has had a chance to happen
MOZ_MUST_USE bool EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
uint32_t &aOut0RTTBytesWritten);
void SetupSSL();
// Start the Spdy transaction handler when NPN indicates spdy/*
- void StartSpdy(uint8_t versionLevel);
+ void StartSpdy(nsISSLSocketControl *ssl, uint8_t versionLevel);
// Like the above, but do the bare minimum to do 0RTT data, so we can back
// it out, if necessary
void Start0RTTSpdy(uint8_t versionLevel);
// Helpers for Start*Spdy
nsresult TryTakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction> > &list);
nsresult MoveTransactionsToSpdy(nsresult status, nsTArray<RefPtr<nsAHttpTransaction> > &list);
--- a/netwerk/socket/nsISSLSocketControl.idl
+++ b/netwerk/socket/nsISSLSocketControl.idl
@@ -126,16 +126,22 @@ interface nsISSLSocketControl : nsISuppo
const short SSL_HMAC_MD5 = 3;
const short SSL_HMAC_SHA = 4;
const short SSL_HMAC_SHA256 = 5;
const short SSL_MAC_AEAD = 6;
[infallible] readonly attribute short MACAlgorithmUsed;
/**
+ * If set to true before the server requests a client cert
+ * no cert will be sent.
+ */
+ [noscript] attribute boolean denyClientCert;
+
+ /**
* If set before the server requests a client cert (assuming it does so at
* all), then this cert will be presented to the server, instead of asking
* the user or searching the set of rememebered user cert decisions.
*/
attribute nsIX509Cert clientCert;
/**
* bypassAuthentication is true if the server certificate checks are
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -115,16 +115,17 @@ nsNSSSocketInfo::nsNSSSocketInfo(SharedS
mCertVerificationState(before_cert_verification),
mSharedState(aState),
mForSTARTTLS(false),
mHandshakePending(true),
mRememberClientAuthCertificate(false),
mPreliminaryHandshakeDone(false),
mNPNCompleted(false),
mEarlyDataAccepted(false),
+ mDenyClientCert(false),
mFalseStartCallbackCalled(false),
mFalseStarted(false),
mIsFullHandshake(false),
mHandshakeCompleted(false),
mJoined(false),
mSentClientCert(false),
mNotedTimeUntilReady(false),
mFailedVerification(false),
@@ -391,16 +392,30 @@ nsNSSSocketInfo::GetEarlyDataAccepted(bo
void
nsNSSSocketInfo::SetEarlyDataAccepted(bool aAccepted)
{
mEarlyDataAccepted = aAccepted;
}
NS_IMETHODIMP
+nsNSSSocketInfo::GetDenyClientCert(bool* aDenyClientCert)
+{
+ *aDenyClientCert = mDenyClientCert;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNSSSocketInfo::SetDenyClientCert(bool aDenyClientCert)
+{
+ mDenyClientCert = aDenyClientCert;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsNSSSocketInfo::DriveHandshake()
{
if (!mFd) {
return NS_ERROR_FAILURE;
}
PRErrorCode errorCode = GetErrorCode();
if (errorCode) {
return GetXPCOMFromNSSError(errorCode);
@@ -2141,16 +2156,24 @@ nsNSS_SSLGetClientAuthData(void* arg, PR
UniqueCERTCertificate serverCert(SSL_PeerCertificate(socket));
if (!serverCert) {
MOZ_ASSERT_UNREACHABLE(
"Missing server cert should have been detected during server cert auth.");
PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
return SECFailure;
}
+ if (info->GetDenyClientCert()) {
+ MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+ ("[%p] Not returning client cert due to denyClientCert attribute\n", socket));
+ *pRetCert = nullptr;
+ *pRetKey = nullptr;
+ return SECSuccess;
+ }
+
if (info->GetJoined()) {
// We refuse to send a client certificate when there are multiple hostnames
// joined on this connection, because we only show the user one hostname
// (mHostName) in the client certificate UI.
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p] Not returning client cert due to previous join\n", socket));
*pRetCert = nullptr;
--- a/security/manager/ssl/nsNSSIOLayer.h
+++ b/security/manager/ssl/nsNSSIOLayer.h
@@ -68,16 +68,17 @@ public:
void SetFalseStarted() { mFalseStarted = true; }
// Note that this is only valid *during* a handshake; at the end of the handshake,
// it gets reset back to false.
void SetFullHandshake() { mIsFullHandshake = true; }
bool IsFullHandshake() const { return mIsFullHandshake; }
bool GetJoined() { return mJoined; }
+ bool GetDenyClientCert() { return mDenyClientCert; }
void SetSentClientCert() { mSentClientCert = true; }
uint32_t GetProviderFlags() const { return mProviderFlags; }
uint32_t GetProviderTlsFlags() const { return mProviderTlsFlags; }
mozilla::psm::SharedSSLState& SharedState();
// XXX: These are only used on for diagnostic purposes
@@ -180,16 +181,17 @@ private:
bool mRememberClientAuthCertificate;
bool mPreliminaryHandshakeDone; // after false start items are complete
nsresult ActivateSSL();
nsCString mNegotiatedNPN;
bool mNPNCompleted;
bool mEarlyDataAccepted;
+ bool mDenyClientCert;
bool mFalseStartCallbackCalled;
bool mFalseStarted;
bool mIsFullHandshake;
bool mHandshakeCompleted;
bool mJoined;
bool mSentClientCert;
bool mNotedTimeUntilReady;
bool mFailedVerification;