diff --git a/browser/base/content/pageinfo/security.js b/browser/base/content/pageinfo/security.js index 81890c653..eec5dd060 100644 --- a/browser/base/content/pageinfo/security.js +++ b/browser/base/content/pageinfo/security.js @@ -90,6 +90,9 @@ var security = { case nsISSLStatus.TLS_VERSION_1_2: retval.version = "TLS 1.2" break; + case nsISSLStatus.TLS_VERSION_1_3: + retval.version = "TLS 1.3" + break; } return retval; diff --git a/config/external/nss/Makefile.in b/config/external/nss/Makefile.in index 713c66a33..1e960672e 100644 --- a/config/external/nss/Makefile.in +++ b/config/external/nss/Makefile.in @@ -122,6 +122,7 @@ DEFAULT_GMAKE_FLAGS += NSPR_LIB_DIR=$(NSPR_LIB_DIR) DEFAULT_GMAKE_FLAGS += MOZILLA_CLIENT=1 DEFAULT_GMAKE_FLAGS += NO_MDUPDATE=1 DEFAULT_GMAKE_FLAGS += NSS_ENABLE_ECC=1 +DEFAULT_GMAKE_FLAGS += NSS_ENABLE_TLS_1_3=1 ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_1) DEFAULT_GMAKE_FLAGS += OS_DLLFLAGS='-static-libgcc' NSPR31_LIB_PREFIX=lib endif diff --git a/devtools/shared/webconsole/network-helper.js b/devtools/shared/webconsole/network-helper.js index c6bc763ae..6159d91af 100644 --- a/devtools/shared/webconsole/network-helper.js +++ b/devtools/shared/webconsole/network-helper.js @@ -529,7 +529,7 @@ var NetworkHelper = { * If state == broken: * - errorMessage: full error message from nsITransportSecurityInfo. * If state == secure: - * - protocolVersion: one of TLSv1, TLSv1.1, TLSv1.2. + * - protocolVersion: one of TLSv1, TLSv1.1, TLSv1.2, TLSv1.3. * - cipherSuite: the cipher suite used in this connection. * - cert: information about certificate used in this connection. * See parseCertificateInfo for the contents. @@ -712,7 +712,7 @@ var NetworkHelper = { * @param Number version * One of nsISSLStatus version constants. * @return string - * One of TLSv1, TLSv1.1, TLSv1.2 if @param version is valid, + * One of TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 if @param version is valid, * Unknown otherwise. */ formatSecurityProtocol: function NH_formatSecurityProtocol(version) { @@ -723,6 +723,8 @@ var NetworkHelper = { return "TLSv1.1"; case Ci.nsISSLStatus.TLS_VERSION_1_2: return "TLSv1.2"; + case Ci.nsISSLStatus.TLS_VERSION_1_3: + return "TLSv1.3"; default: DevToolsUtils.reportException("NetworkHelper.formatSecurityProtocol", "protocolVersion " + version + " is unknown."); diff --git a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp index c39d7571a..959451864 100644 --- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp +++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp @@ -1116,6 +1116,8 @@ NS_IMETHODIMP nsWebBrowserPersist::OnStatus( case NS_NET_STATUS_END_FTP_TRANSACTION: case NS_NET_STATUS_CONNECTING_TO: case NS_NET_STATUS_CONNECTED_TO: + case NS_NET_STATUS_TLS_HANDSHAKE_STARTING: + case NS_NET_STATUS_TLS_HANDSHAKE_ENDED: case NS_NET_STATUS_SENDING_TO: case NS_NET_STATUS_RECEIVING_FROM: case NS_NET_STATUS_WAITING_FOR: diff --git a/media/mtransport/transportlayerdtls.cpp b/media/mtransport/transportlayerdtls.cpp index ad8c2244b..8a1c8e738 100644 --- a/media/mtransport/transportlayerdtls.cpp +++ b/media/mtransport/transportlayerdtls.cpp @@ -454,6 +454,15 @@ TransportLayerDtls::SetVerificationDigest(const std::string digest_algorithm, return NS_OK; } +// These are the named groups that we will allow. +static const SSLNamedGroup NamedGroupPreferences[] = { + ssl_grp_ec_curve25519, + ssl_grp_ec_secp256r1, + ssl_grp_ec_secp384r1, + ssl_grp_ffdhe_2048, + ssl_grp_ffdhe_3072 +}; + // TODO: make sure this is called from STS. Otherwise // we have thread safety issues bool TransportLayerDtls::Setup() { @@ -588,6 +597,13 @@ bool TransportLayerDtls::Setup() { return false; } + rv = SSL_NamedGroupConfig(ssl_fd, NamedGroupPreferences, + mozilla::ArrayLength(NamedGroupPreferences)); + if (rv != SECSuccess) { + MOZ_MTLOG(ML_ERROR, "Couldn't set named groups"); + return false; + } + // Certificate validation rv = SSL_AuthCertificateHook(ssl_fd, AuthCertificateHook, reinterpret_cast(this)); @@ -675,6 +691,7 @@ static const uint32_t EnabledCiphers[] = { static const uint32_t DisabledCiphers[] = { // ALL SHA384 ciphers are disabled per bug 1310061. TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, @@ -702,22 +719,14 @@ static const uint32_t DisabledCiphers[] = { TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, TLS_RSA_WITH_SEED_CBC_SHA, - SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_RC4_128_MD5, TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_DHE_DSS_WITH_DES_CBC_SHA, - SSL_RSA_FIPS_WITH_DES_CBC_SHA, TLS_RSA_WITH_DES_CBC_SHA, - TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, - TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, - - TLS_RSA_EXPORT_WITH_RC4_40_MD5, - TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, - TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS_ECDHE_RSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_NULL_SHA, diff --git a/netwerk/base/Dashboard.cpp b/netwerk/base/Dashboard.cpp index 398758aef..cf180dc1e 100644 --- a/netwerk/base/Dashboard.cpp +++ b/netwerk/base/Dashboard.cpp @@ -893,13 +893,15 @@ typedef struct #define ERROR(key, val) {key, #key} ErrorEntry socketTransportStatuses[] = { - ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)), - ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)), - ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)), - ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)), - ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)), - ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)), - ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)), + ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)), + ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)), + ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)), + ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)), + ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)), + ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED, FAILURE(13)), + ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)), + ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)), + ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)), }; #undef ERROR diff --git a/netwerk/base/nsITLSServerSocket.idl b/netwerk/base/nsITLSServerSocket.idl index 447a14483..f3ab63415 100644 --- a/netwerk/base/nsITLSServerSocket.idl +++ b/netwerk/base/nsITLSServerSocket.idl @@ -100,6 +100,7 @@ interface nsITLSClientStatus : nsISupports const short TLS_VERSION_1 = 0x0301; const short TLS_VERSION_1_1 = 0x0302; const short TLS_VERSION_1_2 = 0x0303; + const short TLS_VERSION_1_3 = 0x0304; const short TLS_VERSION_UNKNOWN = -1; /** diff --git a/netwerk/base/security-prefs.js b/netwerk/base/security-prefs.js index a4b48961b..32c3be090 100644 --- a/netwerk/base/security-prefs.js +++ b/netwerk/base/security-prefs.js @@ -3,10 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ pref("security.tls.version.min", 1); -pref("security.tls.version.max", 3); +pref("security.tls.version.max", 4); pref("security.tls.version.fallback-limit", 3); pref("security.tls.insecure_fallback_hosts", ""); pref("security.tls.unrestricted_rc4_fallback", false); +pref("security.tls.enable_0rtt_data", true); pref("security.ssl.treat_unsafe_negotiation_as_broken", false); pref("security.ssl.require_safe_negotiation", false); diff --git a/netwerk/locales/en-US/necko.properties b/netwerk/locales/en-US/necko.properties index c350b24c2..d48308c1b 100644 --- a/netwerk/locales/en-US/necko.properties +++ b/netwerk/locales/en-US/necko.properties @@ -17,6 +17,8 @@ 9=Wrote %1$S 10=Waiting for %1$S… 11=Looked up %1$S… +12=Performing a TLS handshake to %1$S… +13=The TLS handshake finished for %1$S… 27=Beginning FTP transaction… 28=Finished FTP transaction diff --git a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp index 57a7d0957..dede9bec2 100644 --- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp @@ -2025,6 +2025,8 @@ nsFtpState::OnTransportStatus(nsITransport *transport, nsresult status, case NS_NET_STATUS_RESOLVED_HOST: case NS_NET_STATUS_CONNECTING_TO: case NS_NET_STATUS_CONNECTED_TO: + case NS_NET_STATUS_TLS_HANDSHAKE_STARTING: + case NS_NET_STATUS_TLS_HANDSHAKE_ENDED: break; default: return NS_OK; diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index 702d48176..173593e2a 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -2240,6 +2240,8 @@ Http2Session::OnTransportStatus(nsITransport* aTransport, case NS_NET_STATUS_RESOLVED_HOST: case NS_NET_STATUS_CONNECTING_TO: case NS_NET_STATUS_CONNECTED_TO: + case NS_NET_STATUS_TLS_HANDSHAKE_STARTING: + case NS_NET_STATUS_TLS_HANDSHAKE_ENDED: { Http2Stream *target = mStreamIDHash.Get(1); nsAHttpTransaction *transaction = target ? target->Transaction() : nullptr; @@ -2306,7 +2308,13 @@ Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader *reader, if (!stream) { LOG3(("Http2Session %p could not identify a stream to write; suspending.", this)); + uint32_t availBeforeFlush = mOutputQueueUsed - mOutputQueueSent; FlushOutputQueue(); + uint32_t availAfterFlush = mOutputQueueUsed - mOutputQueueSent; + if (availBeforeFlush != availAfterFlush) { + LOG3(("Http2Session %p ResumeRecv After early flush in ReadSegments", this)); + ResumeRecv(); + } SetWriteCallbacks(); return NS_BASE_STREAM_WOULD_BLOCK; } diff --git a/netwerk/protocol/http/nsAHttpTransaction.h b/netwerk/protocol/http/nsAHttpTransaction.h index ff0695190..9b1e33ecc 100644 --- a/netwerk/protocol/http/nsAHttpTransaction.h +++ b/netwerk/protocol/http/nsAHttpTransaction.h @@ -204,6 +204,22 @@ public: virtual void DisableSpdy() { } virtual void ReuseConnectionOnRestartOK(bool) { } + + // Returns true if early-data is possible. + virtual bool Do0RTT() { + return false; + } + // This function will be called when a tls handshake has been finished and + // we know whether early-data that was sent has been accepted or not, e.g. + // do we need to restart a transaction. This will be called only if Do0RTT + // returns true. + // If aRestart parameter is true we need to restart the transaction, + // otherwise the erly-data has been accepted and we can continue the + // transaction. + // The function will return success or failure of the transaction restart. + virtual nsresult Finish0RTT(bool aRestart) { + return NS_ERROR_NOT_IMPLEMENTED; + } }; NS_DEFINE_STATIC_IID_ACCESSOR(nsAHttpTransaction, NS_AHTTPTRANSACTION_IID) diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index c6b9f4f1a..31229a82d 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -79,6 +79,9 @@ nsHttpConnection::nsHttpConnection() , mResponseTimeoutEnabled(false) , mTCPKeepaliveConfig(kTCPKeepaliveDisabled) , mForceSendPending(false) + , m0RTTChecked(false) + , mWaitingFor0RTTResponse(false) + , mContentBytesWritten0RTT(0) { LOG(("Creating nsHttpConnection @%p\n", this)); @@ -96,18 +99,22 @@ nsHttpConnection::~nsHttpConnection() if (!mEverUsedSpdy) { LOG(("nsHttpConnection %p performed %d HTTP/1.x transactions\n", this, mHttp1xTransactionCount)); +/* Telemetry::Accumulate(Telemetry::HTTP_REQUEST_PER_CONN, mHttp1xTransactionCount); +*/ } if (mTotalBytesRead) { uint32_t totalKBRead = static_cast(mTotalBytesRead >> 10); LOG(("nsHttpConnection %p read %dkb on connection spdy=%d\n", this, totalKBRead, mEverUsedSpdy)); +/* Telemetry::Accumulate(mEverUsedSpdy ? Telemetry::SPDY_KBREAD_PER_CONN : Telemetry::HTTP_KBREAD_PER_CONN, totalKBRead); +*/ } if (mForceSendTimer) { mForceSendTimer->Cancel(); @@ -268,8 +275,12 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion) } bool -nsHttpConnection::EnsureNPNComplete() +nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, + uint32_t &aOut0RTTBytesWritten) { + aOut0RTTWriteHandshakeValue = NS_OK; + aOut0RTTBytesWritten = 0; + // If for some reason the components to check on NPN aren't available, // this function will just return true to continue on and disable SPDY @@ -294,16 +305,81 @@ nsHttpConnection::EnsureNPNComplete() goto npnComplete; } + if (!m0RTTChecked) { + // We reuse m0RTTChecked. We want to send this status only once. + mTransaction->OnTransportStatus(mSocketTransport, + NS_NET_STATUS_TLS_HANDSHAKE_STARTING, + 0); + } + ssl = do_QueryInterface(securityInfo, &rv); if (NS_FAILED(rv)) goto npnComplete; rv = ssl->GetNegotiatedNPN(negotiatedNPN); + if (!m0RTTChecked && (rv == NS_ERROR_NOT_CONNECTED) && + !mConnInfo->UsingProxy()) { + // There is no ALPN info (yet!). We need to consider doing 0RTT. We + // will do so if there is ALPN information from a previous session + // (AlpnEarlySelection), we are using HTTP/1, and the request data can + // be safely retried. + m0RTTChecked = true; + nsAutoCString earlyNegotiatedNPN; + nsresult rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN); + if (NS_FAILED(rvEarlyAlpn)) { + // if ssl->DriveHandshake() has never been called the value + // for AlpnEarlySelection is still not set. So call it here and + // check again. + LOG(("nsHttpConnection::EnsureNPNComplete %p - " + "early selected alpn not available, we will try one more time.", + this)); + // Let's do DriveHandshake again. + rv = ssl->DriveHandshake(); + if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) { + goto npnComplete; + } + + // Check NegotiatedNPN first. + rv = ssl->GetNegotiatedNPN(negotiatedNPN); + if (rv == NS_ERROR_NOT_CONNECTED) { + rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN); + } + } + + if (NS_FAILED(rvEarlyAlpn)) { + LOG(("nsHttpConnection::EnsureNPNComplete %p - " + "early selected alpn not available", this)); + } else { + LOG(("nsHttpConnection::EnsureNPNComplete %p -" + "early selected alpn: %s", this, earlyNegotiatedNPN.get())); + uint32_t infoIndex; + const SpdyInformation *info = gHttpHandler->SpdyInfo(); + // We are doing 0RTT only with Http/1 right now! + if (NS_FAILED(info->GetNPNIndex(earlyNegotiatedNPN, &infoIndex))) { + // Check if early-data is allowed for this transaction. + if (mTransaction->Do0RTT()) { + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - We " + "can do 0RTT!", this)); + mWaitingFor0RTTResponse = true; + } + } + } + } + if (rv == NS_ERROR_NOT_CONNECTED) { - // By writing 0 bytes to the socket the SSL handshake machine is - // pushed forward. - uint32_t count = 0; - rv = mSocketOut->Write("", 0, &count); + if (mWaitingFor0RTTResponse) { + aOut0RTTWriteHandshakeValue = mTransaction->ReadSegments(this, + nsIOService::gDefaultSegmentSize, &aOut0RTTBytesWritten); + if (NS_FAILED(aOut0RTTWriteHandshakeValue) && + aOut0RTTWriteHandshakeValue != NS_BASE_STREAM_WOULD_BLOCK) { + goto npnComplete; + } + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - written %d " + "bytes during 0RTT", this, aOut0RTTBytesWritten)); + mContentBytesWritten0RTT += aOut0RTTBytesWritten; + } + + rv = ssl->DriveHandshake(); if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) { goto npnComplete; } @@ -316,18 +392,49 @@ nsHttpConnection::EnsureNPNComplete() this, mConnInfo->HashKey().get(), negotiatedNPN.get(), mTLSFilter ? " [Double Tunnel]" : "")); - uint32_t infoIndex; - const SpdyInformation *info = gHttpHandler->SpdyInfo(); - if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) { - StartSpdy(info->Version[infoIndex]); + bool ealyDataAccepted = false; + if (mWaitingFor0RTTResponse) { + mWaitingFor0RTTResponse = false; + // Check if early data has been accepted. + rv = ssl->GetEarlyDataAccepted(&ealyDataAccepted); + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - early data " + "that was sent during 0RTT %s been accepted.", + this, ealyDataAccepted ? "has" : "has not")); + if (NS_FAILED(rv) || + NS_FAILED(mTransaction->Finish0RTT(!ealyDataAccepted))) { + mTransaction->Close(NS_ERROR_NET_RESET); + goto npnComplete; + } + } + if (!ealyDataAccepted) { + uint32_t infoIndex; + const SpdyInformation *info = gHttpHandler->SpdyInfo(); + if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) { + StartSpdy(info->Version[infoIndex]); + } + } else { + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - %d bytes " + "has been sent during 0RTT.", this, mContentBytesWritten0RTT)); + mContentBytesWritten = mContentBytesWritten0RTT; } - Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy()); + //Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy()); } npnComplete: LOG(("nsHttpConnection::EnsureNPNComplete setting complete to true")); mNPNComplete = true; + + mTransaction->OnTransportStatus(mSocketTransport, + NS_NET_STATUS_TLS_HANDSHAKE_ENDED, + 0); + if (mWaitingFor0RTTResponse) { + mWaitingFor0RTTResponse = false; + if (NS_FAILED(mTransaction->Finish0RTT(true))) { + mTransaction->Close(NS_ERROR_NET_RESET); + } + mContentBytesWritten0RTT = 0; + } return true; } @@ -1572,7 +1679,9 @@ nsHttpConnection::OnSocketWritable() // request differently for http/1, http/2, spdy, etc.. and that is // negotiated with NPN/ALPN in the SSL handshake. - if (mConnInfo->UsingHttpsProxy() && !EnsureNPNComplete()) { + if (mConnInfo->UsingHttpsProxy() && + !EnsureNPNComplete(rv, transactionBytes)) { + MOZ_ASSERT(!transactionBytes); mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK; } else if (mProxyConnectStream) { // If we're need an HTTP/1 CONNECT tunnel through a proxy @@ -1581,8 +1690,11 @@ nsHttpConnection::OnSocketWritable() rv = mProxyConnectStream->ReadSegments(ReadFromStream, this, nsIOService::gDefaultSegmentSize, &transactionBytes); - } else if (!EnsureNPNComplete()) { - mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK; + } else if (!EnsureNPNComplete(rv, transactionBytes)) { + if (NS_SUCCEEDED(rv) && !transactionBytes && + NS_SUCCEEDED(mSocketOutCondition)) { + mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK; + } } else { // for non spdy sessions let the connection manager know @@ -1630,7 +1742,7 @@ nsHttpConnection::OnSocketWritable() } else if (!transactionBytes) { rv = NS_OK; - if (mTransaction) { // in case the ReadSegments stack called CloseTransaction() + if (mTransaction && !mWaitingFor0RTTResponse) { // in case the ReadSegments stack called CloseTransaction() // // at this point we've written out the entire transaction, and now we // must wait for the server's response. we manufacture a status message diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index f4fef480a..f7ddde320 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -241,7 +241,8 @@ private: // Makes certain the SSL handshake is complete and NPN negotiation // has had a chance to happen - bool EnsureNPNComplete(); + bool EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, + uint32_t &aOut0RTTBytesWritten); void SetupSSL(); // Start the Spdy transaction handler when NPN indicates spdy/* @@ -350,6 +351,17 @@ private: uint32_t mTCPKeepaliveConfig; nsCOMPtr mTCPKeepaliveTransitionTimer; + // Helper variable for 0RTT handshake; + bool m0RTTChecked; // Possible 0RTT has been + // checked. + bool mWaitingFor0RTTResponse; // We have are + // sending 0RTT + // data and we + // are waiting + // for the end of + // the handsake. + int64_t mContentBytesWritten0RTT; + private: // For ForceSend() static void ForceSendIO(nsITimer *aTimer, void *aClosure); diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 11918e33e..3ee234738 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -142,6 +142,8 @@ nsHttpTransaction::nsHttpTransaction() , mAppId(NECKO_NO_APP_ID) , mIsInBrowser(false) , mClassOfService(0) + , m0RTTInProgress(false) + , mTransportStatus(NS_OK) { LOG(("Creating nsHttpTransaction @%p\n", this)); gHttpHandler->GetMaxPipelineObjectSize(&mMaxPipelineObjectSize); @@ -532,6 +534,50 @@ nsHttpTransaction::OnTransportStatus(nsITransport* transport, } } + // A transaction can given to multiple HalfOpen sockets (this is a bug in + // nsHttpConnectionMgr). We are going to fix it here as a work around to be + // able to uplift it. + switch(status) { + case NS_NET_STATUS_RESOLVING_HOST: + if (mTransportStatus != NS_OK) { + LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events " + "from backup transport")); + return; + } + break; + case NS_NET_STATUS_RESOLVED_HOST: + if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST && + mTransportStatus != NS_OK) { + LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events " + "from backup transport")); + return; + } + break; + case NS_NET_STATUS_CONNECTING_TO: + if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST && + mTransportStatus != NS_NET_STATUS_RESOLVED_HOST && + mTransportStatus != NS_OK) { + LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events " + "from backup transport")); + return; + } + break; + case NS_NET_STATUS_CONNECTED_TO: + if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST && + mTransportStatus != NS_NET_STATUS_RESOLVED_HOST && + mTransportStatus != NS_NET_STATUS_CONNECTING_TO && + mTransportStatus != NS_OK) { + LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events " + "from backup transport")); + return; + } + break; + default: + LOG(("nsHttpTransaction::OnSocketStatus - a new event")); + } + + mTransportStatus = status; + // If the timing is enabled, and we are not using a persistent connection // then the requestStart timestamp will be null, so we mark the timestamps // for domainLookupStart/End and connectStart/End @@ -545,7 +591,9 @@ nsHttpTransaction::OnTransportStatus(nsITransport* transport, } else if (status == NS_NET_STATUS_CONNECTING_TO) { SetConnectStart(TimeStamp::Now()); } else if (status == NS_NET_STATUS_CONNECTED_TO) { - SetConnectEnd(TimeStamp::Now()); + SetConnectEnd(TimeStamp::Now(), true); + } else if (status == NS_NET_STATUS_TLS_HANDSHAKE_ENDED) { + SetConnectEnd(TimeStamp::Now(), false); } } @@ -690,7 +738,7 @@ nsHttpTransaction::ReadSegments(nsAHttpSegmentReader *reader, return mStatus; } - if (!mConnected) { + if (!mConnected && !m0RTTInProgress) { mConnected = true; mConnection->GetSecurityInfo(getter_AddRefs(mSecurityInfo)); } @@ -1274,6 +1322,8 @@ nsHttpTransaction::Restart() } } + mTransportStatus = NS_OK; + return gHttpHandler->InitiateTransaction(this, mPriority); } @@ -2307,5 +2357,38 @@ nsHttpTransaction::GetNetworkAddresses(NetAddr &self, NetAddr &peer) peer = mPeerAddr; } +bool +nsHttpTransaction::Do0RTT() +{ + if (mRequestHead->IsSafeMethod() && + !mConnection->IsProxyConnectInProgress()) { + m0RTTInProgress = true; + } + return m0RTTInProgress; +} + +nsresult +nsHttpTransaction::Finish0RTT(bool aRestart) +{ + LOG(("nsHttpTransaction::Finish0RTT %p %d\n", this, aRestart)); + MOZ_ASSERT(m0RTTInProgress); + m0RTTInProgress = false; + if (aRestart) { + // Reset request headers to be sent again. + nsCOMPtr seekable = + do_QueryInterface(mRequestStream); + if (seekable) { + seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + } else { + return NS_ERROR_FAILURE; + } + } else if (!mConnected) { + // this is code that was skipped in ::ReadSegments while in 0RTT + mConnected = true; + mConnection->GetSecurityInfo(getter_AddRefs(mSecurityInfo)); + } + return NS_OK; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index 4f5d244e1..4a6154a8c 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -166,6 +166,8 @@ public: int64_t GetTransferSize() { return mTransferSize; } + bool Do0RTT() override; + nsresult Finish0RTT(bool aRestart) override; private: friend class DeleteHttpTransaction; virtual ~nsHttpTransaction(); @@ -453,6 +455,10 @@ public: private: RefPtr mTunnelProvider; + bool m0RTTInProgress; + + nsresult mTransportStatus; + public: void GetNetworkAddresses(NetAddr &self, NetAddr &peer); diff --git a/netwerk/socket/nsISSLSocketControl.idl b/netwerk/socket/nsISSLSocketControl.idl index eaf350814..ea1ec0729 100644 --- a/netwerk/socket/nsISSLSocketControl.idl +++ b/netwerk/socket/nsISSLSocketControl.idl @@ -44,6 +44,22 @@ interface nsISSLSocketControl : nsISupports { */ readonly attribute ACString negotiatedNPN; + /* For 0RTT we need to know the alpn protocol selected for the last tls + * session. This function will return a value if applicable or an error + * NS_ERROR_NOT_AVAILABLE. + */ + ACString getAlpnEarlySelection(); + + /* If 0RTT handshake was applied and some data has been sent, as soon as + * the handshake finishes this attribute will be set to appropriate value. + */ + readonly attribute bool earlyDataAccepted; + + /* When 0RTT is performed, PR_Write will not drive the handshake forward. + * It must be forced by calling this function. + */ + void driveHandshake(); + /* Determine if a potential SSL connection to hostname:port with * a desired NPN negotiated protocol of npnProtocol can use the socket * associated with this object instead of making a new one. @@ -83,6 +99,7 @@ interface nsISSLSocketControl : nsISupports { const short TLS_VERSION_1 = 0x0301; const short TLS_VERSION_1_1 = 0x0302; const short TLS_VERSION_1_2 = 0x0303; + const short TLS_VERSION_1_3 = 0x0304; const short SSL_VERSION_UNKNOWN = -1; [infallible] readonly attribute short SSLVersionUsed; diff --git a/security/manager/ssl/nsISSLStatus.idl b/security/manager/ssl/nsISSLStatus.idl index 05c140dbb..da1fbcfac 100644 --- a/security/manager/ssl/nsISSLStatus.idl +++ b/security/manager/ssl/nsISSLStatus.idl @@ -20,6 +20,7 @@ interface nsISSLStatus : nsISupports { const short TLS_VERSION_1 = 1; const short TLS_VERSION_1_1 = 2; const short TLS_VERSION_1_2 = 3; + const short TLS_VERSION_1_3 = 4; readonly attribute unsigned short protocolVersion; readonly attribute boolean isDomainMismatch; diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp index 266f69acc..0fc839478 100644 --- a/security/manager/ssl/nsNSSCallbacks.cpp +++ b/security/manager/ssl/nsNSSCallbacks.cpp @@ -891,6 +891,7 @@ PreliminaryHandshakeDone(PRFileDesc* fd) SSLChannelInfo channelInfo; if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) == SECSuccess) { infoObject->SetSSLVersionUsed(channelInfo.protocolVersion); + infoObject->SetEarlyDataAccepted(channelInfo.earlyDataAccepted); SSLCipherSuiteInfo cipherInfo; if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo, @@ -905,7 +906,7 @@ PreliminaryHandshakeDone(PRFileDesc* fd) status->mHaveCipherSuiteAndProtocol = true; status->mCipherSuite = channelInfo.cipherSuite; status->mProtocolVersion = channelInfo.protocolVersion & 0xFF; - infoObject->SetKEAUsed(cipherInfo.keaType); + infoObject->SetKEAUsed(channelInfo.keaType); infoObject->SetKEAKeyBits(channelInfo.keaKeyBits); infoObject->SetMACAlgorithmUsed(cipherInfo.macAlgorithm); } @@ -966,7 +967,7 @@ CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart) sizeof (cipherInfo)) != SECSuccess) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - " " KEA %d\n", fd, - static_cast(cipherInfo.keaType))); + static_cast(channelInfo.keaType))); return SECSuccess; } @@ -982,10 +983,10 @@ CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart) } // See bug 952863 for why ECDHE is allowed, but DHE (and RSA) are not. - if (cipherInfo.keaType != ssl_kea_ecdh) { + if (channelInfo.keaType != ssl_kea_ecdh) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - " "unsupported KEA %d\n", fd, - static_cast(cipherInfo.keaType))); + static_cast(channelInfo.keaType))); reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED; } @@ -1032,6 +1033,7 @@ CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart) } #if(0) // TenFourFox issue 334 +#error this no longer has correct constants and should not be reenabled static void AccumulateNonECCKeySize(Telemetry::ID probe, uint32_t bits) { @@ -1156,7 +1158,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) { if (rv == SECSuccess) { #if(0) // TenFourFox issue 334 // Get the protocol version for telemetry - // 1=tls1, 2=tls1.1, 3=tls1.2 + // 1=tls1, 2=tls1.1, 3=tls1.2, 4=tls1.3 unsigned int versionEnum = channelInfo.protocolVersion & 0xFF; MOZ_ASSERT(versionEnum > 0); Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum); @@ -1179,16 +1181,16 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) { infoObject->IsFullHandshake() ? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL : Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED, - cipherInfo.keaType); + channelInfo.keaType); #endif DebugOnly KEAUsed; MOZ_ASSERT(NS_SUCCEEDED(infoObject->GetKEAUsed(&KEAUsed)) && - (KEAUsed == cipherInfo.keaType)); + (KEAUsed == channelInfo.keaType)); #if(0) if (infoObject->IsFullHandshake()) { - switch (cipherInfo.keaType) { + switch (channelInfo.keaType) { case ssl_kea_rsa: AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL, channelInfo.keaKeyBits); @@ -1210,7 +1212,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) { cipherInfo.authAlgorithm); // RSA key exchange doesn't use a signature for auth. - if (cipherInfo.keaType != ssl_kea_rsa) { + if (channelInfo.keaType != ssl_kea_rsa) { switch (cipherInfo.authAlgorithm) { case ssl_auth_rsa: AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL, @@ -1241,11 +1243,16 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) { } PRBool siteSupportsSafeRenego; - rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn, - &siteSupportsSafeRenego); - MOZ_ASSERT(rv == SECSuccess); - if (rv != SECSuccess) { - siteSupportsSafeRenego = false; + if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_3) { + rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn, + &siteSupportsSafeRenego); + MOZ_ASSERT(rv == SECSuccess); + if (rv != SECSuccess) { + siteSupportsSafeRenego = false; + } + } else { + // TLS 1.3 dropped support for renegotiation. + siteSupportsSafeRenego = true; } bool renegotiationUnsafe = !siteSupportsSafeRenego && ioLayerHelpers.treatUnsafeNegotiationAsBroken(); diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp index 8ab022f9b..47a819404 100644 --- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -646,6 +646,13 @@ static const CipherPref sCipherPrefs[] = { { "security.ssl3.dhe_rsa_aes_256_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true }, + { "security.tls13.aes_128_gcm_sha256", + TLS_AES_128_GCM_SHA256, true }, + { "security.tls13.chacha20_poly1305_sha256", + TLS_CHACHA20_POLY1305_SHA256, true }, + { "security.tls13.aes_256_gcm_sha384", + TLS_AES_256_GCM_SHA384, true }, + { "security.ssl3.ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA, true, true }, // deprecated (RC4) { "security.ssl3.ecdhe_ecdsa_rc4_128_sha", @@ -730,6 +737,7 @@ static const bool REQUIRE_SAFE_NEGOTIATION_DEFAULT = false; static const bool FALSE_START_ENABLED_DEFAULT = true; static const bool NPN_ENABLED_DEFAULT = true; static const bool ALPN_ENABLED_DEFAULT = false; +static const bool ENABLED_0RTT_DATA_DEFAULT = false; static void ConfigureTLSSessionIdentifiers() @@ -899,7 +907,7 @@ nsNSSComponent::setEnabledTLSVersions() // keep these values in sync with security-prefs.js // 1 means TLS 1.0, 2 means TLS 1.1, etc. static const uint32_t PSM_DEFAULT_MIN_TLS_VERSION = 1; - static const uint32_t PSM_DEFAULT_MAX_TLS_VERSION = 3; + static const uint32_t PSM_DEFAULT_MAX_TLS_VERSION = 4; uint32_t minFromPrefs = Preferences::GetUint("security.tls.version.min", PSM_DEFAULT_MIN_TLS_VERSION); @@ -1091,6 +1099,9 @@ nsNSSComponent::InitializeNSS() SSL_OptionSetDefault(SSL_ENABLE_ALPN, Preferences::GetBool("security.ssl.enable_alpn", ALPN_ENABLED_DEFAULT)); + SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA, + Preferences::GetBool("security.tls.enable_0rtt_data", + ENABLED_0RTT_DATA_DEFAULT)); if (NS_FAILED(InitializeCipherSuite())) { MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("Unable to initialize cipher suite settings\n")); @@ -1306,6 +1317,10 @@ nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic, SSL_OptionSetDefault(SSL_ENABLE_ALPN, Preferences::GetBool("security.ssl.enable_alpn", ALPN_ENABLED_DEFAULT)); + } else if (prefName.EqualsLiteral("security.tls.enable_0rtt_data")) { + SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA, + Preferences::GetBool("security.tls.enable_0rtt_data", + ENABLED_0RTT_DATA_DEFAULT)); } else if (prefName.Equals("security.ssl.disable_session_identifiers")) { ConfigureTLSSessionIdentifiers(); } else if (prefName.EqualsLiteral("security.OCSP.enabled") || diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp index 1362129bc..18b6bb92e 100644 --- a/security/manager/ssl/nsNSSIOLayer.cpp +++ b/security/manager/ssl/nsNSSIOLayer.cpp @@ -61,6 +61,8 @@ using namespace mozilla::psm; namespace { +#define MAX_ALPN_LENGTH 255 + void getSiteKey(const nsACString& hostName, uint16_t port, /*out*/ nsCSubstring& key) @@ -93,6 +95,7 @@ nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags) mRememberClientAuthCertificate(false), mPreliminaryHandshakeDone(false), mNPNCompleted(false), + mEarlyDataAccepted(false), mFalseStartCallbackCalled(false), mFalseStarted(false), mIsFullHandshake(false), @@ -316,6 +319,71 @@ nsNSSSocketInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN) return NS_OK; } +NS_IMETHODIMP +nsNSSSocketInfo::GetAlpnEarlySelection(nsACString& aAlpnSelected) +{ + nsNSSShutDownPreventionLock locker; + if (isAlreadyShutDown() || isPK11LoggedOut()) { + return NS_ERROR_NOT_AVAILABLE; + } + SSLNextProtoState alpnState; + unsigned char chosenAlpn[MAX_ALPN_LENGTH]; + unsigned int chosenAlpnLen; + SECStatus rv = SSL_GetNextProto(mFd, &alpnState, chosenAlpn, &chosenAlpnLen, + AssertedCast(ArrayLength(chosenAlpn))); + + if (rv != SECSuccess || alpnState != SSL_NEXT_PROTO_EARLY_VALUE || + chosenAlpnLen == 0) { + return NS_ERROR_NOT_AVAILABLE; + } + + aAlpnSelected.Assign(BitwiseCast(chosenAlpn), + chosenAlpnLen); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSSocketInfo::GetEarlyDataAccepted(bool* aAccepted) +{ + *aAccepted = mEarlyDataAccepted; + return NS_OK; +} + +void +nsNSSSocketInfo::SetEarlyDataAccepted(bool aAccepted) +{ + mEarlyDataAccepted = aAccepted; +} + +NS_IMETHODIMP +nsNSSSocketInfo::DriveHandshake() +{ + nsNSSShutDownPreventionLock locker; + if (isAlreadyShutDown() || isPK11LoggedOut()) { + return NS_ERROR_NOT_AVAILABLE; + } + if (!mFd) { + return NS_ERROR_FAILURE; + } + PRErrorCode errorCode = GetErrorCode(); + if (errorCode) { + return GetXPCOMFromNSSError(errorCode); + } + + SECStatus rv = SSL_ForceHandshake(mFd); + + if (rv != SECSuccess) { + errorCode = PR_GetError(); + if (errorCode == PR_WOULD_BLOCK_ERROR) { + return NS_BASE_STREAM_WOULD_BLOCK; + } + + SetCanceled(errorCode, PlainErrorMessage); + return GetXPCOMFromNSSError(errorCode); + } + return NS_OK; +} + NS_IMETHODIMP nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval) { @@ -704,7 +772,7 @@ nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString& hostName, mTLSIntoleranceInfo.Put(key, entry); } -uint16_t +void nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName, int16_t port) { @@ -713,12 +781,10 @@ nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName, MutexAutoLock lock(mutex); - uint16_t tolerant = 0; IntoleranceEntry entry; if (mTLSIntoleranceInfo.Get(key, &entry)) { entry.AssertInvariant(); - tolerant = entry.tolerant; entry.intolerant = 0; entry.intoleranceReason = 0; if (entry.strongCipherStatus != StrongCiphersWorked) { @@ -728,8 +794,6 @@ nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName, entry.AssertInvariant(); mTLSIntoleranceInfo.Put(key, entry); } - - return tolerant; } bool @@ -753,49 +817,7 @@ nsSSLIOLayerHelpers::rememberIntolerantAtVersion(const nsACString& hostName, { if (intolerant <= minVersion || fallbackLimitReached(hostName, intolerant)) { // We can't fall back any further. Assume that intolerance isn't the issue. - uint32_t tolerant = forgetIntolerance(hostName, port); - // If we know the server is tolerant at the version, we don't have to - // gather the telemetry. - if (intolerant <= tolerant) { - return false; - } - - uint32_t fallbackLimitBucket = 0; - // added if the version has reached the min version. - if (intolerant <= minVersion) { - switch (minVersion) { - case SSL_LIBRARY_VERSION_TLS_1_0: - fallbackLimitBucket += 1; - break; - case SSL_LIBRARY_VERSION_TLS_1_1: - fallbackLimitBucket += 2; - break; - case SSL_LIBRARY_VERSION_TLS_1_2: - fallbackLimitBucket += 3; - break; - } - } - // added if the version has reached the fallback limit. - if (intolerant <= mVersionFallbackLimit) { - switch (mVersionFallbackLimit) { - case SSL_LIBRARY_VERSION_TLS_1_0: - fallbackLimitBucket += 4; - break; - case SSL_LIBRARY_VERSION_TLS_1_1: - fallbackLimitBucket += 8; - break; - case SSL_LIBRARY_VERSION_TLS_1_2: - fallbackLimitBucket += 12; - break; - } - } -#if(0) - if (fallbackLimitBucket) { - Telemetry::Accumulate(Telemetry::SSL_FALLBACK_LIMIT_REACHED, - fallbackLimitBucket); - } -#endif - + forgetIntolerance(hostName, port); return false; } @@ -1047,6 +1069,7 @@ class SSLErrorRunnable : public SyncRunnableBase namespace { +#if(0) uint32_t tlsIntoleranceTelemetryBucket(PRErrorCode err) { // returns a numeric code for where we track various errors in telemetry @@ -1065,9 +1088,11 @@ uint32_t tlsIntoleranceTelemetryBucket(PRErrorCode err) case SSL_ERROR_DECODE_ERROR_ALERT: return 14; case PR_CONNECT_RESET_ERROR: return 16; case PR_END_OF_FILE_ERROR: return 17; + case SSL_ERROR_INTERNAL_ERROR_ALERT: return 18; default: return 0; } } +#endif bool retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo) @@ -1143,12 +1168,13 @@ retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo) return false; } +#if(0) +#error doesn't support TLS 1.3 uint32_t reason = tlsIntoleranceTelemetryBucket(err); if (reason == 0) { return false; } -#if(0) Telemetry::ID pre; Telemetry::ID post; switch (range.max) { @@ -2564,8 +2590,11 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS, if (range.max < maxEnabledVersion) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd)); - if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) { - return NS_ERROR_FAILURE; + // Some servers will choke if we send the fallback SCSV with TLS 1.2. + if (range.max < SSL_LIBRARY_VERSION_TLS_1_2) { + if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) { + return NS_ERROR_FAILURE; + } } } diff --git a/security/manager/ssl/nsNSSIOLayer.h b/security/manager/ssl/nsNSSIOLayer.h index f3646c094..ba966c420 100644 --- a/security/manager/ssl/nsNSSIOLayer.h +++ b/security/manager/ssl/nsNSSIOLayer.h @@ -52,6 +52,7 @@ public: const nsNSSShutDownPreventionLock& proofOfLock); void SetNegotiatedNPN(const char* value, uint32_t length); + void SetEarlyDataAccepted(bool aAccepted); void SetHandshakeCompleted(); void NoteTimeUntilReady(); @@ -139,6 +140,7 @@ private: nsCString mNegotiatedNPN; bool mNPNCompleted; + bool mEarlyDataAccepted; bool mFalseStartCallbackCalled; bool mFalseStarted; bool mIsFullHandshake; @@ -216,9 +218,7 @@ public: PRErrorCode intoleranceReason); bool rememberStrongCiphersFailed(const nsACString& hostName, int16_t port, PRErrorCode intoleranceReason); - // returns the known tolerant version - // or 0 if there is no known tolerant version - uint16_t forgetIntolerance(const nsACString& hostname, int16_t port); + void forgetIntolerance(const nsACString& hostname, int16_t port); void adjustForTLSIntolerance(const nsACString& hostname, int16_t port, /*in/out*/ SSLVersionRange& range, /*out*/ StrongCipherStatus& strongCipherStatus); diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp index 6f8af253a..8059e0155 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp @@ -1090,7 +1090,15 @@ NS_IMETHODIMP nsDocLoader::OnStatus(nsIRequest* aRequest, nsISupports* ctxt, if (!sbs) return NS_ERROR_FAILURE; nsXPIDLString msg; - nsresult rv = sbs->FormatStatusMessage(aStatus, aStatusArg, + /* TenFourFox issue 590. Map NS_NET_STATUS_TLS_HANDSHAKE_STARTING and + NS_NET_STATUS_TLS_HANDSHAKE_ENDED to NS_NET_STATUS_CONNECTED_TO so + that we don't instantly invalidate all our locales. See also + netwerk/locales/en-US/necko.properties XXX */ + nsresult rv = sbs->FormatStatusMessage( + (aStatus == NS_NET_STATUS_TLS_HANDSHAKE_STARTING || + aStatus == NS_NET_STATUS_TLS_HANDSHAKE_ENDED) ? + NS_NET_STATUS_CONNECTED_TO : aStatus, + aStatusArg, getter_Copies(msg)); if (NS_FAILED(rv)) return rv; diff --git a/xpcom/base/ErrorList.h b/xpcom/base/ErrorList.h index 1610caf9e..63586f59e 100644 --- a/xpcom/base/ErrorList.h +++ b/xpcom/base/ErrorList.h @@ -313,13 +313,15 @@ ERROR(NS_NET_STATUS_WRITING, FAILURE(9)), /* nsISocketTransport */ - ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)), - ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)), - ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)), - ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)), - ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)), - ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)), - ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)), + ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)), + ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)), + ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)), + ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)), + ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)), + ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED, FAILURE(13)), + ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)), + ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)), + ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)), /* nsIInterceptedChannel */ /* Generic error for non-specific failures during service worker interception */