PSA: Add support for HKDF-Extend and HKDF-Expand algs

Signed-off-by: Przemek Stekiel <przemyslaw.stekiel@mobica.com>
This commit is contained in:
Przemek Stekiel 2022-05-10 13:53:33 +02:00
parent 6b6ce3278e
commit 17520fe2c5

View file

@ -4295,7 +4295,8 @@ psa_status_t psa_key_derivation_abort( psa_key_derivation_operation_t *operation
} }
else else
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) #if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) ) if( PSA_ALG_IS_HKDF( kdf_alg ) || PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) ||
PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) )
{ {
mbedtls_free( operation->ctx.hkdf.info ); mbedtls_free( operation->ctx.hkdf.info );
status = psa_mac_abort( &operation->ctx.hkdf.hmac ); status = psa_mac_abort( &operation->ctx.hkdf.hmac );
@ -4379,15 +4380,17 @@ psa_status_t psa_key_derivation_set_capacity( psa_key_derivation_operation_t *op
/* Read some bytes from an HKDF-based operation. This performs a chunk /* Read some bytes from an HKDF-based operation. This performs a chunk
* of the expand phase of the HKDF algorithm. */ * of the expand phase of the HKDF algorithm. */
static psa_status_t psa_key_derivation_hkdf_read( psa_hkdf_key_derivation_t *hkdf, static psa_status_t psa_key_derivation_hkdf_read( psa_hkdf_key_derivation_t *hkdf,
psa_algorithm_t hash_alg, psa_algorithm_t kdf_alg,
uint8_t *output, uint8_t *output,
size_t output_length ) size_t output_length )
{ {
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
uint8_t hash_length = PSA_HASH_LENGTH( hash_alg ); uint8_t hash_length = PSA_HASH_LENGTH( hash_alg );
size_t hmac_output_length; size_t hmac_output_length;
psa_status_t status; psa_status_t status;
if( hkdf->state < HKDF_STATE_KEYED || ! hkdf->info_set ) if( hkdf->state < HKDF_STATE_KEYED ||
( ! hkdf->info_set && ! PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) ) )
return( PSA_ERROR_BAD_STATE ); return( PSA_ERROR_BAD_STATE );
hkdf->state = HKDF_STATE_OUTPUT; hkdf->state = HKDF_STATE_OUTPUT;
@ -4411,40 +4414,49 @@ static psa_status_t psa_key_derivation_hkdf_read( psa_hkdf_key_derivation_t *hkd
if( hkdf->block_number == 0xff ) if( hkdf->block_number == 0xff )
return( PSA_ERROR_BAD_STATE ); return( PSA_ERROR_BAD_STATE );
if( PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) && hkdf->block_number == 0 )
{
memcpy( hkdf->output_block, hkdf->prk, hash_length );
}
/* We need a new block */ /* We need a new block */
++hkdf->block_number; ++hkdf->block_number;
hkdf->offset_in_block = 0; hkdf->offset_in_block = 0;
status = psa_key_derivation_start_hmac( &hkdf->hmac, if( ! PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
hash_alg,
hkdf->prk,
hash_length );
if( status != PSA_SUCCESS )
return( status );
if( hkdf->block_number != 1 )
{ {
status = psa_key_derivation_start_hmac( &hkdf->hmac,
hash_alg,
hkdf->prk,
hash_length );
if( status != PSA_SUCCESS )
return( status );
if( hkdf->block_number != 1 )
{
status = psa_mac_update( &hkdf->hmac,
hkdf->output_block,
hash_length );
if( status != PSA_SUCCESS )
return( status );
}
status = psa_mac_update( &hkdf->hmac, status = psa_mac_update( &hkdf->hmac,
hkdf->output_block, hkdf->info,
hash_length ); hkdf->info_length );
if( status != PSA_SUCCESS )
return( status );
status = psa_mac_update( &hkdf->hmac,
&hkdf->block_number, 1 );
if( status != PSA_SUCCESS )
return( status );
status = psa_mac_sign_finish( &hkdf->hmac,
hkdf->output_block,
sizeof( hkdf->output_block ),
&hmac_output_length );
if( status != PSA_SUCCESS ) if( status != PSA_SUCCESS )
return( status ); return( status );
} }
status = psa_mac_update( &hkdf->hmac,
hkdf->info,
hkdf->info_length );
if( status != PSA_SUCCESS )
return( status );
status = psa_mac_update( &hkdf->hmac,
&hkdf->block_number, 1 );
if( status != PSA_SUCCESS )
return( status );
status = psa_mac_sign_finish( &hkdf->hmac,
hkdf->output_block,
sizeof( hkdf->output_block ),
&hmac_output_length );
if( status != PSA_SUCCESS )
return( status );
} }
return( PSA_SUCCESS ); return( PSA_SUCCESS );
@ -4650,10 +4662,10 @@ psa_status_t psa_key_derivation_output_bytes(
operation->capacity -= output_length; operation->capacity -= output_length;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) #if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) ) if( PSA_ALG_IS_HKDF( kdf_alg ) || PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) ||
PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
{ {
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg ); status = psa_key_derivation_hkdf_read( &operation->ctx.hkdf, kdf_alg,
status = psa_key_derivation_hkdf_read( &operation->ctx.hkdf, hash_alg,
output, output_length ); output, output_length );
} }
else else
@ -5043,7 +5055,8 @@ psa_status_t psa_key_derivation_output_key( const psa_key_attributes_t *attribut
static int is_kdf_alg_supported( psa_algorithm_t kdf_alg ) static int is_kdf_alg_supported( psa_algorithm_t kdf_alg )
{ {
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) #if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) ) if( PSA_ALG_IS_HKDF( kdf_alg ) || PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) ||
PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) )
return( 1 ); return( 1 );
#endif #endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) #if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF)
@ -5097,8 +5110,10 @@ static psa_status_t psa_key_derivation_setup_kdf(
{ {
return( PSA_ERROR_NOT_SUPPORTED ); return( PSA_ERROR_NOT_SUPPORTED );
} }
if( PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
operation->capacity = 255 * hash_size; operation->capacity = hash_size;
else
operation->capacity = 255 * hash_size;
return( PSA_SUCCESS ); return( PSA_SUCCESS );
} }
@ -5154,15 +5169,18 @@ psa_status_t psa_key_derivation_setup( psa_key_derivation_operation_t *operation
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) #if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
static psa_status_t psa_hkdf_input( psa_hkdf_key_derivation_t *hkdf, static psa_status_t psa_hkdf_input( psa_hkdf_key_derivation_t *hkdf,
psa_algorithm_t hash_alg, psa_algorithm_t kdf_alg,
psa_key_derivation_step_t step, psa_key_derivation_step_t step,
const uint8_t *data, const uint8_t *data,
size_t data_length ) size_t data_length )
{ {
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
psa_status_t status; psa_status_t status;
switch( step ) switch( step )
{ {
case PSA_KEY_DERIVATION_INPUT_SALT: case PSA_KEY_DERIVATION_INPUT_SALT:
if( PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
if( hkdf->state != HKDF_STATE_INIT ) if( hkdf->state != HKDF_STATE_INIT )
return( PSA_ERROR_BAD_STATE ); return( PSA_ERROR_BAD_STATE );
else else
@ -5177,32 +5195,48 @@ static psa_status_t psa_hkdf_input( psa_hkdf_key_derivation_t *hkdf,
} }
case PSA_KEY_DERIVATION_INPUT_SECRET: case PSA_KEY_DERIVATION_INPUT_SECRET:
/* If no salt was provided, use an empty salt. */ /* If no salt was provided, use an empty salt. */
if( hkdf->state == HKDF_STATE_INIT ) if( PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) )
{ {
status = psa_key_derivation_start_hmac( &hkdf->hmac, if( hkdf->state != HKDF_STATE_INIT )
hash_alg, return( PSA_ERROR_BAD_STATE );
NULL, 0 );
if( data_length > sizeof( hkdf->prk ) )
return( PSA_ERROR_INVALID_ARGUMENT );
memcpy( hkdf->prk, data, data_length );
}
else
{
if( hkdf->state == HKDF_STATE_INIT )
{
status = psa_key_derivation_start_hmac( &hkdf->hmac,
hash_alg,
NULL, 0 );
if( status != PSA_SUCCESS )
return( status );
hkdf->state = HKDF_STATE_STARTED;
}
if( hkdf->state != HKDF_STATE_STARTED )
return( PSA_ERROR_BAD_STATE );
status = psa_mac_update( &hkdf->hmac,
data, data_length );
if( status != PSA_SUCCESS )
return( status );
status = psa_mac_sign_finish( &hkdf->hmac,
hkdf->prk,
sizeof( hkdf->prk ),
&data_length );
if( status != PSA_SUCCESS ) if( status != PSA_SUCCESS )
return( status ); return( status );
hkdf->state = HKDF_STATE_STARTED;
} }
if( hkdf->state != HKDF_STATE_STARTED )
return( PSA_ERROR_BAD_STATE );
status = psa_mac_update( &hkdf->hmac,
data, data_length );
if( status != PSA_SUCCESS )
return( status );
status = psa_mac_sign_finish( &hkdf->hmac,
hkdf->prk,
sizeof( hkdf->prk ),
&data_length );
if( status != PSA_SUCCESS )
return( status );
hkdf->offset_in_block = PSA_HASH_LENGTH( hash_alg ); hkdf->offset_in_block = PSA_HASH_LENGTH( hash_alg );
hkdf->block_number = 0; hkdf->block_number = 0;
hkdf->state = HKDF_STATE_KEYED; hkdf->state = HKDF_STATE_KEYED;
return( PSA_SUCCESS ); return( PSA_SUCCESS );
case PSA_KEY_DERIVATION_INPUT_INFO: case PSA_KEY_DERIVATION_INPUT_INFO:
if( PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
if( hkdf->state == HKDF_STATE_OUTPUT ) if( hkdf->state == HKDF_STATE_OUTPUT )
return( PSA_ERROR_BAD_STATE ); return( PSA_ERROR_BAD_STATE );
if( hkdf->info_set ) if( hkdf->info_set )
@ -5488,10 +5522,10 @@ static psa_status_t psa_key_derivation_input_internal(
goto exit; goto exit;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) #if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) ) if( PSA_ALG_IS_HKDF( kdf_alg ) || PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) ||
PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) )
{ {
status = psa_hkdf_input( &operation->ctx.hkdf, status = psa_hkdf_input( &operation->ctx.hkdf, kdf_alg,
PSA_ALG_HKDF_GET_HASH( kdf_alg ),
step, data, data_length ); step, data, data_length );
} }
else else