1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-12-24 17:41:01 +03:00

Merge pull request #5834 from mprse/HKDF_1

HKDF 1: PSA: implement HKDF_Expand and HKDF_Extract algorithms
This commit is contained in:
Gilles Peskine
2022-06-20 15:27:46 +02:00
committed by GitHub
12 changed files with 636 additions and 66 deletions

View File

@@ -88,6 +88,12 @@
#define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) )
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND)
#define BUILTIN_ALG_ANY_HKDF 1
#endif
/****************************************************************/
/* Global data, support functions and library management */
/****************************************************************/
@@ -4235,13 +4241,13 @@ psa_status_t psa_aead_abort( psa_aead_operation_t *operation )
/* Generators */
/****************************************************************/
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) || \
#if defined(BUILTIN_ALG_ANY_HKDF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
#define AT_LEAST_ONE_BUILTIN_KDF
#endif /* At least one builtin KDF */
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) || \
#if defined(BUILTIN_ALG_ANY_HKDF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
static psa_status_t psa_key_derivation_start_hmac(
@@ -4294,14 +4300,14 @@ psa_status_t psa_key_derivation_abort( psa_key_derivation_operation_t *operation
* nothing to do. */
}
else
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) )
#if defined(BUILTIN_ALG_ANY_HKDF)
if( PSA_ALG_IS_ANY_HKDF( kdf_alg ) )
{
mbedtls_free( operation->ctx.hkdf.info );
status = psa_mac_abort( &operation->ctx.hkdf.hmac );
}
else
#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF */
#endif /* BUILTIN_ALG_ANY_HKDF */
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
if( PSA_ALG_IS_TLS12_PRF( kdf_alg ) ||
@@ -4375,19 +4381,29 @@ psa_status_t psa_key_derivation_set_capacity( psa_key_derivation_operation_t *op
return( PSA_SUCCESS );
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
/* Read some bytes from an HKDF-based operation. This performs a chunk
* of the expand phase of the HKDF algorithm. */
#if defined(BUILTIN_ALG_ANY_HKDF)
/* Read some bytes from an HKDF-based operation. */
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,
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 );
size_t hmac_output_length;
psa_status_t status;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT)
const uint8_t last_block = PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) ? 0 : 0xff;
#else
const uint8_t last_block = 0xff;
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */
if( hkdf->state < HKDF_STATE_KEYED || ! hkdf->info_set )
if( hkdf->state < HKDF_STATE_KEYED ||
( !hkdf->info_set
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT)
&& !PSA_ALG_IS_HKDF_EXTRACT( kdf_alg )
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */
) )
return( PSA_ERROR_BAD_STATE );
hkdf->state = HKDF_STATE_OUTPUT;
@@ -4403,12 +4419,12 @@ static psa_status_t psa_key_derivation_hkdf_read( psa_hkdf_key_derivation_t *hkd
hkdf->offset_in_block += n;
if( output_length == 0 )
break;
/* We can't be wanting more output after block 0xff, otherwise
/* We can't be wanting more output after the last block, otherwise
* the capacity check in psa_key_derivation_output_bytes() would have
* prevented this call. It could happen only if the operation
* object was corrupted or if this function is called directly
* inside the library. */
if( hkdf->block_number == 0xff )
if( hkdf->block_number == last_block )
return( PSA_ERROR_BAD_STATE );
/* We need a new block */
@@ -4449,7 +4465,7 @@ static psa_status_t psa_key_derivation_hkdf_read( psa_hkdf_key_derivation_t *hkd
return( PSA_SUCCESS );
}
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF */
#endif /* BUILTIN_ALG_ANY_HKDF */
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
@@ -4649,15 +4665,14 @@ psa_status_t psa_key_derivation_output_bytes(
}
operation->capacity -= output_length;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) )
#if defined(BUILTIN_ALG_ANY_HKDF)
if( PSA_ALG_IS_ANY_HKDF( kdf_alg ) )
{
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
status = psa_key_derivation_hkdf_read( &operation->ctx.hkdf, hash_alg,
status = psa_key_derivation_hkdf_read( &operation->ctx.hkdf, kdf_alg,
output, output_length );
}
else
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF */
#endif /* BUILTIN_ALG_ANY_HKDF */
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
if( PSA_ALG_IS_TLS12_PRF( kdf_alg ) ||
@@ -5046,6 +5061,14 @@ static int is_kdf_alg_supported( psa_algorithm_t kdf_alg )
if( PSA_ALG_IS_HKDF( kdf_alg ) )
return( 1 );
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT)
if( PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
return( 1 );
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND)
if( PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) )
return( 1 );
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF)
if( PSA_ALG_IS_TLS12_PRF( kdf_alg ) )
return( 1 );
@@ -5097,8 +5120,12 @@ static psa_status_t psa_key_derivation_setup_kdf(
{
return( PSA_ERROR_NOT_SUPPORTED );
}
operation->capacity = 255 * hash_size;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT)
if( PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
operation->capacity = hash_size;
else
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */
operation->capacity = 255 * hash_size;
return( PSA_SUCCESS );
}
@@ -5152,17 +5179,22 @@ psa_status_t psa_key_derivation_setup( psa_key_derivation_operation_t *operation
return( status );
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
#if defined(BUILTIN_ALG_ANY_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,
const uint8_t *data,
size_t data_length )
{
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
psa_status_t status;
switch( step )
{
case PSA_KEY_DERIVATION_INPUT_SALT:
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND)
if( PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND */
if( hkdf->state != HKDF_STATE_INIT )
return( PSA_ERROR_BAD_STATE );
else
@@ -5176,33 +5208,82 @@ static psa_status_t psa_hkdf_input( psa_hkdf_key_derivation_t *hkdf,
return( PSA_SUCCESS );
}
case PSA_KEY_DERIVATION_INPUT_SECRET:
/* If no salt was provided, use an empty salt. */
if( hkdf->state == HKDF_STATE_INIT )
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND)
if( PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) )
{
status = psa_key_derivation_start_hmac( &hkdf->hmac,
hash_alg,
NULL, 0 );
/* We shouldn't be in different state as HKDF_EXPAND only allows
* two inputs: SECRET (this case) and INFO which does not modify
* the state. It could happen only if the hkdf
* object was corrupted. */
if( hkdf->state != HKDF_STATE_INIT )
return( PSA_ERROR_BAD_STATE );
/* Allow only input that fits expected prk size */
if( data_length != PSA_HASH_LENGTH( hash_alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
memcpy( hkdf->prk, data, data_length );
}
else
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND */
{
/* HKDF: If no salt was provided, use an empty salt.
* HKDF-EXTRACT: salt is mandatory. */
if( hkdf->state == HKDF_STATE_INIT )
{
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT)
if( PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
return( PSA_ERROR_BAD_STATE );
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */
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 )
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->block_number = 0;
hkdf->state = HKDF_STATE_KEYED;
hkdf->block_number = 0;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT)
if( PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
{
/* The only block of output is the PRK. */
memcpy( hkdf->output_block, hkdf->prk, PSA_HASH_LENGTH( hash_alg ) );
hkdf->offset_in_block = 0;
}
else
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */
{
/* Block 0 is empty, and the next block will be
* generated by psa_key_derivation_hkdf_read(). */
hkdf->offset_in_block = PSA_HASH_LENGTH( hash_alg );
}
return( PSA_SUCCESS );
case PSA_KEY_DERIVATION_INPUT_INFO:
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT)
if( PSA_ALG_IS_HKDF_EXTRACT( kdf_alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND)
if( PSA_ALG_IS_HKDF_EXPAND( kdf_alg ) &&
hkdf->state == HKDF_STATE_INIT )
return( PSA_ERROR_BAD_STATE );
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */
if( hkdf->state == HKDF_STATE_OUTPUT )
return( PSA_ERROR_BAD_STATE );
if( hkdf->info_set )
@@ -5221,7 +5302,7 @@ static psa_status_t psa_hkdf_input( psa_hkdf_key_derivation_t *hkdf,
return( PSA_ERROR_INVALID_ARGUMENT );
}
}
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF */
#endif /* BUILTIN_ALG_ANY_HKDF */
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
@@ -5486,15 +5567,14 @@ static psa_status_t psa_key_derivation_input_internal(
if( status != PSA_SUCCESS )
goto exit;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) )
#if defined(BUILTIN_ALG_ANY_HKDF)
if( PSA_ALG_IS_ANY_HKDF( kdf_alg ) )
{
status = psa_hkdf_input( &operation->ctx.hkdf,
PSA_ALG_HKDF_GET_HASH( kdf_alg ),
status = psa_hkdf_input( &operation->ctx.hkdf, kdf_alg,
step, data, data_length );
}
else
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF */
#endif /* BUILTIN_ALG_ANY_HKDF */
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF)
if( PSA_ALG_IS_TLS12_PRF( kdf_alg ) )
{