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 <steveanton@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20193}
This commit is contained in:
Steve Anton 2017-10-06 11:20:31 -07:00 committed by Commit Bot
parent 97a9f76bce
commit 6b63cd5e54
8 changed files with 624 additions and 768 deletions

View File

@ -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",

View File

@ -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.

View File

@ -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<PeerConnectionWrapper> 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<rtc::RTCCertificateGeneratorInterface> cert_gen) {
auto fake_port_allocator = rtc::MakeUnique<cricket::FakePortAllocator>(
rtc::Thread::Current(), nullptr);
auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
auto pc = pc_factory_->CreatePeerConnection(
config, std::move(fake_port_allocator), std::move(cert_gen),
observer.get());
if (!pc) {
return nullptr;
}
return rtc::MakeUnique<PeerConnectionWrapper>(pc_factory_, pc,
std::move(observer));
}
// Accepts the same arguments as CreatePeerConnection and adds default audio
// and video tracks.
template <typename... Args>
WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
if (!wrapper) {
return nullptr;
}
wrapper->AddAudioVideoStream("s", "a", "v");
return wrapper;
}
std::unique_ptr<rtc::VirtualSocketServer> vss_;
rtc::AutoSocketServerThread main_;
rtc::scoped_refptr<PeerConnectionFactoryInterface> 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<const cricket::MediaContentDescription*>(
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<const cricket::MediaContentDescription*>(
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<const cricket::MediaContentDescription*>(
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<cricket::MediaContentDescription*>(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<SdpType, CertGenTime, CertGenResult, size_t>> {
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<FakeRTCCertificateGenerator>();
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<rtc::scoped_refptr<MockCreateSessionDescriptionObserver>>
observers;
for (size_t i = 0; i < concurrent_calls_; i++) {
rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer =
new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>();
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

View File

@ -125,16 +125,21 @@ class FakeRTCCertificateGenerator
typedef rtc::TypedMessageData<rtc::scoped_refptr<
rtc::RTCCertificateGeneratorCallback> > 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<MessageData*>(msg->pdata);
rtc::scoped_refptr<rtc::RTCCertificateGeneratorCallback> 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_

View File

@ -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 "

View File

@ -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).

View File

@ -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<RTCCertificateGenerationMethod>,
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<FakeMetricsObserver>()) {
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<FakeRTCCertificateGenerator> 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<const cricket::AudioContentDescription*>(
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<const cricket::VideoContentDescription*>(
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<const cricket::AudioContentDescription*>(
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<const cricket::VideoContentDescription*>(
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<JsepSessionDescription> offer(
CreateRemoteOffer(options, cricket::SEC_REQUIRED));
ASSERT_TRUE(offer.get() != NULL);
VerifyCryptoParams(offer->description());
SetRemoteDescriptionWithoutError(offer.release());
std::unique_ptr<SessionDescriptionInterface> 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<SessionDescriptionInterface> 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<JsepSessionDescription> 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<WebRtcSessionCreateSDPObserverForTest>
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<rtc::VirtualSocketServer> vss_;
std::unique_ptr<rtc::FirewallSocketServer> fss_;
@ -1669,7 +1380,6 @@ class WebRtcSessionTest
std::unique_ptr<cricket::MediaSessionDescriptionFactory> desc_factory_;
rtc::SocketAddress stun_socket_addr_;
std::unique_ptr<cricket::TestStunServer> stun_server_;
cricket::TestTurnServer turn_server_;
rtc::FakeNetworkManager network_manager_;
std::unique_ptr<cricket::BasicPortAllocator> 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<SessionDescriptionInterface> 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<SessionDescriptionInterface> offer(CreateOffer());
VerifyCryptoParams(offer->description());
SetRemoteDescriptionWithoutError(offer.release());
std::unique_ptr<SessionDescriptionInterface> answer(CreateAnswer());
VerifyCryptoParams(answer->description());
}
TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDPGcm) {
InitWithGcm();
SendAudioVideoStream1();
std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer());
VerifyCryptoParams(offer->description(), true);
SetRemoteDescriptionWithoutError(offer.release());
std::unique_ptr<SessionDescriptionInterface> answer(CreateAnswer());
VerifyCryptoParams(answer->description(), true);
}
TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) {
options_.disable_encryption = true;
Init();
SendAudioVideoStream1();
std::unique_ptr<SessionDescriptionInterface> 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<SessionDescriptionInterface> 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<SessionDescriptionInterface> 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<rtc::RTCCertificate> 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<SessionDescriptionInterface> 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<JsepSessionDescription> offer(
CreateRemoteOffer(options, cricket::SEC_DISABLED));
ASSERT_TRUE(offer.get() != NULL);
SetRemoteDescriptionWithoutError(offer.release());
std::unique_ptr<SessionDescriptionInterface> 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<SessionDescriptionInterface> 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<SessionDescriptionInterface> 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<bool>(true);
Init();

View File

@ -4,4 +4,5 @@ DtmfSenderTest.*
PeerConnectionIntegrationTest.*
PeerConnectionEndToEndTest.*
PeerConnectionInterfaceTest.*
PeerConnectionCryptoUnitTest.*
RTCStatsIntegrationTest.*