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 #ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_ 6 #define QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_ 7 8 #include <cstddef> 9 #include <cstdint> 10 #include <map> 11 #include <memory> 12 #include <string> 13 #include <vector> 14 15 #include "absl/strings/string_view.h" 16 #include "openssl/base.h" 17 #include "quiche/quic/core/crypto/crypto_handshake.h" 18 #include "quiche/quic/core/crypto/crypto_handshake_message.h" 19 #include "quiche/quic/core/crypto/crypto_protocol.h" 20 #include "quiche/quic/core/crypto/crypto_secret_boxer.h" 21 #include "quiche/quic/core/crypto/key_exchange.h" 22 #include "quiche/quic/core/crypto/proof_source.h" 23 #include "quiche/quic/core/crypto/quic_compressed_certs_cache.h" 24 #include "quiche/quic/core/crypto/quic_crypto_proof.h" 25 #include "quiche/quic/core/crypto/quic_random.h" 26 #include "quiche/quic/core/proto/cached_network_parameters_proto.h" 27 #include "quiche/quic/core/proto/source_address_token_proto.h" 28 #include "quiche/quic/core/quic_time.h" 29 #include "quiche/quic/platform/api/quic_export.h" 30 #include "quiche/quic/platform/api/quic_mutex.h" 31 #include "quiche/quic/platform/api/quic_socket_address.h" 32 #include "quiche/common/platform/api/quiche_reference_counted.h" 33 34 namespace quic { 35 36 class CryptoHandshakeMessage; 37 class ProofSource; 38 class QuicClock; 39 class QuicServerConfigProtobuf; 40 struct QuicSignedServerConfig; 41 42 // ClientHelloInfo contains information about a client hello message that is 43 // only kept for as long as it's being processed. 44 struct QUICHE_EXPORT ClientHelloInfo { 45 ClientHelloInfo(const QuicIpAddress& in_client_ip, QuicWallTime in_now); 46 ClientHelloInfo(const ClientHelloInfo& other); 47 ~ClientHelloInfo(); 48 49 // Inputs to EvaluateClientHello. 50 const QuicIpAddress client_ip; 51 const QuicWallTime now; 52 53 // Outputs from EvaluateClientHello. 54 bool valid_source_address_token; 55 absl::string_view sni; 56 absl::string_view client_nonce; 57 absl::string_view server_nonce; 58 absl::string_view user_agent_id; 59 SourceAddressTokens source_address_tokens; 60 61 // Errors from EvaluateClientHello. 62 std::vector<uint32_t> reject_reasons; 63 static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync"); 64 }; 65 66 namespace test { 67 class QuicCryptoServerConfigPeer; 68 } // namespace test 69 70 // Hook that allows application code to subscribe to primary config changes. 71 class QUICHE_EXPORT PrimaryConfigChangedCallback { 72 public: 73 PrimaryConfigChangedCallback(); 74 PrimaryConfigChangedCallback(const PrimaryConfigChangedCallback&) = delete; 75 PrimaryConfigChangedCallback& operator=(const PrimaryConfigChangedCallback&) = 76 delete; 77 virtual ~PrimaryConfigChangedCallback(); 78 virtual void Run(const std::string& scid) = 0; 79 }; 80 81 // Callback used to accept the result of the |client_hello| validation step. 82 class QUICHE_EXPORT ValidateClientHelloResultCallback { 83 public: 84 // Opaque token that holds information about the client_hello and 85 // its validity. Can be interpreted by calling ProcessClientHello. 86 struct QUICHE_EXPORT Result : public quiche::QuicheReferenceCounted { 87 Result(const CryptoHandshakeMessage& in_client_hello, 88 QuicIpAddress in_client_ip, QuicWallTime in_now); 89 90 CryptoHandshakeMessage client_hello; 91 ClientHelloInfo info; 92 QuicErrorCode error_code; 93 std::string error_details; 94 95 // Populated if the CHLO STK contained a CachedNetworkParameters proto. 96 CachedNetworkParameters cached_network_params; 97 98 protected: 99 ~Result() override; 100 }; 101 102 ValidateClientHelloResultCallback(); 103 ValidateClientHelloResultCallback(const ValidateClientHelloResultCallback&) = 104 delete; 105 ValidateClientHelloResultCallback& operator=( 106 const ValidateClientHelloResultCallback&) = delete; 107 virtual ~ValidateClientHelloResultCallback(); 108 virtual void Run(quiche::QuicheReferenceCountedPointer<Result> result, 109 std::unique_ptr<ProofSource::Details> details) = 0; 110 }; 111 112 // Callback used to accept the result of the ProcessClientHello method. 113 class QUICHE_EXPORT ProcessClientHelloResultCallback { 114 public: 115 ProcessClientHelloResultCallback(); 116 ProcessClientHelloResultCallback(const ProcessClientHelloResultCallback&) = 117 delete; 118 ProcessClientHelloResultCallback& operator=( 119 const ProcessClientHelloResultCallback&) = delete; 120 virtual ~ProcessClientHelloResultCallback(); 121 virtual void Run(QuicErrorCode error, const std::string& error_details, 122 std::unique_ptr<CryptoHandshakeMessage> message, 123 std::unique_ptr<DiversificationNonce> diversification_nonce, 124 std::unique_ptr<ProofSource::Details> details) = 0; 125 }; 126 127 // Callback used to receive the results of a call to 128 // BuildServerConfigUpdateMessage. 129 class QUICHE_EXPORT BuildServerConfigUpdateMessageResultCallback { 130 public: 131 BuildServerConfigUpdateMessageResultCallback() = default; ~BuildServerConfigUpdateMessageResultCallback()132 virtual ~BuildServerConfigUpdateMessageResultCallback() {} 133 BuildServerConfigUpdateMessageResultCallback( 134 const BuildServerConfigUpdateMessageResultCallback&) = delete; 135 BuildServerConfigUpdateMessageResultCallback& operator=( 136 const BuildServerConfigUpdateMessageResultCallback&) = delete; 137 virtual void Run(bool ok, const CryptoHandshakeMessage& message) = 0; 138 }; 139 140 // Object that is interested in built rejections (which include REJ, SREJ and 141 // cheap SREJ). 142 class QUICHE_EXPORT RejectionObserver { 143 public: 144 RejectionObserver() = default; ~RejectionObserver()145 virtual ~RejectionObserver() {} 146 RejectionObserver(const RejectionObserver&) = delete; 147 RejectionObserver& operator=(const RejectionObserver&) = delete; 148 // Called after a rejection is built. 149 virtual void OnRejectionBuilt(const std::vector<uint32_t>& reasons, 150 CryptoHandshakeMessage* out) const = 0; 151 }; 152 153 // Factory for creating KeyExchange objects. 154 class QUICHE_EXPORT KeyExchangeSource { 155 public: 156 virtual ~KeyExchangeSource() = default; 157 158 // Returns the default KeyExchangeSource. 159 static std::unique_ptr<KeyExchangeSource> Default(); 160 161 // Create a new KeyExchange using the curve specified by |type| using the 162 // specified private key. |private_key| may be empty for key-exchange 163 // mechanisms which do not hold the private key in-process. If |is_fallback| 164 // is set, |private_key| is required to be set, and a local key-exchange 165 // object should be returned. 166 virtual std::unique_ptr<AsynchronousKeyExchange> Create( 167 std::string server_config_id, bool is_fallback, QuicTag type, 168 absl::string_view private_key) = 0; 169 }; 170 171 // QuicCryptoServerConfig contains the crypto configuration of a QUIC server. 172 // Unlike a client, a QUIC server can have multiple configurations active in 173 // order to support clients resuming with a previous configuration. 174 // TODO(agl): when adding configurations at runtime is added, this object will 175 // need to consider locking. 176 class QUICHE_EXPORT QuicCryptoServerConfig { 177 public: 178 // ConfigOptions contains options for generating server configs. 179 struct QUICHE_EXPORT ConfigOptions { 180 ConfigOptions(); 181 ConfigOptions(const ConfigOptions& other); 182 ~ConfigOptions(); 183 184 // expiry_time is the time, in UNIX seconds, when the server config will 185 // expire. If unset, it defaults to the current time plus six months. 186 QuicWallTime expiry_time; 187 // channel_id_enabled controls whether the server config will indicate 188 // support for ChannelIDs. 189 bool channel_id_enabled; 190 // id contains the server config id for the resulting config. If empty, a 191 // random id is generated. 192 std::string id; 193 // orbit contains the kOrbitSize bytes of the orbit value for the server 194 // config. If |orbit| is empty then a random orbit is generated. 195 std::string orbit; 196 // p256 determines whether a P-256 public key will be included in the 197 // server config. Note that this breaks deterministic server-config 198 // generation since P-256 key generation doesn't use the QuicRandom given 199 // to GenerateConfig(). 200 bool p256; 201 }; 202 203 // |source_address_token_secret|: secret key material used for encrypting and 204 // decrypting source address tokens. It can be of any length as it is fed 205 // into a KDF before use. In tests, use TESTING. 206 // |server_nonce_entropy|: an entropy source used to generate the orbit and 207 // key for server nonces, which are always local to a given instance of a 208 // server. Not owned. 209 // |proof_source|: provides certificate chains and signatures. 210 // |key_exchange_source|: provides key-exchange functionality. 211 QuicCryptoServerConfig( 212 absl::string_view source_address_token_secret, 213 QuicRandom* server_nonce_entropy, 214 std::unique_ptr<ProofSource> proof_source, 215 std::unique_ptr<KeyExchangeSource> key_exchange_source); 216 QuicCryptoServerConfig(const QuicCryptoServerConfig&) = delete; 217 QuicCryptoServerConfig& operator=(const QuicCryptoServerConfig&) = delete; 218 ~QuicCryptoServerConfig(); 219 220 // TESTING is a magic parameter for passing to the constructor in tests. 221 static const char TESTING[]; 222 223 // Generates a QuicServerConfigProtobuf protobuf suitable for 224 // AddConfig and SetConfigs. 225 static QuicServerConfigProtobuf GenerateConfig(QuicRandom* rand, 226 const QuicClock* clock, 227 const ConfigOptions& options); 228 229 // AddConfig adds a QuicServerConfigProtobuf to the available configurations. 230 // It returns the SCFG message from the config if successful. |now| is used in 231 // conjunction with |protobuf->primary_time()| to determine whether the 232 // config should be made primary. 233 std::unique_ptr<CryptoHandshakeMessage> AddConfig( 234 const QuicServerConfigProtobuf& protobuf, QuicWallTime now); 235 236 // AddDefaultConfig calls GenerateConfig to create a config and then calls 237 // AddConfig to add it. See the comment for |GenerateConfig| for details of 238 // the arguments. 239 std::unique_ptr<CryptoHandshakeMessage> AddDefaultConfig( 240 QuicRandom* rand, const QuicClock* clock, const ConfigOptions& options); 241 242 // SetConfigs takes a vector of config protobufs and the current time. 243 // Configs are assumed to be uniquely identified by their server config ID. 244 // Previously unknown configs are added and possibly made the primary config 245 // depending on their |primary_time| and the value of |now|. Configs that are 246 // known, but are missing from the protobufs are deleted, unless they are 247 // currently the primary config. SetConfigs returns false if any errors were 248 // encountered and no changes to the QuicCryptoServerConfig will occur. 249 bool SetConfigs(const std::vector<QuicServerConfigProtobuf>& protobufs, 250 const QuicServerConfigProtobuf* fallback_protobuf, 251 QuicWallTime now); 252 253 // SetSourceAddressTokenKeys sets the keys to be tried, in order, when 254 // decrypting a source address token. Note that these keys are used *without* 255 // passing them through a KDF, in contradistinction to the 256 // |source_address_token_secret| argument to the constructor. 257 void SetSourceAddressTokenKeys(const std::vector<std::string>& keys); 258 259 // Get the server config ids for all known configs. 260 std::vector<std::string> GetConfigIds() const; 261 262 // Checks |client_hello| for gross errors and determines whether it can be 263 // shown to be fresh (i.e. not a replay). The result of the validation step 264 // must be interpreted by calling QuicCryptoServerConfig::ProcessClientHello 265 // from the done_cb. 266 // 267 // ValidateClientHello may invoke the done_cb before unrolling the 268 // stack if it is able to assess the validity of the client_nonce 269 // without asynchronous operations. 270 // 271 // client_hello: the incoming client hello message. 272 // client_ip: the IP address of the client, which is used to generate and 273 // validate source-address tokens. 274 // server_address: the IP address and port of the server. The IP address and 275 // port may be used for certificate selection. 276 // version: protocol version used for this connection. 277 // clock: used to validate client nonces and ephemeral keys. 278 // signed_config: in/out parameter to which will be written the crypto proof 279 // used in reply to a proof demand. The pointed-to-object must live until 280 // the callback is invoked. 281 // done_cb: single-use callback that accepts an opaque 282 // ValidatedClientHelloMsg token that holds information about 283 // the client hello. The callback will always be called exactly 284 // once, either under the current call stack, or after the 285 // completion of an asynchronous operation. 286 void ValidateClientHello( 287 const CryptoHandshakeMessage& client_hello, 288 const QuicSocketAddress& client_address, 289 const QuicSocketAddress& server_address, QuicTransportVersion version, 290 const QuicClock* clock, 291 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> 292 signed_config, 293 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const; 294 295 // ProcessClientHello processes |client_hello| and decides whether to accept 296 // or reject the connection. If the connection is to be accepted, |done_cb| is 297 // invoked with the contents of the ServerHello and QUIC_NO_ERROR. Otherwise 298 // |done_cb| is called with a REJ or SREJ message and QUIC_NO_ERROR. 299 // 300 // validate_chlo_result: Output from the asynchronous call to 301 // ValidateClientHello. Contains the client hello message and 302 // information about it. 303 // reject_only: Only generate rejections, not server hello messages. 304 // connection_id: the ConnectionId for the connection, which is used in key 305 // derivation. 306 // server_ip: the IP address of the server. The IP address may be used for 307 // certificate selection. 308 // client_address: the IP address and port of the client. The IP address is 309 // used to generate and validate source-address tokens. 310 // version: version of the QUIC protocol in use for this connection 311 // supported_versions: versions of the QUIC protocol that this server 312 // supports. 313 // clock: used to validate client nonces and ephemeral keys. 314 // rand: an entropy source 315 // compressed_certs_cache: the cache that caches a set of most recently used 316 // certs. Owned by QuicDispatcher. 317 // params: the state of the handshake. This may be updated with a server 318 // nonce when we send a rejection. 319 // signed_config: output structure containing the crypto proof used in reply 320 // to a proof demand. 321 // total_framing_overhead: the total per-packet overhead for a stream frame 322 // chlo_packet_size: the size, in bytes, of the CHLO packet 323 // done_cb: the callback invoked on completion 324 void ProcessClientHello( 325 quiche::QuicheReferenceCountedPointer< 326 ValidateClientHelloResultCallback::Result> 327 validate_chlo_result, 328 bool reject_only, QuicConnectionId connection_id, 329 const QuicSocketAddress& server_address, 330 const QuicSocketAddress& client_address, ParsedQuicVersion version, 331 const ParsedQuicVersionVector& supported_versions, const QuicClock* clock, 332 QuicRandom* rand, QuicCompressedCertsCache* compressed_certs_cache, 333 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> 334 params, 335 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> 336 signed_config, 337 QuicByteCount total_framing_overhead, QuicByteCount chlo_packet_size, 338 std::shared_ptr<ProcessClientHelloResultCallback> done_cb) const; 339 340 // BuildServerConfigUpdateMessage invokes |cb| with a SCUP message containing 341 // the current primary config, an up to date source-address token, and cert 342 // chain and proof in the case of secure QUIC. Passes true to |cb| if the 343 // message was generated successfully, and false otherwise. This method 344 // assumes ownership of |cb|. 345 // 346 // |cached_network_params| is optional, and can be nullptr. 347 void BuildServerConfigUpdateMessage( 348 QuicTransportVersion version, absl::string_view chlo_hash, 349 const SourceAddressTokens& previous_source_address_tokens, 350 const QuicSocketAddress& server_address, 351 const QuicSocketAddress& client_address, const QuicClock* clock, 352 QuicRandom* rand, QuicCompressedCertsCache* compressed_certs_cache, 353 const QuicCryptoNegotiatedParameters& params, 354 const CachedNetworkParameters* cached_network_params, 355 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const; 356 357 // set_replay_protection controls whether replay protection is enabled. If 358 // replay protection is disabled then no strike registers are needed and 359 // frontends can share an orbit value without a shared strike-register. 360 // However, an attacker can duplicate a handshake and cause a client's 361 // request to be processed twice. 362 void set_replay_protection(bool on); 363 364 // set_chlo_multiplier specifies the multiple of the CHLO message size 365 // that a REJ message must stay under when the client doesn't present a 366 // valid source-address token. 367 void set_chlo_multiplier(size_t multiplier); 368 369 // When sender is allowed to not pad client hello (not standards compliant), 370 // we need to disable the client hello check. set_validate_chlo_size(bool new_value)371 void set_validate_chlo_size(bool new_value) { 372 validate_chlo_size_ = new_value; 373 } 374 375 // Returns whether the sender is allowed to not pad the client hello. validate_chlo_size()376 bool validate_chlo_size() const { return validate_chlo_size_; } 377 378 // When QUIC is tunneled through some other mechanism, source token validation 379 // may be disabled. Do not disable it if you are not providing other 380 // protection. (|true| protects against UDP amplification attack.). set_validate_source_address_token(bool new_value)381 void set_validate_source_address_token(bool new_value) { 382 validate_source_address_token_ = new_value; 383 } 384 385 // set_source_address_token_future_secs sets the number of seconds into the 386 // future that source-address tokens will be accepted from. Since 387 // source-address tokens are authenticated, this should only happen if 388 // another, valid server has clock-skew. 389 void set_source_address_token_future_secs(uint32_t future_secs); 390 391 // set_source_address_token_lifetime_secs sets the number of seconds that a 392 // source-address token will be valid for. 393 void set_source_address_token_lifetime_secs(uint32_t lifetime_secs); 394 395 // set_enable_serving_sct enables or disables serving signed cert timestamp 396 // (RFC6962) in server hello. 397 void set_enable_serving_sct(bool enable_serving_sct); 398 399 // Set and take ownership of the callback to invoke on primary config changes. 400 void AcquirePrimaryConfigChangedCb( 401 std::unique_ptr<PrimaryConfigChangedCallback> cb); 402 403 // Returns the number of configs this object owns. 404 int NumberOfConfigs() const; 405 406 // NewSourceAddressToken returns a fresh source address token for the given 407 // IP address. |previous_tokens| is the received tokens, and can be empty. 408 // |cached_network_params| is optional, and can be nullptr. 409 std::string NewSourceAddressToken( 410 const CryptoSecretBoxer& crypto_secret_boxer, 411 const SourceAddressTokens& previous_tokens, const QuicIpAddress& ip, 412 QuicRandom* rand, QuicWallTime now, 413 const CachedNetworkParameters* cached_network_params) const; 414 415 // ParseSourceAddressToken parses the source address tokens contained in 416 // the encrypted |token|, and populates |tokens| with the parsed tokens. 417 // Returns HANDSHAKE_OK if |token| could be parsed, or the reason for the 418 // failure. 419 HandshakeFailureReason ParseSourceAddressToken( 420 const CryptoSecretBoxer& crypto_secret_boxer, absl::string_view token, 421 SourceAddressTokens& tokens) const; 422 423 // ValidateSourceAddressTokens returns HANDSHAKE_OK if the source address 424 // tokens in |tokens| contain a valid and timely token for the IP address 425 // |ip| given that the current time is |now|. Otherwise it returns the 426 // reason for failure. |cached_network_params| is populated if the valid 427 // token contains a CachedNetworkParameters proto. 428 HandshakeFailureReason ValidateSourceAddressTokens( 429 const SourceAddressTokens& tokens, const QuicIpAddress& ip, 430 QuicWallTime now, CachedNetworkParameters* cached_network_params) const; 431 432 // Callers retain the ownership of |rejection_observer| which must outlive the 433 // config. set_rejection_observer(RejectionObserver * rejection_observer)434 void set_rejection_observer(RejectionObserver* rejection_observer) { 435 rejection_observer_ = rejection_observer; 436 } 437 438 ProofSource* proof_source() const; 439 440 SSL_CTX* ssl_ctx() const; 441 442 // The groups to use for key exchange in the TLS handshake; preferred_groups()443 const std::vector<uint16_t>& preferred_groups() const { 444 return preferred_groups_; 445 } 446 447 // Sets the preferred groups that will be used in the TLS handshake. Values 448 // in the |preferred_groups| vector are NamedGroup enum codepoints from 449 // https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.7. set_preferred_groups(const std::vector<uint16_t> & preferred_groups)450 void set_preferred_groups(const std::vector<uint16_t>& preferred_groups) { 451 preferred_groups_ = preferred_groups; 452 } 453 454 // Pre-shared key used during the handshake. pre_shared_key()455 const std::string& pre_shared_key() const { return pre_shared_key_; } set_pre_shared_key(absl::string_view psk)456 void set_pre_shared_key(absl::string_view psk) { 457 pre_shared_key_ = std::string(psk); 458 } 459 pad_rej()460 bool pad_rej() const { return pad_rej_; } set_pad_rej(bool new_value)461 void set_pad_rej(bool new_value) { pad_rej_ = new_value; } 462 pad_shlo()463 bool pad_shlo() const { return pad_shlo_; } set_pad_shlo(bool new_value)464 void set_pad_shlo(bool new_value) { pad_shlo_ = new_value; } 465 source_address_token_boxer()466 const CryptoSecretBoxer& source_address_token_boxer() const { 467 return source_address_token_boxer_; 468 } 469 470 private: 471 friend class test::QuicCryptoServerConfigPeer; 472 friend struct QuicSignedServerConfig; 473 474 // Config represents a server config: a collection of preferences and 475 // Diffie-Hellman public values. 476 class QUICHE_EXPORT Config : public QuicCryptoConfig, 477 public quiche::QuicheReferenceCounted { 478 public: 479 Config(); 480 Config(const Config&) = delete; 481 Config& operator=(const Config&) = delete; 482 483 // TODO(rtenneti): since this is a class, we should probably do 484 // getters/setters here. 485 // |serialized| contains the bytes of this server config, suitable for 486 // sending on the wire. 487 std::string serialized; 488 // id contains the SCID of this server config. 489 std::string id; 490 // orbit contains the orbit value for this config: an opaque identifier 491 // used to identify clusters of server frontends. 492 unsigned char orbit[kOrbitSize]; 493 494 // key_exchanges contains key exchange objects. The values correspond, 495 // one-to-one, with the tags in |kexs| from the parent class. 496 std::vector<std::unique_ptr<AsynchronousKeyExchange>> key_exchanges; 497 498 // channel_id_enabled is true if the config in |serialized| specifies that 499 // ChannelIDs are supported. 500 bool channel_id_enabled; 501 502 // is_primary is true if this config is the one that we'll give out to 503 // clients as the current one. 504 bool is_primary; 505 506 // primary_time contains the timestamp when this config should become the 507 // primary config. A value of QuicWallTime::Zero() means that this config 508 // will not be promoted at a specific time. 509 QuicWallTime primary_time; 510 511 // expiry_time contains the timestamp when this config expires. 512 QuicWallTime expiry_time; 513 514 // Secondary sort key for use when selecting primary configs and 515 // there are multiple configs with the same primary time. 516 // Smaller numbers mean higher priority. 517 uint64_t priority; 518 519 // source_address_token_boxer_ is used to protect the 520 // source-address tokens that are given to clients. 521 // Points to either source_address_token_boxer_storage or the 522 // default boxer provided by QuicCryptoServerConfig. 523 const CryptoSecretBoxer* source_address_token_boxer; 524 525 // Holds the override source_address_token_boxer instance if the 526 // Config is not using the default source address token boxer 527 // instance provided by QuicCryptoServerConfig. 528 std::unique_ptr<CryptoSecretBoxer> source_address_token_boxer_storage; 529 530 private: 531 ~Config() override; 532 }; 533 534 using ConfigMap = 535 std::map<ServerConfigID, quiche::QuicheReferenceCountedPointer<Config>>; 536 537 // Get a ref to the config with a given server config id. 538 quiche::QuicheReferenceCountedPointer<Config> GetConfigWithScid( 539 absl::string_view requested_scid) const 540 QUIC_SHARED_LOCKS_REQUIRED(configs_lock_); 541 542 // A snapshot of the configs associated with an in-progress handshake. 543 struct QUICHE_EXPORT Configs { 544 quiche::QuicheReferenceCountedPointer<Config> requested; 545 quiche::QuicheReferenceCountedPointer<Config> primary; 546 quiche::QuicheReferenceCountedPointer<Config> fallback; 547 }; 548 549 // Get a snapshot of the current configs associated with a handshake. If this 550 // method was called earlier in this handshake |old_primary_config| should be 551 // set to the primary config returned from that invocation, otherwise nullptr. 552 // 553 // Returns true if any configs are loaded. If false is returned, |configs| is 554 // not modified. 555 bool GetCurrentConfigs( 556 const QuicWallTime& now, absl::string_view requested_scid, 557 quiche::QuicheReferenceCountedPointer<Config> old_primary_config, 558 Configs* configs) const; 559 560 // ConfigPrimaryTimeLessThan returns true if a->primary_time < 561 // b->primary_time. 562 static bool ConfigPrimaryTimeLessThan( 563 const quiche::QuicheReferenceCountedPointer<Config>& a, 564 const quiche::QuicheReferenceCountedPointer<Config>& b); 565 566 // SelectNewPrimaryConfig reevaluates the primary config based on the 567 // "primary_time" deadlines contained in each. 568 void SelectNewPrimaryConfig(QuicWallTime now) const 569 QUIC_EXCLUSIVE_LOCKS_REQUIRED(configs_lock_); 570 571 // EvaluateClientHello checks |client_hello_state->client_hello| for gross 572 // errors and determines whether it is fresh (i.e. not a replay). The results 573 // are written to |client_hello_state->info|. 574 void EvaluateClientHello( 575 const QuicSocketAddress& server_address, 576 const QuicSocketAddress& client_address, QuicTransportVersion version, 577 const Configs& configs, 578 quiche::QuicheReferenceCountedPointer< 579 ValidateClientHelloResultCallback::Result> 580 client_hello_state, 581 std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const; 582 583 // Convenience class which carries the arguments passed to 584 // |ProcessClientHellp| along. 585 class QUICHE_EXPORT ProcessClientHelloContext { 586 public: ProcessClientHelloContext(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)587 ProcessClientHelloContext( 588 quiche::QuicheReferenceCountedPointer< 589 ValidateClientHelloResultCallback::Result> 590 validate_chlo_result, 591 bool reject_only, QuicConnectionId connection_id, 592 const QuicSocketAddress& server_address, 593 const QuicSocketAddress& client_address, ParsedQuicVersion version, 594 const ParsedQuicVersionVector& supported_versions, 595 const QuicClock* clock, QuicRandom* rand, 596 QuicCompressedCertsCache* compressed_certs_cache, 597 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> 598 params, 599 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> 600 signed_config, 601 QuicByteCount total_framing_overhead, QuicByteCount chlo_packet_size, 602 std::shared_ptr<ProcessClientHelloResultCallback> done_cb) 603 : validate_chlo_result_(validate_chlo_result), 604 reject_only_(reject_only), 605 connection_id_(connection_id), 606 server_address_(server_address), 607 client_address_(client_address), 608 version_(version), 609 supported_versions_(supported_versions), 610 clock_(clock), 611 rand_(rand), 612 compressed_certs_cache_(compressed_certs_cache), 613 params_(params), 614 signed_config_(signed_config), 615 total_framing_overhead_(total_framing_overhead), 616 chlo_packet_size_(chlo_packet_size), 617 done_cb_(std::move(done_cb)) {} 618 619 ~ProcessClientHelloContext(); 620 621 // Invoke |done_cb_| with an error status 622 void Fail(QuicErrorCode error, const std::string& error_details); 623 624 // Invoke |done_cb_| with a success status 625 void Succeed(std::unique_ptr<CryptoHandshakeMessage> message, 626 std::unique_ptr<DiversificationNonce> diversification_nonce, 627 std::unique_ptr<ProofSource::Details> proof_source_details); 628 629 // Member accessors 630 quiche::QuicheReferenceCountedPointer< 631 ValidateClientHelloResultCallback::Result> validate_chlo_result()632 validate_chlo_result() const { 633 return validate_chlo_result_; 634 } reject_only()635 bool reject_only() const { return reject_only_; } connection_id()636 QuicConnectionId connection_id() const { return connection_id_; } server_address()637 QuicSocketAddress server_address() const { return server_address_; } client_address()638 QuicSocketAddress client_address() const { return client_address_; } version()639 ParsedQuicVersion version() const { return version_; } supported_versions()640 ParsedQuicVersionVector supported_versions() const { 641 return supported_versions_; 642 } clock()643 const QuicClock* clock() const { return clock_; } rand()644 QuicRandom* rand() const { return rand_; } // NOLINT compressed_certs_cache()645 QuicCompressedCertsCache* compressed_certs_cache() const { 646 return compressed_certs_cache_; 647 } 648 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> params()649 params() const { 650 return params_; 651 } 652 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config()653 signed_config() const { 654 return signed_config_; 655 } total_framing_overhead()656 QuicByteCount total_framing_overhead() const { 657 return total_framing_overhead_; 658 } chlo_packet_size()659 QuicByteCount chlo_packet_size() const { return chlo_packet_size_; } 660 661 // Derived value accessors client_hello()662 const CryptoHandshakeMessage& client_hello() const { 663 return validate_chlo_result()->client_hello; 664 } info()665 const ClientHelloInfo& info() const { return validate_chlo_result()->info; } transport_version()666 QuicTransportVersion transport_version() const { 667 return version().transport_version; 668 } 669 670 private: 671 const quiche::QuicheReferenceCountedPointer< 672 ValidateClientHelloResultCallback::Result> 673 validate_chlo_result_; 674 const bool reject_only_; 675 const QuicConnectionId connection_id_; 676 const QuicSocketAddress server_address_; 677 const QuicSocketAddress client_address_; 678 const ParsedQuicVersion version_; 679 const ParsedQuicVersionVector supported_versions_; 680 const QuicClock* const clock_; 681 QuicRandom* const rand_; 682 QuicCompressedCertsCache* const compressed_certs_cache_; 683 const quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> 684 params_; 685 const quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> 686 signed_config_; 687 const QuicByteCount total_framing_overhead_; 688 const QuicByteCount chlo_packet_size_; 689 std::shared_ptr<ProcessClientHelloResultCallback> done_cb_; 690 }; 691 692 // Callback class for bridging between ProcessClientHello and 693 // ProcessClientHelloAfterGetProof. 694 class ProcessClientHelloCallback; 695 friend class ProcessClientHelloCallback; 696 697 // Portion of ProcessClientHello which executes after GetProof. 698 void ProcessClientHelloAfterGetProof( 699 bool found_error, 700 std::unique_ptr<ProofSource::Details> proof_source_details, 701 std::unique_ptr<ProcessClientHelloContext> context, 702 const Configs& configs) const; 703 704 // Callback class for bridging between ProcessClientHelloAfterGetProof and 705 // ProcessClientHelloAfterCalculateSharedKeys. 706 class ProcessClientHelloAfterGetProofCallback; 707 friend class ProcessClientHelloAfterGetProofCallback; 708 709 // Portion of ProcessClientHello which executes after CalculateSharedKeys. 710 void ProcessClientHelloAfterCalculateSharedKeys( 711 bool found_error, 712 std::unique_ptr<ProofSource::Details> proof_source_details, 713 QuicTag key_exchange_type, std::unique_ptr<CryptoHandshakeMessage> out, 714 absl::string_view public_value, 715 std::unique_ptr<ProcessClientHelloContext> context, 716 const Configs& configs) const; 717 718 // Send a REJ which contains a different ServerConfig than the one the client 719 // originally used. This is necessary in cases where we discover in the 720 // middle of the handshake that the private key for the ServerConfig the 721 // client used is not accessible. 722 void SendRejectWithFallbackConfig( 723 std::unique_ptr<ProcessClientHelloContext> context, 724 quiche::QuicheReferenceCountedPointer<Config> fallback_config) const; 725 726 // Callback class for bridging between SendRejectWithFallbackConfig and 727 // SendRejectWithFallbackConfigAfterGetProof. 728 class SendRejectWithFallbackConfigCallback; 729 friend class SendRejectWithFallbackConfigCallback; 730 731 // Portion of ProcessClientHello which executes after GetProof in the case 732 // where we have received a CHLO but need to reject it due to the ServerConfig 733 // private keys being inaccessible. 734 void SendRejectWithFallbackConfigAfterGetProof( 735 bool found_error, 736 std::unique_ptr<ProofSource::Details> proof_source_details, 737 std::unique_ptr<ProcessClientHelloContext> context, 738 quiche::QuicheReferenceCountedPointer<Config> fallback_config) const; 739 740 // BuildRejectionAndRecordStats calls |BuildRejection| below and also informs 741 // the RejectionObserver. 742 void BuildRejectionAndRecordStats(const ProcessClientHelloContext& context, 743 const Config& config, 744 const std::vector<uint32_t>& reject_reasons, 745 CryptoHandshakeMessage* out) const; 746 747 // BuildRejection sets |out| to be a REJ message in reply to |client_hello|. 748 void BuildRejection(const ProcessClientHelloContext& context, 749 const Config& config, 750 const std::vector<uint32_t>& reject_reasons, 751 CryptoHandshakeMessage* out) const; 752 753 // CompressChain compresses the certificates in |chain->certs| and returns a 754 // compressed representation. |client_cached_cert_hashes| contains 755 // 64-bit, FNV-1a hashes of certificates that the peer already possesses. 756 static std::string CompressChain( 757 QuicCompressedCertsCache* compressed_certs_cache, 758 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain, 759 const std::string& client_cached_cert_hashes); 760 761 // ParseConfigProtobuf parses the given config protobuf and returns a 762 // quiche::QuicheReferenceCountedPointer<Config> if successful. The caller 763 // adopts the reference to the Config. On error, ParseConfigProtobuf returns 764 // nullptr. 765 quiche::QuicheReferenceCountedPointer<Config> ParseConfigProtobuf( 766 const QuicServerConfigProtobuf& protobuf, bool is_fallback) const; 767 768 // ValidateSingleSourceAddressToken returns HANDSHAKE_OK if the source 769 // address token in |token| is a timely token for the IP address |ip| 770 // given that the current time is |now|. Otherwise it returns the reason 771 // for failure. 772 HandshakeFailureReason ValidateSingleSourceAddressToken( 773 const SourceAddressToken& token, const QuicIpAddress& ip, 774 QuicWallTime now) const; 775 776 // Returns HANDSHAKE_OK if the source address token in |token| is a timely 777 // token given that the current time is |now|. Otherwise it returns the 778 // reason for failure. 779 HandshakeFailureReason ValidateSourceAddressTokenTimestamp( 780 const SourceAddressToken& token, QuicWallTime now) const; 781 782 // NewServerNonce generates and encrypts a random nonce. 783 std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const; 784 785 // ValidateExpectedLeafCertificate checks the |client_hello| to see if it has 786 // an XLCT tag, and if so, verifies that its value matches the hash of the 787 // server's leaf certificate. |certs| is used to compare against the XLCT 788 // value. This method returns true if the XLCT tag is not present, or if the 789 // XLCT tag is present and valid. It returns false otherwise. 790 bool ValidateExpectedLeafCertificate( 791 const CryptoHandshakeMessage& client_hello, 792 const std::vector<std::string>& certs) const; 793 794 // Callback to receive the results of ProofSource::GetProof. Note: this 795 // callback has no cancellation support, since the lifetime of the ProofSource 796 // is controlled by this object via unique ownership. If that ownership 797 // stricture changes, this decision may need to be revisited. 798 class BuildServerConfigUpdateMessageProofSourceCallback 799 : public ProofSource::Callback { 800 public: 801 BuildServerConfigUpdateMessageProofSourceCallback( 802 const BuildServerConfigUpdateMessageProofSourceCallback&) = delete; 803 ~BuildServerConfigUpdateMessageProofSourceCallback() override; 804 void operator=(const BuildServerConfigUpdateMessageProofSourceCallback&) = 805 delete; 806 BuildServerConfigUpdateMessageProofSourceCallback( 807 const QuicCryptoServerConfig* config, 808 QuicCompressedCertsCache* compressed_certs_cache, 809 const QuicCryptoNegotiatedParameters& params, 810 CryptoHandshakeMessage message, 811 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb); 812 813 void Run( 814 bool ok, 815 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain, 816 const QuicCryptoProof& proof, 817 std::unique_ptr<ProofSource::Details> details) override; 818 819 private: 820 const QuicCryptoServerConfig* config_; 821 QuicCompressedCertsCache* compressed_certs_cache_; 822 const std::string client_cached_cert_hashes_; 823 const bool sct_supported_by_client_; 824 const std::string sni_; 825 CryptoHandshakeMessage message_; 826 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb_; 827 }; 828 829 // Invoked by BuildServerConfigUpdateMessageProofSourceCallback::Run once 830 // the proof has been acquired. Finishes building the server config update 831 // message and invokes |cb|. 832 void FinishBuildServerConfigUpdateMessage( 833 QuicCompressedCertsCache* compressed_certs_cache, 834 const std::string& client_cached_cert_hashes, 835 bool sct_supported_by_client, const std::string& sni, bool ok, 836 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain, 837 const std::string& signature, const std::string& leaf_cert_sct, 838 std::unique_ptr<ProofSource::Details> details, 839 CryptoHandshakeMessage message, 840 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const; 841 842 // Returns true if the next config promotion should happen now. 843 bool IsNextConfigReady(QuicWallTime now) const 844 QUIC_SHARED_LOCKS_REQUIRED(configs_lock_); 845 846 // replay_protection_ controls whether the server enforces that handshakes 847 // aren't replays. 848 bool replay_protection_; 849 850 // The multiple of the CHLO message size that a REJ message must stay under 851 // when the client doesn't present a valid source-address token. This is 852 // used to protect QUIC from amplification attacks. 853 size_t chlo_multiplier_; 854 855 // configs_ satisfies the following invariants: 856 // 1) configs_.empty() <-> primary_config_ == nullptr 857 // 2) primary_config_ != nullptr -> primary_config_->is_primary 858 // 3) ∀ c∈configs_, c->is_primary <-> c == primary_config_ 859 mutable QuicMutex configs_lock_; 860 861 // configs_ contains all active server configs. It's expected that there are 862 // about half-a-dozen configs active at any one time. 863 ConfigMap configs_ QUIC_GUARDED_BY(configs_lock_); 864 865 // primary_config_ points to a Config (which is also in |configs_|) which is 866 // the primary config - i.e. the one that we'll give out to new clients. 867 mutable quiche::QuicheReferenceCountedPointer<Config> primary_config_ 868 QUIC_GUARDED_BY(configs_lock_); 869 870 // fallback_config_ points to a Config (which is also in |configs_|) which is 871 // the fallback config, which will be used if the other configs are unuseable 872 // for some reason. 873 // 874 // TODO(b/112548056): This is currently always nullptr. 875 quiche::QuicheReferenceCountedPointer<Config> fallback_config_ 876 QUIC_GUARDED_BY(configs_lock_); 877 878 // next_config_promotion_time_ contains the nearest, future time when an 879 // active config will be promoted to primary. 880 mutable QuicWallTime next_config_promotion_time_ 881 QUIC_GUARDED_BY(configs_lock_); 882 883 // Callback to invoke when the primary config changes. 884 std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_ 885 QUIC_GUARDED_BY(configs_lock_); 886 887 // Used to protect the source-address tokens that are given to clients. 888 CryptoSecretBoxer source_address_token_boxer_; 889 890 // server_nonce_boxer_ is used to encrypt and validate suggested server 891 // nonces. 892 CryptoSecretBoxer server_nonce_boxer_; 893 894 // server_nonce_orbit_ contains the random, per-server orbit values that this 895 // server will use to generate server nonces (the moral equivalent of a SYN 896 // cookies). 897 uint8_t server_nonce_orbit_[8]; 898 899 // proof_source_ contains an object that can provide certificate chains and 900 // signatures. 901 std::unique_ptr<ProofSource> proof_source_; 902 903 // key_exchange_source_ contains an object that can provide key exchange 904 // objects. 905 std::unique_ptr<KeyExchangeSource> key_exchange_source_; 906 907 // ssl_ctx_ contains the server configuration for doing TLS handshakes. 908 bssl::UniquePtr<SSL_CTX> ssl_ctx_; 909 910 // The groups to use for key exchange in the TLS handshake; 911 std::vector<uint16_t> preferred_groups_; 912 913 // These fields store configuration values. See the comments for their 914 // respective setter functions. 915 uint32_t source_address_token_future_secs_; 916 uint32_t source_address_token_lifetime_secs_; 917 918 // Enable serving SCT or not. 919 bool enable_serving_sct_; 920 921 // Does not own this observer. 922 RejectionObserver* rejection_observer_; 923 924 // If non-empty, the server will operate in the pre-shared key mode by 925 // incorporating |pre_shared_key_| into the key schedule. 926 std::string pre_shared_key_; 927 928 // Whether REJ message should be padded to max packet size. 929 bool pad_rej_; 930 931 // Whether SHLO message should be padded to max packet size. 932 bool pad_shlo_; 933 934 // If client is allowed to send a small client hello (by disabling padding), 935 // server MUST not check for the client hello size. 936 // DO NOT disable this unless you have some other way of validating client. 937 // (e.g. in realtime scenarios, where quic is tunneled through ICE, ICE will 938 // do its own peer validation using STUN pings with ufrag/upass). 939 bool validate_chlo_size_; 940 941 // When source address is validated by some other means (e.g. when using ICE), 942 // source address token validation may be disabled. 943 bool validate_source_address_token_; 944 }; 945 946 struct QUICHE_EXPORT QuicSignedServerConfig 947 : public quiche::QuicheReferenceCounted { 948 QuicSignedServerConfig(); 949 950 QuicCryptoProof proof; 951 quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain; 952 // The server config that is used for this proof (and the rest of the 953 // request). 954 quiche::QuicheReferenceCountedPointer<QuicCryptoServerConfig::Config> config; 955 std::string primary_scid; 956 957 protected: 958 ~QuicSignedServerConfig() override; 959 }; 960 961 } // namespace quic 962 963 #endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_ 964