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