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;