xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/crypto/quic_crypto_client_config.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
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 "quiche/quic/core/crypto/quic_crypto_client_config.h"
6 
7 #include <algorithm>
8 #include <memory>
9 #include <string>
10 
11 #include "absl/base/macros.h"
12 #include "absl/memory/memory.h"
13 #include "absl/strings/match.h"
14 #include "absl/strings/string_view.h"
15 #include "openssl/ssl.h"
16 #include "quiche/quic/core/crypto/cert_compressor.h"
17 #include "quiche/quic/core/crypto/chacha20_poly1305_encrypter.h"
18 #include "quiche/quic/core/crypto/crypto_framer.h"
19 #include "quiche/quic/core/crypto/crypto_protocol.h"
20 #include "quiche/quic/core/crypto/crypto_utils.h"
21 #include "quiche/quic/core/crypto/curve25519_key_exchange.h"
22 #include "quiche/quic/core/crypto/key_exchange.h"
23 #include "quiche/quic/core/crypto/p256_key_exchange.h"
24 #include "quiche/quic/core/crypto/proof_verifier.h"
25 #include "quiche/quic/core/crypto/quic_encrypter.h"
26 #include "quiche/quic/core/crypto/quic_random.h"
27 #include "quiche/quic/core/crypto/tls_client_connection.h"
28 #include "quiche/quic/core/quic_connection_id.h"
29 #include "quiche/quic/core/quic_types.h"
30 #include "quiche/quic/core/quic_utils.h"
31 #include "quiche/quic/platform/api/quic_bug_tracker.h"
32 #include "quiche/quic/platform/api/quic_client_stats.h"
33 #include "quiche/quic/platform/api/quic_hostname_utils.h"
34 #include "quiche/quic/platform/api/quic_logging.h"
35 
36 namespace quic {
37 
38 namespace {
39 
40 // Tracks the reason (the state of the server config) for sending inchoate
41 // ClientHello to the server.
RecordInchoateClientHelloReason(QuicCryptoClientConfig::CachedState::ServerConfigState state)42 void RecordInchoateClientHelloReason(
43     QuicCryptoClientConfig::CachedState::ServerConfigState state) {
44   QUIC_CLIENT_HISTOGRAM_ENUM(
45       "QuicInchoateClientHelloReason", state,
46       QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT, "");
47 }
48 
49 // Tracks the state of the QUIC server information loaded from the disk cache.
RecordDiskCacheServerConfigState(QuicCryptoClientConfig::CachedState::ServerConfigState state)50 void RecordDiskCacheServerConfigState(
51     QuicCryptoClientConfig::CachedState::ServerConfigState state) {
52   QUIC_CLIENT_HISTOGRAM_ENUM(
53       "QuicServerInfo.DiskCacheState", state,
54       QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT, "");
55 }
56 
57 }  // namespace
58 
QuicCryptoClientConfig(std::unique_ptr<ProofVerifier> proof_verifier)59 QuicCryptoClientConfig::QuicCryptoClientConfig(
60     std::unique_ptr<ProofVerifier> proof_verifier)
61     : QuicCryptoClientConfig(std::move(proof_verifier), nullptr) {}
62 
QuicCryptoClientConfig(std::unique_ptr<ProofVerifier> proof_verifier,std::shared_ptr<SessionCache> session_cache)63 QuicCryptoClientConfig::QuicCryptoClientConfig(
64     std::unique_ptr<ProofVerifier> proof_verifier,
65     std::shared_ptr<SessionCache> session_cache)
66     : proof_verifier_(std::move(proof_verifier)),
67       session_cache_(std::move(session_cache)),
68       ssl_ctx_(TlsClientConnection::CreateSslCtx(
69           !GetQuicFlag(quic_disable_client_tls_zero_rtt))) {
70   QUICHE_DCHECK(proof_verifier_.get());
71   SetDefaults();
72 }
73 
~QuicCryptoClientConfig()74 QuicCryptoClientConfig::~QuicCryptoClientConfig() {}
75 
CachedState()76 QuicCryptoClientConfig::CachedState::CachedState()
77     : server_config_valid_(false),
78       expiration_time_(QuicWallTime::Zero()),
79       generation_counter_(0) {}
80 
~CachedState()81 QuicCryptoClientConfig::CachedState::~CachedState() {}
82 
IsComplete(QuicWallTime now) const83 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
84   if (server_config_.empty()) {
85     RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY);
86     return false;
87   }
88 
89   if (!server_config_valid_) {
90     RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID);
91     return false;
92   }
93 
94   const CryptoHandshakeMessage* scfg = GetServerConfig();
95   if (!scfg) {
96     // Should be impossible short of cache corruption.
97     RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
98     QUICHE_DCHECK(false);
99     return false;
100   }
101 
102   if (now.IsBefore(expiration_time_)) {
103     return true;
104   }
105 
106   QUIC_CLIENT_HISTOGRAM_TIMES(
107       "QuicClientHelloServerConfig.InvalidDuration",
108       QuicTime::Delta::FromSeconds(now.ToUNIXSeconds() -
109                                    expiration_time_.ToUNIXSeconds()),
110       QuicTime::Delta::FromSeconds(60),              // 1 min.
111       QuicTime::Delta::FromSeconds(20 * 24 * 3600),  // 20 days.
112       50, "");
113   RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED);
114   return false;
115 }
116 
IsEmpty() const117 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
118   return server_config_.empty();
119 }
120 
121 const CryptoHandshakeMessage*
GetServerConfig() const122 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
123   if (server_config_.empty()) {
124     return nullptr;
125   }
126 
127   if (!scfg_) {
128     scfg_ = CryptoFramer::ParseMessage(server_config_);
129     QUICHE_DCHECK(scfg_.get());
130   }
131   return scfg_.get();
132 }
133 
134 QuicCryptoClientConfig::CachedState::ServerConfigState
SetServerConfig(absl::string_view server_config,QuicWallTime now,QuicWallTime expiry_time,std::string * error_details)135 QuicCryptoClientConfig::CachedState::SetServerConfig(
136     absl::string_view server_config, QuicWallTime now, QuicWallTime expiry_time,
137     std::string* error_details) {
138   const bool matches_existing = server_config == server_config_;
139 
140   // Even if the new server config matches the existing one, we still wish to
141   // reject it if it has expired.
142   std::unique_ptr<CryptoHandshakeMessage> new_scfg_storage;
143   const CryptoHandshakeMessage* new_scfg;
144 
145   if (!matches_existing) {
146     new_scfg_storage = CryptoFramer::ParseMessage(server_config);
147     new_scfg = new_scfg_storage.get();
148   } else {
149     new_scfg = GetServerConfig();
150   }
151 
152   if (!new_scfg) {
153     *error_details = "SCFG invalid";
154     return SERVER_CONFIG_INVALID;
155   }
156 
157   if (expiry_time.IsZero()) {
158     uint64_t expiry_seconds;
159     if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
160       *error_details = "SCFG missing EXPY";
161       return SERVER_CONFIG_INVALID_EXPIRY;
162     }
163     expiration_time_ = QuicWallTime::FromUNIXSeconds(expiry_seconds);
164   } else {
165     expiration_time_ = expiry_time;
166   }
167 
168   if (now.IsAfter(expiration_time_)) {
169     *error_details = "SCFG has expired";
170     return SERVER_CONFIG_EXPIRED;
171   }
172 
173   if (!matches_existing) {
174     server_config_ = std::string(server_config);
175     SetProofInvalid();
176     scfg_ = std::move(new_scfg_storage);
177   }
178   return SERVER_CONFIG_VALID;
179 }
180 
InvalidateServerConfig()181 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
182   server_config_.clear();
183   scfg_.reset();
184   SetProofInvalid();
185 }
186 
SetProof(const std::vector<std::string> & certs,absl::string_view cert_sct,absl::string_view chlo_hash,absl::string_view signature)187 void QuicCryptoClientConfig::CachedState::SetProof(
188     const std::vector<std::string>& certs, absl::string_view cert_sct,
189     absl::string_view chlo_hash, absl::string_view signature) {
190   bool has_changed = signature != server_config_sig_ ||
191                      chlo_hash != chlo_hash_ || certs_.size() != certs.size();
192 
193   if (!has_changed) {
194     for (size_t i = 0; i < certs_.size(); i++) {
195       if (certs_[i] != certs[i]) {
196         has_changed = true;
197         break;
198       }
199     }
200   }
201 
202   if (!has_changed) {
203     return;
204   }
205 
206   // If the proof has changed then it needs to be revalidated.
207   SetProofInvalid();
208   certs_ = certs;
209   cert_sct_ = std::string(cert_sct);
210   chlo_hash_ = std::string(chlo_hash);
211   server_config_sig_ = std::string(signature);
212 }
213 
Clear()214 void QuicCryptoClientConfig::CachedState::Clear() {
215   server_config_.clear();
216   source_address_token_.clear();
217   certs_.clear();
218   cert_sct_.clear();
219   chlo_hash_.clear();
220   server_config_sig_.clear();
221   server_config_valid_ = false;
222   proof_verify_details_.reset();
223   scfg_.reset();
224   ++generation_counter_;
225 }
226 
ClearProof()227 void QuicCryptoClientConfig::CachedState::ClearProof() {
228   SetProofInvalid();
229   certs_.clear();
230   cert_sct_.clear();
231   chlo_hash_.clear();
232   server_config_sig_.clear();
233 }
234 
SetProofValid()235 void QuicCryptoClientConfig::CachedState::SetProofValid() {
236   server_config_valid_ = true;
237 }
238 
SetProofInvalid()239 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
240   server_config_valid_ = false;
241   ++generation_counter_;
242 }
243 
Initialize(absl::string_view server_config,absl::string_view source_address_token,const std::vector<std::string> & certs,const std::string & cert_sct,absl::string_view chlo_hash,absl::string_view signature,QuicWallTime now,QuicWallTime expiration_time)244 bool QuicCryptoClientConfig::CachedState::Initialize(
245     absl::string_view server_config, absl::string_view source_address_token,
246     const std::vector<std::string>& certs, const std::string& cert_sct,
247     absl::string_view chlo_hash, absl::string_view signature, QuicWallTime now,
248     QuicWallTime expiration_time) {
249   QUICHE_DCHECK(server_config_.empty());
250 
251   if (server_config.empty()) {
252     RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY);
253     return false;
254   }
255 
256   std::string error_details;
257   ServerConfigState state =
258       SetServerConfig(server_config, now, expiration_time, &error_details);
259   RecordDiskCacheServerConfigState(state);
260   if (state != SERVER_CONFIG_VALID) {
261     QUIC_DVLOG(1) << "SetServerConfig failed with " << error_details;
262     return false;
263   }
264 
265   chlo_hash_.assign(chlo_hash.data(), chlo_hash.size());
266   server_config_sig_.assign(signature.data(), signature.size());
267   source_address_token_.assign(source_address_token.data(),
268                                source_address_token.size());
269   certs_ = certs;
270   cert_sct_ = cert_sct;
271   return true;
272 }
273 
server_config() const274 const std::string& QuicCryptoClientConfig::CachedState::server_config() const {
275   return server_config_;
276 }
277 
source_address_token() const278 const std::string& QuicCryptoClientConfig::CachedState::source_address_token()
279     const {
280   return source_address_token_;
281 }
282 
certs() const283 const std::vector<std::string>& QuicCryptoClientConfig::CachedState::certs()
284     const {
285   return certs_;
286 }
287 
cert_sct() const288 const std::string& QuicCryptoClientConfig::CachedState::cert_sct() const {
289   return cert_sct_;
290 }
291 
chlo_hash() const292 const std::string& QuicCryptoClientConfig::CachedState::chlo_hash() const {
293   return chlo_hash_;
294 }
295 
signature() const296 const std::string& QuicCryptoClientConfig::CachedState::signature() const {
297   return server_config_sig_;
298 }
299 
proof_valid() const300 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
301   return server_config_valid_;
302 }
303 
generation_counter() const304 uint64_t QuicCryptoClientConfig::CachedState::generation_counter() const {
305   return generation_counter_;
306 }
307 
308 const ProofVerifyDetails*
proof_verify_details() const309 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
310   return proof_verify_details_.get();
311 }
312 
set_source_address_token(absl::string_view token)313 void QuicCryptoClientConfig::CachedState::set_source_address_token(
314     absl::string_view token) {
315   source_address_token_ = std::string(token);
316 }
317 
set_cert_sct(absl::string_view cert_sct)318 void QuicCryptoClientConfig::CachedState::set_cert_sct(
319     absl::string_view cert_sct) {
320   cert_sct_ = std::string(cert_sct);
321 }
322 
SetProofVerifyDetails(ProofVerifyDetails * details)323 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
324     ProofVerifyDetails* details) {
325   proof_verify_details_.reset(details);
326 }
327 
InitializeFrom(const QuicCryptoClientConfig::CachedState & other)328 void QuicCryptoClientConfig::CachedState::InitializeFrom(
329     const QuicCryptoClientConfig::CachedState& other) {
330   QUICHE_DCHECK(server_config_.empty());
331   QUICHE_DCHECK(!server_config_valid_);
332   server_config_ = other.server_config_;
333   source_address_token_ = other.source_address_token_;
334   certs_ = other.certs_;
335   cert_sct_ = other.cert_sct_;
336   chlo_hash_ = other.chlo_hash_;
337   server_config_sig_ = other.server_config_sig_;
338   server_config_valid_ = other.server_config_valid_;
339   expiration_time_ = other.expiration_time_;
340   if (other.proof_verify_details_ != nullptr) {
341     proof_verify_details_.reset(other.proof_verify_details_->Clone());
342   }
343   ++generation_counter_;
344 }
345 
SetDefaults()346 void QuicCryptoClientConfig::SetDefaults() {
347   // Key exchange methods.
348   kexs = {kC255, kP256};
349 
350   // Authenticated encryption algorithms. Prefer AES-GCM if hardware-supported
351   // fast implementation is available.
352   if (EVP_has_aes_hardware() == 1) {
353     aead = {kAESG, kCC20};
354   } else {
355     aead = {kCC20, kAESG};
356   }
357 }
358 
LookupOrCreate(const QuicServerId & server_id)359 QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate(
360     const QuicServerId& server_id) {
361   auto it = cached_states_.find(server_id);
362   if (it != cached_states_.end()) {
363     return it->second.get();
364   }
365 
366   CachedState* cached = new CachedState;
367   cached_states_.insert(std::make_pair(server_id, absl::WrapUnique(cached)));
368   bool cache_populated = PopulateFromCanonicalConfig(server_id, cached);
369   QUIC_CLIENT_HISTOGRAM_BOOL(
370       "QuicCryptoClientConfig.PopulatedFromCanonicalConfig", cache_populated,
371       "");
372   return cached;
373 }
374 
ClearCachedStates(const ServerIdFilter & filter)375 void QuicCryptoClientConfig::ClearCachedStates(const ServerIdFilter& filter) {
376   for (auto it = cached_states_.begin(); it != cached_states_.end(); ++it) {
377     if (filter.Matches(it->first)) it->second->Clear();
378   }
379 }
380 
FillInchoateClientHello(const QuicServerId & server_id,const ParsedQuicVersion preferred_version,const CachedState * cached,QuicRandom * rand,bool demand_x509_proof,quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,CryptoHandshakeMessage * out) const381 void QuicCryptoClientConfig::FillInchoateClientHello(
382     const QuicServerId& server_id, const ParsedQuicVersion preferred_version,
383     const CachedState* cached, QuicRandom* rand, bool demand_x509_proof,
384     quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters>
385         out_params,
386     CryptoHandshakeMessage* out) const {
387   out->set_tag(kCHLO);
388   out->set_minimum_size(1);
389 
390   // Server name indication. We only send SNI if it's a valid domain name, as
391   // per the spec.
392   if (QuicHostnameUtils::IsValidSNI(server_id.host())) {
393     out->SetStringPiece(kSNI, server_id.host());
394   }
395   out->SetVersion(kVER, preferred_version);
396 
397   if (!user_agent_id_.empty()) {
398     out->SetStringPiece(kUAID, user_agent_id_);
399   }
400 
401   if (!alpn_.empty()) {
402     out->SetStringPiece(kALPN, alpn_);
403   }
404 
405   // Even though this is an inchoate CHLO, send the SCID so that
406   // the STK can be validated by the server.
407   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
408   if (scfg != nullptr) {
409     absl::string_view scid;
410     if (scfg->GetStringPiece(kSCID, &scid)) {
411       out->SetStringPiece(kSCID, scid);
412     }
413   }
414 
415   if (!cached->source_address_token().empty()) {
416     out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
417   }
418 
419   if (!demand_x509_proof) {
420     return;
421   }
422 
423   char proof_nonce[32];
424   rand->RandBytes(proof_nonce, ABSL_ARRAYSIZE(proof_nonce));
425   out->SetStringPiece(
426       kNONP, absl::string_view(proof_nonce, ABSL_ARRAYSIZE(proof_nonce)));
427 
428   out->SetVector(kPDMD, QuicTagVector{kX509});
429 
430   out->SetStringPiece(kCertificateSCTTag, "");
431 
432   const std::vector<std::string>& certs = cached->certs();
433   // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
434   // client config is being used for multiple connections, another connection
435   // doesn't update the cached certificates and cause us to be unable to
436   // process the server's compressed certificate chain.
437   out_params->cached_certs = certs;
438   if (!certs.empty()) {
439     std::vector<uint64_t> hashes;
440     hashes.reserve(certs.size());
441     for (auto i = certs.begin(); i != certs.end(); ++i) {
442       hashes.push_back(QuicUtils::FNV1a_64_Hash(*i));
443     }
444     out->SetVector(kCCRT, hashes);
445   }
446 }
447 
FillClientHello(const QuicServerId & server_id,QuicConnectionId connection_id,const ParsedQuicVersion preferred_version,const ParsedQuicVersion actual_version,const CachedState * cached,QuicWallTime now,QuicRandom * rand,quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,CryptoHandshakeMessage * out,std::string * error_details) const448 QuicErrorCode QuicCryptoClientConfig::FillClientHello(
449     const QuicServerId& server_id, QuicConnectionId connection_id,
450     const ParsedQuicVersion preferred_version,
451     const ParsedQuicVersion actual_version, const CachedState* cached,
452     QuicWallTime now, QuicRandom* rand,
453     quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters>
454         out_params,
455     CryptoHandshakeMessage* out, std::string* error_details) const {
456   QUICHE_DCHECK(error_details != nullptr);
457   QUIC_BUG_IF(quic_bug_12943_2,
458               !QuicUtils::IsConnectionIdValidForVersion(
459                   connection_id, preferred_version.transport_version))
460       << "FillClientHello: attempted to use connection ID " << connection_id
461       << " which is invalid with version " << preferred_version;
462 
463   FillInchoateClientHello(server_id, preferred_version, cached, rand,
464                           /* demand_x509_proof= */ true, out_params, out);
465 
466   out->set_minimum_size(1);
467 
468   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
469   if (!scfg) {
470     // This should never happen as our caller should have checked
471     // cached->IsComplete() before calling this function.
472     *error_details = "Handshake not ready";
473     return QUIC_CRYPTO_INTERNAL_ERROR;
474   }
475 
476   absl::string_view scid;
477   if (!scfg->GetStringPiece(kSCID, &scid)) {
478     *error_details = "SCFG missing SCID";
479     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
480   }
481   out->SetStringPiece(kSCID, scid);
482 
483   out->SetStringPiece(kCertificateSCTTag, "");
484 
485   QuicTagVector their_aeads;
486   QuicTagVector their_key_exchanges;
487   if (scfg->GetTaglist(kAEAD, &their_aeads) != QUIC_NO_ERROR ||
488       scfg->GetTaglist(kKEXS, &their_key_exchanges) != QUIC_NO_ERROR) {
489     *error_details = "Missing AEAD or KEXS";
490     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
491   }
492 
493   // AEAD: the work loads on the client and server are symmetric. Since the
494   // client is more likely to be CPU-constrained, break the tie by favoring
495   // the client's preference.
496   // Key exchange: the client does more work than the server, so favor the
497   // client's preference.
498   size_t key_exchange_index;
499   if (!FindMutualQuicTag(aead, their_aeads, &out_params->aead, nullptr) ||
500       !FindMutualQuicTag(kexs, their_key_exchanges, &out_params->key_exchange,
501                          &key_exchange_index)) {
502     *error_details = "Unsupported AEAD or KEXS";
503     return QUIC_CRYPTO_NO_SUPPORT;
504   }
505   out->SetVector(kAEAD, QuicTagVector{out_params->aead});
506   out->SetVector(kKEXS, QuicTagVector{out_params->key_exchange});
507 
508   absl::string_view public_value;
509   if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
510       QUIC_NO_ERROR) {
511     *error_details = "Missing public value";
512     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
513   }
514 
515   absl::string_view orbit;
516   if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) {
517     *error_details = "SCFG missing OBIT";
518     return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
519   }
520 
521   CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce);
522   out->SetStringPiece(kNONC, out_params->client_nonce);
523   if (!out_params->server_nonce.empty()) {
524     out->SetStringPiece(kServerNonceTag, out_params->server_nonce);
525   }
526 
527   switch (out_params->key_exchange) {
528     case kC255:
529       out_params->client_key_exchange = Curve25519KeyExchange::New(
530           Curve25519KeyExchange::NewPrivateKey(rand));
531       break;
532     case kP256:
533       out_params->client_key_exchange =
534           P256KeyExchange::New(P256KeyExchange::NewPrivateKey());
535       break;
536     default:
537       QUICHE_DCHECK(false);
538       *error_details = "Configured to support an unknown key exchange";
539       return QUIC_CRYPTO_INTERNAL_ERROR;
540   }
541 
542   if (!out_params->client_key_exchange->CalculateSharedKeySync(
543           public_value, &out_params->initial_premaster_secret)) {
544     *error_details = "Key exchange failure";
545     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
546   }
547   out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
548 
549   const std::vector<std::string>& certs = cached->certs();
550   if (certs.empty()) {
551     *error_details = "No certs to calculate XLCT";
552     return QUIC_CRYPTO_INTERNAL_ERROR;
553   }
554   out->SetValue(kXLCT, CryptoUtils::ComputeLeafCertHash(certs[0]));
555 
556   // Derive the symmetric keys and set up the encrypters and decrypters.
557   // Set the following members of out_params:
558   //   out_params->hkdf_input_suffix
559   //   out_params->initial_crypters
560   out_params->hkdf_input_suffix.clear();
561   out_params->hkdf_input_suffix.append(connection_id.data(),
562                                        connection_id.length());
563   const QuicData& client_hello_serialized = out->GetSerialized();
564   out_params->hkdf_input_suffix.append(client_hello_serialized.data(),
565                                        client_hello_serialized.length());
566   out_params->hkdf_input_suffix.append(cached->server_config());
567   if (certs.empty()) {
568     *error_details = "No certs found to include in KDF";
569     return QUIC_CRYPTO_INTERNAL_ERROR;
570   }
571   out_params->hkdf_input_suffix.append(certs[0]);
572 
573   std::string hkdf_input;
574   const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
575   hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
576   hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
577   hkdf_input.append(out_params->hkdf_input_suffix);
578 
579   std::string* subkey_secret = &out_params->initial_subkey_secret;
580 
581   if (!CryptoUtils::DeriveKeys(
582           actual_version, out_params->initial_premaster_secret,
583           out_params->aead, out_params->client_nonce, out_params->server_nonce,
584           pre_shared_key_, hkdf_input, Perspective::IS_CLIENT,
585           CryptoUtils::Diversification::Pending(),
586           &out_params->initial_crypters, subkey_secret)) {
587     *error_details = "Symmetric key setup failed";
588     return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
589   }
590 
591   return QUIC_NO_ERROR;
592 }
593 
CacheNewServerConfig(const CryptoHandshakeMessage & message,QuicWallTime now,QuicTransportVersion,absl::string_view chlo_hash,const std::vector<std::string> & cached_certs,CachedState * cached,std::string * error_details)594 QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig(
595     const CryptoHandshakeMessage& message, QuicWallTime now,
596     QuicTransportVersion /*version*/, absl::string_view chlo_hash,
597     const std::vector<std::string>& cached_certs, CachedState* cached,
598     std::string* error_details) {
599   QUICHE_DCHECK(error_details != nullptr);
600 
601   absl::string_view scfg;
602   if (!message.GetStringPiece(kSCFG, &scfg)) {
603     *error_details = "Missing SCFG";
604     return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
605   }
606 
607   QuicWallTime expiration_time = QuicWallTime::Zero();
608   uint64_t expiry_seconds;
609   if (message.GetUint64(kSTTL, &expiry_seconds) == QUIC_NO_ERROR) {
610     // Only cache configs for a maximum of 1 week.
611     expiration_time = now.Add(QuicTime::Delta::FromSeconds(
612         std::min(expiry_seconds, kNumSecondsPerWeek)));
613   }
614 
615   CachedState::ServerConfigState state =
616       cached->SetServerConfig(scfg, now, expiration_time, error_details);
617   if (state == CachedState::SERVER_CONFIG_EXPIRED) {
618     return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
619   }
620   // TODO(rtenneti): Return more specific error code than returning
621   // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
622   if (state != CachedState::SERVER_CONFIG_VALID) {
623     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
624   }
625 
626   absl::string_view token;
627   if (message.GetStringPiece(kSourceAddressTokenTag, &token)) {
628     cached->set_source_address_token(token);
629   }
630 
631   absl::string_view proof, cert_bytes, cert_sct;
632   bool has_proof = message.GetStringPiece(kPROF, &proof);
633   bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes);
634   if (has_proof && has_cert) {
635     std::vector<std::string> certs;
636     if (!CertCompressor::DecompressChain(cert_bytes, cached_certs, &certs)) {
637       *error_details = "Certificate data invalid";
638       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
639     }
640 
641     message.GetStringPiece(kCertificateSCTTag, &cert_sct);
642     cached->SetProof(certs, cert_sct, chlo_hash, proof);
643   } else {
644     // Secure QUIC: clear existing proof as we have been sent a new SCFG
645     // without matching proof/certs.
646     cached->ClearProof();
647 
648     if (has_proof && !has_cert) {
649       *error_details = "Certificate missing";
650       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
651     }
652 
653     if (!has_proof && has_cert) {
654       *error_details = "Proof missing";
655       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
656     }
657   }
658 
659   return QUIC_NO_ERROR;
660 }
661 
ProcessRejection(const CryptoHandshakeMessage & rej,QuicWallTime now,const QuicTransportVersion version,absl::string_view chlo_hash,CachedState * cached,quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,std::string * error_details)662 QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
663     const CryptoHandshakeMessage& rej, QuicWallTime now,
664     const QuicTransportVersion version, absl::string_view chlo_hash,
665     CachedState* cached,
666     quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters>
667         out_params,
668     std::string* error_details) {
669   QUICHE_DCHECK(error_details != nullptr);
670 
671   if (rej.tag() != kREJ) {
672     *error_details = "Message is not REJ";
673     return QUIC_CRYPTO_INTERNAL_ERROR;
674   }
675 
676   QuicErrorCode error =
677       CacheNewServerConfig(rej, now, version, chlo_hash,
678                            out_params->cached_certs, cached, error_details);
679   if (error != QUIC_NO_ERROR) {
680     return error;
681   }
682 
683   absl::string_view nonce;
684   if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
685     out_params->server_nonce = std::string(nonce);
686   }
687 
688   return QUIC_NO_ERROR;
689 }
690 
ProcessServerHello(const CryptoHandshakeMessage & server_hello,QuicConnectionId,ParsedQuicVersion version,const ParsedQuicVersionVector & negotiated_versions,CachedState * cached,quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,std::string * error_details)691 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
692     const CryptoHandshakeMessage& server_hello,
693     QuicConnectionId /*connection_id*/, ParsedQuicVersion version,
694     const ParsedQuicVersionVector& negotiated_versions, CachedState* cached,
695     quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters>
696         out_params,
697     std::string* error_details) {
698   QUICHE_DCHECK(error_details != nullptr);
699 
700   QuicErrorCode valid = CryptoUtils::ValidateServerHello(
701       server_hello, negotiated_versions, error_details);
702   if (valid != QUIC_NO_ERROR) {
703     return valid;
704   }
705 
706   // Learn about updated source address tokens.
707   absl::string_view token;
708   if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) {
709     cached->set_source_address_token(token);
710   }
711 
712   absl::string_view shlo_nonce;
713   if (!server_hello.GetStringPiece(kServerNonceTag, &shlo_nonce)) {
714     *error_details = "server hello missing server nonce";
715     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
716   }
717 
718   // TODO(agl):
719   //   learn about updated SCFGs.
720 
721   absl::string_view public_value;
722   if (!server_hello.GetStringPiece(kPUBS, &public_value)) {
723     *error_details = "server hello missing forward secure public value";
724     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
725   }
726 
727   if (!out_params->client_key_exchange->CalculateSharedKeySync(
728           public_value, &out_params->forward_secure_premaster_secret)) {
729     *error_details = "Key exchange failure";
730     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
731   }
732 
733   std::string hkdf_input;
734   const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
735   hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
736   hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
737   hkdf_input.append(out_params->hkdf_input_suffix);
738 
739   if (!CryptoUtils::DeriveKeys(
740           version, out_params->forward_secure_premaster_secret,
741           out_params->aead, out_params->client_nonce,
742           shlo_nonce.empty() ? out_params->server_nonce : shlo_nonce,
743           pre_shared_key_, hkdf_input, Perspective::IS_CLIENT,
744           CryptoUtils::Diversification::Never(),
745           &out_params->forward_secure_crypters, &out_params->subkey_secret)) {
746     *error_details = "Symmetric key setup failed";
747     return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
748   }
749 
750   return QUIC_NO_ERROR;
751 }
752 
ProcessServerConfigUpdate(const CryptoHandshakeMessage & server_config_update,QuicWallTime now,const QuicTransportVersion version,absl::string_view chlo_hash,CachedState * cached,quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,std::string * error_details)753 QuicErrorCode QuicCryptoClientConfig::ProcessServerConfigUpdate(
754     const CryptoHandshakeMessage& server_config_update, QuicWallTime now,
755     const QuicTransportVersion version, absl::string_view chlo_hash,
756     CachedState* cached,
757     quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters>
758         out_params,
759     std::string* error_details) {
760   QUICHE_DCHECK(error_details != nullptr);
761 
762   if (server_config_update.tag() != kSCUP) {
763     *error_details = "ServerConfigUpdate must have kSCUP tag.";
764     return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
765   }
766   return CacheNewServerConfig(server_config_update, now, version, chlo_hash,
767                               out_params->cached_certs, cached, error_details);
768 }
769 
proof_verifier() const770 ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
771   return proof_verifier_.get();
772 }
773 
session_cache() const774 SessionCache* QuicCryptoClientConfig::session_cache() const {
775   return session_cache_.get();
776 }
777 
set_session_cache(std::shared_ptr<SessionCache> session_cache)778 void QuicCryptoClientConfig::set_session_cache(
779     std::shared_ptr<SessionCache> session_cache) {
780   session_cache_ = std::move(session_cache);
781 }
782 
proof_source() const783 ClientProofSource* QuicCryptoClientConfig::proof_source() const {
784   return proof_source_.get();
785 }
786 
set_proof_source(std::unique_ptr<ClientProofSource> proof_source)787 void QuicCryptoClientConfig::set_proof_source(
788     std::unique_ptr<ClientProofSource> proof_source) {
789   proof_source_ = std::move(proof_source);
790 }
791 
ssl_ctx() const792 SSL_CTX* QuicCryptoClientConfig::ssl_ctx() const { return ssl_ctx_.get(); }
793 
InitializeFrom(const QuicServerId & server_id,const QuicServerId & canonical_server_id,QuicCryptoClientConfig * canonical_crypto_config)794 void QuicCryptoClientConfig::InitializeFrom(
795     const QuicServerId& server_id, const QuicServerId& canonical_server_id,
796     QuicCryptoClientConfig* canonical_crypto_config) {
797   CachedState* canonical_cached =
798       canonical_crypto_config->LookupOrCreate(canonical_server_id);
799   if (!canonical_cached->proof_valid()) {
800     return;
801   }
802   CachedState* cached = LookupOrCreate(server_id);
803   cached->InitializeFrom(*canonical_cached);
804 }
805 
AddCanonicalSuffix(const std::string & suffix)806 void QuicCryptoClientConfig::AddCanonicalSuffix(const std::string& suffix) {
807   canonical_suffixes_.push_back(suffix);
808 }
809 
PopulateFromCanonicalConfig(const QuicServerId & server_id,CachedState * cached)810 bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
811     const QuicServerId& server_id, CachedState* cached) {
812   QUICHE_DCHECK(cached->IsEmpty());
813   size_t i = 0;
814   for (; i < canonical_suffixes_.size(); ++i) {
815     if (absl::EndsWithIgnoreCase(server_id.host(), canonical_suffixes_[i])) {
816       break;
817     }
818   }
819   if (i == canonical_suffixes_.size()) {
820     return false;
821   }
822 
823   QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
824                                 server_id.privacy_mode_enabled());
825   auto it = canonical_server_map_.lower_bound(suffix_server_id);
826   if (it == canonical_server_map_.end() || it->first != suffix_server_id) {
827     // This is the first host we've seen which matches the suffix, so make it
828     // canonical.  Use |it| as position hint for faster insertion.
829     canonical_server_map_.insert(
830         it, std::make_pair(std::move(suffix_server_id), std::move(server_id)));
831     return false;
832   }
833 
834   const QuicServerId& canonical_server_id = it->second;
835   CachedState* canonical_state = cached_states_[canonical_server_id].get();
836   if (!canonical_state->proof_valid()) {
837     return false;
838   }
839 
840   // Update canonical version to point at the "most recent" entry.
841   it->second = server_id;
842 
843   cached->InitializeFrom(*canonical_state);
844   return true;
845 }
846 
847 }  // namespace quic
848