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