diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 705462edaf..2af4032eff 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -93,6 +93,140 @@ psa_status_t psa_crypto_init(void);
 
 /**@}*/
 
+/** \defgroup policy Key policies
+ * @{
+ */
+
+/** The type of the key policy data structure.
+ *
+ * Before calling any function on a key policy, the application must initialize
+ * it by any of the following means:
+ * - Set the structure to all-bits-zero, for example:
+ *   \code
+ *   psa_key_policy_t policy;
+ *   memset(&policy, 0, sizeof(policy));
+ *   \endcode
+ * - Initialize the structure to logical zero values, for example:
+ *   \code
+ *   psa_key_policy_t policy = {0};
+ *   \endcode
+ * - Initialize the structure to the initializer #PSA_KEY_POLICY_INIT,
+ *   for example:
+ *   \code
+ *   psa_key_policy_t policy = PSA_KEY_POLICY_INIT;
+ *   \endcode
+ * - Assign the result of the function psa_key_policy_init()
+ *   to the structure, for example:
+ *   \code
+ *   psa_key_policy_t policy;
+ *   policy = psa_key_policy_init();
+ *   \endcode
+ *
+ * This is an implementation-defined \c struct. Applications should not
+ * make any assumptions about the content of this structure except
+ * as directed by the documentation of a specific implementation. */
+typedef struct psa_key_policy_s psa_key_policy_t;
+
+/** \def PSA_KEY_POLICY_INIT
+ *
+ * This macro returns a suitable initializer for a key policy object of type
+ * #psa_key_policy_t.
+ */
+#ifdef __DOXYGEN_ONLY__
+/* This is an example definition for documentation purposes.
+ * Implementations should define a suitable value in `crypto_struct.h`.
+ */
+#define PSA_KEY_POLICY_INIT {0}
+#endif
+
+/** Return an initial value for a key policy that forbids all usage of the key.
+ */
+static psa_key_policy_t psa_key_policy_init(void);
+
+/** \brief Set the standard fields of a policy structure.
+ *
+ * Note that this function does not make any consistency check of the
+ * parameters. The values are only checked when applying the policy to
+ * a key slot with psa_set_key_policy().
+ *
+ * \param[in,out] policy The key policy to modify. It must have been
+ *                       initialized as per the documentation for
+ *                       #psa_key_policy_t.
+ * \param usage          The permitted uses for the key.
+ * \param alg            The algorithm that the key may be used for.
+ */
+void psa_key_policy_set_usage(psa_key_policy_t *policy,
+                              psa_key_usage_t usage,
+                              psa_algorithm_t alg);
+
+/** \brief Retrieve the usage field of a policy structure.
+ *
+ * \param[in] policy    The policy object to query.
+ *
+ * \return The permitted uses for a key with this policy.
+ */
+psa_key_usage_t psa_key_policy_get_usage(const psa_key_policy_t *policy);
+
+/** \brief Retrieve the algorithm field of a policy structure.
+ *
+ * \param[in] policy    The policy object to query.
+ *
+ * \return The permitted algorithm for a key with this policy.
+ */
+psa_algorithm_t psa_key_policy_get_algorithm(const psa_key_policy_t *policy);
+
+/** \brief Set the usage policy on a key slot.
+ *
+ * This function must be called on an empty key slot, before importing,
+ * generating or creating a key in the slot. Changing the policy of an
+ * existing key is not permitted.
+ *
+ * Implementations may set restrictions on supported key policies
+ * depending on the key type and the key slot.
+ *
+ * \param handle        Handle to the key whose policy is to be changed.
+ * \param[in] policy    The policy object to query.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ *         If the key is persistent, it is implementation-defined whether
+ *         the policy has been saved to persistent storage. Implementations
+ *         may defer saving the policy until the key material is created.
+ * \retval #PSA_ERROR_INVALID_HANDLE
+ * \retval #PSA_ERROR_OCCUPIED_SLOT
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ * \retval #PSA_ERROR_TAMPERING_DETECTED
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_set_key_policy(psa_key_handle_t handle,
+                                const psa_key_policy_t *policy);
+
+/** \brief Get the usage policy for a key slot.
+ *
+ * \param handle        Handle to the key slot whose policy is being queried.
+ * \param[out] policy   On success, the key's policy.
+ *
+ * \retval #PSA_SUCCESS
+ * \retval #PSA_ERROR_INVALID_HANDLE
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ * \retval #PSA_ERROR_TAMPERING_DETECTED
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_get_key_policy(psa_key_handle_t handle,
+                                psa_key_policy_t *policy);
+
+/**@}*/
+
 /** \defgroup key_management Key management
  * @{
  */
