| OLD | NEW |
| (Empty) |
| 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 "net/quic/crypto/quic_crypto_server_config.h" | |
| 6 | |
| 7 #include <stdlib.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 #include <memory> | |
| 11 | |
| 12 #include "base/macros.h" | |
| 13 #include "base/memory/ref_counted.h" | |
| 14 #include "base/stl_util.h" | |
| 15 #include "crypto/hkdf.h" | |
| 16 #include "crypto/secure_hash.h" | |
| 17 #include "net/base/ip_address.h" | |
| 18 #include "net/quic/crypto/aes_128_gcm_12_decrypter.h" | |
| 19 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" | |
| 20 #include "net/quic/crypto/cert_compressor.h" | |
| 21 #include "net/quic/crypto/chacha20_poly1305_encrypter.h" | |
| 22 #include "net/quic/crypto/channel_id.h" | |
| 23 #include "net/quic/crypto/crypto_framer.h" | |
| 24 #include "net/quic/crypto/crypto_handshake_message.h" | |
| 25 #include "net/quic/crypto/crypto_server_config_protobuf.h" | |
| 26 #include "net/quic/crypto/crypto_utils.h" | |
| 27 #include "net/quic/crypto/curve25519_key_exchange.h" | |
| 28 #include "net/quic/crypto/ephemeral_key_source.h" | |
| 29 #include "net/quic/crypto/key_exchange.h" | |
| 30 #include "net/quic/crypto/local_strike_register_client.h" | |
| 31 #include "net/quic/crypto/p256_key_exchange.h" | |
| 32 #include "net/quic/crypto/proof_source.h" | |
| 33 #include "net/quic/crypto/quic_decrypter.h" | |
| 34 #include "net/quic/crypto/quic_encrypter.h" | |
| 35 #include "net/quic/crypto/quic_random.h" | |
| 36 #include "net/quic/crypto/strike_register.h" | |
| 37 #include "net/quic/crypto/strike_register_client.h" | |
| 38 #include "net/quic/proto/source_address_token.pb.h" | |
| 39 #include "net/quic/quic_bug_tracker.h" | |
| 40 #include "net/quic/quic_clock.h" | |
| 41 #include "net/quic/quic_flags.h" | |
| 42 #include "net/quic/quic_protocol.h" | |
| 43 #include "net/quic/quic_socket_address_coder.h" | |
| 44 #include "net/quic/quic_utils.h" | |
| 45 | |
| 46 using base::StringPiece; | |
| 47 using crypto::SecureHash; | |
| 48 using std::map; | |
| 49 using std::sort; | |
| 50 using std::string; | |
| 51 using std::vector; | |
| 52 | |
| 53 namespace net { | |
| 54 | |
| 55 namespace { | |
| 56 | |
| 57 // kMultiplier is the multiple of the CHLO message size that a REJ message | |
| 58 // must stay under when the client doesn't present a valid source-address | |
| 59 // token. This is used to protect QUIC from amplification attacks. | |
| 60 // TODO(rch): Reduce this to 2 again once b/25933682 is fixed. | |
| 61 const size_t kMultiplier = 3; | |
| 62 | |
| 63 const int kMaxTokenAddresses = 4; | |
| 64 | |
| 65 string DeriveSourceAddressTokenKey(StringPiece source_address_token_secret) { | |
| 66 crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, | |
| 67 "QUIC source address token key", | |
| 68 CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */, | |
| 69 0 /* no subkey secret */); | |
| 70 return hkdf.server_write_key().as_string(); | |
| 71 } | |
| 72 | |
| 73 IPAddress DualstackIPAddress(const IPAddress& ip) { | |
| 74 if (ip.IsIPv4()) { | |
| 75 return ConvertIPv4ToIPv4MappedIPv6(ip); | |
| 76 } | |
| 77 return ip; | |
| 78 } | |
| 79 | |
| 80 } // namespace | |
| 81 | |
| 82 class ValidateClientHelloHelper { | |
| 83 public: | |
| 84 ValidateClientHelloHelper(ValidateClientHelloResultCallback::Result* result, | |
| 85 ValidateClientHelloResultCallback* done_cb) | |
| 86 : result_(result), done_cb_(done_cb) {} | |
| 87 | |
| 88 ~ValidateClientHelloHelper() { | |
| 89 QUIC_BUG_IF(done_cb_ != nullptr) | |
| 90 << "Deleting ValidateClientHelloHelper with a pending callback."; | |
| 91 } | |
| 92 | |
| 93 void ValidationComplete( | |
| 94 QuicErrorCode error_code, | |
| 95 const char* error_details, | |
| 96 std::unique_ptr<ProofSource::Details> proof_source_details) { | |
| 97 result_->error_code = error_code; | |
| 98 result_->error_details = error_details; | |
| 99 done_cb_->Run(result_, std::move(proof_source_details)); | |
| 100 DetachCallback(); | |
| 101 } | |
| 102 | |
| 103 void DetachCallback() { | |
| 104 QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached."; | |
| 105 done_cb_ = nullptr; | |
| 106 } | |
| 107 | |
| 108 private: | |
| 109 ValidateClientHelloResultCallback::Result* result_; | |
| 110 ValidateClientHelloResultCallback* done_cb_; | |
| 111 | |
| 112 DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloHelper); | |
| 113 }; | |
| 114 | |
| 115 class VerifyNonceIsValidAndUniqueCallback | |
| 116 : public StrikeRegisterClient::ResultCallback { | |
| 117 public: | |
| 118 VerifyNonceIsValidAndUniqueCallback( | |
| 119 ValidateClientHelloResultCallback::Result* result, | |
| 120 std::unique_ptr<ProofSource::Details> proof_source_details, | |
| 121 ValidateClientHelloResultCallback* done_cb) | |
| 122 : result_(result), | |
| 123 proof_source_details_(std::move(proof_source_details)), | |
| 124 done_cb_(done_cb) {} | |
| 125 | |
| 126 protected: | |
| 127 void RunImpl(bool nonce_is_valid_and_unique, | |
| 128 InsertStatus nonce_error) override { | |
| 129 DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique | |
| 130 << " nonce_error: " << nonce_error; | |
| 131 if (!nonce_is_valid_and_unique) { | |
| 132 HandshakeFailureReason client_nonce_error; | |
| 133 switch (nonce_error) { | |
| 134 case NONCE_INVALID_FAILURE: | |
| 135 client_nonce_error = CLIENT_NONCE_INVALID_FAILURE; | |
| 136 break; | |
| 137 case NONCE_NOT_UNIQUE_FAILURE: | |
| 138 client_nonce_error = CLIENT_NONCE_NOT_UNIQUE_FAILURE; | |
| 139 break; | |
| 140 case NONCE_INVALID_ORBIT_FAILURE: | |
| 141 client_nonce_error = CLIENT_NONCE_INVALID_ORBIT_FAILURE; | |
| 142 break; | |
| 143 case NONCE_INVALID_TIME_FAILURE: | |
| 144 client_nonce_error = CLIENT_NONCE_INVALID_TIME_FAILURE; | |
| 145 break; | |
| 146 case STRIKE_REGISTER_TIMEOUT: | |
| 147 client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT; | |
| 148 break; | |
| 149 case STRIKE_REGISTER_FAILURE: | |
| 150 client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_FAILURE; | |
| 151 break; | |
| 152 case NONCE_UNKNOWN_FAILURE: | |
| 153 client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE; | |
| 154 break; | |
| 155 case NONCE_OK: | |
| 156 default: | |
| 157 QUIC_BUG << "Unexpected client nonce error: " << nonce_error; | |
| 158 client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE; | |
| 159 break; | |
| 160 } | |
| 161 result_->info.reject_reasons.push_back(client_nonce_error); | |
| 162 } | |
| 163 done_cb_->Run(result_, std::move(proof_source_details_)); | |
| 164 } | |
| 165 | |
| 166 private: | |
| 167 ValidateClientHelloResultCallback::Result* result_; | |
| 168 std::unique_ptr<ProofSource::Details> proof_source_details_; | |
| 169 ValidateClientHelloResultCallback* done_cb_; | |
| 170 | |
| 171 DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback); | |
| 172 }; | |
| 173 | |
| 174 // static | |
| 175 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing"; | |
| 176 | |
| 177 ClientHelloInfo::ClientHelloInfo(const IPAddress& in_client_ip, | |
| 178 QuicWallTime in_now) | |
| 179 : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {} | |
| 180 | |
| 181 ClientHelloInfo::~ClientHelloInfo() {} | |
| 182 | |
| 183 PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {} | |
| 184 | |
| 185 PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {} | |
| 186 | |
| 187 ValidateClientHelloResultCallback::Result::Result( | |
| 188 const CryptoHandshakeMessage& in_client_hello, | |
| 189 IPAddress in_client_ip, | |
| 190 QuicWallTime in_now) | |
| 191 : client_hello(in_client_hello), | |
| 192 info(in_client_ip, in_now), | |
| 193 error_code(QUIC_NO_ERROR) {} | |
| 194 | |
| 195 ValidateClientHelloResultCallback::Result::~Result() {} | |
| 196 | |
| 197 ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {} | |
| 198 | |
| 199 ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {} | |
| 200 | |
| 201 void ValidateClientHelloResultCallback::Run( | |
| 202 const Result* result, | |
| 203 std::unique_ptr<ProofSource::Details> details) { | |
| 204 RunImpl(result->client_hello, *result, std::move(details)); | |
| 205 delete result; | |
| 206 delete this; | |
| 207 } | |
| 208 | |
| 209 QuicCryptoServerConfig::ConfigOptions::ConfigOptions() | |
| 210 : expiry_time(QuicWallTime::Zero()), | |
| 211 channel_id_enabled(false), | |
| 212 token_binding_enabled(false), | |
| 213 p256(false) {} | |
| 214 | |
| 215 QuicCryptoServerConfig::ConfigOptions::ConfigOptions( | |
| 216 const ConfigOptions& other) = default; | |
| 217 | |
| 218 QuicCryptoServerConfig::QuicCryptoServerConfig( | |
| 219 StringPiece source_address_token_secret, | |
| 220 QuicRandom* server_nonce_entropy, | |
| 221 std::unique_ptr<ProofSource> proof_source) | |
| 222 : replay_protection_(true), | |
| 223 chlo_multiplier_(kMultiplier), | |
| 224 configs_lock_(), | |
| 225 primary_config_(nullptr), | |
| 226 next_config_promotion_time_(QuicWallTime::Zero()), | |
| 227 server_nonce_strike_register_lock_(), | |
| 228 proof_source_(std::move(proof_source)), | |
| 229 strike_register_no_startup_period_(false), | |
| 230 strike_register_max_entries_(1 << 10), | |
| 231 strike_register_window_secs_(600), | |
| 232 source_address_token_future_secs_(3600), | |
| 233 source_address_token_lifetime_secs_(86400), | |
| 234 server_nonce_strike_register_max_entries_(1 << 10), | |
| 235 server_nonce_strike_register_window_secs_(120), | |
| 236 enable_serving_sct_(false) { | |
| 237 DCHECK(proof_source_.get()); | |
| 238 default_source_address_token_boxer_.SetKeys( | |
| 239 {DeriveSourceAddressTokenKey(source_address_token_secret)}); | |
| 240 | |
| 241 // Generate a random key and orbit for server nonces. | |
| 242 server_nonce_entropy->RandBytes(server_nonce_orbit_, | |
| 243 sizeof(server_nonce_orbit_)); | |
| 244 const size_t key_size = server_nonce_boxer_.GetKeySize(); | |
| 245 std::unique_ptr<uint8_t[]> key_bytes(new uint8_t[key_size]); | |
| 246 server_nonce_entropy->RandBytes(key_bytes.get(), key_size); | |
| 247 | |
| 248 server_nonce_boxer_.SetKeys( | |
| 249 {string(reinterpret_cast<char*>(key_bytes.get()), key_size)}); | |
| 250 } | |
| 251 | |
| 252 QuicCryptoServerConfig::~QuicCryptoServerConfig() { | |
| 253 primary_config_ = nullptr; | |
| 254 } | |
| 255 | |
| 256 // static | |
| 257 QuicServerConfigProtobuf* QuicCryptoServerConfig::GenerateConfig( | |
| 258 QuicRandom* rand, | |
| 259 const QuicClock* clock, | |
| 260 const ConfigOptions& options) { | |
| 261 CryptoHandshakeMessage msg; | |
| 262 | |
| 263 const string curve25519_private_key = | |
| 264 Curve25519KeyExchange::NewPrivateKey(rand); | |
| 265 std::unique_ptr<Curve25519KeyExchange> curve25519( | |
| 266 Curve25519KeyExchange::New(curve25519_private_key)); | |
| 267 StringPiece curve25519_public_value = curve25519->public_value(); | |
| 268 | |
| 269 string encoded_public_values; | |
| 270 // First three bytes encode the length of the public value. | |
| 271 DCHECK_LT(curve25519_public_value.size(), (1U << 24)); | |
| 272 encoded_public_values.push_back( | |
| 273 static_cast<char>(curve25519_public_value.size())); | |
| 274 encoded_public_values.push_back( | |
| 275 static_cast<char>(curve25519_public_value.size() >> 8)); | |
| 276 encoded_public_values.push_back( | |
| 277 static_cast<char>(curve25519_public_value.size() >> 16)); | |
| 278 encoded_public_values.append(curve25519_public_value.data(), | |
| 279 curve25519_public_value.size()); | |
| 280 | |
| 281 string p256_private_key; | |
| 282 if (options.p256) { | |
| 283 p256_private_key = P256KeyExchange::NewPrivateKey(); | |
| 284 std::unique_ptr<P256KeyExchange> p256( | |
| 285 P256KeyExchange::New(p256_private_key)); | |
| 286 StringPiece p256_public_value = p256->public_value(); | |
| 287 | |
| 288 DCHECK_LT(p256_public_value.size(), (1U << 24)); | |
| 289 encoded_public_values.push_back( | |
| 290 static_cast<char>(p256_public_value.size())); | |
| 291 encoded_public_values.push_back( | |
| 292 static_cast<char>(p256_public_value.size() >> 8)); | |
| 293 encoded_public_values.push_back( | |
| 294 static_cast<char>(p256_public_value.size() >> 16)); | |
| 295 encoded_public_values.append(p256_public_value.data(), | |
| 296 p256_public_value.size()); | |
| 297 } | |
| 298 | |
| 299 msg.set_tag(kSCFG); | |
| 300 if (options.p256) { | |
| 301 msg.SetVector(kKEXS, QuicTagVector{kC255, kP256}); | |
| 302 } else { | |
| 303 msg.SetVector(kKEXS, QuicTagVector{kC255}); | |
| 304 } | |
| 305 msg.SetVector(kAEAD, QuicTagVector{kAESG, kCC20}); | |
| 306 msg.SetStringPiece(kPUBS, encoded_public_values); | |
| 307 | |
| 308 if (options.expiry_time.IsZero()) { | |
| 309 const QuicWallTime now = clock->WallNow(); | |
| 310 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds( | |
| 311 60 * 60 * 24 * 180 /* 180 days, ~six months */)); | |
| 312 const uint64_t expiry_seconds = expiry.ToUNIXSeconds(); | |
| 313 msg.SetValue(kEXPY, expiry_seconds); | |
| 314 } else { | |
| 315 msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds()); | |
| 316 } | |
| 317 | |
| 318 char orbit_bytes[kOrbitSize]; | |
| 319 if (options.orbit.size() == sizeof(orbit_bytes)) { | |
| 320 memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes)); | |
| 321 } else { | |
| 322 DCHECK(options.orbit.empty()); | |
| 323 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes)); | |
| 324 } | |
| 325 msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes))); | |
| 326 | |
| 327 if (options.channel_id_enabled) { | |
| 328 msg.SetVector(kPDMD, QuicTagVector{kCHID}); | |
| 329 } | |
| 330 | |
| 331 if (options.token_binding_enabled) { | |
| 332 msg.SetVector(kTBKP, QuicTagVector{kP256}); | |
| 333 } | |
| 334 | |
| 335 if (options.id.empty()) { | |
| 336 // We need to ensure that the SCID changes whenever the server config does | |
| 337 // thus we make it a hash of the rest of the server config. | |
| 338 std::unique_ptr<QuicData> serialized( | |
| 339 CryptoFramer::ConstructHandshakeMessage(msg)); | |
| 340 std::unique_ptr<SecureHash> hash(SecureHash::Create(SecureHash::SHA256)); | |
| 341 hash->Update(serialized->data(), serialized->length()); | |
| 342 | |
| 343 char scid_bytes[16]; | |
| 344 hash->Finish(scid_bytes, sizeof(scid_bytes)); | |
| 345 msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes))); | |
| 346 } else { | |
| 347 msg.SetStringPiece(kSCID, options.id); | |
| 348 } | |
| 349 // Don't put new tags below this point. The SCID generation should hash over | |
| 350 // everything but itself and so extra tags should be added prior to the | |
| 351 // preceeding if block. | |
| 352 | |
| 353 std::unique_ptr<QuicData> serialized( | |
| 354 CryptoFramer::ConstructHandshakeMessage(msg)); | |
| 355 | |
| 356 std::unique_ptr<QuicServerConfigProtobuf> config( | |
| 357 new QuicServerConfigProtobuf); | |
| 358 config->set_config(serialized->AsStringPiece()); | |
| 359 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key(); | |
| 360 curve25519_key->set_tag(kC255); | |
| 361 curve25519_key->set_private_key(curve25519_private_key); | |
| 362 | |
| 363 if (options.p256) { | |
| 364 QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key(); | |
| 365 p256_key->set_tag(kP256); | |
| 366 p256_key->set_private_key(p256_private_key); | |
| 367 } | |
| 368 | |
| 369 return config.release(); | |
| 370 } | |
| 371 | |
| 372 CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( | |
| 373 QuicServerConfigProtobuf* protobuf, | |
| 374 const QuicWallTime now) { | |
| 375 std::unique_ptr<CryptoHandshakeMessage> msg( | |
| 376 CryptoFramer::ParseMessage(protobuf->config())); | |
| 377 | |
| 378 if (!msg.get()) { | |
| 379 LOG(WARNING) << "Failed to parse server config message"; | |
| 380 return nullptr; | |
| 381 } | |
| 382 | |
| 383 scoped_refptr<Config> config(ParseConfigProtobuf(protobuf)); | |
| 384 if (!config.get()) { | |
| 385 LOG(WARNING) << "Failed to parse server config message"; | |
| 386 return nullptr; | |
| 387 } | |
| 388 | |
| 389 { | |
| 390 base::AutoLock locked(configs_lock_); | |
| 391 if (configs_.find(config->id) != configs_.end()) { | |
| 392 LOG(WARNING) << "Failed to add config because another with the same " | |
| 393 "server config id already exists: " | |
| 394 << QuicUtils::HexEncode(config->id); | |
| 395 return nullptr; | |
| 396 } | |
| 397 | |
| 398 configs_[config->id] = config; | |
| 399 SelectNewPrimaryConfig(now); | |
| 400 DCHECK(primary_config_.get()); | |
| 401 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); | |
| 402 } | |
| 403 | |
| 404 return msg.release(); | |
| 405 } | |
| 406 | |
| 407 CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( | |
| 408 QuicRandom* rand, | |
| 409 const QuicClock* clock, | |
| 410 const ConfigOptions& options) { | |
| 411 std::unique_ptr<QuicServerConfigProtobuf> config( | |
| 412 GenerateConfig(rand, clock, options)); | |
| 413 return AddConfig(config.get(), clock->WallNow()); | |
| 414 } | |
| 415 | |
| 416 bool QuicCryptoServerConfig::SetConfigs( | |
| 417 const vector<QuicServerConfigProtobuf*>& protobufs, | |
| 418 const QuicWallTime now) { | |
| 419 vector<scoped_refptr<Config>> parsed_configs; | |
| 420 bool ok = true; | |
| 421 | |
| 422 for (vector<QuicServerConfigProtobuf*>::const_iterator i = protobufs.begin(); | |
| 423 i != protobufs.end(); ++i) { | |
| 424 scoped_refptr<Config> config(ParseConfigProtobuf(*i)); | |
| 425 if (!config.get()) { | |
| 426 ok = false; | |
| 427 break; | |
| 428 } | |
| 429 | |
| 430 parsed_configs.push_back(config); | |
| 431 } | |
| 432 | |
| 433 if (parsed_configs.empty()) { | |
| 434 LOG(WARNING) << "New config list is empty."; | |
| 435 ok = false; | |
| 436 } | |
| 437 | |
| 438 if (!ok) { | |
| 439 LOG(WARNING) << "Rejecting QUIC configs because of above errors"; | |
| 440 } else { | |
| 441 VLOG(1) << "Updating configs:"; | |
| 442 | |
| 443 base::AutoLock locked(configs_lock_); | |
| 444 ConfigMap new_configs; | |
| 445 | |
| 446 for (vector<scoped_refptr<Config>>::const_iterator i = | |
| 447 parsed_configs.begin(); | |
| 448 i != parsed_configs.end(); ++i) { | |
| 449 scoped_refptr<Config> config = *i; | |
| 450 | |
| 451 ConfigMap::iterator it = configs_.find(config->id); | |
| 452 if (it != configs_.end()) { | |
| 453 VLOG(1) << "Keeping scid: " << QuicUtils::HexEncode(config->id) | |
| 454 << " orbit: " | |
| 455 << QuicUtils::HexEncode( | |
| 456 reinterpret_cast<const char*>(config->orbit), kOrbitSize) | |
| 457 << " new primary_time " << config->primary_time.ToUNIXSeconds() | |
| 458 << " old primary_time " | |
| 459 << it->second->primary_time.ToUNIXSeconds() << " new priority " | |
| 460 << config->priority << " old priority " << it->second->priority; | |
| 461 // Update primary_time and priority. | |
| 462 it->second->primary_time = config->primary_time; | |
| 463 it->second->priority = config->priority; | |
| 464 new_configs.insert(*it); | |
| 465 } else { | |
| 466 VLOG(1) << "Adding scid: " << QuicUtils::HexEncode(config->id) | |
| 467 << " orbit: " | |
| 468 << QuicUtils::HexEncode( | |
| 469 reinterpret_cast<const char*>(config->orbit), kOrbitSize) | |
| 470 << " primary_time " << config->primary_time.ToUNIXSeconds() | |
| 471 << " priority " << config->priority; | |
| 472 new_configs.insert(std::make_pair(config->id, config)); | |
| 473 } | |
| 474 } | |
| 475 | |
| 476 configs_.swap(new_configs); | |
| 477 SelectNewPrimaryConfig(now); | |
| 478 DCHECK(primary_config_.get()); | |
| 479 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); | |
| 480 } | |
| 481 | |
| 482 return ok; | |
| 483 } | |
| 484 | |
| 485 void QuicCryptoServerConfig::SetDefaultSourceAddressTokenKeys( | |
| 486 const vector<string>& keys) { | |
| 487 default_source_address_token_boxer_.SetKeys(keys); | |
| 488 } | |
| 489 | |
| 490 void QuicCryptoServerConfig::GetConfigIds(vector<string>* scids) const { | |
| 491 base::AutoLock locked(configs_lock_); | |
| 492 for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end(); | |
| 493 ++it) { | |
| 494 scids->push_back(it->first); | |
| 495 } | |
| 496 } | |
| 497 | |
| 498 void QuicCryptoServerConfig::ValidateClientHello( | |
| 499 const CryptoHandshakeMessage& client_hello, | |
| 500 const IPAddress& client_ip, | |
| 501 const IPAddress& server_ip, | |
| 502 QuicVersion version, | |
| 503 const QuicClock* clock, | |
| 504 QuicCryptoProof* crypto_proof, | |
| 505 ValidateClientHelloResultCallback* done_cb) const { | |
| 506 const QuicWallTime now(clock->WallNow()); | |
| 507 | |
| 508 ValidateClientHelloResultCallback::Result* result = | |
| 509 new ValidateClientHelloResultCallback::Result(client_hello, client_ip, | |
| 510 now); | |
| 511 | |
| 512 StringPiece requested_scid; | |
| 513 client_hello.GetStringPiece(kSCID, &requested_scid); | |
| 514 | |
| 515 uint8_t primary_orbit[kOrbitSize]; | |
| 516 scoped_refptr<Config> requested_config; | |
| 517 scoped_refptr<Config> primary_config; | |
| 518 { | |
| 519 base::AutoLock locked(configs_lock_); | |
| 520 | |
| 521 if (!primary_config_.get()) { | |
| 522 result->error_code = QUIC_CRYPTO_INTERNAL_ERROR; | |
| 523 result->error_details = "No configurations loaded"; | |
| 524 } else { | |
| 525 if (!next_config_promotion_time_.IsZero() && | |
| 526 next_config_promotion_time_.IsAfter(now)) { | |
| 527 SelectNewPrimaryConfig(now); | |
| 528 DCHECK(primary_config_.get()); | |
| 529 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); | |
| 530 } | |
| 531 | |
| 532 memcpy(primary_orbit, primary_config_->orbit, sizeof(primary_orbit)); | |
| 533 } | |
| 534 | |
| 535 requested_config = GetConfigWithScid(requested_scid); | |
| 536 primary_config = primary_config_; | |
| 537 crypto_proof->config = primary_config_; | |
| 538 } | |
| 539 | |
| 540 if (result->error_code == QUIC_NO_ERROR) { | |
| 541 if (FLAGS_quic_refresh_proof && version > QUIC_VERSION_30) { | |
| 542 // QUIC v31 and above require a new proof for each CHLO so clear the | |
| 543 // existing proof, if any. | |
| 544 crypto_proof->chain = nullptr; | |
| 545 crypto_proof->signature = ""; | |
| 546 crypto_proof->cert_sct = ""; | |
| 547 } | |
| 548 EvaluateClientHello(server_ip, version, primary_orbit, requested_config, | |
| 549 primary_config, crypto_proof, result, done_cb); | |
| 550 } else { | |
| 551 done_cb->Run(result, nullptr /* proof_source_details */); | |
| 552 } | |
| 553 } | |
| 554 | |
| 555 QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( | |
| 556 const ValidateClientHelloResultCallback::Result& validate_chlo_result, | |
| 557 bool reject_only, | |
| 558 QuicConnectionId connection_id, | |
| 559 const IPAddress& server_ip, | |
| 560 const IPEndPoint& client_address, | |
| 561 QuicVersion version, | |
| 562 const QuicVersionVector& supported_versions, | |
| 563 bool use_stateless_rejects, | |
| 564 QuicConnectionId server_designated_connection_id, | |
| 565 const QuicClock* clock, | |
| 566 QuicRandom* rand, | |
| 567 QuicCompressedCertsCache* compressed_certs_cache, | |
| 568 QuicCryptoNegotiatedParameters* params, | |
| 569 QuicCryptoProof* crypto_proof, | |
| 570 CryptoHandshakeMessage* out, | |
| 571 DiversificationNonce* out_diversification_nonce, | |
| 572 string* error_details) const { | |
| 573 DCHECK(error_details); | |
| 574 | |
| 575 const CryptoHandshakeMessage& client_hello = | |
| 576 validate_chlo_result.client_hello; | |
| 577 const ClientHelloInfo& info = validate_chlo_result.info; | |
| 578 | |
| 579 QuicErrorCode valid = CryptoUtils::ValidateClientHello( | |
| 580 client_hello, version, supported_versions, error_details); | |
| 581 if (valid != QUIC_NO_ERROR) | |
| 582 return valid; | |
| 583 | |
| 584 StringPiece requested_scid; | |
| 585 client_hello.GetStringPiece(kSCID, &requested_scid); | |
| 586 const QuicWallTime now(clock->WallNow()); | |
| 587 | |
| 588 scoped_refptr<Config> requested_config; | |
| 589 scoped_refptr<Config> primary_config; | |
| 590 { | |
| 591 base::AutoLock locked(configs_lock_); | |
| 592 | |
| 593 if (!primary_config_.get()) { | |
| 594 *error_details = "No configurations loaded"; | |
| 595 return QUIC_CRYPTO_INTERNAL_ERROR; | |
| 596 } | |
| 597 | |
| 598 if (!next_config_promotion_time_.IsZero() && | |
| 599 next_config_promotion_time_.IsAfter(now)) { | |
| 600 SelectNewPrimaryConfig(now); | |
| 601 DCHECK(primary_config_.get()); | |
| 602 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); | |
| 603 } | |
| 604 | |
| 605 // Use the config that the client requested in order to do key-agreement. | |
| 606 // Otherwise give it a copy of |primary_config_| to use. | |
| 607 primary_config = crypto_proof->config; | |
| 608 requested_config = GetConfigWithScid(requested_scid); | |
| 609 } | |
| 610 | |
| 611 if (validate_chlo_result.error_code != QUIC_NO_ERROR) { | |
| 612 *error_details = validate_chlo_result.error_details; | |
| 613 return validate_chlo_result.error_code; | |
| 614 } | |
| 615 | |
| 616 out->Clear(); | |
| 617 | |
| 618 bool x509_supported = false; | |
| 619 bool x509_ecdsa_supported = false; | |
| 620 ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported); | |
| 621 if (!x509_supported && FLAGS_quic_require_x509) { | |
| 622 *error_details = "Missing or invalid PDMD"; | |
| 623 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 624 } | |
| 625 DCHECK(proof_source_.get()); | |
| 626 string chlo_hash; | |
| 627 CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash); | |
| 628 // No need to get a new proof if one was already generated. | |
| 629 if (!crypto_proof->chain && | |
| 630 !proof_source_->GetProof( | |
| 631 server_ip, info.sni.as_string(), primary_config->serialized, version, | |
| 632 chlo_hash, x509_ecdsa_supported, &crypto_proof->chain, | |
| 633 &crypto_proof->signature, &crypto_proof->cert_sct)) { | |
| 634 return QUIC_HANDSHAKE_FAILED; | |
| 635 } | |
| 636 | |
| 637 StringPiece cert_sct; | |
| 638 if (client_hello.GetStringPiece(kCertificateSCTTag, &cert_sct) && | |
| 639 cert_sct.empty()) { | |
| 640 params->sct_supported_by_client = true; | |
| 641 } | |
| 642 | |
| 643 if (!info.reject_reasons.empty() || !requested_config.get()) { | |
| 644 BuildRejection(version, *primary_config, client_hello, info, | |
| 645 validate_chlo_result.cached_network_params, | |
| 646 use_stateless_rejects, server_designated_connection_id, rand, | |
| 647 compressed_certs_cache, params, *crypto_proof, out); | |
| 648 return QUIC_NO_ERROR; | |
| 649 } | |
| 650 | |
| 651 if (reject_only) { | |
| 652 return QUIC_NO_ERROR; | |
| 653 } | |
| 654 | |
| 655 const QuicTag* their_aeads; | |
| 656 const QuicTag* their_key_exchanges; | |
| 657 size_t num_their_aeads, num_their_key_exchanges; | |
| 658 if (client_hello.GetTaglist(kAEAD, &their_aeads, &num_their_aeads) != | |
| 659 QUIC_NO_ERROR || | |
| 660 client_hello.GetTaglist(kKEXS, &their_key_exchanges, | |
| 661 &num_their_key_exchanges) != QUIC_NO_ERROR || | |
| 662 num_their_aeads != 1 || num_their_key_exchanges != 1) { | |
| 663 *error_details = "Missing or invalid AEAD or KEXS"; | |
| 664 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 665 } | |
| 666 | |
| 667 size_t key_exchange_index; | |
| 668 if (!QuicUtils::FindMutualTag(requested_config->aead, their_aeads, | |
| 669 num_their_aeads, QuicUtils::LOCAL_PRIORITY, | |
| 670 ¶ms->aead, nullptr) || | |
| 671 !QuicUtils::FindMutualTag(requested_config->kexs, their_key_exchanges, | |
| 672 num_their_key_exchanges, | |
| 673 QuicUtils::LOCAL_PRIORITY, | |
| 674 ¶ms->key_exchange, &key_exchange_index)) { | |
| 675 *error_details = "Unsupported AEAD or KEXS"; | |
| 676 return QUIC_CRYPTO_NO_SUPPORT; | |
| 677 } | |
| 678 | |
| 679 if (!requested_config->tb_key_params.empty()) { | |
| 680 const QuicTag* their_tbkps; | |
| 681 size_t num_their_tbkps; | |
| 682 switch (client_hello.GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) { | |
| 683 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: | |
| 684 break; | |
| 685 case QUIC_NO_ERROR: | |
| 686 if (QuicUtils::FindMutualTag( | |
| 687 requested_config->tb_key_params, their_tbkps, num_their_tbkps, | |
| 688 QuicUtils::LOCAL_PRIORITY, ¶ms->token_binding_key_param, | |
| 689 nullptr)) { | |
| 690 break; | |
| 691 } | |
| 692 default: | |
| 693 *error_details = "Invalid Token Binding key parameter"; | |
| 694 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 695 } | |
| 696 } | |
| 697 | |
| 698 StringPiece public_value; | |
| 699 if (!client_hello.GetStringPiece(kPUBS, &public_value)) { | |
| 700 *error_details = "Missing public value"; | |
| 701 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 702 } | |
| 703 | |
| 704 const KeyExchange* key_exchange = | |
| 705 requested_config->key_exchanges[key_exchange_index]; | |
| 706 if (!key_exchange->CalculateSharedKey(public_value, | |
| 707 ¶ms->initial_premaster_secret)) { | |
| 708 *error_details = "Invalid public value"; | |
| 709 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 710 } | |
| 711 | |
| 712 if (!info.sni.empty()) { | |
| 713 std::unique_ptr<char[]> sni_tmp(new char[info.sni.length() + 1]); | |
| 714 memcpy(sni_tmp.get(), info.sni.data(), info.sni.length()); | |
| 715 sni_tmp[info.sni.length()] = 0; | |
| 716 params->sni = CryptoUtils::NormalizeHostname(sni_tmp.get()); | |
| 717 } | |
| 718 | |
| 719 string hkdf_suffix; | |
| 720 const QuicData& client_hello_serialized = client_hello.GetSerialized(); | |
| 721 hkdf_suffix.reserve(sizeof(connection_id) + client_hello_serialized.length() + | |
| 722 requested_config->serialized.size()); | |
| 723 hkdf_suffix.append(reinterpret_cast<char*>(&connection_id), | |
| 724 sizeof(connection_id)); | |
| 725 hkdf_suffix.append(client_hello_serialized.data(), | |
| 726 client_hello_serialized.length()); | |
| 727 hkdf_suffix.append(requested_config->serialized); | |
| 728 DCHECK(proof_source_.get()); | |
| 729 if (crypto_proof->chain->certs.empty()) { | |
| 730 *error_details = "Failed to get certs"; | |
| 731 return QUIC_CRYPTO_INTERNAL_ERROR; | |
| 732 } | |
| 733 hkdf_suffix.append(crypto_proof->chain->certs.at(0)); | |
| 734 | |
| 735 StringPiece cetv_ciphertext; | |
| 736 if (requested_config->channel_id_enabled && | |
| 737 client_hello.GetStringPiece(kCETV, &cetv_ciphertext)) { | |
| 738 CryptoHandshakeMessage client_hello_copy(client_hello); | |
| 739 client_hello_copy.Erase(kCETV); | |
| 740 client_hello_copy.Erase(kPAD); | |
| 741 | |
| 742 const QuicData& client_hello_copy_serialized = | |
| 743 client_hello_copy.GetSerialized(); | |
| 744 string hkdf_input; | |
| 745 hkdf_input.append(QuicCryptoConfig::kCETVLabel, | |
| 746 strlen(QuicCryptoConfig::kCETVLabel) + 1); | |
| 747 hkdf_input.append(reinterpret_cast<char*>(&connection_id), | |
| 748 sizeof(connection_id)); | |
| 749 hkdf_input.append(client_hello_copy_serialized.data(), | |
| 750 client_hello_copy_serialized.length()); | |
| 751 hkdf_input.append(requested_config->serialized); | |
| 752 | |
| 753 CrypterPair crypters; | |
| 754 if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead, | |
| 755 info.client_nonce, info.server_nonce, | |
| 756 hkdf_input, Perspective::IS_SERVER, | |
| 757 CryptoUtils::Diversification::Never(), | |
| 758 &crypters, nullptr /* subkey secret */)) { | |
| 759 *error_details = "Symmetric key setup failed"; | |
| 760 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; | |
| 761 } | |
| 762 | |
| 763 char plaintext[kMaxPacketSize]; | |
| 764 size_t plaintext_length = 0; | |
| 765 const bool success = crypters.decrypter->DecryptPacket( | |
| 766 kDefaultPathId, 0 /* packet number */, | |
| 767 StringPiece() /* associated data */, cetv_ciphertext, plaintext, | |
| 768 &plaintext_length, kMaxPacketSize); | |
| 769 if (!success) { | |
| 770 *error_details = "CETV decryption failure"; | |
| 771 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 772 } | |
| 773 std::unique_ptr<CryptoHandshakeMessage> cetv( | |
| 774 CryptoFramer::ParseMessage(StringPiece(plaintext, plaintext_length))); | |
| 775 if (!cetv.get()) { | |
| 776 *error_details = "CETV parse error"; | |
| 777 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 778 } | |
| 779 | |
| 780 StringPiece key, signature; | |
| 781 if (cetv->GetStringPiece(kCIDK, &key) && | |
| 782 cetv->GetStringPiece(kCIDS, &signature)) { | |
| 783 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) { | |
| 784 *error_details = "ChannelID signature failure"; | |
| 785 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 786 } | |
| 787 | |
| 788 params->channel_id = key.as_string(); | |
| 789 } | |
| 790 } | |
| 791 | |
| 792 string hkdf_input; | |
| 793 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; | |
| 794 hkdf_input.reserve(label_len + hkdf_suffix.size()); | |
| 795 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); | |
| 796 hkdf_input.append(hkdf_suffix); | |
| 797 | |
| 798 string* subkey_secret = ¶ms->initial_subkey_secret; | |
| 799 CryptoUtils::Diversification diversification = | |
| 800 CryptoUtils::Diversification::Never(); | |
| 801 if (version > QUIC_VERSION_32) { | |
| 802 rand->RandBytes(reinterpret_cast<char*>(out_diversification_nonce), | |
| 803 sizeof(*out_diversification_nonce)); | |
| 804 diversification = | |
| 805 CryptoUtils::Diversification::Now(out_diversification_nonce); | |
| 806 } | |
| 807 | |
| 808 if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead, | |
| 809 info.client_nonce, info.server_nonce, hkdf_input, | |
| 810 Perspective::IS_SERVER, diversification, | |
| 811 ¶ms->initial_crypters, subkey_secret)) { | |
| 812 *error_details = "Symmetric key setup failed"; | |
| 813 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; | |
| 814 } | |
| 815 | |
| 816 string forward_secure_public_value; | |
| 817 if (ephemeral_key_source_.get()) { | |
| 818 params->forward_secure_premaster_secret = | |
| 819 ephemeral_key_source_->CalculateForwardSecureKey( | |
| 820 key_exchange, rand, clock->ApproximateNow(), public_value, | |
| 821 &forward_secure_public_value); | |
| 822 } else { | |
| 823 std::unique_ptr<KeyExchange> forward_secure_key_exchange( | |
| 824 key_exchange->NewKeyPair(rand)); | |
| 825 forward_secure_public_value = | |
| 826 forward_secure_key_exchange->public_value().as_string(); | |
| 827 if (!forward_secure_key_exchange->CalculateSharedKey( | |
| 828 public_value, ¶ms->forward_secure_premaster_secret)) { | |
| 829 *error_details = "Invalid public value"; | |
| 830 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 831 } | |
| 832 } | |
| 833 | |
| 834 string forward_secure_hkdf_input; | |
| 835 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; | |
| 836 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size()); | |
| 837 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, | |
| 838 label_len); | |
| 839 forward_secure_hkdf_input.append(hkdf_suffix); | |
| 840 | |
| 841 string shlo_nonce; | |
| 842 shlo_nonce = NewServerNonce(rand, info.now); | |
| 843 out->SetStringPiece(kServerNonceTag, shlo_nonce); | |
| 844 | |
| 845 if (!CryptoUtils::DeriveKeys( | |
| 846 params->forward_secure_premaster_secret, params->aead, | |
| 847 info.client_nonce, | |
| 848 shlo_nonce.empty() ? info.server_nonce : shlo_nonce, | |
| 849 forward_secure_hkdf_input, Perspective::IS_SERVER, | |
| 850 CryptoUtils::Diversification::Never(), | |
| 851 ¶ms->forward_secure_crypters, ¶ms->subkey_secret)) { | |
| 852 *error_details = "Symmetric key setup failed"; | |
| 853 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; | |
| 854 } | |
| 855 | |
| 856 out->set_tag(kSHLO); | |
| 857 QuicTagVector supported_version_tags; | |
| 858 for (size_t i = 0; i < supported_versions.size(); ++i) { | |
| 859 supported_version_tags.push_back( | |
| 860 QuicVersionToQuicTag(supported_versions[i])); | |
| 861 } | |
| 862 out->SetVector(kVER, supported_version_tags); | |
| 863 out->SetStringPiece( | |
| 864 kSourceAddressTokenTag, | |
| 865 NewSourceAddressToken(*requested_config.get(), info.source_address_tokens, | |
| 866 client_address.address(), rand, info.now, nullptr)); | |
| 867 QuicSocketAddressCoder address_coder(client_address); | |
| 868 out->SetStringPiece(kCADR, address_coder.Encode()); | |
| 869 out->SetStringPiece(kPUBS, forward_secure_public_value); | |
| 870 | |
| 871 return QUIC_NO_ERROR; | |
| 872 } | |
| 873 | |
| 874 scoped_refptr<QuicCryptoServerConfig::Config> | |
| 875 QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid) const { | |
| 876 // In Chromium, we will dead lock if the lock is held by the current thread. | |
| 877 // Chromium doesn't have AssertReaderHeld API call. | |
| 878 // configs_lock_.AssertReaderHeld(); | |
| 879 | |
| 880 if (!requested_scid.empty()) { | |
| 881 ConfigMap::const_iterator it = configs_.find(requested_scid.as_string()); | |
| 882 if (it != configs_.end()) { | |
| 883 // We'll use the config that the client requested in order to do | |
| 884 // key-agreement. | |
| 885 return scoped_refptr<Config>(it->second); | |
| 886 } | |
| 887 } | |
| 888 | |
| 889 return scoped_refptr<Config>(); | |
| 890 } | |
| 891 | |
| 892 // ConfigPrimaryTimeLessThan is a comparator that implements "less than" for | |
| 893 // Config's based on their primary_time. | |
| 894 // static | |
| 895 bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan( | |
| 896 const scoped_refptr<Config>& a, | |
| 897 const scoped_refptr<Config>& b) { | |
| 898 if (a->primary_time.IsBefore(b->primary_time) || | |
| 899 b->primary_time.IsBefore(a->primary_time)) { | |
| 900 // Primary times differ. | |
| 901 return a->primary_time.IsBefore(b->primary_time); | |
| 902 } else if (a->priority != b->priority) { | |
| 903 // Primary times are equal, sort backwards by priority. | |
| 904 return a->priority < b->priority; | |
| 905 } else { | |
| 906 // Primary times and priorities are equal, sort by config id. | |
| 907 return a->id < b->id; | |
| 908 } | |
| 909 } | |
| 910 | |
| 911 void QuicCryptoServerConfig::SelectNewPrimaryConfig( | |
| 912 const QuicWallTime now) const { | |
| 913 vector<scoped_refptr<Config>> configs; | |
| 914 configs.reserve(configs_.size()); | |
| 915 | |
| 916 for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end(); | |
| 917 ++it) { | |
| 918 // TODO(avd) Exclude expired configs? | |
| 919 configs.push_back(it->second); | |
| 920 } | |
| 921 | |
| 922 if (configs.empty()) { | |
| 923 if (primary_config_.get()) { | |
| 924 QUIC_BUG << "No valid QUIC server config. Keeping the current config."; | |
| 925 } else { | |
| 926 QUIC_BUG << "No valid QUIC server config."; | |
| 927 } | |
| 928 return; | |
| 929 } | |
| 930 | |
| 931 std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan); | |
| 932 | |
| 933 Config* best_candidate = configs[0].get(); | |
| 934 | |
| 935 for (size_t i = 0; i < configs.size(); ++i) { | |
| 936 const scoped_refptr<Config> config(configs[i]); | |
| 937 if (!config->primary_time.IsAfter(now)) { | |
| 938 if (config->primary_time.IsAfter(best_candidate->primary_time)) { | |
| 939 best_candidate = config.get(); | |
| 940 } | |
| 941 continue; | |
| 942 } | |
| 943 | |
| 944 // This is the first config with a primary_time in the future. Thus the | |
| 945 // previous Config should be the primary and this one should determine the | |
| 946 // next_config_promotion_time_. | |
| 947 scoped_refptr<Config> new_primary(best_candidate); | |
| 948 if (i == 0) { | |
| 949 // We need the primary_time of the next config. | |
| 950 if (configs.size() > 1) { | |
| 951 next_config_promotion_time_ = configs[1]->primary_time; | |
| 952 } else { | |
| 953 next_config_promotion_time_ = QuicWallTime::Zero(); | |
| 954 } | |
| 955 } else { | |
| 956 next_config_promotion_time_ = config->primary_time; | |
| 957 } | |
| 958 | |
| 959 if (primary_config_.get()) { | |
| 960 primary_config_->is_primary = false; | |
| 961 } | |
| 962 primary_config_ = new_primary; | |
| 963 new_primary->is_primary = true; | |
| 964 DVLOG(1) << "New primary config. orbit: " | |
| 965 << QuicUtils::HexEncode( | |
| 966 reinterpret_cast<const char*>(primary_config_->orbit), | |
| 967 kOrbitSize); | |
| 968 if (primary_config_changed_cb_.get() != nullptr) { | |
| 969 primary_config_changed_cb_->Run(primary_config_->id); | |
| 970 } | |
| 971 | |
| 972 return; | |
| 973 } | |
| 974 | |
| 975 // All config's primary times are in the past. We should make the most recent | |
| 976 // and highest priority candidate primary. | |
| 977 scoped_refptr<Config> new_primary(best_candidate); | |
| 978 if (primary_config_.get()) { | |
| 979 primary_config_->is_primary = false; | |
| 980 } | |
| 981 primary_config_ = new_primary; | |
| 982 new_primary->is_primary = true; | |
| 983 DVLOG(1) << "New primary config. orbit: " | |
| 984 << QuicUtils::HexEncode( | |
| 985 reinterpret_cast<const char*>(primary_config_->orbit), | |
| 986 kOrbitSize) | |
| 987 << " scid: " << QuicUtils::HexEncode(primary_config_->id); | |
| 988 next_config_promotion_time_ = QuicWallTime::Zero(); | |
| 989 if (primary_config_changed_cb_.get() != nullptr) { | |
| 990 primary_config_changed_cb_->Run(primary_config_->id); | |
| 991 } | |
| 992 } | |
| 993 | |
| 994 class EvaluateClientHelloCallback : public ProofSource::Callback { | |
| 995 public: | |
| 996 EvaluateClientHelloCallback( | |
| 997 const QuicCryptoServerConfig& config, | |
| 998 bool found_error, | |
| 999 const IPAddress& server_ip, | |
| 1000 QuicVersion version, | |
| 1001 const uint8_t* primary_orbit, | |
| 1002 scoped_refptr<QuicCryptoServerConfig::Config> requested_config, | |
| 1003 scoped_refptr<QuicCryptoServerConfig::Config> primary_config, | |
| 1004 QuicCryptoProof* crypto_proof, | |
| 1005 ValidateClientHelloResultCallback::Result* client_hello_state, | |
| 1006 ValidateClientHelloResultCallback* done_cb) | |
| 1007 : config_(config), | |
| 1008 found_error_(found_error), | |
| 1009 server_ip_(server_ip), | |
| 1010 version_(version), | |
| 1011 primary_orbit_(primary_orbit), | |
| 1012 requested_config_(std::move(requested_config)), | |
| 1013 primary_config_(std::move(primary_config)), | |
| 1014 crypto_proof_(crypto_proof), | |
| 1015 client_hello_state_(client_hello_state), | |
| 1016 done_cb_(done_cb) {} | |
| 1017 | |
| 1018 void Run(bool ok, | |
| 1019 const scoped_refptr<ProofSource::Chain>& chain, | |
| 1020 const string& signature, | |
| 1021 const string& leaf_cert_sct, | |
| 1022 std::unique_ptr<ProofSource::Details> details) override { | |
| 1023 if (ok) { | |
| 1024 crypto_proof_->chain = chain; | |
| 1025 crypto_proof_->signature = signature; | |
| 1026 crypto_proof_->cert_sct = leaf_cert_sct; | |
| 1027 } | |
| 1028 config_.EvaluateClientHelloAfterGetProof( | |
| 1029 found_error_, server_ip_, version_, primary_orbit_, requested_config_, | |
| 1030 primary_config_, crypto_proof_, std::move(details), !ok, | |
| 1031 client_hello_state_, done_cb_); | |
| 1032 } | |
| 1033 | |
| 1034 private: | |
| 1035 const QuicCryptoServerConfig& config_; | |
| 1036 const bool found_error_; | |
| 1037 const IPAddress& server_ip_; | |
| 1038 const QuicVersion version_; | |
| 1039 const uint8_t* primary_orbit_; | |
| 1040 const scoped_refptr<QuicCryptoServerConfig::Config> requested_config_; | |
| 1041 const scoped_refptr<QuicCryptoServerConfig::Config> primary_config_; | |
| 1042 QuicCryptoProof* crypto_proof_; | |
| 1043 ValidateClientHelloResultCallback::Result* client_hello_state_; | |
| 1044 ValidateClientHelloResultCallback* done_cb_; | |
| 1045 }; | |
| 1046 | |
| 1047 void QuicCryptoServerConfig::EvaluateClientHello( | |
| 1048 const IPAddress& server_ip, | |
| 1049 QuicVersion version, | |
| 1050 const uint8_t* primary_orbit, | |
| 1051 scoped_refptr<Config> requested_config, | |
| 1052 scoped_refptr<Config> primary_config, | |
| 1053 QuicCryptoProof* crypto_proof, | |
| 1054 ValidateClientHelloResultCallback::Result* client_hello_state, | |
| 1055 ValidateClientHelloResultCallback* done_cb) const { | |
| 1056 ValidateClientHelloHelper helper(client_hello_state, done_cb); | |
| 1057 | |
| 1058 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello; | |
| 1059 ClientHelloInfo* info = &(client_hello_state->info); | |
| 1060 | |
| 1061 if (client_hello.size() < kClientHelloMinimumSize) { | |
| 1062 helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH, | |
| 1063 "Client hello too small", nullptr); | |
| 1064 return; | |
| 1065 } | |
| 1066 | |
| 1067 if (client_hello.GetStringPiece(kSNI, &info->sni) && | |
| 1068 !CryptoUtils::IsValidSNI(info->sni)) { | |
| 1069 helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, | |
| 1070 "Invalid SNI name", nullptr); | |
| 1071 return; | |
| 1072 } | |
| 1073 | |
| 1074 client_hello.GetStringPiece(kUAID, &info->user_agent_id); | |
| 1075 | |
| 1076 HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON; | |
| 1077 StringPiece srct; | |
| 1078 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { | |
| 1079 Config& config = requested_config ? *requested_config : *primary_config; | |
| 1080 source_address_token_error = | |
| 1081 ParseSourceAddressToken(config, srct, &info->source_address_tokens); | |
| 1082 | |
| 1083 if (source_address_token_error == HANDSHAKE_OK) { | |
| 1084 source_address_token_error = ValidateSourceAddressTokens( | |
| 1085 info->source_address_tokens, info->client_ip, info->now, | |
| 1086 &client_hello_state->cached_network_params); | |
| 1087 } | |
| 1088 info->valid_source_address_token = | |
| 1089 (source_address_token_error == HANDSHAKE_OK); | |
| 1090 } else { | |
| 1091 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; | |
| 1092 } | |
| 1093 | |
| 1094 if (!requested_config.get()) { | |
| 1095 StringPiece requested_scid; | |
| 1096 if (client_hello.GetStringPiece(kSCID, &requested_scid)) { | |
| 1097 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); | |
| 1098 } else { | |
| 1099 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); | |
| 1100 } | |
| 1101 // No server config with the requested ID. | |
| 1102 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr); | |
| 1103 return; | |
| 1104 } | |
| 1105 | |
| 1106 if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) { | |
| 1107 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); | |
| 1108 // Report no client nonce as INCHOATE_HELLO_FAILURE. | |
| 1109 helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr); | |
| 1110 return; | |
| 1111 } | |
| 1112 | |
| 1113 bool found_error = false; | |
| 1114 if (source_address_token_error != HANDSHAKE_OK) { | |
| 1115 info->reject_reasons.push_back(source_address_token_error); | |
| 1116 // No valid source address token. | |
| 1117 found_error = true; | |
| 1118 } | |
| 1119 | |
| 1120 bool get_proof_failed = false; | |
| 1121 bool x509_supported = false; | |
| 1122 bool x509_ecdsa_supported = false; | |
| 1123 ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported); | |
| 1124 string serialized_config = primary_config->serialized; | |
| 1125 string chlo_hash; | |
| 1126 CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash); | |
| 1127 bool need_proof = true; | |
| 1128 if (FLAGS_quic_refresh_proof) { | |
| 1129 need_proof = !crypto_proof->chain; | |
| 1130 } | |
| 1131 if (FLAGS_enable_async_get_proof) { | |
| 1132 if (need_proof) { | |
| 1133 // Make an async call to GetProof and setup the callback to trampoline | |
| 1134 // back into EvaluateClientHelloAfterGetProof | |
| 1135 std::unique_ptr<EvaluateClientHelloCallback> cb( | |
| 1136 new EvaluateClientHelloCallback( | |
| 1137 *this, found_error, server_ip, version, primary_orbit, | |
| 1138 requested_config, primary_config, crypto_proof, | |
| 1139 client_hello_state, done_cb)); | |
| 1140 proof_source_->GetProof(server_ip, info->sni.as_string(), | |
| 1141 serialized_config, version, chlo_hash, | |
| 1142 x509_ecdsa_supported, std::move(cb)); | |
| 1143 helper.DetachCallback(); | |
| 1144 return; | |
| 1145 } | |
| 1146 } | |
| 1147 | |
| 1148 // No need to get a new proof if one was already generated. | |
| 1149 if (need_proof && | |
| 1150 !proof_source_->GetProof( | |
| 1151 server_ip, info->sni.as_string(), serialized_config, version, | |
| 1152 chlo_hash, x509_ecdsa_supported, &crypto_proof->chain, | |
| 1153 &crypto_proof->signature, &crypto_proof->cert_sct)) { | |
| 1154 get_proof_failed = true; | |
| 1155 } | |
| 1156 | |
| 1157 // Details are null because the synchronous version of GetProof does not | |
| 1158 // return any stats. Eventually the synchronous codepath will be eliminated. | |
| 1159 EvaluateClientHelloAfterGetProof( | |
| 1160 found_error, server_ip, version, primary_orbit, requested_config, | |
| 1161 primary_config, crypto_proof, nullptr /* proof_source_details */, | |
| 1162 get_proof_failed, client_hello_state, done_cb); | |
| 1163 helper.DetachCallback(); | |
| 1164 } | |
| 1165 | |
| 1166 void QuicCryptoServerConfig::EvaluateClientHelloAfterGetProof( | |
| 1167 bool found_error, | |
| 1168 const IPAddress& server_ip, | |
| 1169 QuicVersion version, | |
| 1170 const uint8_t* primary_orbit, | |
| 1171 scoped_refptr<Config> requested_config, | |
| 1172 scoped_refptr<Config> primary_config, | |
| 1173 QuicCryptoProof* crypto_proof, | |
| 1174 std::unique_ptr<ProofSource::Details> proof_source_details, | |
| 1175 bool get_proof_failed, | |
| 1176 ValidateClientHelloResultCallback::Result* client_hello_state, | |
| 1177 ValidateClientHelloResultCallback* done_cb) const { | |
| 1178 ValidateClientHelloHelper helper(client_hello_state, done_cb); | |
| 1179 const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello; | |
| 1180 ClientHelloInfo* info = &(client_hello_state->info); | |
| 1181 | |
| 1182 if (get_proof_failed) { | |
| 1183 found_error = true; | |
| 1184 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); | |
| 1185 } | |
| 1186 | |
| 1187 if (!ValidateExpectedLeafCertificate(client_hello, *crypto_proof)) { | |
| 1188 found_error = true; | |
| 1189 info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE); | |
| 1190 } | |
| 1191 | |
| 1192 if (info->client_nonce.size() != kNonceSize) { | |
| 1193 info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE); | |
| 1194 // Invalid client nonce. | |
| 1195 LOG(ERROR) << "Invalid client nonce: " << client_hello.DebugString(); | |
| 1196 DVLOG(1) << "Invalid client nonce."; | |
| 1197 found_error = true; | |
| 1198 } | |
| 1199 | |
| 1200 // Server nonce is optional, and used for key derivation if present. | |
| 1201 client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce); | |
| 1202 | |
| 1203 if (version > QUIC_VERSION_32) { | |
| 1204 DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher."; | |
| 1205 // If the server nonce is empty and we're requiring handshake confirmation | |
| 1206 // for DoS reasons then we must reject the CHLO. | |
| 1207 if (FLAGS_quic_require_handshake_confirmation && | |
| 1208 info->server_nonce.empty()) { | |
| 1209 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE); | |
| 1210 } | |
| 1211 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
| 1212 std::move(proof_source_details)); | |
| 1213 return; | |
| 1214 } | |
| 1215 | |
| 1216 if (!replay_protection_) { | |
| 1217 DVLOG(1) << "No replay protection."; | |
| 1218 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
| 1219 std::move(proof_source_details)); | |
| 1220 return; | |
| 1221 } | |
| 1222 | |
| 1223 if (!info->server_nonce.empty()) { | |
| 1224 // If the server nonce is present, use it to establish uniqueness. | |
| 1225 HandshakeFailureReason server_nonce_error = | |
| 1226 ValidateServerNonce(info->server_nonce, info->now); | |
| 1227 bool is_unique = server_nonce_error == HANDSHAKE_OK; | |
| 1228 if (!is_unique) { | |
| 1229 info->reject_reasons.push_back(server_nonce_error); | |
| 1230 } | |
| 1231 DVLOG(1) << "Using server nonce, unique: " << is_unique; | |
| 1232 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
| 1233 std::move(proof_source_details)); | |
| 1234 return; | |
| 1235 } | |
| 1236 // If we hit this block, the server nonce was empty. If we're requiring | |
| 1237 // handshake confirmation for DoS reasons and there's no server nonce present, | |
| 1238 // reject the CHLO. | |
| 1239 if (FLAGS_quic_require_handshake_confirmation || | |
| 1240 FLAGS_quic_require_handshake_confirmation_pre33) { | |
| 1241 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE); | |
| 1242 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
| 1243 std::move(proof_source_details)); | |
| 1244 return; | |
| 1245 } | |
| 1246 | |
| 1247 // We want to contact strike register only if there are no errors because it | |
| 1248 // is a RPC call and is expensive. | |
| 1249 if (found_error) { | |
| 1250 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
| 1251 std::move(proof_source_details)); | |
| 1252 return; | |
| 1253 } | |
| 1254 | |
| 1255 // Use the client nonce to establish uniqueness. | |
| 1256 StrikeRegisterClient* strike_register_client; | |
| 1257 { | |
| 1258 base::AutoLock locked(strike_register_client_lock_); | |
| 1259 strike_register_client = strike_register_client_.get(); | |
| 1260 } | |
| 1261 | |
| 1262 if (!strike_register_client) { | |
| 1263 // Either a valid server nonces or a strike register is required. | |
| 1264 // Since neither are present, reject the handshake which will send a | |
| 1265 // server nonce to the client. | |
| 1266 info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE); | |
| 1267 helper.ValidationComplete(QUIC_NO_ERROR, "", | |
| 1268 std::move(proof_source_details)); | |
| 1269 return; | |
| 1270 } | |
| 1271 | |
| 1272 strike_register_client->VerifyNonceIsValidAndUnique( | |
| 1273 info->client_nonce, info->now, | |
| 1274 new VerifyNonceIsValidAndUniqueCallback( | |
| 1275 client_hello_state, std::move(proof_source_details), done_cb)); | |
| 1276 helper.DetachCallback(); | |
| 1277 } | |
| 1278 | |
| 1279 bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage( | |
| 1280 QuicVersion version, | |
| 1281 StringPiece chlo_hash, | |
| 1282 const SourceAddressTokens& previous_source_address_tokens, | |
| 1283 const IPAddress& server_ip, | |
| 1284 const IPAddress& client_ip, | |
| 1285 const QuicClock* clock, | |
| 1286 QuicRandom* rand, | |
| 1287 QuicCompressedCertsCache* compressed_certs_cache, | |
| 1288 const QuicCryptoNegotiatedParameters& params, | |
| 1289 const CachedNetworkParameters* cached_network_params, | |
| 1290 CryptoHandshakeMessage* out) const { | |
| 1291 string serialized; | |
| 1292 string source_address_token; | |
| 1293 const CommonCertSets* common_cert_sets; | |
| 1294 { | |
| 1295 base::AutoLock locked(configs_lock_); | |
| 1296 serialized = primary_config_->serialized; | |
| 1297 common_cert_sets = primary_config_->common_cert_sets; | |
| 1298 source_address_token = NewSourceAddressToken( | |
| 1299 *primary_config_, previous_source_address_tokens, client_ip, rand, | |
| 1300 clock->WallNow(), cached_network_params); | |
| 1301 } | |
| 1302 | |
| 1303 out->set_tag(kSCUP); | |
| 1304 out->SetStringPiece(kSCFG, serialized); | |
| 1305 out->SetStringPiece(kSourceAddressTokenTag, source_address_token); | |
| 1306 | |
| 1307 scoped_refptr<ProofSource::Chain> chain; | |
| 1308 string signature; | |
| 1309 string cert_sct; | |
| 1310 if (!proof_source_->GetProof(server_ip, params.sni, serialized, version, | |
| 1311 chlo_hash, params.x509_ecdsa_supported, &chain, | |
| 1312 &signature, &cert_sct)) { | |
| 1313 DVLOG(1) << "Server: failed to get proof."; | |
| 1314 return false; | |
| 1315 } | |
| 1316 | |
| 1317 const string compressed = CompressChain( | |
| 1318 compressed_certs_cache, chain, params.client_common_set_hashes, | |
| 1319 params.client_cached_cert_hashes, common_cert_sets); | |
| 1320 | |
| 1321 out->SetStringPiece(kCertificateTag, compressed); | |
| 1322 out->SetStringPiece(kPROF, signature); | |
| 1323 if (params.sct_supported_by_client && enable_serving_sct_) { | |
| 1324 if (cert_sct.empty()) { | |
| 1325 DLOG(WARNING) << "SCT is expected but it is empty."; | |
| 1326 } else { | |
| 1327 out->SetStringPiece(kCertificateSCTTag, cert_sct); | |
| 1328 } | |
| 1329 } | |
| 1330 return true; | |
| 1331 } | |
| 1332 | |
| 1333 void QuicCryptoServerConfig::BuildServerConfigUpdateMessage( | |
| 1334 QuicVersion version, | |
| 1335 StringPiece chlo_hash, | |
| 1336 const SourceAddressTokens& previous_source_address_tokens, | |
| 1337 const IPAddress& server_ip, | |
| 1338 const IPAddress& client_ip, | |
| 1339 const QuicClock* clock, | |
| 1340 QuicRandom* rand, | |
| 1341 QuicCompressedCertsCache* compressed_certs_cache, | |
| 1342 const QuicCryptoNegotiatedParameters& params, | |
| 1343 const CachedNetworkParameters* cached_network_params, | |
| 1344 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const { | |
| 1345 string serialized; | |
| 1346 string source_address_token; | |
| 1347 const CommonCertSets* common_cert_sets; | |
| 1348 { | |
| 1349 base::AutoLock locked(configs_lock_); | |
| 1350 serialized = primary_config_->serialized; | |
| 1351 common_cert_sets = primary_config_->common_cert_sets; | |
| 1352 source_address_token = NewSourceAddressToken( | |
| 1353 *primary_config_, previous_source_address_tokens, client_ip, rand, | |
| 1354 clock->WallNow(), cached_network_params); | |
| 1355 } | |
| 1356 | |
| 1357 CryptoHandshakeMessage message; | |
| 1358 message.set_tag(kSCUP); | |
| 1359 message.SetStringPiece(kSCFG, serialized); | |
| 1360 message.SetStringPiece(kSourceAddressTokenTag, source_address_token); | |
| 1361 | |
| 1362 std::unique_ptr<BuildServerConfigUpdateMessageProofSourceCallback> | |
| 1363 proof_source_cb(new BuildServerConfigUpdateMessageProofSourceCallback( | |
| 1364 this, version, compressed_certs_cache, common_cert_sets, params, | |
| 1365 std::move(message), std::move(cb))); | |
| 1366 | |
| 1367 proof_source_->GetProof(server_ip, params.sni, serialized, version, chlo_hash, | |
| 1368 params.x509_ecdsa_supported, | |
| 1369 std::move(proof_source_cb)); | |
| 1370 } | |
| 1371 | |
| 1372 QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: | |
| 1373 ~BuildServerConfigUpdateMessageProofSourceCallback() {} | |
| 1374 | |
| 1375 QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: | |
| 1376 BuildServerConfigUpdateMessageProofSourceCallback( | |
| 1377 const QuicCryptoServerConfig* config, | |
| 1378 QuicVersion version, | |
| 1379 QuicCompressedCertsCache* compressed_certs_cache, | |
| 1380 const CommonCertSets* common_cert_sets, | |
| 1381 const QuicCryptoNegotiatedParameters& params, | |
| 1382 CryptoHandshakeMessage message, | |
| 1383 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) | |
| 1384 : config_(config), | |
| 1385 version_(version), | |
| 1386 compressed_certs_cache_(compressed_certs_cache), | |
| 1387 common_cert_sets_(common_cert_sets), | |
| 1388 client_common_set_hashes_(params.client_common_set_hashes), | |
| 1389 client_cached_cert_hashes_(params.client_cached_cert_hashes), | |
| 1390 sct_supported_by_client_(params.sct_supported_by_client), | |
| 1391 message_(std::move(message)), | |
| 1392 cb_(std::move(cb)) {} | |
| 1393 | |
| 1394 void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: | |
| 1395 Run(bool ok, | |
| 1396 const scoped_refptr<ProofSource::Chain>& chain, | |
| 1397 const string& signature, | |
| 1398 const string& leaf_cert_sct, | |
| 1399 std::unique_ptr<ProofSource::Details> details) { | |
| 1400 config_->FinishBuildServerConfigUpdateMessage( | |
| 1401 version_, compressed_certs_cache_, common_cert_sets_, | |
| 1402 client_common_set_hashes_, client_cached_cert_hashes_, | |
| 1403 sct_supported_by_client_, ok, chain, signature, leaf_cert_sct, | |
| 1404 std::move(details), std::move(message_), std::move(cb_)); | |
| 1405 } | |
| 1406 | |
| 1407 void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage( | |
| 1408 QuicVersion version, | |
| 1409 QuicCompressedCertsCache* compressed_certs_cache, | |
| 1410 const CommonCertSets* common_cert_sets, | |
| 1411 const string& client_common_set_hashes, | |
| 1412 const string& client_cached_cert_hashes, | |
| 1413 bool sct_supported_by_client, | |
| 1414 bool ok, | |
| 1415 const scoped_refptr<ProofSource::Chain>& chain, | |
| 1416 const string& signature, | |
| 1417 const string& leaf_cert_sct, | |
| 1418 std::unique_ptr<ProofSource::Details> details, | |
| 1419 CryptoHandshakeMessage message, | |
| 1420 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const { | |
| 1421 if (!ok) { | |
| 1422 cb->Run(false, message); | |
| 1423 return; | |
| 1424 } | |
| 1425 | |
| 1426 const string compressed = | |
| 1427 CompressChain(compressed_certs_cache, chain, client_common_set_hashes, | |
| 1428 client_cached_cert_hashes, common_cert_sets); | |
| 1429 | |
| 1430 message.SetStringPiece(kCertificateTag, compressed); | |
| 1431 message.SetStringPiece(kPROF, signature); | |
| 1432 if (sct_supported_by_client && enable_serving_sct_) { | |
| 1433 if (leaf_cert_sct.empty()) { | |
| 1434 DLOG(WARNING) << "SCT is expected but it is empty."; | |
| 1435 } else { | |
| 1436 message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct); | |
| 1437 } | |
| 1438 } | |
| 1439 | |
| 1440 cb->Run(true, message); | |
| 1441 } | |
| 1442 | |
| 1443 void QuicCryptoServerConfig::BuildRejection( | |
| 1444 QuicVersion version, | |
| 1445 const Config& config, | |
| 1446 const CryptoHandshakeMessage& client_hello, | |
| 1447 const ClientHelloInfo& info, | |
| 1448 const CachedNetworkParameters& cached_network_params, | |
| 1449 bool use_stateless_rejects, | |
| 1450 QuicConnectionId server_designated_connection_id, | |
| 1451 QuicRandom* rand, | |
| 1452 QuicCompressedCertsCache* compressed_certs_cache, | |
| 1453 QuicCryptoNegotiatedParameters* params, | |
| 1454 const QuicCryptoProof& crypto_proof, | |
| 1455 CryptoHandshakeMessage* out) const { | |
| 1456 if (FLAGS_enable_quic_stateless_reject_support && use_stateless_rejects) { | |
| 1457 DVLOG(1) << "QUIC Crypto server config returning stateless reject " | |
| 1458 << "with server-designated connection ID " | |
| 1459 << server_designated_connection_id; | |
| 1460 out->set_tag(kSREJ); | |
| 1461 out->SetValue(kRCID, server_designated_connection_id); | |
| 1462 } else { | |
| 1463 out->set_tag(kREJ); | |
| 1464 } | |
| 1465 out->SetStringPiece(kSCFG, config.serialized); | |
| 1466 out->SetStringPiece( | |
| 1467 kSourceAddressTokenTag, | |
| 1468 NewSourceAddressToken(config, info.source_address_tokens, info.client_ip, | |
| 1469 rand, info.now, &cached_network_params)); | |
| 1470 if (replay_protection_) { | |
| 1471 out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now)); | |
| 1472 } | |
| 1473 | |
| 1474 // Send client the reject reason for debugging purposes. | |
| 1475 DCHECK_LT(0u, info.reject_reasons.size()); | |
| 1476 out->SetVector(kRREJ, info.reject_reasons); | |
| 1477 | |
| 1478 // The client may have requested a certificate chain. | |
| 1479 bool x509_supported = false; | |
| 1480 ParseProofDemand(client_hello, &x509_supported, | |
| 1481 ¶ms->x509_ecdsa_supported); | |
| 1482 if (!x509_supported && FLAGS_quic_require_x509) { | |
| 1483 QUIC_BUG << "x509 certificates not supported in proof demand"; | |
| 1484 return; | |
| 1485 } | |
| 1486 | |
| 1487 StringPiece client_common_set_hashes; | |
| 1488 if (client_hello.GetStringPiece(kCCS, &client_common_set_hashes)) { | |
| 1489 params->client_common_set_hashes = client_common_set_hashes.as_string(); | |
| 1490 } | |
| 1491 | |
| 1492 StringPiece client_cached_cert_hashes; | |
| 1493 if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) { | |
| 1494 params->client_cached_cert_hashes = client_cached_cert_hashes.as_string(); | |
| 1495 } | |
| 1496 | |
| 1497 const string compressed = | |
| 1498 CompressChain(compressed_certs_cache, crypto_proof.chain, | |
| 1499 params->client_common_set_hashes, | |
| 1500 params->client_cached_cert_hashes, config.common_cert_sets); | |
| 1501 | |
| 1502 // kREJOverheadBytes is a very rough estimate of how much of a REJ | |
| 1503 // message is taken up by things other than the certificates. | |
| 1504 // STK: 56 bytes | |
| 1505 // SNO: 56 bytes | |
| 1506 // SCFG | |
| 1507 // SCID: 16 bytes | |
| 1508 // PUBS: 38 bytes | |
| 1509 const size_t kREJOverheadBytes = 166; | |
| 1510 // max_unverified_size is the number of bytes that the certificate chain, | |
| 1511 // signature, and (optionally) signed certificate timestamp can consume before | |
| 1512 // we will demand a valid source-address token. | |
| 1513 const size_t max_unverified_size = | |
| 1514 client_hello.size() * chlo_multiplier_ - kREJOverheadBytes; | |
| 1515 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes, | |
| 1516 "overhead calculation may underflow"); | |
| 1517 bool should_return_sct = | |
| 1518 params->sct_supported_by_client && enable_serving_sct_; | |
| 1519 const size_t sct_size = should_return_sct ? crypto_proof.cert_sct.size() : 0; | |
| 1520 if (info.valid_source_address_token || | |
| 1521 crypto_proof.signature.size() + compressed.size() + sct_size < | |
| 1522 max_unverified_size) { | |
| 1523 out->SetStringPiece(kCertificateTag, compressed); | |
| 1524 out->SetStringPiece(kPROF, crypto_proof.signature); | |
| 1525 if (should_return_sct) { | |
| 1526 if (crypto_proof.cert_sct.empty()) { | |
| 1527 DLOG(WARNING) << "SCT is expected but it is empty."; | |
| 1528 } else { | |
| 1529 out->SetStringPiece(kCertificateSCTTag, crypto_proof.cert_sct); | |
| 1530 } | |
| 1531 } | |
| 1532 } | |
| 1533 } | |
| 1534 | |
| 1535 string QuicCryptoServerConfig::CompressChain( | |
| 1536 QuicCompressedCertsCache* compressed_certs_cache, | |
| 1537 const scoped_refptr<ProofSource::Chain>& chain, | |
| 1538 const string& client_common_set_hashes, | |
| 1539 const string& client_cached_cert_hashes, | |
| 1540 const CommonCertSets* common_sets) { | |
| 1541 // Check whether the compressed certs is available in the cache. | |
| 1542 DCHECK(compressed_certs_cache); | |
| 1543 const string* cached_value = compressed_certs_cache->GetCompressedCert( | |
| 1544 chain, client_common_set_hashes, client_cached_cert_hashes); | |
| 1545 if (cached_value) { | |
| 1546 return *cached_value; | |
| 1547 } | |
| 1548 | |
| 1549 const string compressed = | |
| 1550 CertCompressor::CompressChain(chain->certs, client_common_set_hashes, | |
| 1551 client_common_set_hashes, common_sets); | |
| 1552 | |
| 1553 // Insert the newly compressed cert to cache. | |
| 1554 compressed_certs_cache->Insert(chain, client_common_set_hashes, | |
| 1555 client_cached_cert_hashes, compressed); | |
| 1556 return compressed; | |
| 1557 } | |
| 1558 | |
| 1559 scoped_refptr<QuicCryptoServerConfig::Config> | |
| 1560 QuicCryptoServerConfig::ParseConfigProtobuf( | |
| 1561 QuicServerConfigProtobuf* protobuf) { | |
| 1562 std::unique_ptr<CryptoHandshakeMessage> msg( | |
| 1563 CryptoFramer::ParseMessage(protobuf->config())); | |
| 1564 | |
| 1565 if (msg->tag() != kSCFG) { | |
| 1566 LOG(WARNING) << "Server config message has tag " << msg->tag() | |
| 1567 << " expected " << kSCFG; | |
| 1568 return nullptr; | |
| 1569 } | |
| 1570 | |
| 1571 scoped_refptr<Config> config(new Config); | |
| 1572 config->serialized = protobuf->config(); | |
| 1573 | |
| 1574 if (!protobuf->has_source_address_token_secret_override()) { | |
| 1575 // Use the default boxer. | |
| 1576 config->source_address_token_boxer = &default_source_address_token_boxer_; | |
| 1577 } else { | |
| 1578 // Create override boxer instance. | |
| 1579 CryptoSecretBoxer* boxer = new CryptoSecretBoxer; | |
| 1580 boxer->SetKeys({DeriveSourceAddressTokenKey( | |
| 1581 protobuf->source_address_token_secret_override())}); | |
| 1582 config->source_address_token_boxer_storage.reset(boxer); | |
| 1583 config->source_address_token_boxer = boxer; | |
| 1584 } | |
| 1585 | |
| 1586 if (protobuf->has_primary_time()) { | |
| 1587 config->primary_time = | |
| 1588 QuicWallTime::FromUNIXSeconds(protobuf->primary_time()); | |
| 1589 } | |
| 1590 | |
| 1591 config->priority = protobuf->priority(); | |
| 1592 | |
| 1593 StringPiece scid; | |
| 1594 if (!msg->GetStringPiece(kSCID, &scid)) { | |
| 1595 LOG(WARNING) << "Server config message is missing SCID"; | |
| 1596 return nullptr; | |
| 1597 } | |
| 1598 config->id = scid.as_string(); | |
| 1599 | |
| 1600 const QuicTag* aead_tags; | |
| 1601 size_t aead_len; | |
| 1602 if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) { | |
| 1603 LOG(WARNING) << "Server config message is missing AEAD"; | |
| 1604 return nullptr; | |
| 1605 } | |
| 1606 config->aead = vector<QuicTag>(aead_tags, aead_tags + aead_len); | |
| 1607 | |
| 1608 const QuicTag* kexs_tags; | |
| 1609 size_t kexs_len; | |
| 1610 if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) { | |
| 1611 LOG(WARNING) << "Server config message is missing KEXS"; | |
| 1612 return nullptr; | |
| 1613 } | |
| 1614 | |
| 1615 const QuicTag* tbkp_tags; | |
| 1616 size_t tbkp_len; | |
| 1617 QuicErrorCode err; | |
| 1618 if ((err = msg->GetTaglist(kTBKP, &tbkp_tags, &tbkp_len)) != | |
| 1619 QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND && | |
| 1620 err != QUIC_NO_ERROR) { | |
| 1621 LOG(WARNING) << "Server config message is missing or has invalid TBKP"; | |
| 1622 return nullptr; | |
| 1623 } | |
| 1624 config->tb_key_params = vector<QuicTag>(tbkp_tags, tbkp_tags + tbkp_len); | |
| 1625 | |
| 1626 StringPiece orbit; | |
| 1627 if (!msg->GetStringPiece(kORBT, &orbit)) { | |
| 1628 LOG(WARNING) << "Server config message is missing ORBT"; | |
| 1629 return nullptr; | |
| 1630 } | |
| 1631 | |
| 1632 if (orbit.size() != kOrbitSize) { | |
| 1633 LOG(WARNING) << "Orbit value in server config is the wrong length." | |
| 1634 " Got " | |
| 1635 << orbit.size() << " want " << kOrbitSize; | |
| 1636 return nullptr; | |
| 1637 } | |
| 1638 static_assert(sizeof(config->orbit) == kOrbitSize, | |
| 1639 "orbit has incorrect size"); | |
| 1640 memcpy(config->orbit, orbit.data(), sizeof(config->orbit)); | |
| 1641 | |
| 1642 { | |
| 1643 StrikeRegisterClient* strike_register_client; | |
| 1644 { | |
| 1645 base::AutoLock locked(strike_register_client_lock_); | |
| 1646 strike_register_client = strike_register_client_.get(); | |
| 1647 } | |
| 1648 | |
| 1649 if (strike_register_client != nullptr && | |
| 1650 !strike_register_client->IsKnownOrbit(orbit)) { | |
| 1651 LOG(WARNING) | |
| 1652 << "Rejecting server config with orbit that the strike register " | |
| 1653 "client doesn't know about."; | |
| 1654 return nullptr; | |
| 1655 } | |
| 1656 } | |
| 1657 | |
| 1658 if (kexs_len != protobuf->key_size()) { | |
| 1659 LOG(WARNING) << "Server config has " << kexs_len | |
| 1660 << " key exchange methods configured, but " | |
| 1661 << protobuf->key_size() << " private keys"; | |
| 1662 return nullptr; | |
| 1663 } | |
| 1664 | |
| 1665 const QuicTag* proof_demand_tags; | |
| 1666 size_t num_proof_demand_tags; | |
| 1667 if (msg->GetTaglist(kPDMD, &proof_demand_tags, &num_proof_demand_tags) == | |
| 1668 QUIC_NO_ERROR) { | |
| 1669 for (size_t i = 0; i < num_proof_demand_tags; i++) { | |
| 1670 if (proof_demand_tags[i] == kCHID) { | |
| 1671 config->channel_id_enabled = true; | |
| 1672 break; | |
| 1673 } | |
| 1674 } | |
| 1675 } | |
| 1676 | |
| 1677 for (size_t i = 0; i < kexs_len; i++) { | |
| 1678 const QuicTag tag = kexs_tags[i]; | |
| 1679 string private_key; | |
| 1680 | |
| 1681 config->kexs.push_back(tag); | |
| 1682 | |
| 1683 for (size_t j = 0; j < protobuf->key_size(); j++) { | |
| 1684 const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i); | |
| 1685 if (key.tag() == tag) { | |
| 1686 private_key = key.private_key(); | |
| 1687 break; | |
| 1688 } | |
| 1689 } | |
| 1690 | |
| 1691 if (private_key.empty()) { | |
| 1692 LOG(WARNING) << "Server config contains key exchange method without " | |
| 1693 "corresponding private key: " | |
| 1694 << tag; | |
| 1695 return nullptr; | |
| 1696 } | |
| 1697 | |
| 1698 std::unique_ptr<KeyExchange> ka; | |
| 1699 switch (tag) { | |
| 1700 case kC255: | |
| 1701 ka.reset(Curve25519KeyExchange::New(private_key)); | |
| 1702 if (!ka.get()) { | |
| 1703 LOG(WARNING) << "Server config contained an invalid curve25519" | |
| 1704 " private key."; | |
| 1705 return nullptr; | |
| 1706 } | |
| 1707 break; | |
| 1708 case kP256: | |
| 1709 ka.reset(P256KeyExchange::New(private_key)); | |
| 1710 if (!ka.get()) { | |
| 1711 LOG(WARNING) << "Server config contained an invalid P-256" | |
| 1712 " private key."; | |
| 1713 return nullptr; | |
| 1714 } | |
| 1715 break; | |
| 1716 default: | |
| 1717 LOG(WARNING) << "Server config message contains unknown key exchange " | |
| 1718 "method: " | |
| 1719 << tag; | |
| 1720 return nullptr; | |
| 1721 } | |
| 1722 | |
| 1723 for (const KeyExchange* key_exchange : config->key_exchanges) { | |
| 1724 if (key_exchange->tag() == tag) { | |
| 1725 LOG(WARNING) << "Duplicate key exchange in config: " << tag; | |
| 1726 return nullptr; | |
| 1727 } | |
| 1728 } | |
| 1729 | |
| 1730 config->key_exchanges.push_back(ka.release()); | |
| 1731 } | |
| 1732 | |
| 1733 return config; | |
| 1734 } | |
| 1735 | |
| 1736 void QuicCryptoServerConfig::SetEphemeralKeySource( | |
| 1737 EphemeralKeySource* ephemeral_key_source) { | |
| 1738 ephemeral_key_source_.reset(ephemeral_key_source); | |
| 1739 } | |
| 1740 | |
| 1741 void QuicCryptoServerConfig::SetStrikeRegisterClient( | |
| 1742 StrikeRegisterClient* strike_register_client) { | |
| 1743 base::AutoLock locker(strike_register_client_lock_); | |
| 1744 DCHECK(!strike_register_client_.get()); | |
| 1745 strike_register_client_.reset(strike_register_client); | |
| 1746 } | |
| 1747 | |
| 1748 void QuicCryptoServerConfig::set_replay_protection(bool on) { | |
| 1749 replay_protection_ = on; | |
| 1750 } | |
| 1751 | |
| 1752 void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) { | |
| 1753 chlo_multiplier_ = multiplier; | |
| 1754 } | |
| 1755 | |
| 1756 void QuicCryptoServerConfig::set_strike_register_no_startup_period() { | |
| 1757 base::AutoLock locker(strike_register_client_lock_); | |
| 1758 DCHECK(!strike_register_client_.get()); | |
| 1759 strike_register_no_startup_period_ = true; | |
| 1760 } | |
| 1761 | |
| 1762 void QuicCryptoServerConfig::set_strike_register_max_entries( | |
| 1763 uint32_t max_entries) { | |
| 1764 base::AutoLock locker(strike_register_client_lock_); | |
| 1765 DCHECK(!strike_register_client_.get()); | |
| 1766 strike_register_max_entries_ = max_entries; | |
| 1767 } | |
| 1768 | |
| 1769 void QuicCryptoServerConfig::set_strike_register_window_secs( | |
| 1770 uint32_t window_secs) { | |
| 1771 base::AutoLock locker(strike_register_client_lock_); | |
| 1772 DCHECK(!strike_register_client_.get()); | |
| 1773 strike_register_window_secs_ = window_secs; | |
| 1774 } | |
| 1775 | |
| 1776 void QuicCryptoServerConfig::set_source_address_token_future_secs( | |
| 1777 uint32_t future_secs) { | |
| 1778 source_address_token_future_secs_ = future_secs; | |
| 1779 } | |
| 1780 | |
| 1781 void QuicCryptoServerConfig::set_source_address_token_lifetime_secs( | |
| 1782 uint32_t lifetime_secs) { | |
| 1783 source_address_token_lifetime_secs_ = lifetime_secs; | |
| 1784 } | |
| 1785 | |
| 1786 void QuicCryptoServerConfig::set_server_nonce_strike_register_max_entries( | |
| 1787 uint32_t max_entries) { | |
| 1788 DCHECK(!server_nonce_strike_register_.get()); | |
| 1789 server_nonce_strike_register_max_entries_ = max_entries; | |
| 1790 } | |
| 1791 | |
| 1792 void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs( | |
| 1793 uint32_t window_secs) { | |
| 1794 DCHECK(!server_nonce_strike_register_.get()); | |
| 1795 server_nonce_strike_register_window_secs_ = window_secs; | |
| 1796 } | |
| 1797 | |
| 1798 void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) { | |
| 1799 enable_serving_sct_ = enable_serving_sct; | |
| 1800 } | |
| 1801 | |
| 1802 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb( | |
| 1803 PrimaryConfigChangedCallback* cb) { | |
| 1804 base::AutoLock locked(configs_lock_); | |
| 1805 primary_config_changed_cb_.reset(cb); | |
| 1806 } | |
| 1807 | |
| 1808 string QuicCryptoServerConfig::NewSourceAddressToken( | |
| 1809 const Config& config, | |
| 1810 const SourceAddressTokens& previous_tokens, | |
| 1811 const IPAddress& ip, | |
| 1812 QuicRandom* rand, | |
| 1813 QuicWallTime now, | |
| 1814 const CachedNetworkParameters* cached_network_params) const { | |
| 1815 SourceAddressTokens source_address_tokens; | |
| 1816 SourceAddressToken* source_address_token = source_address_tokens.add_tokens(); | |
| 1817 source_address_token->set_ip(IPAddressToPackedString(DualstackIPAddress(ip))); | |
| 1818 source_address_token->set_timestamp(now.ToUNIXSeconds()); | |
| 1819 if (cached_network_params != nullptr) { | |
| 1820 *(source_address_token->mutable_cached_network_parameters()) = | |
| 1821 *cached_network_params; | |
| 1822 } | |
| 1823 | |
| 1824 // Append previous tokens. | |
| 1825 for (const SourceAddressToken& token : previous_tokens.tokens()) { | |
| 1826 if (source_address_tokens.tokens_size() > kMaxTokenAddresses) { | |
| 1827 break; | |
| 1828 } | |
| 1829 | |
| 1830 if (token.ip() == source_address_token->ip()) { | |
| 1831 // It's for the same IP address. | |
| 1832 continue; | |
| 1833 } | |
| 1834 | |
| 1835 if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) { | |
| 1836 continue; | |
| 1837 } | |
| 1838 | |
| 1839 *(source_address_tokens.add_tokens()) = token; | |
| 1840 } | |
| 1841 | |
| 1842 return config.source_address_token_boxer->Box( | |
| 1843 rand, source_address_tokens.SerializeAsString()); | |
| 1844 } | |
| 1845 | |
| 1846 int QuicCryptoServerConfig::NumberOfConfigs() const { | |
| 1847 base::AutoLock locked(configs_lock_); | |
| 1848 return configs_.size(); | |
| 1849 } | |
| 1850 | |
| 1851 HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken( | |
| 1852 const Config& config, | |
| 1853 StringPiece token, | |
| 1854 SourceAddressTokens* tokens) const { | |
| 1855 string storage; | |
| 1856 StringPiece plaintext; | |
| 1857 if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) { | |
| 1858 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE; | |
| 1859 } | |
| 1860 | |
| 1861 if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) { | |
| 1862 // Some clients might still be using the old source token format so | |
| 1863 // attempt to parse that format. | |
| 1864 // TODO(rch): remove this code once the new format is ubiquitous. | |
| 1865 SourceAddressToken source_address_token; | |
| 1866 if (!source_address_token.ParseFromArray(plaintext.data(), | |
| 1867 plaintext.size())) { | |
| 1868 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE; | |
| 1869 } | |
| 1870 *tokens->add_tokens() = source_address_token; | |
| 1871 } | |
| 1872 | |
| 1873 return HANDSHAKE_OK; | |
| 1874 } | |
| 1875 | |
| 1876 HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens( | |
| 1877 const SourceAddressTokens& source_address_tokens, | |
| 1878 const IPAddress& ip, | |
| 1879 QuicWallTime now, | |
| 1880 CachedNetworkParameters* cached_network_params) const { | |
| 1881 HandshakeFailureReason reason = | |
| 1882 SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE; | |
| 1883 for (const SourceAddressToken& token : source_address_tokens.tokens()) { | |
| 1884 reason = ValidateSingleSourceAddressToken(token, ip, now); | |
| 1885 if (reason == HANDSHAKE_OK) { | |
| 1886 if (token.has_cached_network_parameters()) { | |
| 1887 *cached_network_params = token.cached_network_parameters(); | |
| 1888 } | |
| 1889 break; | |
| 1890 } | |
| 1891 } | |
| 1892 return reason; | |
| 1893 } | |
| 1894 | |
| 1895 HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken( | |
| 1896 const SourceAddressToken& source_address_token, | |
| 1897 const IPAddress& ip, | |
| 1898 QuicWallTime now) const { | |
| 1899 if (source_address_token.ip() != | |
| 1900 IPAddressToPackedString(DualstackIPAddress(ip))) { | |
| 1901 // It's for a different IP address. | |
| 1902 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE; | |
| 1903 } | |
| 1904 | |
| 1905 return ValidateSourceAddressTokenTimestamp(source_address_token, now); | |
| 1906 } | |
| 1907 | |
| 1908 HandshakeFailureReason | |
| 1909 QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp( | |
| 1910 const SourceAddressToken& source_address_token, | |
| 1911 QuicWallTime now) const { | |
| 1912 const QuicWallTime timestamp( | |
| 1913 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp())); | |
| 1914 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp)); | |
| 1915 | |
| 1916 if (now.IsBefore(timestamp) && | |
| 1917 delta.ToSeconds() > source_address_token_future_secs_) { | |
| 1918 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE; | |
| 1919 } | |
| 1920 | |
| 1921 if (now.IsAfter(timestamp) && | |
| 1922 delta.ToSeconds() > source_address_token_lifetime_secs_) { | |
| 1923 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE; | |
| 1924 } | |
| 1925 | |
| 1926 return HANDSHAKE_OK; | |
| 1927 } | |
| 1928 | |
| 1929 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server | |
| 1930 // nonce. | |
| 1931 static const size_t kServerNoncePlaintextSize = | |
| 1932 4 /* timestamp */ + 20 /* random bytes */; | |
| 1933 | |
| 1934 string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand, | |
| 1935 QuicWallTime now) const { | |
| 1936 const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds()); | |
| 1937 | |
| 1938 uint8_t server_nonce[kServerNoncePlaintextSize]; | |
| 1939 static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small"); | |
| 1940 server_nonce[0] = static_cast<uint8_t>(timestamp >> 24); | |
| 1941 server_nonce[1] = static_cast<uint8_t>(timestamp >> 16); | |
| 1942 server_nonce[2] = static_cast<uint8_t>(timestamp >> 8); | |
| 1943 server_nonce[3] = static_cast<uint8_t>(timestamp); | |
| 1944 rand->RandBytes(&server_nonce[sizeof(timestamp)], | |
| 1945 sizeof(server_nonce) - sizeof(timestamp)); | |
| 1946 | |
| 1947 return server_nonce_boxer_.Box( | |
| 1948 rand, | |
| 1949 StringPiece(reinterpret_cast<char*>(server_nonce), sizeof(server_nonce))); | |
| 1950 } | |
| 1951 | |
| 1952 HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce( | |
| 1953 StringPiece token, | |
| 1954 QuicWallTime now) const { | |
| 1955 string storage; | |
| 1956 StringPiece plaintext; | |
| 1957 if (!server_nonce_boxer_.Unbox(token, &storage, &plaintext)) { | |
| 1958 return SERVER_NONCE_DECRYPTION_FAILURE; | |
| 1959 } | |
| 1960 | |
| 1961 // plaintext contains: | |
| 1962 // uint32_t timestamp | |
| 1963 // uint8_t[20] random bytes | |
| 1964 | |
| 1965 if (plaintext.size() != kServerNoncePlaintextSize) { | |
| 1966 // This should never happen because the value decrypted correctly. | |
| 1967 QUIC_BUG << "Seemingly valid server nonce had incorrect length."; | |
| 1968 return SERVER_NONCE_INVALID_FAILURE; | |
| 1969 } | |
| 1970 | |
| 1971 uint8_t server_nonce[32]; | |
| 1972 memcpy(server_nonce, plaintext.data(), 4); | |
| 1973 memcpy(server_nonce + 4, server_nonce_orbit_, sizeof(server_nonce_orbit_)); | |
| 1974 memcpy(server_nonce + 4 + sizeof(server_nonce_orbit_), plaintext.data() + 4, | |
| 1975 20); | |
| 1976 static_assert(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce), | |
| 1977 "bad nonce buffer length"); | |
| 1978 | |
| 1979 InsertStatus nonce_error; | |
| 1980 { | |
| 1981 base::AutoLock auto_lock(server_nonce_strike_register_lock_); | |
| 1982 if (server_nonce_strike_register_.get() == nullptr) { | |
| 1983 server_nonce_strike_register_.reset(new StrikeRegister( | |
| 1984 server_nonce_strike_register_max_entries_, | |
| 1985 static_cast<uint32_t>(now.ToUNIXSeconds()), | |
| 1986 server_nonce_strike_register_window_secs_, server_nonce_orbit_, | |
| 1987 StrikeRegister::NO_STARTUP_PERIOD_NEEDED)); | |
| 1988 } | |
| 1989 nonce_error = server_nonce_strike_register_->Insert( | |
| 1990 server_nonce, static_cast<uint32_t>(now.ToUNIXSeconds())); | |
| 1991 } | |
| 1992 | |
| 1993 switch (nonce_error) { | |
| 1994 case NONCE_OK: | |
| 1995 return HANDSHAKE_OK; | |
| 1996 case NONCE_INVALID_FAILURE: | |
| 1997 case NONCE_INVALID_ORBIT_FAILURE: | |
| 1998 return SERVER_NONCE_INVALID_FAILURE; | |
| 1999 case NONCE_NOT_UNIQUE_FAILURE: | |
| 2000 return SERVER_NONCE_NOT_UNIQUE_FAILURE; | |
| 2001 case NONCE_INVALID_TIME_FAILURE: | |
| 2002 return SERVER_NONCE_INVALID_TIME_FAILURE; | |
| 2003 case NONCE_UNKNOWN_FAILURE: | |
| 2004 case STRIKE_REGISTER_TIMEOUT: | |
| 2005 case STRIKE_REGISTER_FAILURE: | |
| 2006 default: | |
| 2007 QUIC_BUG << "Unexpected server nonce error: " << nonce_error; | |
| 2008 return SERVER_NONCE_NOT_UNIQUE_FAILURE; | |
| 2009 } | |
| 2010 } | |
| 2011 | |
| 2012 bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate( | |
| 2013 const CryptoHandshakeMessage& client_hello, | |
| 2014 const QuicCryptoProof& crypto_proof) const { | |
| 2015 if (crypto_proof.chain->certs.empty()) { | |
| 2016 return false; | |
| 2017 } | |
| 2018 | |
| 2019 uint64_t hash_from_client; | |
| 2020 if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) { | |
| 2021 return false; | |
| 2022 } | |
| 2023 return CryptoUtils::ComputeLeafCertHash(crypto_proof.chain->certs.at(0)) == | |
| 2024 hash_from_client; | |
| 2025 } | |
| 2026 | |
| 2027 void QuicCryptoServerConfig::ParseProofDemand( | |
| 2028 const CryptoHandshakeMessage& client_hello, | |
| 2029 bool* x509_supported, | |
| 2030 bool* x509_ecdsa_supported) const { | |
| 2031 const QuicTag* their_proof_demands; | |
| 2032 size_t num_their_proof_demands; | |
| 2033 | |
| 2034 if (client_hello.GetTaglist(kPDMD, &their_proof_demands, | |
| 2035 &num_their_proof_demands) != QUIC_NO_ERROR) { | |
| 2036 return; | |
| 2037 } | |
| 2038 | |
| 2039 *x509_supported = false; | |
| 2040 for (size_t i = 0; i < num_their_proof_demands; i++) { | |
| 2041 switch (their_proof_demands[i]) { | |
| 2042 case kX509: | |
| 2043 *x509_supported = true; | |
| 2044 *x509_ecdsa_supported = true; | |
| 2045 break; | |
| 2046 case kX59R: | |
| 2047 *x509_supported = true; | |
| 2048 break; | |
| 2049 } | |
| 2050 } | |
| 2051 } | |
| 2052 | |
| 2053 QuicCryptoServerConfig::Config::Config() | |
| 2054 : channel_id_enabled(false), | |
| 2055 is_primary(false), | |
| 2056 primary_time(QuicWallTime::Zero()), | |
| 2057 priority(0), | |
| 2058 source_address_token_boxer(nullptr) {} | |
| 2059 | |
| 2060 QuicCryptoServerConfig::Config::~Config() { | |
| 2061 STLDeleteElements(&key_exchanges); | |
| 2062 } | |
| 2063 | |
| 2064 QuicCryptoProof::QuicCryptoProof() {} | |
| 2065 QuicCryptoProof::~QuicCryptoProof() {} | |
| 2066 } // namespace net | |
| OLD | NEW |