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 @@ +