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