psa: Implement persistent keys

Allow use of persistent keys, including configuring them, importing and
exporting them, and destroying them.

When getting a slot using psa_get_key_slot, there are 3 scenarios that
can occur if the keys lifetime is persistent:

1. Key type is PSA_KEY_TYPE_NONE, no persistent storage entry:
   -  The key slot is treated as a standard empty key slot
2. Key type is PSA_KEY_TYPE_NONE, persistent storage entry exists:
   -  Attempt to load the key from persistent storage
3. Key type is not PSA_KEY_TYPE_NONE:
   -  As checking persistent storage on every use of the key could
      be expensive, the persistent key is assumed to be saved in
      persistent storage, the in-memory key is continued to be used.
diff --git a/crypto/tests/Makefile b/crypto/tests/Makefile
index 2f68e86..cc4355b 100644
--- a/crypto/tests/Makefile
+++ b/crypto/tests/Makefile
@@ -16,12 +16,14 @@
 APPS := \
 	test_suite_psa_crypto \
 	test_suite_psa_crypto_metadata \
+	test_suite_psa_crypto_persistent_key \
 	test_suite_psa_crypto_storage_file \
 # Don't delete this line.
 
 # Look up for associated function files
 func.test_suite_psa_crypto := test_suite_psa_crypto
 func.test_suite_psa_crypto_metadata := test_suite_psa_crypto_metadata
+func.test_suite_psa_crypto_persistent_key := test_suite_psa_crypto_persistent_key
 func.test_suite_psa_crypto_storage_file := test_suite_psa_crypto_storage_file
 
 .SILENT:
@@ -58,6 +60,7 @@
 test: $(APPS)
 	./test_suite_psa_crypto_metadata
 	./test_suite_psa_crypto
+	./test_suite_psa_crypto_persistent_key
 	./test_suite_psa_crypto_storage_file
 
 # Create separate targets for generating embedded tests.
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index d1a3f0f..1ca6492 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -1441,6 +1441,7 @@
  * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
  * \retval #PSA_ERROR_INSUFFICIENT_STORAGE
  * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_STORAGE_FAILURE
  * \retval #PSA_ERROR_HARDWARE_FAILURE
  * \retval #PSA_ERROR_TAMPERING_DETECTED
  * \retval #PSA_ERROR_BAD_STATE
@@ -1922,6 +1923,16 @@
  * whether the lifetime of an occupied key slot can be changed, is
  * implementation-dependent.
  *
+ * When creating a persistent key, you must call this function before creating
+ * the key material with psa_import_key(), psa_generate_key() or
+ * psa_generator_import_key(). To open an existing persistent key, you must
+ * call this function with the correct lifetime value before using the slot
+ * for a cryptographic operation. Once a slot's lifetime has been set,
+ * the lifetime remains associated with the slot until a subsequent call to
+ * psa_set_key_lifetime(), until the key is wiped with psa_destroy_key or
+ * until the application terminates (or disconnects from the cryptography
+ * service, if the implementation offers such a possibility).
+ *
  * \param key           Slot whose lifetime is to be changed.
  * \param lifetime      The lifetime value to set for the given key slot.
  *
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index c205e12..6b08983 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -43,6 +43,10 @@
 
 #include "psa/crypto.h"
 
+/* Include internal declarations that are useful for implementing persistently
+ * stored keys. */
+#include "psa_crypto_storage.h"
+
 #include <stdlib.h>
 #include <string.h>
 #if defined(MBEDTLS_PLATFORM_C)
@@ -702,6 +706,27 @@
     return( PSA_SUCCESS );
 }
 
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+static psa_status_t psa_load_persistent_key_into_slot( psa_key_slot_t key,
+                                                       key_slot_t *p_slot )
+{
+    psa_status_t status = PSA_SUCCESS;
+    uint8_t *key_data = NULL;
+    size_t key_data_length = 0;
+
+    status = psa_load_persistent_key( key, &( p_slot )->type,
+                                      &( p_slot )->policy, &key_data,
+                                      &key_data_length );
+    if( status != PSA_SUCCESS )
+        goto exit;
+    status = psa_import_key_into_slot( p_slot,
+                                       key_data, key_data_length );
+exit:
+    psa_free_persistent_key_data( key_data, key_data_length );
+    return( status );
+}
+#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
+
 /* Retrieve a key slot, occupied or not. */
 static psa_status_t psa_get_key_slot( psa_key_slot_t key,
                                       key_slot_t **p_slot )
