New API function: psa_key_agreement

Set up a generator from a key agreement.
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index 5759a15..d321e68 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -435,6 +435,18 @@
 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
 derive_key_policy:PSA_KEY_USAGE_DERIVE:PSA_ALG_HKDF(PSA_ALG_SHA_256):PSA_KEY_TYPE_DERIVE:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HKDF(PSA_ALG_SHA_224)
 
+PSA key policy: agreement, permitted
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C
+agreement_key_policy:PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH(PSA_ALG_SELECT_RAW):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_ALG_ECDH(PSA_ALG_SELECT_RAW)
+
+PSA key policy: agreement, not permitted
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C
+agreement_key_policy:0:PSA_ALG_ECDH(PSA_ALG_SELECT_RAW):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_ALG_ECDH(PSA_ALG_SELECT_RAW)
+
+PSA key policy: agreement, wrong algorithm
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C
+agreement_key_policy:PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH(PSA_ALG_SELECT_RAW):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_ALG_FFDH(PSA_ALG_SELECT_RAW)
+
 PSA key lifetime: set and get volatile
 key_lifetime:PSA_KEY_LIFETIME_VOLATILE
 
@@ -1525,6 +1537,14 @@
 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
 derive_key_export:PSA_ALG_HKDF(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":1:41
 
+PSA key agreement setup: ECDH, unknown KDF
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C
+key_agreement_setup:PSA_ALG_ECDH(0):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"3078020101042100c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433a00a06082a8648ce3d030107a14403420004dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":"3059301306072a8648ce3d020106082a8648ce3d03010703420004d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":PSA_ERROR_NOT_SUPPORTED
+
+PSA key agreement setup: not a key agreement algorithm
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C
+key_agreement_setup:PSA_ALG_HKDF( PSA_ALG_SHA_256 ):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"3078020101042100c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433a00a06082a8648ce3d030107a14403420004dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":"3059301306072a8648ce3d020106082a8648ce3d03010703420004d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":PSA_ERROR_INVALID_ARGUMENT
+
 PSA generate random: 0 bytes
 generate_random:0
 
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index d2875ae..b7b7c4c 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -392,6 +392,51 @@
     return( 0 );
 }
 
+static int exercise_key_agreement_key( psa_key_slot_t key,
+                                       psa_key_usage_t usage,
+                                       psa_algorithm_t alg )
+{
+    psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT;
+    psa_key_type_t key_type;
+    psa_key_type_t public_key_type;
+    size_t key_bits;
+    uint8_t *public_key = NULL;
+    size_t public_key_length;
+    unsigned char output[1];
+    int ok = 0;
+
+    if( usage & PSA_KEY_USAGE_DERIVE )
+    {
+        /* We need two keys to exercise key agreement. Exercise the
+         * private key against its own public key. */
+        TEST_ASSERT( psa_get_key_information( key,
+                                              &key_type,
+                                              &key_bits ) == PSA_SUCCESS );
+        public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR( key_type );
+        public_key_length = PSA_KEY_EXPORT_MAX_SIZE( public_key_type,
+                                                     key_bits );
+        public_key = mbedtls_calloc( 1, public_key_length );
+        TEST_ASSERT( public_key != NULL );
+        TEST_ASSERT(
+            psa_export_public_key( key,
+                                   public_key, public_key_length,
+                                   &public_key_length ) == PSA_SUCCESS );
+        TEST_ASSERT( psa_key_agreement( &generator,
+                                        key,
+                                        public_key, public_key_length,
+                                        alg ) == PSA_SUCCESS );
+        TEST_ASSERT( psa_generator_read( &generator,
+                                         output,
+                                         sizeof( output ) ) == PSA_SUCCESS );
+        TEST_ASSERT( psa_generator_abort( &generator ) == PSA_SUCCESS );
+    }
+    ok = 1;
+
+exit:
+    mbedtls_free( public_key );
+    return( ok );
+}
+
 static int is_oid_of_key_type( psa_key_type_t type,
                                const uint8_t *oid, size_t oid_length )
 {
@@ -737,6 +782,8 @@
         ok = exercise_asymmetric_encryption_key( slot, usage, alg );
     else if( PSA_ALG_IS_KEY_DERIVATION( alg ) )
         ok = exercise_key_derivation_key( slot, usage, alg );
+    else if( PSA_ALG_IS_KEY_AGREEMENT( alg ) )
+        ok = exercise_key_agreement_key( slot, usage, alg );
     else
     {
         char message[40];
@@ -1271,6 +1318,7 @@
             PSA_KEY_USAGE_ENCRYPT :
             PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ) :
           PSA_ALG_IS_KEY_DERIVATION( alg ) ? PSA_KEY_USAGE_DERIVE :
+          PSA_ALG_IS_KEY_AGREEMENT( alg ) ? PSA_KEY_USAGE_DERIVE :
           0 );
     psa_key_policy_t policy;
     psa_key_type_t got_type;
