From: uazo Date: Thu, 24 Mar 2022 10:08:00 +0000 Subject: Disable TLS resumption Disable resumption feature for all HTTPS and QUIC connections; the feature could be used to track users even without cookies. Sessions are not currently saved to disk in Chromium (although there is support for it) but are long enough to constitute a privacy risk (2h for TLS 1.2 and 7 days for TLS 1.3) if user does not frequently close the browser. Since session information is not kept in the HTTP cache it is not cleared when deleting navigation data (although it is possible to clear it by selecting "passwords"). Two new user configurable flags are introduced: * kDisableTLSResumption, active by default * kLogTLSResumption, that would allow to find in logcat reused sessions in lines matching "SSL Log:" See also: * https://arxiv.org/abs/1810.07304 Original License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html --- .../about_flags_cc/Disable-TLS-resumption.inc | 12 ++++ .../features_cc/Disable-TLS-resumption.inc | 7 ++ .../features_h/Disable-TLS-resumption.inc | 5 ++ net/http/http_network_session.cc | 1 + net/quic/quic_session_pool.cc | 35 +++++++++- net/socket/ssl_client_socket_impl.cc | 68 +++++++++++++++++++ net/socket/ssl_client_socket_impl.h | 2 + 7 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 cromite_flags/chrome/browser/about_flags_cc/Disable-TLS-resumption.inc create mode 100644 cromite_flags/net/base/features_cc/Disable-TLS-resumption.inc create mode 100644 cromite_flags/net/base/features_h/Disable-TLS-resumption.inc diff --git a/cromite_flags/chrome/browser/about_flags_cc/Disable-TLS-resumption.inc b/cromite_flags/chrome/browser/about_flags_cc/Disable-TLS-resumption.inc new file mode 100644 --- /dev/null +++ b/cromite_flags/chrome/browser/about_flags_cc/Disable-TLS-resumption.inc @@ -0,0 +1,12 @@ +#ifdef FLAG_SECTION + + {"disable-tls-resumption", + "Disable TLS Session Resumption", + "Disable TLS session resumption.", kOsAll, + FEATURE_VALUE_TYPE(net::features::kDisableTLSResumption)}, + {"log-tls-resumption", + "Log TLS Session Resumption", + "Log TLS Session Resumption", kOsAll, + FEATURE_VALUE_TYPE(net::features::kLogTLSResumption)}, + +#endif diff --git a/cromite_flags/net/base/features_cc/Disable-TLS-resumption.inc b/cromite_flags/net/base/features_cc/Disable-TLS-resumption.inc new file mode 100644 --- /dev/null +++ b/cromite_flags/net/base/features_cc/Disable-TLS-resumption.inc @@ -0,0 +1,7 @@ +CROMITE_FEATURE(kDisableTLSResumption, + "DisableTLSResumption", + base::FEATURE_ENABLED_BY_DEFAULT); + +CROMITE_FEATURE(kLogTLSResumption, + "LogTLSResumption", + base::FEATURE_DISABLED_BY_DEFAULT); diff --git a/cromite_flags/net/base/features_h/Disable-TLS-resumption.inc b/cromite_flags/net/base/features_h/Disable-TLS-resumption.inc new file mode 100644 --- /dev/null +++ b/cromite_flags/net/base/features_h/Disable-TLS-resumption.inc @@ -0,0 +1,5 @@ +// Disables TLS resumption. +NET_EXPORT BASE_DECLARE_FEATURE(kDisableTLSResumption); + +// Log TLS resumption. +NET_EXPORT BASE_DECLARE_FEATURE(kLogTLSResumption); diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -217,6 +217,7 @@ HttpNetworkSession::HttpNetworkSession(const HttpNetworkSessionParams& params, next_protos_.push_back(NextProto::kProtoHTTP11); + DCHECK(context.quic_context->params()->max_server_configs_stored_in_properties == 0); http_server_properties_->SetMaxServerConfigsStoredInProperties( context.quic_context->params()->max_server_configs_stored_in_properties); http_server_properties_->SetBrokenAlternativeServicesDelayParams( diff --git a/net/quic/quic_session_pool.cc b/net/quic/quic_session_pool.cc --- a/net/quic/quic_session_pool.cc +++ b/net/quic/quic_session_pool.cc @@ -384,6 +384,38 @@ base::TimeDelta GetAdditionalDelayForMainJob() { } // namespace +class BromiteSessionCache : public quic::QuicClientSessionCache { + public: + BromiteSessionCache() = default; + ~BromiteSessionCache() override = default; + + void Insert(const quic::QuicServerId& server_id, + bssl::UniquePtr session, + const quic::TransportParameters& params, + const quic::ApplicationState* application_state) override { + if (base::FeatureList::IsEnabled(net::features::kDisableTLSResumption)) + SSL_SESSION_set_timeout(session.get(), 0); + if (base::FeatureList::IsEnabled(net::features::kLogTLSResumption)) { + LOG(INFO) << "SSL Log: new quic session created " + << server_id.host(); + } + quic::QuicClientSessionCache::Insert(server_id, + std::move(session), params, application_state); + } + + std::unique_ptr Lookup( + const quic::QuicServerId& server_id, quic::QuicWallTime now, + const SSL_CTX* ctx) override { + auto value = quic::QuicClientSessionCache::Lookup(server_id, now, ctx); + if (value != nullptr && + base::FeatureList::IsEnabled(net::features::kLogTLSResumption)) { + LOG(INFO) << "SSL Log: QUIC session resumed " + << server_id.host(); + } + return value; + } +}; + QuicSessionRequest::QuicSessionRequest(QuicSessionPool* pool) : pool_(pool) {} QuicSessionRequest::~QuicSessionRequest() { @@ -2484,8 +2516,7 @@ QuicSessionPool::CreateCryptoConfigHandle(QuicCryptoClientConfigKey key) { cert_verifier_, transport_security_state_, sct_auditing_delegate_, std::move(hostnames_to_allow_unknown_roots), key.network_anonymization_key), - std::make_unique( - kDefaultQuicSessionCacheSize), + std::make_unique(), kDefaultQuicSessionCacheSize, this); quic::QuicCryptoClientConfig* crypto_config = crypto_config_owner->config(); diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc --- a/net/socket/ssl_client_socket_impl.cc +++ b/net/socket/ssl_client_socket_impl.cc @@ -31,6 +31,7 @@ #include "base/strings/string_view_util.h" #include "base/synchronization/lock.h" #include "base/task/sequenced_task_runner.h" +#include "base/types/fixed_array.h" #include "base/trace_event/trace_event.h" #include "base/values.h" #include "build/build_config.h" @@ -292,7 +293,41 @@ SSLClientSocketImpl::SSLClientSocketImpl( CHECK(context_); } +void SSLClientSocketImpl::Log_ssl_session_data(const std::string& tag, SSL_SESSION* session) { + if (session == NULL) { + LOG(INFO) << "SSL Log: " + << tag + << " host: " << host_and_port_.ToString() + << " NIK: " << ssl_config_.network_anonymization_key.ToDebugString(); + return; + } + + unsigned len; + const uint8_t *session_id = SSL_SESSION_get_id(session, &len); + base::FixedArray session_id_bytes(len); + for (unsigned i = 0; i < len; i++) { + session_id_bytes[i] = UNSAFE_TODO(session_id[i]); + } + + const uint8_t *ticket; + size_t ticklen; + SSL_SESSION_get0_ticket(session, &ticket, &ticklen); + base::FixedArray ticket_bytes(ticklen); + for (size_t i = 0; i < ticklen; i++) { + ticket_bytes[i] = UNSAFE_TODO(ticket[i]); + } + + LOG(INFO) << "SSL Log: " + << tag + << " host: " << host_and_port_.ToString() + << " NIK: " << ssl_config_.network_anonymization_key.ToDebugString() + << " sessionid: " << base::HexEncode(base::span(session_id_bytes)) + << (ticklen > 0 ? " ticket:" + base::HexEncode(ticket_bytes) : ""); +} + SSLClientSocketImpl::~SSLClientSocketImpl() { + if (base::FeatureList::IsEnabled(net::features::kLogTLSResumption)) + Log_ssl_session_data("Disconnect", NULL); Disconnect(); } @@ -710,6 +745,8 @@ int SSLClientSocketImpl::Init() { } if (session) SSL_set_session(ssl_.get(), session.get()); + if (session && base::FeatureList::IsEnabled(net::features::kLogTLSResumption)) + Log_ssl_session_data("Old session resumed", session.get()); } transport_adapter_ = std::make_unique( @@ -994,6 +1031,35 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) { : SSLHandshakeDetails::kTLS13Full; } } + if (base::FeatureList::IsEnabled(net::features::kLogTLSResumption)) { + switch(details) + { + case SSLHandshakeDetails::kTLS13Early: + Log_ssl_session_data("SSL Log: session reused: kTLS13Early mode", NULL); + break; + case SSLHandshakeDetails::kTLS13ResumeWithHelloRetryRequest: + Log_ssl_session_data("SSL Log: session reused: kTLS13ResumeWithHelloRetryRequest mode", NULL); + break; + case SSLHandshakeDetails::kTLS13Resume: + Log_ssl_session_data("SSL Log: session reused: kTLS13Resume mode", NULL); + break; + case SSLHandshakeDetails::kTLS12Resume: + Log_ssl_session_data("SSL Log: session reused: kTLS12Resume mode", NULL); + break; + case SSLHandshakeDetails::kTLS12Full: + Log_ssl_session_data("SSL Log: session reused: kTLS12Full mode", NULL); + break; + case SSLHandshakeDetails::kTLS12FalseStart: + Log_ssl_session_data("SSL Log: session reused: kTLS12FalseStart mode", NULL); + break; + case SSLHandshakeDetails::kTLS13Full: + Log_ssl_session_data("SSL Log: session reused: kTLS13Full mode", NULL); + break; + case SSLHandshakeDetails::kTLS13FullWithHelloRetryRequest: + Log_ssl_session_data("SSL Log: session reused: kTLS13FullWithHelloRetryRequest mode", NULL); + break; + } + } UMA_HISTOGRAM_ENUMERATION("Net.SSLHandshakeDetails", details); // Measure TLS connections that implement the renegotiation_info and EMS @@ -1624,6 +1690,8 @@ bool SSLClientSocketImpl::IsRenegotiationAllowed() const { } bool SSLClientSocketImpl::IsCachingEnabled() const { + if (base::FeatureList::IsEnabled(net::features::kDisableTLSResumption)) + return false; return context_->ssl_client_session_cache() != nullptr; } diff --git a/net/socket/ssl_client_socket_impl.h b/net/socket/ssl_client_socket_impl.h --- a/net/socket/ssl_client_socket_impl.h +++ b/net/socket/ssl_client_socket_impl.h @@ -128,6 +128,8 @@ class NET_EXPORT_PRIVATE SSLClientSocketImpl friend class SSLContext; FRIEND_TEST_ALL_PREFIXES(SSLClientSocketTest, ParseServerTrustAnchorIDs); + void Log_ssl_session_data(const std::string& tag, SSL_SESSION* session); + int Init(); void DoReadCallback(int result); void DoWriteCallback(int result); --