blob: 0f5499509ba9d2b889b28a310236d562967adcf3 [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
11#include "p2p/base/fakeportallocator.h"
12#include "pc/mediasession.h"
13#include "pc/peerconnectionwrapper.h"
14#include "pc/sdputils.h"
15#ifdef WEBRTC_ANDROID
16#include "pc/test/androidtestinitializer.h"
17#endif
18#include "pc/test/fakeaudiocapturemodule.h"
19#include "pc/test/fakertccertificategenerator.h"
20#include "rtc_base/gunit.h"
21#include "rtc_base/ptr_util.h"
22#include "rtc_base/virtualsocketserver.h"
23
24namespace webrtc {
25
26using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
27using ::testing::Values;
28using ::testing::Combine;
29
30constexpr int kGenerateCertTimeout = 1000;
31
32class PeerConnectionCryptoUnitTest : public ::testing::Test {
33 protected:
34 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
35
36 PeerConnectionCryptoUnitTest()
37 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
38#ifdef WEBRTC_ANDROID
39 InitializeAndroidObjects();
40#endif
41 pc_factory_ = CreatePeerConnectionFactory(
42 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
43 FakeAudioCaptureModule::Create(), nullptr, nullptr);
44 }
45
46 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
47 return CreatePeerConnection(config, nullptr);
48 }
49
50 WrapperPtr CreatePeerConnection(
51 const RTCConfiguration& config,
52 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_gen) {
53 auto fake_port_allocator = rtc::MakeUnique<cricket::FakePortAllocator>(
54 rtc::Thread::Current(), nullptr);
55 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
56 auto pc = pc_factory_->CreatePeerConnection(
57 config, std::move(fake_port_allocator), std::move(cert_gen),
58 observer.get());
59 if (!pc) {
60 return nullptr;
61 }
62
63 return rtc::MakeUnique<PeerConnectionWrapper>(pc_factory_, pc,
64 std::move(observer));
65 }
66
67 // Accepts the same arguments as CreatePeerConnection and adds default audio
68 // and video tracks.
69 template <typename... Args>
70 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
71 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
72 if (!wrapper) {
73 return nullptr;
74 }
75 wrapper->AddAudioVideoStream("s", "a", "v");
76 return wrapper;
77 }
78
79 std::unique_ptr<rtc::VirtualSocketServer> vss_;
80 rtc::AutoSocketServerThread main_;
81 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
82};
83
84SdpContentPredicate HaveDtlsFingerprint() {
85 return [](const cricket::ContentInfo* content,
86 const cricket::TransportInfo* transport) {
87 return transport->description.identity_fingerprint != nullptr;
88 };
89}
90
91SdpContentPredicate HaveSdesCryptos() {
92 return [](const cricket::ContentInfo* content,
93 const cricket::TransportInfo* transport) {
94 const auto* media_desc =
95 static_cast<const cricket::MediaContentDescription*>(
96 content->description);
97 return !media_desc->cryptos().empty();
98 };
99}
100
101SdpContentPredicate HaveProtocol(const std::string& protocol) {
102 return [protocol](const cricket::ContentInfo* content,
103 const cricket::TransportInfo* transport) {
104 const auto* media_desc =
105 static_cast<const cricket::MediaContentDescription*>(
106 content->description);
107 return media_desc->protocol() == protocol;
108 };
109}
110
111SdpContentPredicate HaveSdesGcmCryptos(size_t num_crypto_suites) {
112 return [num_crypto_suites](const cricket::ContentInfo* content,
113 const cricket::TransportInfo* transport) {
114 const auto* media_desc =
115 static_cast<const cricket::MediaContentDescription*>(
116 content->description);
117 if (media_desc->cryptos().size() != num_crypto_suites) {
118 return false;
119 }
120 const cricket::CryptoParams first_params = media_desc->cryptos()[0];
121 return first_params.key_params.size() == 67U &&
122 first_params.cipher_suite == "AEAD_AES_256_GCM";
123 };
124}
125
126SdpContentMutator RemoveSdesCryptos() {
127 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
128 auto* media_desc =
129 static_cast<cricket::MediaContentDescription*>(content->description);
130 media_desc->set_cryptos({});
131 };
132}
133
134SdpContentMutator RemoveDtlsFingerprint() {
135 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
136 transport->description.identity_fingerprint.reset();
137 };
138}
139
140// When DTLS is enabled, the SDP offer/answer should have a DTLS fingerprint and
141// no SDES cryptos.
142TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInOfferWhenDtlsEnabled) {
143 RTCConfiguration config;
144 config.enable_dtls_srtp.emplace(true);
145 auto caller = CreatePeerConnectionWithAudioVideo(config);
146
147 auto offer = caller->CreateOffer();
148 ASSERT_TRUE(offer);
149
150 ASSERT_FALSE(offer->description()->contents().empty());
151 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), offer->description()));
152 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description()));
153 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
154 offer->description()));
155}
156TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInAnswerWhenDtlsEnabled) {
157 RTCConfiguration config;
158 config.enable_dtls_srtp.emplace(true);
159 auto caller = CreatePeerConnectionWithAudioVideo(config);
160 auto callee = CreatePeerConnectionWithAudioVideo(config);
161
162 callee->SetRemoteDescription(caller->CreateOffer());
163 auto answer = callee->CreateAnswer();
164 ASSERT_TRUE(answer);
165
166 ASSERT_FALSE(answer->description()->contents().empty());
167 EXPECT_TRUE(SdpContentsAll(HaveDtlsFingerprint(), answer->description()));
168 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description()));
169 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolDtlsSavpf),
170 answer->description()));
171}
172
173// When DTLS is disabled, the SDP offer/answer should include SDES cryptos and
174// should not have a DTLS fingerprint.
175TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInOfferWhenDtlsDisabled) {
176 RTCConfiguration config;
177 config.enable_dtls_srtp.emplace(false);
178 auto caller = CreatePeerConnectionWithAudioVideo(config);
179
180 auto offer = caller->CreateOffer();
181 ASSERT_TRUE(offer);
182
183 ASSERT_FALSE(offer->description()->contents().empty());
184 EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), offer->description()));
185 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description()));
186 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf),
187 offer->description()));
188}
189TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInAnswerWhenDtlsDisabled) {
190 RTCConfiguration config;
191 config.enable_dtls_srtp.emplace(false);
192 auto caller = CreatePeerConnectionWithAudioVideo(config);
193 auto callee = CreatePeerConnectionWithAudioVideo(config);
194
195 callee->SetRemoteDescription(caller->CreateOffer());
196 auto answer = callee->CreateAnswer();
197 ASSERT_TRUE(answer);
198
199 ASSERT_FALSE(answer->description()->contents().empty());
200 EXPECT_TRUE(SdpContentsAll(HaveSdesCryptos(), answer->description()));
201 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description()));
202 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf),
203 answer->description()));
204}
205
206// When encryption is disabled, the SDP offer/answer should have neither a DTLS
207// fingerprint nor any SDES crypto options.
208TEST_F(PeerConnectionCryptoUnitTest,
209 CorrectCryptoInOfferWhenEncryptionDisabled) {
210 PeerConnectionFactoryInterface::Options options;
211 options.disable_encryption = true;
212 pc_factory_->SetOptions(options);
213
214 RTCConfiguration config;
215 config.enable_dtls_srtp.emplace(false);
216 auto caller = CreatePeerConnectionWithAudioVideo(config);
217
218 auto offer = caller->CreateOffer();
219 ASSERT_TRUE(offer);
220
221 ASSERT_FALSE(offer->description()->contents().empty());
222 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), offer->description()));
223 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), offer->description()));
224 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf),
225 offer->description()));
226}
227TEST_F(PeerConnectionCryptoUnitTest,
228 CorrectCryptoInAnswerWhenEncryptionDisabled) {
229 PeerConnectionFactoryInterface::Options options;
230 options.disable_encryption = true;
231 pc_factory_->SetOptions(options);
232
233 RTCConfiguration config;
234 config.enable_dtls_srtp.emplace(false);
235 auto caller = CreatePeerConnectionWithAudioVideo(config);
236 auto callee = CreatePeerConnectionWithAudioVideo(config);
237
238 callee->SetRemoteDescription(caller->CreateOffer());
239 auto answer = callee->CreateAnswer();
240 ASSERT_TRUE(answer);
241
242 ASSERT_FALSE(answer->description()->contents().empty());
243 EXPECT_TRUE(SdpContentsNone(HaveSdesCryptos(), answer->description()));
244 EXPECT_TRUE(SdpContentsNone(HaveDtlsFingerprint(), answer->description()));
245 EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf),
246 answer->description()));
247}
248
249// When DTLS is disabled and GCM cipher suites are enabled, the SDP offer/answer
250// should have the correct ciphers in the SDES crypto options.
251// With GCM cipher suites enabled, there will be 3 cryptos in the offer and 1
252// in the answer.
253TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInOfferWithSdesAndGcm) {
254 PeerConnectionFactoryInterface::Options options;
255 options.crypto_options.enable_gcm_crypto_suites = true;
256 pc_factory_->SetOptions(options);
257
258 RTCConfiguration config;
259 config.enable_dtls_srtp.emplace(false);
260 auto caller = CreatePeerConnectionWithAudioVideo(config);
261
262 auto offer = caller->CreateOffer();
263 ASSERT_TRUE(offer);
264
265 ASSERT_FALSE(offer->description()->contents().empty());
266 EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description()));
267}
268TEST_F(PeerConnectionCryptoUnitTest, CorrectCryptoInAnswerWithSdesAndGcm) {
269 PeerConnectionFactoryInterface::Options options;
270 options.crypto_options.enable_gcm_crypto_suites = true;
271 pc_factory_->SetOptions(options);
272
273 RTCConfiguration config;
274 config.enable_dtls_srtp.emplace(false);
275 auto caller = CreatePeerConnectionWithAudioVideo(config);
276 auto callee = CreatePeerConnectionWithAudioVideo(config);
277
278 callee->SetRemoteDescription(caller->CreateOffer());
279 auto answer = callee->CreateAnswer();
280 ASSERT_TRUE(answer);
281
282 ASSERT_FALSE(answer->description()->contents().empty());
283 EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(1), answer->description()));
284}
285
286TEST_F(PeerConnectionCryptoUnitTest, CanSetSdesGcmRemoteOfferAndLocalAnswer) {
287 PeerConnectionFactoryInterface::Options options;
288 options.crypto_options.enable_gcm_crypto_suites = true;
289 pc_factory_->SetOptions(options);
290
291 RTCConfiguration config;
292 config.enable_dtls_srtp.emplace(false);
293 auto caller = CreatePeerConnectionWithAudioVideo(config);
294 auto callee = CreatePeerConnectionWithAudioVideo(config);
295
296 auto offer = caller->CreateOffer();
297 ASSERT_TRUE(offer);
298 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
299
300 auto answer = callee->CreateAnswer();
301 ASSERT_TRUE(answer);
302 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
303}
304
305// The following group tests that two PeerConnections can successfully exchange
306// an offer/answer when DTLS is off and that they will refuse any offer/answer
307// applied locally/remotely if it does not include SDES cryptos.
308TEST_F(PeerConnectionCryptoUnitTest, ExchangeOfferAnswerWhenSdesOn) {
309 RTCConfiguration config;
310 config.enable_dtls_srtp.emplace(false);
311 auto caller = CreatePeerConnectionWithAudioVideo(config);
312 auto callee = CreatePeerConnectionWithAudioVideo(config);
313
314 auto offer = caller->CreateOfferAndSetAsLocal();
315 ASSERT_TRUE(offer);
316 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
317
318 auto answer = callee->CreateAnswerAndSetAsLocal();
319 ASSERT_TRUE(answer);
320 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
321}
322TEST_F(PeerConnectionCryptoUnitTest,
323 FailToSetLocalOfferWithNoCryptosWhenSdesOn) {
324 RTCConfiguration config;
325 config.enable_dtls_srtp.emplace(false);
326 auto caller = CreatePeerConnectionWithAudioVideo(config);
327
328 auto offer = caller->CreateOffer();
329 SdpContentsForEach(RemoveSdesCryptos(), offer->description());
330
331 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
332}
333TEST_F(PeerConnectionCryptoUnitTest,
334 FailToSetRemoteOfferWithNoCryptosWhenSdesOn) {
335 RTCConfiguration config;
336 config.enable_dtls_srtp.emplace(false);
337 auto caller = CreatePeerConnectionWithAudioVideo(config);
338 auto callee = CreatePeerConnectionWithAudioVideo(config);
339
340 auto offer = caller->CreateOffer();
341 SdpContentsForEach(RemoveSdesCryptos(), offer->description());
342
343 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
344}
345TEST_F(PeerConnectionCryptoUnitTest,
346 FailToSetLocalAnswerWithNoCryptosWhenSdesOn) {
347 RTCConfiguration config;
348 config.enable_dtls_srtp.emplace(false);
349 auto caller = CreatePeerConnectionWithAudioVideo(config);
350 auto callee = CreatePeerConnectionWithAudioVideo(config);
351
352 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
353 auto answer = callee->CreateAnswer();
354 SdpContentsForEach(RemoveSdesCryptos(), answer->description());
355
356 EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
357}
358TEST_F(PeerConnectionCryptoUnitTest,
359 FailToSetRemoteAnswerWithNoCryptosWhenSdesOn) {
360 RTCConfiguration config;
361 config.enable_dtls_srtp.emplace(false);
362 auto caller = CreatePeerConnectionWithAudioVideo(config);
363 auto callee = CreatePeerConnectionWithAudioVideo(config);
364
365 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
366 auto answer = callee->CreateAnswerAndSetAsLocal();
367 SdpContentsForEach(RemoveSdesCryptos(), answer->description());
368
369 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
370}
371
372// The following group tests that two PeerConnections can successfully exchange
373// an offer/answer when DTLS is on and that they will refuse any offer/answer
374// applied locally/remotely if it does not include a DTLS fingerprint.
375TEST_F(PeerConnectionCryptoUnitTest, ExchangeOfferAnswerWhenDtlsOn) {
376 RTCConfiguration config;
377 config.enable_dtls_srtp.emplace(true);
378 auto caller = CreatePeerConnectionWithAudioVideo(config);
379 auto callee = CreatePeerConnectionWithAudioVideo(config);
380
381 auto offer = caller->CreateOfferAndSetAsLocal();
382 ASSERT_TRUE(offer);
383 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
384
385 auto answer = callee->CreateAnswerAndSetAsLocal();
386 ASSERT_TRUE(answer);
387 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
388}
389TEST_F(PeerConnectionCryptoUnitTest,
390 FailToSetLocalOfferWithNoFingerprintWhenDtlsOn) {
391 RTCConfiguration config;
392 config.enable_dtls_srtp.emplace(true);
393 auto caller = CreatePeerConnectionWithAudioVideo(config);
394
395 auto offer = caller->CreateOffer();
396 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
397
398 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
399}
400TEST_F(PeerConnectionCryptoUnitTest,
401 FailToSetRemoteOfferWithNoFingerprintWhenDtlsOn) {
402 RTCConfiguration config;
403 config.enable_dtls_srtp.emplace(true);
404 auto caller = CreatePeerConnectionWithAudioVideo(config);
405 auto callee = CreatePeerConnectionWithAudioVideo(config);
406
407 auto offer = caller->CreateOffer();
408 SdpContentsForEach(RemoveDtlsFingerprint(), offer->description());
409
410 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
411}
412TEST_F(PeerConnectionCryptoUnitTest,
413 FailToSetLocalAnswerWithNoFingerprintWhenDtlsOn) {
414 RTCConfiguration config;
415 config.enable_dtls_srtp.emplace(true);
416 auto caller = CreatePeerConnectionWithAudioVideo(config);
417 auto callee = CreatePeerConnectionWithAudioVideo(config);
418
419 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
420 auto answer = callee->CreateAnswer();
421 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
422}
423TEST_F(PeerConnectionCryptoUnitTest,
424 FailToSetRemoteAnswerWithNoFingerprintWhenDtlsOn) {
425 RTCConfiguration config;
426 config.enable_dtls_srtp.emplace(true);
427 auto caller = CreatePeerConnectionWithAudioVideo(config);
428 auto callee = CreatePeerConnectionWithAudioVideo(config);
429
430 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
431 auto answer = callee->CreateAnswerAndSetAsLocal();
432 SdpContentsForEach(RemoveDtlsFingerprint(), answer->description());
433
434 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
435}
436
437// Test that an offer/answer can be exchanged when encryption is disabled.
438TEST_F(PeerConnectionCryptoUnitTest, ExchangeOfferAnswerWhenNoEncryption) {
439 PeerConnectionFactoryInterface::Options options;
440 options.disable_encryption = true;
441 pc_factory_->SetOptions(options);
442
443 RTCConfiguration config;
444 config.enable_dtls_srtp.emplace(false);
445 auto caller = CreatePeerConnectionWithAudioVideo(config);
446 auto callee = CreatePeerConnectionWithAudioVideo(config);
447
448 auto offer = caller->CreateOfferAndSetAsLocal();
449 ASSERT_TRUE(offer);
450 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
451
452 auto answer = callee->CreateAnswerAndSetAsLocal();
453 ASSERT_TRUE(answer);
454 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
455}
456
457// Tests that a DTLS call can be established when the certificate is specified
458// in the PeerConnection config and no certificate generator is specified.
459TEST_F(PeerConnectionCryptoUnitTest,
460 ExchangeOfferAnswerWhenDtlsCertificateInConfig) {
461 RTCConfiguration caller_config;
462 caller_config.enable_dtls_srtp.emplace(true);
463 caller_config.certificates.push_back(
464 FakeRTCCertificateGenerator::GenerateCertificate());
465 auto caller = CreatePeerConnectionWithAudioVideo(caller_config);
466
467 RTCConfiguration callee_config;
468 callee_config.enable_dtls_srtp.emplace(true);
469 callee_config.certificates.push_back(
470 FakeRTCCertificateGenerator::GenerateCertificate());
471 auto callee = CreatePeerConnectionWithAudioVideo(callee_config);
472
473 auto offer = caller->CreateOfferAndSetAsLocal();
474 ASSERT_TRUE(offer);
475 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
476
477 auto answer = callee->CreateAnswerAndSetAsLocal();
478 ASSERT_TRUE(answer);
479 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
480}
481
482// The following parameterized test verifies that CreateOffer/CreateAnswer
483// returns successfully (or with failure if the underlying certificate generator
484// fails) no matter when the DTLS certificate is generated. If multiple
485// CreateOffer/CreateAnswer calls are made while waiting for the certificate,
486// they all finish after the certificate is generated.
487
488// Whether the test will call CreateOffer or CreateAnswer.
489enum class SdpType { kOffer, kAnswer };
490std::ostream& operator<<(std::ostream& out, SdpType value) {
491 switch (value) {
492 case SdpType::kOffer:
493 return out << "offer";
494 case SdpType::kAnswer:
495 return out << "answer";
496 default:
497 return out << "unknown";
498 }
499}
500
501// Whether the certificate will be generated before calling CreateOffer or
502// while CreateOffer is executing.
503enum class CertGenTime { kBefore, kDuring };
504std::ostream& operator<<(std::ostream& out, CertGenTime value) {
505 switch (value) {
506 case CertGenTime::kBefore:
507 return out << "before";
508 case CertGenTime::kDuring:
509 return out << "during";
510 default:
511 return out << "unknown";
512 }
513}
514
515// Whether the fake certificate generator will produce a certificate or fail.
516enum class CertGenResult { kSucceed, kFail };
517std::ostream& operator<<(std::ostream& out, CertGenResult value) {
518 switch (value) {
519 case CertGenResult::kSucceed:
520 return out << "succeed";
521 case CertGenResult::kFail:
522 return out << "fail";
523 default:
524 return out << "unknown";
525 }
526}
527
528class PeerConnectionCryptoDtlsCertGenUnitTest
529 : public PeerConnectionCryptoUnitTest,
530 public ::testing::WithParamInterface<
531 ::testing::tuple<SdpType, CertGenTime, CertGenResult, size_t>> {
532 protected:
533 PeerConnectionCryptoDtlsCertGenUnitTest() {
534 sdp_type_ = ::testing::get<0>(GetParam());
535 cert_gen_time_ = ::testing::get<1>(GetParam());
536 cert_gen_result_ = ::testing::get<2>(GetParam());
537 concurrent_calls_ = ::testing::get<3>(GetParam());
538 }
539
540 SdpType sdp_type_;
541 CertGenTime cert_gen_time_;
542 CertGenResult cert_gen_result_;
543 size_t concurrent_calls_;
544};
545
546TEST_P(PeerConnectionCryptoDtlsCertGenUnitTest, TestCertificateGeneration) {
547 RTCConfiguration config;
548 config.enable_dtls_srtp.emplace(true);
549 auto owned_fake_certificate_generator =
550 rtc::MakeUnique<FakeRTCCertificateGenerator>();
551 auto* fake_certificate_generator = owned_fake_certificate_generator.get();
552 fake_certificate_generator->set_should_fail(cert_gen_result_ ==
553 CertGenResult::kFail);
554 fake_certificate_generator->set_should_wait(cert_gen_time_ ==
555 CertGenTime::kDuring);
556 WrapperPtr pc;
557 if (sdp_type_ == SdpType::kOffer) {
558 pc = CreatePeerConnectionWithAudioVideo(
559 config, std::move(owned_fake_certificate_generator));
560 } else {
561 auto caller = CreatePeerConnectionWithAudioVideo(config);
562 pc = CreatePeerConnectionWithAudioVideo(
563 config, std::move(owned_fake_certificate_generator));
564 pc->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
565 }
566 if (cert_gen_time_ == CertGenTime::kBefore) {
567 ASSERT_TRUE_WAIT(fake_certificate_generator->generated_certificates() +
568 fake_certificate_generator->generated_failures() >
569 0,
570 kGenerateCertTimeout);
571 } else {
572 ASSERT_EQ(fake_certificate_generator->generated_certificates(), 0);
573 fake_certificate_generator->set_should_wait(false);
574 }
575 std::vector<rtc::scoped_refptr<MockCreateSessionDescriptionObserver>>
576 observers;
577 for (size_t i = 0; i < concurrent_calls_; i++) {
578 rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer =
579 new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>();
580 observers.push_back(observer);
581 if (sdp_type_ == SdpType::kOffer) {
582 pc->pc()->CreateOffer(observer, nullptr);
583 } else {
584 pc->pc()->CreateAnswer(observer, nullptr);
585 }
586 }
587 for (auto& observer : observers) {
588 EXPECT_TRUE_WAIT(observer->called(), 1000);
589 if (cert_gen_result_ == CertGenResult::kSucceed) {
590 EXPECT_TRUE(observer->result());
591 } else {
592 EXPECT_FALSE(observer->result());
593 }
594 }
595}
596
597INSTANTIATE_TEST_CASE_P(
598 PeerConnectionCryptoUnitTest,
599 PeerConnectionCryptoDtlsCertGenUnitTest,
600 Combine(Values(SdpType::kOffer, SdpType::kAnswer),
601 Values(CertGenTime::kBefore, CertGenTime::kDuring),
602 Values(CertGenResult::kSucceed, CertGenResult::kFail),
603 Values(1, 3)));
604
605} // namespace webrtc