diff --git a/ChangeLog.d/tls12-check-finished-calc.txt b/ChangeLog.d/tls12-check-finished-calc.txt new file mode 100644 index 0000000000..cd52d32ffd --- /dev/null +++ b/ChangeLog.d/tls12-check-finished-calc.txt @@ -0,0 +1,6 @@ +Security + * Fix a vulnerability in the TLS 1.2 handshake. If memory allocation failed + or there was a cryptographic hardware failure when calculating the + Finished message, it could be calculated incorrectly. This would break + the security guarantees of the TLS handshake. + CVE-2025-27810 diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index e3873690f7..17bb631b59 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -467,7 +467,8 @@ struct mbedtls_ssl_handshake_params { void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t); void (*calc_verify)(const mbedtls_ssl_context *, unsigned char *, size_t *); - void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int); + MBEDTLS_CHECK_RETURN_CRITICAL + int (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int); mbedtls_ssl_tls_prf_cb *tls_prf; #if defined(MBEDTLS_DHM_C) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 65d5b964d3..73f9c7f471 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -624,6 +624,23 @@ exit: } #endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) +static int mbedtls_ssl_md_error_from_psa(psa_status_t status) +{ + switch (status) { + case PSA_ERROR_NOT_SUPPORTED: + return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE; + case PSA_ERROR_BAD_STATE: /* Intentional fallthrough */ + case PSA_ERROR_BUFFER_TOO_SMALL: + return MBEDTLS_ERR_MD_BAD_INPUT_DATA; + case PSA_ERROR_INSUFFICIENT_MEMORY: + return MBEDTLS_ERR_MD_ALLOC_FAILED; + default: + return MBEDTLS_ERR_MD_HW_ACCEL_FAILED; + } +} +#endif + #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -892,25 +909,25 @@ static void ssl_update_checksum_md5sha1(mbedtls_ssl_context *, const unsigned ch #if defined(MBEDTLS_SSL_PROTO_SSL3) static void ssl_calc_verify_ssl(const mbedtls_ssl_context *, unsigned char *, size_t *); -static void ssl_calc_finished_ssl(mbedtls_ssl_context *, unsigned char *, int); +static int ssl_calc_finished_ssl(mbedtls_ssl_context *, unsigned char *, int); #endif #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) static void ssl_calc_verify_tls(const mbedtls_ssl_context *, unsigned char *, size_t *); -static void ssl_calc_finished_tls(mbedtls_ssl_context *, unsigned char *, int); +static int ssl_calc_finished_tls(mbedtls_ssl_context *, unsigned char *, int); #endif #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SHA256_C) static void ssl_update_checksum_sha256(mbedtls_ssl_context *, const unsigned char *, size_t); static void ssl_calc_verify_tls_sha256(const mbedtls_ssl_context *, unsigned char *, size_t *); -static void ssl_calc_finished_tls_sha256(mbedtls_ssl_context *, unsigned char *, int); +static int ssl_calc_finished_tls_sha256(mbedtls_ssl_context *, unsigned char *, int); #endif #if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384) static void ssl_update_checksum_sha384(mbedtls_ssl_context *, const unsigned char *, size_t); static void ssl_calc_verify_tls_sha384(const mbedtls_ssl_context *, unsigned char *, size_t *); -static void ssl_calc_finished_tls_sha384(mbedtls_ssl_context *, unsigned char *, int); +static int ssl_calc_finished_tls_sha384(mbedtls_ssl_context *, unsigned char *, int); #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ @@ -3136,7 +3153,7 @@ static void ssl_update_checksum_sha384(mbedtls_ssl_context *ssl, #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined(MBEDTLS_SSL_PROTO_SSL3) -static void ssl_calc_finished_ssl( +static int ssl_calc_finished_ssl( mbedtls_ssl_context *ssl, unsigned char *buf, int from) { const char *sender; @@ -3218,11 +3235,13 @@ static void ssl_calc_finished_ssl( mbedtls_platform_zeroize(sha1sum, sizeof(sha1sum)); MBEDTLS_SSL_DEBUG_MSG(2, ("<= calc finished")); + + return 0; } #endif /* MBEDTLS_SSL_PROTO_SSL3 */ #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) -static void ssl_calc_finished_tls( +static int ssl_calc_finished_tls( mbedtls_ssl_context *ssl, unsigned char *buf, int from) { int len = 12; @@ -3278,12 +3297,14 @@ static void ssl_calc_finished_tls( mbedtls_platform_zeroize(padbuf, sizeof(padbuf)); MBEDTLS_SSL_DEBUG_MSG(2, ("<= calc finished")); + + return 0; } #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SHA256_C) -static void ssl_calc_finished_tls_sha256( +static int ssl_calc_finished_tls_sha256( mbedtls_ssl_context *ssl, unsigned char *buf, int from) { int len = 12; @@ -3314,13 +3335,13 @@ static void ssl_calc_finished_tls_sha256( status = psa_hash_clone(&ssl->handshake->fin_sha256_psa, &sha256_psa); if (status != PSA_SUCCESS) { MBEDTLS_SSL_DEBUG_MSG(2, ("PSA hash clone failed")); - return; + return mbedtls_ssl_md_error_from_psa(status); } status = psa_hash_finish(&sha256_psa, padbuf, sizeof(padbuf), &hash_size); if (status != PSA_SUCCESS) { MBEDTLS_SSL_DEBUG_MSG(2, ("PSA hash finish failed")); - return; + return mbedtls_ssl_md_error_from_psa(status); } MBEDTLS_SSL_DEBUG_BUF(3, "PSA calculated padbuf", padbuf, 32); #else @@ -3354,12 +3375,14 @@ static void ssl_calc_finished_tls_sha256( mbedtls_platform_zeroize(padbuf, sizeof(padbuf)); MBEDTLS_SSL_DEBUG_MSG(2, ("<= calc finished")); + + return 0; } #endif /* MBEDTLS_SHA256_C */ #if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384) -static void ssl_calc_finished_tls_sha384( +static int ssl_calc_finished_tls_sha384( mbedtls_ssl_context *ssl, unsigned char *buf, int from) { int len = 12; @@ -3390,13 +3413,13 @@ static void ssl_calc_finished_tls_sha384( status = psa_hash_clone(&ssl->handshake->fin_sha384_psa, &sha384_psa); if (status != PSA_SUCCESS) { MBEDTLS_SSL_DEBUG_MSG(2, ("PSA hash clone failed")); - return; + return mbedtls_ssl_md_error_from_psa(status); } status = psa_hash_finish(&sha384_psa, padbuf, sizeof(padbuf), &hash_size); if (status != PSA_SUCCESS) { MBEDTLS_SSL_DEBUG_MSG(2, ("PSA hash finish failed")); - return; + return mbedtls_ssl_md_error_from_psa(status); } MBEDTLS_SSL_DEBUG_BUF(3, "PSA calculated padbuf", padbuf, 48); #else @@ -3441,6 +3464,8 @@ static void ssl_calc_finished_tls_sha384( mbedtls_platform_zeroize(padbuf, sizeof(padbuf)); MBEDTLS_SSL_DEBUG_MSG(2, ("<= calc finished")); + + return 0; } #endif /* MBEDTLS_SHA512_C && !MBEDTLS_SHA512_NO_SHA384 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ @@ -3535,7 +3560,12 @@ int mbedtls_ssl_write_finished(mbedtls_ssl_context *ssl) mbedtls_ssl_update_out_pointers(ssl, ssl->transform_negotiate); - ssl->handshake->calc_finished(ssl, ssl->out_msg + 4, ssl->conf->endpoint); + ret = ssl->handshake->calc_finished(ssl, ssl->out_msg + 4, + ssl->conf->endpoint); + if (ret != 0) { + MBEDTLS_SSL_DEBUG_RET(1, "calc_finished", ret); + return ret; + } /* * RFC 5246 7.4.9 (Page 63) says 12 is the default length and ciphersuites @@ -3664,7 +3694,11 @@ int mbedtls_ssl_parse_finished(mbedtls_ssl_context *ssl) #endif hash_len = 12; - ssl->handshake->calc_finished(ssl, buf, ssl->conf->endpoint ^ 1); + ret = ssl->handshake->calc_finished(ssl, buf, ssl->conf->endpoint ^ 1); + if (ret != 0) { + MBEDTLS_SSL_DEBUG_RET(1, "calc_finished", ret); + goto exit; + } if ((ret = mbedtls_ssl_read_record(ssl, 1)) != 0) { MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_read_record", ret); @@ -7626,17 +7660,8 @@ exit: if (status != PSA_SUCCESS) { mbedtls_ssl_send_alert_message(ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR); - switch (status) { - case PSA_ERROR_NOT_SUPPORTED: - return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE; - case PSA_ERROR_BAD_STATE: /* Intentional fallthrough */ - case PSA_ERROR_BUFFER_TOO_SMALL: - return MBEDTLS_ERR_MD_BAD_INPUT_DATA; - case PSA_ERROR_INSUFFICIENT_MEMORY: - return MBEDTLS_ERR_MD_ALLOC_FAILED; - default: - return MBEDTLS_ERR_MD_HW_ACCEL_FAILED; - } + + return mbedtls_ssl_md_error_from_psa(status); } return 0; }