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.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 47605d4..de1f772 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -1332,6 +1332,14 @@
     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 )
 {
     if( operation->alg == 0 )
@@ -1352,12 +1360,7 @@
 #if defined(MBEDTLS_MD_C)
     if( PSA_ALG_IS_HMAC( operation->alg ) )
     {
-        size_t block_size =
-            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 );
+        psa_hmac_abort_internal( &operation->ctx.hmac );
     }
     else
 #endif /* MBEDTLS_MD_C */
@@ -1407,43 +1410,33 @@
 #endif /* MBEDTLS_CMAC_C */
 
 #if defined(MBEDTLS_MD_C)
-static int psa_hmac_setup( psa_mac_operation_t *operation,
-                           psa_key_type_t key_type,
-                           key_slot_t *slot,
-                           psa_algorithm_t alg )
+static psa_status_t psa_hmac_setup_internal( psa_hmac_internal_data *hmac,
+                                             const uint8_t *key,
+                                             size_t key_length,
+                                             psa_algorithm_t hash_alg )
 {
     unsigned char ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
-    unsigned char *opad = operation->ctx.hmac.opad;
     size_t i;
-    size_t block_size =
-        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;
+    size_t block_size = psa_get_hash_block_size( hash_alg );
     psa_status_t status;
 
-    if( block_size == 0 || digest_size == 0 )
+    if( block_size == 0 )
         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. */
     if( key_length > block_size )
     {
-        status = psa_hash_update( &operation->ctx.hmac.hash_ctx,
-                                  slot->data.raw.data, slot->data.raw.bytes );
+        status = psa_hash_update( &hmac->hash_ctx, key, key_length );
         if( status != PSA_SUCCESS )
             return( status );
-        status = psa_hash_finish( &operation->ctx.hmac.hash_ctx,
+        status = psa_hash_finish( &hmac->hash_ctx,
                                   ipad, sizeof( ipad ), &key_length );
         if( status != PSA_SUCCESS )
             return( status );
     }
     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
      * to create the ipad value. */
@@ -1454,22 +1447,17 @@
     /* Copy the key material from ipad to opad, flipping the requisite bits,
      * and filling the rest of opad with the requisite constant. */
     for( i = 0; i < key_length; i++ )
-        opad[i] = ipad[i] ^ 0x36 ^ 0x5C;
-    memset( opad + key_length, 0x5C, block_size - key_length );
+        hmac->opad[i] = ipad[i] ^ 0x36 ^ 0x5C;
+    memset( hmac->opad + key_length, 0x5C, block_size - key_length );
 
-    status = psa_hash_setup( &operation->ctx.hmac.hash_ctx,
-                             PSA_ALG_HMAC_HASH( alg ) );
+    status = psa_hash_setup( &hmac->hash_ctx, hash_alg );
     if( status != PSA_SUCCESS )
         goto cleanup;
 
-    status = psa_hash_update( &operation->ctx.hmac.hash_ctx, ipad,
-                              block_size );
+    status = psa_hash_update( &hmac->hash_ctx, ipad, block_size );
 
 cleanup:
     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 );
 }
@@ -1517,7 +1505,22 @@
 #if defined(MBEDTLS_MD_C)
     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
 #endif /* MBEDTLS_MD_C */
@@ -1591,12 +1594,49 @@
     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,
                                              uint8_t *mac,
                                              size_t mac_size )
 {
-    psa_status_t status;
-
     if( ! operation->key_set )
         return( PSA_ERROR_BAD_STATE );
     if( operation->iv_required && ! operation->iv_set )
@@ -1616,41 +1656,8 @@
 #if defined(MBEDTLS_MD_C)
     if( PSA_ALG_IS_HMAC( operation->alg ) )
     {
-        unsigned char tmp[MBEDTLS_MD_MAX_SIZE];
-        unsigned char *opad = operation->ctx.hmac.opad;
-        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 );
+        return( psa_hmac_finish_internal( &operation->ctx.hmac,
+                                          mac, mac_size ) );
     }
     else
 #endif /* MBEDTLS_MD_C */