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/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 );