1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/core/crypto/quic_crypto_server_config.h"
6
7 #include <algorithm>
8 #include <cstdlib>
9 #include <memory>
10 #include <optional>
11 #include <string>
12 #include <utility>
13
14 #include "absl/base/attributes.h"
15 #include "absl/strings/escaping.h"
16 #include "absl/strings/str_format.h"
17 #include "absl/strings/string_view.h"
18 #include "openssl/sha.h"
19 #include "openssl/ssl.h"
20 #include "quiche/quic/core/crypto/aes_128_gcm_12_decrypter.h"
21 #include "quiche/quic/core/crypto/aes_128_gcm_12_encrypter.h"
22 #include "quiche/quic/core/crypto/cert_compressor.h"
23 #include "quiche/quic/core/crypto/certificate_view.h"
24 #include "quiche/quic/core/crypto/chacha20_poly1305_encrypter.h"
25 #include "quiche/quic/core/crypto/channel_id.h"
26 #include "quiche/quic/core/crypto/crypto_framer.h"
27 #include "quiche/quic/core/crypto/crypto_handshake_message.h"
28 #include "quiche/quic/core/crypto/crypto_utils.h"
29 #include "quiche/quic/core/crypto/curve25519_key_exchange.h"
30 #include "quiche/quic/core/crypto/key_exchange.h"
31 #include "quiche/quic/core/crypto/p256_key_exchange.h"
32 #include "quiche/quic/core/crypto/proof_source.h"
33 #include "quiche/quic/core/crypto/quic_decrypter.h"
34 #include "quiche/quic/core/crypto/quic_encrypter.h"
35 #include "quiche/quic/core/crypto/quic_hkdf.h"
36 #include "quiche/quic/core/crypto/quic_random.h"
37 #include "quiche/quic/core/crypto/tls_server_connection.h"
38 #include "quiche/quic/core/proto/crypto_server_config_proto.h"
39 #include "quiche/quic/core/proto/source_address_token_proto.h"
40 #include "quiche/quic/core/quic_clock.h"
41 #include "quiche/quic/core/quic_connection_context.h"
42 #include "quiche/quic/core/quic_packets.h"
43 #include "quiche/quic/core/quic_socket_address_coder.h"
44 #include "quiche/quic/core/quic_types.h"
45 #include "quiche/quic/core/quic_utils.h"
46 #include "quiche/quic/platform/api/quic_bug_tracker.h"
47 #include "quiche/quic/platform/api/quic_flag_utils.h"
48 #include "quiche/quic/platform/api/quic_flags.h"
49 #include "quiche/quic/platform/api/quic_hostname_utils.h"
50 #include "quiche/quic/platform/api/quic_logging.h"
51 #include "quiche/quic/platform/api/quic_socket_address.h"
52 #include "quiche/quic/platform/api/quic_testvalue.h"
53 #include "quiche/common/platform/api/quiche_reference_counted.h"
54
55 namespace quic {
56
57 namespace {
58
59 // kMultiplier is the multiple of the CHLO message size that a REJ message
60 // must stay under when the client doesn't present a valid source-address
61 // token. This is used to protect QUIC from amplification attacks.
62 // TODO(rch): Reduce this to 2 again once b/25933682 is fixed.
63 const size_t kMultiplier = 3;
64
65 const int kMaxTokenAddresses = 4;
66
DeriveSourceAddressTokenKey(absl::string_view source_address_token_secret)67 std::string DeriveSourceAddressTokenKey(
68 absl::string_view source_address_token_secret) {
69 QuicHKDF hkdf(source_address_token_secret, absl::string_view() /* no salt */,
70 "QUIC source address token key",
71 CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */,
72 0 /* no subkey secret */);
73 return std::string(hkdf.server_write_key());
74 }
75
76 // Default source for creating KeyExchange objects.
77 class DefaultKeyExchangeSource : public KeyExchangeSource {
78 public:
79 DefaultKeyExchangeSource() = default;
80 ~DefaultKeyExchangeSource() override = default;
81
Create(std::string,bool,QuicTag type,absl::string_view private_key)82 std::unique_ptr<AsynchronousKeyExchange> Create(
83 std::string /*server_config_id*/, bool /* is_fallback */, QuicTag type,
84 absl::string_view private_key) override {
85 if (private_key.empty()) {
86 QUIC_LOG(WARNING) << "Server config contains key exchange method without "
87 "corresponding private key of type "
88 << QuicTagToString(type);
89 return nullptr;
90 }
91
92 std::unique_ptr<SynchronousKeyExchange> ka =
93 CreateLocalSynchronousKeyExchange(type, private_key);
94 if (!ka) {
95 QUIC_LOG(WARNING) << "Failed to create key exchange method of type "
96 << QuicTagToString(type);
97 }
98 return ka;
99 }
100 };
101
102 // Returns true if the PDMD field from the client hello demands an X509
103 // certificate.
ClientDemandsX509Proof(const CryptoHandshakeMessage & client_hello)104 bool ClientDemandsX509Proof(const CryptoHandshakeMessage& client_hello) {
105 QuicTagVector their_proof_demands;
106
107 if (client_hello.GetTaglist(kPDMD, &their_proof_demands) != QUIC_NO_ERROR) {
108 return false;
109 }
110
111 for (const QuicTag tag : their_proof_demands) {
112 if (tag == kX509) {
113 return true;
114 }
115 }
116 return false;
117 }
118
FormatCryptoHandshakeMessageForTrace(const CryptoHandshakeMessage * message)119 std::string FormatCryptoHandshakeMessageForTrace(
120 const CryptoHandshakeMessage* message) {
121 if (message == nullptr) {
122 return "<null message>";
123 }
124
125 std::string s = QuicTagToString(message->tag());
126
127 // Append the reasons for REJ.
128 if (const auto it = message->tag_value_map().find(kRREJ);
129 it != message->tag_value_map().end()) {
130 const std::string& value = it->second;
131 // The value is a vector of uint32_t(s).
132 if (value.size() % sizeof(uint32_t) == 0) {
133 absl::StrAppend(&s, " RREJ:[");
134 // Append comma-separated list of reasons to |s|.
135 for (size_t j = 0; j < value.size(); j += sizeof(uint32_t)) {
136 uint32_t reason;
137 memcpy(&reason, value.data() + j, sizeof(reason));
138 if (j > 0) {
139 absl::StrAppend(&s, ",");
140 }
141 absl::StrAppend(&s, CryptoUtils::HandshakeFailureReasonToString(
142 static_cast<HandshakeFailureReason>(reason)));
143 }
144 absl::StrAppend(&s, "]");
145 } else {
146 absl::StrAppendFormat(&s, " RREJ:[unexpected length:%u]", value.size());
147 }
148 }
149
150 return s;
151 }
152
153 } // namespace
154
155 // static
Default()156 std::unique_ptr<KeyExchangeSource> KeyExchangeSource::Default() {
157 return std::make_unique<DefaultKeyExchangeSource>();
158 }
159
160 class ValidateClientHelloHelper {
161 public:
162 // Note: stores a pointer to a unique_ptr, and std::moves the unique_ptr when
163 // ValidationComplete is called.
ValidateClientHelloHelper(quiche::QuicheReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result,std::unique_ptr<ValidateClientHelloResultCallback> * done_cb)164 ValidateClientHelloHelper(
165 quiche::QuicheReferenceCountedPointer<
166 ValidateClientHelloResultCallback::Result>
167 result,
168 std::unique_ptr<ValidateClientHelloResultCallback>* done_cb)
169 : result_(std::move(result)), done_cb_(done_cb) {}
170 ValidateClientHelloHelper(const ValidateClientHelloHelper&) = delete;
171 ValidateClientHelloHelper& operator=(const ValidateClientHelloHelper&) =
172 delete;
173
~ValidateClientHelloHelper()174 ~ValidateClientHelloHelper() {
175 QUIC_BUG_IF(quic_bug_12963_1, done_cb_ != nullptr)
176 << "Deleting ValidateClientHelloHelper with a pending callback.";
177 }
178
ValidationComplete(QuicErrorCode error_code,const char * error_details,std::unique_ptr<ProofSource::Details> proof_source_details)179 void ValidationComplete(
180 QuicErrorCode error_code, const char* error_details,
181 std::unique_ptr<ProofSource::Details> proof_source_details) {
182 result_->error_code = error_code;
183 result_->error_details = error_details;
184 (*done_cb_)->Run(std::move(result_), std::move(proof_source_details));
185 DetachCallback();
186 }
187
DetachCallback()188 void DetachCallback() {
189 QUIC_BUG_IF(quic_bug_10630_1, done_cb_ == nullptr)
190 << "Callback already detached.";
191 done_cb_ = nullptr;
192 }
193
194 private:
195 quiche::QuicheReferenceCountedPointer<
196 ValidateClientHelloResultCallback::Result>
197 result_;
198 std::unique_ptr<ValidateClientHelloResultCallback>* done_cb_;
199 };
200
201 // static
202 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
203
ClientHelloInfo(const QuicIpAddress & in_client_ip,QuicWallTime in_now)204 ClientHelloInfo::ClientHelloInfo(const QuicIpAddress& in_client_ip,
205 QuicWallTime in_now)
206 : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {}
207
208 ClientHelloInfo::ClientHelloInfo(const ClientHelloInfo& other) = default;
209
~ClientHelloInfo()210 ClientHelloInfo::~ClientHelloInfo() {}
211
PrimaryConfigChangedCallback()212 PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {}
213
~PrimaryConfigChangedCallback()214 PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {}
215
Result(const CryptoHandshakeMessage & in_client_hello,QuicIpAddress in_client_ip,QuicWallTime in_now)216 ValidateClientHelloResultCallback::Result::Result(
217 const CryptoHandshakeMessage& in_client_hello, QuicIpAddress in_client_ip,
218 QuicWallTime in_now)
219 : client_hello(in_client_hello),
220 info(in_client_ip, in_now),
221 error_code(QUIC_NO_ERROR) {}
222
~Result()223 ValidateClientHelloResultCallback::Result::~Result() {}
224
ValidateClientHelloResultCallback()225 ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {}
226
~ValidateClientHelloResultCallback()227 ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {}
228
ProcessClientHelloResultCallback()229 ProcessClientHelloResultCallback::ProcessClientHelloResultCallback() {}
230
~ProcessClientHelloResultCallback()231 ProcessClientHelloResultCallback::~ProcessClientHelloResultCallback() {}
232
ConfigOptions()233 QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
234 : expiry_time(QuicWallTime::Zero()),
235 channel_id_enabled(false),
236 p256(false) {}
237
238 QuicCryptoServerConfig::ConfigOptions::ConfigOptions(
239 const ConfigOptions& other) = default;
240
~ConfigOptions()241 QuicCryptoServerConfig::ConfigOptions::~ConfigOptions() {}
242
243 QuicCryptoServerConfig::ProcessClientHelloContext::
~ProcessClientHelloContext()244 ~ProcessClientHelloContext() {
245 if (done_cb_ != nullptr) {
246 QUIC_LOG(WARNING)
247 << "Deleting ProcessClientHelloContext with a pending callback.";
248 }
249 }
250
Fail(QuicErrorCode error,const std::string & error_details)251 void QuicCryptoServerConfig::ProcessClientHelloContext::Fail(
252 QuicErrorCode error, const std::string& error_details) {
253 QUIC_TRACEPRINTF("ProcessClientHello failed: error=%s, details=%s",
254 QuicErrorCodeToString(error), error_details);
255 done_cb_->Run(error, error_details, nullptr, nullptr, nullptr);
256 done_cb_ = nullptr;
257 }
258
Succeed(std::unique_ptr<CryptoHandshakeMessage> message,std::unique_ptr<DiversificationNonce> diversification_nonce,std::unique_ptr<ProofSource::Details> proof_source_details)259 void QuicCryptoServerConfig::ProcessClientHelloContext::Succeed(
260 std::unique_ptr<CryptoHandshakeMessage> message,
261 std::unique_ptr<DiversificationNonce> diversification_nonce,
262 std::unique_ptr<ProofSource::Details> proof_source_details) {
263 QUIC_TRACEPRINTF("ProcessClientHello succeeded: %s",
264 FormatCryptoHandshakeMessageForTrace(message.get()));
265
266 done_cb_->Run(QUIC_NO_ERROR, std::string(), std::move(message),
267 std::move(diversification_nonce),
268 std::move(proof_source_details));
269 done_cb_ = nullptr;
270 }
271
QuicCryptoServerConfig(absl::string_view source_address_token_secret,QuicRandom * server_nonce_entropy,std::unique_ptr<ProofSource> proof_source,std::unique_ptr<KeyExchangeSource> key_exchange_source)272 QuicCryptoServerConfig::QuicCryptoServerConfig(
273 absl::string_view source_address_token_secret,
274 QuicRandom* server_nonce_entropy, std::unique_ptr<ProofSource> proof_source,
275 std::unique_ptr<KeyExchangeSource> key_exchange_source)
276 : replay_protection_(true),
277 chlo_multiplier_(kMultiplier),
278 configs_lock_(),
279 primary_config_(nullptr),
280 next_config_promotion_time_(QuicWallTime::Zero()),
281 proof_source_(std::move(proof_source)),
282 key_exchange_source_(std::move(key_exchange_source)),
283 ssl_ctx_(TlsServerConnection::CreateSslCtx(proof_source_.get())),
284 source_address_token_future_secs_(3600),
285 source_address_token_lifetime_secs_(86400),
286 enable_serving_sct_(false),
287 rejection_observer_(nullptr),
288 pad_rej_(true),
289 pad_shlo_(true),
290 validate_chlo_size_(true),
291 validate_source_address_token_(true) {
292 QUICHE_DCHECK(proof_source_.get());
293 source_address_token_boxer_.SetKeys(
294 {DeriveSourceAddressTokenKey(source_address_token_secret)});
295
296 // Generate a random key and orbit for server nonces.
297 server_nonce_entropy->RandBytes(server_nonce_orbit_,
298 sizeof(server_nonce_orbit_));
299 const size_t key_size = server_nonce_boxer_.GetKeySize();
300 std::unique_ptr<uint8_t[]> key_bytes(new uint8_t[key_size]);
301 server_nonce_entropy->RandBytes(key_bytes.get(), key_size);
302
303 server_nonce_boxer_.SetKeys(
304 {std::string(reinterpret_cast<char*>(key_bytes.get()), key_size)});
305 }
306
~QuicCryptoServerConfig()307 QuicCryptoServerConfig::~QuicCryptoServerConfig() {}
308
309 // static
GenerateConfig(QuicRandom * rand,const QuicClock * clock,const ConfigOptions & options)310 QuicServerConfigProtobuf QuicCryptoServerConfig::GenerateConfig(
311 QuicRandom* rand, const QuicClock* clock, const ConfigOptions& options) {
312 CryptoHandshakeMessage msg;
313
314 const std::string curve25519_private_key =
315 Curve25519KeyExchange::NewPrivateKey(rand);
316 std::unique_ptr<Curve25519KeyExchange> curve25519 =
317 Curve25519KeyExchange::New(curve25519_private_key);
318 absl::string_view curve25519_public_value = curve25519->public_value();
319
320 std::string encoded_public_values;
321 // First three bytes encode the length of the public value.
322 QUICHE_DCHECK_LT(curve25519_public_value.size(), (1U << 24));
323 encoded_public_values.push_back(
324 static_cast<char>(curve25519_public_value.size()));
325 encoded_public_values.push_back(
326 static_cast<char>(curve25519_public_value.size() >> 8));
327 encoded_public_values.push_back(
328 static_cast<char>(curve25519_public_value.size() >> 16));
329 encoded_public_values.append(curve25519_public_value.data(),
330 curve25519_public_value.size());
331
332 std::string p256_private_key;
333 if (options.p256) {
334 p256_private_key = P256KeyExchange::NewPrivateKey();
335 std::unique_ptr<P256KeyExchange> p256(
336 P256KeyExchange::New(p256_private_key));
337 absl::string_view p256_public_value = p256->public_value();
338
339 QUICHE_DCHECK_LT(p256_public_value.size(), (1U << 24));
340 encoded_public_values.push_back(
341 static_cast<char>(p256_public_value.size()));
342 encoded_public_values.push_back(
343 static_cast<char>(p256_public_value.size() >> 8));
344 encoded_public_values.push_back(
345 static_cast<char>(p256_public_value.size() >> 16));
346 encoded_public_values.append(p256_public_value.data(),
347 p256_public_value.size());
348 }
349
350 msg.set_tag(kSCFG);
351 if (options.p256) {
352 msg.SetVector(kKEXS, QuicTagVector{kC255, kP256});
353 } else {
354 msg.SetVector(kKEXS, QuicTagVector{kC255});
355 }
356 msg.SetVector(kAEAD, QuicTagVector{kAESG, kCC20});
357 msg.SetStringPiece(kPUBS, encoded_public_values);
358
359 if (options.expiry_time.IsZero()) {
360 const QuicWallTime now = clock->WallNow();
361 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds(
362 60 * 60 * 24 * 180 /* 180 days, ~six months */));
363 const uint64_t expiry_seconds = expiry.ToUNIXSeconds();
364 msg.SetValue(kEXPY, expiry_seconds);
365 } else {
366 msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds());
367 }
368
369 char orbit_bytes[kOrbitSize];
370 if (options.orbit.size() == sizeof(orbit_bytes)) {
371 memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes));
372 } else {
373 QUICHE_DCHECK(options.orbit.empty());
374 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
375 }
376 msg.SetStringPiece(kORBT,
377 absl::string_view(orbit_bytes, sizeof(orbit_bytes)));
378
379 if (options.channel_id_enabled) {
380 msg.SetVector(kPDMD, QuicTagVector{kCHID});
381 }
382
383 if (options.id.empty()) {
384 // We need to ensure that the SCID changes whenever the server config does
385 // thus we make it a hash of the rest of the server config.
386 std::unique_ptr<QuicData> serialized =
387 CryptoFramer::ConstructHandshakeMessage(msg);
388
389 uint8_t scid_bytes[SHA256_DIGEST_LENGTH];
390 SHA256(reinterpret_cast<const uint8_t*>(serialized->data()),
391 serialized->length(), scid_bytes);
392 // The SCID is a truncated SHA-256 digest.
393 static_assert(16 <= SHA256_DIGEST_LENGTH, "SCID length too high.");
394 msg.SetStringPiece(
395 kSCID,
396 absl::string_view(reinterpret_cast<const char*>(scid_bytes), 16));
397 } else {
398 msg.SetStringPiece(kSCID, options.id);
399 }
400 // Don't put new tags below this point. The SCID generation should hash over
401 // everything but itself and so extra tags should be added prior to the
402 // preceding if block.
403
404 std::unique_ptr<QuicData> serialized =
405 CryptoFramer::ConstructHandshakeMessage(msg);
406
407 QuicServerConfigProtobuf config;
408 config.set_config(std::string(serialized->AsStringPiece()));
409 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config.add_key();
410 curve25519_key->set_tag(kC255);
411 curve25519_key->set_private_key(curve25519_private_key);
412
413 if (options.p256) {
414 QuicServerConfigProtobuf::PrivateKey* p256_key = config.add_key();
415 p256_key->set_tag(kP256);
416 p256_key->set_private_key(p256_private_key);
417 }
418
419 return config;
420 }
421
AddConfig(const QuicServerConfigProtobuf & protobuf,const QuicWallTime now)422 std::unique_ptr<CryptoHandshakeMessage> QuicCryptoServerConfig::AddConfig(
423 const QuicServerConfigProtobuf& protobuf, const QuicWallTime now) {
424 std::unique_ptr<CryptoHandshakeMessage> msg =
425 CryptoFramer::ParseMessage(protobuf.config());
426
427 if (!msg) {
428 QUIC_LOG(WARNING) << "Failed to parse server config message";
429 return nullptr;
430 }
431
432 quiche::QuicheReferenceCountedPointer<Config> config =
433 ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
434 if (!config) {
435 QUIC_LOG(WARNING) << "Failed to parse server config message";
436 return nullptr;
437 }
438
439 {
440 QuicWriterMutexLock locked(&configs_lock_);
441 if (configs_.find(config->id) != configs_.end()) {
442 QUIC_LOG(WARNING) << "Failed to add config because another with the same "
443 "server config id already exists: "
444 << absl::BytesToHexString(config->id);
445 return nullptr;
446 }
447
448 configs_[config->id] = config;
449 SelectNewPrimaryConfig(now);
450 QUICHE_DCHECK(primary_config_.get());
451 QUICHE_DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
452 primary_config_.get());
453 }
454
455 return msg;
456 }
457
458 std::unique_ptr<CryptoHandshakeMessage>
AddDefaultConfig(QuicRandom * rand,const QuicClock * clock,const ConfigOptions & options)459 QuicCryptoServerConfig::AddDefaultConfig(QuicRandom* rand,
460 const QuicClock* clock,
461 const ConfigOptions& options) {
462 return AddConfig(GenerateConfig(rand, clock, options), clock->WallNow());
463 }
464
SetConfigs(const std::vector<QuicServerConfigProtobuf> & protobufs,const QuicServerConfigProtobuf * fallback_protobuf,const QuicWallTime now)465 bool QuicCryptoServerConfig::SetConfigs(
466 const std::vector<QuicServerConfigProtobuf>& protobufs,
467 const QuicServerConfigProtobuf* fallback_protobuf, const QuicWallTime now) {
468 std::vector<quiche::QuicheReferenceCountedPointer<Config>> parsed_configs;
469 for (auto& protobuf : protobufs) {
470 quiche::QuicheReferenceCountedPointer<Config> config =
471 ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
472 if (!config) {
473 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
474 return false;
475 }
476
477 parsed_configs.push_back(config);
478 }
479
480 quiche::QuicheReferenceCountedPointer<Config> fallback_config;
481 if (fallback_protobuf != nullptr) {
482 fallback_config =
483 ParseConfigProtobuf(*fallback_protobuf, /* is_fallback = */ true);
484 if (!fallback_config) {
485 QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
486 return false;
487 }
488 QUIC_LOG(INFO) << "Fallback config has scid "
489 << absl::BytesToHexString(fallback_config->id);
490 parsed_configs.push_back(fallback_config);
491 } else {
492 QUIC_LOG(INFO) << "No fallback config provided";
493 }
494
495 if (parsed_configs.empty()) {
496 QUIC_LOG(WARNING)
497 << "Rejecting QUIC configs because new config list is empty.";
498 return false;
499 }
500
501 QUIC_LOG(INFO) << "Updating configs:";
502
503 QuicWriterMutexLock locked(&configs_lock_);
504 ConfigMap new_configs;
505
506 for (const quiche::QuicheReferenceCountedPointer<Config>& config :
507 parsed_configs) {
508 auto it = configs_.find(config->id);
509 if (it != configs_.end()) {
510 QUIC_LOG(INFO) << "Keeping scid: " << absl::BytesToHexString(config->id)
511 << " orbit: "
512 << absl::BytesToHexString(absl::string_view(
513 reinterpret_cast<const char*>(config->orbit),
514 kOrbitSize))
515 << " new primary_time "
516 << config->primary_time.ToUNIXSeconds()
517 << " old primary_time "
518 << it->second->primary_time.ToUNIXSeconds()
519 << " new priority " << config->priority << " old priority "
520 << it->second->priority;
521 // Update primary_time and priority.
522 it->second->primary_time = config->primary_time;
523 it->second->priority = config->priority;
524 new_configs.insert(*it);
525 } else {
526 QUIC_LOG(INFO) << "Adding scid: " << absl::BytesToHexString(config->id)
527 << " orbit: "
528 << absl::BytesToHexString(absl::string_view(
529 reinterpret_cast<const char*>(config->orbit),
530 kOrbitSize))
531 << " primary_time " << config->primary_time.ToUNIXSeconds()
532 << " priority " << config->priority;
533 new_configs.emplace(config->id, config);
534 }
535 }
536
537 configs_ = std::move(new_configs);
538 fallback_config_ = fallback_config;
539 SelectNewPrimaryConfig(now);
540 QUICHE_DCHECK(primary_config_.get());
541 QUICHE_DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
542 primary_config_.get());
543
544 return true;
545 }
546
SetSourceAddressTokenKeys(const std::vector<std::string> & keys)547 void QuicCryptoServerConfig::SetSourceAddressTokenKeys(
548 const std::vector<std::string>& keys) {
549 // TODO(b/208866709)
550 source_address_token_boxer_.SetKeys(keys);
551 }
552
GetConfigIds() const553 std::vector<std::string> QuicCryptoServerConfig::GetConfigIds() const {
554 QuicReaderMutexLock locked(&configs_lock_);
555 std::vector<std::string> scids;
556 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
557 scids.push_back(it->first);
558 }
559 return scids;
560 }
561
ValidateClientHello(const CryptoHandshakeMessage & client_hello,const QuicSocketAddress & client_address,const QuicSocketAddress & server_address,QuicTransportVersion version,const QuicClock * clock,quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config,std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const562 void QuicCryptoServerConfig::ValidateClientHello(
563 const CryptoHandshakeMessage& client_hello,
564 const QuicSocketAddress& client_address,
565 const QuicSocketAddress& server_address, QuicTransportVersion version,
566 const QuicClock* clock,
567 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config,
568 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
569 const QuicWallTime now(clock->WallNow());
570
571 quiche::QuicheReferenceCountedPointer<
572 ValidateClientHelloResultCallback::Result>
573 result(new ValidateClientHelloResultCallback::Result(
574 client_hello, client_address.host(), now));
575
576 absl::string_view requested_scid;
577 // We ignore here the return value from GetStringPiece. If there is no SCID
578 // tag, EvaluateClientHello will discover that because GetCurrentConfigs will
579 // not have found the requested config (i.e. because none of the configs will
580 // have an empty string as its id).
581 client_hello.GetStringPiece(kSCID, &requested_scid);
582 Configs configs;
583 if (!GetCurrentConfigs(now, requested_scid,
584 /* old_primary_config = */ nullptr, &configs)) {
585 result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
586 result->error_details = "No configurations loaded";
587 }
588 signed_config->config = configs.primary;
589
590 if (result->error_code == QUIC_NO_ERROR) {
591 // QUIC requires a new proof for each CHLO so clear any existing proof.
592 signed_config->chain = nullptr;
593 signed_config->proof.signature = "";
594 signed_config->proof.leaf_cert_scts = "";
595 EvaluateClientHello(server_address, client_address, version, configs,
596 result, std::move(done_cb));
597 } else {
598 done_cb->Run(result, /* details = */ nullptr);
599 }
600 }
601
602 class QuicCryptoServerConfig::ProcessClientHelloCallback
603 : public ProofSource::Callback {
604 public:
ProcessClientHelloCallback(const QuicCryptoServerConfig * config,std::unique_ptr<ProcessClientHelloContext> context,const Configs & configs)605 ProcessClientHelloCallback(const QuicCryptoServerConfig* config,
606 std::unique_ptr<ProcessClientHelloContext> context,
607 const Configs& configs)
608 : config_(config), context_(std::move(context)), configs_(configs) {}
609
Run(bool ok,const quiche::QuicheReferenceCountedPointer<ProofSource::Chain> & chain,const QuicCryptoProof & proof,std::unique_ptr<ProofSource::Details> details)610 void Run(
611 bool ok,
612 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain,
613 const QuicCryptoProof& proof,
614 std::unique_ptr<ProofSource::Details> details) override {
615 if (ok) {
616 context_->signed_config()->chain = chain;
617 context_->signed_config()->proof = proof;
618 }
619 config_->ProcessClientHelloAfterGetProof(!ok, std::move(details),
620 std::move(context_), configs_);
621 }
622
623 private:
624 const QuicCryptoServerConfig* config_;
625 std::unique_ptr<ProcessClientHelloContext> context_;
626 const Configs configs_;
627 };
628
629 class QuicCryptoServerConfig::ProcessClientHelloAfterGetProofCallback
630 : public AsynchronousKeyExchange::Callback {
631 public:
ProcessClientHelloAfterGetProofCallback(const QuicCryptoServerConfig * config,std::unique_ptr<ProofSource::Details> proof_source_details,QuicTag key_exchange_type,std::unique_ptr<CryptoHandshakeMessage> out,absl::string_view public_value,std::unique_ptr<ProcessClientHelloContext> context,const Configs & configs)632 ProcessClientHelloAfterGetProofCallback(
633 const QuicCryptoServerConfig* config,
634 std::unique_ptr<ProofSource::Details> proof_source_details,
635 QuicTag key_exchange_type, std::unique_ptr<CryptoHandshakeMessage> out,
636 absl::string_view public_value,
637 std::unique_ptr<ProcessClientHelloContext> context,
638 const Configs& configs)
639 : config_(config),
640 proof_source_details_(std::move(proof_source_details)),
641 key_exchange_type_(key_exchange_type),
642 out_(std::move(out)),
643 public_value_(public_value),
644 context_(std::move(context)),
645 configs_(configs) {}
646
Run(bool ok)647 void Run(bool ok) override {
648 config_->ProcessClientHelloAfterCalculateSharedKeys(
649 !ok, std::move(proof_source_details_), key_exchange_type_,
650 std::move(out_), public_value_, std::move(context_), configs_);
651 }
652
653 private:
654 const QuicCryptoServerConfig* config_;
655 std::unique_ptr<ProofSource::Details> proof_source_details_;
656 const QuicTag key_exchange_type_;
657 std::unique_ptr<CryptoHandshakeMessage> out_;
658 const std::string public_value_;
659 std::unique_ptr<ProcessClientHelloContext> context_;
660 const Configs configs_;
661 std::unique_ptr<ProcessClientHelloResultCallback> done_cb_;
662 };
663
664 class QuicCryptoServerConfig::SendRejectWithFallbackConfigCallback
665 : public ProofSource::Callback {
666 public:
SendRejectWithFallbackConfigCallback(const QuicCryptoServerConfig * config,std::unique_ptr<ProcessClientHelloContext> context,quiche::QuicheReferenceCountedPointer<Config> fallback_config)667 SendRejectWithFallbackConfigCallback(
668 const QuicCryptoServerConfig* config,
669 std::unique_ptr<ProcessClientHelloContext> context,
670 quiche::QuicheReferenceCountedPointer<Config> fallback_config)
671 : config_(config),
672 context_(std::move(context)),
673 fallback_config_(fallback_config) {}
674
675 // Capture |chain| and |proof| into the signed config, and then invoke
676 // SendRejectWithFallbackConfigAfterGetProof.
Run(bool ok,const quiche::QuicheReferenceCountedPointer<ProofSource::Chain> & chain,const QuicCryptoProof & proof,std::unique_ptr<ProofSource::Details> details)677 void Run(
678 bool ok,
679 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain,
680 const QuicCryptoProof& proof,
681 std::unique_ptr<ProofSource::Details> details) override {
682 if (ok) {
683 context_->signed_config()->chain = chain;
684 context_->signed_config()->proof = proof;
685 }
686 config_->SendRejectWithFallbackConfigAfterGetProof(
687 !ok, std::move(details), std::move(context_), fallback_config_);
688 }
689
690 private:
691 const QuicCryptoServerConfig* config_;
692 std::unique_ptr<ProcessClientHelloContext> context_;
693 quiche::QuicheReferenceCountedPointer<Config> fallback_config_;
694 };
695
ProcessClientHello(quiche::QuicheReferenceCountedPointer<ValidateClientHelloResultCallback::Result> validate_chlo_result,bool reject_only,QuicConnectionId connection_id,const QuicSocketAddress & server_address,const QuicSocketAddress & client_address,ParsedQuicVersion version,const ParsedQuicVersionVector & supported_versions,const QuicClock * clock,QuicRandom * rand,QuicCompressedCertsCache * compressed_certs_cache,quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config,QuicByteCount total_framing_overhead,QuicByteCount chlo_packet_size,std::shared_ptr<ProcessClientHelloResultCallback> done_cb) const696 void QuicCryptoServerConfig::ProcessClientHello(
697 quiche::QuicheReferenceCountedPointer<
698 ValidateClientHelloResultCallback::Result>
699 validate_chlo_result,
700 bool reject_only, QuicConnectionId connection_id,
701 const QuicSocketAddress& server_address,
702 const QuicSocketAddress& client_address, ParsedQuicVersion version,
703 const ParsedQuicVersionVector& supported_versions, const QuicClock* clock,
704 QuicRandom* rand, QuicCompressedCertsCache* compressed_certs_cache,
705 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters>
706 params,
707 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config,
708 QuicByteCount total_framing_overhead, QuicByteCount chlo_packet_size,
709 std::shared_ptr<ProcessClientHelloResultCallback> done_cb) const {
710 QUICHE_DCHECK(done_cb);
711 auto context = std::make_unique<ProcessClientHelloContext>(
712 validate_chlo_result, reject_only, connection_id, server_address,
713 client_address, version, supported_versions, clock, rand,
714 compressed_certs_cache, params, signed_config, total_framing_overhead,
715 chlo_packet_size, std::move(done_cb));
716
717 // Verify that various parts of the CHLO are valid
718 std::string error_details;
719 QuicErrorCode valid = CryptoUtils::ValidateClientHello(
720 context->client_hello(), context->version(),
721 context->supported_versions(), &error_details);
722 if (valid != QUIC_NO_ERROR) {
723 context->Fail(valid, error_details);
724 return;
725 }
726
727 absl::string_view requested_scid;
728 context->client_hello().GetStringPiece(kSCID, &requested_scid);
729 Configs configs;
730 if (!GetCurrentConfigs(context->clock()->WallNow(), requested_scid,
731 signed_config->config, &configs)) {
732 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "No configurations loaded");
733 return;
734 }
735
736 if (context->validate_chlo_result()->error_code != QUIC_NO_ERROR) {
737 context->Fail(context->validate_chlo_result()->error_code,
738 context->validate_chlo_result()->error_details);
739 return;
740 }
741
742 if (!ClientDemandsX509Proof(context->client_hello())) {
743 context->Fail(QUIC_UNSUPPORTED_PROOF_DEMAND, "Missing or invalid PDMD");
744 return;
745 }
746
747 // No need to get a new proof if one was already generated.
748 if (!context->signed_config()->chain) {
749 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
750 context->client_hello(), Perspective::IS_SERVER);
751 const QuicSocketAddress context_server_address = context->server_address();
752 const std::string sni = std::string(context->info().sni);
753 const QuicTransportVersion transport_version = context->transport_version();
754
755 auto cb = std::make_unique<ProcessClientHelloCallback>(
756 this, std::move(context), configs);
757
758 QUICHE_DCHECK(proof_source_.get());
759 proof_source_->GetProof(context_server_address, client_address, sni,
760 configs.primary->serialized, transport_version,
761 chlo_hash, std::move(cb));
762 return;
763 }
764
765 ProcessClientHelloAfterGetProof(
766 /* found_error = */ false, /* proof_source_details = */ nullptr,
767 std::move(context), configs);
768 }
769
ProcessClientHelloAfterGetProof(bool found_error,std::unique_ptr<ProofSource::Details> proof_source_details,std::unique_ptr<ProcessClientHelloContext> context,const Configs & configs) const770 void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
771 bool found_error,
772 std::unique_ptr<ProofSource::Details> proof_source_details,
773 std::unique_ptr<ProcessClientHelloContext> context,
774 const Configs& configs) const {
775 QUIC_BUG_IF(quic_bug_12963_2,
776 !QuicUtils::IsConnectionIdValidForVersion(
777 context->connection_id(), context->transport_version()))
778 << "ProcessClientHelloAfterGetProof: attempted to use connection ID "
779 << context->connection_id() << " which is invalid with version "
780 << context->version();
781
782 if (context->info().reject_reasons.empty()) {
783 if (!context->signed_config() || !context->signed_config()->chain) {
784 // No chain.
785 context->validate_chlo_result()->info.reject_reasons.push_back(
786 SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
787 } else if (!ValidateExpectedLeafCertificate(
788 context->client_hello(),
789 context->signed_config()->chain->certs)) {
790 // Has chain but leaf is invalid.
791 context->validate_chlo_result()->info.reject_reasons.push_back(
792 INVALID_EXPECTED_LEAF_CERTIFICATE);
793 }
794 }
795
796 if (found_error) {
797 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
798 return;
799 }
800
801 auto out_diversification_nonce = std::make_unique<DiversificationNonce>();
802
803 absl::string_view cert_sct;
804 if (context->client_hello().GetStringPiece(kCertificateSCTTag, &cert_sct) &&
805 cert_sct.empty()) {
806 context->params()->sct_supported_by_client = true;
807 }
808
809 auto out = std::make_unique<CryptoHandshakeMessage>();
810 if (!context->info().reject_reasons.empty() || !configs.requested) {
811 BuildRejectionAndRecordStats(*context, *configs.primary,
812 context->info().reject_reasons, out.get());
813 context->Succeed(std::move(out), std::move(out_diversification_nonce),
814 std::move(proof_source_details));
815 return;
816 }
817
818 if (context->reject_only()) {
819 context->Succeed(std::move(out), std::move(out_diversification_nonce),
820 std::move(proof_source_details));
821 return;
822 }
823
824 QuicTagVector their_aeads;
825 QuicTagVector their_key_exchanges;
826 if (context->client_hello().GetTaglist(kAEAD, &their_aeads) !=
827 QUIC_NO_ERROR ||
828 context->client_hello().GetTaglist(kKEXS, &their_key_exchanges) !=
829 QUIC_NO_ERROR ||
830 their_aeads.size() != 1 || their_key_exchanges.size() != 1) {
831 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
832 "Missing or invalid AEAD or KEXS");
833 return;
834 }
835
836 size_t key_exchange_index;
837 if (!FindMutualQuicTag(configs.requested->aead, their_aeads,
838 &context->params()->aead, nullptr) ||
839 !FindMutualQuicTag(configs.requested->kexs, their_key_exchanges,
840 &context->params()->key_exchange,
841 &key_exchange_index)) {
842 context->Fail(QUIC_CRYPTO_NO_SUPPORT, "Unsupported AEAD or KEXS");
843 return;
844 }
845
846 absl::string_view public_value;
847 if (!context->client_hello().GetStringPiece(kPUBS, &public_value)) {
848 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
849 "Missing public value");
850 return;
851 }
852
853 // Allow testing a specific adversarial case in which a client sends a public
854 // value of incorrect size.
855 AdjustTestValue("quic::QuicCryptoServerConfig::public_value_adjust",
856 &public_value);
857
858 const AsynchronousKeyExchange* key_exchange =
859 configs.requested->key_exchanges[key_exchange_index].get();
860 std::string* initial_premaster_secret =
861 &context->params()->initial_premaster_secret;
862 auto cb = std::make_unique<ProcessClientHelloAfterGetProofCallback>(
863 this, std::move(proof_source_details), key_exchange->type(),
864 std::move(out), public_value, std::move(context), configs);
865 key_exchange->CalculateSharedKeyAsync(public_value, initial_premaster_secret,
866 std::move(cb));
867 }
868
ProcessClientHelloAfterCalculateSharedKeys(bool found_error,std::unique_ptr<ProofSource::Details> proof_source_details,QuicTag key_exchange_type,std::unique_ptr<CryptoHandshakeMessage> out,absl::string_view public_value,std::unique_ptr<ProcessClientHelloContext> context,const Configs & configs) const869 void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys(
870 bool found_error,
871 std::unique_ptr<ProofSource::Details> proof_source_details,
872 QuicTag key_exchange_type, std::unique_ptr<CryptoHandshakeMessage> out,
873 absl::string_view public_value,
874 std::unique_ptr<ProcessClientHelloContext> context,
875 const Configs& configs) const {
876 QUIC_BUG_IF(quic_bug_12963_3,
877 !QuicUtils::IsConnectionIdValidForVersion(
878 context->connection_id(), context->transport_version()))
879 << "ProcessClientHelloAfterCalculateSharedKeys:"
880 " attempted to use connection ID "
881 << context->connection_id() << " which is invalid with version "
882 << context->version();
883
884 if (found_error) {
885 // If we are already using the fallback config, or there is no fallback
886 // config to use, just bail out of the handshake.
887 if (configs.fallback == nullptr ||
888 context->signed_config()->config == configs.fallback) {
889 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
890 "Failed to calculate shared key");
891 } else {
892 SendRejectWithFallbackConfig(std::move(context), configs.fallback);
893 }
894 return;
895 }
896
897 if (!context->info().sni.empty()) {
898 context->params()->sni =
899 QuicHostnameUtils::NormalizeHostname(context->info().sni);
900 }
901
902 std::string hkdf_suffix;
903 const QuicData& client_hello_serialized =
904 context->client_hello().GetSerialized();
905 hkdf_suffix.reserve(context->connection_id().length() +
906 client_hello_serialized.length() +
907 configs.requested->serialized.size());
908 hkdf_suffix.append(context->connection_id().data(),
909 context->connection_id().length());
910 hkdf_suffix.append(client_hello_serialized.data(),
911 client_hello_serialized.length());
912 hkdf_suffix.append(configs.requested->serialized);
913 QUICHE_DCHECK(proof_source_.get());
914 if (context->signed_config()->chain->certs.empty()) {
915 context->Fail(QUIC_CRYPTO_INTERNAL_ERROR, "Failed to get certs");
916 return;
917 }
918 hkdf_suffix.append(context->signed_config()->chain->certs[0]);
919
920 absl::string_view cetv_ciphertext;
921 if (configs.requested->channel_id_enabled &&
922 context->client_hello().GetStringPiece(kCETV, &cetv_ciphertext)) {
923 CryptoHandshakeMessage client_hello_copy(context->client_hello());
924 client_hello_copy.Erase(kCETV);
925 client_hello_copy.Erase(kPAD);
926
927 const QuicData& client_hello_copy_serialized =
928 client_hello_copy.GetSerialized();
929 std::string hkdf_input;
930 hkdf_input.append(QuicCryptoConfig::kCETVLabel,
931 strlen(QuicCryptoConfig::kCETVLabel) + 1);
932 hkdf_input.append(context->connection_id().data(),
933 context->connection_id().length());
934 hkdf_input.append(client_hello_copy_serialized.data(),
935 client_hello_copy_serialized.length());
936 hkdf_input.append(configs.requested->serialized);
937
938 CrypterPair crypters;
939 if (!CryptoUtils::DeriveKeys(
940 context->version(), context->params()->initial_premaster_secret,
941 context->params()->aead, context->info().client_nonce,
942 context->info().server_nonce, pre_shared_key_, hkdf_input,
943 Perspective::IS_SERVER, CryptoUtils::Diversification::Never(),
944 &crypters, nullptr /* subkey secret */)) {
945 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
946 "Symmetric key setup failed");
947 return;
948 }
949
950 char plaintext[kMaxOutgoingPacketSize];
951 size_t plaintext_length = 0;
952 const bool success = crypters.decrypter->DecryptPacket(
953 0 /* packet number */, absl::string_view() /* associated data */,
954 cetv_ciphertext, plaintext, &plaintext_length, kMaxOutgoingPacketSize);
955 if (!success) {
956 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
957 "CETV decryption failure");
958 return;
959 }
960 std::unique_ptr<CryptoHandshakeMessage> cetv(CryptoFramer::ParseMessage(
961 absl::string_view(plaintext, plaintext_length)));
962 if (!cetv) {
963 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV parse error");
964 return;
965 }
966
967 absl::string_view key, signature;
968 if (cetv->GetStringPiece(kCIDK, &key) &&
969 cetv->GetStringPiece(kCIDS, &signature)) {
970 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) {
971 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
972 "ChannelID signature failure");
973 return;
974 }
975
976 context->params()->channel_id = std::string(key);
977 }
978 }
979
980 std::string hkdf_input;
981 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
982 hkdf_input.reserve(label_len + hkdf_suffix.size());
983 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
984 hkdf_input.append(hkdf_suffix);
985
986 auto out_diversification_nonce = std::make_unique<DiversificationNonce>();
987 context->rand()->RandBytes(out_diversification_nonce->data(),
988 out_diversification_nonce->size());
989 CryptoUtils::Diversification diversification =
990 CryptoUtils::Diversification::Now(out_diversification_nonce.get());
991 if (!CryptoUtils::DeriveKeys(
992 context->version(), context->params()->initial_premaster_secret,
993 context->params()->aead, context->info().client_nonce,
994 context->info().server_nonce, pre_shared_key_, hkdf_input,
995 Perspective::IS_SERVER, diversification,
996 &context->params()->initial_crypters,
997 &context->params()->initial_subkey_secret)) {
998 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
999 "Symmetric key setup failed");
1000 return;
1001 }
1002
1003 std::string forward_secure_public_value;
1004 std::unique_ptr<SynchronousKeyExchange> forward_secure_key_exchange =
1005 CreateLocalSynchronousKeyExchange(key_exchange_type, context->rand());
1006 if (!forward_secure_key_exchange) {
1007 QUIC_DLOG(WARNING) << "Failed to create keypair";
1008 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
1009 "Failed to create keypair");
1010 return;
1011 }
1012
1013 forward_secure_public_value =
1014 std::string(forward_secure_key_exchange->public_value());
1015 if (!forward_secure_key_exchange->CalculateSharedKeySync(
1016 public_value, &context->params()->forward_secure_premaster_secret)) {
1017 context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
1018 "Invalid public value");
1019 return;
1020 }
1021
1022 std::string forward_secure_hkdf_input;
1023 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
1024 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
1025 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
1026 label_len);
1027 forward_secure_hkdf_input.append(hkdf_suffix);
1028
1029 std::string shlo_nonce;
1030 shlo_nonce = NewServerNonce(context->rand(), context->info().now);
1031 out->SetStringPiece(kServerNonceTag, shlo_nonce);
1032
1033 if (!CryptoUtils::DeriveKeys(
1034 context->version(),
1035 context->params()->forward_secure_premaster_secret,
1036 context->params()->aead, context->info().client_nonce,
1037 shlo_nonce.empty() ? context->info().server_nonce : shlo_nonce,
1038 pre_shared_key_, forward_secure_hkdf_input, Perspective::IS_SERVER,
1039 CryptoUtils::Diversification::Never(),
1040 &context->params()->forward_secure_crypters,
1041 &context->params()->subkey_secret)) {
1042 context->Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
1043 "Symmetric key setup failed");
1044 return;
1045 }
1046
1047 out->set_tag(kSHLO);
1048 out->SetVersionVector(kVER, context->supported_versions());
1049 out->SetStringPiece(
1050 kSourceAddressTokenTag,
1051 NewSourceAddressToken(*configs.requested->source_address_token_boxer,
1052 context->info().source_address_tokens,
1053 context->client_address().host(), context->rand(),
1054 context->info().now, nullptr));
1055 QuicSocketAddressCoder address_coder(context->client_address());
1056 out->SetStringPiece(kCADR, address_coder.Encode());
1057 out->SetStringPiece(kPUBS, forward_secure_public_value);
1058
1059 context->Succeed(std::move(out), std::move(out_diversification_nonce),
1060 std::move(proof_source_details));
1061 }
1062
SendRejectWithFallbackConfig(std::unique_ptr<ProcessClientHelloContext> context,quiche::QuicheReferenceCountedPointer<Config> fallback_config) const1063 void QuicCryptoServerConfig::SendRejectWithFallbackConfig(
1064 std::unique_ptr<ProcessClientHelloContext> context,
1065 quiche::QuicheReferenceCountedPointer<Config> fallback_config) const {
1066 // We failed to calculate a shared initial key, likely because we tried to use
1067 // a remote key-exchange service which could not be reached. We want to send
1068 // a REJ which tells the client to use a different ServerConfig which
1069 // corresponds to a local keypair. To generate the REJ we need to request a
1070 // new proof.
1071 const std::string chlo_hash = CryptoUtils::HashHandshakeMessage(
1072 context->client_hello(), Perspective::IS_SERVER);
1073 const QuicSocketAddress server_address = context->server_address();
1074 const std::string sni(context->info().sni);
1075 const QuicTransportVersion transport_version = context->transport_version();
1076
1077 const QuicSocketAddress& client_address = context->client_address();
1078 auto cb = std::make_unique<SendRejectWithFallbackConfigCallback>(
1079 this, std::move(context), fallback_config);
1080 proof_source_->GetProof(server_address, client_address, sni,
1081 fallback_config->serialized, transport_version,
1082 chlo_hash, std::move(cb));
1083 }
1084
SendRejectWithFallbackConfigAfterGetProof(bool found_error,std::unique_ptr<ProofSource::Details> proof_source_details,std::unique_ptr<ProcessClientHelloContext> context,quiche::QuicheReferenceCountedPointer<Config> fallback_config) const1085 void QuicCryptoServerConfig::SendRejectWithFallbackConfigAfterGetProof(
1086 bool found_error,
1087 std::unique_ptr<ProofSource::Details> proof_source_details,
1088 std::unique_ptr<ProcessClientHelloContext> context,
1089 quiche::QuicheReferenceCountedPointer<Config> fallback_config) const {
1090 if (found_error) {
1091 context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
1092 return;
1093 }
1094
1095 auto out = std::make_unique<CryptoHandshakeMessage>();
1096 BuildRejectionAndRecordStats(*context, *fallback_config,
1097 {SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE},
1098 out.get());
1099
1100 context->Succeed(std::move(out), std::make_unique<DiversificationNonce>(),
1101 std::move(proof_source_details));
1102 }
1103
1104 quiche::QuicheReferenceCountedPointer<QuicCryptoServerConfig::Config>
GetConfigWithScid(absl::string_view requested_scid) const1105 QuicCryptoServerConfig::GetConfigWithScid(
1106 absl::string_view requested_scid) const {
1107 configs_lock_.AssertReaderHeld();
1108
1109 if (!requested_scid.empty()) {
1110 auto it = configs_.find((std::string(requested_scid)));
1111 if (it != configs_.end()) {
1112 // We'll use the config that the client requested in order to do
1113 // key-agreement.
1114 return quiche::QuicheReferenceCountedPointer<Config>(it->second);
1115 }
1116 }
1117
1118 return quiche::QuicheReferenceCountedPointer<Config>();
1119 }
1120
GetCurrentConfigs(const QuicWallTime & now,absl::string_view requested_scid,quiche::QuicheReferenceCountedPointer<Config> old_primary_config,Configs * configs) const1121 bool QuicCryptoServerConfig::GetCurrentConfigs(
1122 const QuicWallTime& now, absl::string_view requested_scid,
1123 quiche::QuicheReferenceCountedPointer<Config> old_primary_config,
1124 Configs* configs) const {
1125 QuicReaderMutexLock locked(&configs_lock_);
1126
1127 if (!primary_config_) {
1128 return false;
1129 }
1130
1131 if (IsNextConfigReady(now)) {
1132 configs_lock_.ReaderUnlock();
1133 configs_lock_.WriterLock();
1134 SelectNewPrimaryConfig(now);
1135 QUICHE_DCHECK(primary_config_.get());
1136 QUICHE_DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
1137 primary_config_.get());
1138 configs_lock_.WriterUnlock();
1139 configs_lock_.ReaderLock();
1140 }
1141
1142 if (old_primary_config != nullptr) {
1143 configs->primary = old_primary_config;
1144 } else {
1145 configs->primary = primary_config_;
1146 }
1147 configs->requested = GetConfigWithScid(requested_scid);
1148 configs->fallback = fallback_config_;
1149
1150 return true;
1151 }
1152
1153 // ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
1154 // Config's based on their primary_time.
1155 // static
ConfigPrimaryTimeLessThan(const quiche::QuicheReferenceCountedPointer<Config> & a,const quiche::QuicheReferenceCountedPointer<Config> & b)1156 bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
1157 const quiche::QuicheReferenceCountedPointer<Config>& a,
1158 const quiche::QuicheReferenceCountedPointer<Config>& b) {
1159 if (a->primary_time.IsBefore(b->primary_time) ||
1160 b->primary_time.IsBefore(a->primary_time)) {
1161 // Primary times differ.
1162 return a->primary_time.IsBefore(b->primary_time);
1163 } else if (a->priority != b->priority) {
1164 // Primary times are equal, sort backwards by priority.
1165 return a->priority < b->priority;
1166 } else {
1167 // Primary times and priorities are equal, sort by config id.
1168 return a->id < b->id;
1169 }
1170 }
1171
SelectNewPrimaryConfig(const QuicWallTime now) const1172 void QuicCryptoServerConfig::SelectNewPrimaryConfig(
1173 const QuicWallTime now) const {
1174 std::vector<quiche::QuicheReferenceCountedPointer<Config>> configs;
1175 configs.reserve(configs_.size());
1176
1177 for (auto it = configs_.begin(); it != configs_.end(); ++it) {
1178 // TODO(avd) Exclude expired configs?
1179 configs.push_back(it->second);
1180 }
1181
1182 if (configs.empty()) {
1183 if (primary_config_ != nullptr) {
1184 QUIC_BUG(quic_bug_10630_2)
1185 << "No valid QUIC server config. Keeping the current config.";
1186 } else {
1187 QUIC_BUG(quic_bug_10630_3) << "No valid QUIC server config.";
1188 }
1189 return;
1190 }
1191
1192 std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan);
1193
1194 quiche::QuicheReferenceCountedPointer<Config> best_candidate = configs[0];
1195
1196 for (size_t i = 0; i < configs.size(); ++i) {
1197 const quiche::QuicheReferenceCountedPointer<Config> config(configs[i]);
1198 if (!config->primary_time.IsAfter(now)) {
1199 if (config->primary_time.IsAfter(best_candidate->primary_time)) {
1200 best_candidate = config;
1201 }
1202 continue;
1203 }
1204
1205 // This is the first config with a primary_time in the future. Thus the
1206 // previous Config should be the primary and this one should determine the
1207 // next_config_promotion_time_.
1208 quiche::QuicheReferenceCountedPointer<Config> new_primary = best_candidate;
1209 if (i == 0) {
1210 // We need the primary_time of the next config.
1211 if (configs.size() > 1) {
1212 next_config_promotion_time_ = configs[1]->primary_time;
1213 } else {
1214 next_config_promotion_time_ = QuicWallTime::Zero();
1215 }
1216 } else {
1217 next_config_promotion_time_ = config->primary_time;
1218 }
1219
1220 if (primary_config_) {
1221 primary_config_->is_primary = false;
1222 }
1223 primary_config_ = new_primary;
1224 new_primary->is_primary = true;
1225 QUIC_DLOG(INFO) << "New primary config. orbit: "
1226 << absl::BytesToHexString(
1227 absl::string_view(reinterpret_cast<const char*>(
1228 primary_config_->orbit),
1229 kOrbitSize));
1230 if (primary_config_changed_cb_ != nullptr) {
1231 primary_config_changed_cb_->Run(primary_config_->id);
1232 }
1233
1234 return;
1235 }
1236
1237 // All config's primary times are in the past. We should make the most recent
1238 // and highest priority candidate primary.
1239 quiche::QuicheReferenceCountedPointer<Config> new_primary = best_candidate;
1240 if (primary_config_) {
1241 primary_config_->is_primary = false;
1242 }
1243 primary_config_ = new_primary;
1244 new_primary->is_primary = true;
1245 QUIC_DLOG(INFO) << "New primary config. orbit: "
1246 << absl::BytesToHexString(absl::string_view(
1247 reinterpret_cast<const char*>(primary_config_->orbit),
1248 kOrbitSize))
1249 << " scid: " << absl::BytesToHexString(primary_config_->id);
1250 next_config_promotion_time_ = QuicWallTime::Zero();
1251 if (primary_config_changed_cb_ != nullptr) {
1252 primary_config_changed_cb_->Run(primary_config_->id);
1253 }
1254 }
1255
EvaluateClientHello(const QuicSocketAddress &,const QuicSocketAddress &,QuicTransportVersion,const Configs & configs,quiche::QuicheReferenceCountedPointer<ValidateClientHelloResultCallback::Result> client_hello_state,std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const1256 void QuicCryptoServerConfig::EvaluateClientHello(
1257 const QuicSocketAddress& /*server_address*/,
1258 const QuicSocketAddress& /*client_address*/,
1259 QuicTransportVersion /*version*/, const Configs& configs,
1260 quiche::QuicheReferenceCountedPointer<
1261 ValidateClientHelloResultCallback::Result>
1262 client_hello_state,
1263 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
1264 ValidateClientHelloHelper helper(client_hello_state, &done_cb);
1265
1266 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
1267 ClientHelloInfo* info = &(client_hello_state->info);
1268
1269 if (client_hello.GetStringPiece(kSNI, &info->sni) &&
1270 !QuicHostnameUtils::IsValidSNI(info->sni)) {
1271 helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
1272 "Invalid SNI name", nullptr);
1273 return;
1274 }
1275
1276 client_hello.GetStringPiece(kUAID, &info->user_agent_id);
1277
1278 HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
1279 if (validate_source_address_token_) {
1280 absl::string_view srct;
1281 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
1282 Config& config =
1283 configs.requested != nullptr ? *configs.requested : *configs.primary;
1284 source_address_token_error =
1285 ParseSourceAddressToken(*config.source_address_token_boxer, srct,
1286 info->source_address_tokens);
1287
1288 if (source_address_token_error == HANDSHAKE_OK) {
1289 source_address_token_error = ValidateSourceAddressTokens(
1290 info->source_address_tokens, info->client_ip, info->now,
1291 &client_hello_state->cached_network_params);
1292 }
1293 info->valid_source_address_token =
1294 (source_address_token_error == HANDSHAKE_OK);
1295 } else {
1296 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
1297 }
1298 } else {
1299 source_address_token_error = HANDSHAKE_OK;
1300 info->valid_source_address_token = true;
1301 }
1302
1303 if (!configs.requested) {
1304 absl::string_view requested_scid;
1305 if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
1306 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
1307 } else {
1308 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1309 }
1310 // No server config with the requested ID.
1311 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1312 return;
1313 }
1314
1315 if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) {
1316 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
1317 // Report no client nonce as INCHOATE_HELLO_FAILURE.
1318 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
1319 return;
1320 }
1321
1322 if (source_address_token_error != HANDSHAKE_OK) {
1323 info->reject_reasons.push_back(source_address_token_error);
1324 // No valid source address token.
1325 }
1326
1327 if (info->client_nonce.size() != kNonceSize) {
1328 info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
1329 // Invalid client nonce.
1330 QUIC_LOG_FIRST_N(ERROR, 2)
1331 << "Invalid client nonce: " << client_hello.DebugString();
1332 QUIC_DLOG(INFO) << "Invalid client nonce.";
1333 }
1334
1335 // Server nonce is optional, and used for key derivation if present.
1336 client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
1337
1338 // If the server nonce is empty and we're requiring handshake confirmation
1339 // for DoS reasons then we must reject the CHLO.
1340 if (GetQuicReloadableFlag(quic_require_handshake_confirmation) &&
1341 info->server_nonce.empty()) {
1342 QUIC_RELOADABLE_FLAG_COUNT(quic_require_handshake_confirmation);
1343 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
1344 }
1345 helper.ValidationComplete(QUIC_NO_ERROR, "",
1346 std::unique_ptr<ProofSource::Details>());
1347 }
1348
BuildServerConfigUpdateMessage(QuicTransportVersion version,absl::string_view chlo_hash,const SourceAddressTokens & previous_source_address_tokens,const QuicSocketAddress & server_address,const QuicSocketAddress & client_address,const QuicClock * clock,QuicRandom * rand,QuicCompressedCertsCache * compressed_certs_cache,const QuicCryptoNegotiatedParameters & params,const CachedNetworkParameters * cached_network_params,std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const1349 void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
1350 QuicTransportVersion version, absl::string_view chlo_hash,
1351 const SourceAddressTokens& previous_source_address_tokens,
1352 const QuicSocketAddress& server_address,
1353 const QuicSocketAddress& client_address, const QuicClock* clock,
1354 QuicRandom* rand, QuicCompressedCertsCache* compressed_certs_cache,
1355 const QuicCryptoNegotiatedParameters& params,
1356 const CachedNetworkParameters* cached_network_params,
1357 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
1358 std::string serialized;
1359 std::string source_address_token;
1360 {
1361 QuicReaderMutexLock locked(&configs_lock_);
1362 serialized = primary_config_->serialized;
1363 source_address_token = NewSourceAddressToken(
1364 *primary_config_->source_address_token_boxer,
1365 previous_source_address_tokens, client_address.host(), rand,
1366 clock->WallNow(), cached_network_params);
1367 }
1368
1369 CryptoHandshakeMessage message;
1370 message.set_tag(kSCUP);
1371 message.SetStringPiece(kSCFG, serialized);
1372 message.SetStringPiece(kSourceAddressTokenTag, source_address_token);
1373
1374 auto proof_source_cb =
1375 std::make_unique<BuildServerConfigUpdateMessageProofSourceCallback>(
1376 this, compressed_certs_cache, params, std::move(message),
1377 std::move(cb));
1378
1379 proof_source_->GetProof(server_address, client_address, params.sni,
1380 serialized, version, chlo_hash,
1381 std::move(proof_source_cb));
1382 }
1383
1384 QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
~BuildServerConfigUpdateMessageProofSourceCallback()1385 ~BuildServerConfigUpdateMessageProofSourceCallback() {}
1386
1387 QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
BuildServerConfigUpdateMessageProofSourceCallback(const QuicCryptoServerConfig * config,QuicCompressedCertsCache * compressed_certs_cache,const QuicCryptoNegotiatedParameters & params,CryptoHandshakeMessage message,std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb)1388 BuildServerConfigUpdateMessageProofSourceCallback(
1389 const QuicCryptoServerConfig* config,
1390 QuicCompressedCertsCache* compressed_certs_cache,
1391 const QuicCryptoNegotiatedParameters& params,
1392 CryptoHandshakeMessage message,
1393 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb)
1394 : config_(config),
1395 compressed_certs_cache_(compressed_certs_cache),
1396 client_cached_cert_hashes_(params.client_cached_cert_hashes),
1397 sct_supported_by_client_(params.sct_supported_by_client),
1398 sni_(params.sni),
1399 message_(std::move(message)),
1400 cb_(std::move(cb)) {}
1401
1402 void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
Run(bool ok,const quiche::QuicheReferenceCountedPointer<ProofSource::Chain> & chain,const QuicCryptoProof & proof,std::unique_ptr<ProofSource::Details> details)1403 Run(bool ok,
1404 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain,
1405 const QuicCryptoProof& proof,
1406 std::unique_ptr<ProofSource::Details> details) {
1407 config_->FinishBuildServerConfigUpdateMessage(
1408 compressed_certs_cache_, client_cached_cert_hashes_,
1409 sct_supported_by_client_, sni_, ok, chain, proof.signature,
1410 proof.leaf_cert_scts, std::move(details), std::move(message_),
1411 std::move(cb_));
1412 }
1413
FinishBuildServerConfigUpdateMessage(QuicCompressedCertsCache * compressed_certs_cache,const std::string & client_cached_cert_hashes,bool sct_supported_by_client,const std::string & sni,bool ok,const quiche::QuicheReferenceCountedPointer<ProofSource::Chain> & chain,const std::string & signature,const std::string & leaf_cert_sct,std::unique_ptr<ProofSource::Details>,CryptoHandshakeMessage message,std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const1414 void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage(
1415 QuicCompressedCertsCache* compressed_certs_cache,
1416 const std::string& client_cached_cert_hashes, bool sct_supported_by_client,
1417 const std::string& sni, bool ok,
1418 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain,
1419 const std::string& signature, const std::string& leaf_cert_sct,
1420 std::unique_ptr<ProofSource::Details> /*details*/,
1421 CryptoHandshakeMessage message,
1422 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
1423 if (!ok) {
1424 cb->Run(false, message);
1425 return;
1426 }
1427
1428 const std::string compressed =
1429 CompressChain(compressed_certs_cache, chain, client_cached_cert_hashes);
1430
1431 message.SetStringPiece(kCertificateTag, compressed);
1432 message.SetStringPiece(kPROF, signature);
1433 if (sct_supported_by_client && enable_serving_sct_) {
1434 if (leaf_cert_sct.empty()) {
1435 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
1436 << "SCT is expected but it is empty. SNI: " << sni;
1437 } else {
1438 message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct);
1439 }
1440 }
1441
1442 cb->Run(true, message);
1443 }
1444
BuildRejectionAndRecordStats(const ProcessClientHelloContext & context,const Config & config,const std::vector<uint32_t> & reject_reasons,CryptoHandshakeMessage * out) const1445 void QuicCryptoServerConfig::BuildRejectionAndRecordStats(
1446 const ProcessClientHelloContext& context, const Config& config,
1447 const std::vector<uint32_t>& reject_reasons,
1448 CryptoHandshakeMessage* out) const {
1449 BuildRejection(context, config, reject_reasons, out);
1450 if (rejection_observer_ != nullptr) {
1451 rejection_observer_->OnRejectionBuilt(reject_reasons, out);
1452 }
1453 }
1454
BuildRejection(const ProcessClientHelloContext & context,const Config & config,const std::vector<uint32_t> & reject_reasons,CryptoHandshakeMessage * out) const1455 void QuicCryptoServerConfig::BuildRejection(
1456 const ProcessClientHelloContext& context, const Config& config,
1457 const std::vector<uint32_t>& reject_reasons,
1458 CryptoHandshakeMessage* out) const {
1459 const QuicWallTime now = context.clock()->WallNow();
1460
1461 out->set_tag(kREJ);
1462 out->SetStringPiece(kSCFG, config.serialized);
1463 out->SetStringPiece(
1464 kSourceAddressTokenTag,
1465 NewSourceAddressToken(
1466 *config.source_address_token_boxer,
1467 context.info().source_address_tokens, context.info().client_ip,
1468 context.rand(), context.info().now,
1469 &context.validate_chlo_result()->cached_network_params));
1470 out->SetValue(kSTTL, config.expiry_time.AbsoluteDifference(now).ToSeconds());
1471 if (replay_protection_) {
1472 out->SetStringPiece(kServerNonceTag,
1473 NewServerNonce(context.rand(), context.info().now));
1474 }
1475
1476 // Send client the reject reason for debugging purposes.
1477 QUICHE_DCHECK_LT(0u, reject_reasons.size());
1478 out->SetVector(kRREJ, reject_reasons);
1479
1480 // The client may have requested a certificate chain.
1481 if (!ClientDemandsX509Proof(context.client_hello())) {
1482 QUIC_BUG(quic_bug_10630_4)
1483 << "x509 certificates not supported in proof demand";
1484 return;
1485 }
1486
1487 absl::string_view client_cached_cert_hashes;
1488 if (context.client_hello().GetStringPiece(kCCRT,
1489 &client_cached_cert_hashes)) {
1490 context.params()->client_cached_cert_hashes =
1491 std::string(client_cached_cert_hashes);
1492 } else {
1493 context.params()->client_cached_cert_hashes.clear();
1494 }
1495
1496 const std::string compressed = CompressChain(
1497 context.compressed_certs_cache(), context.signed_config()->chain,
1498 context.params()->client_cached_cert_hashes);
1499
1500 QUICHE_DCHECK_GT(context.chlo_packet_size(), context.client_hello().size());
1501 // kREJOverheadBytes is a very rough estimate of how much of a REJ
1502 // message is taken up by things other than the certificates.
1503 // STK: 56 bytes
1504 // SNO: 56 bytes
1505 // SCFG
1506 // SCID: 16 bytes
1507 // PUBS: 38 bytes
1508 const size_t kREJOverheadBytes = 166;
1509 // max_unverified_size is the number of bytes that the certificate chain,
1510 // signature, and (optionally) signed certificate timestamp can consume before
1511 // we will demand a valid source-address token.
1512 const size_t max_unverified_size =
1513 chlo_multiplier_ *
1514 (context.chlo_packet_size() - context.total_framing_overhead()) -
1515 kREJOverheadBytes;
1516 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
1517 "overhead calculation may underflow");
1518 bool should_return_sct =
1519 context.params()->sct_supported_by_client && enable_serving_sct_;
1520 const std::string& cert_sct = context.signed_config()->proof.leaf_cert_scts;
1521 const size_t sct_size = should_return_sct ? cert_sct.size() : 0;
1522 const size_t total_size = context.signed_config()->proof.signature.size() +
1523 compressed.size() + sct_size;
1524 if (context.info().valid_source_address_token ||
1525 total_size < max_unverified_size) {
1526 out->SetStringPiece(kCertificateTag, compressed);
1527 out->SetStringPiece(kPROF, context.signed_config()->proof.signature);
1528 if (should_return_sct) {
1529 if (cert_sct.empty()) {
1530 // Log SNI and subject name for the leaf cert if its SCT is empty.
1531 // This is for debugging b/28342827.
1532 const std::vector<std::string>& certs =
1533 context.signed_config()->chain->certs;
1534 std::string ca_subject;
1535 if (!certs.empty()) {
1536 std::unique_ptr<CertificateView> view =
1537 CertificateView::ParseSingleCertificate(certs[0]);
1538 if (view != nullptr) {
1539 std::optional<std::string> maybe_ca_subject =
1540 view->GetHumanReadableSubject();
1541 if (maybe_ca_subject.has_value()) {
1542 ca_subject = *maybe_ca_subject;
1543 }
1544 }
1545 }
1546 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
1547 << "SCT is expected but it is empty. sni: '"
1548 << context.params()->sni << "' cert subject: '" << ca_subject
1549 << "'";
1550 } else {
1551 out->SetStringPiece(kCertificateSCTTag, cert_sct);
1552 }
1553 }
1554 } else {
1555 QUIC_LOG_EVERY_N_SEC(WARNING, 60)
1556 << "Sending inchoate REJ for hostname: " << context.info().sni
1557 << " signature: " << context.signed_config()->proof.signature.size()
1558 << " cert: " << compressed.size() << " sct:" << sct_size
1559 << " total: " << total_size << " max: " << max_unverified_size;
1560 }
1561 }
1562
CompressChain(QuicCompressedCertsCache * compressed_certs_cache,const quiche::QuicheReferenceCountedPointer<ProofSource::Chain> & chain,const std::string & client_cached_cert_hashes)1563 std::string QuicCryptoServerConfig::CompressChain(
1564 QuicCompressedCertsCache* compressed_certs_cache,
1565 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain,
1566 const std::string& client_cached_cert_hashes) {
1567 // Check whether the compressed certs is available in the cache.
1568 QUICHE_DCHECK(compressed_certs_cache);
1569 const std::string* cached_value = compressed_certs_cache->GetCompressedCert(
1570 chain, client_cached_cert_hashes);
1571 if (cached_value) {
1572 return *cached_value;
1573 }
1574 std::string compressed =
1575 CertCompressor::CompressChain(chain->certs, client_cached_cert_hashes);
1576 // Insert the newly compressed cert to cache.
1577 compressed_certs_cache->Insert(chain, client_cached_cert_hashes, compressed);
1578 return compressed;
1579 }
1580
1581 quiche::QuicheReferenceCountedPointer<QuicCryptoServerConfig::Config>
ParseConfigProtobuf(const QuicServerConfigProtobuf & protobuf,bool is_fallback) const1582 QuicCryptoServerConfig::ParseConfigProtobuf(
1583 const QuicServerConfigProtobuf& protobuf, bool is_fallback) const {
1584 std::unique_ptr<CryptoHandshakeMessage> msg =
1585 CryptoFramer::ParseMessage(protobuf.config());
1586
1587 if (!msg) {
1588 QUIC_LOG(WARNING) << "Failed to parse server config message";
1589 return nullptr;
1590 }
1591
1592 if (msg->tag() != kSCFG) {
1593 QUIC_LOG(WARNING) << "Server config message has tag " << msg->tag()
1594 << ", but expected " << kSCFG;
1595 return nullptr;
1596 }
1597
1598 quiche::QuicheReferenceCountedPointer<Config> config(new Config);
1599 config->serialized = protobuf.config();
1600 config->source_address_token_boxer = &source_address_token_boxer_;
1601
1602 if (protobuf.has_primary_time()) {
1603 config->primary_time =
1604 QuicWallTime::FromUNIXSeconds(protobuf.primary_time());
1605 }
1606
1607 config->priority = protobuf.priority();
1608
1609 absl::string_view scid;
1610 if (!msg->GetStringPiece(kSCID, &scid)) {
1611 QUIC_LOG(WARNING) << "Server config message is missing SCID";
1612 return nullptr;
1613 }
1614 if (scid.empty()) {
1615 QUIC_LOG(WARNING) << "Server config message contains an empty SCID";
1616 return nullptr;
1617 }
1618 config->id = std::string(scid);
1619
1620 if (msg->GetTaglist(kAEAD, &config->aead) != QUIC_NO_ERROR) {
1621 QUIC_LOG(WARNING) << "Server config message is missing AEAD";
1622 return nullptr;
1623 }
1624
1625 QuicTagVector kexs_tags;
1626 if (msg->GetTaglist(kKEXS, &kexs_tags) != QUIC_NO_ERROR) {
1627 QUIC_LOG(WARNING) << "Server config message is missing KEXS";
1628 return nullptr;
1629 }
1630
1631 absl::string_view orbit;
1632 if (!msg->GetStringPiece(kORBT, &orbit)) {
1633 QUIC_LOG(WARNING) << "Server config message is missing ORBT";
1634 return nullptr;
1635 }
1636
1637 if (orbit.size() != kOrbitSize) {
1638 QUIC_LOG(WARNING) << "Orbit value in server config is the wrong length."
1639 " Got "
1640 << orbit.size() << " want " << kOrbitSize;
1641 return nullptr;
1642 }
1643 static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size");
1644 memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
1645
1646 QuicTagVector proof_demand_tags;
1647 if (msg->GetTaglist(kPDMD, &proof_demand_tags) == QUIC_NO_ERROR) {
1648 for (QuicTag tag : proof_demand_tags) {
1649 if (tag == kCHID) {
1650 config->channel_id_enabled = true;
1651 break;
1652 }
1653 }
1654 }
1655
1656 for (size_t i = 0; i < kexs_tags.size(); i++) {
1657 const QuicTag tag = kexs_tags[i];
1658 std::string private_key;
1659
1660 config->kexs.push_back(tag);
1661
1662 for (int j = 0; j < protobuf.key_size(); j++) {
1663 const QuicServerConfigProtobuf::PrivateKey& key = protobuf.key(i);
1664 if (key.tag() == tag) {
1665 private_key = key.private_key();
1666 break;
1667 }
1668 }
1669
1670 std::unique_ptr<AsynchronousKeyExchange> ka =
1671 key_exchange_source_->Create(config->id, is_fallback, tag, private_key);
1672 if (!ka) {
1673 return nullptr;
1674 }
1675 for (const auto& key_exchange : config->key_exchanges) {
1676 if (key_exchange->type() == tag) {
1677 QUIC_LOG(WARNING) << "Duplicate key exchange in config: " << tag;
1678 return nullptr;
1679 }
1680 }
1681
1682 config->key_exchanges.push_back(std::move(ka));
1683 }
1684
1685 uint64_t expiry_seconds;
1686 if (msg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
1687 QUIC_LOG(WARNING) << "Server config message is missing EXPY";
1688 return nullptr;
1689 }
1690 config->expiry_time = QuicWallTime::FromUNIXSeconds(expiry_seconds);
1691
1692 return config;
1693 }
1694
set_replay_protection(bool on)1695 void QuicCryptoServerConfig::set_replay_protection(bool on) {
1696 replay_protection_ = on;
1697 }
1698
set_chlo_multiplier(size_t multiplier)1699 void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) {
1700 chlo_multiplier_ = multiplier;
1701 }
1702
set_source_address_token_future_secs(uint32_t future_secs)1703 void QuicCryptoServerConfig::set_source_address_token_future_secs(
1704 uint32_t future_secs) {
1705 source_address_token_future_secs_ = future_secs;
1706 }
1707
set_source_address_token_lifetime_secs(uint32_t lifetime_secs)1708 void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
1709 uint32_t lifetime_secs) {
1710 source_address_token_lifetime_secs_ = lifetime_secs;
1711 }
1712
set_enable_serving_sct(bool enable_serving_sct)1713 void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) {
1714 enable_serving_sct_ = enable_serving_sct;
1715 }
1716
AcquirePrimaryConfigChangedCb(std::unique_ptr<PrimaryConfigChangedCallback> cb)1717 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
1718 std::unique_ptr<PrimaryConfigChangedCallback> cb) {
1719 QuicWriterMutexLock locked(&configs_lock_);
1720 primary_config_changed_cb_ = std::move(cb);
1721 }
1722
NewSourceAddressToken(const CryptoSecretBoxer & crypto_secret_boxer,const SourceAddressTokens & previous_tokens,const QuicIpAddress & ip,QuicRandom * rand,QuicWallTime now,const CachedNetworkParameters * cached_network_params) const1723 std::string QuicCryptoServerConfig::NewSourceAddressToken(
1724 const CryptoSecretBoxer& crypto_secret_boxer,
1725 const SourceAddressTokens& previous_tokens, const QuicIpAddress& ip,
1726 QuicRandom* rand, QuicWallTime now,
1727 const CachedNetworkParameters* cached_network_params) const {
1728 SourceAddressTokens source_address_tokens;
1729 SourceAddressToken* source_address_token = source_address_tokens.add_tokens();
1730 source_address_token->set_ip(ip.DualStacked().ToPackedString());
1731 source_address_token->set_timestamp(now.ToUNIXSeconds());
1732 if (cached_network_params != nullptr) {
1733 *(source_address_token->mutable_cached_network_parameters()) =
1734 *cached_network_params;
1735 }
1736
1737 // Append previous tokens.
1738 for (const SourceAddressToken& token : previous_tokens.tokens()) {
1739 if (source_address_tokens.tokens_size() > kMaxTokenAddresses) {
1740 break;
1741 }
1742
1743 if (token.ip() == source_address_token->ip()) {
1744 // It's for the same IP address.
1745 continue;
1746 }
1747
1748 if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) {
1749 continue;
1750 }
1751
1752 *(source_address_tokens.add_tokens()) = token;
1753 }
1754
1755 return crypto_secret_boxer.Box(rand,
1756 source_address_tokens.SerializeAsString());
1757 }
1758
NumberOfConfigs() const1759 int QuicCryptoServerConfig::NumberOfConfigs() const {
1760 QuicReaderMutexLock locked(&configs_lock_);
1761 return configs_.size();
1762 }
1763
proof_source() const1764 ProofSource* QuicCryptoServerConfig::proof_source() const {
1765 return proof_source_.get();
1766 }
1767
ssl_ctx() const1768 SSL_CTX* QuicCryptoServerConfig::ssl_ctx() const { return ssl_ctx_.get(); }
1769
ParseSourceAddressToken(const CryptoSecretBoxer & crypto_secret_boxer,absl::string_view token,SourceAddressTokens & tokens) const1770 HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken(
1771 const CryptoSecretBoxer& crypto_secret_boxer, absl::string_view token,
1772 SourceAddressTokens& tokens) const {
1773 std::string storage;
1774 absl::string_view plaintext;
1775 if (!crypto_secret_boxer.Unbox(token, &storage, &plaintext)) {
1776 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
1777 }
1778
1779 if (!tokens.ParseFromArray(plaintext.data(), plaintext.size())) {
1780 // Some clients might still be using the old source token format so
1781 // attempt to parse that format.
1782 // TODO(rch): remove this code once the new format is ubiquitous.
1783 SourceAddressToken old_source_token;
1784 if (!old_source_token.ParseFromArray(plaintext.data(), plaintext.size())) {
1785 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
1786 }
1787 *tokens.add_tokens() = old_source_token;
1788 }
1789
1790 return HANDSHAKE_OK;
1791 }
1792
ValidateSourceAddressTokens(const SourceAddressTokens & source_address_tokens,const QuicIpAddress & ip,QuicWallTime now,CachedNetworkParameters * cached_network_params) const1793 HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens(
1794 const SourceAddressTokens& source_address_tokens, const QuicIpAddress& ip,
1795 QuicWallTime now, CachedNetworkParameters* cached_network_params) const {
1796 HandshakeFailureReason reason =
1797 SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1798 for (const SourceAddressToken& token : source_address_tokens.tokens()) {
1799 reason = ValidateSingleSourceAddressToken(token, ip, now);
1800 if (reason == HANDSHAKE_OK) {
1801 if (cached_network_params != nullptr &&
1802 token.has_cached_network_parameters()) {
1803 *cached_network_params = token.cached_network_parameters();
1804 }
1805 break;
1806 }
1807 }
1808 return reason;
1809 }
1810
ValidateSingleSourceAddressToken(const SourceAddressToken & source_address_token,const QuicIpAddress & ip,QuicWallTime now) const1811 HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken(
1812 const SourceAddressToken& source_address_token, const QuicIpAddress& ip,
1813 QuicWallTime now) const {
1814 if (source_address_token.ip() != ip.DualStacked().ToPackedString()) {
1815 // It's for a different IP address.
1816 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
1817 }
1818
1819 return ValidateSourceAddressTokenTimestamp(source_address_token, now);
1820 }
1821
1822 HandshakeFailureReason
ValidateSourceAddressTokenTimestamp(const SourceAddressToken & source_address_token,QuicWallTime now) const1823 QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp(
1824 const SourceAddressToken& source_address_token, QuicWallTime now) const {
1825 const QuicWallTime timestamp(
1826 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
1827 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
1828
1829 if (now.IsBefore(timestamp) &&
1830 delta.ToSeconds() > source_address_token_future_secs_) {
1831 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
1832 }
1833
1834 if (now.IsAfter(timestamp) &&
1835 delta.ToSeconds() > source_address_token_lifetime_secs_) {
1836 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
1837 }
1838
1839 return HANDSHAKE_OK;
1840 }
1841
1842 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server
1843 // nonce.
1844 static const size_t kServerNoncePlaintextSize =
1845 4 /* timestamp */ + 20 /* random bytes */;
1846
NewServerNonce(QuicRandom * rand,QuicWallTime now) const1847 std::string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
1848 QuicWallTime now) const {
1849 const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds());
1850
1851 uint8_t server_nonce[kServerNoncePlaintextSize];
1852 static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small");
1853 server_nonce[0] = static_cast<uint8_t>(timestamp >> 24);
1854 server_nonce[1] = static_cast<uint8_t>(timestamp >> 16);
1855 server_nonce[2] = static_cast<uint8_t>(timestamp >> 8);
1856 server_nonce[3] = static_cast<uint8_t>(timestamp);
1857 rand->RandBytes(&server_nonce[sizeof(timestamp)],
1858 sizeof(server_nonce) - sizeof(timestamp));
1859
1860 return server_nonce_boxer_.Box(
1861 rand, absl::string_view(reinterpret_cast<char*>(server_nonce),
1862 sizeof(server_nonce)));
1863 }
1864
ValidateExpectedLeafCertificate(const CryptoHandshakeMessage & client_hello,const std::vector<std::string> & certs) const1865 bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate(
1866 const CryptoHandshakeMessage& client_hello,
1867 const std::vector<std::string>& certs) const {
1868 if (certs.empty()) {
1869 return false;
1870 }
1871
1872 uint64_t hash_from_client;
1873 if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) {
1874 return false;
1875 }
1876 return CryptoUtils::ComputeLeafCertHash(certs[0]) == hash_from_client;
1877 }
1878
IsNextConfigReady(QuicWallTime now) const1879 bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const {
1880 return !next_config_promotion_time_.IsZero() &&
1881 !next_config_promotion_time_.IsAfter(now);
1882 }
1883
Config()1884 QuicCryptoServerConfig::Config::Config()
1885 : channel_id_enabled(false),
1886 is_primary(false),
1887 primary_time(QuicWallTime::Zero()),
1888 expiry_time(QuicWallTime::Zero()),
1889 priority(0),
1890 source_address_token_boxer(nullptr) {}
1891
~Config()1892 QuicCryptoServerConfig::Config::~Config() {}
1893
QuicSignedServerConfig()1894 QuicSignedServerConfig::QuicSignedServerConfig() {}
~QuicSignedServerConfig()1895 QuicSignedServerConfig::~QuicSignedServerConfig() {}
1896
1897 } // namespace quic
1898