blob: 4dc34ffd13f80294e325a371fdd47b1d1e287d1f [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>
bnc463f2352019-10-10 04:49:34 -070011#include <utility>
QUICHE teama6ef0a62019-03-07 20:34:33 -050012
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "third_party/boringssl/src/include/openssl/sha.h"
14#include "third_party/boringssl/src/include/openssl/ssl.h"
15#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter.h"
16#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h"
17#include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h"
18#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h"
19#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h"
20#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
21#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
22#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
23#include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h"
24#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
25#include "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h"
26#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
QUICHE team3a72e2f2020-01-24 15:13:19 -080027#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050028#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
29#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
30#include "net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h"
31#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
QUICHE team3a72e2f2020-01-24 15:13:19 -080032#include "net/third_party/quiche/src/quic/core/crypto/server_proof_verifier.h"
nharper6ebe83b2019-06-13 17:43:52 -070033#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h"
dschinazi56fb53e2019-06-21 15:30:04 -070034#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config_proto.h"
35#include "net/third_party/quiche/src/quic/core/proto/source_address_token_proto.h"
vasilvv89713d02020-02-11 14:33:26 -080036#include "net/third_party/quiche/src/quic/core/quic_clock.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050037#include "net/third_party/quiche/src/quic/core/quic_packets.h"
38#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h"
39#include "net/third_party/quiche/src/quic/core/quic_types.h"
40#include "net/third_party/quiche/src/quic/core/quic_utils.h"
41#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
42#include "net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050043#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
44#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
45#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
46#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
47#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050048#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
dmcardle904ef182019-12-13 08:34:33 -080049#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
50#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050051
52namespace quic {
53
54namespace {
55
56// kMultiplier is the multiple of the CHLO message size that a REJ message
57// must stay under when the client doesn't present a valid source-address
58// token. This is used to protect QUIC from amplification attacks.
59// TODO(rch): Reduce this to 2 again once b/25933682 is fixed.
60const size_t kMultiplier = 3;
61
62const int kMaxTokenAddresses = 4;
63
vasilvvc48c8712019-03-11 13:38:16 -070064std::string DeriveSourceAddressTokenKey(
dmcardle904ef182019-12-13 08:34:33 -080065 quiche::QuicheStringPiece source_address_token_secret) {
66 QuicHKDF hkdf(
67 source_address_token_secret, quiche::QuicheStringPiece() /* no salt */,
68 "QUIC source address token key", CryptoSecretBoxer::GetKeySize(),
69 0 /* no fixed IV needed */, 0 /* no subkey secret */);
vasilvvc48c8712019-03-11 13:38:16 -070070 return std::string(hkdf.server_write_key());
QUICHE teama6ef0a62019-03-07 20:34:33 -050071}
72
73// Default source for creating KeyExchange objects.
74class DefaultKeyExchangeSource : public KeyExchangeSource {
75 public:
76 DefaultKeyExchangeSource() = default;
77 ~DefaultKeyExchangeSource() override = default;
78
QUICHE teamfe1aca62019-03-14 13:39:01 -070079 std::unique_ptr<AsynchronousKeyExchange> Create(
dschinazi17d42422019-06-18 16:35:07 -070080 std::string /*server_config_id*/,
QUICHE teamf03456c2019-03-21 08:54:47 -070081 bool /* is_fallback */,
QUICHE teamfe1aca62019-03-14 13:39:01 -070082 QuicTag type,
dmcardle904ef182019-12-13 08:34:33 -080083 quiche::QuicheStringPiece private_key) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -050084 if (private_key.empty()) {
85 QUIC_LOG(WARNING) << "Server config contains key exchange method without "
QUICHE teamfe1aca62019-03-14 13:39:01 -070086 "corresponding private key of type "
87 << QuicTagToString(type);
QUICHE teama6ef0a62019-03-07 20:34:33 -050088 return nullptr;
89 }
90
QUICHE teamfe1aca62019-03-14 13:39:01 -070091 std::unique_ptr<SynchronousKeyExchange> ka =
92 CreateLocalSynchronousKeyExchange(type, private_key);
93 if (!ka) {
94 QUIC_LOG(WARNING) << "Failed to create key exchange method of type "
95 << QuicTagToString(type);
QUICHE teama6ef0a62019-03-07 20:34:33 -050096 }
97 return ka;
98 }
99};
100
QUICHE teame29fcd62019-03-15 13:54:47 -0700101// Returns true if the PDMD field from the client hello demands an X509
102// certificate.
103bool ClientDemandsX509Proof(const CryptoHandshakeMessage& client_hello) {
104 QuicTagVector their_proof_demands;
105
106 if (client_hello.GetTaglist(kPDMD, &their_proof_demands) != QUIC_NO_ERROR) {
107 return false;
108 }
109
110 for (const QuicTag tag : their_proof_demands) {
111 if (tag == kX509) {
112 return true;
113 }
114 }
115 return false;
116}
117
QUICHE teama6ef0a62019-03-07 20:34:33 -0500118} // namespace
119
120// static
121std::unique_ptr<KeyExchangeSource> KeyExchangeSource::Default() {
vasilvv0fc587f2019-09-06 13:33:08 -0700122 return std::make_unique<DefaultKeyExchangeSource>();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500123}
124
125class ValidateClientHelloHelper {
126 public:
127 // Note: stores a pointer to a unique_ptr, and std::moves the unique_ptr when
128 // ValidationComplete is called.
129 ValidateClientHelloHelper(
130 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
131 result,
132 std::unique_ptr<ValidateClientHelloResultCallback>* done_cb)
133 : result_(std::move(result)), done_cb_(done_cb) {}
134 ValidateClientHelloHelper(const ValidateClientHelloHelper&) = delete;
135 ValidateClientHelloHelper& operator=(const ValidateClientHelloHelper&) =
136 delete;
137
138 ~ValidateClientHelloHelper() {
139 QUIC_BUG_IF(done_cb_ != nullptr)
140 << "Deleting ValidateClientHelloHelper with a pending callback.";
141 }
142
143 void ValidationComplete(
144 QuicErrorCode error_code,
145 const char* error_details,
146 std::unique_ptr<ProofSource::Details> proof_source_details) {
147 result_->error_code = error_code;
148 result_->error_details = error_details;
149 (*done_cb_)->Run(std::move(result_), std::move(proof_source_details));
150 DetachCallback();
151 }
152
153 void DetachCallback() {
154 QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached.";
155 done_cb_ = nullptr;
156 }
157
158 private:
159 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
160 result_;
161 std::unique_ptr<ValidateClientHelloResultCallback>* done_cb_;
162};
163
164// static
165const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
166
167ClientHelloInfo::ClientHelloInfo(const QuicIpAddress& in_client_ip,
168 QuicWallTime in_now)
169 : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {}
170
171ClientHelloInfo::ClientHelloInfo(const ClientHelloInfo& other) = default;
172
173ClientHelloInfo::~ClientHelloInfo() {}
174
175PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {}
176
177PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {}
178
179ValidateClientHelloResultCallback::Result::Result(
180 const CryptoHandshakeMessage& in_client_hello,
181 QuicIpAddress in_client_ip,
182 QuicWallTime in_now)
183 : client_hello(in_client_hello),
184 info(in_client_ip, in_now),
185 error_code(QUIC_NO_ERROR) {}
186
187ValidateClientHelloResultCallback::Result::~Result() {}
188
189ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {}
190
191ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {}
192
193ProcessClientHelloResultCallback::ProcessClientHelloResultCallback() {}
194
195ProcessClientHelloResultCallback::~ProcessClientHelloResultCallback() {}
196
197QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
198 : expiry_time(QuicWallTime::Zero()),
199 channel_id_enabled(false),
200 p256(false) {}
201
202QuicCryptoServerConfig::ConfigOptions::ConfigOptions(
203 const ConfigOptions& other) = default;
204
205QuicCryptoServerConfig::ConfigOptions::~ConfigOptions() {}
206
QUICHE team4dae8412019-03-18 13:11:00 -0700207QuicCryptoServerConfig::ProcessClientHelloContext::
208 ~ProcessClientHelloContext() {
209 if (done_cb_ != nullptr) {
nharperff86db32019-05-08 10:38:23 -0700210 QUIC_LOG(WARNING)
QUICHE team4dae8412019-03-18 13:11:00 -0700211 << "Deleting ProcessClientHelloContext with a pending callback.";
212 }
213}
214
215void QuicCryptoServerConfig::ProcessClientHelloContext::Fail(
216 QuicErrorCode error,
217 const std::string& error_details) {
218 done_cb_->Run(error, error_details, nullptr, nullptr, nullptr);
219 done_cb_ = nullptr;
220}
221
222void QuicCryptoServerConfig::ProcessClientHelloContext::Succeed(
223 std::unique_ptr<CryptoHandshakeMessage> message,
224 std::unique_ptr<DiversificationNonce> diversification_nonce,
225 std::unique_ptr<ProofSource::Details> proof_source_details) {
226 done_cb_->Run(QUIC_NO_ERROR, std::string(), std::move(message),
227 std::move(diversification_nonce),
228 std::move(proof_source_details));
229 done_cb_ = nullptr;
230}
231
QUICHE teama6ef0a62019-03-07 20:34:33 -0500232QuicCryptoServerConfig::QuicCryptoServerConfig(
dmcardle904ef182019-12-13 08:34:33 -0800233 quiche::QuicheStringPiece source_address_token_secret,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500234 QuicRandom* server_nonce_entropy,
235 std::unique_ptr<ProofSource> proof_source,
nharper6ebe83b2019-06-13 17:43:52 -0700236 std::unique_ptr<KeyExchangeSource> key_exchange_source)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500237 : replay_protection_(true),
238 chlo_multiplier_(kMultiplier),
239 configs_lock_(),
240 primary_config_(nullptr),
241 next_config_promotion_time_(QuicWallTime::Zero()),
242 proof_source_(std::move(proof_source)),
QUICHE team3a72e2f2020-01-24 15:13:19 -0800243 client_cert_mode_(ClientCertMode::kNone),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500244 key_exchange_source_(std::move(key_exchange_source)),
nharper1c06fd82019-06-24 14:33:34 -0700245 ssl_ctx_(TlsServerConnection::CreateSslCtx()),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500246 source_address_token_future_secs_(3600),
247 source_address_token_lifetime_secs_(86400),
248 enable_serving_sct_(false),
249 rejection_observer_(nullptr),
250 pad_rej_(true),
251 pad_shlo_(true),
252 validate_chlo_size_(true),
253 validate_source_address_token_(true) {
254 DCHECK(proof_source_.get());
255 source_address_token_boxer_.SetKeys(
256 {DeriveSourceAddressTokenKey(source_address_token_secret)});
257
258 // Generate a random key and orbit for server nonces.
259 server_nonce_entropy->RandBytes(server_nonce_orbit_,
260 sizeof(server_nonce_orbit_));
261 const size_t key_size = server_nonce_boxer_.GetKeySize();
262 std::unique_ptr<uint8_t[]> key_bytes(new uint8_t[key_size]);
263 server_nonce_entropy->RandBytes(key_bytes.get(), key_size);
264
265 server_nonce_boxer_.SetKeys(
vasilvvc48c8712019-03-11 13:38:16 -0700266 {std::string(reinterpret_cast<char*>(key_bytes.get()), key_size)});
QUICHE teama6ef0a62019-03-07 20:34:33 -0500267}
268
269QuicCryptoServerConfig::~QuicCryptoServerConfig() {}
270
271// static
QUICHE teambbaa8be2019-03-21 12:54:17 -0700272QuicServerConfigProtobuf QuicCryptoServerConfig::GenerateConfig(
273 QuicRandom* rand,
274 const QuicClock* clock,
275 const ConfigOptions& options) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500276 CryptoHandshakeMessage msg;
277
vasilvvc48c8712019-03-11 13:38:16 -0700278 const std::string curve25519_private_key =
QUICHE teama6ef0a62019-03-07 20:34:33 -0500279 Curve25519KeyExchange::NewPrivateKey(rand);
QUICHE teamfe1aca62019-03-14 13:39:01 -0700280 std::unique_ptr<Curve25519KeyExchange> curve25519 =
281 Curve25519KeyExchange::New(curve25519_private_key);
dmcardle904ef182019-12-13 08:34:33 -0800282 quiche::QuicheStringPiece curve25519_public_value =
283 curve25519->public_value();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500284
vasilvvc48c8712019-03-11 13:38:16 -0700285 std::string encoded_public_values;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500286 // First three bytes encode the length of the public value.
287 DCHECK_LT(curve25519_public_value.size(), (1U << 24));
288 encoded_public_values.push_back(
289 static_cast<char>(curve25519_public_value.size()));
290 encoded_public_values.push_back(
291 static_cast<char>(curve25519_public_value.size() >> 8));
292 encoded_public_values.push_back(
293 static_cast<char>(curve25519_public_value.size() >> 16));
294 encoded_public_values.append(curve25519_public_value.data(),
295 curve25519_public_value.size());
296
vasilvvc48c8712019-03-11 13:38:16 -0700297 std::string p256_private_key;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500298 if (options.p256) {
299 p256_private_key = P256KeyExchange::NewPrivateKey();
300 std::unique_ptr<P256KeyExchange> p256(
301 P256KeyExchange::New(p256_private_key));
dmcardle904ef182019-12-13 08:34:33 -0800302 quiche::QuicheStringPiece p256_public_value = p256->public_value();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500303
304 DCHECK_LT(p256_public_value.size(), (1U << 24));
305 encoded_public_values.push_back(
306 static_cast<char>(p256_public_value.size()));
307 encoded_public_values.push_back(
308 static_cast<char>(p256_public_value.size() >> 8));
309 encoded_public_values.push_back(
310 static_cast<char>(p256_public_value.size() >> 16));
311 encoded_public_values.append(p256_public_value.data(),
312 p256_public_value.size());
313 }
314
315 msg.set_tag(kSCFG);
316 if (options.p256) {
317 msg.SetVector(kKEXS, QuicTagVector{kC255, kP256});
318 } else {
319 msg.SetVector(kKEXS, QuicTagVector{kC255});
320 }
321 msg.SetVector(kAEAD, QuicTagVector{kAESG, kCC20});
322 msg.SetStringPiece(kPUBS, encoded_public_values);
323
324 if (options.expiry_time.IsZero()) {
325 const QuicWallTime now = clock->WallNow();
326 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds(
327 60 * 60 * 24 * 180 /* 180 days, ~six months */));
328 const uint64_t expiry_seconds = expiry.ToUNIXSeconds();
329 msg.SetValue(kEXPY, expiry_seconds);
330 } else {
331 msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds());
332 }
333
334 char orbit_bytes[kOrbitSize];
335 if (options.orbit.size() == sizeof(orbit_bytes)) {
336 memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes));
337 } else {
338 DCHECK(options.orbit.empty());
339 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
340 }
dmcardle904ef182019-12-13 08:34:33 -0800341 msg.SetStringPiece(
342 kORBT, quiche::QuicheStringPiece(orbit_bytes, sizeof(orbit_bytes)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500343
344 if (options.channel_id_enabled) {
345 msg.SetVector(kPDMD, QuicTagVector{kCHID});
346 }
347
QUICHE teama6ef0a62019-03-07 20:34:33 -0500348 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.");
dmcardle904ef182019-12-13 08:34:33 -0800359 msg.SetStringPiece(kSCID,
360 quiche::QuicheStringPiece(
361 reinterpret_cast<const char*>(scid_bytes), 16));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500362 } else {
363 msg.SetStringPiece(kSCID, options.id);
364 }
365 // Don't put new tags below this point. The SCID generation should hash over
366 // everything but itself and so extra tags should be added prior to the
367 // preceding if block.
368
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700369 std::unique_ptr<QuicData> serialized =
370 CryptoFramer::ConstructHandshakeMessage(msg);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500371
QUICHE teambbaa8be2019-03-21 12:54:17 -0700372 QuicServerConfigProtobuf config;
373 config.set_config(std::string(serialized->AsStringPiece()));
374 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config.add_key();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500375 curve25519_key->set_tag(kC255);
376 curve25519_key->set_private_key(curve25519_private_key);
377
378 if (options.p256) {
QUICHE teambbaa8be2019-03-21 12:54:17 -0700379 QuicServerConfigProtobuf::PrivateKey* p256_key = config.add_key();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500380 p256_key->set_tag(kP256);
381 p256_key->set_private_key(p256_private_key);
382 }
383
384 return config;
385}
386
QUICHE teamd5af58a2019-03-14 20:35:50 -0700387std::unique_ptr<CryptoHandshakeMessage> QuicCryptoServerConfig::AddConfig(
QUICHE teambbaa8be2019-03-21 12:54:17 -0700388 const QuicServerConfigProtobuf& protobuf,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500389 const QuicWallTime now) {
QUICHE teamd5af58a2019-03-14 20:35:50 -0700390 std::unique_ptr<CryptoHandshakeMessage> msg =
QUICHE teambbaa8be2019-03-21 12:54:17 -0700391 CryptoFramer::ParseMessage(protobuf.config());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500392
wub07a2b072019-10-24 11:23:20 -0700393 if (!msg) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394 QUIC_LOG(WARNING) << "Failed to parse server config message";
395 return nullptr;
396 }
397
QUICHE team99055cf2019-03-22 11:27:53 -0700398 QuicReferenceCountedPointer<Config> config =
399 ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
wub07a2b072019-10-24 11:23:20 -0700400 if (!config) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500401 QUIC_LOG(WARNING) << "Failed to parse server config message";
402 return nullptr;
403 }
404
405 {
406 QuicWriterMutexLock locked(&configs_lock_);
407 if (configs_.find(config->id) != configs_.end()) {
408 QUIC_LOG(WARNING) << "Failed to add config because another with the same "
409 "server config id already exists: "
dmcardle904ef182019-12-13 08:34:33 -0800410 << quiche::QuicheTextUtils::HexEncode(config->id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500411 return nullptr;
412 }
413
414 configs_[config->id] = config;
415 SelectNewPrimaryConfig(now);
416 DCHECK(primary_config_.get());
417 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
418 primary_config_.get());
419 }
420
QUICHE teamd5af58a2019-03-14 20:35:50 -0700421 return msg;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500422}
423
QUICHE teamd5af58a2019-03-14 20:35:50 -0700424std::unique_ptr<CryptoHandshakeMessage>
425QuicCryptoServerConfig::AddDefaultConfig(QuicRandom* rand,
426 const QuicClock* clock,
427 const ConfigOptions& options) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500428 return AddConfig(GenerateConfig(rand, clock, options), clock->WallNow());
429}
430
431bool QuicCryptoServerConfig::SetConfigs(
QUICHE teambbaa8be2019-03-21 12:54:17 -0700432 const std::vector<QuicServerConfigProtobuf>& protobufs,
QUICHE team99055cf2019-03-22 11:27:53 -0700433 const QuicServerConfigProtobuf* fallback_protobuf,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500434 const QuicWallTime now) {
435 std::vector<QuicReferenceCountedPointer<Config>> parsed_configs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500436 for (auto& protobuf : protobufs) {
QUICHE team99055cf2019-03-22 11:27:53 -0700437 QuicReferenceCountedPointer<Config> config =
438 ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500439 if (!config) {
QUICHE team78c2d5e2019-03-19 10:50:50 -0700440 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
441 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500442 }
443
444 parsed_configs.push_back(config);
445 }
446
QUICHE team99055cf2019-03-22 11:27:53 -0700447 QuicReferenceCountedPointer<Config> fallback_config;
448 if (fallback_protobuf != nullptr) {
449 fallback_config =
450 ParseConfigProtobuf(*fallback_protobuf, /* is_fallback = */ true);
451 if (!fallback_config) {
452 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
453 return false;
454 }
455 QUIC_LOG(INFO) << "Fallback config has scid "
dmcardle904ef182019-12-13 08:34:33 -0800456 << quiche::QuicheTextUtils::HexEncode(fallback_config->id);
QUICHE team99055cf2019-03-22 11:27:53 -0700457 parsed_configs.push_back(fallback_config);
458 } else {
459 QUIC_LOG(INFO) << "No fallback config provided";
460 }
461
QUICHE teama6ef0a62019-03-07 20:34:33 -0500462 if (parsed_configs.empty()) {
QUICHE team78c2d5e2019-03-19 10:50:50 -0700463 QUIC_LOG(WARNING)
464 << "Rejecting QUIC configs because new config list is empty.";
465 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500466 }
467
QUICHE team78c2d5e2019-03-19 10:50:50 -0700468 QUIC_LOG(INFO) << "Updating configs:";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500469
QUICHE team78c2d5e2019-03-19 10:50:50 -0700470 QuicWriterMutexLock locked(&configs_lock_);
471 ConfigMap new_configs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500472
QUICHE team78c2d5e2019-03-19 10:50:50 -0700473 for (const QuicReferenceCountedPointer<Config>& config : parsed_configs) {
474 auto it = configs_.find(config->id);
475 if (it != configs_.end()) {
dmcardle904ef182019-12-13 08:34:33 -0800476 QUIC_LOG(INFO)
477 << "Keeping scid: " << quiche::QuicheTextUtils::HexEncode(config->id)
478 << " orbit: "
479 << quiche::QuicheTextUtils::HexEncode(
480 reinterpret_cast<const char*>(config->orbit), kOrbitSize)
481 << " new primary_time " << config->primary_time.ToUNIXSeconds()
482 << " old primary_time " << it->second->primary_time.ToUNIXSeconds()
483 << " new priority " << config->priority << " old priority "
484 << it->second->priority;
QUICHE team78c2d5e2019-03-19 10:50:50 -0700485 // Update primary_time and priority.
486 it->second->primary_time = config->primary_time;
487 it->second->priority = config->priority;
488 new_configs.insert(*it);
489 } else {
dmcardle904ef182019-12-13 08:34:33 -0800490 QUIC_LOG(INFO) << "Adding scid: "
491 << quiche::QuicheTextUtils::HexEncode(config->id)
QUICHE team78c2d5e2019-03-19 10:50:50 -0700492 << " orbit: "
dmcardle904ef182019-12-13 08:34:33 -0800493 << quiche::QuicheTextUtils::HexEncode(
QUICHE team78c2d5e2019-03-19 10:50:50 -0700494 reinterpret_cast<const char*>(config->orbit),
495 kOrbitSize)
496 << " primary_time " << config->primary_time.ToUNIXSeconds()
497 << " priority " << config->priority;
498 new_configs.emplace(config->id, config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500499 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500500 }
501
QUICHE team78c2d5e2019-03-19 10:50:50 -0700502 configs_ = std::move(new_configs);
QUICHE team99055cf2019-03-22 11:27:53 -0700503 fallback_config_ = fallback_config;
QUICHE team78c2d5e2019-03-19 10:50:50 -0700504 SelectNewPrimaryConfig(now);
505 DCHECK(primary_config_.get());
506 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
507 primary_config_.get());
508
509 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500510}
511
512void QuicCryptoServerConfig::SetSourceAddressTokenKeys(
vasilvvc48c8712019-03-11 13:38:16 -0700513 const std::vector<std::string>& keys) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500514 source_address_token_boxer_.SetKeys(keys);
515}
516
517void QuicCryptoServerConfig::GetConfigIds(
vasilvvc48c8712019-03-11 13:38:16 -0700518 std::vector<std::string>* scids) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500519 QuicReaderMutexLock locked(&configs_lock_);
520 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
521 scids->push_back(it->first);
522 }
523}
524
525void QuicCryptoServerConfig::ValidateClientHello(
526 const CryptoHandshakeMessage& client_hello,
527 const QuicIpAddress& client_ip,
528 const QuicSocketAddress& server_address,
529 QuicTransportVersion version,
530 const QuicClock* clock,
531 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
532 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
533 const QuicWallTime now(clock->WallNow());
534
535 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result(
536 new ValidateClientHelloResultCallback::Result(client_hello, client_ip,
537 now));
538
dmcardle904ef182019-12-13 08:34:33 -0800539 quiche::QuicheStringPiece requested_scid;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500540 client_hello.GetStringPiece(kSCID, &requested_scid);
QUICHE team1225f472019-03-19 15:52:25 -0700541 Configs configs;
542 if (!GetCurrentConfigs(now, requested_scid,
543 /* old_primary_config = */ nullptr, &configs)) {
544 result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
545 result->error_details = "No configurations loaded";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500546 }
QUICHE team1225f472019-03-19 15:52:25 -0700547 signed_config->config = configs.primary;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500548
549 if (result->error_code == QUIC_NO_ERROR) {
550 // QUIC requires a new proof for each CHLO so clear any existing proof.
551 signed_config->chain = nullptr;
552 signed_config->proof.signature = "";
553 signed_config->proof.leaf_cert_scts = "";
QUICHE team1225f472019-03-19 15:52:25 -0700554 EvaluateClientHello(server_address, version, configs, result,
555 std::move(done_cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500556 } else {
557 done_cb->Run(result, /* details = */ nullptr);
558 }
559}
560
QUICHE teama6ef0a62019-03-07 20:34:33 -0500561class QuicCryptoServerConfig::ProcessClientHelloCallback
562 : public ProofSource::Callback {
563 public:
QUICHE team1225f472019-03-19 15:52:25 -0700564 ProcessClientHelloCallback(const QuicCryptoServerConfig* config,
565 std::unique_ptr<ProcessClientHelloContext> context,
566 const Configs& configs)
567 : config_(config), context_(std::move(context)), configs_(configs) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500568
569 void Run(bool ok,
570 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
571 const QuicCryptoProof& proof,
572 std::unique_ptr<ProofSource::Details> details) override {
573 if (ok) {
QUICHE team4dae8412019-03-18 13:11:00 -0700574 context_->signed_config()->chain = chain;
575 context_->signed_config()->proof = proof;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500576 }
QUICHE team1225f472019-03-19 15:52:25 -0700577 config_->ProcessClientHelloAfterGetProof(!ok, std::move(details),
578 std::move(context_), configs_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500579 }
580
581 private:
582 const QuicCryptoServerConfig* config_;
QUICHE team4dae8412019-03-18 13:11:00 -0700583 std::unique_ptr<ProcessClientHelloContext> context_;
QUICHE team1225f472019-03-19 15:52:25 -0700584 const Configs configs_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500585};
586
587class QuicCryptoServerConfig::ProcessClientHelloAfterGetProofCallback
QUICHE teamfe1aca62019-03-14 13:39:01 -0700588 : public AsynchronousKeyExchange::Callback {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500589 public:
590 ProcessClientHelloAfterGetProofCallback(
591 const QuicCryptoServerConfig* config,
592 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE teamfe1aca62019-03-14 13:39:01 -0700593 QuicTag key_exchange_type,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500594 std::unique_ptr<CryptoHandshakeMessage> out,
dmcardle904ef182019-12-13 08:34:33 -0800595 quiche::QuicheStringPiece public_value,
QUICHE team4dae8412019-03-18 13:11:00 -0700596 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700597 const Configs& configs)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500598 : config_(config),
599 proof_source_details_(std::move(proof_source_details)),
QUICHE teamfe1aca62019-03-14 13:39:01 -0700600 key_exchange_type_(key_exchange_type),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500601 out_(std::move(out)),
602 public_value_(public_value),
QUICHE team4dae8412019-03-18 13:11:00 -0700603 context_(std::move(context)),
QUICHE team1225f472019-03-19 15:52:25 -0700604 configs_(configs) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500605
606 void Run(bool ok) override {
607 config_->ProcessClientHelloAfterCalculateSharedKeys(
QUICHE teamfe1aca62019-03-14 13:39:01 -0700608 !ok, std::move(proof_source_details_), key_exchange_type_,
QUICHE team1225f472019-03-19 15:52:25 -0700609 std::move(out_), public_value_, std::move(context_), configs_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500610 }
611
612 private:
613 const QuicCryptoServerConfig* config_;
614 std::unique_ptr<ProofSource::Details> proof_source_details_;
QUICHE team99055cf2019-03-22 11:27:53 -0700615 const QuicTag key_exchange_type_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500616 std::unique_ptr<CryptoHandshakeMessage> out_;
QUICHE team99055cf2019-03-22 11:27:53 -0700617 const std::string public_value_;
QUICHE team4dae8412019-03-18 13:11:00 -0700618 std::unique_ptr<ProcessClientHelloContext> context_;
QUICHE team1225f472019-03-19 15:52:25 -0700619 const Configs configs_;
QUICHE team59882932019-03-27 11:02:17 -0700620 std::unique_ptr<ProcessClientHelloResultCallback> done_cb_;
621};
622
623class QuicCryptoServerConfig::SendRejectWithFallbackConfigCallback
624 : public ProofSource::Callback {
625 public:
626 SendRejectWithFallbackConfigCallback(
627 const QuicCryptoServerConfig* config,
628 std::unique_ptr<ProcessClientHelloContext> context,
629 QuicReferenceCountedPointer<Config> fallback_config)
630 : config_(config),
631 context_(std::move(context)),
632 fallback_config_(fallback_config) {}
633
634 // Capture |chain| and |proof| into the signed config, and then invoke
635 // SendRejectWithFallbackConfigAfterGetProof.
636 void Run(bool ok,
637 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
638 const QuicCryptoProof& proof,
639 std::unique_ptr<ProofSource::Details> details) override {
640 if (ok) {
641 context_->signed_config()->chain = chain;
642 context_->signed_config()->proof = proof;
643 }
644 config_->SendRejectWithFallbackConfigAfterGetProof(
645 !ok, std::move(details), std::move(context_), fallback_config_);
646 }
647
648 private:
649 const QuicCryptoServerConfig* config_;
650 std::unique_ptr<ProcessClientHelloContext> context_;
651 QuicReferenceCountedPointer<Config> fallback_config_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500652};
653
654void QuicCryptoServerConfig::ProcessClientHello(
655 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
656 validate_chlo_result,
657 bool reject_only,
658 QuicConnectionId connection_id,
659 const QuicSocketAddress& server_address,
660 const QuicSocketAddress& client_address,
661 ParsedQuicVersion version,
662 const ParsedQuicVersionVector& supported_versions,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500663 const QuicClock* clock,
664 QuicRandom* rand,
665 QuicCompressedCertsCache* compressed_certs_cache,
666 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,
667 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
668 QuicByteCount total_framing_overhead,
669 QuicByteCount chlo_packet_size,
670 std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
671 DCHECK(done_cb);
vasilvv0fc587f2019-09-06 13:33:08 -0700672 auto context = std::make_unique<ProcessClientHelloContext>(
QUICHE team4dae8412019-03-18 13:11:00 -0700673 validate_chlo_result, reject_only, connection_id, server_address,
wubecf9bd82019-06-05 04:57:02 -0700674 client_address, version, supported_versions, clock, rand,
675 compressed_certs_cache, params, signed_config, total_framing_overhead,
676 chlo_packet_size, std::move(done_cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500677
QUICHE team1225f472019-03-19 15:52:25 -0700678 // Verify that various parts of the CHLO are valid
vasilvvc48c8712019-03-11 13:38:16 -0700679 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500680 QuicErrorCode valid = CryptoUtils::ValidateClientHello(
QUICHE team4dae8412019-03-18 13:11:00 -0700681 context->client_hello(), context->version(),
682 context->supported_versions(), &error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500683 if (valid != QUIC_NO_ERROR) {
QUICHE team4dae8412019-03-18 13:11:00 -0700684 context->Fail(valid, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500685 return;
686 }
687
dmcardle904ef182019-12-13 08:34:33 -0800688 quiche::QuicheStringPiece requested_scid;
QUICHE team4dae8412019-03-18 13:11:00 -0700689 context->client_hello().GetStringPiece(kSCID, &requested_scid);
QUICHE team1225f472019-03-19 15:52:25 -0700690 Configs configs;
691 if (!GetCurrentConfigs(context->clock()->WallNow(), requested_scid,
692 signed_config->config, &configs)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700693 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "No configurations loaded");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500694 return;
695 }
696
QUICHE team4dae8412019-03-18 13:11:00 -0700697 if (context->validate_chlo_result()->error_code != QUIC_NO_ERROR) {
698 context->Fail(context->validate_chlo_result()->error_code,
699 context->validate_chlo_result()->error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500700 return;
701 }
702
QUICHE team4dae8412019-03-18 13:11:00 -0700703 if (!ClientDemandsX509Proof(context->client_hello())) {
704 context->Fail(QUIC_UNSUPPORTED_PROOF_DEMAND, "Missing or invalid PDMD");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500705 return;
706 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500707
708 // No need to get a new proof if one was already generated.
QUICHE team4dae8412019-03-18 13:11:00 -0700709 if (!context->signed_config()->chain) {
710 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
711 context->client_hello(), Perspective::IS_SERVER);
712 const QuicSocketAddress server_address = context->server_address();
713 const std::string sni = std::string(context->info().sni);
714 const QuicTransportVersion transport_version = context->transport_version();
715
vasilvv0fc587f2019-09-06 13:33:08 -0700716 auto cb = std::make_unique<ProcessClientHelloCallback>(
QUICHE team1225f472019-03-19 15:52:25 -0700717 this, std::move(context), configs);
QUICHE team84910bd2019-03-15 07:03:40 -0700718
719 DCHECK(proof_source_.get());
QUICHE team1225f472019-03-19 15:52:25 -0700720 proof_source_->GetProof(server_address, sni, configs.primary->serialized,
QUICHE team4dae8412019-03-18 13:11:00 -0700721 transport_version, chlo_hash, std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500722 return;
723 }
724
QUICHE teama6ef0a62019-03-07 20:34:33 -0500725 ProcessClientHelloAfterGetProof(
726 /* found_error = */ false, /* proof_source_details = */ nullptr,
QUICHE team1225f472019-03-19 15:52:25 -0700727 std::move(context), configs);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500728}
729
730void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
731 bool found_error,
732 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE team4dae8412019-03-18 13:11:00 -0700733 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700734 const Configs& configs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500735 QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -0700736 context->connection_id(), context->transport_version()))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500737 << "ProcessClientHelloAfterGetProof: attempted to use connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -0700738 << context->connection_id() << " which is invalid with version "
739 << QuicVersionToString(context->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500740
741 if (found_error) {
QUICHE team4dae8412019-03-18 13:11:00 -0700742 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500743 return;
744 }
745
vasilvv0fc587f2019-09-06 13:33:08 -0700746 auto out_diversification_nonce = std::make_unique<DiversificationNonce>();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500747
dmcardle904ef182019-12-13 08:34:33 -0800748 quiche::QuicheStringPiece cert_sct;
QUICHE team4dae8412019-03-18 13:11:00 -0700749 if (context->client_hello().GetStringPiece(kCertificateSCTTag, &cert_sct) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500750 cert_sct.empty()) {
QUICHE team4dae8412019-03-18 13:11:00 -0700751 context->params()->sct_supported_by_client = true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500752 }
753
vasilvv0fc587f2019-09-06 13:33:08 -0700754 auto out = std::make_unique<CryptoHandshakeMessage>();
QUICHE team1225f472019-03-19 15:52:25 -0700755 if (!context->info().reject_reasons.empty() || !configs.requested) {
QUICHE teamaa924f12019-03-21 11:26:21 -0700756 BuildRejectionAndRecordStats(*context, *configs.primary,
757 context->info().reject_reasons, out.get());
QUICHE team4dae8412019-03-18 13:11:00 -0700758 context->Succeed(std::move(out), std::move(out_diversification_nonce),
759 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500760 return;
761 }
762
QUICHE team4dae8412019-03-18 13:11:00 -0700763 if (context->reject_only()) {
764 context->Succeed(std::move(out), std::move(out_diversification_nonce),
765 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500766 return;
767 }
768
769 QuicTagVector their_aeads;
770 QuicTagVector their_key_exchanges;
QUICHE team4dae8412019-03-18 13:11:00 -0700771 if (context->client_hello().GetTaglist(kAEAD, &their_aeads) !=
772 QUIC_NO_ERROR ||
773 context->client_hello().GetTaglist(kKEXS, &their_key_exchanges) !=
774 QUIC_NO_ERROR ||
QUICHE teama6ef0a62019-03-07 20:34:33 -0500775 their_aeads.size() != 1 || their_key_exchanges.size() != 1) {
QUICHE team4dae8412019-03-18 13:11:00 -0700776 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
777 "Missing or invalid AEAD or KEXS");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500778 return;
779 }
780
781 size_t key_exchange_index;
QUICHE team1225f472019-03-19 15:52:25 -0700782 if (!FindMutualQuicTag(configs.requested->aead, their_aeads,
QUICHE team4dae8412019-03-18 13:11:00 -0700783 &context->params()->aead, nullptr) ||
QUICHE team1225f472019-03-19 15:52:25 -0700784 !FindMutualQuicTag(configs.requested->kexs, their_key_exchanges,
QUICHE team4dae8412019-03-18 13:11:00 -0700785 &context->params()->key_exchange,
786 &key_exchange_index)) {
787 context->Fail(QUIC_CRYPTO_NO_SUPPORT, "Unsupported AEAD or KEXS");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500788 return;
789 }
790
dmcardle904ef182019-12-13 08:34:33 -0800791 quiche::QuicheStringPiece public_value;
QUICHE team4dae8412019-03-18 13:11:00 -0700792 if (!context->client_hello().GetStringPiece(kPUBS, &public_value)) {
793 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
794 "Missing public value");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500795 return;
796 }
797
QUICHE teamfe1aca62019-03-14 13:39:01 -0700798 const AsynchronousKeyExchange* key_exchange =
QUICHE team1225f472019-03-19 15:52:25 -0700799 configs.requested->key_exchanges[key_exchange_index].get();
QUICHE team4dae8412019-03-18 13:11:00 -0700800 std::string* initial_premaster_secret =
801 &context->params()->initial_premaster_secret;
vasilvv0fc587f2019-09-06 13:33:08 -0700802 auto cb = std::make_unique<ProcessClientHelloAfterGetProofCallback>(
QUICHE teamfe1aca62019-03-14 13:39:01 -0700803 this, std::move(proof_source_details), key_exchange->type(),
QUICHE team1225f472019-03-19 15:52:25 -0700804 std::move(out), public_value, std::move(context), configs);
QUICHE team4dae8412019-03-18 13:11:00 -0700805 key_exchange->CalculateSharedKeyAsync(public_value, initial_premaster_secret,
806 std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500807}
808
809void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys(
810 bool found_error,
811 std::unique_ptr<ProofSource::Details> proof_source_details,
QUICHE teamfe1aca62019-03-14 13:39:01 -0700812 QuicTag key_exchange_type,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500813 std::unique_ptr<CryptoHandshakeMessage> out,
dmcardle904ef182019-12-13 08:34:33 -0800814 quiche::QuicheStringPiece public_value,
QUICHE team4dae8412019-03-18 13:11:00 -0700815 std::unique_ptr<ProcessClientHelloContext> context,
QUICHE team1225f472019-03-19 15:52:25 -0700816 const Configs& configs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500817 QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
QUICHE team4dae8412019-03-18 13:11:00 -0700818 context->connection_id(), context->transport_version()))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500819 << "ProcessClientHelloAfterCalculateSharedKeys:"
820 " attempted to use connection ID "
QUICHE team4dae8412019-03-18 13:11:00 -0700821 << context->connection_id() << " which is invalid with version "
822 << QuicVersionToString(context->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500823
824 if (found_error) {
QUICHE team59882932019-03-27 11:02:17 -0700825 // If we are already using the fallback config, just bail out of the
826 // handshake.
827 if (context->signed_config()->config == configs.fallback ||
828 !GetQuicReloadableFlag(
829 send_quic_fallback_server_config_on_leto_error)) {
830 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
831 "Failed to calculate shared key");
832 } else {
833 SendRejectWithFallbackConfig(std::move(context), configs.fallback);
834 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500835 return;
836 }
837
QUICHE team4dae8412019-03-18 13:11:00 -0700838 if (!context->info().sni.empty()) {
839 context->params()->sni =
840 QuicHostnameUtils::NormalizeHostname(context->info().sni);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500841 }
842
vasilvvc48c8712019-03-11 13:38:16 -0700843 std::string hkdf_suffix;
QUICHE team4dae8412019-03-18 13:11:00 -0700844 const QuicData& client_hello_serialized =
845 context->client_hello().GetSerialized();
846 hkdf_suffix.reserve(context->connection_id().length() +
vasilvvc48c8712019-03-11 13:38:16 -0700847 client_hello_serialized.length() +
QUICHE team1225f472019-03-19 15:52:25 -0700848 configs.requested->serialized.size());
QUICHE team4dae8412019-03-18 13:11:00 -0700849 hkdf_suffix.append(context->connection_id().data(),
850 context->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500851 hkdf_suffix.append(client_hello_serialized.data(),
852 client_hello_serialized.length());
QUICHE team1225f472019-03-19 15:52:25 -0700853 hkdf_suffix.append(configs.requested->serialized);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500854 DCHECK(proof_source_.get());
QUICHE team4dae8412019-03-18 13:11:00 -0700855 if (context->signed_config()->chain->certs.empty()) {
856 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "Failed to get certs");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500857 return;
858 }
QUICHE team4dae8412019-03-18 13:11:00 -0700859 hkdf_suffix.append(context->signed_config()->chain->certs.at(0));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500860
dmcardle904ef182019-12-13 08:34:33 -0800861 quiche::QuicheStringPiece cetv_ciphertext;
QUICHE team1225f472019-03-19 15:52:25 -0700862 if (configs.requested->channel_id_enabled &&
QUICHE team4dae8412019-03-18 13:11:00 -0700863 context->client_hello().GetStringPiece(kCETV, &cetv_ciphertext)) {
864 CryptoHandshakeMessage client_hello_copy(context->client_hello());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500865 client_hello_copy.Erase(kCETV);
866 client_hello_copy.Erase(kPAD);
867
868 const QuicData& client_hello_copy_serialized =
869 client_hello_copy.GetSerialized();
vasilvvc48c8712019-03-11 13:38:16 -0700870 std::string hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500871 hkdf_input.append(QuicCryptoConfig::kCETVLabel,
872 strlen(QuicCryptoConfig::kCETVLabel) + 1);
QUICHE team4dae8412019-03-18 13:11:00 -0700873 hkdf_input.append(context->connection_id().data(),
874 context->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500875 hkdf_input.append(client_hello_copy_serialized.data(),
876 client_hello_copy_serialized.length());
QUICHE team1225f472019-03-19 15:52:25 -0700877 hkdf_input.append(configs.requested->serialized);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500878
879 CrypterPair crypters;
880 if (!CryptoUtils::DeriveKeys(
nharperc1bbfe62019-09-27 16:48:40 -0700881 context->version(), context->params()->initial_premaster_secret,
QUICHE team4dae8412019-03-18 13:11:00 -0700882 context->params()->aead, context->info().client_nonce,
883 context->info().server_nonce, pre_shared_key_, hkdf_input,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500884 Perspective::IS_SERVER, CryptoUtils::Diversification::Never(),
885 &crypters, nullptr /* subkey secret */)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700886 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
887 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500888 return;
889 }
890
dschinazi66dea072019-04-09 11:41:06 -0700891 char plaintext[kMaxOutgoingPacketSize];
QUICHE teama6ef0a62019-03-07 20:34:33 -0500892 size_t plaintext_length = 0;
893 const bool success = crypters.decrypter->DecryptPacket(
dmcardle904ef182019-12-13 08:34:33 -0800894 0 /* packet number */,
895 quiche::QuicheStringPiece() /* associated data */, cetv_ciphertext,
896 plaintext, &plaintext_length, kMaxOutgoingPacketSize);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500897 if (!success) {
QUICHE team4dae8412019-03-18 13:11:00 -0700898 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
899 "CETV decryption failure");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500900 return;
901 }
902 std::unique_ptr<CryptoHandshakeMessage> cetv(CryptoFramer::ParseMessage(
dmcardle904ef182019-12-13 08:34:33 -0800903 quiche::QuicheStringPiece(plaintext, plaintext_length)));
wub07a2b072019-10-24 11:23:20 -0700904 if (!cetv) {
QUICHE team4dae8412019-03-18 13:11:00 -0700905 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV parse error");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500906 return;
907 }
908
dmcardle904ef182019-12-13 08:34:33 -0800909 quiche::QuicheStringPiece key, signature;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500910 if (cetv->GetStringPiece(kCIDK, &key) &&
911 cetv->GetStringPiece(kCIDS, &signature)) {
912 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) {
QUICHE team4dae8412019-03-18 13:11:00 -0700913 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
914 "ChannelID signature failure");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500915 return;
916 }
917
QUICHE team4dae8412019-03-18 13:11:00 -0700918 context->params()->channel_id = std::string(key);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500919 }
920 }
921
vasilvvc48c8712019-03-11 13:38:16 -0700922 std::string hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500923 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
924 hkdf_input.reserve(label_len + hkdf_suffix.size());
925 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
926 hkdf_input.append(hkdf_suffix);
927
vasilvv0fc587f2019-09-06 13:33:08 -0700928 auto out_diversification_nonce = std::make_unique<DiversificationNonce>();
QUICHE team4dae8412019-03-18 13:11:00 -0700929 context->rand()->RandBytes(out_diversification_nonce->data(),
930 out_diversification_nonce->size());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500931 CryptoUtils::Diversification diversification =
932 CryptoUtils::Diversification::Now(out_diversification_nonce.get());
933 if (!CryptoUtils::DeriveKeys(
nharperc1bbfe62019-09-27 16:48:40 -0700934 context->version(), context->params()->initial_premaster_secret,
935 context->params()->aead, context->info().client_nonce,
936 context->info().server_nonce, pre_shared_key_, hkdf_input,
937 Perspective::IS_SERVER, diversification,
QUICHE team4dae8412019-03-18 13:11:00 -0700938 &context->params()->initial_crypters,
939 &context->params()->initial_subkey_secret)) {
940 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
941 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500942 return;
943 }
944
vasilvvc48c8712019-03-11 13:38:16 -0700945 std::string forward_secure_public_value;
QUICHE teamfe1aca62019-03-14 13:39:01 -0700946 std::unique_ptr<SynchronousKeyExchange> forward_secure_key_exchange =
QUICHE team4dae8412019-03-18 13:11:00 -0700947 CreateLocalSynchronousKeyExchange(key_exchange_type, context->rand());
QUICHE teamfe1aca62019-03-14 13:39:01 -0700948 if (!forward_secure_key_exchange) {
949 QUIC_DLOG(WARNING) << "Failed to create keypair";
QUICHE team4dae8412019-03-18 13:11:00 -0700950 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
951 "Failed to create keypair");
QUICHE teamfe1aca62019-03-14 13:39:01 -0700952 return;
953 }
954
QUICHE teama6ef0a62019-03-07 20:34:33 -0500955 forward_secure_public_value =
vasilvvc48c8712019-03-11 13:38:16 -0700956 std::string(forward_secure_key_exchange->public_value());
QUICHE teamfe1aca62019-03-14 13:39:01 -0700957 if (!forward_secure_key_exchange->CalculateSharedKeySync(
QUICHE team4dae8412019-03-18 13:11:00 -0700958 public_value, &context->params()->forward_secure_premaster_secret)) {
959 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
960 "Invalid public value");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500961 return;
962 }
963
vasilvvc48c8712019-03-11 13:38:16 -0700964 std::string forward_secure_hkdf_input;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500965 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
966 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
967 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
968 label_len);
969 forward_secure_hkdf_input.append(hkdf_suffix);
970
vasilvvc48c8712019-03-11 13:38:16 -0700971 std::string shlo_nonce;
QUICHE team4dae8412019-03-18 13:11:00 -0700972 shlo_nonce = NewServerNonce(context->rand(), context->info().now);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500973 out->SetStringPiece(kServerNonceTag, shlo_nonce);
974
975 if (!CryptoUtils::DeriveKeys(
nharperc1bbfe62019-09-27 16:48:40 -0700976 context->version(),
QUICHE team4dae8412019-03-18 13:11:00 -0700977 context->params()->forward_secure_premaster_secret,
978 context->params()->aead, context->info().client_nonce,
979 shlo_nonce.empty() ? context->info().server_nonce : shlo_nonce,
980 pre_shared_key_, forward_secure_hkdf_input, Perspective::IS_SERVER,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500981 CryptoUtils::Diversification::Never(),
QUICHE team4dae8412019-03-18 13:11:00 -0700982 &context->params()->forward_secure_crypters,
983 &context->params()->subkey_secret)) {
984 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
985 "Symmetric key setup failed");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500986 return;
987 }
988
989 out->set_tag(kSHLO);
QUICHE team4dae8412019-03-18 13:11:00 -0700990 out->SetVersionVector(kVER, context->supported_versions());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500991 out->SetStringPiece(
992 kSourceAddressTokenTag,
QUICHE team1225f472019-03-19 15:52:25 -0700993 NewSourceAddressToken(*configs.requested,
QUICHE team4dae8412019-03-18 13:11:00 -0700994 context->info().source_address_tokens,
995 context->client_address().host(), context->rand(),
996 context->info().now, nullptr));
997 QuicSocketAddressCoder address_coder(context->client_address());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500998 out->SetStringPiece(kCADR, address_coder.Encode());
999 out->SetStringPiece(kPUBS, forward_secure_public_value);
1000
QUICHE team4dae8412019-03-18 13:11:00 -07001001 context->Succeed(std::move(out), std::move(out_diversification_nonce),
1002 std::move(proof_source_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001003}
1004
QUICHE team59882932019-03-27 11:02:17 -07001005void QuicCryptoServerConfig::SendRejectWithFallbackConfig(
1006 std::unique_ptr<ProcessClientHelloContext> context,
1007 QuicReferenceCountedPointer<Config> fallback_config) const {
1008 // We failed to calculate a shared initial key, likely because we tried to use
1009 // a remote key-exchange service which could not be reached. We want to send
1010 // a REJ which tells the client to use a different ServerConfig which
1011 // corresponds to a local keypair. To generate the REJ we need to request a
1012 // new proof.
1013 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
1014 context->client_hello(), Perspective::IS_SERVER);
1015 const QuicSocketAddress server_address = context->server_address();
1016 const std::string sni(context->info().sni);
1017 const QuicTransportVersion transport_version = context->transport_version();
1018
vasilvv0fc587f2019-09-06 13:33:08 -07001019 auto cb = std::make_unique<SendRejectWithFallbackConfigCallback>(
QUICHE team59882932019-03-27 11:02:17 -07001020 this, std::move(context), fallback_config);
1021 proof_source_->GetProof(server_address, sni, fallback_config->serialized,
1022 transport_version, chlo_hash, std::move(cb));
1023}
1024
1025void QuicCryptoServerConfig::SendRejectWithFallbackConfigAfterGetProof(
1026 bool found_error,
1027 std::unique_ptr<ProofSource::Details> proof_source_details,
1028 std::unique_ptr<ProcessClientHelloContext> context,
1029 QuicReferenceCountedPointer<Config> fallback_config) const {
1030 if (found_error) {
1031 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
1032 return;
1033 }
1034
vasilvv0fc587f2019-09-06 13:33:08 -07001035 auto out = std::make_unique<CryptoHandshakeMessage>();
QUICHE team59882932019-03-27 11:02:17 -07001036 BuildRejectionAndRecordStats(*context, *fallback_config,
1037 {SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE},
1038 out.get());
1039
vasilvv0fc587f2019-09-06 13:33:08 -07001040 context->Succeed(std::move(out), std::make_unique<DiversificationNonce>(),
QUICHE team59882932019-03-27 11:02:17 -07001041 std::move(proof_source_details));
1042}
1043
QUICHE teama6ef0a62019-03-07 20:34:33 -05001044QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
1045QuicCryptoServerConfig::GetConfigWithScid(
dmcardle904ef182019-12-13 08:34:33 -08001046 quiche::QuicheStringPiece requested_scid) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001047 configs_lock_.AssertReaderHeld();
1048
1049 if (!requested_scid.empty()) {
vasilvvc48c8712019-03-11 13:38:16 -07001050 auto it = configs_.find((std::string(requested_scid)));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001051 if (it != configs_.end()) {
1052 // We'll use the config that the client requested in order to do
1053 // key-agreement.
1054 return QuicReferenceCountedPointer<Config>(it->second);
1055 }
1056 }
1057
1058 return QuicReferenceCountedPointer<Config>();
1059}
1060
QUICHE team1225f472019-03-19 15:52:25 -07001061bool QuicCryptoServerConfig::GetCurrentConfigs(
1062 const QuicWallTime& now,
dmcardle904ef182019-12-13 08:34:33 -08001063 quiche::QuicheStringPiece requested_scid,
QUICHE team1225f472019-03-19 15:52:25 -07001064 QuicReferenceCountedPointer<Config> old_primary_config,
1065 Configs* configs) const {
1066 QuicReaderMutexLock locked(&configs_lock_);
1067
1068 if (!primary_config_) {
1069 return false;
1070 }
1071
1072 if (IsNextConfigReady(now)) {
1073 configs_lock_.ReaderUnlock();
1074 configs_lock_.WriterLock();
1075 SelectNewPrimaryConfig(now);
1076 DCHECK(primary_config_.get());
1077 DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
1078 primary_config_.get());
1079 configs_lock_.WriterUnlock();
1080 configs_lock_.ReaderLock();
1081 }
1082
1083 if (old_primary_config != nullptr) {
1084 configs->primary = old_primary_config;
1085 } else {
1086 configs->primary = primary_config_;
1087 }
1088 configs->requested = GetConfigWithScid(requested_scid);
QUICHE team99055cf2019-03-22 11:27:53 -07001089 configs->fallback = fallback_config_;
QUICHE team1225f472019-03-19 15:52:25 -07001090
1091 return true;
1092}
1093
QUICHE teama6ef0a62019-03-07 20:34:33 -05001094// ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
1095// Config's based on their primary_time.
1096// static
1097bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
1098 const QuicReferenceCountedPointer<Config>& a,
1099 const QuicReferenceCountedPointer<Config>& b) {
1100 if (a->primary_time.IsBefore(b->primary_time) ||
1101 b->primary_time.IsBefore(a->primary_time)) {
1102 // Primary times differ.
1103 return a->primary_time.IsBefore(b->primary_time);
1104 } else if (a->priority != b->priority) {
1105 // Primary times are equal, sort backwards by priority.
1106 return a->priority < b->priority;
1107 } else {
1108 // Primary times and priorities are equal, sort by config id.
1109 return a->id < b->id;
1110 }
1111}
1112
1113void QuicCryptoServerConfig::SelectNewPrimaryConfig(
1114 const QuicWallTime now) const {
1115 std::vector<QuicReferenceCountedPointer<Config>> configs;
1116 configs.reserve(configs_.size());
1117
1118 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
1119 // TODO(avd) Exclude expired configs?
1120 configs.push_back(it->second);
1121 }
1122
1123 if (configs.empty()) {
1124 if (primary_config_ != nullptr) {
1125 QUIC_BUG << "No valid QUIC server config. Keeping the current config.";
1126 } else {
1127 QUIC_BUG << "No valid QUIC server config.";
1128 }
1129 return;
1130 }
1131
1132 std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan);
1133
1134 QuicReferenceCountedPointer<Config> best_candidate = configs[0];
1135
1136 for (size_t i = 0; i < configs.size(); ++i) {
1137 const QuicReferenceCountedPointer<Config> config(configs[i]);
1138 if (!config->primary_time.IsAfter(now)) {
1139 if (config->primary_time.IsAfter(best_candidate->primary_time)) {
1140 best_candidate = config;
1141 }
1142 continue;
1143 }
1144
1145 // This is the first config with a primary_time in the future. Thus the
1146 // previous Config should be the primary and this one should determine the
1147 // next_config_promotion_time_.
1148 QuicReferenceCountedPointer<Config> new_primary = best_candidate;
1149 if (i == 0) {
1150 // We need the primary_time of the next config.
1151 if (configs.size() > 1) {
1152 next_config_promotion_time_ = configs[1]->primary_time;
1153 } else {
1154 next_config_promotion_time_ = QuicWallTime::Zero();
1155 }
1156 } else {
1157 next_config_promotion_time_ = config->primary_time;
1158 }
1159
1160 if (primary_config_) {
1161 primary_config_->is_primary = false;
1162 }
1163 primary_config_ = new_primary;
1164 new_primary->is_primary = true;
1165 QUIC_DLOG(INFO) << "New primary config. orbit: "
dmcardle904ef182019-12-13 08:34:33 -08001166 << quiche::QuicheTextUtils::HexEncode(
1167 reinterpret_cast<const char*>(
1168 primary_config_->orbit),
1169 kOrbitSize);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001170 if (primary_config_changed_cb_ != nullptr) {
1171 primary_config_changed_cb_->Run(primary_config_->id);
1172 }
1173
1174 return;
1175 }
1176
1177 // All config's primary times are in the past. We should make the most recent
1178 // and highest priority candidate primary.
1179 QuicReferenceCountedPointer<Config> new_primary = best_candidate;
1180 if (primary_config_) {
1181 primary_config_->is_primary = false;
1182 }
1183 primary_config_ = new_primary;
1184 new_primary->is_primary = true;
1185 QUIC_DLOG(INFO) << "New primary config. orbit: "
dmcardle904ef182019-12-13 08:34:33 -08001186 << quiche::QuicheTextUtils::HexEncode(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001187 reinterpret_cast<const char*>(primary_config_->orbit),
1188 kOrbitSize)
dmcardle904ef182019-12-13 08:34:33 -08001189 << " scid: "
1190 << quiche::QuicheTextUtils::HexEncode(primary_config_->id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001191 next_config_promotion_time_ = QuicWallTime::Zero();
1192 if (primary_config_changed_cb_ != nullptr) {
1193 primary_config_changed_cb_->Run(primary_config_->id);
1194 }
1195}
1196
QUICHE teama6ef0a62019-03-07 20:34:33 -05001197void QuicCryptoServerConfig::EvaluateClientHello(
1198 const QuicSocketAddress& server_address,
dschinazi17d42422019-06-18 16:35:07 -07001199 QuicTransportVersion /*version*/,
QUICHE team1225f472019-03-19 15:52:25 -07001200 const Configs& configs,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001201 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
1202 client_hello_state,
1203 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001204 ValidateClientHelloHelper helper(client_hello_state, &done_cb);
1205
1206 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
1207 ClientHelloInfo* info = &(client_hello_state->info);
1208
1209 if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) {
1210 helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
1211 "Client hello too small", nullptr);
1212 return;
1213 }
1214
1215 if (client_hello.GetStringPiece(kSNI, &info->sni) &&
1216 !QuicHostnameUtils::IsValidSNI(info->sni)) {
1217 helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
1218 "Invalid SNI name", nullptr);
1219 return;
1220 }
1221
1222 client_hello.GetStringPiece(kUAID, &info->user_agent_id);
1223
1224 HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
1225 if (validate_source_address_token_) {
dmcardle904ef182019-12-13 08:34:33 -08001226 quiche::QuicheStringPiece srct;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001227 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
1228 Config& config =
QUICHE team1225f472019-03-19 15:52:25 -07001229 configs.requested != nullptr ? *configs.requested : *configs.primary;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001230 source_address_token_error =
1231 ParseSourceAddressToken(config, srct, &info->source_address_tokens);
1232
1233 if (source_address_token_error == HANDSHAKE_OK) {
1234 source_address_token_error = ValidateSourceAddressTokens(
1235 info->source_address_tokens, info->client_ip, info->now,
1236 &client_hello_state->cached_network_params);
1237 }
1238 info->valid_source_address_token =
1239 (source_address_token_error == HANDSHAKE_OK);
1240 } else {
1241 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
1242 }
1243 } else {
1244 source_address_token_error = HANDSHAKE_OK;
1245 info->valid_source_address_token = true;
1246 }
1247
QUICHE team1225f472019-03-19 15:52:25 -07001248 if (!configs.requested) {
dmcardle904ef182019-12-13 08:34:33 -08001249 quiche::QuicheStringPiece requested_scid;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001250 if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
1251 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1252 } else {
1253 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1254 }
1255 // No server config with the requested ID.
1256 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1257 return;
1258 }
1259
1260 if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) {
1261 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1262 // Report no client nonce as INCHOATE_HELLO_FAILURE.
1263 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1264 return;
1265 }
1266
1267 if (source_address_token_error != HANDSHAKE_OK) {
1268 info->reject_reasons.push_back(source_address_token_error);
1269 // No valid source address token.
1270 }
1271
1272 QuicReferenceCountedPointer<ProofSource::Chain> chain =
vasilvvc48c8712019-03-11 13:38:16 -07001273 proof_source_->GetCertChain(server_address, std::string(info->sni));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001274 if (!chain) {
1275 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1276 } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) {
1277 info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
1278 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001279
1280 if (info->client_nonce.size() != kNonceSize) {
1281 info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
1282 // Invalid client nonce.
1283 QUIC_LOG_FIRST_N(ERROR, 2)
1284 << "Invalid client nonce: " << client_hello.DebugString();
1285 QUIC_DLOG(INFO) << "Invalid client nonce.";
1286 }
1287
1288 // Server nonce is optional, and used for key derivation if present.
1289 client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
1290
QUICHE teama6ef0a62019-03-07 20:34:33 -05001291 // If the server nonce is empty and we're requiring handshake confirmation
1292 // for DoS reasons then we must reject the CHLO.
1293 if (GetQuicReloadableFlag(quic_require_handshake_confirmation) &&
1294 info->server_nonce.empty()) {
1295 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
1296 }
QUICHE team79fb9e22019-03-15 07:49:56 -07001297 helper.ValidationComplete(QUIC_NO_ERROR, "",
1298 std::unique_ptr<ProofSource::Details>());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001299}
1300
1301void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
1302 QuicTransportVersion version,
dmcardle904ef182019-12-13 08:34:33 -08001303 quiche::QuicheStringPiece chlo_hash,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001304 const SourceAddressTokens& previous_source_address_tokens,
1305 const QuicSocketAddress& server_address,
1306 const QuicIpAddress& client_ip,
1307 const QuicClock* clock,
1308 QuicRandom* rand,
1309 QuicCompressedCertsCache* compressed_certs_cache,
1310 const QuicCryptoNegotiatedParameters& params,
1311 const CachedNetworkParameters* cached_network_params,
1312 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
vasilvvc48c8712019-03-11 13:38:16 -07001313 std::string serialized;
1314 std::string source_address_token;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001315 const CommonCertSets* common_cert_sets;
1316 {
1317 QuicReaderMutexLock locked(&configs_lock_);
1318 serialized = primary_config_->serialized;
1319 common_cert_sets = primary_config_->common_cert_sets;
1320 source_address_token = NewSourceAddressToken(
1321 *primary_config_, previous_source_address_tokens, client_ip, rand,
1322 clock->WallNow(), cached_network_params);
1323 }
1324
1325 CryptoHandshakeMessage message;
1326 message.set_tag(kSCUP);
1327 message.SetStringPiece(kSCFG, serialized);
1328 message.SetStringPiece(kSourceAddressTokenTag, source_address_token);
1329
QUICHE teamea5bdef2019-03-13 15:41:27 -07001330 auto proof_source_cb =
vasilvv0fc587f2019-09-06 13:33:08 -07001331 std::make_unique<BuildServerConfigUpdateMessageProofSourceCallback>(
QUICHE team39a71e52019-03-15 14:24:34 -07001332 this, compressed_certs_cache, common_cert_sets, params,
QUICHE teamea5bdef2019-03-13 15:41:27 -07001333 std::move(message), std::move(cb));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001334
1335 proof_source_->GetProof(server_address, params.sni, serialized, version,
1336 chlo_hash, std::move(proof_source_cb));
1337}
1338
1339QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1340 ~BuildServerConfigUpdateMessageProofSourceCallback() {}
1341
1342QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1343 BuildServerConfigUpdateMessageProofSourceCallback(
1344 const QuicCryptoServerConfig* config,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001345 QuicCompressedCertsCache* compressed_certs_cache,
1346 const CommonCertSets* common_cert_sets,
1347 const QuicCryptoNegotiatedParameters& params,
1348 CryptoHandshakeMessage message,
1349 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb)
1350 : config_(config),
QUICHE teama6ef0a62019-03-07 20:34:33 -05001351 compressed_certs_cache_(compressed_certs_cache),
1352 common_cert_sets_(common_cert_sets),
1353 client_common_set_hashes_(params.client_common_set_hashes),
1354 client_cached_cert_hashes_(params.client_cached_cert_hashes),
1355 sct_supported_by_client_(params.sct_supported_by_client),
1356 sni_(params.sni),
1357 message_(std::move(message)),
1358 cb_(std::move(cb)) {}
1359
1360void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
1361 Run(bool ok,
1362 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
1363 const QuicCryptoProof& proof,
1364 std::unique_ptr<ProofSource::Details> details) {
1365 config_->FinishBuildServerConfigUpdateMessage(
QUICHE team39a71e52019-03-15 14:24:34 -07001366 compressed_certs_cache_, common_cert_sets_, client_common_set_hashes_,
1367 client_cached_cert_hashes_, sct_supported_by_client_, sni_, ok, chain,
1368 proof.signature, proof.leaf_cert_scts, std::move(details),
1369 std::move(message_), std::move(cb_));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001370}
1371
1372void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001373 QuicCompressedCertsCache* compressed_certs_cache,
1374 const CommonCertSets* common_cert_sets,
vasilvvc48c8712019-03-11 13:38:16 -07001375 const std::string& client_common_set_hashes,
1376 const std::string& client_cached_cert_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001377 bool sct_supported_by_client,
vasilvvc48c8712019-03-11 13:38:16 -07001378 const std::string& sni,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001379 bool ok,
1380 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
vasilvvc48c8712019-03-11 13:38:16 -07001381 const std::string& signature,
1382 const std::string& leaf_cert_sct,
dschinazi17d42422019-06-18 16:35:07 -07001383 std::unique_ptr<ProofSource::Details> /*details*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001384 CryptoHandshakeMessage message,
1385 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
1386 if (!ok) {
1387 cb->Run(false, message);
1388 return;
1389 }
1390
vasilvvc48c8712019-03-11 13:38:16 -07001391 const std::string compressed =
QUICHE teama6ef0a62019-03-07 20:34:33 -05001392 CompressChain(compressed_certs_cache, chain, client_common_set_hashes,
1393 client_cached_cert_hashes, common_cert_sets);
1394
1395 message.SetStringPiece(kCertificateTag, compressed);
1396 message.SetStringPiece(kPROF, signature);
1397 if (sct_supported_by_client && enable_serving_sct_) {
1398 if (leaf_cert_sct.empty()) {
1399 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
1400 << "SCT is expected but it is empty. SNI: " << sni;
1401 } else {
1402 message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct);
1403 }
1404 }
1405
1406 cb->Run(true, message);
1407}
1408
QUICHE teamaa924f12019-03-21 11:26:21 -07001409void QuicCryptoServerConfig::BuildRejectionAndRecordStats(
1410 const ProcessClientHelloContext& context,
1411 const Config& config,
1412 const std::vector<uint32_t>& reject_reasons,
1413 CryptoHandshakeMessage* out) const {
1414 BuildRejection(context, config, reject_reasons, out);
1415 if (rejection_observer_ != nullptr) {
1416 rejection_observer_->OnRejectionBuilt(reject_reasons, out);
1417 }
1418}
1419
QUICHE teama6ef0a62019-03-07 20:34:33 -05001420void QuicCryptoServerConfig::BuildRejection(
QUICHE team4dae8412019-03-18 13:11:00 -07001421 const ProcessClientHelloContext& context,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001422 const Config& config,
QUICHE teame6dcf322019-03-19 12:23:47 -07001423 const std::vector<uint32_t>& reject_reasons,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001424 CryptoHandshakeMessage* out) const {
QUICHE team4dae8412019-03-18 13:11:00 -07001425 const QuicWallTime now = context.clock()->WallNow();
wub0a4b9c52019-05-28 13:18:58 -07001426
1427 out->set_tag(kREJ);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001428 out->SetStringPiece(kSCFG, config.serialized);
1429 out->SetStringPiece(
1430 kSourceAddressTokenTag,
QUICHE team4dae8412019-03-18 13:11:00 -07001431 NewSourceAddressToken(
1432 config, context.info().source_address_tokens,
1433 context.info().client_ip, context.rand(), context.info().now,
1434 &context.validate_chlo_result()->cached_network_params));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001435 out->SetValue(kSTTL, config.expiry_time.AbsoluteDifference(now).ToSeconds());
1436 if (replay_protection_) {
QUICHE team4dae8412019-03-18 13:11:00 -07001437 out->SetStringPiece(kServerNonceTag,
1438 NewServerNonce(context.rand(), context.info().now));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001439 }
1440
1441 // Send client the reject reason for debugging purposes.
QUICHE teame6dcf322019-03-19 12:23:47 -07001442 DCHECK_LT(0u, reject_reasons.size());
1443 out->SetVector(kRREJ, reject_reasons);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001444
1445 // The client may have requested a certificate chain.
QUICHE team4dae8412019-03-18 13:11:00 -07001446 if (!ClientDemandsX509Proof(context.client_hello())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001447 QUIC_BUG << "x509 certificates not supported in proof demand";
1448 return;
1449 }
1450
dmcardle904ef182019-12-13 08:34:33 -08001451 quiche::QuicheStringPiece client_common_set_hashes;
QUICHE team4dae8412019-03-18 13:11:00 -07001452 if (context.client_hello().GetStringPiece(kCCS, &client_common_set_hashes)) {
1453 context.params()->client_common_set_hashes =
1454 std::string(client_common_set_hashes);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001455 }
1456
dmcardle904ef182019-12-13 08:34:33 -08001457 quiche::QuicheStringPiece client_cached_cert_hashes;
QUICHE team4dae8412019-03-18 13:11:00 -07001458 if (context.client_hello().GetStringPiece(kCCRT,
1459 &client_cached_cert_hashes)) {
1460 context.params()->client_cached_cert_hashes =
1461 std::string(client_cached_cert_hashes);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001462 } else {
QUICHE team4dae8412019-03-18 13:11:00 -07001463 context.params()->client_cached_cert_hashes.clear();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001464 }
1465
QUICHE team4dae8412019-03-18 13:11:00 -07001466 const std::string compressed = CompressChain(
1467 context.compressed_certs_cache(), context.signed_config()->chain,
1468 context.params()->client_common_set_hashes,
1469 context.params()->client_cached_cert_hashes, config.common_cert_sets);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001470
QUICHE team4dae8412019-03-18 13:11:00 -07001471 DCHECK_GT(context.chlo_packet_size(), context.client_hello().size());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001472 // kREJOverheadBytes is a very rough estimate of how much of a REJ
1473 // message is taken up by things other than the certificates.
1474 // STK: 56 bytes
1475 // SNO: 56 bytes
1476 // SCFG
1477 // SCID: 16 bytes
1478 // PUBS: 38 bytes
1479 const size_t kREJOverheadBytes = 166;
1480 // max_unverified_size is the number of bytes that the certificate chain,
1481 // signature, and (optionally) signed certificate timestamp can consume before
1482 // we will demand a valid source-address token.
1483 const size_t max_unverified_size =
QUICHE team4dae8412019-03-18 13:11:00 -07001484 chlo_multiplier_ *
1485 (context.chlo_packet_size() - context.total_framing_overhead()) -
QUICHE teama6ef0a62019-03-07 20:34:33 -05001486 kREJOverheadBytes;
1487 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
1488 "overhead calculation may underflow");
1489 bool should_return_sct =
QUICHE team4dae8412019-03-18 13:11:00 -07001490 context.params()->sct_supported_by_client && enable_serving_sct_;
1491 const std::string& cert_sct = context.signed_config()->proof.leaf_cert_scts;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001492 const size_t sct_size = should_return_sct ? cert_sct.size() : 0;
QUICHE team4dae8412019-03-18 13:11:00 -07001493 const size_t total_size = context.signed_config()->proof.signature.size() +
1494 compressed.size() + sct_size;
1495 if (context.info().valid_source_address_token ||
1496 total_size < max_unverified_size) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001497 out->SetStringPiece(kCertificateTag, compressed);
QUICHE team4dae8412019-03-18 13:11:00 -07001498 out->SetStringPiece(kPROF, context.signed_config()->proof.signature);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001499 if (should_return_sct) {
1500 if (cert_sct.empty()) {
QUICHE teama80920c2019-08-22 14:06:29 -07001501 // Log SNI and subject name for the leaf cert if its SCT is empty.
1502 // This is for debugging b/28342827.
1503 const std::vector<std::string>& certs =
1504 context.signed_config()->chain->certs;
dmcardle904ef182019-12-13 08:34:33 -08001505 quiche::QuicheStringPiece ca_subject;
QUICHE teama80920c2019-08-22 14:06:29 -07001506 if (!certs.empty()) {
1507 QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001508 }
QUICHE teama80920c2019-08-22 14:06:29 -07001509 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
1510 << "SCT is expected but it is empty. sni: '"
1511 << context.params()->sni << "' cert subject: '" << ca_subject
1512 << "'";
QUICHE teama6ef0a62019-03-07 20:34:33 -05001513 } else {
1514 out->SetStringPiece(kCertificateSCTTag, cert_sct);
1515 }
1516 }
1517 } else {
1518 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
QUICHE team4dae8412019-03-18 13:11:00 -07001519 << "Sending inchoate REJ for hostname: " << context.info().sni
1520 << " signature: " << context.signed_config()->proof.signature.size()
QUICHE teama6ef0a62019-03-07 20:34:33 -05001521 << " cert: " << compressed.size() << " sct:" << sct_size
1522 << " total: " << total_size << " max: " << max_unverified_size;
1523 }
1524}
1525
vasilvvc48c8712019-03-11 13:38:16 -07001526std::string QuicCryptoServerConfig::CompressChain(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001527 QuicCompressedCertsCache* compressed_certs_cache,
1528 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
vasilvvc48c8712019-03-11 13:38:16 -07001529 const std::string& client_common_set_hashes,
1530 const std::string& client_cached_cert_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001531 const CommonCertSets* common_sets) {
1532 // Check whether the compressed certs is available in the cache.
1533 DCHECK(compressed_certs_cache);
vasilvvc48c8712019-03-11 13:38:16 -07001534 const std::string* cached_value = compressed_certs_cache->GetCompressedCert(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001535 chain, client_common_set_hashes, client_cached_cert_hashes);
1536 if (cached_value) {
1537 return *cached_value;
1538 }
vasilvvc48c8712019-03-11 13:38:16 -07001539 std::string compressed =
QUICHE teama6ef0a62019-03-07 20:34:33 -05001540 CertCompressor::CompressChain(chain->certs, client_common_set_hashes,
1541 client_cached_cert_hashes, common_sets);
1542 // Insert the newly compressed cert to cache.
1543 compressed_certs_cache->Insert(chain, client_common_set_hashes,
1544 client_cached_cert_hashes, compressed);
1545 return compressed;
1546}
1547
1548QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
1549QuicCryptoServerConfig::ParseConfigProtobuf(
QUICHE team99055cf2019-03-22 11:27:53 -07001550 const QuicServerConfigProtobuf& protobuf,
1551 bool is_fallback) const {
QUICHE teamfe1aca62019-03-14 13:39:01 -07001552 std::unique_ptr<CryptoHandshakeMessage> msg =
QUICHE teambbaa8be2019-03-21 12:54:17 -07001553 CryptoFramer::ParseMessage(protobuf.config());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001554
1555 if (msg->tag() != kSCFG) {
1556 QUIC_LOG(WARNING) << "Server config message has tag " << msg->tag()
1557 << " expected " << kSCFG;
1558 return nullptr;
1559 }
1560
1561 QuicReferenceCountedPointer<Config> config(new Config);
QUICHE teambbaa8be2019-03-21 12:54:17 -07001562 config->serialized = protobuf.config();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001563 config->source_address_token_boxer = &source_address_token_boxer_;
1564
QUICHE teambbaa8be2019-03-21 12:54:17 -07001565 if (protobuf.has_primary_time()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001566 config->primary_time =
QUICHE teambbaa8be2019-03-21 12:54:17 -07001567 QuicWallTime::FromUNIXSeconds(protobuf.primary_time());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001568 }
1569
QUICHE teambbaa8be2019-03-21 12:54:17 -07001570 config->priority = protobuf.priority();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001571
dmcardle904ef182019-12-13 08:34:33 -08001572 quiche::QuicheStringPiece scid;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001573 if (!msg->GetStringPiece(kSCID, &scid)) {
1574 QUIC_LOG(WARNING) << "Server config message is missing SCID";
1575 return nullptr;
1576 }
vasilvvc48c8712019-03-11 13:38:16 -07001577 config->id = std::string(scid);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001578
1579 if (msg->GetTaglist(kAEAD, &config->aead) != QUIC_NO_ERROR) {
1580 QUIC_LOG(WARNING) << "Server config message is missing AEAD";
1581 return nullptr;
1582 }
1583
1584 QuicTagVector kexs_tags;
1585 if (msg->GetTaglist(kKEXS, &kexs_tags) != QUIC_NO_ERROR) {
1586 QUIC_LOG(WARNING) << "Server config message is missing KEXS";
1587 return nullptr;
1588 }
1589
dmcardle904ef182019-12-13 08:34:33 -08001590 quiche::QuicheStringPiece orbit;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001591 if (!msg->GetStringPiece(kORBT, &orbit)) {
1592 QUIC_LOG(WARNING) << "Server config message is missing ORBT";
1593 return nullptr;
1594 }
1595
1596 if (orbit.size() != kOrbitSize) {
1597 QUIC_LOG(WARNING) << "Orbit value in server config is the wrong length."
1598 " Got "
1599 << orbit.size() << " want " << kOrbitSize;
1600 return nullptr;
1601 }
1602 static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size");
1603 memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
1604
QUICHE team59882932019-03-27 11:02:17 -07001605 if ((kexs_tags.size() != static_cast<size_t>(protobuf.key_size())) &&
1606 (!GetQuicRestartFlag(dont_fetch_quic_private_keys_from_leto) &&
1607 protobuf.key_size() == 0)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001608 QUIC_LOG(WARNING) << "Server config has " << kexs_tags.size()
1609 << " key exchange methods configured, but "
QUICHE teambbaa8be2019-03-21 12:54:17 -07001610 << protobuf.key_size() << " private keys";
QUICHE teama6ef0a62019-03-07 20:34:33 -05001611 return nullptr;
1612 }
1613
1614 QuicTagVector proof_demand_tags;
1615 if (msg->GetTaglist(kPDMD, &proof_demand_tags) == QUIC_NO_ERROR) {
1616 for (QuicTag tag : proof_demand_tags) {
1617 if (tag == kCHID) {
1618 config->channel_id_enabled = true;
1619 break;
1620 }
1621 }
1622 }
1623
1624 for (size_t i = 0; i < kexs_tags.size(); i++) {
1625 const QuicTag tag = kexs_tags[i];
vasilvvc48c8712019-03-11 13:38:16 -07001626 std::string private_key;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001627
1628 config->kexs.push_back(tag);
1629
QUICHE teambbaa8be2019-03-21 12:54:17 -07001630 for (int j = 0; j < protobuf.key_size(); j++) {
1631 const QuicServerConfigProtobuf::PrivateKey& key = protobuf.key(i);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001632 if (key.tag() == tag) {
1633 private_key = key.private_key();
1634 break;
1635 }
1636 }
1637
QUICHE team99055cf2019-03-22 11:27:53 -07001638 std::unique_ptr<AsynchronousKeyExchange> ka =
1639 key_exchange_source_->Create(config->id, is_fallback, tag, private_key);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001640 if (!ka) {
1641 return nullptr;
1642 }
1643 for (const auto& key_exchange : config->key_exchanges) {
QUICHE teamfe1aca62019-03-14 13:39:01 -07001644 if (key_exchange->type() == tag) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001645 QUIC_LOG(WARNING) << "Duplicate key exchange in config: " << tag;
1646 return nullptr;
1647 }
1648 }
1649
1650 config->key_exchanges.push_back(std::move(ka));
1651 }
1652
1653 uint64_t expiry_seconds;
1654 if (msg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
1655 QUIC_LOG(WARNING) << "Server config message is missing EXPY";
1656 return nullptr;
1657 }
1658 config->expiry_time = QuicWallTime::FromUNIXSeconds(expiry_seconds);
1659
1660 return config;
1661}
1662
1663void QuicCryptoServerConfig::set_replay_protection(bool on) {
1664 replay_protection_ = on;
1665}
1666
1667void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) {
1668 chlo_multiplier_ = multiplier;
1669}
1670
1671void QuicCryptoServerConfig::set_source_address_token_future_secs(
1672 uint32_t future_secs) {
1673 source_address_token_future_secs_ = future_secs;
1674}
1675
1676void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
1677 uint32_t lifetime_secs) {
1678 source_address_token_lifetime_secs_ = lifetime_secs;
1679}
1680
1681void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) {
1682 enable_serving_sct_ = enable_serving_sct;
1683}
1684
1685void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
1686 std::unique_ptr<PrimaryConfigChangedCallback> cb) {
1687 QuicWriterMutexLock locked(&configs_lock_);
1688 primary_config_changed_cb_ = std::move(cb);
1689}
1690
vasilvvc48c8712019-03-11 13:38:16 -07001691std::string QuicCryptoServerConfig::NewSourceAddressToken(
QUICHE teama6ef0a62019-03-07 20:34:33 -05001692 const Config& config,
1693 const SourceAddressTokens& previous_tokens,
1694 const QuicIpAddress& ip,
1695 QuicRandom* rand,
1696 QuicWallTime now,
1697 const CachedNetworkParameters* cached_network_params) const {
1698 SourceAddressTokens source_address_tokens;
1699 SourceAddressToken* source_address_token = source_address_tokens.add_tokens();
1700 source_address_token->set_ip(ip.DualStacked().ToPackedString());
1701 source_address_token->set_timestamp(now.ToUNIXSeconds());
1702 if (cached_network_params != nullptr) {
1703 *(source_address_token->mutable_cached_network_parameters()) =
1704 *cached_network_params;
1705 }
1706
1707 // Append previous tokens.
1708 for (const SourceAddressToken& token : previous_tokens.tokens()) {
1709 if (source_address_tokens.tokens_size() > kMaxTokenAddresses) {
1710 break;
1711 }
1712
1713 if (token.ip() == source_address_token->ip()) {
1714 // It's for the same IP address.
1715 continue;
1716 }
1717
1718 if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) {
1719 continue;
1720 }
1721
1722 *(source_address_tokens.add_tokens()) = token;
1723 }
1724
1725 return config.source_address_token_boxer->Box(
1726 rand, source_address_tokens.SerializeAsString());
1727}
1728
1729int QuicCryptoServerConfig::NumberOfConfigs() const {
1730 QuicReaderMutexLock locked(&configs_lock_);
1731 return configs_.size();
1732}
1733
1734ProofSource* QuicCryptoServerConfig::proof_source() const {
1735 return proof_source_.get();
1736}
1737
QUICHE team3a72e2f2020-01-24 15:13:19 -08001738ServerProofVerifier* QuicCryptoServerConfig::proof_verifier() const {
1739 return proof_verifier_.get();
1740}
1741
1742void QuicCryptoServerConfig::set_proof_verifier(
1743 std::unique_ptr<ServerProofVerifier> proof_verifier) {
1744 proof_verifier_ = std::move(proof_verifier);
1745}
1746
1747ClientCertMode QuicCryptoServerConfig::client_cert_mode() const {
1748 return client_cert_mode_;
1749}
1750
1751void QuicCryptoServerConfig::set_client_cert_mode(ClientCertMode mode) {
1752 client_cert_mode_ = mode;
1753}
1754
QUICHE teama6ef0a62019-03-07 20:34:33 -05001755SSL_CTX* QuicCryptoServerConfig::ssl_ctx() const {
1756 return ssl_ctx_.get();
1757}
1758
1759HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken(
1760 const Config& config,
dmcardle904ef182019-12-13 08:34:33 -08001761 quiche::QuicheStringPiece token,
QUICHE teama6ef0a62019-03-07 20:34:33 -05001762 SourceAddressTokens* tokens) const {
vasilvvc48c8712019-03-11 13:38:16 -07001763 std::string storage;
dmcardle904ef182019-12-13 08:34:33 -08001764 quiche::QuicheStringPiece plaintext;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001765 if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) {
1766 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
1767 }
1768
1769 if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) {
1770 // Some clients might still be using the old source token format so
1771 // attempt to parse that format.
1772 // TODO(rch): remove this code once the new format is ubiquitous.
1773 SourceAddressToken token;
1774 if (!token.ParseFromArray(plaintext.data(), plaintext.size())) {
1775 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
1776 }
1777 *tokens->add_tokens() = token;
1778 }
1779
1780 return HANDSHAKE_OK;
1781}
1782
1783HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens(
1784 const SourceAddressTokens& source_address_tokens,
1785 const QuicIpAddress& ip,
1786 QuicWallTime now,
1787 CachedNetworkParameters* cached_network_params) const {
1788 HandshakeFailureReason reason =
1789 SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1790 for (const SourceAddressToken& token : source_address_tokens.tokens()) {
1791 reason = ValidateSingleSourceAddressToken(token, ip, now);
1792 if (reason == HANDSHAKE_OK) {
1793 if (token.has_cached_network_parameters()) {
1794 *cached_network_params = token.cached_network_parameters();
1795 }
1796 break;
1797 }
1798 }
1799 return reason;
1800}
1801
1802HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken(
1803 const SourceAddressToken& source_address_token,
1804 const QuicIpAddress& ip,
1805 QuicWallTime now) const {
1806 if (source_address_token.ip() != ip.DualStacked().ToPackedString()) {
1807 // It's for a different IP address.
1808 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1809 }
1810
1811 return ValidateSourceAddressTokenTimestamp(source_address_token, now);
1812}
1813
1814HandshakeFailureReason
1815QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp(
1816 const SourceAddressToken& source_address_token,
1817 QuicWallTime now) const {
1818 const QuicWallTime timestamp(
1819 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
1820 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
1821
1822 if (now.IsBefore(timestamp) &&
1823 delta.ToSeconds() > source_address_token_future_secs_) {
1824 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
1825 }
1826
1827 if (now.IsAfter(timestamp) &&
1828 delta.ToSeconds() > source_address_token_lifetime_secs_) {
1829 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
1830 }
1831
1832 return HANDSHAKE_OK;
1833}
1834
1835// kServerNoncePlaintextSize is the number of bytes in an unencrypted server
1836// nonce.
1837static const size_t kServerNoncePlaintextSize =
1838 4 /* timestamp */ + 20 /* random bytes */;
1839
vasilvvc48c8712019-03-11 13:38:16 -07001840std::string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
1841 QuicWallTime now) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001842 const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds());
1843
1844 uint8_t server_nonce[kServerNoncePlaintextSize];
1845 static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small");
1846 server_nonce[0] = static_cast<uint8_t>(timestamp >> 24);
1847 server_nonce[1] = static_cast<uint8_t>(timestamp >> 16);
1848 server_nonce[2] = static_cast<uint8_t>(timestamp >> 8);
1849 server_nonce[3] = static_cast<uint8_t>(timestamp);
1850 rand->RandBytes(&server_nonce[sizeof(timestamp)],
1851 sizeof(server_nonce) - sizeof(timestamp));
1852
1853 return server_nonce_boxer_.Box(
dmcardle904ef182019-12-13 08:34:33 -08001854 rand, quiche::QuicheStringPiece(reinterpret_cast<char*>(server_nonce),
1855 sizeof(server_nonce)));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001856}
1857
1858bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate(
1859 const CryptoHandshakeMessage& client_hello,
vasilvvc48c8712019-03-11 13:38:16 -07001860 const std::vector<std::string>& certs) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001861 if (certs.empty()) {
1862 return false;
1863 }
1864
1865 uint64_t hash_from_client;
1866 if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) {
1867 return false;
1868 }
1869 return CryptoUtils::ComputeLeafCertHash(certs.at(0)) == hash_from_client;
1870}
1871
QUICHE teama6ef0a62019-03-07 20:34:33 -05001872bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001873 return !next_config_promotion_time_.IsZero() &&
rcha19b43d2019-03-22 13:58:37 -07001874 !next_config_promotion_time_.IsAfter(now);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001875}
1876
1877QuicCryptoServerConfig::Config::Config()
1878 : channel_id_enabled(false),
1879 is_primary(false),
1880 primary_time(QuicWallTime::Zero()),
1881 expiry_time(QuicWallTime::Zero()),
1882 priority(0),
1883 source_address_token_boxer(nullptr) {}
1884
1885QuicCryptoServerConfig::Config::~Config() {}
1886
1887QuicSignedServerConfig::QuicSignedServerConfig() {}
1888QuicSignedServerConfig::~QuicSignedServerConfig() {}
1889
1890} // namespace quic