From b309eec4a54dcc171c59d74c54ad3838e3537e61 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Nov 2018 20:56:14 +0100 Subject: [PATCH 1/8] Move library initialization tests to a new test suite --- tests/CMakeLists.txt | 1 + tests/suites/test_suite_psa_crypto.data | 9 ---- tests/suites/test_suite_psa_crypto.function | 36 ------------- tests/suites/test_suite_psa_crypto_init.data | 8 +++ .../test_suite_psa_crypto_init.function | 50 +++++++++++++++++++ 5 files changed, 59 insertions(+), 45 deletions(-) create mode 100644 tests/suites/test_suite_psa_crypto_init.data create mode 100644 tests/suites/test_suite_psa_crypto_init.function diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 95d60ff31..56ce9338a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -113,6 +113,7 @@ add_test_suite(poly1305) add_test_suite(psa_crypto) add_test_suite(psa_crypto_entropy) add_test_suite(psa_crypto_hash) +add_test_suite(psa_crypto_init) add_test_suite(psa_crypto_metadata) add_test_suite(psa_crypto_persistent_key) add_test_suite(psa_crypto_storage_file) diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index e1c1b0545..1ce394e5a 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -1,9 +1,6 @@ PSA compile-time sanity checks static_checks: -PSA init/deinit -init_deinit: - PSA fill 250 slots fill_slots:250 @@ -1829,12 +1826,6 @@ PSA generate key: ECC, SECP256R1, incorrect bit size depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDSA_C generate_key:PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_ECDSA_ANY:PSA_ERROR_INVALID_ARGUMENT -PSA validate module initialization: random -validate_module_init_generate_random: - -PSA validate module initialization: key based -validate_module_init_key_based: - persistent key can be accessed after in-memory deletion: AES, 128 bits, CTR depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PSA_CRYPTO_STORAGE_C persistent_key_load_key_from_storage:"2b7e151628aed2a6abf7158809cf4f3c":PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_EXPORT:PSA_ALG_CTR:IMPORT_KEY:PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 53295befa..2fa060b25 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -871,22 +871,6 @@ void static_checks( ) } /* END_CASE */ -/* BEGIN_CASE */ -void init_deinit( ) -{ - psa_status_t status; - int i; - for( i = 0; i <= 1; i++ ) - { - status = psa_crypto_init( ); - TEST_ASSERT( status == PSA_SUCCESS ); - status = psa_crypto_init( ); - TEST_ASSERT( status == PSA_SUCCESS ); - mbedtls_psa_crypto_free( ); - } -} -/* END_CASE */ - /* BEGIN_CASE */ void fill_slots( int max_arg ) { @@ -4018,26 +4002,6 @@ exit: } /* END_CASE */ -/* BEGIN_CASE */ -void validate_module_init_generate_random( ) -{ - psa_status_t status; - uint8_t random[10] = { 0 }; - status = psa_generate_random( random, sizeof( random ) ); - TEST_ASSERT( status == PSA_ERROR_BAD_STATE ); -} -/* END_CASE */ - -/* BEGIN_CASE */ -void validate_module_init_key_based( ) -{ - psa_status_t status; - uint8_t data[10] = { 0 }; - status = psa_import_key( 1, PSA_KEY_TYPE_RAW_DATA, data, sizeof( data ) ); - TEST_ASSERT( status == PSA_ERROR_BAD_STATE ); -} -/* END_CASE */ - /* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */ void persistent_key_load_key_from_storage( data_t *data, int type_arg, int bits, int usage_arg, diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data new file mode 100644 index 000000000..ad90c17cd --- /dev/null +++ b/tests/suites/test_suite_psa_crypto_init.data @@ -0,0 +1,8 @@ +PSA init/deinit +init_deinit: + +PSA validate module initialization: random +validate_module_init_generate_random: + +PSA validate module initialization: key based +validate_module_init_key_based: diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function new file mode 100644 index 000000000..4ac76a3a5 --- /dev/null +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -0,0 +1,50 @@ +/* BEGIN_HEADER */ +#include + +#if defined(MBEDTLS_PSA_CRYPTO_SPM) +#include "spm/psa_defs.h" +#endif +#include "psa/crypto.h" + +/* END_HEADER */ + +/* BEGIN_DEPENDENCIES + * depends_on:MBEDTLS_PSA_CRYPTO_C + * END_DEPENDENCIES + */ + +/* BEGIN_CASE */ +void init_deinit( ) +{ + psa_status_t status; + int i; + for( i = 0; i <= 1; i++ ) + { + status = psa_crypto_init( ); + TEST_ASSERT( status == PSA_SUCCESS ); + status = psa_crypto_init( ); + TEST_ASSERT( status == PSA_SUCCESS ); + mbedtls_psa_crypto_free( ); + } +} +/* END_CASE */ + +/* BEGIN_CASE */ +void validate_module_init_generate_random( ) +{ + psa_status_t status; + uint8_t random[10] = { 0 }; + status = psa_generate_random( random, sizeof( random ) ); + TEST_ASSERT( status == PSA_ERROR_BAD_STATE ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void validate_module_init_key_based( ) +{ + psa_status_t status; + uint8_t data[10] = { 0 }; + status = psa_import_key( 1, PSA_KEY_TYPE_RAW_DATA, data, sizeof( data ) ); + TEST_ASSERT( status == PSA_ERROR_BAD_STATE ); +} +/* END_CASE */ From 445e2257453520b3af895b62649415771d3f4bfc Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Nov 2018 21:00:42 +0100 Subject: [PATCH 2/8] Test that deinit deactivates random generation and key slots --- tests/suites/test_suite_psa_crypto_init.data | 16 +++++++++----- .../test_suite_psa_crypto_init.function | 22 +++++++++++++++---- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data index ad90c17cd..61f067d06 100644 --- a/tests/suites/test_suite_psa_crypto_init.data +++ b/tests/suites/test_suite_psa_crypto_init.data @@ -1,8 +1,14 @@ PSA init/deinit -init_deinit: +init_deinit:2 -PSA validate module initialization: random -validate_module_init_generate_random: +No random without init +validate_module_init_generate_random:0 -PSA validate module initialization: key based -validate_module_init_key_based: +No key slot access without init +validate_module_init_key_based:0 + +No random after deinit +validate_module_init_generate_random:1 + +No key slot access after deinit +validate_module_init_key_based:1 diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 4ac76a3a5..7fccc13d2 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -14,11 +14,11 @@ */ /* BEGIN_CASE */ -void init_deinit( ) +void init_deinit( int count ) { psa_status_t status; int i; - for( i = 0; i <= 1; i++ ) + for( i = 0; i < count; i++ ) { status = psa_crypto_init( ); TEST_ASSERT( status == PSA_SUCCESS ); @@ -30,20 +30,34 @@ void init_deinit( ) /* END_CASE */ /* BEGIN_CASE */ -void validate_module_init_generate_random( ) +void validate_module_init_generate_random( int count ) { psa_status_t status; uint8_t random[10] = { 0 }; + int i; + for( i = 0; i < count; i++ ) + { + status = psa_crypto_init( ); + TEST_ASSERT( status == PSA_SUCCESS ); + mbedtls_psa_crypto_free( ); + } status = psa_generate_random( random, sizeof( random ) ); TEST_ASSERT( status == PSA_ERROR_BAD_STATE ); } /* END_CASE */ /* BEGIN_CASE */ -void validate_module_init_key_based( ) +void validate_module_init_key_based( int count ) { psa_status_t status; uint8_t data[10] = { 0 }; + int i; + for( i = 0; i < count; i++ ) + { + status = psa_crypto_init( ); + TEST_ASSERT( status == PSA_SUCCESS ); + mbedtls_psa_crypto_free( ); + } status = psa_import_key( 1, PSA_KEY_TYPE_RAW_DATA, data, sizeof( data ) ); TEST_ASSERT( status == PSA_ERROR_BAD_STATE ); } From c6b6907066b016a2e2babb9ea6940d6a8c202575 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Nov 2018 21:42:52 +0100 Subject: [PATCH 3/8] Make library init and deinit more robust to errors Allow mbedtls_psa_crypto_free to be called twice, or without a prior call to psa_crypto_init. Keep track of the initialization state more precisely in psa_crypto_init so that mbedtls_psa_crypto_free knows what to do. --- library/psa_crypto.c | 51 ++++++++++++++----- tests/suites/test_suite_psa_crypto_init.data | 6 +++ .../test_suite_psa_crypto_init.function | 13 +++++ 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 291dcdb0d..4c0ac1213 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -146,12 +146,21 @@ static int key_type_is_raw_bytes( psa_key_type_t type ) return( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) ); } +enum rng_state +{ + RNG_NOT_INITIALIZED = 0, + RNG_INITIALIZED, + RNG_SEEDED, +}; + typedef struct { - int initialized; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; key_slot_t key_slots[PSA_KEY_SLOT_COUNT]; + unsigned initialized : 1; + enum rng_state rng_state : 2; + unsigned key_slots_initialized : 1; } psa_global_data_t; static psa_global_data_t global_data; @@ -4433,18 +4442,26 @@ void mbedtls_psa_crypto_free( void ) psa_key_slot_t key; key_slot_t *slot; psa_status_t status; - - for( key = 1; key <= PSA_KEY_SLOT_COUNT; key++ ) + if( global_data.key_slots_initialized ) { - status = psa_get_key_slot( key, &slot ); - if( status != PSA_SUCCESS ) - continue; - psa_remove_key_data_from_memory( slot ); - /* Zeroize the slot to wipe metadata such as policies. */ - mbedtls_zeroize( slot, sizeof( *slot ) ); + for( key = 1; key <= PSA_KEY_SLOT_COUNT; key++ ) + { + status = psa_get_key_slot( key, &slot ); + if( status != PSA_SUCCESS ) + continue; + psa_remove_key_data_from_memory( slot ); + /* Zeroize the slot to wipe metadata such as policies. */ + mbedtls_zeroize( slot, sizeof( *slot ) ); + } } - mbedtls_ctr_drbg_free( &global_data.ctr_drbg ); - mbedtls_entropy_free( &global_data.entropy ); + if( global_data.rng_state != RNG_NOT_INITIALIZED ) + { + mbedtls_ctr_drbg_free( &global_data.ctr_drbg ); + mbedtls_entropy_free( &global_data.entropy ); + } + /* Wipe all remaining data, including configuration. + * In particular, this sets all state indicator to the value + * indicating "uninitialized". */ mbedtls_zeroize( &global_data, sizeof( global_data ) ); } @@ -4453,20 +4470,30 @@ psa_status_t psa_crypto_init( void ) int ret; const unsigned char drbg_seed[] = "PSA"; + /* Double initialization is explicitly allowed. */ if( global_data.initialized != 0 ) return( PSA_SUCCESS ); mbedtls_zeroize( &global_data, sizeof( global_data ) ); + + /* Initialize the random generator. */ mbedtls_entropy_init( &global_data.entropy ); mbedtls_ctr_drbg_init( &global_data.ctr_drbg ); - + global_data.rng_state = RNG_INITIALIZED; ret = mbedtls_ctr_drbg_seed( &global_data.ctr_drbg, mbedtls_entropy_func, &global_data.entropy, drbg_seed, sizeof( drbg_seed ) - 1 ); if( ret != 0 ) goto exit; + global_data.rng_state = RNG_SEEDED; + /* Initialize the key slots. Zero-initialization has made all key + * slots empty, so there is nothing to do. In a future version we will + * load data from storage. */ + global_data.key_slots_initialized = 1; + + /* All done. */ global_data.initialized = 1; exit: diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data index 61f067d06..e44111814 100644 --- a/tests/suites/test_suite_psa_crypto_init.data +++ b/tests/suites/test_suite_psa_crypto_init.data @@ -1,6 +1,12 @@ PSA init/deinit init_deinit:2 +PSA deinit without init +deinit_without_init:0 + +PSA deinit twice +deinit_without_init:1 + No random without init validate_module_init_generate_random:0 diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 7fccc13d2..7cb10c0a1 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -29,6 +29,19 @@ void init_deinit( int count ) } /* END_CASE */ +/* BEGIN_CASE */ +void deinit_without_init( int count ) +{ + int i; + for( i = 0; i < count; i++ ) + { + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + mbedtls_psa_crypto_free( ); + } + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void validate_module_init_generate_random( int count ) { From 5e769522359e3b07167f9d1696c971cd5d19fc6e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Nov 2018 21:59:56 +0100 Subject: [PATCH 4/8] Add a facility to configure entropy sources Add a function to configure entropy sources. For testing only. Use it to test that the library initialization fails properly if there is no entropy source. --- library/psa_crypto.c | 25 ++++- library/psa_crypto_invasive.h | 79 ++++++++++++++++ tests/suites/test_suite_psa_crypto_init.data | 6 ++ .../test_suite_psa_crypto_init.function | 93 +++++++++++++++++++ 4 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 library/psa_crypto_invasive.h diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 4c0ac1213..f4c87d3e2 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -43,6 +43,7 @@ #include "psa/crypto.h" +#include "psa_crypto_invasive.h" /* Include internal declarations that are useful for implementing persistently * stored keys. */ #include "psa_crypto_storage.h" @@ -155,6 +156,8 @@ enum rng_state typedef struct { + void (* entropy_init )( mbedtls_entropy_context *ctx ); + void (* entropy_free )( mbedtls_entropy_context *ctx ); mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; key_slot_t key_slots[PSA_KEY_SLOT_COUNT]; @@ -4437,6 +4440,17 @@ psa_status_t psa_generate_key( psa_key_slot_t key, /* Module setup */ /****************************************************************/ +psa_status_t mbedtls_psa_crypto_configure_entropy_sources( + void (* entropy_init )( mbedtls_entropy_context *ctx ), + void (* entropy_free )( mbedtls_entropy_context *ctx ) ) +{ + if( global_data.rng_state != RNG_NOT_INITIALIZED ) + return( PSA_ERROR_BAD_STATE ); + global_data.entropy_init = entropy_init; + global_data.entropy_free = entropy_free; + return( PSA_SUCCESS ); +} + void mbedtls_psa_crypto_free( void ) { psa_key_slot_t key; @@ -4457,7 +4471,7 @@ void mbedtls_psa_crypto_free( void ) if( global_data.rng_state != RNG_NOT_INITIALIZED ) { mbedtls_ctr_drbg_free( &global_data.ctr_drbg ); - mbedtls_entropy_free( &global_data.entropy ); + global_data.entropy_free( &global_data.entropy ); } /* Wipe all remaining data, including configuration. * In particular, this sets all state indicator to the value @@ -4474,10 +4488,15 @@ psa_status_t psa_crypto_init( void ) if( global_data.initialized != 0 ) return( PSA_SUCCESS ); - mbedtls_zeroize( &global_data, sizeof( global_data ) ); + /* Set default configuration if + * mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */ + if( global_data.entropy_init == NULL ) + global_data.entropy_init = mbedtls_entropy_init; + if( global_data.entropy_free == NULL ) + global_data.entropy_free = mbedtls_entropy_free; /* Initialize the random generator. */ - mbedtls_entropy_init( &global_data.entropy ); + global_data.entropy_init( &global_data.entropy ); mbedtls_ctr_drbg_init( &global_data.ctr_drbg ); global_data.rng_state = RNG_INITIALIZED; ret = mbedtls_ctr_drbg_seed( &global_data.ctr_drbg, diff --git a/library/psa_crypto_invasive.h b/library/psa_crypto_invasive.h new file mode 100644 index 000000000..642652a47 --- /dev/null +++ b/library/psa_crypto_invasive.h @@ -0,0 +1,79 @@ +/** + * \file psa_crypto_invasive.h + * + * \brief PSA cryptography module: invasive interfaces for test only. + * + * The interfaces in this file are intended for testing purposes only. + * They MUST NOT be made available to clients over IPC in integrations + * with isolation, and they SHOULD NOT be made available in library + * integrations except when building the library for testing. + */ +/* + * 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_INVASIVE_H +#define PSA_CRYPTO_INVASIVE_H + +#if defined(MBEDTLS_CONFIG_FILE) +#include MBEDTLS_CONFIG_FILE +#else +#include "mbedtls/config.h" +#endif + +#include "psa/crypto.h" + +#include "mbedtls/entropy.h" + +/** \brief Configure entropy sources. + * + * This function may only be called before a call to psa_crypto_init(), + * or after a call to mbedtls_psa_crypto_free() and before any + * subsequent call to psa_crypto_init(). + * + * This function is only intended for test purposes. The functionality + * it provides is also useful for system integrators, but + * system integrators should configure entropy drivers instead of + * breaking through to the Mbed TLS API. + * + * \param entropy_init Function to initialize the entropy context + * and set up the desired entropy sources. + * It is called by psa_crypto_init(). + * By default this is mbedtls_entropy_init(). + * This function cannot report failures directly. + * To indicate a failure, set the entropy context + * to a state where mbedtls_entropy_func() will + * return an error. + * \param entropy_free Function to free the entropy context + * and associated resources. + * It is called by mbedtls_psa_crypto_free(). + * By default this is mbedtls_entropy_free(). + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_NOT_PERMITTED + * The caller does not have the permission to configure + * entropy sources. + * \retval PSA_ERROR_BAD_STATE + * The library has already been initialized. + */ +psa_status_t mbedtls_psa_crypto_configure_entropy_sources( + void (* entropy_init )( mbedtls_entropy_context *ctx ), + void (* entropy_free )( mbedtls_entropy_context *ctx ) ); + +#endif /* PSA_CRYPTO_INVASIVE_H */ diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data index e44111814..8ce044dc6 100644 --- a/tests/suites/test_suite_psa_crypto_init.data +++ b/tests/suites/test_suite_psa_crypto_init.data @@ -18,3 +18,9 @@ validate_module_init_generate_random:1 No key slot access after deinit validate_module_init_key_based:1 + +Custom entropy sources: all standard +custom_entropy_sources:0x0000ffff:PSA_SUCCESS + +Custom entropy sources: none +custom_entropy_sources:0:PSA_ERROR_INSUFFICIENT_ENTROPY diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 7cb10c0a1..0957969d5 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -6,6 +6,73 @@ #endif #include "psa/crypto.h" +/* Some tests in this module configure entropy sources. */ +#include "psa_crypto_invasive.h" + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" + +#define ENTROPY_SOURCE_PLATFORM 0x00000001 +#define ENTROPY_SOURCE_TIMING 0x00000002 +#define ENTROPY_SOURCE_HAVEGE 0x00000004 +#define ENTROPY_SOURCE_HARDWARE 0x00000008 +#define ENTROPY_SOURCE_NV_SEED 0x00000010 +static uint32_t custom_entropy_sources_mask; + +/* This is a modified version of mbedtls_entropy_init() from entropy.c + * which chooses entropy sources dynamically. */ +static void custom_entropy_init( mbedtls_entropy_context *ctx ) +{ + ctx->source_count = 0; + memset( ctx->source, 0, sizeof( ctx->source ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif + + ctx->accumulator_started = 0; +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_init( &ctx->accumulator ); +#else + mbedtls_sha256_init( &ctx->accumulator ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_init( &ctx->havege_data ); +#endif + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) + if( custom_entropy_sources_mask & ENTROPY_SOURCE_PLATFORM ) + mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL, + MBEDTLS_ENTROPY_MIN_PLATFORM, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_TIMING_C) + if( custom_entropy_sources_mask & ENTROPY_SOURCE_TIMING ) + mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDCLOCK, + MBEDTLS_ENTROPY_SOURCE_WEAK ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + if( custom_entropy_sources_mask & ENTROPY_SOURCE_HAVEGE ) + mbedtls_entropy_add_source( ctx, mbedtls_havege_poll, &ctx->havege_data, + MBEDTLS_ENTROPY_MIN_HAVEGE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + if( custom_entropy_sources_mask & ENTROPY_SOURCE_HARDWARE ) + mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDWARE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + if( custom_entropy_sources_mask & ENTROPY_SOURCE_NV_SEED ) + mbedtls_entropy_add_source( ctx, mbedtls_nv_seed_poll, NULL, + MBEDTLS_ENTROPY_BLOCK_SIZE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); + ctx->initial_entropy_run = 0; +#endif +} + /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -75,3 +142,29 @@ void validate_module_init_key_based( int count ) TEST_ASSERT( status == PSA_ERROR_BAD_STATE ); } /* END_CASE */ + +/* BEGIN_CASE */ +void custom_entropy_sources( int sources_arg, int expected_init_status_arg ) +{ + psa_status_t expected_init_status = expected_init_status_arg; + int inited = 0; + uint8_t random[10] = { 0 }; + + custom_entropy_sources_mask = sources_arg; + TEST_ASSERT( mbedtls_psa_crypto_configure_entropy_sources( + custom_entropy_init, mbedtls_entropy_free ) == + PSA_SUCCESS ); + + TEST_ASSERT( psa_crypto_init( ) == expected_init_status ); + if( expected_init_status != PSA_SUCCESS ) + goto exit; + inited = 1; + + TEST_ASSERT( psa_generate_random( random, sizeof( random ) ) == + PSA_SUCCESS ); + +exit: + if( inited ) + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ From ebe770c693250dc2cc179b54361b81849fddd0a8 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Nov 2018 22:41:50 +0100 Subject: [PATCH 5/8] Add tests with a fake entropy source Add tests with a fake entropy source to check that the required amount of entropy is one block, fed in one or more steps. --- tests/suites/test_suite_psa_crypto_init.data | 15 ++++ .../test_suite_psa_crypto_init.function | 82 ++++++++++++++++++- 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data index 8ce044dc6..58817d93b 100644 --- a/tests/suites/test_suite_psa_crypto_init.data +++ b/tests/suites/test_suite_psa_crypto_init.data @@ -24,3 +24,18 @@ custom_entropy_sources:0x0000ffff:PSA_SUCCESS Custom entropy sources: none custom_entropy_sources:0:PSA_ERROR_INSUFFICIENT_ENTROPY + +Fake entropy: never returns anything +fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:0:PSA_ERROR_INSUFFICIENT_ENTROPY + +Fake entropy: less than the block size +fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY + +Fake entropy: one block eventually +fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS + +Fake entropy: one block in two steps +fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:1:-1:-1:PSA_SUCCESS + +Fake entropy: more than one block in two steps +fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 0957969d5..5aa571d49 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -12,12 +12,41 @@ #include "mbedtls/entropy.h" #include "mbedtls/entropy_poll.h" +#define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) ) + +typedef struct +{ + size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */ + size_t max_steps; + size_t *length_sequence; + size_t step; +} fake_entropy_state_t; +static int fake_entropy_source( void *state_arg, + unsigned char *output, size_t len, + size_t *olen ) +{ + fake_entropy_state_t *state = state_arg; + size_t i; + + if( state->step >= state->max_steps ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = MIN( len, state->length_sequence[state->step] ); + for( i = 0; i < *olen; i++ ) + output[i] = i; + ++state->step; + return( 0 ); +}; + #define ENTROPY_SOURCE_PLATFORM 0x00000001 #define ENTROPY_SOURCE_TIMING 0x00000002 #define ENTROPY_SOURCE_HAVEGE 0x00000004 #define ENTROPY_SOURCE_HARDWARE 0x00000008 #define ENTROPY_SOURCE_NV_SEED 0x00000010 +#define ENTROPY_SOURCE_FAKE 0x40000000 + static uint32_t custom_entropy_sources_mask; +static fake_entropy_state_t fake_entropy_state; /* This is a modified version of mbedtls_entropy_init() from entropy.c * which chooses entropy sources dynamically. */ @@ -71,6 +100,12 @@ static void custom_entropy_init( mbedtls_entropy_context *ctx ) MBEDTLS_ENTROPY_SOURCE_STRONG ); ctx->initial_entropy_run = 0; #endif + + if( custom_entropy_sources_mask & ENTROPY_SOURCE_FAKE ) + mbedtls_entropy_add_source( ctx, + fake_entropy_source, &fake_entropy_state, + fake_entropy_state.threshold, + MBEDTLS_ENTROPY_SOURCE_STRONG ); } /* END_HEADER */ @@ -147,7 +182,6 @@ void validate_module_init_key_based( int count ) void custom_entropy_sources( int sources_arg, int expected_init_status_arg ) { psa_status_t expected_init_status = expected_init_status_arg; - int inited = 0; uint8_t random[10] = { 0 }; custom_entropy_sources_mask = sources_arg; @@ -158,13 +192,53 @@ void custom_entropy_sources( int sources_arg, int expected_init_status_arg ) TEST_ASSERT( psa_crypto_init( ) == expected_init_status ); if( expected_init_status != PSA_SUCCESS ) goto exit; - inited = 1; TEST_ASSERT( psa_generate_random( random, sizeof( random ) ) == PSA_SUCCESS ); exit: - if( inited ) - mbedtls_psa_crypto_free( ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void fake_entropy_source( int threshold, + int amount1, + int amount2, + int amount3, + int amount4, + int expected_init_status_arg ) +{ + psa_status_t expected_init_status = expected_init_status_arg; + uint8_t random[10] = { 0 }; + size_t lengths[4]; + + fake_entropy_state.threshold = threshold; + fake_entropy_state.step = 0; + fake_entropy_state.max_steps = 0; + if( amount1 >= 0 ) + lengths[fake_entropy_state.max_steps++] = amount1; + if( amount2 >= 0 ) + lengths[fake_entropy_state.max_steps++] = amount2; + if( amount3 >= 0 ) + lengths[fake_entropy_state.max_steps++] = amount3; + if( amount4 >= 0 ) + lengths[fake_entropy_state.max_steps++] = amount4; + fake_entropy_state.length_sequence = lengths; + + custom_entropy_sources_mask = ENTROPY_SOURCE_FAKE; + TEST_ASSERT( mbedtls_psa_crypto_configure_entropy_sources( + custom_entropy_init, mbedtls_entropy_free ) == + PSA_SUCCESS ); + + TEST_ASSERT( psa_crypto_init( ) == expected_init_status ); + if( expected_init_status != PSA_SUCCESS ) + goto exit; + + TEST_ASSERT( psa_generate_random( random, sizeof( random ) ) == + PSA_SUCCESS ); + +exit: + mbedtls_psa_crypto_free( ); } /* END_CASE */ From 0b3b5733fcd27261de5cab1e35212e08339ca65e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Nov 2018 23:09:54 +0100 Subject: [PATCH 6/8] Support NV seed enabled at compile time but not at runtime When testing with custom entropy sources, if MBEDTLS_ENTROPY_NV_SEED is enabled at compile time but the NV seed source is not used at runtime, mbedtls_entropy_func makes a second pass anyway. Cope with this in the test code by telling the entropy module not to make this second pass. --- tests/suites/test_suite_psa_crypto_init.function | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 5aa571d49..13dfd3366 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -95,10 +95,17 @@ static void custom_entropy_init( mbedtls_entropy_context *ctx ) #endif #if defined(MBEDTLS_ENTROPY_NV_SEED) if( custom_entropy_sources_mask & ENTROPY_SOURCE_NV_SEED ) + { mbedtls_entropy_add_source( ctx, mbedtls_nv_seed_poll, NULL, MBEDTLS_ENTROPY_BLOCK_SIZE, MBEDTLS_ENTROPY_SOURCE_STRONG ); - ctx->initial_entropy_run = 0; + ctx->initial_entropy_run = 0; + } + else + { + /* Skip the NV seed even though it's compiled in. */ + ctx->initial_entropy_run = 1; + } #endif if( custom_entropy_sources_mask & ENTROPY_SOURCE_FAKE ) From 0fce4c58301df29664b904dae76d13d30f81128a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Nov 2018 23:21:01 +0100 Subject: [PATCH 7/8] Add init tests with entropy from NV seed --- tests/suites/test_suite_psa_crypto_init.data | 9 +++++ .../test_suite_psa_crypto_init.function | 35 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data index 58817d93b..6996c115b 100644 --- a/tests/suites/test_suite_psa_crypto_init.data +++ b/tests/suites/test_suite_psa_crypto_init.data @@ -39,3 +39,12 @@ fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:1: Fake entropy: more than one block in two steps fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:PSA_SUCCESS + +NV seed only: less than minimum +entropy_from_nv_seed:MBEDTLS_ENTROPY_MIN_PLATFORM - 1:PSA_ERROR_INSUFFICIENT_ENTROPY + +NV seed only: less than one block +entropy_from_nv_seed:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:PSA_ERROR_INSUFFICIENT_ENTROPY + +NV seed only: just enough +entropy_from_nv_seed:ENTROPY_MIN_NV_SEED_SIZE:PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 13dfd3366..f4bb86f09 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -11,8 +11,13 @@ #include "mbedtls/entropy.h" #include "mbedtls/entropy_poll.h" +#include "mbedtls/platform.h" #define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) ) +#define MAX( x, y ) ( ( x ) > ( y ) ? ( x ) : ( y ) ) + +#define ENTROPY_MIN_NV_SEED_SIZE \ + MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) typedef struct { @@ -249,3 +254,33 @@ exit: mbedtls_psa_crypto_free( ); } /* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED */ +void entropy_from_nv_seed( int seed_size_arg, + int expected_init_status_arg ) +{ + psa_status_t expected_init_status = expected_init_status_arg; + uint8_t random[10] = { 0 }; + uint8_t *seed = NULL; + size_t seed_size = seed_size_arg; + + ASSERT_ALLOC( seed, seed_size ); + TEST_ASSERT( mbedtls_nv_seed_write( seed, seed_size ) >= 0 ); + + custom_entropy_sources_mask = ENTROPY_SOURCE_NV_SEED; + TEST_ASSERT( mbedtls_psa_crypto_configure_entropy_sources( + custom_entropy_init, mbedtls_entropy_free ) == + PSA_SUCCESS ); + + TEST_ASSERT( psa_crypto_init( ) == expected_init_status ); + if( expected_init_status != PSA_SUCCESS ) + goto exit; + + TEST_ASSERT( psa_generate_random( random, sizeof( random ) ) == + PSA_SUCCESS ); + +exit: + mbedtls_free( seed ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ From 9e1be6a246cffccbaec50ed9831d9e79b1dbb7c3 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Nov 2018 23:21:37 +0100 Subject: [PATCH 8/8] Create the NV seed file for the tests if needed Write an all-bits-zero NV seed file for the tests. Without this, if the seed file is not present when this test suite is executed, the PSA module initialization will fail, causing most test cases to fail. Also write an all-bits-zero NV seed file at the end. The test cases in this test suite mess with the file, but subsequent test suites may need it. --- tests/suites/test_suite_psa_crypto_init.data | 6 ++++++ tests/suites/test_suite_psa_crypto_init.function | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data index 6996c115b..c57a764ef 100644 --- a/tests/suites/test_suite_psa_crypto_init.data +++ b/tests/suites/test_suite_psa_crypto_init.data @@ -1,3 +1,6 @@ +Create NV seed file +create_nv_seed: + PSA init/deinit init_deinit:2 @@ -48,3 +51,6 @@ entropy_from_nv_seed:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:PSA_ERROR_INSUFFICIENT_ENTRO NV seed only: just enough entropy_from_nv_seed:ENTROPY_MIN_NV_SEED_SIZE:PSA_SUCCESS + +Recreate NV seed file +create_nv_seed: diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index f4bb86f09..359650429 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -127,6 +127,14 @@ static void custom_entropy_init( mbedtls_entropy_context *ctx ) * END_DEPENDENCIES */ +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED */ +void create_nv_seed( ) +{ + static unsigned char seed[ENTROPY_MIN_NV_SEED_SIZE]; + TEST_ASSERT( mbedtls_nv_seed_write( seed, sizeof( seed ) ) >= 0 ); +} +/* END_CASE */ + /* BEGIN_CASE */ void init_deinit( int count ) {