Add support for changing the TLS elliptic curve set.

This CL is almost identical to http://chromium-review.googlesource.com/c/611150

Bug: webrtc:8213
Change-Id: I21a8a0041a73b3171ed66b687dc47a579d45fe19
Reviewed-on: https://chromium-review.googlesource.com/653205
Commit-Queue: Diogo Real <diogor@google.com>
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Reviewed-by: Emad Omara <emadomara@webrtc.org>
Reviewed-by: Zeke Chin <tkchin@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#19755}
This commit is contained in:
Diogo Real
2017-09-08 12:50:41 -07:00
committed by Commit Bot
parent bdf3072f1a
commit 7bd1f1bb5b
21 changed files with 178 additions and 17 deletions

View File

@ -195,12 +195,15 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
std::string hostname;
// List of protocols to be used in the TLS ALPN extension.
std::vector<std::string> tls_alpn_protocols;
// List of elliptic curves to be used in the TLS elliptic curves extension.
std::vector<std::string> tls_elliptic_curves;
bool operator==(const IceServer& o) const {
return uri == o.uri && urls == o.urls && username == o.username &&
password == o.password && tls_cert_policy == o.tls_cert_policy &&
hostname == o.hostname &&
tls_alpn_protocols == o.tls_alpn_protocols;
tls_alpn_protocols == o.tls_alpn_protocols &&
tls_elliptic_curves == o.tls_elliptic_curves;
}
bool operator!=(const IceServer& o) const { return !(*this == o); }
};

View File

@ -159,6 +159,7 @@ AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
}
ssl_adapter->SetAlpnProtocols(tcp_options.tls_alpn_protocols);
ssl_adapter->SetEllipticCurves(tcp_options.tls_elliptic_curves);
socket = ssl_adapter;

View File

