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.
This commit is contained in:
Gilles Peskine 2018-11-30 18:54:54 +01:00
parent 5ec7b078ea
commit 961849f6d1
7 changed files with 304 additions and 8 deletions

View file

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

View file

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

View file

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

View file

@ -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 <stdlib.h>
#include <string.h>
#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 */

View file

@ -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 */

View file

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

View file

@ -232,6 +232,7 @@
<ClInclude Include="..\..\include\psa\crypto_sizes.h" />
<ClInclude Include="..\..\include\psa\crypto_struct.h" />
<ClInclude Include="..\..\library/psa_crypto_invasive.h" />
<ClInclude Include="..\..\library/psa_crypto_slot_management.h" />
<ClInclude Include="..\..\library/psa_crypto_storage.h" />
<ClInclude Include="..\..\library/psa_crypto_storage_backend.h" />
</ItemGroup>
@ -291,6 +292,7 @@
<ClCompile Include="..\..\library\platform_util.c" />
<ClCompile Include="..\..\library\poly1305.c" />
<ClCompile Include="..\..\library\psa_crypto.c" />
<ClCompile Include="..\..\library\psa_crypto_slot_management.c" />
<ClCompile Include="..\..\library\psa_crypto_storage.c" />
<ClCompile Include="..\..\library\psa_crypto_storage_file.c" />
<ClCompile Include="..\..\library\psa_crypto_storage_its.c" />