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