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

Unified Diff: webrtc/pc/srtpfilter_unittest.cc

Issue 2761143002: Support encrypted RTP extensions (RFC 6904) (Closed)
Patch Set: Created 3 years, 9 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
Index: webrtc/pc/srtpfilter_unittest.cc
diff --git a/webrtc/pc/srtpfilter_unittest.cc b/webrtc/pc/srtpfilter_unittest.cc
index af8b69f73e334496ef4e2bc80224a66ecd85d6f8..e7469b4bf57958f5bd4d0b01893e4e99e9133877 100644
--- a/webrtc/pc/srtpfilter_unittest.cc
+++ b/webrtc/pc/srtpfilter_unittest.cc
@@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <algorithm>
+
#include "webrtc/pc/srtpfilter.h"
#include "third_party/libsrtp/include/srtp.h"
@@ -193,17 +195,104 @@ class SrtpFilterTest : public testing::Test {
EXPECT_EQ(rtcp_len, out_len);
EXPECT_EQ(0, memcmp(rtcp_packet, kRtcpReport, rtcp_len));
}
+ void CompareHeaderExtensions(const char* packet1, const char* packet2,
+ const std::vector<int> encrypted_headers, bool expect_equal) {
+ // This expects both packets to be based on kPcmuWithExtensionsFrame.
Taylor Brandstetter 2017/03/22 18:00:11 nit: Comment may look better above method rather t
joachim 2017/03/23 00:04:34 Done.
+
+ // RTP header + extension header are the same.
+ EXPECT_EQ(0, memcmp(packet1, packet2, 12 + 4));
+ // Check for one-byte header extensions.
+ EXPECT_EQ('\xBE', packet1[12]);
+ EXPECT_EQ('\xDE', packet1[13]);
+ // Determine position and size of extension headers.
+ size_t extension_words = packet1[14] << 8 | packet1[15];
+ const char* extension_data1 = packet1 + 12 + 4;
+ const char* extension_end1 = extension_data1 + extension_words * 4;
+ const char* extension_data2 = packet2 + 12 + 4;
+ while (extension_data1 < extension_end1) {
+ uint8_t id = (*extension_data1 & 0xf0) >> 4;
+ uint8_t len = (*extension_data1 & 0x0f) +1;
+ extension_data1++;
+ extension_data2++;
+ EXPECT_LE(extension_data1, extension_end1);
+ if (id == 15) {
+ // Finished parsing.
+ break;
+ }
+
+ // The header extension doesn't get encrypted if the id not in the list
+ // of header extensions to encrypt.
Taylor Brandstetter 2017/03/22 18:00:11 So, unencrypted extensions are always expected to
joachim 2017/03/23 00:04:34 Done.
+ if (expect_equal ||
+ std::find(encrypted_headers.begin(), encrypted_headers.end(), id) ==
+ encrypted_headers.end()) {
+ EXPECT_EQ(0, memcmp(extension_data1, extension_data2, len));
+ } else {
+ EXPECT_NE(0, memcmp(extension_data1, extension_data2, len));
+ }
+
+ extension_data1 += len;
+ extension_data2 += len;
+ // Skip padding.
+ while (extension_data1 < extension_end1 && *extension_data1 == 0) {
+ extension_data1++;
+ extension_data2++;
+ }
+ }
+ }
+ void TestProtectUnprotectHeaderEncryption(const std::string& cs1,
+ const std::string& cs2, const std::vector<int>& encrypted_headers) {
+ rtc::Buffer rtp_buffer(sizeof(kPcmuWithExtensionsFrame) +
+ rtp_auth_tag_len(cs1));
+ char* rtp_packet = rtp_buffer.data<char>();
+ char original_rtp_packet[sizeof(kPcmuWithExtensionsFrame)];
+ int rtp_len = sizeof(kPcmuWithExtensionsFrame), out_len;
+ memcpy(rtp_packet, kPcmuWithExtensionsFrame, 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) + 2,
+ ++sequence_number_);
+ memcpy(original_rtp_packet, rtp_packet, rtp_len);
+
+ EXPECT_TRUE(f1_.ProtectRtp(rtp_packet, rtp_len,
+ static_cast<int>(rtp_buffer.size()),
+ &out_len));
+ EXPECT_EQ(out_len, rtp_len + rtp_auth_tag_len(cs1));
+ EXPECT_NE(0, memcmp(rtp_packet, original_rtp_packet, rtp_len));
+ CompareHeaderExtensions(rtp_packet, original_rtp_packet, encrypted_headers,
+ false);
+ EXPECT_TRUE(f2_.UnprotectRtp(rtp_packet, out_len, &out_len));
+ EXPECT_EQ(rtp_len, out_len);
+ EXPECT_EQ(0, memcmp(rtp_packet, original_rtp_packet, rtp_len));
+ CompareHeaderExtensions(rtp_packet, original_rtp_packet, encrypted_headers,
+ true);
+
+ EXPECT_TRUE(f2_.ProtectRtp(rtp_packet, rtp_len,
+ static_cast<int>(rtp_buffer.size()),
+ &out_len));
+ EXPECT_EQ(out_len, rtp_len + rtp_auth_tag_len(cs2));
+ EXPECT_NE(0, memcmp(rtp_packet, original_rtp_packet, rtp_len));
+ CompareHeaderExtensions(rtp_packet, original_rtp_packet, encrypted_headers,
+ false);
+ EXPECT_TRUE(f1_.UnprotectRtp(rtp_packet, out_len, &out_len));
+ EXPECT_EQ(rtp_len, out_len);
+ EXPECT_EQ(0, memcmp(rtp_packet, original_rtp_packet, rtp_len));
+ CompareHeaderExtensions(rtp_packet, original_rtp_packet, encrypted_headers,
+ true);
+ }
void TestProtectSetParamsDirect(bool enable_external_auth, int cs,
const uint8_t* key1, int key1_len, const uint8_t* key2, int key2_len,
const std::string& cs_name) {
+ std::vector<int> no_encrypted_headers;
EXPECT_EQ(key1_len, key2_len);
EXPECT_EQ(cs_name, rtc::SrtpCryptoSuiteToName(cs));
if (enable_external_auth) {
f1_.EnableExternalAuth();
f2_.EnableExternalAuth();
}
- EXPECT_TRUE(f1_.SetRtpParams(cs, key1, key1_len, cs, key2, key2_len));
- EXPECT_TRUE(f2_.SetRtpParams(cs, key2, key2_len, cs, key1, key1_len));
+ EXPECT_TRUE(f1_.SetRtpParams(cs, key1, key1_len, no_encrypted_headers,
+ cs, key2, key2_len, no_encrypted_headers));
+ EXPECT_TRUE(f2_.SetRtpParams(cs, key2, key2_len, no_encrypted_headers,
+ cs, key1, key1_len, no_encrypted_headers));
EXPECT_TRUE(f1_.SetRtcpParams(cs, key1, key1_len, cs, key2, key2_len));
EXPECT_TRUE(f2_.SetRtcpParams(cs, key2, key2_len, cs, key1, key1_len));
EXPECT_TRUE(f1_.IsActive());
@@ -217,6 +306,25 @@ class SrtpFilterTest : public testing::Test {
}
TestProtectUnprotect(cs_name, cs_name);
}
+ void TestProtectSetParamsDirectHeaderEncryption(int cs,
+ const uint8_t* key1, int key1_len, const uint8_t* key2, int key2_len,
+ const std::string& cs_name) {
+ std::vector<int> encrypted_headers;
+ encrypted_headers.push_back(1);
+ // Don't encrypt header ids 2 and 3.
+ encrypted_headers.push_back(4);
+ EXPECT_EQ(key1_len, key2_len);
+ EXPECT_EQ(cs_name, rtc::SrtpCryptoSuiteToName(cs));
+ EXPECT_TRUE(f1_.SetRtpParams(cs, key1, key1_len, encrypted_headers,
+ cs, key2, key2_len, encrypted_headers));
+ EXPECT_TRUE(f2_.SetRtpParams(cs, key2, key2_len, encrypted_headers,
+ cs, key1, key1_len, encrypted_headers));
+ EXPECT_TRUE(f1_.IsActive());
+ EXPECT_TRUE(f2_.IsActive());
+ EXPECT_FALSE(f1_.IsExternalAuthActive());
+ EXPECT_FALSE(f2_.IsExternalAuthActive());
+ TestProtectUnprotectHeaderEncryption(cs_name, cs_name, encrypted_headers);
+ }
cricket::SrtpFilter f1_;
cricket::SrtpFilter f2_;
int sequence_number_;
@@ -619,6 +727,13 @@ TEST_P(SrtpFilterProtectSetParamsDirectTest, Test_AES_CM_128_HMAC_SHA1_80) {
CS_AES_CM_128_HMAC_SHA1_80);
}
+TEST_F(SrtpFilterTest,
+ TestProtectSetParamsDirectHeaderEncryption_AES_CM_128_HMAC_SHA1_80) {
+ TestProtectSetParamsDirectHeaderEncryption(rtc::SRTP_AES128_CM_SHA1_80,
+ kTestKey1, kTestKeyLen, kTestKey2, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_80);
+}
+
// Test directly setting the params with AES_CM_128_HMAC_SHA1_32.
TEST_P(SrtpFilterProtectSetParamsDirectTest, Test_AES_CM_128_HMAC_SHA1_32) {
bool enable_external_auth = GetParam();
@@ -627,6 +742,13 @@ TEST_P(SrtpFilterProtectSetParamsDirectTest, Test_AES_CM_128_HMAC_SHA1_32) {
CS_AES_CM_128_HMAC_SHA1_32);
}
+TEST_F(SrtpFilterTest,
+ TestProtectSetParamsDirectHeaderEncryption_AES_CM_128_HMAC_SHA1_32) {
+ TestProtectSetParamsDirectHeaderEncryption(rtc::SRTP_AES128_CM_SHA1_32,
+ kTestKey1, kTestKeyLen, kTestKey2, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_32);
+}
+
// Test directly setting the params with SRTP_AEAD_AES_128_GCM.
TEST_P(SrtpFilterProtectSetParamsDirectTest, Test_SRTP_AEAD_AES_128_GCM) {
bool enable_external_auth = GetParam();
@@ -635,6 +757,13 @@ TEST_P(SrtpFilterProtectSetParamsDirectTest, Test_SRTP_AEAD_AES_128_GCM) {
CS_AEAD_AES_128_GCM);
}
+TEST_F(SrtpFilterTest,
+ TestProtectSetParamsDirectHeaderEncryption_SRTP_AEAD_AES_128_GCM) {
+ TestProtectSetParamsDirectHeaderEncryption(rtc::SRTP_AEAD_AES_128_GCM,
+ kTestKeyGcm128_1, kTestKeyGcm128Len, kTestKeyGcm128_2, kTestKeyGcm128Len,
+ CS_AEAD_AES_128_GCM);
+}
+
// Test directly setting the params with SRTP_AEAD_AES_256_GCM.
TEST_P(SrtpFilterProtectSetParamsDirectTest, Test_SRTP_AEAD_AES_256_GCM) {
bool enable_external_auth = GetParam();
@@ -643,6 +772,13 @@ TEST_P(SrtpFilterProtectSetParamsDirectTest, Test_SRTP_AEAD_AES_256_GCM) {
CS_AEAD_AES_256_GCM);
}
+TEST_F(SrtpFilterTest,
+ TestProtectSetParamsDirectHeaderEncryption_SRTP_AEAD_AES_256_GCM) {
+ TestProtectSetParamsDirectHeaderEncryption(rtc::SRTP_AEAD_AES_256_GCM,
+ kTestKeyGcm256_1, kTestKeyGcm256Len, kTestKeyGcm256_2, kTestKeyGcm256Len,
+ CS_AEAD_AES_256_GCM);
+}
+
// Run all tests both with and without external auth enabled.
INSTANTIATE_TEST_CASE_P(ExternalAuth,
SrtpFilterProtectSetParamsDirectTest,
@@ -650,9 +786,11 @@ INSTANTIATE_TEST_CASE_P(ExternalAuth,
// Test directly setting the params with bogus keys.
TEST_F(SrtpFilterTest, TestSetParamsKeyTooShort) {
+ std::vector<int> no_encrypted_headers;
EXPECT_FALSE(f1_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1,
- kTestKeyLen - 1, rtc::SRTP_AES128_CM_SHA1_80,
- kTestKey1, kTestKeyLen - 1));
+ kTestKeyLen - 1, no_encrypted_headers,
+ rtc::SRTP_AES128_CM_SHA1_80, kTestKey1,
+ kTestKeyLen - 1, no_encrypted_headers));
EXPECT_FALSE(f1_.SetRtcpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1,
kTestKeyLen - 1, rtc::SRTP_AES128_CM_SHA1_80,
kTestKey1, kTestKeyLen - 1));
@@ -704,30 +842,44 @@ class SrtpSessionTest : public testing::Test {
// Test that we can set up the session and keys properly.
TEST_F(SrtpSessionTest, TestGoodSetup) {
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
- EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
+ std::vector<int> no_encrypted_headers;
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
+ EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
}
// Test that we can't change the keys once set.
TEST_F(SrtpSessionTest, TestBadSetup) {
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
- EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
+ std::vector<int> no_encrypted_headers;
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
+ EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
EXPECT_FALSE(
- s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen));
+ s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen,
+ no_encrypted_headers));
EXPECT_FALSE(
- s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen));
+ s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen,
+ no_encrypted_headers));
}
// Test that we fail keys of the wrong length.
TEST_F(SrtpSessionTest, TestKeysTooShort) {
- EXPECT_FALSE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, 1));
- EXPECT_FALSE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, 1));
+ std::vector<int> no_encrypted_headers;
+ EXPECT_FALSE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, 1,
+ no_encrypted_headers));
+ EXPECT_FALSE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, 1,
+ no_encrypted_headers));
}
// Test that we can encrypt and decrypt RTP/RTCP using AES_CM_128_HMAC_SHA1_80.
TEST_F(SrtpSessionTest, TestProtect_AES_CM_128_HMAC_SHA1_80) {
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
- EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
+ std::vector<int> no_encrypted_headers;
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
+ EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_80);
TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_80);
TestUnprotectRtp(CS_AES_CM_128_HMAC_SHA1_80);
@@ -736,8 +888,11 @@ TEST_F(SrtpSessionTest, TestProtect_AES_CM_128_HMAC_SHA1_80) {
// Test that we can encrypt and decrypt RTP/RTCP using AES_CM_128_HMAC_SHA1_32.
TEST_F(SrtpSessionTest, TestProtect_AES_CM_128_HMAC_SHA1_32) {
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen));
- EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen));
+ std::vector<int> no_encrypted_headers;
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
+ EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_32);
TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_32);
TestUnprotectRtp(CS_AES_CM_128_HMAC_SHA1_32);
@@ -745,7 +900,9 @@ TEST_F(SrtpSessionTest, TestProtect_AES_CM_128_HMAC_SHA1_32) {
}
TEST_F(SrtpSessionTest, TestGetSendStreamPacketIndex) {
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen));
+ std::vector<int> no_encrypted_headers;
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
int64_t index;
int out_len = 0;
EXPECT_TRUE(s1_.ProtectRtp(rtp_packet_, rtp_len_,
@@ -757,9 +914,12 @@ TEST_F(SrtpSessionTest, TestGetSendStreamPacketIndex) {
// Test that we fail to unprotect if someone tampers with the RTP/RTCP paylaods.
TEST_F(SrtpSessionTest, TestTamperReject) {
+ std::vector<int> no_encrypted_headers;
int out_len;
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
- EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
+ EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_80);
TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_80);
rtp_packet_[0] = 0x12;
@@ -770,17 +930,22 @@ TEST_F(SrtpSessionTest, TestTamperReject) {
// Test that we fail to unprotect if the payloads are not authenticated.
TEST_F(SrtpSessionTest, TestUnencryptReject) {
+ std::vector<int> no_encrypted_headers;
int out_len;
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
- EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
+ EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
EXPECT_FALSE(s2_.UnprotectRtp(rtp_packet_, rtp_len_, &out_len));
EXPECT_FALSE(s2_.UnprotectRtcp(rtcp_packet_, rtcp_len_, &out_len));
}
// Test that we fail when using buffers that are too small.
TEST_F(SrtpSessionTest, TestBuffersTooSmall) {
+ std::vector<int> no_encrypted_headers;
int out_len;
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
EXPECT_FALSE(s1_.ProtectRtp(rtp_packet_, rtp_len_,
sizeof(rtp_packet_) - 10, &out_len));
EXPECT_FALSE(s1_.ProtectRtcp(rtcp_packet_, rtcp_len_,
@@ -788,14 +953,17 @@ TEST_F(SrtpSessionTest, TestBuffersTooSmall) {
}
TEST_F(SrtpSessionTest, TestReplay) {
+ std::vector<int> no_encrypted_headers;
static const uint16_t kMaxSeqnum = static_cast<uint16_t>(-1);
static const uint16_t seqnum_big = 62275;
static const uint16_t seqnum_small = 10;
static const uint16_t replay_window = 1024;
int out_len;
- EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
- EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen));
+ EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
+ EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
+ no_encrypted_headers));
// Initial sequence number.
rtc::SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2, seqnum_big);

Powered by Google App Engine
This is Rietveld 408576698