Do secure element key creation and destruction in a transaction

Key creation and key destruction for a key in a secure element both
require updating three pieces of data: the key data in the secure
element, the key metadata in internal storage, and the SE driver's
persistent data. Perform these actions in a transaction so that
recovery is possible if the action is interrupted midway.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 77acf2e..c482747 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -950,7 +950,20 @@
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
     driver = psa_get_se_driver_entry( slot->lifetime );
     if( driver != NULL )
+    {
+        psa_crypto_prepare_transaction( PSA_CRYPTO_TRANSACTION_DESTROY_KEY );
+        psa_crypto_transaction.key.lifetime = slot->lifetime;
+        psa_crypto_transaction.key.slot = slot->data.se.slot_number;
+        psa_crypto_transaction.key.id = slot->persistent_storage_id;
+        status = psa_crypto_save_transaction( );
+        if( status != PSA_SUCCESS )
+        {
+            /* TOnogrepDO: destroy what can be destroyed anyway */
+            return( status );
+        }
+
         status = psa_destroy_se_key( driver, slot->data.se.slot_number );
+    }
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
@@ -961,6 +974,18 @@
     }
 #endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
 
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    if( driver != NULL )
+    {
+        status = psa_crypto_stop_transaction( );
+        if( status != PSA_SUCCESS )
+        {
+            /* TOnogrepDO: destroy what can be destroyed anyway */
+            return( status );
+        }
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
     status = psa_wipe_key_slot( slot );
     if( status != PSA_SUCCESS )
         return( status );
@@ -1382,8 +1407,10 @@
     slot->type = attributes->type;
 
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-    /* Find a slot number. Don't yet mark it as allocated in case
-     * the key creation fails or there is a power failure. */
+    /* Find a slot number for the new key. Save the slot number in
+     * persistent storage, but do not yet save the driver's persistent
+     * state, so that if the power fails during the key creation process,
+     * we can roll back to a state where the key doesn't exist. */
     if( *p_drv != NULL )
     {
         status = psa_find_se_slot_for_key( attributes, *p_drv,
@@ -1391,6 +1418,13 @@
         if( status != PSA_SUCCESS )
             return( status );
     }
+    psa_crypto_prepare_transaction( PSA_CRYPTO_TRANSACTION_CREATE_KEY );
+    psa_crypto_transaction.key.lifetime = slot->lifetime;
+    psa_crypto_transaction.key.slot = slot->data.se.slot_number;
+    psa_crypto_transaction.key.id = slot->persistent_storage_id;
+    status = psa_crypto_save_transaction( );
+    if( status != PSA_SUCCESS )
+        return( status );
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     return( status );
@@ -1459,6 +1493,9 @@
             psa_destroy_persistent_key( slot->persistent_storage_id );
             return( status );
         }
+        status = psa_crypto_stop_transaction( );
+        if( status != PSA_SUCCESS )
+            return( status );
     }
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
@@ -1490,6 +1527,11 @@
      * element, and the failure happened later (when saving metadata
      * to internal storage), we need to destroy the key in the secure
      * element. */
+
+    /* Abort the ongoing transaction if any. We already did what it
+     * takes to undo any partial creation. All that's left is to update
+     * the transaction data itself. */
+    (void) psa_crypto_stop_transaction( );
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     psa_wipe_key_slot( slot );
@@ -5674,6 +5716,19 @@
     if( status != PSA_SUCCESS )
         goto exit;
 
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    status = psa_crypto_load_transaction( );
+    if( status == PSA_SUCCESS )
+    {
+        /*TOnogrepDO: complete or abort the transaction*/
+    }
+    else if( status == PSA_ERROR_DOES_NOT_EXIST )
+    {
+        /* There's no transaction to complete. It's all good. */
+        status = PSA_SUCCESS;
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
     /* All done. */
     global_data.initialized = 1;
 
diff --git a/library/psa_crypto_storage.h b/library/psa_crypto_storage.h
index 16f5d5c..2e4079f 100644
--- a/library/psa_crypto_storage.h
+++ b/library/psa_crypto_storage.h
@@ -29,15 +29,9 @@
 extern "C" {
 #endif
 
-/* Include the Mbed TLS configuration file, the way Mbed TLS does it
- * in each of its header files. */
-#if defined(MBEDTLS_CONFIG_FILE)
-#include MBEDTLS_CONFIG_FILE
-#else
-#include "mbedtls/config.h"
-#endif
-
 #include "psa/crypto.h"
+#include "psa/crypto_se_driver.h"
+
 #include <stdint.h>
 #include <string.h>
 
@@ -223,6 +217,22 @@
  */
 #define PSA_CRYPTO_TRANSACTION_NONE             ( (psa_crypto_transaction_type_t) 0x0000 )
 
+/** A key creation transaction.
+ *
+ * This is only used for keys in an external cryptoprocessor (secure element).
+ * Keys in RAM or in internal storage are created atomically in storage
+ * (simple file creation), so they do not need a transaction mechanism.
+ */
+#define PSA_CRYPTO_TRANSACTION_CREATE_KEY       ( (psa_crypto_transaction_type_t) 0x0001 )
+
+/** A key destruction transaction.
+ *
+ * This is only used for keys in an external cryptoprocessor (secure element).
+ * Keys in RAM or in internal storage are destroyed atomically in storage
+ * (simple file deletion), so they do not need a transaction mechanism.
+ */
+#define PSA_CRYPTO_TRANSACTION_DESTROY_KEY      ( (psa_crypto_transaction_type_t) 0x0002 )
+
 /** Transaction data.
  *
  * This type is designed to be serialized by writing the memory representation
@@ -266,7 +276,21 @@
     struct psa_crypto_transaction_unknown_s
     {
         psa_crypto_transaction_type_t type;
+        uint16_t unused1;
+        uint32_t unused2;
+        uint64_t unused3;
+        uint64_t unused4;
     } unknown;
+    /* ::type is #PSA_CRYPTO_TRANSACTION_CREATE_KEY or
+     * #PSA_CRYPTO_TRANSACTION_DESTROY_KEY. */
+    struct psa_crypto_transaction_key_s
+    {
+        psa_crypto_transaction_type_t type;
+        uint16_t unused1;
+        psa_key_lifetime_t lifetime;
+        psa_key_slot_number_t slot;
+        psa_key_id_t id;
+    } key;
 } psa_crypto_transaction_t;
 
 /** The single active transaction.