xref: /aosp_15_r20/external/cronet/net/http/http_response_info.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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 "net/http/http_response_info.h"
6 
7 #include <optional>
8 
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/pickle.h"
12 #include "base/time/time.h"
13 #include "net/base/net_errors.h"
14 #include "net/cert/sct_status_flags.h"
15 #include "net/cert/signed_certificate_timestamp.h"
16 #include "net/cert/x509_certificate.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/ssl/ssl_cert_request_info.h"
19 #include "net/ssl/ssl_connection_status_flags.h"
20 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
21 #include "third_party/boringssl/src/include/openssl/ssl.h"
22 
23 using base::Time;
24 
25 namespace net {
26 
27 namespace {
28 
KeyExchangeGroupIsValid(int ssl_connection_status)29 bool KeyExchangeGroupIsValid(int ssl_connection_status) {
30   // TLS 1.3 and later always treat the field correctly.
31   if (SSLConnectionStatusToVersion(ssl_connection_status) >=
32       SSL_CONNECTION_VERSION_TLS1_3) {
33     return true;
34   }
35 
36   // Prior to TLS 1.3, only ECDHE ciphers have groups.
37   const SSL_CIPHER* cipher = SSL_get_cipher_by_value(
38       SSLConnectionStatusToCipherSuite(ssl_connection_status));
39   return cipher && SSL_CIPHER_get_kx_nid(cipher) == NID_kx_ecdhe;
40 }
41 
42 }  // namespace
43 
44 // These values can be bit-wise combined to form the flags field of the
45 // serialized HttpResponseInfo.
46 enum {
47   // The version of the response info used when persisting response info.
48   RESPONSE_INFO_VERSION = 3,
49 
50   // The minimum version supported for deserializing response info.
51   RESPONSE_INFO_MINIMUM_VERSION = 3,
52 
53   // We reserve up to 8 bits for the version number.
54   RESPONSE_INFO_VERSION_MASK = 0xFF,
55 
56   // This bit is set if the response info has a cert at the end.
57   // Version 1 serialized only the end-entity certificate, while subsequent
58   // versions include the available certificate chain.
59   RESPONSE_INFO_HAS_CERT = 1 << 8,
60 
61   // This bit was historically set if the response info had a security-bits
62   // field (security strength, in bits, of the SSL connection) at the end.
63   RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9,
64 
65   // This bit is set if the response info has a cert status at the end.
66   RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10,
67 
68   // This bit is set if the response info has vary header data.
69   RESPONSE_INFO_HAS_VARY_DATA = 1 << 11,
70 
71   // This bit is set if the request was cancelled before completion.
72   RESPONSE_INFO_TRUNCATED = 1 << 12,
73 
74   // This bit is set if the response was received via SPDY.
75   RESPONSE_INFO_WAS_SPDY = 1 << 13,
76 
77   // This bit is set if the request has ALPN negotiated.
78   RESPONSE_INFO_WAS_ALPN = 1 << 14,
79 
80   // This bit is set if the request was fetched via an explicit proxy.
81   RESPONSE_INFO_WAS_PROXY = 1 << 15,
82 
83   // This bit is set if the response info has an SSL connection status field.
84   // This contains the ciphersuite used to fetch the resource as well as the
85   // protocol version, compression method and whether SSLv3 fallback was used.
86   RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16,
87 
88   // This bit is set if the response info has protocol version.
89   RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL = 1 << 17,
90 
91   // This bit is set if the response info has connection info.
92   RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18,
93 
94   // This bit is set if the request has http authentication.
95   RESPONSE_INFO_USE_HTTP_AUTHENTICATION = 1 << 19,
96 
97   // This bit is set if ssl_info has SCTs.
98   RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS = 1 << 20,
99 
100   RESPONSE_INFO_UNUSED_SINCE_PREFETCH = 1 << 21,
101 
102   // This bit is set if the response has a key exchange group.
103   RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP = 1 << 22,
104 
105   // This bit is set if ssl_info recorded that PKP was bypassed due to a local
106   // trust anchor.
107   RESPONSE_INFO_PKP_BYPASSED = 1 << 23,
108 
109   // This bit is set if stale_revalidate_time is stored.
110   RESPONSE_INFO_HAS_STALENESS = 1 << 24,
111 
112   // This bit is set if the response has a peer signature algorithm.
113   RESPONSE_INFO_HAS_PEER_SIGNATURE_ALGORITHM = 1 << 25,
114 
115   // This bit is set if the response is a prefetch whose reuse should be
116   // restricted in some way.
117   RESPONSE_INFO_RESTRICTED_PREFETCH = 1 << 26,
118 
119   // This bit is set if the response has a nonempty `dns_aliases` entry.
120   RESPONSE_INFO_HAS_DNS_ALIASES = 1 << 27,
121 
122   // This bit is now unused. It may be set on existing entries. Previously it
123   // was set for an entry in the single-keyed cache that had been marked
124   // unusable due to the cache transparency checksum not matching.
125   RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE = 1 << 28,
126 
127   // This bit is set if the response has `encrypted_client_hello` set.
128   RESPONSE_INFO_ENCRYPTED_CLIENT_HELLO = 1 << 29,
129 
130   // This bit is set if the response has `browser_run_id` set.
131   RESPONSE_INFO_BROWSER_RUN_ID = 1 << 30,
132 
133   // This bit is set if the response has extra bit set.
134   RESPONSE_INFO_HAS_EXTRA_FLAGS = 1 << 31,
135 };
136 
137 // These values can be bit-wise combined to form the extra flags field of the
138 // serialized HttpResponseInfo.
139 enum {
140   // This bit is set if the request usd a shared dictionary for decoding its
141   // body.
142   RESPONSE_EXTRA_INFO_DID_USE_SHARED_DICTIONARY = 1,
143 };
144 
145 HttpResponseInfo::HttpResponseInfo() = default;
146 
147 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) = default;
148 
149 HttpResponseInfo::~HttpResponseInfo() = default;
150 
151 HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) =
152     default;
153 
InitFromPickle(const base::Pickle & pickle,bool * response_truncated)154 bool HttpResponseInfo::InitFromPickle(const base::Pickle& pickle,
155                                       bool* response_truncated) {
156   base::PickleIterator iter(pickle);
157 
158   // Read flags and verify version
159   int flags;
160   int extra_flags = 0;
161   if (!iter.ReadInt(&flags))
162     return false;
163   if (flags & RESPONSE_INFO_HAS_EXTRA_FLAGS) {
164     if (!iter.ReadInt(&extra_flags)) {
165       return false;
166     }
167   }
168   int version = flags & RESPONSE_INFO_VERSION_MASK;
169   if (version < RESPONSE_INFO_MINIMUM_VERSION ||
170       version > RESPONSE_INFO_VERSION) {
171     DLOG(ERROR) << "unexpected response info version: " << version;
172     return false;
173   }
174 
175   // Read request-time
176   int64_t time_val;
177   if (!iter.ReadInt64(&time_val))
178     return false;
179   request_time = Time::FromInternalValue(time_val);
180   was_cached = true;  // Set status to show cache resurrection.
181 
182   // Read response-time
183   if (!iter.ReadInt64(&time_val))
184     return false;
185   response_time = Time::FromInternalValue(time_val);
186 
187   // Read response-headers
188   headers = base::MakeRefCounted<HttpResponseHeaders>(&iter);
189   if (headers->response_code() == -1)
190     return false;
191 
192   // Read ssl-info
193   if (flags & RESPONSE_INFO_HAS_CERT) {
194     ssl_info.cert = X509Certificate::CreateFromPickle(&iter);
195     if (!ssl_info.cert.get())
196       return false;
197   }
198   if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
199     CertStatus cert_status;
200     if (!iter.ReadUInt32(&cert_status))
201       return false;
202     ssl_info.cert_status = cert_status;
203   }
204   if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) {
205     // The security_bits field has been removed from ssl_info. For backwards
206     // compatibility, we should still read the value out of iter.
207     int security_bits;
208     if (!iter.ReadInt(&security_bits))
209       return false;
210   }
211 
212   if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) {
213     int connection_status;
214     if (!iter.ReadInt(&connection_status))
215       return false;
216 
217     // SSLv3 is gone, so drop cached entries that were loaded over SSLv3.
218     if (SSLConnectionStatusToVersion(connection_status) ==
219         SSL_CONNECTION_VERSION_SSL3) {
220       return false;
221     }
222     ssl_info.connection_status = connection_status;
223   }
224 
225   // Signed Certificate Timestamps are no longer persisted to the cache, so
226   // ignore them when reading them out.
227   if (flags & RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS) {
228     int num_scts;
229     if (!iter.ReadInt(&num_scts))
230       return false;
231     for (int i = 0; i < num_scts; ++i) {
232       scoped_refptr<ct::SignedCertificateTimestamp> sct(
233           ct::SignedCertificateTimestamp::CreateFromPickle(&iter));
234       uint16_t status;
235       if (!sct.get() || !iter.ReadUInt16(&status))
236         return false;
237     }
238   }
239 
240   // Read vary-data
241   if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
242     if (!vary_data.InitFromPickle(&iter))
243       return false;
244   }
245 
246   // Read socket_address.
247   std::string socket_address_host;
248   if (!iter.ReadString(&socket_address_host))
249     return false;
250   // If the host was written, we always expect the port to follow.
251   uint16_t socket_address_port;
252   if (!iter.ReadUInt16(&socket_address_port))
253     return false;
254 
255   IPAddress ip_address;
256   if (ip_address.AssignFromIPLiteral(socket_address_host)) {
257     remote_endpoint = IPEndPoint(ip_address, socket_address_port);
258   } else if (ParseURLHostnameToAddress(socket_address_host, &ip_address)) {
259     remote_endpoint = IPEndPoint(ip_address, socket_address_port);
260   }
261 
262   // Read protocol-version.
263   if (flags & RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL) {
264     if (!iter.ReadString(&alpn_negotiated_protocol))
265       return false;
266   }
267 
268   // Read connection info.
269   if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) {
270     int value;
271     if (!iter.ReadInt(&value))
272       return false;
273 
274     if (value > static_cast<int>(HttpConnectionInfo::kUNKNOWN) &&
275         value <= static_cast<int>(HttpConnectionInfo::kMaxValue)) {
276       connection_info = static_cast<HttpConnectionInfo>(value);
277     }
278   }
279 
280   // Read key_exchange_group
281   if (flags & RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP) {
282     int key_exchange_group;
283     if (!iter.ReadInt(&key_exchange_group))
284       return false;
285 
286     // Historically, the key_exchange_group field was key_exchange_info which
287     // conflated a number of different values based on the cipher suite, so some
288     // values must be discarded. See https://crbug.com/639421.
289     if (KeyExchangeGroupIsValid(ssl_info.connection_status))
290       ssl_info.key_exchange_group = key_exchange_group;
291   }
292 
293   // Read staleness time.
294   if (flags & RESPONSE_INFO_HAS_STALENESS) {
295     if (!iter.ReadInt64(&time_val))
296       return false;
297     stale_revalidate_timeout = base::Time() + base::Microseconds(time_val);
298   }
299 
300   was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
301 
302   was_alpn_negotiated = (flags & RESPONSE_INFO_WAS_ALPN) != 0;
303 
304   was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0;
305 
306   *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0;
307 
308   did_use_http_auth = (flags & RESPONSE_INFO_USE_HTTP_AUTHENTICATION) != 0;
309 
310   unused_since_prefetch = (flags & RESPONSE_INFO_UNUSED_SINCE_PREFETCH) != 0;
311 
312   restricted_prefetch = (flags & RESPONSE_INFO_RESTRICTED_PREFETCH) != 0;
313 
314   // RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE is unused.
315 
316   ssl_info.pkp_bypassed = (flags & RESPONSE_INFO_PKP_BYPASSED) != 0;
317 
318   // Read peer_signature_algorithm.
319   if (flags & RESPONSE_INFO_HAS_PEER_SIGNATURE_ALGORITHM) {
320     int peer_signature_algorithm;
321     if (!iter.ReadInt(&peer_signature_algorithm) ||
322         !base::IsValueInRangeForNumericType<uint16_t>(
323             peer_signature_algorithm)) {
324       return false;
325     }
326     ssl_info.peer_signature_algorithm =
327         base::checked_cast<uint16_t>(peer_signature_algorithm);
328   }
329 
330   // Read DNS aliases.
331   if (flags & RESPONSE_INFO_HAS_DNS_ALIASES) {
332     int num_aliases;
333     if (!iter.ReadInt(&num_aliases))
334       return false;
335 
336     std::string alias;
337     for (int i = 0; i < num_aliases; i++) {
338       if (!iter.ReadString(&alias))
339         return false;
340       dns_aliases.insert(alias);
341     }
342   }
343 
344   ssl_info.encrypted_client_hello =
345       (flags & RESPONSE_INFO_ENCRYPTED_CLIENT_HELLO) != 0;
346 
347   // Read browser_run_id.
348   if (flags & RESPONSE_INFO_BROWSER_RUN_ID) {
349     int64_t id;
350     if (!iter.ReadInt64(&id))
351       return false;
352     browser_run_id = std::make_optional(id);
353   }
354 
355   did_use_shared_dictionary =
356       (extra_flags & RESPONSE_EXTRA_INFO_DID_USE_SHARED_DICTIONARY) != 0;
357   return true;
358 }
359 
Persist(base::Pickle * pickle,bool skip_transient_headers,bool response_truncated) const360 void HttpResponseInfo::Persist(base::Pickle* pickle,
361                                bool skip_transient_headers,
362                                bool response_truncated) const {
363   int flags = RESPONSE_INFO_VERSION;
364   int extra_flags = 0;
365   if (ssl_info.is_valid()) {
366     flags |= RESPONSE_INFO_HAS_CERT;
367     flags |= RESPONSE_INFO_HAS_CERT_STATUS;
368     if (ssl_info.key_exchange_group != 0)
369       flags |= RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP;
370     if (ssl_info.connection_status != 0)
371       flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS;
372     if (ssl_info.peer_signature_algorithm != 0)
373       flags |= RESPONSE_INFO_HAS_PEER_SIGNATURE_ALGORITHM;
374   }
375   if (vary_data.is_valid())
376     flags |= RESPONSE_INFO_HAS_VARY_DATA;
377   if (response_truncated)
378     flags |= RESPONSE_INFO_TRUNCATED;
379   if (was_fetched_via_spdy)
380     flags |= RESPONSE_INFO_WAS_SPDY;
381   if (was_alpn_negotiated) {
382     flags |= RESPONSE_INFO_WAS_ALPN;
383     flags |= RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL;
384   }
385   if (was_fetched_via_proxy)
386     flags |= RESPONSE_INFO_WAS_PROXY;
387   if (connection_info != HttpConnectionInfo::kUNKNOWN) {
388     flags |= RESPONSE_INFO_HAS_CONNECTION_INFO;
389   }
390   if (did_use_http_auth)
391     flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION;
392   if (unused_since_prefetch)
393     flags |= RESPONSE_INFO_UNUSED_SINCE_PREFETCH;
394   if (restricted_prefetch)
395     flags |= RESPONSE_INFO_RESTRICTED_PREFETCH;
396   // RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE is not used.
397   if (ssl_info.pkp_bypassed)
398     flags |= RESPONSE_INFO_PKP_BYPASSED;
399   if (!stale_revalidate_timeout.is_null())
400     flags |= RESPONSE_INFO_HAS_STALENESS;
401   if (!dns_aliases.empty())
402     flags |= RESPONSE_INFO_HAS_DNS_ALIASES;
403   if (ssl_info.encrypted_client_hello)
404     flags |= RESPONSE_INFO_ENCRYPTED_CLIENT_HELLO;
405   if (browser_run_id.has_value())
406     flags |= RESPONSE_INFO_BROWSER_RUN_ID;
407 
408   if (did_use_shared_dictionary) {
409     extra_flags |= RESPONSE_EXTRA_INFO_DID_USE_SHARED_DICTIONARY;
410   }
411 
412   if (extra_flags) {
413     flags |= RESPONSE_INFO_HAS_EXTRA_FLAGS;
414   }
415 
416   pickle->WriteInt(flags);
417   if (extra_flags) {
418     pickle->WriteInt(extra_flags);
419   }
420   pickle->WriteInt64(request_time.ToInternalValue());
421   pickle->WriteInt64(response_time.ToInternalValue());
422 
423   HttpResponseHeaders::PersistOptions persist_options =
424       HttpResponseHeaders::PERSIST_RAW;
425 
426   if (skip_transient_headers) {
427     persist_options = HttpResponseHeaders::PERSIST_SANS_COOKIES |
428                       HttpResponseHeaders::PERSIST_SANS_CHALLENGES |
429                       HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP |
430                       HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
431                       HttpResponseHeaders::PERSIST_SANS_RANGES |
432                       HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE;
433   }
434 
435   headers->Persist(pickle, persist_options);
436 
437   if (ssl_info.is_valid()) {
438     ssl_info.cert->Persist(pickle);
439     pickle->WriteUInt32(ssl_info.cert_status);
440     if (ssl_info.connection_status != 0)
441       pickle->WriteInt(ssl_info.connection_status);
442   }
443 
444   if (vary_data.is_valid())
445     vary_data.Persist(pickle);
446 
447   pickle->WriteString(remote_endpoint.ToStringWithoutPort());
448   pickle->WriteUInt16(remote_endpoint.port());
449 
450   if (was_alpn_negotiated)
451     pickle->WriteString(alpn_negotiated_protocol);
452 
453   if (connection_info != HttpConnectionInfo::kUNKNOWN) {
454     pickle->WriteInt(static_cast<int>(connection_info));
455   }
456 
457   if (ssl_info.is_valid() && ssl_info.key_exchange_group != 0)
458     pickle->WriteInt(ssl_info.key_exchange_group);
459 
460   if (flags & RESPONSE_INFO_HAS_STALENESS) {
461     pickle->WriteInt64(
462         (stale_revalidate_timeout - base::Time()).InMicroseconds());
463   }
464 
465   if (ssl_info.is_valid() && ssl_info.peer_signature_algorithm != 0)
466     pickle->WriteInt(ssl_info.peer_signature_algorithm);
467 
468   if (!dns_aliases.empty()) {
469     pickle->WriteInt(dns_aliases.size());
470     for (const auto& alias : dns_aliases)
471       pickle->WriteString(alias);
472   }
473 
474   if (browser_run_id.has_value()) {
475     pickle->WriteInt64(browser_run_id.value());
476   }
477 }
478 
DidUseQuic() const479 bool HttpResponseInfo::DidUseQuic() const {
480   switch (connection_info) {
481     case HttpConnectionInfo::kUNKNOWN:
482     case HttpConnectionInfo::kHTTP1_1:
483     case HttpConnectionInfo::kDEPRECATED_SPDY2:
484     case HttpConnectionInfo::kDEPRECATED_SPDY3:
485     case HttpConnectionInfo::kHTTP2:
486     case HttpConnectionInfo::kDEPRECATED_HTTP2_14:
487     case HttpConnectionInfo::kDEPRECATED_HTTP2_15:
488     case HttpConnectionInfo::kHTTP0_9:
489     case HttpConnectionInfo::kHTTP1_0:
490       return false;
491     case HttpConnectionInfo::kQUIC_UNKNOWN_VERSION:
492     case HttpConnectionInfo::kQUIC_32:
493     case HttpConnectionInfo::kQUIC_33:
494     case HttpConnectionInfo::kQUIC_34:
495     case HttpConnectionInfo::kQUIC_35:
496     case HttpConnectionInfo::kQUIC_36:
497     case HttpConnectionInfo::kQUIC_37:
498     case HttpConnectionInfo::kQUIC_38:
499     case HttpConnectionInfo::kQUIC_39:
500     case HttpConnectionInfo::kQUIC_40:
501     case HttpConnectionInfo::kQUIC_41:
502     case HttpConnectionInfo::kQUIC_42:
503     case HttpConnectionInfo::kQUIC_43:
504     case HttpConnectionInfo::kQUIC_44:
505     case HttpConnectionInfo::kQUIC_45:
506     case HttpConnectionInfo::kQUIC_46:
507     case HttpConnectionInfo::kQUIC_47:
508     case HttpConnectionInfo::kQUIC_Q048:
509     case HttpConnectionInfo::kQUIC_T048:
510     case HttpConnectionInfo::kQUIC_Q049:
511     case HttpConnectionInfo::kQUIC_T049:
512     case HttpConnectionInfo::kQUIC_Q050:
513     case HttpConnectionInfo::kQUIC_T050:
514     case HttpConnectionInfo::kQUIC_Q099:
515     case HttpConnectionInfo::kQUIC_T099:
516     case HttpConnectionInfo::kQUIC_999:
517     case HttpConnectionInfo::kQUIC_DRAFT_25:
518     case HttpConnectionInfo::kQUIC_DRAFT_27:
519     case HttpConnectionInfo::kQUIC_DRAFT_28:
520     case HttpConnectionInfo::kQUIC_DRAFT_29:
521     case HttpConnectionInfo::kQUIC_T051:
522     case HttpConnectionInfo::kQUIC_RFC_V1:
523     case HttpConnectionInfo::kDEPRECATED_QUIC_2_DRAFT_1:
524     case HttpConnectionInfo::kQUIC_2_DRAFT_8:
525       return true;
526   }
527 }
528 
529 }  // namespace net
530