mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-15 06:40:43 +01:00

Instead of going through our wrappers in ptr_util.h. This CL was generated by the following script: git grep -l ptr_util | xargs perl -pi -e 's,#include "rtc_base/ptr_util.h",#include "absl/memory/memory.h",' git grep -l MakeUnique | xargs perl -pi -e 's,\b(rtc::)?MakeUnique\b,absl::make_unique,g' git grep -l WrapUnique | xargs perl -pi -e 's,\b(rtc::)?WrapUnique\b,absl::WrapUnique,g' git checkout -- rtc_base/ptr_util{.h,_unittest.cc} git cl format Followed by manually adding dependencies on //third_party/abseil-cpp/absl/memory until `gn check` stopped complaining. Bug: webrtc:9473 Change-Id: I89ccd363f070479b8c431eb2c3d404a46eaacc1c Reviewed-on: https://webrtc-review.googlesource.com/86600 Commit-Queue: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23850}
560 lines
26 KiB
C++
560 lines
26 KiB
C++
/*
|
|
* Copyright 2017 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 "pc/dtlssrtptransport.h"
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "absl/memory/memory.h"
|
|
#include "media/base/fakertp.h"
|
|
#include "p2p/base/dtlstransportinternal.h"
|
|
#include "p2p/base/fakedtlstransport.h"
|
|
#include "p2p/base/fakepackettransport.h"
|
|
#include "p2p/base/p2pconstants.h"
|
|
#include "pc/rtptransport.h"
|
|
#include "pc/rtptransporttestutil.h"
|
|
#include "rtc_base/asyncpacketsocket.h"
|
|
#include "rtc_base/gunit.h"
|
|
#include "rtc_base/sslstreamadapter.h"
|
|
|
|
using cricket::FakeDtlsTransport;
|
|
using cricket::FakeIceTransport;
|
|
using webrtc::DtlsSrtpTransport;
|
|
using webrtc::SrtpTransport;
|
|
using webrtc::RtpTransport;
|
|
|
|
const int kRtpAuthTagLen = 10;
|
|
|
|
class DtlsSrtpTransportTest : public testing::Test,
|
|
public sigslot::has_slots<> {
|
|
protected:
|
|
DtlsSrtpTransportTest() {}
|
|
|
|
~DtlsSrtpTransportTest() {
|
|
if (dtls_srtp_transport1_) {
|
|
dtls_srtp_transport1_->UnregisterRtpDemuxerSink(&transport_observer1_);
|
|
}
|
|
if (dtls_srtp_transport2_) {
|
|
dtls_srtp_transport2_->UnregisterRtpDemuxerSink(&transport_observer2_);
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<DtlsSrtpTransport> MakeDtlsSrtpTransport(
|
|
FakeDtlsTransport* rtp_dtls,
|
|
FakeDtlsTransport* rtcp_dtls,
|
|
bool rtcp_mux_enabled) {
|
|
auto dtls_srtp_transport =
|
|
absl::make_unique<DtlsSrtpTransport>(rtcp_mux_enabled);
|
|
|
|
dtls_srtp_transport->SetDtlsTransports(rtp_dtls, rtcp_dtls);
|
|
|
|
return dtls_srtp_transport;
|
|
}
|
|
|
|
void MakeDtlsSrtpTransports(FakeDtlsTransport* rtp_dtls1,
|
|
FakeDtlsTransport* rtcp_dtls1,
|
|
FakeDtlsTransport* rtp_dtls2,
|
|
FakeDtlsTransport* rtcp_dtls2,
|
|
bool rtcp_mux_enabled) {
|
|
dtls_srtp_transport1_ =
|
|
MakeDtlsSrtpTransport(rtp_dtls1, rtcp_dtls1, rtcp_mux_enabled);
|
|
dtls_srtp_transport2_ =
|
|
MakeDtlsSrtpTransport(rtp_dtls2, rtcp_dtls2, rtcp_mux_enabled);
|
|
|
|
dtls_srtp_transport1_->SignalRtcpPacketReceived.connect(
|
|
&transport_observer1_,
|
|
&webrtc::TransportObserver::OnRtcpPacketReceived);
|
|
dtls_srtp_transport1_->SignalReadyToSend.connect(
|
|
&transport_observer1_, &webrtc::TransportObserver::OnReadyToSend);
|
|
|
|
dtls_srtp_transport2_->SignalRtcpPacketReceived.connect(
|
|
&transport_observer2_,
|
|
&webrtc::TransportObserver::OnRtcpPacketReceived);
|
|
dtls_srtp_transport2_->SignalReadyToSend.connect(
|
|
&transport_observer2_, &webrtc::TransportObserver::OnReadyToSend);
|
|
webrtc::RtpDemuxerCriteria demuxer_criteria;
|
|
// 0x00 is the payload type used in kPcmuFrame.
|
|
demuxer_criteria.payload_types = {0x00};
|
|
dtls_srtp_transport1_->RegisterRtpDemuxerSink(demuxer_criteria,
|
|
&transport_observer1_);
|
|
dtls_srtp_transport2_->RegisterRtpDemuxerSink(demuxer_criteria,
|
|
&transport_observer2_);
|
|
}
|
|
|
|
void CompleteDtlsHandshake(FakeDtlsTransport* fake_dtls1,
|
|
FakeDtlsTransport* fake_dtls2) {
|
|
auto cert1 = rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
|
|
rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
|
|
fake_dtls1->SetLocalCertificate(cert1);
|
|
auto cert2 = rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
|
|
rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
|
|
fake_dtls2->SetLocalCertificate(cert2);
|
|
fake_dtls1->SetDestination(fake_dtls2);
|
|
}
|
|
|
|
void SendRecvRtpPackets() {
|
|
ASSERT_TRUE(dtls_srtp_transport1_);
|
|
ASSERT_TRUE(dtls_srtp_transport2_);
|
|
ASSERT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
|
|
ASSERT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
|
|
|
|
size_t rtp_len = sizeof(kPcmuFrame);
|
|
size_t packet_size = rtp_len + kRtpAuthTagLen;
|
|
rtc::Buffer rtp_packet_buffer(packet_size);
|
|
char* rtp_packet_data = rtp_packet_buffer.data<char>();
|
|
memcpy(rtp_packet_data, kPcmuFrame, 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_packet1to2(rtp_packet_data, rtp_len,
|
|
packet_size);
|
|
rtc::CopyOnWriteBuffer rtp_packet2to1(rtp_packet_data, rtp_len,
|
|
packet_size);
|
|
|
|
rtc::PacketOptions options;
|
|
// Send a packet from |srtp_transport1_| to |srtp_transport2_| and verify
|
|
// that the packet can be successfully received and decrypted.
|
|
int prev_received_packets = transport_observer2_.rtp_count();
|
|
ASSERT_TRUE(dtls_srtp_transport1_->SendRtpPacket(&rtp_packet1to2, options,
|
|
cricket::PF_SRTP_BYPASS));
|
|
ASSERT_TRUE(transport_observer2_.last_recv_rtp_packet().data());
|
|
EXPECT_EQ(0, memcmp(transport_observer2_.last_recv_rtp_packet().data(),
|
|
kPcmuFrame, rtp_len));
|
|
EXPECT_EQ(prev_received_packets + 1, transport_observer2_.rtp_count());
|
|
|
|
prev_received_packets = transport_observer1_.rtp_count();
|
|
ASSERT_TRUE(dtls_srtp_transport2_->SendRtpPacket(&rtp_packet2to1, options,
|
|
cricket::PF_SRTP_BYPASS));
|
|
ASSERT_TRUE(transport_observer1_.last_recv_rtp_packet().data());
|
|
EXPECT_EQ(0, memcmp(transport_observer1_.last_recv_rtp_packet().data(),
|
|
kPcmuFrame, rtp_len));
|
|
EXPECT_EQ(prev_received_packets + 1, transport_observer1_.rtp_count());
|
|
}
|
|
|
|
void SendRecvRtcpPackets() {
|
|
size_t rtcp_len = sizeof(kRtcpReport);
|
|
size_t packet_size = rtcp_len + 4 + kRtpAuthTagLen;
|
|
rtc::Buffer rtcp_packet_buffer(packet_size);
|
|
|
|
// TODO(zhihuang): Remove the extra copy when the SendRtpPacket method
|
|
// doesn't take the CopyOnWriteBuffer by pointer.
|
|
rtc::CopyOnWriteBuffer rtcp_packet1to2(kRtcpReport, rtcp_len, packet_size);
|
|
rtc::CopyOnWriteBuffer rtcp_packet2to1(kRtcpReport, rtcp_len, packet_size);
|
|
|
|
rtc::PacketOptions options;
|
|
// Send a packet from |srtp_transport1_| to |srtp_transport2_| and verify
|
|
// that the packet can be successfully received and decrypted.
|
|
int prev_received_packets = transport_observer2_.rtcp_count();
|
|
ASSERT_TRUE(dtls_srtp_transport1_->SendRtcpPacket(&rtcp_packet1to2, options,
|
|
cricket::PF_SRTP_BYPASS));
|
|
ASSERT_TRUE(transport_observer2_.last_recv_rtcp_packet().data());
|
|
EXPECT_EQ(0, memcmp(transport_observer2_.last_recv_rtcp_packet().data(),
|
|
kRtcpReport, rtcp_len));
|
|
EXPECT_EQ(prev_received_packets + 1, transport_observer2_.rtcp_count());
|
|
|
|
// Do the same thing in the opposite direction;
|
|
prev_received_packets = transport_observer1_.rtcp_count();
|
|
ASSERT_TRUE(dtls_srtp_transport2_->SendRtcpPacket(&rtcp_packet2to1, options,
|
|
cricket::PF_SRTP_BYPASS));
|
|
ASSERT_TRUE(transport_observer1_.last_recv_rtcp_packet().data());
|
|
EXPECT_EQ(0, memcmp(transport_observer1_.last_recv_rtcp_packet().data(),
|
|
kRtcpReport, rtcp_len));
|
|
EXPECT_EQ(prev_received_packets + 1, transport_observer1_.rtcp_count());
|
|
}
|
|
|
|
void SendRecvRtpPacketsWithHeaderExtension(
|
|
const std::vector<int>& encrypted_header_ids) {
|
|
ASSERT_TRUE(dtls_srtp_transport1_);
|
|
ASSERT_TRUE(dtls_srtp_transport2_);
|
|
ASSERT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
|
|
ASSERT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
|
|
|
|
size_t rtp_len = sizeof(kPcmuFrameWithExtensions);
|
|
size_t packet_size = rtp_len + kRtpAuthTagLen;
|
|
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_packet1to2(rtp_packet_data, rtp_len,
|
|
packet_size);
|
|
rtc::CopyOnWriteBuffer rtp_packet2to1(rtp_packet_data, rtp_len,
|
|
packet_size);
|
|
|
|
char original_rtp_data[sizeof(kPcmuFrameWithExtensions)];
|
|
memcpy(original_rtp_data, rtp_packet_data, rtp_len);
|
|
|
|
rtc::PacketOptions options;
|
|
// Send a packet from |srtp_transport1_| to |srtp_transport2_| and verify
|
|
// that the packet can be successfully received and decrypted.
|
|
ASSERT_TRUE(dtls_srtp_transport1_->SendRtpPacket(&rtp_packet1to2, options,
|
|
cricket::PF_SRTP_BYPASS));
|
|
ASSERT_TRUE(transport_observer2_.last_recv_rtp_packet().data());
|
|
EXPECT_EQ(0, memcmp(transport_observer2_.last_recv_rtp_packet().data(),
|
|
original_rtp_data, rtp_len));
|
|
// Get the encrypted packet from underneath packet transport and verify the
|
|
// data and header extension are actually encrypted.
|
|
auto fake_dtls_transport = static_cast<FakeDtlsTransport*>(
|
|
dtls_srtp_transport1_->rtp_packet_transport());
|
|
auto fake_ice_transport =
|
|
static_cast<FakeIceTransport*>(fake_dtls_transport->ice_transport());
|
|
EXPECT_NE(0, memcmp(fake_ice_transport->last_sent_packet().data(),
|
|
original_rtp_data, rtp_len));
|
|
CompareHeaderExtensions(reinterpret_cast<const char*>(
|
|
fake_ice_transport->last_sent_packet().data()),
|
|
fake_ice_transport->last_sent_packet().size(),
|
|
original_rtp_data, rtp_len, encrypted_header_ids,
|
|
false);
|
|
|
|
// Do the same thing in the opposite direction.
|
|
ASSERT_TRUE(dtls_srtp_transport2_->SendRtpPacket(&rtp_packet2to1, options,
|
|
cricket::PF_SRTP_BYPASS));
|
|
ASSERT_TRUE(transport_observer1_.last_recv_rtp_packet().data());
|
|
EXPECT_EQ(0, memcmp(transport_observer1_.last_recv_rtp_packet().data(),
|
|
original_rtp_data, rtp_len));
|
|
// Get the encrypted packet from underneath packet transport and verify the
|
|
// data and header extension are actually encrypted.
|
|
fake_dtls_transport = static_cast<FakeDtlsTransport*>(
|
|
dtls_srtp_transport2_->rtp_packet_transport());
|
|
fake_ice_transport =
|
|
static_cast<FakeIceTransport*>(fake_dtls_transport->ice_transport());
|
|
EXPECT_NE(0, memcmp(fake_ice_transport->last_sent_packet().data(),
|
|
original_rtp_data, rtp_len));
|
|
CompareHeaderExtensions(reinterpret_cast<const char*>(
|
|
fake_ice_transport->last_sent_packet().data()),
|
|
fake_ice_transport->last_sent_packet().size(),
|
|
original_rtp_data, rtp_len, encrypted_header_ids,
|
|
false);
|
|
}
|
|
|
|
void SendRecvPackets() {
|
|
SendRecvRtpPackets();
|
|
SendRecvRtcpPackets();
|
|
}
|
|
|
|
std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport1_;
|
|
std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport2_;
|
|
webrtc::TransportObserver transport_observer1_;
|
|
webrtc::TransportObserver transport_observer2_;
|
|
|
|
int sequence_number_ = 0;
|
|
};
|
|
|
|
// Tests that if RTCP muxing is enabled and transports are set after RTP
|
|
// transport finished the handshake, SRTP is set up.
|
|
TEST_F(DtlsSrtpTransportTest, SetTransportsAfterHandshakeCompleteWithRtcpMux) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"video", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"video", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), nullptr, rtp_dtls2.get(), nullptr,
|
|
/*rtcp_mux_enabled=*/true);
|
|
|
|
auto rtp_dtls3 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtp_dtls4 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
|
|
CompleteDtlsHandshake(rtp_dtls3.get(), rtp_dtls4.get());
|
|
|
|
dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls3.get(), nullptr);
|
|
dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls4.get(), nullptr);
|
|
|
|
SendRecvPackets();
|
|
}
|
|
|
|
// Tests that if RTCP muxing is not enabled and transports are set after both
|
|
// RTP and RTCP transports finished the handshake, SRTP is set up.
|
|
TEST_F(DtlsSrtpTransportTest,
|
|
SetTransportsAfterHandshakeCompleteWithoutRtcpMux) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"video", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"video", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"video", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"video", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
|
|
rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
|
|
|
|
auto rtp_dtls3 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls3 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
auto rtp_dtls4 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls4 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
CompleteDtlsHandshake(rtp_dtls3.get(), rtp_dtls4.get());
|
|
CompleteDtlsHandshake(rtcp_dtls3.get(), rtcp_dtls4.get());
|
|
|
|
dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls3.get(), rtcp_dtls3.get());
|
|
dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls4.get(), rtcp_dtls4.get());
|
|
|
|
SendRecvPackets();
|
|
}
|
|
|
|
// Tests if RTCP muxing is enabled, SRTP is set up as soon as the RTP DTLS
|
|
// handshake is finished.
|
|
TEST_F(DtlsSrtpTransportTest, SetTransportsBeforeHandshakeCompleteWithRtcpMux) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
|
|
rtcp_dtls2.get(),
|
|
/*rtcp_mux_enabled=*/false);
|
|
|
|
dtls_srtp_transport1_->SetRtcpMuxEnabled(true);
|
|
dtls_srtp_transport2_->SetRtcpMuxEnabled(true);
|
|
CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
|
|
SendRecvPackets();
|
|
}
|
|
|
|
// Tests if RTCP muxing is not enabled, SRTP is set up when both the RTP and
|
|
// RTCP DTLS handshake are finished.
|
|
TEST_F(DtlsSrtpTransportTest,
|
|
SetTransportsBeforeHandshakeCompleteWithoutRtcpMux) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
|
|
rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
|
|
|
|
CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
|
|
EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
|
|
EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
|
|
CompleteDtlsHandshake(rtcp_dtls1.get(), rtcp_dtls2.get());
|
|
SendRecvPackets();
|
|
}
|
|
|
|
// Tests that if the DtlsTransport underneath is changed, the previous DTLS-SRTP
|
|
// context will be reset and will be re-setup once the new transports' handshake
|
|
// complete.
|
|
TEST_F(DtlsSrtpTransportTest, DtlsSrtpResetAfterDtlsTransportChange) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), nullptr, rtp_dtls2.get(), nullptr,
|
|
/*rtcp_mux_enabled=*/true);
|
|
|
|
CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
|
|
EXPECT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
|
|
EXPECT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
|
|
|
|
auto rtp_dtls3 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtp_dtls4 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
|
|
// The previous context is reset.
|
|
dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls3.get(), nullptr);
|
|
dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls4.get(), nullptr);
|
|
EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
|
|
EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
|
|
|
|
// Re-setup.
|
|
CompleteDtlsHandshake(rtp_dtls3.get(), rtp_dtls4.get());
|
|
SendRecvPackets();
|
|
}
|
|
|
|
// Tests if only the RTP DTLS handshake complete, and then RTCP muxing is
|
|
// enabled, SRTP is set up.
|
|
TEST_F(DtlsSrtpTransportTest,
|
|
RtcpMuxEnabledAfterRtpTransportHandshakeComplete) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
|
|
rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
|
|
|
|
CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
|
|
// Inactive because the RTCP transport handshake didn't complete.
|
|
EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
|
|
EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
|
|
|
|
dtls_srtp_transport1_->SetRtcpMuxEnabled(true);
|
|
dtls_srtp_transport2_->SetRtcpMuxEnabled(true);
|
|
// The transports should be active and be able to send packets when the
|
|
// RTCP muxing is enabled.
|
|
SendRecvPackets();
|
|
}
|
|
|
|
// Tests that when SetSend/RecvEncryptedHeaderExtensionIds is called, the SRTP
|
|
// sessions are updated with new encryped header extension IDs immediately.
|
|
TEST_F(DtlsSrtpTransportTest, EncryptedHeaderExtensionIdUpdated) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), nullptr, rtp_dtls2.get(), nullptr,
|
|
/*rtcp_mux_enabled=*/true);
|
|
CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
|
|
|
|
std::vector<int> encrypted_headers;
|
|
encrypted_headers.push_back(kHeaderExtensionIDs[0]);
|
|
encrypted_headers.push_back(kHeaderExtensionIDs[1]);
|
|
|
|
dtls_srtp_transport1_->UpdateSendEncryptedHeaderExtensionIds(
|
|
encrypted_headers);
|
|
dtls_srtp_transport1_->UpdateRecvEncryptedHeaderExtensionIds(
|
|
encrypted_headers);
|
|
dtls_srtp_transport2_->UpdateSendEncryptedHeaderExtensionIds(
|
|
encrypted_headers);
|
|
dtls_srtp_transport2_->UpdateRecvEncryptedHeaderExtensionIds(
|
|
encrypted_headers);
|
|
}
|
|
|
|
// Tests if RTCP muxing is enabled. DtlsSrtpTransport is ready to send once the
|
|
// RTP DtlsTransport is ready.
|
|
TEST_F(DtlsSrtpTransportTest, SignalReadyToSendFiredWithRtcpMux) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), nullptr, rtp_dtls2.get(), nullptr,
|
|
/*rtcp_mux_enabled=*/true);
|
|
|
|
rtp_dtls1->SetDestination(rtp_dtls2.get());
|
|
EXPECT_TRUE(transport_observer1_.ready_to_send());
|
|
EXPECT_TRUE(transport_observer2_.ready_to_send());
|
|
}
|
|
|
|
// Tests if RTCP muxing is not enabled. DtlsSrtpTransport is ready to send once
|
|
// both the RTP and RTCP DtlsTransport are ready.
|
|
TEST_F(DtlsSrtpTransportTest, SignalReadyToSendFiredWithoutRtcpMux) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
|
|
rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
|
|
|
|
rtp_dtls1->SetDestination(rtp_dtls2.get());
|
|
EXPECT_FALSE(transport_observer1_.ready_to_send());
|
|
EXPECT_FALSE(transport_observer2_.ready_to_send());
|
|
|
|
rtcp_dtls1->SetDestination(rtcp_dtls2.get());
|
|
EXPECT_TRUE(transport_observer1_.ready_to_send());
|
|
EXPECT_TRUE(transport_observer2_.ready_to_send());
|
|
}
|
|
|
|
// Test that if an endpoint "fully" enables RTCP mux, setting the RTCP
|
|
// transport to null, it *doesn't* reset its SRTP context. That would cause the
|
|
// ROC and SRTCP index to be reset, causing replay detection and other errors
|
|
// when attempting to unprotect packets.
|
|
// Regression test for bugs.webrtc.org/8996
|
|
TEST_F(DtlsSrtpTransportTest, SrtpSessionNotResetWhenRtcpTransportRemoved) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
|
|
rtcp_dtls2.get(), /*rtcp_mux_enabled=*/true);
|
|
CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
|
|
CompleteDtlsHandshake(rtcp_dtls1.get(), rtcp_dtls2.get());
|
|
|
|
// Send some RTCP packets, causing the SRTCP index to be incremented.
|
|
SendRecvRtcpPackets();
|
|
|
|
// Set RTCP transport to null, which previously would trigger this problem.
|
|
dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls1.get(), nullptr);
|
|
|
|
// Attempt to send more RTCP packets. If the issue occurred, one side would
|
|
// reset its context while the other would not, causing replay detection
|
|
// errors when a packet with a duplicate SRTCP index is received.
|
|
SendRecvRtcpPackets();
|
|
}
|
|
|
|
// Tests that RTCP packets can be sent and received if both sides actively reset
|
|
// the SRTP parameters with the |active_reset_srtp_params_| flag.
|
|
TEST_F(DtlsSrtpTransportTest, ActivelyResetSrtpParams) {
|
|
auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
|
|
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
|
|
|
|
MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
|
|
rtcp_dtls2.get(), /*rtcp_mux_enabled=*/true);
|
|
CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
|
|
CompleteDtlsHandshake(rtcp_dtls1.get(), rtcp_dtls2.get());
|
|
|
|
// Send some RTCP packets, causing the SRTCP index to be incremented.
|
|
SendRecvRtcpPackets();
|
|
|
|
// Only set the |active_reset_srtp_params_| flag to be true one side.
|
|
dtls_srtp_transport1_->SetActiveResetSrtpParams(true);
|
|
// Set RTCP transport to null to trigger the SRTP parameters update.
|
|
dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls1.get(), nullptr);
|
|
dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls2.get(), nullptr);
|
|
|
|
// Sending some RTCP packets.
|
|
size_t rtcp_len = sizeof(kRtcpReport);
|
|
size_t packet_size = rtcp_len + 4 + kRtpAuthTagLen;
|
|
rtc::Buffer rtcp_packet_buffer(packet_size);
|
|
rtc::CopyOnWriteBuffer rtcp_packet(kRtcpReport, rtcp_len, packet_size);
|
|
int prev_received_packets = transport_observer2_.rtcp_count();
|
|
ASSERT_TRUE(dtls_srtp_transport1_->SendRtcpPacket(
|
|
&rtcp_packet, rtc::PacketOptions(), cricket::PF_SRTP_BYPASS));
|
|
// The RTCP packet is not exepected to be received because the SRTP parameters
|
|
// are only reset on one side and the SRTCP index is out of sync.
|
|
EXPECT_EQ(prev_received_packets, transport_observer2_.rtcp_count());
|
|
|
|
// Set the flag to be true on the other side.
|
|
dtls_srtp_transport2_->SetActiveResetSrtpParams(true);
|
|
// Set RTCP transport to null to trigger the SRTP parameters update.
|
|
dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls1.get(), nullptr);
|
|
dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls2.get(), nullptr);
|
|
|
|
// RTCP packets flow is expected to work just fine.
|
|
SendRecvRtcpPackets();
|
|
}
|