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