From 90edc99e30c480c2db9c916b8d83767970f3003c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 15:39:19 +0100 Subject: [PATCH 01/26] Create a header file for PSA crypto random generator abstraction Subsequent commits will move declarations and definitions there. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 2 ++ library/psa_crypto_random.h | 26 ++++++++++++++++++++++++++ visualc/VS2010/mbedTLS.vcxproj | 1 + 3 files changed, 29 insertions(+) create mode 100644 library/psa_crypto_random.h diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 66c8f65bc..c041e8eed 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -40,6 +40,8 @@ * stored keys. */ #include "psa_crypto_storage.h" +#include "psa_crypto_random.h" + #include #include #include diff --git a/library/psa_crypto_random.h b/library/psa_crypto_random.h new file mode 100644 index 000000000..c90891dc9 --- /dev/null +++ b/library/psa_crypto_random.h @@ -0,0 +1,26 @@ +/** \file psa_crypto_random.h + * + * \brief PSA crypto random generator abstraction. + */ +/* + * Copyright The Mbed TLS Contributors + * 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. + */ + +#ifndef PSA_CRYPTO_RANDOM_H +#define PSA_CRYPTO_RANDOM_H + + +#endif /* PSA_CRYPTO_RANDOM_H */ diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 0af414517..1d28df097 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -251,6 +251,7 @@ + From 30524eb7e5a34ef9839600f172e248d05696fcb5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 17:02:26 +0100 Subject: [PATCH 02/26] psa_crypto: create random and drbg abstraction Create wrapper functions around calls to CTR_DRBG and around calls to entropy+DRBG. This is in preparation for allowing alternative DRBG implementations that use the Mbed TLS entropy module, or complete RNG implementations that bypass the entropy module as well. This is purely a refactoring commit. No behavior change. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 159 ++++++++++++++++++++---------------- library/psa_crypto_random.h | 104 +++++++++++++++++++++++ 2 files changed, 192 insertions(+), 71 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index c041e8eed..a8d2621a8 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -62,7 +62,6 @@ #include "mbedtls/cipher.h" #include "mbedtls/ccm.h" #include "mbedtls/cmac.h" -#include "mbedtls/ctr_drbg.h" #include "mbedtls/des.h" #include "mbedtls/ecdh.h" #include "mbedtls/ecp.h" @@ -117,10 +116,7 @@ static int key_type_is_raw_bytes( psa_key_type_t type ) 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; + mbedtls_psa_random_context_t rng; unsigned initialized : 1; unsigned rng_state : 2; } psa_global_data_t; @@ -869,7 +865,7 @@ static psa_status_t psa_export_ecp_key( psa_key_type_t type, /* Calculate the public key */ status = mbedtls_to_psa_error( mbedtls_ecp_mul( &ecp->grp, &ecp->Q, &ecp->d, &ecp->grp.G, - mbedtls_ctr_drbg_random, &global_data.ctr_drbg ) ); + mbedtls_psa_get_random, mbedtls_psa_random_state( &global_data.rng ) ) ); if( status != PSA_SUCCESS ) return( status ); } @@ -3651,8 +3647,8 @@ static psa_status_t psa_rsa_sign( mbedtls_rsa_context *rsa, mbedtls_rsa_set_padding( rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); ret = mbedtls_rsa_pkcs1_sign( rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), MBEDTLS_RSA_PRIVATE, md_alg, (unsigned int) hash_length, @@ -3666,8 +3662,8 @@ static psa_status_t psa_rsa_sign( mbedtls_rsa_context *rsa, { mbedtls_rsa_set_padding( rsa, MBEDTLS_RSA_PKCS_V21, md_alg ); ret = mbedtls_rsa_rsassa_pss_sign( rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_NONE, (unsigned int) hash_length, @@ -3709,8 +3705,8 @@ static psa_status_t psa_rsa_verify( mbedtls_rsa_context *rsa, mbedtls_rsa_set_padding( rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); ret = mbedtls_rsa_pkcs1_verify( rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), MBEDTLS_RSA_PUBLIC, md_alg, (unsigned int) hash_length, @@ -3724,8 +3720,8 @@ static psa_status_t psa_rsa_verify( mbedtls_rsa_context *rsa, { mbedtls_rsa_set_padding( rsa, MBEDTLS_RSA_PKCS_V21, md_alg ); ret = mbedtls_rsa_rsassa_pss_verify( rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_NONE, (unsigned int) hash_length, @@ -3782,8 +3778,8 @@ static psa_status_t psa_ecdsa_sign( mbedtls_ecp_keypair *ecp, MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det_ext( &ecp->grp, &r, &s, &ecp->d, hash, hash_length, md_alg, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg ) ); + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ) ) ); } else #endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */ @@ -3791,8 +3787,8 @@ static psa_status_t psa_ecdsa_sign( mbedtls_ecp_keypair *ecp, (void) alg; MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ecp->grp, &r, &s, &ecp->d, hash, hash_length, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg ) ); + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ) ) ); } MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &r, @@ -3837,7 +3833,7 @@ static psa_status_t psa_ecdsa_verify( mbedtls_ecp_keypair *ecp, { MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ecp->grp, &ecp->Q, &ecp->d, &ecp->grp.G, - mbedtls_ctr_drbg_random, &global_data.ctr_drbg ) ); + mbedtls_psa_get_random, mbedtls_psa_random_state( &global_data.rng ) ) ); } ret = mbedtls_ecdsa_verify( &ecp->grp, hash, hash_length, @@ -4137,8 +4133,8 @@ psa_status_t psa_asymmetric_encrypt( mbedtls_svc_key_id_t key, { status = mbedtls_to_psa_error( mbedtls_rsa_pkcs1_encrypt( rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), MBEDTLS_RSA_PUBLIC, input_length, input, @@ -4152,8 +4148,8 @@ psa_status_t psa_asymmetric_encrypt( mbedtls_svc_key_id_t key, psa_rsa_oaep_set_padding_mode( alg, rsa ); status = mbedtls_to_psa_error( mbedtls_rsa_rsaes_oaep_encrypt( rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), MBEDTLS_RSA_PUBLIC, salt, salt_length, input_length, @@ -4244,8 +4240,8 @@ psa_status_t psa_asymmetric_decrypt( mbedtls_svc_key_id_t key, { status = mbedtls_to_psa_error( mbedtls_rsa_pkcs1_decrypt( rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), MBEDTLS_RSA_PRIVATE, output_length, input, @@ -4260,8 +4256,8 @@ psa_status_t psa_asymmetric_decrypt( mbedtls_svc_key_id_t key, psa_rsa_oaep_set_padding_mode( alg, rsa ); status = mbedtls_to_psa_error( mbedtls_rsa_rsaes_oaep_decrypt( rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), MBEDTLS_RSA_PRIVATE, salt, salt_length, output_length, @@ -4495,8 +4491,8 @@ psa_status_t psa_cipher_generate_iv( psa_cipher_operation_t *operation, status = PSA_ERROR_BUFFER_TOO_SMALL; goto exit; } - ret = mbedtls_ctr_drbg_random( &global_data.ctr_drbg, - iv, operation->iv_size ); + ret = mbedtls_psa_get_random( mbedtls_psa_random_state( &global_data.rng ), + iv, operation->iv_size ); if( ret != 0 ) { status = mbedtls_to_psa_error( ret ); @@ -6111,8 +6107,8 @@ static psa_status_t psa_key_agreement_ecdh( const uint8_t *peer_key, mbedtls_ecdh_calc_secret( &ecdh, shared_secret_length, shared_secret, shared_secret_size, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg ) ); + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ) ) ); if( status != PSA_SUCCESS ) goto exit; if( PSA_BITS_TO_BYTES( bits ) != *shared_secret_length ) @@ -6290,28 +6286,72 @@ exit: } + /****************************************************************/ /* Random generation */ /****************************************************************/ +/** Initialize the PSA random generator. + */ +static void mbedtls_psa_random_init( mbedtls_psa_random_context_t *rng ) +{ + /* Set default configuration if + * mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */ + if( rng->entropy_init == NULL ) + rng->entropy_init = mbedtls_entropy_init; + if( rng->entropy_free == NULL ) + rng->entropy_free = mbedtls_entropy_free; + + rng->entropy_init( &rng->entropy ); +#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \ + defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) + /* The PSA entropy injection feature depends on using NV seed as an entropy + * source. Add NV seed as an entropy source for PSA entropy injection. */ + mbedtls_entropy_add_source( &rng->entropy, + mbedtls_nv_seed_poll, NULL, + MBEDTLS_ENTROPY_BLOCK_SIZE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif + + mbedtls_psa_drbg_init( mbedtls_psa_random_state( rng ) ); +} + +/** Deinitialize the PSA random generator. + */ +static void mbedtls_psa_random_free( mbedtls_psa_random_context_t *rng ) +{ + mbedtls_psa_drbg_free( mbedtls_psa_random_state( rng ) ); + rng->entropy_free( &rng->entropy ); +} + +/** Seed the PSA random generator. + */ +static psa_status_t mbedtls_psa_random_seed( mbedtls_psa_random_context_t *rng ) +{ + const unsigned char drbg_seed[] = "PSA"; + int ret = mbedtls_psa_drbg_seed( rng, drbg_seed, sizeof( drbg_seed ) - 1 ); + return mbedtls_to_psa_error( ret ); +} + psa_status_t psa_generate_random( uint8_t *output, size_t output_size ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; GUARD_MODULE_INITIALIZED; - while( output_size > MBEDTLS_CTR_DRBG_MAX_REQUEST ) + while( output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ) { - ret = mbedtls_ctr_drbg_random( &global_data.ctr_drbg, - output, - MBEDTLS_CTR_DRBG_MAX_REQUEST ); + ret = mbedtls_psa_get_random( + mbedtls_psa_random_state( &global_data.rng ), + output, MBEDTLS_PSA_RANDOM_MAX_REQUEST ); if( ret != 0 ) return( mbedtls_to_psa_error( ret ) ); - output += MBEDTLS_CTR_DRBG_MAX_REQUEST; - output_size -= MBEDTLS_CTR_DRBG_MAX_REQUEST; + output += MBEDTLS_PSA_RANDOM_MAX_REQUEST; + output_size -= MBEDTLS_PSA_RANDOM_MAX_REQUEST; } - ret = mbedtls_ctr_drbg_random( &global_data.ctr_drbg, output, output_size ); + ret = mbedtls_psa_get_random( mbedtls_psa_random_state( &global_data.rng ), + output, output_size ); return( mbedtls_to_psa_error( ret ) ); } @@ -6417,8 +6457,8 @@ static psa_status_t psa_generate_key_internal( return( status ); mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); ret = mbedtls_rsa_gen_key( &rsa, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg, + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ), (unsigned int) bits, exponent ); if( ret != 0 ) @@ -6463,8 +6503,8 @@ static psa_status_t psa_generate_key_internal( return( PSA_ERROR_NOT_SUPPORTED ); mbedtls_ecp_keypair_init( &ecp ); ret = mbedtls_ecp_gen_key( grp_id, &ecp, - mbedtls_ctr_drbg_random, - &global_data.ctr_drbg ); + mbedtls_psa_get_random, + mbedtls_psa_random_state( &global_data.rng ) ); if( ret != 0 ) { mbedtls_ecp_keypair_free( &ecp ); @@ -6550,8 +6590,8 @@ psa_status_t mbedtls_psa_crypto_configure_entropy_sources( { 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; + global_data.rng.entropy_init = entropy_init; + global_data.rng.entropy_free = entropy_free; return( PSA_SUCCESS ); } @@ -6560,8 +6600,7 @@ void mbedtls_psa_crypto_free( void ) psa_wipe_all_key_slots( ); if( global_data.rng_state != RNG_NOT_INITIALIZED ) { - mbedtls_ctr_drbg_free( &global_data.ctr_drbg ); - global_data.entropy_free( &global_data.entropy ); + mbedtls_psa_random_free( &global_data.rng ); } /* Wipe all remaining data, including configuration. * In particular, this sets all state indicator to the value @@ -6603,37 +6642,15 @@ static psa_status_t psa_crypto_recover_transaction( psa_status_t psa_crypto_init( void ) { psa_status_t status; - const unsigned char drbg_seed[] = "PSA"; /* Double initialization is explicitly allowed. */ if( global_data.initialized != 0 ) return( PSA_SUCCESS ); - /* 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. */ - global_data.entropy_init( &global_data.entropy ); -#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \ - defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) - /* The PSA entropy injection feature depends on using NV seed as an entropy - * source. Add NV seed as an entropy source for PSA entropy injection. */ - mbedtls_entropy_add_source( &global_data.entropy, - mbedtls_nv_seed_poll, NULL, - MBEDTLS_ENTROPY_BLOCK_SIZE, - MBEDTLS_ENTROPY_SOURCE_STRONG ); -#endif - mbedtls_ctr_drbg_init( &global_data.ctr_drbg ); + /* Initialize and seed the random generator. */ + mbedtls_psa_random_init( &global_data.rng ); global_data.rng_state = RNG_INITIALIZED; - status = mbedtls_to_psa_error( - mbedtls_ctr_drbg_seed( &global_data.ctr_drbg, - mbedtls_entropy_func, - &global_data.entropy, - drbg_seed, sizeof( drbg_seed ) - 1 ) ); + status = mbedtls_psa_random_seed( &global_data.rng ); if( status != PSA_SUCCESS ) goto exit; global_data.rng_state = RNG_SEEDED; diff --git a/library/psa_crypto_random.h b/library/psa_crypto_random.h index c90891dc9..95974d93e 100644 --- a/library/psa_crypto_random.h +++ b/library/psa_crypto_random.h @@ -22,5 +22,109 @@ #ifndef PSA_CRYPTO_RANDOM_H #define PSA_CRYPTO_RANDOM_H +/* Currently, the only supported RNG is Mbed TLS's CTR_DRBG seeded with + * mbedtls_entropy_func(). */ + +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/entropy.h" + +/** The type of the PSA DRBG context. + */ +typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t; + +/** Initialize the PSA DRBG. + * + * \param p_rng Pointer to the Mbed TLS DRBG state. + */ +static inline void mbedtls_psa_drbg_init( mbedtls_psa_drbg_context_t *p_rng ) +{ + mbedtls_ctr_drbg_init( p_rng ); +} + +/** Deinitialize the PSA DRBG. + * + * \param p_rng Pointer to the Mbed TLS DRBG state. + */ +static inline void mbedtls_psa_drbg_free( mbedtls_psa_drbg_context_t *p_rng ) +{ + mbedtls_ctr_drbg_free( p_rng ); +} + +/** The type of the PSA random generator context. + * + * The random generator context is composed of an entropy context and + * a DRBG context. + */ +typedef struct +{ + void (* entropy_init )( mbedtls_entropy_context *ctx ); + void (* entropy_free )( mbedtls_entropy_context *ctx ); + mbedtls_entropy_context entropy; + mbedtls_psa_drbg_context_t drbg; +} mbedtls_psa_random_context_t; + +/** Return random data. + * + * This function is suitable as the \p f_rng parameter to Mbed TLS functions + * that require a random generator. Use mbedtls_psa_random_state() to + * obtain the \p p_rng parameter. + * + * \param p_rng The CTR_DRBG context. This must be + * mbedtls_psa_random_state( \c rng ) + * where \c rng is a pointer to a + * ::mbedtls_psa_random_context_t structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer in bytes. + * It must be at most #MBEDTLS_PSA_RANDOM_MAX_REQUEST. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. + */ +static inline int mbedtls_psa_get_random( void *p_rng, + unsigned char *output, + size_t output_len ) +{ + return( mbedtls_ctr_drbg_random( p_rng, output, output_len ) ); +} + +/** The maximum number of bytes that mbedtls_psa_get_random() is expected to + * return. + */ +#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST + +/** Retrieve the DRBG state from the PSA RNG state. + * + * \param rng Pointer to the PSA random generator state. + * + * \return The DRBG state (\c p_rng argument ). + */ +static inline mbedtls_psa_drbg_context_t *mbedtls_psa_random_state( + mbedtls_psa_random_context_t *rng ) +{ + return( &rng->drbg ); +} + + +/** Seed the PSA DRBG. + * + * \param rng DRBG context to be seeded. + * \param custom The personalization string. + * This can be \c NULL, in which case the personalization + * string is empty regardless of the value of \p len. + * \param len The length of the personalization string. + * + * \return \c 0 on success. + * \return An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure. + */ +static inline int mbedtls_psa_drbg_seed( + mbedtls_psa_random_context_t *rng, + const unsigned char *custom, size_t len ) +{ + return( mbedtls_ctr_drbg_seed( mbedtls_psa_random_state( rng ), + mbedtls_entropy_func, + &rng->entropy, + custom, len ) ); +} #endif /* PSA_CRYPTO_RANDOM_H */ From f08b3f862408f03f78e30b524d0589446d9234a0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 17:36:48 +0100 Subject: [PATCH 03/26] Autonomous random driver: create configuration option Create a configuration option for autonomous random drivers, i.e. PSA crypto drivers that provide a random generator, that have their own entropy source and do not support injecting entropy from another source. This commit only creates the configuration option. Subsequent commits will add the implementation and tests. Signed-off-by: Gilles Peskine --- include/mbedtls/check_config.h | 9 +++++---- include/mbedtls/config.h | 32 +++++++++++++++++++++++++++++++- library/version_features.c | 3 +++ programs/test/query_config.c | 8 ++++++++ scripts/config.py | 1 + 5 files changed, 48 insertions(+), 5 deletions(-) diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index 1ebb7066a..91aaf80dc 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -572,10 +572,11 @@ #error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously" #endif -#if defined(MBEDTLS_PSA_CRYPTO_C) && \ - !( defined(MBEDTLS_CTR_DRBG_C) && \ - defined(MBEDTLS_ENTROPY_C) ) -#error "MBEDTLS_PSA_CRYPTO_C defined, but not all prerequisites" +#if defined(MBEDTLS_PSA_CRYPTO_C) && \ + !( ( defined(MBEDTLS_CTR_DRBG_C) && \ + defined(MBEDTLS_ENTROPY_C) ) || \ + defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) ) +#error "MBEDTLS_PSA_CRYPTO_C defined, but not all prerequisites (missing RNG)" #endif #if defined(MBEDTLS_PSA_CRYPTO_SPM) && !defined(MBEDTLS_PSA_CRYPTO_C) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 464b61ee2..02618fbfa 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1337,6 +1337,35 @@ */ //#define MBEDTLS_PSA_CRYPTO_DRIVERS +/** \def MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + * + * Make the PSA Crypto module use an external random generator provided + * by a driver, instead of Mbed TLS's entropy and DRBG modules. + * + * If you enable this option, you must supply a type called + * \c mbedtls_psa_external_random_context_t and a function called + * mbedtls_psa_external_get_random() with the following prototype: + * ``` + * psa_status_t mbedtls_psa_external_get_random( + * mbedtls_psa_external_random_context_t *context, + * uint8_t *output, size_t output_size, size_t *output_length); + * ); + * ``` + * The \c context value is initialized to 0 before the first call. + * The function must fill the \c output buffer with \p output_size bytes + * of random data and set \c *output_length to \p output_size. + * + * Requires: MBEDTLS_PSA_CRYPTO_C + * + * \warning If you enable this option, code that uses the PSA cryptography + * interface will not use any of the entropy sources set up for + * the entropy module, nor the NV seed that MBEDTLS_ENTROPY_NV_SEED + * enables. + * + * \note This option is experimental and may be removed without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + /** * \def MBEDTLS_PSA_CRYPTO_SPM * @@ -3115,7 +3144,8 @@ * * Module: library/psa_crypto.c * - * Requires: MBEDTLS_CTR_DRBG_C, MBEDTLS_ENTROPY_C + * Requires: either MBEDTLS_CTR_DRBG_C and MBEDTLS_ENTROPY_C, + * or MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. * */ #define MBEDTLS_PSA_CRYPTO_C diff --git a/library/version_features.c b/library/version_features.c index 42ccaf954..80f121a0d 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -438,6 +438,9 @@ static const char * const features[] = { #if defined(MBEDTLS_PSA_CRYPTO_DRIVERS) "MBEDTLS_PSA_CRYPTO_DRIVERS", #endif /* MBEDTLS_PSA_CRYPTO_DRIVERS */ +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + "MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG", +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ #if defined(MBEDTLS_PSA_CRYPTO_SPM) "MBEDTLS_PSA_CRYPTO_SPM", #endif /* MBEDTLS_PSA_CRYPTO_SPM */ diff --git a/programs/test/query_config.c b/programs/test/query_config.c index 1345b11fe..05a953c63 100644 --- a/programs/test/query_config.c +++ b/programs/test/query_config.c @@ -1224,6 +1224,14 @@ int query_config( const char *config ) } #endif /* MBEDTLS_PSA_CRYPTO_DRIVERS */ +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + if( strcmp( "MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG ); + return( 0 ); + } +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + #if defined(MBEDTLS_PSA_CRYPTO_SPM) if( strcmp( "MBEDTLS_PSA_CRYPTO_SPM", config ) == 0 ) { diff --git a/scripts/config.py b/scripts/config.py index ae0614ae0..b60f93d7d 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -185,6 +185,7 @@ EXCLUDE_FROM_FULL = frozenset([ 'MBEDTLS_PKCS11_C', # build dependency (libpkcs11-helper) 'MBEDTLS_PLATFORM_NO_STD_FUNCTIONS', # removes a feature 'MBEDTLS_PSA_CRYPTO_CONFIG', # toggles old/new style PSA config + 'MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG', # behavior change + build dependency 'MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER', # incompatible with USE_PSA_CRYPTO 'MBEDTLS_PSA_CRYPTO_SPM', # platform dependency (PSA SPM) 'MBEDTLS_PSA_INJECT_ENTROPY', # build dependency (hook functions) From 514a8fdf4077fee122f9ed882ce30908aeb90e7f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 17:41:53 +0100 Subject: [PATCH 04/26] Create a file for PSA crypto test helpers Signed-off-by: Gilles Peskine --- tests/src/psa_crypto_helpers.c | 30 ++++++++++++++++++++++++++++++ visualc/VS2010/mbedTLS.vcxproj | 1 + 2 files changed, 31 insertions(+) create mode 100644 tests/src/psa_crypto_helpers.c diff --git a/tests/src/psa_crypto_helpers.c b/tests/src/psa_crypto_helpers.c new file mode 100644 index 000000000..40877c7f7 --- /dev/null +++ b/tests/src/psa_crypto_helpers.c @@ -0,0 +1,30 @@ +/** \file psa_crypto_helpers.c + * + * \brief Helper functions to test PSA crypto functionality. + */ + +/* + * Copyright The Mbed TLS Contributors + * 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. + */ + +#include +#include + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 1d28df097..98b8d66f6 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -351,6 +351,7 @@ + From b8af22858dbbb5fa0d1cfcf262d4a70f63f0bd60 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 18:00:34 +0100 Subject: [PATCH 05/26] Autonomous random driver: declare the type and function Define a sample type mbedtls_psa_external_random_context_t in psa/crypto_platform.h and define the prototype of mbedtls_psa_external_get_random() in a public header. Signed-off-by: Gilles Peskine --- include/mbedtls/config.h | 7 ++++--- include/psa/crypto_extra.h | 30 ++++++++++++++++++++++++++++++ include/psa/crypto_platform.h | 6 ++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 02618fbfa..58d78075d 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1342,9 +1342,10 @@ * Make the PSA Crypto module use an external random generator provided * by a driver, instead of Mbed TLS's entropy and DRBG modules. * - * If you enable this option, you must supply a type called - * \c mbedtls_psa_external_random_context_t and a function called - * mbedtls_psa_external_get_random() with the following prototype: + * If you enable this option, you must supply configure the type + * ::mbedtls_psa_external_random_context_t in psa/crypto_platform.h + * and define a function called mbedtls_psa_external_get_random() + * with the following prototype: * ``` * psa_status_t mbedtls_psa_external_get_random( * mbedtls_psa_external_random_context_t *context, diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index b25addc85..218a6bab2 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -649,6 +649,36 @@ mbedtls_ecp_group_id mbedtls_ecc_group_of_psa( psa_ecc_family_t curve, /**@}*/ +/** \defgroup psa_external_rng External random generator + * @{ + */ + +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/** External random generator function, implemented by the platform. + * + * When the compile-time option #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled, + * this function replaces Mbed TLS's entropy and DRBG modules for all + * random generation triggered via PSA crypto interfaces. + * + * \param[in,out] context Pointer to the random generator context. + * This is all-bits-zero on the first call + * and preserved between successive calls. + * \param[out] output Output buffer. On success, this buffer + * contains random data with a uniform + * distribution. + * \param output_size The size of the \p output buffer in bytes. + * \param[out] output_length On success, set this value to \p output_size. + * + * \retval #PSA_SUCCESS + * \retval #PSA_ERROR_HARDWARE_FAILURE + */ +psa_status_t mbedtls_psa_external_get_random( + mbedtls_psa_external_random_context_t *context, + uint8_t *output, size_t output_size, size_t *output_length ); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + +/**@}*/ + #ifdef __cplusplus } #endif diff --git a/include/psa/crypto_platform.h b/include/psa/crypto_platform.h index 567398dbf..a147a3eea 100644 --- a/include/psa/crypto_platform.h +++ b/include/psa/crypto_platform.h @@ -81,4 +81,10 @@ static inline int mbedtls_key_owner_id_equal( mbedtls_key_owner_id_t id1, #endif /* MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER */ +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +typedef struct { + uint8_t opaque[32]; +} mbedtls_psa_external_random_context_t; +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + #endif /* PSA_CRYPTO_PLATFORM_H */ From 1c49f1ac4606963f1b6ac00a18dbe870e0222fa0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 18:46:25 +0100 Subject: [PATCH 06/26] Include headers in psa_crypto.h for mbedtls_to_psa_error psa_crypto must be able to convert error codes even from modules that it doesn't call directly. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index a8d2621a8..a32ce94e4 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -51,6 +51,7 @@ #define mbedtls_free free #endif +#include "mbedtls/aes.h" #include "mbedtls/arc4.h" #include "mbedtls/asn1.h" #include "mbedtls/asn1write.h" @@ -62,6 +63,7 @@ #include "mbedtls/cipher.h" #include "mbedtls/ccm.h" #include "mbedtls/cmac.h" +#include "mbedtls/ctr_drbg.h" #include "mbedtls/des.h" #include "mbedtls/ecdh.h" #include "mbedtls/ecp.h" From 4fc21fdeb6ecff1165b1a7e77cea5676b8058ee0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 18:47:18 +0100 Subject: [PATCH 07/26] Implement MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG Implement support for MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. For test purposes, write an implementation that uses libc rand(). Signed-off-by: Gilles Peskine --- include/mbedtls/check_config.h | 5 +++ library/psa_crypto.c | 37 ++++++++++++++++++- library/psa_crypto_invasive.h | 2 + library/psa_crypto_random.h | 30 +++++++++++++++ tests/src/psa_crypto_helpers.c | 16 ++++++++ .../test_suite_psa_crypto_init.function | 12 ++++-- 6 files changed, 97 insertions(+), 5 deletions(-) diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index 91aaf80dc..949727994 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -605,6 +605,11 @@ #error "MBEDTLS_PSA_INJECT_ENTROPY is not compatible with actual entropy sources" #endif +#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \ + !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +#error "MBEDTLS_PSA_INJECT_ENTROPY is not compatible with MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG" +#endif + #if defined(MBEDTLS_PSA_ITS_FILE_C) && \ !defined(MBEDTLS_FS_IO) #error "MBEDTLS_PSA_ITS_FILE_C defined, but not all prerequisites" diff --git a/library/psa_crypto.c b/library/psa_crypto.c index a32ce94e4..410d6a191 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -6297,6 +6297,10 @@ exit: */ static void mbedtls_psa_random_init( mbedtls_psa_random_context_t *rng ) { +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + memset( rng, 0, sizeof( *rng ) ); +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + /* Set default configuration if * mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */ if( rng->entropy_init == NULL ) @@ -6316,31 +6320,59 @@ static void mbedtls_psa_random_init( mbedtls_psa_random_context_t *rng ) #endif mbedtls_psa_drbg_init( mbedtls_psa_random_state( rng ) ); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } /** Deinitialize the PSA random generator. */ static void mbedtls_psa_random_free( mbedtls_psa_random_context_t *rng ) { +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + memset( rng, 0, sizeof( *rng ) ); +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ mbedtls_psa_drbg_free( mbedtls_psa_random_state( rng ) ); rng->entropy_free( &rng->entropy ); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } /** Seed the PSA random generator. */ static psa_status_t mbedtls_psa_random_seed( mbedtls_psa_random_context_t *rng ) { +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + /* Do nothing: the external RNG seeds itself. */ + (void) rng; + return( PSA_SUCCESS ); +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ const unsigned char drbg_seed[] = "PSA"; int ret = mbedtls_psa_drbg_seed( rng, drbg_seed, sizeof( drbg_seed ) - 1 ); return mbedtls_to_psa_error( ret ); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } psa_status_t psa_generate_random( uint8_t *output, size_t output_size ) { - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; GUARD_MODULE_INITIALIZED; +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + + size_t output_length = 0; + psa_status_t status = mbedtls_psa_external_get_random( &global_data.rng, + output, output_size, + &output_length ); + if( status != PSA_SUCCESS ) + return( status ); + /* Breaking up a request into smaller chunks is currently not supported + * for the extrernal RNG interface. */ + if( output_length != output_size ) + return( PSA_ERROR_INSUFFICIENT_ENTROPY ); + return( PSA_SUCCESS ); + +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + while( output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ) { ret = mbedtls_psa_get_random( @@ -6355,6 +6387,7 @@ psa_status_t psa_generate_random( uint8_t *output, ret = mbedtls_psa_get_random( mbedtls_psa_random_state( &global_data.rng ), output, output_size ); return( mbedtls_to_psa_error( ret ) ); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } #if defined(MBEDTLS_PSA_INJECT_ENTROPY) @@ -6586,6 +6619,7 @@ exit: /* Module setup */ /****************************************************************/ +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) psa_status_t mbedtls_psa_crypto_configure_entropy_sources( void (* entropy_init )( mbedtls_entropy_context *ctx ), void (* entropy_free )( mbedtls_entropy_context *ctx ) ) @@ -6596,6 +6630,7 @@ psa_status_t mbedtls_psa_crypto_configure_entropy_sources( global_data.rng.entropy_free = entropy_free; return( PSA_SUCCESS ); } +#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ void mbedtls_psa_crypto_free( void ) { diff --git a/library/psa_crypto_invasive.h b/library/psa_crypto_invasive.h index 2b4ee1f34..be127d9f8 100644 --- a/library/psa_crypto_invasive.h +++ b/library/psa_crypto_invasive.h @@ -38,6 +38,7 @@ #include "mbedtls/entropy.h" +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) /** \brief Configure entropy sources. * * This function may only be called before a call to psa_crypto_init(), @@ -73,5 +74,6 @@ psa_status_t mbedtls_psa_crypto_configure_entropy_sources( void (* entropy_init )( mbedtls_entropy_context *ctx ), void (* entropy_free )( mbedtls_entropy_context *ctx ) ); +#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ #endif /* PSA_CRYPTO_INVASIVE_H */ diff --git a/library/psa_crypto_random.h b/library/psa_crypto_random.h index 95974d93e..2e7f94d4c 100644 --- a/library/psa_crypto_random.h +++ b/library/psa_crypto_random.h @@ -22,6 +22,34 @@ #ifndef PSA_CRYPTO_RANDOM_H #define PSA_CRYPTO_RANDOM_H +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + +#include +#include // only for error codes +#include + +typedef mbedtls_psa_external_random_context_t mbedtls_psa_random_context_t; + +static inline int mbedtls_psa_get_random( void *p_rng, + unsigned char *output, + size_t output_size ) +{ + (void) p_rng; + psa_status_t status = psa_generate_random( output, output_size ); + if( status == PSA_SUCCESS ) + return( 0 ); + else + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); +} + +static inline void *mbedtls_psa_random_state( mbedtls_psa_random_context_t *rng ) +{ + (void) rng; + return( NULL ); +} + +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + /* Currently, the only supported RNG is Mbed TLS's CTR_DRBG seeded with * mbedtls_entropy_func(). */ @@ -127,4 +155,6 @@ static inline int mbedtls_psa_drbg_seed( custom, len ) ); } +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + #endif /* PSA_CRYPTO_RANDOM_H */ diff --git a/tests/src/psa_crypto_helpers.c b/tests/src/psa_crypto_helpers.c index 40877c7f7..dacda683a 100644 --- a/tests/src/psa_crypto_helpers.c +++ b/tests/src/psa_crypto_helpers.c @@ -27,4 +27,20 @@ #include +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +#include + +psa_status_t mbedtls_psa_external_get_random( + mbedtls_psa_external_random_context_t *context, + uint8_t *output, size_t output_size, size_t *output_length ) +{ + /* This implementation is for test purposes only! + * Use the libc non-cryptographic random generator. */ + (void) context; + mbedtls_test_rnd_std_rand( NULL, output, output_size ); + *output_length = output_size; + return( PSA_SUCCESS ); +} +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + #endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 62ef6e2d7..867e4236c 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -17,6 +17,8 @@ #include "mbedtls/ctr_drbg.h" #define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + typedef struct { size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */ @@ -118,6 +120,8 @@ static void custom_entropy_init( mbedtls_entropy_context *ctx ) MBEDTLS_ENTROPY_SOURCE_STRONG ); } +#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ + /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -125,7 +129,7 @@ static void custom_entropy_init( mbedtls_entropy_context *ctx ) * END_DEPENDENCIES */ -/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED */ +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void create_nv_seed( ) { static unsigned char seed[ENTROPY_MIN_NV_SEED_SIZE]; @@ -201,7 +205,7 @@ void validate_module_init_key_based( int count ) } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void custom_entropy_sources( int sources_arg, int expected_init_status_arg ) { psa_status_t expected_init_status = expected_init_status_arg; @@ -222,7 +226,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void fake_entropy_source( int threshold, int amount1, int amount2, @@ -262,7 +266,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED */ +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void entropy_from_nv_seed( int seed_size_arg, int expected_init_status_arg ) { From 82e57d1611877b7d27f7194cb34528b8eca54ea2 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 21:31:17 +0100 Subject: [PATCH 08/26] PSA: support HMAC_DRBG Support using HMAC_DRBG instead of CTR_DRBG in the PSA subsystem. Use HMAC_DRBG if CTR_DRBG is available. Choose between SHA-256 and SHA-512 based on availability. Signed-off-by: Gilles Peskine --- include/mbedtls/check_config.h | 2 +- include/mbedtls/config.h | 1 + library/psa_crypto.c | 15 +++- library/psa_crypto_random.h | 72 +++++++++++++++++-- tests/scripts/all.sh | 4 -- .../test_suite_psa_crypto_init.function | 10 +++ 6 files changed, 91 insertions(+), 13 deletions(-) diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index 949727994..939ec6c65 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -573,7 +573,7 @@ #endif #if defined(MBEDTLS_PSA_CRYPTO_C) && \ - !( ( defined(MBEDTLS_CTR_DRBG_C) && \ + !( ( ( defined(MBEDTLS_CTR_DRBG_C) || defined(MBEDTLS_HMAC_DRBG_C) ) && \ defined(MBEDTLS_ENTROPY_C) ) || \ defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) ) #error "MBEDTLS_PSA_CRYPTO_C defined, but not all prerequisites (missing RNG)" diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 58d78075d..c022a6174 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -3146,6 +3146,7 @@ * Module: library/psa_crypto.c * * Requires: either MBEDTLS_CTR_DRBG_C and MBEDTLS_ENTROPY_C, + * or MBEDTLS_HMAC_DRBG_C and MBEDTLS_ENTROPY_C, * or MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. * */ diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 410d6a191..66c4f7de0 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -63,7 +63,6 @@ #include "mbedtls/cipher.h" #include "mbedtls/ccm.h" #include "mbedtls/cmac.h" -#include "mbedtls/ctr_drbg.h" #include "mbedtls/des.h" #include "mbedtls/ecdh.h" #include "mbedtls/ecp.h" @@ -214,6 +213,8 @@ psa_status_t mbedtls_to_psa_error( int ret ) case MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED: return( PSA_ERROR_HARDWARE_FAILURE ); +#if !( defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) || \ + defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) ) case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED: return( PSA_ERROR_INSUFFICIENT_ENTROPY ); case MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG: @@ -221,6 +222,7 @@ psa_status_t mbedtls_to_psa_error( int ret ) return( PSA_ERROR_NOT_SUPPORTED ); case MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR: return( PSA_ERROR_INSUFFICIENT_ENTROPY ); +#endif case MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH: return( PSA_ERROR_NOT_SUPPORTED ); @@ -239,6 +241,17 @@ psa_status_t mbedtls_to_psa_error( int ret ) case MBEDTLS_ERR_GCM_HW_ACCEL_FAILED: return( PSA_ERROR_HARDWARE_FAILURE ); +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) && \ + defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) + case MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED: + return( PSA_ERROR_INSUFFICIENT_ENTROPY ); + case MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG: + case MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR: + return( PSA_ERROR_INSUFFICIENT_ENTROPY ); +#endif + case MBEDTLS_ERR_MD2_HW_ACCEL_FAILED: case MBEDTLS_ERR_MD4_HW_ACCEL_FAILED: case MBEDTLS_ERR_MD5_HW_ACCEL_FAILED: diff --git a/library/psa_crypto_random.h b/library/psa_crypto_random.h index 2e7f94d4c..0f13c1392 100644 --- a/library/psa_crypto_random.h +++ b/library/psa_crypto_random.h @@ -50,15 +50,48 @@ static inline void *mbedtls_psa_random_state( mbedtls_psa_random_context_t *rng #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ -/* Currently, the only supported RNG is Mbed TLS's CTR_DRBG seeded with - * mbedtls_entropy_func(). */ +/* Choose a DRBG based on configuration and availability */ +#if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) + +#include "mbedtls/hmac_drbg.h" + +#elif defined(MBEDTLS_CTR_DRBG_C) #include "mbedtls/ctr_drbg.h" + +#elif defined(MBEDTLS_HMAC_DRBG_C) + +#include "mbedtls/hmac_drbg.h" +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_SHA256_C) +#include +#if SIZE_MAX > 0xffffffff +/* Looks like a 64-bit system, so prefer SHA-512. */ +#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_MD_SHA512 +#else +/* Looks like a 32-bit system, so prefer SHA-256. */ +#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_MD_SHA256 +#endif +#elif defined(MBEDTLS_SHA512_C) +#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_MD_SHA512 +#elif defined(MBEDTLS_SHA256_C) +#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_MD_SHA256 +#else +#error "No hash algorithm available for HMAC_DBRG." +#endif + +#else +#error "No DRBG module available for the psa_crypto module." +#endif + #include "mbedtls/entropy.h" /** The type of the PSA DRBG context. */ +#if defined(MBEDTLS_CTR_DRBG_C) typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t; +#elif defined(MBEDTLS_HMAC_DRBG_C) +typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t; +#endif /** Initialize the PSA DRBG. * @@ -66,7 +99,11 @@ typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t; */ static inline void mbedtls_psa_drbg_init( mbedtls_psa_drbg_context_t *p_rng ) { +#if defined(MBEDTLS_CTR_DRBG_C) mbedtls_ctr_drbg_init( p_rng ); +#elif defined(MBEDTLS_HMAC_DRBG_C) + mbedtls_hmac_drbg_init( p_rng ); +#endif } /** Deinitialize the PSA DRBG. @@ -75,7 +112,11 @@ static inline void mbedtls_psa_drbg_init( mbedtls_psa_drbg_context_t *p_rng ) */ static inline void mbedtls_psa_drbg_free( mbedtls_psa_drbg_context_t *p_rng ) { +#if defined(MBEDTLS_CTR_DRBG_C) mbedtls_ctr_drbg_free( p_rng ); +#elif defined(MBEDTLS_HMAC_DRBG_C) + mbedtls_hmac_drbg_free( p_rng ); +#endif } /** The type of the PSA random generator context. @@ -97,7 +138,7 @@ typedef struct * that require a random generator. Use mbedtls_psa_random_state() to * obtain the \p p_rng parameter. * - * \param p_rng The CTR_DRBG context. This must be + * \param p_rng The DRBG context. This must be * mbedtls_psa_random_state( \c rng ) * where \c rng is a pointer to a * ::mbedtls_psa_random_context_t structure. @@ -105,21 +146,29 @@ typedef struct * \param output_len The length of the buffer in bytes. * It must be at most #MBEDTLS_PSA_RANDOM_MAX_REQUEST. * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or - * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. + * \retval \c 0 on success. + * \return \c MBEDTLS_ERR_xxx_DRBG_xxx or + * \c MBEDTLS_ERR_PLATFORM_xxx on failure. */ static inline int mbedtls_psa_get_random( void *p_rng, unsigned char *output, size_t output_len ) { +#if defined(MBEDTLS_CTR_DRBG_C) return( mbedtls_ctr_drbg_random( p_rng, output, output_len ) ); +#elif defined(MBEDTLS_HMAC_DRBG_C) + return( mbedtls_hmac_drbg_random( p_rng, output, output_len ) ); +#endif } /** The maximum number of bytes that mbedtls_psa_get_random() is expected to * return. */ +#if defined(MBEDTLS_CTR_DRBG_C) #define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST +#elif defined(MBEDTLS_HMAC_DRBG_C) +#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST +#endif /** Retrieve the DRBG state from the PSA RNG state. * @@ -133,7 +182,6 @@ static inline mbedtls_psa_drbg_context_t *mbedtls_psa_random_state( return( &rng->drbg ); } - /** Seed the PSA DRBG. * * \param rng DRBG context to be seeded. @@ -149,10 +197,20 @@ static inline int mbedtls_psa_drbg_seed( mbedtls_psa_random_context_t *rng, const unsigned char *custom, size_t len ) { +#if defined(MBEDTLS_CTR_DRBG_C) return( mbedtls_ctr_drbg_seed( mbedtls_psa_random_state( rng ), mbedtls_entropy_func, &rng->entropy, custom, len ) ); +#elif defined(MBEDTLS_HMAC_DRBG_C) + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type( MBEDTLS_PSA_HMAC_DRBG_MD_TYPE ); + return( mbedtls_hmac_drbg_seed( mbedtls_psa_random_state( rng ), + md_info, + mbedtls_entropy_func, + &rng->entropy, + custom, len ) ); +#endif } #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 2bb2216c9..30ec62f86 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -915,10 +915,6 @@ component_test_no_ctr_drbg () { msg "build: Full minus CTR_DRBG" scripts/config.py full scripts/config.py unset MBEDTLS_CTR_DRBG_C - scripts/config.py unset MBEDTLS_PSA_CRYPTO_C # requires CTR_DRBG - scripts/config.py unset MBEDTLS_PSA_CRYPTO_STORAGE_C # requires PSA Crypto - scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C # requires PSA Crypto - scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO # requires PSA Crypto CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . make diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 867e4236c..16e44c7af 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -11,11 +11,21 @@ #define ENTROPY_MIN_NV_SEED_SIZE \ MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) +#include "psa_crypto_random.h" +#if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) +/* PSA crypto uses the HMAC_DRBG module. It reads from the entropy source twice: + * once for the initial entropy and once for a nonce. The nonce length is + * half the entropy length. For SHA-256, SHA-384 or SHA-512, the + * entropy length is 256 per the documentation of mbedtls_hmac_drbg_seed(), + * and PSA crypto doesn't support other hashes for HMAC_DRBG. */ +#define ENTROPY_NONCE_LEN ( 256 / 2 ) +#else /* PSA crypto uses the CTR_DRBG module. In some configurations, it needs * to read from the entropy source twice: once for the initial entropy * and once for a nonce. */ #include "mbedtls/ctr_drbg.h" #define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN +#endif #if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) From ed038902813a5afba50276f68d3a0a8a8c7c69c1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 21:33:21 +0100 Subject: [PATCH 09/26] PSA: allow the configuration to favor HMAC_DRBG Allow the user to configure PSA to use HMAC_DRBG even if CTR_DRBG is available, or to explicitly select the hash algorithm to use for HMAC_DRBG, by setting MBEDTLS_PSA_HMAC_DRBG_MD_TYPE in config.h. Signed-off-by: Gilles Peskine --- include/mbedtls/config.h | 14 ++++++++++++++ programs/test/query_config.c | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index c022a6174..5755df3b9 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -3635,6 +3635,20 @@ */ //#define MBEDTLS_PARAM_FAILED( cond ) assert( cond ) +/* PSA options */ +/** \def MBEDTLS_PSA_HMAC_DRBG_MD_TYPE + * + * Use HMAC_DRBG with the specified hash algorithm for HMAC_DRBG for the + * PSA crypto subsystem. + * + * If this option is unset: + * - If CTR_DRBG is available, the PSA subsystem uses it rather than HMAC_DRBG. + * - Otherwise, the PSA subsystem uses one HMAC_DRBG with of + * #MBEDTLS_MD_SHA512 or #MBEDTLS_MD_SHA256 based on availability and + * on unspecified heuristics. + */ +//#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_MD_SHA256 + /* SSL Cache options */ //#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ //#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ diff --git a/programs/test/query_config.c b/programs/test/query_config.c index 05a953c63..1fb7384fd 100644 --- a/programs/test/query_config.c +++ b/programs/test/query_config.c @@ -2616,6 +2616,14 @@ int query_config( const char *config ) } #endif /* MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO */ +#if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) + if( strcmp( "MBEDTLS_PSA_HMAC_DRBG_MD_TYPE", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_HMAC_DRBG_MD_TYPE ); + return( 0 ); + } +#endif /* MBEDTLS_PSA_HMAC_DRBG_MD_TYPE */ + #if defined(MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT) if( strcmp( "MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT", config ) == 0 ) { From 68cc434c115e528552c21a7966379e774fdbb9c7 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 21:37:48 +0100 Subject: [PATCH 10/26] PSA support for HMAC_DRBG: changelog entry Signed-off-by: Gilles Peskine --- ChangeLog.d/psa-crypto-hmac-drbg.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 ChangeLog.d/psa-crypto-hmac-drbg.txt diff --git a/ChangeLog.d/psa-crypto-hmac-drbg.txt b/ChangeLog.d/psa-crypto-hmac-drbg.txt new file mode 100644 index 000000000..18a0d1b56 --- /dev/null +++ b/ChangeLog.d/psa-crypto-hmac-drbg.txt @@ -0,0 +1,5 @@ +Features + * The PSA crypto subsystem can now use HMAC_DRBG instead of CTR_DRBG. + CTR_DRBG is used by default if it is available, but you can override + this choice by setting MBEDTLS_PSA_HMAC_DRBG_MD_TYPE at compile time. + Fix #3354. From 14c332baeeadb5e32030778d0ed0cc08873ff05b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 14 Nov 2020 12:26:53 +0100 Subject: [PATCH 11/26] Fix a Doxygen warning We generate the Doxygen documentation in a configuration where part of config.h is excluded. See https://github.com/ARMmbed/mbedtls/issues/520 ``` /var/lib/build/include/mbedtls/config.h:3635: warning: documentation for unknown define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE found. ``` This is a more general issue and fixing it is out of scope of my current work. Therefore, just do something simple to silence Doxygen, and never mind that this causes the documentation of `MBEDTLS_PSA_HMAC_DRBG_MD_TYPE` to be omitted from the rendered documentation. We'll fix that when we fix all the configuration macros with a similar problem. Signed-off-by: Gilles Peskine --- include/mbedtls/config.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 5755df3b9..6f2d54156 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -3636,8 +3636,7 @@ //#define MBEDTLS_PARAM_FAILED( cond ) assert( cond ) /* PSA options */ -/** \def MBEDTLS_PSA_HMAC_DRBG_MD_TYPE - * +/** * Use HMAC_DRBG with the specified hash algorithm for HMAC_DRBG for the * PSA crypto subsystem. * From 89ffb28051c12f14d101437d4d1d245475ecb5f0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 18 Nov 2020 15:23:08 +0100 Subject: [PATCH 12/26] Fix option compatibility check Signed-off-by: Gilles Peskine --- include/mbedtls/check_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index 939ec6c65..accf51e32 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -606,7 +606,7 @@ #endif #if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \ - !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) #error "MBEDTLS_PSA_INJECT_ENTROPY is not compatible with MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG" #endif From b663a6014032d0c082cca50292cec115e20d3938 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 18 Nov 2020 15:27:37 +0100 Subject: [PATCH 13/26] Note the expectations on mbedtls_psa_external_get_random() Signed-off-by: Gilles Peskine --- include/mbedtls/config.h | 8 ++++++++ include/psa/crypto_extra.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 6f2d54156..6a41649e1 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1342,6 +1342,14 @@ * Make the PSA Crypto module use an external random generator provided * by a driver, instead of Mbed TLS's entropy and DRBG modules. * + * \note This random generator must deliver random numbers with cryptographic + * quality and high performance. It must supply unpredictable numbers + * with a uniform distribution. The implementation of this function + * is responsible for ensuring that the random generator is seeded + * with sufficient entropy. If you have a hardware TRNG which is slow + * or delivers non-uniform output, declare it as an entropy source + * with mbedtls_entropy_add_source() instead of enabling this option. + * * If you enable this option, you must supply configure the type * ::mbedtls_psa_external_random_context_t in psa/crypto_platform.h * and define a function called mbedtls_psa_external_get_random() diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 218a6bab2..0ebf140c3 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -660,6 +660,14 @@ mbedtls_ecp_group_id mbedtls_ecc_group_of_psa( psa_ecc_family_t curve, * this function replaces Mbed TLS's entropy and DRBG modules for all * random generation triggered via PSA crypto interfaces. * + * \note This random generator must deliver random numbers with cryptographic + * quality and high performance. It must supply unpredictable numbers + * with a uniform distribution. The implementation of this function + * is responsible for ensuring that the random generator is seeded + * with sufficient entropy. If you have a hardware TRNG which is slow + * or delivers non-uniform output, declare it as an entropy source + * with mbedtls_entropy_add_source() instead of enabling this option. + * * \param[in,out] context Pointer to the random generator context. * This is all-bits-zero on the first call * and preserved between successive calls. From c0963010c06a1c3b3ce7affa58b7d655432e6d31 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 18 Nov 2020 15:33:33 +0100 Subject: [PATCH 14/26] Document mbedtls_psa_external_random_context_t Note that the implementation here is just a sample, and integrators are expected to replace it with whatever they need. But do try to supply a definition that can be somewhat useful (give room for pointer+size). Signed-off-by: Gilles Peskine --- include/psa/crypto_platform.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/psa/crypto_platform.h b/include/psa/crypto_platform.h index a147a3eea..17ebd70e7 100644 --- a/include/psa/crypto_platform.h +++ b/include/psa/crypto_platform.h @@ -82,8 +82,17 @@ static inline int mbedtls_key_owner_id_equal( mbedtls_key_owner_id_t id1, #endif /* MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER */ #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/** The type of contexts passed to mbedtls_psa_external_get_random(). + * + * Mbed TLS initializes the context to all-bits-zero before calling + * mbedtls_psa_external_get_random() for the first time. + * + * The definition of this type in the Mbed TLS source code is for + * demonstration purposes. Implementers of mbedtls_psa_external_get_random() + * are expected to replace it with a custom definition. + */ typedef struct { - uint8_t opaque[32]; + uintptr_t opaque[2]; } mbedtls_psa_external_random_context_t; #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ From c109b37b07146261e2eaae6a483743ac257721e9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 23 Nov 2020 17:39:04 +0100 Subject: [PATCH 15/26] Test MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG Add two builds with MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG to all.sh: * full minus all DRBG (validates that PSA can work without any of the DRBG modules). * with MBEDTLS_USE_PSA_CRYPTO and no CTR_DRBG (validates that PSA can work without CTR_DRBG, and that it works for USE_PSA_CRYPTO). The goal is to exercise default/full, with/out USE_PSA_CRYPTO, and with/out deterministic ECDSA (which requires HMAC_DRBG). The choice of pairing is rather arbitrary. Signed-off-by: Gilles Peskine --- tests/scripts/all.sh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 30ec62f86..c53ce870f 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -941,6 +941,36 @@ component_test_no_hmac_drbg () { # so there's little value in running those lengthy tests here. } +component_test_psa_external_rng_no_drbg () { + msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG" + scripts/config.py full + scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + scripts/config.py unset MBEDTLS_CTR_DRBG_C + scripts/config.py unset MBEDTLS_HMAC_DRBG_C + scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG + scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG + make CFLAGS="$ASAN_CFLAGS -O2" LDFLAGS="$ASAN_CFLAGS" + + msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG" + make test + + # No ssl-opt.sh/compat.sh because they require CTR_DRBG. +} + +component_test_psa_external_rng_use_psa_crypto () { + msg "build: full + PSA_CRYPTO_EXTERNAL_RNG + USE_PSA_CRYPTO minus CTR_DRBG" + scripts/config.py full + scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + scripts/config.py set MBEDTLS_USE_PSA_CRYPTO + scripts/config.py unset MBEDTLS_CTR_DRBG_C + make CFLAGS="$ASAN_CFLAGS -O2" LDFLAGS="$ASAN_CFLAGS" + + msg "test: full + PSA_CRYPTO_EXTERNAL_RNG + USE_PSA_CRYPTO minus CTR_DRBG" + make test + + # No ssl-opt.sh/compat.sh because they require CTR_DRBG. +} + component_test_ecp_no_internal_rng () { msg "build: Default plus ECP_NO_INTERNAL_RNG minus DRBG modules" scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG From bee96c8db9fe118578b5677abdcebe90cdda7a89 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 23 Nov 2020 21:00:09 +0100 Subject: [PATCH 16/26] Explain the conditions for checking DRBG error codes Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 66c4f7de0..b3d7eb465 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -215,6 +215,8 @@ psa_status_t mbedtls_to_psa_error( int ret ) #if !( defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) || \ defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) ) + /* Only check CTR_DRBG error codes if underlying mbedtls_xxx + * functions are passed a CTR_DRBG instance. */ case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED: return( PSA_ERROR_INSUFFICIENT_ENTROPY ); case MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG: @@ -243,6 +245,8 @@ psa_status_t mbedtls_to_psa_error( int ret ) #if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) && \ defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) + /* Only check HMAC_DRBG error codes if underlying mbedtls_xxx + * functions are passed a HMAC_DRBG instance. */ case MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED: return( PSA_ERROR_INSUFFICIENT_ENTROPY ); case MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG: From b0a748e3400a45ce84245a14631c1638f2bf86d4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Nov 2020 12:01:54 +0100 Subject: [PATCH 17/26] Copyediting Signed-off-by: Gilles Peskine --- include/mbedtls/config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 6a41649e1..c5f65e178 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1350,7 +1350,7 @@ * or delivers non-uniform output, declare it as an entropy source * with mbedtls_entropy_add_source() instead of enabling this option. * - * If you enable this option, you must supply configure the type + * If you enable this option, you must configure the type * ::mbedtls_psa_external_random_context_t in psa/crypto_platform.h * and define a function called mbedtls_psa_external_get_random() * with the following prototype: @@ -3650,7 +3650,7 @@ * * If this option is unset: * - If CTR_DRBG is available, the PSA subsystem uses it rather than HMAC_DRBG. - * - Otherwise, the PSA subsystem uses one HMAC_DRBG with of + * - Otherwise, the PSA subsystem uses HMAC_DRBG with either * #MBEDTLS_MD_SHA512 or #MBEDTLS_MD_SHA256 based on availability and * on unspecified heuristics. */ From e995b9b3f00029dfdf212aaf54cc5716eed2eaec Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Nov 2020 12:08:00 +0100 Subject: [PATCH 18/26] Clarify statuses from mbedtls_psa_external_get_random Add and document PSA_ERROR_INSUFFICIENT_ENTROPY. Signed-off-by: Gilles Peskine --- include/psa/crypto_extra.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 0ebf140c3..59851bb1c 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -678,7 +678,20 @@ mbedtls_ecp_group_id mbedtls_ecc_group_of_psa( psa_ecc_family_t curve, * \param[out] output_length On success, set this value to \p output_size. * * \retval #PSA_SUCCESS + * Success. The output buffer contains \p output_size bytes of + * cryptographic-quality random data, and \c *output_length is + * set to \p output_size. + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY + * The random generator requires extra entropy and there is no + * way to obtain entropy under current environment conditions. + * This error should not happen under normal circumstances since + * this function is responsible for obtaining as much entropy as + * it needs. However implementations of this function may return + * #PSA_ERROR_INSUFFICIENT_ENTROPY if there is no way to obtain + * entropy without blocking indefinitely. * \retval #PSA_ERROR_HARDWARE_FAILURE + * A failure of the random generator hardware that isn't covered + * by #PSA_ERROR_INSUFFICIENT_ENTROPY. */ psa_status_t mbedtls_psa_external_get_random( mbedtls_psa_external_random_context_t *context, From 5894e8e7a4ba5ac85ad3ba48e99fd50d9977e48d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 14 Dec 2020 14:54:06 +0100 Subject: [PATCH 19/26] Replace mbedtls_psa_random_state( ... ) by MBEDTLS_PSA_RANDOM_STATE Hide the obtention of the pointer to the RNG state behind a macro. To make it possible to use this macro in a module other than psa_crypto.c, which will happen in the future, make sure that the definition of the macro does not reference internal variables of psa_crypto.c. For this purpose, in the internal-DRBG case, export a symbol containing the address of the DRBG state. When the RNG state is a pointer a DRBG state, just keep this pointer in a variable: there's no need to store a pointer to a larger structure. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 48 +++++++++++++++++++++---------------- library/psa_crypto_random.h | 47 ++++++++++++++++++------------------ 2 files changed, 50 insertions(+), 45 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index b3d7eb465..bb38475e8 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -124,6 +124,11 @@ typedef struct static psa_global_data_t global_data; +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state = + &global_data.rng.drbg; +#endif + #define GUARD_MODULE_INITIALIZED \ if( global_data.initialized == 0 ) \ return( PSA_ERROR_BAD_STATE ); @@ -884,7 +889,7 @@ static psa_status_t psa_export_ecp_key( psa_key_type_t type, /* Calculate the public key */ status = mbedtls_to_psa_error( mbedtls_ecp_mul( &ecp->grp, &ecp->Q, &ecp->d, &ecp->grp.G, - mbedtls_psa_get_random, mbedtls_psa_random_state( &global_data.rng ) ) ); + mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE ) ); if( status != PSA_SUCCESS ) return( status ); } @@ -3667,7 +3672,7 @@ static psa_status_t psa_rsa_sign( mbedtls_rsa_context *rsa, MBEDTLS_MD_NONE ); ret = mbedtls_rsa_pkcs1_sign( rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, MBEDTLS_RSA_PRIVATE, md_alg, (unsigned int) hash_length, @@ -3682,7 +3687,7 @@ static psa_status_t psa_rsa_sign( mbedtls_rsa_context *rsa, mbedtls_rsa_set_padding( rsa, MBEDTLS_RSA_PKCS_V21, md_alg ); ret = mbedtls_rsa_rsassa_pss_sign( rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_NONE, (unsigned int) hash_length, @@ -3725,7 +3730,7 @@ static psa_status_t psa_rsa_verify( mbedtls_rsa_context *rsa, MBEDTLS_MD_NONE ); ret = mbedtls_rsa_pkcs1_verify( rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, MBEDTLS_RSA_PUBLIC, md_alg, (unsigned int) hash_length, @@ -3740,7 +3745,7 @@ static psa_status_t psa_rsa_verify( mbedtls_rsa_context *rsa, mbedtls_rsa_set_padding( rsa, MBEDTLS_RSA_PKCS_V21, md_alg ); ret = mbedtls_rsa_rsassa_pss_verify( rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_NONE, (unsigned int) hash_length, @@ -3798,7 +3803,7 @@ static psa_status_t psa_ecdsa_sign( mbedtls_ecp_keypair *ecp, &ecp->d, hash, hash_length, md_alg, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ) ) ); + MBEDTLS_PSA_RANDOM_STATE ) ); } else #endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */ @@ -3807,7 +3812,7 @@ static psa_status_t psa_ecdsa_sign( mbedtls_ecp_keypair *ecp, MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ecp->grp, &r, &s, &ecp->d, hash, hash_length, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ) ) ); + MBEDTLS_PSA_RANDOM_STATE ) ); } MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &r, @@ -3852,7 +3857,7 @@ static psa_status_t psa_ecdsa_verify( mbedtls_ecp_keypair *ecp, { MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ecp->grp, &ecp->Q, &ecp->d, &ecp->grp.G, - mbedtls_psa_get_random, mbedtls_psa_random_state( &global_data.rng ) ) ); + mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE ) ); } ret = mbedtls_ecdsa_verify( &ecp->grp, hash, hash_length, @@ -4153,7 +4158,7 @@ psa_status_t psa_asymmetric_encrypt( mbedtls_svc_key_id_t key, status = mbedtls_to_psa_error( mbedtls_rsa_pkcs1_encrypt( rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, MBEDTLS_RSA_PUBLIC, input_length, input, @@ -4168,7 +4173,7 @@ psa_status_t psa_asymmetric_encrypt( mbedtls_svc_key_id_t key, status = mbedtls_to_psa_error( mbedtls_rsa_rsaes_oaep_encrypt( rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, MBEDTLS_RSA_PUBLIC, salt, salt_length, input_length, @@ -4260,7 +4265,7 @@ psa_status_t psa_asymmetric_decrypt( mbedtls_svc_key_id_t key, status = mbedtls_to_psa_error( mbedtls_rsa_pkcs1_decrypt( rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, MBEDTLS_RSA_PRIVATE, output_length, input, @@ -4276,7 +4281,7 @@ psa_status_t psa_asymmetric_decrypt( mbedtls_svc_key_id_t key, status = mbedtls_to_psa_error( mbedtls_rsa_rsaes_oaep_decrypt( rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, MBEDTLS_RSA_PRIVATE, salt, salt_length, output_length, @@ -4510,7 +4515,7 @@ psa_status_t psa_cipher_generate_iv( psa_cipher_operation_t *operation, status = PSA_ERROR_BUFFER_TOO_SMALL; goto exit; } - ret = mbedtls_psa_get_random( mbedtls_psa_random_state( &global_data.rng ), + ret = mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, iv, operation->iv_size ); if( ret != 0 ) { @@ -6127,7 +6132,7 @@ static psa_status_t psa_key_agreement_ecdh( const uint8_t *peer_key, shared_secret_length, shared_secret, shared_secret_size, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ) ) ); + MBEDTLS_PSA_RANDOM_STATE ) ); if( status != PSA_SUCCESS ) goto exit; if( PSA_BITS_TO_BYTES( bits ) != *shared_secret_length ) @@ -6336,7 +6341,7 @@ static void mbedtls_psa_random_init( mbedtls_psa_random_context_t *rng ) MBEDTLS_ENTROPY_SOURCE_STRONG ); #endif - mbedtls_psa_drbg_init( mbedtls_psa_random_state( rng ) ); + mbedtls_psa_drbg_init( MBEDTLS_PSA_RANDOM_STATE ); #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } @@ -6347,7 +6352,7 @@ static void mbedtls_psa_random_free( mbedtls_psa_random_context_t *rng ) #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) memset( rng, 0, sizeof( *rng ) ); #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ - mbedtls_psa_drbg_free( mbedtls_psa_random_state( rng ) ); + mbedtls_psa_drbg_free( MBEDTLS_PSA_RANDOM_STATE ); rng->entropy_free( &rng->entropy ); #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } @@ -6362,7 +6367,8 @@ static psa_status_t mbedtls_psa_random_seed( mbedtls_psa_random_context_t *rng ) return( PSA_SUCCESS ); #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ const unsigned char drbg_seed[] = "PSA"; - int ret = mbedtls_psa_drbg_seed( rng, drbg_seed, sizeof( drbg_seed ) - 1 ); + int ret = mbedtls_psa_drbg_seed( &rng->entropy, + drbg_seed, sizeof( drbg_seed ) - 1 ); return mbedtls_to_psa_error( ret ); #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } @@ -6393,7 +6399,7 @@ psa_status_t psa_generate_random( uint8_t *output, while( output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ) { ret = mbedtls_psa_get_random( - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, output, MBEDTLS_PSA_RANDOM_MAX_REQUEST ); if( ret != 0 ) return( mbedtls_to_psa_error( ret ) ); @@ -6401,7 +6407,7 @@ psa_status_t psa_generate_random( uint8_t *output, output_size -= MBEDTLS_PSA_RANDOM_MAX_REQUEST; } - ret = mbedtls_psa_get_random( mbedtls_psa_random_state( &global_data.rng ), + ret = mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, output, output_size ); return( mbedtls_to_psa_error( ret ) ); #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ @@ -6510,7 +6516,7 @@ static psa_status_t psa_generate_key_internal( mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); ret = mbedtls_rsa_gen_key( &rsa, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ), + MBEDTLS_PSA_RANDOM_STATE, (unsigned int) bits, exponent ); if( ret != 0 ) @@ -6556,7 +6562,7 @@ static psa_status_t psa_generate_key_internal( mbedtls_ecp_keypair_init( &ecp ); ret = mbedtls_ecp_gen_key( grp_id, &ecp, mbedtls_psa_get_random, - mbedtls_psa_random_state( &global_data.rng ) ); + MBEDTLS_PSA_RANDOM_STATE ); if( ret != 0 ) { mbedtls_ecp_keypair_free( &ecp ); diff --git a/library/psa_crypto_random.h b/library/psa_crypto_random.h index 0f13c1392..cc1222a39 100644 --- a/library/psa_crypto_random.h +++ b/library/psa_crypto_random.h @@ -42,11 +42,7 @@ static inline int mbedtls_psa_get_random( void *p_rng, return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); } -static inline void *mbedtls_psa_random_state( mbedtls_psa_random_context_t *rng ) -{ - (void) rng; - return( NULL ); -} +#define MBEDTLS_PSA_RANDOM_STATE NULL #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ @@ -135,13 +131,11 @@ typedef struct /** Return random data. * * This function is suitable as the \p f_rng parameter to Mbed TLS functions - * that require a random generator. Use mbedtls_psa_random_state() to + * that require a random generator. Use #MBEDTLS_PSA_RANDOM_STATE to * obtain the \p p_rng parameter. * * \param p_rng The DRBG context. This must be - * mbedtls_psa_random_state( \c rng ) - * where \c rng is a pointer to a - * ::mbedtls_psa_random_context_t structure. + * #MBEDTLS_PSA_RANDOM_STATE. * \param output The buffer to fill. * \param output_len The length of the buffer in bytes. * It must be at most #MBEDTLS_PSA_RANDOM_MAX_REQUEST. @@ -170,21 +164,26 @@ static inline int mbedtls_psa_get_random( void *p_rng, #define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST #endif -/** Retrieve the DRBG state from the PSA RNG state. +/** A pointer to the PSA DRBG state. * - * \param rng Pointer to the PSA random generator state. - * - * \return The DRBG state (\c p_rng argument ). + * This variable is only intended to be used through the macro + * #MBEDTLS_PSA_RANDOM_STATE. */ -static inline mbedtls_psa_drbg_context_t *mbedtls_psa_random_state( - mbedtls_psa_random_context_t *rng ) -{ - return( &rng->drbg ); -} +extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state; + +/** A pointer to the PSA DRBG state. + * + * This macro expnds to an expression that is suitable as the \c p_rng + * parameter to pass to mbedtls_psa_get_random(). + * + * This macro exists in all configurations where the psa_crypto module is + * enabled. Its expansion depends on the configuration. + */ +#define MBEDTLS_PSA_RANDOM_STATE mbedtls_psa_random_state /** Seed the PSA DRBG. * - * \param rng DRBG context to be seeded. + * \param entropy An entropy context to read the seed from. * \param custom The personalization string. * This can be \c NULL, in which case the personalization * string is empty regardless of the value of \p len. @@ -194,21 +193,21 @@ static inline mbedtls_psa_drbg_context_t *mbedtls_psa_random_state( * \return An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure. */ static inline int mbedtls_psa_drbg_seed( - mbedtls_psa_random_context_t *rng, + mbedtls_entropy_context *entropy, const unsigned char *custom, size_t len ) { #if defined(MBEDTLS_CTR_DRBG_C) - return( mbedtls_ctr_drbg_seed( mbedtls_psa_random_state( rng ), + return( mbedtls_ctr_drbg_seed( MBEDTLS_PSA_RANDOM_STATE, mbedtls_entropy_func, - &rng->entropy, + entropy, custom, len ) ); #elif defined(MBEDTLS_HMAC_DRBG_C) const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_PSA_HMAC_DRBG_MD_TYPE ); - return( mbedtls_hmac_drbg_seed( mbedtls_psa_random_state( rng ), + return( mbedtls_hmac_drbg_seed( MBEDTLS_PSA_RANDOM_STATE, md_info, mbedtls_entropy_func, - &rng->entropy, + entropy, custom, len ) ); #endif } From 8814fc4a348db5c66f04fafc67bccb4d0648e8c5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 14 Dec 2020 15:33:44 +0100 Subject: [PATCH 20/26] Make mbedtls_psa_get_random more usable outside psa_crypto.c In the external RNG case, don't make mbedtls_psa_get_random() a static inline function: this would likely result in identical instances of this function in every module that uses it. Instead, make it a single function with external linkage. In the non-external case, instead of a trivial wrapper function, make mbedtls_psa_get_random a constant pointer to whichever DRBG function is being used. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 18 ++++++++++++++++++ library/psa_crypto_random.h | 27 +++++++++------------------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index bb38475e8..288e0717e 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -6413,6 +6413,24 @@ psa_status_t psa_generate_random( uint8_t *output, #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } +/* Wrapper function allowing the classic API to use the PSA RNG. + * In the non-external case, mbedtls_psa_get_random is defined + * as a constant function pointer in psa_crypto_random.h. + */ +#if defined (MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +int mbedtls_psa_get_random( void *p_rng, + unsigned char *output, + size_t output_size ) +{ + (void) p_rng; + psa_status_t status = psa_generate_random( output, output_size ); + if( status == PSA_SUCCESS ) + return( 0 ); + else + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); +} +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + #if defined(MBEDTLS_PSA_INJECT_ENTROPY) #include "mbedtls/entropy_poll.h" diff --git a/library/psa_crypto_random.h b/library/psa_crypto_random.h index cc1222a39..2482d6bc2 100644 --- a/library/psa_crypto_random.h +++ b/library/psa_crypto_random.h @@ -30,17 +30,9 @@ typedef mbedtls_psa_external_random_context_t mbedtls_psa_random_context_t; -static inline int mbedtls_psa_get_random( void *p_rng, - unsigned char *output, - size_t output_size ) -{ - (void) p_rng; - psa_status_t status = psa_generate_random( output, output_size ); - if( status == PSA_SUCCESS ) - return( 0 ); - else - return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); -} +int mbedtls_psa_get_random( void *p_rng, + unsigned char *output, + size_t output_size ); #define MBEDTLS_PSA_RANDOM_STATE NULL @@ -144,16 +136,15 @@ typedef struct * \return \c MBEDTLS_ERR_xxx_DRBG_xxx or * \c MBEDTLS_ERR_PLATFORM_xxx on failure. */ -static inline int mbedtls_psa_get_random( void *p_rng, - unsigned char *output, - size_t output_len ) -{ #if defined(MBEDTLS_CTR_DRBG_C) - return( mbedtls_ctr_drbg_random( p_rng, output, output_len ) ); +static int ( *const mbedtls_psa_get_random )( + void *p_rng, unsigned char *output, size_t output_size ) = + mbedtls_ctr_drbg_random; #elif defined(MBEDTLS_HMAC_DRBG_C) - return( mbedtls_hmac_drbg_random( p_rng, output, output_len ) ); +static int ( *const mbedtls_psa_get_random )( + void *p_rng, unsigned char *output, size_t output_size ) = + mbedtls_hmac_drbg_random; #endif -} /** The maximum number of bytes that mbedtls_psa_get_random() is expected to * return. From b2b64d36421a081f30c34db3140b3845874a78d0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 14 Dec 2020 16:43:58 +0100 Subject: [PATCH 21/26] Rename psa_crypto_random.h to psa_crypto_random_impl.h Make it clear that this is an abstraction of the random generator abstraction, and not an abstraction of the PSA random generator. mbedtls_psa_get_random and MBEDTLS_PSA_RANDOM_STATE are public-facing definitions and will be moved in a subsequent commit. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 4 ++-- .../{psa_crypto_random.h => psa_crypto_random_impl.h} | 10 +++++----- tests/suites/test_suite_psa_crypto_init.function | 2 +- visualc/VS2010/mbedTLS.vcxproj | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) rename library/{psa_crypto_random.h => psa_crypto_random_impl.h} (96%) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 288e0717e..79b0633fa 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -40,7 +40,7 @@ * stored keys. */ #include "psa_crypto_storage.h" -#include "psa_crypto_random.h" +#include "psa_crypto_random_impl.h" #include #include @@ -6415,7 +6415,7 @@ psa_status_t psa_generate_random( uint8_t *output, /* Wrapper function allowing the classic API to use the PSA RNG. * In the non-external case, mbedtls_psa_get_random is defined - * as a constant function pointer in psa_crypto_random.h. + * as a constant function pointer in psa_crypto_random_impl.h. */ #if defined (MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) int mbedtls_psa_get_random( void *p_rng, diff --git a/library/psa_crypto_random.h b/library/psa_crypto_random_impl.h similarity index 96% rename from library/psa_crypto_random.h rename to library/psa_crypto_random_impl.h index 2482d6bc2..6b445c62f 100644 --- a/library/psa_crypto_random.h +++ b/library/psa_crypto_random_impl.h @@ -1,6 +1,6 @@ -/** \file psa_crypto_random.h +/** \file psa_crypto_random_impl.h * - * \brief PSA crypto random generator abstraction. + * \brief PSA crypto random generator implementation abstraction. */ /* * Copyright The Mbed TLS Contributors @@ -19,8 +19,8 @@ * limitations under the License. */ -#ifndef PSA_CRYPTO_RANDOM_H -#define PSA_CRYPTO_RANDOM_H +#ifndef PSA_CRYPTO_RANDOM_IMPL_H +#define PSA_CRYPTO_RANDOM_IMPL_H #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) @@ -205,4 +205,4 @@ static inline int mbedtls_psa_drbg_seed( #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ -#endif /* PSA_CRYPTO_RANDOM_H */ +#endif /* PSA_CRYPTO_RANDOM_IMPL_H */ diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index 16e44c7af..e6097bb27 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -11,7 +11,7 @@ #define ENTROPY_MIN_NV_SEED_SIZE \ MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) -#include "psa_crypto_random.h" +#include "psa_crypto_random_impl.h" #if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) /* PSA crypto uses the HMAC_DRBG module. It reads from the entropy source twice: * once for the initial entropy and once for a nonce. The nonce length is diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 98b8d66f6..ee6d28dc0 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -251,7 +251,7 @@ - + From b3cd9633f4b51719c2eb33a7fdc0cb208fd88c73 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 14 Dec 2020 19:54:24 +0100 Subject: [PATCH 22/26] Pacify check-names.sh Signed-off-by: Gilles Peskine --- library/psa_crypto_random_impl.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h index 6b445c62f..8c745dae2 100644 --- a/library/psa_crypto_random_impl.h +++ b/library/psa_crypto_random_impl.h @@ -120,6 +120,13 @@ typedef struct mbedtls_psa_drbg_context_t drbg; } mbedtls_psa_random_context_t; +/* The type of an Mbed TLS random generator function. This should be + * part of the public API instead of repeating the type everywhere. + * For the time being, declare it here. Declaring a type is necessary + * to define mbedtls_psa_get_random as a variable of a function pointer + * type without incurring the wrath of check-names.sh. */ +typedef int mbedtls_f_rng_t( void *p_rng, unsigned char *output, size_t output_size ); + /** Return random data. * * This function is suitable as the \p f_rng parameter to Mbed TLS functions @@ -137,13 +144,9 @@ typedef struct * \c MBEDTLS_ERR_PLATFORM_xxx on failure. */ #if defined(MBEDTLS_CTR_DRBG_C) -static int ( *const mbedtls_psa_get_random )( - void *p_rng, unsigned char *output, size_t output_size ) = - mbedtls_ctr_drbg_random; +static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random; #elif defined(MBEDTLS_HMAC_DRBG_C) -static int ( *const mbedtls_psa_get_random )( - void *p_rng, unsigned char *output, size_t output_size ) = - mbedtls_hmac_drbg_random; +static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random; #endif /** The maximum number of bytes that mbedtls_psa_get_random() is expected to From 88fa5c463e916724b052657fdbc04fb208ea1060 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 4 Jan 2021 21:00:53 +0100 Subject: [PATCH 23/26] Minor documentation improvements Signed-off-by: Gilles Peskine --- include/psa/crypto_platform.h | 2 +- library/psa_crypto_random_impl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/psa/crypto_platform.h b/include/psa/crypto_platform.h index 17ebd70e7..8acf22c7f 100644 --- a/include/psa/crypto_platform.h +++ b/include/psa/crypto_platform.h @@ -82,7 +82,7 @@ static inline int mbedtls_key_owner_id_equal( mbedtls_key_owner_id_t id1, #endif /* MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER */ #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) -/** The type of contexts passed to mbedtls_psa_external_get_random(). +/** The type of the context passed to mbedtls_psa_external_get_random(). * * Mbed TLS initializes the context to all-bits-zero before calling * mbedtls_psa_external_get_random() for the first time. diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h index 8c745dae2..07e1d1031 100644 --- a/library/psa_crypto_random_impl.h +++ b/library/psa_crypto_random_impl.h @@ -167,7 +167,7 @@ extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state; /** A pointer to the PSA DRBG state. * - * This macro expnds to an expression that is suitable as the \c p_rng + * This macro expands to an expression that is suitable as the \c p_rng * parameter to pass to mbedtls_psa_get_random(). * * This macro exists in all configurations where the psa_crypto module is From 71ddab91548fbb610764f25f26ed22881bad6ec2 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 4 Jan 2021 21:01:07 +0100 Subject: [PATCH 24/26] Simplify the chunk loop in psa_generate_random Make the code slightly more readable and slightly smaller. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 79b0633fa..4d32da7da 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -6394,21 +6394,18 @@ psa_status_t psa_generate_random( uint8_t *output, #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - - while( output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ) + int ret = 0; + while( output_size > 0 ) { - ret = mbedtls_psa_get_random( - MBEDTLS_PSA_RANDOM_STATE, - output, MBEDTLS_PSA_RANDOM_MAX_REQUEST ); - if( ret != 0 ) - return( mbedtls_to_psa_error( ret ) ); - output += MBEDTLS_PSA_RANDOM_MAX_REQUEST; - output_size -= MBEDTLS_PSA_RANDOM_MAX_REQUEST; + size_t request_size = + ( output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ? + MBEDTLS_PSA_RANDOM_MAX_REQUEST : + output_size ); + ret = mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, + output, request_size ); + output_size -= request_size; + output += request_size; } - - ret = mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, - output, output_size ); return( mbedtls_to_psa_error( ret ) ); #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } From 0c59ba88cbad9fa54e15a35b914c5d6ad3632f6f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 5 Jan 2021 14:10:59 +0100 Subject: [PATCH 25/26] Fix the error detection in psa_generate_random If a call to mbedtls_psa_get_random other than the last one failed, this went undetected. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 4d32da7da..c82fecb08 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -6394,19 +6394,20 @@ psa_status_t psa_generate_random( uint8_t *output, #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ - int ret = 0; while( output_size > 0 ) { size_t request_size = ( output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ? MBEDTLS_PSA_RANDOM_MAX_REQUEST : output_size ); - ret = mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, - output, request_size ); + int ret = mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, + output, request_size ); + if( ret != 0 ) + return( mbedtls_to_psa_error( ret ) ); output_size -= request_size; output += request_size; } - return( mbedtls_to_psa_error( ret ) ); + return( PSA_SUCCESS ); #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } From 9c3e0602535dec9cba6f7d533682fc7f07c17ced Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 5 Jan 2021 16:03:55 +0100 Subject: [PATCH 26/26] Explain the design of mbedtls_psa_get_random better Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 18 ++++++++++++++++-- library/psa_crypto_random_impl.h | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index c82fecb08..896da3fe2 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -6412,14 +6412,28 @@ psa_status_t psa_generate_random( uint8_t *output, } /* Wrapper function allowing the classic API to use the PSA RNG. - * In the non-external case, mbedtls_psa_get_random is defined - * as a constant function pointer in psa_crypto_random_impl.h. + * + * `mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE, ...)` calls + * `psa_generate_random(...)`. The state parameter is ignored since the + * PSA API doesn't support passing an explicit state. + * + * In the non-external case, psa_generate_random() calls an + * `mbedtls_xxx_drbg_random` function which has exactly the same signature + * and semantics as mbedtls_psa_get_random(). As an optimization, + * instead of doing this back-and-forth between the PSA API and the + * classic API, psa_crypto_random_impl.h defines `mbedtls_psa_get_random` + * as a constant function pointer to `mbedtls_xxx_drbg_random`. */ #if defined (MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) int mbedtls_psa_get_random( void *p_rng, unsigned char *output, size_t output_size ) { + /* This function takes a pointer to the RNG state because that's what + * classic mbedtls functions using an RNG expect. The PSA RNG manages + * its own state internally and doesn't let the caller access that state. + * So we just ignore the state parameter, and in practice we'll pass + * NULL. */ (void) p_rng; psa_status_t status = psa_generate_random( output, output_size ); if( status == PSA_SUCCESS ) diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h index 07e1d1031..1232186c9 100644 --- a/library/psa_crypto_random_impl.h +++ b/library/psa_crypto_random_impl.h @@ -30,10 +30,12 @@ typedef mbedtls_psa_external_random_context_t mbedtls_psa_random_context_t; +/* Trivial wrapper around psa_generate_random(). */ int mbedtls_psa_get_random( void *p_rng, unsigned char *output, size_t output_size ); +/* The PSA RNG API doesn't need any externally maintained state. */ #define MBEDTLS_PSA_RANDOM_STATE NULL #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ @@ -163,6 +165,8 @@ static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random; * This variable is only intended to be used through the macro * #MBEDTLS_PSA_RANDOM_STATE. */ +/* psa_crypto.c sets this variable to a pointer to the DRBG state in the + * global PSA crypto state. */ extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state; /** A pointer to the PSA DRBG state.