Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mbedTLS] Integrate TLS handshake defragmentation PR #103247

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/classes/EditorSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,10 @@
<member name="network/tls/editor_tls_certificates" type="String" setter="" getter="">
The TLS certificate bundle to use for HTTP requests made within the editor (e.g. from the AssetLib tab). If left empty, the [url=https://github.com/godotengine/godot/blob/master/thirdparty/certs/ca-certificates.crt]included Mozilla certificate bundle[/url] will be used.
</member>
<member name="network/tls/enable_tls_v1.3" type="bool" setter="" getter="">
If [code]true[/code], enable TLSv1.3 negotiation.
[b]Note:[/b] Only supported when using Mbed TLS 3.0 or later (Linux distribution packages may be compiled against older system Mbed TLS packages), otherwise the maximum supported TLS version is always TLSv1.2.
</member>
<member name="project_manager/default_renderer" type="String" setter="" getter="">
The renderer type that will be checked off by default when creating a new project. Accepted strings are "forward_plus", "mobile" or "gl_compatibility".
</member>
Expand Down
3 changes: 1 addition & 2 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2204,9 +2204,8 @@
The CA certificates bundle to use for TLS connections. If this is set to a non-empty value, this will [i]override[/i] Godot's default [url=https://github.com/godotengine/godot/blob/master/thirdparty/certs/ca-certificates.crt]Mozilla certificate bundle[/url]. If left empty, the default certificate bundle will be used.
If in doubt, leave this setting empty.
</member>
<member name="network/tls/enable_tls_v1.3" type="bool" setter="" getter="" default="false">
<member name="network/tls/enable_tls_v1.3" type="bool" setter="" getter="" default="true">
If [code]true[/code], enable TLSv1.3 negotiation.
[b]Note:[/b] This is experimental, and may cause connections to fail in some cases (notably, if the remote server uses TLS handshake fragmentation).
[b]Note:[/b] Only supported when using Mbed TLS 3.0 or later (Linux distribution packages may be compiled against older system Mbed TLS packages), otherwise the maximum supported TLS version is always TLSv1.2.
</member>
<member name="physics/2d/default_angular_damp" type="float" setter="" getter="" default="1.0">
Expand Down
1 change: 1 addition & 0 deletions editor/editor_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {

// SSL
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/tls/editor_tls_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "network/tls/enable_tls_v1.3", true, "")

// Debug
_initial_set("network/debug/remote_host", "127.0.0.1"); // Hints provided in setup_network
Expand Down
2 changes: 1 addition & 1 deletion modules/mbedtls/register_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void initialize_mbedtls_module(ModuleInitializationLevel p_level) {
return;
}

GLOBAL_DEF("network/tls/enable_tls_v1.3", false);
GLOBAL_DEF("network/tls/enable_tls_v1.3", true);

#if MBEDTLS_VERSION_MAJOR >= 3
int status = psa_crypto_init();
Expand Down
30 changes: 26 additions & 4 deletions modules/mbedtls/tls_context_mbedtls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@

#include "core/config/project_settings.h"

#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
#endif // TOOLS_ENABLED
Comment on lines +35 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically not editor code shouldn't include editor headers (see #53295), but we have quite a few exceptions.
In this case I don't see any easy way to avoid this, it would need to be passed as a argument from where mbedtls is used in the editor, and that seems worse than allowing this exception.


static void my_debug(void *ctx, int level,
const char *file, int line,
const char *str) {
Expand Down Expand Up @@ -148,8 +152,17 @@ Error TLSContextMbedTLS::init_server(int p_transport, Ref<TLSOptions> p_options,
}

#if MBEDTLS_VERSION_MAJOR >= 3
if (Engine::get_singleton()->is_editor_hint() || !(bool)GLOBAL_GET("network/tls/enable_tls_v1.3")) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (!EditorSettings::get_singleton()->get_setting("network/tls/enable_tls_v1.3").operator bool()) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
}
} else
#endif
{
if (!GLOBAL_GET("network/tls/enable_tls_v1.3").operator bool()) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
}
}
#endif

