Index: pc/srtpfilter.cc |
diff --git a/pc/srtpfilter.cc b/pc/srtpfilter.cc |
index fbea08fdc5154e4f41b04ee748dffab454550b26..c01f29bef59591c7e6a8a8d163b2c7e37fbd7d26 100644 |
--- a/pc/srtpfilter.cc |
+++ b/pc/srtpfilter.cc |
@@ -17,6 +17,7 @@ |
#include "media/base/rtputils.h" |
#include "pc/srtpsession.h" |
#include "rtc_base/base64.h" |
+#include "rtc_base/buffer.h" |
#include "rtc_base/byteorder.h" |
#include "rtc_base/checks.h" |
#include "rtc_base/logging.h" |
@@ -62,6 +63,210 @@ bool SrtpFilter::SetProvisionalAnswer( |
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(); |
+ send_session_->SetEncryptedHeaderExtensionIds( |
+ send_encrypted_header_extension_ids_); |
+ if (!send_session_->SetSend(send_cs, send_key, send_key_len)) { |
+ return false; |
+ } |
+ |
+ recv_session_->SetEncryptedHeaderExtensionIds( |
+ recv_encrypted_header_extension_ids_); |
+ 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; |
+} |
+ |
+bool SrtpFilter::UpdateRtpParams(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 update SRTP Params when filter is not active"; |
+ return false; |
+ } |
+ send_session_->SetEncryptedHeaderExtensionIds( |
+ send_encrypted_header_extension_ids_); |
+ if (!send_session_->UpdateSend(send_cs, send_key, send_key_len)) { |
+ return false; |
+ } |
+ |
+ recv_session_->SetEncryptedHeaderExtensionIds( |
+ recv_encrypted_header_extension_ids_); |
+ if (!recv_session_->UpdateRecv(recv_cs, recv_key, recv_key_len)) { |
+ return false; |
+ } |
+ |
+ LOG(LS_INFO) << "SRTP updated 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()); |
+ if (!send_rtcp_session_->SetRecv(send_cs, send_key, send_key_len)) { |
+ return false; |
+ } |
+ |
+ recv_rtcp_session_.reset(new SrtpSession()); |
+ 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; |
+ } |
+ RTC_CHECK(send_session_); |
+ 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; |
+ } |
+ RTC_CHECK(send_session_); |
+ 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 { |
+ RTC_CHECK(send_session_); |
+ 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; |
+ } |
+ RTC_CHECK(recv_session_); |
+ 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 { |
+ RTC_CHECK(recv_session_); |
+ 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; |
+ } |
+ |
+ RTC_CHECK(send_session_); |
+ return send_session_->GetRtpAuthParams(key, key_len, tag_len); |
+} |
+ |
+bool SrtpFilter::GetSrtpOverhead(int* srtp_overhead) const { |
+ if (!IsActive()) { |
+ LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active"; |
+ return false; |
+ } |
+ |
+ RTC_CHECK(send_session_); |
+ *srtp_overhead = send_session_->GetSrtpOverhead(); |
+ return true; |
+} |
+ |
+void SrtpFilter::EnableExternalAuth() { |
+ RTC_DCHECK(!IsActive()); |
+ external_auth_enabled_ = true; |
+} |
+ |
+bool SrtpFilter::IsExternalAuthEnabled() const { |
+ return external_auth_enabled_; |
+} |
+ |
+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(); |
+} |
+ |
+void SrtpFilter::SetEncryptedHeaderExtensionIds( |
+ ContentSource source, |
+ const std::vector<int>& extension_ids) { |
+ if (source == CS_LOCAL) { |
+ recv_encrypted_header_extension_ids_ = extension_ids; |
+ } else { |
+ send_encrypted_header_extension_ids_ = extension_ids; |
+ } |
+} |
+ |
bool SrtpFilter::ExpectOffer(ContentSource source) { |
return ((state_ == ST_INIT) || |
(state_ == ST_ACTIVE) || |
@@ -119,16 +324,13 @@ bool SrtpFilter::DoSetAnswer(const std::vector<CryptoParams>& answer_params, |
CryptoParams selected_params; |
if (!NegotiateParams(answer_params, &selected_params)) |
return false; |
- |
- const CryptoParams& new_send_params = |
+ const CryptoParams& send_params = |
(source == CS_REMOTE) ? selected_params : answer_params[0]; |
- const CryptoParams& new_recv_params = |
+ const CryptoParams& recv_params = |
(source == CS_REMOTE) ? answer_params[0] : selected_params; |
- if (!ApplySendParams(new_send_params) || !ApplyRecvParams(new_recv_params)) { |
+ if (!ApplyParams(send_params, recv_params)) { |
return false; |
} |
- applied_send_params_ = new_send_params; |
- applied_recv_params_ = new_recv_params; |
if (final) { |
offer_params_.clear(); |
@@ -140,6 +342,17 @@ bool SrtpFilter::DoSetAnswer(const std::vector<CryptoParams>& answer_params, |
return true; |
} |
+void SrtpFilter::CreateSrtpSessions() { |
+ send_session_.reset(new SrtpSession()); |
+ applied_send_params_ = CryptoParams(); |
+ recv_session_.reset(new SrtpSession()); |
+ applied_recv_params_ = CryptoParams(); |
+ |
+ if (external_auth_enabled_) { |
+ send_session_->EnableExternalAuth(); |
+ } |
+} |
+ |
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, |
@@ -167,76 +380,85 @@ bool SrtpFilter::NegotiateParams(const std::vector<CryptoParams>& answer_params, |
return ret; |
} |
-bool SrtpFilter::ResetParams() { |
- offer_params_.clear(); |
- applied_send_params_ = CryptoParams(); |
- applied_recv_params_ = CryptoParams(); |
- send_cipher_suite_ = rtc::Optional<int>(); |
- recv_cipher_suite_ = rtc::Optional<int>(); |
- send_key_.Clear(); |
- recv_key_.Clear(); |
- state_ = ST_INIT; |
- return true; |
-} |
- |
-bool SrtpFilter::ApplySendParams(const CryptoParams& send_params) { |
+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) { |
- LOG(LS_INFO) << "Applying the same SRTP send parameters again. No-op."; |
- |
- // We do not want to reset the ROC if the keys are the same. So just return. |
- return true; |
- } |
- |
- send_cipher_suite_ = rtc::Optional<int>( |
- rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite)); |
- if (send_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) { |
- LOG(LS_WARNING) << "Unknown crypto suite(s) received:" |
- << " send cipher_suite " << send_params.cipher_suite; |
- return false; |
- } |
- |
- int send_key_len, send_salt_len; |
- if (!rtc::GetSrtpKeyAndSaltLengths(*send_cipher_suite_, &send_key_len, |
- &send_salt_len)) { |
- LOG(LS_WARNING) << "Could not get lengths for crypto suite(s):" |
- << " send cipher_suite " << send_params.cipher_suite; |
- return false; |
- } |
- |
- send_key_ = rtc::Buffer(send_key_len + send_salt_len); |
- return ParseKeyParams(send_params.key_params, send_key_.data(), |
- send_key_.size()); |
-} |
- |
-bool SrtpFilter::ApplyRecvParams(const CryptoParams& recv_params) { |
- if (applied_recv_params_.cipher_suite == recv_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 recv parameters again. No-op."; |
+ 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; |
} |
- recv_cipher_suite_ = rtc::Optional<int>( |
- rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite)); |
- if (recv_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) { |
+ int send_suite = rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite); |
+ int recv_suite = rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite); |
+ if (send_suite == rtc::SRTP_INVALID_CRYPTO_SUITE || |
+ recv_suite == rtc::SRTP_INVALID_CRYPTO_SUITE) { |
LOG(LS_WARNING) << "Unknown crypto suite(s) received:" |
+ << " send cipher_suite " << send_params.cipher_suite |
<< " recv cipher_suite " << recv_params.cipher_suite; |
return false; |
} |
+ int send_key_len, send_salt_len; |
int recv_key_len, recv_salt_len; |
- if (!rtc::GetSrtpKeyAndSaltLengths(*recv_cipher_suite_, &recv_key_len, |
+ if (!rtc::GetSrtpKeyAndSaltLengths(send_suite, &send_key_len, |
+ &send_salt_len) || |
+ !rtc::GetSrtpKeyAndSaltLengths(recv_suite, &recv_key_len, |
&recv_salt_len)) { |
LOG(LS_WARNING) << "Could not get lengths for crypto suite(s):" |
+ << " send cipher_suite " << send_params.cipher_suite |
<< " recv cipher_suite " << recv_params.cipher_suite; |
return false; |
} |
- recv_key_ = rtc::Buffer(recv_key_len + recv_salt_len); |
- return ParseKeyParams(recv_params.key_params, recv_key_.data(), |
- recv_key_.size()); |
+ // TODO(juberti): Zero these buffers after use. |
+ bool ret; |
+ rtc::Buffer send_key(send_key_len + send_salt_len); |
+ rtc::Buffer recv_key(recv_key_len + recv_salt_len); |
+ ret = (ParseKeyParams(send_params.key_params, send_key.data(), |
+ send_key.size()) && |
+ ParseKeyParams(recv_params.key_params, recv_key.data(), |
+ recv_key.size())); |
+ if (ret) { |
+ CreateSrtpSessions(); |
+ send_session_->SetEncryptedHeaderExtensionIds( |
+ send_encrypted_header_extension_ids_); |
+ recv_session_->SetEncryptedHeaderExtensionIds( |
+ recv_encrypted_header_extension_ids_); |
+ ret = (send_session_->SetSend( |
+ rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite), |
+ send_key.data(), send_key.size()) && |
+ recv_session_->SetRecv( |
+ rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite), |
+ recv_key.data(), recv_key.size())); |
+ } |
+ 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, |