mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-10-23 01:52:40 +03:00
Switch legacy cipher to constant-time invalid padding reporting
In internal `get_padding` functions, report whether the padding was invalid through a separate output parameter, rather than the return code. Take advantage of this to have `mbedtls_cipher_finish_padded()` be the easy path that just passes the `invalid_padding` through. Make `mbedtls_cipher_finish()` a wrapper around `mbedtls_cipher_finish_padded()` that converts the invalid-padding output into an error code. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
@@ -329,8 +329,15 @@ typedef struct mbedtls_cipher_context_t {
|
|||||||
/** Padding functions to use, if relevant for
|
/** Padding functions to use, if relevant for
|
||||||
* the specific cipher mode.
|
* the specific cipher mode.
|
||||||
*/
|
*/
|
||||||
void(*MBEDTLS_PRIVATE(add_padding))(unsigned char *output, size_t olen, size_t data_len);
|
void(*MBEDTLS_PRIVATE(add_padding))(unsigned char *output, size_t olen,
|
||||||
int(*MBEDTLS_PRIVATE(get_padding))(unsigned char *input, size_t ilen, size_t *data_len);
|
size_t data_len);
|
||||||
|
/* Report invalid-padding condition through the output parameter
|
||||||
|
* invalid_padding. To minimize changes in Mbed TLS 3.6, where this
|
||||||
|
* declaration is in a public header, use the public type size_t
|
||||||
|
* rather than the internal type mbedtls_ct_condition_t. */
|
||||||
|
int(*MBEDTLS_PRIVATE(get_padding))(unsigned char *input, size_t ilen,
|
||||||
|
size_t *data_len,
|
||||||
|
size_t *invalid_padding);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Buffer for input that has not been processed yet. */
|
/** Buffer for input that has not been processed yet. */
|
||||||
|
@@ -846,7 +846,8 @@ static void add_pkcs_padding(unsigned char *output, size_t output_len,
|
|||||||
*/
|
*/
|
||||||
MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input,
|
MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input,
|
||||||
size_t input_len,
|
size_t input_len,
|
||||||
size_t *data_len)
|
size_t *data_len,
|
||||||
|
size_t *invalid_padding)
|
||||||
{
|
{
|
||||||
size_t i, pad_idx;
|
size_t i, pad_idx;
|
||||||
unsigned char padding_len;
|
unsigned char padding_len;
|
||||||
@@ -872,7 +873,8 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input,
|
|||||||
/* If the padding is invalid, set the output length to 0 */
|
/* If the padding is invalid, set the output length to 0 */
|
||||||
*data_len = mbedtls_ct_if(bad, 0, input_len - padding_len);
|
*data_len = mbedtls_ct_if(bad, 0, input_len - padding_len);
|
||||||
|
|
||||||
return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING);
|
*invalid_padding = mbedtls_ct_size_if_else_0(bad, SIZE_MAX);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
|
#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
|
||||||
|
|
||||||
@@ -893,7 +895,7 @@ static void add_one_and_zeros_padding(unsigned char *output,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int get_one_and_zeros_padding(unsigned char *input, size_t input_len,
|
static int get_one_and_zeros_padding(unsigned char *input, size_t input_len,
|
||||||
size_t *data_len)
|
size_t *data_len, size_t *invalid_padding)
|
||||||
{
|
{
|
||||||
if (NULL == input || NULL == data_len) {
|
if (NULL == input || NULL == data_len) {
|
||||||
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
|
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
|
||||||
@@ -916,7 +918,8 @@ static int get_one_and_zeros_padding(unsigned char *input, size_t input_len,
|
|||||||
in_padding = mbedtls_ct_bool_and(in_padding, mbedtls_ct_bool_not(is_nonzero));
|
in_padding = mbedtls_ct_bool_and(in_padding, mbedtls_ct_bool_not(is_nonzero));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING);
|
*invalid_padding = mbedtls_ct_size_if_else_0(bad, SIZE_MAX);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
|
#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
|
||||||
|
|
||||||
@@ -937,7 +940,7 @@ static void add_zeros_and_len_padding(unsigned char *output,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int get_zeros_and_len_padding(unsigned char *input, size_t input_len,
|
static int get_zeros_and_len_padding(unsigned char *input, size_t input_len,
|
||||||
size_t *data_len)
|
size_t *data_len, size_t *invalid_padding)
|
||||||
{
|
{
|
||||||
size_t i, pad_idx;
|
size_t i, pad_idx;
|
||||||
unsigned char padding_len;
|
unsigned char padding_len;
|
||||||
@@ -963,7 +966,8 @@ static int get_zeros_and_len_padding(unsigned char *input, size_t input_len,
|
|||||||
bad = mbedtls_ct_bool_or(bad, nonzero_pad_byte);
|
bad = mbedtls_ct_bool_or(bad, nonzero_pad_byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING);
|
*invalid_padding = mbedtls_ct_size_if_else_0(bad, SIZE_MAX);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
|
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
|
||||||
|
|
||||||
@@ -978,7 +982,7 @@ static void add_zeros_padding(unsigned char *output,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int get_zeros_padding(unsigned char *input, size_t input_len,
|
static int get_zeros_padding(unsigned char *input, size_t input_len,
|
||||||
size_t *data_len)
|
size_t *data_len, size_t *invalid_padding)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
mbedtls_ct_condition_t done = MBEDTLS_CT_FALSE, prev_done;
|
mbedtls_ct_condition_t done = MBEDTLS_CT_FALSE, prev_done;
|
||||||
@@ -994,6 +998,7 @@ static int get_zeros_padding(unsigned char *input, size_t input_len,
|
|||||||
*data_len = mbedtls_ct_size_if(mbedtls_ct_bool_ne(done, prev_done), i, *data_len);
|
*data_len = mbedtls_ct_size_if(mbedtls_ct_bool_ne(done, prev_done), i, *data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*invalid_padding = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
|
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
|
||||||
@@ -1005,20 +1010,21 @@ static int get_zeros_padding(unsigned char *input, size_t input_len,
|
|||||||
* but a trivial get_padding function
|
* but a trivial get_padding function
|
||||||
*/
|
*/
|
||||||
static int get_no_padding(unsigned char *input, size_t input_len,
|
static int get_no_padding(unsigned char *input, size_t input_len,
|
||||||
size_t *data_len)
|
size_t *data_len, size_t *invalid_padding)
|
||||||
{
|
{
|
||||||
if (NULL == input || NULL == data_len) {
|
if (NULL == input || NULL == data_len) {
|
||||||
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
|
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
*data_len = input_len;
|
*data_len = input_len;
|
||||||
|
*invalid_padding = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
|
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
|
||||||
|
|
||||||
int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx,
|
int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx,
|
||||||
unsigned char *output, size_t *olen)
|
unsigned char *output, size_t *olen,
|
||||||
|
size_t *invalid_padding)
|
||||||
{
|
{
|
||||||
if (ctx->cipher_info == NULL) {
|
if (ctx->cipher_info == NULL) {
|
||||||
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
|
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
|
||||||
@@ -1034,6 +1040,7 @@ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx,
|
|||||||
#endif /* MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_DEPRECATED_REMOVED */
|
#endif /* MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_DEPRECATED_REMOVED */
|
||||||
|
|
||||||
*olen = 0;
|
*olen = 0;
|
||||||
|
*invalid_padding = 0;
|
||||||
|
|
||||||
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
|
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
|
||||||
/* CBC mode requires padding so we make sure a call to
|
/* CBC mode requires padding so we make sure a call to
|
||||||
@@ -1110,7 +1117,7 @@ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx,
|
|||||||
/* Set output size for decryption */
|
/* Set output size for decryption */
|
||||||
if (MBEDTLS_DECRYPT == ctx->operation) {
|
if (MBEDTLS_DECRYPT == ctx->operation) {
|
||||||
return ctx->get_padding(output, mbedtls_cipher_get_block_size(ctx),
|
return ctx->get_padding(output, mbedtls_cipher_get_block_size(ctx),
|
||||||
olen);
|
olen, invalid_padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set output size for encryption */
|
/* Set output size for encryption */
|
||||||
@@ -1124,20 +1131,16 @@ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx,
|
|||||||
return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
|
return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx,
|
int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx,
|
||||||
unsigned char *output, size_t *olen,
|
unsigned char *output, size_t *olen)
|
||||||
size_t *invalid_padding)
|
|
||||||
{
|
{
|
||||||
*invalid_padding = 0;
|
size_t invalid_padding = 0;
|
||||||
int ret = mbedtls_cipher_finish(ctx, output, olen);
|
int ret = mbedtls_cipher_finish_padded(ctx, output, olen,
|
||||||
#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) || \
|
&invalid_padding);
|
||||||
defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) || \
|
if (ret == 0) {
|
||||||
defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
|
ret = mbedtls_ct_error_if_else_0(invalid_padding,
|
||||||
if (ret == MBEDTLS_ERR_CIPHER_INVALID_PADDING) {
|
MBEDTLS_ERR_CIPHER_INVALID_PADDING);
|
||||||
ret = 0;
|
|
||||||
*invalid_padding = SIZE_MAX;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1410,14 +1413,17 @@ int mbedtls_cipher_crypt(mbedtls_cipher_context_t *ctx,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = mbedtls_cipher_finish(ctx, output + *olen,
|
size_t invalid_padding = 0;
|
||||||
&finish_olen)) != 0) {
|
if ((ret = mbedtls_cipher_finish_padded(ctx, output + *olen,
|
||||||
|
&finish_olen,
|
||||||
|
&invalid_padding)) != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
*olen += finish_olen;
|
*olen += finish_olen;
|
||||||
|
|
||||||
return 0;
|
ret = mbedtls_ct_error_if_else_0(invalid_padding,
|
||||||
|
MBEDTLS_ERR_CIPHER_INVALID_PADDING);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MBEDTLS_CIPHER_MODE_AEAD)
|
#if defined(MBEDTLS_CIPHER_MODE_AEAD)
|
||||||
|
@@ -20,7 +20,8 @@
|
|||||||
|
|
||||||
MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input,
|
MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input,
|
||||||
size_t input_len,
|
size_t input_len,
|
||||||
size_t *data_len);
|
size_t *data_len,
|
||||||
|
size_t *invalid_padding);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -1475,8 +1475,8 @@ exit:
|
|||||||
/* END_CASE */
|
/* END_CASE */
|
||||||
|
|
||||||
/* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_CBC */
|
/* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_CBC */
|
||||||
void check_padding(int pad_mode, data_t *input, int ret, int dlen_check
|
void check_padding(int pad_mode, data_t *input,
|
||||||
)
|
int expected_ret, int dlen_check)
|
||||||
{
|
{
|
||||||
mbedtls_cipher_info_t cipher_info;
|
mbedtls_cipher_info_t cipher_info;
|
||||||
mbedtls_cipher_context_t ctx;
|
mbedtls_cipher_context_t ctx;
|
||||||
@@ -1489,10 +1489,20 @@ void check_padding(int pad_mode, data_t *input, int ret, int dlen_check
|
|||||||
|
|
||||||
TEST_ASSERT(0 == mbedtls_cipher_set_padding_mode(&ctx, pad_mode));
|
TEST_ASSERT(0 == mbedtls_cipher_set_padding_mode(&ctx, pad_mode));
|
||||||
|
|
||||||
|
size_t invalid_padding = 42;
|
||||||
TEST_ASSERT(ret == ctx.get_padding(input->x, input->len, &dlen));
|
int ret = ctx.get_padding(input->x, input->len, &dlen, &invalid_padding);
|
||||||
if (0 == ret) {
|
switch (expected_ret) {
|
||||||
TEST_ASSERT(dlen == (size_t) dlen_check);
|
case 0:
|
||||||
|
TEST_EQUAL(ret, 0);
|
||||||
|
TEST_EQUAL(invalid_padding, 0);
|
||||||
|
TEST_EQUAL(dlen, dlen_check);
|
||||||
|
break;
|
||||||
|
case MBEDTLS_ERR_CIPHER_INVALID_PADDING:
|
||||||
|
TEST_EQUAL(ret, 0);
|
||||||
|
TEST_EQUAL(invalid_padding, SIZE_MAX);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TEST_EQUAL(ret, expected_ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* END_CASE */
|
/* END_CASE */
|
||||||
@@ -1585,14 +1595,27 @@ void get_pkcs_padding(data_t *decrypted_block, int exp_ret, int exp_len)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
size_t calculated_len;
|
size_t calculated_len;
|
||||||
|
size_t invalid_padding;
|
||||||
|
|
||||||
TEST_CF_SECRET(decrypted_block->x, decrypted_block->len);
|
TEST_CF_SECRET(decrypted_block->x, decrypted_block->len);
|
||||||
ret = mbedtls_get_pkcs_padding(decrypted_block->x, decrypted_block->len,
|
ret = mbedtls_get_pkcs_padding(decrypted_block->x, decrypted_block->len,
|
||||||
&calculated_len);
|
&calculated_len, &invalid_padding);
|
||||||
|
|
||||||
TEST_EQUAL(ret, exp_ret);
|
switch (exp_ret) {
|
||||||
if (exp_ret == 0) {
|
case 0:
|
||||||
TEST_EQUAL(calculated_len, exp_len);
|
TEST_EQUAL(ret, 0);
|
||||||
|
TEST_EQUAL(invalid_padding, 0);
|
||||||
|
TEST_EQUAL(calculated_len, exp_len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MBEDTLS_ERR_CIPHER_INVALID_PADDING:
|
||||||
|
TEST_EQUAL(ret, 0);
|
||||||
|
TEST_EQUAL(invalid_padding, ~(size_t) 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
TEST_EQUAL(ret, exp_ret);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* END_CASE */
|
/* END_CASE */
|
||||||
|
Reference in New Issue
Block a user