Index: webrtc/p2p/base/jseptransport_unittest.cc |
diff --git a/webrtc/p2p/base/jseptransport_unittest.cc b/webrtc/p2p/base/jseptransport_unittest.cc |
index ccb7016e0531f82a2b5c8376772813a3f3484dfd..23ed4d857df70378cdc5d90eef8ca19040886cb1 100644 |
--- a/webrtc/p2p/base/jseptransport_unittest.cc |
+++ b/webrtc/p2p/base/jseptransport_unittest.cc |
@@ -32,16 +32,21 @@ static const char kIcePwd2[] = "TESTICEPWD00000000000002"; |
class JsepTransportTest : public testing::Test, public sigslot::has_slots<> { |
public: |
- JsepTransportTest() |
- : transport_(new JsepTransport("test content name", nullptr)) {} |
+ JsepTransportTest() { RecreateTransport(); } |
+ |
bool SetupChannel() { |
fake_ice_transport_.reset(new FakeIceTransport(transport_->mid(), 1)); |
fake_dtls_transport_.reset( |
new FakeDtlsTransport(fake_ice_transport_.get())); |
return transport_->AddChannel(fake_dtls_transport_.get(), 1); |
} |
+ |
void DestroyChannel() { transport_->RemoveChannel(1); } |
+ void RecreateTransport() { |
+ transport_.reset(new JsepTransport("test content name", nullptr)); |
+ } |
+ |
protected: |
std::unique_ptr<FakeDtlsTransport> fake_dtls_transport_; |
std::unique_ptr<FakeIceTransport> fake_ice_transport_; |
@@ -167,10 +172,22 @@ TEST_F(JsepTransportTest, TestVerifyCertificateFingerprint) { |
} |
} |
-// Tests that NegotiateRole sets the SSL role correctly. |
-TEST_F(JsepTransportTest, TestNegotiateRole) { |
+// Tests the logic of DTLS role negotiation for an initial offer/answer. |
+TEST_F(JsepTransportTest, DtlsRoleNegotiation) { |
+ rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
+ rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>( |
+ rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); |
+ std::unique_ptr<rtc::SSLFingerprint> fingerprint( |
+ rtc::SSLFingerprint::CreateFromCertificate(certificate)); |
+ |
TransportDescription local_desc(kIceUfrag1, kIcePwd1); |
TransportDescription remote_desc(kIceUfrag2, kIcePwd2); |
+ // Just use the same fingerprint in both descriptions; the remote fingerprint |
+ // doesn't matter in a non end-to-end test. |
+ local_desc.identity_fingerprint.reset( |
+ TransportDescription::CopyFingerprint(fingerprint.get())); |
+ remote_desc.identity_fingerprint.reset( |
+ TransportDescription::CopyFingerprint(fingerprint.get())); |
struct NegotiateRoleParams { |
cricket::ConnectionRole local_role; |
@@ -179,7 +196,6 @@ TEST_F(JsepTransportTest, TestNegotiateRole) { |
cricket::ContentAction remote_action; |
}; |
- rtc::SSLRole ssl_role; |
std::string error_desc; |
// Parameters which set the SSL role to SSL_CLIENT. |
@@ -194,16 +210,25 @@ TEST_F(JsepTransportTest, TestNegotiateRole) { |
cricket::CA_OFFER, cricket::CA_PRANSWER}}; |
for (auto& param : valid_client_params) { |
+ RecreateTransport(); |
+ transport_->SetLocalCertificate(certificate); |
+ |
local_desc.connection_role = param.local_role; |
remote_desc.connection_role = param.remote_role; |
- ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
- remote_desc, param.remote_action, nullptr)); |
- ASSERT_TRUE(transport_->SetLocalTransportDescription( |
- local_desc, param.local_action, nullptr)); |
- EXPECT_TRUE( |
- transport_->NegotiateRole(param.local_action, &ssl_role, &error_desc)); |
- EXPECT_EQ(rtc::SSL_CLIENT, ssl_role); |
+ // Set the offer first. |
+ if (param.local_action == cricket::CA_OFFER) { |
+ EXPECT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, param.local_action, nullptr)); |
+ EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, param.remote_action, nullptr)); |
+ } else { |
+ EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, param.remote_action, nullptr)); |
+ EXPECT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, param.local_action, nullptr)); |
+ } |
+ EXPECT_EQ(rtc::SSL_CLIENT, *transport_->GetSslRole()); |
} |
// Parameters which set the SSL role to SSL_SERVER. |
@@ -218,16 +243,25 @@ TEST_F(JsepTransportTest, TestNegotiateRole) { |
cricket::CA_OFFER, cricket::CA_PRANSWER}}; |
for (auto& param : valid_server_params) { |
+ RecreateTransport(); |
+ transport_->SetLocalCertificate(certificate); |
+ |
local_desc.connection_role = param.local_role; |
remote_desc.connection_role = param.remote_role; |
- ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
- remote_desc, param.remote_action, nullptr)); |
- ASSERT_TRUE(transport_->SetLocalTransportDescription( |
- local_desc, param.local_action, nullptr)); |
- EXPECT_TRUE( |
- transport_->NegotiateRole(param.local_action, &ssl_role, &error_desc)); |
- EXPECT_EQ(rtc::SSL_SERVER, ssl_role); |
+ // Set the offer first. |
+ if (param.local_action == cricket::CA_OFFER) { |
+ EXPECT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, param.local_action, nullptr)); |
+ EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, param.remote_action, nullptr)); |
+ } else { |
+ EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, param.remote_action, nullptr)); |
+ EXPECT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, param.local_action, nullptr)); |
+ } |
+ EXPECT_EQ(rtc::SSL_SERVER, *transport_->GetSslRole()); |
} |
// Invalid parameters due to both peers having a duplicate role. |
@@ -258,15 +292,24 @@ TEST_F(JsepTransportTest, TestNegotiateRole) { |
cricket::CA_OFFER, cricket::CA_PRANSWER}}; |
for (auto& param : duplicate_params) { |
+ RecreateTransport(); |
+ transport_->SetLocalCertificate(certificate); |
+ |
local_desc.connection_role = param.local_role; |
remote_desc.connection_role = param.remote_role; |
- ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
- remote_desc, param.remote_action, nullptr)); |
- ASSERT_TRUE(transport_->SetLocalTransportDescription( |
- local_desc, param.local_action, nullptr)); |
- EXPECT_FALSE( |
- transport_->NegotiateRole(param.local_action, &ssl_role, &error_desc)); |
+ // Set the offer first. |
+ if (param.local_action == cricket::CA_OFFER) { |
+ EXPECT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, param.local_action, nullptr)); |
+ EXPECT_FALSE(transport_->SetRemoteTransportDescription( |
+ remote_desc, param.remote_action, nullptr)); |
+ } else { |
+ EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, param.remote_action, nullptr)); |
+ EXPECT_FALSE(transport_->SetLocalTransportDescription( |
+ local_desc, param.local_action, nullptr)); |
+ } |
} |
// Invalid parameters due to the offerer not using ACTPASS. |
@@ -297,14 +340,113 @@ TEST_F(JsepTransportTest, TestNegotiateRole) { |
cricket::CA_OFFER, cricket::CA_PRANSWER}}; |
for (auto& param : offerer_without_actpass_params) { |
+ RecreateTransport(); |
+ transport_->SetLocalCertificate(certificate); |
+ |
local_desc.connection_role = param.local_role; |
remote_desc.connection_role = param.remote_role; |
- ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
- remote_desc, param.remote_action, nullptr)); |
- ASSERT_TRUE(transport_->SetLocalTransportDescription( |
- local_desc, param.local_action, nullptr)); |
- EXPECT_FALSE( |
- transport_->NegotiateRole(param.local_action, &ssl_role, &error_desc)); |
+ // Set the offer first. |
+ // TODO(deadbeef): Really this should fail as soon as the offer is |
+ // attempted to be applied, and not when the answer is applied. |
+ if (param.local_action == cricket::CA_OFFER) { |
+ EXPECT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, param.local_action, nullptr)); |
+ EXPECT_FALSE(transport_->SetRemoteTransportDescription( |
+ remote_desc, param.remote_action, nullptr)); |
+ } else { |
+ EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, param.remote_action, nullptr)); |
+ EXPECT_FALSE(transport_->SetLocalTransportDescription( |
+ local_desc, param.local_action, nullptr)); |
+ } |
} |
} |
+ |
+// Test that a remote offer with the current negotiated role can be accepted. |
+// This is allowed by dtls-sdp, though we'll never generate such an offer, |
+// since JSEP requires generating "actpass". |
+TEST_F(JsepTransportTest, RemoteOfferWithCurrentNegotiatedDtlsRole) { |
+ rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
+ rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>( |
+ rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); |
+ std::unique_ptr<rtc::SSLFingerprint> fingerprint( |
+ rtc::SSLFingerprint::CreateFromCertificate(certificate)); |
+ transport_->SetLocalCertificate(certificate); |
+ |
+ TransportDescription local_desc(kIceUfrag1, kIcePwd1); |
+ TransportDescription remote_desc(kIceUfrag2, kIcePwd2); |
+ // Just use the same fingerprint in both descriptions; the remote fingerprint |
+ // doesn't matter in a non end-to-end test. |
+ local_desc.identity_fingerprint.reset( |
+ TransportDescription::CopyFingerprint(fingerprint.get())); |
+ remote_desc.identity_fingerprint.reset( |
+ TransportDescription::CopyFingerprint(fingerprint.get())); |
+ |
+ remote_desc.connection_role = cricket::CONNECTIONROLE_ACTPASS; |
+ local_desc.connection_role = cricket::CONNECTIONROLE_ACTIVE; |
+ |
+ // Normal initial offer/answer with "actpass" in the offer and "active" in |
+ // the answer. |
+ ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, cricket::CA_OFFER, nullptr)); |
+ ASSERT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, cricket::CA_ANSWER, nullptr)); |
+ |
+ // Sanity check that role was actually negotiated. |
+ rtc::Optional<rtc::SSLRole> role = transport_->GetSslRole(); |
+ ASSERT_TRUE(role); |
+ EXPECT_EQ(rtc::SSL_CLIENT, *role); |
+ |
+ // Subsequent offer with current negotiated role of "passive". |
+ remote_desc.connection_role = cricket::CONNECTIONROLE_PASSIVE; |
+ EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, cricket::CA_OFFER, nullptr)); |
+ EXPECT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, cricket::CA_ANSWER, nullptr)); |
+} |
+ |
+// Test that a remote offer with the inverse of the current negotiated DTLS |
+// role is rejected. |
+TEST_F(JsepTransportTest, RemoteOfferThatChangesNegotiatedDtlsRole) { |
+ rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
+ rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>( |
+ rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); |
+ std::unique_ptr<rtc::SSLFingerprint> fingerprint( |
+ rtc::SSLFingerprint::CreateFromCertificate(certificate)); |
+ transport_->SetLocalCertificate(certificate); |
+ |
+ TransportDescription local_desc(kIceUfrag1, kIcePwd1); |
+ TransportDescription remote_desc(kIceUfrag2, kIcePwd2); |
+ // Just use the same fingerprint in both descriptions; the remote fingerprint |
+ // doesn't matter in a non end-to-end test. |
+ local_desc.identity_fingerprint.reset( |
+ TransportDescription::CopyFingerprint(fingerprint.get())); |
+ remote_desc.identity_fingerprint.reset( |
+ TransportDescription::CopyFingerprint(fingerprint.get())); |
+ |
+ remote_desc.connection_role = cricket::CONNECTIONROLE_ACTPASS; |
+ local_desc.connection_role = cricket::CONNECTIONROLE_ACTIVE; |
+ |
+ // Normal initial offer/answer with "actpass" in the offer and "active" in |
+ // the answer. |
+ ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, cricket::CA_OFFER, nullptr)); |
+ ASSERT_TRUE(transport_->SetLocalTransportDescription( |
+ local_desc, cricket::CA_ANSWER, nullptr)); |
+ |
+ // Sanity check that role was actually negotiated. |
+ rtc::Optional<rtc::SSLRole> role = transport_->GetSslRole(); |
+ ASSERT_TRUE(role); |
+ EXPECT_EQ(rtc::SSL_CLIENT, *role); |
+ |
+ // Subsequent offer with "active", which is the opposite of the remote |
+ // endpoint's negotiated role. |
+ // TODO(deadbeef): Really this should fail as soon as the offer is |
+ // attempted to be applied, and not when the answer is applied. |
+ remote_desc.connection_role = cricket::CONNECTIONROLE_ACTIVE; |
+ EXPECT_TRUE(transport_->SetRemoteTransportDescription( |
+ remote_desc, cricket::CA_OFFER, nullptr)); |
+ EXPECT_FALSE(transport_->SetLocalTransportDescription( |
+ local_desc, cricket::CA_ANSWER, nullptr)); |
+} |