Project import generated by Copybara.
PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h
new file mode 100644
index 0000000..9f91c9a
--- /dev/null
+++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -0,0 +1,877 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
+#define QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "third_party/boringssl/src/include/openssl/base.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h"
+#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h"
+#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/third_party/quiche/src/quic/core/proto/source_address_token.pb.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+class CryptoHandshakeMessage;
+class ProofSource;
+class QuicClock;
+class QuicRandom;
+class QuicServerConfigProtobuf;
+struct QuicSignedServerConfig;
+
+// ClientHelloInfo contains information about a client hello message that is
+// only kept for as long as it's being processed.
+struct ClientHelloInfo {
+ ClientHelloInfo(const QuicIpAddress& in_client_ip, QuicWallTime in_now);
+ ClientHelloInfo(const ClientHelloInfo& other);
+ ~ClientHelloInfo();
+
+ // Inputs to EvaluateClientHello.
+ const QuicIpAddress client_ip;
+ const QuicWallTime now;
+
+ // Outputs from EvaluateClientHello.
+ bool valid_source_address_token;
+ QuicStringPiece sni;
+ QuicStringPiece client_nonce;
+ QuicStringPiece server_nonce;
+ QuicStringPiece user_agent_id;
+ SourceAddressTokens source_address_tokens;
+
+ // Errors from EvaluateClientHello.
+ std::vector<uint32_t> reject_reasons;
+ static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
+};
+
+namespace test {
+class QuicCryptoServerConfigPeer;
+} // namespace test
+
+// Hook that allows application code to subscribe to primary config changes.
+class PrimaryConfigChangedCallback {
+ public:
+ PrimaryConfigChangedCallback();
+ PrimaryConfigChangedCallback(const PrimaryConfigChangedCallback&) = delete;
+ PrimaryConfigChangedCallback& operator=(const PrimaryConfigChangedCallback&) =
+ delete;
+ virtual ~PrimaryConfigChangedCallback();
+ virtual void Run(const QuicString& scid) = 0;
+};
+
+// Callback used to accept the result of the |client_hello| validation step.
+class QUIC_EXPORT_PRIVATE ValidateClientHelloResultCallback {
+ public:
+ // Opaque token that holds information about the client_hello and
+ // its validity. Can be interpreted by calling ProcessClientHello.
+ struct QUIC_EXPORT_PRIVATE Result : public QuicReferenceCounted {
+ Result(const CryptoHandshakeMessage& in_client_hello,
+ QuicIpAddress in_client_ip,
+ QuicWallTime in_now);
+
+ CryptoHandshakeMessage client_hello;
+ ClientHelloInfo info;
+ QuicErrorCode error_code;
+ QuicString error_details;
+
+ // Populated if the CHLO STK contained a CachedNetworkParameters proto.
+ CachedNetworkParameters cached_network_params;
+
+ protected:
+ ~Result() override;
+ };
+
+ ValidateClientHelloResultCallback();
+ ValidateClientHelloResultCallback(const ValidateClientHelloResultCallback&) =
+ delete;
+ ValidateClientHelloResultCallback& operator=(
+ const ValidateClientHelloResultCallback&) = delete;
+ virtual ~ValidateClientHelloResultCallback();
+ virtual void Run(QuicReferenceCountedPointer<Result> result,
+ std::unique_ptr<ProofSource::Details> details) = 0;
+};
+
+// Callback used to accept the result of the ProcessClientHello method.
+class QUIC_EXPORT_PRIVATE ProcessClientHelloResultCallback {
+ public:
+ ProcessClientHelloResultCallback();
+ ProcessClientHelloResultCallback(const ProcessClientHelloResultCallback&) =
+ delete;
+ ProcessClientHelloResultCallback& operator=(
+ const ProcessClientHelloResultCallback&) = delete;
+ virtual ~ProcessClientHelloResultCallback();
+ virtual void Run(QuicErrorCode error,
+ const QuicString& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce,
+ std::unique_ptr<ProofSource::Details> details) = 0;
+};
+
+// Callback used to receive the results of a call to
+// BuildServerConfigUpdateMessage.
+class BuildServerConfigUpdateMessageResultCallback {
+ public:
+ BuildServerConfigUpdateMessageResultCallback() = default;
+ virtual ~BuildServerConfigUpdateMessageResultCallback() {}
+ BuildServerConfigUpdateMessageResultCallback(
+ const BuildServerConfigUpdateMessageResultCallback&) = delete;
+ BuildServerConfigUpdateMessageResultCallback& operator=(
+ const BuildServerConfigUpdateMessageResultCallback&) = delete;
+ virtual void Run(bool ok, const CryptoHandshakeMessage& message) = 0;
+};
+
+// Object that is interested in built rejections (which include REJ, SREJ and
+// cheap SREJ).
+class RejectionObserver {
+ public:
+ RejectionObserver() = default;
+ virtual ~RejectionObserver() {}
+ RejectionObserver(const RejectionObserver&) = delete;
+ RejectionObserver& operator=(const RejectionObserver&) = delete;
+ // Called after a rejection is built.
+ virtual void OnRejectionBuilt(const std::vector<uint32_t>& reasons,
+ CryptoHandshakeMessage* out) const = 0;
+};
+
+// Factory for creating KeyExchange objects.
+class QUIC_EXPORT_PRIVATE KeyExchangeSource {
+ public:
+ virtual ~KeyExchangeSource() = default;
+
+ // Returns the default KeyExchangeSource.
+ static std::unique_ptr<KeyExchangeSource> Default();
+
+ // Create a new KeyExchange of the specified type using the specified
+ // private key.
+ virtual std::unique_ptr<KeyExchange> Create(QuicString /*server_config_id*/,
+ QuicTag type,
+ QuicStringPiece private_key) = 0;
+};
+
+// QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
+// Unlike a client, a QUIC server can have multiple configurations active in
+// order to support clients resuming with a previous configuration.
+// TODO(agl): when adding configurations at runtime is added, this object will
+// need to consider locking.
+class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
+ public:
+ // ConfigOptions contains options for generating server configs.
+ struct QUIC_EXPORT_PRIVATE ConfigOptions {
+ ConfigOptions();
+ ConfigOptions(const ConfigOptions& other);
+ ~ConfigOptions();
+
+ // expiry_time is the time, in UNIX seconds, when the server config will
+ // expire. If unset, it defaults to the current time plus six months.
+ QuicWallTime expiry_time;
+ // channel_id_enabled controls whether the server config will indicate
+ // support for ChannelIDs.
+ bool channel_id_enabled;
+ // token_binding_params contains the list of Token Binding params (e.g.
+ // P256, TB10) that the server config will include.
+ QuicTagVector token_binding_params;
+ // id contains the server config id for the resulting config. If empty, a
+ // random id is generated.
+ QuicString id;
+ // orbit contains the kOrbitSize bytes of the orbit value for the server
+ // config. If |orbit| is empty then a random orbit is generated.
+ QuicString orbit;
+ // p256 determines whether a P-256 public key will be included in the
+ // server config. Note that this breaks deterministic server-config
+ // generation since P-256 key generation doesn't use the QuicRandom given
+ // to DefaultConfig().
+ bool p256;
+ };
+
+ // |source_address_token_secret|: secret key material used for encrypting and
+ // decrypting source address tokens. It can be of any length as it is fed
+ // into a KDF before use. In tests, use TESTING.
+ // |server_nonce_entropy|: an entropy source used to generate the orbit and
+ // key for server nonces, which are always local to a given instance of a
+ // server. Not owned.
+ // |proof_source|: provides certificate chains and signatures. This class
+ // takes ownership of |proof_source|.
+ // |ssl_ctx|: The SSL_CTX used for doing TLS handshakes.
+ QuicCryptoServerConfig(QuicStringPiece source_address_token_secret,
+ QuicRandom* server_nonce_entropy,
+ std::unique_ptr<ProofSource> proof_source,
+ std::unique_ptr<KeyExchangeSource> key_exchange_source,
+ bssl::UniquePtr<SSL_CTX> ssl_ctx);
+ QuicCryptoServerConfig(const QuicCryptoServerConfig&) = delete;
+ QuicCryptoServerConfig& operator=(const QuicCryptoServerConfig&) = delete;
+ ~QuicCryptoServerConfig();
+
+ // TESTING is a magic parameter for passing to the constructor in tests.
+ static const char TESTING[];
+
+ // Generates a QuicServerConfigProtobuf protobuf suitable for
+ // AddConfig and SetConfigs.
+ static std::unique_ptr<QuicServerConfigProtobuf> GenerateConfig(
+ QuicRandom* rand,
+ const QuicClock* clock,
+ const ConfigOptions& options);
+
+ // AddConfig adds a QuicServerConfigProtobuf to the available configurations.
+ // It returns the SCFG message from the config if successful. The caller
+ // takes ownership of the CryptoHandshakeMessage. |now| is used in
+ // conjunction with |protobuf->primary_time()| to determine whether the
+ // config should be made primary.
+ CryptoHandshakeMessage* AddConfig(
+ std::unique_ptr<QuicServerConfigProtobuf> protobuf,
+ QuicWallTime now);
+
+ // AddDefaultConfig calls DefaultConfig to create a config and then calls
+ // AddConfig to add it. See the comment for |DefaultConfig| for details of
+ // the arguments.
+ CryptoHandshakeMessage* AddDefaultConfig(QuicRandom* rand,
+ const QuicClock* clock,
+ const ConfigOptions& options);
+
+ // SetConfigs takes a vector of config protobufs and the current time.
+ // Configs are assumed to be uniquely identified by their server config ID.
+ // Previously unknown configs are added and possibly made the primary config
+ // depending on their |primary_time| and the value of |now|. Configs that are
+ // known, but are missing from the protobufs are deleted, unless they are
+ // currently the primary config. SetConfigs returns false if any errors were
+ // encountered and no changes to the QuicCryptoServerConfig will occur.
+ bool SetConfigs(
+ const std::vector<std::unique_ptr<QuicServerConfigProtobuf>>& protobufs,
+ QuicWallTime now);
+
+ // SetSourceAddressTokenKeys sets the keys to be tried, in order, when
+ // decrypting a source address token. Note that these keys are used *without*
+ // passing them through a KDF, in contradistinction to the
+ // |source_address_token_secret| argument to the constructor.
+ void SetSourceAddressTokenKeys(const std::vector<QuicString>& keys);
+
+ // Get the server config ids for all known configs.
+ void GetConfigIds(std::vector<QuicString>* scids) const;
+
+ // Checks |client_hello| for gross errors and determines whether it can be
+ // shown to be fresh (i.e. not a replay). The result of the validation step
+ // must be interpreted by calling QuicCryptoServerConfig::ProcessClientHello
+ // from the done_cb.
+ //
+ // ValidateClientHello may invoke the done_cb before unrolling the
+ // stack if it is able to assess the validity of the client_nonce
+ // without asynchronous operations.
+ //
+ // client_hello: the incoming client hello message.
+ // client_ip: the IP address of the client, which is used to generate and
+ // validate source-address tokens.
+ // server_address: the IP address and port of the server. The IP address and
+ // port may be used for certificate selection.
+ // version: protocol version used for this connection.
+ // clock: used to validate client nonces and ephemeral keys.
+ // crypto_proof: in/out parameter to which will be written the crypto proof
+ // used in reply to a proof demand. The pointed-to-object must
+ // live until the callback is invoked.
+ // done_cb: single-use callback that accepts an opaque
+ // ValidatedClientHelloMsg token that holds information about
+ // the client hello. The callback will always be called exactly
+ // once, either under the current call stack, or after the
+ // completion of an asynchronous operation.
+ void ValidateClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ const QuicIpAddress& client_ip,
+ const QuicSocketAddress& server_address,
+ QuicTransportVersion version,
+ const QuicClock* clock,
+ QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const;
+
+ // ProcessClientHello processes |client_hello| and decides whether to accept
+ // or reject the connection. If the connection is to be accepted, |done_cb| is
+ // invoked with the contents of the ServerHello and QUIC_NO_ERROR. Otherwise
+ // |done_cb| is called with a REJ or SREJ message and QUIC_NO_ERROR.
+ //
+ // validate_chlo_result: Output from the asynchronous call to
+ // ValidateClientHello. Contains the client hello message and
+ // information about it.
+ // reject_only: Only generate rejections, not server hello messages.
+ // connection_id: the ConnectionId for the connection, which is used in key
+ // derivation.
+ // server_ip: the IP address of the server. The IP address may be used for
+ // certificate selection.
+ // client_address: the IP address and port of the client. The IP address is
+ // used to generate and validate source-address tokens.
+ // version: version of the QUIC protocol in use for this connection
+ // supported_versions: versions of the QUIC protocol that this server
+ // supports.
+ // clock: used to validate client nonces and ephemeral keys.
+ // rand: an entropy source
+ // compressed_certs_cache: the cache that caches a set of most recently used
+ // certs. Owned by QuicDispatcher.
+ // params: the state of the handshake. This may be updated with a server
+ // nonce when we send a rejection.
+ // crypto_proof: output structure containing the crypto proof used in reply to
+ // a proof demand.
+ // total_framing_overhead: the total per-packet overhead for a stream frame
+ // chlo_packet_size: the size, in bytes, of the CHLO packet
+ // done_cb: the callback invoked on completion
+ void ProcessClientHello(
+ QuicReferenceCountedPointer<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,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,
+ QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const;
+
+ // BuildServerConfigUpdateMessage invokes |cb| with a SCUP message containing
+ // the current primary config, an up to date source-address token, and cert
+ // chain and proof in the case of secure QUIC. Passes true to |cb| if the
+ // message was generated successfully, and false otherwise. This method
+ // assumes ownership of |cb|.
+ //
+ // |cached_network_params| is optional, and can be nullptr.
+ void BuildServerConfigUpdateMessage(
+ QuicTransportVersion version,
+ QuicStringPiece chlo_hash,
+ const SourceAddressTokens& previous_source_address_tokens,
+ const QuicSocketAddress& server_address,
+ const QuicIpAddress& client_ip,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const QuicCryptoNegotiatedParameters& params,
+ const CachedNetworkParameters* cached_network_params,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const;
+
+ // set_replay_protection controls whether replay protection is enabled. If
+ // replay protection is disabled then no strike registers are needed and
+ // frontends can share an orbit value without a shared strike-register.
+ // However, an attacker can duplicate a handshake and cause a client's
+ // request to be processed twice.
+ void set_replay_protection(bool on);
+
+ // set_chlo_multiplier specifies the multiple of the CHLO message size
+ // that a REJ message must stay under when the client doesn't present a
+ // valid source-address token.
+ void set_chlo_multiplier(size_t multiplier);
+
+ // When sender is allowed to not pad client hello (not standards compliant),
+ // we need to disable the client hello check.
+ void set_validate_chlo_size(bool new_value) {
+ validate_chlo_size_ = new_value;
+ }
+
+ // Returns whether the sender is allowed to not pad the client hello.
+ bool validate_chlo_size() const { return validate_chlo_size_; }
+
+ // When QUIC is tunneled through some other mechanism, source token validation
+ // may be disabled. Do not disable it if you are not providing other
+ // protection. (|true| protects against UDP amplification attack.).
+ void set_validate_source_address_token(bool new_value) {
+ validate_source_address_token_ = new_value;
+ }
+
+ // set_source_address_token_future_secs sets the number of seconds into the
+ // future that source-address tokens will be accepted from. Since
+ // source-address tokens are authenticated, this should only happen if
+ // another, valid server has clock-skew.
+ void set_source_address_token_future_secs(uint32_t future_secs);
+
+ // set_source_address_token_lifetime_secs sets the number of seconds that a
+ // source-address token will be valid for.
+ void set_source_address_token_lifetime_secs(uint32_t lifetime_secs);
+
+ // set_enable_serving_sct enables or disables serving signed cert timestamp
+ // (RFC6962) in server hello.
+ void set_enable_serving_sct(bool enable_serving_sct);
+
+ // Set and take ownership of the callback to invoke on primary config changes.
+ void AcquirePrimaryConfigChangedCb(
+ std::unique_ptr<PrimaryConfigChangedCallback> cb);
+
+ // Returns the number of configs this object owns.
+ int NumberOfConfigs() const;
+
+ // Callers retain the ownership of |rejection_observer| which must outlive the
+ // config.
+ void set_rejection_observer(RejectionObserver* rejection_observer) {
+ rejection_observer_ = rejection_observer;
+ }
+
+ ProofSource* proof_source() const;
+
+ SSL_CTX* ssl_ctx() const;
+
+ void set_pre_shared_key(QuicStringPiece psk) {
+ pre_shared_key_ = QuicString(psk);
+ }
+
+ bool pad_rej() const { return pad_rej_; }
+ void set_pad_rej(bool new_value) { pad_rej_ = new_value; }
+
+ bool pad_shlo() const { return pad_shlo_; }
+ void set_pad_shlo(bool new_value) { pad_shlo_ = new_value; }
+
+ private:
+ friend class test::QuicCryptoServerConfigPeer;
+ friend struct QuicSignedServerConfig;
+
+ // Config represents a server config: a collection of preferences and
+ // Diffie-Hellman public values.
+ class QUIC_EXPORT_PRIVATE Config : public QuicCryptoConfig,
+ public QuicReferenceCounted {
+ public:
+ Config();
+ Config(const Config&) = delete;
+ Config& operator=(const Config&) = delete;
+
+ // TODO(rtenneti): since this is a class, we should probably do
+ // getters/setters here.
+ // |serialized| contains the bytes of this server config, suitable for
+ // sending on the wire.
+ QuicString serialized;
+ // id contains the SCID of this server config.
+ QuicString id;
+ // orbit contains the orbit value for this config: an opaque identifier
+ // used to identify clusters of server frontends.
+ unsigned char orbit[kOrbitSize];
+
+ // key_exchanges contains key exchange objects with the private keys
+ // already loaded. The values correspond, one-to-one, with the tags in
+ // |kexs| from the parent class.
+ std::vector<std::unique_ptr<KeyExchange>> key_exchanges;
+
+ // tag_value_map contains the raw key/value pairs for the config.
+ QuicTagValueMap tag_value_map;
+
+ // channel_id_enabled is true if the config in |serialized| specifies that
+ // ChannelIDs are supported.
+ bool channel_id_enabled;
+
+ // is_primary is true if this config is the one that we'll give out to
+ // clients as the current one.
+ bool is_primary;
+
+ // primary_time contains the timestamp when this config should become the
+ // primary config. A value of QuicWallTime::Zero() means that this config
+ // will not be promoted at a specific time.
+ QuicWallTime primary_time;
+
+ // expiry_time contains the timestamp when this config expires.
+ QuicWallTime expiry_time;
+
+ // Secondary sort key for use when selecting primary configs and
+ // there are multiple configs with the same primary time.
+ // Smaller numbers mean higher priority.
+ uint64_t priority;
+
+ // source_address_token_boxer_ is used to protect the
+ // source-address tokens that are given to clients.
+ // Points to either source_address_token_boxer_storage or the
+ // default boxer provided by QuicCryptoServerConfig.
+ const CryptoSecretBoxer* source_address_token_boxer;
+
+ // Holds the override source_address_token_boxer instance if the
+ // Config is not using the default source address token boxer
+ // instance provided by QuicCryptoServerConfig.
+ std::unique_ptr<CryptoSecretBoxer> source_address_token_boxer_storage;
+
+ private:
+ ~Config() override;
+ };
+
+ typedef std::map<ServerConfigID, QuicReferenceCountedPointer<Config>>
+ ConfigMap;
+
+ // Get a ref to the config with a given server config id.
+ QuicReferenceCountedPointer<Config> GetConfigWithScid(
+ QuicStringPiece requested_scid) const
+ SHARED_LOCKS_REQUIRED(configs_lock_);
+
+ // ConfigPrimaryTimeLessThan returns true if a->primary_time <
+ // b->primary_time.
+ static bool ConfigPrimaryTimeLessThan(
+ const QuicReferenceCountedPointer<Config>& a,
+ const QuicReferenceCountedPointer<Config>& b);
+
+ // SelectNewPrimaryConfig reevaluates the primary config based on the
+ // "primary_time" deadlines contained in each.
+ void SelectNewPrimaryConfig(QuicWallTime now) const
+ EXCLUSIVE_LOCKS_REQUIRED(configs_lock_);
+
+ // EvaluateClientHello checks |client_hello| for gross errors and determines
+ // whether it can be shown to be fresh (i.e. not a replay). The results are
+ // written to |info|.
+ void EvaluateClientHello(
+ const QuicSocketAddress& server_address,
+ QuicTransportVersion version,
+ QuicReferenceCountedPointer<Config> requested_config,
+ QuicReferenceCountedPointer<Config> primary_config,
+ QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof,
+ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+ client_hello_state,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const;
+
+ // Callback class for bridging between EvaluateClientHello and
+ // EvaluateClientHelloAfterGetProof.
+ class EvaluateClientHelloCallback;
+ friend class EvaluateClientHelloCallback;
+
+ // Continuation of EvaluateClientHello after the call to
+ // ProofSource::GetProof. |get_proof_failed| indicates whether GetProof
+ // failed. If GetProof was not run, then |get_proof_failed| will be
+ // set to false.
+ void EvaluateClientHelloAfterGetProof(
+ const QuicIpAddress& server_ip,
+ QuicTransportVersion version,
+ QuicReferenceCountedPointer<Config> requested_config,
+ QuicReferenceCountedPointer<Config> primary_config,
+ QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ bool get_proof_failed,
+ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+ client_hello_state,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const;
+
+ // Callback class for bridging between ProcessClientHello and
+ // ProcessClientHelloAfterGetProof.
+ class ProcessClientHelloCallback;
+ friend class ProcessClientHelloCallback;
+
+ // Portion of ProcessClientHello which executes after GetProof.
+ void ProcessClientHelloAfterGetProof(
+ bool found_error,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+ validate_chlo_result,
+ bool reject_only,
+ QuicConnectionId connection_id,
+ const QuicSocketAddress& client_address,
+ ParsedQuicVersion version,
+ const ParsedQuicVersionVector& supported_versions,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,
+ QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ const QuicReferenceCountedPointer<Config>& requested_config,
+ const QuicReferenceCountedPointer<Config>& primary_config,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const;
+
+ // Callback class for bridging between ProcessClientHelloAfterGetProof and
+ // ProcessClientHelloAfterCalculateSharedKeys.
+ class ProcessClientHelloAfterGetProofCallback;
+ friend class ProcessClientHelloAfterGetProofCallback;
+
+ // Portion of ProcessClientHello which executes after CalculateSharedKeys.
+ void ProcessClientHelloAfterCalculateSharedKeys(
+ bool found_error,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ const KeyExchange::Factory& key_exchange_factory,
+ std::unique_ptr<CryptoHandshakeMessage> out,
+ QuicStringPiece public_value,
+ const ValidateClientHelloResultCallback::Result& validate_chlo_result,
+ QuicConnectionId connection_id,
+ const QuicSocketAddress& client_address,
+ ParsedQuicVersion version,
+ const ParsedQuicVersionVector& supported_versions,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,
+ QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
+ const QuicReferenceCountedPointer<Config>& requested_config,
+ const QuicReferenceCountedPointer<Config>& primary_config,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const;
+
+ // BuildRejection sets |out| to be a REJ message in reply to |client_hello|.
+ void BuildRejection(
+ QuicTransportVersion version,
+ QuicWallTime now,
+ const Config& config,
+ const CryptoHandshakeMessage& client_hello,
+ const ClientHelloInfo& info,
+ const CachedNetworkParameters& cached_network_params,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params,
+ const QuicSignedServerConfig& crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ CryptoHandshakeMessage* out) const;
+
+ // CompressChain compresses the certificates in |chain->certs| and returns a
+ // compressed representation. |common_sets| contains the common certificate
+ // sets known locally and |client_common_set_hashes| contains the hashes of
+ // the common sets known to the peer. |client_cached_cert_hashes| contains
+ // 64-bit, FNV-1a hashes of certificates that the peer already possesses.
+ static QuicString CompressChain(
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
+ const QuicString& client_common_set_hashes,
+ const QuicString& client_cached_cert_hashes,
+ const CommonCertSets* common_sets);
+
+ // ParseConfigProtobuf parses the given config protobuf and returns a
+ // QuicReferenceCountedPointer<Config> if successful. The caller adopts the
+ // reference to the Config. On error, ParseConfigProtobuf returns nullptr.
+ QuicReferenceCountedPointer<Config> ParseConfigProtobuf(
+ const std::unique_ptr<QuicServerConfigProtobuf>& protobuf);
+
+ // NewSourceAddressToken returns a fresh source address token for the given
+ // IP address. |cached_network_params| is optional, and can be nullptr.
+ QuicString NewSourceAddressToken(
+ const Config& config,
+ const SourceAddressTokens& previous_tokens,
+ const QuicIpAddress& ip,
+ QuicRandom* rand,
+ QuicWallTime now,
+ const CachedNetworkParameters* cached_network_params) const;
+
+ // ParseSourceAddressToken parses the source address tokens contained in
+ // the encrypted |token|, and populates |tokens| with the parsed tokens.
+ // Returns HANDSHAKE_OK if |token| could be parsed, or the reason for the
+ // failure.
+ HandshakeFailureReason ParseSourceAddressToken(
+ const Config& config,
+ QuicStringPiece token,
+ SourceAddressTokens* tokens) const;
+
+ // ValidateSourceAddressTokens returns HANDSHAKE_OK if the source address
+ // tokens in |tokens| contain a valid and timely token for the IP address
+ // |ip| given that the current time is |now|. Otherwise it returns the
+ // reason for failure. |cached_network_params| is populated if the valid
+ // token contains a CachedNetworkParameters proto.
+ HandshakeFailureReason ValidateSourceAddressTokens(
+ const SourceAddressTokens& tokens,
+ const QuicIpAddress& ip,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) const;
+
+ // ValidateSingleSourceAddressToken returns HANDSHAKE_OK if the source
+ // address token in |token| is a timely token for the IP address |ip|
+ // given that the current time is |now|. Otherwise it returns the reason
+ // for failure.
+ HandshakeFailureReason ValidateSingleSourceAddressToken(
+ const SourceAddressToken& token,
+ const QuicIpAddress& ip,
+ QuicWallTime now) const;
+
+ // Returns HANDSHAKE_OK if the source address token in |token| is a timely
+ // token given that the current time is |now|. Otherwise it returns the
+ // reason for failure.
+ HandshakeFailureReason ValidateSourceAddressTokenTimestamp(
+ const SourceAddressToken& token,
+ QuicWallTime now) const;
+
+ // NewServerNonce generates and encrypts a random nonce.
+ QuicString NewServerNonce(QuicRandom* rand, QuicWallTime now) const;
+
+ // ValidateExpectedLeafCertificate checks the |client_hello| to see if it has
+ // an XLCT tag, and if so, verifies that its value matches the hash of the
+ // server's leaf certificate. |certs| is used to compare against the XLCT
+ // value. This method returns true if the XLCT tag is not present, or if the
+ // XLCT tag is present and valid. It returns false otherwise.
+ bool ValidateExpectedLeafCertificate(
+ const CryptoHandshakeMessage& client_hello,
+ const std::vector<QuicString>& certs) const;
+
+ // Returns true if the PDMD field from the client hello demands an X509
+ // certificate.
+ bool ClientDemandsX509Proof(const CryptoHandshakeMessage& client_hello) const;
+
+ // Callback to receive the results of ProofSource::GetProof. Note: this
+ // callback has no cancellation support, since the lifetime of the ProofSource
+ // is controlled by this object via unique ownership. If that ownership
+ // stricture changes, this decision may need to be revisited.
+ class BuildServerConfigUpdateMessageProofSourceCallback
+ : public ProofSource::Callback {
+ public:
+ BuildServerConfigUpdateMessageProofSourceCallback(
+ const BuildServerConfigUpdateMessageProofSourceCallback&) = delete;
+ ~BuildServerConfigUpdateMessageProofSourceCallback() override;
+ void operator=(const BuildServerConfigUpdateMessageProofSourceCallback&) =
+ delete;
+ BuildServerConfigUpdateMessageProofSourceCallback(
+ const QuicCryptoServerConfig* config,
+ QuicTransportVersion version,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const CommonCertSets* common_cert_sets,
+ const QuicCryptoNegotiatedParameters& params,
+ CryptoHandshakeMessage message,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb);
+
+ void Run(bool ok,
+ const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
+ const QuicCryptoProof& proof,
+ std::unique_ptr<ProofSource::Details> details) override;
+
+ private:
+ const QuicCryptoServerConfig* config_;
+ const QuicTransportVersion version_;
+ QuicCompressedCertsCache* compressed_certs_cache_;
+ const CommonCertSets* common_cert_sets_;
+ const QuicString client_common_set_hashes_;
+ const QuicString client_cached_cert_hashes_;
+ const bool sct_supported_by_client_;
+ const QuicString sni_;
+ CryptoHandshakeMessage message_;
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb_;
+ };
+
+ // Invoked by BuildServerConfigUpdateMessageProofSourceCallback::Run once
+ // the proof has been acquired. Finishes building the server config update
+ // message and invokes |cb|.
+ void FinishBuildServerConfigUpdateMessage(
+ QuicTransportVersion version,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const CommonCertSets* common_cert_sets,
+ const QuicString& client_common_set_hashes,
+ const QuicString& client_cached_cert_hashes,
+ bool sct_supported_by_client,
+ const QuicString& sni,
+ bool ok,
+ const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
+ const QuicString& signature,
+ const QuicString& leaf_cert_sct,
+ std::unique_ptr<ProofSource::Details> details,
+ CryptoHandshakeMessage message,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const;
+
+ // Returns true if the next config promotion should happen now.
+ bool IsNextConfigReady(QuicWallTime now) const
+ SHARED_LOCKS_REQUIRED(configs_lock_);
+
+ // replay_protection_ controls whether the server enforces that handshakes
+ // aren't replays.
+ bool replay_protection_;
+
+ // The multiple of the CHLO message size that a REJ message must stay under
+ // when the client doesn't present a valid source-address token. This is
+ // used to protect QUIC from amplification attacks.
+ size_t chlo_multiplier_;
+
+ // configs_ satisfies the following invariants:
+ // 1) configs_.empty() <-> primary_config_ == nullptr
+ // 2) primary_config_ != nullptr -> primary_config_->is_primary
+ // 3) ∀ c∈configs_, c->is_primary <-> c == primary_config_
+ mutable QuicMutex configs_lock_;
+ // configs_ contains all active server configs. It's expected that there are
+ // about half-a-dozen configs active at any one time.
+ ConfigMap configs_ GUARDED_BY(configs_lock_);
+ // primary_config_ points to a Config (which is also in |configs_|) which is
+ // the primary config - i.e. the one that we'll give out to new clients.
+ mutable QuicReferenceCountedPointer<Config> primary_config_
+ GUARDED_BY(configs_lock_);
+ // next_config_promotion_time_ contains the nearest, future time when an
+ // active config will be promoted to primary.
+ mutable QuicWallTime next_config_promotion_time_ GUARDED_BY(configs_lock_);
+ // Callback to invoke when the primary config changes.
+ std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_
+ GUARDED_BY(configs_lock_);
+
+ // Used to protect the source-address tokens that are given to clients.
+ CryptoSecretBoxer source_address_token_boxer_;
+
+ // server_nonce_boxer_ is used to encrypt and validate suggested server
+ // nonces.
+ CryptoSecretBoxer server_nonce_boxer_;
+
+ // server_nonce_orbit_ contains the random, per-server orbit values that this
+ // server will use to generate server nonces (the moral equivalent of a SYN
+ // cookies).
+ uint8_t server_nonce_orbit_[8];
+
+ // proof_source_ contains an object that can provide certificate chains and
+ // signatures.
+ std::unique_ptr<ProofSource> proof_source_;
+
+ // key_exchange_source_ contains an object that can provide key exchange
+ // objects.
+ std::unique_ptr<KeyExchangeSource> key_exchange_source_;
+
+ // ssl_ctx_ contains the server configuration for doing TLS handshakes.
+ bssl::UniquePtr<SSL_CTX> ssl_ctx_;
+
+ // These fields store configuration values. See the comments for their
+ // respective setter functions.
+ uint32_t source_address_token_future_secs_;
+ uint32_t source_address_token_lifetime_secs_;
+
+ // Enable serving SCT or not.
+ bool enable_serving_sct_;
+
+ // Does not own this observer.
+ RejectionObserver* rejection_observer_;
+
+ // If non-empty, the server will operate in the pre-shared key mode by
+ // incorporating |pre_shared_key_| into the key schedule.
+ QuicString pre_shared_key_;
+
+ // Whether REJ message should be padded to max packet size.
+ bool pad_rej_;
+
+ // Whether SHLO message should be padded to max packet size.
+ bool pad_shlo_;
+
+ // If client is allowed to send a small client hello (by disabling padding),
+ // server MUST not check for the client hello size.
+ // DO NOT disable this unless you have some other way of validating client.
+ // (e.g. in realtime scenarios, where quic is tunneled through ICE, ICE will
+ // do its own peer validation using STUN pings with ufrag/upass).
+ bool validate_chlo_size_;
+
+ // When source address is validated by some other means (e.g. when using ICE),
+ // source address token validation may be disabled.
+ bool validate_source_address_token_;
+};
+
+struct QUIC_EXPORT_PRIVATE QuicSignedServerConfig
+ : public QuicReferenceCounted {
+ QuicSignedServerConfig();
+
+ QuicCryptoProof proof;
+ QuicReferenceCountedPointer<ProofSource::Chain> chain;
+ // The server config that is used for this proof (and the rest of the
+ // request).
+ QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> config;
+ QuicString primary_scid;
+
+ protected:
+ ~QuicSignedServerConfig() override;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_