| 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 "base/stl_util.h" | |
| 10 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" | |
| 11 #include "net/quic/crypto/crypto_handshake_message.h" | |
| 12 #include "net/quic/crypto/crypto_secret_boxer.h" | |
| 13 #include "net/quic/crypto/crypto_server_config_protobuf.h" | |
| 14 #include "net/quic/crypto/quic_random.h" | |
| 15 #include "net/quic/crypto/strike_register_client.h" | |
| 16 #include "net/quic/quic_flags.h" | |
| 17 #include "net/quic/quic_time.h" | |
| 18 #include "net/quic/test_tools/mock_clock.h" | |
| 19 #include "net/quic/test_tools/quic_test_utils.h" | |
| 20 #include "testing/gmock/include/gmock/gmock.h" | |
| 21 #include "testing/gtest/include/gtest/gtest.h" | |
| 22 | |
| 23 using base::StringPiece; | |
| 24 using std::map; | |
| 25 using std::pair; | |
| 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 scoped_refptr<QuicCryptoServerConfig::Config> GetConfig(string config_id) { | |
| 38 base::AutoLock locked(server_config_->configs_lock_); | |
| 39 if (config_id == "<primary>") { | |
| 40 return scoped_refptr<QuicCryptoServerConfig::Config>( | |
| 41 server_config_->primary_config_); | |
| 42 } else { | |
| 43 return server_config_->GetConfigWithScid(config_id); | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 bool ConfigHasDefaultSourceAddressTokenBoxer(string config_id) { | |
| 48 scoped_refptr<QuicCryptoServerConfig::Config> config = GetConfig(config_id); | |
| 49 return config->source_address_token_boxer == | |
| 50 &(server_config_->default_source_address_token_boxer_); | |
| 51 } | |
| 52 | |
| 53 string NewSourceAddressToken(string config_id, | |
| 54 SourceAddressTokens previous_tokens, | |
| 55 const IPEndPoint& ip, | |
| 56 QuicRandom* rand, | |
| 57 QuicWallTime now, | |
| 58 CachedNetworkParameters* cached_network_params) { | |
| 59 return server_config_->NewSourceAddressToken(*GetConfig(config_id), | |
| 60 previous_tokens, ip, rand, now, | |
| 61 cached_network_params); | |
| 62 } | |
| 63 | |
| 64 HandshakeFailureReason ValidateSourceAddressToken(string config_id, | |
| 65 StringPiece srct, | |
| 66 const IPEndPoint& ip, | |
| 67 QuicWallTime now) { | |
| 68 return ValidateSourceAddressToken(config_id, srct, ip, now, NULL); | |
| 69 } | |
| 70 | |
| 71 HandshakeFailureReason ValidateSourceAddressToken( | |
| 72 string config_id, | |
| 73 StringPiece srct, | |
| 74 const IPEndPoint& ip, | |
| 75 QuicWallTime now, | |
| 76 CachedNetworkParameters* cached_network_params) { | |
| 77 return server_config_->ValidateSourceAddressToken( | |
| 78 *GetConfig(config_id), srct, ip, now, cached_network_params); | |
| 79 } | |
| 80 | |
| 81 HandshakeFailureReason ValidateSourceAddressTokens(string config_id, | |
| 82 StringPiece srct, | |
| 83 const IPEndPoint& ip, | |
| 84 QuicWallTime now) { | |
| 85 return ValidateSourceAddressTokens(config_id, srct, ip, now, NULL); | |
| 86 } | |
| 87 | |
| 88 HandshakeFailureReason ValidateSourceAddressTokens( | |
| 89 string config_id, | |
| 90 StringPiece srct, | |
| 91 const IPEndPoint& ip, | |
| 92 QuicWallTime now, | |
| 93 CachedNetworkParameters* cached_network_params) { | |
| 94 SourceAddressTokens tokens; | |
| 95 HandshakeFailureReason reason = server_config_->ParseSourceAddressToken( | |
| 96 *GetConfig(config_id), srct, &tokens); | |
| 97 if (reason != HANDSHAKE_OK) { | |
| 98 return reason; | |
| 99 } | |
| 100 | |
| 101 return server_config_->ValidateSourceAddressTokens(tokens, ip, now, | |
| 102 cached_network_params); | |
| 103 } | |
| 104 | |
| 105 string NewServerNonce(QuicRandom* rand, QuicWallTime now) const { | |
| 106 return server_config_->NewServerNonce(rand, now); | |
| 107 } | |
| 108 | |
| 109 HandshakeFailureReason ValidateServerNonce(StringPiece token, | |
| 110 QuicWallTime now) { | |
| 111 return server_config_->ValidateServerNonce(token, now); | |
| 112 } | |
| 113 | |
| 114 base::Lock* GetStrikeRegisterClientLock() { | |
| 115 return &server_config_->strike_register_client_lock_; | |
| 116 } | |
| 117 | |
| 118 // CheckConfigs compares the state of the Configs in |server_config_| to the | |
| 119 // description given as arguments. The arguments are given as | |
| 120 // nullptr-terminated pairs. The first of each pair is the server config ID of | |
| 121 // a Config. The second is a boolean describing whether the config is the | |
| 122 // primary. For example: | |
| 123 // CheckConfigs(nullptr); // checks that no Configs are loaded. | |
| 124 // | |
| 125 // // Checks that exactly three Configs are loaded with the given IDs and | |
| 126 // // status. | |
| 127 // CheckConfigs( | |
| 128 // "id1", false, | |
| 129 // "id2", true, | |
| 130 // "id3", false, | |
| 131 // nullptr); | |
| 132 void CheckConfigs(const char* server_config_id1, ...) { | |
| 133 va_list ap; | |
| 134 va_start(ap, server_config_id1); | |
| 135 | |
| 136 vector<pair<ServerConfigID, bool> > expected; | |
| 137 bool first = true; | |
| 138 for (;;) { | |
| 139 const char* server_config_id; | |
| 140 if (first) { | |
| 141 server_config_id = server_config_id1; | |
| 142 first = false; | |
| 143 } else { | |
| 144 server_config_id = va_arg(ap, const char*); | |
| 145 } | |
| 146 | |
| 147 if (!server_config_id) { | |
| 148 break; | |
| 149 } | |
| 150 | |
| 151 // varargs will promote the value to an int so we have to read that from | |
| 152 // the stack and cast down. | |
| 153 const bool is_primary = static_cast<bool>(va_arg(ap, int)); | |
| 154 expected.push_back(std::make_pair(server_config_id, is_primary)); | |
| 155 } | |
| 156 | |
| 157 va_end(ap); | |
| 158 | |
| 159 base::AutoLock locked(server_config_->configs_lock_); | |
| 160 | |
| 161 ASSERT_EQ(expected.size(), server_config_->configs_.size()) | |
| 162 << ConfigsDebug(); | |
| 163 | |
| 164 for (QuicCryptoServerConfig::ConfigMap::const_iterator | |
| 165 i = server_config_->configs_.begin(); | |
| 166 i != server_config_->configs_.end(); ++i) { | |
| 167 bool found = false; | |
| 168 for (vector<pair<ServerConfigID, bool> >::iterator j = expected.begin(); | |
| 169 j != expected.end(); ++j) { | |
| 170 if (i->first == j->first && i->second->is_primary == j->second) { | |
| 171 found = true; | |
| 172 j->first.clear(); | |
| 173 break; | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 ASSERT_TRUE(found) << "Failed to find match for " << i->first | |
| 178 << " in configs:\n" << ConfigsDebug(); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 // ConfigsDebug returns a string that contains debugging information about | |
| 183 // the set of Configs loaded in |server_config_| and their status. | |
| 184 // ConfigsDebug() should be called after acquiring | |
| 185 // server_config_->configs_lock_. | |
| 186 string ConfigsDebug() { | |
| 187 if (server_config_->configs_.empty()) { | |
| 188 return "No Configs in QuicCryptoServerConfig"; | |
| 189 } | |
| 190 | |
| 191 string s; | |
| 192 | |
| 193 for (QuicCryptoServerConfig::ConfigMap::const_iterator | |
| 194 i = server_config_->configs_.begin(); | |
| 195 i != server_config_->configs_.end(); ++i) { | |
| 196 const scoped_refptr<QuicCryptoServerConfig::Config> config = i->second; | |
| 197 if (config->is_primary) { | |
| 198 s += "(primary) "; | |
| 199 } else { | |
| 200 s += " "; | |
| 201 } | |
| 202 s += config->id; | |
| 203 s += "\n"; | |
| 204 } | |
| 205 | |
| 206 return s; | |
| 207 } | |
| 208 | |
| 209 void SelectNewPrimaryConfig(int seconds) { | |
| 210 base::AutoLock locked(server_config_->configs_lock_); | |
| 211 server_config_->SelectNewPrimaryConfig( | |
| 212 QuicWallTime::FromUNIXSeconds(seconds)); | |
| 213 } | |
| 214 | |
| 215 private: | |
| 216 const QuicCryptoServerConfig* server_config_; | |
| 217 }; | |
| 218 | |
| 219 class TestStrikeRegisterClient : public StrikeRegisterClient { | |
| 220 public: | |
| 221 explicit TestStrikeRegisterClient(QuicCryptoServerConfig* config) | |
| 222 : config_(config), | |
| 223 is_known_orbit_called_(false) { | |
| 224 } | |
| 225 | |
| 226 bool IsKnownOrbit(StringPiece orbit) const override { | |
| 227 // Ensure that the strike register client lock is not held. | |
| 228 QuicCryptoServerConfigPeer peer(config_); | |
| 229 base::Lock* m = peer.GetStrikeRegisterClientLock(); | |
| 230 // In Chromium, we will dead lock if the lock is held by the current thread. | |
| 231 // Chromium doesn't have AssertNotHeld API call. | |
| 232 // m->AssertNotHeld(); | |
| 233 base::AutoLock lock(*m); | |
| 234 | |
| 235 is_known_orbit_called_ = true; | |
| 236 return true; | |
| 237 } | |
| 238 | |
| 239 void VerifyNonceIsValidAndUnique(StringPiece nonce, | |
| 240 QuicWallTime now, | |
| 241 ResultCallback* cb) override { | |
| 242 LOG(FATAL) << "Not implemented"; | |
| 243 } | |
| 244 | |
| 245 bool is_known_orbit_called() { return is_known_orbit_called_; } | |
| 246 | |
| 247 private: | |
| 248 QuicCryptoServerConfig* config_; | |
| 249 mutable bool is_known_orbit_called_; | |
| 250 }; | |
| 251 | |
| 252 TEST(QuicCryptoServerConfigTest, ServerConfig) { | |
| 253 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 254 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand); | |
| 255 MockClock clock; | |
| 256 | |
| 257 scoped_ptr<CryptoHandshakeMessage>( | |
| 258 server.AddDefaultConfig(rand, &clock, | |
| 259 QuicCryptoServerConfig::ConfigOptions())); | |
| 260 } | |
| 261 | |
| 262 TEST(QuicCryptoServerConfigTest, GetOrbitIsCalledWithoutTheStrikeRegisterLock) { | |
| 263 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 264 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand); | |
| 265 MockClock clock; | |
| 266 | |
| 267 TestStrikeRegisterClient* strike_register = | |
| 268 new TestStrikeRegisterClient(&server); | |
| 269 server.SetStrikeRegisterClient(strike_register); | |
| 270 | |
| 271 QuicCryptoServerConfig::ConfigOptions options; | |
| 272 scoped_ptr<CryptoHandshakeMessage>( | |
| 273 server.AddDefaultConfig(rand, &clock, options)); | |
| 274 EXPECT_TRUE(strike_register->is_known_orbit_called()); | |
| 275 } | |
| 276 | |
| 277 class SourceAddressTokenTest : public ::testing::Test { | |
| 278 public: | |
| 279 SourceAddressTokenTest() | |
| 280 : ip4_(IPEndPoint(Loopback4(), 1)), | |
| 281 ip4_dual_(ConvertIPv4NumberToIPv6Number(ip4_.address()), 1), | |
| 282 ip6_(IPEndPoint(Loopback6(), 2)), | |
| 283 original_time_(QuicWallTime::Zero()), | |
| 284 rand_(QuicRandom::GetInstance()), | |
| 285 server_(QuicCryptoServerConfig::TESTING, rand_), | |
| 286 peer_(&server_) { | |
| 287 // Advance the clock to some non-zero time. | |
| 288 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); | |
| 289 original_time_ = clock_.WallNow(); | |
| 290 | |
| 291 primary_config_.reset(server_.AddDefaultConfig( | |
| 292 rand_, &clock_, QuicCryptoServerConfig::ConfigOptions())); | |
| 293 | |
| 294 // Add a config that overrides the default boxer. | |
| 295 QuicCryptoServerConfig::ConfigOptions options; | |
| 296 options.id = kOverride; | |
| 297 override_config_protobuf_.reset( | |
| 298 QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options)); | |
| 299 override_config_protobuf_->set_source_address_token_secret_override( | |
| 300 "a secret key"); | |
| 301 // Lower priority than the default config. | |
| 302 override_config_protobuf_->set_priority(1); | |
| 303 override_config_.reset( | |
| 304 server_.AddConfig(override_config_protobuf_.get(), original_time_)); | |
| 305 } | |
| 306 | |
| 307 string NewSourceAddressToken(string config_id, const IPEndPoint& ip) { | |
| 308 return NewSourceAddressToken(config_id, ip, NULL); | |
| 309 } | |
| 310 | |
| 311 string NewSourceAddressToken(string config_id, | |
| 312 const IPEndPoint& ip, | |
| 313 const SourceAddressTokens& previous_tokens) { | |
| 314 return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_, | |
| 315 clock_.WallNow(), NULL); | |
| 316 } | |
| 317 | |
| 318 string NewSourceAddressToken(string config_id, | |
| 319 const IPEndPoint& ip, | |
| 320 CachedNetworkParameters* cached_network_params) { | |
| 321 SourceAddressTokens previous_tokens; | |
| 322 return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_, | |
| 323 clock_.WallNow(), cached_network_params); | |
| 324 } | |
| 325 | |
| 326 HandshakeFailureReason ValidateSourceAddressToken(string config_id, | |
| 327 StringPiece srct, | |
| 328 const IPEndPoint& ip) { | |
| 329 return ValidateSourceAddressToken(config_id, srct, ip, NULL); | |
| 330 } | |
| 331 | |
| 332 HandshakeFailureReason ValidateSourceAddressToken( | |
| 333 string config_id, | |
| 334 StringPiece srct, | |
| 335 const IPEndPoint& ip, | |
| 336 CachedNetworkParameters* cached_network_params) { | |
| 337 return peer_.ValidateSourceAddressToken( | |
| 338 config_id, srct, ip, clock_.WallNow(), cached_network_params); | |
| 339 } | |
| 340 | |
| 341 HandshakeFailureReason ValidateSourceAddressTokens(string config_id, | |
| 342 StringPiece srct, | |
| 343 const IPEndPoint& ip) { | |
| 344 return ValidateSourceAddressTokens(config_id, srct, ip, NULL); | |
| 345 } | |
| 346 | |
| 347 HandshakeFailureReason ValidateSourceAddressTokens( | |
| 348 string config_id, | |
| 349 StringPiece srct, | |
| 350 const IPEndPoint& ip, | |
| 351 CachedNetworkParameters* cached_network_params) { | |
| 352 return peer_.ValidateSourceAddressTokens( | |
| 353 config_id, srct, ip, clock_.WallNow(), cached_network_params); | |
| 354 } | |
| 355 | |
| 356 const string kPrimary = "<primary>"; | |
| 357 const string kOverride = "Config with custom source address token key"; | |
| 358 | |
| 359 IPEndPoint ip4_; | |
| 360 IPEndPoint ip4_dual_; | |
| 361 IPEndPoint ip6_; | |
| 362 | |
| 363 MockClock clock_; | |
| 364 QuicWallTime original_time_; | |
| 365 QuicRandom* rand_ = QuicRandom::GetInstance(); | |
| 366 QuicCryptoServerConfig server_; | |
| 367 QuicCryptoServerConfigPeer peer_; | |
| 368 // Stores the primary config. | |
| 369 scoped_ptr<CryptoHandshakeMessage> primary_config_; | |
| 370 scoped_ptr<QuicServerConfigProtobuf> override_config_protobuf_; | |
| 371 scoped_ptr<CryptoHandshakeMessage> override_config_; | |
| 372 }; | |
| 373 | |
| 374 TEST_F(SourceAddressTokenTest, SourceAddressToken) { | |
| 375 ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens, | |
| 376 false); | |
| 377 | |
| 378 EXPECT_TRUE(peer_.ConfigHasDefaultSourceAddressTokenBoxer(kPrimary)); | |
| 379 EXPECT_FALSE(peer_.ConfigHasDefaultSourceAddressTokenBoxer(kOverride)); | |
| 380 | |
| 381 // Primary config generates configs that validate successfully. | |
| 382 const string token4 = NewSourceAddressToken(kPrimary, ip4_); | |
| 383 const string token4d = NewSourceAddressToken(kPrimary, ip4_dual_); | |
| 384 const string token6 = NewSourceAddressToken(kPrimary, ip6_); | |
| 385 EXPECT_EQ(HANDSHAKE_OK, ValidateSourceAddressToken(kPrimary, token4, ip4_)); | |
| 386 ASSERT_EQ(HANDSHAKE_OK, | |
| 387 ValidateSourceAddressToken(kPrimary, token4, ip4_dual_)); | |
| 388 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 389 ValidateSourceAddressToken(kPrimary, token4, ip6_)); | |
| 390 ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressToken(kPrimary, token4d, ip4_)); | |
| 391 ASSERT_EQ(HANDSHAKE_OK, | |
| 392 ValidateSourceAddressToken(kPrimary, token4d, ip4_dual_)); | |
| 393 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 394 ValidateSourceAddressToken(kPrimary, token4d, ip6_)); | |
| 395 ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressToken(kPrimary, token6, ip6_)); | |
| 396 | |
| 397 // Override config generates configs that validate successfully. | |
| 398 const string override_token4 = NewSourceAddressToken(kOverride, ip4_); | |
| 399 const string override_token6 = NewSourceAddressToken(kOverride, ip6_); | |
| 400 ASSERT_EQ(HANDSHAKE_OK, | |
| 401 ValidateSourceAddressToken(kOverride, override_token4, ip4_)); | |
| 402 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 403 ValidateSourceAddressToken(kOverride, override_token4, ip6_)); | |
| 404 ASSERT_EQ(HANDSHAKE_OK, | |
| 405 ValidateSourceAddressToken(kOverride, override_token6, ip6_)); | |
| 406 | |
| 407 // Tokens generated by the primary config do not validate | |
| 408 // successfully against the override config, and vice versa. | |
| 409 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 410 ValidateSourceAddressToken(kOverride, token4, ip4_)); | |
| 411 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 412 ValidateSourceAddressToken(kOverride, token6, ip6_)); | |
| 413 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 414 ValidateSourceAddressToken(kPrimary, override_token4, ip4_)); | |
| 415 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 416 ValidateSourceAddressToken(kPrimary, override_token6, ip6_)); | |
| 417 } | |
| 418 | |
| 419 TEST_F(SourceAddressTokenTest, SourceAddressTokenExpiration) { | |
| 420 ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens, | |
| 421 false); | |
| 422 | |
| 423 const string token = NewSourceAddressToken(kPrimary, ip4_); | |
| 424 | |
| 425 // Validation fails if the token is from the future. | |
| 426 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(-3600 * 2)); | |
| 427 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE, | |
| 428 ValidateSourceAddressToken(kPrimary, token, ip4_)); | |
| 429 | |
| 430 // Validation fails after tokens expire. | |
| 431 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(86400 * 7)); | |
| 432 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE, | |
| 433 ValidateSourceAddressToken(kPrimary, token, ip4_)); | |
| 434 } | |
| 435 | |
| 436 TEST_F(SourceAddressTokenTest, SourceAddressTokenWithNetworkParams) { | |
| 437 ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens, | |
| 438 false); | |
| 439 | |
| 440 // Make sure that if the source address token contains CachedNetworkParameters | |
| 441 // that this gets written to ValidateSourceAddressToken output argument. | |
| 442 CachedNetworkParameters cached_network_params_input; | |
| 443 cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234); | |
| 444 const string token4_with_cached_network_params = | |
| 445 NewSourceAddressToken(kPrimary, ip4_, &cached_network_params_input); | |
| 446 | |
| 447 CachedNetworkParameters cached_network_params_output; | |
| 448 #if 0 | |
| 449 // TODO(rtenneti): For server, enable the following check after serialization | |
| 450 // of optional CachedNetworkParameters is implemented. | |
| 451 EXPECT_NE(cached_network_params_output.DebugString(), | |
| 452 cached_network_params_input.DebugString()); | |
| 453 #endif | |
| 454 ValidateSourceAddressToken(kPrimary, token4_with_cached_network_params, ip4_, | |
| 455 &cached_network_params_output); | |
| 456 #if 0 | |
| 457 // TODO(rtenneti): For server, enable the following check after serialization | |
| 458 // of optional CachedNetworkParameters is implemented. | |
| 459 EXPECT_EQ(cached_network_params_output.DebugString(), | |
| 460 cached_network_params_input.DebugString()); | |
| 461 #endif | |
| 462 } | |
| 463 | |
| 464 // Test basic behavior of source address tokens including being specific | |
| 465 // to a single IP address and server config. | |
| 466 // | |
| 467 // TODO(rtenneti): For server, enable the following test after serialization of | |
| 468 // SourceAddressTokens is implemented. | |
| 469 TEST_F(SourceAddressTokenTest, DISABLED_NewSourceAddressToken) { | |
| 470 ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens, | |
| 471 true); | |
| 472 | |
| 473 // Primary config generates configs that validate successfully. | |
| 474 const string token4 = NewSourceAddressToken(kPrimary, ip4_); | |
| 475 const string token4d = NewSourceAddressToken(kPrimary, ip4_dual_); | |
| 476 const string token6 = NewSourceAddressToken(kPrimary, ip6_); | |
| 477 EXPECT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4, ip4_)); | |
| 478 ASSERT_EQ(HANDSHAKE_OK, | |
| 479 ValidateSourceAddressTokens(kPrimary, token4, ip4_dual_)); | |
| 480 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 481 ValidateSourceAddressTokens(kPrimary, token4, ip6_)); | |
| 482 ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4d, ip4_)); | |
| 483 ASSERT_EQ(HANDSHAKE_OK, | |
| 484 ValidateSourceAddressTokens(kPrimary, token4d, ip4_dual_)); | |
| 485 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 486 ValidateSourceAddressTokens(kPrimary, token4d, ip6_)); | |
| 487 ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token6, ip6_)); | |
| 488 | |
| 489 // Override config generates configs that validate successfully. | |
| 490 const string override_token4 = NewSourceAddressToken(kOverride, ip4_); | |
| 491 const string override_token6 = NewSourceAddressToken(kOverride, ip6_); | |
| 492 ASSERT_EQ(HANDSHAKE_OK, | |
| 493 ValidateSourceAddressTokens(kOverride, override_token4, ip4_)); | |
| 494 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, | |
| 495 ValidateSourceAddressTokens(kOverride, override_token4, ip6_)); | |
| 496 ASSERT_EQ(HANDSHAKE_OK, | |
| 497 ValidateSourceAddressTokens(kOverride, override_token6, ip6_)); | |
| 498 | |
| 499 // Tokens generated by the primary config do not validate | |
| 500 // successfully against the override config, and vice versa. | |
| 501 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 502 ValidateSourceAddressTokens(kOverride, token4, ip4_)); | |
| 503 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 504 ValidateSourceAddressTokens(kOverride, token6, ip6_)); | |
| 505 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 506 ValidateSourceAddressTokens(kPrimary, override_token4, ip4_)); | |
| 507 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, | |
| 508 ValidateSourceAddressTokens(kPrimary, override_token6, ip6_)); | |
| 509 } | |
| 510 | |
| 511 // TODO(rtenneti): For server, enable the following test after serialization of | |
| 512 // SourceAddressTokens is implemented. | |
| 513 TEST_F(SourceAddressTokenTest, DISABLED_NewSourceAddressTokenExpiration) { | |
| 514 ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens, | |
| 515 true); | |
| 516 | |
| 517 const string token = NewSourceAddressToken(kPrimary, ip4_); | |
| 518 | |
| 519 // Validation fails if the token is from the future. | |
| 520 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(-3600 * 2)); | |
| 521 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE, | |
| 522 ValidateSourceAddressTokens(kPrimary, token, ip4_)); | |
| 523 | |
| 524 // Validation fails after tokens expire. | |
| 525 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(86400 * 7)); | |
| 526 ASSERT_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE, | |
| 527 ValidateSourceAddressTokens(kPrimary, token, ip4_)); | |
| 528 } | |
| 529 | |
| 530 TEST_F(SourceAddressTokenTest, NewSourceAddressTokenWithNetworkParams) { | |
| 531 ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens, | |
| 532 true); | |
| 533 | |
| 534 // Make sure that if the source address token contains CachedNetworkParameters | |
| 535 // that this gets written to ValidateSourceAddressToken output argument. | |
| 536 CachedNetworkParameters cached_network_params_input; | |
| 537 cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234); | |
| 538 const string token4_with_cached_network_params = | |
| 539 NewSourceAddressToken(kPrimary, ip4_, &cached_network_params_input); | |
| 540 | |
| 541 CachedNetworkParameters cached_network_params_output; | |
| 542 #if 0 | |
| 543 // TODO(rtenneti): For server, enable the following check after serialization | |
| 544 // of optional CachedNetworkParameters is implemented. | |
| 545 EXPECT_NE(cached_network_params_output.DebugString(), | |
| 546 cached_network_params_input.DebugString()); | |
| 547 #endif | |
| 548 ValidateSourceAddressTokens(kPrimary, token4_with_cached_network_params, ip4_, | |
| 549 &cached_network_params_output); | |
| 550 #if 0 | |
| 551 // TODO(rtenneti): For server, enable the following check after serialization | |
| 552 // of optional CachedNetworkParameters is implemented. | |
| 553 EXPECT_EQ(cached_network_params_output.DebugString(), | |
| 554 cached_network_params_input.DebugString()); | |
| 555 #endif | |
| 556 } | |
| 557 | |
| 558 // Test the ability for a source address token to be valid for multiple | |
| 559 // addresses. | |
| 560 // | |
| 561 // TODO(rtenneti): For server, enable the following test after serialization of | |
| 562 // SourceAddressTokens is implemented. | |
| 563 TEST_F(SourceAddressTokenTest, DISABLED_SourceAddressTokenMultipleAddresses) { | |
| 564 ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens, | |
| 565 true); | |
| 566 | |
| 567 QuicWallTime now = clock_.WallNow(); | |
| 568 | |
| 569 // Now create a token which is usable for both addresses. | |
| 570 SourceAddressToken previous_token; | |
| 571 IPAddressNumber ip_address = ip6_.address(); | |
| 572 if (ip6_.GetSockAddrFamily() == AF_INET) { | |
| 573 ip_address = ConvertIPv4NumberToIPv6Number(ip_address); | |
| 574 } | |
| 575 previous_token.set_ip(IPAddressToPackedString(ip_address)); | |
| 576 previous_token.set_timestamp(now.ToUNIXSeconds()); | |
| 577 SourceAddressTokens previous_tokens; | |
| 578 (*previous_tokens.add_tokens()) = previous_token; | |
| 579 const string token4or6 = | |
| 580 NewSourceAddressToken(kPrimary, ip4_, previous_tokens); | |
| 581 | |
| 582 EXPECT_EQ(HANDSHAKE_OK, | |
| 583 ValidateSourceAddressTokens(kPrimary, token4or6, ip4_)); | |
| 584 ASSERT_EQ(HANDSHAKE_OK, | |
| 585 ValidateSourceAddressTokens(kPrimary, token4or6, ip6_)); | |
| 586 } | |
| 587 | |
| 588 TEST(QuicCryptoServerConfigTest, ValidateServerNonce) { | |
| 589 QuicRandom* rand = QuicRandom::GetInstance(); | |
| 590 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand); | |
| 591 QuicCryptoServerConfigPeer peer(&server); | |
| 592 | |
| 593 StringPiece message("hello world"); | |
| 594 const size_t key_size = CryptoSecretBoxer::GetKeySize(); | |
| 595 scoped_ptr<uint8[]> key(new uint8[key_size]); | |
| 596 memset(key.get(), 0x11, key_size); | |
| 597 | |
| 598 CryptoSecretBoxer boxer; | |
| 599 boxer.SetKey(StringPiece(reinterpret_cast<char*>(key.get()), key_size)); | |
| 600 const string box = boxer.Box(rand, message); | |
| 601 MockClock clock; | |
| 602 QuicWallTime now = clock.WallNow(); | |
| 603 const QuicWallTime original_time = now; | |
| 604 EXPECT_EQ(SERVER_NONCE_DECRYPTION_FAILURE, | |
| 605 peer.ValidateServerNonce(box, now)); | |
| 606 | |
| 607 string server_nonce = peer.NewServerNonce(rand, now); | |
| 608 EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now)); | |
| 609 EXPECT_EQ(SERVER_NONCE_NOT_UNIQUE_FAILURE, | |
| 610 peer.ValidateServerNonce(server_nonce, now)); | |
| 611 | |
| 612 now = original_time.Add(QuicTime::Delta::FromSeconds(1000 * 7)); | |
| 613 server_nonce = peer.NewServerNonce(rand, now); | |
| 614 EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now)); | |
| 615 } | |
| 616 | |
| 617 class CryptoServerConfigsTest : public ::testing::Test { | |
| 618 public: | |
| 619 CryptoServerConfigsTest() | |
| 620 : rand_(QuicRandom::GetInstance()), | |
| 621 config_(QuicCryptoServerConfig::TESTING, rand_), | |
| 622 test_peer_(&config_) {} | |
| 623 | |
| 624 void SetUp() override { | |
| 625 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000)); | |
| 626 } | |
| 627 | |
| 628 // SetConfigs constructs suitable config protobufs and calls SetConfigs on | |
| 629 // |config_|. The arguments are given as nullptr-terminated pairs. The first | |
| 630 // of each pair is the server config ID of a Config. The second is the | |
| 631 // |primary_time| of that Config, given in epoch seconds. (Although note that, | |
| 632 // in these tests, time is set to 1000 seconds since the epoch.) For example: | |
| 633 // SetConfigs(nullptr); // calls |config_.SetConfigs| with no protobufs. | |
| 634 // | |
| 635 // // Calls |config_.SetConfigs| with two protobufs: one for a Config with | |
| 636 // // a |primary_time| of 900 and priority 1, and another with | |
| 637 // // a |primary_time| of 1000 and priority 2. | |
| 638 | |
| 639 // CheckConfigs( | |
| 640 // "id1", 900, 1, | |
| 641 // "id2", 1000, 2, | |
| 642 // nullptr); | |
| 643 // | |
| 644 // If the server config id starts with "INVALID" then the generated protobuf | |
| 645 // will be invalid. | |
| 646 void SetConfigs(const char* server_config_id1, ...) { | |
| 647 const char kOrbit[] = "12345678"; | |
| 648 | |
| 649 va_list ap; | |
| 650 va_start(ap, server_config_id1); | |
| 651 bool has_invalid = false; | |
| 652 bool is_empty = true; | |
| 653 | |
| 654 vector<QuicServerConfigProtobuf*> protobufs; | |
| 655 bool first = true; | |
| 656 for (;;) { | |
| 657 const char* server_config_id; | |
| 658 if (first) { | |
| 659 server_config_id = server_config_id1; | |
| 660 first = false; | |
| 661 } else { | |
| 662 server_config_id = va_arg(ap, const char*); | |
| 663 } | |
| 664 | |
| 665 if (!server_config_id) { | |
| 666 break; | |
| 667 } | |
| 668 | |
| 669 is_empty = false; | |
| 670 int primary_time = va_arg(ap, int); | |
| 671 int priority = va_arg(ap, int); | |
| 672 | |
| 673 QuicCryptoServerConfig::ConfigOptions options; | |
| 674 options.id = server_config_id; | |
| 675 options.orbit = kOrbit; | |
| 676 QuicServerConfigProtobuf* protobuf( | |
| 677 QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options)); | |
| 678 protobuf->set_primary_time(primary_time); | |
| 679 protobuf->set_priority(priority); | |
| 680 if (string(server_config_id).find("INVALID") == 0) { | |
| 681 protobuf->clear_key(); | |
| 682 has_invalid = true; | |
| 683 } | |
| 684 protobufs.push_back(protobuf); | |
| 685 } | |
| 686 | |
| 687 ASSERT_EQ(!has_invalid && !is_empty, | |
| 688 config_.SetConfigs(protobufs, clock_.WallNow())); | |
| 689 STLDeleteElements(&protobufs); | |
| 690 } | |
| 691 | |
| 692 protected: | |
| 693 QuicRandom* const rand_; | |
| 694 MockClock clock_; | |
| 695 QuicCryptoServerConfig config_; | |
| 696 QuicCryptoServerConfigPeer test_peer_; | |
| 697 }; | |
| 698 | |
| 699 TEST_F(CryptoServerConfigsTest, NoConfigs) { | |
| 700 test_peer_.CheckConfigs(nullptr); | |
| 701 } | |
| 702 | |
| 703 TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) { | |
| 704 // Make sure that "b" is primary even though "a" comes first. | |
| 705 SetConfigs("a", 1100, 1, | |
| 706 "b", 900, 1, | |
| 707 nullptr); | |
| 708 test_peer_.CheckConfigs( | |
| 709 "a", false, | |
| 710 "b", true, | |
| 711 nullptr); | |
| 712 } | |
| 713 | |
| 714 TEST_F(CryptoServerConfigsTest, MakePrimarySecond) { | |
| 715 // Make sure that a remains primary after b is added. | |
| 716 SetConfigs("a", 900, 1, | |
| 717 "b", 1100, 1, | |
| 718 nullptr); | |
| 719 test_peer_.CheckConfigs( | |
| 720 "a", true, | |
| 721 "b", false, | |
| 722 nullptr); | |
| 723 } | |
| 724 | |
| 725 TEST_F(CryptoServerConfigsTest, Delete) { | |
| 726 // Ensure that configs get deleted when removed. | |
| 727 SetConfigs("a", 800, 1, | |
| 728 "b", 900, 1, | |
| 729 "c", 1100, 1, | |
| 730 nullptr); | |
| 731 test_peer_.CheckConfigs( | |
| 732 "a", false, | |
| 733 "b", true, | |
| 734 "c", false, | |
| 735 nullptr); | |
| 736 SetConfigs("b", 900, 1, | |
| 737 "c", 1100, 1, | |
| 738 nullptr); | |
| 739 test_peer_.CheckConfigs( | |
| 740 "b", true, | |
| 741 "c", false, | |
| 742 nullptr); | |
| 743 } | |
| 744 | |
| 745 TEST_F(CryptoServerConfigsTest, DeletePrimary) { | |
| 746 // Ensure that deleting the primary config works. | |
| 747 SetConfigs("a", 800, 1, | |
| 748 "b", 900, 1, | |
| 749 "c", 1100, 1, | |
| 750 nullptr); | |
| 751 test_peer_.CheckConfigs( | |
| 752 "a", false, | |
| 753 "b", true, | |
| 754 "c", false, | |
| 755 nullptr); | |
| 756 SetConfigs("a", 800, 1, | |
| 757 "c", 1100, 1, | |
| 758 nullptr); | |
| 759 test_peer_.CheckConfigs( | |
| 760 "a", true, | |
| 761 "c", false, | |
| 762 nullptr); | |
| 763 } | |
| 764 | |
| 765 TEST_F(CryptoServerConfigsTest, FailIfDeletingAllConfigs) { | |
| 766 // Ensure that configs get deleted when removed. | |
| 767 SetConfigs("a", 800, 1, | |
| 768 "b", 900, 1, | |
| 769 nullptr); | |
| 770 test_peer_.CheckConfigs( | |
| 771 "a", false, | |
| 772 "b", true, | |
| 773 nullptr); | |
| 774 SetConfigs(nullptr); | |
| 775 // Config change is rejected, still using old configs. | |
| 776 test_peer_.CheckConfigs( | |
| 777 "a", false, | |
| 778 "b", true, | |
| 779 nullptr); | |
| 780 } | |
| 781 | |
| 782 TEST_F(CryptoServerConfigsTest, ChangePrimaryTime) { | |
| 783 // Check that updates to primary time get picked up. | |
| 784 SetConfigs("a", 400, 1, | |
| 785 "b", 800, 1, | |
| 786 "c", 1200, 1, | |
| 787 nullptr); | |
| 788 test_peer_.SelectNewPrimaryConfig(500); | |
| 789 test_peer_.CheckConfigs( | |
| 790 "a", true, | |
| 791 "b", false, | |
| 792 "c", false, | |
| 793 nullptr); | |
| 794 SetConfigs("a", 1200, 1, | |
| 795 "b", 800, 1, | |
| 796 "c", 400, 1, | |
| 797 nullptr); | |
| 798 test_peer_.SelectNewPrimaryConfig(500); | |
| 799 test_peer_.CheckConfigs( | |
| 800 "a", false, | |
| 801 "b", false, | |
| 802 "c", true, | |
| 803 nullptr); | |
| 804 } | |
| 805 | |
| 806 TEST_F(CryptoServerConfigsTest, AllConfigsInThePast) { | |
| 807 // Check that the most recent config is selected. | |
| 808 SetConfigs("a", 400, 1, | |
| 809 "b", 800, 1, | |
| 810 "c", 1200, 1, | |
| 811 nullptr); | |
| 812 test_peer_.SelectNewPrimaryConfig(1500); | |
| 813 test_peer_.CheckConfigs( | |
| 814 "a", false, | |
| 815 "b", false, | |
| 816 "c", true, | |
| 817 nullptr); | |
| 818 } | |
| 819 | |
| 820 TEST_F(CryptoServerConfigsTest, AllConfigsInTheFuture) { | |
| 821 // Check that the first config is selected. | |
| 822 SetConfigs("a", 400, 1, | |
| 823 "b", 800, 1, | |
| 824 "c", 1200, 1, | |
| 825 nullptr); | |
| 826 test_peer_.SelectNewPrimaryConfig(100); | |
| 827 test_peer_.CheckConfigs( | |
| 828 "a", true, | |
| 829 "b", false, | |
| 830 "c", false, | |
| 831 nullptr); | |
| 832 } | |
| 833 | |
| 834 TEST_F(CryptoServerConfigsTest, SortByPriority) { | |
| 835 // Check that priority is used to decide on a primary config when | |
| 836 // configs have the same primary time. | |
| 837 SetConfigs("a", 900, 1, | |
| 838 "b", 900, 2, | |
| 839 "c", 900, 3, | |
| 840 nullptr); | |
| 841 test_peer_.CheckConfigs( | |
| 842 "a", true, | |
| 843 "b", false, | |
| 844 "c", false, | |
| 845 nullptr); | |
| 846 test_peer_.SelectNewPrimaryConfig(800); | |
| 847 test_peer_.CheckConfigs( | |
| 848 "a", true, | |
| 849 "b", false, | |
| 850 "c", false, | |
| 851 nullptr); | |
| 852 test_peer_.SelectNewPrimaryConfig(1000); | |
| 853 test_peer_.CheckConfigs( | |
| 854 "a", true, | |
| 855 "b", false, | |
| 856 "c", false, | |
| 857 nullptr); | |
| 858 | |
| 859 // Change priorities and expect sort order to change. | |
| 860 SetConfigs("a", 900, 2, | |
| 861 "b", 900, 1, | |
| 862 "c", 900, 0, | |
| 863 nullptr); | |
| 864 test_peer_.CheckConfigs( | |
| 865 "a", false, | |
| 866 "b", false, | |
| 867 "c", true, | |
| 868 nullptr); | |
| 869 test_peer_.SelectNewPrimaryConfig(800); | |
| 870 test_peer_.CheckConfigs( | |
| 871 "a", false, | |
| 872 "b", false, | |
| 873 "c", true, | |
| 874 nullptr); | |
| 875 test_peer_.SelectNewPrimaryConfig(1000); | |
| 876 test_peer_.CheckConfigs( | |
| 877 "a", false, | |
| 878 "b", false, | |
| 879 "c", true, | |
| 880 nullptr); | |
| 881 } | |
| 882 | |
| 883 TEST_F(CryptoServerConfigsTest, AdvancePrimary) { | |
| 884 // Check that a new primary config is enabled at the right time. | |
| 885 SetConfigs("a", 900, 1, | |
| 886 "b", 1100, 1, | |
| 887 nullptr); | |
| 888 test_peer_.SelectNewPrimaryConfig(1000); | |
| 889 test_peer_.CheckConfigs( | |
| 890 "a", true, | |
| 891 "b", false, | |
| 892 nullptr); | |
| 893 test_peer_.SelectNewPrimaryConfig(1101); | |
| 894 test_peer_.CheckConfigs( | |
| 895 "a", false, | |
| 896 "b", true, | |
| 897 nullptr); | |
| 898 } | |
| 899 | |
| 900 TEST_F(CryptoServerConfigsTest, InvalidConfigs) { | |
| 901 // Ensure that invalid configs don't change anything. | |
| 902 SetConfigs("a", 800, 1, | |
| 903 "b", 900, 1, | |
| 904 "c", 1100, 1, | |
| 905 nullptr); | |
| 906 test_peer_.CheckConfigs( | |
| 907 "a", false, | |
| 908 "b", true, | |
| 909 "c", false, | |
| 910 nullptr); | |
| 911 SetConfigs("a", 800, 1, | |
| 912 "c", 1100, 1, | |
| 913 "INVALID1", 1000, 1, | |
| 914 nullptr); | |
| 915 test_peer_.CheckConfigs( | |
| 916 "a", false, | |
| 917 "b", true, | |
| 918 "c", false, | |
| 919 nullptr); | |
| 920 } | |
| 921 | |
| 922 } // namespace test | |
| 923 } // namespace net | |
| OLD | NEW |