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();
49 virtual void SetUp() {
50 scoped_ptr<CryptoHandshakeMessage> msg(
51 config_.AddDefaultConfig(rand_, &clock_,
55 CHECK(msg->GetStringPiece(kORBT, &orbit));
56 CHECK_EQ(sizeof(orbit_), orbit.size());
57 memcpy(orbit_, orbit.data(), orbit.size());
59 char public_value[32];
60 memset(public_value, 42, sizeof(public_value));
62 const string nonce_str = GenerateNonce();
63 nonce_hex_ = "#" + base::HexEncode(nonce_str.data(), nonce_str.size());
64 pub_hex_ = "#" + base::HexEncode(public_value, sizeof(public_value));
66 CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
70 "PUBS", pub_hex_.c_str(),
71 "NONC", nonce_hex_.c_str(),
72 "$padding", static_cast<int>(kClientHelloMinimumSize),
74 ShouldSucceed(client_hello);
75 // The message should be rejected because the source-address token is
77 ASSERT_EQ(kREJ, out_.tag());
80 ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
81 srct_hex_ = "#" + base::HexEncode(srct.data(), srct.size());
84 ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg));
85 server_config_.reset(CryptoFramer::ParseMessage(scfg));
88 ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid));
89 scid_hex_ = "#" + base::HexEncode(scid.data(), scid.size());
92 // Helper used to accept the result of ValidateClientHello and pass
93 // it on to ProcessClientHello.
94 class ValidateCallback : public ValidateClientHelloResultCallback {
96 ValidateCallback(CryptoServerTest* test,
98 const char* error_substr,
101 should_succeed_(should_succeed),
102 error_substr_(error_substr),
107 virtual void RunImpl(const CryptoHandshakeMessage& client_hello,
108 const Result& result) OVERRIDE {
110 // Ensure that the strike register client lock is not held.
111 QuicCryptoServerConfigPeer peer(&test_->config_);
112 base::Lock* m = peer.GetStrikeRegisterClientLock();
113 // In Chromium, we will dead lock if the lock is held by the current
114 // thread. Chromium doesn't have AssertNotHeld API call.
115 // m->AssertNotHeld();
116 base::AutoLock lock(*m);
118 ASSERT_FALSE(*called_);
119 test_->ProcessValidationResult(
120 client_hello, result, should_succeed_, error_substr_);
125 CryptoServerTest* test_;
126 bool should_succeed_;
127 const char* error_substr_;
131 void CheckServerHello(const CryptoHandshakeMessage& server_hello) {
132 const QuicTag* versions;
134 server_hello.GetTaglist(kVER, &versions, &num_versions);
135 ASSERT_EQ(QuicSupportedVersions().size(), num_versions);
136 for (size_t i = 0; i < num_versions; ++i) {
137 EXPECT_EQ(QuicVersionToQuicTag(QuicSupportedVersions()[i]), versions[i]);
141 ASSERT_TRUE(server_hello.GetStringPiece(kCADR, &address));
142 QuicSocketAddressCoder decoder;
143 ASSERT_TRUE(decoder.Decode(address.data(), address.size()));
144 EXPECT_EQ(client_address_.address(), decoder.ip());
145 EXPECT_EQ(client_address_.port(), decoder.port());
148 void ShouldSucceed(const CryptoHandshakeMessage& message) {
150 RunValidate(message, new ValidateCallback(this, true, "", &called));
155 const CryptoHandshakeMessage& message,
156 ValidateClientHelloResultCallback* cb) {
157 config_.ValidateClientHello(message, client_address_, &clock_, cb);
160 void ShouldFailMentioning(const char* error_substr,
161 const CryptoHandshakeMessage& message) {
163 ShouldFailMentioning(error_substr, message, &called);
167 void ShouldFailMentioning(const char* error_substr,
168 const CryptoHandshakeMessage& message,
170 config_.ValidateClientHello(
171 message, client_address_, &clock_,
172 new ValidateCallback(this, false, error_substr, called));
175 void ProcessValidationResult(const CryptoHandshakeMessage& message,
176 const ValidateCallback::Result& result,
178 const char* error_substr) {
179 string error_details;
180 QuicErrorCode error = config_.ProcessClientHello(
181 result, 1 /* GUID */, client_address_,
182 supported_versions_.front(), supported_versions_, &clock_, rand_,
183 ¶ms_, &out_, &error_details);
185 if (should_succeed) {
186 ASSERT_EQ(error, QUIC_NO_ERROR)
187 << "Message failed with error " << error_details << ": "
188 << message.DebugString();
190 ASSERT_NE(error, QUIC_NO_ERROR)
191 << "Message didn't fail: " << message.DebugString();
193 EXPECT_TRUE(error_details.find(error_substr) != string::npos)
194 << error_substr << " not in " << error_details;
198 CryptoHandshakeMessage InchoateClientHello(const char* message_tag, ...) {
200 va_start(ap, message_tag);
202 CryptoHandshakeMessage message =
203 CryptoTestUtils::BuildMessage(message_tag, ap);
206 message.SetStringPiece(kPAD, string(kClientHelloMinimumSize, '-'));
210 string GenerateNonce() {
212 CryptoUtils::GenerateNonce(
213 clock_.WallNow(), rand_,
214 StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)),
220 QuicRandom* const rand_;
222 const IPEndPoint client_address_;
223 QuicVersionVector supported_versions_;
224 QuicCryptoServerConfig config_;
225 QuicCryptoServerConfig::ConfigOptions config_options_;
226 QuicCryptoNegotiatedParameters params_;
227 CryptoHandshakeMessage out_;
228 uint8 orbit_[kOrbitSize];
230 // These strings contain hex escaped values from the server suitable for
231 // passing to |InchoateClientHello| when constructing client hello messages.
232 string nonce_hex_, pub_hex_, srct_hex_, scid_hex_;
233 scoped_ptr<CryptoHandshakeMessage> server_config_;
236 TEST_F(CryptoServerTest, BadSNI) {
237 static const char* kBadSNIs[] = {
246 for (size_t i = 0; i < arraysize(kBadSNIs); i++) {
247 ShouldFailMentioning("SNI", InchoateClientHello(
254 // TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource.
255 TEST_F(CryptoServerTest, DISABLED_DefaultCert) {
256 // Check that the server replies with a default certificate when no SNI is
258 ShouldSucceed(InchoateClientHello(
262 "SCID", scid_hex_.c_str(),
263 "#004b5453", srct_hex_.c_str(),
264 "PUBS", pub_hex_.c_str(),
265 "NONC", nonce_hex_.c_str(),
266 "$padding", static_cast<int>(kClientHelloMinimumSize),
270 StringPiece cert, proof;
271 EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
272 EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
273 EXPECT_NE(0u, cert.size());
274 EXPECT_NE(0u, proof.size());
277 TEST_F(CryptoServerTest, TooSmall) {
278 ShouldFailMentioning("too small", CryptoTestUtils::Message(
283 TEST_F(CryptoServerTest, BadSourceAddressToken) {
284 // Invalid source-address tokens should be ignored.
285 static const char* kBadSourceAddressTokens[] = {
289 "#0000000000000000000000000000000000000000",
292 for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) {
293 ShouldSucceed(InchoateClientHello(
295 "STK", kBadSourceAddressTokens[i],
300 TEST_F(CryptoServerTest, BadClientNonce) {
301 // Invalid nonces should be ignored.
302 static const char* kBadNonces[] = {
305 "#0000000000000000000000000000000000000000",
308 for (size_t i = 0; i < arraysize(kBadNonces); i++) {
309 ShouldSucceed(InchoateClientHello(
311 "NONC", kBadNonces[i],
316 TEST_F(CryptoServerTest, DowngradeAttack) {
317 if (supported_versions_.size() == 1) {
318 // No downgrade attack is possible if the server only supports one version.
321 // Set the client's preferred version to a supported version that
322 // is not the "current" version (supported_versions_.front()).
323 string client_version = QuicUtils::TagToString(
324 QuicVersionToQuicTag(supported_versions_.back()));
326 ShouldFailMentioning("Downgrade", InchoateClientHello(
328 "VER\0", client_version.data(),
332 TEST_F(CryptoServerTest, ReplayProtection) {
333 // This tests that disabling replay protection works.
334 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
338 "SCID", scid_hex_.c_str(),
339 "#004b5453", srct_hex_.c_str(),
340 "PUBS", pub_hex_.c_str(),
341 "NONC", nonce_hex_.c_str(),
342 "$padding", static_cast<int>(kClientHelloMinimumSize),
345 // The message should be rejected because the strike-register is still
347 ASSERT_EQ(kREJ, out_.tag());
349 config_.set_replay_protection(false);
352 // The message should be accepted now.
353 ASSERT_EQ(kSHLO, out_.tag());
354 CheckServerHello(out_);
357 // The message should accepted twice when replay protection is off.
358 ASSERT_EQ(kSHLO, out_.tag());
359 CheckServerHello(out_);
362 TEST(CryptoServerConfigGenerationTest, Determinism) {
363 // Test that using a deterministic PRNG causes the server-config to be
366 MockRandom rand_a, rand_b;
367 const QuicCryptoServerConfig::ConfigOptions options;
370 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
371 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
372 scoped_ptr<CryptoHandshakeMessage> scfg_a(
373 a.AddDefaultConfig(&rand_a, &clock, options));
374 scoped_ptr<CryptoHandshakeMessage> scfg_b(
375 b.AddDefaultConfig(&rand_b, &clock, options));
377 ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString());
380 TEST(CryptoServerConfigGenerationTest, SCIDVaries) {
381 // This test ensures that the server config ID varies for different server
384 MockRandom rand_a, rand_b;
385 const QuicCryptoServerConfig::ConfigOptions options;
388 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
389 rand_b.ChangeValue();
390 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
391 scoped_ptr<CryptoHandshakeMessage> scfg_a(
392 a.AddDefaultConfig(&rand_a, &clock, options));
393 scoped_ptr<CryptoHandshakeMessage> scfg_b(
394 b.AddDefaultConfig(&rand_b, &clock, options));
396 StringPiece scid_a, scid_b;
397 EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a));
398 EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b));
400 EXPECT_NE(scid_a, scid_b);
404 TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) {
406 const QuicCryptoServerConfig::ConfigOptions options;
409 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
410 scoped_ptr<CryptoHandshakeMessage> scfg(
411 a.AddDefaultConfig(&rand_a, &clock, options));
414 EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
415 // Need to take a copy of |scid| has we're about to call |Erase|.
416 const string scid_str(scid.as_string());
420 const QuicData& serialized(scfg->GetSerialized());
422 scoped_ptr<crypto::SecureHash> hash(
423 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
424 hash->Update(serialized.data(), serialized.length());
426 hash->Finish(digest, sizeof(digest));
428 ASSERT_EQ(scid.size(), sizeof(digest));
429 EXPECT_TRUE(0 == memcmp(digest, scid_str.data(), sizeof(digest)));
432 class CryptoServerTestNoConfig : public CryptoServerTest {
434 virtual void SetUp() {
435 // Deliberately don't add a config so that we can test this situation.
439 TEST_F(CryptoServerTestNoConfig, DontCrash) {
440 ShouldFailMentioning("No config", InchoateClientHello(
445 class AsyncStrikeServerVerificationTest : public CryptoServerTest {
447 AsyncStrikeServerVerificationTest() {
450 virtual void SetUp() {
451 const string kOrbit = "12345678";
452 config_options_.orbit = kOrbit;
453 strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
454 10000, // strike_register_max_entries
455 static_cast<uint32>(clock_.WallNow().ToUNIXSeconds()),
456 60, // strike_register_window_secs
457 reinterpret_cast<const uint8 *>(kOrbit.data()),
458 StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
459 config_.SetStrikeRegisterClient(strike_register_client_);
460 CryptoServerTest::SetUp();
461 strike_register_client_->StartDelayingVerification();
464 DelayedVerifyStrikeRegisterClient* strike_register_client_;
467 TEST_F(AsyncStrikeServerVerificationTest, AsyncReplayProtection) {
468 // This tests async validation with a strike register works.
469 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
473 "SCID", scid_hex_.c_str(),
474 "#004b5453", srct_hex_.c_str(),
475 "PUBS", pub_hex_.c_str(),
476 "NONC", nonce_hex_.c_str(),
477 "$padding", static_cast<int>(kClientHelloMinimumSize),
480 // Clear the message tag.
484 RunValidate(msg, new ValidateCallback(this, true, "", &called));
485 // The verification request was queued.
486 ASSERT_FALSE(called);
487 EXPECT_EQ(0u, out_.tag());
488 EXPECT_EQ(1, strike_register_client_->PendingVerifications());
490 // Continue processing the verification request.
491 strike_register_client_->RunPendingVerifications();
493 EXPECT_EQ(0, strike_register_client_->PendingVerifications());
494 // The message should be accepted now.
495 EXPECT_EQ(kSHLO, out_.tag());
497 // Rejected if replayed.
498 RunValidate(msg, new ValidateCallback(this, true, "", &called));
499 // The verification request was queued.
500 ASSERT_FALSE(called);
501 EXPECT_EQ(1, strike_register_client_->PendingVerifications());
503 strike_register_client_->RunPendingVerifications();
505 EXPECT_EQ(0, strike_register_client_->PendingVerifications());
506 // The message should be rejected now.
507 EXPECT_EQ(kREJ, out_.tag());