#include "base/stl_util.h"
#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/crypto/crypto_handshake_message.h"
+#include "net/quic/crypto/crypto_secret_boxer.h"
#include "net/quic/crypto/crypto_server_config_protobuf.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/crypto/strike_register_client.h"
#include "net/quic/quic_time.h"
#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config)
: server_config_(server_config) {}
- string NewSourceAddressToken(IPEndPoint ip,
- QuicRandom* rand,
- QuicWallTime now) {
- return server_config_->NewSourceAddressToken(ip, rand, now);
+ scoped_refptr<QuicCryptoServerConfig::Config> GetConfig(string config_id) {
+ base::AutoLock locked(server_config_->configs_lock_);
+ if (config_id == "<primary>") {
+ return scoped_refptr<QuicCryptoServerConfig::Config>(
+ server_config_->primary_config_);
+ } else {
+ return server_config_->GetConfigWithScid(config_id);
+ }
+ }
+
+ bool ConfigHasDefaultSourceAddressTokenBoxer(string config_id) {
+ scoped_refptr<QuicCryptoServerConfig::Config> config = GetConfig(config_id);
+ return config->source_address_token_boxer ==
+ &(server_config_->default_source_address_token_boxer_);
}
- bool ValidateSourceAddressToken(StringPiece srct,
- IPEndPoint ip,
- QuicWallTime now) {
- return server_config_->ValidateSourceAddressToken(srct, ip, now);
+ string NewSourceAddressToken(
+ string config_id,
+ const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicWallTime now) {
+ return NewSourceAddressToken(config_id, ip, rand, now, NULL);
+ }
+
+ string NewSourceAddressToken(
+ string config_id,
+ const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) {
+ return server_config_->NewSourceAddressToken(
+ *GetConfig(config_id), ip, rand, now, cached_network_params);
+ }
+
+ HandshakeFailureReason ValidateSourceAddressToken(string config_id,
+ StringPiece srct,
+ const IPEndPoint& ip,
+ QuicWallTime now) {
+ return ValidateSourceAddressToken(config_id, srct, ip, now, NULL);
+ }
+
+ HandshakeFailureReason ValidateSourceAddressToken(
+ string config_id,
+ StringPiece srct,
+ const IPEndPoint& ip,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) {
+ return server_config_->ValidateSourceAddressToken(
+ *GetConfig(config_id), srct, ip, now, cached_network_params);
+ }
+
+ string NewServerNonce(QuicRandom* rand, QuicWallTime now) const {
+ return server_config_->NewServerNonce(rand, now);
+ }
+
+ HandshakeFailureReason ValidateServerNonce(StringPiece token,
+ QuicWallTime now) {
+ return server_config_->ValidateServerNonce(token, now);
}
base::Lock* GetStrikeRegisterClientLock() {
}
// CheckConfigs compares the state of the Configs in |server_config_| to the
- // description given as arguments. The arguments are given as NULL-terminated
- // pairs. The first of each pair is the server config ID of a Config. The
- // second is a boolean describing whether the config is the primary. For
- // example:
- // CheckConfigs(NULL); // checks that no Configs are loaded.
+ // description given as arguments. The arguments are given as
+ // nullptr-terminated pairs. The first of each pair is the server config ID of
+ // a Config. The second is a boolean describing whether the config is the
+ // primary. For example:
+ // CheckConfigs(nullptr); // checks that no Configs are loaded.
//
// // Checks that exactly three Configs are loaded with the given IDs and
// // status.
// "id1", false,
// "id2", true,
// "id3", false,
- // NULL);
+ // nullptr);
void CheckConfigs(const char* server_config_id1, ...) {
va_list ap;
va_start(ap, server_config_id1);
is_known_orbit_called_(false) {
}
- virtual bool IsKnownOrbit(StringPiece orbit) const OVERRIDE {
+ bool IsKnownOrbit(StringPiece orbit) const override {
// Ensure that the strike register client lock is not held.
QuicCryptoServerConfigPeer peer(config_);
base::Lock* m = peer.GetStrikeRegisterClientLock();
return true;
}
- virtual void VerifyNonceIsValidAndUnique(
- StringPiece nonce,
- QuicWallTime now,
- ResultCallback* cb) OVERRIDE {
+ void VerifyNonceIsValidAndUnique(StringPiece nonce,
+ QuicWallTime now,
+ ResultCallback* cb) override {
LOG(FATAL) << "Not implemented";
}
}
TEST(QuicCryptoServerConfigTest, SourceAddressTokens) {
- QuicRandom* rand = QuicRandom::GetInstance();
- QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand);
- IPAddressNumber ip;
- CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
- IPEndPoint ip4 = IPEndPoint(ip, 1);
- CHECK(ParseIPLiteralToNumber("2001:db8:0::42", &ip));
- IPEndPoint ip6 = IPEndPoint(ip, 2);
+ const string kPrimary = "<primary>";
+ const string kOverride = "Config with custom source address token key";
+
MockClock clock;
clock.AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
- QuicCryptoServerConfigPeer peer(&server);
QuicWallTime now = clock.WallNow();
const QuicWallTime original_time = now;
- const string token4 = peer.NewSourceAddressToken(ip4, rand, now);
- const string token6 = peer.NewSourceAddressToken(ip6, rand, now);
- EXPECT_TRUE(peer.ValidateSourceAddressToken(token4, ip4, now));
- EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip6, now));
- EXPECT_TRUE(peer.ValidateSourceAddressToken(token6, ip6, now));
+ QuicRandom* rand = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand);
+ QuicCryptoServerConfigPeer peer(&server);
+ scoped_ptr<CryptoHandshakeMessage>(
+ server.AddDefaultConfig(rand, &clock,
+ QuicCryptoServerConfig::ConfigOptions()));
+
+ // Add a config that overrides the default boxer.
+ QuicCryptoServerConfig::ConfigOptions options;
+ options.id = kOverride;
+ scoped_ptr<QuicServerConfigProtobuf> protobuf(
+ QuicCryptoServerConfig::GenerateConfig(rand, &clock, options));
+ protobuf->set_source_address_token_secret_override("a secret key");
+ // Lower priority than the default config.
+ protobuf->set_priority(1);
+ scoped_ptr<CryptoHandshakeMessage>(
+ server.AddConfig(protobuf.get(), now));
+
+ EXPECT_TRUE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kPrimary));
+ EXPECT_FALSE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kOverride));
+
+ IPEndPoint ip4 = IPEndPoint(Loopback4(), 1);
+ IPEndPoint ip4d = IPEndPoint(ConvertIPv4NumberToIPv6Number(ip4.address()), 1);
+ IPEndPoint ip6 = IPEndPoint(Loopback6(), 2);
+
+ // Primary config generates configs that validate successfully.
+ const string token4 = peer.NewSourceAddressToken(kPrimary, ip4, rand, now);
+ const string token4d = peer.NewSourceAddressToken(kPrimary, ip4d, rand, now);
+ const string token6 = peer.NewSourceAddressToken(kPrimary, ip6, rand, now);
+ EXPECT_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
+ kPrimary, token4, ip4, now));
+ DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
+ kPrimary, token4, ip4d, now));
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer.ValidateSourceAddressToken(kPrimary, token4, ip6, now));
+ DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
+ kPrimary, token4d, ip4, now));
+ DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
+ kPrimary, token4d, ip4d, now));
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer.ValidateSourceAddressToken(kPrimary, token4d, ip6, now));
+ DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
+ kPrimary, token6, ip6, now));
+
+ // Override config generates configs that validate successfully.
+ const string override_token4 = peer.NewSourceAddressToken(
+ kOverride, ip4, rand, now);
+ const string override_token6 = peer.NewSourceAddressToken(
+ kOverride, ip6, rand, now);
+ DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
+ kOverride, override_token4, ip4, now));
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer.ValidateSourceAddressToken(kOverride, override_token4, ip6,
+ now));
+ DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
+ kOverride, override_token6, ip6, now));
+
+ // Tokens generated by the primary config do not validate
+ // successfully against the override config, and vice versa.
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer.ValidateSourceAddressToken(kOverride, token4, ip4, now));
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer.ValidateSourceAddressToken(kOverride, token6, ip6, now));
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer.ValidateSourceAddressToken(kPrimary, override_token4, ip4,
+ now));
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer.ValidateSourceAddressToken(kPrimary, override_token6, ip6,
+ now));
+
+ // Validation fails after tokens expire.
now = original_time.Add(QuicTime::Delta::FromSeconds(86400 * 7));
- EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip4, now));
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
+ peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now));
now = original_time.Subtract(QuicTime::Delta::FromSeconds(3600 * 2));
- EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip4, now));
+ DCHECK_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
+ peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now));
+
+ // Make sure that if the source address token contains CachedNetworkParameters
+ // that this gets written to ValidateSourceAddressToken output argument.
+ CachedNetworkParameters cached_network_params_input;
+ cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234);
+ const string token4_with_cached_network_params = peer.NewSourceAddressToken(
+ kPrimary, ip4, rand, now, &cached_network_params_input);
+
+ CachedNetworkParameters cached_network_params_output;
+ EXPECT_NE(cached_network_params_output, cached_network_params_input);
+ peer.ValidateSourceAddressToken(kPrimary, token4_with_cached_network_params,
+ ip4, now, &cached_network_params_output);
+ // TODO(rtenneti): For server, enable the following check after serialization
+ // of optional CachedNetworkParameters is implemented.
+ // EXPECT_EQ(cached_network_params_output, cached_network_params_input);
+}
+
+TEST(QuicCryptoServerConfigTest, ValidateServerNonce) {
+ QuicRandom* rand = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand);
+ QuicCryptoServerConfigPeer peer(&server);
+
+ StringPiece message("hello world");
+ const size_t key_size = CryptoSecretBoxer::GetKeySize();
+ scoped_ptr<uint8[]> key(new uint8[key_size]);
+ memset(key.get(), 0x11, key_size);
+
+ CryptoSecretBoxer boxer;
+ boxer.SetKey(StringPiece(reinterpret_cast<char*>(key.get()), key_size));
+ const string box = boxer.Box(rand, message);
+ MockClock clock;
+ QuicWallTime now = clock.WallNow();
+ const QuicWallTime original_time = now;
+ EXPECT_EQ(SERVER_NONCE_DECRYPTION_FAILURE,
+ peer.ValidateServerNonce(box, now));
+
+ string server_nonce = peer.NewServerNonce(rand, now);
+ EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now));
+ EXPECT_EQ(SERVER_NONCE_NOT_UNIQUE_FAILURE,
+ peer.ValidateServerNonce(server_nonce, now));
+
+ now = original_time.Add(QuicTime::Delta::FromSeconds(1000 * 7));
+ server_nonce = peer.NewServerNonce(rand, now);
+ EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now));
}
class CryptoServerConfigsTest : public ::testing::Test {
config_(QuicCryptoServerConfig::TESTING, rand_),
test_peer_(&config_) {}
- virtual void SetUp() {
+ void SetUp() override {
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000));
}
// SetConfigs constructs suitable config protobufs and calls SetConfigs on
- // |config_|. The arguments are given as NULL-terminated pairs. The first of
- // each pair is the server config ID of a Config. The second is the
- // |primary_time| of that Config, given in epoch seconds. (Although note
- // that, in these tests, time is set to 1000 seconds since the epoch.) For
- // example:
- // SetConfigs(NULL); // calls |config_.SetConfigs| with no protobufs.
+ // |config_|. The arguments are given as nullptr-terminated pairs. The first
+ // of each pair is the server config ID of a Config. The second is the
+ // |primary_time| of that Config, given in epoch seconds. (Although note that,
+ // in these tests, time is set to 1000 seconds since the epoch.) For example:
+ // SetConfigs(nullptr); // calls |config_.SetConfigs| with no protobufs.
//
// // Calls |config_.SetConfigs| with two protobufs: one for a Config with
// // a |primary_time| of 900 and priority 1, and another with
// CheckConfigs(
// "id1", 900, 1,
// "id2", 1000, 2,
- // NULL);
+ // nullptr);
//
// If the server config id starts with "INVALID" then the generated protobuf
// will be invalid.
};
TEST_F(CryptoServerConfigsTest, NoConfigs) {
- test_peer_.CheckConfigs(NULL);
+ test_peer_.CheckConfigs(nullptr);
}
TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) {
// Make sure that "b" is primary even though "a" comes first.
SetConfigs("a", 1100, 1,
"b", 900, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", false,
"b", true,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, MakePrimarySecond) {
// Make sure that a remains primary after b is added.
SetConfigs("a", 900, 1,
"b", 1100, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", true,
"b", false,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, Delete) {
SetConfigs("a", 800, 1,
"b", 900, 1,
"c", 1100, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", false,
"b", true,
"c", false,
- NULL);
+ nullptr);
SetConfigs("b", 900, 1,
"c", 1100, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"b", true,
"c", false,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, DeletePrimary) {
SetConfigs("a", 800, 1,
"b", 900, 1,
"c", 1100, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", false,
"b", true,
"c", false,
- NULL);
+ nullptr);
SetConfigs("a", 800, 1,
"c", 1100, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", true,
"c", false,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, FailIfDeletingAllConfigs) {
// Ensure that configs get deleted when removed.
SetConfigs("a", 800, 1,
"b", 900, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", false,
"b", true,
- NULL);
- SetConfigs(NULL);
+ nullptr);
+ SetConfigs(nullptr);
// Config change is rejected, still using old configs.
test_peer_.CheckConfigs(
"a", false,
"b", true,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, ChangePrimaryTime) {
SetConfigs("a", 400, 1,
"b", 800, 1,
"c", 1200, 1,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(500);
test_peer_.CheckConfigs(
"a", true,
"b", false,
"c", false,
- NULL);
+ nullptr);
SetConfigs("a", 1200, 1,
"b", 800, 1,
"c", 400, 1,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(500);
test_peer_.CheckConfigs(
"a", false,
"b", false,
"c", true,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, AllConfigsInThePast) {
SetConfigs("a", 400, 1,
"b", 800, 1,
"c", 1200, 1,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(1500);
test_peer_.CheckConfigs(
"a", false,
"b", false,
"c", true,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, AllConfigsInTheFuture) {
SetConfigs("a", 400, 1,
"b", 800, 1,
"c", 1200, 1,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(100);
test_peer_.CheckConfigs(
"a", true,
"b", false,
"c", false,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, SortByPriority) {
SetConfigs("a", 900, 1,
"b", 900, 2,
"c", 900, 3,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", true,
"b", false,
"c", false,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(800);
test_peer_.CheckConfigs(
"a", true,
"b", false,
"c", false,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(1000);
test_peer_.CheckConfigs(
"a", true,
"b", false,
"c", false,
- NULL);
+ nullptr);
// Change priorities and expect sort order to change.
SetConfigs("a", 900, 2,
"b", 900, 1,
"c", 900, 0,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", false,
"b", false,
"c", true,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(800);
test_peer_.CheckConfigs(
"a", false,
"b", false,
"c", true,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(1000);
test_peer_.CheckConfigs(
"a", false,
"b", false,
"c", true,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, AdvancePrimary) {
// Check that a new primary config is enabled at the right time.
SetConfigs("a", 900, 1,
"b", 1100, 1,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(1000);
test_peer_.CheckConfigs(
"a", true,
"b", false,
- NULL);
+ nullptr);
test_peer_.SelectNewPrimaryConfig(1101);
test_peer_.CheckConfigs(
"a", false,
"b", true,
- NULL);
+ nullptr);
}
TEST_F(CryptoServerConfigsTest, InvalidConfigs) {
SetConfigs("a", 800, 1,
"b", 900, 1,
"c", 1100, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", false,
"b", true,
"c", false,
- NULL);
+ nullptr);
SetConfigs("a", 800, 1,
"c", 1100, 1,
"INVALID1", 1000, 1,
- NULL);
+ nullptr);
test_peer_.CheckConfigs(
"a", false,
"b", true,
"c", false,
- NULL);
+ nullptr);
}
} // namespace test