Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 1 | // Copyright (c) 2019 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 | |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 5 | #include <memory> |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 6 | #include <utility> |
| 7 | |
| 8 | #include "absl/strings/string_view.h" |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 9 | #include "quiche/quic/core/io/quic_default_event_loop.h" |
| 10 | #include "quiche/quic/core/io/quic_event_loop.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 11 | #include "quiche/quic/core/proto/crypto_server_config_proto.h" |
| 12 | #include "quiche/quic/core/quic_alarm_factory.h" |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 13 | #include "quiche/quic/core/quic_default_clock.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 14 | #include "quiche/quic/platform/api/quic_expect_bug.h" |
| 15 | #include "quiche/quic/platform/api/quic_test.h" |
| 16 | #include "quiche/quic/platform/api/quic_test_loopback.h" |
| 17 | #include "quiche/quic/qbone/platform/icmp_packet.h" |
| 18 | #include "quiche/quic/qbone/qbone_client_session.h" |
| 19 | #include "quiche/quic/qbone/qbone_constants.h" |
| 20 | #include "quiche/quic/qbone/qbone_control_placeholder.pb.h" |
| 21 | #include "quiche/quic/qbone/qbone_packet_processor_test_tools.h" |
| 22 | #include "quiche/quic/qbone/qbone_server_session.h" |
| 23 | #include "quiche/quic/test_tools/crypto_test_utils.h" |
| 24 | #include "quiche/quic/test_tools/mock_clock.h" |
martinduke | 605dca2 | 2022-09-01 10:40:19 -0700 | [diff] [blame] | 25 | #include "quiche/quic/test_tools/mock_connection_id_generator.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 26 | #include "quiche/quic/test_tools/quic_connection_peer.h" |
| 27 | #include "quiche/quic/test_tools/quic_session_peer.h" |
| 28 | #include "quiche/quic/test_tools/quic_test_utils.h" |
vasilvv | 3d87065 | 2023-06-05 09:29:16 -0700 | [diff] [blame] | 29 | #include "quiche/common/quiche_callbacks.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 30 | |
| 31 | namespace quic { |
| 32 | namespace test { |
| 33 | namespace { |
| 34 | |
| 35 | using ::testing::_; |
| 36 | using ::testing::Contains; |
| 37 | using ::testing::ElementsAre; |
| 38 | using ::testing::Eq; |
| 39 | using ::testing::Invoke; |
| 40 | using ::testing::NiceMock; |
| 41 | using ::testing::Not; |
| 42 | |
| 43 | std::string TestPacketIn(const std::string& body) { |
| 44 | return PrependIPv6HeaderForTest(body, 5); |
| 45 | } |
| 46 | |
| 47 | std::string TestPacketOut(const std::string& body) { |
| 48 | return PrependIPv6HeaderForTest(body, 4); |
| 49 | } |
| 50 | |
| 51 | ParsedQuicVersionVector GetTestParams() { |
fayang | 6a2c7aa | 2023-03-23 06:57:57 -0700 | [diff] [blame] | 52 | SetQuicReloadableFlag(quic_disable_version_q046, false); |
fayang | fc04b8a | 2023-05-18 09:26:25 -0700 | [diff] [blame] | 53 | return CurrentSupportedVersionsWithQuicCrypto(); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 54 | } |
| 55 | |
| 56 | // Used by QuicCryptoServerConfig to provide server credentials, passes |
| 57 | // everything through to ProofSourceForTesting if success is true, |
| 58 | // and fails otherwise. |
| 59 | class IndirectionProofSource : public ProofSource { |
| 60 | public: |
| 61 | explicit IndirectionProofSource(bool success) { |
| 62 | if (success) { |
| 63 | proof_source_ = crypto_test_utils::ProofSourceForTesting(); |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | // ProofSource override. |
| 68 | void GetProof(const QuicSocketAddress& server_address, |
| 69 | const QuicSocketAddress& client_address, |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 70 | const std::string& hostname, const std::string& server_config, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 71 | QuicTransportVersion transport_version, |
| 72 | absl::string_view chlo_hash, |
| 73 | std::unique_ptr<Callback> callback) override { |
| 74 | if (!proof_source_) { |
| 75 | QuicCryptoProof proof; |
| 76 | quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain = |
| 77 | GetCertChain(server_address, client_address, hostname, |
| 78 | &proof.cert_matched_sni); |
| 79 | callback->Run(/*ok=*/false, chain, proof, /*details=*/nullptr); |
| 80 | return; |
| 81 | } |
| 82 | proof_source_->GetProof(server_address, client_address, hostname, |
| 83 | server_config, transport_version, chlo_hash, |
| 84 | std::move(callback)); |
| 85 | } |
| 86 | |
| 87 | quiche::QuicheReferenceCountedPointer<Chain> GetCertChain( |
| 88 | const QuicSocketAddress& server_address, |
| 89 | const QuicSocketAddress& client_address, const std::string& hostname, |
| 90 | bool* cert_matched_sni) override { |
| 91 | if (!proof_source_) { |
| 92 | return quiche::QuicheReferenceCountedPointer<Chain>(); |
| 93 | } |
| 94 | return proof_source_->GetCertChain(server_address, client_address, hostname, |
| 95 | cert_matched_sni); |
| 96 | } |
| 97 | |
| 98 | void ComputeTlsSignature( |
| 99 | const QuicSocketAddress& server_address, |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 100 | const QuicSocketAddress& client_address, const std::string& hostname, |
| 101 | uint16_t signature_algorithm, absl::string_view in, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 102 | std::unique_ptr<SignatureCallback> callback) override { |
| 103 | if (!proof_source_) { |
| 104 | callback->Run(/*ok=*/true, "Signature", /*details=*/nullptr); |
| 105 | return; |
| 106 | } |
| 107 | proof_source_->ComputeTlsSignature(server_address, client_address, hostname, |
| 108 | signature_algorithm, in, |
| 109 | std::move(callback)); |
| 110 | } |
| 111 | |
| 112 | absl::InlinedVector<uint16_t, 8> SupportedTlsSignatureAlgorithms() |
| 113 | const override { |
| 114 | if (!proof_source_) { |
| 115 | return {}; |
| 116 | } |
| 117 | return proof_source_->SupportedTlsSignatureAlgorithms(); |
| 118 | } |
| 119 | |
| 120 | TicketCrypter* GetTicketCrypter() override { return nullptr; } |
| 121 | |
| 122 | private: |
| 123 | std::unique_ptr<ProofSource> proof_source_; |
| 124 | }; |
| 125 | |
| 126 | // Used by QuicCryptoClientConfig to verify server credentials, passes |
| 127 | // everything through to ProofVerifierForTesting is success is true, |
| 128 | // otherwise returns a canned response of QUIC_FAILURE. |
| 129 | class IndirectionProofVerifier : public ProofVerifier { |
| 130 | public: |
| 131 | explicit IndirectionProofVerifier(bool success) { |
| 132 | if (success) { |
| 133 | proof_verifier_ = crypto_test_utils::ProofVerifierForTesting(); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | // ProofVerifier override |
| 138 | QuicAsyncStatus VerifyProof( |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 139 | const std::string& hostname, const uint16_t port, |
| 140 | const std::string& server_config, QuicTransportVersion transport_version, |
| 141 | absl::string_view chlo_hash, const std::vector<std::string>& certs, |
| 142 | const std::string& cert_sct, const std::string& signature, |
| 143 | const ProofVerifyContext* context, std::string* error_details, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 144 | std::unique_ptr<ProofVerifyDetails>* verify_details, |
| 145 | std::unique_ptr<ProofVerifierCallback> callback) override { |
| 146 | if (!proof_verifier_) { |
| 147 | return QUIC_FAILURE; |
| 148 | } |
| 149 | return proof_verifier_->VerifyProof( |
| 150 | hostname, port, server_config, transport_version, chlo_hash, certs, |
| 151 | cert_sct, signature, context, error_details, verify_details, |
| 152 | std::move(callback)); |
| 153 | } |
| 154 | |
| 155 | QuicAsyncStatus VerifyCertChain( |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 156 | const std::string& hostname, const uint16_t port, |
| 157 | const std::vector<std::string>& certs, const std::string& ocsp_response, |
| 158 | const std::string& cert_sct, const ProofVerifyContext* context, |
| 159 | std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 160 | uint8_t* out_alert, |
| 161 | std::unique_ptr<ProofVerifierCallback> callback) override { |
| 162 | if (!proof_verifier_) { |
| 163 | return QUIC_FAILURE; |
| 164 | } |
| 165 | return proof_verifier_->VerifyCertChain( |
| 166 | hostname, port, certs, ocsp_response, cert_sct, context, error_details, |
| 167 | details, out_alert, std::move(callback)); |
| 168 | } |
| 169 | |
| 170 | std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { |
| 171 | if (!proof_verifier_) { |
| 172 | return nullptr; |
| 173 | } |
| 174 | return proof_verifier_->CreateDefaultContext(); |
| 175 | } |
| 176 | |
| 177 | private: |
| 178 | std::unique_ptr<ProofVerifier> proof_verifier_; |
| 179 | }; |
| 180 | |
| 181 | class DataSavingQbonePacketWriter : public QbonePacketWriter { |
| 182 | public: |
| 183 | void WritePacketToNetwork(const char* packet, size_t size) override { |
| 184 | data_.push_back(std::string(packet, size)); |
| 185 | } |
| 186 | |
| 187 | const std::vector<std::string>& data() { return data_; } |
| 188 | |
| 189 | private: |
| 190 | std::vector<std::string> data_; |
| 191 | }; |
| 192 | |
| 193 | template <class T> |
| 194 | class DataSavingQboneControlHandler : public QboneControlHandler<T> { |
| 195 | public: |
| 196 | void OnControlRequest(const T& request) override { data_.push_back(request); } |
| 197 | |
| 198 | void OnControlError() override { error_ = true; } |
| 199 | |
| 200 | const std::vector<T>& data() { return data_; } |
| 201 | bool error() { return error_; } |
| 202 | |
| 203 | private: |
| 204 | std::vector<T> data_; |
| 205 | bool error_ = false; |
| 206 | }; |
| 207 | |
| 208 | // Single-threaded scheduled task runner based on a MockClock. |
| 209 | // |
| 210 | // Simulates asynchronous execution on a single thread by holding scheduled |
| 211 | // tasks until Run() is called. Performs no synchronization, assumes that |
| 212 | // Schedule() and Run() are called on the same thread. |
| 213 | class FakeTaskRunner { |
| 214 | public: |
| 215 | explicit FakeTaskRunner(MockQuicConnectionHelper* helper) |
| 216 | : tasks_([](const TaskType& l, const TaskType& r) { |
| 217 | // Items at a later time should run after items at an earlier time. |
| 218 | // Priority queue comparisons should return true if l appears after r. |
| 219 | return l->time() > r->time(); |
| 220 | }), |
| 221 | helper_(helper) {} |
| 222 | |
| 223 | // Runs all tasks in time order. Executes tasks scheduled at |
| 224 | // the same in an arbitrary order. |
| 225 | void Run() { |
| 226 | while (!tasks_.empty()) { |
| 227 | tasks_.top()->Run(); |
| 228 | tasks_.pop(); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | private: |
| 233 | class InnerTask { |
| 234 | public: |
| 235 | InnerTask(std::function<void()> task, QuicTime time) |
| 236 | : task_(std::move(task)), time_(time) {} |
| 237 | |
| 238 | void Cancel() { cancelled_ = true; } |
| 239 | |
| 240 | void Run() { |
| 241 | if (!cancelled_) { |
vasilvv | 3d87065 | 2023-06-05 09:29:16 -0700 | [diff] [blame] | 242 | std::move(task_)(); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 243 | } |
| 244 | } |
| 245 | |
| 246 | QuicTime time() const { return time_; } |
| 247 | |
| 248 | private: |
| 249 | bool cancelled_ = false; |
vasilvv | 3d87065 | 2023-06-05 09:29:16 -0700 | [diff] [blame] | 250 | quiche::SingleUseCallback<void()> task_; |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 251 | QuicTime time_; |
| 252 | }; |
| 253 | |
| 254 | public: |
| 255 | // Schedules a function to run immediately and advances the time. |
| 256 | void Schedule(std::function<void()> task) { |
| 257 | tasks_.push(std::shared_ptr<InnerTask>( |
| 258 | new InnerTask(std::move(task), helper_->GetClock()->Now()))); |
| 259 | helper_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
| 260 | } |
| 261 | |
| 262 | private: |
| 263 | using TaskType = std::shared_ptr<InnerTask>; |
vasilvv | 3d87065 | 2023-06-05 09:29:16 -0700 | [diff] [blame] | 264 | std::priority_queue< |
| 265 | TaskType, std::vector<TaskType>, |
| 266 | quiche::UnretainedCallback<bool(const TaskType&, const TaskType&)>> |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 267 | tasks_; |
| 268 | MockQuicConnectionHelper* helper_; |
| 269 | }; |
| 270 | |
| 271 | class QboneSessionTest : public QuicTestWithParam<ParsedQuicVersion> { |
| 272 | public: |
| 273 | QboneSessionTest() |
| 274 | : supported_versions_({GetParam()}), |
| 275 | runner_(&helper_), |
| 276 | compressed_certs_cache_(100) {} |
| 277 | |
| 278 | ~QboneSessionTest() override { |
| 279 | delete client_connection_; |
| 280 | delete server_connection_; |
| 281 | } |
| 282 | |
| 283 | const MockClock* GetClock() const { |
| 284 | return static_cast<const MockClock*>(helper_.GetClock()); |
| 285 | } |
| 286 | |
| 287 | // The parameters are used to control whether the handshake will success or |
| 288 | // not. |
| 289 | void CreateClientAndServerSessions(bool client_handshake_success = true, |
| 290 | bool server_handshake_success = true, |
| 291 | bool send_qbone_alpn = true) { |
| 292 | // Quic crashes if packets are sent at time 0, and the clock defaults to 0. |
| 293 | helper_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000)); |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 294 | event_loop_ = GetDefaultEventLoop()->Create(QuicDefaultClock::Get()); |
| 295 | alarm_factory_ = event_loop_->CreateAlarmFactory(); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 296 | client_writer_ = std::make_unique<DataSavingQbonePacketWriter>(); |
| 297 | server_writer_ = std::make_unique<DataSavingQbonePacketWriter>(); |
| 298 | client_handler_ = |
| 299 | std::make_unique<DataSavingQboneControlHandler<QboneClientRequest>>(); |
| 300 | server_handler_ = |
| 301 | std::make_unique<DataSavingQboneControlHandler<QboneServerRequest>>(); |
| 302 | QuicSocketAddress server_address(TestLoopback(), 0); |
| 303 | QuicSocketAddress client_address; |
| 304 | if (server_address.host().address_family() == IpAddressFamily::IP_V4) { |
| 305 | client_address = QuicSocketAddress(QuicIpAddress::Any4(), 0); |
| 306 | } else { |
| 307 | client_address = QuicSocketAddress(QuicIpAddress::Any6(), 0); |
| 308 | } |
| 309 | |
| 310 | { |
| 311 | client_connection_ = new QuicConnection( |
| 312 | TestConnectionId(), client_address, server_address, &helper_, |
| 313 | alarm_factory_.get(), new NiceMock<MockPacketWriter>(), true, |
martinduke | 605dca2 | 2022-09-01 10:40:19 -0700 | [diff] [blame] | 314 | Perspective::IS_CLIENT, supported_versions_, |
| 315 | connection_id_generator_); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 316 | client_connection_->SetSelfAddress(client_address); |
| 317 | QuicConfig config; |
| 318 | client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>( |
| 319 | std::make_unique<IndirectionProofVerifier>(client_handshake_success)); |
| 320 | if (send_qbone_alpn) { |
| 321 | client_crypto_config_->set_alpn("qbone"); |
| 322 | } |
| 323 | client_peer_ = std::make_unique<QboneClientSession>( |
| 324 | client_connection_, client_crypto_config_.get(), |
| 325 | /*owner=*/nullptr, config, supported_versions_, |
| 326 | QuicServerId("test.example.com", 1234, false), client_writer_.get(), |
| 327 | client_handler_.get()); |
| 328 | } |
| 329 | |
| 330 | { |
| 331 | server_connection_ = new QuicConnection( |
| 332 | TestConnectionId(), server_address, client_address, &helper_, |
| 333 | alarm_factory_.get(), new NiceMock<MockPacketWriter>(), true, |
martinduke | 605dca2 | 2022-09-01 10:40:19 -0700 | [diff] [blame] | 334 | Perspective::IS_SERVER, supported_versions_, |
| 335 | connection_id_generator_); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 336 | server_connection_->SetSelfAddress(server_address); |
| 337 | QuicConfig config; |
| 338 | server_crypto_config_ = std::make_unique<QuicCryptoServerConfig>( |
| 339 | QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), |
| 340 | std::make_unique<IndirectionProofSource>(server_handshake_success), |
| 341 | KeyExchangeSource::Default()); |
| 342 | QuicCryptoServerConfig::ConfigOptions options; |
| 343 | QuicServerConfigProtobuf primary_config = |
| 344 | server_crypto_config_->GenerateConfig(QuicRandom::GetInstance(), |
| 345 | GetClock(), options); |
| 346 | std::unique_ptr<CryptoHandshakeMessage> message( |
| 347 | server_crypto_config_->AddConfig(primary_config, |
| 348 | GetClock()->WallNow())); |
| 349 | |
| 350 | server_peer_ = std::make_unique<QboneServerSession>( |
| 351 | supported_versions_, server_connection_, nullptr, config, |
| 352 | server_crypto_config_.get(), &compressed_certs_cache_, |
| 353 | server_writer_.get(), TestLoopback6(), TestLoopback6(), 64, |
| 354 | server_handler_.get()); |
| 355 | } |
| 356 | |
| 357 | // Hook everything up! |
| 358 | MockPacketWriter* client_writer = static_cast<MockPacketWriter*>( |
| 359 | QuicConnectionPeer::GetWriter(client_peer_->connection())); |
martinduke | acfdb39 | 2023-05-23 15:23:55 -0700 | [diff] [blame] | 360 | ON_CALL(*client_writer, WritePacket(_, _, _, _, _, _)) |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 361 | .WillByDefault(Invoke([this](const char* buffer, size_t buf_len, |
| 362 | const QuicIpAddress& self_address, |
| 363 | const QuicSocketAddress& peer_address, |
martinduke | acfdb39 | 2023-05-23 15:23:55 -0700 | [diff] [blame] | 364 | PerPacketOptions* option, |
| 365 | const QuicPacketWriterParams& params) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 366 | char* copy = new char[1024 * 1024]; |
| 367 | memcpy(copy, buffer, buf_len); |
| 368 | runner_.Schedule([this, copy, buf_len] { |
| 369 | QuicReceivedPacket packet(copy, buf_len, GetClock()->Now()); |
| 370 | server_peer_->ProcessUdpPacket(server_connection_->self_address(), |
| 371 | client_connection_->self_address(), |
| 372 | packet); |
| 373 | delete[] copy; |
| 374 | }); |
| 375 | return WriteResult(WRITE_STATUS_OK, buf_len); |
| 376 | })); |
| 377 | MockPacketWriter* server_writer = static_cast<MockPacketWriter*>( |
| 378 | QuicConnectionPeer::GetWriter(server_peer_->connection())); |
martinduke | acfdb39 | 2023-05-23 15:23:55 -0700 | [diff] [blame] | 379 | ON_CALL(*server_writer, WritePacket(_, _, _, _, _, _)) |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 380 | .WillByDefault(Invoke([this](const char* buffer, size_t buf_len, |
| 381 | const QuicIpAddress& self_address, |
| 382 | const QuicSocketAddress& peer_address, |
martinduke | acfdb39 | 2023-05-23 15:23:55 -0700 | [diff] [blame] | 383 | PerPacketOptions* options, |
| 384 | const QuicPacketWriterParams& params) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 385 | char* copy = new char[1024 * 1024]; |
| 386 | memcpy(copy, buffer, buf_len); |
| 387 | runner_.Schedule([this, copy, buf_len] { |
| 388 | QuicReceivedPacket packet(copy, buf_len, GetClock()->Now()); |
| 389 | client_peer_->ProcessUdpPacket(client_connection_->self_address(), |
| 390 | server_connection_->self_address(), |
| 391 | packet); |
| 392 | delete[] copy; |
| 393 | }); |
| 394 | return WriteResult(WRITE_STATUS_OK, buf_len); |
| 395 | })); |
| 396 | } |
| 397 | |
| 398 | void StartHandshake() { |
| 399 | server_peer_->Initialize(); |
| 400 | client_peer_->Initialize(); |
| 401 | runner_.Run(); |
| 402 | } |
| 403 | |
| 404 | void ExpectICMPTooBigResponse(const std::vector<std::string>& written_packets, |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 405 | const int mtu, const std::string& packet) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 406 | auto* header = reinterpret_cast<const ip6_hdr*>(packet.data()); |
| 407 | icmp6_hdr icmp_header{}; |
| 408 | icmp_header.icmp6_type = ICMP6_PACKET_TOO_BIG; |
| 409 | icmp_header.icmp6_mtu = mtu; |
| 410 | |
| 411 | std::string expected; |
| 412 | CreateIcmpPacket(header->ip6_dst, header->ip6_src, icmp_header, packet, |
| 413 | [&expected](absl::string_view icmp_packet) { |
| 414 | expected = std::string(icmp_packet); |
| 415 | }); |
| 416 | |
| 417 | EXPECT_THAT(written_packets, Contains(expected)); |
| 418 | } |
| 419 | |
| 420 | // Test handshake establishment and sending/receiving of data for two |
| 421 | // directions. |
| 422 | void TestStreamConnection(bool use_messages) { |
| 423 | ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); |
| 424 | ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); |
| 425 | ASSERT_TRUE(server_peer_->IsEncryptionEstablished()); |
| 426 | ASSERT_TRUE(client_peer_->IsEncryptionEstablished()); |
| 427 | |
| 428 | // Create an outgoing stream from the client and say hello. |
| 429 | QUIC_LOG(INFO) << "Sending client -> server"; |
| 430 | client_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")); |
| 431 | client_peer_->ProcessPacketFromNetwork(TestPacketIn("world")); |
| 432 | runner_.Run(); |
| 433 | // The server should see the data, the client hasn't received |
| 434 | // anything yet. |
| 435 | EXPECT_THAT(server_writer_->data(), |
| 436 | ElementsAre(TestPacketOut("hello"), TestPacketOut("world"))); |
| 437 | EXPECT_TRUE(client_writer_->data().empty()); |
| 438 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 439 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 440 | |
| 441 | // Let's pretend some service responds. |
| 442 | QUIC_LOG(INFO) << "Sending server -> client"; |
| 443 | server_peer_->ProcessPacketFromNetwork(TestPacketIn("Hello Again")); |
| 444 | server_peer_->ProcessPacketFromNetwork(TestPacketIn("Again")); |
| 445 | runner_.Run(); |
| 446 | EXPECT_THAT(server_writer_->data(), |
| 447 | ElementsAre(TestPacketOut("hello"), TestPacketOut("world"))); |
| 448 | EXPECT_THAT( |
| 449 | client_writer_->data(), |
| 450 | ElementsAre(TestPacketOut("Hello Again"), TestPacketOut("Again"))); |
| 451 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 452 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 453 | |
| 454 | // Try to send long payloads that are larger than the QUIC MTU but |
| 455 | // smaller than the QBONE max size. |
| 456 | // This should trigger the non-ephemeral stream code path. |
| 457 | std::string long_data( |
| 458 | QboneConstants::kMaxQbonePacketBytes - sizeof(ip6_hdr) - 1, 'A'); |
| 459 | QUIC_LOG(INFO) << "Sending server -> client long data"; |
| 460 | server_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data)); |
| 461 | runner_.Run(); |
| 462 | if (use_messages) { |
| 463 | ExpectICMPTooBigResponse( |
| 464 | server_writer_->data(), |
| 465 | server_peer_->connection()->GetGuaranteedLargestMessagePayload(), |
| 466 | TestPacketOut(long_data)); |
| 467 | } else { |
| 468 | EXPECT_THAT(client_writer_->data(), Contains(TestPacketOut(long_data))); |
| 469 | } |
| 470 | EXPECT_THAT(server_writer_->data(), |
| 471 | Not(Contains(TestPacketOut(long_data)))); |
| 472 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 473 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 474 | |
| 475 | QUIC_LOG(INFO) << "Sending client -> server long data"; |
| 476 | client_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data)); |
| 477 | runner_.Run(); |
| 478 | if (use_messages) { |
| 479 | ExpectICMPTooBigResponse( |
| 480 | client_writer_->data(), |
| 481 | client_peer_->connection()->GetGuaranteedLargestMessagePayload(), |
| 482 | TestPacketIn(long_data)); |
| 483 | } else { |
| 484 | EXPECT_THAT(server_writer_->data(), Contains(TestPacketOut(long_data))); |
| 485 | } |
| 486 | EXPECT_FALSE(client_peer_->EarlyDataAccepted()); |
| 487 | EXPECT_FALSE(client_peer_->ReceivedInchoateReject()); |
| 488 | EXPECT_THAT(client_peer_->GetNumReceivedServerConfigUpdates(), Eq(0)); |
| 489 | |
| 490 | if (!use_messages) { |
| 491 | EXPECT_THAT(client_peer_->GetNumStreamedPackets(), Eq(1)); |
| 492 | EXPECT_THAT(server_peer_->GetNumStreamedPackets(), Eq(1)); |
| 493 | } |
| 494 | |
| 495 | if (use_messages) { |
| 496 | EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(0)); |
| 497 | EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(0)); |
| 498 | EXPECT_THAT(client_peer_->GetNumMessagePackets(), Eq(2)); |
| 499 | EXPECT_THAT(server_peer_->GetNumMessagePackets(), Eq(2)); |
| 500 | } else { |
| 501 | EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(2)); |
| 502 | EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(2)); |
| 503 | EXPECT_THAT(client_peer_->GetNumMessagePackets(), Eq(0)); |
| 504 | EXPECT_THAT(server_peer_->GetNumMessagePackets(), Eq(0)); |
| 505 | } |
| 506 | |
| 507 | // All streams are ephemeral and should be gone. |
| 508 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 509 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 510 | } |
| 511 | |
| 512 | // Test that client and server are not connected after handshake failure. |
| 513 | void TestDisconnectAfterFailedHandshake() { |
| 514 | EXPECT_FALSE(client_peer_->IsEncryptionEstablished()); |
| 515 | EXPECT_FALSE(client_peer_->OneRttKeysAvailable()); |
| 516 | |
| 517 | EXPECT_FALSE(server_peer_->IsEncryptionEstablished()); |
| 518 | EXPECT_FALSE(server_peer_->OneRttKeysAvailable()); |
| 519 | } |
| 520 | |
| 521 | protected: |
| 522 | const ParsedQuicVersionVector supported_versions_; |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 523 | std::unique_ptr<QuicEventLoop> event_loop_; |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 524 | std::unique_ptr<QuicAlarmFactory> alarm_factory_; |
| 525 | FakeTaskRunner runner_; |
| 526 | MockQuicConnectionHelper helper_; |
| 527 | QuicConnection* client_connection_; |
| 528 | QuicConnection* server_connection_; |
| 529 | QuicCompressedCertsCache compressed_certs_cache_; |
| 530 | |
| 531 | std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_; |
| 532 | std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_; |
| 533 | std::unique_ptr<DataSavingQbonePacketWriter> client_writer_; |
| 534 | std::unique_ptr<DataSavingQbonePacketWriter> server_writer_; |
| 535 | std::unique_ptr<DataSavingQboneControlHandler<QboneClientRequest>> |
| 536 | client_handler_; |
| 537 | std::unique_ptr<DataSavingQboneControlHandler<QboneServerRequest>> |
| 538 | server_handler_; |
| 539 | |
| 540 | std::unique_ptr<QboneServerSession> server_peer_; |
| 541 | std::unique_ptr<QboneClientSession> client_peer_; |
martinduke | 605dca2 | 2022-09-01 10:40:19 -0700 | [diff] [blame] | 542 | MockConnectionIdGenerator connection_id_generator_; |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 543 | }; |
| 544 | |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 545 | INSTANTIATE_TEST_SUITE_P(Tests, QboneSessionTest, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 546 | ::testing::ValuesIn(GetTestParams()), |
| 547 | ::testing::PrintToStringParamName()); |
| 548 | |
| 549 | TEST_P(QboneSessionTest, StreamConnection) { |
| 550 | CreateClientAndServerSessions(); |
| 551 | client_peer_->set_send_packets_as_messages(false); |
| 552 | server_peer_->set_send_packets_as_messages(false); |
| 553 | StartHandshake(); |
| 554 | TestStreamConnection(false); |
| 555 | } |
| 556 | |
| 557 | TEST_P(QboneSessionTest, Messages) { |
| 558 | CreateClientAndServerSessions(); |
| 559 | client_peer_->set_send_packets_as_messages(true); |
| 560 | server_peer_->set_send_packets_as_messages(true); |
| 561 | StartHandshake(); |
| 562 | TestStreamConnection(true); |
| 563 | } |
| 564 | |
| 565 | TEST_P(QboneSessionTest, ClientRejection) { |
| 566 | CreateClientAndServerSessions(false /*client_handshake_success*/, |
| 567 | true /*server_handshake_success*/, |
| 568 | true /*send_qbone_alpn*/); |
| 569 | StartHandshake(); |
| 570 | TestDisconnectAfterFailedHandshake(); |
| 571 | } |
| 572 | |
| 573 | TEST_P(QboneSessionTest, BadAlpn) { |
| 574 | CreateClientAndServerSessions(true /*client_handshake_success*/, |
| 575 | true /*server_handshake_success*/, |
| 576 | false /*send_qbone_alpn*/); |
| 577 | StartHandshake(); |
| 578 | TestDisconnectAfterFailedHandshake(); |
| 579 | } |
| 580 | |
| 581 | TEST_P(QboneSessionTest, ServerRejection) { |
| 582 | CreateClientAndServerSessions(true /*client_handshake_success*/, |
| 583 | false /*server_handshake_success*/, |
| 584 | true /*send_qbone_alpn*/); |
| 585 | StartHandshake(); |
| 586 | TestDisconnectAfterFailedHandshake(); |
| 587 | } |
| 588 | |
| 589 | // Test that data streams are not created before handshake. |
| 590 | TEST_P(QboneSessionTest, CannotCreateDataStreamBeforeHandshake) { |
| 591 | CreateClientAndServerSessions(); |
| 592 | EXPECT_QUIC_BUG(client_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")), |
| 593 | "Attempting to send packet before encryption established"); |
| 594 | EXPECT_QUIC_BUG(server_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")), |
| 595 | "Attempting to send packet before encryption established"); |
| 596 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 597 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 598 | } |
| 599 | |
| 600 | TEST_P(QboneSessionTest, ControlRequests) { |
| 601 | CreateClientAndServerSessions(); |
| 602 | StartHandshake(); |
| 603 | EXPECT_TRUE(client_handler_->data().empty()); |
| 604 | EXPECT_FALSE(client_handler_->error()); |
| 605 | EXPECT_TRUE(server_handler_->data().empty()); |
| 606 | EXPECT_FALSE(server_handler_->error()); |
| 607 | |
| 608 | QboneClientRequest client_request; |
| 609 | client_request.SetExtension(client_placeholder, "hello from the server"); |
| 610 | EXPECT_TRUE(server_peer_->SendClientRequest(client_request)); |
| 611 | runner_.Run(); |
| 612 | ASSERT_FALSE(client_handler_->data().empty()); |
| 613 | EXPECT_THAT(client_handler_->data()[0].GetExtension(client_placeholder), |
| 614 | Eq("hello from the server")); |
| 615 | EXPECT_FALSE(client_handler_->error()); |
| 616 | |
| 617 | QboneServerRequest server_request; |
| 618 | server_request.SetExtension(server_placeholder, "hello from the client"); |
| 619 | EXPECT_TRUE(client_peer_->SendServerRequest(server_request)); |
| 620 | runner_.Run(); |
| 621 | ASSERT_FALSE(server_handler_->data().empty()); |
| 622 | EXPECT_THAT(server_handler_->data()[0].GetExtension(server_placeholder), |
| 623 | Eq("hello from the client")); |
| 624 | EXPECT_FALSE(server_handler_->error()); |
| 625 | } |
| 626 | |
| 627 | } // namespace |
| 628 | } // namespace test |
| 629 | } // namespace quic |