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,
44 // NOTE: Add new server config states only immediately above this line. Make
45 // sure to update the QuicServerConfigState enum in
46 // tools/metrics/histograms/histograms.xml accordingly.
50 void RecordServerConfigState(ServerConfigState server_config_state
) {
51 UMA_HISTOGRAM_ENUMERATION("Net.QuicClientHelloServerConfigState",
52 server_config_state
, SERVER_CONFIG_COUNT
);
57 QuicCryptoClientConfig::QuicCryptoClientConfig()
58 : disable_ecdsa_(false) {}
60 QuicCryptoClientConfig::~QuicCryptoClientConfig() {
61 STLDeleteValues(&cached_states_
);
64 QuicCryptoClientConfig::CachedState::CachedState()
65 : server_config_valid_(false),
66 generation_counter_(0) {}
68 QuicCryptoClientConfig::CachedState::~CachedState() {}
70 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now
) const {
71 if (server_config_
.empty()) {
72 RecordServerConfigState(SERVER_CONFIG_EMPTY
);
76 if (!server_config_valid_
) {
77 RecordServerConfigState(SERVER_CONFIG_INVALID
);
81 const CryptoHandshakeMessage
* scfg
= GetServerConfig();
83 // Should be impossible short of cache corruption.
85 RecordServerConfigState(SERVER_CONFIG_CORRUPTED
);
89 uint64 expiry_seconds
;
90 if (scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
||
91 now
.ToUNIXSeconds() >= expiry_seconds
) {
92 RecordServerConfigState(SERVER_CONFIG_EXPIRED
);
99 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
100 return server_config_
.empty();
103 const CryptoHandshakeMessage
*
104 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
105 if (server_config_
.empty()) {
110 scfg_
.reset(CryptoFramer::ParseMessage(server_config_
));
116 QuicErrorCode
QuicCryptoClientConfig::CachedState::SetServerConfig(
117 StringPiece server_config
, QuicWallTime now
, string
* error_details
) {
118 const bool matches_existing
= server_config
== server_config_
;
120 // Even if the new server config matches the existing one, we still wish to
121 // reject it if it has expired.
122 scoped_ptr
<CryptoHandshakeMessage
> new_scfg_storage
;
123 const CryptoHandshakeMessage
* new_scfg
;
125 if (!matches_existing
) {
126 new_scfg_storage
.reset(CryptoFramer::ParseMessage(server_config
));
127 new_scfg
= new_scfg_storage
.get();
129 new_scfg
= GetServerConfig();
133 *error_details
= "SCFG invalid";
134 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
137 uint64 expiry_seconds
;
138 if (new_scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
139 *error_details
= "SCFG missing EXPY";
140 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
143 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
144 *error_details
= "SCFG has expired";
145 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED
;
148 if (!matches_existing
) {
149 server_config_
= server_config
.as_string();
151 scfg_
.reset(new_scfg_storage
.release());
153 return QUIC_NO_ERROR
;
156 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
157 server_config_
.clear();
162 void QuicCryptoClientConfig::CachedState::SetProof(const vector
<string
>& certs
,
163 StringPiece signature
) {
165 signature
!= server_config_sig_
|| certs_
.size() != certs
.size();
168 for (size_t i
= 0; i
< certs_
.size(); i
++) {
169 if (certs_
[i
] != certs
[i
]) {
180 // If the proof has changed then it needs to be revalidated.
183 server_config_sig_
= signature
.as_string();
186 void QuicCryptoClientConfig::CachedState::Clear() {
187 server_config_
.clear();
188 source_address_token_
.clear();
190 server_config_sig_
.clear();
191 server_config_valid_
= false;
192 proof_verify_details_
.reset();
194 ++generation_counter_
;
197 void QuicCryptoClientConfig::CachedState::ClearProof() {
200 server_config_sig_
.clear();
203 void QuicCryptoClientConfig::CachedState::SetProofValid() {
204 server_config_valid_
= true;
207 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
208 server_config_valid_
= false;
209 ++generation_counter_
;
212 bool QuicCryptoClientConfig::CachedState::Initialize(
213 StringPiece server_config
,
214 StringPiece source_address_token
,
215 const vector
<string
>& certs
,
216 StringPiece signature
,
218 DCHECK(server_config_
.empty());
220 if (server_config
.empty()) {
224 string error_details
;
225 QuicErrorCode error
= SetServerConfig(server_config
, now
,
227 if (error
!= QUIC_NO_ERROR
) {
228 DVLOG(1) << "SetServerConfig failed with " << error_details
;
232 signature
.CopyToString(&server_config_sig_
);
233 source_address_token
.CopyToString(&source_address_token_
);
238 const string
& QuicCryptoClientConfig::CachedState::server_config() const {
239 return server_config_
;
243 QuicCryptoClientConfig::CachedState::source_address_token() const {
244 return source_address_token_
;
247 const vector
<string
>& QuicCryptoClientConfig::CachedState::certs() const {
251 const string
& QuicCryptoClientConfig::CachedState::signature() const {
252 return server_config_sig_
;
255 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
256 return server_config_valid_
;
259 uint64
QuicCryptoClientConfig::CachedState::generation_counter() const {
260 return generation_counter_
;
263 const ProofVerifyDetails
*
264 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
265 return proof_verify_details_
.get();
268 void QuicCryptoClientConfig::CachedState::set_source_address_token(
270 source_address_token_
= token
.as_string();
273 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
274 ProofVerifyDetails
* details
) {
275 proof_verify_details_
.reset(details
);
278 void QuicCryptoClientConfig::CachedState::InitializeFrom(
279 const QuicCryptoClientConfig::CachedState
& other
) {
280 DCHECK(server_config_
.empty());
281 DCHECK(!server_config_valid_
);
282 server_config_
= other
.server_config_
;
283 source_address_token_
= other
.source_address_token_
;
284 certs_
= other
.certs_
;
285 server_config_sig_
= other
.server_config_sig_
;
286 server_config_valid_
= other
.server_config_valid_
;
287 ++generation_counter_
;
290 void QuicCryptoClientConfig::SetDefaults() {
291 // Key exchange methods.
296 // Authenticated encryption algorithms. Prefer ChaCha20 by default.
298 if (ChaCha20Poly1305Encrypter::IsSupported()) {
299 aead
.push_back(kCC12
);
301 aead
.push_back(kAESG
);
303 disable_ecdsa_
= false;
306 QuicCryptoClientConfig::CachedState
* QuicCryptoClientConfig::LookupOrCreate(
307 const QuicServerId
& server_id
) {
308 CachedStateMap::const_iterator it
= cached_states_
.find(server_id
);
309 if (it
!= cached_states_
.end()) {
313 CachedState
* cached
= new CachedState
;
314 cached_states_
.insert(make_pair(server_id
, cached
));
315 PopulateFromCanonicalConfig(server_id
, cached
);
319 void QuicCryptoClientConfig::ClearCachedStates() {
320 for (CachedStateMap::const_iterator it
= cached_states_
.begin();
321 it
!= cached_states_
.end(); ++it
) {
326 void QuicCryptoClientConfig::FillInchoateClientHello(
327 const QuicServerId
& server_id
,
328 const QuicVersion preferred_version
,
329 const CachedState
* cached
,
330 QuicCryptoNegotiatedParameters
* out_params
,
331 CryptoHandshakeMessage
* out
) const {
333 out
->set_minimum_size(kClientHelloMinimumSize
);
335 // Server name indication. We only send SNI if it's a valid domain name, as
337 if (CryptoUtils::IsValidSNI(server_id
.host())) {
338 out
->SetStringPiece(kSNI
, server_id
.host());
340 out
->SetValue(kVER
, QuicVersionToQuicTag(preferred_version
));
342 if (!user_agent_id_
.empty()) {
343 out
->SetStringPiece(kUAID
, user_agent_id_
);
346 if (!cached
->source_address_token().empty()) {
347 out
->SetStringPiece(kSourceAddressTokenTag
, cached
->source_address_token());
350 if (server_id
.is_https()) {
351 if (disable_ecdsa_
) {
352 out
->SetTaglist(kPDMD
, kX59R
, 0);
354 out
->SetTaglist(kPDMD
, kX509
, 0);
358 if (common_cert_sets
) {
359 out
->SetStringPiece(kCCS
, common_cert_sets
->GetCommonHashes());
362 const vector
<string
>& certs
= cached
->certs();
363 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
364 // client config is being used for multiple connections, another connection
365 // doesn't update the cached certificates and cause us to be unable to
366 // process the server's compressed certificate chain.
367 out_params
->cached_certs
= certs
;
368 if (!certs
.empty()) {
369 vector
<uint64
> hashes
;
370 hashes
.reserve(certs
.size());
371 for (vector
<string
>::const_iterator i
= certs
.begin();
372 i
!= certs
.end(); ++i
) {
373 hashes
.push_back(QuicUtils::FNV1a_64_Hash(i
->data(), i
->size()));
375 out
->SetVector(kCCRT
, hashes
);
379 QuicErrorCode
QuicCryptoClientConfig::FillClientHello(
380 const QuicServerId
& server_id
,
381 QuicConnectionId connection_id
,
382 const QuicVersion preferred_version
,
383 const CachedState
* cached
,
386 const ChannelIDKey
* channel_id_key
,
387 QuicCryptoNegotiatedParameters
* out_params
,
388 CryptoHandshakeMessage
* out
,
389 string
* error_details
) const {
390 DCHECK(error_details
!= NULL
);
392 FillInchoateClientHello(server_id
, preferred_version
, cached
,
395 const CryptoHandshakeMessage
* scfg
= cached
->GetServerConfig();
397 // This should never happen as our caller should have checked
398 // cached->IsComplete() before calling this function.
399 *error_details
= "Handshake not ready";
400 return QUIC_CRYPTO_INTERNAL_ERROR
;
404 if (!scfg
->GetStringPiece(kSCID
, &scid
)) {
405 *error_details
= "SCFG missing SCID";
406 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
408 out
->SetStringPiece(kSCID
, scid
);
410 const QuicTag
* their_aeads
;
411 const QuicTag
* their_key_exchanges
;
412 size_t num_their_aeads
, num_their_key_exchanges
;
413 if (scfg
->GetTaglist(kAEAD
, &their_aeads
,
414 &num_their_aeads
) != QUIC_NO_ERROR
||
415 scfg
->GetTaglist(kKEXS
, &their_key_exchanges
,
416 &num_their_key_exchanges
) != QUIC_NO_ERROR
) {
417 *error_details
= "Missing AEAD or KEXS";
418 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
421 // AEAD: the work loads on the client and server are symmetric. Since the
422 // client is more likely to be CPU-constrained, break the tie by favoring
423 // the client's preference.
424 // Key exchange: the client does more work than the server, so favor the
425 // client's preference.
426 size_t key_exchange_index
;
427 if (!QuicUtils::FindMutualTag(
428 aead
, their_aeads
, num_their_aeads
, QuicUtils::LOCAL_PRIORITY
,
429 &out_params
->aead
, NULL
) ||
430 !QuicUtils::FindMutualTag(
431 kexs
, their_key_exchanges
, num_their_key_exchanges
,
432 QuicUtils::LOCAL_PRIORITY
, &out_params
->key_exchange
,
433 &key_exchange_index
)) {
434 *error_details
= "Unsupported AEAD or KEXS";
435 return QUIC_CRYPTO_NO_SUPPORT
;
437 out
->SetTaglist(kAEAD
, out_params
->aead
, 0);
438 out
->SetTaglist(kKEXS
, out_params
->key_exchange
, 0);
440 StringPiece public_value
;
441 if (scfg
->GetNthValue24(kPUBS
, key_exchange_index
, &public_value
) !=
443 *error_details
= "Missing public value";
444 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
448 if (!scfg
->GetStringPiece(kORBT
, &orbit
) || orbit
.size() != kOrbitSize
) {
449 *error_details
= "SCFG missing OBIT";
450 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
453 CryptoUtils::GenerateNonce(now
, rand
, orbit
, &out_params
->client_nonce
);
454 out
->SetStringPiece(kNONC
, out_params
->client_nonce
);
455 if (!out_params
->server_nonce
.empty()) {
456 out
->SetStringPiece(kServerNonceTag
, out_params
->server_nonce
);
459 switch (out_params
->key_exchange
) {
461 out_params
->client_key_exchange
.reset(Curve25519KeyExchange::New(
462 Curve25519KeyExchange::NewPrivateKey(rand
)));
465 out_params
->client_key_exchange
.reset(P256KeyExchange::New(
466 P256KeyExchange::NewPrivateKey()));
470 *error_details
= "Configured to support an unknown key exchange";
471 return QUIC_CRYPTO_INTERNAL_ERROR
;
474 if (!out_params
->client_key_exchange
->CalculateSharedKey(
475 public_value
, &out_params
->initial_premaster_secret
)) {
476 *error_details
= "Key exchange failure";
477 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
479 out
->SetStringPiece(kPUBS
, out_params
->client_key_exchange
->public_value());
481 if (channel_id_key
) {
482 // In order to calculate the encryption key for the CETV block we need to
483 // serialise the client hello as it currently is (i.e. without the CETV
484 // block). For this, the client hello is serialized without padding.
485 const size_t orig_min_size
= out
->minimum_size();
486 out
->set_minimum_size(0);
488 CryptoHandshakeMessage cetv
;
492 const QuicData
& client_hello_serialized
= out
->GetSerialized();
493 hkdf_input
.append(QuicCryptoConfig::kCETVLabel
,
494 strlen(QuicCryptoConfig::kCETVLabel
) + 1);
495 hkdf_input
.append(reinterpret_cast<char*>(&connection_id
),
496 sizeof(connection_id
));
497 hkdf_input
.append(client_hello_serialized
.data(),
498 client_hello_serialized
.length());
499 hkdf_input
.append(cached
->server_config());
501 string key
= channel_id_key
->SerializeKey();
503 if (!channel_id_key
->Sign(hkdf_input
, &signature
)) {
504 *error_details
= "Channel ID signature failed";
505 return QUIC_INVALID_CHANNEL_ID_SIGNATURE
;
508 cetv
.SetStringPiece(kCIDK
, key
);
509 cetv
.SetStringPiece(kCIDS
, signature
);
511 CrypterPair crypters
;
512 if (!CryptoUtils::DeriveKeys(out_params
->initial_premaster_secret
,
513 out_params
->aead
, out_params
->client_nonce
,
514 out_params
->server_nonce
, hkdf_input
,
515 CryptoUtils::CLIENT
, &crypters
)) {
516 *error_details
= "Symmetric key setup failed";
517 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
520 const QuicData
& cetv_plaintext
= cetv
.GetSerialized();
521 scoped_ptr
<QuicData
> cetv_ciphertext(crypters
.encrypter
->EncryptPacket(
522 0 /* sequence number */,
523 StringPiece() /* associated data */,
524 cetv_plaintext
.AsStringPiece()));
525 if (!cetv_ciphertext
.get()) {
526 *error_details
= "Packet encryption failed";
527 return QUIC_ENCRYPTION_FAILURE
;
530 out
->SetStringPiece(kCETV
, cetv_ciphertext
->AsStringPiece());
533 out
->set_minimum_size(orig_min_size
);
536 // Derive the symmetric keys and set up the encrypters and decrypters.
537 // Set the following members of out_params:
538 // out_params->hkdf_input_suffix
539 // out_params->initial_crypters
540 out_params
->hkdf_input_suffix
.clear();
541 out_params
->hkdf_input_suffix
.append(reinterpret_cast<char*>(&connection_id
),
542 sizeof(connection_id
));
543 const QuicData
& client_hello_serialized
= out
->GetSerialized();
544 out_params
->hkdf_input_suffix
.append(client_hello_serialized
.data(),
545 client_hello_serialized
.length());
546 out_params
->hkdf_input_suffix
.append(cached
->server_config());
549 const size_t label_len
= strlen(QuicCryptoConfig::kInitialLabel
) + 1;
550 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
551 hkdf_input
.append(QuicCryptoConfig::kInitialLabel
, label_len
);
552 hkdf_input
.append(out_params
->hkdf_input_suffix
);
554 if (!CryptoUtils::DeriveKeys(
555 out_params
->initial_premaster_secret
, out_params
->aead
,
556 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
557 CryptoUtils::CLIENT
, &out_params
->initial_crypters
)) {
558 *error_details
= "Symmetric key setup failed";
559 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
562 return QUIC_NO_ERROR
;
565 QuicErrorCode
QuicCryptoClientConfig::CacheNewServerConfig(
566 const CryptoHandshakeMessage
& message
,
568 const vector
<string
>& cached_certs
,
570 string
* error_details
) {
571 DCHECK(error_details
!= NULL
);
574 if (!message
.GetStringPiece(kSCFG
, &scfg
)) {
575 *error_details
= "Missing SCFG";
576 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
579 QuicErrorCode error
= cached
->SetServerConfig(scfg
, now
, error_details
);
580 if (error
!= QUIC_NO_ERROR
) {
585 if (message
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
586 cached
->set_source_address_token(token
);
589 StringPiece proof
, cert_bytes
;
590 bool has_proof
= message
.GetStringPiece(kPROF
, &proof
);
591 bool has_cert
= message
.GetStringPiece(kCertificateTag
, &cert_bytes
);
592 if (has_proof
&& has_cert
) {
593 vector
<string
> certs
;
594 if (!CertCompressor::DecompressChain(cert_bytes
, cached_certs
,
595 common_cert_sets
, &certs
)) {
596 *error_details
= "Certificate data invalid";
597 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
600 cached
->SetProof(certs
, proof
);
602 cached
->ClearProof();
603 if (has_proof
&& !has_cert
) {
604 *error_details
= "Certificate missing";
605 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
608 if (!has_proof
&& has_cert
) {
609 *error_details
= "Proof missing";
610 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
614 return QUIC_NO_ERROR
;
617 QuicErrorCode
QuicCryptoClientConfig::ProcessRejection(
618 const CryptoHandshakeMessage
& rej
,
622 QuicCryptoNegotiatedParameters
* out_params
,
623 string
* error_details
) {
624 DCHECK(error_details
!= NULL
);
626 if (rej
.tag() != kREJ
) {
627 *error_details
= "Message is not REJ";
628 return QUIC_CRYPTO_INTERNAL_ERROR
;
631 QuicErrorCode error
= CacheNewServerConfig(rej
, now
, out_params
->cached_certs
,
632 cached
, error_details
);
633 if (error
!= QUIC_NO_ERROR
) {
638 if (rej
.GetStringPiece(kServerNonceTag
, &nonce
)) {
639 out_params
->server_nonce
= nonce
.as_string();
642 const uint32
* reject_reasons
;
643 size_t num_reject_reasons
;
644 COMPILE_ASSERT(sizeof(QuicTag
) == sizeof(uint32
), header_out_of_sync
);
645 if (rej
.GetTaglist(kRREJ
, &reject_reasons
,
646 &num_reject_reasons
) == QUIC_NO_ERROR
) {
647 uint32 packed_error
= 0;
648 for (size_t i
= 0; i
< num_reject_reasons
; ++i
) {
649 // HANDSHAKE_OK is 0 and don't report that as error.
650 if (reject_reasons
[i
] == HANDSHAKE_OK
|| reject_reasons
[i
] >= 32) {
653 HandshakeFailureReason reason
=
654 static_cast<HandshakeFailureReason
>(reject_reasons
[i
]);
655 packed_error
|= 1 << (reason
- 1);
657 DVLOG(1) << "Reasons for rejection: " << packed_error
;
659 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
662 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Insecure",
667 return QUIC_NO_ERROR
;
670 QuicErrorCode
QuicCryptoClientConfig::ProcessServerHello(
671 const CryptoHandshakeMessage
& server_hello
,
672 QuicConnectionId connection_id
,
673 const QuicVersionVector
& negotiated_versions
,
675 QuicCryptoNegotiatedParameters
* out_params
,
676 string
* error_details
) {
677 DCHECK(error_details
!= NULL
);
679 if (server_hello
.tag() != kSHLO
) {
680 *error_details
= "Bad tag";
681 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
684 const QuicTag
* supported_version_tags
;
685 size_t num_supported_versions
;
687 if (server_hello
.GetTaglist(kVER
, &supported_version_tags
,
688 &num_supported_versions
) != QUIC_NO_ERROR
) {
689 *error_details
= "server hello missing version list";
690 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
692 if (!negotiated_versions
.empty()) {
693 bool mismatch
= num_supported_versions
!= negotiated_versions
.size();
694 for (size_t i
= 0; i
< num_supported_versions
&& !mismatch
; ++i
) {
695 mismatch
= QuicTagToQuicVersion(supported_version_tags
[i
]) !=
696 negotiated_versions
[i
];
698 // The server sent a list of supported versions, and the connection
699 // reports that there was a version negotiation during the handshake.
700 // Ensure that these two lists are identical.
702 *error_details
= "Downgrade attack detected";
703 return QUIC_VERSION_NEGOTIATION_MISMATCH
;
707 // Learn about updated source address tokens.
709 if (server_hello
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
710 cached
->set_source_address_token(token
);
714 // learn about updated SCFGs.
716 StringPiece public_value
;
717 if (!server_hello
.GetStringPiece(kPUBS
, &public_value
)) {
718 *error_details
= "server hello missing forward secure public value";
719 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
722 if (!out_params
->client_key_exchange
->CalculateSharedKey(
723 public_value
, &out_params
->forward_secure_premaster_secret
)) {
724 *error_details
= "Key exchange failure";
725 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
729 const size_t label_len
= strlen(QuicCryptoConfig::kForwardSecureLabel
) + 1;
730 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
731 hkdf_input
.append(QuicCryptoConfig::kForwardSecureLabel
, label_len
);
732 hkdf_input
.append(out_params
->hkdf_input_suffix
);
734 if (!CryptoUtils::DeriveKeys(
735 out_params
->forward_secure_premaster_secret
, out_params
->aead
,
736 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
737 CryptoUtils::CLIENT
, &out_params
->forward_secure_crypters
)) {
738 *error_details
= "Symmetric key setup failed";
739 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
742 return QUIC_NO_ERROR
;
745 QuicErrorCode
QuicCryptoClientConfig::ProcessServerConfigUpdate(
746 const CryptoHandshakeMessage
& server_config_update
,
749 QuicCryptoNegotiatedParameters
* out_params
,
750 string
* error_details
) {
751 DCHECK(error_details
!= NULL
);
753 if (server_config_update
.tag() != kSCUP
) {
754 *error_details
= "ServerConfigUpdate must have kSCUP tag.";
755 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
758 return CacheNewServerConfig(server_config_update
, now
,
759 out_params
->cached_certs
, cached
, error_details
);
762 ProofVerifier
* QuicCryptoClientConfig::proof_verifier() const {
763 return proof_verifier_
.get();
766 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier
* verifier
) {
767 proof_verifier_
.reset(verifier
);
770 ChannelIDSource
* QuicCryptoClientConfig::channel_id_source() const {
771 return channel_id_source_
.get();
774 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource
* source
) {
775 channel_id_source_
.reset(source
);
778 void QuicCryptoClientConfig::InitializeFrom(
779 const QuicServerId
& server_id
,
780 const QuicServerId
& canonical_server_id
,
781 QuicCryptoClientConfig
* canonical_crypto_config
) {
782 CachedState
* canonical_cached
=
783 canonical_crypto_config
->LookupOrCreate(canonical_server_id
);
784 if (!canonical_cached
->proof_valid()) {
787 CachedState
* cached
= LookupOrCreate(server_id
);
788 cached
->InitializeFrom(*canonical_cached
);
791 void QuicCryptoClientConfig::AddCanonicalSuffix(const string
& suffix
) {
792 canoncial_suffixes_
.push_back(suffix
);
795 void QuicCryptoClientConfig::PreferAesGcm() {
796 DCHECK(!aead
.empty());
797 if (aead
.size() <= 1) {
800 QuicTagVector::iterator pos
= find(aead
.begin(), aead
.end(), kAESG
);
801 if (pos
!= aead
.end()) {
803 aead
.insert(aead
.begin(), kAESG
);
807 void QuicCryptoClientConfig::DisableEcdsa() {
808 disable_ecdsa_
= true;
811 void QuicCryptoClientConfig::PopulateFromCanonicalConfig(
812 const QuicServerId
& server_id
,
813 CachedState
* server_state
) {
814 DCHECK(server_state
->IsEmpty());
816 for (; i
< canoncial_suffixes_
.size(); ++i
) {
817 if (EndsWith(server_id
.host(), canoncial_suffixes_
[i
], false)) {
821 if (i
== canoncial_suffixes_
.size())
824 QuicServerId
suffix_server_id(canoncial_suffixes_
[i
], server_id
.port(),
825 server_id
.is_https(),
826 server_id
.privacy_mode());
827 if (!ContainsKey(canonical_server_map_
, suffix_server_id
)) {
828 // This is the first host we've seen which matches the suffix, so make it
830 canonical_server_map_
[suffix_server_id
] = server_id
;
834 const QuicServerId
& canonical_server_id
=
835 canonical_server_map_
[suffix_server_id
];
836 CachedState
* canonical_state
= cached_states_
[canonical_server_id
];
837 if (!canonical_state
->proof_valid()) {
841 // Update canonical version to point at the "most recent" entry.
842 canonical_server_map_
[suffix_server_id
] = server_id
;
844 server_state
->InitializeFrom(*canonical_state
);