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_test_utils.h"
21 #include "net/quic/test_tools/simple_quic_framer.h"
23 using base::StringPiece
;
34 const char kServerHostname
[] = "test.example.com";
35 const uint16 kServerPort
= 80;
37 // CryptoFramerVisitor is a framer visitor that records handshake messages.
38 class CryptoFramerVisitor
: public CryptoFramerVisitorInterface
{
44 void OnError(CryptoFramer
* framer
) override
{ error_
= true; }
46 void OnHandshakeMessage(const CryptoHandshakeMessage
& message
) override
{
47 messages_
.push_back(message
);
54 const vector
<CryptoHandshakeMessage
>& messages() const {
60 vector
<CryptoHandshakeMessage
> messages_
;
63 // MovePackets parses crypto handshake messages from packet number
64 // |*inout_packet_index| through to the last packet (or until a packet fails to
65 // decrypt) and has |dest_stream| process them. |*inout_packet_index| is updated
66 // with an index one greater than the last packet processed.
67 void MovePackets(PacketSavingConnection
* source_conn
,
68 size_t *inout_packet_index
,
69 QuicCryptoStream
* dest_stream
,
70 PacketSavingConnection
* dest_conn
) {
71 SimpleQuicFramer
framer(source_conn
->supported_versions());
72 CryptoFramer crypto_framer
;
73 CryptoFramerVisitor crypto_visitor
;
75 // In order to properly test the code we need to perform encryption and
76 // decryption so that the crypters latch when expected. The crypters are in
77 // |dest_conn|, but we don't want to try and use them there. Instead we swap
78 // them into |framer|, perform the decryption with them, and then swap them
80 QuicConnectionPeer::SwapCrypters(dest_conn
, framer
.framer());
82 crypto_framer
.set_visitor(&crypto_visitor
);
84 size_t index
= *inout_packet_index
;
85 for (; index
< source_conn
->encrypted_packets_
.size(); index
++) {
86 if (!framer
.ProcessPacket(*source_conn
->encrypted_packets_
[index
])) {
87 // The framer will be unable to decrypt forward-secure packets sent after
88 // the handshake is complete. Don't treat them as handshake packets.
92 for (vector
<QuicStreamFrame
>::const_iterator
93 i
= framer
.stream_frames().begin();
94 i
!= framer
.stream_frames().end(); ++i
) {
95 scoped_ptr
<string
> frame_data(i
->GetDataAsString());
96 ASSERT_TRUE(crypto_framer
.ProcessInput(*frame_data
));
97 ASSERT_FALSE(crypto_visitor
.error());
100 *inout_packet_index
= index
;
102 QuicConnectionPeer::SwapCrypters(dest_conn
, framer
.framer());
104 ASSERT_EQ(0u, crypto_framer
.InputBytesRemaining());
106 for (vector
<CryptoHandshakeMessage
>::const_iterator
107 i
= crypto_visitor
.messages().begin();
108 i
!= crypto_visitor
.messages().end(); ++i
) {
109 dest_stream
->OnHandshakeMessage(*i
);
113 // HexChar parses |c| as a hex character. If valid, it sets |*value| to the
114 // value of the hex character and returns true. Otherwise it returns false.
115 bool HexChar(char c
, uint8
* value
) {
116 if (c
>= '0' && c
<= '9') {
120 if (c
>= 'a' && c
<= 'f') {
121 *value
= c
- 'a' + 10;
124 if (c
>= 'A' && c
<= 'F') {
125 *value
= c
- 'A' + 10;
131 // A ChannelIDSource that works in asynchronous mode unless the |callback|
132 // argument to GetChannelIDKey is nullptr.
133 class AsyncTestChannelIDSource
: public ChannelIDSource
,
134 public CryptoTestUtils::CallbackSource
{
136 // Takes ownership of |sync_source|, a synchronous ChannelIDSource.
137 explicit AsyncTestChannelIDSource(ChannelIDSource
* sync_source
)
138 : sync_source_(sync_source
) {}
139 ~AsyncTestChannelIDSource() override
{}
141 // ChannelIDSource implementation.
142 QuicAsyncStatus
GetChannelIDKey(const string
& hostname
,
143 scoped_ptr
<ChannelIDKey
>* channel_id_key
,
144 ChannelIDSourceCallback
* callback
) override
{
147 return sync_source_
->GetChannelIDKey(hostname
, channel_id_key
, nullptr);
150 // Asynchronous mode.
151 QuicAsyncStatus status
=
152 sync_source_
->GetChannelIDKey(hostname
, &channel_id_key_
, nullptr);
153 if (status
!= QUIC_SUCCESS
) {
156 callback_
.reset(callback
);
160 // CallbackSource implementation.
161 void RunPendingCallbacks() override
{
162 if (callback_
.get()) {
163 callback_
->Run(&channel_id_key_
);
169 scoped_ptr
<ChannelIDSource
> sync_source_
;
170 scoped_ptr
<ChannelIDSourceCallback
> callback_
;
171 scoped_ptr
<ChannelIDKey
> channel_id_key_
;
174 } // anonymous namespace
176 CryptoTestUtils::FakeClientOptions::FakeClientOptions()
177 : dont_verify_certs(false),
178 channel_id_enabled(false),
179 channel_id_source_async(false) {
183 int CryptoTestUtils::HandshakeWithFakeServer(
184 PacketSavingConnection
* client_conn
,
185 QuicCryptoClientStream
* client
) {
186 PacketSavingConnection
* server_conn
=
187 new PacketSavingConnection(true, client_conn
->supported_versions());
188 TestSession
server_session(server_conn
, DefaultQuicConfig());
189 server_session
.InitializeSession();
190 QuicCryptoServerConfig
crypto_config(QuicCryptoServerConfig::TESTING
,
191 QuicRandom::GetInstance());
193 SetupCryptoServerConfigForTest(
194 server_session
.connection()->clock(),
195 server_session
.connection()->random_generator(),
196 server_session
.config(), &crypto_config
);
198 QuicCryptoServerStream
server(crypto_config
, &server_session
);
199 server_session
.SetCryptoStream(&server
);
201 // The client's handshake must have been started already.
202 CHECK_NE(0u, client_conn
->encrypted_packets_
.size());
204 CommunicateHandshakeMessages(client_conn
, client
, server_conn
, &server
);
206 CompareClientAndServerKeys(client
, &server
);
208 return client
->num_sent_client_hellos();
212 int CryptoTestUtils::HandshakeWithFakeClient(
213 PacketSavingConnection
* server_conn
,
214 QuicCryptoServerStream
* server
,
215 const FakeClientOptions
& options
) {
216 PacketSavingConnection
* client_conn
= new PacketSavingConnection(false);
217 // Advance the time, because timers do not like uninitialized times.
218 client_conn
->AdvanceTime(QuicTime::Delta::FromSeconds(1));
219 TestClientSession
client_session(client_conn
, DefaultQuicConfig());
220 QuicCryptoClientConfig crypto_config
;
222 if (!options
.dont_verify_certs
) {
223 // TODO(wtc): replace this with ProofVerifierForTesting() when we have
224 // a working ProofSourceForTesting().
225 crypto_config
.SetProofVerifier(FakeProofVerifierForTesting());
227 bool is_https
= false;
228 AsyncTestChannelIDSource
* async_channel_id_source
= nullptr;
229 if (options
.channel_id_enabled
) {
232 ChannelIDSource
* source
= ChannelIDSourceForTesting();
233 if (options
.channel_id_source_async
) {
234 async_channel_id_source
= new AsyncTestChannelIDSource(source
);
235 source
= async_channel_id_source
;
237 crypto_config
.SetChannelIDSource(source
);
239 QuicServerId
server_id(kServerHostname
, kServerPort
, is_https
,
240 PRIVACY_MODE_DISABLED
);
241 QuicCryptoClientStream
client(server_id
, &client_session
,
242 ProofVerifyContextForTesting(),
244 client_session
.SetCryptoStream(&client
);
246 client
.CryptoConnect();
247 CHECK_EQ(1u, client_conn
->encrypted_packets_
.size());
249 CommunicateHandshakeMessagesAndRunCallbacks(
250 client_conn
, &client
, server_conn
, server
, async_channel_id_source
);
252 CompareClientAndServerKeys(&client
, server
);
254 if (options
.channel_id_enabled
) {
255 scoped_ptr
<ChannelIDKey
> channel_id_key
;
256 QuicAsyncStatus status
= crypto_config
.channel_id_source()->GetChannelIDKey(
257 kServerHostname
, &channel_id_key
, nullptr);
258 EXPECT_EQ(QUIC_SUCCESS
, status
);
259 EXPECT_EQ(channel_id_key
->SerializeKey(),
260 server
->crypto_negotiated_params().channel_id
);
261 EXPECT_EQ(options
.channel_id_source_async
,
262 client
.WasChannelIDSourceCallbackRun());
265 return client
.num_sent_client_hellos();
269 void CryptoTestUtils::SetupCryptoServerConfigForTest(
270 const QuicClock
* clock
,
273 QuicCryptoServerConfig
* crypto_config
) {
274 QuicCryptoServerConfig::ConfigOptions options
;
275 options
.channel_id_enabled
= true;
276 scoped_ptr
<CryptoHandshakeMessage
> scfg(
277 crypto_config
->AddDefaultConfig(rand
, clock
, options
));
281 void CryptoTestUtils::CommunicateHandshakeMessages(
282 PacketSavingConnection
* a_conn
,
284 PacketSavingConnection
* b_conn
,
285 QuicCryptoStream
* b
) {
286 CommunicateHandshakeMessagesAndRunCallbacks(a_conn
, a
, b_conn
, b
, nullptr);
290 void CryptoTestUtils::CommunicateHandshakeMessagesAndRunCallbacks(
291 PacketSavingConnection
* a_conn
,
293 PacketSavingConnection
* b_conn
,
295 CallbackSource
* callback_source
) {
296 size_t a_i
= 0, b_i
= 0;
297 while (!a
->handshake_confirmed()) {
298 ASSERT_GT(a_conn
->encrypted_packets_
.size(), a_i
);
299 VLOG(1) << "Processing " << a_conn
->encrypted_packets_
.size() - a_i
301 MovePackets(a_conn
, &a_i
, b
, b_conn
);
302 if (callback_source
) {
303 callback_source
->RunPendingCallbacks();
306 ASSERT_GT(b_conn
->encrypted_packets_
.size(), b_i
);
307 VLOG(1) << "Processing " << b_conn
->encrypted_packets_
.size() - b_i
309 MovePackets(b_conn
, &b_i
, a
, a_conn
);
310 if (callback_source
) {
311 callback_source
->RunPendingCallbacks();
317 pair
<size_t, size_t> CryptoTestUtils::AdvanceHandshake(
318 PacketSavingConnection
* a_conn
,
321 PacketSavingConnection
* b_conn
,
324 VLOG(1) << "Processing " << a_conn
->encrypted_packets_
.size() - a_i
326 MovePackets(a_conn
, &a_i
, b
, b_conn
);
328 VLOG(1) << "Processing " << b_conn
->encrypted_packets_
.size() - b_i
330 if (b_conn
->encrypted_packets_
.size() - b_i
== 2) {
333 MovePackets(b_conn
, &b_i
, a
, a_conn
);
335 return std::make_pair(a_i
, b_i
);
339 string
CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage
& message
,
341 QuicTagValueMap::const_iterator it
= message
.tag_value_map().find(tag
);
342 if (it
== message
.tag_value_map().end()) {
348 class MockCommonCertSets
: public CommonCertSets
{
350 MockCommonCertSets(StringPiece cert
, uint64 hash
, uint32 index
)
351 : cert_(cert
.as_string()),
356 StringPiece
GetCommonHashes() const override
{
357 CHECK(false) << "not implemented";
358 return StringPiece();
361 StringPiece
GetCert(uint64 hash
, uint32 index
) const override
{
362 if (hash
== hash_
&& index
== index_
) {
365 return StringPiece();
368 bool MatchCert(StringPiece cert
,
369 StringPiece common_set_hashes
,
371 uint32
* out_index
) const override
{
376 if (common_set_hashes
.size() % sizeof(uint64
) != 0) {
379 bool client_has_set
= false;
380 for (size_t i
= 0; i
< common_set_hashes
.size(); i
+= sizeof(uint64
)) {
382 memcpy(&hash
, common_set_hashes
.data() + i
, sizeof(hash
));
384 client_has_set
= true;
389 if (!client_has_set
) {
404 CommonCertSets
* CryptoTestUtils::MockCommonCertSets(StringPiece cert
,
407 return new class MockCommonCertSets(cert
, hash
, index
);
410 void CryptoTestUtils::CompareClientAndServerKeys(
411 QuicCryptoClientStream
* client
,
412 QuicCryptoServerStream
* server
) {
413 const QuicEncrypter
* client_encrypter(
414 client
->session()->connection()->encrypter(ENCRYPTION_INITIAL
));
415 const QuicDecrypter
* client_decrypter(
416 client
->session()->connection()->decrypter());
417 const QuicEncrypter
* client_forward_secure_encrypter(
418 client
->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE
));
419 const QuicDecrypter
* client_forward_secure_decrypter(
420 client
->session()->connection()->alternative_decrypter());
421 const QuicEncrypter
* server_encrypter(
422 server
->session()->connection()->encrypter(ENCRYPTION_INITIAL
));
423 const QuicDecrypter
* server_decrypter(
424 server
->session()->connection()->decrypter());
425 const QuicEncrypter
* server_forward_secure_encrypter(
426 server
->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE
));
427 const QuicDecrypter
* server_forward_secure_decrypter(
428 server
->session()->connection()->alternative_decrypter());
430 StringPiece client_encrypter_key
= client_encrypter
->GetKey();
431 StringPiece client_encrypter_iv
= client_encrypter
->GetNoncePrefix();
432 StringPiece client_decrypter_key
= client_decrypter
->GetKey();
433 StringPiece client_decrypter_iv
= client_decrypter
->GetNoncePrefix();
434 StringPiece client_forward_secure_encrypter_key
=
435 client_forward_secure_encrypter
->GetKey();
436 StringPiece client_forward_secure_encrypter_iv
=
437 client_forward_secure_encrypter
->GetNoncePrefix();
438 StringPiece client_forward_secure_decrypter_key
=
439 client_forward_secure_decrypter
->GetKey();
440 StringPiece client_forward_secure_decrypter_iv
=
441 client_forward_secure_decrypter
->GetNoncePrefix();
442 StringPiece server_encrypter_key
= server_encrypter
->GetKey();
443 StringPiece server_encrypter_iv
= server_encrypter
->GetNoncePrefix();
444 StringPiece server_decrypter_key
= server_decrypter
->GetKey();
445 StringPiece server_decrypter_iv
= server_decrypter
->GetNoncePrefix();
446 StringPiece server_forward_secure_encrypter_key
=
447 server_forward_secure_encrypter
->GetKey();
448 StringPiece server_forward_secure_encrypter_iv
=
449 server_forward_secure_encrypter
->GetNoncePrefix();
450 StringPiece server_forward_secure_decrypter_key
=
451 server_forward_secure_decrypter
->GetKey();
452 StringPiece server_forward_secure_decrypter_iv
=
453 server_forward_secure_decrypter
->GetNoncePrefix();
455 StringPiece client_subkey_secret
=
456 client
->crypto_negotiated_params().subkey_secret
;
457 StringPiece server_subkey_secret
=
458 server
->crypto_negotiated_params().subkey_secret
;
461 const char kSampleLabel
[] = "label";
462 const char kSampleContext
[] = "context";
463 const size_t kSampleOutputLength
= 32;
464 string client_key_extraction
;
465 string server_key_extraction
;
466 EXPECT_TRUE(client
->ExportKeyingMaterial(kSampleLabel
,
469 &client_key_extraction
));
470 EXPECT_TRUE(server
->ExportKeyingMaterial(kSampleLabel
,
473 &server_key_extraction
));
475 CompareCharArraysWithHexError("client write key",
476 client_encrypter_key
.data(),
477 client_encrypter_key
.length(),
478 server_decrypter_key
.data(),
479 server_decrypter_key
.length());
480 CompareCharArraysWithHexError("client write IV",
481 client_encrypter_iv
.data(),
482 client_encrypter_iv
.length(),
483 server_decrypter_iv
.data(),
484 server_decrypter_iv
.length());
485 CompareCharArraysWithHexError("server write key",
486 server_encrypter_key
.data(),
487 server_encrypter_key
.length(),
488 client_decrypter_key
.data(),
489 client_decrypter_key
.length());
490 CompareCharArraysWithHexError("server write IV",
491 server_encrypter_iv
.data(),
492 server_encrypter_iv
.length(),
493 client_decrypter_iv
.data(),
494 client_decrypter_iv
.length());
495 CompareCharArraysWithHexError("client forward secure write key",
496 client_forward_secure_encrypter_key
.data(),
497 client_forward_secure_encrypter_key
.length(),
498 server_forward_secure_decrypter_key
.data(),
499 server_forward_secure_decrypter_key
.length());
500 CompareCharArraysWithHexError("client forward secure write IV",
501 client_forward_secure_encrypter_iv
.data(),
502 client_forward_secure_encrypter_iv
.length(),
503 server_forward_secure_decrypter_iv
.data(),
504 server_forward_secure_decrypter_iv
.length());
505 CompareCharArraysWithHexError("server forward secure write key",
506 server_forward_secure_encrypter_key
.data(),
507 server_forward_secure_encrypter_key
.length(),
508 client_forward_secure_decrypter_key
.data(),
509 client_forward_secure_decrypter_key
.length());
510 CompareCharArraysWithHexError("server forward secure write IV",
511 server_forward_secure_encrypter_iv
.data(),
512 server_forward_secure_encrypter_iv
.length(),
513 client_forward_secure_decrypter_iv
.data(),
514 client_forward_secure_decrypter_iv
.length());
515 CompareCharArraysWithHexError("subkey secret",
516 client_subkey_secret
.data(),
517 client_subkey_secret
.length(),
518 server_subkey_secret
.data(),
519 server_subkey_secret
.length());
520 CompareCharArraysWithHexError("sample key extraction",
521 client_key_extraction
.data(),
522 client_key_extraction
.length(),
523 server_key_extraction
.data(),
524 server_key_extraction
.length());
528 QuicTag
CryptoTestUtils::ParseTag(const char* tagstr
) {
529 const size_t len
= strlen(tagstr
);
534 if (tagstr
[0] == '#') {
535 CHECK_EQ(static_cast<size_t>(1 + 2*4), len
);
538 for (size_t i
= 0; i
< 8; i
++) {
542 CHECK(HexChar(tagstr
[i
], &v
));
550 for (size_t i
= 0; i
< 4; i
++) {
553 tag
|= static_cast<uint32
>(tagstr
[i
]) << 24;
561 CryptoHandshakeMessage
CryptoTestUtils::Message(const char* message_tag
, ...) {
563 va_start(ap
, message_tag
);
565 CryptoHandshakeMessage message
= BuildMessage(message_tag
, ap
);
571 CryptoHandshakeMessage
CryptoTestUtils::BuildMessage(const char* message_tag
,
573 CryptoHandshakeMessage msg
;
574 msg
.set_tag(ParseTag(message_tag
));
577 const char* tagstr
= va_arg(ap
, const char*);
578 if (tagstr
== nullptr) {
582 if (tagstr
[0] == '$') {
584 const char* const special
= tagstr
+ 1;
585 if (strcmp(special
, "padding") == 0) {
586 const int min_bytes
= va_arg(ap
, int);
587 msg
.set_minimum_size(min_bytes
);
589 CHECK(false) << "Unknown special value: " << special
;
595 const QuicTag tag
= ParseTag(tagstr
);
596 const char* valuestr
= va_arg(ap
, const char*);
598 size_t len
= strlen(valuestr
);
599 if (len
> 0 && valuestr
[0] == '#') {
603 CHECK_EQ(0u, len
% 2);
604 scoped_ptr
<uint8
[]> buf(new uint8
[len
/2]);
606 for (size_t i
= 0; i
< len
/2; i
++) {
608 CHECK(HexChar(valuestr
[i
*2], &v
));
610 CHECK(HexChar(valuestr
[i
*2 + 1], &v
));
615 tag
, StringPiece(reinterpret_cast<char*>(buf
.get()), len
/2));
619 msg
.SetStringPiece(tag
, valuestr
);
622 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
623 // that any padding is included.
624 scoped_ptr
<QuicData
> bytes(CryptoFramer::ConstructHandshakeMessage(msg
));
625 scoped_ptr
<CryptoHandshakeMessage
> parsed(
626 CryptoFramer::ParseMessage(bytes
->AsStringPiece()));