/* * Copyright 2018 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.
*/
// Create a new JsepTransport with a FakeDtlsTransport and a // FakeIceTransport.
std::unique_ptr<JsepTransport> CreateJsepTransport2(bool rtcp_mux_enabled) { auto ice_internal = std::make_unique<FakeIceTransport>(
kTransportName, ICE_CANDIDATE_COMPONENT_RTP); auto rtp_dtls_transport =
std::make_unique<FakeDtlsTransport>(ice_internal.get()); auto ice = CreateIceTransport(std::move(ice_internal));
std::unique_ptr<FakeIceTransport> rtcp_ice_internal;
std::unique_ptr<FakeDtlsTransport> rtcp_dtls_transport; if (!rtcp_mux_enabled) {
rtcp_ice_internal = std::make_unique<FakeIceTransport>(
kTransportName, ICE_CANDIDATE_COMPONENT_RTCP);
rtcp_dtls_transport =
std::make_unique<FakeDtlsTransport>(rtcp_ice_internal.get());
} auto rtcp_ice = CreateIceTransport(std::move(rtcp_ice_internal));
rtc::AutoThread main_thread_;
std::unique_ptr<JsepTransport> jsep_transport_; bool signal_rtcp_mux_active_received_ = false; // The SrtpTransport is owned by `jsep_transport_`. Keep a raw pointer here // for testing.
webrtc::SrtpTransport* sdes_transport_ = nullptr;
// The parameterized tests cover both cases when RTCP mux is enable and // disabled. class JsepTransport2WithRtcpMux : public JsepTransport2Test, public ::testing::WithParamInterface<bool> {};
// This test verifies the ICE parameters are properly applied to the transports.
TEST_P(JsepTransport2WithRtcpMux, SetIceParameters) { bool rtcp_mux_enabled = GetParam();
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
// Verify that SSL role and remote fingerprint were set correctly based on // transport descriptions. auto role = jsep_transport_->GetDtlsRole();
ASSERT_TRUE(role);
EXPECT_EQ(rtc::SSL_SERVER, role); // Because remote description was "active". auto fake_dtls = static_cast<FakeDtlsTransport*>(jsep_transport_->rtp_dtls_transport());
EXPECT_EQ(remote_description.transport_desc.identity_fingerprint->ToString(),
fake_dtls->dtls_fingerprint().ToString());
if (!rtcp_mux_enabled) { auto fake_rtcp_dtls = static_cast<FakeDtlsTransport*>(jsep_transport_->rtcp_dtls_transport());
EXPECT_EQ(
remote_description.transport_desc.identity_fingerprint->ToString(),
fake_rtcp_dtls->dtls_fingerprint().ToString());
}
}
// Same as above test, but with remote transport description using // CONNECTIONROLE_PASSIVE, expecting SSL_CLIENT role.
TEST_P(JsepTransport2WithRtcpMux, SetDtlsParametersWithPassiveAnswer) { bool rtcp_mux_enabled = GetParam();
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
// Verify that SSL role and remote fingerprint were set correctly based on // transport descriptions. auto role = jsep_transport_->GetDtlsRole();
ASSERT_TRUE(role);
EXPECT_EQ(rtc::SSL_CLIENT,
role); // Because remote description was "passive". auto fake_dtls = static_cast<FakeDtlsTransport*>(jsep_transport_->rtp_dtls_transport());
EXPECT_EQ(remote_description.transport_desc.identity_fingerprint->ToString(),
fake_dtls->dtls_fingerprint().ToString());
if (!rtcp_mux_enabled) { auto fake_rtcp_dtls = static_cast<FakeDtlsTransport*>(jsep_transport_->rtcp_dtls_transport());
EXPECT_EQ(
remote_description.transport_desc.identity_fingerprint->ToString(),
fake_rtcp_dtls->dtls_fingerprint().ToString());
}
}
// Tests SetNeedsIceRestartFlag and need_ice_restart, ensuring needs_ice_restart // only starts returning "false" once an ICE restart has been initiated.
TEST_P(JsepTransport2WithRtcpMux, NeedsIceRestart) { bool rtcp_mux_enabled = GetParam();
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
// Use the same JsepTransportDescription for both offer and answer.
JsepTransportDescription description;
description.transport_desc = TransportDescription(kIceUfrag1, kIcePwd1);
ASSERT_TRUE(
jsep_transport_
->SetLocalJsepTransportDescription(description, SdpType::kOffer)
.ok());
ASSERT_TRUE(
jsep_transport_
->SetRemoteJsepTransportDescription(description, SdpType::kAnswer)
.ok()); // Flag initially should be false.
EXPECT_FALSE(jsep_transport_->needs_ice_restart());
// After setting flag, it should be true.
jsep_transport_->SetNeedsIceRestartFlag();
EXPECT_TRUE(jsep_transport_->needs_ice_restart());
// Tests that VerifyCertificateFingerprint only returns true when the // certificate matches the fingerprint.
TEST_P(JsepTransport2WithRtcpMux, VerifyCertificateFingerprint) { bool rtcp_mux_enabled = GetParam();
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
// Tests the logic of DTLS role negotiation for an initial offer/answer.
TEST_P(JsepTransport2WithRtcpMux, ValidDtlsRoleNegotiation) { bool rtcp_mux_enabled = GetParam(); // Just use the same certificate for both sides; doesn't really matter in a // non end-to-end test.
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing", rtc::KT_ECDSA));
// Tests the logic of DTLS role negotiation for an initial offer/answer.
TEST_P(JsepTransport2WithRtcpMux, InvalidDtlsRoleNegotiation) { bool rtcp_mux_enabled = GetParam(); // Just use the same certificate for both sides; doesn't really matter in a // non end-to-end test.
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing", rtc::KT_ECDSA));
// Invalid parameters due to the offerer not using a role consistent with the // state
NegotiateRoleParams offerer_without_actpass_params[] = { // Cannot use ACTPASS in an answer
{CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kAnswer,
SdpType::kOffer},
{CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kPrAnswer,
SdpType::kOffer}, // Cannot send ACTIVE or PASSIVE in an offer (must handle, must not send)
{CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer,
SdpType::kAnswer},
{CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer,
SdpType::kAnswer},
{CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kOffer,
SdpType::kAnswer},
{CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer,
SdpType::kPrAnswer},
{CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer,
SdpType::kPrAnswer},
{CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kOffer,
SdpType::kPrAnswer}};
for (auto& param : offerer_without_actpass_params) {
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
jsep_transport_->SetLocalCertificate(certificate);
// Test that a reoffer in the opposite direction is successful as long as the // role isn't changing. Doesn't test every possible combination like the test // above.
TEST_F(JsepTransport2Test, ValidDtlsReofferFromAnswerer) { // Just use the same certificate for both sides; doesn't really matter in a // non end-to-end test.
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing", rtc::KT_ECDSA)); bool rtcp_mux_enabled = true;
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
jsep_transport_->SetLocalCertificate(certificate);
// We were actpass->active previously, now in the other direction it's // actpass->passive.
JsepTransportDescription remote_offer =
MakeJsepTransportDescription(rtcp_mux_enabled, kIceUfrag2, kIcePwd2,
certificate, CONNECTIONROLE_ACTPASS);
JsepTransportDescription local_answer =
MakeJsepTransportDescription(rtcp_mux_enabled, kIceUfrag1, kIcePwd1,
certificate, CONNECTIONROLE_PASSIVE);
// Test that a reoffer in the opposite direction fails if the role changes. // Inverse of test above.
TEST_F(JsepTransport2Test, InvalidDtlsReofferFromAnswerer) { // Just use the same certificate for both sides; doesn't really matter in a // non end-to-end test.
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing", rtc::KT_ECDSA)); bool rtcp_mux_enabled = true;
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
jsep_transport_->SetLocalCertificate(certificate);
// Changing role to passive here isn't allowed. Though for some reason this // only fails in SetLocalTransportDescription.
JsepTransportDescription remote_offer =
MakeJsepTransportDescription(rtcp_mux_enabled, kIceUfrag2, kIcePwd2,
certificate, CONNECTIONROLE_PASSIVE);
JsepTransportDescription local_answer =
MakeJsepTransportDescription(rtcp_mux_enabled, kIceUfrag1, kIcePwd1,
certificate, CONNECTIONROLE_ACTIVE);
// Test that a remote offer with the current negotiated role can be accepted. // This is allowed by dtls-sdp, though we'll never generate such an offer, // since JSEP requires generating "actpass".
TEST_F(JsepTransport2Test, RemoteOfferWithCurrentNegotiatedDtlsRole) {
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing", rtc::KT_ECDSA)); bool rtcp_mux_enabled = true;
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
jsep_transport_->SetLocalCertificate(certificate);
// Normal initial offer/answer with "actpass" in the offer and "active" in // the answer.
ASSERT_TRUE(
jsep_transport_
->SetRemoteJsepTransportDescription(remote_desc, SdpType::kOffer)
.ok());
ASSERT_TRUE(
jsep_transport_
->SetLocalJsepTransportDescription(local_desc, SdpType::kAnswer)
.ok());
// Sanity check that role was actually negotiated.
std::optional<rtc::SSLRole> role = jsep_transport_->GetDtlsRole();
ASSERT_TRUE(role);
EXPECT_EQ(rtc::SSL_CLIENT, *role);
// Subsequent offer with current negotiated role of "passive".
remote_desc.transport_desc.connection_role = CONNECTIONROLE_PASSIVE;
EXPECT_TRUE(
jsep_transport_
->SetRemoteJsepTransportDescription(remote_desc, SdpType::kOffer)
.ok());
EXPECT_TRUE(
jsep_transport_
->SetLocalJsepTransportDescription(local_desc, SdpType::kAnswer)
.ok());
}
// Test that a remote offer with the inverse of the current negotiated DTLS // role is rejected.
TEST_F(JsepTransport2Test, RemoteOfferThatChangesNegotiatedDtlsRole) {
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing", rtc::KT_ECDSA)); bool rtcp_mux_enabled = true;
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
jsep_transport_->SetLocalCertificate(certificate);
// Normal initial offer/answer with "actpass" in the offer and "active" in // the answer.
ASSERT_TRUE(
jsep_transport_
->SetRemoteJsepTransportDescription(remote_desc, SdpType::kOffer)
.ok());
ASSERT_TRUE(
jsep_transport_
->SetLocalJsepTransportDescription(local_desc, SdpType::kAnswer)
.ok());
// Sanity check that role was actually negotiated.
std::optional<rtc::SSLRole> role = jsep_transport_->GetDtlsRole();
ASSERT_TRUE(role);
EXPECT_EQ(rtc::SSL_CLIENT, *role);
// Subsequent offer with current negotiated role of "passive".
remote_desc.transport_desc.connection_role = CONNECTIONROLE_ACTIVE;
EXPECT_TRUE(
jsep_transport_
->SetRemoteJsepTransportDescription(remote_desc, SdpType::kOffer)
.ok());
EXPECT_FALSE(
jsep_transport_
->SetLocalJsepTransportDescription(local_desc, SdpType::kAnswer)
.ok());
}
// Test that a remote offer which changes both fingerprint and role is accepted.
TEST_F(JsepTransport2Test, RemoteOfferThatChangesFingerprintAndDtlsRole) {
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing1", rtc::KT_ECDSA));
rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing2", rtc::KT_ECDSA)); bool rtcp_mux_enabled = true;
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
jsep_transport_->SetLocalCertificate(certificate);
// Normal initial offer/answer with "actpass" in the offer and "active" in // the answer.
ASSERT_TRUE(
jsep_transport_
->SetRemoteJsepTransportDescription(remote_desc, SdpType::kOffer)
.ok());
ASSERT_TRUE(
jsep_transport_
->SetLocalJsepTransportDescription(local_desc, SdpType::kAnswer)
.ok());
// Sanity check that role was actually negotiated.
std::optional<rtc::SSLRole> role = jsep_transport_->GetDtlsRole();
ASSERT_TRUE(role);
EXPECT_EQ(rtc::SSL_CLIENT, *role);
// Subsequent exchange with new remote fingerprint and different role.
local_desc.transport_desc.connection_role = CONNECTIONROLE_PASSIVE;
EXPECT_TRUE(
jsep_transport_
->SetRemoteJsepTransportDescription(remote_desc2, SdpType::kOffer)
.ok());
EXPECT_TRUE(
jsep_transport_
->SetLocalJsepTransportDescription(local_desc, SdpType::kAnswer)
.ok());
role = jsep_transport_->GetDtlsRole();
ASSERT_TRUE(role);
EXPECT_EQ(rtc::SSL_SERVER, *role);
}
// Testing that a legacy client that doesn't use the setup attribute will be // interpreted as having an active role.
TEST_F(JsepTransport2Test, DtlsSetupWithLegacyAsAnswerer) {
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(
rtc::SSLIdentity::Create("testing", rtc::KT_ECDSA)); bool rtcp_mux_enabled = true;
jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled);
jsep_transport_->SetLocalCertificate(certificate);
std::optional<rtc::SSLRole> role = jsep_transport_->GetDtlsRole();
ASSERT_TRUE(role); // Since legacy answer omitted setup atribute, and we offered actpass, we // should act as passive (server).
EXPECT_EQ(rtc::SSL_SERVER, *role);
}
// Tests that when the RTCP mux is successfully negotiated, the RTCP transport // will be destroyed and the SignalRtpMuxActive will be fired.
TEST_F(JsepTransport2Test, RtcpMuxNegotiation) {
jsep_transport_ = CreateJsepTransport2(/*rtcp_mux_enabled=*/false);
JsepTransportDescription local_desc;
local_desc.rtcp_mux_enabled = true;
ASSERT_NE(nullptr, jsep_transport_->rtcp_dtls_transport());
EXPECT_FALSE(signal_rtcp_mux_active_received_);
// Tests that the remote candidates can be added to the transports after both // local and remote descriptions are set.
TEST_F(JsepTransport2Test, AddRemoteCandidates) {
jsep_transport_ = CreateJsepTransport2(/*rtcp_mux_enabled=*/true); auto fake_ice_transport = static_cast<FakeIceTransport*>(
jsep_transport_->rtp_dtls_transport()->ice_transport());
JsepTransportDescription desc;
ASSERT_TRUE(
jsep_transport_->SetLocalJsepTransportDescription(desc, SdpType::kOffer)
.ok()); // Expected to fail because the remote description is unset.
EXPECT_FALSE(jsep_transport_->AddRemoteCandidates(candidates).ok());
class JsepTransport2HeaderExtensionTest
: public JsepTransport2Test, public ::testing::WithParamInterface<std::tuple<Scenario, bool>> { protected:
JsepTransport2HeaderExtensionTest() {}
auto fake_dtls1 = static_cast<FakeDtlsTransport*>(jsep_transport1_->rtp_dtls_transport()); auto fake_dtls2 = static_cast<FakeDtlsTransport*>(jsep_transport2_->rtp_dtls_transport());
void TestOneWaySendRecvPacketWithEncryptedHeaderExtension(
JsepTransport* sender_transport) {
size_t rtp_len = sizeof(kPcmuFrameWithExtensions);
size_t packet_size = rtp_len + GetRtpAuthLen();
rtc::Buffer rtp_packet_buffer(packet_size); char* rtp_packet_data = rtp_packet_buffer.data<char>();
memcpy(rtp_packet_data, kPcmuFrameWithExtensions, rtp_len); // In order to be able to run this test function multiple times we can not // use the same sequence number twice. Increase the sequence number by one.
rtc::SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_data) + 2,
++sequence_number_);
rtc::CopyOnWriteBuffer rtp_packet(rtp_packet_data, rtp_len, packet_size);
int packet_count_before = received_packet_count_;
rtc::PacketOptions options; // Send a packet and verify that the packet can be successfully received and // decrypted.
ASSERT_TRUE(sender_transport->rtp_transport()->SendRtpPacket(
&rtp_packet, options, cricket::PF_SRTP_BYPASS));
EXPECT_EQ(packet_count_before + 1, received_packet_count_);
}
int sequence_number_ = 0; int received_packet_count_ = 0;
std::unique_ptr<JsepTransport> jsep_transport1_;
std::unique_ptr<JsepTransport> jsep_transport2_;
std::vector<int> recv_encrypted_headers1_;
std::vector<int> recv_encrypted_headers2_;
};
// Test that the encrypted header extension works and can be changed in // different scenarios.
TEST_P(JsepTransport2HeaderExtensionTest, EncryptedHeaderExtensionNegotiation) {
Scenario scenario = std::get<0>(GetParam()); bool use_gcm = std::get<1>(GetParam());
CreateJsepTransportPair();
recv_encrypted_headers1_.push_back(kHeaderExtensionIDs[0]);
recv_encrypted_headers2_.push_back(kHeaderExtensionIDs[1]);
if (use_gcm) { auto fake_dtls1 = static_cast<FakeDtlsTransport*>(jsep_transport1_->rtp_dtls_transport()); auto fake_dtls2 = static_cast<FakeDtlsTransport*>(jsep_transport2_->rtp_dtls_transport());
if (scenario == Scenario::kDtlsBeforeCallerSetAnswer) {
ConnectTransport(); // Sending packet from transport2 to transport1 should work when they are // partially configured.
TestOneWaySendRecvPacketWithEncryptedHeaderExtension( /*sender_transport=*/jsep_transport2_.get());
}
// This test verifies the ICE parameters are properly applied to the transports.
TEST_F(JsepTransport2Test, SetIceParametersWithRenomination) {
jsep_transport_ = CreateJsepTransport2(/* rtcp_mux_enabled= */ true);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.