xref: /aosp_15_r20/external/webrtc/p2p/base/transport_description_factory_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2012 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/transport_description_factory.h"
12 
13 #include <stddef.h>
14 
15 #include <memory>
16 #include <string>
17 #include <vector>
18 
19 #include "absl/strings/string_view.h"
20 #include "p2p/base/p2p_constants.h"
21 #include "p2p/base/transport_description.h"
22 #include "rtc_base/copy_on_write_buffer.h"
23 #include "rtc_base/fake_ssl_identity.h"
24 #include "rtc_base/ssl_certificate.h"
25 #include "rtc_base/ssl_fingerprint.h"
26 #include "rtc_base/ssl_identity.h"
27 #include "test/gmock.h"
28 #include "test/gtest.h"
29 #include "test/scoped_key_value_config.h"
30 
31 using cricket::TransportDescription;
32 using cricket::TransportDescriptionFactory;
33 using cricket::TransportOptions;
34 using ::testing::Contains;
35 using ::testing::Not;
36 
37 class TransportDescriptionFactoryTest : public ::testing::Test {
38  public:
TransportDescriptionFactoryTest()39   TransportDescriptionFactoryTest()
40       : ice_credentials_({}),
41         f1_(field_trials_),
42         f2_(field_trials_),
43         cert1_(rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
44             new rtc::FakeSSLIdentity("User1")))),
45         cert2_(rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
46             new rtc::FakeSSLIdentity("User2")))) {}
47 
CheckDesc(const TransportDescription * desc,absl::string_view opt,absl::string_view ice_ufrag,absl::string_view ice_pwd,absl::string_view dtls_alg)48   void CheckDesc(const TransportDescription* desc,
49                  absl::string_view opt,
50                  absl::string_view ice_ufrag,
51                  absl::string_view ice_pwd,
52                  absl::string_view dtls_alg) {
53     ASSERT_TRUE(desc != NULL);
54     EXPECT_EQ(!opt.empty(), desc->HasOption(opt));
55     if (ice_ufrag.empty() && ice_pwd.empty()) {
56       EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
57                 desc->ice_ufrag.size());
58       EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
59                 desc->ice_pwd.size());
60     } else {
61       EXPECT_EQ(ice_ufrag, desc->ice_ufrag);
62       EXPECT_EQ(ice_pwd, desc->ice_pwd);
63     }
64     if (dtls_alg.empty()) {
65       EXPECT_TRUE(desc->identity_fingerprint.get() == NULL);
66     } else {
67       ASSERT_TRUE(desc->identity_fingerprint.get() != NULL);
68       EXPECT_EQ(desc->identity_fingerprint->algorithm, dtls_alg);
69       EXPECT_GT(desc->identity_fingerprint->digest.size(), 0U);
70     }
71   }
72 
73   // This test ice restart by doing two offer answer exchanges. On the second
74   // exchange ice is restarted. The test verifies that the ufrag and password
75   // in the offer and answer is changed.
76   // If `dtls` is true, the test verifies that the finger print is not changed.
TestIceRestart(bool dtls)77   void TestIceRestart(bool dtls) {
78     SetDtls(dtls);
79     cricket::TransportOptions options;
80     // The initial offer / answer exchange.
81     std::unique_ptr<TransportDescription> offer =
82         f1_.CreateOffer(options, NULL, &ice_credentials_);
83     std::unique_ptr<TransportDescription> answer =
84         f2_.CreateAnswer(offer.get(), options, true, NULL, &ice_credentials_);
85 
86     // Create an updated offer where we restart ice.
87     options.ice_restart = true;
88     std::unique_ptr<TransportDescription> restart_offer =
89         f1_.CreateOffer(options, offer.get(), &ice_credentials_);
90 
91     VerifyUfragAndPasswordChanged(dtls, offer.get(), restart_offer.get());
92 
93     // Create a new answer. The transport ufrag and password is changed since
94     // |options.ice_restart == true|
95     std::unique_ptr<TransportDescription> restart_answer = f2_.CreateAnswer(
96         restart_offer.get(), options, true, answer.get(), &ice_credentials_);
97     ASSERT_TRUE(restart_answer.get() != NULL);
98 
99     VerifyUfragAndPasswordChanged(dtls, answer.get(), restart_answer.get());
100   }
101 
VerifyUfragAndPasswordChanged(bool dtls,const TransportDescription * org_desc,const TransportDescription * restart_desc)102   void VerifyUfragAndPasswordChanged(bool dtls,
103                                      const TransportDescription* org_desc,
104                                      const TransportDescription* restart_desc) {
105     EXPECT_NE(org_desc->ice_pwd, restart_desc->ice_pwd);
106     EXPECT_NE(org_desc->ice_ufrag, restart_desc->ice_ufrag);
107     EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
108               restart_desc->ice_ufrag.size());
109     EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
110               restart_desc->ice_pwd.size());
111     // If DTLS is enabled, make sure the finger print is unchanged.
112     if (dtls) {
113       EXPECT_FALSE(
114           org_desc->identity_fingerprint->GetRfc4572Fingerprint().empty());
115       EXPECT_EQ(org_desc->identity_fingerprint->GetRfc4572Fingerprint(),
116                 restart_desc->identity_fingerprint->GetRfc4572Fingerprint());
117     }
118   }
119 
TestIceRenomination(bool dtls)120   void TestIceRenomination(bool dtls) {
121     SetDtls(dtls);
122 
123     cricket::TransportOptions options;
124     // The initial offer / answer exchange.
125     std::unique_ptr<TransportDescription> offer =
126         f1_.CreateOffer(options, nullptr, &ice_credentials_);
127     ASSERT_TRUE(offer);
128     EXPECT_THAT(offer->transport_options, Not(Contains("renomination")));
129 
130     std::unique_ptr<TransportDescription> answer = f2_.CreateAnswer(
131         offer.get(), options, true, nullptr, &ice_credentials_);
132     ASSERT_TRUE(answer);
133     EXPECT_THAT(answer->transport_options, Not(Contains("renomination")));
134 
135     options.enable_ice_renomination = true;
136     std::unique_ptr<TransportDescription> renomination_offer =
137         f1_.CreateOffer(options, offer.get(), &ice_credentials_);
138     ASSERT_TRUE(renomination_offer);
139     EXPECT_THAT(renomination_offer->transport_options,
140                 Contains("renomination"));
141 
142     std::unique_ptr<TransportDescription> renomination_answer =
143         f2_.CreateAnswer(renomination_offer.get(), options, true, answer.get(),
144                          &ice_credentials_);
145     ASSERT_TRUE(renomination_answer);
146     EXPECT_THAT(renomination_answer->transport_options,
147                 Contains("renomination"));
148   }
149 
150  protected:
SetDtls(bool dtls)151   void SetDtls(bool dtls) {
152     if (dtls) {
153       f1_.set_secure(cricket::SEC_ENABLED);
154       f2_.set_secure(cricket::SEC_ENABLED);
155       f1_.set_certificate(cert1_);
156       f2_.set_certificate(cert2_);
157     } else {
158       f1_.set_secure(cricket::SEC_DISABLED);
159       f2_.set_secure(cricket::SEC_DISABLED);
160     }
161   }
162 
163   webrtc::test::ScopedKeyValueConfig field_trials_;
164   cricket::IceCredentialsIterator ice_credentials_;
165   TransportDescriptionFactory f1_;
166   TransportDescriptionFactory f2_;
167 
168   rtc::scoped_refptr<rtc::RTCCertificate> cert1_;
169   rtc::scoped_refptr<rtc::RTCCertificate> cert2_;
170 };
171 
TEST_F(TransportDescriptionFactoryTest,TestOfferDefault)172 TEST_F(TransportDescriptionFactoryTest, TestOfferDefault) {
173   std::unique_ptr<TransportDescription> desc =
174       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
175   CheckDesc(desc.get(), "", "", "", "");
176 }
177 
TEST_F(TransportDescriptionFactoryTest,TestOfferDtls)178 TEST_F(TransportDescriptionFactoryTest, TestOfferDtls) {
179   f1_.set_secure(cricket::SEC_ENABLED);
180   f1_.set_certificate(cert1_);
181   std::string digest_alg;
182   ASSERT_TRUE(
183       cert1_->GetSSLCertificate().GetSignatureDigestAlgorithm(&digest_alg));
184   std::unique_ptr<TransportDescription> desc =
185       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
186   CheckDesc(desc.get(), "", "", "", digest_alg);
187   // Ensure it also works with SEC_REQUIRED.
188   f1_.set_secure(cricket::SEC_REQUIRED);
189   desc = f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
190   CheckDesc(desc.get(), "", "", "", digest_alg);
191 }
192 
193 // Test generating an offer with DTLS fails with no identity.
TEST_F(TransportDescriptionFactoryTest,TestOfferDtlsWithNoIdentity)194 TEST_F(TransportDescriptionFactoryTest, TestOfferDtlsWithNoIdentity) {
195   f1_.set_secure(cricket::SEC_ENABLED);
196   std::unique_ptr<TransportDescription> desc =
197       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
198   ASSERT_TRUE(desc.get() == NULL);
199 }
200 
201 // Test updating an offer with DTLS to pick ICE.
202 // The ICE credentials should stay the same in the new offer.
TEST_F(TransportDescriptionFactoryTest,TestOfferDtlsReofferDtls)203 TEST_F(TransportDescriptionFactoryTest, TestOfferDtlsReofferDtls) {
204   f1_.set_secure(cricket::SEC_ENABLED);
205   f1_.set_certificate(cert1_);
206   std::string digest_alg;
207   ASSERT_TRUE(
208       cert1_->GetSSLCertificate().GetSignatureDigestAlgorithm(&digest_alg));
209   std::unique_ptr<TransportDescription> old_desc =
210       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
211   ASSERT_TRUE(old_desc.get() != NULL);
212   std::unique_ptr<TransportDescription> desc =
213       f1_.CreateOffer(TransportOptions(), old_desc.get(), &ice_credentials_);
214   CheckDesc(desc.get(), "", old_desc->ice_ufrag, old_desc->ice_pwd, digest_alg);
215 }
216 
TEST_F(TransportDescriptionFactoryTest,TestAnswerDefault)217 TEST_F(TransportDescriptionFactoryTest, TestAnswerDefault) {
218   std::unique_ptr<TransportDescription> offer =
219       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
220   ASSERT_TRUE(offer.get() != NULL);
221   std::unique_ptr<TransportDescription> desc = f2_.CreateAnswer(
222       offer.get(), TransportOptions(), true, NULL, &ice_credentials_);
223   CheckDesc(desc.get(), "", "", "", "");
224   desc = f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL,
225                           &ice_credentials_);
226   CheckDesc(desc.get(), "", "", "", "");
227 }
228 
229 // Test that we can update an answer properly; ICE credentials shouldn't change.
TEST_F(TransportDescriptionFactoryTest,TestReanswer)230 TEST_F(TransportDescriptionFactoryTest, TestReanswer) {
231   std::unique_ptr<TransportDescription> offer =
232       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
233   ASSERT_TRUE(offer.get() != NULL);
234   std::unique_ptr<TransportDescription> old_desc = f2_.CreateAnswer(
235       offer.get(), TransportOptions(), true, NULL, &ice_credentials_);
236   ASSERT_TRUE(old_desc.get() != NULL);
237   std::unique_ptr<TransportDescription> desc = f2_.CreateAnswer(
238       offer.get(), TransportOptions(), true, old_desc.get(), &ice_credentials_);
239   ASSERT_TRUE(desc.get() != NULL);
240   CheckDesc(desc.get(), "", old_desc->ice_ufrag, old_desc->ice_pwd, "");
241 }
242 
243 // Test that we handle answering an offer with DTLS with no DTLS.
TEST_F(TransportDescriptionFactoryTest,TestAnswerDtlsToNoDtls)244 TEST_F(TransportDescriptionFactoryTest, TestAnswerDtlsToNoDtls) {
245   f1_.set_secure(cricket::SEC_ENABLED);
246   f1_.set_certificate(cert1_);
247   std::unique_ptr<TransportDescription> offer =
248       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
249   ASSERT_TRUE(offer.get() != NULL);
250   std::unique_ptr<TransportDescription> desc = f2_.CreateAnswer(
251       offer.get(), TransportOptions(), true, NULL, &ice_credentials_);
252   CheckDesc(desc.get(), "", "", "", "");
253 }
254 
255 // Test that we handle answering an offer without DTLS if we have DTLS enabled,
256 // but fail if we require DTLS.
TEST_F(TransportDescriptionFactoryTest,TestAnswerNoDtlsToDtls)257 TEST_F(TransportDescriptionFactoryTest, TestAnswerNoDtlsToDtls) {
258   f2_.set_secure(cricket::SEC_ENABLED);
259   f2_.set_certificate(cert2_);
260   std::unique_ptr<TransportDescription> offer =
261       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
262   ASSERT_TRUE(offer.get() != NULL);
263   std::unique_ptr<TransportDescription> desc = f2_.CreateAnswer(
264       offer.get(), TransportOptions(), true, NULL, &ice_credentials_);
265   CheckDesc(desc.get(), "", "", "", "");
266   f2_.set_secure(cricket::SEC_REQUIRED);
267   desc = f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL,
268                           &ice_credentials_);
269   ASSERT_TRUE(desc.get() == NULL);
270 }
271 
272 // Test that we handle answering an DTLS offer with DTLS, both if we have
273 // DTLS enabled and required.
TEST_F(TransportDescriptionFactoryTest,TestAnswerDtlsToDtls)274 TEST_F(TransportDescriptionFactoryTest, TestAnswerDtlsToDtls) {
275   f1_.set_secure(cricket::SEC_ENABLED);
276   f1_.set_certificate(cert1_);
277 
278   f2_.set_secure(cricket::SEC_ENABLED);
279   f2_.set_certificate(cert2_);
280   // f2_ produces the answer that is being checked in this test, so the
281   // answer must contain fingerprint lines with cert2_'s digest algorithm.
282   std::string digest_alg2;
283   ASSERT_TRUE(
284       cert2_->GetSSLCertificate().GetSignatureDigestAlgorithm(&digest_alg2));
285 
286   std::unique_ptr<TransportDescription> offer =
287       f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
288   ASSERT_TRUE(offer.get() != NULL);
289   std::unique_ptr<TransportDescription> desc = f2_.CreateAnswer(
290       offer.get(), TransportOptions(), true, NULL, &ice_credentials_);
291   CheckDesc(desc.get(), "", "", "", digest_alg2);
292   f2_.set_secure(cricket::SEC_REQUIRED);
293   desc = f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL,
294                           &ice_credentials_);
295   CheckDesc(desc.get(), "", "", "", digest_alg2);
296 }
297 
298 // Test that ice ufrag and password is changed in an updated offer and answer
299 // if `TransportDescriptionOptions::ice_restart` is true.
TEST_F(TransportDescriptionFactoryTest,TestIceRestart)300 TEST_F(TransportDescriptionFactoryTest, TestIceRestart) {
301   TestIceRestart(false);
302 }
303 
304 // Test that ice ufrag and password is changed in an updated offer and answer
305 // if `TransportDescriptionOptions::ice_restart` is true and DTLS is enabled.
TEST_F(TransportDescriptionFactoryTest,TestIceRestartWithDtls)306 TEST_F(TransportDescriptionFactoryTest, TestIceRestartWithDtls) {
307   TestIceRestart(true);
308 }
309 
310 // Test that ice renomination is set in an updated offer and answer
311 // if `TransportDescriptionOptions::enable_ice_renomination` is true.
TEST_F(TransportDescriptionFactoryTest,TestIceRenomination)312 TEST_F(TransportDescriptionFactoryTest, TestIceRenomination) {
313   TestIceRenomination(false);
314 }
315 
316 // Test that ice renomination is set in an updated offer and answer
317 // if `TransportDescriptionOptions::enable_ice_renomination` is true and DTLS
318 // is enabled.
TEST_F(TransportDescriptionFactoryTest,TestIceRenominationWithDtls)319 TEST_F(TransportDescriptionFactoryTest, TestIceRenominationWithDtls) {
320   TestIceRenomination(true);
321 }
322 
323 // Test that offers and answers have ice-option:trickle.
TEST_F(TransportDescriptionFactoryTest,AddsTrickleIceOption)324 TEST_F(TransportDescriptionFactoryTest, AddsTrickleIceOption) {
325   cricket::TransportOptions options;
326   std::unique_ptr<TransportDescription> offer =
327       f1_.CreateOffer(options, nullptr, &ice_credentials_);
328   EXPECT_TRUE(offer->HasOption("trickle"));
329   std::unique_ptr<TransportDescription> answer =
330       f2_.CreateAnswer(offer.get(), options, true, nullptr, &ice_credentials_);
331   EXPECT_TRUE(answer->HasOption("trickle"));
332 }
333 
334 // Test CreateOffer with IceCredentialsIterator.
TEST_F(TransportDescriptionFactoryTest,CreateOfferIceCredentialsIterator)335 TEST_F(TransportDescriptionFactoryTest, CreateOfferIceCredentialsIterator) {
336   std::vector<cricket::IceParameters> credentials = {
337       cricket::IceParameters("kalle", "anka", false)};
338   cricket::IceCredentialsIterator credentialsIterator(credentials);
339   cricket::TransportOptions options;
340   std::unique_ptr<TransportDescription> offer =
341       f1_.CreateOffer(options, nullptr, &credentialsIterator);
342   EXPECT_EQ(offer->GetIceParameters().ufrag, credentials[0].ufrag);
343   EXPECT_EQ(offer->GetIceParameters().pwd, credentials[0].pwd);
344 }
345 
346 // Test CreateAnswer with IceCredentialsIterator.
TEST_F(TransportDescriptionFactoryTest,CreateAnswerIceCredentialsIterator)347 TEST_F(TransportDescriptionFactoryTest, CreateAnswerIceCredentialsIterator) {
348   cricket::TransportOptions options;
349   std::unique_ptr<TransportDescription> offer =
350       f1_.CreateOffer(options, nullptr, &ice_credentials_);
351 
352   std::vector<cricket::IceParameters> credentials = {
353       cricket::IceParameters("kalle", "anka", false)};
354   cricket::IceCredentialsIterator credentialsIterator(credentials);
355   std::unique_ptr<TransportDescription> answer = f1_.CreateAnswer(
356       offer.get(), options, false, nullptr, &credentialsIterator);
357   EXPECT_EQ(answer->GetIceParameters().ufrag, credentials[0].ufrag);
358   EXPECT_EQ(answer->GetIceParameters().pwd, credentials[0].pwd);
359 }
360 
TEST_F(TransportDescriptionFactoryTest,CreateAnswerToDtlsActpassOffer)361 TEST_F(TransportDescriptionFactoryTest, CreateAnswerToDtlsActpassOffer) {
362   f1_.set_secure(cricket::SEC_ENABLED);
363   f1_.set_certificate(cert1_);
364 
365   f2_.set_secure(cricket::SEC_ENABLED);
366   f2_.set_certificate(cert2_);
367   cricket::TransportOptions options;
368   std::unique_ptr<TransportDescription> offer =
369       f1_.CreateOffer(options, nullptr, &ice_credentials_);
370 
371   std::unique_ptr<TransportDescription> answer =
372       f2_.CreateAnswer(offer.get(), options, false, nullptr, &ice_credentials_);
373   EXPECT_EQ(answer->connection_role, cricket::CONNECTIONROLE_ACTIVE);
374 }
375 
TEST_F(TransportDescriptionFactoryTest,CreateAnswerToDtlsActiveOffer)376 TEST_F(TransportDescriptionFactoryTest, CreateAnswerToDtlsActiveOffer) {
377   f1_.set_secure(cricket::SEC_ENABLED);
378   f1_.set_certificate(cert1_);
379 
380   f2_.set_secure(cricket::SEC_ENABLED);
381   f2_.set_certificate(cert2_);
382   cricket::TransportOptions options;
383   std::unique_ptr<TransportDescription> offer =
384       f1_.CreateOffer(options, nullptr, &ice_credentials_);
385   offer->connection_role = cricket::CONNECTIONROLE_ACTIVE;
386 
387   std::unique_ptr<TransportDescription> answer =
388       f2_.CreateAnswer(offer.get(), options, false, nullptr, &ice_credentials_);
389   EXPECT_EQ(answer->connection_role, cricket::CONNECTIONROLE_PASSIVE);
390 }
391 
TEST_F(TransportDescriptionFactoryTest,CreateAnswerToDtlsPassiveOffer)392 TEST_F(TransportDescriptionFactoryTest, CreateAnswerToDtlsPassiveOffer) {
393   f1_.set_secure(cricket::SEC_ENABLED);
394   f1_.set_certificate(cert1_);
395 
396   f2_.set_secure(cricket::SEC_ENABLED);
397   f2_.set_certificate(cert2_);
398   cricket::TransportOptions options;
399   std::unique_ptr<TransportDescription> offer =
400       f1_.CreateOffer(options, nullptr, &ice_credentials_);
401   offer->connection_role = cricket::CONNECTIONROLE_PASSIVE;
402 
403   std::unique_ptr<TransportDescription> answer =
404       f2_.CreateAnswer(offer.get(), options, false, nullptr, &ice_credentials_);
405   EXPECT_EQ(answer->connection_role, cricket::CONNECTIONROLE_ACTIVE);
406 }
407