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