blob: 1741b992891df5b5e3241e9abf23500bdff2b3e3 [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"
46#include "rtc_base/ref_counted_object.h"
47#include "rtc_base/rtc_certificate.h"
48#include "rtc_base/rtc_certificate_generator.h"
49#include "rtc_base/ssl_fingerprint.h"
50#include "rtc_base/thread.h"
51#include "test/gtest.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>(
Steve Anton6b63cd52017-10-06 11:20:31 -0700100 rtc::Thread::Current(), nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200101 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Anton71182f42018-01-19 14:59:54 -0800102 RTCConfiguration modified_config = config;
103 modified_config.sdp_semantics = sdp_semantics_;
Steve Anton6b63cd52017-10-06 11:20:31 -0700104 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton71182f42018-01-19 14:59:54 -0800105 modified_config, std::move(fake_port_allocator), std::move(cert_gen),
Steve Anton6b63cd52017-10-06 11:20:31 -0700106 observer.get());
107 if (!pc) {
108 return nullptr;
109 }
110
Yves Gerey4e933292018-10-31 15:36:05 +0100111 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200112 return std::make_unique<PeerConnectionWrapper>(pc_factory_, pc,
113 std::move(observer));
Steve Anton6b63cd52017-10-06 11:20:31 -0700114 }
115
116 // Accepts the same arguments as CreatePeerConnection and adds default audio
117 // and video tracks.
118 template <typename... Args>
119 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
120 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
121 if (!wrapper) {
122 return nullptr;
123 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700124 wrapper->AddAudioTrack("a");
125 wrapper->AddVideoTrack("v");
Steve Anton6b63cd52017-10-06 11:20:31 -0700126 return wrapper;
127 }
128
Steve Anton8a63f782017-10-23 13:08:53 -0700129 cricket::ConnectionRole& AudioConnectionRole(
130 cricket::SessionDescription* desc) {
131 return ConnectionRoleFromContent(desc, cricket::GetFirstAudioContent(desc));
132 }
133
134 cricket::ConnectionRole& VideoConnectionRole(
135 cricket::SessionDescription* desc) {
136 return ConnectionRoleFromContent(desc, cricket::GetFirstVideoContent(desc));
137 }
138
139 cricket::ConnectionRole& ConnectionRoleFromContent(
140 cricket::SessionDescription* desc,
141 cricket::ContentInfo* content) {
142 RTC_DCHECK(content);
143 auto* transport_info = desc->GetTransportInfoByName(content->name);
144 RTC_DCHECK(transport_info);
145 return transport_info->description.connection_role;
146 }
147
Steve Anton6b63cd52017-10-06 11:20:31 -0700148 std::unique_ptr<rtc::VirtualSocketServer> vss_;
149 rtc::AutoSocketServerThread main_;
150 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
Steve Anton71182f42018-01-19 14:59:54 -0800151 const SdpSemantics sdp_semantics_;
Steve Anton6b63cd52017-10-06 11:20:31 -0700152};
153
154SdpContentPredicate HaveDtlsFingerprint() {
155 return [](const cricket::ContentInfo* content,
156 const cricket::TransportInfo* transport) {
157 return transport->description.identity_fingerprint != nullptr;
158 };
159}
160
Harald Alvestrand0d018412021-11-04 13:52:31 +0000161SdpContentPredicate HaveSdesCryptos() {
162 return [](const cricket::ContentInfo* content,
163 const cricket::TransportInfo* transport) {
164 return !content->media_description()->cryptos().empty();
165 };
166}
167
Steve Anton6b63cd52017-10-06 11:20:31 -0700168SdpContentPredicate HaveProtocol(const std::string& protocol) {
169 return [protocol](const cricket::ContentInfo* content,
170 const cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800171 return content->media_description()->protocol() == protocol;
Steve Anton6b63cd52017-10-06 11:20:31 -0700172 };
173}
174
Harald Alvestrand0d018412021-11-04 13:52:31 +0000175SdpContentPredicate HaveSdesGcmCryptos(size_t num_crypto_suites) {
176 return [num_crypto_suites](const cricket::ContentInfo* content,
177 const cricket::TransportInfo* transport) {
178 const auto& cryptos = content->media_description()->cryptos();
179 if (cryptos.size() != num_crypto_suites) {
180 return false;
181 }
182 for (size_t i = 0; i < cryptos.size(); ++i) {
183 if (cryptos[i].key_params.size() == 67U &&
184 cryptos[i].cipher_suite == "AEAD_AES_256_GCM")
185 return true;
186 }
187 return false;
188 };
189}
190
Steve Anton71182f42018-01-19 14:59:54 -0800191class PeerConnectionCryptoTest
192 : public PeerConnectionCryptoBaseTest,
193 public ::testing::WithParamInterface<SdpSemantics> {
194 protected:
195 PeerConnectionCryptoTest() : PeerConnectionCryptoBaseTest(GetParam()) {}
196};
197
Harald Alvestrand0d018412021-11-04 13:52:31 +0000198SdpContentMutator RemoveSdesCryptos() {
199 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
200 content->media_description()->set_cryptos({});
201 };
202}
203
Steve Anton6b63cd52017-10-06 11:20:31 -0700204SdpContentMutator RemoveDtlsFingerprint() {
205 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
206 transport->description.identity_fingerprint.reset();
207 };
208}
209
Harald Alvestrand0d018412021-11-04 13:52:31 +0000210// When DTLS is enabled, the SDP offer/answer should have a DTLS fingerprint and
211// no SDES cryptos.
Steve Anton71182f42018-01-19 14:59:54 -0800212TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsEnabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700213 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000214 config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700215 auto caller = CreatePeerConnectionWithAudioVideo(config);
216
217 auto offer = caller->CreateOffer();
218 ASSERT_TRUE(offer);
219
220 ASSERT_FALSE(offer->description()->contents().empty());
221 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), offer->description()));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000222 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description()));
Steve Anton6b63cd52017-10-06 11:20:31 -0700223 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
224 offer->description()));
225}
Steve Anton71182f42018-01-19 14:59:54 -0800226TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsEnabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700227 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000228 config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700229 auto caller = CreatePeerConnectionWithAudioVideo(config);
230 auto callee = CreatePeerConnectionWithAudioVideo(config);
231
232 callee->SetRemoteDescription(caller->CreateOffer());
233 auto answer = callee->CreateAnswer();
234 ASSERT_TRUE(answer);
235
236 ASSERT_FALSE(answer->description()->contents().empty());
237 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), answer->description()));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000238 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description()));
Steve Anton6b63cd52017-10-06 11:20:31 -0700239 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
240 answer->description()));
241}
242
Harald Alvestrand50b95522021-11-18 10:01:06 +0000243// When DTLS is disabled, the SDP offer/answer should include SDES cryptos and
244// should not have a DTLS fingerprint.
245TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsDisabled) {
246 RTCConfiguration config;
247 config.enable_dtls_srtp.emplace(false);
248 auto caller = CreatePeerConnectionWithAudioVideo(config);
249
250 auto offer = caller->CreateOffer();
251 ASSERT_TRUE(offer);
252
253 ASSERT_FALSE(offer->description()->contents().empty());
254 EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), offer->description()));
255 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description()));
256 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf),
257 offer->description()));
258}
259TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsDisabled) {
260 RTCConfiguration config;
261 config.enable_dtls_srtp.emplace(false);
262 auto caller = CreatePeerConnectionWithAudioVideo(config);
263 auto callee = CreatePeerConnectionWithAudioVideo(config);
264
265 callee->SetRemoteDescription(caller->CreateOffer());
266 auto answer = callee->CreateAnswer();
267 ASSERT_TRUE(answer);
268
269 ASSERT_FALSE(answer->description()->contents().empty());
270 EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), answer->description()));
271 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description()));
272 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf),
273 answer->description()));
274}
275
Steve Anton6b63cd52017-10-06 11:20:31 -0700276// When encryption is disabled, the SDP offer/answer should have neither a DTLS
277// fingerprint nor any SDES crypto options.
Steve Anton71182f42018-01-19 14:59:54 -0800278TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenEncryptionDisabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700279 PeerConnectionFactoryInterface::Options options;
280 options.disable_encryption = true;
281 pc_factory_->SetOptions(options);
282
283 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000284 config.enable_dtls_srtp.emplace(false);
Steve Anton6b63cd52017-10-06 11:20:31 -0700285 auto caller = CreatePeerConnectionWithAudioVideo(config);
286
287 auto offer = caller->CreateOffer();
288 ASSERT_TRUE(offer);
289
290 ASSERT_FALSE(offer->description()->contents().empty());
Harald Alvestrand0d018412021-11-04 13:52:31 +0000291 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description()));
Steve Anton6b63cd52017-10-06 11:20:31 -0700292 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description()));
293 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf),
294 offer->description()));
295}
Steve Anton71182f42018-01-19 14:59:54 -0800296TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenEncryptionDisabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700297 PeerConnectionFactoryInterface::Options options;
298 options.disable_encryption = true;
299 pc_factory_->SetOptions(options);
300
301 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000302 config.enable_dtls_srtp.emplace(false);
Steve Anton6b63cd52017-10-06 11:20:31 -0700303 auto caller = CreatePeerConnectionWithAudioVideo(config);
304 auto callee = CreatePeerConnectionWithAudioVideo(config);
305
306 callee->SetRemoteDescription(caller->CreateOffer());
307 auto answer = callee->CreateAnswer();
308 ASSERT_TRUE(answer);
309
310 ASSERT_FALSE(answer->description()->contents().empty());
Harald Alvestrand0d018412021-11-04 13:52:31 +0000311 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description()));
Steve Anton6b63cd52017-10-06 11:20:31 -0700312 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description()));
313 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf),
314 answer->description()));
315}
316
Harald Alvestrand50b95522021-11-18 10:01:06 +0000317// CryptoOptions has been promoted to RTCConfiguration. As such if it is ever
318// set in the configuration it should overrite the settings set in the factory.
319TEST_P(PeerConnectionCryptoTest, RTCConfigurationCryptoOptionOverridesFactory) {
320 PeerConnectionFactoryInterface::Options options;
321 options.crypto_options.srtp.enable_gcm_crypto_suites = true;
322 pc_factory_->SetOptions(options);
323
324 RTCConfiguration config;
325 config.enable_dtls_srtp.emplace(false);
326 CryptoOptions crypto_options;
327 crypto_options.srtp.enable_gcm_crypto_suites = false;
328 config.crypto_options = crypto_options;
329 auto caller = CreatePeerConnectionWithAudioVideo(config);
330
331 auto offer = caller->CreateOffer();
332 ASSERT_TRUE(offer);
333
334 ASSERT_FALSE(offer->description()->contents().empty());
335 // This should exist if GCM is enabled see CorrectCryptoInOfferWithSdesAndGcm
336 EXPECT_FALSE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description()));
337}
338
339// When DTLS is disabled and GCM cipher suites are enabled, the SDP offer/answer
340// should have the correct ciphers in the SDES crypto options.
341// With GCM cipher suites enabled, there will be 3 cryptos in the offer and 1
342// in the answer.
343TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWithSdesAndGcm) {
344 PeerConnectionFactoryInterface::Options options;
345 options.crypto_options.srtp.enable_gcm_crypto_suites = true;
346 pc_factory_->SetOptions(options);
347
348 RTCConfiguration config;
349 config.enable_dtls_srtp.emplace(false);
350 auto caller = CreatePeerConnectionWithAudioVideo(config);
351
352 auto offer = caller->CreateOffer();
353 ASSERT_TRUE(offer);
354
355 ASSERT_FALSE(offer->description()->contents().empty());
356 EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description()));
357}
358
359TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWithSdesAndGcm) {
360 PeerConnectionFactoryInterface::Options options;
361 options.crypto_options.srtp.enable_gcm_crypto_suites = true;
362 pc_factory_->SetOptions(options);
363
364 RTCConfiguration config;
365 config.enable_dtls_srtp.emplace(false);
366 auto caller = CreatePeerConnectionWithAudioVideo(config);
367 auto callee = CreatePeerConnectionWithAudioVideo(config);
368
369 auto offer = caller->CreateOffer();
370 for (cricket::ContentInfo& content : offer->description()->contents()) {
371 auto cryptos = content.media_description()->cryptos();
372 cryptos.erase(cryptos.begin()); // Assumes that non-GCM is the default.
373 content.media_description()->set_cryptos(cryptos);
374 }
375
376 callee->SetRemoteDescription(std::move(offer));
377 auto answer = callee->CreateAnswer();
378 ASSERT_TRUE(answer);
379
380 ASSERT_FALSE(answer->description()->contents().empty());
381 EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(1), answer->description()));
382}
383
Steve Anton71182f42018-01-19 14:59:54 -0800384TEST_P(PeerConnectionCryptoTest, CanSetSdesGcmRemoteOfferAndLocalAnswer) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700385 PeerConnectionFactoryInterface::Options options;
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700386 options.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6b63cd52017-10-06 11:20:31 -0700387 pc_factory_->SetOptions(options);
388
389 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000390 config.enable_dtls_srtp.emplace(false);
Steve Anton6b63cd52017-10-06 11:20:31 -0700391 auto caller = CreatePeerConnectionWithAudioVideo(config);
392 auto callee = CreatePeerConnectionWithAudioVideo(config);
393
394 auto offer = caller->CreateOffer();
395 ASSERT_TRUE(offer);
396 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
397
398 auto answer = callee->CreateAnswer();
399 ASSERT_TRUE(answer);
400 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
Harald Alvestrand50b95522021-11-18 10:01:06 +0000401}
402
403// The following group tests that two PeerConnections can successfully exchange
404// an offer/answer when DTLS is off and that they will refuse any offer/answer
405// applied locally/remotely if it does not include SDES cryptos.
406TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenSdesOn) {
407 RTCConfiguration config;
408 config.enable_dtls_srtp.emplace(false);
409 auto caller = CreatePeerConnectionWithAudioVideo(config);
410 auto callee = CreatePeerConnectionWithAudioVideo(config);
411
412 auto offer = caller->CreateOfferAndSetAsLocal();
413 ASSERT_TRUE(offer);
414 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
415
416 auto answer = callee->CreateAnswerAndSetAsLocal();
417 ASSERT_TRUE(answer);
418 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
419}
420TEST_P(PeerConnectionCryptoTest, FailToSetLocalOfferWithNoCryptosWhenSdesOn) {
421 RTCConfiguration config;
422 config.enable_dtls_srtp.emplace(false);
423 auto caller = CreatePeerConnectionWithAudioVideo(config);
424
425 auto offer = caller->CreateOffer();
426 SdpContentsForEach(RemoveSdesCryptos(), offer->description());
427
428 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
429}
430TEST_P(PeerConnectionCryptoTest, FailToSetRemoteOfferWithNoCryptosWhenSdesOn) {
431 RTCConfiguration config;
432 config.enable_dtls_srtp.emplace(false);
433 auto caller = CreatePeerConnectionWithAudioVideo(config);
434 auto callee = CreatePeerConnectionWithAudioVideo(config);
435
436 auto offer = caller->CreateOffer();
437 SdpContentsForEach(RemoveSdesCryptos(), offer->description());
438
439 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
440}
441TEST_P(PeerConnectionCryptoTest, FailToSetLocalAnswerWithNoCryptosWhenSdesOn) {
442 RTCConfiguration config;
443 config.enable_dtls_srtp.emplace(false);
444 auto caller = CreatePeerConnectionWithAudioVideo(config);
445 auto callee = CreatePeerConnectionWithAudioVideo(config);
446
447 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
448 auto answer = callee->CreateAnswer();
449 SdpContentsForEach(RemoveSdesCryptos(), answer->description());
450
451 EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
452}
453TEST_P(PeerConnectionCryptoTest, FailToSetRemoteAnswerWithNoCryptosWhenSdesOn) {
454 RTCConfiguration config;
455 config.enable_dtls_srtp.emplace(false);
456 auto caller = CreatePeerConnectionWithAudioVideo(config);
457 auto callee = CreatePeerConnectionWithAudioVideo(config);
458
459 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
460 auto answer = callee->CreateAnswerAndSetAsLocal();
461 SdpContentsForEach(RemoveSdesCryptos(), answer->description());
462
463 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
Steve Anton6b63cd52017-10-06 11:20:31 -0700464}
465
466// The following group tests that two PeerConnections can successfully exchange
467// an offer/answer when DTLS is on and that they will refuse any offer/answer
468// applied locally/remotely if it does not include a DTLS fingerprint.
Steve Anton71182f42018-01-19 14:59:54 -0800469TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenDtlsOn) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700470 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000471 config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700472 auto caller = CreatePeerConnectionWithAudioVideo(config);
473 auto callee = CreatePeerConnectionWithAudioVideo(config);
474
475 auto offer = caller->CreateOfferAndSetAsLocal();
476 ASSERT_TRUE(offer);
477 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
478
479 auto answer = callee->CreateAnswerAndSetAsLocal();
480 ASSERT_TRUE(answer);
481 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
482}
Steve Anton71182f42018-01-19 14:59:54 -0800483TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700484 FailToSetLocalOfferWithNoFingerprintWhenDtlsOn) {
485 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000486 config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700487 auto caller = CreatePeerConnectionWithAudioVideo(config);
488
489 auto offer = caller->CreateOffer();
490 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
491
492 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
493}
Steve Anton71182f42018-01-19 14:59:54 -0800494TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700495 FailToSetRemoteOfferWithNoFingerprintWhenDtlsOn) {
496 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000497 config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700498 auto caller = CreatePeerConnectionWithAudioVideo(config);
499 auto callee = CreatePeerConnectionWithAudioVideo(config);
500
501 auto offer = caller->CreateOffer();
502 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
503
504 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
505}
Steve Anton71182f42018-01-19 14:59:54 -0800506TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700507 FailToSetLocalAnswerWithNoFingerprintWhenDtlsOn) {
508 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000509 config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700510 auto caller = CreatePeerConnectionWithAudioVideo(config);
511 auto callee = CreatePeerConnectionWithAudioVideo(config);
512
513 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
514 auto answer = callee->CreateAnswer();
515 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
516}
Steve Anton71182f42018-01-19 14:59:54 -0800517TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700518 FailToSetRemoteAnswerWithNoFingerprintWhenDtlsOn) {
519 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000520 config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700521 auto caller = CreatePeerConnectionWithAudioVideo(config);
522 auto callee = CreatePeerConnectionWithAudioVideo(config);
523
524 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
525 auto answer = callee->CreateAnswerAndSetAsLocal();
526 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
527
528 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
529}
530
531// Test that an offer/answer can be exchanged when encryption is disabled.
Steve Anton71182f42018-01-19 14:59:54 -0800532TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenNoEncryption) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700533 PeerConnectionFactoryInterface::Options options;
534 options.disable_encryption = true;
535 pc_factory_->SetOptions(options);
536
537 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000538 config.enable_dtls_srtp.emplace(false);
Steve Anton6b63cd52017-10-06 11:20:31 -0700539 auto caller = CreatePeerConnectionWithAudioVideo(config);
540 auto callee = CreatePeerConnectionWithAudioVideo(config);
541
542 auto offer = caller->CreateOfferAndSetAsLocal();
543 ASSERT_TRUE(offer);
544 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
545
546 auto answer = callee->CreateAnswerAndSetAsLocal();
547 ASSERT_TRUE(answer);
548 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
549}
550
551// Tests that a DTLS call can be established when the certificate is specified
552// in the PeerConnection config and no certificate generator is specified.
Steve Anton71182f42018-01-19 14:59:54 -0800553TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700554 ExchangeOfferAnswerWhenDtlsCertificateInConfig) {
555 RTCConfiguration caller_config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000556 caller_config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700557 caller_config.certificates.push_back(
558 FakeRTCCertificateGenerator::GenerateCertificate());
559 auto caller = CreatePeerConnectionWithAudioVideo(caller_config);
560
561 RTCConfiguration callee_config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000562 callee_config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700563 callee_config.certificates.push_back(
564 FakeRTCCertificateGenerator::GenerateCertificate());
565 auto callee = CreatePeerConnectionWithAudioVideo(callee_config);
566
567 auto offer = caller->CreateOfferAndSetAsLocal();
568 ASSERT_TRUE(offer);
569 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
570
571 auto answer = callee->CreateAnswerAndSetAsLocal();
572 ASSERT_TRUE(answer);
573 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
574}
575
576// The following parameterized test verifies that CreateOffer/CreateAnswer
577// returns successfully (or with failure if the underlying certificate generator
578// fails) no matter when the DTLS certificate is generated. If multiple
579// CreateOffer/CreateAnswer calls are made while waiting for the certificate,
580// they all finish after the certificate is generated.
581
Steve Anton6b63cd52017-10-06 11:20:31 -0700582// Whether the certificate will be generated before calling CreateOffer or
583// while CreateOffer is executing.
584enum class CertGenTime { kBefore, kDuring };
585std::ostream& operator<<(std::ostream& out, CertGenTime value) {
586 switch (value) {
587 case CertGenTime::kBefore:
588 return out << "before";
589 case CertGenTime::kDuring:
590 return out << "during";
591 default:
592 return out << "unknown";
593 }
594}
595
596// Whether the fake certificate generator will produce a certificate or fail.
597enum class CertGenResult { kSucceed, kFail };
598std::ostream& operator<<(std::ostream& out, CertGenResult value) {
599 switch (value) {
600 case CertGenResult::kSucceed:
601 return out << "succeed";
602 case CertGenResult::kFail:
603 return out << "fail";
604 default:
605 return out << "unknown";
606 }
607}
608
Steve Anton71182f42018-01-19 14:59:54 -0800609class PeerConnectionCryptoDtlsCertGenTest
610 : public PeerConnectionCryptoBaseTest,
611 public ::testing::WithParamInterface<std::tuple<SdpSemantics,
612 SdpType,
613 CertGenTime,
614 CertGenResult,
615 size_t>> {
Steve Anton6b63cd52017-10-06 11:20:31 -0700616 protected:
Steve Anton71182f42018-01-19 14:59:54 -0800617 PeerConnectionCryptoDtlsCertGenTest()
618 : PeerConnectionCryptoBaseTest(std::get<0>(GetParam())) {
619 sdp_type_ = std::get<1>(GetParam());
620 cert_gen_time_ = std::get<2>(GetParam());
621 cert_gen_result_ = std::get<3>(GetParam());
622 concurrent_calls_ = std::get<4>(GetParam());
Steve Anton6b63cd52017-10-06 11:20:31 -0700623 }
624
625 SdpType sdp_type_;
626 CertGenTime cert_gen_time_;
627 CertGenResult cert_gen_result_;
628 size_t concurrent_calls_;
629};
630
Steve Anton71182f42018-01-19 14:59:54 -0800631TEST_P(PeerConnectionCryptoDtlsCertGenTest, TestCertificateGeneration) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700632 RTCConfiguration config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000633 config.enable_dtls_srtp.emplace(true);
Steve Anton6b63cd52017-10-06 11:20:31 -0700634 auto owned_fake_certificate_generator =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200635 std::make_unique<FakeRTCCertificateGenerator>();
Steve Anton6b63cd52017-10-06 11:20:31 -0700636 auto* fake_certificate_generator = owned_fake_certificate_generator.get();
637 fake_certificate_generator->set_should_fail(cert_gen_result_ ==
638 CertGenResult::kFail);
639 fake_certificate_generator->set_should_wait(cert_gen_time_ ==
640 CertGenTime::kDuring);
641 WrapperPtr pc;
642 if (sdp_type_ == SdpType::kOffer) {
643 pc = CreatePeerConnectionWithAudioVideo(
644 config, std::move(owned_fake_certificate_generator));
645 } else {
646 auto caller = CreatePeerConnectionWithAudioVideo(config);
647 pc = CreatePeerConnectionWithAudioVideo(
648 config, std::move(owned_fake_certificate_generator));
649 pc->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
650 }
651 if (cert_gen_time_ == CertGenTime::kBefore) {
652 ASSERT_TRUE_WAIT(fake_certificate_generator->generated_certificates() +
653 fake_certificate_generator->generated_failures() >
654 0,
655 kGenerateCertTimeout);
656 } else {
657 ASSERT_EQ(fake_certificate_generator->generated_certificates(), 0);
658 fake_certificate_generator->set_should_wait(false);
659 }
660 std::vector<rtc::scoped_refptr<MockCreateSessionDescriptionObserver>>
661 observers;
662 for (size_t i = 0; i < concurrent_calls_; i++) {
663 rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer =
Tommi87f70902021-04-27 14:43:08 +0200664 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Steve Anton6b63cd52017-10-06 11:20:31 -0700665 observers.push_back(observer);
666 if (sdp_type_ == SdpType::kOffer) {
Niels Möllerf06f9232018-08-07 12:32:18 +0200667 pc->pc()->CreateOffer(observer,
668 PeerConnectionInterface::RTCOfferAnswerOptions());
Steve Anton6b63cd52017-10-06 11:20:31 -0700669 } else {
Niels Möllerf06f9232018-08-07 12:32:18 +0200670 pc->pc()->CreateAnswer(observer,
671 PeerConnectionInterface::RTCOfferAnswerOptions());
Steve Anton6b63cd52017-10-06 11:20:31 -0700672 }
673 }
674 for (auto& observer : observers) {
675 EXPECT_TRUE_WAIT(observer->called(), 1000);
676 if (cert_gen_result_ == CertGenResult::kSucceed) {
677 EXPECT_TRUE(observer->result());
678 } else {
679 EXPECT_FALSE(observer->result());
680 }
681 }
682}
683
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100684INSTANTIATE_TEST_SUITE_P(
Steve Anton71182f42018-01-19 14:59:54 -0800685 PeerConnectionCryptoTest,
686 PeerConnectionCryptoDtlsCertGenTest,
687 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
688 Values(SdpType::kOffer, SdpType::kAnswer),
Steve Anton6b63cd52017-10-06 11:20:31 -0700689 Values(CertGenTime::kBefore, CertGenTime::kDuring),
690 Values(CertGenResult::kSucceed, CertGenResult::kFail),
691 Values(1, 3)));
692
Steve Anton8a63f782017-10-23 13:08:53 -0700693// Test that we can create and set an answer correctly when different
694// SSL roles have been negotiated for different transports.
695// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4525
Steve Anton71182f42018-01-19 14:59:54 -0800696TEST_P(PeerConnectionCryptoTest, CreateAnswerWithDifferentSslRoles) {
Steve Anton8a63f782017-10-23 13:08:53 -0700697 auto caller = CreatePeerConnectionWithAudioVideo();
698 auto callee = CreatePeerConnectionWithAudioVideo();
699
700 RTCOfferAnswerOptions options_no_bundle;
701 options_no_bundle.use_rtp_mux = false;
702
703 // First, negotiate different SSL roles for audio and video.
704 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
705 auto answer = callee->CreateAnswer(options_no_bundle);
706
707 AudioConnectionRole(answer->description()) = cricket::CONNECTIONROLE_ACTIVE;
708 VideoConnectionRole(answer->description()) = cricket::CONNECTIONROLE_PASSIVE;
709
710 ASSERT_TRUE(
711 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
712 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
713
714 // Now create an offer in the reverse direction, and ensure the initial
715 // offerer responds with an answer with the correct SSL roles.
716 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
717 answer = caller->CreateAnswer(options_no_bundle);
718
719 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
720 AudioConnectionRole(answer->description()));
721 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
722 VideoConnectionRole(answer->description()));
723
724 ASSERT_TRUE(
725 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
726 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
727
728 // Lastly, start BUNDLE-ing on "audio", expecting that the "passive" role of
729 // audio is transferred over to video in the answer that completes the BUNDLE
730 // negotiation.
731 RTCOfferAnswerOptions options_bundle;
732 options_bundle.use_rtp_mux = true;
733
734 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
735 answer = caller->CreateAnswer(options_bundle);
736
737 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
738 AudioConnectionRole(answer->description()));
739 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
740 VideoConnectionRole(answer->description()));
741
742 ASSERT_TRUE(
743 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
744 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
745}
746
Steve Anton80dd7b52018-02-16 17:08:42 -0800747// Tests that if the DTLS fingerprint is invalid then all future calls to
748// SetLocalDescription and SetRemoteDescription will fail due to a session
749// error.
750// This is a regression test for crbug.com/800775
751TEST_P(PeerConnectionCryptoTest, SessionErrorIfFingerprintInvalid) {
752 auto callee_certificate = rtc::RTCCertificate::FromPEM(kRsaPems[0]);
753 auto other_certificate = rtc::RTCCertificate::FromPEM(kRsaPems[1]);
754
755 auto caller = CreatePeerConnectionWithAudioVideo();
756 RTCConfiguration callee_config;
Harald Alvestrand50b95522021-11-18 10:01:06 +0000757 callee_config.enable_dtls_srtp.emplace(true);
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,
793 Values(SdpSemantics::kPlanB,
794 SdpSemantics::kUnifiedPlan));
Steve Anton71182f42018-01-19 14:59:54 -0800795
Steve Anton6b63cd52017-10-06 11:20:31 -0700796} // namespace webrtc