psa: mgmt: Add key slot reuse

When looking for an empty key slot to store
the description of a key, if all key slots
are in use, reuse the first encountered
and unaccessed key slot containing the
description of a permanent key.

Signed-off-by: Ronald Cron <ronald.cron@arm.com>
diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c
index 9271e14..5a1fc74 100644
--- a/library/psa_crypto_slot_management.c
+++ b/library/psa_crypto_slot_management.c
@@ -173,27 +173,62 @@
 psa_status_t psa_get_empty_key_slot( psa_key_id_t *volatile_key_id,
                                      psa_key_slot_t **p_slot )
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     size_t slot_idx;
+    psa_key_slot_t *selected_slot, *unaccessed_permanent_key_slot;
 
     if( ! global_data.key_slots_initialized )
-        return( PSA_ERROR_BAD_STATE );
-
-    for( slot_idx = PSA_KEY_SLOT_COUNT; slot_idx > 0; slot_idx-- )
     {
-        *p_slot = &global_data.key_slots[ slot_idx - 1 ];
-        if( ! psa_is_key_slot_occupied( *p_slot ) )
-        {
-            *volatile_key_id = PSA_KEY_ID_VOLATILE_MIN +
-                               ( (psa_key_id_t)slot_idx ) - 1;
-
-            psa_increment_key_slot_access_count( *p_slot );
-
-            return( PSA_SUCCESS );
-        }
+        status = PSA_ERROR_BAD_STATE;
+        goto error;
     }
 
+    selected_slot = unaccessed_permanent_key_slot = NULL;
+    for( slot_idx = 0; slot_idx < PSA_KEY_SLOT_COUNT; slot_idx++ )
+    {
+        psa_key_slot_t *slot = &global_data.key_slots[ slot_idx ];
+        if( ! psa_is_key_slot_occupied( slot ) )
+        {
+            selected_slot = slot;
+            break;
+        }
+
+        if( ( unaccessed_permanent_key_slot == NULL ) &&
+            ( ! PSA_KEY_LIFETIME_IS_VOLATILE( slot->attr.lifetime ) ) &&
+            ( ! psa_is_key_slot_accessed( slot ) ) )
+            unaccessed_permanent_key_slot = slot;
+    }
+
+    /*
+     * If there is no unused key slot and there is at least one unaccessed key
+     * slot containing the description of a permament key, recycle the first
+     * such key slot we encountered. If we need later on to operate on the
+     * permanent key we evict now, we will reload its description from storage.
+     */
+    if( ( selected_slot == NULL ) &&
+        ( unaccessed_permanent_key_slot != NULL ) )
+    {
+        selected_slot = unaccessed_permanent_key_slot;
+        selected_slot->access_count = 1;
+        psa_wipe_key_slot( selected_slot );
+    }
+
+    if( selected_slot != NULL )
+    {
+        *volatile_key_id = PSA_KEY_ID_VOLATILE_MIN +
+            ( (psa_key_id_t)( selected_slot - global_data.key_slots ) );
+        *p_slot = selected_slot;
+        psa_increment_key_slot_access_count( selected_slot );
+
+        return( PSA_SUCCESS );
+    }
+    status = PSA_ERROR_INSUFFICIENT_MEMORY;
+
+error:
     *p_slot = NULL;
-    return( PSA_ERROR_INSUFFICIENT_MEMORY );
+    *volatile_key_id = 0;
+
+    return( status );
 }
 
 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)