summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2023-01-30 13:28:31 +0100
committerRémi Verschelde <rverschelde@gmail.com>2023-01-30 13:28:31 +0100
commitbde3310f02196c5a0962153426fd0209020af5a6 (patch)
tree2bf302ea12ecc3834bdacfde0369437469fcf92e /modules
parent6c19a619adbcafd33603b6993e7a8b2452269b68 (diff)
parent7cd80e6a6dd48019fb292e49eab10eefff293132 (diff)
Merge pull request #71995 from Faless/net/4.x_tls_verify
[NET] Refactor TLS configuration.
Diffstat (limited to 'modules')
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml12
-rw-r--r--modules/enet/enet_connection.cpp14
-rw-r--r--modules/enet/enet_connection.h4
-rw-r--r--modules/mbedtls/dtls_server_mbedtls.cpp20
-rw-r--r--modules/mbedtls/dtls_server_mbedtls.h8
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.cpp16
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.h4
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp43
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.h4
-rw-r--r--modules/mbedtls/tls_context_mbedtls.cpp47
-rw-r--r--modules/mbedtls/tls_context_mbedtls.h10
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml10
-rw-r--r--modules/websocket/doc_classes/WebSocketPeer.xml5
-rw-r--r--modules/websocket/emws_peer.cpp6
-rw-r--r--modules/websocket/emws_peer.h2
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp27
-rw-r--r--modules/websocket/websocket_multiplayer_peer.h8
-rw-r--r--modules/websocket/websocket_peer.cpp2
-rw-r--r--modules/websocket/websocket_peer.h2
-rw-r--r--modules/websocket/wsl_peer.cpp15
-rw-r--r--modules/websocket/wsl_peer.h5
21 files changed, 130 insertions, 134 deletions
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index 8c84fe87d7..dc832976d9 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -84,19 +84,17 @@
</method>
<method name="dtls_client_setup">
<return type="int" enum="Error" />
- <param index="0" name="certificate" type="X509Certificate" />
- <param index="1" name="hostname" type="String" />
- <param index="2" name="verify" type="bool" default="true" />
+ <param index="0" name="hostname" type="String" />
+ <param index="1" name="client_options" type="TLSOptions" default="null" />
<description>
- Configure this ENetHost to use the custom Godot extension allowing DTLS encryption for ENet clients. Call this before [method connect_to_host] to have ENet connect using DTLS with [code]certificate[/code] and [code]hostname[/code] verification. Verification can be optionally turned off via the [code]verify[/code] parameter.
+ Configure this ENetHost to use the custom Godot extension allowing DTLS encryption for ENet clients. Call this before [method connect_to_host] to have ENet connect using DTLS validating the server certificate against [code]hostname[/code]. You can pass the optional [param client_options] parameter to customize the trusted certification authorities, or disable the common name verification. See [method TLSOptions.client] and [method TLSOptions.client_unsafe].
</description>
</method>
<method name="dtls_server_setup">
<return type="int" enum="Error" />
- <param index="0" name="key" type="CryptoKey" />
- <param index="1" name="certificate" type="X509Certificate" />
+ <param index="0" name="server_options" type="TLSOptions" />
<description>
- Configure this ENetHost to use the custom Godot extension allowing DTLS encryption for ENet servers. Call this right after [method create_host_bound] to have ENet expect peers to connect using DTLS.
+ Configure this ENetHost to use the custom Godot extension allowing DTLS encryption for ENet servers. Call this right after [method create_host_bound] to have ENet expect peers to connect using DTLS. See [method TLSOptions.server].
</description>
</method>
<method name="flush">
diff --git a/modules/enet/enet_connection.cpp b/modules/enet/enet_connection.cpp
index d16e7d7c4a..804263186f 100644
--- a/modules/enet/enet_connection.cpp
+++ b/modules/enet/enet_connection.cpp
@@ -273,10 +273,11 @@ TypedArray<ENetPacketPeer> ENetConnection::_get_peers() {
return out;
}
-Error ENetConnection::dtls_server_setup(Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) {
+Error ENetConnection::dtls_server_setup(const Ref<TLSOptions> &p_options) {
#ifdef GODOT_ENET
ERR_FAIL_COND_V_MSG(!host, ERR_UNCONFIGURED, "The ENetConnection instance isn't currently active.");
- return enet_host_dtls_server_setup(host, p_key.ptr(), p_cert.ptr()) ? FAILED : OK;
+ ERR_FAIL_COND_V(p_options.is_null() || !p_options->is_server(), ERR_INVALID_PARAMETER);
+ return enet_host_dtls_server_setup(host, const_cast<TLSOptions *>(p_options.ptr())) ? FAILED : OK;
#else
ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "ENet DTLS support not available in this build.");
#endif
@@ -291,10 +292,11 @@ void ENetConnection::refuse_new_connections(bool p_refuse) {
#endif
}
-Error ENetConnection::dtls_client_setup(Ref<X509Certificate> p_cert, const String &p_hostname, bool p_verify) {
+Error ENetConnection::dtls_client_setup(const String &p_hostname, const Ref<TLSOptions> &p_options) {
#ifdef GODOT_ENET
ERR_FAIL_COND_V_MSG(!host, ERR_UNCONFIGURED, "The ENetConnection instance isn't currently active.");
- return enet_host_dtls_client_setup(host, p_cert.ptr(), p_verify, p_hostname.utf8().get_data()) ? FAILED : OK;
+ ERR_FAIL_COND_V(p_options.is_null() || p_options->is_server(), ERR_INVALID_PARAMETER);
+ return enet_host_dtls_client_setup(host, p_hostname.utf8().get_data(), const_cast<TLSOptions *>(p_options.ptr())) ? FAILED : OK;
#else
ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "ENet DTLS support not available in this build.");
#endif
@@ -351,8 +353,8 @@ void ENetConnection::_bind_methods() {
ClassDB::bind_method(D_METHOD("channel_limit", "limit"), &ENetConnection::channel_limit);
ClassDB::bind_method(D_METHOD("broadcast", "channel", "packet", "flags"), &ENetConnection::_broadcast);
ClassDB::bind_method(D_METHOD("compress", "mode"), &ENetConnection::compress);
- ClassDB::bind_method(D_METHOD("dtls_server_setup", "key", "certificate"), &ENetConnection::dtls_server_setup);
- ClassDB::bind_method(D_METHOD("dtls_client_setup", "certificate", "hostname", "verify"), &ENetConnection::dtls_client_setup, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("dtls_server_setup", "server_options"), &ENetConnection::dtls_server_setup);
+ ClassDB::bind_method(D_METHOD("dtls_client_setup", "hostname", "client_options"), &ENetConnection::dtls_client_setup, DEFVAL(Ref<TLSOptions>()));
ClassDB::bind_method(D_METHOD("refuse_new_connections", "refuse"), &ENetConnection::refuse_new_connections);
ClassDB::bind_method(D_METHOD("pop_statistic", "statistic"), &ENetConnection::pop_statistic);
ClassDB::bind_method(D_METHOD("get_max_channels"), &ENetConnection::get_max_channels);
diff --git a/modules/enet/enet_connection.h b/modules/enet/enet_connection.h
index 9e444911cc..481afc48bb 100644
--- a/modules/enet/enet_connection.h
+++ b/modules/enet/enet_connection.h
@@ -128,8 +128,8 @@ public:
int get_local_port() const;
// Godot additions
- Error dtls_server_setup(Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert);
- Error dtls_client_setup(Ref<X509Certificate> p_cert, const String &p_hostname, bool p_verify = true);
+ Error dtls_server_setup(const Ref<TLSOptions> &p_options);
+ Error dtls_client_setup(const String &p_hostname, const Ref<TLSOptions> &p_options);
void refuse_new_connections(bool p_refuse);
ENetConnection() {}
diff --git a/modules/mbedtls/dtls_server_mbedtls.cpp b/modules/mbedtls/dtls_server_mbedtls.cpp
index c54ab8ef6e..62513929ea 100644
--- a/modules/mbedtls/dtls_server_mbedtls.cpp
+++ b/modules/mbedtls/dtls_server_mbedtls.cpp
@@ -31,25 +31,25 @@
#include "dtls_server_mbedtls.h"
#include "packet_peer_mbed_dtls.h"
-Error DTLSServerMbedTLS::setup(Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain) {
- ERR_FAIL_COND_V(_cookies->setup() != OK, ERR_ALREADY_IN_USE);
- _key = p_key;
- _cert = p_cert;
- _ca_chain = p_ca_chain;
+Error DTLSServerMbedTLS::setup(Ref<TLSOptions> p_options) {
+ ERR_FAIL_COND_V(p_options.is_null() || !p_options->is_server(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(cookies->setup() != OK, ERR_ALREADY_IN_USE);
+ tls_options = p_options;
return OK;
}
void DTLSServerMbedTLS::stop() {
- _cookies->clear();
+ cookies->clear();
}
Ref<PacketPeerDTLS> DTLSServerMbedTLS::take_connection(Ref<PacketPeerUDP> p_udp_peer) {
Ref<PacketPeerMbedDTLS> out;
- out.instantiate();
- ERR_FAIL_COND_V(!out.is_valid(), out);
+ ERR_FAIL_COND_V(tls_options.is_null(), out);
ERR_FAIL_COND_V(!p_udp_peer.is_valid(), out);
- out->accept_peer(p_udp_peer, _key, _cert, _ca_chain, _cookies);
+
+ out.instantiate();
+ out->accept_peer(p_udp_peer, tls_options, cookies);
return out;
}
@@ -68,7 +68,7 @@ void DTLSServerMbedTLS::finalize() {
}
DTLSServerMbedTLS::DTLSServerMbedTLS() {
- _cookies.instantiate();
+ cookies.instantiate();
}
DTLSServerMbedTLS::~DTLSServerMbedTLS() {
diff --git a/modules/mbedtls/dtls_server_mbedtls.h b/modules/mbedtls/dtls_server_mbedtls.h
index e4612d01ef..d5841a45fa 100644
--- a/modules/mbedtls/dtls_server_mbedtls.h
+++ b/modules/mbedtls/dtls_server_mbedtls.h
@@ -37,16 +37,14 @@
class DTLSServerMbedTLS : public DTLSServer {
private:
static DTLSServer *_create_func();
- Ref<CryptoKey> _key;
- Ref<X509Certificate> _cert;
- Ref<X509Certificate> _ca_chain;
- Ref<CookieContextMbedTLS> _cookies;
+ Ref<TLSOptions> tls_options;
+ Ref<CookieContextMbedTLS> cookies;
public:
static void initialize();
static void finalize();
- virtual Error setup(Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>());
+ virtual Error setup(Ref<TLSOptions> p_options);
virtual void stop();
virtual Ref<PacketPeerDTLS> take_connection(Ref<PacketPeerUDP> p_peer);
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index 16450e151e..e8eb32f88d 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -114,16 +114,14 @@ Error PacketPeerMbedDTLS::_do_handshake() {
return OK;
}
-Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_validate_certs, const String &p_for_hostname, Ref<X509Certificate> p_ca_certs) {
+Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, const String &p_hostname, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);
- base = p_base;
- int authmode = p_validate_certs ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE;
-
- Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_DATAGRAM, authmode, p_ca_certs);
+ Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_DATAGRAM, p_hostname, p_options.is_valid() ? p_options : TLSOptions::client());
ERR_FAIL_COND_V(err != OK, err);
- mbedtls_ssl_set_hostname(tls_ctx->get_context(), p_for_hostname.utf8().get_data());
+ base = p_base;
+
mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);
mbedtls_ssl_set_timer_cb(tls_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
@@ -137,8 +135,10 @@ Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_vali
return OK;
}
-Error PacketPeerMbedDTLS::accept_peer(Ref<PacketPeerUDP> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain, Ref<CookieContextMbedTLS> p_cookies) {
- Error err = tls_ctx->init_server(MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_VERIFY_NONE, p_key, p_cert, p_cookies);
+Error PacketPeerMbedDTLS::accept_peer(Ref<PacketPeerUDP> p_base, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies) {
+ ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);
+
+ Error err = tls_ctx->init_server(MBEDTLS_SSL_TRANSPORT_DATAGRAM, p_options, p_cookies);
ERR_FAIL_COND_V(err != OK, err);
base = p_base;
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.h b/modules/mbedtls/packet_peer_mbed_dtls.h
index 744ef81524..05decec783 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.h
+++ b/modules/mbedtls/packet_peer_mbed_dtls.h
@@ -64,8 +64,8 @@ protected:
public:
virtual void poll();
- virtual Error accept_peer(Ref<PacketPeerUDP> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert = Ref<X509Certificate>(), Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>(), Ref<CookieContextMbedTLS> p_cookies = Ref<CookieContextMbedTLS>());
- virtual Error connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_validate_certs = true, const String &p_for_hostname = String(), Ref<X509Certificate> p_ca_certs = Ref<X509Certificate>());
+ virtual Error accept_peer(Ref<PacketPeerUDP> p_base, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies = Ref<CookieContextMbedTLS>());
+ virtual Error connect_to_peer(Ref<PacketPeerUDP> p_base, const String &p_hostname, Ref<TLSOptions> p_options = Ref<TLSOptions>());
virtual Status get_status() const;
virtual void disconnect_from_peer();
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index 1d17fb9441..a9d187bd64 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -80,38 +80,30 @@ void StreamPeerMbedTLS::_cleanup() {
}
Error StreamPeerMbedTLS::_do_handshake() {
- int ret = 0;
- while ((ret = mbedtls_ssl_handshake(tls_ctx->get_context())) != 0) {
- if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
- // An error occurred.
- ERR_PRINT("TLS handshake error: " + itos(ret));
- TLSContextMbedTLS::print_mbedtls_error(ret);
- disconnect_from_stream();
- status = STATUS_ERROR;
- return FAILED;
- }
-
- // Handshake is still in progress.
- if (!blocking_handshake) {
- // Will retry via poll later
- return OK;
- }
+ int ret = mbedtls_ssl_handshake(tls_ctx->get_context());
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ // Handshake is still in progress, will retry via poll later.
+ return OK;
+ } else if (ret != 0) {
+ // An error occurred.
+ ERR_PRINT("TLS handshake error: " + itos(ret));
+ TLSContextMbedTLS::print_mbedtls_error(ret);
+ disconnect_from_stream();
+ status = STATUS_ERROR;
+ return FAILED;
}
status = STATUS_CONNECTED;
return OK;
}
-Error StreamPeerMbedTLS::connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs, const String &p_for_hostname, Ref<X509Certificate> p_ca_certs) {
+Error StreamPeerMbedTLS::connect_to_stream(Ref<StreamPeer> p_base, const String &p_common_name, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(p_base.is_null(), ERR_INVALID_PARAMETER);
- base = p_base;
- int authmode = p_validate_certs ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE;
-
- Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_STREAM, authmode, p_ca_certs);
+ Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_STREAM, p_common_name, p_options.is_valid() ? p_options : TLSOptions::client());
ERR_FAIL_COND_V(err != OK, err);
- mbedtls_ssl_set_hostname(tls_ctx->get_context(), p_for_hostname.utf8().get_data());
+ base = p_base;
mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);
status = STATUS_HANDSHAKING;
@@ -124,10 +116,11 @@ Error StreamPeerMbedTLS::connect_to_stream(Ref<StreamPeer> p_base, bool p_valida
return OK;
}
-Error StreamPeerMbedTLS::accept_stream(Ref<StreamPeer> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain) {
+Error StreamPeerMbedTLS::accept_stream(Ref<StreamPeer> p_base, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(p_base.is_null(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_options.is_null() || !p_options->is_server(), ERR_INVALID_PARAMETER);
- Error err = tls_ctx->init_server(MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_VERIFY_NONE, p_key, p_cert);
+ Error err = tls_ctx->init_server(MBEDTLS_SSL_TRANSPORT_STREAM, p_options);
ERR_FAIL_COND_V(err != OK, err);
base = p_base;
@@ -308,10 +301,8 @@ StreamPeerTLS *StreamPeerMbedTLS::_create_func() {
void StreamPeerMbedTLS::initialize_tls() {
_create = _create_func;
- available = true;
}
void StreamPeerMbedTLS::finalize_tls() {
- available = false;
_create = nullptr;
}
diff --git a/modules/mbedtls/stream_peer_mbedtls.h b/modules/mbedtls/stream_peer_mbedtls.h
index 8a36a7ea9a..ec0446c380 100644
--- a/modules/mbedtls/stream_peer_mbedtls.h
+++ b/modules/mbedtls/stream_peer_mbedtls.h
@@ -54,8 +54,8 @@ protected:
public:
virtual void poll();
- virtual Error accept_stream(Ref<StreamPeer> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>());
- virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String(), Ref<X509Certificate> p_valid_cert = Ref<X509Certificate>());
+ virtual Error accept_stream(Ref<StreamPeer> p_base, Ref<TLSOptions> p_options);
+ virtual Error connect_to_stream(Ref<StreamPeer> p_base, const String &p_common_name, Ref<TLSOptions> p_options);
virtual Status get_status() const;
virtual Ref<StreamPeer> get_stream() const;
diff --git a/modules/mbedtls/tls_context_mbedtls.cpp b/modules/mbedtls/tls_context_mbedtls.cpp
index a01137f262..aab082f488 100644
--- a/modules/mbedtls/tls_context_mbedtls.cpp
+++ b/modules/mbedtls/tls_context_mbedtls.cpp
@@ -110,22 +110,20 @@ Error TLSContextMbedTLS::_setup(int p_endpoint, int p_transport, int p_authmode)
return OK;
}
-Error TLSContextMbedTLS::init_server(int p_transport, int p_authmode, Ref<CryptoKeyMbedTLS> p_pkey, Ref<X509CertificateMbedTLS> p_cert, Ref<CookieContextMbedTLS> p_cookies) {
- ERR_FAIL_COND_V(!p_pkey.is_valid(), ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!p_cert.is_valid(), ERR_INVALID_PARAMETER);
+Error TLSContextMbedTLS::init_server(int p_transport, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies) {
+ ERR_FAIL_COND_V(p_options.is_null() || !p_options->is_server(), ERR_INVALID_PARAMETER);
- Error err = _setup(MBEDTLS_SSL_IS_SERVER, p_transport, p_authmode);
+ // Check key and certificate(s)
+ pkey = p_options->get_private_key();
+ certs = p_options->get_own_certificate();
+ ERR_FAIL_COND_V(pkey.is_null() || certs.is_null(), ERR_INVALID_PARAMETER);
+
+ Error err = _setup(MBEDTLS_SSL_IS_SERVER, p_transport, MBEDTLS_SSL_VERIFY_NONE); // TODO client auth.
ERR_FAIL_COND_V(err != OK, err);
// Locking key and certificate(s)
- pkey = p_pkey;
- certs = p_cert;
- if (pkey.is_valid()) {
- pkey->lock();
- }
- if (certs.is_valid()) {
- certs->lock();
- }
+ pkey->lock();
+ certs->lock();
// Adding key and certificate
int ret = mbedtls_ssl_conf_own_cert(&conf, &(certs->cert), &(pkey->pkey));
@@ -150,15 +148,32 @@ Error TLSContextMbedTLS::init_server(int p_transport, int p_authmode, Ref<Crypto
return OK;
}
-Error TLSContextMbedTLS::init_client(int p_transport, int p_authmode, Ref<X509CertificateMbedTLS> p_valid_cas) {
- Error err = _setup(MBEDTLS_SSL_IS_CLIENT, p_transport, p_authmode);
+Error TLSContextMbedTLS::init_client(int p_transport, const String &p_hostname, Ref<TLSOptions> p_options) {
+ ERR_FAIL_COND_V(p_options.is_null() || p_options->is_server(), ERR_INVALID_PARAMETER);
+
+ int authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
+ if (p_options->get_verify_mode() == TLSOptions::TLS_VERIFY_NONE) {
+ authmode = MBEDTLS_SSL_VERIFY_NONE;
+ }
+
+ Error err = _setup(MBEDTLS_SSL_IS_CLIENT, p_transport, authmode);
ERR_FAIL_COND_V(err != OK, err);
+ if (p_options->get_verify_mode() == TLSOptions::TLS_VERIFY_FULL) {
+ String cn = p_options->get_common_name();
+ if (cn.is_empty()) {
+ cn = p_hostname;
+ }
+ mbedtls_ssl_set_hostname(&tls, cn.utf8().get_data());
+ } else {
+ mbedtls_ssl_set_hostname(&tls, nullptr);
+ }
+
X509CertificateMbedTLS *cas = nullptr;
- if (p_valid_cas.is_valid()) {
+ if (p_options->get_trusted_ca_chain().is_valid()) {
// Locking CA certificates
- certs = p_valid_cas;
+ certs = p_options->get_trusted_ca_chain();
certs->lock();
cas = certs.ptr();
} else {
diff --git a/modules/mbedtls/tls_context_mbedtls.h b/modules/mbedtls/tls_context_mbedtls.h
index 574e80e199..f1bad6a40c 100644
--- a/modules/mbedtls/tls_context_mbedtls.h
+++ b/modules/mbedtls/tls_context_mbedtls.h
@@ -71,17 +71,17 @@ public:
static void print_mbedtls_error(int p_ret);
Ref<X509CertificateMbedTLS> certs;
+ Ref<CryptoKeyMbedTLS> pkey;
+ Ref<CookieContextMbedTLS> cookies;
+
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context tls;
mbedtls_ssl_config conf;
- Ref<CookieContextMbedTLS> cookies;
- Ref<CryptoKeyMbedTLS> pkey;
-
Error _setup(int p_endpoint, int p_transport, int p_authmode);
- Error init_server(int p_transport, int p_authmode, Ref<CryptoKeyMbedTLS> p_pkey, Ref<X509CertificateMbedTLS> p_cert, Ref<CookieContextMbedTLS> p_cookies = Ref<CookieContextMbedTLS>());
- Error init_client(int p_transport, int p_authmode, Ref<X509CertificateMbedTLS> p_valid_cas);
+ Error init_server(int p_transport, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies = Ref<CookieContextMbedTLS>());
+ Error init_client(int p_transport, const String &p_hostname, Ref<TLSOptions> p_options);
void clear();
mbedtls_ssl_context *get_context();
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index 7e896a0ca3..aaeb2025ee 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -13,10 +13,9 @@
<method name="create_client">
<return type="int" enum="Error" />
<param index="0" name="url" type="String" />
- <param index="1" name="verify_tls" type="bool" default="true" />
- <param index="2" name="tls_certificate" type="X509Certificate" default="null" />
+ <param index="1" name="tls_client_options" type="TLSOptions" default="null" />
<description>
- Starts a new multiplayer client connecting to the given [param url]. If [param verify_tls] is [code]false[/code] certificate validation will be disabled. If specified, the [param tls_certificate] will be used to verify the TLS host.
+ Starts a new multiplayer client connecting to the given [param url]. TLS certificates will be verified against the hostname when connecting using the [code]wss://[/code] protocol. You can pass the optional [param tls_client_options] parameter to customize the trusted certification authorities, or disable the common name verification. See [method TLSOptions.client] and [method TLSOptions.client_unsafe].
[b]Note[/b]: It is recommended to specify the scheme part of the URL, i.e. the [param url] should start with either [code]ws://[/code] or [code]wss://[/code].
</description>
</method>
@@ -24,10 +23,9 @@
<return type="int" enum="Error" />
<param index="0" name="port" type="int" />
<param index="1" name="bind_address" type="String" default="&quot;*&quot;" />
- <param index="2" name="tls_key" type="CryptoKey" default="null" />
- <param index="3" name="tls_certificate" type="X509Certificate" default="null" />
+ <param index="2" name="tls_server_options" type="TLSOptions" default="null" />
<description>
- Starts a new multiplayer server listening on the given [param port]. You can optionally specify a [param bind_address], and provide a [param tls_key] and [param tls_certificate] to use TLS.
+ Starts a new multiplayer server listening on the given [param port]. You can optionally specify a [param bind_address], and provide valiid [param tls_server_options] to use TLS. See [method TLSOptions.server].
</description>
</method>
<method name="get_peer" qualifiers="const">
diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml
index 41d166a0f5..0f8c27c4cc 100644
--- a/modules/websocket/doc_classes/WebSocketPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketPeer.xml
@@ -58,10 +58,9 @@
<method name="connect_to_url">
<return type="int" enum="Error" />
<param index="0" name="url" type="String" />
- <param index="1" name="verify_tls" type="bool" default="true" />
- <param index="2" name="trusted_tls_certificate" type="X509Certificate" default="null" />
+ <param index="1" name="tls_client_options" type="TLSOptions" default="null" />
<description>
- Connects to the given URL. If [param verify_tls] is [code]false[/code] certificate validation will be disabled. If specified, the [param trusted_tls_certificate] will be the only one accepted when connecting to a TLS host.
+ Connects to the given URL. TLS certificates will be verified against the hostname when connecting using the [code]wss://[/code] protocol. You can pass the optional [param tls_client_options] parameter to customize the trusted certification authorities, or disable the common name verification. See [method TLSOptions.client] and [method TLSOptions.client_unsafe].
[b]Note:[/b] To avoid mixed content warnings or errors in Web, you may have to use a [code]url[/code] that starts with [code]wss://[/code] (secure) instead of [code]ws://[/code]. When doing so, make sure to use the fully qualified domain name that matches the one defined in the server's TLS certificate. Do not connect directly via the IP address for [code]wss://[/code] connections, as it won't match with the TLS certificate.
</description>
</method>
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 1ec557427f..7b14a3a61d 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -58,7 +58,8 @@ void EMWSPeer::_esws_on_close(void *p_obj, int p_code, const char *p_reason, int
peer->ready_state = STATE_CLOSED;
}
-Error EMWSPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509Certificate> p_tls_certificate) {
+Error EMWSPeer::connect_to_url(const String &p_url, Ref<TLSOptions> p_tls_options) {
+ ERR_FAIL_COND_V(p_tls_options.is_valid() && p_tls_options->is_server(), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(ready_state != STATE_CLOSED, ERR_ALREADY_IN_USE);
_clear();
@@ -85,9 +86,6 @@ Error EMWSPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509C
if (handshake_headers.size()) {
WARN_PRINT_ONCE("Custom headers are not supported in Web platform.");
}
- if (p_tls_certificate.is_valid()) {
- WARN_PRINT_ONCE("Custom SSL certificates are not supported in Web platform.");
- }
requested_url = scheme + host;
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index 66c5283d5c..08b2dad977 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -86,7 +86,7 @@ public:
// WebSocketPeer
virtual Error send(const uint8_t *p_buffer, int p_buffer_size, WriteMode p_mode) override;
- virtual Error connect_to_url(const String &p_url, bool p_verify_tls = true, Ref<X509Certificate> p_cert = Ref<X509Certificate>()) override;
+ virtual Error connect_to_url(const String &p_url, Ref<TLSOptions> p_tls_client_options) override;
virtual Error accept_stream(Ref<StreamPeer> p_stream) override;
virtual void close(int p_code = 1000, String p_reason = "") override;
virtual void poll() override;
diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp
index 36b4215f8c..389d8c56ad 100644
--- a/modules/websocket/websocket_multiplayer_peer.cpp
+++ b/modules/websocket/websocket_multiplayer_peer.cpp
@@ -54,11 +54,9 @@ void WebSocketMultiplayerPeer::_clear() {
connection_status = CONNECTION_DISCONNECTED;
unique_id = 0;
peers_map.clear();
- use_tls = false;
tcp_server.unref();
pending_peers.clear();
- tls_certificate.unref();
- tls_key.unref();
+ tls_server_options.unref();
if (current_packet.data != nullptr) {
memfree(current_packet.data);
current_packet.data = nullptr;
@@ -73,8 +71,8 @@ void WebSocketMultiplayerPeer::_clear() {
}
void WebSocketMultiplayerPeer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_client", "url", "verify_tls", "tls_certificate"), &WebSocketMultiplayerPeer::create_client, DEFVAL(true), DEFVAL(Ref<X509Certificate>()));
- ClassDB::bind_method(D_METHOD("create_server", "port", "bind_address", "tls_key", "tls_certificate"), &WebSocketMultiplayerPeer::create_server, DEFVAL("*"), DEFVAL(Ref<CryptoKey>()), DEFVAL(Ref<X509Certificate>()));
+ ClassDB::bind_method(D_METHOD("create_client", "url", "tls_client_options"), &WebSocketMultiplayerPeer::create_client, DEFVAL(Ref<TLSOptions>()));
+ ClassDB::bind_method(D_METHOD("create_server", "port", "bind_address", "tls_server_options"), &WebSocketMultiplayerPeer::create_server, DEFVAL("*"), DEFVAL(Ref<TLSOptions>()));
ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebSocketMultiplayerPeer::get_peer);
ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &WebSocketMultiplayerPeer::get_peer_address);
@@ -179,8 +177,9 @@ int WebSocketMultiplayerPeer::get_max_packet_size() const {
return get_outbound_buffer_size() - PROTO_SIZE;
}
-Error WebSocketMultiplayerPeer::create_server(int p_port, IPAddress p_bind_ip, Ref<CryptoKey> p_tls_key, Ref<X509Certificate> p_tls_certificate) {
+Error WebSocketMultiplayerPeer::create_server(int p_port, IPAddress p_bind_ip, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(get_connection_status() != CONNECTION_DISCONNECTED, ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(p_options.is_valid() && !p_options->is_server(), ERR_INVALID_PARAMETER);
_clear();
tcp_server.instantiate();
Error err = tcp_server->listen(p_port, p_bind_ip);
@@ -190,20 +189,16 @@ Error WebSocketMultiplayerPeer::create_server(int p_port, IPAddress p_bind_ip, R
}
unique_id = 1;
connection_status = CONNECTION_CONNECTED;
- // TLS config
- tls_key = p_tls_key;
- tls_certificate = p_tls_certificate;
- if (tls_key.is_valid() && tls_certificate.is_valid()) {
- use_tls = true;
- }
+ tls_server_options = p_options;
return OK;
}
-Error WebSocketMultiplayerPeer::create_client(const String &p_url, bool p_verify_tls, Ref<X509Certificate> p_tls_certificate) {
+Error WebSocketMultiplayerPeer::create_client(const String &p_url, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(get_connection_status() != CONNECTION_DISCONNECTED, ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(p_options.is_valid() && p_options->is_server(), ERR_INVALID_PARAMETER);
_clear();
Ref<WebSocketPeer> peer = _create_peer();
- Error err = peer->connect_to_url(p_url, p_verify_tls, p_tls_certificate);
+ Error err = peer->connect_to_url(p_url, p_options);
if (err != OK) {
return err;
}
@@ -334,14 +329,14 @@ void WebSocketMultiplayerPeer::_poll_server() {
to_remove.insert(id); // Error.
continue;
}
- if (!use_tls) {
+ if (tls_server_options.is_null()) {
peer.ws = _create_peer();
peer.ws->accept_stream(peer.tcp);
continue;
} else {
if (peer.connection == peer.tcp) {
Ref<StreamPeerTLS> tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
- Error err = tls->accept_stream(peer.tcp, tls_key, tls_certificate);
+ Error err = tls->accept_stream(peer.tcp, tls_server_options);
if (err != OK) {
to_remove.insert(id);
continue;
diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h
index ea10e8799f..22f1bc939b 100644
--- a/modules/websocket/websocket_multiplayer_peer.h
+++ b/modules/websocket/websocket_multiplayer_peer.h
@@ -71,9 +71,7 @@ protected:
Ref<WebSocketPeer> peer_config;
HashMap<int, PendingPeer> pending_peers;
Ref<TCPServer> tcp_server;
- bool use_tls = false;
- Ref<X509Certificate> tls_certificate;
- Ref<CryptoKey> tls_key;
+ Ref<TLSOptions> tls_server_options;
ConnectionStatus connection_status = CONNECTION_DISCONNECTED;
@@ -115,8 +113,8 @@ public:
/* WebSocketPeer */
virtual Ref<WebSocketPeer> get_peer(int p_peer_id) const;
- Error create_client(const String &p_url, bool p_verify_tls, Ref<X509Certificate> p_tls_certificate);
- Error create_server(int p_port, IPAddress p_bind_ip, Ref<CryptoKey> p_tls_key, Ref<X509Certificate> p_tls_certificate);
+ Error create_client(const String &p_url, Ref<TLSOptions> p_options);
+ Error create_server(int p_port, IPAddress p_bind_ip, Ref<TLSOptions> p_options);
void set_supported_protocols(const Vector<String> &p_protocols);
Vector<String> get_supported_protocols() const;
diff --git a/modules/websocket/websocket_peer.cpp b/modules/websocket/websocket_peer.cpp
index d10315f64c..3c0d316bc9 100644
--- a/modules/websocket/websocket_peer.cpp
+++ b/modules/websocket/websocket_peer.cpp
@@ -39,7 +39,7 @@ WebSocketPeer::~WebSocketPeer() {
}
void WebSocketPeer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("connect_to_url", "url", "verify_tls", "trusted_tls_certificate"), &WebSocketPeer::connect_to_url, DEFVAL(true), DEFVAL(Ref<X509Certificate>()));
+ ClassDB::bind_method(D_METHOD("connect_to_url", "url", "tls_client_options"), &WebSocketPeer::connect_to_url, DEFVAL(Ref<TLSOptions>()));
ClassDB::bind_method(D_METHOD("accept_stream", "stream"), &WebSocketPeer::accept_stream);
ClassDB::bind_method(D_METHOD("send", "message", "write_mode"), &WebSocketPeer::_send_bind, DEFVAL(WRITE_MODE_BINARY));
ClassDB::bind_method(D_METHOD("send_text", "message"), &WebSocketPeer::send_text);
diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h
index 3a1527b769..3110e87071 100644
--- a/modules/websocket/websocket_peer.h
+++ b/modules/websocket/websocket_peer.h
@@ -81,7 +81,7 @@ public:
return _create();
}
- virtual Error connect_to_url(const String &p_url, bool p_verify_tls = true, Ref<X509Certificate> p_cert = Ref<X509Certificate>()) { return ERR_UNAVAILABLE; };
+ virtual Error connect_to_url(const String &p_url, Ref<TLSOptions> p_options = Ref<TLSOptions>()) = 0;
virtual Error accept_stream(Ref<StreamPeer> p_stream) = 0;
virtual Error send(const uint8_t *p_buffer, int p_buffer_size, WriteMode p_mode) = 0;
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index 9ba286d5ee..8a150c8561 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -333,8 +333,7 @@ void WSLPeer::_do_client_handshake() {
// Start SSL handshake
tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
ERR_FAIL_COND_MSG(tls.is_null(), "SSL is not available in this build.");
- tls->set_blocking_handshake_enabled(false);
- if (tls->connect_to_stream(tcp, verify_tls, requested_host, tls_cert) != OK) {
+ if (tls->connect_to_stream(tcp, requested_host, tls_options) != OK) {
close(-1);
return; // Error.
}
@@ -476,9 +475,10 @@ bool WSLPeer::_verify_server_response() {
return true;
}
-Error WSLPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509Certificate> p_cert) {
+Error WSLPeer::connect_to_url(const String &p_url, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(wsl_ctx || tcp.is_valid(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(p_url.is_empty(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_options.is_valid() && p_options->is_server(), ERR_INVALID_PARAMETER);
_clear();
@@ -506,8 +506,13 @@ Error WSLPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509Ce
requested_url = p_url;
requested_host = host;
- verify_tls = p_verify_tls;
- tls_cert = p_cert;
+
+ if (p_options.is_valid()) {
+ tls_options = p_options;
+ } else {
+ tls_options = TLSOptions::client();
+ }
+
tcp.instantiate();
resolver.start(host, port);
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index fc81d39a37..c06e768b6d 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -102,8 +102,7 @@ private:
// WebSocket configuration.
bool use_tls = true;
- bool verify_tls = true;
- Ref<X509Certificate> tls_cert;
+ Ref<TLSOptions> tls_options;
// Packet buffers.
Vector<uint8_t> packet_buffer;
@@ -132,7 +131,7 @@ public:
// WebSocketPeer
virtual Error send(const uint8_t *p_buffer, int p_buffer_size, WriteMode p_mode) override;
- virtual Error connect_to_url(const String &p_url, bool p_verify_tls = true, Ref<X509Certificate> p_cert = Ref<X509Certificate>()) override;
+ virtual Error connect_to_url(const String &p_url, Ref<TLSOptions> p_options = Ref<TLSOptions>()) override;
virtual Error accept_stream(Ref<StreamPeer> p_stream) override;
virtual void close(int p_code = 1000, String p_reason = "") override;
virtual void poll() override;