@@ -545,139 +679,70 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
                                    size_t data_size,
                                    size_t *data_length);
 
-/**@}*/
-
-/** \defgroup policy Key policies
- * @{
- */
-
-/** The type of the key policy data structure.
+/** Make a copy of a key.
  *
- * Before calling any function on a key policy, the application must initialize
- * it by any of the following means:
- * - Set the structure to all-bits-zero, for example:
- *   \code
- *   psa_key_policy_t policy;
- *   memset(&policy, 0, sizeof(policy));
- *   \endcode
- * - Initialize the structure to logical zero values, for example:
- *   \code
- *   psa_key_policy_t policy = {0};
- *   \endcode
- * - Initialize the structure to the initializer #PSA_KEY_POLICY_INIT,
- *   for example:
- *   \code
- *   psa_key_policy_t policy = PSA_KEY_POLICY_INIT;
- *   \endcode
- * - Assign the result of the function psa_key_policy_init()
- *   to the structure, for example:
- *   \code
- *   psa_key_policy_t policy;
- *   policy = psa_key_policy_init();
- *   \endcode
+ * Copy key material from one location to another.
  *
- * This is an implementation-defined \c struct. Applications should not
- * make any assumptions about the content of this structure except
- * as directed by the documentation of a specific implementation. */
-typedef struct psa_key_policy_s psa_key_policy_t;
-
-/** \def PSA_KEY_POLICY_INIT
+ * This function is primarily useful to copy a key from one lifetime
+ * to another. The target key retains its lifetime and location.
  *
- * This macro returns a suitable initializer for a key policy object of type
- * #psa_key_policy_t.
- */
-#ifdef __DOXYGEN_ONLY__
-/* This is an example definition for documentation purposes.
- * Implementations should define a suitable value in `crypto_struct.h`.
- */
-#define PSA_KEY_POLICY_INIT {0}
-#endif
-
-/** Return an initial value for a key policy that forbids all usage of the key.
- */
-static psa_key_policy_t psa_key_policy_init(void);
-
-/** \brief Set the standard fields of a policy structure.
+ * In an implementation where slots have different ownerships,
+ * this functin may be used to share a key with a different party,
+ * subject to implementation-defined restrictions on key sharing.
+ * In this case \p constraint would typically prevent the recipient
+ * from exporting the key.
  *
- * Note that this function does not make any consistency check of the
- * parameters. The values are only checked when applying the policy to
- * a key slot with psa_set_key_policy().
+ * The resulting key may only be used in a way that conforms to all
+ * three of: the policy of the source key, the policy previously set
+ * on the target, and the \p constraint parameter passed when calling
+ * this function.
+ * - The usage flags on the resulting key are the bitwise-and of the
+ *   usage flags on the source policy, the previously-set target policy
+ *   and the policy constraint.
+ * - If all three policies allow the same algorithm or wildcard-based
+ *   algorithm policy, the resulting key has the same algorithm policy.
+ * - If one of the policies allows an algorithm and all the other policies
+ *   either allow the same algorithm or a wildcard-based algorithm policy
+ *   that includes this algorithm, the resulting key allows the same
+ *   algorithm.
  *
- * \param[in,out] policy The key policy to modify. It must have been
- *                       initialized as per the documentation for
- *                       #psa_key_policy_t.
- * \param usage          The permitted uses for the key.
- * \param alg            The algorithm that the key may be used for.
- */
-void psa_key_policy_set_usage(psa_key_policy_t *policy,
-                              psa_key_usage_t usage,
-                              psa_algorithm_t alg);
-
-/** \brief Retrieve the usage field of a policy structure.
+ * The effect of this function on implementation-defined metadata is
+ * implementation-defined.
  *
- * \param[in] policy    The policy object to query.
- *
- * \return The permitted uses for a key with this policy.
- */
-psa_key_usage_t psa_key_policy_get_usage(const psa_key_policy_t *policy);
-
-/** \brief Retrieve the algorithm field of a policy structure.
- *
- * \param[in] policy    The policy object to query.
- *
- * \return The permitted algorithm for a key with this policy.
- */
-psa_algorithm_t psa_key_policy_get_algorithm(const psa_key_policy_t *policy);
-
-/** \brief Set the usage policy on a key slot.
- *
- * This function must be called on an empty key slot, before importing,
- * generating or creating a key in the slot. Changing the policy of an
- * existing key is not permitted.
- *
- * Implementations may set restrictions on supported key policies
- * depending on the key type and the key slot.
- *
- * \param handle        Handle to the key whose policy is to be changed.
- * \param[in] policy    The policy object to query.
+ * \param source_handle     The key to copy. It must be a handle to an
+ *                          occupied slot.
+ * \param target_handle     A handle to the target slot. It must not contain
+ *                          key material yet.
+ * \param[in] constraint    An optional policy constraint. If this parameter
+ *                          is non-null then the resulting key will conform
+ *                          to this policy in addition to the source policy
+ *                          and the policy already present on the target
+ *                          slot. If this parameter is null then the
+ *                          function behaves in the same way as if it was
+ *                          the target policy, i.e. only the source and
+ *                          target policies apply.
  *
  * \retval #PSA_SUCCESS
- *         Success.
- *         If the key is persistent, it is implementation-defined whether
- *         the policy has been saved to persistent storage. Implementations
- *         may defer saving the policy until the key material is created.
  * \retval #PSA_ERROR_INVALID_HANDLE
  * \retval #PSA_ERROR_OCCUPIED_SLOT
- * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         \p target already contains key material.
+ * \retval #PSA_ERROR_EMPTY_SLOT
+ *         \p source does not contain key material.
  * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         The policy constraints on the source, on the target and
+ *         \p constraints are incompatible.
+ * \retval #PSA_ERROR_NOT_PERMITTED
+ *         The source key is not exportable and its lifetime does not
+ *         allow copying it to the target's lifetime.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_INSUFFICIENT_STORAGE
  * \retval #PSA_ERROR_COMMUNICATION_FAILURE
  * \retval #PSA_ERROR_HARDWARE_FAILURE
  * \retval #PSA_ERROR_TAMPERING_DETECTED
- * \retval #PSA_ERROR_BAD_STATE
- *         The library has not been previously initialized by psa_crypto_init().
- *         It is implementation-dependent whether a failure to initialize
- *         results in this error code.
  */