@ -20,6 +20,7 @@ namespace rtc {
struct PacketSocketTcpOptions {
int opts;
std::vector<std::string> tls_alpn_protocols;
std::vector<std::string> tls_elliptic_curves;
};
class AsyncPacketSocket;

View File

@ -536,7 +536,7 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
return TurnPort::Create(
&main_, socket_factory, MakeNetwork(addr), 0, 0, username_, password_,
ProtocolAddress(server_addr, int_proto), kRelayCredentials, 0,
std::string(), std::vector<std::string>());
std::string(), std::vector<std::string>(), std::vector<std::string>());
}
RelayPort* CreateGturnPort(const SocketAddress& addr,
ProtocolType int_proto, ProtocolType ext_proto) {

View File

@ -192,6 +192,7 @@ struct RelayServerConfig {
int priority = 0;
TlsCertPolicy tls_cert_policy = TlsCertPolicy::TLS_CERT_POLICY_SECURE;
std::vector<std::string> tls_alpn_protocols;
std::vector<std::string> tls_elliptic_curves;
};
class PortAllocatorSession : public sigslot::has_slots<> {

View File

@ -222,7 +222,8 @@ TurnPort::TurnPort(rtc::Thread* thread,
const RelayCredentials& credentials,
int server_priority,
const std::string& origin,
const std::vector<std::string>& tls_alpn_protocols)
const std::vector<std::string>& tls_alpn_protocols,
const std::vector<std::string>& tls_elliptic_curves)
: Port(thread,
RELAY_PORT_TYPE,
factory,
@ -233,6 +234,7 @@ TurnPort::TurnPort(rtc::Thread* thread,
password),
server_address_(server_address),
tls_alpn_protocols_(tls_alpn_protocols),
tls_elliptic_curves_(tls_elliptic_curves),
credentials_(credentials),
socket_(NULL),
resolver_(NULL),
@ -341,6 +343,7 @@ bool TurnPort::CreateTurnClientSocket() {
rtc::PacketSocketTcpOptions tcp_options;
tcp_options.opts = opts;
tcp_options.tls_alpn_protocols = tls_alpn_protocols_;
tcp_options.tls_elliptic_curves = tls_elliptic_curves_;
socket_ = socket_factory()->CreateClientTcpSocket(
rtc::SocketAddress(Network()->GetBestIP(), 0), server_address_.address,
proxy(), user_agent(), tcp_options);

View File

@ -70,10 +70,11 @@ class TurnPort : public Port {
const RelayCredentials& credentials,
int server_priority,
const std::string& origin,
const std::vector<std::string>& tls_alpn_protocols) {
const std::vector<std::string>& tls_alpn_protocols,
const std::vector<std::string>& tls_elliptic_curves) {
return new TurnPort(thread, factory, network, min_port, max_port, username,
password, server_address, credentials, server_priority,
origin, tls_alpn_protocols);
origin, tls_alpn_protocols, tls_elliptic_curves);
}
virtual ~TurnPort();
@ -100,6 +101,10 @@ class TurnPort : public Port {
return tls_alpn_protocols_;
}
virtual std::vector<std::string> GetTlsEllipticCurves() const {
return tls_elliptic_curves_;
}
virtual void PrepareAddress();
virtual Connection* CreateConnection(
const Candidate& c, PortInterface::CandidateOrigin origin);
@ -192,7 +197,8 @@ class TurnPort : public Port {
const RelayCredentials& credentials,
int server_priority,
const std::string& origin,
const std::vector<std::string>& alpn_protocols);
const std::vector<std::string>& tls_alpn_protocols,
const std::vector<std::string>& tls_elliptic_curves);
private:
enum {
@ -273,6 +279,7 @@ class TurnPort : public Port {
ProtocolAddress server_address_;
TlsCertPolicy tls_cert_policy_ = TlsCertPolicy::TLS_CERT_POLICY_SECURE;
std::vector<std::string> tls_alpn_protocols_;
std::vector<std::string> tls_elliptic_curves_;
RelayCredentials credentials_;
AttemptedServerSet attempted_server_addresses_;

View File

@ -263,7 +263,8 @@ class TurnPortTest : public testing::Test,
RelayCredentials credentials(username, password);
turn_port_.reset(TurnPort::Create(
&main_, &socket_factory_, network, 0, 0, kIceUfrag1, kIcePwd1,
server_address, credentials, 0, origin, std::vector<std::string>()));
server_address, credentials, 0, origin, std::vector<std::string>(),
std::vector<std::string>()));
// This TURN port will be the controlling.
turn_port_->SetIceRole(ICEROLE_CONTROLLING);
ConnectSignals();

View File

@ -1445,7 +1445,7 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
session_->allocator()->min_port(), session_->allocator()->max_port(),
session_->username(), session_->password(), *relay_port,
config.credentials, config.priority, session_->allocator()->origin(),
config.tls_alpn_protocols);
config.tls_alpn_protocols, config.tls_elliptic_curves);
}
RTC_DCHECK(port != NULL);
port->SetTlsCertPolicy(config.tls_cert_policy);

View File

@ -258,6 +258,7 @@ static RTCErrorType ParseIceServerUrl(
cricket::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK;
}
config.tls_alpn_protocols = server.tls_alpn_protocols;
config.tls_elliptic_curves = server.tls_elliptic_curves;
turn_servers->push_back(config);
break;

View File

@ -31,6 +31,7 @@
#include "webrtc/rtc_base/openssl.h"
#include "webrtc/rtc_base/safe_conversions.h"
#include "webrtc/rtc_base/sslroots.h"
#include "webrtc/rtc_base/stringencode.h"
#include "webrtc/rtc_base/stringutils.h"
#include "webrtc/rtc_base/thread.h"
@ -311,6 +312,10 @@ void OpenSSLAdapter::SetAlpnProtocols(const std::vector<std::string>& protos) {
alpn_protocols_ = protos;
}
void OpenSSLAdapter::SetEllipticCurves(const std::vector<std::string>& curves) {
elliptic_curves_ = curves;
}
void OpenSSLAdapter::SetMode(SSLMode mode) {
RTC_DCHECK(!ssl_ctx_);
RTC_DCHECK(state_ == SSL_NONE);
@ -445,6 +450,10 @@ int OpenSSLAdapter::BeginSSL() {
}
}
if (!elliptic_curves_.empty()) {
SSL_set1_curves_list(ssl_, rtc::join(elliptic_curves_, ':').c_str());
}
// Now that the initial config is done, transfer ownership of |bio| to the
// SSL object. If ContinueSSL() fails, the bio will be freed in Cleanup().
SSL_set_bio(ssl_, bio, bio);

