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_client_stream.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
      9 #include "net/quic/crypto/quic_decrypter.h"
     10 #include "net/quic/crypto/quic_encrypter.h"
     11 #include "net/quic/quic_protocol.h"
     12 #include "net/quic/test_tools/crypto_test_utils.h"
     13 #include "net/quic/test_tools/quic_test_utils.h"
     14 #include "net/quic/test_tools/simple_quic_framer.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace net {
     19 namespace test {
     20 namespace {
     21 
     22 const char kServerHostname[] = "example.com";
     23 
     24 class TestQuicVisitor : public NoOpFramerVisitor {
     25  public:
     26   TestQuicVisitor()
     27       : frame_valid_(false) {
     28   }
     29 
     30   // NoOpFramerVisitor
     31   virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
     32     frame_ = frame;
     33     frame_valid_ = true;
     34     return true;
     35   }
     36 
     37   bool frame_valid() const {
     38     return frame_valid_;
     39   }
     40   QuicStreamFrame* frame() { return &frame_; }
     41 
     42  private:
     43   QuicStreamFrame frame_;
     44   bool frame_valid_;
     45 
     46   DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor);
     47 };
     48 
     49 class QuicCryptoClientStreamTest : public ::testing::Test {
     50  public:
     51   QuicCryptoClientStreamTest()
     52       : addr_(),
     53         connection_(new PacketSavingConnection(1, addr_, true)),
     54         session_(new TestSession(connection_, DefaultQuicConfig(), true)),
     55         stream_(new QuicCryptoClientStream(kServerHostname, session_.get(),
     56                                            &crypto_config_)) {
     57     session_->SetCryptoStream(stream_.get());
     58     crypto_config_.SetDefaults();
     59   }
     60 
     61   void CompleteCryptoHandshake() {
     62     EXPECT_TRUE(stream_->CryptoConnect());
     63     CryptoTestUtils::HandshakeWithFakeServer(connection_, stream_.get());
     64   }
     65 
     66   void ConstructHandshakeMessage() {
     67     CryptoFramer framer;
     68     message_data_.reset(framer.ConstructHandshakeMessage(message_));
     69   }
     70 
     71   IPEndPoint addr_;
     72   PacketSavingConnection* connection_;
     73   scoped_ptr<TestSession> session_;
     74   scoped_ptr<QuicCryptoClientStream> stream_;
     75   CryptoHandshakeMessage message_;
     76   scoped_ptr<QuicData> message_data_;
     77   QuicCryptoClientConfig crypto_config_;
     78 };
     79 
     80 TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
     81   if (!Aes128Gcm12Encrypter::IsSupported()) {
     82     LOG(INFO) << "AES GCM not supported. Test skipped.";
     83     return;
     84   }
     85 
     86   EXPECT_FALSE(stream_->encryption_established());
     87   EXPECT_FALSE(stream_->handshake_confirmed());
     88 }
     89 
     90 TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
     91   if (!Aes128Gcm12Encrypter::IsSupported()) {
     92     LOG(INFO) << "AES GCM not supported. Test skipped.";
     93     return;
     94   }
     95 
     96   CompleteCryptoHandshake();
     97   EXPECT_TRUE(stream_->encryption_established());
     98   EXPECT_TRUE(stream_->handshake_confirmed());
     99 }
    100 
    101 TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
    102   if (!Aes128Gcm12Encrypter::IsSupported()) {
    103     LOG(INFO) << "AES GCM not supported. Test skipped.";
    104     return;
    105   }
    106 
    107   CompleteCryptoHandshake();
    108 
    109   EXPECT_CALL(*connection_, SendConnectionClose(
    110       QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
    111   message_.set_tag(kCHLO);
    112   ConstructHandshakeMessage();
    113   stream_->ProcessData(message_data_->data(), message_data_->length());
    114 }
    115 
    116 TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
    117   if (!Aes128Gcm12Encrypter::IsSupported()) {
    118     LOG(INFO) << "AES GCM not supported. Test skipped.";
    119     return;
    120   }
    121 
    122   EXPECT_TRUE(stream_->CryptoConnect());
    123 
    124   message_.set_tag(kCHLO);
    125   ConstructHandshakeMessage();
    126 
    127   EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
    128         QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "Expected REJ"));
    129   stream_->ProcessData(message_data_->data(), message_data_->length());
    130 }
    131 
    132 TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
    133   if (!Aes128Gcm12Encrypter::IsSupported()) {
    134     LOG(INFO) << "AES GCM not supported. Test skipped.";
    135     return;
    136   }
    137 
    138   CompleteCryptoHandshake();
    139 
    140   const QuicConfig* config = session_->config();
    141   EXPECT_EQ(kQBIC, config->congestion_control());
    142   EXPECT_EQ(kDefaultTimeoutSecs,
    143             config->idle_connection_state_lifetime().ToSeconds());
    144   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
    145             config->max_streams_per_connection());
    146   EXPECT_EQ(0, config->keepalive_timeout().ToSeconds());
    147 
    148   const QuicCryptoNegotiatedParameters& crypto_params(
    149       stream_->crypto_negotiated_params());
    150   EXPECT_EQ(kAESG, crypto_params.aead);
    151   EXPECT_EQ(kC255, crypto_params.key_exchange);
    152 }
    153 
    154 TEST_F(QuicCryptoClientStreamTest, InvalidHostname) {
    155   if (!Aes128Gcm12Encrypter::IsSupported()) {
    156     LOG(INFO) << "AES GCM not supported. Test skipped.";
    157     return;
    158   }
    159 
    160   stream_.reset(new QuicCryptoClientStream("invalid", session_.get(),
    161                                            &crypto_config_));
    162   session_->SetCryptoStream(stream_.get());
    163 
    164   CompleteCryptoHandshake();
    165   EXPECT_TRUE(stream_->encryption_established());
    166   EXPECT_TRUE(stream_->handshake_confirmed());
    167 }
    168 
    169 TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
    170   // Seed the config with a cached server config.
    171   CompleteCryptoHandshake();
    172 
    173   connection_ = new PacketSavingConnection(1, addr_, true);
    174   session_.reset(new TestSession(connection_, QuicConfig(), true));
    175   stream_.reset(new QuicCryptoClientStream(kServerHostname, session_.get(),
    176                                            &crypto_config_));
    177 
    178   session_->SetCryptoStream(stream_.get());
    179   session_->config()->SetDefaults();
    180 
    181   // Advance time 5 years to ensure that we pass the expiry time of the cached
    182   // server config.
    183   reinterpret_cast<MockClock*>(const_cast<QuicClock*>(connection_->clock()))
    184       ->AdvanceTime(QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
    185 
    186   // Check that a client hello was sent and that CryptoConnect doesn't fail
    187   // with an error.
    188   EXPECT_TRUE(stream_->CryptoConnect());
    189   ASSERT_EQ(1u, connection_->packets_.size());
    190 }
    191 
    192 }  // namespace
    193 }  // namespace test
    194 }  // namespace net
    195