Expand Down Expand Up @@ -197,8 +210,17 @@ Error TLSContextMbedTLS::init_client(int p_transport, const String &p_hostname,
}

#if MBEDTLS_VERSION_MAJOR >= 3
if (Engine::get_singleton()->is_editor_hint() || !(bool)GLOBAL_GET("network/tls/enable_tls_v1.3")) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (!EditorSettings::get_singleton()->get_setting("network/tls/enable_tls_v1.3").operator bool()) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
}
} else
#endif
{
if (!GLOBAL_GET("network/tls/enable_tls_v1.3").operator bool()) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
}
}
#endif

Expand Down
1 change: 1 addition & 0 deletions thirdparty/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ File extracted from upstream release tarball:
Patches:

- `0001-msvc-2019-psa-redeclaration.patch` (GH-90535)
- `0002-pr-9981-defragment-incoming-tls-handshake-messages.patch` (GH-103247)


## meshoptimizer
Expand Down
11 changes: 10 additions & 1 deletion thirdparty/mbedtls/include/mbedtls/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1724,7 +1724,16 @@ struct mbedtls_ssl_context {
int MBEDTLS_PRIVATE(early_data_state);
#endif

unsigned MBEDTLS_PRIVATE(badmac_seen); /*!< records with a bad MAC received */
/** Multipurpose field.
*
* - DTLS: records with a bad MAC received.
* - TLS: accumulated length of handshake fragments (up to \c in_hslen).
*
* This field is multipurpose in order to preserve the ABI in the
* Mbed TLS 3.6 LTS branch. Until 3.6.2, it was only used in DTLS
* and called `badmac_seen`.
*/
unsigned MBEDTLS_PRIVATE(badmac_seen_or_in_hsfraglen);

#if defined(MBEDTLS_X509_CRT_PARSE_C)
/** Callback to customize X.509 certificate chain verification */
Expand Down
5 changes: 3 additions & 2 deletions thirdparty/mbedtls/library/ssl_misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1829,10 +1829,11 @@ void mbedtls_ssl_set_timer(mbedtls_ssl_context *ssl, uint32_t millisecs);
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_check_timer(mbedtls_ssl_context *ssl);

void mbedtls_ssl_reset_in_out_pointers(mbedtls_ssl_context *ssl);
void mbedtls_ssl_reset_in_pointers(mbedtls_ssl_context *ssl);
void mbedtls_ssl_update_in_pointers(mbedtls_ssl_context *ssl);
void mbedtls_ssl_reset_out_pointers(mbedtls_ssl_context *ssl);
void mbedtls_ssl_update_out_pointers(mbedtls_ssl_context *ssl,
mbedtls_ssl_transform *transform);
void mbedtls_ssl_update_in_pointers(mbedtls_ssl_context *ssl);

MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_session_reset_int(mbedtls_ssl_context *ssl, int partial);
Expand Down
120 changes: 103 additions & 17 deletions thirdparty/mbedtls/library/ssl_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "constant_time_internal.h"
#include "mbedtls/constant_time.h"

#include <limits.h>
#include <string.h>

#if defined(MBEDTLS_USE_PSA_CRYPTO)
Expand Down Expand Up @@ -3220,13 +3221,17 @@ static uint32_t ssl_get_hs_total_len(mbedtls_ssl_context const *ssl)

int mbedtls_ssl_prepare_handshake_record(mbedtls_ssl_context *ssl)
{
if (ssl->in_msglen < mbedtls_ssl_hs_hdr_len(ssl)) {
/* First handshake fragment must at least include the header. */
if (ssl->in_msglen < mbedtls_ssl_hs_hdr_len(ssl) && ssl->in_hslen == 0) {
MBEDTLS_SSL_DEBUG_MSG(1, ("handshake message too short: %" MBEDTLS_PRINTF_SIZET,
ssl->in_msglen));
return MBEDTLS_ERR_SSL_INVALID_RECORD;
}

ssl->in_hslen = mbedtls_ssl_hs_hdr_len(ssl) + ssl_get_hs_total_len(ssl);
if (ssl->in_hslen == 0) {
ssl->in_hslen = mbedtls_ssl_hs_hdr_len(ssl) + ssl_get_hs_total_len(ssl);
ssl->badmac_seen_or_in_hsfraglen = 0;
}

MBEDTLS_SSL_DEBUG_MSG(3, ("handshake message: msglen ="
" %" MBEDTLS_PRINTF_SIZET ", type = %u, hslen = %"
Expand Down Expand Up @@ -3292,10 +3297,67 @@ int mbedtls_ssl_prepare_handshake_record(mbedtls_ssl_context *ssl)
}
} else
#endif /* MBEDTLS_SSL_PROTO_DTLS */
/* With TLS we don't handle fragmentation (for now) */
if (ssl->in_msglen < ssl->in_hslen) {
MBEDTLS_SSL_DEBUG_MSG(1, ("TLS handshake fragmentation not supported"));
return MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
if (ssl->badmac_seen_or_in_hsfraglen <= ssl->in_hslen) {
int ret;
const size_t hs_remain = ssl->in_hslen - ssl->badmac_seen_or_in_hsfraglen;
MBEDTLS_SSL_DEBUG_MSG(3,
("handshake fragment: %u .. %"
MBEDTLS_PRINTF_SIZET " of %"
MBEDTLS_PRINTF_SIZET " msglen %" MBEDTLS_PRINTF_SIZET,
ssl->badmac_seen_or_in_hsfraglen,
(size_t) ssl->badmac_seen_or_in_hsfraglen +
(hs_remain <= ssl->in_msglen ? hs_remain : ssl->in_msglen),
ssl->in_hslen, ssl->in_msglen));
if (ssl->in_msglen < hs_remain) {
/* ssl->in_msglen is a 25-bit value since it is the sum of the
* header length plus the payload length, the header length is 4
* and the payload length was received on the wire encoded as
* 3 octets. We don't support 16-bit platforms; more specifically,
* we assume that both unsigned and size_t are at least 32 bits.
* Therefore there is no possible integer overflow here.
*/
ssl->badmac_seen_or_in_hsfraglen += (unsigned) ssl->in_msglen;
ssl->in_hdr = ssl->in_msg + ssl->in_msglen;
ssl->in_msglen = 0;
mbedtls_ssl_update_in_pointers(ssl);
return MBEDTLS_ERR_SSL_CONTINUE_PROCESSING;
}
if (ssl->badmac_seen_or_in_hsfraglen > 0) {
/*
* At in_first_hdr we have a sequence of records that cover the next handshake
* record, each with its own record header that we need to remove.
* Note that the reassembled record size may not equal the size of the message,
* there may be more messages after it, complete or partial.
*/
unsigned char *in_first_hdr = ssl->in_buf + MBEDTLS_SSL_SEQUENCE_NUMBER_LEN;
unsigned char *p = in_first_hdr, *q = NULL;
size_t merged_rec_len = 0;
do {
mbedtls_record rec;
ret = ssl_parse_record_header(ssl, p, mbedtls_ssl_in_hdr_len(ssl), &rec);
if (ret != 0) {
return ret;
}
merged_rec_len += rec.data_len;
p = rec.buf + rec.buf_len;
if (q != NULL) {
memmove(q, rec.buf + rec.data_offset, rec.data_len);
q += rec.data_len;
} else {
q = p;
}
} while (merged_rec_len < ssl->in_hslen);
ssl->in_hdr = in_first_hdr;
mbedtls_ssl_update_in_pointers(ssl);
ssl->in_msglen = merged_rec_len;
/* Adjust message length. */
MBEDTLS_PUT_UINT16_BE(merged_rec_len, ssl->in_len, 0);
ssl->badmac_seen_or_in_hsfraglen = 0;
MBEDTLS_SSL_DEBUG_BUF(4, "reassembled record",
ssl->in_hdr, mbedtls_ssl_in_hdr_len(ssl) + merged_rec_len);
}
} else {
return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
}

return 0;
Expand Down Expand Up @@ -4640,6 +4702,16 @@ static int ssl_consume_current_message(mbedtls_ssl_context *ssl)
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}

if (ssl->badmac_seen_or_in_hsfraglen != 0) {
/* Not all handshake fragments have arrived, do not consume. */
MBEDTLS_SSL_DEBUG_MSG(3,
("waiting for more fragments (%u of %"
MBEDTLS_PRINTF_SIZET ", %" MBEDTLS_PRINTF_SIZET " left)",
ssl->badmac_seen_or_in_hsfraglen, ssl->in_hslen,
ssl->in_hslen - ssl->badmac_seen_or_in_hsfraglen));
return 0;
}

/*
* Get next Handshake message in the current record
*/
Expand All @@ -4665,6 +4737,7 @@ static int ssl_consume_current_message(mbedtls_ssl_context *ssl)
ssl->in_msglen -= ssl->in_hslen;
memmove(ssl->in_msg, ssl->in_msg + ssl->in_hslen,
ssl->in_msglen);
MBEDTLS_PUT_UINT16_BE(ssl->in_msglen, ssl->in_len, 0);

MBEDTLS_SSL_DEBUG_BUF(4, "remaining content in record",
ssl->in_msg, ssl->in_msglen);
Expand Down Expand Up @@ -4967,10 +5040,12 @@ static int ssl_get_next_record(mbedtls_ssl_context *ssl)
return ret;
}

if (ssl->conf->badmac_limit != 0 &&
++ssl->badmac_seen >= ssl->conf->badmac_limit) {
MBEDTLS_SSL_DEBUG_MSG(1, ("too many records with bad MAC"));
return MBEDTLS_ERR_SSL_INVALID_MAC;
if (ssl->conf->badmac_limit != 0) {
++ssl->badmac_seen_or_in_hsfraglen;
if (ssl->badmac_seen_or_in_hsfraglen >= ssl->conf->badmac_limit) {
MBEDTLS_SSL_DEBUG_MSG(1, ("too many records with bad MAC"));
return MBEDTLS_ERR_SSL_INVALID_MAC;
}
}

/* As above, invalid records cause
Expand Down Expand Up @@ -5345,7 +5420,7 @@ void mbedtls_ssl_update_in_pointers(mbedtls_ssl_context *ssl)
} else
#endif
{
ssl->in_ctr = ssl->in_hdr - MBEDTLS_SSL_SEQUENCE_NUMBER_LEN;
ssl->in_ctr = ssl->in_buf;
ssl->in_len = ssl->in_hdr + 3;
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
ssl->in_cid = ssl->in_len;
Expand All @@ -5361,24 +5436,35 @@ void mbedtls_ssl_update_in_pointers(mbedtls_ssl_context *ssl)
* Setup an SSL context
*/

void mbedtls_ssl_reset_in_out_pointers(mbedtls_ssl_context *ssl)
void mbedtls_ssl_reset_in_pointers(mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
ssl->in_hdr = ssl->in_buf;
} else
#endif /* MBEDTLS_SSL_PROTO_DTLS */
{
ssl->in_hdr = ssl->in_buf + MBEDTLS_SSL_SEQUENCE_NUMBER_LEN;
}

/* Derive other internal pointers. */
mbedtls_ssl_update_in_pointers(ssl);
}

void mbedtls_ssl_reset_out_pointers(mbedtls_ssl_context *ssl)
{
/* Set the incoming and outgoing record pointers. */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
ssl->out_hdr = ssl->out_buf;
ssl->in_hdr = ssl->in_buf;
} else
#endif /* MBEDTLS_SSL_PROTO_DTLS */
{
ssl->out_ctr = ssl->out_buf;
ssl->out_hdr = ssl->out_buf + 8;
ssl->in_hdr = ssl->in_buf + 8;
ssl->out_hdr = ssl->out_buf + MBEDTLS_SSL_SEQUENCE_NUMBER_LEN;
}

/* Derive other internal pointers. */
mbedtls_ssl_update_out_pointers(ssl, NULL /* no transform enabled */);
mbedtls_ssl_update_in_pointers(ssl);
}

/*
Expand Down
Loading