blob: 1d90e04714b2a5996468f21c8dcd0d01b0020e72 [file] [log] [blame]
Steve Anton6b63cd52017-10-06 18:20:311/*
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:5911#include <stddef.h>
Mirko Bonadei317a1f02019-09-17 15:06:1812
Harald Alvestrandc24a2182022-02-23 13:44:5913#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 12:48:5423#include "api/audio_codecs/builtin_audio_decoder_factory.h"
24#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Mirko Bonadei2ff3f492018-11-22 08:00:1325#include "api/create_peerconnection_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5926#include "api/crypto/crypto_options.h"
Harald Alvestrandc24a2182022-02-23 13:44:5927#include "api/jsep.h"
28#include "api/peer_connection_interface.h"
29#include "api/scoped_refptr.h"
philipel098cfbd2023-03-31 15:11:3630#include "api/video_codecs/video_decoder_factory_template.h"
31#include "api/video_codecs/video_decoder_factory_template_dav1d_adapter.h"
32#include "api/video_codecs/video_decoder_factory_template_libvpx_vp8_adapter.h"
33#include "api/video_codecs/video_decoder_factory_template_libvpx_vp9_adapter.h"
34#include "api/video_codecs/video_decoder_factory_template_open_h264_adapter.h"
35#include "api/video_codecs/video_encoder_factory_template.h"
36#include "api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h"
37#include "api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h"
38#include "api/video_codecs/video_encoder_factory_template_libvpx_vp9_adapter.h"
39#include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h"
Harald Alvestrandc24a2182022-02-23 13:44:5940#include "modules/audio_device/include/audio_device.h"
41#include "modules/audio_processing/include/audio_processing.h"
Steve Anton10542f22019-01-11 17:11:0042#include "p2p/base/fake_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:5943#include "p2p/base/port_allocator.h"
44#include "p2p/base/transport_description.h"
45#include "p2p/base/transport_info.h"
46#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 17:11:0047#include "pc/media_session.h"
48#include "pc/peer_connection_wrapper.h"
49#include "pc/sdp_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:5950#include "pc/session_description.h"
51#include "pc/test/mock_peer_connection_observers.h"
52#include "rtc_base/checks.h"
Harald Alvestrandc24a2182022-02-23 13:44:5953#include "rtc_base/rtc_certificate.h"
54#include "rtc_base/rtc_certificate_generator.h"
55#include "rtc_base/ssl_fingerprint.h"
56#include "rtc_base/thread.h"
Philipp Hancke5aaa9ed2024-01-15 09:07:5857#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:5958#include "test/gtest.h"
Sameer Vijaykar0793ee72023-01-23 15:31:2959#include "test/scoped_key_value_config.h"
Steve Anton6b63cd52017-10-06 18:20:3160#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 17:11:0061#include "pc/test/android_test_initializer.h"
Steve Anton6b63cd52017-10-06 18:20:3162#endif
Steve Anton10542f22019-01-11 17:11:0063#include "pc/test/fake_audio_capture_module.h"
64#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton6b63cd52017-10-06 18:20:3165#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 17:11:0066#include "rtc_base/virtual_socket_server.h"
Steve Anton6b63cd52017-10-06 18:20:3167
68namespace webrtc {
69
70using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
Steve Anton8a63f782017-10-23 20:08:5371using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
Steve Anton6b63cd52017-10-06 18:20:3172using ::testing::Combine;
Philipp Hancke5aaa9ed2024-01-15 09:07:5873using ::testing::HasSubstr;
Jonas Olssona4d87372019-07-05 17:08:3374using ::testing::Values;
Steve Anton6b63cd52017-10-06 18:20:3175
76constexpr int kGenerateCertTimeout = 1000;
77
Steve Anton71182f42018-01-19 22:59:5478class PeerConnectionCryptoBaseTest : public ::testing::Test {
Steve Anton6b63cd52017-10-06 18:20:3179 protected:
80 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
81
Steve Anton71182f42018-01-19 22:59:5482 explicit PeerConnectionCryptoBaseTest(SdpSemantics sdp_semantics)
83 : vss_(new rtc::VirtualSocketServer()),
84 main_(vss_.get()),
85 sdp_semantics_(sdp_semantics) {
Steve Anton6b63cd52017-10-06 18:20:3186#ifdef WEBRTC_ANDROID
87 InitializeAndroidObjects();
88#endif
89 pc_factory_ = CreatePeerConnectionFactory(
90 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Karl Wiberg1b0eae32017-10-17 12:48:5491 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
philipel098cfbd2023-03-31 15:11:3692 CreateBuiltinAudioDecoderFactory(),
93 std::make_unique<VideoEncoderFactoryTemplate<
94 LibvpxVp8EncoderTemplateAdapter, LibvpxVp9EncoderTemplateAdapter,
95 OpenH264EncoderTemplateAdapter, LibaomAv1EncoderTemplateAdapter>>(),
96 std::make_unique<VideoDecoderFactoryTemplate<
97 LibvpxVp8DecoderTemplateAdapter, LibvpxVp9DecoderTemplateAdapter,
98 OpenH264DecoderTemplateAdapter, Dav1dDecoderTemplateAdapter>>(),
99 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Anton6b63cd52017-10-06 18:20:31100 }
101
Steve Anton8a63f782017-10-23 20:08:53102 WrapperPtr CreatePeerConnection() {
103 return CreatePeerConnection(RTCConfiguration());
104 }
105
Steve Anton6b63cd52017-10-06 18:20:31106 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
107 return CreatePeerConnection(config, nullptr);
108 }
109
110 WrapperPtr CreatePeerConnection(
111 const RTCConfiguration& config,
112 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_gen) {
Mirko Bonadei317a1f02019-09-17 15:06:18113 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Byoungchan Leed58f5262022-06-27 09:05:22114 rtc::Thread::Current(),
Sameer Vijaykar0793ee72023-01-23 15:31:29115 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()),
116 &field_trials_);
Mirko Bonadei317a1f02019-09-17 15:06:18117 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Anton71182f42018-01-19 22:59:54118 RTCConfiguration modified_config = config;
119 modified_config.sdp_semantics = sdp_semantics_;
Florent Castelli72424402022-04-06 01:45:10120 PeerConnectionDependencies pc_dependencies(observer.get());
121 pc_dependencies.allocator = std::move(fake_port_allocator);
122 pc_dependencies.cert_generator = std::move(cert_gen);
123 auto result = pc_factory_->CreatePeerConnectionOrError(
124 modified_config, std::move(pc_dependencies));
125 if (!result.ok()) {
Steve Anton6b63cd52017-10-06 18:20:31126 return nullptr;
127 }
128
Niels Möllerafb246b2022-04-20 12:26:50129 observer->SetPeerConnectionInterface(result.value().get());
Florent Castelli72424402022-04-06 01:45:10130 return std::make_unique<PeerConnectionWrapper>(
131 pc_factory_, result.MoveValue(), std::move(observer));
Steve Anton6b63cd52017-10-06 18:20:31132 }
133
134 // Accepts the same arguments as CreatePeerConnection and adds default audio
135 // and video tracks.
136 template <typename... Args>
137 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
138 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
139 if (!wrapper) {
140 return nullptr;
141 }
Steve Anton8d3444d2017-10-20 22:30:51142 wrapper->AddAudioTrack("a");
143 wrapper->AddVideoTrack("v");
Steve Anton6b63cd52017-10-06 18:20:31144 return wrapper;
145 }
146
Steve Anton8a63f782017-10-23 20:08:53147 cricket::ConnectionRole& AudioConnectionRole(
148 cricket::SessionDescription* desc) {
149 return ConnectionRoleFromContent(desc, cricket::GetFirstAudioContent(desc));
150 }
151
152 cricket::ConnectionRole& VideoConnectionRole(
153 cricket::SessionDescription* desc) {
154 return ConnectionRoleFromContent(desc, cricket::GetFirstVideoContent(desc));
155 }
156
157 cricket::ConnectionRole& ConnectionRoleFromContent(
158 cricket::SessionDescription* desc,
159 cricket::ContentInfo* content) {
160 RTC_DCHECK(content);
161 auto* transport_info = desc->GetTransportInfoByName(content->name);
162 RTC_DCHECK(transport_info);
163 return transport_info->description.connection_role;
164 }
165
Harald Alvestranda6544372023-11-13 09:33:56166 test::ScopedKeyValueConfig field_trials_;
Steve Anton6b63cd52017-10-06 18:20:31167 std::unique_ptr<rtc::VirtualSocketServer> vss_;
168 rtc::AutoSocketServerThread main_;
169 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
Steve Anton71182f42018-01-19 22:59:54170 const SdpSemantics sdp_semantics_;
Steve Anton6b63cd52017-10-06 18:20:31171};
172
173SdpContentPredicate HaveDtlsFingerprint() {
174 return [](const cricket::ContentInfo* content,
175 const cricket::TransportInfo* transport) {
176 return transport->description.identity_fingerprint != nullptr;
177 };
178}
179
Steve Anton6b63cd52017-10-06 18:20:31180SdpContentPredicate HaveProtocol(const std::string& protocol) {
181 return [protocol](const cricket::ContentInfo* content,
182 const cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 23:14:30183 return content->media_description()->protocol() == protocol;
Steve Anton6b63cd52017-10-06 18:20:31184 };
185}
186
Steve Anton71182f42018-01-19 22:59:54187class PeerConnectionCryptoTest
188 : public PeerConnectionCryptoBaseTest,
189 public ::testing::WithParamInterface<SdpSemantics> {
190 protected:
191 PeerConnectionCryptoTest() : PeerConnectionCryptoBaseTest(GetParam()) {}
192};
193
Steve Anton6b63cd52017-10-06 18:20:31194SdpContentMutator RemoveDtlsFingerprint() {
195 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
196 transport->description.identity_fingerprint.reset();
197 };
198}
199
Harald Alvestrand974044e2024-02-08 13:15:51200// When DTLS is enabled, the SDP offer/answer should have a DTLS fingerprint
Steve Anton71182f42018-01-19 22:59:54201TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsEnabled) {
Steve Anton6b63cd52017-10-06 18:20:31202 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 18:20:31203 auto caller = CreatePeerConnectionWithAudioVideo(config);
204
205 auto offer = caller->CreateOffer();
206 ASSERT_TRUE(offer);
207
208 ASSERT_FALSE(offer->description()->contents().empty());
209 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), offer->description()));
Steve Anton6b63cd52017-10-06 18:20:31210 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
211 offer->description()));
212}
Steve Anton71182f42018-01-19 22:59:54213TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsEnabled) {
Steve Anton6b63cd52017-10-06 18:20:31214 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 18:20:31215 auto caller = CreatePeerConnectionWithAudioVideo(config);
216 auto callee = CreatePeerConnectionWithAudioVideo(config);
217
218 callee->SetRemoteDescription(caller->CreateOffer());
219 auto answer = callee->CreateAnswer();
220 ASSERT_TRUE(answer);
221
222 ASSERT_FALSE(answer->description()->contents().empty());
223 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), answer->description()));
Steve Anton6b63cd52017-10-06 18:20:31224 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
225 answer->description()));
226}
227
Steve Anton6b63cd52017-10-06 18:20:31228// The following group tests that two PeerConnections can successfully exchange
229// an offer/answer when DTLS is on and that they will refuse any offer/answer
230// applied locally/remotely if it does not include a DTLS fingerprint.
Steve Anton71182f42018-01-19 22:59:54231TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenDtlsOn) {
Steve Anton6b63cd52017-10-06 18:20:31232 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 18:20:31233 auto caller = CreatePeerConnectionWithAudioVideo(config);
234 auto callee = CreatePeerConnectionWithAudioVideo(config);
235
236 auto offer = caller->CreateOfferAndSetAsLocal();
237 ASSERT_TRUE(offer);
238 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
239
240 auto answer = callee->CreateAnswerAndSetAsLocal();
241 ASSERT_TRUE(answer);
242 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
243}
Steve Anton71182f42018-01-19 22:59:54244TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 18:20:31245 FailToSetLocalOfferWithNoFingerprintWhenDtlsOn) {
246 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 18:20:31247 auto caller = CreatePeerConnectionWithAudioVideo(config);
248
249 auto offer = caller->CreateOffer();
250 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
251
252 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
253}
Steve Anton71182f42018-01-19 22:59:54254TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 18:20:31255 FailToSetRemoteOfferWithNoFingerprintWhenDtlsOn) {
256 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 18:20:31257 auto caller = CreatePeerConnectionWithAudioVideo(config);
258 auto callee = CreatePeerConnectionWithAudioVideo(config);
259
260 auto offer = caller->CreateOffer();
261 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
262
263 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
264}
Steve Anton71182f42018-01-19 22:59:54265TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 18:20:31266 FailToSetLocalAnswerWithNoFingerprintWhenDtlsOn) {
267 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 18:20:31268 auto caller = CreatePeerConnectionWithAudioVideo(config);
269 auto callee = CreatePeerConnectionWithAudioVideo(config);
270
271 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
272 auto answer = callee->CreateAnswer();
273 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
274}
Steve Anton71182f42018-01-19 22:59:54275TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 18:20:31276 FailToSetRemoteAnswerWithNoFingerprintWhenDtlsOn) {
277 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 18:20:31278 auto caller = CreatePeerConnectionWithAudioVideo(config);
279 auto callee = CreatePeerConnectionWithAudioVideo(config);
280
281 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
282 auto answer = callee->CreateAnswerAndSetAsLocal();
283 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
284
285 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
286}
287
Steve Anton6b63cd52017-10-06 18:20:31288// Tests that a DTLS call can be established when the certificate is specified
289// in the PeerConnection config and no certificate generator is specified.
Steve Anton71182f42018-01-19 22:59:54290TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 18:20:31291 ExchangeOfferAnswerWhenDtlsCertificateInConfig) {
292 RTCConfiguration caller_config;
Steve Anton6b63cd52017-10-06 18:20:31293 caller_config.certificates.push_back(
294 FakeRTCCertificateGenerator::GenerateCertificate());
295 auto caller = CreatePeerConnectionWithAudioVideo(caller_config);
296
297 RTCConfiguration callee_config;
Steve Anton6b63cd52017-10-06 18:20:31298 callee_config.certificates.push_back(
299 FakeRTCCertificateGenerator::GenerateCertificate());
300 auto callee = CreatePeerConnectionWithAudioVideo(callee_config);
301
302 auto offer = caller->CreateOfferAndSetAsLocal();
303 ASSERT_TRUE(offer);
304 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
305
306 auto answer = callee->CreateAnswerAndSetAsLocal();
307 ASSERT_TRUE(answer);
308 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
309}
310
311// The following parameterized test verifies that CreateOffer/CreateAnswer
312// returns successfully (or with failure if the underlying certificate generator
313// fails) no matter when the DTLS certificate is generated. If multiple
314// CreateOffer/CreateAnswer calls are made while waiting for the certificate,
315// they all finish after the certificate is generated.
316
Steve Anton6b63cd52017-10-06 18:20:31317// Whether the certificate will be generated before calling CreateOffer or
318// while CreateOffer is executing.
319enum class CertGenTime { kBefore, kDuring };
320std::ostream& operator<<(std::ostream& out, CertGenTime value) {
321 switch (value) {
322 case CertGenTime::kBefore:
323 return out << "before";
324 case CertGenTime::kDuring:
325 return out << "during";
326 default:
327 return out << "unknown";
328 }
329}
330
331// Whether the fake certificate generator will produce a certificate or fail.
332enum class CertGenResult { kSucceed, kFail };
333std::ostream& operator<<(std::ostream& out, CertGenResult value) {
334 switch (value) {
335 case CertGenResult::kSucceed:
336 return out << "succeed";
337 case CertGenResult::kFail:
338 return out << "fail";
339 default:
340 return out << "unknown";
341 }
342}
343
Steve Anton71182f42018-01-19 22:59:54344class PeerConnectionCryptoDtlsCertGenTest
345 : public PeerConnectionCryptoBaseTest,
346 public ::testing::WithParamInterface<std::tuple<SdpSemantics,
347 SdpType,
348 CertGenTime,
349 CertGenResult,
350 size_t>> {
Steve Anton6b63cd52017-10-06 18:20:31351 protected:
Steve Anton71182f42018-01-19 22:59:54352 PeerConnectionCryptoDtlsCertGenTest()
353 : PeerConnectionCryptoBaseTest(std::get<0>(GetParam())) {
354 sdp_type_ = std::get<1>(GetParam());
355 cert_gen_time_ = std::get<2>(GetParam());
356 cert_gen_result_ = std::get<3>(GetParam());
357 concurrent_calls_ = std::get<4>(GetParam());
Steve Anton6b63cd52017-10-06 18:20:31358 }
359
360 SdpType sdp_type_;
361 CertGenTime cert_gen_time_;
362 CertGenResult cert_gen_result_;
363 size_t concurrent_calls_;
364};
365
Steve Anton71182f42018-01-19 22:59:54366TEST_P(PeerConnectionCryptoDtlsCertGenTest, TestCertificateGeneration) {
Steve Anton6b63cd52017-10-06 18:20:31367 RTCConfiguration config;
Steve Anton6b63cd52017-10-06 18:20:31368 auto owned_fake_certificate_generator =
Mirko Bonadei317a1f02019-09-17 15:06:18369 std::make_unique<FakeRTCCertificateGenerator>();
Steve Anton6b63cd52017-10-06 18:20:31370 auto* fake_certificate_generator = owned_fake_certificate_generator.get();
371 fake_certificate_generator->set_should_fail(cert_gen_result_ ==
372 CertGenResult::kFail);
373 fake_certificate_generator->set_should_wait(cert_gen_time_ ==
374 CertGenTime::kDuring);
375 WrapperPtr pc;
376 if (sdp_type_ == SdpType::kOffer) {
377 pc = CreatePeerConnectionWithAudioVideo(
378 config, std::move(owned_fake_certificate_generator));
379 } else {
380 auto caller = CreatePeerConnectionWithAudioVideo(config);
381 pc = CreatePeerConnectionWithAudioVideo(
382 config, std::move(owned_fake_certificate_generator));
383 pc->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
384 }
385 if (cert_gen_time_ == CertGenTime::kBefore) {
386 ASSERT_TRUE_WAIT(fake_certificate_generator->generated_certificates() +
387 fake_certificate_generator->generated_failures() >
388 0,
389 kGenerateCertTimeout);
390 } else {
391 ASSERT_EQ(fake_certificate_generator->generated_certificates(), 0);
392 fake_certificate_generator->set_should_wait(false);
393 }
394 std::vector<rtc::scoped_refptr<MockCreateSessionDescriptionObserver>>
395 observers;
396 for (size_t i = 0; i < concurrent_calls_; i++) {
397 rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer =
Tommi87f70902021-04-27 12:43:08398 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Steve Anton6b63cd52017-10-06 18:20:31399 observers.push_back(observer);
400 if (sdp_type_ == SdpType::kOffer) {
Niels Möllerafb246b2022-04-20 12:26:50401 pc->pc()->CreateOffer(observer.get(),
Niels Möllerf06f9232018-08-07 10:32:18402 PeerConnectionInterface::RTCOfferAnswerOptions());
Steve Anton6b63cd52017-10-06 18:20:31403 } else {
Niels Möllerafb246b2022-04-20 12:26:50404 pc->pc()->CreateAnswer(observer.get(),
Niels Möllerf06f9232018-08-07 10:32:18405 PeerConnectionInterface::RTCOfferAnswerOptions());
Steve Anton6b63cd52017-10-06 18:20:31406 }
407 }
408 for (auto& observer : observers) {
409 EXPECT_TRUE_WAIT(observer->called(), 1000);
410 if (cert_gen_result_ == CertGenResult::kSucceed) {
411 EXPECT_TRUE(observer->result());
412 } else {
413 EXPECT_FALSE(observer->result());
414 }
415 }
416}
417
Mirko Bonadeic84f6612019-01-31 11:20:57418INSTANTIATE_TEST_SUITE_P(
Steve Anton71182f42018-01-19 22:59:54419 PeerConnectionCryptoTest,
420 PeerConnectionCryptoDtlsCertGenTest,
Florent Castelli15a38de2022-04-05 22:38:21421 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Anton71182f42018-01-19 22:59:54422 Values(SdpType::kOffer, SdpType::kAnswer),
Steve Anton6b63cd52017-10-06 18:20:31423 Values(CertGenTime::kBefore, CertGenTime::kDuring),
424 Values(CertGenResult::kSucceed, CertGenResult::kFail),
425 Values(1, 3)));
426
Steve Anton8a63f782017-10-23 20:08:53427// Test that we can create and set an answer correctly when different
428// SSL roles have been negotiated for different transports.
429// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4525
Steve Anton71182f42018-01-19 22:59:54430TEST_P(PeerConnectionCryptoTest, CreateAnswerWithDifferentSslRoles) {
Steve Anton8a63f782017-10-23 20:08:53431 auto caller = CreatePeerConnectionWithAudioVideo();
432 auto callee = CreatePeerConnectionWithAudioVideo();
433
434 RTCOfferAnswerOptions options_no_bundle;
435 options_no_bundle.use_rtp_mux = false;
436
437 // First, negotiate different SSL roles for audio and video.
438 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
439 auto answer = callee->CreateAnswer(options_no_bundle);
440
441 AudioConnectionRole(answer->description()) = cricket::CONNECTIONROLE_ACTIVE;
442 VideoConnectionRole(answer->description()) = cricket::CONNECTIONROLE_PASSIVE;
443
444 ASSERT_TRUE(
445 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
446 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
447
448 // Now create an offer in the reverse direction, and ensure the initial
449 // offerer responds with an answer with the correct SSL roles.
450 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
451 answer = caller->CreateAnswer(options_no_bundle);
452
453 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
454 AudioConnectionRole(answer->description()));
455 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
456 VideoConnectionRole(answer->description()));
457
458 ASSERT_TRUE(
459 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
460 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
461
462 // Lastly, start BUNDLE-ing on "audio", expecting that the "passive" role of
463 // audio is transferred over to video in the answer that completes the BUNDLE
464 // negotiation.
465 RTCOfferAnswerOptions options_bundle;
466 options_bundle.use_rtp_mux = true;
467
468 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
469 answer = caller->CreateAnswer(options_bundle);
470
471 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
472 AudioConnectionRole(answer->description()));
473 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
474 VideoConnectionRole(answer->description()));
475
476 ASSERT_TRUE(
477 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
478 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
479}
480
Steve Anton80dd7b52018-02-17 01:08:42481// Tests that if the DTLS fingerprint is invalid then all future calls to
482// SetLocalDescription and SetRemoteDescription will fail due to a session
483// error.
484// This is a regression test for crbug.com/800775
485TEST_P(PeerConnectionCryptoTest, SessionErrorIfFingerprintInvalid) {
486 auto callee_certificate = rtc::RTCCertificate::FromPEM(kRsaPems[0]);
487 auto other_certificate = rtc::RTCCertificate::FromPEM(kRsaPems[1]);
488
489 auto caller = CreatePeerConnectionWithAudioVideo();
490 RTCConfiguration callee_config;
Steve Anton80dd7b52018-02-17 01:08:42491 callee_config.certificates.push_back(callee_certificate);
492 auto callee = CreatePeerConnectionWithAudioVideo(callee_config);
493
494 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
495
496 // Create an invalid answer with the other certificate's fingerprint.
Steve Anton25ca0ac2019-06-25 17:40:48497 auto valid_answer = callee->CreateAnswer();
498 auto invalid_answer = CloneSessionDescription(valid_answer.get());
Steve Anton80dd7b52018-02-17 01:08:42499 auto* audio_content =
500 cricket::GetFirstAudioContent(invalid_answer->description());
501 ASSERT_TRUE(audio_content);
502 auto* audio_transport_info =
503 invalid_answer->description()->GetTransportInfoByName(
504 audio_content->name);
505 ASSERT_TRUE(audio_transport_info);
Steve Anton4905edb2018-10-16 02:27:44506 audio_transport_info->description.identity_fingerprint =
507 rtc::SSLFingerprint::CreateFromCertificate(*other_certificate);
Steve Anton80dd7b52018-02-17 01:08:42508
509 // Set the invalid answer and expect a fingerprint error.
510 std::string error;
511 ASSERT_FALSE(callee->SetLocalDescription(std::move(invalid_answer), &error));
Philipp Hancke5aaa9ed2024-01-15 09:07:58512 EXPECT_THAT(error, HasSubstr("Local fingerprint does not match identity."));
Steve Anton80dd7b52018-02-17 01:08:42513
514 // Make sure that setting a valid remote offer or local answer also fails now.
515 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Philipp Hancke5aaa9ed2024-01-15 09:07:58516 EXPECT_THAT(error, HasSubstr("Session error code: ERROR_CONTENT."));
Steve Anton25ca0ac2019-06-25 17:40:48517 ASSERT_FALSE(callee->SetLocalDescription(std::move(valid_answer), &error));
Philipp Hancke5aaa9ed2024-01-15 09:07:58518 EXPECT_THAT(error, HasSubstr("Session error code: ERROR_CONTENT."));
Steve Anton80dd7b52018-02-17 01:08:42519}
520
Mirko Bonadeic84f6612019-01-31 11:20:57521INSTANTIATE_TEST_SUITE_P(PeerConnectionCryptoTest,
522 PeerConnectionCryptoTest,
Florent Castelli15a38de2022-04-05 22:38:21523 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 11:20:57524 SdpSemantics::kUnifiedPlan));
Steve Anton71182f42018-01-19 22:59:54525
Steve Anton6b63cd52017-10-06 18:20:31526} // namespace webrtc