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.
5 #include "net/quic/crypto/quic_crypto_client_config.h"
7 #include "base/metrics/histogram.h"
8 #include "base/metrics/sparse_histogram.h"
9 #include "base/profiler/scoped_tracker.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "net/quic/crypto/cert_compressor.h"
13 #include "net/quic/crypto/chacha20_poly1305_encrypter.h"
14 #include "net/quic/crypto/channel_id.h"
15 #include "net/quic/crypto/common_cert_set.h"
16 #include "net/quic/crypto/crypto_framer.h"
17 #include "net/quic/crypto/crypto_utils.h"
18 #include "net/quic/crypto/curve25519_key_exchange.h"
19 #include "net/quic/crypto/key_exchange.h"
20 #include "net/quic/crypto/p256_key_exchange.h"
21 #include "net/quic/crypto/proof_verifier.h"
22 #include "net/quic/crypto/quic_encrypter.h"
23 #include "net/quic/quic_utils.h"
25 using base::StringPiece
;
34 // Tracks the reason (the state of the server config) for sending inchoate
35 // ClientHello to the server.
36 void RecordInchoateClientHelloReason(
37 QuicCryptoClientConfig::CachedState::ServerConfigState state
) {
38 UMA_HISTOGRAM_ENUMERATION(
39 "Net.QuicInchoateClientHelloReason", state
,
40 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT
);
43 // Tracks the state of the QUIC server information loaded from the disk cache.
44 void RecordDiskCacheServerConfigState(
45 QuicCryptoClientConfig::CachedState::ServerConfigState state
) {
46 UMA_HISTOGRAM_ENUMERATION(
47 "Net.QuicServerInfo.DiskCacheState", state
,
48 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT
);
53 QuicCryptoClientConfig::QuicCryptoClientConfig()
54 : disable_ecdsa_(false) {
58 QuicCryptoClientConfig::~QuicCryptoClientConfig() {
59 STLDeleteValues(&cached_states_
);
62 QuicCryptoClientConfig::CachedState::CachedState()
63 : server_config_valid_(false),
64 generation_counter_(0) {}
66 QuicCryptoClientConfig::CachedState::~CachedState() {}
68 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now
) const {
69 if (server_config_
.empty()) {
70 RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY
);
74 if (!server_config_valid_
) {
75 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID
);
79 const CryptoHandshakeMessage
* scfg
= GetServerConfig();
81 // Should be impossible short of cache corruption.
83 RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED
);
87 uint64 expiry_seconds
;
88 if (scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
89 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY
);
92 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
93 UMA_HISTOGRAM_CUSTOM_TIMES(
94 "Net.QuicClientHelloServerConfig.InvalidDuration",
95 base::TimeDelta::FromSeconds(now
.ToUNIXSeconds() - expiry_seconds
),
96 base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
97 RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED
);
104 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
105 return server_config_
.empty();
108 const CryptoHandshakeMessage
*
109 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
110 if (server_config_
.empty()) {
115 scfg_
.reset(CryptoFramer::ParseMessage(server_config_
));
121 QuicCryptoClientConfig::CachedState::ServerConfigState
122 QuicCryptoClientConfig::CachedState::SetServerConfig(
123 StringPiece server_config
, QuicWallTime now
, string
* error_details
) {
124 const bool matches_existing
= server_config
== server_config_
;
126 // Even if the new server config matches the existing one, we still wish to
127 // reject it if it has expired.
128 scoped_ptr
<CryptoHandshakeMessage
> new_scfg_storage
;
129 const CryptoHandshakeMessage
* new_scfg
;
131 if (!matches_existing
) {
132 new_scfg_storage
.reset(CryptoFramer::ParseMessage(server_config
));
133 new_scfg
= new_scfg_storage
.get();
135 new_scfg
= GetServerConfig();
139 *error_details
= "SCFG invalid";
140 return SERVER_CONFIG_INVALID
;
143 uint64 expiry_seconds
;
144 if (new_scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
145 *error_details
= "SCFG missing EXPY";
146 return SERVER_CONFIG_INVALID_EXPIRY
;
149 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
150 *error_details
= "SCFG has expired";
151 return SERVER_CONFIG_EXPIRED
;
154 if (!matches_existing
) {
155 server_config_
= server_config
.as_string();
157 scfg_
.reset(new_scfg_storage
.release());
159 return SERVER_CONFIG_VALID
;
162 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
163 server_config_
.clear();
168 void QuicCryptoClientConfig::CachedState::SetProof(const vector
<string
>& certs
,
169 StringPiece signature
) {
171 signature
!= server_config_sig_
|| certs_
.size() != certs
.size();
174 for (size_t i
= 0; i
< certs_
.size(); i
++) {
175 if (certs_
[i
] != certs
[i
]) {
186 // If the proof has changed then it needs to be revalidated.
189 server_config_sig_
= signature
.as_string();
192 void QuicCryptoClientConfig::CachedState::Clear() {
193 server_config_
.clear();
194 source_address_token_
.clear();
196 server_config_sig_
.clear();
197 server_config_valid_
= false;
198 proof_verify_details_
.reset();
200 ++generation_counter_
;
203 void QuicCryptoClientConfig::CachedState::ClearProof() {
206 server_config_sig_
.clear();
209 void QuicCryptoClientConfig::CachedState::SetProofValid() {
210 server_config_valid_
= true;
213 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
214 server_config_valid_
= false;
215 ++generation_counter_
;
218 bool QuicCryptoClientConfig::CachedState::Initialize(
219 StringPiece server_config
,
220 StringPiece source_address_token
,
221 const vector
<string
>& certs
,
222 StringPiece signature
,
224 DCHECK(server_config_
.empty());
226 if (server_config
.empty()) {
227 RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY
);
231 string error_details
;
232 ServerConfigState state
= SetServerConfig(server_config
, now
,
234 RecordDiskCacheServerConfigState(state
);
235 if (state
!= SERVER_CONFIG_VALID
) {
236 DVLOG(1) << "SetServerConfig failed with " << error_details
;
240 signature
.CopyToString(&server_config_sig_
);
241 source_address_token
.CopyToString(&source_address_token_
);
246 const string
& QuicCryptoClientConfig::CachedState::server_config() const {
247 return server_config_
;
251 QuicCryptoClientConfig::CachedState::source_address_token() const {
252 return source_address_token_
;
255 const vector
<string
>& QuicCryptoClientConfig::CachedState::certs() const {
259 const string
& QuicCryptoClientConfig::CachedState::signature() const {
260 return server_config_sig_
;
263 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
264 return server_config_valid_
;
267 uint64
QuicCryptoClientConfig::CachedState::generation_counter() const {
268 return generation_counter_
;
271 const ProofVerifyDetails
*
272 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
273 return proof_verify_details_
.get();
276 void QuicCryptoClientConfig::CachedState::set_source_address_token(
278 source_address_token_
= token
.as_string();
281 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
282 ProofVerifyDetails
* details
) {
283 proof_verify_details_
.reset(details
);
286 void QuicCryptoClientConfig::CachedState::InitializeFrom(
287 const QuicCryptoClientConfig::CachedState
& other
) {
288 DCHECK(server_config_
.empty());
289 DCHECK(!server_config_valid_
);
290 server_config_
= other
.server_config_
;
291 source_address_token_
= other
.source_address_token_
;
292 certs_
= other
.certs_
;
293 server_config_sig_
= other
.server_config_sig_
;
294 server_config_valid_
= other
.server_config_valid_
;
295 if (other
.proof_verify_details_
.get() != nullptr) {
296 proof_verify_details_
.reset(other
.proof_verify_details_
->Clone());
298 ++generation_counter_
;
301 void QuicCryptoClientConfig::SetDefaults() {
302 // Key exchange methods.
307 // Authenticated encryption algorithms. Prefer ChaCha20 by default.
309 if (ChaCha20Poly1305Encrypter::IsSupported()) {
310 aead
.push_back(kCC12
);
312 aead
.push_back(kAESG
);
314 disable_ecdsa_
= false;
317 QuicCryptoClientConfig::CachedState
* QuicCryptoClientConfig::LookupOrCreate(
318 const QuicServerId
& server_id
) {
319 CachedStateMap::const_iterator it
= cached_states_
.find(server_id
);
320 if (it
!= cached_states_
.end()) {
324 CachedState
* cached
= new CachedState
;
325 cached_states_
.insert(std::make_pair(server_id
, cached
));
326 bool cache_populated
= PopulateFromCanonicalConfig(server_id
, cached
);
327 UMA_HISTOGRAM_BOOLEAN(
328 "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig",
333 void QuicCryptoClientConfig::ClearCachedStates() {
334 for (CachedStateMap::const_iterator it
= cached_states_
.begin();
335 it
!= cached_states_
.end(); ++it
) {
340 void QuicCryptoClientConfig::FillInchoateClientHello(
341 const QuicServerId
& server_id
,
342 const QuicVersion preferred_version
,
343 const CachedState
* cached
,
344 QuicCryptoNegotiatedParameters
* out_params
,
345 CryptoHandshakeMessage
* out
) const {
346 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
347 tracked_objects::ScopedTracker
tracking_profile(
348 FROM_HERE_WITH_EXPLICIT_FUNCTION(
349 "422516 QuicCryptoClientConfig::FillInchoateClientHello"));
352 out
->set_minimum_size(kClientHelloMinimumSize
);
354 // Server name indication. We only send SNI if it's a valid domain name, as
356 if (CryptoUtils::IsValidSNI(server_id
.host())) {
357 out
->SetStringPiece(kSNI
, server_id
.host());
359 out
->SetValue(kVER
, QuicVersionToQuicTag(preferred_version
));
361 if (!user_agent_id_
.empty()) {
362 out
->SetStringPiece(kUAID
, user_agent_id_
);
365 if (!cached
->source_address_token().empty()) {
366 out
->SetStringPiece(kSourceAddressTokenTag
, cached
->source_address_token());
369 if (server_id
.is_https()) {
370 if (disable_ecdsa_
) {
371 out
->SetTaglist(kPDMD
, kX59R
, 0);
373 out
->SetTaglist(kPDMD
, kX509
, 0);
377 if (common_cert_sets
) {
378 out
->SetStringPiece(kCCS
, common_cert_sets
->GetCommonHashes());
381 const vector
<string
>& certs
= cached
->certs();
382 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
383 // client config is being used for multiple connections, another connection
384 // doesn't update the cached certificates and cause us to be unable to
385 // process the server's compressed certificate chain.
386 out_params
->cached_certs
= certs
;
387 if (!certs
.empty()) {
388 vector
<uint64
> hashes
;
389 hashes
.reserve(certs
.size());
390 for (vector
<string
>::const_iterator i
= certs
.begin();
391 i
!= certs
.end(); ++i
) {
392 hashes
.push_back(QuicUtils::FNV1a_64_Hash(i
->data(), i
->size()));
394 out
->SetVector(kCCRT
, hashes
);
398 QuicErrorCode
QuicCryptoClientConfig::FillClientHello(
399 const QuicServerId
& server_id
,
400 QuicConnectionId connection_id
,
401 const QuicVersion preferred_version
,
402 const CachedState
* cached
,
405 const ChannelIDKey
* channel_id_key
,
406 QuicCryptoNegotiatedParameters
* out_params
,
407 CryptoHandshakeMessage
* out
,
408 string
* error_details
) const {
409 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
410 tracked_objects::ScopedTracker
tracking_profile(
411 FROM_HERE_WITH_EXPLICIT_FUNCTION(
412 "422516 QuicCryptoClientConfig::FillClientHello"));
414 DCHECK(error_details
!= nullptr);
416 FillInchoateClientHello(server_id
, preferred_version
, cached
,
419 const CryptoHandshakeMessage
* scfg
= cached
->GetServerConfig();
421 // This should never happen as our caller should have checked
422 // cached->IsComplete() before calling this function.
423 *error_details
= "Handshake not ready";
424 return QUIC_CRYPTO_INTERNAL_ERROR
;
428 if (!scfg
->GetStringPiece(kSCID
, &scid
)) {
429 *error_details
= "SCFG missing SCID";
430 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
432 out
->SetStringPiece(kSCID
, scid
);
434 const QuicTag
* their_aeads
;
435 const QuicTag
* their_key_exchanges
;
436 size_t num_their_aeads
, num_their_key_exchanges
;
437 if (scfg
->GetTaglist(kAEAD
, &their_aeads
,
438 &num_their_aeads
) != QUIC_NO_ERROR
||
439 scfg
->GetTaglist(kKEXS
, &their_key_exchanges
,
440 &num_their_key_exchanges
) != QUIC_NO_ERROR
) {
441 *error_details
= "Missing AEAD or KEXS";
442 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
445 // AEAD: the work loads on the client and server are symmetric. Since the
446 // client is more likely to be CPU-constrained, break the tie by favoring
447 // the client's preference.
448 // Key exchange: the client does more work than the server, so favor the
449 // client's preference.
450 size_t key_exchange_index
;
451 if (!QuicUtils::FindMutualTag(
452 aead
, their_aeads
, num_their_aeads
, QuicUtils::LOCAL_PRIORITY
,
453 &out_params
->aead
, nullptr) ||
454 !QuicUtils::FindMutualTag(
455 kexs
, their_key_exchanges
, num_their_key_exchanges
,
456 QuicUtils::LOCAL_PRIORITY
, &out_params
->key_exchange
,
457 &key_exchange_index
)) {
458 *error_details
= "Unsupported AEAD or KEXS";
459 return QUIC_CRYPTO_NO_SUPPORT
;
461 out
->SetTaglist(kAEAD
, out_params
->aead
, 0);
462 out
->SetTaglist(kKEXS
, out_params
->key_exchange
, 0);
464 StringPiece public_value
;
465 if (scfg
->GetNthValue24(kPUBS
, key_exchange_index
, &public_value
) !=
467 *error_details
= "Missing public value";
468 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
472 if (!scfg
->GetStringPiece(kORBT
, &orbit
) || orbit
.size() != kOrbitSize
) {
473 *error_details
= "SCFG missing OBIT";
474 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
477 CryptoUtils::GenerateNonce(now
, rand
, orbit
, &out_params
->client_nonce
);
478 out
->SetStringPiece(kNONC
, out_params
->client_nonce
);
479 if (!out_params
->server_nonce
.empty()) {
480 out
->SetStringPiece(kServerNonceTag
, out_params
->server_nonce
);
483 switch (out_params
->key_exchange
) {
485 out_params
->client_key_exchange
.reset(Curve25519KeyExchange::New(
486 Curve25519KeyExchange::NewPrivateKey(rand
)));
489 out_params
->client_key_exchange
.reset(P256KeyExchange::New(
490 P256KeyExchange::NewPrivateKey()));
494 *error_details
= "Configured to support an unknown key exchange";
495 return QUIC_CRYPTO_INTERNAL_ERROR
;
498 if (!out_params
->client_key_exchange
->CalculateSharedKey(
499 public_value
, &out_params
->initial_premaster_secret
)) {
500 *error_details
= "Key exchange failure";
501 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
503 out
->SetStringPiece(kPUBS
, out_params
->client_key_exchange
->public_value());
505 if (channel_id_key
) {
506 // In order to calculate the encryption key for the CETV block we need to
507 // serialise the client hello as it currently is (i.e. without the CETV
508 // block). For this, the client hello is serialized without padding.
509 const size_t orig_min_size
= out
->minimum_size();
510 out
->set_minimum_size(0);
512 CryptoHandshakeMessage cetv
;
516 const QuicData
& client_hello_serialized
= out
->GetSerialized();
517 hkdf_input
.append(QuicCryptoConfig::kCETVLabel
,
518 strlen(QuicCryptoConfig::kCETVLabel
) + 1);
519 hkdf_input
.append(reinterpret_cast<char*>(&connection_id
),
520 sizeof(connection_id
));
521 hkdf_input
.append(client_hello_serialized
.data(),
522 client_hello_serialized
.length());
523 hkdf_input
.append(cached
->server_config());
525 string key
= channel_id_key
->SerializeKey();
527 if (!channel_id_key
->Sign(hkdf_input
, &signature
)) {
528 *error_details
= "Channel ID signature failed";
529 return QUIC_INVALID_CHANNEL_ID_SIGNATURE
;
532 cetv
.SetStringPiece(kCIDK
, key
);
533 cetv
.SetStringPiece(kCIDS
, signature
);
535 CrypterPair crypters
;
536 if (!CryptoUtils::DeriveKeys(out_params
->initial_premaster_secret
,
537 out_params
->aead
, out_params
->client_nonce
,
538 out_params
->server_nonce
, hkdf_input
,
539 CryptoUtils::CLIENT
, &crypters
,
540 nullptr /* subkey secret */)) {
541 *error_details
= "Symmetric key setup failed";
542 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
545 const QuicData
& cetv_plaintext
= cetv
.GetSerialized();
546 const size_t encrypted_len
=
547 crypters
.encrypter
->GetCiphertextSize(cetv_plaintext
.length());
548 scoped_ptr
<char[]> output(new char[encrypted_len
]);
549 size_t output_size
= 0;
550 if (!crypters
.encrypter
->EncryptPacket(
551 0 /* sequence number */, StringPiece() /* associated data */,
552 cetv_plaintext
.AsStringPiece(), output
.get(), &output_size
,
554 *error_details
= "Packet encryption failed";
555 return QUIC_ENCRYPTION_FAILURE
;
558 out
->SetStringPiece(kCETV
, StringPiece(output
.get(), output_size
));
561 out
->set_minimum_size(orig_min_size
);
564 // Derive the symmetric keys and set up the encrypters and decrypters.
565 // Set the following members of out_params:
566 // out_params->hkdf_input_suffix
567 // out_params->initial_crypters
568 out_params
->hkdf_input_suffix
.clear();
569 out_params
->hkdf_input_suffix
.append(reinterpret_cast<char*>(&connection_id
),
570 sizeof(connection_id
));
571 const QuicData
& client_hello_serialized
= out
->GetSerialized();
572 out_params
->hkdf_input_suffix
.append(client_hello_serialized
.data(),
573 client_hello_serialized
.length());
574 out_params
->hkdf_input_suffix
.append(cached
->server_config());
577 const size_t label_len
= strlen(QuicCryptoConfig::kInitialLabel
) + 1;
578 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
579 hkdf_input
.append(QuicCryptoConfig::kInitialLabel
, label_len
);
580 hkdf_input
.append(out_params
->hkdf_input_suffix
);
582 if (!CryptoUtils::DeriveKeys(
583 out_params
->initial_premaster_secret
, out_params
->aead
,
584 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
585 CryptoUtils::CLIENT
, &out_params
->initial_crypters
,
586 nullptr /* subkey secret */)) {
587 *error_details
= "Symmetric key setup failed";
588 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
591 return QUIC_NO_ERROR
;
594 QuicErrorCode
QuicCryptoClientConfig::CacheNewServerConfig(
595 const CryptoHandshakeMessage
& message
,
597 const vector
<string
>& cached_certs
,
599 string
* error_details
) {
600 DCHECK(error_details
!= nullptr);
603 if (!message
.GetStringPiece(kSCFG
, &scfg
)) {
604 *error_details
= "Missing SCFG";
605 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
608 CachedState::ServerConfigState state
= cached
->SetServerConfig(
609 scfg
, now
, error_details
);
610 if (state
== CachedState::SERVER_CONFIG_EXPIRED
) {
611 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED
;
613 // TODO(rtenneti): Return more specific error code than returning
614 // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
615 if (state
!= CachedState::SERVER_CONFIG_VALID
) {
616 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
620 if (message
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
621 cached
->set_source_address_token(token
);
624 StringPiece proof
, cert_bytes
;
625 bool has_proof
= message
.GetStringPiece(kPROF
, &proof
);
626 bool has_cert
= message
.GetStringPiece(kCertificateTag
, &cert_bytes
);
627 if (has_proof
&& has_cert
) {
628 vector
<string
> certs
;
629 if (!CertCompressor::DecompressChain(cert_bytes
, cached_certs
,
630 common_cert_sets
, &certs
)) {
631 *error_details
= "Certificate data invalid";
632 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
635 cached
->SetProof(certs
, proof
);
637 if (proof_verifier() != nullptr) {
638 // Secure QUIC: clear existing proof as we have been sent a new SCFG
639 // without matching proof/certs.
640 cached
->ClearProof();
643 if (has_proof
&& !has_cert
) {
644 *error_details
= "Certificate missing";
645 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
648 if (!has_proof
&& has_cert
) {
649 *error_details
= "Proof missing";
650 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
654 return QUIC_NO_ERROR
;
657 QuicErrorCode
QuicCryptoClientConfig::ProcessRejection(
658 const CryptoHandshakeMessage
& rej
,
662 QuicCryptoNegotiatedParameters
* out_params
,
663 string
* error_details
) {
664 DCHECK(error_details
!= nullptr);
666 if (rej
.tag() != kREJ
) {
667 *error_details
= "Message is not REJ";
668 return QUIC_CRYPTO_INTERNAL_ERROR
;
671 QuicErrorCode error
= CacheNewServerConfig(rej
, now
, out_params
->cached_certs
,
672 cached
, error_details
);
673 if (error
!= QUIC_NO_ERROR
) {
678 if (rej
.GetStringPiece(kServerNonceTag
, &nonce
)) {
679 out_params
->server_nonce
= nonce
.as_string();
682 const uint32
* reject_reasons
;
683 size_t num_reject_reasons
;
684 static_assert(sizeof(QuicTag
) == sizeof(uint32
), "header out of sync");
685 if (rej
.GetTaglist(kRREJ
, &reject_reasons
,
686 &num_reject_reasons
) == QUIC_NO_ERROR
) {
687 uint32 packed_error
= 0;
688 for (size_t i
= 0; i
< num_reject_reasons
; ++i
) {
689 // HANDSHAKE_OK is 0 and don't report that as error.
690 if (reject_reasons
[i
] == HANDSHAKE_OK
|| reject_reasons
[i
] >= 32) {
693 HandshakeFailureReason reason
=
694 static_cast<HandshakeFailureReason
>(reject_reasons
[i
]);
695 packed_error
|= 1 << (reason
- 1);
697 DVLOG(1) << "Reasons for rejection: " << packed_error
;
699 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
702 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Insecure",
707 return QUIC_NO_ERROR
;
710 QuicErrorCode
QuicCryptoClientConfig::ProcessServerHello(
711 const CryptoHandshakeMessage
& server_hello
,
712 QuicConnectionId connection_id
,
713 const QuicVersionVector
& negotiated_versions
,
715 QuicCryptoNegotiatedParameters
* out_params
,
716 string
* error_details
) {
717 DCHECK(error_details
!= nullptr);
719 if (server_hello
.tag() != kSHLO
) {
720 *error_details
= "Bad tag";
721 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
724 const QuicTag
* supported_version_tags
;
725 size_t num_supported_versions
;
727 if (server_hello
.GetTaglist(kVER
, &supported_version_tags
,
728 &num_supported_versions
) != QUIC_NO_ERROR
) {
729 *error_details
= "server hello missing version list";
730 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
732 if (!negotiated_versions
.empty()) {
733 bool mismatch
= num_supported_versions
!= negotiated_versions
.size();
734 for (size_t i
= 0; i
< num_supported_versions
&& !mismatch
; ++i
) {
735 mismatch
= QuicTagToQuicVersion(supported_version_tags
[i
]) !=
736 negotiated_versions
[i
];
738 // The server sent a list of supported versions, and the connection
739 // reports that there was a version negotiation during the handshake.
740 // Ensure that these two lists are identical.
742 *error_details
= "Downgrade attack detected";
743 return QUIC_VERSION_NEGOTIATION_MISMATCH
;
747 // Learn about updated source address tokens.
749 if (server_hello
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
750 cached
->set_source_address_token(token
);
754 // learn about updated SCFGs.
756 StringPiece public_value
;
757 if (!server_hello
.GetStringPiece(kPUBS
, &public_value
)) {
758 *error_details
= "server hello missing forward secure public value";
759 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
762 if (!out_params
->client_key_exchange
->CalculateSharedKey(
763 public_value
, &out_params
->forward_secure_premaster_secret
)) {
764 *error_details
= "Key exchange failure";
765 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
769 const size_t label_len
= strlen(QuicCryptoConfig::kForwardSecureLabel
) + 1;
770 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
771 hkdf_input
.append(QuicCryptoConfig::kForwardSecureLabel
, label_len
);
772 hkdf_input
.append(out_params
->hkdf_input_suffix
);
774 if (!CryptoUtils::DeriveKeys(
775 out_params
->forward_secure_premaster_secret
, out_params
->aead
,
776 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
777 CryptoUtils::CLIENT
, &out_params
->forward_secure_crypters
,
778 &out_params
->subkey_secret
)) {
779 *error_details
= "Symmetric key setup failed";
780 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
783 return QUIC_NO_ERROR
;
786 QuicErrorCode
QuicCryptoClientConfig::ProcessServerConfigUpdate(
787 const CryptoHandshakeMessage
& server_config_update
,
790 QuicCryptoNegotiatedParameters
* out_params
,
791 string
* error_details
) {
792 DCHECK(error_details
!= nullptr);
794 if (server_config_update
.tag() != kSCUP
) {
795 *error_details
= "ServerConfigUpdate must have kSCUP tag.";
796 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
799 return CacheNewServerConfig(server_config_update
, now
,
800 out_params
->cached_certs
, cached
, error_details
);
803 ProofVerifier
* QuicCryptoClientConfig::proof_verifier() const {
804 return proof_verifier_
.get();
807 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier
* verifier
) {
808 proof_verifier_
.reset(verifier
);
811 ChannelIDSource
* QuicCryptoClientConfig::channel_id_source() const {
812 return channel_id_source_
.get();
815 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource
* source
) {
816 channel_id_source_
.reset(source
);
819 void QuicCryptoClientConfig::InitializeFrom(
820 const QuicServerId
& server_id
,
821 const QuicServerId
& canonical_server_id
,
822 QuicCryptoClientConfig
* canonical_crypto_config
) {
823 CachedState
* canonical_cached
=
824 canonical_crypto_config
->LookupOrCreate(canonical_server_id
);
825 if (!canonical_cached
->proof_valid()) {
828 CachedState
* cached
= LookupOrCreate(server_id
);
829 cached
->InitializeFrom(*canonical_cached
);
832 void QuicCryptoClientConfig::AddCanonicalSuffix(const string
& suffix
) {
833 canonical_suffixes_
.push_back(suffix
);
836 void QuicCryptoClientConfig::PreferAesGcm() {
837 DCHECK(!aead
.empty());
838 if (aead
.size() <= 1) {
841 QuicTagVector::iterator pos
= std::find(aead
.begin(), aead
.end(), kAESG
);
842 if (pos
!= aead
.end()) {
844 aead
.insert(aead
.begin(), kAESG
);
848 void QuicCryptoClientConfig::DisableEcdsa() {
849 disable_ecdsa_
= true;
852 bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
853 const QuicServerId
& server_id
,
854 CachedState
* server_state
) {
855 DCHECK(server_state
->IsEmpty());
857 for (; i
< canonical_suffixes_
.size(); ++i
) {
858 if (EndsWith(server_id
.host(), canonical_suffixes_
[i
], false)) {
862 if (i
== canonical_suffixes_
.size()) {
866 QuicServerId
suffix_server_id(canonical_suffixes_
[i
], server_id
.port(),
867 server_id
.is_https(),
868 server_id
.privacy_mode());
869 if (!ContainsKey(canonical_server_map_
, suffix_server_id
)) {
870 // This is the first host we've seen which matches the suffix, so make it
872 canonical_server_map_
[suffix_server_id
] = server_id
;
876 const QuicServerId
& canonical_server_id
=
877 canonical_server_map_
[suffix_server_id
];
878 CachedState
* canonical_state
= cached_states_
[canonical_server_id
];
879 if (!canonical_state
->proof_valid()) {
883 // Update canonical version to point at the "most recent" entry.
884 canonical_server_map_
[suffix_server_id
] = server_id
;
886 server_state
->InitializeFrom(*canonical_state
);