OLD | NEW |
| (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_server_config.h" | |
6 | |
7 #include <stdlib.h> | |
8 | |
9 #include <algorithm> | |
10 #include <memory> | |
11 | |
12 #include "base/macros.h" | |
13 #include "base/memory/ref_counted.h" | |
14 #include "base/stl_util.h" | |
15 #include "crypto/hkdf.h" | |
16 #include "crypto/secure_hash.h" | |
17 #include "net/base/ip_address.h" | |
18 #include "net/quic/crypto/aes_128_gcm_12_decrypter.h" | |
19 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" | |
20 #include "net/quic/crypto/cert_compressor.h" | |
21 #include "net/quic/crypto/chacha20_poly1305_encrypter.h" | |
22 #include "net/quic/crypto/channel_id.h" | |
23 #include "net/quic/crypto/crypto_framer.h" | |
24 #include "net/quic/crypto/crypto_handshake_message.h" | |
25 #include "net/quic/crypto/crypto_server_config_protobuf.h" | |
26 #include "net/quic/crypto/crypto_utils.h" | |
27 #include "net/quic/crypto/curve25519_key_exchange.h" | |
28 #include "net/quic/crypto/ephemeral_key_source.h" | |
29 #include "net/quic/crypto/key_exchange.h" | |
30 #include "net/quic/crypto/local_strike_register_client.h" | |
31 #include "net/quic/crypto/p256_key_exchange.h" | |
32 #include "net/quic/crypto/proof_source.h" | |
33 #include "net/quic/crypto/quic_decrypter.h" | |
34 #include "net/quic/crypto/quic_encrypter.h" | |
35 #include "net/quic/crypto/quic_random.h" | |
36 #include "net/quic/crypto/strike_register.h" | |
37 #include "net/quic/crypto/strike_register_client.h" | |
38 #include "net/quic/proto/source_address_token.pb.h" | |
39 #include "net/quic/quic_bug_tracker.h" | |
40 #include "net/quic/quic_clock.h" | |
41 #include "net/quic/quic_flags.h" | |
42 #include "net/quic/quic_protocol.h" | |
43 #include "net/quic/quic_socket_address_coder.h" | |
44 #include "net/quic/quic_utils.h" | |
45 | |
46 using base::StringPiece; | |
47 using crypto::SecureHash; | |
48 using std::map; | |
49 using std::sort; | |
50 using std::string; | |
51 using std::vector; | |
52 | |
53 namespace net { | |
54 | |
55 namespace { | |
56 | |
57 // kMultiplier is the multiple of the CHLO message size that a REJ message | |
58 // must stay under when the client doesn't present a valid source-address | |
59 // token. This is used to protect QUIC from amplification attacks. | |
60 // TODO(rch): Reduce this to 2 again once b/25933682 is fixed. | |
61 const size_t kMultiplier = 3; | |
62 | |
63 const int kMaxTokenAddresses = 4; | |
64 | |
65 string DeriveSourceAddressTokenKey(StringPiece source_address_token_secret) { | |
66 crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, | |
67 "QUIC source address token key", | |
68 CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */, | |
69 0 /* no subkey secret */); | |
70 return hkdf.server_write_key().as_string(); | |
71 } | |
72 | |
73 IPAddress DualstackIPAddress(const IPAddress& ip) { | |
74 if (ip.IsIPv4()) { | |
75 return ConvertIPv4ToIPv4MappedIPv6(ip); | |
76 } | |
77 return ip; | |
78 } | |
79 | |
80 } // namespace | |
81 | |
82 class ValidateClientHelloHelper { | |
83 public: | |
84 ValidateClientHelloHelper(ValidateClientHelloResultCallback::Result* result, | |
85 ValidateClientHelloResultCallback* done_cb) | |
86 : result_(result), done_cb_(done_cb) {} | |
87 | |
88 ~ValidateClientHelloHelper() { | |
89 QUIC_BUG_IF(done_cb_ != nullptr) | |
90 << "Deleting ValidateClientHelloHelper with a pending callback."; | |
91 } | |
92 | |
93 void ValidationComplete( | |
94 QuicErrorCode error_code, | |
95 const char* error_details, | |
96 std::unique_ptr<ProofSource::Details> proof_source_details) { | |
97 result_->error_code = error_code; | |
98 result_->error_details = error_details; | |
99 done_cb_->Run(result_, std::move(proof_source_details)); | |
100 DetachCallback(); | |
101 } | |
102 | |
103 void DetachCallback() { | |
104 QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached."; | |
105 done_cb_ = nullptr; | |
106 } | |
107 | |
108 private: | |
109 ValidateClientHelloResultCallback::Result* result_; | |
110 ValidateClientHelloResultCallback* done_cb_; | |
111 | |
112 DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloHelper); | |
113 }; | |
114 | |
115 class VerifyNonceIsValidAndUniqueCallback | |
116 : public StrikeRegisterClient::ResultCallback { | |
117 public: | |
118 VerifyNonceIsValidAndUniqueCallback( | |
119 ValidateClientHelloResultCallback::Result* result, | |
120 std::unique_ptr<ProofSource::Details> proof_source_details, | |
121 ValidateClientHelloResultCallback* done_cb) | |
122 : result_(result), | |
123 proof_source_details_(std::move(proof_source_details)), | |
124 done_cb_(done_cb) {} | |
125 | |
126 protected: | |
127 void RunImpl(bool nonce_is_valid_and_unique, | |
128 InsertStatus nonce_error) override { | |
129 DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique | |
130 << " nonce_error: " << nonce_error; | |
131 if (!nonce_is_valid_and_unique) { | |
132 HandshakeFailureReason client_nonce_error; | |
133 switch (nonce_error) { | |
134 case NONCE_INVALID_FAILURE: | |
135 client_nonce_error = CLIENT_NONCE_INVALID_FAILURE; | |
136 break; | |
137 case NONCE_NOT_UNIQUE_FAILURE: | |
138 client_nonce_error = CLIENT_NONCE_NOT_UNIQUE_FAILURE; | |
139 break; | |
140 case NONCE_INVALID_ORBIT_FAILURE: | |
141 client_nonce_error = CLIENT_NONCE_INVALID_ORBIT_FAILURE; | |
142 break; | |
143 case NONCE_INVALID_TIME_FAILURE: | |
144 client_nonce_error = CLIENT_NONCE_INVALID_TIME_FAILURE; | |
145 break; | |
146 case STRIKE_REGISTER_TIMEOUT: | |
147 client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT; | |
148 break; | |
149 case STRIKE_REGISTER_FAILURE: | |
150 client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_FAILURE; | |
151 break; | |
152 case NONCE_UNKNOWN_FAILURE: | |
153 client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE; | |
154 break; | |
155 case NONCE_OK: | |
156 default: | |
157 QUIC_BUG << "Unexpected client nonce error: " << nonce_error; | |
158 client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE; | |
159 break; | |
160 } | |
161 result_->info.reject_reasons.push_back(client_nonce_error); | |
162 } | |
163 done_cb_->Run(result_, std::move(proof_source_details_)); | |
164 } | |
165 | |
166 private: | |
167 ValidateClientHelloResultCallback::Result* result_; | |
168 std::unique_ptr<ProofSource::Details> proof_source_details_; | |
169 ValidateClientHelloResultCallback* done_cb_; | |
170 | |
171 DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback); | |
172 }; | |
173 | |
174 // static | |
175 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing"; | |
176 | |
177 ClientHelloInfo::ClientHelloInfo(const IPAddress& in_client_ip, | |
178 QuicWallTime in_now) | |
179 : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {} | |
180 | |
181 ClientHelloInfo::~ClientHelloInfo() {} | |
182 | |
183 PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {} | |
184 | |
185 PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {} | |
186 | |
187 ValidateClientHelloResultCallback::Result::Result( | |
188 const CryptoHandshakeMessage& in_client_hello, | |
189 IPAddress in_client_ip, | |
190 QuicWallTime in_now) | |
191 : client_hello(in_client_hello), | |
192 info(in_client_ip, in_now), | |
193 error_code(QUIC_NO_ERROR) {} | |
194 | |
195 ValidateClientHelloResultCallback::Result::~Result() {} | |
196 | |
197 ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {} | |
198 | |
199 ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {} | |
200 | |
201 void ValidateClientHelloResultCallback::Run( | |
202 const Result* result, | |
203 std::unique_ptr<ProofSource::Details> details) { | |
204 RunImpl(result->client_hello, *result, std::move(details)); | |
205 delete result; | |
206 delete this; | |
207 } | |
208 | |
209 QuicCryptoServerConfig::ConfigOptions::ConfigOptions() | |
210 : expiry_time(QuicWallTime::Zero()), | |
211 channel_id_enabled(false), | |
212 token_binding_enabled(false), | |
213 p256(false) {} | |
214 | |
215 QuicCryptoServerConfig::ConfigOptions::ConfigOptions( | |
216 const ConfigOptions& other) = default; | |
217 | |
218 QuicCryptoServerConfig::QuicCryptoServerConfig( | |
219 StringPiece source_address_token_secret, | |
220 QuicRandom* server_nonce_entropy, | |
221 std::unique_ptr<ProofSource> proof_source) | |
222 : replay_protection_(true), | |
223 chlo_multiplier_(kMultiplier), | |
224 configs_lock_(), | |
225 primary_config_(nullptr), | |
226 next_config_promotion_time_(QuicWallTime::Zero()), | |
227 server_nonce_strike_register_lock_(), | |
228 proof_source_(std::move(proof_source)), | |
229 strike_register_no_startup_period_(false), | |
230 strike_register_max_entries_(1 << 10), | |
231 strike_register_window_secs_(600), | |
232 source_address_token_future_secs_(3600), | |
233 source_address_token_lifetime_secs_(86400), | |
234 server_nonce_strike_register_max_entries_(1 << 10), | |
235 server_nonce_strike_register_window_secs_(120), | |
236 enable_serving_sct_(false) { | |
237 DCHECK(proof_source_.get()); | |
238 default_source_address_token_boxer_.SetKeys( | |
239 {DeriveSourceAddressTokenKey(source_address_token_secret)}); | |
240 | |
241 // Generate a random key and orbit for server nonces. | |
242 server_nonce_entropy->RandBytes(server_nonce_orbit_, | |
243 sizeof(server_nonce_orbit_)); | |
244 const size_t key_size = server_nonce_boxer_.GetKeySize(); | |
245 std::unique_ptr<uint8_t[]> key_bytes(new uint8_t[key_size]); | |
246 server_nonce_entropy->RandBytes(key_bytes.get(), key_size); | |
247 | |
248 server_nonce_boxer_.SetKeys( | |
249 {string(reinterpret_cast<char*>(key_bytes.get()), key_size)}); | |
250 } | |
251 | |
252 QuicCryptoServerConfig::~QuicCryptoServerConfig() { | |
253 primary_config_ = nullptr; | |
254 } | |
255 | |
256 // static | |
257 QuicServerConfigProtobuf* QuicCryptoServerConfig::GenerateConfig( | |
258 QuicRandom* rand, | |
259 const QuicClock* clock, | |
260 const ConfigOptions& options) { | |
261 CryptoHandshakeMessage msg; | |
262 | |
263 const string curve25519_private_key = | |
264 Curve25519KeyExchange::NewPrivateKey(rand); | |
265 std::unique_ptr<Curve25519KeyExchange> curve25519( | |
266 Curve25519KeyExchange::New(curve25519_private_key)); | |
267 StringPiece curve25519_public_value = curve25519->public_value(); | |
268 | |
269 string encoded_public_values; | |
270 // First three bytes encode the length of the public value. | |
271 DCHECK_LT(curve25519_public_value.size(), (1U << 24)); | |
272 encoded_public_values.push_back( | |
273 static_cast<char>(curve25519_public_value.size())); | |
274 encoded_public_values.push_back( | |
275 static_cast<char>(curve25519_public_value.size() >> 8)); | |
276 encoded_public_values.push_back( | |
277 static_cast<char>(curve25519_public_value.size() >> 16)); | |
278 encoded_public_values.append(curve25519_public_value.data(), | |
279 curve25519_public_value.size()); | |
280 | |
281 string p256_private_key; | |
282 if (options.p256) { | |
283 p256_private_key = P256KeyExchange::NewPrivateKey(); | |
284 std::unique_ptr<P256KeyExchange> p256( | |
285 P256KeyExchange::New(p256_private_key)); | |
286 StringPiece p256_public_value = p256->public_value(); | |
287 | |
288 DCHECK_LT(p256_public_value.size(), (1U << 24)); | |
289 encoded_public_values.push_back( | |
290 static_cast<char>(p256_public_value.size())); | |
291 encoded_public_values.push_back( | |
292 static_cast<char>(p256_public_value.size() >> 8)); | |
293 encoded_public_values.push_back( | |
294 static_cast<char>(p256_public_value.size() >> 16)); | |
295 encoded_public_values.append(p256_public_value.data(), | |
296 p256_public_value.size()); | |
297 } | |
298 | |
299 msg.set_tag(kSCFG); | |
300 if (options.p256) { | |
301 msg.SetVector(kKEXS, QuicTagVector{kC255, kP256}); | |
302 } else { | |
303 msg.SetVector(kKEXS, QuicTagVector{kC255}); | |
304 } | |
305 msg.SetVector(kAEAD, QuicTagVector{kAESG, kCC20}); | |
306 msg.SetStringPiece(kPUBS, encoded_public_values); | |
307 | |
308 if (options.expiry_time.IsZero()) { | |
309 const QuicWallTime now = clock->WallNow(); | |
310 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds( | |
311 60 * 60 * 24 * 180 /* 180 days, ~six months */)); | |
312 const uint64_t expiry_seconds = expiry.ToUNIXSeconds(); | |
313 msg.SetValue(kEXPY, expiry_seconds); | |
314 } else { | |
315 msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds()); | |
316 } | |
317 | |
318 char orbit_bytes[kOrbitSize]; | |
319 if (options.orbit.size() == sizeof(orbit_bytes)) { | |
320 memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes)); | |
321 } else { | |
322 DCHECK(options.orbit.empty()); | |
323 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes)); | |
324 } | |
325 msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes))); | |
326 | |
327 if (options.channel_id_enabled) { | |
328 msg.SetVector(kPDMD, QuicTagVector{kCHID}); | |
329 } | |
330 | |
331 if (options.token_binding_enabled) { | |
332 msg.SetVector(kTBKP, QuicTagVector{kP256}); | |
333 } | |
334 | |
335 if (options.id.empty()) { | |
336 // We need to ensure that the SCID changes whenever the server config does | |
337 // thus we make it a hash of the rest of the server config. | |
338 std::unique_ptr<QuicData> serialized( | |
339 CryptoFramer::ConstructHandshakeMessage(msg)); | |
340 std::unique_ptr<SecureHash> hash(SecureHash::Create(SecureHash::SHA256)); | |
341 hash->Update(serialized->data(), serialized->length()); | |
342 | |
343 char scid_bytes[16]; | |
344 hash->Finish(scid_bytes, sizeof(scid_bytes)); | |
345 msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes))); | |
346 } else { | |
347 msg.SetStringPiece(kSCID, options.id); | |
348 } | |
349 // Don't put new tags below this point. The SCID generation should hash over | |
350 // everything but itself and so extra tags should be added prior to the | |
351 // preceeding if block. | |
352 | |
353 std::unique_ptr<QuicData> serialized( | |
354 CryptoFramer::ConstructHandshakeMessage(msg)); | |
355 | |
356 std::unique_ptr<QuicServerConfigProtobuf> config( | |
357 new QuicServerConfigProtobuf); | |
358 config->set_config(serialized->AsStringPiece()); | |
359 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key(); | |
360 curve25519_key->set_tag(kC255); | |
361 curve25519_key->set_private_key(curve25519_private_key); | |
362 | |
363 if (options.p256) { | |
364 QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key(); | |
365 p256_key->set_tag(kP256); | |
366 p256_key->set_private_key(p256_private_key); | |
367 } | |
368 | |
369 return config.release(); | |
370 } | |
371 | |
372 CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( | |
373 QuicServerConfigProtobuf* protobuf, | |
374 const QuicWallTime now) { | |
375 std::unique_ptr<CryptoHandshakeMessage> msg( | |
376 CryptoFramer::ParseMessage(protobuf->config())); | |
377 | |
378 if (!msg.get()) { | |
379 LOG(WARNING) << "Failed to parse server config message"; | |
380 return nullptr; | |
381 } | |
382 | |
383 scoped_refptr<Config> config(ParseConfigProtobuf(protobuf)); | |
384 if (!config.get()) { | |
385 LOG(WARNING) << "Failed to parse server config message"; | |
386 return nullptr; | |
387 } | |
388 | |
389 { | |
390 base::AutoLock locked(configs_lock_); | |
391 if (configs_.find(config->id) != configs_.end()) { | |
392 LOG(WARNING) << "Failed to add config because another with the same " | |
393 "server config id already exists: " | |
394 << QuicUtils::HexEncode(config->id); | |
395 return nullptr; | |
396 } | |
397 | |
398 configs_[config->id] = config; | |
399 SelectNewPrimaryConfig(now); | |
400 DCHECK(primary_config_.get()); | |
401 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); | |
402 } | |
403 | |
404 return msg.release(); | |
405 } | |
406 | |
407 CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( | |
408 QuicRandom* rand, | |
409 const QuicClock* clock, | |
410 const ConfigOptions& options) { | |
411 std::unique_ptr<QuicServerConfigProtobuf> config( | |
412 GenerateConfig(rand, clock, options)); | |
413 return AddConfig(config.get(), clock->WallNow()); | |
414 } | |
415 | |
416 bool QuicCryptoServerConfig::SetConfigs( | |
417 const vector<QuicServerConfigProtobuf*>& protobufs, | |
418 const QuicWallTime now) { | |
419 vector<scoped_refptr<Config>> parsed_configs; | |
420 bool ok = true; | |
421 | |
422 for (vector<QuicServerConfigProtobuf*>::const_iterator i = protobufs.begin(); | |
423 i != protobufs.end(); ++i) { | |
424 scoped_refptr<Config> config(ParseConfigProtobuf(*i)); | |
425 if (!config.get()) { | |
426 ok = false; | |
427 break; | |
428 } | |
429 | |
430 parsed_configs.push_back(config); | |
431 } | |
432 | |
433 if (parsed_configs.empty()) { | |
434 LOG(WARNING) << "New config list is empty."; | |
435 ok = false; | |
436 } | |
437 | |
438 if (!ok) { | |
439 LOG(WARNING) << "Rejecting QUIC configs because of above errors"; | |
440 } else { | |
441 VLOG(1) << "Updating configs:"; | |
442 | |
443 base::AutoLock locked(configs_lock_); | |
444 ConfigMap new_configs; | |
445 | |
446 for (vector<scoped_refptr<Config>>::const_iterator i = | |
447 parsed_configs.begin(); | |
448 i != parsed_configs.end(); ++i) { | |
449 scoped_refptr<Config> config = *i; | |
450 | |
451 ConfigMap::iterator it = configs_.find(config->id); | |
452 if (it != configs_.end()) { | |
453 VLOG(1) << "Keeping scid: " << QuicUtils::HexEncode(config->id) | |
454 << " orbit: " | |
455 << QuicUtils::HexEncode( | |
456 reinterpret_cast<const char*>(config->orbit), kOrbitSize) | |
457 << " new primary_time " << config->primary_time.ToUNIXSeconds() | |
458 << " old primary_time " | |
459 << it->second->primary_time.ToUNIXSeconds() << " new priority " | |
460 << config->priority << " old priority " << it->second->priority; | |
461 // Update primary_time and priority. | |
462 it->second->primary_time = config->primary_time; | |
463 it->second->priority = config->priority; | |
464 new_configs.insert(*it); | |
465 } else { | |
466 VLOG(1) << "Adding scid: " << QuicUtils::HexEncode(config->id) | |
467 << " orbit: " | |
468 << QuicUtils::HexEncode( | |
469 reinterpret_cast<const char*>(config->orbit), kOrbitSize) | |
470 << " primary_time " << config->primary_time.ToUNIXSeconds() | |
471 << " priority " << config->priority; | |
472 new_configs.insert(std::make_pair(config->id, config)); | |
473 } | |
474 } | |
475 | |
476 configs_.swap(new_configs); | |
477 SelectNewPrimaryConfig(now); | |
478 DCHECK(primary_config_.get()); | |
479 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); | |
480 } | |
481 | |
482 return ok; | |
483 } | |
484 | |
485 void QuicCryptoServerConfig::SetDefaultSourceAddressTokenKeys( | |
486 const vector<string>& keys) { | |
487 default_source_address_token_boxer_.SetKeys(keys); | |
488 } | |
489 | |
490 void QuicCryptoServerConfig::GetConfigIds(vector<string>* scids) const { | |
491 base::AutoLock locked(configs_lock_); | |
492 for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end(); | |
493 ++it) { | |
494 scids->push_back(it->first); | |
495 } | |
496 } | |
497 | |
498 void QuicCryptoServerConfig::ValidateClientHello( | |
499 const CryptoHandshakeMessage& client_hello, | |
500 const IPAddress& client_ip, | |
501 const IPAddress& server_ip, | |
502 QuicVersion version, | |
503 const QuicClock* clock, | |
504 QuicCryptoProof* crypto_proof, | |
505 ValidateClientHelloResultCallback* done_cb) const { | |
506 const QuicWallTime now(clock->WallNow()); | |
507 | |
508 ValidateClientHelloResultCallback::Result* result = | |
509 new ValidateClientHelloResultCallback::Result(client_hello, client_ip, | |
510 now); | |
511 | |
512 StringPiece requested_scid; | |
513 client_hello.GetStringPiece(kSCID, &requested_scid); | |
514 | |
515 uint8_t primary_orbit[kOrbitSize]; | |
516 scoped_refptr<Config> requested_config; | |
517 scoped_refptr<Config> primary_config; | |
518 { | |
519 base::AutoLock locked(configs_lock_); | |
520 | |
521 if (!primary_config_.get()) { | |
522 result->error_code = QUIC_CRYPTO_INTERNAL_ERROR; | |
523 result->error_details = "No configurations loaded"; | |
524 } else { | |
525 if (!next_config_promotion_time_.IsZero() && | |
526 next_config_promotion_time_.IsAfter(now)) { | |
527 SelectNewPrimaryConfig(now); | |
528 DCHECK(primary_config_.get()); | |
529 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); | |
530 } | |
531 | |
532 memcpy(primary_orbit, primary_config_->orbit, sizeof(primary_orbit)); | |
533 } | |
534 | |
535 requested_config = GetConfigWithScid(requested_scid); | |
536 primary_config = primary_config_; | |
537 crypto_proof->config = primary_config_; | |
538 } | |
539 | |
540 if (result->error_code == QUIC_NO_ERROR) { | |
541 if (FLAGS_quic_refresh_proof && version > QUIC_VERSION_30) { | |
542 // QUIC v31 and above require a new proof for each CHLO so clear the | |
543 // existing proof, if any. | |
544 crypto_proof->chain = nullptr; | |
545 crypto_proof->signature = ""; | |
546 crypto_proof->cert_sct = ""; | |
547 } | |
548 EvaluateClientHello(server_ip, version, primary_orbit, requested_config, | |
549 primary_config, crypto_proof, result, done_cb); | |
550 } else { | |
551 done_cb->Run(result, nullptr /* proof_source_details */); | |
552 } | |
553 } | |
554 | |
555 QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( | |
556 const ValidateClientHelloResultCallback::Result& validate_chlo_result, | |
557 bool reject_only, | |
558 QuicConnectionId connection_id, | |
559 const IPAddress& server_ip, | |
560 const IPEndPoint& client_address, | |
561 QuicVersion version, | |
562 const QuicVersionVector& supported_versions, | |
563 bool use_stateless_rejects, | |
564 QuicConnectionId server_designated_connection_id, | |
565 const QuicClock* clock, | |
566 QuicRandom* rand, | |
567 QuicCompressedCertsCache* compressed_certs_cache, | |
568 QuicCryptoNegotiatedParameters* params, | |
569 QuicCryptoProof* crypto_proof, | |
570 CryptoHandshakeMessage* out, | |
571 DiversificationNonce* out_diversification_nonce, | |
572 string* error_details) const { | |
573 DCHECK(error_details); | |
574 | |
575 const CryptoHandshakeMessage& client_hello = | |
576 validate_chlo_result.client_hello; | |
577 const ClientHelloInfo& info = validate_chlo_result.info; | |
578 | |
579 QuicErrorCode valid = CryptoUtils::ValidateClientHello( | |
580 client_hello, version, supported_versions, error_details); | |
581 if (valid != QUIC_NO_ERROR) | |
582 return valid; | |
583 | |
584 StringPiece requested_scid; | |
585 client_hello.GetStringPiece(kSCID, &requested_scid); | |
586 const QuicWallTime now(clock->WallNow()); | |
587 | |
588 scoped_refptr<Config> requested_config; | |
589 scoped_refptr<Config> primary_config; | |
590 { | |
591 base::AutoLock locked(configs_lock_); | |
592 | |
593 if (!primary_config_.get()) { | |
594 *error_details = "No configurations loaded"; | |
595 return QUIC_CRYPTO_INTERNAL_ERROR; | |
596 } | |
597 | |
598 if (!next_config_promotion_time_.IsZero() && | |
599 next_config_promotion_time_.IsAfter(now)) { | |
600 SelectNewPrimaryConfig(now); | |
601 DCHECK(primary_config_.get()); | |
602 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); | |
603 } | |
604 | |
605 // Use the config that the client requested in order to do key-agreement. | |
606 // Otherwise give it a copy of |primary_config_| to use. | |
607 primary_config = crypto_proof->config; | |
608 requested_config = GetConfigWithScid(requested_scid); | |
609 } | |
610 | |
611 if (validate_chlo_result.error_code != QUIC_NO_ERROR) { | |
612 *error_details = validate_chlo_result.error_details; | |
613 return validate_chlo_result.error_code; | |
614 } | |
615 | |
616 out->Clear(); | |
617 | |
618 bool x509_supported = false; | |
619 bool x509_ecdsa_supported = false; | |
620 ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported); | |
621 if (!x509_supported && FLAGS_quic_require_x509) { | |
622 *error_details = "Missing or invalid PDMD"; | |
623 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
624 } | |
625 DCHECK(proof_source_.get()); | |
626 string chlo_hash; | |
627 CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash); | |
628 // No need to get a new proof if one was already generated. | |
629 if (!crypto_proof->chain && | |
630 !proof_source_->GetProof( | |
631 server_ip, info.sni.as_string(), primary_config->serialized, version, | |
632 chlo_hash, x509_ecdsa_supported, &crypto_proof->chain, | |
633 &crypto_proof->signature, &crypto_proof->cert_sct)) { | |
634 return QUIC_HANDSHAKE_FAILED; | |
635 } | |
636 | |
637 StringPiece cert_sct; | |
638 if (client_hello.GetStringPiece(kCertificateSCTTag, &cert_sct) && | |
639 cert_sct.empty()) { | |
640 params->sct_supported_by_client = true; | |
641 } | |
642 | |
643 if (!info.reject_reasons.empty() || !requested_config.get()) { | |
644 BuildRejection(version, *primary_config, client_hello, info, | |
645 validate_chlo_result.cached_network_params, | |
646 use_stateless_rejects, server_designated_connection_id, rand, | |
647 compressed_certs_cache, params, *crypto_proof, out); | |
648 return QUIC_NO_ERROR; | |
649 } | |
650 | |
651 if (reject_only) { | |
652 return QUIC_NO_ERROR; | |
653 } | |
654 | |
655 const QuicTag* their_aeads; | |
656 const QuicTag* their_key_exchanges; | |
657 size_t num_their_aeads, num_their_key_exchanges; | |
658 if (client_hello.GetTaglist(kAEAD, &their_aeads, &num_their_aeads) != | |
659 QUIC_NO_ERROR || | |
660 client_hello.GetTaglist(kKEXS, &their_key_exchanges, | |
661 &num_their_key_exchanges) != QUIC_NO_ERROR || | |
662 num_their_aeads != 1 || num_their_key_exchanges != 1) { | |
663 *error_details = "Missing or invalid AEAD or KEXS"; | |
664 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
665 } | |
666 | |
667 size_t key_exchange_index; | |
668 if (!QuicUtils::FindMutualTag(requested_config->aead, their_aeads, | |
669 num_their_aeads, QuicUtils::LOCAL_PRIORITY, | |
670 ¶ms->aead, nullptr) || | |
671 !QuicUtils::FindMutualTag(requested_config->kexs, their_key_exchanges, | |
672 num_their_key_exchanges, | |
673 QuicUtils::LOCAL_PRIORITY, | |
674 ¶ms->key_exchange, &key_exchange_index)) { | |
675 *error_details = "Unsupported AEAD or KEXS"; | |
676 return QUIC_CRYPTO_NO_SUPPORT; | |
677 } | |
678 | |
679 if (!requested_config->tb_key_params.empty()) { | |
680 const QuicTag* their_tbkps; | |
681 size_t num_their_tbkps; | |
682 switch (client_hello.GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) { | |
683 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: | |
684 break; | |
685 case QUIC_NO_ERROR: | |
686 if (QuicUtils::FindMutualTag( | |
687 requested_config->tb_key_params, their_tbkps, num_their_tbkps, | |
688 QuicUtils::LOCAL_PRIORITY, ¶ms->token_binding_key_param, | |
689 nullptr)) { | |
690 break; | |
691 } | |
692 default: | |
693 *error_details = "Invalid Token Binding key parameter"; | |
694 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
695 } | |
696 } | |
697 | |
698 StringPiece public_value; | |
699 if (!client_hello.GetStringPiece(kPUBS, &public_value)) { | |
700 *error_details = "Missing public value"; | |
701 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
702 } | |
703 | |
704 const KeyExchange* key_exchange = | |
705 requested_config->key_exchanges[key_exchange_index]; | |
706 if (!key_exchange->CalculateSharedKey(public_value, | |
707 ¶ms->initial_premaster_secret)) { | |
708 *error_details = "Invalid public value"; | |
709 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
710 } | |
711 | |
712 if (!info.sni.empty()) { | |
713 std::unique_ptr<char[]> sni_tmp(new char[info.sni.length() + 1]); | |
714 memcpy(sni_tmp.get(), info.sni.data(), info.sni.length()); | |
715 sni_tmp[info.sni.length()] = 0; | |
716 params->sni = CryptoUtils::NormalizeHostname(sni_tmp.get()); | |
717 } | |
718 | |
719 string hkdf_suffix; | |
720 const QuicData& client_hello_serialized = client_hello.GetSerialized(); | |
721 hkdf_suffix.reserve(sizeof(connection_id) + client_hello_serialized.length() + | |
722 requested_config->serialized.size()); | |
723 hkdf_suffix.append(reinterpret_cast<char*>(&connection_id), | |
724 sizeof(connection_id)); | |
725 hkdf_suffix.append(client_hello_serialized.data(), | |
726 client_hello_serialized.length()); | |
727 hkdf_suffix.append(requested_config->serialized); | |
728 DCHECK(proof_source_.get()); | |
729 if (crypto_proof->chain->certs.empty()) { | |
730 *error_details = "Failed to get certs"; | |
731 return QUIC_CRYPTO_INTERNAL_ERROR; | |
732 } | |
733 hkdf_suffix.append(crypto_proof->chain->certs.at(0)); | |
734 | |
735 StringPiece cetv_ciphertext; | |
736 if (requested_config->channel_id_enabled && | |
737 client_hello.GetStringPiece(kCETV, &cetv_ciphertext)) { | |
738 CryptoHandshakeMessage client_hello_copy(client_hello); | |
739 client_hello_copy.Erase(kCETV); | |
740 client_hello_copy.Erase(kPAD); | |
741 | |
742 const QuicData& client_hello_copy_serialized = | |
743 client_hello_copy.GetSerialized(); | |
744 string hkdf_input; | |
745 hkdf_input.append(QuicCryptoConfig::kCETVLabel, | |
746 strlen(QuicCryptoConfig::kCETVLabel) + 1); | |
747 hkdf_input.append(reinterpret_cast<char*>(&connection_id), | |
748 sizeof(connection_id)); | |
749 hkdf_input.append(client_hello_copy_serialized.data(), | |
750 client_hello_copy_serialized.length()); | |
751 hkdf_input.append(requested_config->serialized); | |
752 | |
753 CrypterPair crypters; | |
754 if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead, | |
755 info.client_nonce, info.server_nonce, | |
756 hkdf_input, Perspective::IS_SERVER, | |
757 CryptoUtils::Diversification::Never(), | |
758 &crypters, nullptr /* subkey secret */)) { | |
759 *error_details = "Symmetric key setup failed"; | |
760 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; | |
761 } | |
762 | |
763 char plaintext[kMaxPacketSize]; | |
764 size_t plaintext_length = 0; | |
765 const bool success = crypters.decrypter->DecryptPacket( | |
766 kDefaultPathId, 0 /* packet number */, | |
767 StringPiece() /* associated data */, cetv_ciphertext, plaintext, | |
768 &plaintext_length, kMaxPacketSize); | |
769 if (!success) { | |
770 *error_details = "CETV decryption failure"; | |
771 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
772 } | |
773 std::unique_ptr<CryptoHandshakeMessage> cetv( | |
774 CryptoFramer::ParseMessage(StringPiece(plaintext, plaintext_length))); | |
775 if (!cetv.get()) { | |
776 *error_details = "CETV parse error"; | |
777 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
778 } | |
779 | |
780 StringPiece key, signature; | |
781 if (cetv->GetStringPiece(kCIDK, &key) && | |
782 cetv->GetStringPiece(kCIDS, &signature)) { | |
783 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) { | |
784 *error_details = "ChannelID signature failure"; | |
785 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
786 } | |
787 | |
788 params->channel_id = key.as_string(); | |
789 } | |
790 } | |
791 | |
792 string hkdf_input; | |
793 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; | |
794 hkdf_input.reserve(label_len + hkdf_suffix.size()); | |
795 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); | |
796 hkdf_input.append(hkdf_suffix); | |
797 | |
798 string* subkey_secret = ¶ms->initial_subkey_secret; | |
799 CryptoUtils::Diversification diversification = | |
800 CryptoUtils::Diversification::Never(); | |
801 if (version > QUIC_VERSION_32) { | |
802 rand->RandBytes(reinterpret_cast<char*>(out_diversification_nonce), | |
803 sizeof(*out_diversification_nonce)); | |
804 diversification = | |
805 CryptoUtils::Diversification::Now(out_diversification_nonce); | |
806 } | |
807 | |
808 if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead, | |
809 info.client_nonce, info.server_nonce, hkdf_input, | |
810 Perspective::IS_SERVER, diversification, | |
811 ¶ms->initial_crypters, subkey_secret)) { | |
812 *error_details = "Symmetric key setup failed"; | |
813 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; | |
814 } | |
815 | |
816 string forward_secure_public_value; | |
817 if (ephemeral_key_source_.get()) { | |
818 params->forward_secure_premaster_secret = | |
819 ephemeral_key_source_->CalculateForwardSecureKey( | |
820 key_exchange, rand, clock->ApproximateNow(), public_value, | |
821 &forward_secure_public_value); | |
822 } else { | |
823 std::unique_ptr<KeyExchange> forward_secure_key_exchange( | |
824 key_exchange->NewKeyPair(rand)); | |
825 forward_secure_public_value = | |
826 forward_secure_key_exchange->public_value().as_string(); | |
827 if (!forward_secure_key_exchange->CalculateSharedKey( | |
828 public_value, ¶ms->forward_secure_premaster_secret)) { | |
829 *error_details = "Invalid public value"; | |
830 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
831 } | |
832 } | |
833 | |
834 string forward_secure_hkdf_input; | |
835 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; | |
836 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size()); | |
837 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, | |
838 label_len); | |
839 forward_secure_hkdf_input.append(hkdf_suffix); | |
840 | |
841 string shlo_nonce; | |
842 shlo_nonce = NewServerNonce(rand, info.now); | |
843 out->SetStringPiece(kServerNonceTag, shlo_nonce); | |
844 | |
845 if (!CryptoUtils::DeriveKeys( | |
846 params->forward_secure_premaster_secret, params->aead, | |
847 info.client_nonce, | |
848 shlo_nonce.empty() ? info.server_nonce : shlo_nonce, | |
849 forward_secure_hkdf_input, Perspective::IS_SERVER, | |
850 CryptoUtils::Diversification::Never(), | |
851 ¶ms->forward_secure_crypters, ¶ms->subkey_secret)) { | |
852 *error_details = "Symmetric key setup failed"; | |
853 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; | |
854 } | |
855 | |
856 out->set_tag(kSHLO); | |
857 QuicTagVector supported_version_tags; | |
858 for (size_t i = 0; i < supported_versions.size(); ++i) { | |
859 supported_version_tags.push_back( | |
860 QuicVersionToQuicTag(supported_versions[i])); | |
861 } | |
862 out->SetVector(kVER, supported_version_tags); | |
863 out->SetStringPiece( | |
864 kSourceAddressTokenTag, | |
865 NewSourceAddressToken(*requested_config.get(), info.source_address_tokens, | |
866 client_address.address(), rand, info.now, nullptr)); | |
867 QuicSocketAddressCoder address_coder(client_address); | |
868 out->SetStringPiece(kCADR, address_coder.Encode()); | |
869 out->SetStringPiece(kPUBS, forward_secure_public_value); | |
870 | |
871 return QUIC_NO_ERROR; | |
872 } | |
873 | |
874 scoped_refptr<QuicCryptoServerConfig::Config> | |
875 QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid) const { | |
876 // In Chromium, we will dead lock if the lock is held by the current thread. | |
877 // Chromium doesn't have AssertReaderHeld API call. | |
878 // configs_lock_.AssertReaderHeld(); | |
879 | |
880 if (!requested_scid.empty()) { | |
881 ConfigMap::const_iterator it = configs_.find(requested_scid.as_string()); | |
882 if (it != configs_.end()) { | |
883 // We'll use the config that the client requested in order to do | |
884 // key-agreement. | |
885 return scoped_refptr<Config>(it->second); | |
886 } | |
887 } | |
888 | |
889 return scoped_refptr<Config>(); | |
890 } | |
891 | |
892 // ConfigPrimaryTimeLessThan is a comparator that implements "less than" for | |
893 // Config's based on their primary_time. | |
894 // static | |
895 bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan( | |
896 const scoped_refptr<Config>& a, | |
897 const scoped_refptr<Config>& b) { | |
898 if (a->primary_time.IsBefore(b->primary_time) || | |
899 b->primary_time.IsBefore(a->primary_time)) { | |
900 // Primary times differ. | |
901 return a->primary_time.IsBefore(b->primary_time); | |
902 } else if (a->priority != b->priority) { | |
903 // Primary times are equal, sort backwards by priority. | |
904 return a->priority < b->priority; | |
905 } else { | |
906 // Primary times and priorities are equal, sort by config id. | |
907 return a->id < b->id; | |
908 } | |
909 } | |
910 | |
911 void QuicCryptoServerConfig::SelectNewPrimaryConfig( | |
912 const QuicWallTime now) const { | |
913 vector<scoped_refptr<Config>> configs; | |
914 configs.reserve(configs_.size()); | |
915 | |
916 for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end(); | |
917 ++it) { | |
918 // TODO(avd) Exclude expired configs? | |
919 configs.push_back(it->second); | |
920 } | |
921 | |
922 if (configs.empty()) { | |
923 if (primary_config_.get()) { | |
924 QUIC_BUG << "No valid QUIC server config. Keeping the current config."; | |
925 } else { | |
926 QUIC_BUG << "No valid QUIC server config."; | |
927 } | |
928 return; | |
929 } | |
930 | |
931 std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan); | |
932 | |
933 Config* best_candidate = configs[0].get(); | |
934 | |
935 for (size_t i = 0; i < configs.size(); ++i) { | |
936 const scoped_refptr<Config> config(configs[i]); | |
937 if (!config->primary_time.IsAfter(now)) { | |
938 if (config->primary_time.IsAfter(best_candidate->primary_time)) { | |
939 best_candidate = config.get(); | |
940 } | |
941 continue; | |
942 } | |
943 | |
944 // This is the first config with a primary_time in the future. Thus the | |
945 // previous Config should be the primary and this one should determine the | |
946 // next_config_promotion_time_. | |
947 scoped_refptr<Config> new_primary(best_candidate); | |
948 if (i == 0) { | |
949 // We need the primary_time of the next config. | |
950 if (configs.size() > 1) { | |
951 next_config_promotion_time_ = configs[1]->primary_time; | |
952 } else { | |
953 next_config_promotion_time_ = QuicWallTime::Zero(); | |
954 } | |
955 } else { | |
956 next_config_promotion_time_ = config->primary_time; | |
957 } | |
958 | |
959 if (primary_config_.get()) { | |
960 primary_config_->is_primary = false; | |
961 } | |
962 primary_config_ = new_primary; | |
963 new_primary->is_primary = true; | |
964 DVLOG(1) << "New primary config. orbit: " | |
965 << QuicUtils::HexEncode( | |
966 reinterpret_cast<const char*>(primary_config_->orbit), | |
967 kOrbitSize); | |
968 if (primary_config_changed_cb_.get() != nullptr) { | |
969 primary_config_changed_cb_->Run(primary_config_->id); | |
970 } | |
971 | |
972 return; | |
973 } | |
974 | |
975 // All config's primary times are in the past. We should make the most recent | |
976 // and highest priority candidate primary. | |
977 scoped_refptr<Config> new_primary(best_candidate); | |
978 if (primary_config_.get()) { | |
979 primary_config_->is_primary = false; | |
980 } | |
981 primary_config_ = new_primary; | |
982 new_primary->is_primary = true; | |
983 DVLOG(1) << "New primary config. orbit: " | |
984 << QuicUtils::HexEncode( | |
985 reinterpret_cast<const char*>(primary_config_->orbit), | |
986 kOrbitSize) | |
987 << " scid: " << QuicUtils::HexEncode(primary_config_->id); | |
988 next_config_promotion_time_ = QuicWallTime::Zero(); | |
989 if (primary_config_changed_cb_.get() != nullptr) { | |
990 primary_config_changed_cb_->Run(primary_config_->id); | |
991 } | |
992 } | |
993 | |
994 class EvaluateClientHelloCallback : public ProofSource::Callback { | |
995 public: | |
996 EvaluateClientHelloCallback( | |
997 const QuicCryptoServerConfig& config, | |
998 bool found_error, | |
999 const IPAddress& server_ip, | |
1000 QuicVersion version, | |
1001 const uint8_t* primary_orbit, | |
1002 scoped_refptr<QuicCryptoServerConfig::Config> requested_config, | |
1003 scoped_refptr<QuicCryptoServerConfig::Config> primary_config, | |
1004 QuicCryptoProof* crypto_proof, | |
1005 ValidateClientHelloResultCallback::Result* client_hello_state, | |
1006 ValidateClientHelloResultCallback* done_cb) | |
1007 : config_(config), | |
1008 found_error_(found_error), | |
1009 server_ip_(server_ip), | |
1010 version_(version), | |
1011 primary_orbit_(primary_orbit), | |
1012 requested_config_(std::move(requested_config)), | |
1013 primary_config_(std::move(primary_config)), | |
1014 crypto_proof_(crypto_proof), | |
1015 client_hello_state_(client_hello_state), | |
1016 done_cb_(done_cb) {} | |
1017 | |
1018 void Run(bool ok, | |
1019 const scoped_refptr<ProofSource::Chain>& chain, | |
1020 const string& signature, | |
1021 const string& leaf_cert_sct, | |
1022 std::unique_ptr<ProofSource::Details> details) override { | |
1023 if (ok) { | |
1024 crypto_proof_->chain = chain; | |
1025 crypto_proof_->signature = signature; | |
1026 crypto_proof_->cert_sct = leaf_cert_sct; | |
1027 } | |
1028 config_.EvaluateClientHelloAfterGetProof( | |
1029 found_error_, server_ip_, version_, primary_orbit_, requested_config_, | |
1030 primary_config_, crypto_proof_, std::move(details), !ok, | |
1031 client_hello_state_, done_cb_); | |
1032 } | |
1033 | |
1034 private: | |
1035 const QuicCryptoServerConfig& config_; | |
1036 const bool found_error_; | |
1037 const IPAddress& server_ip_; | |
1038 const QuicVersion version_; | |
1039 const uint8_t* primary_orbit_; | |
1040 const scoped_refptr<QuicCryptoServerConfig::Config> requested_config_; | |
1041 const scoped_refptr<QuicCryptoServerConfig::Config> primary_config_; | |
1042 QuicCryptoProof* crypto_proof_; | |
1043 ValidateClientHelloResultCallback::Result* client_hello_state_; | |
1044 ValidateClientHelloResultCallback* done_cb_; | |
1045 }; | |
1046 | |
1047 void QuicCryptoServerConfig::EvaluateClientHello( | |
1048 const IPAddress& server_ip, | |
1049 QuicVersion version, | |
1050 const uint8_t* primary_orbit, | |
1051 scoped_refptr<Config> requested_config, | |
1052 scoped_refptr<Config> primary_config, | |
1053 QuicCryptoProof* crypto_proof, | |
1054 ValidateClientHelloResultCallback::Result* client_hello_state, | |
1055 ValidateClientHelloResultCallback* done_cb) const { | |
1056 ValidateClientHelloHelper helper(client_hello_state, done_cb); | |
1057 | |
1058 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello; | |
1059 ClientHelloInfo* info = &(client_hello_state->info); | |
1060 | |
1061 if (client_hello.size() < kClientHelloMinimumSize) { | |
1062 helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH, | |
1063 "Client hello too small", nullptr); | |
1064 return; | |
1065 } | |
1066 | |
1067 if (client_hello.GetStringPiece(kSNI, &info->sni) && | |
1068 !CryptoUtils::IsValidSNI(info->sni)) { | |
1069 helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, | |
1070 "Invalid SNI name", nullptr); | |
1071 return; | |
1072 } | |
1073 | |
1074 client_hello.GetStringPiece(kUAID, &info->user_agent_id); | |
1075 | |
1076 HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON; | |
1077 StringPiece srct; | |
1078 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { | |
1079 Config& config = requested_config ? *requested_config : *primary_config; | |
1080 source_address_token_error = | |
1081 ParseSourceAddressToken(config, srct, &info->source_address_tokens); | |
1082 | |
1083 if (source_address_token_error == HANDSHAKE_OK) { | |
1084 source_address_token_error = ValidateSourceAddressTokens( | |
1085 info->source_address_tokens, info->client_ip, info->now, | |
1086 &client_hello_state->cached_network_params); | |
1087 } | |
1088 info->valid_source_address_token = | |
1089 (source_address_token_error == HANDSHAKE_OK); | |
1090 } else { | |
1091 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; | |
1092 } | |
1093 | |
1094 if (!requested_config.get()) { | |
1095 StringPiece requested_scid; | |
1096 if (client_hello.GetStringPiece(kSCID, &requested_scid)) { | |
1097 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); | |
1098 } else { | |
1099 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); | |
1100 } | |
1101 // No server config with the requested ID. | |
1102 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr); | |
1103 return; | |
1104 } | |
1105 | |
1106 if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) { | |
1107 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); | |
1108 // Report no client nonce as INCHOATE_HELLO_FAILURE. | |
1109 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr); | |
1110 return; | |
1111 } | |
1112 | |
1113 bool found_error = false; | |
1114 if (source_address_token_error != HANDSHAKE_OK) { | |
1115 info->reject_reasons.push_back(source_address_token_error); | |
1116 // No valid source address token. | |
1117 found_error = true; | |
1118 } | |
1119 | |
1120 bool get_proof_failed = false; | |
1121 bool x509_supported = false; | |
1122 bool x509_ecdsa_supported = false; | |
1123 ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported); | |
1124 string serialized_config = primary_config->serialized; | |
1125 string chlo_hash; | |
1126 CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash); | |
1127 bool need_proof = true; | |
1128 if (FLAGS_quic_refresh_proof) { | |
1129 need_proof = !crypto_proof->chain; | |
1130 } | |
1131 if (FLAGS_enable_async_get_proof) { | |
1132 if (need_proof) { | |
1133 // Make an async call to GetProof and setup the callback to trampoline | |
1134 // back into EvaluateClientHelloAfterGetProof | |
1135 std::unique_ptr<EvaluateClientHelloCallback> cb( | |
1136 new EvaluateClientHelloCallback( | |
1137 *this, found_error, server_ip, version, primary_orbit, | |
1138 requested_config, primary_config, crypto_proof, | |
1139 client_hello_state, done_cb)); | |
1140 proof_source_->GetProof(server_ip, info->sni.as_string(), | |
1141 serialized_config, version, chlo_hash, | |
1142 x509_ecdsa_supported, std::move(cb)); | |
1143 helper.DetachCallback(); | |
1144 return; | |
1145 } | |
1146 } | |
1147 | |
1148 // No need to get a new proof if one was already generated. | |
1149 if (need_proof && | |
1150 !proof_source_->GetProof( | |
1151 server_ip, info->sni.as_string(), serialized_config, version, | |
1152 chlo_hash, x509_ecdsa_supported, &crypto_proof->chain, | |
1153 &crypto_proof->signature, &crypto_proof->cert_sct)) { | |
1154 get_proof_failed = true; | |
1155 } | |
1156 | |
1157 // Details are null because the synchronous version of GetProof does not | |
1158 // return any stats. Eventually the synchronous codepath will be eliminated. | |
1159 EvaluateClientHelloAfterGetProof( | |
1160 found_error, server_ip, version, primary_orbit, requested_config, | |
1161 primary_config, crypto_proof, nullptr /* proof_source_details */, | |
1162 get_proof_failed, client_hello_state, done_cb); | |
1163 helper.DetachCallback(); | |
1164 } | |
1165 | |
1166 void QuicCryptoServerConfig::EvaluateClientHelloAfterGetProof( | |
1167 bool found_error, | |
1168 const IPAddress& server_ip, | |
1169 QuicVersion version, | |
1170 const uint8_t* primary_orbit, | |
1171 scoped_refptr<Config> requested_config, | |
1172 scoped_refptr<Config> primary_config, | |
1173 QuicCryptoProof* crypto_proof, | |
1174 std::unique_ptr<ProofSource::Details> proof_source_details, | |
1175 bool get_proof_failed, | |
1176 ValidateClientHelloResultCallback::Result* client_hello_state, | |
1177 ValidateClientHelloResultCallback* done_cb) const { | |
1178 ValidateClientHelloHelper helper(client_hello_state, done_cb); | |
1179 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello; | |
1180 ClientHelloInfo* info = &(client_hello_state->info); | |
1181 | |
1182 if (get_proof_failed) { | |
1183 found_error = true; | |
1184 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); | |
1185 } | |
1186 | |
1187 if (!ValidateExpectedLeafCertificate(client_hello, *crypto_proof)) { | |
1188 found_error = true; | |
1189 info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE); | |
1190 } | |
1191 | |
1192 if (info->client_nonce.size() != kNonceSize) { | |
1193 info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE); | |
1194 // Invalid client nonce. | |
1195 LOG(ERROR) << "Invalid client nonce: " << client_hello.DebugString(); | |
1196 DVLOG(1) << "Invalid client nonce."; | |
1197 found_error = true; | |
1198 } | |
1199 | |
1200 // Server nonce is optional, and used for key derivation if present. | |
1201 client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce); | |
1202 | |
1203 if (version > QUIC_VERSION_32) { | |
1204 DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher."; | |
1205 // If the server nonce is empty and we're requiring handshake confirmation | |
1206 // for DoS reasons then we must reject the CHLO. | |
1207 if (FLAGS_quic_require_handshake_confirmation && | |
1208 info->server_nonce.empty()) { | |
1209 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE); | |
1210 } | |
1211 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
1212 std::move(proof_source_details)); | |
1213 return; | |
1214 } | |
1215 | |
1216 if (!replay_protection_) { | |
1217 DVLOG(1) << "No replay protection."; | |
1218 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
1219 std::move(proof_source_details)); | |
1220 return; | |
1221 } | |
1222 | |
1223 if (!info->server_nonce.empty()) { | |
1224 // If the server nonce is present, use it to establish uniqueness. | |
1225 HandshakeFailureReason server_nonce_error = | |
1226 ValidateServerNonce(info->server_nonce, info->now); | |
1227 bool is_unique = server_nonce_error == HANDSHAKE_OK; | |
1228 if (!is_unique) { | |
1229 info->reject_reasons.push_back(server_nonce_error); | |
1230 } | |
1231 DVLOG(1) << "Using server nonce, unique: " << is_unique; | |
1232 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
1233 std::move(proof_source_details)); | |
1234 return; | |
1235 } | |
1236 // If we hit this block, the server nonce was empty. If we're requiring | |
1237 // handshake confirmation for DoS reasons and there's no server nonce present, | |
1238 // reject the CHLO. | |
1239 if (FLAGS_quic_require_handshake_confirmation || | |
1240 FLAGS_quic_require_handshake_confirmation_pre33) { | |
1241 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE); | |
1242 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
1243 std::move(proof_source_details)); | |
1244 return; | |
1245 } | |
1246 | |
1247 // We want to contact strike register only if there are no errors because it | |
1248 // is a RPC call and is expensive. | |
1249 if (found_error) { | |
1250 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
1251 std::move(proof_source_details)); | |
1252 return; | |
1253 } | |
1254 | |
1255 // Use the client nonce to establish uniqueness. | |
1256 StrikeRegisterClient* strike_register_client; | |
1257 { | |
1258 base::AutoLock locked(strike_register_client_lock_); | |
1259 strike_register_client = strike_register_client_.get(); | |
1260 } | |
1261 | |
1262 if (!strike_register_client) { | |
1263 // Either a valid server nonces or a strike register is required. | |
1264 // Since neither are present, reject the handshake which will send a | |
1265 // server nonce to the client. | |
1266 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE); | |
1267 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
1268 std::move(proof_source_details)); | |
1269 return; | |
1270 } | |
1271 | |
1272 strike_register_client->VerifyNonceIsValidAndUnique( | |
1273 info->client_nonce, info->now, | |
1274 new VerifyNonceIsValidAndUniqueCallback( | |
1275 client_hello_state, std::move(proof_source_details), done_cb)); | |
1276 helper.DetachCallback(); | |
1277 } | |
1278 | |
1279 bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage( | |
1280 QuicVersion version, | |
1281 StringPiece chlo_hash, | |
1282 const SourceAddressTokens& previous_source_address_tokens, | |
1283 const IPAddress& server_ip, | |
1284 const IPAddress& client_ip, | |
1285 const QuicClock* clock, | |
1286 QuicRandom* rand, | |
1287 QuicCompressedCertsCache* compressed_certs_cache, | |
1288 const QuicCryptoNegotiatedParameters& params, | |
1289 const CachedNetworkParameters* cached_network_params, | |
1290 CryptoHandshakeMessage* out) const { | |
1291 string serialized; | |
1292 string source_address_token; | |
1293 const CommonCertSets* common_cert_sets; | |
1294 { | |
1295 base::AutoLock locked(configs_lock_); | |
1296 serialized = primary_config_->serialized; | |
1297 common_cert_sets = primary_config_->common_cert_sets; | |
1298 source_address_token = NewSourceAddressToken( | |
1299 *primary_config_, previous_source_address_tokens, client_ip, rand, | |
1300 clock->WallNow(), cached_network_params); | |
1301 } | |
1302 | |
1303 out->set_tag(kSCUP); | |
1304 out->SetStringPiece(kSCFG, serialized); | |
1305 out->SetStringPiece(kSourceAddressTokenTag, source_address_token); | |
1306 | |
1307 scoped_refptr<ProofSource::Chain> chain; | |
1308 string signature; | |
1309 string cert_sct; | |
1310 if (!proof_source_->GetProof(server_ip, params.sni, serialized, version, | |
1311 chlo_hash, params.x509_ecdsa_supported, &chain, | |
1312 &signature, &cert_sct)) { | |
1313 DVLOG(1) << "Server: failed to get proof."; | |
1314 return false; | |
1315 } | |
1316 | |
1317 const string compressed = CompressChain( | |
1318 compressed_certs_cache, chain, params.client_common_set_hashes, | |
1319 params.client_cached_cert_hashes, common_cert_sets); | |
1320 | |
1321 out->SetStringPiece(kCertificateTag, compressed); | |
1322 out->SetStringPiece(kPROF, signature); | |
1323 if (params.sct_supported_by_client && enable_serving_sct_) { | |
1324 if (cert_sct.empty()) { | |
1325 DLOG(WARNING) << "SCT is expected but it is empty."; | |
1326 } else { | |
1327 out->SetStringPiece(kCertificateSCTTag, cert_sct); | |
1328 } | |
1329 } | |
1330 return true; | |
1331 } | |
1332 | |
1333 void QuicCryptoServerConfig::BuildServerConfigUpdateMessage( | |
1334 QuicVersion version, | |
1335 StringPiece chlo_hash, | |
1336 const SourceAddressTokens& previous_source_address_tokens, | |
1337 const IPAddress& server_ip, | |
1338 const IPAddress& client_ip, | |
1339 const QuicClock* clock, | |
1340 QuicRandom* rand, | |
1341 QuicCompressedCertsCache* compressed_certs_cache, | |
1342 const QuicCryptoNegotiatedParameters& params, | |
1343 const CachedNetworkParameters* cached_network_params, | |
1344 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const { | |
1345 string serialized; | |
1346 string source_address_token; | |
1347 const CommonCertSets* common_cert_sets; | |
1348 { | |
1349 base::AutoLock locked(configs_lock_); | |
1350 serialized = primary_config_->serialized; | |
1351 common_cert_sets = primary_config_->common_cert_sets; | |
1352 source_address_token = NewSourceAddressToken( | |
1353 *primary_config_, previous_source_address_tokens, client_ip, rand, | |
1354 clock->WallNow(), cached_network_params); | |
1355 } | |
1356 | |
1357 CryptoHandshakeMessage message; | |
1358 message.set_tag(kSCUP); | |
1359 message.SetStringPiece(kSCFG, serialized); | |
1360 message.SetStringPiece(kSourceAddressTokenTag, source_address_token); | |
1361 | |
1362 std::unique_ptr<BuildServerConfigUpdateMessageProofSourceCallback> | |
1363 proof_source_cb(new BuildServerConfigUpdateMessageProofSourceCallback( | |
1364 this, version, compressed_certs_cache, common_cert_sets, params, | |
1365 std::move(message), std::move(cb))); | |
1366 | |
1367 proof_source_->GetProof(server_ip, params.sni, serialized, version, chlo_hash, | |
1368 params.x509_ecdsa_supported, | |
1369 std::move(proof_source_cb)); | |
1370 } | |
1371 | |
1372 QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: | |
1373 ~BuildServerConfigUpdateMessageProofSourceCallback() {} | |
1374 | |
1375 QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: | |
1376 BuildServerConfigUpdateMessageProofSourceCallback( | |
1377 const QuicCryptoServerConfig* config, | |
1378 QuicVersion version, | |
1379 QuicCompressedCertsCache* compressed_certs_cache, | |
1380 const CommonCertSets* common_cert_sets, | |
1381 const QuicCryptoNegotiatedParameters& params, | |
1382 CryptoHandshakeMessage message, | |
1383 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) | |
1384 : config_(config), | |
1385 version_(version), | |
1386 compressed_certs_cache_(compressed_certs_cache), | |
1387 common_cert_sets_(common_cert_sets), | |
1388 client_common_set_hashes_(params.client_common_set_hashes), | |
1389 client_cached_cert_hashes_(params.client_cached_cert_hashes), | |
1390 sct_supported_by_client_(params.sct_supported_by_client), | |
1391 message_(std::move(message)), | |
1392 cb_(std::move(cb)) {} | |
1393 | |
1394 void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: | |
1395 Run(bool ok, | |
1396 const scoped_refptr<ProofSource::Chain>& chain, | |
1397 const string& signature, | |
1398 const string& leaf_cert_sct, | |
1399 std::unique_ptr<ProofSource::Details> details) { | |
1400 config_->FinishBuildServerConfigUpdateMessage( | |
1401 version_, compressed_certs_cache_, common_cert_sets_, | |
1402 client_common_set_hashes_, client_cached_cert_hashes_, | |
1403 sct_supported_by_client_, ok, chain, signature, leaf_cert_sct, | |
1404 std::move(details), std::move(message_), std::move(cb_)); | |
1405 } | |
1406 | |
1407 void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage( | |
1408 QuicVersion version, | |
1409 QuicCompressedCertsCache* compressed_certs_cache, | |
1410 const CommonCertSets* common_cert_sets, | |
1411 const string& client_common_set_hashes, | |
1412 const string& client_cached_cert_hashes, | |
1413 bool sct_supported_by_client, | |
1414 bool ok, | |
1415 const scoped_refptr<ProofSource::Chain>& chain, | |
1416 const string& signature, | |
1417 const string& leaf_cert_sct, | |
1418 std::unique_ptr<ProofSource::Details> details, | |
1419 CryptoHandshakeMessage message, | |
1420 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const { | |
1421 if (!ok) { | |
1422 cb->Run(false, message); | |
1423 return; | |
1424 } | |
1425 | |
1426 const string compressed = | |
1427 CompressChain(compressed_certs_cache, chain, client_common_set_hashes, | |
1428 client_cached_cert_hashes, common_cert_sets); | |
1429 | |
1430 message.SetStringPiece(kCertificateTag, compressed); | |
1431 message.SetStringPiece(kPROF, signature); | |
1432 if (sct_supported_by_client && enable_serving_sct_) { | |
1433 if (leaf_cert_sct.empty()) { | |
1434 DLOG(WARNING) << "SCT is expected but it is empty."; | |
1435 } else { | |
1436 message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct); | |
1437 } | |
1438 } | |
1439 | |
1440 cb->Run(true, message); | |
1441 } | |
1442 | |
1443 void QuicCryptoServerConfig::BuildRejection( | |
1444 QuicVersion version, | |
1445 const Config& config, | |
1446 const CryptoHandshakeMessage& client_hello, | |
1447 const ClientHelloInfo& info, | |
1448 const CachedNetworkParameters& cached_network_params, | |
1449 bool use_stateless_rejects, | |
1450 QuicConnectionId server_designated_connection_id, | |
1451 QuicRandom* rand, | |
1452 QuicCompressedCertsCache* compressed_certs_cache, | |
1453 QuicCryptoNegotiatedParameters* params, | |
1454 const QuicCryptoProof& crypto_proof, | |
1455 CryptoHandshakeMessage* out) const { | |
1456 if (FLAGS_enable_quic_stateless_reject_support && use_stateless_rejects) { | |
1457 DVLOG(1) << "QUIC Crypto server config returning stateless reject " | |
1458 << "with server-designated connection ID " | |
1459 << server_designated_connection_id; | |
1460 out->set_tag(kSREJ); | |
1461 out->SetValue(kRCID, server_designated_connection_id); | |
1462 } else { | |
1463 out->set_tag(kREJ); | |
1464 } | |
1465 out->SetStringPiece(kSCFG, config.serialized); | |
1466 out->SetStringPiece( | |
1467 kSourceAddressTokenTag, | |
1468 NewSourceAddressToken(config, info.source_address_tokens, info.client_ip, | |
1469 rand, info.now, &cached_network_params)); | |
1470 if (replay_protection_) { | |
1471 out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now)); | |
1472 } | |
1473 | |
1474 // Send client the reject reason for debugging purposes. | |
1475 DCHECK_LT(0u, info.reject_reasons.size()); | |
1476 out->SetVector(kRREJ, info.reject_reasons); | |
1477 | |
1478 // The client may have requested a certificate chain. | |
1479 bool x509_supported = false; | |
1480 ParseProofDemand(client_hello, &x509_supported, | |
1481 ¶ms->x509_ecdsa_supported); | |
1482 if (!x509_supported && FLAGS_quic_require_x509) { | |
1483 QUIC_BUG << "x509 certificates not supported in proof demand"; | |
1484 return; | |
1485 } | |
1486 | |
1487 StringPiece client_common_set_hashes; | |
1488 if (client_hello.GetStringPiece(kCCS, &client_common_set_hashes)) { | |
1489 params->client_common_set_hashes = client_common_set_hashes.as_string(); | |
1490 } | |
1491 | |
1492 StringPiece client_cached_cert_hashes; | |
1493 if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) { | |
1494 params->client_cached_cert_hashes = client_cached_cert_hashes.as_string(); | |
1495 } | |
1496 | |
1497 const string compressed = | |
1498 CompressChain(compressed_certs_cache, crypto_proof.chain, | |
1499 params->client_common_set_hashes, | |
1500 params->client_cached_cert_hashes, config.common_cert_sets); | |
1501 | |
1502 // kREJOverheadBytes is a very rough estimate of how much of a REJ | |
1503 // message is taken up by things other than the certificates. | |
1504 // STK: 56 bytes | |
1505 // SNO: 56 bytes | |
1506 // SCFG | |
1507 // SCID: 16 bytes | |
1508 // PUBS: 38 bytes | |
1509 const size_t kREJOverheadBytes = 166; | |
1510 // max_unverified_size is the number of bytes that the certificate chain, | |
1511 // signature, and (optionally) signed certificate timestamp can consume before | |
1512 // we will demand a valid source-address token. | |
1513 const size_t max_unverified_size = | |
1514 client_hello.size() * chlo_multiplier_ - kREJOverheadBytes; | |
1515 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes, | |
1516 "overhead calculation may underflow"); | |
1517 bool should_return_sct = | |
1518 params->sct_supported_by_client && enable_serving_sct_; | |
1519 const size_t sct_size = should_return_sct ? crypto_proof.cert_sct.size() : 0; | |
1520 if (info.valid_source_address_token || | |
1521 crypto_proof.signature.size() + compressed.size() + sct_size < | |
1522 max_unverified_size) { | |
1523 out->SetStringPiece(kCertificateTag, compressed); | |
1524 out->SetStringPiece(kPROF, crypto_proof.signature); | |
1525 if (should_return_sct) { | |
1526 if (crypto_proof.cert_sct.empty()) { | |
1527 DLOG(WARNING) << "SCT is expected but it is empty."; | |
1528 } else { | |
1529 out->SetStringPiece(kCertificateSCTTag, crypto_proof.cert_sct); | |
1530 } | |
1531 } | |
1532 } | |
1533 } | |
1534 | |
1535 string QuicCryptoServerConfig::CompressChain( | |
1536 QuicCompressedCertsCache* compressed_certs_cache, | |
1537 const scoped_refptr<ProofSource::Chain>& chain, | |
1538 const string& client_common_set_hashes, | |
1539 const string& client_cached_cert_hashes, | |
1540 const CommonCertSets* common_sets) { | |
1541 // Check whether the compressed certs is available in the cache. | |
1542 DCHECK(compressed_certs_cache); | |
1543 const string* cached_value = compressed_certs_cache->GetCompressedCert( | |
1544 chain, client_common_set_hashes, client_cached_cert_hashes); | |
1545 if (cached_value) { | |
1546 return *cached_value; | |
1547 } | |
1548 | |
1549 const string compressed = | |
1550 CertCompressor::CompressChain(chain->certs, client_common_set_hashes, | |
1551 client_common_set_hashes, common_sets); | |
1552 | |
1553 // Insert the newly compressed cert to cache. | |
1554 compressed_certs_cache->Insert(chain, client_common_set_hashes, | |
1555 client_cached_cert_hashes, compressed); | |
1556 return compressed; | |
1557 } | |
1558 | |
1559 scoped_refptr<QuicCryptoServerConfig::Config> | |
1560 QuicCryptoServerConfig::ParseConfigProtobuf( | |
1561 QuicServerConfigProtobuf* protobuf) { | |
1562 std::unique_ptr<CryptoHandshakeMessage> msg( | |
1563 CryptoFramer::ParseMessage(protobuf->config())); | |
1564 | |
1565 if (msg->tag() != kSCFG) { | |
1566 LOG(WARNING) << "Server config message has tag " << msg->tag() | |
1567 << " expected " << kSCFG; | |
1568 return nullptr; | |
1569 } | |
1570 | |
1571 scoped_refptr<Config> config(new Config); | |
1572 config->serialized = protobuf->config(); | |
1573 | |
1574 if (!protobuf->has_source_address_token_secret_override()) { | |
1575 // Use the default boxer. | |
1576 config->source_address_token_boxer = &default_source_address_token_boxer_; | |
1577 } else { | |
1578 // Create override boxer instance. | |
1579 CryptoSecretBoxer* boxer = new CryptoSecretBoxer; | |
1580 boxer->SetKeys({DeriveSourceAddressTokenKey( | |
1581 protobuf->source_address_token_secret_override())}); | |
1582 config->source_address_token_boxer_storage.reset(boxer); | |
1583 config->source_address_token_boxer = boxer; | |
1584 } | |
1585 | |
1586 if (protobuf->has_primary_time()) { | |
1587 config->primary_time = | |
1588 QuicWallTime::FromUNIXSeconds(protobuf->primary_time()); | |
1589 } | |
1590 | |
1591 config->priority = protobuf->priority(); | |
1592 | |
1593 StringPiece scid; | |
1594 if (!msg->GetStringPiece(kSCID, &scid)) { | |
1595 LOG(WARNING) << "Server config message is missing SCID"; | |
1596 return nullptr; | |
1597 } | |
1598 config->id = scid.as_string(); | |
1599 | |
1600 const QuicTag* aead_tags; | |
1601 size_t aead_len; | |
1602 if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) { | |
1603 LOG(WARNING) << "Server config message is missing AEAD"; | |
1604 return nullptr; | |
1605 } | |
1606 config->aead = vector<QuicTag>(aead_tags, aead_tags + aead_len); | |
1607 | |
1608 const QuicTag* kexs_tags; | |
1609 size_t kexs_len; | |
1610 if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) { | |
1611 LOG(WARNING) << "Server config message is missing KEXS"; | |
1612 return nullptr; | |
1613 } | |
1614 | |
1615 const QuicTag* tbkp_tags; | |
1616 size_t tbkp_len; | |
1617 QuicErrorCode err; | |
1618 if ((err = msg->GetTaglist(kTBKP, &tbkp_tags, &tbkp_len)) != | |
1619 QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND && | |
1620 err != QUIC_NO_ERROR) { | |
1621 LOG(WARNING) << "Server config message is missing or has invalid TBKP"; | |
1622 return nullptr; | |
1623 } | |
1624 config->tb_key_params = vector<QuicTag>(tbkp_tags, tbkp_tags + tbkp_len); | |
1625 | |
1626 StringPiece orbit; | |
1627 if (!msg->GetStringPiece(kORBT, &orbit)) { | |
1628 LOG(WARNING) << "Server config message is missing ORBT"; | |
1629 return nullptr; | |
1630 } | |
1631 | |
1632 if (orbit.size() != kOrbitSize) { | |
1633 LOG(WARNING) << "Orbit value in server config is the wrong length." | |
1634 " Got " | |
1635 << orbit.size() << " want " << kOrbitSize; | |
1636 return nullptr; | |
1637 } | |
1638 static_assert(sizeof(config->orbit) == kOrbitSize, | |
1639 "orbit has incorrect size"); | |
1640 memcpy(config->orbit, orbit.data(), sizeof(config->orbit)); | |
1641 | |
1642 { | |
1643 StrikeRegisterClient* strike_register_client; | |
1644 { | |
1645 base::AutoLock locked(strike_register_client_lock_); | |
1646 strike_register_client = strike_register_client_.get(); | |
1647 } | |
1648 | |
1649 if (strike_register_client != nullptr && | |
1650 !strike_register_client->IsKnownOrbit(orbit)) { | |
1651 LOG(WARNING) | |
1652 << "Rejecting server config with orbit that the strike register " | |
1653 "client doesn't know about."; | |
1654 return nullptr; | |
1655 } | |
1656 } | |
1657 | |
1658 if (kexs_len != protobuf->key_size()) { | |
1659 LOG(WARNING) << "Server config has " << kexs_len | |
1660 << " key exchange methods configured, but " | |
1661 << protobuf->key_size() << " private keys"; | |
1662 return nullptr; | |
1663 } | |
1664 | |
1665 const QuicTag* proof_demand_tags; | |
1666 size_t num_proof_demand_tags; | |
1667 if (msg->GetTaglist(kPDMD, &proof_demand_tags, &num_proof_demand_tags) == | |
1668 QUIC_NO_ERROR) { | |
1669 for (size_t i = 0; i < num_proof_demand_tags; i++) { | |
1670 if (proof_demand_tags[i] == kCHID) { | |
1671 config->channel_id_enabled = true; | |
1672 break; | |
1673 } | |
1674 } | |
1675 } | |
1676 | |
1677 for (size_t i = 0; i < kexs_len; i++) { | |
1678 const QuicTag tag = kexs_tags[i]; | |
1679 string private_key; | |
1680 | |
1681 config->kexs.push_back(tag); | |
1682 | |
1683 for (size_t j = 0; j < protobuf->key_size(); j++) { | |
1684 const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i); | |
1685 if (key.tag() == tag) { | |
1686 private_key = key.private_key(); | |
1687 break; | |
1688 } | |
1689 } | |
1690 | |
1691 if (private_key.empty()) { | |
1692 LOG(WARNING) << "Server config contains key exchange method without " | |
1693 "corresponding private key: " | |
1694 << tag; | |
1695 return nullptr; | |
1696 } | |
1697 | |
1698 std::unique_ptr<KeyExchange> ka; | |
1699 switch (tag) { | |
1700 case kC255: | |
1701 ka.reset(Curve25519KeyExchange::New(private_key)); | |
1702 if (!ka.get()) { | |
1703 LOG(WARNING) << "Server config contained an invalid curve25519" | |
1704 " private key."; | |
1705 return nullptr; | |
1706 } | |
1707 break; | |
1708 case kP256: | |
1709 ka.reset(P256KeyExchange::New(private_key)); | |
1710 if (!ka.get()) { | |
1711 LOG(WARNING) << "Server config contained an invalid P-256" | |
1712 " private key."; | |
1713 return nullptr; | |
1714 } | |
1715 break; | |
1716 default: | |
1717 LOG(WARNING) << "Server config message contains unknown key exchange " | |
1718 "method: " | |
1719 << tag; | |
1720 return nullptr; | |
1721 } | |
1722 | |
1723 for (const KeyExchange* key_exchange : config->key_exchanges) { | |
1724 if (key_exchange->tag() == tag) { | |
1725 LOG(WARNING) << "Duplicate key exchange in config: " << tag; | |
1726 return nullptr; | |
1727 } | |
1728 } | |
1729 | |
1730 config->key_exchanges.push_back(ka.release()); | |
1731 } | |
1732 | |
1733 return config; | |
1734 } | |
1735 | |
1736 void QuicCryptoServerConfig::SetEphemeralKeySource( | |
1737 EphemeralKeySource* ephemeral_key_source) { | |
1738 ephemeral_key_source_.reset(ephemeral_key_source); | |
1739 } | |
1740 | |
1741 void QuicCryptoServerConfig::SetStrikeRegisterClient( | |
1742 StrikeRegisterClient* strike_register_client) { | |
1743 base::AutoLock locker(strike_register_client_lock_); | |
1744 DCHECK(!strike_register_client_.get()); | |
1745 strike_register_client_.reset(strike_register_client); | |
1746 } | |
1747 | |
1748 void QuicCryptoServerConfig::set_replay_protection(bool on) { | |
1749 replay_protection_ = on; | |
1750 } | |
1751 | |
1752 void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) { | |
1753 chlo_multiplier_ = multiplier; | |
1754 } | |
1755 | |
1756 void QuicCryptoServerConfig::set_strike_register_no_startup_period() { | |
1757 base::AutoLock locker(strike_register_client_lock_); | |
1758 DCHECK(!strike_register_client_.get()); | |
1759 strike_register_no_startup_period_ = true; | |
1760 } | |
1761 | |
1762 void QuicCryptoServerConfig::set_strike_register_max_entries( | |
1763 uint32_t max_entries) { | |
1764 base::AutoLock locker(strike_register_client_lock_); | |
1765 DCHECK(!strike_register_client_.get()); | |
1766 strike_register_max_entries_ = max_entries; | |
1767 } | |
1768 | |
1769 void QuicCryptoServerConfig::set_strike_register_window_secs( | |
1770 uint32_t window_secs) { | |
1771 base::AutoLock locker(strike_register_client_lock_); | |
1772 DCHECK(!strike_register_client_.get()); | |
1773 strike_register_window_secs_ = window_secs; | |
1774 } | |
1775 | |
1776 void QuicCryptoServerConfig::set_source_address_token_future_secs( | |
1777 uint32_t future_secs) { | |
1778 source_address_token_future_secs_ = future_secs; | |
1779 } | |
1780 | |
1781 void QuicCryptoServerConfig::set_source_address_token_lifetime_secs( | |
1782 uint32_t lifetime_secs) { | |
1783 source_address_token_lifetime_secs_ = lifetime_secs; | |
1784 } | |
1785 | |
1786 void QuicCryptoServerConfig::set_server_nonce_strike_register_max_entries( | |
1787 uint32_t max_entries) { | |
1788 DCHECK(!server_nonce_strike_register_.get()); | |
1789 server_nonce_strike_register_max_entries_ = max_entries; | |
1790 } | |
1791 | |
1792 void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs( | |
1793 uint32_t window_secs) { | |
1794 DCHECK(!server_nonce_strike_register_.get()); | |
1795 server_nonce_strike_register_window_secs_ = window_secs; | |
1796 } | |
1797 | |
1798 void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) { | |
1799 enable_serving_sct_ = enable_serving_sct; | |
1800 } | |
1801 | |
1802 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb( | |
1803 PrimaryConfigChangedCallback* cb) { | |
1804 base::AutoLock locked(configs_lock_); | |
1805 primary_config_changed_cb_.reset(cb); | |
1806 } | |
1807 | |
1808 string QuicCryptoServerConfig::NewSourceAddressToken( | |
1809 const Config& config, | |
1810 const SourceAddressTokens& previous_tokens, | |
1811 const IPAddress& ip, | |
1812 QuicRandom* rand, | |
1813 QuicWallTime now, | |
1814 const CachedNetworkParameters* cached_network_params) const { | |
1815 SourceAddressTokens source_address_tokens; | |
1816 SourceAddressToken* source_address_token = source_address_tokens.add_tokens(); | |
1817 source_address_token->set_ip(IPAddressToPackedString(DualstackIPAddress(ip))); | |
1818 source_address_token->set_timestamp(now.ToUNIXSeconds()); | |
1819 if (cached_network_params != nullptr) { | |
1820 *(source_address_token->mutable_cached_network_parameters()) = | |
1821 *cached_network_params; | |
1822 } | |
1823 | |
1824 // Append previous tokens. | |
1825 for (const SourceAddressToken& token : previous_tokens.tokens()) { | |
1826 if (source_address_tokens.tokens_size() > kMaxTokenAddresses) { | |
1827 break; | |
1828 } | |
1829 | |
1830 if (token.ip() == source_address_token->ip()) { | |
1831 // It's for the same IP address. | |
1832 continue; | |
1833 } | |
1834 | |
1835 if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) { | |
1836 continue; | |
1837 } | |
1838 | |
1839 *(source_address_tokens.add_tokens()) = token; | |
1840 } | |
1841 | |
1842 return config.source_address_token_boxer->Box( | |
1843 rand, source_address_tokens.SerializeAsString()); | |
1844 } | |
1845 | |
1846 int QuicCryptoServerConfig::NumberOfConfigs() const { | |
1847 base::AutoLock locked(configs_lock_); | |
1848 return configs_.size(); | |
1849 } | |
1850 | |
1851 HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken( | |
1852 const Config& config, | |
1853 StringPiece token, | |
1854 SourceAddressTokens* tokens) const { | |
1855 string storage; | |
1856 StringPiece plaintext; | |
1857 if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) { | |
1858 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE; | |
1859 } | |
1860 | |
1861 if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) { | |
1862 // Some clients might still be using the old source token format so | |
1863 // attempt to parse that format. | |
1864 // TODO(rch): remove this code once the new format is ubiquitous. | |
1865 SourceAddressToken source_address_token; | |
1866 if (!source_address_token.ParseFromArray(plaintext.data(), | |
1867 plaintext.size())) { | |
1868 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE; | |
1869 } | |
1870 *tokens->add_tokens() = source_address_token; | |
1871 } | |
1872 | |
1873 return HANDSHAKE_OK; | |
1874 } | |
1875 | |
1876 HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens( | |
1877 const SourceAddressTokens& source_address_tokens, | |
1878 const IPAddress& ip, | |
1879 QuicWallTime now, | |
1880 CachedNetworkParameters* cached_network_params) const { | |
1881 HandshakeFailureReason reason = | |
1882 SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE; | |
1883 for (const SourceAddressToken& token : source_address_tokens.tokens()) { | |
1884 reason = ValidateSingleSourceAddressToken(token, ip, now); | |
1885 if (reason == HANDSHAKE_OK) { | |
1886 if (token.has_cached_network_parameters()) { | |
1887 *cached_network_params = token.cached_network_parameters(); | |
1888 } | |
1889 break; | |
1890 } | |
1891 } | |
1892 return reason; | |
1893 } | |
1894 | |
1895 HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken( | |
1896 const SourceAddressToken& source_address_token, | |
1897 const IPAddress& ip, | |
1898 QuicWallTime now) const { | |
1899 if (source_address_token.ip() != | |
1900 IPAddressToPackedString(DualstackIPAddress(ip))) { | |
1901 // It's for a different IP address. | |
1902 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE; | |
1903 } | |
1904 | |
1905 return ValidateSourceAddressTokenTimestamp(source_address_token, now); | |
1906 } | |
1907 | |
1908 HandshakeFailureReason | |
1909 QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp( | |
1910 const SourceAddressToken& source_address_token, | |
1911 QuicWallTime now) const { | |
1912 const QuicWallTime timestamp( | |
1913 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp())); | |
1914 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp)); | |
1915 | |
1916 if (now.IsBefore(timestamp) && | |
1917 delta.ToSeconds() > source_address_token_future_secs_) { | |
1918 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE; | |
1919 } | |
1920 | |
1921 if (now.IsAfter(timestamp) && | |
1922 delta.ToSeconds() > source_address_token_lifetime_secs_) { | |
1923 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE; | |
1924 } | |
1925 | |
1926 return HANDSHAKE_OK; | |
1927 } | |
1928 | |
1929 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server | |
1930 // nonce. | |
1931 static const size_t kServerNoncePlaintextSize = | |
1932 4 /* timestamp */ + 20 /* random bytes */; | |
1933 | |
1934 string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand, | |
1935 QuicWallTime now) const { | |
1936 const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds()); | |
1937 | |
1938 uint8_t server_nonce[kServerNoncePlaintextSize]; | |
1939 static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small"); | |
1940 server_nonce[0] = static_cast<uint8_t>(timestamp >> 24); | |
1941 server_nonce[1] = static_cast<uint8_t>(timestamp >> 16); | |
1942 server_nonce[2] = static_cast<uint8_t>(timestamp >> 8); | |
1943 server_nonce[3] = static_cast<uint8_t>(timestamp); | |
1944 rand->RandBytes(&server_nonce[sizeof(timestamp)], | |
1945 sizeof(server_nonce) - sizeof(timestamp)); | |
1946 | |
1947 return server_nonce_boxer_.Box( | |
1948 rand, | |
1949 StringPiece(reinterpret_cast<char*>(server_nonce), sizeof(server_nonce))); | |
1950 } | |
1951 | |
1952 HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce( | |
1953 StringPiece token, | |
1954 QuicWallTime now) const { | |
1955 string storage; | |
1956 StringPiece plaintext; | |
1957 if (!server_nonce_boxer_.Unbox(token, &storage, &plaintext)) { | |
1958 return SERVER_NONCE_DECRYPTION_FAILURE; | |
1959 } | |
1960 | |
1961 // plaintext contains: | |
1962 // uint32_t timestamp | |
1963 // uint8_t[20] random bytes | |
1964 | |
1965 if (plaintext.size() != kServerNoncePlaintextSize) { | |
1966 // This should never happen because the value decrypted correctly. | |
1967 QUIC_BUG << "Seemingly valid server nonce had incorrect length."; | |
1968 return SERVER_NONCE_INVALID_FAILURE; | |
1969 } | |
1970 | |
1971 uint8_t server_nonce[32]; | |
1972 memcpy(server_nonce, plaintext.data(), 4); | |
1973 memcpy(server_nonce + 4, server_nonce_orbit_, sizeof(server_nonce_orbit_)); | |
1974 memcpy(server_nonce + 4 + sizeof(server_nonce_orbit_), plaintext.data() + 4, | |
1975 20); | |
1976 static_assert(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce), | |
1977 "bad nonce buffer length"); | |
1978 | |
1979 InsertStatus nonce_error; | |
1980 { | |
1981 base::AutoLock auto_lock(server_nonce_strike_register_lock_); | |
1982 if (server_nonce_strike_register_.get() == nullptr) { | |
1983 server_nonce_strike_register_.reset(new StrikeRegister( | |
1984 server_nonce_strike_register_max_entries_, | |
1985 static_cast<uint32_t>(now.ToUNIXSeconds()), | |
1986 server_nonce_strike_register_window_secs_, server_nonce_orbit_, | |
1987 StrikeRegister::NO_STARTUP_PERIOD_NEEDED)); | |
1988 } | |
1989 nonce_error = server_nonce_strike_register_->Insert( | |
1990 server_nonce, static_cast<uint32_t>(now.ToUNIXSeconds())); | |
1991 } | |
1992 | |
1993 switch (nonce_error) { | |
1994 case NONCE_OK: | |
1995 return HANDSHAKE_OK; | |
1996 case NONCE_INVALID_FAILURE: | |
1997 case NONCE_INVALID_ORBIT_FAILURE: | |
1998 return SERVER_NONCE_INVALID_FAILURE; | |
1999 case NONCE_NOT_UNIQUE_FAILURE: | |
2000 return SERVER_NONCE_NOT_UNIQUE_FAILURE; | |
2001 case NONCE_INVALID_TIME_FAILURE: | |
2002 return SERVER_NONCE_INVALID_TIME_FAILURE; | |
2003 case NONCE_UNKNOWN_FAILURE: | |
2004 case STRIKE_REGISTER_TIMEOUT: | |
2005 case STRIKE_REGISTER_FAILURE: | |
2006 default: | |
2007 QUIC_BUG << "Unexpected server nonce error: " << nonce_error; | |
2008 return SERVER_NONCE_NOT_UNIQUE_FAILURE; | |
2009 } | |
2010 } | |
2011 | |
2012 bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate( | |
2013 const CryptoHandshakeMessage& client_hello, | |
2014 const QuicCryptoProof& crypto_proof) const { | |
2015 if (crypto_proof.chain->certs.empty()) { | |
2016 return false; | |
2017 } | |
2018 | |
2019 uint64_t hash_from_client; | |
2020 if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) { | |
2021 return false; | |
2022 } | |
2023 return CryptoUtils::ComputeLeafCertHash(crypto_proof.chain->certs.at(0)) == | |
2024 hash_from_client; | |
2025 } | |
2026 | |
2027 void QuicCryptoServerConfig::ParseProofDemand( | |
2028 const CryptoHandshakeMessage& client_hello, | |
2029 bool* x509_supported, | |
2030 bool* x509_ecdsa_supported) const { | |
2031 const QuicTag* their_proof_demands; | |
2032 size_t num_their_proof_demands; | |
2033 | |
2034 if (client_hello.GetTaglist(kPDMD, &their_proof_demands, | |
2035 &num_their_proof_demands) != QUIC_NO_ERROR) { | |
2036 return; | |
2037 } | |
2038 | |
2039 *x509_supported = false; | |
2040 for (size_t i = 0; i < num_their_proof_demands; i++) { | |
2041 switch (their_proof_demands[i]) { | |
2042 case kX509: | |
2043 *x509_supported = true; | |
2044 *x509_ecdsa_supported = true; | |
2045 break; | |
2046 case kX59R: | |
2047 *x509_supported = true; | |
2048 break; | |
2049 } | |
2050 } | |
2051 } | |
2052 | |
2053 QuicCryptoServerConfig::Config::Config() | |
2054 : channel_id_enabled(false), | |
2055 is_primary(false), | |
2056 primary_time(QuicWallTime::Zero()), | |
2057 priority(0), | |
2058 source_address_token_boxer(nullptr) {} | |
2059 | |
2060 QuicCryptoServerConfig::Config::~Config() { | |
2061 STLDeleteElements(&key_exchanges); | |
2062 } | |
2063 | |
2064 QuicCryptoProof::QuicCryptoProof() {} | |
2065 QuicCryptoProof::~QuicCryptoProof() {} | |
2066 } // namespace net | |
OLD | NEW |