Make maximum SSL version configurable through PeerConnectionFactory::Options
This can be used to activate DTLS 1.2 through a command-line flag from Chromium
later.
BUG=chromium:428343
R=jiayl@webrtc.org, juberti@google.com
Review URL: https://webrtc-codereview.appspot.com/54509004
Cr-Commit-Position: refs/heads/master@{#9328}
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc
index fe712e8..99ee9be 100644
--- a/talk/app/webrtc/peerconnection_unittest.cc
+++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -82,6 +82,7 @@
using webrtc::MockSetSessionDescriptionObserver;
using webrtc::MockStatsObserver;
using webrtc::PeerConnectionInterface;
+using webrtc::PeerConnectionFactory;
using webrtc::SessionDescriptionInterface;
using webrtc::StreamCollectionInterface;
@@ -501,7 +502,8 @@
video_decoder_factory_enabled_(false),
signaling_message_receiver_(NULL) {
}
- bool Init(const MediaConstraintsInterface* constraints) {
+ bool Init(const MediaConstraintsInterface* constraints,
+ const PeerConnectionFactory::Options* options) {
EXPECT_TRUE(!peer_connection_);
EXPECT_TRUE(!peer_connection_factory_);
allocator_factory_ = webrtc::FakePortAllocatorFactory::Create();
@@ -523,6 +525,9 @@
if (!peer_connection_factory_) {
return false;
}
+ if (options) {
+ peer_connection_factory_->SetOptions(*options);
+ }
peer_connection_ = CreatePeerConnection(allocator_factory_.get(),
constraints);
return peer_connection_.get() != NULL;
@@ -619,9 +624,10 @@
public:
static JsepTestClient* CreateClient(
const std::string& id,
- const MediaConstraintsInterface* constraints) {
+ const MediaConstraintsInterface* constraints,
+ const PeerConnectionFactory::Options* options) {
JsepTestClient* client(new JsepTestClient(id));
- if (!client->Init(constraints)) {
+ if (!client->Init(constraints, options)) {
delete client;
return NULL;
}
@@ -967,10 +973,19 @@
bool CreateTestClients(MediaConstraintsInterface* init_constraints,
MediaConstraintsInterface* recv_constraints) {
+ return CreateTestClients(init_constraints, NULL, recv_constraints, NULL);
+ }
+
+ bool CreateTestClients(MediaConstraintsInterface* init_constraints,
+ PeerConnectionFactory::Options* init_options,
+ MediaConstraintsInterface* recv_constraints,
+ PeerConnectionFactory::Options* recv_options) {
initiating_client_.reset(SignalingClass::CreateClient("Caller: ",
- init_constraints));
+ init_constraints,
+ init_options));
receiving_client_.reset(SignalingClass::CreateClient("Callee: ",
- recv_constraints));
+ recv_constraints,
+ recv_options));
if (!initiating_client_ || !receiving_client_) {
return false;
}
@@ -1307,13 +1322,77 @@
kMaxWaitForStatsMs);
}
-// Test that we can get negotiated ciphers.
-TEST_F(JsepPeerConnectionP2PTestClient, GetNegotiatedCiphersStats) {
- ASSERT_TRUE(CreateTestClients());
+// Test that DTLS 1.0 is used if both sides only support DTLS 1.0.
+TEST_F(JsepPeerConnectionP2PTestClient, GetDtls12None) {
+ PeerConnectionFactory::Options init_options;
+ init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
+ PeerConnectionFactory::Options recv_options;
+ recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
+ ASSERT_TRUE(CreateTestClients(NULL, &init_options, NULL, &recv_options));
LocalP2PTest();
- // TODO(jbauch): this should check for DTLS 1.0 / 1.2 when we have a way to
- // enable DTLS 1.2 on peer connections.
+ EXPECT_EQ_WAIT(
+ rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
+ initializing_client()->GetDtlsCipherStats(),
+ kMaxWaitForStatsMs);
+
+ EXPECT_EQ_WAIT(
+ kDefaultSrtpCipher,
+ initializing_client()->GetSrtpCipherStats(),
+ kMaxWaitForStatsMs);
+}
+
+// Test that DTLS 1.2 is used if both ends support it.
+TEST_F(JsepPeerConnectionP2PTestClient, GetDtls12Both) {
+ PeerConnectionFactory::Options init_options;
+ init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
+ PeerConnectionFactory::Options recv_options;
+ recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
+ ASSERT_TRUE(CreateTestClients(NULL, &init_options, NULL, &recv_options));
+ LocalP2PTest();
+
+ EXPECT_EQ_WAIT(
+ rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_12),
+ initializing_client()->GetDtlsCipherStats(),
+ kMaxWaitForStatsMs);
+
+ EXPECT_EQ_WAIT(
+ kDefaultSrtpCipher,
+ initializing_client()->GetSrtpCipherStats(),
+ kMaxWaitForStatsMs);
+}
+
+// Test that DTLS 1.0 is used if the initator supports DTLS 1.2 and the
+// received supports 1.0.
+TEST_F(JsepPeerConnectionP2PTestClient, GetDtls12Init) {
+ PeerConnectionFactory::Options init_options;
+ init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
+ PeerConnectionFactory::Options recv_options;
+ recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
+ ASSERT_TRUE(CreateTestClients(NULL, &init_options, NULL, &recv_options));
+ LocalP2PTest();
+
+ EXPECT_EQ_WAIT(
+ rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
+ initializing_client()->GetDtlsCipherStats(),
+ kMaxWaitForStatsMs);
+
+ EXPECT_EQ_WAIT(
+ kDefaultSrtpCipher,
+ initializing_client()->GetSrtpCipherStats(),
+ kMaxWaitForStatsMs);
+}
+
+// Test that DTLS 1.0 is used if the initator supports DTLS 1.0 and the
+// received supports 1.2.
+TEST_F(JsepPeerConnectionP2PTestClient, GetDtls12Recv) {
+ PeerConnectionFactory::Options init_options;
+ init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
+ PeerConnectionFactory::Options recv_options;
+ recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
+ ASSERT_TRUE(CreateTestClients(NULL, &init_options, NULL, &recv_options));
+ LocalP2PTest();
+
EXPECT_EQ_WAIT(
rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
initializing_client()->GetDtlsCipherStats(),
diff --git a/talk/app/webrtc/peerconnectioninterface.h b/talk/app/webrtc/peerconnectioninterface.h
index 329137f..59cc700 100644
--- a/talk/app/webrtc/peerconnectioninterface.h
+++ b/talk/app/webrtc/peerconnectioninterface.h
@@ -79,6 +79,7 @@
#include "talk/app/webrtc/umametrics.h"
#include "webrtc/base/fileutils.h"
#include "webrtc/base/network.h"
+#include "webrtc/base/sslstreamadapter.h"
#include "webrtc/base/socketaddress.h"
namespace rtc {
@@ -518,7 +519,8 @@
Options() :
disable_encryption(false),
disable_sctp_data_channels(false),
- network_ignore_mask(rtc::kDefaultNetworkIgnoreMask) {
+ network_ignore_mask(rtc::kDefaultNetworkIgnoreMask),
+ ssl_max_version(rtc::SSL_PROTOCOL_DTLS_10) {
}
bool disable_encryption;
bool disable_sctp_data_channels;
@@ -527,6 +529,11 @@
// ADAPTER_TYPE_ETHERNET | ADAPTER_TYPE_LOOPBACK will ignore Ethernet and
// loopback interfaces.
int network_ignore_mask;
+
+ // Sets the maximum supported protocol version. The highest version
+ // supported by both ends will be used for the connection, i.e. if one
+ // party supports DTLS 1.0 and the other DTLS 1.2, DTLS 1.0 will be used.
+ rtc::SSLProtocolVersion ssl_max_version;
};
virtual void SetOptions(const Options& options) = 0;
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index e461365..a058129 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -524,6 +524,7 @@
const PeerConnectionInterface::RTCConfiguration& rtc_configuration) {
bundle_policy_ = rtc_configuration.bundle_policy;
rtcp_mux_policy_ = rtc_configuration.rtcp_mux_policy;
+ SetSslMaxProtocolVersion(options.ssl_max_version);
// TODO(perkj): Take |constraints| into consideration. Return false if not all
// mandatory constraints can be fulfilled. Note that |constraints|
diff --git a/webrtc/p2p/base/dtlstransport.h b/webrtc/p2p/base/dtlstransport.h
index 8e17ea6..27cece4 100644
--- a/webrtc/p2p/base/dtlstransport.h
+++ b/webrtc/p2p/base/dtlstransport.h
@@ -33,7 +33,8 @@
rtc::SSLIdentity* identity)
: Base(signaling_thread, worker_thread, content_name, allocator),
identity_(identity),
- secure_role_(rtc::SSL_CLIENT) {
+ secure_role_(rtc::SSL_CLIENT),
+ ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10) {
}
~DtlsTransport() {
@@ -50,6 +51,11 @@
return true;
}
+ virtual bool SetSslMaxProtocolVersion_w(rtc::SSLProtocolVersion version) {
+ ssl_max_version_ = version;
+ return true;
+ }
+
virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
std::string* error_desc) {
rtc::SSLFingerprint* local_fp =
@@ -189,8 +195,10 @@
}
virtual DtlsTransportChannelWrapper* CreateTransportChannel(int component) {
- return new DtlsTransportChannelWrapper(
+ DtlsTransportChannelWrapper* channel = new DtlsTransportChannelWrapper(
this, Base::CreateTransportChannel(component));
+ channel->SetSslMaxProtocolVersion(ssl_max_version_);
+ return channel;
}
virtual void DestroyTransportChannel(TransportChannelImpl* channel) {
@@ -231,6 +239,7 @@
rtc::SSLIdentity* identity_;
rtc::SSLRole secure_role_;
+ rtc::SSLProtocolVersion ssl_max_version_;
rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint_;
};
diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc
index 6a206d4..e73cf68 100644
--- a/webrtc/p2p/base/dtlstransportchannel.cc
+++ b/webrtc/p2p/base/dtlstransportchannel.cc
@@ -163,15 +163,16 @@
return true;
}
-void DtlsTransportChannelWrapper::SetMaxProtocolVersion(
+bool DtlsTransportChannelWrapper::SetSslMaxProtocolVersion(
rtc::SSLProtocolVersion version) {
if (dtls_state_ != STATE_NONE) {
LOG(LS_ERROR) << "Not changing max. protocol version "
<< "while DTLS is negotiating";
- return;
+ return false;
}
ssl_max_version_ = version;
+ return true;
}
bool DtlsTransportChannelWrapper::SetSslRole(rtc::SSLRole role) {
diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h
index a48d09f..1af5efd 100644
--- a/webrtc/p2p/base/dtlstransportchannel.h
+++ b/webrtc/p2p/base/dtlstransportchannel.h
@@ -129,7 +129,7 @@
return channel_->SessionId();
}
- virtual void SetMaxProtocolVersion(rtc::SSLProtocolVersion version);
+ virtual bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
// Set up the ciphers to use for DTLS-SRTP. If this method is not called
// before DTLS starts, or |ciphers| is empty, SRTP keys won't be negotiated.
diff --git a/webrtc/p2p/base/dtlstransportchannel_unittest.cc b/webrtc/p2p/base/dtlstransportchannel_unittest.cc
index 670f8f9..8c1c21c 100644
--- a/webrtc/p2p/base/dtlstransportchannel_unittest.cc
+++ b/webrtc/p2p/base/dtlstransportchannel_unittest.cc
@@ -90,7 +90,7 @@
static_cast<cricket::DtlsTransportChannelWrapper*>(
transport_->CreateChannel(i));
ASSERT_TRUE(channel != NULL);
- channel->SetMaxProtocolVersion(ssl_max_version_);
+ channel->SetSslMaxProtocolVersion(ssl_max_version_);
channel->SignalWritableState.connect(this,
&DtlsTestClient::OnTransportChannelWritableState);
channel->SignalReadPacket.connect(this,
diff --git a/webrtc/p2p/base/session.cc b/webrtc/p2p/base/session.cc
index 8cbe128..d1f6e54 100644
--- a/webrtc/p2p/base/session.cc
+++ b/webrtc/p2p/base/session.cc
@@ -342,6 +342,7 @@
transport_type_(NS_GINGLE_P2P),
initiator_(initiator),
identity_(NULL),
+ ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10),
ice_tiebreaker_(rtc::CreateRandomId64()),
role_switch_(false) {
ASSERT(signaling_thread->IsCurrent());
@@ -404,6 +405,15 @@
return true;
}
+bool BaseSession::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
+ if (state_ != STATE_INIT) {
+ return false;
+ }
+
+ ssl_max_version_ = version;
+ return true;
+}
+
bool BaseSession::PushdownTransportDescription(ContentSource source,
ContentAction action,
std::string* error_desc) {
@@ -501,6 +511,7 @@
Transport* transport = CreateTransport(content_name);
transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
transport->SetIceTiebreaker(ice_tiebreaker_);
+ transport->SetSslMaxProtocolVersion(ssl_max_version_);
// TODO: Connect all the Transport signals to TransportProxy
// then to the BaseSession.
transport->SignalConnecting.connect(
diff --git a/webrtc/p2p/base/session.h b/webrtc/p2p/base/session.h
index ba4206a..318a788 100644
--- a/webrtc/p2p/base/session.h
+++ b/webrtc/p2p/base/session.h
@@ -323,6 +323,8 @@
// Specifies the identity to use in this session.
bool SetIdentity(rtc::SSLIdentity* identity);
+ bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
+
bool PushdownTransportDescription(ContentSource source,
ContentAction action,
std::string* error_desc);
@@ -445,6 +447,7 @@
const std::string transport_type_;
bool initiator_;
rtc::SSLIdentity* identity_;
+ rtc::SSLProtocolVersion ssl_max_version_;
rtc::scoped_ptr<const SessionDescription> local_description_;
rtc::scoped_ptr<SessionDescription> remote_description_;
uint64 ice_tiebreaker_;
diff --git a/webrtc/p2p/base/transport.cc b/webrtc/p2p/base/transport.cc
index df452fd..0184af3 100644
--- a/webrtc/p2p/base/transport.cc
+++ b/webrtc/p2p/base/transport.cc
@@ -458,6 +458,11 @@
&Transport::GetSslRole_w, this, ssl_role));
}
+bool Transport::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
+ return worker_thread_->Invoke<bool>(Bind(
+ &Transport::SetSslMaxProtocolVersion_w, this, version));
+}
+
void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) {
for (std::vector<Candidate>::const_iterator iter = candidates.begin();
iter != candidates.end();
diff --git a/webrtc/p2p/base/transport.h b/webrtc/p2p/base/transport.h
index c4ab03d..d7ebc9c 100644
--- a/webrtc/p2p/base/transport.h
+++ b/webrtc/p2p/base/transport.h
@@ -264,6 +264,9 @@
virtual bool GetSslRole(rtc::SSLRole* ssl_role) const;
+ // Must be called before channel is starting to connect.
+ virtual bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
+
protected:
// These are called by Create/DestroyChannel above in order to create or
// destroy the appropriate type of channel.
@@ -320,6 +323,10 @@
return false;
}
+ virtual bool SetSslMaxProtocolVersion_w(rtc::SSLProtocolVersion version) {
+ return false;
+ }
+
private:
struct ChannelMapEntry {
ChannelMapEntry() : impl_(NULL), candidates_allocated_(false), ref_(0) {}