Skip to content

Commit

Permalink
Merge pull request Mbed-TLS#4316 from gabor-mezei-arm/3258_implement_…
Browse files Browse the repository at this point in the history
…one-shot_MAC

Implement one-shot MAC
  • Loading branch information
gilles-peskine-arm authored Jun 22, 2021
2 parents 3e7ddb2 + 4d91bcd commit 36ff66c
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 76 deletions.
3 changes: 3 additions & 0 deletions ChangeLog.d/one-shot-mac.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Features
* Implement psa_mac_compute() and psa_mac_verify() as defined in the
PSA Cryptograpy API 1.0.0 specification.
209 changes: 163 additions & 46 deletions library/psa_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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 )
{
Expand Down Expand Up @@ -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 )
{
/* 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
/* 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 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 );
Expand Down Expand Up @@ -2424,7 +2432,116 @@ psa_status_t psa_mac_verify_finish( psa_mac_operation_t *operation,
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 */
Expand Down
62 changes: 38 additions & 24 deletions library/psa_crypto_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -493,6 +469,44 @@ static psa_status_t mac_verify_finish(

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)
Expand Down
Loading

0 comments on commit 36ff66c

Please sign in to comment.