From ea29bfb14893c8334558269488dcb92396449b30 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 19 Jun 2019 12:21:20 +0100 Subject: [PATCH] Add tls12_prf key derivation to the new API The TLS 1.2 pseudorandom function does a lot of distinct HMAC operations with the same key. To save the battery and CPU cycles spent on calculating the paddings and hashing the inner padding, we keep the hash context in the status right after the inner padding having been hashed and clone it as needed. --- library/psa_crypto.c | 77 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index ba9b3e346..153bc6d97 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -4132,7 +4132,8 @@ static psa_status_t psa_key_derivation_tls12_prf_generate_next_block( { psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( alg ); uint8_t hash_length = PSA_HASH_SIZE( hash_alg ); - psa_status_t status; + psa_hash_operation_t backup = PSA_HASH_OPERATION_INIT; + psa_status_t status, cleanup_status; /* We can't be wanting more output after block 0xff, otherwise * the capacity check in psa_key_derivation_output_bytes() would have @@ -4155,19 +4156,81 @@ static psa_status_t psa_key_derivation_tls12_prf_generate_next_block( * HMAC_hash(secret, A(3) + seed) + ... * * A(0) = seed - * A(i) = HMAC_hash( secret, A(i-1) ) + * A(i) = HMAC_hash(secret, A(i-1)) * - * The `psa_tls12_prf_key_derivation` structures saves the block + * The `psa_tls12_prf_key_derivation` structure saves the block * `HMAC_hash(secret, A(i) + seed)` from which the output * is currently extracted as `output_block`. */ - (void) hash_length; - (void) status; + /* Save the hash context before using it, to preserve the hash state with + * only the inner padding in it. We need this, because inner padding depends + * on the key (secret in the RFC's terminology). */ + status = psa_hash_clone( &tls12_prf->hmac.hash_ctx, &backup ); + if( status != PSA_SUCCESS ) + goto cleanup; + + /* Calculate A(i) where i = tls12_prf->block_number. */ + if( tls12_prf->block_number == 1 ) + { + /* A(1) = HMAC_hash(secret, A(0)), where A(0) = seed. (The RFC overloads + * the variable seed and in this instance means it in the context of the + * P_hash function, where seed = label + seed.) */ + status = psa_hash_update( &tls12_prf->hmac.hash_ctx, + tls12_prf->label, tls12_prf->label_length ); + if( status != PSA_SUCCESS ) + goto cleanup; + status = psa_hash_update( &tls12_prf->hmac.hash_ctx, + tls12_prf->seed, tls12_prf->seed_length ); + if( status != PSA_SUCCESS ) + goto cleanup; + } + else + { + /* A(i) = HMAC_hash(secret, A(i-1)) */ + status = psa_hash_update( &tls12_prf->hmac.hash_ctx, + tls12_prf->Ai, hash_length ); + if( status != PSA_SUCCESS ) + goto cleanup; + } + + status = psa_hmac_finish_internal( &tls12_prf->hmac, + tls12_prf->Ai, hash_length ); + if( status != PSA_SUCCESS ) + goto cleanup; + status = psa_hash_clone( &backup, &tls12_prf->hmac.hash_ctx ); + if( status != PSA_SUCCESS ) + goto cleanup; + + /* Calculate HMAC_hash(secret, A(i) + label + seed). */ + status = psa_hash_update( &tls12_prf->hmac.hash_ctx, + tls12_prf->Ai, hash_length ); + if( status != PSA_SUCCESS ) + goto cleanup; + status = psa_hash_update( &tls12_prf->hmac.hash_ctx, + tls12_prf->label, tls12_prf->label_length ); + if( status != PSA_SUCCESS ) + goto cleanup; + status = psa_hash_update( &tls12_prf->hmac.hash_ctx, + tls12_prf->seed, tls12_prf->seed_length ); + if( status != PSA_SUCCESS ) + goto cleanup; + status = psa_hmac_finish_internal( &tls12_prf->hmac, + tls12_prf->output_block, hash_length ); + if( status != PSA_SUCCESS ) + goto cleanup; + status = psa_hash_clone( &backup, &tls12_prf->hmac.hash_ctx ); + if( status != PSA_SUCCESS ) + goto cleanup; + cleanup: - return( PSA_ERROR_NOT_SUPPORTED ); + cleanup_status = psa_hash_abort( &backup ); + if( status == PSA_SUCCESS && cleanup_status != PSA_SUCCESS ) + status = cleanup_status; + + return( status ); } #endif /* PSA_PRE_1_0_KEY_DERIVATION */ @@ -4295,7 +4358,6 @@ psa_status_t psa_key_derivation_output_bytes( output, output_length ); } else -#if defined(PSA_PRE_1_0_KEY_DERIVATION) if( PSA_ALG_IS_TLS12_PRF( kdf_alg ) || PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) ) { @@ -4304,7 +4366,6 @@ psa_status_t psa_key_derivation_output_bytes( output_length ); } else -#endif /* PSA_PRE_1_0_KEY_DERIVATION */ #endif /* MBEDTLS_MD_C */ { return( PSA_ERROR_BAD_STATE );