mirror of
https://github.com/godotengine/godot.git
synced 2026-01-06 10:11:57 +03:00
[NET] Refactor TLS configuration.
Use a TLSOptions configuration object which is created via static functions. - "TLSOptions.client": uses the standard CA and common name verification. - "TLSOptions.client_unsafe": uses optional CA verification (i.e. if specified) - "TLSOptions.server": is the standard server configuration (chain + key) This will allow us to expand the TLS configuration options to include e.g. mutual authentication without bloating the classes that uses StreamPeerTLS and PacketPeerDTLS as underlying peers.
This commit is contained in:
@@ -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=""*"" />
|
||||
<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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -334,7 +334,7 @@ void WSLPeer::_do_client_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 +476,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 +507,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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user