Browse Source

New PacketPeerDTLS and DTLSServer classes.

Custom instance implementation via the mbedtls module.
Fabio Alessandrelli 6 years ago
parent
commit
35a9f0fe64

+ 54 - 0
core/io/dtls_server.cpp

@@ -0,0 +1,54 @@
+/*************************************************************************/
+/*  dtls_server.cpp                                                      */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "dtls_server.h"
+#include "core/os/file_access.h"
+#include "core/project_settings.h"
+
+DTLSServer *(*DTLSServer::_create)() = NULL;
+bool DTLSServer::available = false;
+
+DTLSServer *DTLSServer::create() {
+
+	return _create();
+}
+
+bool DTLSServer::is_available() {
+	return available;
+}
+
+void DTLSServer::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("setup", "key", "certificate", "chain"), &DTLSServer::setup, DEFVAL(Ref<X509Certificate>()));
+	ClassDB::bind_method(D_METHOD("take_connection", "udp_peer"), &DTLSServer::take_connection);
+}
+
+DTLSServer::DTLSServer() {
+}

+ 57 - 0
core/io/dtls_server.h

@@ -0,0 +1,57 @@
+/*************************************************************************/
+/*  dtls_server.h                                                        */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef DTLS_SERVER_H
+#define DTLS_SERVER_H
+
+#include "core/io/net_socket.h"
+#include "core/io/packet_peer_dtls.h"
+
+class DTLSServer : public Reference {
+	GDCLASS(DTLSServer, Reference);
+
+protected:
+	static DTLSServer *(*_create)();
+	static void _bind_methods();
+
+	static bool available;
+
+public:
+	static bool is_available();
+	static DTLSServer *create();
+
+	virtual Error setup(Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>()) = 0;
+	virtual void stop() = 0;
+	virtual Ref<PacketPeerDTLS> take_connection(Ref<PacketPeerUDP> p_peer) = 0;
+
+	DTLSServer();
+};
+
+#endif // DTLS_SERVER_H

+ 62 - 0
core/io/packet_peer_dtls.cpp

@@ -0,0 +1,62 @@
+/*************************************************************************/
+/*  packet_peer_dtls.cpp                                                 */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "packet_peer_dtls.h"
+#include "core/os/file_access.h"
+#include "core/project_settings.h"
+
+PacketPeerDTLS *(*PacketPeerDTLS::_create)() = NULL;
+bool PacketPeerDTLS::available = false;
+
+PacketPeerDTLS *PacketPeerDTLS::create() {
+
+	return _create();
+}
+
+bool PacketPeerDTLS::is_available() {
+	return available;
+}
+
+void PacketPeerDTLS::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("poll"), &PacketPeerDTLS::poll);
+	ClassDB::bind_method(D_METHOD("connect_to_peer", "packet_peer", "validate_certs", "for_hostname", "valid_certificate"), &PacketPeerDTLS::connect_to_peer, DEFVAL(true), DEFVAL(String()), DEFVAL(Ref<X509Certificate>()));
+	ClassDB::bind_method(D_METHOD("get_status"), &PacketPeerDTLS::get_status);
+	ClassDB::bind_method(D_METHOD("disconnect_from_peer"), &PacketPeerDTLS::disconnect_from_peer);
+
+	BIND_ENUM_CONSTANT(STATUS_DISCONNECTED);
+	BIND_ENUM_CONSTANT(STATUS_HANDSHAKING);
+	BIND_ENUM_CONSTANT(STATUS_CONNECTED);
+	BIND_ENUM_CONSTANT(STATUS_ERROR);
+	BIND_ENUM_CONSTANT(STATUS_ERROR_HOSTNAME_MISMATCH);
+}
+
+PacketPeerDTLS::PacketPeerDTLS() {
+}

+ 68 - 0
core/io/packet_peer_dtls.h

