| OLD | NEW |
| (Empty) |
| 1 // Copyright 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 "net/quic/crypto/quic_crypto_server_config.h" | |
| 6 | |
| 7 #include <stdarg.h> | |
| 8 | |
| 9 #include <memory> | |
| 10 | |
| 11 #include "base/stl_util.h" | |
| 12 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" | |
| 13 #include "net/quic/crypto/cert_compressor.h" | |
| 14 #include "net/quic/crypto/chacha20_poly1305_encrypter.h" | |
| 15 #include "net/quic/crypto/crypto_handshake_message.h" | |
| 16 #include "net/quic/crypto/crypto_secret_boxer.h" | |
| 17 #include "net/quic/crypto/crypto_server_config_protobuf.h" | |
| 18 #include "net/quic/crypto/quic_random.h" | |
| 19 #include "net/quic/crypto/strike_register_client.h" | |
| 20 #include "net/quic/quic_flags.h" | |
| 21 #include "net/quic/quic_time.h" | |
| 22 #include "net/quic/test_tools/crypto_test_utils.h" | |
| 23 #include "net/quic/test_tools/mock_clock.h" | |
| 24 #include "net/quic/test_tools/quic_crypto_server_config_peer.h" | |
| 25 #include "net/quic/test_tools/quic_test_utils.h" | |
| 26 #include "testing/gmock/include/gmock/gmock.h" | |
| 27 #include "testing/gtest/include/gtest/gtest.h" | |
| 28 | |
| 29 using base::StringPiece; | |
| 30 using std::map; | |
| 31 using std::pair; | |
| 32 using std::string; | |
| 33 using std::vector; | |
| 34 | |
| 35 namespace net { | |
| 36 namespace test { | |
| 37 | |
| 38 class TestStrikeRegisterClient : public StrikeRegisterClient { | |
| 39 public: | |
| 40 explicit TestStrikeRegisterClient(QuicCryptoServerConfig* config) | |
| 41 : config_(config), is_known_orbit_called_(false) {} | |
| 42 | |
| 43 bool IsKnownOrbit(StringPiece orbit) const override { | |
| 44 // Ensure that the strike register client lock is not held. | |
| 45 QuicCryptoServerConfigPeer peer(config_); | |
| 46 base::Lock* m = peer.GetStrikeRegisterClientLock(); | |
| 47 // In Chromium, we will dead lock if the lock is held by the current thread. | |
| 48 // Chromium doesn't have AssertNotHeld API call. | |
| 49 // m->AssertNotHeld(); | |
| 50 base::AutoLock lock(*m); | |
| 51 | |
| 52 is_known_orbit_called_ = true; | |
| 53 return true; | |
| 54 } | |
| 55 | |
| 56 void VerifyNonceIsValidAndUnique(StringPiece nonce, | |
| 57 QuicWallTime now, | |
| 58 ResultCallback* cb) override { | |
| 59 LOG(FATAL) << "Not implemented"; | |
| 60 } | |
| 61 | |
| 62 bool is_known_orbit_called() { return is_known_orbit_called_; } | |
| 63 | |
| 64 private: | |
| 65 QuicCryptoServerConfig* config_; | |
| 66 mutable bool is_known_orbit_called_; | |
| 67 }; | |
| 68 | |
| 69 TEST(QuicCryptoServerConfigTest, ServerConfig) { | |
| 70 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 71 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, | |
| 72 CryptoTestUtils::ProofSourceForTesting()); | |
| 73 MockClock clock; | |
| 74 | |
| 75 std::unique_ptr<CryptoHandshakeMessage> message(server.AddDefaultConfig( | |
| 76 rand, &clock, QuicCryptoServerConfig::ConfigOptions())); | |
| 77 | |
| 78 // The default configuration should have AES-GCM and at least one ChaCha20 | |
| 79 // cipher. | |
| 80 const QuicTag* aead_tags; | |
| 81 size_t aead_len; | |
| 82 ASSERT_EQ(QUIC_NO_ERROR, message->GetTaglist(kAEAD, &aead_tags, &aead_len)); | |
| 83 vector<QuicTag> aead(aead_tags, aead_tags + aead_len); | |
| 84 EXPECT_THAT(aead, ::testing::Contains(kAESG)); | |
| 85 EXPECT_LE(1u, aead.size()); | |
| 86 } | |
| 87 | |
| 88 TEST(QuicCryptoServerConfigTest, GetOrbitIsCalledWithoutTheStrikeRegisterLock) { | |
| 89 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 90 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, | |
| 91 CryptoTestUtils::ProofSourceForTesting()); | |
| 92 MockClock clock; | |
| 93 | |
| 94 TestStrikeRegisterClient* strike_register = | |
| 95 new TestStrikeRegisterClient(&server); | |
| 96 server.SetStrikeRegisterClient(strike_register); | |
| 97 | |
| 98 QuicCryptoServerConfig::ConfigOptions options; | |
| 99 std::unique_ptr<CryptoHandshakeMessage> message( | |
| 100 server.AddDefaultConfig(rand, &clock, options)); | |
| 101 EXPECT_TRUE(strike_register->is_known_orbit_called()); | |
| 102 } | |
| 103 | |
| 104 TEST(QuicCryptoServerConfigTest, CompressCerts) { | |
| 105 QuicCompressedCertsCache compressed_certs_cache( | |
| 106 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); | |
| 107 | |
| 108 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 109 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, | |
| 110 CryptoTestUtils::ProofSourceForTesting()); | |
| 111 QuicCryptoServerConfigPeer peer(&server); | |
| 112 | |
| 113 vector<string> certs = {"testcert"}; | |
| 114 scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs)); | |
| 115 | |
| 116 string compressed = QuicCryptoServerConfigPeer::CompressChain( | |
| 117 &compressed_certs_cache, chain, "", "", nullptr); | |
| 118 | |
| 119 EXPECT_EQ(compressed_certs_cache.Size(), 1u); | |
| 120 } | |
| 121 | |
| 122 TEST(QuicCryptoServerConfigTest, CompressSameCertsTwice) { | |
| 123 QuicCompressedCertsCache compressed_certs_cache( | |
| 124 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); | |
| 125 | |
| 126 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 127 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, | |
| 128 CryptoTestUtils::ProofSourceForTesting()); | |
| 129 QuicCryptoServerConfigPeer peer(&server); | |
| 130 | |
| 131 // Compress the certs for the first time. | |
| 132 vector<string> certs = {"testcert"}; | |
| 133 scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs)); | |
| 134 string common_certs = ""; | |
| 135 string cached_certs = ""; | |
| 136 | |
| 137 string compressed = QuicCryptoServerConfigPeer::CompressChain( | |
| 138 &compressed_certs_cache, chain, common_certs, cached_certs, nullptr); | |
| 139 EXPECT_EQ(compressed_certs_cache.Size(), 1u); | |
| 140 | |
| 141 // Compress the same certs, should use cache if available. | |
| 142 string compressed2 = QuicCryptoServerConfigPeer::CompressChain( | |
| 143 &compressed_certs_cache, chain, common_certs, cached_certs, nullptr); | |
| 144 EXPECT_EQ(compressed, compressed2); | |
| 145 EXPECT_EQ(compressed_certs_cache.Size(), 1u); | |
| 146 } | |
| 147 | |
| 148 TEST(QuicCryptoServerConfigTest, CompressDifferentCerts) { | |
| 149 // This test compresses a set of similar but not identical certs. Cache if | |
| 150 // used should return cache miss and add all the compressed certs. | |
| 151 QuicCompressedCertsCache compressed_certs_cache( | |
| 152 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); | |
| 153 | |
| 154 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 155 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, | |
| 156 CryptoTestUtils::ProofSourceForTesting()); | |
| 157 QuicCryptoServerConfigPeer peer(&server); | |
| 158 | |
| 159 vector<string> certs = {"testcert"}; | |
| 160 scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs)); | |
| 161 string common_certs = ""; | |
| 162 string cached_certs = ""; | |
| 163 | |
| 164 string compressed = QuicCryptoServerConfigPeer::CompressChain( | |
| 165 &compressed_certs_cache, chain, common_certs, cached_certs, nullptr); | |
| 166 EXPECT_EQ(compressed_certs_cache.Size(), 1u); | |
| 167 | |
| 168 // Compress a similar certs which only differs in the chain. | |
| 169 scoped_refptr<ProofSource::Chain> chain2(new ProofSource::Chain(certs)); | |
| 170 | |
| 171 string compressed2 = QuicCryptoServerConfigPeer::CompressChain( | |
| 172 &compressed_certs_cache, chain2, common_certs, cached_certs, nullptr); | |
| 173 EXPECT_EQ(compressed_certs_cache.Size(), 2u); | |
| 174 | |
| 175 // Compress a similar certs which only differs in common certs field. | |
| 176 static const uint64_t set_hash = 42; | |
| 177 std::unique_ptr<CommonCertSets> common_sets( | |
| 178 CryptoTestUtils::MockCommonCertSets(certs[0], set_hash, 1)); | |
| 179 StringPiece different_common_certs(reinterpret_cast<const char*>(&set_hash), | |
| 180 sizeof(set_hash)); | |
| 181 string compressed3 = QuicCryptoServerConfigPeer::CompressChain( | |
| 182 &compressed_certs_cache, chain, different_common_certs.as_string(), | |
| 183 cached_certs, common_sets.get()); | |
| 184 EXPECT_EQ(compressed_certs_cache.Size(), 3u); | |
| 185 } | |
| 186 | |
| 187 class SourceAddressTokenTest : public ::testing::Test { | |
| 188 public: | |
| 189 SourceAddressTokenTest() | |
| 190 : ip4_(Loopback4()), | |
| 191 ip4_dual_(ConvertIPv4ToIPv4MappedIPv6(ip4_)), | |
| 192 ip6_(Loopback6()), | |
| 193 original_time_(QuicWallTime::Zero()), | |
| 194 rand_(QuicRandom::GetInstance()), | |
| 195 server_(QuicCryptoServerConfig::TESTING, | |
| 196 rand_, | |
| 197 CryptoTestUtils::ProofSourceForTesting()), | |
| 198 peer_(&server_) { | |
| 199 // Advance the clock to some non-zero time. | |
| 200 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); | |
| 201 original_time_ = clock_.WallNow(); | |
| 202 | |
| 203 primary_config_.reset(server_.AddDefaultConfig( | |
| 204 rand_, &clock_, QuicCryptoServerConfig::ConfigOptions())); | |
| 205 | |
| 206 // Add a config that overrides the default boxer. | |
| 207 QuicCryptoServerConfig::ConfigOptions options; | |
| 208 options.id = kOverride; | |
| 209 override_config_protobuf_.reset( | |
| 210 QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options)); | |
| 211 override_config_protobuf_->set_source_address_token_secret_override( | |
| 212 "a secret key"); | |
| 213 // Lower priority than the default config. | |
| 214 override_config_protobuf_->set_priority(1); | |
| 215 override_config_.reset( | |
| 216 server_.AddConfig(override_config_protobuf_.get(), original_time_)); | |
| 217 } | |
| 218 | |
| 219 string NewSourceAddressToken(string config_id, const IPAddress& ip) { | |
| 220 return NewSourceAddressToken(config_id, ip, nullptr); | |
| 221 } | |
| 222 | |
| 223 string NewSourceAddressToken(string config_id, | |
| 224 const IPAddress& ip, | |
| 225 const SourceAddressTokens& previous_tokens) { | |
| 226 return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_, | |
| 227 clock_.WallNow(), nullptr); | |
| 228 } | |
| 229 | |
| 230 string NewSourceAddressToken(string config_id, | |
| 231 const IPAddress& ip, | |
| 232 CachedNetworkParameters* cached_network_params) { | |
| 233 SourceAddressTokens previous_tokens; | |
| 234 return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_, | |
| 235 clock_.WallNow(), cached_network_params); | |
| 236 } | |
| 237 | |
| 238 HandshakeFailureReason ValidateSourceAddressTokens(string config_id, | |
| 239 StringPiece srct, | |
| 240 const IPAddress& ip) { | |
| 241 return ValidateSourceAddressTokens(config_id, srct, ip, nullptr); | |
| 242 } | |
| 243 | |
| 244 HandshakeFailureReason ValidateSourceAddressTokens( | |
| 245 string config_id, | |
| 246 StringPiece srct, | |
| 247 const IPAddress& ip, | |
| 248 CachedNetworkParameters* cached_network_params) { | |
| 249 return peer_.ValidateSourceAddressTokens( | |
| 250 config_id, srct, ip, clock_.WallNow(), cached_network_params); | |
| 251 } | |
| 252 | |
| 253 const string kPrimary = "<primary>"; | |
| 254 const string kOverride = "Config with custom source address token key"; | |
| 255 | |
| 256 IPAddress ip4_; | |
| 257 IPAddress ip4_dual_; | |
| 258 IPAddress ip6_; | |
| 259 | |
| 260 MockClock clock_; | |
| 261 QuicWallTime original_time_; | |
| 262 QuicRandom* rand_ = QuicRandom::GetInstance(); | |
| 263 QuicCryptoServerConfig server_; | |
| 264 QuicCryptoServerConfigPeer peer_; | |
| 265 // Stores the primary config. | |
| 266 std::unique_ptr<CryptoHandshakeMessage> primary_config_; | |
| 267 std::unique_ptr<QuicServerConfigProtobuf> override_config_protobuf_; | |
| 268 std::unique_ptr<CryptoHandshakeMessage> override_config_; | |
| 269 }; | |
| 270 | |
| 271 // Test basic behavior of source address tokens including being specific | |
| 272 // to a single IP address and server config. | |
| 273 TEST_F(SourceAddressTokenTest, NewSourceAddressToken) { | |
| 274 // Primary config generates configs that validate successfully. | |
| 275 const string token4 = NewSourceAddressToken(kPrimary, ip4_); | |
| 276 const string token4d = NewSourceAddressToken(kPrimary, ip4_dual_); | |
| 277 const string token6 = NewSourceAddressToken(kPrimary, ip6_); | |
| 278 EXPECT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4, ip4_)); | |
| 279 ASSERT_EQ(HANDSHAKE_OK, | |
| 280 ValidateSourceAddressTokens(kPrimary, token4, ip4_dual_)); | |
| 281 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 282 ValidateSourceAddressTokens(kPrimary, token4, ip6_)); | |
| 283 ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4d, ip4_)); | |
| 284 ASSERT_EQ(HANDSHAKE_OK, | |
| 285 ValidateSourceAddressTokens(kPrimary, token4d, ip4_dual_)); | |
| 286 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 287 ValidateSourceAddressTokens(kPrimary, token4d, ip6_)); | |
| 288 ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token6, ip6_)); | |
| 289 | |
| 290 // Override config generates configs that validate successfully. | |
| 291 const string override_token4 = NewSourceAddressToken(kOverride, ip4_); | |
| 292 const string override_token6 = NewSourceAddressToken(kOverride, ip6_); | |
| 293 ASSERT_EQ(HANDSHAKE_OK, | |
| 294 ValidateSourceAddressTokens(kOverride, override_token4, ip4_)); | |
| 295 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 296 ValidateSourceAddressTokens(kOverride, override_token4, ip6_)); | |
| 297 ASSERT_EQ(HANDSHAKE_OK, | |
| 298 ValidateSourceAddressTokens(kOverride, override_token6, ip6_)); | |
| 299 | |
| 300 // Tokens generated by the primary config do not validate | |
| 301 // successfully against the override config, and vice versa. | |
| 302 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 303 ValidateSourceAddressTokens(kOverride, token4, ip4_)); | |
| 304 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 305 ValidateSourceAddressTokens(kOverride, token6, ip6_)); | |
| 306 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 307 ValidateSourceAddressTokens(kPrimary, override_token4, ip4_)); | |
| 308 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 309 ValidateSourceAddressTokens(kPrimary, override_token6, ip6_)); | |
| 310 } | |
| 311 | |
| 312 TEST_F(SourceAddressTokenTest, NewSourceAddressTokenExpiration) { | |
| 313 const string token = NewSourceAddressToken(kPrimary, ip4_); | |
| 314 | |
| 315 // Validation fails if the token is from the future. | |
| 316 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(-3600 * 2)); | |
| 317 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE, | |
| 318 ValidateSourceAddressTokens(kPrimary, token, ip4_)); | |
| 319 | |
| 320 // Validation fails after tokens expire. | |
| 321 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(86400 * 7)); | |
| 322 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE, | |
| 323 ValidateSourceAddressTokens(kPrimary, token, ip4_)); | |
| 324 } | |
| 325 | |
| 326 TEST_F(SourceAddressTokenTest, NewSourceAddressTokenWithNetworkParams) { | |
| 327 // Make sure that if the source address token contains CachedNetworkParameters | |
| 328 // that this gets written to ValidateSourceAddressToken output argument. | |
| 329 CachedNetworkParameters cached_network_params_input; | |
| 330 cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234); | |
| 331 const string token4_with_cached_network_params = | |
| 332 NewSourceAddressToken(kPrimary, ip4_, &cached_network_params_input); | |
| 333 | |
| 334 CachedNetworkParameters cached_network_params_output; | |
| 335 EXPECT_NE(cached_network_params_output.SerializeAsString(), | |
| 336 cached_network_params_input.SerializeAsString()); | |
| 337 ValidateSourceAddressTokens(kPrimary, token4_with_cached_network_params, ip4_, | |
| 338 &cached_network_params_output); | |
| 339 EXPECT_EQ(cached_network_params_output.SerializeAsString(), | |
| 340 cached_network_params_input.SerializeAsString()); | |
| 341 } | |
| 342 | |
| 343 // Test the ability for a source address token to be valid for multiple | |
| 344 // addresses. | |
| 345 TEST_F(SourceAddressTokenTest, SourceAddressTokenMultipleAddresses) { | |
| 346 QuicWallTime now = clock_.WallNow(); | |
| 347 | |
| 348 // Now create a token which is usable for both addresses. | |
| 349 SourceAddressToken previous_token; | |
| 350 IPAddress ip_address = ip6_; | |
| 351 if (ip6_.IsIPv4()) { | |
| 352 ip_address = ConvertIPv4ToIPv4MappedIPv6(ip_address); | |
| 353 } | |
| 354 previous_token.set_ip(IPAddressToPackedString(ip_address)); | |
| 355 previous_token.set_timestamp(now.ToUNIXSeconds()); | |
| 356 SourceAddressTokens previous_tokens; | |
| 357 (*previous_tokens.add_tokens()) = previous_token; | |
| 358 const string token4or6 = | |
| 359 NewSourceAddressToken(kPrimary, ip4_, previous_tokens); | |
| 360 | |
| 361 EXPECT_EQ(HANDSHAKE_OK, | |
| 362 ValidateSourceAddressTokens(kPrimary, token4or6, ip4_)); | |
| 363 ASSERT_EQ(HANDSHAKE_OK, | |
| 364 ValidateSourceAddressTokens(kPrimary, token4or6, ip6_)); | |
| 365 } | |
| 366 | |
| 367 TEST(QuicCryptoServerConfigTest, ValidateServerNonce) { | |
| 368 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 369 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, | |
| 370 CryptoTestUtils::ProofSourceForTesting()); | |
| 371 QuicCryptoServerConfigPeer peer(&server); | |
| 372 | |
| 373 StringPiece message("hello world"); | |
| 374 const size_t key_size = CryptoSecretBoxer::GetKeySize(); | |
| 375 std::unique_ptr<uint8_t[]> key(new uint8_t[key_size]); | |
| 376 memset(key.get(), 0x11, key_size); | |
| 377 | |
| 378 CryptoSecretBoxer boxer; | |
| 379 boxer.SetKeys({string(reinterpret_cast<char*>(key.get()), key_size)}); | |
| 380 const string box = boxer.Box(rand, message); | |
| 381 MockClock clock; | |
| 382 QuicWallTime now = clock.WallNow(); | |
| 383 const QuicWallTime original_time = now; | |
| 384 EXPECT_EQ(SERVER_NONCE_DECRYPTION_FAILURE, | |
| 385 peer.ValidateServerNonce(box, now)); | |
| 386 | |
| 387 string server_nonce = peer.NewServerNonce(rand, now); | |
| 388 EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now)); | |
| 389 EXPECT_EQ(SERVER_NONCE_NOT_UNIQUE_FAILURE, | |
| 390 peer.ValidateServerNonce(server_nonce, now)); | |
| 391 | |
| 392 now = original_time.Add(QuicTime::Delta::FromSeconds(1000 * 7)); | |
| 393 server_nonce = peer.NewServerNonce(rand, now); | |
| 394 EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now)); | |
| 395 } | |
| 396 | |
| 397 class CryptoServerConfigsTest : public ::testing::Test { | |
| 398 public: | |
| 399 CryptoServerConfigsTest() | |
| 400 : rand_(QuicRandom::GetInstance()), | |
| 401 config_(QuicCryptoServerConfig::TESTING, | |
| 402 rand_, | |
| 403 CryptoTestUtils::ProofSourceForTesting()), | |
| 404 test_peer_(&config_) {} | |
| 405 | |
| 406 void SetUp() override { | |
| 407 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000)); | |
| 408 } | |
| 409 | |
| 410 // SetConfigs constructs suitable config protobufs and calls SetConfigs on | |
| 411 // |config_|. The arguments are given as nullptr-terminated pairs. The first | |
| 412 // of each pair is the server config ID of a Config. The second is the | |
| 413 // |primary_time| of that Config, given in epoch seconds. (Although note that, | |
| 414 // in these tests, time is set to 1000 seconds since the epoch.) For example: | |
| 415 // SetConfigs(nullptr); // calls |config_.SetConfigs| with no protobufs. | |
| 416 // | |
| 417 // // Calls |config_.SetConfigs| with two protobufs: one for a Config with | |
| 418 // // a |primary_time| of 900 and priority 1, and another with | |
| 419 // // a |primary_time| of 1000 and priority 2. | |
| 420 | |
| 421 // CheckConfigs( | |
| 422 // "id1", 900, 1, | |
| 423 // "id2", 1000, 2, | |
| 424 // nullptr); | |
| 425 // | |
| 426 // If the server config id starts with "INVALID" then the generated protobuf | |
| 427 // will be invalid. | |
| 428 void SetConfigs(const char* server_config_id1, ...) { | |
| 429 const char kOrbit[] = "12345678"; | |
| 430 | |
| 431 va_list ap; | |
| 432 va_start(ap, server_config_id1); | |
| 433 bool has_invalid = false; | |
| 434 bool is_empty = true; | |
| 435 | |
| 436 vector<QuicServerConfigProtobuf*> protobufs; | |
| 437 bool first = true; | |
| 438 for (;;) { | |
| 439 const char* server_config_id; | |
| 440 if (first) { | |
| 441 server_config_id = server_config_id1; | |
| 442 first = false; | |
| 443 } else { | |
| 444 server_config_id = va_arg(ap, const char*); | |
| 445 } | |
| 446 | |
| 447 if (!server_config_id) { | |
| 448 break; | |
| 449 } | |
| 450 | |
| 451 is_empty = false; | |
| 452 int primary_time = va_arg(ap, int); | |
| 453 int priority = va_arg(ap, int); | |
| 454 | |
| 455 QuicCryptoServerConfig::ConfigOptions options; | |
| 456 options.id = server_config_id; | |
| 457 options.orbit = kOrbit; | |
| 458 QuicServerConfigProtobuf* protobuf( | |
| 459 QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options)); | |
| 460 protobuf->set_primary_time(primary_time); | |
| 461 protobuf->set_priority(priority); | |
| 462 if (string(server_config_id).find("INVALID") == 0) { | |
| 463 protobuf->clear_key(); | |
| 464 has_invalid = true; | |
| 465 } | |
| 466 protobufs.push_back(protobuf); | |
| 467 } | |
| 468 | |
| 469 ASSERT_EQ(!has_invalid && !is_empty, | |
| 470 config_.SetConfigs(protobufs, clock_.WallNow())); | |
| 471 STLDeleteElements(&protobufs); | |
| 472 } | |
| 473 | |
| 474 protected: | |
| 475 QuicRandom* const rand_; | |
| 476 MockClock clock_; | |
| 477 QuicCryptoServerConfig config_; | |
| 478 QuicCryptoServerConfigPeer test_peer_; | |
| 479 }; | |
| 480 | |
| 481 TEST_F(CryptoServerConfigsTest, NoConfigs) { | |
| 482 test_peer_.CheckConfigs(nullptr); | |
| 483 } | |
| 484 | |
| 485 TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) { | |
| 486 // Make sure that "b" is primary even though "a" comes first. | |
| 487 SetConfigs("a", 1100, 1, "b", 900, 1, nullptr); | |
| 488 test_peer_.CheckConfigs("a", false, "b", true, nullptr); | |
| 489 } | |
| 490 | |
| 491 TEST_F(CryptoServerConfigsTest, MakePrimarySecond) { | |
| 492 // Make sure that a remains primary after b is added. | |
| 493 SetConfigs("a", 900, 1, "b", 1100, 1, nullptr); | |
| 494 test_peer_.CheckConfigs("a", true, "b", false, nullptr); | |
| 495 } | |
| 496 | |
| 497 TEST_F(CryptoServerConfigsTest, Delete) { | |
| 498 // Ensure that configs get deleted when removed. | |
| 499 SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr); | |
| 500 test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr); | |
| 501 SetConfigs("b", 900, 1, "c", 1100, 1, nullptr); | |
| 502 test_peer_.CheckConfigs("b", true, "c", false, nullptr); | |
| 503 } | |
| 504 | |
| 505 TEST_F(CryptoServerConfigsTest, DeletePrimary) { | |
| 506 // Ensure that deleting the primary config works. | |
| 507 SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr); | |
| 508 test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr); | |
| 509 SetConfigs("a", 800, 1, "c", 1100, 1, nullptr); | |
| 510 test_peer_.CheckConfigs("a", true, "c", false, nullptr); | |
| 511 } | |
| 512 | |
| 513 TEST_F(CryptoServerConfigsTest, FailIfDeletingAllConfigs) { | |
| 514 // Ensure that configs get deleted when removed. | |
| 515 SetConfigs("a", 800, 1, "b", 900, 1, nullptr); | |
| 516 test_peer_.CheckConfigs("a", false, "b", true, nullptr); | |
| 517 SetConfigs(nullptr); | |
| 518 // Config change is rejected, still using old configs. | |
| 519 test_peer_.CheckConfigs("a", false, "b", true, nullptr); | |
| 520 } | |
| 521 | |
| 522 TEST_F(CryptoServerConfigsTest, ChangePrimaryTime) { | |
| 523 // Check that updates to primary time get picked up. | |
| 524 SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr); | |
| 525 test_peer_.SelectNewPrimaryConfig(500); | |
| 526 test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); | |
| 527 SetConfigs("a", 1200, 1, "b", 800, 1, "c", 400, 1, nullptr); | |
| 528 test_peer_.SelectNewPrimaryConfig(500); | |
| 529 test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); | |
| 530 } | |
| 531 | |
| 532 TEST_F(CryptoServerConfigsTest, AllConfigsInThePast) { | |
| 533 // Check that the most recent config is selected. | |
| 534 SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr); | |
| 535 test_peer_.SelectNewPrimaryConfig(1500); | |
| 536 test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); | |
| 537 } | |
| 538 | |
| 539 TEST_F(CryptoServerConfigsTest, AllConfigsInTheFuture) { | |
| 540 // Check that the first config is selected. | |
| 541 SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr); | |
| 542 test_peer_.SelectNewPrimaryConfig(100); | |
| 543 test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); | |
| 544 } | |
| 545 | |
| 546 TEST_F(CryptoServerConfigsTest, SortByPriority) { | |
| 547 // Check that priority is used to decide on a primary config when | |
| 548 // configs have the same primary time. | |
| 549 SetConfigs("a", 900, 1, "b", 900, 2, "c", 900, 3, nullptr); | |
| 550 test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); | |
| 551 test_peer_.SelectNewPrimaryConfig(800); | |
| 552 test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); | |
| 553 test_peer_.SelectNewPrimaryConfig(1000); | |
| 554 test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); | |
| 555 | |
| 556 // Change priorities and expect sort order to change. | |
| 557 SetConfigs("a", 900, 2, "b", 900, 1, "c", 900, 0, nullptr); | |
| 558 test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); | |
| 559 test_peer_.SelectNewPrimaryConfig(800); | |
| 560 test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); | |
| 561 test_peer_.SelectNewPrimaryConfig(1000); | |
| 562 test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); | |
| 563 } | |
| 564 | |
| 565 TEST_F(CryptoServerConfigsTest, AdvancePrimary) { | |
| 566 // Check that a new primary config is enabled at the right time. | |
| 567 SetConfigs("a", 900, 1, "b", 1100, 1, nullptr); | |
| 568 test_peer_.SelectNewPrimaryConfig(1000); | |
| 569 test_peer_.CheckConfigs("a", true, "b", false, nullptr); | |
| 570 test_peer_.SelectNewPrimaryConfig(1101); | |
| 571 test_peer_.CheckConfigs("a", false, "b", true, nullptr); | |
| 572 } | |
| 573 | |
| 574 TEST_F(CryptoServerConfigsTest, InvalidConfigs) { | |
| 575 // Ensure that invalid configs don't change anything. | |
| 576 SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr); | |
| 577 test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr); | |
| 578 SetConfigs("a", 800, 1, "c", 1100, 1, "INVALID1", 1000, 1, nullptr); | |
| 579 test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr); | |
| 580 } | |
| 581 | |
| 582 } // namespace test | |
| 583 } // namespace net | |
| OLD | NEW |