SE drivers: implement persistent storage

Store the persistent data of secure element drivers.

This is fully implemented, but not at all tested.
diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c
index 7287ac0..bae44fa 100644
--- a/library/psa_crypto_se.c
+++ b/library/psa_crypto_se.c
@@ -35,6 +35,13 @@
 
 #include "psa_crypto_se.h"
 
+#if defined(MBEDTLS_PSA_ITS_FILE_C)
+#include "psa_crypto_its.h"
+#else /* Native ITS implementation */
+#include "psa/error.h"
+#include "psa/internal_trusted_storage.h"
+#endif
+
 #include "mbedtls/platform.h"
 #if !defined(MBEDTLS_PLATFORM_C)
 #define mbedtls_calloc calloc
@@ -114,20 +121,52 @@
 /* Persistent data management */
 /****************************************************************/
 
+static psa_status_t psa_get_se_driver_its_file_uid(
+    const psa_se_drv_table_entry_t *driver,
+    psa_storage_uid_t *uid )
+{
+    if( driver->lifetime > PSA_MAX_SE_LIFETIME )
+        return( PSA_ERROR_NOT_SUPPORTED );
+    *uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + driver->lifetime;
+    return( PSA_SUCCESS );
+}
+
 psa_status_t psa_load_se_persistent_data(
     const psa_se_drv_table_entry_t *driver )
 {
-    /*TODO*/
-    (void) driver;
-    return( PSA_SUCCESS );
+    psa_status_t status;
+    psa_storage_uid_t uid;
+
+    status = psa_get_se_driver_its_file_uid( driver, &uid );
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    return( psa_its_get( uid, 0, driver->internal.persistent_data_size,
+                         driver->internal.persistent_data ) );
 }
 
 psa_status_t psa_save_se_persistent_data(
     const psa_se_drv_table_entry_t *driver )
 {
-    /*TODO*/
-    (void) driver;
-    return( PSA_SUCCESS );
+    psa_status_t status;
+    psa_storage_uid_t uid;
+
+    status = psa_get_se_driver_its_file_uid( driver, &uid );
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    return( psa_its_set( uid, driver->internal.persistent_data_size,
+                         driver->internal.persistent_data,
+                         0 ) );
+}
+
+psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime )
+{
+    psa_storage_uid_t uid;
+    if( lifetime > PSA_MAX_SE_LIFETIME )
+        return( PSA_ERROR_NOT_SUPPORTED );
+    uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime;
+    return( psa_its_remove( uid ) );
 }
 
 psa_status_t psa_find_se_slot_for_key(
@@ -201,6 +240,8 @@
     {
         return( PSA_ERROR_INVALID_ARGUMENT );
     }
+    if( lifetime > PSA_MAX_SE_LIFETIME )
+        return( PSA_ERROR_NOT_SUPPORTED );
 
     for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
     {
@@ -227,8 +268,11 @@
             status = PSA_ERROR_INSUFFICIENT_MEMORY;
             goto error;
         }
+        /* Load the driver's persistent data. On first use, the persistent
+         * data does not exist in storage, and is initialized to
+         * all-bits-zero by the calloc call just above. */
         status = psa_load_se_persistent_data( &driver_table[i] );
-        if( status != PSA_SUCCESS )
+        if( status != PSA_SUCCESS && status != PSA_ERROR_DOES_NOT_EXIST )
             goto error;
     }
     driver_table[i].internal.persistent_data_size =
diff --git a/library/psa_crypto_se.h b/library/psa_crypto_se.h
index f1d7e7c..08e658c 100644
--- a/library/psa_crypto_se.h
+++ b/library/psa_crypto_se.h
@@ -31,6 +31,30 @@
 #include "psa/crypto.h"
 #include "psa/crypto_se_driver.h"
 
+/** The maximum lifetime value that this implementation supports
+ * for a secure element.
+ *
+ * This is not a characteristic that each PSA implementation has, but a
+ * limitation of the current implementation due to the constraints imposed
+ * by storage. See #PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE.
+ *
+ * The minimum lifetime value for a secure element is 2, like on any
+ * PSA implementation (0=volatile and 1=internal-storage are taken).
+ */
+#define PSA_MAX_SE_LIFETIME 255
+
+/** The base of the range of ITS file identifiers for secure element
+ * driver persistent data.
+ *
+ * We use a slice of the implemenation reserved range 0xffff0000..0xffffffff,
+ * specifically the range 0xfffffe00..0xfffffeff. The length of this range
+ * drives the value of #PSA_MAX_SE_LIFETIME.
+ * The identifiers 0xfffffe00 and 0xfffffe01 are actually not used since
+ * they correspond to #PSA_KEY_LIFETIME_VOLATILE and
+ * #PSA_KEY_LIFETIME_PERSISTENT which don't have a driver.
+ */
+#define PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE ( (psa_key_id_t) 0xfffffe00 )
+
 /** The maximum number of registered secure element driver lifetimes. */
 #define PSA_MAX_SE_DRIVERS 4
 
@@ -138,4 +162,13 @@
 psa_status_t psa_save_se_persistent_data(
     const psa_se_drv_table_entry_t *driver );
 
+/** Destroy the persistent data of a secure element driver.
+ *
+ * This is currently only used for testing.
+ *
+ * \param[in] lifetime  The driver lifetime whose persistent data should
+ *                      be erased.
+ */
+psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime );
+
 #endif /* PSA_CRYPTO_SE_H */
diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
index 5a2ebe7..010f696 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
@@ -119,13 +119,18 @@
 #define MAX_KEY_ID_FOR_TEST 10
 void psa_purge_storage( void )
 {
-    psa_key_id_t i;
+    psa_key_id_t id;
+    psa_key_lifetime_t lifetime;
     /* The tests may have potentially created key ids from 1 to
      * MAX_KEY_ID_FOR_TEST. In addition, run the destroy function on key id
      * 0, which file-based storage uses as a temporary file. */
-    for( i = 0; i <= MAX_KEY_ID_FOR_TEST; i++ )
-        psa_destroy_persistent_key( i );
+    for( id = 0; id <= MAX_KEY_ID_FOR_TEST; id++ )
+        psa_destroy_persistent_key( id );
+    /* Purge the transaction file. */
     psa_crypto_stop_transaction( );
+    /* Purge driver persistent data. */
+    for( lifetime = 0; lifetime < PSA_MAX_SE_LIFETIME; lifetime++ )
+        psa_destroy_se_persistent_data( lifetime );
 }
 
 /* END_HEADER */