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