Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / net / quic / test_tools / crypto_test_utils.cc
blob1f3da2b7463fa5de1bac403f8eb7a7bbce26a9cb
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.
5 #include "net/quic/test_tools/crypto_test_utils.h"
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_framer_peer.h"
21 #include "net/quic/test_tools/quic_test_utils.h"
22 #include "net/quic/test_tools/simple_quic_framer.h"
24 using base::StringPiece;
25 using std::make_pair;
26 using std::pair;
27 using std::string;
28 using std::vector;
30 namespace net {
31 namespace test {
33 namespace {
35 const char kServerHostname[] = "test.example.com";
36 const uint16 kServerPort = 80;
38 // CryptoFramerVisitor is a framer visitor that records handshake messages.
39 class CryptoFramerVisitor : public CryptoFramerVisitorInterface {
40 public:
41 CryptoFramerVisitor()
42 : error_(false) {
45 void OnError(CryptoFramer* framer) override { error_ = true; }
47 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
48 messages_.push_back(message);
51 bool error() const {
52 return error_;
55 const vector<CryptoHandshakeMessage>& messages() const {
56 return messages_;
59 private:
60 bool error_;
61 vector<CryptoHandshakeMessage> messages_;
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;
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());
83 crypto_framer.set_visitor(&crypto_visitor);
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;
93 for (const QuicStreamFrame& stream_frame : framer.stream_frames()) {
94 ASSERT_TRUE(crypto_framer.ProcessInput(stream_frame.data));
95 ASSERT_FALSE(crypto_visitor.error());
98 *inout_packet_index = index;
100 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
102 ASSERT_EQ(0u, crypto_framer.InputBytesRemaining());
104 for (const CryptoHandshakeMessage& message : crypto_visitor.messages()) {
105 dest_stream->OnHandshakeMessage(message);
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.
111 bool HexChar(char c, uint8* value) {
112 if (c >= '0' && c <= '9') {
113 *value = c - '0';
114 return true;
116 if (c >= 'a' && c <= 'f') {
117 *value = c - 'a' + 10;
118 return true;
120 if (c >= 'A' && c <= 'F') {
121 *value = c - 'A' + 10;
122 return true;
124 return false;
127 // A ChannelIDSource that works in asynchronous mode unless the |callback|
128 // argument to GetChannelIDKey is nullptr.
129 class AsyncTestChannelIDSource : public ChannelIDSource,
130 public CryptoTestUtils::CallbackSource {
131 public:
132 // Takes ownership of |sync_source|, a synchronous ChannelIDSource.
133 explicit AsyncTestChannelIDSource(ChannelIDSource* sync_source)
134 : sync_source_(sync_source) {}
135 ~AsyncTestChannelIDSource() override {}
137 // ChannelIDSource implementation.
138 QuicAsyncStatus GetChannelIDKey(const string& hostname,
139 scoped_ptr<ChannelIDKey>* channel_id_key,
140 ChannelIDSourceCallback* callback) override {
141 // Synchronous mode.
142 if (!callback) {
143 return sync_source_->GetChannelIDKey(hostname, channel_id_key, nullptr);
146 // Asynchronous mode.
147 QuicAsyncStatus status =
148 sync_source_->GetChannelIDKey(hostname, &channel_id_key_, nullptr);
149 if (status != QUIC_SUCCESS) {
150 return QUIC_FAILURE;
152 callback_.reset(callback);
153 return QUIC_PENDING;
156 // CallbackSource implementation.
157 void RunPendingCallbacks() override {
158 if (callback_.get()) {
159 callback_->Run(&channel_id_key_);
160 callback_.reset();
164 private:
165 scoped_ptr<ChannelIDSource> sync_source_;
166 scoped_ptr<ChannelIDSourceCallback> callback_;
167 scoped_ptr<ChannelIDKey> channel_id_key_;
170 } // anonymous namespace
172 CryptoTestUtils::FakeClientOptions::FakeClientOptions()
173 : dont_verify_certs(false),
174 channel_id_enabled(false),
175 channel_id_source_async(false) {
178 // static
179 int CryptoTestUtils::HandshakeWithFakeServer(
180 PacketSavingConnection* client_conn,
181 QuicCryptoClientStream* client) {
182 PacketSavingConnection* server_conn = new PacketSavingConnection(
183 Perspective::IS_SERVER, client_conn->supported_versions());
185 QuicConfig config = DefaultQuicConfig();
186 QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING,
187 QuicRandom::GetInstance());
188 SetupCryptoServerConfigForTest(server_conn->clock(),
189 server_conn->random_generator(), &config,
190 &crypto_config);
192 TestQuicSpdyServerSession server_session(server_conn, config, &crypto_config);
194 // The client's handshake must have been started already.
195 CHECK_NE(0u, client_conn->encrypted_packets_.size());
197 CommunicateHandshakeMessages(client_conn, client, server_conn,
198 server_session.GetCryptoStream());
200 CompareClientAndServerKeys(client, server_session.GetCryptoStream());
202 return client->num_sent_client_hellos();
205 // static
206 int CryptoTestUtils::HandshakeWithFakeClient(
207 PacketSavingConnection* server_conn,
208 QuicCryptoServerStream* server,
209 const FakeClientOptions& options) {
210 PacketSavingConnection* client_conn =
211 new PacketSavingConnection(Perspective::IS_CLIENT);
212 // Advance the time, because timers do not like uninitialized times.
213 client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
215 QuicCryptoClientConfig crypto_config;
216 bool is_https = false;
217 AsyncTestChannelIDSource* async_channel_id_source = nullptr;
218 if (options.channel_id_enabled) {
219 is_https = true;
221 ChannelIDSource* source = ChannelIDSourceForTesting();
222 if (options.channel_id_source_async) {
223 async_channel_id_source = new AsyncTestChannelIDSource(source);
224 source = async_channel_id_source;
226 crypto_config.SetChannelIDSource(source);
228 QuicServerId server_id(kServerHostname, kServerPort, is_https,
229 PRIVACY_MODE_DISABLED);
230 if (!options.dont_verify_certs) {
231 #if defined(USE_OPENSSL)
232 crypto_config.SetProofVerifier(ProofVerifierForTesting());
233 #else
234 // TODO(rch): Implement a NSS proof source.
235 crypto_config.SetProofVerifier(FakeProofVerifierForTesting());
236 #endif
238 TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
239 server_id, &crypto_config);
241 client_session.GetCryptoStream()->CryptoConnect();
242 CHECK_EQ(1u, client_conn->encrypted_packets_.size());
244 CommunicateHandshakeMessagesAndRunCallbacks(
245 client_conn, client_session.GetCryptoStream(), server_conn, server,
246 async_channel_id_source);
248 CompareClientAndServerKeys(client_session.GetCryptoStream(), server);
250 if (options.channel_id_enabled) {
251 scoped_ptr<ChannelIDKey> channel_id_key;
252 QuicAsyncStatus status = crypto_config.channel_id_source()->GetChannelIDKey(
253 kServerHostname, &channel_id_key, nullptr);
254 EXPECT_EQ(QUIC_SUCCESS, status);
255 EXPECT_EQ(channel_id_key->SerializeKey(),
256 server->crypto_negotiated_params().channel_id);
257 EXPECT_EQ(
258 options.channel_id_source_async,
259 client_session.GetCryptoStream()->WasChannelIDSourceCallbackRun());
262 return client_session.GetCryptoStream()->num_sent_client_hellos();
265 // static
266 void CryptoTestUtils::SetupCryptoServerConfigForTest(
267 const QuicClock* clock,
268 QuicRandom* rand,
269 QuicConfig* config,
270 QuicCryptoServerConfig* crypto_config) {
271 QuicCryptoServerConfig::ConfigOptions options;
272 options.channel_id_enabled = true;
273 scoped_ptr<CryptoHandshakeMessage> scfg(
274 crypto_config->AddDefaultConfig(rand, clock, options));
277 // static
278 void CryptoTestUtils::CommunicateHandshakeMessages(
279 PacketSavingConnection* a_conn,
280 QuicCryptoStream* a,
281 PacketSavingConnection* b_conn,
282 QuicCryptoStream* b) {
283 CommunicateHandshakeMessagesAndRunCallbacks(a_conn, a, b_conn, b, nullptr);
286 // static
287 void CryptoTestUtils::CommunicateHandshakeMessagesAndRunCallbacks(
288 PacketSavingConnection* a_conn,
289 QuicCryptoStream* a,
290 PacketSavingConnection* b_conn,
291 QuicCryptoStream* b,
292 CallbackSource* callback_source) {
293 size_t a_i = 0, b_i = 0;
294 while (!a->handshake_confirmed()) {
295 ASSERT_GT(a_conn->encrypted_packets_.size(), a_i);
296 VLOG(1) << "Processing " << a_conn->encrypted_packets_.size() - a_i
297 << " packets a->b";
298 MovePackets(a_conn, &a_i, b, b_conn);
299 if (callback_source) {
300 callback_source->RunPendingCallbacks();
303 ASSERT_GT(b_conn->encrypted_packets_.size(), b_i);
304 VLOG(1) << "Processing " << b_conn->encrypted_packets_.size() - b_i
305 << " packets b->a";
306 MovePackets(b_conn, &b_i, a, a_conn);
307 if (callback_source) {
308 callback_source->RunPendingCallbacks();
313 // static
314 pair<size_t, size_t> CryptoTestUtils::AdvanceHandshake(
315 PacketSavingConnection* a_conn,
316 QuicCryptoStream* a,
317 size_t a_i,
318 PacketSavingConnection* b_conn,
319 QuicCryptoStream* b,
320 size_t b_i) {
321 VLOG(1) << "Processing " << a_conn->encrypted_packets_.size() - a_i
322 << " packets a->b";
323 MovePackets(a_conn, &a_i, b, b_conn);
325 VLOG(1) << "Processing " << b_conn->encrypted_packets_.size() - b_i
326 << " packets b->a";
327 if (b_conn->encrypted_packets_.size() - b_i == 2) {
328 VLOG(1) << "here";
330 MovePackets(b_conn, &b_i, a, a_conn);
332 return std::make_pair(a_i, b_i);
335 // static
336 string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message,
337 QuicTag tag) {
338 QuicTagValueMap::const_iterator it = message.tag_value_map().find(tag);
339 if (it == message.tag_value_map().end()) {
340 return string();
342 return it->second;
345 class MockCommonCertSets : public CommonCertSets {
346 public:
347 MockCommonCertSets(StringPiece cert, uint64 hash, uint32 index)
348 : cert_(cert.as_string()),
349 hash_(hash),
350 index_(index) {
353 StringPiece GetCommonHashes() const override {
354 CHECK(false) << "not implemented";
355 return StringPiece();
358 StringPiece GetCert(uint64 hash, uint32 index) const override {
359 if (hash == hash_ && index == index_) {
360 return cert_;
362 return StringPiece();
365 bool MatchCert(StringPiece cert,
366 StringPiece common_set_hashes,
367 uint64* out_hash,
368 uint32* out_index) const override {
369 if (cert != cert_) {
370 return false;
373 if (common_set_hashes.size() % sizeof(uint64) != 0) {
374 return false;
376 bool client_has_set = false;
377 for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64)) {
378 uint64 hash;
379 memcpy(&hash, common_set_hashes.data() + i, sizeof(hash));
380 if (hash == hash_) {
381 client_has_set = true;
382 break;
386 if (!client_has_set) {
387 return false;
390 *out_hash = hash_;
391 *out_index = index_;
392 return true;
395 private:
396 const string cert_;
397 const uint64 hash_;
398 const uint32 index_;
401 CommonCertSets* CryptoTestUtils::MockCommonCertSets(StringPiece cert,
402 uint64 hash,
403 uint32 index) {
404 return new class MockCommonCertSets(cert, hash, index);
407 void CryptoTestUtils::CompareClientAndServerKeys(
408 QuicCryptoClientStream* client,
409 QuicCryptoServerStream* server) {
410 QuicFramer* client_framer =
411 QuicConnectionPeer::GetFramer(client->session()->connection());
412 QuicFramer* server_framer =
413 QuicConnectionPeer::GetFramer(server->session()->connection());
414 const QuicEncrypter* client_encrypter(
415 QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_INITIAL));
416 const QuicDecrypter* client_decrypter(
417 client->session()->connection()->decrypter());
418 const QuicEncrypter* client_forward_secure_encrypter(
419 QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_FORWARD_SECURE));
420 const QuicDecrypter* client_forward_secure_decrypter(
421 client->session()->connection()->alternative_decrypter());
422 const QuicEncrypter* server_encrypter(
423 QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_INITIAL));
424 const QuicDecrypter* server_decrypter(
425 server->session()->connection()->decrypter());
426 const QuicEncrypter* server_forward_secure_encrypter(
427 QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_FORWARD_SECURE));
428 const QuicDecrypter* server_forward_secure_decrypter(
429 server->session()->connection()->alternative_decrypter());
431 StringPiece client_encrypter_key = client_encrypter->GetKey();
432 StringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix();
433 StringPiece client_decrypter_key = client_decrypter->GetKey();
434 StringPiece client_decrypter_iv = client_decrypter->GetNoncePrefix();
435 StringPiece client_forward_secure_encrypter_key =
436 client_forward_secure_encrypter->GetKey();
437 StringPiece client_forward_secure_encrypter_iv =
438 client_forward_secure_encrypter->GetNoncePrefix();
439 StringPiece client_forward_secure_decrypter_key =
440 client_forward_secure_decrypter->GetKey();
441 StringPiece client_forward_secure_decrypter_iv =
442 client_forward_secure_decrypter->GetNoncePrefix();
443 StringPiece server_encrypter_key = server_encrypter->GetKey();
444 StringPiece server_encrypter_iv = server_encrypter->GetNoncePrefix();
445 StringPiece server_decrypter_key = server_decrypter->GetKey();
446 StringPiece server_decrypter_iv = server_decrypter->GetNoncePrefix();
447 StringPiece server_forward_secure_encrypter_key =
448 server_forward_secure_encrypter->GetKey();
449 StringPiece server_forward_secure_encrypter_iv =
450 server_forward_secure_encrypter->GetNoncePrefix();
451 StringPiece server_forward_secure_decrypter_key =
452 server_forward_secure_decrypter->GetKey();
453 StringPiece server_forward_secure_decrypter_iv =
454 server_forward_secure_decrypter->GetNoncePrefix();
456 StringPiece client_subkey_secret =
457 client->crypto_negotiated_params().subkey_secret;
458 StringPiece server_subkey_secret =
459 server->crypto_negotiated_params().subkey_secret;
462 const char kSampleLabel[] = "label";
463 const char kSampleContext[] = "context";
464 const size_t kSampleOutputLength = 32;
465 string client_key_extraction;
466 string server_key_extraction;
467 EXPECT_TRUE(client->ExportKeyingMaterial(kSampleLabel,
468 kSampleContext,
469 kSampleOutputLength,
470 &client_key_extraction));
471 EXPECT_TRUE(server->ExportKeyingMaterial(kSampleLabel,
472 kSampleContext,
473 kSampleOutputLength,
474 &server_key_extraction));
476 CompareCharArraysWithHexError("client write key",
477 client_encrypter_key.data(),
478 client_encrypter_key.length(),
479 server_decrypter_key.data(),
480 server_decrypter_key.length());
481 CompareCharArraysWithHexError("client write IV",
482 client_encrypter_iv.data(),
483 client_encrypter_iv.length(),
484 server_decrypter_iv.data(),
485 server_decrypter_iv.length());
486 CompareCharArraysWithHexError("server write key",
487 server_encrypter_key.data(),
488 server_encrypter_key.length(),
489 client_decrypter_key.data(),
490 client_decrypter_key.length());
491 CompareCharArraysWithHexError("server write IV",
492 server_encrypter_iv.data(),
493 server_encrypter_iv.length(),
494 client_decrypter_iv.data(),
495 client_decrypter_iv.length());
496 CompareCharArraysWithHexError("client forward secure write key",
497 client_forward_secure_encrypter_key.data(),
498 client_forward_secure_encrypter_key.length(),
499 server_forward_secure_decrypter_key.data(),
500 server_forward_secure_decrypter_key.length());
501 CompareCharArraysWithHexError("client forward secure write IV",
502 client_forward_secure_encrypter_iv.data(),
503 client_forward_secure_encrypter_iv.length(),
504 server_forward_secure_decrypter_iv.data(),
505 server_forward_secure_decrypter_iv.length());
506 CompareCharArraysWithHexError("server forward secure write key",
507 server_forward_secure_encrypter_key.data(),
508 server_forward_secure_encrypter_key.length(),
509 client_forward_secure_decrypter_key.data(),
510 client_forward_secure_decrypter_key.length());
511 CompareCharArraysWithHexError("server forward secure write IV",
512 server_forward_secure_encrypter_iv.data(),
513 server_forward_secure_encrypter_iv.length(),
514 client_forward_secure_decrypter_iv.data(),
515 client_forward_secure_decrypter_iv.length());
516 CompareCharArraysWithHexError("subkey secret",
517 client_subkey_secret.data(),
518 client_subkey_secret.length(),
519 server_subkey_secret.data(),
520 server_subkey_secret.length());
521 CompareCharArraysWithHexError("sample key extraction",
522 client_key_extraction.data(),
523 client_key_extraction.length(),
524 server_key_extraction.data(),
525 server_key_extraction.length());
528 // static
529 QuicTag CryptoTestUtils::ParseTag(const char* tagstr) {
530 const size_t len = strlen(tagstr);
531 CHECK_NE(0u, len);
533 QuicTag tag = 0;
535 if (tagstr[0] == '#') {
536 CHECK_EQ(static_cast<size_t>(1 + 2*4), len);
537 tagstr++;
539 for (size_t i = 0; i < 8; i++) {
540 tag <<= 4;
542 uint8 v = 0;
543 CHECK(HexChar(tagstr[i], &v));
544 tag |= v;
547 return tag;
550 CHECK_LE(len, 4u);
551 for (size_t i = 0; i < 4; i++) {
552 tag >>= 8;
553 if (i < len) {
554 tag |= static_cast<uint32>(tagstr[i]) << 24;
558 return tag;
561 // static
562 CryptoHandshakeMessage CryptoTestUtils::Message(const char* message_tag, ...) {
563 va_list ap;
564 va_start(ap, message_tag);
566 CryptoHandshakeMessage msg;
567 msg.set_tag(ParseTag(message_tag));
569 for (;;) {
570 const char* tagstr = va_arg(ap, const char*);
571 if (tagstr == nullptr) {
572 break;
575 if (tagstr[0] == '$') {
576 // Special value.
577 const char* const special = tagstr + 1;
578 if (strcmp(special, "padding") == 0) {
579 const int min_bytes = va_arg(ap, int);
580 msg.set_minimum_size(min_bytes);
581 } else {
582 CHECK(false) << "Unknown special value: " << special;
585 continue;
588 const QuicTag tag = ParseTag(tagstr);
589 const char* valuestr = va_arg(ap, const char*);
591 size_t len = strlen(valuestr);
592 if (len > 0 && valuestr[0] == '#') {
593 valuestr++;
594 len--;
596 CHECK_EQ(0u, len % 2);
597 scoped_ptr<uint8[]> buf(new uint8[len/2]);
599 for (size_t i = 0; i < len/2; i++) {
600 uint8 v = 0;
601 CHECK(HexChar(valuestr[i*2], &v));
602 buf[i] = v << 4;
603 CHECK(HexChar(valuestr[i*2 + 1], &v));
604 buf[i] |= v;
607 msg.SetStringPiece(
608 tag, StringPiece(reinterpret_cast<char*>(buf.get()), len/2));
609 continue;
612 msg.SetStringPiece(tag, valuestr);
615 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
616 // that any padding is included.
617 scoped_ptr<QuicData> bytes(CryptoFramer::ConstructHandshakeMessage(msg));
618 scoped_ptr<CryptoHandshakeMessage> parsed(
619 CryptoFramer::ParseMessage(bytes->AsStringPiece()));
620 CHECK(parsed.get());
622 va_end(ap);
623 return *parsed;
626 } // namespace test
627 } // namespace net