@@ -1643,6 +1691,61 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void agreement_key_policy( int policy_usage,
+                           int policy_alg,
+                           int key_type_arg,
+                           data_t *key_data,
+                           int exercise_alg )
+{
+    int key_slot = 1;
+    psa_key_policy_t policy;
+    psa_key_type_t key_type = key_type_arg;
+    psa_key_type_t public_key_type;
+    size_t key_bits;
+    uint8_t *public_key = NULL;
+    size_t public_key_length;
+    psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT;
+    psa_status_t status;
+
+    TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS );
+
+    psa_key_policy_init( &policy );
+    psa_key_policy_set_usage( &policy, policy_usage, policy_alg );
+    TEST_ASSERT( psa_set_key_policy( key_slot, &policy ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_import_key( key_slot, key_type,
+                                 key_data->x, key_data->len ) == PSA_SUCCESS );
+
+    /* We need two keys to exercise key agreement. Exercise the
+     * private key against its own public key. */
+    TEST_ASSERT( psa_get_key_information( key_slot,
+                                          &key_type,
+                                          &key_bits ) == PSA_SUCCESS );
+    public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR( key_type );
+    public_key_length = PSA_KEY_EXPORT_MAX_SIZE( public_key_type, key_bits );
+    public_key = mbedtls_calloc( 1, public_key_length );
+    TEST_ASSERT( public_key != NULL );
+    TEST_ASSERT( psa_export_public_key( key_slot,
+                                        public_key, public_key_length,
+                                        &public_key_length ) == PSA_SUCCESS );
+
+    status = psa_key_agreement( &generator, key_slot,
+                                public_key, public_key_length,
+                                exercise_alg );
+    if( policy_alg == exercise_alg &&
+        ( policy_usage & PSA_KEY_USAGE_DERIVE ) != 0 )
+        TEST_ASSERT( status == PSA_SUCCESS );
+    else
+        TEST_ASSERT( status == PSA_ERROR_NOT_PERMITTED );
+
+exit:
+    psa_generator_abort( &generator );
+    psa_destroy_key( key_slot );
+    mbedtls_psa_crypto_free( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void key_lifetime( int lifetime_arg )
 {
     int key_slot = 1;
@@ -3656,6 +3759,39 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void key_agreement_setup( int alg_arg,
+                          int our_key_type_arg, data_t *our_key_data,
+                          data_t *peer_key_data,
+                          int expected_status_arg )
+{
+    psa_key_slot_t our_key = 1;
+    psa_algorithm_t alg = alg_arg;
+    psa_key_type_t our_key_type = our_key_type_arg;
+    psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT;
+    psa_key_policy_t policy;
+
+    TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS );
+
+    psa_key_policy_init( &policy );
+    psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
+    TEST_ASSERT( psa_set_key_policy( our_key, &policy ) == PSA_SUCCESS );
+    TEST_ASSERT( psa_import_key( our_key, our_key_type,
+                                 our_key_data->x,
+                                 our_key_data->len ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_key_agreement( &generator,
+                                    our_key,
+                                    peer_key_data->x, peer_key_data->len,
+                                    alg ) == expected_status_arg );
+
+exit:
+    psa_generator_abort( &generator );
+    psa_destroy_key( our_key );
+    mbedtls_psa_crypto_free( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void generate_random( int bytes_arg )
 {
     size_t bytes = bytes_arg;