Create the SrtpTransportInterface.
Create the SrtpTransportInterface, a subclass of RtpTransportInterface, which
allows the user to set the send and receive keys. The functionalities are
implemented inside the RtpTransportAdapters on top of BaseChannel.
BUG=webrtc:7013
Review-Url: https://codereview.webrtc.org/2714813004
Cr-Commit-Position: refs/heads/master@{#17023}
diff --git a/webrtc/api/BUILD.gn b/webrtc/api/BUILD.gn
index 716f8c9..3447e92 100644
--- a/webrtc/api/BUILD.gn
+++ b/webrtc/api/BUILD.gn
@@ -94,6 +94,7 @@
"ortc/packettransportinterface.h",
"ortc/rtptransportcontrollerinterface.h",
"ortc/rtptransportinterface.h",
+ "ortc/srtptransportinterface.h",
"ortc/udptransportinterface.h",
]
diff --git a/webrtc/api/ortc/ortcfactoryinterface.h b/webrtc/api/ortc/ortcfactoryinterface.h
index 855e3b0..62ed90d 100644
--- a/webrtc/api/ortc/ortcfactoryinterface.h
+++ b/webrtc/api/ortc/ortcfactoryinterface.h
@@ -23,6 +23,7 @@
#include "webrtc/api/ortc/packettransportinterface.h"
#include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
#include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/api/ortc/srtptransportinterface.h"
#include "webrtc/api/ortc/udptransportinterface.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/api/rtpparameters.h"
@@ -126,6 +127,14 @@
PacketTransportInterface* rtcp,
RtpTransportControllerInterface* transport_controller) = 0;
+ // Creates an SrtpTransport which is an RTP transport that uses SRTP.
+ virtual RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+ CreateSrtpTransport(
+ const RtcpParameters& rtcp_parameters,
+ PacketTransportInterface* rtp,
+ PacketTransportInterface* rtcp,
+ RtpTransportControllerInterface* transport_controller) = 0;
+
// Returns the capabilities of an RTP sender of type |kind|. These
// capabilities can be used to determine what RtpParameters to use to create
// an RtpSender.
diff --git a/webrtc/api/ortc/ortcrtpsenderinterface.h b/webrtc/api/ortc/ortcrtpsenderinterface.h
index e369b53..a0fc208 100644
--- a/webrtc/api/ortc/ortcrtpsenderinterface.h
+++ b/webrtc/api/ortc/ortcrtpsenderinterface.h
@@ -18,8 +18,8 @@
#ifndef WEBRTC_API_ORTC_ORTCRTPSENDERINTERFACE_H_
#define WEBRTC_API_ORTC_ORTCRTPSENDERINTERFACE_H_
-#include "webrtc/api/mediatypes.h"
#include "webrtc/api/mediastreaminterface.h"
+#include "webrtc/api/mediatypes.h"
#include "webrtc/api/ortc/rtptransportinterface.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/api/rtpparameters.h"
diff --git a/webrtc/api/ortc/srtptransportinterface.h b/webrtc/api/ortc/srtptransportinterface.h
new file mode 100644
index 0000000..f64618c
--- /dev/null
+++ b/webrtc/api/ortc/srtptransportinterface.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_
+#define WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_
+
+#include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/api/rtcerror.h"
+#include "webrtc/media/base/cryptoparams.h"
+
+namespace webrtc {
+
+// The subclass of the RtpTransport which uses SRTP. The keying information
+// is explicitly passed in from the application.
+//
+// If using SDP and SDES (RFC4568) for signaling, then after applying the
+// answer, the negotiated keying information from the offer and answer would be
+// set and the SRTP would be active.
+//
+// Note that Edge's implementation of ORTC provides a similar API point, called
+// RTCSrtpSdesTransport:
+// https://msdn.microsoft.com/en-us/library/mt502527(v=vs.85).aspx
+class SrtpTransportInterface : public RtpTransportInterface {
+ public:
+ virtual ~SrtpTransportInterface() {}
+
+ // There are some limitations of the current implementation:
+ // 1. Send and receive keys must use the same crypto suite.
+ // 2. The keys can't be changed after initially set.
+ // 3. The keys must be set before creating a sender/receiver using the SRTP
+ // transport.
+ // Set the SRTP keying material for sending RTP and RTCP.
+ virtual RTCError SetSrtpSendKey(const cricket::CryptoParams& params) = 0;
+
+ // Set the SRTP keying material for receiving RTP and RTCP.
+ virtual RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) = 0;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_
diff --git a/webrtc/api/rtpparameters.h b/webrtc/api/rtpparameters.h
index e4fe47b..a428804 100644
--- a/webrtc/api/rtpparameters.h
+++ b/webrtc/api/rtpparameters.h
@@ -16,8 +16,8 @@
#include <vector>
#include "webrtc/api/mediatypes.h"
-#include "webrtc/config.h"
#include "webrtc/base/optional.h"
+#include "webrtc/config.h"
namespace webrtc {
diff --git a/webrtc/ortc/BUILD.gn b/webrtc/ortc/BUILD.gn
index ebba3b8..9e1c18f 100644
--- a/webrtc/ortc/BUILD.gn
+++ b/webrtc/ortc/BUILD.gn
@@ -58,6 +58,7 @@
"rtpparametersconversion_unittest.cc",
"rtptransport_unittest.cc",
"rtptransportcontroller_unittest.cc",
+ "srtptransport_unittest.cc",
"testrtpparameters.cc",
"testrtpparameters.h",
]
diff --git a/webrtc/ortc/ortcfactory.cc b/webrtc/ortc/ortcfactory.cc
index c0d54d1..8af6191 100644
--- a/webrtc/ortc/ortcfactory.cc
+++ b/webrtc/ortc/ortcfactory.cc
@@ -11,11 +11,11 @@
#include "webrtc/ortc/ortcfactory.h"
#include <sstream>
-#include <vector>
#include <utility> // For std::move.
+#include <vector>
-#include "webrtc/api/proxy.h"
#include "webrtc/api/mediastreamtrackproxy.h"
+#include "webrtc/api/proxy.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/api/videosourceproxy.h"
#include "webrtc/base/asyncpacketsocket.h"
@@ -33,9 +33,9 @@
#include "webrtc/ortc/rtptransportcontrolleradapter.h"
#include "webrtc/p2p/base/basicpacketsocketfactory.h"
#include "webrtc/p2p/base/udptransport.h"
+#include "webrtc/pc/audiotrack.h"
#include "webrtc/pc/channelmanager.h"
#include "webrtc/pc/localaudiosource.h"
-#include "webrtc/pc/audiotrack.h"
#include "webrtc/pc/videocapturertracksource.h"
#include "webrtc/pc/videotrack.h"
@@ -78,6 +78,14 @@
PacketTransportInterface*,
PacketTransportInterface*,
RtpTransportControllerInterface*)
+
+PROXY_METHOD4(RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>,
+ CreateSrtpTransport,
+ const RtcpParameters&,
+ PacketTransportInterface*,
+ PacketTransportInterface*,
+ RtpTransportControllerInterface*)
+
PROXY_CONSTMETHOD1(RtpCapabilities,
GetRtpSenderCapabilities,
cricket::MediaType)
@@ -250,6 +258,43 @@
}
}
+RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+OrtcFactory::CreateSrtpTransport(
+ const RtcpParameters& rtcp_parameters,
+ PacketTransportInterface* rtp,
+ PacketTransportInterface* rtcp,
+ RtpTransportControllerInterface* transport_controller) {
+ RTC_DCHECK_RUN_ON(signaling_thread_);
+ RtcpParameters copied_parameters = rtcp_parameters;
+ if (copied_parameters.cname.empty()) {
+ copied_parameters.cname = default_cname_;
+ }
+ if (transport_controller) {
+ return transport_controller->GetInternal()->CreateProxiedSrtpTransport(
+ copied_parameters, rtp, rtcp);
+ } else {
+ // If |transport_controller| is null, create one automatically, which the
+ // returned SrtpTransport will own.
+ auto controller_result = CreateRtpTransportController();
+ if (!controller_result.ok()) {
+ return controller_result.MoveError();
+ }
+ auto controller = controller_result.MoveValue();
+ auto transport_result =
+ controller->GetInternal()->CreateProxiedSrtpTransport(copied_parameters,
+ rtp, rtcp);
+ // If SrtpTransport was successfully created, transfer ownership of
+ // |rtp_transport_controller|. Otherwise it will go out of scope and be
+ // deleted automatically.
+ if (transport_result.ok()) {
+ transport_result.value()
+ ->GetInternal()
+ ->TakeOwnershipOfRtpTransportController(std::move(controller));
+ }
+ return transport_result;
+ }
+}
+
RtpCapabilities OrtcFactory::GetRtpSenderCapabilities(
cricket::MediaType kind) const {
RTC_DCHECK_RUN_ON(signaling_thread_);
diff --git a/webrtc/ortc/ortcfactory.h b/webrtc/ortc/ortcfactory.h
index 71f525d..8d67a3f 100644
--- a/webrtc/ortc/ortcfactory.h
+++ b/webrtc/ortc/ortcfactory.h
@@ -49,6 +49,12 @@
PacketTransportInterface* rtcp,
RtpTransportControllerInterface* transport_controller) override;
+ RTCErrorOr<std::unique_ptr<SrtpTransportInterface>> CreateSrtpTransport(
+ const RtcpParameters& rtcp_parameters,
+ PacketTransportInterface* rtp,
+ PacketTransportInterface* rtcp,
+ RtpTransportControllerInterface* transport_controller) override;
+
RtpCapabilities GetRtpSenderCapabilities(
cricket::MediaType kind) const override;
diff --git a/webrtc/ortc/ortcfactory_integrationtest.cc b/webrtc/ortc/ortcfactory_integrationtest.cc
index e935f06..0f782b2 100644
--- a/webrtc/ortc/ortcfactory_integrationtest.cc
+++ b/webrtc/ortc/ortcfactory_integrationtest.cc
@@ -25,13 +25,38 @@
namespace {
-const int kDefaultTimeout = 10000; // 10 seconds.
+const int kDefaultTimeout = 10000; // 10 seconds.
+const int kReceivingDuration = 1000; // 1 second.
// Default number of audio/video frames to wait for before considering a test a
// success.
const int kDefaultNumFrames = 3;
const rtc::IPAddress kIPv4LocalHostAddress =
rtc::IPAddress(0x7F000001); // 127.0.0.1
+static const char kTestKeyParams1[] =
+ "inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVz";
+static const char kTestKeyParams2[] =
+ "inline:PS1uQCVeeCFCanVmcjkpaywjNWhcYD0mXXtxaVBR";
+static const char kTestKeyParams3[] =
+ "inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVa";
+static const char kTestKeyParams4[] =
+ "inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVb";
+static const cricket::CryptoParams kTestCryptoParams1(1,
+ "AES_CM_128_HMAC_SHA1_80",
+ kTestKeyParams1,
+ "");
+static const cricket::CryptoParams kTestCryptoParams2(1,
+ "AES_CM_128_HMAC_SHA1_80",
+ kTestKeyParams2,
+ "");
+static const cricket::CryptoParams kTestCryptoParams3(1,
+ "AES_CM_128_HMAC_SHA1_80",
+ kTestKeyParams3,
+ "");
+static const cricket::CryptoParams kTestCryptoParams4(1,
+ "AES_CM_128_HMAC_SHA1_80",
+ kTestKeyParams4,
+ "");
} // namespace
namespace webrtc {
@@ -71,6 +96,9 @@
typedef std::pair<std::unique_ptr<RtpTransportInterface>,
std::unique_ptr<RtpTransportInterface>>
RtpTransportPair;
+ typedef std::pair<std::unique_ptr<SrtpTransportInterface>,
+ std::unique_ptr<SrtpTransportInterface>>
+ SrtpTransportPair;
typedef std::pair<std::unique_ptr<RtpTransportControllerInterface>,
std::unique_ptr<RtpTransportControllerInterface>>
RtpTransportControllerPair;
@@ -115,6 +143,20 @@
return {transport_result1.MoveValue(), transport_result2.MoveValue()};
}
+ SrtpTransportPair CreateSrtpTransportPair(
+ const RtcpParameters& rtcp_parameters,
+ const UdpTransportPair& rtp_udp_transports,
+ const UdpTransportPair& rtcp_udp_transports,
+ const RtpTransportControllerPair& transport_controllers) {
+ auto transport_result1 = ortc_factory1_->CreateSrtpTransport(
+ rtcp_parameters, rtp_udp_transports.first.get(),
+ rtcp_udp_transports.first.get(), transport_controllers.first.get());
+ auto transport_result2 = ortc_factory2_->CreateSrtpTransport(
+ rtcp_parameters, rtp_udp_transports.second.get(),
+ rtcp_udp_transports.second.get(), transport_controllers.second.get());
+ return {transport_result1.MoveValue(), transport_result2.MoveValue()};
+ }
+
// For convenience when |rtcp_udp_transports| and |transport_controllers|
// aren't needed.
RtpTransportPair CreateRtpTransportPair(
@@ -125,6 +167,38 @@
RtpTransportControllerPair());
}
+ SrtpTransportPair CreateSrtpTransportPairAndSetKeys(
+ const RtcpParameters& rtcp_parameters,
+ const UdpTransportPair& rtp_udp_transports) {
+ SrtpTransportPair srtp_transports = CreateSrtpTransportPair(
+ rtcp_parameters, rtp_udp_transports, UdpTransportPair(),
+ RtpTransportControllerPair());
+ EXPECT_TRUE(srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1).ok());
+ EXPECT_TRUE(
+ srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2).ok());
+ EXPECT_TRUE(
+ srtp_transports.second->SetSrtpSendKey(kTestCryptoParams2).ok());
+ EXPECT_TRUE(
+ srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams1).ok());
+ return srtp_transports;
+ }
+
+ SrtpTransportPair CreateSrtpTransportPairAndSetMismatchingKeys(
+ const RtcpParameters& rtcp_parameters,
+ const UdpTransportPair& rtp_udp_transports) {
+ SrtpTransportPair srtp_transports = CreateSrtpTransportPair(
+ rtcp_parameters, rtp_udp_transports, UdpTransportPair(),
+ RtpTransportControllerPair());
+ EXPECT_TRUE(srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1).ok());
+ EXPECT_TRUE(
+ srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2).ok());
+ EXPECT_TRUE(
+ srtp_transports.second->SetSrtpSendKey(kTestCryptoParams1).ok());
+ EXPECT_TRUE(
+ srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams2).ok());
+ return srtp_transports;
+ }
+
// Ends up using fake audio capture module, which was passed into OrtcFactory
// on creation.
rtc::scoped_refptr<webrtc::AudioTrackInterface> CreateLocalAudioTrack(
@@ -152,6 +226,110 @@
ortc_factory->CreateVideoTrack(id, source));
}
+ // Helper function used to test two way RTP senders and receivers with basic
+ // configurations.
+ // If |expect_success| is true, waits for kDefaultTimeout for
+ // kDefaultNumFrames frames to be received by all RtpReceivers.
+ // If |expect_success| is false, simply waits for |kReceivingDuration|, and
+ // stores the number of received frames in |received_audio_frame1_| etc.
+ void BasicTwoWayRtpSendersAndReceiversTest(RtpTransportPair srtp_transports,
+ bool expect_success) {
+ received_audio_frames1_ = 0;
+ received_audio_frames2_ = 0;
+ rendered_video_frames1_ = 0;
+ rendered_video_frames2_ = 0;
+ // Create all the senders and receivers (four per endpoint).
+ auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
+ cricket::MEDIA_TYPE_AUDIO, srtp_transports.first.get());
+ auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
+ cricket::MEDIA_TYPE_VIDEO, srtp_transports.first.get());
+ auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
+ cricket::MEDIA_TYPE_AUDIO, srtp_transports.first.get());
+ auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
+ cricket::MEDIA_TYPE_VIDEO, srtp_transports.first.get());
+ ASSERT_TRUE(audio_sender_result1.ok());
+ ASSERT_TRUE(video_sender_result1.ok());
+ ASSERT_TRUE(audio_receiver_result1.ok());
+ ASSERT_TRUE(video_receiver_result1.ok());
+ auto audio_sender1 = audio_sender_result1.MoveValue();
+ auto video_sender1 = video_sender_result1.MoveValue();
+ auto audio_receiver1 = audio_receiver_result1.MoveValue();
+ auto video_receiver1 = video_receiver_result1.MoveValue();
+
+ auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
+ cricket::MEDIA_TYPE_AUDIO, srtp_transports.second.get());
+ auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
+ cricket::MEDIA_TYPE_VIDEO, srtp_transports.second.get());
+ auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
+ cricket::MEDIA_TYPE_AUDIO, srtp_transports.second.get());
+ auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
+ cricket::MEDIA_TYPE_VIDEO, srtp_transports.second.get());
+ ASSERT_TRUE(audio_sender_result2.ok());
+ ASSERT_TRUE(video_sender_result2.ok());
+ ASSERT_TRUE(audio_receiver_result2.ok());
+ ASSERT_TRUE(video_receiver_result2.ok());
+ auto audio_sender2 = audio_sender_result2.MoveValue();
+ auto video_sender2 = video_sender_result2.MoveValue();
+ auto audio_receiver2 = audio_receiver_result2.MoveValue();
+ auto video_receiver2 = video_receiver_result2.MoveValue();
+
+ // Add fake tracks.
+ RTCError error = audio_sender1->SetTrack(
+ CreateLocalAudioTrack("audio", ortc_factory1_.get()));
+ EXPECT_TRUE(error.ok());
+ error = video_sender1->SetTrack(
+ CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory1_.get()));
+ EXPECT_TRUE(error.ok());
+ error = audio_sender2->SetTrack(
+ CreateLocalAudioTrack("audio", ortc_factory2_.get()));
+ EXPECT_TRUE(error.ok());
+ error = video_sender2->SetTrack(
+ CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory2_.get()));
+ EXPECT_TRUE(error.ok());
+
+ // "sent_X_parameters1" are the parameters that endpoint 1 sends with and
+ // endpoint 2 receives with.
+ RtpParameters sent_opus_parameters1 =
+ MakeMinimalOpusParametersWithSsrc(0xdeadbeef);
+ RtpParameters sent_vp8_parameters1 =
+ MakeMinimalVp8ParametersWithSsrc(0xbaadfeed);
+ RtpParameters sent_opus_parameters2 =
+ MakeMinimalOpusParametersWithSsrc(0x13333337);
+ RtpParameters sent_vp8_parameters2 =
+ MakeMinimalVp8ParametersWithSsrc(0x12345678);
+
+ // Configure the senders' and receivers' parameters.
+ EXPECT_TRUE(audio_receiver1->Receive(sent_opus_parameters2).ok());
+ EXPECT_TRUE(video_receiver1->Receive(sent_vp8_parameters2).ok());
+ EXPECT_TRUE(audio_receiver2->Receive(sent_opus_parameters1).ok());
+ EXPECT_TRUE(video_receiver2->Receive(sent_vp8_parameters1).ok());
+ EXPECT_TRUE(audio_sender1->Send(sent_opus_parameters1).ok());
+ EXPECT_TRUE(video_sender1->Send(sent_vp8_parameters1).ok());
+ EXPECT_TRUE(audio_sender2->Send(sent_opus_parameters2).ok());
+ EXPECT_TRUE(video_sender2->Send(sent_vp8_parameters2).ok());
+
+ FakeVideoTrackRenderer fake_video_renderer1(
+ static_cast<VideoTrackInterface*>(video_receiver1->GetTrack().get()));
+ FakeVideoTrackRenderer fake_video_renderer2(
+ static_cast<VideoTrackInterface*>(video_receiver2->GetTrack().get()));
+
+ if (expect_success) {
+ EXPECT_TRUE_WAIT(
+ fake_audio_capture_module1_->frames_received() > kDefaultNumFrames &&
+ fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames &&
+ fake_audio_capture_module2_->frames_received() >
+ kDefaultNumFrames &&
+ fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames,
+ kDefaultTimeout);
+ } else {
+ WAIT(false, kReceivingDuration);
+ rendered_video_frames1_ = fake_video_renderer1.num_rendered_frames();
+ rendered_video_frames2_ = fake_video_renderer2.num_rendered_frames();
+ received_audio_frames1_ = fake_audio_capture_module1_->frames_received();
+ received_audio_frames2_ = fake_audio_capture_module2_->frames_received();
+ }
+ }
+
rtc::PhysicalSocketServer physical_socket_server_;
rtc::VirtualSocketServer virtual_socket_server_;
rtc::Thread network_thread_;
@@ -162,6 +340,10 @@
std::unique_ptr<OrtcFactoryInterface> ortc_factory2_;
// Actually owned by video tracks.
std::vector<cricket::FakeVideoCapturer*> fake_video_capturers_;
+ int received_audio_frames1_ = 0;
+ int received_audio_frames2_ = 0;
+ int rendered_video_frames1_ = 0;
+ int rendered_video_frames2_ = 0;
};
// Very basic end-to-end test with a single pair of audio RTP sender and
@@ -285,102 +467,75 @@
auto udp_transports = CreateAndConnectUdpTransportPair();
auto rtp_transports =
CreateRtpTransportPair(MakeRtcpMuxParameters(), udp_transports);
+ bool expect_success = true;
+ BasicTwoWayRtpSendersAndReceiversTest(std::move(rtp_transports),
+ expect_success);
+}
- // Create all the senders and receivers (four per endpoint).
- auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
- cricket::MEDIA_TYPE_AUDIO, rtp_transports.first.get());
- auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
- cricket::MEDIA_TYPE_VIDEO, rtp_transports.first.get());
- auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
- cricket::MEDIA_TYPE_AUDIO, rtp_transports.first.get());
- auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
- cricket::MEDIA_TYPE_VIDEO, rtp_transports.first.get());
- ASSERT_TRUE(audio_sender_result1.ok());
- ASSERT_TRUE(video_sender_result1.ok());
- ASSERT_TRUE(audio_receiver_result1.ok());
- ASSERT_TRUE(video_receiver_result1.ok());
- auto audio_sender1 = audio_sender_result1.MoveValue();
- auto video_sender1 = video_sender_result1.MoveValue();
- auto audio_receiver1 = audio_receiver_result1.MoveValue();
- auto video_receiver1 = video_receiver_result1.MoveValue();
+TEST_F(OrtcFactoryIntegrationTest,
+ BasicTwoWayAudioVideoSrtpSendersAndReceivers) {
+ auto udp_transports = CreateAndConnectUdpTransportPair();
+ auto srtp_transports = CreateSrtpTransportPairAndSetKeys(
+ MakeRtcpMuxParameters(), udp_transports);
+ bool expect_success = true;
+ BasicTwoWayRtpSendersAndReceiversTest(std::move(srtp_transports),
+ expect_success);
+}
- auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
- cricket::MEDIA_TYPE_AUDIO, rtp_transports.second.get());
- auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
- cricket::MEDIA_TYPE_VIDEO, rtp_transports.second.get());
- auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
- cricket::MEDIA_TYPE_AUDIO, rtp_transports.second.get());
- auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
- cricket::MEDIA_TYPE_VIDEO, rtp_transports.second.get());
- ASSERT_TRUE(audio_sender_result2.ok());
- ASSERT_TRUE(video_sender_result2.ok());
- ASSERT_TRUE(audio_receiver_result2.ok());
- ASSERT_TRUE(video_receiver_result2.ok());
- auto audio_sender2 = audio_sender_result2.MoveValue();
- auto video_sender2 = video_sender_result2.MoveValue();
- auto audio_receiver2 = audio_receiver_result2.MoveValue();
- auto video_receiver2 = video_receiver_result2.MoveValue();
+// Tests that the packets cannot be decoded if the keys are mismatched.
+TEST_F(OrtcFactoryIntegrationTest, SrtpSendersAndReceiversWithMismatchingKeys) {
+ auto udp_transports = CreateAndConnectUdpTransportPair();
+ auto srtp_transports = CreateSrtpTransportPairAndSetMismatchingKeys(
+ MakeRtcpMuxParameters(), udp_transports);
+ bool expect_success = false;
+ BasicTwoWayRtpSendersAndReceiversTest(std::move(srtp_transports),
+ expect_success);
+ // No frames are expected to be decoded.
+ EXPECT_TRUE(received_audio_frames1_ == 0 && received_audio_frames2_ == 0 &&
+ rendered_video_frames1_ == 0 && rendered_video_frames2_ == 0);
+}
- // Add fake tracks.
- RTCError error = audio_sender1->SetTrack(
- CreateLocalAudioTrack("audio", ortc_factory1_.get()));
- EXPECT_TRUE(error.ok());
- error = video_sender1->SetTrack(
- CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory1_.get()));
- EXPECT_TRUE(error.ok());
- error = audio_sender2->SetTrack(
- CreateLocalAudioTrack("audio", ortc_factory2_.get()));
- EXPECT_TRUE(error.ok());
- error = video_sender2->SetTrack(
- CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory2_.get()));
- EXPECT_TRUE(error.ok());
+// Tests that the frames cannot be decoded if only one side uses SRTP.
+TEST_F(OrtcFactoryIntegrationTest, OneSideSrtpSenderAndReceiver) {
+ auto rtcp_parameters = MakeRtcpMuxParameters();
+ auto udp_transports = CreateAndConnectUdpTransportPair();
+ auto rtcp_udp_transports = UdpTransportPair();
+ auto transport_controllers = RtpTransportControllerPair();
+ auto transport_result1 = ortc_factory1_->CreateRtpTransport(
+ rtcp_parameters, udp_transports.first.get(),
+ rtcp_udp_transports.first.get(), transport_controllers.first.get());
+ auto transport_result2 = ortc_factory2_->CreateSrtpTransport(
+ rtcp_parameters, udp_transports.second.get(),
+ rtcp_udp_transports.second.get(), transport_controllers.second.get());
- // "sent_X_parameters1" are the parameters that endpoint 1 sends with and
- // endpoint 2 receives with.
- RtpParameters sent_opus_parameters1 =
- MakeMinimalOpusParametersWithSsrc(0xdeadbeef);
- RtpParameters sent_vp8_parameters1 =
- MakeMinimalVp8ParametersWithSsrc(0xbaadfeed);
- RtpParameters sent_opus_parameters2 =
- MakeMinimalOpusParametersWithSsrc(0x13333337);
- RtpParameters sent_vp8_parameters2 =
- MakeMinimalVp8ParametersWithSsrc(0x12345678);
+ auto rtp_transport = transport_result1.MoveValue();
+ auto srtp_transport = transport_result2.MoveValue();
+ EXPECT_TRUE(srtp_transport->SetSrtpSendKey(kTestCryptoParams1).ok());
+ EXPECT_TRUE(srtp_transport->SetSrtpReceiveKey(kTestCryptoParams2).ok());
+ bool expect_success = false;
+ BasicTwoWayRtpSendersAndReceiversTest(
+ {std::move(rtp_transport), std::move(srtp_transport)}, expect_success);
- // Configure the senders' and receivers' parameters.
- EXPECT_TRUE(audio_receiver1->Receive(sent_opus_parameters2).ok());
- EXPECT_TRUE(video_receiver1->Receive(sent_vp8_parameters2).ok());
- EXPECT_TRUE(audio_receiver2->Receive(sent_opus_parameters1).ok());
- EXPECT_TRUE(video_receiver2->Receive(sent_vp8_parameters1).ok());
- EXPECT_TRUE(audio_sender1->Send(sent_opus_parameters1).ok());
- EXPECT_TRUE(video_sender1->Send(sent_vp8_parameters1).ok());
- EXPECT_TRUE(audio_sender2->Send(sent_opus_parameters2).ok());
- EXPECT_TRUE(video_sender2->Send(sent_vp8_parameters2).ok());
-
- FakeVideoTrackRenderer fake_video_renderer1(
- static_cast<VideoTrackInterface*>(video_receiver1->GetTrack().get()));
- FakeVideoTrackRenderer fake_video_renderer2(
- static_cast<VideoTrackInterface*>(video_receiver2->GetTrack().get()));
-
- // Senders and receivers are connected and configured; audio and video frames
- // should be able to flow at this point.
- EXPECT_TRUE_WAIT(
- fake_audio_capture_module1_->frames_received() > kDefaultNumFrames &&
- fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames &&
- fake_audio_capture_module2_->frames_received() > kDefaultNumFrames &&
- fake_video_renderer2.num_rendered_frames() > kDefaultNumFrames,
- kDefaultTimeout);
+ // The SRTP side is not expected to decode any audio or video frames.
+ // The RTP side is not expected to decode any video frames while it is
+ // possible that the encrypted audio frames can be accidentally decoded which
+ // is why received_audio_frames1_ is not validated.
+ EXPECT_TRUE(received_audio_frames2_ == 0 && rendered_video_frames1_ == 0 &&
+ rendered_video_frames2_ == 0);
}
// End-to-end test with two pairs of RTP senders and receivers, for audio and
// video. Unlike the test above, this attempts to make the parameters as
-// complex as possible.
+// complex as possible. The senders and receivers use the SRTP transport with
+// different keys.
//
// Uses non-muxed RTCP, with separate audio/video transports, and a full set of
// parameters, as would normally be used in a PeerConnection.
//
// TODO(deadbeef): Update this test as more audio/video features become
// supported.
-TEST_F(OrtcFactoryIntegrationTest, FullTwoWayAudioVideoRtpSendersAndReceivers) {
+TEST_F(OrtcFactoryIntegrationTest,
+ FullTwoWayAudioVideoSrtpSendersAndReceivers) {
// We want four pairs of UDP transports for this test, for audio/video and
// RTP/RTCP.
auto audio_rtp_udp_transports = CreateAndConnectUdpTransportPair();
@@ -394,26 +549,37 @@
RtcpParameters audio_rtcp_parameters;
audio_rtcp_parameters.mux = false;
- auto audio_rtp_transports =
- CreateRtpTransportPair(audio_rtcp_parameters, audio_rtp_udp_transports,
- audio_rtcp_udp_transports, transport_controllers);
+ auto audio_srtp_transports =
+ CreateSrtpTransportPair(audio_rtcp_parameters, audio_rtp_udp_transports,
+ audio_rtcp_udp_transports, transport_controllers);
RtcpParameters video_rtcp_parameters;
video_rtcp_parameters.mux = false;
video_rtcp_parameters.reduced_size = true;
- auto video_rtp_transports =
- CreateRtpTransportPair(video_rtcp_parameters, video_rtp_udp_transports,
- video_rtcp_udp_transports, transport_controllers);
+ auto video_srtp_transports =
+ CreateSrtpTransportPair(video_rtcp_parameters, video_rtp_udp_transports,
+ video_rtcp_udp_transports, transport_controllers);
+
+ // Set keys for SRTP transports.
+ audio_srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1);
+ audio_srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2);
+ video_srtp_transports.first->SetSrtpSendKey(kTestCryptoParams3);
+ video_srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams4);
+
+ audio_srtp_transports.second->SetSrtpSendKey(kTestCryptoParams2);
+ audio_srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams1);
+ video_srtp_transports.second->SetSrtpSendKey(kTestCryptoParams4);
+ video_srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams3);
// Create all the senders and receivers (four per endpoint).
auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
- cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.first.get());
+ cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.first.get());
auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
- cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.first.get());
+ cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.first.get());
auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
- cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.first.get());
+ cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.first.get());
auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
- cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.first.get());
+ cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.first.get());
ASSERT_TRUE(audio_sender_result1.ok());
ASSERT_TRUE(video_sender_result1.ok());
ASSERT_TRUE(audio_receiver_result1.ok());
@@ -424,13 +590,13 @@
auto video_receiver1 = video_receiver_result1.MoveValue();
auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
- cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.second.get());
+ cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.second.get());
auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
- cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.second.get());
+ cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.second.get());
auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
- cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.second.get());
+ cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.second.get());
auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
- cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.second.get());
+ cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.second.get());
ASSERT_TRUE(audio_sender_result2.ok());
ASSERT_TRUE(video_sender_result2.ok());
ASSERT_TRUE(audio_receiver_result2.ok());
diff --git a/webrtc/ortc/ortcfactory_unittest.cc b/webrtc/ortc/ortcfactory_unittest.cc
index 80e679b..200939a 100644
--- a/webrtc/ortc/ortcfactory_unittest.cc
+++ b/webrtc/ortc/ortcfactory_unittest.cc
@@ -82,6 +82,24 @@
EXPECT_TRUE(result.ok());
}
+// Simple test for the successful cases of CreateSrtpTransport.
+TEST_F(OrtcFactoryTest, CreateSrtpTransport) {
+ rtc::FakePacketTransport rtp("rtp");
+ rtc::FakePacketTransport rtcp("rtcp");
+ // With muxed RTCP.
+ RtcpParameters rtcp_parameters;
+ rtcp_parameters.mux = true;
+ auto result = ortc_factory_->CreateSrtpTransport(rtcp_parameters, &rtp,
+ nullptr, nullptr);
+ EXPECT_TRUE(result.ok());
+ result.MoveValue().reset();
+ // With non-muxed RTCP.
+ rtcp_parameters.mux = false;
+ result =
+ ortc_factory_->CreateSrtpTransport(rtcp_parameters, &rtp, &rtcp, nullptr);
+ EXPECT_TRUE(result.ok());
+}
+
// If no CNAME is provided, one should be generated and returned by
// GetRtpParameters.
TEST_F(OrtcFactoryTest, CreateRtpTransportGeneratesCname) {
diff --git a/webrtc/ortc/ortcrtpreceiver_unittest.cc b/webrtc/ortc/ortcrtpreceiver_unittest.cc
index 1764af0..aa7d81d 100644
--- a/webrtc/ortc/ortcrtpreceiver_unittest.cc
+++ b/webrtc/ortc/ortcrtpreceiver_unittest.cc
@@ -12,9 +12,9 @@
#include "webrtc/base/gunit.h"
#include "webrtc/media/base/fakemediaengine.h"
-#include "webrtc/p2p/base/fakepackettransport.h"
#include "webrtc/ortc/ortcfactory.h"
#include "webrtc/ortc/testrtpparameters.h"
+#include "webrtc/p2p/base/fakepackettransport.h"
#include "webrtc/pc/test/fakevideotracksource.h"
namespace webrtc {
diff --git a/webrtc/ortc/ortcrtpsender_unittest.cc b/webrtc/ortc/ortcrtpsender_unittest.cc
index 954b997..47cb337 100644
--- a/webrtc/ortc/ortcrtpsender_unittest.cc
+++ b/webrtc/ortc/ortcrtpsender_unittest.cc
@@ -12,9 +12,9 @@
#include "webrtc/base/gunit.h"
#include "webrtc/media/base/fakemediaengine.h"
-#include "webrtc/p2p/base/fakepackettransport.h"
#include "webrtc/ortc/ortcfactory.h"
#include "webrtc/ortc/testrtpparameters.h"
+#include "webrtc/p2p/base/fakepackettransport.h"
#include "webrtc/pc/test/fakevideotracksource.h"
namespace webrtc {
diff --git a/webrtc/ortc/rtpparametersconversion.h b/webrtc/ortc/rtpparametersconversion.h
index a1680a2..a466895 100644
--- a/webrtc/ortc/rtpparametersconversion.h
+++ b/webrtc/ortc/rtpparametersconversion.h
@@ -17,8 +17,8 @@
#include "webrtc/api/rtcerror.h"
#include "webrtc/api/rtpparameters.h"
#include "webrtc/base/optional.h"
-#include "webrtc/pc/mediasession.h"
#include "webrtc/media/base/codec.h"
+#include "webrtc/pc/mediasession.h"
namespace webrtc {
diff --git a/webrtc/ortc/rtptransportadapter.cc b/webrtc/ortc/rtptransportadapter.cc
index 439f9a8..3982f2d 100644
--- a/webrtc/ortc/rtptransportadapter.cc
+++ b/webrtc/ortc/rtptransportadapter.cc
@@ -32,6 +32,20 @@
}
END_PROXY_MAP()
+BEGIN_OWNED_PROXY_MAP(SrtpTransport)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(PacketTransportInterface*, GetRtpPacketTransport)
+PROXY_CONSTMETHOD0(PacketTransportInterface*, GetRtcpPacketTransport)
+PROXY_METHOD1(RTCError, SetRtcpParameters, const RtcpParameters&)
+PROXY_CONSTMETHOD0(RtcpParameters, GetRtcpParameters)
+PROXY_METHOD1(RTCError, SetSrtpSendKey, const cricket::CryptoParams&)
+PROXY_METHOD1(RTCError, SetSrtpReceiveKey, const cricket::CryptoParams&)
+protected:
+RtpTransportAdapter* GetInternal() override {
+ return internal();
+}
+END_PROXY_MAP()
+
// static
RTCErrorOr<std::unique_ptr<RtpTransportInterface>>
RtpTransportAdapter::CreateProxied(
@@ -64,7 +78,43 @@
rtp_transport_controller->signaling_thread(),
rtp_transport_controller->worker_thread(),
std::unique_ptr<RtpTransportAdapter>(new RtpTransportAdapter(
- rtcp_parameters, rtp, rtcp, rtp_transport_controller)));
+ rtcp_parameters, rtp, rtcp, rtp_transport_controller,
+ /*is_srtp_transport*/ false)));
+}
+
+RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+RtpTransportAdapter::CreateSrtpProxied(
+ const RtcpParameters& rtcp_parameters,
+ PacketTransportInterface* rtp,
+ PacketTransportInterface* rtcp,
+ RtpTransportControllerAdapter* rtp_transport_controller) {
+ if (!rtp) {
+ LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
+ "Must provide an RTP packet transport.");
+ }
+ if (!rtcp_parameters.mux && !rtcp) {
+ LOG_AND_RETURN_ERROR(
+ RTCErrorType::INVALID_PARAMETER,
+ "Must provide an RTCP packet transport when RTCP muxing is not used.");
+ }
+ if (rtcp_parameters.mux && rtcp) {
+ LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
+ "Creating an RtpTransport with RTCP muxing enabled, "
+ "with a separate RTCP packet transport?");
+ }
+ if (!rtp_transport_controller) {
+ // Since OrtcFactory::CreateRtpTransport creates an RtpTransportController
+ // automatically when one isn't passed in, this should never be reached.
+ RTC_NOTREACHED();
+ LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
+ "Must provide an RTP transport controller.");
+ }
+ return SrtpTransportProxyWithInternal<RtpTransportAdapter>::Create(
+ rtp_transport_controller->signaling_thread(),
+ rtp_transport_controller->worker_thread(),
+ std::unique_ptr<RtpTransportAdapter>(new RtpTransportAdapter(
+ rtcp_parameters, rtp, rtcp, rtp_transport_controller,
+ /*is_srtp_transport*/ true)));
}
void RtpTransportAdapter::TakeOwnershipOfRtpTransportController(
@@ -78,11 +128,13 @@
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
- RtpTransportControllerAdapter* rtp_transport_controller)
+ RtpTransportControllerAdapter* rtp_transport_controller,
+ bool is_srtp_transport)
: rtp_packet_transport_(rtp),
rtcp_packet_transport_(rtcp),
rtp_transport_controller_(rtp_transport_controller),
- rtcp_parameters_(rtcp_parameters) {
+ rtcp_parameters_(rtcp_parameters),
+ is_srtp_transport_(is_srtp_transport) {
RTC_DCHECK(rtp_transport_controller);
// CNAME should have been filled by OrtcFactory if empty.
RTC_DCHECK(!rtcp_parameters_.cname.empty());
@@ -126,4 +178,36 @@
return RTCError::OK();
}
+RTCError RtpTransportAdapter::SetSrtpSendKey(
+ const cricket::CryptoParams& params) {
+ if (send_key_) {
+ LOG_AND_RETURN_ERROR(
+ webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+ "Setting the SRTP send key twice is currently unsupported.");
+ }
+ if (receive_key_ && receive_key_->cipher_suite != params.cipher_suite) {
+ LOG_AND_RETURN_ERROR(
+ webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+ "The send key and receive key must have the same cipher suite.");
+ }
+ send_key_ = rtc::Optional<cricket::CryptoParams>(params);
+ return RTCError::OK();
+}
+
+RTCError RtpTransportAdapter::SetSrtpReceiveKey(
+ const cricket::CryptoParams& params) {
+ if (receive_key_) {
+ LOG_AND_RETURN_ERROR(
+ webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+ "Setting the SRTP receive key twice is currently unsupported.");
+ }
+ if (send_key_ && send_key_->cipher_suite != params.cipher_suite) {
+ LOG_AND_RETURN_ERROR(
+ webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+ "The send key and receive key must have the same cipher suite.");
+ }
+ receive_key_ = rtc::Optional<cricket::CryptoParams>(params);
+ return RTCError::OK();
+}
+
} // namespace webrtc
diff --git a/webrtc/ortc/rtptransportadapter.h b/webrtc/ortc/rtptransportadapter.h
index 169ae61..59a123e 100644
--- a/webrtc/ortc/rtptransportadapter.h
+++ b/webrtc/ortc/rtptransportadapter.h
@@ -14,7 +14,7 @@
#include <memory>
#include <vector>
-#include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/api/ortc/srtptransportinterface.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/sigslot.h"
@@ -24,13 +24,14 @@
namespace webrtc {
-// Implementation of RtpTransportInterface to be used with RtpSenderAdapter,
-// RtpReceiverAdapter, and RtpTransportControllerAdapter classes.
+// Implementation of SrtpTransportInterface to be used with RtpSenderAdapter,
+// RtpReceiverAdapter, and RtpTransportControllerAdapter classes. This class
+// is used to implement both a secure and insecure RTP transport.
//
// TODO(deadbeef): When BaseChannel is split apart into separate
// "RtpTransport"/"RtpTransceiver"/"RtpSender"/"RtpReceiver" objects, this
// adapter object can be removed.
-class RtpTransportAdapter : public RtpTransportInterface {
+class RtpTransportAdapter : public SrtpTransportInterface {
public:
// |rtp| can't be null. |rtcp| can if RTCP muxing is used immediately (meaning
// |rtcp_parameters.mux| is also true).
@@ -39,6 +40,13 @@
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerAdapter* rtp_transport_controller);
+
+ static RTCErrorOr<std::unique_ptr<SrtpTransportInterface>> CreateSrtpProxied(
+ const RtcpParameters& rtcp_parameters,
+ PacketTransportInterface* rtp,
+ PacketTransportInterface* rtcp,
+ RtpTransportControllerAdapter* rtp_transport_controller);
+
~RtpTransportAdapter() override;
// RtpTransportInterface implementation.
@@ -47,6 +55,10 @@
RTCError SetRtcpParameters(const RtcpParameters& parameters) override;
RtcpParameters GetRtcpParameters() const override { return rtcp_parameters_; }
+ // SRTP specific implementation.
+ RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override;
+ RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override;
+
// Methods used internally by OrtcFactory.
RtpTransportControllerAdapter* rtp_transport_controller() {
return rtp_transport_controller_;
@@ -58,6 +70,14 @@
// returning this transport from GetTransports().
sigslot::signal1<RtpTransportAdapter*> SignalDestroyed;
+ // Used by the RtpTransportControllerAdapter to tell if an rtp sender or
+ // receiver can be created.
+ bool is_srtp_transport() { return is_srtp_transport_; }
+ // Used by the RtpTransportControllerAdapter to set keys for senders and
+ // receivers.
+ rtc::Optional<cricket::CryptoParams> send_key() { return send_key_; }
+ rtc::Optional<cricket::CryptoParams> receive_key() { return receive_key_; }
+
protected:
RtpTransportAdapter* GetInternal() override { return this; }
@@ -65,7 +85,8 @@
RtpTransportAdapter(const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
- RtpTransportControllerAdapter* rtp_transport_controller);
+ RtpTransportControllerAdapter* rtp_transport_controller,
+ bool is_srtp_transport);
PacketTransportInterface* rtp_packet_transport_;
PacketTransportInterface* rtcp_packet_transport_;
@@ -75,6 +96,11 @@
owned_rtp_transport_controller_;
RtcpParameters rtcp_parameters_;
+ // SRTP specific members.
+ rtc::Optional<cricket::CryptoParams> send_key_;
+ rtc::Optional<cricket::CryptoParams> receive_key_;
+ bool is_srtp_transport_;
+
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpTransportAdapter);
};
diff --git a/webrtc/ortc/rtptransportcontrolleradapter.cc b/webrtc/ortc/rtptransportcontrolleradapter.cc
index 08e943a..ad5d8b5 100644
--- a/webrtc/ortc/rtptransportcontrolleradapter.cc
+++ b/webrtc/ortc/rtptransportcontrolleradapter.cc
@@ -11,8 +11,8 @@
#include "webrtc/ortc/rtptransportcontrolleradapter.h"
#include <algorithm> // For "remove", "find".
-#include <sstream>
#include <set>
+#include <sstream>
#include <unordered_map>
#include <utility> // For std::move.
@@ -138,6 +138,21 @@
return result;
}
+RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+RtpTransportControllerAdapter::CreateProxiedSrtpTransport(
+ const RtcpParameters& rtcp_parameters,
+ PacketTransportInterface* rtp,
+ PacketTransportInterface* rtcp) {
+ auto result =
+ RtpTransportAdapter::CreateSrtpProxied(rtcp_parameters, rtp, rtcp, this);
+ if (result.ok()) {
+ transport_proxies_.push_back(result.value().get());
+ transport_proxies_.back()->GetInternal()->SignalDestroyed.connect(
+ this, &RtpTransportControllerAdapter::OnRtpTransportDestroyed);
+ }
+ return result;
+}
+
RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>
RtpTransportControllerAdapter::CreateProxiedRtpSender(
cricket::MediaType kind,
@@ -605,6 +620,11 @@
"RtpSender and RtpReceiver is not currently "
"supported.");
}
+ RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_,
+ &remote_audio_description_);
+ if (!err.ok()) {
+ return err;
+ }
// If setting new transport, extract its RTCP parameters and create voice
// channel.
if (!inner_audio_transport_) {
@@ -635,6 +655,11 @@
"RtpSender and RtpReceiver is not currently "
"supported.");
}
+ RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_,
+ &remote_video_description_);
+ if (!err.ok()) {
+ return err;
+ }
// If setting new transport, extract its RTCP parameters and create video
// channel.
if (!inner_video_transport_) {
@@ -665,6 +690,11 @@
"RtpReceiver and RtpReceiver is not currently "
"supported.");
}
+ RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_,
+ &remote_audio_description_);
+ if (!err.ok()) {
+ return err;
+ }
// If setting new transport, extract its RTCP parameters and create voice
// channel.
if (!inner_audio_transport_) {
@@ -695,6 +725,11 @@
"RtpReceiver and RtpReceiver is not currently "
"supported.");
}
+ RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_,
+ &remote_video_description_);
+ if (!err.ok()) {
+ return err;
+ }
// If setting new transport, extract its RTCP parameters and create video
// channel.
if (!inner_video_transport_) {
@@ -896,4 +931,25 @@
return result;
}
+RTCError RtpTransportControllerAdapter::MaybeSetCryptos(
+ RtpTransportInterface* rtp_transport,
+ cricket::MediaContentDescription* local_description,
+ cricket::MediaContentDescription* remote_description) {
+ if (rtp_transport->GetInternal()->is_srtp_transport()) {
+ if (!rtp_transport->GetInternal()->send_key() ||
+ !rtp_transport->GetInternal()->receive_key()) {
+ LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER,
+ "The SRTP send key or receive key is not set.")
+ }
+ std::vector<cricket::CryptoParams> cryptos;
+ cryptos.push_back(*(rtp_transport->GetInternal()->receive_key()));
+ local_description->set_cryptos(cryptos);
+
+ cryptos.clear();
+ cryptos.push_back(*(rtp_transport->GetInternal()->send_key()));
+ remote_description->set_cryptos(cryptos);
+ }
+ return RTCError::OK();
+}
+
} // namespace webrtc
diff --git a/webrtc/ortc/rtptransportcontrolleradapter.h b/webrtc/ortc/rtptransportcontrolleradapter.h
index 4e02b95..902ec01 100644
--- a/webrtc/ortc/rtptransportcontrolleradapter.h
+++ b/webrtc/ortc/rtptransportcontrolleradapter.h
@@ -16,18 +16,18 @@
#include <string>
#include <vector>
+#include "webrtc/api/ortc/ortcrtpreceiverinterface.h"
+#include "webrtc/api/ortc/ortcrtpsenderinterface.h"
+#include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
+#include "webrtc/api/ortc/srtptransportinterface.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/thread.h"
#include "webrtc/call/call.h"
#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
-#include "webrtc/api/ortc/ortcrtpreceiverinterface.h"
-#include "webrtc/api/ortc/ortcrtpsenderinterface.h"
-#include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
-#include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/media/base/mediachannel.h" // For MediaConfig.
#include "webrtc/pc/channelmanager.h"
#include "webrtc/pc/mediacontroller.h"
-#include "webrtc/media/base/mediachannel.h" // For MediaConfig.
namespace webrtc {
@@ -81,6 +81,12 @@
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp);
+
+ RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+ CreateProxiedSrtpTransport(const RtcpParameters& rtcp_parameters,
+ PacketTransportInterface* rtp,
+ PacketTransportInterface* rtcp);
+
// |transport_proxy| needs to be a proxy to a transport because the
// application may call GetTransport() on the returned sender or receiver,
// and expects it to return a thread-safe transport proxy.
@@ -170,6 +176,13 @@
const std::string& cname,
const cricket::MediaContentDescription& description) const;
+ // If the |rtp_transport| is a SrtpTransport, set the cryptos of the
+ // audio/video content descriptions.
+ RTCError MaybeSetCryptos(
+ RtpTransportInterface* rtp_transport,
+ cricket::MediaContentDescription* local_description,
+ cricket::MediaContentDescription* remote_description);
+
rtc::Thread* signaling_thread_;
rtc::Thread* worker_thread_;
// |transport_proxies_| and |inner_audio_transport_|/|inner_audio_transport_|
diff --git a/webrtc/ortc/srtptransport_unittest.cc b/webrtc/ortc/srtptransport_unittest.cc
new file mode 100644
index 0000000..1287a02
--- /dev/null
+++ b/webrtc/ortc/srtptransport_unittest.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#include <memory>
+
+#include "webrtc/base/gunit.h"
+#include "webrtc/media/base/fakemediaengine.h"
+#include "webrtc/ortc/ortcfactory.h"
+#include "webrtc/ortc/testrtpparameters.h"
+#include "webrtc/p2p/base/fakepackettransport.h"
+
+namespace webrtc {
+
+static const char kTestSha1KeyParams1[] =
+ "inline:WVNfX19zZW1jdGwgKCkgewkyMjA7fQp9CnVubGVz";
+static const char kTestSha1KeyParams2[] =
+ "inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR";
+static const char kTestGcmKeyParams3[] =
+ "inline:e166KFlKzJsGW0d5apX+rrI05vxbrvMJEzFI14aTDCa63IRTlLK4iH66uOI=";
+
+static const cricket::CryptoParams kTestSha1CryptoParams1(
+ 1,
+ "AES_CM_128_HMAC_SHA1_80",
+ kTestSha1KeyParams1,
+ "");
+static const cricket::CryptoParams kTestSha1CryptoParams2(
+ 1,
+ "AES_CM_128_HMAC_SHA1_80",
+ kTestSha1KeyParams2,
+ "");
+static const cricket::CryptoParams kTestGcmCryptoParams3(1,
+ "AEAD_AES_256_GCM",
+ kTestGcmKeyParams3,
+ "");
+
+// This test uses fake packet transports and a fake media engine, in order to
+// test the SrtpTransport at only an API level. Any end-to-end test should go in
+// ortcfactory_integrationtest.cc instead.
+class SrtpTransportTest : public testing::Test {
+ public:
+ SrtpTransportTest() {
+ fake_media_engine_ = new cricket::FakeMediaEngine();
+ // Note: This doesn't need to use fake network classes, since it uses
+ // FakePacketTransports.
+ auto result = OrtcFactory::Create(
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ std::unique_ptr<cricket::MediaEngineInterface>(fake_media_engine_));
+ ortc_factory_ = result.MoveValue();
+ rtp_transport_controller_ =
+ ortc_factory_->CreateRtpTransportController().MoveValue();
+
+ fake_packet_transport_.reset(new rtc::FakePacketTransport("fake"));
+ auto srtp_transport_result = ortc_factory_->CreateSrtpTransport(
+ rtcp_parameters_, fake_packet_transport_.get(), nullptr,
+ rtp_transport_controller_.get());
+ srtp_transport_ = srtp_transport_result.MoveValue();
+ }
+
+ protected:
+ // Owned by |ortc_factory_|.
+ cricket::FakeMediaEngine* fake_media_engine_;
+ std::unique_ptr<OrtcFactoryInterface> ortc_factory_;
+ std::unique_ptr<RtpTransportControllerInterface> rtp_transport_controller_;
+ std::unique_ptr<SrtpTransportInterface> srtp_transport_;
+ RtcpParameters rtcp_parameters_;
+ std::unique_ptr<rtc::FakePacketTransport> fake_packet_transport_;
+};
+
+// Tests that setting the SRTP send/receive key succeeds.
+TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKey) {
+ EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+ EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+ auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
+ srtp_transport_.get());
+ EXPECT_TRUE(sender_result.ok());
+ auto receiver_result = ortc_factory_->CreateRtpReceiver(
+ cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
+ EXPECT_TRUE(receiver_result.ok());
+}
+
+// Tests that setting the SRTP send/receive key twice is not supported.
+TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKeyTwice) {
+ EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+ EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
+ srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams2).type());
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
+ srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams1).type());
+ // Ensure that the senders and receivers can be created despite the previous
+ // errors.
+ auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
+ srtp_transport_.get());
+ EXPECT_TRUE(sender_result.ok());
+ auto receiver_result = ortc_factory_->CreateRtpReceiver(
+ cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
+ EXPECT_TRUE(receiver_result.ok());
+}
+
+// Test that the SRTP send key and receive key must have the same cipher suite.
+TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKeyDifferentCipherSuite) {
+ EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
+ srtp_transport_->SetSrtpReceiveKey(kTestGcmCryptoParams3).type());
+ EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+ // Ensure that the senders and receivers can be created despite the previous
+ // error.
+ auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
+ srtp_transport_.get());
+ EXPECT_TRUE(sender_result.ok());
+ auto receiver_result = ortc_factory_->CreateRtpReceiver(
+ cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
+ EXPECT_TRUE(receiver_result.ok());
+}
+
+class SrtpTransportTestWithMediaType
+ : public SrtpTransportTest,
+ public ::testing::WithParamInterface<cricket::MediaType> {};
+
+// Tests that the senders cannot be created before setting the keys.
+TEST_P(SrtpTransportTestWithMediaType, CreateSenderBeforeSettingKeys) {
+ auto sender_result =
+ ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, sender_result.error().type());
+ EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+ sender_result =
+ ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, sender_result.error().type());
+ EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+ // Ensure that after the keys are set, a sender can be created, despite the
+ // previous errors.
+ sender_result =
+ ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
+ EXPECT_TRUE(sender_result.ok());
+}
+
+// Tests that the receivers cannot be created before setting the keys.
+TEST_P(SrtpTransportTestWithMediaType, CreateReceiverBeforeSettingKeys) {
+ auto receiver_result =
+ ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
+ receiver_result.error().type());
+ EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+ receiver_result =
+ ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
+ receiver_result.error().type());
+ EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+ // Ensure that after the keys are set, a receiver can be created, despite the
+ // previous errors.
+ receiver_result =
+ ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
+ EXPECT_TRUE(receiver_result.ok());
+}
+
+INSTANTIATE_TEST_CASE_P(SenderCreatationTest,
+ SrtpTransportTestWithMediaType,
+ ::testing::Values(cricket::MEDIA_TYPE_AUDIO,
+ cricket::MEDIA_TYPE_VIDEO));
+
+} // namespace webrtc