OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 #include "net/quic/test_tools/crypto_test_utils.h" | |
6 | |
7 #include "net/quic/crypto/channel_id.h" | |
8 #include "net/quic/crypto/common_cert_set.h" | |
9 #include "net/quic/crypto/crypto_handshake.h" | |
10 #include "net/quic/crypto/quic_crypto_server_config.h" | |
11 #include "net/quic/crypto/quic_decrypter.h" | |
12 #include "net/quic/crypto/quic_encrypter.h" | |
13 #include "net/quic/crypto/quic_random.h" | |
14 #include "net/quic/quic_clock.h" | |
15 #include "net/quic/quic_crypto_client_stream.h" | |
16 #include "net/quic/quic_crypto_server_stream.h" | |
17 #include "net/quic/quic_crypto_stream.h" | |
18 #include "net/quic/quic_server_id.h" | |
19 #include "net/quic/test_tools/quic_connection_peer.h" | |
20 #include "net/quic/test_tools/quic_test_utils.h" | |
21 #include "net/quic/test_tools/simple_quic_framer.h" | |
22 | |
23 using base::StringPiece; | |
24 using std::make_pair; | |
25 using std::pair; | |
26 using std::string; | |
27 using std::vector; | |
28 | |
29 namespace net { | |
30 namespace test { | |
31 | |
32 namespace { | |
33 | |
34 const char kServerHostname[] = "test.example.com"; | |
35 const uint16 kServerPort = 80; | |
36 | |
37 // CryptoFramerVisitor is a framer visitor that records handshake messages. | |
38 class CryptoFramerVisitor : public CryptoFramerVisitorInterface { | |
39 public: | |
40 CryptoFramerVisitor() | |
41 : error_(false) { | |
42 } | |
43 | |
44 void OnError(CryptoFramer* framer) override { error_ = true; } | |
45 | |
46 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override { | |
47 messages_.push_back(message); | |
48 } | |
49 | |
50 bool error() const { | |
51 return error_; | |
52 } | |
53 | |
54 const vector<CryptoHandshakeMessage>& messages() const { | |
55 return messages_; | |
56 } | |
57 | |
58 private: | |
59 bool error_; | |
60 vector<CryptoHandshakeMessage> messages_; | |
61 }; | |
62 | |
63 // MovePackets parses crypto handshake messages from packet number | |
64 // |*inout_packet_index| through to the last packet (or until a packet fails to | |
65 // decrypt) and has |dest_stream| process them. |*inout_packet_index| is updated | |
66 // with an index one greater than the last packet processed. | |
67 void MovePackets(PacketSavingConnection* source_conn, | |
68 size_t *inout_packet_index, | |
69 QuicCryptoStream* dest_stream, | |
70 PacketSavingConnection* dest_conn) { | |
71 SimpleQuicFramer framer(source_conn->supported_versions()); | |
72 CryptoFramer crypto_framer; | |
73 CryptoFramerVisitor crypto_visitor; | |
74 | |
75 // In order to properly test the code we need to perform encryption and | |
76 // decryption so that the crypters latch when expected. The crypters are in | |
77 // |dest_conn|, but we don't want to try and use them there. Instead we swap | |
78 // them into |framer|, perform the decryption with them, and then swap them | |
79 // back. | |
80 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); | |
81 | |
82 crypto_framer.set_visitor(&crypto_visitor); | |
83 | |
84 size_t index = *inout_packet_index; | |
85 for (; index < source_conn->encrypted_packets_.size(); index++) { | |
86 if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) { | |
87 // The framer will be unable to decrypt forward-secure packets sent after | |
88 // the handshake is complete. Don't treat them as handshake packets. | |
89 break; | |
90 } | |
91 | |
92 for (vector<QuicStreamFrame>::const_iterator | |
93 i = framer.stream_frames().begin(); | |
94 i != framer.stream_frames().end(); ++i) { | |
95 scoped_ptr<string> frame_data(i->GetDataAsString()); | |
96 ASSERT_TRUE(crypto_framer.ProcessInput(*frame_data)); | |
97 ASSERT_FALSE(crypto_visitor.error()); | |
98 } | |
99 } | |
100 *inout_packet_index = index; | |
101 | |
102 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); | |
103 | |
104 ASSERT_EQ(0u, crypto_framer.InputBytesRemaining()); | |
105 | |
106 for (vector<CryptoHandshakeMessage>::const_iterator | |
107 i = crypto_visitor.messages().begin(); | |
108 i != crypto_visitor.messages().end(); ++i) { | |
109 dest_stream->OnHandshakeMessage(*i); | |
110 } | |
111 } | |
112 | |
113 // HexChar parses |c| as a hex character. If valid, it sets |*value| to the | |
114 // value of the hex character and returns true. Otherwise it returns false. | |
115 bool HexChar(char c, uint8* value) { | |
116 if (c >= '0' && c <= '9') { | |
117 *value = c - '0'; | |
118 return true; | |
119 } | |
120 if (c >= 'a' && c <= 'f') { | |
121 *value = c - 'a' + 10; | |
122 return true; | |
123 } | |
124 if (c >= 'A' && c <= 'F') { | |
125 *value = c - 'A' + 10; | |
126 return true; | |
127 } | |
128 return false; | |
129 } | |
130 | |
131 // A ChannelIDSource that works in asynchronous mode unless the |callback| | |
132 // argument to GetChannelIDKey is nullptr. | |
133 class AsyncTestChannelIDSource : public ChannelIDSource, | |
134 public CryptoTestUtils::CallbackSource { | |
135 public: | |
136 // Takes ownership of |sync_source|, a synchronous ChannelIDSource. | |
137 explicit AsyncTestChannelIDSource(ChannelIDSource* sync_source) | |
138 : sync_source_(sync_source) {} | |
139 ~AsyncTestChannelIDSource() override {} | |
140 | |
141 // ChannelIDSource implementation. | |
142 QuicAsyncStatus GetChannelIDKey(const string& hostname, | |
143 scoped_ptr<ChannelIDKey>* channel_id_key, | |
144 ChannelIDSourceCallback* callback) override { | |
145 // Synchronous mode. | |
146 if (!callback) { | |
147 return sync_source_->GetChannelIDKey(hostname, channel_id_key, nullptr); | |
148 } | |
149 | |
150 // Asynchronous mode. | |
151 QuicAsyncStatus status = | |
152 sync_source_->GetChannelIDKey(hostname, &channel_id_key_, nullptr); | |
153 if (status != QUIC_SUCCESS) { | |
154 return QUIC_FAILURE; | |
155 } | |
156 callback_.reset(callback); | |
157 return QUIC_PENDING; | |
158 } | |
159 | |
160 // CallbackSource implementation. | |
161 void RunPendingCallbacks() override { | |
162 if (callback_.get()) { | |
163 callback_->Run(&channel_id_key_); | |
164 callback_.reset(); | |
165 } | |
166 } | |
167 | |
168 private: | |
169 scoped_ptr<ChannelIDSource> sync_source_; | |
170 scoped_ptr<ChannelIDSourceCallback> callback_; | |
171 scoped_ptr<ChannelIDKey> channel_id_key_; | |
172 }; | |
173 | |
174 } // anonymous namespace | |
175 | |
176 CryptoTestUtils::FakeClientOptions::FakeClientOptions() | |
177 : dont_verify_certs(false), | |
178 channel_id_enabled(false), | |
179 channel_id_source_async(false) { | |
180 } | |
181 | |
182 // static | |
183 int CryptoTestUtils::HandshakeWithFakeServer( | |
184 PacketSavingConnection* client_conn, | |
185 QuicCryptoClientStream* client) { | |
186 PacketSavingConnection* server_conn = | |
187 new PacketSavingConnection(true, client_conn->supported_versions()); | |
188 TestSession server_session(server_conn, DefaultQuicConfig()); | |
189 server_session.InitializeSession(); | |
190 QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING, | |
191 QuicRandom::GetInstance()); | |
192 | |
193 SetupCryptoServerConfigForTest( | |
194 server_session.connection()->clock(), | |
195 server_session.connection()->random_generator(), | |
196 server_session.config(), &crypto_config); | |
197 | |
198 QuicCryptoServerStream server(crypto_config, &server_session); | |
199 server_session.SetCryptoStream(&server); | |
200 | |
201 // The client's handshake must have been started already. | |
202 CHECK_NE(0u, client_conn->encrypted_packets_.size()); | |
203 | |
204 CommunicateHandshakeMessages(client_conn, client, server_conn, &server); | |
205 | |
206 CompareClientAndServerKeys(client, &server); | |
207 | |
208 return client->num_sent_client_hellos(); | |
209 } | |
210 | |
211 // static | |
212 int CryptoTestUtils::HandshakeWithFakeClient( | |
213 PacketSavingConnection* server_conn, | |
214 QuicCryptoServerStream* server, | |
215 const FakeClientOptions& options) { | |
216 PacketSavingConnection* client_conn = new PacketSavingConnection(false); | |
217 // Advance the time, because timers do not like uninitialized times. | |
218 client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1)); | |
219 TestClientSession client_session(client_conn, DefaultQuicConfig()); | |
220 QuicCryptoClientConfig crypto_config; | |
221 | |
222 if (!options.dont_verify_certs) { | |
223 // TODO(wtc): replace this with ProofVerifierForTesting() when we have | |
224 // a working ProofSourceForTesting(). | |
225 crypto_config.SetProofVerifier(FakeProofVerifierForTesting()); | |
226 } | |
227 bool is_https = false; | |
228 AsyncTestChannelIDSource* async_channel_id_source = nullptr; | |
229 if (options.channel_id_enabled) { | |
230 is_https = true; | |
231 | |
232 ChannelIDSource* source = ChannelIDSourceForTesting(); | |
233 if (options.channel_id_source_async) { | |
234 async_channel_id_source = new AsyncTestChannelIDSource(source); | |
235 source = async_channel_id_source; | |
236 } | |
237 crypto_config.SetChannelIDSource(source); | |
238 } | |
239 QuicServerId server_id(kServerHostname, kServerPort, is_https, | |
240 PRIVACY_MODE_DISABLED); | |
241 QuicCryptoClientStream client(server_id, &client_session, | |
242 ProofVerifyContextForTesting(), | |
243 &crypto_config); | |
244 client_session.SetCryptoStream(&client); | |
245 | |
246 client.CryptoConnect(); | |
247 CHECK_EQ(1u, client_conn->encrypted_packets_.size()); | |
248 | |
249 CommunicateHandshakeMessagesAndRunCallbacks( | |
250 client_conn, &client, server_conn, server, async_channel_id_source); | |
251 | |
252 CompareClientAndServerKeys(&client, server); | |
253 | |
254 if (options.channel_id_enabled) { | |
255 scoped_ptr<ChannelIDKey> channel_id_key; | |
256 QuicAsyncStatus status = crypto_config.channel_id_source()->GetChannelIDKey( | |
257 kServerHostname, &channel_id_key, nullptr); | |
258 EXPECT_EQ(QUIC_SUCCESS, status); | |
259 EXPECT_EQ(channel_id_key->SerializeKey(), | |
260 server->crypto_negotiated_params().channel_id); | |
261 EXPECT_EQ(options.channel_id_source_async, | |
262 client.WasChannelIDSourceCallbackRun()); | |
263 } | |
264 | |
265 return client.num_sent_client_hellos(); | |
266 } | |
267 | |
268 // static | |
269 void CryptoTestUtils::SetupCryptoServerConfigForTest( | |
270 const QuicClock* clock, | |
271 QuicRandom* rand, | |
272 QuicConfig* config, | |
273 QuicCryptoServerConfig* crypto_config) { | |
274 QuicCryptoServerConfig::ConfigOptions options; | |
275 options.channel_id_enabled = true; | |
276 scoped_ptr<CryptoHandshakeMessage> scfg( | |
277 crypto_config->AddDefaultConfig(rand, clock, options)); | |
278 } | |
279 | |
280 // static | |
281 void CryptoTestUtils::CommunicateHandshakeMessages( | |
282 PacketSavingConnection* a_conn, | |
283 QuicCryptoStream* a, | |
284 PacketSavingConnection* b_conn, | |
285 QuicCryptoStream* b) { | |
286 CommunicateHandshakeMessagesAndRunCallbacks(a_conn, a, b_conn, b, nullptr); | |
287 } | |
288 | |
289 // static | |
290 void CryptoTestUtils::CommunicateHandshakeMessagesAndRunCallbacks( | |
291 PacketSavingConnection* a_conn, | |
292 QuicCryptoStream* a, | |
293 PacketSavingConnection* b_conn, | |
294 QuicCryptoStream* b, | |
295 CallbackSource* callback_source) { | |
296 size_t a_i = 0, b_i = 0; | |
297 while (!a->handshake_confirmed()) { | |
298 ASSERT_GT(a_conn->encrypted_packets_.size(), a_i); | |
299 VLOG(1) << "Processing " << a_conn->encrypted_packets_.size() - a_i | |
300 << " packets a->b"; | |
301 MovePackets(a_conn, &a_i, b, b_conn); | |
302 if (callback_source) { | |
303 callback_source->RunPendingCallbacks(); | |
304 } | |
305 | |
306 ASSERT_GT(b_conn->encrypted_packets_.size(), b_i); | |
307 VLOG(1) << "Processing " << b_conn->encrypted_packets_.size() - b_i | |
308 << " packets b->a"; | |
309 MovePackets(b_conn, &b_i, a, a_conn); | |
310 if (callback_source) { | |
311 callback_source->RunPendingCallbacks(); | |
312 } | |
313 } | |
314 } | |
315 | |
316 // static | |
317 pair<size_t, size_t> CryptoTestUtils::AdvanceHandshake( | |
318 PacketSavingConnection* a_conn, | |
319 QuicCryptoStream* a, | |
320 size_t a_i, | |
321 PacketSavingConnection* b_conn, | |
322 QuicCryptoStream* b, | |
323 size_t b_i) { | |
324 VLOG(1) << "Processing " << a_conn->encrypted_packets_.size() - a_i | |
325 << " packets a->b"; | |
326 MovePackets(a_conn, &a_i, b, b_conn); | |
327 | |
328 VLOG(1) << "Processing " << b_conn->encrypted_packets_.size() - b_i | |
329 << " packets b->a"; | |
330 if (b_conn->encrypted_packets_.size() - b_i == 2) { | |
331 VLOG(1) << "here"; | |
332 } | |
333 MovePackets(b_conn, &b_i, a, a_conn); | |
334 | |
335 return std::make_pair(a_i, b_i); | |
336 } | |
337 | |
338 // static | |
339 string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message, | |
340 QuicTag tag) { | |
341 QuicTagValueMap::const_iterator it = message.tag_value_map().find(tag); | |
342 if (it == message.tag_value_map().end()) { | |
343 return string(); | |
344 } | |
345 return it->second; | |
346 } | |
347 | |
348 class MockCommonCertSets : public CommonCertSets { | |
349 public: | |
350 MockCommonCertSets(StringPiece cert, uint64 hash, uint32 index) | |
351 : cert_(cert.as_string()), | |
352 hash_(hash), | |
353 index_(index) { | |
354 } | |
355 | |
356 StringPiece GetCommonHashes() const override { | |
357 CHECK(false) << "not implemented"; | |
358 return StringPiece(); | |
359 } | |
360 | |
361 StringPiece GetCert(uint64 hash, uint32 index) const override { | |
362 if (hash == hash_ && index == index_) { | |
363 return cert_; | |
364 } | |
365 return StringPiece(); | |
366 } | |
367 | |
368 bool MatchCert(StringPiece cert, | |
369 StringPiece common_set_hashes, | |
370 uint64* out_hash, | |
371 uint32* out_index) const override { | |
372 if (cert != cert_) { | |
373 return false; | |
374 } | |
375 | |
376 if (common_set_hashes.size() % sizeof(uint64) != 0) { | |
377 return false; | |
378 } | |
379 bool client_has_set = false; | |
380 for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64)) { | |
381 uint64 hash; | |
382 memcpy(&hash, common_set_hashes.data() + i, sizeof(hash)); | |
383 if (hash == hash_) { | |
384 client_has_set = true; | |
385 break; | |
386 } | |
387 } | |
388 | |
389 if (!client_has_set) { | |
390 return false; | |
391 } | |
392 | |
393 *out_hash = hash_; | |
394 *out_index = index_; | |
395 return true; | |
396 } | |
397 | |
398 private: | |
399 const string cert_; | |
400 const uint64 hash_; | |
401 const uint32 index_; | |
402 }; | |
403 | |
404 CommonCertSets* CryptoTestUtils::MockCommonCertSets(StringPiece cert, | |
405 uint64 hash, | |
406 uint32 index) { | |
407 return new class MockCommonCertSets(cert, hash, index); | |
408 } | |
409 | |
410 void CryptoTestUtils::CompareClientAndServerKeys( | |
411 QuicCryptoClientStream* client, | |
412 QuicCryptoServerStream* server) { | |
413 const QuicEncrypter* client_encrypter( | |
414 client->session()->connection()->encrypter(ENCRYPTION_INITIAL)); | |
415 const QuicDecrypter* client_decrypter( | |
416 client->session()->connection()->decrypter()); | |
417 const QuicEncrypter* client_forward_secure_encrypter( | |
418 client->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE)); | |
419 const QuicDecrypter* client_forward_secure_decrypter( | |
420 client->session()->connection()->alternative_decrypter()); | |
421 const QuicEncrypter* server_encrypter( | |
422 server->session()->connection()->encrypter(ENCRYPTION_INITIAL)); | |
423 const QuicDecrypter* server_decrypter( | |
424 server->session()->connection()->decrypter()); | |
425 const QuicEncrypter* server_forward_secure_encrypter( | |
426 server->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE)); | |
427 const QuicDecrypter* server_forward_secure_decrypter( | |
428 server->session()->connection()->alternative_decrypter()); | |
429 | |
430 StringPiece client_encrypter_key = client_encrypter->GetKey(); | |
431 StringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix(); | |
432 StringPiece client_decrypter_key = client_decrypter->GetKey(); | |
433 StringPiece client_decrypter_iv = client_decrypter->GetNoncePrefix(); | |
434 StringPiece client_forward_secure_encrypter_key = | |
435 client_forward_secure_encrypter->GetKey(); | |
436 StringPiece client_forward_secure_encrypter_iv = | |
437 client_forward_secure_encrypter->GetNoncePrefix(); | |
438 StringPiece client_forward_secure_decrypter_key = | |
439 client_forward_secure_decrypter->GetKey(); | |
440 StringPiece client_forward_secure_decrypter_iv = | |
441 client_forward_secure_decrypter->GetNoncePrefix(); | |
442 StringPiece server_encrypter_key = server_encrypter->GetKey(); | |
443 StringPiece server_encrypter_iv = server_encrypter->GetNoncePrefix(); | |
444 StringPiece server_decrypter_key = server_decrypter->GetKey(); | |
445 StringPiece server_decrypter_iv = server_decrypter->GetNoncePrefix(); | |
446 StringPiece server_forward_secure_encrypter_key = | |
447 server_forward_secure_encrypter->GetKey(); | |
448 StringPiece server_forward_secure_encrypter_iv = | |
449 server_forward_secure_encrypter->GetNoncePrefix(); | |
450 StringPiece server_forward_secure_decrypter_key = | |
451 server_forward_secure_decrypter->GetKey(); | |
452 StringPiece server_forward_secure_decrypter_iv = | |
453 server_forward_secure_decrypter->GetNoncePrefix(); | |
454 | |
455 StringPiece client_subkey_secret = | |
456 client->crypto_negotiated_params().subkey_secret; | |
457 StringPiece server_subkey_secret = | |
458 server->crypto_negotiated_params().subkey_secret; | |
459 | |
460 | |
461 const char kSampleLabel[] = "label"; | |
462 const char kSampleContext[] = "context"; | |
463 const size_t kSampleOutputLength = 32; | |
464 string client_key_extraction; | |
465 string server_key_extraction; | |
466 EXPECT_TRUE(client->ExportKeyingMaterial(kSampleLabel, | |
467 kSampleContext, | |
468 kSampleOutputLength, | |
469 &client_key_extraction)); | |
470 EXPECT_TRUE(server->ExportKeyingMaterial(kSampleLabel, | |
471 kSampleContext, | |
472 kSampleOutputLength, | |
473 &server_key_extraction)); | |
474 | |
475 CompareCharArraysWithHexError("client write key", | |
476 client_encrypter_key.data(), | |
477 client_encrypter_key.length(), | |
478 server_decrypter_key.data(), | |
479 server_decrypter_key.length()); | |
480 CompareCharArraysWithHexError("client write IV", | |
481 client_encrypter_iv.data(), | |
482 client_encrypter_iv.length(), | |
483 server_decrypter_iv.data(), | |
484 server_decrypter_iv.length()); | |
485 CompareCharArraysWithHexError("server write key", | |
486 server_encrypter_key.data(), | |
487 server_encrypter_key.length(), | |
488 client_decrypter_key.data(), | |
489 client_decrypter_key.length()); | |
490 CompareCharArraysWithHexError("server write IV", | |
491 server_encrypter_iv.data(), | |
492 server_encrypter_iv.length(), | |
493 client_decrypter_iv.data(), | |
494 client_decrypter_iv.length()); | |
495 CompareCharArraysWithHexError("client forward secure write key", | |
496 client_forward_secure_encrypter_key.data(), | |
497 client_forward_secure_encrypter_key.length(), | |
498 server_forward_secure_decrypter_key.data(), | |
499 server_forward_secure_decrypter_key.length()); | |
500 CompareCharArraysWithHexError("client forward secure write IV", | |
501 client_forward_secure_encrypter_iv.data(), | |
502 client_forward_secure_encrypter_iv.length(), | |
503 server_forward_secure_decrypter_iv.data(), | |
504 server_forward_secure_decrypter_iv.length()); | |
505 CompareCharArraysWithHexError("server forward secure write key", | |
506 server_forward_secure_encrypter_key.data(), | |
507 server_forward_secure_encrypter_key.length(), | |
508 client_forward_secure_decrypter_key.data(), | |
509 client_forward_secure_decrypter_key.length()); | |
510 CompareCharArraysWithHexError("server forward secure write IV", | |
511 server_forward_secure_encrypter_iv.data(), | |
512 server_forward_secure_encrypter_iv.length(), | |
513 client_forward_secure_decrypter_iv.data(), | |
514 client_forward_secure_decrypter_iv.length()); | |
515 CompareCharArraysWithHexError("subkey secret", | |
516 client_subkey_secret.data(), | |
517 client_subkey_secret.length(), | |
518 server_subkey_secret.data(), | |
519 server_subkey_secret.length()); | |
520 CompareCharArraysWithHexError("sample key extraction", | |
521 client_key_extraction.data(), | |
522 client_key_extraction.length(), | |
523 server_key_extraction.data(), | |
524 server_key_extraction.length()); | |
525 } | |
526 | |
527 // static | |
528 QuicTag CryptoTestUtils::ParseTag(const char* tagstr) { | |
529 const size_t len = strlen(tagstr); | |
530 CHECK_NE(0u, len); | |
531 | |
532 QuicTag tag = 0; | |
533 | |
534 if (tagstr[0] == '#') { | |
535 CHECK_EQ(static_cast<size_t>(1 + 2*4), len); | |
536 tagstr++; | |
537 | |
538 for (size_t i = 0; i < 8; i++) { | |
539 tag <<= 4; | |
540 | |
541 uint8 v = 0; | |
542 CHECK(HexChar(tagstr[i], &v)); | |
543 tag |= v; | |
544 } | |
545 | |
546 return tag; | |
547 } | |
548 | |
549 CHECK_LE(len, 4u); | |
550 for (size_t i = 0; i < 4; i++) { | |
551 tag >>= 8; | |
552 if (i < len) { | |
553 tag |= static_cast<uint32>(tagstr[i]) << 24; | |
554 } | |
555 } | |
556 | |
557 return tag; | |
558 } | |
559 | |
560 // static | |
561 CryptoHandshakeMessage CryptoTestUtils::Message(const char* message_tag, ...) { | |
562 va_list ap; | |
563 va_start(ap, message_tag); | |
564 | |
565 CryptoHandshakeMessage message = BuildMessage(message_tag, ap); | |
566 va_end(ap); | |
567 return message; | |
568 } | |
569 | |
570 // static | |
571 CryptoHandshakeMessage CryptoTestUtils::BuildMessage(const char* message_tag, | |
572 va_list ap) { | |
573 CryptoHandshakeMessage msg; | |
574 msg.set_tag(ParseTag(message_tag)); | |
575 | |
576 for (;;) { | |
577 const char* tagstr = va_arg(ap, const char*); | |
578 if (tagstr == nullptr) { | |
579 break; | |
580 } | |
581 | |
582 if (tagstr[0] == '$') { | |
583 // Special value. | |
584 const char* const special = tagstr + 1; | |
585 if (strcmp(special, "padding") == 0) { | |
586 const int min_bytes = va_arg(ap, int); | |
587 msg.set_minimum_size(min_bytes); | |
588 } else { | |
589 CHECK(false) << "Unknown special value: " << special; | |
590 } | |
591 | |
592 continue; | |
593 } | |
594 | |
595 const QuicTag tag = ParseTag(tagstr); | |
596 const char* valuestr = va_arg(ap, const char*); | |
597 | |
598 size_t len = strlen(valuestr); | |
599 if (len > 0 && valuestr[0] == '#') { | |
600 valuestr++; | |
601 len--; | |
602 | |
603 CHECK_EQ(0u, len % 2); | |
604 scoped_ptr<uint8[]> buf(new uint8[len/2]); | |
605 | |
606 for (size_t i = 0; i < len/2; i++) { | |
607 uint8 v = 0; | |
608 CHECK(HexChar(valuestr[i*2], &v)); | |
609 buf[i] = v << 4; | |
610 CHECK(HexChar(valuestr[i*2 + 1], &v)); | |
611 buf[i] |= v; | |
612 } | |
613 | |
614 msg.SetStringPiece( | |
615 tag, StringPiece(reinterpret_cast<char*>(buf.get()), len/2)); | |
616 continue; | |
617 } | |
618 | |
619 msg.SetStringPiece(tag, valuestr); | |
620 } | |
621 | |
622 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure | |
623 // that any padding is included. | |
624 scoped_ptr<QuicData> bytes(CryptoFramer::ConstructHandshakeMessage(msg)); | |
625 scoped_ptr<CryptoHandshakeMessage> parsed( | |
626 CryptoFramer::ParseMessage(bytes->AsStringPiece())); | |
627 CHECK(parsed.get()); | |
628 | |
629 return *parsed; | |
630 } | |
631 | |
632 } // namespace test | |
633 } // namespace net | |
OLD | NEW |