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 "base/strings/string_number_conversions.h" 6 #include "crypto/secure_hash.h" 7 #include "net/quic/crypto/crypto_utils.h" 8 #include "net/quic/crypto/quic_crypto_server_config.h" 9 #include "net/quic/crypto/quic_random.h" 10 #include "net/quic/quic_utils.h" 11 #include "net/quic/test_tools/crypto_test_utils.h" 12 #include "net/quic/test_tools/delayed_verify_strike_register_client.h" 13 #include "net/quic/test_tools/mock_clock.h" 14 #include "net/quic/test_tools/mock_random.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 using base::StringPiece; 18 using std::string; 19 20 namespace net { 21 namespace test { 22 23 class CryptoServerTest : public ::testing::Test { 24 public: 25 CryptoServerTest() 26 : rand_(QuicRandom::GetInstance()), 27 config_(QuicCryptoServerConfig::TESTING, rand_), 28 addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ? 29 ip_ : IPAddressNumber(), 1) { 30 config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting()); 31 supported_versions_ = QuicSupportedVersions(); 32 } 33 34 virtual void SetUp() { 35 scoped_ptr<CryptoHandshakeMessage> msg( 36 config_.AddDefaultConfig(rand_, &clock_, 37 config_options_)); 38 39 StringPiece orbit; 40 CHECK(msg->GetStringPiece(kORBT, &orbit)); 41 CHECK_EQ(sizeof(orbit_), orbit.size()); 42 memcpy(orbit_, orbit.data(), orbit.size()); 43 44 char public_value[32]; 45 memset(public_value, 42, sizeof(public_value)); 46 47 const string nonce_str = GenerateNonce(); 48 nonce_hex_ = "#" + base::HexEncode(nonce_str.data(), nonce_str.size()); 49 pub_hex_ = "#" + base::HexEncode(public_value, sizeof(public_value)); 50 51 CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( 52 "CHLO", 53 "AEAD", "AESG", 54 "KEXS", "C255", 55 "PUBS", pub_hex_.c_str(), 56 "NONC", nonce_hex_.c_str(), 57 "$padding", static_cast<int>(kClientHelloMinimumSize), 58 NULL); 59 ShouldSucceed(client_hello); 60 // The message should be rejected because the source-address token is 61 // missing. 62 ASSERT_EQ(kREJ, out_.tag()); 63 64 StringPiece srct; 65 ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct)); 66 srct_hex_ = "#" + base::HexEncode(srct.data(), srct.size()); 67 68 StringPiece scfg; 69 ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg)); 70 server_config_.reset(CryptoFramer::ParseMessage(scfg)); 71 72 StringPiece scid; 73 ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid)); 74 scid_hex_ = "#" + base::HexEncode(scid.data(), scid.size()); 75 } 76 77 // Helper used to accept the result of ValidateClientHello and pass 78 // it on to ProcessClientHello. 79 class ValidateCallback : public ValidateClientHelloResultCallback { 80 public: 81 ValidateCallback(CryptoServerTest* test, 82 bool should_succeed, 83 const char* error_substr, 84 bool* called) 85 : test_(test), 86 should_succeed_(should_succeed), 87 error_substr_(error_substr), 88 called_(called) { 89 *called_ = false; 90 } 91 92 virtual void RunImpl(const CryptoHandshakeMessage& client_hello, 93 const Result& result) OVERRIDE { 94 ASSERT_FALSE(*called_); 95 test_->ProcessValidationResult( 96 client_hello, result, should_succeed_, error_substr_); 97 *called_ = true; 98 } 99 100 private: 101 CryptoServerTest* test_; 102 bool should_succeed_; 103 const char* error_substr_; 104 bool* called_; 105 }; 106 107 void ShouldSucceed(const CryptoHandshakeMessage& message) { 108 bool called = false; 109 ShouldSucceed(message, &called); 110 EXPECT_TRUE(called); 111 } 112 113 void ShouldSucceed(const CryptoHandshakeMessage& message, 114 bool* called) { 115 config_.ValidateClientHello( 116 message, addr_, &clock_, 117 new ValidateCallback(this, true, "", called)); 118 } 119 120 void ShouldFailMentioning(const char* error_substr, 121 const CryptoHandshakeMessage& message) { 122 bool called = false; 123 ShouldFailMentioning(error_substr, message, &called); 124 EXPECT_TRUE(called); 125 } 126 127 void ShouldFailMentioning(const char* error_substr, 128 const CryptoHandshakeMessage& message, 129 bool* called) { 130 config_.ValidateClientHello( 131 message, addr_, &clock_, 132 new ValidateCallback(this, false, error_substr, called)); 133 } 134 135 void ProcessValidationResult(const CryptoHandshakeMessage& message, 136 const ValidateCallback::Result& result, 137 bool should_succeed, 138 const char* error_substr) { 139 string error_details; 140 QuicErrorCode error = config_.ProcessClientHello( 141 result, 1 /* GUID */, addr_, 142 supported_versions_.front(), supported_versions_, &clock_, rand_, 143 ¶ms_, &out_, &error_details); 144 145 if (should_succeed) { 146 ASSERT_EQ(error, QUIC_NO_ERROR) 147 << "Message failed with error " << error_details << ": " 148 << message.DebugString(); 149 } else { 150 ASSERT_NE(error, QUIC_NO_ERROR) 151 << "Message didn't fail: " << message.DebugString(); 152 153 EXPECT_TRUE(error_details.find(error_substr) != string::npos) 154 << error_substr << " not in " << error_details; 155 } 156 } 157 158 CryptoHandshakeMessage InchoateClientHello(const char* message_tag, ...) { 159 va_list ap; 160 va_start(ap, message_tag); 161 162 CryptoHandshakeMessage message = 163 CryptoTestUtils::BuildMessage(message_tag, ap); 164 va_end(ap); 165 166 message.SetStringPiece(kPAD, string(kClientHelloMinimumSize, '-')); 167 return message; 168 } 169 170 string GenerateNonce() { 171 string nonce; 172 CryptoUtils::GenerateNonce( 173 clock_.WallNow(), rand_, 174 StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)), 175 &nonce); 176 return nonce; 177 } 178 179 protected: 180 QuicRandom* const rand_; 181 MockClock clock_; 182 QuicVersionVector supported_versions_; 183 QuicCryptoServerConfig config_; 184 QuicCryptoServerConfig::ConfigOptions config_options_; 185 QuicCryptoNegotiatedParameters params_; 186 CryptoHandshakeMessage out_; 187 IPAddressNumber ip_; 188 IPEndPoint addr_; 189 uint8 orbit_[kOrbitSize]; 190 191 // These strings contain hex escaped values from the server suitable for 192 // passing to |InchoateClientHello| when constructing client hello messages. 193 string nonce_hex_, pub_hex_, srct_hex_, scid_hex_; 194 scoped_ptr<CryptoHandshakeMessage> server_config_; 195 }; 196 197 TEST_F(CryptoServerTest, BadSNI) { 198 static const char* kBadSNIs[] = { 199 "", 200 "foo", 201 "#00", 202 "#ff00", 203 "127.0.0.1", 204 "ffee::1", 205 }; 206 207 for (size_t i = 0; i < arraysize(kBadSNIs); i++) { 208 ShouldFailMentioning("SNI", InchoateClientHello( 209 "CHLO", 210 "SNI", kBadSNIs[i], 211 NULL)); 212 } 213 } 214 215 // TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource. 216 TEST_F(CryptoServerTest, DISABLED_DefaultCert) { 217 // Check that the server replies with a default certificate when no SNI is 218 // specified. 219 ShouldSucceed(InchoateClientHello( 220 "CHLO", 221 "AEAD", "AESG", 222 "KEXS", "C255", 223 "SCID", scid_hex_.c_str(), 224 "#004b5453", srct_hex_.c_str(), 225 "PUBS", pub_hex_.c_str(), 226 "NONC", nonce_hex_.c_str(), 227 "$padding", static_cast<int>(kClientHelloMinimumSize), 228 "PDMD", "X509", 229 NULL)); 230 231 StringPiece cert, proof; 232 EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); 233 EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); 234 EXPECT_NE(0u, cert.size()); 235 EXPECT_NE(0u, proof.size()); 236 } 237 238 TEST_F(CryptoServerTest, TooSmall) { 239 ShouldFailMentioning("too small", CryptoTestUtils::Message( 240 "CHLO", 241 NULL)); 242 } 243 244 TEST_F(CryptoServerTest, BadSourceAddressToken) { 245 // Invalid source-address tokens should be ignored. 246 static const char* kBadSourceAddressTokens[] = { 247 "", 248 "foo", 249 "#0000", 250 "#0000000000000000000000000000000000000000", 251 }; 252 253 for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) { 254 ShouldSucceed(InchoateClientHello( 255 "CHLO", 256 "STK", kBadSourceAddressTokens[i], 257 NULL)); 258 } 259 } 260 261 TEST_F(CryptoServerTest, BadClientNonce) { 262 // Invalid nonces should be ignored. 263 static const char* kBadNonces[] = { 264 "", 265 "#0000", 266 "#0000000000000000000000000000000000000000", 267 }; 268 269 for (size_t i = 0; i < arraysize(kBadNonces); i++) { 270 ShouldSucceed(InchoateClientHello( 271 "CHLO", 272 "NONC", kBadNonces[i], 273 NULL)); 274 } 275 } 276 277 TEST_F(CryptoServerTest, DowngradeAttack) { 278 if (supported_versions_.size() == 1) { 279 // No downgrade attack is possible if the server only supports one version. 280 return; 281 } 282 // Set the client's preferred version to a supported version that 283 // is not the "current" version (supported_versions_.front()). 284 string client_version = QuicUtils::TagToString( 285 QuicVersionToQuicTag(supported_versions_.back())); 286 287 ShouldFailMentioning("Downgrade", InchoateClientHello( 288 "CHLO", 289 "VER\0", client_version.data(), 290 NULL)); 291 } 292 293 TEST_F(CryptoServerTest, ReplayProtection) { 294 // This tests that disabling replay protection works. 295 CryptoHandshakeMessage msg = CryptoTestUtils::Message( 296 "CHLO", 297 "AEAD", "AESG", 298 "KEXS", "C255", 299 "SCID", scid_hex_.c_str(), 300 "#004b5453", srct_hex_.c_str(), 301 "PUBS", pub_hex_.c_str(), 302 "NONC", nonce_hex_.c_str(), 303 "$padding", static_cast<int>(kClientHelloMinimumSize), 304 NULL); 305 ShouldSucceed(msg); 306 // The message should be rejected because the strike-register is still 307 // quiescent. 308 ASSERT_EQ(kREJ, out_.tag()); 309 310 config_.set_replay_protection(false); 311 312 ShouldSucceed(msg); 313 // The message should be accepted now. 314 ASSERT_EQ(kSHLO, out_.tag()); 315 316 ShouldSucceed(msg); 317 // The message should accepted twice when replay protection is off. 318 ASSERT_EQ(kSHLO, out_.tag()); 319 const QuicTag* versions; 320 size_t num_versions; 321 out_.GetTaglist(kVER, &versions, &num_versions); 322 ASSERT_EQ(QuicSupportedVersions().size(), num_versions); 323 for (size_t i = 0; i < num_versions; ++i) { 324 EXPECT_EQ(QuicVersionToQuicTag(QuicSupportedVersions()[i]), versions[i]); 325 } 326 } 327 328 TEST(CryptoServerConfigGenerationTest, Determinism) { 329 // Test that using a deterministic PRNG causes the server-config to be 330 // deterministic. 331 332 MockRandom rand_a, rand_b; 333 const QuicCryptoServerConfig::ConfigOptions options; 334 MockClock clock; 335 336 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a); 337 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b); 338 scoped_ptr<CryptoHandshakeMessage> scfg_a( 339 a.AddDefaultConfig(&rand_a, &clock, options)); 340 scoped_ptr<CryptoHandshakeMessage> scfg_b( 341 b.AddDefaultConfig(&rand_b, &clock, options)); 342 343 ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString()); 344 } 345 346 TEST(CryptoServerConfigGenerationTest, SCIDVaries) { 347 // This test ensures that the server config ID varies for different server 348 // configs. 349 350 MockRandom rand_a, rand_b; 351 const QuicCryptoServerConfig::ConfigOptions options; 352 MockClock clock; 353 354 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a); 355 rand_b.ChangeValue(); 356 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b); 357 scoped_ptr<CryptoHandshakeMessage> scfg_a( 358 a.AddDefaultConfig(&rand_a, &clock, options)); 359 scoped_ptr<CryptoHandshakeMessage> scfg_b( 360 b.AddDefaultConfig(&rand_b, &clock, options)); 361 362 StringPiece scid_a, scid_b; 363 EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a)); 364 EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b)); 365 366 EXPECT_NE(scid_a, scid_b); 367 } 368 369 370 TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) { 371 MockRandom rand_a; 372 const QuicCryptoServerConfig::ConfigOptions options; 373 MockClock clock; 374 375 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a); 376 scoped_ptr<CryptoHandshakeMessage> scfg( 377 a.AddDefaultConfig(&rand_a, &clock, options)); 378 379 StringPiece scid; 380 EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid)); 381 // Need to take a copy of |scid| has we're about to call |Erase|. 382 const string scid_str(scid.as_string()); 383 384 scfg->Erase(kSCID); 385 scfg->MarkDirty(); 386 const QuicData& serialized(scfg->GetSerialized()); 387 388 scoped_ptr<crypto::SecureHash> hash( 389 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); 390 hash->Update(serialized.data(), serialized.length()); 391 uint8 digest[16]; 392 hash->Finish(digest, sizeof(digest)); 393 394 ASSERT_EQ(scid.size(), sizeof(digest)); 395 EXPECT_TRUE(0 == memcmp(digest, scid_str.data(), sizeof(digest))); 396 } 397 398 class CryptoServerTestNoConfig : public CryptoServerTest { 399 public: 400 virtual void SetUp() { 401 // Deliberately don't add a config so that we can test this situation. 402 } 403 }; 404 405 TEST_F(CryptoServerTestNoConfig, DontCrash) { 406 ShouldFailMentioning("No config", InchoateClientHello( 407 "CHLO", 408 NULL)); 409 } 410 411 class AsyncStrikeServerVerificationTest : public CryptoServerTest { 412 protected: 413 AsyncStrikeServerVerificationTest() { 414 } 415 416 virtual void SetUp() { 417 const string kOrbit = "12345678"; 418 config_options_.orbit = kOrbit; 419 strike_register_client_ = new DelayedVerifyStrikeRegisterClient( 420 10000, // strike_register_max_entries 421 static_cast<uint32>(clock_.WallNow().ToUNIXSeconds()), 422 60, // strike_register_window_secs 423 reinterpret_cast<const uint8 *>(kOrbit.data()), 424 StrikeRegister::NO_STARTUP_PERIOD_NEEDED); 425 config_.SetStrikeRegisterClient(strike_register_client_); 426 CryptoServerTest::SetUp(); 427 strike_register_client_->StartDelayingVerification(); 428 } 429 430 DelayedVerifyStrikeRegisterClient* strike_register_client_; 431 }; 432 433 TEST_F(AsyncStrikeServerVerificationTest, AsyncReplayProtection) { 434 // This tests async validation with a strike register works. 435 CryptoHandshakeMessage msg = CryptoTestUtils::Message( 436 "CHLO", 437 "AEAD", "AESG", 438 "KEXS", "C255", 439 "SCID", scid_hex_.c_str(), 440 "#004b5453", srct_hex_.c_str(), 441 "PUBS", pub_hex_.c_str(), 442 "NONC", nonce_hex_.c_str(), 443 "$padding", static_cast<int>(kClientHelloMinimumSize), 444 NULL); 445 446 // Clear the message tag. 447 out_.set_tag(0); 448 449 bool called = false; 450 ShouldSucceed(msg, &called); 451 // The verification request was queued. 452 ASSERT_FALSE(called); 453 EXPECT_EQ(0u, out_.tag()); 454 EXPECT_EQ(1, strike_register_client_->PendingVerifications()); 455 456 // Continue processing the verification request. 457 strike_register_client_->RunPendingVerifications(); 458 ASSERT_TRUE(called); 459 EXPECT_EQ(0, strike_register_client_->PendingVerifications()); 460 // The message should be accepted now. 461 EXPECT_EQ(kSHLO, out_.tag()); 462 463 // Rejected if replayed. 464 ShouldSucceed(msg, &called); 465 // The verification request was queued. 466 ASSERT_FALSE(called); 467 EXPECT_EQ(1, strike_register_client_->PendingVerifications()); 468 469 strike_register_client_->RunPendingVerifications(); 470 ASSERT_TRUE(called); 471 EXPECT_EQ(0, strike_register_client_->PendingVerifications()); 472 // The message should be rejected now. 473 EXPECT_EQ(kREJ, out_.tag()); 474 } 475 476 } // namespace test 477 } // namespace net 478