View File

@ -40,6 +40,7 @@ class OpenSSLAdapter : public SSLAdapter, public MessageHandler {
void SetIgnoreBadCert(bool ignore) override;
void SetAlpnProtocols(const std::vector<std::string>& protos) override;
void SetEllipticCurves(const std::vector<std::string>& curves) override;
void SetMode(SSLMode mode) override;
void SetIdentity(SSLIdentity* identity) override;
@ -136,6 +137,8 @@ class OpenSSLAdapter : public SSLAdapter, public MessageHandler {
bool ignore_bad_cert_;
// List of protocols to be used in the TLS ALPN extension.
std::vector<std::string> alpn_protocols_;
// List of elliptic curves to be used in the TLS elliptic curves extension.
std::vector<std::string> elliptic_curves_;
bool custom_verification_succeeded_;
};

View File

@ -48,7 +48,9 @@ class SSLAdapter : public AsyncSocketAdapter {
// TODO(juberti): Remove the opportunistic encryption mechanism in
// BasicPacketSocketFactory that uses this function.
virtual void SetIgnoreBadCert(bool ignore) = 0;
virtual void SetAlpnProtocols(const std::vector<std::string>& protos) = 0;
virtual void SetEllipticCurves(const std::vector<std::string>& curves) = 0;
// Do DTLS or TLS (default is TLS, if unspecified)
virtual void SetMode(SSLMode mode) = 0;

View File

@ -64,6 +64,10 @@ class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
ssl_adapter_->SetAlpnProtocols(protos);
}
void SetEllipticCurves(const std::vector<std::string>& curves) {
ssl_adapter_->SetEllipticCurves(curves);
}
rtc::SocketAddress GetAddress() const {
return ssl_adapter_->GetLocalAddress();
}
@ -290,6 +294,10 @@ class SSLAdapterTestBase : public testing::Test,
client_->SetAlpnProtocols(protos);
}
void SetEllipticCurves(const std::vector<std::string>& curves) {
client_->SetEllipticCurves(curves);
}
void TestHandshake(bool expect_success) {
int rv;
@ -450,6 +458,14 @@ TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSALPN) {
TestTransfer("Hello, world!");
}
// Test transfer with TLS Elliptic curves set to "X25519:P-256:P-384:P-521"
TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSEllipticCurves) {
std::vector<std::string> elliptic_curves{"X25519", "P-256", "P-384", "P-521"};
SetEllipticCurves(elliptic_curves);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Basic tests: DTLS
// Test that handshake works, using RSA

View File

@ -645,6 +645,28 @@ bool tokenize_first(const std::string& source,
return true;
}
std::string join(const std::vector<std::string>& source, char delimiter) {
if (source.size() == 0) {
return std::string();
}
// Find length of the string to be returned to pre-allocate memory.
size_t source_string_length = 0;
for (size_t i = 0; i < source.size(); ++i) {
source_string_length += source[i].length();
}
// Build the joined string.
std::string joined_string;
joined_string.reserve(source_string_length + source.size() - 1);
for (size_t i = 0; i < source.size(); ++i) {
if (i != 0) {
joined_string += delimiter;
}
joined_string += source[i];
}
return joined_string;
}
size_t split(const std::string& source, char delimiter,
std::vector<std::string>* fields) {
RTC_DCHECK(fields);

View File

@ -136,6 +136,10 @@ inline std::string s_url_decode(const std::string& source) {
return s_transform(source, url_decode);
}
// Joins the source vector of strings into a single string, with each
// field in source being separated by delimiter. No trailing delimiter is added.
std::string join(const std::vector<std::string>& source, char delimiter);
// Splits the source string into multiple fields separated by delimiter,
// with duplicates of delimiter creating empty fields.
size_t split(const std::string& source, char delimiter,

View File

@ -113,6 +113,10 @@ public class PeerConnection {
// List of protocols to be used in the TLS ALPN extension.
public final List<String> tlsAlpnProtocols;
// List of elliptic curves to be used in the TLS elliptic curves extension.
// Only curve names supported by OpenSSL should be used (eg. "P-256","X25519").
public final List<String> tlsEllipticCurves;
/** Convenience constructor for STUN servers. */
@Deprecated
public IceServer(String uri) {
@ -132,22 +136,23 @@ public class PeerConnection {
@Deprecated
public IceServer(String uri, String username, String password, TlsCertPolicy tlsCertPolicy,
String hostname) {
this(uri, username, password, tlsCertPolicy, hostname, null);
this(uri, username, password, tlsCertPolicy, hostname, null, null);
}
private IceServer(String uri, String username, String password, TlsCertPolicy tlsCertPolicy,
String hostname, List<String> tlsAlpnProtocols) {
String hostname, List<String> tlsAlpnProtocols, List<String> tlsEllipticCurves) {
this.uri = uri;
this.username = username;
this.password = password;
this.tlsCertPolicy = tlsCertPolicy;
this.hostname = hostname;
this.tlsAlpnProtocols = tlsAlpnProtocols;
this.tlsEllipticCurves = tlsEllipticCurves;
}
public String toString() {
return uri + " [" + username + ":" + password + "] [" + tlsCertPolicy + "] [" + hostname
+ "] [" + tlsAlpnProtocols + "]";
+ "] [" + tlsAlpnProtocols + "] [" + tlsEllipticCurves + "]";
}
public static Builder builder(String uri) {
@ -161,6 +166,7 @@ public class PeerConnection {
private TlsCertPolicy tlsCertPolicy = TlsCertPolicy.TLS_CERT_POLICY_SECURE;
private String hostname = "";
private List<String> tlsAlpnProtocols;
private List<String> tlsEllipticCurves;
private Builder(String uri) {
this.uri = uri;
@ -191,8 +197,14 @@ public class PeerConnection {
return this;
}
public Builder setTlsEllipticCurves(List<String> tlsEllipticCurves) {
this.tlsEllipticCurves = tlsEllipticCurves;
return this;
}
public IceServer createIceServer() {
return new IceServer(uri, username, password, tlsCertPolicy, hostname, tlsAlpnProtocols);
return new IceServer(
uri, username, password, tlsCertPolicy, hostname, tlsAlpnProtocols, tlsEllipticCurves);
}
}
}

View File

@ -364,6 +364,8 @@ void JavaToNativeIceServers(JNIEnv* jni,
GetFieldID(jni, j_ice_server_class, "hostname", "Ljava/lang/String;");
jfieldID j_ice_server_tls_alpn_protocols_id = GetFieldID(
jni, j_ice_server_class, "tlsAlpnProtocols", "Ljava/util/List;");
jfieldID j_ice_server_tls_elliptic_curves_id = GetFieldID(
jni, j_ice_server_class, "tlsEllipticCurves", "Ljava/util/List;");
jstring uri = reinterpret_cast<jstring>(
GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
jstring username = reinterpret_cast<jstring>(
@ -376,6 +378,8 @@ void JavaToNativeIceServers(JNIEnv* jni,
GetObjectField(jni, j_ice_server, j_ice_server_hostname_id));
jobject tls_alpn_protocols = GetNullableObjectField(
jni, j_ice_server, j_ice_server_tls_alpn_protocols_id);
jobject tls_elliptic_curves = GetNullableObjectField(
jni, j_ice_server, j_ice_server_tls_elliptic_curves_id);
PeerConnectionInterface::IceServer server;
server.uri = JavaToStdString(jni, uri);
server.username = JavaToStdString(jni, username);
@ -383,6 +387,8 @@ void JavaToNativeIceServers(JNIEnv* jni,
server.tls_cert_policy = tls_cert_policy;
server.hostname = JavaToStdString(jni, hostname);
server.tls_alpn_protocols = JavaToStdVectorStrings(jni, tls_alpn_protocols);
server.tls_elliptic_curves =
JavaToStdVectorStrings(jni, tls_elliptic_curves);
ice_servers->push_back(server);
}
}

View File

@ -20,6 +20,7 @@
@synthesize tlsCertPolicy = _tlsCertPolicy;
@synthesize hostname = _hostname;
@synthesize tlsAlpnProtocols = _tlsAlpnProtocols;
@synthesize tlsEllipticCurves = _tlsEllipticCurves;
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings {
return [self initWithURLStrings:urlStrings
@ -57,7 +58,7 @@
credential:credential
tlsCertPolicy:tlsCertPolicy
hostname:hostname
tlsAlpnProtocols:[NSMutableArray new]];
tlsAlpnProtocols:[NSArray array]];
}
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
@ -66,6 +67,22 @@
tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
hostname:(NSString *)hostname
tlsAlpnProtocols:(NSArray<NSString *> *)tlsAlpnProtocols {
return [self initWithURLStrings:urlStrings
username:username
credential:credential
tlsCertPolicy:tlsCertPolicy
hostname:hostname
tlsAlpnProtocols:tlsAlpnProtocols
tlsEllipticCurves:[NSArray array]];
}
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
username:(NSString *)username
credential:(NSString *)credential
tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
hostname:(NSString *)hostname
tlsAlpnProtocols:(NSArray<NSString *> *)tlsAlpnProtocols
tlsEllipticCurves:(NSArray<NSString *> *)tlsEllipticCurves {
NSParameterAssert(urlStrings.count);
if (self = [super init]) {
_urlStrings = [[NSArray alloc] initWithArray:urlStrings copyItems:YES];
@ -74,18 +91,20 @@
_tlsCertPolicy = tlsCertPolicy;
_hostname = [hostname copy];
_tlsAlpnProtocols = [[NSArray alloc] initWithArray:tlsAlpnProtocols copyItems:YES];
_tlsEllipticCurves = [[NSArray alloc] initWithArray:tlsEllipticCurves copyItems:YES];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCIceServer:\n%@\n%@\n%@\n%@\n%@\n%@",
return [NSString stringWithFormat:@"RTCIceServer:\n%@\n%@\n%@\n%@\n%@\n%@\n%@",
_urlStrings,
_username,
_credential,
[self stringForTlsCertPolicy:_tlsCertPolicy],
_hostname,
_tlsAlpnProtocols];
_tlsAlpnProtocols,
_tlsEllipticCurves];
}
#pragma mark - Private
@ -110,6 +129,10 @@
iceServer.tls_alpn_protocols.push_back(proto.stdString);
}];
[_tlsEllipticCurves enumerateObjectsUsingBlock:^(NSString *curve, NSUInteger idx, BOOL *stop) {
iceServer.tls_elliptic_curves.push_back(curve.stdString);
}];
[_urlStrings enumerateObjectsUsingBlock:^(NSString *url,
NSUInteger idx,
BOOL *stop) {
@ -144,6 +167,11 @@
for (auto const &proto : nativeServer.tls_alpn_protocols) {
[tlsAlpnProtocols addObject:[NSString stringForStdString:proto]];
}
NSMutableArray *tlsEllipticCurves =
[NSMutableArray arrayWithCapacity:nativeServer.tls_elliptic_curves.size()];
for (auto const &curve : nativeServer.tls_elliptic_curves) {
[tlsEllipticCurves addObject:[NSString stringForStdString:curve]];
}
RTCTlsCertPolicy tlsCertPolicy;
switch (nativeServer.tls_cert_policy) {
@ -160,7 +188,8 @@
credential:credential
tlsCertPolicy:tlsCertPolicy
hostname:hostname
tlsAlpnProtocols:tlsAlpnProtocols];
tlsAlpnProtocols:tlsAlpnProtocols
tlsEllipticCurves:tlsEllipticCurves];
return self;
}

View File

@ -46,6 +46,12 @@ RTC_EXPORT
/** List of protocols to be used in the TLS ALPN extension. */
@property(nonatomic, readonly) NSArray<NSString *> *tlsAlpnProtocols;
/**
List elliptic curves to be used in the TLS elliptic curves extension.
Only curve names supported by OpenSSL should be used (eg. "P-256","X25519").
*/
@property(nonatomic, readonly) NSArray<NSString *> *tlsEllipticCurves;
- (nonnull instancetype)init NS_UNAVAILABLE;
/** Convenience initializer for a server with no authentication (e.g. STUN). */
@ -87,7 +93,20 @@ RTC_EXPORT
credential:(nullable NSString *)credential
tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
hostname:(nullable NSString *)hostname
tlsAlpnProtocols:(NSArray<NSString *> *)tlsAlpnProtocols
tlsAlpnProtocols:(NSArray<NSString *> *)tlsAlpnProtocols;
/**
* Initialize an RTCIceServer with its associated URLs, optional username,
* optional credential, TLS cert policy, hostname, ALPN protocols and
* elliptic curves.
*/
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
username:(nullable NSString *)username
credential:(nullable NSString *)credential
tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
hostname:(nullable NSString *)hostname
tlsAlpnProtocols:(nullable NSArray<NSString *> *)tlsAlpnProtocols
tlsEllipticCurves:(nullable NSArray<NSString *> *)tlsEllipticCurves
NS_DESIGNATED_INITIALIZER;
@end

View File

@ -92,6 +92,24 @@
EXPECT_EQ(2u, iceStruct.tls_alpn_protocols.size());
}
- (void)testTlsEllipticCurves {
RTCIceServer *server = [[RTCIceServer alloc] initWithURLStrings:@[ @"turn1:turn1.example.net" ]
username:@"username"
credential:@"credential"
tlsCertPolicy:RTCTlsCertPolicySecure
hostname:@"hostname"
tlsAlpnProtocols:@[ @"proto1", @"proto2" ]
tlsEllipticCurves:@[ @"curve1", @"curve2" ]];
webrtc::PeerConnectionInterface::IceServer iceStruct = server.nativeServer;
EXPECT_EQ(1u, iceStruct.urls.size());
EXPECT_EQ("turn1:turn1.example.net", iceStruct.urls.front());
EXPECT_EQ("username", iceStruct.username);
EXPECT_EQ("credential", iceStruct.password);
EXPECT_EQ("hostname", iceStruct.hostname);
EXPECT_EQ(2u, iceStruct.tls_alpn_protocols.size());
EXPECT_EQ(2u, iceStruct.tls_elliptic_curves.size());
}
- (void)testInitFromNativeServer {
webrtc::PeerConnectionInterface::IceServer nativeServer;
nativeServer.username = "username";
@ -100,6 +118,8 @@
nativeServer.hostname = "hostname";
nativeServer.tls_alpn_protocols.push_back("proto1");
nativeServer.tls_alpn_protocols.push_back("proto2");
nativeServer.tls_elliptic_curves.push_back("curve1");
nativeServer.tls_elliptic_curves.push_back("curve2");
RTCIceServer *iceServer =
[[RTCIceServer alloc] initWithNativeServer:nativeServer];
@ -110,6 +130,7 @@
EXPECT_EQ("password", [NSString stdStringForString:iceServer.credential]);
EXPECT_EQ("hostname", [NSString stdStringForString:iceServer.hostname]);
EXPECT_EQ(2u, iceServer.tlsAlpnProtocols.count);
EXPECT_EQ(2u, iceServer.tlsEllipticCurves.count);
}
@end