-psa_status_t psa_set_key_policy(psa_key_handle_t handle,
-                                const psa_key_policy_t *policy);
-
-/** \brief Get the usage policy for a key slot.
- *
- * \param handle        Handle to the key slot whose policy is being queried.
- * \param[out] policy   On success, the key's policy.
- *
- * \retval #PSA_SUCCESS
- * \retval #PSA_ERROR_INVALID_HANDLE
- * \retval #PSA_ERROR_COMMUNICATION_FAILURE
- * \retval #PSA_ERROR_HARDWARE_FAILURE
- * \retval #PSA_ERROR_TAMPERING_DETECTED
- * \retval #PSA_ERROR_BAD_STATE
- *         The library has not been previously initialized by psa_crypto_init().
- *         It is implementation-dependent whether a failure to initialize
- *         results in this error code.
- */
-psa_status_t psa_get_key_policy(psa_key_handle_t handle,
-                                psa_key_policy_t *policy);
+psa_status_t psa_copy_key(psa_key_handle_t source_handle,
+                          psa_key_handle_t target_handle,
+                          const psa_key_policy_t *constraint);
 
 /**@}*/
 
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 3a97f44b9d..eb4d43347a 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -713,6 +713,32 @@ static psa_status_t psa_get_empty_key_slot( psa_key_handle_t handle,
     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 @@ static int psa_key_policy_permits( const psa_key_policy_t *policy,
     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 @@ psa_status_t psa_get_key_information( psa_key_handle_t handle,
     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 @@ exit:
 }
 #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 );
+}
+
 
 
 /****************************************************************/
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.data b/tests/suites/test_suite_psa_crypto_slot_management.data
index e8ec40c4c6..72957589a2 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.data
+++ b/tests/suites/test_suite_psa_crypto_slot_management.data
@@ -65,6 +65,18 @@ Create not supported
 depends_on:!MBEDTLS_PSA_CRYPTO_STORAGE_C
 create_fail:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_ERROR_NOT_SUPPORTED
 
+Copy volatile to volatile
+copy_across_lifetimes:PSA_KEY_LIFETIME_VOLATILE:0:PSA_KEY_USAGE_EXPORT:0:PSA_KEY_TYPE_RAW_DATA:"4142434445":PSA_KEY_LIFETIME_VOLATILE:0:PSA_KEY_USAGE_EXPORT:0:-1:-1:PSA_KEY_USAGE_EXPORT:0
+
+Copy volatile to persistent
+copy_across_lifetimes:PSA_KEY_LIFETIME_VOLATILE:0:PSA_KEY_USAGE_EXPORT:0:PSA_KEY_TYPE_RAW_DATA:"4142434445":PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT:0:-1:-1:PSA_KEY_USAGE_EXPORT:0
+
+Copy persistent to volatile
+copy_across_lifetimes:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT:0:PSA_KEY_TYPE_RAW_DATA:"4142434445":PSA_KEY_LIFETIME_VOLATILE:0:PSA_KEY_USAGE_EXPORT:0:-1:-1:PSA_KEY_USAGE_EXPORT:0
+
+Copy persistent to persistent
+copy_across_lifetimes:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT:0:PSA_KEY_TYPE_RAW_DATA:"4142434445":PSA_KEY_LIFETIME_PERSISTENT:2:PSA_KEY_USAGE_EXPORT:0:-1:-1:PSA_KEY_USAGE_EXPORT:0
+
 Close/destroy invalid handle
 invalid_handle:
 
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function
index 46fafcc1d7..8a6ef07832 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.function
+++ b/tests/suites/test_suite_psa_crypto_slot_management.function
@@ -293,6 +293,115 @@ exit:
 }
 /* END_CASE */
 
