blob: 2918a23bb1388f37209f016321fe2d0fca4efd8b [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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>
vasilvv872e7a32019-03-12 16:42:44 -070011#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050012#include <vector>
13
QUICHE teama6ef0a62019-03-07 20:34:33 -050014#include "third_party/boringssl/src/include/openssl/base.h"
15#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
16#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
17#include "net/third_party/quiche/src/quic/core/quic_packets.h"
18#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
20#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050021#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
22
23namespace quic {
24
QUICHE teama6ef0a62019-03-07 20:34:33 -050025class CryptoHandshakeMessage;
26class ProofVerifier;
27class ProofVerifyDetails;
28class QuicRandom;
29
30// QuicCryptoClientConfig contains crypto-related configuration settings for a
31// client. Note that this object isn't thread-safe. It's designed to be used on
32// a single thread at a time.
33class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
34 public:
35 // A CachedState contains the information that the client needs in order to
36 // perform a 0-RTT handshake with a server. This information can be reused
37 // over several connections to the same server.
38 class QUIC_EXPORT_PRIVATE CachedState {
39 public:
40 // Enum to track if the server config is valid or not. If it is not valid,
41 // it specifies why it is invalid.
42 enum ServerConfigState {
43 // WARNING: Do not change the numerical values of any of server config
44 // state. Do not remove deprecated server config states - just comment
45 // them as deprecated.
46 SERVER_CONFIG_EMPTY = 0,
47 SERVER_CONFIG_INVALID = 1,
48 SERVER_CONFIG_CORRUPTED = 2,
49 SERVER_CONFIG_EXPIRED = 3,
50 SERVER_CONFIG_INVALID_EXPIRY = 4,
51 SERVER_CONFIG_VALID = 5,
52 // NOTE: Add new server config states only immediately above this line.
53 // Make sure to update the QuicServerConfigState enum in
54 // tools/metrics/histograms/histograms.xml accordingly.
55 SERVER_CONFIG_COUNT
56 };
57
58 CachedState();
59 CachedState(const CachedState&) = delete;
60 CachedState& operator=(const CachedState&) = delete;
61 ~CachedState();
62
63 // IsComplete returns true if this object contains enough information to
64 // perform a handshake with the server. |now| is used to judge whether any
65 // cached server config has expired.
66 bool IsComplete(QuicWallTime now) const;
67
68 // IsEmpty returns true if |server_config_| is empty.
69 bool IsEmpty() const;
70
71 // GetServerConfig returns the parsed contents of |server_config|, or
72 // nullptr if |server_config| is empty. The return value is owned by this
73 // object and is destroyed when this object is.
74 const CryptoHandshakeMessage* GetServerConfig() const;
75
76 // SetServerConfig checks that |server_config| parses correctly and stores
77 // it in |server_config_|. |now| is used to judge whether |server_config|
78 // has expired.
79 ServerConfigState SetServerConfig(QuicStringPiece server_config,
80 QuicWallTime now,
81 QuicWallTime expiry_time,
vasilvvc48c8712019-03-11 13:38:16 -070082 std::string* error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -050083
84 // InvalidateServerConfig clears the cached server config (if any).
85 void InvalidateServerConfig();
86
87 // SetProof stores a cert chain, cert signed timestamp and signature.
vasilvvc48c8712019-03-11 13:38:16 -070088 void SetProof(const std::vector<std::string>& certs,
QUICHE teama6ef0a62019-03-07 20:34:33 -050089 QuicStringPiece cert_sct,
90 QuicStringPiece chlo_hash,
91 QuicStringPiece signature);
92
93 // Clears all the data.
94 void Clear();
95
96 // Clears the certificate chain and signature and invalidates the proof.
97 void ClearProof();
98
99 // SetProofValid records that the certificate chain and signature have been
100 // validated and that it's safe to assume that the server is legitimate.
101 // (Note: this does not check the chain or signature.)
102 void SetProofValid();
103
104 // If the server config or the proof has changed then it needs to be
105 // revalidated. Helper function to keep server_config_valid_ and
106 // generation_counter_ in sync.
107 void SetProofInvalid();
108
vasilvvc48c8712019-03-11 13:38:16 -0700109 const std::string& server_config() const;
110 const std::string& source_address_token() const;
111 const std::vector<std::string>& certs() const;
112 const std::string& cert_sct() const;
113 const std::string& chlo_hash() const;
114 const std::string& signature() const;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500115 bool proof_valid() const;
116 uint64_t generation_counter() const;
117 const ProofVerifyDetails* proof_verify_details() const;
118
119 void set_source_address_token(QuicStringPiece token);
120
121 void set_cert_sct(QuicStringPiece cert_sct);
122
123 // Adds the connection ID to the queue of server-designated connection-ids.
124 void add_server_designated_connection_id(QuicConnectionId connection_id);
125
126 // If true, the crypto config contains at least one connection ID specified
127 // by the server, and the client should use one of these IDs when initiating
128 // the next connection.
129 bool has_server_designated_connection_id() const;
130
131 // This function should only be called when
132 // has_server_designated_connection_id is true. Returns the next
133 // connection_id specified by the server and removes it from the
134 // queue of ids.
135 QuicConnectionId GetNextServerDesignatedConnectionId();
136
137 // Adds the servernonce to the queue of server nonces.
vasilvvc48c8712019-03-11 13:38:16 -0700138 void add_server_nonce(const std::string& server_nonce);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500139
140 // If true, the crypto config contains at least one server nonce, and the
141 // client should use one of these nonces.
142 bool has_server_nonce() const;
143
144 // This function should only be called when has_server_nonce is true.
145 // Returns the next server_nonce specified by the server and removes it
146 // from the queue of nonces.
vasilvvc48c8712019-03-11 13:38:16 -0700147 std::string GetNextServerNonce();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500148
149 // SetProofVerifyDetails takes ownership of |details|.
150 void SetProofVerifyDetails(ProofVerifyDetails* details);
151
152 // Copy the |server_config_|, |source_address_token_|, |certs_|,
153 // |expiration_time_|, |cert_sct_|, |chlo_hash_| and |server_config_sig_|
154 // from the |other|. The remaining fields, |generation_counter_|,
155 // |proof_verify_details_|, and |scfg_| remain unchanged.
156 void InitializeFrom(const CachedState& other);
157
158 // Initializes this cached state based on the arguments provided.
159 // Returns false if there is a problem parsing the server config.
160 bool Initialize(QuicStringPiece server_config,
161 QuicStringPiece source_address_token,
vasilvvc48c8712019-03-11 13:38:16 -0700162 const std::vector<std::string>& certs,
163 const std::string& cert_sct,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500164 QuicStringPiece chlo_hash,
165 QuicStringPiece signature,
166 QuicWallTime now,
167 QuicWallTime expiration_time);
168
169 private:
vasilvvc48c8712019-03-11 13:38:16 -0700170 std::string server_config_; // A serialized handshake message.
171 std::string source_address_token_; // An opaque proof of IP ownership.
172 std::vector<std::string> certs_; // A list of certificates in leaf-first
173 // order.
174 std::string cert_sct_; // Signed timestamp of the leaf cert.
175 std::string chlo_hash_; // Hash of the CHLO message.
176 std::string server_config_sig_; // A signature of |server_config_|.
177 bool server_config_valid_; // True if |server_config_| is correctly
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178 // signed and |certs_| has been validated.
179 QuicWallTime expiration_time_; // Time when the config is no longer valid.
180 // Generation counter associated with the |server_config_|, |certs_| and
181 // |server_config_sig_| combination. It is incremented whenever we set
182 // server_config_valid_ to false.
183 uint64_t generation_counter_;
184
185 std::unique_ptr<ProofVerifyDetails> proof_verify_details_;
186
187 // scfg contains the cached, parsed value of |server_config|.
188 mutable std::unique_ptr<CryptoHandshakeMessage> scfg_;
189
190 // TODO(jokulik): Consider using a hash-set as extra book-keeping to ensure
191 // that no connection-id is added twice. Also, consider keeping the server
192 // nonces and connection_ids together in one queue.
193 QuicQueue<QuicConnectionId> server_designated_connection_ids_;
vasilvvc48c8712019-03-11 13:38:16 -0700194 QuicQueue<std::string> server_nonces_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500195 };
196
197 // Used to filter server ids for partial config deletion.
198 class ServerIdFilter {
199 public:
200 virtual ~ServerIdFilter() {}
201
202 // Returns true if |server_id| matches the filter.
203 virtual bool Matches(const QuicServerId& server_id) const = 0;
204 };
205
206 QuicCryptoClientConfig(std::unique_ptr<ProofVerifier> proof_verifier,
207 bssl::UniquePtr<SSL_CTX> ssl_ctx);
208 QuicCryptoClientConfig(const QuicCryptoClientConfig&) = delete;
209 QuicCryptoClientConfig& operator=(const QuicCryptoClientConfig&) = delete;
210 ~QuicCryptoClientConfig();
211
212 // LookupOrCreate returns a CachedState for the given |server_id|. If no such
213 // CachedState currently exists, it will be created and cached.
214 CachedState* LookupOrCreate(const QuicServerId& server_id);
215
216 // Delete CachedState objects whose server ids match |filter| from
217 // cached_states.
218 void ClearCachedStates(const ServerIdFilter& filter);
219
220 // FillInchoateClientHello sets |out| to be a CHLO message that elicits a
221 // source-address token or SCFG from a server. If |cached| is non-nullptr, the
222 // source-address token will be taken from it. |out_params| is used in order
223 // to store the cached certs that were sent as hints to the server in
224 // |out_params->cached_certs|. |preferred_version| is the version of the
225 // QUIC protocol that this client chose to use initially. This allows the
226 // server to detect downgrade attacks. If |demand_x509_proof| is true,
227 // then |out| will include an X509 proof demand, and the associated
228 // certificate related fields.
229 void FillInchoateClientHello(
230 const QuicServerId& server_id,
231 const ParsedQuicVersion preferred_version,
232 const CachedState* cached,
233 QuicRandom* rand,
234 bool demand_x509_proof,
235 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,
236 CryptoHandshakeMessage* out) const;
237
238 // FillClientHello sets |out| to be a CHLO message based on the configuration
239 // of this object. This object must have cached enough information about
240 // the server's hostname in order to perform a handshake. This can be checked
241 // with the |IsComplete| member of |CachedState|.
242 //
243 // |now| and |rand| are used to generate the nonce and |out_params| is
244 // filled with the results of the handshake that the server is expected to
245 // accept. |preferred_version| is the version of the QUIC protocol that this
246 // client chose to use initially. This allows the server to detect downgrade
247 // attacks.
248 //
249 // If |channel_id_key| is not null, it is used to sign a secret value derived
250 // from the client and server's keys, and the Channel ID public key and the
251 // signature are placed in the CETV value of the CHLO.
252 QuicErrorCode FillClientHello(
253 const QuicServerId& server_id,
254 QuicConnectionId connection_id,
255 const ParsedQuicVersion preferred_version,
256 const CachedState* cached,
257 QuicWallTime now,
258 QuicRandom* rand,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500259 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,
260 CryptoHandshakeMessage* out,
vasilvvc48c8712019-03-11 13:38:16 -0700261 std::string* error_details) const;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500262
263 // ProcessRejection processes a REJ message from a server and updates the
264 // cached information about that server. After this, |IsComplete| may return
265 // true for that server's CachedState. If the rejection message contains state
266 // about a future handshake (i.e. an nonce value from the server), then it
267 // will be saved in |out_params|. |now| is used to judge whether the server
268 // config in the rejection message has expired.
269 QuicErrorCode ProcessRejection(
270 const CryptoHandshakeMessage& rej,
271 QuicWallTime now,
272 QuicTransportVersion version,
273 QuicStringPiece chlo_hash,
274 CachedState* cached,
275 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,
vasilvvc48c8712019-03-11 13:38:16 -0700276 std::string* error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500277
278 // ProcessServerHello processes the message in |server_hello|, updates the
279 // cached information about that server, writes the negotiated parameters to
280 // |out_params| and returns QUIC_NO_ERROR. If |server_hello| is unacceptable
281 // then it puts an error message in |error_details| and returns an error
282 // code. |version| is the QUIC version for the current connection.
283 // |negotiated_versions| contains the list of version, if any, that were
bnce433f532019-04-16 13:05:27 -0700284 // present in a version negotiation packet previously received from the
QUICHE teama6ef0a62019-03-07 20:34:33 -0500285 // server. The contents of this list will be compared against the list of
286 // versions provided in the VER tag of the server hello.
287 QuicErrorCode ProcessServerHello(
288 const CryptoHandshakeMessage& server_hello,
289 QuicConnectionId connection_id,
290 ParsedQuicVersion version,
291 const ParsedQuicVersionVector& negotiated_versions,
292 CachedState* cached,
293 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,
vasilvvc48c8712019-03-11 13:38:16 -0700294 std::string* error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295
296 // Processes the message in |server_update|, updating the cached source
297 // address token, and server config.
298 // If |server_update| is invalid then |error_details| will contain an error
299 // message, and an error code will be returned. If all has gone well
300 // QUIC_NO_ERROR is returned.
301 QuicErrorCode ProcessServerConfigUpdate(
302 const CryptoHandshakeMessage& server_update,
303 QuicWallTime now,
304 const QuicTransportVersion version,
305 QuicStringPiece chlo_hash,
306 CachedState* cached,
307 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,
vasilvvc48c8712019-03-11 13:38:16 -0700308 std::string* error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500309
310 ProofVerifier* proof_verifier() const;
311
QUICHE teama6ef0a62019-03-07 20:34:33 -0500312 SSL_CTX* ssl_ctx() const;
313
QUICHE teama6ef0a62019-03-07 20:34:33 -0500314 // Initialize the CachedState from |canonical_crypto_config| for the
315 // |canonical_server_id| as the initial CachedState for |server_id|. We will
316 // copy config data only if |canonical_crypto_config| has valid proof.
317 void InitializeFrom(const QuicServerId& server_id,
318 const QuicServerId& canonical_server_id,
319 QuicCryptoClientConfig* canonical_crypto_config);
320
321 // Adds |suffix| as a domain suffix for which the server's crypto config
322 // is expected to be shared among servers with the domain suffix. If a server
323 // matches this suffix, then the server config from another server with the
324 // suffix will be used to initialize the cached state for this server.
vasilvvc48c8712019-03-11 13:38:16 -0700325 void AddCanonicalSuffix(const std::string& suffix);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500326
327 // Saves the |user_agent_id| that will be passed in QUIC's CHLO message.
vasilvvc48c8712019-03-11 13:38:16 -0700328 void set_user_agent_id(const std::string& user_agent_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329 user_agent_id_ = user_agent_id;
330 }
331
332 // Returns the user_agent_id that will be provided in the client hello
333 // handshake message.
vasilvvc48c8712019-03-11 13:38:16 -0700334 const std::string& user_agent_id() const { return user_agent_id_; }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500335
336 // Saves the |alpn| that will be passed in QUIC's CHLO message.
vasilvvc48c8712019-03-11 13:38:16 -0700337 void set_alpn(const std::string& alpn) { alpn_ = alpn; }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500338
339 void set_pre_shared_key(QuicStringPiece psk) {
vasilvvc48c8712019-03-11 13:38:16 -0700340 pre_shared_key_ = std::string(psk);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500341 }
342
343 bool pad_inchoate_hello() const { return pad_inchoate_hello_; }
344 void set_pad_inchoate_hello(bool new_value) {
345 pad_inchoate_hello_ = new_value;
346 }
347
348 bool pad_full_hello() const { return pad_full_hello_; }
349 void set_pad_full_hello(bool new_value) { pad_full_hello_ = new_value; }
350
351 private:
352 // Sets the members to reasonable, default values.
353 void SetDefaults();
354
355 // CacheNewServerConfig checks for SCFG, STK, PROF, and CRT tags in |message|,
356 // verifies them, and stores them in the cached state if they validate.
357 // This is used on receipt of a REJ from a server, or when a server sends
358 // updated server config during a connection.
359 QuicErrorCode CacheNewServerConfig(
360 const CryptoHandshakeMessage& message,
361 QuicWallTime now,
362 QuicTransportVersion version,
363 QuicStringPiece chlo_hash,
vasilvvc48c8712019-03-11 13:38:16 -0700364 const std::vector<std::string>& cached_certs,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500365 CachedState* cached,
vasilvvc48c8712019-03-11 13:38:16 -0700366 std::string* error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500367
368 // If the suffix of the hostname in |server_id| is in |canonical_suffixes_|,
369 // then populate |cached| with the canonical cached state from
370 // |canonical_server_map_| for that suffix. Returns true if |cached| is
371 // initialized with canonical cached state.
372 bool PopulateFromCanonicalConfig(const QuicServerId& server_id,
373 CachedState* cached);
374
375 // cached_states_ maps from the server_id to the cached information about
376 // that server.
377 std::map<QuicServerId, std::unique_ptr<CachedState>> cached_states_;
378
379 // Contains a map of servers which could share the same server config. Map
380 // from a canonical host suffix/port/scheme to a representative server with
381 // the canonical suffix, which has a plausible set of initial certificates
382 // (or at least server public key).
383 std::map<QuicServerId, QuicServerId> canonical_server_map_;
384
385 // Contains list of suffixes (for exmaple ".c.youtube.com",
386 // ".googlevideo.com") of canonical hostnames.
vasilvvc48c8712019-03-11 13:38:16 -0700387 std::vector<std::string> canonical_suffixes_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500388
389 std::unique_ptr<ProofVerifier> proof_verifier_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500390 bssl::UniquePtr<SSL_CTX> ssl_ctx_;
391
392 // The |user_agent_id_| passed in QUIC's CHLO message.
vasilvvc48c8712019-03-11 13:38:16 -0700393 std::string user_agent_id_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394
395 // The |alpn_| passed in QUIC's CHLO message.
vasilvvc48c8712019-03-11 13:38:16 -0700396 std::string alpn_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500397
398 // If non-empty, the client will operate in the pre-shared key mode by
399 // incorporating |pre_shared_key_| into the key schedule.
vasilvvc48c8712019-03-11 13:38:16 -0700400 std::string pre_shared_key_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500401
402 // In QUIC, technically, client hello should be fully padded.
403 // However, fully padding on slow network connection (e.g. 50kbps) can add
404 // 150ms latency to one roundtrip. Therefore, you can disable padding of
405 // individual messages. It is recommend to leave at least one message in
406 // each direction fully padded (e.g. full CHLO and SHLO), but if you know
407 // the lower-bound MTU, you don't need to pad all of them (keep in mind that
408 // it's not OK to do it according to the standard).
409 //
410 // Also, if you disable padding, you must disable (change) the
411 // anti-amplification protection. You should only do so if you have some
412 // other means of verifying the client.
413 bool pad_inchoate_hello_ = true;
414 bool pad_full_hello_ = true;
415};
416
417} // namespace quic
418
419#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_