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_CLIENT_CONFIG_H_ 6 #define QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_ 7 8 #include <cstdint> 9 #include <map> 10 #include <memory> 11 #include <string> 12 #include <vector> 13 14 #include "absl/strings/string_view.h" 15 #include "openssl/base.h" 16 #include "openssl/ssl.h" 17 #include "quiche/quic/core/crypto/client_proof_source.h" 18 #include "quiche/quic/core/crypto/crypto_handshake.h" 19 #include "quiche/quic/core/crypto/crypto_protocol.h" 20 #include "quiche/quic/core/crypto/quic_random.h" 21 #include "quiche/quic/core/crypto/transport_parameters.h" 22 #include "quiche/quic/core/quic_packets.h" 23 #include "quiche/quic/core/quic_server_id.h" 24 #include "quiche/quic/platform/api/quic_export.h" 25 #include "quiche/common/platform/api/quiche_reference_counted.h" 26 27 namespace quic { 28 29 class CryptoHandshakeMessage; 30 class ProofVerifier; 31 class ProofVerifyDetails; 32 33 // QuicResumptionState stores the state a client needs for performing connection 34 // resumption. 35 struct QUICHE_EXPORT QuicResumptionState { 36 // |tls_session| holds the cryptographic state necessary for a resumption. It 37 // includes the ALPN negotiated on the connection where the ticket was 38 // received. 39 bssl::UniquePtr<SSL_SESSION> tls_session; 40 41 // If the application using QUIC doesn't support 0-RTT handshakes or the 42 // client didn't receive a 0-RTT capable session ticket from the server, 43 // |transport_params| will be null. Otherwise, it will contain the transport 44 // parameters received from the server on the original connection. 45 std::unique_ptr<TransportParameters> transport_params = nullptr; 46 47 // If |transport_params| is null, then |application_state| is ignored and 48 // should be empty. |application_state| contains serialized state that the 49 // client received from the server at the application layer that the client 50 // needs to remember when performing a 0-RTT handshake. 51 std::unique_ptr<ApplicationState> application_state = nullptr; 52 53 // Opaque token received in NEW_TOKEN frame if any. 54 std::string token; 55 }; 56 57 // SessionCache is an interface for managing storing and retrieving 58 // QuicResumptionState structs. 59 class QUICHE_EXPORT SessionCache { 60 public: ~SessionCache()61 virtual ~SessionCache() {} 62 63 // Inserts |session|, |params|, and |application_states| into the cache, keyed 64 // by |server_id|. Insert is first called after all three values are present. 65 // The ownership of |session| is transferred to the cache, while other two are 66 // copied. Multiple sessions might need to be inserted for a connection. 67 // SessionCache implementations should support storing 68 // multiple entries per server ID. 69 virtual void Insert(const QuicServerId& server_id, 70 bssl::UniquePtr<SSL_SESSION> session, 71 const TransportParameters& params, 72 const ApplicationState* application_state) = 0; 73 74 // Lookup is called once at the beginning of each TLS handshake to potentially 75 // provide the saved state both for the TLS handshake and for sending 0-RTT 76 // data (if supported). Lookup may return a nullptr. Implementations should 77 // delete cache entries after returning them in Lookup so that session tickets 78 // are used only once. 79 virtual std::unique_ptr<QuicResumptionState> Lookup( 80 const QuicServerId& server_id, QuicWallTime now, const SSL_CTX* ctx) = 0; 81 82 // Called when 0-RTT is rejected. Disables early data for all the TLS tickets 83 // associated with |server_id|. 84 virtual void ClearEarlyData(const QuicServerId& server_id) = 0; 85 86 // Called when NEW_TOKEN frame is received. 87 virtual void OnNewTokenReceived(const QuicServerId& server_id, 88 absl::string_view token) = 0; 89 90 // Called to remove expired entries. 91 virtual void RemoveExpiredEntries(QuicWallTime now) = 0; 92 93 // Clear the session cache. 94 virtual void Clear() = 0; 95 }; 96 97 // QuicCryptoClientConfig contains crypto-related configuration settings for a 98 // client. Note that this object isn't thread-safe. It's designed to be used on 99 // a single thread at a time. 100 class QUICHE_EXPORT QuicCryptoClientConfig : public QuicCryptoConfig { 101 public: 102 // A CachedState contains the information that the client needs in order to 103 // perform a 0-RTT handshake with a server. This information can be reused 104 // over several connections to the same server. 105 class QUICHE_EXPORT CachedState { 106 public: 107 // Enum to track if the server config is valid or not. If it is not valid, 108 // it specifies why it is invalid. 109 enum ServerConfigState { 110 // WARNING: Do not change the numerical values of any of server config 111 // state. Do not remove deprecated server config states - just comment 112 // them as deprecated. 113 SERVER_CONFIG_EMPTY = 0, 114 SERVER_CONFIG_INVALID = 1, 115 SERVER_CONFIG_CORRUPTED = 2, 116 SERVER_CONFIG_EXPIRED = 3, 117 SERVER_CONFIG_INVALID_EXPIRY = 4, 118 SERVER_CONFIG_VALID = 5, 119 // NOTE: Add new server config states only immediately above this line. 120 // Make sure to update the QuicServerConfigState enum in 121 // tools/metrics/histograms/histograms.xml accordingly. 122 SERVER_CONFIG_COUNT 123 }; 124 125 CachedState(); 126 CachedState(const CachedState&) = delete; 127 CachedState& operator=(const CachedState&) = delete; 128 ~CachedState(); 129 130 // IsComplete returns true if this object contains enough information to 131 // perform a handshake with the server. |now| is used to judge whether any 132 // cached server config has expired. 133 bool IsComplete(QuicWallTime now) const; 134 135 // IsEmpty returns true if |server_config_| is empty. 136 bool IsEmpty() const; 137 138 // GetServerConfig returns the parsed contents of |server_config|, or 139 // nullptr if |server_config| is empty. The return value is owned by this 140 // object and is destroyed when this object is. 141 const CryptoHandshakeMessage* GetServerConfig() const; 142 143 // SetServerConfig checks that |server_config| parses correctly and stores 144 // it in |server_config_|. |now| is used to judge whether |server_config| 145 // has expired. 146 ServerConfigState SetServerConfig(absl::string_view server_config, 147 QuicWallTime now, 148 QuicWallTime expiry_time, 149 std::string* error_details); 150 151 // InvalidateServerConfig clears the cached server config (if any). 152 void InvalidateServerConfig(); 153 154 // SetProof stores a cert chain, cert signed timestamp and signature. 155 void SetProof(const std::vector<std::string>& certs, 156 absl::string_view cert_sct, absl::string_view chlo_hash, 157 absl::string_view signature); 158 159 // Clears all the data. 160 void Clear(); 161 162 // Clears the certificate chain and signature and invalidates the proof. 163 void ClearProof(); 164 165 // SetProofValid records that the certificate chain and signature have been 166 // validated and that it's safe to assume that the server is legitimate. 167 // (Note: this does not check the chain or signature.) 168 void SetProofValid(); 169 170 // If the server config or the proof has changed then it needs to be 171 // revalidated. Helper function to keep server_config_valid_ and 172 // generation_counter_ in sync. 173 void SetProofInvalid(); 174 175 const std::string& server_config() const; 176 const std::string& source_address_token() const; 177 const std::vector<std::string>& certs() const; 178 const std::string& cert_sct() const; 179 const std::string& chlo_hash() const; 180 const std::string& signature() const; 181 bool proof_valid() const; 182 uint64_t generation_counter() const; 183 const ProofVerifyDetails* proof_verify_details() const; 184 185 void set_source_address_token(absl::string_view token); 186 187 void set_cert_sct(absl::string_view cert_sct); 188 189 // SetProofVerifyDetails takes ownership of |details|. 190 void SetProofVerifyDetails(ProofVerifyDetails* details); 191 192 // Copy the |server_config_|, |source_address_token_|, |certs_|, 193 // |expiration_time_|, |cert_sct_|, |chlo_hash_| and |server_config_sig_| 194 // from the |other|. The remaining fields, |generation_counter_|, 195 // |proof_verify_details_|, and |scfg_| remain unchanged. 196 void InitializeFrom(const CachedState& other); 197 198 // Initializes this cached state based on the arguments provided. 199 // Returns false if there is a problem parsing the server config. 200 bool Initialize(absl::string_view server_config, 201 absl::string_view source_address_token, 202 const std::vector<std::string>& certs, 203 const std::string& cert_sct, absl::string_view chlo_hash, 204 absl::string_view signature, QuicWallTime now, 205 QuicWallTime expiration_time); 206 207 private: 208 std::string server_config_; // A serialized handshake message. 209 std::string source_address_token_; // An opaque proof of IP ownership. 210 std::vector<std::string> certs_; // A list of certificates in leaf-first 211 // order. 212 std::string cert_sct_; // Signed timestamp of the leaf cert. 213 std::string chlo_hash_; // Hash of the CHLO message. 214 std::string server_config_sig_; // A signature of |server_config_|. 215 bool server_config_valid_; // True if |server_config_| is correctly 216 // signed and |certs_| has been validated. 217 QuicWallTime expiration_time_; // Time when the config is no longer valid. 218 // Generation counter associated with the |server_config_|, |certs_| and 219 // |server_config_sig_| combination. It is incremented whenever we set 220 // server_config_valid_ to false. 221 uint64_t generation_counter_; 222 223 std::unique_ptr<ProofVerifyDetails> proof_verify_details_; 224 225 // scfg contains the cached, parsed value of |server_config|. 226 mutable std::unique_ptr<CryptoHandshakeMessage> scfg_; 227 }; 228 229 // Used to filter server ids for partial config deletion. 230 class QUICHE_EXPORT ServerIdFilter { 231 public: ~ServerIdFilter()232 virtual ~ServerIdFilter() {} 233 234 // Returns true if |server_id| matches the filter. 235 virtual bool Matches(const QuicServerId& server_id) const = 0; 236 }; 237 238 // DEPRECATED: Use the constructor below instead. 239 explicit QuicCryptoClientConfig( 240 std::unique_ptr<ProofVerifier> proof_verifier); 241 QuicCryptoClientConfig(std::unique_ptr<ProofVerifier> proof_verifier, 242 std::shared_ptr<SessionCache> session_cache); 243 QuicCryptoClientConfig(const QuicCryptoClientConfig&) = delete; 244 QuicCryptoClientConfig& operator=(const QuicCryptoClientConfig&) = delete; 245 ~QuicCryptoClientConfig(); 246 247 // LookupOrCreate returns a CachedState for the given |server_id|. If no such 248 // CachedState currently exists, it will be created and cached. 249 CachedState* LookupOrCreate(const QuicServerId& server_id); 250 251 // Delete CachedState objects whose server ids match |filter| from 252 // cached_states. 253 void ClearCachedStates(const ServerIdFilter& filter); 254 255 // FillInchoateClientHello sets |out| to be a CHLO message that elicits a 256 // source-address token or SCFG from a server. If |cached| is non-nullptr, the 257 // source-address token will be taken from it. |out_params| is used in order 258 // to store the cached certs that were sent as hints to the server in 259 // |out_params->cached_certs|. |preferred_version| is the version of the 260 // QUIC protocol that this client chose to use initially. This allows the 261 // server to detect downgrade attacks. If |demand_x509_proof| is true, 262 // then |out| will include an X509 proof demand, and the associated 263 // certificate related fields. 264 void FillInchoateClientHello( 265 const QuicServerId& server_id, const ParsedQuicVersion preferred_version, 266 const CachedState* cached, QuicRandom* rand, bool demand_x509_proof, 267 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> 268 out_params, 269 CryptoHandshakeMessage* out) const; 270 271 // FillClientHello sets |out| to be a CHLO message based on the configuration 272 // of this object. This object must have cached enough information about 273 // the server's hostname in order to perform a handshake. This can be checked 274 // with the |IsComplete| member of |CachedState|. 275 // 276 // |now| and |rand| are used to generate the nonce and |out_params| is 277 // filled with the results of the handshake that the server is expected to 278 // accept. |preferred_version| is the version of the QUIC protocol that this 279 // client chose to use initially. This allows the server to detect downgrade 280 // attacks. 281 // 282 // If |channel_id_key| is not null, it is used to sign a secret value derived 283 // from the client and server's keys, and the Channel ID public key and the 284 // signature are placed in the CETV value of the CHLO. 285 QuicErrorCode FillClientHello( 286 const QuicServerId& server_id, QuicConnectionId connection_id, 287 const ParsedQuicVersion preferred_version, 288 const ParsedQuicVersion actual_version, const CachedState* cached, 289 QuicWallTime now, QuicRandom* rand, 290 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> 291 out_params, 292 CryptoHandshakeMessage* out, std::string* error_details) const; 293 294 // ProcessRejection processes a REJ message from a server and updates the 295 // cached information about that server. After this, |IsComplete| may return 296 // true for that server's CachedState. If the rejection message contains state 297 // about a future handshake (i.e. an nonce value from the server), then it 298 // will be saved in |out_params|. |now| is used to judge whether the server 299 // config in the rejection message has expired. 300 QuicErrorCode ProcessRejection( 301 const CryptoHandshakeMessage& rej, QuicWallTime now, 302 QuicTransportVersion version, absl::string_view chlo_hash, 303 CachedState* cached, 304 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> 305 out_params, 306 std::string* error_details); 307 308 // ProcessServerHello processes the message in |server_hello|, updates the 309 // cached information about that server, writes the negotiated parameters to 310 // |out_params| and returns QUIC_NO_ERROR. If |server_hello| is unacceptable 311 // then it puts an error message in |error_details| and returns an error 312 // code. |version| is the QUIC version for the current connection. 313 // |negotiated_versions| contains the list of version, if any, that were 314 // present in a version negotiation packet previously received from the 315 // server. The contents of this list will be compared against the list of 316 // versions provided in the VER tag of the server hello. 317 QuicErrorCode ProcessServerHello( 318 const CryptoHandshakeMessage& server_hello, 319 QuicConnectionId connection_id, ParsedQuicVersion version, 320 const ParsedQuicVersionVector& negotiated_versions, CachedState* cached, 321 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> 322 out_params, 323 std::string* error_details); 324 325 // Processes the message in |server_config_update|, updating the cached source 326 // address token, and server config. 327 // If |server_config_update| is invalid then |error_details| will contain an 328 // error message, and an error code will be returned. If all has gone well 329 // QUIC_NO_ERROR is returned. 330 QuicErrorCode ProcessServerConfigUpdate( 331 const CryptoHandshakeMessage& server_config_update, QuicWallTime now, 332 const QuicTransportVersion version, absl::string_view chlo_hash, 333 CachedState* cached, 334 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> 335 out_params, 336 std::string* error_details); 337 338 ProofVerifier* proof_verifier() const; 339 SessionCache* session_cache() const; 340 void set_session_cache(std::shared_ptr<SessionCache> session_cache); 341 ClientProofSource* proof_source() const; 342 void set_proof_source(std::unique_ptr<ClientProofSource> proof_source); 343 SSL_CTX* ssl_ctx() const; 344 345 // Initialize the CachedState from |canonical_crypto_config| for the 346 // |canonical_server_id| as the initial CachedState for |server_id|. We will 347 // copy config data only if |canonical_crypto_config| has valid proof. 348 void InitializeFrom(const QuicServerId& server_id, 349 const QuicServerId& canonical_server_id, 350 QuicCryptoClientConfig* canonical_crypto_config); 351 352 // Adds |suffix| as a domain suffix for which the server's crypto config 353 // is expected to be shared among servers with the domain suffix. If a server 354 // matches this suffix, then the server config from another server with the 355 // suffix will be used to initialize the cached state for this server. 356 void AddCanonicalSuffix(const std::string& suffix); 357 358 // The groups to use for key exchange in the TLS handshake. preferred_groups()359 const std::vector<uint16_t>& preferred_groups() const { 360 return preferred_groups_; 361 } 362 363 // Sets the preferred groups that will be used in the TLS handshake. Values 364 // in the |preferred_groups| vector are NamedGroup enum codepoints from 365 // https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.7. set_preferred_groups(const std::vector<uint16_t> & preferred_groups)366 void set_preferred_groups(const std::vector<uint16_t>& preferred_groups) { 367 preferred_groups_ = preferred_groups; 368 } 369 370 // Saves the |user_agent_id| that will be passed in QUIC's CHLO message. set_user_agent_id(const std::string & user_agent_id)371 void set_user_agent_id(const std::string& user_agent_id) { 372 user_agent_id_ = user_agent_id; 373 } 374 375 // Returns the user_agent_id that will be provided in the client hello 376 // handshake message. user_agent_id()377 const std::string& user_agent_id() const { return user_agent_id_; } 378 set_tls_signature_algorithms(std::string signature_algorithms)379 void set_tls_signature_algorithms(std::string signature_algorithms) { 380 tls_signature_algorithms_ = std::move(signature_algorithms); 381 } 382 tls_signature_algorithms()383 const std::optional<std::string>& tls_signature_algorithms() const { 384 return tls_signature_algorithms_; 385 } 386 387 // Saves the |alpn| that will be passed in QUIC's CHLO message. set_alpn(const std::string & alpn)388 void set_alpn(const std::string& alpn) { alpn_ = alpn; } 389 390 // Saves the pre-shared key used during the handshake. set_pre_shared_key(absl::string_view psk)391 void set_pre_shared_key(absl::string_view psk) { 392 pre_shared_key_ = std::string(psk); 393 } 394 395 // Returns the pre-shared key used during the handshake. pre_shared_key()396 const std::string& pre_shared_key() const { return pre_shared_key_; } 397 pad_inchoate_hello()398 bool pad_inchoate_hello() const { return pad_inchoate_hello_; } set_pad_inchoate_hello(bool new_value)399 void set_pad_inchoate_hello(bool new_value) { 400 pad_inchoate_hello_ = new_value; 401 } 402 pad_full_hello()403 bool pad_full_hello() const { return pad_full_hello_; } set_pad_full_hello(bool new_value)404 void set_pad_full_hello(bool new_value) { pad_full_hello_ = new_value; } 405 406 #if BORINGSSL_API_VERSION >= 27 alps_use_new_codepoint()407 bool alps_use_new_codepoint() const { return alps_use_new_codepoint_; } set_alps_use_new_codepoint(bool new_value)408 void set_alps_use_new_codepoint(bool new_value) { 409 alps_use_new_codepoint_ = new_value; 410 } 411 #endif // BORINGSSL_API_VERSION 412 413 private: 414 // Sets the members to reasonable, default values. 415 void SetDefaults(); 416 417 // CacheNewServerConfig checks for SCFG, STK, PROF, and CRT tags in |message|, 418 // verifies them, and stores them in the cached state if they validate. 419 // This is used on receipt of a REJ from a server, or when a server sends 420 // updated server config during a connection. 421 QuicErrorCode CacheNewServerConfig( 422 const CryptoHandshakeMessage& message, QuicWallTime now, 423 QuicTransportVersion version, absl::string_view chlo_hash, 424 const std::vector<std::string>& cached_certs, CachedState* cached, 425 std::string* error_details); 426 427 // If the suffix of the hostname in |server_id| is in |canonical_suffixes_|, 428 // then populate |cached| with the canonical cached state from 429 // |canonical_server_map_| for that suffix. Returns true if |cached| is 430 // initialized with canonical cached state. 431 bool PopulateFromCanonicalConfig(const QuicServerId& server_id, 432 CachedState* cached); 433 434 // cached_states_ maps from the server_id to the cached information about 435 // that server. 436 std::map<QuicServerId, std::unique_ptr<CachedState>> cached_states_; 437 438 // Contains a map of servers which could share the same server config. Map 439 // from a canonical host suffix/port/scheme to a representative server with 440 // the canonical suffix, which has a plausible set of initial certificates 441 // (or at least server public key). 442 std::map<QuicServerId, QuicServerId> canonical_server_map_; 443 444 // Contains list of suffixes (for exmaple ".c.youtube.com", 445 // ".googlevideo.com") of canonical hostnames. 446 std::vector<std::string> canonical_suffixes_; 447 448 std::unique_ptr<ProofVerifier> proof_verifier_; 449 std::shared_ptr<SessionCache> session_cache_; 450 std::unique_ptr<ClientProofSource> proof_source_; 451 452 bssl::UniquePtr<SSL_CTX> ssl_ctx_; 453 454 // The groups to use for key exchange in the TLS handshake. 455 std::vector<uint16_t> preferred_groups_; 456 457 // The |user_agent_id_| passed in QUIC's CHLO message. 458 std::string user_agent_id_; 459 460 // The |alpn_| passed in QUIC's CHLO message. 461 std::string alpn_; 462 463 // If non-empty, the client will operate in the pre-shared key mode by 464 // incorporating |pre_shared_key_| into the key schedule. 465 std::string pre_shared_key_; 466 467 // If set, configure the client to use the specified signature algorithms, via 468 // SSL_set1_sigalgs_list. TLS only. 469 std::optional<std::string> tls_signature_algorithms_; 470 471 // In QUIC, technically, client hello should be fully padded. 472 // However, fully padding on slow network connection (e.g. 50kbps) can add 473 // 150ms latency to one roundtrip. Therefore, you can disable padding of 474 // individual messages. It is recommend to leave at least one message in 475 // each direction fully padded (e.g. full CHLO and SHLO), but if you know 476 // the lower-bound MTU, you don't need to pad all of them (keep in mind that 477 // it's not OK to do it according to the standard). 478 // 479 // Also, if you disable padding, you must disable (change) the 480 // anti-amplification protection. You should only do so if you have some 481 // other means of verifying the client. 482 bool pad_inchoate_hello_ = true; 483 bool pad_full_hello_ = true; 484 485 #if BORINGSSL_API_VERSION >= 27 486 // Set whether ALPS uses the new codepoint or not. 487 bool alps_use_new_codepoint_ = false; 488 #endif // BORINGSSL_API_VERSION 489 }; 490 491 } // namespace quic 492 493 #endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_ 494