ringrtc: Propagate externally-negotiated keys.

This commit is contained in:
Miriam Zimmerman 2024-05-23 10:02:22 -04:00
parent e0b555e38d
commit 2cf10f1072
19 changed files with 410 additions and 48 deletions

View file

@ -274,6 +274,8 @@ rtc_library("libjingle_peerconnection_api") {
visibility = [ "*" ]
cflags = []
sources = [
# RingRTC change: Propagate externally-negotiated keys.
"crypto_params.h",
"data_channel_interface.cc",
"data_channel_interface.h",
# RingRTC change to add ICE forking

44
api/crypto_params.h Normal file
View file

@ -0,0 +1,44 @@
/*
* Copyright 2019-2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
// RingRTC change: Struct to carry SRTP crypto parameters to RTP transport.
#ifndef API_CRYPTO_PARAMS_H_
#define API_CRYPTO_PARAMS_H_
#include <algorithm>
#include "rtc_base/buffer.h"
#include "rtc_base/ssl_stream_adapter.h" // kSrtpInvalidCryptoSuite
namespace cricket {
// Parameters for propagating SRTP params to RTP transport.
struct CryptoParams {
CryptoParams() = default;
// Manually define a copy constructor because ZeroOnFreeBuffer assumes its
// contents might be quite large, and wants us to be explicit. However, keys
// won't be extremely large, so allow copies.
CryptoParams(const CryptoParams& other)
: crypto_suite(other.crypto_suite),
key_params(other.key_params.data(), other.key_params.size()) {}
// Similarly define an assignment constructor.
CryptoParams& operator=(CryptoParams other) {
std::swap(crypto_suite, other.crypto_suite);
// ZeroOnFreeBuffer defines a swap()
std::swap(key_params, other.key_params);
return *this;
}
int crypto_suite = rtc::kSrtpInvalidCryptoSuite;
// Key and salt.
rtc::ZeroOnFreeBuffer<uint8_t> key_params;
};
} // namespace cricket
#endif // API_CRYPTO_PARAMS_H_

View file

@ -23,7 +23,8 @@ namespace cricket {
TransportDescriptionFactory::TransportDescriptionFactory(
const webrtc::FieldTrialsView& field_trials)
: field_trials_(field_trials) {}
// RingRTC: Allow out-of-band / "manual" key negotiation.
: manually_specify_keys_(false), field_trials_(field_trials) {}
TransportDescriptionFactory::~TransportDescriptionFactory() = default;
@ -52,6 +53,12 @@ std::unique_ptr<TransportDescription> TransportDescriptionFactory::CreateOffer(
if (insecure_ && !certificate_) {
return desc;
}
// RingRTC: Allow out-of-band / "manual" key negotiation.
if (manually_specify_keys_) {
RTC_LOG(LS_INFO) << "Skipping SetSecurityInfo because expect manual keys";
return desc;
}
// Fail if we can't create the fingerprint.
// If we are the initiator set role to "actpass".
if (!SetSecurityInfo(desc.get(), CONNECTIONROLE_ACTPASS)) {
@ -95,6 +102,12 @@ std::unique_ptr<TransportDescription> TransportDescriptionFactory::CreateAnswer(
if ((!certificate_ || !offer->identity_fingerprint.get()) && insecure()) {
return desc;
}
// RingRTC: Allow out-of-band / "manual" key negotiation.
if (manually_specify_keys_) {
RTC_LOG(LS_INFO) << "Skipping SetSecurityInfo because expect manual keys";
return desc;
}
if (!offer->identity_fingerprint.get()) {
if (require_transport_attributes) {
// We require DTLS, but the other side didn't offer it. Fail.

View file

@ -43,12 +43,17 @@ class TransportDescriptionFactory {
const webrtc::FieldTrialsView& field_trials);
~TransportDescriptionFactory();
// RingRTC: Allow out-of-band / "manual" key negotiation.
bool manually_specify_keys() const { return manually_specify_keys_; }
// The certificate to use when setting up DTLS.
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate() const {
return certificate_;
}
// Specifies the certificate to use
// RingRTC: Allow out-of-band / "manual" key negotiation.
// Specifies that keys should be manually specified.
void set_manually_specify_keys(bool b) { manually_specify_keys_ = b; }
// Specifies the certificate to use (only used when !manually_specify_keys).
void set_certificate(rtc::scoped_refptr<rtc::RTCCertificate> certificate) {
certificate_ = std::move(certificate);
}
@ -85,6 +90,11 @@ class TransportDescriptionFactory {
bool SetSecurityInfo(TransportDescription* description,
ConnectionRole role) const;
bool insecure_ = false;
// RingRTC: Allow out-of-band / "manual" key negotiation.
// True iff keys should be manually specified (e.g. negotiated out of band,
// and not via DTLS).
bool manually_specify_keys_ = false;
rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
const webrtc::FieldTrialsView& field_trials_;
};

View file

@ -213,6 +213,8 @@ rtc_source_set("jsep_transport") {
":rtp_transport_internal",
":sctp_transport",
":session_description",
# RingRTC: Allow out-of-band / "manual" key negotiation.
":srtp_key_carrier",
":srtp_transport",
":transport_stats",
"../api:array_view",
@ -538,6 +540,21 @@ rtc_source_set("sctp_utils") {
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
# RingRTC: Allow out-of-band / "manual" key negotiation.
rtc_source_set("srtp_key_carrier") {
visibility = [ ":*" ]
sources = [
"srtp_key_carrier.cc",
"srtp_key_carrier.h",
]
deps = [
":session_description",
"../api:libjingle_peerconnection_api",
"../rtc_base:logging",
"../rtc_base:ssl",
]
}
rtc_source_set("srtp_session") {
visibility = [ ":*" ]
sources = [

View file

@ -36,10 +36,14 @@ JsepTransportDescription::JsepTransportDescription() {}
JsepTransportDescription::JsepTransportDescription(
bool rtcp_mux_enabled,
// RingRTC: Allow out-of-band / "manual" key negotiation.
const std::optional<CryptoParams>& crypto,
const std::vector<int>& encrypted_header_extension_ids,
int rtp_abs_sendtime_extn_id,
const TransportDescription& transport_desc)
: rtcp_mux_enabled(rtcp_mux_enabled),
// RingRTC: Allow out-of-band / "manual" key negotiation.
crypto(crypto),
encrypted_header_extension_ids(encrypted_header_extension_ids),
rtp_abs_sendtime_extn_id(rtp_abs_sendtime_extn_id),
transport_desc(transport_desc) {}
@ -47,6 +51,8 @@ JsepTransportDescription::JsepTransportDescription(
JsepTransportDescription::JsepTransportDescription(
const JsepTransportDescription& from)
: rtcp_mux_enabled(from.rtcp_mux_enabled),
// RingRTC: Allow out-of-band / "manual" key negotiation.
crypto(from.crypto),
encrypted_header_extension_ids(from.encrypted_header_extension_ids),
rtp_abs_sendtime_extn_id(from.rtp_abs_sendtime_extn_id),
transport_desc(from.transport_desc) {}
@ -59,6 +65,8 @@ JsepTransportDescription& JsepTransportDescription::operator=(
return *this;
}
rtcp_mux_enabled = from.rtcp_mux_enabled;
// RingRTC: Allow out-of-band / "manual" key negotiation.
crypto = from.crypto;
encrypted_header_extension_ids = from.encrypted_header_extension_ids;
rtp_abs_sendtime_extn_id = from.rtp_abs_sendtime_extn_id;
transport_desc = from.transport_desc;
@ -72,7 +80,8 @@ JsepTransport::JsepTransport(
rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport,
rtc::scoped_refptr<webrtc::IceTransportInterface> rtcp_ice_transport,
std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
// RingRTC: Allow out-of-band / "manual" key negotiation.
std::unique_ptr<webrtc::SrtpTransport> srtp_transport,
std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport,
@ -84,7 +93,8 @@ JsepTransport::JsepTransport(
ice_transport_(std::move(ice_transport)),
rtcp_ice_transport_(std::move(rtcp_ice_transport)),
unencrypted_rtp_transport_(std::move(unencrypted_rtp_transport)),
sdes_transport_(std::move(sdes_transport)),
// RingRTC: Allow out-of-band / "manual" key negotiation.
srtp_transport_(std::move(srtp_transport)),
dtls_srtp_transport_(std::move(dtls_srtp_transport)),
rtp_dtls_transport_(rtp_dtls_transport
? rtc::make_ref_counted<webrtc::DtlsTransport>(
@ -108,15 +118,18 @@ JsepTransport::JsepTransport(
(rtcp_dtls_transport_ != nullptr));
// Verify the "only one out of these three can be set" invariant.
if (unencrypted_rtp_transport_) {
RTC_DCHECK(!sdes_transport);
// RingRTC: Allow out-of-band / "manual" key negotiation.
RTC_DCHECK(!srtp_transport);
RTC_DCHECK(!dtls_srtp_transport);
} else if (sdes_transport_) {
} else if (srtp_transport_) {
// RingRTC: Allow out-of-band / "manual" key negotiation.
RTC_DCHECK(!unencrypted_rtp_transport);
RTC_DCHECK(!dtls_srtp_transport);
} else {
RTC_DCHECK(dtls_srtp_transport_);
RTC_DCHECK(!unencrypted_rtp_transport);
RTC_DCHECK(!sdes_transport);
// RingRTC: Allow out-of-band / "manual" key negotiation.
RTC_DCHECK(!srtp_transport);
}
if (sctp_transport_) {
@ -163,9 +176,21 @@ webrtc::RTCError JsepTransport::SetLocalJsepTransportDescription(
"Failed to setup RTCP mux.");
}
if (dtls_srtp_transport_) {
// RingRTC: Allow out-of-band / "manual" key negotiation.
// If doing SRTP with manual keys, setup the crypto parameters.
if (srtp_transport_) {
RTC_DCHECK(!unencrypted_rtp_transport_);
RTC_DCHECK(!sdes_transport_);
RTC_DCHECK(!dtls_srtp_transport_);
if (!SetSrtpCrypto(jsep_description.crypto,
jsep_description.encrypted_header_extension_ids, type,
ContentSource::CS_LOCAL)) {
return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
"Failed to setup SRTP crypto parameters.");
}
} else if (dtls_srtp_transport_) {
RTC_DCHECK(!unencrypted_rtp_transport_);
// RingRTC: Allow out-of-band / "manual" key negotiation.
RTC_DCHECK(!srtp_transport_);
dtls_srtp_transport_->UpdateRecvEncryptedHeaderExtensionIds(
jsep_description.encrypted_header_extension_ids);
}
@ -240,9 +265,22 @@ webrtc::RTCError JsepTransport::SetRemoteJsepTransportDescription(
"Failed to setup RTCP mux.");
}
if (dtls_srtp_transport_) {
// RingRTC: Allow out-of-band / "manual" key negotiation.
// If doing SRTP, setup the SRTP crypto parameters.
if (srtp_transport_) {
RTC_DCHECK(!unencrypted_rtp_transport_);
RTC_DCHECK(!sdes_transport_);
RTC_DCHECK(!dtls_srtp_transport_);
if (!SetSrtpCrypto(jsep_description.crypto,
jsep_description.encrypted_header_extension_ids, type,
ContentSource::CS_REMOTE)) {
return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
"Failed to setup SRTP crypto parameters.");
}
srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
jsep_description.rtp_abs_sendtime_extn_id);
} else if (dtls_srtp_transport_) {
RTC_DCHECK(!unencrypted_rtp_transport_);
RTC_DCHECK(!srtp_transport_);
dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds(
jsep_description.encrypted_header_extension_ids);
dtls_srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
@ -429,17 +467,20 @@ bool JsepTransport::SetRtcpMux(bool enable,
void JsepTransport::ActivateRtcpMux() {
if (unencrypted_rtp_transport_) {
RTC_DCHECK(!sdes_transport_);
// RingRTC: Allow out-of-band / "manual" key negotiation.
RTC_DCHECK(!srtp_transport_);
RTC_DCHECK(!dtls_srtp_transport_);
unencrypted_rtp_transport_->SetRtcpPacketTransport(nullptr);
} else if (sdes_transport_) {
} else if (srtp_transport_) {
// RingRTC: Allow out-of-band / "manual" key negotiation.
RTC_DCHECK(!unencrypted_rtp_transport_);
RTC_DCHECK(!dtls_srtp_transport_);
sdes_transport_->SetRtcpPacketTransport(nullptr);
srtp_transport_->SetRtcpPacketTransport(nullptr);
} else if (dtls_srtp_transport_) {
RTC_DCHECK(dtls_srtp_transport_);
RTC_DCHECK(!unencrypted_rtp_transport_);
RTC_DCHECK(!sdes_transport_);
// RingRTC: Allow out-of-band / "manual" key negotiation.
RTC_DCHECK(!srtp_transport_);
dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport(),
/*rtcp_dtls_transport=*/nullptr);
}
@ -448,6 +489,46 @@ void JsepTransport::ActivateRtcpMux() {
rtcp_mux_active_callback_();
}
// RingRTC: Allow out-of-band / "manual" key negotiation.
bool JsepTransport::SetSrtpCrypto(
const std::optional<CryptoParams>& crypto,
const std::vector<int>& encrypted_extension_ids,
webrtc::SdpType type,
ContentSource source) {
RTC_DCHECK_RUN_ON(network_thread_);
if (!crypto.has_value()) {
RTC_LOG(LS_ERROR) << "Setting manually-specified SRTP without any keys";
return false;
}
if (!srtp_key_carrier_.ApplyParams(crypto.value(), type, source)) {
return false;
}
if (source == ContentSource::CS_LOCAL) {
recv_extension_ids_ = encrypted_extension_ids;
} else {
send_extension_ids_ = encrypted_extension_ids;
}
// If appropriate, apply the negotiated parameters
// to the SRTP transport.
if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
const CryptoParams& send = srtp_key_carrier_.send_params();
const CryptoParams& recv = srtp_key_carrier_.recv_params();
RTC_DCHECK(send_extension_ids_);
RTC_DCHECK(recv_extension_ids_);
return srtp_transport_->SetRtpParams(
send.crypto_suite,
send.key_params.data(),
static_cast<int>(send.key_params.size()),
*(send_extension_ids_), recv.crypto_suite,
recv.key_params.data(),
static_cast<int>(recv.key_params.size()),
*(recv_extension_ids_));
}
return true;
}
webrtc::RTCError JsepTransport::NegotiateAndSetDtlsParameters(
SdpType local_description_type) {
RTC_DCHECK_RUN_ON(network_thread_);

View file

@ -17,6 +17,11 @@
#include <string>
#include <vector>
// RingRTC: Allow out-of-band / "manual" key negotiation.
#include <optional>
#include "api/crypto_params.h"
#include "pc/srtp_key_carrier.h"
#include "absl/types/optional.h"
#include "api/candidate.h"
#include "api/ice_transport_interface.h"
@ -57,6 +62,8 @@ struct JsepTransportDescription {
JsepTransportDescription();
JsepTransportDescription(
bool rtcp_mux_enabled,
// RingRTC: Allow out-of-band / "manual" key negotiation.
const std::optional<CryptoParams>& crypto,
const std::vector<int>& encrypted_header_extension_ids,
int rtp_abs_sendtime_extn_id,
const TransportDescription& transport_description);
@ -66,6 +73,8 @@ struct JsepTransportDescription {
JsepTransportDescription& operator=(const JsepTransportDescription& from);
bool rtcp_mux_enabled = true;
// RingRTC: Allow out-of-band / "manual" key negotiation.
std::optional<CryptoParams> crypto;
std::vector<int> encrypted_header_extension_ids;
int rtp_abs_sendtime_extn_id = -1;
// TODO(zhihuang): Add the ICE and DTLS related variables and methods from
@ -92,7 +101,8 @@ class JsepTransport {
rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport,
rtc::scoped_refptr<webrtc::IceTransportInterface> rtcp_ice_transport,
std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
// RingRTC: Allow out-of-band / "manual" key negotiation.
std::unique_ptr<webrtc::SrtpTransport> srtp_transport,
std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport,
@ -169,8 +179,9 @@ class JsepTransport {
if (dtls_srtp_transport_) {
return dtls_srtp_transport_.get();
}
if (sdes_transport_) {
return sdes_transport_.get();
// RingRTC: Allow out-of-band / "manual" key negotiation.
if (srtp_transport_) {
return srtp_transport_.get();
}
if (unencrypted_rtp_transport_) {
return unencrypted_rtp_transport_.get();
@ -239,6 +250,12 @@ class JsepTransport {
void ActivateRtcpMux() RTC_RUN_ON(network_thread_);
// RingRTC: Allow out-of-band / "manual" key negotiation.
bool SetSrtpCrypto(const std::optional<CryptoParams>& crypto,
const std::vector<int>& encrypted_extension_ids,
webrtc::SdpType type,
ContentSource source);
// Negotiates and sets the DTLS parameters based on the current local and
// remote transport description, such as the DTLS role to use, and whether
// DTLS should be activated.
@ -290,7 +307,8 @@ class JsepTransport {
// To avoid downcasting and make it type safe, keep three unique pointers for
// different SRTP mode and only one of these is non-nullptr.
const std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport_;
const std::unique_ptr<webrtc::SrtpTransport> sdes_transport_;
// RingRTC: Allow out-of-band / "manual" key negotiation.
const std::unique_ptr<webrtc::SrtpTransport> srtp_transport_;
const std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport_;
const rtc::scoped_refptr<webrtc::DtlsTransport> rtp_dtls_transport_;
@ -301,6 +319,8 @@ class JsepTransport {
const rtc::scoped_refptr<webrtc::SctpTransport> sctp_transport_;
// RingRTC: Allow out-of-band / "manual" key negotiation.
SrtpKeyCarrier srtp_key_carrier_ RTC_GUARDED_BY(network_thread_);
RtcpMuxFilter rtcp_mux_negotiator_ RTC_GUARDED_BY(network_thread_);
// Cache the encrypted header extension IDs for SDES negoitation.

View file

@ -527,7 +527,8 @@ JsepTransportController::CreateUnencryptedRtpTransport(
return unencrypted_rtp_transport;
}
std::unique_ptr<SrtpTransport> JsepTransportController::CreateSdesTransport(
// RingRTC: Allow out-of-band / "manual" key negotiation.
std::unique_ptr<SrtpTransport> JsepTransportController::CreateSrtpTransport(
const std::string& transport_name,
cricket::DtlsTransportInternal* rtp_dtls_transport,
cricket::DtlsTransportInternal* rtcp_dtls_transport) {
@ -987,9 +988,10 @@ JsepTransportController::CreateJsepTransportDescription(
? true
: content_desc->rtcp_mux();
// RingRTC: Allow out-of-band / "manual" key negotiation.
return cricket::JsepTransportDescription(
rtcp_mux_enabled, encrypted_extension_ids, rtp_abs_sendtime_extn_id,
transport_info.description);
rtcp_mux_enabled, content_desc->crypto(), encrypted_extension_ids,
rtp_abs_sendtime_extn_id, transport_info.description);
}
std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
@ -1095,6 +1097,13 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
if (transport) {
return RTCError::OK();
}
// RingRTC: Allow out-of-band / "manual" key negotiation.
const cricket::MediaContentDescription* content_desc =
content_info.media_description();
if (certificate_ && content_desc->crypto().has_value()) {
return RTCError(RTCErrorType::INVALID_PARAMETER,
"Manual keys and DTLS-SRTP cannot be enabled at the same time.");
}
rtc::scoped_refptr<IceTransportInterface> ice =
CreateIceTransport(content_info.name, /*rtcp=*/false);
@ -1104,7 +1113,8 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
std::unique_ptr<SrtpTransport> sdes_transport;
// RingRTC: Allow out-of-band / "manual" key negotiation.
std::unique_ptr<SrtpTransport> srtp_transport;
std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
rtc::scoped_refptr<IceTransportInterface> rtcp_ice;
@ -1121,6 +1131,11 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
<< "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
} else if (content_desc->crypto().has_value()) {
// RingRTC: Allow out-of-band / "manual" key negotiation.
srtp_transport = CreateSrtpTransport(
content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
RTC_LOG(LS_INFO) << "Creating SrtpTransport.";
} else {
RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
dtls_srtp_transport = CreateDtlsSrtpTransport(
@ -1136,7 +1151,8 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
std::unique_ptr<cricket::JsepTransport> jsep_transport =
std::make_unique<cricket::JsepTransport>(
content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
std::move(unencrypted_rtp_transport), std::move(sdes_transport),
// RingRTC: Allow out-of-band / "manual" key negotiation.
std::move(unencrypted_rtp_transport), std::move(srtp_transport),
std::move(dtls_srtp_transport), std::move(rtp_dtls_transport),
std::move(rtcp_dtls_transport), std::move(sctp_transport), [&]() {
RTC_DCHECK_RUN_ON(network_thread_);

View file

@ -450,7 +450,8 @@ class JsepTransportController : public sigslot::has_slots<> {
const std::string& transport_name,
rtc::PacketTransportInternal* rtp_packet_transport,
rtc::PacketTransportInternal* rtcp_packet_transport);
std::unique_ptr<SrtpTransport> CreateSdesTransport(
// RingRTC: Allow out-of-band / "manual" key negotiation.
std::unique_ptr<SrtpTransport> CreateSrtpTransport(
const std::string& transport_name,
cricket::DtlsTransportInternal* rtp_dtls_transport,
cricket::DtlsTransportInternal* rtcp_dtls_transport);

View file

@ -1161,8 +1161,12 @@ bool IsMediaProtocolSupported(MediaType type,
}
}
void SetMediaProtocol(bool secure_transport, MediaContentDescription* desc) {
if (secure_transport)
// RingRTC: Allow out-of-band / "manual" key negotiation.
void SetMediaProtocol(bool secure_transport, bool manually_specify_keys,
MediaContentDescription* desc) {
if (desc->crypto().has_value() || manually_specify_keys)
desc->set_protocol(kMediaProtocolSavpf);
else if (secure_transport)
desc->set_protocol(kMediaProtocolDtlsSavpf);
else
desc->set_protocol(kMediaProtocolAvpf);
@ -2090,7 +2094,9 @@ RTCError MediaSessionDescriptionFactory::AddRtpContentForOffer(
// Insecure transport should only occur in testing.
bool secure_transport = !(transport_desc_factory_->insecure());
SetMediaProtocol(secure_transport, content_description.get());
// RingRTC: Allow out-of-band / "manual" key negotiation.
SetMediaProtocol(secure_transport, manually_specify_keys(),
content_description.get());
content_description->set_direction(media_description_options.direction);

View file

@ -161,6 +161,9 @@ class MediaSessionDescriptionFactory {
const VideoCodecs& recv_codecs);
RtpHeaderExtensions filtered_rtp_header_extensions(
RtpHeaderExtensions extensions) const;
// RingRTC: Allow out-of-band / "manual" key negotiation.
bool manually_specify_keys() const { return manually_specify_keys_; }
void set_manually_specify_keys(bool b) { manually_specify_keys_ = b; }
void set_enable_encrypted_rtp_header_extensions(bool enable) {
enable_encrypted_rtp_header_extensions_ = enable;
@ -319,6 +322,8 @@ class MediaSessionDescriptionFactory {
webrtc::AlwaysValidPointer<rtc::UniqueRandomIdGenerator> const
ssrc_generator_;
bool enable_encrypted_rtp_header_extensions_ = false;
// RingRTC: Allow out-of-band / "manual" key negotiation.
bool manually_specify_keys_ = false;
const TransportDescriptionFactory* transport_desc_factory_;
};

View file

@ -2734,9 +2734,11 @@ void PeerConnection::ReportRemoteIceCandidateAdded(
}
}
// RingRTC: Allow out-of-band / "manual" key negotiation.
bool PeerConnection::SrtpRequired() const {
RTC_DCHECK_RUN_ON(signaling_thread());
return dtls_enabled_;
return (dtls_enabled_ ||
sdp_handler_->webrtc_session_desc_factory()->ManuallySpecifyKeys());
}
void PeerConnection::OnTransportControllerGatheringState(

View file

@ -286,8 +286,7 @@ RTCError VerifyCrypto(const SessionDescription* desc,
continue;
}
#if !defined(WEBRTC_FUCHSIA)
// RingRTC change to always disable DTLS.
// RTC_CHECK(dtls_enabled) << "SDES protocol is only allowed in Fuchsia";
RTC_CHECK(dtls_enabled) << "SDES protocol is only allowed in Fuchsia";
#endif
const std::string& mid = content_info.name;
auto it = bundle_groups_by_mid.find(mid);
@ -1397,6 +1396,8 @@ void SdpOfferAnswerHandler::Initialize(
RTC_LOG(LS_INFO)
<< "Disabling encryption. This should only be done in tests.";
webrtc_session_desc_factory_->SetInsecureForTesting();
// RingRTC: Allow out-of-band / "manual" key negotiation.
webrtc_session_desc_factory_->SetManuallySpecifyKeys(false);
}
webrtc_session_desc_factory_->set_enable_encrypted_rtp_header_extensions(
@ -3559,7 +3560,11 @@ RTCError SdpOfferAnswerHandler::ValidateSessionDescription(
// Verify crypto settings.
std::string crypto_error;
if (pc_->dtls_enabled()) {
// RingRTC: Allow out-of-band / "manual" key negotiation.
// Do not verify if "ManuallySpecifyKeys" is set; `VerifyCrypto` only makes
// sense for DTLS.
if (!webrtc_session_desc_factory_->ManuallySpecifyKeys() &&
pc_->dtls_enabled()) {
RTCError crypto_error = VerifyCrypto(
sdesc->description(), pc_->dtls_enabled(), bundle_groups_by_mid);
if (!crypto_error.ok()) {

View file

@ -23,6 +23,8 @@
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
// RingRTC: Allow out-of-band / "manual" key negotiation.
#include "api/crypto_params.h"
#include "api/media_types.h"
#include "api/rtp_parameters.h"
#include "api/rtp_transceiver_direction.h"
@ -121,6 +123,12 @@ class MediaContentDescription {
bandwidth_type_ = bandwidth_type;
}
// RingRTC: Allow out-of-band / "manual" key negotiation.
const absl::optional<CryptoParams>& crypto() const { return crypto_; }
void set_crypto(const absl::optional<CryptoParams>& crypto) {
crypto_ = crypto;
}
// List of RTP header extensions. URIs are **NOT** guaranteed to be unique
// as they can appear twice when both encrypted and non-encrypted extensions
// are present.
@ -260,6 +268,8 @@ class MediaContentDescription {
int bandwidth_ = kAutoBandwidth;
std::string bandwidth_type_ = kApplicationSpecificBandwidth;
// RingRTC: Allow out-of-band / "manual" key negotiation.
absl::optional<CryptoParams> crypto_;
std::vector<webrtc::RtpExtension> rtp_header_extensions_;
bool rtp_header_extensions_set_ = false;
StreamParamsVec send_streams_;

67
pc/srtp_key_carrier.cc Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright 2009 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// RingRTC: Allow out-of-band / "manual" key negotiation.
#include "pc/srtp_key_carrier.h"
#include "rtc_base/logging.h"
#include "rtc_base/ssl_stream_adapter.h"
namespace cricket {
SrtpKeyCarrier::SrtpKeyCarrier() = default;
SrtpKeyCarrier::~SrtpKeyCarrier() = default;
bool SrtpKeyCarrier::ApplyParams(const CryptoParams& crypto,
webrtc::SdpType type,
ContentSource source) {
switch (type) {
case webrtc::SdpType::kOffer:
offer_params_ = crypto;
return true;
case webrtc::SdpType::kPrAnswer:
case webrtc::SdpType::kAnswer:
return SetAnswer(crypto, source);
default:
return false;
}
}
bool SrtpKeyCarrier::SetAnswer(const CryptoParams& answer_params,
ContentSource source) {
if (!offer_params_.has_value()) {
RTC_LOG(LS_WARNING) << "Missing offer parameters when handling SRTP answer";
return false;
}
const CryptoParams& new_send_params =
(source == CS_REMOTE) ? offer_params_.value() : answer_params;
const CryptoParams& new_recv_params =
(source == CS_REMOTE) ? answer_params : offer_params_.value();
if (new_send_params.crypto_suite == rtc::kSrtpInvalidCryptoSuite) {
RTC_LOG(LS_WARNING) << "Invalid crypto suite(s) received for send";
return false;
}
if (new_recv_params.crypto_suite == rtc::kSrtpInvalidCryptoSuite) {
RTC_LOG(LS_WARNING) << "Invalid crypto suite(s) received for recv";
return false;
}
applied_send_params_ = new_send_params;
applied_recv_params_ = new_recv_params;
offer_params_ = std::nullopt;
return true;
}
} // namespace cricket

51
pc/srtp_key_carrier.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright 2009 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// RingRTC: Allow out-of-band / "manual" key negotiation.
#ifndef PC_SRTP_KEY_CARRIER_H_
#define PC_SRTP_KEY_CARRIER_H_
#include <optional>
#include "api/crypto_params.h"
#include "api/jsep.h"
#include "pc/session_description.h"
namespace cricket {
// A helper class used to propagate crypto params.
class SrtpKeyCarrier {
public:
SrtpKeyCarrier();
~SrtpKeyCarrier();
// Handle the offer/answer propagation of the crypto parameters.
// If type is kPrAnswer or kAnswer, returns true iff `send_params` and
// `recv_params` are usable.
bool ApplyParams(const CryptoParams& crypto,
webrtc::SdpType type,
ContentSource source);
const CryptoParams& send_params() { return applied_send_params_; }
const CryptoParams& recv_params() { return applied_recv_params_; }
private:
// Applies params to be visible from `send_params` and `recv_params`.
bool SetAnswer(const CryptoParams& answer_params, ContentSource source);
std::optional<CryptoParams> offer_params_;
CryptoParams applied_send_params_;
CryptoParams applied_recv_params_;
};
} // namespace cricket
#endif // PC_SRTP_KEY_CARRIER_H_

View file

@ -129,9 +129,14 @@ WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
if (!dtls_enabled) {
RTC_LOG(LS_INFO) << "DTLS-SRTP disabled";
transport_desc_factory_.SetInsecureForTesting();
// RingRTC: Allow out-of-band / "manual" key negotiation.
SetManuallySpecifyKeys(true);
return;
}
// RingRTC: Allow out-of-band / "manual" key negotiation.
// Manual keys are disabled if DTLS is on.
SetManuallySpecifyKeys(false);
if (certificate) {
// Use `certificate`.
certificate_request_state_ = CERTIFICATE_WAITING;
@ -256,6 +261,16 @@ void WebRtcSessionDescriptionFactory::CreateAnswer(
}
}
// RingRTC: Allow out-of-band / "manual" key negotiation.
void WebRtcSessionDescriptionFactory::SetManuallySpecifyKeys(bool b) {
transport_desc_factory_.set_manually_specify_keys(b);
session_desc_factory_.set_manually_specify_keys(b);
}
bool WebRtcSessionDescriptionFactory::ManuallySpecifyKeys() const {
return session_desc_factory_.manually_specify_keys();
}
void WebRtcSessionDescriptionFactory::InternalCreateOffer(
CreateSessionDescriptionRequest request) {
if (sdp_info_->local_description()) {

View file

@ -73,6 +73,10 @@ class WebRtcSessionDescriptionFactory {
void CreateAnswer(CreateSessionDescriptionObserver* observer,
const cricket::MediaSessionOptions& session_options);
// RingRTC: Allow out-of-band / "manual" key negotiation.
void SetManuallySpecifyKeys(bool b);
bool ManuallySpecifyKeys() const;
void set_enable_encrypted_rtp_header_extensions(bool enable) {
session_desc_factory_.set_enable_encrypted_rtp_header_extensions(enable);
}

View file

@ -21,7 +21,6 @@
#include "rffi/src/stats_observer.h"
#include "rtc_base/message_digest.h"
#include "rtc_base/string_encode.h"
#include "rtc_base/third_party/base64/base64.h"
#include "system_wrappers/include/field_trial.h"
#include <algorithm>
@ -201,11 +200,10 @@ Rust_disableDtlsAndSetSrtpKey(webrtc::SessionDescriptionInterface* session_descr
}
cricket::CryptoParams crypto_params;
crypto_params.crypto_suite = rtc::SrtpCryptoSuiteToName(crypto_suite);
crypto_params.crypto_suite = crypto_suite;
std::string key(key_borrowed, key_len);
std::string salt(salt_borrowed, salt_len);
crypto_params.key_params = "inline:" + rtc::Base64::Encode(key + salt);
crypto_params.key_params.SetData(key_borrowed, key_len);
crypto_params.key_params.AppendData(salt_borrowed, salt_len);
// Disable DTLS
for (cricket::TransportInfo& transport : session->transport_infos()) {
@ -218,9 +216,7 @@ Rust_disableDtlsAndSetSrtpKey(webrtc::SessionDescriptionInterface* session_descr
cricket::MediaContentDescription* media = content.media_description();
if (media) {
media->set_protocol(cricket::kMediaProtocolSavpf);
std::vector<cricket::CryptoParams> cryptos;
cryptos.push_back(crypto_params);
media->set_cryptos(cryptos);
media->set_crypto(crypto_params);
}
}
@ -550,18 +546,15 @@ CreateSessionDescriptionForGroupCall(bool local,
// Use SRTP master key material instead
cricket::CryptoParams crypto_params;
crypto_params.crypto_suite = rtc::SrtpCryptoSuiteToName(srtp_key.suite);
std::string key(srtp_key.key_borrowed, srtp_key.key_len);
std::string salt(srtp_key.salt_borrowed, srtp_key.salt_len);
crypto_params.key_params = "inline:" + rtc::Base64::Encode(key + salt);
crypto_params.crypto_suite = srtp_key.suite;
crypto_params.key_params.SetData(srtp_key.key_borrowed, srtp_key.key_len);
crypto_params.key_params.AppendData(srtp_key.salt_borrowed, srtp_key.salt_len);
auto set_rtp_params = [crypto_params] (cricket::MediaContentDescription* media) {
media->set_protocol(cricket::kMediaProtocolSavpf);
media->set_rtcp_mux(true);
std::vector<cricket::CryptoParams> cryptos;
cryptos.push_back(crypto_params);
media->set_cryptos(cryptos);
media->set_crypto(crypto_params);
};
auto local_direction = local ? RtpTransceiverDirection::kSendOnly : RtpTransceiverDirection::kRecvOnly;