@@ -0,0 +1,68 @@
+/*************************************************************************/
+/*  packet_peer_dtls.h                                                   */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef PACKET_PEER_DTLS_H
+#define PACKET_PEER_DTLS_H
+
+#include "core/crypto/crypto.h"
+#include "core/io/packet_peer_udp.h"
+
+class PacketPeerDTLS : public PacketPeer {
+	GDCLASS(PacketPeerDTLS, PacketPeer);
+
+protected:
+	static PacketPeerDTLS *(*_create)();
+	static void _bind_methods();
+
+	static bool available;
+
+public:
+	enum Status {
+		STATUS_DISCONNECTED,
+		STATUS_HANDSHAKING,
+		STATUS_CONNECTED,
+		STATUS_ERROR,
+		STATUS_ERROR_HOSTNAME_MISMATCH
+	};
+
+	virtual void poll() = 0;
+	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>()) = 0;
+	virtual void disconnect_from_peer() = 0;
+	virtual Status get_status() const = 0;
+
+	static PacketPeerDTLS *create();
+	static bool is_available();
+
+	PacketPeerDTLS();
+};
+
+VARIANT_ENUM_CAST(PacketPeerDTLS::Status);
+
+#endif // PACKET_PEER_DTLS_H

+ 4 - 0
core/register_core_types.cpp

@@ -40,12 +40,14 @@
 #include "core/func_ref.h"
 #include "core/input_map.h"
 #include "core/io/config_file.h"
+#include "core/io/dtls_server.h"
 #include "core/io/http_client.h"
 #include "core/io/image_loader.h"
 #include "core/io/marshalls.h"
 #include "core/io/multiplayer_api.h"
 #include "core/io/networked_multiplayer_peer.h"
 #include "core/io/packet_peer.h"
+#include "core/io/packet_peer_dtls.h"
 #include "core/io/packet_peer_udp.h"
 #include "core/io/pck_packer.h"
 #include "core/io/resource_format_binary.h"
@@ -157,6 +159,8 @@ void register_core_types() {
 	ClassDB::register_class<TCP_Server>();
 	ClassDB::register_class<PacketPeerUDP>();
 	ClassDB::register_class<UDPServer>();
+	ClassDB::register_custom_instance_class<PacketPeerDTLS>();
+	ClassDB::register_custom_instance_class<DTLSServer>();
 
 	// Crypto
 	ClassDB::register_class<HashingContext>();

+ 78 - 0
modules/mbedtls/dtls_server_mbedtls.cpp

@@ -0,0 +1,78 @@
+/*************************************************************************/
+/*  dtls_server_mbedtls.cpp                                              */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#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;
+	return OK;
+}
+
+void DTLSServerMbedTLS::stop() {
+	_cookies->clear();
+}
+
+Ref<PacketPeerDTLS> DTLSServerMbedTLS::take_connection(Ref<PacketPeerUDP> p_udp_peer) {
+	Ref<PacketPeerMbedDTLS> out;
+	out.instance();
+
+	ERR_FAIL_COND_V(!out.is_valid(), out);
+	ERR_FAIL_COND_V(!p_udp_peer.is_valid(), out);
+	out->accept_peer(p_udp_peer, _key, _cert, _ca_chain, _cookies);
+	return out;
+}
+
+DTLSServer *DTLSServerMbedTLS::_create_func() {
+
+	return memnew(DTLSServerMbedTLS);
+}
+
+void DTLSServerMbedTLS::initialize() {
+
+	_create = _create_func;
+	available = true;
+}
+
+void DTLSServerMbedTLS::finalize() {
+	_create = NULL;
+	available = false;
+}
+
+DTLSServerMbedTLS::DTLSServerMbedTLS() {
+	_cookies.instance();
+}
+
+DTLSServerMbedTLS::~DTLSServerMbedTLS() {
+	stop();
+}

+ 58 - 0
modules/mbedtls/dtls_server_mbedtls.h

@@ -0,0 +1,58 @@
+/*************************************************************************/
+/*  dtls_server_mbedtls.h                                                */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef MBED_DTLS_SERVER_H
+#define MBED_DTLS_SERVER_H
+
+#include "core/io/dtls_server.h"
+#include "ssl_context_mbedtls.h"
+
+class DTLSServerMbedTLS : public DTLSServer {
+
+private:
+	static DTLSServer *_create_func();
+	Ref<CryptoKey> _key;
+	Ref<X509Certificate> _cert;
+	Ref<X509Certificate> _ca_chain;
+	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 void stop();
+	virtual Ref<PacketPeerDTLS> take_connection(Ref<PacketPeerUDP> p_peer);
+
+	DTLSServerMbedTLS();
+	~DTLSServerMbedTLS();
+};
+
+#endif // MBED_DTLS_SERVER_H

