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_macros.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
;
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 void QuicCryptoClientConfig::CachedState::add_server_designated_connection_id(
122 QuicConnectionId connection_id
) {
123 server_designated_connection_ids_
.push(connection_id
);
126 bool QuicCryptoClientConfig::CachedState::has_server_designated_connection_id()
128 return !server_designated_connection_ids_
.empty();
131 void QuicCryptoClientConfig::CachedState::add_server_nonce(
132 const string
& server_nonce
) {
133 server_nonces_
.push(server_nonce
);
136 bool QuicCryptoClientConfig::CachedState::has_server_nonce() const {
137 return !server_nonces_
.empty();
140 QuicCryptoClientConfig::CachedState::ServerConfigState
141 QuicCryptoClientConfig::CachedState::SetServerConfig(
142 StringPiece server_config
, QuicWallTime now
, string
* error_details
) {
143 const bool matches_existing
= server_config
== server_config_
;
145 // Even if the new server config matches the existing one, we still wish to
146 // reject it if it has expired.
147 scoped_ptr
<CryptoHandshakeMessage
> new_scfg_storage
;
148 const CryptoHandshakeMessage
* new_scfg
;
150 if (!matches_existing
) {
151 new_scfg_storage
.reset(CryptoFramer::ParseMessage(server_config
));
152 new_scfg
= new_scfg_storage
.get();
154 new_scfg
= GetServerConfig();
158 *error_details
= "SCFG invalid";
159 return SERVER_CONFIG_INVALID
;
162 uint64 expiry_seconds
;
163 if (new_scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
164 *error_details
= "SCFG missing EXPY";
165 return SERVER_CONFIG_INVALID_EXPIRY
;
168 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
169 *error_details
= "SCFG has expired";
170 return SERVER_CONFIG_EXPIRED
;
173 if (!matches_existing
) {
174 server_config_
= server_config
.as_string();
176 scfg_
.reset(new_scfg_storage
.release());
178 return SERVER_CONFIG_VALID
;
181 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
182 server_config_
.clear();
185 queue
<QuicConnectionId
> empty_queue
;
186 swap(server_designated_connection_ids_
, empty_queue
);
189 void QuicCryptoClientConfig::CachedState::SetProof(const vector
<string
>& certs
,
190 StringPiece signature
) {
192 signature
!= server_config_sig_
|| certs_
.size() != certs
.size();
195 for (size_t i
= 0; i
< certs_
.size(); i
++) {
196 if (certs_
[i
] != certs
[i
]) {
207 // If the proof has changed then it needs to be revalidated.
210 server_config_sig_
= signature
.as_string();
213 void QuicCryptoClientConfig::CachedState::Clear() {
214 server_config_
.clear();
215 source_address_token_
.clear();
217 server_config_sig_
.clear();
218 server_config_valid_
= false;
219 proof_verify_details_
.reset();
221 ++generation_counter_
;
222 queue
<QuicConnectionId
> empty_queue
;
223 swap(server_designated_connection_ids_
, empty_queue
);
226 void QuicCryptoClientConfig::CachedState::ClearProof() {
229 server_config_sig_
.clear();
232 void QuicCryptoClientConfig::CachedState::SetProofValid() {
233 server_config_valid_
= true;
236 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
237 server_config_valid_
= false;
238 ++generation_counter_
;
241 bool QuicCryptoClientConfig::CachedState::Initialize(
242 StringPiece server_config
,
243 StringPiece source_address_token
,
244 const vector
<string
>& certs
,
245 StringPiece signature
,
247 DCHECK(server_config_
.empty());
249 if (server_config
.empty()) {
250 RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY
);
254 string error_details
;
255 ServerConfigState state
= SetServerConfig(server_config
, now
,
257 RecordDiskCacheServerConfigState(state
);
258 if (state
!= SERVER_CONFIG_VALID
) {
259 DVLOG(1) << "SetServerConfig failed with " << error_details
;
263 signature
.CopyToString(&server_config_sig_
);
264 source_address_token
.CopyToString(&source_address_token_
);
269 const string
& QuicCryptoClientConfig::CachedState::server_config() const {
270 return server_config_
;
274 QuicCryptoClientConfig::CachedState::source_address_token() const {
275 return source_address_token_
;
278 const vector
<string
>& QuicCryptoClientConfig::CachedState::certs() const {
282 const string
& QuicCryptoClientConfig::CachedState::signature() const {
283 return server_config_sig_
;
286 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
287 return server_config_valid_
;
290 uint64
QuicCryptoClientConfig::CachedState::generation_counter() const {
291 return generation_counter_
;
294 const ProofVerifyDetails
*
295 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
296 return proof_verify_details_
.get();
299 void QuicCryptoClientConfig::CachedState::set_source_address_token(
301 source_address_token_
= token
.as_string();
304 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
305 ProofVerifyDetails
* details
) {
306 proof_verify_details_
.reset(details
);
309 void QuicCryptoClientConfig::CachedState::InitializeFrom(
310 const QuicCryptoClientConfig::CachedState
& other
) {
311 DCHECK(server_config_
.empty());
312 DCHECK(!server_config_valid_
);
313 server_config_
= other
.server_config_
;
314 source_address_token_
= other
.source_address_token_
;
315 certs_
= other
.certs_
;
316 server_config_sig_
= other
.server_config_sig_
;
317 server_config_valid_
= other
.server_config_valid_
;
318 server_designated_connection_ids_
= other
.server_designated_connection_ids_
;
319 if (other
.proof_verify_details_
.get() != nullptr) {
320 proof_verify_details_
.reset(other
.proof_verify_details_
->Clone());
322 ++generation_counter_
;
326 QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() {
327 if (server_designated_connection_ids_
.empty()) {
329 << "Attempting to consume a connection id that was never designated.";
332 const QuicConnectionId next_id
= server_designated_connection_ids_
.front();
333 server_designated_connection_ids_
.pop();
337 string
QuicCryptoClientConfig::CachedState::GetNextServerNonce() {
338 if (server_nonces_
.empty()) {
340 << "Attempting to consume a server nonce that was never designated.";
343 const string server_nonce
= server_nonces_
.front();
344 server_nonces_
.pop();
348 void QuicCryptoClientConfig::SetDefaults() {
349 // Key exchange methods.
354 // Authenticated encryption algorithms. Prefer ChaCha20 by default.
356 if (ChaCha20Poly1305Encrypter::IsSupported()) {
357 aead
.push_back(kCC12
);
359 aead
.push_back(kAESG
);
361 disable_ecdsa_
= false;
364 QuicCryptoClientConfig::CachedState
* QuicCryptoClientConfig::LookupOrCreate(
365 const QuicServerId
& server_id
) {
366 CachedStateMap::const_iterator it
= cached_states_
.find(server_id
);
367 if (it
!= cached_states_
.end()) {
371 CachedState
* cached
= new CachedState
;
372 cached_states_
.insert(std::make_pair(server_id
, cached
));
373 bool cache_populated
= PopulateFromCanonicalConfig(server_id
, cached
);
374 UMA_HISTOGRAM_BOOLEAN(
375 "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig",
380 void QuicCryptoClientConfig::ClearCachedStates() {
381 for (CachedStateMap::const_iterator it
= cached_states_
.begin();
382 it
!= cached_states_
.end(); ++it
) {
387 void QuicCryptoClientConfig::FillInchoateClientHello(
388 const QuicServerId
& server_id
,
389 const QuicVersion preferred_version
,
390 const CachedState
* cached
,
391 QuicCryptoNegotiatedParameters
* out_params
,
392 CryptoHandshakeMessage
* out
) const {
394 out
->set_minimum_size(kClientHelloMinimumSize
);
396 // Server name indication. We only send SNI if it's a valid domain name, as
398 if (CryptoUtils::IsValidSNI(server_id
.host())) {
399 out
->SetStringPiece(kSNI
, server_id
.host());
401 out
->SetValue(kVER
, QuicVersionToQuicTag(preferred_version
));
403 if (!user_agent_id_
.empty()) {
404 out
->SetStringPiece(kUAID
, user_agent_id_
);
407 if (!cached
->source_address_token().empty()) {
408 out
->SetStringPiece(kSourceAddressTokenTag
, cached
->source_address_token());
411 if (server_id
.is_https()) {
412 if (disable_ecdsa_
) {
413 out
->SetTaglist(kPDMD
, kX59R
, 0);
415 out
->SetTaglist(kPDMD
, kX509
, 0);
419 if (common_cert_sets
) {
420 out
->SetStringPiece(kCCS
, common_cert_sets
->GetCommonHashes());
423 const vector
<string
>& certs
= cached
->certs();
424 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
425 // client config is being used for multiple connections, another connection
426 // doesn't update the cached certificates and cause us to be unable to
427 // process the server's compressed certificate chain.
428 out_params
->cached_certs
= certs
;
429 if (!certs
.empty()) {
430 vector
<uint64
> hashes
;
431 hashes
.reserve(certs
.size());
432 for (vector
<string
>::const_iterator i
= certs
.begin();
433 i
!= certs
.end(); ++i
) {
434 hashes
.push_back(QuicUtils::FNV1a_64_Hash(i
->data(), i
->size()));
436 out
->SetVector(kCCRT
, hashes
);
440 QuicErrorCode
QuicCryptoClientConfig::FillClientHello(
441 const QuicServerId
& server_id
,
442 QuicConnectionId connection_id
,
443 const QuicVersion preferred_version
,
444 const CachedState
* cached
,
447 const ChannelIDKey
* channel_id_key
,
448 QuicCryptoNegotiatedParameters
* out_params
,
449 CryptoHandshakeMessage
* out
,
450 string
* error_details
) const {
451 DCHECK(error_details
!= nullptr);
453 FillInchoateClientHello(server_id
, preferred_version
, cached
,
456 const CryptoHandshakeMessage
* scfg
= cached
->GetServerConfig();
458 // This should never happen as our caller should have checked
459 // cached->IsComplete() before calling this function.
460 *error_details
= "Handshake not ready";
461 return QUIC_CRYPTO_INTERNAL_ERROR
;
465 if (!scfg
->GetStringPiece(kSCID
, &scid
)) {
466 *error_details
= "SCFG missing SCID";
467 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
469 out
->SetStringPiece(kSCID
, scid
);
471 const QuicTag
* their_aeads
;
472 const QuicTag
* their_key_exchanges
;
473 size_t num_their_aeads
, num_their_key_exchanges
;
474 if (scfg
->GetTaglist(kAEAD
, &their_aeads
,
475 &num_their_aeads
) != QUIC_NO_ERROR
||
476 scfg
->GetTaglist(kKEXS
, &their_key_exchanges
,
477 &num_their_key_exchanges
) != QUIC_NO_ERROR
) {
478 *error_details
= "Missing AEAD or KEXS";
479 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
482 // AEAD: the work loads on the client and server are symmetric. Since the
483 // client is more likely to be CPU-constrained, break the tie by favoring
484 // the client's preference.
485 // Key exchange: the client does more work than the server, so favor the
486 // client's preference.
487 size_t key_exchange_index
;
488 if (!QuicUtils::FindMutualTag(
489 aead
, their_aeads
, num_their_aeads
, QuicUtils::LOCAL_PRIORITY
,
490 &out_params
->aead
, nullptr) ||
491 !QuicUtils::FindMutualTag(
492 kexs
, their_key_exchanges
, num_their_key_exchanges
,
493 QuicUtils::LOCAL_PRIORITY
, &out_params
->key_exchange
,
494 &key_exchange_index
)) {
495 *error_details
= "Unsupported AEAD or KEXS";
496 return QUIC_CRYPTO_NO_SUPPORT
;
498 out
->SetTaglist(kAEAD
, out_params
->aead
, 0);
499 out
->SetTaglist(kKEXS
, out_params
->key_exchange
, 0);
501 StringPiece public_value
;
502 if (scfg
->GetNthValue24(kPUBS
, key_exchange_index
, &public_value
) !=
504 *error_details
= "Missing public value";
505 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
509 if (!scfg
->GetStringPiece(kORBT
, &orbit
) || orbit
.size() != kOrbitSize
) {
510 *error_details
= "SCFG missing OBIT";
511 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
514 CryptoUtils::GenerateNonce(now
, rand
, orbit
, &out_params
->client_nonce
);
515 out
->SetStringPiece(kNONC
, out_params
->client_nonce
);
516 if (!out_params
->server_nonce
.empty()) {
517 out
->SetStringPiece(kServerNonceTag
, out_params
->server_nonce
);
520 switch (out_params
->key_exchange
) {
522 out_params
->client_key_exchange
.reset(Curve25519KeyExchange::New(
523 Curve25519KeyExchange::NewPrivateKey(rand
)));
526 out_params
->client_key_exchange
.reset(P256KeyExchange::New(
527 P256KeyExchange::NewPrivateKey()));
531 *error_details
= "Configured to support an unknown key exchange";
532 return QUIC_CRYPTO_INTERNAL_ERROR
;
535 if (!out_params
->client_key_exchange
->CalculateSharedKey(
536 public_value
, &out_params
->initial_premaster_secret
)) {
537 *error_details
= "Key exchange failure";
538 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
540 out
->SetStringPiece(kPUBS
, out_params
->client_key_exchange
->public_value());
542 if (channel_id_key
) {
543 // In order to calculate the encryption key for the CETV block we need to
544 // serialise the client hello as it currently is (i.e. without the CETV
545 // block). For this, the client hello is serialized without padding.
546 const size_t orig_min_size
= out
->minimum_size();
547 out
->set_minimum_size(0);
549 CryptoHandshakeMessage cetv
;
553 const QuicData
& client_hello_serialized
= out
->GetSerialized();
554 hkdf_input
.append(QuicCryptoConfig::kCETVLabel
,
555 strlen(QuicCryptoConfig::kCETVLabel
) + 1);
556 hkdf_input
.append(reinterpret_cast<char*>(&connection_id
),
557 sizeof(connection_id
));
558 hkdf_input
.append(client_hello_serialized
.data(),
559 client_hello_serialized
.length());
560 hkdf_input
.append(cached
->server_config());
562 string key
= channel_id_key
->SerializeKey();
564 if (!channel_id_key
->Sign(hkdf_input
, &signature
)) {
565 *error_details
= "Channel ID signature failed";
566 return QUIC_INVALID_CHANNEL_ID_SIGNATURE
;
569 cetv
.SetStringPiece(kCIDK
, key
);
570 cetv
.SetStringPiece(kCIDS
, signature
);
572 CrypterPair crypters
;
573 if (!CryptoUtils::DeriveKeys(
574 out_params
->initial_premaster_secret
, out_params
->aead
,
575 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
576 Perspective::IS_CLIENT
, &crypters
, nullptr /* subkey secret */)) {
577 *error_details
= "Symmetric key setup failed";
578 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
581 const QuicData
& cetv_plaintext
= cetv
.GetSerialized();
582 const size_t encrypted_len
=
583 crypters
.encrypter
->GetCiphertextSize(cetv_plaintext
.length());
584 scoped_ptr
<char[]> output(new char[encrypted_len
]);
585 size_t output_size
= 0;
586 if (!crypters
.encrypter
->EncryptPacket(
587 0 /* packet number */, StringPiece() /* associated data */,
588 cetv_plaintext
.AsStringPiece(), output
.get(), &output_size
,
590 *error_details
= "Packet encryption failed";
591 return QUIC_ENCRYPTION_FAILURE
;
594 out
->SetStringPiece(kCETV
, StringPiece(output
.get(), output_size
));
597 out
->set_minimum_size(orig_min_size
);
600 // Derive the symmetric keys and set up the encrypters and decrypters.
601 // Set the following members of out_params:
602 // out_params->hkdf_input_suffix
603 // out_params->initial_crypters
604 out_params
->hkdf_input_suffix
.clear();
605 out_params
->hkdf_input_suffix
.append(reinterpret_cast<char*>(&connection_id
),
606 sizeof(connection_id
));
607 const QuicData
& client_hello_serialized
= out
->GetSerialized();
608 out_params
->hkdf_input_suffix
.append(client_hello_serialized
.data(),
609 client_hello_serialized
.length());
610 out_params
->hkdf_input_suffix
.append(cached
->server_config());
613 const size_t label_len
= strlen(QuicCryptoConfig::kInitialLabel
) + 1;
614 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
615 hkdf_input
.append(QuicCryptoConfig::kInitialLabel
, label_len
);
616 hkdf_input
.append(out_params
->hkdf_input_suffix
);
618 if (!CryptoUtils::DeriveKeys(
619 out_params
->initial_premaster_secret
, out_params
->aead
,
620 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
621 Perspective::IS_CLIENT
, &out_params
->initial_crypters
,
622 nullptr /* subkey secret */)) {
623 *error_details
= "Symmetric key setup failed";
624 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
627 return QUIC_NO_ERROR
;
630 QuicErrorCode
QuicCryptoClientConfig::CacheNewServerConfig(
631 const CryptoHandshakeMessage
& message
,
633 const vector
<string
>& cached_certs
,
635 string
* error_details
) {
636 DCHECK(error_details
!= nullptr);
639 if (!message
.GetStringPiece(kSCFG
, &scfg
)) {
640 *error_details
= "Missing SCFG";
641 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
644 CachedState::ServerConfigState state
= cached
->SetServerConfig(
645 scfg
, now
, error_details
);
646 if (state
== CachedState::SERVER_CONFIG_EXPIRED
) {
647 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED
;
649 // TODO(rtenneti): Return more specific error code than returning
650 // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
651 if (state
!= CachedState::SERVER_CONFIG_VALID
) {
652 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
656 if (message
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
657 cached
->set_source_address_token(token
);
660 StringPiece proof
, cert_bytes
;
661 bool has_proof
= message
.GetStringPiece(kPROF
, &proof
);
662 bool has_cert
= message
.GetStringPiece(kCertificateTag
, &cert_bytes
);
663 if (has_proof
&& has_cert
) {
664 vector
<string
> certs
;
665 if (!CertCompressor::DecompressChain(cert_bytes
, cached_certs
,
666 common_cert_sets
, &certs
)) {
667 *error_details
= "Certificate data invalid";
668 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
671 cached
->SetProof(certs
, proof
);
673 if (proof_verifier() != nullptr) {
674 // Secure QUIC: clear existing proof as we have been sent a new SCFG
675 // without matching proof/certs.
676 cached
->ClearProof();
679 if (has_proof
&& !has_cert
) {
680 *error_details
= "Certificate missing";
681 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
684 if (!has_proof
&& has_cert
) {
685 *error_details
= "Proof missing";
686 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
690 return QUIC_NO_ERROR
;
693 QuicErrorCode
QuicCryptoClientConfig::ProcessRejection(
694 const CryptoHandshakeMessage
& rej
,
698 QuicCryptoNegotiatedParameters
* out_params
,
699 string
* error_details
) {
700 DCHECK(error_details
!= nullptr);
702 if ((rej
.tag() != kREJ
) && (rej
.tag() != kSREJ
)) {
703 *error_details
= "Message is not REJ or SREJ";
704 return QUIC_CRYPTO_INTERNAL_ERROR
;
707 QuicErrorCode error
= CacheNewServerConfig(rej
, now
, out_params
->cached_certs
,
708 cached
, error_details
);
709 if (error
!= QUIC_NO_ERROR
) {
714 if (rej
.GetStringPiece(kServerNonceTag
, &nonce
)) {
715 out_params
->server_nonce
= nonce
.as_string();
718 const uint32
* reject_reasons
;
719 size_t num_reject_reasons
;
720 static_assert(sizeof(QuicTag
) == sizeof(uint32
), "header out of sync");
721 if (rej
.GetTaglist(kRREJ
, &reject_reasons
,
722 &num_reject_reasons
) == QUIC_NO_ERROR
) {
723 uint32 packed_error
= 0;
724 for (size_t i
= 0; i
< num_reject_reasons
; ++i
) {
725 // HANDSHAKE_OK is 0 and don't report that as error.
726 if (reject_reasons
[i
] == HANDSHAKE_OK
|| reject_reasons
[i
] >= 32) {
729 HandshakeFailureReason reason
=
730 static_cast<HandshakeFailureReason
>(reject_reasons
[i
]);
731 packed_error
|= 1 << (reason
- 1);
733 DVLOG(1) << "Reasons for rejection: " << packed_error
;
735 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
738 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Insecure",
743 if (rej
.tag() == kSREJ
) {
744 QuicConnectionId connection_id
;
745 if (rej
.GetUint64(kRCID
, &connection_id
) != QUIC_NO_ERROR
) {
746 *error_details
= "Missing kRCID";
747 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
749 cached
->add_server_designated_connection_id(connection_id
);
750 if (!nonce
.empty()) {
751 cached
->add_server_nonce(nonce
.as_string());
753 return QUIC_NO_ERROR
;
756 return QUIC_NO_ERROR
;
759 QuicErrorCode
QuicCryptoClientConfig::ProcessServerHello(
760 const CryptoHandshakeMessage
& server_hello
,
761 QuicConnectionId connection_id
,
762 const QuicVersionVector
& negotiated_versions
,
764 QuicCryptoNegotiatedParameters
* out_params
,
765 string
* error_details
) {
766 DCHECK(error_details
!= nullptr);
768 if (server_hello
.tag() != kSHLO
) {
769 *error_details
= "Bad tag";
770 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
773 const QuicTag
* supported_version_tags
;
774 size_t num_supported_versions
;
776 if (server_hello
.GetTaglist(kVER
, &supported_version_tags
,
777 &num_supported_versions
) != QUIC_NO_ERROR
) {
778 *error_details
= "server hello missing version list";
779 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
781 if (!negotiated_versions
.empty()) {
782 bool mismatch
= num_supported_versions
!= negotiated_versions
.size();
783 for (size_t i
= 0; i
< num_supported_versions
&& !mismatch
; ++i
) {
784 mismatch
= QuicTagToQuicVersion(supported_version_tags
[i
]) !=
785 negotiated_versions
[i
];
787 // The server sent a list of supported versions, and the connection
788 // reports that there was a version negotiation during the handshake.
789 // Ensure that these two lists are identical.
791 *error_details
= "Downgrade attack detected";
792 return QUIC_VERSION_NEGOTIATION_MISMATCH
;
796 // Learn about updated source address tokens.
798 if (server_hello
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
799 cached
->set_source_address_token(token
);
803 // learn about updated SCFGs.
805 StringPiece public_value
;
806 if (!server_hello
.GetStringPiece(kPUBS
, &public_value
)) {
807 *error_details
= "server hello missing forward secure public value";
808 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
811 if (!out_params
->client_key_exchange
->CalculateSharedKey(
812 public_value
, &out_params
->forward_secure_premaster_secret
)) {
813 *error_details
= "Key exchange failure";
814 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
818 const size_t label_len
= strlen(QuicCryptoConfig::kForwardSecureLabel
) + 1;
819 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
820 hkdf_input
.append(QuicCryptoConfig::kForwardSecureLabel
, label_len
);
821 hkdf_input
.append(out_params
->hkdf_input_suffix
);
823 if (!CryptoUtils::DeriveKeys(
824 out_params
->forward_secure_premaster_secret
, out_params
->aead
,
825 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
826 Perspective::IS_CLIENT
, &out_params
->forward_secure_crypters
,
827 &out_params
->subkey_secret
)) {
828 *error_details
= "Symmetric key setup failed";
829 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
832 return QUIC_NO_ERROR
;
835 QuicErrorCode
QuicCryptoClientConfig::ProcessServerConfigUpdate(
836 const CryptoHandshakeMessage
& server_config_update
,
839 QuicCryptoNegotiatedParameters
* out_params
,
840 string
* error_details
) {
841 DCHECK(error_details
!= nullptr);
843 if (server_config_update
.tag() != kSCUP
) {
844 *error_details
= "ServerConfigUpdate must have kSCUP tag.";
845 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
848 return CacheNewServerConfig(server_config_update
, now
,
849 out_params
->cached_certs
, cached
, error_details
);
852 ProofVerifier
* QuicCryptoClientConfig::proof_verifier() const {
853 return proof_verifier_
.get();
856 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier
* verifier
) {
857 proof_verifier_
.reset(verifier
);
860 ChannelIDSource
* QuicCryptoClientConfig::channel_id_source() const {
861 return channel_id_source_
.get();
864 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource
* source
) {
865 channel_id_source_
.reset(source
);
868 void QuicCryptoClientConfig::InitializeFrom(
869 const QuicServerId
& server_id
,
870 const QuicServerId
& canonical_server_id
,
871 QuicCryptoClientConfig
* canonical_crypto_config
) {
872 CachedState
* canonical_cached
=
873 canonical_crypto_config
->LookupOrCreate(canonical_server_id
);
874 if (!canonical_cached
->proof_valid()) {
877 CachedState
* cached
= LookupOrCreate(server_id
);
878 cached
->InitializeFrom(*canonical_cached
);
881 void QuicCryptoClientConfig::AddCanonicalSuffix(const string
& suffix
) {
882 canonical_suffixes_
.push_back(suffix
);
885 void QuicCryptoClientConfig::PreferAesGcm() {
886 DCHECK(!aead
.empty());
887 if (aead
.size() <= 1) {
890 QuicTagVector::iterator pos
= std::find(aead
.begin(), aead
.end(), kAESG
);
891 if (pos
!= aead
.end()) {
893 aead
.insert(aead
.begin(), kAESG
);
897 void QuicCryptoClientConfig::DisableEcdsa() {
898 disable_ecdsa_
= true;
901 bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
902 const QuicServerId
& server_id
,
903 CachedState
* server_state
) {
904 DCHECK(server_state
->IsEmpty());
906 for (; i
< canonical_suffixes_
.size(); ++i
) {
907 if (base::EndsWith(server_id
.host(), canonical_suffixes_
[i
],
908 base::CompareCase::INSENSITIVE_ASCII
)) {
912 if (i
== canonical_suffixes_
.size()) {
916 QuicServerId
suffix_server_id(canonical_suffixes_
[i
], server_id
.port(),
917 server_id
.is_https(),
918 server_id
.privacy_mode());
919 if (!ContainsKey(canonical_server_map_
, suffix_server_id
)) {
920 // This is the first host we've seen which matches the suffix, so make it
922 canonical_server_map_
[suffix_server_id
] = server_id
;
926 const QuicServerId
& canonical_server_id
=
927 canonical_server_map_
[suffix_server_id
];
928 CachedState
* canonical_state
= cached_states_
[canonical_server_id
];
929 if (!canonical_state
->proof_valid()) {
933 // Update canonical version to point at the "most recent" entry.
934 canonical_server_map_
[suffix_server_id
] = server_id
;
936 server_state
->InitializeFrom(*canonical_state
);