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

The existing methods SetEncrypedHeaderExtensionIds in SrtpTransport and SrtpSession are removed because those methods could be confusing. When these methods are called the head extension IDs are not actually updated and the user need to call SetRtpParams again to make that happen. The existing setter just caches the new IDs. To make it less confusing, the SetEncryptedHeaderExtensionIds is removed and the new extension IDs will be set immediately when setting the crypto params. For SDES, the crypto params and the header extension IDs will be set at the same time. For DTLS, the new header extensions are cached in BaseChannel and will be set when the DTLS handshake is completed. Another major change is that when doing DTLS-SRTP, the encrypted header extension IDs will be updated only when they are changed. Bug: webrtc:7013 Change-Id: Ib70d4797456ae5ecb61b3dfff15c7e3e7ede89bd Reviewed-on: https://webrtc-review.googlesource.com/15860 Commit-Queue: Zhi Huang <zhihuang@webrtc.org> Reviewed-by: Peter Thatcher <pthatcher@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20639}
226 lines
9.3 KiB
C++
226 lines
9.3 KiB
C++
/*
|
|
* Copyright 2004 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/srtpsession.h"
|
|
|
|
#include <string>
|
|
|
|
#include "media/base/fakertp.h"
|
|
#include "pc/srtptestutil.h"
|
|
#include "rtc_base/gunit.h"
|
|
#include "rtc_base/sslstreamadapter.h" // For rtc::SRTP_*
|
|
|
|
namespace rtc {
|
|
|
|
std::vector<int> kEncryptedHeaderExtensionIds;
|
|
|
|
class SrtpSessionTest : public testing::Test {
|
|
protected:
|
|
virtual void SetUp() {
|
|
rtp_len_ = sizeof(kPcmuFrame);
|
|
rtcp_len_ = sizeof(kRtcpReport);
|
|
memcpy(rtp_packet_, kPcmuFrame, rtp_len_);
|
|
memcpy(rtcp_packet_, kRtcpReport, rtcp_len_);
|
|
}
|
|
void TestProtectRtp(const std::string& cs) {
|
|
int out_len = 0;
|
|
EXPECT_TRUE(
|
|
s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_), &out_len));
|
|
EXPECT_EQ(out_len, rtp_len_ + rtp_auth_tag_len(cs));
|
|
EXPECT_NE(0, memcmp(rtp_packet_, kPcmuFrame, rtp_len_));
|
|
rtp_len_ = out_len;
|
|
}
|
|
void TestProtectRtcp(const std::string& cs) {
|
|
int out_len = 0;
|
|
EXPECT_TRUE(s1_.ProtectRtcp(rtcp_packet_, rtcp_len_, sizeof(rtcp_packet_),
|
|
&out_len));
|
|
EXPECT_EQ(out_len, rtcp_len_ + 4 + rtcp_auth_tag_len(cs)); // NOLINT
|
|
EXPECT_NE(0, memcmp(rtcp_packet_, kRtcpReport, rtcp_len_));
|
|
rtcp_len_ = out_len;
|
|
}
|
|
void TestUnprotectRtp(const std::string& cs) {
|
|
int out_len = 0, expected_len = sizeof(kPcmuFrame);
|
|
EXPECT_TRUE(s2_.UnprotectRtp(rtp_packet_, rtp_len_, &out_len));
|
|
EXPECT_EQ(expected_len, out_len);
|
|
EXPECT_EQ(0, memcmp(rtp_packet_, kPcmuFrame, out_len));
|
|
}
|
|
void TestUnprotectRtcp(const std::string& cs) {
|
|
int out_len = 0, expected_len = sizeof(kRtcpReport);
|
|
EXPECT_TRUE(s2_.UnprotectRtcp(rtcp_packet_, rtcp_len_, &out_len));
|
|
EXPECT_EQ(expected_len, out_len);
|
|
EXPECT_EQ(0, memcmp(rtcp_packet_, kRtcpReport, out_len));
|
|
}
|
|
cricket::SrtpSession s1_;
|
|
cricket::SrtpSession s2_;
|
|
char rtp_packet_[sizeof(kPcmuFrame) + 10];
|
|
char rtcp_packet_[sizeof(kRtcpReport) + 4 + 10];
|
|
int rtp_len_;
|
|
int rtcp_len_;
|
|
};
|
|
|
|
// Test that we can set up the session and keys properly.
|
|
TEST_F(SrtpSessionTest, TestGoodSetup) {
|
|
EXPECT_TRUE(s1_.SetSend(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_TRUE(s2_.SetRecv(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
}
|
|
|
|
// Test that we can't change the keys once set.
|
|
TEST_F(SrtpSessionTest, TestBadSetup) {
|
|
EXPECT_TRUE(s1_.SetSend(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_TRUE(s2_.SetRecv(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_FALSE(s1_.SetSend(SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_FALSE(s2_.SetRecv(SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
}
|
|
|
|
// Test that we fail keys of the wrong length.
|
|
TEST_F(SrtpSessionTest, TestKeysTooShort) {
|
|
EXPECT_FALSE(s1_.SetSend(SRTP_AES128_CM_SHA1_80, kTestKey1, 1,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_FALSE(s2_.SetRecv(SRTP_AES128_CM_SHA1_80, kTestKey1, 1,
|
|
kEncryptedHeaderExtensionIds));
|
|
}
|
|
|
|
// 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(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_TRUE(s2_.SetRecv(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_80);
|
|
TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_80);
|
|
TestUnprotectRtp(CS_AES_CM_128_HMAC_SHA1_80);
|
|
TestUnprotectRtcp(CS_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(SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_TRUE(s2_.SetRecv(SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_32);
|
|
TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_32);
|
|
TestUnprotectRtp(CS_AES_CM_128_HMAC_SHA1_32);
|
|
TestUnprotectRtcp(CS_AES_CM_128_HMAC_SHA1_32);
|
|
}
|
|
|
|
TEST_F(SrtpSessionTest, TestGetSendStreamPacketIndex) {
|
|
EXPECT_TRUE(s1_.SetSend(SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
int64_t index;
|
|
int out_len = 0;
|
|
EXPECT_TRUE(s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_),
|
|
&out_len, &index));
|
|
// |index| will be shifted by 16.
|
|
int64_t be64_index = static_cast<int64_t>(NetworkToHost64(1 << 16));
|
|
EXPECT_EQ(be64_index, index);
|
|
}
|
|
|
|
// Test that we fail to unprotect if someone tampers with the RTP/RTCP paylaods.
|
|
TEST_F(SrtpSessionTest, TestTamperReject) {
|
|
int out_len;
|
|
EXPECT_TRUE(s1_.SetSend(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_TRUE(s2_.SetRecv(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_80);
|
|
TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_80);
|
|
rtp_packet_[0] = 0x12;
|
|
rtcp_packet_[1] = 0x34;
|
|
EXPECT_FALSE(s2_.UnprotectRtp(rtp_packet_, rtp_len_, &out_len));
|
|
EXPECT_FALSE(s2_.UnprotectRtcp(rtcp_packet_, rtcp_len_, &out_len));
|
|
}
|
|
|
|
// Test that we fail to unprotect if the payloads are not authenticated.
|
|
TEST_F(SrtpSessionTest, TestUnencryptReject) {
|
|
int out_len;
|
|
EXPECT_TRUE(s1_.SetSend(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_TRUE(s2_.SetRecv(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
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) {
|
|
int out_len;
|
|
EXPECT_TRUE(s1_.SetSend(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_FALSE(s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_) - 10,
|
|
&out_len));
|
|
EXPECT_FALSE(s1_.ProtectRtcp(rtcp_packet_, rtcp_len_,
|
|
sizeof(rtcp_packet_) - 14, &out_len));
|
|
}
|
|
|
|
TEST_F(SrtpSessionTest, TestReplay) {
|
|
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(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
EXPECT_TRUE(s2_.SetRecv(SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen,
|
|
kEncryptedHeaderExtensionIds));
|
|
|
|
// Initial sequence number.
|
|
SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2, seqnum_big);
|
|
EXPECT_TRUE(
|
|
s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_), &out_len));
|
|
|
|
// Replay within the 1024 window should succeed.
|
|
SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2,
|
|
seqnum_big - replay_window + 1);
|
|
EXPECT_TRUE(
|
|
s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_), &out_len));
|
|
|
|
// Replay out side of the 1024 window should fail.
|
|
SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2,
|
|
seqnum_big - replay_window - 1);
|
|
EXPECT_FALSE(
|
|
s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_), &out_len));
|
|
|
|
// Increment sequence number to a small number.
|
|
SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2, seqnum_small);
|
|
EXPECT_TRUE(
|
|
s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_), &out_len));
|
|
|
|
// Replay around 0 but out side of the 1024 window should fail.
|
|
SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2,
|
|
kMaxSeqnum + seqnum_small - replay_window - 1);
|
|
EXPECT_FALSE(
|
|
s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_), &out_len));
|
|
|
|
// Replay around 0 but within the 1024 window should succeed.
|
|
for (uint16_t seqnum = 65000; seqnum < 65003; ++seqnum) {
|
|
SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2, seqnum);
|
|
EXPECT_TRUE(
|
|
s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_), &out_len));
|
|
}
|
|
|
|
// Go back to normal sequence nubmer.
|
|
// NOTE: without the fix in libsrtp, this would fail. This is because
|
|
// without the fix, the loop above would keep incrementing local sequence
|
|
// number in libsrtp, eventually the new sequence number would go out side
|
|
// of the window.
|
|
SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2, seqnum_small + 1);
|
|
EXPECT_TRUE(
|
|
s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_), &out_len));
|
|
}
|
|
|
|
} // namespace rtc
|