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