@@ -715,6 +740,23 @@
         return( PSA_ERROR_INVALID_ARGUMENT );
 
     *p_slot = &global_data.key_slots[key - 1];
+
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+    if( ( *p_slot )->lifetime == PSA_KEY_LIFETIME_PERSISTENT )
+    {
+        /* There are two circumstances this can occur: the key material has
+         * not yet been created, or the key exists in storage but has not yet
+         * been loaded into memory. */
+        if( ( *p_slot )->type == PSA_KEY_TYPE_NONE )
+        {
+            psa_status_t status = PSA_SUCCESS;
+            status = psa_load_persistent_key_into_slot( key, *p_slot );
+            if( status != PSA_ERROR_EMPTY_SLOT )
+                return( status );
+        }
+    }
+#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
+
     return( PSA_SUCCESS );
 }
 
@@ -830,18 +872,44 @@
         return( status );
     }
 
-    return( PSA_SUCCESS );
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+    if( slot->lifetime == PSA_KEY_LIFETIME_PERSISTENT )
+    {
+        /* Store in file location */
+        status = psa_save_persistent_key( key, slot->type, &slot->policy, data,
+                                          data_length );
+        if( status != PSA_SUCCESS )
+        {
+            (void) psa_remove_key_data_from_memory( slot );
+            slot->type = PSA_KEY_TYPE_NONE;
+        }
+    }
+#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
+
+    return( status );
 }
 
 psa_status_t psa_destroy_key( psa_key_slot_t key )
 {
     key_slot_t *slot;
-    psa_status_t status;
+    psa_status_t status = PSA_SUCCESS;
+    psa_status_t storage_status = PSA_SUCCESS;
 
     status = psa_get_key_slot( key, &slot );
     if( status != PSA_SUCCESS )
         return( status );
-    return( psa_remove_key_from_memory( slot ) );
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+    if( slot->lifetime == PSA_KEY_LIFETIME_PERSISTENT )
+    {
+        storage_status = psa_destroy_persistent_key( key );
+    }
+#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
+    status = psa_remove_key_data_from_memory( slot );
+    /* Zeroize the slot to wipe metadata such as policies. */
+    mbedtls_zeroize( slot, sizeof( *slot ) );
+    if( status != PSA_SUCCESS )
+        return( status );
+    return( storage_status );
 }
 
 /* Return the size of the key in the given slot, in bits. */
@@ -2974,16 +3042,21 @@
 
     if( lifetime != PSA_KEY_LIFETIME_VOLATILE &&
         lifetime != PSA_KEY_LIFETIME_PERSISTENT &&
-        lifetime != PSA_KEY_LIFETIME_WRITE_ONCE)
+        lifetime != PSA_KEY_LIFETIME_WRITE_ONCE )
         return( PSA_ERROR_INVALID_ARGUMENT );
 
     status = psa_get_empty_key_slot( key, &slot );
     if( status != PSA_SUCCESS )
         return( status );
 
-    if( lifetime != PSA_KEY_LIFETIME_VOLATILE )
+    if( lifetime == PSA_KEY_LIFETIME_WRITE_ONCE )
         return( PSA_ERROR_NOT_SUPPORTED );
 
+#if !defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+    if( lifetime == PSA_KEY_LIFETIME_PERSISTENT )
+        return( PSA_ERROR_NOT_SUPPORTED );
+#endif
+
     slot->lifetime = lifetime;
 
     return( PSA_SUCCESS );
diff --git a/scripts/mbed_crypto.make b/scripts/mbed_crypto.make
index ab54d55..f51f5f8 100644
--- a/scripts/mbed_crypto.make
+++ b/scripts/mbed_crypto.make
@@ -158,6 +158,8 @@
 	tests/suites/test_suite_psa_crypto_hash.function \
 	tests/suites/test_suite_psa_crypto_metadata.data \
 	tests/suites/test_suite_psa_crypto_metadata.function \
