blob: b2f24692bf24218f63618ad6144134e0cc079dbb [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
Karl Wiberg1b0eae32017-10-17 14:48:54 +020011#include "api/audio_codecs/builtin_audio_decoder_factory.h"
12#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Steve Anton6b63cd52017-10-06 11:20:31 -070013#include "p2p/base/fakeportallocator.h"
14#include "pc/mediasession.h"
15#include "pc/peerconnectionwrapper.h"
16#include "pc/sdputils.h"
17#ifdef WEBRTC_ANDROID
18#include "pc/test/androidtestinitializer.h"
19#endif
20#include "pc/test/fakeaudiocapturemodule.h"
21#include "pc/test/fakertccertificategenerator.h"
22#include "rtc_base/gunit.h"
23#include "rtc_base/ptr_util.h"
24#include "rtc_base/virtualsocketserver.h"
25
26namespace webrtc {
27
28using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
Steve Anton8a63f782017-10-23 13:08:53 -070029using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
Steve Anton6b63cd52017-10-06 11:20:31 -070030using ::testing::Values;
31using ::testing::Combine;
32
33constexpr int kGenerateCertTimeout = 1000;
34
Steve Anton71182f42018-01-19 14:59:54 -080035class PeerConnectionCryptoBaseTest : public ::testing::Test {
Steve Anton6b63cd52017-10-06 11:20:31 -070036 protected:
37 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
38
Steve Anton71182f42018-01-19 14:59:54 -080039 explicit PeerConnectionCryptoBaseTest(SdpSemantics sdp_semantics)
40 : vss_(new rtc::VirtualSocketServer()),
41 main_(vss_.get()),
42 sdp_semantics_(sdp_semantics) {
Steve Anton6b63cd52017-10-06 11:20:31 -070043#ifdef WEBRTC_ANDROID
44 InitializeAndroidObjects();
45#endif
46 pc_factory_ = CreatePeerConnectionFactory(
47 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Karl Wiberg1b0eae32017-10-17 14:48:54 +020048 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
49 CreateBuiltinAudioDecoderFactory(), nullptr, nullptr);
Steve Anton6b63cd52017-10-06 11:20:31 -070050 }
51
Steve Anton8a63f782017-10-23 13:08:53 -070052 WrapperPtr CreatePeerConnection() {
53 return CreatePeerConnection(RTCConfiguration());
54 }
55
Steve Anton6b63cd52017-10-06 11:20:31 -070056 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
57 return CreatePeerConnection(config, nullptr);
58 }
59
60 WrapperPtr CreatePeerConnection(
61 const RTCConfiguration& config,
62 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_gen) {
63 auto fake_port_allocator = rtc::MakeUnique<cricket::FakePortAllocator>(
64 rtc::Thread::Current(), nullptr);
65 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
Steve Anton71182f42018-01-19 14:59:54 -080066 RTCConfiguration modified_config = config;
67 modified_config.sdp_semantics = sdp_semantics_;
Steve Anton6b63cd52017-10-06 11:20:31 -070068 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton71182f42018-01-19 14:59:54 -080069 modified_config, std::move(fake_port_allocator), std::move(cert_gen),
Steve Anton6b63cd52017-10-06 11:20:31 -070070 observer.get());
71 if (!pc) {
72 return nullptr;
73 }
74
75 return rtc::MakeUnique<PeerConnectionWrapper>(pc_factory_, pc,
76 std::move(observer));
77 }
78
79 // Accepts the same arguments as CreatePeerConnection and adds default audio
80 // and video tracks.
81 template <typename... Args>
82 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
83 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
84 if (!wrapper) {
85 return nullptr;
86 }
Steve Anton8d3444d2017-10-20 15:30:51 -070087 wrapper->AddAudioTrack("a");
88 wrapper->AddVideoTrack("v");
Steve Anton6b63cd52017-10-06 11:20:31 -070089 return wrapper;
90 }
91
Steve Anton8a63f782017-10-23 13:08:53 -070092 cricket::ConnectionRole& AudioConnectionRole(
93 cricket::SessionDescription* desc) {
94 return ConnectionRoleFromContent(desc, cricket::GetFirstAudioContent(desc));
95 }
96
97 cricket::ConnectionRole& VideoConnectionRole(
98 cricket::SessionDescription* desc) {
99 return ConnectionRoleFromContent(desc, cricket::GetFirstVideoContent(desc));
100 }
101
102 cricket::ConnectionRole& ConnectionRoleFromContent(
103 cricket::SessionDescription* desc,
104 cricket::ContentInfo* content) {
105 RTC_DCHECK(content);
106 auto* transport_info = desc->GetTransportInfoByName(content->name);
107 RTC_DCHECK(transport_info);
108 return transport_info->description.connection_role;
109 }
110
Steve Anton6b63cd52017-10-06 11:20:31 -0700111 std::unique_ptr<rtc::VirtualSocketServer> vss_;
112 rtc::AutoSocketServerThread main_;
113 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
Steve Anton71182f42018-01-19 14:59:54 -0800114 const SdpSemantics sdp_semantics_;
Steve Anton6b63cd52017-10-06 11:20:31 -0700115};
116
117SdpContentPredicate HaveDtlsFingerprint() {
118 return [](const cricket::ContentInfo* content,
119 const cricket::TransportInfo* transport) {
120 return transport->description.identity_fingerprint != nullptr;
121 };
122}
123
124SdpContentPredicate HaveSdesCryptos() {
125 return [](const cricket::ContentInfo* content,
126 const cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800127 return !content->media_description()->cryptos().empty();
Steve Anton6b63cd52017-10-06 11:20:31 -0700128 };
129}
130
131SdpContentPredicate HaveProtocol(const std::string& protocol) {
132 return [protocol](const cricket::ContentInfo* content,
133 const cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800134 return content->media_description()->protocol() == protocol;
Steve Anton6b63cd52017-10-06 11:20:31 -0700135 };
136}
137
138SdpContentPredicate HaveSdesGcmCryptos(size_t num_crypto_suites) {
139 return [num_crypto_suites](const cricket::ContentInfo* content,
140 const cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800141 const auto& cryptos = content->media_description()->cryptos();
142 if (cryptos.size() != num_crypto_suites) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700143 return false;
144 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800145 const cricket::CryptoParams first_params = cryptos[0];
Steve Anton6b63cd52017-10-06 11:20:31 -0700146 return first_params.key_params.size() == 67U &&
147 first_params.cipher_suite == "AEAD_AES_256_GCM";
148 };
149}
150
Steve Anton71182f42018-01-19 14:59:54 -0800151class PeerConnectionCryptoTest
152 : public PeerConnectionCryptoBaseTest,
153 public ::testing::WithParamInterface<SdpSemantics> {
154 protected:
155 PeerConnectionCryptoTest() : PeerConnectionCryptoBaseTest(GetParam()) {}
156};
157
Steve Anton6b63cd52017-10-06 11:20:31 -0700158SdpContentMutator RemoveSdesCryptos() {
159 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800160 content->media_description()->set_cryptos({});
Steve Anton6b63cd52017-10-06 11:20:31 -0700161 };
162}
163
164SdpContentMutator RemoveDtlsFingerprint() {
165 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
166 transport->description.identity_fingerprint.reset();
167 };
168}
169
170// When DTLS is enabled, the SDP offer/answer should have a DTLS fingerprint and
171// no SDES cryptos.
Steve Anton71182f42018-01-19 14:59:54 -0800172TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsEnabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700173 RTCConfiguration config;
174 config.enable_dtls_srtp.emplace(true);
175 auto caller = CreatePeerConnectionWithAudioVideo(config);
176
177 auto offer = caller->CreateOffer();
178 ASSERT_TRUE(offer);
179
180 ASSERT_FALSE(offer->description()->contents().empty());
181 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), offer->description()));
182 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description()));
183 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
184 offer->description()));
185}
Steve Anton71182f42018-01-19 14:59:54 -0800186TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsEnabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700187 RTCConfiguration config;
188 config.enable_dtls_srtp.emplace(true);
189 auto caller = CreatePeerConnectionWithAudioVideo(config);
190 auto callee = CreatePeerConnectionWithAudioVideo(config);
191
192 callee->SetRemoteDescription(caller->CreateOffer());
193 auto answer = callee->CreateAnswer();
194 ASSERT_TRUE(answer);
195
196 ASSERT_FALSE(answer->description()->contents().empty());
197 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), answer->description()));
198 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description()));
199 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
200 answer->description()));
201}
202
203// When DTLS is disabled, the SDP offer/answer should include SDES cryptos and
204// should not have a DTLS fingerprint.
Steve Anton71182f42018-01-19 14:59:54 -0800205TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsDisabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700206 RTCConfiguration config;
207 config.enable_dtls_srtp.emplace(false);
208 auto caller = CreatePeerConnectionWithAudioVideo(config);
209
210 auto offer = caller->CreateOffer();
211 ASSERT_TRUE(offer);
212
213 ASSERT_FALSE(offer->description()->contents().empty());
214 EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), offer->description()));
215 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description()));
216 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf),
217 offer->description()));
218}
Steve Anton71182f42018-01-19 14:59:54 -0800219TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsDisabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700220 RTCConfiguration config;
221 config.enable_dtls_srtp.emplace(false);
222 auto caller = CreatePeerConnectionWithAudioVideo(config);
223 auto callee = CreatePeerConnectionWithAudioVideo(config);
224
225 callee->SetRemoteDescription(caller->CreateOffer());
226 auto answer = callee->CreateAnswer();
227 ASSERT_TRUE(answer);
228
229 ASSERT_FALSE(answer->description()->contents().empty());
230 EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), answer->description()));
231 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description()));
232 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf),
233 answer->description()));
234}
235
236// When encryption is disabled, the SDP offer/answer should have neither a DTLS
237// fingerprint nor any SDES crypto options.
Steve Anton71182f42018-01-19 14:59:54 -0800238TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenEncryptionDisabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700239 PeerConnectionFactoryInterface::Options options;
240 options.disable_encryption = true;
241 pc_factory_->SetOptions(options);
242
243 RTCConfiguration config;
244 config.enable_dtls_srtp.emplace(false);
245 auto caller = CreatePeerConnectionWithAudioVideo(config);
246
247 auto offer = caller->CreateOffer();
248 ASSERT_TRUE(offer);
249
250 ASSERT_FALSE(offer->description()->contents().empty());
251 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description()));
252 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description()));
253 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf),
254 offer->description()));
255}
Steve Anton71182f42018-01-19 14:59:54 -0800256TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenEncryptionDisabled) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700257 PeerConnectionFactoryInterface::Options options;
258 options.disable_encryption = true;
259 pc_factory_->SetOptions(options);
260
261 RTCConfiguration config;
262 config.enable_dtls_srtp.emplace(false);
263 auto caller = CreatePeerConnectionWithAudioVideo(config);
264 auto callee = CreatePeerConnectionWithAudioVideo(config);
265
266 callee->SetRemoteDescription(caller->CreateOffer());
267 auto answer = callee->CreateAnswer();
268 ASSERT_TRUE(answer);
269
270 ASSERT_FALSE(answer->description()->contents().empty());
271 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description()));
272 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description()));
273 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf),
274 answer->description()));
275}
276
277// When DTLS is disabled and GCM cipher suites are enabled, the SDP offer/answer
278// should have the correct ciphers in the SDES crypto options.
279// With GCM cipher suites enabled, there will be 3 cryptos in the offer and 1
280// in the answer.
Steve Anton71182f42018-01-19 14:59:54 -0800281TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWithSdesAndGcm) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700282 PeerConnectionFactoryInterface::Options options;
283 options.crypto_options.enable_gcm_crypto_suites = true;
284 pc_factory_->SetOptions(options);
285
286 RTCConfiguration config;
287 config.enable_dtls_srtp.emplace(false);
288 auto caller = CreatePeerConnectionWithAudioVideo(config);
289
290 auto offer = caller->CreateOffer();
291 ASSERT_TRUE(offer);
292
293 ASSERT_FALSE(offer->description()->contents().empty());
294 EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description()));
295}
Steve Anton71182f42018-01-19 14:59:54 -0800296TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWithSdesAndGcm) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700297 PeerConnectionFactoryInterface::Options options;
298 options.crypto_options.enable_gcm_crypto_suites = true;
299 pc_factory_->SetOptions(options);
300
301 RTCConfiguration config;
302 config.enable_dtls_srtp.emplace(false);
303 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());
311 EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(1), answer->description()));
312}
313
Steve Anton71182f42018-01-19 14:59:54 -0800314TEST_P(PeerConnectionCryptoTest, CanSetSdesGcmRemoteOfferAndLocalAnswer) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700315 PeerConnectionFactoryInterface::Options options;
316 options.crypto_options.enable_gcm_crypto_suites = true;
317 pc_factory_->SetOptions(options);
318
319 RTCConfiguration config;
320 config.enable_dtls_srtp.emplace(false);
321 auto caller = CreatePeerConnectionWithAudioVideo(config);
322 auto callee = CreatePeerConnectionWithAudioVideo(config);
323
324 auto offer = caller->CreateOffer();
325 ASSERT_TRUE(offer);
326 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
327
328 auto answer = callee->CreateAnswer();
329 ASSERT_TRUE(answer);
330 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
331}
332
333// The following group tests that two PeerConnections can successfully exchange
334// an offer/answer when DTLS is off and that they will refuse any offer/answer
335// applied locally/remotely if it does not include SDES cryptos.
Steve Anton71182f42018-01-19 14:59:54 -0800336TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenSdesOn) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700337 RTCConfiguration config;
338 config.enable_dtls_srtp.emplace(false);
339 auto caller = CreatePeerConnectionWithAudioVideo(config);
340 auto callee = CreatePeerConnectionWithAudioVideo(config);
341
342 auto offer = caller->CreateOfferAndSetAsLocal();
343 ASSERT_TRUE(offer);
344 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
345
346 auto answer = callee->CreateAnswerAndSetAsLocal();
347 ASSERT_TRUE(answer);
348 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
349}
Steve Anton71182f42018-01-19 14:59:54 -0800350TEST_P(PeerConnectionCryptoTest, FailToSetLocalOfferWithNoCryptosWhenSdesOn) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700351 RTCConfiguration config;
352 config.enable_dtls_srtp.emplace(false);
353 auto caller = CreatePeerConnectionWithAudioVideo(config);
354
355 auto offer = caller->CreateOffer();
356 SdpContentsForEach(RemoveSdesCryptos(), offer->description());
357
358 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
359}
Steve Anton71182f42018-01-19 14:59:54 -0800360TEST_P(PeerConnectionCryptoTest, FailToSetRemoteOfferWithNoCryptosWhenSdesOn) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700361 RTCConfiguration config;
362 config.enable_dtls_srtp.emplace(false);
363 auto caller = CreatePeerConnectionWithAudioVideo(config);
364 auto callee = CreatePeerConnectionWithAudioVideo(config);
365
366 auto offer = caller->CreateOffer();
367 SdpContentsForEach(RemoveSdesCryptos(), offer->description());
368
369 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
370}
Steve Anton71182f42018-01-19 14:59:54 -0800371TEST_P(PeerConnectionCryptoTest, FailToSetLocalAnswerWithNoCryptosWhenSdesOn) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700372 RTCConfiguration config;
373 config.enable_dtls_srtp.emplace(false);
374 auto caller = CreatePeerConnectionWithAudioVideo(config);
375 auto callee = CreatePeerConnectionWithAudioVideo(config);
376
377 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
378 auto answer = callee->CreateAnswer();
379 SdpContentsForEach(RemoveSdesCryptos(), answer->description());
380
381 EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
382}
Steve Anton71182f42018-01-19 14:59:54 -0800383TEST_P(PeerConnectionCryptoTest, FailToSetRemoteAnswerWithNoCryptosWhenSdesOn) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700384 RTCConfiguration config;
385 config.enable_dtls_srtp.emplace(false);
386 auto caller = CreatePeerConnectionWithAudioVideo(config);
387 auto callee = CreatePeerConnectionWithAudioVideo(config);
388
389 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
390 auto answer = callee->CreateAnswerAndSetAsLocal();
391 SdpContentsForEach(RemoveSdesCryptos(), answer->description());
392
393 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
394}
395
396// The following group tests that two PeerConnections can successfully exchange
397// an offer/answer when DTLS is on and that they will refuse any offer/answer
398// applied locally/remotely if it does not include a DTLS fingerprint.
Steve Anton71182f42018-01-19 14:59:54 -0800399TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenDtlsOn) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700400 RTCConfiguration config;
401 config.enable_dtls_srtp.emplace(true);
402 auto caller = CreatePeerConnectionWithAudioVideo(config);
403 auto callee = CreatePeerConnectionWithAudioVideo(config);
404
405 auto offer = caller->CreateOfferAndSetAsLocal();
406 ASSERT_TRUE(offer);
407 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
408
409 auto answer = callee->CreateAnswerAndSetAsLocal();
410 ASSERT_TRUE(answer);
411 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
412}
Steve Anton71182f42018-01-19 14:59:54 -0800413TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700414 FailToSetLocalOfferWithNoFingerprintWhenDtlsOn) {
415 RTCConfiguration config;
416 config.enable_dtls_srtp.emplace(true);
417 auto caller = CreatePeerConnectionWithAudioVideo(config);
418
419 auto offer = caller->CreateOffer();
420 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
421
422 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
423}
Steve Anton71182f42018-01-19 14:59:54 -0800424TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700425 FailToSetRemoteOfferWithNoFingerprintWhenDtlsOn) {
426 RTCConfiguration config;
427 config.enable_dtls_srtp.emplace(true);
428 auto caller = CreatePeerConnectionWithAudioVideo(config);
429 auto callee = CreatePeerConnectionWithAudioVideo(config);
430
431 auto offer = caller->CreateOffer();
432 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
433
434 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
435}
Steve Anton71182f42018-01-19 14:59:54 -0800436TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700437 FailToSetLocalAnswerWithNoFingerprintWhenDtlsOn) {
438 RTCConfiguration config;
439 config.enable_dtls_srtp.emplace(true);
440 auto caller = CreatePeerConnectionWithAudioVideo(config);
441 auto callee = CreatePeerConnectionWithAudioVideo(config);
442
443 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
444 auto answer = callee->CreateAnswer();
445 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
446}
Steve Anton71182f42018-01-19 14:59:54 -0800447TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700448 FailToSetRemoteAnswerWithNoFingerprintWhenDtlsOn) {
449 RTCConfiguration config;
450 config.enable_dtls_srtp.emplace(true);
451 auto caller = CreatePeerConnectionWithAudioVideo(config);
452 auto callee = CreatePeerConnectionWithAudioVideo(config);
453
454 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
455 auto answer = callee->CreateAnswerAndSetAsLocal();
456 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
457
458 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
459}
460
461// Test that an offer/answer can be exchanged when encryption is disabled.
Steve Anton71182f42018-01-19 14:59:54 -0800462TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenNoEncryption) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700463 PeerConnectionFactoryInterface::Options options;
464 options.disable_encryption = true;
465 pc_factory_->SetOptions(options);
466
467 RTCConfiguration config;
468 config.enable_dtls_srtp.emplace(false);
469 auto caller = CreatePeerConnectionWithAudioVideo(config);
470 auto callee = CreatePeerConnectionWithAudioVideo(config);
471
472 auto offer = caller->CreateOfferAndSetAsLocal();
473 ASSERT_TRUE(offer);
474 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
475
476 auto answer = callee->CreateAnswerAndSetAsLocal();
477 ASSERT_TRUE(answer);
478 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
479}
480
481// Tests that a DTLS call can be established when the certificate is specified
482// in the PeerConnection config and no certificate generator is specified.
Steve Anton71182f42018-01-19 14:59:54 -0800483TEST_P(PeerConnectionCryptoTest,
Steve Anton6b63cd52017-10-06 11:20:31 -0700484 ExchangeOfferAnswerWhenDtlsCertificateInConfig) {
485 RTCConfiguration caller_config;
486 caller_config.enable_dtls_srtp.emplace(true);
487 caller_config.certificates.push_back(
488 FakeRTCCertificateGenerator::GenerateCertificate());
489 auto caller = CreatePeerConnectionWithAudioVideo(caller_config);
490
491 RTCConfiguration callee_config;
492 callee_config.enable_dtls_srtp.emplace(true);
493 callee_config.certificates.push_back(
494 FakeRTCCertificateGenerator::GenerateCertificate());
495 auto callee = CreatePeerConnectionWithAudioVideo(callee_config);
496
497 auto offer = caller->CreateOfferAndSetAsLocal();
498 ASSERT_TRUE(offer);
499 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
500
501 auto answer = callee->CreateAnswerAndSetAsLocal();
502 ASSERT_TRUE(answer);
503 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
504}
505
506// The following parameterized test verifies that CreateOffer/CreateAnswer
507// returns successfully (or with failure if the underlying certificate generator
508// fails) no matter when the DTLS certificate is generated. If multiple
509// CreateOffer/CreateAnswer calls are made while waiting for the certificate,
510// they all finish after the certificate is generated.
511
Steve Anton6b63cd52017-10-06 11:20:31 -0700512// Whether the certificate will be generated before calling CreateOffer or
513// while CreateOffer is executing.
514enum class CertGenTime { kBefore, kDuring };
515std::ostream& operator<<(std::ostream& out, CertGenTime value) {
516 switch (value) {
517 case CertGenTime::kBefore:
518 return out << "before";
519 case CertGenTime::kDuring:
520 return out << "during";
521 default:
522 return out << "unknown";
523 }
524}
525
526// Whether the fake certificate generator will produce a certificate or fail.
527enum class CertGenResult { kSucceed, kFail };
528std::ostream& operator<<(std::ostream& out, CertGenResult value) {
529 switch (value) {
530 case CertGenResult::kSucceed:
531 return out << "succeed";
532 case CertGenResult::kFail:
533 return out << "fail";
534 default:
535 return out << "unknown";
536 }
537}
538
Steve Anton71182f42018-01-19 14:59:54 -0800539class PeerConnectionCryptoDtlsCertGenTest
540 : public PeerConnectionCryptoBaseTest,
541 public ::testing::WithParamInterface<std::tuple<SdpSemantics,
542 SdpType,
543 CertGenTime,
544 CertGenResult,
545 size_t>> {
Steve Anton6b63cd52017-10-06 11:20:31 -0700546 protected:
Steve Anton71182f42018-01-19 14:59:54 -0800547 PeerConnectionCryptoDtlsCertGenTest()
548 : PeerConnectionCryptoBaseTest(std::get<0>(GetParam())) {
549 sdp_type_ = std::get<1>(GetParam());
550 cert_gen_time_ = std::get<2>(GetParam());
551 cert_gen_result_ = std::get<3>(GetParam());
552 concurrent_calls_ = std::get<4>(GetParam());
Steve Anton6b63cd52017-10-06 11:20:31 -0700553 }
554
555 SdpType sdp_type_;
556 CertGenTime cert_gen_time_;
557 CertGenResult cert_gen_result_;
558 size_t concurrent_calls_;
559};
560
Steve Anton71182f42018-01-19 14:59:54 -0800561TEST_P(PeerConnectionCryptoDtlsCertGenTest, TestCertificateGeneration) {
Steve Anton6b63cd52017-10-06 11:20:31 -0700562 RTCConfiguration config;
563 config.enable_dtls_srtp.emplace(true);
564 auto owned_fake_certificate_generator =
565 rtc::MakeUnique<FakeRTCCertificateGenerator>();
566 auto* fake_certificate_generator = owned_fake_certificate_generator.get();
567 fake_certificate_generator->set_should_fail(cert_gen_result_ ==
568 CertGenResult::kFail);
569 fake_certificate_generator->set_should_wait(cert_gen_time_ ==
570 CertGenTime::kDuring);
571 WrapperPtr pc;
572 if (sdp_type_ == SdpType::kOffer) {
573 pc = CreatePeerConnectionWithAudioVideo(
574 config, std::move(owned_fake_certificate_generator));
575 } else {
576 auto caller = CreatePeerConnectionWithAudioVideo(config);
577 pc = CreatePeerConnectionWithAudioVideo(
578 config, std::move(owned_fake_certificate_generator));
579 pc->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
580 }
581 if (cert_gen_time_ == CertGenTime::kBefore) {
582 ASSERT_TRUE_WAIT(fake_certificate_generator->generated_certificates() +
583 fake_certificate_generator->generated_failures() >
584 0,
585 kGenerateCertTimeout);
586 } else {
587 ASSERT_EQ(fake_certificate_generator->generated_certificates(), 0);
588 fake_certificate_generator->set_should_wait(false);
589 }
590 std::vector<rtc::scoped_refptr<MockCreateSessionDescriptionObserver>>
591 observers;
592 for (size_t i = 0; i < concurrent_calls_; i++) {
593 rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer =
594 new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>();
595 observers.push_back(observer);
596 if (sdp_type_ == SdpType::kOffer) {
597 pc->pc()->CreateOffer(observer, nullptr);
598 } else {
599 pc->pc()->CreateAnswer(observer, nullptr);
600 }
601 }
602 for (auto& observer : observers) {
603 EXPECT_TRUE_WAIT(observer->called(), 1000);
604 if (cert_gen_result_ == CertGenResult::kSucceed) {
605 EXPECT_TRUE(observer->result());
606 } else {
607 EXPECT_FALSE(observer->result());
608 }
609 }
610}
611
612INSTANTIATE_TEST_CASE_P(
Steve Anton71182f42018-01-19 14:59:54 -0800613 PeerConnectionCryptoTest,
614 PeerConnectionCryptoDtlsCertGenTest,
615 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
616 Values(SdpType::kOffer, SdpType::kAnswer),
Steve Anton6b63cd52017-10-06 11:20:31 -0700617 Values(CertGenTime::kBefore, CertGenTime::kDuring),
618 Values(CertGenResult::kSucceed, CertGenResult::kFail),
619 Values(1, 3)));
620
Steve Anton8a63f782017-10-23 13:08:53 -0700621// Test that we can create and set an answer correctly when different
622// SSL roles have been negotiated for different transports.
623// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4525
Steve Anton71182f42018-01-19 14:59:54 -0800624TEST_P(PeerConnectionCryptoTest, CreateAnswerWithDifferentSslRoles) {
Steve Anton8a63f782017-10-23 13:08:53 -0700625 auto caller = CreatePeerConnectionWithAudioVideo();
626 auto callee = CreatePeerConnectionWithAudioVideo();
627
628 RTCOfferAnswerOptions options_no_bundle;
629 options_no_bundle.use_rtp_mux = false;
630
631 // First, negotiate different SSL roles for audio and video.
632 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
633 auto answer = callee->CreateAnswer(options_no_bundle);
634
635 AudioConnectionRole(answer->description()) = cricket::CONNECTIONROLE_ACTIVE;
636 VideoConnectionRole(answer->description()) = cricket::CONNECTIONROLE_PASSIVE;
637
638 ASSERT_TRUE(
639 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
640 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
641
642 // Now create an offer in the reverse direction, and ensure the initial
643 // offerer responds with an answer with the correct SSL roles.
644 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
645 answer = caller->CreateAnswer(options_no_bundle);
646
647 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
648 AudioConnectionRole(answer->description()));
649 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
650 VideoConnectionRole(answer->description()));
651
652 ASSERT_TRUE(
653 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
654 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
655
656 // Lastly, start BUNDLE-ing on "audio", expecting that the "passive" role of
657 // audio is transferred over to video in the answer that completes the BUNDLE
658 // negotiation.
659 RTCOfferAnswerOptions options_bundle;
660 options_bundle.use_rtp_mux = true;
661
662 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
663 answer = caller->CreateAnswer(options_bundle);
664
665 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
666 AudioConnectionRole(answer->description()));
667 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
668 VideoConnectionRole(answer->description()));
669
670 ASSERT_TRUE(
671 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
672 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
673}
674
Steve Anton80dd7b52018-02-16 17:08:42 -0800675// Tests that if the DTLS fingerprint is invalid then all future calls to
676// SetLocalDescription and SetRemoteDescription will fail due to a session
677// error.
678// This is a regression test for crbug.com/800775
679TEST_P(PeerConnectionCryptoTest, SessionErrorIfFingerprintInvalid) {
680 auto callee_certificate = rtc::RTCCertificate::FromPEM(kRsaPems[0]);
681 auto other_certificate = rtc::RTCCertificate::FromPEM(kRsaPems[1]);
682
683 auto caller = CreatePeerConnectionWithAudioVideo();
684 RTCConfiguration callee_config;
685 callee_config.enable_dtls_srtp.emplace(true);
686 callee_config.certificates.push_back(callee_certificate);
687 auto callee = CreatePeerConnectionWithAudioVideo(callee_config);
688
689 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
690
691 // Create an invalid answer with the other certificate's fingerprint.
692 auto invalid_answer = callee->CreateAnswer();
693 auto* audio_content =
694 cricket::GetFirstAudioContent(invalid_answer->description());
695 ASSERT_TRUE(audio_content);
696 auto* audio_transport_info =
697 invalid_answer->description()->GetTransportInfoByName(
698 audio_content->name);
699 ASSERT_TRUE(audio_transport_info);
700 audio_transport_info->description.identity_fingerprint.reset(
701 rtc::SSLFingerprint::CreateFromCertificate(other_certificate));
702
703 // Set the invalid answer and expect a fingerprint error.
704 std::string error;
705 ASSERT_FALSE(callee->SetLocalDescription(std::move(invalid_answer), &error));
706 EXPECT_PRED_FORMAT2(AssertStringContains, error,
707 "Local fingerprint does not match identity.");
708
709 // Make sure that setting a valid remote offer or local answer also fails now.
710 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
711 EXPECT_PRED_FORMAT2(AssertStringContains, error,
712 "Session error code: ERROR_CONTENT.");
713 ASSERT_FALSE(callee->SetLocalDescription(callee->CreateAnswer(), &error));
714 EXPECT_PRED_FORMAT2(AssertStringContains, error,
715 "Session error code: ERROR_CONTENT.");
716}
717
Steve Anton71182f42018-01-19 14:59:54 -0800718INSTANTIATE_TEST_CASE_P(PeerConnectionCryptoTest,
719 PeerConnectionCryptoTest,
720 Values(SdpSemantics::kPlanB,
721 SdpSemantics::kUnifiedPlan));
722
Steve Anton6b63cd52017-10-06 11:20:31 -0700723} // namespace webrtc