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