• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
12 #include <vector>
13 
14 #include "webrtc/p2p/base/constants.h"
15 #include "webrtc/p2p/base/transportdescription.h"
16 #include "webrtc/p2p/base/transportdescriptionfactory.h"
17 #include "webrtc/base/fakesslidentity.h"
18 #include "webrtc/base/gunit.h"
19 #include "webrtc/base/ssladapter.h"
20 
21 using rtc::scoped_ptr;
22 using cricket::TransportDescriptionFactory;
23 using cricket::TransportDescription;
24 using cricket::TransportOptions;
25 
26 class TransportDescriptionFactoryTest : public testing::Test {
27  public:
TransportDescriptionFactoryTest()28   TransportDescriptionFactoryTest()
29       : cert1_(rtc::RTCCertificate::Create(
30             scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("User1")))),
31         cert2_(rtc::RTCCertificate::Create(
32             scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("User2")))) {}
33 
CheckDesc(const TransportDescription * desc,const std::string & opt,const std::string & ice_ufrag,const std::string & ice_pwd,const std::string & dtls_alg)34   void CheckDesc(const TransportDescription* desc,
35                  const std::string& opt, const std::string& ice_ufrag,
36                  const std::string& ice_pwd, const std::string& dtls_alg) {
37     ASSERT_TRUE(desc != NULL);
38     EXPECT_EQ(!opt.empty(), desc->HasOption(opt));
39     if (ice_ufrag.empty() && ice_pwd.empty()) {
40       EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
41                 desc->ice_ufrag.size());
42       EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
43                 desc->ice_pwd.size());
44     } else {
45       EXPECT_EQ(ice_ufrag, desc->ice_ufrag);
46       EXPECT_EQ(ice_pwd, desc->ice_pwd);
47     }
48     if (dtls_alg.empty()) {
49       EXPECT_TRUE(desc->identity_fingerprint.get() == NULL);
50     } else {
51       ASSERT_TRUE(desc->identity_fingerprint.get() != NULL);
52       EXPECT_EQ(desc->identity_fingerprint->algorithm, dtls_alg);
53       EXPECT_GT(desc->identity_fingerprint->digest.size(), 0U);
54     }
55   }
56 
57   // This test ice restart by doing two offer answer exchanges. On the second
58   // exchange ice is restarted. The test verifies that the ufrag and password
59   // in the offer and answer is changed.
60   // If |dtls| is true, the test verifies that the finger print is not changed.
TestIceRestart(bool dtls)61   void TestIceRestart(bool dtls) {
62     if (dtls) {
63       f1_.set_secure(cricket::SEC_ENABLED);
64       f2_.set_secure(cricket::SEC_ENABLED);
65       f1_.set_certificate(cert1_);
66       f2_.set_certificate(cert2_);
67     } else {
68       f1_.set_secure(cricket::SEC_DISABLED);
69       f2_.set_secure(cricket::SEC_DISABLED);
70     }
71 
72     cricket::TransportOptions options;
73     // The initial offer / answer exchange.
74     rtc::scoped_ptr<TransportDescription> offer(f1_.CreateOffer(
75         options, NULL));
76     rtc::scoped_ptr<TransportDescription> answer(
77         f2_.CreateAnswer(offer.get(),
78                          options, NULL));
79 
80     // Create an updated offer where we restart ice.
81     options.ice_restart = true;
82     rtc::scoped_ptr<TransportDescription> restart_offer(f1_.CreateOffer(
83         options, offer.get()));
84 
85     VerifyUfragAndPasswordChanged(dtls, offer.get(), restart_offer.get());
86 
87     // Create a new answer. The transport ufrag and password is changed since
88     // |options.ice_restart == true|
89     rtc::scoped_ptr<TransportDescription> restart_answer(
90         f2_.CreateAnswer(restart_offer.get(), options, answer.get()));
91     ASSERT_TRUE(restart_answer.get() != NULL);
92 
93     VerifyUfragAndPasswordChanged(dtls, answer.get(), restart_answer.get());
94   }
95 
VerifyUfragAndPasswordChanged(bool dtls,const TransportDescription * org_desc,const TransportDescription * restart_desc)96   void VerifyUfragAndPasswordChanged(bool dtls,
97                                      const TransportDescription* org_desc,
98                                      const TransportDescription* restart_desc) {
99     EXPECT_NE(org_desc->ice_pwd, restart_desc->ice_pwd);
100     EXPECT_NE(org_desc->ice_ufrag, restart_desc->ice_ufrag);
101     EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
102               restart_desc->ice_ufrag.size());
103     EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
104               restart_desc->ice_pwd.size());
105     // If DTLS is enabled, make sure the finger print is unchanged.
106     if (dtls) {
107       EXPECT_FALSE(
108           org_desc->identity_fingerprint->GetRfc4572Fingerprint().empty());
109       EXPECT_EQ(org_desc->identity_fingerprint->GetRfc4572Fingerprint(),
110                 restart_desc->identity_fingerprint->GetRfc4572Fingerprint());
111     }
112   }
113 
114  protected:
115   TransportDescriptionFactory f1_;
116   TransportDescriptionFactory f2_;
117 
118   rtc::scoped_refptr<rtc::RTCCertificate> cert1_;
119   rtc::scoped_refptr<rtc::RTCCertificate> cert2_;
120 };
121 
TEST_F(TransportDescriptionFactoryTest,TestOfferDefault)122 TEST_F(TransportDescriptionFactoryTest, TestOfferDefault) {
123   scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
124       TransportOptions(), NULL));
125   CheckDesc(desc.get(), "", "", "", "");
126 }
127 
TEST_F(TransportDescriptionFactoryTest,TestOfferDtls)128 TEST_F(TransportDescriptionFactoryTest, TestOfferDtls) {
129   f1_.set_secure(cricket::SEC_ENABLED);
130   f1_.set_certificate(cert1_);
131   std::string digest_alg;
132   ASSERT_TRUE(cert1_->ssl_certificate().GetSignatureDigestAlgorithm(
133       &digest_alg));
134   scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
135       TransportOptions(), NULL));
136   CheckDesc(desc.get(), "", "", "", digest_alg);
137   // Ensure it also works with SEC_REQUIRED.
138   f1_.set_secure(cricket::SEC_REQUIRED);
139   desc.reset(f1_.CreateOffer(TransportOptions(), NULL));
140   CheckDesc(desc.get(), "", "", "", digest_alg);
141 }
142 
143 // Test generating an offer with DTLS fails with no identity.
TEST_F(TransportDescriptionFactoryTest,TestOfferDtlsWithNoIdentity)144 TEST_F(TransportDescriptionFactoryTest, TestOfferDtlsWithNoIdentity) {
145   f1_.set_secure(cricket::SEC_ENABLED);
146   scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
147       TransportOptions(), NULL));
148   ASSERT_TRUE(desc.get() == NULL);
149 }
150 
151 // Test updating an offer with DTLS to pick ICE.
152 // The ICE credentials should stay the same in the new offer.
TEST_F(TransportDescriptionFactoryTest,TestOfferDtlsReofferDtls)153 TEST_F(TransportDescriptionFactoryTest, TestOfferDtlsReofferDtls) {
154   f1_.set_secure(cricket::SEC_ENABLED);
155   f1_.set_certificate(cert1_);
156   std::string digest_alg;
157   ASSERT_TRUE(cert1_->ssl_certificate().GetSignatureDigestAlgorithm(
158       &digest_alg));
159   scoped_ptr<TransportDescription> old_desc(f1_.CreateOffer(
160       TransportOptions(), NULL));
161   ASSERT_TRUE(old_desc.get() != NULL);
162   scoped_ptr<TransportDescription> desc(
163       f1_.CreateOffer(TransportOptions(), old_desc.get()));
164   CheckDesc(desc.get(), "",
165             old_desc->ice_ufrag, old_desc->ice_pwd, digest_alg);
166 }
167 
TEST_F(TransportDescriptionFactoryTest,TestAnswerDefault)168 TEST_F(TransportDescriptionFactoryTest, TestAnswerDefault) {
169   scoped_ptr<TransportDescription> offer(f1_.CreateOffer(
170       TransportOptions(), NULL));
171   ASSERT_TRUE(offer.get() != NULL);
172   scoped_ptr<TransportDescription> desc(f2_.CreateAnswer(
173       offer.get(), TransportOptions(), NULL));
174   CheckDesc(desc.get(), "", "", "", "");
175   desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(),
176                               NULL));
177   CheckDesc(desc.get(), "", "", "", "");
178 }
179 
180 // Test that we can update an answer properly; ICE credentials shouldn't change.
TEST_F(TransportDescriptionFactoryTest,TestReanswer)181 TEST_F(TransportDescriptionFactoryTest, TestReanswer) {
182   scoped_ptr<TransportDescription> offer(
183       f1_.CreateOffer(TransportOptions(), NULL));
184   ASSERT_TRUE(offer.get() != NULL);
185   scoped_ptr<TransportDescription> old_desc(
186       f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
187   ASSERT_TRUE(old_desc.get() != NULL);
188   scoped_ptr<TransportDescription> desc(
189       f2_.CreateAnswer(offer.get(), TransportOptions(),
190                        old_desc.get()));
191   ASSERT_TRUE(desc.get() != NULL);
192   CheckDesc(desc.get(), "",
193             old_desc->ice_ufrag, old_desc->ice_pwd, "");
194 }
195 
196 // Test that we handle answering an offer with DTLS with no DTLS.
TEST_F(TransportDescriptionFactoryTest,TestAnswerDtlsToNoDtls)197 TEST_F(TransportDescriptionFactoryTest, TestAnswerDtlsToNoDtls) {
198   f1_.set_secure(cricket::SEC_ENABLED);
199   f1_.set_certificate(cert1_);
200   scoped_ptr<TransportDescription> offer(
201       f1_.CreateOffer(TransportOptions(), NULL));
202   ASSERT_TRUE(offer.get() != NULL);
203   scoped_ptr<TransportDescription> desc(
204       f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
205   CheckDesc(desc.get(), "", "", "", "");
206 }
207 
208 // Test that we handle answering an offer without DTLS if we have DTLS enabled,
209 // but fail if we require DTLS.
TEST_F(TransportDescriptionFactoryTest,TestAnswerNoDtlsToDtls)210 TEST_F(TransportDescriptionFactoryTest, TestAnswerNoDtlsToDtls) {
211   f2_.set_secure(cricket::SEC_ENABLED);
212   f2_.set_certificate(cert2_);
213   scoped_ptr<TransportDescription> offer(
214       f1_.CreateOffer(TransportOptions(), NULL));
215   ASSERT_TRUE(offer.get() != NULL);
216   scoped_ptr<TransportDescription> desc(
217       f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
218   CheckDesc(desc.get(), "", "", "", "");
219   f2_.set_secure(cricket::SEC_REQUIRED);
220   desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(),
221                               NULL));
222   ASSERT_TRUE(desc.get() == NULL);
223 }
224 
225 // Test that we handle answering an DTLS offer with DTLS, both if we have
226 // DTLS enabled and required.
TEST_F(TransportDescriptionFactoryTest,TestAnswerDtlsToDtls)227 TEST_F(TransportDescriptionFactoryTest, TestAnswerDtlsToDtls) {
228   f1_.set_secure(cricket::SEC_ENABLED);
229   f1_.set_certificate(cert1_);
230 
231   f2_.set_secure(cricket::SEC_ENABLED);
232   f2_.set_certificate(cert2_);
233   // f2_ produces the answer that is being checked in this test, so the
234   // answer must contain fingerprint lines with cert2_'s digest algorithm.
235   std::string digest_alg2;
236   ASSERT_TRUE(cert2_->ssl_certificate().GetSignatureDigestAlgorithm(
237       &digest_alg2));
238 
239   scoped_ptr<TransportDescription> offer(
240       f1_.CreateOffer(TransportOptions(), NULL));
241   ASSERT_TRUE(offer.get() != NULL);
242   scoped_ptr<TransportDescription> desc(
243       f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
244   CheckDesc(desc.get(), "", "", "", digest_alg2);
245   f2_.set_secure(cricket::SEC_REQUIRED);
246   desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(),
247                               NULL));
248   CheckDesc(desc.get(), "", "", "", digest_alg2);
249 }
250 
251 // Test that ice ufrag and password is changed in an updated offer and answer
252 // if |TransportDescriptionOptions::ice_restart| is true.
TEST_F(TransportDescriptionFactoryTest,TestIceRestart)253 TEST_F(TransportDescriptionFactoryTest, TestIceRestart) {
254   TestIceRestart(false);
255 }
256 
257 // Test that ice ufrag and password is changed in an updated offer and answer
258 // if |TransportDescriptionOptions::ice_restart| is true and DTLS is enabled.
TEST_F(TransportDescriptionFactoryTest,TestIceRestartWithDtls)259 TEST_F(TransportDescriptionFactoryTest, TestIceRestartWithDtls) {
260   TestIceRestart(true);
261 }
262