| OLD | NEW |
| (Empty) |
| 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 <algorithm> | |
| 6 #include <cstdint> | |
| 7 #include <memory> | |
| 8 #include <ostream> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/strings/string_number_conversions.h" | |
| 12 #include "crypto/secure_hash.h" | |
| 13 #include "net/quic/crypto/cert_compressor.h" | |
| 14 #include "net/quic/crypto/common_cert_set.h" | |
| 15 #include "net/quic/crypto/crypto_handshake.h" | |
| 16 #include "net/quic/crypto/crypto_server_config_protobuf.h" | |
| 17 #include "net/quic/crypto/crypto_utils.h" | |
| 18 #include "net/quic/crypto/proof_source.h" | |
| 19 #include "net/quic/crypto/quic_crypto_server_config.h" | |
| 20 #include "net/quic/crypto/quic_random.h" | |
| 21 #include "net/quic/quic_flags.h" | |
| 22 #include "net/quic/quic_socket_address_coder.h" | |
| 23 #include "net/quic/quic_utils.h" | |
| 24 #include "net/quic/test_tools/crypto_test_utils.h" | |
| 25 #include "net/quic/test_tools/delayed_verify_strike_register_client.h" | |
| 26 #include "net/quic/test_tools/mock_clock.h" | |
| 27 #include "net/quic/test_tools/mock_random.h" | |
| 28 #include "net/quic/test_tools/quic_crypto_server_config_peer.h" | |
| 29 #include "net/quic/test_tools/quic_test_utils.h" | |
| 30 #include "testing/gtest/include/gtest/gtest.h" | |
| 31 | |
| 32 using base::StringPiece; | |
| 33 using std::endl; | |
| 34 using std::ostream; | |
| 35 using std::string; | |
| 36 using std::vector; | |
| 37 | |
| 38 namespace net { | |
| 39 namespace test { | |
| 40 | |
| 41 namespace { | |
| 42 | |
| 43 class DummyProofVerifierCallback : public ProofVerifierCallback { | |
| 44 public: | |
| 45 DummyProofVerifierCallback() {} | |
| 46 ~DummyProofVerifierCallback() override {} | |
| 47 | |
| 48 void Run(bool ok, | |
| 49 const std::string& error_details, | |
| 50 std::unique_ptr<ProofVerifyDetails>* details) override { | |
| 51 // Do nothing | |
| 52 } | |
| 53 }; | |
| 54 | |
| 55 const char kOldConfigId[] = "old-config-id"; | |
| 56 | |
| 57 } // namespace | |
| 58 | |
| 59 struct TestParams { | |
| 60 TestParams(bool enable_stateless_rejects, | |
| 61 bool use_stateless_rejects, | |
| 62 QuicVersionVector supported_versions) | |
| 63 : enable_stateless_rejects(enable_stateless_rejects), | |
| 64 use_stateless_rejects(use_stateless_rejects), | |
| 65 supported_versions(supported_versions) {} | |
| 66 | |
| 67 friend ostream& operator<<(ostream& os, const TestParams& p) { | |
| 68 os << " enable_stateless_rejects: " << p.enable_stateless_rejects | |
| 69 << std::endl; | |
| 70 os << " use_stateless_rejects: " << p.use_stateless_rejects << std::endl; | |
| 71 os << " versions: " << QuicVersionVectorToString(p.supported_versions) | |
| 72 << " }"; | |
| 73 return os; | |
| 74 } | |
| 75 | |
| 76 // This only enables the stateless reject feature via the feature-flag. | |
| 77 // It does not force the crypto server to emit stateless rejects. | |
| 78 bool enable_stateless_rejects; | |
| 79 // If true, this forces the server to send a stateless reject when | |
| 80 // rejecting messages. This should be a no-op if | |
| 81 // enable_stateless_rejects is false. | |
| 82 bool use_stateless_rejects; | |
| 83 // Versions supported by client and server. | |
| 84 QuicVersionVector supported_versions; | |
| 85 }; | |
| 86 | |
| 87 // Constructs various test permutations. | |
| 88 vector<TestParams> GetTestParams() { | |
| 89 vector<TestParams> params; | |
| 90 static const bool kTrueFalse[] = {true, false}; | |
| 91 for (bool enable_stateless_rejects : kTrueFalse) { | |
| 92 for (bool use_stateless_rejects : kTrueFalse) { | |
| 93 // Start with all versions, remove highest on each iteration. | |
| 94 QuicVersionVector supported_versions = QuicSupportedVersions(); | |
| 95 while (!supported_versions.empty()) { | |
| 96 params.push_back(TestParams(enable_stateless_rejects, | |
| 97 use_stateless_rejects, supported_versions)); | |
| 98 supported_versions.erase(supported_versions.begin()); | |
| 99 } | |
| 100 } | |
| 101 } | |
| 102 return params; | |
| 103 } | |
| 104 | |
| 105 class CryptoServerTest : public ::testing::TestWithParam<TestParams> { | |
| 106 public: | |
| 107 CryptoServerTest() | |
| 108 : rand_(QuicRandom::GetInstance()), | |
| 109 client_address_(Loopback4(), 1234), | |
| 110 config_(QuicCryptoServerConfig::TESTING, | |
| 111 rand_, | |
| 112 CryptoTestUtils::ProofSourceForTesting()), | |
| 113 compressed_certs_cache_( | |
| 114 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { | |
| 115 supported_versions_ = GetParam().supported_versions; | |
| 116 config_.set_enable_serving_sct(true); | |
| 117 | |
| 118 client_version_ = supported_versions_.front(); | |
| 119 client_version_string_ = | |
| 120 QuicUtils::TagToString(QuicVersionToQuicTag(client_version_)); | |
| 121 | |
| 122 FLAGS_quic_require_handshake_confirmation_pre33 = false; | |
| 123 FLAGS_enable_quic_stateless_reject_support = | |
| 124 GetParam().enable_stateless_rejects; | |
| 125 use_stateless_rejects_ = GetParam().use_stateless_rejects; | |
| 126 } | |
| 127 | |
| 128 void SetUp() override { | |
| 129 QuicCryptoServerConfig::ConfigOptions old_config_options; | |
| 130 old_config_options.id = kOldConfigId; | |
| 131 delete config_.AddDefaultConfig(rand_, &clock_, old_config_options); | |
| 132 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000)); | |
| 133 std::unique_ptr<QuicServerConfigProtobuf> primary_config( | |
| 134 config_.GenerateConfig(rand_, &clock_, config_options_)); | |
| 135 primary_config->set_primary_time(clock_.WallNow().ToUNIXSeconds()); | |
| 136 std::unique_ptr<CryptoHandshakeMessage> msg( | |
| 137 config_.AddConfig(primary_config.get(), clock_.WallNow())); | |
| 138 | |
| 139 StringPiece orbit; | |
| 140 CHECK(msg->GetStringPiece(kORBT, &orbit)); | |
| 141 CHECK_EQ(sizeof(orbit_), orbit.size()); | |
| 142 memcpy(orbit_, orbit.data(), orbit.size()); | |
| 143 | |
| 144 char public_value[32]; | |
| 145 memset(public_value, 42, sizeof(public_value)); | |
| 146 | |
| 147 nonce_hex_ = "#" + QuicUtils::HexEncode(GenerateNonce()); | |
| 148 pub_hex_ = "#" + QuicUtils::HexEncode(public_value, sizeof(public_value)); | |
| 149 | |
| 150 // clang-format off | |
| 151 CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( | |
| 152 "CHLO", | |
| 153 "PDMD", "X509", | |
| 154 "AEAD", "AESG", | |
| 155 "KEXS", "C255", | |
| 156 "PUBS", pub_hex_.c_str(), | |
| 157 "NONC", nonce_hex_.c_str(), | |
| 158 "CSCT", "", | |
| 159 "VER\0", client_version_string_.c_str(), | |
| 160 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 161 nullptr); | |
| 162 // clang-format on | |
| 163 ShouldSucceed(client_hello); | |
| 164 // The message should be rejected because the source-address token is | |
| 165 // missing. | |
| 166 CheckRejectTag(); | |
| 167 const HandshakeFailureReason kRejectReasons[] = { | |
| 168 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 169 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 170 CheckForServerDesignatedConnectionId(); | |
| 171 | |
| 172 StringPiece srct; | |
| 173 ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct)); | |
| 174 srct_hex_ = "#" + QuicUtils::HexEncode(srct); | |
| 175 | |
| 176 StringPiece scfg; | |
| 177 ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg)); | |
| 178 server_config_.reset(CryptoFramer::ParseMessage(scfg)); | |
| 179 | |
| 180 StringPiece scid; | |
| 181 ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid)); | |
| 182 scid_hex_ = "#" + QuicUtils::HexEncode(scid); | |
| 183 | |
| 184 crypto_proof_ = QuicCryptoProof(); | |
| 185 DCHECK(crypto_proof_.chain.get() == nullptr); | |
| 186 } | |
| 187 | |
| 188 // Helper used to accept the result of ValidateClientHello and pass | |
| 189 // it on to ProcessClientHello. | |
| 190 class ValidateCallback : public ValidateClientHelloResultCallback { | |
| 191 public: | |
| 192 ValidateCallback(CryptoServerTest* test, | |
| 193 bool should_succeed, | |
| 194 const char* error_substr, | |
| 195 bool* called) | |
| 196 : test_(test), | |
| 197 should_succeed_(should_succeed), | |
| 198 error_substr_(error_substr), | |
| 199 called_(called) { | |
| 200 *called_ = false; | |
| 201 } | |
| 202 | |
| 203 void RunImpl(const CryptoHandshakeMessage& client_hello, | |
| 204 const Result& result, | |
| 205 std::unique_ptr<ProofSource::Details> /* details */) override { | |
| 206 { | |
| 207 // Ensure that the strike register client lock is not held. | |
| 208 QuicCryptoServerConfigPeer peer(&test_->config_); | |
| 209 base::Lock* m = peer.GetStrikeRegisterClientLock(); | |
| 210 // In Chromium, we will dead lock if the lock is held by the current | |
| 211 // thread. Chromium doesn't have AssertNotHeld API call. | |
| 212 // m->AssertNotHeld(); | |
| 213 base::AutoLock lock(*m); | |
| 214 } | |
| 215 ASSERT_FALSE(*called_); | |
| 216 test_->ProcessValidationResult(client_hello, result, should_succeed_, | |
| 217 error_substr_); | |
| 218 *called_ = true; | |
| 219 } | |
| 220 | |
| 221 private: | |
| 222 CryptoServerTest* test_; | |
| 223 bool should_succeed_; | |
| 224 const char* error_substr_; | |
| 225 bool* called_; | |
| 226 }; | |
| 227 | |
| 228 void CheckServerHello(const CryptoHandshakeMessage& server_hello) { | |
| 229 const QuicTag* versions; | |
| 230 size_t num_versions; | |
| 231 server_hello.GetTaglist(kVER, &versions, &num_versions); | |
| 232 ASSERT_EQ(supported_versions_.size(), num_versions); | |
| 233 for (size_t i = 0; i < num_versions; ++i) { | |
| 234 EXPECT_EQ(QuicVersionToQuicTag(supported_versions_[i]), versions[i]); | |
| 235 } | |
| 236 | |
| 237 StringPiece address; | |
| 238 ASSERT_TRUE(server_hello.GetStringPiece(kCADR, &address)); | |
| 239 QuicSocketAddressCoder decoder; | |
| 240 ASSERT_TRUE(decoder.Decode(address.data(), address.size())); | |
| 241 EXPECT_EQ(client_address_.address(), decoder.ip()); | |
| 242 EXPECT_EQ(client_address_.port(), decoder.port()); | |
| 243 } | |
| 244 | |
| 245 void ShouldSucceed(const CryptoHandshakeMessage& message) { | |
| 246 bool called = false; | |
| 247 IPAddress server_ip; | |
| 248 config_.ValidateClientHello(message, client_address_.address(), server_ip, | |
| 249 supported_versions_.front(), &clock_, | |
| 250 &crypto_proof_, | |
| 251 new ValidateCallback(this, true, "", &called)); | |
| 252 EXPECT_TRUE(called); | |
| 253 } | |
| 254 | |
| 255 void ShouldFailMentioning(const char* error_substr, | |
| 256 const CryptoHandshakeMessage& message) { | |
| 257 bool called = false; | |
| 258 ShouldFailMentioning(error_substr, message, &called); | |
| 259 EXPECT_TRUE(called); | |
| 260 } | |
| 261 | |
| 262 void ShouldFailMentioning(const char* error_substr, | |
| 263 const CryptoHandshakeMessage& message, | |
| 264 bool* called) { | |
| 265 IPAddress server_ip; | |
| 266 config_.ValidateClientHello( | |
| 267 message, client_address_.address(), server_ip, | |
| 268 supported_versions_.front(), &clock_, &crypto_proof_, | |
| 269 new ValidateCallback(this, false, error_substr, called)); | |
| 270 } | |
| 271 | |
| 272 void ProcessValidationResult(const CryptoHandshakeMessage& message, | |
| 273 const ValidateCallback::Result& result, | |
| 274 bool should_succeed, | |
| 275 const char* error_substr) { | |
| 276 IPAddress server_ip; | |
| 277 DiversificationNonce diversification_nonce; | |
| 278 string error_details; | |
| 279 QuicConnectionId server_designated_connection_id = | |
| 280 rand_for_id_generation_.RandUint64(); | |
| 281 QuicErrorCode error = config_.ProcessClientHello( | |
| 282 result, /*reject_only=*/false, /*connection_id=*/1, server_ip, | |
| 283 client_address_, supported_versions_.front(), supported_versions_, | |
| 284 use_stateless_rejects_, server_designated_connection_id, &clock_, rand_, | |
| 285 &compressed_certs_cache_, ¶ms_, &crypto_proof_, &out_, | |
| 286 &diversification_nonce, &error_details); | |
| 287 | |
| 288 if (should_succeed) { | |
| 289 ASSERT_EQ(error, QUIC_NO_ERROR) << "Message failed with error " | |
| 290 << error_details << ": " | |
| 291 << message.DebugString(); | |
| 292 } else { | |
| 293 ASSERT_NE(error, QUIC_NO_ERROR) << "Message didn't fail: " | |
| 294 << message.DebugString(); | |
| 295 | |
| 296 EXPECT_TRUE(error_details.find(error_substr) != string::npos) | |
| 297 << error_substr << " not in " << error_details; | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 string GenerateNonce() { | |
| 302 string nonce; | |
| 303 CryptoUtils::GenerateNonce( | |
| 304 clock_.WallNow(), rand_, | |
| 305 StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)), | |
| 306 &nonce); | |
| 307 return nonce; | |
| 308 } | |
| 309 | |
| 310 void CheckRejectReasons( | |
| 311 const HandshakeFailureReason* expected_handshake_failures, | |
| 312 size_t expected_count) { | |
| 313 const uint32_t* reject_reasons; | |
| 314 size_t num_reject_reasons; | |
| 315 static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync"); | |
| 316 QuicErrorCode error_code = | |
| 317 out_.GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons); | |
| 318 ASSERT_EQ(QUIC_NO_ERROR, error_code); | |
| 319 | |
| 320 EXPECT_EQ(expected_count, num_reject_reasons); | |
| 321 for (size_t i = 0; i < num_reject_reasons; ++i) { | |
| 322 EXPECT_EQ(expected_handshake_failures[i], reject_reasons[i]); | |
| 323 } | |
| 324 } | |
| 325 | |
| 326 // If the server is rejecting statelessly, make sure it contains a | |
| 327 // server-designated connection id. Once the check is complete, | |
| 328 // allow the random id-generator to move to the next value. | |
| 329 void CheckForServerDesignatedConnectionId() { | |
| 330 QuicConnectionId server_designated_connection_id; | |
| 331 if (!RejectsAreStateless()) { | |
| 332 EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, | |
| 333 out_.GetUint64(kRCID, &server_designated_connection_id)); | |
| 334 } else { | |
| 335 ASSERT_EQ(QUIC_NO_ERROR, | |
| 336 out_.GetUint64(kRCID, &server_designated_connection_id)); | |
| 337 EXPECT_EQ(rand_for_id_generation_.RandUint64(), | |
| 338 server_designated_connection_id); | |
| 339 } | |
| 340 rand_for_id_generation_.ChangeValue(); | |
| 341 } | |
| 342 | |
| 343 void CheckRejectTag() { | |
| 344 if (RejectsAreStateless()) { | |
| 345 ASSERT_EQ(kSREJ, out_.tag()) << QuicUtils::TagToString(out_.tag()); | |
| 346 } else { | |
| 347 ASSERT_EQ(kREJ, out_.tag()) << QuicUtils::TagToString(out_.tag()); | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 bool RejectsAreStateless() { | |
| 352 return GetParam().enable_stateless_rejects && | |
| 353 GetParam().use_stateless_rejects; | |
| 354 } | |
| 355 | |
| 356 string XlctHexString() { | |
| 357 uint64_t xlct = CryptoTestUtils::LeafCertHashForTesting(); | |
| 358 return "#" + | |
| 359 QuicUtils::HexEncode(reinterpret_cast<char*>(&xlct), sizeof(xlct)); | |
| 360 } | |
| 361 | |
| 362 protected: | |
| 363 QuicRandom* const rand_; | |
| 364 MockRandom rand_for_id_generation_; | |
| 365 MockClock clock_; | |
| 366 IPEndPoint client_address_; | |
| 367 QuicVersionVector supported_versions_; | |
| 368 QuicVersion client_version_; | |
| 369 string client_version_string_; | |
| 370 QuicCryptoServerConfig config_; | |
| 371 QuicCompressedCertsCache compressed_certs_cache_; | |
| 372 QuicCryptoServerConfig::ConfigOptions config_options_; | |
| 373 QuicCryptoNegotiatedParameters params_; | |
| 374 QuicCryptoProof crypto_proof_; | |
| 375 CryptoHandshakeMessage out_; | |
| 376 uint8_t orbit_[kOrbitSize]; | |
| 377 bool use_stateless_rejects_; | |
| 378 | |
| 379 // These strings contain hex escaped values from the server suitable for using | |
| 380 // when constructing client hello messages. | |
| 381 string nonce_hex_, pub_hex_, srct_hex_, scid_hex_; | |
| 382 std::unique_ptr<CryptoHandshakeMessage> server_config_; | |
| 383 }; | |
| 384 | |
| 385 INSTANTIATE_TEST_CASE_P(CryptoServerTests, | |
| 386 CryptoServerTest, | |
| 387 ::testing::ValuesIn(GetTestParams())); | |
| 388 | |
| 389 TEST_P(CryptoServerTest, BadSNI) { | |
| 390 // clang-format off | |
| 391 static const char* const kBadSNIs[] = { | |
| 392 "", | |
| 393 "foo", | |
| 394 "#00", | |
| 395 "#ff00", | |
| 396 "127.0.0.1", | |
| 397 "ffee::1", | |
| 398 }; | |
| 399 // clang-format on | |
| 400 | |
| 401 for (size_t i = 0; i < arraysize(kBadSNIs); i++) { | |
| 402 // clang-format off | |
| 403 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 404 "CHLO", | |
| 405 "PDMD", "X509", | |
| 406 "SNI", kBadSNIs[i], | |
| 407 "VER\0", client_version_string_.c_str(), | |
| 408 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 409 nullptr); | |
| 410 // clang-format on | |
| 411 ShouldFailMentioning("SNI", msg); | |
| 412 const HandshakeFailureReason kRejectReasons[] = { | |
| 413 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 414 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 415 } | |
| 416 } | |
| 417 | |
| 418 TEST_P(CryptoServerTest, DefaultCert) { | |
| 419 // Check that the server replies with a default certificate when no SNI is | |
| 420 // specified. The CHLO is constructed to generate a REJ with certs, so must | |
| 421 // not contain a valid STK, and must include PDMD. | |
| 422 // clang-format off | |
| 423 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 424 "CHLO", | |
| 425 "AEAD", "AESG", | |
| 426 "KEXS", "C255", | |
| 427 "PUBS", pub_hex_.c_str(), | |
| 428 "NONC", nonce_hex_.c_str(), | |
| 429 "PDMD", "X509", | |
| 430 "VER\0", client_version_string_.c_str(), | |
| 431 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 432 nullptr); | |
| 433 // clang-format on | |
| 434 | |
| 435 ShouldSucceed(msg); | |
| 436 StringPiece cert, proof, cert_sct; | |
| 437 EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); | |
| 438 EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); | |
| 439 EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); | |
| 440 EXPECT_NE(0u, cert.size()); | |
| 441 EXPECT_NE(0u, proof.size()); | |
| 442 const HandshakeFailureReason kRejectReasons[] = { | |
| 443 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 444 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 445 EXPECT_LT(0u, cert_sct.size()); | |
| 446 } | |
| 447 | |
| 448 TEST_P(CryptoServerTest, RejectTooLarge) { | |
| 449 // Check that the server replies with no certificate when a CHLO is | |
| 450 // constructed with a PDMD but no SKT when the REJ would be too large. | |
| 451 // clang-format off | |
| 452 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 453 "CHLO", | |
| 454 "PDMD", "X509", | |
| 455 "AEAD", "AESG", | |
| 456 "KEXS", "C255", | |
| 457 "PUBS", pub_hex_.c_str(), | |
| 458 "NONC", nonce_hex_.c_str(), | |
| 459 "PDMD", "X509", | |
| 460 "VER\0", client_version_string_.c_str(), | |
| 461 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 462 nullptr); | |
| 463 // clang-format on | |
| 464 | |
| 465 // The REJ will be larger than the CHLO so no PROF or CRT will be sent. | |
| 466 config_.set_chlo_multiplier(1); | |
| 467 | |
| 468 ShouldSucceed(msg); | |
| 469 StringPiece cert, proof, cert_sct; | |
| 470 EXPECT_FALSE(out_.GetStringPiece(kCertificateTag, &cert)); | |
| 471 EXPECT_FALSE(out_.GetStringPiece(kPROF, &proof)); | |
| 472 EXPECT_FALSE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); | |
| 473 const HandshakeFailureReason kRejectReasons[] = { | |
| 474 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 475 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 476 } | |
| 477 | |
| 478 TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) { | |
| 479 // Check that the server replies with no certificate when a CHLO is | |
| 480 // constructed with a PDMD but no SKT when the REJ would be too large. | |
| 481 // clang-format off | |
| 482 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 483 "CHLO", | |
| 484 "PDMD", "X509", | |
| 485 "AEAD", "AESG", | |
| 486 "KEXS", "C255", | |
| 487 "PUBS", pub_hex_.c_str(), | |
| 488 "NONC", nonce_hex_.c_str(), | |
| 489 "#004b5453", srct_hex_.c_str(), | |
| 490 "PDMD", "X509", | |
| 491 "VER\0", client_version_string_.c_str(), | |
| 492 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 493 nullptr); | |
| 494 // clang-format on | |
| 495 | |
| 496 // The REJ will be larger than the CHLO so no PROF or CRT will be sent. | |
| 497 config_.set_chlo_multiplier(1); | |
| 498 | |
| 499 ShouldSucceed(msg); | |
| 500 StringPiece cert, proof, cert_sct; | |
| 501 EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); | |
| 502 EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); | |
| 503 EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); | |
| 504 EXPECT_NE(0u, cert.size()); | |
| 505 EXPECT_NE(0u, proof.size()); | |
| 506 const HandshakeFailureReason kRejectReasons[] = { | |
| 507 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 508 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 509 } | |
| 510 | |
| 511 TEST_P(CryptoServerTest, TooSmall) { | |
| 512 // clang-format off | |
| 513 ShouldFailMentioning("too small", CryptoTestUtils::Message( | |
| 514 "CHLO", | |
| 515 "PDMD", "X509", | |
| 516 "VER\0", client_version_string_.c_str(), | |
| 517 nullptr)); | |
| 518 // clang-format on | |
| 519 const HandshakeFailureReason kRejectReasons[] = { | |
| 520 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 521 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 522 } | |
| 523 | |
| 524 TEST_P(CryptoServerTest, BadSourceAddressToken) { | |
| 525 // Invalid source-address tokens should be ignored. | |
| 526 // clang-format off | |
| 527 static const char* const kBadSourceAddressTokens[] = { | |
| 528 "", | |
| 529 "foo", | |
| 530 "#0000", | |
| 531 "#0000000000000000000000000000000000000000", | |
| 532 }; | |
| 533 // clang-format on | |
| 534 | |
| 535 for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) { | |
| 536 // clang-format off | |
| 537 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 538 "CHLO", | |
| 539 "PDMD", "X509", | |
| 540 "STK", kBadSourceAddressTokens[i], | |
| 541 "VER\0", client_version_string_.c_str(), | |
| 542 "$padding", static_cast<int>(kClientHelloMinimumSize), nullptr); | |
| 543 // clang-format on | |
| 544 ShouldSucceed(msg); | |
| 545 const HandshakeFailureReason kRejectReasons[] = { | |
| 546 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 547 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 548 } | |
| 549 } | |
| 550 | |
| 551 TEST_P(CryptoServerTest, BadClientNonce) { | |
| 552 // clang-format off | |
| 553 static const char* const kBadNonces[] = { | |
| 554 "", | |
| 555 "#0000", | |
| 556 "#0000000000000000000000000000000000000000", | |
| 557 }; | |
| 558 // clang-format on | |
| 559 | |
| 560 for (size_t i = 0; i < arraysize(kBadNonces); i++) { | |
| 561 // Invalid nonces should be ignored, in an inchoate CHLO. | |
| 562 // clang-format off | |
| 563 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 564 "CHLO", | |
| 565 "PDMD", "X509", | |
| 566 "NONC", kBadNonces[i], | |
| 567 "VER\0", client_version_string_.c_str(), | |
| 568 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 569 nullptr); | |
| 570 // clang-format on | |
| 571 ShouldSucceed(msg); | |
| 572 const HandshakeFailureReason kRejectReasons[] = { | |
| 573 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 574 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 575 | |
| 576 // Invalid nonces should result in CLIENT_NONCE_INVALID_FAILURE. | |
| 577 // clang-format off | |
| 578 CryptoHandshakeMessage msg1 = CryptoTestUtils::Message( | |
| 579 "CHLO", | |
| 580 "PDMD", "X509", | |
| 581 "AEAD", "AESG", | |
| 582 "KEXS", "C255", | |
| 583 "SCID", scid_hex_.c_str(), | |
| 584 "#004b5453", srct_hex_.c_str(), | |
| 585 "PUBS", pub_hex_.c_str(), | |
| 586 "NONC", kBadNonces[i], | |
| 587 "NONP", kBadNonces[i], | |
| 588 "XLCT", XlctHexString().c_str(), | |
| 589 "VER\0", client_version_string_.c_str(), | |
| 590 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 591 nullptr); | |
| 592 // clang-format on | |
| 593 | |
| 594 ShouldSucceed(msg1); | |
| 595 | |
| 596 CheckRejectTag(); | |
| 597 const HandshakeFailureReason kRejectReasons1[] = { | |
| 598 CLIENT_NONCE_INVALID_FAILURE}; | |
| 599 CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1)); | |
| 600 } | |
| 601 } | |
| 602 | |
| 603 TEST_P(CryptoServerTest, NoClientNonce) { | |
| 604 // No client nonces should result in INCHOATE_HELLO_FAILURE. | |
| 605 // clang-format off | |
| 606 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 607 "CHLO", | |
| 608 "PDMD", "X509", | |
| 609 "VER\0", client_version_string_.c_str(), | |
| 610 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 611 nullptr); | |
| 612 // clang-format on | |
| 613 | |
| 614 ShouldSucceed(msg); | |
| 615 const HandshakeFailureReason kRejectReasons[] = { | |
| 616 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 617 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 618 | |
| 619 // clang-format off | |
| 620 CryptoHandshakeMessage msg1 = CryptoTestUtils::Message( | |
| 621 "CHLO", | |
| 622 "PDMD", "X509", | |
| 623 "AEAD", "AESG", | |
| 624 "KEXS", "C255", | |
| 625 "SCID", scid_hex_.c_str(), | |
| 626 "#004b5453", srct_hex_.c_str(), | |
| 627 "PUBS", pub_hex_.c_str(), | |
| 628 "XLCT", XlctHexString().c_str(), | |
| 629 "VER\0", client_version_string_.c_str(), | |
| 630 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 631 nullptr); | |
| 632 // clang-format on | |
| 633 | |
| 634 ShouldSucceed(msg1); | |
| 635 CheckRejectTag(); | |
| 636 const HandshakeFailureReason kRejectReasons1[] = { | |
| 637 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 638 CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1)); | |
| 639 } | |
| 640 | |
| 641 TEST_P(CryptoServerTest, DowngradeAttack) { | |
| 642 if (supported_versions_.size() == 1) { | |
| 643 // No downgrade attack is possible if the server only supports one version. | |
| 644 return; | |
| 645 } | |
| 646 // Set the client's preferred version to a supported version that | |
| 647 // is not the "current" version (supported_versions_.front()). | |
| 648 string bad_version = | |
| 649 QuicUtils::TagToString(QuicVersionToQuicTag(supported_versions_.back())); | |
| 650 | |
| 651 // clang-format off | |
| 652 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 653 "CHLO", | |
| 654 "PDMD", "X509", | |
| 655 "VER\0", bad_version.c_str(), | |
| 656 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 657 nullptr); | |
| 658 // clang-format on | |
| 659 ShouldFailMentioning("Downgrade", msg); | |
| 660 const HandshakeFailureReason kRejectReasons[] = { | |
| 661 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 662 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 663 } | |
| 664 | |
| 665 TEST_P(CryptoServerTest, CorruptServerConfig) { | |
| 666 // This tests corrupted server config. | |
| 667 // clang-format off | |
| 668 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 669 "CHLO", | |
| 670 "PDMD", "X509", | |
| 671 "AEAD", "AESG", | |
| 672 "KEXS", "C255", | |
| 673 "SCID", (string(1, 'X') + scid_hex_).c_str(), | |
| 674 "#004b5453", srct_hex_.c_str(), | |
| 675 "PUBS", pub_hex_.c_str(), | |
| 676 "NONC", nonce_hex_.c_str(), | |
| 677 "VER\0", client_version_string_.c_str(), | |
| 678 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 679 nullptr); | |
| 680 // clang-format on | |
| 681 ShouldSucceed(msg); | |
| 682 CheckRejectTag(); | |
| 683 const HandshakeFailureReason kRejectReasons[] = { | |
| 684 SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE}; | |
| 685 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 686 } | |
| 687 | |
| 688 TEST_P(CryptoServerTest, CorruptSourceAddressToken) { | |
| 689 // This tests corrupted source address token. | |
| 690 // clang-format off | |
| 691 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 692 "CHLO", | |
| 693 "PDMD", "X509", | |
| 694 "AEAD", "AESG", | |
| 695 "KEXS", "C255", | |
| 696 "SCID", scid_hex_.c_str(), | |
| 697 "#004b5453", (string(1, 'X') + srct_hex_).c_str(), | |
| 698 "PUBS", pub_hex_.c_str(), | |
| 699 "NONC", nonce_hex_.c_str(), | |
| 700 "XLCT", XlctHexString().c_str(), | |
| 701 "VER\0", client_version_string_.c_str(), | |
| 702 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 703 nullptr); | |
| 704 // clang-format on | |
| 705 ShouldSucceed(msg); | |
| 706 CheckRejectTag(); | |
| 707 const HandshakeFailureReason kRejectReasons[] = { | |
| 708 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE}; | |
| 709 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 710 } | |
| 711 | |
| 712 TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) { | |
| 713 // This test corrupts client nonce and source address token. | |
| 714 // clang-format off | |
| 715 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 716 "CHLO", | |
| 717 "PDMD", "X509", | |
| 718 "AEAD", "AESG", | |
| 719 "KEXS", "C255", | |
| 720 "SCID", scid_hex_.c_str(), | |
| 721 "#004b5453", (string(1, 'X') + srct_hex_).c_str(), | |
| 722 "PUBS", pub_hex_.c_str(), | |
| 723 "NONC", (string(1, 'X') + nonce_hex_).c_str(), | |
| 724 "XLCT", XlctHexString().c_str(), | |
| 725 "VER\0", client_version_string_.c_str(), | |
| 726 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 727 nullptr); | |
| 728 // clang-format on | |
| 729 ShouldSucceed(msg); | |
| 730 CheckRejectTag(); | |
| 731 const HandshakeFailureReason kRejectReasons[] = { | |
| 732 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE}; | |
| 733 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 734 } | |
| 735 | |
| 736 TEST_P(CryptoServerTest, CorruptMultipleTags) { | |
| 737 // This test corrupts client nonce, server nonce and source address token. | |
| 738 // clang-format off | |
| 739 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 740 "CHLO", | |
| 741 "PDMD", "X509", | |
| 742 "AEAD", "AESG", | |
| 743 "KEXS", "C255", | |
| 744 "SCID", scid_hex_.c_str(), | |
| 745 "#004b5453", (string(1, 'X') + srct_hex_).c_str(), | |
| 746 "PUBS", pub_hex_.c_str(), | |
| 747 "NONC", (string(1, 'X') + nonce_hex_).c_str(), | |
| 748 "NONP", (string(1, 'X') + nonce_hex_).c_str(), | |
| 749 "SNO\0", (string(1, 'X') + nonce_hex_).c_str(), | |
| 750 "XLCT", XlctHexString().c_str(), | |
| 751 "VER\0", client_version_string_.c_str(), | |
| 752 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 753 nullptr); | |
| 754 // clang-format on | |
| 755 ShouldSucceed(msg); | |
| 756 CheckRejectTag(); | |
| 757 | |
| 758 if (client_version_ <= QUIC_VERSION_32) { | |
| 759 const HandshakeFailureReason kRejectReasons[] = { | |
| 760 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE, | |
| 761 SERVER_NONCE_DECRYPTION_FAILURE}; | |
| 762 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 763 } else { | |
| 764 const HandshakeFailureReason kRejectReasons[] = { | |
| 765 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE}; | |
| 766 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 767 }; | |
| 768 } | |
| 769 | |
| 770 TEST_P(CryptoServerTest, NoServerNonce) { | |
| 771 // When no server nonce is present and no strike register is configured, | |
| 772 // the CHLO should be rejected. | |
| 773 // clang-format off | |
| 774 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 775 "CHLO", | |
| 776 "PDMD", "X509", | |
| 777 "AEAD", "AESG", | |
| 778 "KEXS", "C255", | |
| 779 "SCID", scid_hex_.c_str(), | |
| 780 "#004b5453", srct_hex_.c_str(), | |
| 781 "PUBS", pub_hex_.c_str(), | |
| 782 "NONC", nonce_hex_.c_str(), | |
| 783 "NONP", nonce_hex_.c_str(), | |
| 784 "XLCT", XlctHexString().c_str(), | |
| 785 "VER\0", client_version_string_.c_str(), | |
| 786 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 787 nullptr); | |
| 788 // clang-format on | |
| 789 | |
| 790 ShouldSucceed(msg); | |
| 791 | |
| 792 if (client_version_ <= QUIC_VERSION_32) { | |
| 793 CheckRejectTag(); | |
| 794 const HandshakeFailureReason kRejectReasons[] = { | |
| 795 SERVER_NONCE_REQUIRED_FAILURE}; | |
| 796 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 797 } else { | |
| 798 // Even without a server nonce, this ClientHello should be accepted in | |
| 799 // version 33. | |
| 800 ASSERT_EQ(kSHLO, out_.tag()); | |
| 801 CheckServerHello(out_); | |
| 802 } | |
| 803 } | |
| 804 | |
| 805 TEST_P(CryptoServerTest, ProofForSuppliedServerConfig) { | |
| 806 client_address_ = IPEndPoint(Loopback6(), 1234); | |
| 807 // clang-format off | |
| 808 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 809 "CHLO", | |
| 810 "AEAD", "AESG", | |
| 811 "KEXS", "C255", | |
| 812 "PDMD", "X509", | |
| 813 "SCID", kOldConfigId, | |
| 814 "#004b5453", srct_hex_.c_str(), | |
| 815 "PUBS", pub_hex_.c_str(), | |
| 816 "NONC", nonce_hex_.c_str(), | |
| 817 "VER\0", client_version_string_.c_str(), | |
| 818 "XLCT", XlctHexString().c_str(), | |
| 819 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 820 nullptr); | |
| 821 // clang-format on | |
| 822 ShouldSucceed(msg); | |
| 823 // The message should be rejected because the source-address token is no | |
| 824 // longer valid. | |
| 825 CheckRejectTag(); | |
| 826 const HandshakeFailureReason kRejectReasons[] = { | |
| 827 SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE}; | |
| 828 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 829 | |
| 830 StringPiece cert, proof, scfg_str; | |
| 831 EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); | |
| 832 EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); | |
| 833 EXPECT_TRUE(out_.GetStringPiece(kSCFG, &scfg_str)); | |
| 834 std::unique_ptr<CryptoHandshakeMessage> scfg( | |
| 835 CryptoFramer::ParseMessage(scfg_str)); | |
| 836 StringPiece scid; | |
| 837 EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid)); | |
| 838 EXPECT_NE(scid, kOldConfigId); | |
| 839 | |
| 840 // Get certs from compressed certs. | |
| 841 const CommonCertSets* common_cert_sets(CommonCertSets::GetInstanceQUIC()); | |
| 842 vector<string> cached_certs; | |
| 843 | |
| 844 vector<string> certs; | |
| 845 ASSERT_TRUE(CertCompressor::DecompressChain(cert, cached_certs, | |
| 846 common_cert_sets, &certs)); | |
| 847 | |
| 848 // Check that the proof in the REJ message is valid. | |
| 849 std::unique_ptr<ProofVerifier> proof_verifier( | |
| 850 CryptoTestUtils::ProofVerifierForTesting()); | |
| 851 std::unique_ptr<ProofVerifyContext> verify_context( | |
| 852 CryptoTestUtils::ProofVerifyContextForTesting()); | |
| 853 std::unique_ptr<ProofVerifyDetails> details; | |
| 854 string error_details; | |
| 855 std::unique_ptr<ProofVerifierCallback> callback( | |
| 856 new DummyProofVerifierCallback()); | |
| 857 string chlo_hash; | |
| 858 CryptoUtils::HashHandshakeMessage(msg, &chlo_hash); | |
| 859 EXPECT_EQ(QUIC_SUCCESS, | |
| 860 proof_verifier->VerifyProof( | |
| 861 "test.example.com", 443, scfg_str.as_string(), client_version_, | |
| 862 chlo_hash, certs, "", proof.as_string(), verify_context.get(), | |
| 863 &error_details, &details, std::move(callback))); | |
| 864 } | |
| 865 | |
| 866 TEST_P(CryptoServerTest, RejectInvalidXlct) { | |
| 867 // clang-format off | |
| 868 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 869 "CHLO", | |
| 870 "PDMD", "X509", | |
| 871 "AEAD", "AESG", | |
| 872 "KEXS", "C255", | |
| 873 "SCID", scid_hex_.c_str(), | |
| 874 "#004b5453", srct_hex_.c_str(), | |
| 875 "PUBS", pub_hex_.c_str(), | |
| 876 "NONC", nonce_hex_.c_str(), | |
| 877 "VER\0", client_version_string_.c_str(), | |
| 878 "XLCT", "#0102030405060708", | |
| 879 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 880 nullptr); | |
| 881 // clang-format on | |
| 882 // If replay protection isn't disabled, then | |
| 883 // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false | |
| 884 // and cause ProcessClientHello to exit early (and generate a REJ message). | |
| 885 config_.set_replay_protection(false); | |
| 886 | |
| 887 ShouldSucceed(msg); | |
| 888 // clang-format off | |
| 889 const HandshakeFailureReason kRejectReasons[] = { | |
| 890 INVALID_EXPECTED_LEAF_CERTIFICATE | |
| 891 }; | |
| 892 // clang-format on | |
| 893 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 894 } | |
| 895 | |
| 896 TEST_P(CryptoServerTest, ValidXlct) { | |
| 897 // clang-format off | |
| 898 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 899 "CHLO", | |
| 900 "PDMD", "X509", | |
| 901 "AEAD", "AESG", | |
| 902 "KEXS", "C255", | |
| 903 "SCID", scid_hex_.c_str(), | |
| 904 "#004b5453", srct_hex_.c_str(), | |
| 905 "PUBS", pub_hex_.c_str(), | |
| 906 "NONC", nonce_hex_.c_str(), | |
| 907 "NONP", "123456789012345678901234567890", | |
| 908 "VER\0", client_version_string_.c_str(), | |
| 909 "XLCT", XlctHexString().c_str(), | |
| 910 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 911 nullptr); | |
| 912 // clang-format on | |
| 913 // If replay protection isn't disabled, then | |
| 914 // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false | |
| 915 // and cause ProcessClientHello to exit early (and generate a REJ message). | |
| 916 config_.set_replay_protection(false); | |
| 917 | |
| 918 ShouldSucceed(msg); | |
| 919 EXPECT_EQ(kSHLO, out_.tag()); | |
| 920 } | |
| 921 | |
| 922 TEST_P(CryptoServerTest, NonceInSHLO) { | |
| 923 // clang-format off | |
| 924 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 925 "CHLO", | |
| 926 "PDMD", "X509", | |
| 927 "AEAD", "AESG", | |
| 928 "KEXS", "C255", | |
| 929 "SCID", scid_hex_.c_str(), | |
| 930 "#004b5453", srct_hex_.c_str(), | |
| 931 "PUBS", pub_hex_.c_str(), | |
| 932 "NONC", nonce_hex_.c_str(), | |
| 933 "VER\0", client_version_string_.c_str(), | |
| 934 "XLCT", XlctHexString().c_str(), | |
| 935 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 936 nullptr); | |
| 937 // clang-format on | |
| 938 // If replay protection isn't disabled, then | |
| 939 // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false | |
| 940 // and cause ProcessClientHello to exit early (and generate a REJ message). | |
| 941 config_.set_replay_protection(false); | |
| 942 | |
| 943 ShouldSucceed(msg); | |
| 944 EXPECT_EQ(kSHLO, out_.tag()); | |
| 945 | |
| 946 StringPiece nonce; | |
| 947 EXPECT_TRUE(out_.GetStringPiece(kServerNonceTag, &nonce)); | |
| 948 } | |
| 949 | |
| 950 TEST(CryptoServerConfigGenerationTest, Determinism) { | |
| 951 // Test that using a deterministic PRNG causes the server-config to be | |
| 952 // deterministic. | |
| 953 | |
| 954 MockRandom rand_a, rand_b; | |
| 955 const QuicCryptoServerConfig::ConfigOptions options; | |
| 956 MockClock clock; | |
| 957 | |
| 958 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, | |
| 959 CryptoTestUtils::ProofSourceForTesting()); | |
| 960 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b, | |
| 961 CryptoTestUtils::ProofSourceForTesting()); | |
| 962 std::unique_ptr<CryptoHandshakeMessage> scfg_a( | |
| 963 a.AddDefaultConfig(&rand_a, &clock, options)); | |
| 964 std::unique_ptr<CryptoHandshakeMessage> scfg_b( | |
| 965 b.AddDefaultConfig(&rand_b, &clock, options)); | |
| 966 | |
| 967 ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString()); | |
| 968 } | |
| 969 | |
| 970 TEST(CryptoServerConfigGenerationTest, SCIDVaries) { | |
| 971 // This test ensures that the server config ID varies for different server | |
| 972 // configs. | |
| 973 | |
| 974 MockRandom rand_a, rand_b; | |
| 975 const QuicCryptoServerConfig::ConfigOptions options; | |
| 976 MockClock clock; | |
| 977 | |
| 978 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, | |
| 979 CryptoTestUtils::ProofSourceForTesting()); | |
| 980 rand_b.ChangeValue(); | |
| 981 QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b, | |
| 982 CryptoTestUtils::ProofSourceForTesting()); | |
| 983 std::unique_ptr<CryptoHandshakeMessage> scfg_a( | |
| 984 a.AddDefaultConfig(&rand_a, &clock, options)); | |
| 985 std::unique_ptr<CryptoHandshakeMessage> scfg_b( | |
| 986 b.AddDefaultConfig(&rand_b, &clock, options)); | |
| 987 | |
| 988 StringPiece scid_a, scid_b; | |
| 989 EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a)); | |
| 990 EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b)); | |
| 991 | |
| 992 EXPECT_NE(scid_a, scid_b); | |
| 993 } | |
| 994 | |
| 995 TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) { | |
| 996 MockRandom rand_a; | |
| 997 const QuicCryptoServerConfig::ConfigOptions options; | |
| 998 MockClock clock; | |
| 999 | |
| 1000 QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, | |
| 1001 CryptoTestUtils::ProofSourceForTesting()); | |
| 1002 std::unique_ptr<CryptoHandshakeMessage> scfg( | |
| 1003 a.AddDefaultConfig(&rand_a, &clock, options)); | |
| 1004 | |
| 1005 StringPiece scid; | |
| 1006 EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid)); | |
| 1007 // Need to take a copy of |scid| has we're about to call |Erase|. | |
| 1008 const string scid_str(scid.as_string()); | |
| 1009 | |
| 1010 scfg->Erase(kSCID); | |
| 1011 scfg->MarkDirty(); | |
| 1012 const QuicData& serialized(scfg->GetSerialized()); | |
| 1013 | |
| 1014 std::unique_ptr<crypto::SecureHash> hash( | |
| 1015 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | |
| 1016 hash->Update(serialized.data(), serialized.length()); | |
| 1017 uint8_t digest[16]; | |
| 1018 hash->Finish(digest, sizeof(digest)); | |
| 1019 | |
| 1020 ASSERT_EQ(scid.size(), sizeof(digest)); | |
| 1021 EXPECT_EQ(0, memcmp(digest, scid_str.c_str(), sizeof(digest))); | |
| 1022 } | |
| 1023 | |
| 1024 class CryptoServerTestNoConfig : public CryptoServerTest { | |
| 1025 public: | |
| 1026 void SetUp() override { | |
| 1027 // Deliberately don't add a config so that we can test this situation. | |
| 1028 } | |
| 1029 }; | |
| 1030 | |
| 1031 TEST_P(CryptoServerTestNoConfig, DontCrash) { | |
| 1032 // clang-format off | |
| 1033 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 1034 "CHLO", | |
| 1035 "PDMD", "X509", | |
| 1036 "VER\0", client_version_string_.c_str(), | |
| 1037 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 1038 nullptr); | |
| 1039 // clang-format on | |
| 1040 ShouldFailMentioning("No config", msg); | |
| 1041 | |
| 1042 const HandshakeFailureReason kRejectReasons[] = { | |
| 1043 SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; | |
| 1044 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 1045 } | |
| 1046 | |
| 1047 class CryptoServerTestOldVersion : public CryptoServerTest { | |
| 1048 public: | |
| 1049 void SetUp() override { | |
| 1050 client_version_ = supported_versions_.back(); | |
| 1051 client_version_string_ = | |
| 1052 QuicUtils::TagToString(QuicVersionToQuicTag(client_version_)); | |
| 1053 CryptoServerTest::SetUp(); | |
| 1054 } | |
| 1055 }; | |
| 1056 | |
| 1057 TEST_P(CryptoServerTestOldVersion, ServerIgnoresXlct) { | |
| 1058 // clang-format off | |
| 1059 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 1060 "CHLO", | |
| 1061 "PDMD", "X509", | |
| 1062 "AEAD", "AESG", | |
| 1063 "KEXS", "C255", | |
| 1064 "SCID", scid_hex_.c_str(), | |
| 1065 "#004b5453", srct_hex_.c_str(), | |
| 1066 "PUBS", pub_hex_.c_str(), | |
| 1067 "NONC", nonce_hex_.c_str(), | |
| 1068 "VER\0", client_version_string_.c_str(), | |
| 1069 "XLCT", "#0100000000000000", | |
| 1070 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 1071 nullptr); | |
| 1072 // clang-format on | |
| 1073 // If replay protection isn't disabled, then | |
| 1074 // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false | |
| 1075 // and cause ProcessClientHello to exit early (and generate a REJ message). | |
| 1076 config_.set_replay_protection(false); | |
| 1077 | |
| 1078 ShouldSucceed(msg); | |
| 1079 EXPECT_EQ(kSHLO, out_.tag()); | |
| 1080 } | |
| 1081 | |
| 1082 TEST_P(CryptoServerTestOldVersion, XlctNotRequired) { | |
| 1083 // clang-format off | |
| 1084 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 1085 "CHLO", | |
| 1086 "PDMD", "X509", | |
| 1087 "AEAD", "AESG", | |
| 1088 "KEXS", "C255", | |
| 1089 "SCID", scid_hex_.c_str(), | |
| 1090 "#004b5453", srct_hex_.c_str(), | |
| 1091 "PUBS", pub_hex_.c_str(), | |
| 1092 "NONC", nonce_hex_.c_str(), | |
| 1093 "VER\0", client_version_string_.c_str(), | |
| 1094 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 1095 nullptr); | |
| 1096 // clang-format on | |
| 1097 // If replay protection isn't disabled, then | |
| 1098 // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false | |
| 1099 // and cause ProcessClientHello to exit early (and generate a REJ message). | |
| 1100 config_.set_replay_protection(false); | |
| 1101 | |
| 1102 ShouldSucceed(msg); | |
| 1103 EXPECT_EQ(kSHLO, out_.tag()); | |
| 1104 } | |
| 1105 | |
| 1106 class AsyncStrikeServerVerificationTest : public CryptoServerTest { | |
| 1107 protected: | |
| 1108 AsyncStrikeServerVerificationTest() {} | |
| 1109 | |
| 1110 void SetUp() override { | |
| 1111 const string kOrbit = "12345678"; | |
| 1112 config_options_.orbit = kOrbit; | |
| 1113 strike_register_client_ = new DelayedVerifyStrikeRegisterClient( | |
| 1114 10000, // strike_register_max_entries | |
| 1115 static_cast<uint32_t>(clock_.WallNow().ToUNIXSeconds()), | |
| 1116 60, // strike_register_window_secs | |
| 1117 reinterpret_cast<const uint8_t*>(kOrbit.c_str()), | |
| 1118 StrikeRegister::NO_STARTUP_PERIOD_NEEDED); | |
| 1119 config_.SetStrikeRegisterClient(strike_register_client_); | |
| 1120 ASSERT_NO_FATAL_FAILURE(CryptoServerTest::SetUp()); | |
| 1121 strike_register_client_->StartDelayingVerification(); | |
| 1122 } | |
| 1123 | |
| 1124 DelayedVerifyStrikeRegisterClient* strike_register_client_; | |
| 1125 }; | |
| 1126 | |
| 1127 TEST_P(AsyncStrikeServerVerificationTest, AsyncReplayProtection) { | |
| 1128 // This tests async validation with a strike register works. | |
| 1129 // clang-format off | |
| 1130 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 1131 "CHLO", | |
| 1132 "PDMD", "X509", | |
| 1133 "AEAD", "AESG", | |
| 1134 "KEXS", "C255", | |
| 1135 "SCID", scid_hex_.c_str(), | |
| 1136 "#004b5453", srct_hex_.c_str(), | |
| 1137 "PUBS", pub_hex_.c_str(), | |
| 1138 "NONC", nonce_hex_.c_str(), | |
| 1139 "VER\0", client_version_string_.c_str(), | |
| 1140 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 1141 nullptr); | |
| 1142 // clang-format on | |
| 1143 | |
| 1144 // Clear the message tag. | |
| 1145 out_.set_tag(0); | |
| 1146 | |
| 1147 bool called = false; | |
| 1148 IPAddress server_ip; | |
| 1149 config_.ValidateClientHello(msg, client_address_.address(), server_ip, | |
| 1150 client_version_, &clock_, &crypto_proof_, | |
| 1151 new ValidateCallback(this, true, "", &called)); | |
| 1152 // The verification request was queued. | |
| 1153 ASSERT_FALSE(called); | |
| 1154 EXPECT_EQ(0u, out_.tag()); | |
| 1155 EXPECT_EQ(1, strike_register_client_->PendingVerifications()); | |
| 1156 | |
| 1157 // Continue processing the verification request. | |
| 1158 strike_register_client_->RunPendingVerifications(); | |
| 1159 ASSERT_TRUE(called); | |
| 1160 EXPECT_EQ(0, strike_register_client_->PendingVerifications()); | |
| 1161 // The message should be accepted now. | |
| 1162 EXPECT_EQ(kSHLO, out_.tag()); | |
| 1163 | |
| 1164 // Rejected if replayed. | |
| 1165 config_.ValidateClientHello(msg, client_address_.address(), server_ip, | |
| 1166 client_version_, &clock_, &crypto_proof_, | |
| 1167 new ValidateCallback(this, true, "", &called)); | |
| 1168 // The verification request was queued. | |
| 1169 ASSERT_FALSE(called); | |
| 1170 EXPECT_EQ(1, strike_register_client_->PendingVerifications()); | |
| 1171 | |
| 1172 strike_register_client_->RunPendingVerifications(); | |
| 1173 ASSERT_TRUE(called); | |
| 1174 EXPECT_EQ(0, strike_register_client_->PendingVerifications()); | |
| 1175 // The message should be rejected now. | |
| 1176 CheckRejectTag(); | |
| 1177 } | |
| 1178 | |
| 1179 TEST_P(AsyncStrikeServerVerificationTest, RequireHandshakeCofirmationPre33) { | |
| 1180 FLAGS_quic_require_handshake_confirmation = false; | |
| 1181 FLAGS_quic_require_handshake_confirmation_pre33 = true; | |
| 1182 // clang-format off | |
| 1183 CryptoHandshakeMessage msg = CryptoTestUtils::Message( | |
| 1184 "CHLO", | |
| 1185 "PDMD", "X509", | |
| 1186 "AEAD", "AESG", | |
| 1187 "KEXS", "C255", | |
| 1188 "SNI", "foobar1.example.com", | |
| 1189 "SCID", scid_hex_.c_str(), | |
| 1190 "#004b5453", srct_hex_.c_str(), | |
| 1191 "PUBS", pub_hex_.c_str(), | |
| 1192 "NONC", nonce_hex_.c_str(), | |
| 1193 "VER\0", client_version_string_.c_str(), | |
| 1194 "XLCT", XlctHexString().c_str(), | |
| 1195 "$padding", static_cast<int>(kClientHelloMinimumSize), | |
| 1196 nullptr); | |
| 1197 // clang-format on | |
| 1198 | |
| 1199 ShouldSucceed(msg); | |
| 1200 | |
| 1201 if (client_version_ <= QUIC_VERSION_32) { | |
| 1202 // clang-format off | |
| 1203 const HandshakeFailureReason kRejectReasons[] = { | |
| 1204 SERVER_NONCE_REQUIRED_FAILURE | |
| 1205 }; | |
| 1206 // clang-format on | |
| 1207 CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); | |
| 1208 EXPECT_EQ(0, strike_register_client_->PendingVerifications()); | |
| 1209 } else { | |
| 1210 // version 33. | |
| 1211 ASSERT_EQ(kSHLO, out_.tag()); | |
| 1212 CheckServerHello(out_); | |
| 1213 } | |
| 1214 } | |
| 1215 | |
| 1216 } // namespace test | |
| 1217 } // namespace net | |
| OLD | NEW |