blob: 50ea2f88264c934e7be0fe18708b4e2b9532784b [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"
nharper6ebe83b2019-06-13 17:43:52 -070030#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h"
dschinazi56fb53e2019-06-21 15:30:04 -070031#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config_proto.h"
32#include "net/third_party/quiche/src/quic/core/proto/source_address_token_proto.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050033#include "net/third_party/quiche/src/quic/core/quic_packets.h"
34#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h"
35#include "net/third_party/quiche/src/quic/core/quic_types.h"
36#include "net/third_party/quiche/src/quic/core/quic_utils.h"
37#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
38#include "net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h"
39#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
40#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
41#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
42#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
43#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
44#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
45#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
46#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
47#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050048#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
49#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
50
51namespace quic {
52
53namespace {
54
55// kMultiplier is the multiple of the CHLO message size that a REJ message
56// must stay under when the client doesn't present a valid source-address
57// token. This is used to protect QUIC from amplification attacks.
58// TODO(rch): Reduce this to 2 again once b/25933682 is fixed.
59const size_t kMultiplier = 3;
60
61const int kMaxTokenAddresses = 4;
62
vasilvvc48c8712019-03-11 13:38:16 -070063std::string DeriveSourceAddressTokenKey(
QUICHE teama6ef0a62019-03-07 20:34:33 -050064 QuicStringPiece source_address_token_secret) {
65 QuicHKDF hkdf(source_address_token_secret, QuicStringPiece() /* no salt */,
66 "QUIC source address token key",
67 CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */,
68 0 /* no subkey secret */);
vasilvvc48c8712019-03-11 13:38:16 -070069 return std::string(hkdf.server_write_key());
QUICHE teama6ef0a62019-03-07 20:34:33 -050070}
71
72// Default source for creating KeyExchange objects.
73class DefaultKeyExchangeSource : public KeyExchangeSource {
74 public:
75 DefaultKeyExchangeSource() = default;
76 ~DefaultKeyExchangeSource() override = default;
77
QUICHE teamfe1aca62019-03-14 13:39:01 -070078 std::unique_ptr<AsynchronousKeyExchange> Create(
dschinazi17d42422019-06-18 16:35:07 -070079 std::string /*server_config_id*/,
QUICHE teamf03456c2019-03-21 08:54:47 -070080 bool /* is_fallback */,
QUICHE teamfe1aca62019-03-14 13:39:01 -070081 QuicTag type,
82 QuicStringPiece private_key) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -050083 if (private_key.empty()) {
84 QUIC_LOG(WARNING) << "Server config contains key exchange method without "
QUICHE teamfe1aca62019-03-14 13:39:01 -070085 "corresponding private key of type "
86 << QuicTagToString(type);
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 return nullptr;
88 }
89
QUICHE teamfe1aca62019-03-14 13:39:01 -070090 std::unique_ptr<SynchronousKeyExchange> ka =
91 CreateLocalSynchronousKeyExchange(type, private_key);
92 if (!ka) {
93 QUIC_LOG(WARNING) << "Failed to create key exchange method of type "
94 << QuicTagToString(type);
QUICHE teama6ef0a62019-03-07 20:34:33 -050095 }
96 return ka;
97 }
98};
99
QUICHE teame29fcd62019-03-15 13:54:47 -0700100// Returns true if the PDMD field from the client hello demands an X509
101// certificate.
102bool ClientDemandsX509Proof(const CryptoHandshakeMessage& client_hello) {
103 QuicTagVector their_proof_demands;
104
105 if (client_hello.GetTaglist(kPDMD, &their_proof_demands) != QUIC_NO_ERROR) {
106 return false;
107 }
108
109 for (const QuicTag tag : their_proof_demands) {
110 if (tag == kX509) {
111 return true;
112 }
113 }
114 return false;
115}
116
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117} // namespace
118
119// static
120std::unique_ptr<KeyExchangeSource> KeyExchangeSource::Default() {
121 return QuicMakeUnique<DefaultKeyExchangeSource>();
122}
123
124class ValidateClientHelloHelper {
125 public:
126 // Note: stores a pointer to a unique_ptr, and std::moves the unique_ptr when
127 // ValidationComplete is called.
128 ValidateClientHelloHelper(
129 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
130 result,
131 std::unique_ptr<ValidateClientHelloResultCallback>* done_cb)
132 : result_(std::move(result)), done_cb_(done_cb) {}
133 ValidateClientHelloHelper(const ValidateClientHelloHelper&) = delete;
134 ValidateClientHelloHelper& operator=(const ValidateClientHelloHelper&) =
135 delete;
136
137 ~ValidateClientHelloHelper() {
138 QUIC_BUG_IF(done_cb_ != nullptr)
139 << "Deleting ValidateClientHelloHelper with a pending callback.";
140 }
141
142 void ValidationComplete(
143 QuicErrorCode error_code,
144 const char* error_details,
145 std::unique_ptr<ProofSource::Details> proof_source_details) {
146 result_->error_code = error_code;
147 result_->error_details = error_details;
148 (*done_cb_)->Run(std::move(result_), std::move(proof_source_details));
149 DetachCallback();
150 }
151
152 void DetachCallback() {
153 QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached.";
154 done_cb_ = nullptr;
155 }
156
157 private:
158 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
159 result_;
160 std::unique_ptr<ValidateClientHelloResultCallback>* done_cb_;
161};
162
163// static
164const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
165
166ClientHelloInfo::ClientHelloInfo(const QuicIpAddress& in_client_ip,
167 QuicWallTime in_now)
168 : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {}
169
170ClientHelloInfo::ClientHelloInfo(const ClientHelloInfo& other) = default;
171
172ClientHelloInfo::~ClientHelloInfo() {}
173
174PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {}
175
176PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {}
177
178ValidateClientHelloResultCallback::Result::Result(
179 const CryptoHandshakeMessage& in_client_hello,
180 QuicIpAddress in_client_ip,
181 QuicWallTime in_now)
182 : client_hello(in_client_hello),
183 info(in_client_ip, in_now),
184 error_code(QUIC_NO_ERROR) {}
185
186ValidateClientHelloResultCallback::Result::~Result() {}
187
188ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {}
189
190ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {}
191
192ProcessClientHelloResultCallback::ProcessClientHelloResultCallback() {}
193
194ProcessClientHelloResultCallback::~ProcessClientHelloResultCallback() {}
195
196QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
197 : expiry_time(QuicWallTime::Zero()),
198 channel_id_enabled(false),
199 p256(false) {}
200
201QuicCryptoServerConfig::ConfigOptions::ConfigOptions(
202 const ConfigOptions& other) = default;
203
204QuicCryptoServerConfig::ConfigOptions::~ConfigOptions() {}
205
QUICHE team4dae8412019-03-18 13:11:00 -0700206QuicCryptoServerConfig::ProcessClientHelloContext::
207 ~ProcessClientHelloContext() {
208 if (done_cb_ != nullptr) {
nharperff86db32019-05-08 10:38:23 -0700209 QUIC_LOG(WARNING)
QUICHE team4dae8412019-03-18 13:11:00 -0700210 << "Deleting ProcessClientHelloContext with a pending callback.";
211 }
212}
213
214void QuicCryptoServerConfig::ProcessClientHelloContext::Fail(
215 QuicErrorCode error,
216 const std::string& error_details) {
217 done_cb_->Run(error, error_details, nullptr, nullptr, nullptr);
218 done_cb_ = nullptr;
219}
220
221void QuicCryptoServerConfig::ProcessClientHelloContext::Succeed(
222 std::unique_ptr<CryptoHandshakeMessage> message,
223 std::unique_ptr<DiversificationNonce> diversification_nonce,
224 std::unique_ptr<ProofSource::Details> proof_source_details) {
225 done_cb_->Run(QUIC_NO_ERROR, std::string(), std::move(message),
226 std::move(diversification_nonce),
227 std::move(proof_source_details));
228 done_cb_ = nullptr;
229}
230
QUICHE teama6ef0a62019-03-07 20:34:33 -0500231QuicCryptoServerConfig::QuicCryptoServerConfig(
232 QuicStringPiece source_address_token_secret,
233 QuicRandom* server_nonce_entropy,
234 std::unique_ptr<ProofSource> proof_source,
nharper6ebe83b2019-06-13 17:43:52 -0700235 std::unique_ptr<KeyExchangeSource> key_exchange_source)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500236 : 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)),
nharper1c06fd82019-06-24 14:33:34 -0700243 ssl_ctx_(TlsServerConnection::CreateSslCtx()),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500244 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
QUICHE teama6ef0a62019-03-07 20:34:33 -0500344 if (options.id.empty()) {
345 // We need to ensure that the SCID changes whenever the server config does
346 // thus we make it a hash of the rest of the server config.
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700347 std::unique_ptr<QuicData> serialized =
348 CryptoFramer::ConstructHandshakeMessage(msg);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500349
350 uint8_t scid_bytes[SHA256_DIGEST_LENGTH];
351 SHA256(reinterpret_cast<const uint8_t*>(serialized->data()),
352 serialized->length(), scid_bytes);
353 // The SCID is a truncated SHA-256 digest.
354 static_assert(16 <= SHA256_DIGEST_LENGTH, "SCID length too high.");
355 msg.SetStringPiece(
356 kSCID, QuicStringPiece(reinterpret_cast<const char*>(scid_bytes), 16));
357 } else {
358 msg.SetStringPiece(kSCID, options.id);
359 }
360 // Don't put new tags below this point. The SCID generation should hash over
361 // everything but itself and so extra tags should be added prior to the
362 // preceding if block.
363
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700364 std::unique_ptr<QuicData> serialized =
365 CryptoFramer::ConstructHandshakeMessage(msg);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500366
QUICHE teambbaa8be2019-03-21 12:54:17 -0700367 QuicServerConfigProtobuf config;
368 config.set_config(std::string(serialized->AsStringPiece()));
369 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config.add_key();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500370 curve25519_key->set_tag(kC255);
371 curve25519_key->set_private_key(curve25519_private_key);
372
373 if (options.p256) {
QUICHE teambbaa8be2019-03-21 12:54:17 -0700374 QuicServerConfigProtobuf::PrivateKey* p256_key = config.add_key();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500375 p256_key->set_tag(kP256);
376 p256_key->set_private_key(p256_private_key);
377 }
378
379 return config;
380}
381
QUICHE teamd5af58a2019-03-14 20:35:50 -0700382std::unique_ptr<CryptoHandshakeMessage> QuicCryptoServerConfig::AddConfig(
QUICHE teambbaa8be2019-03-21 12:54:17 -0700383 const QuicServerConfigProtobuf& protobuf,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500384 const QuicWallTime now) {
QUICHE teamd5af58a2019-03-14 20:35:50 -0700385 std::unique_ptr<CryptoHandshakeMessage> msg =
QUICHE teambbaa8be2019-03-21 12:54:17 -0700386 CryptoFramer::ParseMessage(protobuf.config());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500387
388 if (!msg.get()) {
389 QUIC_LOG(WARNING) << "Failed to parse server config message";
390 return nullptr;
391 }
392
QUICHE team99055cf2019-03-22 11:27:53 -0700393 QuicReferenceCountedPointer<Config> config =
394 ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500395 if (!config.get()) {
396 QUIC_LOG(WARNING) << "Failed to parse server config message";
397 return nullptr;
398 }
399
400 {
401 QuicWriterMutexLock locked(&configs_lock_);
402 if (configs_.find(config->id) != configs_.end()) {
403 QUIC_LOG(WARNING) << "Failed to add config because another with the same "
404 "server config id already exists: "
405 << QuicTextUtils::HexEncode(config->id);
406 return nullptr;
407 }
408
409 configs_[config->id] = config;
410 SelectNewPrimaryConfig(now);
411 DCHECK(primary_config_.get());
412 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
413 primary_config_.get());
414 }
415
QUICHE teamd5af58a2019-03-14 20:35:50 -0700416 return msg;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500417}
418
QUICHE teamd5af58a2019-03-14 20:35:50 -0700419std::unique_ptr<CryptoHandshakeMessage>
420QuicCryptoServerConfig::AddDefaultConfig(QuicRandom* rand,
421 const QuicClock* clock,
422 const ConfigOptions& options) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500423 return AddConfig(GenerateConfig(rand, clock, options), clock->WallNow());
424}
425
426bool QuicCryptoServerConfig::SetConfigs(
QUICHE teambbaa8be2019-03-21 12:54:17 -0700427 const std::vector<QuicServerConfigProtobuf>& protobufs,
QUICHE team99055cf2019-03-22 11:27:53 -0700428 const QuicServerConfigProtobuf* fallback_protobuf,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500429 const QuicWallTime now) {
430 std::vector<QuicReferenceCountedPointer<Config>> parsed_configs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500431 for (auto& protobuf : protobufs) {
QUICHE team99055cf2019-03-22 11:27:53 -0700432 QuicReferenceCountedPointer<Config> config =
433 ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500434 if (!config) {
QUICHE team78c2d5e2019-03-19 10:50:50 -0700435 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
436 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500437 }
438
439 parsed_configs.push_back(config);
440 }
441
QUICHE team99055cf2019-03-22 11:27:53 -0700442 QuicReferenceCountedPointer<Config> fallback_config;
443 if (fallback_protobuf != nullptr) {
444 fallback_config =
445 ParseConfigProtobuf(*fallback_protobuf, /* is_fallback = */ true);
446 if (!fallback_config) {
447 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
448 return false;
449 }
450 QUIC_LOG(INFO) << "Fallback config has scid "
451 << QuicTextUtils::HexEncode(fallback_config->id);
452 parsed_configs.push_back(fallback_config);
453 } else {
454 QUIC_LOG(INFO) << "No fallback config provided";
455 }
456
QUICHE teama6ef0a62019-03-07 20:34:33 -0500457 if (parsed_configs.empty()) {
QUICHE team78c2d5e2019-03-19 10:50:50 -0700458 QUIC_LOG(WARNING)
459 << "Rejecting QUIC configs because new config list is empty.";
460 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500461 }
462
QUICHE team78c2d5e2019-03-19 10:50:50 -0700463 QUIC_LOG(INFO) << "Updating configs:";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500464
QUICHE team78c2d5e2019-03-19 10:50:50 -0700465 QuicWriterMutexLock locked(&configs_lock_);
466 ConfigMap new_configs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500467
QUICHE team78c2d5e2019-03-19 10:50:50 -0700468 for (const QuicReferenceCountedPointer<Config>& config : parsed_configs) {
469 auto it = configs_.find(config->id);
470 if (it != configs_.end()) {
471 QUIC_LOG(INFO) << "Keeping scid: " << QuicTextUtils::HexEncode(config->id)
472 << " orbit: "
473 << QuicTextUtils::HexEncode(
474 reinterpret_cast<const char*>(config->orbit),
475 kOrbitSize)
476 << " new primary_time "
477 << config->primary_time.ToUNIXSeconds()
478 << " old primary_time "
479 << it->second->primary_time.ToUNIXSeconds()
480 << " new priority " << config->priority << " old priority "
481 << it->second->priority;
482 // Update primary_time and priority.
483 it->second->primary_time = config->primary_time;
484 it->second->priority = config->priority;
485 new_configs.insert(*it);
486 } else {
487 QUIC_LOG(INFO) << "Adding scid: " << QuicTextUtils::HexEncode(config->id)
488 << " orbit: "
489 << QuicTextUtils::HexEncode(
490 reinterpret_cast<const char*>(config->orbit),
491 kOrbitSize)
492 << " primary_time " << config->primary_time.ToUNIXSeconds()
493 << " priority " << config->priority;
494 new_configs.emplace(config->id, config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500495 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500496 }
497
QUICHE team78c2d5e2019-03-19 10:50:50 -0700498 configs_ = std::move(new_configs);
QUICHE team99055cf2019-03-22 11:27:53 -0700499 fallback_config_ = fallback_config;
QUICHE team78c2d5e2019-03-19 10:50:50 -0700500 SelectNewPrimaryConfig(now);
501 DCHECK(primary_config_.get());
502 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
503 primary_config_.get());
504
505 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500506}
507
508void QuicCryptoServerConfig::SetSourceAddressTokenKeys(
vasilvvc48c8712019-03-11 13:38:16 -0700509 const std::vector<std::string>& keys) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500510 source_address_token_boxer_.SetKeys(keys);
511}
512
513void QuicCryptoServerConfig::GetConfigIds(
vasilvvc48c8712019-03-11 13:38:16 -0700514 std::vector<std::string>* scids) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500515 QuicReaderMutexLock locked(&configs_lock_);
516 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
517 scids->push_back(it->first);
518 }
519}
520
521void QuicCryptoServerConfig::ValidateClientHello(
522 const CryptoHandshakeMessage& client_hello,
523 const QuicIpAddress& client_ip,
524 const QuicSocketAddress& server_address,
525 QuicTransportVersion version,
526 const QuicClock* clock,
527 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
528 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
529 const QuicWallTime now(clock->WallNow());
530
531 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result(
532 new ValidateClientHelloResultCallback::Result(client_hello, client_ip,
533 now));
534
535 QuicStringPiece requested_scid;
536 client_hello.GetStringPiece(kSCID, &requested_scid);
QUICHE team1225f472019-03-19 15:52:25 -0700537 Configs configs;
538 if (!GetCurrentConfigs(now, requested_scid,
539 /* old_primary_config = */ nullptr, &configs)) {
540 result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
541 result->error_details = "No configurations loaded";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500542 }
QUICHE team1225f472019-03-19 15:52:25 -0700543 signed_config->config = configs.primary;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500544
545 if (result->error_code == QUIC_NO_ERROR) {
546 // QUIC requires a new proof for each CHLO so clear any existing proof.
547 signed_config->chain = nullptr;
548 signed_config->proof.signature = "";
549 signed_config->proof.leaf_cert_scts = "";
QUICHE team1225f472019-03-19 15:52:25 -0700550 EvaluateClientHello(server_address, version, configs, result,
551 std::move(done_cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500552 } else {
553 done_cb->Run(result, /* details = */ nullptr);
554 }
555}
556
QUICHE teama6ef0a62019-03-07 20:34:33 -0500557class QuicCryptoServerConfig::ProcessClientHelloCallback
558 : public ProofSource::Callback {
559 public:
QUICHE team1225f472019-03-19 15:52:25 -0700560 ProcessClientHelloCallback(const QuicCryptoServerConfig* config,
561 std::unique_ptr<ProcessClientHelloContext> context,
562 const Configs& configs)
563 : config_(config), context_(std::move(context)), configs_(configs) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500564
565 void Run(bool ok,
566 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
567 const QuicCryptoProof& proof,
568 std::unique_ptr<ProofSource::Details> details) override {
569 if (ok) {
QUICHE team4dae8412019-03-18 13:11:00 -0700570 context_->signed_config()->chain = chain;
571 context_->signed_config()->proof = proof;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500572 }
QUICHE team1225f472019-03-19 15:52:25 -0700573 config_->ProcessClientHelloAfterGetProof(!ok, std::move(details),
574 std::move(context_), configs_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500575 }
576
577 private:
578 const QuicCryptoServerConfig* config_;
QUICHE team4dae8412019-03-18 13:11:00 -0700579 std::unique_ptr<ProcessClientHelloContext> context_;
QUICHE team1225f472019-03-19 15:52:25 -0700580 const Configs configs_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500581};
582
583class QuicCryptoServerConfig::ProcessClientHelloAfterGetProofCallback
QUICHE teamfe1aca62019-03-14 13:39:01 -0700584 : public AsynchronousKeyExchange::Callback {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500585 public:
586 ProcessClientHelloAfterGetProofCallback(
587 const QuicCryptoServerConfig* config,
588 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE teamfe1aca62019-03-14 13:39:01 -0700589 QuicTag key_exchange_type,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500590 std::unique_ptr<CryptoHandshakeMessage> out,
591 QuicStringPiece public_value,
QUICHE team4dae8412019-03-18 13:11:00 -0700592 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700593 const Configs& configs)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500594 : config_(config),
595 proof_source_details_(std::move(proof_source_details)),
QUICHE teamfe1aca62019-03-14 13:39:01 -0700596 key_exchange_type_(key_exchange_type),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500597 out_(std::move(out)),
598 public_value_(public_value),
QUICHE team4dae8412019-03-18 13:11:00 -0700599 context_(std::move(context)),
QUICHE team1225f472019-03-19 15:52:25 -0700600 configs_(configs) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500601
602 void Run(bool ok) override {
603 config_->ProcessClientHelloAfterCalculateSharedKeys(
QUICHE teamfe1aca62019-03-14 13:39:01 -0700604 !ok, std::move(proof_source_details_), key_exchange_type_,
QUICHE team1225f472019-03-19 15:52:25 -0700605 std::move(out_), public_value_, std::move(context_), configs_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500606 }
607
608 private:
609 const QuicCryptoServerConfig* config_;
610 std::unique_ptr<ProofSource::Details> proof_source_details_;
QUICHE team99055cf2019-03-22 11:27:53 -0700611 const QuicTag key_exchange_type_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500612 std::unique_ptr<CryptoHandshakeMessage> out_;
QUICHE team99055cf2019-03-22 11:27:53 -0700613 const std::string public_value_;
QUICHE team4dae8412019-03-18 13:11:00 -0700614 std::unique_ptr<ProcessClientHelloContext> context_;
QUICHE team1225f472019-03-19 15:52:25 -0700615 const Configs configs_;
QUICHE team59882932019-03-27 11:02:17 -0700616 std::unique_ptr<ProcessClientHelloResultCallback> done_cb_;
617};
618
619class QuicCryptoServerConfig::SendRejectWithFallbackConfigCallback
620 : public ProofSource::Callback {
621 public:
622 SendRejectWithFallbackConfigCallback(
623 const QuicCryptoServerConfig* config,
624 std::unique_ptr<ProcessClientHelloContext> context,
625 QuicReferenceCountedPointer<Config> fallback_config)
626 : config_(config),
627 context_(std::move(context)),
628 fallback_config_(fallback_config) {}
629
630 // Capture |chain| and |proof| into the signed config, and then invoke
631 // SendRejectWithFallbackConfigAfterGetProof.
632 void Run(bool ok,
633 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
634 const QuicCryptoProof& proof,
635 std::unique_ptr<ProofSource::Details> details) override {
636 if (ok) {
637 context_->signed_config()->chain = chain;
638 context_->signed_config()->proof = proof;
639 }
640 config_->SendRejectWithFallbackConfigAfterGetProof(
641 !ok, std::move(details), std::move(context_), fallback_config_);
642 }
643
644 private:
645 const QuicCryptoServerConfig* config_;
646 std::unique_ptr<ProcessClientHelloContext> context_;
647 QuicReferenceCountedPointer<Config> fallback_config_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500648};
649
650void QuicCryptoServerConfig::ProcessClientHello(
651 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
652 validate_chlo_result,
653 bool reject_only,
654 QuicConnectionId connection_id,
655 const QuicSocketAddress& server_address,
656 const QuicSocketAddress& client_address,
657 ParsedQuicVersion version,
658 const ParsedQuicVersionVector& supported_versions,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500659 const QuicClock* clock,
660 QuicRandom* rand,
661 QuicCompressedCertsCache* compressed_certs_cache,
662 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,
663 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
664 QuicByteCount total_framing_overhead,
665 QuicByteCount chlo_packet_size,
666 std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
667 DCHECK(done_cb);
QUICHE team4dae8412019-03-18 13:11:00 -0700668 auto context = QuicMakeUnique<ProcessClientHelloContext>(
669 validate_chlo_result, reject_only, connection_id, server_address,
wubecf9bd82019-06-05 04:57:02 -0700670 client_address, version, supported_versions, clock, rand,
671 compressed_certs_cache, params, signed_config, total_framing_overhead,
672 chlo_packet_size, std::move(done_cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500673
QUICHE team1225f472019-03-19 15:52:25 -0700674 // Verify that various parts of the CHLO are valid
vasilvvc48c8712019-03-11 13:38:16 -0700675 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500676 QuicErrorCode valid = CryptoUtils::ValidateClientHello(
QUICHE team4dae8412019-03-18 13:11:00 -0700677 context->client_hello(), context->version(),
678 context->supported_versions(), &error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500679 if (valid != QUIC_NO_ERROR) {
QUICHE team4dae8412019-03-18 13:11:00 -0700680 context->Fail(valid, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500681 return;
682 }
683
684 QuicStringPiece requested_scid;
QUICHE team4dae8412019-03-18 13:11:00 -0700685 context->client_hello().GetStringPiece(kSCID, &requested_scid);
QUICHE team1225f472019-03-19 15:52:25 -0700686 Configs configs;
687 if (!GetCurrentConfigs(context->clock()->WallNow(), requested_scid,
688 signed_config->config, &configs)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700689 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "No configurations loaded");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500690 return;
691 }
692
QUICHE team4dae8412019-03-18 13:11:00 -0700693 if (context->validate_chlo_result()->error_code != QUIC_NO_ERROR) {
694 context->Fail(context->validate_chlo_result()->error_code,
695 context->validate_chlo_result()->error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500696 return;
697 }
698
QUICHE team4dae8412019-03-18 13:11:00 -0700699 if (!ClientDemandsX509Proof(context->client_hello())) {
700 context->Fail(QUIC_UNSUPPORTED_PROOF_DEMAND, "Missing or invalid PDMD");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500701 return;
702 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500703
704 // No need to get a new proof if one was already generated.
QUICHE team4dae8412019-03-18 13:11:00 -0700705 if (!context->signed_config()->chain) {
706 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
707 context->client_hello(), Perspective::IS_SERVER);
708 const QuicSocketAddress server_address = context->server_address();
709 const std::string sni = std::string(context->info().sni);
710 const QuicTransportVersion transport_version = context->transport_version();
711
QUICHE teamea5bdef2019-03-13 15:41:27 -0700712 auto cb = QuicMakeUnique<ProcessClientHelloCallback>(
QUICHE team1225f472019-03-19 15:52:25 -0700713 this, std::move(context), configs);
QUICHE team84910bd2019-03-15 07:03:40 -0700714
715 DCHECK(proof_source_.get());
QUICHE team1225f472019-03-19 15:52:25 -0700716 proof_source_->GetProof(server_address, sni, configs.primary->serialized,
QUICHE team4dae8412019-03-18 13:11:00 -0700717 transport_version, chlo_hash, std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500718 return;
719 }
720
QUICHE teama6ef0a62019-03-07 20:34:33 -0500721 ProcessClientHelloAfterGetProof(
722 /* found_error = */ false, /* proof_source_details = */ nullptr,
QUICHE team1225f472019-03-19 15:52:25 -0700723 std::move(context), configs);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500724}
725
726void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
727 bool found_error,
728 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE team4dae8412019-03-18 13:11:00 -0700729 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700730 const Configs& configs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500731 QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -0700732 context->connection_id(), context->transport_version()))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500733 << "ProcessClientHelloAfterGetProof: attempted to use connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -0700734 << context->connection_id() << " which is invalid with version "
735 << QuicVersionToString(context->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500736
737 if (found_error) {
QUICHE team4dae8412019-03-18 13:11:00 -0700738 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500739 return;
740 }
741
QUICHE teamea5bdef2019-03-13 15:41:27 -0700742 auto out_diversification_nonce = QuicMakeUnique<DiversificationNonce>();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500743
744 QuicStringPiece cert_sct;
QUICHE team4dae8412019-03-18 13:11:00 -0700745 if (context->client_hello().GetStringPiece(kCertificateSCTTag, &cert_sct) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500746 cert_sct.empty()) {
QUICHE team4dae8412019-03-18 13:11:00 -0700747 context->params()->sct_supported_by_client = true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500748 }
749
QUICHE teamea5bdef2019-03-13 15:41:27 -0700750 auto out = QuicMakeUnique<CryptoHandshakeMessage>();
QUICHE team1225f472019-03-19 15:52:25 -0700751 if (!context->info().reject_reasons.empty() || !configs.requested) {
QUICHE teamaa924f12019-03-21 11:26:21 -0700752 BuildRejectionAndRecordStats(*context, *configs.primary,
753 context->info().reject_reasons, out.get());
QUICHE team4dae8412019-03-18 13:11:00 -0700754 context->Succeed(std::move(out), std::move(out_diversification_nonce),
755 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500756 return;
757 }
758
QUICHE team4dae8412019-03-18 13:11:00 -0700759 if (context->reject_only()) {
760 context->Succeed(std::move(out), std::move(out_diversification_nonce),
761 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500762 return;
763 }
764
765 QuicTagVector their_aeads;
766 QuicTagVector their_key_exchanges;
QUICHE team4dae8412019-03-18 13:11:00 -0700767 if (context->client_hello().GetTaglist(kAEAD, &their_aeads) !=
768 QUIC_NO_ERROR ||
769 context->client_hello().GetTaglist(kKEXS, &their_key_exchanges) !=
770 QUIC_NO_ERROR ||
QUICHE teama6ef0a62019-03-07 20:34:33 -0500771 their_aeads.size() != 1 || their_key_exchanges.size() != 1) {
QUICHE team4dae8412019-03-18 13:11:00 -0700772 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
773 "Missing or invalid AEAD or KEXS");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500774 return;
775 }
776
777 size_t key_exchange_index;
QUICHE team1225f472019-03-19 15:52:25 -0700778 if (!FindMutualQuicTag(configs.requested->aead, their_aeads,
QUICHE team4dae8412019-03-18 13:11:00 -0700779 &context->params()->aead, nullptr) ||
QUICHE team1225f472019-03-19 15:52:25 -0700780 !FindMutualQuicTag(configs.requested->kexs, their_key_exchanges,
QUICHE team4dae8412019-03-18 13:11:00 -0700781 &context->params()->key_exchange,
782 &key_exchange_index)) {
783 context->Fail(QUIC_CRYPTO_NO_SUPPORT, "Unsupported AEAD or KEXS");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500784 return;
785 }
786
QUICHE teama6ef0a62019-03-07 20:34:33 -0500787 QuicStringPiece public_value;
QUICHE team4dae8412019-03-18 13:11:00 -0700788 if (!context->client_hello().GetStringPiece(kPUBS, &public_value)) {
789 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
790 "Missing public value");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500791 return;
792 }
793
QUICHE teamfe1aca62019-03-14 13:39:01 -0700794 const AsynchronousKeyExchange* key_exchange =
QUICHE team1225f472019-03-19 15:52:25 -0700795 configs.requested->key_exchanges[key_exchange_index].get();
QUICHE team4dae8412019-03-18 13:11:00 -0700796 std::string* initial_premaster_secret =
797 &context->params()->initial_premaster_secret;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500798 auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>(
QUICHE teamfe1aca62019-03-14 13:39:01 -0700799 this, std::move(proof_source_details), key_exchange->type(),
QUICHE team1225f472019-03-19 15:52:25 -0700800 std::move(out), public_value, std::move(context), configs);
QUICHE team4dae8412019-03-18 13:11:00 -0700801 key_exchange->CalculateSharedKeyAsync(public_value, initial_premaster_secret,
802 std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500803}
804
805void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys(
806 bool found_error,
807 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE teamfe1aca62019-03-14 13:39:01 -0700808 QuicTag key_exchange_type,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500809 std::unique_ptr<CryptoHandshakeMessage> out,
810 QuicStringPiece public_value,
QUICHE team4dae8412019-03-18 13:11:00 -0700811 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700812 const Configs& configs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500813 QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -0700814 context->connection_id(), context->transport_version()))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500815 << "ProcessClientHelloAfterCalculateSharedKeys:"
816 " attempted to use connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -0700817 << context->connection_id() << " which is invalid with version "
818 << QuicVersionToString(context->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500819
820 if (found_error) {
QUICHE team59882932019-03-27 11:02:17 -0700821 // If we are already using the fallback config, just bail out of the
822 // handshake.
823 if (context->signed_config()->config == configs.fallback ||
824 !GetQuicReloadableFlag(
825 send_quic_fallback_server_config_on_leto_error)) {
826 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
827 "Failed to calculate shared key");
828 } else {
829 SendRejectWithFallbackConfig(std::move(context), configs.fallback);
830 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500831 return;
832 }
833
QUICHE team4dae8412019-03-18 13:11:00 -0700834 if (!context->info().sni.empty()) {
835 context->params()->sni =
836 QuicHostnameUtils::NormalizeHostname(context->info().sni);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500837 }
838
vasilvvc48c8712019-03-11 13:38:16 -0700839 std::string hkdf_suffix;
QUICHE team4dae8412019-03-18 13:11:00 -0700840 const QuicData& client_hello_serialized =
841 context->client_hello().GetSerialized();
842 hkdf_suffix.reserve(context->connection_id().length() +
vasilvvc48c8712019-03-11 13:38:16 -0700843 client_hello_serialized.length() +
QUICHE team1225f472019-03-19 15:52:25 -0700844 configs.requested->serialized.size());
QUICHE team4dae8412019-03-18 13:11:00 -0700845 hkdf_suffix.append(context->connection_id().data(),
846 context->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500847 hkdf_suffix.append(client_hello_serialized.data(),
848 client_hello_serialized.length());
QUICHE team1225f472019-03-19 15:52:25 -0700849 hkdf_suffix.append(configs.requested->serialized);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500850 DCHECK(proof_source_.get());
QUICHE team4dae8412019-03-18 13:11:00 -0700851 if (context->signed_config()->chain->certs.empty()) {
852 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "Failed to get certs");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500853 return;
854 }
QUICHE team4dae8412019-03-18 13:11:00 -0700855 hkdf_suffix.append(context->signed_config()->chain->certs.at(0));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500856
857 QuicStringPiece cetv_ciphertext;
QUICHE team1225f472019-03-19 15:52:25 -0700858 if (configs.requested->channel_id_enabled &&
QUICHE team4dae8412019-03-18 13:11:00 -0700859 context->client_hello().GetStringPiece(kCETV, &cetv_ciphertext)) {
860 CryptoHandshakeMessage client_hello_copy(context->client_hello());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500861 client_hello_copy.Erase(kCETV);
862 client_hello_copy.Erase(kPAD);
863
864 const QuicData& client_hello_copy_serialized =
865 client_hello_copy.GetSerialized();
vasilvvc48c8712019-03-11 13:38:16 -0700866 std::string hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500867 hkdf_input.append(QuicCryptoConfig::kCETVLabel,
868 strlen(QuicCryptoConfig::kCETVLabel) + 1);
QUICHE team4dae8412019-03-18 13:11:00 -0700869 hkdf_input.append(context->connection_id().data(),
870 context->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500871 hkdf_input.append(client_hello_copy_serialized.data(),
872 client_hello_copy_serialized.length());
QUICHE team1225f472019-03-19 15:52:25 -0700873 hkdf_input.append(configs.requested->serialized);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500874
875 CrypterPair crypters;
876 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700877 context->params()->initial_premaster_secret,
878 context->params()->aead, context->info().client_nonce,
879 context->info().server_nonce, pre_shared_key_, hkdf_input,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500880 Perspective::IS_SERVER, CryptoUtils::Diversification::Never(),
881 &crypters, nullptr /* subkey secret */)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700882 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
883 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500884 return;
885 }
886
dschinazi66dea072019-04-09 11:41:06 -0700887 char plaintext[kMaxOutgoingPacketSize];
QUICHE teama6ef0a62019-03-07 20:34:33 -0500888 size_t plaintext_length = 0;
889 const bool success = crypters.decrypter->DecryptPacket(
890 0 /* packet number */, QuicStringPiece() /* associated data */,
dschinazi66dea072019-04-09 11:41:06 -0700891 cetv_ciphertext, plaintext, &plaintext_length, kMaxOutgoingPacketSize);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500892 if (!success) {
QUICHE team4dae8412019-03-18 13:11:00 -0700893 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
894 "CETV decryption failure");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500895 return;
896 }
897 std::unique_ptr<CryptoHandshakeMessage> cetv(CryptoFramer::ParseMessage(
898 QuicStringPiece(plaintext, plaintext_length)));
899 if (!cetv.get()) {
QUICHE team4dae8412019-03-18 13:11:00 -0700900 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV parse error");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500901 return;
902 }
903
904 QuicStringPiece key, signature;
905 if (cetv->GetStringPiece(kCIDK, &key) &&
906 cetv->GetStringPiece(kCIDS, &signature)) {
907 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700908 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
909 "ChannelID signature failure");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500910 return;
911 }
912
QUICHE team4dae8412019-03-18 13:11:00 -0700913 context->params()->channel_id = std::string(key);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500914 }
915 }
916
vasilvvc48c8712019-03-11 13:38:16 -0700917 std::string hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500918 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
919 hkdf_input.reserve(label_len + hkdf_suffix.size());
920 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
921 hkdf_input.append(hkdf_suffix);
922
QUICHE team45c889c2019-03-14 16:37:01 -0700923 auto out_diversification_nonce = QuicMakeUnique<DiversificationNonce>();
QUICHE team4dae8412019-03-18 13:11:00 -0700924 context->rand()->RandBytes(out_diversification_nonce->data(),
925 out_diversification_nonce->size());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500926 CryptoUtils::Diversification diversification =
927 CryptoUtils::Diversification::Now(out_diversification_nonce.get());
928 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700929 context->params()->initial_premaster_secret, context->params()->aead,
930 context->info().client_nonce, context->info().server_nonce,
931 pre_shared_key_, hkdf_input, Perspective::IS_SERVER, diversification,
932 &context->params()->initial_crypters,
933 &context->params()->initial_subkey_secret)) {
934 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
935 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500936 return;
937 }
938
vasilvvc48c8712019-03-11 13:38:16 -0700939 std::string forward_secure_public_value;
QUICHE teamfe1aca62019-03-14 13:39:01 -0700940 std::unique_ptr<SynchronousKeyExchange> forward_secure_key_exchange =
QUICHE team4dae8412019-03-18 13:11:00 -0700941 CreateLocalSynchronousKeyExchange(key_exchange_type, context->rand());
QUICHE teamfe1aca62019-03-14 13:39:01 -0700942 if (!forward_secure_key_exchange) {
943 QUIC_DLOG(WARNING) << "Failed to create keypair";
QUICHE team4dae8412019-03-18 13:11:00 -0700944 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
945 "Failed to create keypair");
QUICHE teamfe1aca62019-03-14 13:39:01 -0700946 return;
947 }
948
QUICHE teama6ef0a62019-03-07 20:34:33 -0500949 forward_secure_public_value =
vasilvvc48c8712019-03-11 13:38:16 -0700950 std::string(forward_secure_key_exchange->public_value());
QUICHE teamfe1aca62019-03-14 13:39:01 -0700951 if (!forward_secure_key_exchange->CalculateSharedKeySync(
QUICHE team4dae8412019-03-18 13:11:00 -0700952 public_value, &context->params()->forward_secure_premaster_secret)) {
953 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
954 "Invalid public value");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500955 return;
956 }
957
vasilvvc48c8712019-03-11 13:38:16 -0700958 std::string forward_secure_hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500959 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
960 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
961 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
962 label_len);
963 forward_secure_hkdf_input.append(hkdf_suffix);
964
vasilvvc48c8712019-03-11 13:38:16 -0700965 std::string shlo_nonce;
QUICHE team4dae8412019-03-18 13:11:00 -0700966 shlo_nonce = NewServerNonce(context->rand(), context->info().now);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500967 out->SetStringPiece(kServerNonceTag, shlo_nonce);
968
969 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700970 context->params()->forward_secure_premaster_secret,
971 context->params()->aead, context->info().client_nonce,
972 shlo_nonce.empty() ? context->info().server_nonce : shlo_nonce,
973 pre_shared_key_, forward_secure_hkdf_input, Perspective::IS_SERVER,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500974 CryptoUtils::Diversification::Never(),
QUICHE team4dae8412019-03-18 13:11:00 -0700975 &context->params()->forward_secure_crypters,
976 &context->params()->subkey_secret)) {
977 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
978 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500979 return;
980 }
981
982 out->set_tag(kSHLO);
QUICHE team4dae8412019-03-18 13:11:00 -0700983 out->SetVersionVector(kVER, context->supported_versions());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500984 out->SetStringPiece(
985 kSourceAddressTokenTag,
QUICHE team1225f472019-03-19 15:52:25 -0700986 NewSourceAddressToken(*configs.requested,
QUICHE team4dae8412019-03-18 13:11:00 -0700987 context->info().source_address_tokens,
988 context->client_address().host(), context->rand(),
989 context->info().now, nullptr));
990 QuicSocketAddressCoder address_coder(context->client_address());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500991 out->SetStringPiece(kCADR, address_coder.Encode());
992 out->SetStringPiece(kPUBS, forward_secure_public_value);
993
QUICHE team4dae8412019-03-18 13:11:00 -0700994 context->Succeed(std::move(out), std::move(out_diversification_nonce),
995 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500996}
997
QUICHE team59882932019-03-27 11:02:17 -0700998void QuicCryptoServerConfig::SendRejectWithFallbackConfig(
999 std::unique_ptr<ProcessClientHelloContext> context,
1000 QuicReferenceCountedPointer<Config> fallback_config) const {
1001 // We failed to calculate a shared initial key, likely because we tried to use
1002 // a remote key-exchange service which could not be reached. We want to send
1003 // a REJ which tells the client to use a different ServerConfig which
1004 // corresponds to a local keypair. To generate the REJ we need to request a
1005 // new proof.
1006 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
1007 context->client_hello(), Perspective::IS_SERVER);
1008 const QuicSocketAddress server_address = context->server_address();
1009 const std::string sni(context->info().sni);
1010 const QuicTransportVersion transport_version = context->transport_version();
1011
1012 auto cb = QuicMakeUnique<SendRejectWithFallbackConfigCallback>(
1013 this, std::move(context), fallback_config);
1014 proof_source_->GetProof(server_address, sni, fallback_config->serialized,
1015 transport_version, chlo_hash, std::move(cb));
1016}
1017
1018void QuicCryptoServerConfig::SendRejectWithFallbackConfigAfterGetProof(
1019 bool found_error,
1020 std::unique_ptr<ProofSource::Details> proof_source_details,
1021 std::unique_ptr<ProcessClientHelloContext> context,
1022 QuicReferenceCountedPointer<Config> fallback_config) const {
1023 if (found_error) {
1024 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
1025 return;
1026 }
1027
1028 auto out = QuicMakeUnique<CryptoHandshakeMessage>();
1029 BuildRejectionAndRecordStats(*context, *fallback_config,
1030 {SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE},
1031 out.get());
1032
1033 context->Succeed(std::move(out), QuicMakeUnique<DiversificationNonce>(),
1034 std::move(proof_source_details));
1035}
1036
QUICHE teama6ef0a62019-03-07 20:34:33 -05001037QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
1038QuicCryptoServerConfig::GetConfigWithScid(
1039 QuicStringPiece requested_scid) const {
1040 configs_lock_.AssertReaderHeld();
1041
1042 if (!requested_scid.empty()) {
vasilvvc48c8712019-03-11 13:38:16 -07001043 auto it = configs_.find((std::string(requested_scid)));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001044 if (it != configs_.end()) {
1045 // We'll use the config that the client requested in order to do
1046 // key-agreement.
1047 return QuicReferenceCountedPointer<Config>(it->second);
1048 }
1049 }
1050
1051 return QuicReferenceCountedPointer<Config>();
1052}
1053
QUICHE team1225f472019-03-19 15:52:25 -07001054bool QuicCryptoServerConfig::GetCurrentConfigs(
1055 const QuicWallTime& now,
1056 QuicStringPiece requested_scid,
1057 QuicReferenceCountedPointer<Config> old_primary_config,
1058 Configs* configs) const {
1059 QuicReaderMutexLock locked(&configs_lock_);
1060
1061 if (!primary_config_) {
1062 return false;
1063 }
1064
1065 if (IsNextConfigReady(now)) {
1066 configs_lock_.ReaderUnlock();
1067 configs_lock_.WriterLock();
1068 SelectNewPrimaryConfig(now);
1069 DCHECK(primary_config_.get());
1070 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
1071 primary_config_.get());
1072 configs_lock_.WriterUnlock();
1073 configs_lock_.ReaderLock();
1074 }
1075
1076 if (old_primary_config != nullptr) {
1077 configs->primary = old_primary_config;
1078 } else {
1079 configs->primary = primary_config_;
1080 }
1081 configs->requested = GetConfigWithScid(requested_scid);
QUICHE team99055cf2019-03-22 11:27:53 -07001082 configs->fallback = fallback_config_;
QUICHE team1225f472019-03-19 15:52:25 -07001083
1084 return true;
1085}
1086
QUICHE teama6ef0a62019-03-07 20:34:33 -05001087// ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
1088// Config's based on their primary_time.
1089// static
1090bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
1091 const QuicReferenceCountedPointer<Config>& a,
1092 const QuicReferenceCountedPointer<Config>& b) {
1093 if (a->primary_time.IsBefore(b->primary_time) ||
1094 b->primary_time.IsBefore(a->primary_time)) {
1095 // Primary times differ.
1096 return a->primary_time.IsBefore(b->primary_time);
1097 } else if (a->priority != b->priority) {
1098 // Primary times are equal, sort backwards by priority.
1099 return a->priority < b->priority;
1100 } else {
1101 // Primary times and priorities are equal, sort by config id.
1102 return a->id < b->id;
1103 }
1104}
1105
1106void QuicCryptoServerConfig::SelectNewPrimaryConfig(
1107 const QuicWallTime now) const {
1108 std::vector<QuicReferenceCountedPointer<Config>> configs;
1109 configs.reserve(configs_.size());
1110
1111 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
1112 // TODO(avd) Exclude expired configs?
1113 configs.push_back(it->second);
1114 }
1115
1116 if (configs.empty()) {
1117 if (primary_config_ != nullptr) {
1118 QUIC_BUG << "No valid QUIC server config. Keeping the current config.";
1119 } else {
1120 QUIC_BUG << "No valid QUIC server config.";
1121 }
1122 return;
1123 }
1124
1125 std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan);
1126
1127 QuicReferenceCountedPointer<Config> best_candidate = configs[0];
1128
1129 for (size_t i = 0; i < configs.size(); ++i) {
1130 const QuicReferenceCountedPointer<Config> config(configs[i]);
1131 if (!config->primary_time.IsAfter(now)) {
1132 if (config->primary_time.IsAfter(best_candidate->primary_time)) {
1133 best_candidate = config;
1134 }
1135 continue;
1136 }
1137
1138 // This is the first config with a primary_time in the future. Thus the
1139 // previous Config should be the primary and this one should determine the
1140 // next_config_promotion_time_.
1141 QuicReferenceCountedPointer<Config> new_primary = best_candidate;
1142 if (i == 0) {
1143 // We need the primary_time of the next config.
1144 if (configs.size() > 1) {
1145 next_config_promotion_time_ = configs[1]->primary_time;
1146 } else {
1147 next_config_promotion_time_ = QuicWallTime::Zero();
1148 }
1149 } else {
1150 next_config_promotion_time_ = config->primary_time;
1151 }
1152
1153 if (primary_config_) {
1154 primary_config_->is_primary = false;
1155 }
1156 primary_config_ = new_primary;
1157 new_primary->is_primary = true;
1158 QUIC_DLOG(INFO) << "New primary config. orbit: "
1159 << QuicTextUtils::HexEncode(reinterpret_cast<const char*>(
1160 primary_config_->orbit),
1161 kOrbitSize);
1162 if (primary_config_changed_cb_ != nullptr) {
1163 primary_config_changed_cb_->Run(primary_config_->id);
1164 }
1165
1166 return;
1167 }
1168
1169 // All config's primary times are in the past. We should make the most recent
1170 // and highest priority candidate primary.
1171 QuicReferenceCountedPointer<Config> new_primary = best_candidate;
1172 if (primary_config_) {
1173 primary_config_->is_primary = false;
1174 }
1175 primary_config_ = new_primary;
1176 new_primary->is_primary = true;
1177 QUIC_DLOG(INFO) << "New primary config. orbit: "
1178 << QuicTextUtils::HexEncode(
1179 reinterpret_cast<const char*>(primary_config_->orbit),
1180 kOrbitSize)
1181 << " scid: " << QuicTextUtils::HexEncode(primary_config_->id);
1182 next_config_promotion_time_ = QuicWallTime::Zero();
1183 if (primary_config_changed_cb_ != nullptr) {
1184 primary_config_changed_cb_->Run(primary_config_->id);
1185 }
1186}
1187
QUICHE teama6ef0a62019-03-07 20:34:33 -05001188void QuicCryptoServerConfig::EvaluateClientHello(
1189 const QuicSocketAddress& server_address,
dschinazi17d42422019-06-18 16:35:07 -07001190 QuicTransportVersion /*version*/,
QUICHE team1225f472019-03-19 15:52:25 -07001191 const Configs& configs,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001192 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
1193 client_hello_state,
1194 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001195 ValidateClientHelloHelper helper(client_hello_state, &done_cb);
1196
1197 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
1198 ClientHelloInfo* info = &(client_hello_state->info);
1199
1200 if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) {
1201 helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
1202 "Client hello too small", nullptr);
1203 return;
1204 }
1205
1206 if (client_hello.GetStringPiece(kSNI, &info->sni) &&
1207 !QuicHostnameUtils::IsValidSNI(info->sni)) {
1208 helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
1209 "Invalid SNI name", nullptr);
1210 return;
1211 }
1212
1213 client_hello.GetStringPiece(kUAID, &info->user_agent_id);
1214
1215 HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
1216 if (validate_source_address_token_) {
1217 QuicStringPiece srct;
1218 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
1219 Config& config =
QUICHE team1225f472019-03-19 15:52:25 -07001220 configs.requested != nullptr ? *configs.requested : *configs.primary;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001221 source_address_token_error =
1222 ParseSourceAddressToken(config, srct, &info->source_address_tokens);
1223
1224 if (source_address_token_error == HANDSHAKE_OK) {
1225 source_address_token_error = ValidateSourceAddressTokens(
1226 info->source_address_tokens, info->client_ip, info->now,
1227 &client_hello_state->cached_network_params);
1228 }
1229 info->valid_source_address_token =
1230 (source_address_token_error == HANDSHAKE_OK);
1231 } else {
1232 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
1233 }
1234 } else {
1235 source_address_token_error = HANDSHAKE_OK;
1236 info->valid_source_address_token = true;
1237 }
1238
QUICHE team1225f472019-03-19 15:52:25 -07001239 if (!configs.requested) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001240 QuicStringPiece requested_scid;
1241 if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
1242 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1243 } else {
1244 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1245 }
1246 // No server config with the requested ID.
1247 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1248 return;
1249 }
1250
1251 if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) {
1252 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1253 // Report no client nonce as INCHOATE_HELLO_FAILURE.
1254 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1255 return;
1256 }
1257
1258 if (source_address_token_error != HANDSHAKE_OK) {
1259 info->reject_reasons.push_back(source_address_token_error);
1260 // No valid source address token.
1261 }
1262
1263 QuicReferenceCountedPointer<ProofSource::Chain> chain =
vasilvvc48c8712019-03-11 13:38:16 -07001264 proof_source_->GetCertChain(server_address, std::string(info->sni));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001265 if (!chain) {
1266 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1267 } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) {
1268 info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
1269 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001270
1271 if (info->client_nonce.size() != kNonceSize) {
1272 info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
1273 // Invalid client nonce.
1274 QUIC_LOG_FIRST_N(ERROR, 2)
1275 << "Invalid client nonce: " << client_hello.DebugString();
1276 QUIC_DLOG(INFO) << "Invalid client nonce.";
1277 }
1278
1279 // Server nonce is optional, and used for key derivation if present.
1280 client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
1281
1282 QUIC_DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher.";
1283 // If the server nonce is empty and we're requiring handshake confirmation
1284 // for DoS reasons then we must reject the CHLO.
1285 if (GetQuicReloadableFlag(quic_require_handshake_confirmation) &&
1286 info->server_nonce.empty()) {
1287 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
1288 }
QUICHE team79fb9e22019-03-15 07:49:56 -07001289 helper.ValidationComplete(QUIC_NO_ERROR, "",
1290 std::unique_ptr<ProofSource::Details>());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001291}
1292
1293void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
1294 QuicTransportVersion version,
1295 QuicStringPiece chlo_hash,
1296 const SourceAddressTokens& previous_source_address_tokens,
1297 const QuicSocketAddress& server_address,
1298 const QuicIpAddress& client_ip,
1299 const QuicClock* clock,
1300 QuicRandom* rand,
1301 QuicCompressedCertsCache* compressed_certs_cache,
1302 const QuicCryptoNegotiatedParameters& params,
1303 const CachedNetworkParameters* cached_network_params,
1304 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
vasilvvc48c8712019-03-11 13:38:16 -07001305 std::string serialized;
1306 std::string source_address_token;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001307 const CommonCertSets* common_cert_sets;
1308 {
1309 QuicReaderMutexLock locked(&configs_lock_);
1310 serialized = primary_config_->serialized;
1311 common_cert_sets = primary_config_->common_cert_sets;
1312 source_address_token = NewSourceAddressToken(
1313 *primary_config_, previous_source_address_tokens, client_ip, rand,
1314 clock->WallNow(), cached_network_params);
1315 }
1316
1317 CryptoHandshakeMessage message;
1318 message.set_tag(kSCUP);
1319 message.SetStringPiece(kSCFG, serialized);
1320 message.SetStringPiece(kSourceAddressTokenTag, source_address_token);
1321
QUICHE teamea5bdef2019-03-13 15:41:27 -07001322 auto proof_source_cb =
1323 QuicMakeUnique<BuildServerConfigUpdateMessageProofSourceCallback>(
QUICHE team39a71e52019-03-15 14:24:34 -07001324 this, compressed_certs_cache, common_cert_sets, params,
QUICHE teamea5bdef2019-03-13 15:41:27 -07001325 std::move(message), std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001326
1327 proof_source_->GetProof(server_address, params.sni, serialized, version,
1328 chlo_hash, std::move(proof_source_cb));
1329}
1330
1331QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1332 ~BuildServerConfigUpdateMessageProofSourceCallback() {}
1333
1334QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1335 BuildServerConfigUpdateMessageProofSourceCallback(
1336 const QuicCryptoServerConfig* config,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001337 QuicCompressedCertsCache* compressed_certs_cache,
1338 const CommonCertSets* common_cert_sets,
1339 const QuicCryptoNegotiatedParameters& params,
1340 CryptoHandshakeMessage message,
1341 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb)
1342 : config_(config),
QUICHE teama6ef0a62019-03-07 20:34:33 -05001343 compressed_certs_cache_(compressed_certs_cache),
1344 common_cert_sets_(common_cert_sets),
1345 client_common_set_hashes_(params.client_common_set_hashes),
1346 client_cached_cert_hashes_(params.client_cached_cert_hashes),
1347 sct_supported_by_client_(params.sct_supported_by_client),
1348 sni_(params.sni),
1349 message_(std::move(message)),
1350 cb_(std::move(cb)) {}
1351
1352void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1353 Run(bool ok,
1354 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
1355 const QuicCryptoProof& proof,
1356 std::unique_ptr<ProofSource::Details> details) {
1357 config_->FinishBuildServerConfigUpdateMessage(
QUICHE team39a71e52019-03-15 14:24:34 -07001358 compressed_certs_cache_, common_cert_sets_, client_common_set_hashes_,
1359 client_cached_cert_hashes_, sct_supported_by_client_, sni_, ok, chain,
1360 proof.signature, proof.leaf_cert_scts, std::move(details),
1361 std::move(message_), std::move(cb_));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001362}
1363
1364void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001365 QuicCompressedCertsCache* compressed_certs_cache,
1366 const CommonCertSets* common_cert_sets,
vasilvvc48c8712019-03-11 13:38:16 -07001367 const std::string& client_common_set_hashes,
1368 const std::string& client_cached_cert_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001369 bool sct_supported_by_client,
vasilvvc48c8712019-03-11 13:38:16 -07001370 const std::string& sni,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001371 bool ok,
1372 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
vasilvvc48c8712019-03-11 13:38:16 -07001373 const std::string& signature,
1374 const std::string& leaf_cert_sct,
dschinazi17d42422019-06-18 16:35:07 -07001375 std::unique_ptr<ProofSource::Details> /*details*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001376 CryptoHandshakeMessage message,
1377 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
1378 if (!ok) {
1379 cb->Run(false, message);
1380 return;
1381 }
1382
vasilvvc48c8712019-03-11 13:38:16 -07001383 const std::string compressed =
QUICHE teama6ef0a62019-03-07 20:34:33 -05001384 CompressChain(compressed_certs_cache, chain, client_common_set_hashes,
1385 client_cached_cert_hashes, common_cert_sets);
1386
1387 message.SetStringPiece(kCertificateTag, compressed);
1388 message.SetStringPiece(kPROF, signature);
1389 if (sct_supported_by_client && enable_serving_sct_) {
1390 if (leaf_cert_sct.empty()) {
1391 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
1392 << "SCT is expected but it is empty. SNI: " << sni;
1393 } else {
1394 message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct);
1395 }
1396 }
1397
1398 cb->Run(true, message);
1399}
1400
QUICHE teamaa924f12019-03-21 11:26:21 -07001401void QuicCryptoServerConfig::BuildRejectionAndRecordStats(
1402 const ProcessClientHelloContext& context,
1403 const Config& config,
1404 const std::vector<uint32_t>& reject_reasons,
1405 CryptoHandshakeMessage* out) const {
1406 BuildRejection(context, config, reject_reasons, out);
1407 if (rejection_observer_ != nullptr) {
1408 rejection_observer_->OnRejectionBuilt(reject_reasons, out);
1409 }
1410}
1411
QUICHE teama6ef0a62019-03-07 20:34:33 -05001412void QuicCryptoServerConfig::BuildRejection(
QUICHE team4dae8412019-03-18 13:11:00 -07001413 const ProcessClientHelloContext& context,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001414 const Config& config,
QUICHE teame6dcf322019-03-19 12:23:47 -07001415 const std::vector<uint32_t>& reject_reasons,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001416 CryptoHandshakeMessage* out) const {
QUICHE team4dae8412019-03-18 13:11:00 -07001417 const QuicWallTime now = context.clock()->WallNow();
wub0a4b9c52019-05-28 13:18:58 -07001418
1419 out->set_tag(kREJ);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001420 out->SetStringPiece(kSCFG, config.serialized);
1421 out->SetStringPiece(
1422 kSourceAddressTokenTag,
QUICHE team4dae8412019-03-18 13:11:00 -07001423 NewSourceAddressToken(
1424 config, context.info().source_address_tokens,
1425 context.info().client_ip, context.rand(), context.info().now,
1426 &context.validate_chlo_result()->cached_network_params));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001427 out->SetValue(kSTTL, config.expiry_time.AbsoluteDifference(now).ToSeconds());
1428 if (replay_protection_) {
QUICHE team4dae8412019-03-18 13:11:00 -07001429 out->SetStringPiece(kServerNonceTag,
1430 NewServerNonce(context.rand(), context.info().now));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001431 }
1432
1433 // Send client the reject reason for debugging purposes.
QUICHE teame6dcf322019-03-19 12:23:47 -07001434 DCHECK_LT(0u, reject_reasons.size());
1435 out->SetVector(kRREJ, reject_reasons);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001436
1437 // The client may have requested a certificate chain.
QUICHE team4dae8412019-03-18 13:11:00 -07001438 if (!ClientDemandsX509Proof(context.client_hello())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001439 QUIC_BUG << "x509 certificates not supported in proof demand";
1440 return;
1441 }
1442
1443 QuicStringPiece client_common_set_hashes;
QUICHE team4dae8412019-03-18 13:11:00 -07001444 if (context.client_hello().GetStringPiece(kCCS, &client_common_set_hashes)) {
1445 context.params()->client_common_set_hashes =
1446 std::string(client_common_set_hashes);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001447 }
1448
1449 QuicStringPiece client_cached_cert_hashes;
QUICHE team4dae8412019-03-18 13:11:00 -07001450 if (context.client_hello().GetStringPiece(kCCRT,
1451 &client_cached_cert_hashes)) {
1452 context.params()->client_cached_cert_hashes =
1453 std::string(client_cached_cert_hashes);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001454 } else {
QUICHE team4dae8412019-03-18 13:11:00 -07001455 context.params()->client_cached_cert_hashes.clear();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001456 }
1457
QUICHE team4dae8412019-03-18 13:11:00 -07001458 const std::string compressed = CompressChain(
1459 context.compressed_certs_cache(), context.signed_config()->chain,
1460 context.params()->client_common_set_hashes,
1461 context.params()->client_cached_cert_hashes, config.common_cert_sets);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001462
QUICHE team4dae8412019-03-18 13:11:00 -07001463 DCHECK_GT(context.chlo_packet_size(), context.client_hello().size());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001464 // kREJOverheadBytes is a very rough estimate of how much of a REJ
1465 // message is taken up by things other than the certificates.
1466 // STK: 56 bytes
1467 // SNO: 56 bytes
1468 // SCFG
1469 // SCID: 16 bytes
1470 // PUBS: 38 bytes
1471 const size_t kREJOverheadBytes = 166;
1472 // max_unverified_size is the number of bytes that the certificate chain,
1473 // signature, and (optionally) signed certificate timestamp can consume before
1474 // we will demand a valid source-address token.
1475 const size_t max_unverified_size =
QUICHE team4dae8412019-03-18 13:11:00 -07001476 chlo_multiplier_ *
1477 (context.chlo_packet_size() - context.total_framing_overhead()) -
QUICHE teama6ef0a62019-03-07 20:34:33 -05001478 kREJOverheadBytes;
1479 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
1480 "overhead calculation may underflow");
1481 bool should_return_sct =
QUICHE team4dae8412019-03-18 13:11:00 -07001482 context.params()->sct_supported_by_client && enable_serving_sct_;
1483 const std::string& cert_sct = context.signed_config()->proof.leaf_cert_scts;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001484 const size_t sct_size = should_return_sct ? cert_sct.size() : 0;
QUICHE team4dae8412019-03-18 13:11:00 -07001485 const size_t total_size = context.signed_config()->proof.signature.size() +
1486 compressed.size() + sct_size;
1487 if (context.info().valid_source_address_token ||
1488 total_size < max_unverified_size) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001489 out->SetStringPiece(kCertificateTag, compressed);
QUICHE team4dae8412019-03-18 13:11:00 -07001490 out->SetStringPiece(kPROF, context.signed_config()->proof.signature);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001491 if (should_return_sct) {
1492 if (cert_sct.empty()) {
1493 if (!GetQuicReloadableFlag(quic_log_cert_name_for_empty_sct)) {
1494 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001495 << "SCT is expected but it is empty. sni :"
1496 << context.params()->sni;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001497 } else {
1498 // Log SNI and subject name for the leaf cert if its SCT is empty.
1499 // This is for debugging b/28342827.
QUICHE team4dae8412019-03-18 13:11:00 -07001500 const std::vector<std::string>& certs =
1501 context.signed_config()->chain->certs;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001502 QuicStringPiece ca_subject;
1503 if (!certs.empty()) {
1504 QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject);
1505 }
1506 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001507 << "SCT is expected but it is empty. sni: '"
1508 << context.params()->sni << "' cert subject: '" << ca_subject
1509 << "'";
QUICHE teama6ef0a62019-03-07 20:34:33 -05001510 }
1511 } else {
1512 out->SetStringPiece(kCertificateSCTTag, cert_sct);
1513 }
1514 }
1515 } else {
1516 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001517 << "Sending inchoate REJ for hostname: " << context.info().sni
1518 << " signature: " << context.signed_config()->proof.signature.size()
QUICHE teama6ef0a62019-03-07 20:34:33 -05001519 << " cert: " << compressed.size() << " sct:" << sct_size
1520 << " total: " << total_size << " max: " << max_unverified_size;
1521 }
1522}
1523
vasilvvc48c8712019-03-11 13:38:16 -07001524std::string QuicCryptoServerConfig::CompressChain(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001525 QuicCompressedCertsCache* compressed_certs_cache,
1526 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
vasilvvc48c8712019-03-11 13:38:16 -07001527 const std::string& client_common_set_hashes,
1528 const std::string& client_cached_cert_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001529 const CommonCertSets* common_sets) {
1530 // Check whether the compressed certs is available in the cache.
1531 DCHECK(compressed_certs_cache);
vasilvvc48c8712019-03-11 13:38:16 -07001532 const std::string* cached_value = compressed_certs_cache->GetCompressedCert(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001533 chain, client_common_set_hashes, client_cached_cert_hashes);
1534 if (cached_value) {
1535 return *cached_value;
1536 }
vasilvvc48c8712019-03-11 13:38:16 -07001537 std::string compressed =
QUICHE teama6ef0a62019-03-07 20:34:33 -05001538 CertCompressor::CompressChain(chain->certs, client_common_set_hashes,
1539 client_cached_cert_hashes, common_sets);
1540 // Insert the newly compressed cert to cache.
1541 compressed_certs_cache->Insert(chain, client_common_set_hashes,
1542 client_cached_cert_hashes, compressed);
1543 return compressed;
1544}
1545
1546QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
1547QuicCryptoServerConfig::ParseConfigProtobuf(
QUICHE team99055cf2019-03-22 11:27:53 -07001548 const QuicServerConfigProtobuf& protobuf,
1549 bool is_fallback) const {
QUICHE teamfe1aca62019-03-14 13:39:01 -07001550 std::unique_ptr<CryptoHandshakeMessage> msg =
QUICHE teambbaa8be2019-03-21 12:54:17 -07001551 CryptoFramer::ParseMessage(protobuf.config());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001552
1553 if (msg->tag() != kSCFG) {
1554 QUIC_LOG(WARNING) << "Server config message has tag " << msg->tag()
1555 << " expected " << kSCFG;
1556 return nullptr;
1557 }
1558
1559 QuicReferenceCountedPointer<Config> config(new Config);
QUICHE teambbaa8be2019-03-21 12:54:17 -07001560 config->serialized = protobuf.config();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001561 config->source_address_token_boxer = &source_address_token_boxer_;
1562
QUICHE teambbaa8be2019-03-21 12:54:17 -07001563 if (protobuf.has_primary_time()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001564 config->primary_time =
QUICHE teambbaa8be2019-03-21 12:54:17 -07001565 QuicWallTime::FromUNIXSeconds(protobuf.primary_time());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001566 }
1567
QUICHE teambbaa8be2019-03-21 12:54:17 -07001568 config->priority = protobuf.priority();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001569
1570 QuicStringPiece scid;
1571 if (!msg->GetStringPiece(kSCID, &scid)) {
1572 QUIC_LOG(WARNING) << "Server config message is missing SCID";
1573 return nullptr;
1574 }
vasilvvc48c8712019-03-11 13:38:16 -07001575 config->id = std::string(scid);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001576
1577 if (msg->GetTaglist(kAEAD, &config->aead) != QUIC_NO_ERROR) {
1578 QUIC_LOG(WARNING) << "Server config message is missing AEAD";
1579 return nullptr;
1580 }
1581
1582 QuicTagVector kexs_tags;
1583 if (msg->GetTaglist(kKEXS, &kexs_tags) != QUIC_NO_ERROR) {
1584 QUIC_LOG(WARNING) << "Server config message is missing KEXS";
1585 return nullptr;
1586 }
1587
QUICHE teama6ef0a62019-03-07 20:34:33 -05001588 QuicStringPiece orbit;
1589 if (!msg->GetStringPiece(kORBT, &orbit)) {
1590 QUIC_LOG(WARNING) << "Server config message is missing ORBT";
1591 return nullptr;
1592 }
1593
1594 if (orbit.size() != kOrbitSize) {
1595 QUIC_LOG(WARNING) << "Orbit value in server config is the wrong length."
1596 " Got "
1597 << orbit.size() << " want " << kOrbitSize;
1598 return nullptr;
1599 }
1600 static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size");
1601 memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
1602
QUICHE team59882932019-03-27 11:02:17 -07001603 if ((kexs_tags.size() != static_cast<size_t>(protobuf.key_size())) &&
1604 (!GetQuicRestartFlag(dont_fetch_quic_private_keys_from_leto) &&
1605 protobuf.key_size() == 0)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001606 QUIC_LOG(WARNING) << "Server config has " << kexs_tags.size()
1607 << " key exchange methods configured, but "
QUICHE teambbaa8be2019-03-21 12:54:17 -07001608 << protobuf.key_size() << " private keys";
QUICHE teama6ef0a62019-03-07 20:34:33 -05001609 return nullptr;
1610 }
1611
1612 QuicTagVector proof_demand_tags;
1613 if (msg->GetTaglist(kPDMD, &proof_demand_tags) == QUIC_NO_ERROR) {
1614 for (QuicTag tag : proof_demand_tags) {
1615 if (tag == kCHID) {
1616 config->channel_id_enabled = true;
1617 break;
1618 }
1619 }
1620 }
1621
1622 for (size_t i = 0; i < kexs_tags.size(); i++) {
1623 const QuicTag tag = kexs_tags[i];
vasilvvc48c8712019-03-11 13:38:16 -07001624 std::string private_key;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001625
1626 config->kexs.push_back(tag);
1627
QUICHE teambbaa8be2019-03-21 12:54:17 -07001628 for (int j = 0; j < protobuf.key_size(); j++) {
1629 const QuicServerConfigProtobuf::PrivateKey& key = protobuf.key(i);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001630 if (key.tag() == tag) {
1631 private_key = key.private_key();
1632 break;
1633 }
1634 }
1635
QUICHE team99055cf2019-03-22 11:27:53 -07001636 std::unique_ptr<AsynchronousKeyExchange> ka =
1637 key_exchange_source_->Create(config->id, is_fallback, tag, private_key);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001638 if (!ka) {
1639 return nullptr;
1640 }
1641 for (const auto& key_exchange : config->key_exchanges) {
QUICHE teamfe1aca62019-03-14 13:39:01 -07001642 if (key_exchange->type() == tag) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001643 QUIC_LOG(WARNING) << "Duplicate key exchange in config: " << tag;
1644 return nullptr;
1645 }
1646 }
1647
1648 config->key_exchanges.push_back(std::move(ka));
1649 }
1650
1651 uint64_t expiry_seconds;
1652 if (msg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
1653 QUIC_LOG(WARNING) << "Server config message is missing EXPY";
1654 return nullptr;
1655 }
1656 config->expiry_time = QuicWallTime::FromUNIXSeconds(expiry_seconds);
1657
1658 return config;
1659}
1660
1661void QuicCryptoServerConfig::set_replay_protection(bool on) {
1662 replay_protection_ = on;
1663}
1664
1665void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) {
1666 chlo_multiplier_ = multiplier;
1667}
1668
1669void QuicCryptoServerConfig::set_source_address_token_future_secs(
1670 uint32_t future_secs) {
1671 source_address_token_future_secs_ = future_secs;
1672}
1673
1674void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
1675 uint32_t lifetime_secs) {
1676 source_address_token_lifetime_secs_ = lifetime_secs;
1677}
1678
1679void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) {
1680 enable_serving_sct_ = enable_serving_sct;
1681}
1682
1683void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
1684 std::unique_ptr<PrimaryConfigChangedCallback> cb) {
1685 QuicWriterMutexLock locked(&configs_lock_);
1686 primary_config_changed_cb_ = std::move(cb);
1687}
1688
vasilvvc48c8712019-03-11 13:38:16 -07001689std::string QuicCryptoServerConfig::NewSourceAddressToken(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001690 const Config& config,
1691 const SourceAddressTokens& previous_tokens,
1692 const QuicIpAddress& ip,
1693 QuicRandom* rand,
1694 QuicWallTime now,
1695 const CachedNetworkParameters* cached_network_params) const {
1696 SourceAddressTokens source_address_tokens;
1697 SourceAddressToken* source_address_token = source_address_tokens.add_tokens();
1698 source_address_token->set_ip(ip.DualStacked().ToPackedString());
1699 source_address_token->set_timestamp(now.ToUNIXSeconds());
1700 if (cached_network_params != nullptr) {
1701 *(source_address_token->mutable_cached_network_parameters()) =
1702 *cached_network_params;
1703 }
1704
1705 // Append previous tokens.
1706 for (const SourceAddressToken& token : previous_tokens.tokens()) {
1707 if (source_address_tokens.tokens_size() > kMaxTokenAddresses) {
1708 break;
1709 }
1710
1711 if (token.ip() == source_address_token->ip()) {
1712 // It's for the same IP address.
1713 continue;
1714 }
1715
1716 if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) {
1717 continue;
1718 }
1719
1720 *(source_address_tokens.add_tokens()) = token;
1721 }
1722
1723 return config.source_address_token_boxer->Box(
1724 rand, source_address_tokens.SerializeAsString());
1725}
1726
1727int QuicCryptoServerConfig::NumberOfConfigs() const {
1728 QuicReaderMutexLock locked(&configs_lock_);
1729 return configs_.size();
1730}
1731
1732ProofSource* QuicCryptoServerConfig::proof_source() const {
1733 return proof_source_.get();
1734}
1735
1736SSL_CTX* QuicCryptoServerConfig::ssl_ctx() const {
1737 return ssl_ctx_.get();
1738}
1739
1740HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken(
1741 const Config& config,
1742 QuicStringPiece token,
1743 SourceAddressTokens* tokens) const {
vasilvvc48c8712019-03-11 13:38:16 -07001744 std::string storage;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001745 QuicStringPiece plaintext;
1746 if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) {
1747 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
1748 }
1749
1750 if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) {
1751 // Some clients might still be using the old source token format so
1752 // attempt to parse that format.
1753 // TODO(rch): remove this code once the new format is ubiquitous.
1754 SourceAddressToken token;
1755 if (!token.ParseFromArray(plaintext.data(), plaintext.size())) {
1756 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
1757 }
1758 *tokens->add_tokens() = token;
1759 }
1760
1761 return HANDSHAKE_OK;
1762}
1763
1764HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens(
1765 const SourceAddressTokens& source_address_tokens,
1766 const QuicIpAddress& ip,
1767 QuicWallTime now,
1768 CachedNetworkParameters* cached_network_params) const {
1769 HandshakeFailureReason reason =
1770 SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1771 for (const SourceAddressToken& token : source_address_tokens.tokens()) {
1772 reason = ValidateSingleSourceAddressToken(token, ip, now);
1773 if (reason == HANDSHAKE_OK) {
1774 if (token.has_cached_network_parameters()) {
1775 *cached_network_params = token.cached_network_parameters();
1776 }
1777 break;
1778 }
1779 }
1780 return reason;
1781}
1782
1783HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken(
1784 const SourceAddressToken& source_address_token,
1785 const QuicIpAddress& ip,
1786 QuicWallTime now) const {
1787 if (source_address_token.ip() != ip.DualStacked().ToPackedString()) {
1788 // It's for a different IP address.
1789 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1790 }
1791
1792 return ValidateSourceAddressTokenTimestamp(source_address_token, now);
1793}
1794
1795HandshakeFailureReason
1796QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp(
1797 const SourceAddressToken& source_address_token,
1798 QuicWallTime now) const {
1799 const QuicWallTime timestamp(
1800 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
1801 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
1802
1803 if (now.IsBefore(timestamp) &&
1804 delta.ToSeconds() > source_address_token_future_secs_) {
1805 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
1806 }
1807
1808 if (now.IsAfter(timestamp) &&
1809 delta.ToSeconds() > source_address_token_lifetime_secs_) {
1810 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
1811 }
1812
1813 return HANDSHAKE_OK;
1814}
1815
1816// kServerNoncePlaintextSize is the number of bytes in an unencrypted server
1817// nonce.
1818static const size_t kServerNoncePlaintextSize =
1819 4 /* timestamp */ + 20 /* random bytes */;
1820
vasilvvc48c8712019-03-11 13:38:16 -07001821std::string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
1822 QuicWallTime now) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001823 const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds());
1824
1825 uint8_t server_nonce[kServerNoncePlaintextSize];
1826 static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small");
1827 server_nonce[0] = static_cast<uint8_t>(timestamp >> 24);
1828 server_nonce[1] = static_cast<uint8_t>(timestamp >> 16);
1829 server_nonce[2] = static_cast<uint8_t>(timestamp >> 8);
1830 server_nonce[3] = static_cast<uint8_t>(timestamp);
1831 rand->RandBytes(&server_nonce[sizeof(timestamp)],
1832 sizeof(server_nonce) - sizeof(timestamp));
1833
1834 return server_nonce_boxer_.Box(
1835 rand, QuicStringPiece(reinterpret_cast<char*>(server_nonce),
1836 sizeof(server_nonce)));
1837}
1838
1839bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate(
1840 const CryptoHandshakeMessage& client_hello,
vasilvvc48c8712019-03-11 13:38:16 -07001841 const std::vector<std::string>& certs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001842 if (certs.empty()) {
1843 return false;
1844 }
1845
1846 uint64_t hash_from_client;
1847 if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) {
1848 return false;
1849 }
1850 return CryptoUtils::ComputeLeafCertHash(certs.at(0)) == hash_from_client;
1851}
1852
QUICHE teama6ef0a62019-03-07 20:34:33 -05001853bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001854 return !next_config_promotion_time_.IsZero() &&
rcha19b43d2019-03-22 13:58:37 -07001855 !next_config_promotion_time_.IsAfter(now);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001856}
1857
1858QuicCryptoServerConfig::Config::Config()
1859 : channel_id_enabled(false),
1860 is_primary(false),
1861 primary_time(QuicWallTime::Zero()),
1862 expiry_time(QuicWallTime::Zero()),
1863 priority(0),
1864 source_address_token_boxer(nullptr) {}
1865
1866QuicCryptoServerConfig::Config::~Config() {}
1867
1868QuicSignedServerConfig::QuicSignedServerConfig() {}
1869QuicSignedServerConfig::~QuicSignedServerConfig() {}
1870
1871} // namespace quic