• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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