Isolate HMAC code into its own functions

Create internal functions for HMAC operations. This prepares for two
things: separating crypto-sensitive code from argument decoding and
validation, and using HMAC for other purposes than a MAC inside the
library (e.g. HMAC_DRBG, HKDF).

No intended observable behavior change in this commit.
This commit is contained in:
Gilles Peskine 2018-07-12 17:04:55 +02:00 committed by itayzafrir
parent 94e44540ff
commit 01126fae7f

View file

@ -1332,6 +1332,14 @@ static psa_status_t psa_mac_init( psa_mac_operation_t *operation,
return( status ); return( status );
} }
#if defined(MBEDTLS_MD_C)
static psa_status_t psa_hmac_abort_internal( psa_hmac_internal_data *hmac )
{
mbedtls_zeroize( hmac->opad, sizeof( hmac->opad ) );
return( psa_hash_abort( &hmac->hash_ctx ) );
}
#endif /* MBEDTLS_MD_C */
psa_status_t psa_mac_abort( psa_mac_operation_t *operation ) psa_status_t psa_mac_abort( psa_mac_operation_t *operation )
{ {
if( operation->alg == 0 ) if( operation->alg == 0 )
@ -1352,12 +1360,7 @@ psa_status_t psa_mac_abort( psa_mac_operation_t *operation )
#if defined(MBEDTLS_MD_C) #if defined(MBEDTLS_MD_C)
if( PSA_ALG_IS_HMAC( operation->alg ) ) if( PSA_ALG_IS_HMAC( operation->alg ) )
{ {
size_t block_size = psa_hmac_abort_internal( &operation->ctx.hmac );
psa_get_hash_block_size( PSA_ALG_HMAC_HASH( operation->alg ) );
if( block_size == 0 )
goto bad_state;
psa_hash_abort( &operation->ctx.hmac.hash_ctx );
mbedtls_zeroize( operation->ctx.hmac.opad, block_size );
} }
else else
#endif /* MBEDTLS_MD_C */ #endif /* MBEDTLS_MD_C */
@ -1407,43 +1410,33 @@ static int psa_cmac_setup( 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_setup( psa_mac_operation_t *operation, static psa_status_t psa_hmac_setup_internal( psa_hmac_internal_data *hmac,
psa_key_type_t key_type, const uint8_t *key,
key_slot_t *slot, size_t key_length,
psa_algorithm_t alg ) psa_algorithm_t hash_alg )
{ {
unsigned char ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE]; unsigned char ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
unsigned char *opad = operation->ctx.hmac.opad;
size_t i; size_t i;
size_t block_size = size_t block_size = psa_get_hash_block_size( hash_alg );
psa_get_hash_block_size( PSA_ALG_HMAC_HASH( alg ) );
unsigned int digest_size =
PSA_HASH_SIZE( PSA_ALG_HMAC_HASH( alg ) );
size_t key_length = slot->data.raw.bytes;
psa_status_t status; psa_status_t status;
if( block_size == 0 || digest_size == 0 ) if( block_size == 0 )
return( PSA_ERROR_NOT_SUPPORTED ); return( PSA_ERROR_NOT_SUPPORTED );
if( key_type != PSA_KEY_TYPE_HMAC )
return( PSA_ERROR_INVALID_ARGUMENT );
operation->mac_size = digest_size;
/* The hash was started earlier in psa_mac_init. */ /* The hash was started earlier in psa_mac_init. */
if( key_length > block_size ) if( key_length > block_size )
{ {
status = psa_hash_update( &operation->ctx.hmac.hash_ctx, status = psa_hash_update( &hmac->hash_ctx, key, key_length );
slot->data.raw.data, slot->data.raw.bytes );
if( status != PSA_SUCCESS ) if( status != PSA_SUCCESS )
return( status ); return( status );
status = psa_hash_finish( &operation->ctx.hmac.hash_ctx, status = psa_hash_finish( &hmac->hash_ctx,
ipad, sizeof( ipad ), &key_length ); ipad, sizeof( ipad ), &key_length );
if( status != PSA_SUCCESS ) if( status != PSA_SUCCESS )
return( status ); return( status );
} }
else else
memcpy( ipad, slot->data.raw.data, slot->data.raw.bytes ); memcpy( ipad, key, key_length );
/* ipad contains the key followed by garbage. Xor and fill with 0x36 /* ipad contains the key followed by garbage. Xor and fill with 0x36
* to create the ipad value. */ * to create the ipad value. */
@ -1454,22 +1447,17 @@ static int psa_hmac_setup( psa_mac_operation_t *operation,
/* Copy the key material from ipad to opad, flipping the requisite bits, /* Copy the key material from ipad to opad, flipping the requisite bits,
* and filling the rest of opad with the requisite constant. */ * and filling the rest of opad with the requisite constant. */
for( i = 0; i < key_length; i++ ) for( i = 0; i < key_length; i++ )
opad[i] = ipad[i] ^ 0x36 ^ 0x5C; hmac->opad[i] = ipad[i] ^ 0x36 ^ 0x5C;
memset( opad + key_length, 0x5C, block_size - key_length ); memset( hmac->opad + key_length, 0x5C, block_size - key_length );
status = psa_hash_setup( &operation->ctx.hmac.hash_ctx, status = psa_hash_setup( &hmac->hash_ctx, hash_alg );
PSA_ALG_HMAC_HASH( alg ) );
if( status != PSA_SUCCESS ) if( status != PSA_SUCCESS )
goto cleanup; goto cleanup;
status = psa_hash_update( &operation->ctx.hmac.hash_ctx, ipad, status = psa_hash_update( &hmac->hash_ctx, ipad, block_size );
block_size );
cleanup: 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
* succeeds, and it will be wiped by psa_mac_abort() called from
* psa_mac_setup in the error case. */
return( status ); return( status );
} }
@ -1517,7 +1505,22 @@ static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
#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_setup( operation, slot->type, slot, alg ); psa_algorithm_t hash_alg = PSA_ALG_HMAC_HASH( alg );
if( hash_alg == 0 )
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
if( slot->type != PSA_KEY_TYPE_HMAC )
{
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
status = psa_hmac_setup_internal( &operation->ctx.hmac,
slot->data.raw.data,
slot->data.raw.bytes,
hash_alg );
operation->mac_size = PSA_HASH_SIZE( hash_alg );
} }
else else
#endif /* MBEDTLS_MD_C */ #endif /* MBEDTLS_MD_C */
@ -1591,12 +1594,49 @@ cleanup:
return( status ); return( status );
} }
#if defined(MBEDTLS_MD_C)
static psa_status_t psa_hmac_finish_internal( psa_hmac_internal_data *hmac,
uint8_t *mac,
size_t mac_size )
{
unsigned char tmp[MBEDTLS_MD_MAX_SIZE];
psa_algorithm_t hash_alg = hmac->hash_ctx.alg;
size_t hash_size = 0;
size_t block_size = psa_get_hash_block_size( hash_alg );
psa_status_t status;
if( block_size == 0 )
return( PSA_ERROR_NOT_SUPPORTED );
status = psa_hash_finish( &hmac->hash_ctx, tmp, sizeof( tmp ), &hash_size );
if( status != PSA_SUCCESS )
return( status );
/* From here on, tmp needs to be wiped. */
status = psa_hash_setup( &hmac->hash_ctx, hash_alg );
if( status != PSA_SUCCESS )
goto exit;
status = psa_hash_update( &hmac->hash_ctx, hmac->opad, block_size );
if( status != PSA_SUCCESS )
goto exit;
status = psa_hash_update( &hmac->hash_ctx, tmp, hash_size );
if( status != PSA_SUCCESS )
goto exit;
status = psa_hash_finish( &hmac->hash_ctx, mac, mac_size, &hash_size );
exit:
mbedtls_zeroize( tmp, hash_size );
return( status );
}
#endif /* MBEDTLS_MD_C */
static psa_status_t psa_mac_finish_internal( psa_mac_operation_t *operation, static psa_status_t psa_mac_finish_internal( psa_mac_operation_t *operation,
uint8_t *mac, uint8_t *mac,
size_t mac_size ) size_t mac_size )
{ {
psa_status_t status;
if( ! operation->key_set ) if( ! operation->key_set )
return( PSA_ERROR_BAD_STATE ); return( PSA_ERROR_BAD_STATE );
if( operation->iv_required && ! operation->iv_set ) if( operation->iv_required && ! operation->iv_set )
@ -1616,41 +1656,8 @@ static psa_status_t psa_mac_finish_internal( psa_mac_operation_t *operation,
#if defined(MBEDTLS_MD_C) #if defined(MBEDTLS_MD_C)
if( PSA_ALG_IS_HMAC( operation->alg ) ) if( PSA_ALG_IS_HMAC( operation->alg ) )
{ {
unsigned char tmp[MBEDTLS_MD_MAX_SIZE]; return( psa_hmac_finish_internal( &operation->ctx.hmac,
unsigned char *opad = operation->ctx.hmac.opad; mac, mac_size ) );
size_t hash_size = 0;
size_t block_size =
psa_get_hash_block_size( PSA_ALG_HMAC_HASH( operation->alg ) );
if( block_size == 0 )
return( PSA_ERROR_NOT_SUPPORTED );
status = psa_hash_finish( &operation->ctx.hmac.hash_ctx, tmp,
sizeof( tmp ), &hash_size );
if( status != PSA_SUCCESS )
return( status );
/* From here on, tmp needs to be wiped. */
status = psa_hash_setup( &operation->ctx.hmac.hash_ctx,
PSA_ALG_HMAC_HASH( operation->alg ) );
if( status != PSA_SUCCESS )
goto hmac_cleanup;
status = psa_hash_update( &operation->ctx.hmac.hash_ctx, opad,
block_size );
if( status != PSA_SUCCESS )
goto hmac_cleanup;
status = psa_hash_update( &operation->ctx.hmac.hash_ctx, tmp,
hash_size );
if( status != PSA_SUCCESS )
goto hmac_cleanup;
status = psa_hash_finish( &operation->ctx.hmac.hash_ctx, mac,
mac_size, &hash_size );
hmac_cleanup:
mbedtls_zeroize( tmp, hash_size );
return( status );
} }
else else
#endif /* MBEDTLS_MD_C */ #endif /* MBEDTLS_MD_C */