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.
5 #ifndef NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
6 #define NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string_piece.h"
15 #include "base/synchronization/lock.h"
16 #include "net/base/ip_endpoint.h"
17 #include "net/base/net_export.h"
18 #include "net/quic/crypto/cached_network_parameters.h"
19 #include "net/quic/crypto/crypto_handshake.h"
20 #include "net/quic/crypto/crypto_handshake_message.h"
21 #include "net/quic/crypto/crypto_protocol.h"
22 #include "net/quic/crypto/crypto_secret_boxer.h"
23 #include "net/quic/crypto/source_address_token.h"
24 #include "net/quic/quic_time.h"
28 class CryptoHandshakeMessage
;
29 class EphemeralKeySource
;
36 class QuicServerConfigProtobuf
;
38 class StrikeRegisterClient
;
40 // ClientHelloInfo contains information about a client hello message that is
41 // only kept for as long as it's being processed.
42 struct ClientHelloInfo
{
43 ClientHelloInfo(const IPEndPoint
& in_client_ip
, QuicWallTime in_now
);
46 // Inputs to EvaluateClientHello.
47 const IPEndPoint client_ip
;
48 const QuicWallTime now
;
50 // Outputs from EvaluateClientHello.
51 bool valid_source_address_token
;
52 bool client_nonce_well_formed
;
54 base::StringPiece sni
;
55 base::StringPiece client_nonce
;
56 base::StringPiece server_nonce
;
57 base::StringPiece user_agent_id
;
58 SourceAddressTokens source_address_tokens
;
60 // Errors from EvaluateClientHello.
61 std::vector
<uint32
> reject_reasons
;
62 static_assert(sizeof(QuicTag
) == sizeof(uint32
), "header out of sync");
66 class QuicCryptoServerConfigPeer
;
69 // Hook that allows application code to subscribe to primary config changes.
70 class PrimaryConfigChangedCallback
{
72 PrimaryConfigChangedCallback();
73 virtual ~PrimaryConfigChangedCallback();
74 virtual void Run(const std::string
& scid
) = 0;
77 DISALLOW_COPY_AND_ASSIGN(PrimaryConfigChangedCallback
);
80 // Callback used to accept the result of the |client_hello| validation step.
81 class NET_EXPORT_PRIVATE ValidateClientHelloResultCallback
{
83 // Opaque token that holds information about the client_hello and
84 // its validity. Can be interpreted by calling ProcessClientHello.
86 Result(const CryptoHandshakeMessage
& in_client_hello
,
87 IPEndPoint in_client_ip
,
91 CryptoHandshakeMessage client_hello
;
93 QuicErrorCode error_code
;
94 std::string error_details
;
96 // Populated if the CHLO STK contained a CachedNetworkParameters proto.
97 CachedNetworkParameters cached_network_params
;
100 ValidateClientHelloResultCallback();
101 virtual ~ValidateClientHelloResultCallback();
102 void Run(const Result
* result
);
105 virtual void RunImpl(const CryptoHandshakeMessage
& client_hello
,
106 const Result
& result
) = 0;
109 DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloResultCallback
);
112 // QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
113 // Unlike a client, a QUIC server can have multiple configurations active in
114 // order to support clients resuming with a previous configuration.
115 // TODO(agl): when adding configurations at runtime is added, this object will
116 // need to consider locking.
117 class NET_EXPORT_PRIVATE QuicCryptoServerConfig
{
119 // ConfigOptions contains options for generating server configs.
120 struct NET_EXPORT_PRIVATE ConfigOptions
{
123 // expiry_time is the time, in UNIX seconds, when the server config will
124 // expire. If unset, it defaults to the current time plus six months.
125 QuicWallTime expiry_time
;
126 // channel_id_enabled controls whether the server config will indicate
127 // support for ChannelIDs.
128 bool channel_id_enabled
;
129 // id contains the server config id for the resulting config. If empty, a
130 // random id is generated.
132 // orbit contains the kOrbitSize bytes of the orbit value for the server
133 // config. If |orbit| is empty then a random orbit is generated.
135 // p256 determines whether a P-256 public key will be included in the
136 // server config. Note that this breaks deterministic server-config
137 // generation since P-256 key generation doesn't use the QuicRandom given
138 // to DefaultConfig().
142 // |source_address_token_secret|: secret key material used for encrypting and
143 // decrypting source address tokens. It can be of any length as it is fed
144 // into a KDF before use. In tests, use TESTING.
145 // |server_nonce_entropy|: an entropy source used to generate the orbit and
146 // key for server nonces, which are always local to a given instance of a
148 QuicCryptoServerConfig(base::StringPiece source_address_token_secret
,
149 QuicRandom
* server_nonce_entropy
);
150 ~QuicCryptoServerConfig();
152 // TESTING is a magic parameter for passing to the constructor in tests.
153 static const char TESTING
[];
155 // Generates a QuicServerConfigProtobuf protobuf suitable for
156 // AddConfig and SetConfigs.
157 static QuicServerConfigProtobuf
* GenerateConfig(
159 const QuicClock
* clock
,
160 const ConfigOptions
& options
);
162 // AddConfig adds a QuicServerConfigProtobuf to the availible configurations.
163 // It returns the SCFG message from the config if successful. The caller
164 // takes ownership of the CryptoHandshakeMessage. |now| is used in
165 // conjunction with |protobuf->primary_time()| to determine whether the
166 // config should be made primary.
167 CryptoHandshakeMessage
* AddConfig(QuicServerConfigProtobuf
* protobuf
,
170 // AddDefaultConfig calls DefaultConfig to create a config and then calls
171 // AddConfig to add it. See the comment for |DefaultConfig| for details of
173 CryptoHandshakeMessage
* AddDefaultConfig(
175 const QuicClock
* clock
,
176 const ConfigOptions
& options
);
178 // SetConfigs takes a vector of config protobufs and the current time.
179 // Configs are assumed to be uniquely identified by their server config ID.
180 // Previously unknown configs are added and possibly made the primary config
181 // depending on their |primary_time| and the value of |now|. Configs that are
182 // known, but are missing from the protobufs are deleted, unless they are
183 // currently the primary config. SetConfigs returns false if any errors were
184 // encountered and no changes to the QuicCryptoServerConfig will occur.
185 bool SetConfigs(const std::vector
<QuicServerConfigProtobuf
*>& protobufs
,
188 // Get the server config ids for all known configs.
189 void GetConfigIds(std::vector
<std::string
>* scids
) const;
191 // Checks |client_hello| for gross errors and determines whether it
192 // can be shown to be fresh (i.e. not a replay). The result of the
193 // validation step must be interpreted by calling
194 // QuicCryptoServerConfig::ProcessClientHello from the done_cb.
196 // ValidateClientHello may invoke the done_cb before unrolling the
197 // stack if it is able to assess the validity of the client_nonce
198 // without asynchronous operations.
200 // client_hello: the incoming client hello message.
201 // client_ip: the IP address of the client, which is used to generate and
202 // validate source-address tokens.
203 // clock: used to validate client nonces and ephemeral keys.
204 // done_cb: single-use callback that accepts an opaque
205 // ValidatedClientHelloMsg token that holds information about
206 // the client hello. The callback will always be called exactly
207 // once, either under the current call stack, or after the
208 // completion of an asynchronous operation.
209 void ValidateClientHello(
210 const CryptoHandshakeMessage
& client_hello
,
211 IPEndPoint client_ip
,
212 const QuicClock
* clock
,
213 ValidateClientHelloResultCallback
* done_cb
) const;
215 // ProcessClientHello processes |client_hello| and decides whether to accept
216 // or reject the connection. If the connection is to be accepted, |out| is
217 // set to the contents of the ServerHello, |out_params| is completed and
218 // QUIC_NO_ERROR is returned. Otherwise |out| is set to be a REJ message and
219 // an error code is returned.
221 // validate_chlo_result: Output from the asynchronous call to
222 // ValidateClientHello. Contains the client hello message and
223 // information about it.
224 // connection_id: the ConnectionId for the connection, which is used in key
226 // server_ip: the IP address and port of the server. The IP address may be
227 // used for certificate selection.
228 // client_address: the IP address and port of the client. The IP address is
229 // used to generate and validate source-address tokens.
230 // version: version of the QUIC protocol in use for this connection
231 // supported_versions: versions of the QUIC protocol that this server
233 // initial_flow_control_window: size of initial flow control window this
234 // server uses for new streams.
235 // clock: used to validate client nonces and ephemeral keys.
236 // rand: an entropy source
237 // params: the state of the handshake. This may be updated with a server
238 // nonce when we send a rejection. After a successful handshake, this will
239 // contain the state of the connection.
240 // out: the resulting handshake message (either REJ or SHLO)
241 // error_details: used to store a string describing any error.
242 QuicErrorCode
ProcessClientHello(
243 const ValidateClientHelloResultCallback::Result
& validate_chlo_result
,
244 QuicConnectionId connection_id
,
245 const IPEndPoint
& server_ip
,
246 const IPEndPoint
& client_address
,
248 const QuicVersionVector
& supported_versions
,
249 const QuicClock
* clock
,
251 QuicCryptoNegotiatedParameters
* params
,
252 CryptoHandshakeMessage
* out
,
253 std::string
* error_details
) const;
255 // BuildServerConfigUpdateMessage sets |out| to be a SCUP message containing
256 // the current primary config, an up to date source-address token, and cert
257 // chain and proof in the case of secure QUIC. Returns true if successfully
260 // |cached_network_params| is optional, and can be nullptr.
261 bool BuildServerConfigUpdateMessage(
262 const SourceAddressTokens
& previous_source_address_tokens
,
263 const IPEndPoint
& server_ip
,
264 const IPEndPoint
& client_ip
,
265 const QuicClock
* clock
,
267 const QuicCryptoNegotiatedParameters
& params
,
268 const CachedNetworkParameters
* cached_network_params
,
269 CryptoHandshakeMessage
* out
) const;
271 // SetProofSource installs |proof_source| as the ProofSource for handshakes.
272 // This object takes ownership of |proof_source|.
273 void SetProofSource(ProofSource
* proof_source
);
275 // SetEphemeralKeySource installs an object that can cache ephemeral keys for
276 // a short period of time. This object takes ownership of
277 // |ephemeral_key_source|. If not set then ephemeral keys will be generated
279 void SetEphemeralKeySource(EphemeralKeySource
* ephemeral_key_source
);
281 // Install an externall created StrikeRegisterClient for use to
282 // interact with the strike register. This object takes ownership
283 // of the |strike_register_client|.
284 void SetStrikeRegisterClient(StrikeRegisterClient
* strike_register_client
);
286 // set_replay_protection controls whether replay protection is enabled. If
287 // replay protection is disabled then no strike registers are needed and
288 // frontends can share an orbit value without a shared strike-register.
289 // However, an attacker can duplicate a handshake and cause a client's
290 // request to be processed twice.
291 void set_replay_protection(bool on
);
293 // set_strike_register_no_startup_period configures the strike register to
294 // not have a startup period.
295 void set_strike_register_no_startup_period();
297 // set_strike_register_max_entries sets the maximum number of entries that
298 // the internal strike register will hold. If the strike register fills up
299 // then the oldest entries (by the client's clock) will be dropped.
300 void set_strike_register_max_entries(uint32 max_entries
);
302 // set_strike_register_window_secs sets the number of seconds around the
303 // current time that the strike register will attempt to be authoritative
304 // for. Setting a larger value allows for greater client clock-skew, but
305 // means that the quiescent startup period must be longer.
306 void set_strike_register_window_secs(uint32 window_secs
);
308 // set_source_address_token_future_secs sets the number of seconds into the
309 // future that source-address tokens will be accepted from. Since
310 // source-address tokens are authenticated, this should only happen if
311 // another, valid server has clock-skew.
312 void set_source_address_token_future_secs(uint32 future_secs
);
314 // set_source_address_token_lifetime_secs sets the number of seconds that a
315 // source-address token will be valid for.
316 void set_source_address_token_lifetime_secs(uint32 lifetime_secs
);
318 // set_server_nonce_strike_register_max_entries sets the number of entries in
319 // the server-nonce strike-register. This is used to record that server nonce
320 // values have been used. If the number of entries is too small then clients
321 // which are depending on server nonces may fail to handshake because their
322 // nonce has expired in the amount of time it took to go from the server to
323 // the client and back.
324 void set_server_nonce_strike_register_max_entries(uint32 max_entries
);
326 // set_server_nonce_strike_register_window_secs sets the number of seconds
327 // around the current time that the server-nonce strike-register will accept
328 // nonces from. Setting a larger value allows for clients to delay follow-up
329 // client hellos for longer and still use server nonces as proofs of
331 void set_server_nonce_strike_register_window_secs(uint32 window_secs
);
333 // Set and take ownership of the callback to invoke on primary config changes.
334 void AcquirePrimaryConfigChangedCb(PrimaryConfigChangedCallback
* cb
);
336 // Returns true if this config has a |proof_source_|.
337 bool HasProofSource() const;
340 friend class test::QuicCryptoServerConfigPeer
;
342 // Config represents a server config: a collection of preferences and
343 // Diffie-Hellman public values.
344 class NET_EXPORT_PRIVATE Config
: public QuicCryptoConfig
,
345 public base::RefCounted
<Config
> {
349 // TODO(rtenneti): since this is a class, we should probably do
350 // getters/setters here.
351 // |serialized| contains the bytes of this server config, suitable for
352 // sending on the wire.
353 std::string serialized
;
354 // id contains the SCID of this server config.
356 // orbit contains the orbit value for this config: an opaque identifier
357 // used to identify clusters of server frontends.
358 unsigned char orbit
[kOrbitSize
];
360 // key_exchanges contains key exchange objects with the private keys
361 // already loaded. The values correspond, one-to-one, with the tags in
362 // |kexs| from the parent class.
363 std::vector
<KeyExchange
*> key_exchanges
;
365 // tag_value_map contains the raw key/value pairs for the config.
366 QuicTagValueMap tag_value_map
;
368 // channel_id_enabled is true if the config in |serialized| specifies that
369 // ChannelIDs are supported.
370 bool channel_id_enabled
;
372 // is_primary is true if this config is the one that we'll give out to
373 // clients as the current one.
376 // primary_time contains the timestamp when this config should become the
377 // primary config. A value of QuicWallTime::Zero() means that this config
378 // will not be promoted at a specific time.
379 QuicWallTime primary_time
;
381 // Secondary sort key for use when selecting primary configs and
382 // there are multiple configs with the same primary time.
383 // Smaller numbers mean higher priority.
386 // source_address_token_boxer_ is used to protect the
387 // source-address tokens that are given to clients.
388 // Points to either source_address_token_boxer_storage or the
389 // default boxer provided by QuicCryptoServerConfig.
390 const CryptoSecretBoxer
* source_address_token_boxer
;
392 // Holds the override source_address_token_boxer instance if the
393 // Config is not using the default source address token boxer
394 // instance provided by QuicCryptoServerConfig.
395 scoped_ptr
<CryptoSecretBoxer
> source_address_token_boxer_storage
;
398 friend class base::RefCounted
<Config
>;
402 DISALLOW_COPY_AND_ASSIGN(Config
);
405 typedef std::map
<ServerConfigID
, scoped_refptr
<Config
> > ConfigMap
;
407 // Get a ref to the config with a given server config id.
408 scoped_refptr
<Config
> GetConfigWithScid(
409 base::StringPiece requested_scid
) const;
411 // ConfigPrimaryTimeLessThan returns true if a->primary_time <
413 static bool ConfigPrimaryTimeLessThan(const scoped_refptr
<Config
>& a
,
414 const scoped_refptr
<Config
>& b
);
416 // SelectNewPrimaryConfig reevaluates the primary config based on the
417 // "primary_time" deadlines contained in each.
418 void SelectNewPrimaryConfig(QuicWallTime now
) const;
420 // EvaluateClientHello checks |client_hello| for gross errors and determines
421 // whether it can be shown to be fresh (i.e. not a replay). The results are
422 // written to |info|.
423 void EvaluateClientHello(
424 const uint8
* primary_orbit
,
425 scoped_refptr
<Config
> requested_config
,
426 ValidateClientHelloResultCallback::Result
* client_hello_state
,
427 ValidateClientHelloResultCallback
* done_cb
) const;
429 // BuildRejection sets |out| to be a REJ message in reply to |client_hello|.
430 void BuildRejection(const IPEndPoint
& server_ip
,
431 const Config
& config
,
432 const CryptoHandshakeMessage
& client_hello
,
433 const ClientHelloInfo
& info
,
434 const CachedNetworkParameters
& cached_network_params
,
436 QuicCryptoNegotiatedParameters
* params
,
437 CryptoHandshakeMessage
* out
) const;
439 // ParseConfigProtobuf parses the given config protobuf and returns a
440 // scoped_refptr<Config> if successful. The caller adopts the reference to the
441 // Config. On error, ParseConfigProtobuf returns nullptr.
442 scoped_refptr
<Config
> ParseConfigProtobuf(QuicServerConfigProtobuf
* protobuf
);
444 // NewSourceAddressToken returns a fresh source address token for the given
445 // IP address. |cached_network_params| is optional, and can be nullptr.
446 std::string
NewSourceAddressToken(
447 const Config
& config
,
448 const SourceAddressTokens
& previous_tokens
,
449 const IPEndPoint
& ip
,
452 const CachedNetworkParameters
* cached_network_params
) const;
454 // ParseSourceAddressToken parses the source address tokens contained in
455 // the encrypted |token|, and populates |tokens| with the parsed tokens.
456 // Returns HANDSHAKE_OK if |token| could be parsed, or the reason for the
458 HandshakeFailureReason
ParseSourceAddressToken(
459 const Config
& config
,
460 base::StringPiece token
,
461 SourceAddressTokens
* tokens
) const;
463 // ValidateSourceAddressToken returns HANDSHAKE_OK if the source address
464 // tokens in |tokens| contain a valid and timely token for the IP address
465 // |ip| given that the current time is |now|. Otherwise it returns the
466 // reason for failure. |cached_network_params| is populated if the valid
467 // token contains a CachedNetworkParameters proto.
468 // TODO(rch): remove this method when we remove:
469 // FLAGS_quic_use_multiple_address_in_source_tokens.
470 HandshakeFailureReason
ValidateSourceAddressToken(
471 const Config
& config
,
472 base::StringPiece token
,
473 const IPEndPoint
& ip
,
475 CachedNetworkParameters
* cached_network_params
) const;
477 // ValidateSourceAddressTokens returns HANDSHAKE_OK if the source address
478 // tokens in |tokens| contain a valid and timely token for the IP address
479 // |ip| given that the current time is |now|. Otherwise it returns the
480 // reason for failure. |cached_network_params| is populated if the valid
481 // token contains a CachedNetworkParameters proto.
482 HandshakeFailureReason
ValidateSourceAddressTokens(
483 const SourceAddressTokens
& tokens
,
484 const IPEndPoint
& ip
,
486 CachedNetworkParameters
* cached_network_params
) const;
488 // ValidateSingleSourceAddressToken returns HANDSHAKE_OK if the source
489 // address token in |token| is a timely token for the IP address |ip|
490 // given that the current time is |now|. Otherwise it returns the reason
492 HandshakeFailureReason
ValidateSingleSourceAddressToken(
493 const SourceAddressToken
& token
,
494 const IPEndPoint
& ip
,
495 QuicWallTime now
) const;
497 // Returns HANDSHAKE_OK if the source address token in |token| is a timely
498 // token given that the current time is |now|. Otherwise it returns the
499 // reason for failure.
500 HandshakeFailureReason
ValidateSourceAddressTokenTimestamp(
501 const SourceAddressToken
& token
,
502 QuicWallTime now
) const;
504 // NewServerNonce generates and encrypts a random nonce.
505 std::string
NewServerNonce(QuicRandom
* rand
, QuicWallTime now
) const;
507 // ValidateServerNonce decrypts |token| and verifies that it hasn't been
508 // previously used and is recent enough that it is plausible that it was part
509 // of a very recently provided rejection ("recent" will be on the order of
510 // 10-30 seconds). If so, it records that it has been used and returns
511 // HANDSHAKE_OK. Otherwise it returns the reason for failure.
512 HandshakeFailureReason
ValidateServerNonce(
513 base::StringPiece echoed_server_nonce
,
514 QuicWallTime now
) const;
516 // replay_protection_ controls whether the server enforces that handshakes
518 bool replay_protection_
;
520 // configs_ satisfies the following invariants:
521 // 1) configs_.empty() <-> primary_config_ == nullptr
522 // 2) primary_config_ != nullptr -> primary_config_->is_primary
523 // 3) ∀ c∈configs_, c->is_primary <-> c == primary_config_
524 mutable base::Lock configs_lock_
;
525 // configs_ contains all active server configs. It's expected that there are
526 // about half-a-dozen configs active at any one time.
528 // primary_config_ points to a Config (which is also in |configs_|) which is
529 // the primary config - i.e. the one that we'll give out to new clients.
530 mutable scoped_refptr
<Config
> primary_config_
;
531 // next_config_promotion_time_ contains the nearest, future time when an
532 // active config will be promoted to primary.
533 mutable QuicWallTime next_config_promotion_time_
;
534 // Callback to invoke when the primary config changes.
535 scoped_ptr
<PrimaryConfigChangedCallback
> primary_config_changed_cb_
;
537 // Protects access to the pointer held by strike_register_client_.
538 mutable base::Lock strike_register_client_lock_
;
539 // strike_register_ contains a data structure that keeps track of previously
540 // observed client nonces in order to prevent replay attacks.
541 mutable scoped_ptr
<StrikeRegisterClient
> strike_register_client_
;
543 // Default source_address_token_boxer_ used to protect the
544 // source-address tokens that are given to clients. Individual
545 // configs may use boxers with alternate secrets.
546 CryptoSecretBoxer default_source_address_token_boxer_
;
548 // server_nonce_boxer_ is used to encrypt and validate suggested server
550 CryptoSecretBoxer server_nonce_boxer_
;
552 // server_nonce_orbit_ contains the random, per-server orbit values that this
553 // server will use to generate server nonces (the moral equivalent of a SYN
555 uint8 server_nonce_orbit_
[8];
557 mutable base::Lock server_nonce_strike_register_lock_
;
558 // server_nonce_strike_register_ contains a data structure that keeps track of
559 // previously observed server nonces from this server, in order to prevent
561 mutable scoped_ptr
<StrikeRegister
> server_nonce_strike_register_
;
563 // proof_source_ contains an object that can provide certificate chains and
565 scoped_ptr
<ProofSource
> proof_source_
;
567 // ephemeral_key_source_ contains an object that caches ephemeral keys for a
568 // short period of time.
569 scoped_ptr
<EphemeralKeySource
> ephemeral_key_source_
;
571 // These fields store configuration values. See the comments for their
572 // respective setter functions.
573 bool strike_register_no_startup_period_
;
574 uint32 strike_register_max_entries_
;
575 uint32 strike_register_window_secs_
;
576 uint32 source_address_token_future_secs_
;
577 uint32 source_address_token_lifetime_secs_
;
578 uint32 server_nonce_strike_register_max_entries_
;
579 uint32 server_nonce_strike_register_window_secs_
;
581 DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerConfig
);
586 #endif // NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_