Merge pull request #1599 from bjwtaylor/ssl-ignores-failure-restricted

Fix issues in ssl where it ignores the failure return
This commit is contained in:
Ronald Cron 2026-06-24 15:02:34 +02:00 committed by GitHub
commit f74ef9b3ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 198 additions and 21 deletions

View File

@ -0,0 +1,17 @@
Security
* Fix a bug where transcript-hash computation errors during TLS 1.2
extended master secret calculation could be ignored instead of causing the
handshake to fail. This could allow a handshake to continue with a master
secret that was not correctly bound to the handshake transcript,
undermining the security guarantees of the extended master secret
extension. Report by Mathew Gretton-Dann. CVE-2026-50581
* Fix a TLS 1.3 server-side error-handling bug affecting session ticket
generation. Under rare conditions, such as memory allocation failures
while computing the resumption master secret, the server could issue
invalid session tickets instead of failing the handshake. Clients
presented with such tickets would fail session resumption and fall back to
a full handshake. In deployments relying on session resumption, repeated
occurrences could increase the frequency of full handshakes and amplify
resource consumption during periods of resource exhaustion or other
transient failures. Reported by jjfz123.
CVE-2026-50640

View File

@ -29,7 +29,6 @@
#include <string.h>
#include "mbedtls/psa_util.h"
#include "md_psa.h" // for mbedtls_md_error_from_psa()
#include "psa/crypto.h"
#if defined(MBEDTLS_X509_CRT_PARSE_C)
@ -846,21 +845,21 @@ int mbedtls_ssl_reset_checksum(mbedtls_ssl_context *ssl)
#if defined(PSA_WANT_ALG_SHA_256)
status = psa_hash_abort(&ssl->handshake->fin_sha256_psa);
if (status != PSA_SUCCESS) {
return mbedtls_md_error_from_psa(status);
return PSA_TO_MBEDTLS_ERR(status);
}
status = psa_hash_setup(&ssl->handshake->fin_sha256_psa, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
return mbedtls_md_error_from_psa(status);
return PSA_TO_MBEDTLS_ERR(status);
}
#endif
#if defined(PSA_WANT_ALG_SHA_384)
status = psa_hash_abort(&ssl->handshake->fin_sha384_psa);
if (status != PSA_SUCCESS) {
return mbedtls_md_error_from_psa(status);
return PSA_TO_MBEDTLS_ERR(status);
}
status = psa_hash_setup(&ssl->handshake->fin_sha384_psa, PSA_ALG_SHA_384);
if (status != PSA_SUCCESS) {
return mbedtls_md_error_from_psa(status);
return PSA_TO_MBEDTLS_ERR(status);
}
#endif
return 0;
@ -880,13 +879,13 @@ static int ssl_update_checksum_start(mbedtls_ssl_context *ssl,
#if defined(PSA_WANT_ALG_SHA_256)
status = psa_hash_update(&ssl->handshake->fin_sha256_psa, buf, len);
if (status != PSA_SUCCESS) {
return mbedtls_md_error_from_psa(status);
return PSA_TO_MBEDTLS_ERR(status);
}
#endif
#if defined(PSA_WANT_ALG_SHA_384)
status = psa_hash_update(&ssl->handshake->fin_sha384_psa, buf, len);
if (status != PSA_SUCCESS) {
return mbedtls_md_error_from_psa(status);
return PSA_TO_MBEDTLS_ERR(status);
}
#endif
return 0;
@ -896,7 +895,7 @@ static int ssl_update_checksum_start(mbedtls_ssl_context *ssl,
static int ssl_update_checksum_sha256(mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len)
{
return mbedtls_md_error_from_psa(psa_hash_update(
return PSA_TO_MBEDTLS_ERR(psa_hash_update(
&ssl->handshake->fin_sha256_psa, buf, len));
}
#endif
@ -905,7 +904,7 @@ static int ssl_update_checksum_sha256(mbedtls_ssl_context *ssl,
static int ssl_update_checksum_sha384(mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len)
{
return mbedtls_md_error_from_psa(psa_hash_update(
return PSA_TO_MBEDTLS_ERR(psa_hash_update(
&ssl->handshake->fin_sha384_psa, buf, len));
}
#endif
@ -6293,11 +6292,16 @@ static int ssl_compute_master(mbedtls_ssl_handshake_params *handshake,
#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
if (handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED) {
lbl = "extended master secret";
seed = session_hash;
ret = handshake->calc_verify(ssl, session_hash, &seed_len);
if (ret != 0) {
MBEDTLS_SSL_DEBUG_RET(1, "calc_verify", ret);
return ret;
}
if (seed_len > sizeof(session_hash)) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad session hash length"));
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
seed = session_hash;
MBEDTLS_SSL_DEBUG_BUF(3, "session hash for extended master secret",
session_hash, seed_len);
@ -6564,7 +6568,7 @@ static int ssl_calc_verify_tls_psa(const mbedtls_ssl_context *ssl,
exit:
psa_hash_abort(&cloned_op);
return mbedtls_md_error_from_psa(status);
return PSA_TO_MBEDTLS_ERR(status);
}
#if defined(PSA_WANT_ALG_SHA_256)
@ -7257,7 +7261,7 @@ static int ssl_calc_finished_tls_generic(mbedtls_ssl_context *ssl, void *ctx,
exit:
psa_hash_abort(&cloned_op);
return mbedtls_md_error_from_psa(status);
return PSA_TO_MBEDTLS_ERR(status);
}
#if defined(PSA_WANT_ALG_SHA_256)

View File

@ -1746,7 +1746,7 @@ static void ssl_write_supported_point_formats_ext(mbedtls_ssl_context *ssl,
MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
static void ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl,
static int ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl,
unsigned char *buf,
size_t *olen)
{
@ -1760,14 +1760,14 @@ static void ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl,
/* Skip costly computation if not needed */
if (ssl->handshake->ciphersuite_info->key_exchange !=
MBEDTLS_KEY_EXCHANGE_ECJPAKE) {
return;
return 0;
}
MBEDTLS_SSL_DEBUG_MSG(3, ("server hello, ecjpake kkpp extension"));
if (end - p < 4) {
MBEDTLS_SSL_DEBUG_MSG(1, ("buffer too small"));
return;
return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
}
MBEDTLS_PUT_UINT16_BE(MBEDTLS_TLS_EXT_ECJPAKE_KKPP, p, 0);
@ -1780,13 +1780,14 @@ static void ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl,
psa_destroy_key(ssl->handshake->psa_pake_password);
psa_pake_abort(&ssl->handshake->psa_pake_ctx);
MBEDTLS_SSL_DEBUG_RET(1, "psa_pake_output", ret);
return;
return ret;
}
MBEDTLS_PUT_UINT16_BE(kkpp_len, p, 0);
p += 2;
*olen = kkpp_len + 4;
return 0;
}
#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
@ -2169,7 +2170,11 @@ static int ssl_write_server_hello(mbedtls_ssl_context *ssl)
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
ssl_write_ecjpake_kkpp_ext(ssl, p + 2 + ext_len, &olen);
ret = ssl_write_ecjpake_kkpp_ext(ssl, p + 2 + ext_len, &olen);
if (ret != 0) {
MBEDTLS_SSL_DEBUG_RET(1, "ssl_write_ecjpake_kkpp_ext", ret);
return ret;
}
ext_len += olen;
#endif

View File

@ -2804,6 +2804,7 @@ static int ssl_tls13_parse_new_session_ticket_exts(mbedtls_ssl_context *ssl,
MBEDTLS_SSL_DEBUG_RET(
1, "ssl_tls13_parse_new_session_ticket_early_data_ext",
ret);
return ret;
}
break;
#endif /* MBEDTLS_SSL_EARLY_DATA */

View File

@ -3077,6 +3077,7 @@ static int ssl_tls13_process_client_finished(mbedtls_ssl_context *ssl)
if (ret != 0) {
MBEDTLS_SSL_DEBUG_RET(
1, "mbedtls_ssl_tls13_compute_resumption_master_secret", ret);
return ret;
}
mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_HANDSHAKE_WRAPUP);

View File

@ -3378,6 +3378,22 @@ elliptic_curve_get_properties
TLS 1.3 resume session with ticket
tls13_resume_session_with_ticket
TLS 1.3 server propagates RMS computation error
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS:MBEDTLS_ERR_SSL_INTERNAL_ERROR
TLS 1.3 client propagates RMS computation error
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:"<= write finished message":MBEDTLS_SSL_CLIENT_FINISHED:-1:MBEDTLS_ERR_SSL_INTERNAL_ERROR
TLS 1.2 server propagates EMS computation error
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY:MBEDTLS_ERR_SSL_INTERNAL_ERROR
TLS 1.2 client propagates EMS computation error
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CERTIFICATE_VERIFY:-1:MBEDTLS_ERR_SSL_INTERNAL_ERROR
TLS 1.3 read early data, early data accepted
tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED

View File

@ -55,6 +55,53 @@ static int failing_ticket_write_unset_lifetime(
PSA_WANT_ALG_SHA_256 && PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY &&
MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */
#if defined(MBEDTLS_SSL_TLS_C) && defined(MBEDTLS_DEBUG_C) && \
defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SRV_C) && \
defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) && \
defined(MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP) && \
defined(PSA_WANT_ALG_SHA_256)
typedef struct {
/* Context for tls_abort_transcript(). The debug callback watches for
* trigger in the SSL debug trace, then aborts this connection's transcript
* hash operation exactly once so the test can check error propagation. */
mbedtls_ssl_context *ssl;
const char *trigger;
int triggered;
} tls_abort_transcript_context;
static void tls_abort_transcript(void *ctx, int level,
const char *file, int line,
const char *str)
{
tls_abort_transcript_context *abort_ctx = ctx;
(void) level;
(void) file;
(void) line;
if (abort_ctx->triggered) {
return;
}
if (abort_ctx->ssl == NULL) {
return;
}
if (abort_ctx->ssl->handshake == NULL) {
return;
}
if (strstr(str, abort_ctx->trigger) == NULL) {
return;
}
abort_ctx->triggered = 1;
#if defined(PSA_WANT_ALG_SHA_256)
psa_hash_abort(&abort_ctx->ssl->handshake->fin_sha256_psa);
#endif
#if defined(PSA_WANT_ALG_SHA_384)
psa_hash_abort(&abort_ctx->ssl->handshake->fin_sha384_psa);
#endif
}
#endif
#if (!defined(MBEDTLS_SSL_PROTO_TLS1_2)) && \
defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) && \
defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_DEBUG_C) && \
@ -4358,6 +4405,92 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C:MBEDTLS_DEBUG_C:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP:PSA_WANT_ALG_SHA_256 */
void tls_transcript_error_propagation(int endpoint,
int tls_version,
const char *trigger,
int target_state,
int peer_target_state,
int expected_ret)
{
int ret = -1;
mbedtls_test_ssl_endpoint client_ep, server_ep;
mbedtls_test_handshake_test_options client_options;
mbedtls_test_init_handshake_options(&client_options);
mbedtls_test_handshake_test_options server_options;
mbedtls_test_init_handshake_options(&server_options);
tls_abort_transcript_context abort_ctx;
memset(&abort_ctx, 0, sizeof(abort_ctx));
mbedtls_ssl_context *peer_ssl_context = NULL;
PSA_INIT();
client_options.client_min_version = tls_version;
client_options.client_max_version = tls_version;
server_options.server_min_version = tls_version;
server_options.server_max_version = tls_version;
abort_ctx.trigger = trigger;
TEST_ASSERT(abort_ctx.trigger != NULL);
if (endpoint == MBEDTLS_SSL_IS_CLIENT) {
client_options.cli_log_obj = &abort_ctx;
client_options.cli_log_fun = tls_abort_transcript;
abort_ctx.ssl = &client_ep.ssl;
peer_ssl_context = &server_ep.ssl;
} else {
server_options.srv_log_obj = &abort_ctx;
server_options.srv_log_fun = tls_abort_transcript;
abort_ctx.ssl = &server_ep.ssl;
peer_ssl_context = &client_ep.ssl;
}
mbedtls_debug_set_threshold(4);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
&client_options), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
&server_options), 0);
/* Keep enough socket capacity for setup traffic so the final step below
* exercises the target state instead of only flushing previous messages. */
TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket),
&(server_ep.socket), 4096), 0);
TEST_EQUAL(mbedtls_test_move_handshake_to_state(
abort_ctx.ssl, peer_ssl_context,
target_state), 0);
/*
* Advance the peer further through the handshake so that it emits the
* messages needed by the endpoint under test to proceed through its next
* step.
*/
if (peer_target_state != -1) {
TEST_EQUAL(mbedtls_test_move_handshake_to_state(
peer_ssl_context, abort_ctx.ssl,
peer_target_state), 0);
TEST_EQUAL(mbedtls_ssl_flush_output(peer_ssl_context), 0);
}
TEST_EQUAL(mbedtls_ssl_flush_output(abort_ctx.ssl), 0);
TEST_EQUAL(abort_ctx.ssl->state, target_state);
TEST_EQUAL(abort_ctx.triggered, 0);
ret = mbedtls_ssl_handshake_step(abort_ctx.ssl);
TEST_ASSERT(abort_ctx.triggered);
TEST_ASSERT(ret != 0);
TEST_EQUAL(ret, expected_ret);
exit:
mbedtls_test_ssl_endpoint_free(&client_ep);
mbedtls_test_ssl_endpoint_free(&server_ep);
mbedtls_test_free_handshake_options(&client_options);
mbedtls_test_free_handshake_options(&server_options);
mbedtls_debug_set_threshold(0);
PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384:PSA_HAVE_ALG_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */
void tls13_resume_session_with_ticket()
{