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