From cf6d40a92de43a402be22514c479793ba5326ee3 Mon Sep 17 00:00:00 2001 From: Paulo Santos Date: Wed, 20 May 2026 14:39:00 -0300 Subject: [PATCH] ssl: size _pms_ecdh against PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE In PSA-client-only builds (MBEDTLS_PSA_CRYPTO_C disabled, e.g. NS-side mbedtls dispatching to a secure PSA service like TF-M), the local ECP_LIGHT cascade does not run and MBEDTLS_ECP_MAX_BYTES collapses to 1. The `_pms_ecdh` and `_pms_ecdhe_psk` members of `union mbedtls_ssl_premaster_secret` then declare 1-byte arrays. In builds where only ECDHE-RSA / ECDHE-ECDSA is enabled (no PSK, no ECJPAKE), the whole union ends up that small, and psa_raw_key_agreement() returns PSA_ERROR_BUFFER_TOO_SMALL during the TLS 1.2 ECDHE handshake. The handshake aborts as MBEDTLS_ERR_SSL_HW_ACCEL_FAILED with no path to success in this configuration. Introduce MBEDTLS_SSL_PMS_ECDH_SIZE as max(PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE, MBEDTLS_ECP_MAX_BYTES) so both legacy ECP and PSA-client builds get a sufficient buffer. PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE is always defined, sized by the enabled PSA_WANT_ECC_* curves. Signed-off-by: Paulo Santos --- ChangeLog.d/fix-pms-ecdh-psa-client-size.txt | 8 ++++++++ include/mbedtls/ssl.h | 18 ++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 ChangeLog.d/fix-pms-ecdh-psa-client-size.txt diff --git a/ChangeLog.d/fix-pms-ecdh-psa-client-size.txt b/ChangeLog.d/fix-pms-ecdh-psa-client-size.txt new file mode 100644 index 0000000000..3047a56e10 --- /dev/null +++ b/ChangeLog.d/fix-pms-ecdh-psa-client-size.txt @@ -0,0 +1,8 @@ +Bugfix + * Fix TLS 1.2 ECDHE handshakes failing in PSA-client-only + builds (MBEDTLS_PSA_CRYPTO_C disabled) where + MBEDTLS_ECP_MAX_BYTES collapses to 1 and the + premaster-secret union sized below + PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE caused + psa_raw_key_agreement() to return PSA_ERROR_BUFFER_TOO_SMALL. + Fixes #10757. diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 3a69df5466..baedf3464c 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -648,18 +648,32 @@ #endif #endif /* !MBEDTLS_PSK_MAX_LEN */ +/** + * In PSA-client-only builds (MBEDTLS_PSA_CRYPTO_C off, e.g. NS-side + * mbedtls dispatching to a secure PSA service like TF-M) the local + * ECP_LIGHT cascade does not run and MBEDTLS_ECP_MAX_BYTES collapses + * to 1. Take the larger of that and PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE, + * which is sized by the enabled PSA_WANT_ECC_* curves and is always + * defined, so psa_raw_key_agreement() has a real output buffer to + * write the ECDH shared secret into. + */ +#define MBEDTLS_SSL_PMS_ECDH_SIZE \ + (PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE > MBEDTLS_ECP_MAX_BYTES \ + ? PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE \ + : MBEDTLS_ECP_MAX_BYTES) + /* Dummy type used only for its size */ union mbedtls_ssl_premaster_secret { unsigned char dummy; /* Make the union non-empty even with SSL disabled */ #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) - unsigned char _pms_ecdh[MBEDTLS_ECP_MAX_BYTES]; /* RFC 4492 5.10 */ + unsigned char _pms_ecdh[MBEDTLS_SSL_PMS_ECDH_SIZE]; /* RFC 4492 5.10 */ #endif #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) unsigned char _pms_psk[4 + 2 * MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 2 */ #endif #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) - unsigned char _pms_ecdhe_psk[4 + MBEDTLS_ECP_MAX_BYTES + unsigned char _pms_ecdhe_psk[4 + MBEDTLS_SSL_PMS_ECDH_SIZE + MBEDTLS_PSK_MAX_LEN]; /* RFC 5489 2 */ #endif #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)