mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-03-01 13:13:28 +00:00
Merge pull request #9464 from gilles-peskine-arm/psa-keystore-dynamic-development
dynamically sized key store
This commit is contained in:
commit
ab0af45d11
@ -1,3 +1,9 @@
|
|||||||
|
Features
|
||||||
|
* When the new compilation option MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled,
|
||||||
|
the number of volatile PSA keys is virtually unlimited, at the expense
|
||||||
|
of increased code size. This option is off by default, but enabled in
|
||||||
|
the default mbedtls_config.h. Fixes #9216.
|
||||||
|
|
||||||
Bugfix
|
Bugfix
|
||||||
* Fix interference between PSA volatile keys and built-in keys
|
* Fix interference between PSA volatile keys and built-in keys
|
||||||
when MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS is enabled and
|
when MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS is enabled and
|
||||||
|
@ -1232,6 +1232,23 @@
|
|||||||
*/
|
*/
|
||||||
//#define MBEDTLS_PSA_CRYPTO_SPM
|
//#define MBEDTLS_PSA_CRYPTO_SPM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def MBEDTLS_PSA_KEY_STORE_DYNAMIC
|
||||||
|
*
|
||||||
|
* Dynamically resize the PSA key store to accommodate any number of
|
||||||
|
* volatile keys (until the heap memory is exhausted).
|
||||||
|
*
|
||||||
|
* If this option is disabled, the key store has a fixed size
|
||||||
|
* #MBEDTLS_PSA_KEY_SLOT_COUNT for volatile keys and loaded persistent keys
|
||||||
|
* together.
|
||||||
|
*
|
||||||
|
* This option has no effect when #MBEDTLS_PSA_CRYPTO_C is disabled.
|
||||||
|
*
|
||||||
|
* Module: library/psa_crypto.c
|
||||||
|
* Requires: MBEDTLS_PSA_CRYPTO_C
|
||||||
|
*/
|
||||||
|
#define MBEDTLS_PSA_KEY_STORE_DYNAMIC
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uncomment to enable p256-m. This is an alternative implementation of
|
* Uncomment to enable p256-m. This is an alternative implementation of
|
||||||
* key generation, ECDH and (randomized) ECDSA on the curve SECP256R1.
|
* key generation, ECDH and (randomized) ECDSA on the curve SECP256R1.
|
||||||
@ -3825,9 +3842,13 @@
|
|||||||
|
|
||||||
/** \def MBEDTLS_PSA_KEY_SLOT_COUNT
|
/** \def MBEDTLS_PSA_KEY_SLOT_COUNT
|
||||||
*
|
*
|
||||||
* The maximum amount of PSA keys simultaneously in memory. This counts all
|
* When #MBEDTLS_PSA_KEY_STORE_DYNAMIC is disabled,
|
||||||
|
* the maximum amount of PSA keys simultaneously in memory. This counts all
|
||||||
* volatile keys, plus loaded persistent keys.
|
* volatile keys, plus loaded persistent keys.
|
||||||
*
|
*
|
||||||
|
* When #MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled,
|
||||||
|
* the maximum number of loaded persistent keys.
|
||||||
|
*
|
||||||
* Currently, persistent keys do not need to be loaded all the time while
|
* Currently, persistent keys do not need to be loaded all the time while
|
||||||
* a multipart operation is in progress, only while the operation is being
|
* a multipart operation is in progress, only while the operation is being
|
||||||
* set up. This may change in future versions of the library.
|
* set up. This may change in future versions of the library.
|
||||||
|
@ -2069,6 +2069,40 @@ common_block_cipher_dispatch () {
|
|||||||
scripts/config.py set MBEDTLS_DEPRECATED_REMOVED
|
scripts/config.py set MBEDTLS_DEPRECATED_REMOVED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component_test_full_block_cipher_psa_dispatch_static_keystore () {
|
||||||
|
msg "build: full + PSA dispatch in block_cipher with static keystore"
|
||||||
|
# Check that the static key store works well when CTR_DRBG uses a
|
||||||
|
# PSA key for AES.
|
||||||
|
scripts/config.py unset MBEDTLS_PSA_KEY_STORE_DYNAMIC
|
||||||
|
|
||||||
|
loc_accel_list="ALG_ECB_NO_PADDING \
|
||||||
|
KEY_TYPE_AES KEY_TYPE_ARIA KEY_TYPE_CAMELLIA"
|
||||||
|
|
||||||
|
# Configure
|
||||||
|
# ---------
|
||||||
|
|
||||||
|
common_block_cipher_dispatch 1
|
||||||
|
|
||||||
|
# Build
|
||||||
|
# -----
|
||||||
|
|
||||||
|
helper_libtestdriver1_make_drivers "$loc_accel_list"
|
||||||
|
|
||||||
|
helper_libtestdriver1_make_main "$loc_accel_list"
|
||||||
|
|
||||||
|
# Make sure disabled components were not re-enabled by accident (additive
|
||||||
|
# config)
|
||||||
|
not grep mbedtls_aes_ library/aes.o
|
||||||
|
not grep mbedtls_aria_ library/aria.o
|
||||||
|
not grep mbedtls_camellia_ library/camellia.o
|
||||||
|
|
||||||
|
# Run the tests
|
||||||
|
# -------------
|
||||||
|
|
||||||
|
msg "test: full + PSA dispatch in block_cipher with static keystore"
|
||||||
|
make test
|
||||||
|
}
|
||||||
|
|
||||||
component_test_full_block_cipher_psa_dispatch () {
|
component_test_full_block_cipher_psa_dispatch () {
|
||||||
msg "build: full + PSA dispatch in block_cipher"
|
msg "build: full + PSA dispatch in block_cipher"
|
||||||
|
|
||||||
@ -2593,6 +2627,16 @@ component_test_se_default () {
|
|||||||
make test
|
make test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component_test_full_static_keystore () {
|
||||||
|
msg "build: full config - MBEDTLS_PSA_KEY_STORE_DYNAMIC"
|
||||||
|
scripts/config.py full
|
||||||
|
scripts/config.py unset MBEDTLS_PSA_KEY_STORE_DYNAMIC
|
||||||
|
make CC=clang CFLAGS="$ASAN_CFLAGS -Os" LDFLAGS="$ASAN_CFLAGS"
|
||||||
|
|
||||||
|
msg "test: full config - MBEDTLS_PSA_KEY_STORE_DYNAMIC"
|
||||||
|
make test
|
||||||
|
}
|
||||||
|
|
||||||
component_test_psa_crypto_drivers () {
|
component_test_psa_crypto_drivers () {
|
||||||
msg "build: full + test drivers dispatching to builtins"
|
msg "build: full + test drivers dispatching to builtins"
|
||||||
scripts/config.py full
|
scripts/config.py full
|
||||||
|
@ -1210,15 +1210,15 @@ psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot)
|
|||||||
case PSA_SLOT_PENDING_DELETION:
|
case PSA_SLOT_PENDING_DELETION:
|
||||||
/* In this state psa_wipe_key_slot() must only be called if the
|
/* In this state psa_wipe_key_slot() must only be called if the
|
||||||
* caller is the last reader. */
|
* caller is the last reader. */
|
||||||
if (slot->registered_readers != 1) {
|
if (slot->var.occupied.registered_readers != 1) {
|
||||||
MBEDTLS_TEST_HOOK_TEST_ASSERT(slot->registered_readers == 1);
|
MBEDTLS_TEST_HOOK_TEST_ASSERT(slot->var.occupied.registered_readers == 1);
|
||||||
status = PSA_ERROR_CORRUPTION_DETECTED;
|
status = PSA_ERROR_CORRUPTION_DETECTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PSA_SLOT_FILLING:
|
case PSA_SLOT_FILLING:
|
||||||
/* In this state registered_readers must be 0. */
|
/* In this state registered_readers must be 0. */
|
||||||
if (slot->registered_readers != 0) {
|
if (slot->var.occupied.registered_readers != 0) {
|
||||||
MBEDTLS_TEST_HOOK_TEST_ASSERT(slot->registered_readers == 0);
|
MBEDTLS_TEST_HOOK_TEST_ASSERT(slot->var.occupied.registered_readers == 0);
|
||||||
status = PSA_ERROR_CORRUPTION_DETECTED;
|
status = PSA_ERROR_CORRUPTION_DETECTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1232,6 +1232,11 @@ psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot)
|
|||||||
status = PSA_ERROR_CORRUPTION_DETECTED;
|
status = PSA_ERROR_CORRUPTION_DETECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
size_t slice_index = slot->slice_index;
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
|
|
||||||
/* Multipart operations may still be using the key. This is safe
|
/* Multipart operations may still be using the key. This is safe
|
||||||
* because all multipart operation objects are independent from
|
* because all multipart operation objects are independent from
|
||||||
* the key slot: if they need to access the key after the setup
|
* the key slot: if they need to access the key after the setup
|
||||||
@ -1242,6 +1247,17 @@ psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot)
|
|||||||
* zeroize because the metadata is not particularly sensitive.
|
* zeroize because the metadata is not particularly sensitive.
|
||||||
* This memset also sets the slot's state to PSA_SLOT_EMPTY. */
|
* This memset also sets the slot's state to PSA_SLOT_EMPTY. */
|
||||||
memset(slot, 0, sizeof(*slot));
|
memset(slot, 0, sizeof(*slot));
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
/* If the slot is already corrupted, something went deeply wrong,
|
||||||
|
* like a thread still using the slot or a stray pointer leading
|
||||||
|
* to the slot's memory being used for another object. Let the slot
|
||||||
|
* leak rather than make the corruption worse. */
|
||||||
|
if (status == PSA_SUCCESS) {
|
||||||
|
status = psa_free_key_slot(slice_index, slot);
|
||||||
|
}
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1753,8 +1769,6 @@ static psa_status_t psa_start_key_creation(
|
|||||||
psa_se_drv_table_entry_t **p_drv)
|
psa_se_drv_table_entry_t **p_drv)
|
||||||
{
|
{
|
||||||
psa_status_t status;
|
psa_status_t status;
|
||||||
psa_key_id_t volatile_key_id;
|
|
||||||
psa_key_slot_t *slot;
|
|
||||||
|
|
||||||
(void) method;
|
(void) method;
|
||||||
*p_drv = NULL;
|
*p_drv = NULL;
|
||||||
@ -1764,11 +1778,16 @@ static psa_status_t psa_start_key_creation(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int key_is_volatile = PSA_KEY_LIFETIME_IS_VOLATILE(attributes->lifetime);
|
||||||
|
psa_key_id_t volatile_key_id;
|
||||||
|
|
||||||
#if defined(MBEDTLS_THREADING_C)
|
#if defined(MBEDTLS_THREADING_C)
|
||||||
PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
|
PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
|
||||||
&mbedtls_threading_key_slot_mutex));
|
&mbedtls_threading_key_slot_mutex));
|
||||||
#endif
|
#endif
|
||||||
status = psa_reserve_free_key_slot(&volatile_key_id, p_slot);
|
status = psa_reserve_free_key_slot(
|
||||||
|
key_is_volatile ? &volatile_key_id : NULL,
|
||||||
|
p_slot);
|
||||||
#if defined(MBEDTLS_THREADING_C)
|
#if defined(MBEDTLS_THREADING_C)
|
||||||
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
|
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
|
||||||
&mbedtls_threading_key_slot_mutex));
|
&mbedtls_threading_key_slot_mutex));
|
||||||
@ -1776,7 +1795,7 @@ static psa_status_t psa_start_key_creation(
|
|||||||
if (status != PSA_SUCCESS) {
|
if (status != PSA_SUCCESS) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
slot = *p_slot;
|
psa_key_slot_t *slot = *p_slot;
|
||||||
|
|
||||||
/* We're storing the declared bit-size of the key. It's up to each
|
/* We're storing the declared bit-size of the key. It's up to each
|
||||||
* creation mechanism to verify that this information is correct.
|
* creation mechanism to verify that this information is correct.
|
||||||
@ -1787,7 +1806,7 @@ static psa_status_t psa_start_key_creation(
|
|||||||
* definition. */
|
* definition. */
|
||||||
|
|
||||||
slot->attr = *attributes;
|
slot->attr = *attributes;
|
||||||
if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) {
|
if (key_is_volatile) {
|
||||||
#if !defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
|
#if !defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
|
||||||
slot->attr.id = volatile_key_id;
|
slot->attr.id = volatile_key_id;
|
||||||
#else
|
#else
|
||||||
|
@ -59,6 +59,8 @@ typedef enum {
|
|||||||
* and metadata for one key.
|
* and metadata for one key.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/* This field is accessed in a lot of places. Putting it first
|
||||||
|
* reduces the code size. */
|
||||||
psa_key_attributes_t attr;
|
psa_key_attributes_t attr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -78,35 +80,77 @@ typedef struct {
|
|||||||
* slots that are in a suitable state for the function.
|
* slots that are in a suitable state for the function.
|
||||||
* For example, psa_get_and_lock_key_slot_in_memory, which finds a slot
|
* For example, psa_get_and_lock_key_slot_in_memory, which finds a slot
|
||||||
* containing a given key ID, will only check slots whose state variable is
|
* containing a given key ID, will only check slots whose state variable is
|
||||||
* PSA_SLOT_FULL. */
|
* PSA_SLOT_FULL.
|
||||||
|
*/
|
||||||
psa_key_slot_state_t state;
|
psa_key_slot_state_t state;
|
||||||
|
|
||||||
/*
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
* Number of functions registered as reading the material in the key slot.
|
/* The index of the slice containing this slot.
|
||||||
|
* This field must be filled if the slot contains a key
|
||||||
|
* (including keys being created or destroyed), and can be either
|
||||||
|
* filled or 0 when the slot is free.
|
||||||
*
|
*
|
||||||
* Library functions must not write directly to registered_readers
|
* In most cases, the slice index can be deduced from the key identifer.
|
||||||
*
|
* We keep it in a separate field for robustness (it reduces the chance
|
||||||
* A function must call psa_register_read(slot) before reading the current
|
* that a coding mistake in the key store will result in accessing the
|
||||||
* contents of the slot for an operation.
|
* wrong slice), and also so that it's available even on code paths
|
||||||
* They then must call psa_unregister_read(slot) once they have finished
|
* during creation or destruction where the key identifier might not be
|
||||||
* reading the current contents of the slot. If the key slot mutex is not
|
* filled in.
|
||||||
* held (when mutexes are enabled), this call must be done via a call to
|
* */
|
||||||
* psa_unregister_read_under_mutex(slot).
|
uint8_t slice_index;
|
||||||
* A function must call psa_key_slot_has_readers(slot) to check if
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
* the slot is in use for reading.
|
|
||||||
*
|
union {
|
||||||
* This counter is used to prevent resetting the key slot while the library
|
struct {
|
||||||
* may access it. For example, such control is needed in the following
|
/* The index of the next slot in the free list for this
|
||||||
* scenarios:
|
* slice, relative * to the next array element.
|
||||||
* . In case of key slot starvation, all key slots contain the description
|
*
|
||||||
* of a key, and the library asks for the description of a persistent
|
* That is, 0 means the next slot, 1 means the next slot
|
||||||
* key not present in the key slots, the key slots currently accessed by
|
* but one, etc. -1 would mean the slot itself. -2 means
|
||||||
* the library cannot be reclaimed to free a key slot to load the
|
* the previous slot, etc.
|
||||||
* persistent key.
|
*
|
||||||
* . In case of a multi-threaded application where one thread asks to close
|
* If this is beyond the array length, the free list ends with the
|
||||||
* or purge or destroy a key while it is in use by the library through
|
* current element.
|
||||||
* another thread. */
|
*
|
||||||
size_t registered_readers;
|
* The reason for this strange encoding is that 0 means the next
|
||||||
|
* element. This way, when we allocate a slice and initialize it
|
||||||
|
* to all-zero, the slice is ready for use, with a free list that
|
||||||
|
* consists of all the slots in order.
|
||||||
|
*/
|
||||||
|
int32_t next_free_relative_to_next;
|
||||||
|
} free;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/*
|
||||||
|
* Number of functions registered as reading the material in the key slot.
|
||||||
|
*
|
||||||
|
* Library functions must not write directly to registered_readers
|
||||||
|
*
|
||||||
|
* A function must call psa_register_read(slot) before reading
|
||||||
|
* the current contents of the slot for an operation.
|
||||||
|
* They then must call psa_unregister_read(slot) once they have
|
||||||
|
* finished reading the current contents of the slot. If the key
|
||||||
|
* slot mutex is not held (when mutexes are enabled), this call
|
||||||
|
* must be done via a call to
|
||||||
|
* psa_unregister_read_under_mutex(slot).
|
||||||
|
* A function must call psa_key_slot_has_readers(slot) to check if
|
||||||
|
* the slot is in use for reading.
|
||||||
|
*
|
||||||
|
* This counter is used to prevent resetting the key slot while
|
||||||
|
* the library may access it. For example, such control is needed
|
||||||
|
* in the following scenarios:
|
||||||
|
* . In case of key slot starvation, all key slots contain the
|
||||||
|
* description of a key, and the library asks for the
|
||||||
|
* description of a persistent key not present in the
|
||||||
|
* key slots, the key slots currently accessed by the
|
||||||
|
* library cannot be reclaimed to free a key slot to load
|
||||||
|
* the persistent key.
|
||||||
|
* . In case of a multi-threaded application where one thread
|
||||||
|
* asks to close or purge or destroy a key while it is in use
|
||||||
|
* by the library through another thread. */
|
||||||
|
size_t registered_readers;
|
||||||
|
} occupied;
|
||||||
|
} var;
|
||||||
|
|
||||||
/* Dynamically allocated key data buffer.
|
/* Dynamically allocated key data buffer.
|
||||||
* Format as specified in psa_export_key(). */
|
* Format as specified in psa_export_key(). */
|
||||||
@ -169,7 +213,7 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
static inline int psa_key_slot_has_readers(const psa_key_slot_t *slot)
|
static inline int psa_key_slot_has_readers(const psa_key_slot_t *slot)
|
||||||
{
|
{
|
||||||
return slot->registered_readers > 0;
|
return slot->var.occupied.registered_readers > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||||
|
@ -58,17 +58,140 @@ MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MAX < MBEDTLS_PSA_KEY_ID_BUILTIN_MIN |
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
|
||||||
|
/* Dynamic key store.
|
||||||
|
*
|
||||||
|
* The key store consists of multiple slices.
|
||||||
|
*
|
||||||
|
* The volatile keys are stored in variable-sized tables called slices.
|
||||||
|
* Slices are allocated on demand and deallocated when possible.
|
||||||
|
* The size of slices increases exponentially, so the average overhead
|
||||||
|
* (number of slots that are allocated but not used) is roughly
|
||||||
|
* proportional to the number of keys (with a factor that grows
|
||||||
|
* when the key store is fragmented).
|
||||||
|
*
|
||||||
|
* One slice is dedicated to the cache of persistent and built-in keys.
|
||||||
|
* For simplicity, they are separated from volatile keys. This cache
|
||||||
|
* slice has a fixed size and has the slice index KEY_SLOT_CACHE_SLICE_INDEX,
|
||||||
|
* located after the slices for volatile keys.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Size of the last slice containing the cache of persistent and built-in keys. */
|
||||||
|
#define PERSISTENT_KEY_CACHE_COUNT MBEDTLS_PSA_KEY_SLOT_COUNT
|
||||||
|
|
||||||
|
/* Volatile keys are stored in slices 0 through
|
||||||
|
* (KEY_SLOT_VOLATILE_SLICE_COUNT - 1) inclusive.
|
||||||
|
* Each slice is twice the size of the previous slice.
|
||||||
|
* Volatile key identifiers encode the slice number as follows:
|
||||||
|
* bits 30..31: 0b10 (mandated by the PSA Crypto specification).
|
||||||
|
* bits 25..29: slice index (0...KEY_SLOT_VOLATILE_SLICE_COUNT-1)
|
||||||
|
* bits 0..24: slot index in slice
|
||||||
|
*/
|
||||||
|
#define KEY_ID_SLOT_INDEX_WIDTH 25u
|
||||||
|
#define KEY_ID_SLICE_INDEX_WIDTH 5u
|
||||||
|
|
||||||
|
#define KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH 16u
|
||||||
|
#define KEY_SLOT_VOLATILE_SLICE_COUNT 22u
|
||||||
|
#define KEY_SLICE_COUNT (KEY_SLOT_VOLATILE_SLICE_COUNT + 1u)
|
||||||
|
#define KEY_SLOT_CACHE_SLICE_INDEX KEY_SLOT_VOLATILE_SLICE_COUNT
|
||||||
|
|
||||||
|
|
||||||
|
/* Check that the length of the largest slice (calculated as
|
||||||
|
* KEY_SLICE_LENGTH_MAX below) does not overflow size_t. We use
|
||||||
|
* an indirect method in case the calculation of KEY_SLICE_LENGTH_MAX
|
||||||
|
* itself overflows uintmax_t: if (BASE_LENGTH << c)
|
||||||
|
* overflows size_t then BASE_LENGTH > SIZE_MAX >> c.
|
||||||
|
*/
|
||||||
|
#if (KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH > \
|
||||||
|
SIZE_MAX >> (KEY_SLOT_VOLATILE_SLICE_COUNT - 1))
|
||||||
|
#error "Maximum slice length overflows size_t"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KEY_ID_SLICE_INDEX_WIDTH + KEY_ID_SLOT_INDEX_WIDTH > 30
|
||||||
|
#error "Not enough room in volatile key IDs for slice index and slot index"
|
||||||
|
#endif
|
||||||
|
#if KEY_SLOT_VOLATILE_SLICE_COUNT > (1 << KEY_ID_SLICE_INDEX_WIDTH)
|
||||||
|
#error "Too many slices to fit the slice index in a volatile key ID"
|
||||||
|
#endif
|
||||||
|
#define KEY_SLICE_LENGTH_MAX \
|
||||||
|
(KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << (KEY_SLOT_VOLATILE_SLICE_COUNT - 1))
|
||||||
|
#if KEY_SLICE_LENGTH_MAX > 1 << KEY_ID_SLOT_INDEX_WIDTH
|
||||||
|
#error "Not enough room in volatile key IDs for a slot index in the largest slice"
|
||||||
|
#endif
|
||||||
|
#if KEY_ID_SLICE_INDEX_WIDTH > 8
|
||||||
|
#error "Slice index does not fit in uint8_t for psa_key_slot_t::slice_index"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Calculate the volatile key id to use for a given slot.
|
||||||
|
* This function assumes valid parameter values. */
|
||||||
|
static psa_key_id_t volatile_key_id_of_index(size_t slice_idx,
|
||||||
|
size_t slot_idx)
|
||||||
|
{
|
||||||
|
/* We assert above that the slice and slot indexes fit in separate
|
||||||
|
* bit-fields inside psa_key_id_t, which is a 32-bit type per the
|
||||||
|
* PSA Cryptography specification. */
|
||||||
|
return (psa_key_id_t) (0x40000000u |
|
||||||
|
(slice_idx << KEY_ID_SLOT_INDEX_WIDTH) |
|
||||||
|
slot_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the slice containing the given volatile key.
|
||||||
|
* This function assumes valid parameter values. */
|
||||||
|
static size_t slice_index_of_volatile_key_id(psa_key_id_t key_id)
|
||||||
|
{
|
||||||
|
size_t mask = (1LU << KEY_ID_SLICE_INDEX_WIDTH) - 1;
|
||||||
|
return (key_id >> KEY_ID_SLOT_INDEX_WIDTH) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the index of the slot containing the given volatile key.
|
||||||
|
* This function assumes valid parameter values. */
|
||||||
|
static size_t slot_index_of_volatile_key_id(psa_key_id_t key_id)
|
||||||
|
{
|
||||||
|
return key_id & ((1LU << KEY_ID_SLOT_INDEX_WIDTH) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In global_data.first_free_slot_index, use this special value to
|
||||||
|
* indicate that the slice is full. */
|
||||||
|
#define FREE_SLOT_INDEX_NONE ((size_t) -1)
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_TEST_HOOKS)
|
||||||
|
size_t psa_key_slot_volatile_slice_count(void)
|
||||||
|
{
|
||||||
|
return KEY_SLOT_VOLATILE_SLICE_COUNT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
|
/* Static key store.
|
||||||
|
*
|
||||||
|
* All the keys (volatile or persistent) are in a single slice.
|
||||||
|
* We only use slices as a concept to allow some differences between
|
||||||
|
* static and dynamic key store management to be buried in auxiliary
|
||||||
|
* functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PERSISTENT_KEY_CACHE_COUNT MBEDTLS_PSA_KEY_SLOT_COUNT
|
||||||
|
#define KEY_SLICE_COUNT 1u
|
||||||
|
#define KEY_SLOT_CACHE_SLICE_INDEX 0
|
||||||
|
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
psa_key_slot_t *key_slices[KEY_SLICE_COUNT];
|
||||||
|
size_t first_free_slot_index[KEY_SLOT_VOLATILE_SLICE_COUNT];
|
||||||
|
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
psa_key_slot_t key_slots[MBEDTLS_PSA_KEY_SLOT_COUNT];
|
psa_key_slot_t key_slots[MBEDTLS_PSA_KEY_SLOT_COUNT];
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
uint8_t key_slots_initialized;
|
uint8_t key_slots_initialized;
|
||||||
} psa_global_data_t;
|
} psa_global_data_t;
|
||||||
|
|
||||||
static psa_global_data_t global_data;
|
static psa_global_data_t global_data;
|
||||||
|
|
||||||
MBEDTLS_STATIC_ASSERT(ARRAY_LENGTH(global_data.key_slots) <=
|
|
||||||
PSA_KEY_ID_VOLATILE_MAX - PSA_KEY_ID_VOLATILE_MIN + 1,
|
|
||||||
"The key slot array is larger than the volatile key ID range");
|
|
||||||
|
|
||||||
static uint8_t psa_get_key_slots_initialized(void)
|
static uint8_t psa_get_key_slots_initialized(void)
|
||||||
{
|
{
|
||||||
uint8_t initialized;
|
uint8_t initialized;
|
||||||
@ -86,6 +209,125 @@ static uint8_t psa_get_key_slots_initialized(void)
|
|||||||
return initialized;
|
return initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** The length of the given slice in the key slot table.
|
||||||
|
*
|
||||||
|
* \param slice_idx The slice number. It must satisfy
|
||||||
|
* 0 <= slice_idx < KEY_SLICE_COUNT.
|
||||||
|
*
|
||||||
|
* \return The number of elements in the given slice.
|
||||||
|
*/
|
||||||
|
static inline size_t key_slice_length(size_t slice_idx);
|
||||||
|
|
||||||
|
/** Get a pointer to the slot where the given volatile key is located.
|
||||||
|
*
|
||||||
|
* \param key_id The key identifier. It must be a valid volatile key
|
||||||
|
* identifier.
|
||||||
|
* \return A pointer to the only slot that the given key
|
||||||
|
* can be in. Note that the slot may be empty or
|
||||||
|
* contain a different key.
|
||||||
|
*/
|
||||||
|
static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id);
|
||||||
|
|
||||||
|
/** Get a pointer to an entry in the persistent key cache.
|
||||||
|
*
|
||||||
|
* \param slot_idx The index in the table. It must satisfy
|
||||||
|
* 0 <= slot_idx < PERSISTENT_KEY_CACHE_COUNT.
|
||||||
|
* \return A pointer to the slot containing the given
|
||||||
|
* persistent key cache entry.
|
||||||
|
*/
|
||||||
|
static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx);
|
||||||
|
|
||||||
|
/** Get a pointer to a slot given by slice and index.
|
||||||
|
*
|
||||||
|
* \param slice_idx The slice number. It must satisfy
|
||||||
|
* 0 <= slice_idx < KEY_SLICE_COUNT.
|
||||||
|
* \param slot_idx An index in the given slice. It must satisfy
|
||||||
|
* 0 <= slot_idx < key_slice_length(slice_idx).
|
||||||
|
*
|
||||||
|
* \return A pointer to the given slot.
|
||||||
|
*/
|
||||||
|
static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx);
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_TEST_HOOKS)
|
||||||
|
size_t (*mbedtls_test_hook_psa_volatile_key_slice_length)(size_t slice_idx) = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline size_t key_slice_length(size_t slice_idx)
|
||||||
|
{
|
||||||
|
if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) {
|
||||||
|
return PERSISTENT_KEY_CACHE_COUNT;
|
||||||
|
} else {
|
||||||
|
#if defined(MBEDTLS_TEST_HOOKS)
|
||||||
|
if (mbedtls_test_hook_psa_volatile_key_slice_length != NULL) {
|
||||||
|
return mbedtls_test_hook_psa_volatile_key_slice_length(slice_idx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << slice_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id)
|
||||||
|
{
|
||||||
|
size_t slice_idx = slice_index_of_volatile_key_id(key_id);
|
||||||
|
if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size_t slot_idx = slot_index_of_volatile_key_id(key_id);
|
||||||
|
if (slot_idx >= key_slice_length(slice_idx)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
psa_key_slot_t *slice = global_data.key_slices[slice_idx];
|
||||||
|
if (slice == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return &slice[slot_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx)
|
||||||
|
{
|
||||||
|
return &global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX][slot_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx)
|
||||||
|
{
|
||||||
|
return &global_data.key_slices[slice_idx][slot_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
|
static inline size_t key_slice_length(size_t slice_idx)
|
||||||
|
{
|
||||||
|
(void) slice_idx;
|
||||||
|
return ARRAY_LENGTH(global_data.key_slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id)
|
||||||
|
{
|
||||||
|
MBEDTLS_STATIC_ASSERT(ARRAY_LENGTH(global_data.key_slots) <=
|
||||||
|
PSA_KEY_ID_VOLATILE_MAX - PSA_KEY_ID_VOLATILE_MIN + 1,
|
||||||
|
"The key slot array is larger than the volatile key ID range");
|
||||||
|
return &global_data.key_slots[key_id - PSA_KEY_ID_VOLATILE_MIN];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx)
|
||||||
|
{
|
||||||
|
return &global_data.key_slots[slot_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx)
|
||||||
|
{
|
||||||
|
(void) slice_idx;
|
||||||
|
return &global_data.key_slots[slot_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int psa_is_valid_key_id(mbedtls_svc_key_id_t key, int vendor_ok)
|
int psa_is_valid_key_id(mbedtls_svc_key_id_t key, int vendor_ok)
|
||||||
{
|
{
|
||||||
psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key);
|
psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key);
|
||||||
@ -147,12 +389,13 @@ static psa_status_t psa_get_and_lock_key_slot_in_memory(
|
|||||||
psa_key_slot_t *slot = NULL;
|
psa_key_slot_t *slot = NULL;
|
||||||
|
|
||||||
if (psa_key_id_is_volatile(key_id)) {
|
if (psa_key_id_is_volatile(key_id)) {
|
||||||
slot = &global_data.key_slots[key_id - PSA_KEY_ID_VOLATILE_MIN];
|
slot = get_volatile_key_slot(key_id);
|
||||||
|
|
||||||
/* Check if both the PSA key identifier key_id and the owner
|
/* Check if both the PSA key identifier key_id and the owner
|
||||||
* identifier of key match those of the key slot. */
|
* identifier of key match those of the key slot. */
|
||||||
if ((slot->state == PSA_SLOT_FULL) &&
|
if (slot != NULL &&
|
||||||
(mbedtls_svc_key_id_equal(key, slot->attr.id))) {
|
slot->state == PSA_SLOT_FULL &&
|
||||||
|
mbedtls_svc_key_id_equal(key, slot->attr.id)) {
|
||||||
status = PSA_SUCCESS;
|
status = PSA_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
status = PSA_ERROR_DOES_NOT_EXIST;
|
status = PSA_ERROR_DOES_NOT_EXIST;
|
||||||
@ -162,8 +405,8 @@ static psa_status_t psa_get_and_lock_key_slot_in_memory(
|
|||||||
return PSA_ERROR_INVALID_HANDLE;
|
return PSA_ERROR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (slot_idx = 0; slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT; slot_idx++) {
|
for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) {
|
||||||
slot = &global_data.key_slots[slot_idx];
|
slot = get_persistent_key_slot(slot_idx);
|
||||||
/* Only consider slots which are in a full state. */
|
/* Only consider slots which are in a full state. */
|
||||||
if ((slot->state == PSA_SLOT_FULL) &&
|
if ((slot->state == PSA_SLOT_FULL) &&
|
||||||
(mbedtls_svc_key_id_equal(key, slot->attr.id))) {
|
(mbedtls_svc_key_id_equal(key, slot->attr.id))) {
|
||||||
@ -186,29 +429,169 @@ static psa_status_t psa_get_and_lock_key_slot_in_memory(
|
|||||||
|
|
||||||
psa_status_t psa_initialize_key_slots(void)
|
psa_status_t psa_initialize_key_slots(void)
|
||||||
{
|
{
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] =
|
||||||
|
mbedtls_calloc(PERSISTENT_KEY_CACHE_COUNT,
|
||||||
|
sizeof(*global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX]));
|
||||||
|
if (global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] == NULL) {
|
||||||
|
return PSA_ERROR_INSUFFICIENT_MEMORY;
|
||||||
|
}
|
||||||
|
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
/* Nothing to do: program startup and psa_wipe_all_key_slots() both
|
/* Nothing to do: program startup and psa_wipe_all_key_slots() both
|
||||||
* guarantee that the key slots are initialized to all-zero, which
|
* guarantee that the key slots are initialized to all-zero, which
|
||||||
* means that all the key slots are in a valid, empty state. The global
|
* means that all the key slots are in a valid, empty state. The global
|
||||||
* data mutex is already held when calling this function, so no need to
|
* data mutex is already held when calling this function, so no need to
|
||||||
* lock it here, to set the flag. */
|
* lock it here, to set the flag. */
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
global_data.key_slots_initialized = 1;
|
global_data.key_slots_initialized = 1;
|
||||||
return PSA_SUCCESS;
|
return PSA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void psa_wipe_all_key_slots(void)
|
void psa_wipe_all_key_slots(void)
|
||||||
{
|
{
|
||||||
size_t slot_idx;
|
for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) {
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
for (slot_idx = 0; slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT; slot_idx++) {
|
if (global_data.key_slices[slice_idx] == NULL) {
|
||||||
psa_key_slot_t *slot = &global_data.key_slots[slot_idx];
|
continue;
|
||||||
slot->registered_readers = 1;
|
}
|
||||||
slot->state = PSA_SLOT_PENDING_DELETION;
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
(void) psa_wipe_key_slot(slot);
|
for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) {
|
||||||
|
psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx);
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
/* When MBEDTLS_PSA_KEY_STORE_DYNAMIC is disabled, calling
|
||||||
|
* psa_wipe_key_slot() on an unused slot is useless, but it
|
||||||
|
* happens to work (because we flip the state to PENDING_DELETION).
|
||||||
|
*
|
||||||
|
* When MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled,
|
||||||
|
* psa_wipe_key_slot() needs to have a valid slice_index
|
||||||
|
* field, but that value might not be correct in a
|
||||||
|
* free slot, so we must not call it.
|
||||||
|
*
|
||||||
|
* Bypass the call to psa_wipe_key_slot() if the slot is empty,
|
||||||
|
* but only if MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, to save
|
||||||
|
* a few bytes of code size otherwise.
|
||||||
|
*/
|
||||||
|
if (slot->state == PSA_SLOT_EMPTY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
slot->var.occupied.registered_readers = 1;
|
||||||
|
slot->state = PSA_SLOT_PENDING_DELETION;
|
||||||
|
(void) psa_wipe_key_slot(slot);
|
||||||
|
}
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
mbedtls_free(global_data.key_slices[slice_idx]);
|
||||||
|
global_data.key_slices[slice_idx] = NULL;
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
for (size_t slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) {
|
||||||
|
global_data.first_free_slot_index[slice_idx] = 0;
|
||||||
|
}
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
/* The global data mutex is already held when calling this function. */
|
/* The global data mutex is already held when calling this function. */
|
||||||
global_data.key_slots_initialized = 0;
|
global_data.key_slots_initialized = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
|
||||||
|
static psa_status_t psa_allocate_volatile_key_slot(psa_key_id_t *key_id,
|
||||||
|
psa_key_slot_t **p_slot)
|
||||||
|
{
|
||||||
|
size_t slice_idx;
|
||||||
|
for (slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) {
|
||||||
|
if (global_data.first_free_slot_index[slice_idx] != FREE_SLOT_INDEX_NONE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slice_idx == KEY_SLOT_VOLATILE_SLICE_COUNT) {
|
||||||
|
return PSA_ERROR_INSUFFICIENT_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global_data.key_slices[slice_idx] == NULL) {
|
||||||
|
global_data.key_slices[slice_idx] =
|
||||||
|
mbedtls_calloc(key_slice_length(slice_idx),
|
||||||
|
sizeof(psa_key_slot_t));
|
||||||
|
if (global_data.key_slices[slice_idx] == NULL) {
|
||||||
|
return PSA_ERROR_INSUFFICIENT_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
psa_key_slot_t *slice = global_data.key_slices[slice_idx];
|
||||||
|
|
||||||
|
size_t slot_idx = global_data.first_free_slot_index[slice_idx];
|
||||||
|
*key_id = volatile_key_id_of_index(slice_idx, slot_idx);
|
||||||
|
|
||||||
|
psa_key_slot_t *slot = &slice[slot_idx];
|
||||||
|
size_t next_free = slot_idx + 1 + slot->var.free.next_free_relative_to_next;
|
||||||
|
if (next_free >= key_slice_length(slice_idx)) {
|
||||||
|
next_free = FREE_SLOT_INDEX_NONE;
|
||||||
|
}
|
||||||
|
global_data.first_free_slot_index[slice_idx] = next_free;
|
||||||
|
/* The .next_free field is not meaningful when the slot is not free,
|
||||||
|
* so give it the same content as freshly initialized memory. */
|
||||||
|
slot->var.free.next_free_relative_to_next = 0;
|
||||||
|
|
||||||
|
psa_status_t status = psa_key_slot_state_transition(slot,
|
||||||
|
PSA_SLOT_EMPTY,
|
||||||
|
PSA_SLOT_FILLING);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
/* The only reason for failure is if the slot state was not empty.
|
||||||
|
* This indicates that something has gone horribly wrong.
|
||||||
|
* In this case, we leave the slot out of the free list, and stop
|
||||||
|
* modifying it. This minimizes any further corruption. The slot
|
||||||
|
* is a memory leak, but that's a lesser evil. */
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_slot = slot;
|
||||||
|
/* We assert at compile time that the slice index fits in uint8_t. */
|
||||||
|
slot->slice_index = (uint8_t) slice_idx;
|
||||||
|
return PSA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
psa_status_t psa_free_key_slot(size_t slice_idx,
|
||||||
|
psa_key_slot_t *slot)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) {
|
||||||
|
/* This is a cache entry. We don't maintain a free list, so
|
||||||
|
* there's nothing to do. */
|
||||||
|
return PSA_SUCCESS;
|
||||||
|
}
|
||||||
|
if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) {
|
||||||
|
return PSA_ERROR_CORRUPTION_DETECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
psa_key_slot_t *slice = global_data.key_slices[slice_idx];
|
||||||
|
psa_key_slot_t *slice_end = slice + key_slice_length(slice_idx);
|
||||||
|
if (slot < slice || slot >= slice_end) {
|
||||||
|
/* The slot isn't actually in the slice! We can't detect that
|
||||||
|
* condition for sure, because the pointer comparison itself is
|
||||||
|
* undefined behavior in that case. That same condition makes the
|
||||||
|
* subtraction to calculate the slot index also UB.
|
||||||
|
* Give up now to avoid causing further corruption.
|
||||||
|
*/
|
||||||
|
return PSA_ERROR_CORRUPTION_DETECTED;
|
||||||
|
}
|
||||||
|
size_t slot_idx = slot - slice;
|
||||||
|
|
||||||
|
size_t next_free = global_data.first_free_slot_index[slice_idx];
|
||||||
|
if (next_free >= key_slice_length(slice_idx)) {
|
||||||
|
/* The slot was full. The newly freed slot thus becomes the
|
||||||
|
* end of the free list. */
|
||||||
|
next_free = key_slice_length(slice_idx);
|
||||||
|
}
|
||||||
|
global_data.first_free_slot_index[slice_idx] = slot_idx;
|
||||||
|
slot->var.free.next_free_relative_to_next =
|
||||||
|
(int32_t) next_free - (int32_t) slot_idx - 1;
|
||||||
|
|
||||||
|
return PSA_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
|
psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
|
||||||
psa_key_slot_t **p_slot)
|
psa_key_slot_t **p_slot)
|
||||||
{
|
{
|
||||||
@ -221,9 +604,19 @@ psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
if (volatile_key_id != NULL) {
|
||||||
|
return psa_allocate_volatile_key_slot(volatile_key_id, p_slot);
|
||||||
|
}
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
|
/* With a dynamic key store, allocate an entry in the cache slice,
|
||||||
|
* applicable only to non-volatile keys that get cached in RAM.
|
||||||
|
* With a static key store, allocate an entry in the sole slice,
|
||||||
|
* applicable to all keys. */
|
||||||
selected_slot = unused_persistent_key_slot = NULL;
|
selected_slot = unused_persistent_key_slot = NULL;
|
||||||
for (slot_idx = 0; slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT; slot_idx++) {
|
for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) {
|
||||||
psa_key_slot_t *slot = &global_data.key_slots[slot_idx];
|
psa_key_slot_t *slot = get_key_slot(KEY_SLOT_CACHE_SLICE_INDEX, slot_idx);
|
||||||
if (slot->state == PSA_SLOT_EMPTY) {
|
if (slot->state == PSA_SLOT_EMPTY) {
|
||||||
selected_slot = slot;
|
selected_slot = slot;
|
||||||
break;
|
break;
|
||||||
@ -261,8 +654,18 @@ psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
*volatile_key_id = PSA_KEY_ID_VOLATILE_MIN +
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
((psa_key_id_t) (selected_slot - global_data.key_slots));
|
selected_slot->slice_index = KEY_SLOT_CACHE_SLICE_INDEX;
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
if (volatile_key_id != NULL) {
|
||||||
|
/* Refresh slot_idx, for when the slot is not the original
|
||||||
|
* selected_slot but rather unused_persistent_key_slot. */
|
||||||
|
slot_idx = selected_slot - global_data.key_slots;
|
||||||
|
*volatile_key_id = PSA_KEY_ID_VOLATILE_MIN + slot_idx;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
*p_slot = selected_slot;
|
*p_slot = selected_slot;
|
||||||
|
|
||||||
return PSA_SUCCESS;
|
return PSA_SUCCESS;
|
||||||
@ -271,7 +674,6 @@ psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
*p_slot = NULL;
|
*p_slot = NULL;
|
||||||
*volatile_key_id = 0;
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -430,9 +832,8 @@ psa_status_t psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key,
|
|||||||
/* Loading keys from storage requires support for such a mechanism */
|
/* Loading keys from storage requires support for such a mechanism */
|
||||||
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \
|
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \
|
||||||
defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
|
defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
|
||||||
psa_key_id_t volatile_key_id;
|
|
||||||
|
|
||||||
status = psa_reserve_free_key_slot(&volatile_key_id, p_slot);
|
status = psa_reserve_free_key_slot(NULL, p_slot);
|
||||||
if (status != PSA_SUCCESS) {
|
if (status != PSA_SUCCESS) {
|
||||||
#if defined(MBEDTLS_THREADING_C)
|
#if defined(MBEDTLS_THREADING_C)
|
||||||
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
|
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
|
||||||
@ -500,12 +901,12 @@ psa_status_t psa_unregister_read(psa_key_slot_t *slot)
|
|||||||
/* If we are the last reader and the slot is marked for deletion,
|
/* If we are the last reader and the slot is marked for deletion,
|
||||||
* we must wipe the slot here. */
|
* we must wipe the slot here. */
|
||||||
if ((slot->state == PSA_SLOT_PENDING_DELETION) &&
|
if ((slot->state == PSA_SLOT_PENDING_DELETION) &&
|
||||||
(slot->registered_readers == 1)) {
|
(slot->var.occupied.registered_readers == 1)) {
|
||||||
return psa_wipe_key_slot(slot);
|
return psa_wipe_key_slot(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (psa_key_slot_has_readers(slot)) {
|
if (psa_key_slot_has_readers(slot)) {
|
||||||
slot->registered_readers--;
|
slot->var.occupied.registered_readers--;
|
||||||
return PSA_SUCCESS;
|
return PSA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,7 +1040,7 @@ psa_status_t psa_close_key(psa_key_handle_t handle)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot->registered_readers == 1) {
|
if (slot->var.occupied.registered_readers == 1) {
|
||||||
status = psa_wipe_key_slot(slot);
|
status = psa_wipe_key_slot(slot);
|
||||||
} else {
|
} else {
|
||||||
status = psa_unregister_read(slot);
|
status = psa_unregister_read(slot);
|
||||||
@ -674,7 +1075,7 @@ psa_status_t psa_purge_key(mbedtls_svc_key_id_t key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) &&
|
if ((!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) &&
|
||||||
(slot->registered_readers == 1)) {
|
(slot->var.occupied.registered_readers == 1)) {
|
||||||
status = psa_wipe_key_slot(slot);
|
status = psa_wipe_key_slot(slot);
|
||||||
} else {
|
} else {
|
||||||
status = psa_unregister_read(slot);
|
status = psa_unregister_read(slot);
|
||||||
@ -689,34 +1090,39 @@ psa_status_t psa_purge_key(mbedtls_svc_key_id_t key)
|
|||||||
|
|
||||||
void mbedtls_psa_get_stats(mbedtls_psa_stats_t *stats)
|
void mbedtls_psa_get_stats(mbedtls_psa_stats_t *stats)
|
||||||
{
|
{
|
||||||
size_t slot_idx;
|
|
||||||
|
|
||||||
memset(stats, 0, sizeof(*stats));
|
memset(stats, 0, sizeof(*stats));
|
||||||
|
|
||||||
for (slot_idx = 0; slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT; slot_idx++) {
|
for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) {
|
||||||
const psa_key_slot_t *slot = &global_data.key_slots[slot_idx];
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
if (psa_key_slot_has_readers(slot)) {
|
if (global_data.key_slices[slice_idx] == NULL) {
|
||||||
++stats->locked_slots;
|
|
||||||
}
|
|
||||||
if (slot->state == PSA_SLOT_EMPTY) {
|
|
||||||
++stats->empty_slots;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) {
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
++stats->volatile_slots;
|
for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) {
|
||||||
} else {
|
const psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx);
|
||||||
psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id);
|
if (slot->state == PSA_SLOT_EMPTY) {
|
||||||
++stats->persistent_slots;
|
++stats->empty_slots;
|
||||||
if (id > stats->max_open_internal_key_id) {
|
continue;
|
||||||
stats->max_open_internal_key_id = id;
|
|
||||||
}
|
}
|
||||||
}
|
if (psa_key_slot_has_readers(slot)) {
|
||||||
if (PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime) !=
|
++stats->locked_slots;
|
||||||
PSA_KEY_LOCATION_LOCAL_STORAGE) {
|
}
|
||||||
psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id);
|
if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) {
|
||||||
++stats->external_slots;
|
++stats->volatile_slots;
|
||||||
if (id > stats->max_open_external_key_id) {
|
} else {
|
||||||
stats->max_open_external_key_id = id;
|
psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id);
|
||||||
|
++stats->persistent_slots;
|
||||||
|
if (id > stats->max_open_internal_key_id) {
|
||||||
|
stats->max_open_internal_key_id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime) !=
|
||||||
|
PSA_KEY_LOCATION_LOCAL_STORAGE) {
|
||||||
|
psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id);
|
||||||
|
++stats->external_slots;
|
||||||
|
if (id > stats->max_open_external_key_id) {
|
||||||
|
stats->max_open_external_key_id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
*
|
*
|
||||||
* The first #MBEDTLS_PSA_KEY_SLOT_COUNT identifiers of the implementation
|
* The first #MBEDTLS_PSA_KEY_SLOT_COUNT identifiers of the implementation
|
||||||
* range of key identifiers are reserved for volatile key identifiers.
|
* range of key identifiers are reserved for volatile key identifiers.
|
||||||
* A volatile key identifier is equal to #PSA_KEY_ID_VOLATILE_MIN plus the
|
*
|
||||||
* index of the key slot containing the volatile key definition.
|
* If \c id is a a volatile key identifier, #PSA_KEY_ID_VOLATILE_MIN - \c id
|
||||||
|
* indicates the key slot containing the volatile key definition. See
|
||||||
|
* psa_crypto_slot_management.c for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** The minimum value for a volatile key identifier.
|
/** The minimum value for a volatile key identifier.
|
||||||
@ -27,8 +29,12 @@
|
|||||||
|
|
||||||
/** The maximum value for a volatile key identifier.
|
/** The maximum value for a volatile key identifier.
|
||||||
*/
|
*/
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
#define PSA_KEY_ID_VOLATILE_MAX (MBEDTLS_PSA_KEY_ID_BUILTIN_MIN - 1)
|
||||||
|
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
#define PSA_KEY_ID_VOLATILE_MAX \
|
#define PSA_KEY_ID_VOLATILE_MAX \
|
||||||
(PSA_KEY_ID_VOLATILE_MIN + MBEDTLS_PSA_KEY_SLOT_COUNT - 1)
|
(PSA_KEY_ID_VOLATILE_MIN + MBEDTLS_PSA_KEY_SLOT_COUNT - 1)
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
/** Test whether a key identifier is a volatile key identifier.
|
/** Test whether a key identifier is a volatile key identifier.
|
||||||
*
|
*
|
||||||
@ -94,6 +100,24 @@ psa_status_t psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key,
|
|||||||
*/
|
*/
|
||||||
psa_status_t psa_initialize_key_slots(void);
|
psa_status_t psa_initialize_key_slots(void);
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
/* Allow test code to customize the key slice length. We use this in tests
|
||||||
|
* that exhaust the key store to reach a full key store in reasonable time
|
||||||
|
* and memory.
|
||||||
|
*
|
||||||
|
* The length of each slice must be between 1 and
|
||||||
|
* (1 << KEY_ID_SLOT_INDEX_WIDTH) inclusive.
|
||||||
|
*
|
||||||
|
* The length for a given slice index must not change while
|
||||||
|
* the key store is initialized.
|
||||||
|
*/
|
||||||
|
extern size_t (*mbedtls_test_hook_psa_volatile_key_slice_length)(
|
||||||
|
size_t slice_idx);
|
||||||
|
|
||||||
|
/* The number of volatile key slices. */
|
||||||
|
size_t psa_key_slot_volatile_slice_count(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Delete all data from key slots in memory.
|
/** Delete all data from key slots in memory.
|
||||||
* This function is not thread safe, it wipes every key slot regardless of
|
* This function is not thread safe, it wipes every key slot regardless of
|
||||||
* state and reader count. It should only be called when no slot is in use.
|
* state and reader count. It should only be called when no slot is in use.
|
||||||
@ -113,13 +137,22 @@ void psa_wipe_all_key_slots(void);
|
|||||||
* If multi-threading is enabled, the caller must hold the
|
* If multi-threading is enabled, the caller must hold the
|
||||||
* global key slot mutex.
|
* global key slot mutex.
|
||||||
*
|
*
|
||||||
* \param[out] volatile_key_id On success, volatile key identifier
|
* \param[out] volatile_key_id - If null, reserve a cache slot for
|
||||||
* associated to the returned slot.
|
* a persistent or built-in key.
|
||||||
|
* - If non-null, allocate a slot for
|
||||||
|
* a volatile key. On success,
|
||||||
|
* \p *volatile_key_id is the
|
||||||
|
* identifier corresponding to the
|
||||||
|
* returned slot. It is the caller's
|
||||||
|
* responsibility to set this key identifier
|
||||||
|
* in the attributes.
|
||||||
* \param[out] p_slot On success, a pointer to the slot.
|
* \param[out] p_slot On success, a pointer to the slot.
|
||||||
*
|
*
|
||||||
* \retval #PSA_SUCCESS \emptydescription
|
* \retval #PSA_SUCCESS \emptydescription
|
||||||
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
|
||||||
* There were no free key slots.
|
* There were no free key slots.
|
||||||
|
* When #MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, there was not
|
||||||
|
* enough memory to allocate more slots.
|
||||||
* \retval #PSA_ERROR_BAD_STATE \emptydescription
|
* \retval #PSA_ERROR_BAD_STATE \emptydescription
|
||||||
* \retval #PSA_ERROR_CORRUPTION_DETECTED
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED
|
||||||
* This function attempted to operate on a key slot which was in an
|
* This function attempted to operate on a key slot which was in an
|
||||||
@ -128,6 +161,29 @@ void psa_wipe_all_key_slots(void);
|
|||||||
psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
|
psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
|
||||||
psa_key_slot_t **p_slot);
|
psa_key_slot_t **p_slot);
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
|
/** Return a key slot to the free list.
|
||||||
|
*
|
||||||
|
* Call this function when a slot obtained from psa_reserve_free_key_slot()
|
||||||
|
* is no longer in use.
|
||||||
|
*
|
||||||
|
* If multi-threading is enabled, the caller must hold the
|
||||||
|
* global key slot mutex.
|
||||||
|
*
|
||||||
|
* \param slice_idx The slice containing the slot.
|
||||||
|
* This is `slot->slice_index` when the slot
|
||||||
|
* is obtained from psa_reserve_free_key_slot().
|
||||||
|
* \param slot The key slot.
|
||||||
|
*
|
||||||
|
* \retval #PSA_SUCCESS \emptydescription
|
||||||
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED
|
||||||
|
* This function attempted to operate on a key slot which was in an
|
||||||
|
* unexpected state.
|
||||||
|
*/
|
||||||
|
psa_status_t psa_free_key_slot(size_t slice_idx,
|
||||||
|
psa_key_slot_t *slot);
|
||||||
|
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
|
|
||||||
/** Change the state of a key slot.
|
/** Change the state of a key slot.
|
||||||
*
|
*
|
||||||
* This function changes the state of the key slot from expected_state to
|
* This function changes the state of the key slot from expected_state to
|
||||||
@ -174,10 +230,10 @@ static inline psa_status_t psa_key_slot_state_transition(
|
|||||||
static inline psa_status_t psa_register_read(psa_key_slot_t *slot)
|
static inline psa_status_t psa_register_read(psa_key_slot_t *slot)
|
||||||
{
|
{
|
||||||
if ((slot->state != PSA_SLOT_FULL) ||
|
if ((slot->state != PSA_SLOT_FULL) ||
|
||||||
(slot->registered_readers >= SIZE_MAX)) {
|
(slot->var.occupied.registered_readers >= SIZE_MAX)) {
|
||||||
return PSA_ERROR_CORRUPTION_DETECTED;
|
return PSA_ERROR_CORRUPTION_DETECTED;
|
||||||
}
|
}
|
||||||
slot->registered_readers++;
|
slot->var.occupied.registered_readers++;
|
||||||
|
|
||||||
return PSA_SUCCESS;
|
return PSA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -129,9 +129,9 @@ depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C
|
|||||||
# writing, this happens in builds where AES uses a PSA driver and the
|
# writing, this happens in builds where AES uses a PSA driver and the
|
||||||
# PSA RNG uses AES-CTR_DRBG through the PSA AES.
|
# PSA RNG uses AES-CTR_DRBG through the PSA AES.
|
||||||
# Pick a key id that's in the middle of the volatile key ID range.
|
# Pick a key id that's in the middle of the volatile key ID range.
|
||||||
# That works out both when MBEDTLS_PSA_KEY_SLOT_DYNAMIC is enabled and
|
# That works out both when MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled and
|
||||||
# volatile key IDs are assigned starting with the lowest value, and when
|
# volatile key IDs are assigned starting with the lowest value, and when
|
||||||
# MBEDTLS_PSA_KEY_SLOT_DYNAMIC is disabled and volatile key IDs are assigned
|
# MBEDTLS_PSA_KEY_STORE_DYNAMIC is disabled and volatile key IDs are assigned
|
||||||
# starting with the highest values.
|
# starting with the highest values.
|
||||||
open_fail:(PSA_KEY_ID_VOLATILE_MIN + PSA_KEY_ID_VOLATILE_MAX) / 2:PSA_ERROR_DOES_NOT_EXIST
|
open_fail:(PSA_KEY_ID_VOLATILE_MIN + PSA_KEY_ID_VOLATILE_MAX) / 2:PSA_ERROR_DOES_NOT_EXIST
|
||||||
|
|
||||||
@ -228,6 +228,11 @@ invalid_handle:INVALID_HANDLE_HUGE:PSA_ERROR_INVALID_HANDLE
|
|||||||
Key slot count: maximum
|
Key slot count: maximum
|
||||||
many_transient_keys:MBEDTLS_PSA_KEY_SLOT_COUNT - MBEDTLS_TEST_PSA_INTERNAL_KEYS
|
many_transient_keys:MBEDTLS_PSA_KEY_SLOT_COUNT - MBEDTLS_TEST_PSA_INTERNAL_KEYS
|
||||||
|
|
||||||
|
Key slot count: dynamic: more than MBEDTLS_PSA_KEY_SLOT_COUNT
|
||||||
|
depends_on:MBEDTLS_PSA_KEY_STORE_DYNAMIC
|
||||||
|
# Check that MBEDTLS_PSA_KEY_SLOT_COUNT doesn't apply to volatile keys.
|
||||||
|
many_transient_keys:MBEDTLS_PSA_KEY_SLOT_COUNT + 1
|
||||||
|
|
||||||
Key slot count: try to overfill, destroy first
|
Key slot count: try to overfill, destroy first
|
||||||
fill_key_store:0
|
fill_key_store:0
|
||||||
|
|
||||||
|
@ -98,10 +98,30 @@ exit:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Currently, there is always a maximum number of volatile keys that can
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
|
||||||
* realistically be reached in tests. When we add configurations where this
|
#if defined(MBEDTLS_TEST_HOOKS)
|
||||||
* is not true, undefine the macro in such configurations. */
|
/* Artificially restrictable dynamic key store */
|
||||||
|
#define KEY_SLICE_1_LENGTH 4
|
||||||
|
#define KEY_SLICE_2_LENGTH 10
|
||||||
|
static size_t tiny_key_slice_length(size_t slice_idx)
|
||||||
|
{
|
||||||
|
switch (slice_idx) {
|
||||||
|
case 1: return KEY_SLICE_1_LENGTH;
|
||||||
|
case 2: return KEY_SLICE_2_LENGTH;
|
||||||
|
default: return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define MAX_VOLATILE_KEYS \
|
||||||
|
(KEY_SLICE_1_LENGTH + KEY_SLICE_2_LENGTH + \
|
||||||
|
psa_key_slot_volatile_slice_count() - 2)
|
||||||
|
|
||||||
|
#else /* Effectively unbounded dynamic key store */
|
||||||
|
#undef MAX_VOLATILE_KEYS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* Static key store */
|
||||||
#define MAX_VOLATILE_KEYS MBEDTLS_PSA_KEY_SLOT_COUNT
|
#define MAX_VOLATILE_KEYS MBEDTLS_PSA_KEY_SLOT_COUNT
|
||||||
|
#endif
|
||||||
|
|
||||||
/* END_HEADER */
|
/* END_HEADER */
|
||||||
|
|
||||||
@ -867,6 +887,10 @@ void fill_key_store(int key_to_destroy_arg)
|
|||||||
uint8_t exported[sizeof(size_t)];
|
uint8_t exported[sizeof(size_t)];
|
||||||
size_t exported_length;
|
size_t exported_length;
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) && defined(MBEDTLS_TEST_HOOKS)
|
||||||
|
mbedtls_test_hook_psa_volatile_key_slice_length = &tiny_key_slice_length;
|
||||||
|
#endif
|
||||||
|
|
||||||
PSA_ASSERT(psa_crypto_init());
|
PSA_ASSERT(psa_crypto_init());
|
||||||
|
|
||||||
mbedtls_psa_stats_t stats;
|
mbedtls_psa_stats_t stats;
|
||||||
@ -949,6 +973,9 @@ void fill_key_store(int key_to_destroy_arg)
|
|||||||
exit:
|
exit:
|
||||||
PSA_DONE();
|
PSA_DONE();
|
||||||
mbedtls_free(keys);
|
mbedtls_free(keys);
|
||||||
|
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) && defined(MBEDTLS_TEST_HOOKS)
|
||||||
|
mbedtls_test_hook_psa_volatile_key_slice_length = NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/* END_CASE */
|
/* END_CASE */
|
||||||
|
|
||||||
@ -1028,7 +1055,7 @@ exit:
|
|||||||
}
|
}
|
||||||
/* END_CASE */
|
/* END_CASE */
|
||||||
|
|
||||||
/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */
|
/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C:!MBEDTLS_PSA_KEY_STORE_DYNAMIC */
|
||||||
void non_reusable_key_slots_integrity_in_case_of_key_slot_starvation()
|
void non_reusable_key_slots_integrity_in_case_of_key_slot_starvation()
|
||||||
{
|
{
|
||||||
psa_status_t status;
|
psa_status_t status;
|
||||||
@ -1068,7 +1095,14 @@ void non_reusable_key_slots_integrity_in_case_of_key_slot_starvation()
|
|||||||
TEST_ASSERT(mbedtls_svc_key_id_equal(returned_key_id, persistent_key));
|
TEST_ASSERT(mbedtls_svc_key_id_equal(returned_key_id, persistent_key));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the maximum available number of volatile keys
|
* Create the maximum available number of keys that are locked in
|
||||||
|
* memory. This can be:
|
||||||
|
* - volatile keys, when MBEDTLS_PSA_KEY_STORE_DYNAMIC is disabled;
|
||||||
|
* - opened persistent keys (could work, but not currently implemented
|
||||||
|
* in this test function);
|
||||||
|
* - keys in use by another thread (we don't do this because it would
|
||||||
|
* be hard to arrange and we can't control how long the keys are
|
||||||
|
* locked anyway).
|
||||||
*/
|
*/
|
||||||
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
|
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
|
||||||
for (i = 0; i < available_key_slots; i++) {
|
for (i = 0; i < available_key_slots; i++) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user