Merge pull request #1168 from gabor-mezei-arm/bp228_buffer_protection_for_cipher

[Backport] Buffer protection for cipher functions
This commit is contained in:
David Horstmann 2024-03-05 18:43:01 +00:00 committed by GitHub
commit 81a14e0dfd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 98 additions and 27 deletions

View File

@ -230,6 +230,8 @@ mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state =
uint8_t *output_copy_name = NULL; uint8_t *output_copy_name = NULL;
#define LOCAL_OUTPUT_ALLOC(output, length, output_copy) \ #define LOCAL_OUTPUT_ALLOC(output, length, output_copy) \
output_copy = output; output_copy = output;
#define LOCAL_OUTPUT_ALLOC_WITH_COPY(output, length, output_copy) \
output_copy = output;
#define LOCAL_OUTPUT_FREE(output, output_copy) \ #define LOCAL_OUTPUT_FREE(output, output_copy) \
output_copy = NULL; output_copy = NULL;
#endif /* MBEDTLS_PSA_COPY_CALLER_BUFFERS */ #endif /* MBEDTLS_PSA_COPY_CALLER_BUFFERS */
@ -3724,14 +3726,15 @@ psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation,
} }
psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation, psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation,
uint8_t *iv, uint8_t *iv_external,
size_t iv_size, size_t iv_size,
size_t *iv_length) size_t *iv_length)
{ {
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
uint8_t local_iv[PSA_CIPHER_IV_MAX_SIZE];
size_t default_iv_length = 0; size_t default_iv_length = 0;
LOCAL_OUTPUT_DECLARE(iv_external, iv);
if (operation->id == 0) { if (operation->id == 0) {
status = PSA_ERROR_BAD_STATE; status = PSA_ERROR_BAD_STATE;
goto exit; goto exit;
@ -3753,33 +3756,40 @@ psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation,
goto exit; goto exit;
} }
status = psa_generate_random_internal(local_iv, default_iv_length); LOCAL_OUTPUT_ALLOC(iv_external, default_iv_length, iv);
status = psa_generate_random_internal(iv, default_iv_length);
if (status != PSA_SUCCESS) { if (status != PSA_SUCCESS) {
goto exit; goto exit;
} }
status = psa_driver_wrapper_cipher_set_iv(operation, status = psa_driver_wrapper_cipher_set_iv(operation,
local_iv, default_iv_length); iv, default_iv_length);
exit: exit:
if (status == PSA_SUCCESS) { if (status == PSA_SUCCESS) {
memcpy(iv, local_iv, default_iv_length);
*iv_length = default_iv_length; *iv_length = default_iv_length;
operation->iv_set = 1; operation->iv_set = 1;
} else { } else {
*iv_length = 0; *iv_length = 0;
psa_cipher_abort(operation); psa_cipher_abort(operation);
if (iv != NULL) {
mbedtls_platform_zeroize(iv, default_iv_length);
}
} }
LOCAL_OUTPUT_FREE(iv_external, iv);
return status; return status;
} }
psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation, psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation,
const uint8_t *iv, const uint8_t *iv_external,
size_t iv_length) size_t iv_length)
{ {
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
LOCAL_INPUT_DECLARE(iv_external, iv);
if (operation->id == 0) { if (operation->id == 0) {
status = PSA_ERROR_BAD_STATE; status = PSA_ERROR_BAD_STATE;
goto exit; goto exit;
@ -3795,6 +3805,8 @@ psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation,
goto exit; goto exit;
} }
LOCAL_INPUT_ALLOC(iv_external, iv_length, iv);
status = psa_driver_wrapper_cipher_set_iv(operation, status = psa_driver_wrapper_cipher_set_iv(operation,
iv, iv,
iv_length); iv_length);
@ -3805,18 +3817,24 @@ exit:
} else { } else {
psa_cipher_abort(operation); psa_cipher_abort(operation);
} }
LOCAL_INPUT_FREE(iv_external, iv);
return status; return status;
} }
psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, psa_status_t psa_cipher_update(psa_cipher_operation_t *operation,
const uint8_t *input, const uint8_t *input_external,
size_t input_length, size_t input_length,
uint8_t *output, uint8_t *output_external,
size_t output_size, size_t output_size,
size_t *output_length) size_t *output_length)
{ {
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
LOCAL_INPUT_DECLARE(input_external, input);
LOCAL_OUTPUT_DECLARE(output_external, output);
if (operation->id == 0) { if (operation->id == 0) {
status = PSA_ERROR_BAD_STATE; status = PSA_ERROR_BAD_STATE;
goto exit; goto exit;
@ -3827,6 +3845,9 @@ psa_status_t psa_cipher_update(psa_cipher_operation_t *operation,
goto exit; goto exit;
} }
LOCAL_INPUT_ALLOC(input_external, input_length, input);
LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
status = psa_driver_wrapper_cipher_update(operation, status = psa_driver_wrapper_cipher_update(operation,
input, input,
input_length, input_length,
@ -3839,16 +3860,21 @@ exit:
psa_cipher_abort(operation); psa_cipher_abort(operation);
} }
LOCAL_INPUT_FREE(input_external, input);
LOCAL_OUTPUT_FREE(output_external, output);
return status; return status;
} }
psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation, psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation,
uint8_t *output, uint8_t *output_external,
size_t output_size, size_t output_size,
size_t *output_length) size_t *output_length)
{ {
psa_status_t status = PSA_ERROR_GENERIC_ERROR; psa_status_t status = PSA_ERROR_GENERIC_ERROR;
LOCAL_OUTPUT_DECLARE(output_external, output);
if (operation->id == 0) { if (operation->id == 0) {
status = PSA_ERROR_BAD_STATE; status = PSA_ERROR_BAD_STATE;
goto exit; goto exit;
@ -3859,6 +3885,8 @@ psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation,
goto exit; goto exit;
} }
LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
status = psa_driver_wrapper_cipher_finish(operation, status = psa_driver_wrapper_cipher_finish(operation,
output, output,
output_size, output_size,
@ -3866,13 +3894,15 @@ psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation,
exit: exit:
if (status == PSA_SUCCESS) { if (status == PSA_SUCCESS) {
return psa_cipher_abort(operation); status = psa_cipher_abort(operation);
} else { } else {
*output_length = 0; *output_length = 0;
(void) psa_cipher_abort(operation); (void) psa_cipher_abort(operation);
return status;
} }
LOCAL_OUTPUT_FREE(output_external, output);
return status;
} }
psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation) psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation)
@ -3911,9 +3941,6 @@ psa_status_t psa_cipher_encrypt(mbedtls_svc_key_id_t key,
LOCAL_INPUT_DECLARE(input_external, input); LOCAL_INPUT_DECLARE(input_external, input);
LOCAL_OUTPUT_DECLARE(output_external, output); LOCAL_OUTPUT_DECLARE(output_external, output);
LOCAL_INPUT_ALLOC(input_external, input_length, input);
LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
if (!PSA_ALG_IS_CIPHER(alg)) { if (!PSA_ALG_IS_CIPHER(alg)) {
status = PSA_ERROR_INVALID_ARGUMENT; status = PSA_ERROR_INVALID_ARGUMENT;
goto exit; goto exit;
@ -3948,6 +3975,9 @@ psa_status_t psa_cipher_encrypt(mbedtls_svc_key_id_t key,
} }
} }
LOCAL_INPUT_ALLOC(input_external, input_length, input);
LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
status = psa_driver_wrapper_cipher_encrypt( status = psa_driver_wrapper_cipher_encrypt(
&attributes, slot->key.data, slot->key.bytes, &attributes, slot->key.data, slot->key.bytes,
alg, local_iv, default_iv_length, input, input_length, alg, local_iv, default_iv_length, input, input_length,
@ -3977,9 +4007,9 @@ exit:
psa_status_t psa_cipher_decrypt(mbedtls_svc_key_id_t key, psa_status_t psa_cipher_decrypt(mbedtls_svc_key_id_t key,
psa_algorithm_t alg, psa_algorithm_t alg,
const uint8_t *input, const uint8_t *input_external,
size_t input_length, size_t input_length,
uint8_t *output, uint8_t *output_external,
size_t output_size, size_t output_size,
size_t *output_length) size_t *output_length)
{ {
@ -3988,6 +4018,9 @@ psa_status_t psa_cipher_decrypt(mbedtls_svc_key_id_t key,
psa_key_attributes_t attributes; psa_key_attributes_t attributes;
psa_key_slot_t *slot = NULL; psa_key_slot_t *slot = NULL;
LOCAL_INPUT_DECLARE(input_external, input);
LOCAL_OUTPUT_DECLARE(output_external, output);
if (!PSA_ALG_IS_CIPHER(alg)) { if (!PSA_ALG_IS_CIPHER(alg)) {
status = PSA_ERROR_INVALID_ARGUMENT; status = PSA_ERROR_INVALID_ARGUMENT;
goto exit; goto exit;
@ -4009,6 +4042,9 @@ psa_status_t psa_cipher_decrypt(mbedtls_svc_key_id_t key,
goto exit; goto exit;
} }
LOCAL_INPUT_ALLOC(input_external, input_length, input);
LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
status = psa_driver_wrapper_cipher_decrypt( status = psa_driver_wrapper_cipher_decrypt(
&attributes, slot->key.data, slot->key.bytes, &attributes, slot->key.data, slot->key.bytes,
alg, input, input_length, alg, input, input_length,
@ -4024,6 +4060,9 @@ exit:
*output_length = 0; *output_length = 0;
} }
LOCAL_INPUT_FREE(input_external, input);
LOCAL_OUTPUT_FREE(output_external, output);
return status; return status;
} }

View File

@ -402,7 +402,11 @@ psa_status_t mbedtls_psa_cipher_update(
output_length); output_length);
} else } else
#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING */ #endif /* MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING */
{ if (input_length == 0) {
/* There is no input, nothing to be done */
*output_length = 0;
status = PSA_SUCCESS;
} else {
status = mbedtls_to_psa_error( status = mbedtls_to_psa_error(
mbedtls_cipher_update(&operation->ctx.cipher, input, mbedtls_cipher_update(&operation->ctx.cipher, input,
input_length, output, output_length)); input_length, output, output_length));

View File

@ -153,7 +153,9 @@ class PSAWrapperGenerator(c_wrapper_generator.Base):
#pylint: disable=too-many-return-statements #pylint: disable=too-many-return-statements
if function_name.startswith('psa_aead'): if function_name.startswith('psa_aead'):
return True return True
if function_name == 'psa_cipher_encrypt': if function_name in {'psa_cipher_encrypt', 'psa_cipher_decrypt',
'psa_cipher_update', 'psa_cipher_finish',
'psa_cipher_generate_iv', 'psa_cipher_set_iv'}:
return True return True
if function_name in ('psa_key_derivation_output_bytes', if function_name in ('psa_key_derivation_output_bytes',
'psa_key_derivation_input_bytes'): 'psa_key_derivation_input_bytes'):

View File

@ -182,7 +182,15 @@ psa_status_t mbedtls_test_wrap_psa_cipher_decrypt(
size_t arg5_output_size, size_t arg5_output_size,
size_t *arg6_output_length) size_t *arg6_output_length)
{ {
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
MBEDTLS_TEST_MEMORY_POISON(arg4_output, arg5_output_size);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
psa_status_t status = (psa_cipher_decrypt)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_output, arg5_output_size, arg6_output_length); psa_status_t status = (psa_cipher_decrypt)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_output, arg5_output_size, arg6_output_length);
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
MBEDTLS_TEST_MEMORY_UNPOISON(arg4_output, arg5_output_size);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
return status; return status;
} }
@ -235,7 +243,13 @@ psa_status_t mbedtls_test_wrap_psa_cipher_finish(
size_t arg2_output_size, size_t arg2_output_size,
size_t *arg3_output_length) size_t *arg3_output_length)
{ {
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_POISON(arg1_output, arg2_output_size);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
psa_status_t status = (psa_cipher_finish)(arg0_operation, arg1_output, arg2_output_size, arg3_output_length); psa_status_t status = (psa_cipher_finish)(arg0_operation, arg1_output, arg2_output_size, arg3_output_length);
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_UNPOISON(arg1_output, arg2_output_size);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
return status; return status;
} }
@ -246,7 +260,13 @@ psa_status_t mbedtls_test_wrap_psa_cipher_generate_iv(
size_t arg2_iv_size, size_t arg2_iv_size,
size_t *arg3_iv_length) size_t *arg3_iv_length)
{ {
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_POISON(arg1_iv, arg2_iv_size);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
psa_status_t status = (psa_cipher_generate_iv)(arg0_operation, arg1_iv, arg2_iv_size, arg3_iv_length); psa_status_t status = (psa_cipher_generate_iv)(arg0_operation, arg1_iv, arg2_iv_size, arg3_iv_length);
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_UNPOISON(arg1_iv, arg2_iv_size);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
return status; return status;
} }
@ -256,7 +276,13 @@ psa_status_t mbedtls_test_wrap_psa_cipher_set_iv(
const uint8_t *arg1_iv, const uint8_t *arg1_iv,
size_t arg2_iv_length) size_t arg2_iv_length)
{ {
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_POISON(arg1_iv, arg2_iv_length);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
psa_status_t status = (psa_cipher_set_iv)(arg0_operation, arg1_iv, arg2_iv_length); psa_status_t status = (psa_cipher_set_iv)(arg0_operation, arg1_iv, arg2_iv_length);
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_UNPOISON(arg1_iv, arg2_iv_length);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
return status; return status;
} }
@ -269,7 +295,15 @@ psa_status_t mbedtls_test_wrap_psa_cipher_update(
size_t arg4_output_size, size_t arg4_output_size,
size_t *arg5_output_length) size_t *arg5_output_length)
{ {
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_POISON(arg1_input, arg2_input_length);
MBEDTLS_TEST_MEMORY_POISON(arg3_output, arg4_output_size);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
psa_status_t status = (psa_cipher_update)(arg0_operation, arg1_input, arg2_input_length, arg3_output, arg4_output_size, arg5_output_length); psa_status_t status = (psa_cipher_update)(arg0_operation, arg1_input, arg2_input_length, arg3_output, arg4_output_size, arg5_output_length);
#if defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS)
MBEDTLS_TEST_MEMORY_UNPOISON(arg1_input, arg2_input_length);
MBEDTLS_TEST_MEMORY_UNPOISON(arg3_output, arg4_output_size);
#endif /* defined(MBEDTLS_PSA_COPY_CALLER_BUFFERS) */
return status; return status;
} }

View File

@ -983,14 +983,6 @@ void cipher_entry_points(int alg_arg, int key_type_arg,
/* When generating the IV fails, it should call abort too */ /* When generating the IV fails, it should call abort too */
TEST_EQUAL(mbedtls_test_driver_cipher_hooks.hits, 2); TEST_EQUAL(mbedtls_test_driver_cipher_hooks.hits, 2);
TEST_EQUAL(status, mbedtls_test_driver_cipher_hooks.forced_status); TEST_EQUAL(status, mbedtls_test_driver_cipher_hooks.forced_status);
/*
* Check that the output buffer is still in the same state.
* This will fail if the output buffer is used by the core to pass the IV
* it generated to the driver (and is not restored).
*/
for (size_t i = 0; i < 16; i++) {
TEST_EQUAL(output[i], 0xa5);
}
/* Failure should prevent further operations from executing on the driver */ /* Failure should prevent further operations from executing on the driver */
mbedtls_test_driver_cipher_hooks.hits = 0; mbedtls_test_driver_cipher_hooks.hits = 0;
status = psa_cipher_update(&operation, status = psa_cipher_update(&operation,