Process Alt-Svc headers.
[chromium-blink-merge.git] / net / quic / crypto / crypto_server_test.cc
blob46db1662a5a239fc125f81aef372656a112a64b7
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 config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
97 supported_versions_ = QuicSupportedVersions();
98 client_version_ = QuicUtils::TagToString(
99 QuicVersionToQuicTag(supported_versions_.front()));
101 FLAGS_use_early_return_when_verifying_chlo =
102 GetParam().use_early_return_when_verifying_chlo;
103 FLAGS_enable_quic_stateless_reject_support =
104 GetParam().enable_stateless_rejects;
105 use_stateless_rejects_ = GetParam().use_stateless_rejects;
108 void SetUp() override {
109 scoped_ptr<CryptoHandshakeMessage> msg(
110 config_.AddDefaultConfig(rand_, &clock_,
111 config_options_));
113 StringPiece orbit;
114 CHECK(msg->GetStringPiece(kORBT, &orbit));
115 CHECK_EQ(sizeof(orbit_), orbit.size());
116 memcpy(orbit_, orbit.data(), orbit.size());
118 char public_value[32];
119 memset(public_value, 42, sizeof(public_value));
121 const string nonce_str = GenerateNonce();
122 nonce_hex_ = "#" + base::HexEncode(nonce_str.data(), nonce_str.size());
123 pub_hex_ = "#" + base::HexEncode(public_value, sizeof(public_value));
125 CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
126 "CHLO",
127 "AEAD", "AESG",
128 "KEXS", "C255",
129 "PUBS", pub_hex_.c_str(),
130 "NONC", nonce_hex_.c_str(),
131 "VER\0", client_version_.data(),
132 "$padding", static_cast<int>(kClientHelloMinimumSize),
133 nullptr);
134 ShouldSucceed(client_hello);
135 // The message should be rejected because the source-address token is
136 // missing.
137 CheckRejectTag();
138 const HandshakeFailureReason kRejectReasons[] = {
139 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
141 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
142 CheckForServerDesignatedConnectionId();
144 StringPiece srct;
145 ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
146 srct_hex_ = "#" + base::HexEncode(srct.data(), srct.size());
148 StringPiece scfg;
149 ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg));
150 server_config_.reset(CryptoFramer::ParseMessage(scfg));
152 StringPiece scid;
153 ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid));
154 scid_hex_ = "#" + base::HexEncode(scid.data(), scid.size());
157 // Helper used to accept the result of ValidateClientHello and pass
158 // it on to ProcessClientHello.
159 class ValidateCallback : public ValidateClientHelloResultCallback {
160 public:
161 ValidateCallback(CryptoServerTest* test,
162 bool should_succeed,
163 const char* error_substr,
164 bool* called)
165 : test_(test),
166 should_succeed_(should_succeed),
167 error_substr_(error_substr),
168 called_(called) {
169 *called_ = false;
172 void RunImpl(const CryptoHandshakeMessage& client_hello,
173 const Result& result) override {
175 // Ensure that the strike register client lock is not held.
176 QuicCryptoServerConfigPeer peer(&test_->config_);
177 base::Lock* m = peer.GetStrikeRegisterClientLock();
178 // In Chromium, we will dead lock if the lock is held by the current
179 // thread. Chromium doesn't have AssertNotHeld API call.
180 // m->AssertNotHeld();
181 base::AutoLock lock(*m);
183 ASSERT_FALSE(*called_);
184 test_->ProcessValidationResult(
185 client_hello, result, should_succeed_, error_substr_);
186 *called_ = true;
189 private:
190 CryptoServerTest* test_;
191 bool should_succeed_;
192 const char* error_substr_;
193 bool* called_;
196 void CheckServerHello(const CryptoHandshakeMessage& server_hello) {
197 const QuicTag* versions;
198 size_t num_versions;
199 server_hello.GetTaglist(kVER, &versions, &num_versions);
200 ASSERT_EQ(QuicSupportedVersions().size(), num_versions);
201 for (size_t i = 0; i < num_versions; ++i) {
202 EXPECT_EQ(QuicVersionToQuicTag(QuicSupportedVersions()[i]), versions[i]);
205 StringPiece address;
206 ASSERT_TRUE(server_hello.GetStringPiece(kCADR, &address));
207 QuicSocketAddressCoder decoder;
208 ASSERT_TRUE(decoder.Decode(address.data(), address.size()));
209 EXPECT_EQ(client_address_.address(), decoder.ip());
210 EXPECT_EQ(client_address_.port(), decoder.port());
213 void ShouldSucceed(const CryptoHandshakeMessage& message) {
214 bool called = false;
215 RunValidate(message, new ValidateCallback(this, true, "", &called));
216 EXPECT_TRUE(called);
219 void RunValidate(
220 const CryptoHandshakeMessage& message,
221 ValidateClientHelloResultCallback* cb) {
222 config_.ValidateClientHello(message, client_address_.address(), &clock_,
223 cb);
226 void ShouldFailMentioning(const char* error_substr,
227 const CryptoHandshakeMessage& message) {
228 bool called = false;
229 ShouldFailMentioning(error_substr, message, &called);
230 EXPECT_TRUE(called);
233 void ShouldFailMentioning(const char* error_substr,
234 const CryptoHandshakeMessage& message,
235 bool* called) {
236 config_.ValidateClientHello(
237 message, client_address_.address(), &clock_,
238 new ValidateCallback(this, false, error_substr, called));
241 void ProcessValidationResult(const CryptoHandshakeMessage& message,
242 const ValidateCallback::Result& result,
243 bool should_succeed,
244 const char* error_substr) {
245 IPAddressNumber server_ip;
246 string error_details;
247 QuicConnectionId server_designated_connection_id =
248 rand_for_id_generation_.RandUint64();
249 QuicErrorCode error = config_.ProcessClientHello(
250 result, 1 /* ConnectionId */, server_ip, client_address_,
251 supported_versions_.front(), supported_versions_,
252 use_stateless_rejects_, server_designated_connection_id, &clock_, rand_,
253 &params_, &out_, &error_details);
255 if (should_succeed) {
256 ASSERT_EQ(error, QUIC_NO_ERROR)
257 << "Message failed with error " << error_details << ": "
258 << message.DebugString();
259 } else {
260 ASSERT_NE(error, QUIC_NO_ERROR)
261 << "Message didn't fail: " << message.DebugString();
263 EXPECT_TRUE(error_details.find(error_substr) != string::npos)
264 << error_substr << " not in " << error_details;
268 CryptoHandshakeMessage InchoateClientHello(const char* message_tag, ...) {
269 va_list ap;
270 va_start(ap, message_tag);
272 CryptoHandshakeMessage message =
273 CryptoTestUtils::BuildMessage(message_tag, ap);
274 va_end(ap);
276 message.SetStringPiece(kPAD, string(kClientHelloMinimumSize, '-'));
277 return message;
280 string GenerateNonce() {
281 string nonce;
282 CryptoUtils::GenerateNonce(
283 clock_.WallNow(), rand_,
284 StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)),
285 &nonce);
286 return nonce;
289 void CheckRejectReasons(
290 const HandshakeFailureReason* expected_handshake_failures,
291 size_t expected_count) {
292 const uint32* reject_reasons;
293 size_t num_reject_reasons;
294 COMPILE_ASSERT(sizeof(QuicTag) == sizeof(uint32), header_out_of_sync);
295 QuicErrorCode error_code = out_.GetTaglist(kRREJ, &reject_reasons,
296 &num_reject_reasons);
297 ASSERT_EQ(QUIC_NO_ERROR, error_code);
299 if (FLAGS_use_early_return_when_verifying_chlo) {
300 EXPECT_EQ(1u, num_reject_reasons);
301 } else {
302 EXPECT_EQ(expected_count, num_reject_reasons);
304 for (size_t i = 0; i < num_reject_reasons; ++i) {
305 EXPECT_EQ(expected_handshake_failures[i], reject_reasons[i]);
309 // If the server is rejecting statelessly, make sure it contains a
310 // server-designated connection id. Once the check is complete,
311 // allow the random id-generator to move to the next value.
312 void CheckForServerDesignatedConnectionId() {
313 QuicConnectionId server_designated_connection_id;
314 if (!RejectsAreStateless()) {
315 EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
316 out_.GetUint64(kRCID, &server_designated_connection_id));
317 } else {
318 ASSERT_EQ(QUIC_NO_ERROR,
319 out_.GetUint64(kRCID, &server_designated_connection_id));
320 EXPECT_EQ(rand_for_id_generation_.RandUint64(),
321 server_designated_connection_id);
323 rand_for_id_generation_.ChangeValue();
326 void CheckRejectTag() {
327 if (RejectsAreStateless()) {
328 ASSERT_EQ(kSREJ, out_.tag());
329 } else {
330 ASSERT_EQ(kREJ, out_.tag());
334 bool RejectsAreStateless() {
335 return GetParam().enable_stateless_rejects &&
336 GetParam().use_stateless_rejects;
339 protected:
340 QuicRandom* const rand_;
341 MockRandom rand_for_id_generation_;
342 MockClock clock_;
343 const IPEndPoint client_address_;
344 QuicVersionVector supported_versions_;
345 string client_version_;
346 QuicCryptoServerConfig config_;
347 QuicCryptoServerConfig::ConfigOptions config_options_;
348 QuicCryptoNegotiatedParameters params_;
349 CryptoHandshakeMessage out_;
350 uint8 orbit_[kOrbitSize];
351 bool use_stateless_rejects_;
353 // These strings contain hex escaped values from the server suitable for
354 // passing to |InchoateClientHello| when constructing client hello messages.
355 string nonce_hex_, pub_hex_, srct_hex_, scid_hex_;
356 scoped_ptr<CryptoHandshakeMessage> server_config_;
359 // Run all CryptoServerTest with both values of
360 // FLAGS_use_early_return_when_verifying_chlo.
361 INSTANTIATE_TEST_CASE_P(CryptoServerTests,
362 CryptoServerTest,
363 ::testing::ValuesIn(GetTestParams()));
365 TEST_P(CryptoServerTest, BadSNI) {
366 static const char* const kBadSNIs[] = {
368 "foo",
369 "#00",
370 "#ff00",
371 "127.0.0.1",
372 "ffee::1",
375 string client_version = QuicUtils::TagToString(
376 QuicVersionToQuicTag(supported_versions_.front()));
378 for (size_t i = 0; i < arraysize(kBadSNIs); i++) {
379 ShouldFailMentioning("SNI", InchoateClientHello(
380 "CHLO",
381 "SNI", kBadSNIs[i],
382 "VER\0", client_version.data(),
383 nullptr));
384 const HandshakeFailureReason kRejectReasons[] = {
385 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
387 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
391 // TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource.
392 // See http://crbug.com/514472.
393 TEST_F(CryptoServerTest, DISABLED_DefaultCert) {
394 // Check that the server replies with a default certificate when no SNI is
395 // specified.
396 ShouldSucceed(InchoateClientHello(
397 "CHLO",
398 "AEAD", "AESG",
399 "KEXS", "C255",
400 "SCID", scid_hex_.c_str(),
401 "#004b5453", srct_hex_.c_str(),
402 "PUBS", pub_hex_.c_str(),
403 "NONC", nonce_hex_.c_str(),
404 "$padding", static_cast<int>(kClientHelloMinimumSize),
405 "PDMD", "X509",
406 "VER\0", client_version_.data(),
407 nullptr));
409 StringPiece cert, proof;
410 EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
411 EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
412 EXPECT_NE(0u, cert.size());
413 EXPECT_NE(0u, proof.size());
414 const HandshakeFailureReason kRejectReasons[] = {
415 CLIENT_NONCE_INVALID_TIME_FAILURE
417 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
420 TEST_P(CryptoServerTest, TooSmall) {
421 ShouldFailMentioning("too small", CryptoTestUtils::Message(
422 "CHLO",
423 "VER\0", client_version_.data(),
424 nullptr));
425 const HandshakeFailureReason kRejectReasons[] = {
426 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
428 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
431 TEST_P(CryptoServerTest, BadSourceAddressToken) {
432 // Invalid source-address tokens should be ignored.
433 static const char* const kBadSourceAddressTokens[] = {
435 "foo",
436 "#0000",
437 "#0000000000000000000000000000000000000000",
440 for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) {
441 ShouldSucceed(InchoateClientHello(
442 "CHLO",
443 "STK", kBadSourceAddressTokens[i],
444 "VER\0", client_version_.data(),
445 nullptr));
446 const HandshakeFailureReason kRejectReasons[] = {
447 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
449 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
453 TEST_P(CryptoServerTest, BadClientNonce) {
454 // Invalid nonces should be ignored.
455 static const char* const kBadNonces[] = {
457 "#0000",
458 "#0000000000000000000000000000000000000000",
461 for (size_t i = 0; i < arraysize(kBadNonces); i++) {
462 ShouldSucceed(InchoateClientHello(
463 "CHLO",
464 "NONC", kBadNonces[i],
465 "VER\0", client_version_.data(),
466 nullptr));
467 const HandshakeFailureReason kRejectReasons[] = {
468 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
470 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
474 TEST_P(CryptoServerTest, DowngradeAttack) {
475 if (supported_versions_.size() == 1) {
476 // No downgrade attack is possible if the server only supports one version.
477 return;
479 // Set the client's preferred version to a supported version that
480 // is not the "current" version (supported_versions_.front()).
481 string bad_version = QuicUtils::TagToString(
482 QuicVersionToQuicTag(supported_versions_.back()));
484 ShouldFailMentioning("Downgrade", InchoateClientHello(
485 "CHLO",
486 "VER\0", bad_version.data(),
487 nullptr));
488 const HandshakeFailureReason kRejectReasons[] = {
489 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
491 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
494 TEST_P(CryptoServerTest, CorruptServerConfig) {
495 // This tests corrupted server config.
496 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
497 "CHLO",
498 "AEAD", "AESG",
499 "KEXS", "C255",
500 "SCID", (string(1, 'X') + scid_hex_).c_str(),
501 "#004b5453", srct_hex_.c_str(),
502 "PUBS", pub_hex_.c_str(),
503 "NONC", nonce_hex_.c_str(),
504 "VER\0", client_version_.data(),
505 "$padding", static_cast<int>(kClientHelloMinimumSize),
506 nullptr);
507 ShouldSucceed(msg);
508 CheckRejectTag();
509 const HandshakeFailureReason kRejectReasons[] = {
510 SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE
512 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
515 TEST_P(CryptoServerTest, CorruptSourceAddressToken) {
516 // This tests corrupted source address token.
517 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
518 "CHLO",
519 "AEAD", "AESG",
520 "KEXS", "C255",
521 "SCID", scid_hex_.c_str(),
522 "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
523 "PUBS", pub_hex_.c_str(),
524 "NONC", nonce_hex_.c_str(),
525 "VER\0", client_version_.data(),
526 "$padding", static_cast<int>(kClientHelloMinimumSize),
527 nullptr);
528 ShouldSucceed(msg);
529 CheckRejectTag();
530 const HandshakeFailureReason kRejectReasons[] = {
531 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
533 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
536 TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) {
537 // This test corrupts client nonce and source address token.
538 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
539 "CHLO",
540 "AEAD", "AESG",
541 "KEXS", "C255",
542 "SCID", scid_hex_.c_str(),
543 "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
544 "PUBS", pub_hex_.c_str(),
545 "NONC", (string(1, 'X') + nonce_hex_).c_str(),
546 "VER\0", client_version_.data(),
547 "$padding", static_cast<int>(kClientHelloMinimumSize),
548 nullptr);
549 ShouldSucceed(msg);
550 CheckRejectTag();
551 const HandshakeFailureReason kRejectReasons[] = {
552 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
553 CLIENT_NONCE_INVALID_FAILURE
555 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
558 TEST_P(CryptoServerTest, CorruptMultipleTags) {
559 // This test corrupts client nonce, server nonce and source address token.
560 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
561 "CHLO",
562 "AEAD", "AESG",
563 "KEXS", "C255",
564 "SCID", scid_hex_.c_str(),
565 "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
566 "PUBS", pub_hex_.c_str(),
567 "NONC", (string(1, 'X') + nonce_hex_).c_str(),
568 "SNO\0", (string(1, 'X') + nonce_hex_).c_str(),
569 "VER\0", client_version_.data(),
570 "$padding", static_cast<int>(kClientHelloMinimumSize),
571 nullptr);
572 ShouldSucceed(msg);
573 CheckRejectTag();
574 const HandshakeFailureReason kRejectReasons[] = {
575 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
576 CLIENT_NONCE_INVALID_FAILURE,
577 SERVER_NONCE_DECRYPTION_FAILURE,
579 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
582 TEST_P(CryptoServerTest, ReplayProtection) {
583 // This tests that disabling replay protection works.
584 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
585 "CHLO",
586 "AEAD", "AESG",
587 "KEXS", "C255",
588 "SCID", scid_hex_.c_str(),
589 "#004b5453", srct_hex_.c_str(),
590 "PUBS", pub_hex_.c_str(),
591 "NONC", nonce_hex_.c_str(),
592 "VER\0", client_version_.data(),
593 "$padding", static_cast<int>(kClientHelloMinimumSize),
594 nullptr);
595 ShouldSucceed(msg);
596 // The message should be rejected because the strike-register is still
597 // quiescent.
598 CheckRejectTag();
600 const HandshakeFailureReason kRejectReasons[] = {
601 CLIENT_NONCE_INVALID_TIME_FAILURE
603 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
605 config_.set_replay_protection(false);
607 ShouldSucceed(msg);
608 // The message should be accepted now.
609 ASSERT_EQ(kSHLO, out_.tag());
610 CheckServerHello(out_);
612 ShouldSucceed(msg);
613 // The message should accepted twice when replay protection is off.
614 ASSERT_EQ(kSHLO, out_.tag());
615 CheckServerHello(out_);
618 TEST(CryptoServerConfigGenerationTest, Determinism) {
619 // Test that using a deterministic PRNG causes the server-config to be
620 // deterministic.
622 MockRandom rand_a, rand_b;
623 const QuicCryptoServerConfig::ConfigOptions options;
624 MockClock clock;
626 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
627 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
628 scoped_ptr<CryptoHandshakeMessage> scfg_a(
629 a.AddDefaultConfig(&rand_a, &clock, options));
630 scoped_ptr<CryptoHandshakeMessage> scfg_b(
631 b.AddDefaultConfig(&rand_b, &clock, options));
633 ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString());
636 TEST(CryptoServerConfigGenerationTest, SCIDVaries) {
637 // This test ensures that the server config ID varies for different server
638 // configs.
640 MockRandom rand_a, rand_b;
641 const QuicCryptoServerConfig::ConfigOptions options;
642 MockClock clock;
644 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
645 rand_b.ChangeValue();
646 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
647 scoped_ptr<CryptoHandshakeMessage> scfg_a(
648 a.AddDefaultConfig(&rand_a, &clock, options));
649 scoped_ptr<CryptoHandshakeMessage> scfg_b(
650 b.AddDefaultConfig(&rand_b, &clock, options));
652 StringPiece scid_a, scid_b;
653 EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a));
654 EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b));
656 EXPECT_NE(scid_a, scid_b);
659 TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) {
660 MockRandom rand_a;
661 const QuicCryptoServerConfig::ConfigOptions options;
662 MockClock clock;
664 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
665 scoped_ptr<CryptoHandshakeMessage> scfg(
666 a.AddDefaultConfig(&rand_a, &clock, options));
668 StringPiece scid;
669 EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
670 // Need to take a copy of |scid| has we're about to call |Erase|.
671 const string scid_str(scid.as_string());
673 scfg->Erase(kSCID);
674 scfg->MarkDirty();
675 const QuicData& serialized(scfg->GetSerialized());
677 scoped_ptr<crypto::SecureHash> hash(
678 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
679 hash->Update(serialized.data(), serialized.length());
680 uint8 digest[16];
681 hash->Finish(digest, sizeof(digest));
683 ASSERT_EQ(scid.size(), sizeof(digest));
684 EXPECT_EQ(0, memcmp(digest, scid_str.data(), sizeof(digest)));
687 class CryptoServerTestNoConfig : public CryptoServerTest {
688 public:
689 void SetUp() override {
690 // Deliberately don't add a config so that we can test this situation.
694 TEST_P(CryptoServerTestNoConfig, DontCrash) {
695 ShouldFailMentioning("No config", InchoateClientHello(
696 "CHLO",
697 "VER\0", client_version_.data(),
698 nullptr));
700 const HandshakeFailureReason kRejectReasons[] = {
701 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
703 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
706 class AsyncStrikeServerVerificationTest : public CryptoServerTest {
707 protected:
708 AsyncStrikeServerVerificationTest() {
711 void SetUp() override {
712 const string kOrbit = "12345678";
713 config_options_.orbit = kOrbit;
714 strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
715 10000, // strike_register_max_entries
716 static_cast<uint32>(clock_.WallNow().ToUNIXSeconds()),
717 60, // strike_register_window_secs
718 reinterpret_cast<const uint8 *>(kOrbit.data()),
719 StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
720 config_.SetStrikeRegisterClient(strike_register_client_);
721 CryptoServerTest::SetUp();
722 strike_register_client_->StartDelayingVerification();
725 DelayedVerifyStrikeRegisterClient* strike_register_client_;
728 TEST_P(AsyncStrikeServerVerificationTest, AsyncReplayProtection) {
729 // This tests async validation with a strike register works.
730 CryptoHandshakeMessage msg = CryptoTestUtils::Message(
731 "CHLO",
732 "AEAD", "AESG",
733 "KEXS", "C255",
734 "SCID", scid_hex_.c_str(),
735 "#004b5453", srct_hex_.c_str(),
736 "PUBS", pub_hex_.c_str(),
737 "NONC", nonce_hex_.c_str(),
738 "VER\0", client_version_.data(),
739 "$padding", static_cast<int>(kClientHelloMinimumSize),
740 nullptr);
742 // Clear the message tag.
743 out_.set_tag(0);
745 bool called = false;
746 RunValidate(msg, new ValidateCallback(this, true, "", &called));
747 // The verification request was queued.
748 ASSERT_FALSE(called);
749 EXPECT_EQ(0u, out_.tag());
750 EXPECT_EQ(1, strike_register_client_->PendingVerifications());
752 // Continue processing the verification request.
753 strike_register_client_->RunPendingVerifications();
754 ASSERT_TRUE(called);
755 EXPECT_EQ(0, strike_register_client_->PendingVerifications());
756 // The message should be accepted now.
757 EXPECT_EQ(kSHLO, out_.tag());
759 // Rejected if replayed.
760 RunValidate(msg, new ValidateCallback(this, true, "", &called));
761 // The verification request was queued.
762 ASSERT_FALSE(called);
763 EXPECT_EQ(1, strike_register_client_->PendingVerifications());
765 strike_register_client_->RunPendingVerifications();
766 ASSERT_TRUE(called);
767 EXPECT_EQ(0, strike_register_client_->PendingVerifications());
768 // The message should be rejected now.
769 CheckRejectTag();
772 } // namespace test
773 } // namespace net