Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / quic / crypto / quic_crypto_client_config.cc
blob13a8bb8fada9501e887d5ee289c925c924b5e522
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;
25 using std::map;
26 using std::string;
27 using std::queue;
28 using std::vector;
30 namespace net {
32 namespace {
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);
51 } // namespace
53 QuicCryptoClientConfig::QuicCryptoClientConfig()
54 : disable_ecdsa_(false) {
55 SetDefaults();
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);
71 return false;
74 if (!server_config_valid_) {
75 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID);
76 return false;
79 const CryptoHandshakeMessage* scfg = GetServerConfig();
80 if (!scfg) {
81 // Should be impossible short of cache corruption.
82 DCHECK(false);
83 RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
84 return false;
87 uint64 expiry_seconds;
88 if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
89 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY);
90 return false;
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);
98 return false;
101 return true;
104 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
105 return server_config_.empty();
108 const CryptoHandshakeMessage*
109 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
110 if (server_config_.empty()) {
111 return nullptr;
114 if (!scfg_.get()) {
115 scfg_.reset(CryptoFramer::ParseMessage(server_config_));
116 DCHECK(scfg_.get());
118 return scfg_.get();
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()
127 const {
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();
153 } else {
154 new_scfg = GetServerConfig();
157 if (!new_scfg) {
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();
175 SetProofInvalid();
176 scfg_.reset(new_scfg_storage.release());
178 return SERVER_CONFIG_VALID;
181 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
182 server_config_.clear();
183 scfg_.reset();
184 SetProofInvalid();
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) {
191 bool has_changed =
192 signature != server_config_sig_ || certs_.size() != certs.size();
194 if (!has_changed) {
195 for (size_t i = 0; i < certs_.size(); i++) {
196 if (certs_[i] != certs[i]) {
197 has_changed = true;
198 break;
203 if (!has_changed) {
204 return;
207 // If the proof has changed then it needs to be revalidated.
208 SetProofInvalid();
209 certs_ = certs;
210 server_config_sig_ = signature.as_string();
213 void QuicCryptoClientConfig::CachedState::Clear() {
214 server_config_.clear();
215 source_address_token_.clear();
216 certs_.clear();
217 server_config_sig_.clear();
218 server_config_valid_ = false;
219 proof_verify_details_.reset();
220 scfg_.reset();
221 ++generation_counter_;
222 queue<QuicConnectionId> empty_queue;
223 swap(server_designated_connection_ids_, empty_queue);
226 void QuicCryptoClientConfig::CachedState::ClearProof() {
227 SetProofInvalid();
228 certs_.clear();
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,
246 QuicWallTime now) {
247 DCHECK(server_config_.empty());
249 if (server_config.empty()) {
250 RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY);
251 return false;
254 string error_details;
255 ServerConfigState state = SetServerConfig(server_config, now,
256 &error_details);
257 RecordDiskCacheServerConfigState(state);
258 if (state != SERVER_CONFIG_VALID) {
259 DVLOG(1) << "SetServerConfig failed with " << error_details;
260 return false;
263 signature.CopyToString(&server_config_sig_);
264 source_address_token.CopyToString(&source_address_token_);
265 certs_ = certs;
266 return true;
269 const string& QuicCryptoClientConfig::CachedState::server_config() const {
270 return server_config_;
273 const string&
274 QuicCryptoClientConfig::CachedState::source_address_token() const {
275 return source_address_token_;
278 const vector<string>& QuicCryptoClientConfig::CachedState::certs() const {
279 return certs_;
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(
300 StringPiece 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_;
325 QuicConnectionId
326 QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() {
327 if (server_designated_connection_ids_.empty()) {
328 LOG(DFATAL)
329 << "Attempting to consume a connection id that was never designated.";
330 return 0;
332 const QuicConnectionId next_id = server_designated_connection_ids_.front();
333 server_designated_connection_ids_.pop();
334 return next_id;
337 string QuicCryptoClientConfig::CachedState::GetNextServerNonce() {
338 if (server_nonces_.empty()) {
339 LOG(DFATAL)
340 << "Attempting to consume a server nonce that was never designated.";
341 return "";
343 const string server_nonce = server_nonces_.front();
344 server_nonces_.pop();
345 return server_nonce;
348 void QuicCryptoClientConfig::SetDefaults() {
349 // Key exchange methods.
350 kexs.resize(2);
351 kexs[0] = kC255;
352 kexs[1] = kP256;
354 // Authenticated encryption algorithms. Prefer ChaCha20 by default.
355 aead.clear();
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()) {
368 return it->second;
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",
376 cache_populated);
377 return cached;
380 void QuicCryptoClientConfig::ClearCachedStates() {
381 for (CachedStateMap::const_iterator it = cached_states_.begin();
382 it != cached_states_.end(); ++it) {
383 it->second->Clear();
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 {
393 out->set_tag(kCHLO);
394 out->set_minimum_size(kClientHelloMinimumSize);
396 // Server name indication. We only send SNI if it's a valid domain name, as
397 // per the spec.
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);
414 } else {
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,
445 QuicWallTime now,
446 QuicRandom* rand,
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,
454 out_params, out);
456 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
457 if (!scfg) {
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;
464 StringPiece scid;
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) !=
503 QUIC_NO_ERROR) {
504 *error_details = "Missing public value";
505 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
508 StringPiece orbit;
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) {
521 case kC255:
522 out_params->client_key_exchange.reset(Curve25519KeyExchange::New(
523 Curve25519KeyExchange::NewPrivateKey(rand)));
524 break;
525 case kP256:
526 out_params->client_key_exchange.reset(P256KeyExchange::New(
527 P256KeyExchange::NewPrivateKey()));
528 break;
529 default:
530 DCHECK(false);
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;
550 cetv.set_tag(kCETV);
552 string hkdf_input;
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();
563 string signature;
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,
589 encrypted_len)) {
590 *error_details = "Packet encryption failed";
591 return QUIC_ENCRYPTION_FAILURE;
594 out->SetStringPiece(kCETV, StringPiece(output.get(), output_size));
595 out->MarkDirty();
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());
612 string hkdf_input;
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,
632 QuicWallTime now,
633 const vector<string>& cached_certs,
634 CachedState* cached,
635 string* error_details) {
636 DCHECK(error_details != nullptr);
638 StringPiece scfg;
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;
655 StringPiece token;
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);
672 } else {
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,
695 QuicWallTime now,
696 CachedState* cached,
697 bool is_https,
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) {
710 return error;
713 StringPiece nonce;
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) {
727 continue;
729 HandshakeFailureReason reason =
730 static_cast<HandshakeFailureReason>(reject_reasons[i]);
731 packed_error |= 1 << (reason - 1);
733 DVLOG(1) << "Reasons for rejection: " << packed_error;
734 if (is_https) {
735 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
736 packed_error);
737 } else {
738 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Insecure",
739 packed_error);
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,
763 CachedState* cached,
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.
790 if (mismatch) {
791 *error_details = "Downgrade attack detected";
792 return QUIC_VERSION_NEGOTIATION_MISMATCH;
796 // Learn about updated source address tokens.
797 StringPiece token;
798 if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) {
799 cached->set_source_address_token(token);
802 // TODO(agl):
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;
817 string hkdf_input;
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,
837 QuicWallTime now,
838 CachedState* cached,
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()) {
875 return;
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) {
888 return;
890 QuicTagVector::iterator pos = std::find(aead.begin(), aead.end(), kAESG);
891 if (pos != aead.end()) {
892 aead.erase(pos);
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());
905 size_t i = 0;
906 for (; i < canonical_suffixes_.size(); ++i) {
907 if (base::EndsWith(server_id.host(), canonical_suffixes_[i],
908 base::CompareCase::INSENSITIVE_ASCII)) {
909 break;
912 if (i == canonical_suffixes_.size()) {
913 return false;
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
921 // canonical.
922 canonical_server_map_[suffix_server_id] = server_id;
923 return false;
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()) {
930 return false;
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);
937 return true;
940 } // namespace net