+	tests/suites/test_suite_psa_crypto_persistent_key.data \
+	tests/suites/test_suite_psa_crypto_persistent_key.function \
 	tests/suites/test_suite_psa_crypto_storage_file.data \
 	tests/suites/test_suite_psa_crypto_storage_file.function \
 # Don't delete this line.
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 7af7fcf..34658c8 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -113,6 +113,7 @@
 add_test_suite(psa_crypto)
 add_test_suite(psa_crypto_hash)
 add_test_suite(psa_crypto_metadata)
+add_test_suite(psa_crypto_persistent_key)
 add_test_suite(psa_crypto_storage_file)
 add_test_suite(shax)
 add_test_suite(ssl)
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index ea214d2..7e70de3 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -1834,3 +1834,7 @@
 
 PSA validate module initialization: key based
 validate_module_init_key_based:
+
+persistent key can be accessed after in-memory deletion: AES, 128 bits, CTR
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PSA_CRYPTO_STORAGE_C
+persistent_key_load_key_from_storage:"2b7e151628aed2a6abf7158809cf4f3c":PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_EXPORT:PSA_ALG_CTR
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 674a6e9..4692dbe 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -4030,3 +4030,84 @@
     TEST_ASSERT( status == PSA_ERROR_BAD_STATE );
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */
+void persistent_key_load_key_from_storage( data_t *data, int type_arg,
+                                           int bits, int usage_arg,
+                                           int alg_arg )
+{
+    psa_key_slot_t slot = 1;
+    psa_key_type_t type = (psa_key_type_t) type_arg;
+    psa_key_type_t type_get;
+    size_t bits_get;
+    psa_key_policy_t policy_set;
+    psa_key_policy_t policy_get;
+    psa_key_usage_t policy_usage = (psa_key_usage_t) usage_arg;
+    psa_algorithm_t policy_alg = (psa_algorithm_t) alg_arg;
+    unsigned char *first_export = NULL;
+    unsigned char *second_export = NULL;
+    size_t export_size = PSA_KEY_EXPORT_MAX_SIZE( type, bits );
+    size_t first_exported_length;
+    size_t second_exported_length;
+
+    ASSERT_ALLOC( first_export, export_size );
+    ASSERT_ALLOC( second_export, export_size );
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_set_key_lifetime(
+        slot, PSA_KEY_LIFETIME_PERSISTENT ) == PSA_SUCCESS );
+
+    psa_key_policy_init( &policy_set );
+
+    psa_key_policy_set_usage( &policy_set, policy_usage,
+                              policy_alg );
+
+    TEST_ASSERT( psa_set_key_policy( slot, &policy_set ) == PSA_SUCCESS );
+
+    /* Import the key */
+    TEST_ASSERT( psa_import_key( slot, type,
+                                 data->x, data->len ) == PSA_SUCCESS );
+
+    /* Export the key */
+    TEST_ASSERT( psa_export_key( slot, first_export, export_size,
+                                 &first_exported_length ) == PSA_SUCCESS );
+
+    /* Shutdown and restart */
+    mbedtls_psa_crypto_free();
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    /* Mark slot as persistent again */
+    TEST_ASSERT( psa_set_key_lifetime(
+        slot, PSA_KEY_LIFETIME_PERSISTENT ) == PSA_SUCCESS );
+
+    /* Check key slot still contains key data */
+    TEST_ASSERT( psa_get_key_information(
+        slot, &type_get, &bits_get ) == PSA_SUCCESS );
+    TEST_ASSERT( type_get == type );
+    TEST_ASSERT( bits_get == (size_t) bits );
+
+    TEST_ASSERT( psa_get_key_policy( slot, &policy_get ) == PSA_SUCCESS );
+    TEST_ASSERT( psa_key_policy_get_usage(
+        &policy_get ) == policy_usage );
+    TEST_ASSERT( psa_key_policy_get_algorithm(
+        &policy_get ) == policy_alg );
+
+    /* Export the key again */
+    TEST_ASSERT( psa_export_key( slot, second_export, export_size,
+                                 &second_exported_length ) == PSA_SUCCESS );
+
+    ASSERT_COMPARE( first_export, first_exported_length,
+                    second_export, second_exported_length );
+
+    ASSERT_COMPARE( data->x, data->len,
+                    first_export, first_exported_length );
+
+exit:
+    mbedtls_free( first_export );
+    mbedtls_free( second_export );
+    psa_destroy_key( slot );
+    mbedtls_psa_crypto_free();
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.data b/tests/suites/test_suite_psa_crypto_persistent_key.data
new file mode 100644
index 0000000..46e547c
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_persistent_key.data
@@ -0,0 +1,78 @@
+PSA Storage format data for storage
+format_storage_data_check:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"505341004b45590000000000000001700100000000000012620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION
+
+PSA Storage parse stored data
+parse_storage_data_check:"505341004b45590000000000000001700100000000000012620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_SUCCESS
+
+PSA Storage parse stored data wrong version, should fail
+parse_storage_data_check:"505341004b455900ffffffff000001700100000000000012620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ERROR_STORAGE_FAILURE
+
+PSA Storage parse too big data, should fail
+parse_storage_data_check:"505341004b45590000000000000001700100000000000012ffffffff3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ERROR_STORAGE_FAILURE
+
+PSA Storage parse bad magic, should fail
+parse_storage_data_check:"645341004b45590000000000000001700100000000000012620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ERROR_STORAGE_FAILURE
+
+PSA Storage parse not enough magic, should fail
+parse_storage_data_check:"505341004b4559":"":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ERROR_STORAGE_FAILURE
+
+# Not specific to files, but only run this test in an environment where the maximum size could be reached.
+Save maximum size persistent raw key
+depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
+save_large_persistent_key:0:PSA_SUCCESS
+
+Save larger than maximum size persistent raw key, should fail
+save_large_persistent_key:1:PSA_ERROR_INSUFFICIENT_STORAGE
+
+Persistent key is configurable
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+persistent_key_is_configurable:1:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24"
+
+Persistent key destroy
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+persistent_key_destroy:1:1:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RAW_DATA:"deadbeef"
+
+Persistent key destroy missing key
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+persistent_key_destroy:1:0:PSA_KEY_TYPE_RSA_KEYPAIR:"":PSA_KEY_TYPE_RAW_DATA:"deadbeef"
+
+Key lifetime defaults to volatile
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+default_volatile_lifetime:1:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24"
+
+Persistent key import
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+persistent_key_import:1:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_SUCCESS
+
+Persistent key import garbage data, should fail
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+persistent_key_import:1:PSA_KEY_TYPE_RSA_KEYPAIR:"11111111":PSA_ERROR_INVALID_ARGUMENT
+
+import/export persistent raw key: 0 byte
+import_export_persistent_key:"":PSA_KEY_TYPE_RAW_DATA:0:0
+
+import/export persistent raw key: 1 byte
+import_export_persistent_key:"2a":PSA_KEY_TYPE_RAW_DATA:8:0
+
+import/export persistent key RSA public key: good, 1024-bit
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+import_export_persistent_key:"30819f300d06092a864886f70d010101050003818d0030818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001":PSA_KEY_TYPE_RSA_PUBLIC_KEY:1024:0
+
+import/export persistent key RSA keypair: good, 1024-bit
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+import_export_persistent_key:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEYPAIR:1024:0
+
+import/export persistent raw key file not exist: 1 byte
+import_export_persistent_key:"2a":PSA_KEY_TYPE_RAW_DATA:8:1
+
+import/export persistent key RSA public key file not exist: 1024-bit
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+import_export_persistent_key:"30819f300d06092a864886f70d010101050003818d0030818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001":PSA_KEY_TYPE_RSA_PUBLIC_KEY:1024:1
+
+import/export persistent key RSA keypair file not exist: 1024-bit
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+import_export_persistent_key:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEYPAIR:1024:1
+
+PSA import/export-persistent symmetric key: 16 bytes
+depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
+import_export_persistent_key:"2b7e151628aed2a6abf7158809cf4f3c":PSA_KEY_TYPE_AES:128:0
diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.function b/tests/suites/test_suite_psa_crypto_persistent_key.function
new file mode 100644
index 0000000..505f1f9
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_persistent_key.function
@@ -0,0 +1,341 @@
+/* BEGIN_HEADER */
+#include <stdint.h>
+#include "psa/crypto.h"
+#include "psa_crypto_storage.h"
+#include "psa_crypto_storage_backend.h"
+#include "mbedtls/md.h"
+
+#define PSA_KEY_STORAGE_MAGIC_HEADER "PSA\0KEY"
+#define PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH ( sizeof( PSA_KEY_STORAGE_MAGIC_HEADER ) )
+
+typedef struct {
+    uint8_t magic[PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH];
+    uint8_t version[4];
+    uint8_t type[sizeof( psa_key_type_t )];
+    uint8_t policy[sizeof( psa_key_policy_t )];
+    uint8_t data_len[4];
+    uint8_t key_data[];
+} psa_persistent_key_storage_format;
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_PSA_CRYPTO_STORAGE_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE */
+void format_storage_data_check( data_t *key_data,
+                                data_t *expected_file_data,
+                                int key_type, int key_usage, int key_alg )
+{
+    uint8_t *file_data;
+    size_t file_data_length;
+    psa_key_policy_t key_policy;
+
+    key_policy.usage = (psa_key_usage_t) key_usage;
+    key_policy.alg = (psa_algorithm_t) key_alg;
+
+    file_data_length = key_data->len + sizeof( psa_persistent_key_storage_format );
+    file_data = mbedtls_calloc( 1, file_data_length );
+    psa_format_key_data_for_storage( key_data->x, key_data->len,
+                                     (psa_key_type_t) key_type, &key_policy,
+                                     file_data );
+
+    ASSERT_COMPARE( expected_file_data->x, expected_file_data->len,
+                    file_data, file_data_length );
+    mbedtls_free( file_data );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void parse_storage_data_check( data_t *file_data,
+                               data_t *expected_key_data,
+                               int expected_key_type,
+                               int expected_key_usage,
+                               int expected_key_alg,
+                               int expected_status )
+{
+    uint8_t *key_data = NULL;
+    size_t key_data_length = 0;
+    psa_key_type_t key_type = 0;
+    psa_key_policy_t key_policy;
+    psa_status_t status;
+
+    status = psa_parse_key_data_from_storage( file_data->x, file_data->len,
+                                              &key_data, &key_data_length,
+                                              &key_type, &key_policy );
+
+    TEST_ASSERT( status == expected_status );
+    if( status != PSA_SUCCESS )
+        goto exit;
+
+    TEST_ASSERT( key_type == (psa_key_type_t) expected_key_type );
+    TEST_ASSERT( key_policy.usage == (uint32_t) expected_key_usage );
+    TEST_ASSERT( key_policy.alg == (uint32_t) expected_key_alg );
+    ASSERT_COMPARE( expected_key_data->x, expected_key_data->len,
+                    key_data, key_data_length );
+
+exit:
+    mbedtls_free( key_data );
+}
+/* END_CASE */
+
+
+/* BEGIN_CASE */
+void save_large_persistent_key( int data_too_large, int expected_status )
+{
+    psa_key_slot_t slot = 1;
+    uint8_t *data = NULL;
+    size_t data_length = PSA_CRYPTO_MAX_STORAGE_SIZE;
+
+    if( data_too_large )
+        data_length += 1;
+
+    ASSERT_ALLOC( data, data_length );
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_set_key_lifetime(
+        slot, PSA_KEY_LIFETIME_PERSISTENT ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_import_key( slot, PSA_KEY_TYPE_RAW_DATA,
+        data, data_length ) == expected_status );
+
+exit:
+    mbedtls_free( data );
+    psa_destroy_persistent_key( slot );
+    mbedtls_psa_crypto_free();
+}
+/* END_CASE */
+
+
+/* BEGIN_CASE */
+void persistent_key_is_configurable( int slot_arg, int type_arg,
+                                     data_t *data )
+{
+    psa_key_policy_t policy;
+    psa_key_lifetime_t lifetime;
+    psa_key_slot_t slot = (psa_key_slot_t) slot_arg;
+    psa_key_type_t type = (psa_key_type_t) type_arg;
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_set_key_lifetime(
+        slot, PSA_KEY_LIFETIME_PERSISTENT ) == PSA_SUCCESS );
+
+    psa_key_policy_init( &policy );
+
+    TEST_ASSERT( psa_set_key_policy( slot, &policy ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_import_key( slot, type,
+                                 data->x, data->len ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_get_key_lifetime( slot, &lifetime ) == PSA_SUCCESS );
+
+    TEST_ASSERT( lifetime == PSA_KEY_LIFETIME_PERSISTENT );
+
+exit:
+    psa_destroy_persistent_key( slot );
+    mbedtls_psa_crypto_free();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void persistent_key_destroy( int slot_arg, int should_store,
+                             int first_type_arg, data_t *first_data,
+                             int second_type_arg, data_t *second_data )
+{
+    psa_key_policy_t policy;
+    psa_key_slot_t slot = (psa_key_slot_t) slot_arg;
+    psa_key_type_t first_type = (psa_key_type_t) first_type_arg;
+    psa_key_type_t second_type = (psa_key_type_t) second_type_arg;
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_set_key_lifetime(
+        slot, PSA_KEY_LIFETIME_PERSISTENT ) == PSA_SUCCESS );
+
+    psa_key_policy_init( &policy );
+
+    if( should_store == 1 )
+    {
+        TEST_ASSERT( psa_import_key(
+            slot, first_type,
+            first_data->x, first_data->len ) == PSA_SUCCESS );
+    }
+
+    /* Destroy the key */
+    TEST_ASSERT( psa_destroy_key( slot ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_get_key_information(
+        slot, NULL, NULL ) == PSA_ERROR_EMPTY_SLOT );
+
+    /* Check key slot storage is removed */
+    TEST_ASSERT( psa_is_key_present_in_storage( slot ) == 0 );
+
+    /* Check destroying the key again doesn't report failure */
+    TEST_ASSERT( psa_destroy_key( slot ) == PSA_SUCCESS );
+    TEST_ASSERT( psa_get_key_information(
+        slot, NULL, NULL ) == PSA_ERROR_EMPTY_SLOT );
+
+    /* Shutdown and restart */
+    mbedtls_psa_crypto_free();
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    /* Mark slot as persistent again */
+    TEST_ASSERT( psa_set_key_lifetime(
+        slot, PSA_KEY_LIFETIME_PERSISTENT ) == PSA_SUCCESS );
+
+    /* Check key slot is empty */
+    TEST_ASSERT( psa_get_key_information(
+        slot, NULL, NULL ) == PSA_ERROR_EMPTY_SLOT );
+
+    /* Import different key data to ensure slot really was empty */
+    psa_key_policy_init( &policy );
+
+    psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_EXPORT,
+                              PSA_ALG_VENDOR_FLAG );
+
+    TEST_ASSERT( psa_set_key_policy( slot, &policy ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_import_key(
+        slot, second_type,
+        second_data->x, second_data->len ) == PSA_SUCCESS );
+
+exit:
+    psa_destroy_persistent_key( slot );
+    mbedtls_psa_crypto_free();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void default_volatile_lifetime( int slot_arg, int type_arg, data_t *data )
+{
+    psa_key_policy_t policy;
+    psa_key_slot_t slot = (psa_key_slot_t) slot_arg;
+    psa_key_type_t type = (psa_key_type_t) type_arg;
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    psa_key_policy_init( &policy );
+
+    TEST_ASSERT( psa_import_key( slot, type,
+                                 data->x, data->len ) == PSA_SUCCESS );
+
+    /* Shutdown and restart */
+    mbedtls_psa_crypto_free();
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    /* Check key slot is empty */
+    TEST_ASSERT( psa_get_key_information(
+        slot, NULL, NULL ) == PSA_ERROR_EMPTY_SLOT );
+
+exit:
+    psa_destroy_persistent_key( slot );
+    mbedtls_psa_crypto_free();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void persistent_key_import( int slot_arg, int type_arg, data_t *data,
+                            int expected_status )
+{
+    psa_key_policy_t policy;
+    psa_key_lifetime_t lifetime;
+    psa_key_slot_t slot = (psa_key_slot_t) slot_arg;
+    psa_key_type_t type = (psa_key_type_t) type_arg;
+
+    TEST_ASSERT( psa_crypto_init() == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_set_key_lifetime(
+        slot, PSA_KEY_LIFETIME_PERSISTENT ) == PSA_SUCCESS );
+
+    psa_key_policy_init( &policy );
+
+    TEST_ASSERT( psa_import_key( slot, type,
+                                 data->x, data->len ) == expected_status );
+
+    if( expected_status != PSA_SUCCESS )
+    {
+        TEST_ASSERT( psa_is_key_present_in_storage( slot ) == 0 );
+        goto exit;
+    }
+
+    TEST_ASSERT( psa_get_key_lifetime( slot, &lifetime ) == PSA_SUCCESS );
+
+    TEST_ASSERT( lifetime == PSA_KEY_LIFETIME_PERSISTENT );
+
+exit:
+    psa_destroy_persistent_key( slot );
+    mbedtls_psa_crypto_free();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void import_export_persistent_key( data_t *data, int type_arg,
+                                   int expected_bits, int key_not_exist )
+{
+    psa_key_slot_t slot = 1;
+    psa_key_type_t type = (psa_key_type_t) type_arg;
+    unsigned char *exported = NULL;
+    size_t export_size = data->len;
+    size_t exported_length;
+    psa_key_type_t got_type;
+    size_t got_bits;
+    psa_key_policy_t policy;
+    psa_key_lifetime_t lifetime_get;
+
+    ASSERT_ALLOC( exported, export_size );
+
+    TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_set_key_lifetime(
+        slot, PSA_KEY_LIFETIME_PERSISTENT ) == PSA_SUCCESS );
+
+    psa_key_policy_init( &policy );
+
+    psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_EXPORT,
+                              PSA_ALG_VENDOR_FLAG );
+
+    TEST_ASSERT( psa_set_key_policy( slot, &policy ) == PSA_SUCCESS );
+
+    /* Import the key */
+    TEST_ASSERT( psa_import_key( slot, type,
+                                 data->x, data->len ) == PSA_SUCCESS );
+
+    TEST_ASSERT( psa_get_key_lifetime(
+        slot, &lifetime_get ) == PSA_SUCCESS );
+    TEST_ASSERT( lifetime_get == PSA_KEY_LIFETIME_PERSISTENT );
+
+    /* Test the key information */
+    TEST_ASSERT( psa_get_key_information(
+        slot, &got_type, &got_bits ) == PSA_SUCCESS );
+    TEST_ASSERT( got_type == type );
+    TEST_ASSERT( got_bits == (size_t) expected_bits );
+
+    TEST_ASSERT( psa_is_key_present_in_storage( slot ) == 1 );
+
+    if( key_not_exist )
+    {
+        psa_destroy_persistent_key( slot );
+    }
+    /* Export the key */
+    TEST_ASSERT( psa_export_key( slot, exported, export_size,
+                                 &exported_length ) == PSA_SUCCESS );
+
+    ASSERT_COMPARE( data->x, data->len, exported, exported_length );
+
+    /* Destroy the key */
+    TEST_ASSERT( psa_destroy_key( slot ) == PSA_SUCCESS );
+    TEST_ASSERT( psa_get_key_information(
+                     slot, NULL, NULL ) == PSA_ERROR_EMPTY_SLOT );
+    TEST_ASSERT( psa_is_key_present_in_storage( slot ) == 0 );
+
+exit:
+    mbedtls_free( exported );
+    psa_destroy_persistent_key( slot );
+    mbedtls_psa_crypto_free( );
+}
+/* END_CASE */