Index: webrtc/p2p/base/dtlstransportchannel_unittest.cc |
diff --git a/webrtc/p2p/base/dtlstransportchannel_unittest.cc b/webrtc/p2p/base/dtlstransportchannel_unittest.cc |
index 705df2d95f0d6e28a37a1e38f63feaf087969b68..6eb0f0e3f1aa857461a5e3feecf1451956cc0ef6 100644 |
--- a/webrtc/p2p/base/dtlstransportchannel_unittest.cc |
+++ b/webrtc/p2p/base/dtlstransportchannel_unittest.cc |
@@ -45,9 +45,13 @@ cricket::TransportDescription MakeTransportDescription( |
std::unique_ptr<rtc::SSLFingerprint> fingerprint; |
if (cert) { |
std::string digest_algorithm; |
- cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); |
+ EXPECT_TRUE( |
+ cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm)); |
+ EXPECT_FALSE(digest_algorithm.empty()); |
fingerprint.reset( |
rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); |
+ EXPECT_TRUE(fingerprint.get() != NULL); |
+ EXPECT_EQ(rtc::DIGEST_SHA_256, digest_algorithm); |
} |
return cricket::TransportDescription(std::vector<std::string>(), kIceUfrag1, |
kIcePwd1, cricket::ICEMODE_FULL, role, |
@@ -124,6 +128,48 @@ class DtlsTestClient : public sigslot::has_slots<> { |
local_role, remote_role, flags); |
} |
+ void MaybeSetSrtpCryptoSuites() { |
+ if (!use_dtls_srtp_) { |
+ return; |
+ } |
+ std::vector<int> ciphers; |
+ ciphers.push_back(rtc::SRTP_AES128_CM_SHA1_80); |
+ // SRTP ciphers will be set only in the beginning. |
+ for (cricket::DtlsTransportChannelWrapper* channel : channels_) { |
+ EXPECT_TRUE(channel->SetSrtpCryptoSuites(ciphers)); |
+ } |
+ } |
+ |
+ void SetLocalTransportDescription( |
+ const rtc::scoped_refptr<rtc::RTCCertificate>& cert, |
+ cricket::ContentAction action, |
+ ConnectionRole role, |
+ int flags) { |
+ // If |NF_EXPECT_FAILURE| is set, expect SRTD or SLTD to fail when |
+ // content action is CA_ANSWER. |
+ bool expect_success = |
+ !((action == cricket::CA_ANSWER) && (flags & NF_EXPECT_FAILURE)); |
+ EXPECT_EQ(expect_success, |
+ transport_->SetLocalTransportDescription( |
+ MakeTransportDescription(cert, role), action, nullptr)); |
+ set_local_cert_ = (cert != nullptr); |
+ } |
+ |
+ void SetRemoteTransportDescription( |
+ const rtc::scoped_refptr<rtc::RTCCertificate>& cert, |
+ cricket::ContentAction action, |
+ ConnectionRole role, |
+ int flags) { |
+ // If |NF_EXPECT_FAILURE| is set, expect SRTD or SLTD to fail when |
+ // content action is CA_ANSWER. |
+ bool expect_success = |
+ !((action == cricket::CA_ANSWER) && (flags & NF_EXPECT_FAILURE)); |
+ EXPECT_EQ(expect_success, |
+ transport_->SetRemoteTransportDescription( |
+ MakeTransportDescription(cert, role), action, nullptr)); |
+ set_remote_cert_ = (cert != nullptr); |
+ } |
+ |
// Allow any DTLS configuration to be specified (including invalid ones). |
void Negotiate(const rtc::scoped_refptr<rtc::RTCCertificate>& local_cert, |
const rtc::scoped_refptr<rtc::RTCCertificate>& remote_cert, |
@@ -131,67 +177,23 @@ class DtlsTestClient : public sigslot::has_slots<> { |
ConnectionRole local_role, |
ConnectionRole remote_role, |
int flags) { |
- std::unique_ptr<rtc::SSLFingerprint> local_fingerprint; |
- std::unique_ptr<rtc::SSLFingerprint> remote_fingerprint; |
- if (local_cert) { |
- std::string digest_algorithm; |
- ASSERT_TRUE(local_cert->ssl_certificate().GetSignatureDigestAlgorithm( |
- &digest_algorithm)); |
- ASSERT_FALSE(digest_algorithm.empty()); |
- local_fingerprint.reset(rtc::SSLFingerprint::Create( |
- digest_algorithm, local_cert->identity())); |
- ASSERT_TRUE(local_fingerprint.get() != NULL); |
- EXPECT_EQ(rtc::DIGEST_SHA_256, digest_algorithm); |
- } |
- if (remote_cert) { |
- std::string digest_algorithm; |
- ASSERT_TRUE(remote_cert->ssl_certificate().GetSignatureDigestAlgorithm( |
- &digest_algorithm)); |
- ASSERT_FALSE(digest_algorithm.empty()); |
- remote_fingerprint.reset(rtc::SSLFingerprint::Create( |
- digest_algorithm, remote_cert->identity())); |
- ASSERT_TRUE(remote_fingerprint.get() != NULL); |
- EXPECT_EQ(rtc::DIGEST_SHA_256, digest_algorithm); |
- } |
- |
- if (use_dtls_srtp_ && !(flags & NF_REOFFER)) { |
+ if (!(flags & NF_REOFFER)) { |
// SRTP ciphers will be set only in the beginning. |
- for (std::vector<cricket::DtlsTransportChannelWrapper*>::iterator it = |
- channels_.begin(); it != channels_.end(); ++it) { |
- std::vector<int> ciphers; |
- ciphers.push_back(rtc::SRTP_AES128_CM_SHA1_80); |
- ASSERT_TRUE((*it)->SetSrtpCryptoSuites(ciphers)); |
- } |
+ MaybeSetSrtpCryptoSuites(); |
} |
- |
- cricket::TransportDescription local_desc( |
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL, |
- local_role, |
- // If remote if the offerer and has no DTLS support, answer will be |
- // without any fingerprint. |
- (action == cricket::CA_ANSWER && !remote_cert) |
- ? nullptr |
- : local_fingerprint.get()); |
- |
- cricket::TransportDescription remote_desc( |
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL, |
- remote_role, remote_fingerprint.get()); |
- |
- bool expect_success = (flags & NF_EXPECT_FAILURE) ? false : true; |
- // If |expect_success| is false, expect SRTD or SLTD to fail when |
- // content action is CA_ANSWER. |
if (action == cricket::CA_OFFER) { |
- ASSERT_TRUE(transport_->SetLocalTransportDescription( |
- local_desc, cricket::CA_OFFER, NULL)); |
- ASSERT_EQ(expect_success, transport_->SetRemoteTransportDescription( |
- remote_desc, cricket::CA_ANSWER, NULL)); |
+ SetLocalTransportDescription(local_cert, cricket::CA_OFFER, local_role, |
+ flags); |
+ SetRemoteTransportDescription(remote_cert, cricket::CA_ANSWER, |
+ remote_role, flags); |
} else { |
- ASSERT_TRUE(transport_->SetRemoteTransportDescription( |
- remote_desc, cricket::CA_OFFER, NULL)); |
- ASSERT_EQ(expect_success, transport_->SetLocalTransportDescription( |
- local_desc, cricket::CA_ANSWER, NULL)); |
+ SetRemoteTransportDescription(remote_cert, cricket::CA_OFFER, remote_role, |
+ flags); |
+ // If remote if the offerer and has no DTLS support, answer will be |
+ // without any fingerprint. |
+ SetLocalTransportDescription(remote_cert ? local_cert : nullptr, |
+ cricket::CA_ANSWER, local_role, flags); |
} |
- negotiated_dtls_ = (local_cert && remote_cert); |
} |
bool Connect(DtlsTestClient* peer, bool asymmetric) { |
@@ -227,6 +229,8 @@ class DtlsTestClient : public sigslot::has_slots<> { |
return received_dtls_client_hellos_; |
} |
+ bool negotiated_dtls() const { return set_local_cert_ && set_remote_cert_; } |
+ |
void CheckRole(rtc::SSLRole role) { |
if (role == rtc::SSL_CLIENT) { |
ASSERT_EQ(0, received_dtls_client_hellos_); |
@@ -243,7 +247,7 @@ class DtlsTestClient : public sigslot::has_slots<> { |
int crypto_suite; |
bool rv = (*it)->GetSrtpCryptoSuite(&crypto_suite); |
- if (negotiated_dtls_ && expected_crypto_suite) { |
+ if (negotiated_dtls() && expected_crypto_suite) { |
ASSERT_TRUE(rv); |
ASSERT_EQ(crypto_suite, expected_crypto_suite); |
@@ -259,7 +263,7 @@ class DtlsTestClient : public sigslot::has_slots<> { |
int cipher; |
bool rv = (*it)->GetSslCipherSuite(&cipher); |
- if (negotiated_dtls_) { |
+ if (negotiated_dtls()) { |
ASSERT_TRUE(rv); |
EXPECT_TRUE( |
@@ -388,7 +392,7 @@ class DtlsTestClient : public sigslot::has_slots<> { |
} else if (data[13] == 2) { |
++received_dtls_server_hellos_; |
} |
- } else if (negotiated_dtls_ && !(data[0] >= 20 && data[0] <= 22)) { |
+ } else if (negotiated_dtls() && !(data[0] >= 20 && data[0] <= 22)) { |
ASSERT_TRUE(data[0] == 23 || IsRtpLeadByte(data[0])); |
if (data[0] == 23) { |
ASSERT_TRUE(VerifyEncryptedPacket(data, size)); |
@@ -407,7 +411,8 @@ class DtlsTestClient : public sigslot::has_slots<> { |
std::set<int> received_; |
bool use_dtls_srtp_ = false; |
rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; |
- bool negotiated_dtls_ = false; |
+ bool set_local_cert_ = false; |
+ bool set_remote_cert_ = false; |
int received_dtls_client_hellos_ = 0; |
int received_dtls_server_hellos_ = 0; |
rtc::SentPacket sent_packet_; |
@@ -457,10 +462,35 @@ class DtlsTransportChannelTest : public testing::Test { |
use_dtls_srtp_ = true; |
} |
- bool Connect(ConnectionRole client1_role, ConnectionRole client2_role) { |
- Negotiate(client1_role, client2_role); |
+ // Negotiate local/remote fingerprint before or after the underlying |
+ // tranpsort is connected? |
+ enum NegotiateOrdering { NEGOTIATE_BEFORE_CONNECT, CONNECT_BEFORE_NEGOTIATE }; |
+ bool Connect(ConnectionRole client1_role, |
+ ConnectionRole client2_role, |
+ NegotiateOrdering ordering = NEGOTIATE_BEFORE_CONNECT) { |
+ bool rv; |
+ if (ordering == NEGOTIATE_BEFORE_CONNECT) { |
+ Negotiate(client1_role, client2_role); |
+ rv = client1_.Connect(&client2_, false); |
+ } else { |
+ client1_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLING); |
+ client2_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLED); |
+ client1_.MaybeSetSrtpCryptoSuites(); |
+ client2_.MaybeSetSrtpCryptoSuites(); |
+ // This is equivalent to an offer being processed on both sides, but an |
+ // answer not yet being received on the initiating side. So the |
+ // connection will be made before negotiation has finished on both sides. |
+ client1_.SetLocalTransportDescription(client1_.certificate(), |
+ cricket::CA_OFFER, client1_role, 0); |
+ client2_.SetRemoteTransportDescription( |
+ client1_.certificate(), cricket::CA_OFFER, client1_role, 0); |
+ client2_.SetLocalTransportDescription( |
+ client2_.certificate(), cricket::CA_ANSWER, client2_role, 0); |
+ rv = client1_.Connect(&client2_, false); |
+ client1_.SetRemoteTransportDescription( |
+ client2_.certificate(), cricket::CA_ANSWER, client2_role, 0); |
+ } |
- bool rv = client1_.Connect(&client2_, false); |
EXPECT_TRUE(rv); |
if (!rv) |
return false; |
@@ -1018,3 +1048,14 @@ TEST_F(DtlsTransportChannelTest, TestRetransmissionSchedule) { |
EXPECT_EQ(++expected_hellos, client1_.received_dtls_client_hellos()); |
} |
} |
+ |
+// Test that a DTLS connection can be made even if the underlying transport |
+// is connected before DTLS fingerprints/roles have been negotiated. |
+TEST_F(DtlsTransportChannelTest, TestConnectBeforeNegotiate) { |
+ MAYBE_SKIP_TEST(HaveDtls); |
+ PrepareDtls(true, true, rtc::KT_DEFAULT); |
+ ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS, |
+ cricket::CONNECTIONROLE_ACTIVE, |
+ CONNECT_BEFORE_NEGOTIATE)); |
+ TestTransfer(0, 1000, 100, false); |
+} |