diff --git a/api/BUILD.gn b/api/BUILD.gn index 84b0c0ebb3..31dd8983ce 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -93,6 +93,7 @@ rtc_static_library("libjingle_peerconnection_api") { "crypto_params.h", "data_channel_interface.cc", "data_channel_interface.h", + "dtls_transport_interface.cc", "dtls_transport_interface.h", "dtmf_sender_interface.h", "ice_transport_interface.h", diff --git a/api/DEPS b/api/DEPS index 6afa3d7ab0..34bdfe03ce 100644 --- a/api/DEPS +++ b/api/DEPS @@ -75,6 +75,7 @@ specific_include_rules = { "dtls_transport_interface\.h": [ "+rtc_base/ref_count.h", + "+rtc_base/ssl_certificate.h", ], "dtmf_sender_interface\.h": [ diff --git a/api/dtls_transport_interface.cc b/api/dtls_transport_interface.cc new file mode 100644 index 0000000000..2bb5049615 --- /dev/null +++ b/api/dtls_transport_interface.cc @@ -0,0 +1,43 @@ +/* + * Copyright 2019 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 "api/dtls_transport_interface.h" + +namespace webrtc { + +DtlsTransportInformation::DtlsTransportInformation() + : state_(DtlsTransportState::kNew) {} + +DtlsTransportInformation::DtlsTransportInformation(DtlsTransportState state) + : state_(state) {} + +DtlsTransportInformation::DtlsTransportInformation( + DtlsTransportState state, + std::unique_ptr remote_ssl_certificates) + : state_(state), + remote_ssl_certificates_(std::move(remote_ssl_certificates)) {} + +DtlsTransportInformation::DtlsTransportInformation( + const DtlsTransportInformation& c) + : state_(c.state()), + remote_ssl_certificates_(c.remote_ssl_certificates() + ? c.remote_ssl_certificates()->Clone() + : nullptr) {} + +DtlsTransportInformation& DtlsTransportInformation::operator=( + const DtlsTransportInformation& c) { + state_ = c.state(); + remote_ssl_certificates_ = c.remote_ssl_certificates() + ? c.remote_ssl_certificates()->Clone() + : nullptr; + return *this; +} + +} // namespace webrtc diff --git a/api/dtls_transport_interface.h b/api/dtls_transport_interface.h index 7f35a232f3..0270043cbc 100644 --- a/api/dtls_transport_interface.h +++ b/api/dtls_transport_interface.h @@ -11,10 +11,14 @@ #ifndef API_DTLS_TRANSPORT_INTERFACE_H_ #define API_DTLS_TRANSPORT_INTERFACE_H_ +#include +#include + #include "api/ice_transport_interface.h" #include "api/rtc_error.h" #include "api/scoped_refptr.h" #include "rtc_base/ref_count.h" +#include "rtc_base/ssl_certificate.h" namespace webrtc { @@ -34,11 +38,28 @@ enum class DtlsTransportState { // DTLSTransport. class DtlsTransportInformation { public: - explicit DtlsTransportInformation(DtlsTransportState state) : state_(state) {} + DtlsTransportInformation(); + explicit DtlsTransportInformation(DtlsTransportState state); + DtlsTransportInformation( + DtlsTransportState state, + std::unique_ptr remote_ssl_certificates); + // Copy and assign + DtlsTransportInformation(const DtlsTransportInformation& c); + DtlsTransportInformation& operator=(const DtlsTransportInformation& c); + // Move + DtlsTransportInformation(DtlsTransportInformation&& other) = default; + DtlsTransportInformation& operator=(DtlsTransportInformation&& other) = + default; + DtlsTransportState state() const { return state_; } - // TODO(hta): Add remote certificate access + // The accessor returns a temporary pointer, it does not release ownership. + const rtc::SSLCertChain* remote_ssl_certificates() const { + return remote_ssl_certificates_.get(); + } + private: DtlsTransportState state_; + std::unique_ptr remote_ssl_certificates_; }; class DtlsTransportObserverInterface { diff --git a/pc/dtls_transport.cc b/pc/dtls_transport.cc index 38cef1e549..9ce72a3b8b 100644 --- a/pc/dtls_transport.cc +++ b/pc/dtls_transport.cc @@ -116,8 +116,15 @@ void DtlsTransport::UpdateInformation() { RTC_DCHECK_RUN_ON(owner_thread_); rtc::CritScope scope(&lock_); if (internal_dtls_transport_) { - info_ = DtlsTransportInformation( - TranslateState(internal_dtls_transport_->dtls_state())); + if (internal_dtls_transport_->dtls_state() == + cricket::DTLS_TRANSPORT_CONNECTED) { + info_ = DtlsTransportInformation( + TranslateState(internal_dtls_transport_->dtls_state()), + internal_dtls_transport_->GetRemoteSSLCertChain()); + } else { + info_ = DtlsTransportInformation( + TranslateState(internal_dtls_transport_->dtls_state())); + } } else { info_ = DtlsTransportInformation(DtlsTransportState::kClosed); } diff --git a/pc/dtls_transport_unittest.cc b/pc/dtls_transport_unittest.cc index 0c27c1b6c3..05f5440b24 100644 --- a/pc/dtls_transport_unittest.cc +++ b/pc/dtls_transport_unittest.cc @@ -31,6 +31,7 @@ class TestDtlsTransportObserver : public DtlsTransportObserverInterface { void OnStateChange(DtlsTransportInformation info) override { state_change_called_ = true; states_.push_back(info.state()); + info_ = info; } void OnError(RTCError error) override {} @@ -44,6 +45,7 @@ class TestDtlsTransportObserver : public DtlsTransportObserverInterface { } bool state_change_called_ = false; + DtlsTransportInformation info_; std::vector states_; }; @@ -52,9 +54,12 @@ class DtlsTransportTest : public ::testing::Test { DtlsTransport* transport() { return transport_.get(); } DtlsTransportObserverInterface* observer() { return &observer_; } - void CreateTransport() { + void CreateTransport(rtc::FakeSSLCertificate* certificate = nullptr) { auto cricket_transport = absl::make_unique( "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP); + if (certificate) { + cricket_transport->SetRemoteSSLCertificate(certificate); + } transport_ = new rtc::RefCountedObject(std::move(cricket_transport)); } @@ -113,4 +118,28 @@ TEST_F(DtlsTransportTest, CloseWhenClearing) { kDefaultTimeout); } +TEST_F(DtlsTransportTest, CertificateAppearsOnConnect) { + rtc::FakeSSLCertificate fake_certificate("fake data"); + CreateTransport(&fake_certificate); + transport()->RegisterObserver(observer()); + CompleteDtlsHandshake(); + ASSERT_TRUE_WAIT(observer_.state() == DtlsTransportState::kConnected, + kDefaultTimeout); + EXPECT_TRUE(observer_.info_.remote_ssl_certificates() != nullptr); +} + +TEST_F(DtlsTransportTest, CertificateDisappearsOnClose) { + rtc::FakeSSLCertificate fake_certificate("fake data"); + CreateTransport(&fake_certificate); + transport()->RegisterObserver(observer()); + CompleteDtlsHandshake(); + ASSERT_TRUE_WAIT(observer_.state() == DtlsTransportState::kConnected, + kDefaultTimeout); + EXPECT_TRUE(observer_.info_.remote_ssl_certificates() != nullptr); + transport()->Clear(); + ASSERT_TRUE_WAIT(observer_.state() == DtlsTransportState::kClosed, + kDefaultTimeout); + EXPECT_FALSE(observer_.info_.remote_ssl_certificates()); +} + } // namespace webrtc