Support GCM ciphers even if ENABLE_EXTERNAL_AUTH is defined.

With ENABLE_EXTERNAL_AUTH, external auth will only be used depending
on the selected cipher (allowed for non-GCM, not allowed for GCM).

BUG=webrtc:5222, chromium:628400

Review-Url: https://codereview.webrtc.org/2720663003
Cr-Commit-Position: refs/heads/master@{#16955}
This commit is contained in:
jbauch 2017-03-01 15:34:36 -08:00 committed by Commit bot
parent 0c003776a9
commit d48f488bed
6 changed files with 165 additions and 50 deletions

View File

@ -55,7 +55,7 @@ rtc_static_library("rtc_pc") {
"../media",
]
if (build_with_chromium) {
if (rtc_enable_external_auth) {
sources += [
"externalhmac.cc",
"externalhmac.h",

View File

@ -740,22 +740,27 @@ bool BaseChannel::SendPacket(bool rtcp,
res = srtp_filter_.ProtectRtp(
data, len, static_cast<int>(packet->capacity()), &len);
#else
updated_options.packet_time_params.rtp_sendtime_extension_id =
rtp_abs_sendtime_extn_id_;
res = srtp_filter_.ProtectRtp(
data, len, static_cast<int>(packet->capacity()), &len,
&updated_options.packet_time_params.srtp_packet_index);
// If protection succeeds, let's get auth params from srtp.
if (res) {
uint8_t* auth_key = NULL;
int key_len;
res = srtp_filter_.GetRtpAuthParams(
&auth_key, &key_len,
&updated_options.packet_time_params.srtp_auth_tag_len);
if (!srtp_filter_.IsExternalAuthActive()) {
res = srtp_filter_.ProtectRtp(
data, len, static_cast<int>(packet->capacity()), &len);
} else {
updated_options.packet_time_params.rtp_sendtime_extension_id =
rtp_abs_sendtime_extn_id_;
res = srtp_filter_.ProtectRtp(
data, len, static_cast<int>(packet->capacity()), &len,
&updated_options.packet_time_params.srtp_packet_index);
// If protection succeeds, let's get auth params from srtp.
if (res) {
updated_options.packet_time_params.srtp_auth_key.resize(key_len);
updated_options.packet_time_params.srtp_auth_key.assign(
auth_key, auth_key + key_len);
uint8_t* auth_key = NULL;
int key_len;
res = srtp_filter_.GetRtpAuthParams(
&auth_key, &key_len,
&updated_options.packet_time_params.srtp_auth_tag_len);
if (res) {
updated_options.packet_time_params.srtp_auth_key.resize(key_len);
updated_options.packet_time_params.srtp_auth_key.assign(
auth_key, auth_key + key_len);
}
}
}
#endif

View File

@ -101,14 +101,6 @@ bool ChannelManager::SetCryptoOptions_w(
LOG(LS_WARNING) << "Not changing crypto options in existing channels.";
}
crypto_options_ = crypto_options;
#if defined(ENABLE_EXTERNAL_AUTH)
if (crypto_options_.enable_gcm_crypto_suites) {
// TODO(jbauch): Re-enable once https://crbug.com/628400 is resolved.
crypto_options_.enable_gcm_crypto_suites = false;
LOG(LS_WARNING) << "GCM ciphers are not supported with " <<
"ENABLE_EXTERNAL_AUTH and will be disabled.";
}
#endif
return true;
}

View File

@ -21,6 +21,7 @@
#include "webrtc/base/byteorder.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/sslstreamadapter.h"
#include "webrtc/base/stringencode.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/media/base/rtputils.h"
@ -225,6 +226,18 @@ bool SrtpFilter::GetSrtpOverhead(int* srtp_overhead) const {
return true;
}
#if defined(ENABLE_EXTERNAL_AUTH)
bool SrtpFilter::IsExternalAuthActive() const {
if (!IsActive()) {
LOG(LS_WARNING) << "Failed to check IsExternalAuthActive: SRTP not active";
return false;
}
RTC_CHECK(send_session_);
return send_session_->IsExternalAuthActive();
}
#endif
void SrtpFilter::set_signal_silent_time(int signal_silent_time_in_ms) {
signal_silent_time_in_ms_ = signal_silent_time_in_ms;
if (IsActive()) {
@ -462,12 +475,7 @@ bool SrtpSession::inited_ = false;
// This lock protects SrtpSession::inited_.
rtc::GlobalLockPod SrtpSession::lock_;
SrtpSession::SrtpSession()
: session_(nullptr),
rtp_auth_tag_len_(0),
rtcp_auth_tag_len_(0),
srtp_stat_(new SrtpStat()),
last_send_seq_num_(-1) {
SrtpSession::SrtpSession() : srtp_stat_(new SrtpStat()) {
SignalSrtpError.repeat(srtp_stat_->SignalSrtpError);
}
@ -593,6 +601,11 @@ bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
bool SrtpSession::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) {
#if defined(ENABLE_EXTERNAL_AUTH)
RTC_DCHECK(thread_checker_.CalledOnValidThread());
RTC_DCHECK(IsExternalAuthActive());
if (!IsExternalAuthActive()) {
return false;
}
ExternalHmacContext* external_hmac = nullptr;
// stream_template will be the reference context for other streams.
// Let's use it for getting the keys.
@ -620,6 +633,12 @@ int SrtpSession::GetSrtpOverhead() const {
return rtp_auth_tag_len_;
}
#if defined(ENABLE_EXTERNAL_AUTH)
bool SrtpSession::IsExternalAuthActive() const {
return external_auth_active_;
}
#endif
bool SrtpSession::GetSendStreamPacketIndex(void* p,
int in_len,
int64_t* index) {
@ -662,15 +681,12 @@ bool SrtpSession::SetKey(int type, int cs, const uint8_t* key, size_t len) {
// RTP HMAC is shortened to 32 bits, but RTCP remains 80 bits.
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
#if !defined(ENABLE_EXTERNAL_AUTH)
// TODO(jbauch): Re-enable once https://crbug.com/628400 is resolved.
} else if (cs == rtc::SRTP_AEAD_AES_128_GCM) {
srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
} else if (cs == rtc::SRTP_AEAD_AES_256_GCM) {
srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp);
#endif // ENABLE_EXTERNAL_AUTH
} else {
LOG(LS_WARNING) << "Failed to create SRTP session: unsupported"
<< " cipher_suite " << cs;
@ -704,8 +720,9 @@ bool SrtpSession::SetKey(int type, int cs, const uint8_t* key, size_t len) {
// We want to set this option only for rtp packets.
// By default policy structure is initialized to HMAC_SHA1.
#if defined(ENABLE_EXTERNAL_AUTH)
// Enable external HMAC authentication only for outgoing streams.
if (type == ssrc_any_outbound) {
// Enable external HMAC authentication only for outgoing streams and only
// for cipher suites that support it (i.e. only non-GCM cipher suites).
if (type == ssrc_any_outbound && !rtc::IsGcmCryptoSuite(cs)) {
policy.rtp.auth_type = EXTERNAL_HMAC_SHA1;
}
#endif
@ -721,6 +738,9 @@ bool SrtpSession::SetKey(int type, int cs, const uint8_t* key, size_t len) {
srtp_set_user_data(session_, this);
rtp_auth_tag_len_ = policy.rtp.auth_tag_len;
rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len;
#if defined(ENABLE_EXTERNAL_AUTH)
external_auth_active_ = (policy.rtp.auth_type == EXTERNAL_HMAC_SHA1);
#endif
return true;
}

View File

@ -114,6 +114,13 @@ class SrtpFilter {
// Returns srtp overhead for rtp packets.
bool GetSrtpOverhead(int* srtp_overhead) const;
#if defined(ENABLE_EXTERNAL_AUTH)
// A SRTP filter supports external creation of the auth tag if a non-GCM
// cipher is used. This method is only valid after the RTP params have
// been set.
bool IsExternalAuthActive() const;
#endif
// Update the silent threshold (in ms) for signaling errors.
void set_signal_silent_time(int signal_silent_time_in_ms);
@ -206,6 +213,13 @@ class SrtpSession {
int GetSrtpOverhead() const;
#if defined(ENABLE_EXTERNAL_AUTH)
// A SRTP session supports external creation of the auth tag if a non-GCM
// cipher is used. This method is only valid after the RTP params have
// been set.
bool IsExternalAuthActive() const;
#endif
// Update the silent threshold (in ms) for signaling errors.
void set_signal_silent_time(int signal_silent_time_in_ms);
@ -225,13 +239,16 @@ class SrtpSession {
static void HandleEventThunk(srtp_event_data_t* ev);
rtc::ThreadChecker thread_checker_;
srtp_ctx_t_* session_;
int rtp_auth_tag_len_;
int rtcp_auth_tag_len_;
srtp_ctx_t_* session_ = nullptr;
int rtp_auth_tag_len_ = 0;
int rtcp_auth_tag_len_ = 0;
std::unique_ptr<SrtpStat> srtp_stat_;
static bool inited_;
static rtc::GlobalLockPod lock_;
int last_send_seq_num_;
int last_send_seq_num_ = -1;
#if defined(ENABLE_EXTERNAL_AUTH)
bool external_auth_active_ = false;
#endif
RTC_DISALLOW_COPY_AND_ASSIGN(SrtpSession);
};

View File

@ -11,6 +11,7 @@
#include "webrtc/pc/srtpfilter.h"
#include "third_party/libsrtp/include/srtp.h"
#include "webrtc/base/buffer.h"
#include "webrtc/base/byteorder.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/gunit.h"
@ -30,6 +31,14 @@ using cricket::CS_REMOTE;
static const uint8_t kTestKey1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234";
static const uint8_t kTestKey2[] = "4321ZYXWVUTSRQPONMLKJIHGFEDCBA";
static const int kTestKeyLen = 30;
static const uint8_t kTestKeyGcm128_1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ12";
static const uint8_t kTestKeyGcm128_2[] = "21ZYXWVUTSRQPONMLKJIHGFEDCBA";
static const int kTestKeyGcm128Len = 28; // 128 bits key + 96 bits salt.
static const uint8_t kTestKeyGcm256_1[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr";
static const uint8_t kTestKeyGcm256_2[] =
"rqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA";
static const int kTestKeyGcm256Len = 44; // 256 bits key + 96 bits salt.
static const std::string kTestKeyParams1 =
"inline:WVNfX19zZW1jdGwgKCkgewkyMjA7fQp9CnVubGVz";
static const std::string kTestKeyParams2 =
@ -60,10 +69,20 @@ static const cricket::CryptoParams kTestCryptoParamsGcm4(
1, "AEAD_AES_128_GCM", kTestKeyParamsGcm4, "");
static int rtp_auth_tag_len(const std::string& cs) {
return (cs == CS_AES_CM_128_HMAC_SHA1_32) ? 4 : 10;
if (cs == CS_AES_CM_128_HMAC_SHA1_32) {
return 4;
} else if (cs == CS_AEAD_AES_128_GCM || cs == CS_AEAD_AES_256_GCM) {
return 16;
} else {
return 10;
}
}
static int rtcp_auth_tag_len(const std::string& cs) {
return 10;
if (cs == CS_AEAD_AES_128_GCM || cs == CS_AEAD_AES_256_GCM) {
return 16;
} else {
return 10;
}
}
class SrtpFilterTest : public testing::Test {
@ -89,9 +108,11 @@ class SrtpFilterTest : public testing::Test {
EXPECT_TRUE(f2_.IsActive());
}
void TestProtectUnprotect(const std::string& cs1, const std::string& cs2) {
char rtp_packet[sizeof(kPcmuFrame) + 10];
rtc::Buffer rtp_buffer(sizeof(kPcmuFrame) + rtp_auth_tag_len(cs1));
char* rtp_packet = rtp_buffer.data<char>();
char original_rtp_packet[sizeof(kPcmuFrame)];
char rtcp_packet[sizeof(kRtcpReport) + 4 + 10];
rtc::Buffer rtcp_buffer(sizeof(kRtcpReport) + 4 + rtcp_auth_tag_len(cs2));
char* rtcp_packet = rtcp_buffer.data<char>();
int rtp_len = sizeof(kPcmuFrame), rtcp_len = sizeof(kRtcpReport), out_len;
memcpy(rtp_packet, kPcmuFrame, rtp_len);
// In order to be able to run this test function multiple times we can not
@ -102,7 +123,8 @@ class SrtpFilterTest : public testing::Test {
memcpy(rtcp_packet, kRtcpReport, rtcp_len);
EXPECT_TRUE(f1_.ProtectRtp(rtp_packet, rtp_len,
sizeof(rtp_packet), &out_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));
EXPECT_TRUE(f2_.UnprotectRtp(rtp_packet, out_len, &out_len));
@ -110,7 +132,8 @@ class SrtpFilterTest : public testing::Test {
EXPECT_EQ(0, memcmp(rtp_packet, original_rtp_packet, rtp_len));
EXPECT_TRUE(f2_.ProtectRtp(rtp_packet, rtp_len,
sizeof(rtp_packet), &out_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));
EXPECT_TRUE(f1_.UnprotectRtp(rtp_packet, out_len, &out_len));
@ -118,7 +141,8 @@ class SrtpFilterTest : public testing::Test {
EXPECT_EQ(0, memcmp(rtp_packet, original_rtp_packet, rtp_len));
EXPECT_TRUE(f1_.ProtectRtcp(rtcp_packet, rtcp_len,
sizeof(rtcp_packet), &out_len));
static_cast<int>(rtcp_buffer.size()),
&out_len));
EXPECT_EQ(out_len, rtcp_len + 4 + rtcp_auth_tag_len(cs1)); // NOLINT
EXPECT_NE(0, memcmp(rtcp_packet, kRtcpReport, rtcp_len));
EXPECT_TRUE(f2_.UnprotectRtcp(rtcp_packet, out_len, &out_len));
@ -126,7 +150,8 @@ class SrtpFilterTest : public testing::Test {
EXPECT_EQ(0, memcmp(rtcp_packet, kRtcpReport, rtcp_len));
EXPECT_TRUE(f2_.ProtectRtcp(rtcp_packet, rtcp_len,
sizeof(rtcp_packet), &out_len));
static_cast<int>(rtcp_buffer.size()),
&out_len));
EXPECT_EQ(out_len, rtcp_len + 4 + rtcp_auth_tag_len(cs2)); // NOLINT
EXPECT_NE(0, memcmp(rtcp_packet, kRtcpReport, rtcp_len));
EXPECT_TRUE(f1_.UnprotectRtcp(rtcp_packet, out_len, &out_len));
@ -522,7 +547,7 @@ TEST_F(SrtpFilterTest, TestDisableEncryption) {
EXPECT_FALSE(f2_.IsActive());
}
// Test directly setting the params with AES_CM_128_HMAC_SHA1_80
// Test directly setting the params with AES_CM_128_HMAC_SHA1_80.
TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_AES_CM_128_HMAC_SHA1_80) {
EXPECT_TRUE(f1_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1,
kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_80,
@ -538,10 +563,14 @@ TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_AES_CM_128_HMAC_SHA1_80) {
kTestKey1, kTestKeyLen));
EXPECT_TRUE(f1_.IsActive());
EXPECT_TRUE(f2_.IsActive());
#if defined(ENABLE_EXTERNAL_AUTH)
EXPECT_TRUE(f1_.IsExternalAuthActive());
EXPECT_TRUE(f2_.IsExternalAuthActive());
#endif
TestProtectUnprotect(CS_AES_CM_128_HMAC_SHA1_80, CS_AES_CM_128_HMAC_SHA1_80);
}
// Test directly setting the params with AES_CM_128_HMAC_SHA1_32
// Test directly setting the params with AES_CM_128_HMAC_SHA1_32.
TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_AES_CM_128_HMAC_SHA1_32) {
EXPECT_TRUE(f1_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1,
kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_32,
@ -557,10 +586,60 @@ TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_AES_CM_128_HMAC_SHA1_32) {
kTestKey1, kTestKeyLen));
EXPECT_TRUE(f1_.IsActive());
EXPECT_TRUE(f2_.IsActive());
#if defined(ENABLE_EXTERNAL_AUTH)
EXPECT_TRUE(f1_.IsExternalAuthActive());
EXPECT_TRUE(f2_.IsExternalAuthActive());
#endif
TestProtectUnprotect(CS_AES_CM_128_HMAC_SHA1_32, CS_AES_CM_128_HMAC_SHA1_32);
}
// Test directly setting the params with bogus keys
// Test directly setting the params with SRTP_AEAD_AES_128_GCM.
TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_SRTP_AEAD_AES_128_GCM) {
EXPECT_TRUE(f1_.SetRtpParams(rtc::SRTP_AEAD_AES_128_GCM, kTestKeyGcm128_1,
kTestKeyGcm128Len, rtc::SRTP_AEAD_AES_128_GCM,
kTestKeyGcm128_2, kTestKeyGcm128Len));
EXPECT_TRUE(f2_.SetRtpParams(rtc::SRTP_AEAD_AES_128_GCM, kTestKeyGcm128_2,
kTestKeyGcm128Len, rtc::SRTP_AEAD_AES_128_GCM,
kTestKeyGcm128_1, kTestKeyGcm128Len));
EXPECT_TRUE(f1_.SetRtcpParams(rtc::SRTP_AEAD_AES_128_GCM, kTestKeyGcm128_1,
kTestKeyGcm128Len, rtc::SRTP_AEAD_AES_128_GCM,
kTestKeyGcm128_2, kTestKeyGcm128Len));
EXPECT_TRUE(f2_.SetRtcpParams(rtc::SRTP_AEAD_AES_128_GCM, kTestKeyGcm128_2,
kTestKeyGcm128Len, rtc::SRTP_AEAD_AES_128_GCM,
kTestKeyGcm128_1, kTestKeyGcm128Len));
EXPECT_TRUE(f1_.IsActive());
EXPECT_TRUE(f2_.IsActive());
#if defined(ENABLE_EXTERNAL_AUTH)
EXPECT_FALSE(f1_.IsExternalAuthActive());
EXPECT_FALSE(f2_.IsExternalAuthActive());
#endif
TestProtectUnprotect(CS_AEAD_AES_128_GCM, CS_AEAD_AES_128_GCM);
}
// Test directly setting the params with SRTP_AEAD_AES_256_GCM.
TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_SRTP_AEAD_AES_256_GCM) {
EXPECT_TRUE(f1_.SetRtpParams(rtc::SRTP_AEAD_AES_256_GCM, kTestKeyGcm256_1,
kTestKeyGcm256Len, rtc::SRTP_AEAD_AES_256_GCM,
kTestKeyGcm256_2, kTestKeyGcm256Len));
EXPECT_TRUE(f2_.SetRtpParams(rtc::SRTP_AEAD_AES_256_GCM, kTestKeyGcm256_2,
kTestKeyGcm256Len, rtc::SRTP_AEAD_AES_256_GCM,
kTestKeyGcm256_1, kTestKeyGcm256Len));
EXPECT_TRUE(f1_.SetRtcpParams(rtc::SRTP_AEAD_AES_256_GCM, kTestKeyGcm256_1,
kTestKeyGcm256Len, rtc::SRTP_AEAD_AES_256_GCM,
kTestKeyGcm256_2, kTestKeyGcm256Len));
EXPECT_TRUE(f2_.SetRtcpParams(rtc::SRTP_AEAD_AES_256_GCM, kTestKeyGcm256_2,
kTestKeyGcm256Len, rtc::SRTP_AEAD_AES_256_GCM,
kTestKeyGcm256_1, kTestKeyGcm256Len));
EXPECT_TRUE(f1_.IsActive());
EXPECT_TRUE(f2_.IsActive());
#if defined(ENABLE_EXTERNAL_AUTH)
EXPECT_FALSE(f1_.IsExternalAuthActive());
EXPECT_FALSE(f2_.IsExternalAuthActive());
#endif
TestProtectUnprotect(CS_AEAD_AES_256_GCM, CS_AEAD_AES_256_GCM);
}
// Test directly setting the params with bogus keys.
TEST_F(SrtpFilterTest, TestSetParamsKeyTooShort) {
EXPECT_FALSE(f1_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1,
kTestKeyLen - 1, rtc::SRTP_AES128_CM_SHA1_80,
@ -578,6 +657,8 @@ TEST_F(SrtpFilterTest, TestGetSendAuthParams) {
EXPECT_TRUE(f1_.SetRtcpParams(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1,
kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_32,
kTestKey2, kTestKeyLen));
// Non-GCM ciphers support external auth.
EXPECT_TRUE(f1_.IsExternalAuthActive());
uint8_t* auth_key = NULL;
int auth_key_len = 0, auth_tag_len = 0;
EXPECT_TRUE(f1_.GetRtpAuthParams(&auth_key, &auth_key_len, &auth_tag_len));