deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2011 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 <memory> |
| 12 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 13 | #include "p2p/base/fakedtlstransport.h" |
| 14 | #include "p2p/base/fakeicetransport.h" |
| 15 | #include "rtc_base/fakesslidentity.h" |
| 16 | #include "rtc_base/gunit.h" |
| 17 | #include "rtc_base/network.h" |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 18 | |
| 19 | using cricket::JsepTransport; |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 20 | using cricket::FakeDtlsTransport; |
| 21 | using cricket::FakeIceTransport; |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 22 | using cricket::IceRole; |
| 23 | using cricket::TransportDescription; |
| 24 | using rtc::SocketAddress; |
| 25 | |
| 26 | static const char kIceUfrag1[] = "TESTICEUFRAG0001"; |
| 27 | static const char kIcePwd1[] = "TESTICEPWD00000000000001"; |
| 28 | |
| 29 | static const char kIceUfrag2[] = "TESTICEUFRAG0002"; |
| 30 | static const char kIcePwd2[] = "TESTICEPWD00000000000002"; |
| 31 | |
| 32 | class JsepTransportTest : public testing::Test, public sigslot::has_slots<> { |
| 33 | public: |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 34 | JsepTransportTest() { RecreateTransport(); } |
| 35 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 36 | bool SetupChannel() { |
deadbeef | f534659 | 2017-01-24 21:51:21 -0800 | [diff] [blame] | 37 | fake_ice_transport_.reset(new FakeIceTransport(transport_->mid(), 1)); |
| 38 | fake_dtls_transport_.reset( |
| 39 | new FakeDtlsTransport(fake_ice_transport_.get())); |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 40 | return transport_->AddChannel(fake_dtls_transport_.get(), 1); |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 41 | } |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 42 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 43 | void DestroyChannel() { transport_->RemoveChannel(1); } |
| 44 | |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 45 | void RecreateTransport() { |
| 46 | transport_.reset(new JsepTransport("test content name", nullptr)); |
| 47 | } |
| 48 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 49 | protected: |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 50 | std::unique_ptr<FakeDtlsTransport> fake_dtls_transport_; |
deadbeef | f534659 | 2017-01-24 21:51:21 -0800 | [diff] [blame] | 51 | std::unique_ptr<FakeIceTransport> fake_ice_transport_; |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 52 | std::unique_ptr<JsepTransport> transport_; |
| 53 | }; |
| 54 | |
| 55 | // This test verifies channels are created with proper ICE |
| 56 | // ufrag/password after a transport description is applied. |
| 57 | TEST_F(JsepTransportTest, TestChannelIceParameters) { |
| 58 | cricket::TransportDescription local_desc(kIceUfrag1, kIcePwd1); |
| 59 | ASSERT_TRUE(transport_->SetLocalTransportDescription( |
| 60 | local_desc, cricket::CA_OFFER, NULL)); |
| 61 | EXPECT_TRUE(SetupChannel()); |
deadbeef | f534659 | 2017-01-24 21:51:21 -0800 | [diff] [blame] | 62 | EXPECT_EQ(cricket::ICEMODE_FULL, fake_ice_transport_->remote_ice_mode()); |
| 63 | EXPECT_EQ(kIceUfrag1, fake_ice_transport_->ice_ufrag()); |
| 64 | EXPECT_EQ(kIcePwd1, fake_ice_transport_->ice_pwd()); |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 65 | |
| 66 | cricket::TransportDescription remote_desc(kIceUfrag1, kIcePwd1); |
| 67 | ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
| 68 | remote_desc, cricket::CA_ANSWER, NULL)); |
deadbeef | f534659 | 2017-01-24 21:51:21 -0800 | [diff] [blame] | 69 | EXPECT_EQ(cricket::ICEMODE_FULL, fake_ice_transport_->remote_ice_mode()); |
| 70 | EXPECT_EQ(kIceUfrag1, fake_ice_transport_->remote_ice_ufrag()); |
| 71 | EXPECT_EQ(kIcePwd1, fake_ice_transport_->remote_ice_pwd()); |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | // Verifies that IceCredentialsChanged returns true when either ufrag or pwd |
| 75 | // changed, and false in other cases. |
| 76 | TEST_F(JsepTransportTest, TestIceCredentialsChanged) { |
| 77 | EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u2", "p2")); |
| 78 | EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u2", "p1")); |
| 79 | EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u1", "p2")); |
| 80 | EXPECT_FALSE(cricket::IceCredentialsChanged("u1", "p1", "u1", "p1")); |
| 81 | } |
| 82 | |
deadbeef | d1a38b5 | 2016-12-10 13:15:33 -0800 | [diff] [blame] | 83 | // Tests SetNeedsIceRestartFlag and NeedsIceRestart, ensuring NeedsIceRestart |
| 84 | // only starts returning "false" once an ICE restart has been initiated. |
| 85 | TEST_F(JsepTransportTest, NeedsIceRestart) { |
| 86 | // Do initial offer/answer so there's something to restart. |
| 87 | cricket::TransportDescription local_desc(kIceUfrag1, kIcePwd1); |
| 88 | cricket::TransportDescription remote_desc(kIceUfrag1, kIcePwd1); |
| 89 | ASSERT_TRUE(transport_->SetLocalTransportDescription( |
| 90 | local_desc, cricket::CA_OFFER, nullptr)); |
| 91 | ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
| 92 | remote_desc, cricket::CA_ANSWER, nullptr)); |
| 93 | |
| 94 | // Flag initially should be false. |
| 95 | EXPECT_FALSE(transport_->NeedsIceRestart()); |
| 96 | |
| 97 | // After setting flag, it should be true. |
| 98 | transport_->SetNeedsIceRestartFlag(); |
| 99 | EXPECT_TRUE(transport_->NeedsIceRestart()); |
| 100 | |
| 101 | // Doing an identical offer/answer shouldn't clear the flag. |
| 102 | ASSERT_TRUE(transport_->SetLocalTransportDescription( |
| 103 | local_desc, cricket::CA_OFFER, nullptr)); |
| 104 | ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
| 105 | remote_desc, cricket::CA_ANSWER, nullptr)); |
| 106 | EXPECT_TRUE(transport_->NeedsIceRestart()); |
| 107 | |
| 108 | // Doing an offer/answer that restarts ICE should clear the flag. |
| 109 | cricket::TransportDescription ice_restart_local_desc(kIceUfrag2, kIcePwd2); |
| 110 | cricket::TransportDescription ice_restart_remote_desc(kIceUfrag2, kIcePwd2); |
| 111 | ASSERT_TRUE(transport_->SetLocalTransportDescription( |
| 112 | ice_restart_local_desc, cricket::CA_OFFER, nullptr)); |
| 113 | ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
| 114 | ice_restart_remote_desc, cricket::CA_ANSWER, nullptr)); |
| 115 | EXPECT_FALSE(transport_->NeedsIceRestart()); |
| 116 | } |
| 117 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 118 | TEST_F(JsepTransportTest, TestGetStats) { |
| 119 | EXPECT_TRUE(SetupChannel()); |
| 120 | cricket::TransportStats stats; |
| 121 | EXPECT_TRUE(transport_->GetStats(&stats)); |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 122 | // Note that this tests the behavior of a FakeIceTransport. |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 123 | ASSERT_EQ(1U, stats.channel_stats.size()); |
| 124 | EXPECT_EQ(1, stats.channel_stats[0].component); |
| 125 | // Set local transport description for FakeTransport before connecting. |
| 126 | TransportDescription faketransport_desc( |
| 127 | std::vector<std::string>(), |
| 128 | rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH), |
| 129 | rtc::CreateRandomString(cricket::ICE_PWD_LENGTH), cricket::ICEMODE_FULL, |
| 130 | cricket::CONNECTIONROLE_NONE, nullptr); |
| 131 | transport_->SetLocalTransportDescription(faketransport_desc, |
| 132 | cricket::CA_OFFER, nullptr); |
| 133 | EXPECT_TRUE(transport_->GetStats(&stats)); |
| 134 | ASSERT_EQ(1U, stats.channel_stats.size()); |
| 135 | EXPECT_EQ(1, stats.channel_stats[0].component); |
| 136 | } |
| 137 | |
| 138 | // Tests that VerifyCertificateFingerprint only returns true when the |
| 139 | // certificate matches the fingerprint. |
| 140 | TEST_F(JsepTransportTest, TestVerifyCertificateFingerprint) { |
| 141 | std::string error_desc; |
| 142 | EXPECT_FALSE( |
| 143 | transport_->VerifyCertificateFingerprint(nullptr, nullptr, &error_desc)); |
| 144 | rtc::KeyType key_types[] = {rtc::KT_RSA, rtc::KT_ECDSA}; |
| 145 | |
| 146 | for (auto& key_type : key_types) { |
| 147 | rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
| 148 | rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>( |
| 149 | rtc::SSLIdentity::Generate("testing", key_type))); |
| 150 | ASSERT_NE(nullptr, certificate); |
| 151 | |
| 152 | std::string digest_algorithm; |
| 153 | ASSERT_TRUE(certificate->ssl_certificate().GetSignatureDigestAlgorithm( |
| 154 | &digest_algorithm)); |
| 155 | ASSERT_FALSE(digest_algorithm.empty()); |
| 156 | std::unique_ptr<rtc::SSLFingerprint> good_fingerprint( |
| 157 | rtc::SSLFingerprint::Create(digest_algorithm, certificate->identity())); |
| 158 | ASSERT_NE(nullptr, good_fingerprint); |
| 159 | |
| 160 | EXPECT_TRUE(transport_->VerifyCertificateFingerprint( |
| 161 | certificate.get(), good_fingerprint.get(), &error_desc)); |
| 162 | EXPECT_FALSE(transport_->VerifyCertificateFingerprint( |
| 163 | certificate.get(), nullptr, &error_desc)); |
| 164 | EXPECT_FALSE(transport_->VerifyCertificateFingerprint( |
| 165 | nullptr, good_fingerprint.get(), &error_desc)); |
| 166 | |
| 167 | rtc::SSLFingerprint bad_fingerprint = *good_fingerprint; |
| 168 | bad_fingerprint.digest.AppendData("0", 1); |
| 169 | EXPECT_FALSE(transport_->VerifyCertificateFingerprint( |
| 170 | certificate.get(), &bad_fingerprint, &error_desc)); |
| 171 | } |
| 172 | } |
| 173 | |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 174 | // Tests the logic of DTLS role negotiation for an initial offer/answer. |
| 175 | TEST_F(JsepTransportTest, DtlsRoleNegotiation) { |
| 176 | rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
| 177 | rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>( |
| 178 | rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); |
| 179 | std::unique_ptr<rtc::SSLFingerprint> fingerprint( |
| 180 | rtc::SSLFingerprint::CreateFromCertificate(certificate)); |
| 181 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 182 | TransportDescription local_desc(kIceUfrag1, kIcePwd1); |
| 183 | TransportDescription remote_desc(kIceUfrag2, kIcePwd2); |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 184 | // Just use the same fingerprint in both descriptions; the remote fingerprint |
| 185 | // doesn't matter in a non end-to-end test. |
| 186 | local_desc.identity_fingerprint.reset( |
| 187 | TransportDescription::CopyFingerprint(fingerprint.get())); |
| 188 | remote_desc.identity_fingerprint.reset( |
| 189 | TransportDescription::CopyFingerprint(fingerprint.get())); |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 190 | |
| 191 | struct NegotiateRoleParams { |
| 192 | cricket::ConnectionRole local_role; |
| 193 | cricket::ConnectionRole remote_role; |
| 194 | cricket::ContentAction local_action; |
| 195 | cricket::ContentAction remote_action; |
| 196 | }; |
| 197 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 198 | std::string error_desc; |
| 199 | |
| 200 | // Parameters which set the SSL role to SSL_CLIENT. |
| 201 | NegotiateRoleParams valid_client_params[] = { |
| 202 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_ACTPASS, |
| 203 | cricket::CA_ANSWER, cricket::CA_OFFER}, |
| 204 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_ACTPASS, |
| 205 | cricket::CA_PRANSWER, cricket::CA_OFFER}, |
| 206 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_PASSIVE, |
| 207 | cricket::CA_OFFER, cricket::CA_ANSWER}, |
| 208 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_PASSIVE, |
| 209 | cricket::CA_OFFER, cricket::CA_PRANSWER}}; |
| 210 | |
| 211 | for (auto& param : valid_client_params) { |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 212 | RecreateTransport(); |
| 213 | transport_->SetLocalCertificate(certificate); |
| 214 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 215 | local_desc.connection_role = param.local_role; |
| 216 | remote_desc.connection_role = param.remote_role; |
| 217 | |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 218 | // Set the offer first. |
| 219 | if (param.local_action == cricket::CA_OFFER) { |
| 220 | EXPECT_TRUE(transport_->SetLocalTransportDescription( |
| 221 | local_desc, param.local_action, nullptr)); |
| 222 | EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
| 223 | remote_desc, param.remote_action, nullptr)); |
| 224 | } else { |
| 225 | EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
| 226 | remote_desc, param.remote_action, nullptr)); |
| 227 | EXPECT_TRUE(transport_->SetLocalTransportDescription( |
| 228 | local_desc, param.local_action, nullptr)); |
| 229 | } |
| 230 | EXPECT_EQ(rtc::SSL_CLIENT, *transport_->GetSslRole()); |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 231 | } |
| 232 | |
| 233 | // Parameters which set the SSL role to SSL_SERVER. |
| 234 | NegotiateRoleParams valid_server_params[] = { |
| 235 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_ACTPASS, |
| 236 | cricket::CA_ANSWER, cricket::CA_OFFER}, |
| 237 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_ACTPASS, |
| 238 | cricket::CA_PRANSWER, cricket::CA_OFFER}, |
| 239 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_ACTIVE, |
| 240 | cricket::CA_OFFER, cricket::CA_ANSWER}, |
| 241 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_ACTIVE, |
| 242 | cricket::CA_OFFER, cricket::CA_PRANSWER}}; |
| 243 | |
| 244 | for (auto& param : valid_server_params) { |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 245 | RecreateTransport(); |
| 246 | transport_->SetLocalCertificate(certificate); |
| 247 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 248 | local_desc.connection_role = param.local_role; |
| 249 | remote_desc.connection_role = param.remote_role; |
| 250 | |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 251 | // Set the offer first. |
| 252 | if (param.local_action == cricket::CA_OFFER) { |
| 253 | EXPECT_TRUE(transport_->SetLocalTransportDescription( |
| 254 | local_desc, param.local_action, nullptr)); |
| 255 | EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
| 256 | remote_desc, param.remote_action, nullptr)); |
| 257 | } else { |
| 258 | EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
| 259 | remote_desc, param.remote_action, nullptr)); |
| 260 | EXPECT_TRUE(transport_->SetLocalTransportDescription( |
| 261 | local_desc, param.local_action, nullptr)); |
| 262 | } |
| 263 | EXPECT_EQ(rtc::SSL_SERVER, *transport_->GetSslRole()); |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 264 | } |
| 265 | |
| 266 | // Invalid parameters due to both peers having a duplicate role. |
| 267 | NegotiateRoleParams duplicate_params[] = { |
| 268 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_ACTIVE, |
| 269 | cricket::CA_ANSWER, cricket::CA_OFFER}, |
| 270 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_ACTPASS, |
| 271 | cricket::CA_ANSWER, cricket::CA_OFFER}, |
| 272 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_PASSIVE, |
| 273 | cricket::CA_ANSWER, cricket::CA_OFFER}, |
| 274 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_ACTIVE, |
| 275 | cricket::CA_PRANSWER, cricket::CA_OFFER}, |
| 276 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_ACTPASS, |
| 277 | cricket::CA_PRANSWER, cricket::CA_OFFER}, |
| 278 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_PASSIVE, |
| 279 | cricket::CA_PRANSWER, cricket::CA_OFFER}, |
| 280 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_ACTIVE, |
| 281 | cricket::CA_OFFER, cricket::CA_ANSWER}, |
| 282 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_ACTPASS, |
| 283 | cricket::CA_OFFER, cricket::CA_ANSWER}, |
| 284 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_PASSIVE, |
| 285 | cricket::CA_OFFER, cricket::CA_ANSWER}, |
| 286 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_ACTIVE, |
| 287 | cricket::CA_OFFER, cricket::CA_PRANSWER}, |
| 288 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_ACTPASS, |
| 289 | cricket::CA_OFFER, cricket::CA_PRANSWER}, |
| 290 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_PASSIVE, |
| 291 | cricket::CA_OFFER, cricket::CA_PRANSWER}}; |
| 292 | |
| 293 | for (auto& param : duplicate_params) { |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 294 | RecreateTransport(); |
| 295 | transport_->SetLocalCertificate(certificate); |
| 296 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 297 | local_desc.connection_role = param.local_role; |
| 298 | remote_desc.connection_role = param.remote_role; |
| 299 | |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 300 | // Set the offer first. |
| 301 | if (param.local_action == cricket::CA_OFFER) { |
| 302 | EXPECT_TRUE(transport_->SetLocalTransportDescription( |
| 303 | local_desc, param.local_action, nullptr)); |
| 304 | EXPECT_FALSE(transport_->SetRemoteTransportDescription( |
| 305 | remote_desc, param.remote_action, nullptr)); |
| 306 | } else { |
| 307 | EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
| 308 | remote_desc, param.remote_action, nullptr)); |
| 309 | EXPECT_FALSE(transport_->SetLocalTransportDescription( |
| 310 | local_desc, param.local_action, nullptr)); |
| 311 | } |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 312 | } |
| 313 | |
| 314 | // Invalid parameters due to the offerer not using ACTPASS. |
| 315 | NegotiateRoleParams offerer_without_actpass_params[] = { |
| 316 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_PASSIVE, |
| 317 | cricket::CA_ANSWER, cricket::CA_OFFER}, |
| 318 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_ACTIVE, |
| 319 | cricket::CA_ANSWER, cricket::CA_OFFER}, |
| 320 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_PASSIVE, |
| 321 | cricket::CA_ANSWER, cricket::CA_OFFER}, |
| 322 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_PASSIVE, |
| 323 | cricket::CA_PRANSWER, cricket::CA_OFFER}, |
| 324 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_ACTIVE, |
| 325 | cricket::CA_PRANSWER, cricket::CA_OFFER}, |
| 326 | {cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_PASSIVE, |
| 327 | cricket::CA_PRANSWER, cricket::CA_OFFER}, |
| 328 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_PASSIVE, |
| 329 | cricket::CA_OFFER, cricket::CA_ANSWER}, |
| 330 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_ACTIVE, |
| 331 | cricket::CA_OFFER, cricket::CA_ANSWER}, |
| 332 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_ACTPASS, |
| 333 | cricket::CA_OFFER, cricket::CA_ANSWER}, |
| 334 | {cricket::CONNECTIONROLE_ACTIVE, cricket::CONNECTIONROLE_PASSIVE, |
| 335 | cricket::CA_OFFER, cricket::CA_PRANSWER}, |
| 336 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_ACTIVE, |
| 337 | cricket::CA_OFFER, cricket::CA_PRANSWER}, |
| 338 | {cricket::CONNECTIONROLE_PASSIVE, cricket::CONNECTIONROLE_ACTPASS, |
| 339 | cricket::CA_OFFER, cricket::CA_PRANSWER}}; |
| 340 | |
| 341 | for (auto& param : offerer_without_actpass_params) { |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 342 | RecreateTransport(); |
| 343 | transport_->SetLocalCertificate(certificate); |
| 344 | |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 345 | local_desc.connection_role = param.local_role; |
| 346 | remote_desc.connection_role = param.remote_role; |
| 347 | |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 348 | // Set the offer first. |
| 349 | // TODO(deadbeef): Really this should fail as soon as the offer is |
| 350 | // attempted to be applied, and not when the answer is applied. |
| 351 | if (param.local_action == cricket::CA_OFFER) { |
| 352 | EXPECT_TRUE(transport_->SetLocalTransportDescription( |
| 353 | local_desc, param.local_action, nullptr)); |
| 354 | EXPECT_FALSE(transport_->SetRemoteTransportDescription( |
| 355 | remote_desc, param.remote_action, nullptr)); |
| 356 | } else { |
| 357 | EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
| 358 | remote_desc, param.remote_action, nullptr)); |
| 359 | EXPECT_FALSE(transport_->SetLocalTransportDescription( |
| 360 | local_desc, param.local_action, nullptr)); |
| 361 | } |
deadbeef | 49f34fd | 2016-12-06 16:22:06 -0800 | [diff] [blame] | 362 | } |
| 363 | } |
deadbeef | d8cfa1a | 2017-03-27 10:33:26 -0700 | [diff] [blame] | 364 | |
| 365 | // Test that a remote offer with the current negotiated role can be accepted. |
| 366 | // This is allowed by dtls-sdp, though we'll never generate such an offer, |
| 367 | // since JSEP requires generating "actpass". |
| 368 | TEST_F(JsepTransportTest, RemoteOfferWithCurrentNegotiatedDtlsRole) { |
| 369 | rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
| 370 | rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>( |
| 371 | rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); |
| 372 | std::unique_ptr<rtc::SSLFingerprint> fingerprint( |
| 373 | rtc::SSLFingerprint::CreateFromCertificate(certificate)); |
| 374 | transport_->SetLocalCertificate(certificate); |
| 375 | |
| 376 | TransportDescription local_desc(kIceUfrag1, kIcePwd1); |
| 377 | TransportDescription remote_desc(kIceUfrag2, kIcePwd2); |
| 378 | // Just use the same fingerprint in both descriptions; the remote fingerprint |
| 379 | // doesn't matter in a non end-to-end test. |
| 380 | local_desc.identity_fingerprint.reset( |
| 381 | TransportDescription::CopyFingerprint(fingerprint.get())); |
| 382 | remote_desc.identity_fingerprint.reset( |
| 383 | TransportDescription::CopyFingerprint(fingerprint.get())); |
| 384 | |
| 385 | remote_desc.connection_role = cricket::CONNECTIONROLE_ACTPASS; |
| 386 | local_desc.connection_role = cricket::CONNECTIONROLE_ACTIVE; |
| 387 | |
| 388 | // Normal initial offer/answer with "actpass" in the offer and "active" in |
| 389 | // the answer. |
| 390 | ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
| 391 | remote_desc, cricket::CA_OFFER, nullptr)); |
| 392 | ASSERT_TRUE(transport_->SetLocalTransportDescription( |
| 393 | local_desc, cricket::CA_ANSWER, nullptr)); |
| 394 | |
| 395 | // Sanity check that role was actually negotiated. |
| 396 | rtc::Optional<rtc::SSLRole> role = transport_->GetSslRole(); |
| 397 | ASSERT_TRUE(role); |
| 398 | EXPECT_EQ(rtc::SSL_CLIENT, *role); |
| 399 | |
| 400 | // Subsequent offer with current negotiated role of "passive". |
| 401 | remote_desc.connection_role = cricket::CONNECTIONROLE_PASSIVE; |
| 402 | EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
| 403 | remote_desc, cricket::CA_OFFER, nullptr)); |
| 404 | EXPECT_TRUE(transport_->SetLocalTransportDescription( |
| 405 | local_desc, cricket::CA_ANSWER, nullptr)); |
| 406 | } |
| 407 | |
| 408 | // Test that a remote offer with the inverse of the current negotiated DTLS |
| 409 | // role is rejected. |
| 410 | TEST_F(JsepTransportTest, RemoteOfferThatChangesNegotiatedDtlsRole) { |
| 411 | rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
| 412 | rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>( |
| 413 | rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); |
| 414 | std::unique_ptr<rtc::SSLFingerprint> fingerprint( |
| 415 | rtc::SSLFingerprint::CreateFromCertificate(certificate)); |
| 416 | transport_->SetLocalCertificate(certificate); |
| 417 | |
| 418 | TransportDescription local_desc(kIceUfrag1, kIcePwd1); |
| 419 | TransportDescription remote_desc(kIceUfrag2, kIcePwd2); |
| 420 | // Just use the same fingerprint in both descriptions; the remote fingerprint |
| 421 | // doesn't matter in a non end-to-end test. |
| 422 | local_desc.identity_fingerprint.reset( |
| 423 | TransportDescription::CopyFingerprint(fingerprint.get())); |
| 424 | remote_desc.identity_fingerprint.reset( |
| 425 | TransportDescription::CopyFingerprint(fingerprint.get())); |
| 426 | |
| 427 | remote_desc.connection_role = cricket::CONNECTIONROLE_ACTPASS; |
| 428 | local_desc.connection_role = cricket::CONNECTIONROLE_ACTIVE; |
| 429 | |
| 430 | // Normal initial offer/answer with "actpass" in the offer and "active" in |
| 431 | // the answer. |
| 432 | ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
| 433 | remote_desc, cricket::CA_OFFER, nullptr)); |
| 434 | ASSERT_TRUE(transport_->SetLocalTransportDescription( |
| 435 | local_desc, cricket::CA_ANSWER, nullptr)); |
| 436 | |
| 437 | // Sanity check that role was actually negotiated. |
| 438 | rtc::Optional<rtc::SSLRole> role = transport_->GetSslRole(); |
| 439 | ASSERT_TRUE(role); |
| 440 | EXPECT_EQ(rtc::SSL_CLIENT, *role); |
| 441 | |
| 442 | // Subsequent offer with "active", which is the opposite of the remote |
| 443 | // endpoint's negotiated role. |
| 444 | // TODO(deadbeef): Really this should fail as soon as the offer is |
| 445 | // attempted to be applied, and not when the answer is applied. |
| 446 | remote_desc.connection_role = cricket::CONNECTIONROLE_ACTIVE; |
| 447 | EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
| 448 | remote_desc, cricket::CA_OFFER, nullptr)); |
| 449 | EXPECT_FALSE(transport_->SetLocalTransportDescription( |
| 450 | local_desc, cricket::CA_ANSWER, nullptr)); |
| 451 | } |