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 #include "net/quic/crypto/crypto_handshake.h" | 5 #include "net/quic/crypto/crypto_handshake.h" |
6 | 6 |
7 #include <ctype.h> | 7 #include <ctype.h> |
8 | 8 |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/string_split.h" | 12 #include "base/strings/string_split.h" |
13 #include "crypto/secure_hash.h" | 13 #include "crypto/secure_hash.h" |
14 #include "net/base/net_util.h" | 14 #include "net/base/net_util.h" |
15 #include "net/quic/crypto/cert_compressor.h" | 15 #include "net/quic/crypto/cert_compressor.h" |
16 #include "net/quic/crypto/common_cert_set.h" | 16 #include "net/quic/crypto/common_cert_set.h" |
17 #include "net/quic/crypto/crypto_framer.h" | 17 #include "net/quic/crypto/crypto_framer.h" |
18 #include "net/quic/crypto/crypto_utils.h" | 18 #include "net/quic/crypto/crypto_utils.h" |
19 #include "net/quic/crypto/curve25519_key_exchange.h" | 19 #include "net/quic/crypto/curve25519_key_exchange.h" |
20 #include "net/quic/crypto/key_exchange.h" | 20 #include "net/quic/crypto/key_exchange.h" |
21 #include "net/quic/crypto/p256_key_exchange.h" | 21 #include "net/quic/crypto/p256_key_exchange.h" |
22 #include "net/quic/crypto/proof_verifier.h" | 22 #include "net/quic/crypto/proof_verifier.h" |
23 #include "net/quic/crypto/quic_decrypter.h" | 23 #include "net/quic/crypto/quic_decrypter.h" |
24 #include "net/quic/crypto/quic_encrypter.h" | 24 #include "net/quic/crypto/quic_encrypter.h" |
25 #include "net/quic/crypto/quic_random.h" | 25 #include "net/quic/crypto/quic_random.h" |
26 #include "net/quic/quic_clock.h" | |
27 #include "net/quic/quic_protocol.h" | 26 #include "net/quic/quic_protocol.h" |
28 #include "net/quic/quic_utils.h" | 27 #include "net/quic/quic_utils.h" |
29 | 28 |
30 using base::StringPiece; | 29 using base::StringPiece; |
31 using std::map; | 30 using std::map; |
32 using std::string; | 31 using std::string; |
33 using std::vector; | 32 using std::vector; |
34 | 33 |
35 namespace net { | 34 namespace net { |
36 | 35 |
(...skipping 25 matching lines...) Expand all Loading... |
62 serialized_.reset(); | 61 serialized_.reset(); |
63 } | 62 } |
64 | 63 |
65 const QuicData& CryptoHandshakeMessage::GetSerialized() const { | 64 const QuicData& CryptoHandshakeMessage::GetSerialized() const { |
66 if (!serialized_.get()) { | 65 if (!serialized_.get()) { |
67 serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this)); | 66 serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this)); |
68 } | 67 } |
69 return *serialized_.get(); | 68 return *serialized_.get(); |
70 } | 69 } |
71 | 70 |
72 void CryptoHandshakeMessage::Insert(CryptoTagValueMap::const_iterator begin, | 71 void CryptoHandshakeMessage::Insert(QuicTagValueMap::const_iterator begin, |
73 CryptoTagValueMap::const_iterator end) { | 72 QuicTagValueMap::const_iterator end) { |
74 tag_value_map_.insert(begin, end); | 73 tag_value_map_.insert(begin, end); |
75 } | 74 } |
76 | 75 |
77 void CryptoHandshakeMessage::SetTaglist(CryptoTag tag, ...) { | 76 void CryptoHandshakeMessage::SetTaglist(QuicTag tag, ...) { |
78 // Warning, if sizeof(CryptoTag) > sizeof(int) then this function will break | 77 // Warning, if sizeof(QuicTag) > sizeof(int) then this function will break |
79 // because the terminating 0 will only be promoted to int. | 78 // because the terminating 0 will only be promoted to int. |
80 COMPILE_ASSERT(sizeof(CryptoTag) <= sizeof(int), | 79 COMPILE_ASSERT(sizeof(QuicTag) <= sizeof(int), |
81 crypto_tag_not_be_larger_than_int_or_varargs_will_break); | 80 crypto_tag_not_be_larger_than_int_or_varargs_will_break); |
82 | 81 |
83 vector<CryptoTag> tags; | 82 vector<QuicTag> tags; |
84 va_list ap; | 83 va_list ap; |
85 | 84 |
86 va_start(ap, tag); | 85 va_start(ap, tag); |
87 for (;;) { | 86 for (;;) { |
88 CryptoTag list_item = va_arg(ap, CryptoTag); | 87 QuicTag list_item = va_arg(ap, QuicTag); |
89 if (list_item == 0) { | 88 if (list_item == 0) { |
90 break; | 89 break; |
91 } | 90 } |
92 tags.push_back(list_item); | 91 tags.push_back(list_item); |
93 } | 92 } |
94 | 93 |
95 // Because of the way that we keep tags in memory, we can copy the contents | 94 // Because of the way that we keep tags in memory, we can copy the contents |
96 // of the vector and get the correct bytes in wire format. See | 95 // of the vector and get the correct bytes in wire format. See |
97 // crypto_protocol.h. This assumes that the system is little-endian. | 96 // crypto_protocol.h. This assumes that the system is little-endian. |
98 SetVector(tag, tags); | 97 SetVector(tag, tags); |
99 | 98 |
100 va_end(ap); | 99 va_end(ap); |
101 } | 100 } |
102 | 101 |
103 void CryptoHandshakeMessage::SetStringPiece(CryptoTag tag, StringPiece value) { | 102 void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) { |
104 tag_value_map_[tag] = value.as_string(); | 103 tag_value_map_[tag] = value.as_string(); |
105 } | 104 } |
106 | 105 |
107 QuicErrorCode CryptoHandshakeMessage::GetTaglist(CryptoTag tag, | 106 QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag, |
108 const CryptoTag** out_tags, | 107 const QuicTag** out_tags, |
109 size_t* out_len) const { | 108 size_t* out_len) const { |
110 CryptoTagValueMap::const_iterator it = tag_value_map_.find(tag); | 109 QuicTagValueMap::const_iterator it = tag_value_map_.find(tag); |
111 *out_len = 0; | 110 *out_len = 0; |
112 QuicErrorCode ret = QUIC_NO_ERROR; | 111 QuicErrorCode ret = QUIC_NO_ERROR; |
113 | 112 |
114 if (it == tag_value_map_.end()) { | 113 if (it == tag_value_map_.end()) { |
115 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 114 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
116 } else if (it->second.size() % sizeof(CryptoTag) != 0) { | 115 } else if (it->second.size() % sizeof(QuicTag) != 0) { |
117 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 116 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
118 } | 117 } |
119 | 118 |
120 if (ret != QUIC_NO_ERROR) { | 119 if (ret != QUIC_NO_ERROR) { |
121 *out_tags = NULL; | 120 *out_tags = NULL; |
122 *out_len = 0; | 121 *out_len = 0; |
123 return ret; | 122 return ret; |
124 } | 123 } |
125 | 124 |
126 *out_tags = reinterpret_cast<const CryptoTag*>(it->second.data()); | 125 *out_tags = reinterpret_cast<const QuicTag*>(it->second.data()); |
127 *out_len = it->second.size() / sizeof(CryptoTag); | 126 *out_len = it->second.size() / sizeof(QuicTag); |
128 return ret; | 127 return ret; |
129 } | 128 } |
130 | 129 |
131 bool CryptoHandshakeMessage::GetStringPiece(CryptoTag tag, | 130 bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag, |
132 StringPiece* out) const { | 131 StringPiece* out) const { |
133 CryptoTagValueMap::const_iterator it = tag_value_map_.find(tag); | 132 QuicTagValueMap::const_iterator it = tag_value_map_.find(tag); |
134 if (it == tag_value_map_.end()) { | 133 if (it == tag_value_map_.end()) { |
135 return false; | 134 return false; |
136 } | 135 } |
137 *out = it->second; | 136 *out = it->second; |
138 return true; | 137 return true; |
139 } | 138 } |
140 | 139 |
141 QuicErrorCode CryptoHandshakeMessage::GetNthValue16(CryptoTag tag, | 140 QuicErrorCode CryptoHandshakeMessage::GetNthValue24(QuicTag tag, |
142 unsigned index, | 141 unsigned index, |
143 StringPiece* out) const { | 142 StringPiece* out) const { |
144 StringPiece value; | 143 StringPiece value; |
145 if (!GetStringPiece(tag, &value)) { | 144 if (!GetStringPiece(tag, &value)) { |
146 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 145 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
147 } | 146 } |
148 | 147 |
149 for (unsigned i = 0;; i++) { | 148 for (unsigned i = 0;; i++) { |
150 if (value.empty()) { | 149 if (value.empty()) { |
151 return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND; | 150 return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND; |
152 } | 151 } |
153 if (value.size() < 2) { | 152 if (value.size() < 3) { |
154 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 153 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
155 } | 154 } |
156 | 155 |
157 const unsigned char* data = | 156 const unsigned char* data = |
158 reinterpret_cast<const unsigned char*>(value.data()); | 157 reinterpret_cast<const unsigned char*>(value.data()); |
159 size_t size = static_cast<size_t>(data[0]) | | 158 size_t size = static_cast<size_t>(data[0]) | |
160 (static_cast<size_t>(data[1]) << 8); | 159 (static_cast<size_t>(data[1]) << 8) | |
161 value.remove_prefix(2); | 160 (static_cast<size_t>(data[2]) << 16); |
| 161 value.remove_prefix(3); |
162 | 162 |
163 if (value.size() < size) { | 163 if (value.size() < size) { |
164 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 164 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
165 } | 165 } |
166 | 166 |
167 if (i == index) { | 167 if (i == index) { |
168 *out = StringPiece(value.data(), size); | 168 *out = StringPiece(value.data(), size); |
169 return QUIC_NO_ERROR; | 169 return QUIC_NO_ERROR; |
170 } | 170 } |
171 | 171 |
172 value.remove_prefix(size); | 172 value.remove_prefix(size); |
173 } | 173 } |
174 } | 174 } |
175 | 175 |
176 bool CryptoHandshakeMessage::GetString(CryptoTag tag, string* out) const { | 176 bool CryptoHandshakeMessage::GetString(QuicTag tag, string* out) const { |
177 CryptoTagValueMap::const_iterator it = tag_value_map_.find(tag); | 177 QuicTagValueMap::const_iterator it = tag_value_map_.find(tag); |
178 if (it == tag_value_map_.end()) { | 178 if (it == tag_value_map_.end()) { |
179 return false; | 179 return false; |
180 } | 180 } |
181 *out = it->second; | 181 *out = it->second; |
182 return true; | 182 return true; |
183 } | 183 } |
184 | 184 |
185 QuicErrorCode CryptoHandshakeMessage::GetUint16(CryptoTag tag, | 185 QuicErrorCode CryptoHandshakeMessage::GetUint16(QuicTag tag, |
186 uint16* out) const { | 186 uint16* out) const { |
187 return GetPOD(tag, out, sizeof(uint16)); | 187 return GetPOD(tag, out, sizeof(uint16)); |
188 } | 188 } |
189 | 189 |
190 QuicErrorCode CryptoHandshakeMessage::GetUint32(CryptoTag tag, | 190 QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag, |
191 uint32* out) const { | 191 uint32* out) const { |
192 return GetPOD(tag, out, sizeof(uint32)); | 192 return GetPOD(tag, out, sizeof(uint32)); |
193 } | 193 } |
194 | 194 |
| 195 QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag, |
| 196 uint64* out) const { |
| 197 return GetPOD(tag, out, sizeof(uint64)); |
| 198 } |
| 199 |
195 string CryptoHandshakeMessage::DebugString() const { | 200 string CryptoHandshakeMessage::DebugString() const { |
196 return DebugStringInternal(0); | 201 return DebugStringInternal(0); |
197 } | 202 } |
198 | 203 |
199 QuicErrorCode CryptoHandshakeMessage::GetPOD( | 204 QuicErrorCode CryptoHandshakeMessage::GetPOD( |
200 CryptoTag tag, void* out, size_t len) const { | 205 QuicTag tag, void* out, size_t len) const { |
201 CryptoTagValueMap::const_iterator it = tag_value_map_.find(tag); | 206 QuicTagValueMap::const_iterator it = tag_value_map_.find(tag); |
202 QuicErrorCode ret = QUIC_NO_ERROR; | 207 QuicErrorCode ret = QUIC_NO_ERROR; |
203 | 208 |
204 if (it == tag_value_map_.end()) { | 209 if (it == tag_value_map_.end()) { |
205 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 210 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
206 } else if (it->second.size() != len) { | 211 } else if (it->second.size() != len) { |
207 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 212 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
208 } | 213 } |
209 | 214 |
210 if (ret != QUIC_NO_ERROR) { | 215 if (ret != QUIC_NO_ERROR) { |
211 memset(out, 0, len); | 216 memset(out, 0, len); |
212 return ret; | 217 return ret; |
213 } | 218 } |
214 | 219 |
215 memcpy(out, it->second.data(), len); | 220 memcpy(out, it->second.data(), len); |
216 return ret; | 221 return ret; |
217 } | 222 } |
218 | 223 |
219 // TagToString is a utility function for pretty-printing handshake messages | 224 // TagToString is a utility function for pretty-printing handshake messages |
220 // that converts a tag to a string. It will try to maintain the human friendly | 225 // that converts a tag to a string. It will try to maintain the human friendly |
221 // name if possible (i.e. kABCD -> "ABCD"), or will just treat it as a number | 226 // name if possible (i.e. kABCD -> "ABCD"), or will just treat it as a number |
222 // if not. | 227 // if not. |
223 static string TagToString(CryptoTag tag) { | 228 static string TagToString(QuicTag tag) { |
224 char chars[4]; | 229 char chars[4]; |
225 bool ascii = true; | 230 bool ascii = true; |
226 const CryptoTag orig_tag = tag; | 231 const QuicTag orig_tag = tag; |
227 | 232 |
228 for (size_t i = 0; i < sizeof(chars); i++) { | 233 for (size_t i = 0; i < sizeof(chars); i++) { |
229 chars[i] = tag; | 234 chars[i] = tag; |
230 if (chars[i] == 0 && i == 3) { | 235 if (chars[i] == 0 && i == 3) { |
231 chars[i] = ' '; | 236 chars[i] = ' '; |
232 } | 237 } |
233 if (!isprint(static_cast<unsigned char>(chars[i]))) { | 238 if (!isprint(static_cast<unsigned char>(chars[i]))) { |
234 ascii = false; | 239 ascii = false; |
235 break; | 240 break; |
236 } | 241 } |
237 tag >>= 8; | 242 tag >>= 8; |
238 } | 243 } |
239 | 244 |
240 if (ascii) { | 245 if (ascii) { |
241 return string(chars, sizeof(chars)); | 246 return string(chars, sizeof(chars)); |
242 } | 247 } |
243 | 248 |
244 return base::UintToString(orig_tag); | 249 return base::UintToString(orig_tag); |
245 } | 250 } |
246 | 251 |
247 string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { | 252 string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { |
248 string ret = string(2 * indent, ' ') + TagToString(tag_) + "<\n"; | 253 string ret = string(2 * indent, ' ') + TagToString(tag_) + "<\n"; |
249 ++indent; | 254 ++indent; |
250 for (CryptoTagValueMap::const_iterator it = tag_value_map_.begin(); | 255 for (QuicTagValueMap::const_iterator it = tag_value_map_.begin(); |
251 it != tag_value_map_.end(); ++it) { | 256 it != tag_value_map_.end(); ++it) { |
252 ret += string(2 * indent, ' ') + TagToString(it->first) + ": "; | 257 ret += string(2 * indent, ' ') + TagToString(it->first) + ": "; |
253 | 258 |
254 bool done = false; | 259 bool done = false; |
255 switch (it->first) { | 260 switch (it->first) { |
256 case kKATO: | 261 case kKATO: |
257 case kVERS: | 262 case kVERS: |
258 // uint32 value | 263 // uint32 value |
259 if (it->second.size() == 4) { | 264 if (it->second.size() == 4) { |
260 uint32 value; | 265 uint32 value; |
261 memcpy(&value, it->second.data(), sizeof(value)); | 266 memcpy(&value, it->second.data(), sizeof(value)); |
262 ret += base::UintToString(value); | 267 ret += base::UintToString(value); |
263 done = true; | |
264 } | |
265 break; | |
266 case kKEXS: | |
267 case kAEAD: | |
268 case kCGST: | |
269 case kPDMD: | |
270 // tag lists | |
271 if (it->second.size() % sizeof(CryptoTag) == 0) { | |
272 for (size_t j = 0; j < it->second.size(); j += sizeof(CryptoTag)) { | |
273 CryptoTag tag; | |
274 memcpy(&tag, it->second.data() + j, sizeof(tag)); | |
275 if (j > 0) { | |
276 ret += ","; | |
277 } | |
278 ret += TagToString(tag); | |
279 } | |
280 done = true; | |
281 } | |
282 break; | |
283 case kSCFG: | |
284 // nested messages. | |
285 if (!it->second.empty()) { | |
286 scoped_ptr<CryptoHandshakeMessage> msg( | |
287 CryptoFramer::ParseMessage(it->second)); | |
288 if (msg.get()) { | |
289 ret += "\n"; | |
290 ret += msg->DebugStringInternal(indent + 1); | |
291 | |
292 done = true; | 268 done = true; |
293 } | 269 } |
294 } | 270 break; |
295 break; | 271 case kKEXS: |
| 272 case kAEAD: |
| 273 case kCGST: |
| 274 case kPDMD: |
| 275 // tag lists |
| 276 if (it->second.size() % sizeof(QuicTag) == 0) { |
| 277 for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) { |
| 278 QuicTag tag; |
| 279 memcpy(&tag, it->second.data() + j, sizeof(tag)); |
| 280 if (j > 0) { |
| 281 ret += ","; |
| 282 } |
| 283 ret += TagToString(tag); |
| 284 } |
| 285 done = true; |
| 286 } |
| 287 break; |
| 288 case kSCFG: |
| 289 // nested messages. |
| 290 if (!it->second.empty()) { |
| 291 scoped_ptr<CryptoHandshakeMessage> msg( |
| 292 CryptoFramer::ParseMessage(it->second)); |
| 293 if (msg.get()) { |
| 294 ret += "\n"; |
| 295 ret += msg->DebugStringInternal(indent + 1); |
| 296 |
| 297 done = true; |
| 298 } |
| 299 } |
| 300 break; |
296 } | 301 } |
297 | 302 |
298 if (!done) { | 303 if (!done) { |
299 // If there's no specific format for this tag, or the value is invalid, | 304 // If there's no specific format for this tag, or the value is invalid, |
300 // then just use hex. | 305 // then just use hex. |
301 ret += base::HexEncode(it->second.data(), it->second.size()); | 306 ret += base::HexEncode(it->second.data(), it->second.size()); |
302 } | 307 } |
303 ret += "\n"; | 308 ret += "\n"; |
304 } | 309 } |
305 --indent; | 310 --indent; |
306 ret += string(2 * indent, ' ') + ">"; | 311 ret += string(2 * indent, ' ') + ">"; |
307 return ret; | 312 return ret; |
308 } | 313 } |
309 | 314 |
310 QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters() | 315 QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters() |
311 : version(0), | 316 : version(0), |
312 key_exchange(0), | 317 key_exchange(0), |
313 aead(0) { | 318 aead(0) { |
314 } | 319 } |
315 | 320 |
316 QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() { | 321 QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {} |
317 } | |
318 | 322 |
| 323 CrypterPair::CrypterPair() {} |
| 324 CrypterPair::~CrypterPair() {} |
319 | 325 |
320 // static | 326 // static |
321 const char QuicCryptoConfig::kLabel[] = "QUIC key expansion"; | 327 const char QuicCryptoConfig::kInitialLabel[] = "QUIC key expansion"; |
| 328 |
| 329 const char QuicCryptoConfig::kForwardSecureLabel[] = |
| 330 "QUIC forward secure key expansion"; |
322 | 331 |
323 QuicCryptoConfig::QuicCryptoConfig() | 332 QuicCryptoConfig::QuicCryptoConfig() |
324 : version(0), | 333 : version(0), |
325 common_cert_set_(new CommonCertSetQUIC) { | 334 common_cert_set_(new CommonCertSetsQUIC) { |
326 } | 335 } |
327 | 336 |
328 QuicCryptoConfig::~QuicCryptoConfig() {} | 337 QuicCryptoConfig::~QuicCryptoConfig() {} |
329 | 338 |
330 QuicCryptoClientConfig::QuicCryptoClientConfig() {} | 339 QuicCryptoClientConfig::QuicCryptoClientConfig() {} |
331 | 340 |
332 QuicCryptoClientConfig::~QuicCryptoClientConfig() { | 341 QuicCryptoClientConfig::~QuicCryptoClientConfig() { |
333 STLDeleteValues(&cached_states_); | 342 STLDeleteValues(&cached_states_); |
334 } | 343 } |
335 | 344 |
(...skipping 12 matching lines...) Expand all Loading... |
348 return NULL; | 357 return NULL; |
349 } | 358 } |
350 | 359 |
351 if (!scfg_.get()) { | 360 if (!scfg_.get()) { |
352 scfg_.reset(CryptoFramer::ParseMessage(server_config_)); | 361 scfg_.reset(CryptoFramer::ParseMessage(server_config_)); |
353 DCHECK(scfg_.get()); | 362 DCHECK(scfg_.get()); |
354 } | 363 } |
355 return scfg_.get(); | 364 return scfg_.get(); |
356 } | 365 } |
357 | 366 |
358 bool QuicCryptoClientConfig::CachedState::SetServerConfig( | 367 bool QuicCryptoClientConfig::CachedState::SetServerConfig(StringPiece scfg) { |
359 StringPiece scfg) { | |
360 scfg_.reset(CryptoFramer::ParseMessage(scfg)); | 368 scfg_.reset(CryptoFramer::ParseMessage(scfg)); |
361 if (!scfg_.get()) { | 369 if (!scfg_.get()) { |
362 return false; | 370 return false; |
363 } | 371 } |
364 server_config_ = scfg.as_string(); | 372 server_config_ = scfg.as_string(); |
365 return true; | 373 return true; |
366 } | 374 } |
367 | 375 |
368 void QuicCryptoClientConfig::CachedState::SetProof( | 376 void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs, |
369 const vector<string>& certs, StringPiece signature) { | 377 StringPiece signature) { |
370 bool has_changed = signature != server_config_sig_; | 378 bool has_changed = signature != server_config_sig_; |
371 | 379 |
372 if (certs_.size() != certs.size()) { | 380 if (certs_.size() != certs.size()) { |
373 has_changed = true; | 381 has_changed = true; |
374 } | 382 } |
375 if (!has_changed) { | 383 if (!has_changed) { |
376 for (size_t i = 0; i < certs_.size(); i++) { | 384 for (size_t i = 0; i < certs_.size(); i++) { |
377 if (certs_[i] != certs[i]) { | 385 if (certs_[i] != certs[i]) { |
378 has_changed = true; | 386 has_changed = true; |
379 break; | 387 break; |
380 } | 388 } |
381 } | 389 } |
382 } | 390 } |
383 | 391 |
384 if (!has_changed) { | 392 if (!has_changed) { |
385 return; | 393 return; |
386 } | 394 } |
387 | 395 |
388 // If the proof has changed then it needs to be revalidated. | 396 // If the proof has changed then it needs to be revalidated. |
389 server_config_valid_ = false; | 397 server_config_valid_ = false; |
390 certs_ = certs; | 398 certs_ = certs; |
391 server_config_sig_ = signature.as_string(); | 399 server_config_sig_ = signature.as_string(); |
392 } | 400 } |
393 | 401 |
394 void QuicCryptoClientConfig::CachedState::SetProofValid() { | 402 void QuicCryptoClientConfig::CachedState::SetProofValid() { |
395 server_config_valid_ = true; | 403 server_config_valid_ = true; |
396 } | 404 } |
397 | 405 |
398 const string& | 406 const string& QuicCryptoClientConfig::CachedState::server_config() const { |
399 QuicCryptoClientConfig::CachedState::server_config() const { | |
400 return server_config_; | 407 return server_config_; |
401 } | 408 } |
402 | 409 |
403 const string& | 410 const string& |
404 QuicCryptoClientConfig::CachedState::source_address_token() const { | 411 QuicCryptoClientConfig::CachedState::source_address_token() const { |
405 return source_address_token_; | 412 return source_address_token_; |
406 } | 413 } |
407 | 414 |
408 const vector<string>& QuicCryptoClientConfig::CachedState::certs() const { | 415 const vector<string>& QuicCryptoClientConfig::CachedState::certs() const { |
409 return certs_; | 416 return certs_; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 // Server name indication. | 466 // Server name indication. |
460 // If server_hostname is not an IP address literal, it is a DNS hostname. | 467 // If server_hostname is not an IP address literal, it is a DNS hostname. |
461 IPAddressNumber ip; | 468 IPAddressNumber ip; |
462 if (!server_hostname.empty() && | 469 if (!server_hostname.empty() && |
463 !ParseIPLiteralToNumber(server_hostname, &ip)) { | 470 !ParseIPLiteralToNumber(server_hostname, &ip)) { |
464 out->SetStringPiece(kSNI, server_hostname); | 471 out->SetStringPiece(kSNI, server_hostname); |
465 } | 472 } |
466 out->SetValue(kVERS, version); | 473 out->SetValue(kVERS, version); |
467 | 474 |
468 if (!cached->source_address_token().empty()) { | 475 if (!cached->source_address_token().empty()) { |
469 out->SetStringPiece(kSRCT, cached->source_address_token()); | 476 out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token()); |
470 } | 477 } |
471 | 478 |
472 out->SetTaglist(kPDMD, kX509, 0); | 479 out->SetTaglist(kPDMD, kX509, 0); |
473 | 480 |
474 if (common_cert_set_.get()) { | 481 if (common_cert_set_.get()) { |
475 out->SetStringPiece(kCCS, common_cert_set_->GetCommonHashes()); | 482 out->SetStringPiece(kCCS, common_cert_set_->GetCommonHashes()); |
476 } | 483 } |
477 | 484 |
478 const vector<string>& certs = cached->certs(); | 485 const vector<string>& certs = cached->certs(); |
| 486 out_params->cached_certs = certs; |
479 if (!certs.empty()) { | 487 if (!certs.empty()) { |
480 vector<uint64> hashes; | 488 vector<uint64> hashes; |
481 hashes.reserve(certs.size()); | 489 hashes.reserve(certs.size()); |
482 for (vector<string>::const_iterator i = certs.begin(); | 490 for (vector<string>::const_iterator i = certs.begin(); |
483 i != certs.end(); ++i) { | 491 i != certs.end(); ++i) { |
484 hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size())); | 492 hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size())); |
485 } | 493 } |
486 out->SetVector(kCCRT, hashes); | 494 out->SetVector(kCCRT, hashes); |
487 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the | 495 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the |
488 // client config is being used for multiple connections, another connection | 496 // client config is being used for multiple connections, another connection |
489 // doesn't update the cached certificates and cause us to be unable to | 497 // doesn't update the cached certificates and cause us to be unable to |
490 // process the server's compressed certificate chain. | 498 // process the server's compressed certificate chain. |
491 out_params->cached_certs = certs; | |
492 } | 499 } |
493 } | 500 } |
494 | 501 |
495 QuicErrorCode QuicCryptoClientConfig::FillClientHello( | 502 QuicErrorCode QuicCryptoClientConfig::FillClientHello( |
496 const string& server_hostname, | 503 const string& server_hostname, |
497 QuicGuid guid, | 504 QuicGuid guid, |
498 const CachedState* cached, | 505 const CachedState* cached, |
499 const QuicClock* clock, | 506 QuicWallTime now, |
500 QuicRandom* rand, | 507 QuicRandom* rand, |
501 QuicCryptoNegotiatedParameters* out_params, | 508 QuicCryptoNegotiatedParameters* out_params, |
502 CryptoHandshakeMessage* out, | 509 CryptoHandshakeMessage* out, |
503 string* error_details) const { | 510 string* error_details) const { |
504 DCHECK(error_details != NULL); | 511 DCHECK(error_details != NULL); |
505 | 512 |
506 FillInchoateClientHello(server_hostname, cached, out_params, out); | 513 FillInchoateClientHello(server_hostname, cached, out_params, out); |
507 | 514 |
508 const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); | 515 const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); |
509 if (!scfg) { | 516 if (!scfg) { |
510 // This should never happen as our caller should have checked | 517 // This should never happen as our caller should have checked |
511 // cached->is_complete() before calling this function. | 518 // cached->is_complete() before calling this function. |
512 *error_details = "Handshake not ready"; | 519 *error_details = "Handshake not ready"; |
513 return QUIC_CRYPTO_INTERNAL_ERROR; | 520 return QUIC_CRYPTO_INTERNAL_ERROR; |
514 } | 521 } |
515 | 522 |
| 523 uint64 expiry_seconds; |
| 524 if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { |
| 525 *error_details = "SCFG missing EXPY"; |
| 526 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 527 } |
| 528 |
| 529 if (static_cast<uint64>(now.ToUNIXSeconds()) >= expiry_seconds) { |
| 530 *error_details = "SCFG expired"; |
| 531 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED; |
| 532 } |
| 533 |
516 StringPiece scid; | 534 StringPiece scid; |
517 if (!scfg->GetStringPiece(kSCID, &scid)) { | 535 if (!scfg->GetStringPiece(kSCID, &scid)) { |
518 *error_details = "SCFG missing SCID"; | 536 *error_details = "SCFG missing SCID"; |
519 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 537 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
520 } | 538 } |
521 out->SetStringPiece(kSCID, scid); | 539 out->SetStringPiece(kSCID, scid); |
522 | 540 |
523 // Calculate the mutual algorithms that the connection is going to use. | 541 // Calculate the mutual algorithms that the connection is going to use. |
524 if (scfg->GetUint16(kVERS, &out_params->version) != QUIC_NO_ERROR || | 542 if (scfg->GetUint16(kVERS, &out_params->version) != QUIC_NO_ERROR || |
525 out_params->version != QuicCryptoConfig::CONFIG_VERSION) { | 543 out_params->version != QuicCryptoConfig::CONFIG_VERSION) { |
526 *error_details = "Bad version"; | 544 *error_details = "Bad version"; |
527 return QUIC_CRYPTO_VERSION_NOT_SUPPORTED; | 545 return QUIC_CRYPTO_VERSION_NOT_SUPPORTED; |
528 } | 546 } |
529 | 547 |
530 const CryptoTag* their_aeads; | 548 const QuicTag* their_aeads; |
531 const CryptoTag* their_key_exchanges; | 549 const QuicTag* their_key_exchanges; |
532 size_t num_their_aeads, num_their_key_exchanges; | 550 size_t num_their_aeads, num_their_key_exchanges; |
533 if (scfg->GetTaglist(kAEAD, &their_aeads, | 551 if (scfg->GetTaglist(kAEAD, &their_aeads, |
534 &num_their_aeads) != QUIC_NO_ERROR || | 552 &num_their_aeads) != QUIC_NO_ERROR || |
535 scfg->GetTaglist(kKEXS, &their_key_exchanges, | 553 scfg->GetTaglist(kKEXS, &their_key_exchanges, |
536 &num_their_key_exchanges) != QUIC_NO_ERROR) { | 554 &num_their_key_exchanges) != QUIC_NO_ERROR) { |
537 *error_details = "Missing AEAD or KEXS"; | 555 *error_details = "Missing AEAD or KEXS"; |
538 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 556 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
539 } | 557 } |
540 | 558 |
541 size_t key_exchange_index; | 559 size_t key_exchange_index; |
542 if (!CryptoUtils::FindMutualTag(aead, | 560 if (!CryptoUtils::FindMutualTag(aead, their_aeads, num_their_aeads, |
543 their_aeads, num_their_aeads, | 561 CryptoUtils::PEER_PRIORITY, &out_params->aead, |
544 CryptoUtils::PEER_PRIORITY, | |
545 &out_params->aead, | |
546 NULL) || | 562 NULL) || |
547 !CryptoUtils::FindMutualTag(kexs, | 563 !CryptoUtils::FindMutualTag( |
548 their_key_exchanges, num_their_key_exchanges, | 564 kexs, their_key_exchanges, num_their_key_exchanges, |
549 CryptoUtils::PEER_PRIORITY, | 565 CryptoUtils::PEER_PRIORITY, &out_params->key_exchange, |
550 &out_params->key_exchange, | 566 &key_exchange_index)) { |
551 &key_exchange_index)) { | |
552 *error_details = "Unsupported AEAD or KEXS"; | 567 *error_details = "Unsupported AEAD or KEXS"; |
553 return QUIC_CRYPTO_NO_SUPPORT; | 568 return QUIC_CRYPTO_NO_SUPPORT; |
554 } | 569 } |
555 out->SetTaglist(kAEAD, out_params->aead, 0); | 570 out->SetTaglist(kAEAD, out_params->aead, 0); |
556 out->SetTaglist(kKEXS, out_params->key_exchange, 0); | 571 out->SetTaglist(kKEXS, out_params->key_exchange, 0); |
557 | 572 |
558 StringPiece public_value; | 573 StringPiece public_value; |
559 if (scfg->GetNthValue16(kPUBS, key_exchange_index, &public_value) != | 574 if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) != |
560 QUIC_NO_ERROR) { | 575 QUIC_NO_ERROR) { |
561 *error_details = "Missing public value"; | 576 *error_details = "Missing public value"; |
562 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 577 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
563 } | 578 } |
564 | 579 |
565 StringPiece orbit; | 580 StringPiece orbit; |
566 if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) { | 581 if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) { |
567 *error_details = "SCFG missing OBIT"; | 582 *error_details = "SCFG missing OBIT"; |
568 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 583 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
569 } | 584 } |
570 | 585 |
571 string nonce; | 586 CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce); |
572 CryptoUtils::GenerateNonce(clock->NowAsDeltaSinceUnixEpoch(), rand, orbit, | 587 out->SetStringPiece(kNONC, out_params->client_nonce); |
573 &nonce); | 588 if (!out_params->server_nonce.empty()) { |
574 out->SetStringPiece(kNONC, nonce); | 589 out->SetStringPiece(kServerNonceTag, out_params->server_nonce); |
575 | |
576 scoped_ptr<KeyExchange> key_exchange; | |
577 switch (out_params->key_exchange) { | |
578 case kC255: | |
579 key_exchange.reset(Curve25519KeyExchange::New( | |
580 Curve25519KeyExchange::NewPrivateKey(rand))); | |
581 break; | |
582 case kP256: | |
583 key_exchange.reset(P256KeyExchange::New( | |
584 P256KeyExchange::NewPrivateKey())); | |
585 break; | |
586 default: | |
587 DCHECK(false); | |
588 *error_details = "Configured to support an unknown key exchange"; | |
589 return QUIC_CRYPTO_INTERNAL_ERROR; | |
590 } | 590 } |
591 | 591 |
592 if (!key_exchange->CalculateSharedKey(public_value, | 592 switch (out_params->key_exchange) { |
593 &out_params->premaster_secret)) { | 593 case kC255: |
| 594 out_params->client_key_exchange.reset(Curve25519KeyExchange::New( |
| 595 Curve25519KeyExchange::NewPrivateKey(rand))); |
| 596 break; |
| 597 case kP256: |
| 598 out_params->client_key_exchange |
| 599 .reset(P256KeyExchange::New(P256KeyExchange::NewPrivateKey())); |
| 600 break; |
| 601 default: |
| 602 DCHECK(false); |
| 603 *error_details = "Configured to support an unknown key exchange"; |
| 604 return QUIC_CRYPTO_INTERNAL_ERROR; |
| 605 } |
| 606 |
| 607 if (!out_params->client_key_exchange->CalculateSharedKey( |
| 608 public_value, &out_params->initial_premaster_secret)) { |
594 *error_details = "Key exchange failure"; | 609 *error_details = "Key exchange failure"; |
595 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 610 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
596 } | 611 } |
597 out->SetStringPiece(kPUBS, key_exchange->public_value()); | 612 out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value()); |
598 | 613 |
599 string hkdf_input(QuicCryptoConfig::kLabel, | 614 out_params->hkdf_input_suffix.clear(); |
600 strlen(QuicCryptoConfig::kLabel) + 1); | 615 out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&guid), |
601 hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid)); | 616 sizeof(guid)); |
| 617 const QuicData& client_hello_serialized = out->GetSerialized(); |
| 618 out_params->hkdf_input_suffix.append(client_hello_serialized.data(), |
| 619 client_hello_serialized.length()); |
| 620 out_params->hkdf_input_suffix.append(cached->server_config()); |
602 | 621 |
603 const QuicData& client_hello_serialized = out->GetSerialized(); | 622 string hkdf_input; |
604 hkdf_input.append(client_hello_serialized.data(), | 623 const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; |
605 client_hello_serialized.length()); | 624 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size()); |
606 hkdf_input.append(cached->server_config()); | 625 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); |
| 626 hkdf_input.append(out_params->hkdf_input_suffix); |
607 | 627 |
608 CryptoUtils::DeriveKeys(out_params, nonce, hkdf_input, CryptoUtils::CLIENT); | 628 CryptoUtils::DeriveKeys(out_params->initial_premaster_secret, |
| 629 out_params->aead, out_params->client_nonce, |
| 630 out_params->server_nonce, hkdf_input, |
| 631 CryptoUtils::CLIENT, &out_params->initial_crypters); |
609 | 632 |
610 return QUIC_NO_ERROR; | 633 return QUIC_NO_ERROR; |
611 } | 634 } |
612 | 635 |
613 QuicErrorCode QuicCryptoClientConfig::ProcessRejection( | 636 QuicErrorCode QuicCryptoClientConfig::ProcessRejection( |
614 CachedState* cached, | 637 CachedState* cached, |
615 const CryptoHandshakeMessage& rej, | 638 const CryptoHandshakeMessage& rej, |
616 QuicCryptoNegotiatedParameters* out_params, | 639 QuicCryptoNegotiatedParameters* out_params, |
617 string* error_details) { | 640 string* error_details) { |
618 DCHECK(error_details != NULL); | 641 DCHECK(error_details != NULL); |
619 | 642 |
620 StringPiece scfg; | 643 StringPiece scfg; |
621 if (!rej.GetStringPiece(kSCFG, &scfg)) { | 644 if (!rej.GetStringPiece(kSCFG, &scfg)) { |
622 *error_details = "Missing SCFG"; | 645 *error_details = "Missing SCFG"; |
623 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 646 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
624 } | 647 } |
625 | 648 |
626 if (!cached->SetServerConfig(scfg)) { | 649 if (!cached->SetServerConfig(scfg)) { |
627 *error_details = "Invalid SCFG"; | 650 *error_details = "Invalid SCFG"; |
628 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 651 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
629 } | 652 } |
630 | 653 |
631 StringPiece token; | 654 StringPiece token; |
632 if (rej.GetStringPiece(kSRCT, &token)) { | 655 if (rej.GetStringPiece(kSourceAddressTokenTag, &token)) { |
633 cached->set_source_address_token(token); | 656 cached->set_source_address_token(token); |
634 } | 657 } |
635 | 658 |
636 StringPiece nonce; | 659 StringPiece nonce; |
637 if (rej.GetStringPiece(kNONC, &nonce) && | 660 if (rej.GetStringPiece(kServerNonceTag, &nonce) && nonce.size() == |
638 nonce.size() == kNonceSize) { | 661 kNonceSize) { |
639 out_params->server_nonce = nonce.as_string(); | 662 out_params->server_nonce = nonce.as_string(); |
640 } | 663 } |
641 | 664 |
642 StringPiece proof, cert_bytes; | 665 StringPiece proof, cert_bytes; |
643 if (rej.GetStringPiece(kPROF, &proof) && | 666 if (rej.GetStringPiece(kPROF, &proof) && |
644 rej.GetStringPiece(kCERT, &cert_bytes)) { | 667 rej.GetStringPiece(kCertificateTag, &cert_bytes)) { |
645 vector<string> certs; | 668 vector<string> certs; |
646 if (!CertCompressor::DecompressChain(cert_bytes, out_params->cached_certs, | 669 if (!CertCompressor::DecompressChain(cert_bytes, out_params->cached_certs, |
647 common_cert_set_.get(), &certs)) { | 670 common_cert_set_.get(), &certs)) { |
648 *error_details = "Certificate data invalid"; | 671 *error_details = "Certificate data invalid"; |
649 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 672 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
650 } | 673 } |
651 | 674 |
652 cached->SetProof(certs, proof); | 675 cached->SetProof(certs, proof); |
653 } | 676 } |
654 | 677 |
655 return QUIC_NO_ERROR; | 678 return QUIC_NO_ERROR; |
656 } | 679 } |
657 | 680 |
658 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( | 681 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( |
659 const CryptoHandshakeMessage& server_hello, | 682 const CryptoHandshakeMessage& server_hello, |
660 const string& nonce, | 683 QuicGuid guid, |
661 QuicCryptoNegotiatedParameters* out_params, | 684 QuicCryptoNegotiatedParameters* out_params, |
662 string* error_details) { | 685 string* error_details) { |
663 DCHECK(error_details != NULL); | 686 DCHECK(error_details != NULL); |
664 | 687 |
665 if (server_hello.tag() != kSHLO) { | 688 if (server_hello.tag() != kSHLO) { |
666 *error_details = "Bad tag"; | 689 *error_details = "Bad tag"; |
667 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; | 690 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; |
668 } | 691 } |
669 | 692 |
670 // TODO(agl): | 693 // TODO(agl): |
671 // learn about updated SCFGs. | 694 // learn about updated SCFGs. |
672 // read ephemeral public value for forward-secret keys. | 695 |
| 696 StringPiece public_value; |
| 697 if (!server_hello.GetStringPiece(kPUBS, &public_value)) { |
| 698 *error_details = "server hello missing forward secure public value"; |
| 699 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 700 } |
| 701 |
| 702 if (!out_params->client_key_exchange->CalculateSharedKey( |
| 703 public_value, &out_params->forward_secure_premaster_secret)) { |
| 704 *error_details = "Key exchange failure"; |
| 705 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 706 } |
| 707 |
| 708 string hkdf_input; |
| 709 const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; |
| 710 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size()); |
| 711 hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len); |
| 712 hkdf_input.append(out_params->hkdf_input_suffix); |
| 713 |
| 714 CryptoUtils::DeriveKeys( |
| 715 out_params->forward_secure_premaster_secret, out_params->aead, |
| 716 out_params->client_nonce, out_params->server_nonce, hkdf_input, |
| 717 CryptoUtils::CLIENT, &out_params->forward_secure_crypters); |
673 | 718 |
674 return QUIC_NO_ERROR; | 719 return QUIC_NO_ERROR; |
675 } | 720 } |
676 | 721 |
677 const ProofVerifier* QuicCryptoClientConfig::proof_verifier() const { | 722 const ProofVerifier* QuicCryptoClientConfig::proof_verifier() const { |
678 return proof_verifier_.get(); | 723 return proof_verifier_.get(); |
679 } | 724 } |
680 | 725 |
681 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier* verifier) { | 726 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier* verifier) { |
682 proof_verifier_.reset(verifier); | 727 proof_verifier_.reset(verifier); |
683 } | 728 } |
684 | 729 |
685 } // namespace net | 730 } // namespace net |
OLD | NEW |