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 <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
    728