/* * Copyright 2024 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include #include #include "api/candidate.h" #include "api/crypto/crypto_options.h" #include "api/scoped_refptr.h" #include "api/test/rtc_error_matchers.h" #include "api/units/time_delta.h" #include "p2p/base/basic_packet_socket_factory.h" #include "p2p/base/ice_transport_internal.h" #include "p2p/base/p2p_transport_channel.h" #include "p2p/base/port_allocator.h" #include "p2p/base/transport_description.h" #include "p2p/client/basic_port_allocator.h" #include "p2p/dtls/dtls_transport.h" #include "rtc_base/fake_clock.h" #include "rtc_base/fake_network.h" #include "rtc_base/rtc_certificate.h" #include "rtc_base/socket_address.h" #include "rtc_base/ssl_fingerprint.h" #include "rtc_base/ssl_identity.h" #include "rtc_base/ssl_stream_adapter.h" #include "rtc_base/third_party/sigslot/sigslot.h" #include "rtc_base/thread.h" #include "rtc_base/virtual_socket_server.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/wait_until.h" namespace { constexpr int kDefaultTimeout = 10000; void SetRemoteFingerprintFromCert( cricket::DtlsTransport& transport, const rtc::scoped_refptr& cert) { std::unique_ptr fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert); transport.SetRemoteParameters( fingerprint->algorithm, reinterpret_cast(fingerprint->digest.data()), fingerprint->digest.size(), std::nullopt); } } // namespace namespace cricket { using ::testing::IsTrue; class DtlsIceIntegrationTest : public ::testing::TestWithParam< std::tuple>, public sigslot::has_slots<> { public: void CandidateC2S(IceTransportInternal*, const Candidate& c) { thread_.PostTask([this, c = c]() { server_ice_->AddRemoteCandidate(c); }); } void CandidateS2C(IceTransportInternal*, const Candidate& c) { thread_.PostTask([this, c = c]() { client_ice_->AddRemoteCandidate(c); }); } protected: DtlsIceIntegrationTest() : ss_(std::make_unique()), socket_factory_( std::make_unique(ss_.get())), thread_(ss_.get()), client_allocator_( std::make_unique(&network_manager_, socket_factory_.get())), server_allocator_( std::make_unique(&network_manager_, socket_factory_.get())), client_ice_( std::make_unique("client_transport", 0, client_allocator_.get())), server_ice_( std::make_unique("server_transport", 0, server_allocator_.get())), client_dtls_(client_ice_.get(), webrtc::CryptoOptions(), /*event_log=*/nullptr, std::get<2>(GetParam())), server_dtls_(server_ice_.get(), webrtc::CryptoOptions(), /*event_log=*/nullptr, std::get<2>(GetParam())), client_ice_parameters_("c_ufrag", "c_icepwd_something_something", false), server_ice_parameters_("s_ufrag", "s_icepwd_something_something", false), client_dtls_stun_piggyback_(std::get<0>(GetParam())), server_dtls_stun_piggyback_(std::get<1>(GetParam())) { // Setup ICE. client_ice_->SetIceParameters(client_ice_parameters_); client_ice_->SetRemoteIceParameters(server_ice_parameters_); client_ice_->SetIceRole(ICEROLE_CONTROLLING); client_ice_->SignalCandidateGathered.connect( this, &DtlsIceIntegrationTest::CandidateC2S); server_ice_->SetIceParameters(server_ice_parameters_); server_ice_->SetRemoteIceParameters(client_ice_parameters_); server_ice_->SetIceRole(ICEROLE_CONTROLLED); server_ice_->SignalCandidateGathered.connect( this, &DtlsIceIntegrationTest::CandidateS2C); // Setup DTLS. auto client_certificate = rtc::RTCCertificate::Create( rtc::SSLIdentity::Create("test", rtc::KT_DEFAULT)); client_dtls_.SetLocalCertificate(client_certificate); client_dtls_.SetDtlsRole(rtc::SSL_SERVER); auto server_certificate = rtc::RTCCertificate::Create( rtc::SSLIdentity::Create("test", rtc::KT_DEFAULT)); server_dtls_.SetLocalCertificate(server_certificate); server_dtls_.SetDtlsRole(rtc::SSL_CLIENT); SetRemoteFingerprintFromCert(server_dtls_, client_certificate); SetRemoteFingerprintFromCert(client_dtls_, server_certificate); // Setup the network. network_manager_.AddInterface(rtc::SocketAddress("192.168.1.1", 0)); client_allocator_->Initialize(); server_allocator_->Initialize(); } ~DtlsIceIntegrationTest() = default; rtc::FakeNetworkManager network_manager_; std::unique_ptr ss_; std::unique_ptr socket_factory_; rtc::AutoSocketServerThread thread_; std::unique_ptr client_allocator_; std::unique_ptr server_allocator_; std::unique_ptr client_ice_; std::unique_ptr server_ice_; DtlsTransport client_dtls_; DtlsTransport server_dtls_; IceParameters client_ice_parameters_; IceParameters server_ice_parameters_; bool client_dtls_stun_piggyback_; bool server_dtls_stun_piggyback_; rtc::ScopedFakeClock fake_clock_; }; TEST_P(DtlsIceIntegrationTest, SmokeTest) { cricket::IceConfig client_config; client_config.dtls_handshake_in_stun = client_dtls_stun_piggyback_; client_ice_->SetIceConfig(client_config); cricket::IceConfig server_config; server_config.dtls_handshake_in_stun = server_dtls_stun_piggyback_; server_ice_->SetIceConfig(server_config); client_ice_->MaybeStartGathering(); server_ice_->MaybeStartGathering(); // Note: this only reaches the pending piggybacking state. EXPECT_THAT( webrtc::WaitUntil( [&] { return client_dtls_.writable() && server_dtls_.writable(); }, IsTrue(), {.timeout = webrtc::TimeDelta::Millis(kDefaultTimeout), .clock = &fake_clock_}), webrtc::IsRtcOk()); EXPECT_EQ(client_ice_->IsDtlsPiggybackSupportedByPeer(), client_dtls_stun_piggyback_ && server_dtls_stun_piggyback_); EXPECT_EQ(server_ice_->IsDtlsPiggybackSupportedByPeer(), client_dtls_stun_piggyback_ && server_dtls_stun_piggyback_); } // Test cases are parametrized by // * client-piggybacking-enabled, // * server-piggybacking-enabled, // * maximum DTLS version to use. INSTANTIATE_TEST_SUITE_P( DtlsStunPiggybackingIntegrationTest, DtlsIceIntegrationTest, ::testing::Values( std::make_tuple(false, false, rtc::SSL_PROTOCOL_DTLS_12), std::make_tuple(true, false, rtc::SSL_PROTOCOL_DTLS_12), std::make_tuple(false, true, rtc::SSL_PROTOCOL_DTLS_12), std::make_tuple(true, true, rtc::SSL_PROTOCOL_DTLS_12), // Skip negative cases that are behaving similar for DTLS 1.3 std::make_tuple(true, true, rtc::SSL_PROTOCOL_DTLS_13))); } // namespace cricket