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