mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2026-09-20 00:57:24 +00:00
Define and use mbedtls_rsa_decrypt_decompose_ret()
Use a more structured way of isolating and translating sensitive error codes from RSA PKCS#1v1.5 decryption. Signed-off-by: Gilles Peskine <[email protected]> Signed-off-by: Manuel Pégourié-Gonnard <[email protected]>
This commit is contained in:
committed by
Manuel Pégourié-Gonnard
parent
ea0a2c6d03
commit
fe47e9ed89
+11
-17
@@ -331,24 +331,18 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
|
||||
NULL, 0,
|
||||
output, osize, olen);
|
||||
|
||||
/* We want to convert status into an MBEDTLS code without allowing an
|
||||
* attacker to distinguish between 0, invalid padding, or buffer too
|
||||
* small. (It's OK if the attacker distinguishes between one of the
|
||||
* above three and other status such as out of memory.) Since
|
||||
* PSA_PK_RSA_TO_MBEDTLS_ERR() is leaky, hide the difference from it. */
|
||||
mbedtls_ct_condition_t bad_padding = mbedtls_ct_uint_eq(
|
||||
(mbedtls_ct_uint_t) status,
|
||||
(mbedtls_ct_uint_t) PSA_ERROR_INVALID_PADDING);
|
||||
mbedtls_ct_condition_t large_msg = mbedtls_ct_uint_eq(
|
||||
(mbedtls_ct_uint_t) status,
|
||||
(mbedtls_ct_uint_t) PSA_ERROR_BUFFER_TOO_SMALL);
|
||||
status = mbedtls_ct_error_if(bad_padding, 0, status);
|
||||
status = mbedtls_ct_error_if(large_msg, 0, status);
|
||||
/* 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 = mbedtls_ct_error_if(bad_padding,
|
||||
MBEDTLS_ERR_RSA_INVALID_PADDING, ret);
|
||||
ret = mbedtls_ct_error_if(large_msg,
|
||||
MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, ret);
|
||||
ret |= problem;
|
||||
|
||||
cleanup:
|
||||
mbedtls_zeroize_and_free(buf, buf_size);
|
||||
|
||||
+13
-19
@@ -653,28 +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)
|
||||
int ret = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(
|
||||
int combined_ret = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(
|
||||
rsa, mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE,
|
||||
output_length, input, output, output_size);
|
||||
|
||||
/* We want to convert ret into a psa status without allowing an
|
||||
* attacker to distinguish between 0, invalid padding, or buffer too
|
||||
* small. (It's OK if the attacker distinguishes between one of the
|
||||
* above three and other status such as out of memory.) Since
|
||||
* mbedtls_to_psa_error() is leaky, hide the difference from it. */
|
||||
mbedtls_ct_condition_t bad_padding = mbedtls_ct_uint_eq(
|
||||
(mbedtls_ct_uint_t) ret,
|
||||
(mbedtls_ct_uint_t) MBEDTLS_ERR_RSA_INVALID_PADDING);
|
||||
mbedtls_ct_condition_t large_msg = mbedtls_ct_uint_eq(
|
||||
(mbedtls_ct_uint_t) ret,
|
||||
(mbedtls_ct_uint_t) MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE);
|
||||
ret = mbedtls_ct_error_if(bad_padding, 0, ret);
|
||||
ret = mbedtls_ct_error_if(large_msg, 0, ret);
|
||||
status = mbedtls_to_psa_error(ret);
|
||||
status = mbedtls_ct_error_if(bad_padding,
|
||||
PSA_ERROR_INVALID_PADDING, status);
|
||||
status = mbedtls_ct_error_if(large_msg,
|
||||
PSA_ERROR_BUFFER_TOO_SMALL, status);
|
||||
/* 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 */
|
||||
|
||||
@@ -542,6 +542,32 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_ct_rsaes_pkcs1_v15_unpadding(
|
||||
|
||||
#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,
|
||||
|
||||
@@ -155,4 +155,34 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_ct_rsaes_pkcs1_v15_unpadding(
|
||||
#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 */
|
||||
|
||||
@@ -52,6 +52,18 @@ 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
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -157,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,
|
||||
input,
|
||||
&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,
|
||||
input,
|
||||
&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,
|
||||
|
||||
Reference in New Issue
Block a user