Home | History | Annotate | Download | only in base
      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:
     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 
     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.
     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 
     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 
    122 TEST_F(TransportDescriptionFactoryTest, TestOfferDefault) {
    123   scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
    124       TransportOptions(), NULL));
    125   CheckDesc(desc.get(), "", "", "", "");
    126 }
    127 
    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.
    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.
    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 
    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.
    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.
    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.
    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.
    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.
    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.
    259 TEST_F(TransportDescriptionFactoryTest, TestIceRestartWithDtls) {
    260   TestIceRestart(true);
    261 }
    262