mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-07-30 22:43:08 +03:00
Merge remote-tracking branch 'crypto/pr/212' into development
* crypto/pr/212: (337 commits) Make TODO comments consistent Fix PSA tests Fix psa_generate_random for >1024 bytes Add tests to generate more random than MBEDTLS_CTR_DRBG_MAX_REQUEST Fix double free in psa_generate_key when psa_generate_random fails Fix copypasta in test data Avoid a lowercase letter in a macro name Correct some comments Fix PSA init/deinit in mbedtls_xxx tests when using PSA Make psa_calculate_key_bits return psa_key_bits_t Adjust secure element code to the new ITS interface More refactoring: consolidate attribute validation Fix policy validity check on key creation. Add test function for import with a bad policy Test key creation with an invalid type (0 and nonzero) Remove "allocated" flag from key slots Take advantage of psa_core_key_attributes_t internally #2 Store the key size in the slot in memory Take advantage of psa_core_key_attributes_t internally: key loading Switch storage functions over to psa_core_key_attributes_t ...
This commit is contained in:
@ -61,6 +61,7 @@ set(src_crypto
|
||||
platform_util.c
|
||||
poly1305.c
|
||||
psa_crypto.c
|
||||
psa_crypto_se.c
|
||||
psa_crypto_slot_management.c
|
||||
psa_crypto_storage.c
|
||||
psa_its_file.c
|
||||
|
@ -80,7 +80,7 @@ OBJS_CRYPTO= aes.o aesni.o arc4.o \
|
||||
pk.o pk_wrap.o pkcs12.o \
|
||||
pkcs5.o pkparse.o pkwrite.o \
|
||||
platform.o platform_util.o poly1305.o \
|
||||
psa_crypto.o \
|
||||
psa_crypto.o psa_crypto_se.o \
|
||||
psa_crypto_slot_management.o \
|
||||
psa_crypto_storage.o \
|
||||
psa_its_file.o \
|
||||
|
@ -297,8 +297,7 @@ int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx,
|
||||
|
||||
psa_status_t status;
|
||||
psa_key_type_t key_type;
|
||||
psa_key_usage_t key_usage;
|
||||
psa_key_policy_t key_policy;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
|
||||
/* PSA Crypto API only accepts byte-aligned keys. */
|
||||
if( key_bitlen % 8 != 0 )
|
||||
@ -312,40 +311,33 @@ int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx,
|
||||
ctx->cipher_info->type );
|
||||
if( key_type == 0 )
|
||||
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
|
||||
|
||||
/* Allocate a key slot to use. */
|
||||
status = psa_allocate_key( &cipher_psa->slot );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED );
|
||||
|
||||
/* Indicate that we own the key slot and need to
|
||||
* destroy it in mbedtls_cipher_free(). */
|
||||
cipher_psa->slot_state = MBEDTLS_CIPHER_PSA_KEY_OWNED;
|
||||
|
||||
/* From that point on, the responsibility for destroying the
|
||||
* key slot is on mbedtls_cipher_free(). This includes the case
|
||||
* where the policy setup or key import below fail, as
|
||||
* mbedtls_cipher_free() needs to be called in any case. */
|
||||
|
||||
/* Setup policy for the new key slot. */
|
||||
key_policy = psa_key_policy_init();
|
||||
psa_set_key_type( &attributes, key_type );
|
||||
|
||||
/* Mbed TLS' cipher layer doesn't enforce the mode of operation
|
||||
* (encrypt vs. decrypt): it is possible to setup a key for encryption
|
||||
* and use it for AEAD decryption. Until tests relying on this
|
||||
* are changed, allow any usage in PSA. */
|
||||
/* key_usage = mbedtls_psa_translate_cipher_operation( operation ); */
|
||||
key_usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT;
|
||||
psa_key_policy_set_usage( &key_policy, key_usage, cipher_psa->alg );
|
||||
status = psa_set_key_policy( cipher_psa->slot, &key_policy );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED );
|
||||
psa_set_key_usage_flags( &attributes,
|
||||
/* mbedtls_psa_translate_cipher_operation( operation ); */
|
||||
PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT );
|
||||
psa_set_key_algorithm( &attributes, cipher_psa->alg );
|
||||
|
||||
/* Populate new key slot. */
|
||||
status = psa_import_key( cipher_psa->slot,
|
||||
key_type, key, key_bytelen );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED );
|
||||
status = psa_import_key( &attributes, key, key_bytelen,
|
||||
&cipher_psa->slot );
|
||||
switch( status )
|
||||
{
|
||||
case PSA_SUCCESS:
|
||||
break;
|
||||
case PSA_ERROR_INSUFFICIENT_MEMORY:
|
||||
return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED );
|
||||
case PSA_ERROR_NOT_SUPPORTED:
|
||||
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
|
||||
default:
|
||||
return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED );
|
||||
}
|
||||
/* Indicate that we own the key slot and need to
|
||||
* destroy it in mbedtls_cipher_free(). */
|
||||
cipher_psa->slot_state = MBEDTLS_CIPHER_PSA_KEY_OWNED;
|
||||
|
||||
ctx->key_bitlen = key_bitlen;
|
||||
ctx->operation = operation;
|
||||
|
37
library/pk.c
37
library/pk.c
@ -158,17 +158,20 @@ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info )
|
||||
int mbedtls_pk_setup_opaque( mbedtls_pk_context *ctx, const psa_key_handle_t key )
|
||||
{
|
||||
const mbedtls_pk_info_t * const info = &mbedtls_pk_opaque_info;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_handle_t *pk_ctx;
|
||||
psa_key_type_t type;
|
||||
|
||||
if( ctx == NULL || ctx->pk_info != NULL )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
|
||||
if( PSA_SUCCESS != psa_get_key_information( key, &type, NULL ) )
|
||||
if( PSA_SUCCESS != psa_get_key_attributes( key, &attributes ) )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
type = psa_get_key_type( &attributes );
|
||||
psa_reset_key_attributes( &attributes );
|
||||
|
||||
/* Current implementation of can_do() relies on this. */
|
||||
if( ! PSA_KEY_TYPE_IS_ECC_KEYPAIR( type ) )
|
||||
if( ! PSA_KEY_TYPE_IS_ECC_KEY_PAIR( type ) )
|
||||
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE) ;
|
||||
|
||||
if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL )
|
||||
@ -589,19 +592,18 @@ mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx )
|
||||
* Currently only works for EC private keys.
|
||||
*/
|
||||
int mbedtls_pk_wrap_as_opaque( mbedtls_pk_context *pk,
|
||||
psa_key_handle_t *slot,
|
||||
psa_key_handle_t *handle,
|
||||
psa_algorithm_t hash_alg )
|
||||
{
|
||||
#if !defined(MBEDTLS_ECP_C)
|
||||
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
|
||||
#else
|
||||
psa_key_handle_t key;
|
||||
const mbedtls_ecp_keypair *ec;
|
||||
unsigned char d[MBEDTLS_ECP_MAX_BYTES];
|
||||
size_t d_len;
|
||||
psa_ecc_curve_t curve_id;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_type_t key_type;
|
||||
psa_key_policy_t policy;
|
||||
int ret;
|
||||
|
||||
/* export the private key material in the format PSA wants */
|
||||
@ -614,32 +616,23 @@ int mbedtls_pk_wrap_as_opaque( mbedtls_pk_context *pk,
|
||||
return( ret );
|
||||
|
||||
curve_id = mbedtls_ecp_curve_info_from_grp_id( ec->grp.id )->tls_id;
|
||||
key_type = PSA_KEY_TYPE_ECC_KEYPAIR(
|
||||
key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(
|
||||
mbedtls_psa_parse_tls_ecc_group ( curve_id ) );
|
||||
|
||||
/* allocate a key slot */
|
||||
if( PSA_SUCCESS != psa_allocate_key( &key ) )
|
||||
return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
|
||||
/* prepare the key attributes */
|
||||
psa_set_key_type( &attributes, key_type );
|
||||
psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN );
|
||||
psa_set_key_algorithm( &attributes, PSA_ALG_ECDSA(hash_alg) );
|
||||
|
||||
/* set policy */
|
||||
policy = psa_key_policy_init();
|
||||
psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_SIGN,
|
||||
PSA_ALG_ECDSA(hash_alg) );
|
||||
if( PSA_SUCCESS != psa_set_key_policy( key, &policy ) )
|
||||
/* import private key into PSA */
|
||||
if( PSA_SUCCESS != psa_import_key( &attributes, d, d_len, handle ) )
|
||||
return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
|
||||
|
||||
/* import private key in slot */
|
||||
if( PSA_SUCCESS != psa_import_key( key, key_type, d, d_len ) )
|
||||
return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
|
||||
|
||||
/* remember slot number to be destroyed later by caller */
|
||||
*slot = key;
|
||||
|
||||
/* make PK context wrap the key slot */
|
||||
mbedtls_pk_free( pk );
|
||||
mbedtls_pk_init( pk );
|
||||
|
||||
return( mbedtls_pk_setup_opaque( pk, key ) );
|
||||
return( mbedtls_pk_setup_opaque( pk, *handle ) );
|
||||
#endif /* MBEDTLS_ECP_C */
|
||||
}
|
||||
#endif /* MBEDTLS_USE_PSA_CRYPTO */
|
||||
|
@ -546,9 +546,9 @@ static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
const unsigned char *sig, size_t sig_len )
|
||||
{
|
||||
int ret;
|
||||
psa_key_handle_t key_slot;
|
||||
psa_key_policy_t policy;
|
||||
psa_key_type_t psa_type;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_handle_t key_handle = 0;
|
||||
psa_status_t status;
|
||||
mbedtls_pk_context key;
|
||||
int key_len;
|
||||
/* see ECP_PUB_DER_MAX_BYTES in pkwrite.c */
|
||||
@ -576,23 +576,17 @@ static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
if( psa_md == 0 )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
psa_sig_md = PSA_ALG_ECDSA( psa_md );
|
||||
psa_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY( curve );
|
||||
|
||||
if( ( ret = psa_allocate_key( &key_slot ) ) != PSA_SUCCESS )
|
||||
return( mbedtls_psa_err_translate_pk( ret ) );
|
||||
psa_set_key_type( &attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY( curve ) );
|
||||
psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY );
|
||||
psa_set_key_algorithm( &attributes, psa_sig_md );
|
||||
|
||||
policy = psa_key_policy_init();
|
||||
psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_VERIFY, psa_sig_md );
|
||||
if( ( ret = psa_set_key_policy( key_slot, &policy ) ) != PSA_SUCCESS )
|
||||
status = psa_import_key( &attributes,
|
||||
buf + sizeof( buf ) - key_len, key_len,
|
||||
&key_handle );
|
||||
if( status != PSA_SUCCESS )
|
||||
{
|
||||
ret = mbedtls_psa_err_translate_pk( ret );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if( psa_import_key( key_slot, psa_type, buf + sizeof( buf ) - key_len, key_len )
|
||||
!= PSA_SUCCESS )
|
||||
{
|
||||
ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
|
||||
ret = mbedtls_psa_err_translate_pk( status );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -611,7 +605,7 @@ static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if( psa_asymmetric_verify( key_slot, psa_sig_md,
|
||||
if( psa_asymmetric_verify( key_handle, psa_sig_md,
|
||||
hash, hash_len,
|
||||
buf, 2 * signature_part_size )
|
||||
!= PSA_SUCCESS )
|
||||
@ -628,7 +622,7 @@ static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
psa_destroy_key( key_slot );
|
||||
psa_destroy_key( key_handle );
|
||||
return( ret );
|
||||
}
|
||||
#else /* MBEDTLS_USE_PSA_CRYPTO */
|
||||
@ -898,10 +892,13 @@ static size_t pk_opaque_get_bitlen( const void *ctx )
|
||||
{
|
||||
const psa_key_handle_t *key = (const psa_key_handle_t *) ctx;
|
||||
size_t bits;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
|
||||
if( PSA_SUCCESS != psa_get_key_information( *key, NULL, &bits ) )
|
||||
if( PSA_SUCCESS != psa_get_key_attributes( *key, &attributes ) )
|
||||
return( 0 );
|
||||
|
||||
bits = psa_get_key_bits( &attributes );
|
||||
psa_reset_key_attributes( &attributes );
|
||||
return( bits );
|
||||
}
|
||||
|
||||
@ -1002,8 +999,9 @@ static int pk_opaque_sign_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
|
||||
{
|
||||
const psa_key_handle_t *key = (const psa_key_handle_t *) ctx;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_algorithm_t alg = PSA_ALG_ECDSA( mbedtls_psa_translate_md( md_alg ) );
|
||||
size_t bits, buf_len;
|
||||
size_t buf_len;
|
||||
psa_status_t status;
|
||||
|
||||
/* PSA has its own RNG */
|
||||
@ -1014,11 +1012,11 @@ static int pk_opaque_sign_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
* that information. Assume that the buffer is large enough for a
|
||||
* maximal-length signature with that key (otherwise the application is
|
||||
* buggy anyway). */
|
||||
status = psa_get_key_information( *key, NULL, &bits );
|
||||
status = psa_get_key_attributes( *key, &attributes );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( mbedtls_psa_err_translate_pk( status ) );
|
||||
|
||||
buf_len = MBEDTLS_ECDSA_MAX_SIG_LEN( bits );
|
||||
buf_len = MBEDTLS_ECDSA_MAX_SIG_LEN( psa_get_key_bits( &attributes ) );
|
||||
psa_reset_key_attributes( &attributes );
|
||||
|
||||
/* make the signature */
|
||||
status = psa_asymmetric_sign( *key, alg, hash, hash_len,
|
||||
|
@ -246,17 +246,16 @@ int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, si
|
||||
#if defined(MBEDTLS_USE_PSA_CRYPTO)
|
||||
if( pk_type == MBEDTLS_PK_OPAQUE )
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_type_t key_type;
|
||||
psa_key_handle_t handle;
|
||||
psa_ecc_curve_t curve;
|
||||
|
||||
handle = *((psa_key_handle_t*) key->pk_ctx );
|
||||
|
||||
status = psa_get_key_information( handle, &key_type,
|
||||
NULL /* bitsize not needed */ );
|
||||
if( status != PSA_SUCCESS )
|
||||
if( PSA_SUCCESS != psa_get_key_attributes( handle, &attributes ) )
|
||||
return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
|
||||
key_type = psa_get_key_type( &attributes );
|
||||
psa_reset_key_attributes( &attributes );
|
||||
|
||||
curve = PSA_KEY_TYPE_GET_CURVE( key_type );
|
||||
if( curve == 0 )
|
||||
|
2461
library/psa_crypto.c
2461
library/psa_crypto.c
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@
|
||||
#endif
|
||||
|
||||
#include "psa/crypto.h"
|
||||
#include "psa/crypto_se_driver.h"
|
||||
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/rsa.h"
|
||||
@ -38,27 +39,95 @@
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
psa_key_type_t type;
|
||||
psa_key_policy_t policy;
|
||||
psa_key_lifetime_t lifetime;
|
||||
psa_key_file_id_t persistent_storage_id;
|
||||
unsigned allocated : 1;
|
||||
psa_core_key_attributes_t attr;
|
||||
union
|
||||
{
|
||||
/* Raw-data key (key_type_is_raw_bytes() in psa_crypto.c) */
|
||||
struct raw_data
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t bytes;
|
||||
} raw;
|
||||
#if defined(MBEDTLS_RSA_C)
|
||||
/* RSA public key or key pair */
|
||||
mbedtls_rsa_context *rsa;
|
||||
#endif /* MBEDTLS_RSA_C */
|
||||
#if defined(MBEDTLS_ECP_C)
|
||||
/* EC public key or key pair */
|
||||
mbedtls_ecp_keypair *ecp;
|
||||
#endif /* MBEDTLS_ECP_C */
|
||||
/* Any key type in a secure element */
|
||||
struct se
|
||||
{
|
||||
psa_key_slot_number_t slot_number;
|
||||
} se;
|
||||
} data;
|
||||
} psa_key_slot_t;
|
||||
|
||||
/** Test whether a key slot is occupied.
|
||||
*
|
||||
* A key slot is occupied iff the key type is nonzero. This works because
|
||||
* no valid key can have 0 as its key type.
|
||||
*
|
||||
* \param[in] slot The key slot to test.
|
||||
*
|
||||
* \return 1 if the slot is occupied, 0 otherwise.
|
||||
*/
|
||||
static inline int psa_is_key_slot_occupied( const psa_key_slot_t *slot )
|
||||
{
|
||||
return( slot->attr.type != 0 );
|
||||
}
|
||||
|
||||
/** Retrieve flags from psa_key_slot_t::attr::core::flags.
|
||||
*
|
||||
* \param[in] slot The key slot to query.
|
||||
* \param mask The mask of bits to extract.
|
||||
*
|
||||
* \return The key attribute flags in the given slot,
|
||||
* bitwise-anded with \p mask.
|
||||
*/
|
||||
static inline uint16_t psa_key_slot_get_flags( const psa_key_slot_t *slot,
|
||||
uint16_t mask )
|
||||
{
|
||||
return( slot->attr.flags & mask );
|
||||
}
|
||||
|
||||
/** Set flags in psa_key_slot_t::attr::core::flags.
|
||||
*
|
||||
* \param[in,out] slot The key slot to modify.
|
||||
* \param mask The mask of bits to modify.
|
||||
* \param value The new value of the selected bits.
|
||||
*/
|
||||
static inline void psa_key_slot_set_flags( psa_key_slot_t *slot,
|
||||
uint16_t mask,
|
||||
uint16_t value )
|
||||
{
|
||||
slot->attr.flags = ( ( ~mask & slot->attr.flags ) |
|
||||
( mask & value ) );
|
||||
}
|
||||
|
||||
/** Turn on flags in psa_key_slot_t::attr::core::flags.
|
||||
*
|
||||
* \param[in,out] slot The key slot to modify.
|
||||
* \param mask The mask of bits to set.
|
||||
*/
|
||||
static inline void psa_key_slot_set_bits_in_flags( psa_key_slot_t *slot,
|
||||
uint16_t mask )
|
||||
{
|
||||
slot->attr.flags |= mask;
|
||||
}
|
||||
|
||||
/** Turn off flags in psa_key_slot_t::attr::core::flags.
|
||||
*
|
||||
* \param[in,out] slot The key slot to modify.
|
||||
* \param mask The mask of bits to clear.
|
||||
*/
|
||||
static inline void psa_key_slot_clear_bits( psa_key_slot_t *slot,
|
||||
uint16_t mask )
|
||||
{
|
||||
slot->attr.flags &= ~mask;
|
||||
}
|
||||
|
||||
/** Completely wipe a slot in memory, including its policy.
|
||||
*
|
||||
* Persistent storage is not affected.
|
||||
@ -68,7 +137,7 @@ typedef struct
|
||||
* \retval PSA_SUCCESS
|
||||
* Success. This includes the case of a key slot that was
|
||||
* already fully wiped.
|
||||
* \retval PSA_ERROR_TAMPERING_DETECTED
|
||||
* \retval PSA_ERROR_CORRUPTION_DETECTED
|
||||
*/
|
||||
psa_status_t psa_wipe_key_slot( psa_key_slot_t *slot );
|
||||
|
||||
|
339
library/psa_crypto_se.c
Normal file
339
library/psa_crypto_se.c
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* PSA crypto support for secure element drivers
|
||||
*/
|
||||
/* Copyright (C) 2019, 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_SE_C)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "psa/crypto_se_driver.h"
|
||||
|
||||
#include "psa_crypto_se.h"
|
||||
|
||||
#if defined(MBEDTLS_PSA_ITS_FILE_C)
|
||||
#include "psa_crypto_its.h"
|
||||
#else /* Native ITS implementation */
|
||||
#include "psa/error.h"
|
||||
#include "psa/internal_trusted_storage.h"
|
||||
#endif
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
#if !defined(MBEDTLS_PLATFORM_C)
|
||||
#define mbedtls_calloc calloc
|
||||
#define mbedtls_free free
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Driver lookup */
|
||||
/****************************************************************/
|
||||
|
||||
/* This structure is identical to psa_drv_se_context_t declared in
|
||||
* `crypto_se_driver.h`, except that some parts are writable here
|
||||
* (non-const, or pointer to non-const). */
|
||||
typedef struct
|
||||
{
|
||||
void *persistent_data;
|
||||
size_t persistent_data_size;
|
||||
uintptr_t transient_data;
|
||||
} psa_drv_se_internal_context_t;
|
||||
|
||||
typedef struct psa_se_drv_table_entry_s
|
||||
{
|
||||
psa_key_lifetime_t lifetime;
|
||||
const psa_drv_se_t *methods;
|
||||
union
|
||||
{
|
||||
psa_drv_se_internal_context_t internal;
|
||||
psa_drv_se_context_t context;
|
||||
};
|
||||
} psa_se_drv_table_entry_t;
|
||||
|
||||
static psa_se_drv_table_entry_t driver_table[PSA_MAX_SE_DRIVERS];
|
||||
|
||||
psa_se_drv_table_entry_t *psa_get_se_driver_entry(
|
||||
psa_key_lifetime_t lifetime )
|
||||
{
|
||||
size_t i;
|
||||
/* In the driver table, lifetime=0 means an entry that isn't used.
|
||||
* No driver has a lifetime of 0 because it's a reserved value
|
||||
* (which designates volatile keys). Make sure we never return
|
||||
* a driver entry for lifetime 0. */
|
||||
if( lifetime == 0 )
|
||||
return( NULL );
|
||||
for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
|
||||
{
|
||||
if( driver_table[i].lifetime == lifetime )
|
||||
return( &driver_table[i] );
|
||||
}
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
const psa_drv_se_t *psa_get_se_driver_methods(
|
||||
const psa_se_drv_table_entry_t *driver )
|
||||
{
|
||||
return( driver->methods );
|
||||
}
|
||||
|
||||
psa_drv_se_context_t *psa_get_se_driver_context(
|
||||
psa_se_drv_table_entry_t *driver )
|
||||
{
|
||||
return( &driver->context );
|
||||
}
|
||||
|
||||
int psa_get_se_driver( psa_key_lifetime_t lifetime,
|
||||
const psa_drv_se_t **p_methods,
|
||||
psa_drv_se_context_t **p_drv_context)
|
||||
{
|
||||
psa_se_drv_table_entry_t *driver = psa_get_se_driver_entry( lifetime );
|
||||
if( p_methods != NULL )
|
||||
*p_methods = ( driver ? driver->methods : NULL );
|
||||
if( p_drv_context != NULL )
|
||||
*p_drv_context = ( driver ? &driver->context : NULL );
|
||||
return( driver != NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Persistent data management */
|
||||
/****************************************************************/
|
||||
|
||||
static psa_status_t psa_get_se_driver_its_file_uid(
|
||||
const psa_se_drv_table_entry_t *driver,
|
||||
psa_storage_uid_t *uid )
|
||||
{
|
||||
if( driver->lifetime > PSA_MAX_SE_LIFETIME )
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
/* ITS file sizes are limited to 32 bits. */
|
||||
if( driver->internal.persistent_data_size > UINT32_MAX )
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
#endif
|
||||
|
||||
/* See the documentation of PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE. */
|
||||
*uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + driver->lifetime;
|
||||
return( PSA_SUCCESS );
|
||||
}
|
||||
|
||||
psa_status_t psa_load_se_persistent_data(
|
||||
const psa_se_drv_table_entry_t *driver )
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_storage_uid_t uid;
|
||||
size_t length;
|
||||
|
||||
status = psa_get_se_driver_its_file_uid( driver, &uid );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( status );
|
||||
|
||||
/* Read the amount of persistent data that the driver requests.
|
||||
* If the data in storage is larger, it is truncated. If the data
|
||||
* in storage is smaller, silently keep what is already at the end
|
||||
* of the output buffer. */
|
||||
/* psa_get_se_driver_its_file_uid ensures that the size_t
|
||||
* persistent_data_size is in range, but compilers don't know that,
|
||||
* so cast to reassure them. */
|
||||
return( psa_its_get( uid, 0,
|
||||
(uint32_t) driver->internal.persistent_data_size,
|
||||
driver->internal.persistent_data,
|
||||
&length ) );
|
||||
}
|
||||
|
||||
psa_status_t psa_save_se_persistent_data(
|
||||
const psa_se_drv_table_entry_t *driver )
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_storage_uid_t uid;
|
||||
|
||||
status = psa_get_se_driver_its_file_uid( driver, &uid );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( status );
|
||||
|
||||
/* psa_get_se_driver_its_file_uid ensures that the size_t
|
||||
* persistent_data_size is in range, but compilers don't know that,
|
||||
* so cast to reassure them. */
|
||||
return( psa_its_set( uid,
|
||||
(uint32_t) driver->internal.persistent_data_size,
|
||||
driver->internal.persistent_data,
|
||||
0 ) );
|
||||
}
|
||||
|
||||
psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime )
|
||||
{
|
||||
psa_storage_uid_t uid;
|
||||
if( lifetime > PSA_MAX_SE_LIFETIME )
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime;
|
||||
return( psa_its_remove( uid ) );
|
||||
}
|
||||
|
||||
psa_status_t psa_find_se_slot_for_key(
|
||||
const psa_key_attributes_t *attributes,
|
||||
psa_se_drv_table_entry_t *driver,
|
||||
psa_key_slot_number_t *slot_number )
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_drv_se_allocate_key_t p_allocate = NULL;
|
||||
|
||||
/* If the lifetime is wrong, it's a bug in the library. */
|
||||
if( driver->lifetime != psa_get_key_lifetime( attributes ) )
|
||||
return( PSA_ERROR_CORRUPTION_DETECTED );
|
||||
|
||||
/* If the driver doesn't support key creation in any way, give up now. */
|
||||
if( driver->methods->key_management == NULL )
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
p_allocate = driver->methods->key_management->p_allocate;
|
||||
|
||||
/* If the driver doesn't tell us how to allocate a slot, that's
|
||||
* not supported for the time being. */
|
||||
if( p_allocate == NULL )
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
|
||||
status = p_allocate( &driver->context,
|
||||
driver->internal.persistent_data,
|
||||
attributes,
|
||||
slot_number );
|
||||
return( status );
|
||||
}
|
||||
|
||||
psa_status_t psa_destroy_se_key( psa_se_drv_table_entry_t *driver,
|
||||
psa_key_slot_number_t slot_number )
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_status_t storage_status;
|
||||
/* Normally a missing method would mean that the action is not
|
||||
* supported. But psa_destroy_key() is not supposed to return
|
||||
* PSA_ERROR_NOT_SUPPORTED: if you can create a key, you should
|
||||
* be able to destroy it. The only use case for a driver that
|
||||
* does not have a way to destroy keys at all is if the keys are
|
||||
* locked in a read-only state: we can use the keys but not
|
||||
* destroy them. Hence, if the driver doesn't support destroying
|
||||
* keys, it's really a lack of permission. */
|
||||
if( driver->methods->key_management == NULL ||
|
||||
driver->methods->key_management->p_destroy == NULL )
|
||||
return( PSA_ERROR_NOT_PERMITTED );
|
||||
status = driver->methods->key_management->p_destroy(
|
||||
&driver->context,
|
||||
driver->internal.persistent_data,
|
||||
slot_number );
|
||||
storage_status = psa_save_se_persistent_data( driver );
|
||||
return( status == PSA_SUCCESS ? storage_status : status );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Driver registration */
|
||||
/****************************************************************/
|
||||
|
||||
psa_status_t psa_register_se_driver(
|
||||
psa_key_lifetime_t lifetime,
|
||||
const psa_drv_se_t *methods)
|
||||
{
|
||||
size_t i;
|
||||
psa_status_t status;
|
||||
|
||||
if( methods->hal_version != PSA_DRV_SE_HAL_VERSION )
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
/* Driver table entries are 0-initialized. 0 is not a valid driver
|
||||
* lifetime because it means a volatile key. */
|
||||
#if defined(static_assert)
|
||||
static_assert( PSA_KEY_LIFETIME_VOLATILE == 0,
|
||||
"Secure element support requires 0 to mean a volatile key" );
|
||||
#endif
|
||||
if( lifetime == PSA_KEY_LIFETIME_VOLATILE ||
|
||||
lifetime == PSA_KEY_LIFETIME_PERSISTENT )
|
||||
{
|
||||
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||
}
|
||||
if( lifetime > PSA_MAX_SE_LIFETIME )
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
|
||||
for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
|
||||
{
|
||||
if( driver_table[i].lifetime == 0 )
|
||||
break;
|
||||
/* Check that lifetime isn't already in use up to the first free
|
||||
* entry. Since entries are created in order and never deleted,
|
||||
* there can't be a used entry after the first free entry. */
|
||||
if( driver_table[i].lifetime == lifetime )
|
||||
return( PSA_ERROR_ALREADY_EXISTS );
|
||||
}
|
||||
if( i == PSA_MAX_SE_DRIVERS )
|
||||
return( PSA_ERROR_INSUFFICIENT_MEMORY );
|
||||
|
||||
driver_table[i].lifetime = lifetime;
|
||||
driver_table[i].methods = methods;
|
||||
|
||||
if( methods->persistent_data_size != 0 )
|
||||
{
|
||||
driver_table[i].internal.persistent_data =
|
||||
mbedtls_calloc( 1, methods->persistent_data_size );
|
||||
if( driver_table[i].internal.persistent_data == NULL )
|
||||
{
|
||||
status = PSA_ERROR_INSUFFICIENT_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
/* Load the driver's persistent data. On first use, the persistent
|
||||
* data does not exist in storage, and is initialized to
|
||||
* all-bits-zero by the calloc call just above. */
|
||||
status = psa_load_se_persistent_data( &driver_table[i] );
|
||||
if( status != PSA_SUCCESS && status != PSA_ERROR_DOES_NOT_EXIST )
|
||||
goto error;
|
||||
}
|
||||
driver_table[i].internal.persistent_data_size =
|
||||
methods->persistent_data_size;
|
||||
|
||||
return( PSA_SUCCESS );
|
||||
|
||||
error:
|
||||
memset( &driver_table[i], 0, sizeof( driver_table[i] ) );
|
||||
return( status );
|
||||
}
|
||||
|
||||
void psa_unregister_all_se_drivers( void )
|
||||
{
|
||||
size_t i;
|
||||
for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
|
||||
{
|
||||
if( driver_table[i].internal.persistent_data != NULL )
|
||||
mbedtls_free( driver_table[i].internal.persistent_data );
|
||||
}
|
||||
memset( driver_table, 0, sizeof( driver_table ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* The end */
|
||||
/****************************************************************/
|
||||
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
|
183
library/psa_crypto_se.h
Normal file
183
library/psa_crypto_se.h
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* PSA crypto support for secure element drivers
|
||||
*/
|
||||
/* Copyright (C) 2019, 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_SE_H
|
||||
#define PSA_CRYPTO_SE_H
|
||||
|
||||
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||
#include "mbedtls/config.h"
|
||||
#else
|
||||
#include MBEDTLS_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
#include "psa/crypto.h"
|
||||
#include "psa/crypto_se_driver.h"
|
||||
|
||||
/** The maximum lifetime value that this implementation supports
|
||||
* for a secure element.
|
||||
*
|
||||
* This is not a characteristic that each PSA implementation has, but a
|
||||
* limitation of the current implementation due to the constraints imposed
|
||||
* by storage. See #PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE.
|
||||
*
|
||||
* The minimum lifetime value for a secure element is 2, like on any
|
||||
* PSA implementation (0=volatile and 1=internal-storage are taken).
|
||||
*/
|
||||
#define PSA_MAX_SE_LIFETIME 255
|
||||
|
||||
/** The base of the range of ITS file identifiers for secure element
|
||||
* driver persistent data.
|
||||
*
|
||||
* We use a slice of the implemenation reserved range 0xffff0000..0xffffffff,
|
||||
* specifically the range 0xfffffe00..0xfffffeff. The length of this range
|
||||
* drives the value of #PSA_MAX_SE_LIFETIME.
|
||||
* The identifiers 0xfffffe00 and 0xfffffe01 are actually not used since
|
||||
* they correspond to #PSA_KEY_LIFETIME_VOLATILE and
|
||||
* #PSA_KEY_LIFETIME_PERSISTENT which don't have a driver.
|
||||
*/
|
||||
#define PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE ( (psa_key_id_t) 0xfffffe00 )
|
||||
|
||||
/** The maximum number of registered secure element driver lifetimes. */
|
||||
#define PSA_MAX_SE_DRIVERS 4
|
||||
|
||||
/** Unregister all secure element drivers.
|
||||
*
|
||||
* \warning Do not call this function while the library is in the initialized
|
||||
* state. This function is only intended to be called at the end
|
||||
* of mbedtls_psa_crypto_free().
|
||||
*/
|
||||
void psa_unregister_all_se_drivers( void );
|
||||
|
||||
/** A structure that describes a registered secure element driver.
|
||||
*
|
||||
* A secure element driver table entry contains a pointer to the
|
||||
* driver's method table as well as the driver context structure.
|
||||
*/
|
||||
typedef struct psa_se_drv_table_entry_s psa_se_drv_table_entry_t;
|
||||
|
||||
/** Return the secure element driver information for a lifetime value.
|
||||
*
|
||||
* \param lifetime The lifetime value to query.
|
||||
* \param[out] p_methods On output, if there is a driver,
|
||||
* \c *methods points to its method table.
|
||||
* Otherwise \c *methods is \c NULL.
|
||||
* \param[out] p_drv_context On output, if there is a driver,
|
||||
* \c *drv_context points to its context
|
||||
* structure.
|
||||
* Otherwise \c *drv_context is \c NULL.
|
||||
*
|
||||
* \retval 1
|
||||
* \p lifetime corresponds to a registered driver.
|
||||
* \retval 0
|
||||
* \p lifetime does not correspond to a registered driver.
|
||||
*/
|
||||
int psa_get_se_driver( psa_key_lifetime_t lifetime,
|
||||
const psa_drv_se_t **p_methods,
|
||||
psa_drv_se_context_t **p_drv_context);
|
||||
|
||||
/** Return the secure element driver table entry for a lifetime value.
|
||||
*
|
||||
* \param lifetime The lifetime value to query.
|
||||
*
|
||||
* \return The driver table entry for \p lifetime, or
|
||||
* \p NULL if \p lifetime does not correspond to a registered driver.
|
||||
*/
|
||||
psa_se_drv_table_entry_t *psa_get_se_driver_entry(
|
||||
psa_key_lifetime_t lifetime );
|
||||
|
||||
/** Return the method table for a secure element driver.
|
||||
*
|
||||
* \param[in] driver The driver table entry to access, or \c NULL.
|
||||
*
|
||||
* \return The driver's method table.
|
||||
* \c NULL if \p driver is \c NULL.
|
||||
*/
|
||||
const psa_drv_se_t *psa_get_se_driver_methods(
|
||||
const psa_se_drv_table_entry_t *driver );
|
||||
|
||||
/** Return the context of a secure element driver.
|
||||
*
|
||||
* \param[in] driver The driver table entry to access, or \c NULL.
|
||||
*
|
||||
* \return A pointer to the driver context.
|
||||
* \c NULL if \p driver is \c NULL.
|
||||
*/
|
||||
psa_drv_se_context_t *psa_get_se_driver_context(
|
||||
psa_se_drv_table_entry_t *driver );
|
||||
|
||||
/** Find a free slot for a key that is to be created.
|
||||
*
|
||||
* This function calls the relevant method in the driver to find a suitable
|
||||
* slot for a key with the given attributes.
|
||||
*
|
||||
* \param[in] attributes Metadata about the key that is about to be created.
|
||||
* \param[in] driver The driver table entry to query.
|
||||
* \param[out] slot_number On success, a slot number that is free in this
|
||||
* secure element.
|
||||
*/
|
||||
psa_status_t psa_find_se_slot_for_key(
|
||||
const psa_key_attributes_t *attributes,
|
||||
psa_se_drv_table_entry_t *driver,
|
||||
psa_key_slot_number_t *slot_number );
|
||||
|
||||
/** Destoy a key in a secure element.
|
||||
*
|
||||
* This function calls the relevant driver method to destroy a key
|
||||
* and updates the driver's persistent data.
|
||||
*/
|
||||
psa_status_t psa_destroy_se_key( psa_se_drv_table_entry_t *driver,
|
||||
psa_key_slot_number_t slot_number );
|
||||
|
||||
/** Load the persistent data of a secure element driver.
|
||||
*
|
||||
* \param driver The driver table entry containing the persistent
|
||||
* data to load from storage.
|
||||
*/
|
||||
psa_status_t psa_load_se_persistent_data(
|
||||
const psa_se_drv_table_entry_t *driver );
|
||||
|
||||
/** Save the persistent data of a secure element driver.
|
||||
*
|
||||
* \param[in] driver The driver table entry containing the persistent
|
||||
* data to save to storage.
|
||||
*/
|
||||
psa_status_t psa_save_se_persistent_data(
|
||||
const psa_se_drv_table_entry_t *driver );
|
||||
|
||||
/** Destroy the persistent data of a secure element driver.
|
||||
*
|
||||
* This is currently only used for testing.
|
||||
*
|
||||
* \param[in] lifetime The driver lifetime whose persistent data should
|
||||
* be erased.
|
||||
*/
|
||||
psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime );
|
||||
|
||||
|
||||
/** The storage representation of a key whose data is in a secure element.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t slot_number[sizeof( psa_key_slot_number_t )];
|
||||
uint8_t bits[sizeof( psa_key_bits_t )];
|
||||
} psa_se_key_data_storage_t;
|
||||
|
||||
#endif /* PSA_CRYPTO_SE_H */
|
@ -33,6 +33,9 @@
|
||||
#include "psa_crypto_core.h"
|
||||
#include "psa_crypto_slot_management.h"
|
||||
#include "psa_crypto_storage.h"
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||
#include "psa_crypto_se.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -71,8 +74,8 @@ psa_status_t psa_get_key_slot( psa_key_handle_t handle,
|
||||
return( PSA_ERROR_INVALID_HANDLE );
|
||||
slot = &global_data.key_slots[handle - 1];
|
||||
|
||||
/* If the slot hasn't been allocated, the handle is invalid. */
|
||||
if( ! slot->allocated )
|
||||
/* If the slot isn't occupied, the handle is invalid. */
|
||||
if( ! psa_is_key_slot_occupied( slot ) )
|
||||
return( PSA_ERROR_INVALID_HANDLE );
|
||||
|
||||
*p_slot = slot;
|
||||
@ -99,71 +102,55 @@ void psa_wipe_all_key_slots( void )
|
||||
global_data.key_slots_initialized = 0;
|
||||
}
|
||||
|
||||
/** Find a free key slot and mark it as in use.
|
||||
*
|
||||
* \param[out] handle On success, a slot number that is not in use. This
|
||||
* value can be used as a handle to the slot.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
|
||||
*/
|
||||
static psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle )
|
||||
psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle,
|
||||
psa_key_slot_t **p_slot )
|
||||
{
|
||||
if( ! global_data.key_slots_initialized )
|
||||
return( PSA_ERROR_BAD_STATE );
|
||||
|
||||
for( *handle = PSA_KEY_SLOT_COUNT; *handle != 0; --( *handle ) )
|
||||
{
|
||||
psa_key_slot_t *slot = &global_data.key_slots[*handle - 1];
|
||||
if( ! slot->allocated )
|
||||
{
|
||||
slot->allocated = 1;
|
||||
*p_slot = &global_data.key_slots[*handle - 1];
|
||||
if( ! psa_is_key_slot_occupied( *p_slot ) )
|
||||
return( PSA_SUCCESS );
|
||||
}
|
||||
}
|
||||
*p_slot = NULL;
|
||||
return( PSA_ERROR_INSUFFICIENT_MEMORY );
|
||||
}
|
||||
|
||||
/** Wipe a key slot and mark it as available.
|
||||
*
|
||||
* This does not affect persistent storage.
|
||||
*
|
||||
* \param handle The handle to the key slot to release.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* \retval #PSA_ERROR_INVALID_ARGUMENT
|
||||
* \retval #PSA_ERROR_TAMPERING_DETECTED
|
||||
*/
|
||||
static psa_status_t psa_internal_release_key_slot( psa_key_handle_t handle )
|
||||
{
|
||||
psa_key_slot_t *slot;
|
||||
psa_status_t status;
|
||||
|
||||
status = psa_get_key_slot( handle, &slot );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( status );
|
||||
|
||||
return( psa_wipe_key_slot( slot ) );
|
||||
}
|
||||
|
||||
psa_status_t psa_allocate_key( psa_key_handle_t *handle )
|
||||
{
|
||||
*handle = 0;
|
||||
return( psa_internal_allocate_key_slot( handle ) );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
|
||||
static psa_status_t psa_load_persistent_key_into_slot( psa_key_slot_t *p_slot )
|
||||
static psa_status_t psa_load_persistent_key_into_slot( psa_key_slot_t *slot )
|
||||
{
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
uint8_t *key_data = NULL;
|
||||
size_t key_data_length = 0;
|
||||
|
||||
status = psa_load_persistent_key( p_slot->persistent_storage_id,
|
||||
&( p_slot )->type,
|
||||
&( p_slot )->policy, &key_data,
|
||||
&key_data_length );
|
||||
status = psa_load_persistent_key( &slot->attr,
|
||||
&key_data, &key_data_length );
|
||||
if( status != PSA_SUCCESS )
|
||||
goto exit;
|
||||
status = psa_import_key_into_slot( p_slot,
|
||||
key_data, key_data_length );
|
||||
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||
if( psa_key_lifetime_is_external( slot->attr.lifetime ) )
|
||||
{
|
||||
psa_se_key_data_storage_t *data;
|
||||
if( key_data_length != sizeof( *data ) )
|
||||
{
|
||||
status = PSA_ERROR_STORAGE_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
data = (psa_se_key_data_storage_t *) key_data;
|
||||
memcpy( &slot->data.se.slot_number, &data->slot_number,
|
||||
sizeof( slot->data.se.slot_number ) );
|
||||
memcpy( &slot->attr.bits, &data->bits,
|
||||
sizeof( slot->attr.bits ) );
|
||||
}
|
||||
else
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
|
||||
{
|
||||
status = psa_import_key_into_slot( slot, key_data, key_data_length );
|
||||
}
|
||||
|
||||
exit:
|
||||
psa_free_persistent_key_data( key_data, key_data_length );
|
||||
return( status );
|
||||
@ -176,120 +163,132 @@ exit:
|
||||
* is provided.
|
||||
*
|
||||
* \param file_id The key identifier to check.
|
||||
* \param vendor_ok Nonzero to allow key ids in the vendor range.
|
||||
* 0 to allow only key ids in the application range.
|
||||
*
|
||||
* \return 1 if \p file_id is acceptable, otherwise 0.
|
||||
*/
|
||||
static int psa_is_key_id_valid( psa_key_file_id_t file_id )
|
||||
static int psa_is_key_id_valid( psa_key_file_id_t file_id,
|
||||
int vendor_ok )
|
||||
{
|
||||
psa_app_key_id_t key_id = PSA_KEY_FILE_GET_KEY_ID( file_id );
|
||||
/* Reject id=0 because by general library conventions, 0 is an invalid
|
||||
* value wherever possible. */
|
||||
if( key_id == 0 )
|
||||
if( PSA_KEY_ID_USER_MIN <= key_id && key_id <= PSA_KEY_ID_USER_MAX )
|
||||
return( 1 );
|
||||
else if( vendor_ok &&
|
||||
PSA_KEY_ID_VENDOR_MIN <= key_id &&
|
||||
key_id <= PSA_KEY_ID_VENDOR_MAX )
|
||||
return( 1 );
|
||||
else
|
||||
return( 0 );
|
||||
/* Reject high values because the file names are reserved for the
|
||||
* library's internal use. */
|
||||
if( key_id > PSA_MAX_PERSISTENT_KEY_IDENTIFIER )
|
||||
return( 0 );
|
||||
return( 1 );
|
||||
}
|
||||
#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
|
||||
|
||||
/** 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_DOES_NOT_EXIST
|
||||
* 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
|
||||
*/
|
||||
static psa_status_t psa_internal_make_key_persistent( psa_key_handle_t handle,
|
||||
psa_key_file_id_t id )
|
||||
psa_status_t psa_validate_persistent_key_parameters(
|
||||
psa_key_lifetime_t lifetime,
|
||||
psa_key_file_id_t id,
|
||||
psa_se_drv_table_entry_t **p_drv,
|
||||
int creating )
|
||||
{
|
||||
if( p_drv != NULL )
|
||||
*p_drv = NULL;
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||
if( psa_key_lifetime_is_external( lifetime ) )
|
||||
{
|
||||
*p_drv = psa_get_se_driver_entry( lifetime );
|
||||
if( *p_drv == NULL )
|
||||
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||
}
|
||||
else
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
|
||||
if( lifetime != PSA_KEY_LIFETIME_PERSISTENT )
|
||||
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
|
||||
if( ! psa_is_key_id_valid( id, ! creating ) )
|
||||
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||
return( PSA_SUCCESS );
|
||||
|
||||
#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
|
||||
(void) id;
|
||||
(void) creating;
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
#endif /* !MBEDTLS_PSA_CRYPTO_STORAGE_C */
|
||||
}
|
||||
|
||||
psa_status_t psa_open_key( psa_key_file_id_t id, psa_key_handle_t *handle )
|
||||
{
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
|
||||
psa_key_slot_t *slot;
|
||||
psa_status_t status;
|
||||
psa_key_slot_t *slot;
|
||||
|
||||
if( ! psa_is_key_id_valid( id ) )
|
||||
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||
*handle = 0;
|
||||
|
||||
status = psa_validate_persistent_key_parameters(
|
||||
PSA_KEY_LIFETIME_PERSISTENT, id, NULL, 0 );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( status );
|
||||
|
||||
status = psa_internal_allocate_key_slot( handle, &slot );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( status );
|
||||
|
||||
slot->attr.lifetime = PSA_KEY_LIFETIME_PERSISTENT;
|
||||
slot->attr.id = id;
|
||||
|
||||
status = psa_load_persistent_key_into_slot( slot );
|
||||
if( status != PSA_SUCCESS )
|
||||
{
|
||||
psa_wipe_key_slot( slot );
|
||||
*handle = 0;
|
||||
}
|
||||
return( status );
|
||||
|
||||
#else /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
|
||||
(void) id;
|
||||
*handle = 0;
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
#endif /* !defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
|
||||
}
|
||||
|
||||
psa_status_t psa_close_key( psa_key_handle_t handle )
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_key_slot_t *slot;
|
||||
|
||||
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 );
|
||||
|
||||
#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
|
||||
(void) handle;
|
||||
(void) id;
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
#endif /* !MBEDTLS_PSA_CRYPTO_STORAGE_C */
|
||||
return( psa_wipe_key_slot( slot ) );
|
||||
}
|
||||
|
||||
static psa_status_t persistent_key_setup( psa_key_lifetime_t lifetime,
|
||||
psa_key_file_id_t id,
|
||||
psa_key_handle_t *handle,
|
||||
psa_status_t wanted_load_status )
|
||||
void mbedtls_psa_get_stats( mbedtls_psa_stats_t *stats )
|
||||
{
|
||||
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_key_handle_t key;
|
||||
memset( stats, 0, sizeof( *stats ) );
|
||||
for( key = 1; key <= PSA_KEY_SLOT_COUNT; key++ )
|
||||
{
|
||||
psa_internal_release_key_slot( *handle );
|
||||
*handle = 0;
|
||||
const psa_key_slot_t *slot = &global_data.key_slots[key - 1];
|
||||
if( ! psa_is_key_slot_occupied( slot ) )
|
||||
{
|
||||
++stats->empty_slots;
|
||||
continue;
|
||||
}
|
||||
if( slot->attr.lifetime == PSA_KEY_LIFETIME_VOLATILE )
|
||||
++stats->volatile_slots;
|
||||
else if( slot->attr.lifetime == PSA_KEY_LIFETIME_PERSISTENT )
|
||||
{
|
||||
++stats->persistent_slots;
|
||||
if( slot->attr.id > stats->max_open_internal_key_id )
|
||||
stats->max_open_internal_key_id = slot->attr.id;
|
||||
}
|
||||
else
|
||||
{
|
||||
++stats->external_slots;
|
||||
if( slot->attr.id > stats->max_open_external_key_id )
|
||||
stats->max_open_external_key_id = slot->attr.id;
|
||||
}
|
||||
}
|
||||
return( status );
|
||||
}
|
||||
|
||||
psa_status_t psa_open_key( psa_key_lifetime_t lifetime,
|
||||
psa_key_file_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_file_id_t id,
|
||||
psa_key_handle_t *handle )
|
||||
{
|
||||
psa_status_t status;
|
||||
|
||||
status = persistent_key_setup( lifetime, id, handle,
|
||||
PSA_ERROR_DOES_NOT_EXIST );
|
||||
switch( status )
|
||||
{
|
||||
case PSA_SUCCESS: return( PSA_ERROR_ALREADY_EXISTS );
|
||||
case PSA_ERROR_DOES_NOT_EXIST: 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 */
|
||||
|
@ -22,6 +22,9 @@
|
||||
#ifndef PSA_CRYPTO_SLOT_MANAGEMENT_H
|
||||
#define PSA_CRYPTO_SLOT_MANAGEMENT_H
|
||||
|
||||
#include "psa/crypto.h"
|
||||
#include "psa_crypto_se.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
|
||||
@ -55,4 +58,72 @@ psa_status_t psa_initialize_key_slots( void );
|
||||
* This does not affect persistent storage. */
|
||||
void psa_wipe_all_key_slots( void );
|
||||
|
||||
/** Find a free key slot.
|
||||
*
|
||||
* This function returns a key slot that is available for use and is in its
|
||||
* ground state (all-bits-zero).
|
||||
*
|
||||
* \param[out] handle On success, a slot number that can be used as a
|
||||
* handle to the slot.
|
||||
* \param[out] p_slot On success, a pointer to the slot.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
|
||||
* \retval #PSA_ERROR_BAD_STATE
|
||||
*/
|
||||
psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle,
|
||||
psa_key_slot_t **p_slot );
|
||||
|
||||
/** Test whether a lifetime designates a key in an external cryptoprocessor.
|
||||
*
|
||||
* \param lifetime The lifetime to test.
|
||||
*
|
||||
* \retval 1
|
||||
* The lifetime designates an external key. There should be a
|
||||
* registered driver for this lifetime, otherwise the key cannot
|
||||
* be created or manipulated.
|
||||
* \retval 0
|
||||
* The lifetime designates a key that is volatile or in internal
|
||||
* storage.
|
||||
*/
|
||||
static inline int psa_key_lifetime_is_external( psa_key_lifetime_t lifetime )
|
||||
{
|
||||
return( lifetime != PSA_KEY_LIFETIME_VOLATILE &&
|
||||
lifetime != PSA_KEY_LIFETIME_PERSISTENT );
|
||||
}
|
||||
|
||||
/** Test whether the given parameters are acceptable for a persistent key.
|
||||
*
|
||||
* This function does not access the storage in any way. It only tests
|
||||
* whether the parameters are meaningful and permitted by general policy.
|
||||
* It does not test whether the a file by the given id exists or could be
|
||||
* created.
|
||||
*
|
||||
* If the key is in external storage, this function returns the corresponding
|
||||
* driver.
|
||||
*
|
||||
* \param lifetime The lifetime to test.
|
||||
* \param id The key id to test.
|
||||
* \param[out] p_drv On output, if \p lifetime designates a key
|
||||
* in an external processor, \c *p_drv is a pointer
|
||||
* to the driver table entry fot this lifetime.
|
||||
* If \p lifetime designates a transparent key,
|
||||
* \c *p_drv is \c NULL.
|
||||
* \param creating 0 if attempting to open an existing key.
|
||||
* Nonzero if attempting to create a key.
|
||||
*
|
||||
* \retval PSA_SUCCESS
|
||||
* The given parameters are valid.
|
||||
* \retval PSA_ERROR_INVALID_ARGUMENT
|
||||
* \p lifetime is volatile or is invalid.
|
||||
* \retval PSA_ERROR_INVALID_ARGUMENT
|
||||
* \p id is invalid.
|
||||
*/
|
||||
psa_status_t psa_validate_persistent_key_parameters(
|
||||
psa_key_lifetime_t lifetime,
|
||||
psa_key_file_id_t id,
|
||||
psa_se_drv_table_entry_t **p_drv,
|
||||
int creating );
|
||||
|
||||
|
||||
#endif /* PSA_CRYPTO_SLOT_MANAGEMENT_H */
|
||||
|
@ -50,6 +50,12 @@
|
||||
#define mbedtls_free free
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Key storage */
|
||||
/****************************************************************/
|
||||
|
||||
/* Determine a file name (ITS file identifier) for the given key file
|
||||
* identifier. The file name must be distinct from any file that is used
|
||||
* for a purpose other than storing a key. Currently, the only such file
|
||||
@ -224,7 +230,7 @@ static psa_status_t psa_crypto_storage_get_data_length(
|
||||
* 32-bit integer manipulation macros (little endian)
|
||||
*/
|
||||
#ifndef GET_UINT32_LE
|
||||
#define GET_UINT32_LE(n,b,i) \
|
||||
#define GET_UINT32_LE( n, b, i ) \
|
||||
{ \
|
||||
(n) = ( (uint32_t) (b)[(i) ] ) \
|
||||
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
|
||||
@ -234,7 +240,7 @@ static psa_status_t psa_crypto_storage_get_data_length(
|
||||
#endif
|
||||
|
||||
#ifndef PUT_UINT32_LE
|
||||
#define PUT_UINT32_LE(n,b,i) \
|
||||
#define PUT_UINT32_LE( n, b, i ) \
|
||||
{ \
|
||||
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
|
||||
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
|
||||
@ -252,6 +258,7 @@ static psa_status_t psa_crypto_storage_get_data_length(
|
||||
typedef struct {
|
||||
uint8_t magic[PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH];
|
||||
uint8_t version[4];
|
||||
uint8_t lifetime[sizeof( psa_key_lifetime_t )];
|
||||
uint8_t type[sizeof( psa_key_type_t )];
|
||||
uint8_t policy[sizeof( psa_key_policy_t )];
|
||||
uint8_t data_len[4];
|
||||
@ -260,20 +267,20 @@ typedef struct {
|
||||
|
||||
void psa_format_key_data_for_storage( const uint8_t *data,
|
||||
const size_t data_length,
|
||||
const psa_key_type_t type,
|
||||
const psa_key_policy_t *policy,
|
||||
const psa_core_key_attributes_t *attr,
|
||||
uint8_t *storage_data )
|
||||
{
|
||||
psa_persistent_key_storage_format *storage_format =
|
||||
(psa_persistent_key_storage_format *) storage_data;
|
||||
|
||||
memcpy( storage_format->magic, PSA_KEY_STORAGE_MAGIC_HEADER, PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH );
|
||||
PUT_UINT32_LE(0, storage_format->version, 0);
|
||||
PUT_UINT32_LE(type, storage_format->type, 0);
|
||||
PUT_UINT32_LE(policy->usage, storage_format->policy, 0);
|
||||
PUT_UINT32_LE(policy->alg, storage_format->policy, sizeof( uint32_t ));
|
||||
PUT_UINT32_LE(policy->alg2, storage_format->policy, 2 * sizeof( uint32_t ) );
|
||||
PUT_UINT32_LE(data_length, storage_format->data_len, 0);
|
||||
PUT_UINT32_LE( 0, storage_format->version, 0 );
|
||||
PUT_UINT32_LE( attr->lifetime, storage_format->lifetime, 0 );
|
||||
PUT_UINT32_LE( attr->type, storage_format->type, 0 );
|
||||
PUT_UINT32_LE( attr->policy.usage, storage_format->policy, 0 );
|
||||
PUT_UINT32_LE( attr->policy.alg, storage_format->policy, sizeof( uint32_t ) );
|
||||
PUT_UINT32_LE( attr->policy.alg2, storage_format->policy, 2 * sizeof( uint32_t ) );
|
||||
PUT_UINT32_LE( data_length, storage_format->data_len, 0 );
|
||||
memcpy( storage_format->key_data, data, data_length );
|
||||
}
|
||||
|
||||
@ -289,8 +296,7 @@ psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
|
||||
size_t storage_data_length,
|
||||
uint8_t **key_data,
|
||||
size_t *key_data_length,
|
||||
psa_key_type_t *type,
|
||||
psa_key_policy_t *policy )
|
||||
psa_core_key_attributes_t *attr )
|
||||
{
|
||||
psa_status_t status;
|
||||
const psa_persistent_key_storage_format *storage_format =
|
||||
@ -304,32 +310,37 @@ psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
|
||||
if( status != PSA_SUCCESS )
|
||||
return( status );
|
||||
|
||||
GET_UINT32_LE(version, storage_format->version, 0);
|
||||
GET_UINT32_LE( version, storage_format->version, 0 );
|
||||
if( version != 0 )
|
||||
return( PSA_ERROR_STORAGE_FAILURE );
|
||||
|
||||
GET_UINT32_LE(*key_data_length, storage_format->data_len, 0);
|
||||
GET_UINT32_LE( *key_data_length, storage_format->data_len, 0 );
|
||||
if( *key_data_length > ( storage_data_length - sizeof(*storage_format) ) ||
|
||||
*key_data_length > PSA_CRYPTO_MAX_STORAGE_SIZE )
|
||||
return( PSA_ERROR_STORAGE_FAILURE );
|
||||
|
||||
*key_data = mbedtls_calloc( 1, *key_data_length );
|
||||
if( *key_data == NULL )
|
||||
return( PSA_ERROR_INSUFFICIENT_MEMORY );
|
||||
if( *key_data_length == 0 )
|
||||
{
|
||||
*key_data = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*key_data = mbedtls_calloc( 1, *key_data_length );
|
||||
if( *key_data == NULL )
|
||||
return( PSA_ERROR_INSUFFICIENT_MEMORY );
|
||||
memcpy( *key_data, storage_format->key_data, *key_data_length );
|
||||
}
|
||||
|
||||
GET_UINT32_LE(*type, storage_format->type, 0);
|
||||
GET_UINT32_LE(policy->usage, storage_format->policy, 0);
|
||||
GET_UINT32_LE(policy->alg, storage_format->policy, sizeof( uint32_t ));
|
||||
GET_UINT32_LE(policy->alg2, storage_format->policy, 2 * sizeof( uint32_t ));
|
||||
|
||||
memcpy( *key_data, storage_format->key_data, *key_data_length );
|
||||
GET_UINT32_LE( attr->lifetime, storage_format->lifetime, 0 );
|
||||
GET_UINT32_LE( attr->type, storage_format->type, 0 );
|
||||
GET_UINT32_LE( attr->policy.usage, storage_format->policy, 0 );
|
||||
GET_UINT32_LE( attr->policy.alg, storage_format->policy, sizeof( uint32_t ) );
|
||||
GET_UINT32_LE( attr->policy.alg2, storage_format->policy, 2 * sizeof( uint32_t ) );
|
||||
|
||||
return( PSA_SUCCESS );
|
||||
}
|
||||
|
||||
psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
|
||||
const psa_key_type_t type,
|
||||
const psa_key_policy_t *policy,
|
||||
psa_status_t psa_save_persistent_key( const psa_core_key_attributes_t *attr,
|
||||
const uint8_t *data,
|
||||
const size_t data_length )
|
||||
{
|
||||
@ -345,10 +356,9 @@ psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
|
||||
if( storage_data == NULL )
|
||||
return( PSA_ERROR_INSUFFICIENT_MEMORY );
|
||||
|
||||
psa_format_key_data_for_storage( data, data_length, type, policy,
|
||||
storage_data );
|
||||
psa_format_key_data_for_storage( data, data_length, attr, storage_data );
|
||||
|
||||
status = psa_crypto_storage_store( key,
|
||||
status = psa_crypto_storage_store( attr->id,
|
||||
storage_data, storage_data_length );
|
||||
|
||||
mbedtls_free( storage_data );
|
||||
@ -365,15 +375,14 @@ void psa_free_persistent_key_data( uint8_t *key_data, size_t key_data_length )
|
||||
mbedtls_free( key_data );
|
||||
}
|
||||
|
||||
psa_status_t psa_load_persistent_key( psa_key_file_id_t key,
|
||||
psa_key_type_t *type,
|
||||
psa_key_policy_t *policy,
|
||||
psa_status_t psa_load_persistent_key( psa_core_key_attributes_t *attr,
|
||||
uint8_t **data,
|
||||
size_t *data_length )
|
||||
{
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
uint8_t *loaded_data;
|
||||
size_t storage_data_length = 0;
|
||||
psa_key_id_t key = attr->id;
|
||||
|
||||
status = psa_crypto_storage_get_data_length( key, &storage_data_length );
|
||||
if( status != PSA_SUCCESS )
|
||||
@ -389,13 +398,74 @@ psa_status_t psa_load_persistent_key( psa_key_file_id_t key,
|
||||
goto exit;
|
||||
|
||||
status = psa_parse_key_data_from_storage( loaded_data, storage_data_length,
|
||||
data, data_length, type, policy );
|
||||
data, data_length, attr );
|
||||
|
||||
exit:
|
||||
mbedtls_free( loaded_data );
|
||||
return( status );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Transactions */
|
||||
/****************************************************************/
|
||||
|
||||
#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
|
||||
|
||||
psa_crypto_transaction_t psa_crypto_transaction;
|
||||
|
||||
psa_status_t psa_crypto_save_transaction( void )
|
||||
{
|
||||
struct psa_storage_info_t p_info;
|
||||
psa_status_t status;
|
||||
status = psa_its_get_info( PSA_CRYPTO_ITS_RANDOM_SEED_UID, &p_info );
|
||||
if( status == PSA_SUCCESS )
|
||||
{
|
||||
/* This shouldn't happen: we're trying to start a transaction while
|
||||
* there is still a transaction that hasn't been replayed. */
|
||||
return( PSA_ERROR_CORRUPTION_DETECTED );
|
||||
}
|
||||
else if( status != PSA_ERROR_DOES_NOT_EXIST )
|
||||
return( status );
|
||||
return( psa_its_set( PSA_CRYPTO_ITS_TRANSACTION_UID,
|
||||
sizeof( psa_crypto_transaction ),
|
||||
&psa_crypto_transaction,
|
||||
0 ) );
|
||||
}
|
||||
|
||||
psa_status_t psa_crypto_load_transaction( void )
|
||||
{
|
||||
psa_status_t status;
|
||||
size_t length;
|
||||
status = psa_its_get( PSA_CRYPTO_ITS_TRANSACTION_UID, 0,
|
||||
sizeof( psa_crypto_transaction ),
|
||||
&psa_crypto_transaction, &length );
|
||||
if( status != PSA_SUCCESS )
|
||||
return( status );
|
||||
if( length != sizeof( psa_crypto_transaction ) )
|
||||
return( PSA_ERROR_STORAGE_FAILURE );
|
||||
return( PSA_SUCCESS );
|
||||
}
|
||||
|
||||
psa_status_t psa_crypto_stop_transaction( void )
|
||||
{
|
||||
psa_status_t status = psa_its_remove( PSA_CRYPTO_ITS_TRANSACTION_UID );
|
||||
/* Whether or not updating the storage succeeded, the transaction is
|
||||
* finished now. It's too late to go back, so zero out the in-memory
|
||||
* data. */
|
||||
memset( &psa_crypto_transaction, 0, sizeof( psa_crypto_transaction ) );
|
||||
return( status );
|
||||
}
|
||||
|
||||
#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Random generator state */
|
||||
/****************************************************************/
|
||||
|
||||
#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
|
||||
psa_status_t mbedtls_psa_storage_inject_entropy( const unsigned char *seed,
|
||||
size_t seed_size )
|
||||
@ -418,4 +488,10 @@ psa_status_t mbedtls_psa_storage_inject_entropy( const unsigned char *seed,
|
||||
}
|
||||
#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* The end */
|
||||
/****************************************************************/
|
||||
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
|
||||
|
@ -29,20 +29,20 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Include the Mbed TLS configuration file, the way Mbed TLS does it
|
||||
* in each of its header files. */
|
||||
#if defined(MBEDTLS_CONFIG_FILE)
|
||||
#include MBEDTLS_CONFIG_FILE
|
||||
#else
|
||||
#include "mbedtls/config.h"
|
||||
#endif
|
||||
|
||||
#include "psa/crypto.h"
|
||||
#include <stdint.h>
|
||||
#include "psa/crypto_se_driver.h"
|
||||
|
||||
/* Limit the maximum key size to 30kB (just in case someone tries to
|
||||
* inadvertently store an obscene amount of data) */
|
||||
#define PSA_CRYPTO_MAX_STORAGE_SIZE ( 30 * 1024 )
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Limit the maximum key size in storage. This should have no effect
|
||||
* since the key size is limited in memory. */
|
||||
#define PSA_CRYPTO_MAX_STORAGE_SIZE ( PSA_BITS_TO_BYTES( PSA_MAX_KEY_BITS ) )
|
||||
/* Sanity check: a file size must fit in 32 bits. Allow a generous
|
||||
* 64kB of metadata. */
|
||||
#if PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000
|
||||
#error PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000
|
||||
#endif
|
||||
|
||||
/** The maximum permitted persistent slot number.
|
||||
*
|
||||
@ -59,7 +59,7 @@ extern "C" {
|
||||
* This limitation will probably become moot when we implement client
|
||||
* separation for key storage.
|
||||
*/
|
||||
#define PSA_MAX_PERSISTENT_KEY_IDENTIFIER 0xfffeffff
|
||||
#define PSA_MAX_PERSISTENT_KEY_IDENTIFIER PSA_KEY_ID_VENDOR_MAX
|
||||
|
||||
/**
|
||||
* \brief Checks if persistent data is stored for the given key slot number
|
||||
@ -88,12 +88,11 @@ int psa_is_key_present_in_storage( const psa_key_file_id_t key );
|
||||
* already occupied non-persistent key, as well as validating the key data.
|
||||
*
|
||||
*
|
||||
* \param key Persistent identifier of the key to be stored. This
|
||||
* should be an unoccupied storage location.
|
||||
* \param type Key type (a \c PSA_KEY_TYPE_XXX value).
|
||||
* \param[in] policy The key policy to save.
|
||||
* \param[in] data Buffer containing the key data.
|
||||
* \param data_length The number of bytes that make up the key data.
|
||||
* \param[in] attr The attributes of the key to save.
|
||||
* The key identifier field in the attributes
|
||||
* determines the key's location.
|
||||
* \param[in] data Buffer containing the key data.
|
||||
* \param data_length The number of bytes that make up the key data.
|
||||
*
|
||||
* \retval PSA_SUCCESS
|
||||
* \retval PSA_ERROR_INSUFFICIENT_MEMORY
|
||||
@ -101,9 +100,7 @@ int psa_is_key_present_in_storage( const psa_key_file_id_t key );
|
||||
* \retval PSA_ERROR_STORAGE_FAILURE
|
||||
* \retval PSA_ERROR_ALREADY_EXISTS
|
||||
*/
|
||||
psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
|
||||
const psa_key_type_t type,
|
||||
const psa_key_policy_t *policy,
|
||||
psa_status_t psa_save_persistent_key( const psa_core_key_attributes_t *attr,
|
||||
const uint8_t *data,
|
||||
const size_t data_length );
|
||||
|
||||
@ -119,11 +116,10 @@ psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
|
||||
* this function to zeroize and free this buffer, regardless of whether this
|
||||
* function succeeds or fails.
|
||||
*
|
||||
* \param key Persistent identifier of the key to be loaded. This
|
||||
* should be an occupied storage location.
|
||||
* \param[out] type On success, the key type (a \c PSA_KEY_TYPE_XXX
|
||||
* value).
|
||||
* \param[out] policy On success, the key's policy.
|
||||
* \param[in,out] attr On input, the key identifier field identifies
|
||||
* the key to load. Other fields are ignored.
|
||||
* On success, the attribute structure contains
|
||||
* the key metadata that was loaded from storage.
|
||||
* \param[out] data Pointer to an allocated key data buffer on return.
|
||||
* \param[out] data_length The number of bytes that make up the key data.
|
||||
*
|
||||
@ -132,9 +128,7 @@ psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
|
||||
* \retval PSA_ERROR_STORAGE_FAILURE
|
||||
* \retval PSA_ERROR_DOES_NOT_EXIST
|
||||
*/
|
||||
psa_status_t psa_load_persistent_key( psa_key_file_id_t key,
|
||||
psa_key_type_t *type,
|
||||
psa_key_policy_t *policy,
|
||||
psa_status_t psa_load_persistent_key( psa_core_key_attributes_t *attr,
|
||||
uint8_t **data,
|
||||
size_t *data_length );
|
||||
|
||||
@ -166,17 +160,15 @@ void psa_free_persistent_key_data( uint8_t *key_data, size_t key_data_length );
|
||||
/**
|
||||
* \brief Formats key data and metadata for persistent storage
|
||||
*
|
||||
* \param[in] data Buffer for the key data.
|
||||
* \param[in] data Buffer containing the key data.
|
||||
* \param data_length Length of the key data buffer.
|
||||
* \param type Key type (a \c PSA_KEY_TYPE_XXX value).
|
||||
* \param policy The key policy.
|
||||
* \param[in] attr The core attributes of the key.
|
||||
* \param[out] storage_data Output buffer for the formatted data.
|
||||
*
|
||||
*/
|
||||
void psa_format_key_data_for_storage( const uint8_t *data,
|
||||
const size_t data_length,
|
||||
const psa_key_type_t type,
|
||||
const psa_key_policy_t *policy,
|
||||
const psa_core_key_attributes_t *attr,
|
||||
uint8_t *storage_data );
|
||||
|
||||
/**
|
||||
@ -188,8 +180,8 @@ void psa_format_key_data_for_storage( const uint8_t *data,
|
||||
* containing the key data. This must be freed
|
||||
* using psa_free_persistent_key_data()
|
||||
* \param[out] key_data_length Length of the key data buffer
|
||||
* \param[out] type Key type (a \c PSA_KEY_TYPE_XXX value).
|
||||
* \param[out] policy The key policy.
|
||||
* \param[out] attr On success, the attribute structure is filled
|
||||
* with the loaded key metadata.
|
||||
*
|
||||
* \retval PSA_SUCCESS
|
||||
* \retval PSA_ERROR_INSUFFICIENT_STORAGE
|
||||
@ -200,8 +192,180 @@ psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
|
||||
size_t storage_data_length,
|
||||
uint8_t **key_data,
|
||||
size_t *key_data_length,
|
||||
psa_key_type_t *type,
|
||||
psa_key_policy_t *policy );
|
||||
psa_core_key_attributes_t *attr );
|
||||
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||
/** This symbol is defined if transaction support is required. */
|
||||
#define PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS
|
||||
#endif
|
||||
|
||||
#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
|
||||
|
||||
/** The type of transaction that is in progress.
|
||||
*/
|
||||
/* This is an integer type rather than an enum for two reasons: to support
|
||||
* unknown values when loading a transaction file, and to ensure that the
|
||||
* type has a known size.
|
||||
*/
|
||||
typedef uint16_t psa_crypto_transaction_type_t;
|
||||
|
||||
/** No transaction is in progress.
|
||||
*
|
||||
* This has the value 0, so zero-initialization sets a transaction's type to
|
||||
* this value.
|
||||
*/
|
||||
#define PSA_CRYPTO_TRANSACTION_NONE ( (psa_crypto_transaction_type_t) 0x0000 )
|
||||
|
||||
/** A key creation transaction.
|
||||
*
|
||||
* This is only used for keys in an external cryptoprocessor (secure element).
|
||||
* Keys in RAM or in internal storage are created atomically in storage
|
||||
* (simple file creation), so they do not need a transaction mechanism.
|
||||
*/
|
||||
#define PSA_CRYPTO_TRANSACTION_CREATE_KEY ( (psa_crypto_transaction_type_t) 0x0001 )
|
||||
|
||||
/** A key destruction transaction.
|
||||
*
|
||||
* This is only used for keys in an external cryptoprocessor (secure element).
|
||||
* Keys in RAM or in internal storage are destroyed atomically in storage
|
||||
* (simple file deletion), so they do not need a transaction mechanism.
|
||||
*/
|
||||
#define PSA_CRYPTO_TRANSACTION_DESTROY_KEY ( (psa_crypto_transaction_type_t) 0x0002 )
|
||||
|
||||
/** Transaction data.
|
||||
*
|
||||
* This type is designed to be serialized by writing the memory representation
|
||||
* and reading it back on the same device.
|
||||
*
|
||||
* \note The transaction mechanism is designed for a single active transaction
|
||||
* at a time. The transaction object is #psa_crypto_transaction.
|
||||
*
|
||||
* \note If an API call starts a transaction, it must complete this transaction
|
||||
* before returning to the application.
|
||||
*
|
||||
* The lifetime of a transaction is the following (note that only one
|
||||
* transaction may be active at a time):
|
||||
*
|
||||
* -# Call psa_crypto_prepare_transaction() to initialize the transaction
|
||||
* object in memory and declare the type of transaction that is starting.
|
||||
* -# Fill in the type-specific fields of #psa_crypto_transaction.
|
||||
* -# Call psa_crypto_save_transaction() to start the transaction. This
|
||||
* saves the transaction data to internal storage.
|
||||
* -# Perform the work of the transaction by modifying files, contacting
|
||||
* external entities, or whatever needs doing. Note that the transaction
|
||||
* may be interrupted by a power failure, so you need to have a way
|
||||
* recover from interruptions either by undoing what has been done
|
||||
* so far or by resuming where you left off.
|
||||
* -# If there are intermediate stages in the transaction, update
|
||||
* the fields of #psa_crypto_transaction and call
|
||||
* psa_crypto_save_transaction() again when each stage is reached.
|
||||
* -# When the transaction is over, call psa_crypto_stop_transaction() to
|
||||
* remove the transaction data in storage and in memory.
|
||||
*
|
||||
* If the system crashes while a transaction is in progress, psa_crypto_init()
|
||||
* calls psa_crypto_load_transaction() and takes care of completing or
|
||||
* rewinding the transaction. This is done in psa_crypto_recover_transaction()
|
||||
* in psa_crypto.c. If you add a new type of transaction, be
|
||||
* sure to add code for it in psa_crypto_recover_transaction().
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
/* Each element of this union must have the following properties
|
||||
* to facilitate serialization and deserialization:
|
||||
*
|
||||
* - The element is a struct.
|
||||
* - The first field of the struct is `psa_crypto_transaction_type_t type`.
|
||||
* - Elements of the struct are arranged such a way that there is
|
||||
* no padding.
|
||||
*/
|
||||
struct psa_crypto_transaction_unknown_s
|
||||
{
|
||||
psa_crypto_transaction_type_t type;
|
||||
uint16_t unused1;
|
||||
uint32_t unused2;
|
||||
uint64_t unused3;
|
||||
uint64_t unused4;
|
||||
} unknown;
|
||||
/* ::type is #PSA_CRYPTO_TRANSACTION_CREATE_KEY or
|
||||
* #PSA_CRYPTO_TRANSACTION_DESTROY_KEY. */
|
||||
struct psa_crypto_transaction_key_s
|
||||
{
|
||||
psa_crypto_transaction_type_t type;
|
||||
uint16_t unused1;
|
||||
psa_key_lifetime_t lifetime;
|
||||
psa_key_slot_number_t slot;
|
||||
psa_key_id_t id;
|
||||
} key;
|
||||
} psa_crypto_transaction_t;
|
||||
|
||||
/** The single active transaction.
|
||||
*/
|
||||
extern psa_crypto_transaction_t psa_crypto_transaction;
|
||||
|
||||
/** Prepare for a transaction.
|
||||
*
|
||||
* There must not be an ongoing transaction.
|
||||
*
|
||||
* \param type The type of transaction to start.
|
||||
*/
|
||||
static inline void psa_crypto_prepare_transaction(
|
||||
psa_crypto_transaction_type_t type )
|
||||
{
|
||||
psa_crypto_transaction.unknown.type = type;
|
||||
}
|
||||
|
||||
/** Save the transaction data to storage.
|
||||
*
|
||||
* You may call this function multiple times during a transaction to
|
||||
* atomically update the transaction state.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* \retval #PSA_ERROR_INSUFFICIENT_STORAGE
|
||||
* \retval #PSA_ERROR_STORAGE_FAILURE
|
||||
*/
|
||||
psa_status_t psa_crypto_save_transaction( void );
|
||||
|
||||
/** Load the transaction data from storage, if any.
|
||||
*
|
||||
* This function is meant to be called from psa_crypto_init() to recover
|
||||
* in case a transaction was interrupted by a system crash.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* The data about the ongoing transaction has been loaded to
|
||||
* #psa_crypto_transaction.
|
||||
* \retval #PSA_ERROR_DOES_NOT_EXIST
|
||||
* There is no ongoing transaction.
|
||||
* \retval #PSA_ERROR_STORAGE_FAILURE
|
||||
*/
|
||||
psa_status_t psa_crypto_load_transaction( void );
|
||||
|
||||
/** Indicate that the current transaction is finished.
|
||||
*
|
||||
* Call this function at the very end of transaction processing.
|
||||
* This function does not "commit" or "abort" the transaction: the storage
|
||||
* subsystem has no concept of "commit" and "abort", just saving and
|
||||
* removing the transaction information in storage.
|
||||
*
|
||||
* This function erases the transaction data in storage (if any) and
|
||||
* resets the transaction data in memory.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* There was transaction data in storage.
|
||||
* \retval #PSA_ERROR_DOES_NOT_EXIST
|
||||
* There was no transaction data in storage.
|
||||
* \retval #PSA_ERROR_STORAGE_FAILURE
|
||||
* It was impossible to determine whether there was transaction data
|
||||
* in storage, or the transaction data could not be erased.
|
||||
*/
|
||||
psa_status_t psa_crypto_stop_transaction( void );
|
||||
|
||||
/** The ITS file identifier for the transaction data.
|
||||
*
|
||||
* 0xffffffNN = special file; 0x74 = 't' for transaction.
|
||||
*/
|
||||
#define PSA_CRYPTO_ITS_TRANSACTION_UID ( (psa_key_id_t) 0xffffff74 )
|
||||
|
||||
#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
|
||||
|
||||
#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
|
||||
/** Backend side of mbedtls_psa_inject_entropy().
|
||||
|
@ -558,6 +558,9 @@ static const char * const features[] = {
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_C)
|
||||
"MBEDTLS_PSA_CRYPTO_C",
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_C */
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||
"MBEDTLS_PSA_CRYPTO_SE_C",
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
|
||||
"MBEDTLS_PSA_CRYPTO_STORAGE_C",
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
|
||||
|
Reference in New Issue
Block a user