+/* BEGIN_CASE */
+void copy_across_lifetimes( int source_lifetime_arg, int source_id_arg,
+                            int source_usage_arg, int source_alg_arg,
+                            int type_arg, data_t *material,
+                            int target_lifetime_arg, int target_id_arg,
+                            int target_usage_arg, int target_alg_arg,
+                            int constraint_usage_arg, int constraint_alg_arg,
+                            int expected_usage_arg, int expected_alg_arg )
+{
+    psa_key_lifetime_t source_lifetime = source_lifetime_arg;
+    psa_key_id_t source_id = source_id_arg;
+    psa_key_usage_t source_usage = source_usage_arg;
+    psa_algorithm_t source_alg = source_alg_arg;
+    psa_key_handle_t source_handle = 0;
+    psa_key_policy_t source_policy = PSA_KEY_POLICY_INIT;
+    psa_key_type_t source_type = type_arg;
+    size_t source_bits;
+    psa_key_lifetime_t target_lifetime = target_lifetime_arg;
+    psa_key_id_t target_id = target_id_arg;
+    psa_key_usage_t target_usage = target_usage_arg;
+    psa_algorithm_t target_alg = target_alg_arg;
+    psa_key_handle_t target_handle = 0;
+    psa_key_policy_t target_policy = PSA_KEY_POLICY_INIT;
+    psa_key_type_t target_type;
+    size_t target_bits;
+    psa_key_usage_t constraint_usage = constraint_usage_arg;
+    psa_algorithm_t constraint_alg = constraint_alg_arg;
+    psa_key_policy_t constraint = PSA_KEY_POLICY_INIT;
+    psa_key_policy_t *p_constraint = NULL;
+    psa_key_usage_t expected_usage = expected_usage_arg;
+    psa_algorithm_t expected_alg = expected_alg_arg;
+    uint8_t *export_buffer = NULL;
+
+    if( constraint_usage_arg != -1 )
+    {
+        p_constraint = &constraint;
+        psa_key_policy_set_usage( p_constraint,
+                                  constraint_usage, constraint_alg );
+    }
+    TEST_MAX_KEY_ID( source_id );
+    TEST_MAX_KEY_ID( target_id );
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    /* Populate the source slot. */
+    if( source_lifetime == PSA_KEY_LIFETIME_VOLATILE )
+        PSA_ASSERT( psa_allocate_key( &source_handle ) );
+    else
+        PSA_ASSERT( psa_create_key( source_lifetime, source_id,
+                                    &source_handle ) );
+    psa_key_policy_set_usage( &source_policy, source_usage, source_alg );
+    PSA_ASSERT( psa_set_key_policy( source_handle, &source_policy ) );
+    PSA_ASSERT( psa_import_key( source_handle, source_type,
+                                material->x, material->len ) );
+    PSA_ASSERT( psa_get_key_information( source_handle, NULL, &source_bits ) );
+
+    /* Prepare the target slot. */
+    if( target_lifetime == PSA_KEY_LIFETIME_VOLATILE )
+        PSA_ASSERT( psa_allocate_key( &target_handle ) );
+    else
+        PSA_ASSERT( psa_create_key( target_lifetime, target_id,
+                                    &target_handle ) );
+    psa_key_policy_set_usage( &target_policy, target_usage, target_alg );
+    PSA_ASSERT( psa_set_key_policy( target_handle, &target_policy ) );
+    target_policy = psa_key_policy_init();
+
+    /* Copy the key. */
+    PSA_ASSERT( psa_copy_key( source_handle, target_handle, p_constraint ) );
+
+    /* Destroy the source to ensure that this doesn't affect the target. */
+    PSA_ASSERT( psa_destroy_key( source_handle ) );
+
+    /* If the target key is persistent, restart the system to make
+     * sure that the material is still alive. */
+    if( target_lifetime != PSA_KEY_LIFETIME_VOLATILE )
+    {
+        mbedtls_psa_crypto_free( );
+        PSA_ASSERT( psa_crypto_init( ) );
+        PSA_ASSERT( psa_open_key( target_lifetime, target_id,
+                                  &target_handle ) );
+    }
+
+    /* Test that the target slot has the expected content. */
+    PSA_ASSERT( psa_get_key_information( target_handle,
+                                         &target_type, &target_bits ) );
+    TEST_ASSERT( source_type == target_type );
+    TEST_ASSERT( source_bits == target_bits );
+    PSA_ASSERT( psa_get_key_policy( target_handle, &target_policy ) );
+    TEST_ASSERT( expected_usage == psa_key_policy_get_usage( &target_policy ) );
+    TEST_ASSERT( expected_alg == psa_key_policy_get_algorithm( &target_policy ) );
+    if( expected_usage & PSA_KEY_USAGE_EXPORT )
+    {
+        size_t length;
+        ASSERT_ALLOC( export_buffer, material->len );
+        PSA_ASSERT( psa_export_key( target_handle, export_buffer,
+                                    material->len, &length ) );
+        ASSERT_COMPARE( material->x, material->len,
+                        export_buffer, length );
+    }
+
+exit:
+    mbedtls_psa_crypto_free( );
+    mbedtls_free( export_buffer );
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+    psa_purge_key_storage( );
+#endif
+}
+/* END_CASE */
+
 /* BEGIN_CASE */
 void invalid_handle( )
 {