Implement psa_key_agreement_raw_shared_secret

Refactor: split psa_key_agreement_raw_internal out of
psa_key_agreement_internal, and call it from
psa_key_agreement_raw_shared_secret as well.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 149d135..6660efe 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -4596,6 +4596,37 @@
 
 #define PSA_KEY_AGREEMENT_MAX_SHARED_SECRET_SIZE MBEDTLS_ECP_MAX_BYTES
 
+static psa_status_t psa_key_agreement_raw_internal( psa_algorithm_t alg,
+                                                    psa_key_slot_t *private_key,
+                                                    const uint8_t *peer_key,
+                                                    size_t peer_key_length,
+                                                    uint8_t *shared_secret,
+                                                    size_t shared_secret_size,
+                                                    size_t *shared_secret_length )
+{
+    switch( alg )
+    {
+#if defined(MBEDTLS_ECDH_C)
+        case PSA_ALG_ECDH:
+            if( ! PSA_KEY_TYPE_IS_ECC_KEYPAIR( private_key->type ) )
+                return( PSA_ERROR_INVALID_ARGUMENT );
+            return( psa_key_agreement_ecdh( peer_key, peer_key_length,
+                                            private_key->data.ecp,
+                                            shared_secret, shared_secret_size,
+                                            shared_secret_length ) );
+            break;
+#endif /* MBEDTLS_ECDH_C */
+        default:
+            (void) private_key;
+            (void) peer_key;
+            (void) peer_key_length;
+            (void) shared_secret;
+            (void) shared_secret_size;
+            (void) shared_secret_length;
+            return( PSA_ERROR_NOT_SUPPORTED );
+    }
+}
+
 /* Note that if this function fails, you must call psa_generator_abort()
  * to potentially free embedded data structures and wipe confidential data.
  */
@@ -4608,28 +4639,16 @@
     psa_status_t status;
     uint8_t shared_secret[PSA_KEY_AGREEMENT_MAX_SHARED_SECRET_SIZE];
     size_t shared_secret_length = 0;
+    psa_algorithm_t ka_alg = PSA_ALG_KEY_AGREEMENT_GET_BASE( generator->alg );
 
     /* Step 1: run the secret agreement algorithm to generate the shared
      * secret. */
-    switch( PSA_ALG_KEY_AGREEMENT_GET_BASE( generator->alg ) )
-    {
-#if defined(MBEDTLS_ECDH_C)
-        case PSA_ALG_ECDH:
-            if( ! PSA_KEY_TYPE_IS_ECC_KEYPAIR( private_key->type ) )
-                return( PSA_ERROR_INVALID_ARGUMENT );
-            status = psa_key_agreement_ecdh( peer_key, peer_key_length,
-                                             private_key->data.ecp,
+    status = psa_key_agreement_raw_internal( ka_alg,
+                                             private_key,
+                                             peer_key, peer_key_length,
                                              shared_secret,
                                              sizeof( shared_secret ),
                                              &shared_secret_length );
-            break;
-#endif /* MBEDTLS_ECDH_C */
-        default:
-            (void) private_key;
-            (void) peer_key;
-            (void) peer_key_length;
-            return( PSA_ERROR_NOT_SUPPORTED );
-    }
     if( status != PSA_SUCCESS )
         goto exit;
 
@@ -4665,6 +4684,47 @@
     return( status );
 }
 
+psa_status_t psa_key_agreement_raw_shared_secret( psa_algorithm_t alg,
+                                                  psa_key_handle_t private_key,
+                                                  const uint8_t *peer_key,
+                                                  size_t peer_key_length,
+                                                  uint8_t *output,
+                                                  size_t output_size,
+                                                  size_t *output_length )
+{
+    psa_key_slot_t *slot;
+    psa_status_t status;
+
+    if( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) )
+    {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto exit;
+    }
+    status = psa_get_key_from_slot( private_key, &slot,
+                                    PSA_KEY_USAGE_DERIVE, alg );
+    if( status != PSA_SUCCESS )
+        goto exit;
+
+    status = psa_key_agreement_raw_internal( alg, slot,
+                                             peer_key, peer_key_length,
+                                             output, output_size,
+                                             output_length );
+
+exit:
+    if( status != PSA_SUCCESS )
+    {
+        /* If an error happens and is not handled properly, the output
+         * may be used as a key to protect sensitive data. Arrange for such
+         * a key to be random, which is likely to result in decryption or
+         * verification errors. This is better than filling the buffer with
+         * some constant data such as zeros, which would result in the data
+         * being protected with a reproducible, easily knowable key.
+         */
+        psa_generate_random( output, output_size );
+        *output_length = output_size;
+    }
+    return( status );
+}
 
 
 /****************************************************************/