blob: 7cd97610d30b17b1a5e871c057d29c19dd585101 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
6
7#include <algorithm>
8#include <cstdlib>
9#include <memory>
vasilvv872e7a32019-03-12 16:42:44 -070010#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050011
QUICHE teama6ef0a62019-03-07 20:34:33 -050012#include "third_party/boringssl/src/include/openssl/sha.h"
13#include "third_party/boringssl/src/include/openssl/ssl.h"
14#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter.h"
15#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h"
16#include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h"
17#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h"
18#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h"
19#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
20#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
21#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
22#include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h"
23#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
24#include "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h"
25#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
26#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
27#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
28#include "net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h"
29#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
30#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.pb.h"
31#include "net/third_party/quiche/src/quic/core/proto/source_address_token.pb.h"
32#include "net/third_party/quiche/src/quic/core/quic_packets.h"
33#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h"
34#include "net/third_party/quiche/src/quic/core/quic_types.h"
35#include "net/third_party/quiche/src/quic/core/quic_utils.h"
36#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
37#include "net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h"
38#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
39#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
40#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
41#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
42#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
43#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
44#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
45#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
46#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050047#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
48#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
49
50namespace quic {
51
52namespace {
53
54// kMultiplier is the multiple of the CHLO message size that a REJ message
55// must stay under when the client doesn't present a valid source-address
56// token. This is used to protect QUIC from amplification attacks.
57// TODO(rch): Reduce this to 2 again once b/25933682 is fixed.
58const size_t kMultiplier = 3;
59
60const int kMaxTokenAddresses = 4;
61
vasilvvc48c8712019-03-11 13:38:16 -070062std::string DeriveSourceAddressTokenKey(
QUICHE teama6ef0a62019-03-07 20:34:33 -050063 QuicStringPiece source_address_token_secret) {
64 QuicHKDF hkdf(source_address_token_secret, QuicStringPiece() /* no salt */,
65 "QUIC source address token key",
66 CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */,
67 0 /* no subkey secret */);
vasilvvc48c8712019-03-11 13:38:16 -070068 return std::string(hkdf.server_write_key());
QUICHE teama6ef0a62019-03-07 20:34:33 -050069}
70
71// Default source for creating KeyExchange objects.
72class DefaultKeyExchangeSource : public KeyExchangeSource {
73 public:
74 DefaultKeyExchangeSource() = default;
75 ~DefaultKeyExchangeSource() override = default;
76
QUICHE teamfe1aca62019-03-14 13:39:01 -070077 std::unique_ptr<AsynchronousKeyExchange> Create(
78 std::string server_config_id,
QUICHE teamf03456c2019-03-21 08:54:47 -070079 bool /* is_fallback */,
QUICHE teamfe1aca62019-03-14 13:39:01 -070080 QuicTag type,
81 QuicStringPiece private_key) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -050082 if (private_key.empty()) {
83 QUIC_LOG(WARNING) << "Server config contains key exchange method without "
QUICHE teamfe1aca62019-03-14 13:39:01 -070084 "corresponding private key of type "
85 << QuicTagToString(type);
QUICHE teama6ef0a62019-03-07 20:34:33 -050086 return nullptr;
87 }
88
QUICHE teamfe1aca62019-03-14 13:39:01 -070089 std::unique_ptr<SynchronousKeyExchange> ka =
90 CreateLocalSynchronousKeyExchange(type, private_key);
91 if (!ka) {
92 QUIC_LOG(WARNING) << "Failed to create key exchange method of type "
93 << QuicTagToString(type);
QUICHE teama6ef0a62019-03-07 20:34:33 -050094 }
95 return ka;
96 }
97};
98
QUICHE teame29fcd62019-03-15 13:54:47 -070099// Returns true if the PDMD field from the client hello demands an X509
100// certificate.
101bool ClientDemandsX509Proof(const CryptoHandshakeMessage& client_hello) {
102 QuicTagVector their_proof_demands;
103
104 if (client_hello.GetTaglist(kPDMD, &their_proof_demands) != QUIC_NO_ERROR) {
105 return false;
106 }
107
108 for (const QuicTag tag : their_proof_demands) {
109 if (tag == kX509) {
110 return true;
111 }
112 }
113 return false;
114}
115
QUICHE teama6ef0a62019-03-07 20:34:33 -0500116} // namespace
117
118// static
119std::unique_ptr<KeyExchangeSource> KeyExchangeSource::Default() {
120 return QuicMakeUnique<DefaultKeyExchangeSource>();
121}
122
123class ValidateClientHelloHelper {
124 public:
125 // Note: stores a pointer to a unique_ptr, and std::moves the unique_ptr when
126 // ValidationComplete is called.
127 ValidateClientHelloHelper(
128 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
129 result,
130 std::unique_ptr<ValidateClientHelloResultCallback>* done_cb)
131 : result_(std::move(result)), done_cb_(done_cb) {}
132 ValidateClientHelloHelper(const ValidateClientHelloHelper&) = delete;
133 ValidateClientHelloHelper& operator=(const ValidateClientHelloHelper&) =
134 delete;
135
136 ~ValidateClientHelloHelper() {
137 QUIC_BUG_IF(done_cb_ != nullptr)
138 << "Deleting ValidateClientHelloHelper with a pending callback.";
139 }
140
141 void ValidationComplete(
142 QuicErrorCode error_code,
143 const char* error_details,
144 std::unique_ptr<ProofSource::Details> proof_source_details) {
145 result_->error_code = error_code;
146 result_->error_details = error_details;
147 (*done_cb_)->Run(std::move(result_), std::move(proof_source_details));
148 DetachCallback();
149 }
150
151 void DetachCallback() {
152 QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached.";
153 done_cb_ = nullptr;
154 }
155
156 private:
157 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
158 result_;
159 std::unique_ptr<ValidateClientHelloResultCallback>* done_cb_;
160};
161
162// static
163const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
164
165ClientHelloInfo::ClientHelloInfo(const QuicIpAddress& in_client_ip,
166 QuicWallTime in_now)
167 : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {}
168
169ClientHelloInfo::ClientHelloInfo(const ClientHelloInfo& other) = default;
170
171ClientHelloInfo::~ClientHelloInfo() {}
172
173PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {}
174
175PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {}
176
177ValidateClientHelloResultCallback::Result::Result(
178 const CryptoHandshakeMessage& in_client_hello,
179 QuicIpAddress in_client_ip,
180 QuicWallTime in_now)
181 : client_hello(in_client_hello),
182 info(in_client_ip, in_now),
183 error_code(QUIC_NO_ERROR) {}
184
185ValidateClientHelloResultCallback::Result::~Result() {}
186
187ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {}
188
189ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {}
190
191ProcessClientHelloResultCallback::ProcessClientHelloResultCallback() {}
192
193ProcessClientHelloResultCallback::~ProcessClientHelloResultCallback() {}
194
195QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
196 : expiry_time(QuicWallTime::Zero()),
197 channel_id_enabled(false),
198 p256(false) {}
199
200QuicCryptoServerConfig::ConfigOptions::ConfigOptions(
201 const ConfigOptions& other) = default;
202
203QuicCryptoServerConfig::ConfigOptions::~ConfigOptions() {}
204
QUICHE team4dae8412019-03-18 13:11:00 -0700205QuicCryptoServerConfig::ProcessClientHelloContext::
206 ~ProcessClientHelloContext() {
207 if (done_cb_ != nullptr) {
nharperff86db32019-05-08 10:38:23 -0700208 QUIC_LOG(WARNING)
QUICHE team4dae8412019-03-18 13:11:00 -0700209 << "Deleting ProcessClientHelloContext with a pending callback.";
210 }
211}
212
213void QuicCryptoServerConfig::ProcessClientHelloContext::Fail(
214 QuicErrorCode error,
215 const std::string& error_details) {
216 done_cb_->Run(error, error_details, nullptr, nullptr, nullptr);
217 done_cb_ = nullptr;
218}
219
220void QuicCryptoServerConfig::ProcessClientHelloContext::Succeed(
221 std::unique_ptr<CryptoHandshakeMessage> message,
222 std::unique_ptr<DiversificationNonce> diversification_nonce,
223 std::unique_ptr<ProofSource::Details> proof_source_details) {
224 done_cb_->Run(QUIC_NO_ERROR, std::string(), std::move(message),
225 std::move(diversification_nonce),
226 std::move(proof_source_details));
227 done_cb_ = nullptr;
228}
229
QUICHE teama6ef0a62019-03-07 20:34:33 -0500230QuicCryptoServerConfig::QuicCryptoServerConfig(
231 QuicStringPiece source_address_token_secret,
232 QuicRandom* server_nonce_entropy,
233 std::unique_ptr<ProofSource> proof_source,
234 std::unique_ptr<KeyExchangeSource> key_exchange_source,
235 bssl::UniquePtr<SSL_CTX> ssl_ctx)
236 : replay_protection_(true),
237 chlo_multiplier_(kMultiplier),
238 configs_lock_(),
239 primary_config_(nullptr),
240 next_config_promotion_time_(QuicWallTime::Zero()),
241 proof_source_(std::move(proof_source)),
242 key_exchange_source_(std::move(key_exchange_source)),
243 ssl_ctx_(std::move(ssl_ctx)),
244 source_address_token_future_secs_(3600),
245 source_address_token_lifetime_secs_(86400),
246 enable_serving_sct_(false),
247 rejection_observer_(nullptr),
248 pad_rej_(true),
249 pad_shlo_(true),
250 validate_chlo_size_(true),
251 validate_source_address_token_(true) {
252 DCHECK(proof_source_.get());
253 source_address_token_boxer_.SetKeys(
254 {DeriveSourceAddressTokenKey(source_address_token_secret)});
255
256 // Generate a random key and orbit for server nonces.
257 server_nonce_entropy->RandBytes(server_nonce_orbit_,
258 sizeof(server_nonce_orbit_));
259 const size_t key_size = server_nonce_boxer_.GetKeySize();
260 std::unique_ptr<uint8_t[]> key_bytes(new uint8_t[key_size]);
261 server_nonce_entropy->RandBytes(key_bytes.get(), key_size);
262
263 server_nonce_boxer_.SetKeys(
vasilvvc48c8712019-03-11 13:38:16 -0700264 {std::string(reinterpret_cast<char*>(key_bytes.get()), key_size)});
QUICHE teama6ef0a62019-03-07 20:34:33 -0500265}
266
267QuicCryptoServerConfig::~QuicCryptoServerConfig() {}
268
269// static
QUICHE teambbaa8be2019-03-21 12:54:17 -0700270QuicServerConfigProtobuf QuicCryptoServerConfig::GenerateConfig(
271 QuicRandom* rand,
272 const QuicClock* clock,
273 const ConfigOptions& options) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500274 CryptoHandshakeMessage msg;
275
vasilvvc48c8712019-03-11 13:38:16 -0700276 const std::string curve25519_private_key =
QUICHE teama6ef0a62019-03-07 20:34:33 -0500277 Curve25519KeyExchange::NewPrivateKey(rand);
QUICHE teamfe1aca62019-03-14 13:39:01 -0700278 std::unique_ptr<Curve25519KeyExchange> curve25519 =
279 Curve25519KeyExchange::New(curve25519_private_key);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500280 QuicStringPiece curve25519_public_value = curve25519->public_value();
281
vasilvvc48c8712019-03-11 13:38:16 -0700282 std::string encoded_public_values;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283 // First three bytes encode the length of the public value.
284 DCHECK_LT(curve25519_public_value.size(), (1U << 24));
285 encoded_public_values.push_back(
286 static_cast<char>(curve25519_public_value.size()));
287 encoded_public_values.push_back(
288 static_cast<char>(curve25519_public_value.size() >> 8));
289 encoded_public_values.push_back(
290 static_cast<char>(curve25519_public_value.size() >> 16));
291 encoded_public_values.append(curve25519_public_value.data(),
292 curve25519_public_value.size());
293
vasilvvc48c8712019-03-11 13:38:16 -0700294 std::string p256_private_key;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295 if (options.p256) {
296 p256_private_key = P256KeyExchange::NewPrivateKey();
297 std::unique_ptr<P256KeyExchange> p256(
298 P256KeyExchange::New(p256_private_key));
299 QuicStringPiece p256_public_value = p256->public_value();
300
301 DCHECK_LT(p256_public_value.size(), (1U << 24));
302 encoded_public_values.push_back(
303 static_cast<char>(p256_public_value.size()));
304 encoded_public_values.push_back(
305 static_cast<char>(p256_public_value.size() >> 8));
306 encoded_public_values.push_back(
307 static_cast<char>(p256_public_value.size() >> 16));
308 encoded_public_values.append(p256_public_value.data(),
309 p256_public_value.size());
310 }
311
312 msg.set_tag(kSCFG);
313 if (options.p256) {
314 msg.SetVector(kKEXS, QuicTagVector{kC255, kP256});
315 } else {
316 msg.SetVector(kKEXS, QuicTagVector{kC255});
317 }
318 msg.SetVector(kAEAD, QuicTagVector{kAESG, kCC20});
319 msg.SetStringPiece(kPUBS, encoded_public_values);
320
321 if (options.expiry_time.IsZero()) {
322 const QuicWallTime now = clock->WallNow();
323 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds(
324 60 * 60 * 24 * 180 /* 180 days, ~six months */));
325 const uint64_t expiry_seconds = expiry.ToUNIXSeconds();
326 msg.SetValue(kEXPY, expiry_seconds);
327 } else {
328 msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds());
329 }
330
331 char orbit_bytes[kOrbitSize];
332 if (options.orbit.size() == sizeof(orbit_bytes)) {
333 memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes));
334 } else {
335 DCHECK(options.orbit.empty());
336 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
337 }
338 msg.SetStringPiece(kORBT, QuicStringPiece(orbit_bytes, sizeof(orbit_bytes)));
339
340 if (options.channel_id_enabled) {
341 msg.SetVector(kPDMD, QuicTagVector{kCHID});
342 }
343
344 if (!options.token_binding_params.empty()) {
345 msg.SetVector(kTBKP, options.token_binding_params);
346 }
347
348 if (options.id.empty()) {
349 // We need to ensure that the SCID changes whenever the server config does
350 // thus we make it a hash of the rest of the server config.
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700351 std::unique_ptr<QuicData> serialized =
352 CryptoFramer::ConstructHandshakeMessage(msg);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500353
354 uint8_t scid_bytes[SHA256_DIGEST_LENGTH];
355 SHA256(reinterpret_cast<const uint8_t*>(serialized->data()),
356 serialized->length(), scid_bytes);
357 // The SCID is a truncated SHA-256 digest.
358 static_assert(16 <= SHA256_DIGEST_LENGTH, "SCID length too high.");
359 msg.SetStringPiece(
360 kSCID, QuicStringPiece(reinterpret_cast<const char*>(scid_bytes), 16));
361 } else {
362 msg.SetStringPiece(kSCID, options.id);
363 }
364 // Don't put new tags below this point. The SCID generation should hash over
365 // everything but itself and so extra tags should be added prior to the
366 // preceding if block.
367
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700368 std::unique_ptr<QuicData> serialized =
369 CryptoFramer::ConstructHandshakeMessage(msg);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500370
QUICHE teambbaa8be2019-03-21 12:54:17 -0700371 QuicServerConfigProtobuf config;
372 config.set_config(std::string(serialized->AsStringPiece()));
373 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config.add_key();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500374 curve25519_key->set_tag(kC255);
375 curve25519_key->set_private_key(curve25519_private_key);
376
377 if (options.p256) {
QUICHE teambbaa8be2019-03-21 12:54:17 -0700378 QuicServerConfigProtobuf::PrivateKey* p256_key = config.add_key();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500379 p256_key->set_tag(kP256);
380 p256_key->set_private_key(p256_private_key);
381 }
382
383 return config;
384}
385
QUICHE teamd5af58a2019-03-14 20:35:50 -0700386std::unique_ptr<CryptoHandshakeMessage> QuicCryptoServerConfig::AddConfig(
QUICHE teambbaa8be2019-03-21 12:54:17 -0700387 const QuicServerConfigProtobuf& protobuf,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500388 const QuicWallTime now) {
QUICHE teamd5af58a2019-03-14 20:35:50 -0700389 std::unique_ptr<CryptoHandshakeMessage> msg =
QUICHE teambbaa8be2019-03-21 12:54:17 -0700390 CryptoFramer::ParseMessage(protobuf.config());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500391
392 if (!msg.get()) {
393 QUIC_LOG(WARNING) << "Failed to parse server config message";
394 return nullptr;
395 }
396
QUICHE team99055cf2019-03-22 11:27:53 -0700397 QuicReferenceCountedPointer<Config> config =
398 ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500399 if (!config.get()) {
400 QUIC_LOG(WARNING) << "Failed to parse server config message";
401 return nullptr;
402 }
403
404 {
405 QuicWriterMutexLock locked(&configs_lock_);
406 if (configs_.find(config->id) != configs_.end()) {
407 QUIC_LOG(WARNING) << "Failed to add config because another with the same "
408 "server config id already exists: "
409 << QuicTextUtils::HexEncode(config->id);
410 return nullptr;
411 }
412
413 configs_[config->id] = config;
414 SelectNewPrimaryConfig(now);
415 DCHECK(primary_config_.get());
416 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
417 primary_config_.get());
418 }
419
QUICHE teamd5af58a2019-03-14 20:35:50 -0700420 return msg;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500421}
422
QUICHE teamd5af58a2019-03-14 20:35:50 -0700423std::unique_ptr<CryptoHandshakeMessage>
424QuicCryptoServerConfig::AddDefaultConfig(QuicRandom* rand,
425 const QuicClock* clock,
426 const ConfigOptions& options) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500427 return AddConfig(GenerateConfig(rand, clock, options), clock->WallNow());
428}
429
430bool QuicCryptoServerConfig::SetConfigs(
QUICHE teambbaa8be2019-03-21 12:54:17 -0700431 const std::vector<QuicServerConfigProtobuf>& protobufs,
QUICHE team99055cf2019-03-22 11:27:53 -0700432 const QuicServerConfigProtobuf* fallback_protobuf,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500433 const QuicWallTime now) {
434 std::vector<QuicReferenceCountedPointer<Config>> parsed_configs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500435 for (auto& protobuf : protobufs) {
QUICHE team99055cf2019-03-22 11:27:53 -0700436 QuicReferenceCountedPointer<Config> config =
437 ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500438 if (!config) {
QUICHE team78c2d5e2019-03-19 10:50:50 -0700439 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
440 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500441 }
442
443 parsed_configs.push_back(config);
444 }
445
QUICHE team99055cf2019-03-22 11:27:53 -0700446 QuicReferenceCountedPointer<Config> fallback_config;
447 if (fallback_protobuf != nullptr) {
448 fallback_config =
449 ParseConfigProtobuf(*fallback_protobuf, /* is_fallback = */ true);
450 if (!fallback_config) {
451 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
452 return false;
453 }
454 QUIC_LOG(INFO) << "Fallback config has scid "
455 << QuicTextUtils::HexEncode(fallback_config->id);
456 parsed_configs.push_back(fallback_config);
457 } else {
458 QUIC_LOG(INFO) << "No fallback config provided";
459 }
460
QUICHE teama6ef0a62019-03-07 20:34:33 -0500461 if (parsed_configs.empty()) {
QUICHE team78c2d5e2019-03-19 10:50:50 -0700462 QUIC_LOG(WARNING)
463 << "Rejecting QUIC configs because new config list is empty.";
464 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500465 }
466
QUICHE team78c2d5e2019-03-19 10:50:50 -0700467 QUIC_LOG(INFO) << "Updating configs:";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500468
QUICHE team78c2d5e2019-03-19 10:50:50 -0700469 QuicWriterMutexLock locked(&configs_lock_);
470 ConfigMap new_configs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500471
QUICHE team78c2d5e2019-03-19 10:50:50 -0700472 for (const QuicReferenceCountedPointer<Config>& config : parsed_configs) {
473 auto it = configs_.find(config->id);
474 if (it != configs_.end()) {
475 QUIC_LOG(INFO) << "Keeping scid: " << QuicTextUtils::HexEncode(config->id)
476 << " orbit: "
477 << QuicTextUtils::HexEncode(
478 reinterpret_cast<const char*>(config->orbit),
479 kOrbitSize)
480 << " new primary_time "
481 << config->primary_time.ToUNIXSeconds()
482 << " old primary_time "
483 << it->second->primary_time.ToUNIXSeconds()
484 << " new priority " << config->priority << " old priority "
485 << it->second->priority;
486 // Update primary_time and priority.
487 it->second->primary_time = config->primary_time;
488 it->second->priority = config->priority;
489 new_configs.insert(*it);
490 } else {
491 QUIC_LOG(INFO) << "Adding scid: " << QuicTextUtils::HexEncode(config->id)
492 << " orbit: "
493 << QuicTextUtils::HexEncode(
494 reinterpret_cast<const char*>(config->orbit),
495 kOrbitSize)
496 << " primary_time " << config->primary_time.ToUNIXSeconds()
497 << " priority " << config->priority;
498 new_configs.emplace(config->id, config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500499 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500500 }
501
QUICHE team78c2d5e2019-03-19 10:50:50 -0700502 configs_ = std::move(new_configs);
QUICHE team99055cf2019-03-22 11:27:53 -0700503 fallback_config_ = fallback_config;
QUICHE team78c2d5e2019-03-19 10:50:50 -0700504 SelectNewPrimaryConfig(now);
505 DCHECK(primary_config_.get());
506 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
507 primary_config_.get());
508
509 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500510}
511
512void QuicCryptoServerConfig::SetSourceAddressTokenKeys(
vasilvvc48c8712019-03-11 13:38:16 -0700513 const std::vector<std::string>& keys) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500514 source_address_token_boxer_.SetKeys(keys);
515}
516
517void QuicCryptoServerConfig::GetConfigIds(
vasilvvc48c8712019-03-11 13:38:16 -0700518 std::vector<std::string>* scids) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500519 QuicReaderMutexLock locked(&configs_lock_);
520 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
521 scids->push_back(it->first);
522 }
523}
524
525void QuicCryptoServerConfig::ValidateClientHello(
526 const CryptoHandshakeMessage& client_hello,
527 const QuicIpAddress& client_ip,
528 const QuicSocketAddress& server_address,
529 QuicTransportVersion version,
530 const QuicClock* clock,
531 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
532 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
533 const QuicWallTime now(clock->WallNow());
534
535 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result(
536 new ValidateClientHelloResultCallback::Result(client_hello, client_ip,
537 now));
538
539 QuicStringPiece requested_scid;
540 client_hello.GetStringPiece(kSCID, &requested_scid);
QUICHE team1225f472019-03-19 15:52:25 -0700541 Configs configs;
542 if (!GetCurrentConfigs(now, requested_scid,
543 /* old_primary_config = */ nullptr, &configs)) {
544 result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
545 result->error_details = "No configurations loaded";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500546 }
QUICHE team1225f472019-03-19 15:52:25 -0700547 signed_config->config = configs.primary;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500548
549 if (result->error_code == QUIC_NO_ERROR) {
550 // QUIC requires a new proof for each CHLO so clear any existing proof.
551 signed_config->chain = nullptr;
552 signed_config->proof.signature = "";
553 signed_config->proof.leaf_cert_scts = "";
QUICHE team1225f472019-03-19 15:52:25 -0700554 EvaluateClientHello(server_address, version, configs, result,
555 std::move(done_cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500556 } else {
557 done_cb->Run(result, /* details = */ nullptr);
558 }
559}
560
QUICHE teama6ef0a62019-03-07 20:34:33 -0500561class QuicCryptoServerConfig::ProcessClientHelloCallback
562 : public ProofSource::Callback {
563 public:
QUICHE team1225f472019-03-19 15:52:25 -0700564 ProcessClientHelloCallback(const QuicCryptoServerConfig* config,
565 std::unique_ptr<ProcessClientHelloContext> context,
566 const Configs& configs)
567 : config_(config), context_(std::move(context)), configs_(configs) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500568
569 void Run(bool ok,
570 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
571 const QuicCryptoProof& proof,
572 std::unique_ptr<ProofSource::Details> details) override {
573 if (ok) {
QUICHE team4dae8412019-03-18 13:11:00 -0700574 context_->signed_config()->chain = chain;
575 context_->signed_config()->proof = proof;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500576 }
QUICHE team1225f472019-03-19 15:52:25 -0700577 config_->ProcessClientHelloAfterGetProof(!ok, std::move(details),
578 std::move(context_), configs_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500579 }
580
581 private:
582 const QuicCryptoServerConfig* config_;
QUICHE team4dae8412019-03-18 13:11:00 -0700583 std::unique_ptr<ProcessClientHelloContext> context_;
QUICHE team1225f472019-03-19 15:52:25 -0700584 const Configs configs_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500585};
586
587class QuicCryptoServerConfig::ProcessClientHelloAfterGetProofCallback
QUICHE teamfe1aca62019-03-14 13:39:01 -0700588 : public AsynchronousKeyExchange::Callback {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500589 public:
590 ProcessClientHelloAfterGetProofCallback(
591 const QuicCryptoServerConfig* config,
592 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE teamfe1aca62019-03-14 13:39:01 -0700593 QuicTag key_exchange_type,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500594 std::unique_ptr<CryptoHandshakeMessage> out,
595 QuicStringPiece public_value,
QUICHE team4dae8412019-03-18 13:11:00 -0700596 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700597 const Configs& configs)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500598 : config_(config),
599 proof_source_details_(std::move(proof_source_details)),
QUICHE teamfe1aca62019-03-14 13:39:01 -0700600 key_exchange_type_(key_exchange_type),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500601 out_(std::move(out)),
602 public_value_(public_value),
QUICHE team4dae8412019-03-18 13:11:00 -0700603 context_(std::move(context)),
QUICHE team1225f472019-03-19 15:52:25 -0700604 configs_(configs) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500605
606 void Run(bool ok) override {
607 config_->ProcessClientHelloAfterCalculateSharedKeys(
QUICHE teamfe1aca62019-03-14 13:39:01 -0700608 !ok, std::move(proof_source_details_), key_exchange_type_,
QUICHE team1225f472019-03-19 15:52:25 -0700609 std::move(out_), public_value_, std::move(context_), configs_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500610 }
611
612 private:
613 const QuicCryptoServerConfig* config_;
614 std::unique_ptr<ProofSource::Details> proof_source_details_;
QUICHE team99055cf2019-03-22 11:27:53 -0700615 const QuicTag key_exchange_type_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500616 std::unique_ptr<CryptoHandshakeMessage> out_;
QUICHE team99055cf2019-03-22 11:27:53 -0700617 const std::string public_value_;
QUICHE team4dae8412019-03-18 13:11:00 -0700618 std::unique_ptr<ProcessClientHelloContext> context_;
QUICHE team1225f472019-03-19 15:52:25 -0700619 const Configs configs_;
QUICHE team59882932019-03-27 11:02:17 -0700620 std::unique_ptr<ProcessClientHelloResultCallback> done_cb_;
621};
622
623class QuicCryptoServerConfig::SendRejectWithFallbackConfigCallback
624 : public ProofSource::Callback {
625 public:
626 SendRejectWithFallbackConfigCallback(
627 const QuicCryptoServerConfig* config,
628 std::unique_ptr<ProcessClientHelloContext> context,
629 QuicReferenceCountedPointer<Config> fallback_config)
630 : config_(config),
631 context_(std::move(context)),
632 fallback_config_(fallback_config) {}
633
634 // Capture |chain| and |proof| into the signed config, and then invoke
635 // SendRejectWithFallbackConfigAfterGetProof.
636 void Run(bool ok,
637 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
638 const QuicCryptoProof& proof,
639 std::unique_ptr<ProofSource::Details> details) override {
640 if (ok) {
641 context_->signed_config()->chain = chain;
642 context_->signed_config()->proof = proof;
643 }
644 config_->SendRejectWithFallbackConfigAfterGetProof(
645 !ok, std::move(details), std::move(context_), fallback_config_);
646 }
647
648 private:
649 const QuicCryptoServerConfig* config_;
650 std::unique_ptr<ProcessClientHelloContext> context_;
651 QuicReferenceCountedPointer<Config> fallback_config_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500652};
653
654void QuicCryptoServerConfig::ProcessClientHello(
655 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
656 validate_chlo_result,
657 bool reject_only,
658 QuicConnectionId connection_id,
659 const QuicSocketAddress& server_address,
660 const QuicSocketAddress& client_address,
661 ParsedQuicVersion version,
662 const ParsedQuicVersionVector& supported_versions,
663 bool use_stateless_rejects,
664 QuicConnectionId server_designated_connection_id,
665 const QuicClock* clock,
666 QuicRandom* rand,
667 QuicCompressedCertsCache* compressed_certs_cache,
668 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,
669 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
670 QuicByteCount total_framing_overhead,
671 QuicByteCount chlo_packet_size,
672 std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
673 DCHECK(done_cb);
QUICHE team4dae8412019-03-18 13:11:00 -0700674 auto context = QuicMakeUnique<ProcessClientHelloContext>(
675 validate_chlo_result, reject_only, connection_id, server_address,
676 client_address, version, supported_versions, use_stateless_rejects,
677 server_designated_connection_id, clock, rand, compressed_certs_cache,
678 params, signed_config, total_framing_overhead, chlo_packet_size,
679 std::move(done_cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500680
QUICHE team1225f472019-03-19 15:52:25 -0700681 // Verify that various parts of the CHLO are valid
vasilvvc48c8712019-03-11 13:38:16 -0700682 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500683 QuicErrorCode valid = CryptoUtils::ValidateClientHello(
QUICHE team4dae8412019-03-18 13:11:00 -0700684 context->client_hello(), context->version(),
685 context->supported_versions(), &error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500686 if (valid != QUIC_NO_ERROR) {
QUICHE team4dae8412019-03-18 13:11:00 -0700687 context->Fail(valid, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500688 return;
689 }
690
691 QuicStringPiece requested_scid;
QUICHE team4dae8412019-03-18 13:11:00 -0700692 context->client_hello().GetStringPiece(kSCID, &requested_scid);
QUICHE team1225f472019-03-19 15:52:25 -0700693 Configs configs;
694 if (!GetCurrentConfigs(context->clock()->WallNow(), requested_scid,
695 signed_config->config, &configs)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700696 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "No configurations loaded");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500697 return;
698 }
699
QUICHE team4dae8412019-03-18 13:11:00 -0700700 if (context->validate_chlo_result()->error_code != QUIC_NO_ERROR) {
701 context->Fail(context->validate_chlo_result()->error_code,
702 context->validate_chlo_result()->error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500703 return;
704 }
705
QUICHE team4dae8412019-03-18 13:11:00 -0700706 if (!ClientDemandsX509Proof(context->client_hello())) {
707 context->Fail(QUIC_UNSUPPORTED_PROOF_DEMAND, "Missing or invalid PDMD");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500708 return;
709 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500710
711 // No need to get a new proof if one was already generated.
QUICHE team4dae8412019-03-18 13:11:00 -0700712 if (!context->signed_config()->chain) {
713 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
714 context->client_hello(), Perspective::IS_SERVER);
715 const QuicSocketAddress server_address = context->server_address();
716 const std::string sni = std::string(context->info().sni);
717 const QuicTransportVersion transport_version = context->transport_version();
718
QUICHE teamea5bdef2019-03-13 15:41:27 -0700719 auto cb = QuicMakeUnique<ProcessClientHelloCallback>(
QUICHE team1225f472019-03-19 15:52:25 -0700720 this, std::move(context), configs);
QUICHE team84910bd2019-03-15 07:03:40 -0700721
722 DCHECK(proof_source_.get());
QUICHE team1225f472019-03-19 15:52:25 -0700723 proof_source_->GetProof(server_address, sni, configs.primary->serialized,
QUICHE team4dae8412019-03-18 13:11:00 -0700724 transport_version, chlo_hash, std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500725 return;
726 }
727
QUICHE teama6ef0a62019-03-07 20:34:33 -0500728 ProcessClientHelloAfterGetProof(
729 /* found_error = */ false, /* proof_source_details = */ nullptr,
QUICHE team1225f472019-03-19 15:52:25 -0700730 std::move(context), configs);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500731}
732
733void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
734 bool found_error,
735 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE team4dae8412019-03-18 13:11:00 -0700736 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700737 const Configs& configs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500738 QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -0700739 context->connection_id(), context->transport_version()))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500740 << "ProcessClientHelloAfterGetProof: attempted to use connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -0700741 << context->connection_id() << " which is invalid with version "
742 << QuicVersionToString(context->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500743
744 if (found_error) {
QUICHE team4dae8412019-03-18 13:11:00 -0700745 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500746 return;
747 }
748
QUICHE teamea5bdef2019-03-13 15:41:27 -0700749 auto out_diversification_nonce = QuicMakeUnique<DiversificationNonce>();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500750
751 QuicStringPiece cert_sct;
QUICHE team4dae8412019-03-18 13:11:00 -0700752 if (context->client_hello().GetStringPiece(kCertificateSCTTag, &cert_sct) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500753 cert_sct.empty()) {
QUICHE team4dae8412019-03-18 13:11:00 -0700754 context->params()->sct_supported_by_client = true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500755 }
756
QUICHE teamea5bdef2019-03-13 15:41:27 -0700757 auto out = QuicMakeUnique<CryptoHandshakeMessage>();
QUICHE team1225f472019-03-19 15:52:25 -0700758 if (!context->info().reject_reasons.empty() || !configs.requested) {
QUICHE teamaa924f12019-03-21 11:26:21 -0700759 BuildRejectionAndRecordStats(*context, *configs.primary,
760 context->info().reject_reasons, out.get());
QUICHE team4dae8412019-03-18 13:11:00 -0700761 context->Succeed(std::move(out), std::move(out_diversification_nonce),
762 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500763 return;
764 }
765
QUICHE team4dae8412019-03-18 13:11:00 -0700766 if (context->reject_only()) {
767 context->Succeed(std::move(out), std::move(out_diversification_nonce),
768 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500769 return;
770 }
771
772 QuicTagVector their_aeads;
773 QuicTagVector their_key_exchanges;
QUICHE team4dae8412019-03-18 13:11:00 -0700774 if (context->client_hello().GetTaglist(kAEAD, &their_aeads) !=
775 QUIC_NO_ERROR ||
776 context->client_hello().GetTaglist(kKEXS, &their_key_exchanges) !=
777 QUIC_NO_ERROR ||
QUICHE teama6ef0a62019-03-07 20:34:33 -0500778 their_aeads.size() != 1 || their_key_exchanges.size() != 1) {
QUICHE team4dae8412019-03-18 13:11:00 -0700779 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
780 "Missing or invalid AEAD or KEXS");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500781 return;
782 }
783
784 size_t key_exchange_index;
QUICHE team1225f472019-03-19 15:52:25 -0700785 if (!FindMutualQuicTag(configs.requested->aead, their_aeads,
QUICHE team4dae8412019-03-18 13:11:00 -0700786 &context->params()->aead, nullptr) ||
QUICHE team1225f472019-03-19 15:52:25 -0700787 !FindMutualQuicTag(configs.requested->kexs, their_key_exchanges,
QUICHE team4dae8412019-03-18 13:11:00 -0700788 &context->params()->key_exchange,
789 &key_exchange_index)) {
790 context->Fail(QUIC_CRYPTO_NO_SUPPORT, "Unsupported AEAD or KEXS");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500791 return;
792 }
793
QUICHE team1225f472019-03-19 15:52:25 -0700794 if (!configs.requested->tb_key_params.empty()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500795 QuicTagVector their_tbkps;
QUICHE team4dae8412019-03-18 13:11:00 -0700796 switch (context->client_hello().GetTaglist(kTBKP, &their_tbkps)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500797 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
798 break;
799 case QUIC_NO_ERROR:
QUICHE team1225f472019-03-19 15:52:25 -0700800 if (FindMutualQuicTag(configs.requested->tb_key_params, their_tbkps,
QUICHE team4dae8412019-03-18 13:11:00 -0700801 &context->params()->token_binding_key_param,
802 nullptr)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500803 break;
804 }
805 QUIC_FALLTHROUGH_INTENDED;
806 default:
QUICHE team4dae8412019-03-18 13:11:00 -0700807 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
808 "Invalid Token Binding key parameter");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500809 return;
810 }
811 }
812
813 QuicStringPiece public_value;
QUICHE team4dae8412019-03-18 13:11:00 -0700814 if (!context->client_hello().GetStringPiece(kPUBS, &public_value)) {
815 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
816 "Missing public value");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500817 return;
818 }
819
QUICHE teamfe1aca62019-03-14 13:39:01 -0700820 const AsynchronousKeyExchange* key_exchange =
QUICHE team1225f472019-03-19 15:52:25 -0700821 configs.requested->key_exchanges[key_exchange_index].get();
QUICHE team4dae8412019-03-18 13:11:00 -0700822 std::string* initial_premaster_secret =
823 &context->params()->initial_premaster_secret;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500824 auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>(
QUICHE teamfe1aca62019-03-14 13:39:01 -0700825 this, std::move(proof_source_details), key_exchange->type(),
QUICHE team1225f472019-03-19 15:52:25 -0700826 std::move(out), public_value, std::move(context), configs);
QUICHE team4dae8412019-03-18 13:11:00 -0700827 key_exchange->CalculateSharedKeyAsync(public_value, initial_premaster_secret,
828 std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500829}
830
831void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys(
832 bool found_error,
833 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE teamfe1aca62019-03-14 13:39:01 -0700834 QuicTag key_exchange_type,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500835 std::unique_ptr<CryptoHandshakeMessage> out,
836 QuicStringPiece public_value,
QUICHE team4dae8412019-03-18 13:11:00 -0700837 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700838 const Configs& configs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500839 QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -0700840 context->connection_id(), context->transport_version()))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500841 << "ProcessClientHelloAfterCalculateSharedKeys:"
842 " attempted to use connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -0700843 << context->connection_id() << " which is invalid with version "
844 << QuicVersionToString(context->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500845
846 if (found_error) {
QUICHE team59882932019-03-27 11:02:17 -0700847 // If we are already using the fallback config, just bail out of the
848 // handshake.
849 if (context->signed_config()->config == configs.fallback ||
850 !GetQuicReloadableFlag(
851 send_quic_fallback_server_config_on_leto_error)) {
852 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
853 "Failed to calculate shared key");
854 } else {
855 SendRejectWithFallbackConfig(std::move(context), configs.fallback);
856 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500857 return;
858 }
859
QUICHE team4dae8412019-03-18 13:11:00 -0700860 if (!context->info().sni.empty()) {
861 context->params()->sni =
862 QuicHostnameUtils::NormalizeHostname(context->info().sni);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500863 }
864
vasilvvc48c8712019-03-11 13:38:16 -0700865 std::string hkdf_suffix;
QUICHE team4dae8412019-03-18 13:11:00 -0700866 const QuicData& client_hello_serialized =
867 context->client_hello().GetSerialized();
868 hkdf_suffix.reserve(context->connection_id().length() +
vasilvvc48c8712019-03-11 13:38:16 -0700869 client_hello_serialized.length() +
QUICHE team1225f472019-03-19 15:52:25 -0700870 configs.requested->serialized.size());
QUICHE team4dae8412019-03-18 13:11:00 -0700871 hkdf_suffix.append(context->connection_id().data(),
872 context->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500873 hkdf_suffix.append(client_hello_serialized.data(),
874 client_hello_serialized.length());
QUICHE team1225f472019-03-19 15:52:25 -0700875 hkdf_suffix.append(configs.requested->serialized);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500876 DCHECK(proof_source_.get());
QUICHE team4dae8412019-03-18 13:11:00 -0700877 if (context->signed_config()->chain->certs.empty()) {
878 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "Failed to get certs");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500879 return;
880 }
QUICHE team4dae8412019-03-18 13:11:00 -0700881 hkdf_suffix.append(context->signed_config()->chain->certs.at(0));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500882
883 QuicStringPiece cetv_ciphertext;
QUICHE team1225f472019-03-19 15:52:25 -0700884 if (configs.requested->channel_id_enabled &&
QUICHE team4dae8412019-03-18 13:11:00 -0700885 context->client_hello().GetStringPiece(kCETV, &cetv_ciphertext)) {
886 CryptoHandshakeMessage client_hello_copy(context->client_hello());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500887 client_hello_copy.Erase(kCETV);
888 client_hello_copy.Erase(kPAD);
889
890 const QuicData& client_hello_copy_serialized =
891 client_hello_copy.GetSerialized();
vasilvvc48c8712019-03-11 13:38:16 -0700892 std::string hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500893 hkdf_input.append(QuicCryptoConfig::kCETVLabel,
894 strlen(QuicCryptoConfig::kCETVLabel) + 1);
QUICHE team4dae8412019-03-18 13:11:00 -0700895 hkdf_input.append(context->connection_id().data(),
896 context->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500897 hkdf_input.append(client_hello_copy_serialized.data(),
898 client_hello_copy_serialized.length());
QUICHE team1225f472019-03-19 15:52:25 -0700899 hkdf_input.append(configs.requested->serialized);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500900
901 CrypterPair crypters;
902 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700903 context->params()->initial_premaster_secret,
904 context->params()->aead, context->info().client_nonce,
905 context->info().server_nonce, pre_shared_key_, hkdf_input,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500906 Perspective::IS_SERVER, CryptoUtils::Diversification::Never(),
907 &crypters, nullptr /* subkey secret */)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700908 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
909 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500910 return;
911 }
912
dschinazi66dea072019-04-09 11:41:06 -0700913 char plaintext[kMaxOutgoingPacketSize];
QUICHE teama6ef0a62019-03-07 20:34:33 -0500914 size_t plaintext_length = 0;
915 const bool success = crypters.decrypter->DecryptPacket(
916 0 /* packet number */, QuicStringPiece() /* associated data */,
dschinazi66dea072019-04-09 11:41:06 -0700917 cetv_ciphertext, plaintext, &plaintext_length, kMaxOutgoingPacketSize);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500918 if (!success) {
QUICHE team4dae8412019-03-18 13:11:00 -0700919 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
920 "CETV decryption failure");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500921 return;
922 }
923 std::unique_ptr<CryptoHandshakeMessage> cetv(CryptoFramer::ParseMessage(
924 QuicStringPiece(plaintext, plaintext_length)));
925 if (!cetv.get()) {
QUICHE team4dae8412019-03-18 13:11:00 -0700926 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV parse error");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500927 return;
928 }
929
930 QuicStringPiece key, signature;
931 if (cetv->GetStringPiece(kCIDK, &key) &&
932 cetv->GetStringPiece(kCIDS, &signature)) {
933 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700934 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
935 "ChannelID signature failure");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500936 return;
937 }
938
QUICHE team4dae8412019-03-18 13:11:00 -0700939 context->params()->channel_id = std::string(key);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500940 }
941 }
942
vasilvvc48c8712019-03-11 13:38:16 -0700943 std::string hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500944 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
945 hkdf_input.reserve(label_len + hkdf_suffix.size());
946 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
947 hkdf_input.append(hkdf_suffix);
948
QUICHE team45c889c2019-03-14 16:37:01 -0700949 auto out_diversification_nonce = QuicMakeUnique<DiversificationNonce>();
QUICHE team4dae8412019-03-18 13:11:00 -0700950 context->rand()->RandBytes(out_diversification_nonce->data(),
951 out_diversification_nonce->size());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500952 CryptoUtils::Diversification diversification =
953 CryptoUtils::Diversification::Now(out_diversification_nonce.get());
954 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700955 context->params()->initial_premaster_secret, context->params()->aead,
956 context->info().client_nonce, context->info().server_nonce,
957 pre_shared_key_, hkdf_input, Perspective::IS_SERVER, diversification,
958 &context->params()->initial_crypters,
959 &context->params()->initial_subkey_secret)) {
960 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
961 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500962 return;
963 }
964
vasilvvc48c8712019-03-11 13:38:16 -0700965 std::string forward_secure_public_value;
QUICHE teamfe1aca62019-03-14 13:39:01 -0700966 std::unique_ptr<SynchronousKeyExchange> forward_secure_key_exchange =
QUICHE team4dae8412019-03-18 13:11:00 -0700967 CreateLocalSynchronousKeyExchange(key_exchange_type, context->rand());
QUICHE teamfe1aca62019-03-14 13:39:01 -0700968 if (!forward_secure_key_exchange) {
969 QUIC_DLOG(WARNING) << "Failed to create keypair";
QUICHE team4dae8412019-03-18 13:11:00 -0700970 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
971 "Failed to create keypair");
QUICHE teamfe1aca62019-03-14 13:39:01 -0700972 return;
973 }
974
QUICHE teama6ef0a62019-03-07 20:34:33 -0500975 forward_secure_public_value =
vasilvvc48c8712019-03-11 13:38:16 -0700976 std::string(forward_secure_key_exchange->public_value());
QUICHE teamfe1aca62019-03-14 13:39:01 -0700977 if (!forward_secure_key_exchange->CalculateSharedKeySync(
QUICHE team4dae8412019-03-18 13:11:00 -0700978 public_value, &context->params()->forward_secure_premaster_secret)) {
979 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
980 "Invalid public value");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500981 return;
982 }
983
vasilvvc48c8712019-03-11 13:38:16 -0700984 std::string forward_secure_hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500985 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
986 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
987 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
988 label_len);
989 forward_secure_hkdf_input.append(hkdf_suffix);
990
vasilvvc48c8712019-03-11 13:38:16 -0700991 std::string shlo_nonce;
QUICHE team4dae8412019-03-18 13:11:00 -0700992 shlo_nonce = NewServerNonce(context->rand(), context->info().now);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500993 out->SetStringPiece(kServerNonceTag, shlo_nonce);
994
995 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700996 context->params()->forward_secure_premaster_secret,
997 context->params()->aead, context->info().client_nonce,
998 shlo_nonce.empty() ? context->info().server_nonce : shlo_nonce,
999 pre_shared_key_, forward_secure_hkdf_input, Perspective::IS_SERVER,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001000 CryptoUtils::Diversification::Never(),
QUICHE team4dae8412019-03-18 13:11:00 -07001001 &context->params()->forward_secure_crypters,
1002 &context->params()->subkey_secret)) {
1003 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
1004 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -05001005 return;
1006 }
1007
1008 out->set_tag(kSHLO);
QUICHE team4dae8412019-03-18 13:11:00 -07001009 out->SetVersionVector(kVER, context->supported_versions());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001010 out->SetStringPiece(
1011 kSourceAddressTokenTag,
QUICHE team1225f472019-03-19 15:52:25 -07001012 NewSourceAddressToken(*configs.requested,
QUICHE team4dae8412019-03-18 13:11:00 -07001013 context->info().source_address_tokens,
1014 context->client_address().host(), context->rand(),
1015 context->info().now, nullptr));
1016 QuicSocketAddressCoder address_coder(context->client_address());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001017 out->SetStringPiece(kCADR, address_coder.Encode());
1018 out->SetStringPiece(kPUBS, forward_secure_public_value);
1019
QUICHE team4dae8412019-03-18 13:11:00 -07001020 context->Succeed(std::move(out), std::move(out_diversification_nonce),
1021 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001022}
1023
QUICHE team59882932019-03-27 11:02:17 -07001024void QuicCryptoServerConfig::SendRejectWithFallbackConfig(
1025 std::unique_ptr<ProcessClientHelloContext> context,
1026 QuicReferenceCountedPointer<Config> fallback_config) const {
1027 // We failed to calculate a shared initial key, likely because we tried to use
1028 // a remote key-exchange service which could not be reached. We want to send
1029 // a REJ which tells the client to use a different ServerConfig which
1030 // corresponds to a local keypair. To generate the REJ we need to request a
1031 // new proof.
1032 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
1033 context->client_hello(), Perspective::IS_SERVER);
1034 const QuicSocketAddress server_address = context->server_address();
1035 const std::string sni(context->info().sni);
1036 const QuicTransportVersion transport_version = context->transport_version();
1037
1038 auto cb = QuicMakeUnique<SendRejectWithFallbackConfigCallback>(
1039 this, std::move(context), fallback_config);
1040 proof_source_->GetProof(server_address, sni, fallback_config->serialized,
1041 transport_version, chlo_hash, std::move(cb));
1042}
1043
1044void QuicCryptoServerConfig::SendRejectWithFallbackConfigAfterGetProof(
1045 bool found_error,
1046 std::unique_ptr<ProofSource::Details> proof_source_details,
1047 std::unique_ptr<ProcessClientHelloContext> context,
1048 QuicReferenceCountedPointer<Config> fallback_config) const {
1049 if (found_error) {
1050 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
1051 return;
1052 }
1053
1054 auto out = QuicMakeUnique<CryptoHandshakeMessage>();
1055 BuildRejectionAndRecordStats(*context, *fallback_config,
1056 {SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE},
1057 out.get());
1058
1059 context->Succeed(std::move(out), QuicMakeUnique<DiversificationNonce>(),
1060 std::move(proof_source_details));
1061}
1062
QUICHE teama6ef0a62019-03-07 20:34:33 -05001063QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
1064QuicCryptoServerConfig::GetConfigWithScid(
1065 QuicStringPiece requested_scid) const {
1066 configs_lock_.AssertReaderHeld();
1067
1068 if (!requested_scid.empty()) {
vasilvvc48c8712019-03-11 13:38:16 -07001069 auto it = configs_.find((std::string(requested_scid)));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001070 if (it != configs_.end()) {
1071 // We'll use the config that the client requested in order to do
1072 // key-agreement.
1073 return QuicReferenceCountedPointer<Config>(it->second);
1074 }
1075 }
1076
1077 return QuicReferenceCountedPointer<Config>();
1078}
1079
QUICHE team1225f472019-03-19 15:52:25 -07001080bool QuicCryptoServerConfig::GetCurrentConfigs(
1081 const QuicWallTime& now,
1082 QuicStringPiece requested_scid,
1083 QuicReferenceCountedPointer<Config> old_primary_config,
1084 Configs* configs) const {
1085 QuicReaderMutexLock locked(&configs_lock_);
1086
1087 if (!primary_config_) {
1088 return false;
1089 }
1090
1091 if (IsNextConfigReady(now)) {
1092 configs_lock_.ReaderUnlock();
1093 configs_lock_.WriterLock();
1094 SelectNewPrimaryConfig(now);
1095 DCHECK(primary_config_.get());
1096 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
1097 primary_config_.get());
1098 configs_lock_.WriterUnlock();
1099 configs_lock_.ReaderLock();
1100 }
1101
1102 if (old_primary_config != nullptr) {
1103 configs->primary = old_primary_config;
1104 } else {
1105 configs->primary = primary_config_;
1106 }
1107 configs->requested = GetConfigWithScid(requested_scid);
QUICHE team99055cf2019-03-22 11:27:53 -07001108 configs->fallback = fallback_config_;
QUICHE team1225f472019-03-19 15:52:25 -07001109
1110 return true;
1111}
1112
QUICHE teama6ef0a62019-03-07 20:34:33 -05001113// ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
1114// Config's based on their primary_time.
1115// static
1116bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
1117 const QuicReferenceCountedPointer<Config>& a,
1118 const QuicReferenceCountedPointer<Config>& b) {
1119 if (a->primary_time.IsBefore(b->primary_time) ||
1120 b->primary_time.IsBefore(a->primary_time)) {
1121 // Primary times differ.
1122 return a->primary_time.IsBefore(b->primary_time);
1123 } else if (a->priority != b->priority) {
1124 // Primary times are equal, sort backwards by priority.
1125 return a->priority < b->priority;
1126 } else {
1127 // Primary times and priorities are equal, sort by config id.
1128 return a->id < b->id;
1129 }
1130}
1131
1132void QuicCryptoServerConfig::SelectNewPrimaryConfig(
1133 const QuicWallTime now) const {
1134 std::vector<QuicReferenceCountedPointer<Config>> configs;
1135 configs.reserve(configs_.size());
1136
1137 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
1138 // TODO(avd) Exclude expired configs?
1139 configs.push_back(it->second);
1140 }
1141
1142 if (configs.empty()) {
1143 if (primary_config_ != nullptr) {
1144 QUIC_BUG << "No valid QUIC server config. Keeping the current config.";
1145 } else {
1146 QUIC_BUG << "No valid QUIC server config.";
1147 }
1148 return;
1149 }
1150
1151 std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan);
1152
1153 QuicReferenceCountedPointer<Config> best_candidate = configs[0];
1154
1155 for (size_t i = 0; i < configs.size(); ++i) {
1156 const QuicReferenceCountedPointer<Config> config(configs[i]);
1157 if (!config->primary_time.IsAfter(now)) {
1158 if (config->primary_time.IsAfter(best_candidate->primary_time)) {
1159 best_candidate = config;
1160 }
1161 continue;
1162 }
1163
1164 // This is the first config with a primary_time in the future. Thus the
1165 // previous Config should be the primary and this one should determine the
1166 // next_config_promotion_time_.
1167 QuicReferenceCountedPointer<Config> new_primary = best_candidate;
1168 if (i == 0) {
1169 // We need the primary_time of the next config.
1170 if (configs.size() > 1) {
1171 next_config_promotion_time_ = configs[1]->primary_time;
1172 } else {
1173 next_config_promotion_time_ = QuicWallTime::Zero();
1174 }
1175 } else {
1176 next_config_promotion_time_ = config->primary_time;
1177 }
1178
1179 if (primary_config_) {
1180 primary_config_->is_primary = false;
1181 }
1182 primary_config_ = new_primary;
1183 new_primary->is_primary = true;
1184 QUIC_DLOG(INFO) << "New primary config. orbit: "
1185 << QuicTextUtils::HexEncode(reinterpret_cast<const char*>(
1186 primary_config_->orbit),
1187 kOrbitSize);
1188 if (primary_config_changed_cb_ != nullptr) {
1189 primary_config_changed_cb_->Run(primary_config_->id);
1190 }
1191
1192 return;
1193 }
1194
1195 // All config's primary times are in the past. We should make the most recent
1196 // and highest priority candidate primary.
1197 QuicReferenceCountedPointer<Config> new_primary = best_candidate;
1198 if (primary_config_) {
1199 primary_config_->is_primary = false;
1200 }
1201 primary_config_ = new_primary;
1202 new_primary->is_primary = true;
1203 QUIC_DLOG(INFO) << "New primary config. orbit: "
1204 << QuicTextUtils::HexEncode(
1205 reinterpret_cast<const char*>(primary_config_->orbit),
1206 kOrbitSize)
1207 << " scid: " << QuicTextUtils::HexEncode(primary_config_->id);
1208 next_config_promotion_time_ = QuicWallTime::Zero();
1209 if (primary_config_changed_cb_ != nullptr) {
1210 primary_config_changed_cb_->Run(primary_config_->id);
1211 }
1212}
1213
QUICHE teama6ef0a62019-03-07 20:34:33 -05001214void QuicCryptoServerConfig::EvaluateClientHello(
1215 const QuicSocketAddress& server_address,
1216 QuicTransportVersion version,
QUICHE team1225f472019-03-19 15:52:25 -07001217 const Configs& configs,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001218 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
1219 client_hello_state,
1220 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001221 ValidateClientHelloHelper helper(client_hello_state, &done_cb);
1222
1223 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
1224 ClientHelloInfo* info = &(client_hello_state->info);
1225
1226 if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) {
1227 helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
1228 "Client hello too small", nullptr);
1229 return;
1230 }
1231
1232 if (client_hello.GetStringPiece(kSNI, &info->sni) &&
1233 !QuicHostnameUtils::IsValidSNI(info->sni)) {
1234 helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
1235 "Invalid SNI name", nullptr);
1236 return;
1237 }
1238
1239 client_hello.GetStringPiece(kUAID, &info->user_agent_id);
1240
1241 HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
1242 if (validate_source_address_token_) {
1243 QuicStringPiece srct;
1244 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
1245 Config& config =
QUICHE team1225f472019-03-19 15:52:25 -07001246 configs.requested != nullptr ? *configs.requested : *configs.primary;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001247 source_address_token_error =
1248 ParseSourceAddressToken(config, srct, &info->source_address_tokens);
1249
1250 if (source_address_token_error == HANDSHAKE_OK) {
1251 source_address_token_error = ValidateSourceAddressTokens(
1252 info->source_address_tokens, info->client_ip, info->now,
1253 &client_hello_state->cached_network_params);
1254 }
1255 info->valid_source_address_token =
1256 (source_address_token_error == HANDSHAKE_OK);
1257 } else {
1258 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
1259 }
1260 } else {
1261 source_address_token_error = HANDSHAKE_OK;
1262 info->valid_source_address_token = true;
1263 }
1264
QUICHE team1225f472019-03-19 15:52:25 -07001265 if (!configs.requested) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001266 QuicStringPiece requested_scid;
1267 if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
1268 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1269 } else {
1270 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1271 }
1272 // No server config with the requested ID.
1273 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1274 return;
1275 }
1276
1277 if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) {
1278 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1279 // Report no client nonce as INCHOATE_HELLO_FAILURE.
1280 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1281 return;
1282 }
1283
1284 if (source_address_token_error != HANDSHAKE_OK) {
1285 info->reject_reasons.push_back(source_address_token_error);
1286 // No valid source address token.
1287 }
1288
1289 QuicReferenceCountedPointer<ProofSource::Chain> chain =
vasilvvc48c8712019-03-11 13:38:16 -07001290 proof_source_->GetCertChain(server_address, std::string(info->sni));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001291 if (!chain) {
1292 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1293 } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) {
1294 info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
1295 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001296
1297 if (info->client_nonce.size() != kNonceSize) {
1298 info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
1299 // Invalid client nonce.
1300 QUIC_LOG_FIRST_N(ERROR, 2)
1301 << "Invalid client nonce: " << client_hello.DebugString();
1302 QUIC_DLOG(INFO) << "Invalid client nonce.";
1303 }
1304
1305 // Server nonce is optional, and used for key derivation if present.
1306 client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
1307
1308 QUIC_DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher.";
1309 // If the server nonce is empty and we're requiring handshake confirmation
1310 // for DoS reasons then we must reject the CHLO.
1311 if (GetQuicReloadableFlag(quic_require_handshake_confirmation) &&
1312 info->server_nonce.empty()) {
1313 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
1314 }
QUICHE team79fb9e22019-03-15 07:49:56 -07001315 helper.ValidationComplete(QUIC_NO_ERROR, "",
1316 std::unique_ptr<ProofSource::Details>());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001317}
1318
1319void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
1320 QuicTransportVersion version,
1321 QuicStringPiece chlo_hash,
1322 const SourceAddressTokens& previous_source_address_tokens,
1323 const QuicSocketAddress& server_address,
1324 const QuicIpAddress& client_ip,
1325 const QuicClock* clock,
1326 QuicRandom* rand,
1327 QuicCompressedCertsCache* compressed_certs_cache,
1328 const QuicCryptoNegotiatedParameters& params,
1329 const CachedNetworkParameters* cached_network_params,
1330 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
vasilvvc48c8712019-03-11 13:38:16 -07001331 std::string serialized;
1332 std::string source_address_token;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001333 const CommonCertSets* common_cert_sets;
1334 {
1335 QuicReaderMutexLock locked(&configs_lock_);
1336 serialized = primary_config_->serialized;
1337 common_cert_sets = primary_config_->common_cert_sets;
1338 source_address_token = NewSourceAddressToken(
1339 *primary_config_, previous_source_address_tokens, client_ip, rand,
1340 clock->WallNow(), cached_network_params);
1341 }
1342
1343 CryptoHandshakeMessage message;
1344 message.set_tag(kSCUP);
1345 message.SetStringPiece(kSCFG, serialized);
1346 message.SetStringPiece(kSourceAddressTokenTag, source_address_token);
1347
QUICHE teamea5bdef2019-03-13 15:41:27 -07001348 auto proof_source_cb =
1349 QuicMakeUnique<BuildServerConfigUpdateMessageProofSourceCallback>(
QUICHE team39a71e52019-03-15 14:24:34 -07001350 this, compressed_certs_cache, common_cert_sets, params,
QUICHE teamea5bdef2019-03-13 15:41:27 -07001351 std::move(message), std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001352
1353 proof_source_->GetProof(server_address, params.sni, serialized, version,
1354 chlo_hash, std::move(proof_source_cb));
1355}
1356
1357QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1358 ~BuildServerConfigUpdateMessageProofSourceCallback() {}
1359
1360QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1361 BuildServerConfigUpdateMessageProofSourceCallback(
1362 const QuicCryptoServerConfig* config,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001363 QuicCompressedCertsCache* compressed_certs_cache,
1364 const CommonCertSets* common_cert_sets,
1365 const QuicCryptoNegotiatedParameters& params,
1366 CryptoHandshakeMessage message,
1367 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb)
1368 : config_(config),
QUICHE teama6ef0a62019-03-07 20:34:33 -05001369 compressed_certs_cache_(compressed_certs_cache),
1370 common_cert_sets_(common_cert_sets),
1371 client_common_set_hashes_(params.client_common_set_hashes),
1372 client_cached_cert_hashes_(params.client_cached_cert_hashes),
1373 sct_supported_by_client_(params.sct_supported_by_client),
1374 sni_(params.sni),
1375 message_(std::move(message)),
1376 cb_(std::move(cb)) {}
1377
1378void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1379 Run(bool ok,
1380 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
1381 const QuicCryptoProof& proof,
1382 std::unique_ptr<ProofSource::Details> details) {
1383 config_->FinishBuildServerConfigUpdateMessage(
QUICHE team39a71e52019-03-15 14:24:34 -07001384 compressed_certs_cache_, common_cert_sets_, client_common_set_hashes_,
1385 client_cached_cert_hashes_, sct_supported_by_client_, sni_, ok, chain,
1386 proof.signature, proof.leaf_cert_scts, std::move(details),
1387 std::move(message_), std::move(cb_));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001388}
1389
1390void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001391 QuicCompressedCertsCache* compressed_certs_cache,
1392 const CommonCertSets* common_cert_sets,
vasilvvc48c8712019-03-11 13:38:16 -07001393 const std::string& client_common_set_hashes,
1394 const std::string& client_cached_cert_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001395 bool sct_supported_by_client,
vasilvvc48c8712019-03-11 13:38:16 -07001396 const std::string& sni,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001397 bool ok,
1398 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
vasilvvc48c8712019-03-11 13:38:16 -07001399 const std::string& signature,
1400 const std::string& leaf_cert_sct,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001401 std::unique_ptr<ProofSource::Details> details,
1402 CryptoHandshakeMessage message,
1403 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
1404 if (!ok) {
1405 cb->Run(false, message);
1406 return;
1407 }
1408
vasilvvc48c8712019-03-11 13:38:16 -07001409 const std::string compressed =
QUICHE teama6ef0a62019-03-07 20:34:33 -05001410 CompressChain(compressed_certs_cache, chain, client_common_set_hashes,
1411 client_cached_cert_hashes, common_cert_sets);
1412
1413 message.SetStringPiece(kCertificateTag, compressed);
1414 message.SetStringPiece(kPROF, signature);
1415 if (sct_supported_by_client && enable_serving_sct_) {
1416 if (leaf_cert_sct.empty()) {
1417 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
1418 << "SCT is expected but it is empty. SNI: " << sni;
1419 } else {
1420 message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct);
1421 }
1422 }
1423
1424 cb->Run(true, message);
1425}
1426
QUICHE teamaa924f12019-03-21 11:26:21 -07001427void QuicCryptoServerConfig::BuildRejectionAndRecordStats(
1428 const ProcessClientHelloContext& context,
1429 const Config& config,
1430 const std::vector<uint32_t>& reject_reasons,
1431 CryptoHandshakeMessage* out) const {
1432 BuildRejection(context, config, reject_reasons, out);
1433 if (rejection_observer_ != nullptr) {
1434 rejection_observer_->OnRejectionBuilt(reject_reasons, out);
1435 }
1436}
1437
QUICHE teama6ef0a62019-03-07 20:34:33 -05001438void QuicCryptoServerConfig::BuildRejection(
QUICHE team4dae8412019-03-18 13:11:00 -07001439 const ProcessClientHelloContext& context,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001440 const Config& config,
QUICHE teame6dcf322019-03-19 12:23:47 -07001441 const std::vector<uint32_t>& reject_reasons,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001442 CryptoHandshakeMessage* out) const {
QUICHE team4dae8412019-03-18 13:11:00 -07001443 const QuicWallTime now = context.clock()->WallNow();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001444 if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) &&
QUICHE team4dae8412019-03-18 13:11:00 -07001445 context.use_stateless_rejects()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001446 QUIC_DVLOG(1) << "QUIC Crypto server config returning stateless reject "
1447 << "with server-designated connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -07001448 << context.server_designated_connection_id();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001449 out->set_tag(kSREJ);
vasilvvc48c8712019-03-11 13:38:16 -07001450 if (!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -07001451 context.server_designated_connection_id(),
1452 context.transport_version())) {
vasilvvc48c8712019-03-11 13:38:16 -07001453 QUIC_BUG << "Tried to send server designated connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -07001454 << context.server_designated_connection_id()
vasilvvc48c8712019-03-11 13:38:16 -07001455 << " which is invalid with version "
QUICHE team4dae8412019-03-18 13:11:00 -07001456 << QuicVersionToString(context.transport_version());
vasilvvc48c8712019-03-11 13:38:16 -07001457 return;
1458 }
1459 out->SetStringPiece(
QUICHE team4dae8412019-03-18 13:11:00 -07001460 kRCID,
1461 QuicStringPiece(context.server_designated_connection_id().data(),
1462 context.server_designated_connection_id().length()));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001463 } else {
1464 out->set_tag(kREJ);
1465 }
1466 out->SetStringPiece(kSCFG, config.serialized);
1467 out->SetStringPiece(
1468 kSourceAddressTokenTag,
QUICHE team4dae8412019-03-18 13:11:00 -07001469 NewSourceAddressToken(
1470 config, context.info().source_address_tokens,
1471 context.info().client_ip, context.rand(), context.info().now,
1472 &context.validate_chlo_result()->cached_network_params));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001473 out->SetValue(kSTTL, config.expiry_time.AbsoluteDifference(now).ToSeconds());
1474 if (replay_protection_) {
QUICHE team4dae8412019-03-18 13:11:00 -07001475 out->SetStringPiece(kServerNonceTag,
1476 NewServerNonce(context.rand(), context.info().now));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001477 }
1478
1479 // Send client the reject reason for debugging purposes.
QUICHE teame6dcf322019-03-19 12:23:47 -07001480 DCHECK_LT(0u, reject_reasons.size());
1481 out->SetVector(kRREJ, reject_reasons);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001482
1483 // The client may have requested a certificate chain.
QUICHE team4dae8412019-03-18 13:11:00 -07001484 if (!ClientDemandsX509Proof(context.client_hello())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001485 QUIC_BUG << "x509 certificates not supported in proof demand";
1486 return;
1487 }
1488
1489 QuicStringPiece client_common_set_hashes;
QUICHE team4dae8412019-03-18 13:11:00 -07001490 if (context.client_hello().GetStringPiece(kCCS, &client_common_set_hashes)) {
1491 context.params()->client_common_set_hashes =
1492 std::string(client_common_set_hashes);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001493 }
1494
1495 QuicStringPiece client_cached_cert_hashes;
QUICHE team4dae8412019-03-18 13:11:00 -07001496 if (context.client_hello().GetStringPiece(kCCRT,
1497 &client_cached_cert_hashes)) {
1498 context.params()->client_cached_cert_hashes =
1499 std::string(client_cached_cert_hashes);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001500 } else {
QUICHE team4dae8412019-03-18 13:11:00 -07001501 context.params()->client_cached_cert_hashes.clear();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001502 }
1503
QUICHE team4dae8412019-03-18 13:11:00 -07001504 const std::string compressed = CompressChain(
1505 context.compressed_certs_cache(), context.signed_config()->chain,
1506 context.params()->client_common_set_hashes,
1507 context.params()->client_cached_cert_hashes, config.common_cert_sets);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001508
QUICHE team4dae8412019-03-18 13:11:00 -07001509 DCHECK_GT(context.chlo_packet_size(), context.client_hello().size());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001510 // kREJOverheadBytes is a very rough estimate of how much of a REJ
1511 // message is taken up by things other than the certificates.
1512 // STK: 56 bytes
1513 // SNO: 56 bytes
1514 // SCFG
1515 // SCID: 16 bytes
1516 // PUBS: 38 bytes
1517 const size_t kREJOverheadBytes = 166;
1518 // max_unverified_size is the number of bytes that the certificate chain,
1519 // signature, and (optionally) signed certificate timestamp can consume before
1520 // we will demand a valid source-address token.
1521 const size_t max_unverified_size =
QUICHE team4dae8412019-03-18 13:11:00 -07001522 chlo_multiplier_ *
1523 (context.chlo_packet_size() - context.total_framing_overhead()) -
QUICHE teama6ef0a62019-03-07 20:34:33 -05001524 kREJOverheadBytes;
1525 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
1526 "overhead calculation may underflow");
1527 bool should_return_sct =
QUICHE team4dae8412019-03-18 13:11:00 -07001528 context.params()->sct_supported_by_client && enable_serving_sct_;
1529 const std::string& cert_sct = context.signed_config()->proof.leaf_cert_scts;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001530 const size_t sct_size = should_return_sct ? cert_sct.size() : 0;
QUICHE team4dae8412019-03-18 13:11:00 -07001531 const size_t total_size = context.signed_config()->proof.signature.size() +
1532 compressed.size() + sct_size;
1533 if (context.info().valid_source_address_token ||
1534 total_size < max_unverified_size) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001535 out->SetStringPiece(kCertificateTag, compressed);
QUICHE team4dae8412019-03-18 13:11:00 -07001536 out->SetStringPiece(kPROF, context.signed_config()->proof.signature);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001537 if (should_return_sct) {
1538 if (cert_sct.empty()) {
1539 if (!GetQuicReloadableFlag(quic_log_cert_name_for_empty_sct)) {
1540 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001541 << "SCT is expected but it is empty. sni :"
1542 << context.params()->sni;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001543 } else {
1544 // Log SNI and subject name for the leaf cert if its SCT is empty.
1545 // This is for debugging b/28342827.
QUICHE team4dae8412019-03-18 13:11:00 -07001546 const std::vector<std::string>& certs =
1547 context.signed_config()->chain->certs;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001548 QuicStringPiece ca_subject;
1549 if (!certs.empty()) {
1550 QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject);
1551 }
1552 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001553 << "SCT is expected but it is empty. sni: '"
1554 << context.params()->sni << "' cert subject: '" << ca_subject
1555 << "'";
QUICHE teama6ef0a62019-03-07 20:34:33 -05001556 }
1557 } else {
1558 out->SetStringPiece(kCertificateSCTTag, cert_sct);
1559 }
1560 }
1561 } else {
1562 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001563 << "Sending inchoate REJ for hostname: " << context.info().sni
1564 << " signature: " << context.signed_config()->proof.signature.size()
QUICHE teama6ef0a62019-03-07 20:34:33 -05001565 << " cert: " << compressed.size() << " sct:" << sct_size
1566 << " total: " << total_size << " max: " << max_unverified_size;
1567 }
1568}
1569
vasilvvc48c8712019-03-11 13:38:16 -07001570std::string QuicCryptoServerConfig::CompressChain(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001571 QuicCompressedCertsCache* compressed_certs_cache,
1572 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
vasilvvc48c8712019-03-11 13:38:16 -07001573 const std::string& client_common_set_hashes,
1574 const std::string& client_cached_cert_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001575 const CommonCertSets* common_sets) {
1576 // Check whether the compressed certs is available in the cache.
1577 DCHECK(compressed_certs_cache);
vasilvvc48c8712019-03-11 13:38:16 -07001578 const std::string* cached_value = compressed_certs_cache->GetCompressedCert(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001579 chain, client_common_set_hashes, client_cached_cert_hashes);
1580 if (cached_value) {
1581 return *cached_value;
1582 }
vasilvvc48c8712019-03-11 13:38:16 -07001583 std::string compressed =
QUICHE teama6ef0a62019-03-07 20:34:33 -05001584 CertCompressor::CompressChain(chain->certs, client_common_set_hashes,
1585 client_cached_cert_hashes, common_sets);
1586 // Insert the newly compressed cert to cache.
1587 compressed_certs_cache->Insert(chain, client_common_set_hashes,
1588 client_cached_cert_hashes, compressed);
1589 return compressed;
1590}
1591
1592QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
1593QuicCryptoServerConfig::ParseConfigProtobuf(
QUICHE team99055cf2019-03-22 11:27:53 -07001594 const QuicServerConfigProtobuf& protobuf,
1595 bool is_fallback) const {
QUICHE teamfe1aca62019-03-14 13:39:01 -07001596 std::unique_ptr<CryptoHandshakeMessage> msg =
QUICHE teambbaa8be2019-03-21 12:54:17 -07001597 CryptoFramer::ParseMessage(protobuf.config());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001598
1599 if (msg->tag() != kSCFG) {
1600 QUIC_LOG(WARNING) << "Server config message has tag " << msg->tag()
1601 << " expected " << kSCFG;
1602 return nullptr;
1603 }
1604
1605 QuicReferenceCountedPointer<Config> config(new Config);
QUICHE teambbaa8be2019-03-21 12:54:17 -07001606 config->serialized = protobuf.config();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001607 config->source_address_token_boxer = &source_address_token_boxer_;
1608
QUICHE teambbaa8be2019-03-21 12:54:17 -07001609 if (protobuf.has_primary_time()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001610 config->primary_time =
QUICHE teambbaa8be2019-03-21 12:54:17 -07001611 QuicWallTime::FromUNIXSeconds(protobuf.primary_time());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001612 }
1613
QUICHE teambbaa8be2019-03-21 12:54:17 -07001614 config->priority = protobuf.priority();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001615
1616 QuicStringPiece scid;
1617 if (!msg->GetStringPiece(kSCID, &scid)) {
1618 QUIC_LOG(WARNING) << "Server config message is missing SCID";
1619 return nullptr;
1620 }
vasilvvc48c8712019-03-11 13:38:16 -07001621 config->id = std::string(scid);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001622
1623 if (msg->GetTaglist(kAEAD, &config->aead) != QUIC_NO_ERROR) {
1624 QUIC_LOG(WARNING) << "Server config message is missing AEAD";
1625 return nullptr;
1626 }
1627
1628 QuicTagVector kexs_tags;
1629 if (msg->GetTaglist(kKEXS, &kexs_tags) != QUIC_NO_ERROR) {
1630 QUIC_LOG(WARNING) << "Server config message is missing KEXS";
1631 return nullptr;
1632 }
1633
1634 QuicErrorCode err;
1635 if ((err = msg->GetTaglist(kTBKP, &config->tb_key_params)) !=
1636 QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND &&
1637 err != QUIC_NO_ERROR) {
1638 QUIC_LOG(WARNING) << "Server config message is missing or has invalid TBKP";
1639 return nullptr;
1640 }
1641
1642 QuicStringPiece orbit;
1643 if (!msg->GetStringPiece(kORBT, &orbit)) {
1644 QUIC_LOG(WARNING) << "Server config message is missing ORBT";
1645 return nullptr;
1646 }
1647
1648 if (orbit.size() != kOrbitSize) {
1649 QUIC_LOG(WARNING) << "Orbit value in server config is the wrong length."
1650 " Got "
1651 << orbit.size() << " want " << kOrbitSize;
1652 return nullptr;
1653 }
1654 static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size");
1655 memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
1656
QUICHE team59882932019-03-27 11:02:17 -07001657 if ((kexs_tags.size() != static_cast<size_t>(protobuf.key_size())) &&
1658 (!GetQuicRestartFlag(dont_fetch_quic_private_keys_from_leto) &&
1659 protobuf.key_size() == 0)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001660 QUIC_LOG(WARNING) << "Server config has " << kexs_tags.size()
1661 << " key exchange methods configured, but "
QUICHE teambbaa8be2019-03-21 12:54:17 -07001662 << protobuf.key_size() << " private keys";
QUICHE teama6ef0a62019-03-07 20:34:33 -05001663 return nullptr;
1664 }
1665
1666 QuicTagVector proof_demand_tags;
1667 if (msg->GetTaglist(kPDMD, &proof_demand_tags) == QUIC_NO_ERROR) {
1668 for (QuicTag tag : proof_demand_tags) {
1669 if (tag == kCHID) {
1670 config->channel_id_enabled = true;
1671 break;
1672 }
1673 }
1674 }
1675
1676 for (size_t i = 0; i < kexs_tags.size(); i++) {
1677 const QuicTag tag = kexs_tags[i];
vasilvvc48c8712019-03-11 13:38:16 -07001678 std::string private_key;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001679
1680 config->kexs.push_back(tag);
1681
QUICHE teambbaa8be2019-03-21 12:54:17 -07001682 for (int j = 0; j < protobuf.key_size(); j++) {
1683 const QuicServerConfigProtobuf::PrivateKey& key = protobuf.key(i);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001684 if (key.tag() == tag) {
1685 private_key = key.private_key();
1686 break;
1687 }
1688 }
1689
QUICHE team99055cf2019-03-22 11:27:53 -07001690 std::unique_ptr<AsynchronousKeyExchange> ka =
1691 key_exchange_source_->Create(config->id, is_fallback, tag, private_key);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001692 if (!ka) {
1693 return nullptr;
1694 }
1695 for (const auto& key_exchange : config->key_exchanges) {
QUICHE teamfe1aca62019-03-14 13:39:01 -07001696 if (key_exchange->type() == tag) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001697 QUIC_LOG(WARNING) << "Duplicate key exchange in config: " << tag;
1698 return nullptr;
1699 }
1700 }
1701
1702 config->key_exchanges.push_back(std::move(ka));
1703 }
1704
1705 uint64_t expiry_seconds;
1706 if (msg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
1707 QUIC_LOG(WARNING) << "Server config message is missing EXPY";
1708 return nullptr;
1709 }
1710 config->expiry_time = QuicWallTime::FromUNIXSeconds(expiry_seconds);
1711
1712 return config;
1713}
1714
1715void QuicCryptoServerConfig::set_replay_protection(bool on) {
1716 replay_protection_ = on;
1717}
1718
1719void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) {
1720 chlo_multiplier_ = multiplier;
1721}
1722
1723void QuicCryptoServerConfig::set_source_address_token_future_secs(
1724 uint32_t future_secs) {
1725 source_address_token_future_secs_ = future_secs;
1726}
1727
1728void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
1729 uint32_t lifetime_secs) {
1730 source_address_token_lifetime_secs_ = lifetime_secs;
1731}
1732
1733void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) {
1734 enable_serving_sct_ = enable_serving_sct;
1735}
1736
1737void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
1738 std::unique_ptr<PrimaryConfigChangedCallback> cb) {
1739 QuicWriterMutexLock locked(&configs_lock_);
1740 primary_config_changed_cb_ = std::move(cb);
1741}
1742
vasilvvc48c8712019-03-11 13:38:16 -07001743std::string QuicCryptoServerConfig::NewSourceAddressToken(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001744 const Config& config,
1745 const SourceAddressTokens& previous_tokens,
1746 const QuicIpAddress& ip,
1747 QuicRandom* rand,
1748 QuicWallTime now,
1749 const CachedNetworkParameters* cached_network_params) const {
1750 SourceAddressTokens source_address_tokens;
1751 SourceAddressToken* source_address_token = source_address_tokens.add_tokens();
1752 source_address_token->set_ip(ip.DualStacked().ToPackedString());
1753 source_address_token->set_timestamp(now.ToUNIXSeconds());
1754 if (cached_network_params != nullptr) {
1755 *(source_address_token->mutable_cached_network_parameters()) =
1756 *cached_network_params;
1757 }
1758
1759 // Append previous tokens.
1760 for (const SourceAddressToken& token : previous_tokens.tokens()) {
1761 if (source_address_tokens.tokens_size() > kMaxTokenAddresses) {
1762 break;
1763 }
1764
1765 if (token.ip() == source_address_token->ip()) {
1766 // It's for the same IP address.
1767 continue;
1768 }
1769
1770 if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) {
1771 continue;
1772 }
1773
1774 *(source_address_tokens.add_tokens()) = token;
1775 }
1776
1777 return config.source_address_token_boxer->Box(
1778 rand, source_address_tokens.SerializeAsString());
1779}
1780
1781int QuicCryptoServerConfig::NumberOfConfigs() const {
1782 QuicReaderMutexLock locked(&configs_lock_);
1783 return configs_.size();
1784}
1785
1786ProofSource* QuicCryptoServerConfig::proof_source() const {
1787 return proof_source_.get();
1788}
1789
1790SSL_CTX* QuicCryptoServerConfig::ssl_ctx() const {
1791 return ssl_ctx_.get();
1792}
1793
1794HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken(
1795 const Config& config,
1796 QuicStringPiece token,
1797 SourceAddressTokens* tokens) const {
vasilvvc48c8712019-03-11 13:38:16 -07001798 std::string storage;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001799 QuicStringPiece plaintext;
1800 if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) {
1801 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
1802 }
1803
1804 if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) {
1805 // Some clients might still be using the old source token format so
1806 // attempt to parse that format.
1807 // TODO(rch): remove this code once the new format is ubiquitous.
1808 SourceAddressToken token;
1809 if (!token.ParseFromArray(plaintext.data(), plaintext.size())) {
1810 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
1811 }
1812 *tokens->add_tokens() = token;
1813 }
1814
1815 return HANDSHAKE_OK;
1816}
1817
1818HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens(
1819 const SourceAddressTokens& source_address_tokens,
1820 const QuicIpAddress& ip,
1821 QuicWallTime now,
1822 CachedNetworkParameters* cached_network_params) const {
1823 HandshakeFailureReason reason =
1824 SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1825 for (const SourceAddressToken& token : source_address_tokens.tokens()) {
1826 reason = ValidateSingleSourceAddressToken(token, ip, now);
1827 if (reason == HANDSHAKE_OK) {
1828 if (token.has_cached_network_parameters()) {
1829 *cached_network_params = token.cached_network_parameters();
1830 }
1831 break;
1832 }
1833 }
1834 return reason;
1835}
1836
1837HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken(
1838 const SourceAddressToken& source_address_token,
1839 const QuicIpAddress& ip,
1840 QuicWallTime now) const {
1841 if (source_address_token.ip() != ip.DualStacked().ToPackedString()) {
1842 // It's for a different IP address.
1843 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1844 }
1845
1846 return ValidateSourceAddressTokenTimestamp(source_address_token, now);
1847}
1848
1849HandshakeFailureReason
1850QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp(
1851 const SourceAddressToken& source_address_token,
1852 QuicWallTime now) const {
1853 const QuicWallTime timestamp(
1854 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
1855 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
1856
1857 if (now.IsBefore(timestamp) &&
1858 delta.ToSeconds() > source_address_token_future_secs_) {
1859 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
1860 }
1861
1862 if (now.IsAfter(timestamp) &&
1863 delta.ToSeconds() > source_address_token_lifetime_secs_) {
1864 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
1865 }
1866
1867 return HANDSHAKE_OK;
1868}
1869
1870// kServerNoncePlaintextSize is the number of bytes in an unencrypted server
1871// nonce.
1872static const size_t kServerNoncePlaintextSize =
1873 4 /* timestamp */ + 20 /* random bytes */;
1874
vasilvvc48c8712019-03-11 13:38:16 -07001875std::string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
1876 QuicWallTime now) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001877 const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds());
1878
1879 uint8_t server_nonce[kServerNoncePlaintextSize];
1880 static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small");
1881 server_nonce[0] = static_cast<uint8_t>(timestamp >> 24);
1882 server_nonce[1] = static_cast<uint8_t>(timestamp >> 16);
1883 server_nonce[2] = static_cast<uint8_t>(timestamp >> 8);
1884 server_nonce[3] = static_cast<uint8_t>(timestamp);
1885 rand->RandBytes(&server_nonce[sizeof(timestamp)],
1886 sizeof(server_nonce) - sizeof(timestamp));
1887
1888 return server_nonce_boxer_.Box(
1889 rand, QuicStringPiece(reinterpret_cast<char*>(server_nonce),
1890 sizeof(server_nonce)));
1891}
1892
1893bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate(
1894 const CryptoHandshakeMessage& client_hello,
vasilvvc48c8712019-03-11 13:38:16 -07001895 const std::vector<std::string>& certs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001896 if (certs.empty()) {
1897 return false;
1898 }
1899
1900 uint64_t hash_from_client;
1901 if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) {
1902 return false;
1903 }
1904 return CryptoUtils::ComputeLeafCertHash(certs.at(0)) == hash_from_client;
1905}
1906
QUICHE teama6ef0a62019-03-07 20:34:33 -05001907bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001908 return !next_config_promotion_time_.IsZero() &&
rcha19b43d2019-03-22 13:58:37 -07001909 !next_config_promotion_time_.IsAfter(now);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001910}
1911
1912QuicCryptoServerConfig::Config::Config()
1913 : channel_id_enabled(false),
1914 is_primary(false),
1915 primary_time(QuicWallTime::Zero()),
1916 expiry_time(QuicWallTime::Zero()),
1917 priority(0),
1918 source_address_token_boxer(nullptr) {}
1919
1920QuicCryptoServerConfig::Config::~Config() {}
1921
1922QuicSignedServerConfig::QuicSignedServerConfig() {}
1923QuicSignedServerConfig::~QuicSignedServerConfig() {}
1924
1925} // namespace quic