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. 4 5 #include <ostream> 6 #include <vector> 7 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" 23 24 using base::StringPiece; 25 using std::ostream; 26 using std::string; 27 using std::vector; 28 29 namespace net { 30 namespace test { 31 32 class QuicCryptoServerConfigPeer { 33 public: 34 explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config) 35 : server_config_(server_config) {} 36 37 base::Lock* GetStrikeRegisterClientLock() { 38 return &server_config_->strike_register_client_lock_; 39 } 40 41 private: 42 QuicCryptoServerConfig* server_config_; 43 }; 44 45 // Run tests with combinations of 46 // {FLAGS_use_early_return_when_verifying_chlo, 47 // FLAGS_send_quic_crypto_reject_reason}. 48 struct TestParams { 49 TestParams(bool use_early_return_when_verifying_chlo, 50 bool send_quic_crypto_reject_reason) 51 : use_early_return_when_verifying_chlo( 52 use_early_return_when_verifying_chlo), 53 send_quic_crypto_reject_reason(send_quic_crypto_reject_reason) { 54 } 55 56 friend ostream& operator<<(ostream& os, const TestParams& p) { 57 os << "{ use_early_return_when_verifying_chlo: " 58 << p.use_early_return_when_verifying_chlo 59 << " send_quic_crypto_reject_reason: " 60 << p.send_quic_crypto_reject_reason << " }"; 61 return os; 62 } 63 64 bool use_early_return_when_verifying_chlo; 65 bool send_quic_crypto_reject_reason; 66 }; 67 68 // Constructs various test permutations. 69 vector<TestParams> GetTestParams() { 70 vector<TestParams> params; 71 params.push_back(TestParams(false, false)); 72 params.push_back(TestParams(false, true)); 73 params.push_back(TestParams(true, false)); 74 params.push_back(TestParams(true, true)); 75 return params; 76 } 77 78 class CryptoServerTest : public ::testing::TestWithParam<TestParams> { 79 public: 80 CryptoServerTest() 81 : rand_(QuicRandom::GetInstance()), 82 client_address_(Loopback4(), 1234), 83 config_(QuicCryptoServerConfig::TESTING, rand_) { 84 config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting()); 85 supported_versions_ = QuicSupportedVersions(); 86 client_version_ = QuicUtils::TagToString( 87 QuicVersionToQuicTag(supported_versions_.front())); 88 89 FLAGS_use_early_return_when_verifying_chlo = 90 GetParam().use_early_return_when_verifying_chlo; 91 FLAGS_send_quic_crypto_reject_reason = 92 GetParam().send_quic_crypto_reject_reason; 93 } 94 95 virtual void SetUp() { 96 scoped_ptr<CryptoHandshakeMessage> msg( 97 config_.AddDefaultConfig(rand_, &clock_, 98 config_options_)); 99 100 StringPiece orbit; 101 CHECK(msg->GetStringPiece(kORBT, &orbit)); 102 CHECK_EQ(sizeof(orbit_), orbit.size()); 103 memcpy(orbit_, orbit.data(), orbit.size()); 104 105 char public_value[32]; 106 memset(public_value, 42, sizeof(public_value)); 107 108 const string nonce_str = GenerateNonce(); 109 nonce_hex_ = "#" + base::HexEncode(nonce_str.data(), nonce_str.size()); 110 pub_hex_ = "#" + base::HexEncode(public_value, sizeof(public_value)); 111 112 CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( 113 "CHLO", 114 "AEAD", "AESG", 115 "KEXS", "C255", 116 "PUBS", pub_hex_.c_str(), 117 "NONC", nonce_hex_.c_str(), 118 "VER\0", client_version_.data(), 119 "$padding", static_cast<int>(kClientHelloMinimumSize), 120 NULL); 121 ShouldSucceed(client_hello); 122 // The message should be rejected because the source-address token is 123 // missing. 124 ASSERT_EQ(kREJ, out_.tag()); 125 const HandshakeFailureReason kRejectReasons[] = { 126 SERVER_CONFIG_INCHOATE_HELLO_FAILURE 127 }; 128 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 129 130 StringPiece srct; 131 ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct)); 132 srct_hex_ = "#" + base::HexEncode(srct.data(), srct.size()); 133 134 StringPiece scfg; 135 ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg)); 136 server_config_.reset(CryptoFramer::ParseMessage(scfg)); 137 138 StringPiece scid; 139 ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid)); 140 scid_hex_ = "#" + base::HexEncode(scid.data(), scid.size()); 141 } 142 143 // Helper used to accept the result of ValidateClientHello and pass 144 // it on to ProcessClientHello. 145 class ValidateCallback : public ValidateClientHelloResultCallback { 146 public: 147 ValidateCallback(CryptoServerTest* test, 148 bool should_succeed, 149 const char* error_substr, 150 bool* called) 151 : test_(test), 152 should_succeed_(should_succeed), 153 error_substr_(error_substr), 154 called_(called) { 155 *called_ = false; 156 } 157 158 virtual void RunImpl(const CryptoHandshakeMessage& client_hello, 159 const Result& result) OVERRIDE { 160 { 161 // Ensure that the strike register client lock is not held. 162 QuicCryptoServerConfigPeer peer(&test_->config_); 163 base::Lock* m = peer.GetStrikeRegisterClientLock(); 164 // In Chromium, we will dead lock if the lock is held by the current 165 // thread. Chromium doesn't have AssertNotHeld API call. 166 // m->AssertNotHeld(); 167 base::AutoLock lock(*m); 168 } 169 ASSERT_FALSE(*called_); 170 test_->ProcessValidationResult( 171 client_hello, result, should_succeed_, error_substr_); 172 *called_ = true; 173 } 174 175 private: 176 CryptoServerTest* test_; 177 bool should_succeed_; 178 const char* error_substr_; 179 bool* called_; 180 }; 181 182 void CheckServerHello(const CryptoHandshakeMessage& server_hello) { 183 const QuicTag* versions; 184 size_t num_versions; 185 server_hello.GetTaglist(kVER, &versions, &num_versions); 186 ASSERT_EQ(QuicSupportedVersions().size(), num_versions); 187 for (size_t i = 0; i < num_versions; ++i) { 188 EXPECT_EQ(QuicVersionToQuicTag(QuicSupportedVersions()[i]), versions[i]); 189 } 190 191 StringPiece address; 192 ASSERT_TRUE(server_hello.GetStringPiece(kCADR, &address)); 193 QuicSocketAddressCoder decoder; 194 ASSERT_TRUE(decoder.Decode(address.data(), address.size())); 195 EXPECT_EQ(client_address_.address(), decoder.ip()); 196 EXPECT_EQ(client_address_.port(), decoder.port()); 197 } 198 199 void ShouldSucceed(const CryptoHandshakeMessage& message) { 200 bool called = false; 201 RunValidate(message, new ValidateCallback(this, true, "", &called)); 202 EXPECT_TRUE(called); 203 } 204 205 void RunValidate( 206 const CryptoHandshakeMessage& message, 207 ValidateClientHelloResultCallback* cb) { 208 config_.ValidateClientHello(message, client_address_, &clock_, cb); 209 } 210 211 void ShouldFailMentioning(const char* error_substr, 212 const CryptoHandshakeMessage& message) { 213 bool called = false; 214 ShouldFailMentioning(error_substr, message, &called); 215 EXPECT_TRUE(called); 216 } 217 218 void ShouldFailMentioning(const char* error_substr, 219 const CryptoHandshakeMessage& message, 220 bool* called) { 221 config_.ValidateClientHello( 222 message, client_address_, &clock_, 223 new ValidateCallback(this, false, error_substr, called)); 224 } 225 226 void ProcessValidationResult(const CryptoHandshakeMessage& message, 227 const ValidateCallback::Result& result, 228 bool should_succeed, 229 const char* error_substr) { 230 string error_details; 231 QuicErrorCode error = config_.ProcessClientHello( 232 result, 1 /* ConnectionId */, client_address_, 233 supported_versions_.front(), supported_versions_, &clock_, rand_, 234 ¶ms_, &out_, &error_details); 235 236 if (should_succeed) { 237 ASSERT_EQ(error, QUIC_NO_ERROR) 238 << "Message failed with error " << error_details << ": " 239 << message.DebugString(); 240 } else { 241 ASSERT_NE(error, QUIC_NO_ERROR) 242 << "Message didn't fail: " << message.DebugString(); 243 244 EXPECT_TRUE(error_details.find(error_substr) != string::npos) 245 << error_substr << " not in " << error_details; 246 } 247 } 248 249 CryptoHandshakeMessage InchoateClientHello(const char* message_tag, ...) { 250 va_list ap; 251 va_start(ap, message_tag); 252 253 CryptoHandshakeMessage message = 254 CryptoTestUtils::BuildMessage(message_tag, ap); 255 va_end(ap); 256 257 message.SetStringPiece(kPAD, string(kClientHelloMinimumSize, '-')); 258 return message; 259 } 260 261 string GenerateNonce() { 262 string nonce; 263 CryptoUtils::GenerateNonce( 264 clock_.WallNow(), rand_, 265 StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)), 266 &nonce); 267 return nonce; 268 } 269 270 void CheckRejectReasons( 271 const HandshakeFailureReason* expected_handshake_failures, 272 size_t expected_count) { 273 const uint32* reject_reasons; 274 size_t num_reject_reasons; 275 COMPILE_ASSERT(sizeof(QuicTag) == sizeof(uint32), header_out_of_sync); 276 QuicErrorCode error_code = out_.GetTaglist(kRREJ, &reject_reasons, 277 &num_reject_reasons); 278 if (!FLAGS_send_quic_crypto_reject_reason) { 279 ASSERT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error_code); 280 return; 281 } 282 ASSERT_EQ(QUIC_NO_ERROR, error_code); 283 284 if (FLAGS_use_early_return_when_verifying_chlo) { 285 EXPECT_EQ(1u, num_reject_reasons); 286 } else { 287 EXPECT_EQ(expected_count, num_reject_reasons); 288 } 289 for (size_t i = 0; i < num_reject_reasons; ++i) { 290 EXPECT_EQ(expected_handshake_failures[i], reject_reasons[i]); 291 } 292 } 293 294 protected: 295 QuicRandom* const rand_; 296 MockClock clock_; 297 const IPEndPoint client_address_; 298 QuicVersionVector supported_versions_; 299 string client_version_; 300 QuicCryptoServerConfig config_; 301 QuicCryptoServerConfig::ConfigOptions config_options_; 302 QuicCryptoNegotiatedParameters params_; 303 CryptoHandshakeMessage out_; 304 uint8 orbit_[kOrbitSize]; 305 306 // These strings contain hex escaped values from the server suitable for 307 // passing to |InchoateClientHello| when constructing client hello messages. 308 string nonce_hex_, pub_hex_, srct_hex_, scid_hex_; 309 scoped_ptr<CryptoHandshakeMessage> server_config_; 310 }; 311 312 // Run all CryptoServerTest with all combinations of 313 // FLAGS_use_early_return_when_verifying_chlo and 314 // FLAGS_send_quic_crypto_reject_reason. 315 INSTANTIATE_TEST_CASE_P(CryptoServerTests, 316 CryptoServerTest, 317 ::testing::ValuesIn(GetTestParams())); 318 319 TEST_P(CryptoServerTest, BadSNI) { 320 static const char* kBadSNIs[] = { 321 "", 322 "foo", 323 "#00", 324 "#ff00", 325 "127.0.0.1", 326 "ffee::1", 327 }; 328 329 string client_version = QuicUtils::TagToString( 330 QuicVersionToQuicTag(supported_versions_.front())); 331 332 for (size_t i = 0; i < arraysize(kBadSNIs); i++) { 333 ShouldFailMentioning("SNI", InchoateClientHello( 334 "CHLO", 335 "SNI", kBadSNIs[i], 336 "VER\0", client_version.data(), 337 NULL)); 338 const HandshakeFailureReason kRejectReasons[] = { 339 SERVER_CONFIG_INCHOATE_HELLO_FAILURE 340 }; 341 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 342 } 343 } 344 345 // TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource. 346 TEST_F(CryptoServerTest, DISABLED_DefaultCert) { 347 // Check that the server replies with a default certificate when no SNI is 348 // specified. 349 ShouldSucceed(InchoateClientHello( 350 "CHLO", 351 "AEAD", "AESG", 352 "KEXS", "C255", 353 "SCID", scid_hex_.c_str(), 354 "#004b5453", srct_hex_.c_str(), 355 "PUBS", pub_hex_.c_str(), 356 "NONC", nonce_hex_.c_str(), 357 "$padding", static_cast<int>(kClientHelloMinimumSize), 358 "PDMD", "X509", 359 "VER\0", client_version_.data(), 360 NULL)); 361 362 StringPiece cert, proof; 363 EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); 364 EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); 365 EXPECT_NE(0u, cert.size()); 366 EXPECT_NE(0u, proof.size()); 367 const HandshakeFailureReason kRejectReasons[] = { 368 CLIENT_NONCE_INVALID_TIME_FAILURE 369 }; 370 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 371 } 372 373 TEST_P(CryptoServerTest, TooSmall) { 374 ShouldFailMentioning("too small", CryptoTestUtils::Message( 375 "CHLO", 376 "VER\0", client_version_.data(), 377 NULL)); 378 const HandshakeFailureReason kRejectReasons[] = { 379 SERVER_CONFIG_INCHOATE_HELLO_FAILURE 380 }; 381 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 382 } 383 384 TEST_P(CryptoServerTest, BadSourceAddressToken) { 385 // Invalid source-address tokens should be ignored. 386 static const char* kBadSourceAddressTokens[] = { 387 "", 388 "foo", 389 "#0000", 390 "#0000000000000000000000000000000000000000", 391 }; 392 393 for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) { 394 ShouldSucceed(InchoateClientHello( 395 "CHLO", 396 "STK", kBadSourceAddressTokens[i], 397 "VER\0", client_version_.data(), 398 NULL)); 399 const HandshakeFailureReason kRejectReasons[] = { 400 SERVER_CONFIG_INCHOATE_HELLO_FAILURE 401 }; 402 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 403 } 404 } 405 406 TEST_P(CryptoServerTest, BadClientNonce) { 407 // Invalid nonces should be ignored. 408 static const char* kBadNonces[] = { 409 "", 410 "#0000", 411 "#0000000000000000000000000000000000000000", 412 }; 413 414 for (size_t i = 0; i < arraysize(kBadNonces); i++) { 415 ShouldSucceed(InchoateClientHello( 416 "CHLO", 417 "NONC", kBadNonces[i], 418 "VER\0", client_version_.data(), 419 NULL)); 420 const HandshakeFailureReason kRejectReasons[] = { 421 SERVER_CONFIG_INCHOATE_HELLO_FAILURE 422 }; 423 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 424 } 425 } 426 427 TEST_P(CryptoServerTest, DowngradeAttack) { 428 if (supported_versions_.size() == 1) { 429 // No downgrade attack is possible if the server only supports one version. 430 return; 431 } 432 // Set the client's preferred version to a supported version that 433 // is not the "current" version (supported_versions_.front()). 434 string bad_version = QuicUtils::TagToString( 435 QuicVersionToQuicTag(supported_versions_.back())); 436 437 ShouldFailMentioning("Downgrade", InchoateClientHello( 438 "CHLO", 439 "VER\0", bad_version.data(), 440 NULL)); 441 const HandshakeFailureReason kRejectReasons[] = { 442 SERVER_CONFIG_INCHOATE_HELLO_FAILURE 443 }; 444 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 445 } 446 447 TEST_P(CryptoServerTest, CorruptServerConfig) { 448 // This tests corrupted server config. 449 CryptoHandshakeMessage msg = CryptoTestUtils::Message( 450 "CHLO", 451 "AEAD", "AESG", 452 "KEXS", "C255", 453 "SCID", (string(1, 'X') + scid_hex_).c_str(), 454 "#004b5453", srct_hex_.c_str(), 455 "PUBS", pub_hex_.c_str(), 456 "NONC", nonce_hex_.c_str(), 457 "VER\0", client_version_.data(), 458 "$padding", static_cast<int>(kClientHelloMinimumSize), 459 NULL); 460 ShouldSucceed(msg); 461 ASSERT_EQ(kREJ, out_.tag()); 462 const HandshakeFailureReason kRejectReasons[] = { 463 SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE 464 }; 465 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 466 } 467 468 TEST_P(CryptoServerTest, CorruptSourceAddressToken) { 469 // This tests corrupted source address token. 470 CryptoHandshakeMessage msg = CryptoTestUtils::Message( 471 "CHLO", 472 "AEAD", "AESG", 473 "KEXS", "C255", 474 "SCID", scid_hex_.c_str(), 475 "#004b5453", (string(1, 'X') + srct_hex_).c_str(), 476 "PUBS", pub_hex_.c_str(), 477 "NONC", nonce_hex_.c_str(), 478 "VER\0", client_version_.data(), 479 "$padding", static_cast<int>(kClientHelloMinimumSize), 480 NULL); 481 ShouldSucceed(msg); 482 ASSERT_EQ(kREJ, out_.tag()); 483 const HandshakeFailureReason kRejectReasons[] = { 484 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE 485 }; 486 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 487 } 488 489 TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) { 490 // This test corrupts client nonce and source address token. 491 CryptoHandshakeMessage msg = CryptoTestUtils::Message( 492 "CHLO", 493 "AEAD", "AESG", 494 "KEXS", "C255", 495 "SCID", scid_hex_.c_str(), 496 "#004b5453", (string(1, 'X') + srct_hex_).c_str(), 497 "PUBS", pub_hex_.c_str(), 498 "NONC", (string(1, 'X') + nonce_hex_).c_str(), 499 "VER\0", client_version_.data(), 500 "$padding", static_cast<int>(kClientHelloMinimumSize), 501 NULL); 502 ShouldSucceed(msg); 503 ASSERT_EQ(kREJ, out_.tag()); 504 const HandshakeFailureReason kRejectReasons[] = { 505 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, 506 CLIENT_NONCE_INVALID_FAILURE 507 }; 508 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 509 } 510 511 TEST_P(CryptoServerTest, CorruptMultipleTags) { 512 // This test corrupts client nonce, server nonce and source address token. 513 CryptoHandshakeMessage msg = CryptoTestUtils::Message( 514 "CHLO", 515 "AEAD", "AESG", 516 "KEXS", "C255", 517 "SCID", scid_hex_.c_str(), 518 "#004b5453", (string(1, 'X') + srct_hex_).c_str(), 519 "PUBS", pub_hex_.c_str(), 520 "NONC", (string(1, 'X') + nonce_hex_).c_str(), 521 "SNO\0", (string(1, 'X') + nonce_hex_).c_str(), 522 "VER\0", client_version_.data(), 523 "$padding", static_cast<int>(kClientHelloMinimumSize), 524 NULL); 525 ShouldSucceed(msg); 526 ASSERT_EQ(kREJ, out_.tag()); 527 const HandshakeFailureReason kRejectReasons[] = { 528 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, 529 CLIENT_NONCE_INVALID_FAILURE, 530 SERVER_NONCE_DECRYPTION_FAILURE, 531 }; 532 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 533 } 534 535 TEST_P(CryptoServerTest, ReplayProtection) { 536 // This tests that disabling replay protection works. 537 CryptoHandshakeMessage msg = CryptoTestUtils::Message( 538 "CHLO", 539 "AEAD", "AESG", 540 "KEXS", "C255", 541 "SCID", scid_hex_.c_str(), 542 "#004b5453", srct_hex_.c_str(), 543 "PUBS", pub_hex_.c_str(), 544 "NONC", nonce_hex_.c_str(), 545 "VER\0", client_version_.data(), 546 "$padding", static_cast<int>(kClientHelloMinimumSize), 547 NULL); 548 ShouldSucceed(msg); 549 // The message should be rejected because the strike-register is still 550 // quiescent. 551 ASSERT_EQ(kREJ, out_.tag()); 552 553 const HandshakeFailureReason kRejectReasons[] = { 554 CLIENT_NONCE_INVALID_TIME_FAILURE 555 }; 556 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 557 558 config_.set_replay_protection(false); 559 560 ShouldSucceed(msg); 561 // The message should be accepted now. 562 ASSERT_EQ(kSHLO, out_.tag()); 563 CheckServerHello(out_); 564 565 ShouldSucceed(msg); 566 // The message should accepted twice when replay protection is off. 567 ASSERT_EQ(kSHLO, out_.tag()); 568 CheckServerHello(out_); 569 } 570 571 TEST(CryptoServerConfigGenerationTest, Determinism) { 572 // Test that using a deterministic PRNG causes the server-config to be 573 // deterministic. 574 575 MockRandom rand_a, rand_b; 576 const QuicCryptoServerConfig::ConfigOptions options; 577 MockClock clock; 578 579 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a); 580 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b); 581 scoped_ptr<CryptoHandshakeMessage> scfg_a( 582 a.AddDefaultConfig(&rand_a, &clock, options)); 583 scoped_ptr<CryptoHandshakeMessage> scfg_b( 584 b.AddDefaultConfig(&rand_b, &clock, options)); 585 586 ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString()); 587 } 588 589 TEST(CryptoServerConfigGenerationTest, SCIDVaries) { 590 // This test ensures that the server config ID varies for different server 591 // configs. 592 593 MockRandom rand_a, rand_b; 594 const QuicCryptoServerConfig::ConfigOptions options; 595 MockClock clock; 596 597 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a); 598 rand_b.ChangeValue(); 599 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b); 600 scoped_ptr<CryptoHandshakeMessage> scfg_a( 601 a.AddDefaultConfig(&rand_a, &clock, options)); 602 scoped_ptr<CryptoHandshakeMessage> scfg_b( 603 b.AddDefaultConfig(&rand_b, &clock, options)); 604 605 StringPiece scid_a, scid_b; 606 EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a)); 607 EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b)); 608 609 EXPECT_NE(scid_a, scid_b); 610 } 611 612 613 TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) { 614 MockRandom rand_a; 615 const QuicCryptoServerConfig::ConfigOptions options; 616 MockClock clock; 617 618 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a); 619 scoped_ptr<CryptoHandshakeMessage> scfg( 620 a.AddDefaultConfig(&rand_a, &clock, options)); 621 622 StringPiece scid; 623 EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid)); 624 // Need to take a copy of |scid| has we're about to call |Erase|. 625 const string scid_str(scid.as_string()); 626 627 scfg->Erase(kSCID); 628 scfg->MarkDirty(); 629 const QuicData& serialized(scfg->GetSerialized()); 630 631 scoped_ptr<crypto::SecureHash> hash( 632 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); 633 hash->Update(serialized.data(), serialized.length()); 634 uint8 digest[16]; 635 hash->Finish(digest, sizeof(digest)); 636 637 ASSERT_EQ(scid.size(), sizeof(digest)); 638 EXPECT_EQ(0, memcmp(digest, scid_str.data(), sizeof(digest))); 639 } 640 641 class CryptoServerTestNoConfig : public CryptoServerTest { 642 public: 643 virtual void SetUp() { 644 // Deliberately don't add a config so that we can test this situation. 645 } 646 }; 647 648 TEST_P(CryptoServerTestNoConfig, DontCrash) { 649 ShouldFailMentioning("No config", InchoateClientHello( 650 "CHLO", 651 "VER\0", client_version_.data(), 652 NULL)); 653 654 const HandshakeFailureReason kRejectReasons[] = { 655 SERVER_CONFIG_INCHOATE_HELLO_FAILURE 656 }; 657 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); 658 } 659 660 class AsyncStrikeServerVerificationTest : public CryptoServerTest { 661 protected: 662 AsyncStrikeServerVerificationTest() { 663 } 664 665 virtual void SetUp() { 666 const string kOrbit = "12345678"; 667 config_options_.orbit = kOrbit; 668 strike_register_client_ = new DelayedVerifyStrikeRegisterClient( 669 10000, // strike_register_max_entries 670 static_cast<uint32>(clock_.WallNow().ToUNIXSeconds()), 671 60, // strike_register_window_secs 672 reinterpret_cast<const uint8 *>(kOrbit.data()), 673 StrikeRegister::NO_STARTUP_PERIOD_NEEDED); 674 config_.SetStrikeRegisterClient(strike_register_client_); 675 CryptoServerTest::SetUp(); 676 strike_register_client_->StartDelayingVerification(); 677 } 678 679 DelayedVerifyStrikeRegisterClient* strike_register_client_; 680 }; 681 682 TEST_P(AsyncStrikeServerVerificationTest, AsyncReplayProtection) { 683 // This tests async validation with a strike register works. 684 CryptoHandshakeMessage msg = CryptoTestUtils::Message( 685 "CHLO", 686 "AEAD", "AESG", 687 "KEXS", "C255", 688 "SCID", scid_hex_.c_str(), 689 "#004b5453", srct_hex_.c_str(), 690 "PUBS", pub_hex_.c_str(), 691 "NONC", nonce_hex_.c_str(), 692 "VER\0", client_version_.data(), 693 "$padding", static_cast<int>(kClientHelloMinimumSize), 694 NULL); 695 696 // Clear the message tag. 697 out_.set_tag(0); 698 699 bool called = false; 700 RunValidate(msg, new ValidateCallback(this, true, "", &called)); 701 // The verification request was queued. 702 ASSERT_FALSE(called); 703 EXPECT_EQ(0u, out_.tag()); 704 EXPECT_EQ(1, strike_register_client_->PendingVerifications()); 705 706 // Continue processing the verification request. 707 strike_register_client_->RunPendingVerifications(); 708 ASSERT_TRUE(called); 709 EXPECT_EQ(0, strike_register_client_->PendingVerifications()); 710 // The message should be accepted now. 711 EXPECT_EQ(kSHLO, out_.tag()); 712 713 // Rejected if replayed. 714 RunValidate(msg, new ValidateCallback(this, true, "", &called)); 715 // The verification request was queued. 716 ASSERT_FALSE(called); 717 EXPECT_EQ(1, strike_register_client_->PendingVerifications()); 718 719 strike_register_client_->RunPendingVerifications(); 720 ASSERT_TRUE(called); 721 EXPECT_EQ(0, strike_register_client_->PendingVerifications()); 722 // The message should be rejected now. 723 EXPECT_EQ(kREJ, out_.tag()); 724 } 725 726 } // namespace test 727 } // namespace net 728