Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2486)

Unified Diff: webrtc/pc/channel.cc

Issue 3012953002: Created the DtlsSrtpTransport.
Patch Set: Initial review. Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/pc/channel.cc
diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc
index d99a1058683f0e6c51a00e862463edfcce6f9c05..2266b9a52345b0586fd309c9ec8c0dec35757fa0 100644
--- a/webrtc/pc/channel.cc
+++ b/webrtc/pc/channel.cc
@@ -63,9 +63,6 @@ enum {
MSG_FIRSTPACKETRECEIVED,
};
-// Value specified in RFC 5764.
-static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
-
static const int kAgcMinus10db = -10;
static void SafeSetError(const std::string& message, std::string* error_desc) {
@@ -162,18 +159,8 @@ BaseChannel::BaseChannel(rtc::Thread* worker_thread,
media_channel_(media_channel),
selected_candidate_pair_(nullptr) {
RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
- if (srtp_required) {
- auto transport =
- rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_required, content_name);
- srtp_transport_ = transport.get();
- rtp_transport_ = std::move(transport);
-#if defined(ENABLE_EXTERNAL_AUTH)
- srtp_transport_->EnableExternalAuth();
-#endif
- } else {
- rtp_transport_ = rtc::MakeUnique<webrtc::RtpTransport>(rtcp_mux_required);
- srtp_transport_ = nullptr;
- }
+ rtp_transport_ = rtc::MakeUnique<webrtc::RtpTransport>(rtcp_mux_required);
+ srtp_transport_ = nullptr;
rtp_transport_->SignalReadyToSend.connect(
this, &BaseChannel::OnTransportReadyToSend);
// TODO(zstein): RtpTransport::SignalPacketReceived will probably be replaced
@@ -321,13 +308,12 @@ void BaseChannel::SetTransports_n(
// When using DTLS-SRTP, we must reset the SrtpTransport every time the
// DtlsTransport changes and wait until the DTLS handshake is complete to set
// the newly negotiated parameters.
- if (ShouldSetupDtlsSrtp_n()) {
+ if (rtp_dtls_transport && rtp_dtls_transport->IsDtlsActive()) {
// Set |writable_| to false such that UpdateWritableState_w can set up
// DTLS-SRTP when |writable_| becomes true again.
writable_ = false;
- dtls_active_ = false;
- if (srtp_transport_) {
- srtp_transport_->ResetParams();
+ if (dtls_srtp_transport_) {
+ dtls_srtp_transport_->ResetParams();
}
}
@@ -391,6 +377,9 @@ void BaseChannel::SetTransport_n(
if (new_dtls_transport) {
ConnectToDtlsTransport(new_dtls_transport);
+ if (dtls_srtp_transport_) {
+ dtls_srtp_transport_->SetDtlsTransport(rtcp, new_dtls_transport);
+ }
} else {
ConnectToPacketTransport(new_packet_transport);
}
@@ -594,9 +583,8 @@ void BaseChannel::OnDtlsState(DtlsTransportInternal* transport,
// TransportChannel) or when TransportChannel is attached after DTLS is
// negotiated.
if (state != DTLS_TRANSPORT_CONNECTED) {
- dtls_active_ = false;
- if (srtp_transport_) {
- srtp_transport_->ResetParams();
+ if (dtls_srtp_transport_) {
+ dtls_srtp_transport_->ResetParams();
}
}
}
@@ -690,6 +678,16 @@ bool BaseChannel::SendPacket(bool rtcp,
return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_NORMAL)
: rtp_transport_->SendRtpPacket(packet, options, PF_NORMAL);
}
+
+ if (dtls_srtp_transport_) {
+ RTC_DCHECK(!srtp_transport_);
+ RTC_DCHECK(dtls_srtp_transport_->IsActive());
+ // Bon voyage.
+ return rtcp ? dtls_srtp_transport_->SendRtcpPacket(packet, options,
+ PF_SRTP_BYPASS)
+ : dtls_srtp_transport_->SendRtpPacket(packet, options,
+ PF_SRTP_BYPASS);
+ }
RTC_DCHECK(srtp_transport_);
RTC_DCHECK(srtp_transport_->IsActive());
// Bon voyage.
@@ -846,102 +844,6 @@ bool BaseChannel::ShouldSetupDtlsSrtp_n() const {
return rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive();
}
-// This function returns true if either DTLS-SRTP is not in use
-// *or* DTLS-SRTP is successfully set up.
-bool BaseChannel::SetupDtlsSrtp_n(bool rtcp) {
- RTC_DCHECK(network_thread_->IsCurrent());
- bool ret = false;
-
- DtlsTransportInternal* transport =
- rtcp ? rtcp_dtls_transport_ : rtp_dtls_transport_;
- RTC_DCHECK(transport);
- RTC_DCHECK(transport->IsDtlsActive());
-
- int selected_crypto_suite;
-
- if (!transport->GetSrtpCryptoSuite(&selected_crypto_suite)) {
- LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite";
- return false;
- }
-
- LOG(LS_INFO) << "Installing keys from DTLS-SRTP on " << content_name() << " "
- << RtpRtcpStringLiteral(rtcp);
-
- int key_len;
- int salt_len;
- if (!rtc::GetSrtpKeyAndSaltLengths(selected_crypto_suite, &key_len,
- &salt_len)) {
- LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite" << selected_crypto_suite;
- return false;
- }
-
- // OK, we're now doing DTLS (RFC 5764)
- std::vector<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
-
- // RFC 5705 exporter using the RFC 5764 parameters
- if (!transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0, false,
- &dtls_buffer[0], dtls_buffer.size())) {
- LOG(LS_WARNING) << "DTLS-SRTP key export failed";
- RTC_NOTREACHED(); // This should never happen
- return false;
- }
-
- // Sync up the keys with the DTLS-SRTP interface
- std::vector<unsigned char> client_write_key(key_len + salt_len);
- std::vector<unsigned char> server_write_key(key_len + salt_len);
- size_t offset = 0;
- memcpy(&client_write_key[0], &dtls_buffer[offset], key_len);
- offset += key_len;
- memcpy(&server_write_key[0], &dtls_buffer[offset], key_len);
- offset += key_len;
- memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len);
- offset += salt_len;
- memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len);
-
- std::vector<unsigned char> *send_key, *recv_key;
- rtc::SSLRole role;
- if (!transport->GetSslRole(&role)) {
- LOG(LS_WARNING) << "GetSslRole failed";
- return false;
- }
-
- if (role == rtc::SSL_SERVER) {
- send_key = &server_write_key;
- recv_key = &client_write_key;
- } else {
- send_key = &client_write_key;
- recv_key = &server_write_key;
- }
-
- if (rtcp) {
- if (!dtls_active()) {
- RTC_DCHECK(srtp_transport_);
- ret = srtp_transport_->SetRtcpParams(
- selected_crypto_suite, &(*send_key)[0],
- static_cast<int>(send_key->size()), selected_crypto_suite,
- &(*recv_key)[0], static_cast<int>(recv_key->size()));
- } else {
- // RTCP doesn't need to call SetRtpParam because it is only used
- // to make the updated encrypted RTP header extension IDs take effect.
- ret = true;
- }
- } else {
- RTC_DCHECK(srtp_transport_);
- ret = srtp_transport_->SetRtpParams(selected_crypto_suite, &(*send_key)[0],
- static_cast<int>(send_key->size()),
- selected_crypto_suite, &(*recv_key)[0],
- static_cast<int>(recv_key->size()));
- dtls_active_ = ret;
- }
-
- if (!ret) {
- LOG(LS_WARNING) << "DTLS-SRTP key installation failed";
- } else {
- UpdateTransportOverhead();
- }
- return ret;
-}
-
void BaseChannel::MaybeSetupDtlsSrtp_n() {
if (dtls_active()) {
return;
@@ -951,17 +853,17 @@ void BaseChannel::MaybeSetupDtlsSrtp_n() {
return;
}
- if (!srtp_transport_) {
- EnableSrtpTransport_n();
+ if (!dtls_srtp_transport_) {
+ EnableDtlsSrtpTransport_n();
}
- if (!SetupDtlsSrtp_n(false)) {
+ if (!dtls_srtp_transport_->SetupDtlsSrtp(false)) {
SignalDtlsSrtpSetupFailure_n(false);
return;
}
if (rtcp_dtls_transport_) {
- if (!SetupDtlsSrtp_n(true)) {
+ if (!dtls_srtp_transport_->SetupDtlsSrtp(true)) {
SignalDtlsSrtpSetupFailure_n(true);
return;
}
@@ -1039,13 +941,19 @@ bool BaseChannel::CheckSrtpConfig_n(const std::vector<CryptoParams>& cryptos,
}
void BaseChannel::EnableSrtpTransport_n() {
- if (srtp_transport_ == nullptr) {
+ if (!srtp_transport_) {
pthatcher 2017/09/12 00:24:44 This could use an early return.
Zhi Huang 2017/09/27 00:46:32 Done.
+ // DtlsSrtpTransport and SrtpTransport shouldn't be enabled at the same
+ // time.
pthatcher 2017/09/12 00:24:43 If SrtpTransport is really just for SDES, I think
Zhi Huang 2017/09/27 00:46:32 Done.
+ RTC_DCHECK(!dtls_srtp_transport_);
rtp_transport_->SignalReadyToSend.disconnect(this);
rtp_transport_->SignalPacketReceived.disconnect(this);
auto transport = rtc::MakeUnique<webrtc::SrtpTransport>(
std::move(rtp_transport_), content_name_);
srtp_transport_ = transport.get();
+#if defined(ENABLE_EXTERNAL_AUTH)
+ srtp_transport_->EnableExternalAuth();
+#endif
rtp_transport_ = std::move(transport);
rtp_transport_->SignalReadyToSend.connect(
@@ -1056,6 +964,50 @@ void BaseChannel::EnableSrtpTransport_n() {
}
}
+void BaseChannel::EnableDtlsSrtpTransport_n() {
pthatcher 2017/09/12 00:24:43 This could just be called EnableDtlsSrtp_n().
Zhi Huang 2017/09/27 00:46:32 Done.
+ if (!dtls_srtp_transport_) {
pthatcher 2017/09/12 00:24:43 This could use an early return.
Zhi Huang 2017/09/27 00:46:32 Done.
+ // DtlsSrtpTransport and SrtpTransport shouldn't be enabled at the same
+ // time.
+ RTC_DCHECK(!srtp_transport_);
+ rtp_transport_->SignalReadyToSend.disconnect(this);
+ rtp_transport_->SignalPacketReceived.disconnect(this);
+
+ std::unique_ptr<webrtc::SrtpTransport> srtp_transport =
+ rtc::MakeUnique<webrtc::SrtpTransport>(std::move(rtp_transport_),
+ content_name_);
+ srtp_transport->SetEncryptedHeaderExtensionIds(
+ cricket::CS_LOCAL, recv_encrypted_header_extension_ids_);
+ srtp_transport->SetEncryptedHeaderExtensionIds(
+ cricket::CS_REMOTE, send_encrypted_header_extension_ids_);
+#if defined(ENABLE_EXTERNAL_AUTH)
+ srtp_transport->EnableExternalAuth();
+#endif
+ std::unique_ptr<webrtc::DtlsSrtpTransport> transport =
+ rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(srtp_transport),
+ content_name_);
+ dtls_srtp_transport_ = transport.get();
+ dtls_srtp_transport_->SetDtlsTransport(true, rtcp_dtls_transport_);
+ dtls_srtp_transport_->SetDtlsTransport(false, rtp_dtls_transport_);
+
+ rtp_transport_ = std::move(transport);
+ rtp_transport_->SignalReadyToSend.connect(
+ this, &BaseChannel::OnTransportReadyToSend);
+ rtp_transport_->SignalPacketReceived.connect(
+ this, &BaseChannel::OnPacketReceived);
+ LOG(LS_INFO) << "Wrapping SrtpTransport in DtlsSrtpTransport.";
+ }
+}
+
+void BaseChannel::CacheEncryptedHeaderExtensionIds(
+ cricket::ContentSource source,
+ const std::vector<int>& extension_ids) {
+ if (source == cricket::CS_LOCAL) {
+ recv_encrypted_header_extension_ids_ = extension_ids;
+ } else {
+ send_encrypted_header_extension_ids_ = extension_ids;
+ }
+}
+
bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos,
ContentAction action,
ContentSource src,
@@ -1072,75 +1024,74 @@ bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos,
if (!ret) {
return false;
}
+ // Cache the encrypted extension ids. This is needed because |SetSrtp_n| could
+ // happen before |dtls| is true and DtlsSrtpTransport is enabled.
+ CacheEncryptedHeaderExtensionIds(src, encrypted_extension_ids);
- // If SRTP was not required, but we're setting a description that uses SDES,
- // we need to upgrade to an SrtpTransport.
- if (!srtp_transport_ && !dtls && !cryptos.empty()) {
- EnableSrtpTransport_n();
- }
- if (srtp_transport_) {
- srtp_transport_->SetEncryptedHeaderExtensionIds(src,
- encrypted_extension_ids);
- }
- switch (action) {
- case CA_OFFER:
- // If DTLS is already active on the channel, we could be renegotiating
- // here. We don't update the srtp filter.
- if (!dtls) {
+ if (!dtls) {
+ // If SRTP was not required, but we're setting a description that uses SDES,
+ // we need to upgrade to an SrtpTransport.
+ if (!srtp_transport_ && !cryptos.empty()) {
+ EnableSrtpTransport_n();
+ }
+ if (srtp_transport_) {
+ srtp_transport_->SetEncryptedHeaderExtensionIds(src,
+ encrypted_extension_ids);
+ }
+ switch (action) {
+ case CA_OFFER:
ret = sdes_negotiator_.SetOffer(cryptos, src);
- }
- break;
- case CA_PRANSWER:
- // If we're doing DTLS-SRTP, we don't want to update the filter
- // with an answer, because we already have SRTP parameters.
- if (!dtls) {
+ break;
+ case CA_PRANSWER:
ret = sdes_negotiator_.SetProvisionalAnswer(cryptos, src);
- }
- break;
- case CA_ANSWER:
- // If we're doing DTLS-SRTP, we don't want to update the filter
- // with an answer, because we already have SRTP parameters.
- if (!dtls) {
+ break;
+ case CA_ANSWER:
ret = sdes_negotiator_.SetAnswer(cryptos, src);
+ break;
+ default:
+ break;
+ }
+ // If setting an SDES answer succeeded, apply the negotiated parameters
+ // to the SRTP transport.
+ if ((action == CA_PRANSWER || action == CA_ANSWER) && ret) {
+ if (sdes_negotiator_.send_cipher_suite() &&
+ sdes_negotiator_.recv_cipher_suite()) {
+ ret = srtp_transport_->SetRtpParams(
+ *(sdes_negotiator_.send_cipher_suite()),
+ sdes_negotiator_.send_key().data(),
+ static_cast<int>(sdes_negotiator_.send_key().size()),
+ *(sdes_negotiator_.recv_cipher_suite()),
+ sdes_negotiator_.recv_key().data(),
+ static_cast<int>(sdes_negotiator_.recv_key().size()));
+ } else {
+ LOG(LS_INFO) << "No crypto keys are provided for SDES.";
+ if (action == CA_ANSWER && srtp_transport_) {
+ // Explicitly reset the |srtp_transport_| if no crypto param is
+ // provided in the answer. No need to call |ResetParams()| for
+ // |sdes_negotiator_| because it resets the params inside |SetAnswer|.
+ srtp_transport_->ResetParams();
+ }
}
- break;
- default:
- break;
- }
-
- // If setting an SDES answer succeeded, apply the negotiated parameters
- // to the SRTP transport.
- if ((action == CA_PRANSWER || action == CA_ANSWER) && !dtls && ret) {
- if (sdes_negotiator_.send_cipher_suite() &&
- sdes_negotiator_.recv_cipher_suite()) {
- ret = srtp_transport_->SetRtpParams(
- *(sdes_negotiator_.send_cipher_suite()),
- sdes_negotiator_.send_key().data(),
- static_cast<int>(sdes_negotiator_.send_key().size()),
- *(sdes_negotiator_.recv_cipher_suite()),
- sdes_negotiator_.recv_key().data(),
- static_cast<int>(sdes_negotiator_.recv_key().size()));
+ }
+ } else {
+ // Update the DtlsSrtpTransport if using DTLS.
+ // TODO(jbauch): Only update if encrypted extension ids have changed.
pthatcher 2017/09/12 00:24:44 Shouldn't this comment be moved down into the "els
Zhi Huang 2017/09/27 00:46:32 Done.
+ if (!dtls_srtp_transport_) {
+ EnableDtlsSrtpTransport_n();
} else {
- LOG(LS_INFO) << "No crypto keys are provided for SDES.";
- if (action == CA_ANSWER && srtp_transport_) {
- // Explicitly reset the |srtp_transport_| if no crypto param is
- // provided in the answer. No need to call |ResetParams()| for
- // |sdes_negotiator_| because it resets the params inside |SetAnswer|.
- srtp_transport_->ResetParams();
- }
+ dtls_srtp_transport_->SetEncryptedHeaderExtensionIds(
+ src, encrypted_extension_ids);
+ }
+ if (dtls_active() && dtls_srtp_transport_->rtp_dtls_transport() &&
+ dtls_srtp_transport_->rtp_dtls_transport()->dtls_state() ==
+ DTLS_TRANSPORT_CONNECTED) {
+ bool rtcp = false;
+ ret = dtls_srtp_transport_->SetupDtlsSrtp(rtcp);
}
}
- // Only update SRTP filter if using DTLS. SDES is handled internally
- // by the SRTP filter.
- // TODO(jbauch): Only update if encrypted extension ids have changed.
- if (ret && dtls_active() && rtp_dtls_transport_ &&
- rtp_dtls_transport_->dtls_state() == DTLS_TRANSPORT_CONNECTED) {
- bool rtcp = false;
- ret = SetupDtlsSrtp_n(rtcp);
- }
if (!ret) {
- SafeSetError("Failed to setup SRTP filter.", error_desc);
+ SafeSetError("Failed to setup SRTP transport.", error_desc);
pthatcher 2017/09/12 00:24:44 You could just say "Failed to setup SRTP".
Zhi Huang 2017/09/27 00:46:32 Done.
return false;
}
return true;

Powered by Google App Engine
This is Rietveld 408576698