blob: 253fb0eaf3237ef47200acfea2efdd5959996e59 [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) {
208 LOG(WARNING)
209 << "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
397 QuicReferenceCountedPointer<Config> config(ParseConfigProtobuf(protobuf));
398 if (!config.get()) {
399 QUIC_LOG(WARNING) << "Failed to parse server config message";
400 return nullptr;
401 }
402
403 {
404 QuicWriterMutexLock locked(&configs_lock_);
405 if (configs_.find(config->id) != configs_.end()) {
406 QUIC_LOG(WARNING) << "Failed to add config because another with the same "
407 "server config id already exists: "
408 << QuicTextUtils::HexEncode(config->id);
409 return nullptr;
410 }
411
412 configs_[config->id] = config;
413 SelectNewPrimaryConfig(now);
414 DCHECK(primary_config_.get());
415 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
416 primary_config_.get());
417 }
418
QUICHE teamd5af58a2019-03-14 20:35:50 -0700419 return msg;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500420}
421
QUICHE teamd5af58a2019-03-14 20:35:50 -0700422std::unique_ptr<CryptoHandshakeMessage>
423QuicCryptoServerConfig::AddDefaultConfig(QuicRandom* rand,
424 const QuicClock* clock,
425 const ConfigOptions& options) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500426 return AddConfig(GenerateConfig(rand, clock, options), clock->WallNow());
427}
428
429bool QuicCryptoServerConfig::SetConfigs(
QUICHE teambbaa8be2019-03-21 12:54:17 -0700430 const std::vector<QuicServerConfigProtobuf>& protobufs,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500431 const QuicWallTime now) {
432 std::vector<QuicReferenceCountedPointer<Config>> parsed_configs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500433 for (auto& protobuf : protobufs) {
434 QuicReferenceCountedPointer<Config> config(ParseConfigProtobuf(protobuf));
435 if (!config) {
QUICHE team78c2d5e2019-03-19 10:50:50 -0700436 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
437 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500438 }
439
440 parsed_configs.push_back(config);
441 }
442
443 if (parsed_configs.empty()) {
QUICHE team78c2d5e2019-03-19 10:50:50 -0700444 QUIC_LOG(WARNING)
445 << "Rejecting QUIC configs because new config list is empty.";
446 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500447 }
448
QUICHE team78c2d5e2019-03-19 10:50:50 -0700449 QUIC_LOG(INFO) << "Updating configs:";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500450
QUICHE team78c2d5e2019-03-19 10:50:50 -0700451 QuicWriterMutexLock locked(&configs_lock_);
452 ConfigMap new_configs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500453
QUICHE team78c2d5e2019-03-19 10:50:50 -0700454 for (const QuicReferenceCountedPointer<Config>& config : parsed_configs) {
455 auto it = configs_.find(config->id);
456 if (it != configs_.end()) {
457 QUIC_LOG(INFO) << "Keeping scid: " << QuicTextUtils::HexEncode(config->id)
458 << " orbit: "
459 << QuicTextUtils::HexEncode(
460 reinterpret_cast<const char*>(config->orbit),
461 kOrbitSize)
462 << " new primary_time "
463 << config->primary_time.ToUNIXSeconds()
464 << " old primary_time "
465 << it->second->primary_time.ToUNIXSeconds()
466 << " new priority " << config->priority << " old priority "
467 << it->second->priority;
468 // Update primary_time and priority.
469 it->second->primary_time = config->primary_time;
470 it->second->priority = config->priority;
471 new_configs.insert(*it);
472 } else {
473 QUIC_LOG(INFO) << "Adding scid: " << QuicTextUtils::HexEncode(config->id)
474 << " orbit: "
475 << QuicTextUtils::HexEncode(
476 reinterpret_cast<const char*>(config->orbit),
477 kOrbitSize)
478 << " primary_time " << config->primary_time.ToUNIXSeconds()
479 << " priority " << config->priority;
480 new_configs.emplace(config->id, config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500481 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500482 }
483
QUICHE team78c2d5e2019-03-19 10:50:50 -0700484 configs_ = std::move(new_configs);
485 SelectNewPrimaryConfig(now);
486 DCHECK(primary_config_.get());
487 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
488 primary_config_.get());
489
490 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500491}
492
493void QuicCryptoServerConfig::SetSourceAddressTokenKeys(
vasilvvc48c8712019-03-11 13:38:16 -0700494 const std::vector<std::string>& keys) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500495 source_address_token_boxer_.SetKeys(keys);
496}
497
498void QuicCryptoServerConfig::GetConfigIds(
vasilvvc48c8712019-03-11 13:38:16 -0700499 std::vector<std::string>* scids) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500500 QuicReaderMutexLock locked(&configs_lock_);
501 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
502 scids->push_back(it->first);
503 }
504}
505
506void QuicCryptoServerConfig::ValidateClientHello(
507 const CryptoHandshakeMessage& client_hello,
508 const QuicIpAddress& client_ip,
509 const QuicSocketAddress& server_address,
510 QuicTransportVersion version,
511 const QuicClock* clock,
512 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
513 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
514 const QuicWallTime now(clock->WallNow());
515
516 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result(
517 new ValidateClientHelloResultCallback::Result(client_hello, client_ip,
518 now));
519
520 QuicStringPiece requested_scid;
521 client_hello.GetStringPiece(kSCID, &requested_scid);
QUICHE team1225f472019-03-19 15:52:25 -0700522 Configs configs;
523 if (!GetCurrentConfigs(now, requested_scid,
524 /* old_primary_config = */ nullptr, &configs)) {
525 result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
526 result->error_details = "No configurations loaded";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500527 }
QUICHE team1225f472019-03-19 15:52:25 -0700528 signed_config->config = configs.primary;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500529
530 if (result->error_code == QUIC_NO_ERROR) {
531 // QUIC requires a new proof for each CHLO so clear any existing proof.
532 signed_config->chain = nullptr;
533 signed_config->proof.signature = "";
534 signed_config->proof.leaf_cert_scts = "";
QUICHE team1225f472019-03-19 15:52:25 -0700535 EvaluateClientHello(server_address, version, configs, result,
536 std::move(done_cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500537 } else {
538 done_cb->Run(result, /* details = */ nullptr);
539 }
540}
541
QUICHE teama6ef0a62019-03-07 20:34:33 -0500542class QuicCryptoServerConfig::ProcessClientHelloCallback
543 : public ProofSource::Callback {
544 public:
QUICHE team1225f472019-03-19 15:52:25 -0700545 ProcessClientHelloCallback(const QuicCryptoServerConfig* config,
546 std::unique_ptr<ProcessClientHelloContext> context,
547 const Configs& configs)
548 : config_(config), context_(std::move(context)), configs_(configs) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500549
550 void Run(bool ok,
551 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
552 const QuicCryptoProof& proof,
553 std::unique_ptr<ProofSource::Details> details) override {
554 if (ok) {
QUICHE team4dae8412019-03-18 13:11:00 -0700555 context_->signed_config()->chain = chain;
556 context_->signed_config()->proof = proof;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500557 }
QUICHE team1225f472019-03-19 15:52:25 -0700558 config_->ProcessClientHelloAfterGetProof(!ok, std::move(details),
559 std::move(context_), configs_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500560 }
561
562 private:
563 const QuicCryptoServerConfig* config_;
QUICHE team4dae8412019-03-18 13:11:00 -0700564 std::unique_ptr<ProcessClientHelloContext> context_;
QUICHE team1225f472019-03-19 15:52:25 -0700565 const Configs configs_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500566};
567
568class QuicCryptoServerConfig::ProcessClientHelloAfterGetProofCallback
QUICHE teamfe1aca62019-03-14 13:39:01 -0700569 : public AsynchronousKeyExchange::Callback {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500570 public:
571 ProcessClientHelloAfterGetProofCallback(
572 const QuicCryptoServerConfig* config,
573 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE teamfe1aca62019-03-14 13:39:01 -0700574 QuicTag key_exchange_type,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500575 std::unique_ptr<CryptoHandshakeMessage> out,
576 QuicStringPiece public_value,
QUICHE team4dae8412019-03-18 13:11:00 -0700577 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700578 const Configs& configs)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500579 : config_(config),
580 proof_source_details_(std::move(proof_source_details)),
QUICHE teamfe1aca62019-03-14 13:39:01 -0700581 key_exchange_type_(key_exchange_type),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500582 out_(std::move(out)),
583 public_value_(public_value),
QUICHE team4dae8412019-03-18 13:11:00 -0700584 context_(std::move(context)),
QUICHE team1225f472019-03-19 15:52:25 -0700585 configs_(configs) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500586
587 void Run(bool ok) override {
588 config_->ProcessClientHelloAfterCalculateSharedKeys(
QUICHE teamfe1aca62019-03-14 13:39:01 -0700589 !ok, std::move(proof_source_details_), key_exchange_type_,
QUICHE team1225f472019-03-19 15:52:25 -0700590 std::move(out_), public_value_, std::move(context_), configs_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500591 }
592
593 private:
594 const QuicCryptoServerConfig* config_;
595 std::unique_ptr<ProofSource::Details> proof_source_details_;
QUICHE teamfe1aca62019-03-14 13:39:01 -0700596 QuicTag key_exchange_type_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500597 std::unique_ptr<CryptoHandshakeMessage> out_;
vasilvvc48c8712019-03-11 13:38:16 -0700598 std::string public_value_;
QUICHE team4dae8412019-03-18 13:11:00 -0700599 std::unique_ptr<ProcessClientHelloContext> context_;
QUICHE team1225f472019-03-19 15:52:25 -0700600 const Configs configs_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500601};
602
603void QuicCryptoServerConfig::ProcessClientHello(
604 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
605 validate_chlo_result,
606 bool reject_only,
607 QuicConnectionId connection_id,
608 const QuicSocketAddress& server_address,
609 const QuicSocketAddress& client_address,
610 ParsedQuicVersion version,
611 const ParsedQuicVersionVector& supported_versions,
612 bool use_stateless_rejects,
613 QuicConnectionId server_designated_connection_id,
614 const QuicClock* clock,
615 QuicRandom* rand,
616 QuicCompressedCertsCache* compressed_certs_cache,
617 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,
618 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
619 QuicByteCount total_framing_overhead,
620 QuicByteCount chlo_packet_size,
621 std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
622 DCHECK(done_cb);
QUICHE team4dae8412019-03-18 13:11:00 -0700623 auto context = QuicMakeUnique<ProcessClientHelloContext>(
624 validate_chlo_result, reject_only, connection_id, server_address,
625 client_address, version, supported_versions, use_stateless_rejects,
626 server_designated_connection_id, clock, rand, compressed_certs_cache,
627 params, signed_config, total_framing_overhead, chlo_packet_size,
628 std::move(done_cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500629
QUICHE team1225f472019-03-19 15:52:25 -0700630 // Verify that various parts of the CHLO are valid
vasilvvc48c8712019-03-11 13:38:16 -0700631 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500632 QuicErrorCode valid = CryptoUtils::ValidateClientHello(
QUICHE team4dae8412019-03-18 13:11:00 -0700633 context->client_hello(), context->version(),
634 context->supported_versions(), &error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500635 if (valid != QUIC_NO_ERROR) {
QUICHE team4dae8412019-03-18 13:11:00 -0700636 context->Fail(valid, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500637 return;
638 }
639
640 QuicStringPiece requested_scid;
QUICHE team4dae8412019-03-18 13:11:00 -0700641 context->client_hello().GetStringPiece(kSCID, &requested_scid);
QUICHE team1225f472019-03-19 15:52:25 -0700642 Configs configs;
643 if (!GetCurrentConfigs(context->clock()->WallNow(), requested_scid,
644 signed_config->config, &configs)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700645 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "No configurations loaded");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500646 return;
647 }
648
QUICHE team4dae8412019-03-18 13:11:00 -0700649 if (context->validate_chlo_result()->error_code != QUIC_NO_ERROR) {
650 context->Fail(context->validate_chlo_result()->error_code,
651 context->validate_chlo_result()->error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500652 return;
653 }
654
QUICHE team4dae8412019-03-18 13:11:00 -0700655 if (!ClientDemandsX509Proof(context->client_hello())) {
656 context->Fail(QUIC_UNSUPPORTED_PROOF_DEMAND, "Missing or invalid PDMD");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500657 return;
658 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500659
660 // No need to get a new proof if one was already generated.
QUICHE team4dae8412019-03-18 13:11:00 -0700661 if (!context->signed_config()->chain) {
662 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
663 context->client_hello(), Perspective::IS_SERVER);
664 const QuicSocketAddress server_address = context->server_address();
665 const std::string sni = std::string(context->info().sni);
666 const QuicTransportVersion transport_version = context->transport_version();
667
QUICHE teamea5bdef2019-03-13 15:41:27 -0700668 auto cb = QuicMakeUnique<ProcessClientHelloCallback>(
QUICHE team1225f472019-03-19 15:52:25 -0700669 this, std::move(context), configs);
QUICHE team84910bd2019-03-15 07:03:40 -0700670
671 DCHECK(proof_source_.get());
QUICHE team1225f472019-03-19 15:52:25 -0700672 proof_source_->GetProof(server_address, sni, configs.primary->serialized,
QUICHE team4dae8412019-03-18 13:11:00 -0700673 transport_version, chlo_hash, std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500674 return;
675 }
676
QUICHE teama6ef0a62019-03-07 20:34:33 -0500677 ProcessClientHelloAfterGetProof(
678 /* found_error = */ false, /* proof_source_details = */ nullptr,
QUICHE team1225f472019-03-19 15:52:25 -0700679 std::move(context), configs);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500680}
681
682void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
683 bool found_error,
684 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE team4dae8412019-03-18 13:11:00 -0700685 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700686 const Configs& configs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500687 QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -0700688 context->connection_id(), context->transport_version()))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500689 << "ProcessClientHelloAfterGetProof: attempted to use connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -0700690 << context->connection_id() << " which is invalid with version "
691 << QuicVersionToString(context->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500692
693 if (found_error) {
QUICHE team4dae8412019-03-18 13:11:00 -0700694 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500695 return;
696 }
697
QUICHE teamea5bdef2019-03-13 15:41:27 -0700698 auto out_diversification_nonce = QuicMakeUnique<DiversificationNonce>();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500699
700 QuicStringPiece cert_sct;
QUICHE team4dae8412019-03-18 13:11:00 -0700701 if (context->client_hello().GetStringPiece(kCertificateSCTTag, &cert_sct) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500702 cert_sct.empty()) {
QUICHE team4dae8412019-03-18 13:11:00 -0700703 context->params()->sct_supported_by_client = true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500704 }
705
QUICHE teamea5bdef2019-03-13 15:41:27 -0700706 auto out = QuicMakeUnique<CryptoHandshakeMessage>();
QUICHE team1225f472019-03-19 15:52:25 -0700707 if (!context->info().reject_reasons.empty() || !configs.requested) {
QUICHE teamaa924f12019-03-21 11:26:21 -0700708 BuildRejectionAndRecordStats(*context, *configs.primary,
709 context->info().reject_reasons, out.get());
QUICHE team4dae8412019-03-18 13:11:00 -0700710 context->Succeed(std::move(out), std::move(out_diversification_nonce),
711 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500712 return;
713 }
714
QUICHE team4dae8412019-03-18 13:11:00 -0700715 if (context->reject_only()) {
716 context->Succeed(std::move(out), std::move(out_diversification_nonce),
717 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500718 return;
719 }
720
721 QuicTagVector their_aeads;
722 QuicTagVector their_key_exchanges;
QUICHE team4dae8412019-03-18 13:11:00 -0700723 if (context->client_hello().GetTaglist(kAEAD, &their_aeads) !=
724 QUIC_NO_ERROR ||
725 context->client_hello().GetTaglist(kKEXS, &their_key_exchanges) !=
726 QUIC_NO_ERROR ||
QUICHE teama6ef0a62019-03-07 20:34:33 -0500727 their_aeads.size() != 1 || their_key_exchanges.size() != 1) {
QUICHE team4dae8412019-03-18 13:11:00 -0700728 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
729 "Missing or invalid AEAD or KEXS");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500730 return;
731 }
732
733 size_t key_exchange_index;
QUICHE team1225f472019-03-19 15:52:25 -0700734 if (!FindMutualQuicTag(configs.requested->aead, their_aeads,
QUICHE team4dae8412019-03-18 13:11:00 -0700735 &context->params()->aead, nullptr) ||
QUICHE team1225f472019-03-19 15:52:25 -0700736 !FindMutualQuicTag(configs.requested->kexs, their_key_exchanges,
QUICHE team4dae8412019-03-18 13:11:00 -0700737 &context->params()->key_exchange,
738 &key_exchange_index)) {
739 context->Fail(QUIC_CRYPTO_NO_SUPPORT, "Unsupported AEAD or KEXS");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500740 return;
741 }
742
QUICHE team1225f472019-03-19 15:52:25 -0700743 if (!configs.requested->tb_key_params.empty()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500744 QuicTagVector their_tbkps;
QUICHE team4dae8412019-03-18 13:11:00 -0700745 switch (context->client_hello().GetTaglist(kTBKP, &their_tbkps)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500746 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
747 break;
748 case QUIC_NO_ERROR:
QUICHE team1225f472019-03-19 15:52:25 -0700749 if (FindMutualQuicTag(configs.requested->tb_key_params, their_tbkps,
QUICHE team4dae8412019-03-18 13:11:00 -0700750 &context->params()->token_binding_key_param,
751 nullptr)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500752 break;
753 }
754 QUIC_FALLTHROUGH_INTENDED;
755 default:
QUICHE team4dae8412019-03-18 13:11:00 -0700756 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
757 "Invalid Token Binding key parameter");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500758 return;
759 }
760 }
761
762 QuicStringPiece public_value;
QUICHE team4dae8412019-03-18 13:11:00 -0700763 if (!context->client_hello().GetStringPiece(kPUBS, &public_value)) {
764 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
765 "Missing public value");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500766 return;
767 }
768
QUICHE teamfe1aca62019-03-14 13:39:01 -0700769 const AsynchronousKeyExchange* key_exchange =
QUICHE team1225f472019-03-19 15:52:25 -0700770 configs.requested->key_exchanges[key_exchange_index].get();
QUICHE team4dae8412019-03-18 13:11:00 -0700771 std::string* initial_premaster_secret =
772 &context->params()->initial_premaster_secret;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500773 auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>(
QUICHE teamfe1aca62019-03-14 13:39:01 -0700774 this, std::move(proof_source_details), key_exchange->type(),
QUICHE team1225f472019-03-19 15:52:25 -0700775 std::move(out), public_value, std::move(context), configs);
QUICHE team4dae8412019-03-18 13:11:00 -0700776 key_exchange->CalculateSharedKeyAsync(public_value, initial_premaster_secret,
777 std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500778}
779
780void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys(
781 bool found_error,
782 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE teamfe1aca62019-03-14 13:39:01 -0700783 QuicTag key_exchange_type,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500784 std::unique_ptr<CryptoHandshakeMessage> out,
785 QuicStringPiece public_value,
QUICHE team4dae8412019-03-18 13:11:00 -0700786 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700787 const Configs& configs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500788 QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -0700789 context->connection_id(), context->transport_version()))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500790 << "ProcessClientHelloAfterCalculateSharedKeys:"
791 " attempted to use connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -0700792 << context->connection_id() << " which is invalid with version "
793 << QuicVersionToString(context->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500794
795 if (found_error) {
QUICHE team4dae8412019-03-18 13:11:00 -0700796 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
797 "Failed to calculate shared key");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500798 return;
799 }
800
QUICHE team4dae8412019-03-18 13:11:00 -0700801 if (!context->info().sni.empty()) {
802 context->params()->sni =
803 QuicHostnameUtils::NormalizeHostname(context->info().sni);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500804 }
805
vasilvvc48c8712019-03-11 13:38:16 -0700806 std::string hkdf_suffix;
QUICHE team4dae8412019-03-18 13:11:00 -0700807 const QuicData& client_hello_serialized =
808 context->client_hello().GetSerialized();
809 hkdf_suffix.reserve(context->connection_id().length() +
vasilvvc48c8712019-03-11 13:38:16 -0700810 client_hello_serialized.length() +
QUICHE team1225f472019-03-19 15:52:25 -0700811 configs.requested->serialized.size());
QUICHE team4dae8412019-03-18 13:11:00 -0700812 hkdf_suffix.append(context->connection_id().data(),
813 context->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500814 hkdf_suffix.append(client_hello_serialized.data(),
815 client_hello_serialized.length());
QUICHE team1225f472019-03-19 15:52:25 -0700816 hkdf_suffix.append(configs.requested->serialized);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500817 DCHECK(proof_source_.get());
QUICHE team4dae8412019-03-18 13:11:00 -0700818 if (context->signed_config()->chain->certs.empty()) {
819 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "Failed to get certs");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500820 return;
821 }
QUICHE team4dae8412019-03-18 13:11:00 -0700822 hkdf_suffix.append(context->signed_config()->chain->certs.at(0));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500823
824 QuicStringPiece cetv_ciphertext;
QUICHE team1225f472019-03-19 15:52:25 -0700825 if (configs.requested->channel_id_enabled &&
QUICHE team4dae8412019-03-18 13:11:00 -0700826 context->client_hello().GetStringPiece(kCETV, &cetv_ciphertext)) {
827 CryptoHandshakeMessage client_hello_copy(context->client_hello());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500828 client_hello_copy.Erase(kCETV);
829 client_hello_copy.Erase(kPAD);
830
831 const QuicData& client_hello_copy_serialized =
832 client_hello_copy.GetSerialized();
vasilvvc48c8712019-03-11 13:38:16 -0700833 std::string hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500834 hkdf_input.append(QuicCryptoConfig::kCETVLabel,
835 strlen(QuicCryptoConfig::kCETVLabel) + 1);
QUICHE team4dae8412019-03-18 13:11:00 -0700836 hkdf_input.append(context->connection_id().data(),
837 context->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500838 hkdf_input.append(client_hello_copy_serialized.data(),
839 client_hello_copy_serialized.length());
QUICHE team1225f472019-03-19 15:52:25 -0700840 hkdf_input.append(configs.requested->serialized);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500841
842 CrypterPair crypters;
843 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700844 context->params()->initial_premaster_secret,
845 context->params()->aead, context->info().client_nonce,
846 context->info().server_nonce, pre_shared_key_, hkdf_input,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500847 Perspective::IS_SERVER, CryptoUtils::Diversification::Never(),
848 &crypters, nullptr /* subkey secret */)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700849 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
850 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500851 return;
852 }
853
854 char plaintext[kMaxPacketSize];
855 size_t plaintext_length = 0;
856 const bool success = crypters.decrypter->DecryptPacket(
857 0 /* packet number */, QuicStringPiece() /* associated data */,
858 cetv_ciphertext, plaintext, &plaintext_length, kMaxPacketSize);
859 if (!success) {
QUICHE team4dae8412019-03-18 13:11:00 -0700860 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
861 "CETV decryption failure");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500862 return;
863 }
864 std::unique_ptr<CryptoHandshakeMessage> cetv(CryptoFramer::ParseMessage(
865 QuicStringPiece(plaintext, plaintext_length)));
866 if (!cetv.get()) {
QUICHE team4dae8412019-03-18 13:11:00 -0700867 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV parse error");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500868 return;
869 }
870
871 QuicStringPiece key, signature;
872 if (cetv->GetStringPiece(kCIDK, &key) &&
873 cetv->GetStringPiece(kCIDS, &signature)) {
874 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700875 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
876 "ChannelID signature failure");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500877 return;
878 }
879
QUICHE team4dae8412019-03-18 13:11:00 -0700880 context->params()->channel_id = std::string(key);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500881 }
882 }
883
vasilvvc48c8712019-03-11 13:38:16 -0700884 std::string hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500885 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
886 hkdf_input.reserve(label_len + hkdf_suffix.size());
887 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
888 hkdf_input.append(hkdf_suffix);
889
QUICHE team45c889c2019-03-14 16:37:01 -0700890 auto out_diversification_nonce = QuicMakeUnique<DiversificationNonce>();
QUICHE team4dae8412019-03-18 13:11:00 -0700891 context->rand()->RandBytes(out_diversification_nonce->data(),
892 out_diversification_nonce->size());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500893 CryptoUtils::Diversification diversification =
894 CryptoUtils::Diversification::Now(out_diversification_nonce.get());
895 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700896 context->params()->initial_premaster_secret, context->params()->aead,
897 context->info().client_nonce, context->info().server_nonce,
898 pre_shared_key_, hkdf_input, Perspective::IS_SERVER, diversification,
899 &context->params()->initial_crypters,
900 &context->params()->initial_subkey_secret)) {
901 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
902 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500903 return;
904 }
905
vasilvvc48c8712019-03-11 13:38:16 -0700906 std::string forward_secure_public_value;
QUICHE teamfe1aca62019-03-14 13:39:01 -0700907 std::unique_ptr<SynchronousKeyExchange> forward_secure_key_exchange =
QUICHE team4dae8412019-03-18 13:11:00 -0700908 CreateLocalSynchronousKeyExchange(key_exchange_type, context->rand());
QUICHE teamfe1aca62019-03-14 13:39:01 -0700909 if (!forward_secure_key_exchange) {
910 QUIC_DLOG(WARNING) << "Failed to create keypair";
QUICHE team4dae8412019-03-18 13:11:00 -0700911 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
912 "Failed to create keypair");
QUICHE teamfe1aca62019-03-14 13:39:01 -0700913 return;
914 }
915
QUICHE teama6ef0a62019-03-07 20:34:33 -0500916 forward_secure_public_value =
vasilvvc48c8712019-03-11 13:38:16 -0700917 std::string(forward_secure_key_exchange->public_value());
QUICHE teamfe1aca62019-03-14 13:39:01 -0700918 if (!forward_secure_key_exchange->CalculateSharedKeySync(
QUICHE team4dae8412019-03-18 13:11:00 -0700919 public_value, &context->params()->forward_secure_premaster_secret)) {
920 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
921 "Invalid public value");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500922 return;
923 }
924
vasilvvc48c8712019-03-11 13:38:16 -0700925 std::string forward_secure_hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500926 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
927 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
928 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
929 label_len);
930 forward_secure_hkdf_input.append(hkdf_suffix);
931
vasilvvc48c8712019-03-11 13:38:16 -0700932 std::string shlo_nonce;
QUICHE team4dae8412019-03-18 13:11:00 -0700933 shlo_nonce = NewServerNonce(context->rand(), context->info().now);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500934 out->SetStringPiece(kServerNonceTag, shlo_nonce);
935
936 if (!CryptoUtils::DeriveKeys(
QUICHE team4dae8412019-03-18 13:11:00 -0700937 context->params()->forward_secure_premaster_secret,
938 context->params()->aead, context->info().client_nonce,
939 shlo_nonce.empty() ? context->info().server_nonce : shlo_nonce,
940 pre_shared_key_, forward_secure_hkdf_input, Perspective::IS_SERVER,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500941 CryptoUtils::Diversification::Never(),
QUICHE team4dae8412019-03-18 13:11:00 -0700942 &context->params()->forward_secure_crypters,
943 &context->params()->subkey_secret)) {
944 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
945 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500946 return;
947 }
948
949 out->set_tag(kSHLO);
QUICHE team4dae8412019-03-18 13:11:00 -0700950 out->SetVersionVector(kVER, context->supported_versions());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500951 out->SetStringPiece(
952 kSourceAddressTokenTag,
QUICHE team1225f472019-03-19 15:52:25 -0700953 NewSourceAddressToken(*configs.requested,
QUICHE team4dae8412019-03-18 13:11:00 -0700954 context->info().source_address_tokens,
955 context->client_address().host(), context->rand(),
956 context->info().now, nullptr));
957 QuicSocketAddressCoder address_coder(context->client_address());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500958 out->SetStringPiece(kCADR, address_coder.Encode());
959 out->SetStringPiece(kPUBS, forward_secure_public_value);
960
QUICHE team4dae8412019-03-18 13:11:00 -0700961 context->Succeed(std::move(out), std::move(out_diversification_nonce),
962 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500963}
964
965QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
966QuicCryptoServerConfig::GetConfigWithScid(
967 QuicStringPiece requested_scid) const {
968 configs_lock_.AssertReaderHeld();
969
970 if (!requested_scid.empty()) {
vasilvvc48c8712019-03-11 13:38:16 -0700971 auto it = configs_.find((std::string(requested_scid)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500972 if (it != configs_.end()) {
973 // We'll use the config that the client requested in order to do
974 // key-agreement.
975 return QuicReferenceCountedPointer<Config>(it->second);
976 }
977 }
978
979 return QuicReferenceCountedPointer<Config>();
980}
981
QUICHE team1225f472019-03-19 15:52:25 -0700982bool QuicCryptoServerConfig::GetCurrentConfigs(
983 const QuicWallTime& now,
984 QuicStringPiece requested_scid,
985 QuicReferenceCountedPointer<Config> old_primary_config,
986 Configs* configs) const {
987 QuicReaderMutexLock locked(&configs_lock_);
988
989 if (!primary_config_) {
990 return false;
991 }
992
993 if (IsNextConfigReady(now)) {
994 configs_lock_.ReaderUnlock();
995 configs_lock_.WriterLock();
996 SelectNewPrimaryConfig(now);
997 DCHECK(primary_config_.get());
998 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
999 primary_config_.get());
1000 configs_lock_.WriterUnlock();
1001 configs_lock_.ReaderLock();
1002 }
1003
1004 if (old_primary_config != nullptr) {
1005 configs->primary = old_primary_config;
1006 } else {
1007 configs->primary = primary_config_;
1008 }
1009 configs->requested = GetConfigWithScid(requested_scid);
1010
1011 return true;
1012}
1013
QUICHE teama6ef0a62019-03-07 20:34:33 -05001014// ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
1015// Config's based on their primary_time.
1016// static
1017bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
1018 const QuicReferenceCountedPointer<Config>& a,
1019 const QuicReferenceCountedPointer<Config>& b) {
1020 if (a->primary_time.IsBefore(b->primary_time) ||
1021 b->primary_time.IsBefore(a->primary_time)) {
1022 // Primary times differ.
1023 return a->primary_time.IsBefore(b->primary_time);
1024 } else if (a->priority != b->priority) {
1025 // Primary times are equal, sort backwards by priority.
1026 return a->priority < b->priority;
1027 } else {
1028 // Primary times and priorities are equal, sort by config id.
1029 return a->id < b->id;
1030 }
1031}
1032
1033void QuicCryptoServerConfig::SelectNewPrimaryConfig(
1034 const QuicWallTime now) const {
1035 std::vector<QuicReferenceCountedPointer<Config>> configs;
1036 configs.reserve(configs_.size());
1037
1038 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
1039 // TODO(avd) Exclude expired configs?
1040 configs.push_back(it->second);
1041 }
1042
1043 if (configs.empty()) {
1044 if (primary_config_ != nullptr) {
1045 QUIC_BUG << "No valid QUIC server config. Keeping the current config.";
1046 } else {
1047 QUIC_BUG << "No valid QUIC server config.";
1048 }
1049 return;
1050 }
1051
1052 std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan);
1053
1054 QuicReferenceCountedPointer<Config> best_candidate = configs[0];
1055
1056 for (size_t i = 0; i < configs.size(); ++i) {
1057 const QuicReferenceCountedPointer<Config> config(configs[i]);
1058 if (!config->primary_time.IsAfter(now)) {
1059 if (config->primary_time.IsAfter(best_candidate->primary_time)) {
1060 best_candidate = config;
1061 }
1062 continue;
1063 }
1064
1065 // This is the first config with a primary_time in the future. Thus the
1066 // previous Config should be the primary and this one should determine the
1067 // next_config_promotion_time_.
1068 QuicReferenceCountedPointer<Config> new_primary = best_candidate;
1069 if (i == 0) {
1070 // We need the primary_time of the next config.
1071 if (configs.size() > 1) {
1072 next_config_promotion_time_ = configs[1]->primary_time;
1073 } else {
1074 next_config_promotion_time_ = QuicWallTime::Zero();
1075 }
1076 } else {
1077 next_config_promotion_time_ = config->primary_time;
1078 }
1079
1080 if (primary_config_) {
1081 primary_config_->is_primary = false;
1082 }
1083 primary_config_ = new_primary;
1084 new_primary->is_primary = true;
1085 QUIC_DLOG(INFO) << "New primary config. orbit: "
1086 << QuicTextUtils::HexEncode(reinterpret_cast<const char*>(
1087 primary_config_->orbit),
1088 kOrbitSize);
1089 if (primary_config_changed_cb_ != nullptr) {
1090 primary_config_changed_cb_->Run(primary_config_->id);
1091 }
1092
1093 return;
1094 }
1095
1096 // All config's primary times are in the past. We should make the most recent
1097 // and highest priority candidate primary.
1098 QuicReferenceCountedPointer<Config> new_primary = best_candidate;
1099 if (primary_config_) {
1100 primary_config_->is_primary = false;
1101 }
1102 primary_config_ = new_primary;
1103 new_primary->is_primary = true;
1104 QUIC_DLOG(INFO) << "New primary config. orbit: "
1105 << QuicTextUtils::HexEncode(
1106 reinterpret_cast<const char*>(primary_config_->orbit),
1107 kOrbitSize)
1108 << " scid: " << QuicTextUtils::HexEncode(primary_config_->id);
1109 next_config_promotion_time_ = QuicWallTime::Zero();
1110 if (primary_config_changed_cb_ != nullptr) {
1111 primary_config_changed_cb_->Run(primary_config_->id);
1112 }
1113}
1114
QUICHE teama6ef0a62019-03-07 20:34:33 -05001115void QuicCryptoServerConfig::EvaluateClientHello(
1116 const QuicSocketAddress& server_address,
1117 QuicTransportVersion version,
QUICHE team1225f472019-03-19 15:52:25 -07001118 const Configs& configs,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001119 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
1120 client_hello_state,
1121 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001122 ValidateClientHelloHelper helper(client_hello_state, &done_cb);
1123
1124 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
1125 ClientHelloInfo* info = &(client_hello_state->info);
1126
1127 if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) {
1128 helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
1129 "Client hello too small", nullptr);
1130 return;
1131 }
1132
1133 if (client_hello.GetStringPiece(kSNI, &info->sni) &&
1134 !QuicHostnameUtils::IsValidSNI(info->sni)) {
1135 helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
1136 "Invalid SNI name", nullptr);
1137 return;
1138 }
1139
1140 client_hello.GetStringPiece(kUAID, &info->user_agent_id);
1141
1142 HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
1143 if (validate_source_address_token_) {
1144 QuicStringPiece srct;
1145 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
1146 Config& config =
QUICHE team1225f472019-03-19 15:52:25 -07001147 configs.requested != nullptr ? *configs.requested : *configs.primary;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001148 source_address_token_error =
1149 ParseSourceAddressToken(config, srct, &info->source_address_tokens);
1150
1151 if (source_address_token_error == HANDSHAKE_OK) {
1152 source_address_token_error = ValidateSourceAddressTokens(
1153 info->source_address_tokens, info->client_ip, info->now,
1154 &client_hello_state->cached_network_params);
1155 }
1156 info->valid_source_address_token =
1157 (source_address_token_error == HANDSHAKE_OK);
1158 } else {
1159 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
1160 }
1161 } else {
1162 source_address_token_error = HANDSHAKE_OK;
1163 info->valid_source_address_token = true;
1164 }
1165
QUICHE team1225f472019-03-19 15:52:25 -07001166 if (!configs.requested) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001167 QuicStringPiece requested_scid;
1168 if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
1169 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1170 } else {
1171 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1172 }
1173 // No server config with the requested ID.
1174 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1175 return;
1176 }
1177
1178 if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) {
1179 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1180 // Report no client nonce as INCHOATE_HELLO_FAILURE.
1181 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1182 return;
1183 }
1184
1185 if (source_address_token_error != HANDSHAKE_OK) {
1186 info->reject_reasons.push_back(source_address_token_error);
1187 // No valid source address token.
1188 }
1189
1190 QuicReferenceCountedPointer<ProofSource::Chain> chain =
vasilvvc48c8712019-03-11 13:38:16 -07001191 proof_source_->GetCertChain(server_address, std::string(info->sni));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001192 if (!chain) {
1193 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1194 } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) {
1195 info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
1196 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001197
1198 if (info->client_nonce.size() != kNonceSize) {
1199 info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
1200 // Invalid client nonce.
1201 QUIC_LOG_FIRST_N(ERROR, 2)
1202 << "Invalid client nonce: " << client_hello.DebugString();
1203 QUIC_DLOG(INFO) << "Invalid client nonce.";
1204 }
1205
1206 // Server nonce is optional, and used for key derivation if present.
1207 client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
1208
1209 QUIC_DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher.";
1210 // If the server nonce is empty and we're requiring handshake confirmation
1211 // for DoS reasons then we must reject the CHLO.
1212 if (GetQuicReloadableFlag(quic_require_handshake_confirmation) &&
1213 info->server_nonce.empty()) {
1214 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
1215 }
QUICHE team79fb9e22019-03-15 07:49:56 -07001216 helper.ValidationComplete(QUIC_NO_ERROR, "",
1217 std::unique_ptr<ProofSource::Details>());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001218}
1219
1220void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
1221 QuicTransportVersion version,
1222 QuicStringPiece chlo_hash,
1223 const SourceAddressTokens& previous_source_address_tokens,
1224 const QuicSocketAddress& server_address,
1225 const QuicIpAddress& client_ip,
1226 const QuicClock* clock,
1227 QuicRandom* rand,
1228 QuicCompressedCertsCache* compressed_certs_cache,
1229 const QuicCryptoNegotiatedParameters& params,
1230 const CachedNetworkParameters* cached_network_params,
1231 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
vasilvvc48c8712019-03-11 13:38:16 -07001232 std::string serialized;
1233 std::string source_address_token;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001234 const CommonCertSets* common_cert_sets;
1235 {
1236 QuicReaderMutexLock locked(&configs_lock_);
1237 serialized = primary_config_->serialized;
1238 common_cert_sets = primary_config_->common_cert_sets;
1239 source_address_token = NewSourceAddressToken(
1240 *primary_config_, previous_source_address_tokens, client_ip, rand,
1241 clock->WallNow(), cached_network_params);
1242 }
1243
1244 CryptoHandshakeMessage message;
1245 message.set_tag(kSCUP);
1246 message.SetStringPiece(kSCFG, serialized);
1247 message.SetStringPiece(kSourceAddressTokenTag, source_address_token);
1248
QUICHE teamea5bdef2019-03-13 15:41:27 -07001249 auto proof_source_cb =
1250 QuicMakeUnique<BuildServerConfigUpdateMessageProofSourceCallback>(
QUICHE team39a71e52019-03-15 14:24:34 -07001251 this, compressed_certs_cache, common_cert_sets, params,
QUICHE teamea5bdef2019-03-13 15:41:27 -07001252 std::move(message), std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001253
1254 proof_source_->GetProof(server_address, params.sni, serialized, version,
1255 chlo_hash, std::move(proof_source_cb));
1256}
1257
1258QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1259 ~BuildServerConfigUpdateMessageProofSourceCallback() {}
1260
1261QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1262 BuildServerConfigUpdateMessageProofSourceCallback(
1263 const QuicCryptoServerConfig* config,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001264 QuicCompressedCertsCache* compressed_certs_cache,
1265 const CommonCertSets* common_cert_sets,
1266 const QuicCryptoNegotiatedParameters& params,
1267 CryptoHandshakeMessage message,
1268 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb)
1269 : config_(config),
QUICHE teama6ef0a62019-03-07 20:34:33 -05001270 compressed_certs_cache_(compressed_certs_cache),
1271 common_cert_sets_(common_cert_sets),
1272 client_common_set_hashes_(params.client_common_set_hashes),
1273 client_cached_cert_hashes_(params.client_cached_cert_hashes),
1274 sct_supported_by_client_(params.sct_supported_by_client),
1275 sni_(params.sni),
1276 message_(std::move(message)),
1277 cb_(std::move(cb)) {}
1278
1279void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1280 Run(bool ok,
1281 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
1282 const QuicCryptoProof& proof,
1283 std::unique_ptr<ProofSource::Details> details) {
1284 config_->FinishBuildServerConfigUpdateMessage(
QUICHE team39a71e52019-03-15 14:24:34 -07001285 compressed_certs_cache_, common_cert_sets_, client_common_set_hashes_,
1286 client_cached_cert_hashes_, sct_supported_by_client_, sni_, ok, chain,
1287 proof.signature, proof.leaf_cert_scts, std::move(details),
1288 std::move(message_), std::move(cb_));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001289}
1290
1291void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001292 QuicCompressedCertsCache* compressed_certs_cache,
1293 const CommonCertSets* common_cert_sets,
vasilvvc48c8712019-03-11 13:38:16 -07001294 const std::string& client_common_set_hashes,
1295 const std::string& client_cached_cert_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001296 bool sct_supported_by_client,
vasilvvc48c8712019-03-11 13:38:16 -07001297 const std::string& sni,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001298 bool ok,
1299 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
vasilvvc48c8712019-03-11 13:38:16 -07001300 const std::string& signature,
1301 const std::string& leaf_cert_sct,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001302 std::unique_ptr<ProofSource::Details> details,
1303 CryptoHandshakeMessage message,
1304 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
1305 if (!ok) {
1306 cb->Run(false, message);
1307 return;
1308 }
1309
vasilvvc48c8712019-03-11 13:38:16 -07001310 const std::string compressed =
QUICHE teama6ef0a62019-03-07 20:34:33 -05001311 CompressChain(compressed_certs_cache, chain, client_common_set_hashes,
1312 client_cached_cert_hashes, common_cert_sets);
1313
1314 message.SetStringPiece(kCertificateTag, compressed);
1315 message.SetStringPiece(kPROF, signature);
1316 if (sct_supported_by_client && enable_serving_sct_) {
1317 if (leaf_cert_sct.empty()) {
1318 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
1319 << "SCT is expected but it is empty. SNI: " << sni;
1320 } else {
1321 message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct);
1322 }
1323 }
1324
1325 cb->Run(true, message);
1326}
1327
QUICHE teamaa924f12019-03-21 11:26:21 -07001328void QuicCryptoServerConfig::BuildRejectionAndRecordStats(
1329 const ProcessClientHelloContext& context,
1330 const Config& config,
1331 const std::vector<uint32_t>& reject_reasons,
1332 CryptoHandshakeMessage* out) const {
1333 BuildRejection(context, config, reject_reasons, out);
1334 if (rejection_observer_ != nullptr) {
1335 rejection_observer_->OnRejectionBuilt(reject_reasons, out);
1336 }
1337}
1338
QUICHE teama6ef0a62019-03-07 20:34:33 -05001339void QuicCryptoServerConfig::BuildRejection(
QUICHE team4dae8412019-03-18 13:11:00 -07001340 const ProcessClientHelloContext& context,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001341 const Config& config,
QUICHE teame6dcf322019-03-19 12:23:47 -07001342 const std::vector<uint32_t>& reject_reasons,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001343 CryptoHandshakeMessage* out) const {
QUICHE team4dae8412019-03-18 13:11:00 -07001344 const QuicWallTime now = context.clock()->WallNow();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001345 if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) &&
QUICHE team4dae8412019-03-18 13:11:00 -07001346 context.use_stateless_rejects()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001347 QUIC_DVLOG(1) << "QUIC Crypto server config returning stateless reject "
1348 << "with server-designated connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -07001349 << context.server_designated_connection_id();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001350 out->set_tag(kSREJ);
vasilvvc48c8712019-03-11 13:38:16 -07001351 if (!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -07001352 context.server_designated_connection_id(),
1353 context.transport_version())) {
vasilvvc48c8712019-03-11 13:38:16 -07001354 QUIC_BUG << "Tried to send server designated connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -07001355 << context.server_designated_connection_id()
vasilvvc48c8712019-03-11 13:38:16 -07001356 << " which is invalid with version "
QUICHE team4dae8412019-03-18 13:11:00 -07001357 << QuicVersionToString(context.transport_version());
vasilvvc48c8712019-03-11 13:38:16 -07001358 return;
1359 }
1360 out->SetStringPiece(
QUICHE team4dae8412019-03-18 13:11:00 -07001361 kRCID,
1362 QuicStringPiece(context.server_designated_connection_id().data(),
1363 context.server_designated_connection_id().length()));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001364 } else {
1365 out->set_tag(kREJ);
1366 }
1367 out->SetStringPiece(kSCFG, config.serialized);
1368 out->SetStringPiece(
1369 kSourceAddressTokenTag,
QUICHE team4dae8412019-03-18 13:11:00 -07001370 NewSourceAddressToken(
1371 config, context.info().source_address_tokens,
1372 context.info().client_ip, context.rand(), context.info().now,
1373 &context.validate_chlo_result()->cached_network_params));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001374 out->SetValue(kSTTL, config.expiry_time.AbsoluteDifference(now).ToSeconds());
1375 if (replay_protection_) {
QUICHE team4dae8412019-03-18 13:11:00 -07001376 out->SetStringPiece(kServerNonceTag,
1377 NewServerNonce(context.rand(), context.info().now));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001378 }
1379
1380 // Send client the reject reason for debugging purposes.
QUICHE teame6dcf322019-03-19 12:23:47 -07001381 DCHECK_LT(0u, reject_reasons.size());
1382 out->SetVector(kRREJ, reject_reasons);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001383
1384 // The client may have requested a certificate chain.
QUICHE team4dae8412019-03-18 13:11:00 -07001385 if (!ClientDemandsX509Proof(context.client_hello())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001386 QUIC_BUG << "x509 certificates not supported in proof demand";
1387 return;
1388 }
1389
1390 QuicStringPiece client_common_set_hashes;
QUICHE team4dae8412019-03-18 13:11:00 -07001391 if (context.client_hello().GetStringPiece(kCCS, &client_common_set_hashes)) {
1392 context.params()->client_common_set_hashes =
1393 std::string(client_common_set_hashes);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001394 }
1395
1396 QuicStringPiece client_cached_cert_hashes;
QUICHE team4dae8412019-03-18 13:11:00 -07001397 if (context.client_hello().GetStringPiece(kCCRT,
1398 &client_cached_cert_hashes)) {
1399 context.params()->client_cached_cert_hashes =
1400 std::string(client_cached_cert_hashes);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001401 } else {
QUICHE team4dae8412019-03-18 13:11:00 -07001402 context.params()->client_cached_cert_hashes.clear();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001403 }
1404
QUICHE team4dae8412019-03-18 13:11:00 -07001405 const std::string compressed = CompressChain(
1406 context.compressed_certs_cache(), context.signed_config()->chain,
1407 context.params()->client_common_set_hashes,
1408 context.params()->client_cached_cert_hashes, config.common_cert_sets);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001409
QUICHE team4dae8412019-03-18 13:11:00 -07001410 DCHECK_GT(context.chlo_packet_size(), context.client_hello().size());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001411 // kREJOverheadBytes is a very rough estimate of how much of a REJ
1412 // message is taken up by things other than the certificates.
1413 // STK: 56 bytes
1414 // SNO: 56 bytes
1415 // SCFG
1416 // SCID: 16 bytes
1417 // PUBS: 38 bytes
1418 const size_t kREJOverheadBytes = 166;
1419 // max_unverified_size is the number of bytes that the certificate chain,
1420 // signature, and (optionally) signed certificate timestamp can consume before
1421 // we will demand a valid source-address token.
1422 const size_t max_unverified_size =
QUICHE team4dae8412019-03-18 13:11:00 -07001423 chlo_multiplier_ *
1424 (context.chlo_packet_size() - context.total_framing_overhead()) -
QUICHE teama6ef0a62019-03-07 20:34:33 -05001425 kREJOverheadBytes;
1426 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
1427 "overhead calculation may underflow");
1428 bool should_return_sct =
QUICHE team4dae8412019-03-18 13:11:00 -07001429 context.params()->sct_supported_by_client && enable_serving_sct_;
1430 const std::string& cert_sct = context.signed_config()->proof.leaf_cert_scts;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001431 const size_t sct_size = should_return_sct ? cert_sct.size() : 0;
QUICHE team4dae8412019-03-18 13:11:00 -07001432 const size_t total_size = context.signed_config()->proof.signature.size() +
1433 compressed.size() + sct_size;
1434 if (context.info().valid_source_address_token ||
1435 total_size < max_unverified_size) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001436 out->SetStringPiece(kCertificateTag, compressed);
QUICHE team4dae8412019-03-18 13:11:00 -07001437 out->SetStringPiece(kPROF, context.signed_config()->proof.signature);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001438 if (should_return_sct) {
1439 if (cert_sct.empty()) {
1440 if (!GetQuicReloadableFlag(quic_log_cert_name_for_empty_sct)) {
1441 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001442 << "SCT is expected but it is empty. sni :"
1443 << context.params()->sni;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001444 } else {
1445 // Log SNI and subject name for the leaf cert if its SCT is empty.
1446 // This is for debugging b/28342827.
QUICHE team4dae8412019-03-18 13:11:00 -07001447 const std::vector<std::string>& certs =
1448 context.signed_config()->chain->certs;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001449 QuicStringPiece ca_subject;
1450 if (!certs.empty()) {
1451 QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject);
1452 }
1453 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001454 << "SCT is expected but it is empty. sni: '"
1455 << context.params()->sni << "' cert subject: '" << ca_subject
1456 << "'";
QUICHE teama6ef0a62019-03-07 20:34:33 -05001457 }
1458 } else {
1459 out->SetStringPiece(kCertificateSCTTag, cert_sct);
1460 }
1461 }
1462 } else {
1463 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001464 << "Sending inchoate REJ for hostname: " << context.info().sni
1465 << " signature: " << context.signed_config()->proof.signature.size()
QUICHE teama6ef0a62019-03-07 20:34:33 -05001466 << " cert: " << compressed.size() << " sct:" << sct_size
1467 << " total: " << total_size << " max: " << max_unverified_size;
1468 }
1469}
1470
vasilvvc48c8712019-03-11 13:38:16 -07001471std::string QuicCryptoServerConfig::CompressChain(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001472 QuicCompressedCertsCache* compressed_certs_cache,
1473 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
vasilvvc48c8712019-03-11 13:38:16 -07001474 const std::string& client_common_set_hashes,
1475 const std::string& client_cached_cert_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001476 const CommonCertSets* common_sets) {
1477 // Check whether the compressed certs is available in the cache.
1478 DCHECK(compressed_certs_cache);
vasilvvc48c8712019-03-11 13:38:16 -07001479 const std::string* cached_value = compressed_certs_cache->GetCompressedCert(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001480 chain, client_common_set_hashes, client_cached_cert_hashes);
1481 if (cached_value) {
1482 return *cached_value;
1483 }
vasilvvc48c8712019-03-11 13:38:16 -07001484 std::string compressed =
QUICHE teama6ef0a62019-03-07 20:34:33 -05001485 CertCompressor::CompressChain(chain->certs, client_common_set_hashes,
1486 client_cached_cert_hashes, common_sets);
1487 // Insert the newly compressed cert to cache.
1488 compressed_certs_cache->Insert(chain, client_common_set_hashes,
1489 client_cached_cert_hashes, compressed);
1490 return compressed;
1491}
1492
1493QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
1494QuicCryptoServerConfig::ParseConfigProtobuf(
QUICHE teambbaa8be2019-03-21 12:54:17 -07001495 const QuicServerConfigProtobuf& protobuf) {
QUICHE teamfe1aca62019-03-14 13:39:01 -07001496 std::unique_ptr<CryptoHandshakeMessage> msg =
QUICHE teambbaa8be2019-03-21 12:54:17 -07001497 CryptoFramer::ParseMessage(protobuf.config());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001498
1499 if (msg->tag() != kSCFG) {
1500 QUIC_LOG(WARNING) << "Server config message has tag " << msg->tag()
1501 << " expected " << kSCFG;
1502 return nullptr;
1503 }
1504
1505 QuicReferenceCountedPointer<Config> config(new Config);
QUICHE teambbaa8be2019-03-21 12:54:17 -07001506 config->serialized = protobuf.config();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001507 config->source_address_token_boxer = &source_address_token_boxer_;
1508
QUICHE teambbaa8be2019-03-21 12:54:17 -07001509 if (protobuf.has_primary_time()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001510 config->primary_time =
QUICHE teambbaa8be2019-03-21 12:54:17 -07001511 QuicWallTime::FromUNIXSeconds(protobuf.primary_time());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001512 }
1513
QUICHE teambbaa8be2019-03-21 12:54:17 -07001514 config->priority = protobuf.priority();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001515
1516 QuicStringPiece scid;
1517 if (!msg->GetStringPiece(kSCID, &scid)) {
1518 QUIC_LOG(WARNING) << "Server config message is missing SCID";
1519 return nullptr;
1520 }
vasilvvc48c8712019-03-11 13:38:16 -07001521 config->id = std::string(scid);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001522
1523 if (msg->GetTaglist(kAEAD, &config->aead) != QUIC_NO_ERROR) {
1524 QUIC_LOG(WARNING) << "Server config message is missing AEAD";
1525 return nullptr;
1526 }
1527
1528 QuicTagVector kexs_tags;
1529 if (msg->GetTaglist(kKEXS, &kexs_tags) != QUIC_NO_ERROR) {
1530 QUIC_LOG(WARNING) << "Server config message is missing KEXS";
1531 return nullptr;
1532 }
1533
1534 QuicErrorCode err;
1535 if ((err = msg->GetTaglist(kTBKP, &config->tb_key_params)) !=
1536 QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND &&
1537 err != QUIC_NO_ERROR) {
1538 QUIC_LOG(WARNING) << "Server config message is missing or has invalid TBKP";
1539 return nullptr;
1540 }
1541
1542 QuicStringPiece orbit;
1543 if (!msg->GetStringPiece(kORBT, &orbit)) {
1544 QUIC_LOG(WARNING) << "Server config message is missing ORBT";
1545 return nullptr;
1546 }
1547
1548 if (orbit.size() != kOrbitSize) {
1549 QUIC_LOG(WARNING) << "Orbit value in server config is the wrong length."
1550 " Got "
1551 << orbit.size() << " want " << kOrbitSize;
1552 return nullptr;
1553 }
1554 static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size");
1555 memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
1556
QUICHE teambbaa8be2019-03-21 12:54:17 -07001557 if (kexs_tags.size() != static_cast<size_t>(protobuf.key_size())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001558 QUIC_LOG(WARNING) << "Server config has " << kexs_tags.size()
1559 << " key exchange methods configured, but "
QUICHE teambbaa8be2019-03-21 12:54:17 -07001560 << protobuf.key_size() << " private keys";
QUICHE teama6ef0a62019-03-07 20:34:33 -05001561 return nullptr;
1562 }
1563
1564 QuicTagVector proof_demand_tags;
1565 if (msg->GetTaglist(kPDMD, &proof_demand_tags) == QUIC_NO_ERROR) {
1566 for (QuicTag tag : proof_demand_tags) {
1567 if (tag == kCHID) {
1568 config->channel_id_enabled = true;
1569 break;
1570 }
1571 }
1572 }
1573
1574 for (size_t i = 0; i < kexs_tags.size(); i++) {
1575 const QuicTag tag = kexs_tags[i];
vasilvvc48c8712019-03-11 13:38:16 -07001576 std::string private_key;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001577
1578 config->kexs.push_back(tag);
1579
QUICHE teambbaa8be2019-03-21 12:54:17 -07001580 for (int j = 0; j < protobuf.key_size(); j++) {
1581 const QuicServerConfigProtobuf::PrivateKey& key = protobuf.key(i);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001582 if (key.tag() == tag) {
1583 private_key = key.private_key();
1584 break;
1585 }
1586 }
1587
QUICHE teamf03456c2019-03-21 08:54:47 -07001588 std::unique_ptr<AsynchronousKeyExchange> ka = key_exchange_source_->Create(
1589 config->id, /* is_fallback = */ false, tag, private_key);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001590 if (!ka) {
1591 return nullptr;
1592 }
1593 for (const auto& key_exchange : config->key_exchanges) {
QUICHE teamfe1aca62019-03-14 13:39:01 -07001594 if (key_exchange->type() == tag) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001595 QUIC_LOG(WARNING) << "Duplicate key exchange in config: " << tag;
1596 return nullptr;
1597 }
1598 }
1599
1600 config->key_exchanges.push_back(std::move(ka));
1601 }
1602
1603 uint64_t expiry_seconds;
1604 if (msg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
1605 QUIC_LOG(WARNING) << "Server config message is missing EXPY";
1606 return nullptr;
1607 }
1608 config->expiry_time = QuicWallTime::FromUNIXSeconds(expiry_seconds);
1609
1610 return config;
1611}
1612
1613void QuicCryptoServerConfig::set_replay_protection(bool on) {
1614 replay_protection_ = on;
1615}
1616
1617void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) {
1618 chlo_multiplier_ = multiplier;
1619}
1620
1621void QuicCryptoServerConfig::set_source_address_token_future_secs(
1622 uint32_t future_secs) {
1623 source_address_token_future_secs_ = future_secs;
1624}
1625
1626void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
1627 uint32_t lifetime_secs) {
1628 source_address_token_lifetime_secs_ = lifetime_secs;
1629}
1630
1631void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) {
1632 enable_serving_sct_ = enable_serving_sct;
1633}
1634
1635void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
1636 std::unique_ptr<PrimaryConfigChangedCallback> cb) {
1637 QuicWriterMutexLock locked(&configs_lock_);
1638 primary_config_changed_cb_ = std::move(cb);
1639}
1640
vasilvvc48c8712019-03-11 13:38:16 -07001641std::string QuicCryptoServerConfig::NewSourceAddressToken(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001642 const Config& config,
1643 const SourceAddressTokens& previous_tokens,
1644 const QuicIpAddress& ip,
1645 QuicRandom* rand,
1646 QuicWallTime now,
1647 const CachedNetworkParameters* cached_network_params) const {
1648 SourceAddressTokens source_address_tokens;
1649 SourceAddressToken* source_address_token = source_address_tokens.add_tokens();
1650 source_address_token->set_ip(ip.DualStacked().ToPackedString());
1651 source_address_token->set_timestamp(now.ToUNIXSeconds());
1652 if (cached_network_params != nullptr) {
1653 *(source_address_token->mutable_cached_network_parameters()) =
1654 *cached_network_params;
1655 }
1656
1657 // Append previous tokens.
1658 for (const SourceAddressToken& token : previous_tokens.tokens()) {
1659 if (source_address_tokens.tokens_size() > kMaxTokenAddresses) {
1660 break;
1661 }
1662
1663 if (token.ip() == source_address_token->ip()) {
1664 // It's for the same IP address.
1665 continue;
1666 }
1667
1668 if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) {
1669 continue;
1670 }
1671
1672 *(source_address_tokens.add_tokens()) = token;
1673 }
1674
1675 return config.source_address_token_boxer->Box(
1676 rand, source_address_tokens.SerializeAsString());
1677}
1678
1679int QuicCryptoServerConfig::NumberOfConfigs() const {
1680 QuicReaderMutexLock locked(&configs_lock_);
1681 return configs_.size();
1682}
1683
1684ProofSource* QuicCryptoServerConfig::proof_source() const {
1685 return proof_source_.get();
1686}
1687
1688SSL_CTX* QuicCryptoServerConfig::ssl_ctx() const {
1689 return ssl_ctx_.get();
1690}
1691
1692HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken(
1693 const Config& config,
1694 QuicStringPiece token,
1695 SourceAddressTokens* tokens) const {
vasilvvc48c8712019-03-11 13:38:16 -07001696 std::string storage;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001697 QuicStringPiece plaintext;
1698 if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) {
1699 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
1700 }
1701
1702 if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) {
1703 // Some clients might still be using the old source token format so
1704 // attempt to parse that format.
1705 // TODO(rch): remove this code once the new format is ubiquitous.
1706 SourceAddressToken token;
1707 if (!token.ParseFromArray(plaintext.data(), plaintext.size())) {
1708 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
1709 }
1710 *tokens->add_tokens() = token;
1711 }
1712
1713 return HANDSHAKE_OK;
1714}
1715
1716HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens(
1717 const SourceAddressTokens& source_address_tokens,
1718 const QuicIpAddress& ip,
1719 QuicWallTime now,
1720 CachedNetworkParameters* cached_network_params) const {
1721 HandshakeFailureReason reason =
1722 SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1723 for (const SourceAddressToken& token : source_address_tokens.tokens()) {
1724 reason = ValidateSingleSourceAddressToken(token, ip, now);
1725 if (reason == HANDSHAKE_OK) {
1726 if (token.has_cached_network_parameters()) {
1727 *cached_network_params = token.cached_network_parameters();
1728 }
1729 break;
1730 }
1731 }
1732 return reason;
1733}
1734
1735HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken(
1736 const SourceAddressToken& source_address_token,
1737 const QuicIpAddress& ip,
1738 QuicWallTime now) const {
1739 if (source_address_token.ip() != ip.DualStacked().ToPackedString()) {
1740 // It's for a different IP address.
1741 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1742 }
1743
1744 return ValidateSourceAddressTokenTimestamp(source_address_token, now);
1745}
1746
1747HandshakeFailureReason
1748QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp(
1749 const SourceAddressToken& source_address_token,
1750 QuicWallTime now) const {
1751 const QuicWallTime timestamp(
1752 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
1753 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
1754
1755 if (now.IsBefore(timestamp) &&
1756 delta.ToSeconds() > source_address_token_future_secs_) {
1757 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
1758 }
1759
1760 if (now.IsAfter(timestamp) &&
1761 delta.ToSeconds() > source_address_token_lifetime_secs_) {
1762 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
1763 }
1764
1765 return HANDSHAKE_OK;
1766}
1767
1768// kServerNoncePlaintextSize is the number of bytes in an unencrypted server
1769// nonce.
1770static const size_t kServerNoncePlaintextSize =
1771 4 /* timestamp */ + 20 /* random bytes */;
1772
vasilvvc48c8712019-03-11 13:38:16 -07001773std::string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
1774 QuicWallTime now) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001775 const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds());
1776
1777 uint8_t server_nonce[kServerNoncePlaintextSize];
1778 static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small");
1779 server_nonce[0] = static_cast<uint8_t>(timestamp >> 24);
1780 server_nonce[1] = static_cast<uint8_t>(timestamp >> 16);
1781 server_nonce[2] = static_cast<uint8_t>(timestamp >> 8);
1782 server_nonce[3] = static_cast<uint8_t>(timestamp);
1783 rand->RandBytes(&server_nonce[sizeof(timestamp)],
1784 sizeof(server_nonce) - sizeof(timestamp));
1785
1786 return server_nonce_boxer_.Box(
1787 rand, QuicStringPiece(reinterpret_cast<char*>(server_nonce),
1788 sizeof(server_nonce)));
1789}
1790
1791bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate(
1792 const CryptoHandshakeMessage& client_hello,
vasilvvc48c8712019-03-11 13:38:16 -07001793 const std::vector<std::string>& certs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001794 if (certs.empty()) {
1795 return false;
1796 }
1797
1798 uint64_t hash_from_client;
1799 if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) {
1800 return false;
1801 }
1802 return CryptoUtils::ComputeLeafCertHash(certs.at(0)) == hash_from_client;
1803}
1804
QUICHE teama6ef0a62019-03-07 20:34:33 -05001805bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const {
1806 if (GetQuicReloadableFlag(quic_fix_config_rotation)) {
1807 QUIC_RELOADABLE_FLAG_COUNT(quic_fix_config_rotation);
1808 return !next_config_promotion_time_.IsZero() &&
1809 !next_config_promotion_time_.IsAfter(now);
1810 }
1811 return !next_config_promotion_time_.IsZero() &&
1812 next_config_promotion_time_.IsAfter(now);
1813}
1814
1815QuicCryptoServerConfig::Config::Config()
1816 : channel_id_enabled(false),
1817 is_primary(false),
1818 primary_time(QuicWallTime::Zero()),
1819 expiry_time(QuicWallTime::Zero()),
1820 priority(0),
1821 source_address_token_boxer(nullptr) {}
1822
1823QuicCryptoServerConfig::Config::~Config() {}
1824
1825QuicSignedServerConfig::QuicSignedServerConfig() {}
1826QuicSignedServerConfig::~QuicSignedServerConfig() {}
1827
1828} // namespace quic