Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / net / quic / crypto / crypto_server_test.cc
blob9ab24a0abe848f936c47e80068c1a47a038a2241
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 <ostream>
6 #include <vector>
8 #include "base/basictypes.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "crypto/secure_hash.h"
11 #include "net/quic/crypto/crypto_utils.h"
12 #include "net/quic/crypto/quic_crypto_server_config.h"
13 #include "net/quic/crypto/quic_random.h"
14 #include "net/quic/quic_flags.h"
15 #include "net/quic/quic_socket_address_coder.h"
16 #include "net/quic/quic_utils.h"
17 #include "net/quic/test_tools/crypto_test_utils.h"
18 #include "net/quic/test_tools/delayed_verify_strike_register_client.h"
19 #include "net/quic/test_tools/mock_clock.h"
20 #include "net/quic/test_tools/mock_random.h"
21 #include "net/quic/test_tools/quic_test_utils.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using base::StringPiece;
25 using std::endl;
26 using std::ostream;
27 using std::string;
28 using std::vector;
30 namespace net {
31 namespace test {
33 class QuicCryptoServerConfigPeer {
34 public:
35 explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config)
36 : server_config_(server_config) {}
38 base::Lock* GetStrikeRegisterClientLock() {
39 return &server_config_->strike_register_client_lock_;
42 private:
43 QuicCryptoServerConfig* server_config_;
46 // Run tests with both parities of
47 // FLAGS_use_early_return_when_verifying_chlo.
48 struct TestParams {
49 explicit TestParams(bool use_early_return_when_verifying_chlo,
50 bool enable_stateless_rejects,
51 bool use_stateless_rejects)
52 : use_early_return_when_verifying_chlo(
53 use_early_return_when_verifying_chlo),
54 enable_stateless_rejects(enable_stateless_rejects),
55 use_stateless_rejects(use_stateless_rejects) {}
57 friend ostream& operator<<(ostream& os, const TestParams& p) {
58 os << "{ use_early_return_when_verifying_chlo: "
59 << p.use_early_return_when_verifying_chlo << endl;
60 os << " enable_stateless_rejects: " << p.enable_stateless_rejects << endl;
61 os << " use_stateless_rejects: " << p.use_stateless_rejects << " }";
62 return os;
65 bool use_early_return_when_verifying_chlo;
66 // This only enables the stateless reject feature via the feature-flag.
67 // It does not force the crypto server to emit stateless rejects.
68 bool enable_stateless_rejects;
69 // If true, this forces the server to send a stateless reject when
70 // rejecting messages. This should be a no-op if
71 // enable_stateless_rejects is false.
72 bool use_stateless_rejects;
75 // Constructs various test permutations.
76 vector<TestParams> GetTestParams() {
77 vector<TestParams> params;
78 static const bool kTrueFalse[] = {true, false};
79 for (bool use_early_return : kTrueFalse) {
80 for (bool enable_stateless_rejects : kTrueFalse) {
81 for (bool use_stateless_rejects : kTrueFalse) {
82 params.push_back(TestParams(use_early_return, enable_stateless_rejects,
83 use_stateless_rejects));
87 return params;
90 class CryptoServerTest : public ::testing::TestWithParam<TestParams> {
91 public:
92 CryptoServerTest()
93 : rand_(QuicRandom::GetInstance()),
94 client_address_(Loopback4(), 1234),
95 config_(QuicCryptoServerConfig::TESTING, rand_) {
96 #if defined(USE_OPENSSL)
97 config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
98 #else
99 config_.SetProofSource(CryptoTestUtils::FakeProofSourceForTesting());
100 #endif
101 supported_versions_ = QuicSupportedVersions();
102 client_version_ = QuicUtils::TagToString(
103 QuicVersionToQuicTag(supported_versions_.front()));
105 FLAGS_use_early_return_when_verifying_chlo =
106 GetParam().use_early_return_when_verifying_chlo;
107 FLAGS_enable_quic_stateless_reject_support =
108 GetParam().enable_stateless_rejects;
109 use_stateless_rejects_ = GetParam().use_stateless_rejects;
112 void SetUp() override {
113 scoped_ptr<CryptoHandshakeMessage> msg(
114 config_.AddDefaultConfig(rand_, &clock_, config_options_));
116 StringPiece orbit;
117 CHECK(msg->GetStringPiece(kORBT, &orbit));
118 CHECK_EQ(sizeof(orbit_), orbit.size());
119 memcpy(orbit_, orbit.data(), orbit.size());
121 char public_value[32];
122 memset(public_value, 42, sizeof(public_value));
124 const string nonce_str = GenerateNonce();
125 nonce_hex_ = "#" + base::HexEncode(nonce_str.data(), nonce_str.size());
126 pub_hex_ = "#" + base::HexEncode(public_value, sizeof(public_value));
128 // clang-format off
129 CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
130 "CHLO",
131 "AEAD", "AESG",
132 "KEXS", "C255",
133 "PUBS", pub_hex_.c_str(),
134 "NONC", nonce_hex_.c_str(),
135 "VER\0", client_version_.data(),
136 "$padding", static_cast<int>(kClientHelloMinimumSize),
137 nullptr);
138 // clang-format on
139 ShouldSucceed(client_hello);
140 // The message should be rejected because the source-address token is
141 // missing.
142 CheckRejectTag();
143 const HandshakeFailureReason kRejectReasons[] = {
144 SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
145 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
146 CheckForServerDesignatedConnectionId();
148 StringPiece srct;
149 ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
150 srct_hex_ = "#" + base::HexEncode(srct.data(), srct.size());
152 StringPiece scfg;
153 ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg));
154 server_config_.reset(CryptoFramer::ParseMessage(scfg));
156 StringPiece scid;
157 ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid));
158 scid_hex_ = "#" + base::HexEncode(scid.data(), scid.size());
161 // Helper used to accept the result of ValidateClientHello and pass
162 // it on to ProcessClientHello.
163 class ValidateCallback : public ValidateClientHelloResultCallback {
164 public:
165 ValidateCallback(CryptoServerTest* test,
166 bool should_succeed,
167 const char* error_substr,
168 bool* called)
169 : test_(test),
170 should_succeed_(should_succeed),
171 error_substr_(error_substr),
172 called_(called) {
173 *called_ = false;
176 void RunImpl(const CryptoHandshakeMessage& client_hello,
177 const Result& result) override {
179 // Ensure that the strike register client lock is not held.
180 QuicCryptoServerConfigPeer peer(&test_->config_);
181 base::Lock* m = peer.GetStrikeRegisterClientLock();
182 // In Chromium, we will dead lock if the lock is held by the current
183 // thread. Chromium doesn't have AssertNotHeld API call.
184 // m->AssertNotHeld();
185 base::AutoLock lock(*m);
187 ASSERT_FALSE(*called_);
188 test_->ProcessValidationResult(client_hello, result, should_succeed_,
189 error_substr_);
190 *called_ = true;
193 private:
194 CryptoServerTest* test_;
195 bool should_succeed_;
196 const char* error_substr_;
197 bool* called_;
200 void CheckServerHello(const CryptoHandshakeMessage& server_hello) {
201 const QuicTag* versions;
202 size_t num_versions;
203 server_hello.GetTaglist(kVER, &versions, &num_versions);
204 ASSERT_EQ(QuicSupportedVersions().size(), num_versions);
205 for (size_t i = 0; i < num_versions; ++i) {
206 EXPECT_EQ(QuicVersionToQuicTag(QuicSupportedVersions()[i]), versions[i]);
209 StringPiece address;
210 ASSERT_TRUE(server_hello.GetStringPiece(kCADR, &address));
211 QuicSocketAddressCoder decoder;
212 ASSERT_TRUE(decoder.Decode(address.data(), address.size()));
213 EXPECT_EQ(client_address_.address(), decoder.ip());
214 EXPECT_EQ(client_address_.port(), decoder.port());
217 void ShouldSucceed(const CryptoHandshakeMessage& message) {
218 bool called = false;
219 config_.ValidateClientHello(message, client_address_.address(), &clock_,
220 new ValidateCallback(this, true, "", &called));
221 EXPECT_TRUE(called);
224 void ShouldFailMentioning(const char* error_substr,
225 const CryptoHandshakeMessage& message) {
226 bool called = false;
227 ShouldFailMentioning(error_substr, message, &called);
228 EXPECT_TRUE(called);
231 void ShouldFailMentioning(const char* error_substr,
232 const CryptoHandshakeMessage& message,
233 bool* called) {
234 config_.ValidateClientHello(
235 message, client_address_.address(), &clock_,
236 new ValidateCallback(this, false, error_substr, called));
239 void ProcessValidationResult(const CryptoHandshakeMessage& message,
240 const ValidateCallback::Result& result,
241 bool should_succeed,
242 const char* error_substr) {
243 IPAddressNumber server_ip;
244 string error_details;
245 QuicConnectionId server_designated_connection_id =
246 rand_for_id_generation_.RandUint64();
247 QuicErrorCode error = config_.ProcessClientHello(
248 result, 1 /* ConnectionId */, server_ip, client_address_,
249 supported_versions_.front(), supported_versions_,
250 use_stateless_rejects_, server_designated_connection_id, &clock_, rand_,
251 &params_, &out_, &error_details);
253 if (should_succeed) {
254 ASSERT_EQ(error, QUIC_NO_ERROR) << "Message failed with error "
255 << error_details << ": "
256 << message.DebugString();
257 } else {
258 ASSERT_NE(error, QUIC_NO_ERROR) << "Message didn't fail: "
259 << message.DebugString();
261 EXPECT_TRUE(error_details.find(error_substr) != string::npos)
262 << error_substr << " not in " << error_details;
266 string GenerateNonce() {
267 string nonce;
268 CryptoUtils::GenerateNonce(
269 clock_.WallNow(), rand_,
270 StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)),
271 &nonce);
272 return nonce;
275 void CheckRejectReasons(
276 const HandshakeFailureReason* expected_handshake_failures,
277 size_t expected_count) {
278 const uint32* reject_reasons;
279 size_t num_reject_reasons;
280 COMPILE_ASSERT(sizeof(QuicTag) == sizeof(uint32), header_out_of_sync);
281 QuicErrorCode error_code =
282 out_.GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons);
283 ASSERT_EQ(QUIC_NO_ERROR, error_code);
285 if (FLAGS_use_early_return_when_verifying_chlo) {
286 EXPECT_EQ(1u, num_reject_reasons);
287 } else {
288 EXPECT_EQ(expected_count, num_reject_reasons);
290 for (size_t i = 0; i < num_reject_reasons; ++i) {
291 EXPECT_EQ(expected_handshake_failures[i], reject_reasons[i]);
295 // If the server is rejecting statelessly, make sure it contains a
296 // server-designated connection id. Once the check is complete,
297 // allow the random id-generator to move to the next value.
298 void CheckForServerDesignatedConnectionId() {
299 QuicConnectionId server_designated_connection_id;
300 if (!RejectsAreStateless()) {
301 EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
302 out_.GetUint64(kRCID, &server_designated_connection_id));
303 } else {
304 ASSERT_EQ(QUIC_NO_ERROR,
305 out_.GetUint64(kRCID, &server_designated_connection_id));
306 EXPECT_EQ(rand_for_id_generation_.RandUint64(),
307 server_designated_connection_id);
309 rand_for_id_generation_.ChangeValue();
312 void CheckRejectTag() {
313 if (RejectsAreStateless()) {
314 ASSERT_EQ(kSREJ, out_.tag());
315 } else {
316 ASSERT_EQ(kREJ, out_.tag());
320 bool RejectsAreStateless() {
321 return GetParam().enable_stateless_rejects &&
322 GetParam().use_stateless_rejects;
325 protected:
326 QuicRandom* const rand_;
327 MockRandom rand_for_id_generation_;
328 MockClock clock_;
329 const IPEndPoint client_address_;
330 QuicVersionVector supported_versions_;
331 string client_version_;
332 QuicCryptoServerConfig config_;
333 QuicCryptoServerConfig::ConfigOptions config_options_;
334 QuicCryptoNegotiatedParameters params_;
335 CryptoHandshakeMessage out_;
336 uint8 orbit_[kOrbitSize];
337 bool use_stateless_rejects_;
339 // These strings contain hex escaped values from the server suitable for using
340 // when constructing client hello messages.
341 string nonce_hex_, pub_hex_, srct_hex_, scid_hex_;
342 scoped_ptr<CryptoHandshakeMessage> server_config_;
345 // Run all CryptoServerTest with both values of
346 // FLAGS_use_early_return_when_verifying_chlo.
347 INSTANTIATE_TEST_CASE_P(CryptoServerTests,
348 CryptoServerTest,
349 ::testing::ValuesIn(GetTestParams()));
351 TEST_P(CryptoServerTest, BadSNI) {
352 // clang-format off
353 static const char* const kBadSNIs[] = {
355 "foo",
356 "#00",
357 "#ff00",
358 "127.0.0.1",
359 "ffee::1",
361 // clang-format on
363 string client_version =
364 QuicUtils::TagToString(QuicVersionToQuicTag(supported_versions_.front()));
366 for (size_t i = 0; i < arraysize(kBadSNIs); i++) {
367 // clang-format off
368 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
369 "CHLO",
370 "SNI", kBadSNIs[i],
371 "VER\0", client_version.data(),
372 "$padding", static_cast<int>(kClientHelloMinimumSize),
373 nullptr);
374 // clang-format on
375 ShouldFailMentioning("SNI", msg);
376 const HandshakeFailureReason kRejectReasons[] = {
377 SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
378 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
382 // TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource.
383 // See http://crbug.com/514472.
384 TEST_P(CryptoServerTest, DefaultCert) {
385 // Check that the server replies with a default certificate when no SNI is
386 // specified.
387 // clang-format off
388 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
389 "CHLO",
390 "AEAD", "AESG",
391 "KEXS", "C255",
392 "SCID", scid_hex_.c_str(),
393 "#004b5453", srct_hex_.c_str(),
394 "PUBS", pub_hex_.c_str(),
395 "NONC", nonce_hex_.c_str(),
396 "PDMD", "X509",
397 "VER\0", client_version_.data(),
398 "$padding", static_cast<int>(kClientHelloMinimumSize),
399 nullptr);
400 // clang-format on
402 ShouldSucceed(msg);
403 StringPiece cert, proof;
404 EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
405 EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
406 EXPECT_NE(0u, cert.size());
407 EXPECT_NE(0u, proof.size());
408 const HandshakeFailureReason kRejectReasons[] = {
409 CLIENT_NONCE_INVALID_TIME_FAILURE};
410 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
413 TEST_P(CryptoServerTest, TooSmall) {
414 // clang-format off
415 ShouldFailMentioning("too small", CryptoTestUtils::Message(
416 "CHLO",
417 "VER\0", client_version_.data(),
418 nullptr));
419 // clang-format on
420 const HandshakeFailureReason kRejectReasons[] = {
421 SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
422 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
425 TEST_P(CryptoServerTest, BadSourceAddressToken) {
426 // Invalid source-address tokens should be ignored.
427 // clang-format off
428 static const char* const kBadSourceAddressTokens[] = {
430 "foo",
431 "#0000",
432 "#0000000000000000000000000000000000000000",
434 // clang-format on
436 for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) {
437 // clang-format off
438 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
439 "CHLO",
440 "STK", kBadSourceAddressTokens[i],
441 "VER\0", client_version_.data(),
442 "$padding", static_cast<int>(kClientHelloMinimumSize), nullptr);
443 // clang-format on
444 ShouldSucceed(msg);
445 const HandshakeFailureReason kRejectReasons[] = {
446 SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
447 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
451 TEST_P(CryptoServerTest, BadClientNonce) {
452 // Invalid nonces should be ignored.
453 // clang-format off
454 static const char* const kBadNonces[] = {
456 "#0000",
457 "#0000000000000000000000000000000000000000",
459 // clang-format on
461 for (size_t i = 0; i < arraysize(kBadNonces); i++) {
462 // clang-format off
463 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
464 "CHLO",
465 "NONC", kBadNonces[i],
466 "VER\0", client_version_.data(),
467 "$padding", static_cast<int>(kClientHelloMinimumSize),
468 nullptr);
469 // clang-format on
470 ShouldSucceed(msg);
471 const HandshakeFailureReason kRejectReasons[] = {
472 SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
473 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
477 TEST_P(CryptoServerTest, DowngradeAttack) {
478 if (supported_versions_.size() == 1) {
479 // No downgrade attack is possible if the server only supports one version.
480 return;
482 // Set the client's preferred version to a supported version that
483 // is not the "current" version (supported_versions_.front()).
484 string bad_version =
485 QuicUtils::TagToString(QuicVersionToQuicTag(supported_versions_.back()));
487 // clang-format off
488 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
489 "CHLO",
490 "VER\0", bad_version.data(),
491 "$padding", static_cast<int>(kClientHelloMinimumSize),
492 nullptr);
493 // clang-format on
494 ShouldFailMentioning("Downgrade", msg);
495 const HandshakeFailureReason kRejectReasons[] = {
496 SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
497 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
500 TEST_P(CryptoServerTest, CorruptServerConfig) {
501 // This tests corrupted server config.
502 // clang-format off
503 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
504 "CHLO",
505 "AEAD", "AESG",
506 "KEXS", "C255",
507 "SCID", (string(1, 'X') + scid_hex_).c_str(),
508 "#004b5453", srct_hex_.c_str(),
509 "PUBS", pub_hex_.c_str(),
510 "NONC", nonce_hex_.c_str(),
511 "VER\0", client_version_.data(),
512 "$padding", static_cast<int>(kClientHelloMinimumSize),
513 nullptr);
514 // clang-format on
515 ShouldSucceed(msg);
516 CheckRejectTag();
517 const HandshakeFailureReason kRejectReasons[] = {
518 SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE};
519 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
522 TEST_P(CryptoServerTest, CorruptSourceAddressToken) {
523 // This tests corrupted source address token.
524 // clang-format off
525 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
526 "CHLO",
527 "AEAD", "AESG",
528 "KEXS", "C255",
529 "SCID", scid_hex_.c_str(),
530 "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
531 "PUBS", pub_hex_.c_str(),
532 "NONC", nonce_hex_.c_str(),
533 "VER\0", client_version_.data(),
534 "$padding", static_cast<int>(kClientHelloMinimumSize),
535 nullptr);
536 // clang-format on
537 ShouldSucceed(msg);
538 CheckRejectTag();
539 const HandshakeFailureReason kRejectReasons[] = {
540 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE};
541 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
544 TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) {
545 // This test corrupts client nonce and source address token.
546 // clang-format off
547 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
548 "CHLO",
549 "AEAD", "AESG",
550 "KEXS", "C255",
551 "SCID", scid_hex_.c_str(),
552 "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
553 "PUBS", pub_hex_.c_str(),
554 "NONC", (string(1, 'X') + nonce_hex_).c_str(),
555 "VER\0", client_version_.data(),
556 "$padding", static_cast<int>(kClientHelloMinimumSize),
557 nullptr);
558 // clang-format on
559 ShouldSucceed(msg);
560 CheckRejectTag();
561 const HandshakeFailureReason kRejectReasons[] = {
562 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE};
563 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
566 TEST_P(CryptoServerTest, CorruptMultipleTags) {
567 // This test corrupts client nonce, server nonce and source address token.
568 // clang-format off
569 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
570 "CHLO",
571 "AEAD", "AESG",
572 "KEXS", "C255",
573 "SCID", scid_hex_.c_str(),
574 "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
575 "PUBS", pub_hex_.c_str(),
576 "NONC", (string(1, 'X') + nonce_hex_).c_str(),
577 "SNO\0", (string(1, 'X') + nonce_hex_).c_str(),
578 "VER\0", client_version_.data(),
579 "$padding", static_cast<int>(kClientHelloMinimumSize),
580 nullptr);
581 // clang-format on
582 ShouldSucceed(msg);
583 CheckRejectTag();
584 const HandshakeFailureReason kRejectReasons[] = {
585 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE,
586 SERVER_NONCE_DECRYPTION_FAILURE,
588 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
591 TEST_P(CryptoServerTest, ReplayProtection) {
592 // This tests that disabling replay protection works.
593 // clang-format off
594 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
595 "CHLO",
596 "AEAD", "AESG",
597 "KEXS", "C255",
598 "SCID", scid_hex_.c_str(),
599 "#004b5453", srct_hex_.c_str(),
600 "PUBS", pub_hex_.c_str(),
601 "NONC", nonce_hex_.c_str(),
602 "VER\0", client_version_.data(),
603 "$padding", static_cast<int>(kClientHelloMinimumSize),
604 nullptr);
605 // clang-format on
606 ShouldSucceed(msg);
607 // The message should be rejected because the strike-register is still
608 // quiescent.
609 CheckRejectTag();
611 const HandshakeFailureReason kRejectReasons[] = {
612 CLIENT_NONCE_INVALID_TIME_FAILURE};
613 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
615 config_.set_replay_protection(false);
617 ShouldSucceed(msg);
618 // The message should be accepted now.
619 ASSERT_EQ(kSHLO, out_.tag());
620 CheckServerHello(out_);
622 ShouldSucceed(msg);
623 // The message should accepted twice when replay protection is off.
624 ASSERT_EQ(kSHLO, out_.tag());
625 CheckServerHello(out_);
628 TEST(CryptoServerConfigGenerationTest, Determinism) {
629 // Test that using a deterministic PRNG causes the server-config to be
630 // deterministic.
632 MockRandom rand_a, rand_b;
633 const QuicCryptoServerConfig::ConfigOptions options;
634 MockClock clock;
636 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
637 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
638 scoped_ptr<CryptoHandshakeMessage> scfg_a(
639 a.AddDefaultConfig(&rand_a, &clock, options));
640 scoped_ptr<CryptoHandshakeMessage> scfg_b(
641 b.AddDefaultConfig(&rand_b, &clock, options));
643 ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString());
646 TEST(CryptoServerConfigGenerationTest, SCIDVaries) {
647 // This test ensures that the server config ID varies for different server
648 // configs.
650 MockRandom rand_a, rand_b;
651 const QuicCryptoServerConfig::ConfigOptions options;
652 MockClock clock;
654 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
655 rand_b.ChangeValue();
656 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
657 scoped_ptr<CryptoHandshakeMessage> scfg_a(
658 a.AddDefaultConfig(&rand_a, &clock, options));
659 scoped_ptr<CryptoHandshakeMessage> scfg_b(
660 b.AddDefaultConfig(&rand_b, &clock, options));
662 StringPiece scid_a, scid_b;
663 EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a));
664 EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b));
666 EXPECT_NE(scid_a, scid_b);
669 TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) {
670 MockRandom rand_a;
671 const QuicCryptoServerConfig::ConfigOptions options;
672 MockClock clock;
674 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
675 scoped_ptr<CryptoHandshakeMessage> scfg(
676 a.AddDefaultConfig(&rand_a, &clock, options));
678 StringPiece scid;
679 EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
680 // Need to take a copy of |scid| has we're about to call |Erase|.
681 const string scid_str(scid.as_string());
683 scfg->Erase(kSCID);
684 scfg->MarkDirty();
685 const QuicData& serialized(scfg->GetSerialized());
687 scoped_ptr<crypto::SecureHash> hash(
688 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
689 hash->Update(serialized.data(), serialized.length());
690 uint8 digest[16];
691 hash->Finish(digest, sizeof(digest));
693 ASSERT_EQ(scid.size(), sizeof(digest));
694 EXPECT_EQ(0, memcmp(digest, scid_str.data(), sizeof(digest)));
697 class CryptoServerTestNoConfig : public CryptoServerTest {
698 public:
699 void SetUp() override {
700 // Deliberately don't add a config so that we can test this situation.
704 TEST_P(CryptoServerTestNoConfig, DontCrash) {
705 // clang-format off
706 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
707 "CHLO",
708 "VER\0", client_version_.data(),
709 "$padding", static_cast<int>(kClientHelloMinimumSize),
710 nullptr);
711 // clang-format on
712 ShouldFailMentioning("No config", msg);
714 const HandshakeFailureReason kRejectReasons[] = {
715 SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
716 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
719 class AsyncStrikeServerVerificationTest : public CryptoServerTest {
720 protected:
721 AsyncStrikeServerVerificationTest() {}
723 void SetUp() override {
724 const string kOrbit = "12345678";
725 config_options_.orbit = kOrbit;
726 strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
727 10000, // strike_register_max_entries
728 static_cast<uint32>(clock_.WallNow().ToUNIXSeconds()),
729 60, // strike_register_window_secs
730 reinterpret_cast<const uint8*>(kOrbit.data()),
731 StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
732 config_.SetStrikeRegisterClient(strike_register_client_);
733 CryptoServerTest::SetUp();
734 strike_register_client_->StartDelayingVerification();
737 DelayedVerifyStrikeRegisterClient* strike_register_client_;
740 TEST_P(AsyncStrikeServerVerificationTest, AsyncReplayProtection) {
741 // This tests async validation with a strike register works.
742 // clang-format off
743 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
744 "CHLO",
745 "AEAD", "AESG",
746 "KEXS", "C255",
747 "SCID", scid_hex_.c_str(),
748 "#004b5453", srct_hex_.c_str(),
749 "PUBS", pub_hex_.c_str(),
750 "NONC", nonce_hex_.c_str(),
751 "VER\0", client_version_.data(),
752 "$padding", static_cast<int>(kClientHelloMinimumSize),
753 nullptr);
754 // clang-format on
756 // Clear the message tag.
757 out_.set_tag(0);
759 bool called = false;
760 config_.ValidateClientHello(msg, client_address_.address(), &clock_,
761 new ValidateCallback(this, true, "", &called));
762 // The verification request was queued.
763 ASSERT_FALSE(called);
764 EXPECT_EQ(0u, out_.tag());
765 EXPECT_EQ(1, strike_register_client_->PendingVerifications());
767 // Continue processing the verification request.
768 strike_register_client_->RunPendingVerifications();
769 ASSERT_TRUE(called);
770 EXPECT_EQ(0, strike_register_client_->PendingVerifications());
771 // The message should be accepted now.
772 EXPECT_EQ(kSHLO, out_.tag());
774 // Rejected if replayed.
775 config_.ValidateClientHello(msg, client_address_.address(), &clock_,
776 new ValidateCallback(this, true, "", &called));
777 // The verification request was queued.
778 ASSERT_FALSE(called);
779 EXPECT_EQ(1, strike_register_client_->PendingVerifications());
781 strike_register_client_->RunPendingVerifications();
782 ASSERT_TRUE(called);
783 EXPECT_EQ(0, strike_register_client_->PendingVerifications());
784 // The message should be rejected now.
785 CheckRejectTag();
788 } // namespace test
789 } // namespace net