From 961849f6d189e5b796625bb80b6663c0398b0473 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 30 Nov 2018 18:54:54 +0100 Subject: [PATCH] Implement slot allocation Implement psa_allocate_key, psa_open_key, psa_create_key, psa_close_key. Add support for keys designated to handles to psa_get_key_slot, and thereby to the whole API. Allocated and non-allocated keys can coexist. This is a temporary stage in order to transition from the use of direct slot numbers to allocated handles only. Once all the tests and sample programs have been migrated to use handles, the implementation will be simplified and made more robust with support for handles only. --- library/CMakeLists.txt | 1 + library/Makefile | 1 + library/psa_crypto.c | 107 ++++++++++++++++++++-- library/psa_crypto_slot_management.c | 116 ++++++++++++++++++++++++ library/psa_crypto_slot_management.h | 80 ++++++++++++++++ tests/suites/test_suite_psa_crypto.data | 5 +- visualc/VS2010/mbedTLS.vcxproj | 2 + 7 files changed, 304 insertions(+), 8 deletions(-) create mode 100644 library/psa_crypto_slot_management.c create mode 100644 library/psa_crypto_slot_management.h diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index c8070bb27..3a3f61bcf 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -54,6 +54,7 @@ set(src_crypto platform_util.c poly1305.c psa_crypto.c + psa_crypto_slot_management.c psa_crypto_storage.c psa_crypto_storage_file.c psa_crypto_storage_its.c diff --git a/library/Makefile b/library/Makefile index 95faaaef3..1822a24af 100644 --- a/library/Makefile +++ b/library/Makefile @@ -83,6 +83,7 @@ OBJS_CRYPTO= aes.o aesni.o arc4.o \ pkcs5.o pkparse.o pkwrite.o \ platform.o platform_util.o poly1305.o \ psa_crypto.o \ + psa_crypto_slot_management.o \ psa_crypto_storage.o \ psa_crypto_storage_file.o \ psa_crypto_storage_its.o \ diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 24ad06d38..0d809cbaa 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -44,6 +44,7 @@ #include "psa/crypto.h" #include "psa_crypto_invasive.h" +#include "psa_crypto_slot_management.h" /* Include internal declarations that are useful for implementing persistently * stored keys. */ #include "psa_crypto_storage.h" @@ -117,16 +118,13 @@ static inline int safer_memcmp( const uint8_t *a, const uint8_t *b, size_t n ) /* Global data, support functions and library management */ /****************************************************************/ -/* Number of key slots (plus one because 0 is not used). - * The value is a compile-time constant for now, for simplicity. */ -#define PSA_KEY_SLOT_COUNT 32 - typedef struct { psa_key_type_t type; psa_key_policy_t policy; psa_key_lifetime_t lifetime; psa_key_id_t persistent_storage_id; + unsigned allocated : 1; union { struct raw_data @@ -742,21 +740,34 @@ exit: #endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */ /* Retrieve a key slot, occupied or not. */ -static psa_status_t psa_get_key_slot( psa_key_slot_t key, +static psa_status_t psa_get_key_slot( psa_key_slot_t key_or_handle, key_slot_t **p_slot ) { + psa_key_slot_t key = key_or_handle & ~PSA_KEY_HANDLE_ALLOCATED_FLAG; + int is_handle = ( key_or_handle & PSA_KEY_HANDLE_ALLOCATED_FLAG ) != 0; + psa_status_t error_if_invalid = + ( is_handle ? + PSA_ERROR_INVALID_HANDLE : + PSA_ERROR_INVALID_ARGUMENT ); + GUARD_MODULE_INITIALIZED; /* 0 is not a valid slot number under any circumstance. This * implementation provides slots number 1 to N where N is the * number of available slots. */ if( key == 0 || key > ARRAY_LENGTH( global_data.key_slots ) ) - return( PSA_ERROR_INVALID_ARGUMENT ); + return( error_if_invalid ); *p_slot = &global_data.key_slots[key - 1]; + /* Allocated slots must only be accessed via a handle. + * Unallocated slots must only be accessed directly. */ + if( ( *p_slot )->allocated != is_handle ) + return( error_if_invalid ); + #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) - if( ( *p_slot )->lifetime == PSA_KEY_LIFETIME_PERSISTENT ) + if( ! ( *p_slot )->allocated && + ( *p_slot )->lifetime == PSA_KEY_LIFETIME_PERSISTENT ) { /* There are two circumstances this can occur: the key material has * not yet been created, or the key exists in storage but has not yet @@ -865,6 +876,88 @@ static psa_status_t psa_remove_key_data_from_memory( key_slot_t *slot ) return( PSA_SUCCESS ); } +/* A slot is available if nothing has been set in it: default lifetime + * and policy, no key type. */ +static int psa_internal_is_slot_available( key_slot_t *slot ) +{ + if( slot->allocated ) + return( 0 ); + if( slot->type != PSA_KEY_TYPE_NONE ) + return( 0 ); + if( slot->lifetime != PSA_KEY_LIFETIME_VOLATILE ) + return( 0 ); + if( slot->policy.usage != 0 || slot->policy.alg != 0 ) + return( 0 ); + return( 1 ); +} + +psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle ) +{ + psa_key_slot_t key; + for( key = PSA_KEY_SLOT_COUNT; key != 0; --( key ) ) + { + key_slot_t *slot = &global_data.key_slots[key - 1]; + if( psa_internal_is_slot_available( slot ) ) + { + slot->allocated = 1; + *handle = key | PSA_KEY_HANDLE_ALLOCATED_FLAG; + return( PSA_SUCCESS ); + } + } + return( PSA_ERROR_INSUFFICIENT_MEMORY ); +} + +psa_status_t psa_internal_make_key_persistent( psa_key_handle_t handle, + psa_key_id_t id ) +{ + key_slot_t *slot; + psa_status_t status; + + /* Reject id=0 because by general library conventions, 0 is an invalid + * value wherever possible. */ + if( id == 0 ) + return( PSA_ERROR_INVALID_ARGUMENT ); + /* Reject high values because the file names are reserved for the + * library's internal use. */ + if( id >= 0xffff0000 ) + return( PSA_ERROR_INVALID_ARGUMENT ); + /* Reject values that don't fit in the key slot number type. + * This is a temporary limitation due to the library's internal + * plumbing. */ + if( id > (psa_key_slot_t)( -1 ) ) + return( PSA_ERROR_INVALID_ARGUMENT ); + + status = psa_get_key_slot( handle, &slot ); + if( status != PSA_SUCCESS ) + return( status ); + + slot->lifetime = PSA_KEY_LIFETIME_PERSISTENT; + slot->persistent_storage_id = id; + status = psa_load_persistent_key_into_slot( slot ); + + return( status ); +} + +psa_status_t psa_internal_release_key_slot( psa_key_handle_t handle ) +{ + psa_key_slot_t key; + key_slot_t *slot; + psa_status_t status; + /* Don't call psa_get_key_slot() so as not to trigger its automatic + * loading of persistent key data. */ + if( ( handle & PSA_KEY_HANDLE_ALLOCATED_FLAG ) == 0 ) + return( PSA_ERROR_INVALID_HANDLE ); + key = handle & ~PSA_KEY_HANDLE_ALLOCATED_FLAG; + if( key == 0 || key > ARRAY_LENGTH( global_data.key_slots ) ) + return( PSA_ERROR_INVALID_HANDLE ); + slot = &global_data.key_slots[key - 1]; + if( ! slot->allocated ) + return( PSA_ERROR_INVALID_HANDLE ); + status = psa_remove_key_data_from_memory( slot ); + memset( slot, 0, sizeof( *slot ) ); + return( status ); +} + psa_status_t psa_import_key( psa_key_slot_t key, psa_key_type_t type, const uint8_t *data, diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c new file mode 100644 index 000000000..ae5e146b9 --- /dev/null +++ b/library/psa_crypto_slot_management.c @@ -0,0 +1,116 @@ +/* + * PSA crypto layer on top of Mbed TLS crypto + */ +/* Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include "psa/crypto.h" + +#include "psa_crypto_slot_management.h" +#include "psa_crypto_storage.h" + +#include +#include +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) ) + +psa_status_t psa_allocate_key( psa_key_type_t type, + size_t max_bits, + psa_key_handle_t *handle ) +{ + /* This implementation doesn't reserve memory for the keys. */ + (void) type; + (void) max_bits; + *handle = 0; + return( psa_internal_allocate_key_slot( handle ) ); +} + +static psa_status_t persistent_key_setup( psa_key_lifetime_t lifetime, + psa_key_id_t id, + psa_key_handle_t *handle, + psa_status_t wanted_load_status ) +{ + psa_status_t status; + + *handle = 0; + + if( lifetime != PSA_KEY_LIFETIME_PERSISTENT ) + return( PSA_ERROR_INVALID_ARGUMENT ); + + status = psa_internal_allocate_key_slot( handle ); + if( status != PSA_SUCCESS ) + return( status ); + + status = psa_internal_make_key_persistent( *handle, id ); + if( status != wanted_load_status ) + { + psa_internal_release_key_slot( *handle ); + *handle = 0; + } + return( status ); +} + +psa_status_t psa_open_key( psa_key_lifetime_t lifetime, + psa_key_id_t id, + psa_key_handle_t *handle ) +{ + return( persistent_key_setup( lifetime, id, handle, PSA_SUCCESS ) ); +} + +psa_status_t psa_create_key( psa_key_lifetime_t lifetime, + psa_key_id_t id, + psa_key_type_t type, + size_t max_bits, + psa_key_handle_t *handle ) +{ + psa_status_t status; + + /* This implementation doesn't reserve memory for the keys. */ + (void) type; + (void) max_bits; + + status = persistent_key_setup( lifetime, id, handle, + PSA_ERROR_EMPTY_SLOT ); + switch( status ) + { + case PSA_SUCCESS: return( PSA_ERROR_OCCUPIED_SLOT ); + case PSA_ERROR_EMPTY_SLOT: return( PSA_SUCCESS ); + default: return( status ); + } +} + +psa_status_t psa_close_key( psa_key_handle_t handle ) +{ + return( psa_internal_release_key_slot( handle ) ); +} + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/library/psa_crypto_slot_management.h b/library/psa_crypto_slot_management.h new file mode 100644 index 000000000..36917bbaa --- /dev/null +++ b/library/psa_crypto_slot_management.h @@ -0,0 +1,80 @@ +/* + * PSA crypto layer on top of Mbed TLS crypto + */ +/* Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef PSA_CRYPTO_SLOT_MANAGEMENT_H +#define PSA_CRYPTO_SLOT_MANAGEMENT_H + +/* Number of key slots (plus one because 0 is not used). + * The value is a compile-time constant for now, for simplicity. */ +#define PSA_KEY_SLOT_COUNT 32 + +/* All dynamically allocated handles have this bit set. */ +#define PSA_KEY_HANDLE_ALLOCATED_FLAG ( (psa_key_handle_t) 0x8000 ) + +/** \defgroup core_slot_management Internal functions exposed by the core + * @{ + */ + +/** Find a free key slot and mark it as in use. + * + * \param[out] handle On success, a slot number that is not in use. + * + * \retval #PSA_SUCCESS + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + */ +psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle ); + +/** Wipe an a key slot and mark it as available. + * + * This does not affect persistent storage. + * + * \param handle The key slot number to release. + * + * \retval #PSA_SUCCESS + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \retval #PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_internal_release_key_slot( psa_key_handle_t handle ); + +/** Declare a slot as persistent and load it from storage. + * + * This function may only be called immediately after a successful call + * to psa_internal_allocate_key_slot(). + * + * \param handle A handle to a key slot freshly allocated with + * psa_internal_allocate_key_slot(). + * + * \retval #PSA_SUCCESS + * The slot content was loaded successfully. + * \retval #PSA_ERROR_EMPTY_SLOT + * There is no content for this slot in persistent storage. + * \retval #PSA_ERROR_INVALID_HANDLE + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p id is not acceptable. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_STORAGE_FAILURE + */ +psa_status_t psa_internal_make_key_persistent( psa_key_handle_t handle, + psa_key_id_t id ); + +/**@}*/ + +#endif /* PSA_CRYPTO_SLOT_MANAGEMENT_H */ diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 91739f55e..33ca54f6d 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -39,7 +39,10 @@ PSA export out of range key slot - lower bound export_invalid_slot:0:PSA_ERROR_INVALID_ARGUMENT PSA export out of range key slot - upper bound -export_invalid_slot:(psa_key_slot_t)(-1):PSA_ERROR_INVALID_ARGUMENT +# Hard-code the upper bound of slots that are directly accessible because the +# API does not expose this value. This is temporary: directly-accessible +# slots are about to be removed. +export_invalid_slot:32767:PSA_ERROR_INVALID_ARGUMENT PSA export a slot where there was some activity but no key material creation export_with_no_key_activity diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index d305c4515..341e058a8 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -232,6 +232,7 @@ + @@ -291,6 +292,7 @@ +