New function psa_copy_key

Copy a key from one slot to another.

Implemented and smoke-tested.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 3a97f44..eb4d433 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -713,6 +713,32 @@
     return( status );
 }
 
+/** Calculate the intersection of two algorithm usage policies.
+ *
+ * Return 0 (which allows no operation) on incompatibility.
+ */
+static psa_algorithm_t psa_key_policy_algorithm_intersection(
+    psa_algorithm_t alg1,
+    psa_algorithm_t alg2 )
+{
+    /* Common case: the policy only allows alg. */
+    if( alg1 == alg2 )
+        return( alg1 );
+    /* If the policies are from the same hash-and-sign family, check
+     * if one is a wildcard. */
+    if( PSA_ALG_IS_HASH_AND_SIGN( alg1 ) &&
+        PSA_ALG_IS_HASH_AND_SIGN( alg2 ) &&
+        ( alg1 & ~PSA_ALG_HASH_MASK ) == ( alg2 & ~PSA_ALG_HASH_MASK ) )
+    {
+        if( PSA_ALG_SIGN_GET_HASH( alg1 ) == PSA_ALG_ANY_HASH )
+            return( alg2 );
+        if( PSA_ALG_SIGN_GET_HASH( alg1 ) == PSA_ALG_ANY_HASH )
+            return( alg1 );
+    }
+    /* If the policies are incompatible, allow nothing. */
+    return( 0 );
+}
+
 /** Test whether a policy permits an algorithm.
  *
  * The caller must test usage flags separately.
@@ -736,6 +762,18 @@
     return( 0 );
 }
 
+static psa_status_t psa_restrict_key_policy(
+    psa_key_policy_t *policy,
+    const psa_key_policy_t *constraint )
+{
+    psa_algorithm_t intersection_alg =
+        psa_key_policy_algorithm_intersection( policy->alg, constraint->alg );
+    if( intersection_alg == 0 && policy->alg != 0 && constraint->alg != 0 )
+        return( PSA_ERROR_INVALID_ARGUMENT );
+    policy->usage &= constraint->usage;
+    return( PSA_SUCCESS );
+}
+
 /** Retrieve a slot which must contain a key. The key must have allow all the
  * usage flags set in \p usage. If \p alg is nonzero, the key must allow
  * operations with this algorithm. */
@@ -923,11 +961,11 @@
     return( PSA_SUCCESS );
 }
 
-static  psa_status_t psa_internal_export_key( psa_key_slot_t *slot,
-                                              uint8_t *data,
-                                              size_t data_size,
-                                              size_t *data_length,
-                                              int export_public_key )
+static psa_status_t psa_internal_export_key( const psa_key_slot_t *slot,
+                                             uint8_t *data,
+                                             size_t data_size,
+                                             size_t *data_length,
+                                             int export_public_key )
 {
     *data_length = 0;
 
@@ -1110,6 +1148,65 @@
 }
 #endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
 
+static psa_status_t psa_copy_key_material( const psa_key_slot_t *source,
+                                           psa_key_handle_t target )
+{
+    psa_status_t status;
+    uint8_t *buffer = NULL;
+    size_t buffer_size = 0;
+    size_t length;
+
+    buffer_size = PSA_KEY_EXPORT_MAX_SIZE( source->type,
+                                           psa_get_key_bits( source ) );
+    buffer = mbedtls_calloc( 1, buffer_size );
+    if( buffer == NULL )
+    {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto exit;
+    }
+    status = psa_internal_export_key( source, buffer, buffer_size, &length, 0 );
+    if( status != PSA_SUCCESS )
+        goto exit;
+    status = psa_import_key( target, source->type, buffer, length );
+
+exit:
+    return( status );
+}
+
+psa_status_t psa_copy_key(psa_key_handle_t source_handle,
+                          psa_key_handle_t target_handle,
+                          const psa_key_policy_t *constraint)
+{
+    psa_key_slot_t *source_slot = NULL;
+    psa_key_slot_t *target_slot = NULL;
+    psa_key_policy_t new_policy;
+    psa_status_t status;
+    status = psa_get_key_from_slot( source_handle, &source_slot, 0, 0 );
+    if( status != PSA_SUCCESS )
+        return( status );
+    status = psa_get_empty_key_slot( target_handle, &target_slot );
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    new_policy = target_slot->policy;
+    status = psa_restrict_key_policy( &new_policy, &source_slot->policy );
+    if( status != PSA_SUCCESS )
+        return( status );
+    if( constraint != NULL )
+    {
+        status = psa_restrict_key_policy( &new_policy, constraint );
+        if( status != PSA_SUCCESS )
+            return( status );
+    }
+
+    status = psa_copy_key_material( source_slot, target_handle );
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    target_slot->policy = new_policy;
+    return( PSA_SUCCESS );
+}
+
 
 
 /****************************************************************/