Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / net / quic / crypto / crypto_server_test.cc
blobf1892d3b6ac7813f9029df6a82829ef32ccddfca
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;
21 using std::string;
23 namespace net {
24 namespace test {
26 class QuicCryptoServerConfigPeer {
27 public:
28 explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config)
29 : server_config_(server_config) {}
31 base::Lock* GetStrikeRegisterClientLock() {
32 return &server_config_->strike_register_client_lock_;
35 private:
36 QuicCryptoServerConfig* server_config_;
39 class CryptoServerTest : public ::testing::Test {
40 public:
41 CryptoServerTest()
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_,
54 config_options_));
56 StringPiece orbit;
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(
69 "CHLO",
70 "AEAD", "AESG",
71 "KEXS", "C255",
72 "PUBS", pub_hex_.c_str(),
73 "NONC", nonce_hex_.c_str(),
74 "VER\0", client_version_.data(),
75 "$padding", static_cast<int>(kClientHelloMinimumSize),
76 NULL);
77 ShouldSucceed(client_hello);
78 // The message should be rejected because the source-address token is
79 // missing.
80 ASSERT_EQ(kREJ, out_.tag());
82 StringPiece srct;
83 ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
84 srct_hex_ = "#" + base::HexEncode(srct.data(), srct.size());
86 StringPiece scfg;
87 ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg));
88 server_config_.reset(CryptoFramer::ParseMessage(scfg));
90 StringPiece scid;
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 {
98 public:
99 ValidateCallback(CryptoServerTest* test,
100 bool should_succeed,
101 const char* error_substr,
102 bool* called)
103 : test_(test),
104 should_succeed_(should_succeed),
105 error_substr_(error_substr),
106 called_(called) {
107 *called_ = false;
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_);
124 *called_ = true;
127 private:
128 CryptoServerTest* test_;
129 bool should_succeed_;
130 const char* error_substr_;
131 bool* called_;
134 void CheckServerHello(const CryptoHandshakeMessage& server_hello) {
135 const QuicTag* versions;
136 size_t num_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]);
143 StringPiece address;
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) {
152 bool called = false;
153 RunValidate(message, new ValidateCallback(this, true, "", &called));
154 EXPECT_TRUE(called);
157 void RunValidate(
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) {
165 bool called = false;
166 ShouldFailMentioning(error_substr, message, &called);
167 EXPECT_TRUE(called);
170 void ShouldFailMentioning(const char* error_substr,
171 const CryptoHandshakeMessage& message,
172 bool* called) {
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,
180 bool should_succeed,
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 &params_, &out_, &error_details);
188 if (should_succeed) {
189 ASSERT_EQ(error, QUIC_NO_ERROR)
190 << "Message failed with error " << error_details << ": "
191 << message.DebugString();
192 } else {
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, ...) {
202 va_list ap;
203 va_start(ap, message_tag);
205 CryptoHandshakeMessage message =
206 CryptoTestUtils::BuildMessage(message_tag, ap);
207 va_end(ap);
209 message.SetStringPiece(kPAD, string(kClientHelloMinimumSize, '-'));
210 return message;
213 string GenerateNonce() {
214 string nonce;
215 CryptoUtils::GenerateNonce(
216 clock_.WallNow(), rand_,
217 StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)),
218 &nonce);
219 return nonce;
222 protected:
223 QuicRandom* const rand_;
224 MockClock clock_;
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[] = {
243 "foo",
244 "#00",
245 "#ff00",
246 "127.0.0.1",
247 "ffee::1",
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(
255 "CHLO",
256 "SNI", kBadSNIs[i],
257 "VER\0", client_version.data(),
258 NULL));
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
265 // specified.
266 ShouldSucceed(InchoateClientHello(
267 "CHLO",
268 "AEAD", "AESG",
269 "KEXS", "C255",
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),
275 "PDMD", "X509",
276 "VER\0", client_version_.data(),
277 NULL));
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(
288 "CHLO",
289 "VER\0", client_version_.data(),
290 NULL));
293 TEST_F(CryptoServerTest, BadSourceAddressToken) {
294 // Invalid source-address tokens should be ignored.
295 static const char* kBadSourceAddressTokens[] = {
297 "foo",
298 "#0000",
299 "#0000000000000000000000000000000000000000",
302 for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) {
303 ShouldSucceed(InchoateClientHello(
304 "CHLO",
305 "STK", kBadSourceAddressTokens[i],
306 "VER\0", client_version_.data(),
307 NULL));
311 TEST_F(CryptoServerTest, BadClientNonce) {
312 // Invalid nonces should be ignored.
313 static const char* kBadNonces[] = {
315 "#0000",
316 "#0000000000000000000000000000000000000000",
319 for (size_t i = 0; i < arraysize(kBadNonces); i++) {
320 ShouldSucceed(InchoateClientHello(
321 "CHLO",
322 "NONC", kBadNonces[i],
323 "VER\0", client_version_.data(),
324 NULL));
328 TEST_F(CryptoServerTest, DowngradeAttack) {
329 if (supported_versions_.size() == 1) {
330 // No downgrade attack is possible if the server only supports one version.
331 return;
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(
339 "CHLO",
340 "VER\0", bad_version.data(),
341 NULL));
344 TEST_F(CryptoServerTest, ReplayProtection) {
345 // This tests that disabling replay protection works.
346 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
347 "CHLO",
348 "AEAD", "AESG",
349 "KEXS", "C255",
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),
356 NULL);
357 ShouldSucceed(msg);
358 // The message should be rejected because the strike-register is still
359 // quiescent.
360 ASSERT_EQ(kREJ, out_.tag());
362 config_.set_replay_protection(false);
364 ShouldSucceed(msg);
365 // The message should be accepted now.
366 ASSERT_EQ(kSHLO, out_.tag());
367 CheckServerHello(out_);
369 ShouldSucceed(msg);
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
377 // deterministic.
379 MockRandom rand_a, rand_b;
380 const QuicCryptoServerConfig::ConfigOptions options;
381 MockClock clock;
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
395 // configs.
397 MockRandom rand_a, rand_b;
398 const QuicCryptoServerConfig::ConfigOptions options;
399 MockClock clock;
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) {
418 MockRandom rand_a;
419 const QuicCryptoServerConfig::ConfigOptions options;
420 MockClock clock;
422 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
423 scoped_ptr<CryptoHandshakeMessage> scfg(
424 a.AddDefaultConfig(&rand_a, &clock, options));
426 StringPiece scid;
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());
431 scfg->Erase(kSCID);
432 scfg->MarkDirty();
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());
438 uint8 digest[16];
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 {
446 public:
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(
454 "CHLO",
455 "VER\0", client_version_.data(),
456 NULL));
459 class AsyncStrikeServerVerificationTest : public CryptoServerTest {
460 protected:
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(
484 "CHLO",
485 "AEAD", "AESG",
486 "KEXS", "C255",
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),
493 NULL);
495 // Clear the message tag.
496 out_.set_tag(0);
498 bool called = false;
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();
507 ASSERT_TRUE(called);
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();
519 ASSERT_TRUE(called);
520 EXPECT_EQ(0, strike_register_client_->PendingVerifications());
521 // The message should be rejected now.
522 EXPECT_EQ(kREJ, out_.tag());
525 } // namespace test
526 } // namespace net