Home | History | Annotate | Download | only in quic
      1 // Copyright (c) 2012 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/quic_crypto_server_stream.h"
      6 
      7 #include <map>
      8 #include <vector>
      9 
     10 #include "base/memory/scoped_ptr.h"
     11 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
     12 #include "net/quic/crypto/crypto_framer.h"
     13 #include "net/quic/crypto/crypto_handshake.h"
     14 #include "net/quic/crypto/crypto_protocol.h"
     15 #include "net/quic/crypto/crypto_server_config.h"
     16 #include "net/quic/crypto/crypto_utils.h"
     17 #include "net/quic/crypto/quic_decrypter.h"
     18 #include "net/quic/crypto/quic_encrypter.h"
     19 #include "net/quic/crypto/quic_random.h"
     20 #include "net/quic/quic_crypto_client_stream.h"
     21 #include "net/quic/quic_protocol.h"
     22 #include "net/quic/quic_session.h"
     23 #include "net/quic/test_tools/crypto_test_utils.h"
     24 #include "net/quic/test_tools/quic_test_utils.h"
     25 #include "testing/gmock/include/gmock/gmock.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 
     28 namespace net {
     29 class QuicConnection;
     30 class ReliableQuicStream;
     31 }  // namespace net
     32 
     33 using testing::_;
     34 
     35 namespace net {
     36 namespace test {
     37 namespace {
     38 
     39 // TODO(agl): Use rch's utility class for parsing a message when committed.
     40 class TestQuicVisitor : public NoOpFramerVisitor {
     41  public:
     42   TestQuicVisitor() {}
     43 
     44   // NoOpFramerVisitor
     45   virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
     46     frame_ = frame;
     47     return true;
     48   }
     49 
     50   QuicStreamFrame* frame() { return &frame_; }
     51 
     52  private:
     53   QuicStreamFrame frame_;
     54 
     55   DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor);
     56 };
     57 
     58 class QuicCryptoServerStreamTest : public ::testing::Test {
     59  public:
     60   QuicCryptoServerStreamTest()
     61       : guid_(1),
     62         addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ?
     63               ip_ : IPAddressNumber(), 1),
     64         connection_(new PacketSavingConnection(guid_, addr_, true)),
     65         session_(connection_, QuicConfig(), true),
     66         crypto_config_(QuicCryptoServerConfig::TESTING,
     67                        QuicRandom::GetInstance()),
     68         stream_(crypto_config_, &session_) {
     69     config_.SetDefaults();
     70     session_.config()->SetDefaults();
     71     session_.SetCryptoStream(&stream_);
     72     // We advance the clock initially because the default time is zero and the
     73     // strike register worries that we've just overflowed a uint32 time.
     74     connection_->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
     75     // TODO(rtenneti): Enable testing of ProofSource.
     76     // crypto_config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
     77 
     78     CryptoTestUtils::SetupCryptoServerConfigForTest(
     79         connection_->clock(), connection_->random_generator(),
     80         session_.config(), &crypto_config_);
     81   }
     82 
     83   void ConstructHandshakeMessage() {
     84     CryptoFramer framer;
     85     message_data_.reset(framer.ConstructHandshakeMessage(message_));
     86   }
     87 
     88   int CompleteCryptoHandshake() {
     89     return CryptoTestUtils::HandshakeWithFakeClient(connection_, &stream_,
     90                                                     client_options_);
     91   }
     92 
     93  protected:
     94   IPAddressNumber ip_;
     95   QuicGuid guid_;
     96   IPEndPoint addr_;
     97   PacketSavingConnection* connection_;
     98   TestSession session_;
     99   QuicConfig config_;
    100   QuicCryptoServerConfig crypto_config_;
    101   QuicCryptoServerStream stream_;
    102   CryptoHandshakeMessage message_;
    103   scoped_ptr<QuicData> message_data_;
    104   CryptoTestUtils::FakeClientOptions client_options_;
    105 };
    106 
    107 TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) {
    108   if (!Aes128Gcm12Encrypter::IsSupported()) {
    109     LOG(INFO) << "AES GCM not supported. Test skipped.";
    110     return;
    111   }
    112 
    113   EXPECT_FALSE(stream_.encryption_established());
    114   EXPECT_FALSE(stream_.handshake_confirmed());
    115 }
    116 
    117 TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
    118   if (!Aes128Gcm12Encrypter::IsSupported()) {
    119     LOG(INFO) << "AES GCM not supported. Test skipped.";
    120     return;
    121   }
    122 
    123   // CompleteCryptoHandshake returns the number of client hellos sent. This
    124   // test should send:
    125   //   * One to get a source-address token and certificates.
    126   //   * One to complete the handshake.
    127   EXPECT_EQ(2, CompleteCryptoHandshake());
    128   EXPECT_TRUE(stream_.encryption_established());
    129   EXPECT_TRUE(stream_.handshake_confirmed());
    130 }
    131 
    132 TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
    133   if (!Aes128Gcm12Encrypter::IsSupported()) {
    134     LOG(INFO) << "AES GCM not supported. Test skipped.";
    135     return;
    136   }
    137 
    138   QuicGuid guid(1);
    139   IPAddressNumber ip;
    140   ParseIPLiteralToNumber("127.0.0.1", &ip);
    141   IPEndPoint addr(ip, 0);
    142   PacketSavingConnection* client_conn =
    143       new PacketSavingConnection(guid, addr, false);
    144   PacketSavingConnection* server_conn =
    145       new PacketSavingConnection(guid, addr, false);
    146   client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
    147   server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
    148 
    149   QuicConfig client_config;
    150   client_config.SetDefaults();
    151   scoped_ptr<TestSession> client_session(
    152       new TestSession(client_conn, client_config, false));
    153   QuicCryptoClientConfig client_crypto_config;
    154   client_crypto_config.SetDefaults();
    155 
    156   scoped_ptr<QuicCryptoClientStream> client(new QuicCryptoClientStream(
    157         "test.example.com", client_session.get(), &client_crypto_config));
    158   client_session->SetCryptoStream(client.get());
    159 
    160   // Do a first handshake in order to prime the client config with the server's
    161   // information.
    162   CHECK(client->CryptoConnect());
    163   CHECK_EQ(1u, client_conn->packets_.size());
    164 
    165   scoped_ptr<TestSession> server_session(
    166       new TestSession(server_conn, config_, true));
    167   scoped_ptr<QuicCryptoServerStream> server(
    168       new QuicCryptoServerStream(crypto_config_, server_session.get()));
    169   server_session->SetCryptoStream(server.get());
    170 
    171   CryptoTestUtils::CommunicateHandshakeMessages(
    172       client_conn, client.get(), server_conn, server.get());
    173   EXPECT_EQ(2, client->num_sent_client_hellos());
    174 
    175   // Now do another handshake, hopefully in 0-RTT.
    176   LOG(INFO) << "Resetting for 0-RTT handshake attempt";
    177 
    178   client_conn = new PacketSavingConnection(guid, addr, false);
    179   server_conn = new PacketSavingConnection(guid, addr, false);
    180   // We need to advance time past the strike-server window so that it's
    181   // authoritative in this time span.
    182   client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000));
    183   server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000));
    184 
    185   // This causes the client's nonce to be different and thus stops the
    186   // strike-register from rejecting the repeated nonce.
    187   reinterpret_cast<MockRandom*>(client_conn->random_generator())->ChangeValue();
    188   client_session.reset(new TestSession(client_conn, client_config, false));
    189   server_session.reset(new TestSession(server_conn, config_, true));
    190   client.reset(new QuicCryptoClientStream(
    191         "test.example.com", client_session.get(), &client_crypto_config));
    192   client_session->SetCryptoStream(client.get());
    193 
    194   server.reset(new QuicCryptoServerStream(crypto_config_,
    195                                           server_session.get()));
    196   server_session->SetCryptoStream(server.get());
    197 
    198   CHECK(client->CryptoConnect());
    199 
    200   CryptoTestUtils::CommunicateHandshakeMessages(
    201       client_conn, client.get(), server_conn, server.get());
    202   EXPECT_EQ(1, client->num_sent_client_hellos());
    203 }
    204 
    205 TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) {
    206   if (!Aes128Gcm12Encrypter::IsSupported()) {
    207     LOG(INFO) << "AES GCM not supported. Test skipped.";
    208     return;
    209   }
    210 
    211   CompleteCryptoHandshake();
    212   EXPECT_CALL(*connection_, SendConnectionClose(
    213       QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
    214   message_.set_tag(kCHLO);
    215   ConstructHandshakeMessage();
    216   stream_.ProcessData(message_data_->data(), message_data_->length());
    217 }
    218 
    219 TEST_F(QuicCryptoServerStreamTest, BadMessageType) {
    220   if (!Aes128Gcm12Encrypter::IsSupported()) {
    221     LOG(INFO) << "AES GCM not supported. Test skipped.";
    222     return;
    223   }
    224 
    225   message_.set_tag(kSHLO);
    226   ConstructHandshakeMessage();
    227   EXPECT_CALL(*connection_, SendConnectionClose(
    228       QUIC_INVALID_CRYPTO_MESSAGE_TYPE));
    229   stream_.ProcessData(message_data_->data(), message_data_->length());
    230 }
    231 
    232 TEST_F(QuicCryptoServerStreamTest, WithoutCertificates) {
    233   if (!Aes128Gcm12Encrypter::IsSupported()) {
    234     LOG(INFO) << "AES GCM not supported. Test skipped.";
    235     return;
    236   }
    237 
    238   crypto_config_.SetProofSource(NULL);
    239   client_options_.dont_verify_certs = true;
    240 
    241   // Only 2 client hellos need to be sent in the no-certs case: one to get the
    242   // source-address token and the second to finish.
    243   EXPECT_EQ(2, CompleteCryptoHandshake());
    244   EXPECT_TRUE(stream_.encryption_established());
    245   EXPECT_TRUE(stream_.handshake_confirmed());
    246 }
    247 
    248 TEST_F(QuicCryptoServerStreamTest, ChannelID) {
    249   if (!Aes128Gcm12Encrypter::IsSupported()) {
    250     LOG(INFO) << "AES GCM not supported. Test skipped.";
    251     return;
    252   }
    253 
    254   client_options_.channel_id_enabled = true;
    255   // TODO(rtenneti): Enable testing of ProofVerifier.
    256   // CompleteCryptoHandshake verifies
    257   // stream_.crypto_negotiated_params().channel_id is correct.
    258   EXPECT_EQ(2, CompleteCryptoHandshake());
    259   EXPECT_TRUE(stream_.encryption_established());
    260   EXPECT_TRUE(stream_.handshake_confirmed());
    261 }
    262 
    263 }  // namespace
    264 }  // namespace test
    265 }  // namespace net
    266