Chromium Code Reviews| 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; |