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_time.h" 17 #include "net/quic/test_tools/mock_clock.h" 18 #include "net/quic/test_tools/quic_test_utils.h" 19 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 using base::StringPiece; 23 using std::make_pair; 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( 54 string config_id, 55 IPEndPoint ip, 56 QuicRandom* rand, 57 QuicWallTime now) { 58 return server_config_->NewSourceAddressToken( 59 *GetConfig(config_id), ip, rand, now, NULL); 60 } 61 62 HandshakeFailureReason ValidateSourceAddressToken(string config_id, 63 StringPiece srct, 64 IPEndPoint ip, 65 QuicWallTime now) { 66 return server_config_->ValidateSourceAddressToken( 67 *GetConfig(config_id), srct, ip, now); 68 } 69 70 string NewServerNonce(QuicRandom* rand, QuicWallTime now) const { 71 return server_config_->NewServerNonce(rand, now); 72 } 73 74 HandshakeFailureReason ValidateServerNonce(StringPiece token, 75 QuicWallTime now) { 76 return server_config_->ValidateServerNonce(token, now); 77 } 78 79 base::Lock* GetStrikeRegisterClientLock() { 80 return &server_config_->strike_register_client_lock_; 81 } 82 83 // CheckConfigs compares the state of the Configs in |server_config_| to the 84 // description given as arguments. The arguments are given as NULL-terminated 85 // pairs. The first of each pair is the server config ID of a Config. The 86 // second is a boolean describing whether the config is the primary. For 87 // example: 88 // CheckConfigs(NULL); // checks that no Configs are loaded. 89 // 90 // // Checks that exactly three Configs are loaded with the given IDs and 91 // // status. 92 // CheckConfigs( 93 // "id1", false, 94 // "id2", true, 95 // "id3", false, 96 // NULL); 97 void CheckConfigs(const char* server_config_id1, ...) { 98 va_list ap; 99 va_start(ap, server_config_id1); 100 101 vector<pair<ServerConfigID, bool> > expected; 102 bool first = true; 103 for (;;) { 104 const char* server_config_id; 105 if (first) { 106 server_config_id = server_config_id1; 107 first = false; 108 } else { 109 server_config_id = va_arg(ap, const char*); 110 } 111 112 if (!server_config_id) { 113 break; 114 } 115 116 // varargs will promote the value to an int so we have to read that from 117 // the stack and cast down. 118 const bool is_primary = static_cast<bool>(va_arg(ap, int)); 119 expected.push_back(make_pair(server_config_id, is_primary)); 120 } 121 122 va_end(ap); 123 124 base::AutoLock locked(server_config_->configs_lock_); 125 126 ASSERT_EQ(expected.size(), server_config_->configs_.size()) 127 << ConfigsDebug(); 128 129 for (QuicCryptoServerConfig::ConfigMap::const_iterator 130 i = server_config_->configs_.begin(); 131 i != server_config_->configs_.end(); ++i) { 132 bool found = false; 133 for (vector<pair<ServerConfigID, bool> >::iterator j = expected.begin(); 134 j != expected.end(); ++j) { 135 if (i->first == j->first && i->second->is_primary == j->second) { 136 found = true; 137 j->first.clear(); 138 break; 139 } 140 } 141 142 ASSERT_TRUE(found) << "Failed to find match for " << i->first 143 << " in configs:\n" << ConfigsDebug(); 144 } 145 } 146 147 // ConfigsDebug returns a string that contains debugging information about 148 // the set of Configs loaded in |server_config_| and their status. 149 // ConfigsDebug() should be called after acquiring 150 // server_config_->configs_lock_. 151 string ConfigsDebug() { 152 if (server_config_->configs_.empty()) { 153 return "No Configs in QuicCryptoServerConfig"; 154 } 155 156 string s; 157 158 for (QuicCryptoServerConfig::ConfigMap::const_iterator 159 i = server_config_->configs_.begin(); 160 i != server_config_->configs_.end(); ++i) { 161 const scoped_refptr<QuicCryptoServerConfig::Config> config = i->second; 162 if (config->is_primary) { 163 s += "(primary) "; 164 } else { 165 s += " "; 166 } 167 s += config->id; 168 s += "\n"; 169 } 170 171 return s; 172 } 173 174 void SelectNewPrimaryConfig(int seconds) { 175 base::AutoLock locked(server_config_->configs_lock_); 176 server_config_->SelectNewPrimaryConfig( 177 QuicWallTime::FromUNIXSeconds(seconds)); 178 } 179 180 private: 181 const QuicCryptoServerConfig* server_config_; 182 }; 183 184 class TestStrikeRegisterClient : public StrikeRegisterClient { 185 public: 186 explicit TestStrikeRegisterClient(QuicCryptoServerConfig* config) 187 : config_(config), 188 is_known_orbit_called_(false) { 189 } 190 191 virtual bool IsKnownOrbit(StringPiece orbit) const OVERRIDE { 192 // Ensure that the strike register client lock is not held. 193 QuicCryptoServerConfigPeer peer(config_); 194 base::Lock* m = peer.GetStrikeRegisterClientLock(); 195 // In Chromium, we will dead lock if the lock is held by the current thread. 196 // Chromium doesn't have AssertNotHeld API call. 197 // m->AssertNotHeld(); 198 base::AutoLock lock(*m); 199 200 is_known_orbit_called_ = true; 201 return true; 202 } 203 204 virtual void VerifyNonceIsValidAndUnique( 205 StringPiece nonce, 206 QuicWallTime now, 207 ResultCallback* cb) OVERRIDE { 208 LOG(FATAL) << "Not implemented"; 209 } 210 211 bool is_known_orbit_called() { return is_known_orbit_called_; } 212 213 private: 214 QuicCryptoServerConfig* config_; 215 mutable bool is_known_orbit_called_; 216 }; 217 218 TEST(QuicCryptoServerConfigTest, ServerConfig) { 219 QuicRandom* rand = QuicRandom::GetInstance(); 220 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand); 221 MockClock clock; 222 223 scoped_ptr<CryptoHandshakeMessage>( 224 server.AddDefaultConfig(rand, &clock, 225 QuicCryptoServerConfig::ConfigOptions())); 226 } 227 228 TEST(QuicCryptoServerConfigTest, GetOrbitIsCalledWithoutTheStrikeRegisterLock) { 229 QuicRandom* rand = QuicRandom::GetInstance(); 230 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand); 231 MockClock clock; 232 233 TestStrikeRegisterClient* strike_register = 234 new TestStrikeRegisterClient(&server); 235 server.SetStrikeRegisterClient(strike_register); 236 237 QuicCryptoServerConfig::ConfigOptions options; 238 scoped_ptr<CryptoHandshakeMessage>( 239 server.AddDefaultConfig(rand, &clock, options)); 240 EXPECT_TRUE(strike_register->is_known_orbit_called()); 241 } 242 243 TEST(QuicCryptoServerConfigTest, SourceAddressTokens) { 244 const string kPrimary = "<primary>"; 245 const string kOverride = "Config with custom source address token key"; 246 247 MockClock clock; 248 clock.AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); 249 250 QuicWallTime now = clock.WallNow(); 251 const QuicWallTime original_time = now; 252 253 QuicRandom* rand = QuicRandom::GetInstance(); 254 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand); 255 QuicCryptoServerConfigPeer peer(&server); 256 257 scoped_ptr<CryptoHandshakeMessage>( 258 server.AddDefaultConfig(rand, &clock, 259 QuicCryptoServerConfig::ConfigOptions())); 260 261 // Add a config that overrides the default boxer. 262 QuicCryptoServerConfig::ConfigOptions options; 263 options.id = kOverride; 264 scoped_ptr<QuicServerConfigProtobuf> protobuf( 265 QuicCryptoServerConfig::GenerateConfig(rand, &clock, options)); 266 protobuf->set_source_address_token_secret_override("a secret key"); 267 // Lower priority than the default config. 268 protobuf->set_priority(1); 269 scoped_ptr<CryptoHandshakeMessage>( 270 server.AddConfig(protobuf.get(), now)); 271 272 EXPECT_TRUE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kPrimary)); 273 EXPECT_FALSE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kOverride)); 274 275 IPEndPoint ip4 = IPEndPoint(Loopback4(), 1); 276 IPEndPoint ip4d = IPEndPoint(ConvertIPv4NumberToIPv6Number(ip4.address()), 1); 277 IPEndPoint ip6 = IPEndPoint(Loopback6(), 2); 278 279 // Primary config generates configs that validate successfully. 280 const string token4 = peer.NewSourceAddressToken(kPrimary, ip4, rand, now); 281 const string token4d = peer.NewSourceAddressToken(kPrimary, ip4d, rand, now); 282 const string token6 = peer.NewSourceAddressToken(kPrimary, ip6, rand, now); 283 EXPECT_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken( 284 kPrimary, token4, ip4, now)); 285 DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken( 286 kPrimary, token4, ip4d, now)); 287 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, 288 peer.ValidateSourceAddressToken(kPrimary, token4, ip6, now)); 289 DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken( 290 kPrimary, token4d, ip4, now)); 291 DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken( 292 kPrimary, token4d, ip4d, now)); 293 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, 294 peer.ValidateSourceAddressToken(kPrimary, token4d, ip6, now)); 295 DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken( 296 kPrimary, token6, ip6, now)); 297 298 // Override config generates configs that validate successfully. 299 const string override_token4 = peer.NewSourceAddressToken( 300 kOverride, ip4, rand, now); 301 const string override_token6 = peer.NewSourceAddressToken( 302 kOverride, ip6, rand, now); 303 DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken( 304 kOverride, override_token4, ip4, now)); 305 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, 306 peer.ValidateSourceAddressToken(kOverride, override_token4, ip6, 307 now)); 308 DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken( 309 kOverride, override_token6, ip6, now)); 310 311 // Tokens generated by the primary config do not validate 312 // successfully against the override config, and vice versa. 313 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, 314 peer.ValidateSourceAddressToken(kOverride, token4, ip4, now)); 315 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, 316 peer.ValidateSourceAddressToken(kOverride, token6, ip6, now)); 317 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, 318 peer.ValidateSourceAddressToken(kPrimary, override_token4, ip4, 319 now)); 320 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, 321 peer.ValidateSourceAddressToken(kPrimary, override_token6, ip6, 322 now)); 323 324 // Validation fails after tokens expire. 325 now = original_time.Add(QuicTime::Delta::FromSeconds(86400 * 7)); 326 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE, 327 peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now)); 328 329 now = original_time.Subtract(QuicTime::Delta::FromSeconds(3600 * 2)); 330 DCHECK_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE, 331 peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now)); 332 } 333 334 TEST(QuicCryptoServerConfigTest, ValidateServerNonce) { 335 QuicRandom* rand = QuicRandom::GetInstance(); 336 QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand); 337 QuicCryptoServerConfigPeer peer(&server); 338 339 StringPiece message("hello world"); 340 const size_t key_size = CryptoSecretBoxer::GetKeySize(); 341 scoped_ptr<uint8[]> key(new uint8[key_size]); 342 memset(key.get(), 0x11, key_size); 343 344 CryptoSecretBoxer boxer; 345 boxer.SetKey(StringPiece(reinterpret_cast<char*>(key.get()), key_size)); 346 const string box = boxer.Box(rand, message); 347 MockClock clock; 348 QuicWallTime now = clock.WallNow(); 349 const QuicWallTime original_time = now; 350 EXPECT_EQ(SERVER_NONCE_DECRYPTION_FAILURE, 351 peer.ValidateServerNonce(box, now)); 352 353 string server_nonce = peer.NewServerNonce(rand, now); 354 EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now)); 355 EXPECT_EQ(SERVER_NONCE_NOT_UNIQUE_FAILURE, 356 peer.ValidateServerNonce(server_nonce, now)); 357 358 now = original_time.Add(QuicTime::Delta::FromSeconds(1000 * 7)); 359 server_nonce = peer.NewServerNonce(rand, now); 360 EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now)); 361 } 362 363 class CryptoServerConfigsTest : public ::testing::Test { 364 public: 365 CryptoServerConfigsTest() 366 : rand_(QuicRandom::GetInstance()), 367 config_(QuicCryptoServerConfig::TESTING, rand_), 368 test_peer_(&config_) {} 369 370 virtual void SetUp() { 371 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000)); 372 } 373 374 // SetConfigs constructs suitable config protobufs and calls SetConfigs on 375 // |config_|. The arguments are given as NULL-terminated pairs. The first of 376 // each pair is the server config ID of a Config. The second is the 377 // |primary_time| of that Config, given in epoch seconds. (Although note 378 // that, in these tests, time is set to 1000 seconds since the epoch.) For 379 // example: 380 // SetConfigs(NULL); // calls |config_.SetConfigs| with no protobufs. 381 // 382 // // Calls |config_.SetConfigs| with two protobufs: one for a Config with 383 // // a |primary_time| of 900 and priority 1, and another with 384 // // a |primary_time| of 1000 and priority 2. 385 386 // CheckConfigs( 387 // "id1", 900, 1, 388 // "id2", 1000, 2, 389 // NULL); 390 // 391 // If the server config id starts with "INVALID" then the generated protobuf 392 // will be invalid. 393 void SetConfigs(const char* server_config_id1, ...) { 394 const char kOrbit[] = "12345678"; 395 396 va_list ap; 397 va_start(ap, server_config_id1); 398 bool has_invalid = false; 399 bool is_empty = true; 400 401 vector<QuicServerConfigProtobuf*> protobufs; 402 bool first = true; 403 for (;;) { 404 const char* server_config_id; 405 if (first) { 406 server_config_id = server_config_id1; 407 first = false; 408 } else { 409 server_config_id = va_arg(ap, const char*); 410 } 411 412 if (!server_config_id) { 413 break; 414 } 415 416 is_empty = false; 417 int primary_time = va_arg(ap, int); 418 int priority = va_arg(ap, int); 419 420 QuicCryptoServerConfig::ConfigOptions options; 421 options.id = server_config_id; 422 options.orbit = kOrbit; 423 QuicServerConfigProtobuf* protobuf( 424 QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options)); 425 protobuf->set_primary_time(primary_time); 426 protobuf->set_priority(priority); 427 if (string(server_config_id).find("INVALID") == 0) { 428 protobuf->clear_key(); 429 has_invalid = true; 430 } 431 protobufs.push_back(protobuf); 432 } 433 434 ASSERT_EQ(!has_invalid && !is_empty, 435 config_.SetConfigs(protobufs, clock_.WallNow())); 436 STLDeleteElements(&protobufs); 437 } 438 439 protected: 440 QuicRandom* const rand_; 441 MockClock clock_; 442 QuicCryptoServerConfig config_; 443 QuicCryptoServerConfigPeer test_peer_; 444 }; 445 446 TEST_F(CryptoServerConfigsTest, NoConfigs) { 447 test_peer_.CheckConfigs(NULL); 448 } 449 450 TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) { 451 // Make sure that "b" is primary even though "a" comes first. 452 SetConfigs("a", 1100, 1, 453 "b", 900, 1, 454 NULL); 455 test_peer_.CheckConfigs( 456 "a", false, 457 "b", true, 458 NULL); 459 } 460 461 TEST_F(CryptoServerConfigsTest, MakePrimarySecond) { 462 // Make sure that a remains primary after b is added. 463 SetConfigs("a", 900, 1, 464 "b", 1100, 1, 465 NULL); 466 test_peer_.CheckConfigs( 467 "a", true, 468 "b", false, 469 NULL); 470 } 471 472 TEST_F(CryptoServerConfigsTest, Delete) { 473 // Ensure that configs get deleted when removed. 474 SetConfigs("a", 800, 1, 475 "b", 900, 1, 476 "c", 1100, 1, 477 NULL); 478 test_peer_.CheckConfigs( 479 "a", false, 480 "b", true, 481 "c", false, 482 NULL); 483 SetConfigs("b", 900, 1, 484 "c", 1100, 1, 485 NULL); 486 test_peer_.CheckConfigs( 487 "b", true, 488 "c", false, 489 NULL); 490 } 491 492 TEST_F(CryptoServerConfigsTest, DeletePrimary) { 493 // Ensure that deleting the primary config works. 494 SetConfigs("a", 800, 1, 495 "b", 900, 1, 496 "c", 1100, 1, 497 NULL); 498 test_peer_.CheckConfigs( 499 "a", false, 500 "b", true, 501 "c", false, 502 NULL); 503 SetConfigs("a", 800, 1, 504 "c", 1100, 1, 505 NULL); 506 test_peer_.CheckConfigs( 507 "a", true, 508 "c", false, 509 NULL); 510 } 511 512 TEST_F(CryptoServerConfigsTest, FailIfDeletingAllConfigs) { 513 // Ensure that configs get deleted when removed. 514 SetConfigs("a", 800, 1, 515 "b", 900, 1, 516 NULL); 517 test_peer_.CheckConfigs( 518 "a", false, 519 "b", true, 520 NULL); 521 SetConfigs(NULL); 522 // Config change is rejected, still using old configs. 523 test_peer_.CheckConfigs( 524 "a", false, 525 "b", true, 526 NULL); 527 } 528 529 TEST_F(CryptoServerConfigsTest, ChangePrimaryTime) { 530 // Check that updates to primary time get picked up. 531 SetConfigs("a", 400, 1, 532 "b", 800, 1, 533 "c", 1200, 1, 534 NULL); 535 test_peer_.SelectNewPrimaryConfig(500); 536 test_peer_.CheckConfigs( 537 "a", true, 538 "b", false, 539 "c", false, 540 NULL); 541 SetConfigs("a", 1200, 1, 542 "b", 800, 1, 543 "c", 400, 1, 544 NULL); 545 test_peer_.SelectNewPrimaryConfig(500); 546 test_peer_.CheckConfigs( 547 "a", false, 548 "b", false, 549 "c", true, 550 NULL); 551 } 552 553 TEST_F(CryptoServerConfigsTest, AllConfigsInThePast) { 554 // Check that the most recent config is selected. 555 SetConfigs("a", 400, 1, 556 "b", 800, 1, 557 "c", 1200, 1, 558 NULL); 559 test_peer_.SelectNewPrimaryConfig(1500); 560 test_peer_.CheckConfigs( 561 "a", false, 562 "b", false, 563 "c", true, 564 NULL); 565 } 566 567 TEST_F(CryptoServerConfigsTest, AllConfigsInTheFuture) { 568 // Check that the first config is selected. 569 SetConfigs("a", 400, 1, 570 "b", 800, 1, 571 "c", 1200, 1, 572 NULL); 573 test_peer_.SelectNewPrimaryConfig(100); 574 test_peer_.CheckConfigs( 575 "a", true, 576 "b", false, 577 "c", false, 578 NULL); 579 } 580 581 TEST_F(CryptoServerConfigsTest, SortByPriority) { 582 // Check that priority is used to decide on a primary config when 583 // configs have the same primary time. 584 SetConfigs("a", 900, 1, 585 "b", 900, 2, 586 "c", 900, 3, 587 NULL); 588 test_peer_.CheckConfigs( 589 "a", true, 590 "b", false, 591 "c", false, 592 NULL); 593 test_peer_.SelectNewPrimaryConfig(800); 594 test_peer_.CheckConfigs( 595 "a", true, 596 "b", false, 597 "c", false, 598 NULL); 599 test_peer_.SelectNewPrimaryConfig(1000); 600 test_peer_.CheckConfigs( 601 "a", true, 602 "b", false, 603 "c", false, 604 NULL); 605 606 // Change priorities and expect sort order to change. 607 SetConfigs("a", 900, 2, 608 "b", 900, 1, 609 "c", 900, 0, 610 NULL); 611 test_peer_.CheckConfigs( 612 "a", false, 613 "b", false, 614 "c", true, 615 NULL); 616 test_peer_.SelectNewPrimaryConfig(800); 617 test_peer_.CheckConfigs( 618 "a", false, 619 "b", false, 620 "c", true, 621 NULL); 622 test_peer_.SelectNewPrimaryConfig(1000); 623 test_peer_.CheckConfigs( 624 "a", false, 625 "b", false, 626 "c", true, 627 NULL); 628 } 629 630 TEST_F(CryptoServerConfigsTest, AdvancePrimary) { 631 // Check that a new primary config is enabled at the right time. 632 SetConfigs("a", 900, 1, 633 "b", 1100, 1, 634 NULL); 635 test_peer_.SelectNewPrimaryConfig(1000); 636 test_peer_.CheckConfigs( 637 "a", true, 638 "b", false, 639 NULL); 640 test_peer_.SelectNewPrimaryConfig(1101); 641 test_peer_.CheckConfigs( 642 "a", false, 643 "b", true, 644 NULL); 645 } 646 647 TEST_F(CryptoServerConfigsTest, InvalidConfigs) { 648 // Ensure that invalid configs don't change anything. 649 SetConfigs("a", 800, 1, 650 "b", 900, 1, 651 "c", 1100, 1, 652 NULL); 653 test_peer_.CheckConfigs( 654 "a", false, 655 "b", true, 656 "c", false, 657 NULL); 658 SetConfigs("a", 800, 1, 659 "c", 1100, 1, 660 "INVALID1", 1000, 1, 661 NULL); 662 test_peer_.CheckConfigs( 663 "a", false, 664 "b", true, 665 "c", false, 666 NULL); 667 } 668 669 } // namespace test 670 } // namespace net 671