Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 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/crypto_handshake.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_server_config.h"
     12 #include "net/quic/crypto/crypto_server_config_protobuf.h"
     13 #include "net/quic/crypto/quic_random.h"
     14 #include "net/quic/quic_time.h"
     15 #include "net/quic/test_tools/mock_clock.h"
     16 #include "testing/gmock/include/gmock/gmock.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 using base::StringPiece;
     20 using std::make_pair;
     21 using std::map;
     22 using std::pair;
     23 using std::string;
     24 using std::vector;
     25 
     26 namespace net {
     27 namespace test {
     28 
     29 class QuicCryptoServerConfigPeer {
     30  public:
     31   explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config)
     32       : server_config_(server_config) {}
     33 
     34   string NewSourceAddressToken(IPEndPoint ip,
     35                                QuicRandom* rand,
     36                                QuicWallTime now) {
     37     return server_config_->NewSourceAddressToken(ip, rand, now);
     38   }
     39 
     40   bool ValidateSourceAddressToken(StringPiece srct,
     41                                   IPEndPoint ip,
     42                                   QuicWallTime now) {
     43     return server_config_->ValidateSourceAddressToken(srct, ip, now);
     44   }
     45 
     46   // CheckConfigs compares the state of the Configs in |server_config_| to the
     47   // description given as arguments. The arguments are given as NULL-terminated
     48   // pairs. The first of each pair is the server config ID of a Config. The
     49   // second is a boolean describing whether the config is the primary. For
     50   // example:
     51   //   CheckConfigs(NULL);  // checks that no Configs are loaded.
     52   //
     53   //   // Checks that exactly three Configs are loaded with the given IDs and
     54   //   // status.
     55   //   CheckConfigs(
     56   //     "id1", false,
     57   //     "id2", true,
     58   //     "id3", false,
     59   //     NULL);
     60   void CheckConfigs(const char* server_config_id1, ...) {
     61     va_list ap;
     62     va_start(ap, server_config_id1);
     63 
     64     vector<pair<ServerConfigID, bool> > expected;
     65     bool first = true;
     66     for (;;) {
     67       const char* server_config_id;
     68       if (first) {
     69         server_config_id = server_config_id1;
     70         first = false;
     71       } else {
     72         server_config_id = va_arg(ap, const char*);
     73       }
     74 
     75       if (!server_config_id) {
     76         break;
     77       }
     78 
     79       // varargs will promote the value to an int so we have to read that from
     80       // the stack and cast down.
     81       const bool is_primary = static_cast<bool>(va_arg(ap, int));
     82       expected.push_back(make_pair(server_config_id, is_primary));
     83     }
     84 
     85     va_end(ap);
     86 
     87     base::AutoLock locked(server_config_->configs_lock_);
     88 
     89     ASSERT_EQ(expected.size(), server_config_->configs_.size())
     90         << ConfigsDebug();
     91 
     92     for (QuicCryptoServerConfig::ConfigMap::const_iterator
     93              i = server_config_->configs_.begin();
     94          i != server_config_->configs_.end(); ++i) {
     95       bool found = false;
     96       for (vector<pair<ServerConfigID, bool> >::iterator j = expected.begin();
     97            j != expected.end(); ++j) {
     98         if (i->first == j->first && i->second->is_primary == j->second) {
     99           found = true;
    100           j->first.clear();
    101           break;
    102         }
    103       }
    104 
    105       ASSERT_TRUE(found) << "Failed to find match for " << i->first
    106                          << " in configs:\n" << ConfigsDebug();
    107     }
    108   }
    109 
    110   // ConfigsDebug returns a string that contains debugging information about
    111   // the set of Configs loaded in |server_config_| and their status.
    112   // ConfigsDebug() should be called after acquiring
    113   // server_config_->configs_lock_.
    114   string ConfigsDebug() {
    115     if (server_config_->configs_.empty()) {
    116       return "No Configs in QuicCryptoServerConfig";
    117     }
    118 
    119     string s;
    120 
    121     for (QuicCryptoServerConfig::ConfigMap::const_iterator
    122              i = server_config_->configs_.begin();
    123          i != server_config_->configs_.end(); ++i) {
    124       const scoped_refptr<QuicCryptoServerConfig::Config> config = i->second;
    125       if (config->is_primary) {
    126         s += "(primary) ";
    127       } else {
    128         s += "          ";
    129       }
    130       s += config->id;
    131       s += "\n";
    132     }
    133 
    134     return s;
    135   }
    136 
    137   void SelectNewPrimaryConfig(int seconds) {
    138     base::AutoLock locked(server_config_->configs_lock_);
    139     server_config_->SelectNewPrimaryConfig(
    140         QuicWallTime::FromUNIXSeconds(seconds));
    141   }
    142 
    143  private:
    144   const QuicCryptoServerConfig* server_config_;
    145 };
    146 
    147 TEST(QuicCryptoServerConfigTest, ServerConfig) {
    148   QuicRandom* rand = QuicRandom::GetInstance();
    149   QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand);
    150   MockClock clock;
    151 
    152   scoped_ptr<CryptoHandshakeMessage>(
    153       server.AddDefaultConfig(rand, &clock,
    154                               QuicCryptoServerConfig::ConfigOptions()));
    155 }
    156 
    157 TEST(QuicCryptoServerConfigTest, SourceAddressTokens) {
    158   if (!Aes128Gcm12Encrypter::IsSupported()) {
    159     LOG(INFO) << "AES GCM not supported. Test skipped.";
    160     return;
    161   }
    162 
    163   QuicRandom* rand = QuicRandom::GetInstance();
    164   QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand);
    165   IPAddressNumber ip;
    166   CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
    167   IPEndPoint ip4 = IPEndPoint(ip, 1);
    168   CHECK(ParseIPLiteralToNumber("2001:db8:0::42", &ip));
    169   IPEndPoint ip6 = IPEndPoint(ip, 2);
    170   MockClock clock;
    171   clock.AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
    172   QuicCryptoServerConfigPeer peer(&server);
    173 
    174   QuicWallTime now = clock.WallNow();
    175   const QuicWallTime original_time = now;
    176 
    177   const string token4 = peer.NewSourceAddressToken(ip4, rand, now);
    178   const string token6 = peer.NewSourceAddressToken(ip6, rand, now);
    179   EXPECT_TRUE(peer.ValidateSourceAddressToken(token4, ip4, now));
    180   EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip6, now));
    181   EXPECT_TRUE(peer.ValidateSourceAddressToken(token6, ip6, now));
    182 
    183   now = original_time.Add(QuicTime::Delta::FromSeconds(86400 * 7));
    184   EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip4, now));
    185 
    186   now = original_time.Subtract(QuicTime::Delta::FromSeconds(3600 * 2));
    187   EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip4, now));
    188 }
    189 
    190 class CryptoServerConfigsTest : public ::testing::Test {
    191  public:
    192   CryptoServerConfigsTest()
    193       : rand_(QuicRandom::GetInstance()),
    194         config_(QuicCryptoServerConfig::TESTING, rand_),
    195         test_peer_(&config_) {}
    196 
    197   virtual void SetUp() {
    198     clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000));
    199   }
    200 
    201   // SetConfigs constructs suitable config protobufs and calls SetConfigs on
    202   // |config_|. The arguments are given as NULL-terminated pairs. The first of
    203   // each pair is the server config ID of a Config. The second is the
    204   // |primary_time| of that Config, given in epoch seconds. (Although note
    205   // that, in these tests, time is set to 1000 seconds since the epoch.) For
    206   // example:
    207   //   SetConfigs(NULL);  // calls |config_.SetConfigs| with no protobufs.
    208   //
    209   //   // Calls |config_.SetConfigs| with two protobufs: one for a Config with
    210   //   // a |primary_time| of 900, and another with a |primary_time| of 1000.
    211   //   CheckConfigs(
    212   //     "id1", 900,
    213   //     "id2", 1000,
    214   //     NULL);
    215   //
    216   // If the server config id starts with "INVALID" then the generated protobuf
    217   // will be invalid.
    218   void SetConfigs(const char* server_config_id1, ...) {
    219     va_list ap;
    220     va_start(ap, server_config_id1);
    221     bool has_invalid = false;
    222 
    223     vector<QuicServerConfigProtobuf*> protobufs;
    224     bool first = true;
    225     for (;;) {
    226       const char* server_config_id;
    227       if (first) {
    228         server_config_id = server_config_id1;
    229         first = false;
    230       } else {
    231         server_config_id = va_arg(ap, const char*);
    232       }
    233 
    234       if (!server_config_id) {
    235         break;
    236       }
    237 
    238       int primary_time = va_arg(ap, int);
    239 
    240       QuicCryptoServerConfig::ConfigOptions options;
    241       options.id = server_config_id;
    242       QuicServerConfigProtobuf* protobuf(
    243           QuicCryptoServerConfig::DefaultConfig(rand_, &clock_, options));
    244       protobuf->set_primary_time(primary_time);
    245       if (string(server_config_id).find("INVALID") == 0) {
    246         protobuf->clear_key();
    247         has_invalid = true;
    248       }
    249       protobufs.push_back(protobuf);
    250     }
    251 
    252     ASSERT_EQ(!has_invalid, config_.SetConfigs(protobufs, clock_.WallNow()));
    253     STLDeleteElements(&protobufs);
    254   }
    255 
    256  protected:
    257   QuicRandom* const rand_;
    258   MockClock clock_;
    259   QuicCryptoServerConfig config_;
    260   QuicCryptoServerConfigPeer test_peer_;
    261 };
    262 
    263 TEST_F(CryptoServerConfigsTest, NoConfigs) {
    264   test_peer_.CheckConfigs(NULL);
    265 }
    266 
    267 TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) {
    268   // Make sure that "b" is primary even though "a" comes first.
    269   SetConfigs("a", 1100,
    270              "b", 900,
    271              NULL);
    272   test_peer_.CheckConfigs(
    273       "a", false,
    274       "b", true,
    275       NULL);
    276 }
    277 
    278 TEST_F(CryptoServerConfigsTest, MakePrimarySecond) {
    279   // Make sure that a remains primary after b is added.
    280   SetConfigs("a", 900,
    281              "b", 1100,
    282              NULL);
    283   test_peer_.CheckConfigs(
    284       "a", true,
    285       "b", false,
    286       NULL);
    287 }
    288 
    289 TEST_F(CryptoServerConfigsTest, Delete) {
    290   // Ensure that configs get deleted when removed.
    291   SetConfigs("a", 800,
    292              "b", 900,
    293              "c", 1100,
    294              NULL);
    295   SetConfigs("b", 900,
    296              "c", 1100,
    297              NULL);
    298   test_peer_.CheckConfigs(
    299       "b", true,
    300       "c", false,
    301       NULL);
    302 }
    303 
    304 TEST_F(CryptoServerConfigsTest, DontDeletePrimary) {
    305   // Ensure that the primary config isn't deleted when removed.
    306   SetConfigs("a", 800,
    307              "b", 900,
    308              "c", 1100,
    309              NULL);
    310   SetConfigs("a", 800,
    311              "c", 1100,
    312              NULL);
    313   test_peer_.CheckConfigs(
    314       "a", false,
    315       "b", true,
    316       "c", false,
    317       NULL);
    318 }
    319 
    320 TEST_F(CryptoServerConfigsTest, AdvancePrimary) {
    321   // Check that a new primary config is enabled at the right time.
    322   SetConfigs("a", 900,
    323              "b", 1100,
    324              NULL);
    325   test_peer_.SelectNewPrimaryConfig(1000);
    326   test_peer_.CheckConfigs(
    327       "a", true,
    328       "b", false,
    329       NULL);
    330   test_peer_.SelectNewPrimaryConfig(1101);
    331   test_peer_.CheckConfigs(
    332       "a", false,
    333       "b", true,
    334       NULL);
    335 }
    336 
    337 TEST_F(CryptoServerConfigsTest, InvalidConfigs) {
    338   // Ensure that invalid configs don't change anything.
    339   SetConfigs("a", 800,
    340              "b", 900,
    341              "c", 1100,
    342              NULL);
    343   test_peer_.CheckConfigs(
    344       "a", false,
    345       "b", true,
    346       "c", false,
    347       NULL);
    348   SetConfigs("a", 800,
    349              "c", 1100,
    350              "INVALID1", 1000,
    351              NULL);
    352   test_peer_.CheckConfigs(
    353       "a", false,
    354       "b", true,
    355       "c", false,
    356       NULL);
    357 }
    358 
    359 }  // namespace test
    360 }  // namespace net
    361