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
;
35 enum ServerConfigState
{
36 // WARNING: Do not change the numerical values of any of server config state.
37 // Do not remove deprecated server config states - just comment them as
39 SERVER_CONFIG_EMPTY
= 0,
40 SERVER_CONFIG_INVALID
= 1,
41 SERVER_CONFIG_CORRUPTED
= 2,
42 SERVER_CONFIG_EXPIRED
= 3,
43 SERVER_CONFIG_INVALID_EXPIRY
= 4,
45 // NOTE: Add new server config states only immediately above this line. Make
46 // sure to update the QuicServerConfigState enum in
47 // tools/metrics/histograms/histograms.xml accordingly.
51 void RecordServerConfigState(ServerConfigState server_config_state
) {
52 UMA_HISTOGRAM_ENUMERATION("Net.QuicClientHelloServerConfigState",
53 server_config_state
, SERVER_CONFIG_COUNT
);
58 QuicCryptoClientConfig::QuicCryptoClientConfig()
59 : disable_ecdsa_(false) {}
61 QuicCryptoClientConfig::~QuicCryptoClientConfig() {
62 STLDeleteValues(&cached_states_
);
65 QuicCryptoClientConfig::CachedState::CachedState()
66 : server_config_valid_(false),
67 generation_counter_(0) {}
69 QuicCryptoClientConfig::CachedState::~CachedState() {}
71 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now
) const {
72 if (server_config_
.empty()) {
73 RecordServerConfigState(SERVER_CONFIG_EMPTY
);
77 if (!server_config_valid_
) {
78 RecordServerConfigState(SERVER_CONFIG_INVALID
);
82 const CryptoHandshakeMessage
* scfg
= GetServerConfig();
84 // Should be impossible short of cache corruption.
86 RecordServerConfigState(SERVER_CONFIG_CORRUPTED
);
90 uint64 expiry_seconds
;
91 if (scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
92 RecordServerConfigState(SERVER_CONFIG_INVALID_EXPIRY
);
95 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
96 UMA_HISTOGRAM_CUSTOM_TIMES(
97 "Net.QuicClientHelloServerConfig.InvalidDuration",
98 base::TimeDelta::FromSeconds(now
.ToUNIXSeconds() - expiry_seconds
),
99 base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
100 RecordServerConfigState(SERVER_CONFIG_EXPIRED
);
107 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
108 return server_config_
.empty();
111 const CryptoHandshakeMessage
*
112 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
113 if (server_config_
.empty()) {
118 scfg_
.reset(CryptoFramer::ParseMessage(server_config_
));
124 QuicErrorCode
QuicCryptoClientConfig::CachedState::SetServerConfig(
125 StringPiece server_config
, QuicWallTime now
, string
* error_details
) {
126 const bool matches_existing
= server_config
== server_config_
;
128 // Even if the new server config matches the existing one, we still wish to
129 // reject it if it has expired.
130 scoped_ptr
<CryptoHandshakeMessage
> new_scfg_storage
;
131 const CryptoHandshakeMessage
* new_scfg
;
133 if (!matches_existing
) {
134 new_scfg_storage
.reset(CryptoFramer::ParseMessage(server_config
));
135 new_scfg
= new_scfg_storage
.get();
137 new_scfg
= GetServerConfig();
141 *error_details
= "SCFG invalid";
142 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
145 uint64 expiry_seconds
;
146 if (new_scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
147 *error_details
= "SCFG missing EXPY";
148 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
151 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
152 *error_details
= "SCFG has expired";
153 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED
;
156 if (!matches_existing
) {
157 server_config_
= server_config
.as_string();
159 scfg_
.reset(new_scfg_storage
.release());
161 return QUIC_NO_ERROR
;
164 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
165 server_config_
.clear();
170 void QuicCryptoClientConfig::CachedState::SetProof(const vector
<string
>& certs
,
171 StringPiece signature
) {
173 signature
!= server_config_sig_
|| certs_
.size() != certs
.size();
176 for (size_t i
= 0; i
< certs_
.size(); i
++) {
177 if (certs_
[i
] != certs
[i
]) {
188 // If the proof has changed then it needs to be revalidated.
191 server_config_sig_
= signature
.as_string();
194 void QuicCryptoClientConfig::CachedState::Clear() {
195 server_config_
.clear();
196 source_address_token_
.clear();
198 server_config_sig_
.clear();
199 server_config_valid_
= false;
200 proof_verify_details_
.reset();
202 ++generation_counter_
;
205 void QuicCryptoClientConfig::CachedState::ClearProof() {
208 server_config_sig_
.clear();
211 void QuicCryptoClientConfig::CachedState::SetProofValid() {
212 server_config_valid_
= true;
215 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
216 server_config_valid_
= false;
217 ++generation_counter_
;
220 bool QuicCryptoClientConfig::CachedState::Initialize(
221 StringPiece server_config
,
222 StringPiece source_address_token
,
223 const vector
<string
>& certs
,
224 StringPiece signature
,
226 DCHECK(server_config_
.empty());
228 if (server_config
.empty()) {
232 string error_details
;
233 QuicErrorCode error
= SetServerConfig(server_config
, now
,
235 if (error
!= QUIC_NO_ERROR
) {
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() != NULL
) {
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(make_pair(server_id
, cached
));
326 PopulateFromCanonicalConfig(server_id
, cached
);
330 void QuicCryptoClientConfig::ClearCachedStates() {
331 for (CachedStateMap::const_iterator it
= cached_states_
.begin();
332 it
!= cached_states_
.end(); ++it
) {
337 void QuicCryptoClientConfig::FillInchoateClientHello(
338 const QuicServerId
& server_id
,
339 const QuicVersion preferred_version
,
340 const CachedState
* cached
,
341 QuicCryptoNegotiatedParameters
* out_params
,
342 CryptoHandshakeMessage
* out
) const {
344 out
->set_minimum_size(kClientHelloMinimumSize
);
346 // Server name indication. We only send SNI if it's a valid domain name, as
348 if (CryptoUtils::IsValidSNI(server_id
.host())) {
349 out
->SetStringPiece(kSNI
, server_id
.host());
351 out
->SetValue(kVER
, QuicVersionToQuicTag(preferred_version
));
353 if (!user_agent_id_
.empty()) {
354 out
->SetStringPiece(kUAID
, user_agent_id_
);
357 if (!cached
->source_address_token().empty()) {
358 out
->SetStringPiece(kSourceAddressTokenTag
, cached
->source_address_token());
361 if (server_id
.is_https()) {
362 if (disable_ecdsa_
) {
363 out
->SetTaglist(kPDMD
, kX59R
, 0);
365 out
->SetTaglist(kPDMD
, kX509
, 0);
369 if (common_cert_sets
) {
370 out
->SetStringPiece(kCCS
, common_cert_sets
->GetCommonHashes());
373 const vector
<string
>& certs
= cached
->certs();
374 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
375 // client config is being used for multiple connections, another connection
376 // doesn't update the cached certificates and cause us to be unable to
377 // process the server's compressed certificate chain.
378 out_params
->cached_certs
= certs
;
379 if (!certs
.empty()) {
380 vector
<uint64
> hashes
;
381 hashes
.reserve(certs
.size());
382 for (vector
<string
>::const_iterator i
= certs
.begin();
383 i
!= certs
.end(); ++i
) {
384 hashes
.push_back(QuicUtils::FNV1a_64_Hash(i
->data(), i
->size()));
386 out
->SetVector(kCCRT
, hashes
);
390 QuicErrorCode
QuicCryptoClientConfig::FillClientHello(
391 const QuicServerId
& server_id
,
392 QuicConnectionId connection_id
,
393 const QuicVersion preferred_version
,
394 const CachedState
* cached
,
397 const ChannelIDKey
* channel_id_key
,
398 QuicCryptoNegotiatedParameters
* out_params
,
399 CryptoHandshakeMessage
* out
,
400 string
* error_details
) const {
401 DCHECK(error_details
!= NULL
);
403 FillInchoateClientHello(server_id
, preferred_version
, cached
,
406 const CryptoHandshakeMessage
* scfg
= cached
->GetServerConfig();
408 // This should never happen as our caller should have checked
409 // cached->IsComplete() before calling this function.
410 *error_details
= "Handshake not ready";
411 return QUIC_CRYPTO_INTERNAL_ERROR
;
415 if (!scfg
->GetStringPiece(kSCID
, &scid
)) {
416 *error_details
= "SCFG missing SCID";
417 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
419 out
->SetStringPiece(kSCID
, scid
);
421 const QuicTag
* their_aeads
;
422 const QuicTag
* their_key_exchanges
;
423 size_t num_their_aeads
, num_their_key_exchanges
;
424 if (scfg
->GetTaglist(kAEAD
, &their_aeads
,
425 &num_their_aeads
) != QUIC_NO_ERROR
||
426 scfg
->GetTaglist(kKEXS
, &their_key_exchanges
,
427 &num_their_key_exchanges
) != QUIC_NO_ERROR
) {
428 *error_details
= "Missing AEAD or KEXS";
429 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
432 // AEAD: the work loads on the client and server are symmetric. Since the
433 // client is more likely to be CPU-constrained, break the tie by favoring
434 // the client's preference.
435 // Key exchange: the client does more work than the server, so favor the
436 // client's preference.
437 size_t key_exchange_index
;
438 if (!QuicUtils::FindMutualTag(
439 aead
, their_aeads
, num_their_aeads
, QuicUtils::LOCAL_PRIORITY
,
440 &out_params
->aead
, NULL
) ||
441 !QuicUtils::FindMutualTag(
442 kexs
, their_key_exchanges
, num_their_key_exchanges
,
443 QuicUtils::LOCAL_PRIORITY
, &out_params
->key_exchange
,
444 &key_exchange_index
)) {
445 *error_details
= "Unsupported AEAD or KEXS";
446 return QUIC_CRYPTO_NO_SUPPORT
;
448 out
->SetTaglist(kAEAD
, out_params
->aead
, 0);
449 out
->SetTaglist(kKEXS
, out_params
->key_exchange
, 0);
451 StringPiece public_value
;
452 if (scfg
->GetNthValue24(kPUBS
, key_exchange_index
, &public_value
) !=
454 *error_details
= "Missing public value";
455 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
459 if (!scfg
->GetStringPiece(kORBT
, &orbit
) || orbit
.size() != kOrbitSize
) {
460 *error_details
= "SCFG missing OBIT";
461 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
464 CryptoUtils::GenerateNonce(now
, rand
, orbit
, &out_params
->client_nonce
);
465 out
->SetStringPiece(kNONC
, out_params
->client_nonce
);
466 if (!out_params
->server_nonce
.empty()) {
467 out
->SetStringPiece(kServerNonceTag
, out_params
->server_nonce
);
470 switch (out_params
->key_exchange
) {
472 out_params
->client_key_exchange
.reset(Curve25519KeyExchange::New(
473 Curve25519KeyExchange::NewPrivateKey(rand
)));
476 out_params
->client_key_exchange
.reset(P256KeyExchange::New(
477 P256KeyExchange::NewPrivateKey()));
481 *error_details
= "Configured to support an unknown key exchange";
482 return QUIC_CRYPTO_INTERNAL_ERROR
;
485 if (!out_params
->client_key_exchange
->CalculateSharedKey(
486 public_value
, &out_params
->initial_premaster_secret
)) {
487 *error_details
= "Key exchange failure";
488 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
490 out
->SetStringPiece(kPUBS
, out_params
->client_key_exchange
->public_value());
492 if (channel_id_key
) {
493 // In order to calculate the encryption key for the CETV block we need to
494 // serialise the client hello as it currently is (i.e. without the CETV
495 // block). For this, the client hello is serialized without padding.
496 const size_t orig_min_size
= out
->minimum_size();
497 out
->set_minimum_size(0);
499 CryptoHandshakeMessage cetv
;
503 const QuicData
& client_hello_serialized
= out
->GetSerialized();
504 hkdf_input
.append(QuicCryptoConfig::kCETVLabel
,
505 strlen(QuicCryptoConfig::kCETVLabel
) + 1);
506 hkdf_input
.append(reinterpret_cast<char*>(&connection_id
),
507 sizeof(connection_id
));
508 hkdf_input
.append(client_hello_serialized
.data(),
509 client_hello_serialized
.length());
510 hkdf_input
.append(cached
->server_config());
512 string key
= channel_id_key
->SerializeKey();
514 if (!channel_id_key
->Sign(hkdf_input
, &signature
)) {
515 *error_details
= "Channel ID signature failed";
516 return QUIC_INVALID_CHANNEL_ID_SIGNATURE
;
519 cetv
.SetStringPiece(kCIDK
, key
);
520 cetv
.SetStringPiece(kCIDS
, signature
);
522 CrypterPair crypters
;
523 if (!CryptoUtils::DeriveKeys(out_params
->initial_premaster_secret
,
524 out_params
->aead
, out_params
->client_nonce
,
525 out_params
->server_nonce
, hkdf_input
,
526 CryptoUtils::CLIENT
, &crypters
,
527 NULL
/* subkey secret */)) {
528 *error_details
= "Symmetric key setup failed";
529 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
532 const QuicData
& cetv_plaintext
= cetv
.GetSerialized();
533 scoped_ptr
<QuicData
> cetv_ciphertext(crypters
.encrypter
->EncryptPacket(
534 0 /* sequence number */,
535 StringPiece() /* associated data */,
536 cetv_plaintext
.AsStringPiece()));
537 if (!cetv_ciphertext
.get()) {
538 *error_details
= "Packet encryption failed";
539 return QUIC_ENCRYPTION_FAILURE
;
542 out
->SetStringPiece(kCETV
, cetv_ciphertext
->AsStringPiece());
545 out
->set_minimum_size(orig_min_size
);
548 // Derive the symmetric keys and set up the encrypters and decrypters.
549 // Set the following members of out_params:
550 // out_params->hkdf_input_suffix
551 // out_params->initial_crypters
552 out_params
->hkdf_input_suffix
.clear();
553 out_params
->hkdf_input_suffix
.append(reinterpret_cast<char*>(&connection_id
),
554 sizeof(connection_id
));
555 const QuicData
& client_hello_serialized
= out
->GetSerialized();
556 out_params
->hkdf_input_suffix
.append(client_hello_serialized
.data(),
557 client_hello_serialized
.length());
558 out_params
->hkdf_input_suffix
.append(cached
->server_config());
561 const size_t label_len
= strlen(QuicCryptoConfig::kInitialLabel
) + 1;
562 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
563 hkdf_input
.append(QuicCryptoConfig::kInitialLabel
, label_len
);
564 hkdf_input
.append(out_params
->hkdf_input_suffix
);
566 if (!CryptoUtils::DeriveKeys(
567 out_params
->initial_premaster_secret
, out_params
->aead
,
568 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
569 CryptoUtils::CLIENT
, &out_params
->initial_crypters
,
570 NULL
/* subkey secret */)) {
571 *error_details
= "Symmetric key setup failed";
572 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
575 return QUIC_NO_ERROR
;
578 QuicErrorCode
QuicCryptoClientConfig::CacheNewServerConfig(
579 const CryptoHandshakeMessage
& message
,
581 const vector
<string
>& cached_certs
,
583 string
* error_details
) {
584 DCHECK(error_details
!= NULL
);
587 if (!message
.GetStringPiece(kSCFG
, &scfg
)) {
588 *error_details
= "Missing SCFG";
589 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
592 QuicErrorCode error
= cached
->SetServerConfig(scfg
, now
, error_details
);
593 if (error
!= QUIC_NO_ERROR
) {
598 if (message
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
599 cached
->set_source_address_token(token
);
602 StringPiece proof
, cert_bytes
;
603 bool has_proof
= message
.GetStringPiece(kPROF
, &proof
);
604 bool has_cert
= message
.GetStringPiece(kCertificateTag
, &cert_bytes
);
605 if (has_proof
&& has_cert
) {
606 vector
<string
> certs
;
607 if (!CertCompressor::DecompressChain(cert_bytes
, cached_certs
,
608 common_cert_sets
, &certs
)) {
609 *error_details
= "Certificate data invalid";
610 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
613 cached
->SetProof(certs
, proof
);
615 if (proof_verifier() != NULL
) {
616 // Secure QUIC: clear existing proof as we have been sent a new SCFG
617 // without matching proof/certs.
618 cached
->ClearProof();
621 if (has_proof
&& !has_cert
) {
622 *error_details
= "Certificate missing";
623 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
626 if (!has_proof
&& has_cert
) {
627 *error_details
= "Proof missing";
628 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
632 return QUIC_NO_ERROR
;
635 QuicErrorCode
QuicCryptoClientConfig::ProcessRejection(
636 const CryptoHandshakeMessage
& rej
,
640 QuicCryptoNegotiatedParameters
* out_params
,
641 string
* error_details
) {
642 DCHECK(error_details
!= NULL
);
644 if (rej
.tag() != kREJ
) {
645 *error_details
= "Message is not REJ";
646 return QUIC_CRYPTO_INTERNAL_ERROR
;
649 QuicErrorCode error
= CacheNewServerConfig(rej
, now
, out_params
->cached_certs
,
650 cached
, error_details
);
651 if (error
!= QUIC_NO_ERROR
) {
656 if (rej
.GetStringPiece(kServerNonceTag
, &nonce
)) {
657 out_params
->server_nonce
= nonce
.as_string();
660 const uint32
* reject_reasons
;
661 size_t num_reject_reasons
;
662 COMPILE_ASSERT(sizeof(QuicTag
) == sizeof(uint32
), header_out_of_sync
);
663 if (rej
.GetTaglist(kRREJ
, &reject_reasons
,
664 &num_reject_reasons
) == QUIC_NO_ERROR
) {
665 uint32 packed_error
= 0;
666 for (size_t i
= 0; i
< num_reject_reasons
; ++i
) {
667 // HANDSHAKE_OK is 0 and don't report that as error.
668 if (reject_reasons
[i
] == HANDSHAKE_OK
|| reject_reasons
[i
] >= 32) {
671 HandshakeFailureReason reason
=
672 static_cast<HandshakeFailureReason
>(reject_reasons
[i
]);
673 packed_error
|= 1 << (reason
- 1);
675 DVLOG(1) << "Reasons for rejection: " << packed_error
;
677 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
680 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Insecure",
685 return QUIC_NO_ERROR
;
688 QuicErrorCode
QuicCryptoClientConfig::ProcessServerHello(
689 const CryptoHandshakeMessage
& server_hello
,
690 QuicConnectionId connection_id
,
691 const QuicVersionVector
& negotiated_versions
,
693 QuicCryptoNegotiatedParameters
* out_params
,
694 string
* error_details
) {
695 DCHECK(error_details
!= NULL
);
697 if (server_hello
.tag() != kSHLO
) {
698 *error_details
= "Bad tag";
699 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
702 const QuicTag
* supported_version_tags
;
703 size_t num_supported_versions
;
705 if (server_hello
.GetTaglist(kVER
, &supported_version_tags
,
706 &num_supported_versions
) != QUIC_NO_ERROR
) {
707 *error_details
= "server hello missing version list";
708 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
710 if (!negotiated_versions
.empty()) {
711 bool mismatch
= num_supported_versions
!= negotiated_versions
.size();
712 for (size_t i
= 0; i
< num_supported_versions
&& !mismatch
; ++i
) {
713 mismatch
= QuicTagToQuicVersion(supported_version_tags
[i
]) !=
714 negotiated_versions
[i
];
716 // The server sent a list of supported versions, and the connection
717 // reports that there was a version negotiation during the handshake.
718 // Ensure that these two lists are identical.
720 *error_details
= "Downgrade attack detected";
721 return QUIC_VERSION_NEGOTIATION_MISMATCH
;
725 // Learn about updated source address tokens.
727 if (server_hello
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
728 cached
->set_source_address_token(token
);
732 // learn about updated SCFGs.
734 StringPiece public_value
;
735 if (!server_hello
.GetStringPiece(kPUBS
, &public_value
)) {
736 *error_details
= "server hello missing forward secure public value";
737 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
740 if (!out_params
->client_key_exchange
->CalculateSharedKey(
741 public_value
, &out_params
->forward_secure_premaster_secret
)) {
742 *error_details
= "Key exchange failure";
743 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
747 const size_t label_len
= strlen(QuicCryptoConfig::kForwardSecureLabel
) + 1;
748 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
749 hkdf_input
.append(QuicCryptoConfig::kForwardSecureLabel
, label_len
);
750 hkdf_input
.append(out_params
->hkdf_input_suffix
);
752 if (!CryptoUtils::DeriveKeys(
753 out_params
->forward_secure_premaster_secret
, out_params
->aead
,
754 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
755 CryptoUtils::CLIENT
, &out_params
->forward_secure_crypters
,
756 &out_params
->subkey_secret
)) {
757 *error_details
= "Symmetric key setup failed";
758 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
761 return QUIC_NO_ERROR
;
764 QuicErrorCode
QuicCryptoClientConfig::ProcessServerConfigUpdate(
765 const CryptoHandshakeMessage
& server_config_update
,
768 QuicCryptoNegotiatedParameters
* out_params
,
769 string
* error_details
) {
770 DCHECK(error_details
!= NULL
);
772 if (server_config_update
.tag() != kSCUP
) {
773 *error_details
= "ServerConfigUpdate must have kSCUP tag.";
774 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
777 return CacheNewServerConfig(server_config_update
, now
,
778 out_params
->cached_certs
, cached
, error_details
);
781 ProofVerifier
* QuicCryptoClientConfig::proof_verifier() const {
782 return proof_verifier_
.get();
785 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier
* verifier
) {
786 proof_verifier_
.reset(verifier
);
789 ChannelIDSource
* QuicCryptoClientConfig::channel_id_source() const {
790 return channel_id_source_
.get();
793 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource
* source
) {
794 channel_id_source_
.reset(source
);
797 void QuicCryptoClientConfig::InitializeFrom(
798 const QuicServerId
& server_id
,
799 const QuicServerId
& canonical_server_id
,
800 QuicCryptoClientConfig
* canonical_crypto_config
) {
801 CachedState
* canonical_cached
=
802 canonical_crypto_config
->LookupOrCreate(canonical_server_id
);
803 if (!canonical_cached
->proof_valid()) {
806 CachedState
* cached
= LookupOrCreate(server_id
);
807 cached
->InitializeFrom(*canonical_cached
);
810 void QuicCryptoClientConfig::AddCanonicalSuffix(const string
& suffix
) {
811 canoncial_suffixes_
.push_back(suffix
);
814 void QuicCryptoClientConfig::PreferAesGcm() {
815 DCHECK(!aead
.empty());
816 if (aead
.size() <= 1) {
819 QuicTagVector::iterator pos
= find(aead
.begin(), aead
.end(), kAESG
);
820 if (pos
!= aead
.end()) {
822 aead
.insert(aead
.begin(), kAESG
);
826 void QuicCryptoClientConfig::DisableEcdsa() {
827 disable_ecdsa_
= true;
830 void QuicCryptoClientConfig::PopulateFromCanonicalConfig(
831 const QuicServerId
& server_id
,
832 CachedState
* server_state
) {
833 DCHECK(server_state
->IsEmpty());
835 for (; i
< canoncial_suffixes_
.size(); ++i
) {
836 if (EndsWith(server_id
.host(), canoncial_suffixes_
[i
], false)) {
840 if (i
== canoncial_suffixes_
.size())
843 QuicServerId
suffix_server_id(canoncial_suffixes_
[i
], server_id
.port(),
844 server_id
.is_https(),
845 server_id
.privacy_mode());
846 if (!ContainsKey(canonical_server_map_
, suffix_server_id
)) {
847 // This is the first host we've seen which matches the suffix, so make it
849 canonical_server_map_
[suffix_server_id
] = server_id
;
853 const QuicServerId
& canonical_server_id
=
854 canonical_server_map_
[suffix_server_id
];
855 CachedState
* canonical_state
= cached_states_
[canonical_server_id
];
856 if (!canonical_state
->proof_valid()) {
860 // Update canonical version to point at the "most recent" entry.
861 canonical_server_map_
[suffix_server_id
] = server_id
;
863 server_state
->InitializeFrom(*canonical_state
);