Path: blob/master/modules/mbedtls/packet_peer_mbed_dtls.cpp
10277 views
/**************************************************************************/1/* packet_peer_mbed_dtls.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "packet_peer_mbed_dtls.h"3132int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {33if (buf == nullptr || len == 0) {34return 0;35}3637PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);3839ERR_FAIL_NULL_V(sp, 0);4041Error err = sp->base->put_packet((const uint8_t *)buf, len);42if (err == ERR_BUSY) {43return MBEDTLS_ERR_SSL_WANT_WRITE;44} else if (err != OK) {45ERR_FAIL_V(MBEDTLS_ERR_SSL_INTERNAL_ERROR);46}47return len;48}4950int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {51if (buf == nullptr || len == 0) {52return 0;53}5455PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);5657ERR_FAIL_NULL_V(sp, 0);5859int pc = sp->base->get_available_packet_count();60if (pc == 0) {61return MBEDTLS_ERR_SSL_WANT_READ;62} else if (pc < 0) {63ERR_FAIL_V(MBEDTLS_ERR_SSL_INTERNAL_ERROR);64}6566const uint8_t *buffer;67int buffer_size = 0;68Error err = sp->base->get_packet(&buffer, buffer_size);69if (err != OK) {70return MBEDTLS_ERR_SSL_INTERNAL_ERROR;71}72memcpy(buf, buffer, buffer_size);73return buffer_size;74}7576void PacketPeerMbedDTLS::_cleanup() {77tls_ctx->clear();78base = Ref<PacketPeer>();79status = STATUS_DISCONNECTED;80}8182int PacketPeerMbedDTLS::_set_cookie() {83// Setup DTLS session cookie for this client84uint8_t client_id[18];85IPAddress addr = base->get_packet_address();86uint16_t port = base->get_packet_port();87memcpy(client_id, addr.get_ipv6(), 16);88memcpy(&client_id[16], (uint8_t *)&port, 2);89return mbedtls_ssl_set_client_transport_id(tls_ctx->get_context(), client_id, 18);90}9192Error PacketPeerMbedDTLS::_do_handshake() {93int ret = 0;94while ((ret = mbedtls_ssl_handshake(tls_ctx->get_context())) != 0) {95if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {96if (ret != MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {97ERR_PRINT("TLS handshake error: " + itos(ret));98TLSContextMbedTLS::print_mbedtls_error(ret);99}100_cleanup();101status = STATUS_ERROR;102return FAILED;103}104// Will retry via poll later105return OK;106}107108status = STATUS_CONNECTED;109return OK;110}111112Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, const String &p_hostname, Ref<TLSOptions> p_options) {113ERR_FAIL_COND_V(p_base.is_null() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);114115Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_DATAGRAM, p_hostname, p_options.is_valid() ? p_options : TLSOptions::client());116ERR_FAIL_COND_V(err != OK, err);117118base = p_base;119120mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);121mbedtls_ssl_set_timer_cb(tls_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);122123status = STATUS_HANDSHAKING;124125if (_do_handshake() != OK) {126status = STATUS_ERROR_HOSTNAME_MISMATCH;127return FAILED;128}129130return OK;131}132133Error PacketPeerMbedDTLS::accept_peer(Ref<PacketPeerUDP> p_base, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies) {134ERR_FAIL_COND_V(p_base.is_null() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);135136Error err = tls_ctx->init_server(MBEDTLS_SSL_TRANSPORT_DATAGRAM, p_options, p_cookies);137ERR_FAIL_COND_V(err != OK, err);138139base = p_base;140base->set_blocking_mode(false);141142mbedtls_ssl_session_reset(tls_ctx->get_context());143144int ret = _set_cookie();145if (ret != 0) {146_cleanup();147ERR_FAIL_V_MSG(FAILED, "Error setting DTLS client cookie");148}149150mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);151mbedtls_ssl_set_timer_cb(tls_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);152153status = STATUS_HANDSHAKING;154155if (_do_handshake() != OK) {156status = STATUS_ERROR;157return FAILED;158}159160return OK;161}162163Error PacketPeerMbedDTLS::put_packet(const uint8_t *p_buffer, int p_bytes) {164ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);165166if (p_bytes == 0) {167return OK;168}169170int ret = mbedtls_ssl_write(tls_ctx->get_context(), p_buffer, p_bytes);171if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {172// Non blocking io.173} else if (ret <= 0) {174TLSContextMbedTLS::print_mbedtls_error(ret);175_cleanup();176return ERR_CONNECTION_ERROR;177}178179return OK;180}181182Error PacketPeerMbedDTLS::get_packet(const uint8_t **r_buffer, int &r_bytes) {183ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);184185r_bytes = 0;186187int ret = mbedtls_ssl_read(tls_ctx->get_context(), packet_buffer, PACKET_BUFFER_SIZE);188if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {189ret = 0; // non blocking io190} else if (ret <= 0) {191if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {192// Also send close notify back193disconnect_from_peer();194} else {195_cleanup();196status = STATUS_ERROR;197TLSContextMbedTLS::print_mbedtls_error(ret);198}199return ERR_CONNECTION_ERROR;200}201*r_buffer = packet_buffer;202r_bytes = ret;203204return OK;205}206207void PacketPeerMbedDTLS::poll() {208if (status == STATUS_HANDSHAKING) {209_do_handshake();210return;211} else if (status != STATUS_CONNECTED) {212return;213}214215ERR_FAIL_COND(base.is_null());216217int ret = mbedtls_ssl_read(tls_ctx->get_context(), nullptr, 0);218219if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {220if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {221// Also send close notify back222disconnect_from_peer();223} else {224_cleanup();225status = STATUS_ERROR;226TLSContextMbedTLS::print_mbedtls_error(ret);227}228}229}230231int PacketPeerMbedDTLS::get_available_packet_count() const {232ERR_FAIL_COND_V(status != STATUS_CONNECTED, 0);233234return mbedtls_ssl_get_bytes_avail(&(tls_ctx->tls)) > 0 ? 1 : 0;235}236237int PacketPeerMbedDTLS::get_max_packet_size() const {238return 488; // 512 (UDP in Godot) - 24 (DTLS header)239}240241PacketPeerMbedDTLS::PacketPeerMbedDTLS() {242tls_ctx.instantiate();243}244245PacketPeerMbedDTLS::~PacketPeerMbedDTLS() {246disconnect_from_peer();247}248249void PacketPeerMbedDTLS::disconnect_from_peer() {250if (status != STATUS_CONNECTED && status != STATUS_HANDSHAKING) {251return;252}253254if (status == STATUS_CONNECTED) {255int ret = 0;256// Send SSL close notification, blocking, but ignore other errors.257do {258ret = mbedtls_ssl_close_notify(tls_ctx->get_context());259} while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);260}261262_cleanup();263}264265PacketPeerMbedDTLS::Status PacketPeerMbedDTLS::get_status() const {266return status;267}268269PacketPeerDTLS *PacketPeerMbedDTLS::_create_func(bool p_notify_postinitialize) {270return static_cast<PacketPeerDTLS *>(ClassDB::creator<PacketPeerMbedDTLS>(p_notify_postinitialize));271}272273void PacketPeerMbedDTLS::initialize_dtls() {274_create = _create_func;275available = true;276}277278void PacketPeerMbedDTLS::finalize_dtls() {279_create = nullptr;280available = false;281}282283284