From 54682ec425078e45299628c03d98be10bcef4f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 2 Jun 2026 10:30:59 +0200 Subject: [PATCH] rsa: add CF testing for PKCS#1 v1.5 decode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Pégourié-Gonnard --- library/rsa.c | 35 +++---------------- library/rsa_internal.h | 37 ++++++++++++++++++++ tests/suites/test_suite_pkcs1_v15.function | 39 ++++++++++++++++++++++ 3 files changed, 81 insertions(+), 30 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 2eb042ff5a..94db8282c4 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -414,37 +414,12 @@ end_of_export: #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) -/** This function performs the unpadding part of a PKCS#1 v1.5 decryption - * operation (EME-PKCS1-v1_5 decoding). - * - * \note The return value from this function is a sensitive value - * (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen - * in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING - * is often a situation that an attacker can provoke and leaking which - * one is the result is precisely the information the attacker wants. - * - * \param input The input buffer which is the payload inside PKCS#1v1.5 - * encryption padding, called the "encoded message EM" - * by the terminology. - * \param ilen The length of the payload in the \p input buffer. - * \param output The buffer for the payload, called "message M" by the - * PKCS#1 terminology. This must be a writable buffer of - * length \p output_max_len bytes. - * \param olen The address at which to store the length of - * the payload. This must not be \c NULL. - * \param output_max_len The length in bytes of the output buffer \p output. - * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE - * The output buffer is too small for the unpadded payload. - * \return #MBEDTLS_ERR_RSA_INVALID_PADDING - * The input doesn't contain properly formatted padding. +/* + * EME-PKCS1-v1_5 decoding, see documentation in rsa_internal.h */ -static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, - size_t ilen, - unsigned char *output, - size_t output_max_len, - size_t *olen) +MBEDTLS_STATIC_TESTABLE int mbedtls_ct_rsaes_pkcs1_v15_unpadding( + unsigned char *input, size_t ilen, + unsigned char *output, size_t output_max_len, size_t *olen) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t i, plaintext_max_size; diff --git a/library/rsa_internal.h b/library/rsa_internal.h index f79c3b7122..3b6186c7e8 100644 --- a/library/rsa_internal.h +++ b/library/rsa_internal.h @@ -118,4 +118,41 @@ int mbedtls_rsa_rsassa_pss_sign_no_mode_check(mbedtls_rsa_context *ctx, unsigned char *sig); #endif /* MBEDTLS_PKCS1_V21 */ +/* This would normally be in rsa_invasive.h but it didn't exist before 3.6 + * became an LTS, and I'd rather not add files in LTS if it can be avoided. */ +#if defined(MBEDTLS_TEST_HOOKS) +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + +/** This function performs the unpadding part of a PKCS#1 v1.5 decryption + * operation (EME-PKCS1-v1_5 decoding). + * + * \note The return value from this function is a sensitive value + * (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen + * in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING + * is often a situation that an attacker can provoke and leaking which + * one is the result is precisely the information the attacker wants. + * + * \param input The input buffer which is the payload inside PKCS#1v1.5 + * encryption padding, called the "encoded message EM" + * by the terminology. + * \param ilen The length of the payload in the \p input buffer. + * \param output The buffer for the payload, called "message M" by the + * PKCS#1 terminology. This must be a writable buffer of + * length \p output_max_len bytes. + * \param olen The address at which to store the length of + * the payload. This must not be \c NULL. + * \param output_max_len The length in bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE + * The output buffer is too small for the unpadded payload. + * \return #MBEDTLS_ERR_RSA_INVALID_PADDING + * The input doesn't contain properly formatted padding. + */ +MBEDTLS_STATIC_TESTABLE int mbedtls_ct_rsaes_pkcs1_v15_unpadding( + unsigned char *input, size_t ilen, + unsigned char *output, size_t output_max_len, size_t *olen); +#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ +#endif /* MBEDTLS_TEST_HOOKS */ + #endif /* rsa_internal.h */ diff --git a/tests/suites/test_suite_pkcs1_v15.function b/tests/suites/test_suite_pkcs1_v15.function index 7113274550..e7c1ce22fd 100644 --- a/tests/suites/test_suite_pkcs1_v15.function +++ b/tests/suites/test_suite_pkcs1_v15.function @@ -1,6 +1,39 @@ /* BEGIN_HEADER */ #include "mbedtls/rsa.h" #include "mbedtls/md.h" +#include "rsa_internal.h" +#include + +#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_RSA_ALT) +static void pkcs1_v15_decode_raw(const unsigned char *input, + size_t input_size, + size_t output_size, + int expected_result, + size_t expected_plaintext_length) +{ + unsigned char *input_buf = NULL; + unsigned char *output_buf = NULL; + size_t olen = 0; + + TEST_CALLOC(output_buf, output_size); + + TEST_CALLOC(input_buf, input_size); + memcpy(input_buf, input, input_size); + + TEST_CF_SECRET(input_buf, input_size); + TEST_EQUAL(expected_result, + mbedtls_ct_rsaes_pkcs1_v15_unpadding( + input_buf, input_size, + output_buf, output_size, &olen)); + if (expected_result == 0) { + TEST_EQUAL(expected_plaintext_length, olen); + } + +exit: + mbedtls_free(input_buf); + mbedtls_free(output_buf); +} +#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_RSA_ALT */ /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -257,6 +290,11 @@ void pkcs1_v15_decode(data_t *input, TEST_ASSERT(count < 16); } +#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_RSA_ALT) + pkcs1_v15_decode_raw(original, sizeof(original), output_size, + expected_result, expected_plaintext_length); +#endif + exit: mbedtls_mpi_free(&Nmpi); mbedtls_mpi_free(&Empi); mbedtls_mpi_free(&Pmpi); mbedtls_mpi_free(&Qmpi); @@ -264,6 +302,7 @@ exit: } /* END_CASE */ + /* BEGIN_CASE */ void pkcs1_rsassa_v15_sign(int mod, char *input_P, char *input_Q, char *input_N,