Merge pull request #1636 from mpg/restricted-rsa-padding-3.6

[3.6] Fix side-channel in PSA_ALG_RSA_PKCS1V15_CRYPT
This commit is contained in:
Gilles Peskine
2026-06-24 09:34:57 +02:00
committed by GitHub
15 changed files with 392 additions and 108 deletions
+8
View File
@@ -0,0 +1,8 @@
Security
* Fix a side channel in RSA PKCS#1 v1.5 decryption: error handling in the
library would reveal through timing the difference between success,
invalid padding, or output too large for buffer, giving rise to a
Bleichenbacher attack. Note that while the library now handles sensitive
errors in constant-time, RSA PKCS#1 v1.5 decryption remains inherently
dangerous, should be avoided when possible, and otherwise requires great
care in application code. Found by zhengg. CVE-2026-50587
+9 -5
View File
@@ -930,6 +930,15 @@ int mbedtls_pk_sign_restartable(mbedtls_pk_context *ctx,
/**
* \brief Decrypt message (including padding if relevant).
*
* \warning When using PKCS#1 v1.5 (see note below), this is an
* inherently dangerous function (CWE-242) and the return value
* is sensitive, see mbedtls_rsa_rsaes_pkcs1_v15_decrypt().
*
* \note For keys of type #MBEDTLS_PK_RSA, the encryption algorithm is
* either PKCS#1 v1.5 or OAEP, depending on the padding mode in
* the underlying RSA context. For a pk object constructed by
* parsing, this is PKCS#1 v1.5 by default.
*
* \param ctx The PK context to use. It must have been set up
* with a private key.
* \param input Input to decrypt
@@ -940,11 +949,6 @@ int mbedtls_pk_sign_restartable(mbedtls_pk_context *ctx,
* \param f_rng RNG function, must not be \c NULL.
* \param p_rng RNG parameter
*
* \note For keys of type #MBEDTLS_PK_RSA, the signature algorithm is
* either PKCS#1 v1.5 or OAEP, depending on the padding mode in
* the underlying RSA context. For a pk object constructed by
* parsing, this is PKCS#1 v1.5 by default.
*
* \return 0 on success, or a specific error code.
*/
int mbedtls_pk_decrypt(mbedtls_pk_context *ctx,
+9 -3
View File
@@ -696,7 +696,9 @@ int mbedtls_rsa_rsaes_oaep_encrypt(mbedtls_rsa_context *ctx,
*
* \warning When \p ctx->padding is set to #MBEDTLS_RSA_PKCS_V15,
* mbedtls_rsa_rsaes_pkcs1_v15_decrypt() is called, which is an
* inherently dangerous function (CWE-242).
* inherently dangerous function (CWE-242). In that case, the
* return value of this function is sensitive, see the
* documentation of mbedtls_rsa_rsaes_pkcs1_v15_decrypt().
*
* \note The output buffer length \c output_max_len should be
* as large as the size \p ctx->len of \p ctx->N (for example,
@@ -735,9 +737,13 @@ int mbedtls_rsa_pkcs1_decrypt(mbedtls_rsa_context *ctx,
* operation (RSAES-PKCS1-v1_5-DECRYPT).
*
* \warning This is an inherently dangerous function (CWE-242). Unless
* it is used in a side channel free and safe way (eg.
* implementing the TLS protocol as per 7.4.7.1 of RFC 5246),
* it is used in a side channel free and safe way,
* the calling code is vulnerable.
* Specifically, callers need to ensure an adversary cannot
* distinguish between success, MBEDTLS_ERR_RSA_INVALID_PADDING
* and MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. Also, in the latter two
* cases, the values of the output bytes must be ignored, again
* without revealing whether that's the case.
*
* \note The output buffer length \c output_max_len should be
* as large as the size \p ctx->len of \p ctx->N, for example,
+10
View File
@@ -3136,6 +3136,16 @@ psa_status_t psa_asymmetric_encrypt(mbedtls_svc_key_id_t key,
/**
* \brief Decrypt a short message with a private key.
*
* \warning When \p alg is #PSA_ALG_RSA_PKCS1V15_CRYPT, this is an
* inherently dangerous function (CWE-242): unless it is used
* in a side channel free and safe way, the calling code
* is vulnerable.
* Specifically, callers need to ensure an adversary cannot
* distinguish between success, #PSA_ERROR_INVALID_PADDING and
* #PSA_ERROR_BUFFER_TOO_SMALL. Also, in the latter two cases,
* the values of the output bytes must be ignored, again
* without revealing whether that's the case.
*
* \param key Identifier of the key to use for the operation.
* It must be an asymmetric key pair. It must
* allow the usage #PSA_KEY_USAGE_DECRYPT.
+1 -2
View File
@@ -1760,8 +1760,7 @@
* \warning Calling psa_asymmetric_decrypt() with this algorithm as a
* parameter is considered an inherently dangerous function
* (CWE-242). Unless it is used in a side channel free and safe
* way (eg. implementing the TLS protocol as per 7.4.7.1 of
* RFC 5246), the calling code is vulnerable.
* way, the calling code is vulnerable.
*
*/
#define PSA_ALG_RSA_PKCS1V15_CRYPT ((psa_algorithm_t) 0x07000200)
+38 -15
View File
@@ -34,6 +34,7 @@
#if defined(MBEDTLS_RSA_C)
#include "pkwrite.h"
#include "rsa_internal.h"
#include "constant_time_internal.h"
#endif
#if defined(MBEDTLS_PK_CAN_ECDSA_SOME)
@@ -329,21 +330,33 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
input, ilen,
NULL, 0,
output, osize, olen);
if (status != PSA_SUCCESS) {
ret = PSA_PK_RSA_TO_MBEDTLS_ERR(status);
goto cleanup;
}
ret = 0;
#if defined(MBEDTLS_PKCS1_V15)
/* Translate error codes from PSA to legacy
* Success vs INVALID_PADDING vs BUFFER_TOO_SMALL is sensitive
* (padding oracle attack), so we take care to translate that
* part in constant time.
*/
int problem;
status = mbedtls_rsa_decrypt_decompose_ret(
PSA_ERROR_INVALID_PADDING, MBEDTLS_ERR_RSA_INVALID_PADDING,
PSA_ERROR_BUFFER_TOO_SMALL, MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
status, &problem);
ret = PSA_PK_RSA_TO_MBEDTLS_ERR(status);
ret |= problem;
#else
ret = PSA_PK_RSA_TO_MBEDTLS_ERR(status);
#endif
cleanup:
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);
}
return ret;
/* Don't branch on ret as it is a sensitive value
* (it reveals whether padding was valid).
* Instead branch on status. That means when both ret and
* status were errors, we'll return the unlock status while we would
* normally return the first error, but that's better than leaking info. */
return (status != PSA_SUCCESS) ? PSA_PK_TO_MBEDTLS_ERR(status) : ret;
}
#else /* MBEDTLS_USE_PSA_CRYPTO */
static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
@@ -1503,11 +1516,21 @@ static int rsa_opaque_decrypt(mbedtls_pk_context *pk,
}
status = psa_asymmetric_decrypt(pk->priv_id, alg, input, ilen, NULL, 0, output, osize, olen);
if (status != PSA_SUCCESS) {
return PSA_PK_RSA_TO_MBEDTLS_ERR(status);
}
return 0;
#if defined(MBEDTLS_PKCS1_V15)
/* Translate error codes from PSA to legacy
* Success vs INVALID_PADDING vs BUFFER_TOO_SMALL is sensitive
* (padding oracle attack), so we take care to translate that
* part in constant time.
*/
int problem;
status = mbedtls_rsa_decrypt_decompose_ret(
PSA_ERROR_INVALID_PADDING, MBEDTLS_ERR_RSA_INVALID_PADDING,
PSA_ERROR_BUFFER_TOO_SMALL, MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
status, &problem);
return PSA_PK_RSA_TO_MBEDTLS_ERR(status) | problem;
#else
return PSA_PK_RSA_TO_MBEDTLS_ERR(status);
#endif
}
#endif /* PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC */
+6 -1
View File
@@ -3568,7 +3568,12 @@ exit:
LOCAL_INPUT_FREE(salt_external, salt);
LOCAL_OUTPUT_FREE(output_external, output);
return (status == PSA_SUCCESS) ? unlock_status : status;
/* Don't branch on status as it is a sensitive value
* (it reveals whether padding was valid).
* Instead branch on unlock_status. That means when both status and
* unlock_status were errors, we'll return the unlock error while we would
* normally return the first error, but that's better than leaking info. */
return (unlock_status != PSA_SUCCESS) ? unlock_status : status;
}
/****************************************************************/
+17 -8
View File
@@ -25,6 +25,7 @@
#include <mbedtls/rsa.h>
#include <mbedtls/error.h>
#include "rsa_internal.h"
#include "constant_time_internal.h"
#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) || \
@@ -652,14 +653,22 @@ psa_status_t mbedtls_psa_asymmetric_decrypt(const psa_key_attributes_t *attribut
if (alg == PSA_ALG_RSA_PKCS1V15_CRYPT) {
#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT)
status = mbedtls_to_psa_error(
mbedtls_rsa_pkcs1_decrypt(rsa,
mbedtls_psa_get_random,
MBEDTLS_PSA_RANDOM_STATE,
output_length,
input,
output,
output_size));
int combined_ret = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(
rsa, mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE,
output_length, input, output, output_size);
/* Translate error codes from legacy to PSA.
* Success vs INVALID_PADDING vs OUTPUT_TOO_LARGE is sensitive
* (padding oracle attack), so we take care to translate that
* part in constant time.
*/
int problem;
int public_ret = mbedtls_rsa_decrypt_decompose_ret(
MBEDTLS_ERR_RSA_INVALID_PADDING, PSA_ERROR_INVALID_PADDING,
MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, PSA_ERROR_BUFFER_TOO_SMALL,
combined_ret, &problem);
status = mbedtls_to_psa_error(public_ret);
status |= problem;
#else
status = PSA_ERROR_NOT_SUPPORTED;
#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT */
+31 -30
View File
@@ -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;
@@ -567,6 +542,32 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input,
#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C)
int mbedtls_rsa_decrypt_decompose_ret(
int invalid_padding_in, int invalid_padding_out,
int output_too_large_in, int output_too_large_out,
int combined_ret,
int *problem)
{
*problem = 0;
int ret = combined_ret;
const mbedtls_ct_condition_t invalid_padding_cond =
mbedtls_ct_uint_eq((mbedtls_ct_uint_t) ret,
(mbedtls_ct_uint_t) invalid_padding_in);
*problem = mbedtls_ct_error_if(invalid_padding_cond, invalid_padding_out, *problem);
ret = mbedtls_ct_error_if(invalid_padding_cond, 0, ret);
const mbedtls_ct_condition_t output_too_large_cond =
mbedtls_ct_uint_eq((mbedtls_ct_uint_t) ret,
(mbedtls_ct_uint_t) output_too_large_in);
*problem = mbedtls_ct_error_if(output_too_large_cond, output_too_large_out, *problem);
ret = mbedtls_ct_error_if(output_too_large_cond, 0, ret);
return ret;
}
#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C */
#if !defined(MBEDTLS_RSA_ALT)
int mbedtls_rsa_import(mbedtls_rsa_context *ctx,
+67
View File
@@ -118,4 +118,71 @@ 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 */
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C)
/** Decompose sensitive return values out of a return code, in constant time.
*
* \param invalid_padding_in The value of \p combined_ret that indicates
* invalid padding.
* \param invalid_padding_out The value to set \p problem to in case of
* invalid padding.
* \param output_too_large_in The value of \p combined_ret that indicates
* an insufficient output buffer size.
* \param output_too_large_out The value to set \p problem to in case of
* an insufficient output buffer size.
* \param combined_ret The value to decompose.
* \param[out] problem On output:
* - \p invalid_padding_out,
* if \p combined_ret = \p invalid_padding_in;
* - \p output_too_large_out,
* if \p combined_ret = \p output_too_large_in;
* - otherwise \c 0.
*
* \return - \c 0 if \p combined_ret = \p invalid_padding_in
* or \p combined_ret = \p output_too_large_in;
* - otherwise \c combined_ret.
*/
int mbedtls_rsa_decrypt_decompose_ret(
int invalid_padding_in, int invalid_padding_out,
int output_too_large_in, int output_too_large_out,
int combined_ret,
int *problem);
#endif
#endif /* rsa_internal.h */
+23
View File
@@ -1546,6 +1546,14 @@ void pk_rsa_decrypt_test_vec(data_t *cipher, int mod, int padding, int md_alg,
if (ret == 0) {
TEST_ASSERT(olen == clear->len);
TEST_ASSERT(memcmp(output, clear->x, olen) == 0);
if (clear->len != 0) {
/* Try again with an output buffer that's too small */
TEST_EQUAL(mbedtls_pk_decrypt(&pk, cipher->x, cipher->len,
output, &olen, clear->len - 1,
mbedtls_test_rnd_pseudo_rand, &rnd_info),
MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE);
}
}
exit:
@@ -1618,6 +1626,14 @@ void pk_wrap_rsa_decrypt_test_vec(data_t *cipher, int mod,
if (ret == 0) {
TEST_EQUAL(olen, clear->len);
TEST_EQUAL(memcmp(output, clear->x, olen), 0);
if (clear->len != 0) {
/* Try again with an output buffer that's too small */
TEST_EQUAL(mbedtls_pk_decrypt(&pk, cipher->x, cipher->len,
output, &olen, clear->len - 1,
mbedtls_test_rnd_pseudo_rand, &rnd_info),
MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE);
}
}
TEST_EQUAL(PSA_SUCCESS, psa_destroy_key(key_id));
@@ -1789,6 +1805,13 @@ void pk_rsa_alt()
TEST_ASSERT(test_len == sizeof(msg));
TEST_ASSERT(memcmp(test, msg, test_len) == 0);
/* Try again with an output buffer that's too small */
TEST_EQUAL(mbedtls_pk_decrypt(&alt, ciph, ciph_len,
test, &test_len, sizeof(msg) - 1,
mbedtls_test_rnd_std_rand, NULL),
MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE);
/* Test forbidden operations */
TEST_ASSERT(mbedtls_pk_encrypt(&alt, msg, sizeof(msg),
ciph, &ciph_len, sizeof(ciph),
@@ -0,0 +1,53 @@
RSA sensitive ret: 0
rsa_decrypt_decompose_ret:0:0:0
RSA sensitive ret: sensitive 1
rsa_decrypt_decompose_ret:-1:0:-11
RSA sensitive ret: sensitive 2
rsa_decrypt_decompose_ret:-2:0:-12
RSA sensitive ret: public
rsa_decrypt_decompose_ret:-3:-3:0
RSAES-V15 decoding: good, payload=max, tight output buffer
pkcs1_v15_decode:"0002505152535455565700":117:117:0
RSAES-V15 decoding: good, payload=max, larger output buffer
pkcs1_v15_decode:"0002505152535455565700":117:128:0
RSAES-V15 decoding: good, payload=max-1, tight output buffer
pkcs1_v15_decode:"000250515253545556575800":116:116:0
RSAES-V15 decoding: good, payload=max-1, larger output buffer
pkcs1_v15_decode:"000250515253545556575800":116:117:0
RSAES-V15 decoding: good, payload=1
pkcs1_v15_decode:"00025050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000":1:1:0
RSAES-V15 decoding: good, empty payload
pkcs1_v15_decode:"0002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000":0:0:0
RSAES-V15 decoding: payload=max, output too large
pkcs1_v15_decode:"0002505152535455565700":117:116:MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
RSAES-V15 decoding: payload=max-1, output too large
pkcs1_v15_decode:"000250515253545556575800":116:115:MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
RSAES-V15 decoding: bad first byte
pkcs1_v15_decode:"0102505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: bad second byte (0 instead of 2)
pkcs1_v15_decode:"0000505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: bad second byte (1 instead of 2)
pkcs1_v15_decode:"0001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: padding too short (0)
pkcs1_v15_decode:"000200":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: padding too short (7)
pkcs1_v15_decode:"0002505050505050500000ffffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: unfinished padding
pkcs1_v15_decode:"0002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
-42
View File
@@ -51,45 +51,3 @@ pkcs1_rsassa_v15_sign:1024:"d17f655bf27c8b16d35462c905cc04a26f37e2a67fa9c0ce0dce
RSASSA-V15 Verification Test Vector Int
depends_on:MBEDTLS_MD_CAN_SHA1
pkcs1_rsassa_v15_verify:1024:"a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5":"010001":MBEDTLS_MD_SHA1:MBEDTLS_MD_SHA1:"37b66ae0445843353d47ecb0b4fd14c110e62d6a":"e3b5d5d002c1bce50c2b65ef88a188d83bce7e61":"2154f928615e5101fcdeb57bc08fc2f35c3d5996403861ae3efb1d0712f8bb05cc21f7f5f11f62e5b6ea9f0f2b62180e5cbe7ba535032d6ac8068fff7f362f73d2c3bf5eca6062a1723d7cfd5abb6dcf7e405f2dc560ffe6fc37d38bee4dc9e24fe2bece3e3b4a3f032701d3f0947b42930083dd4ad241b3309b514595482d42":0
RSAES-V15 decoding: good, payload=max, tight output buffer
pkcs1_v15_decode:"0002505152535455565700":117:117:0
RSAES-V15 decoding: good, payload=max, larger output buffer
pkcs1_v15_decode:"0002505152535455565700":117:128:0
RSAES-V15 decoding: good, payload=max-1, tight output buffer
pkcs1_v15_decode:"000250515253545556575800":116:116:0
RSAES-V15 decoding: good, payload=max-1, larger output buffer
pkcs1_v15_decode:"000250515253545556575800":116:117:0
RSAES-V15 decoding: good, payload=1
pkcs1_v15_decode:"00025050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000":1:1:0
RSAES-V15 decoding: good, empty payload
pkcs1_v15_decode:"0002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000":0:0:0
RSAES-V15 decoding: payload=max, output too large
pkcs1_v15_decode:"0002505152535455565700":117:116:MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
RSAES-V15 decoding: payload=max-1, output too large
pkcs1_v15_decode:"000250515253545556575800":116:115:MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
RSAES-V15 decoding: bad first byte
pkcs1_v15_decode:"0102505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: bad second byte (0 instead of 2)
pkcs1_v15_decode:"0000505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: bad second byte (1 instead of 2)
pkcs1_v15_decode:"0001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: padding too short (0)
pkcs1_v15_decode:"000200":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: padding too short (7)
pkcs1_v15_decode:"0002505050505050500000ffffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
RSAES-V15 decoding: unfinished padding
pkcs1_v15_decode:"0002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
@@ -1,6 +1,39 @@
/* BEGIN_HEADER */
#include "mbedtls/rsa.h"
#include "mbedtls/md.h"
#include "rsa_internal.h"
#include <test/constant_flow.h>
#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
@@ -124,6 +157,47 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE */
void rsa_decrypt_decompose_ret(int input,
int expected_ret, int expected_problem)
{
const int sensitive_in_1 = -1;
const int sensitive_in_2 = -2;
const int problem_1 = -11;
const int problem_2 = -12;
int combined_ret = input;
TEST_CF_SECRET(&combined_ret, sizeof(combined_ret));
int actual_problem = 42;
TEST_CF_SECRET(&actual_problem, sizeof(actual_problem));
int actual_ret = mbedtls_rsa_decrypt_decompose_ret(sensitive_in_1, problem_1,
sensitive_in_2, problem_2,
combined_ret,
&actual_problem);
TEST_EQUAL(actual_problem, expected_problem);
TEST_EQUAL(actual_ret, expected_ret);
/* Check invariant when there's no translation, only separation */
actual_ret = mbedtls_rsa_decrypt_decompose_ret(sensitive_in_1, sensitive_in_1,
sensitive_in_2, sensitive_in_2,
combined_ret,
&actual_problem);
TEST_EQUAL(actual_ret, expected_ret);
if (expected_problem == problem_1) {
TEST_EQUAL(actual_problem, sensitive_in_1);
} else if (expected_problem == problem_2) {
TEST_EQUAL(actual_problem, sensitive_in_2);
} else {
TEST_EQUAL(actual_problem, 0);
}
TEST_CF_PUBLIC(&actual_problem, sizeof(actual_problem));
TEST_CF_PUBLIC(&combined_ret, sizeof(combined_ret));
TEST_EQUAL(actual_problem | actual_ret, combined_ret);
}
/* END_CASE */
/* BEGIN_CASE */
void pkcs1_v15_decode(data_t *input,
int expected_plaintext_length_arg,
@@ -257,6 +331,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 +343,7 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE */
void pkcs1_rsassa_v15_sign(int mod, char *input_P,
char *input_Q, char *input_N,
+40 -2
View File
@@ -8756,6 +8756,14 @@ void asymmetric_encrypt_decrypt(int key_type_arg,
TEST_LE_U(output_size, PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE);
TEST_CALLOC(output, output_size);
/* We want the function to work with an output buffer that's just the size
* of the actual plaintext. The PSA spec requires portable callers to pass
* a buffer that's the maximum possible plaintext size, given by
* PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(). When the buffer is smaller than
* that but large enough for the actual plaintext, implementations may either
* return PSA_ERROR_BUFFER_TOO_SMALL or success. Historically we've done the
* latter. Even though we never promised it, people might depend on this
* (our TLS code does), so let's test this behaviour in LTS branches. */
output2_size = input_data->len;
TEST_LE_U(output2_size,
PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg));
@@ -8782,6 +8790,16 @@ void asymmetric_encrypt_decrypt(int key_type_arg,
TEST_MEMORY_COMPARE(input_data->x, input_data->len,
output2, output2_length);
/* Try again with an output buffer that's one byte too small */
if (output2_size != 0) {
TEST_EQUAL(PSA_ERROR_BUFFER_TOO_SMALL,
psa_asymmetric_decrypt(key, alg,
output, output_length,
label->x, label->len,
output2, output2_size - 1,
&output2_length));
}
exit:
/*
* Key attributes may have been returned by psa_get_key_attributes()
@@ -8825,8 +8843,17 @@ void asymmetric_decrypt(int key_type_arg,
PSA_ASSERT(psa_get_key_attributes(key, &attributes));
key_bits = psa_get_key_bits(&attributes);
/* Determine the maximum ciphertext length */
output_size = PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg);
/* We want the function to work with an output buffer that's just the size
* of the actual plaintext. The PSA spec requires portable callers to pass
* a buffer that's the maximum possible plaintext size, given by
* PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(). When the buffer is smaller than
* that but large enough for the actual plaintext, implementations may either
* return PSA_ERROR_BUFFER_TOO_SMALL or success. Historically we've done the
* latter. Even though we never promised it, people might depend on this
* (our TLS code does), so let's test this behaviour in LTS branches. */
output_size = expected_data->len;
TEST_LE_U(output_size,
PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg));
TEST_LE_U(output_size, PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE);
TEST_CALLOC(output, output_size);
@@ -8856,6 +8883,17 @@ void asymmetric_decrypt(int key_type_arg,
output, output_length);
}
/* Try again with an output buffer that's one byte too small */
if (output_size != 0) {
TEST_EQUAL(PSA_ERROR_BUFFER_TOO_SMALL,
psa_asymmetric_decrypt(key, alg,
input_data->x, input_data->len,
label->x, label->len,
output,
output_size - 1,
&output_length));
}
exit:
psa_reset_key_attributes(&attributes);
psa_destroy_key(key);