blob: a6b6cc1ed8551d2b05c07a7609d7e0685ecd3fa3 [file] [log] [blame]
[email protected]ed3fc15d2013-03-08 18:37:441// 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"
[email protected]72818ea2013-03-13 03:23:576
[email protected]38b3fd12013-06-18 08:19:017#include "net/quic/crypto/channel_id.h"
[email protected]c244c5a12013-05-07 20:55:048#include "net/quic/crypto/common_cert_set.h"
[email protected]ef95114d2013-04-17 17:57:019#include "net/quic/crypto/crypto_handshake.h"
[email protected]8e01c062013-10-31 07:35:3110#include "net/quic/crypto/quic_crypto_server_config.h"
[email protected]14e8106c2013-03-14 16:25:3311#include "net/quic/crypto/quic_decrypter.h"
12#include "net/quic/crypto/quic_encrypter.h"
[email protected]ef95114d2013-04-17 17:57:0113#include "net/quic/crypto/quic_random.h"
14#include "net/quic/quic_clock.h"
[email protected]ed3fc15d2013-03-08 18:37:4415#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"
[email protected]2532de12013-05-09 12:29:3318#include "net/quic/test_tools/quic_connection_peer.h"
[email protected]ed3fc15d2013-03-08 18:37:4419#include "net/quic/test_tools/quic_test_utils.h"
20#include "net/quic/test_tools/simple_quic_framer.h"
[email protected]ed3fc15d2013-03-08 18:37:4421
[email protected]14e8106c2013-03-14 16:25:3322using base::StringPiece;
[email protected]691f45a982013-11-19 10:52:0423using std::make_pair;
24using std::pair;
[email protected]ccc66e8a2013-03-26 08:26:1425using std::string;
[email protected]fe053f92013-04-23 20:18:5526using std::vector;
[email protected]14e8106c2013-03-14 16:25:3327
[email protected]ed3fc15d2013-03-08 18:37:4428namespace net {
29namespace test {
30
31namespace {
32
[email protected]fe053f92013-04-23 20:18:5533// CryptoFramerVisitor is a framer visitor that records handshake messages.
34class CryptoFramerVisitor : public CryptoFramerVisitorInterface {
35 public:
36 CryptoFramerVisitor()
37 : error_(false) {
38 }
[email protected]ed3fc15d2013-03-08 18:37:4439
[email protected]42091902013-05-02 02:24:1240 virtual void OnError(CryptoFramer* framer) OVERRIDE {
[email protected]fe053f92013-04-23 20:18:5541 error_ = true;
42 }
[email protected]ed3fc15d2013-03-08 18:37:4443
[email protected]42091902013-05-02 02:24:1244 virtual void OnHandshakeMessage(
45 const CryptoHandshakeMessage& message) OVERRIDE {
[email protected]fe053f92013-04-23 20:18:5546 messages_.push_back(message);
47 }
[email protected]ed3fc15d2013-03-08 18:37:4448
[email protected]fe053f92013-04-23 20:18:5549 bool error() const {
50 return error_;
51 }
[email protected]ed3fc15d2013-03-08 18:37:4452
[email protected]fe053f92013-04-23 20:18:5553 const vector<CryptoHandshakeMessage>& messages() const {
54 return messages_;
55 }
[email protected]ed3fc15d2013-03-08 18:37:4456
[email protected]fe053f92013-04-23 20:18:5557 private:
58 bool error_;
59 vector<CryptoHandshakeMessage> messages_;
60};
61
62// MovePackets parses crypto handshake messages from packet number
63// |*inout_packet_index| through to the last packet and has |dest_stream|
64// process them. |*inout_packet_index| is updated with an index one greater
65// than the last packet processed.
66void MovePackets(PacketSavingConnection* source_conn,
67 size_t *inout_packet_index,
[email protected]2532de12013-05-09 12:29:3368 QuicCryptoStream* dest_stream,
69 PacketSavingConnection* dest_conn) {
[email protected]fe053f92013-04-23 20:18:5570 SimpleQuicFramer framer;
71 CryptoFramer crypto_framer;
72 CryptoFramerVisitor crypto_visitor;
73
[email protected]2532de12013-05-09 12:29:3374 // In order to properly test the code we need to perform encryption and
75 // decryption so that the crypters latch when expected. The crypters are in
76 // |dest_conn|, but we don't want to try and use them there. Instead we swap
77 // them into |framer|, perform the decryption with them, and then swap them
78 // back.
79 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
80
[email protected]fe053f92013-04-23 20:18:5581 crypto_framer.set_visitor(&crypto_visitor);
82
83 size_t index = *inout_packet_index;
[email protected]2532de12013-05-09 12:29:3384 for (; index < source_conn->encrypted_packets_.size(); index++) {
85 ASSERT_TRUE(framer.ProcessPacket(*source_conn->encrypted_packets_[index]));
[email protected]fe053f92013-04-23 20:18:5586 for (vector<QuicStreamFrame>::const_iterator
87 i = framer.stream_frames().begin();
88 i != framer.stream_frames().end(); ++i) {
[email protected]5dafdb62013-11-14 01:24:2689 scoped_ptr<string> frame_data(i->GetDataAsString());
90 ASSERT_TRUE(crypto_framer.ProcessInput(*frame_data));
[email protected]fe053f92013-04-23 20:18:5591 ASSERT_FALSE(crypto_visitor.error());
92 }
93 }
94 *inout_packet_index = index;
95
[email protected]2532de12013-05-09 12:29:3396 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
97
[email protected]fe053f92013-04-23 20:18:5598 ASSERT_EQ(0u, crypto_framer.InputBytesRemaining());
99
100 for (vector<CryptoHandshakeMessage>::const_iterator
101 i = crypto_visitor.messages().begin();
102 i != crypto_visitor.messages().end(); ++i) {
103 dest_stream->OnHandshakeMessage(*i);
[email protected]ed3fc15d2013-03-08 18:37:44104 }
105}
106
[email protected]0bbeb6972013-05-23 04:10:21107// HexChar parses |c| as a hex character. If valid, it sets |*value| to the
108// value of the hex character and returns true. Otherwise it returns false.
109bool HexChar(char c, uint8* value) {
110 if (c >= '0' && c <= '9') {
111 *value = c - '0';
112 return true;
113 }
114 if (c >= 'a' && c <= 'f') {
[email protected]b064310782013-05-30 21:12:17115 *value = c - 'a' + 10;
[email protected]0bbeb6972013-05-23 04:10:21116 return true;
117 }
118 if (c >= 'A' && c <= 'F') {
[email protected]b064310782013-05-30 21:12:17119 *value = c - 'A' + 10;
[email protected]0bbeb6972013-05-23 04:10:21120 return true;
121 }
122 return false;
123}
124
[email protected]ed3fc15d2013-03-08 18:37:44125} // anonymous namespace
126
[email protected]899951652013-05-16 12:52:39127CryptoTestUtils::FakeClientOptions::FakeClientOptions()
[email protected]b064310782013-05-30 21:12:17128 : dont_verify_certs(false),
129 channel_id_enabled(false) {
[email protected]899951652013-05-16 12:52:39130}
131
[email protected]ed3fc15d2013-03-08 18:37:44132// static
[email protected]fe053f92013-04-23 20:18:55133int CryptoTestUtils::HandshakeWithFakeServer(
[email protected]ed3fc15d2013-03-08 18:37:44134 PacketSavingConnection* client_conn,
[email protected]14e8106c2013-03-14 16:25:33135 QuicCryptoClientStream* client) {
[email protected]c05a6d222013-12-16 19:42:03136 PacketSavingConnection* server_conn = new PacketSavingConnection(true);
137 TestSession server_session(server_conn, DefaultQuicConfig());
[email protected]ef95114d2013-04-17 17:57:01138
[email protected]b064310782013-05-30 21:12:17139 QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING,
140 QuicRandom::GetInstance());
[email protected]ef95114d2013-04-17 17:57:01141 SetupCryptoServerConfigForTest(
142 server_session.connection()->clock(),
143 server_session.connection()->random_generator(),
[email protected]899951652013-05-16 12:52:39144 server_session.config(), &crypto_config);
[email protected]ef95114d2013-04-17 17:57:01145
[email protected]899951652013-05-16 12:52:39146 QuicCryptoServerStream server(crypto_config, &server_session);
[email protected]2532de12013-05-09 12:29:33147 server_session.SetCryptoStream(&server);
[email protected]ed3fc15d2013-03-08 18:37:44148
149 // The client's handshake must have been started already.
150 CHECK_NE(0u, client_conn->packets_.size());
151
152 CommunicateHandshakeMessages(client_conn, client, server_conn, &server);
[email protected]14e8106c2013-03-14 16:25:33153
154 CompareClientAndServerKeys(client, &server);
[email protected]fe053f92013-04-23 20:18:55155
156 return client->num_sent_client_hellos();
[email protected]ed3fc15d2013-03-08 18:37:44157}
158
159// static
[email protected]fe053f92013-04-23 20:18:55160int CryptoTestUtils::HandshakeWithFakeClient(
[email protected]ed3fc15d2013-03-08 18:37:44161 PacketSavingConnection* server_conn,
[email protected]899951652013-05-16 12:52:39162 QuicCryptoServerStream* server,
163 const FakeClientOptions& options) {
[email protected]c05a6d222013-12-16 19:42:03164 PacketSavingConnection* client_conn = new PacketSavingConnection(false);
165 TestSession client_session(client_conn, DefaultQuicConfig());
[email protected]ef95114d2013-04-17 17:57:01166 QuicCryptoClientConfig crypto_config;
167
[email protected]899951652013-05-16 12:52:39168 client_session.config()->SetDefaults();
[email protected]ef95114d2013-04-17 17:57:01169 crypto_config.SetDefaults();
[email protected]a57e0272013-04-26 07:31:47170 // TODO(rtenneti): Enable testing of ProofVerifier.
[email protected]899951652013-05-16 12:52:39171 // if (!options.dont_verify_certs) {
[email protected]b064310782013-05-30 21:12:17172 // crypto_config.SetProofVerifier(ProofVerifierForTesting());
[email protected]899951652013-05-16 12:52:39173 // }
[email protected]b064310782013-05-30 21:12:17174 if (options.channel_id_enabled) {
175 crypto_config.SetChannelIDSigner(ChannelIDSignerForTesting());
176 }
[email protected]899951652013-05-16 12:52:39177 QuicCryptoClientStream client("test.example.com", &client_session,
[email protected]ef95114d2013-04-17 17:57:01178 &crypto_config);
[email protected]2532de12013-05-09 12:29:33179 client_session.SetCryptoStream(&client);
[email protected]ed3fc15d2013-03-08 18:37:44180
181 CHECK(client.CryptoConnect());
182 CHECK_EQ(1u, client_conn->packets_.size());
183
184 CommunicateHandshakeMessages(client_conn, &client, server_conn, server);
[email protected]14e8106c2013-03-14 16:25:33185
186 CompareClientAndServerKeys(&client, server);
[email protected]fe053f92013-04-23 20:18:55187
[email protected]38b3fd12013-06-18 08:19:01188 if (options.channel_id_enabled) {
189 EXPECT_EQ(crypto_config.channel_id_signer()->GetKeyForHostname(
190 "test.example.com"),
191 server->crypto_negotiated_params().channel_id);
192 }
193
[email protected]fe053f92013-04-23 20:18:55194 return client.num_sent_client_hellos();
[email protected]14e8106c2013-03-14 16:25:33195}
196
197// static
[email protected]ef95114d2013-04-17 17:57:01198void CryptoTestUtils::SetupCryptoServerConfigForTest(
199 const QuicClock* clock,
200 QuicRandom* rand,
201 QuicConfig* config,
202 QuicCryptoServerConfig* crypto_config) {
203 config->SetDefaults();
[email protected]b064310782013-05-30 21:12:17204 QuicCryptoServerConfig::ConfigOptions options;
205 options.channel_id_enabled = true;
[email protected]ef95114d2013-04-17 17:57:01206 scoped_ptr<CryptoHandshakeMessage> scfg(
[email protected]b064310782013-05-30 21:12:17207 crypto_config->AddDefaultConfig(rand, clock, options));
[email protected]ef95114d2013-04-17 17:57:01208}
209
210// static
[email protected]0bbeb6972013-05-23 04:10:21211void CryptoTestUtils::CommunicateHandshakeMessages(
212 PacketSavingConnection* a_conn,
213 QuicCryptoStream* a,
214 PacketSavingConnection* b_conn,
215 QuicCryptoStream* b) {
216 size_t a_i = 0, b_i = 0;
217 while (!a->handshake_confirmed()) {
218 ASSERT_GT(a_conn->packets_.size(), a_i);
[email protected]b46d6992013-11-25 19:30:52219 LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i
[email protected]0bbeb6972013-05-23 04:10:21220 << " packets a->b";
221 MovePackets(a_conn, &a_i, b, b_conn);
222
223 ASSERT_GT(b_conn->packets_.size(), b_i);
[email protected]b46d6992013-11-25 19:30:52224 LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i
[email protected]0bbeb6972013-05-23 04:10:21225 << " packets b->a";
226 if (b_conn->packets_.size() - b_i == 2) {
[email protected]b46d6992013-11-25 19:30:52227 LOG(INFO) << "here";
[email protected]0bbeb6972013-05-23 04:10:21228 }
229 MovePackets(b_conn, &b_i, a, a_conn);
230 }
231}
232
[email protected]691f45a982013-11-19 10:52:04233pair<size_t, size_t> CryptoTestUtils::AdvanceHandshake(
234 PacketSavingConnection* a_conn,
235 QuicCryptoStream* a,
236 size_t a_i,
237 PacketSavingConnection* b_conn,
238 QuicCryptoStream* b,
239 size_t b_i) {
[email protected]b46d6992013-11-25 19:30:52240 LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i
[email protected]691f45a982013-11-19 10:52:04241 << " packets a->b";
242 MovePackets(a_conn, &a_i, b, b_conn);
243
[email protected]b46d6992013-11-25 19:30:52244 LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i
[email protected]691f45a982013-11-19 10:52:04245 << " packets b->a";
246 if (b_conn->packets_.size() - b_i == 2) {
[email protected]b46d6992013-11-25 19:30:52247 LOG(INFO) << "here";
[email protected]691f45a982013-11-19 10:52:04248 }
249 MovePackets(b_conn, &b_i, a, a_conn);
250
251 return make_pair(a_i, b_i);
252}
253
[email protected]0bbeb6972013-05-23 04:10:21254// static
[email protected]ccc66e8a2013-03-26 08:26:14255string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message,
[email protected]2532de12013-05-09 12:29:33256 QuicTag tag) {
257 QuicTagValueMap::const_iterator it = message.tag_value_map().find(tag);
[email protected]ccc66e8a2013-03-26 08:26:14258 if (it == message.tag_value_map().end()) {
259 return string();
260 }
261 return it->second;
262}
263
[email protected]2532de12013-05-09 12:29:33264class MockCommonCertSets : public CommonCertSets {
[email protected]c244c5a12013-05-07 20:55:04265 public:
[email protected]2532de12013-05-09 12:29:33266 MockCommonCertSets(StringPiece cert, uint64 hash, uint32 index)
[email protected]c244c5a12013-05-07 20:55:04267 : cert_(cert.as_string()),
268 hash_(hash),
269 index_(index) {
270 }
271
[email protected]2532de12013-05-09 12:29:33272 virtual StringPiece GetCommonHashes() const OVERRIDE {
[email protected]c244c5a12013-05-07 20:55:04273 CHECK(false) << "not implemented";
274 return StringPiece();
275 }
276
[email protected]2532de12013-05-09 12:29:33277 virtual StringPiece GetCert(uint64 hash, uint32 index) const OVERRIDE {
[email protected]c244c5a12013-05-07 20:55:04278 if (hash == hash_ && index == index_) {
279 return cert_;
280 }
281 return StringPiece();
282 }
283
284 virtual bool MatchCert(StringPiece cert,
285 StringPiece common_set_hashes,
286 uint64* out_hash,
[email protected]2532de12013-05-09 12:29:33287 uint32* out_index) const OVERRIDE {
[email protected]c244c5a12013-05-07 20:55:04288 if (cert != cert_) {
289 return false;
290 }
291
292 if (common_set_hashes.size() % sizeof(uint64) != 0) {
293 return false;
294 }
295 bool client_has_set = false;
296 for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64)) {
297 uint64 hash;
298 memcpy(&hash, common_set_hashes.data() + i, sizeof(hash));
299 if (hash == hash_) {
300 client_has_set = true;
301 break;
302 }
303 }
304
305 if (!client_has_set) {
306 return false;
307 }
308
309 *out_hash = hash_;
310 *out_index = index_;
311 return true;
312 }
313
314 private:
315 const string cert_;
316 const uint64 hash_;
317 const uint32 index_;
318};
319
[email protected]2532de12013-05-09 12:29:33320CommonCertSets* CryptoTestUtils::MockCommonCertSets(StringPiece cert,
[email protected]899951652013-05-16 12:52:39321 uint64 hash,
322 uint32 index) {
[email protected]2532de12013-05-09 12:29:33323 return new class MockCommonCertSets(cert, hash, index);
[email protected]c244c5a12013-05-07 20:55:04324}
325
[email protected]14e8106c2013-03-14 16:25:33326void CryptoTestUtils::CompareClientAndServerKeys(
327 QuicCryptoClientStream* client,
328 QuicCryptoServerStream* server) {
[email protected]8ba81212013-05-03 13:11:48329 const QuicEncrypter* client_encrypter(
330 client->session()->connection()->encrypter(ENCRYPTION_INITIAL));
[email protected]8ba81212013-05-03 13:11:48331 const QuicDecrypter* client_decrypter(
[email protected]2532de12013-05-09 12:29:33332 client->session()->connection()->decrypter());
333 const QuicEncrypter* client_forward_secure_encrypter(
334 client->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE));
335 const QuicDecrypter* client_forward_secure_decrypter(
[email protected]8ba81212013-05-03 13:11:48336 client->session()->connection()->alternative_decrypter());
337 const QuicEncrypter* server_encrypter(
338 server->session()->connection()->encrypter(ENCRYPTION_INITIAL));
339 const QuicDecrypter* server_decrypter(
340 server->session()->connection()->decrypter());
[email protected]2532de12013-05-09 12:29:33341 const QuicEncrypter* server_forward_secure_encrypter(
342 server->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE));
343 const QuicDecrypter* server_forward_secure_decrypter(
344 server->session()->connection()->alternative_decrypter());
[email protected]8ba81212013-05-03 13:11:48345
346 StringPiece client_encrypter_key = client_encrypter->GetKey();
347 StringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix();
348 StringPiece client_decrypter_key = client_decrypter->GetKey();
349 StringPiece client_decrypter_iv = client_decrypter->GetNoncePrefix();
[email protected]2532de12013-05-09 12:29:33350 StringPiece client_forward_secure_encrypter_key =
351 client_forward_secure_encrypter->GetKey();
352 StringPiece client_forward_secure_encrypter_iv =
353 client_forward_secure_encrypter->GetNoncePrefix();
354 StringPiece client_forward_secure_decrypter_key =
355 client_forward_secure_decrypter->GetKey();
356 StringPiece client_forward_secure_decrypter_iv =
357 client_forward_secure_decrypter->GetNoncePrefix();
[email protected]8ba81212013-05-03 13:11:48358 StringPiece server_encrypter_key = server_encrypter->GetKey();
359 StringPiece server_encrypter_iv = server_encrypter->GetNoncePrefix();
360 StringPiece server_decrypter_key = server_decrypter->GetKey();
361 StringPiece server_decrypter_iv = server_decrypter->GetNoncePrefix();
[email protected]2532de12013-05-09 12:29:33362 StringPiece server_forward_secure_encrypter_key =
363 server_forward_secure_encrypter->GetKey();
364 StringPiece server_forward_secure_encrypter_iv =
365 server_forward_secure_encrypter->GetNoncePrefix();
366 StringPiece server_forward_secure_decrypter_key =
367 server_forward_secure_decrypter->GetKey();
368 StringPiece server_forward_secure_decrypter_iv =
369 server_forward_secure_decrypter->GetNoncePrefix();
[email protected]8ba81212013-05-03 13:11:48370
[email protected]14e8106c2013-03-14 16:25:33371 CompareCharArraysWithHexError("client write key",
372 client_encrypter_key.data(),
373 client_encrypter_key.length(),
374 server_decrypter_key.data(),
375 server_decrypter_key.length());
376 CompareCharArraysWithHexError("client write IV",
377 client_encrypter_iv.data(),
378 client_encrypter_iv.length(),
379 server_decrypter_iv.data(),
380 server_decrypter_iv.length());
381 CompareCharArraysWithHexError("server write key",
382 server_encrypter_key.data(),
383 server_encrypter_key.length(),
384 client_decrypter_key.data(),
385 client_decrypter_key.length());
386 CompareCharArraysWithHexError("server write IV",
387 server_encrypter_iv.data(),
388 server_encrypter_iv.length(),
389 client_decrypter_iv.data(),
390 client_decrypter_iv.length());
[email protected]2532de12013-05-09 12:29:33391 CompareCharArraysWithHexError("client forward secure write key",
392 client_forward_secure_encrypter_key.data(),
393 client_forward_secure_encrypter_key.length(),
394 server_forward_secure_decrypter_key.data(),
395 server_forward_secure_decrypter_key.length());
396 CompareCharArraysWithHexError("client forward secure write IV",
397 client_forward_secure_encrypter_iv.data(),
398 client_forward_secure_encrypter_iv.length(),
399 server_forward_secure_decrypter_iv.data(),
400 server_forward_secure_decrypter_iv.length());
401 CompareCharArraysWithHexError("server forward secure write key",
402 server_forward_secure_encrypter_key.data(),
403 server_forward_secure_encrypter_key.length(),
404 client_forward_secure_decrypter_key.data(),
405 client_forward_secure_decrypter_key.length());
406 CompareCharArraysWithHexError("server forward secure write IV",
407 server_forward_secure_encrypter_iv.data(),
408 server_forward_secure_encrypter_iv.length(),
409 client_forward_secure_decrypter_iv.data(),
410 client_forward_secure_decrypter_iv.length());
[email protected]ed3fc15d2013-03-08 18:37:44411}
[email protected]0bbeb6972013-05-23 04:10:21412
413// static
414QuicTag CryptoTestUtils::ParseTag(const char* tagstr) {
415 const size_t len = strlen(tagstr);
416 CHECK_NE(0u, len);
417
418 QuicTag tag = 0;
419
420 if (tagstr[0] == '#') {
421 CHECK_EQ(static_cast<size_t>(1 + 2*4), len);
422 tagstr++;
423
424 for (size_t i = 0; i < 8; i++) {
425 tag <<= 4;
426
427 uint8 v = 0;
428 CHECK(HexChar(tagstr[i], &v));
429 tag |= v;
430 }
431
432 return tag;
433 }
434
435 CHECK_LE(len, 4u);
436 for (size_t i = 0; i < 4; i++) {
437 tag >>= 8;
438 if (i < len) {
439 tag |= static_cast<uint32>(tagstr[i]) << 24;
440 }
441 }
442
443 return tag;
444}
445
446// static
447CryptoHandshakeMessage CryptoTestUtils::Message(const char* message_tag, ...) {
448 va_list ap;
449 va_start(ap, message_tag);
450
451 CryptoHandshakeMessage message = BuildMessage(message_tag, ap);
452 va_end(ap);
453 return message;
454}
455
456// static
457CryptoHandshakeMessage CryptoTestUtils::BuildMessage(const char* message_tag,
458 va_list ap) {
459 CryptoHandshakeMessage msg;
460 msg.set_tag(ParseTag(message_tag));
461
462 for (;;) {
463 const char* tagstr = va_arg(ap, const char*);
464 if (tagstr == NULL) {
465 break;
466 }
467
[email protected]4e49b6a2013-06-18 16:39:28468 if (tagstr[0] == '$') {
469 // Special value.
470 const char* const special = tagstr + 1;
471 if (strcmp(special, "padding") == 0) {
472 const int min_bytes = va_arg(ap, int);
473 msg.set_minimum_size(min_bytes);
474 } else {
475 CHECK(false) << "Unknown special value: " << special;
476 }
477
478 continue;
479 }
480
[email protected]0bbeb6972013-05-23 04:10:21481 const QuicTag tag = ParseTag(tagstr);
482 const char* valuestr = va_arg(ap, const char*);
483
484 size_t len = strlen(valuestr);
485 if (len > 0 && valuestr[0] == '#') {
486 valuestr++;
487 len--;
488
489 CHECK(len % 2 == 0);
490 scoped_ptr<uint8[]> buf(new uint8[len/2]);
491
492 for (size_t i = 0; i < len/2; i++) {
493 uint8 v = 0;
494 CHECK(HexChar(valuestr[i*2], &v));
495 buf[i] = v << 4;
496 CHECK(HexChar(valuestr[i*2 + 1], &v));
497 buf[i] |= v;
498 }
499
500 msg.SetStringPiece(
501 tag, StringPiece(reinterpret_cast<char*>(buf.get()), len/2));
502 continue;
503 }
504
505 msg.SetStringPiece(tag, valuestr);
506 }
507
[email protected]4e49b6a2013-06-18 16:39:28508 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
509 // that any padding is included.
510 scoped_ptr<QuicData> bytes(CryptoFramer::ConstructHandshakeMessage(msg));
511 scoped_ptr<CryptoHandshakeMessage> parsed(
512 CryptoFramer::ParseMessage(bytes->AsStringPiece()));
513 CHECK(parsed.get());
514
515 return *parsed;
[email protected]0bbeb6972013-05-23 04:10:21516}
517
[email protected]ed3fc15d2013-03-08 18:37:44518} // namespace test
519} // namespace net