Index: talk/session/media/srtpfilter.cc |
diff --git a/talk/session/media/srtpfilter.cc b/talk/session/media/srtpfilter.cc |
deleted file mode 100644 |
index 4e6cbe846e78b87cc55d0a8e3721f04c4b199a6a..0000000000000000000000000000000000000000 |
--- a/talk/session/media/srtpfilter.cc |
+++ /dev/null |
@@ -1,954 +0,0 @@ |
-/* |
- * libjingle |
- * Copyright 2009 Google Inc. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions are met: |
- * |
- * 1. Redistributions of source code must retain the above copyright notice, |
- * this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright notice, |
- * this list of conditions and the following disclaimer in the documentation |
- * and/or other materials provided with the distribution. |
- * 3. The name of the author may not be used to endorse or promote products |
- * derived from this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#undef HAVE_CONFIG_H |
- |
-#include "talk/session/media/srtpfilter.h" |
- |
-#include <string.h> |
- |
-#include <algorithm> |
- |
-#include "webrtc/base/base64.h" |
-#include "webrtc/base/byteorder.h" |
-#include "webrtc/base/common.h" |
-#include "webrtc/base/logging.h" |
-#include "webrtc/base/stringencode.h" |
-#include "webrtc/base/timeutils.h" |
-#include "webrtc/media/base/rtputils.h" |
- |
-// Enable this line to turn on SRTP debugging |
-// #define SRTP_DEBUG |
- |
-#ifdef HAVE_SRTP |
-extern "C" { |
-#ifdef SRTP_RELATIVE_PATH |
-#include "srtp.h" // NOLINT |
-#include "srtp_priv.h" // NOLINT |
-#else |
-#include "third_party/libsrtp/srtp/include/srtp.h" |
-#include "third_party/libsrtp/srtp/include/srtp_priv.h" |
-#endif // SRTP_RELATIVE_PATH |
-} |
-#ifdef ENABLE_EXTERNAL_AUTH |
-#include "talk/session/media/externalhmac.h" |
-#endif // ENABLE_EXTERNAL_AUTH |
-#if !defined(NDEBUG) |
-extern "C" debug_module_t mod_srtp; |
-extern "C" debug_module_t mod_auth; |
-extern "C" debug_module_t mod_cipher; |
-extern "C" debug_module_t mod_stat; |
-extern "C" debug_module_t mod_alloc; |
-extern "C" debug_module_t mod_aes_icm; |
-extern "C" debug_module_t mod_aes_hmac; |
-#endif |
-#else |
-// SrtpFilter needs that constant. |
-#define SRTP_MASTER_KEY_LEN 30 |
-#endif // HAVE_SRTP |
- |
-namespace cricket { |
- |
-const int SRTP_MASTER_KEY_BASE64_LEN = SRTP_MASTER_KEY_LEN * 4 / 3; |
-const int SRTP_MASTER_KEY_KEY_LEN = 16; |
-const int SRTP_MASTER_KEY_SALT_LEN = 14; |
- |
-#ifndef HAVE_SRTP |
- |
-// This helper function is used on systems that don't (yet) have SRTP, |
-// to log that the functions that require it won't do anything. |
-namespace { |
-bool SrtpNotAvailable(const char *func) { |
- LOG(LS_ERROR) << func << ": SRTP is not available on your system."; |
- return false; |
-} |
-} // anonymous namespace |
- |
-#endif // !HAVE_SRTP |
- |
-void EnableSrtpDebugging() { |
-#ifdef HAVE_SRTP |
-#if !defined(NDEBUG) |
- debug_on(mod_srtp); |
- debug_on(mod_auth); |
- debug_on(mod_cipher); |
- debug_on(mod_stat); |
- debug_on(mod_alloc); |
- debug_on(mod_aes_icm); |
- // debug_on(mod_aes_cbc); |
- // debug_on(mod_hmac); |
-#endif |
-#endif // HAVE_SRTP |
-} |
- |
-// NOTE: This is called from ChannelManager D'tor. |
-void ShutdownSrtp() { |
-#ifdef HAVE_SRTP |
- // If srtp_dealloc is not executed then this will clear all existing sessions. |
- // This should be called when application is shutting down. |
- SrtpSession::Terminate(); |
-#endif |
-} |
- |
-SrtpFilter::SrtpFilter() |
- : state_(ST_INIT), |
- signal_silent_time_in_ms_(0) { |
-} |
- |
-SrtpFilter::~SrtpFilter() { |
-} |
- |
-bool SrtpFilter::IsActive() const { |
- return state_ >= ST_ACTIVE; |
-} |
- |
-bool SrtpFilter::SetOffer(const std::vector<CryptoParams>& offer_params, |
- ContentSource source) { |
- if (!ExpectOffer(source)) { |
- LOG(LS_ERROR) << "Wrong state to update SRTP offer"; |
- return false; |
- } |
- return StoreParams(offer_params, source); |
-} |
- |
-bool SrtpFilter::SetAnswer(const std::vector<CryptoParams>& answer_params, |
- ContentSource source) { |
- return DoSetAnswer(answer_params, source, true); |
-} |
- |
-bool SrtpFilter::SetProvisionalAnswer( |
- const std::vector<CryptoParams>& answer_params, |
- ContentSource source) { |
- return DoSetAnswer(answer_params, source, false); |
-} |
- |
-bool SrtpFilter::SetRtpParams(int send_cs, |
- const uint8_t* send_key, |
- int send_key_len, |
- int recv_cs, |
- const uint8_t* recv_key, |
- int recv_key_len) { |
- if (IsActive()) { |
- LOG(LS_ERROR) << "Tried to set SRTP Params when filter already active"; |
- return false; |
- } |
- CreateSrtpSessions(); |
- if (!send_session_->SetSend(send_cs, send_key, send_key_len)) |
- return false; |
- |
- if (!recv_session_->SetRecv(recv_cs, recv_key, recv_key_len)) |
- return false; |
- |
- state_ = ST_ACTIVE; |
- |
- LOG(LS_INFO) << "SRTP activated with negotiated parameters:" |
- << " send cipher_suite " << send_cs |
- << " recv cipher_suite " << recv_cs; |
- return true; |
-} |
- |
-// This function is provided separately because DTLS-SRTP behaves |
-// differently in RTP/RTCP mux and non-mux modes. |
-// |
-// - In the non-muxed case, RTP and RTCP are keyed with different |
-// keys (from different DTLS handshakes), and so we need a new |
-// SrtpSession. |
-// - In the muxed case, they are keyed with the same keys, so |
-// this function is not needed |
-bool SrtpFilter::SetRtcpParams(int send_cs, |
- const uint8_t* send_key, |
- int send_key_len, |
- int recv_cs, |
- const uint8_t* recv_key, |
- int recv_key_len) { |
- // This can only be called once, but can be safely called after |
- // SetRtpParams |
- if (send_rtcp_session_ || recv_rtcp_session_) { |
- LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active"; |
- return false; |
- } |
- |
- send_rtcp_session_.reset(new SrtpSession()); |
- SignalSrtpError.repeat(send_rtcp_session_->SignalSrtpError); |
- send_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms_); |
- if (!send_rtcp_session_->SetRecv(send_cs, send_key, send_key_len)) |
- return false; |
- |
- recv_rtcp_session_.reset(new SrtpSession()); |
- SignalSrtpError.repeat(recv_rtcp_session_->SignalSrtpError); |
- recv_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms_); |
- if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len)) |
- return false; |
- |
- LOG(LS_INFO) << "SRTCP activated with negotiated parameters:" |
- << " send cipher_suite " << send_cs |
- << " recv cipher_suite " << recv_cs; |
- |
- return true; |
-} |
- |
-bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len) { |
- if (!IsActive()) { |
- LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active"; |
- return false; |
- } |
- ASSERT(send_session_ != NULL); |
- return send_session_->ProtectRtp(p, in_len, max_len, out_len); |
-} |
- |
-bool SrtpFilter::ProtectRtp(void* p, |
- int in_len, |
- int max_len, |
- int* out_len, |
- int64_t* index) { |
- if (!IsActive()) { |
- LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active"; |
- return false; |
- } |
- ASSERT(send_session_ != NULL); |
- return send_session_->ProtectRtp(p, in_len, max_len, out_len, index); |
-} |
- |
-bool SrtpFilter::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) { |
- if (!IsActive()) { |
- LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active"; |
- return false; |
- } |
- if (send_rtcp_session_) { |
- return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len); |
- } else { |
- ASSERT(send_session_ != NULL); |
- return send_session_->ProtectRtcp(p, in_len, max_len, out_len); |
- } |
-} |
- |
-bool SrtpFilter::UnprotectRtp(void* p, int in_len, int* out_len) { |
- if (!IsActive()) { |
- LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active"; |
- return false; |
- } |
- ASSERT(recv_session_ != NULL); |
- return recv_session_->UnprotectRtp(p, in_len, out_len); |
-} |
- |
-bool SrtpFilter::UnprotectRtcp(void* p, int in_len, int* out_len) { |
- if (!IsActive()) { |
- LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active"; |
- return false; |
- } |
- if (recv_rtcp_session_) { |
- return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len); |
- } else { |
- ASSERT(recv_session_ != NULL); |
- return recv_session_->UnprotectRtcp(p, in_len, out_len); |
- } |
-} |
- |
-bool SrtpFilter::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) { |
- if (!IsActive()) { |
- LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active"; |
- return false; |
- } |
- |
- ASSERT(send_session_ != NULL); |
- return send_session_->GetRtpAuthParams(key, key_len, tag_len); |
-} |
- |
-void SrtpFilter::set_signal_silent_time(uint32_t signal_silent_time_in_ms) { |
- signal_silent_time_in_ms_ = signal_silent_time_in_ms; |
- if (IsActive()) { |
- ASSERT(send_session_ != NULL); |
- send_session_->set_signal_silent_time(signal_silent_time_in_ms); |
- ASSERT(recv_session_ != NULL); |
- recv_session_->set_signal_silent_time(signal_silent_time_in_ms); |
- if (send_rtcp_session_) |
- send_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms); |
- if (recv_rtcp_session_) |
- recv_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms); |
- } |
-} |
- |
-bool SrtpFilter::ExpectOffer(ContentSource source) { |
- return ((state_ == ST_INIT) || |
- (state_ == ST_ACTIVE) || |
- (state_ == ST_SENTOFFER && source == CS_LOCAL) || |
- (state_ == ST_SENTUPDATEDOFFER && source == CS_LOCAL) || |
- (state_ == ST_RECEIVEDOFFER && source == CS_REMOTE) || |
- (state_ == ST_RECEIVEDUPDATEDOFFER && source == CS_REMOTE)); |
-} |
- |
-bool SrtpFilter::StoreParams(const std::vector<CryptoParams>& params, |
- ContentSource source) { |
- offer_params_ = params; |
- if (state_ == ST_INIT) { |
- state_ = (source == CS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER; |
- } else if (state_ == ST_ACTIVE) { |
- state_ = |
- (source == CS_LOCAL) ? ST_SENTUPDATEDOFFER : ST_RECEIVEDUPDATEDOFFER; |
- } |
- return true; |
-} |
- |
-bool SrtpFilter::ExpectAnswer(ContentSource source) { |
- return ((state_ == ST_SENTOFFER && source == CS_REMOTE) || |
- (state_ == ST_RECEIVEDOFFER && source == CS_LOCAL) || |
- (state_ == ST_SENTUPDATEDOFFER && source == CS_REMOTE) || |
- (state_ == ST_RECEIVEDUPDATEDOFFER && source == CS_LOCAL) || |
- (state_ == ST_SENTPRANSWER_NO_CRYPTO && source == CS_LOCAL) || |
- (state_ == ST_SENTPRANSWER && source == CS_LOCAL) || |
- (state_ == ST_RECEIVEDPRANSWER_NO_CRYPTO && source == CS_REMOTE) || |
- (state_ == ST_RECEIVEDPRANSWER && source == CS_REMOTE)); |
-} |
- |
-bool SrtpFilter::DoSetAnswer(const std::vector<CryptoParams>& answer_params, |
- ContentSource source, |
- bool final) { |
- if (!ExpectAnswer(source)) { |
- LOG(LS_ERROR) << "Invalid state for SRTP answer"; |
- return false; |
- } |
- |
- // If the answer doesn't requests crypto complete the negotiation of an |
- // unencrypted session. |
- // Otherwise, finalize the parameters and apply them. |
- if (answer_params.empty()) { |
- if (final) { |
- return ResetParams(); |
- } else { |
- // Need to wait for the final answer to decide if |
- // we should go to Active state. |
- state_ = (source == CS_LOCAL) ? ST_SENTPRANSWER_NO_CRYPTO : |
- ST_RECEIVEDPRANSWER_NO_CRYPTO; |
- return true; |
- } |
- } |
- CryptoParams selected_params; |
- if (!NegotiateParams(answer_params, &selected_params)) |
- return false; |
- const CryptoParams& send_params = |
- (source == CS_REMOTE) ? selected_params : answer_params[0]; |
- const CryptoParams& recv_params = |
- (source == CS_REMOTE) ? answer_params[0] : selected_params; |
- if (!ApplyParams(send_params, recv_params)) { |
- return false; |
- } |
- |
- if (final) { |
- offer_params_.clear(); |
- state_ = ST_ACTIVE; |
- } else { |
- state_ = |
- (source == CS_LOCAL) ? ST_SENTPRANSWER : ST_RECEIVEDPRANSWER; |
- } |
- return true; |
-} |
- |
-void SrtpFilter::CreateSrtpSessions() { |
- send_session_.reset(new SrtpSession()); |
- applied_send_params_ = CryptoParams(); |
- recv_session_.reset(new SrtpSession()); |
- applied_recv_params_ = CryptoParams(); |
- |
- SignalSrtpError.repeat(send_session_->SignalSrtpError); |
- SignalSrtpError.repeat(recv_session_->SignalSrtpError); |
- |
- send_session_->set_signal_silent_time(signal_silent_time_in_ms_); |
- recv_session_->set_signal_silent_time(signal_silent_time_in_ms_); |
-} |
- |
-bool SrtpFilter::NegotiateParams(const std::vector<CryptoParams>& answer_params, |
- CryptoParams* selected_params) { |
- // We're processing an accept. We should have exactly one set of params, |
- // unless the offer didn't mention crypto, in which case we shouldn't be here. |
- bool ret = (answer_params.size() == 1U && !offer_params_.empty()); |
- if (ret) { |
- // We should find a match between the answer params and the offered params. |
- std::vector<CryptoParams>::const_iterator it; |
- for (it = offer_params_.begin(); it != offer_params_.end(); ++it) { |
- if (answer_params[0].Matches(*it)) { |
- break; |
- } |
- } |
- |
- if (it != offer_params_.end()) { |
- *selected_params = *it; |
- } else { |
- ret = false; |
- } |
- } |
- |
- if (!ret) { |
- LOG(LS_WARNING) << "Invalid parameters in SRTP answer"; |
- } |
- return ret; |
-} |
- |
-bool SrtpFilter::ApplyParams(const CryptoParams& send_params, |
- const CryptoParams& recv_params) { |
- // TODO(jiayl): Split this method to apply send and receive CryptoParams |
- // independently, so that we can skip one method when either send or receive |
- // CryptoParams is unchanged. |
- if (applied_send_params_.cipher_suite == send_params.cipher_suite && |
- applied_send_params_.key_params == send_params.key_params && |
- applied_recv_params_.cipher_suite == recv_params.cipher_suite && |
- applied_recv_params_.key_params == recv_params.key_params) { |
- LOG(LS_INFO) << "Applying the same SRTP parameters again. No-op."; |
- |
- // We do not want to reset the ROC if the keys are the same. So just return. |
- return true; |
- } |
- // TODO(juberti): Zero these buffers after use. |
- bool ret; |
- uint8_t send_key[SRTP_MASTER_KEY_LEN], recv_key[SRTP_MASTER_KEY_LEN]; |
- ret = (ParseKeyParams(send_params.key_params, send_key, sizeof(send_key)) && |
- ParseKeyParams(recv_params.key_params, recv_key, sizeof(recv_key))); |
- if (ret) { |
- CreateSrtpSessions(); |
- ret = (send_session_->SetSend( |
- rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite), send_key, |
- sizeof(send_key)) && |
- recv_session_->SetRecv( |
- rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite), recv_key, |
- sizeof(recv_key))); |
- } |
- if (ret) { |
- LOG(LS_INFO) << "SRTP activated with negotiated parameters:" |
- << " send cipher_suite " << send_params.cipher_suite |
- << " recv cipher_suite " << recv_params.cipher_suite; |
- applied_send_params_ = send_params; |
- applied_recv_params_ = recv_params; |
- } else { |
- LOG(LS_WARNING) << "Failed to apply negotiated SRTP parameters"; |
- } |
- return ret; |
-} |
- |
-bool SrtpFilter::ResetParams() { |
- offer_params_.clear(); |
- state_ = ST_INIT; |
- send_session_ = nullptr; |
- recv_session_ = nullptr; |
- send_rtcp_session_ = nullptr; |
- recv_rtcp_session_ = nullptr; |
- LOG(LS_INFO) << "SRTP reset to init state"; |
- return true; |
-} |
- |
-bool SrtpFilter::ParseKeyParams(const std::string& key_params, |
- uint8_t* key, |
- int len) { |
- // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2" |
- |
- // Fail if key-method is wrong. |
- if (key_params.find("inline:") != 0) { |
- return false; |
- } |
- |
- // Fail if base64 decode fails, or the key is the wrong size. |
- std::string key_b64(key_params.substr(7)), key_str; |
- if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, |
- &key_str, NULL) || |
- static_cast<int>(key_str.size()) != len) { |
- return false; |
- } |
- |
- memcpy(key, key_str.c_str(), len); |
- return true; |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// SrtpSession |
- |
-#ifdef HAVE_SRTP |
- |
-bool SrtpSession::inited_ = false; |
- |
-// This lock protects SrtpSession::inited_ and SrtpSession::sessions_. |
-rtc::GlobalLockPod SrtpSession::lock_; |
- |
-SrtpSession::SrtpSession() |
- : session_(NULL), |
- rtp_auth_tag_len_(0), |
- rtcp_auth_tag_len_(0), |
- srtp_stat_(new SrtpStat()), |
- last_send_seq_num_(-1) { |
- { |
- rtc::GlobalLockScope ls(&lock_); |
- sessions()->push_back(this); |
- } |
- SignalSrtpError.repeat(srtp_stat_->SignalSrtpError); |
-} |
- |
-SrtpSession::~SrtpSession() { |
- { |
- rtc::GlobalLockScope ls(&lock_); |
- sessions()->erase(std::find(sessions()->begin(), sessions()->end(), this)); |
- } |
- if (session_) { |
- srtp_dealloc(session_); |
- } |
-} |
- |
-bool SrtpSession::SetSend(int cs, const uint8_t* key, int len) { |
- return SetKey(ssrc_any_outbound, cs, key, len); |
-} |
- |
-bool SrtpSession::SetRecv(int cs, const uint8_t* key, int len) { |
- return SetKey(ssrc_any_inbound, cs, key, len); |
-} |
- |
-bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) { |
- if (!session_) { |
- LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session"; |
- return false; |
- } |
- |
- int need_len = in_len + rtp_auth_tag_len_; // NOLINT |
- if (max_len < need_len) { |
- LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length " |
- << max_len << " is less than the needed " << need_len; |
- return false; |
- } |
- |
- *out_len = in_len; |
- int err = srtp_protect(session_, p, out_len); |
- uint32_t ssrc; |
- if (GetRtpSsrc(p, in_len, &ssrc)) { |
- srtp_stat_->AddProtectRtpResult(ssrc, err); |
- } |
- int seq_num; |
- GetRtpSeqNum(p, in_len, &seq_num); |
- if (err != err_status_ok) { |
- LOG(LS_WARNING) << "Failed to protect SRTP packet, seqnum=" |
- << seq_num << ", err=" << err << ", last seqnum=" |
- << last_send_seq_num_; |
- return false; |
- } |
- last_send_seq_num_ = seq_num; |
- return true; |
-} |
- |
-bool SrtpSession::ProtectRtp(void* p, |
- int in_len, |
- int max_len, |
- int* out_len, |
- int64_t* index) { |
- if (!ProtectRtp(p, in_len, max_len, out_len)) { |
- return false; |
- } |
- return (index) ? GetSendStreamPacketIndex(p, in_len, index) : true; |
-} |
- |
-bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) { |
- if (!session_) { |
- LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session"; |
- return false; |
- } |
- |
- int need_len = in_len + sizeof(uint32_t) + rtcp_auth_tag_len_; // NOLINT |
- if (max_len < need_len) { |
- LOG(LS_WARNING) << "Failed to protect SRTCP packet: The buffer length " |
- << max_len << " is less than the needed " << need_len; |
- return false; |
- } |
- |
- *out_len = in_len; |
- int err = srtp_protect_rtcp(session_, p, out_len); |
- srtp_stat_->AddProtectRtcpResult(err); |
- if (err != err_status_ok) { |
- LOG(LS_WARNING) << "Failed to protect SRTCP packet, err=" << err; |
- return false; |
- } |
- return true; |
-} |
- |
-bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) { |
- if (!session_) { |
- LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session"; |
- return false; |
- } |
- |
- *out_len = in_len; |
- int err = srtp_unprotect(session_, p, out_len); |
- uint32_t ssrc; |
- if (GetRtpSsrc(p, in_len, &ssrc)) { |
- srtp_stat_->AddUnprotectRtpResult(ssrc, err); |
- } |
- if (err != err_status_ok) { |
- LOG(LS_WARNING) << "Failed to unprotect SRTP packet, err=" << err; |
- return false; |
- } |
- return true; |
-} |
- |
-bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) { |
- if (!session_) { |
- LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session"; |
- return false; |
- } |
- |
- *out_len = in_len; |
- int err = srtp_unprotect_rtcp(session_, p, out_len); |
- srtp_stat_->AddUnprotectRtcpResult(err); |
- if (err != err_status_ok) { |
- LOG(LS_WARNING) << "Failed to unprotect SRTCP packet, err=" << err; |
- return false; |
- } |
- return true; |
-} |
- |
-bool SrtpSession::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) { |
-#if defined(ENABLE_EXTERNAL_AUTH) |
- ExternalHmacContext* external_hmac = NULL; |
- // stream_template will be the reference context for other streams. |
- // Let's use it for getting the keys. |
- srtp_stream_ctx_t* srtp_context = session_->stream_template; |
- if (srtp_context && srtp_context->rtp_auth) { |
- external_hmac = reinterpret_cast<ExternalHmacContext*>( |
- srtp_context->rtp_auth->state); |
- } |
- |
- if (!external_hmac) { |
- LOG(LS_ERROR) << "Failed to get auth keys from libsrtp!."; |
- return false; |
- } |
- |
- *key = external_hmac->key; |
- *key_len = external_hmac->key_length; |
- *tag_len = rtp_auth_tag_len_; |
- return true; |
-#else |
- return false; |
-#endif |
-} |
- |
-bool SrtpSession::GetSendStreamPacketIndex(void* p, |
- int in_len, |
- int64_t* index) { |
- srtp_hdr_t* hdr = reinterpret_cast<srtp_hdr_t*>(p); |
- srtp_stream_ctx_t* stream = srtp_get_stream(session_, hdr->ssrc); |
- if (stream == NULL) |
- return false; |
- |
- // Shift packet index, put into network byte order |
- *index = static_cast<int64_t>( |
- rtc::NetworkToHost64(rdbx_get_packet_index(&stream->rtp_rdbx) << 16)); |
- return true; |
-} |
- |
-void SrtpSession::set_signal_silent_time(uint32_t signal_silent_time_in_ms) { |
- srtp_stat_->set_signal_silent_time(signal_silent_time_in_ms); |
-} |
- |
-bool SrtpSession::SetKey(int type, int cs, const uint8_t* key, int len) { |
- if (session_) { |
- LOG(LS_ERROR) << "Failed to create SRTP session: " |
- << "SRTP session already created"; |
- return false; |
- } |
- |
- if (!Init()) { |
- return false; |
- } |
- |
- srtp_policy_t policy; |
- memset(&policy, 0, sizeof(policy)); |
- |
- if (cs == rtc::SRTP_AES128_CM_SHA1_80) { |
- crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); |
- crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); |
- } else if (cs == rtc::SRTP_AES128_CM_SHA1_32) { |
- crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); // rtp is 32, |
- crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // rtcp still 80 |
- } else { |
- LOG(LS_WARNING) << "Failed to create SRTP session: unsupported" |
- << " cipher_suite " << cs; |
- return false; |
- } |
- |
- if (!key || len != SRTP_MASTER_KEY_LEN) { |
- LOG(LS_WARNING) << "Failed to create SRTP session: invalid key"; |
- return false; |
- } |
- |
- policy.ssrc.type = static_cast<ssrc_type_t>(type); |
- policy.ssrc.value = 0; |
- policy.key = const_cast<uint8_t*>(key); |
- // TODO(astor) parse window size from WSH session-param |
- policy.window_size = 1024; |
- policy.allow_repeat_tx = 1; |
- // If external authentication option is enabled, supply custom auth module |
- // id EXTERNAL_HMAC_SHA1 in the policy structure. |
- // 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) { |
- policy.rtp.auth_type = EXTERNAL_HMAC_SHA1; |
- } |
-#endif |
- policy.next = NULL; |
- |
- int err = srtp_create(&session_, &policy); |
- if (err != err_status_ok) { |
- session_ = NULL; |
- LOG(LS_ERROR) << "Failed to create SRTP session, err=" << err; |
- return false; |
- } |
- |
- |
- rtp_auth_tag_len_ = policy.rtp.auth_tag_len; |
- rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len; |
- return true; |
-} |
- |
-bool SrtpSession::Init() { |
- rtc::GlobalLockScope ls(&lock_); |
- |
- if (!inited_) { |
- int err; |
- err = srtp_init(); |
- if (err != err_status_ok) { |
- LOG(LS_ERROR) << "Failed to init SRTP, err=" << err; |
- return false; |
- } |
- |
- err = srtp_install_event_handler(&SrtpSession::HandleEventThunk); |
- if (err != err_status_ok) { |
- LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err; |
- return false; |
- } |
-#if defined(ENABLE_EXTERNAL_AUTH) |
- err = external_crypto_init(); |
- if (err != err_status_ok) { |
- LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err; |
- return false; |
- } |
-#endif |
- inited_ = true; |
- } |
- |
- return true; |
-} |
- |
-void SrtpSession::Terminate() { |
- rtc::GlobalLockScope ls(&lock_); |
- |
- if (inited_) { |
- int err = srtp_shutdown(); |
- if (err) { |
- LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err; |
- return; |
- } |
- inited_ = false; |
- } |
-} |
- |
-void SrtpSession::HandleEvent(const srtp_event_data_t* ev) { |
- switch (ev->event) { |
- case event_ssrc_collision: |
- LOG(LS_INFO) << "SRTP event: SSRC collision"; |
- break; |
- case event_key_soft_limit: |
- LOG(LS_INFO) << "SRTP event: reached soft key usage limit"; |
- break; |
- case event_key_hard_limit: |
- LOG(LS_INFO) << "SRTP event: reached hard key usage limit"; |
- break; |
- case event_packet_index_limit: |
- LOG(LS_INFO) << "SRTP event: reached hard packet limit (2^48 packets)"; |
- break; |
- default: |
- LOG(LS_INFO) << "SRTP event: unknown " << ev->event; |
- break; |
- } |
-} |
- |
-void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) { |
- rtc::GlobalLockScope ls(&lock_); |
- |
- for (std::list<SrtpSession*>::iterator it = sessions()->begin(); |
- it != sessions()->end(); ++it) { |
- if ((*it)->session_ == ev->session) { |
- (*it)->HandleEvent(ev); |
- break; |
- } |
- } |
-} |
- |
-std::list<SrtpSession*>* SrtpSession::sessions() { |
- RTC_DEFINE_STATIC_LOCAL(std::list<SrtpSession*>, sessions, ()); |
- return &sessions; |
-} |
- |
-#else // !HAVE_SRTP |
- |
-// On some systems, SRTP is not (yet) available. |
- |
-SrtpSession::SrtpSession() { |
- LOG(WARNING) << "SRTP implementation is missing."; |
-} |
- |
-SrtpSession::~SrtpSession() { |
-} |
- |
-bool SrtpSession::SetSend(const std::string& cs, const uint8_t* key, int len) { |
- return SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-bool SrtpSession::SetRecv(const std::string& cs, const uint8_t* key, int len) { |
- return SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-bool SrtpSession::ProtectRtp(void* data, int in_len, int max_len, |
- int* out_len) { |
- return SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-bool SrtpSession::ProtectRtcp(void* data, int in_len, int max_len, |
- int* out_len) { |
- return SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-bool SrtpSession::UnprotectRtp(void* data, int in_len, int* out_len) { |
- return SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-bool SrtpSession::UnprotectRtcp(void* data, int in_len, int* out_len) { |
- return SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-void SrtpSession::set_signal_silent_time(uint32_t signal_silent_time) { |
- // Do nothing. |
-} |
- |
-#endif // HAVE_SRTP |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// SrtpStat |
- |
-#ifdef HAVE_SRTP |
- |
-SrtpStat::SrtpStat() |
- : signal_silent_time_(1000) { |
-} |
- |
-void SrtpStat::AddProtectRtpResult(uint32_t ssrc, int result) { |
- FailureKey key; |
- key.ssrc = ssrc; |
- key.mode = SrtpFilter::PROTECT; |
- switch (result) { |
- case err_status_ok: |
- key.error = SrtpFilter::ERROR_NONE; |
- break; |
- case err_status_auth_fail: |
- key.error = SrtpFilter::ERROR_AUTH; |
- break; |
- default: |
- key.error = SrtpFilter::ERROR_FAIL; |
- } |
- HandleSrtpResult(key); |
-} |
- |
-void SrtpStat::AddUnprotectRtpResult(uint32_t ssrc, int result) { |
- FailureKey key; |
- key.ssrc = ssrc; |
- key.mode = SrtpFilter::UNPROTECT; |
- switch (result) { |
- case err_status_ok: |
- key.error = SrtpFilter::ERROR_NONE; |
- break; |
- case err_status_auth_fail: |
- key.error = SrtpFilter::ERROR_AUTH; |
- break; |
- case err_status_replay_fail: |
- case err_status_replay_old: |
- key.error = SrtpFilter::ERROR_REPLAY; |
- break; |
- default: |
- key.error = SrtpFilter::ERROR_FAIL; |
- } |
- HandleSrtpResult(key); |
-} |
- |
-void SrtpStat::AddProtectRtcpResult(int result) { |
- AddProtectRtpResult(0U, result); |
-} |
- |
-void SrtpStat::AddUnprotectRtcpResult(int result) { |
- AddUnprotectRtpResult(0U, result); |
-} |
- |
-void SrtpStat::HandleSrtpResult(const SrtpStat::FailureKey& key) { |
- // Handle some cases where error should be signalled right away. For other |
- // errors, trigger error for the first time seeing it. After that, silent |
- // the same error for a certain amount of time (default 1 sec). |
- if (key.error != SrtpFilter::ERROR_NONE) { |
- // For errors, signal first time and wait for 1 sec. |
- FailureStat* stat = &(failures_[key]); |
- uint32_t current_time = rtc::Time(); |
- if (stat->last_signal_time == 0 || |
- rtc::TimeDiff(current_time, stat->last_signal_time) > |
- static_cast<int>(signal_silent_time_)) { |
- SignalSrtpError(key.ssrc, key.mode, key.error); |
- stat->last_signal_time = current_time; |
- } |
- } |
-} |
- |
-#else // !HAVE_SRTP |
- |
-// On some systems, SRTP is not (yet) available. |
- |
-SrtpStat::SrtpStat() |
- : signal_silent_time_(1000) { |
- LOG(WARNING) << "SRTP implementation is missing."; |
-} |
- |
-void SrtpStat::AddProtectRtpResult(uint32_t ssrc, int result) { |
- SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-void SrtpStat::AddUnprotectRtpResult(uint32_t ssrc, int result) { |
- SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-void SrtpStat::AddProtectRtcpResult(int result) { |
- SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-void SrtpStat::AddUnprotectRtcpResult(int result) { |
- SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-void SrtpStat::HandleSrtpResult(const SrtpStat::FailureKey& key) { |
- SrtpNotAvailable(__FUNCTION__); |
-} |
- |
-#endif // HAVE_SRTP |
- |
-} // namespace cricket |