OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_ | 5 #ifndef NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_ |
6 #define NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_ | 6 #define NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_ |
7 | 7 |
8 #include <map> | 8 #include <map> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
13 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
14 #include "net/base/net_export.h" | 14 #include "net/base/net_export.h" |
15 #include "net/quic/crypto/crypto_protocol.h" | 15 #include "net/quic/crypto/crypto_protocol.h" |
16 #include "net/quic/quic_protocol.h" | 16 #include "net/quic/quic_protocol.h" |
17 #include "net/quic/quic_time.h" | 17 #include "net/quic/quic_time.h" |
18 | 18 |
19 namespace net { | 19 namespace net { |
20 | 20 |
21 class CommonCertSet; | 21 class CommonCertSets; |
22 class KeyExchange; | 22 class KeyExchange; |
23 class ProofVerifier; | 23 class ProofVerifier; |
24 class QuicClock; | |
25 class QuicDecrypter; | 24 class QuicDecrypter; |
26 class QuicEncrypter; | 25 class QuicEncrypter; |
27 class QuicRandom; | 26 class QuicRandom; |
28 | 27 |
29 // An intermediate format of a handshake message that's convenient for a | 28 // An intermediate format of a handshake message that's convenient for a |
30 // CryptoFramer to serialize from or parse into. | 29 // CryptoFramer to serialize from or parse into. |
31 class NET_EXPORT_PRIVATE CryptoHandshakeMessage { | 30 class NET_EXPORT_PRIVATE CryptoHandshakeMessage { |
32 public: | 31 public: |
33 CryptoHandshakeMessage(); | 32 CryptoHandshakeMessage(); |
34 CryptoHandshakeMessage(const CryptoHandshakeMessage& other); | 33 CryptoHandshakeMessage(const CryptoHandshakeMessage& other); |
35 ~CryptoHandshakeMessage(); | 34 ~CryptoHandshakeMessage(); |
36 | 35 |
37 CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other); | 36 CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other); |
38 | 37 |
39 // Clears state. | 38 // Clears state. |
40 void Clear(); | 39 void Clear(); |
41 | 40 |
42 // GetSerialized returns the serialized form of this message and caches the | 41 // GetSerialized returns the serialized form of this message and caches the |
43 // result. Subsequently altering the message does not invalidate the cache. | 42 // result. Subsequently altering the message does not invalidate the cache. |
44 const QuicData& GetSerialized() const; | 43 const QuicData& GetSerialized() const; |
45 | 44 |
46 // SetValue sets an element with the given tag to the raw, memory contents of | 45 // SetValue sets an element with the given tag to the raw, memory contents of |
47 // |v|. | 46 // |v|. |
48 template<class T> void SetValue(CryptoTag tag, const T& v) { | 47 template<class T> void SetValue(QuicTag tag, const T& v) { |
49 tag_value_map_[tag] = std::string(reinterpret_cast<const char*>(&v), | 48 tag_value_map_[tag] = |
50 sizeof(v)); | 49 std::string(reinterpret_cast<const char*>(&v), sizeof(v)); |
51 } | 50 } |
52 | 51 |
53 // SetVector sets an element with the given tag to the raw contents of an | 52 // SetVector sets an element with the given tag to the raw contents of an |
54 // array of elements in |v|. | 53 // array of elements in |v|. |
55 template<class T> void SetVector(CryptoTag tag, const std::vector<T>& v) { | 54 template<class T> void SetVector(QuicTag tag, const std::vector<T>& v) { |
56 if (v.empty()) { | 55 if (v.empty()) { |
57 tag_value_map_[tag] = std::string(); | 56 tag_value_map_[tag] = std::string(); |
58 } else { | 57 } else { |
59 tag_value_map_[tag] = std::string(reinterpret_cast<const char*>(&v[0]), | 58 tag_value_map_[tag] = std::string(reinterpret_cast<const char*>(&v[0]), |
60 v.size() * sizeof(T)); | 59 v.size() * sizeof(T)); |
61 } | 60 } |
62 } | 61 } |
63 | 62 |
64 // Returns the message tag. | 63 // Returns the message tag. |
65 CryptoTag tag() const { return tag_; } | 64 QuicTag tag() const { return tag_; } |
66 // Sets the message tag. | 65 // Sets the message tag. |
67 void set_tag(CryptoTag tag) { tag_ = tag; } | 66 void set_tag(QuicTag tag) { tag_ = tag; } |
68 | 67 |
69 const CryptoTagValueMap& tag_value_map() const { return tag_value_map_; } | 68 const QuicTagValueMap& tag_value_map() const { return tag_value_map_; } |
70 | 69 |
71 void Insert(CryptoTagValueMap::const_iterator begin, | 70 void Insert(QuicTagValueMap::const_iterator begin, |
72 CryptoTagValueMap::const_iterator end); | 71 QuicTagValueMap::const_iterator end); |
73 | 72 |
74 // SetTaglist sets an element with the given tag to contain a list of tags, | 73 // SetTaglist sets an element with the given tag to contain a list of tags, |
75 // passed as varargs. The argument list must be terminated with a 0 element. | 74 // passed as varargs. The argument list must be terminated with a 0 element. |
76 void SetTaglist(CryptoTag tag, ...); | 75 void SetTaglist(QuicTag tag, ...); |
77 | 76 |
78 void SetStringPiece(CryptoTag tag, base::StringPiece value); | 77 void SetStringPiece(QuicTag tag, base::StringPiece value); |
79 | 78 |
80 // GetTaglist finds an element with the given tag containing zero or more | 79 // GetTaglist finds an element with the given tag containing zero or more |
81 // tags. If such a tag doesn't exist, it returns false. Otherwise it sets | 80 // tags. If such a tag doesn't exist, it returns false. Otherwise it sets |
82 // |out_tags| and |out_len| to point to the array of tags and returns true. | 81 // |out_tags| and |out_len| to point to the array of tags and returns true. |
83 // The array points into the CryptoHandshakeMessage and is valid only for as | 82 // The array points into the CryptoHandshakeMessage and is valid only for as |
84 // long as the CryptoHandshakeMessage exists and is not modified. | 83 // long as the CryptoHandshakeMessage exists and is not modified. |
85 QuicErrorCode GetTaglist(CryptoTag tag, const CryptoTag** out_tags, | 84 QuicErrorCode GetTaglist(QuicTag tag, const QuicTag** out_tags, |
86 size_t* out_len) const; | 85 size_t* out_len) const; |
87 | 86 |
88 bool GetStringPiece(CryptoTag tag, base::StringPiece* out) const; | 87 bool GetStringPiece(QuicTag tag, base::StringPiece* out) const; |
89 | 88 |
90 // GetNthValue16 interprets the value with the given tag to be a series of | 89 // GetNthValue24 interprets the value with the given tag to be a series of |
91 // 16-bit length prefixed values and it returns the subvalue with the given | 90 // 24-bit, length prefixed values and it returns the subvalue with the given |
92 // index. | 91 // index. |
93 QuicErrorCode GetNthValue16(CryptoTag tag, | 92 QuicErrorCode GetNthValue24(QuicTag tag, |
94 unsigned index, | 93 unsigned index, |
95 base::StringPiece* out) const; | 94 base::StringPiece* out) const; |
96 bool GetString(CryptoTag tag, std::string* out) const; | 95 bool GetString(QuicTag tag, std::string* out) const; |
97 QuicErrorCode GetUint16(CryptoTag tag, uint16* out) const; | 96 QuicErrorCode GetUint16(QuicTag tag, uint16* out) const; |
98 QuicErrorCode GetUint32(CryptoTag tag, uint32* out) const; | 97 QuicErrorCode GetUint32(QuicTag tag, uint32* out) const; |
| 98 QuicErrorCode GetUint64(QuicTag tag, uint64* out) const; |
99 | 99 |
100 // DebugString returns a multi-line, string representation of the message | 100 // DebugString returns a multi-line, string representation of the message |
101 // suitable for including in debug output. | 101 // suitable for including in debug output. |
102 std::string DebugString() const; | 102 std::string DebugString() const; |
103 | 103 |
104 private: | 104 private: |
105 // GetPOD is a utility function for extracting a plain-old-data value. If | 105 // GetPOD is a utility function for extracting a plain-old-data value. If |
106 // |tag| exists in the message, and has a value of exactly |len| bytes then | 106 // |tag| exists in the message, and has a value of exactly |len| bytes then |
107 // it copies |len| bytes of data into |out|. Otherwise |len| bytes at |out| | 107 // it copies |len| bytes of data into |out|. Otherwise |len| bytes at |out| |
108 // are zeroed out. | 108 // are zeroed out. |
109 // | 109 // |
110 // If used to copy integers then this assumes that the machine is | 110 // If used to copy integers then this assumes that the machine is |
111 // little-endian. | 111 // little-endian. |
112 QuicErrorCode GetPOD(CryptoTag tag, void* out, size_t len) const; | 112 QuicErrorCode GetPOD(QuicTag tag, void* out, size_t len) const; |
113 | 113 |
114 std::string DebugStringInternal(size_t indent) const; | 114 std::string DebugStringInternal(size_t indent) const; |
115 | 115 |
116 CryptoTag tag_; | 116 QuicTag tag_; |
117 CryptoTagValueMap tag_value_map_; | 117 QuicTagValueMap tag_value_map_; |
118 | 118 |
119 // The serialized form of the handshake message. This member is constructed | 119 // The serialized form of the handshake message. This member is constructed |
120 // lasily. | 120 // lasily. |
121 mutable scoped_ptr<QuicData> serialized_; | 121 mutable scoped_ptr<QuicData> serialized_; |
122 }; | 122 }; |
123 | 123 |
| 124 // A CrypterPair contains the encrypter and decrypter for an encryption level. |
| 125 struct NET_EXPORT_PRIVATE CrypterPair { |
| 126 CrypterPair(); |
| 127 ~CrypterPair(); |
| 128 scoped_ptr<QuicEncrypter> encrypter; |
| 129 scoped_ptr<QuicDecrypter> decrypter; |
| 130 }; |
| 131 |
124 // Parameters negotiated by the crypto handshake. | 132 // Parameters negotiated by the crypto handshake. |
125 struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters { | 133 struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters { |
126 // Initializes the members to 0 or empty values. | 134 // Initializes the members to 0 or empty values. |
127 QuicCryptoNegotiatedParameters(); | 135 QuicCryptoNegotiatedParameters(); |
128 ~QuicCryptoNegotiatedParameters(); | 136 ~QuicCryptoNegotiatedParameters(); |
129 | 137 |
130 uint16 version; | 138 uint16 version; |
131 CryptoTag key_exchange; | 139 QuicTag key_exchange; |
132 CryptoTag aead; | 140 QuicTag aead; |
133 std::string premaster_secret; | 141 std::string initial_premaster_secret; |
134 scoped_ptr<QuicEncrypter> encrypter; | 142 std::string forward_secure_premaster_secret; |
135 scoped_ptr<QuicDecrypter> decrypter; | 143 CrypterPair initial_crypters; |
| 144 CrypterPair forward_secure_crypters; |
136 std::string server_config_id; | 145 std::string server_config_id; |
| 146 std::string client_nonce; |
137 std::string server_nonce; | 147 std::string server_nonce; |
| 148 // hkdf_input_suffix contains the HKDF input following the label: the GUID, |
| 149 // client hello and server config. This is only populated in the client |
| 150 // because only the client needs to derive the forward secure keys at a later |
| 151 // time from the initial keys. |
| 152 std::string hkdf_input_suffix; |
138 // cached_certs contains the cached certificates that a client used when | 153 // cached_certs contains the cached certificates that a client used when |
139 // sending a client hello. | 154 // sending a client hello. |
140 std::vector<std::string> cached_certs; | 155 std::vector<std::string> cached_certs; |
| 156 // client_key_exchange is used by clients to store the ephemeral KeyExchange |
| 157 // for the connection. |
| 158 scoped_ptr<KeyExchange> client_key_exchange; |
141 }; | 159 }; |
142 | 160 |
143 // QuicCryptoConfig contains common configuration between clients and servers. | 161 // QuicCryptoConfig contains common configuration between clients and servers. |
144 class NET_EXPORT_PRIVATE QuicCryptoConfig { | 162 class NET_EXPORT_PRIVATE QuicCryptoConfig { |
145 public: | 163 public: |
146 enum { | 164 enum { |
147 // CONFIG_VERSION is the one (and, for the moment, only) version number that | 165 // CONFIG_VERSION is the one (and, for the moment, only) version number that |
148 // we implement. | 166 // we implement. |
149 CONFIG_VERSION = 0, | 167 CONFIG_VERSION = 0, |
150 }; | 168 }; |
151 | 169 |
152 // kLabel is constant that is used in key derivation to tie the resulting key | 170 // kInitialLabel is a constant that is used when deriving the initial |
153 // to this protocol. | 171 // (non-forward secure) keys for the connection in order to tie the resulting |
154 static const char kLabel[]; | 172 // key to this protocol. |
| 173 static const char kInitialLabel[]; |
| 174 |
| 175 // kForwardSecureLabel is a constant that is used when deriving the forward |
| 176 // secure keys for the connection in order to tie the resulting key to this |
| 177 // protocol. |
| 178 static const char kForwardSecureLabel[]; |
155 | 179 |
156 QuicCryptoConfig(); | 180 QuicCryptoConfig(); |
157 ~QuicCryptoConfig(); | 181 ~QuicCryptoConfig(); |
158 | 182 |
159 // Protocol version | 183 // Protocol version |
160 uint16 version; | 184 uint16 version; |
161 // Key exchange methods. The following two members' values correspond by | 185 // Key exchange methods. The following two members' values correspond by |
162 // index. | 186 // index. |
163 CryptoTagVector kexs; | 187 QuicTagVector kexs; |
164 // Authenticated encryption with associated data (AEAD) algorithms. | 188 // Authenticated encryption with associated data (AEAD) algorithms. |
165 CryptoTagVector aead; | 189 QuicTagVector aead; |
166 | 190 |
167 scoped_ptr<CommonCertSet> common_cert_set_; | 191 scoped_ptr<CommonCertSets> common_cert_set_; |
168 | 192 |
169 private: | 193 private: |
170 DISALLOW_COPY_AND_ASSIGN(QuicCryptoConfig); | 194 DISALLOW_COPY_AND_ASSIGN(QuicCryptoConfig); |
171 }; | 195 }; |
172 | 196 |
173 // QuicCryptoClientConfig contains crypto-related configuration settings for a | 197 // QuicCryptoClientConfig contains crypto-related configuration settings for a |
174 // client. Note that this object isn't thread-safe. It's designed to be used on | 198 // client. Note that this object isn't thread-safe. It's designed to be used on |
175 // a single thread at a time. | 199 // a single thread at a time. |
176 class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { | 200 class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { |
177 public: | 201 public: |
(...skipping 30 matching lines...) Expand all Loading... |
208 | 232 |
209 const std::string& server_config() const; | 233 const std::string& server_config() const; |
210 const std::string& source_address_token() const; | 234 const std::string& source_address_token() const; |
211 const std::vector<std::string>& certs() const; | 235 const std::vector<std::string>& certs() const; |
212 const std::string& signature() const; | 236 const std::string& signature() const; |
213 bool proof_valid() const; | 237 bool proof_valid() const; |
214 | 238 |
215 void set_source_address_token(base::StringPiece token); | 239 void set_source_address_token(base::StringPiece token); |
216 | 240 |
217 private: | 241 private: |
218 std::string server_config_id_; // An opaque id from the server. | 242 std::string server_config_id_; // An opaque id from the server. |
219 std::string server_config_; // A serialized handshake message. | 243 std::string server_config_; // A serialized handshake message. |
220 std::string source_address_token_; // An opaque proof of IP ownership. | 244 std::string source_address_token_; // An opaque proof of IP ownership. |
221 std::vector<std::string> certs_; // A list of certificates in leaf-first | 245 std::vector<std::string> certs_; // A list of certificates in leaf-first |
222 // order. | 246 // order. |
223 std::string server_config_sig_; // A signature of |server_config_|. | 247 std::string server_config_sig_; // A signature of |server_config_|. |
224 bool server_config_valid_; // true if |server_config_| is correctly signed | 248 bool server_config_valid_; // true if |server_config_| is correctly signed |
225 // and |certs_| has been validated. | 249 // and |certs_| has been validated. |
226 | 250 |
227 // scfg contains the cached, parsed value of |server_config|. | 251 // scfg contains the cached, parsed value of |server_config|. |
228 mutable scoped_ptr<CryptoHandshakeMessage> scfg_; | 252 mutable scoped_ptr<CryptoHandshakeMessage> scfg_; |
229 }; | 253 }; |
230 | 254 |
231 QuicCryptoClientConfig(); | 255 QuicCryptoClientConfig(); |
232 ~QuicCryptoClientConfig(); | 256 ~QuicCryptoClientConfig(); |
233 | 257 |
234 // Sets the members to reasonable, default values. | 258 // Sets the members to reasonable, default values. |
235 void SetDefaults(); | 259 void SetDefaults(); |
236 | 260 |
237 // LookupOrCreate returns a CachedState for the given hostname. If no such | 261 // LookupOrCreate returns a CachedState for the given hostname. If no such |
238 // CachedState currently exists, it will be created and cached. | 262 // CachedState currently exists, it will be created and cached. |
239 CachedState* LookupOrCreate(const std::string& server_hostname); | 263 CachedState* LookupOrCreate(const std::string& server_hostname); |
240 | 264 |
241 // FillInchoateClientHello sets |out| to be a CHLO message that elicits a | 265 // FillInchoateClientHello sets |out| to be a CHLO message that elicits a |
242 // source-address token or SCFG from a server. If |cached| is non-NULL, the | 266 // source-address token or SCFG from a server. If |cached| is non-NULL, the |
243 // source-address token will be taken from it. | 267 // source-address token will be taken from it. |out_params| is used in order |
| 268 // to store the cached certs that were sent as hints to the server in |
| 269 // |out_params->cached_certs|. |
244 void FillInchoateClientHello(const std::string& server_hostname, | 270 void FillInchoateClientHello(const std::string& server_hostname, |
245 const CachedState* cached, | 271 const CachedState* cached, |
246 QuicCryptoNegotiatedParameters* out_params, | 272 QuicCryptoNegotiatedParameters* out_params, |
247 CryptoHandshakeMessage* out) const; | 273 CryptoHandshakeMessage* out) const; |
248 | 274 |
249 // FillClientHello sets |out| to be a CHLO message based on the configuration | 275 // FillClientHello sets |out| to be a CHLO message based on the configuration |
250 // of this object. This object must have cached enough information about | 276 // of this object. This object must have cached enough information about |
251 // |server_hostname| in order to perform a handshake. This can be checked | 277 // |server_hostname| in order to perform a handshake. This can be checked |
252 // with the |is_complete| member of |CachedState|. | 278 // with the |is_complete| member of |CachedState|. |
253 // | 279 // |
254 // |clock| and |rand| are used to generate the nonce and |out_params| is | 280 // |clock| and |rand| are used to generate the nonce and |out_params| is |
255 // filled with the results of the handshake that the server is expected to | 281 // filled with the results of the handshake that the server is expected to |
256 // accept. | 282 // accept. |
257 QuicErrorCode FillClientHello(const std::string& server_hostname, | 283 QuicErrorCode FillClientHello(const std::string& server_hostname, |
258 QuicGuid guid, | 284 QuicGuid guid, |
259 const CachedState* cached, | 285 const CachedState* cached, |
260 const QuicClock* clock, | 286 QuicWallTime now, |
261 QuicRandom* rand, | 287 QuicRandom* rand, |
262 QuicCryptoNegotiatedParameters* out_params, | 288 QuicCryptoNegotiatedParameters* out_params, |
263 CryptoHandshakeMessage* out, | 289 CryptoHandshakeMessage* out, |
264 std::string* error_details) const; | 290 std::string* error_details) const; |
265 | 291 |
266 // ProcessRejection processes a REJ message from a server and updates the | 292 // ProcessRejection processes a REJ message from a server and updates the |
267 // cached information about that server. After this, |is_complete| may return | 293 // cached information about that server. After this, |is_complete| may return |
268 // true for that server's CachedState. If the rejection message contains | 294 // true for that server's CachedState. If the rejection message contains |
269 // state about a future handshake (i.e. an nonce value from the server), then | 295 // state about a future handshake (i.e. an nonce value from the server), then |
270 // it will be saved in |out_params|. | 296 // it will be saved in |out_params|. |
271 QuicErrorCode ProcessRejection(CachedState* cached, | 297 QuicErrorCode ProcessRejection(CachedState* cached, |
272 const CryptoHandshakeMessage& rej, | 298 const CryptoHandshakeMessage& rej, |
273 QuicCryptoNegotiatedParameters* out_params, | 299 QuicCryptoNegotiatedParameters* out_params, |
274 std::string* error_details); | 300 std::string* error_details); |
275 | 301 |
276 // ProcessServerHello processes the message in |server_hello|, writes the | 302 // ProcessServerHello processes the message in |server_hello|, writes the |
277 // negotiated parameters to |out_params| and returns QUIC_NO_ERROR. If | 303 // negotiated parameters to |out_params| and returns QUIC_NO_ERROR. If |
278 // |server_hello| is unacceptable then it puts an error message in | 304 // |server_hello| is unacceptable then it puts an error message in |
279 // |error_details| and returns an error code. | 305 // |error_details| and returns an error code. |
280 QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello, | 306 QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello, |
281 const std::string& nonce, | 307 QuicGuid guid, |
282 QuicCryptoNegotiatedParameters* out_params, | 308 QuicCryptoNegotiatedParameters* out_params, |
283 std::string* error_details); | 309 std::string* error_details); |
284 | 310 |
285 const ProofVerifier* proof_verifier() const; | 311 const ProofVerifier* proof_verifier() const; |
286 | 312 |
287 // SetProofVerifier takes ownership of a |ProofVerifier| that clients are | 313 // SetProofVerifier takes ownership of a |ProofVerifier| that clients are |
288 // free to use in order to verify certificate chains from servers. Setting a | 314 // free to use in order to verify certificate chains from servers. Setting a |
289 // |ProofVerifier| does not alter the behaviour of the | 315 // |ProofVerifier| does not alter the behaviour of the |
290 // QuicCryptoClientConfig, it's just a place to store it. | 316 // QuicCryptoClientConfig, it's just a place to store it. |
291 void SetProofVerifier(ProofVerifier* verifier); | 317 void SetProofVerifier(ProofVerifier* verifier); |
292 | 318 |
293 private: | 319 private: |
294 // cached_states_ maps from the server hostname to the cached information | 320 // cached_states_ maps from the server hostname to the cached information |
295 // about that server. | 321 // about that server. |
296 std::map<std::string, CachedState*> cached_states_; | 322 std::map<std::string, CachedState*> cached_states_; |
297 | 323 |
298 scoped_ptr<ProofVerifier> proof_verifier_; | 324 scoped_ptr<ProofVerifier> proof_verifier_; |
299 | 325 |
300 DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientConfig); | 326 DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientConfig); |
301 }; | 327 }; |
302 | 328 |
303 } // namespace net | 329 } // namespace net |
304 | 330 |
305 #endif // NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_ | 331 #endif // NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_ |
OLD | NEW |