summaryrefslogtreecommitdiff
path: root/chromium/net/quic/crypto/crypto_server_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/quic/crypto/crypto_server_test.cc')
-rw-r--r--chromium/net/quic/crypto/crypto_server_test.cc255
1 files changed, 238 insertions, 17 deletions
diff --git a/chromium/net/quic/crypto/crypto_server_test.cc b/chromium/net/quic/crypto/crypto_server_test.cc
index b2cdf820c34..4eec2a86a28 100644
--- a/chromium/net/quic/crypto/crypto_server_test.cc
+++ b/chromium/net/quic/crypto/crypto_server_test.cc
@@ -3,11 +3,15 @@
// found in the LICENSE file.
#include "base/strings/string_number_conversions.h"
-#include "net/quic/crypto/crypto_server_config.h"
+#include "crypto/secure_hash.h"
#include "net/quic/crypto/crypto_utils.h"
+#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/quic_random.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/delayed_verify_strike_register_client.h"
#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/mock_random.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
@@ -24,12 +28,13 @@ class CryptoServerTest : public ::testing::Test {
addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ?
ip_ : IPAddressNumber(), 1) {
config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
+ supported_versions_ = QuicSupportedVersions();
}
virtual void SetUp() {
scoped_ptr<CryptoHandshakeMessage> msg(
config_.AddDefaultConfig(rand_, &clock_,
- QuicCryptoServerConfig::ConfigOptions()));
+ config_options_));
StringPiece orbit;
CHECK(msg->GetStringPiece(kORBT, &orbit));
@@ -69,29 +74,85 @@ class CryptoServerTest : public ::testing::Test {
scid_hex_ = "#" + base::HexEncode(scid.data(), scid.size());
}
+ // Helper used to accept the result of ValidateClientHello and pass
+ // it on to ProcessClientHello.
+ class ValidateCallback : public ValidateClientHelloResultCallback {
+ public:
+ ValidateCallback(CryptoServerTest* test,
+ bool should_succeed,
+ const char* error_substr,
+ bool* called)
+ : test_(test),
+ should_succeed_(should_succeed),
+ error_substr_(error_substr),
+ called_(called) {
+ *called_ = false;
+ }
+
+ virtual void RunImpl(const CryptoHandshakeMessage& client_hello,
+ const Result& result) OVERRIDE {
+ ASSERT_FALSE(*called_);
+ test_->ProcessValidationResult(
+ client_hello, result, should_succeed_, error_substr_);
+ *called_ = true;
+ }
+
+ private:
+ CryptoServerTest* test_;
+ bool should_succeed_;
+ const char* error_substr_;
+ bool* called_;
+ };
+
void ShouldSucceed(const CryptoHandshakeMessage& message) {
- string error_details;
- QuicErrorCode error = config_.ProcessClientHello(
- message, 1 /* GUID */, addr_, &clock_,
- rand_, &params_, &out_, &error_details);
+ bool called = false;
+ ShouldSucceed(message, &called);
+ EXPECT_TRUE(called);
+ }
- ASSERT_EQ(error, QUIC_NO_ERROR)
- << "Message failed with error " << error_details << ": "
- << message.DebugString();
+ void ShouldSucceed(const CryptoHandshakeMessage& message,
+ bool* called) {
+ config_.ValidateClientHello(
+ message, addr_, &clock_,
+ new ValidateCallback(this, true, "", called));
}
void ShouldFailMentioning(const char* error_substr,
const CryptoHandshakeMessage& message) {
- string error_details;
- QuicErrorCode error = config_.ProcessClientHello(
- message, 1 /* GUID */, addr_, &clock_,
- rand_, &params_, &out_, &error_details);
+ bool called = false;
+ ShouldFailMentioning(error_substr, message, &called);
+ EXPECT_TRUE(called);
+ }
- ASSERT_NE(error, QUIC_NO_ERROR)
- << "Message didn't fail: " << message.DebugString();
+ void ShouldFailMentioning(const char* error_substr,
+ const CryptoHandshakeMessage& message,
+ bool* called) {
+ config_.ValidateClientHello(
+ message, addr_, &clock_,
+ new ValidateCallback(this, false, error_substr, called));
+ }
- EXPECT_TRUE(error_details.find(error_substr) != string::npos)
- << error_substr << " not in " << error_details;
+ void ProcessValidationResult(const CryptoHandshakeMessage& message,
+ const ValidateCallback::Result& result,
+ bool should_succeed,
+ const char* error_substr) {
+ string error_details;
+ QuicErrorCode error = config_.ProcessClientHello(
+ result, 1 /* GUID */, addr_,
+ supported_versions_.front(), supported_versions_, &clock_, rand_,
+ &params_, &out_, &error_details);
+
+ if (should_succeed) {
+ ASSERT_EQ(error, QUIC_NO_ERROR)
+ << "Message failed with error " << error_details << ": "
+ << message.DebugString();
+ } else {
+ ASSERT_NE(error, QUIC_NO_ERROR)
+ << "Message didn't fail: " << message.DebugString();
+
+ EXPECT_TRUE(error_details.find(error_substr) != string::npos)
+ << error_substr << " not in " << error_details;
+ }
}
CryptoHandshakeMessage InchoateClientHello(const char* message_tag, ...) {
@@ -118,7 +179,9 @@ class CryptoServerTest : public ::testing::Test {
protected:
QuicRandom* const rand_;
MockClock clock_;
+ QuicVersionVector supported_versions_;
QuicCryptoServerConfig config_;
+ QuicCryptoServerConfig::ConfigOptions config_options_;
QuicCryptoNegotiatedParameters params_;
CryptoHandshakeMessage out_;
IPAddressNumber ip_;
@@ -211,6 +274,22 @@ TEST_F(CryptoServerTest, BadClientNonce) {
}
}
+TEST_F(CryptoServerTest, DowngradeAttack) {
+ if (supported_versions_.size() == 1) {
+ // No downgrade attack is possible if the server only supports one version.
+ return;
+ }
+ // Set the client's preferred version to a supported version that
+ // is not the "current" version (supported_versions_.front()).
+ string client_version = QuicUtils::TagToString(
+ QuicVersionToQuicTag(supported_versions_.back()));
+
+ ShouldFailMentioning("Downgrade", InchoateClientHello(
+ "CHLO",
+ "VER\0", client_version.data(),
+ NULL));
+}
+
TEST_F(CryptoServerTest, ReplayProtection) {
// This tests that disabling replay protection works.
CryptoHandshakeMessage msg = CryptoTestUtils::Message(
@@ -237,6 +316,83 @@ TEST_F(CryptoServerTest, ReplayProtection) {
ShouldSucceed(msg);
// The message should accepted twice when replay protection is off.
ASSERT_EQ(kSHLO, out_.tag());
+ const QuicTag* versions;
+ size_t num_versions;
+ out_.GetTaglist(kVER, &versions, &num_versions);
+ ASSERT_EQ(QuicSupportedVersions().size(), num_versions);
+ for (size_t i = 0; i < num_versions; ++i) {
+ EXPECT_EQ(QuicVersionToQuicTag(QuicSupportedVersions()[i]), versions[i]);
+ }
+}
+
+TEST(CryptoServerConfigGenerationTest, Determinism) {
+ // Test that using a deterministic PRNG causes the server-config to be
+ // deterministic.
+
+ MockRandom rand_a, rand_b;
+ const QuicCryptoServerConfig::ConfigOptions options;
+ MockClock clock;
+
+ QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
+ QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
+ scoped_ptr<CryptoHandshakeMessage> scfg_a(
+ a.AddDefaultConfig(&rand_a, &clock, options));
+ scoped_ptr<CryptoHandshakeMessage> scfg_b(
+ b.AddDefaultConfig(&rand_b, &clock, options));
+
+ ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString());
+}
+
+TEST(CryptoServerConfigGenerationTest, SCIDVaries) {
+ // This test ensures that the server config ID varies for different server
+ // configs.
+
+ MockRandom rand_a, rand_b;
+ const QuicCryptoServerConfig::ConfigOptions options;
+ MockClock clock;
+
+ QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
+ rand_b.ChangeValue();
+ QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
+ scoped_ptr<CryptoHandshakeMessage> scfg_a(
+ a.AddDefaultConfig(&rand_a, &clock, options));
+ scoped_ptr<CryptoHandshakeMessage> scfg_b(
+ b.AddDefaultConfig(&rand_b, &clock, options));
+
+ StringPiece scid_a, scid_b;
+ EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a));
+ EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b));
+
+ EXPECT_NE(scid_a, scid_b);
+}
+
+
+TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) {
+ MockRandom rand_a;
+ const QuicCryptoServerConfig::ConfigOptions options;
+ MockClock clock;
+
+ QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
+ scoped_ptr<CryptoHandshakeMessage> scfg(
+ a.AddDefaultConfig(&rand_a, &clock, options));
+
+ StringPiece scid;
+ EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
+ // Need to take a copy of |scid| has we're about to call |Erase|.
+ const string scid_str(scid.as_string());
+
+ scfg->Erase(kSCID);
+ scfg->MarkDirty();
+ const QuicData& serialized(scfg->GetSerialized());
+
+ scoped_ptr<crypto::SecureHash> hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ hash->Update(serialized.data(), serialized.length());
+ uint8 digest[16];
+ hash->Finish(digest, sizeof(digest));
+
+ ASSERT_EQ(scid.size(), sizeof(digest));
+ EXPECT_TRUE(0 == memcmp(digest, scid_str.data(), sizeof(digest)));
}
class CryptoServerTestNoConfig : public CryptoServerTest {
@@ -252,5 +408,70 @@ TEST_F(CryptoServerTestNoConfig, DontCrash) {
NULL));
}
+class AsyncStrikeServerVerificationTest : public CryptoServerTest {
+ protected:
+ AsyncStrikeServerVerificationTest() {
+ }
+
+ virtual void SetUp() {
+ const string kOrbit = "12345678";
+ config_options_.orbit = kOrbit;
+ strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
+ 10000, // strike_register_max_entries
+ static_cast<uint32>(clock_.WallNow().ToUNIXSeconds()),
+ 60, // strike_register_window_secs
+ reinterpret_cast<const uint8 *>(kOrbit.data()),
+ StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
+ config_.SetStrikeRegisterClient(strike_register_client_);
+ CryptoServerTest::SetUp();
+ strike_register_client_->StartDelayingVerification();
+ }
+
+ DelayedVerifyStrikeRegisterClient* strike_register_client_;
+};
+
+TEST_F(AsyncStrikeServerVerificationTest, AsyncReplayProtection) {
+ // This tests async validation with a strike register works.
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ NULL);
+
+ // Clear the message tag.
+ out_.set_tag(0);
+
+ bool called = false;
+ ShouldSucceed(msg, &called);
+ // The verification request was queued.
+ ASSERT_FALSE(called);
+ EXPECT_EQ(0u, out_.tag());
+ EXPECT_EQ(1, strike_register_client_->PendingVerifications());
+
+ // Continue processing the verification request.
+ strike_register_client_->RunPendingVerifications();
+ ASSERT_TRUE(called);
+ EXPECT_EQ(0, strike_register_client_->PendingVerifications());
+ // The message should be accepted now.
+ EXPECT_EQ(kSHLO, out_.tag());
+
+ // Rejected if replayed.
+ ShouldSucceed(msg, &called);
+ // The verification request was queued.
+ ASSERT_FALSE(called);
+ EXPECT_EQ(1, strike_register_client_->PendingVerifications());
+
+ strike_register_client_->RunPendingVerifications();
+ ASSERT_TRUE(called);
+ EXPECT_EQ(0, strike_register_client_->PendingVerifications());
+ // The message should be rejected now.
+ EXPECT_EQ(kREJ, out_.tag());
+}
+
} // namespace test
} // namespace net