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.
This commit is contained in:
Gilles Peskine 2019-07-22 19:30:34 +02:00
parent c8336cb8f9
commit fc76265385
2 changed files with 89 additions and 10 deletions

View file

@ -950,7 +950,20 @@ psa_status_t psa_destroy_key( psa_key_handle_t handle )
#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 @@ psa_status_t psa_destroy_key( psa_key_handle_t handle )
}
#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 @@ static psa_status_t psa_start_key_creation(
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 @@ static psa_status_t psa_start_key_creation(
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 @@ static psa_status_t psa_finish_key_creation(
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 @@ static void psa_fail_key_creation( psa_key_slot_t *slot,
* 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 @@ psa_status_t psa_crypto_init( void )
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;

View file

@ -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 @@ typedef uint16_t psa_crypto_transaction_type_t;
*/
#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 @@ typedef union
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.