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.
This commit is contained in:
Gilles Peskine 2018-07-08 20:12:23 +02:00 committed by itayzafrir
parent acd4be36fa
commit 89167cb597
4 changed files with 116 additions and 57 deletions

View file

@ -1333,30 +1333,32 @@ psa_status_t psa_hash_abort(psa_hash_operation_t *operation);
* as directed by the documentation of a specific implementation. */ * as directed by the documentation of a specific implementation. */
typedef struct psa_mac_operation_s psa_mac_operation_t; 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) * This function sets up the calculation of the MAC
* is as follows: * (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 * -# Allocate an operation object which will be passed to all the functions
* listed here. * 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 * The key remains associated with the operation even if the content
* of the key slot changes. * of the key slot changes.
* -# Call psa_mac_update() zero, one or more times, passing a fragment * -# 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 message each time. The MAC that is calculated is the MAC
* of the concatenation of these messages in order. * of the concatenation of these messages in order.
* -# To calculate the MAC, call psa_mac_sign_finish(). * -# At the end of the message, call psa_mac_sign_finish() to finish
* To compare the MAC with an expected value, call psa_mac_verify_finish(). * calculating the MAC value and retrieve it.
* *
* The application may call psa_mac_abort() at any time after the operation * 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 * After a successful call to psa_mac_sign_setup(), the application must
* eventually terminate the operation. The following events terminate an * eventually terminate the operation through one of the following methods:
* operation:
* - A failed call to psa_mac_update(). * - A failed call to psa_mac_update().
* - A call to psa_mac_sign_finish(), psa_mac_verify_finish() or * - A call to psa_mac_sign_finish() or psa_mac_abort().
* psa_mac_abort().
* *
* \param operation The operation object to use. * \param operation The operation object to use.
* \param key Slot containing the key to use for the operation. * \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_HARDWARE_FAILURE
* \retval PSA_ERROR_TAMPERING_DETECTED * \retval PSA_ERROR_TAMPERING_DETECTED
*/ */
psa_status_t psa_mac_start(psa_mac_operation_t *operation, psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation,
psa_key_slot_t key, psa_key_slot_t key,
psa_algorithm_t alg); 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, psa_status_t psa_mac_update(psa_mac_operation_t *operation,
const uint8_t *input, const uint8_t *input,

View file

@ -102,8 +102,7 @@ struct psa_mac_operation_s
int iv_required : 1; int iv_required : 1;
int iv_set : 1; int iv_set : 1;
int has_input : 1; int has_input : 1;
int key_usage_sign : 1; int is_sign : 1;
int key_usage_verify : 1;
uint8_t mac_size; uint8_t mac_size;
union union
{ {

View file

@ -1296,8 +1296,7 @@ static psa_status_t psa_mac_init( psa_mac_operation_t *operation,
operation->iv_set = 0; operation->iv_set = 0;
operation->iv_required = 0; operation->iv_required = 0;
operation->has_input = 0; operation->has_input = 0;
operation->key_usage_sign = 0; operation->is_sign = 0;
operation->key_usage_verify = 0;
#if defined(MBEDTLS_CMAC_C) #if defined(MBEDTLS_CMAC_C)
if( alg == PSA_ALG_CMAC ) 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_set = 0;
operation->iv_required = 0; operation->iv_required = 0;
operation->has_input = 0; operation->has_input = 0;
operation->key_usage_sign = 0; operation->is_sign = 0;
operation->key_usage_verify = 0;
return( PSA_SUCCESS ); return( PSA_SUCCESS );
} }
#if defined(MBEDTLS_CMAC_C) #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, size_t key_bits,
key_slot_t *slot, key_slot_t *slot,
const mbedtls_cipher_info_t *cipher_info ) 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 */ #endif /* MBEDTLS_CMAC_C */
#if defined(MBEDTLS_MD_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, psa_key_type_t key_type,
key_slot_t *slot, key_slot_t *slot,
psa_algorithm_t alg ) psa_algorithm_t alg )
@ -1457,39 +1455,34 @@ cleanup:
mbedtls_zeroize( ipad, key_length ); mbedtls_zeroize( ipad, key_length );
/* opad is in the context. It needs to stay in memory if this function /* 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 * 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 ); return( status );
} }
#endif /* MBEDTLS_MD_C */ #endif /* MBEDTLS_MD_C */
psa_status_t psa_mac_start( psa_mac_operation_t *operation, static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
psa_key_slot_t key, psa_key_slot_t key,
psa_algorithm_t alg ) psa_algorithm_t alg,
int is_sign )
{ {
psa_status_t status; psa_status_t status;
key_slot_t *slot; key_slot_t *slot;
size_t key_bits; 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; const mbedtls_cipher_info_t *cipher_info = NULL;
status = psa_mac_init( operation, alg ); status = psa_mac_init( operation, alg );
if( status != PSA_SUCCESS ) if( status != PSA_SUCCESS )
return( status ); 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 ) if( status != PSA_SUCCESS )
return( status ); 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 ); key_bits = psa_get_key_bits( slot );
if( ! PSA_ALG_IS_HMAC( alg ) ) 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) #if defined(MBEDTLS_CMAC_C)
case PSA_ALG_CMAC: case PSA_ALG_CMAC:
status = mbedtls_to_psa_error( psa_cmac_start( operation, status = mbedtls_to_psa_error( psa_cmac_setup( operation,
key_bits, key_bits,
slot, slot,
cipher_info ) ); cipher_info ) );
@ -1513,7 +1506,7 @@ psa_status_t psa_mac_start( psa_mac_operation_t *operation,
default: default:
#if defined(MBEDTLS_MD_C) #if defined(MBEDTLS_MD_C)
if( PSA_ALG_IS_HMAC( alg ) ) 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 else
#endif /* MBEDTLS_MD_C */ #endif /* MBEDTLS_MD_C */
return( PSA_ERROR_NOT_SUPPORTED ); return( PSA_ERROR_NOT_SUPPORTED );
@ -1532,6 +1525,20 @@ psa_status_t psa_mac_start( psa_mac_operation_t *operation,
return( status ); 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, psa_status_t psa_mac_update( psa_mac_operation_t *operation,
const uint8_t *input, const uint8_t *input,
size_t input_length ) 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_size,
size_t *mac_length ) size_t *mac_length )
{ {
if( ! operation->key_usage_sign ) if( ! operation->is_sign )
return( PSA_ERROR_NOT_PERMITTED ); {
psa_mac_abort( operation );
return( PSA_ERROR_BAD_STATE );
}
return( psa_mac_finish_internal( operation, mac, return( psa_mac_finish_internal( operation, mac,
mac_size, mac_length ) ); 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; size_t actual_mac_length;
psa_status_t status; psa_status_t status;
if( ! operation->key_usage_verify ) if( operation->is_sign )
return( PSA_ERROR_NOT_PERMITTED ); {
psa_mac_abort( operation );
return( PSA_ERROR_BAD_STATE );
}
status = psa_mac_finish_internal( operation, status = psa_mac_finish_internal( operation,
actual_mac, sizeof( actual_mac ), actual_mac, sizeof( actual_mac ),

View file

@ -138,7 +138,8 @@ static int exercise_mac_key( psa_key_slot_t key,
if( usage & PSA_KEY_USAGE_SIGN ) 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, TEST_ASSERT( psa_mac_update( &operation,
input, sizeof( input ) ) == PSA_SUCCESS ); input, sizeof( input ) ) == PSA_SUCCESS );
TEST_ASSERT( psa_mac_sign_finish( &operation, 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 ? ( usage & PSA_KEY_USAGE_SIGN ?
PSA_SUCCESS : PSA_SUCCESS :
PSA_ERROR_INVALID_SIGNATURE ); 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, TEST_ASSERT( psa_mac_update( &operation,
input, sizeof( input ) ) == PSA_SUCCESS ); input, sizeof( input ) ) == PSA_SUCCESS );
TEST_ASSERT( psa_mac_verify_finish( &operation, TEST_ASSERT( psa_mac_verify_finish( &operation,
@ -736,7 +738,6 @@ void mac_key_policy( int policy_usage,
psa_mac_operation_t operation; psa_mac_operation_t operation;
psa_status_t status; psa_status_t status;
unsigned char mac[PSA_MAC_MAX_SIZE]; unsigned char mac[PSA_MAC_MAX_SIZE];
size_t output_length;
TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); 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, TEST_ASSERT( psa_import_key( key_slot, key_type,
key_data->x, key_data->len ) == PSA_SUCCESS ); key_data->x, key_data->len ) == PSA_SUCCESS );
status = psa_mac_start( &operation, key_slot, exercise_alg ); status = psa_mac_sign_setup( &operation, key_slot, exercise_alg );
if( status == PSA_SUCCESS )
status = psa_mac_sign_finish( &operation,
mac, sizeof( mac ), &output_length );
if( policy_alg == exercise_alg && if( policy_alg == exercise_alg &&
( policy_usage & PSA_KEY_USAGE_SIGN ) != 0 ) ( policy_usage & PSA_KEY_USAGE_SIGN ) != 0 )
TEST_ASSERT( status == PSA_SUCCESS ); TEST_ASSERT( status == PSA_SUCCESS );
@ -759,12 +757,10 @@ void mac_key_policy( int policy_usage,
psa_mac_abort( &operation ); psa_mac_abort( &operation );
memset( mac, 0, sizeof( mac ) ); memset( mac, 0, sizeof( mac ) );
status = psa_mac_start( &operation, key_slot, exercise_alg ); status = psa_mac_verify_setup( &operation, key_slot, exercise_alg );
if( status == PSA_SUCCESS )
status = psa_mac_verify_finish( &operation, mac, sizeof( mac ) );
if( policy_alg == exercise_alg && if( policy_alg == exercise_alg &&
( policy_usage & PSA_KEY_USAGE_VERIFY ) != 0 ) ( policy_usage & PSA_KEY_USAGE_VERIFY ) != 0 )
TEST_ASSERT( status == PSA_ERROR_INVALID_SIGNATURE ); TEST_ASSERT( status == PSA_SUCCESS );
else else
TEST_ASSERT( status == PSA_ERROR_NOT_PERMITTED ); 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, TEST_ASSERT( psa_import_key( key_slot, key_type,
key->x, key->len ) == PSA_SUCCESS ); 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 ); psa_mac_abort( &operation );
TEST_ASSERT( status == expected_status ); 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, TEST_ASSERT( psa_import_key( key_slot, key_type,
key->x, key->len ) == PSA_SUCCESS ); 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_destroy_key( key_slot ) == PSA_SUCCESS );
TEST_ASSERT( psa_mac_update( &operation, TEST_ASSERT( psa_mac_update( &operation,
input->x, input->len ) == PSA_SUCCESS ); input->x, input->len ) == PSA_SUCCESS );