/* * 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 (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 (cipherType); const SrtpModule::AuthenticationTypes auth_type = static_cast (authType); const SrtpModule::SecurityLevels security_level = static_cast (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 (cipherType); const SrtpModule::AuthenticationTypes auth_type = static_cast (authType); const SrtpModule::SecurityLevels security_level = static_cast (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