+ 297 - 0
modules/mbedtls/packet_peer_mbed_dtls.cpp

@@ -0,0 +1,297 @@
+/*************************************************************************/
+/*  packet_peer_mbed_dtls.cpp                                            */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "packet_peer_mbed_dtls.h"
+#include "mbedtls/platform_util.h"
+
+#include "core/io/stream_peer_ssl.h"
+#include "core/os/file_access.h"
+
+int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
+
+	if (buf == NULL || len <= 0) return 0;
+
+	PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx;
+
+	ERR_FAIL_COND_V(sp == NULL, 0);
+
+	Error err = sp->base->put_packet((const uint8_t *)buf, len);
+	if (err == ERR_BUSY) {
+		return MBEDTLS_ERR_SSL_WANT_WRITE;
+	} else if (err != OK) {
+		ERR_FAIL_V(MBEDTLS_ERR_SSL_INTERNAL_ERROR);
+	}
+	return len;
+}
+
+int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
+
+	if (buf == NULL || len <= 0) return 0;
+
+	PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx;
+
+	ERR_FAIL_COND_V(sp == NULL, 0);
+
+	int pc = sp->base->get_available_packet_count();
+	if (pc == 0) {
+		return MBEDTLS_ERR_SSL_WANT_READ;
+	} else if (pc < 0) {
+		ERR_FAIL_V(MBEDTLS_ERR_SSL_INTERNAL_ERROR);
+	}
+
+	const uint8_t *buffer;
+	int buffer_size = 0;
+	Error err = sp->base->get_packet(&buffer, buffer_size);
+	if (err != OK) {
+		return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+	}
+	copymem(buf, buffer, buffer_size);
+	return buffer_size;
+}
+
+void PacketPeerMbedDTLS::_cleanup() {
+
+	ssl_ctx->clear();
+	base = Ref<PacketPeer>();
+	status = STATUS_DISCONNECTED;
+}
+
+int PacketPeerMbedDTLS::_set_cookie() {
+	// Setup DTLS session cookie for this client
+	uint8_t client_id[18];
+	IP_Address addr = base->get_packet_address();
+	uint16_t port = base->get_packet_port();
+	copymem(client_id, addr.get_ipv6(), 16);
+	copymem(&client_id[16], (uint8_t *)&port, 2);
+	return mbedtls_ssl_set_client_transport_id(ssl_ctx->get_context(), client_id, 18);
+}
+
+Error PacketPeerMbedDTLS::_do_handshake() {
+	int ret = 0;
+	while ((ret = mbedtls_ssl_handshake(ssl_ctx->get_context())) != 0) {
+		if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+			if (ret != MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {
+				ERR_PRINT("TLS handshake error: " + itos(ret));
+				SSLContextMbedTLS::print_mbedtls_error(ret);
+			}
+			_cleanup();
+			status = STATUS_ERROR;
+			return FAILED;
+		}
+		// Will retry via poll later
+		return OK;
+	}
+
+	status = STATUS_CONNECTED;
+	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) {
+
+	ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_connected_to_host(), ERR_INVALID_PARAMETER);
+
+	base = p_base;
+	int ret = 0;
+	int authmode = p_validate_certs ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE;
+
+	Error err = ssl_ctx->init_client(MBEDTLS_SSL_TRANSPORT_DATAGRAM, authmode, p_ca_certs);
+	ERR_FAIL_COND_V(err != OK, err);
+
+	mbedtls_ssl_set_hostname(ssl_ctx->get_context(), p_for_hostname.utf8().get_data());
+	mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, NULL);
+	mbedtls_ssl_set_timer_cb(ssl_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
+
+	status = STATUS_HANDSHAKING;
+
+	if ((ret = _do_handshake()) != OK) {
+		status = STATUS_ERROR_HOSTNAME_MISMATCH;
+		return FAILED;
+	}
+
+	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 = ssl_ctx->init_server(MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_VERIFY_NONE, p_key, p_cert, p_cookies);
+	ERR_FAIL_COND_V(err != OK, err);
+
+	base = p_base;
+	base->set_blocking_mode(false);
+
+	mbedtls_ssl_session_reset(ssl_ctx->get_context());
+
+	int ret = _set_cookie();
+	if (ret != 0) {
+		_cleanup();
+		ERR_FAIL_V_MSG(FAILED, "Error setting DTLS client cookie");
+	}
+
+	mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, NULL);
+	mbedtls_ssl_set_timer_cb(ssl_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
+
+	status = STATUS_HANDSHAKING;
+
+	if ((ret = _do_handshake()) != OK) {
+		status = STATUS_ERROR;
+		return FAILED;
+	}
+
+	return OK;
+}
+
+Error PacketPeerMbedDTLS::put_packet(const uint8_t *p_buffer, int p_bytes) {
+
+	ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
+
+	if (p_bytes == 0)
+		return OK;
+
+	int ret = mbedtls_ssl_write(ssl_ctx->get_context(), p_buffer, p_bytes);
+	if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+		ret = 0; // non blocking io
+	} else if (ret <= 0) {
+		SSLContextMbedTLS::print_mbedtls_error(ret);
+		_cleanup();
+		return ERR_CONNECTION_ERROR;
+	}
+
+	return OK;
+}
+
+Error PacketPeerMbedDTLS::get_packet(const uint8_t **r_buffer, int &r_bytes) {
+
+	ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
+
+	r_bytes = 0;
+
+	int ret = mbedtls_ssl_read(ssl_ctx->get_context(), packet_buffer, PACKET_BUFFER_SIZE);
+	if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+		ret = 0; // non blocking io
+	} else if (ret <= 0) {
+		if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
+			// Also send close notify back
+			disconnect_from_peer();
+		} else {
+			_cleanup();
+			status = STATUS_ERROR;
+			SSLContextMbedTLS::print_mbedtls_error(ret);
+		}
+		return ERR_CONNECTION_ERROR;
+	}
+	*r_buffer = packet_buffer;
+	r_bytes = ret;
+
+	return OK;
+}
+
+void PacketPeerMbedDTLS::poll() {
+
+	if (status == STATUS_HANDSHAKING) {
+		_do_handshake();
+		return;
+	} else if (status != STATUS_CONNECTED) {
+		return;
+	}
+
+	ERR_FAIL_COND(!base.is_valid());
+
+	int ret = mbedtls_ssl_read(ssl_ctx->get_context(), NULL, 0);
+
+	if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+		if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
+			// Also send close notify back
+			disconnect_from_peer();
+		} else {
+			_cleanup();
+			status = STATUS_ERROR;
+			SSLContextMbedTLS::print_mbedtls_error(ret);
+		}
+	}
+}
+
+int PacketPeerMbedDTLS::get_available_packet_count() const {
+
+	ERR_FAIL_COND_V(status != STATUS_CONNECTED, 0);
+
+	return mbedtls_ssl_get_bytes_avail(&(ssl_ctx->ssl)) > 0 ? 1 : 0;
+}
+
+int PacketPeerMbedDTLS::get_max_packet_size() const {
+
+	return 488; // 512 (UDP in Godot) - 24 (DTLS header)
+}
+
+PacketPeerMbedDTLS::PacketPeerMbedDTLS() {
+
+	ssl_ctx.instance();
+	status = STATUS_DISCONNECTED;
+}
+
+PacketPeerMbedDTLS::~PacketPeerMbedDTLS() {
+	disconnect_from_peer();
+}
+
+void PacketPeerMbedDTLS::disconnect_from_peer() {
+
+	if (status != STATUS_CONNECTED && status != STATUS_HANDSHAKING)
+		return;
+
+	if (status == STATUS_CONNECTED) {
+		int ret = 0;
+		// Send SSL close notification, blocking, but ignore other errors.
+		do
+			ret = mbedtls_ssl_close_notify(ssl_ctx->get_context());
+		while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+	}
+
+	_cleanup();
+}
+
+PacketPeerMbedDTLS::Status PacketPeerMbedDTLS::get_status() const {
+
+	return status;
+}
+
+PacketPeerDTLS *PacketPeerMbedDTLS::_create_func() {
+
+	return memnew(PacketPeerMbedDTLS);
+}
+
+void PacketPeerMbedDTLS::initialize_dtls() {
+
+	_create = _create_func;
+	available = true;
+}
+
+void PacketPeerMbedDTLS::finalize_dtls() {
+	_create = NULL;
+	available = false;
+}

