1 // Copyright (c) 2013 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 "base/basictypes.h"
6 #include "base/strings/string_number_conversions.h"
7 #include "crypto/secure_hash.h"
8 #include "net/quic/crypto/crypto_utils.h"
9 #include "net/quic/crypto/quic_crypto_server_config.h"
10 #include "net/quic/crypto/quic_random.h"
11 #include "net/quic/quic_socket_address_coder.h"
12 #include "net/quic/quic_utils.h"
13 #include "net/quic/test_tools/crypto_test_utils.h"
14 #include "net/quic/test_tools/delayed_verify_strike_register_client.h"
15 #include "net/quic/test_tools/mock_clock.h"
16 #include "net/quic/test_tools/mock_random.h"
17 #include "net/quic/test_tools/quic_test_utils.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using base::StringPiece
;
26 class QuicCryptoServerConfigPeer
{
28 explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig
* server_config
)
29 : server_config_(server_config
) {}
31 base::Lock
* GetStrikeRegisterClientLock() {
32 return &server_config_
->strike_register_client_lock_
;
36 QuicCryptoServerConfig
* server_config_
;
39 class CryptoServerTest
: public ::testing::Test
{
42 : rand_(QuicRandom::GetInstance()),
43 client_address_(Loopback4(), 1234),
44 config_(QuicCryptoServerConfig::TESTING
, rand_
) {
45 config_
.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
46 supported_versions_
= QuicSupportedVersions();
47 client_version_
= QuicUtils::TagToString(
48 QuicVersionToQuicTag(supported_versions_
.front()));
51 virtual void SetUp() {
52 scoped_ptr
<CryptoHandshakeMessage
> msg(
53 config_
.AddDefaultConfig(rand_
, &clock_
,
57 CHECK(msg
->GetStringPiece(kORBT
, &orbit
));
58 CHECK_EQ(sizeof(orbit_
), orbit
.size());
59 memcpy(orbit_
, orbit
.data(), orbit
.size());
61 char public_value
[32];
62 memset(public_value
, 42, sizeof(public_value
));
64 const string nonce_str
= GenerateNonce();
65 nonce_hex_
= "#" + base::HexEncode(nonce_str
.data(), nonce_str
.size());
66 pub_hex_
= "#" + base::HexEncode(public_value
, sizeof(public_value
));
68 CryptoHandshakeMessage client_hello
= CryptoTestUtils::Message(
72 "PUBS", pub_hex_
.c_str(),
73 "NONC", nonce_hex_
.c_str(),
74 "VER\0", client_version_
.data(),
75 "$padding", static_cast<int>(kClientHelloMinimumSize
),
77 ShouldSucceed(client_hello
);
78 // The message should be rejected because the source-address token is
80 ASSERT_EQ(kREJ
, out_
.tag());
83 ASSERT_TRUE(out_
.GetStringPiece(kSourceAddressTokenTag
, &srct
));
84 srct_hex_
= "#" + base::HexEncode(srct
.data(), srct
.size());
87 ASSERT_TRUE(out_
.GetStringPiece(kSCFG
, &scfg
));
88 server_config_
.reset(CryptoFramer::ParseMessage(scfg
));
91 ASSERT_TRUE(server_config_
->GetStringPiece(kSCID
, &scid
));
92 scid_hex_
= "#" + base::HexEncode(scid
.data(), scid
.size());
95 // Helper used to accept the result of ValidateClientHello and pass
96 // it on to ProcessClientHello.
97 class ValidateCallback
: public ValidateClientHelloResultCallback
{
99 ValidateCallback(CryptoServerTest
* test
,
101 const char* error_substr
,
104 should_succeed_(should_succeed
),
105 error_substr_(error_substr
),
110 virtual void RunImpl(const CryptoHandshakeMessage
& client_hello
,
111 const Result
& result
) OVERRIDE
{
113 // Ensure that the strike register client lock is not held.
114 QuicCryptoServerConfigPeer
peer(&test_
->config_
);
115 base::Lock
* m
= peer
.GetStrikeRegisterClientLock();
116 // In Chromium, we will dead lock if the lock is held by the current
117 // thread. Chromium doesn't have AssertNotHeld API call.
118 // m->AssertNotHeld();
119 base::AutoLock
lock(*m
);
121 ASSERT_FALSE(*called_
);
122 test_
->ProcessValidationResult(
123 client_hello
, result
, should_succeed_
, error_substr_
);
128 CryptoServerTest
* test_
;
129 bool should_succeed_
;
130 const char* error_substr_
;
134 void CheckServerHello(const CryptoHandshakeMessage
& server_hello
) {
135 const QuicTag
* versions
;
137 server_hello
.GetTaglist(kVER
, &versions
, &num_versions
);
138 ASSERT_EQ(QuicSupportedVersions().size(), num_versions
);
139 for (size_t i
= 0; i
< num_versions
; ++i
) {
140 EXPECT_EQ(QuicVersionToQuicTag(QuicSupportedVersions()[i
]), versions
[i
]);
144 ASSERT_TRUE(server_hello
.GetStringPiece(kCADR
, &address
));
145 QuicSocketAddressCoder decoder
;
146 ASSERT_TRUE(decoder
.Decode(address
.data(), address
.size()));
147 EXPECT_EQ(client_address_
.address(), decoder
.ip());
148 EXPECT_EQ(client_address_
.port(), decoder
.port());
151 void ShouldSucceed(const CryptoHandshakeMessage
& message
) {
153 RunValidate(message
, new ValidateCallback(this, true, "", &called
));
158 const CryptoHandshakeMessage
& message
,
159 ValidateClientHelloResultCallback
* cb
) {
160 config_
.ValidateClientHello(message
, client_address_
, &clock_
, cb
);
163 void ShouldFailMentioning(const char* error_substr
,
164 const CryptoHandshakeMessage
& message
) {
166 ShouldFailMentioning(error_substr
, message
, &called
);
170 void ShouldFailMentioning(const char* error_substr
,
171 const CryptoHandshakeMessage
& message
,
173 config_
.ValidateClientHello(
174 message
, client_address_
, &clock_
,
175 new ValidateCallback(this, false, error_substr
, called
));
178 void ProcessValidationResult(const CryptoHandshakeMessage
& message
,
179 const ValidateCallback::Result
& result
,
181 const char* error_substr
) {
182 string error_details
;
183 QuicErrorCode error
= config_
.ProcessClientHello(
184 result
, 1 /* ConnectionId */, client_address_
,
185 supported_versions_
.front(), supported_versions_
, &clock_
, rand_
,
186 ¶ms_
, &out_
, &error_details
);
188 if (should_succeed
) {
189 ASSERT_EQ(error
, QUIC_NO_ERROR
)
190 << "Message failed with error " << error_details
<< ": "
191 << message
.DebugString();
193 ASSERT_NE(error
, QUIC_NO_ERROR
)
194 << "Message didn't fail: " << message
.DebugString();
196 EXPECT_TRUE(error_details
.find(error_substr
) != string::npos
)
197 << error_substr
<< " not in " << error_details
;
201 CryptoHandshakeMessage
InchoateClientHello(const char* message_tag
, ...) {
203 va_start(ap
, message_tag
);
205 CryptoHandshakeMessage message
=
206 CryptoTestUtils::BuildMessage(message_tag
, ap
);
209 message
.SetStringPiece(kPAD
, string(kClientHelloMinimumSize
, '-'));
213 string
GenerateNonce() {
215 CryptoUtils::GenerateNonce(
216 clock_
.WallNow(), rand_
,
217 StringPiece(reinterpret_cast<const char*>(orbit_
), sizeof(orbit_
)),
223 QuicRandom
* const rand_
;
225 const IPEndPoint client_address_
;
226 QuicVersionVector supported_versions_
;
227 string client_version_
;
228 QuicCryptoServerConfig config_
;
229 QuicCryptoServerConfig::ConfigOptions config_options_
;
230 QuicCryptoNegotiatedParameters params_
;
231 CryptoHandshakeMessage out_
;
232 uint8 orbit_
[kOrbitSize
];
234 // These strings contain hex escaped values from the server suitable for
235 // passing to |InchoateClientHello| when constructing client hello messages.
236 string nonce_hex_
, pub_hex_
, srct_hex_
, scid_hex_
;
237 scoped_ptr
<CryptoHandshakeMessage
> server_config_
;
240 TEST_F(CryptoServerTest
, BadSNI
) {
241 static const char* kBadSNIs
[] = {
250 string client_version
= QuicUtils::TagToString(
251 QuicVersionToQuicTag(supported_versions_
.front()));
253 for (size_t i
= 0; i
< arraysize(kBadSNIs
); i
++) {
254 ShouldFailMentioning("SNI", InchoateClientHello(
257 "VER\0", client_version
.data(),
262 // TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource.
263 TEST_F(CryptoServerTest
, DISABLED_DefaultCert
) {
264 // Check that the server replies with a default certificate when no SNI is
266 ShouldSucceed(InchoateClientHello(
270 "SCID", scid_hex_
.c_str(),
271 "#004b5453", srct_hex_
.c_str(),
272 "PUBS", pub_hex_
.c_str(),
273 "NONC", nonce_hex_
.c_str(),
274 "$padding", static_cast<int>(kClientHelloMinimumSize
),
276 "VER\0", client_version_
.data(),
279 StringPiece cert
, proof
;
280 EXPECT_TRUE(out_
.GetStringPiece(kCertificateTag
, &cert
));
281 EXPECT_TRUE(out_
.GetStringPiece(kPROF
, &proof
));
282 EXPECT_NE(0u, cert
.size());
283 EXPECT_NE(0u, proof
.size());
286 TEST_F(CryptoServerTest
, TooSmall
) {
287 ShouldFailMentioning("too small", CryptoTestUtils::Message(
289 "VER\0", client_version_
.data(),
293 TEST_F(CryptoServerTest
, BadSourceAddressToken
) {
294 // Invalid source-address tokens should be ignored.
295 static const char* kBadSourceAddressTokens
[] = {
299 "#0000000000000000000000000000000000000000",
302 for (size_t i
= 0; i
< arraysize(kBadSourceAddressTokens
); i
++) {
303 ShouldSucceed(InchoateClientHello(
305 "STK", kBadSourceAddressTokens
[i
],
306 "VER\0", client_version_
.data(),
311 TEST_F(CryptoServerTest
, BadClientNonce
) {
312 // Invalid nonces should be ignored.
313 static const char* kBadNonces
[] = {
316 "#0000000000000000000000000000000000000000",
319 for (size_t i
= 0; i
< arraysize(kBadNonces
); i
++) {
320 ShouldSucceed(InchoateClientHello(
322 "NONC", kBadNonces
[i
],
323 "VER\0", client_version_
.data(),
328 TEST_F(CryptoServerTest
, DowngradeAttack
) {
329 if (supported_versions_
.size() == 1) {
330 // No downgrade attack is possible if the server only supports one version.
333 // Set the client's preferred version to a supported version that
334 // is not the "current" version (supported_versions_.front()).
335 string bad_version
= QuicUtils::TagToString(
336 QuicVersionToQuicTag(supported_versions_
.back()));
338 ShouldFailMentioning("Downgrade", InchoateClientHello(
340 "VER\0", bad_version
.data(),
344 TEST_F(CryptoServerTest
, ReplayProtection
) {
345 // This tests that disabling replay protection works.
346 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
350 "SCID", scid_hex_
.c_str(),
351 "#004b5453", srct_hex_
.c_str(),
352 "PUBS", pub_hex_
.c_str(),
353 "NONC", nonce_hex_
.c_str(),
354 "VER\0", client_version_
.data(),
355 "$padding", static_cast<int>(kClientHelloMinimumSize
),
358 // The message should be rejected because the strike-register is still
360 ASSERT_EQ(kREJ
, out_
.tag());
362 config_
.set_replay_protection(false);
365 // The message should be accepted now.
366 ASSERT_EQ(kSHLO
, out_
.tag());
367 CheckServerHello(out_
);
370 // The message should accepted twice when replay protection is off.
371 ASSERT_EQ(kSHLO
, out_
.tag());
372 CheckServerHello(out_
);
375 TEST(CryptoServerConfigGenerationTest
, Determinism
) {
376 // Test that using a deterministic PRNG causes the server-config to be
379 MockRandom rand_a
, rand_b
;
380 const QuicCryptoServerConfig::ConfigOptions options
;
383 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
384 QuicCryptoServerConfig
b(QuicCryptoServerConfig::TESTING
, &rand_b
);
385 scoped_ptr
<CryptoHandshakeMessage
> scfg_a(
386 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
387 scoped_ptr
<CryptoHandshakeMessage
> scfg_b(
388 b
.AddDefaultConfig(&rand_b
, &clock
, options
));
390 ASSERT_EQ(scfg_a
->DebugString(), scfg_b
->DebugString());
393 TEST(CryptoServerConfigGenerationTest
, SCIDVaries
) {
394 // This test ensures that the server config ID varies for different server
397 MockRandom rand_a
, rand_b
;
398 const QuicCryptoServerConfig::ConfigOptions options
;
401 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
402 rand_b
.ChangeValue();
403 QuicCryptoServerConfig
b(QuicCryptoServerConfig::TESTING
, &rand_b
);
404 scoped_ptr
<CryptoHandshakeMessage
> scfg_a(
405 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
406 scoped_ptr
<CryptoHandshakeMessage
> scfg_b(
407 b
.AddDefaultConfig(&rand_b
, &clock
, options
));
409 StringPiece scid_a
, scid_b
;
410 EXPECT_TRUE(scfg_a
->GetStringPiece(kSCID
, &scid_a
));
411 EXPECT_TRUE(scfg_b
->GetStringPiece(kSCID
, &scid_b
));
413 EXPECT_NE(scid_a
, scid_b
);
417 TEST(CryptoServerConfigGenerationTest
, SCIDIsHashOfServerConfig
) {
419 const QuicCryptoServerConfig::ConfigOptions options
;
422 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
423 scoped_ptr
<CryptoHandshakeMessage
> scfg(
424 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
427 EXPECT_TRUE(scfg
->GetStringPiece(kSCID
, &scid
));
428 // Need to take a copy of |scid| has we're about to call |Erase|.
429 const string
scid_str(scid
.as_string());
433 const QuicData
& serialized(scfg
->GetSerialized());
435 scoped_ptr
<crypto::SecureHash
> hash(
436 crypto::SecureHash::Create(crypto::SecureHash::SHA256
));
437 hash
->Update(serialized
.data(), serialized
.length());
439 hash
->Finish(digest
, sizeof(digest
));
441 ASSERT_EQ(scid
.size(), sizeof(digest
));
442 EXPECT_TRUE(0 == memcmp(digest
, scid_str
.data(), sizeof(digest
)));
445 class CryptoServerTestNoConfig
: public CryptoServerTest
{
447 virtual void SetUp() {
448 // Deliberately don't add a config so that we can test this situation.
452 TEST_F(CryptoServerTestNoConfig
, DontCrash
) {
453 ShouldFailMentioning("No config", InchoateClientHello(
455 "VER\0", client_version_
.data(),
459 class AsyncStrikeServerVerificationTest
: public CryptoServerTest
{
461 AsyncStrikeServerVerificationTest() {
464 virtual void SetUp() {
465 const string kOrbit
= "12345678";
466 config_options_
.orbit
= kOrbit
;
467 strike_register_client_
= new DelayedVerifyStrikeRegisterClient(
468 10000, // strike_register_max_entries
469 static_cast<uint32
>(clock_
.WallNow().ToUNIXSeconds()),
470 60, // strike_register_window_secs
471 reinterpret_cast<const uint8
*>(kOrbit
.data()),
472 StrikeRegister::NO_STARTUP_PERIOD_NEEDED
);
473 config_
.SetStrikeRegisterClient(strike_register_client_
);
474 CryptoServerTest::SetUp();
475 strike_register_client_
->StartDelayingVerification();
478 DelayedVerifyStrikeRegisterClient
* strike_register_client_
;
481 TEST_F(AsyncStrikeServerVerificationTest
, AsyncReplayProtection
) {
482 // This tests async validation with a strike register works.
483 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
487 "SCID", scid_hex_
.c_str(),
488 "#004b5453", srct_hex_
.c_str(),
489 "PUBS", pub_hex_
.c_str(),
490 "NONC", nonce_hex_
.c_str(),
491 "VER\0", client_version_
.data(),
492 "$padding", static_cast<int>(kClientHelloMinimumSize
),
495 // Clear the message tag.
499 RunValidate(msg
, new ValidateCallback(this, true, "", &called
));
500 // The verification request was queued.
501 ASSERT_FALSE(called
);
502 EXPECT_EQ(0u, out_
.tag());
503 EXPECT_EQ(1, strike_register_client_
->PendingVerifications());
505 // Continue processing the verification request.
506 strike_register_client_
->RunPendingVerifications();
508 EXPECT_EQ(0, strike_register_client_
->PendingVerifications());
509 // The message should be accepted now.
510 EXPECT_EQ(kSHLO
, out_
.tag());
512 // Rejected if replayed.
513 RunValidate(msg
, new ValidateCallback(this, true, "", &called
));
514 // The verification request was queued.
515 ASSERT_FALSE(called
);
516 EXPECT_EQ(1, strike_register_client_
->PendingVerifications());
518 strike_register_client_
->RunPendingVerifications();
520 EXPECT_EQ(0, strike_register_client_
->PendingVerifications());
521 // The message should be rejected now.
522 EXPECT_EQ(kREJ
, out_
.tag());