Merge pull request #4316 from gabor-mezei-arm/3258_implement_one-shot_MAC

Implement one-shot MAC
This commit is contained in:
Gilles Peskine 2021-06-22 12:18:25 +02:00 committed by GitHub
commit 36ff66c4b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 291 additions and 76 deletions

View File

@ -0,0 +1,3 @@
Features
* Implement psa_mac_compute() and psa_mac_verify() as defined in the
PSA Cryptograpy API 1.0.0 specification.

View File

@ -2220,6 +2220,46 @@ psa_status_t psa_mac_abort( psa_mac_operation_t *operation )
return( status );
}
static psa_status_t psa_mac_finalize_alg_and_key_validation(
psa_algorithm_t alg,
const psa_key_attributes_t *attributes,
uint8_t *mac_size )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_type_t key_type = psa_get_key_type( attributes );
size_t key_bits = psa_get_key_bits( attributes );
if( ! PSA_ALG_IS_MAC( alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
/* Validate the combination of key type and algorithm */
status = psa_mac_key_can_do( alg, key_type );
if( status != PSA_SUCCESS )
return( status );
/* Get the output length for the algorithm and key combination */
*mac_size = PSA_MAC_LENGTH( key_type, key_bits, alg );
if( *mac_size < 4 )
{
/* A very short MAC is too short for security since it can be
* brute-forced. Ancient protocols with 32-bit MACs do exist,
* so we make this our minimum, even though 32 bits is still
* too small for security. */
return( PSA_ERROR_NOT_SUPPORTED );
}
if( *mac_size > PSA_MAC_LENGTH( key_type, key_bits,
PSA_ALG_FULL_LENGTH_MAC( alg ) ) )
{
/* It's impossible to "truncate" to a larger length than the full length
* of the algorithm. */
return( PSA_ERROR_INVALID_ARGUMENT );
}
return( PSA_SUCCESS );
}
static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
mbedtls_svc_key_id_t key,
psa_algorithm_t alg,
@ -2233,9 +2273,6 @@ static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
if( operation->id != 0 )
return( PSA_ERROR_BAD_STATE );
if( ! PSA_ALG_IS_MAC( alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
status = psa_get_and_lock_key_slot_with_policy(
key,
&slot,
@ -2248,39 +2285,12 @@ static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
.core = slot->attr
};
/* Validate the combination of key type and algorithm */
status = psa_mac_key_can_do( alg, psa_get_key_type( &attributes ) );
status = psa_mac_finalize_alg_and_key_validation( alg, &attributes,
&operation->mac_size );
if( status != PSA_SUCCESS )
goto exit;
operation->is_sign = is_sign;
/* Get the output length for the algorithm and key combination */
operation->mac_size = PSA_MAC_LENGTH(
psa_get_key_type( &attributes ),
psa_get_key_bits( &attributes ),
alg );
if( operation->mac_size < 4 )
{
/* A very short MAC is too short for security since it can be
* brute-forced. Ancient protocols with 32-bit MACs do exist,
* so we make this our minimum, even though 32 bits is still
* too small for security. */
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
if( operation->mac_size > PSA_MAC_LENGTH( psa_get_key_type( &attributes ),
psa_get_key_bits( &attributes ),
PSA_ALG_FULL_LENGTH_MAC( alg ) ) )
{
/* It's impossible to "truncate" to a larger length than the full length
* of the algorithm. */
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
/* Dispatch the MAC setup call with validated input */
if( is_sign )
{
@ -2373,24 +2383,22 @@ psa_status_t psa_mac_sign_finish( psa_mac_operation_t *operation,
mac, operation->mac_size,
mac_length );
if( status == PSA_SUCCESS )
/* In case of success, set the potential excess room in the output buffer
* to an invalid value, to avoid potentially leaking a longer MAC.
* In case of error, set the output length and content to a safe default,
* such that in case the caller misses an error check, the output would be
* an unachievable MAC.
*/
if( status != PSA_SUCCESS )
{
/* Set the excess room in the output buffer to an invalid value, to
* avoid potentially leaking a longer MAC. */
if( mac_size > operation->mac_size )
memset( &mac[operation->mac_size],
'!',
mac_size - operation->mac_size );
}
else
{
/* Set the output length and content to a safe default, such that in
* case the caller misses an error check, the output would be an
* unachievable MAC. */
*mac_length = mac_size;
memset( mac, '!', mac_size );
operation->mac_size = 0;
}
if( mac_size > operation->mac_size )
memset( &mac[operation->mac_size], '!',
mac_size - operation->mac_size );
abort_status = psa_mac_abort( operation );
return( status == PSA_SUCCESS ? abort_status : status );
@ -2424,7 +2432,116 @@ cleanup:
return( status == PSA_SUCCESS ? abort_status : status );
}
static psa_status_t psa_mac_compute_internal( mbedtls_svc_key_id_t key,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length,
int is_sign )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
uint8_t operation_mac_size = 0;
status = psa_get_and_lock_key_slot_with_policy(
key, &slot,
is_sign ? PSA_KEY_USAGE_SIGN_HASH : PSA_KEY_USAGE_VERIFY_HASH,
alg );
if( status != PSA_SUCCESS )
goto exit;
psa_key_attributes_t attributes = {
.core = slot->attr
};
status = psa_mac_finalize_alg_and_key_validation( alg, &attributes,
&operation_mac_size );
if( status != PSA_SUCCESS )
goto exit;
if( mac_size < operation_mac_size )
{
status = PSA_ERROR_BUFFER_TOO_SMALL;
goto exit;
}
status = psa_driver_wrapper_mac_compute(
&attributes,
slot->key.data, slot->key.bytes,
alg,
input, input_length,
mac, operation_mac_size, mac_length );
exit:
/* In case of success, set the potential excess room in the output buffer
* to an invalid value, to avoid potentially leaking a longer MAC.
* In case of error, set the output length and content to a safe default,
* such that in case the caller misses an error check, the output would be
* an unachievable MAC.
*/
if( status != PSA_SUCCESS )
{
*mac_length = mac_size;
operation_mac_size = 0;
}
if( mac_size > operation_mac_size )
memset( &mac[operation_mac_size], '!', mac_size - operation_mac_size );
unlock_status = psa_unlock_key_slot( slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
psa_status_t psa_mac_compute( mbedtls_svc_key_id_t key,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length)
{
return( psa_mac_compute_internal( key, alg,
input, input_length,
mac, mac_size, mac_length, 1 ) );
}
psa_status_t psa_mac_verify( mbedtls_svc_key_id_t key,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
const uint8_t *mac,
size_t mac_length)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
uint8_t actual_mac[PSA_MAC_MAX_SIZE];
size_t actual_mac_length;
status = psa_mac_compute_internal( key, alg,
input, input_length,
actual_mac, sizeof( actual_mac ),
&actual_mac_length, 0 );
if( status != PSA_SUCCESS )
goto exit;
if( mac_length != actual_mac_length )
{
status = PSA_ERROR_INVALID_SIGNATURE;
goto exit;
}
if( mbedtls_psa_safer_memcmp( mac, actual_mac, actual_mac_length ) != 0 )
{
status = PSA_ERROR_INVALID_SIGNATURE;
goto exit;
}
exit:
mbedtls_platform_zeroize( actual_mac, sizeof( actual_mac ) );
return ( status );
}
/****************************************************************/
/* Asymmetric cryptography */

View File

@ -355,30 +355,6 @@ static psa_status_t mac_setup( mbedtls_psa_mac_operation_t *operation,
return( status );
}
static psa_status_t mac_compute(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length )
{
/* One-shot MAC has not been implemented in this PSA implementation yet. */
(void) attributes;
(void) key_buffer;
(void) key_buffer_size;
(void) alg;
(void) input;
(void) input_length;
(void) mac;
(void) mac_size;
(void) mac_length;
return( PSA_ERROR_NOT_SUPPORTED );
}
static psa_status_t mac_update(
mbedtls_psa_mac_operation_t *operation,
const uint8_t *input,
@ -493,6 +469,44 @@ cleanup:
return( status );
}
static psa_status_t mac_compute(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
mbedtls_psa_mac_operation_t operation = MBEDTLS_PSA_MAC_OPERATION_INIT;
status = mac_setup( &operation,
attributes, key_buffer, key_buffer_size,
alg );
if( status != PSA_SUCCESS )
goto exit;
if( input_length > 0 )
{
status = mac_update( &operation, input, input_length );
if( status != PSA_SUCCESS )
goto exit;
}
status = mac_finish_internal( &operation, mac, mac_size );
if( status == PSA_SUCCESS )
*mac_length = mac_size;
exit:
mac_abort( &operation );
return( status );
}
#endif /* BUILTIN_ALG_HMAC || BUILTIN_ALG_CMAC */
#if defined(MBEDTLS_PSA_BUILTIN_MAC)

View File

@ -1987,7 +1987,21 @@ void mac_sign( int key_type_arg,
mbedtls_test_set_step( output_size );
ASSERT_ALLOC( actual_mac, output_size );
/* Calculate the MAC. */
/* Calculate the MAC, one-shot case. */
TEST_EQUAL( psa_mac_compute( key, alg,
input->x, input->len,
actual_mac, output_size, &mac_length ),
expected_status );
if( expected_status == PSA_SUCCESS )
{
ASSERT_COMPARE( expected_mac->x, expected_mac->len,
actual_mac, mac_length );
}
if( output_size > 0 )
memset( actual_mac, 0, output_size );
/* Calculate the MAC, multi-part case. */
PSA_ASSERT( psa_mac_sign_setup( &operation, key, alg ) );
PSA_ASSERT( psa_mac_update( &operation,
input->x, input->len ) );
@ -2039,7 +2053,11 @@ void mac_verify( int key_type_arg,
PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
&key ) );
/* Test the correct MAC. */
/* Verify correct MAC, one-shot case. */
PSA_ASSERT( psa_mac_verify( key, alg, input->x, input->len,
expected_mac->x, expected_mac->len ) );
/* Verify correct MAC, multi-part case. */
PSA_ASSERT( psa_mac_verify_setup( &operation, key, alg ) );
PSA_ASSERT( psa_mac_update( &operation,
input->x, input->len ) );
@ -2047,7 +2065,14 @@ void mac_verify( int key_type_arg,
expected_mac->x,
expected_mac->len ) );
/* Test a MAC that's too short. */
/* Test a MAC that's too short, one-shot case. */
TEST_EQUAL( psa_mac_verify( key, alg,
input->x, input->len,
expected_mac->x,
expected_mac->len - 1 ),
PSA_ERROR_INVALID_SIGNATURE );
/* Test a MAC that's too short, multi-part case. */
PSA_ASSERT( psa_mac_verify_setup( &operation, key, alg ) );
PSA_ASSERT( psa_mac_update( &operation,
input->x, input->len ) );
@ -2056,9 +2081,15 @@ void mac_verify( int key_type_arg,
expected_mac->len - 1 ),
PSA_ERROR_INVALID_SIGNATURE );
/* Test a MAC that's too long. */
/* Test a MAC that's too long, one-shot case. */
ASSERT_ALLOC( perturbed_mac, expected_mac->len + 1 );
memcpy( perturbed_mac, expected_mac->x, expected_mac->len );
TEST_EQUAL( psa_mac_verify( key, alg,
input->x, input->len,
perturbed_mac, expected_mac->len + 1 ),
PSA_ERROR_INVALID_SIGNATURE );
/* Test a MAC that's too long, multi-part case. */
PSA_ASSERT( psa_mac_verify_setup( &operation, key, alg ) );
PSA_ASSERT( psa_mac_update( &operation,
input->x, input->len ) );
@ -2072,6 +2103,12 @@ void mac_verify( int key_type_arg,
{
mbedtls_test_set_step( i );
perturbed_mac[i] ^= 1;
TEST_EQUAL( psa_mac_verify( key, alg,
input->x, input->len,
perturbed_mac, expected_mac->len ),
PSA_ERROR_INVALID_SIGNATURE );
PSA_ASSERT( psa_mac_verify_setup( &operation, key, alg ) );
PSA_ASSERT( psa_mac_update( &operation,
input->x, input->len ) );

View File

@ -1118,7 +1118,31 @@ void mac_sign( int key_type_arg,
ASSERT_ALLOC( actual_mac, mac_buffer_size );
mbedtls_test_driver_mac_hooks.forced_status = forced_status;
/* Calculate the MAC. */
/*
* Calculate the MAC, one-shot case.
*/
status = psa_mac_compute( key, alg,
input->x, input->len,
actual_mac, mac_buffer_size,
&mac_length );
TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );
if( forced_status == PSA_SUCCESS ||
forced_status == PSA_ERROR_NOT_SUPPORTED )
{
PSA_ASSERT( status );
}
else
TEST_EQUAL( forced_status, status );
if( mac_buffer_size > 0 )
memset( actual_mac, 0, mac_buffer_size );
mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();
mbedtls_test_driver_mac_hooks.forced_status = forced_status;
/*
* Calculate the MAC, multipart case.
*/
status = psa_mac_sign_setup( &operation, key, alg );
TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );
@ -1214,7 +1238,27 @@ void mac_verify( int key_type_arg,
mbedtls_test_driver_mac_hooks.forced_status = forced_status;
/* Test the correct MAC. */
/*
* Verify the MAC, one-shot case.
*/
status = psa_mac_verify( key, alg,
input->x, input->len,
expected_mac->x, expected_mac->len );
TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );
if( forced_status == PSA_SUCCESS ||
forced_status == PSA_ERROR_NOT_SUPPORTED )
{
PSA_ASSERT( status );
}
else
TEST_EQUAL( forced_status, status );
mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();
mbedtls_test_driver_mac_hooks.forced_status = forced_status;
/*
* Verify the MAC, multi-part case.
*/
status = psa_mac_verify_setup( &operation, key, alg );
TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );