Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(479)

Side by Side Diff: net/quic/crypto/quic_crypto_client_config.cc

Issue 2193073003: Move shared files in net/quic/ into net/quic/core/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: io_thread_unittest.cc Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "net/quic/crypto/quic_crypto_client_config.h"
6
7 #include <memory>
8
9 #include "base/metrics/histogram_macros.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "net/quic/crypto/cert_compressor.h"
13 #include "net/quic/crypto/chacha20_poly1305_encrypter.h"
14 #include "net/quic/crypto/channel_id.h"
15 #include "net/quic/crypto/common_cert_set.h"
16 #include "net/quic/crypto/crypto_framer.h"
17 #include "net/quic/crypto/crypto_utils.h"
18 #include "net/quic/crypto/curve25519_key_exchange.h"
19 #include "net/quic/crypto/key_exchange.h"
20 #include "net/quic/crypto/p256_key_exchange.h"
21 #include "net/quic/crypto/proof_verifier.h"
22 #include "net/quic/crypto/quic_encrypter.h"
23 #include "net/quic/crypto/quic_random.h"
24 #include "net/quic/quic_bug_tracker.h"
25 #include "net/quic/quic_flags.h"
26 #include "net/quic/quic_utils.h"
27
28 using base::StringPiece;
29 using std::map;
30 using std::string;
31 using std::queue;
32 using std::vector;
33
34 namespace net {
35
36 namespace {
37
38 // Tracks the reason (the state of the server config) for sending inchoate
39 // ClientHello to the server.
40 void RecordInchoateClientHelloReason(
41 QuicCryptoClientConfig::CachedState::ServerConfigState state) {
42 UMA_HISTOGRAM_ENUMERATION(
43 "Net.QuicInchoateClientHelloReason", state,
44 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
45 }
46
47 // Tracks the state of the QUIC server information loaded from the disk cache.
48 void RecordDiskCacheServerConfigState(
49 QuicCryptoClientConfig::CachedState::ServerConfigState state) {
50 UMA_HISTOGRAM_ENUMERATION(
51 "Net.QuicServerInfo.DiskCacheState", state,
52 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
53 }
54
55 } // namespace
56
57 QuicCryptoClientConfig::QuicCryptoClientConfig(
58 std::unique_ptr<ProofVerifier> proof_verifier)
59 : proof_verifier_(std::move(proof_verifier)), disable_ecdsa_(false) {
60 DCHECK(proof_verifier_.get());
61 SetDefaults();
62 }
63
64 QuicCryptoClientConfig::~QuicCryptoClientConfig() {
65 STLDeleteValues(&cached_states_);
66 }
67
68 QuicCryptoClientConfig::CachedState::CachedState()
69 : server_config_valid_(false), generation_counter_(0) {}
70
71 QuicCryptoClientConfig::CachedState::~CachedState() {}
72
73 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
74 if (server_config_.empty()) {
75 RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY);
76 return false;
77 }
78
79 if (!server_config_valid_) {
80 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID);
81 return false;
82 }
83
84 const CryptoHandshakeMessage* scfg = GetServerConfig();
85 if (!scfg) {
86 // Should be impossible short of cache corruption.
87 DCHECK(false);
88 RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
89 return false;
90 }
91
92 uint64_t expiry_seconds;
93 if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
94 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY);
95 return false;
96 }
97 if (now.ToUNIXSeconds() >= expiry_seconds) {
98 UMA_HISTOGRAM_CUSTOM_TIMES(
99 "Net.QuicClientHelloServerConfig.InvalidDuration",
100 base::TimeDelta::FromSeconds(now.ToUNIXSeconds() - expiry_seconds),
101 base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
102 RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED);
103 return false;
104 }
105
106 return true;
107 }
108
109 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
110 return server_config_.empty();
111 }
112
113 const CryptoHandshakeMessage*
114 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
115 if (server_config_.empty()) {
116 return nullptr;
117 }
118
119 if (!scfg_.get()) {
120 scfg_.reset(CryptoFramer::ParseMessage(server_config_));
121 DCHECK(scfg_.get());
122 }
123 return scfg_.get();
124 }
125
126 void QuicCryptoClientConfig::CachedState::add_server_designated_connection_id(
127 QuicConnectionId connection_id) {
128 server_designated_connection_ids_.push(connection_id);
129 }
130
131 bool QuicCryptoClientConfig::CachedState::has_server_designated_connection_id()
132 const {
133 return !server_designated_connection_ids_.empty();
134 }
135
136 void QuicCryptoClientConfig::CachedState::add_server_nonce(
137 const string& server_nonce) {
138 server_nonces_.push(server_nonce);
139 }
140
141 bool QuicCryptoClientConfig::CachedState::has_server_nonce() const {
142 return !server_nonces_.empty();
143 }
144
145 QuicCryptoClientConfig::CachedState::ServerConfigState
146 QuicCryptoClientConfig::CachedState::SetServerConfig(StringPiece server_config,
147 QuicWallTime now,
148 string* error_details) {
149 const bool matches_existing = server_config == server_config_;
150
151 // Even if the new server config matches the existing one, we still wish to
152 // reject it if it has expired.
153 std::unique_ptr<CryptoHandshakeMessage> new_scfg_storage;
154 const CryptoHandshakeMessage* new_scfg;
155
156 if (!matches_existing) {
157 new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config));
158 new_scfg = new_scfg_storage.get();
159 } else {
160 new_scfg = GetServerConfig();
161 }
162
163 if (!new_scfg) {
164 *error_details = "SCFG invalid";
165 return SERVER_CONFIG_INVALID;
166 }
167
168 uint64_t expiry_seconds;
169 if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
170 *error_details = "SCFG missing EXPY";
171 return SERVER_CONFIG_INVALID_EXPIRY;
172 }
173
174 if (now.ToUNIXSeconds() >= expiry_seconds) {
175 *error_details = "SCFG has expired";
176 return SERVER_CONFIG_EXPIRED;
177 }
178
179 if (!matches_existing) {
180 server_config_ = server_config.as_string();
181 SetProofInvalid();
182 scfg_.reset(new_scfg_storage.release());
183 }
184 return SERVER_CONFIG_VALID;
185 }
186
187 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
188 server_config_.clear();
189 scfg_.reset();
190 SetProofInvalid();
191 queue<QuicConnectionId> empty_queue;
192 swap(server_designated_connection_ids_, empty_queue);
193 }
194
195 void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
196 StringPiece cert_sct,
197 StringPiece chlo_hash,
198 StringPiece signature) {
199 bool has_changed = signature != server_config_sig_ ||
200 chlo_hash != chlo_hash_ || certs_.size() != certs.size();
201
202 if (!has_changed) {
203 for (size_t i = 0; i < certs_.size(); i++) {
204 if (certs_[i] != certs[i]) {
205 has_changed = true;
206 break;
207 }
208 }
209 }
210
211 if (!has_changed) {
212 return;
213 }
214
215 // If the proof has changed then it needs to be revalidated.
216 SetProofInvalid();
217 certs_ = certs;
218 cert_sct_ = cert_sct.as_string();
219 chlo_hash_ = chlo_hash.as_string();
220 server_config_sig_ = signature.as_string();
221 }
222
223 void QuicCryptoClientConfig::CachedState::Clear() {
224 server_config_.clear();
225 source_address_token_.clear();
226 certs_.clear();
227 cert_sct_.clear();
228 chlo_hash_.clear();
229 server_config_sig_.clear();
230 server_config_valid_ = false;
231 proof_verify_details_.reset();
232 scfg_.reset();
233 ++generation_counter_;
234 queue<QuicConnectionId> empty_queue;
235 swap(server_designated_connection_ids_, empty_queue);
236 }
237
238 void QuicCryptoClientConfig::CachedState::ClearProof() {
239 SetProofInvalid();
240 certs_.clear();
241 cert_sct_.clear();
242 chlo_hash_.clear();
243 server_config_sig_.clear();
244 }
245
246 void QuicCryptoClientConfig::CachedState::SetProofValid() {
247 server_config_valid_ = true;
248 }
249
250 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
251 server_config_valid_ = false;
252 ++generation_counter_;
253 }
254
255 bool QuicCryptoClientConfig::CachedState::Initialize(
256 StringPiece server_config,
257 StringPiece source_address_token,
258 const vector<string>& certs,
259 StringPiece cert_sct,
260 StringPiece chlo_hash,
261 StringPiece signature,
262 QuicWallTime now) {
263 DCHECK(server_config_.empty());
264
265 if (server_config.empty()) {
266 RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY);
267 return false;
268 }
269
270 string error_details;
271 ServerConfigState state = SetServerConfig(server_config, now, &error_details);
272 RecordDiskCacheServerConfigState(state);
273 if (state != SERVER_CONFIG_VALID) {
274 DVLOG(1) << "SetServerConfig failed with " << error_details;
275 return false;
276 }
277
278 signature.CopyToString(&server_config_sig_);
279 source_address_token.CopyToString(&source_address_token_);
280 cert_sct.CopyToString(&cert_sct_);
281 chlo_hash.CopyToString(&chlo_hash_);
282 certs_ = certs;
283 return true;
284 }
285
286 const string& QuicCryptoClientConfig::CachedState::server_config() const {
287 return server_config_;
288 }
289
290 const string& QuicCryptoClientConfig::CachedState::source_address_token()
291 const {
292 return source_address_token_;
293 }
294
295 const vector<string>& QuicCryptoClientConfig::CachedState::certs() const {
296 return certs_;
297 }
298
299 const string& QuicCryptoClientConfig::CachedState::cert_sct() const {
300 return cert_sct_;
301 }
302
303 const string& QuicCryptoClientConfig::CachedState::chlo_hash() const {
304 return chlo_hash_;
305 }
306
307 const string& QuicCryptoClientConfig::CachedState::signature() const {
308 return server_config_sig_;
309 }
310
311 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
312 return server_config_valid_;
313 }
314
315 uint64_t QuicCryptoClientConfig::CachedState::generation_counter() const {
316 return generation_counter_;
317 }
318
319 const ProofVerifyDetails*
320 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
321 return proof_verify_details_.get();
322 }
323
324 void QuicCryptoClientConfig::CachedState::set_source_address_token(
325 StringPiece token) {
326 source_address_token_ = token.as_string();
327 }
328
329 void QuicCryptoClientConfig::CachedState::set_cert_sct(StringPiece cert_sct) {
330 cert_sct_ = cert_sct.as_string();
331 }
332
333 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
334 ProofVerifyDetails* details) {
335 proof_verify_details_.reset(details);
336 }
337
338 void QuicCryptoClientConfig::CachedState::InitializeFrom(
339 const QuicCryptoClientConfig::CachedState& other) {
340 DCHECK(server_config_.empty());
341 DCHECK(!server_config_valid_);
342 server_config_ = other.server_config_;
343 source_address_token_ = other.source_address_token_;
344 certs_ = other.certs_;
345 cert_sct_ = other.cert_sct_;
346 chlo_hash_ = other.chlo_hash_;
347 server_config_sig_ = other.server_config_sig_;
348 server_config_valid_ = other.server_config_valid_;
349 server_designated_connection_ids_ = other.server_designated_connection_ids_;
350 if (other.proof_verify_details_.get() != nullptr) {
351 proof_verify_details_.reset(other.proof_verify_details_->Clone());
352 }
353 ++generation_counter_;
354 }
355
356 QuicConnectionId
357 QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() {
358 if (server_designated_connection_ids_.empty()) {
359 QUIC_BUG
360 << "Attempting to consume a connection id that was never designated.";
361 return 0;
362 }
363 const QuicConnectionId next_id = server_designated_connection_ids_.front();
364 server_designated_connection_ids_.pop();
365 return next_id;
366 }
367
368 string QuicCryptoClientConfig::CachedState::GetNextServerNonce() {
369 if (server_nonces_.empty()) {
370 QUIC_BUG
371 << "Attempting to consume a server nonce that was never designated.";
372 return "";
373 }
374 const string server_nonce = server_nonces_.front();
375 server_nonces_.pop();
376 return server_nonce;
377 }
378
379 void QuicCryptoClientConfig::SetDefaults() {
380 // Key exchange methods.
381 kexs = {kC255, kP256};
382
383 // Authenticated encryption algorithms. Prefer RFC 7539 ChaCha20 by default.
384 aead = {kCC20, kAESG};
385
386 disable_ecdsa_ = false;
387 }
388
389 QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate(
390 const QuicServerId& server_id) {
391 CachedStateMap::const_iterator it = cached_states_.find(server_id);
392 if (it != cached_states_.end()) {
393 return it->second;
394 }
395
396 CachedState* cached = new CachedState;
397 cached_states_.insert(std::make_pair(server_id, cached));
398 bool cache_populated = PopulateFromCanonicalConfig(server_id, cached);
399 UMA_HISTOGRAM_BOOLEAN(
400 "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig",
401 cache_populated);
402 return cached;
403 }
404
405 void QuicCryptoClientConfig::ClearCachedStates() {
406 for (CachedStateMap::const_iterator it = cached_states_.begin();
407 it != cached_states_.end(); ++it) {
408 it->second->Clear();
409 }
410 }
411
412 void QuicCryptoClientConfig::FillInchoateClientHello(
413 const QuicServerId& server_id,
414 const QuicVersion preferred_version,
415 const CachedState* cached,
416 QuicRandom* rand,
417 bool demand_x509_proof,
418 QuicCryptoNegotiatedParameters* out_params,
419 CryptoHandshakeMessage* out) const {
420 out->set_tag(kCHLO);
421 out->set_minimum_size(kClientHelloMinimumSize);
422
423 // Server name indication. We only send SNI if it's a valid domain name, as
424 // per the spec.
425 if (CryptoUtils::IsValidSNI(server_id.host())) {
426 out->SetStringPiece(kSNI, server_id.host());
427 }
428 out->SetValue(kVER, QuicVersionToQuicTag(preferred_version));
429
430 if (!user_agent_id_.empty()) {
431 out->SetStringPiece(kUAID, user_agent_id_);
432 }
433
434 // Even though this is an inchoate CHLO, send the SCID so that
435 // the STK can be validated by the server.
436 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
437 if (scfg != nullptr) {
438 StringPiece scid;
439 if (scfg->GetStringPiece(kSCID, &scid)) {
440 out->SetStringPiece(kSCID, scid);
441 }
442 }
443
444 if (!cached->source_address_token().empty()) {
445 out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
446 }
447
448 if (!demand_x509_proof) {
449 return;
450 }
451
452 char proof_nonce[32];
453 rand->RandBytes(proof_nonce, arraysize(proof_nonce));
454 out->SetStringPiece(kNONP, StringPiece(proof_nonce, arraysize(proof_nonce)));
455
456 if (disable_ecdsa_) {
457 out->SetVector(kPDMD, QuicTagVector{kX59R});
458 } else {
459 out->SetVector(kPDMD, QuicTagVector{kX509});
460 }
461
462 if (common_cert_sets) {
463 out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
464 }
465
466 out->SetStringPiece(kCertificateSCTTag, "");
467
468 const vector<string>& certs = cached->certs();
469 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
470 // client config is being used for multiple connections, another connection
471 // doesn't update the cached certificates and cause us to be unable to
472 // process the server's compressed certificate chain.
473 out_params->cached_certs = certs;
474 if (!certs.empty()) {
475 vector<uint64_t> hashes;
476 hashes.reserve(certs.size());
477 for (vector<string>::const_iterator i = certs.begin(); i != certs.end();
478 ++i) {
479 hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
480 }
481 out->SetVector(kCCRT, hashes);
482 }
483 }
484
485 QuicErrorCode QuicCryptoClientConfig::FillClientHello(
486 const QuicServerId& server_id,
487 QuicConnectionId connection_id,
488 const QuicVersion actual_version,
489 const QuicVersion preferred_version,
490 const CachedState* cached,
491 QuicWallTime now,
492 QuicRandom* rand,
493 const ChannelIDKey* channel_id_key,
494 QuicCryptoNegotiatedParameters* out_params,
495 CryptoHandshakeMessage* out,
496 string* error_details) const {
497 DCHECK(error_details != nullptr);
498
499 FillInchoateClientHello(server_id, preferred_version, cached, rand,
500 /* demand_x509_proof= */ true, out_params, out);
501
502 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
503 if (!scfg) {
504 // This should never happen as our caller should have checked
505 // cached->IsComplete() before calling this function.
506 *error_details = "Handshake not ready";
507 return QUIC_CRYPTO_INTERNAL_ERROR;
508 }
509
510 StringPiece scid;
511 if (!scfg->GetStringPiece(kSCID, &scid)) {
512 *error_details = "SCFG missing SCID";
513 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
514 }
515 out->SetStringPiece(kSCID, scid);
516
517 out->SetStringPiece(kCertificateSCTTag, "");
518
519 const QuicTag* their_aeads;
520 const QuicTag* their_key_exchanges;
521 size_t num_their_aeads, num_their_key_exchanges;
522 if (scfg->GetTaglist(kAEAD, &their_aeads, &num_their_aeads) !=
523 QUIC_NO_ERROR ||
524 scfg->GetTaglist(kKEXS, &their_key_exchanges, &num_their_key_exchanges) !=
525 QUIC_NO_ERROR) {
526 *error_details = "Missing AEAD or KEXS";
527 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
528 }
529
530 // AEAD: the work loads on the client and server are symmetric. Since the
531 // client is more likely to be CPU-constrained, break the tie by favoring
532 // the client's preference.
533 // Key exchange: the client does more work than the server, so favor the
534 // client's preference.
535 size_t key_exchange_index;
536 if (!QuicUtils::FindMutualTag(aead, their_aeads, num_their_aeads,
537 QuicUtils::LOCAL_PRIORITY, &out_params->aead,
538 nullptr) ||
539 !QuicUtils::FindMutualTag(
540 kexs, their_key_exchanges, num_their_key_exchanges,
541 QuicUtils::LOCAL_PRIORITY, &out_params->key_exchange,
542 &key_exchange_index)) {
543 *error_details = "Unsupported AEAD or KEXS";
544 return QUIC_CRYPTO_NO_SUPPORT;
545 }
546 out->SetVector(kAEAD, QuicTagVector{out_params->aead});
547 out->SetVector(kKEXS, QuicTagVector{out_params->key_exchange});
548
549 if (!tb_key_params.empty()) {
550 const QuicTag* their_tbkps;
551 size_t num_their_tbkps;
552 switch (scfg->GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) {
553 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
554 break;
555 case QUIC_NO_ERROR:
556 if (QuicUtils::FindMutualTag(tb_key_params, their_tbkps,
557 num_their_tbkps, QuicUtils::LOCAL_PRIORITY,
558 &out_params->token_binding_key_param,
559 nullptr)) {
560 out->SetVector(kTBKP,
561 QuicTagVector{out_params->token_binding_key_param});
562 }
563 break;
564 default:
565 *error_details = "Invalid TBKP";
566 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
567 }
568 }
569
570 StringPiece public_value;
571 if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
572 QUIC_NO_ERROR) {
573 *error_details = "Missing public value";
574 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
575 }
576
577 StringPiece orbit;
578 if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) {
579 *error_details = "SCFG missing OBIT";
580 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
581 }
582
583 CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce);
584 out->SetStringPiece(kNONC, out_params->client_nonce);
585 if (!out_params->server_nonce.empty()) {
586 out->SetStringPiece(kServerNonceTag, out_params->server_nonce);
587 }
588
589 switch (out_params->key_exchange) {
590 case kC255:
591 out_params->client_key_exchange.reset(Curve25519KeyExchange::New(
592 Curve25519KeyExchange::NewPrivateKey(rand)));
593 break;
594 case kP256:
595 out_params->client_key_exchange.reset(
596 P256KeyExchange::New(P256KeyExchange::NewPrivateKey()));
597 break;
598 default:
599 DCHECK(false);
600 *error_details = "Configured to support an unknown key exchange";
601 return QUIC_CRYPTO_INTERNAL_ERROR;
602 }
603
604 if (!out_params->client_key_exchange->CalculateSharedKey(
605 public_value, &out_params->initial_premaster_secret)) {
606 *error_details = "Key exchange failure";
607 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
608 }
609 out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
610
611 const vector<string>& certs = cached->certs();
612 if (certs.empty()) {
613 *error_details = "No certs to calculate XLCT";
614 return QUIC_CRYPTO_INTERNAL_ERROR;
615 }
616 out->SetValue(kXLCT, CryptoUtils::ComputeLeafCertHash(certs[0]));
617
618 if (channel_id_key) {
619 // In order to calculate the encryption key for the CETV block we need to
620 // serialise the client hello as it currently is (i.e. without the CETV
621 // block). For this, the client hello is serialized without padding.
622 const size_t orig_min_size = out->minimum_size();
623 out->set_minimum_size(0);
624
625 CryptoHandshakeMessage cetv;
626 cetv.set_tag(kCETV);
627
628 string hkdf_input;
629 const QuicData& client_hello_serialized = out->GetSerialized();
630 hkdf_input.append(QuicCryptoConfig::kCETVLabel,
631 strlen(QuicCryptoConfig::kCETVLabel) + 1);
632 hkdf_input.append(reinterpret_cast<char*>(&connection_id),
633 sizeof(connection_id));
634 hkdf_input.append(client_hello_serialized.data(),
635 client_hello_serialized.length());
636 hkdf_input.append(cached->server_config());
637
638 string key = channel_id_key->SerializeKey();
639 string signature;
640 if (!channel_id_key->Sign(hkdf_input, &signature)) {
641 *error_details = "Channel ID signature failed";
642 return QUIC_INVALID_CHANNEL_ID_SIGNATURE;
643 }
644
645 cetv.SetStringPiece(kCIDK, key);
646 cetv.SetStringPiece(kCIDS, signature);
647
648 CrypterPair crypters;
649 if (!CryptoUtils::DeriveKeys(
650 out_params->initial_premaster_secret, out_params->aead,
651 out_params->client_nonce, out_params->server_nonce, hkdf_input,
652 Perspective::IS_CLIENT, CryptoUtils::Diversification::Never(),
653 &crypters, nullptr /* subkey secret */)) {
654 *error_details = "Symmetric key setup failed";
655 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
656 }
657
658 const QuicData& cetv_plaintext = cetv.GetSerialized();
659 const size_t encrypted_len =
660 crypters.encrypter->GetCiphertextSize(cetv_plaintext.length());
661 std::unique_ptr<char[]> output(new char[encrypted_len]);
662 size_t output_size = 0;
663 if (!crypters.encrypter->EncryptPacket(
664 kDefaultPathId /* path id */, 0 /* packet number */,
665 StringPiece() /* associated data */, cetv_plaintext.AsStringPiece(),
666 output.get(), &output_size, encrypted_len)) {
667 *error_details = "Packet encryption failed";
668 return QUIC_ENCRYPTION_FAILURE;
669 }
670
671 out->SetStringPiece(kCETV, StringPiece(output.get(), output_size));
672 out->MarkDirty();
673
674 out->set_minimum_size(orig_min_size);
675 }
676
677 // Derive the symmetric keys and set up the encrypters and decrypters.
678 // Set the following members of out_params:
679 // out_params->hkdf_input_suffix
680 // out_params->initial_crypters
681 out_params->hkdf_input_suffix.clear();
682 out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&connection_id),
683 sizeof(connection_id));
684 const QuicData& client_hello_serialized = out->GetSerialized();
685 out_params->hkdf_input_suffix.append(client_hello_serialized.data(),
686 client_hello_serialized.length());
687 out_params->hkdf_input_suffix.append(cached->server_config());
688 if (certs.empty()) {
689 *error_details = "No certs found to include in KDF";
690 return QUIC_CRYPTO_INTERNAL_ERROR;
691 }
692 out_params->hkdf_input_suffix.append(certs[0]);
693
694 string hkdf_input;
695 const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
696 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
697 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
698 hkdf_input.append(out_params->hkdf_input_suffix);
699
700 string* subkey_secret = &out_params->initial_subkey_secret;
701
702 // Only perform key diversification for QUIC versions 33 and later.
703 // TODO(rch): remove the |actual_version| argument to this method when
704 // QUIC_VERSION_32 is removed.
705 CryptoUtils::Diversification diversification =
706 actual_version > QUIC_VERSION_32 ? CryptoUtils::Diversification::Pending()
707 : CryptoUtils::Diversification::Never();
708 if (!CryptoUtils::DeriveKeys(out_params->initial_premaster_secret,
709 out_params->aead, out_params->client_nonce,
710 out_params->server_nonce, hkdf_input,
711 Perspective::IS_CLIENT, diversification,
712 &out_params->initial_crypters, subkey_secret)) {
713 *error_details = "Symmetric key setup failed";
714 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
715 }
716
717 return QUIC_NO_ERROR;
718 }
719
720 QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig(
721 const CryptoHandshakeMessage& message,
722 QuicWallTime now,
723 QuicVersion version,
724 StringPiece chlo_hash,
725 const vector<string>& cached_certs,
726 CachedState* cached,
727 string* error_details) {
728 DCHECK(error_details != nullptr);
729
730 StringPiece scfg;
731 if (!message.GetStringPiece(kSCFG, &scfg)) {
732 *error_details = "Missing SCFG";
733 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
734 }
735
736 CachedState::ServerConfigState state =
737 cached->SetServerConfig(scfg, now, error_details);
738 if (state == CachedState::SERVER_CONFIG_EXPIRED) {
739 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
740 }
741 // TODO(rtenneti): Return more specific error code than returning
742 // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
743 if (state != CachedState::SERVER_CONFIG_VALID) {
744 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
745 }
746
747 StringPiece token;
748 if (message.GetStringPiece(kSourceAddressTokenTag, &token)) {
749 cached->set_source_address_token(token);
750 }
751
752 StringPiece proof, cert_bytes, cert_sct;
753 bool has_proof = message.GetStringPiece(kPROF, &proof);
754 bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes);
755 if (has_proof && has_cert) {
756 vector<string> certs;
757 if (!CertCompressor::DecompressChain(cert_bytes, cached_certs,
758 common_cert_sets, &certs)) {
759 *error_details = "Certificate data invalid";
760 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
761 }
762
763 message.GetStringPiece(kCertificateSCTTag, &cert_sct);
764 cached->SetProof(certs, cert_sct, chlo_hash, proof);
765 } else {
766 // Secure QUIC: clear existing proof as we have been sent a new SCFG
767 // without matching proof/certs.
768 cached->ClearProof();
769
770 if (has_proof && !has_cert) {
771 *error_details = "Certificate missing";
772 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
773 }
774
775 if (!has_proof && has_cert) {
776 *error_details = "Proof missing";
777 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
778 }
779 }
780
781 return QUIC_NO_ERROR;
782 }
783
784 QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
785 const CryptoHandshakeMessage& rej,
786 QuicWallTime now,
787 const QuicVersion version,
788 StringPiece chlo_hash,
789 CachedState* cached,
790 QuicCryptoNegotiatedParameters* out_params,
791 string* error_details) {
792 DCHECK(error_details != nullptr);
793
794 if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) {
795 *error_details = "Message is not REJ or SREJ";
796 return QUIC_CRYPTO_INTERNAL_ERROR;
797 }
798
799 QuicErrorCode error =
800 CacheNewServerConfig(rej, now, version, chlo_hash,
801 out_params->cached_certs, cached, error_details);
802 if (error != QUIC_NO_ERROR) {
803 return error;
804 }
805
806 StringPiece nonce;
807 if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
808 out_params->server_nonce = nonce.as_string();
809 }
810
811 if (rej.tag() == kSREJ) {
812 QuicConnectionId connection_id;
813 if (rej.GetUint64(kRCID, &connection_id) != QUIC_NO_ERROR) {
814 *error_details = "Missing kRCID";
815 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
816 }
817 cached->add_server_designated_connection_id(connection_id);
818 if (!nonce.empty()) {
819 cached->add_server_nonce(nonce.as_string());
820 }
821 return QUIC_NO_ERROR;
822 }
823
824 return QUIC_NO_ERROR;
825 }
826
827 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
828 const CryptoHandshakeMessage& server_hello,
829 QuicConnectionId connection_id,
830 QuicVersion version,
831 const QuicVersionVector& negotiated_versions,
832 CachedState* cached,
833 QuicCryptoNegotiatedParameters* out_params,
834 string* error_details) {
835 DCHECK(error_details != nullptr);
836
837 QuicErrorCode valid = CryptoUtils::ValidateServerHello(
838 server_hello, negotiated_versions, error_details);
839 if (valid != QUIC_NO_ERROR) {
840 return valid;
841 }
842
843 // Learn about updated source address tokens.
844 StringPiece token;
845 if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) {
846 cached->set_source_address_token(token);
847 }
848
849 StringPiece shlo_nonce;
850 if (!server_hello.GetStringPiece(kServerNonceTag, &shlo_nonce)) {
851 *error_details = "server hello missing server nonce";
852 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
853 }
854
855 // TODO(agl):
856 // learn about updated SCFGs.
857
858 StringPiece public_value;
859 if (!server_hello.GetStringPiece(kPUBS, &public_value)) {
860 *error_details = "server hello missing forward secure public value";
861 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
862 }
863
864 if (!out_params->client_key_exchange->CalculateSharedKey(
865 public_value, &out_params->forward_secure_premaster_secret)) {
866 *error_details = "Key exchange failure";
867 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
868 }
869
870 string hkdf_input;
871 const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
872 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
873 hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
874 hkdf_input.append(out_params->hkdf_input_suffix);
875
876 if (!CryptoUtils::DeriveKeys(
877 out_params->forward_secure_premaster_secret, out_params->aead,
878 out_params->client_nonce,
879 shlo_nonce.empty() ? out_params->server_nonce : shlo_nonce,
880 hkdf_input, Perspective::IS_CLIENT,
881 CryptoUtils::Diversification::Never(),
882 &out_params->forward_secure_crypters, &out_params->subkey_secret)) {
883 *error_details = "Symmetric key setup failed";
884 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
885 }
886
887 return QUIC_NO_ERROR;
888 }
889
890 QuicErrorCode QuicCryptoClientConfig::ProcessServerConfigUpdate(
891 const CryptoHandshakeMessage& server_config_update,
892 QuicWallTime now,
893 const QuicVersion version,
894 StringPiece chlo_hash,
895 CachedState* cached,
896 QuicCryptoNegotiatedParameters* out_params,
897 string* error_details) {
898 DCHECK(error_details != nullptr);
899
900 if (server_config_update.tag() != kSCUP) {
901 *error_details = "ServerConfigUpdate must have kSCUP tag.";
902 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
903 }
904 return CacheNewServerConfig(server_config_update, now, version, chlo_hash,
905 out_params->cached_certs, cached, error_details);
906 }
907
908 ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
909 return proof_verifier_.get();
910 }
911
912 ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const {
913 return channel_id_source_.get();
914 }
915
916 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) {
917 channel_id_source_.reset(source);
918 }
919
920 void QuicCryptoClientConfig::InitializeFrom(
921 const QuicServerId& server_id,
922 const QuicServerId& canonical_server_id,
923 QuicCryptoClientConfig* canonical_crypto_config) {
924 CachedState* canonical_cached =
925 canonical_crypto_config->LookupOrCreate(canonical_server_id);
926 if (!canonical_cached->proof_valid()) {
927 return;
928 }
929 CachedState* cached = LookupOrCreate(server_id);
930 cached->InitializeFrom(*canonical_cached);
931 }
932
933 void QuicCryptoClientConfig::AddCanonicalSuffix(const string& suffix) {
934 canonical_suffixes_.push_back(suffix);
935 }
936
937 void QuicCryptoClientConfig::PreferAesGcm() {
938 DCHECK(!aead.empty());
939 if (aead.size() <= 1) {
940 return;
941 }
942 QuicTagVector::iterator pos = std::find(aead.begin(), aead.end(), kAESG);
943 if (pos != aead.end()) {
944 aead.erase(pos);
945 aead.insert(aead.begin(), kAESG);
946 }
947 }
948
949 void QuicCryptoClientConfig::DisableEcdsa() {
950 disable_ecdsa_ = true;
951 }
952
953 bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
954 const QuicServerId& server_id,
955 CachedState* server_state) {
956 DCHECK(server_state->IsEmpty());
957 size_t i = 0;
958 for (; i < canonical_suffixes_.size(); ++i) {
959 if (base::EndsWith(server_id.host(), canonical_suffixes_[i],
960 base::CompareCase::INSENSITIVE_ASCII)) {
961 break;
962 }
963 }
964 if (i == canonical_suffixes_.size()) {
965 return false;
966 }
967
968 QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
969 server_id.privacy_mode());
970 if (!ContainsKey(canonical_server_map_, suffix_server_id)) {
971 // This is the first host we've seen which matches the suffix, so make it
972 // canonical.
973 canonical_server_map_[suffix_server_id] = server_id;
974 return false;
975 }
976
977 const QuicServerId& canonical_server_id =
978 canonical_server_map_[suffix_server_id];
979 CachedState* canonical_state = cached_states_[canonical_server_id];
980 if (!canonical_state->proof_valid()) {
981 return false;
982 }
983
984 // Update canonical version to point at the "most recent" entry.
985 canonical_server_map_[suffix_server_id] = server_id;
986
987 server_state->InitializeFrom(*canonical_state);
988 return true;
989 }
990
991 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/crypto/quic_crypto_client_config.h ('k') | net/quic/crypto/quic_crypto_client_config_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698