• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
6 #define NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
7 
8 #include <map>
9 #include <string>
10 #include <vector>
11 
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/crypto_handshake.h"
19 #include "net/quic/crypto/crypto_protocol.h"
20 #include "net/quic/crypto/crypto_secret_boxer.h"
21 #include "net/quic/quic_time.h"
22 
23 namespace net {
24 
25 class CryptoHandshakeMessage;
26 class EphemeralKeySource;
27 class KeyExchange;
28 class ProofSource;
29 class QuicClock;
30 class QuicDecrypter;
31 class QuicEncrypter;
32 class QuicRandom;
33 class QuicServerConfigProtobuf;
34 class StrikeRegister;
35 class StrikeRegisterClient;
36 
37 struct ClientHelloInfo;
38 
39 namespace test {
40 class QuicCryptoServerConfigPeer;
41 }  // namespace test
42 
43 enum HandshakeFailureReason {
44   HANDSHAKE_OK = 0,
45 
46   // Failure reasons for an invalid client nonce.
47   // TODO(rtenneti): Implement capturing of error from strike register.
48   CLIENT_NONCE_UNKNOWN_FAILURE = 100,
49   CLIENT_NONCE_INVALID_FAILURE,
50 
51   // Failure reasons for an invalid server nonce.
52   SERVER_NONCE_INVALID_FAILURE = 200,
53   SERVER_NONCE_DECRYPTION_FAILURE,
54   SERVER_NONCE_NOT_UNIQUE_FAILURE,
55 
56   // Failure reasons for an invalid server config.
57   SERVER_CONFIG_INCHOATE_HELLO_FAILURE = 300,
58   SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE,
59 
60   // Failure reasons for an invalid source adddress token.
61   SOURCE_ADDRESS_TOKEN_INVALID_FAILURE = 400,
62   SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
63   SOURCE_ADDRESS_TOKEN_PARSE_FAILURE,
64   SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
65   SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
66   SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
67 };
68 
69 // Hook that allows application code to subscribe to primary config changes.
70 class PrimaryConfigChangedCallback {
71  public:
72   PrimaryConfigChangedCallback();
73   virtual ~PrimaryConfigChangedCallback();
74   virtual void Run(const std::string& scid) = 0;
75 
76  private:
77   DISALLOW_COPY_AND_ASSIGN(PrimaryConfigChangedCallback);
78 };
79 
80 // Callback used to accept the result of the |client_hello| validation step.
81 class NET_EXPORT_PRIVATE ValidateClientHelloResultCallback {
82  public:
83   // Opaque token that holds information about the client_hello and
84   // its validity.  Can be interpreted by calling ProcessClientHello.
85   struct Result;
86 
87   ValidateClientHelloResultCallback();
88   virtual ~ValidateClientHelloResultCallback();
89   void Run(const Result* result);
90 
91  protected:
92   virtual void RunImpl(const CryptoHandshakeMessage& client_hello,
93                        const Result& result) = 0;
94 
95  private:
96   DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloResultCallback);
97 };
98 
99 // QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
100 // Unlike a client, a QUIC server can have multiple configurations active in
101 // order to support clients resuming with a previous configuration.
102 // TODO(agl): when adding configurations at runtime is added, this object will
103 // need to consider locking.
104 class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
105  public:
106   // ConfigOptions contains options for generating server configs.
107   struct NET_EXPORT_PRIVATE ConfigOptions {
108     ConfigOptions();
109 
110     // expiry_time is the time, in UNIX seconds, when the server config will
111     // expire. If unset, it defaults to the current time plus six months.
112     QuicWallTime expiry_time;
113     // channel_id_enabled controls whether the server config will indicate
114     // support for ChannelIDs.
115     bool channel_id_enabled;
116     // id contains the server config id for the resulting config. If empty, a
117     // random id is generated.
118     std::string id;
119     // orbit contains the kOrbitSize bytes of the orbit value for the server
120     // config. If |orbit| is empty then a random orbit is generated.
121     std::string orbit;
122     // p256 determines whether a P-256 public key will be included in the
123     // server config. Note that this breaks deterministic server-config
124     // generation since P-256 key generation doesn't use the QuicRandom given
125     // to DefaultConfig().
126     bool p256;
127   };
128 
129   // |source_address_token_secret|: secret key material used for encrypting and
130   //     decrypting source address tokens. It can be of any length as it is fed
131   //     into a KDF before use. In tests, use TESTING.
132   // |server_nonce_entropy|: an entropy source used to generate the orbit and
133   //     key for server nonces, which are always local to a given instance of a
134   //     server.
135   QuicCryptoServerConfig(base::StringPiece source_address_token_secret,
136                          QuicRandom* server_nonce_entropy);
137   ~QuicCryptoServerConfig();
138 
139   // TESTING is a magic parameter for passing to the constructor in tests.
140   static const char TESTING[];
141 
142   // Generates a QuicServerConfigProtobuf protobuf suitable for
143   // AddConfig and SetConfigs.
144   static QuicServerConfigProtobuf* GenerateConfig(
145       QuicRandom* rand,
146       const QuicClock* clock,
147       const ConfigOptions& options);
148 
149   // AddConfig adds a QuicServerConfigProtobuf to the availible configurations.
150   // It returns the SCFG message from the config if successful. The caller
151   // takes ownership of the CryptoHandshakeMessage. |now| is used in
152   // conjunction with |protobuf->primary_time()| to determine whether the
153   // config should be made primary.
154   CryptoHandshakeMessage* AddConfig(QuicServerConfigProtobuf* protobuf,
155                                     QuicWallTime now);
156 
157   // AddDefaultConfig calls DefaultConfig to create a config and then calls
158   // AddConfig to add it. See the comment for |DefaultConfig| for details of
159   // the arguments.
160   CryptoHandshakeMessage* AddDefaultConfig(
161       QuicRandom* rand,
162       const QuicClock* clock,
163       const ConfigOptions& options);
164 
165   // SetConfigs takes a vector of config protobufs and the current time.
166   // Configs are assumed to be uniquely identified by their server config ID.
167   // Previously unknown configs are added and possibly made the primary config
168   // depending on their |primary_time| and the value of |now|. Configs that are
169   // known, but are missing from the protobufs are deleted, unless they are
170   // currently the primary config. SetConfigs returns false if any errors were
171   // encountered and no changes to the QuicCryptoServerConfig will occur.
172   bool SetConfigs(const std::vector<QuicServerConfigProtobuf*>& protobufs,
173                   QuicWallTime now);
174 
175   // Get the server config ids for all known configs.
176   void GetConfigIds(std::vector<std::string>* scids) const;
177 
178   // Checks |client_hello| for gross errors and determines whether it
179   // can be shown to be fresh (i.e. not a replay).  The result of the
180   // validation step must be interpreted by calling
181   // QuicCryptoServerConfig::ProcessClientHello from the done_cb.
182   //
183   // ValidateClientHello may invoke the done_cb before unrolling the
184   // stack if it is able to assess the validity of the client_nonce
185   // without asynchronous operations.
186   //
187   // client_hello: the incoming client hello message.
188   // client_ip: the IP address of the client, which is used to generate and
189   //     validate source-address tokens.
190   // clock: used to validate client nonces and ephemeral keys.
191   // done_cb: single-use callback that accepts an opaque
192   //     ValidatedClientHelloMsg token that holds information about
193   //     the client hello.  The callback will always be called exactly
194   //     once, either under the current call stack, or after the
195   //     completion of an asynchronous operation.
196   void ValidateClientHello(
197       const CryptoHandshakeMessage& client_hello,
198       IPEndPoint client_ip,
199       const QuicClock* clock,
200       ValidateClientHelloResultCallback* done_cb) const;
201 
202   // ProcessClientHello processes |client_hello| and decides whether to accept
203   // or reject the connection. If the connection is to be accepted, |out| is
204   // set to the contents of the ServerHello, |out_params| is completed and
205   // QUIC_NO_ERROR is returned. Otherwise |out| is set to be a REJ message and
206   // an error code is returned.
207   //
208   // validate_chlo_result: Output from the asynchronous call to
209   //     ValidateClientHello.  Contains the client hello message and
210   //     information about it.
211   // connection_id: the ConnectionId for the connection, which is used in key
212   //     derivation.
213   // client_address: the IP address and port of the client. The IP address is
214   //     used to generate and validate source-address tokens.
215   // version: version of the QUIC protocol in use for this connection
216   // supported_versions: versions of the QUIC protocol that this server
217   //     supports.
218   // initial_flow_control_window: size of initial flow control window this
219   //     server uses for new streams.
220   // clock: used to validate client nonces and ephemeral keys.
221   // rand: an entropy source
222   // params: the state of the handshake. This may be updated with a server
223   //     nonce when we send a rejection. After a successful handshake, this will
224   //     contain the state of the connection.
225   // out: the resulting handshake message (either REJ or SHLO)
226   // error_details: used to store a string describing any error.
227   QuicErrorCode ProcessClientHello(
228       const ValidateClientHelloResultCallback::Result& validate_chlo_result,
229       QuicConnectionId connection_id,
230       IPEndPoint client_address,
231       QuicVersion version,
232       const QuicVersionVector& supported_versions,
233       const QuicClock* clock,
234       QuicRandom* rand,
235       QuicCryptoNegotiatedParameters* params,
236       CryptoHandshakeMessage* out,
237       std::string* error_details) const;
238 
239   // SetProofSource installs |proof_source| as the ProofSource for handshakes.
240   // This object takes ownership of |proof_source|.
241   void SetProofSource(ProofSource* proof_source);
242 
243   // SetEphemeralKeySource installs an object that can cache ephemeral keys for
244   // a short period of time. This object takes ownership of
245   // |ephemeral_key_source|. If not set then ephemeral keys will be generated
246   // per-connection.
247   void SetEphemeralKeySource(EphemeralKeySource* ephemeral_key_source);
248 
249   // Install an externall created StrikeRegisterClient for use to
250   // interact with the strike register.  This object takes ownership
251   // of the |strike_register_client|.
252   void SetStrikeRegisterClient(StrikeRegisterClient* strike_register_client);
253 
254   // set_replay_protection controls whether replay protection is enabled. If
255   // replay protection is disabled then no strike registers are needed and
256   // frontends can share an orbit value without a shared strike-register.
257   // However, an attacker can duplicate a handshake and cause a client's
258   // request to be processed twice.
259   void set_replay_protection(bool on);
260 
261   // set_strike_register_no_startup_period configures the strike register to
262   // not have a startup period.
263   void set_strike_register_no_startup_period();
264 
265   // set_strike_register_max_entries sets the maximum number of entries that
266   // the internal strike register will hold. If the strike register fills up
267   // then the oldest entries (by the client's clock) will be dropped.
268   void set_strike_register_max_entries(uint32 max_entries);
269 
270   // set_strike_register_window_secs sets the number of seconds around the
271   // current time that the strike register will attempt to be authoritative
272   // for. Setting a larger value allows for greater client clock-skew, but
273   // means that the quiescent startup period must be longer.
274   void set_strike_register_window_secs(uint32 window_secs);
275 
276   // set_source_address_token_future_secs sets the number of seconds into the
277   // future that source-address tokens will be accepted from. Since
278   // source-address tokens are authenticated, this should only happen if
279   // another, valid server has clock-skew.
280   void set_source_address_token_future_secs(uint32 future_secs);
281 
282   // set_source_address_token_lifetime_secs sets the number of seconds that a
283   // source-address token will be valid for.
284   void set_source_address_token_lifetime_secs(uint32 lifetime_secs);
285 
286   // set_server_nonce_strike_register_max_entries sets the number of entries in
287   // the server-nonce strike-register. This is used to record that server nonce
288   // values have been used. If the number of entries is too small then clients
289   // which are depending on server nonces may fail to handshake because their
290   // nonce has expired in the amount of time it took to go from the server to
291   // the client and back.
292   void set_server_nonce_strike_register_max_entries(uint32 max_entries);
293 
294   // set_server_nonce_strike_register_window_secs sets the number of seconds
295   // around the current time that the server-nonce strike-register will accept
296   // nonces from. Setting a larger value allows for clients to delay follow-up
297   // client hellos for longer and still use server nonces as proofs of
298   // uniqueness.
299   void set_server_nonce_strike_register_window_secs(uint32 window_secs);
300 
301   // Set and take ownership of the callback to invoke on primary config changes.
302   void AcquirePrimaryConfigChangedCb(PrimaryConfigChangedCallback* cb);
303 
304  private:
305   friend class test::QuicCryptoServerConfigPeer;
306 
307   // Config represents a server config: a collection of preferences and
308   // Diffie-Hellman public values.
309   class NET_EXPORT_PRIVATE Config : public QuicCryptoConfig,
310                                     public base::RefCounted<Config> {
311    public:
312     Config();
313 
314     // TODO(rtenneti): since this is a class, we should probably do
315     // getters/setters here.
316     // |serialized| contains the bytes of this server config, suitable for
317     // sending on the wire.
318     std::string serialized;
319     // id contains the SCID of this server config.
320     std::string id;
321     // orbit contains the orbit value for this config: an opaque identifier
322     // used to identify clusters of server frontends.
323     unsigned char orbit[kOrbitSize];
324 
325     // key_exchanges contains key exchange objects with the private keys
326     // already loaded. The values correspond, one-to-one, with the tags in
327     // |kexs| from the parent class.
328     std::vector<KeyExchange*> key_exchanges;
329 
330     // tag_value_map contains the raw key/value pairs for the config.
331     QuicTagValueMap tag_value_map;
332 
333     // channel_id_enabled is true if the config in |serialized| specifies that
334     // ChannelIDs are supported.
335     bool channel_id_enabled;
336 
337     // is_primary is true if this config is the one that we'll give out to
338     // clients as the current one.
339     bool is_primary;
340 
341     // primary_time contains the timestamp when this config should become the
342     // primary config. A value of QuicWallTime::Zero() means that this config
343     // will not be promoted at a specific time.
344     QuicWallTime primary_time;
345 
346     // Secondary sort key for use when selecting primary configs and
347     // there are multiple configs with the same primary time.
348     // Smaller numbers mean higher priority.
349     uint64 priority;
350 
351     // source_address_token_boxer_ is used to protect the
352     // source-address tokens that are given to clients.
353     // Points to either source_address_token_boxer_storage or the
354     // default boxer provided by QuicCryptoServerConfig.
355     const CryptoSecretBoxer* source_address_token_boxer;
356 
357     // Holds the override source_address_token_boxer instance if the
358     // Config is not using the default source address token boxer
359     // instance provided by QuicCryptoServerConfig.
360     scoped_ptr<CryptoSecretBoxer> source_address_token_boxer_storage;
361 
362    private:
363     friend class base::RefCounted<Config>;
364 
365     virtual ~Config();
366 
367     DISALLOW_COPY_AND_ASSIGN(Config);
368   };
369 
370   typedef std::map<ServerConfigID, scoped_refptr<Config> > ConfigMap;
371 
372   // Get a ref to the config with a given server config id.
373   scoped_refptr<Config> GetConfigWithScid(
374       base::StringPiece requested_scid) const;
375 
376   // ConfigPrimaryTimeLessThan returns true if a->primary_time <
377   // b->primary_time.
378   static bool ConfigPrimaryTimeLessThan(const scoped_refptr<Config>& a,
379                                         const scoped_refptr<Config>& b);
380 
381   // SelectNewPrimaryConfig reevaluates the primary config based on the
382   // "primary_time" deadlines contained in each.
383   void SelectNewPrimaryConfig(QuicWallTime now) const;
384 
385   // EvaluateClientHello checks |client_hello| for gross errors and determines
386   // whether it can be shown to be fresh (i.e. not a replay). The results are
387   // written to |info|.
388   void EvaluateClientHello(
389       const uint8* primary_orbit,
390       scoped_refptr<Config> requested_config,
391       ValidateClientHelloResultCallback::Result* client_hello_state,
392       ValidateClientHelloResultCallback* done_cb) const;
393 
394   // BuildRejection sets |out| to be a REJ message in reply to |client_hello|.
395   void BuildRejection(
396       const Config& config,
397       const CryptoHandshakeMessage& client_hello,
398       const ClientHelloInfo& info,
399       QuicRandom* rand,
400       CryptoHandshakeMessage* out) const;
401 
402   // ParseConfigProtobuf parses the given config protobuf and returns a
403   // scoped_refptr<Config> if successful. The caller adopts the reference to the
404   // Config. On error, ParseConfigProtobuf returns NULL.
405   scoped_refptr<Config> ParseConfigProtobuf(QuicServerConfigProtobuf* protobuf);
406 
407   // NewSourceAddressToken returns a fresh source address token for the given
408   // IP address.
409   std::string NewSourceAddressToken(const Config& config,
410                                     const IPEndPoint& ip,
411                                     QuicRandom* rand,
412                                     QuicWallTime now) const;
413 
414   // ValidateSourceAddressToken returns HANDSHAKE_OK if the source address token
415   // in |token| is a valid and timely token for the IP address |ip| given that
416   // the current time is |now|. Otherwise it returns the reason for failure.
417   HandshakeFailureReason ValidateSourceAddressToken(const Config& config,
418                                                     base::StringPiece token,
419                                                     const IPEndPoint& ip,
420                                                     QuicWallTime now) const;
421 
422   // NewServerNonce generates and encrypts a random nonce.
423   std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const;
424 
425   // ValidateServerNonce decrypts |token| and verifies that it hasn't been
426   // previously used and is recent enough that it is plausible that it was part
427   // of a very recently provided rejection ("recent" will be on the order of
428   // 10-30 seconds). If so, it records that it has been used and returns
429   // HANDSHAKE_OK. Otherwise it returns the reason for failure.
430   HandshakeFailureReason ValidateServerNonce(
431       base::StringPiece echoed_server_nonce,
432       QuicWallTime now) const;
433 
434   // replay_protection_ controls whether the server enforces that handshakes
435   // aren't replays.
436   bool replay_protection_;
437 
438   // configs_ satisfies the following invariants:
439   //   1) configs_.empty() <-> primary_config_ == NULL
440   //   2) primary_config_ != NULL -> primary_config_->is_primary
441   //   3) ∀ c∈configs_, c->is_primary <-> c == primary_config_
442   mutable base::Lock configs_lock_;
443   // configs_ contains all active server configs. It's expected that there are
444   // about half-a-dozen configs active at any one time.
445   ConfigMap configs_;
446   // primary_config_ points to a Config (which is also in |configs_|) which is
447   // the primary config - i.e. the one that we'll give out to new clients.
448   mutable scoped_refptr<Config> primary_config_;
449   // next_config_promotion_time_ contains the nearest, future time when an
450   // active config will be promoted to primary.
451   mutable QuicWallTime next_config_promotion_time_;
452   // Callback to invoke when the primary config changes.
453   scoped_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_;
454 
455   // Protects access to the pointer held by strike_register_client_.
456   mutable base::Lock strike_register_client_lock_;
457   // strike_register_ contains a data structure that keeps track of previously
458   // observed client nonces in order to prevent replay attacks.
459   mutable scoped_ptr<StrikeRegisterClient> strike_register_client_;
460 
461   // Default source_address_token_boxer_ used to protect the
462   // source-address tokens that are given to clients.  Individual
463   // configs may use boxers with alternate secrets.
464   CryptoSecretBoxer default_source_address_token_boxer_;
465 
466   // server_nonce_boxer_ is used to encrypt and validate suggested server
467   // nonces.
468   CryptoSecretBoxer server_nonce_boxer_;
469 
470   // server_nonce_orbit_ contains the random, per-server orbit values that this
471   // server will use to generate server nonces (the moral equivalent of a SYN
472   // cookies).
473   uint8 server_nonce_orbit_[8];
474 
475   mutable base::Lock server_nonce_strike_register_lock_;
476   // server_nonce_strike_register_ contains a data structure that keeps track of
477   // previously observed server nonces from this server, in order to prevent
478   // replay attacks.
479   mutable scoped_ptr<StrikeRegister> server_nonce_strike_register_;
480 
481   // proof_source_ contains an object that can provide certificate chains and
482   // signatures.
483   scoped_ptr<ProofSource> proof_source_;
484 
485   // ephemeral_key_source_ contains an object that caches ephemeral keys for a
486   // short period of time.
487   scoped_ptr<EphemeralKeySource> ephemeral_key_source_;
488 
489   // These fields store configuration values. See the comments for their
490   // respective setter functions.
491   bool strike_register_no_startup_period_;
492   uint32 strike_register_max_entries_;
493   uint32 strike_register_window_secs_;
494   uint32 source_address_token_future_secs_;
495   uint32 source_address_token_lifetime_secs_;
496   uint32 server_nonce_strike_register_max_entries_;
497   uint32 server_nonce_strike_register_window_secs_;
498 
499   DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerConfig);
500 };
501 
502 }  // namespace net
503 
504 #endif  // NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
505