• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CryptoFramerVisitor()40   CryptoFramerVisitor()
41       : error_(false) {
42   }
43 
OnError(CryptoFramer * framer)44   virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; }
45 
OnHandshakeMessage(const CryptoHandshakeMessage & message)46   virtual void OnHandshakeMessage(
47       const CryptoHandshakeMessage& message) OVERRIDE {
48     messages_.push_back(message);
49   }
50 
error() const51   bool error() const {
52     return error_;
53   }
54 
messages() const55   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 and has |dest_stream|
66 // process them. |*inout_packet_index| is updated with an index one greater
67 // than the last packet processed.
MovePackets(PacketSavingConnection * source_conn,size_t * inout_packet_index,QuicCryptoStream * dest_stream,PacketSavingConnection * dest_conn)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     ASSERT_TRUE(framer.ProcessPacket(*source_conn->encrypted_packets_[index]));
88     for (vector<QuicStreamFrame>::const_iterator
89          i =  framer.stream_frames().begin();
90          i != framer.stream_frames().end(); ++i) {
91       scoped_ptr<string> frame_data(i->GetDataAsString());
92       ASSERT_TRUE(crypto_framer.ProcessInput(*frame_data));
93       ASSERT_FALSE(crypto_visitor.error());
94     }
95   }
96   *inout_packet_index = index;
97 
98   QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
99 
100   ASSERT_EQ(0u, crypto_framer.InputBytesRemaining());
101 
102   for (vector<CryptoHandshakeMessage>::const_iterator
103        i = crypto_visitor.messages().begin();
104        i != crypto_visitor.messages().end(); ++i) {
105     dest_stream->OnHandshakeMessage(*i);
106   }
107 }
108 
109 // HexChar parses |c| as a hex character. If valid, it sets |*value| to the
110 // value of the hex character and returns true. Otherwise it returns false.
HexChar(char c,uint8 * value)111 bool HexChar(char c, uint8* value) {
112   if (c >= '0' && c <= '9') {
113     *value = c - '0';
114     return true;
115   }
116   if (c >= 'a' && c <= 'f') {
117     *value = c - 'a' + 10;
118     return true;
119   }
120   if (c >= 'A' && c <= 'F') {
121     *value = c - 'A' + 10;
122     return true;
123   }
124   return false;
125 }
126 
127 }  // anonymous namespace
128 
FakeClientOptions()129 CryptoTestUtils::FakeClientOptions::FakeClientOptions()
130     : dont_verify_certs(false),
131       channel_id_enabled(false) {
132 }
133 
134 // static
HandshakeWithFakeServer(PacketSavingConnection * client_conn,QuicCryptoClientStream * client)135 int CryptoTestUtils::HandshakeWithFakeServer(
136     PacketSavingConnection* client_conn,
137     QuicCryptoClientStream* client) {
138   PacketSavingConnection* server_conn =
139       new PacketSavingConnection(true, client_conn->supported_versions());
140   TestSession server_session(server_conn, DefaultQuicConfig());
141 
142   QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING,
143                                        QuicRandom::GetInstance());
144   SetupCryptoServerConfigForTest(
145       server_session.connection()->clock(),
146       server_session.connection()->random_generator(),
147       server_session.config(), &crypto_config);
148 
149   QuicCryptoServerStream server(crypto_config, &server_session);
150   server_session.SetCryptoStream(&server);
151 
152   // The client's handshake must have been started already.
153   CHECK_NE(0u, client_conn->packets_.size());
154 
155   CommunicateHandshakeMessages(client_conn, client, server_conn, &server);
156 
157   CompareClientAndServerKeys(client, &server);
158 
159   return client->num_sent_client_hellos();
160 }
161 
162 // static
HandshakeWithFakeClient(PacketSavingConnection * server_conn,QuicCryptoServerStream * server,const FakeClientOptions & options)163 int CryptoTestUtils::HandshakeWithFakeClient(
164     PacketSavingConnection* server_conn,
165     QuicCryptoServerStream* server,
166     const FakeClientOptions& options) {
167   PacketSavingConnection* client_conn = new PacketSavingConnection(false);
168   TestClientSession client_session(client_conn, DefaultQuicConfig());
169   QuicCryptoClientConfig crypto_config;
170 
171   client_session.config()->SetDefaults();
172   crypto_config.SetDefaults();
173   // TODO(rtenneti): Enable testing of ProofVerifier.
174   // if (!options.dont_verify_certs) {
175   //   crypto_config.SetProofVerifier(ProofVerifierForTesting());
176   // }
177   if (options.channel_id_enabled) {
178     crypto_config.SetChannelIDSource(ChannelIDSourceForTesting());
179   }
180   QuicServerId server_id(kServerHostname, kServerPort, false,
181                          PRIVACY_MODE_DISABLED);
182   QuicCryptoClientStream client(server_id, &client_session, NULL,
183                                 &crypto_config);
184   client_session.SetCryptoStream(&client);
185 
186   CHECK(client.CryptoConnect());
187   CHECK_EQ(1u, client_conn->packets_.size());
188 
189   CommunicateHandshakeMessages(client_conn, &client, server_conn, server);
190 
191   CompareClientAndServerKeys(&client, server);
192 
193   if (options.channel_id_enabled) {
194     scoped_ptr<ChannelIDKey> channel_id_key;
195     QuicAsyncStatus status =
196         crypto_config.channel_id_source()->GetChannelIDKey(kServerHostname,
197                                                            &channel_id_key,
198                                                            NULL);
199     EXPECT_EQ(QUIC_SUCCESS, status);
200     EXPECT_EQ(channel_id_key->SerializeKey(),
201               server->crypto_negotiated_params().channel_id);
202   }
203 
204   return client.num_sent_client_hellos();
205 }
206 
207 // static
SetupCryptoServerConfigForTest(const QuicClock * clock,QuicRandom * rand,QuicConfig * config,QuicCryptoServerConfig * crypto_config)208 void CryptoTestUtils::SetupCryptoServerConfigForTest(
209     const QuicClock* clock,
210     QuicRandom* rand,
211     QuicConfig* config,
212     QuicCryptoServerConfig* crypto_config) {
213   config->SetDefaults();
214   QuicCryptoServerConfig::ConfigOptions options;
215   options.channel_id_enabled = true;
216   scoped_ptr<CryptoHandshakeMessage> scfg(
217       crypto_config->AddDefaultConfig(rand, clock, options));
218 }
219 
220 // static
CommunicateHandshakeMessages(PacketSavingConnection * a_conn,QuicCryptoStream * a,PacketSavingConnection * b_conn,QuicCryptoStream * b)221 void CryptoTestUtils::CommunicateHandshakeMessages(
222     PacketSavingConnection* a_conn,
223     QuicCryptoStream* a,
224     PacketSavingConnection* b_conn,
225     QuicCryptoStream* b) {
226   size_t a_i = 0, b_i = 0;
227   while (!a->handshake_confirmed()) {
228     ASSERT_GT(a_conn->packets_.size(), a_i);
229     LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i
230               << " packets a->b";
231     MovePackets(a_conn, &a_i, b, b_conn);
232 
233     ASSERT_GT(b_conn->packets_.size(), b_i);
234     LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i
235               << " packets b->a";
236     if (b_conn->packets_.size() - b_i == 2) {
237       LOG(INFO) << "here";
238     }
239     MovePackets(b_conn, &b_i, a, a_conn);
240   }
241 }
242 
243 // static
AdvanceHandshake(PacketSavingConnection * a_conn,QuicCryptoStream * a,size_t a_i,PacketSavingConnection * b_conn,QuicCryptoStream * b,size_t b_i)244 pair<size_t, size_t> CryptoTestUtils::AdvanceHandshake(
245     PacketSavingConnection* a_conn,
246     QuicCryptoStream* a,
247     size_t a_i,
248     PacketSavingConnection* b_conn,
249     QuicCryptoStream* b,
250     size_t b_i) {
251   LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i
252             << " packets a->b";
253   MovePackets(a_conn, &a_i, b, b_conn);
254 
255   LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i
256             << " packets b->a";
257   if (b_conn->packets_.size() - b_i == 2) {
258     LOG(INFO) << "here";
259   }
260   MovePackets(b_conn, &b_i, a, a_conn);
261 
262   return make_pair(a_i, b_i);
263 }
264 
265 // static
GetValueForTag(const CryptoHandshakeMessage & message,QuicTag tag)266 string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message,
267                                        QuicTag tag) {
268   QuicTagValueMap::const_iterator it = message.tag_value_map().find(tag);
269   if (it == message.tag_value_map().end()) {
270     return string();
271   }
272   return it->second;
273 }
274 
275 class MockCommonCertSets : public CommonCertSets {
276  public:
MockCommonCertSets(StringPiece cert,uint64 hash,uint32 index)277   MockCommonCertSets(StringPiece cert, uint64 hash, uint32 index)
278       : cert_(cert.as_string()),
279         hash_(hash),
280         index_(index) {
281   }
282 
GetCommonHashes() const283   virtual StringPiece GetCommonHashes() const OVERRIDE {
284     CHECK(false) << "not implemented";
285     return StringPiece();
286   }
287 
GetCert(uint64 hash,uint32 index) const288   virtual StringPiece GetCert(uint64 hash, uint32 index) const OVERRIDE {
289     if (hash == hash_ && index == index_) {
290       return cert_;
291     }
292     return StringPiece();
293   }
294 
MatchCert(StringPiece cert,StringPiece common_set_hashes,uint64 * out_hash,uint32 * out_index) const295   virtual bool MatchCert(StringPiece cert,
296                          StringPiece common_set_hashes,
297                          uint64* out_hash,
298                          uint32* out_index) const OVERRIDE {
299     if (cert != cert_) {
300       return false;
301     }
302 
303     if (common_set_hashes.size() % sizeof(uint64) != 0) {
304       return false;
305     }
306     bool client_has_set = false;
307     for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64)) {
308       uint64 hash;
309       memcpy(&hash, common_set_hashes.data() + i, sizeof(hash));
310       if (hash == hash_) {
311         client_has_set = true;
312         break;
313       }
314     }
315 
316     if (!client_has_set) {
317       return false;
318     }
319 
320     *out_hash = hash_;
321     *out_index = index_;
322     return true;
323   }
324 
325  private:
326   const string cert_;
327   const uint64 hash_;
328   const uint32 index_;
329 };
330 
MockCommonCertSets(StringPiece cert,uint64 hash,uint32 index)331 CommonCertSets* CryptoTestUtils::MockCommonCertSets(StringPiece cert,
332                                                     uint64 hash,
333                                                     uint32 index) {
334   return new class MockCommonCertSets(cert, hash, index);
335 }
336 
CompareClientAndServerKeys(QuicCryptoClientStream * client,QuicCryptoServerStream * server)337 void CryptoTestUtils::CompareClientAndServerKeys(
338     QuicCryptoClientStream* client,
339     QuicCryptoServerStream* server) {
340   const QuicEncrypter* client_encrypter(
341       client->session()->connection()->encrypter(ENCRYPTION_INITIAL));
342   const QuicDecrypter* client_decrypter(
343       client->session()->connection()->decrypter());
344   const QuicEncrypter* client_forward_secure_encrypter(
345       client->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE));
346   const QuicDecrypter* client_forward_secure_decrypter(
347       client->session()->connection()->alternative_decrypter());
348   const QuicEncrypter* server_encrypter(
349       server->session()->connection()->encrypter(ENCRYPTION_INITIAL));
350   const QuicDecrypter* server_decrypter(
351       server->session()->connection()->decrypter());
352   const QuicEncrypter* server_forward_secure_encrypter(
353       server->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE));
354   const QuicDecrypter* server_forward_secure_decrypter(
355       server->session()->connection()->alternative_decrypter());
356 
357   StringPiece client_encrypter_key = client_encrypter->GetKey();
358   StringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix();
359   StringPiece client_decrypter_key = client_decrypter->GetKey();
360   StringPiece client_decrypter_iv = client_decrypter->GetNoncePrefix();
361   StringPiece client_forward_secure_encrypter_key =
362       client_forward_secure_encrypter->GetKey();
363   StringPiece client_forward_secure_encrypter_iv =
364       client_forward_secure_encrypter->GetNoncePrefix();
365   StringPiece client_forward_secure_decrypter_key =
366       client_forward_secure_decrypter->GetKey();
367   StringPiece client_forward_secure_decrypter_iv =
368       client_forward_secure_decrypter->GetNoncePrefix();
369   StringPiece server_encrypter_key = server_encrypter->GetKey();
370   StringPiece server_encrypter_iv = server_encrypter->GetNoncePrefix();
371   StringPiece server_decrypter_key = server_decrypter->GetKey();
372   StringPiece server_decrypter_iv = server_decrypter->GetNoncePrefix();
373   StringPiece server_forward_secure_encrypter_key =
374       server_forward_secure_encrypter->GetKey();
375   StringPiece server_forward_secure_encrypter_iv =
376       server_forward_secure_encrypter->GetNoncePrefix();
377   StringPiece server_forward_secure_decrypter_key =
378       server_forward_secure_decrypter->GetKey();
379   StringPiece server_forward_secure_decrypter_iv =
380       server_forward_secure_decrypter->GetNoncePrefix();
381 
382   CompareCharArraysWithHexError("client write key",
383                                 client_encrypter_key.data(),
384                                 client_encrypter_key.length(),
385                                 server_decrypter_key.data(),
386                                 server_decrypter_key.length());
387   CompareCharArraysWithHexError("client write IV",
388                                 client_encrypter_iv.data(),
389                                 client_encrypter_iv.length(),
390                                 server_decrypter_iv.data(),
391                                 server_decrypter_iv.length());
392   CompareCharArraysWithHexError("server write key",
393                                 server_encrypter_key.data(),
394                                 server_encrypter_key.length(),
395                                 client_decrypter_key.data(),
396                                 client_decrypter_key.length());
397   CompareCharArraysWithHexError("server write IV",
398                                 server_encrypter_iv.data(),
399                                 server_encrypter_iv.length(),
400                                 client_decrypter_iv.data(),
401                                 client_decrypter_iv.length());
402   CompareCharArraysWithHexError("client forward secure write key",
403                                 client_forward_secure_encrypter_key.data(),
404                                 client_forward_secure_encrypter_key.length(),
405                                 server_forward_secure_decrypter_key.data(),
406                                 server_forward_secure_decrypter_key.length());
407   CompareCharArraysWithHexError("client forward secure write IV",
408                                 client_forward_secure_encrypter_iv.data(),
409                                 client_forward_secure_encrypter_iv.length(),
410                                 server_forward_secure_decrypter_iv.data(),
411                                 server_forward_secure_decrypter_iv.length());
412   CompareCharArraysWithHexError("server forward secure write key",
413                                 server_forward_secure_encrypter_key.data(),
414                                 server_forward_secure_encrypter_key.length(),
415                                 client_forward_secure_decrypter_key.data(),
416                                 client_forward_secure_decrypter_key.length());
417   CompareCharArraysWithHexError("server forward secure write IV",
418                                 server_forward_secure_encrypter_iv.data(),
419                                 server_forward_secure_encrypter_iv.length(),
420                                 client_forward_secure_decrypter_iv.data(),
421                                 client_forward_secure_decrypter_iv.length());
422 }
423 
424 // static
ParseTag(const char * tagstr)425 QuicTag CryptoTestUtils::ParseTag(const char* tagstr) {
426   const size_t len = strlen(tagstr);
427   CHECK_NE(0u, len);
428 
429   QuicTag tag = 0;
430 
431   if (tagstr[0] == '#') {
432     CHECK_EQ(static_cast<size_t>(1 + 2*4), len);
433     tagstr++;
434 
435     for (size_t i = 0; i < 8; i++) {
436       tag <<= 4;
437 
438       uint8 v = 0;
439       CHECK(HexChar(tagstr[i], &v));
440       tag |= v;
441     }
442 
443     return tag;
444   }
445 
446   CHECK_LE(len, 4u);
447   for (size_t i = 0; i < 4; i++) {
448     tag >>= 8;
449     if (i < len) {
450       tag |= static_cast<uint32>(tagstr[i]) << 24;
451     }
452   }
453 
454   return tag;
455 }
456 
457 // static
Message(const char * message_tag,...)458 CryptoHandshakeMessage CryptoTestUtils::Message(const char* message_tag, ...) {
459   va_list ap;
460   va_start(ap, message_tag);
461 
462   CryptoHandshakeMessage message = BuildMessage(message_tag, ap);
463   va_end(ap);
464   return message;
465 }
466 
467 // static
BuildMessage(const char * message_tag,va_list ap)468 CryptoHandshakeMessage CryptoTestUtils::BuildMessage(const char* message_tag,
469                                                      va_list ap) {
470   CryptoHandshakeMessage msg;
471   msg.set_tag(ParseTag(message_tag));
472 
473   for (;;) {
474     const char* tagstr = va_arg(ap, const char*);
475     if (tagstr == NULL) {
476       break;
477     }
478 
479     if (tagstr[0] == '$') {
480       // Special value.
481       const char* const special = tagstr + 1;
482       if (strcmp(special, "padding") == 0) {
483         const int min_bytes = va_arg(ap, int);
484         msg.set_minimum_size(min_bytes);
485       } else {
486         CHECK(false) << "Unknown special value: " << special;
487       }
488 
489       continue;
490     }
491 
492     const QuicTag tag = ParseTag(tagstr);
493     const char* valuestr = va_arg(ap, const char*);
494 
495     size_t len = strlen(valuestr);
496     if (len > 0 && valuestr[0] == '#') {
497       valuestr++;
498       len--;
499 
500       CHECK_EQ(0u, len % 2);
501       scoped_ptr<uint8[]> buf(new uint8[len/2]);
502 
503       for (size_t i = 0; i < len/2; i++) {
504         uint8 v = 0;
505         CHECK(HexChar(valuestr[i*2], &v));
506         buf[i] = v << 4;
507         CHECK(HexChar(valuestr[i*2 + 1], &v));
508         buf[i] |= v;
509       }
510 
511       msg.SetStringPiece(
512           tag, StringPiece(reinterpret_cast<char*>(buf.get()), len/2));
513       continue;
514     }
515 
516     msg.SetStringPiece(tag, valuestr);
517   }
518 
519   // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
520   // that any padding is included.
521   scoped_ptr<QuicData> bytes(CryptoFramer::ConstructHandshakeMessage(msg));
522   scoped_ptr<CryptoHandshakeMessage> parsed(
523       CryptoFramer::ParseMessage(bytes->AsStringPiece()));
524   CHECK(parsed.get());
525 
526   return *parsed;
527 }
528 
529 }  // namespace test
530 }  // namespace net
531