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.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index ba9b3e3..153bc6d 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -4132,7 +4132,8 @@
 {
     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 @@
      *                        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 @@
                                           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 @@
                                                output_length );
     }
     else
-#endif /* PSA_PRE_1_0_KEY_DERIVATION */
 #endif /* MBEDTLS_MD_C */
     {
         return( PSA_ERROR_BAD_STATE );