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 "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"
21
22 using base::StringPiece;
23 using std::find;
24 using std::make_pair;
25 using std::map;
26 using std::string;
27 using std::vector;
28
29 namespace net {
30
QuicCryptoClientConfig()31 QuicCryptoClientConfig::QuicCryptoClientConfig()
32 : disable_ecdsa_(false) {}
33
~QuicCryptoClientConfig()34 QuicCryptoClientConfig::~QuicCryptoClientConfig() {
35 STLDeleteValues(&cached_states_);
36 }
37
CachedState()38 QuicCryptoClientConfig::CachedState::CachedState()
39 : server_config_valid_(false),
40 generation_counter_(0) {}
41
~CachedState()42 QuicCryptoClientConfig::CachedState::~CachedState() {}
43
IsComplete(QuicWallTime now) const44 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
45 if (server_config_.empty() || !server_config_valid_) {
46 return false;
47 }
48
49 const CryptoHandshakeMessage* scfg = GetServerConfig();
50 if (!scfg) {
51 // Should be impossible short of cache corruption.
52 DCHECK(false);
53 return false;
54 }
55
56 uint64 expiry_seconds;
57 if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR ||
58 now.ToUNIXSeconds() >= expiry_seconds) {
59 return false;
60 }
61
62 return true;
63 }
64
IsEmpty() const65 bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
66 return server_config_.empty();
67 }
68
69 const CryptoHandshakeMessage*
GetServerConfig() const70 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
71 if (server_config_.empty()) {
72 return NULL;
73 }
74
75 if (!scfg_.get()) {
76 scfg_.reset(CryptoFramer::ParseMessage(server_config_));
77 DCHECK(scfg_.get());
78 }
79 return scfg_.get();
80 }
81
SetServerConfig(StringPiece server_config,QuicWallTime now,string * error_details)82 QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig(
83 StringPiece server_config, QuicWallTime now, string* error_details) {
84 const bool matches_existing = server_config == server_config_;
85
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;
90
91 if (!matches_existing) {
92 new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config));
93 new_scfg = new_scfg_storage.get();
94 } else {
95 new_scfg = GetServerConfig();
96 }
97
98 if (!new_scfg) {
99 *error_details = "SCFG invalid";
100 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
101 }
102
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;
107 }
108
109 if (now.ToUNIXSeconds() >= expiry_seconds) {
110 *error_details = "SCFG has expired";
111 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
112 }
113
114 if (!matches_existing) {
115 server_config_ = server_config.as_string();
116 SetProofInvalid();
117 scfg_.reset(new_scfg_storage.release());
118 }
119 return QUIC_NO_ERROR;
120 }
121
InvalidateServerConfig()122 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
123 server_config_.clear();
124 scfg_.reset();
125 SetProofInvalid();
126 }
127
SetProof(const vector<string> & certs,StringPiece signature)128 void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
129 StringPiece signature) {
130 bool has_changed =
131 signature != server_config_sig_ || certs_.size() != certs.size();
132
133 if (!has_changed) {
134 for (size_t i = 0; i < certs_.size(); i++) {
135 if (certs_[i] != certs[i]) {
136 has_changed = true;
137 break;
138 }
139 }
140 }
141
142 if (!has_changed) {
143 return;
144 }
145
146 // If the proof has changed then it needs to be revalidated.
147 SetProofInvalid();
148 certs_ = certs;
149 server_config_sig_ = signature.as_string();
150 }
151
Clear()152 void QuicCryptoClientConfig::CachedState::Clear() {
153 server_config_.clear();
154 source_address_token_.clear();
155 certs_.clear();
156 server_config_sig_.clear();
157 server_config_valid_ = false;
158 proof_verify_details_.reset();
159 scfg_.reset();
160 ++generation_counter_;
161 }
162
ClearProof()163 void QuicCryptoClientConfig::CachedState::ClearProof() {
164 SetProofInvalid();
165 certs_.clear();
166 server_config_sig_.clear();
167 }
168
SetProofValid()169 void QuicCryptoClientConfig::CachedState::SetProofValid() {
170 server_config_valid_ = true;
171 }
172
SetProofInvalid()173 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
174 server_config_valid_ = false;
175 ++generation_counter_;
176 }
177
Initialize(StringPiece server_config,StringPiece source_address_token,const vector<string> & certs,StringPiece signature,QuicWallTime now)178 bool QuicCryptoClientConfig::CachedState::Initialize(
179 StringPiece server_config,
180 StringPiece source_address_token,
181 const vector<string>& certs,
182 StringPiece signature,
183 QuicWallTime now) {
184 DCHECK(server_config_.empty());
185
186 if (server_config.empty()) {
187 return false;
188 }
189
190 string error_details;
191 QuicErrorCode error = SetServerConfig(server_config, now,
192 &error_details);
193 if (error != QUIC_NO_ERROR) {
194 DVLOG(1) << "SetServerConfig failed with " << error_details;
195 return false;
196 }
197
198 signature.CopyToString(&server_config_sig_);
199 source_address_token.CopyToString(&source_address_token_);
200 certs_ = certs;
201 return true;
202 }
203
server_config() const204 const string& QuicCryptoClientConfig::CachedState::server_config() const {
205 return server_config_;
206 }
207
208 const string&
source_address_token() const209 QuicCryptoClientConfig::CachedState::source_address_token() const {
210 return source_address_token_;
211 }
212
certs() const213 const vector<string>& QuicCryptoClientConfig::CachedState::certs() const {
214 return certs_;
215 }
216
signature() const217 const string& QuicCryptoClientConfig::CachedState::signature() const {
218 return server_config_sig_;
219 }
220
proof_valid() const221 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
222 return server_config_valid_;
223 }
224
generation_counter() const225 uint64 QuicCryptoClientConfig::CachedState::generation_counter() const {
226 return generation_counter_;
227 }
228
229 const ProofVerifyDetails*
proof_verify_details() const230 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
231 return proof_verify_details_.get();
232 }
233
set_source_address_token(StringPiece token)234 void QuicCryptoClientConfig::CachedState::set_source_address_token(
235 StringPiece token) {
236 source_address_token_ = token.as_string();
237 }
238
SetProofVerifyDetails(ProofVerifyDetails * details)239 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
240 ProofVerifyDetails* details) {
241 proof_verify_details_.reset(details);
242 }
243
InitializeFrom(const QuicCryptoClientConfig::CachedState & other)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_;
254 }
255
SetDefaults()256 void QuicCryptoClientConfig::SetDefaults() {
257 // Key exchange methods.
258 kexs.resize(2);
259 kexs[0] = kC255;
260 kexs[1] = kP256;
261
262 // Authenticated encryption algorithms. Prefer ChaCha20 by default.
263 aead.clear();
264 if (ChaCha20Poly1305Encrypter::IsSupported()) {
265 aead.push_back(kCC12);
266 }
267 aead.push_back(kAESG);
268
269 disable_ecdsa_ = false;
270 }
271
LookupOrCreate(const QuicServerId & server_id)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()) {
276 return it->second;
277 }
278
279 CachedState* cached = new CachedState;
280 cached_states_.insert(make_pair(server_id, cached));
281 PopulateFromCanonicalConfig(server_id, cached);
282 return cached;
283 }
284
ClearCachedStates()285 void QuicCryptoClientConfig::ClearCachedStates() {
286 for (CachedStateMap::const_iterator it = cached_states_.begin();
287 it != cached_states_.end(); ++it) {
288 it->second->Clear();
289 }
290 }
291
FillInchoateClientHello(const QuicServerId & server_id,const QuicVersion preferred_version,const CachedState * cached,QuicCryptoNegotiatedParameters * out_params,CryptoHandshakeMessage * out) const292 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 {
298 out->set_tag(kCHLO);
299 out->set_minimum_size(kClientHelloMinimumSize);
300
301 // Server name indication. We only send SNI if it's a valid domain name, as
302 // per the spec.
303 if (CryptoUtils::IsValidSNI(server_id.host())) {
304 out->SetStringPiece(kSNI, server_id.host());
305 }
306 out->SetValue(kVER, QuicVersionToQuicTag(preferred_version));
307
308 if (!user_agent_id_.empty()) {
309 out->SetStringPiece(kUAID, user_agent_id_);
310 }
311
312 if (!cached->source_address_token().empty()) {
313 out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
314 }
315
316 if (server_id.is_https()) {
317 if (disable_ecdsa_) {
318 out->SetTaglist(kPDMD, kX59R, 0);
319 } else {
320 out->SetTaglist(kPDMD, kX509, 0);
321 }
322 }
323
324 if (common_cert_sets) {
325 out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
326 }
327
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()));
340 }
341 out->SetVector(kCCRT, hashes);
342 }
343 }
344
FillClientHello(const QuicServerId & server_id,QuicConnectionId connection_id,const QuicVersion preferred_version,const CachedState * cached,QuicWallTime now,QuicRandom * rand,const ChannelIDKey * channel_id_key,QuicCryptoNegotiatedParameters * out_params,CryptoHandshakeMessage * out,string * error_details) const345 QuicErrorCode QuicCryptoClientConfig::FillClientHello(
346 const QuicServerId& server_id,
347 QuicConnectionId connection_id,
348 const QuicVersion preferred_version,
349 const CachedState* cached,
350 QuicWallTime now,
351 QuicRandom* rand,
352 const ChannelIDKey* channel_id_key,
353 QuicCryptoNegotiatedParameters* out_params,
354 CryptoHandshakeMessage* out,
355 string* error_details) const {
356 DCHECK(error_details != NULL);
357
358 FillInchoateClientHello(server_id, preferred_version, cached,
359 out_params, out);
360
361 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
362 if (!scfg) {
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;
367 }
368
369 StringPiece scid;
370 if (!scfg->GetStringPiece(kSCID, &scid)) {
371 *error_details = "SCFG missing SCID";
372 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
373 }
374 out->SetStringPiece(kSCID, scid);
375
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;
385 }
386
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;
402 }
403 out->SetTaglist(kAEAD, out_params->aead, 0);
404 out->SetTaglist(kKEXS, out_params->key_exchange, 0);
405
406 StringPiece public_value;
407 if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
408 QUIC_NO_ERROR) {
409 *error_details = "Missing public value";
410 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
411 }
412
413 StringPiece orbit;
414 if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) {
415 *error_details = "SCFG missing OBIT";
416 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
417 }
418
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);
423 }
424
425 switch (out_params->key_exchange) {
426 case kC255:
427 out_params->client_key_exchange.reset(Curve25519KeyExchange::New(
428 Curve25519KeyExchange::NewPrivateKey(rand)));
429 break;
430 case kP256:
431 out_params->client_key_exchange.reset(P256KeyExchange::New(
432 P256KeyExchange::NewPrivateKey()));
433 break;
434 default:
435 DCHECK(false);
436 *error_details = "Configured to support an unknown key exchange";
437 return QUIC_CRYPTO_INTERNAL_ERROR;
438 }
439
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;
444 }
445 out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
446
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);
453
454 CryptoHandshakeMessage cetv;
455 cetv.set_tag(kCETV);
456
457 string hkdf_input;
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());
466
467 string key = channel_id_key->SerializeKey();
468 string signature;
469 if (!channel_id_key->Sign(hkdf_input, &signature)) {
470 *error_details = "Channel ID signature failed";
471 return QUIC_INVALID_CHANNEL_ID_SIGNATURE;
472 }
473
474 cetv.SetStringPiece(kCIDK, key);
475 cetv.SetStringPiece(kCIDS, signature);
476
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;
484 }
485
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;
494 }
495
496 out->SetStringPiece(kCETV, cetv_ciphertext->AsStringPiece());
497 out->MarkDirty();
498
499 out->set_minimum_size(orig_min_size);
500 }
501
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());
513
514 string hkdf_input;
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);
519
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;
526 }
527
528 return QUIC_NO_ERROR;
529 }
530
ProcessRejection(const CryptoHandshakeMessage & rej,QuicWallTime now,CachedState * cached,QuicCryptoNegotiatedParameters * out_params,string * error_details)531 QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
532 const CryptoHandshakeMessage& rej,
533 QuicWallTime now,
534 CachedState* cached,
535 QuicCryptoNegotiatedParameters* out_params,
536 string* error_details) {
537 DCHECK(error_details != NULL);
538
539 if (rej.tag() != kREJ) {
540 *error_details = "Message is not REJ";
541 return QUIC_CRYPTO_INTERNAL_ERROR;
542 }
543
544 StringPiece scfg;
545 if (!rej.GetStringPiece(kSCFG, &scfg)) {
546 *error_details = "Missing SCFG";
547 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
548 }
549
550 QuicErrorCode error = cached->SetServerConfig(scfg, now, error_details);
551 if (error != QUIC_NO_ERROR) {
552 return error;
553 }
554
555 StringPiece token;
556 if (rej.GetStringPiece(kSourceAddressTokenTag, &token)) {
557 cached->set_source_address_token(token);
558 }
559
560 StringPiece nonce;
561 if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
562 out_params->server_nonce = nonce.as_string();
563 }
564
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;
574 }
575
576 cached->SetProof(certs, proof);
577 } else {
578 cached->ClearProof();
579 if (has_proof && !has_cert) {
580 *error_details = "Certificate missing";
581 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
582 }
583
584 if (!has_proof && has_cert) {
585 *error_details = "Proof missing";
586 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
587 }
588 }
589
590 const QuicTag* reject_reasons;
591 size_t num_reject_reasons;
592 if (rej.GetTaglist(kRREJ, &reject_reasons,
593 &num_reject_reasons) == QUIC_NO_ERROR) {
594 #if defined(DEBUG)
595 for (size_t i = 0; i < num_reject_reasons; ++i) {
596 DVLOG(1) << "Reasons for rejection: " << reject_reasons[i];
597 }
598 #endif
599 }
600
601 return QUIC_NO_ERROR;
602 }
603
ProcessServerHello(const CryptoHandshakeMessage & server_hello,QuicConnectionId connection_id,const QuicVersionVector & negotiated_versions,CachedState * cached,QuicCryptoNegotiatedParameters * out_params,string * error_details)604 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
605 const CryptoHandshakeMessage& server_hello,
606 QuicConnectionId connection_id,
607 const QuicVersionVector& negotiated_versions,
608 CachedState* cached,
609 QuicCryptoNegotiatedParameters* out_params,
610 string* error_details) {
611 DCHECK(error_details != NULL);
612
613 if (server_hello.tag() != kSHLO) {
614 *error_details = "Bad tag";
615 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
616 }
617
618 const QuicTag* supported_version_tags;
619 size_t num_supported_versions;
620
621 if (server_hello.GetTaglist(kVER, &supported_version_tags,
622 &num_supported_versions) != QUIC_NO_ERROR) {
623 *error_details = "server hello missing version list";
624 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
625 }
626 if (!negotiated_versions.empty()) {
627 bool mismatch = num_supported_versions != negotiated_versions.size();
628 for (size_t i = 0; i < num_supported_versions && !mismatch; ++i) {
629 mismatch = QuicTagToQuicVersion(supported_version_tags[i]) !=
630 negotiated_versions[i];
631 }
632 // The server sent a list of supported versions, and the connection
633 // reports that there was a version negotiation during the handshake.
634 // Ensure that these two lists are identical.
635 if (mismatch) {
636 *error_details = "Downgrade attack detected";
637 return QUIC_VERSION_NEGOTIATION_MISMATCH;
638 }
639 }
640
641 // Learn about updated source address tokens.
642 StringPiece token;
643 if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) {
644 cached->set_source_address_token(token);
645 }
646
647 // TODO(agl):
648 // learn about updated SCFGs.
649
650 StringPiece public_value;
651 if (!server_hello.GetStringPiece(kPUBS, &public_value)) {
652 *error_details = "server hello missing forward secure public value";
653 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
654 }
655
656 if (!out_params->client_key_exchange->CalculateSharedKey(
657 public_value, &out_params->forward_secure_premaster_secret)) {
658 *error_details = "Key exchange failure";
659 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
660 }
661
662 string hkdf_input;
663 const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
664 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
665 hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
666 hkdf_input.append(out_params->hkdf_input_suffix);
667
668 if (!CryptoUtils::DeriveKeys(
669 out_params->forward_secure_premaster_secret, out_params->aead,
670 out_params->client_nonce, out_params->server_nonce, hkdf_input,
671 CryptoUtils::CLIENT, &out_params->forward_secure_crypters)) {
672 *error_details = "Symmetric key setup failed";
673 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
674 }
675
676 return QUIC_NO_ERROR;
677 }
678
proof_verifier() const679 ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
680 return proof_verifier_.get();
681 }
682
SetProofVerifier(ProofVerifier * verifier)683 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier* verifier) {
684 proof_verifier_.reset(verifier);
685 }
686
channel_id_source() const687 ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const {
688 return channel_id_source_.get();
689 }
690
SetChannelIDSource(ChannelIDSource * source)691 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) {
692 channel_id_source_.reset(source);
693 }
694
InitializeFrom(const QuicServerId & server_id,const QuicServerId & canonical_server_id,QuicCryptoClientConfig * canonical_crypto_config)695 void QuicCryptoClientConfig::InitializeFrom(
696 const QuicServerId& server_id,
697 const QuicServerId& canonical_server_id,
698 QuicCryptoClientConfig* canonical_crypto_config) {
699 CachedState* canonical_cached =
700 canonical_crypto_config->LookupOrCreate(canonical_server_id);
701 if (!canonical_cached->proof_valid()) {
702 return;
703 }
704 CachedState* cached = LookupOrCreate(server_id);
705 cached->InitializeFrom(*canonical_cached);
706 }
707
AddCanonicalSuffix(const string & suffix)708 void QuicCryptoClientConfig::AddCanonicalSuffix(const string& suffix) {
709 canoncial_suffixes_.push_back(suffix);
710 }
711
PreferAesGcm()712 void QuicCryptoClientConfig::PreferAesGcm() {
713 DCHECK(!aead.empty());
714 if (aead.size() <= 1) {
715 return;
716 }
717 QuicTagVector::iterator pos = find(aead.begin(), aead.end(), kAESG);
718 if (pos != aead.end()) {
719 aead.erase(pos);
720 aead.insert(aead.begin(), kAESG);
721 }
722 }
723
DisableEcdsa()724 void QuicCryptoClientConfig::DisableEcdsa() {
725 disable_ecdsa_ = true;
726 }
727
PopulateFromCanonicalConfig(const QuicServerId & server_id,CachedState * server_state)728 void QuicCryptoClientConfig::PopulateFromCanonicalConfig(
729 const QuicServerId& server_id,
730 CachedState* server_state) {
731 DCHECK(server_state->IsEmpty());
732 size_t i = 0;
733 for (; i < canoncial_suffixes_.size(); ++i) {
734 if (EndsWith(server_id.host(), canoncial_suffixes_[i], false)) {
735 break;
736 }
737 }
738 if (i == canoncial_suffixes_.size())
739 return;
740
741 QuicServerId suffix_server_id(canoncial_suffixes_[i], server_id.port(),
742 server_id.is_https(),
743 server_id.privacy_mode());
744 if (!ContainsKey(canonical_server_map_, suffix_server_id)) {
745 // This is the first host we've seen which matches the suffix, so make it
746 // canonical.
747 canonical_server_map_[suffix_server_id] = server_id;
748 return;
749 }
750
751 const QuicServerId& canonical_server_id =
752 canonical_server_map_[suffix_server_id];
753 CachedState* canonical_state = cached_states_[canonical_server_id];
754 if (!canonical_state->proof_valid()) {
755 return;
756 }
757
758 // Update canonical version to point at the "most recent" entry.
759 canonical_server_map_[suffix_server_id] = server_id;
760
761 server_state->InitializeFrom(*canonical_state);
762 }
763
764 } // namespace net
765