xref: /aosp_15_r20/external/cronet/net/url_request/http_with_dns_over_https_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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