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 ProxyInfo & used_proxy_info,std::unique_ptr<HttpStream> stream)232 void OnStreamReady(const ProxyInfo& used_proxy_info,
233 std::unique_ptr<HttpStream> stream) override {
234 stream->Close(false);
235 loop_->Quit();
236 }
237
OnWebSocketHandshakeStreamReady(const ProxyInfo & used_proxy_info,std::unique_ptr<WebSocketHandshakeStreamBase> stream)238 void OnWebSocketHandshakeStreamReady(
239 const ProxyInfo& used_proxy_info,
240 std::unique_ptr<WebSocketHandshakeStreamBase> stream) override {}
241
OnBidirectionalStreamImplReady(const ProxyInfo & used_proxy_info,std::unique_ptr<BidirectionalStreamImpl> stream)242 void OnBidirectionalStreamImplReady(
243 const ProxyInfo& used_proxy_info,
244 std::unique_ptr<BidirectionalStreamImpl> stream) override {}
245
OnStreamFailed(int status,const NetErrorDetails & net_error_details,const ProxyInfo & used_proxy_info,ResolveErrorInfo resolve_eror_info)246 void OnStreamFailed(int status,
247 const NetErrorDetails& net_error_details,
248 const ProxyInfo& used_proxy_info,
249 ResolveErrorInfo resolve_eror_info) override {}
250
OnCertificateError(int status,const SSLInfo & ssl_info)251 void OnCertificateError(int status, const SSLInfo& ssl_info) override {}
252
OnNeedsProxyAuth(const HttpResponseInfo & proxy_response,const ProxyInfo & used_proxy_info,HttpAuthController * auth_controller)253 void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response,
254 const ProxyInfo& used_proxy_info,
255 HttpAuthController* auth_controller) override {}
256
OnNeedsClientAuth(SSLCertRequestInfo * cert_info)257 void OnNeedsClientAuth(SSLCertRequestInfo* cert_info) override {}
258
OnQuicBroken()259 void OnQuicBroken() override {}
260
261 private:
262 raw_ptr<base::RunLoop> loop_;
263 };
264
265 // This test sets up a request which will reenter the connection pools by
266 // triggering a DNS over HTTPS request. It also sets up an idle socket
267 // which was a precondition for the crash we saw in https://crbug.com/830917.
TEST_F(HttpsWithDnsOverHttpsTest,EndToEnd)268 TEST_F(HttpsWithDnsOverHttpsTest, EndToEnd) {
269 // Create and start http server.
270 EmbeddedTestServer http_server(EmbeddedTestServer::Type::TYPE_HTTP);
271 http_server.RegisterRequestHandler(
272 base::BindRepeating(&HttpsWithDnsOverHttpsTest::HandleDefaultRequest,
273 base::Unretained(this)));
274 EXPECT_TRUE(http_server.Start());
275
276 // Set up an idle socket.
277 HttpTransactionFactory* transaction_factory =
278 request_context_->http_transaction_factory();
279 HttpStreamFactory::JobFactory default_job_factory;
280 HttpNetworkSession* network_session = transaction_factory->GetSession();
281 base::RunLoop loop;
282 TestHttpDelegate request_delegate(&loop);
283
284 HttpStreamFactory* factory = network_session->http_stream_factory();
285 HttpRequestInfo request_info;
286 request_info.method = "GET";
287 request_info.url = http_server.GetURL("localhost", "/preconnect");
288
289 std::unique_ptr<HttpStreamRequest> request(factory->RequestStream(
290 request_info, DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
291 &request_delegate, false, false, NetLogWithSource()));
292 loop.Run();
293
294 ClientSocketPool::GroupId group_id(
295 url::SchemeHostPort(request_info.url), PrivacyMode::PRIVACY_MODE_DISABLED,
296 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
297 /*disable_cert_network_fetches=*/false);
298 EXPECT_EQ(network_session
299 ->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
300 ProxyChain::Direct())
301 ->IdleSocketCountInGroup(group_id),
302 1u);
303
304 // The domain "localhost" is resolved locally, so no DNS lookups should have
305 // occurred.
306 EXPECT_EQ(doh_server_.QueriesServed(), 0);
307 EXPECT_EQ(host_resolver_proc_->insecure_queries_served(), 0u);
308 // A stream was established, but no HTTPS request has been made yet.
309 EXPECT_EQ(test_https_requests_served_, 0u);
310
311 // Make a request that will trigger a DoH query as well.
312 TestDelegate d;
313 GURL main_url = https_server_.GetURL(kHostname, "/test");
314 std::unique_ptr<URLRequest> req(context()->CreateRequest(
315 main_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
316 req->Start();
317 d.RunUntilComplete();
318 EXPECT_TRUE(https_server_.ShutdownAndWaitUntilComplete());
319 EXPECT_TRUE(http_server.ShutdownAndWaitUntilComplete());
320 EXPECT_TRUE(doh_server_.ShutdownAndWaitUntilComplete());
321
322 // There should be three DoH lookups for kHostname (A, AAAA, and HTTPS).
323 EXPECT_EQ(doh_server_.QueriesServed(), 3);
324 // The requests to the DoH server are pooled, so there should only be one
325 // insecure lookup for the DoH server hostname.
326 EXPECT_EQ(host_resolver_proc_->insecure_queries_served(), 1u);
327 // There should be one non-DoH HTTPS request for the connection to kHostname.
328 EXPECT_EQ(test_https_requests_served_, 1u);
329
330 EXPECT_TRUE(d.response_completed());
331 EXPECT_EQ(d.request_status(), 0);
332 EXPECT_EQ(d.data_received(), kTestBody);
333 }
334
TEST_F(HttpsWithDnsOverHttpsTest,EndToEndFail)335 TEST_F(HttpsWithDnsOverHttpsTest, EndToEndFail) {
336 // Fail all DoH requests.
337 doh_server_.SetFailRequests(true);
338
339 // Make a request that will trigger a DoH query.
340 TestDelegate d;
341 GURL main_url = https_server_.GetURL(kHostname, "/test");
342 std::unique_ptr<URLRequest> req(context()->CreateRequest(
343 main_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
344 req->Start();
345 d.RunUntilComplete();
346 EXPECT_TRUE(https_server_.ShutdownAndWaitUntilComplete());
347 EXPECT_TRUE(doh_server_.ShutdownAndWaitUntilComplete());
348
349 // No HTTPS connection to the test server will be attempted due to the
350 // host resolution error.
351 EXPECT_EQ(test_https_requests_served_, 0u);
352
353 EXPECT_TRUE(d.response_completed());
354 EXPECT_EQ(d.request_status(), net::ERR_NAME_NOT_RESOLVED);
355
356 const auto& resolve_error_info = req->response_info().resolve_error_info;
357 EXPECT_TRUE(resolve_error_info.is_secure_network_error);
358 EXPECT_EQ(resolve_error_info.error, net::ERR_DNS_MALFORMED_RESPONSE);
359 }
360
361 // An end-to-end test of the HTTPS upgrade behavior.
TEST_F(HttpsWithDnsOverHttpsTest,HttpsUpgrade)362 TEST_F(HttpsWithDnsOverHttpsTest, HttpsUpgrade) {
363 base::test::ScopedFeatureList features;
364 features.InitAndEnableFeatureWithParameters(
365 features::kUseDnsHttpsSvcb,
366 {// Disable timeouts.
367 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
368 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
369 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}});
370 ResetContext();
371
372 GURL https_url = https_server_.GetURL(kHostname, "/test");
373 EXPECT_TRUE(https_url.SchemeIs(url::kHttpsScheme));
374 GURL::Replacements replacements;
375 replacements.SetSchemeStr(url::kHttpScheme);
376 GURL http_url = https_url.ReplaceComponents(replacements);
377
378 // `service_name` is `kHostname` rather than "." because "." specifies the
379 // query name. For non-defaults ports, the query name uses port prefix naming
380 // and does not match the A/AAAA records.
381 doh_server_.AddRecord(BuildTestHttpsServiceRecord(
382 dns_util::GetNameForHttpsQuery(url::SchemeHostPort(https_url)),
383 /*priority=*/1, /*service_name=*/kHostname, /*params=*/{}));
384
385 for (auto mode : {SecureDnsMode::kSecure, SecureDnsMode::kAutomatic}) {
386 SCOPED_TRACE(kSecureDnsModes.at(mode));
387 ResetContext(mode);
388
389 // Fetch the http URL.
390 TestDelegate d;
391 std::unique_ptr<URLRequest> req(context()->CreateRequest(
392 http_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
393 req->Start();
394 d.RunUntilComplete();
395 ASSERT_THAT(d.request_status(), IsOk());
396
397 // The request should have been redirected to https.
398 EXPECT_EQ(d.received_redirect_count(), 1);
399 EXPECT_EQ(req->url(), https_url);
400
401 EXPECT_TRUE(d.response_completed());
402 EXPECT_EQ(d.request_status(), 0);
403 EXPECT_EQ(d.data_received(), kTestBody);
404 }
405 }
406
407 // An end-to-end test for requesting a domain with a basic HTTPS record. Expect
408 // this to exercise connection logic for extra HostResolver results with
409 // metadata.
TEST_F(HttpsWithDnsOverHttpsTest,HttpsMetadata)410 TEST_F(HttpsWithDnsOverHttpsTest, HttpsMetadata) {
411 base::test::ScopedFeatureList features;
412 features.InitAndEnableFeatureWithParameters(
413 features::kUseDnsHttpsSvcb,
414 {// Disable timeouts.
415 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
416 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
417 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}});
418 ResetContext();
419
420 GURL main_url = https_server_.GetURL(kHostname, "/test");
421 EXPECT_TRUE(main_url.SchemeIs(url::kHttpsScheme));
422
423 doh_server_.AddRecord(BuildTestHttpsServiceRecord(
424 dns_util::GetNameForHttpsQuery(url::SchemeHostPort(main_url)),
425 /*priority=*/1, /*service_name=*/kHostname, /*params=*/{}));
426
427 // Fetch the http URL.
428 TestDelegate d;
429
430 std::unique_ptr<URLRequest> req(context()->CreateRequest(
431 main_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
432 req->Start();
433 d.RunUntilComplete();
434 ASSERT_THAT(d.request_status(), IsOk());
435
436 // There should be three DoH lookups for kHostname (A, AAAA, and HTTPS).
437 EXPECT_EQ(doh_server_.QueriesServed(), 3);
438
439 EXPECT_TRUE(d.response_completed());
440 EXPECT_EQ(d.request_status(), 0);
441 EXPECT_EQ(d.data_received(), kTestBody);
442 }
443
TEST_F(DnsOverHttpsIntegrationTest,EncryptedClientHello)444 TEST_F(DnsOverHttpsIntegrationTest, EncryptedClientHello) {
445 base::test::ScopedFeatureList features;
446 features.InitWithFeaturesAndParameters(
447 /*enabled_features=*/{{features::kUseDnsHttpsSvcb,
448 {// Disable timeouts.
449 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
450 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
451 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}}},
452 /*disabled_features=*/{});
453
454 // Configure a test server that speaks ECH.
455 static constexpr char kRealName[] = "secret.example";
456 static constexpr char kPublicName[] = "public.example";
457 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
458 server_cert_config.dns_names = {kRealName};
459
460 SSLServerConfig ssl_server_config;
461 std::vector<uint8_t> ech_config_list;
462 ssl_server_config.ech_keys =
463 MakeTestEchKeys(kPublicName, /*max_name_len=*/128, &ech_config_list);
464 ASSERT_TRUE(ssl_server_config.ech_keys);
465
466 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
467 test_server.SetSSLConfig(server_cert_config, ssl_server_config);
468 RegisterDefaultHandlers(&test_server);
469 ASSERT_TRUE(test_server.Start());
470
471 AddressList addr;
472 ASSERT_TRUE(test_server.GetAddressList(&addr));
473 GURL url = test_server.GetURL(kRealName, "/defaultresponse");
474 AddHostWithEch(url::SchemeHostPort(url), addr.front().address(),
475 ech_config_list);
476
477 for (bool ech_enabled : {true, false}) {
478 SCOPED_TRACE(ech_enabled);
479
480 // Create a new `URLRequestContext`, to ensure there are no cached
481 // sockets, etc., from the previous loop iteration.
482 ResetContext();
483
484 SSLContextConfig config;
485 config.ech_enabled = ech_enabled;
486 ssl_config_service_->UpdateSSLConfigAndNotify(config);
487
488 TestDelegate d;
489 std::unique_ptr<URLRequest> r = context()->CreateRequest(
490 url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS);
491 r->Start();
492 EXPECT_TRUE(r->is_pending());
493
494 d.RunUntilComplete();
495
496 EXPECT_THAT(d.request_status(), IsOk());
497 EXPECT_EQ(1, d.response_started_count());
498 EXPECT_FALSE(d.received_data_before_response());
499 EXPECT_NE(0, d.bytes_received());
500 EXPECT_EQ(ech_enabled, r->ssl_info().encrypted_client_hello);
501 }
502 }
503
504 // Test that, if the DNS returns a stale ECHConfigList (or other key mismatch),
505 // the client can recover and connect to the server, provided the server can
506 // handshake as the public name.
TEST_F(DnsOverHttpsIntegrationTest,EncryptedClientHelloStaleKey)507 TEST_F(DnsOverHttpsIntegrationTest, EncryptedClientHelloStaleKey) {
508 base::test::ScopedFeatureList features;
509 features.InitWithFeaturesAndParameters(
510 /*enabled_features=*/{{features::kUseDnsHttpsSvcb,
511 {// Disable timeouts.
512 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
513 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
514 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}}},
515 /*disabled_features=*/{});
516 ResetContext();
517
518 static constexpr char kRealNameStale[] = "secret1.example";
519 static constexpr char kRealNameWrongPublicName[] = "secret2.example";
520 static constexpr char kPublicName[] = "public.example";
521 static constexpr char kWrongPublicName[] = "wrong-public.example";
522
523 std::vector<uint8_t> ech_config_list, ech_config_list_stale,
524 ech_config_list_wrong_public_name;
525 bssl::UniquePtr<SSL_ECH_KEYS> ech_keys =
526 MakeTestEchKeys(kPublicName, /*max_name_len=*/128, &ech_config_list);
527 ASSERT_TRUE(ech_keys);
528 ASSERT_TRUE(MakeTestEchKeys(kPublicName, /*max_name_len=*/128,
529 &ech_config_list_stale));
530 ASSERT_TRUE(MakeTestEchKeys(kWrongPublicName, /*max_name_len=*/128,
531 &ech_config_list_wrong_public_name));
532
533 // Configure an ECH-supporting server that can speak for all names except
534 // `kWrongPublicName`.
535 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
536 server_cert_config.dns_names = {kRealNameStale, kRealNameWrongPublicName,
537 kPublicName};
538 SSLServerConfig ssl_server_config;
539 ssl_server_config.ech_keys = std::move(ech_keys);
540 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
541 test_server.SetSSLConfig(server_cert_config, ssl_server_config);
542 RegisterDefaultHandlers(&test_server);
543 ASSERT_TRUE(test_server.Start());
544
545 AddressList addr;
546 ASSERT_TRUE(test_server.GetAddressList(&addr));
547 GURL url_stale = test_server.GetURL(kRealNameStale, "/defaultresponse");
548 GURL url_wrong_public_name =
549 test_server.GetURL(kRealNameWrongPublicName, "/defaultresponse");
550 AddHostWithEch(url::SchemeHostPort(url_stale), addr.front().address(),
551 ech_config_list_stale);
552 AddHostWithEch(url::SchemeHostPort(url_wrong_public_name),
553 addr.front().address(), ech_config_list_wrong_public_name);
554
555 // Connecting to `url_stale` should succeed. Although the server will not
556 // decrypt the ClientHello, it can handshake as `kPublicName` and provide new
557 // keys for the client to use.
558 {
559 TestDelegate d;
560 std::unique_ptr<URLRequest> r = context()->CreateRequest(
561 url_stale, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS);
562 r->Start();
563 EXPECT_TRUE(r->is_pending());
564
565 d.RunUntilComplete();
566
567 EXPECT_THAT(d.request_status(), IsOk());
568 EXPECT_EQ(1, d.response_started_count());
569 EXPECT_FALSE(d.received_data_before_response());
570 EXPECT_NE(0, d.bytes_received());
571 EXPECT_TRUE(r->ssl_info().encrypted_client_hello);
572 }
573
574 // Connecting to `url_wrong_public_name` should fail. The server can neither
575 // decrypt the ClientHello, nor handshake as `kWrongPublicName`.
576 {
577 TestDelegate d;
578 std::unique_ptr<URLRequest> r =
579 context()->CreateRequest(url_wrong_public_name, DEFAULT_PRIORITY, &d,
580 TRAFFIC_ANNOTATION_FOR_TESTS);
581 r->Start();
582 EXPECT_TRUE(r->is_pending());
583
584 d.RunUntilComplete();
585
586 EXPECT_THAT(d.request_status(),
587 IsError(ERR_ECH_FALLBACK_CERTIFICATE_INVALID));
588 }
589 }
590
TEST_F(DnsOverHttpsIntegrationTest,EncryptedClientHelloFallback)591 TEST_F(DnsOverHttpsIntegrationTest, EncryptedClientHelloFallback) {
592 base::test::ScopedFeatureList features;
593 features.InitWithFeaturesAndParameters(
594 /*enabled_features=*/{{features::kUseDnsHttpsSvcb,
595 {// Disable timeouts.
596 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
597 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
598 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}}},
599 /*disabled_features=*/{});
600 ResetContext();
601
602 static constexpr char kRealNameStale[] = "secret1.example";
603 static constexpr char kRealNameWrongPublicName[] = "secret2.example";
604 static constexpr char kPublicName[] = "public.example";
605 static constexpr char kWrongPublicName[] = "wrong-public.example";
606
607 std::vector<uint8_t> ech_config_list_stale, ech_config_list_wrong_public_name;
608 ASSERT_TRUE(MakeTestEchKeys(kPublicName, /*max_name_len=*/128,
609 &ech_config_list_stale));
610 ASSERT_TRUE(MakeTestEchKeys(kWrongPublicName, /*max_name_len=*/128,
611 &ech_config_list_wrong_public_name));
612
613 // Configure a server, without ECH, that can speak for all names except
614 // `kWrongPublicName`.
615 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
616 server_cert_config.dns_names = {kRealNameStale, kRealNameWrongPublicName,
617 kPublicName};
618 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
619 test_server.SetSSLConfig(server_cert_config);
620 RegisterDefaultHandlers(&test_server);
621 ASSERT_TRUE(test_server.Start());
622
623 AddressList addr;
624 ASSERT_TRUE(test_server.GetAddressList(&addr));
625 GURL url_stale = test_server.GetURL(kRealNameStale, "/defaultresponse");
626 GURL url_wrong_public_name =
627 test_server.GetURL(kRealNameWrongPublicName, "/defaultresponse");
628 AddHostWithEch(url::SchemeHostPort(url_stale), addr.front().address(),
629 ech_config_list_stale);
630 AddHostWithEch(url::SchemeHostPort(url_wrong_public_name),
631 addr.front().address(), ech_config_list_wrong_public_name);
632
633 // Connecting to `url_stale` should succeed. Although the server will not
634 // decrypt the ClientHello, it can handshake as `kPublicName` and trigger an
635 // authenticated fallback.
636 {
637 TestDelegate d;
638 std::unique_ptr<URLRequest> r = context()->CreateRequest(
639 url_stale, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS);
640 r->Start();
641 EXPECT_TRUE(r->is_pending());
642 d.RunUntilComplete();
643 EXPECT_THAT(d.request_status(), IsOk());
644 EXPECT_EQ(1, d.response_started_count());
645 EXPECT_FALSE(d.received_data_before_response());
646 EXPECT_NE(0, d.bytes_received());
647 EXPECT_FALSE(r->ssl_info().encrypted_client_hello);
648 }
649
650 // Connecting to `url_wrong_public_name` should fail. The server can neither
651 // decrypt the ClientHello, nor handshake as `kWrongPublicName`.
652 {
653 TestDelegate d;
654 std::unique_ptr<URLRequest> r =
655 context()->CreateRequest(url_wrong_public_name, DEFAULT_PRIORITY, &d,
656 TRAFFIC_ANNOTATION_FOR_TESTS);
657 r->Start();
658 EXPECT_TRUE(r->is_pending());
659 d.RunUntilComplete();
660 EXPECT_THAT(d.request_status(),
661 IsError(ERR_ECH_FALLBACK_CERTIFICATE_INVALID));
662 }
663 }
664
TEST_F(DnsOverHttpsIntegrationTest,EncryptedClientHelloFallbackTLS12)665 TEST_F(DnsOverHttpsIntegrationTest, EncryptedClientHelloFallbackTLS12) {
666 base::test::ScopedFeatureList features;
667 features.InitWithFeaturesAndParameters(
668 /*enabled_features=*/{{features::kUseDnsHttpsSvcb,
669 {// Disable timeouts.
670 {"UseDnsHttpsSvcbSecureExtraTimeMax", "0"},
671 {"UseDnsHttpsSvcbSecureExtraTimePercent", "0"},
672 {"UseDnsHttpsSvcbSecureExtraTimeMin", "0"}}}},
673 /*disabled_features=*/{});
674 ResetContext();
675
676 static constexpr char kRealNameStale[] = "secret1.example";
677 static constexpr char kRealNameWrongPublicName[] = "secret2.example";
678 static constexpr char kPublicName[] = "public.example";
679 static constexpr char kWrongPublicName[] = "wrong-public.example";
680
681 std::vector<uint8_t> ech_config_list_stale, ech_config_list_wrong_public_name;
682 ASSERT_TRUE(MakeTestEchKeys(kPublicName, /*max_name_len=*/128,
683 &ech_config_list_stale));
684 ASSERT_TRUE(MakeTestEchKeys(kWrongPublicName, /*max_name_len=*/128,
685 &ech_config_list_wrong_public_name));
686
687 // Configure a server, without ECH or TLS 1.3, that can speak for all names
688 // except `kWrongPublicName`.
689 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
690 server_cert_config.dns_names = {kRealNameStale, kRealNameWrongPublicName,
691 kPublicName};
692 SSLServerConfig ssl_server_config;
693 ssl_server_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2;
694 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
695 test_server.SetSSLConfig(server_cert_config, ssl_server_config);
696 RegisterDefaultHandlers(&test_server);
697 ASSERT_TRUE(test_server.Start());
698
699 AddressList addr;
700 ASSERT_TRUE(test_server.GetAddressList(&addr));
701 GURL url_stale = test_server.GetURL(kRealNameStale, "/defaultresponse");
702 GURL url_wrong_public_name =
703 test_server.GetURL(kRealNameWrongPublicName, "/defaultresponse");
704 AddHostWithEch(url::SchemeHostPort(url_stale), addr.front().address(),
705 ech_config_list_stale);
706 AddHostWithEch(url::SchemeHostPort(url_wrong_public_name),
707 addr.front().address(), ech_config_list_wrong_public_name);
708
709 // Connecting to `url_stale` should succeed. Although the server will not
710 // decrypt the ClientHello, it can handshake as `kPublicName` and trigger an
711 // authenticated fallback.
712 {
713 TestDelegate d;
714 std::unique_ptr<URLRequest> r = context()->CreateRequest(
715 url_stale, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS);
716 r->Start();
717 EXPECT_TRUE(r->is_pending());
718 d.RunUntilComplete();
719 EXPECT_THAT(d.request_status(), IsOk());
720 EXPECT_EQ(1, d.response_started_count());
721 EXPECT_FALSE(d.received_data_before_response());
722 EXPECT_NE(0, d.bytes_received());
723 EXPECT_FALSE(r->ssl_info().encrypted_client_hello);
724 }
725
726 // Connecting to `url_wrong_public_name` should fail. The server can neither
727 // decrypt the ClientHello, nor handshake as `kWrongPublicName`.
728 {
729 TestDelegate d;
730 std::unique_ptr<URLRequest> r =
731 context()->CreateRequest(url_wrong_public_name, DEFAULT_PRIORITY, &d,
732 TRAFFIC_ANNOTATION_FOR_TESTS);
733 r->Start();
734 EXPECT_TRUE(r->is_pending());
735 d.RunUntilComplete();
736 EXPECT_THAT(d.request_status(),
737 IsError(ERR_ECH_FALLBACK_CERTIFICATE_INVALID));
738 }
739 }
740
741 } // namespace
742 } // namespace net
743