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/stl_util.h"
8 #include "base/strings/string_util.h"
9 #include "net/quic/crypto/cert_compressor.h"
10 #include "net/quic/crypto/chacha20_poly1305_encrypter.h"
11 #include "net/quic/crypto/channel_id.h"
12 #include "net/quic/crypto/common_cert_set.h"
13 #include "net/quic/crypto/crypto_framer.h"
14 #include "net/quic/crypto/crypto_utils.h"
15 #include "net/quic/crypto/curve25519_key_exchange.h"
16 #include "net/quic/crypto/key_exchange.h"
17 #include "net/quic/crypto/p256_key_exchange.h"
18 #include "net/quic/crypto/proof_verifier.h"
19 #include "net/quic/crypto/quic_encrypter.h"
20 #include "net/quic/quic_utils.h"
22 using base::StringPiece
;
31 QuicCryptoClientConfig::QuicCryptoClientConfig()
32 : disable_ecdsa_(false) {}
34 QuicCryptoClientConfig::~QuicCryptoClientConfig() {
35 STLDeleteValues(&cached_states_
);
38 QuicCryptoClientConfig::CachedState::CachedState()
39 : server_config_valid_(false),
40 generation_counter_(0) {}
42 QuicCryptoClientConfig::CachedState::~CachedState() {}
44 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now
) const {
45 if (server_config_
.empty() || !server_config_valid_
) {
49 const CryptoHandshakeMessage
* scfg
= GetServerConfig();
51 // Should be impossible short of cache corruption.
56 uint64 expiry_seconds
;
57 if (scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
||
58 now
.ToUNIXSeconds() >= expiry_seconds
) {
65 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
66 return server_config_
.empty();
69 const CryptoHandshakeMessage
*
70 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
71 if (server_config_
.empty()) {
76 scfg_
.reset(CryptoFramer::ParseMessage(server_config_
));
82 QuicErrorCode
QuicCryptoClientConfig::CachedState::SetServerConfig(
83 StringPiece server_config
, QuicWallTime now
, string
* error_details
) {
84 const bool matches_existing
= server_config
== server_config_
;
86 // Even if the new server config matches the existing one, we still wish to
87 // reject it if it has expired.
88 scoped_ptr
<CryptoHandshakeMessage
> new_scfg_storage
;
89 const CryptoHandshakeMessage
* new_scfg
;
91 if (!matches_existing
) {
92 new_scfg_storage
.reset(CryptoFramer::ParseMessage(server_config
));
93 new_scfg
= new_scfg_storage
.get();
95 new_scfg
= GetServerConfig();
99 *error_details
= "SCFG invalid";
100 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
103 uint64 expiry_seconds
;
104 if (new_scfg
->GetUint64(kEXPY
, &expiry_seconds
) != QUIC_NO_ERROR
) {
105 *error_details
= "SCFG missing EXPY";
106 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
109 if (now
.ToUNIXSeconds() >= expiry_seconds
) {
110 *error_details
= "SCFG has expired";
111 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED
;
114 if (!matches_existing
) {
115 server_config_
= server_config
.as_string();
117 scfg_
.reset(new_scfg_storage
.release());
119 return QUIC_NO_ERROR
;
122 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
123 server_config_
.clear();
128 void QuicCryptoClientConfig::CachedState::SetProof(const vector
<string
>& certs
,
129 StringPiece signature
) {
131 signature
!= server_config_sig_
|| certs_
.size() != certs
.size();
134 for (size_t i
= 0; i
< certs_
.size(); i
++) {
135 if (certs_
[i
] != certs
[i
]) {
146 // If the proof has changed then it needs to be revalidated.
149 server_config_sig_
= signature
.as_string();
152 void QuicCryptoClientConfig::CachedState::Clear() {
153 server_config_
.clear();
154 source_address_token_
.clear();
156 server_config_sig_
.clear();
157 server_config_valid_
= false;
158 proof_verify_details_
.reset();
160 ++generation_counter_
;
163 void QuicCryptoClientConfig::CachedState::ClearProof() {
166 server_config_sig_
.clear();
169 void QuicCryptoClientConfig::CachedState::SetProofValid() {
170 server_config_valid_
= true;
173 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
174 server_config_valid_
= false;
175 ++generation_counter_
;
178 bool QuicCryptoClientConfig::CachedState::Initialize(
179 StringPiece server_config
,
180 StringPiece source_address_token
,
181 const vector
<string
>& certs
,
182 StringPiece signature
,
184 DCHECK(server_config_
.empty());
186 if (server_config
.empty()) {
190 string error_details
;
191 QuicErrorCode error
= SetServerConfig(server_config
, now
,
193 if (error
!= QUIC_NO_ERROR
) {
194 DVLOG(1) << "SetServerConfig failed with " << error_details
;
198 signature
.CopyToString(&server_config_sig_
);
199 source_address_token
.CopyToString(&source_address_token_
);
204 const string
& QuicCryptoClientConfig::CachedState::server_config() const {
205 return server_config_
;
209 QuicCryptoClientConfig::CachedState::source_address_token() const {
210 return source_address_token_
;
213 const vector
<string
>& QuicCryptoClientConfig::CachedState::certs() const {
217 const string
& QuicCryptoClientConfig::CachedState::signature() const {
218 return server_config_sig_
;
221 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
222 return server_config_valid_
;
225 uint64
QuicCryptoClientConfig::CachedState::generation_counter() const {
226 return generation_counter_
;
229 const ProofVerifyDetails
*
230 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
231 return proof_verify_details_
.get();
234 void QuicCryptoClientConfig::CachedState::set_source_address_token(
236 source_address_token_
= token
.as_string();
239 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
240 ProofVerifyDetails
* details
) {
241 proof_verify_details_
.reset(details
);
244 void QuicCryptoClientConfig::CachedState::InitializeFrom(
245 const QuicCryptoClientConfig::CachedState
& other
) {
246 DCHECK(server_config_
.empty());
247 DCHECK(!server_config_valid_
);
248 server_config_
= other
.server_config_
;
249 source_address_token_
= other
.source_address_token_
;
250 certs_
= other
.certs_
;
251 server_config_sig_
= other
.server_config_sig_
;
252 server_config_valid_
= other
.server_config_valid_
;
253 ++generation_counter_
;
256 void QuicCryptoClientConfig::SetDefaults() {
257 // Key exchange methods.
262 // Authenticated encryption algorithms. Prefer ChaCha20 by default.
264 if (ChaCha20Poly1305Encrypter::IsSupported()) {
265 aead
.push_back(kCC12
);
267 aead
.push_back(kAESG
);
269 disable_ecdsa_
= false;
272 QuicCryptoClientConfig::CachedState
* QuicCryptoClientConfig::LookupOrCreate(
273 const QuicServerId
& server_id
) {
274 CachedStateMap::const_iterator it
= cached_states_
.find(server_id
);
275 if (it
!= cached_states_
.end()) {
279 CachedState
* cached
= new CachedState
;
280 cached_states_
.insert(make_pair(server_id
, cached
));
281 PopulateFromCanonicalConfig(server_id
, cached
);
285 void QuicCryptoClientConfig::ClearCachedStates() {
286 for (CachedStateMap::const_iterator it
= cached_states_
.begin();
287 it
!= cached_states_
.end(); ++it
) {
292 void QuicCryptoClientConfig::FillInchoateClientHello(
293 const QuicServerId
& server_id
,
294 const QuicVersion preferred_version
,
295 const CachedState
* cached
,
296 QuicCryptoNegotiatedParameters
* out_params
,
297 CryptoHandshakeMessage
* out
) const {
299 out
->set_minimum_size(kClientHelloMinimumSize
);
301 // Server name indication. We only send SNI if it's a valid domain name, as
303 if (CryptoUtils::IsValidSNI(server_id
.host())) {
304 out
->SetStringPiece(kSNI
, server_id
.host());
306 out
->SetValue(kVER
, QuicVersionToQuicTag(preferred_version
));
308 if (!user_agent_id_
.empty()) {
309 out
->SetStringPiece(kUAID
, user_agent_id_
);
312 if (!cached
->source_address_token().empty()) {
313 out
->SetStringPiece(kSourceAddressTokenTag
, cached
->source_address_token());
316 if (server_id
.is_https()) {
317 if (disable_ecdsa_
) {
318 out
->SetTaglist(kPDMD
, kX59R
, 0);
320 out
->SetTaglist(kPDMD
, kX509
, 0);
324 if (common_cert_sets
) {
325 out
->SetStringPiece(kCCS
, common_cert_sets
->GetCommonHashes());
328 const vector
<string
>& certs
= cached
->certs();
329 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
330 // client config is being used for multiple connections, another connection
331 // doesn't update the cached certificates and cause us to be unable to
332 // process the server's compressed certificate chain.
333 out_params
->cached_certs
= certs
;
334 if (!certs
.empty()) {
335 vector
<uint64
> hashes
;
336 hashes
.reserve(certs
.size());
337 for (vector
<string
>::const_iterator i
= certs
.begin();
338 i
!= certs
.end(); ++i
) {
339 hashes
.push_back(QuicUtils::FNV1a_64_Hash(i
->data(), i
->size()));
341 out
->SetVector(kCCRT
, hashes
);
345 QuicErrorCode
QuicCryptoClientConfig::FillClientHello(
346 const QuicServerId
& server_id
,
347 QuicConnectionId connection_id
,
348 const QuicVersion preferred_version
,
349 const CachedState
* cached
,
352 const ChannelIDKey
* channel_id_key
,
353 QuicCryptoNegotiatedParameters
* out_params
,
354 CryptoHandshakeMessage
* out
,
355 string
* error_details
) const {
356 DCHECK(error_details
!= NULL
);
358 FillInchoateClientHello(server_id
, preferred_version
, cached
,
361 const CryptoHandshakeMessage
* scfg
= cached
->GetServerConfig();
363 // This should never happen as our caller should have checked
364 // cached->IsComplete() before calling this function.
365 *error_details
= "Handshake not ready";
366 return QUIC_CRYPTO_INTERNAL_ERROR
;
370 if (!scfg
->GetStringPiece(kSCID
, &scid
)) {
371 *error_details
= "SCFG missing SCID";
372 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
374 out
->SetStringPiece(kSCID
, scid
);
376 const QuicTag
* their_aeads
;
377 const QuicTag
* their_key_exchanges
;
378 size_t num_their_aeads
, num_their_key_exchanges
;
379 if (scfg
->GetTaglist(kAEAD
, &their_aeads
,
380 &num_their_aeads
) != QUIC_NO_ERROR
||
381 scfg
->GetTaglist(kKEXS
, &their_key_exchanges
,
382 &num_their_key_exchanges
) != QUIC_NO_ERROR
) {
383 *error_details
= "Missing AEAD or KEXS";
384 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
387 // AEAD: the work loads on the client and server are symmetric. Since the
388 // client is more likely to be CPU-constrained, break the tie by favoring
389 // the client's preference.
390 // Key exchange: the client does more work than the server, so favor the
391 // client's preference.
392 size_t key_exchange_index
;
393 if (!QuicUtils::FindMutualTag(
394 aead
, their_aeads
, num_their_aeads
, QuicUtils::LOCAL_PRIORITY
,
395 &out_params
->aead
, NULL
) ||
396 !QuicUtils::FindMutualTag(
397 kexs
, their_key_exchanges
, num_their_key_exchanges
,
398 QuicUtils::LOCAL_PRIORITY
, &out_params
->key_exchange
,
399 &key_exchange_index
)) {
400 *error_details
= "Unsupported AEAD or KEXS";
401 return QUIC_CRYPTO_NO_SUPPORT
;
403 out
->SetTaglist(kAEAD
, out_params
->aead
, 0);
404 out
->SetTaglist(kKEXS
, out_params
->key_exchange
, 0);
406 StringPiece public_value
;
407 if (scfg
->GetNthValue24(kPUBS
, key_exchange_index
, &public_value
) !=
409 *error_details
= "Missing public value";
410 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
414 if (!scfg
->GetStringPiece(kORBT
, &orbit
) || orbit
.size() != kOrbitSize
) {
415 *error_details
= "SCFG missing OBIT";
416 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
419 CryptoUtils::GenerateNonce(now
, rand
, orbit
, &out_params
->client_nonce
);
420 out
->SetStringPiece(kNONC
, out_params
->client_nonce
);
421 if (!out_params
->server_nonce
.empty()) {
422 out
->SetStringPiece(kServerNonceTag
, out_params
->server_nonce
);
425 switch (out_params
->key_exchange
) {
427 out_params
->client_key_exchange
.reset(Curve25519KeyExchange::New(
428 Curve25519KeyExchange::NewPrivateKey(rand
)));
431 out_params
->client_key_exchange
.reset(P256KeyExchange::New(
432 P256KeyExchange::NewPrivateKey()));
436 *error_details
= "Configured to support an unknown key exchange";
437 return QUIC_CRYPTO_INTERNAL_ERROR
;
440 if (!out_params
->client_key_exchange
->CalculateSharedKey(
441 public_value
, &out_params
->initial_premaster_secret
)) {
442 *error_details
= "Key exchange failure";
443 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
445 out
->SetStringPiece(kPUBS
, out_params
->client_key_exchange
->public_value());
447 if (channel_id_key
) {
448 // In order to calculate the encryption key for the CETV block we need to
449 // serialise the client hello as it currently is (i.e. without the CETV
450 // block). For this, the client hello is serialized without padding.
451 const size_t orig_min_size
= out
->minimum_size();
452 out
->set_minimum_size(0);
454 CryptoHandshakeMessage cetv
;
458 const QuicData
& client_hello_serialized
= out
->GetSerialized();
459 hkdf_input
.append(QuicCryptoConfig::kCETVLabel
,
460 strlen(QuicCryptoConfig::kCETVLabel
) + 1);
461 hkdf_input
.append(reinterpret_cast<char*>(&connection_id
),
462 sizeof(connection_id
));
463 hkdf_input
.append(client_hello_serialized
.data(),
464 client_hello_serialized
.length());
465 hkdf_input
.append(cached
->server_config());
467 string key
= channel_id_key
->SerializeKey();
469 if (!channel_id_key
->Sign(hkdf_input
, &signature
)) {
470 *error_details
= "Channel ID signature failed";
471 return QUIC_INVALID_CHANNEL_ID_SIGNATURE
;
474 cetv
.SetStringPiece(kCIDK
, key
);
475 cetv
.SetStringPiece(kCIDS
, signature
);
477 CrypterPair crypters
;
478 if (!CryptoUtils::DeriveKeys(out_params
->initial_premaster_secret
,
479 out_params
->aead
, out_params
->client_nonce
,
480 out_params
->server_nonce
, hkdf_input
,
481 CryptoUtils::CLIENT
, &crypters
)) {
482 *error_details
= "Symmetric key setup failed";
483 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
486 const QuicData
& cetv_plaintext
= cetv
.GetSerialized();
487 scoped_ptr
<QuicData
> cetv_ciphertext(crypters
.encrypter
->EncryptPacket(
488 0 /* sequence number */,
489 StringPiece() /* associated data */,
490 cetv_plaintext
.AsStringPiece()));
491 if (!cetv_ciphertext
.get()) {
492 *error_details
= "Packet encryption failed";
493 return QUIC_ENCRYPTION_FAILURE
;
496 out
->SetStringPiece(kCETV
, cetv_ciphertext
->AsStringPiece());
499 out
->set_minimum_size(orig_min_size
);
502 // Derive the symmetric keys and set up the encrypters and decrypters.
503 // Set the following members of out_params:
504 // out_params->hkdf_input_suffix
505 // out_params->initial_crypters
506 out_params
->hkdf_input_suffix
.clear();
507 out_params
->hkdf_input_suffix
.append(reinterpret_cast<char*>(&connection_id
),
508 sizeof(connection_id
));
509 const QuicData
& client_hello_serialized
= out
->GetSerialized();
510 out_params
->hkdf_input_suffix
.append(client_hello_serialized
.data(),
511 client_hello_serialized
.length());
512 out_params
->hkdf_input_suffix
.append(cached
->server_config());
515 const size_t label_len
= strlen(QuicCryptoConfig::kInitialLabel
) + 1;
516 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
517 hkdf_input
.append(QuicCryptoConfig::kInitialLabel
, label_len
);
518 hkdf_input
.append(out_params
->hkdf_input_suffix
);
520 if (!CryptoUtils::DeriveKeys(
521 out_params
->initial_premaster_secret
, out_params
->aead
,
522 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
523 CryptoUtils::CLIENT
, &out_params
->initial_crypters
)) {
524 *error_details
= "Symmetric key setup failed";
525 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
528 return QUIC_NO_ERROR
;
531 QuicErrorCode
QuicCryptoClientConfig::ProcessRejection(
532 const CryptoHandshakeMessage
& rej
,
535 QuicCryptoNegotiatedParameters
* out_params
,
536 string
* error_details
) {
537 DCHECK(error_details
!= NULL
);
539 if (rej
.tag() != kREJ
) {
540 *error_details
= "Message is not REJ";
541 return QUIC_CRYPTO_INTERNAL_ERROR
;
545 if (!rej
.GetStringPiece(kSCFG
, &scfg
)) {
546 *error_details
= "Missing SCFG";
547 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
550 QuicErrorCode error
= cached
->SetServerConfig(scfg
, now
, error_details
);
551 if (error
!= QUIC_NO_ERROR
) {
556 if (rej
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
557 cached
->set_source_address_token(token
);
561 if (rej
.GetStringPiece(kServerNonceTag
, &nonce
)) {
562 out_params
->server_nonce
= nonce
.as_string();
565 StringPiece proof
, cert_bytes
;
566 bool has_proof
= rej
.GetStringPiece(kPROF
, &proof
);
567 bool has_cert
= rej
.GetStringPiece(kCertificateTag
, &cert_bytes
);
568 if (has_proof
&& has_cert
) {
569 vector
<string
> certs
;
570 if (!CertCompressor::DecompressChain(cert_bytes
, out_params
->cached_certs
,
571 common_cert_sets
, &certs
)) {
572 *error_details
= "Certificate data invalid";
573 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
576 cached
->SetProof(certs
, proof
);
578 cached
->ClearProof();
579 if (has_proof
&& !has_cert
) {
580 *error_details
= "Certificate missing";
581 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
584 if (!has_proof
&& has_cert
) {
585 *error_details
= "Proof missing";
586 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
590 const uint32
* reject_reasons
;
591 size_t num_reject_reasons
;
592 COMPILE_ASSERT(sizeof(QuicTag
) == sizeof(uint32
), header_out_of_sync
);
593 if (rej
.GetTaglist(kRREJ
, &reject_reasons
,
594 &num_reject_reasons
) == QUIC_NO_ERROR
) {
596 uint32 packed_error
= 0;
597 for (size_t i
= 0; i
< num_reject_reasons
; ++i
) {
598 // HANDSHAKE_OK is 0 and don't report that as error.
599 if (reject_reasons
[i
] == HANDSHAKE_OK
|| reject_reasons
[i
] >= 32) {
602 HandshakeFailureReason reason
=
603 static_cast<HandshakeFailureReason
>(reject_reasons
[i
]);
604 packed_error
|= 1 << (reason
- 1);
606 DVLOG(1) << "Reasons for rejection: " << packed_error
;
610 return QUIC_NO_ERROR
;
613 QuicErrorCode
QuicCryptoClientConfig::ProcessServerHello(
614 const CryptoHandshakeMessage
& server_hello
,
615 QuicConnectionId connection_id
,
616 const QuicVersionVector
& negotiated_versions
,
618 QuicCryptoNegotiatedParameters
* out_params
,
619 string
* error_details
) {
620 DCHECK(error_details
!= NULL
);
622 if (server_hello
.tag() != kSHLO
) {
623 *error_details
= "Bad tag";
624 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE
;
627 const QuicTag
* supported_version_tags
;
628 size_t num_supported_versions
;
630 if (server_hello
.GetTaglist(kVER
, &supported_version_tags
,
631 &num_supported_versions
) != QUIC_NO_ERROR
) {
632 *error_details
= "server hello missing version list";
633 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
635 if (!negotiated_versions
.empty()) {
636 bool mismatch
= num_supported_versions
!= negotiated_versions
.size();
637 for (size_t i
= 0; i
< num_supported_versions
&& !mismatch
; ++i
) {
638 mismatch
= QuicTagToQuicVersion(supported_version_tags
[i
]) !=
639 negotiated_versions
[i
];
641 // The server sent a list of supported versions, and the connection
642 // reports that there was a version negotiation during the handshake.
643 // Ensure that these two lists are identical.
645 *error_details
= "Downgrade attack detected";
646 return QUIC_VERSION_NEGOTIATION_MISMATCH
;
650 // Learn about updated source address tokens.
652 if (server_hello
.GetStringPiece(kSourceAddressTokenTag
, &token
)) {
653 cached
->set_source_address_token(token
);
657 // learn about updated SCFGs.
659 StringPiece public_value
;
660 if (!server_hello
.GetStringPiece(kPUBS
, &public_value
)) {
661 *error_details
= "server hello missing forward secure public value";
662 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
665 if (!out_params
->client_key_exchange
->CalculateSharedKey(
666 public_value
, &out_params
->forward_secure_premaster_secret
)) {
667 *error_details
= "Key exchange failure";
668 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
672 const size_t label_len
= strlen(QuicCryptoConfig::kForwardSecureLabel
) + 1;
673 hkdf_input
.reserve(label_len
+ out_params
->hkdf_input_suffix
.size());
674 hkdf_input
.append(QuicCryptoConfig::kForwardSecureLabel
, label_len
);
675 hkdf_input
.append(out_params
->hkdf_input_suffix
);
677 if (!CryptoUtils::DeriveKeys(
678 out_params
->forward_secure_premaster_secret
, out_params
->aead
,
679 out_params
->client_nonce
, out_params
->server_nonce
, hkdf_input
,
680 CryptoUtils::CLIENT
, &out_params
->forward_secure_crypters
)) {
681 *error_details
= "Symmetric key setup failed";
682 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
685 return QUIC_NO_ERROR
;
688 ProofVerifier
* QuicCryptoClientConfig::proof_verifier() const {
689 return proof_verifier_
.get();
692 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier
* verifier
) {
693 proof_verifier_
.reset(verifier
);
696 ChannelIDSource
* QuicCryptoClientConfig::channel_id_source() const {
697 return channel_id_source_
.get();
700 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource
* source
) {
701 channel_id_source_
.reset(source
);
704 void QuicCryptoClientConfig::InitializeFrom(
705 const QuicServerId
& server_id
,
706 const QuicServerId
& canonical_server_id
,
707 QuicCryptoClientConfig
* canonical_crypto_config
) {
708 CachedState
* canonical_cached
=
709 canonical_crypto_config
->LookupOrCreate(canonical_server_id
);
710 if (!canonical_cached
->proof_valid()) {
713 CachedState
* cached
= LookupOrCreate(server_id
);
714 cached
->InitializeFrom(*canonical_cached
);
717 void QuicCryptoClientConfig::AddCanonicalSuffix(const string
& suffix
) {
718 canoncial_suffixes_
.push_back(suffix
);
721 void QuicCryptoClientConfig::PreferAesGcm() {
722 DCHECK(!aead
.empty());
723 if (aead
.size() <= 1) {
726 QuicTagVector::iterator pos
= find(aead
.begin(), aead
.end(), kAESG
);
727 if (pos
!= aead
.end()) {
729 aead
.insert(aead
.begin(), kAESG
);
733 void QuicCryptoClientConfig::DisableEcdsa() {
734 disable_ecdsa_
= true;
737 void QuicCryptoClientConfig::PopulateFromCanonicalConfig(
738 const QuicServerId
& server_id
,
739 CachedState
* server_state
) {
740 DCHECK(server_state
->IsEmpty());
742 for (; i
< canoncial_suffixes_
.size(); ++i
) {
743 if (EndsWith(server_id
.host(), canoncial_suffixes_
[i
], false)) {
747 if (i
== canoncial_suffixes_
.size())
750 QuicServerId
suffix_server_id(canoncial_suffixes_
[i
], server_id
.port(),
751 server_id
.is_https(),
752 server_id
.privacy_mode());
753 if (!ContainsKey(canonical_server_map_
, suffix_server_id
)) {
754 // This is the first host we've seen which matches the suffix, so make it
756 canonical_server_map_
[suffix_server_id
] = server_id
;
760 const QuicServerId
& canonical_server_id
=
761 canonical_server_map_
[suffix_server_id
];
762 CachedState
* canonical_state
= cached_states_
[canonical_server_id
];
763 if (!canonical_state
->proof_valid()) {
767 // Update canonical version to point at the "most recent" entry.
768 canonical_server_map_
[suffix_server_id
] = server_id
;
770 server_state
->InitializeFrom(*canonical_state
);