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