blob: fae74681fc4eecd8981dcfc09d17d317f1e91107 [file] [log] [blame]
Steve Anton6b63cd52017-10-06 11:20:31 -07001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Harald Alvestrandc24a2182022-02-23 13:44:59 +000011#include <stddef.h>
Mirko Bonadei317a1f02019-09-17 17:06:18 +020012
Harald Alvestrandc24a2182022-02-23 13:44:59 +000013#include <memory>
14#include <ostream>
15#include <string>
16#include <tuple>
17#include <type_traits>
18#include <utility>
19#include <vector>
20
21#include "absl/types/optional.h"
22#include "api/audio/audio_mixer.h"
Karl Wiberg1b0eae32017-10-17 14:48:54 +020023#include "api/audio_codecs/builtin_audio_decoder_factory.h"
24#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Mirko Bonadei2ff3f492018-11-22 09:00:13 +010025#include "api/create_peerconnection_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000026#include "api/crypto/crypto_options.h"
27#include "api/crypto_params.h"
28#include "api/jsep.h"
29#include "api/peer_connection_interface.h"
30#include "api/scoped_refptr.h"
Anders Carlsson67537952018-05-03 11:28:29 +020031#include "api/video_codecs/builtin_video_decoder_factory.h"
32#include "api/video_codecs/builtin_video_encoder_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000033#include "modules/audio_device/include/audio_device.h"
34#include "modules/audio_processing/include/audio_processing.h"
Steve Anton10542f22019-01-11 09:11:00 -080035#include "p2p/base/fake_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000036#include "p2p/base/port_allocator.h"
37#include "p2p/base/transport_description.h"
38#include "p2p/base/transport_info.h"
39#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080040#include "pc/media_session.h"
41#include "pc/peer_connection_wrapper.h"
42#include "pc/sdp_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000043#include "pc/session_description.h"
44#include "pc/test/mock_peer_connection_observers.h"
45#include "rtc_base/checks.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000046#include "rtc_base/rtc_certificate.h"
47#include "rtc_base/rtc_certificate_generator.h"
48#include "rtc_base/ssl_fingerprint.h"
49#include "rtc_base/thread.h"
50#include "test/gtest.h"
Sameer Vijaykar0793ee72023-01-23 16:31:29 +010051#include "test/scoped_key_value_config.h"
Steve Anton6b63cd52017-10-06 11:20:31 -070052#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080053#include "pc/test/android_test_initializer.h"
Steve Anton6b63cd52017-10-06 11:20:31 -070054#endif
Steve Anton10542f22019-01-11 09:11:00 -080055#include "pc/test/fake_audio_capture_module.h"
56#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton6b63cd52017-10-06 11:20:31 -070057#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080058#include "rtc_base/virtual_socket_server.h"
Steve Anton6b63cd52017-10-06 11:20:31 -070059
60namespace webrtc {
61
62using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
Steve Anton8a63f782017-10-23 13:08:53 -070063using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
Steve Anton6b63cd52017-10-06 11:20:31 -070064using ::testing::Combine;
Jonas Olssona4d87372019-07-05 19:08:33 +020065using ::testing::Values;
Steve Anton6b63cd52017-10-06 11:20:31 -070066
67constexpr int kGenerateCertTimeout = 1000;
68
Steve Anton71182f42018-01-19 14:59:54 -080069class PeerConnectionCryptoBaseTest : public ::testing::Test {
Steve Anton6b63cd52017-10-06 11:20:31 -070070 protected:
71 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
72
Steve Anton71182f42018-01-19 14:59:54 -080073 explicit PeerConnectionCryptoBaseTest(SdpSemantics sdp_semantics)
74 : vss_(new rtc::VirtualSocketServer()),
75 main_(vss_.get()),
76 sdp_semantics_(sdp_semantics) {
Steve Anton6b63cd52017-10-06 11:20:31 -070077#ifdef WEBRTC_ANDROID
78 InitializeAndroidObjects();
79#endif
80 pc_factory_ = CreatePeerConnectionFactory(
81 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Karl Wiberg1b0eae32017-10-17 14:48:54 +020082 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +020083 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
84 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
85 nullptr /* audio_processing */);
Steve Anton6b63cd52017-10-06 11:20:31 -070086 }
87
Steve Anton8a63f782017-10-23 13:08:53 -070088 WrapperPtr CreatePeerConnection() {
89 return CreatePeerConnection(RTCConfiguration());
90 }
91
Steve Anton6b63cd52017-10-06 11:20:31 -070092 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
93 return CreatePeerConnection(config, nullptr);
94 }
95
96 WrapperPtr CreatePeerConnection(
97 const RTCConfiguration& config,
98 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_gen) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020099 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Byoungchan Leed58f5262022-06-27 18:05:22 +0900100 rtc::Thread::Current(),
Sameer Vijaykar0793ee72023-01-23 16:31:29 +0100101 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()),
102 &field_trials_);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200103 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Anton71182f42018-01-19 14:59:54 -0800104 RTCConfiguration modified_config = config;
105 modified_config.sdp_semantics = sdp_semantics_;
Florent Castelli72424402022-04-06 03:45:10 +0200106 PeerConnectionDependencies pc_dependencies(observer.get());
107 pc_dependencies.allocator = std::move(fake_port_allocator);
108 pc_dependencies.cert_generator = std::move(cert_gen);
109 auto result = pc_factory_->CreatePeerConnectionOrError(
110 modified_config, std::move(pc_dependencies));
111 if (!result.ok()) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700112 return nullptr;
113 }
114
Niels Möllerafb246b2022-04-20 14:26:50 +0200115 observer->SetPeerConnectionInterface(result.value().get());
Florent Castelli72424402022-04-06 03:45:10 +0200116 return std::make_unique<PeerConnectionWrapper>(
117 pc_factory_, result.MoveValue(), std::move(observer));
Steve Anton6b63cd52017-10-06 11:20:31 -0700118 }
119
120 // Accepts the same arguments as CreatePeerConnection and adds default audio
121 // and video tracks.
122 template <typename... Args>
123 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
124 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
125 if (!wrapper) {
126 return nullptr;
127 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700128 wrapper->AddAudioTrack("a");
129 wrapper->AddVideoTrack("v");
Steve Anton6b63cd52017-10-06 11:20:31 -0700130 return wrapper;
131 }
132
Steve Anton8a63f782017-10-23 13:08:53 -0700133 cricket::ConnectionRole& AudioConnectionRole(
134 cricket::SessionDescription* desc) {
135 return ConnectionRoleFromContent(desc, cricket::GetFirstAudioContent(desc));
136 }
137
138 cricket::ConnectionRole& VideoConnectionRole(
139 cricket::SessionDescription* desc) {
140 return ConnectionRoleFromContent(desc, cricket::GetFirstVideoContent(desc));
141 }
142
143 cricket::ConnectionRole& ConnectionRoleFromContent(
144 cricket::SessionDescription* desc,
145 cricket::ContentInfo* content) {
146 RTC_DCHECK(content);
147 auto* transport_info = desc->GetTransportInfoByName(content->name);
148 RTC_DCHECK(transport_info);
149 return transport_info->description.connection_role;
150 }
151
Sameer Vijaykar0793ee72023-01-23 16:31:29 +0100152 webrtc::test::ScopedKeyValueConfig field_trials_;
Steve Anton6b63cd52017-10-06 11:20:31 -0700153 std::unique_ptr<rtc::VirtualSocketServer> vss_;
154 rtc::AutoSocketServerThread main_;
155 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
Steve Anton71182f42018-01-19 14:59:54 -0800156 const SdpSemantics sdp_semantics_;
Steve Anton6b63cd52017-10-06 11:20:31 -0700157};
158
159SdpContentPredicate HaveDtlsFingerprint() {
160 return [](const cricket::ContentInfo* content,
161 const cricket::TransportInfo* transport) {
162 return transport->description.identity_fingerprint != nullptr;
163 };
164}
165
Harald Alvestrand0d018412021-11-04 13:52:31 +0000166SdpContentPredicate HaveSdesCryptos() {
167 return [](const cricket::ContentInfo* content,
168 const cricket::TransportInfo* transport) {
169 return !content->media_description()->cryptos().empty();
170 };
171}
172
Steve Anton6b63cd52017-10-06 11:20:31 -0700173SdpContentPredicate HaveProtocol(const std::string& protocol) {
174 return [protocol](const cricket::ContentInfo* content,
175 const cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800176 return content->media_description()->protocol() == protocol;
Steve Anton6b63cd52017-10-06 11:20:31 -0700177 };
178}
179
Harald Alvestrand0d018412021-11-04 13:52:31 +0000180SdpContentPredicate HaveSdesGcmCryptos(size_t num_crypto_suites) {
181 return [num_crypto_suites](const cricket::ContentInfo* content,
182 const cricket::TransportInfo* transport) {
183 const auto& cryptos = content->media_description()->cryptos();
184 if (cryptos.size() != num_crypto_suites) {
185 return false;
186 }
187 for (size_t i = 0; i < cryptos.size(); ++i) {
188 if (cryptos[i].key_params.size() == 67U &&
189 cryptos[i].cipher_suite == "AEAD_AES_256_GCM")
190 return true;
191 }
192 return false;
193 };
194}
195
Steve Anton71182f42018-01-19 14:59:54 -0800196class PeerConnectionCryptoTest
197 : public PeerConnectionCryptoBaseTest,
198 public ::testing::WithParamInterface<SdpSemantics> {
199 protected:
200 PeerConnectionCryptoTest() : PeerConnectionCryptoBaseTest(GetParam()) {}
201};
202
Harald Alvestrand0d018412021-11-04 13:52:31 +0000203SdpContentMutator RemoveSdesCryptos() {
204 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
205 content->media_description()->set_cryptos({});
206 };
207}
208
Steve Anton6b63cd52017-10-06 11:20:31 -0700209SdpContentMutator RemoveDtlsFingerprint() {
210 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
211 transport->description.identity_fingerprint.reset();
212 };
213}
214
Harald Alvestrand0d018412021-11-04 13:52:31 +0000215// When DTLS is enabled, the SDP offer/answer should have a DTLS fingerprint and
216// no SDES cryptos.
Steve Anton71182f42018-01-19 14:59:54 -0800217TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsEnabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700218 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700219 auto caller = CreatePeerConnectionWithAudioVideo(config);
220
221 auto offer = caller->CreateOffer();
222 ASSERT_TRUE(offer);
223
224 ASSERT_FALSE(offer->description()->contents().empty());
225 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), offer->description()));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000226 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description()));
Steve Anton6b63cd52017-10-06 11:20:31 -0700227 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
228 offer->description()));
229}
Steve Anton71182f42018-01-19 14:59:54 -0800230TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsEnabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700231 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700232 auto caller = CreatePeerConnectionWithAudioVideo(config);
233 auto callee = CreatePeerConnectionWithAudioVideo(config);
234
235 callee->SetRemoteDescription(caller->CreateOffer());
236 auto answer = callee->CreateAnswer();
237 ASSERT_TRUE(answer);
238
239 ASSERT_FALSE(answer->description()->contents().empty());
240 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), answer->description()));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000241 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description()));
Steve Anton6b63cd52017-10-06 11:20:31 -0700242 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
243 answer->description()));
244}
245
Harald Alvestrandca327932022-04-04 15:37:31 +0000246#if defined(WEBRTC_FUCHSIA)
Harald Alvestrand50b95522021-11-18 10:01:06 +0000247// When DTLS is disabled, the SDP offer/answer should include SDES cryptos and
248// should not have a DTLS fingerprint.
249TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsDisabled) {
250 RTCConfiguration config;
251 config.enable_dtls_srtp.emplace(false);
252 auto caller = CreatePeerConnectionWithAudioVideo(config);
253
254 auto offer = caller->CreateOffer();
255 ASSERT_TRUE(offer);
256
257 ASSERT_FALSE(offer->description()->contents().empty());
258 EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), offer->description()));
259 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description()));
260 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf),
261 offer->description()));
262}
Harald Alvestrandca327932022-04-04 15:37:31 +0000263
Harald Alvestrand50b95522021-11-18 10:01:06 +0000264TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsDisabled) {
265 RTCConfiguration config;
266 config.enable_dtls_srtp.emplace(false);
267 auto caller = CreatePeerConnectionWithAudioVideo(config);
268 auto callee = CreatePeerConnectionWithAudioVideo(config);
269
270 callee->SetRemoteDescription(caller->CreateOffer());
271 auto answer = callee->CreateAnswer();
272 ASSERT_TRUE(answer);
273
274 ASSERT_FALSE(answer->description()->contents().empty());
275 EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), answer->description()));
276 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description()));
277 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf),
278 answer->description()));
279}
280
Steve Anton6b63cd52017-10-06 11:20:31 -0700281// When encryption is disabled, the SDP offer/answer should have neither a DTLS
282// fingerprint nor any SDES crypto options.
Steve Anton71182f42018-01-19 14:59:54 -0800283TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenEncryptionDisabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700284 PeerConnectionFactoryInterface::Options options;
285 options.disable_encryption = true;
286 pc_factory_->SetOptions(options);
287
288 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000289 config.enable_dtls_srtp.emplace(false);
Steve Anton6b63cd52017-10-06 11:20:31 -0700290 auto caller = CreatePeerConnectionWithAudioVideo(config);
291
292 auto offer = caller->CreateOffer();
293 ASSERT_TRUE(offer);
294
295 ASSERT_FALSE(offer->description()->contents().empty());
Harald Alvestrand0d018412021-11-04 13:52:31 +0000296 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description()));
Steve Anton6b63cd52017-10-06 11:20:31 -0700297 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description()));
298 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf),
299 offer->description()));
300}
Harald Alvestrandca327932022-04-04 15:37:31 +0000301
Steve Anton71182f42018-01-19 14:59:54 -0800302TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenEncryptionDisabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700303 PeerConnectionFactoryInterface::Options options;
304 options.disable_encryption = true;
305 pc_factory_->SetOptions(options);
306
307 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000308 config.enable_dtls_srtp.emplace(false);
Steve Anton6b63cd52017-10-06 11:20:31 -0700309 auto caller = CreatePeerConnectionWithAudioVideo(config);
310 auto callee = CreatePeerConnectionWithAudioVideo(config);
311
312 callee->SetRemoteDescription(caller->CreateOffer());
313 auto answer = callee->CreateAnswer();
314 ASSERT_TRUE(answer);
315
316 ASSERT_FALSE(answer->description()->contents().empty());
Harald Alvestrand0d018412021-11-04 13:52:31 +0000317 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description()));
Steve Anton6b63cd52017-10-06 11:20:31 -0700318 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description()));
319 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf),
320 answer->description()));
321}
322
Harald Alvestrand50b95522021-11-18 10:01:06 +0000323// CryptoOptions has been promoted to RTCConfiguration. As such if it is ever
324// set in the configuration it should overrite the settings set in the factory.
325TEST_P(PeerConnectionCryptoTest, RTCConfigurationCryptoOptionOverridesFactory) {
326 PeerConnectionFactoryInterface::Options options;
327 options.crypto_options.srtp.enable_gcm_crypto_suites = true;
328 pc_factory_->SetOptions(options);
329
330 RTCConfiguration config;
331 config.enable_dtls_srtp.emplace(false);
332 CryptoOptions crypto_options;
333 crypto_options.srtp.enable_gcm_crypto_suites = false;
334 config.crypto_options = crypto_options;
335 auto caller = CreatePeerConnectionWithAudioVideo(config);
336
337 auto offer = caller->CreateOffer();
338 ASSERT_TRUE(offer);
339
340 ASSERT_FALSE(offer->description()->contents().empty());
341 // This should exist if GCM is enabled see CorrectCryptoInOfferWithSdesAndGcm
342 EXPECT_FALSE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description()));
343}
344
345// When DTLS is disabled and GCM cipher suites are enabled, the SDP offer/answer
346// should have the correct ciphers in the SDES crypto options.
347// With GCM cipher suites enabled, there will be 3 cryptos in the offer and 1
348// in the answer.
349TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWithSdesAndGcm) {
350 PeerConnectionFactoryInterface::Options options;
351 options.crypto_options.srtp.enable_gcm_crypto_suites = true;
352 pc_factory_->SetOptions(options);
353
354 RTCConfiguration config;
355 config.enable_dtls_srtp.emplace(false);
356 auto caller = CreatePeerConnectionWithAudioVideo(config);
357
358 auto offer = caller->CreateOffer();
359 ASSERT_TRUE(offer);
360
361 ASSERT_FALSE(offer->description()->contents().empty());
362 EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description()));
363}
364
365TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWithSdesAndGcm) {
366 PeerConnectionFactoryInterface::Options options;
367 options.crypto_options.srtp.enable_gcm_crypto_suites = true;
368 pc_factory_->SetOptions(options);
369
370 RTCConfiguration config;
371 config.enable_dtls_srtp.emplace(false);
372 auto caller = CreatePeerConnectionWithAudioVideo(config);
373 auto callee = CreatePeerConnectionWithAudioVideo(config);
374
375 auto offer = caller->CreateOffer();
376 for (cricket::ContentInfo& content : offer->description()->contents()) {
377 auto cryptos = content.media_description()->cryptos();
378 cryptos.erase(cryptos.begin()); // Assumes that non-GCM is the default.
379 content.media_description()->set_cryptos(cryptos);
380 }
381
382 callee->SetRemoteDescription(std::move(offer));
383 auto answer = callee->CreateAnswer();
384 ASSERT_TRUE(answer);
385
386 ASSERT_FALSE(answer->description()->contents().empty());
387 EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(1), answer->description()));
388}
389
Steve Anton71182f42018-01-19 14:59:54 -0800390TEST_P(PeerConnectionCryptoTest, CanSetSdesGcmRemoteOfferAndLocalAnswer) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700391 PeerConnectionFactoryInterface::Options options;
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700392 options.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6b63cd52017-10-06 11:20:31 -0700393 pc_factory_->SetOptions(options);
394
395 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000396 config.enable_dtls_srtp.emplace(false);
Steve Anton6b63cd52017-10-06 11:20:31 -0700397 auto caller = CreatePeerConnectionWithAudioVideo(config);
398 auto callee = CreatePeerConnectionWithAudioVideo(config);
399
400 auto offer = caller->CreateOffer();
401 ASSERT_TRUE(offer);
402 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
403
404 auto answer = callee->CreateAnswer();
405 ASSERT_TRUE(answer);
406 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
Harald Alvestrand50b95522021-11-18 10:01:06 +0000407}
408
409// The following group tests that two PeerConnections can successfully exchange
410// an offer/answer when DTLS is off and that they will refuse any offer/answer
411// applied locally/remotely if it does not include SDES cryptos.
412TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenSdesOn) {
413 RTCConfiguration config;
414 config.enable_dtls_srtp.emplace(false);
415 auto caller = CreatePeerConnectionWithAudioVideo(config);
416 auto callee = CreatePeerConnectionWithAudioVideo(config);
417
418 auto offer = caller->CreateOfferAndSetAsLocal();
419 ASSERT_TRUE(offer);
420 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
421
422 auto answer = callee->CreateAnswerAndSetAsLocal();
423 ASSERT_TRUE(answer);
424 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
425}
426TEST_P(PeerConnectionCryptoTest, FailToSetLocalOfferWithNoCryptosWhenSdesOn) {
427 RTCConfiguration config;
428 config.enable_dtls_srtp.emplace(false);
429 auto caller = CreatePeerConnectionWithAudioVideo(config);
430
431 auto offer = caller->CreateOffer();
432 SdpContentsForEach(RemoveSdesCryptos(), offer->description());
433
434 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
435}
436TEST_P(PeerConnectionCryptoTest, FailToSetRemoteOfferWithNoCryptosWhenSdesOn) {
437 RTCConfiguration config;
438 config.enable_dtls_srtp.emplace(false);
439 auto caller = CreatePeerConnectionWithAudioVideo(config);
440 auto callee = CreatePeerConnectionWithAudioVideo(config);
441
442 auto offer = caller->CreateOffer();
443 SdpContentsForEach(RemoveSdesCryptos(), offer->description());
444
445 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
446}
447TEST_P(PeerConnectionCryptoTest, FailToSetLocalAnswerWithNoCryptosWhenSdesOn) {
448 RTCConfiguration config;
449 config.enable_dtls_srtp.emplace(false);
450 auto caller = CreatePeerConnectionWithAudioVideo(config);
451 auto callee = CreatePeerConnectionWithAudioVideo(config);
452
453 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
454 auto answer = callee->CreateAnswer();
455 SdpContentsForEach(RemoveSdesCryptos(), answer->description());
456
457 EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
458}
459TEST_P(PeerConnectionCryptoTest, FailToSetRemoteAnswerWithNoCryptosWhenSdesOn) {
460 RTCConfiguration config;
461 config.enable_dtls_srtp.emplace(false);
462 auto caller = CreatePeerConnectionWithAudioVideo(config);
463 auto callee = CreatePeerConnectionWithAudioVideo(config);
464
465 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
466 auto answer = callee->CreateAnswerAndSetAsLocal();
467 SdpContentsForEach(RemoveSdesCryptos(), answer->description());
468
469 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
Steve Anton6b63cd52017-10-06 11:20:31 -0700470}
Harald Alvestrandca327932022-04-04 15:37:31 +0000471#endif
Steve Anton6b63cd52017-10-06 11:20:31 -0700472
473// The following group tests that two PeerConnections can successfully exchange
474// an offer/answer when DTLS is on and that they will refuse any offer/answer
475// applied locally/remotely if it does not include a DTLS fingerprint.
Steve Anton71182f42018-01-19 14:59:54 -0800476TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenDtlsOn) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700477 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700478 auto caller = CreatePeerConnectionWithAudioVideo(config);
479 auto callee = CreatePeerConnectionWithAudioVideo(config);
480
481 auto offer = caller->CreateOfferAndSetAsLocal();
482 ASSERT_TRUE(offer);
483 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
484
485 auto answer = callee->CreateAnswerAndSetAsLocal();
486 ASSERT_TRUE(answer);
487 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
488}
Steve Anton71182f42018-01-19 14:59:54 -0800489TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700490 FailToSetLocalOfferWithNoFingerprintWhenDtlsOn) {
491 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700492 auto caller = CreatePeerConnectionWithAudioVideo(config);
493
494 auto offer = caller->CreateOffer();
495 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
496
497 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
498}
Steve Anton71182f42018-01-19 14:59:54 -0800499TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700500 FailToSetRemoteOfferWithNoFingerprintWhenDtlsOn) {
501 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700502 auto caller = CreatePeerConnectionWithAudioVideo(config);
503 auto callee = CreatePeerConnectionWithAudioVideo(config);
504
505 auto offer = caller->CreateOffer();
506 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
507
508 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
509}
Steve Anton71182f42018-01-19 14:59:54 -0800510TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700511 FailToSetLocalAnswerWithNoFingerprintWhenDtlsOn) {
512 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700513 auto caller = CreatePeerConnectionWithAudioVideo(config);
514 auto callee = CreatePeerConnectionWithAudioVideo(config);
515
516 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
517 auto answer = callee->CreateAnswer();
518 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
519}
Steve Anton71182f42018-01-19 14:59:54 -0800520TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700521 FailToSetRemoteAnswerWithNoFingerprintWhenDtlsOn) {
522 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700523 auto caller = CreatePeerConnectionWithAudioVideo(config);
524 auto callee = CreatePeerConnectionWithAudioVideo(config);
525
526 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
527 auto answer = callee->CreateAnswerAndSetAsLocal();
528 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
529
530 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
531}
532
Harald Alvestrandca327932022-04-04 15:37:31 +0000533#if defined(WEBRTC_FUCHSIA)
Steve Anton6b63cd52017-10-06 11:20:31 -0700534// Test that an offer/answer can be exchanged when encryption is disabled.
Steve Anton71182f42018-01-19 14:59:54 -0800535TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenNoEncryption) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700536 PeerConnectionFactoryInterface::Options options;
537 options.disable_encryption = true;
538 pc_factory_->SetOptions(options);
539
540 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000541 config.enable_dtls_srtp.emplace(false);
Steve Anton6b63cd52017-10-06 11:20:31 -0700542 auto caller = CreatePeerConnectionWithAudioVideo(config);
543 auto callee = CreatePeerConnectionWithAudioVideo(config);
544
545 auto offer = caller->CreateOfferAndSetAsLocal();
546 ASSERT_TRUE(offer);
547 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
548
549 auto answer = callee->CreateAnswerAndSetAsLocal();
550 ASSERT_TRUE(answer);
551 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
552}
Harald Alvestrandca327932022-04-04 15:37:31 +0000553#endif
Steve Anton6b63cd52017-10-06 11:20:31 -0700554
555// Tests that a DTLS call can be established when the certificate is specified
556// in the PeerConnection config and no certificate generator is specified.
Steve Anton71182f42018-01-19 14:59:54 -0800557TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700558 ExchangeOfferAnswerWhenDtlsCertificateInConfig) {
559 RTCConfiguration caller_config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700560 caller_config.certificates.push_back(
561 FakeRTCCertificateGenerator::GenerateCertificate());
562 auto caller = CreatePeerConnectionWithAudioVideo(caller_config);
563
564 RTCConfiguration callee_config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700565 callee_config.certificates.push_back(
566 FakeRTCCertificateGenerator::GenerateCertificate());
567 auto callee = CreatePeerConnectionWithAudioVideo(callee_config);
568
569 auto offer = caller->CreateOfferAndSetAsLocal();
570 ASSERT_TRUE(offer);
571 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
572
573 auto answer = callee->CreateAnswerAndSetAsLocal();
574 ASSERT_TRUE(answer);
575 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
576}
577
578// The following parameterized test verifies that CreateOffer/CreateAnswer
579// returns successfully (or with failure if the underlying certificate generator
580// fails) no matter when the DTLS certificate is generated. If multiple
581// CreateOffer/CreateAnswer calls are made while waiting for the certificate,
582// they all finish after the certificate is generated.
583
Steve Anton6b63cd52017-10-06 11:20:31 -0700584// Whether the certificate will be generated before calling CreateOffer or
585// while CreateOffer is executing.
586enum class CertGenTime { kBefore, kDuring };
587std::ostream& operator<<(std::ostream& out, CertGenTime value) {
588 switch (value) {
589 case CertGenTime::kBefore:
590 return out << "before";
591 case CertGenTime::kDuring:
592 return out << "during";
593 default:
594 return out << "unknown";
595 }
596}
597
598// Whether the fake certificate generator will produce a certificate or fail.
599enum class CertGenResult { kSucceed, kFail };
600std::ostream& operator<<(std::ostream& out, CertGenResult value) {
601 switch (value) {
602 case CertGenResult::kSucceed:
603 return out << "succeed";
604 case CertGenResult::kFail:
605 return out << "fail";
606 default:
607 return out << "unknown";
608 }
609}
610
Steve Anton71182f42018-01-19 14:59:54 -0800611class PeerConnectionCryptoDtlsCertGenTest
612 : public PeerConnectionCryptoBaseTest,
613 public ::testing::WithParamInterface<std::tuple<SdpSemantics,
614 SdpType,
615 CertGenTime,
616 CertGenResult,
617 size_t>> {
Steve Anton6b63cd52017-10-06 11:20:31 -0700618 protected:
Steve Anton71182f42018-01-19 14:59:54 -0800619 PeerConnectionCryptoDtlsCertGenTest()
620 : PeerConnectionCryptoBaseTest(std::get<0>(GetParam())) {
621 sdp_type_ = std::get<1>(GetParam());
622 cert_gen_time_ = std::get<2>(GetParam());
623 cert_gen_result_ = std::get<3>(GetParam());
624 concurrent_calls_ = std::get<4>(GetParam());
Steve Anton6b63cd52017-10-06 11:20:31 -0700625 }
626
627 SdpType sdp_type_;
628 CertGenTime cert_gen_time_;
629 CertGenResult cert_gen_result_;
630 size_t concurrent_calls_;
631};
632
Steve Anton71182f42018-01-19 14:59:54 -0800633TEST_P(PeerConnectionCryptoDtlsCertGenTest, TestCertificateGeneration) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700634 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 11:20:31 -0700635 auto owned_fake_certificate_generator =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200636 std::make_unique<FakeRTCCertificateGenerator>();
Steve Anton6b63cd52017-10-06 11:20:31 -0700637 auto* fake_certificate_generator = owned_fake_certificate_generator.get();
638 fake_certificate_generator->set_should_fail(cert_gen_result_ ==
639 CertGenResult::kFail);
640 fake_certificate_generator->set_should_wait(cert_gen_time_ ==
641 CertGenTime::kDuring);
642 WrapperPtr pc;
643 if (sdp_type_ == SdpType::kOffer) {
644 pc = CreatePeerConnectionWithAudioVideo(
645 config, std::move(owned_fake_certificate_generator));
646 } else {
647 auto caller = CreatePeerConnectionWithAudioVideo(config);
648 pc = CreatePeerConnectionWithAudioVideo(
649 config, std::move(owned_fake_certificate_generator));
650 pc->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
651 }
652 if (cert_gen_time_ == CertGenTime::kBefore) {
653 ASSERT_TRUE_WAIT(fake_certificate_generator->generated_certificates() +
654 fake_certificate_generator->generated_failures() >
655 0,
656 kGenerateCertTimeout);
657 } else {
658 ASSERT_EQ(fake_certificate_generator->generated_certificates(), 0);
659 fake_certificate_generator->set_should_wait(false);
660 }
661 std::vector<rtc::scoped_refptr<MockCreateSessionDescriptionObserver>>
662 observers;
663 for (size_t i = 0; i < concurrent_calls_; i++) {
664 rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer =
Tommi87f70902021-04-27 14:43:08 +0200665 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Steve Anton6b63cd52017-10-06 11:20:31 -0700666 observers.push_back(observer);
667 if (sdp_type_ == SdpType::kOffer) {
Niels Möllerafb246b2022-04-20 14:26:50 +0200668 pc->pc()->CreateOffer(observer.get(),
Niels Möllerf06f9232018-08-07 12:32:18 +0200669 PeerConnectionInterface::RTCOfferAnswerOptions());
Steve Anton6b63cd52017-10-06 11:20:31 -0700670 } else {
Niels Möllerafb246b2022-04-20 14:26:50 +0200671 pc->pc()->CreateAnswer(observer.get(),
Niels Möllerf06f9232018-08-07 12:32:18 +0200672 PeerConnectionInterface::RTCOfferAnswerOptions());
Steve Anton6b63cd52017-10-06 11:20:31 -0700673 }
674 }
675 for (auto& observer : observers) {
676 EXPECT_TRUE_WAIT(observer->called(), 1000);
677 if (cert_gen_result_ == CertGenResult::kSucceed) {
678 EXPECT_TRUE(observer->result());
679 } else {
680 EXPECT_FALSE(observer->result());
681 }
682 }
683}
684
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100685INSTANTIATE_TEST_SUITE_P(
Steve Anton71182f42018-01-19 14:59:54 -0800686 PeerConnectionCryptoTest,
687 PeerConnectionCryptoDtlsCertGenTest,
Florent Castelli15a38de2022-04-06 00:38:21 +0200688 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Anton71182f42018-01-19 14:59:54 -0800689 Values(SdpType::kOffer, SdpType::kAnswer),
Steve Anton6b63cd52017-10-06 11:20:31 -0700690 Values(CertGenTime::kBefore, CertGenTime::kDuring),
691 Values(CertGenResult::kSucceed, CertGenResult::kFail),
692 Values(1, 3)));
693
Steve Anton8a63f782017-10-23 13:08:53 -0700694// Test that we can create and set an answer correctly when different
695// SSL roles have been negotiated for different transports.
696// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4525
Steve Anton71182f42018-01-19 14:59:54 -0800697TEST_P(PeerConnectionCryptoTest, CreateAnswerWithDifferentSslRoles) {
Steve Anton8a63f782017-10-23 13:08:53 -0700698 auto caller = CreatePeerConnectionWithAudioVideo();
699 auto callee = CreatePeerConnectionWithAudioVideo();
700
701 RTCOfferAnswerOptions options_no_bundle;
702 options_no_bundle.use_rtp_mux = false;
703
704 // First, negotiate different SSL roles for audio and video.
705 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
706 auto answer = callee->CreateAnswer(options_no_bundle);
707
708 AudioConnectionRole(answer->description()) = cricket::CONNECTIONROLE_ACTIVE;
709 VideoConnectionRole(answer->description()) = cricket::CONNECTIONROLE_PASSIVE;
710
711 ASSERT_TRUE(
712 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
713 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
714
715 // Now create an offer in the reverse direction, and ensure the initial
716 // offerer responds with an answer with the correct SSL roles.
717 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
718 answer = caller->CreateAnswer(options_no_bundle);
719
720 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
721 AudioConnectionRole(answer->description()));
722 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
723 VideoConnectionRole(answer->description()));
724
725 ASSERT_TRUE(
726 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
727 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
728
729 // Lastly, start BUNDLE-ing on "audio", expecting that the "passive" role of
730 // audio is transferred over to video in the answer that completes the BUNDLE
731 // negotiation.
732 RTCOfferAnswerOptions options_bundle;
733 options_bundle.use_rtp_mux = true;
734
735 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
736 answer = caller->CreateAnswer(options_bundle);
737
738 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
739 AudioConnectionRole(answer->description()));
740 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
741 VideoConnectionRole(answer->description()));
742
743 ASSERT_TRUE(
744 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
745 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
746}
747
Steve Anton80dd7b52018-02-16 17:08:42 -0800748// Tests that if the DTLS fingerprint is invalid then all future calls to
749// SetLocalDescription and SetRemoteDescription will fail due to a session
750// error.
751// This is a regression test for crbug.com/800775
752TEST_P(PeerConnectionCryptoTest, SessionErrorIfFingerprintInvalid) {
753 auto callee_certificate = rtc::RTCCertificate::FromPEM(kRsaPems[0]);
754 auto other_certificate = rtc::RTCCertificate::FromPEM(kRsaPems[1]);
755
756 auto caller = CreatePeerConnectionWithAudioVideo();
757 RTCConfiguration callee_config;
Steve Anton80dd7b52018-02-16 17:08:42 -0800758 callee_config.certificates.push_back(callee_certificate);
759 auto callee = CreatePeerConnectionWithAudioVideo(callee_config);
760
761 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
762
763 // Create an invalid answer with the other certificate's fingerprint.
Steve Anton25ca0ac2019-06-25 10:40:48 -0700764 auto valid_answer = callee->CreateAnswer();
765 auto invalid_answer = CloneSessionDescription(valid_answer.get());
Steve Anton80dd7b52018-02-16 17:08:42 -0800766 auto* audio_content =
767 cricket::GetFirstAudioContent(invalid_answer->description());
768 ASSERT_TRUE(audio_content);
769 auto* audio_transport_info =
770 invalid_answer->description()->GetTransportInfoByName(
771 audio_content->name);
772 ASSERT_TRUE(audio_transport_info);
Steve Anton4905edb2018-10-15 19:27:44 -0700773 audio_transport_info->description.identity_fingerprint =
774 rtc::SSLFingerprint::CreateFromCertificate(*other_certificate);
Steve Anton80dd7b52018-02-16 17:08:42 -0800775
776 // Set the invalid answer and expect a fingerprint error.
777 std::string error;
778 ASSERT_FALSE(callee->SetLocalDescription(std::move(invalid_answer), &error));
779 EXPECT_PRED_FORMAT2(AssertStringContains, error,
780 "Local fingerprint does not match identity.");
781
782 // Make sure that setting a valid remote offer or local answer also fails now.
783 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
784 EXPECT_PRED_FORMAT2(AssertStringContains, error,
785 "Session error code: ERROR_CONTENT.");
Steve Anton25ca0ac2019-06-25 10:40:48 -0700786 ASSERT_FALSE(callee->SetLocalDescription(std::move(valid_answer), &error));
Steve Anton80dd7b52018-02-16 17:08:42 -0800787 EXPECT_PRED_FORMAT2(AssertStringContains, error,
788 "Session error code: ERROR_CONTENT.");
789}
790
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100791INSTANTIATE_TEST_SUITE_P(PeerConnectionCryptoTest,
792 PeerConnectionCryptoTest,
Florent Castelli15a38de2022-04-06 00:38:21 +0200793 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100794 SdpSemantics::kUnifiedPlan));
Steve Anton71182f42018-01-19 14:59:54 -0800795
Steve Anton6b63cd52017-10-06 11:20:31 -0700796} // namespace webrtc