1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <cstdint>
6 #include <vector>
7
8 #include "base/big_endian.h"
9 #include "base/functional/bind.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/memory/scoped_refptr.h"
12 #include "base/strings/strcat.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_piece.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "net/base/features.h"
17 #include "net/base/network_change_notifier.h"
18 #include "net/base/privacy_mode.h"
19 #include "net/base/proxy_server.h"
20 #include "net/dns/context_host_resolver.h"
21 #include "net/dns/dns_client.h"
22 #include "net/dns/dns_config.h"
23 #include "net/dns/dns_query.h"
24 #include "net/dns/dns_test_util.h"
25 #include "net/dns/dns_transaction.h"
26 #include "net/dns/host_resolver.h"
27 #include "net/dns/host_resolver_manager.h"
28 #include "net/dns/host_resolver_proc.h"
29 #include "net/dns/public/dns_config_overrides.h"
30 #include "net/dns/public/dns_over_https_config.h"
31 #include "net/dns/public/secure_dns_mode.h"
32 #include "net/dns/public/secure_dns_policy.h"
33 #include "net/dns/public/util.h"
34 #include "net/http/http_stream_factory_test_util.h"
35 #include "net/log/net_log.h"
36 #include "net/socket/transport_client_socket_pool.h"
37 #include "net/ssl/ssl_config_service.h"
38 #include "net/ssl/test_ssl_config_service.h"
39 #include "net/test/embedded_test_server/embedded_test_server.h"
40 #include "net/test/embedded_test_server/http_request.h"
41 #include "net/test/embedded_test_server/http_response.h"
42 #include "net/test/gtest_util.h"
43 #include "net/test/ssl_test_util.h"
44 #include "net/test/test_doh_server.h"
45 #include "net/test/test_with_task_environment.h"
46 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
47 #include "net/url_request/url_request.h"
48 #include "net/url_request/url_request_context.h"
49 #include "net/url_request/url_request_context_builder.h"
50 #include "net/url_request/url_request_test_util.h"
51 #include "testing/gtest/include/gtest/gtest.h"
52 #include "testing/platform_test.h"
53 #include "third_party/boringssl/src/include/openssl/ssl.h"
54 #include "url/scheme_host_port.h"
55 #include "url/url_constants.h"
56
57 namespace net {
58 namespace {
59
60 using net::test::IsError;
61 using net::test::IsOk;
62
63 const char kDohHostname[] = "doh-server.example";
64 const char kHostname[] = "bar.example.com";
65 const char kTestBody[] = "<html><body>TEST RESPONSE</body></html>";
66
67 class TestHostResolverProc : public HostResolverProc {
68 public:
TestHostResolverProc()69 TestHostResolverProc() : HostResolverProc(nullptr) {}
70
Resolve(const std::string & hostname,AddressFamily address_family,HostResolverFlags host_resolver_flags,AddressList * addrlist,int * os_error)71 int Resolve(const std::string& hostname,
72 AddressFamily address_family,
73 HostResolverFlags host_resolver_flags,
74 AddressList* addrlist,
75 int* os_error) override {
76 insecure_queries_served_++;
77 *addrlist = AddressList::CreateFromIPAddress(IPAddress(127, 0, 0, 1), 0);
78 return OK;
79 }
80
insecure_queries_served()81 uint32_t insecure_queries_served() { return insecure_queries_served_; }
82
83 private:
84 ~TestHostResolverProc() override = default;
85 uint32_t insecure_queries_served_ = 0;
86 };
87
88 // Runs and waits for the DoH probe to complete in automatic mode. The resolver
89 // must have a single DoH server, and the DoH server must serve addresses for
90 // `kDohProbeHostname`.
91 class DohProber : public NetworkChangeNotifier::DNSObserver {
92 public:
DohProber(ContextHostResolver * resolver)93 explicit DohProber(ContextHostResolver* resolver) : resolver_(resolver) {}
94
ProbeAndWaitForCompletion()95 void ProbeAndWaitForCompletion() {
96 std::unique_ptr<HostResolver::ProbeRequest> probe_request =
97 resolver_->CreateDohProbeRequest();
98 EXPECT_THAT(probe_request->Start(), IsError(ERR_IO_PENDING));
99 if (NumAvailableDohServers() == 0) {
100 NetworkChangeNotifier::AddDNSObserver(this);
101 loop_.Run();
102 NetworkChangeNotifier::RemoveDNSObserver(this);
103 }
104 EXPECT_GT(NumAvailableDohServers(), 0u);
105 }
106
OnDNSChanged()107 void OnDNSChanged() override {
108 if (NumAvailableDohServers() > 0) {
109 loop_.Quit();
110 }
111 }
112
113 private:
NumAvailableDohServers()114 size_t NumAvailableDohServers() {
115 ResolveContext* context = resolver_->resolve_context_for_testing();
116 return context->NumAvailableDohServers(
117 context->current_session_for_testing());
118 }
119
120 raw_ptr<ContextHostResolver> resolver_;
121 base::RunLoop loop_;
122 };
123
124 // A test fixture that creates a DoH server with a `URLRequestContext`
125 // configured to use it.
126 class DnsOverHttpsIntegrationTest : public TestWithTaskEnvironment {
127 public:
DnsOverHttpsIntegrationTest()128 DnsOverHttpsIntegrationTest()
129 : host_resolver_proc_(base::MakeRefCounted<TestHostResolverProc>()) {
130 doh_server_.SetHostname(kDohHostname);
131 EXPECT_TRUE(doh_server_.Start());
132
133 // In `kAutomatic` mode, DoH support depends on a probe for
134 // `kDohProbeHostname`.
135 doh_server_.AddAddressRecord(kDohProbeHostname, IPAddress::IPv4Localhost());
136
137 ResetContext();
138 }
139
context()140 URLRequestContext* context() { return request_context_.get(); }
141
ResetContext(SecureDnsMode mode=SecureDnsMode::kSecure)142 void ResetContext(SecureDnsMode mode = SecureDnsMode::kSecure) {
143 // TODO(crbug.com/1252155): Simplify this.
144 HostResolver::ManagerOptions manager_options;
145 // Without a DnsConfig, HostResolverManager will not use DoH, even in
146 // kSecure mode. See https://crbug.com/1251715. However,
147 // DnsClient::BuildEffectiveConfig special-cases overrides that override
148 // everything, so that gets around it. Ideally, we would instead mock out a
149 // system DnsConfig via the usual pathway.
150 manager_options.dns_config_overrides =
151 DnsConfigOverrides::CreateOverridingEverythingWithDefaults();
152 manager_options.dns_config_overrides.secure_dns_mode = mode;
153 manager_options.dns_config_overrides.dns_over_https_config =
154 *DnsOverHttpsConfig::FromString(doh_server_.GetPostOnlyTemplate());
155 manager_options.dns_config_overrides.use_local_ipv6 = true;
156 auto resolver = HostResolver::CreateStandaloneContextResolver(
157 /*net_log=*/nullptr, manager_options);
158
159 // Configure `resolver_` to use `host_resolver_proc_` to resolve
160 // `doh_server_` itself. Additionally, without an explicit HostResolverProc,
161 // HostResolverManager::HaveTestProcOverride disables the built-in DNS
162 // client.
163 auto* resolver_raw = resolver.get();
164 resolver->SetHostResolverSystemParamsForTest(
165 HostResolverSystemTask::Params(host_resolver_proc_, 1));
166
167 auto context_builder = CreateTestURLRequestContextBuilder();
168 context_builder->set_host_resolver(std::move(resolver));
169 auto ssl_config_service =
170 std::make_unique<TestSSLConfigService>(SSLContextConfig());
171 ssl_config_service_ = ssl_config_service.get();
172 context_builder->set_ssl_config_service(std::move(ssl_config_service));
173 request_context_ = context_builder->Build();
174
175 if (mode == SecureDnsMode::kAutomatic) {
176 DohProber prober(resolver_raw);
177 prober.ProbeAndWaitForCompletion();
178 }
179 }
180
AddHostWithEch(const url::SchemeHostPort & host,const IPAddress & address,base::span<const uint8_t> ech_config_list)181 void AddHostWithEch(const url::SchemeHostPort& host,
182 const IPAddress& address,
183 base::span<const uint8_t> ech_config_list) {
184 doh_server_.AddAddressRecord(host.host(), address);
185 doh_server_.AddRecord(BuildTestHttpsServiceRecord(
186 dns_util::GetNameForHttpsQuery(host),
187 /*priority=*/1, /*service_name=*/host.host(),
188 {BuildTestHttpsServiceEchConfigParam(ech_config_list)}));
189 }
190
191 protected:
192 TestDohServer doh_server_;
193 scoped_refptr<net::TestHostResolverProc> host_resolver_proc_;
194 std::unique_ptr<URLRequestContext> request_context_;
195 raw_ptr<TestSSLConfigService> ssl_config_service_;
196 };
197
198 // A convenience wrapper over `DnsOverHttpsIntegrationTest` that also starts an
199 // HTTPS server.
200 class HttpsWithDnsOverHttpsTest : public DnsOverHttpsIntegrationTest {
201 public:
HttpsWithDnsOverHttpsTest()202 HttpsWithDnsOverHttpsTest() {
203 EmbeddedTestServer::ServerCertificateConfig cert_config;
204 cert_config.dns_names = {kHostname};
205 https_server_.SetSSLConfig(cert_config);
206 https_server_.RegisterRequestHandler(
207 base::BindRepeating(&HttpsWithDnsOverHttpsTest::HandleDefaultRequest,
208 base::Unretained(this)));
209 EXPECT_TRUE(https_server_.Start());
210
211 doh_server_.AddAddressRecord(kHostname, IPAddress(127, 0, 0, 1));
212 }
213
HandleDefaultRequest(const test_server::HttpRequest & request)214 std::unique_ptr<test_server::HttpResponse> HandleDefaultRequest(
215 const test_server::HttpRequest& request) {
216 auto http_response = std::make_unique<test_server::BasicHttpResponse>();
217 test_https_requests_served_++;
218 http_response->set_content(kTestBody);
219 http_response->set_content_type("text/html");
220 return std::move(http_response);
221 }
222
223 protected:
224 EmbeddedTestServer https_server_{EmbeddedTestServer::Type::TYPE_HTTPS};
225 uint32_t test_https_requests_served_ = 0;
226 };
227
228 class TestHttpDelegate : public HttpStreamRequest::Delegate {
229 public:
TestHttpDelegate(base::RunLoop * loop)230 explicit TestHttpDelegate(base::RunLoop* loop) : loop_(loop) {}
231 ~TestHttpDelegate() override = default;
OnStreamReady(const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,std::unique_ptr<HttpStream> stream)232 void OnStreamReady(const SSLConfig& used_ssl_config,
233 const ProxyInfo& used_proxy_info,
234 std::unique_ptr<HttpStream> stream) override {
235 stream->Close(false);
236 loop_->Quit();
237 }
238
OnWebSocketHandshakeStreamReady(const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,std::unique_ptr<WebSocketHandshakeStreamBase> stream)239 void OnWebSocketHandshakeStreamReady(
240 const SSLConfig& used_ssl_config,
241 const ProxyInfo& used_proxy_info,
242 std::unique_ptr<WebSocketHandshakeStreamBase> stream) override {}
243
OnBidirectionalStreamImplReady(const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,std::unique_ptr<BidirectionalStreamImpl> stream)244 void OnBidirectionalStreamImplReady(
245 const SSLConfig& used_ssl_config,
246 const ProxyInfo& used_proxy_info,
247 std::unique_ptr<BidirectionalStreamImpl> stream) override {}
248
OnStreamFailed(int status,const NetErrorDetails & net_error_details,const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,ResolveErrorInfo resolve_eror_info)249 void OnStreamFailed(int status,
250 const NetErrorDetails& net_error_details,
251 const SSLConfig& used_ssl_config,
252 const ProxyInfo& used_proxy_info,
253 ResolveErrorInfo resolve_eror_info) override {}
254
OnCertificateError(int status,const SSLConfig & used_ssl_config,const SSLInfo & ssl_info)255 void OnCertificateError(int status,
256 const SSLConfig& used_ssl_config,
257 const SSLInfo& ssl_info) override {}
258
OnNeedsProxyAuth(const HttpResponseInfo & proxy_response,const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,HttpAuthController * auth_controller)259 void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response,
260 const SSLConfig& used_ssl_config,
261 const ProxyInfo& used_proxy_info,
262 HttpAuthController* auth_controller) override {}
263
OnNeedsClientAuth(const SSLConfig & used_ssl_config,SSLCertRequestInfo * cert_info)264 void OnNeedsClientAuth(const SSLConfig& used_ssl_config,
265 SSLCertRequestInfo* cert_info) override {}
266
OnQuicBroken()267 void OnQuicBroken() override {}
268
269 private:
270 raw_ptr<base::RunLoop> loop_;
271 };
272
273 // This test sets up a request which will reenter the connection pools by
274 // triggering a DNS over HTTPS request. It also sets up an idle socket
275 // which was a precondition for the crash we saw in https://crbug.com/830917.
TEST_F(HttpsWithDnsOverHttpsTest,EndToEnd)276 TEST_F(HttpsWithDnsOverHttpsTest, EndToEnd) {
277 // Create and start http server.
278 EmbeddedTestServer http_server(EmbeddedTestServer::Type::TYPE_HTTP);
279 http_server.RegisterRequestHandler(
280 base::BindRepeating(&HttpsWithDnsOverHttpsTest::HandleDefaultRequest,
281 base::Unretained(this)));
282 EXPECT_TRUE(http_server.Start());
283
284 // Set up an idle socket.
285 HttpTransactionFactory* transaction_factory =
286 request_context_->http_transaction_factory();
287 HttpStreamFactory::JobFactory default_job_factory;
288 HttpNetworkSession* network_session = transaction_factory->GetSession();
289 base::RunLoop loop;
290 TestHttpDelegate request_delegate(&loop);
291
292 HttpStreamFactory* factory = network_session->http_stream_factory();
293 HttpRequestInfo request_info;
294 request_info.method = "GET";
295 request_info.url = http_server.GetURL("localhost", "/preconnect");
296
297 std::unique_ptr<HttpStreamRequest> request(factory->RequestStream(
298 request_info, DEFAULT_PRIORITY, SSLConfig(), &request_delegate, false,
299 false, NetLogWithSource()));
300 loop.Run();
301
302 ClientSocketPool::GroupId group_id(
303 url::SchemeHostPort(request_info.url), PrivacyMode::PRIVACY_MODE_DISABLED,
304 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow);
305 EXPECT_EQ(network_session
306 ->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
307 ProxyChain::Direct())
308 ->IdleSocketCountInGroup(group_id),
309 1u);
310
311 // The domain "localhost" is resolved locally, so no DNS lookups should have
312 // occurred.
313 EXPECT_EQ(doh_server_.QueriesServed(), 0);
314 EXPECT_EQ(host_resolver_proc_->insecure_queries_served(), 0u);
315 // A stream was established, but no HTTPS request has been made yet.
316 EXPECT_EQ(test_https_requests_served_, 0u);
317
318 // Make a request that will trigger a DoH query as well.
319 TestDelegate d;
320 GURL main_url = https_server_.GetURL(kHostname, "/test");
321 std::unique_ptr<URLRequest> req(context()->CreateRequest(
322 main_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
323 req->Start();
324 base::RunLoop().Run();
325 EXPECT_TRUE(https_server_.ShutdownAndWaitUntilComplete());
326 EXPECT_TRUE(http_server.ShutdownAndWaitUntilComplete());
327 EXPECT_TRUE(doh_server_.ShutdownAndWaitUntilComplete());
328
329 // There should be three DoH lookups for kHostname (A, AAAA, and HTTPS).
330 EXPECT_EQ(doh_server_.QueriesServed(), 3);
331 // The requests to the DoH server are pooled, so there should only be one
332 // insecure lookup for the DoH server hostname.
333 EXPECT_EQ(host_resolver_proc_->insecure_queries_served(), 1u);
334 // There should be one non-DoH HTTPS request for the connection to kHostname.
335 EXPECT_EQ(test_https_requests_served_, 1u);
336
337 EXPECT_TRUE(d.response_completed());
338 EXPECT_EQ(d.request_status(), 0);
339 EXPECT_EQ(d.data_received(), kTestBody);
340 }
341
TEST_F(HttpsWithDnsOverHttpsTest,EndToEndFail)342 TEST_F(HttpsWithDnsOverHttpsTest, EndToEndFail) {
343 // Fail all DoH requests.
344 doh_server_.SetFailRequests(true);
345
346 // Make a request that will trigger a DoH query.
347 TestDelegate d;
348 GURL main_url = https_server_.GetURL(kHostname, "/test");
349 std::unique_ptr<URLRequest> req(context()->CreateRequest(
350 main_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
351 req->Start();
352 base::RunLoop().Run();
353 EXPECT_TRUE(https_server_.ShutdownAndWaitUntilComplete());
354 EXPECT_TRUE(doh_server_.ShutdownAndWaitUntilComplete());
355
356 // No HTTPS connection to the test server will be attempted due to the
357 // host resolution error.
358 EXPECT_EQ(test_https_requests_served_, 0u);
359
360 EXPECT_TRUE(d.response_completed());
361 EXPECT_EQ(d.request_status(), net::ERR_NAME_NOT_RESOLVED);
362
363 const auto& resolve_error_info = req->response_info().resolve_error_info;
364 EXPECT_TRUE(resolve_error_info.is_secure_network_error);
365 EXPECT_EQ(resolve_error_info.error, net::ERR_DNS_MALFORMED_RESPONSE);
366 }
367
368 // An end-to-end test of the HTTPS upgrade behavior.
TEST_F(HttpsWithDnsOverHttpsTest,HttpsUpgrade)369 TEST_F(HttpsWithDnsOverHttpsTest, HttpsUpgrade) {
370 base::test::ScopedFeatureList features;
371 features.InitAndEnableFeatureWithParameters(
372 features::kUseDnsHttpsSvcb,
373 {// Disable timeouts.
374 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
375 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
376 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}});
377 ResetContext();
378
379 GURL https_url = https_server_.GetURL(kHostname, "/test");
380 EXPECT_TRUE(https_url.SchemeIs(url::kHttpsScheme));
381 GURL::Replacements replacements;
382 replacements.SetSchemeStr(url::kHttpScheme);
383 GURL http_url = https_url.ReplaceComponents(replacements);
384
385 // `service_name` is `kHostname` rather than "." because "." specifies the
386 // query name. For non-defaults ports, the query name uses port prefix naming
387 // and does not match the A/AAAA records.
388 doh_server_.AddRecord(BuildTestHttpsServiceRecord(
389 dns_util::GetNameForHttpsQuery(url::SchemeHostPort(https_url)),
390 /*priority=*/1, /*service_name=*/kHostname, /*params=*/{}));
391
392 for (auto mode : {SecureDnsMode::kSecure, SecureDnsMode::kAutomatic}) {
393 SCOPED_TRACE(kSecureDnsModes.at(mode));
394 ResetContext(mode);
395
396 // Fetch the http URL.
397 TestDelegate d;
398 std::unique_ptr<URLRequest> req(context()->CreateRequest(
399 http_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
400 req->Start();
401 base::RunLoop().Run();
402 ASSERT_THAT(d.request_status(), IsOk());
403
404 // The request should have been redirected to https.
405 EXPECT_EQ(d.received_redirect_count(), 1);
406 EXPECT_EQ(req->url(), https_url);
407
408 EXPECT_TRUE(d.response_completed());
409 EXPECT_EQ(d.request_status(), 0);
410 EXPECT_EQ(d.data_received(), kTestBody);
411 }
412 }
413
414 // An end-to-end test for requesting a domain with a basic HTTPS record. Expect
415 // this to exercise connection logic for extra HostResolver results with
416 // metadata.
TEST_F(HttpsWithDnsOverHttpsTest,HttpsMetadata)417 TEST_F(HttpsWithDnsOverHttpsTest, HttpsMetadata) {
418 base::test::ScopedFeatureList features;
419 features.InitAndEnableFeatureWithParameters(
420 features::kUseDnsHttpsSvcb,
421 {// Disable timeouts.
422 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
423 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
424 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}});
425 ResetContext();
426
427 GURL main_url = https_server_.GetURL(kHostname, "/test");
428 EXPECT_TRUE(main_url.SchemeIs(url::kHttpsScheme));
429
430 doh_server_.AddRecord(BuildTestHttpsServiceRecord(
431 dns_util::GetNameForHttpsQuery(url::SchemeHostPort(main_url)),
432 /*priority=*/1, /*service_name=*/kHostname, /*params=*/{}));
433
434 // Fetch the http URL.
435 TestDelegate d;
436
437 std::unique_ptr<URLRequest> req(context()->CreateRequest(
438 main_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
439 req->Start();
440 base::RunLoop().Run();
441 ASSERT_THAT(d.request_status(), IsOk());
442
443 // There should be three DoH lookups for kHostname (A, AAAA, and HTTPS).
444 EXPECT_EQ(doh_server_.QueriesServed(), 3);
445
446 EXPECT_TRUE(d.response_completed());
447 EXPECT_EQ(d.request_status(), 0);
448 EXPECT_EQ(d.data_received(), kTestBody);
449 }
450
TEST_F(DnsOverHttpsIntegrationTest,EncryptedClientHello)451 TEST_F(DnsOverHttpsIntegrationTest, EncryptedClientHello) {
452 // Configure a test server that speaks ECH.
453 static constexpr char kRealName[] = "secret.example";
454 static constexpr char kPublicName[] = "public.example";
455 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
456 server_cert_config.dns_names = {kRealName};
457
458 SSLServerConfig ssl_server_config;
459 std::vector<uint8_t> ech_config_list;
460 ssl_server_config.ech_keys =
461 MakeTestEchKeys(kPublicName, /*max_name_len=*/128, &ech_config_list);
462 ASSERT_TRUE(ssl_server_config.ech_keys);
463
464 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
465 test_server.SetSSLConfig(server_cert_config, ssl_server_config);
466 RegisterDefaultHandlers(&test_server);
467 ASSERT_TRUE(test_server.Start());
468
469 AddressList addr;
470 ASSERT_TRUE(test_server.GetAddressList(&addr));
471 GURL url = test_server.GetURL(kRealName, "/defaultresponse");
472 AddHostWithEch(url::SchemeHostPort(url), addr.front().address(),
473 ech_config_list);
474
475 for (bool feature_enabled : {true, false}) {
476 SCOPED_TRACE(feature_enabled);
477 base::test::ScopedFeatureList features;
478 if (feature_enabled) {
479 features.InitWithFeaturesAndParameters(
480 /*enabled_features=*/{{features::kUseDnsHttpsSvcb,
481 {// Disable timeouts.
482 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
483 {"UseDnsHttpsSvcbSecureExtraTimePercent",
484 "0"},
485 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}},
486 {features::kEncryptedClientHello, {}}},
487 /*disabled_features=*/{});
488 } else {
489 features.InitWithFeaturesAndParameters(
490 /*enabled_features=*/{{features::kUseDnsHttpsSvcb,
491 {// Disable timeouts.
492 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
493 {"UseDnsHttpsSvcbSecureExtraTimePercent",
494 "0"},
495 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}}},
496 /*disabled_features=*/{features::kEncryptedClientHello});
497 }
498
499 for (bool config_enabled : {true, false}) {
500 SCOPED_TRACE(config_enabled);
501 bool ech_enabled = feature_enabled && config_enabled;
502
503 // Create a new `URLRequestContext`, to ensure there are no cached
504 // sockets, etc., from the previous loop iteration.
505 ResetContext();
506
507 SSLContextConfig config;
508 config.ech_enabled = config_enabled;
509 ssl_config_service_->UpdateSSLConfigAndNotify(config);
510
511 TestDelegate d;
512 std::unique_ptr<URLRequest> r = context()->CreateRequest(
513 url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS);
514 r->Start();
515 EXPECT_TRUE(r->is_pending());
516
517 d.RunUntilComplete();
518
519 EXPECT_THAT(d.request_status(), IsOk());
520 EXPECT_EQ(1, d.response_started_count());
521 EXPECT_FALSE(d.received_data_before_response());
522 EXPECT_NE(0, d.bytes_received());
523 EXPECT_EQ(ech_enabled, r->ssl_info().encrypted_client_hello);
524 }
525 }
526 }
527
528 // Test that, if the DNS returns a stale ECHConfigList (or other key mismatch),
529 // the client can recover and connect to the server, provided the server can
530 // handshake as the public name.
TEST_F(DnsOverHttpsIntegrationTest,EncryptedClientHelloStaleKey)531 TEST_F(DnsOverHttpsIntegrationTest, EncryptedClientHelloStaleKey) {
532 base::test::ScopedFeatureList features;
533 features.InitWithFeaturesAndParameters(
534 /*enabled_features=*/{{features::kEncryptedClientHello, {}},
535 {features::kUseDnsHttpsSvcb,
536 {// Disable timeouts.
537 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
538 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
539 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}}},
540 /*disabled_features=*/{});
541 ResetContext();
542
543 static constexpr char kRealNameStale[] = "secret1.example";
544 static constexpr char kRealNameWrongPublicName[] = "secret2.example";
545 static constexpr char kPublicName[] = "public.example";
546 static constexpr char kWrongPublicName[] = "wrong-public.example";
547
548 std::vector<uint8_t> ech_config_list, ech_config_list_stale,
549 ech_config_list_wrong_public_name;
550 bssl::UniquePtr<SSL_ECH_KEYS> ech_keys =
551 MakeTestEchKeys(kPublicName, /*max_name_len=*/128, &ech_config_list);
552 ASSERT_TRUE(ech_keys);
553 ASSERT_TRUE(MakeTestEchKeys(kPublicName, /*max_name_len=*/128,
554 &ech_config_list_stale));
555 ASSERT_TRUE(MakeTestEchKeys(kWrongPublicName, /*max_name_len=*/128,
556 &ech_config_list_wrong_public_name));
557
558 // Configure an ECH-supporting server that can speak for all names except
559 // `kWrongPublicName`.
560 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
561 server_cert_config.dns_names = {kRealNameStale, kRealNameWrongPublicName,
562 kPublicName};
563 SSLServerConfig ssl_server_config;
564 ssl_server_config.ech_keys = std::move(ech_keys);
565 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
566 test_server.SetSSLConfig(server_cert_config, ssl_server_config);
567 RegisterDefaultHandlers(&test_server);
568 ASSERT_TRUE(test_server.Start());
569
570 AddressList addr;
571 ASSERT_TRUE(test_server.GetAddressList(&addr));
572 GURL url_stale = test_server.GetURL(kRealNameStale, "/defaultresponse");
573 GURL url_wrong_public_name =
574 test_server.GetURL(kRealNameWrongPublicName, "/defaultresponse");
575 AddHostWithEch(url::SchemeHostPort(url_stale), addr.front().address(),
576 ech_config_list_stale);
577 AddHostWithEch(url::SchemeHostPort(url_wrong_public_name),
578 addr.front().address(), ech_config_list_wrong_public_name);
579
580 // Connecting to `url_stale` should succeed. Although the server will not
581 // decrypt the ClientHello, it can handshake as `kPublicName` and provide new
582 // keys for the client to use.
583 {
584 TestDelegate d;
585 std::unique_ptr<URLRequest> r = context()->CreateRequest(
586 url_stale, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS);
587 r->Start();
588 EXPECT_TRUE(r->is_pending());
589
590 d.RunUntilComplete();
591
592 EXPECT_THAT(d.request_status(), IsOk());
593 EXPECT_EQ(1, d.response_started_count());
594 EXPECT_FALSE(d.received_data_before_response());
595 EXPECT_NE(0, d.bytes_received());
596 EXPECT_TRUE(r->ssl_info().encrypted_client_hello);
597 }
598
599 // Connecting to `url_wrong_public_name` should fail. The server can neither
600 // decrypt the ClientHello, nor handshake as `kWrongPublicName`.
601 {
602 TestDelegate d;
603 std::unique_ptr<URLRequest> r =
604 context()->CreateRequest(url_wrong_public_name, DEFAULT_PRIORITY, &d,
605 TRAFFIC_ANNOTATION_FOR_TESTS);
606 r->Start();
607 EXPECT_TRUE(r->is_pending());
608
609 d.RunUntilComplete();
610
611 EXPECT_THAT(d.request_status(),
612 IsError(ERR_ECH_FALLBACK_CERTIFICATE_INVALID));
613 }
614 }
615
TEST_F(DnsOverHttpsIntegrationTest,EncryptedClientHelloFallback)616 TEST_F(DnsOverHttpsIntegrationTest, EncryptedClientHelloFallback) {
617 base::test::ScopedFeatureList features;
618 features.InitWithFeaturesAndParameters(
619 /*enabled_features=*/{{features::kEncryptedClientHello, {}},
620 {features::kUseDnsHttpsSvcb,
621 {// Disable timeouts.
622 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
623 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
624 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}}},
625 /*disabled_features=*/{});
626 ResetContext();
627
628 static constexpr char kRealNameStale[] = "secret1.example";
629 static constexpr char kRealNameWrongPublicName[] = "secret2.example";
630 static constexpr char kPublicName[] = "public.example";
631 static constexpr char kWrongPublicName[] = "wrong-public.example";
632
633 std::vector<uint8_t> ech_config_list_stale, ech_config_list_wrong_public_name;
634 ASSERT_TRUE(MakeTestEchKeys(kPublicName, /*max_name_len=*/128,
635 &ech_config_list_stale));
636 ASSERT_TRUE(MakeTestEchKeys(kWrongPublicName, /*max_name_len=*/128,
637 &ech_config_list_wrong_public_name));
638
639 // Configure a server, without ECH, that can speak for all names except
640 // `kWrongPublicName`.
641 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
642 server_cert_config.dns_names = {kRealNameStale, kRealNameWrongPublicName,
643 kPublicName};
644 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
645 test_server.SetSSLConfig(server_cert_config);
646 RegisterDefaultHandlers(&test_server);
647 ASSERT_TRUE(test_server.Start());
648
649 AddressList addr;
650 ASSERT_TRUE(test_server.GetAddressList(&addr));
651 GURL url_stale = test_server.GetURL(kRealNameStale, "/defaultresponse");
652 GURL url_wrong_public_name =
653 test_server.GetURL(kRealNameWrongPublicName, "/defaultresponse");
654 AddHostWithEch(url::SchemeHostPort(url_stale), addr.front().address(),
655 ech_config_list_stale);
656 AddHostWithEch(url::SchemeHostPort(url_wrong_public_name),
657 addr.front().address(), ech_config_list_wrong_public_name);
658
659 // Connecting to `url_stale` should succeed. Although the server will not
660 // decrypt the ClientHello, it can handshake as `kPublicName` and trigger an
661 // authenticated fallback.
662 {
663 TestDelegate d;
664 std::unique_ptr<URLRequest> r = context()->CreateRequest(
665 url_stale, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS);
666 r->Start();
667 EXPECT_TRUE(r->is_pending());
668 d.RunUntilComplete();
669 EXPECT_THAT(d.request_status(), IsOk());
670 EXPECT_EQ(1, d.response_started_count());
671 EXPECT_FALSE(d.received_data_before_response());
672 EXPECT_NE(0, d.bytes_received());
673 EXPECT_FALSE(r->ssl_info().encrypted_client_hello);
674 }
675
676 // Connecting to `url_wrong_public_name` should fail. The server can neither
677 // decrypt the ClientHello, nor handshake as `kWrongPublicName`.
678 {
679 TestDelegate d;
680 std::unique_ptr<URLRequest> r =
681 context()->CreateRequest(url_wrong_public_name, DEFAULT_PRIORITY, &d,
682 TRAFFIC_ANNOTATION_FOR_TESTS);
683 r->Start();
684 EXPECT_TRUE(r->is_pending());
685 d.RunUntilComplete();
686 EXPECT_THAT(d.request_status(),
687 IsError(ERR_ECH_FALLBACK_CERTIFICATE_INVALID));
688 }
689 }
690
TEST_F(DnsOverHttpsIntegrationTest,EncryptedClientHelloFallbackTLS12)691 TEST_F(DnsOverHttpsIntegrationTest, EncryptedClientHelloFallbackTLS12) {
692 base::test::ScopedFeatureList features;
693 features.InitWithFeaturesAndParameters(
694 /*enabled_features=*/{{features::kEncryptedClientHello, {}},
695 {features::kUseDnsHttpsSvcb,
696 {// Disable timeouts.
697 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
698 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
699 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}}},
700 /*disabled_features=*/{});
701 ResetContext();
702
703 static constexpr char kRealNameStale[] = "secret1.example";
704 static constexpr char kRealNameWrongPublicName[] = "secret2.example";
705 static constexpr char kPublicName[] = "public.example";
706 static constexpr char kWrongPublicName[] = "wrong-public.example";
707
708 std::vector<uint8_t> ech_config_list_stale, ech_config_list_wrong_public_name;
709 ASSERT_TRUE(MakeTestEchKeys(kPublicName, /*max_name_len=*/128,
710 &ech_config_list_stale));
711 ASSERT_TRUE(MakeTestEchKeys(kWrongPublicName, /*max_name_len=*/128,
712 &ech_config_list_wrong_public_name));
713
714 // Configure a server, without ECH or TLS 1.3, that can speak for all names
715 // except `kWrongPublicName`.
716 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
717 server_cert_config.dns_names = {kRealNameStale, kRealNameWrongPublicName,
718 kPublicName};
719 SSLServerConfig ssl_server_config;
720 ssl_server_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2;
721 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
722 test_server.SetSSLConfig(server_cert_config, ssl_server_config);
723 RegisterDefaultHandlers(&test_server);
724 ASSERT_TRUE(test_server.Start());
725
726 AddressList addr;
727 ASSERT_TRUE(test_server.GetAddressList(&addr));
728 GURL url_stale = test_server.GetURL(kRealNameStale, "/defaultresponse");
729 GURL url_wrong_public_name =
730 test_server.GetURL(kRealNameWrongPublicName, "/defaultresponse");
731 AddHostWithEch(url::SchemeHostPort(url_stale), addr.front().address(),
732 ech_config_list_stale);
733 AddHostWithEch(url::SchemeHostPort(url_wrong_public_name),
734 addr.front().address(), ech_config_list_wrong_public_name);
735
736 // Connecting to `url_stale` should succeed. Although the server will not
737 // decrypt the ClientHello, it can handshake as `kPublicName` and trigger an
738 // authenticated fallback.
739 {
740 TestDelegate d;
741 std::unique_ptr<URLRequest> r = context()->CreateRequest(
742 url_stale, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS);
743 r->Start();
744 EXPECT_TRUE(r->is_pending());
745 d.RunUntilComplete();
746 EXPECT_THAT(d.request_status(), IsOk());
747 EXPECT_EQ(1, d.response_started_count());
748 EXPECT_FALSE(d.received_data_before_response());
749 EXPECT_NE(0, d.bytes_received());
750 EXPECT_FALSE(r->ssl_info().encrypted_client_hello);
751 }
752
753 // Connecting to `url_wrong_public_name` should fail. The server can neither
754 // decrypt the ClientHello, nor handshake as `kWrongPublicName`.
755 {
756 TestDelegate d;
757 std::unique_ptr<URLRequest> r =
758 context()->CreateRequest(url_wrong_public_name, DEFAULT_PRIORITY, &d,
759 TRAFFIC_ANNOTATION_FOR_TESTS);
760 r->Start();
761 EXPECT_TRUE(r->is_pending());
762 d.RunUntilComplete();
763 EXPECT_THAT(d.request_status(),
764 IsError(ERR_ECH_FALLBACK_CERTIFICATE_INVALID));
765 }
766 }
767
768 } // namespace
769 } // namespace net
770