From 8c0f7a7a7041b2a50914297c4aa5953ccc51183d Mon Sep 17 00:00:00 2001 From: Steve Anton Date: Tue, 3 Oct 2017 10:03:10 -0700 Subject: [PATCH] Add GetRemoteAudioSSLCertificate() to PeerConnection This method allows the client to get details about the SSL certificate sent by the remote side in the DTLS handshake. This functionality in this new method has been standardized in the RTCDtlsTransport, but until we have that implemented we wish to expose this functionality so clients do not need to depend on WebRtcSession. Bug: webrtc:8323 Change-Id: Ic964266dd7e734cec07289a147fd8d090d74ce6b Reviewed-on: https://webrtc-review.googlesource.com/5641 Reviewed-by: Taylor Brandstetter Commit-Queue: Steve Anton Cr-Commit-Position: refs/heads/master@{#20129} --- pc/peerconnection.cc | 12 +++++++ pc/peerconnection.h | 9 +++++ pc/peerconnection_integrationtest.cc | 52 ++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc index b232a26b81..77e8e024f1 100644 --- a/pc/peerconnection.cc +++ b/pc/peerconnection.cc @@ -1285,6 +1285,18 @@ RTCError PeerConnection::SetBitrate(const BitrateParameters& bitrate) { return RTCError::OK(); } +std::unique_ptr +PeerConnection::GetRemoteAudioSSLCertificate() { + if (!session_) { + return nullptr; + } + auto* voice_channel = session_->voice_channel(); + if (!voice_channel) { + return nullptr; + } + return GetRemoteSSLCertificate(voice_channel->transport_name()); +} + bool PeerConnection::StartRtcEventLog(rtc::PlatformFile file, int64_t max_size_bytes) { return worker_thread()->Invoke( diff --git a/pc/peerconnection.h b/pc/peerconnection.h index 1913e601e0..df5085bf17 100644 --- a/pc/peerconnection.h +++ b/pc/peerconnection.h @@ -70,6 +70,15 @@ class PeerConnection : public PeerConnectionInterface, // directly via this getter. virtual WebRtcSession* session() { return session_; } + // Gets the DTLS SSL certificate associated with the audio transport on the + // remote side. This will become populated once the DTLS connection with the + // peer has been completed, as indicated by the ICE connection state + // transitioning to kIceConnectionCompleted. + // Note that this will be removed once we implement RTCDtlsTransport which + // has standardized method for getting this information. + // See https://www.w3.org/TR/webrtc/#rtcdtlstransport-interface + std::unique_ptr GetRemoteAudioSSLCertificate(); + rtc::scoped_refptr CreateDtmfSender( AudioTrackInterface* track) override; diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc index 5ebf0315fa..e01230101a 100644 --- a/pc/peerconnection_integrationtest.cc +++ b/pc/peerconnection_integrationtest.cc @@ -25,6 +25,7 @@ #include "api/fakemetricsobserver.h" #include "api/mediastreaminterface.h" #include "api/peerconnectioninterface.h" +#include "api/peerconnectionproxy.h" #include "api/test/fakeconstraints.h" #include "media/engine/fakewebrtcvideoengine.h" #include "p2p/base/p2pconstants.h" @@ -66,8 +67,10 @@ using webrtc::MockDataChannelObserver; using webrtc::MockSetSessionDescriptionObserver; using webrtc::MockStatsObserver; using webrtc::ObserverInterface; +using webrtc::PeerConnection; using webrtc::PeerConnectionInterface; using webrtc::PeerConnectionFactory; +using webrtc::PeerConnectionProxy; using webrtc::SessionDescriptionInterface; using webrtc::StreamCollectionInterface; @@ -1290,6 +1293,55 @@ TEST_F(PeerConnectionIntegrationTest, EndToEndCallWithSdes) { kMaxWaitForFramesMs); } +// Tests that the GetRemoteAudioSSLCertificate method returns the remote DTLS +// certificate once the DTLS handshake has finished. +TEST_F(PeerConnectionIntegrationTest, + GetRemoteAudioSSLCertificateReturnsExchangedCertificate) { + auto GetRemoteAudioSSLCertificate = [](PeerConnectionWrapper* wrapper) { + auto pci = reinterpret_cast(wrapper->pc()); + auto pc = reinterpret_cast(pci->internal()); + return pc->GetRemoteAudioSSLCertificate(); + }; + + auto caller_cert = rtc::RTCCertificate::FromPEM(kRsaPems[0]); + auto callee_cert = rtc::RTCCertificate::FromPEM(kRsaPems[1]); + + // Configure each side with a known certificate so they can be compared later. + PeerConnectionInterface::RTCConfiguration caller_config; + caller_config.enable_dtls_srtp.emplace(true); + caller_config.certificates.push_back(caller_cert); + PeerConnectionInterface::RTCConfiguration callee_config; + callee_config.enable_dtls_srtp.emplace(true); + callee_config.certificates.push_back(callee_cert); + ASSERT_TRUE( + CreatePeerConnectionWrappersWithConfig(caller_config, callee_config)); + ConnectFakeSignaling(); + + // When first initialized, there should not be a remote SSL certificate (and + // calling this method should not crash). + EXPECT_EQ(nullptr, GetRemoteAudioSSLCertificate(caller())); + EXPECT_EQ(nullptr, GetRemoteAudioSSLCertificate(callee())); + + caller()->AddAudioOnlyMediaStream(); + callee()->AddAudioOnlyMediaStream(); + caller()->CreateAndSetAndSignalOffer(); + ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout); + ASSERT_TRUE_WAIT(DtlsConnected(), kDefaultTimeout); + + // Once DTLS has been connected, each side should return the other's SSL + // certificate when calling GetRemoteAudioSSLCertificate. + + auto caller_remote_cert = GetRemoteAudioSSLCertificate(caller()); + ASSERT_TRUE(caller_remote_cert); + EXPECT_EQ(callee_cert->ssl_certificate().ToPEMString(), + caller_remote_cert->ToPEMString()); + + auto callee_remote_cert = GetRemoteAudioSSLCertificate(callee()); + ASSERT_TRUE(callee_remote_cert); + EXPECT_EQ(caller_cert->ssl_certificate().ToPEMString(), + callee_remote_cert->ToPEMString()); +} + // This test sets up a call between two parties (using DTLS) and tests that we // can get a video aspect ratio of 16:9. TEST_F(PeerConnectionIntegrationTest, SendAndReceive16To9AspectRatio) {