Make library init and deinit more robust to errors
Allow mbedtls_psa_crypto_free to be called twice, or without a prior
call to psa_crypto_init. Keep track of the initialization state more
precisely in psa_crypto_init so that mbedtls_psa_crypto_free knows
what to do.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 291dcdb..4c0ac12 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -146,12 +146,21 @@
return( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) );
}
+enum rng_state
+{
+ RNG_NOT_INITIALIZED = 0,
+ RNG_INITIALIZED,
+ RNG_SEEDED,
+};
+
typedef struct
{
- int initialized;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
key_slot_t key_slots[PSA_KEY_SLOT_COUNT];
+ unsigned initialized : 1;
+ enum rng_state rng_state : 2;
+ unsigned key_slots_initialized : 1;
} psa_global_data_t;
static psa_global_data_t global_data;
@@ -4433,18 +4442,26 @@
psa_key_slot_t key;
key_slot_t *slot;
psa_status_t status;
-
- for( key = 1; key <= PSA_KEY_SLOT_COUNT; key++ )
+ if( global_data.key_slots_initialized )
{
- status = psa_get_key_slot( key, &slot );
- if( status != PSA_SUCCESS )
- continue;
- psa_remove_key_data_from_memory( slot );
- /* Zeroize the slot to wipe metadata such as policies. */
- mbedtls_zeroize( slot, sizeof( *slot ) );
+ for( key = 1; key <= PSA_KEY_SLOT_COUNT; key++ )
+ {
+ status = psa_get_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ continue;
+ psa_remove_key_data_from_memory( slot );
+ /* Zeroize the slot to wipe metadata such as policies. */
+ mbedtls_zeroize( slot, sizeof( *slot ) );
+ }
}
- mbedtls_ctr_drbg_free( &global_data.ctr_drbg );
- mbedtls_entropy_free( &global_data.entropy );
+ if( global_data.rng_state != RNG_NOT_INITIALIZED )
+ {
+ mbedtls_ctr_drbg_free( &global_data.ctr_drbg );
+ mbedtls_entropy_free( &global_data.entropy );
+ }
+ /* Wipe all remaining data, including configuration.
+ * In particular, this sets all state indicator to the value
+ * indicating "uninitialized". */
mbedtls_zeroize( &global_data, sizeof( global_data ) );
}
@@ -4453,20 +4470,30 @@
int ret;
const unsigned char drbg_seed[] = "PSA";
+ /* Double initialization is explicitly allowed. */
if( global_data.initialized != 0 )
return( PSA_SUCCESS );
mbedtls_zeroize( &global_data, sizeof( global_data ) );
+
+ /* Initialize the random generator. */
mbedtls_entropy_init( &global_data.entropy );
mbedtls_ctr_drbg_init( &global_data.ctr_drbg );
-
+ global_data.rng_state = RNG_INITIALIZED;
ret = mbedtls_ctr_drbg_seed( &global_data.ctr_drbg,
mbedtls_entropy_func,
&global_data.entropy,
drbg_seed, sizeof( drbg_seed ) - 1 );
if( ret != 0 )
goto exit;
+ global_data.rng_state = RNG_SEEDED;
+ /* Initialize the key slots. Zero-initialization has made all key
+ * slots empty, so there is nothing to do. In a future version we will
+ * load data from storage. */
+ global_data.key_slots_initialized = 1;
+
+ /* All done. */
global_data.initialized = 1;
exit:
diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data
index 61f067d..e441118 100644
--- a/tests/suites/test_suite_psa_crypto_init.data
+++ b/tests/suites/test_suite_psa_crypto_init.data
@@ -1,6 +1,12 @@
PSA init/deinit
init_deinit:2
+PSA deinit without init
+deinit_without_init:0
+
+PSA deinit twice
+deinit_without_init:1
+
No random without init
validate_module_init_generate_random:0
diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function
index 7fccc13..7cb10c0 100644
--- a/tests/suites/test_suite_psa_crypto_init.function
+++ b/tests/suites/test_suite_psa_crypto_init.function
@@ -30,6 +30,19 @@
/* END_CASE */
/* BEGIN_CASE */
+void deinit_without_init( int count )
+{
+ int i;
+ for( i = 0; i < count; i++ )
+ {
+ TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS );
+ mbedtls_psa_crypto_free( );
+ }
+ mbedtls_psa_crypto_free( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
void validate_module_init_generate_random( int count )
{
psa_status_t status;