webrtc/video_engine/main/source/vie_encryption_impl.cc

544 lines
20 KiB
C++

/*
* Copyright (c) 2011 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.
*/
/*
* vie_encryption_impl.cc
*/
#include "vie_encryption_impl.h"
// Defines
#include "vie_defines.h"
#include "vie_errors.h"
#include "vie_channel.h"
#include "vie_channel_manager.h"
#include "trace.h"
#include "vie_impl.h"
#ifdef WEBRTC_SRTP
#include "SrtpModule.h"
#endif
namespace webrtc
{
// ----------------------------------------------------------------------------
// GetInterface
// ----------------------------------------------------------------------------
ViEEncryption* ViEEncryption::GetInterface(VideoEngine* videoEngine)
{
#ifdef WEBRTC_VIDEO_ENGINE_ENCRYPTION_API
if (videoEngine == NULL)
{
return NULL;
}
VideoEngineImpl* vieImpl = reinterpret_cast<VideoEngineImpl*> (videoEngine);
ViEEncryptionImpl* vieEncryptionImpl = vieImpl;
(*vieEncryptionImpl)++; // Increase ref count
return vieEncryptionImpl;
#else
return NULL;
#endif
}
// ----------------------------------------------------------------------------
// Release
//
// Releases the interface, i.e. reduces the reference counter. The number of
// remaining references is returned, -1 if released too many times.
// ----------------------------------------------------------------------------
int ViEEncryptionImpl::Release()
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId,
"ViEEncryptionImpl::Release()");
(*this)--; // Decrease ref count
WebRtc_Word32 refCount = GetCount();
if (refCount < 0)
{
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId,
"ViEEncryptionImpl release too many times");
SetLastError(kViEAPIDoesNotExist);
return -1;
}
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId,
"ViEEncryptionImpl reference count: %d", refCount);
return refCount;
}
// ----------------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------------
ViEEncryptionImpl::ViEEncryptionImpl()
{
WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId,
"ViEEncryptionImpl::ViEEncryptionImpl() Ctor");
}
// ----------------------------------------------------------------------------
// Destructor
// ----------------------------------------------------------------------------
ViEEncryptionImpl::~ViEEncryptionImpl()
{
WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId,
"ViEEncryptionImpl::~ViEEncryptionImpl() Dtor");
}
// ============================================================================
// SRTP
// ============================================================================
// ----------------------------------------------------------------------------
// EnableSRTPSend
//
// ----------------------------------------------------------------------------
int ViEEncryptionImpl::EnableSRTPSend(
const int videoChannel, const CipherTypes cipherType,
const unsigned int cipherKeyLength, const AuthenticationTypes authType,
const unsigned int authKeyLength, const unsigned int authTagLength,
const SecurityLevels level, const unsigned char key[kViEMaxSrtpKeyLength],
const bool useForRTCP)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId,
"EnableSRTPSend(channel=%d, cipherType=%d, cipherKeyLength=%d, "
"authType=%d, authKeyLength=%d, authTagLength=%d, level=%d, "
"key=?, RTCP=%s",
videoChannel, cipherType, cipherKeyLength, authType,
authKeyLength, authTagLength, level,
useForRTCP ? "true" : "false");
#ifdef WEBRTC_SRTP
if (!IsInitialized())
{
SetLastError(kViENotInitialized);
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s - ViE instance %d not initialized", __FUNCTION__,
_instanceId);
return -1;
}
bool cipherAllZero = (kCipherNull == cipherType) && (0 == cipherKeyLength);
bool authAllZero = (kAuthNull == authType) &&
(0 == authKeyLength) &&
(0 == authTagLength);
// 1. For no protection all cipher and auth must be zero
// 2. For encryption only all auth must be zero
// 3. For authentication only all cipher must be zero
if (((kNoProtection == level) && (!cipherAllZero || !authAllZero))
|| ((kEncryption == level) && !authAllZero)
|| ((kAuthentication == level) && !cipherAllZero))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
" Invalid input argument");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
// 16 <= cipherKeyLength <= 256
if (((kEncryption == level) || (kEncryptionAndAuthentication == level))
&& ((cipherKeyLength < kViEMinSrtpEncryptLength)
|| (cipherKeyLength > kViEMaxSrtpEncryptLength)))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
" Invalid cipher key length");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
// For HMAC_SHA1 auth:
// authKeyLength <= 20, authTagLength <= 20
if (((kAuthentication == level) || (kEncryptionAndAuthentication == level))
&& (kAuthHmacSha1 == authType)
&& ((authKeyLength > kViEMaxSrtpAuthSh1Length)
|| (authTagLength > kViEMaxSrtpAuthSh1Length)))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
" Invalid auth key or tag length");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
// For NULL auth:
// authKeyLength <= 256, authTagLength <= 12
if (((kAuthentication == level) || (kEncryptionAndAuthentication == level))
&& (kAuthNull == authType)
&& ((authKeyLength > kViEMaxSrtpKeyAuthNullLength)
|| (authTagLength > kViEMaxSrtpTagAuthNullLength)))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
" Invalid auth key or tag length");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
if (!key)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
" key NULL pointer");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
const SrtpModule::CipherTypes cipher_type =
static_cast<const SrtpModule::CipherTypes> (cipherType);
const SrtpModule::AuthenticationTypes auth_type =
static_cast<const SrtpModule::AuthenticationTypes> (authType);
const SrtpModule::SecurityLevels security_level =
static_cast<const SrtpModule::SecurityLevels> (level);
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* vieChannel = cs.Channel(videoChannel);
if (vieChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s: No channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEEncryptionInvalidChannelId);
return -1;
}
if (0 != vieChannel->EnableSRTPSend(cipher_type, cipherKeyLength, auth_type,
authKeyLength, authTagLength,
security_level, key, useForRTCP))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
"Failed to configure SRTP Encryption for sending");
SetLastError(kViEEncryptionUnknownError);
return -1;
}
WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, _instanceId,
"SRTP Enabled for sending");
return 0;
#else
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVoice,
ViEId(_instanceId, videoChannel),
" _SRTP is undefined => _lastError = %d",
LastErrorInternal());
SetLastError(kViEEncryptionSrtpNotSupported);
return -1;
#endif
}
// ----------------------------------------------------------------------------
// DisableSRTPSend
//
// ----------------------------------------------------------------------------
int ViEEncryptionImpl::DisableSRTPSend(const int videoChannel)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"DisableSRTPSend(videoChannel=%d)", videoChannel);
#ifdef WEBRTC_SRTP
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* vieChannel = cs.Channel(videoChannel);
if (vieChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s: No channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEEncryptionInvalidChannelId);
return -1;
}
if (0 != vieChannel->DisableSRTPSend())
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"Failed to Disable SRTP Encryption for sending");
SetLastError(kViEEncryptionUnknownError);
return -1;
}
WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"SRTP Disabled for sending");
return 0;
#else
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVoice,
ViEId(_instanceId, videoChannel),
" _SRTP is undefined => _lastError = %d",
LastErrorInternal());
SetLastError(kViEEncryptionSrtpNotSupported);
return -1;
#endif
}
// ----------------------------------------------------------------------------
// EnableSRTPReceive
//
// ----------------------------------------------------------------------------
int ViEEncryptionImpl::EnableSRTPReceive(
const int videoChannel, const CipherTypes cipherType,
const unsigned int cipherKeyLength, const AuthenticationTypes authType,
const unsigned int authKeyLength, const unsigned int authTagLength,
const SecurityLevels level,
const unsigned char key[kViEMaxSrtpKeyLength], const bool useForRTCP)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"EnableSRTPReceive(channel=%d, cipherType=%d, "
"cipherKeyLength=%d, authType=%d, authKeyLength=%d, "
"authTagLength=%d, level=%d, key=?, RTCP=%s)",
videoChannel, cipherType, cipherKeyLength, authType,
authKeyLength, authTagLength, level,
useForRTCP ? "true" : "false");
#ifdef WEBRTC_SRTP
if (!IsInitialized())
{
SetLastError(kViENotInitialized);
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s - ViE instance %d not initialized", __FUNCTION__,
_instanceId);
return -1;
}
bool cipherAllZero = (kCipherNull == cipherType) && (0 == cipherKeyLength);
bool authAllZero = (kAuthNull == authType)
&& (0 == authKeyLength)
&& (0 == authTagLength);
// 1. For no protection all cipher and auth must be zero
// 2. For encryption only all auth must be zero
// 3. For authentication only all cipher must be zero
if (((kNoProtection == level) && (!cipherAllZero || !authAllZero)) ||
((kEncryption == level) && !authAllZero) ||
((kAuthentication == level) && !cipherAllZero))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
" Invalid input argument");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
// 16 <= cipherKeyLength <= 256
if (((kEncryption == level) || (kEncryptionAndAuthentication == level))
&& ((cipherKeyLength < kViEMinSrtpEncryptLength)
|| (cipherKeyLength > kViEMaxSrtpEncryptLength)))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
" Invalid cipher key length");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
// For HMAC_SHA1 auth:
// authKeyLength <= 20, authTagLength <= 20
if (((kAuthentication == level) || (kEncryptionAndAuthentication == level))
&& (kAuthHmacSha1 == authType)
&& ((authKeyLength > kViEMaxSrtpAuthSh1Length)
|| (authTagLength > kViEMaxSrtpAuthSh1Length)))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
" Invalid auth key or tag length");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
// For NULL auth:
// authKeyLength <= 256, authTagLength <= 12
if (((kAuthentication == level) || (kEncryptionAndAuthentication == level))
&& (kAuthNull == authType)
&& ((authKeyLength > kViEMaxSrtpKeyAuthNullLength)
|| (authTagLength > kViEMaxSrtpTagAuthNullLength)))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
" Invalid auth key or tag length");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
if (!key)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), " key NULL pointer");
SetLastError(kViEEncryptionInvalidSrtpParameter);
return -1;
}
const SrtpModule::CipherTypes cipher_type =
static_cast<const SrtpModule::CipherTypes> (cipherType);
const SrtpModule::AuthenticationTypes auth_type =
static_cast<const SrtpModule::AuthenticationTypes> (authType);
const SrtpModule::SecurityLevels security_level =
static_cast<const SrtpModule::SecurityLevels> (level);
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* vieChannel = cs.Channel(videoChannel);
if (vieChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s: No channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEEncryptionInvalidChannelId);
return -1;
}
if (0 != vieChannel->EnableSRTPReceive(cipher_type, cipherKeyLength,
auth_type, authKeyLength,
authTagLength, security_level, key,
useForRTCP))
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"Failed to configure SRTP Encryption for receiving");
SetLastError(kViEEncryptionUnknownError);
return -1;
}
WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"SRTP Enabled for receiving");
return 0;
#else
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVoice,
ViEId(_instanceId, videoChannel),
" _SRTP is undefined => _lastError = %d",
LastErrorInternal());
SetLastError(kViEEncryptionSrtpNotSupported);
return -1;
#endif
}
// ----------------------------------------------------------------------------
// DisableSRTPReceive
//
// ----------------------------------------------------------------------------
int ViEEncryptionImpl::DisableSRTPReceive(const int videoChannel)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"DisableSRTPReceive(videoChannel=%d)", videoChannel);
#ifdef WEBRTC_SRTP
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* vieChannel = cs.Channel(videoChannel);
if (vieChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s: No channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEEncryptionInvalidChannelId);
return -1;
}
if (0 != vieChannel->DisableSRTPReceive())
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"Failed to Disable SRTP Encryption for receiving");
SetLastError(kViEEncryptionUnknownError);
return -1;
}
WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "SRTP Disabled for receiving");
return 0;
#else
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVoice,
ViEId(_instanceId, videoChannel),
" _SRTP is undefined => _lastError = %d",
LastErrorInternal());
SetLastError(kViEEncryptionSrtpNotSupported);
return -1;
#endif
}
// ============================================================================
// External encryption
// ============================================================================
// ----------------------------------------------------------------------------
// RegisterExternalEncryption
//
// ----------------------------------------------------------------------------
int ViEEncryptionImpl::RegisterExternalEncryption(const int videoChannel,
Encryption& encryption)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"RegisterExternalEncryption(videoChannel=%d)", videoChannel);
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* vieChannel = cs.Channel(videoChannel);
if (vieChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s: No channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEEncryptionInvalidChannelId);
return -1;
}
if (vieChannel->RegisterExternalEncryption(&encryption) != 0)
{
SetLastError(kViEEncryptionUnknownError);
return -1;
}
return 0;
}
// ----------------------------------------------------------------------------
// DeregisterExternalEncryption
//
// ----------------------------------------------------------------------------
int ViEEncryptionImpl::DeregisterExternalEncryption(const int videoChannel)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"RegisterExternalEncryption(videoChannel=%d)", videoChannel);
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* vieChannel = cs.Channel(videoChannel);
if (vieChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s: No channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEEncryptionInvalidChannelId);
return -1;
}
if (vieChannel->DeRegisterExternalEncryption() != 0)
{
SetLastError(kViEEncryptionUnknownError);
return -1;
}
return 0;
}
} // namespace webrtc