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 |