| OLD | NEW |
| (Empty) |
| 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_utils.h" | |
| 16 #include "net/quic/crypto/quic_crypto_server_config.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/delayed_verify_strike_register_client.h" | |
| 25 #include "net/quic/test_tools/quic_test_utils.h" | |
| 26 #include "testing/gmock/include/gmock/gmock.h" | |
| 27 #include "testing/gtest/include/gtest/gtest.h" | |
| 28 | |
| 29 namespace net { | |
| 30 class QuicConnection; | |
| 31 class ReliableQuicStream; | |
| 32 } // namespace net | |
| 33 | |
| 34 using std::pair; | |
| 35 using std::string; | |
| 36 using testing::_; | |
| 37 | |
| 38 namespace net { | |
| 39 namespace test { | |
| 40 | |
| 41 class QuicCryptoServerConfigPeer { | |
| 42 public: | |
| 43 static string GetPrimaryOrbit(const QuicCryptoServerConfig& config) { | |
| 44 base::AutoLock lock(config.configs_lock_); | |
| 45 CHECK(config.primary_config_.get() != nullptr); | |
| 46 return string(reinterpret_cast<const char*>(config.primary_config_->orbit), | |
| 47 kOrbitSize); | |
| 48 } | |
| 49 }; | |
| 50 | |
| 51 namespace { | |
| 52 | |
| 53 const char kServerHostname[] = "test.example.com"; | |
| 54 const uint16 kServerPort = 80; | |
| 55 | |
| 56 class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> { | |
| 57 public: | |
| 58 QuicCryptoServerStreamTest() | |
| 59 : connection_(new PacketSavingConnection(/*is_server=*/true)), | |
| 60 session_(connection_, DefaultQuicConfig()), | |
| 61 crypto_config_(QuicCryptoServerConfig::TESTING, | |
| 62 QuicRandom::GetInstance()), | |
| 63 stream_(crypto_config_, &session_), | |
| 64 strike_register_client_(nullptr) { | |
| 65 session_.SetCryptoStream(&stream_); | |
| 66 // We advance the clock initially because the default time is zero and the | |
| 67 // strike register worries that we've just overflowed a uint32 time. | |
| 68 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); | |
| 69 // TODO(wtc): replace this with ProofSourceForTesting() when Chromium has | |
| 70 // a working ProofSourceForTesting(). | |
| 71 crypto_config_.SetProofSource(CryptoTestUtils::FakeProofSourceForTesting()); | |
| 72 crypto_config_.set_strike_register_no_startup_period(); | |
| 73 | |
| 74 CryptoTestUtils::SetupCryptoServerConfigForTest( | |
| 75 connection_->clock(), connection_->random_generator(), | |
| 76 session_.config(), &crypto_config_); | |
| 77 | |
| 78 if (AsyncStrikeRegisterVerification()) { | |
| 79 string orbit = | |
| 80 QuicCryptoServerConfigPeer::GetPrimaryOrbit(crypto_config_); | |
| 81 strike_register_client_ = new DelayedVerifyStrikeRegisterClient( | |
| 82 10000, // strike_register_max_entries | |
| 83 static_cast<uint32>(connection_->clock()->WallNow().ToUNIXSeconds()), | |
| 84 60, // strike_register_window_secs | |
| 85 reinterpret_cast<const uint8 *>(orbit.data()), | |
| 86 StrikeRegister::NO_STARTUP_PERIOD_NEEDED); | |
| 87 strike_register_client_->StartDelayingVerification(); | |
| 88 crypto_config_.SetStrikeRegisterClient(strike_register_client_); | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 bool AsyncStrikeRegisterVerification() { | |
| 93 return GetParam(); | |
| 94 } | |
| 95 | |
| 96 void ConstructHandshakeMessage() { | |
| 97 CryptoFramer framer; | |
| 98 message_data_.reset(framer.ConstructHandshakeMessage(message_)); | |
| 99 } | |
| 100 | |
| 101 int CompleteCryptoHandshake() { | |
| 102 return CryptoTestUtils::HandshakeWithFakeClient(connection_, &stream_, | |
| 103 client_options_); | |
| 104 } | |
| 105 | |
| 106 protected: | |
| 107 PacketSavingConnection* connection_; | |
| 108 TestClientSession session_; | |
| 109 QuicConfig config_; | |
| 110 QuicCryptoServerConfig crypto_config_; | |
| 111 QuicCryptoServerStream stream_; | |
| 112 CryptoHandshakeMessage message_; | |
| 113 scoped_ptr<QuicData> message_data_; | |
| 114 CryptoTestUtils::FakeClientOptions client_options_; | |
| 115 DelayedVerifyStrikeRegisterClient* strike_register_client_; | |
| 116 }; | |
| 117 | |
| 118 INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool()); | |
| 119 | |
| 120 TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) { | |
| 121 EXPECT_FALSE(stream_.encryption_established()); | |
| 122 EXPECT_FALSE(stream_.handshake_confirmed()); | |
| 123 } | |
| 124 | |
| 125 TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { | |
| 126 // CompleteCryptoHandshake returns the number of client hellos sent. This | |
| 127 // test should send: | |
| 128 // * One to get a source-address token and certificates. | |
| 129 // * One to complete the handshake. | |
| 130 EXPECT_EQ(2, CompleteCryptoHandshake()); | |
| 131 EXPECT_TRUE(stream_.encryption_established()); | |
| 132 EXPECT_TRUE(stream_.handshake_confirmed()); | |
| 133 } | |
| 134 | |
| 135 TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { | |
| 136 PacketSavingConnection* client_conn = | |
| 137 new PacketSavingConnection(/*is_server=*/false); | |
| 138 PacketSavingConnection* server_conn = | |
| 139 new PacketSavingConnection(/*is_server=*/true); | |
| 140 client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); | |
| 141 server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); | |
| 142 | |
| 143 QuicConfig client_config; | |
| 144 scoped_ptr<TestClientSession> client_session( | |
| 145 new TestClientSession(client_conn, client_config)); | |
| 146 QuicCryptoClientConfig client_crypto_config; | |
| 147 | |
| 148 QuicServerId server_id(kServerHostname, kServerPort, false, | |
| 149 PRIVACY_MODE_DISABLED); | |
| 150 scoped_ptr<QuicCryptoClientStream> client(new QuicCryptoClientStream( | |
| 151 server_id, client_session.get(), nullptr, &client_crypto_config)); | |
| 152 client_session->SetCryptoStream(client.get()); | |
| 153 | |
| 154 // Do a first handshake in order to prime the client config with the server's | |
| 155 // information. | |
| 156 client->CryptoConnect(); | |
| 157 CHECK_EQ(1u, client_conn->encrypted_packets_.size()); | |
| 158 | |
| 159 scoped_ptr<TestSession> server_session(new TestSession(server_conn, config_)); | |
| 160 scoped_ptr<QuicCryptoServerStream> server( | |
| 161 new QuicCryptoServerStream(crypto_config_, server_session.get())); | |
| 162 server_session->SetCryptoStream(server.get()); | |
| 163 | |
| 164 CryptoTestUtils::CommunicateHandshakeMessages( | |
| 165 client_conn, client.get(), server_conn, server.get()); | |
| 166 EXPECT_EQ(2, client->num_sent_client_hellos()); | |
| 167 | |
| 168 // Now do another handshake, hopefully in 0-RTT. | |
| 169 LOG(INFO) << "Resetting for 0-RTT handshake attempt"; | |
| 170 | |
| 171 client_conn = new PacketSavingConnection(/*is_server=*/false); | |
| 172 server_conn = new PacketSavingConnection(/*is_server=*/true); | |
| 173 // We need to advance time past the strike-server window so that it's | |
| 174 // authoritative in this time span. | |
| 175 client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000)); | |
| 176 server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000)); | |
| 177 | |
| 178 // This causes the client's nonce to be different and thus stops the | |
| 179 // strike-register from rejecting the repeated nonce. | |
| 180 reinterpret_cast<MockRandom*>(client_conn->random_generator())->ChangeValue(); | |
| 181 client_session.reset(new TestClientSession(client_conn, client_config)); | |
| 182 server_session.reset(new TestSession(server_conn, config_)); | |
| 183 client.reset(new QuicCryptoClientStream(server_id, client_session.get(), | |
| 184 nullptr, &client_crypto_config)); | |
| 185 client_session->SetCryptoStream(client.get()); | |
| 186 | |
| 187 server.reset(new QuicCryptoServerStream(crypto_config_, | |
| 188 server_session.get())); | |
| 189 server_session->SetCryptoStream(server.get()); | |
| 190 | |
| 191 client->CryptoConnect(); | |
| 192 | |
| 193 if (AsyncStrikeRegisterVerification()) { | |
| 194 EXPECT_FALSE(client->handshake_confirmed()); | |
| 195 EXPECT_FALSE(server->handshake_confirmed()); | |
| 196 | |
| 197 // Advance the handshake. Expect that the server will be stuck | |
| 198 // waiting for client nonce verification to complete. | |
| 199 pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake( | |
| 200 client_conn, client.get(), 0, server_conn, server.get(), 0); | |
| 201 EXPECT_EQ(1u, messages_moved.first); | |
| 202 EXPECT_EQ(0u, messages_moved.second); | |
| 203 EXPECT_EQ(1, strike_register_client_->PendingVerifications()); | |
| 204 EXPECT_FALSE(client->handshake_confirmed()); | |
| 205 EXPECT_FALSE(server->handshake_confirmed()); | |
| 206 | |
| 207 // The server handshake completes once the nonce verification completes. | |
| 208 strike_register_client_->RunPendingVerifications(); | |
| 209 EXPECT_FALSE(client->handshake_confirmed()); | |
| 210 EXPECT_TRUE(server->handshake_confirmed()); | |
| 211 | |
| 212 messages_moved = CryptoTestUtils::AdvanceHandshake( | |
| 213 client_conn, client.get(), messages_moved.first, | |
| 214 server_conn, server.get(), messages_moved.second); | |
| 215 EXPECT_EQ(1u, messages_moved.first); | |
| 216 EXPECT_EQ(1u, messages_moved.second); | |
| 217 EXPECT_TRUE(client->handshake_confirmed()); | |
| 218 EXPECT_TRUE(server->handshake_confirmed()); | |
| 219 } else { | |
| 220 CryptoTestUtils::CommunicateHandshakeMessages( | |
| 221 client_conn, client.get(), server_conn, server.get()); | |
| 222 } | |
| 223 | |
| 224 EXPECT_EQ(1, client->num_sent_client_hellos()); | |
| 225 } | |
| 226 | |
| 227 TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) { | |
| 228 CompleteCryptoHandshake(); | |
| 229 EXPECT_CALL(*connection_, SendConnectionClose( | |
| 230 QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); | |
| 231 message_.set_tag(kCHLO); | |
| 232 ConstructHandshakeMessage(); | |
| 233 stream_.ProcessRawData(message_data_->data(), message_data_->length()); | |
| 234 } | |
| 235 | |
| 236 TEST_P(QuicCryptoServerStreamTest, BadMessageType) { | |
| 237 message_.set_tag(kSHLO); | |
| 238 ConstructHandshakeMessage(); | |
| 239 EXPECT_CALL(*connection_, SendConnectionClose( | |
| 240 QUIC_INVALID_CRYPTO_MESSAGE_TYPE)); | |
| 241 stream_.ProcessRawData(message_data_->data(), message_data_->length()); | |
| 242 } | |
| 243 | |
| 244 TEST_P(QuicCryptoServerStreamTest, WithoutCertificates) { | |
| 245 crypto_config_.SetProofSource(nullptr); | |
| 246 client_options_.dont_verify_certs = true; | |
| 247 | |
| 248 // Only 2 client hellos need to be sent in the no-certs case: one to get the | |
| 249 // source-address token and the second to finish. | |
| 250 EXPECT_EQ(2, CompleteCryptoHandshake()); | |
| 251 EXPECT_TRUE(stream_.encryption_established()); | |
| 252 EXPECT_TRUE(stream_.handshake_confirmed()); | |
| 253 } | |
| 254 | |
| 255 TEST_P(QuicCryptoServerStreamTest, ChannelID) { | |
| 256 client_options_.channel_id_enabled = true; | |
| 257 client_options_.channel_id_source_async = false; | |
| 258 // CompleteCryptoHandshake verifies | |
| 259 // stream_.crypto_negotiated_params().channel_id is correct. | |
| 260 EXPECT_EQ(2, CompleteCryptoHandshake()); | |
| 261 EXPECT_TRUE(stream_.encryption_established()); | |
| 262 EXPECT_TRUE(stream_.handshake_confirmed()); | |
| 263 } | |
| 264 | |
| 265 TEST_P(QuicCryptoServerStreamTest, ChannelIDAsync) { | |
| 266 client_options_.channel_id_enabled = true; | |
| 267 client_options_.channel_id_source_async = true; | |
| 268 // CompleteCryptoHandshake verifies | |
| 269 // stream_.crypto_negotiated_params().channel_id is correct. | |
| 270 EXPECT_EQ(2, CompleteCryptoHandshake()); | |
| 271 EXPECT_TRUE(stream_.encryption_established()); | |
| 272 EXPECT_TRUE(stream_.handshake_confirmed()); | |
| 273 } | |
| 274 | |
| 275 TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) { | |
| 276 // An attempt to send a SCUP before completing handshake should fail. | |
| 277 stream_.SendServerConfigUpdate(nullptr); | |
| 278 EXPECT_EQ(0, stream_.num_server_config_update_messages_sent()); | |
| 279 } | |
| 280 | |
| 281 } // namespace | |
| 282 } // namespace test | |
| 283 } // namespace net | |
| OLD | NEW |