+ 88 - 0
modules/mbedtls/packet_peer_mbed_dtls.h

@@ -0,0 +1,88 @@
+/*************************************************************************/
+/*  packet_peer_mbed_dtls.h                                              */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef PACKET_PEER_MBED_DTLS_H
+#define PACKET_PEER_MBED_DTLS_H
+
+#include "core/io/packet_peer_dtls.h"
+#include "ssl_context_mbedtls.h"
+
+#include <mbedtls/timing.h>
+
+class PacketPeerMbedDTLS : public PacketPeerDTLS {
+private:
+	enum {
+		PACKET_BUFFER_SIZE = 65536
+	};
+
+	uint8_t packet_buffer[PACKET_BUFFER_SIZE];
+
+	Status status;
+	String hostname;
+
+	Ref<PacketPeerUDP> base;
+
+	static PacketPeerDTLS *_create_func();
+
+	static int bio_recv(void *ctx, unsigned char *buf, size_t len);
+	static int bio_send(void *ctx, const unsigned char *buf, size_t len);
+	void _cleanup();
+
+protected:
+	Ref<SSLContextMbedTLS> ssl_ctx;
+	mbedtls_timing_delay_context timer;
+
+	static void _bind_methods();
+
+	Error _do_handshake();
+	int _set_cookie();
+
+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 = false, const String &p_for_hostname = String(), Ref<X509Certificate> p_ca_certs = Ref<X509Certificate>());
+	virtual Status get_status() const;
+
+	virtual void disconnect_from_peer();
+
+	virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
+	virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
+
+	virtual int get_available_packet_count() const;
+	virtual int get_max_packet_size() const;
+
+	static void initialize_dtls();
+	static void finalize_dtls();
+
+	PacketPeerMbedDTLS();
+	~PacketPeerMbedDTLS();
+};
+
+#endif // PACKET_PEER_MBED_DTLS_H

