0

Add TLS13EarlyDataEnabled enterprise policy

The policy setting is plumbed via SystemNetworkContextManager.

Bug: 41272059
Change-Id: Ic33ff84d223b63c54db7db0e6ecaed80599dc5c0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6528294
Commit-Queue: Kenichi Ishibashi <bashi@chromium.org>
Reviewed-by: Takashi Toyoshima <toyoshim@chromium.org>
Reviewed-by: Sergey Poromov <poromov@chromium.org>
Reviewed-by: David Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1461903}
This commit is contained in:
Kenichi Ishibashi
2025-05-18 17:08:02 -07:00
committed by Chromium LUCI CQ
parent eb31723f62
commit e7120ff722
19 changed files with 229 additions and 5 deletions

@ -631,6 +631,12 @@ SystemNetworkContextManager::SystemNetworkContextManager(
base::BindRepeating(
&SystemNetworkContextManager::UpdateIPv6ReachabilityOverrideEnabled,
base::Unretained(this)));
pref_change_registrar_.Add(
prefs::kTLS13EarlyDataEnabled,
base::BindRepeating(
&SystemNetworkContextManager::UpdateTLS13EarlyDataEnabled,
base::Unretained(this)));
}
SystemNetworkContextManager::~SystemNetworkContextManager() {
@ -693,6 +699,9 @@ void SystemNetworkContextManager::RegisterPrefs(PrefRegistrySimple* registry) {
#endif // BUILDFLAG(IS_LINUX)
registry->RegisterBooleanPref(prefs::kIPv6ReachabilityOverrideEnabled, false);
// Default value doesn't matter since this pref is only used when managed.
registry->RegisterBooleanPref(prefs::kTLS13EarlyDataEnabled, false);
}
// static
@ -1058,6 +1067,16 @@ void SystemNetworkContextManager::UpdateIPv6ReachabilityOverrideEnabled() {
content::GetNetworkService()->SetIPv6ReachabilityOverride(value);
}
void SystemNetworkContextManager::UpdateTLS13EarlyDataEnabled() {
bool is_managed =
local_state_->IsManagedPreference(prefs::kTLS13EarlyDataEnabled);
bool value =
is_managed
? local_state_->GetBoolean(prefs::kTLS13EarlyDataEnabled)
: base::FeatureList::IsEnabled(net::features::kEnableTLS13EarlyData);
content::GetNetworkService()->SetTLS13EarlyDataEnabled(value);
}
// static
StubResolverConfigReader*
SystemNetworkContextManager::stub_resolver_config_reader_for_testing_ =

@ -235,6 +235,8 @@ class SystemNetworkContextManager {
void UpdateIPv6ReachabilityOverrideEnabled();
void UpdateTLS13EarlyDataEnabled();
// The PrefService to retrieve all the pref values.
raw_ptr<PrefService> local_state_;

@ -1024,6 +1024,9 @@ const PolicyToPreferenceMapEntry kSimplePolicyMap[] = {
{ key::kPostQuantumKeyAgreementEnabled,
prefs::kPostQuantumKeyAgreementEnabled,
base::Value::Type::BOOLEAN },
{ key::kTLS13EarlyDataEnabled,
prefs::kTLS13EarlyDataEnabled,
base::Value::Type::BOOLEAN },
{ key::kSSLErrorOverrideAllowed,
prefs::kSSLErrorOverrideAllowed,
base::Value::Type::BOOLEAN },

@ -36,7 +36,6 @@
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "url/gurl.h"
namespace policy {
class SSLPolicyTest : public PolicyTest {
@ -343,4 +342,107 @@ IN_PROC_BROWSER_TEST_F(ECHPolicyTest, ECHEnabledPolicy) {
EXPECT_EQ(base::ASCIIToUTF16(kECHFailureTitle), result.title);
}
// TLS13EarlyDataPolicyTest relies on the fact that EmbeddedTestServer
// uses HTTP/1.1 without connection reuse (unless the protocol is explicitly
// specified). If EmbeddedTestServer ever gains connection reuse by default,
// we'll need to force it off.
class TLS13EarlyDataPolicyTest : public SSLPolicyTest,
public ::testing::WithParamInterface<bool> {
public:
static constexpr std::string_view kHostname = "a.test";
static constexpr std::string_view kEarlyDataAcceptedTitle = "accepted";
static constexpr std::string_view kEarlyDataNotAcceptedTitle = "not accepted";
TLS13EarlyDataPolicyTest()
: test_server_{net::EmbeddedTestServer::TYPE_HTTPS} {
std::vector<base::test::FeatureRef> enabled_features;
std::vector<base::test::FeatureRef> disabled_features;
if (GetParam()) {
enabled_features.emplace_back(net::features::kHappyEyeballsV3);
} else {
disabled_features.emplace_back(net::features::kHappyEyeballsV3);
}
disabled_features.emplace_back(net::features::kEnableTLS13EarlyData);
feature_list_.InitWithFeatures(enabled_features, disabled_features);
}
void SetUpOnMainThread() override {
net::SSLServerConfig server_config;
server_config.early_data_enabled = true;
test_server_.RegisterRequestHandler(
base::BindRepeating(&TLS13EarlyDataPolicyTest::HandleRequest));
test_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES,
server_config);
ASSERT_TRUE(test_server_.Start());
host_resolver()->AddRule(kHostname, "127.0.0.1");
}
GURL GetURL(std::string_view path) {
return test_server_.GetURL(kHostname, path);
}
private:
static std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
const net::test_server::HttpRequest& request) {
auto response = std::make_unique<net::test_server::BasicHttpResponse>();
response->set_content_type("text/html; charset=utf-8");
response->AddCustomHeader("Connection", "close");
if (request.ssl_info->early_data_accepted) {
response->set_content(
base::StrCat({"<title>", kEarlyDataAcceptedTitle, "</title>"}));
} else {
response->set_content(
base::StrCat({"<title>", kEarlyDataNotAcceptedTitle, "</title>"}));
}
return response;
}
base::test::ScopedFeatureList feature_list_;
net::EmbeddedTestServer test_server_;
};
INSTANTIATE_TEST_SUITE_P(, TLS13EarlyDataPolicyTest, ::testing::Bool());
IN_PROC_BROWSER_TEST_P(TLS13EarlyDataPolicyTest,
TLS13EarlyDataPolicyNoOverride) {
EXPECT_FALSE(GetBooleanPref(prefs::kTLS13EarlyDataEnabled));
LoadResult result = LoadPage(GetURL("/warm-up"));
EXPECT_TRUE(result.success);
result = LoadPage(GetURL("/test-request"));
EXPECT_TRUE(result.success);
EXPECT_EQ(result.title, base::ASCIIToUTF16(kEarlyDataNotAcceptedTitle));
}
IN_PROC_BROWSER_TEST_P(TLS13EarlyDataPolicyTest, TLS13EarlyDataPolicyEnable) {
PolicyMap policies;
SetPolicy(&policies, key::kTLS13EarlyDataEnabled, base::Value(true));
UpdateProviderPolicy(policies);
EXPECT_TRUE(GetBooleanPref(prefs::kTLS13EarlyDataEnabled));
content::FlushNetworkServiceInstanceForTesting();
LoadResult result = LoadPage(GetURL("/warm-up"));
EXPECT_TRUE(result.success);
result = LoadPage(GetURL("/test-request"));
EXPECT_TRUE(result.success);
EXPECT_EQ(result.title, base::ASCIIToUTF16(kEarlyDataAcceptedTitle));
}
IN_PROC_BROWSER_TEST_P(TLS13EarlyDataPolicyTest, TLS13EarlyDataPolicyDisable) {
PolicyMap policies;
SetPolicy(&policies, key::kTLS13EarlyDataEnabled, base::Value(false));
UpdateProviderPolicy(policies);
EXPECT_FALSE(GetBooleanPref(prefs::kTLS13EarlyDataEnabled));
LoadResult result = LoadPage(GetURL("/warm-up"));
EXPECT_TRUE(result.success);
result = LoadPage(GetURL("/test-request"));
EXPECT_TRUE(result.success);
EXPECT_EQ(result.title, base::ASCIIToUTF16(kEarlyDataNotAcceptedTitle));
}
} // namespace policy

@ -2820,6 +2820,9 @@ inline constexpr char kDevicePostQuantumKeyAgreementEnabled[] =
"ssl.device_post_quantum_enabled";
#endif
// Boolean that specifies whether TLS 1.3 Early Data is enabled.
inline constexpr char kTLS13EarlyDataEnabled[] = "ssl.tls13_early_data_enabled";
// If false, disable Encrypted ClientHello (ECH) in TLS connections.
inline constexpr char kEncryptedClientHelloEnabled[] = "ssl.ech_enabled";

@ -1360,6 +1360,7 @@ policies:
1359: NTPFooterManagementNoticeEnabled
1360: NTPFooterExtensionAttributionEnabled
1361: ClearWindowNameForNewBrowsingContextGroup
1362: TLS13EarlyDataEnabled
atomic_groups:
1: Homepage

@ -0,0 +1,41 @@
caption: Enable TLS 1.3 Early Data
default: true
desc: |-
TLS 1.3 Early Data is an extension to TLS 1.3 to send an HTTP request simultaneously with the TLS handshake.
If this policy is not configured, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will follow the default rollout process for TLS 1.3 Early Data.
If it is enabled, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will enable TLS 1.3 Early Data.
If it is disabled, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will not enable TLS 1.3 Early Data.
When the feature is enabled, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> may or may not use TLS 1.3 Early Data depending on server support.
TLS 1.3 Early Data is an established protocol. Existing TLS servers, middleboxes, and security software are expected to either handle or reject TLS 1.3 Early Data without dropping the connection.
However, devices that do not correctly implement TLS may malfunction and disconnect when TLS 1.3 Early Data is in use. If this occurs, administrators should contact the vendor for a fix.
This policy is a temporary measure to control the feature and will be removed afterwards. The policy may be enabled to allow you to test for issues and disabled while issues are being resolved.
example_value: true
features:
dynamic_refresh: true
per_profile: false
future_on:
- fuchsia
items:
- caption: Enable the TLS 1.3 Early Data
value: true
- caption: Disable the TLS 1.3 Early Data
value: false
owners:
- bashi@chromium.org
- blink-network-stack@google.com
schema:
type: boolean
supported_on:
- chrome.*:138-
- chrome_os:138-
- android:138-
tags:
- system-security
type: main

@ -0,0 +1,21 @@
[
{
"os": [
"win",
"linux",
"mac",
"chromeos",
"android",
"fuchsia"
],
"simple_policy_pref_mapping_test": {
"pref_name": "ssl.tls13_early_data_enabled",
"pref_location": "local_state",
"default_value": false,
"values_to_test": [
true,
false
]
}
}
]

@ -381,6 +381,10 @@ void HttpNetworkSession::CloseIdleConnections(const char* net_log_reason_utf8) {
spdy_session_pool_.CloseCurrentIdleSessions(net_log_reason_utf8);
}
void HttpNetworkSession::SetTLS13EarlyDataEnabled(bool enabled) {
params_.enable_early_data = enabled;
}
bool HttpNetworkSession::IsQuicEnabled() const {
return params_.enable_quic;
}

@ -295,6 +295,8 @@ class NET_EXPORT HttpNetworkSession : public base::PowerSuspendObserver {
return application_settings_;
}
void SetTLS13EarlyDataEnabled(bool enabled);
// Evaluates if QUIC is enabled for new streams.
bool IsQuicEnabled() const;

@ -190,8 +190,6 @@ HttpStreamPool::AttemptManager::AttemptManager(Group* group, NetLog* net_log)
ssl_config.privacy_mode = stream_key().privacy_mode();
ssl_config.disable_cert_verification_network_fetches =
stream_key().disable_cert_network_fetches();
ssl_config.early_data_enabled =
http_network_session()->params().enable_early_data;
ssl_config.alpn_protos = http_network_session()->GetAlpnProtos();
ssl_config.application_settings =
@ -445,8 +443,12 @@ HttpStreamPool::AttemptManager::GetSSLConfig(const IPEndPoint& ip_endpoint) {
CHECK(service_endpoint_request_);
CHECK(service_endpoint_request_->EndpointsCryptoReady());
SSLConfig ssl_config = *base_ssl_config_;
ssl_config.early_data_enabled =
http_network_session()->params().enable_early_data;
if (!IsEchEnabled()) {
return *base_ssl_config_;
return ssl_config;
}
const bool svcb_optional = IsSvcbOptional();
@ -458,7 +460,6 @@ HttpStreamPool::AttemptManager::GetSSLConfig(const IPEndPoint& ip_endpoint) {
? endpoint.ipv4_endpoints
: endpoint.ipv6_endpoints;
if (base::Contains(ip_endpoints, ip_endpoint)) {
SSLConfig ssl_config = *base_ssl_config_;
ssl_config.ech_config_list = endpoint.metadata.ech_config_list;
return ssl_config;
}

@ -588,6 +588,7 @@ bool SSLServerContextImpl::SocketImpl::GetSSLInfo(SSLInfo* ssl_info) {
&ssl_info->connection_status);
ssl_info->early_data_received = early_data_received_;
ssl_info->early_data_accepted = SSL_early_data_accepted(ssl_.get());
ssl_info->encrypted_client_hello = SSL_ech_accepted(ssl_.get());
ssl_info->handshake_type = SSL_session_reused(ssl_.get())
? SSLInfo::HANDSHAKE_RESUME

@ -83,6 +83,10 @@ class NET_EXPORT SSLInfo {
// set for server sockets.
bool early_data_received = false;
// True if early data was accepted on the server. This field is only
// set for server sockets.
bool early_data_accepted = false;
// True if the connection negotiated the Encrypted ClientHello extension.
bool encrypted_client_hello = false;

@ -1219,6 +1219,12 @@ void NetworkContext::OnProxyLookupComplete(
proxy_lookup_requests_.erase(it);
}
void NetworkContext::SetTLS13EarlyDataEnabled(bool enabled) {
url_request_context_->http_transaction_factory()
->GetSession()
->SetTLS13EarlyDataEnabled(enabled);
}
void NetworkContext::DisableQuic() {
url_request_context_->http_transaction_factory()->GetSession()->DisableQuic();
}

@ -580,6 +580,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
mojo::PendingReceiver<network::mojom::DeviceBoundSessionManager>
device_bound_session_manager) override;
void SetTLS13EarlyDataEnabled(bool enabled);
// Destroys |request| when a proxy lookup completes.
void OnProxyLookupComplete(ProxyLookupRequest* proxy_lookup_request);

@ -1070,6 +1070,12 @@ void NetworkService::InterceptUrlLoaderForBodyDecoding(
{base::TaskPriority::USER_BLOCKING}));
}
void NetworkService::SetTLS13EarlyDataEnabled(bool enabled) {
for (NetworkContext* network_context : network_contexts_) {
network_context->SetTLS13EarlyDataEnabled(enabled);
}
}
void NetworkService::StartNetLogBounded(base::File file,
uint64_t max_total_size,
net::NetLogCaptureMode capture_mode,

@ -271,6 +271,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
mojo::PendingRemote<network::mojom::URLLoaderClient>
dest_url_loader_client) override;
void SetTLS13EarlyDataEnabled(bool enabled) override;
void StartNetLogBounded(base::File file,
uint64_t max_total_size,
net::NetLogCaptureMode capture_mode,

@ -476,4 +476,7 @@ interface NetworkService {
pending_receiver<URLLoaderClient> source_url_loader_client,
pending_receiver<URLLoader> dest_url_loader,
pending_remote<URLLoaderClient> dest_url_loader_client);
// Enables or disables TLS 1.3 Early Data.
SetTLS13EarlyDataEnabled(bool enabled);
};

@ -2230,6 +2230,7 @@ chromium-metrics-reviews@google.com.
<int value="1359" label="NTPFootermanagementNoticeEnabled"/>
<int value="1360" label="NTPFooterExtensionAttributionEnabled"/>
<int value="1361" label="ClearWindowNameForNewBrowsingContextGroup"/>
<int value="1362" label="TLS13EarlyDataEnabled"/>
</enum>
<enum name="EnterprisePoliciesSources">