 Chromium Code Reviews
 Chromium Code Reviews Issue 3012953002:
  Created the DtlsSrtpTransport.
    
  
    Issue 3012953002:
  Created the DtlsSrtpTransport. 
  | Index: pc/channel.cc | 
| diff --git a/pc/channel.cc b/pc/channel.cc | 
| index 7ddf5de7dd91bf304bf5b0e2dc10f5c55d7dcc57..11bf78261630c7dbbc715df3c6cb60123273707d 100644 | 
| --- a/pc/channel.cc | 
| +++ b/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) { | 
| @@ -155,18 +152,7 @@ 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); | 
| rtp_transport_->SignalReadyToSend.connect( | 
| this, &BaseChannel::OnTransportReadyToSend); | 
| // TODO(zstein): RtpTransport::SignalPacketReceived will probably be replaced | 
| @@ -318,9 +304,8 @@ void BaseChannel::SetTransports_n( | 
| // 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(); | 
| } | 
| } | 
| @@ -384,6 +369,10 @@ void BaseChannel::SetTransport_n( | 
| if (new_dtls_transport) { | 
| ConnectToDtlsTransport(new_dtls_transport); | 
| + if (dtls_srtp_transport_) { | 
| + rtcp ? dtls_srtp_transport_->SetRtcpDtlsTransport(new_dtls_transport) | 
| + : dtls_srtp_transport_->SetRtpDtlsTransport(new_dtls_transport); | 
| + } | 
| } else { | 
| ConnectToPacketTransport(new_packet_transport); | 
| } | 
| @@ -587,9 +576,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(); | 
| } | 
| } | 
| } | 
| @@ -683,11 +671,22 @@ bool BaseChannel::SendPacket(bool rtcp, | 
| return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_NORMAL) | 
| : rtp_transport_->SendRtpPacket(packet, options, PF_NORMAL); | 
| } | 
| - RTC_DCHECK(srtp_transport_); | 
| - RTC_DCHECK(srtp_transport_->IsActive()); | 
| + | 
| + if (dtls_srtp_transport_) { | 
| + RTC_DCHECK(!sdes_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(sdes_transport_); | 
| + RTC_DCHECK(sdes_transport_->IsActive()); | 
| // Bon voyage. | 
| - return rtcp ? srtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS) | 
| - : srtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS); | 
| + return rtcp ? sdes_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS) | 
| + : sdes_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS); | 
| } | 
| bool BaseChannel::HandlesPayloadType(int packet_type) const { | 
| @@ -811,102 +810,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; | 
| @@ -916,17 +819,17 @@ void BaseChannel::MaybeSetupDtlsSrtp_n() { | 
| return; | 
| } | 
| - if (!srtp_transport_) { | 
| - EnableSrtpTransport_n(); | 
| + if (!dtls_srtp_transport_) { | 
| + EnableDtlsSrtp_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; | 
| } | 
| @@ -1003,21 +906,72 @@ bool BaseChannel::CheckSrtpConfig_n(const std::vector<CryptoParams>& cryptos, | 
| return true; | 
| } | 
| -void BaseChannel::EnableSrtpTransport_n() { | 
| - if (srtp_transport_ == nullptr) { | 
| - rtp_transport_->SignalReadyToSend.disconnect(this); | 
| - rtp_transport_->SignalPacketReceived.disconnect(this); | 
| +void BaseChannel::EnableSdes_n() { | 
| + if (sdes_transport_) { | 
| + return; | 
| + } | 
| + // DtlsSrtpTransport and SrtpTransport shouldn't be enabled at the same | 
| + // time. | 
| + 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_); | 
| + sdes_transport_ = transport.get(); | 
| +#if defined(ENABLE_EXTERNAL_AUTH) | 
| + sdes_transport_->EnableExternalAuth(); | 
| +#endif | 
| + rtp_transport_ = std::move(transport); | 
| + | 
| + rtp_transport_->SignalReadyToSend.connect( | 
| + this, &BaseChannel::OnTransportReadyToSend); | 
| + rtp_transport_->SignalPacketReceived.connect(this, | 
| + &BaseChannel::OnPacketReceived); | 
| + LOG(LS_INFO) << "Wrapping RtpTransport in SrtpTransport."; | 
| +} | 
| + | 
| +void BaseChannel::EnableDtlsSrtp_n() { | 
| + if (dtls_srtp_transport_) { | 
| + return; | 
| + } | 
| + // DtlsSrtpTransport and SrtpTransport shouldn't be enabled at the same | 
| + // time. | 
| + RTC_DCHECK(!sdes_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->SetSendEncryptedHeaderExtensionIds( | 
| + send_encrypted_header_extension_ids_); | 
| + srtp_transport->SetRecvEncryptedHeaderExtensionIds( | 
| + recv_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)); | 
| + dtls_srtp_transport_ = transport.get(); | 
| + dtls_srtp_transport_->SetRtcpDtlsTransport(rtcp_dtls_transport_); | 
| + dtls_srtp_transport_->SetRtpDtlsTransport(rtp_dtls_transport_); | 
| - auto transport = rtc::MakeUnique<webrtc::SrtpTransport>( | 
| - std::move(rtp_transport_), content_name_); | 
| - srtp_transport_ = transport.get(); | 
| - rtp_transport_ = std::move(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."; | 
| +} | 
| - rtp_transport_->SignalReadyToSend.connect( | 
| - this, &BaseChannel::OnTransportReadyToSend); | 
| - rtp_transport_->SignalPacketReceived.connect( | 
| - this, &BaseChannel::OnPacketReceived); | 
| - LOG(LS_INFO) << "Wrapping RtpTransport in SrtpTransport."; | 
| +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; | 
| } | 
| } | 
| @@ -1037,37 +991,56 @@ bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos, | 
| if (!ret) { | 
| return false; | 
| } | 
| + // Cache the encrypted extension ids. |SetSrtp_n| could happen before the | 
| + // certficate is ready and the |rtp_dtls_transport_| is active. The | 
| 
Taylor Brandstetter
2017/09/27 23:54:48
certificate
 | 
| + // |dtls_srtp_transport_| is not enabled until the |rtp_dtls_transport_| is | 
| + // active. | 
| + CacheEncryptedHeaderExtensionIds(src, encrypted_extension_ids); | 
| + | 
| + if (!dtls) { | 
| + ret = SetSdesSrtp_n(cryptos, action, src, encrypted_extension_ids); | 
| + } else { | 
| + ret = SetDtlsSrtp_n(src, encrypted_extension_ids); | 
| + } | 
| + | 
| + if (!ret) { | 
| + SafeSetError("Failed to setup SRTP.", error_desc); | 
| + return false; | 
| + } | 
| + return true; | 
| +} | 
| +bool BaseChannel::SetSdesSrtp_n( | 
| + const std::vector<CryptoParams>& cryptos, | 
| + ContentAction action, | 
| + ContentSource src, | 
| + const std::vector<int>& encrypted_extension_ids) { | 
| + if (cryptos.empty()) { | 
| + return true; | 
| + } | 
| // 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 (!sdes_transport_) { | 
| + EnableSdes_n(); | 
| } | 
| - if (srtp_transport_) { | 
| - srtp_transport_->SetEncryptedHeaderExtensionIds(src, | 
| - encrypted_extension_ids); | 
| + if (sdes_transport_) { | 
| + src == cricket::CS_LOCAL | 
| + ? sdes_transport_->SetRecvEncryptedHeaderExtensionIds( | 
| + encrypted_extension_ids) | 
| + : sdes_transport_->SetSendEncryptedHeaderExtensionIds( | 
| + encrypted_extension_ids); | 
| } | 
| + | 
| + bool ret = true; | 
| 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) { | 
| - ret = sdes_negotiator_.SetOffer(cryptos, src); | 
| - } | 
| + 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) { | 
| - ret = sdes_negotiator_.SetProvisionalAnswer(cryptos, src); | 
| - } | 
| + 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) { | 
| - ret = sdes_negotiator_.SetAnswer(cryptos, src); | 
| - } | 
| + ret = sdes_negotiator_.SetAnswer(cryptos, src); | 
| break; | 
| default: | 
| break; | 
| @@ -1075,10 +1048,10 @@ bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos, | 
| // If setting an SDES answer succeeded, apply the negotiated parameters | 
| // to the SRTP transport. | 
| - if ((action == CA_PRANSWER || action == CA_ANSWER) && !dtls && ret) { | 
| + if ((action == CA_PRANSWER || action == CA_ANSWER) && ret) { | 
| if (sdes_negotiator_.send_cipher_suite() && | 
| sdes_negotiator_.recv_cipher_suite()) { | 
| - ret = srtp_transport_->SetRtpParams( | 
| + ret = sdes_transport_->SetRtpParams( | 
| *(sdes_negotiator_.send_cipher_suite()), | 
| sdes_negotiator_.send_key().data(), | 
| static_cast<int>(sdes_negotiator_.send_key().size()), | 
| @@ -1087,28 +1060,41 @@ bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos, | 
| 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 | 
| + if (action == CA_ANSWER && sdes_transport_) { | 
| + // Explicitly reset the |sdes_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(); | 
| + sdes_transport_->ResetParams(); | 
| } | 
| } | 
| } | 
| + return ret; | 
| +} | 
| - // 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 BaseChannel::SetDtlsSrtp_n( | 
| + ContentSource src, | 
| + const std::vector<int>& encrypted_extension_ids) { | 
| + bool ret = true; | 
| + if (!dtls_srtp_transport_) { | 
| + EnableDtlsSrtp_n(); | 
| + } | 
| + // Update the DtlsSrtpTransport if using DTLS. | 
| + // TODO(zhihuang): Only update if encrypted extension ids have changed. | 
| + else { | 
| + src == cricket::CS_LOCAL | 
| + ? dtls_srtp_transport_->SetRecvEncryptedHeaderExtensionIds( | 
| + encrypted_extension_ids) | 
| + : dtls_srtp_transport_->SetSendEncryptedHeaderExtensionIds( | 
| + 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 = SetupDtlsSrtp_n(rtcp); | 
| - } | 
| - if (!ret) { | 
| - SafeSetError("Failed to setup SRTP filter.", error_desc); | 
| - return false; | 
| + ret = dtls_srtp_transport_->SetupDtlsSrtp(rtcp); | 
| } | 
| - return true; | 
| + return ret; | 
| } | 
| bool BaseChannel::SetRtcpMux_n(bool enable, | 
| @@ -1371,8 +1357,8 @@ void BaseChannel::MaybeCacheRtpAbsSendTimeHeaderExtension_w( | 
| void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n( | 
| int rtp_abs_sendtime_extn_id) { | 
| - if (srtp_transport_) { | 
| - srtp_transport_->CacheRtpAbsSendTimeHeaderExtension( | 
| + if (sdes_transport_) { | 
| + sdes_transport_->CacheRtpAbsSendTimeHeaderExtension( | 
| rtp_abs_sendtime_extn_id); | 
| } else { | 
| LOG(LS_WARNING) << "Trying to cache the Absolute Send Time extension id " | 
| @@ -1663,7 +1649,7 @@ int BaseChannel::GetTransportOverheadPerPacket() const { | 
| if (sdes_active()) { | 
| int srtp_overhead = 0; | 
| - if (srtp_transport_->GetSrtpOverhead(&srtp_overhead)) | 
| + if (sdes_transport_->GetSrtpOverhead(&srtp_overhead)) | 
| transport_overhead_per_packet += srtp_overhead; | 
| } |