From 89167cb597c58dd6b9516c6701ab0dc86496adb8 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 8 Jul 2018 20:12:23 +0200 Subject: [PATCH] Split psa_mac_setup -> psa_mac_{sign,verify}_setup Make function names for multipart operations more consistent (MAC setup edition). Split psa_mac_setup into two functions psa_mac_sign_setup and psa_mac_verify_setup. These functions behave identically except that they require different usage flags on the key. The goal of the split is to enforce the key policy during setup rather than at the end of the operation (which was a bit of a hack). In psa_mac_sign_finish and psa_mac_verify_finish, if the operation is of the wrong type, abort the operation before returning BAD_STATE. --- include/psa/crypto.h | 80 +++++++++++++++++---- include/psa/crypto_struct.h | 3 +- library/psa_crypto.c | 67 ++++++++++------- tests/suites/test_suite_psa_crypto.function | 23 +++--- 4 files changed, 116 insertions(+), 57 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 957385916..98573c90f 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -1333,30 +1333,32 @@ psa_status_t psa_hash_abort(psa_hash_operation_t *operation); * as directed by the documentation of a specific implementation. */ typedef struct psa_mac_operation_s psa_mac_operation_t; -/** Start a multipart MAC operation. +/** Start a multipart MAC calculation operation. * - * The sequence of operations to calculate a MAC (message authentication code) - * is as follows: + * This function sets up the calculation of the MAC + * (message authentication code) of a byte string. + * To verify the MAC of a message against an + * expected value, use psa_mac_verify_setup() instead. + * + * The sequence of operations to calculate a MAC is as follows: * -# Allocate an operation object which will be passed to all the functions * listed here. - * -# Call psa_mac_start() to specify the algorithm and key. + * -# Call psa_mac_sign_setup() to specify the algorithm and key. * The key remains associated with the operation even if the content * of the key slot changes. * -# Call psa_mac_update() zero, one or more times, passing a fragment * of the message each time. The MAC that is calculated is the MAC * of the concatenation of these messages in order. - * -# To calculate the MAC, call psa_mac_sign_finish(). - * To compare the MAC with an expected value, call psa_mac_verify_finish(). + * -# At the end of the message, call psa_mac_sign_finish() to finish + * calculating the MAC value and retrieve it. * * The application may call psa_mac_abort() at any time after the operation - * has been initialized with psa_mac_start(). + * has been initialized with psa_mac_sign_setup(). * - * After a successful call to psa_mac_start(), the application must - * eventually terminate the operation. The following events terminate an - * operation: + * After a successful call to psa_mac_sign_setup(), the application must + * eventually terminate the operation through one of the following methods: * - A failed call to psa_mac_update(). - * - A call to psa_mac_sign_finish(), psa_mac_verify_finish() or - * psa_mac_abort(). + * - A call to psa_mac_sign_finish() or psa_mac_abort(). * * \param operation The operation object to use. * \param key Slot containing the key to use for the operation. @@ -1376,9 +1378,57 @@ typedef struct psa_mac_operation_s psa_mac_operation_t; * \retval PSA_ERROR_HARDWARE_FAILURE * \retval PSA_ERROR_TAMPERING_DETECTED */ -psa_status_t psa_mac_start(psa_mac_operation_t *operation, - psa_key_slot_t key, - psa_algorithm_t alg); +psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg); + +/** Start a multipart MAC verification operation. + * + * This function sets up the verification of the MAC + * (message authentication code) of a byte string against an expected value. + * + * The sequence of operations to verify a MAC is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Call psa_mac_verify_setup() to specify the algorithm and key. + * The key remains associated with the operation even if the content + * of the key slot changes. + * -# Call psa_mac_update() zero, one or more times, passing a fragment + * of the message each time. The MAC that is calculated is the MAC + * of the concatenation of these messages in order. + * -# At the end of the message, call psa_mac_verify_finish() to finish + * calculating the actual MAC of the message and verify it against + * the expected value. + * + * The application may call psa_mac_abort() at any time after the operation + * has been initialized with psa_mac_verify_setup(). + * + * After a successful call to psa_mac_verify_setup(), the application must + * eventually terminate the operation through one of the following methods: + * - A failed call to psa_mac_update(). + * - A call to psa_mac_verify_finish() or psa_mac_abort(). + * + * \param operation The operation object to use. + * \param key Slot containing the key to use for the operation. + * \param alg The MAC algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_MAC(alg) is true). + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_NOT_PERMITTED + * \retval PSA_ERROR_INVALID_ARGUMENT + * \c key is not compatible with \c alg. + * \retval PSA_ERROR_NOT_SUPPORTED + * \c alg is not supported or is not a MAC algorithm. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg); psa_status_t psa_mac_update(psa_mac_operation_t *operation, const uint8_t *input, diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index b981f23c7..85c997485 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -102,8 +102,7 @@ struct psa_mac_operation_s int iv_required : 1; int iv_set : 1; int has_input : 1; - int key_usage_sign : 1; - int key_usage_verify : 1; + int is_sign : 1; uint8_t mac_size; union { diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 4c42d61e0..61eef45ca 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -1296,8 +1296,7 @@ static psa_status_t psa_mac_init( psa_mac_operation_t *operation, operation->iv_set = 0; operation->iv_required = 0; operation->has_input = 0; - operation->key_usage_sign = 0; - operation->key_usage_verify = 0; + operation->is_sign = 0; #if defined(MBEDTLS_CMAC_C) if( alg == PSA_ALG_CMAC ) @@ -1367,14 +1366,13 @@ psa_status_t psa_mac_abort( psa_mac_operation_t *operation ) operation->iv_set = 0; operation->iv_required = 0; operation->has_input = 0; - operation->key_usage_sign = 0; - operation->key_usage_verify = 0; + operation->is_sign = 0; return( PSA_SUCCESS ); } #if defined(MBEDTLS_CMAC_C) -static int psa_cmac_start( psa_mac_operation_t *operation, +static int psa_cmac_setup( psa_mac_operation_t *operation, size_t key_bits, key_slot_t *slot, const mbedtls_cipher_info_t *cipher_info ) @@ -1395,7 +1393,7 @@ static int psa_cmac_start( psa_mac_operation_t *operation, #endif /* MBEDTLS_CMAC_C */ #if defined(MBEDTLS_MD_C) -static int psa_hmac_start( psa_mac_operation_t *operation, +static int psa_hmac_setup( psa_mac_operation_t *operation, psa_key_type_t key_type, key_slot_t *slot, psa_algorithm_t alg ) @@ -1457,39 +1455,34 @@ cleanup: mbedtls_zeroize( ipad, key_length ); /* opad is in the context. It needs to stay in memory if this function * succeeds, and it will be wiped by psa_mac_abort() called from - * psa_mac_start in the error case. */ + * psa_mac_setup in the error case. */ return( status ); } #endif /* MBEDTLS_MD_C */ -psa_status_t psa_mac_start( psa_mac_operation_t *operation, - psa_key_slot_t key, - psa_algorithm_t alg ) +static psa_status_t psa_mac_setup( psa_mac_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg, + int is_sign ) { psa_status_t status; key_slot_t *slot; size_t key_bits; + psa_key_usage_t usage = + is_sign ? PSA_KEY_USAGE_SIGN : PSA_KEY_USAGE_VERIFY; const mbedtls_cipher_info_t *cipher_info = NULL; status = psa_mac_init( operation, alg ); if( status != PSA_SUCCESS ) return( status ); + if( is_sign ) + operation->is_sign = 1; - status = psa_get_key_from_slot( key, &slot, 0, alg ); + status = psa_get_key_from_slot( key, &slot, usage, alg ); if( status != PSA_SUCCESS ) return( status ); - /* Since this function is called identically for a sign or verify - * operation, we don't know yet whether the operation is permitted. - * Store the part of the key policy that we can't check in the - * operation structure. psa_mac_sign_finish() or psa_mac_verify_finish() - * will check that remaining part. */ - if( ( slot->policy.usage & PSA_KEY_USAGE_SIGN ) != 0 ) - operation->key_usage_sign = 1; - if( ( slot->policy.usage & PSA_KEY_USAGE_VERIFY ) != 0 ) - operation->key_usage_verify = 1; - key_bits = psa_get_key_bits( slot ); if( ! PSA_ALG_IS_HMAC( alg ) ) @@ -1504,7 +1497,7 @@ psa_status_t psa_mac_start( psa_mac_operation_t *operation, { #if defined(MBEDTLS_CMAC_C) case PSA_ALG_CMAC: - status = mbedtls_to_psa_error( psa_cmac_start( operation, + status = mbedtls_to_psa_error( psa_cmac_setup( operation, key_bits, slot, cipher_info ) ); @@ -1513,7 +1506,7 @@ psa_status_t psa_mac_start( psa_mac_operation_t *operation, default: #if defined(MBEDTLS_MD_C) if( PSA_ALG_IS_HMAC( alg ) ) - status = psa_hmac_start( operation, slot->type, slot, alg ); + status = psa_hmac_setup( operation, slot->type, slot, alg ); else #endif /* MBEDTLS_MD_C */ return( PSA_ERROR_NOT_SUPPORTED ); @@ -1532,6 +1525,20 @@ psa_status_t psa_mac_start( psa_mac_operation_t *operation, return( status ); } +psa_status_t psa_mac_sign_setup( psa_mac_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg ) +{ + return( psa_mac_setup( operation, key, alg, 1 ) ); +} + +psa_status_t psa_mac_verify_setup( psa_mac_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg ) +{ + return( psa_mac_setup( operation, key, alg, 0 ) ); +} + psa_status_t psa_mac_update( psa_mac_operation_t *operation, const uint8_t *input, size_t input_length ) @@ -1676,8 +1683,11 @@ psa_status_t psa_mac_sign_finish( psa_mac_operation_t *operation, size_t mac_size, size_t *mac_length ) { - if( ! operation->key_usage_sign ) - return( PSA_ERROR_NOT_PERMITTED ); + if( ! operation->is_sign ) + { + psa_mac_abort( operation ); + return( PSA_ERROR_BAD_STATE ); + } return( psa_mac_finish_internal( operation, mac, mac_size, mac_length ) ); @@ -1691,8 +1701,11 @@ psa_status_t psa_mac_verify_finish( psa_mac_operation_t *operation, size_t actual_mac_length; psa_status_t status; - if( ! operation->key_usage_verify ) - return( PSA_ERROR_NOT_PERMITTED ); + if( operation->is_sign ) + { + psa_mac_abort( operation ); + return( PSA_ERROR_BAD_STATE ); + } status = psa_mac_finish_internal( operation, actual_mac, sizeof( actual_mac ), diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index fcab07bc3..3a03a76bf 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -138,7 +138,8 @@ static int exercise_mac_key( psa_key_slot_t key, if( usage & PSA_KEY_USAGE_SIGN ) { - TEST_ASSERT( psa_mac_start( &operation, key, alg ) == PSA_SUCCESS ); + TEST_ASSERT( psa_mac_sign_setup( &operation, + key, alg ) == PSA_SUCCESS ); TEST_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) == PSA_SUCCESS ); TEST_ASSERT( psa_mac_sign_finish( &operation, @@ -152,7 +153,8 @@ static int exercise_mac_key( psa_key_slot_t key, ( usage & PSA_KEY_USAGE_SIGN ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE ); - TEST_ASSERT( psa_mac_start( &operation, key, alg ) == PSA_SUCCESS ); + TEST_ASSERT( psa_mac_verify_setup( &operation, + key, alg ) == PSA_SUCCESS ); TEST_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) == PSA_SUCCESS ); TEST_ASSERT( psa_mac_verify_finish( &operation, @@ -736,7 +738,6 @@ void mac_key_policy( int policy_usage, psa_mac_operation_t operation; psa_status_t status; unsigned char mac[PSA_MAC_MAX_SIZE]; - size_t output_length; TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); @@ -747,10 +748,7 @@ void mac_key_policy( int policy_usage, TEST_ASSERT( psa_import_key( key_slot, key_type, key_data->x, key_data->len ) == PSA_SUCCESS ); - status = psa_mac_start( &operation, key_slot, exercise_alg ); - if( status == PSA_SUCCESS ) - status = psa_mac_sign_finish( &operation, - mac, sizeof( mac ), &output_length ); + status = psa_mac_sign_setup( &operation, key_slot, exercise_alg ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_SIGN ) != 0 ) TEST_ASSERT( status == PSA_SUCCESS ); @@ -759,12 +757,10 @@ void mac_key_policy( int policy_usage, psa_mac_abort( &operation ); memset( mac, 0, sizeof( mac ) ); - status = psa_mac_start( &operation, key_slot, exercise_alg ); - if( status == PSA_SUCCESS ) - status = psa_mac_verify_finish( &operation, mac, sizeof( mac ) ); + status = psa_mac_verify_setup( &operation, key_slot, exercise_alg ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_VERIFY ) != 0 ) - TEST_ASSERT( status == PSA_ERROR_INVALID_SIGNATURE ); + TEST_ASSERT( status == PSA_SUCCESS ); else TEST_ASSERT( status == PSA_ERROR_NOT_PERMITTED ); @@ -1155,7 +1151,7 @@ void mac_setup( int key_type_arg, TEST_ASSERT( psa_import_key( key_slot, key_type, key->x, key->len ) == PSA_SUCCESS ); - status = psa_mac_start( &operation, key_slot, alg ); + status = psa_mac_sign_setup( &operation, key_slot, alg ); psa_mac_abort( &operation ); TEST_ASSERT( status == expected_status ); @@ -1196,7 +1192,8 @@ void mac_verify( int key_type_arg, TEST_ASSERT( psa_import_key( key_slot, key_type, key->x, key->len ) == PSA_SUCCESS ); - TEST_ASSERT( psa_mac_start( &operation, key_slot, alg ) == PSA_SUCCESS ); + TEST_ASSERT( psa_mac_verify_setup( &operation, + key_slot, alg ) == PSA_SUCCESS ); TEST_ASSERT( psa_destroy_key( key_slot ) == PSA_SUCCESS ); TEST_ASSERT( psa_mac_update( &operation, input->x, input->len ) == PSA_SUCCESS );