Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(799)

Unified Diff: webrtc/pc/channel_unittest.cc

Issue 2761143002: Support encrypted RTP extensions (RFC 6904) (Closed)
Patch Set: Fix compile error on win_x64 bots. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/pc/channel.cc ('k') | webrtc/pc/mediasession.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/pc/channel_unittest.cc
diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc
index cb7d318982c1c8a6ee1460176d9eb4b5a89316fd..7fe1472e25a33efff3bdee5326ce129e9f6af792 100644
--- a/webrtc/pc/channel_unittest.cc
+++ b/webrtc/pc/channel_unittest.cc
@@ -100,6 +100,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
// Use BaseChannel with PacketTransportInternal rather than
// DtlsTransportInternal.
RAW_PACKET_TRANSPORT = 0x20,
+ GCM_CIPHER = 0x40,
+ ENCRYPTED_HEADERS = 0x80,
};
ChannelTest(bool verify_playout,
@@ -175,6 +177,22 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
fake_rtcp_dtls_transport1_->SetLocalCertificate(cert1);
}
}
+ if (flags1 & ENCRYPTED_HEADERS) {
+ rtc::CryptoOptions crypto_options;
+ crypto_options.enable_encrypted_rtp_header_extensions = true;
+ fake_rtp_dtls_transport1_->SetCryptoOptions(crypto_options);
+ if (fake_rtcp_dtls_transport1_) {
+ fake_rtcp_dtls_transport1_->SetCryptoOptions(crypto_options);
+ }
+ }
+ if (flags1 & GCM_CIPHER) {
+ fake_rtp_dtls_transport1_->SetSrtpCryptoSuite(
+ rtc::SRTP_AEAD_AES_256_GCM);
+ if (fake_rtcp_dtls_transport1_) {
+ fake_rtcp_dtls_transport1_->SetSrtpCryptoSuite(
+ rtc::SRTP_AEAD_AES_256_GCM);
+ }
+ }
}
// Based on flags, create fake DTLS or raw packet transports.
if (flags2 & RAW_PACKET_TRANSPORT) {
@@ -205,6 +223,22 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
fake_rtcp_dtls_transport2_->SetLocalCertificate(cert2);
}
}
+ if (flags2 & ENCRYPTED_HEADERS) {
+ rtc::CryptoOptions crypto_options;
+ crypto_options.enable_encrypted_rtp_header_extensions = true;
+ fake_rtp_dtls_transport2_->SetCryptoOptions(crypto_options);
+ if (fake_rtcp_dtls_transport2_) {
+ fake_rtcp_dtls_transport2_->SetCryptoOptions(crypto_options);
+ }
+ }
+ if (flags2 & GCM_CIPHER) {
+ fake_rtp_dtls_transport2_->SetSrtpCryptoSuite(
+ rtc::SRTP_AEAD_AES_256_GCM);
+ if (fake_rtcp_dtls_transport2_) {
+ fake_rtcp_dtls_transport2_->SetSrtpCryptoSuite(
+ rtc::SRTP_AEAD_AES_256_GCM);
+ }
+ }
}
channel1_.reset(
CreateChannel(worker_thread, network_thread_, &media_engine_, ch1,
@@ -869,6 +903,183 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
}
+ enum EncryptedHeaderTestScenario {
+ // Offer/Answer are processed before DTLS completes.
+ DEFAULT,
+ // DTLS completes before any Offer/Answer have been sent.
+ DTLS_BEFORE_OFFER_ANSWER,
+ // DTLS completes after channel 2 has processed (remote) Offer and (local)
+ // Answer.
+ DTLS_AFTER_CHANNEL2_READY,
+ };
+
+ // Test that encrypted header extensions are working and can be changed when
+ // sending a new OFFER/ANSWER.
+ void TestChangeEncryptedHeaderExtensions(int flags,
+ EncryptedHeaderTestScenario scenario = DEFAULT) {
+ RTC_CHECK(scenario == 0 || (flags & DTLS));
+ struct PacketListener : public sigslot::has_slots<> {
+ PacketListener() {}
+ void OnReadPacket(rtc::PacketTransportInternal* transport,
+ const char* data, size_t size, const rtc::PacketTime& time,
+ int flags) {
+ CompareHeaderExtensions(
+ reinterpret_cast<const char*>(kPcmuFrameWithExtensions),
+ sizeof(kPcmuFrameWithExtensions), data, size, encrypted_headers,
+ false);
+ }
+ std::vector<int> encrypted_headers;
+ } packet_listener1, packet_listener2;
+
+ cricket::StreamParams stream1;
+ stream1.groupid = "group1";
+ stream1.id = "stream1";
+ stream1.ssrcs.push_back(kSsrc1);
+ stream1.cname = "stream1_cname";
+
+ cricket::StreamParams stream2;
+ stream2.groupid = "group1";
+ stream2.id = "stream2";
+ stream2.ssrcs.push_back(kSsrc2);
+ stream2.cname = "stream2_cname";
+
+ // Use SRTP when testing encrypted extensions.
+ int channel_flags = flags | SECURE | ENCRYPTED_HEADERS;
+ // Enable SDES if channel is not using DTLS.
+ int content_flags = (channel_flags & DTLS) == 0 ? SECURE : 0;
+
+ // kPcmuFrameWithExtensions contains RTP extension headers with ids 1-4.
+ // Make sure to use URIs that are supported for encryption.
+ cricket::RtpHeaderExtensions extensions1;
+ extensions1.push_back(
+ RtpExtension(RtpExtension::kAudioLevelUri, 10));
+ extensions1.push_back(
+ RtpExtension(RtpExtension::kAudioLevelUri, 1, true));
+
+ cricket::RtpHeaderExtensions extensions2;
+ extensions2.push_back(
+ RtpExtension(RtpExtension::kAudioLevelUri, 10));
+ extensions2.push_back(
+ RtpExtension(RtpExtension::kAudioLevelUri, 2, true));
+ extensions2.push_back(
+ RtpExtension(RtpExtension::kVideoRotationUri, 3));
+ extensions2.push_back(
+ RtpExtension(RtpExtension::kTimestampOffsetUri, 4, true));
+
+ // Setup a call where channel 1 send |stream1| to channel 2.
+ CreateChannels(channel_flags, channel_flags);
+ fake_rtp_dtls_transport1_->fake_ice_transport()->SignalReadPacket.connect(
+ &packet_listener1, &PacketListener::OnReadPacket);
+ fake_rtp_dtls_transport2_->fake_ice_transport()->SignalReadPacket.connect(
+ &packet_listener2, &PacketListener::OnReadPacket);
+
+ if (scenario == DTLS_BEFORE_OFFER_ANSWER) {
+ ConnectFakeTransports();
+ WaitForThreads();
+ }
+
+ typename T::Content content1;
+ CreateContent(content_flags, kPcmuCodec, kH264Codec, &content1);
+ content1.AddStream(stream1);
+ content1.set_rtp_header_extensions(extensions1);
+ EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER, NULL));
+ EXPECT_TRUE(channel1_->Enable(true));
+ EXPECT_EQ(1u, media_channel1_->send_streams().size());
+ packet_listener1.encrypted_headers.push_back(1);
+
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER, NULL));
+ EXPECT_EQ(1u, media_channel2_->recv_streams().size());
+
+ // Channel 2 sends back |stream2|.
+ typename T::Content content2;
+ CreateContent(content_flags, kPcmuCodec, kH264Codec, &content2);
+ content2.AddStream(stream2);
+ content2.set_rtp_header_extensions(extensions1);
+ EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_ANSWER, NULL));
+ EXPECT_TRUE(channel2_->Enable(true));
+ EXPECT_EQ(1u, media_channel2_->send_streams().size());
+ packet_listener2.encrypted_headers.push_back(1);
+
+ if (scenario == DTLS_AFTER_CHANNEL2_READY) {
+ ConnectFakeTransports();
+ WaitForThreads();
+ }
+
+ if (scenario == DTLS_BEFORE_OFFER_ANSWER ||
+ scenario == DTLS_AFTER_CHANNEL2_READY) {
+ // In both scenarios with partially completed Offer/Answer, sending
+ // packets from Channel 2 to Channel 1 should work.
+ SendCustomRtp2(kSsrc2, 0);
+ WaitForThreads();
+ EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
+ }
+
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_ANSWER, NULL));
+ EXPECT_EQ(1u, media_channel1_->recv_streams().size());
+
+ if (scenario == DEFAULT) {
+ ConnectFakeTransports();
+ WaitForThreads();
+ }
+
+ SendCustomRtp1(kSsrc1, 0);
+ SendCustomRtp2(kSsrc2, 0);
+ WaitForThreads();
+ EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0));
+ EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
+
+ // Let channel 2 update the encrypted header extensions.
+ typename T::Content content3;
+ CreateContent(content_flags, kPcmuCodec, kH264Codec, &content3);
+ content3.AddStream(stream2);
+ content3.set_rtp_header_extensions(extensions2);
+ EXPECT_TRUE(channel2_->SetLocalContent(&content3, CA_OFFER, NULL));
+ ASSERT_EQ(1u, media_channel2_->send_streams().size());
+ EXPECT_EQ(stream2, media_channel2_->send_streams()[0]);
+ packet_listener2.encrypted_headers.clear();
+ packet_listener2.encrypted_headers.push_back(2);
+ packet_listener2.encrypted_headers.push_back(4);
+
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content3, CA_OFFER, NULL));
+ ASSERT_EQ(1u, media_channel1_->recv_streams().size());
+ EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]);
+
+ // Channel 1 is already sending the new encrypted extensions. These
+ // can be decrypted by channel 2. Channel 2 is still sending the old
+ // encrypted extensions (which can be decrypted by channel 1).
+
+ if (flags & DTLS) {
+ // DTLS supports updating the encrypted extensions with only the OFFER
+ // being processed. For SDES both the OFFER and ANSWER must have been
+ // processed to update encrypted extensions, so we can't check this case.
+ SendCustomRtp1(kSsrc1, 0);
+ SendCustomRtp2(kSsrc2, 0);
+ WaitForThreads();
+ EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0));
+ EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
+ }
+
+ // Channel 1 replies with the same extensions.
+ typename T::Content content4;
+ CreateContent(content_flags, kPcmuCodec, kH264Codec, &content4);
+ content4.AddStream(stream1);
+ content4.set_rtp_header_extensions(extensions2);
+ EXPECT_TRUE(channel1_->SetLocalContent(&content4, CA_ANSWER, NULL));
+ EXPECT_EQ(1u, media_channel1_->send_streams().size());
+ packet_listener1.encrypted_headers.clear();
+ packet_listener1.encrypted_headers.push_back(2);
+ packet_listener1.encrypted_headers.push_back(4);
+
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content4, CA_ANSWER, NULL));
+ EXPECT_EQ(1u, media_channel2_->recv_streams().size());
+
+ SendCustomRtp1(kSsrc1, 0);
+ SendCustomRtp2(kSsrc2, 0);
+ WaitForThreads();
+ EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0));
+ EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
+ }
+
// Test that we only start playout and sending at the right times.
void TestPlayoutAndSendingStates() {
CreateChannels(0, 0);
@@ -1955,6 +2166,24 @@ class VoiceChannelDoubleThreadTest : public ChannelTest<VoiceTraits> {
: Base(true, kPcmuFrame, kRtcpReport, NetworkIsWorker::No) {}
};
+class VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest
+ : public ChannelTest<VoiceTraits> {
+ public:
+ typedef ChannelTest<VoiceTraits> Base;
+ VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest()
+ : Base(true, kPcmuFrameWithExtensions, kRtcpReport,
+ NetworkIsWorker::Yes) {}
+};
+
+class VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest
+ : public ChannelTest<VoiceTraits> {
+ public:
+ typedef ChannelTest<VoiceTraits> Base;
+ VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest()
+ : Base(true, kPcmuFrameWithExtensions, kRtcpReport,
+ NetworkIsWorker::No) {}
+};
+
// override to add NULL parameter
template <>
cricket::VideoChannel* ChannelTest<VideoTraits>::CreateChannel(
@@ -2091,6 +2320,48 @@ TEST_F(VoiceChannelSingleThreadTest, TestChangeStreamParamsInContent) {
Base::TestChangeStreamParamsInContent();
}
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtls) {
+ int flags = DTLS;
+ Base::TestChangeEncryptedHeaderExtensions(flags);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsScenario1) {
+ int flags = DTLS;
+ Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsScenario2) {
+ int flags = DTLS;
+ Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsGcm) {
+ int flags = DTLS | GCM_CIPHER;
+ Base::TestChangeEncryptedHeaderExtensions(flags);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsGcmScenario1) {
+ int flags = DTLS | GCM_CIPHER;
+ Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsGcmScenario2) {
+ int flags = DTLS | GCM_CIPHER;
+ Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
+ TestChangeEncryptedHeaderExtensionsSDES) {
+ int flags = 0;
+ Base::TestChangeEncryptedHeaderExtensions(flags);
+}
+
TEST_F(VoiceChannelSingleThreadTest, TestPlayoutAndSendingStates) {
Base::TestPlayoutAndSendingStates();
}
@@ -2408,6 +2679,48 @@ TEST_F(VoiceChannelDoubleThreadTest, TestChangeStreamParamsInContent) {
Base::TestChangeStreamParamsInContent();
}
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtls) {
+ int flags = DTLS;
+ Base::TestChangeEncryptedHeaderExtensions(flags);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsScenario1) {
+ int flags = DTLS;
+ Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsScenario2) {
+ int flags = DTLS;
+ Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsGcm) {
+ int flags = DTLS | GCM_CIPHER;
+ Base::TestChangeEncryptedHeaderExtensions(flags);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsGcmScenario1) {
+ int flags = DTLS | GCM_CIPHER;
+ Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
+ TestChangeEncryptedHeaderExtensionsDtlsGcmScenario2) {
+ int flags = DTLS | GCM_CIPHER;
+ Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY);
+}
+
+TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
+ TestChangeEncryptedHeaderExtensionsSDES) {
+ int flags = 0;
+ Base::TestChangeEncryptedHeaderExtensions(flags);
+}
+
TEST_F(VoiceChannelDoubleThreadTest, TestPlayoutAndSendingStates) {
Base::TestPlayoutAndSendingStates();
}
« no previous file with comments | « webrtc/pc/channel.cc ('k') | webrtc/pc/mediasession.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698