Commit 04599ffe authored by Dragana Damjanovic's avatar Dragana Damjanovic
Browse files

Bug 1718520 - Disable early-data if a SSL_ERROR_PROTOCOL_VERSION_ALERT is received r=mt

If amount of origins that have early-data disabled exceeds certain amount, disable early-data for all origins

This is controlled by prefs.

Differential Revision: https://phabricator.services.mozilla.com/D126555
parent fc881130
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -9946,6 +9946,18 @@
  value: true
  mirror: always

# Disable early data on an origin if SSL_ERROR_PROTOCOL_VERSION_ALERT is received
- name: network.http.early_data_disable_on_error
  type: RelaxedAtomicBool
  value: true
  mirror: always

# Disable early data if it fails for more than this number of origins
- name: network.http.early_data_max_error
  type: RelaxedAtomicUint32
  value: 5
  mirror: always

#---------------------------------------------------------------------------
# Prefs starting with "nglayout."
#---------------------------------------------------------------------------
+21 −4
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include "nsStringStream.h"
#include "nsITransportSecurityInfo.h"
#include "mozpkix/pkixnss.h"
#include "sslerr.h"
#include "sslt.h"
#include "NSSErrorsService.h"
#include "TunnelUtils.h"
@@ -490,6 +491,16 @@ bool nsHttpConnection::EnsureNPNComplete() {
  return false;
}

void nsHttpConnection::EarlyDataDone() {
  if (mEarlyDataState == EarlyData::USED) {
    mEarlyDataState = EarlyData::DONE_USED;
  } else if (mEarlyDataState == EarlyData::CANNOT_BE_USED) {
    mEarlyDataState = EarlyData::DONE_CANNOT_BE_USED;
  } else if (mEarlyDataState == EarlyData::NOT_AVAILABLE) {
    mEarlyDataState = EarlyData::DONE_NOT_AVAILABLE;
  }
}

void nsHttpConnection::FinishNPNSetup(bool handshakeSucceeded,
                                      bool hasSecurityInfo) {
  mNPNComplete = true;
@@ -525,7 +536,8 @@ void nsHttpConnection::FinishNPNSetup(bool handshakeSucceeded,
      Reset0RttForSpdy();
    }
  }
  mEarlyDataState = EarlyData::DONE;

  EarlyDataDone();

  if (hasSecurityInfo) {
    // Telemetry for tls failure rate with and without esni;
@@ -863,6 +875,11 @@ void nsHttpConnection::Close(nsresult reason, bool aIsShutdown) {
        mConnInfo && !(mTransactionCaps & NS_HTTP_ERROR_SOFTLY)) {
      gHttpHandler->ClearHostMapping(mConnInfo);
    }
    if (EarlyDataWasAvailable() &&
        (reason ==
         psm::GetXPCOMFromNSSError(SSL_ERROR_PROTOCOL_VERSION_ALERT))) {
      gHttpHandler->Exclude0RttTcp(mConnInfo);
    }

    if (mSocketTransport) {
      mSocketTransport->SetEventSink(nullptr, nullptr);
@@ -911,8 +928,8 @@ nsresult nsHttpConnection::InitSSLParams(bool connectingToProxy,
    return rv;
  }

  // If proxy is use, don't use early-data.
  if (mConnInfo->UsingProxy()) {
  // If proxy is use or 0RTT is excluded for a origin, don't use early-data.
  if (mConnInfo->UsingProxy() || gHttpHandler->Is0RttTcpExcluded(mConnInfo)) {
    ssl->DisableEarlyData();
  }

@@ -2618,7 +2635,7 @@ void nsHttpConnection::HandshakeDoneInternal() {
      (tlsVersion != nsISSLSocketControl::SSL_VERSION_UNKNOWN));

  EarlyDataTelemetry(tlsVersion, earlyDataAccepted);
  mEarlyDataState = EarlyData::DONE;
  EarlyDataDone();

  if (!earlyDataAccepted) {
    LOG(
+9 −1
Original line number Diff line number Diff line
@@ -357,14 +357,22 @@ class nsHttpConnection final : public HttpConnectionBase,
    NOT_AVAILABLE,
    USED,
    CANNOT_BE_USED,
    DONE,
    DONE_NOT_AVAILABLE,
    DONE_USED,
    DONE_CANNOT_BE_USED,
  };
  EarlyData mEarlyDataState{EarlyData::NOT_AVAILABLE};
  bool EarlyDataAvailable() const {
    return mEarlyDataState == EarlyData::USED ||
           mEarlyDataState == EarlyData::CANNOT_BE_USED;
  }
  bool EarlyDataWasAvailable() const {
    return mEarlyDataState != EarlyData::NOT_AVAILABLE &&
           mEarlyDataState != EarlyData::DONE_NOT_AVAILABLE;
  }
  bool EarlyDataUsed() const { return mEarlyDataState == EarlyData::USED; }
  void EarlyDataDone();

  int64_t mContentBytesWritten0RTT{0};
  nsCString mEarlyNegotiatedALPN;
  bool mDid0RTTSpdy{false};
+26 −0
Original line number Diff line number Diff line
@@ -2925,4 +2925,30 @@ bool nsHttpHandler::IsHostExcludedForHTTPSRR(const nsACString& aHost) {
  return mExcludedHostsForHTTPSRRUpgrade.Contains(aHost);
}

void nsHttpHandler::Exclude0RttTcp(const nsHttpConnectionInfo* ci) {
  MOZ_ASSERT(OnSocketThread());

  if (!StaticPrefs::network_http_early_data_disable_on_error() ||
      (mExcluded0RttTcpOrigins.Count() >=
       StaticPrefs::network_http_early_data_max_error())) {
    return;
  }

  mExcluded0RttTcpOrigins.Insert(ci->GetOrigin());
}

bool nsHttpHandler::Is0RttTcpExcluded(const nsHttpConnectionInfo* ci) {
  MOZ_ASSERT(OnSocketThread());
  if (!StaticPrefs::network_http_early_data_disable_on_error()) {
    return false;
  }

  if (mExcluded0RttTcpOrigins.Count() >=
      StaticPrefs::network_http_early_data_max_error()) {
    return true;
  }

  return mExcluded0RttTcpOrigins.Contains(ci->GetOrigin());
}

}  // namespace mozilla::net
+3 −0
Original line number Diff line number Diff line
@@ -833,6 +833,8 @@ class nsHttpHandler final : public nsIHttpProtocolHandler,
  [[nodiscard]] bool IsHttp2Excluded(const nsHttpConnectionInfo* ci);
  void ExcludeHttp3(const nsHttpConnectionInfo* ci);
  [[nodiscard]] bool IsHttp3Excluded(const nsACString& aRoutedHost);
  void Exclude0RttTcp(const nsHttpConnectionInfo* ci);
  [[nodiscard]] bool Is0RttTcpExcluded(const nsHttpConnectionInfo* ci);

  void ExcludeHTTPSRRHost(const nsACString& aHost);
  [[nodiscard]] bool IsHostExcludedForHTTPSRR(const nsACString& aHost);
@@ -840,6 +842,7 @@ class nsHttpHandler final : public nsIHttpProtocolHandler,
 private:
  nsTHashSet<nsCString> mExcludedHttp2Origins;
  nsTHashSet<nsCString> mExcludedHttp3Origins;
  nsTHashSet<nsCString> mExcluded0RttTcpOrigins;
  // A set of hosts that we should not upgrade to HTTPS with HTTPS RR.
  nsTHashSet<nsCString> mExcludedHostsForHTTPSRRUpgrade;