blob: 86b22e14057569d417d3ae5859ed50536ecc4879 [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]e4c3ea62014-03-15 00:45:1418#include "net/quic/quic_session_key.h"
[email protected]2532de12013-05-09 12:29:3319#include "net/quic/test_tools/quic_connection_peer.h"
[email protected]ed3fc15d2013-03-08 18:37:4420#include "net/quic/test_tools/quic_test_utils.h"
21#include "net/quic/test_tools/simple_quic_framer.h"
[email protected]ed3fc15d2013-03-08 18:37:4422
[email protected]14e8106c2013-03-14 16:25:3323using base::StringPiece;
[email protected]691f45a982013-11-19 10:52:0424using std::make_pair;
25using std::pair;
[email protected]ccc66e8a2013-03-26 08:26:1426using std::string;
[email protected]fe053f92013-04-23 20:18:5527using std::vector;
[email protected]14e8106c2013-03-14 16:25:3328
[email protected]ed3fc15d2013-03-08 18:37:4429namespace net {
30namespace test {
31
32namespace {
33
[email protected]e4c3ea62014-03-15 00:45:1434const char kServerHostname[] = "test.example.com";
35const uint16 kServerPort = 80;
36
[email protected]fe053f92013-04-23 20:18:5537// CryptoFramerVisitor is a framer visitor that records handshake messages.
38class CryptoFramerVisitor : public CryptoFramerVisitorInterface {
39 public:
40 CryptoFramerVisitor()
41 : error_(false) {
42 }
[email protected]ed3fc15d2013-03-08 18:37:4443
[email protected]42091902013-05-02 02:24:1244 virtual void OnError(CryptoFramer* framer) OVERRIDE {
[email protected]fe053f92013-04-23 20:18:5545 error_ = true;
46 }
[email protected]ed3fc15d2013-03-08 18:37:4447
[email protected]42091902013-05-02 02:24:1248 virtual void OnHandshakeMessage(
49 const CryptoHandshakeMessage& message) OVERRIDE {
[email protected]fe053f92013-04-23 20:18:5550 messages_.push_back(message);
51 }
[email protected]ed3fc15d2013-03-08 18:37:4452
[email protected]fe053f92013-04-23 20:18:5553 bool error() const {
54 return error_;
55 }
[email protected]ed3fc15d2013-03-08 18:37:4456
[email protected]fe053f92013-04-23 20:18:5557 const vector<CryptoHandshakeMessage>& messages() const {
58 return messages_;
59 }
[email protected]ed3fc15d2013-03-08 18:37:4460
[email protected]fe053f92013-04-23 20:18:5561 private:
62 bool error_;
63 vector<CryptoHandshakeMessage> messages_;
64};
65
66// MovePackets parses crypto handshake messages from packet number
67// |*inout_packet_index| through to the last packet and has |dest_stream|
68// process them. |*inout_packet_index| is updated with an index one greater
69// than the last packet processed.
70void MovePackets(PacketSavingConnection* source_conn,
71 size_t *inout_packet_index,
[email protected]2532de12013-05-09 12:29:3372 QuicCryptoStream* dest_stream,
73 PacketSavingConnection* dest_conn) {
[email protected]4d640792013-12-18 22:21:0874 SimpleQuicFramer framer(source_conn->supported_versions());
[email protected]fe053f92013-04-23 20:18:5575 CryptoFramer crypto_framer;
76 CryptoFramerVisitor crypto_visitor;
77
[email protected]2532de12013-05-09 12:29:3378 // In order to properly test the code we need to perform encryption and
79 // decryption so that the crypters latch when expected. The crypters are in
80 // |dest_conn|, but we don't want to try and use them there. Instead we swap
81 // them into |framer|, perform the decryption with them, and then swap them
82 // back.
83 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
84
[email protected]fe053f92013-04-23 20:18:5585 crypto_framer.set_visitor(&crypto_visitor);
86
87 size_t index = *inout_packet_index;
[email protected]2532de12013-05-09 12:29:3388 for (; index < source_conn->encrypted_packets_.size(); index++) {
89 ASSERT_TRUE(framer.ProcessPacket(*source_conn->encrypted_packets_[index]));
[email protected]fe053f92013-04-23 20:18:5590 for (vector<QuicStreamFrame>::const_iterator
91 i = framer.stream_frames().begin();
92 i != framer.stream_frames().end(); ++i) {
[email protected]5dafdb62013-11-14 01:24:2693 scoped_ptr<string> frame_data(i->GetDataAsString());
94 ASSERT_TRUE(crypto_framer.ProcessInput(*frame_data));
[email protected]fe053f92013-04-23 20:18:5595 ASSERT_FALSE(crypto_visitor.error());
96 }
97 }
98 *inout_packet_index = index;
99
[email protected]2532de12013-05-09 12:29:33100 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
101
[email protected]fe053f92013-04-23 20:18:55102 ASSERT_EQ(0u, crypto_framer.InputBytesRemaining());
103
104 for (vector<CryptoHandshakeMessage>::const_iterator
105 i = crypto_visitor.messages().begin();
106 i != crypto_visitor.messages().end(); ++i) {
107 dest_stream->OnHandshakeMessage(*i);
[email protected]ed3fc15d2013-03-08 18:37:44108 }
109}
110
[email protected]0bbeb6972013-05-23 04:10:21111// HexChar parses |c| as a hex character. If valid, it sets |*value| to the
112// value of the hex character and returns true. Otherwise it returns false.
113bool HexChar(char c, uint8* value) {
114 if (c >= '0' && c <= '9') {
115 *value = c - '0';
116 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 if (c >= 'A' && c <= 'F') {
[email protected]b064310782013-05-30 21:12:17123 *value = c - 'A' + 10;
[email protected]0bbeb6972013-05-23 04:10:21124 return true;
125 }
126 return false;
127}
128
[email protected]ed3fc15d2013-03-08 18:37:44129} // anonymous namespace
130
[email protected]899951652013-05-16 12:52:39131CryptoTestUtils::FakeClientOptions::FakeClientOptions()
[email protected]b064310782013-05-30 21:12:17132 : dont_verify_certs(false),
133 channel_id_enabled(false) {
[email protected]899951652013-05-16 12:52:39134}
135
[email protected]ed3fc15d2013-03-08 18:37:44136// static
[email protected]fe053f92013-04-23 20:18:55137int CryptoTestUtils::HandshakeWithFakeServer(
[email protected]ed3fc15d2013-03-08 18:37:44138 PacketSavingConnection* client_conn,
[email protected]14e8106c2013-03-14 16:25:33139 QuicCryptoClientStream* client) {
[email protected]4d640792013-12-18 22:21:08140 PacketSavingConnection* server_conn =
141 new PacketSavingConnection(true, client_conn->supported_versions());
[email protected]c05a6d222013-12-16 19:42:03142 TestSession server_session(server_conn, DefaultQuicConfig());
[email protected]ef95114d2013-04-17 17:57:01143
[email protected]b064310782013-05-30 21:12:17144 QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING,
145 QuicRandom::GetInstance());
[email protected]ef95114d2013-04-17 17:57:01146 SetupCryptoServerConfigForTest(
147 server_session.connection()->clock(),
148 server_session.connection()->random_generator(),
[email protected]899951652013-05-16 12:52:39149 server_session.config(), &crypto_config);
[email protected]ef95114d2013-04-17 17:57:01150
[email protected]899951652013-05-16 12:52:39151 QuicCryptoServerStream server(crypto_config, &server_session);
[email protected]2532de12013-05-09 12:29:33152 server_session.SetCryptoStream(&server);
[email protected]ed3fc15d2013-03-08 18:37:44153
154 // The client's handshake must have been started already.
155 CHECK_NE(0u, client_conn->packets_.size());
156
157 CommunicateHandshakeMessages(client_conn, client, server_conn, &server);
[email protected]14e8106c2013-03-14 16:25:33158
159 CompareClientAndServerKeys(client, &server);
[email protected]fe053f92013-04-23 20:18:55160
161 return client->num_sent_client_hellos();
[email protected]ed3fc15d2013-03-08 18:37:44162}
163
164// static
[email protected]fe053f92013-04-23 20:18:55165int CryptoTestUtils::HandshakeWithFakeClient(
[email protected]ed3fc15d2013-03-08 18:37:44166 PacketSavingConnection* server_conn,
[email protected]899951652013-05-16 12:52:39167 QuicCryptoServerStream* server,
168 const FakeClientOptions& options) {
[email protected]c05a6d222013-12-16 19:42:03169 PacketSavingConnection* client_conn = new PacketSavingConnection(false);
170 TestSession client_session(client_conn, DefaultQuicConfig());
[email protected]ef95114d2013-04-17 17:57:01171 QuicCryptoClientConfig crypto_config;
172
[email protected]899951652013-05-16 12:52:39173 client_session.config()->SetDefaults();
[email protected]ef95114d2013-04-17 17:57:01174 crypto_config.SetDefaults();
[email protected]a57e0272013-04-26 07:31:47175 // TODO(rtenneti): Enable testing of ProofVerifier.
[email protected]899951652013-05-16 12:52:39176 // if (!options.dont_verify_certs) {
[email protected]b064310782013-05-30 21:12:17177 // crypto_config.SetProofVerifier(ProofVerifierForTesting());
[email protected]899951652013-05-16 12:52:39178 // }
[email protected]b064310782013-05-30 21:12:17179 if (options.channel_id_enabled) {
180 crypto_config.SetChannelIDSigner(ChannelIDSignerForTesting());
181 }
[email protected]e4c3ea62014-03-15 00:45:14182 QuicSessionKey server_key(kServerHostname, kServerPort, false);
183 QuicCryptoClientStream client(server_key, &client_session, &crypto_config);
[email protected]2532de12013-05-09 12:29:33184 client_session.SetCryptoStream(&client);
[email protected]ed3fc15d2013-03-08 18:37:44185
186 CHECK(client.CryptoConnect());
187 CHECK_EQ(1u, client_conn->packets_.size());
188
189 CommunicateHandshakeMessages(client_conn, &client, server_conn, server);
[email protected]14e8106c2013-03-14 16:25:33190
191 CompareClientAndServerKeys(&client, server);
[email protected]fe053f92013-04-23 20:18:55192
[email protected]38b3fd12013-06-18 08:19:01193 if (options.channel_id_enabled) {
194 EXPECT_EQ(crypto_config.channel_id_signer()->GetKeyForHostname(
[email protected]e4c3ea62014-03-15 00:45:14195 kServerHostname),
[email protected]38b3fd12013-06-18 08:19:01196 server->crypto_negotiated_params().channel_id);
197 }
198
[email protected]fe053f92013-04-23 20:18:55199 return client.num_sent_client_hellos();
[email protected]14e8106c2013-03-14 16:25:33200}
201
202// static
[email protected]ef95114d2013-04-17 17:57:01203void CryptoTestUtils::SetupCryptoServerConfigForTest(
204 const QuicClock* clock,
205 QuicRandom* rand,
206 QuicConfig* config,
207 QuicCryptoServerConfig* crypto_config) {
208 config->SetDefaults();
[email protected]b064310782013-05-30 21:12:17209 QuicCryptoServerConfig::ConfigOptions options;
210 options.channel_id_enabled = true;
[email protected]ef95114d2013-04-17 17:57:01211 scoped_ptr<CryptoHandshakeMessage> scfg(
[email protected]b064310782013-05-30 21:12:17212 crypto_config->AddDefaultConfig(rand, clock, options));
[email protected]ef95114d2013-04-17 17:57:01213}
214
215// static
[email protected]0bbeb6972013-05-23 04:10:21216void CryptoTestUtils::CommunicateHandshakeMessages(
217 PacketSavingConnection* a_conn,
218 QuicCryptoStream* a,
219 PacketSavingConnection* b_conn,
220 QuicCryptoStream* b) {
221 size_t a_i = 0, b_i = 0;
222 while (!a->handshake_confirmed()) {
223 ASSERT_GT(a_conn->packets_.size(), a_i);
[email protected]b46d6992013-11-25 19:30:52224 LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i
[email protected]0bbeb6972013-05-23 04:10:21225 << " packets a->b";
226 MovePackets(a_conn, &a_i, b, b_conn);
227
228 ASSERT_GT(b_conn->packets_.size(), b_i);
[email protected]b46d6992013-11-25 19:30:52229 LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i
[email protected]0bbeb6972013-05-23 04:10:21230 << " packets b->a";
231 if (b_conn->packets_.size() - b_i == 2) {
[email protected]b46d6992013-11-25 19:30:52232 LOG(INFO) << "here";
[email protected]0bbeb6972013-05-23 04:10:21233 }
234 MovePackets(b_conn, &b_i, a, a_conn);
235 }
236}
237
[email protected]691f45a982013-11-19 10:52:04238pair<size_t, size_t> CryptoTestUtils::AdvanceHandshake(
239 PacketSavingConnection* a_conn,
240 QuicCryptoStream* a,
241 size_t a_i,
242 PacketSavingConnection* b_conn,
243 QuicCryptoStream* b,
244 size_t b_i) {
[email protected]b46d6992013-11-25 19:30:52245 LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i
[email protected]691f45a982013-11-19 10:52:04246 << " packets a->b";
247 MovePackets(a_conn, &a_i, b, b_conn);
248
[email protected]b46d6992013-11-25 19:30:52249 LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i
[email protected]691f45a982013-11-19 10:52:04250 << " packets b->a";
251 if (b_conn->packets_.size() - b_i == 2) {
[email protected]b46d6992013-11-25 19:30:52252 LOG(INFO) << "here";
[email protected]691f45a982013-11-19 10:52:04253 }
254 MovePackets(b_conn, &b_i, a, a_conn);
255
256 return make_pair(a_i, b_i);
257}
258
[email protected]0bbeb6972013-05-23 04:10:21259// static
[email protected]ccc66e8a2013-03-26 08:26:14260string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message,
[email protected]2532de12013-05-09 12:29:33261 QuicTag tag) {
262 QuicTagValueMap::const_iterator it = message.tag_value_map().find(tag);
[email protected]ccc66e8a2013-03-26 08:26:14263 if (it == message.tag_value_map().end()) {
264 return string();
265 }
266 return it->second;
267}
268
[email protected]2532de12013-05-09 12:29:33269class MockCommonCertSets : public CommonCertSets {
[email protected]c244c5a12013-05-07 20:55:04270 public:
[email protected]2532de12013-05-09 12:29:33271 MockCommonCertSets(StringPiece cert, uint64 hash, uint32 index)
[email protected]c244c5a12013-05-07 20:55:04272 : cert_(cert.as_string()),
273 hash_(hash),
274 index_(index) {
275 }
276
[email protected]2532de12013-05-09 12:29:33277 virtual StringPiece GetCommonHashes() const OVERRIDE {
[email protected]c244c5a12013-05-07 20:55:04278 CHECK(false) << "not implemented";
279 return StringPiece();
280 }
281
[email protected]2532de12013-05-09 12:29:33282 virtual StringPiece GetCert(uint64 hash, uint32 index) const OVERRIDE {
[email protected]c244c5a12013-05-07 20:55:04283 if (hash == hash_ && index == index_) {
284 return cert_;
285 }
286 return StringPiece();
287 }
288
289 virtual bool MatchCert(StringPiece cert,
290 StringPiece common_set_hashes,
291 uint64* out_hash,
[email protected]2532de12013-05-09 12:29:33292 uint32* out_index) const OVERRIDE {
[email protected]c244c5a12013-05-07 20:55:04293 if (cert != cert_) {
294 return false;
295 }
296
297 if (common_set_hashes.size() % sizeof(uint64) != 0) {
298 return false;
299 }
300 bool client_has_set = false;
301 for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64)) {
302 uint64 hash;
303 memcpy(&hash, common_set_hashes.data() + i, sizeof(hash));
304 if (hash == hash_) {
305 client_has_set = true;
306 break;
307 }
308 }
309
310 if (!client_has_set) {
311 return false;
312 }
313
314 *out_hash = hash_;
315 *out_index = index_;
316 return true;
317 }
318
319 private:
320 const string cert_;
321 const uint64 hash_;
322 const uint32 index_;
323};
324
[email protected]2532de12013-05-09 12:29:33325CommonCertSets* CryptoTestUtils::MockCommonCertSets(StringPiece cert,
[email protected]899951652013-05-16 12:52:39326 uint64 hash,
327 uint32 index) {
[email protected]2532de12013-05-09 12:29:33328 return new class MockCommonCertSets(cert, hash, index);
[email protected]c244c5a12013-05-07 20:55:04329}
330
[email protected]14e8106c2013-03-14 16:25:33331void CryptoTestUtils::CompareClientAndServerKeys(
332 QuicCryptoClientStream* client,
333 QuicCryptoServerStream* server) {
[email protected]8ba81212013-05-03 13:11:48334 const QuicEncrypter* client_encrypter(
335 client->session()->connection()->encrypter(ENCRYPTION_INITIAL));
[email protected]8ba81212013-05-03 13:11:48336 const QuicDecrypter* client_decrypter(
[email protected]2532de12013-05-09 12:29:33337 client->session()->connection()->decrypter());
338 const QuicEncrypter* client_forward_secure_encrypter(
339 client->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE));
340 const QuicDecrypter* client_forward_secure_decrypter(
[email protected]8ba81212013-05-03 13:11:48341 client->session()->connection()->alternative_decrypter());
342 const QuicEncrypter* server_encrypter(
343 server->session()->connection()->encrypter(ENCRYPTION_INITIAL));
344 const QuicDecrypter* server_decrypter(
345 server->session()->connection()->decrypter());
[email protected]2532de12013-05-09 12:29:33346 const QuicEncrypter* server_forward_secure_encrypter(
347 server->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE));
348 const QuicDecrypter* server_forward_secure_decrypter(
349 server->session()->connection()->alternative_decrypter());
[email protected]8ba81212013-05-03 13:11:48350
351 StringPiece client_encrypter_key = client_encrypter->GetKey();
352 StringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix();
353 StringPiece client_decrypter_key = client_decrypter->GetKey();
354 StringPiece client_decrypter_iv = client_decrypter->GetNoncePrefix();
[email protected]2532de12013-05-09 12:29:33355 StringPiece client_forward_secure_encrypter_key =
356 client_forward_secure_encrypter->GetKey();
357 StringPiece client_forward_secure_encrypter_iv =
358 client_forward_secure_encrypter->GetNoncePrefix();
359 StringPiece client_forward_secure_decrypter_key =
360 client_forward_secure_decrypter->GetKey();
361 StringPiece client_forward_secure_decrypter_iv =
362 client_forward_secure_decrypter->GetNoncePrefix();
[email protected]8ba81212013-05-03 13:11:48363 StringPiece server_encrypter_key = server_encrypter->GetKey();
364 StringPiece server_encrypter_iv = server_encrypter->GetNoncePrefix();
365 StringPiece server_decrypter_key = server_decrypter->GetKey();
366 StringPiece server_decrypter_iv = server_decrypter->GetNoncePrefix();
[email protected]2532de12013-05-09 12:29:33367 StringPiece server_forward_secure_encrypter_key =
368 server_forward_secure_encrypter->GetKey();
369 StringPiece server_forward_secure_encrypter_iv =
370 server_forward_secure_encrypter->GetNoncePrefix();
371 StringPiece server_forward_secure_decrypter_key =
372 server_forward_secure_decrypter->GetKey();
373 StringPiece server_forward_secure_decrypter_iv =
374 server_forward_secure_decrypter->GetNoncePrefix();
[email protected]8ba81212013-05-03 13:11:48375
[email protected]14e8106c2013-03-14 16:25:33376 CompareCharArraysWithHexError("client write key",
377 client_encrypter_key.data(),
378 client_encrypter_key.length(),
379 server_decrypter_key.data(),
380 server_decrypter_key.length());
381 CompareCharArraysWithHexError("client write IV",
382 client_encrypter_iv.data(),
383 client_encrypter_iv.length(),
384 server_decrypter_iv.data(),
385 server_decrypter_iv.length());
386 CompareCharArraysWithHexError("server write key",
387 server_encrypter_key.data(),
388 server_encrypter_key.length(),
389 client_decrypter_key.data(),
390 client_decrypter_key.length());
391 CompareCharArraysWithHexError("server write IV",
392 server_encrypter_iv.data(),
393 server_encrypter_iv.length(),
394 client_decrypter_iv.data(),
395 client_decrypter_iv.length());
[email protected]2532de12013-05-09 12:29:33396 CompareCharArraysWithHexError("client forward secure write key",
397 client_forward_secure_encrypter_key.data(),
398 client_forward_secure_encrypter_key.length(),
399 server_forward_secure_decrypter_key.data(),
400 server_forward_secure_decrypter_key.length());
401 CompareCharArraysWithHexError("client forward secure write IV",
402 client_forward_secure_encrypter_iv.data(),
403 client_forward_secure_encrypter_iv.length(),
404 server_forward_secure_decrypter_iv.data(),
405 server_forward_secure_decrypter_iv.length());
406 CompareCharArraysWithHexError("server forward secure write key",
407 server_forward_secure_encrypter_key.data(),
408 server_forward_secure_encrypter_key.length(),
409 client_forward_secure_decrypter_key.data(),
410 client_forward_secure_decrypter_key.length());
411 CompareCharArraysWithHexError("server forward secure write IV",
412 server_forward_secure_encrypter_iv.data(),
413 server_forward_secure_encrypter_iv.length(),
414 client_forward_secure_decrypter_iv.data(),
415 client_forward_secure_decrypter_iv.length());
[email protected]ed3fc15d2013-03-08 18:37:44416}
[email protected]0bbeb6972013-05-23 04:10:21417
418// static
419QuicTag CryptoTestUtils::ParseTag(const char* tagstr) {
420 const size_t len = strlen(tagstr);
421 CHECK_NE(0u, len);
422
423 QuicTag tag = 0;
424
425 if (tagstr[0] == '#') {
426 CHECK_EQ(static_cast<size_t>(1 + 2*4), len);
427 tagstr++;
428
429 for (size_t i = 0; i < 8; i++) {
430 tag <<= 4;
431
432 uint8 v = 0;
433 CHECK(HexChar(tagstr[i], &v));
434 tag |= v;
435 }
436
437 return tag;
438 }
439
440 CHECK_LE(len, 4u);
441 for (size_t i = 0; i < 4; i++) {
442 tag >>= 8;
443 if (i < len) {
444 tag |= static_cast<uint32>(tagstr[i]) << 24;
445 }
446 }
447
448 return tag;
449}
450
451// static
452CryptoHandshakeMessage CryptoTestUtils::Message(const char* message_tag, ...) {
453 va_list ap;
454 va_start(ap, message_tag);
455
456 CryptoHandshakeMessage message = BuildMessage(message_tag, ap);
457 va_end(ap);
458 return message;
459}
460
461// static
462CryptoHandshakeMessage CryptoTestUtils::BuildMessage(const char* message_tag,
463 va_list ap) {
464 CryptoHandshakeMessage msg;
465 msg.set_tag(ParseTag(message_tag));
466
467 for (;;) {
468 const char* tagstr = va_arg(ap, const char*);
469 if (tagstr == NULL) {
470 break;
471 }
472
[email protected]4e49b6a2013-06-18 16:39:28473 if (tagstr[0] == '$') {
474 // Special value.
475 const char* const special = tagstr + 1;
476 if (strcmp(special, "padding") == 0) {
477 const int min_bytes = va_arg(ap, int);
478 msg.set_minimum_size(min_bytes);
479 } else {
480 CHECK(false) << "Unknown special value: " << special;
481 }
482
483 continue;
484 }
485
[email protected]0bbeb6972013-05-23 04:10:21486 const QuicTag tag = ParseTag(tagstr);
487 const char* valuestr = va_arg(ap, const char*);
488
489 size_t len = strlen(valuestr);
490 if (len > 0 && valuestr[0] == '#') {
491 valuestr++;
492 len--;
493
494 CHECK(len % 2 == 0);
495 scoped_ptr<uint8[]> buf(new uint8[len/2]);
496
497 for (size_t i = 0; i < len/2; i++) {
498 uint8 v = 0;
499 CHECK(HexChar(valuestr[i*2], &v));
500 buf[i] = v << 4;
501 CHECK(HexChar(valuestr[i*2 + 1], &v));
502 buf[i] |= v;
503 }
504
505 msg.SetStringPiece(
506 tag, StringPiece(reinterpret_cast<char*>(buf.get()), len/2));
507 continue;
508 }
509
510 msg.SetStringPiece(tag, valuestr);
511 }
512
[email protected]4e49b6a2013-06-18 16:39:28513 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
514 // that any padding is included.
515 scoped_ptr<QuicData> bytes(CryptoFramer::ConstructHandshakeMessage(msg));
516 scoped_ptr<CryptoHandshakeMessage> parsed(
517 CryptoFramer::ParseMessage(bytes->AsStringPiece()));
518 CHECK(parsed.get());
519
520 return *parsed;
[email protected]0bbeb6972013-05-23 04:10:21521}
522
[email protected]ed3fc15d2013-03-08 18:37:44523} // namespace test
524} // namespace net