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/stl_util.h"
10 #include "base/strings/string_util.h"
11 #include "net/quic/crypto/cert_compressor.h"
12 #include "net/quic/crypto/chacha20_poly1305_encrypter.h"
13 #include "net/quic/crypto/channel_id.h"
14 #include "net/quic/crypto/common_cert_set.h"
15 #include "net/quic/crypto/crypto_framer.h"
16 #include "net/quic/crypto/crypto_utils.h"
17 #include "net/quic/crypto/curve25519_key_exchange.h"
18 #include "net/quic/crypto/key_exchange.h"
19 #include "net/quic/crypto/p256_key_exchange.h"
20 #include "net/quic/crypto/proof_verifier.h"
21 #include "net/quic/crypto/quic_encrypter.h"
22 #include "net/quic/quic_utils.h"
24 using base::StringPiece
;
33 // Tracks the reason (the state of the server config) for sending inchoate
34 // ClientHello to the server.
35 void RecordInchoateClientHelloReason(
36 QuicCryptoClientConfig::CachedState::ServerConfigState state
) {
37 UMA_HISTOGRAM_ENUMERATION(
38 "Net.QuicInchoateClientHelloReason", state
,
39 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT
);
42 // Tracks the state of the QUIC server information loaded from the disk cache.
43 void RecordDiskCacheServerConfigState(
44 QuicCryptoClientConfig::CachedState::ServerConfigState state
) {
45 UMA_HISTOGRAM_ENUMERATION(
46 "Net.QuicServerInfo.DiskCacheState", state
,
47 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT
);
52 QuicCryptoClientConfig::QuicCryptoClientConfig()
53 : disable_ecdsa_(false) {
57 QuicCryptoClientConfig::~QuicCryptoClientConfig() {
58 STLDeleteValues(&cached_states_
);
61 QuicCryptoClientConfig::CachedState::CachedState()
62 : server_config_valid_(false),
63 generation_counter_(0) {}
65 QuicCryptoClientConfig::CachedState::~CachedState() {}
67 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now
) const {
68 if (server_config_
.empty()) {
69 RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY
);
73 if (!server_config_valid_
) {
74 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID
);
78 const CryptoHandshakeMessage
* scfg
= GetServerConfig();
80 // Should be impossible short of cache corruption.
82 RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED
);
86 uint64 expiry_seconds
;
87 if (scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
88 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY
);
91 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
92 UMA_HISTOGRAM_CUSTOM_TIMES(
93 "Net.QuicClientHelloServerConfig.InvalidDuration",
94 base::TimeDelta::FromSeconds(now
.ToUNIXSeconds() - expiry_seconds
),
95 base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
96 RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED
);
103 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
104 return server_config_
.empty();
107 const CryptoHandshakeMessage
*
108 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
109 if (server_config_
.empty()) {
114 scfg_
.reset(CryptoFramer::ParseMessage(server_config_
));
120 QuicCryptoClientConfig::CachedState::ServerConfigState
121 QuicCryptoClientConfig::CachedState::SetServerConfig(
122 StringPiece server_config
, QuicWallTime now
, string
* error_details
) {
123 const bool matches_existing
= server_config
== server_config_
;
125 // Even if the new server config matches the existing one, we still wish to
126 // reject it if it has expired.
127 scoped_ptr
<CryptoHandshakeMessage
> new_scfg_storage
;
128 const CryptoHandshakeMessage
* new_scfg
;
130 if (!matches_existing
) {
131 new_scfg_storage
.reset(CryptoFramer::ParseMessage(server_config
));
132 new_scfg
= new_scfg_storage
.get();
134 new_scfg
= GetServerConfig();
138 *error_details
= "SCFG invalid";
139 return SERVER_CONFIG_INVALID
;
142 uint64 expiry_seconds
;
143 if (new_scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
144 *error_details
= "SCFG missing EXPY";
145 return SERVER_CONFIG_INVALID_EXPIRY
;
148 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
149 *error_details
= "SCFG has expired";
150 return SERVER_CONFIG_EXPIRED
;
153 if (!matches_existing
) {
154 server_config_
= server_config
.as_string();
156 scfg_
.reset(new_scfg_storage
.release());
158 return SERVER_CONFIG_VALID
;
161 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
162 server_config_
.clear();
167 void QuicCryptoClientConfig::CachedState::SetProof(const vector
<string
>& certs
,
168 StringPiece signature
) {
170 signature
!= server_config_sig_
|| certs_
.size() != certs
.size();
173 for (size_t i
= 0; i
< certs_
.size(); i
++) {
174 if (certs_
[i
] != certs
[i
]) {
185 // If the proof has changed then it needs to be revalidated.
188 server_config_sig_
= signature
.as_string();
191 void QuicCryptoClientConfig::CachedState::Clear() {
192 server_config_
.clear();
193 source_address_token_
.clear();
195 server_config_sig_
.clear();
196 server_config_valid_
= false;
197 proof_verify_details_
.reset();
199 ++generation_counter_
;
202 void QuicCryptoClientConfig::CachedState::ClearProof() {
205 server_config_sig_
.clear();
208 void QuicCryptoClientConfig::CachedState::SetProofValid() {
209 server_config_valid_
= true;
212 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
213 server_config_valid_
= false;
214 ++generation_counter_
;
217 bool QuicCryptoClientConfig::CachedState::Initialize(
218 StringPiece server_config
,
219 StringPiece source_address_token
,
220 const vector
<string
>& certs
,
221 StringPiece signature
,
223 DCHECK(server_config_
.empty());
225 if (server_config
.empty()) {
226 RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY
);
230 string error_details
;
231 ServerConfigState state
= SetServerConfig(server_config
, now
,
233 RecordDiskCacheServerConfigState(state
);
234 if (state
!= SERVER_CONFIG_VALID
) {
235 DVLOG(1) << "SetServerConfig failed with " << error_details
;
239 signature
.CopyToString(&server_config_sig_
);
240 source_address_token
.CopyToString(&source_address_token_
);
245 const string
& QuicCryptoClientConfig::CachedState::server_config() const {
246 return server_config_
;
250 QuicCryptoClientConfig::CachedState::source_address_token() const {
251 return source_address_token_
;
254 const vector
<string
>& QuicCryptoClientConfig::CachedState::certs() const {
258 const string
& QuicCryptoClientConfig::CachedState::signature() const {
259 return server_config_sig_
;
262 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
263 return server_config_valid_
;
266 uint64
QuicCryptoClientConfig::CachedState::generation_counter() const {
267 return generation_counter_
;
270 const ProofVerifyDetails
*
271 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
272 return proof_verify_details_
.get();
275 void QuicCryptoClientConfig::CachedState::set_source_address_token(
277 source_address_token_
= token
.as_string();
280 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
281 ProofVerifyDetails
* details
) {
282 proof_verify_details_
.reset(details
);
285 void QuicCryptoClientConfig::CachedState::InitializeFrom(
286 const QuicCryptoClientConfig::CachedState
& other
) {
287 DCHECK(server_config_
.empty());
288 DCHECK(!server_config_valid_
);
289 server_config_
= other
.server_config_
;
290 source_address_token_
= other
.source_address_token_
;
291 certs_
= other
.certs_
;
292 server_config_sig_
= other
.server_config_sig_
;
293 server_config_valid_
= other
.server_config_valid_
;
294 if (other
.proof_verify_details_
.get() != nullptr) {
295 proof_verify_details_
.reset(other
.proof_verify_details_
->Clone());
297 ++generation_counter_
;
300 void QuicCryptoClientConfig::SetDefaults() {
301 // Key exchange methods.
306 // Authenticated encryption algorithms. Prefer ChaCha20 by default.
308 if (ChaCha20Poly1305Encrypter::IsSupported()) {
309 aead
.push_back(kCC12
);
311 aead
.push_back(kAESG
);
313 disable_ecdsa_
= false;
316 QuicCryptoClientConfig::CachedState
* QuicCryptoClientConfig::LookupOrCreate(
317 const QuicServerId
& server_id
) {
318 CachedStateMap::const_iterator it
= cached_states_
.find(server_id
);
319 if (it
!= cached_states_
.end()) {
323 CachedState
* cached
= new CachedState
;
324 cached_states_
.insert(std::make_pair(server_id
, cached
));
325 bool cache_populated
= PopulateFromCanonicalConfig(server_id
, cached
);
326 UMA_HISTOGRAM_BOOLEAN(
327 "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig",
332 void QuicCryptoClientConfig::ClearCachedStates() {
333 for (CachedStateMap::const_iterator it
= cached_states_
.begin();
334 it
!= cached_states_
.end(); ++it
) {
339 void QuicCryptoClientConfig::FillInchoateClientHello(
340 const QuicServerId
& server_id
,
341 const QuicVersion preferred_version
,
342 const CachedState
* cached
,
343 QuicCryptoNegotiatedParameters
* out_params
,
344 CryptoHandshakeMessage
* out
) const {
346 out
->set_minimum_size(kClientHelloMinimumSize
);
348 // Server name indication. We only send SNI if it's a valid domain name, as
350 if (CryptoUtils::IsValidSNI(server_id
.host())) {
351 out
->SetStringPiece(kSNI
, server_id
.host());
353 out
->SetValue(kVER
, QuicVersionToQuicTag(preferred_version
));
355 if (!user_agent_id_
.empty()) {
356 out
->SetStringPiece(kUAID
, user_agent_id_
);
359 if (!cached
->source_address_token().empty()) {
360 out
->SetStringPiece(kSourceAddressTokenTag
, cached
->source_address_token());
363 if (server_id
.is_https()) {
364 if (disable_ecdsa_
) {
365 out
->SetTaglist(kPDMD
, kX59R
, 0);
367 out
->SetTaglist(kPDMD
, kX509
, 0);
371 if (common_cert_sets
) {
372 out
->SetStringPiece(kCCS
, common_cert_sets
->GetCommonHashes());
375 const vector
<string
>& certs
= cached
->certs();
376 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
377 // client config is being used for multiple connections, another connection
378 // doesn't update the cached certificates and cause us to be unable to
379 // process the server's compressed certificate chain.
380 out_params
->cached_certs
= certs
;
381 if (!certs
.empty()) {
382 vector
<uint64
> hashes
;
383 hashes
.reserve(certs
.size());
384 for (vector
<string
>::const_iterator i
= certs
.begin();
385 i
!= certs
.end(); ++i
) {
386 hashes
.push_back(QuicUtils::FNV1a_64_Hash(i
->data(), i
->size()));
388 out
->SetVector(kCCRT
, hashes
);
392 QuicErrorCode
QuicCryptoClientConfig::FillClientHello(
393 const QuicServerId
& server_id
,
394 QuicConnectionId connection_id
,
395 const QuicVersion preferred_version
,
396 const CachedState
* cached
,
399 const ChannelIDKey
* channel_id_key
,
400 QuicCryptoNegotiatedParameters
* out_params
,
401 CryptoHandshakeMessage
* out
,
402 string
* error_details
) const {
403 DCHECK(error_details
!= nullptr);
405 FillInchoateClientHello(server_id
, preferred_version
, cached
,
408 const CryptoHandshakeMessage
* scfg
= cached
->GetServerConfig();
410 // This should never happen as our caller should have checked
411 // cached->IsComplete() before calling this function.
412 *error_details
= "Handshake not ready";
413 return QUIC_CRYPTO_INTERNAL_ERROR
;
417 if (!scfg
->GetStringPiece(kSCID
, &scid
)) {
418 *error_details
= "SCFG missing SCID";
419 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
421 out
->SetStringPiece(kSCID
, scid
);
423 const QuicTag
* their_aeads
;
424 const QuicTag
* their_key_exchanges
;
425 size_t num_their_aeads
, num_their_key_exchanges
;
426 if (scfg
->GetTaglist(kAEAD
, &their_aeads
,
427 &num_their_aeads
) != QUIC_NO_ERROR
||
428 scfg
->GetTaglist(kKEXS
, &their_key_exchanges
,
429 &num_their_key_exchanges
) != QUIC_NO_ERROR
) {
430 *error_details
= "Missing AEAD or KEXS";
431 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
434 // AEAD: the work loads on the client and server are symmetric. Since the
435 // client is more likely to be CPU-constrained, break the tie by favoring
436 // the client's preference.
437 // Key exchange: the client does more work than the server, so favor the
438 // client's preference.
439 size_t key_exchange_index
;
440 if (!QuicUtils::FindMutualTag(
441 aead
, their_aeads
, num_their_aeads
, QuicUtils::LOCAL_PRIORITY
,
442 &out_params
->aead
, nullptr) ||
443 !QuicUtils::FindMutualTag(
444 kexs
, their_key_exchanges
, num_their_key_exchanges
,
445 QuicUtils::LOCAL_PRIORITY
, &out_params
->key_exchange
,
446 &key_exchange_index
)) {
447 *error_details
= "Unsupported AEAD or KEXS";
448 return QUIC_CRYPTO_NO_SUPPORT
;
450 out
->SetTaglist(kAEAD
, out_params
->aead
, 0);
451 out
->SetTaglist(kKEXS
, out_params
->key_exchange
, 0);
453 StringPiece public_value
;
454 if (scfg
->GetNthValue24(kPUBS
, key_exchange_index
, &public_value
) !=
456 *error_details
= "Missing public value";
457 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
461 if (!scfg
->GetStringPiece(kORBT
, &orbit
) || orbit
.size() != kOrbitSize
) {
462 *error_details
= "SCFG missing OBIT";
463 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
466 CryptoUtils::GenerateNonce(now
, rand
, orbit
, &out_params
->client_nonce
);
467 out
->SetStringPiece(kNONC
, out_params
->client_nonce
);
468 if (!out_params
->server_nonce
.empty()) {
469 out
->SetStringPiece(kServerNonceTag
, out_params
->server_nonce
);
472 switch (out_params
->key_exchange
) {
474 out_params
->client_key_exchange
.reset(Curve25519KeyExchange::New(
475 Curve25519KeyExchange::NewPrivateKey(rand
)));
478 out_params
->client_key_exchange
.reset(P256KeyExchange::New(
479 P256KeyExchange::NewPrivateKey()));
483 *error_details
= "Configured to support an unknown key exchange";
484 return QUIC_CRYPTO_INTERNAL_ERROR
;
487 if (!out_params
->client_key_exchange
->CalculateSharedKey(
488 public_value
, &out_params
->initial_premaster_secret
)) {
489 *error_details
= "Key exchange failure";
490 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
492 out
->SetStringPiece(kPUBS
, out_params
->client_key_exchange
->public_value());
494 if (channel_id_key
) {
495 // In order to calculate the encryption key for the CETV block we need to
496 // serialise the client hello as it currently is (i.e. without the CETV
497 // block). For this, the client hello is serialized without padding.
498 const size_t orig_min_size
= out
->minimum_size();
499 out
->set_minimum_size(0);
501 CryptoHandshakeMessage cetv
;
505 const QuicData
& client_hello_serialized
= out
->GetSerialized();
506 hkdf_input
.append(QuicCryptoConfig::kCETVLabel
,
507 strlen(QuicCryptoConfig::kCETVLabel
) + 1);
508 hkdf_input
.append(reinterpret_cast<char*>(&connection_id
),
509 sizeof(connection_id
));
510 hkdf_input
.append(client_hello_serialized
.data(),
511 client_hello_serialized
.length());
512 hkdf_input
.append(cached
->server_config());
514 string key
= channel_id_key
->SerializeKey();
516 if (!channel_id_key
->Sign(hkdf_input
, &signature
)) {
517 *error_details
= "Channel ID signature failed";
518 return QUIC_INVALID_CHANNEL_ID_SIGNATURE
;
521 cetv
.SetStringPiece(kCIDK
, key
);
522 cetv
.SetStringPiece(kCIDS
, signature
);
524 CrypterPair crypters
;
525 if (!CryptoUtils::DeriveKeys(
526 out_params
->initial_premaster_secret
, out_params
->aead
,
527 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
528 Perspective::IS_CLIENT
, &crypters
, nullptr /* subkey secret */)) {
529 *error_details
= "Symmetric key setup failed";
530 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
533 const QuicData
& cetv_plaintext
= cetv
.GetSerialized();
534 const size_t encrypted_len
=
535 crypters
.encrypter
->GetCiphertextSize(cetv_plaintext
.length());
536 scoped_ptr
<char[]> output(new char[encrypted_len
]);
537 size_t output_size
= 0;
538 if (!crypters
.encrypter
->EncryptPacket(
539 0 /* sequence number */, StringPiece() /* associated data */,
540 cetv_plaintext
.AsStringPiece(), output
.get(), &output_size
,
542 *error_details
= "Packet encryption failed";
543 return QUIC_ENCRYPTION_FAILURE
;
546 out
->SetStringPiece(kCETV
, StringPiece(output
.get(), output_size
));
549 out
->set_minimum_size(orig_min_size
);
552 // Derive the symmetric keys and set up the encrypters and decrypters.
553 // Set the following members of out_params:
554 // out_params->hkdf_input_suffix
555 // out_params->initial_crypters
556 out_params
->hkdf_input_suffix
.clear();
557 out_params
->hkdf_input_suffix
.append(reinterpret_cast<char*>(&connection_id
),
558 sizeof(connection_id
));
559 const QuicData
& client_hello_serialized
= out
->GetSerialized();
560 out_params
->hkdf_input_suffix
.append(client_hello_serialized
.data(),
561 client_hello_serialized
.length());
562 out_params
->hkdf_input_suffix
.append(cached
->server_config());
565 const size_t label_len
= strlen(QuicCryptoConfig::kInitialLabel
) + 1;
566 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
567 hkdf_input
.append(QuicCryptoConfig::kInitialLabel
, label_len
);
568 hkdf_input
.append(out_params
->hkdf_input_suffix
);
570 if (!CryptoUtils::DeriveKeys(
571 out_params
->initial_premaster_secret
, out_params
->aead
,
572 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
573 Perspective::IS_CLIENT
, &out_params
->initial_crypters
,
574 nullptr /* subkey secret */)) {
575 *error_details
= "Symmetric key setup failed";
576 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
579 return QUIC_NO_ERROR
;
582 QuicErrorCode
QuicCryptoClientConfig::CacheNewServerConfig(
583 const CryptoHandshakeMessage
& message
,
585 const vector
<string
>& cached_certs
,
587 string
* error_details
) {
588 DCHECK(error_details
!= nullptr);
591 if (!message
.GetStringPiece(kSCFG
, &scfg
)) {
592 *error_details
= "Missing SCFG";
593 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
596 CachedState::ServerConfigState state
= cached
->SetServerConfig(
597 scfg
, now
, error_details
);
598 if (state
== CachedState::SERVER_CONFIG_EXPIRED
) {
599 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED
;
601 // TODO(rtenneti): Return more specific error code than returning
602 // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
603 if (state
!= CachedState::SERVER_CONFIG_VALID
) {
604 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
608 if (message
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
609 cached
->set_source_address_token(token
);
612 StringPiece proof
, cert_bytes
;
613 bool has_proof
= message
.GetStringPiece(kPROF
, &proof
);
614 bool has_cert
= message
.GetStringPiece(kCertificateTag
, &cert_bytes
);
615 if (has_proof
&& has_cert
) {
616 vector
<string
> certs
;
617 if (!CertCompressor::DecompressChain(cert_bytes
, cached_certs
,
618 common_cert_sets
, &certs
)) {
619 *error_details
= "Certificate data invalid";
620 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
623 cached
->SetProof(certs
, proof
);
625 if (proof_verifier() != nullptr) {
626 // Secure QUIC: clear existing proof as we have been sent a new SCFG
627 // without matching proof/certs.
628 cached
->ClearProof();
631 if (has_proof
&& !has_cert
) {
632 *error_details
= "Certificate missing";
633 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
636 if (!has_proof
&& has_cert
) {
637 *error_details
= "Proof missing";
638 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
642 return QUIC_NO_ERROR
;
645 QuicErrorCode
QuicCryptoClientConfig::ProcessRejection(
646 const CryptoHandshakeMessage
& rej
,
650 QuicCryptoNegotiatedParameters
* out_params
,
651 string
* error_details
) {
652 DCHECK(error_details
!= nullptr);
654 if (rej
.tag() != kREJ
) {
655 *error_details
= "Message is not REJ";
656 return QUIC_CRYPTO_INTERNAL_ERROR
;
659 QuicErrorCode error
= CacheNewServerConfig(rej
, now
, out_params
->cached_certs
,
660 cached
, error_details
);
661 if (error
!= QUIC_NO_ERROR
) {
666 if (rej
.GetStringPiece(kServerNonceTag
, &nonce
)) {
667 out_params
->server_nonce
= nonce
.as_string();
670 const uint32
* reject_reasons
;
671 size_t num_reject_reasons
;
672 static_assert(sizeof(QuicTag
) == sizeof(uint32
), "header out of sync");
673 if (rej
.GetTaglist(kRREJ
, &reject_reasons
,
674 &num_reject_reasons
) == QUIC_NO_ERROR
) {
675 uint32 packed_error
= 0;
676 for (size_t i
= 0; i
< num_reject_reasons
; ++i
) {
677 // HANDSHAKE_OK is 0 and don't report that as error.
678 if (reject_reasons
[i
] == HANDSHAKE_OK
|| reject_reasons
[i
] >= 32) {
681 HandshakeFailureReason reason
=
682 static_cast<HandshakeFailureReason
>(reject_reasons
[i
]);
683 packed_error
|= 1 << (reason
- 1);
685 DVLOG(1) << "Reasons for rejection: " << packed_error
;
687 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
690 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Insecure",
695 return QUIC_NO_ERROR
;
698 QuicErrorCode
QuicCryptoClientConfig::ProcessServerHello(
699 const CryptoHandshakeMessage
& server_hello
,
700 QuicConnectionId connection_id
,
701 const QuicVersionVector
& negotiated_versions
,
703 QuicCryptoNegotiatedParameters
* out_params
,
704 string
* error_details
) {
705 DCHECK(error_details
!= nullptr);
707 if (server_hello
.tag() != kSHLO
) {
708 *error_details
= "Bad tag";
709 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
712 const QuicTag
* supported_version_tags
;
713 size_t num_supported_versions
;
715 if (server_hello
.GetTaglist(kVER
, &supported_version_tags
,
716 &num_supported_versions
) != QUIC_NO_ERROR
) {
717 *error_details
= "server hello missing version list";
718 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
720 if (!negotiated_versions
.empty()) {
721 bool mismatch
= num_supported_versions
!= negotiated_versions
.size();
722 for (size_t i
= 0; i
< num_supported_versions
&& !mismatch
; ++i
) {
723 mismatch
= QuicTagToQuicVersion(supported_version_tags
[i
]) !=
724 negotiated_versions
[i
];
726 // The server sent a list of supported versions, and the connection
727 // reports that there was a version negotiation during the handshake.
728 // Ensure that these two lists are identical.
730 *error_details
= "Downgrade attack detected";
731 return QUIC_VERSION_NEGOTIATION_MISMATCH
;
735 // Learn about updated source address tokens.
737 if (server_hello
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
738 cached
->set_source_address_token(token
);
742 // learn about updated SCFGs.
744 StringPiece public_value
;
745 if (!server_hello
.GetStringPiece(kPUBS
, &public_value
)) {
746 *error_details
= "server hello missing forward secure public value";
747 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
750 if (!out_params
->client_key_exchange
->CalculateSharedKey(
751 public_value
, &out_params
->forward_secure_premaster_secret
)) {
752 *error_details
= "Key exchange failure";
753 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
757 const size_t label_len
= strlen(QuicCryptoConfig::kForwardSecureLabel
) + 1;
758 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
759 hkdf_input
.append(QuicCryptoConfig::kForwardSecureLabel
, label_len
);
760 hkdf_input
.append(out_params
->hkdf_input_suffix
);
762 if (!CryptoUtils::DeriveKeys(
763 out_params
->forward_secure_premaster_secret
, out_params
->aead
,
764 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
765 Perspective::IS_CLIENT
, &out_params
->forward_secure_crypters
,
766 &out_params
->subkey_secret
)) {
767 *error_details
= "Symmetric key setup failed";
768 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
771 return QUIC_NO_ERROR
;
774 QuicErrorCode
QuicCryptoClientConfig::ProcessServerConfigUpdate(
775 const CryptoHandshakeMessage
& server_config_update
,
778 QuicCryptoNegotiatedParameters
* out_params
,
779 string
* error_details
) {
780 DCHECK(error_details
!= nullptr);
782 if (server_config_update
.tag() != kSCUP
) {
783 *error_details
= "ServerConfigUpdate must have kSCUP tag.";
784 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
787 return CacheNewServerConfig(server_config_update
, now
,
788 out_params
->cached_certs
, cached
, error_details
);
791 ProofVerifier
* QuicCryptoClientConfig::proof_verifier() const {
792 return proof_verifier_
.get();
795 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier
* verifier
) {
796 proof_verifier_
.reset(verifier
);
799 ChannelIDSource
* QuicCryptoClientConfig::channel_id_source() const {
800 return channel_id_source_
.get();
803 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource
* source
) {
804 channel_id_source_
.reset(source
);
807 void QuicCryptoClientConfig::InitializeFrom(
808 const QuicServerId
& server_id
,
809 const QuicServerId
& canonical_server_id
,
810 QuicCryptoClientConfig
* canonical_crypto_config
) {
811 CachedState
* canonical_cached
=
812 canonical_crypto_config
->LookupOrCreate(canonical_server_id
);
813 if (!canonical_cached
->proof_valid()) {
816 CachedState
* cached
= LookupOrCreate(server_id
);
817 cached
->InitializeFrom(*canonical_cached
);
820 void QuicCryptoClientConfig::AddCanonicalSuffix(const string
& suffix
) {
821 canonical_suffixes_
.push_back(suffix
);
824 void QuicCryptoClientConfig::PreferAesGcm() {
825 DCHECK(!aead
.empty());
826 if (aead
.size() <= 1) {
829 QuicTagVector::iterator pos
= std::find(aead
.begin(), aead
.end(), kAESG
);
830 if (pos
!= aead
.end()) {
832 aead
.insert(aead
.begin(), kAESG
);
836 void QuicCryptoClientConfig::DisableEcdsa() {
837 disable_ecdsa_
= true;
840 bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
841 const QuicServerId
& server_id
,
842 CachedState
* server_state
) {
843 DCHECK(server_state
->IsEmpty());
845 for (; i
< canonical_suffixes_
.size(); ++i
) {
846 if (EndsWith(server_id
.host(), canonical_suffixes_
[i
], false)) {
850 if (i
== canonical_suffixes_
.size()) {
854 QuicServerId
suffix_server_id(canonical_suffixes_
[i
], server_id
.port(),
855 server_id
.is_https(),
856 server_id
.privacy_mode());
857 if (!ContainsKey(canonical_server_map_
, suffix_server_id
)) {
858 // This is the first host we've seen which matches the suffix, so make it
860 canonical_server_map_
[suffix_server_id
] = server_id
;
864 const QuicServerId
& canonical_server_id
=
865 canonical_server_map_
[suffix_server_id
];
866 CachedState
* canonical_state
= cached_states_
[canonical_server_id
];
867 if (!canonical_state
->proof_valid()) {
871 // Update canonical version to point at the "most recent" entry.
872 canonical_server_map_
[suffix_server_id
] = server_id
;
874 server_state
->InitializeFrom(*canonical_state
);