From 4d14271515d1c76e5ec70792ce0e53b90653cb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Feb 2026 10:03:57 +0100 Subject: [PATCH 01/24] PK: avoid large stack buffer in to/from PSA functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit But still retain the ability to function without a heap when only ECC is enabled. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 64 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/library/pk.c b/library/pk.c index 51f0c24088..61d333c8f6 100644 --- a/library/pk.c +++ b/library/pk.c @@ -35,6 +35,15 @@ #include #include +#if defined(MBEDTLS_RSA_C) +#define PK_HAVE_KEYS_LARGER_THAN_ECC +#endif + +#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#include "mbedtls/platform.h" // for calloc/free +#endif + + /* * Initialise a mbedtls_pk_context */ @@ -589,16 +598,36 @@ static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, const psa_key_attributes_t *attributes, mbedtls_svc_key_id_t *new_key_id) { - unsigned char key_buffer[PSA_EXPORT_KEY_PAIR_MAX_SIZE]; +#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) + unsigned char *key_buffer = NULL; + size_t key_buffer_size = 0; +#else + unsigned char key_buffer[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH]; + const size_t key_buffer_size = sizeof(key_buffer); +#endif size_t key_length = 0; + +#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) + key_buffer_size = PSA_EXPORT_KEY_PAIR_MAX_SIZE; + key_buffer = mbedtls_calloc(1, key_buffer_size); + if (key_buffer == NULL) { + return MBEDTLS_ERR_PK_ALLOC_FAILED; + } +#endif + psa_status_t status = psa_export_key(old_key_id, - key_buffer, sizeof(key_buffer), + key_buffer, key_buffer_size, &key_length); if (status != PSA_SUCCESS) { - return status; + goto cleanup; } status = psa_import_key(attributes, key_buffer, key_length, new_key_id); mbedtls_platform_zeroize(key_buffer, key_length); + +cleanup: +#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) + mbedtls_free(key_buffer); +#endif return status; } @@ -865,8 +894,13 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; psa_key_type_t key_type; size_t key_bits; - /* Use a buffer size large enough to contain either a key pair or public key. */ - unsigned char exp_key[PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE]; +#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) + unsigned char *exp_key = NULL; + size_t exp_key_size = 0; +#else + unsigned char exp_key[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH]; + const size_t exp_key_size = sizeof(exp_key); +#endif size_t exp_key_len; int ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; @@ -879,10 +913,18 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, return MBEDTLS_ERR_PK_BAD_INPUT_DATA; } +#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) + exp_key_size = PSA_EXPORT_KEY_PAIR_MAX_SIZE; + exp_key = mbedtls_calloc(1, exp_key_size); + if (exp_key == NULL) { + return MBEDTLS_ERR_PK_ALLOC_FAILED; + } +#endif + if (public_only) { - status = psa_export_public_key(key_id, exp_key, sizeof(exp_key), &exp_key_len); + status = psa_export_public_key(key_id, exp_key, exp_key_size, &exp_key_len); } else { - status = psa_export_key(key_id, exp_key, sizeof(exp_key), &exp_key_len); + status = psa_export_key(key_id, exp_key, exp_key_size, &exp_key_len); } if (status != PSA_SUCCESS) { ret = PSA_PK_TO_MBEDTLS_ERR(status); @@ -964,12 +1006,16 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ { (void) key_bits; - return MBEDTLS_ERR_PK_BAD_INPUT_DATA; + ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; + goto exit; } exit: + mbedtls_platform_zeroize(exp_key, exp_key_size); +#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) + mbedtls_free(exp_key); +#endif psa_reset_key_attributes(&key_attr); - mbedtls_platform_zeroize(exp_key, sizeof(exp_key)); return ret; } From eb8289d072b075e022a059e3dc02ec2839170f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Feb 2026 10:26:45 +0100 Subject: [PATCH 02/24] PK: adjust heap buffer size for key type+bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/library/pk.c b/library/pk.c index 61d333c8f6..f4d1123657 100644 --- a/library/pk.c +++ b/library/pk.c @@ -593,8 +593,39 @@ int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk, return 0; } +#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) +#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +static size_t pk_export_max_size(psa_key_type_t key_type, size_t bits) +{ +#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) + if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type)) { + return PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(bits); + } +#endif +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) + if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type)) { + return PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(bits); + } +#endif +#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) + if (key_type == PSA_KEY_TYPE_RSA_PUBLIC_KEY) { + return PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(bits); + } +#endif +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) + if (key_type == PSA_KEY_TYPE_RSA_KEY_PAIR) { + return PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(bits); + } +#endif + /* failsafe */ + return PSA_EXPORT_KEY_PAIR_MAX_SIZE; +} +#endif /* PK_HAVE_KEYS_LARGER_THAN_ECC */ +#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ + #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) || defined(MBEDTLS_USE_PSA_CRYPTO) static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, + psa_key_type_t old_type, size_t old_bits, const psa_key_attributes_t *attributes, mbedtls_svc_key_id_t *new_key_id) { @@ -608,11 +639,14 @@ static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, size_t key_length = 0; #if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) - key_buffer_size = PSA_EXPORT_KEY_PAIR_MAX_SIZE; + key_buffer_size = pk_export_max_size(old_type, old_bits); key_buffer = mbedtls_calloc(1, key_buffer_size); if (key_buffer == NULL) { return MBEDTLS_ERR_PK_ALLOC_FAILED; } +#else + (void) old_type; + (void) old_bits; #endif psa_status_t status = psa_export_key(old_key_id, @@ -657,11 +691,13 @@ static int copy_into_psa(mbedtls_svc_key_id_t old_key_id, return MBEDTLS_ERR_PK_BAD_INPUT_DATA; } psa_key_type_t old_type = psa_get_key_type(&old_attributes); + size_t old_bits = psa_get_key_bits(&old_attributes); psa_reset_key_attributes(&old_attributes); if (old_type != psa_get_key_type(attributes)) { return MBEDTLS_ERR_PK_TYPE_MISMATCH; } - status = export_import_into_psa(old_key_id, attributes, new_key_id); + status = export_import_into_psa(old_key_id, old_type, old_bits, + attributes, new_key_id); } return PSA_PK_TO_MBEDTLS_ERR(status); } @@ -913,8 +949,14 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, return MBEDTLS_ERR_PK_BAD_INPUT_DATA; } + key_type = psa_get_key_type(&key_attr); + if (public_only) { + key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(key_type); + } + key_bits = psa_get_key_bits(&key_attr); + #if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) - exp_key_size = PSA_EXPORT_KEY_PAIR_MAX_SIZE; + exp_key_size = pk_export_max_size(key_type, key_bits); exp_key = mbedtls_calloc(1, exp_key_size); if (exp_key == NULL) { return MBEDTLS_ERR_PK_ALLOC_FAILED; From 210c61336182ce3e48ca0050123fd7611e353039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 11 Feb 2026 13:00:06 +0100 Subject: [PATCH 03/24] PK: fix stack buffer size for ECC keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes 2 out of the 3 tests cases that were failing in test_suite_pk. The last failure will be adressed in the next commit. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/pk.c b/library/pk.c index f4d1123657..e33a497b17 100644 --- a/library/pk.c +++ b/library/pk.c @@ -43,6 +43,12 @@ #include "mbedtls/platform.h" // for calloc/free #endif +/* We know for ECC, pubkey are longer than privkeys, but double check */ +#define PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#if MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH > PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH +#undef PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH +#define PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH +#endif /* * Initialise a mbedtls_pk_context @@ -633,7 +639,7 @@ static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, unsigned char *key_buffer = NULL; size_t key_buffer_size = 0; #else - unsigned char key_buffer[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH]; + unsigned char key_buffer[PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH]; const size_t key_buffer_size = sizeof(key_buffer); #endif size_t key_length = 0; @@ -934,7 +940,7 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, unsigned char *exp_key = NULL; size_t exp_key_size = 0; #else - unsigned char exp_key[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH]; + unsigned char exp_key[PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH]; const size_t exp_key_size = sizeof(exp_key); #endif size_t exp_key_len; From 00fd34ef18049deaa5f6befc942ad51aaa87cd98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 12 Feb 2026 10:07:57 +0100 Subject: [PATCH 04/24] PK: return helpful error on API misuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes test_suite_pk pass again, but beyond that I think it's the right thing to do. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/pk.c b/library/pk.c index e33a497b17..c580c44a1b 100644 --- a/library/pk.c +++ b/library/pk.c @@ -967,6 +967,13 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, if (exp_key == NULL) { return MBEDTLS_ERR_PK_ALLOC_FAILED; } +#else + /* In case we're passed non-ECC key (API misuse), return a sensible error + * now. Otherwise we might get BUFFER_TOO_SMALL when exporting below, which + * is unlikely to be helpful to the user as the buffer is internal. */ + if (!PSA_KEY_TYPE_IS_ECC(key_type)) { + return MBEDTLS_ERR_PK_BAD_INPUT_DATA; + } #endif if (public_only) { From 1cc0e98f683f9496c76e5d2d5e2dc6941b2edbb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 12 Feb 2026 11:04:00 +0100 Subject: [PATCH 05/24] PSA: add and use PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- include/psa/crypto_extra.h | 4 ++-- include/psa/crypto_sizes.h | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 89a38a8054..9324b48895 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -39,9 +39,9 @@ extern "C" { #define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE 1 -#if PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE > MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE +#if PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE > MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE #undef MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE -#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE +#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE #endif /* This covers ciphers, AEADs and CMAC. */ diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index 87b8c39fa6..69fc7d79f2 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -1038,10 +1038,16 @@ PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) #endif -#define PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE \ +/* This is the name that was standardized in PSA Crypto v1.3 */ +#define PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE \ ((PSA_EXPORT_KEY_PAIR_MAX_SIZE > PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) ? \ PSA_EXPORT_KEY_PAIR_MAX_SIZE : PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) +/* This is our old custom name from before it was in the spec, + * keep it around in case users were relying on it. */ +#define PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE \ + PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE + /** Sufficient output buffer size for psa_raw_key_agreement(). * * This macro returns a compile-time constant if its arguments are From 70454dc75b3670b512d48dcd95904581ab06c10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 12 Feb 2026 11:45:49 +0100 Subject: [PATCH 06/24] PK: rework failure case of internal size function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/library/pk.c b/library/pk.c index c580c44a1b..5047fa3b30 100644 --- a/library/pk.c +++ b/library/pk.c @@ -601,6 +601,15 @@ int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk, #if defined(MBEDTLS_PSA_CRYPTO_CLIENT) #if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +/* + * Size needed to export a key of a type supported by PK. + * + * Compared to PSA_EXPORT_KEY_OUTPUT_SIZE() this is better for code size: + * - using a macro in multiple places results in multiple copies of the code; + * - this function only handles key types supported in PK. + * + * Return 0 on unexpected types. Callers need to check for that value. + */ static size_t pk_export_max_size(psa_key_type_t key_type, size_t bits) { #if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) @@ -623,8 +632,7 @@ static size_t pk_export_max_size(psa_key_type_t key_type, size_t bits) return PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(bits); } #endif - /* failsafe */ - return PSA_EXPORT_KEY_PAIR_MAX_SIZE; + return 0; } #endif /* PK_HAVE_KEYS_LARGER_THAN_ECC */ #endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ @@ -644,6 +652,7 @@ static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, #endif size_t key_length = 0; + /* We are exporting from a PK object, so we know key type is valid for PK */ #if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) key_buffer_size = pk_export_max_size(old_type, old_bits); key_buffer = mbedtls_calloc(1, key_buffer_size); @@ -963,6 +972,9 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, #if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) exp_key_size = pk_export_max_size(key_type, key_bits); + if (exp_key_size == 0) { + return MBEDTLS_ERR_PK_BAD_INPUT_DATA; + } exp_key = mbedtls_calloc(1, exp_key_size); if (exp_key == NULL) { return MBEDTLS_ERR_PK_ALLOC_FAILED; From 925341971dba653a811055af163cb9e75d5b0f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 12 Feb 2026 11:52:19 +0100 Subject: [PATCH 07/24] PK: validate type upfront when copying from PSA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The type was validated near the end of the function when importing, but if makes more sense to validate upfront before we possibly allocate a buffer, export the key to it etc. This also guarantees a sensible error value without requiring a special case when exporting on the stack. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/library/pk.c b/library/pk.c index 5047fa3b30..f9b05a3a51 100644 --- a/library/pk.c +++ b/library/pk.c @@ -608,7 +608,8 @@ int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk, * - using a macro in multiple places results in multiple copies of the code; * - this function only handles key types supported in PK. * - * Return 0 on unexpected types. Callers need to check for that value. + * WARNING: callers need to ensure the type is supported before calling this + * function, possibly by calling is_valid_for_pk(). */ static size_t pk_export_max_size(psa_key_type_t key_type, size_t bits) { @@ -937,6 +938,22 @@ int mbedtls_pk_import_into_psa(const mbedtls_pk_context *pk, } } +static int is_valid_for_pk(psa_key_type_t key_type) +{ +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) + if (PSA_KEY_TYPE_IS_ECC(key_type)) { + return 1; + } +#endif +#if defined(MBEDTLS_RSA_C) + if (key_type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || + key_type == PSA_KEY_TYPE_RSA_KEY_PAIR) { + return 1; + } +#endif + return 0; +} + static int copy_from_psa(mbedtls_svc_key_id_t key_id, mbedtls_pk_context *pk, int public_only) @@ -965,6 +982,10 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, } key_type = psa_get_key_type(&key_attr); + if (!is_valid_for_pk(key_type)) { + return MBEDTLS_ERR_PK_BAD_INPUT_DATA; + } + if (public_only) { key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(key_type); } @@ -972,20 +993,10 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, #if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) exp_key_size = pk_export_max_size(key_type, key_bits); - if (exp_key_size == 0) { - return MBEDTLS_ERR_PK_BAD_INPUT_DATA; - } exp_key = mbedtls_calloc(1, exp_key_size); if (exp_key == NULL) { return MBEDTLS_ERR_PK_ALLOC_FAILED; } -#else - /* In case we're passed non-ECC key (API misuse), return a sensible error - * now. Otherwise we might get BUFFER_TOO_SMALL when exporting below, which - * is unlikely to be helpful to the user as the buffer is internal. */ - if (!PSA_KEY_TYPE_IS_ECC(key_type)) { - return MBEDTLS_ERR_PK_BAD_INPUT_DATA; - } #endif if (public_only) { From 56771d12b80705deeed4fc52538c98cbdc18041a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 12 Feb 2026 12:06:54 +0100 Subject: [PATCH 08/24] PK: improve naming & doc of internal macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/library/pk.c b/library/pk.c index f9b05a3a51..55e14bf6fc 100644 --- a/library/pk.c +++ b/library/pk.c @@ -35,20 +35,29 @@ #include #include -#if defined(MBEDTLS_RSA_C) -#define PK_HAVE_KEYS_LARGER_THAN_ECC +/* + * We're trying to statisfy two kinds of users: + * - those who don't want to use the heap; + * - those who can't afford large stack buffers. + * + * The current compromise is that if ECC is the only key type supported in PK, + * then we export keys on the stack, and otherwise we use the heap. + */ +#if !defined(MBEDTLS_RSA_C) +#define PK_EXPORT_KEYS_ON_THE_STACK #endif -#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#if defined(PK_EXPORT_KEYS_ON_THE_STACK) +/* We know for ECC, pubkey are longer than privkeys, but double check */ +#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#if MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH > PK_EXPORT_KEY_STACK_BUFFER_SIZE +#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE +#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH +#endif +#else #include "mbedtls/platform.h" // for calloc/free #endif -/* We know for ECC, pubkey are longer than privkeys, but double check */ -#define PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH -#if MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH > PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH -#undef PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH -#define PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH -#endif /* * Initialise a mbedtls_pk_context @@ -600,7 +609,7 @@ int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk, } #if defined(MBEDTLS_PSA_CRYPTO_CLIENT) -#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) /* * Size needed to export a key of a type supported by PK. * @@ -635,7 +644,7 @@ static size_t pk_export_max_size(psa_key_type_t key_type, size_t bits) #endif return 0; } -#endif /* PK_HAVE_KEYS_LARGER_THAN_ECC */ +#endif /* PK_EXPORT_KEYS_ON_THE_STACK */ #endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) || defined(MBEDTLS_USE_PSA_CRYPTO) @@ -644,17 +653,17 @@ static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, const psa_key_attributes_t *attributes, mbedtls_svc_key_id_t *new_key_id) { -#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) unsigned char *key_buffer = NULL; size_t key_buffer_size = 0; #else - unsigned char key_buffer[PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH]; + unsigned char key_buffer[PK_EXPORT_KEY_STACK_BUFFER_SIZE]; const size_t key_buffer_size = sizeof(key_buffer); #endif size_t key_length = 0; /* We are exporting from a PK object, so we know key type is valid for PK */ -#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) key_buffer_size = pk_export_max_size(old_type, old_bits); key_buffer = mbedtls_calloc(1, key_buffer_size); if (key_buffer == NULL) { @@ -675,7 +684,7 @@ static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, mbedtls_platform_zeroize(key_buffer, key_length); cleanup: -#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) mbedtls_free(key_buffer); #endif return status; @@ -962,11 +971,11 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; psa_key_type_t key_type; size_t key_bits; -#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) unsigned char *exp_key = NULL; size_t exp_key_size = 0; #else - unsigned char exp_key[PK_MAX_EC_KEYPAIR_OR_PUBKEY_LENGTH]; + unsigned char exp_key[PK_EXPORT_KEY_STACK_BUFFER_SIZE]; const size_t exp_key_size = sizeof(exp_key); #endif size_t exp_key_len; @@ -991,7 +1000,7 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, } key_bits = psa_get_key_bits(&key_attr); -#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) exp_key_size = pk_export_max_size(key_type, key_bits); exp_key = mbedtls_calloc(1, exp_key_size); if (exp_key == NULL) { @@ -1090,7 +1099,7 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, exit: mbedtls_platform_zeroize(exp_key, exp_key_size); -#if defined(PK_HAVE_KEYS_LARGER_THAN_ECC) +#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) mbedtls_free(exp_key); #endif psa_reset_key_attributes(&key_attr); From 6b90afb2bba12487253e0fd683ac4b95aeeef08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 12 Feb 2026 12:20:13 +0100 Subject: [PATCH 09/24] PK: ensure we test with keys on the stack or heap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 21 +------------------ library/pk_internal.h | 21 +++++++++++++++++++ ...test_suite_config.crypto_combinations.data | 8 +++++++ tests/suites/test_suite_config.function | 2 +- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/library/pk.c b/library/pk.c index 55e14bf6fc..e34cba8937 100644 --- a/library/pk.c +++ b/library/pk.c @@ -35,26 +35,7 @@ #include #include -/* - * We're trying to statisfy two kinds of users: - * - those who don't want to use the heap; - * - those who can't afford large stack buffers. - * - * The current compromise is that if ECC is the only key type supported in PK, - * then we export keys on the stack, and otherwise we use the heap. - */ -#if !defined(MBEDTLS_RSA_C) -#define PK_EXPORT_KEYS_ON_THE_STACK -#endif - -#if defined(PK_EXPORT_KEYS_ON_THE_STACK) -/* We know for ECC, pubkey are longer than privkeys, but double check */ -#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH -#if MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH > PK_EXPORT_KEY_STACK_BUFFER_SIZE -#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE -#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH -#endif -#else +#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) #include "mbedtls/platform.h" // for calloc/free #endif diff --git a/library/pk_internal.h b/library/pk_internal.h index e86a3a09d2..4d6081cbe2 100644 --- a/library/pk_internal.h +++ b/library/pk_internal.h @@ -44,6 +44,27 @@ #define PEM_BEGIN_ENCRYPTED_PRIVATE_KEY_PKCS8 "-----BEGIN ENCRYPTED PRIVATE KEY-----" #define PEM_END_ENCRYPTED_PRIVATE_KEY_PKCS8 "-----END ENCRYPTED PRIVATE KEY-----" +/* + * We're trying to statisfy two kinds of users: + * - those who don't want to use the heap; + * - those who can't afford large stack buffers. + * + * The current compromise is that if ECC is the only key type supported in PK, + * then we export keys on the stack, and otherwise we use the heap. + */ +#if !defined(MBEDTLS_RSA_C) +#define PK_EXPORT_KEYS_ON_THE_STACK +#endif + +#if defined(PK_EXPORT_KEYS_ON_THE_STACK) +/* We know for ECC, pubkey are longer than privkeys, but double check */ +#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#if MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH > PK_EXPORT_KEY_STACK_BUFFER_SIZE +#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE +#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH +#endif +#endif + #if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA) /** * Public function mbedtls_pk_ec() can be used to get direct access to the diff --git a/tests/suites/test_suite_config.crypto_combinations.data b/tests/suites/test_suite_config.crypto_combinations.data index 9cc09ec895..0f8585a519 100644 --- a/tests/suites/test_suite_config.crypto_combinations.data +++ b/tests/suites/test_suite_config.crypto_combinations.data @@ -12,3 +12,11 @@ pass: Config: ECC: Montgomery curves only depends_on:!MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED:MBEDTLS_ECP_MONTGOMERY_ENABLED pass: + +Config: PK export keys on the stack (ECC is the only PK key type) +depends_on:PK_EXPORT_KEYS_ON_THE_STACK +pass: + +Config: PK export keys on the heap (ECC is not the only PK key type) +depends_on:!PK_EXPORT_KEYS_ON_THE_STACK +pass: diff --git a/tests/suites/test_suite_config.function b/tests/suites/test_suite_config.function index 9e9dd01990..8c68c0c5d3 100644 --- a/tests/suites/test_suite_config.function +++ b/tests/suites/test_suite_config.function @@ -1,5 +1,5 @@ /* BEGIN_HEADER */ - +#include "pk_internal.h" /* END_HEADER */ /* BEGIN_CASE */ From 4bebabb6878e19ea26ce64a34b7a330ff30c90da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 12 Feb 2026 12:46:15 +0100 Subject: [PATCH 10/24] PSA: improve PSA_EXPORT_KEY_OUTPUT_SIZE; PK: use it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- include/psa/crypto_sizes.h | 8 ++----- library/pk.c | 43 ++------------------------------------ 2 files changed, 4 insertions(+), 47 deletions(-) diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index 69fc7d79f2..1bf84de8c4 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -912,15 +912,11 @@ * If the parameters are not valid, the return value is unspecified. */ #define PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits) \ - (PSA_KEY_TYPE_IS_UNSTRUCTURED(key_type) ? PSA_BITS_TO_BYTES(key_bits) : \ - PSA_KEY_TYPE_IS_DH(key_type) ? PSA_BITS_TO_BYTES(key_bits) : \ - (key_type) == PSA_KEY_TYPE_RSA_KEY_PAIR ? PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits) : \ + ((key_type) == PSA_KEY_TYPE_RSA_KEY_PAIR ? PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits) : \ (key_type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY ? PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \ - (key_type) == PSA_KEY_TYPE_DSA_KEY_PAIR ? PSA_KEY_EXPORT_DSA_KEY_PAIR_MAX_SIZE(key_bits) : \ - (key_type) == PSA_KEY_TYPE_DSA_PUBLIC_KEY ? PSA_KEY_EXPORT_DSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \ PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type) ? PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(key_bits) : \ PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \ - 0u) + PSA_BITS_TO_BYTES(key_bits)) /*unstructured; FFDH public or private*/ /** Sufficient output buffer size for psa_export_public_key(). * diff --git a/library/pk.c b/library/pk.c index e34cba8937..b158547613 100644 --- a/library/pk.c +++ b/library/pk.c @@ -589,45 +589,6 @@ int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk, return 0; } -#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) -#if !defined(PK_EXPORT_KEYS_ON_THE_STACK) -/* - * Size needed to export a key of a type supported by PK. - * - * Compared to PSA_EXPORT_KEY_OUTPUT_SIZE() this is better for code size: - * - using a macro in multiple places results in multiple copies of the code; - * - this function only handles key types supported in PK. - * - * WARNING: callers need to ensure the type is supported before calling this - * function, possibly by calling is_valid_for_pk(). - */ -static size_t pk_export_max_size(psa_key_type_t key_type, size_t bits) -{ -#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) - if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type)) { - return PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(bits); - } -#endif -#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) - if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type)) { - return PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(bits); - } -#endif -#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) - if (key_type == PSA_KEY_TYPE_RSA_PUBLIC_KEY) { - return PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(bits); - } -#endif -#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) - if (key_type == PSA_KEY_TYPE_RSA_KEY_PAIR) { - return PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(bits); - } -#endif - return 0; -} -#endif /* PK_EXPORT_KEYS_ON_THE_STACK */ -#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ - #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) || defined(MBEDTLS_USE_PSA_CRYPTO) static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, psa_key_type_t old_type, size_t old_bits, @@ -645,7 +606,7 @@ static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id, /* We are exporting from a PK object, so we know key type is valid for PK */ #if !defined(PK_EXPORT_KEYS_ON_THE_STACK) - key_buffer_size = pk_export_max_size(old_type, old_bits); + key_buffer_size = PSA_EXPORT_KEY_OUTPUT_SIZE(old_type, old_bits); key_buffer = mbedtls_calloc(1, key_buffer_size); if (key_buffer == NULL) { return MBEDTLS_ERR_PK_ALLOC_FAILED; @@ -982,7 +943,7 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id, key_bits = psa_get_key_bits(&key_attr); #if !defined(PK_EXPORT_KEYS_ON_THE_STACK) - exp_key_size = pk_export_max_size(key_type, key_bits); + exp_key_size = PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits); exp_key = mbedtls_calloc(1, exp_key_size); if (exp_key == NULL) { return MBEDTLS_ERR_PK_ALLOC_FAILED; From 3a16bd53062e7a4cba107a9c1f55229b1b9530ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 19 Feb 2026 09:58:14 +0100 Subject: [PATCH 11/24] Add ChangeLog entry for PK large stack buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- ChangeLog.d/pk-large-stack-buffers.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 ChangeLog.d/pk-large-stack-buffers.txt diff --git a/ChangeLog.d/pk-large-stack-buffers.txt b/ChangeLog.d/pk-large-stack-buffers.txt new file mode 100644 index 0000000000..78a66a4519 --- /dev/null +++ b/ChangeLog.d/pk-large-stack-buffers.txt @@ -0,0 +1,7 @@ +Bugfix + * Some functions in PK were using large buffers (around 2KB in the default + configuration) on the stack, which was a problem in environments with a + small stack. Those buffers are now allocated on the heap, except in + configurations where ECC is the only supported key type in PK, making PK + still independent of the heap in such configurations (if the ECC driver + itself is not using the heap). Fixes #476. From ee2c3e819ff961f74c0aa04c6b891ef012ef3eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 23 Feb 2026 09:34:49 +0100 Subject: [PATCH 12/24] Adjust guard for 3.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In all.sh component test_psa_crypto_config_accel_rsa_crypto, where RSA is provided only by a drivers, we were using a stack buffer. However that was not correct, as "opaque" (PSA-held) RSA keys are still possible. This was pointed by failing test cases in test_suite_pk, such as "PSA import into PSA: opaque RSA, EXPORT (ok)". As usual with 3.6, we need more complicated pre-processor conditions. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk_internal.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/pk_internal.h b/library/pk_internal.h index 4d6081cbe2..202f011ea3 100644 --- a/library/pk_internal.h +++ b/library/pk_internal.h @@ -51,8 +51,11 @@ * * The current compromise is that if ECC is the only key type supported in PK, * then we export keys on the stack, and otherwise we use the heap. + * + * RSA can either be used directly or indirectly via opaque keys if enabled. */ -#if !defined(MBEDTLS_RSA_C) +#if !defined(MBEDTLS_RSA_C) && \ + !(defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY)) #define PK_EXPORT_KEYS_ON_THE_STACK #endif From a76d2129ba88fd796a8e1765040f574d669adf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 23 Feb 2026 09:54:12 +0100 Subject: [PATCH 13/24] PK: avoid using a > 2kB stack buffer in RSA -> PSA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here the code path is guarded by RSA_C so using the heap is clearly OK. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/library/pk.c b/library/pk.c index b158547613..254ed64d3e 100644 --- a/library/pk.c +++ b/library/pk.c @@ -681,20 +681,26 @@ static int import_pair_into_psa(const mbedtls_pk_context *pk, if (psa_get_key_type(attributes) != PSA_KEY_TYPE_RSA_KEY_PAIR) { return MBEDTLS_ERR_PK_TYPE_MISMATCH; } - unsigned char key_buffer[ - PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)]; - unsigned char *const key_end = key_buffer + sizeof(key_buffer); + size_t key_bits = psa_get_key_bits(attributes); + size_t key_buffer_size = PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits); + unsigned char *key_buffer = mbedtls_calloc(1, key_buffer_size); + if (key_buffer == NULL) { + return MBEDTLS_ERR_PK_ALLOC_FAILED; + } + unsigned char *const key_end = key_buffer + key_buffer_size; unsigned char *key_data = key_end; int ret = mbedtls_rsa_write_key(mbedtls_pk_rsa(*pk), key_buffer, &key_data); if (ret < 0) { - return ret; + goto cleanup_rsa; } size_t key_length = key_end - key_data; ret = PSA_PK_TO_MBEDTLS_ERR(psa_import_key(attributes, key_data, key_length, key_id)); - mbedtls_platform_zeroize(key_data, key_length); +cleanup_rsa: + mbedtls_platform_zeroize(key_buffer, key_buffer_size); + mbedtls_free(key_buffer); return ret; } #endif /* MBEDTLS_RSA_C */ From 06830d69df11939c2cac78b6458d8da1f1fa91ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 23 Feb 2026 10:01:29 +0100 Subject: [PATCH 14/24] PK: avoid 1kB stack buffer in rsa_alt_check_pair() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Again, guarded by RSA_C, so use of heap is clearly OK. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk_wrap.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/library/pk_wrap.c b/library/pk_wrap.c index 19196b559a..c174ce3b42 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -1336,7 +1336,6 @@ static int rsa_alt_check_pair(mbedtls_pk_context *pub, mbedtls_pk_context *prv, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { - unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; unsigned char hash[32]; size_t sig_len = 0; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -1345,21 +1344,29 @@ static int rsa_alt_check_pair(mbedtls_pk_context *pub, mbedtls_pk_context *prv, return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; } + size_t sig_size = (rsa_get_bitlen(pub) + 7) / 8; + unsigned char *sig = mbedtls_calloc(1, sig_size); + if (sig == NULL) { + return MBEDTLS_ERR_PK_ALLOC_FAILED; + } + memset(hash, 0x2a, sizeof(hash)); if ((ret = rsa_alt_sign_wrap(prv, MBEDTLS_MD_NONE, hash, sizeof(hash), - sig, sizeof(sig), &sig_len, + sig, sig_size, &sig_len, f_rng, p_rng)) != 0) { - return ret; + goto cleanup; } if (rsa_verify_wrap(pub, MBEDTLS_MD_NONE, hash, sizeof(hash), sig, sig_len) != 0) { - return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; } - return 0; +cleanup: + mbedtls_free(sig); + return ret; } #endif /* MBEDTLS_RSA_C */ From 3e7657c81f6e114e8caa99aa8c0f445080b74637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 23 Feb 2026 10:14:21 +0100 Subject: [PATCH 15/24] PK: use smarter size for stack buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original macro was accounting for the size of public FFDH keys, which are not a concern for PK. Use sizes for key types supported by PK, this brings the size of the buffer from 1kB to 528 bytes in the default config. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/pk.c b/library/pk.c index 254ed64d3e..6b8240a304 100644 --- a/library/pk.c +++ b/library/pk.c @@ -39,6 +39,25 @@ #include "mbedtls/platform.h" // for calloc/free #endif +#define MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN \ + PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) + +#define MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN \ + PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS) + +#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN 0 +#if (defined(MBEDTLS_ECP_C) || \ + (defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY))) && \ + MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN > MBEDTLS_PK_MAX_PUBKEY_RAW_LEN +#undef MBEDTLS_PK_MAX_PUBKEY_RAW_LEN +#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN +#endif +#if (defined(MBEDTLS_RSA_C) || \ + (defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))) && \ + MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN > MBEDTLS_PK_MAX_PUBKEY_RAW_LEN +#undef MBEDTLS_PK_MAX_PUBKEY_RAW_LEN +#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN +#endif /* * Initialise a mbedtls_pk_context @@ -779,7 +798,7 @@ static int import_public_into_psa(const mbedtls_pk_context *pk, #if defined(MBEDTLS_RSA_C) || \ (defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA)) || \ defined(MBEDTLS_USE_PSA_CRYPTO) - unsigned char key_buffer[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; + unsigned char key_buffer[MBEDTLS_PK_MAX_PUBKEY_RAW_LEN]; #endif unsigned char *key_data = NULL; size_t key_length = 0; From c5121ed11e928d7fb95dfb71f813efb1886e2722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 23 Feb 2026 11:04:23 +0100 Subject: [PATCH 16/24] PK: only use PSA macros when the header has been included... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/pk.c b/library/pk.c index 6b8240a304..88eee3c515 100644 --- a/library/pk.c +++ b/library/pk.c @@ -39,6 +39,7 @@ #include "mbedtls/platform.h" // for calloc/free #endif +#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) #define MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN \ PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) @@ -58,6 +59,7 @@ #undef MBEDTLS_PK_MAX_PUBKEY_RAW_LEN #define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN #endif +#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ /* * Initialise a mbedtls_pk_context From bc69abd2cbc29842a91d64b248d4f43cfeff4870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 27 Feb 2026 10:13:04 +0100 Subject: [PATCH 17/24] PK: use existing macros and functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/pk.c b/library/pk.c index 88eee3c515..e4a3ac0375 100644 --- a/library/pk.c +++ b/library/pk.c @@ -47,8 +47,7 @@ PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS) #define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN 0 -#if (defined(MBEDTLS_ECP_C) || \ - (defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY))) && \ +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && \ MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN > MBEDTLS_PK_MAX_PUBKEY_RAW_LEN #undef MBEDTLS_PK_MAX_PUBKEY_RAW_LEN #define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN @@ -720,8 +719,7 @@ static int import_pair_into_psa(const mbedtls_pk_context *pk, key_data, key_length, key_id)); cleanup_rsa: - mbedtls_platform_zeroize(key_buffer, key_buffer_size); - mbedtls_free(key_buffer); + mbedtls_zeroize_and_free(key_buffer, key_buffer_size); return ret; } #endif /* MBEDTLS_RSA_C */ @@ -924,8 +922,7 @@ static int is_valid_for_pk(psa_key_type_t key_type) } #endif #if defined(MBEDTLS_RSA_C) - if (key_type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || - key_type == PSA_KEY_TYPE_RSA_KEY_PAIR) { + if (PSA_KEY_TYPE_IS_RSA(key_type)) { return 1; } #endif From 81ecc37372863e1478d7bb93f794a6261924286e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 27 Feb 2026 10:16:20 +0100 Subject: [PATCH 18/24] PK: clarify comment about key export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk_internal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/library/pk_internal.h b/library/pk_internal.h index 202f011ea3..ab42a0b624 100644 --- a/library/pk_internal.h +++ b/library/pk_internal.h @@ -53,6 +53,7 @@ * then we export keys on the stack, and otherwise we use the heap. * * RSA can either be used directly or indirectly via opaque keys if enabled. + * (RSA_ALT is not relevant here as we can't export from such contexts.) */ #if !defined(MBEDTLS_RSA_C) && \ !(defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY)) From 571d78361ac8bdca44d15a96935c613588719f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 27 Feb 2026 10:17:28 +0100 Subject: [PATCH 19/24] PK: zeroize dummy signature just to be sure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The signature of a dummy hash for which no pre-image is know is probably not sensitive, but zeroize it anyway. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk_wrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/pk_wrap.c b/library/pk_wrap.c index c174ce3b42..cafcb87d0d 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -1365,7 +1365,7 @@ static int rsa_alt_check_pair(mbedtls_pk_context *pub, mbedtls_pk_context *prv, } cleanup: - mbedtls_free(sig); + mbedtls_zeroize_and_free(sig, sig_size); return ret; } #endif /* MBEDTLS_RSA_C */ From 127b0352b3eee25fa62a3f6ab447c3d1cd8242bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 27 Feb 2026 10:29:15 +0100 Subject: [PATCH 20/24] PK: move another large buffer to the heap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was previously missed as it only exists when USE_PSA_CRYPTO is enabled. Signed-off-by: Manuel Pégourié-Gonnard --- library/pk_wrap.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/pk_wrap.c b/library/pk_wrap.c index cafcb87d0d..8c038e7db6 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -288,9 +288,6 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk, psa_algorithm_t psa_md_alg, decrypt_alg; psa_status_t status; int key_len; - unsigned char buf[MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES]; - unsigned char *p = buf + sizeof(buf); - ((void) f_rng); ((void) p_rng); @@ -298,6 +295,13 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk, return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; } + const size_t key_bits = mbedtls_pk_get_bitlen(pk); + /* mbedtls_rsa_write_key() uses the same format as PSA export, which + * actually calls it under the hood, so we can use the PSA size macro. */ + const size_t buf_size = PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits); + unsigned char *buf = mbedtls_calloc(1, buf_size); + + unsigned char *p = buf + buf_size; key_len = mbedtls_rsa_write_key(rsa, buf, &p); if (key_len <= 0) { return MBEDTLS_ERR_PK_BAD_INPUT_DATA; @@ -314,7 +318,7 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk, psa_set_key_algorithm(&attributes, decrypt_alg); status = psa_import_key(&attributes, - buf + sizeof(buf) - key_len, key_len, + buf + buf_size - key_len, key_len, &key_id); if (status != PSA_SUCCESS) { ret = PSA_PK_TO_MBEDTLS_ERR(status); @@ -333,7 +337,7 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk, ret = 0; cleanup: - mbedtls_platform_zeroize(buf, sizeof(buf)); + mbedtls_zeroize_and_free(buf, buf_size); status = psa_destroy_key(key_id); if (ret == 0 && status != PSA_SUCCESS) { ret = PSA_PK_TO_MBEDTLS_ERR(status); From 023c51b28227741389e3c7434b421da8a3e832a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 27 Feb 2026 10:37:34 +0100 Subject: [PATCH 21/24] PK: adjust size macro in case PSA is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk_internal.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/pk_internal.h b/library/pk_internal.h index ab42a0b624..d1c26421d4 100644 --- a/library/pk_internal.h +++ b/library/pk_internal.h @@ -61,12 +61,21 @@ #endif #if defined(PK_EXPORT_KEYS_ON_THE_STACK) -/* We know for ECC, pubkey are longer than privkeys, but double check */ +/* We know for ECC, pubkey are longer than privkeys, but double check. + * Also, take the maximum size of legacy and PSA, as PSA might be disabled. */ #define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH -#if MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH > PK_EXPORT_KEY_STACK_BUFFER_SIZE +#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH #undef PK_EXPORT_KEY_STACK_BUFFER_SIZE #define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH #endif +#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_ECP_MAX_BYTES +#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE +#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_ECP_MAX_BYTES +#endif +#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_ECP_MAX_PT_LEN +#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE +#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_ECP_MAX_PT_LEN +#endif #endif #if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA) From 1fee3da79aa529bd0221823829ecc8826f9edaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 27 Feb 2026 10:48:48 +0100 Subject: [PATCH 22/24] PK: require more option combinations in tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- .../test_suite_config.crypto_combinations.data | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_config.crypto_combinations.data b/tests/suites/test_suite_config.crypto_combinations.data index 0f8585a519..fe3899f83c 100644 --- a/tests/suites/test_suite_config.crypto_combinations.data +++ b/tests/suites/test_suite_config.crypto_combinations.data @@ -13,10 +13,18 @@ Config: ECC: Montgomery curves only depends_on:!MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED:MBEDTLS_ECP_MONTGOMERY_ENABLED pass: -Config: PK export keys on the stack (ECC is the only PK key type) -depends_on:PK_EXPORT_KEYS_ON_THE_STACK +Config: PK export keys on the stack (PK is ECC-only) (USE_PSA) +depends_on:PK_EXPORT_KEYS_ON_THE_STACK:MBEDTLS_USE_PSA_CRYPTO pass: -Config: PK export keys on the heap (ECC is not the only PK key type) -depends_on:!PK_EXPORT_KEYS_ON_THE_STACK +Config: PK export keys on the stack (PK is ECC-only) (!USE_PSA) +depends_on:PK_EXPORT_KEYS_ON_THE_STACK:!MBEDTLS_USE_PSA_CRYPTO +pass: + +Config: PK export keys on the heap (PK is not ECC-only) (USE_PSA) +depends_on:!PK_EXPORT_KEYS_ON_THE_STACK:MBEDTLS_USE_PSA_CRYPTO +pass: + +Config: PK export keys on the heap (PK is not ECC-only) (!USE_PSA) +depends_on:!PK_EXPORT_KEYS_ON_THE_STACK:!MBEDTLS_USE_PSA_CRYPTO pass: From 4c4cfe98de970359ddb44a1a2a2ceb2e1b6498d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 3 Mar 2026 09:50:53 +0100 Subject: [PATCH 23/24] PK: use PSA size macros when exporting to PSA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pk.c | 2 +- library/pk_wrap.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/pk.c b/library/pk.c index e4a3ac0375..b5d76dbd91 100644 --- a/library/pk.c +++ b/library/pk.c @@ -1245,7 +1245,7 @@ int mbedtls_pk_verify_ext(mbedtls_pk_type_t type, const void *options, #if defined(MBEDTLS_USE_PSA_CRYPTO) if (pss_opts->mgf1_hash_id == md_alg) { - unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES]; + unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)]; unsigned char *p; int key_len; size_t signature_length; diff --git a/library/pk_wrap.c b/library/pk_wrap.c index 8c038e7db6..5265469349 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -72,7 +72,7 @@ static int rsa_verify_wrap(mbedtls_pk_context *pk, mbedtls_md_type_t md_alg, mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT; psa_status_t status; int key_len; - unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES]; + unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)]; unsigned char *p = buf + sizeof(buf); psa_algorithm_t psa_alg_md; size_t rsa_len = mbedtls_rsa_get_len(rsa); @@ -375,7 +375,7 @@ static int rsa_encrypt_wrap(mbedtls_pk_context *pk, psa_algorithm_t psa_md_alg, psa_encrypt_alg; psa_status_t status; int key_len; - unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES]; + unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)]; unsigned char *p = buf + sizeof(buf); ((void) f_rng); From c763c2e83717d276108c9c28c5c43d9d69e7ce7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 3 Mar 2026 09:53:08 +0100 Subject: [PATCH 24/24] PK: use EC macro for EC key size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/pkwrite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/pkwrite.c b/library/pkwrite.c index ff6c0bfb44..d264abfbd9 100644 --- a/library/pkwrite.c +++ b/library/pkwrite.c @@ -45,10 +45,10 @@ /* Helpers for properly sizing buffers aimed at holding public keys or * key-pairs based on build symbols. */ #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) -#define PK_MAX_EC_PUBLIC_KEY_SIZE PSA_EXPORT_PUBLIC_KEY_MAX_SIZE +#define PK_MAX_EC_PUBLIC_KEY_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH #define PK_MAX_EC_KEY_PAIR_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH #elif defined(MBEDTLS_USE_PSA_CRYPTO) -#define PK_MAX_EC_PUBLIC_KEY_SIZE PSA_EXPORT_PUBLIC_KEY_MAX_SIZE +#define PK_MAX_EC_PUBLIC_KEY_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH #define PK_MAX_EC_KEY_PAIR_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH #else #define PK_MAX_EC_PUBLIC_KEY_SIZE MBEDTLS_ECP_MAX_PT_LEN