From 4f085434b912060874d6697f17aaedd2adae7c49 Mon Sep 17 00:00:00 2001 From: Diogo Real Date: Tue, 11 Sep 2018 16:00:22 -0700 Subject: [PATCH] Add SSLConfig object to IceServer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a rollforward of https://webrtc-review.googlesource.com/c/src/+/96020, with the addition of setting the old tlsCertPolicy, tlsAlpnProtocols and tlsEllipticCurves in the RTCIceServer initializer, for backwards compatibility. Bug: webrtc:9662 Change-Id: I28706ed4ff5abe3f7f913f105779f0e5412aeac5 Reviewed-on: https://webrtc-review.googlesource.com/98762 Commit-Queue: Diogo Real Reviewed-by: Sami Kalliomäki Reviewed-by: Kári Helgason Reviewed-by: Steve Anton Reviewed-by: Qingsi Wang Cr-Commit-Position: refs/heads/master@{#24696} --- api/peerconnectioninterface.h | 10 +- p2p/base/basicpacketsocketfactory.cc | 7 +- p2p/base/packetsocketfactory.h | 7 +- p2p/base/port_unittest.cc | 3 +- p2p/base/portallocator.h | 24 ++- p2p/base/testturnserver.h | 7 +- p2p/base/turnport.cc | 72 +++++-- p2p/base/turnport.h | 55 ++++- p2p/base/turnport_unittest.cc | 19 +- p2p/client/turnportfactory.cc | 17 +- pc/iceserverparsing.cc | 18 +- pc/iceserverparsing_unittest.cc | 8 +- rtc_base/openssladapter.cc | 58 +++-- rtc_base/openssladapter.h | 15 +- rtc_base/ssladapter.cc | 6 + rtc_base/ssladapter.h | 61 +++++- rtc_base/ssladapter_unittest.cc | 170 +++++++++++++-- sdk/BUILD.gn | 4 + sdk/android/BUILD.gn | 4 + .../api/org/webrtc/PeerConnection.java | 38 +++- sdk/android/api/org/webrtc/SslConfig.java | 204 ++++++++++++++++++ sdk/android/src/jni/pc/peerconnection.cc | 4 + sdk/android/src/jni/pc/sslconfig.cc | 78 +++++++ sdk/android/src/jni/pc/sslconfig.h | 30 +++ .../Framework/Headers/WebRTC/RTCSSLConfig.h | 11 + sdk/objc/api/peerconnection/RTCIceServer.h | 33 ++- sdk/objc/api/peerconnection/RTCIceServer.mm | 86 +++++--- .../api/peerconnection/RTCSSLConfig+Native.h | 27 +++ sdk/objc/api/peerconnection/RTCSSLConfig.h | 56 +++++ sdk/objc/api/peerconnection/RTCSSLConfig.mm | 134 ++++++++++++ sdk/objc/unittests/RTCIceServerTest.mm | 10 +- 31 files changed, 1093 insertions(+), 183 deletions(-) create mode 100644 sdk/android/api/org/webrtc/SslConfig.java create mode 100644 sdk/android/src/jni/pc/sslconfig.cc create mode 100644 sdk/android/src/jni/pc/sslconfig.h create mode 100644 sdk/objc/Framework/Headers/WebRTC/RTCSSLConfig.h create mode 100644 sdk/objc/api/peerconnection/RTCSSLConfig+Native.h create mode 100644 sdk/objc/api/peerconnection/RTCSSLConfig.h create mode 100644 sdk/objc/api/peerconnection/RTCSSLConfig.mm diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h index 1c32b69692..c6e5a25b5b 100644 --- a/api/peerconnectioninterface.h +++ b/api/peerconnectioninterface.h @@ -112,6 +112,7 @@ #include "rtc_base/rtccertificate.h" #include "rtc_base/rtccertificategenerator.h" #include "rtc_base/socketaddress.h" +#include "rtc_base/ssladapter.h" #include "rtc_base/sslcertificate.h" #include "rtc_base/sslstreamadapter.h" @@ -187,6 +188,7 @@ class PeerConnectionInterface : public rtc::RefCountInterface { kIceConnectionMax, }; + // Deprecated. TODO(diogor, webrtc:9673): Remove from API. // TLS certificate policy. enum TlsCertPolicy { // For TLS based protocols, ensure the connection is secure by not @@ -211,23 +213,29 @@ class PeerConnectionInterface : public rtc::RefCountInterface { std::vector urls; std::string username; std::string password; + // Deprecated. rtc::SSLConfig should be used instead. TlsCertPolicy tls_cert_policy = kTlsCertPolicySecure; // If the URIs in |urls| only contain IP addresses, this field can be used // to indicate the hostname, which may be necessary for TLS (using the SNI // extension). If |urls| itself contains the hostname, this isn't // necessary. std::string hostname; + // Deprecated. rtc::SSLConfig should be used instead. // List of protocols to be used in the TLS ALPN extension. std::vector tls_alpn_protocols; + // Deprecated. rtc::SSLConfig should be used instead. // List of elliptic curves to be used in the TLS elliptic curves extension. std::vector tls_elliptic_curves; + // SSL configuration options for any SSL/TLS connections to this IceServer. + rtc::SSLConfig ssl_config; 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_elliptic_curves == o.tls_elliptic_curves; + tls_elliptic_curves == o.tls_elliptic_curves && + ssl_config == o.ssl_config; } bool operator!=(const IceServer& o) const { return !(*this == o); } }; diff --git a/p2p/base/basicpacketsocketfactory.cc b/p2p/base/basicpacketsocketfactory.cc index b7eb8ed1c6..c80a40852f 100644 --- a/p2p/base/basicpacketsocketfactory.cc +++ b/p2p/base/basicpacketsocketfactory.cc @@ -157,12 +157,7 @@ AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket( return NULL; } - if (tlsOpts & PacketSocketFactory::OPT_TLS_INSECURE) { - ssl_adapter->SetIgnoreBadCert(true); - } - - ssl_adapter->SetAlpnProtocols(tcp_options.tls_alpn_protocols); - ssl_adapter->SetEllipticCurves(tcp_options.tls_elliptic_curves); + ssl_adapter->SetSSLConfig(tcp_options.ssl_config); ssl_adapter->SetCertVerifier(tcp_options.tls_cert_verifier); socket = ssl_adapter; diff --git a/p2p/base/packetsocketfactory.h b/p2p/base/packetsocketfactory.h index 4667bb1fd7..bbde1137a2 100644 --- a/p2p/base/packetsocketfactory.h +++ b/p2p/base/packetsocketfactory.h @@ -14,8 +14,10 @@ #include #include +#include "absl/types/optional.h" #include "rtc_base/constructormagic.h" #include "rtc_base/proxyinfo.h" +#include "rtc_base/ssladapter.h" #include "rtc_base/sslcertificate.h" namespace rtc { @@ -26,11 +28,12 @@ struct PacketSocketTcpOptions { ~PacketSocketTcpOptions(); int opts = 0; - std::vector tls_alpn_protocols; - std::vector tls_elliptic_curves; // An optional custom SSL certificate verifier that an API user can provide to // inject their own certificate verification logic. SSLCertificateVerifier* tls_cert_verifier = nullptr; + + // SSL configuration options. + rtc::SSLConfig ssl_config; }; class AsyncPacketSocket; diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc index 5aaf315363..b2fe9d054b 100644 --- a/p2p/base/port_unittest.cc +++ b/p2p/base/port_unittest.cc @@ -537,8 +537,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::vector(), - nullptr, nullptr); + std::string(), nullptr, rtc::SSLConfig(), nullptr); } RelayPort* CreateGturnPort(const SocketAddress& addr, ProtocolType int_proto, diff --git a/p2p/base/portallocator.h b/p2p/base/portallocator.h index 8bd709642c..356b1f1758 100644 --- a/p2p/base/portallocator.h +++ b/p2p/base/portallocator.h @@ -20,6 +20,7 @@ #include "p2p/base/portinterface.h" #include "rtc_base/helpers.h" #include "rtc_base/proxyinfo.h" +#include "rtc_base/ssladapter.h" #include "rtc_base/sslcertificate.h" #include "rtc_base/third_party/sigslot/sigslot.h" #include "rtc_base/thread.h" @@ -118,17 +119,6 @@ enum : uint32_t { CF_ALL = 0x7, }; -// TLS certificate policy. -enum class TlsCertPolicy { - // For TLS based protocols, ensure the connection is secure by not - // circumventing certificate validation. - TLS_CERT_POLICY_SECURE, - // For TLS based protocols, disregard security completely by skipping - // certificate validation. This is insecure and should never be used unless - // security is irrelevant in that particular context. - TLS_CERT_POLICY_INSECURE_NO_CHECK, -}; - // TODO(deadbeef): Rename to TurnCredentials (and username to ufrag). struct RelayCredentials { RelayCredentials() {} @@ -144,6 +134,17 @@ struct RelayCredentials { std::string password; }; +// TLS certificate policy. +enum class TlsCertPolicy { + // For TLS based protocols, ensure the connection is secure by not + // circumventing certificate validation. + TLS_CERT_POLICY_SECURE, + // For TLS based protocols, disregard security completely by skipping + // certificate validation. This is insecure and should never be used unless + // security is irrelevant in that particular context. + TLS_CERT_POLICY_INSECURE_NO_CHECK, +}; + typedef std::vector PortList; // TODO(deadbeef): Rename to TurnServerConfig. struct RelayServerConfig { @@ -180,6 +181,7 @@ struct RelayServerConfig { TlsCertPolicy tls_cert_policy = TlsCertPolicy::TLS_CERT_POLICY_SECURE; std::vector tls_alpn_protocols; std::vector tls_elliptic_curves; + rtc::SSLConfig ssl_config; rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr; }; diff --git a/p2p/base/testturnserver.h b/p2p/base/testturnserver.h index 734ca4d972..61a2e10d11 100644 --- a/p2p/base/testturnserver.h +++ b/p2p/base/testturnserver.h @@ -110,7 +110,12 @@ class TestTurnServer : public TurnAuthInterface { adapter->SetRole(rtc::SSL_SERVER); adapter->SetIdentity( rtc::SSLIdentity::Generate(common_name, rtc::KeyParams())); - adapter->SetIgnoreBadCert(ignore_bad_cert); + rtc::SSLConfig ssl_config; + if (ignore_bad_cert) { + ssl_config.tls_cert_policy = + rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + } + adapter->SetSSLConfig(ssl_config); socket = adapter; } socket->Bind(int_addr); diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc index 0883534538..a406d13601 100644 --- a/p2p/base/turnport.cc +++ b/p2p/base/turnport.cc @@ -244,8 +244,47 @@ TurnPort::TurnPort(rtc::Thread* thread, username, password), server_address_(server_address), - tls_alpn_protocols_(tls_alpn_protocols), - tls_elliptic_curves_(tls_elliptic_curves), + tls_cert_verifier_(tls_cert_verifier), + credentials_(credentials), + socket_(NULL), + resolver_(NULL), + error_(0), + request_manager_(thread), + next_channel_number_(TURN_CHANNEL_NUMBER_START), + state_(STATE_CONNECTING), + server_priority_(server_priority), + allocate_mismatch_retries_(0), + turn_customizer_(customizer) { + ssl_config_.tls_alpn_protocols = tls_alpn_protocols; + ssl_config_.tls_elliptic_curves = tls_elliptic_curves; + request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); + request_manager_.set_origin(origin); +} + +TurnPort::TurnPort(rtc::Thread* thread, + rtc::PacketSocketFactory* factory, + rtc::Network* network, + uint16_t min_port, + uint16_t max_port, + const std::string& username, + const std::string& password, + const ProtocolAddress& server_address, + const RelayCredentials& credentials, + int server_priority, + const std::string& origin, + webrtc::TurnCustomizer* customizer, + const rtc::SSLConfig& ssl_config, + rtc::SSLCertificateVerifier* tls_cert_verifier) + : Port(thread, + RELAY_PORT_TYPE, + factory, + network, + min_port, + max_port, + username, + password), + server_address_(server_address), + ssl_config_(ssl_config), tls_cert_verifier_(tls_cert_verifier), credentials_(credentials), socket_(NULL), @@ -289,20 +328,20 @@ ProtocolType TurnPort::GetProtocol() const { return server_address_.proto; } -TlsCertPolicy TurnPort::GetTlsCertPolicy() const { - return tls_cert_policy_; -} - void TurnPort::SetTlsCertPolicy(TlsCertPolicy tls_cert_policy) { - tls_cert_policy_ = tls_cert_policy; + switch (tls_cert_policy) { + case TlsCertPolicy::TLS_CERT_POLICY_SECURE: + ssl_config_.tls_cert_policy = rtc::TlsCertPolicy::TLS_CERT_POLICY_SECURE; + break; + case TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK: + ssl_config_.tls_cert_policy = + rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + break; + } } -std::vector TurnPort::GetTlsAlpnProtocols() const { - return tls_alpn_protocols_; -} - -std::vector TurnPort::GetTlsEllipticCurves() const { - return tls_elliptic_curves_; +const rtc::SSLConfig& TurnPort::GetSslConfig() const { + return ssl_config_; } void TurnPort::PrepareAddress() { @@ -362,8 +401,8 @@ bool TurnPort::CreateTurnClientSocket() { // Apply server address TLS and insecure bits to options. if (server_address_.proto == PROTO_TLS) { - if (tls_cert_policy_ == - TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK) { + if (ssl_config_.tls_cert_policy == + rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK) { opts |= rtc::PacketSocketFactory::OPT_TLS_INSECURE; } else { opts |= rtc::PacketSocketFactory::OPT_TLS; @@ -372,9 +411,8 @@ 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_; tcp_options.tls_cert_verifier = tls_cert_verifier_; + tcp_options.ssl_config = ssl_config_; socket_ = socket_factory()->CreateClientTcpSocket( rtc::SocketAddress(Network()->GetBestIP(), 0), server_address_.address, proxy(), user_agent(), tcp_options); diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h index 5955aafda1..0d9192f611 100644 --- a/p2p/base/turnport.h +++ b/p2p/base/turnport.h @@ -22,6 +22,7 @@ #include "p2p/client/basicportallocator.h" #include "rtc_base/asyncinvoker.h" #include "rtc_base/asyncpacketsocket.h" +#include "rtc_base/ssladapter.h" #include "rtc_base/sslcertificate.h" namespace rtc { @@ -66,6 +67,7 @@ class TurnPort : public Port { customizer); } + // Deprecated. TODO(diogor, webrtc:9673): Remove this constructor. // Create a TURN port that will use a new socket, bound to |network| and // using a port in the range between |min_port| and |max_port|. static TurnPort* Create( @@ -84,10 +86,34 @@ class TurnPort : public Port { const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr) { + rtc::SSLConfig ssl_config; + ssl_config.tls_alpn_protocols = tls_alpn_protocols; + ssl_config.tls_elliptic_curves = tls_elliptic_curves; return new TurnPort(thread, factory, network, min_port, max_port, username, password, server_address, credentials, server_priority, - origin, tls_alpn_protocols, tls_elliptic_curves, - customizer, tls_cert_verifier); + origin, customizer, ssl_config, tls_cert_verifier); + } + + // Create a TURN port that will use a new socket, bound to |network| and + // using a port in the range between |min_port| and |max_port|. + static TurnPort* Create( + rtc::Thread* thread, + rtc::PacketSocketFactory* factory, + rtc::Network* network, + uint16_t min_port, + uint16_t max_port, + const std::string& username, // ice username. + const std::string& password, // ice password. + const ProtocolAddress& server_address, + const RelayCredentials& credentials, + int server_priority, + const std::string& origin, + webrtc::TurnCustomizer* customizer, + const rtc::SSLConfig& ssl_config, + rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr) { + return new TurnPort(thread, factory, network, min_port, max_port, username, + password, server_address, credentials, server_priority, + origin, customizer, ssl_config, tls_cert_verifier); } ~TurnPort() override; @@ -104,11 +130,11 @@ class TurnPort : public Port { ProtocolType GetProtocol() const override; - virtual TlsCertPolicy GetTlsCertPolicy() const; + // Deprecated. SSLConfig should be used instead. + // TODO(diogor, webrtc:9673): Remove this. virtual void SetTlsCertPolicy(TlsCertPolicy tls_cert_policy); - virtual std::vector GetTlsAlpnProtocols() const; - virtual std::vector GetTlsEllipticCurves() const; + virtual const rtc::SSLConfig& GetSslConfig() const; // Release a TURN allocation by sending a refresh with lifetime 0. // Sets state to STATE_RECEIVEONLY. @@ -220,6 +246,21 @@ class TurnPort : public Port { webrtc::TurnCustomizer* customizer, rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr); + TurnPort(rtc::Thread* thread, + rtc::PacketSocketFactory* factory, + rtc::Network* network, + uint16_t min_port, + uint16_t max_port, + const std::string& username, + const std::string& password, + const ProtocolAddress& server_address, + const RelayCredentials& credentials, + int server_priority, + const std::string& origin, + webrtc::TurnCustomizer* customizer, + const rtc::SSLConfig& ssl_config, + rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr); + // NOTE: This method needs to be accessible for StacPort // return true if entry was created (i.e channel_number consumed). bool CreateOrRefreshEntry(const rtc::SocketAddress& addr, @@ -304,9 +345,7 @@ class TurnPort : public Port { size_t size, bool payload); ProtocolAddress server_address_; - TlsCertPolicy tls_cert_policy_ = TlsCertPolicy::TLS_CERT_POLICY_SECURE; - std::vector tls_alpn_protocols_; - std::vector tls_elliptic_curves_; + rtc::SSLConfig ssl_config_; rtc::SSLCertificateVerifier* tls_cert_verifier_; RelayCredentials credentials_; AttemptedServerSet attempted_server_addresses_; diff --git a/p2p/base/turnport_unittest.cc b/p2p/base/turnport_unittest.cc index bac35e891c..73f469d713 100644 --- a/p2p/base/turnport_unittest.cc +++ b/p2p/base/turnport_unittest.cc @@ -270,21 +270,16 @@ class TurnPortTest : public testing::Test, const ProtocolAddress& server_address, const std::string& origin) { 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::vector(), turn_customizer_.get())); + rtc::SSLConfig ssl_config; + ssl_config.tls_cert_policy = + rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + turn_port_.reset(TurnPort::Create(&main_, &socket_factory_, network, 0, 0, + kIceUfrag1, kIcePwd1, server_address, + credentials, 0, origin, + turn_customizer_.get(), ssl_config)); // This TURN port will be the controlling. turn_port_->SetIceRole(ICEROLE_CONTROLLING); ConnectSignals(); - - if (server_address.proto == cricket::PROTO_TLS) { - // The test TURN server has a self-signed certificate so will not pass - // the normal client validation. Instruct the client to ignore certificate - // errors for testing only. - turn_port_->SetTlsCertPolicy( - TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK); - } } void CreateSharedTurnPort(const std::string& username, diff --git a/p2p/client/turnportfactory.cc b/p2p/client/turnportfactory.cc index 6404134c4a..68ceff4fa3 100644 --- a/p2p/client/turnportfactory.cc +++ b/p2p/client/turnportfactory.cc @@ -26,20 +26,29 @@ std::unique_ptr TurnPortFactory::Create( args.username, args.password, *args.server_address, args.config->credentials, args.config->priority, args.origin, args.turn_customizer); - port->SetTlsCertPolicy(args.config->tls_cert_policy); return std::unique_ptr(port); } std::unique_ptr TurnPortFactory::Create(const CreateRelayPortArgs& args, int min_port, int max_port) { + rtc::SSLConfig ssl_config = args.config->ssl_config; + if (!args.config->tls_alpn_protocols.empty()) { + ssl_config.tls_alpn_protocols = args.config->tls_alpn_protocols; + } + if (!args.config->tls_elliptic_curves.empty()) { + ssl_config.tls_elliptic_curves = args.config->tls_elliptic_curves; + } + if (args.config->tls_cert_policy == + TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK) { + ssl_config.tls_cert_policy = + rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + } TurnPort* port = TurnPort::Create( args.network_thread, args.socket_factory, args.network, min_port, max_port, args.username, args.password, *args.server_address, args.config->credentials, args.config->priority, args.origin, - args.config->tls_alpn_protocols, args.config->tls_elliptic_curves, - args.turn_customizer, args.config->tls_cert_verifier); - port->SetTlsCertPolicy(args.config->tls_cert_policy); + args.turn_customizer, ssl_config, args.config->tls_cert_verifier); return std::unique_ptr(port); } diff --git a/pc/iceserverparsing.cc b/pc/iceserverparsing.cc index 806fb3bc21..74d1ed2306 100644 --- a/pc/iceserverparsing.cc +++ b/pc/iceserverparsing.cc @@ -14,6 +14,7 @@ #include #include "rtc_base/arraysize.h" +#include "rtc_base/ssladapter.h" namespace webrtc { @@ -254,13 +255,22 @@ static RTCErrorType ParseIceServerUrl( } cricket::RelayServerConfig config = cricket::RelayServerConfig( socket_address, username, server.password, turn_transport_type); + + config.ssl_config = server.ssl_config; + if (server.tls_cert_policy == PeerConnectionInterface::kTlsCertPolicyInsecureNoCheck) { - config.tls_cert_policy = - cricket::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + config.ssl_config.tls_cert_policy = + rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + } + if (!server.ssl_config.tls_alpn_protocols.has_value() && + !server.tls_alpn_protocols.empty()) { + config.ssl_config.tls_alpn_protocols = server.tls_alpn_protocols; + } + if (!server.ssl_config.tls_elliptic_curves.has_value() && + !server.tls_elliptic_curves.empty()) { + config.ssl_config.tls_elliptic_curves = server.tls_elliptic_curves; } - config.tls_alpn_protocols = server.tls_alpn_protocols; - config.tls_elliptic_curves = server.tls_elliptic_curves; turn_servers->push_back(config); break; diff --git a/pc/iceserverparsing_unittest.cc b/pc/iceserverparsing_unittest.cc index 4ec7a891df..b95f9a5c00 100644 --- a/pc/iceserverparsing_unittest.cc +++ b/pc/iceserverparsing_unittest.cc @@ -86,16 +86,16 @@ TEST_F(IceServerParsingTest, ParseStunPrefixes) { EXPECT_EQ(0U, stun_servers_.size()); EXPECT_EQ(1U, turn_servers_.size()); EXPECT_EQ(cricket::PROTO_TLS, turn_servers_[0].ports[0].proto); - EXPECT_TRUE(turn_servers_[0].tls_cert_policy == - cricket::TlsCertPolicy::TLS_CERT_POLICY_SECURE); + EXPECT_TRUE(turn_servers_[0].ssl_config.tls_cert_policy == + rtc::TlsCertPolicy::TLS_CERT_POLICY_SECURE); EXPECT_TRUE(ParseUrl( "turns:hostname", "username", "password", PeerConnectionInterface::TlsCertPolicy::kTlsCertPolicyInsecureNoCheck)); EXPECT_EQ(0U, stun_servers_.size()); EXPECT_EQ(1U, turn_servers_.size()); - EXPECT_TRUE(turn_servers_[0].tls_cert_policy == - cricket::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK); + EXPECT_TRUE(turn_servers_[0].ssl_config.tls_cert_policy == + rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK); EXPECT_EQ(cricket::PROTO_TLS, turn_servers_[0].ports[0].proto); // invalid prefixes diff --git a/rtc_base/openssladapter.cc b/rtc_base/openssladapter.cc index 50284a6719..2662b37a97 100644 --- a/rtc_base/openssladapter.cc +++ b/rtc_base/openssladapter.cc @@ -209,7 +209,6 @@ OpenSSLAdapter::OpenSSLAdapter(AsyncSocket* socket, ssl_(nullptr), ssl_ctx_(nullptr), ssl_mode_(SSL_MODE_TLS), - ignore_bad_cert_(false), custom_cert_verifier_status_(false) { // If a factory is used, take a reference on the factory's SSL_CTX. // Otherwise, we'll create our own later. @@ -226,16 +225,8 @@ OpenSSLAdapter::~OpenSSLAdapter() { Cleanup(); } -void OpenSSLAdapter::SetIgnoreBadCert(bool ignore) { - ignore_bad_cert_ = ignore; -} - -void OpenSSLAdapter::SetAlpnProtocols(const std::vector& protos) { - alpn_protocols_ = protos; -} - -void OpenSSLAdapter::SetEllipticCurves(const std::vector& curves) { - elliptic_curves_ = curves; +void OpenSSLAdapter::SetSSLConfig(const SSLConfig& ssl_config) { + ssl_config_ = ssl_config; } void OpenSSLAdapter::SetMode(SSLMode mode) { @@ -269,7 +260,7 @@ AsyncSocket* OpenSSLAdapter::Accept(SocketAddress* paddr) { SSLAdapter* adapter = SSLAdapter::Create(socket); adapter->SetIdentity(identity_->GetReference()); adapter->SetRole(rtc::SSL_SERVER); - adapter->SetIgnoreBadCert(ignore_bad_cert_); + adapter->SetSSLConfig(ssl_config_); adapter->StartSSL("", false); return adapter; } @@ -367,13 +358,28 @@ int OpenSSLAdapter::BeginSSL() { } #ifdef OPENSSL_IS_BORINGSSL - // Set a couple common TLS extensions; even though we don't use them yet. - SSL_enable_ocsp_stapling(ssl_); - SSL_enable_signed_cert_timestamps(ssl_); + // Potentially set a couple common TLS extensions; even though we don't use + // them yet. + if (ssl_config_.enable_ocsp_stapling) { + SSL_enable_ocsp_stapling(ssl_); + } + if (ssl_config_.enable_signed_cert_timestamp) { + SSL_enable_signed_cert_timestamps(ssl_); + } + SSL_CTX_set_grease_enabled(ssl_ctx_, ssl_config_.enable_grease); #endif - if (!alpn_protocols_.empty()) { - std::string tls_alpn_string = TransformAlpnProtocols(alpn_protocols_); + if (ssl_config_.max_ssl_version.has_value()) { + SSL_set_max_proto_version(ssl_, ssl_config_.max_ssl_version.value()); + } + + if (ssl_config_.enable_tls_channel_id) { + SSL_enable_tls_channel_id(ssl_); + } + + if (ssl_config_.tls_alpn_protocols.has_value()) { + std::string tls_alpn_string = + TransformAlpnProtocols(ssl_config_.tls_alpn_protocols.value()); if (!tls_alpn_string.empty()) { SSL_set_alpn_protos( ssl_, reinterpret_cast(tls_alpn_string.data()), @@ -381,8 +387,9 @@ int OpenSSLAdapter::BeginSSL() { } } - if (!elliptic_curves_.empty()) { - SSL_set1_curves_list(ssl_, rtc::join(elliptic_curves_, ':').c_str()); + if (ssl_config_.tls_elliptic_curves.has_value()) { + SSL_set1_curves_list( + ssl_, rtc::join(ssl_config_.tls_elliptic_curves.value(), ':').c_str()); } // Now that the initial config is done, transfer ownership of |bio| to the @@ -794,10 +801,10 @@ bool OpenSSLAdapter::SSLPostConnectionCheck(SSL* ssl, const std::string& host) { openssl::VerifyPeerCertMatchesHost(ssl, host) && (SSL_get_verify_result(ssl) == X509_V_OK || custom_cert_verifier_status_); - if (!is_valid_cert_name && ignore_bad_cert_) { + if (!is_valid_cert_name && ShouldIgnoreBadCert()) { RTC_DLOG(LS_WARNING) << "Other TLS post connection checks failed. " - "ignore_bad_cert_ set to true. Overriding name " - "verification failure!"; + "TLS cert policy set to ignore bad certs. " + "Overriding name verification failure!"; is_valid_cert_name = true; } return is_valid_cert_name; @@ -870,7 +877,7 @@ int OpenSSLAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) { } // Should only be used for debugging and development. - if (!ok && stream->ignore_bad_cert_) { + if (!ok && stream->ShouldIgnoreBadCert()) { RTC_DLOG(LS_WARNING) << "Ignoring cert error while verifying cert chain"; ok = 1; } @@ -941,6 +948,11 @@ SSL_CTX* OpenSSLAdapter::CreateContext(SSLMode mode, bool enable_cache) { return ctx; } +bool OpenSSLAdapter::ShouldIgnoreBadCert() { + return ssl_config_.tls_cert_policy == + TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; +} + std::string TransformAlpnProtocols( const std::vector& alpn_protocols) { // Transforms the alpn_protocols list to the format expected by diff --git a/rtc_base/openssladapter.h b/rtc_base/openssladapter.h index 50a7c0845c..9455f0f200 100644 --- a/rtc_base/openssladapter.h +++ b/rtc_base/openssladapter.h @@ -45,9 +45,7 @@ class OpenSSLAdapter : public SSLAdapter, public MessageHandler { SSLCertificateVerifier* ssl_cert_verifier = nullptr); ~OpenSSLAdapter() override; - void SetIgnoreBadCert(bool ignore) override; - void SetAlpnProtocols(const std::vector& protos) override; - void SetEllipticCurves(const std::vector& curves) override; + void SetSSLConfig(const SSLConfig& ssl_config) override; void SetMode(SSLMode mode) override; void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) override; void SetIdentity(SSLIdentity* identity) override; @@ -95,6 +93,9 @@ class OpenSSLAdapter : public SSLAdapter, public MessageHandler { void Error(const char* context, int err, bool signal = true); void Cleanup(); + // If true, the server certificate need not match the configured hostname. + bool ShouldIgnoreBadCert(); + // Return value and arguments have the same meanings as for Send; |error| is // an output parameter filled with the result of SSL_get_error. int DoSslWrite(const void* pv, size_t cb, int* error); @@ -138,12 +139,8 @@ class OpenSSLAdapter : public SSLAdapter, public MessageHandler { std::string ssl_host_name_; // Set the adapter to DTLS or TLS mode before creating the context. SSLMode ssl_mode_; - // If true, the server certificate need not match the configured hostname. - bool ignore_bad_cert_; - // List of protocols to be used in the TLS ALPN extension. - std::vector alpn_protocols_; - // List of elliptic curves to be used in the TLS elliptic curves extension. - std::vector elliptic_curves_; + // SSL configuration for this session. + SSLConfig ssl_config_; // Holds the result of the call to run of the ssl_cert_verify_->Verify() bool custom_cert_verifier_status_; }; diff --git a/rtc_base/ssladapter.cc b/rtc_base/ssladapter.cc index e091f00520..debbd65f94 100644 --- a/rtc_base/ssladapter.cc +++ b/rtc_base/ssladapter.cc @@ -16,6 +16,12 @@ namespace rtc { +SSLConfig::SSLConfig() = default; +SSLConfig::SSLConfig(const SSLConfig&) = default; +SSLConfig::~SSLConfig() = default; + +/////////////////////////////////////////////////////////////////////////////// + SSLAdapterFactory* SSLAdapterFactory::Create() { return new OpenSSLAdapterFactory(); } diff --git a/rtc_base/ssladapter.h b/rtc_base/ssladapter.h index 4843d264fc..33f008ca43 100644 --- a/rtc_base/ssladapter.h +++ b/rtc_base/ssladapter.h @@ -22,6 +22,57 @@ namespace rtc { class SSLAdapter; +// TLS certificate policy. +enum class TlsCertPolicy { + // For TLS based protocols, ensure the connection is secure by not + // circumventing certificate validation. + TLS_CERT_POLICY_SECURE, + // For TLS based protocols, disregard security completely by skipping + // certificate validation. This is insecure and should never be used unless + // security is irrelevant in that particular context. + // Do not set to this value in production code. + // TODO(juberti): Remove the opportunistic encryption mechanism in + // BasicPacketSocketFactory that uses this value. + TLS_CERT_POLICY_INSECURE_NO_CHECK, +}; + +// SSL configuration options. +struct SSLConfig final { + SSLConfig(); + SSLConfig(const SSLConfig&); + ~SSLConfig(); + + bool operator==(const SSLConfig& o) const { + return enable_ocsp_stapling == o.enable_ocsp_stapling && + enable_signed_cert_timestamp == o.enable_signed_cert_timestamp && + enable_tls_channel_id == o.enable_tls_channel_id && + enable_grease == o.enable_grease && + max_ssl_version == o.max_ssl_version && + tls_alpn_protocols == o.tls_alpn_protocols && + tls_elliptic_curves == o.tls_elliptic_curves; + } + bool operator!=(const SSLConfig& o) const { return !(*this == o); } + + // If true, enables the (unused) OCSP stapling TLS extension. + bool enable_ocsp_stapling = true; + // If true, enables the (unused) signed certificate timestamp TLS extension. + bool enable_signed_cert_timestamp = true; + // If true, enables the (unused) channel ID TLS extension. + bool enable_tls_channel_id = false; + // If true, enables the (unused) GREASE TLS extension. + bool enable_grease = false; + // Indicates how to process incoming certificates. + TlsCertPolicy tls_cert_policy = TlsCertPolicy::TLS_CERT_POLICY_SECURE; + // If set, indicates the highest supported SSL version. + absl::optional max_ssl_version; + // If set, indicates the list of protocols to be used in the TLS ALPN + // extension. + absl::optional> tls_alpn_protocols; + // If set, indicates the list of curves to be used in the TLS elliptic curves + // extension. + absl::optional> tls_elliptic_curves; +}; + // Class for creating SSL adapters with shared state, e.g., a session cache, // which allows clients to resume SSL sessions to previously-contacted hosts. // Clients should create the factory using Create(), set up the factory as @@ -52,14 +103,8 @@ class SSLAdapter : public AsyncSocketAdapter { public: explicit SSLAdapter(AsyncSocket* socket) : AsyncSocketAdapter(socket) {} - // Methods that control server certificate verification, used in unit tests. - // Do not call these methods in production code. - // 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& protos) = 0; - virtual void SetEllipticCurves(const std::vector& curves) = 0; + // Sets the SSL configuration for this session. + virtual void SetSSLConfig(const SSLConfig& ssl_config) = 0; // Do DTLS or TLS (default is TLS, if unspecified) virtual void SetMode(SSLMode mode) = 0; diff --git a/rtc_base/ssladapter_unittest.cc b/rtc_base/ssladapter_unittest.cc index ec532b1c44..130cf1f08e 100644 --- a/rtc_base/ssladapter_unittest.cc +++ b/rtc_base/ssladapter_unittest.cc @@ -67,7 +67,9 @@ class SSLAdapterTestDummyClient : public sigslot::has_slots<> { // Ignore any certificate errors for the purpose of testing. // Note: We do this only because we don't have a real certificate. // NEVER USE THIS IN PRODUCTION CODE! - ssl_adapter_->SetIgnoreBadCert(true); + ssl_config_.tls_cert_policy = + rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + ssl_adapter_->SetSSLConfig(ssl_config_); ssl_adapter_->SignalReadEvent.connect( this, &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent); @@ -75,22 +77,52 @@ class SSLAdapterTestDummyClient : public sigslot::has_slots<> { this, &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent); } - void SetIgnoreBadCert(bool ignore_bad_cert) { - ssl_adapter_->SetIgnoreBadCert(ignore_bad_cert); + void SetTlsCertPolicy(rtc::TlsCertPolicy tls_cert_policy) { + ssl_config_.tls_cert_policy = tls_cert_policy; + ssl_adapter_->SetSSLConfig(ssl_config_); + } + + void SetEnableOcspStapling(bool enable_ocsp_stapling) { + ssl_config_.enable_ocsp_stapling = enable_ocsp_stapling; + ssl_adapter_->SetSSLConfig(ssl_config_); + } + + void SetEnableSignedCertTimestamp(bool enable_signed_cert_timestamp) { + ssl_config_.enable_signed_cert_timestamp = enable_signed_cert_timestamp; + ssl_adapter_->SetSSLConfig(ssl_config_); + } + + void SetEnableTlsChannelId(bool enable_tls_channel_id) { + ssl_config_.enable_tls_channel_id = enable_tls_channel_id; + ssl_adapter_->SetSSLConfig(ssl_config_); + } + + void SetEnableGrease(bool enable_grease) { + ssl_config_.enable_grease = enable_grease; + ssl_adapter_->SetSSLConfig(ssl_config_); + } + + void SetMaxSslVersion(const absl::optional& max_ssl_version) { + ssl_config_.max_ssl_version = max_ssl_version; + ssl_adapter_->SetSSLConfig(ssl_config_); + } + + void SetAlpnProtocols( + const absl::optional>& tls_alpn_protocols) { + ssl_config_.tls_alpn_protocols = tls_alpn_protocols; + ssl_adapter_->SetSSLConfig(ssl_config_); + } + + void SetEllipticCurves( + const absl::optional>& tls_elliptic_curves) { + ssl_config_.tls_elliptic_curves = tls_elliptic_curves; + ssl_adapter_->SetSSLConfig(ssl_config_); } void SetCertVerifier(rtc::SSLCertificateVerifier* ssl_cert_verifier) { ssl_adapter_->SetCertVerifier(ssl_cert_verifier); } - void SetAlpnProtocols(const std::vector& protos) { - ssl_adapter_->SetAlpnProtocols(protos); - } - - void SetEllipticCurves(const std::vector& curves) { - ssl_adapter_->SetEllipticCurves(curves); - } - rtc::SocketAddress GetAddress() const { return ssl_adapter_->GetLocalAddress(); } @@ -154,6 +186,8 @@ class SSLAdapterTestDummyClient : public sigslot::has_slots<> { std::unique_ptr ssl_adapter_; + rtc::SSLConfig ssl_config_; + std::string data_; }; @@ -305,29 +339,51 @@ class SSLAdapterTestBase : public testing::Test, public sigslot::has_slots<> { void SetHandshakeWait(int wait) { handshake_wait_ = wait; } - void SetIgnoreBadCert(bool ignore_bad_cert) { - client_->SetIgnoreBadCert(ignore_bad_cert); + void SetTlsCertPolicy(rtc::TlsCertPolicy tls_cert_policy) { + client_->SetTlsCertPolicy(tls_cert_policy); + } + + void SetEnableOcspStapling(bool enable_ocsp_stapling) { + client_->SetEnableOcspStapling(enable_ocsp_stapling); + } + + void SetEnableSignedCertTimestamp(bool enable_signed_cert_timestamp) { + client_->SetEnableSignedCertTimestamp(enable_signed_cert_timestamp); + } + + void SetEnableTlsChannelId(bool enable_tls_channel_id) { + client_->SetEnableTlsChannelId(enable_tls_channel_id); + } + + void SetEnableGrease(bool enable_grease) { + client_->SetEnableGrease(enable_grease); + } + + void SetMaxSslVersion(const absl::optional& max_ssl_version) { + client_->SetMaxSslVersion(max_ssl_version); + } + + void SetAlpnProtocols( + const absl::optional>& tls_alpn_protocols) { + client_->SetAlpnProtocols(tls_alpn_protocols); + } + + void SetEllipticCurves( + const absl::optional>& tls_elliptic_curves) { + client_->SetEllipticCurves(tls_elliptic_curves); } void SetCertVerifier(rtc::SSLCertificateVerifier* ssl_cert_verifier) { client_->SetCertVerifier(ssl_cert_verifier); } - void SetAlpnProtocols(const std::vector& protos) { - client_->SetAlpnProtocols(protos); - } - - void SetEllipticCurves(const std::vector& curves) { - client_->SetEllipticCurves(curves); - } - void SetMockCertVerifier(bool return_value) { auto mock_verifier = absl::make_unique(); EXPECT_CALL(*mock_verifier, Verify(_)).WillRepeatedly(Return(return_value)); cert_verifier_ = std::unique_ptr(std::move(mock_verifier)); - SetIgnoreBadCert(false); + SetTlsCertPolicy(rtc::TlsCertPolicy::TLS_CERT_POLICY_SECURE); SetCertVerifier(cert_verifier_.get()); } @@ -525,6 +581,76 @@ TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransferCustomCertVerifier) { TestTransfer("Hello, world!"); } +// Test transfer with OCSP stapling enabled +TEST_F(SSLAdapterTestTLS_ECDSA, TestOcspStaplingEnabled) { + SetEnableOcspStapling(true); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with OCSP stapling disabled +TEST_F(SSLAdapterTestTLS_ECDSA, TestOcspStaplingDisabled) { + SetEnableOcspStapling(false); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// test transfer with signed cert timestamp enabled +TEST_F(SSLAdapterTestTLS_ECDSA, TestSignedCertTimestampEnabled) { + SetEnableSignedCertTimestamp(true); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with signed cert timestamp disabled +TEST_F(SSLAdapterTestTLS_ECDSA, TestSignedCertTimestampDisabled) { + SetEnableSignedCertTimestamp(false); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with TLS channel ID enabled +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSChannelIdEnabled) { + SetEnableTlsChannelId(true); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with TLS channel ID disabled +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSChannelIdDisabled) { + SetEnableTlsChannelId(false); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with GREASE enabled +TEST_F(SSLAdapterTestTLS_ECDSA, TestGreaseEnabled) { + SetEnableGrease(true); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with GREASE disabled +TEST_F(SSLAdapterTestTLS_ECDSA, TestGreaseDisabled) { + SetEnableGrease(false); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with TLS1_3. +TEST_F(SSLAdapterTestTLS_ECDSA, TestMaxSSLVersionTLS1_3) { + SetMaxSslVersion(0x0304 /* TLS1_3 */); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with TLS1_2. +TEST_F(SSLAdapterTestTLS_ECDSA, TestMaxSSLVersionTLS1_2) { + SetMaxSslVersion(0x0303 /* TLS1_2 */); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + // Test transfer using ALPN with protos as h2 and http/1.1 TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSALPN) { std::vector alpn_protos{"h2", "http/1.1"}; diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 36909e26ae..4930ad5ba0 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -870,6 +870,9 @@ if (is_ios || is_mac) { "objc/api/peerconnection/RTCRtpTransceiver.mm", "objc/api/peerconnection/RTCSSLAdapter.h", "objc/api/peerconnection/RTCSSLAdapter.mm", + "objc/api/peerconnection/RTCSSLConfig+Native.h", + "objc/api/peerconnection/RTCSSLConfig.h", + "objc/api/peerconnection/RTCSSLConfig.mm", "objc/api/peerconnection/RTCSessionDescription+Private.h", "objc/api/peerconnection/RTCSessionDescription.h", "objc/api/peerconnection/RTCSessionDescription.mm", @@ -985,6 +988,7 @@ if (is_ios || is_mac) { "objc/Framework/Headers/WebRTC/RTCRtpSender.h", "objc/Framework/Headers/WebRTC/RTCRtpTransceiver.h", "objc/Framework/Headers/WebRTC/RTCSSLAdapter.h", + "objc/Framework/Headers/WebRTC/RTCSSLConfig.h", "objc/Framework/Headers/WebRTC/RTCSessionDescription.h", "objc/Framework/Headers/WebRTC/RTCTracing.h", "objc/Framework/Headers/WebRTC/RTCVideoCapturer.h", diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 080684aaad..1013f0b012 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -306,6 +306,7 @@ if (is_android) { "api/org/webrtc/RtpSender.java", "api/org/webrtc/RtpTransceiver.java", "api/org/webrtc/SSLCertificateVerifier.java", + "api/org/webrtc/SslConfig.java", "api/org/webrtc/SdpObserver.java", "api/org/webrtc/SessionDescription.java", "api/org/webrtc/StatsObserver.java", @@ -648,6 +649,8 @@ if (is_android) { "src/jni/pc/sessiondescription.h", "src/jni/pc/sslcertificateverifierwrapper.cc", "src/jni/pc/sslcertificateverifierwrapper.h", + "src/jni/pc/sslconfig.cc", + "src/jni/pc/sslconfig.h", "src/jni/pc/statsobserver.cc", "src/jni/pc/statsobserver.h", "src/jni/pc/turncustomizer.cc", @@ -1193,6 +1196,7 @@ if (is_android) { "api/org/webrtc/SSLCertificateVerifier.java", "api/org/webrtc/SdpObserver.java", "api/org/webrtc/SessionDescription.java", + "api/org/webrtc/SslConfig.java", "api/org/webrtc/StatsObserver.java", "api/org/webrtc/StatsReport.java", "api/org/webrtc/TurnCustomizer.java", diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java index 2f9adcf962..2161711575 100644 --- a/sdk/android/api/org/webrtc/PeerConnection.java +++ b/sdk/android/api/org/webrtc/PeerConnection.java @@ -50,6 +50,7 @@ public class PeerConnection { } } + // TODO(diogor, webrtc:9673): Remove TlsCertPolicy. It's deprecated, in favor of SslConfig. /** Tracks PeerConnectionInterface::TlsCertPolicy */ public enum TlsCertPolicy { TLS_CERT_POLICY_SECURE, @@ -126,7 +127,9 @@ public class PeerConnection { public final List urls; public final String username; public final String password; - public final TlsCertPolicy tlsCertPolicy; + // TODO(diogor, webrtc:9673): Remove tlsCertPolicy from this API. + // This field will be ignored if tlsCertPolicy is also set in SslConfig. + @Deprecated public final TlsCertPolicy tlsCertPolicy; // If the URIs in |urls| only contain IP addresses, this field can be used // to indicate the hostname, which may be necessary for TLS (using the SNI @@ -134,12 +137,18 @@ public class PeerConnection { // necessary. public final String hostname; + // TODO(diogor, webrtc:9673): Remove tlsAlpnProtocols from this API. // List of protocols to be used in the TLS ALPN extension. - public final List tlsAlpnProtocols; + @Deprecated public final List tlsAlpnProtocols; + // TODO(diogor, webrtc:9673): Remove tlsEllipticCurves from this API. // 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 tlsEllipticCurves; + // This field will be ignored if tlsEllipticCurves is also set in SslConfig. + @Deprecated public final List tlsEllipticCurves; + + // SSL configuration options for any SSL/TLS connections to this IceServer. + public final SslConfig sslConfig; /** Convenience constructor for STUN servers. */ @Deprecated @@ -161,12 +170,12 @@ public class PeerConnection { public IceServer(String uri, String username, String password, TlsCertPolicy tlsCertPolicy, String hostname) { this(uri, Collections.singletonList(uri), username, password, tlsCertPolicy, hostname, null, - null); + null, SslConfig.builder().createSslConfig()); } private IceServer(String uri, List urls, String username, String password, TlsCertPolicy tlsCertPolicy, String hostname, List tlsAlpnProtocols, - List tlsEllipticCurves) { + List tlsEllipticCurves, SslConfig sslConfig) { if (uri == null || urls == null || urls.isEmpty()) { throw new IllegalArgumentException("uri == null || urls == null || urls.isEmpty()"); } @@ -192,12 +201,13 @@ public class PeerConnection { this.hostname = hostname; this.tlsAlpnProtocols = tlsAlpnProtocols; this.tlsEllipticCurves = tlsEllipticCurves; + this.sslConfig = sslConfig; } @Override public String toString() { return urls + " [" + username + ":" + password + "] [" + tlsCertPolicy + "] [" + hostname - + "] [" + tlsAlpnProtocols + "] [" + tlsEllipticCurves + "]"; + + "] [" + tlsAlpnProtocols + "] [" + tlsEllipticCurves + "] [" + sslConfig + "]"; } public static Builder builder(String uri) { @@ -216,6 +226,7 @@ public class PeerConnection { private String hostname = ""; private List tlsAlpnProtocols; private List tlsEllipticCurves; + private SslConfig sslConfig = SslConfig.builder().createSslConfig(); private Builder(List urls) { if (urls == null || urls.isEmpty()) { @@ -234,6 +245,7 @@ public class PeerConnection { return this; } + @Deprecated public Builder setTlsCertPolicy(TlsCertPolicy tlsCertPolicy) { this.tlsCertPolicy = tlsCertPolicy; return this; @@ -244,19 +256,26 @@ public class PeerConnection { return this; } + @Deprecated public Builder setTlsAlpnProtocols(List tlsAlpnProtocols) { this.tlsAlpnProtocols = tlsAlpnProtocols; return this; } + @Deprecated public Builder setTlsEllipticCurves(List tlsEllipticCurves) { this.tlsEllipticCurves = tlsEllipticCurves; return this; } + public Builder setSslConfig(SslConfig sslConfig) { + this.sslConfig = sslConfig; + return this; + } + public IceServer createIceServer() { return new IceServer(urls.get(0), urls, username, password, tlsCertPolicy, hostname, - tlsAlpnProtocols, tlsEllipticCurves); + tlsAlpnProtocols, tlsEllipticCurves, sslConfig); } } @@ -298,6 +317,11 @@ public class PeerConnection { List getTlsEllipticCurves() { return tlsEllipticCurves; } + + @CalledByNative("IceServer") + SslConfig getSslConfig() { + return sslConfig; + } } /** Java version of PeerConnectionInterface.IceTransportsType */ diff --git a/sdk/android/api/org/webrtc/SslConfig.java b/sdk/android/api/org/webrtc/SslConfig.java new file mode 100644 index 0000000000..7a94928c4b --- /dev/null +++ b/sdk/android/api/org/webrtc/SslConfig.java @@ -0,0 +1,204 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + +/** + * Java version of rtc::SSLConfig. + * + * Contains the configuration of any SSL/TLS connections that are initiated by + * our client. + */ +public class SslConfig { + /** Tracks rtc::TlsCertPolicy */ + public enum TlsCertPolicy { + TLS_CERT_POLICY_SECURE, + TLS_CERT_POLICY_INSECURE_NO_CHECK, + } + + /** Indicates whether to enable OCSP stapling in TLS. */ + public final boolean enableOcspStapling; + /** Indicates whether to enable the signed certificate timestamp extension in TLS. */ + public final boolean enableSignedCertTimestamp; + /** Indicates whether to enable the TLS Channel ID extension. */ + public final boolean enableTlsChannelId; + /** Indicates whether to enable the TLS GREASE extension. */ + public final boolean enableGrease; + + /** Indicates how to process TURN server certificates */ + public final TlsCertPolicy tlsCertPolicy; + + /** + * Highest supported SSL version, as defined in the supported_versions TLS extension. + * If null, the default OpenSSL/BoringSSL max version will be used. + */ + @Nullable public final Integer maxSslVersion; + + /** + * List of protocols to be used in the TLS ALPN extension. + * If null, the default list of OpenSSL/BoringSSL ALPN protocols will be used. + */ + @Nullable public final List 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"). + * If null, the default list of OpenSSL/BoringSSL curves will be used. + */ + @Nullable public final List tlsEllipticCurves; + + private SslConfig(boolean enableOcspStapling, boolean enableSignedCertTimestamp, + boolean enableTlsChannelId, boolean enableGrease, TlsCertPolicy tlsCertPolicy, + Integer maxSslVersion, List tlsAlpnProtocols, List tlsEllipticCurves) { + this.enableOcspStapling = enableOcspStapling; + this.enableSignedCertTimestamp = enableSignedCertTimestamp; + this.enableTlsChannelId = enableTlsChannelId; + this.enableGrease = enableGrease; + this.tlsCertPolicy = tlsCertPolicy; + this.maxSslVersion = maxSslVersion; + if (tlsAlpnProtocols != null) { + this.tlsAlpnProtocols = Collections.unmodifiableList(tlsAlpnProtocols); + } else { + this.tlsAlpnProtocols = null; + } + if (tlsEllipticCurves != null) { + this.tlsEllipticCurves = Collections.unmodifiableList(tlsEllipticCurves); + } else { + this.tlsEllipticCurves = null; + } + } + + @Override + public String toString() { + return "[enableOcspStapling=" + enableOcspStapling + "] [enableSignedCertTimestamp=" + + enableSignedCertTimestamp + "] [enableTlsChannelId=" + enableTlsChannelId + + "] [enableGrease=" + enableGrease + "] [tlsCertPolicy=" + tlsCertPolicy + + "] [maxSslVersion=" + maxSslVersion + "] [tlsAlpnProtocols=" + tlsAlpnProtocols + + "] [tlsEllipticCurves=" + tlsEllipticCurves + "]"; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private boolean enableOcspStapling; + private boolean enableSignedCertTimestamp; + private boolean enableTlsChannelId; + private boolean enableGrease; + private TlsCertPolicy tlsCertPolicy; + @Nullable private Integer maxSslVersion; + @Nullable private List tlsAlpnProtocols; + @Nullable private List tlsEllipticCurves; + + private Builder() { + this.enableOcspStapling = true; + this.enableSignedCertTimestamp = true; + this.enableTlsChannelId = false; + this.enableGrease = false; + this.tlsCertPolicy = TlsCertPolicy.TLS_CERT_POLICY_SECURE; + this.maxSslVersion = null; + this.tlsAlpnProtocols = null; + this.tlsEllipticCurves = null; + } + + public Builder setEnableOcspStapling(boolean enableOcspStapling) { + this.enableOcspStapling = enableOcspStapling; + return this; + } + + public Builder setEnableSignedCertTimestamp(boolean enableSignedCertTimestamp) { + this.enableSignedCertTimestamp = enableSignedCertTimestamp; + return this; + } + + public Builder setEnableTlsChannelId(boolean enableTlsChannelId) { + this.enableTlsChannelId = enableTlsChannelId; + return this; + } + + public Builder setEnableGrease(boolean enableGrease) { + this.enableGrease = enableGrease; + return this; + } + + public Builder setTlsCertPolicy(TlsCertPolicy tlsCertPolicy) { + this.tlsCertPolicy = tlsCertPolicy; + return this; + } + + public Builder setMaxSslVersion(int maxSslVersion) { + this.maxSslVersion = maxSslVersion; + return this; + } + + public Builder setTlsAlpnProtocols(List tlsAlpnProtocols) { + this.tlsAlpnProtocols = tlsAlpnProtocols; + return this; + } + + public Builder setTlsEllipticCurves(List tlsEllipticCurves) { + this.tlsEllipticCurves = tlsEllipticCurves; + return this; + } + + public SslConfig createSslConfig() { + return new SslConfig(enableOcspStapling, enableSignedCertTimestamp, enableTlsChannelId, + enableGrease, tlsCertPolicy, maxSslVersion, tlsAlpnProtocols, tlsEllipticCurves); + } + } + + @CalledByNative + boolean getEnableOcspStapling() { + return enableOcspStapling; + } + + @CalledByNative + boolean getEnableSignedCertTimestamp() { + return enableSignedCertTimestamp; + } + + @CalledByNative + boolean getEnableTlsChannelId() { + return enableTlsChannelId; + } + + @CalledByNative + boolean getEnableGrease() { + return enableGrease; + } + + @CalledByNative + TlsCertPolicy getTlsCertPolicy() { + return tlsCertPolicy; + } + + @Nullable + @CalledByNative + Integer getMaxSslVersion() { + return maxSslVersion; + } + + @Nullable + @CalledByNative + List getTlsAlpnProtocols() { + return tlsAlpnProtocols; + } + + @Nullable + @CalledByNative + List getTlsEllipticCurves() { + return tlsEllipticCurves; + } +} diff --git a/sdk/android/src/jni/pc/peerconnection.cc b/sdk/android/src/jni/pc/peerconnection.cc index 79da797e38..1d9f945ef0 100644 --- a/sdk/android/src/jni/pc/peerconnection.cc +++ b/sdk/android/src/jni/pc/peerconnection.cc @@ -51,6 +51,7 @@ #include "sdk/android/src/jni/pc/rtpsender.h" #include "sdk/android/src/jni/pc/sdpobserver.h" #include "sdk/android/src/jni/pc/sessiondescription.h" +#include "sdk/android/src/jni/pc/sslconfig.h" #include "sdk/android/src/jni/pc/statsobserver.h" #include "sdk/android/src/jni/pc/turncustomizer.h" @@ -87,6 +88,8 @@ PeerConnectionInterface::IceServers JavaToNativeIceServers( Java_IceServer_getTlsAlpnProtocols(jni, j_ice_server); ScopedJavaLocalRef tls_elliptic_curves = Java_IceServer_getTlsEllipticCurves(jni, j_ice_server); + ScopedJavaLocalRef ssl_config = + Java_IceServer_getSslConfig(jni, j_ice_server); PeerConnectionInterface::IceServer server; server.urls = JavaListToNativeVector( jni, urls, &JavaToNativeString); @@ -98,6 +101,7 @@ PeerConnectionInterface::IceServers JavaToNativeIceServers( jni, tls_alpn_protocols, &JavaToNativeString); server.tls_elliptic_curves = JavaListToNativeVector( jni, tls_elliptic_curves, &JavaToNativeString); + server.ssl_config = JavaToNativeSslConfig(jni, ssl_config); ice_servers.push_back(server); } return ice_servers; diff --git a/sdk/android/src/jni/pc/sslconfig.cc b/sdk/android/src/jni/pc/sslconfig.cc new file mode 100644 index 0000000000..678f49a1e1 --- /dev/null +++ b/sdk/android/src/jni/pc/sslconfig.cc @@ -0,0 +1,78 @@ + +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "sdk/android/src/jni/pc/sslconfig.h" + +#include + +#include "rtc_base/ssladapter.h" +#include "sdk/android/generated_peerconnection_jni/jni/SslConfig_jni.h" +#include "sdk/android/native_api/jni/java_types.h" +#include "sdk/android/src/jni/jni_helpers.h" + +namespace webrtc { +namespace jni { + +rtc::TlsCertPolicy JavaToNativeRtcTlsCertPolicy( + JNIEnv* jni, + const JavaRef& j_ssl_config_tls_cert_policy) { + std::string enum_name = GetJavaEnumName(jni, j_ssl_config_tls_cert_policy); + + if (enum_name == "TLS_CERT_POLICY_SECURE") + return rtc::TlsCertPolicy::TLS_CERT_POLICY_SECURE; + + if (enum_name == "TLS_CERT_POLICY_INSECURE_NO_CHECK") + return rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + + RTC_NOTREACHED(); + return rtc::TlsCertPolicy::TLS_CERT_POLICY_SECURE; +} + +rtc::SSLConfig JavaToNativeSslConfig(JNIEnv* jni, + const JavaRef& j_ssl_config) { + rtc::SSLConfig ssl_config; + ssl_config.enable_ocsp_stapling = + Java_SslConfig_getEnableOcspStapling(jni, j_ssl_config); + ssl_config.enable_signed_cert_timestamp = + Java_SslConfig_getEnableSignedCertTimestamp(jni, j_ssl_config); + ssl_config.enable_tls_channel_id = + Java_SslConfig_getEnableTlsChannelId(jni, j_ssl_config); + ssl_config.enable_grease = Java_SslConfig_getEnableGrease(jni, j_ssl_config); + + ScopedJavaLocalRef j_ssl_config_max_ssl_version = + Java_SslConfig_getMaxSslVersion(jni, j_ssl_config); + ssl_config.max_ssl_version = + JavaToNativeOptionalInt(jni, j_ssl_config_max_ssl_version); + + ScopedJavaLocalRef j_ssl_config_tls_cert_policy = + Java_SslConfig_getTlsCertPolicy(jni, j_ssl_config); + ssl_config.tls_cert_policy = + JavaToNativeRtcTlsCertPolicy(jni, j_ssl_config_tls_cert_policy); + + ScopedJavaLocalRef j_ssl_config_tls_alpn_protocols = + Java_SslConfig_getTlsAlpnProtocols(jni, j_ssl_config); + if (!IsNull(jni, j_ssl_config_tls_alpn_protocols)) { + ssl_config.tls_alpn_protocols = + JavaListToNativeVector( + jni, j_ssl_config_tls_alpn_protocols, &JavaToNativeString); + } + ScopedJavaLocalRef j_ssl_config_tls_elliptic_curves = + Java_SslConfig_getTlsEllipticCurves(jni, j_ssl_config); + if (!IsNull(jni, j_ssl_config_tls_elliptic_curves)) { + ssl_config.tls_elliptic_curves = + JavaListToNativeVector( + jni, j_ssl_config_tls_elliptic_curves, &JavaToNativeString); + } + return ssl_config; +} + +} // namespace jni +} // namespace webrtc diff --git a/sdk/android/src/jni/pc/sslconfig.h b/sdk/android/src/jni/pc/sslconfig.h new file mode 100644 index 0000000000..38de114fc7 --- /dev/null +++ b/sdk/android/src/jni/pc/sslconfig.h @@ -0,0 +1,30 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SDK_ANDROID_SRC_JNI_PC_SSLCONFIG_H_ +#define SDK_ANDROID_SRC_JNI_PC_SSLCONFIG_H_ + +#include "api/peerconnectioninterface.h" +#include "sdk/android/native_api/jni/scoped_java_ref.h" + +namespace webrtc { +namespace jni { + +rtc::TlsCertPolicy JavaToNativeRtcTlsCertPolicy( + JNIEnv* jni, + const JavaRef& j_ssl_config_tls_cert_policy); + +rtc::SSLConfig JavaToNativeSslConfig(JNIEnv* env, + const JavaRef& j_ssl_config); + +} // namespace jni +} // namespace webrtc + +#endif // SDK_ANDROID_SRC_JNI_PC_SSLCONFIG_H_ diff --git a/sdk/objc/Framework/Headers/WebRTC/RTCSSLConfig.h b/sdk/objc/Framework/Headers/WebRTC/RTCSSLConfig.h new file mode 100644 index 0000000000..b572522667 --- /dev/null +++ b/sdk/objc/Framework/Headers/WebRTC/RTCSSLConfig.h @@ -0,0 +1,11 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import "api/peerconnection/RTCSSLConfig.h" diff --git a/sdk/objc/api/peerconnection/RTCIceServer.h b/sdk/objc/api/peerconnection/RTCIceServer.h index c2def045a9..a9760c7e54 100644 --- a/sdk/objc/api/peerconnection/RTCIceServer.h +++ b/sdk/objc/api/peerconnection/RTCIceServer.h @@ -11,11 +11,7 @@ #import #import "RTCMacros.h" - -typedef NS_ENUM(NSUInteger, RTCTlsCertPolicy) { - RTCTlsCertPolicySecure, - RTCTlsCertPolicyInsecureNoCheck -}; +#import "RTCSSLConfig.h" NS_ASSUME_NONNULL_BEGIN @@ -32,7 +28,8 @@ RTC_EXPORT @property(nonatomic, readonly, nullable) NSString *credential; /** - * TLS certificate policy to use if this RTCIceServer object is a TURN server. + Deprecated. TODO(diogor, webrtc:9673): Remove from API. + TLS certificate policy to use if this RTCIceServer object is a TURN server. */ @property(nonatomic, readonly) RTCTlsCertPolicy tlsCertPolicy; @@ -43,15 +40,24 @@ RTC_EXPORT */ @property(nonatomic, readonly, nullable) NSString *hostname; -/** List of protocols to be used in the TLS ALPN extension. */ +/** + Deprecated. TODO(diogor, webrtc:9673): Remove from API. + List of protocols to be used in the TLS ALPN extension. + This field will be ignored if also set in RTCSSLConfig. + */ @property(nonatomic, readonly) NSArray *tlsAlpnProtocols; /** + Deprecated. TODO(diogor, webrtc:9673): Remove from API. 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"). + This field will be ignored if also set in RTCSSLConfig. */ @property(nonatomic, readonly) NSArray *tlsEllipticCurves; +/** SSL configuration options for any SSL/TLS connections to this IceServer. */ +@property(nonatomic, readonly) RTCSSLConfig *sslConfig; + - (nonnull instancetype)init NS_UNAVAILABLE; /** Convenience initializer for a server with no authentication (e.g. STUN). */ @@ -106,8 +112,17 @@ RTC_EXPORT tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy hostname:(nullable NSString *)hostname tlsAlpnProtocols:(nullable NSArray *)tlsAlpnProtocols - tlsEllipticCurves:(nullable NSArray *)tlsEllipticCurves - NS_DESIGNATED_INITIALIZER; + tlsEllipticCurves:(nullable NSArray *)tlsEllipticCurves; + +/** + * Initialize an RTCIceServer with its associated URLs, optional + * username, optional credential, hostname and SSL config. + */ +- (instancetype)initWithURLStrings:(NSArray *)urlStrings + username:(nullable NSString *)username + credential:(nullable NSString *)credential + hostname:(nullable NSString *)hostname + sslConfig:(RTCSSLConfig *)sslConfig NS_DESIGNATED_INITIALIZER; @end diff --git a/sdk/objc/api/peerconnection/RTCIceServer.mm b/sdk/objc/api/peerconnection/RTCIceServer.mm index 2138e4c16a..d03fd812ec 100644 --- a/sdk/objc/api/peerconnection/RTCIceServer.mm +++ b/sdk/objc/api/peerconnection/RTCIceServer.mm @@ -9,6 +9,7 @@ */ #import "RTCIceServer+Private.h" +#import "RTCSSLConfig+Native.h" #import "helpers/NSString+StdString.h" @@ -21,6 +22,7 @@ @synthesize hostname = _hostname; @synthesize tlsAlpnProtocols = _tlsAlpnProtocols; @synthesize tlsEllipticCurves = _tlsEllipticCurves; +@synthesize sslConfig = _sslConfig; - (instancetype)initWithURLStrings:(NSArray *)urlStrings { return [self initWithURLStrings:urlStrings @@ -83,28 +85,50 @@ hostname:(NSString *)hostname tlsAlpnProtocols:(NSArray *)tlsAlpnProtocols tlsEllipticCurves:(NSArray *)tlsEllipticCurves { + RTCSSLConfig *sslConfig = [[RTCSSLConfig alloc] init]; + sslConfig.tlsCertPolicy = tlsCertPolicy; + sslConfig.tlsALPNProtocols = [[NSArray alloc] initWithArray:tlsAlpnProtocols copyItems:YES]; + sslConfig.tlsEllipticCurves = [[NSArray alloc] initWithArray:tlsEllipticCurves copyItems:YES]; + return [self initWithURLStrings:urlStrings + username:username + credential:credential + hostname:hostname + sslConfig:sslConfig]; +} + +- (instancetype)initWithURLStrings:(NSArray *)urlStrings + username:(NSString *)username + credential:(NSString *)credential + hostname:(NSString *)hostname + sslConfig:(RTCSSLConfig *)sslConfig { NSParameterAssert(urlStrings.count); if (self = [super init]) { _urlStrings = [[NSArray alloc] initWithArray:urlStrings copyItems:YES]; _username = [username copy]; _credential = [credential copy]; - _tlsCertPolicy = tlsCertPolicy; _hostname = [hostname copy]; - _tlsAlpnProtocols = [[NSArray alloc] initWithArray:tlsAlpnProtocols copyItems:YES]; - _tlsEllipticCurves = [[NSArray alloc] initWithArray:tlsEllipticCurves copyItems:YES]; + _sslConfig = sslConfig; + + // TODO(diogor, webrtc:9673): Remove these duplicate assignments. + _tlsCertPolicy = sslConfig.tlsCertPolicy; + if (sslConfig.tlsALPNProtocols) { + _tlsAlpnProtocols = [[NSArray alloc] initWithArray:sslConfig.tlsALPNProtocols copyItems:YES]; + } + if (sslConfig.tlsEllipticCurves) { + _tlsEllipticCurves = + [[NSArray alloc] initWithArray:sslConfig.tlsEllipticCurves copyItems:YES]; + } } return self; } - (NSString *)description { - return [NSString stringWithFormat:@"RTCIceServer:\n%@\n%@\n%@\n%@\n%@\n%@\n%@", + return [NSString stringWithFormat:@"RTCIceServer:\n%@\n%@\n%@\n%@\n%@", _urlStrings, _username, _credential, - [self stringForTlsCertPolicy:_tlsCertPolicy], _hostname, - _tlsAlpnProtocols, - _tlsEllipticCurves]; + _sslConfig]; } #pragma mark - Private @@ -149,6 +173,8 @@ webrtc::PeerConnectionInterface::kTlsCertPolicyInsecureNoCheck; break; } + + iceServer.ssl_config = [_sslConfig nativeConfig]; return iceServer; } @@ -162,34 +188,38 @@ NSString *username = [NSString stringForStdString:nativeServer.username]; NSString *credential = [NSString stringForStdString:nativeServer.password]; NSString *hostname = [NSString stringForStdString:nativeServer.hostname]; - NSMutableArray *tlsAlpnProtocols = - [NSMutableArray arrayWithCapacity:nativeServer.tls_alpn_protocols.size()]; - 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; + RTCSSLConfig *sslConfig = [[RTCSSLConfig alloc] initWithNativeConfig:nativeServer.ssl_config]; - switch (nativeServer.tls_cert_policy) { - case webrtc::PeerConnectionInterface::kTlsCertPolicySecure: - tlsCertPolicy = RTCTlsCertPolicySecure; - break; - case webrtc::PeerConnectionInterface::kTlsCertPolicyInsecureNoCheck: - tlsCertPolicy = RTCTlsCertPolicyInsecureNoCheck; - break; + if (!nativeServer.ssl_config.tls_alpn_protocols.has_value() && + !nativeServer.tls_alpn_protocols.empty()) { + NSMutableArray *tlsALPNProtocols = + [NSMutableArray arrayWithCapacity:nativeServer.tls_alpn_protocols.size()]; + for (auto const &proto : nativeServer.tls_alpn_protocols) { + [tlsALPNProtocols addObject:[NSString stringForStdString:proto]]; + } + sslConfig.tlsALPNProtocols = tlsALPNProtocols; + } + + if (!nativeServer.ssl_config.tls_elliptic_curves.has_value() && + !nativeServer.tls_elliptic_curves.empty()) { + NSMutableArray *tlsEllipticCurves = + [NSMutableArray arrayWithCapacity:nativeServer.tls_elliptic_curves.size()]; + for (auto const &curve : nativeServer.tls_elliptic_curves) { + [tlsEllipticCurves addObject:[NSString stringForStdString:curve]]; + } + sslConfig.tlsEllipticCurves = tlsEllipticCurves; + } + + if (nativeServer.tls_cert_policy == + webrtc::PeerConnectionInterface::kTlsCertPolicyInsecureNoCheck) { + sslConfig.tlsCertPolicy = RTCTlsCertPolicyInsecureNoCheck; } self = [self initWithURLStrings:urls username:username credential:credential - tlsCertPolicy:tlsCertPolicy hostname:hostname - tlsAlpnProtocols:tlsAlpnProtocols - tlsEllipticCurves:tlsEllipticCurves]; + sslConfig:sslConfig]; return self; } diff --git a/sdk/objc/api/peerconnection/RTCSSLConfig+Native.h b/sdk/objc/api/peerconnection/RTCSSLConfig+Native.h new file mode 100644 index 0000000000..7a38edc272 --- /dev/null +++ b/sdk/objc/api/peerconnection/RTCSSLConfig+Native.h @@ -0,0 +1,27 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import "RTCSSLConfig.h" + +#include "api/peerconnectioninterface.h" +#include "rtc_base/ssladapter.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface RTCSSLConfig (Native) + +- (rtc::SSLConfig)nativeConfig; + +/** Initialize an RTCSSLConfig from a native SSLConfig. */ +- (instancetype)initWithNativeConfig:(const rtc::SSLConfig &)config; + +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/objc/api/peerconnection/RTCSSLConfig.h b/sdk/objc/api/peerconnection/RTCSSLConfig.h new file mode 100644 index 0000000000..54216091d8 --- /dev/null +++ b/sdk/objc/api/peerconnection/RTCSSLConfig.h @@ -0,0 +1,56 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import + +#import + +typedef NS_ENUM(NSUInteger, RTCTlsCertPolicy) { + RTCTlsCertPolicySecure, + RTCTlsCertPolicyInsecureNoCheck +}; + +NS_ASSUME_NONNULL_BEGIN + +RTC_EXPORT +@interface RTCSSLConfig : NSObject + +/** Indicates whether to enable OCSP stapling in TLS. */ +@property(nonatomic) BOOL enableOCSPStapling; + +/** Indicates whether to enable the signed certificate timestamp extension in TLS. */ +@property(nonatomic) BOOL enableSignedCertTimestamp; + +/** Indicates whether to enable the TLS Channel ID extension. */ +@property(nonatomic) BOOL enableTlsChannelId; + +/** Indicates whether to enable the TLS GREASE extension. */ +@property(nonatomic) BOOL enableGrease; + +/** Indicates how to process TURN server certificates */ +@property(nonatomic) RTCTlsCertPolicy tlsCertPolicy; + +/** Highest supported SSL version, as defined in the supported_versions TLS extension. */ +@property(nonatomic, nullable) NSNumber *maxSSLVersion; + +/** List of protocols to be used in the TLS ALPN extension. */ +@property(nonatomic, copy, nullable) NSArray *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"). + */ +@property(nonatomic, copy, nullable) NSArray *tlsEllipticCurves; + +- (instancetype)init; + +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/objc/api/peerconnection/RTCSSLConfig.mm b/sdk/objc/api/peerconnection/RTCSSLConfig.mm new file mode 100644 index 0000000000..60ff47cfd2 --- /dev/null +++ b/sdk/objc/api/peerconnection/RTCSSLConfig.mm @@ -0,0 +1,134 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import "RTCSSLConfig+Native.h" + +#import "helpers/NSString+StdString.h" + +@implementation RTCSSLConfig + +@synthesize enableOCSPStapling = _enableOCSPStapling; +@synthesize enableSignedCertTimestamp = _enableSignedCertTimestamp; +@synthesize enableTlsChannelId = _enableTlsChannelId; +@synthesize enableGrease = _enableGrease; +@synthesize tlsCertPolicy = _tlsCertPolicy; +@synthesize maxSSLVersion = _maxSSLVersion; +@synthesize tlsALPNProtocols = _tlsALPNProtocols; +@synthesize tlsEllipticCurves = _tlsEllipticCurves; + +- (instancetype)init { + // Copy defaults + rtc::SSLConfig config; + return [self initWithNativeConfig:config]; +} + +- (instancetype)initWithNativeConfig:(const rtc::SSLConfig &)config { + if (self = [super init]) { + _enableOCSPStapling = config.enable_ocsp_stapling; + _enableSignedCertTimestamp = config.enable_signed_cert_timestamp; + _enableTlsChannelId = config.enable_tls_channel_id; + _enableGrease = config.enable_grease; + + switch (config.tls_cert_policy) { + case rtc::TlsCertPolicy::TLS_CERT_POLICY_SECURE: + _tlsCertPolicy = RTCTlsCertPolicySecure; + break; + case rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK: + _tlsCertPolicy = RTCTlsCertPolicyInsecureNoCheck; + break; + } + + if (config.max_ssl_version) { + _maxSSLVersion = [NSNumber numberWithInt:*config.max_ssl_version]; + } + if (config.tls_alpn_protocols) { + NSMutableArray *tlsALPNProtocols = + [NSMutableArray arrayWithCapacity:config.tls_alpn_protocols.value().size()]; + for (auto const &proto : config.tls_alpn_protocols.value()) { + [tlsALPNProtocols addObject:[NSString stringForStdString:proto]]; + } + _tlsALPNProtocols = tlsALPNProtocols; + } + if (config.tls_elliptic_curves) { + NSMutableArray *tlsEllipticCurves = + [NSMutableArray arrayWithCapacity:config.tls_elliptic_curves.value().size()]; + for (auto const &curve : config.tls_elliptic_curves.value()) { + [tlsEllipticCurves addObject:[NSString stringForStdString:curve]]; + } + _tlsEllipticCurves = tlsEllipticCurves; + } + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"RTCSSLConfig:\n%d\n%d\n%d\n%d\n%@\n%@\n%@\n%@", + _enableOCSPStapling, + _enableSignedCertTimestamp, + _enableTlsChannelId, + _enableGrease, + [self stringForTlsCertPolicy:_tlsCertPolicy], + _maxSSLVersion, + _tlsALPNProtocols, + _tlsEllipticCurves]; +} + +#pragma mark - Private + +- (NSString *)stringForTlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy { + switch (tlsCertPolicy) { + case RTCTlsCertPolicySecure: + return @"RTCTlsCertPolicySecure"; + case RTCTlsCertPolicyInsecureNoCheck: + return @"RTCTlsCertPolicyInsecureNoCheck"; + } +} + +- (rtc::SSLConfig)nativeConfig { + __block rtc::SSLConfig sslConfig; + + sslConfig.enable_ocsp_stapling = _enableOCSPStapling; + sslConfig.enable_signed_cert_timestamp = _enableSignedCertTimestamp; + sslConfig.enable_tls_channel_id = _enableTlsChannelId; + sslConfig.enable_grease = _enableGrease; + + switch (_tlsCertPolicy) { + case RTCTlsCertPolicySecure: + sslConfig.tls_cert_policy = rtc::TlsCertPolicy::TLS_CERT_POLICY_SECURE; + break; + case RTCTlsCertPolicyInsecureNoCheck: + sslConfig.tls_cert_policy = rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; + break; + } + + if (_maxSSLVersion != nil) { + sslConfig.max_ssl_version = absl::optional(_maxSSLVersion.intValue); + } + + if (_tlsALPNProtocols != nil) { + __block std::vector alpn_protocols; + [_tlsALPNProtocols enumerateObjectsUsingBlock:^(NSString *proto, NSUInteger idx, BOOL *stop) { + alpn_protocols.push_back(proto.stdString); + }]; + sslConfig.tls_alpn_protocols = absl::optional>(alpn_protocols); + } + + if (_tlsEllipticCurves != nil) { + __block std::vector elliptic_curves; + [_tlsEllipticCurves enumerateObjectsUsingBlock:^(NSString *curve, NSUInteger idx, BOOL *stop) { + elliptic_curves.push_back(curve.stdString); + }]; + sslConfig.tls_elliptic_curves = absl::optional>(elliptic_curves); + } + + return sslConfig; +} + +@end diff --git a/sdk/objc/unittests/RTCIceServerTest.mm b/sdk/objc/unittests/RTCIceServerTest.mm index 8ef5195b95..7659196139 100644 --- a/sdk/objc/unittests/RTCIceServerTest.mm +++ b/sdk/objc/unittests/RTCIceServerTest.mm @@ -89,7 +89,7 @@ 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.ssl_config.tls_alpn_protocols.value().size()); } - (void)testTlsEllipticCurves { @@ -106,8 +106,8 @@ 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()); + EXPECT_EQ(2u, iceStruct.ssl_config.tls_alpn_protocols.value().size()); + EXPECT_EQ(2u, iceStruct.ssl_config.tls_elliptic_curves.value().size()); } - (void)testInitFromNativeServer { @@ -129,8 +129,8 @@ EXPECT_EQ("username", [NSString stdStringForString:iceServer.username]); 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); + EXPECT_EQ(2u, iceServer.sslConfig.tlsALPNProtocols.count); + EXPECT_EQ(2u, iceServer.sslConfig.tlsEllipticCurves.count); } @end