+ 6 - 0
modules/mbedtls/register_types.cpp

@@ -31,16 +31,22 @@
 #include "register_types.h"
 
 #include "crypto_mbedtls.h"
+#include "dtls_server_mbedtls.h"
+#include "packet_peer_mbed_dtls.h"
 #include "stream_peer_mbedtls.h"
 
 void register_mbedtls_types() {
 
 	CryptoMbedTLS::initialize_crypto();
 	StreamPeerMbedTLS::initialize_ssl();
+	PacketPeerMbedDTLS::initialize_dtls();
+	DTLSServerMbedTLS::initialize();
 }
 
 void unregister_mbedtls_types() {
 
+	DTLSServerMbedTLS::finalize();
+	PacketPeerMbedDTLS::finalize_dtls();
 	StreamPeerMbedTLS::finalize_ssl();
 	CryptoMbedTLS::finalize_crypto();
 }

+ 54 - 2
modules/mbedtls/ssl_context_mbedtls.cpp

@@ -43,6 +43,48 @@ void SSLContextMbedTLS::print_mbedtls_error(int p_ret) {
 	fflush(stdout);
 }
 
+/// CookieContextMbedTLS
+
+Error CookieContextMbedTLS::setup() {
+	ERR_FAIL_COND_V_MSG(inited, ERR_ALREADY_IN_USE, "This cookie context is already in use");
+
+	mbedtls_ctr_drbg_init(&ctr_drbg);
+	mbedtls_entropy_init(&entropy);
+	mbedtls_ssl_cookie_init(&cookie_ctx);
+	inited = true;
+
+	int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
+	if (ret != 0) {
+		clear(); // Never leave unusable resources around.
+		ERR_FAIL_V_MSG(FAILED, "mbedtls_ctr_drbg_seed returned an error " + itos(ret));
+	}
+
+	ret = mbedtls_ssl_cookie_setup(&cookie_ctx, mbedtls_ctr_drbg_random, &ctr_drbg);
+	if (ret != 0) {
+		clear();
+		ERR_FAIL_V_MSG(FAILED, "mbedtls_ssl_cookie_setup returned an error " + itos(ret));
+	}
+	return OK;
+}
+
+void CookieContextMbedTLS::clear() {
+	if (!inited)
+		return;
+	mbedtls_ctr_drbg_free(&ctr_drbg);
+	mbedtls_entropy_free(&entropy);
+	mbedtls_ssl_cookie_free(&cookie_ctx);
+}
+
+CookieContextMbedTLS::CookieContextMbedTLS() {
+	inited = false;
+}
+
+CookieContextMbedTLS::~CookieContextMbedTLS() {
+	clear();
+}
+
+/// SSLContextMbedTLS
+
 Error SSLContextMbedTLS::_setup(int p_endpoint, int p_transport, int p_authmode) {
 	ERR_FAIL_COND_V_MSG(inited, ERR_ALREADY_IN_USE, "This SSL context is already active");
 
@@ -55,7 +97,7 @@ Error SSLContextMbedTLS::_setup(int p_endpoint, int p_transport, int p_authmode)
 	int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
 	if (ret != 0) {
 		clear(); // Never leave unusable resources around.
-		ERR_FAIL_V_MSG(FAILED, "mbedtls_ctr_drbg_seed returned an error" + itos(ret));
+		ERR_FAIL_V_MSG(FAILED, "mbedtls_ctr_drbg_seed returned an error " + itos(ret));
 	}
 
 	ret = mbedtls_ssl_config_defaults(&conf, p_endpoint, p_transport, MBEDTLS_SSL_PRESET_DEFAULT);
@@ -69,7 +111,7 @@ Error SSLContextMbedTLS::_setup(int p_endpoint, int p_transport, int p_authmode)
 	return OK;
 }
 
