mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2026-08-21 18:49:54 +00:00
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:
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user