From 6b63cd5e54ed535977d136438adbfb03b28f0488 Mon Sep 17 00:00:00 2001 From: Steve Anton Date: Fri, 6 Oct 2017 11:20:31 -0700 Subject: [PATCH] Rewrite WebRtcSession DTLS/SDES crypto tests as PeerConnection tests Bug: webrtc:8222 Change-Id: I6be2c5a5735b77a5c577472b88ff830204dd69eb Reviewed-on: https://webrtc-review.googlesource.com/1160 Commit-Queue: Steve Anton Reviewed-by: Taylor Brandstetter Cr-Commit-Position: refs/heads/master@{#20193} --- pc/BUILD.gn | 1 + pc/channel.h | 3 - pc/peerconnection_crypto_unittest.cc | 605 ++++++++++++++ pc/test/fakertccertificategenerator.h | 18 +- pc/webrtcsession.cc | 4 - pc/webrtcsession.h | 2 - pc/webrtcsession_unittest.cc | 758 ------------------ ...eerconnection_unittests.gtest-memcheck.txt | 1 + 8 files changed, 624 insertions(+), 768 deletions(-) create mode 100644 pc/peerconnection_crypto_unittest.cc diff --git a/pc/BUILD.gn b/pc/BUILD.gn index 1bfa37cae1..6e95bf8a8f 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -391,6 +391,7 @@ if (rtc_include_tests) { "localaudiosource_unittest.cc", "mediaconstraintsinterface_unittest.cc", "mediastream_unittest.cc", + "peerconnection_crypto_unittest.cc", "peerconnection_integrationtest.cc", "peerconnectionendtoend_unittest.cc", "peerconnectionfactory_unittest.cc", diff --git a/pc/channel.h b/pc/channel.h index d9b149cb87..c5888db558 100644 --- a/pc/channel.h +++ b/pc/channel.h @@ -185,9 +185,6 @@ class BaseChannel virtual cricket::MediaType media_type() = 0; - // This function returns true if we require SRTP for call setup. - bool srtp_required_for_testing() const { return srtp_required_; } - // Public for testing. // TODO(zstein): Remove this once channels register themselves with // an RtpTransport in a more explicit way. diff --git a/pc/peerconnection_crypto_unittest.cc b/pc/peerconnection_crypto_unittest.cc new file mode 100644 index 0000000000..0f5499509b --- /dev/null +++ b/pc/peerconnection_crypto_unittest.cc @@ -0,0 +1,605 @@ +/* + * 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 "p2p/base/fakeportallocator.h" +#include "pc/mediasession.h" +#include "pc/peerconnectionwrapper.h" +#include "pc/sdputils.h" +#ifdef WEBRTC_ANDROID +#include "pc/test/androidtestinitializer.h" +#endif +#include "pc/test/fakeaudiocapturemodule.h" +#include "pc/test/fakertccertificategenerator.h" +#include "rtc_base/gunit.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/virtualsocketserver.h" + +namespace webrtc { + +using RTCConfiguration = PeerConnectionInterface::RTCConfiguration; +using ::testing::Values; +using ::testing::Combine; + +constexpr int kGenerateCertTimeout = 1000; + +class PeerConnectionCryptoUnitTest : public ::testing::Test { + protected: + typedef std::unique_ptr WrapperPtr; + + PeerConnectionCryptoUnitTest() + : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) { +#ifdef WEBRTC_ANDROID + InitializeAndroidObjects(); +#endif + pc_factory_ = CreatePeerConnectionFactory( + rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(), + FakeAudioCaptureModule::Create(), nullptr, nullptr); + } + + WrapperPtr CreatePeerConnection(const RTCConfiguration& config) { + return CreatePeerConnection(config, nullptr); + } + + WrapperPtr CreatePeerConnection( + const RTCConfiguration& config, + std::unique_ptr cert_gen) { + auto fake_port_allocator = rtc::MakeUnique( + rtc::Thread::Current(), nullptr); + auto observer = rtc::MakeUnique(); + auto pc = pc_factory_->CreatePeerConnection( + config, std::move(fake_port_allocator), std::move(cert_gen), + observer.get()); + if (!pc) { + return nullptr; + } + + return rtc::MakeUnique(pc_factory_, pc, + std::move(observer)); + } + + // Accepts the same arguments as CreatePeerConnection and adds default audio + // and video tracks. + template + WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) { + auto wrapper = CreatePeerConnection(std::forward(args)...); + if (!wrapper) { + return nullptr; + } + wrapper->AddAudioVideoStream("s", "a", "v"); + return wrapper; + } + + std::unique_ptr vss_; + rtc::AutoSocketServerThread main_; + rtc::scoped_refptr pc_factory_; +}; + +SdpContentPredicate HaveDtlsFingerprint() { + return [](const cricket::ContentInfo* content, + const cricket::TransportInfo* transport) { + return transport->description.identity_fingerprint != nullptr; + }; +} + +SdpContentPredicate HaveSdesCryptos() { + return [](const cricket::ContentInfo* content, + const cricket::TransportInfo* transport) { + const auto* media_desc = + static_cast( + content->description); + return !media_desc->cryptos().empty(); + }; +} + +SdpContentPredicate HaveProtocol(const std::string& protocol) { + return [protocol](const cricket::ContentInfo* content, + const cricket::TransportInfo* transport) { + const auto* media_desc = + static_cast( + content->description); + return media_desc->protocol() == protocol; + }; +} + +SdpContentPredicate HaveSdesGcmCryptos(size_t num_crypto_suites) { + return [num_crypto_suites](const cricket::ContentInfo* content, + const cricket::TransportInfo* transport) { + const auto* media_desc = + static_cast( + content->description); + if (media_desc->cryptos().size() != num_crypto_suites) { + return false; + } + const cricket::CryptoParams first_params = media_desc->cryptos()[0]; + return first_params.key_params.size() == 67U && + first_params.cipher_suite == "AEAD_AES_256_GCM"; + }; +} + +SdpContentMutator RemoveSdesCryptos() { + return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) { + auto* media_desc = + static_cast(content->description); + media_desc->set_cryptos({}); + }; +} + +SdpContentMutator RemoveDtlsFingerprint() { + return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) { + transport->description.identity_fingerprint.reset(); + }; +} + +// When DTLS is enabled, the SDP offer/answer should have a DTLS fingerprint and +// no SDES cryptos. +TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInOfferWhenDtlsEnabled) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(true); + auto caller = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + ASSERT_TRUE(offer); + + ASSERT_FALSE(offer->description()->contents().empty()); + EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), offer->description())); + EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description())); + EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf), + offer->description())); +} +TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInAnswerWhenDtlsEnabled) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(true); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + callee->SetRemoteDescription(caller->CreateOffer()); + auto answer = callee->CreateAnswer(); + ASSERT_TRUE(answer); + + ASSERT_FALSE(answer->description()->contents().empty()); + EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), answer->description())); + EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description())); + EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf), + answer->description())); +} + +// When DTLS is disabled, the SDP offer/answer should include SDES cryptos and +// should not have a DTLS fingerprint. +TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInOfferWhenDtlsDisabled) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + ASSERT_TRUE(offer); + + ASSERT_FALSE(offer->description()->contents().empty()); + EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), offer->description())); + EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description())); + EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf), + offer->description())); +} +TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInAnswerWhenDtlsDisabled) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + callee->SetRemoteDescription(caller->CreateOffer()); + auto answer = callee->CreateAnswer(); + ASSERT_TRUE(answer); + + ASSERT_FALSE(answer->description()->contents().empty()); + EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), answer->description())); + EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description())); + EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf), + answer->description())); +} + +// When encryption is disabled, the SDP offer/answer should have neither a DTLS +// fingerprint nor any SDES crypto options. +TEST_F(PeerConnectionCryptoUnitTest, + CorrectCryptoInOfferWhenEncryptionDisabled) { + PeerConnectionFactoryInterface::Options options; + options.disable_encryption = true; + pc_factory_->SetOptions(options); + + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + ASSERT_TRUE(offer); + + ASSERT_FALSE(offer->description()->contents().empty()); + EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description())); + EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description())); + EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf), + offer->description())); +} +TEST_F(PeerConnectionCryptoUnitTest, + CorrectCryptoInAnswerWhenEncryptionDisabled) { + PeerConnectionFactoryInterface::Options options; + options.disable_encryption = true; + pc_factory_->SetOptions(options); + + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + callee->SetRemoteDescription(caller->CreateOffer()); + auto answer = callee->CreateAnswer(); + ASSERT_TRUE(answer); + + ASSERT_FALSE(answer->description()->contents().empty()); + EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description())); + EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description())); + EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf), + answer->description())); +} + +// When DTLS is disabled and GCM cipher suites are enabled, the SDP offer/answer +// should have the correct ciphers in the SDES crypto options. +// With GCM cipher suites enabled, there will be 3 cryptos in the offer and 1 +// in the answer. +TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInOfferWithSdesAndGcm) { + PeerConnectionFactoryInterface::Options options; + options.crypto_options.enable_gcm_crypto_suites = true; + pc_factory_->SetOptions(options); + + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + ASSERT_TRUE(offer); + + ASSERT_FALSE(offer->description()->contents().empty()); + EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description())); +} +TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInAnswerWithSdesAndGcm) { + PeerConnectionFactoryInterface::Options options; + options.crypto_options.enable_gcm_crypto_suites = true; + pc_factory_->SetOptions(options); + + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + callee->SetRemoteDescription(caller->CreateOffer()); + auto answer = callee->CreateAnswer(); + ASSERT_TRUE(answer); + + ASSERT_FALSE(answer->description()->contents().empty()); + EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(1), answer->description())); +} + +TEST_F(PeerConnectionCryptoUnitTest, CanSetSdesGcmRemoteOfferAndLocalAnswer) { + PeerConnectionFactoryInterface::Options options; + options.crypto_options.enable_gcm_crypto_suites = true; + pc_factory_->SetOptions(options); + + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + ASSERT_TRUE(offer); + ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer))); + + auto answer = callee->CreateAnswer(); + ASSERT_TRUE(answer); + ASSERT_TRUE(callee->SetLocalDescription(std::move(answer))); +} + +// The following group tests that two PeerConnections can successfully exchange +// an offer/answer when DTLS is off and that they will refuse any offer/answer +// applied locally/remotely if it does not include SDES cryptos. +TEST_F(PeerConnectionCryptoUnitTest, ExchangeOfferAnswerWhenSdesOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOfferAndSetAsLocal(); + ASSERT_TRUE(offer); + ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer))); + + auto answer = callee->CreateAnswerAndSetAsLocal(); + ASSERT_TRUE(answer); + ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer))); +} +TEST_F(PeerConnectionCryptoUnitTest, + FailToSetLocalOfferWithNoCryptosWhenSdesOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + SdpContentsForEach(RemoveSdesCryptos(), offer->description()); + + EXPECT_FALSE(caller->SetLocalDescription(std::move(offer))); +} +TEST_F(PeerConnectionCryptoUnitTest, + FailToSetRemoteOfferWithNoCryptosWhenSdesOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + SdpContentsForEach(RemoveSdesCryptos(), offer->description()); + + EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer))); +} +TEST_F(PeerConnectionCryptoUnitTest, + FailToSetLocalAnswerWithNoCryptosWhenSdesOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()); + auto answer = callee->CreateAnswer(); + SdpContentsForEach(RemoveSdesCryptos(), answer->description()); + + EXPECT_FALSE(callee->SetLocalDescription(std::move(answer))); +} +TEST_F(PeerConnectionCryptoUnitTest, + FailToSetRemoteAnswerWithNoCryptosWhenSdesOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()); + auto answer = callee->CreateAnswerAndSetAsLocal(); + SdpContentsForEach(RemoveSdesCryptos(), answer->description()); + + EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer))); +} + +// The following group tests that two PeerConnections can successfully exchange +// an offer/answer when DTLS is on and that they will refuse any offer/answer +// applied locally/remotely if it does not include a DTLS fingerprint. +TEST_F(PeerConnectionCryptoUnitTest, ExchangeOfferAnswerWhenDtlsOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(true); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOfferAndSetAsLocal(); + ASSERT_TRUE(offer); + ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer))); + + auto answer = callee->CreateAnswerAndSetAsLocal(); + ASSERT_TRUE(answer); + ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer))); +} +TEST_F(PeerConnectionCryptoUnitTest, + FailToSetLocalOfferWithNoFingerprintWhenDtlsOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(true); + auto caller = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + SdpContentsForEach(RemoveDtlsFingerprint(), offer->description()); + + EXPECT_FALSE(caller->SetLocalDescription(std::move(offer))); +} +TEST_F(PeerConnectionCryptoUnitTest, + FailToSetRemoteOfferWithNoFingerprintWhenDtlsOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(true); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOffer(); + SdpContentsForEach(RemoveDtlsFingerprint(), offer->description()); + + EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer))); +} +TEST_F(PeerConnectionCryptoUnitTest, + FailToSetLocalAnswerWithNoFingerprintWhenDtlsOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(true); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()); + auto answer = callee->CreateAnswer(); + SdpContentsForEach(RemoveDtlsFingerprint(), answer->description()); +} +TEST_F(PeerConnectionCryptoUnitTest, + FailToSetRemoteAnswerWithNoFingerprintWhenDtlsOn) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(true); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()); + auto answer = callee->CreateAnswerAndSetAsLocal(); + SdpContentsForEach(RemoveDtlsFingerprint(), answer->description()); + + EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer))); +} + +// Test that an offer/answer can be exchanged when encryption is disabled. +TEST_F(PeerConnectionCryptoUnitTest, ExchangeOfferAnswerWhenNoEncryption) { + PeerConnectionFactoryInterface::Options options; + options.disable_encryption = true; + pc_factory_->SetOptions(options); + + RTCConfiguration config; + config.enable_dtls_srtp.emplace(false); + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(config); + + auto offer = caller->CreateOfferAndSetAsLocal(); + ASSERT_TRUE(offer); + ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer))); + + auto answer = callee->CreateAnswerAndSetAsLocal(); + ASSERT_TRUE(answer); + ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer))); +} + +// Tests that a DTLS call can be established when the certificate is specified +// in the PeerConnection config and no certificate generator is specified. +TEST_F(PeerConnectionCryptoUnitTest, + ExchangeOfferAnswerWhenDtlsCertificateInConfig) { + RTCConfiguration caller_config; + caller_config.enable_dtls_srtp.emplace(true); + caller_config.certificates.push_back( + FakeRTCCertificateGenerator::GenerateCertificate()); + auto caller = CreatePeerConnectionWithAudioVideo(caller_config); + + RTCConfiguration callee_config; + callee_config.enable_dtls_srtp.emplace(true); + callee_config.certificates.push_back( + FakeRTCCertificateGenerator::GenerateCertificate()); + auto callee = CreatePeerConnectionWithAudioVideo(callee_config); + + auto offer = caller->CreateOfferAndSetAsLocal(); + ASSERT_TRUE(offer); + ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer))); + + auto answer = callee->CreateAnswerAndSetAsLocal(); + ASSERT_TRUE(answer); + ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer))); +} + +// The following parameterized test verifies that CreateOffer/CreateAnswer +// returns successfully (or with failure if the underlying certificate generator +// fails) no matter when the DTLS certificate is generated. If multiple +// CreateOffer/CreateAnswer calls are made while waiting for the certificate, +// they all finish after the certificate is generated. + +// Whether the test will call CreateOffer or CreateAnswer. +enum class SdpType { kOffer, kAnswer }; +std::ostream& operator<<(std::ostream& out, SdpType value) { + switch (value) { + case SdpType::kOffer: + return out << "offer"; + case SdpType::kAnswer: + return out << "answer"; + default: + return out << "unknown"; + } +} + +// Whether the certificate will be generated before calling CreateOffer or +// while CreateOffer is executing. +enum class CertGenTime { kBefore, kDuring }; +std::ostream& operator<<(std::ostream& out, CertGenTime value) { + switch (value) { + case CertGenTime::kBefore: + return out << "before"; + case CertGenTime::kDuring: + return out << "during"; + default: + return out << "unknown"; + } +} + +// Whether the fake certificate generator will produce a certificate or fail. +enum class CertGenResult { kSucceed, kFail }; +std::ostream& operator<<(std::ostream& out, CertGenResult value) { + switch (value) { + case CertGenResult::kSucceed: + return out << "succeed"; + case CertGenResult::kFail: + return out << "fail"; + default: + return out << "unknown"; + } +} + +class PeerConnectionCryptoDtlsCertGenUnitTest + : public PeerConnectionCryptoUnitTest, + public ::testing::WithParamInterface< + ::testing::tuple> { + protected: + PeerConnectionCryptoDtlsCertGenUnitTest() { + sdp_type_ = ::testing::get<0>(GetParam()); + cert_gen_time_ = ::testing::get<1>(GetParam()); + cert_gen_result_ = ::testing::get<2>(GetParam()); + concurrent_calls_ = ::testing::get<3>(GetParam()); + } + + SdpType sdp_type_; + CertGenTime cert_gen_time_; + CertGenResult cert_gen_result_; + size_t concurrent_calls_; +}; + +TEST_P(PeerConnectionCryptoDtlsCertGenUnitTest, TestCertificateGeneration) { + RTCConfiguration config; + config.enable_dtls_srtp.emplace(true); + auto owned_fake_certificate_generator = + rtc::MakeUnique(); + auto* fake_certificate_generator = owned_fake_certificate_generator.get(); + fake_certificate_generator->set_should_fail(cert_gen_result_ == + CertGenResult::kFail); + fake_certificate_generator->set_should_wait(cert_gen_time_ == + CertGenTime::kDuring); + WrapperPtr pc; + if (sdp_type_ == SdpType::kOffer) { + pc = CreatePeerConnectionWithAudioVideo( + config, std::move(owned_fake_certificate_generator)); + } else { + auto caller = CreatePeerConnectionWithAudioVideo(config); + pc = CreatePeerConnectionWithAudioVideo( + config, std::move(owned_fake_certificate_generator)); + pc->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()); + } + if (cert_gen_time_ == CertGenTime::kBefore) { + ASSERT_TRUE_WAIT(fake_certificate_generator->generated_certificates() + + fake_certificate_generator->generated_failures() > + 0, + kGenerateCertTimeout); + } else { + ASSERT_EQ(fake_certificate_generator->generated_certificates(), 0); + fake_certificate_generator->set_should_wait(false); + } + std::vector> + observers; + for (size_t i = 0; i < concurrent_calls_; i++) { + rtc::scoped_refptr observer = + new rtc::RefCountedObject(); + observers.push_back(observer); + if (sdp_type_ == SdpType::kOffer) { + pc->pc()->CreateOffer(observer, nullptr); + } else { + pc->pc()->CreateAnswer(observer, nullptr); + } + } + for (auto& observer : observers) { + EXPECT_TRUE_WAIT(observer->called(), 1000); + if (cert_gen_result_ == CertGenResult::kSucceed) { + EXPECT_TRUE(observer->result()); + } else { + EXPECT_FALSE(observer->result()); + } + } +} + +INSTANTIATE_TEST_CASE_P( + PeerConnectionCryptoUnitTest, + PeerConnectionCryptoDtlsCertGenUnitTest, + Combine(Values(SdpType::kOffer, SdpType::kAnswer), + Values(CertGenTime::kBefore, CertGenTime::kDuring), + Values(CertGenResult::kSucceed, CertGenResult::kFail), + Values(1, 3))); + +} // namespace webrtc diff --git a/pc/test/fakertccertificategenerator.h b/pc/test/fakertccertificategenerator.h index cac33e4844..9cc79284ea 100644 --- a/pc/test/fakertccertificategenerator.h +++ b/pc/test/fakertccertificategenerator.h @@ -125,16 +125,21 @@ class FakeRTCCertificateGenerator typedef rtc::TypedMessageData > MessageData; - FakeRTCCertificateGenerator() : should_fail_(false) {} + FakeRTCCertificateGenerator() : should_fail_(false), should_wait_(false) {} void set_should_fail(bool should_fail) { should_fail_ = should_fail; } + // If set to true, stalls the generation of the fake certificate until it is + // set to false. + void set_should_wait(bool should_wait) { should_wait_ = should_wait; } + void use_original_key() { key_index_ = 0; } void use_alternate_key() { key_index_ = 1; } int generated_certificates() { return generated_certificates_; } + int generated_failures() { return generated_failures_; } void GenerateCertificateAsync( const rtc::KeyParams& key_params, @@ -201,6 +206,14 @@ class FakeRTCCertificateGenerator // rtc::MessageHandler implementation. void OnMessage(rtc::Message* msg) override { + // If the certificate generation should be stalled, re-post this same + // message to the queue with a small delay so as to wait in a loop until + // set_should_wait(false) is called. + if (should_wait_) { + rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, 1, this, + msg->message_id, msg->pdata); + return; + } MessageData* message_data = static_cast(msg->pdata); rtc::scoped_refptr callback = message_data->data(); @@ -217,6 +230,7 @@ class FakeRTCCertificateGenerator break; } case MSG_FAILURE: + ++generated_failures_; callback->OnFailure(); break; } @@ -224,8 +238,10 @@ class FakeRTCCertificateGenerator } bool should_fail_; + bool should_wait_; int key_index_ = 0; int generated_certificates_ = 0; + int generated_failures_ = 0; }; #endif // PC_TEST_FAKERTCCERTIFICATEGENERATOR_H_ diff --git a/pc/webrtcsession.cc b/pc/webrtcsession.cc index 86015a79fa..f556204c6c 100644 --- a/pc/webrtcsession.cc +++ b/pc/webrtcsession.cc @@ -667,10 +667,6 @@ cricket::BaseChannel* WebRtcSession::GetChannel( return nullptr; } -cricket::SecurePolicy WebRtcSession::SdesPolicy() const { - return webrtc_session_desc_factory_->SdesPolicy(); -} - bool WebRtcSession::GetSctpSslRole(rtc::SSLRole* role) { if (!local_description() || !remote_description()) { LOG(LS_INFO) << "Local and Remote descriptions must be applied to get the " diff --git a/pc/webrtcsession.h b/pc/webrtcsession.h index 284c601b41..16c3931b35 100644 --- a/pc/webrtcsession.h +++ b/pc/webrtcsession.h @@ -241,8 +241,6 @@ class WebRtcSession : cricket::BaseChannel* GetChannel(const std::string& content_name); - cricket::SecurePolicy SdesPolicy() const; - // Get current SSL role used by SCTP's underlying transport. bool GetSctpSslRole(rtc::SSLRole* role); // Get SSL role for an arbitrary m= section (handles bundling correctly). diff --git a/pc/webrtcsession_unittest.cc b/pc/webrtcsession_unittest.cc index fe0049d33a..e3a9e924eb 100644 --- a/pc/webrtcsession_unittest.cc +++ b/pc/webrtcsession_unittest.cc @@ -81,10 +81,6 @@ static const char kClientIPv6AddrHost1[] = "2620:0:aaaa:bbbb:cccc:dddd:eeee:ffff"; static const char kClientAddrHost2[] = "22.22.22.22"; static const char kStunAddrHost[] = "99.99.99.1"; -static const SocketAddress kTurnUdpIntAddr("99.99.99.4", 3478); -static const SocketAddress kTurnUdpExtAddr("99.99.99.6", 0); -static const char kTurnUsername[] = "test"; -static const char kTurnPassword[] = "test"; static const char kSessionVersion[] = "1"; @@ -99,10 +95,6 @@ static const char kMediaContentName1[] = "video"; static const int kDefaultTimeout = 10000; // 10 seconds. static const int kIceCandidatesTimeout = 10000; -static const char kFakeDtlsFingerprint[] = - "BB:CD:72:F7:2F:D0:BA:43:F3:68:B1:0C:23:72:B6:4A:" - "0F:DE:34:06:BC:E0:FE:01:BC:73:C8:6D:F4:65:D5:24"; - static const char kTooLongIceUfragPwd[] = "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag" "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag" @@ -343,22 +335,6 @@ class WebRtcSessionCreateSDPObserverForTest State state_; }; -class FakeAudioSource : public cricket::AudioSource { - public: - FakeAudioSource() : sink_(NULL) {} - virtual ~FakeAudioSource() { - if (sink_) - sink_->OnClose(); - } - - void SetSink(Sink* sink) override { sink_ = sink; } - - const cricket::AudioSource::Sink* sink() const { return sink_; } - - private: - cricket::AudioSource::Sink* sink_; -}; - class WebRtcSessionTest : public testing::TestWithParam, public sigslot::has_slots<> { @@ -384,7 +360,6 @@ class WebRtcSessionTest rtc::SocketAddress(kStunAddrHost, cricket::STUN_SERVER_PORT)), stun_server_(cricket::TestStunServer::Create(Thread::Current(), stun_socket_addr_)), - turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr), metrics_observer_(new rtc::RefCountedObject()) { cricket::ServerAddresses stun_servers; stun_servers.insert(stun_socket_addr_); @@ -464,11 +439,6 @@ class WebRtcSessionTest Init(nullptr, rtcp_mux_policy, rtc::CryptoOptions()); } - void InitWithCryptoOptions(const rtc::CryptoOptions& crypto_options) { - Init(nullptr, PeerConnectionInterface::kRtcpMuxPolicyNegotiate, - crypto_options); - } - // Successfully init with DTLS; with a certificate generated and supplied or // with a store that generates it for us. void InitWithDtls(RTCCertificateGenerationMethod cert_gen_method) { @@ -487,22 +457,6 @@ class WebRtcSessionTest rtc::CryptoOptions()); } - // Init with DTLS with a store that will fail to generate a certificate. - void InitWithDtlsIdentityGenFail() { - std::unique_ptr cert_generator( - new FakeRTCCertificateGenerator()); - cert_generator->set_should_fail(true); - Init(std::move(cert_generator), - PeerConnectionInterface::kRtcpMuxPolicyNegotiate, - rtc::CryptoOptions()); - } - - void InitWithGcm() { - rtc::CryptoOptions crypto_options; - crypto_options.enable_gcm_crypto_suites = true; - InitWithCryptoOptions(crypto_options); - } - // The following convenience functions can be applied for both local side and // remote side. The flags can be overwritten for different use cases. void SendAudioVideoStream1() { @@ -818,95 +772,6 @@ class WebRtcSessionTest return CreateAnswer(options); } - bool ChannelsExist() const { - return (session_->voice_channel() != NULL && - session_->video_channel() != NULL); - } - - void VerifyCryptoParams(const cricket::SessionDescription* sdp, - bool gcm_enabled = false) { - ASSERT_TRUE(session_.get() != NULL); - const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp); - ASSERT_TRUE(content != NULL); - const cricket::AudioContentDescription* audio_content = - static_cast( - content->description); - ASSERT_TRUE(audio_content != NULL); - if (!gcm_enabled) { - ASSERT_EQ(1U, audio_content->cryptos().size()); - ASSERT_EQ(47U, audio_content->cryptos()[0].key_params.size()); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", - audio_content->cryptos()[0].cipher_suite); - EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), - audio_content->protocol()); - } else { - // The offer contains 3 possible crypto suites, the answer 1. - EXPECT_LE(1U, audio_content->cryptos().size()); - EXPECT_NE(2U, audio_content->cryptos().size()); - EXPECT_GE(3U, audio_content->cryptos().size()); - ASSERT_EQ(67U, audio_content->cryptos()[0].key_params.size()); - ASSERT_EQ("AEAD_AES_256_GCM", - audio_content->cryptos()[0].cipher_suite); - EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), - audio_content->protocol()); - } - - content = cricket::GetFirstVideoContent(sdp); - ASSERT_TRUE(content != NULL); - const cricket::VideoContentDescription* video_content = - static_cast( - content->description); - ASSERT_TRUE(video_content != NULL); - if (!gcm_enabled) { - ASSERT_EQ(1U, video_content->cryptos().size()); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", - video_content->cryptos()[0].cipher_suite); - ASSERT_EQ(47U, video_content->cryptos()[0].key_params.size()); - EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), - video_content->protocol()); - } else { - // The offer contains 3 possible crypto suites, the answer 1. - EXPECT_LE(1U, video_content->cryptos().size()); - EXPECT_NE(2U, video_content->cryptos().size()); - EXPECT_GE(3U, video_content->cryptos().size()); - ASSERT_EQ("AEAD_AES_256_GCM", - video_content->cryptos()[0].cipher_suite); - ASSERT_EQ(67U, video_content->cryptos()[0].key_params.size()); - EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), - video_content->protocol()); - } - } - - void VerifyNoCryptoParams(const cricket::SessionDescription* sdp, bool dtls) { - const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp); - ASSERT_TRUE(content != NULL); - const cricket::AudioContentDescription* audio_content = - static_cast( - content->description); - ASSERT_TRUE(audio_content != NULL); - ASSERT_EQ(0U, audio_content->cryptos().size()); - - content = cricket::GetFirstVideoContent(sdp); - ASSERT_TRUE(content != NULL); - const cricket::VideoContentDescription* video_content = - static_cast( - content->description); - ASSERT_TRUE(video_content != NULL); - ASSERT_EQ(0U, video_content->cryptos().size()); - - if (dtls) { - EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf), - audio_content->protocol()); - EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf), - video_content->protocol()); - } else { - EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), - audio_content->protocol()); - EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), - video_content->protocol()); - } - } - // Set the internal fake description factories to do DTLS-SRTP. void SetFactoryDtlsSrtp() { desc_factory_->set_secure(cricket::SEC_DISABLED); @@ -919,45 +784,6 @@ class WebRtcSessionTest tdesc_factory_->set_secure(cricket::SEC_REQUIRED); } - void VerifyFingerprintStatus(const cricket::SessionDescription* sdp, - bool expected) { - const TransportInfo* audio = sdp->GetTransportInfoByName("audio"); - ASSERT_TRUE(audio != NULL); - ASSERT_EQ(expected, audio->description.identity_fingerprint.get() != NULL); - const TransportInfo* video = sdp->GetTransportInfoByName("video"); - ASSERT_TRUE(video != NULL); - ASSERT_EQ(expected, video->description.identity_fingerprint.get() != NULL); - } - - void VerifyAnswerFromNonCryptoOffer() { - // Create an SDP without Crypto. - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - JsepSessionDescription* offer( - CreateRemoteOffer(options, cricket::SEC_DISABLED)); - ASSERT_TRUE(offer != NULL); - VerifyNoCryptoParams(offer->description(), false); - SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto, - offer); - const webrtc::SessionDescriptionInterface* answer = CreateAnswer(); - // Answer should be NULL as no crypto params in offer. - ASSERT_TRUE(answer == NULL); - } - - void VerifyAnswerFromCryptoOffer() { - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - options.bundle_enabled = true; - std::unique_ptr offer( - CreateRemoteOffer(options, cricket::SEC_REQUIRED)); - ASSERT_TRUE(offer.get() != NULL); - VerifyCryptoParams(offer->description()); - SetRemoteDescriptionWithoutError(offer.release()); - std::unique_ptr answer(CreateAnswer()); - ASSERT_TRUE(answer.get() != NULL); - VerifyCryptoParams(answer->description()); - } - bool IceUfragPwdEqual(const cricket::SessionDescription* desc1, const cricket::SessionDescription* desc2) { if (desc1->contents().size() != desc2->contents().size()) { @@ -1120,59 +946,12 @@ class WebRtcSessionTest SetRemoteDescriptionExpectError(SessionDescriptionInterface::kOffer, expected_error, desc); } - void SetRemoteDescriptionPranswerExpectError( - const std::string& expected_error, SessionDescriptionInterface* desc) { - SetRemoteDescriptionExpectError(SessionDescriptionInterface::kPrAnswer, - expected_error, desc); - } void SetRemoteDescriptionAnswerExpectError( const std::string& expected_error, SessionDescriptionInterface* desc) { SetRemoteDescriptionExpectError(SessionDescriptionInterface::kAnswer, expected_error, desc); } - void CreateCryptoOfferAndNonCryptoAnswer(SessionDescriptionInterface** offer, - SessionDescriptionInterface** nocrypto_answer) { - // Create a SDP without Crypto. - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - options.bundle_enabled = true; - *offer = CreateRemoteOffer(options, cricket::SEC_ENABLED); - ASSERT_TRUE(*offer != NULL); - VerifyCryptoParams((*offer)->description()); - - cricket::MediaSessionOptions answer_options; - GetOptionsForRemoteAnswer(&answer_options); - *nocrypto_answer = - CreateRemoteAnswer(*offer, answer_options, cricket::SEC_DISABLED); - EXPECT_TRUE(*nocrypto_answer != NULL); - } - - void CreateDtlsOfferAndNonDtlsAnswer(SessionDescriptionInterface** offer, - SessionDescriptionInterface** nodtls_answer) { - cricket::MediaSessionOptions options; - AddMediaSection(cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO, - cricket::MD_RECVONLY, kActive, &options); - AddMediaSection(cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO, - cricket::MD_RECVONLY, kActive, &options); - options.bundle_enabled = true; - - std::unique_ptr temp_offer( - CreateRemoteOffer(options, cricket::SEC_ENABLED)); - - *nodtls_answer = - CreateRemoteAnswer(temp_offer.get(), options, cricket::SEC_ENABLED); - EXPECT_TRUE(*nodtls_answer != NULL); - VerifyFingerprintStatus((*nodtls_answer)->description(), false); - VerifyCryptoParams((*nodtls_answer)->description()); - - SetFactoryDtlsSrtp(); - *offer = CreateRemoteOffer(options, cricket::SEC_ENABLED); - ASSERT_TRUE(*offer != NULL); - VerifyFingerprintStatus((*offer)->description(), true); - VerifyCryptoParams((*offer)->description()); - } - JsepSessionDescription* CreateRemoteOfferWithVersion( cricket::MediaSessionOptions options, cricket::SecurePolicy secure_policy, @@ -1585,74 +1364,6 @@ class WebRtcSessionTest SetLocalDescriptionWithoutError(offer); } - void VerifyMultipleAsyncCreateDescription( - RTCCertificateGenerationMethod cert_gen_method, - CreateSessionDescriptionRequest::Type type) { - InitWithDtls(cert_gen_method); - VerifyMultipleAsyncCreateDescriptionAfterInit(true, type); - } - - void VerifyMultipleAsyncCreateDescriptionIdentityGenFailure( - CreateSessionDescriptionRequest::Type type) { - InitWithDtlsIdentityGenFail(); - VerifyMultipleAsyncCreateDescriptionAfterInit(false, type); - } - - void VerifyMultipleAsyncCreateDescriptionAfterInit( - bool success, CreateSessionDescriptionRequest::Type type) { - RTC_CHECK(session_); - SetFactoryDtlsSrtp(); - if (type == CreateSessionDescriptionRequest::kAnswer) { - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - std::unique_ptr offer( - CreateRemoteOffer(options, cricket::SEC_DISABLED)); - ASSERT_TRUE(offer.get() != NULL); - SetRemoteDescriptionWithoutError(offer.release()); - } - - PeerConnectionInterface::RTCOfferAnswerOptions options; - cricket::MediaSessionOptions offer_session_options; - cricket::MediaSessionOptions answer_session_options; - GetOptionsForOffer(options, &offer_session_options); - GetOptionsForAnswer(&answer_session_options); - const int kNumber = 3; - rtc::scoped_refptr - observers[kNumber]; - for (int i = 0; i < kNumber; ++i) { - observers[i] = new WebRtcSessionCreateSDPObserverForTest(); - if (type == CreateSessionDescriptionRequest::kOffer) { - session_->CreateOffer(observers[i], options, offer_session_options); - } else { - session_->CreateAnswer(observers[i], answer_session_options); - } - } - - WebRtcSessionCreateSDPObserverForTest::State expected_state = - success ? WebRtcSessionCreateSDPObserverForTest::kSucceeded : - WebRtcSessionCreateSDPObserverForTest::kFailed; - - for (int i = 0; i < kNumber; ++i) { - EXPECT_EQ_WAIT(expected_state, observers[i]->state(), 1000); - if (success) { - EXPECT_TRUE(observers[i]->description() != NULL); - } else { - EXPECT_TRUE(observers[i]->description() == NULL); - } - } - } - - void ConfigureAllocatorWithTurn() { - cricket::RelayServerConfig turn_server(cricket::RELAY_TURN); - cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword); - turn_server.credentials = credentials; - turn_server.ports.push_back( - cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP)); - allocator_->AddTurnServer(turn_server); - allocator_->set_step_delay(cricket::kMinimumStepDelay); - allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP); - } - webrtc::RtcEventLogNullImpl event_log_; std::unique_ptr vss_; std::unique_ptr fss_; @@ -1669,7 +1380,6 @@ class WebRtcSessionTest std::unique_ptr desc_factory_; rtc::SocketAddress stun_socket_addr_; std::unique_ptr stun_server_; - cricket::TestTurnServer turn_server_; rtc::FakeNetworkManager network_manager_; std::unique_ptr allocator_; PeerConnectionFactoryInterface::Options options_; @@ -1698,18 +1408,6 @@ class WebRtcSessionTest rtc::CryptoOptions crypto_options_; }; -TEST_P(WebRtcSessionTest, TestInitializeWithDtls) { - InitWithDtls(GetParam()); - // SDES is disabled when DTLS is on. - EXPECT_EQ(cricket::SEC_DISABLED, session_->SdesPolicy()); -} - -TEST_F(WebRtcSessionTest, TestInitializeWithoutDtls) { - Init(); - // SDES is required if DTLS is off. - EXPECT_EQ(cricket::SEC_REQUIRED, session_->SdesPolicy()); -} - TEST_F(WebRtcSessionTest, TestSessionCandidates) { TestSessionCandidatesWithBundleRtcpMux(false, false); } @@ -1827,12 +1525,10 @@ TEST_F(WebRtcSessionTest, TestReceiveSdesOfferCreateSdesAnswer) { Init(); SendAudioVideoStream2(); SessionDescriptionInterface* offer = CreateOffer(); - VerifyCryptoParams(offer->description()); SetRemoteDescriptionWithoutError(offer); SendAudioVideoStream1(); SessionDescriptionInterface* answer = CreateAnswer(); - VerifyCryptoParams(answer->description()); SetLocalDescriptionWithoutError(answer); const std::string session_id_orig = answer->session_id(); @@ -1895,255 +1591,6 @@ TEST_F(WebRtcSessionTest, SetLocalSdpFailedOnCreateChannel) { SetLocalDescriptionOfferExpectError(kCreateChannelFailed, offer); } -// -// Tests for creating/setting SDP under different SDES/DTLS polices: -// -// --DTLS off and SDES on -// TestCreateSdesOfferReceiveSdesAnswer/TestReceiveSdesOfferCreateSdesAnswer: -// set local/remote offer/answer with crypto --> success -// TestSetNonSdesOfferWhenSdesOn: set local/remote offer without crypto ---> -// failure -// TestSetLocalNonSdesAnswerWhenSdesOn: set local answer without crypto --> -// failure -// TestSetRemoteNonSdesAnswerWhenSdesOn: set remote answer without crypto --> -// failure -// -// --DTLS on and SDES off -// TestCreateDtlsOfferReceiveDtlsAnswer/TestReceiveDtlsOfferCreateDtlsAnswer: -// set local/remote offer/answer with DTLS fingerprint --> success -// TestReceiveNonDtlsOfferWhenDtlsOn: set local/remote offer without DTLS -// fingerprint --> failure -// TestSetLocalNonDtlsAnswerWhenDtlsOn: set local answer without fingerprint -// --> failure -// TestSetRemoteNonDtlsAnswerWhenDtlsOn: set remote answer without fingerprint -// --> failure -// -// --Encryption disabled: DTLS off and SDES off -// TestCreateOfferReceiveAnswerWithoutEncryption: set local offer and remote -// answer without SDES or DTLS --> success -// TestCreateAnswerReceiveOfferWithoutEncryption: set remote offer and local -// answer without SDES or DTLS --> success -// - -// Test that we return a failure when applying a remote/local offer that doesn't -// have cryptos enabled when DTLS is off. -TEST_F(WebRtcSessionTest, TestSetNonSdesOfferWhenSdesOn) { - Init(); - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - JsepSessionDescription* offer = CreateRemoteOffer( - options, cricket::SEC_DISABLED); - ASSERT_TRUE(offer != NULL); - VerifyNoCryptoParams(offer->description(), false); - // SetRemoteDescription and SetLocalDescription will take the ownership of - // the offer. - SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto, offer); - offer = CreateRemoteOffer(options, cricket::SEC_DISABLED); - ASSERT_TRUE(offer != NULL); - SetLocalDescriptionOfferExpectError(kSdpWithoutSdesCrypto, offer); -} - -// Test that we return a failure when applying a local answer that doesn't have -// cryptos enabled when DTLS is off. -TEST_F(WebRtcSessionTest, TestSetLocalNonSdesAnswerWhenSdesOn) { - Init(); - SessionDescriptionInterface* offer = NULL; - SessionDescriptionInterface* answer = NULL; - CreateCryptoOfferAndNonCryptoAnswer(&offer, &answer); - // SetRemoteDescription and SetLocalDescription will take the ownership of - // the offer. - SetRemoteDescriptionWithoutError(offer); - SetLocalDescriptionAnswerExpectError(kSdpWithoutSdesCrypto, answer); -} - -// Test we will return fail when apply an remote answer that doesn't have -// crypto enabled when DTLS is off. -TEST_F(WebRtcSessionTest, TestSetRemoteNonSdesAnswerWhenSdesOn) { - Init(); - SessionDescriptionInterface* offer = NULL; - SessionDescriptionInterface* answer = NULL; - CreateCryptoOfferAndNonCryptoAnswer(&offer, &answer); - // SetRemoteDescription and SetLocalDescription will take the ownership of - // the offer. - SetLocalDescriptionWithoutError(offer); - SetRemoteDescriptionAnswerExpectError(kSdpWithoutSdesCrypto, answer); -} - -// Test that we accept an offer with a DTLS fingerprint when DTLS is on -// and that we return an answer with a DTLS fingerprint. -TEST_P(WebRtcSessionTest, TestReceiveDtlsOfferCreateDtlsAnswer) { - SendAudioVideoStream1(); - InitWithDtls(GetParam()); - SetFactoryDtlsSrtp(); - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - JsepSessionDescription* offer = - CreateRemoteOffer(options, cricket::SEC_DISABLED); - ASSERT_TRUE(offer != NULL); - VerifyFingerprintStatus(offer->description(), true); - VerifyNoCryptoParams(offer->description(), true); - - // SetRemoteDescription will take the ownership of the offer. - SetRemoteDescriptionWithoutError(offer); - - // Verify that we get a crypto fingerprint in the answer. - SessionDescriptionInterface* answer = CreateAnswer(); - ASSERT_TRUE(answer != NULL); - VerifyFingerprintStatus(answer->description(), true); - // Check that we don't have an a=crypto line in the answer. - VerifyNoCryptoParams(answer->description(), true); - - // Now set the local description, which should work, even without a=crypto. - SetLocalDescriptionWithoutError(answer); -} - -// Test that we set a local offer with a DTLS fingerprint when DTLS is on -// and then we accept a remote answer with a DTLS fingerprint successfully. -TEST_P(WebRtcSessionTest, TestCreateDtlsOfferReceiveDtlsAnswer) { - SendAudioVideoStream1(); - InitWithDtls(GetParam()); - SetFactoryDtlsSrtp(); - - // Verify that we get a crypto fingerprint in the answer. - SessionDescriptionInterface* offer = CreateOffer(); - ASSERT_TRUE(offer != NULL); - VerifyFingerprintStatus(offer->description(), true); - // Check that we don't have an a=crypto line in the offer. - VerifyNoCryptoParams(offer->description(), true); - - // Now set the local description, which should work, even without a=crypto. - SetLocalDescriptionWithoutError(offer); - - cricket::MediaSessionOptions options; - GetOptionsForAnswer(&options); - JsepSessionDescription* answer = - CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED); - ASSERT_TRUE(answer != NULL); - VerifyFingerprintStatus(answer->description(), true); - VerifyNoCryptoParams(answer->description(), true); - - // SetRemoteDescription will take the ownership of the answer. - SetRemoteDescriptionWithoutError(answer); -} - -// Test that if we support DTLS and the other side didn't offer a fingerprint, -// we will fail to set the remote description. -TEST_P(WebRtcSessionTest, TestReceiveNonDtlsOfferWhenDtlsOn) { - InitWithDtls(GetParam()); - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - options.bundle_enabled = true; - JsepSessionDescription* offer = CreateRemoteOffer( - options, cricket::SEC_REQUIRED); - ASSERT_TRUE(offer != NULL); - VerifyFingerprintStatus(offer->description(), false); - VerifyCryptoParams(offer->description()); - - // SetRemoteDescription will take the ownership of the offer. - SetRemoteDescriptionOfferExpectError( - kSdpWithoutDtlsFingerprint, offer); - - offer = CreateRemoteOffer(options, cricket::SEC_REQUIRED); - // SetLocalDescription will take the ownership of the offer. - SetLocalDescriptionOfferExpectError( - kSdpWithoutDtlsFingerprint, offer); -} - -// Test that we return a failure when applying a local answer that doesn't have -// a DTLS fingerprint when DTLS is required. -TEST_P(WebRtcSessionTest, TestSetLocalNonDtlsAnswerWhenDtlsOn) { - InitWithDtls(GetParam()); - SessionDescriptionInterface* offer = NULL; - SessionDescriptionInterface* answer = NULL; - CreateDtlsOfferAndNonDtlsAnswer(&offer, &answer); - - // SetRemoteDescription and SetLocalDescription will take the ownership of - // the offer and answer. - SetRemoteDescriptionWithoutError(offer); - SetLocalDescriptionAnswerExpectError( - kSdpWithoutDtlsFingerprint, answer); -} - -// Test that we return a failure when applying a remote answer that doesn't have -// a DTLS fingerprint when DTLS is required. -TEST_P(WebRtcSessionTest, TestSetRemoteNonDtlsAnswerWhenDtlsOn) { - InitWithDtls(GetParam()); - SessionDescriptionInterface* offer = CreateOffer(); - cricket::MediaSessionOptions offer_options; - GetOptionsForRemoteOffer(&offer_options); - - std::unique_ptr temp_offer( - CreateRemoteOffer(offer_options, cricket::SEC_ENABLED)); - - cricket::MediaSessionOptions answer_options; - GetOptionsForAnswer(&answer_options); - JsepSessionDescription* answer = CreateRemoteAnswer( - temp_offer.get(), answer_options, cricket::SEC_ENABLED); - - // SetRemoteDescription and SetLocalDescription will take the ownership of - // the offer and answer. - SetLocalDescriptionWithoutError(offer); - SetRemoteDescriptionAnswerExpectError( - kSdpWithoutDtlsFingerprint, answer); -} - -// Test that we create a local offer without SDES or DTLS and accept a remote -// answer without SDES or DTLS when encryption is disabled. -TEST_P(WebRtcSessionTest, TestCreateOfferReceiveAnswerWithoutEncryption) { - SendAudioVideoStream1(); - options_.disable_encryption = true; - InitWithDtls(GetParam()); - - // Verify that we get a crypto fingerprint in the answer. - SessionDescriptionInterface* offer = CreateOffer(); - ASSERT_TRUE(offer != NULL); - VerifyFingerprintStatus(offer->description(), false); - // Check that we don't have an a=crypto line in the offer. - VerifyNoCryptoParams(offer->description(), false); - - // Now set the local description, which should work, even without a=crypto. - SetLocalDescriptionWithoutError(offer); - - cricket::MediaSessionOptions options; - GetOptionsForAnswer(&options); - JsepSessionDescription* answer = - CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED); - ASSERT_TRUE(answer != NULL); - VerifyFingerprintStatus(answer->description(), false); - VerifyNoCryptoParams(answer->description(), false); - - // SetRemoteDescription will take the ownership of the answer. - SetRemoteDescriptionWithoutError(answer); -} - -// Test that we create a local answer without SDES or DTLS and accept a remote -// offer without SDES or DTLS when encryption is disabled. -TEST_P(WebRtcSessionTest, TestCreateAnswerReceiveOfferWithoutEncryption) { - options_.disable_encryption = true; - InitWithDtls(GetParam()); - - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - JsepSessionDescription* offer = - CreateRemoteOffer(options, cricket::SEC_DISABLED); - ASSERT_TRUE(offer != NULL); - VerifyFingerprintStatus(offer->description(), false); - VerifyNoCryptoParams(offer->description(), false); - - // SetRemoteDescription will take the ownership of the offer. - SetRemoteDescriptionWithoutError(offer); - - // Verify that we get a crypto fingerprint in the answer. - SessionDescriptionInterface* answer = CreateAnswer(); - ASSERT_TRUE(answer != NULL); - VerifyFingerprintStatus(answer->description(), false); - // Check that we don't have an a=crypto line in the answer. - VerifyNoCryptoParams(answer->description(), false); - - // Now set the local description, which should work, even without a=crypto. - SetLocalDescriptionWithoutError(answer); -} - // Test that we can create and set an answer correctly when different // SSL roles have been negotiated for different transports. // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4525 @@ -3041,44 +2488,6 @@ TEST_F(WebRtcSessionTest, TestAVOfferWithVideoOnlyAnswer) { EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id); } -TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDP) { - Init(); - SendAudioVideoStream1(); - std::unique_ptr offer(CreateOffer()); - VerifyCryptoParams(offer->description()); - SetRemoteDescriptionWithoutError(offer.release()); - std::unique_ptr answer(CreateAnswer()); - VerifyCryptoParams(answer->description()); -} - -TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDPGcm) { - InitWithGcm(); - SendAudioVideoStream1(); - std::unique_ptr offer(CreateOffer()); - VerifyCryptoParams(offer->description(), true); - SetRemoteDescriptionWithoutError(offer.release()); - std::unique_ptr answer(CreateAnswer()); - VerifyCryptoParams(answer->description(), true); -} - -TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) { - options_.disable_encryption = true; - Init(); - SendAudioVideoStream1(); - std::unique_ptr offer(CreateOffer()); - VerifyNoCryptoParams(offer->description(), false); -} - -TEST_F(WebRtcSessionTest, VerifyAnswerFromNonCryptoOffer) { - Init(); - VerifyAnswerFromNonCryptoOffer(); -} - -TEST_F(WebRtcSessionTest, VerifyAnswerFromCryptoOffer) { - Init(); - VerifyAnswerFromCryptoOffer(); -} - // This test verifies that setLocalDescription fails if // no a=ice-ufrag and a=ice-pwd lines are present in the SDP. TEST_F(WebRtcSessionTest, TestSetLocalDescriptionWithoutIce) { @@ -3692,12 +3101,6 @@ TEST_F(WebRtcSessionTest, TestDisabledRtcpMuxWithBundleEnabled) { SetLocalDescriptionWithoutError(offer); } -TEST_F(WebRtcSessionTest, SetSetupGcm) { - InitWithGcm(); - SendAudioVideoStream1(); - CreateAndSetRemoteOfferAndLocalAnswer(); -} - // This test verifies the |initial_offerer| flag when session initiates the // call. TEST_F(WebRtcSessionTest, TestInitiatorFlagAsOriginator) { @@ -3825,44 +3228,6 @@ TEST_F(WebRtcSessionTest, TestIceStartAfterSetLocalDescriptionOnly) { EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); } -// This test verifies that crypto parameter is updated in local session -// description as per security policy set in MediaSessionDescriptionFactory. -TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescription) { - Init(); - SendAudioVideoStream1(); - std::unique_ptr offer(CreateOffer()); - - // Making sure SetLocalDescription correctly sets crypto value in - // SessionDescription object after de-serialization of sdp string. The value - // will be set as per MediaSessionDescriptionFactory. - std::string offer_str; - offer->ToString(&offer_str); - SessionDescriptionInterface* jsep_offer_str = - CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL); - SetLocalDescriptionWithoutError(jsep_offer_str); - EXPECT_TRUE(session_->voice_channel()->srtp_required_for_testing()); - EXPECT_TRUE(session_->video_channel()->srtp_required_for_testing()); -} - -// This test verifies the crypto parameter when security is disabled. -TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescriptionWithDisabled) { - options_.disable_encryption = true; - Init(); - SendAudioVideoStream1(); - std::unique_ptr offer(CreateOffer()); - - // Making sure SetLocalDescription correctly sets crypto value in - // SessionDescription object after de-serialization of sdp string. The value - // will be set as per MediaSessionDescriptionFactory. - std::string offer_str; - offer->ToString(&offer_str); - SessionDescriptionInterface* jsep_offer_str = - CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL); - SetLocalDescriptionWithoutError(jsep_offer_str); - EXPECT_FALSE(session_->voice_channel()->srtp_required_for_testing()); - EXPECT_FALSE(session_->video_channel()->srtp_required_for_testing()); -} - // This test verifies that an answer contains new ufrag and password if an offer // with new ufrag and password is received. TEST_F(WebRtcSessionTest, TestCreateAnswerWithNewUfragAndPassword) { @@ -4243,129 +3608,6 @@ TEST_P(WebRtcSessionTest, TestSctpDataChannelOpenMessage) { last_data_channel_config_.open_handshake_role); } -TEST_P(WebRtcSessionTest, TestUsesProvidedCertificate) { - rtc::scoped_refptr certificate = - FakeRTCCertificateGenerator::GenerateCertificate(); - - configuration_.certificates.push_back(certificate); - Init(); - EXPECT_TRUE_WAIT(!session_->waiting_for_certificate_for_testing(), 1000); - - EXPECT_EQ(session_->certificate_for_testing(), certificate); -} - -// Verifies that CreateOffer succeeds when CreateOffer is called before async -// identity generation is finished (even if a certificate is provided this is -// an async op). -TEST_P(WebRtcSessionTest, TestCreateOfferBeforeIdentityRequestReturnSuccess) { - InitWithDtls(GetParam()); - - EXPECT_TRUE(session_->waiting_for_certificate_for_testing()); - SendAudioVideoStream1(); - std::unique_ptr offer(CreateOffer()); - - EXPECT_TRUE(offer != NULL); - VerifyNoCryptoParams(offer->description(), true); - VerifyFingerprintStatus(offer->description(), true); -} - -// Verifies that CreateAnswer succeeds when CreateOffer is called before async -// identity generation is finished (even if a certificate is provided this is -// an async op). -TEST_P(WebRtcSessionTest, TestCreateAnswerBeforeIdentityRequestReturnSuccess) { - InitWithDtls(GetParam()); - SetFactoryDtlsSrtp(); - - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - std::unique_ptr offer( - CreateRemoteOffer(options, cricket::SEC_DISABLED)); - ASSERT_TRUE(offer.get() != NULL); - SetRemoteDescriptionWithoutError(offer.release()); - - std::unique_ptr answer(CreateAnswer()); - EXPECT_TRUE(answer != NULL); - VerifyNoCryptoParams(answer->description(), true); - VerifyFingerprintStatus(answer->description(), true); -} - -// Verifies that CreateOffer succeeds when CreateOffer is called after async -// identity generation is finished (even if a certificate is provided this is -// an async op). -TEST_P(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnSuccess) { - InitWithDtls(GetParam()); - - EXPECT_TRUE_WAIT(!session_->waiting_for_certificate_for_testing(), 1000); - - std::unique_ptr offer(CreateOffer()); - EXPECT_TRUE(offer != NULL); -} - -// Verifies that CreateOffer fails when CreateOffer is called after async -// identity generation fails. -TEST_F(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnFailure) { - InitWithDtlsIdentityGenFail(); - - EXPECT_TRUE_WAIT(!session_->waiting_for_certificate_for_testing(), 1000); - - std::unique_ptr offer(CreateOffer()); - EXPECT_TRUE(offer == NULL); -} - -// Verifies that CreateOffer succeeds when Multiple CreateOffer calls are made -// before async identity generation is finished. -TEST_P(WebRtcSessionTest, - TestMultipleCreateOfferBeforeIdentityRequestReturnSuccess) { - VerifyMultipleAsyncCreateDescription(GetParam(), - CreateSessionDescriptionRequest::kOffer); -} - -// Verifies that CreateOffer fails when Multiple CreateOffer calls are made -// before async identity generation fails. -TEST_F(WebRtcSessionTest, - TestMultipleCreateOfferBeforeIdentityRequestReturnFailure) { - VerifyMultipleAsyncCreateDescriptionIdentityGenFailure( - CreateSessionDescriptionRequest::kOffer); -} - -// Verifies that CreateAnswer succeeds when Multiple CreateAnswer calls are made -// before async identity generation is finished. -TEST_P(WebRtcSessionTest, - TestMultipleCreateAnswerBeforeIdentityRequestReturnSuccess) { - VerifyMultipleAsyncCreateDescription( - GetParam(), CreateSessionDescriptionRequest::kAnswer); -} - -// Verifies that CreateAnswer fails when Multiple CreateAnswer calls are made -// before async identity generation fails. -TEST_F(WebRtcSessionTest, - TestMultipleCreateAnswerBeforeIdentityRequestReturnFailure) { - VerifyMultipleAsyncCreateDescriptionIdentityGenFailure( - CreateSessionDescriptionRequest::kAnswer); -} - -// Verifies that setRemoteDescription fails when DTLS is disabled and the remote -// offer has no SDES crypto but only DTLS fingerprint. -TEST_F(WebRtcSessionTest, TestSetRemoteOfferFailIfDtlsDisabledAndNoCrypto) { - // Init without DTLS. - Init(); - // Create a remote offer with secured transport disabled. - cricket::MediaSessionOptions options; - GetOptionsForRemoteOffer(&options); - JsepSessionDescription* offer(CreateRemoteOffer( - options, cricket::SEC_DISABLED)); - // Adds a DTLS fingerprint to the remote offer. - cricket::SessionDescription* sdp = offer->description(); - TransportInfo* audio = sdp->GetTransportInfoByName("audio"); - ASSERT_TRUE(audio != NULL); - ASSERT_TRUE(audio->description.identity_fingerprint.get() == NULL); - audio->description.identity_fingerprint.reset( - rtc::SSLFingerprint::CreateFromRfc4572( - rtc::DIGEST_SHA_256, kFakeDtlsFingerprint)); - SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto, - offer); -} - TEST_F(WebRtcSessionTest, TestCombinedAudioVideoBweConstraint) { configuration_.combined_audio_video_bwe = rtc::Optional(true); Init(); diff --git a/tools_webrtc/valgrind/gtest_exclude/peerconnection_unittests.gtest-memcheck.txt b/tools_webrtc/valgrind/gtest_exclude/peerconnection_unittests.gtest-memcheck.txt index f1aec4dca6..497f1f0b8f 100644 --- a/tools_webrtc/valgrind/gtest_exclude/peerconnection_unittests.gtest-memcheck.txt +++ b/tools_webrtc/valgrind/gtest_exclude/peerconnection_unittests.gtest-memcheck.txt @@ -4,4 +4,5 @@ DtmfSenderTest.* PeerConnectionIntegrationTest.* PeerConnectionEndToEndTest.* PeerConnectionInterfaceTest.* +PeerConnectionCryptoUnitTest.* RTCStatsIntegrationTest.*