-Error SSLContextMbedTLS::init_server(int p_transport, int p_authmode, Ref<CryptoKeyMbedTLS> p_pkey, Ref<X509CertificateMbedTLS> p_cert) {
+Error SSLContextMbedTLS::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);
 
@@ -94,6 +136,15 @@ Error SSLContextMbedTLS::init_server(int p_transport, int p_authmode, Ref<Crypto
 	if (certs->cert.next) {
 		mbedtls_ssl_conf_ca_chain(&conf, certs->cert.next, NULL);
 	}
+	// DTLS Cookies
+	if (p_transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+		if (p_cookies.is_null() || !p_cookies->inited) {
+			clear();
+			ERR_FAIL_V(ERR_BUG);
+		}
+		cookies = p_cookies;
+		mbedtls_ssl_conf_dtls_cookies(&conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &(cookies->cookie_ctx));
+	}
 	mbedtls_ssl_setup(&ssl, &conf);
 	return OK;
 }
@@ -139,6 +190,7 @@ void SSLContextMbedTLS::clear() {
 	if (pkey.is_valid())
 		pkey->unlock();
 	pkey = Ref<CryptoKeyMbedTLS>();
+	cookies = Ref<CookieContextMbedTLS>();
 	inited = false;
 }
 

+ 23 - 1
modules/mbedtls/ssl_context_mbedtls.h

@@ -42,6 +42,27 @@
 #include <mbedtls/debug.h>
 #include <mbedtls/entropy.h>
 #include <mbedtls/ssl.h>
+#include <mbedtls/ssl_cookie.h>
+
+class SSLContextMbedTLS;
+
+class CookieContextMbedTLS : public Reference {
+
+	friend class SSLContextMbedTLS;
+
+protected:
+	bool inited;
+	mbedtls_entropy_context entropy;
+	mbedtls_ctr_drbg_context ctr_drbg;
+	mbedtls_ssl_cookie_ctx cookie_ctx;
+
+public:
+	Error setup();
+	void clear();
+
+	CookieContextMbedTLS();
+	~CookieContextMbedTLS();
+};
 
 class SSLContextMbedTLS : public Reference {
 
@@ -59,10 +80,11 @@ public:
 	mbedtls_ssl_context ssl;
 	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);
+	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);
 	void clear();