diff --git a/ChangeLog.d/mbedtls_psa_get_random.txt b/ChangeLog.d/mbedtls_psa_get_random.txt new file mode 100644 index 000000000..f6e6b0966 --- /dev/null +++ b/ChangeLog.d/mbedtls_psa_get_random.txt @@ -0,0 +1,9 @@ +Features + * Partial implementation of the PSA crypto driver interface: Mbed TLS can + now use an external random generator instead of the library's own + entropy collection and DRBG code. Enable MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + and see the documentation of mbedtls_psa_external_get_random() for details. + * Applications using both mbedtls_xxx and psa_xxx functions (for example, + applications using TLS and MBEDTLS_USE_PSA_CRYPTO) can now use the PSA + random generator with mbedtls_xxx functions. See the documentation of + mbedtls_psa_get_random() for details. diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h index 0b8a216ac..f18857cf5 100644 --- a/include/mbedtls/psa_util.h +++ b/include/mbedtls/psa_util.h @@ -419,4 +419,90 @@ static inline int mbedtls_psa_tls_ecpoint_to_psa_ec( unsigned char const *src, #endif /* MBEDTLS_USE_PSA_CRYPTO */ +/* Expose whatever RNG the PSA subsystem uses to applications using the + * mbedtls_xxx API. The declarations and definitions here need to be + * consistent with the implementation in library/psa_crypto_random_impl.h. + * See that file for implementation documentation. */ +#if defined(MBEDTLS_PSA_CRYPTO_C) + +/* The type of a `f_rng` random generator function that many library functions + * take. + * + * This type name is not part of the Mbed TLS stable API. It may be renamed + * or moved without warning. + */ +typedef int mbedtls_f_rng_t( void *p_rng, unsigned char *output, size_t output_size ); + +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + +/** The random generator function for the PSA subsystem. + * + * This function is suitable as the `f_rng` random generator function + * parameter of many `mbedtls_xxx` functions. Use #MBEDTLS_PSA_RANDOM_STATE + * to obtain the \p p_rng parameter. + * + * The implementation of this function depends on the configuration of the + * library. + * + * \note Depending on the configuration, this may be a function or + * a pointer to a function. + * + * \note This function may only be used if the PSA crypto subsystem is active. + * This means that you must call psa_crypto_init() before any call to + * this function, and you must not call this function after calling + * mbedtls_psa_crypto_free(). + * + * \param p_rng The random generator context. This must be + * #MBEDTLS_PSA_RANDOM_STATE. No other state is + * supported. + * \param output The buffer to fill. It must have room for + * \c output_size bytes. + * \param output_size The number of bytes to write to \p output. + * This function may fail if \p output_size is too + * large. It is guaranteed to accept any output size + * requested by Mbed TLS library functions. The + * maximum request size depends on the library + * configuration. + * + * \return \c 0 on success. + * \return An `MBEDTLS_ERR_ENTROPY_xxx`, + * `MBEDTLS_ERR_PLATFORM_xxx, + * `MBEDTLS_ERR_CTR_DRBG_xxx` or + * `MBEDTLS_ERR_HMAC_DRBG_xxx` on error. + */ +int mbedtls_psa_get_random( void *p_rng, + unsigned char *output, + size_t output_size ); + +/** The random generator state for the PSA subsystem. + * + * This macro expands to an expression which is suitable as the `p_rng` + * random generator state parameter of many `mbedtls_xxx` functions. + * It must be used in combination with the random generator function + * mbedtls_psa_get_random(). + * + * The implementation of this macro depends on the configuration of the + * library. Do not make any assumption on its nature. + */ +#define MBEDTLS_PSA_RANDOM_STATE NULL + +#else /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ + +#if defined(MBEDTLS_CTR_DRBG_C) +#include "mbedtls/ctr_drbg.h" +typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t; +static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random; +#elif defined(MBEDTLS_HMAC_DRBG_C) +#include "mbedtls/hmac_drbg.h" +typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t; +static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random; +#endif +extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state; + +#define MBEDTLS_PSA_RANDOM_STATE mbedtls_psa_random_state + +#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ + #endif /* MBEDTLS_PSA_UTIL_H */ diff --git a/library/entropy_poll.c b/library/entropy_poll.c index 84b70fe6f..2c1e0937b 100644 --- a/library/entropy_poll.c +++ b/library/entropy_poll.c @@ -220,13 +220,13 @@ int mbedtls_null_entropy_poll( void *data, { ((void) data); ((void) output); - *olen = 0; + *olen = 0; if( len < sizeof(unsigned char) ) return( 0 ); + output[0] = 0; *olen = sizeof(unsigned char); - return( 0 ); } #endif diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h index 1232186c9..3c4c09a28 100644 --- a/library/psa_crypto_random_impl.h +++ b/library/psa_crypto_random_impl.h @@ -1,6 +1,14 @@ /** \file psa_crypto_random_impl.h * * \brief PSA crypto random generator implementation abstraction. + * + * The definitions here need to be consistent with the declarations + * in include/mbedtls/psa_util.h. This file contains some redundant + * declarations to increase the chance that a compiler will detect + * inconsistencies if one file is changed without updating the other, + * but not all potential inconsistencies can be enforced, so make sure + * to check the public declarations and contracts in + * include/mbedtls/psa_util.h if you modify this file. */ /* * Copyright The Mbed TLS Contributors @@ -22,6 +30,8 @@ #ifndef PSA_CRYPTO_RANDOM_IMPL_H #define PSA_CRYPTO_RANDOM_IMPL_H +#include + #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) #include @@ -75,14 +85,6 @@ int mbedtls_psa_get_random( void *p_rng, #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. * * \param p_rng Pointer to the Mbed TLS DRBG state. @@ -122,33 +124,18 @@ 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 - * 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. - * \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. - * - * \retval \c 0 on success. - * \return \c MBEDTLS_ERR_xxx_DRBG_xxx or - * \c MBEDTLS_ERR_PLATFORM_xxx on failure. +/* Defined in include/mbedtls/psa_util.h so that it's visible to + * application code. The declaration here is redundant, but included + * as a safety net to make it more likely that a future change that + * accidentally causes the implementation to diverge from the interface + * will be noticed. */ +/* Do not include the declaration under MSVC because it doesn't accept it + * ("error C2370: 'mbedtls_psa_get_random' : redefinition; different storage class"). + * Observed with Visual Studio 2013. A known bug apparently: + * https://stackoverflow.com/questions/8146541/duplicate-external-static-declarations-not-allowed-in-visual-studio */ -#if defined(MBEDTLS_CTR_DRBG_C) -static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random; -#elif defined(MBEDTLS_HMAC_DRBG_C) -static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random; +#if !defined(_MSC_VER) +static mbedtls_f_rng_t *const mbedtls_psa_get_random; #endif /** The maximum number of bytes that mbedtls_psa_get_random() is expected to @@ -167,6 +154,9 @@ static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random; */ /* psa_crypto.c sets this variable to a pointer to the DRBG state in the * global PSA crypto state. */ +/* The type `mbedtls_psa_drbg_context_t` is defined in + * include/mbedtls/psa_util.h so that `mbedtls_psa_random_state` can be + * declared there and be visible to application code. */ extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state; /** A pointer to the PSA DRBG state. diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 876555d93..4875b785c 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -703,7 +703,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_USE_PSA_CRYPTO) psa_key_id_t key_slot = 0; /* invalid key slot */ #endif -#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ char *p, *q; const int *list; #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) @@ -760,10 +760,10 @@ int main( int argc, char *argv[] ) ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED; goto exit; } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) mbedtls_test_enable_insecure_external_rng( ); #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ -#endif /* MBEDTLS_USE_PSA_CRYPTO */ if( argc == 0 ) { @@ -1536,7 +1536,8 @@ int main( int argc, char *argv[] ) mbedtls_printf( "\n . Seeding the random number generator..." ); fflush( stdout ); - if( rng_seed( &rng, opt.reproducible, pers ) != 0 ) + ret = rng_seed( &rng, opt.reproducible, pers ); + if( ret != 0 ) goto exit; mbedtls_printf( " ok\n" ); @@ -1881,7 +1882,7 @@ int main( int argc, char *argv[] ) #else fprintf( stderr, "Warning: reproducible option used without constant time\n" ); #endif -#endif +#endif /* MBEDTLS_HAVE_TIME */ } mbedtls_ssl_conf_rng( &conf, rng_get, &rng ); mbedtls_ssl_conf_dbg( &conf, my_debug, stdout ); @@ -1927,7 +1928,7 @@ int main( int argc, char *argv[] ) goto exit; } } -#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_ECP_C) if( opt.curves != NULL && @@ -2999,19 +3000,7 @@ exit: #if defined(MBEDTLS_USE_PSA_CRYPTO) psa_destroy_key( key_slot ); #endif -#endif - mbedtls_ssl_session_free( &saved_session ); - mbedtls_ssl_free( &ssl ); - mbedtls_ssl_config_free( &conf ); - rng_free( &rng ); - if( session_data != NULL ) - mbedtls_platform_zeroize( session_data, session_data_len ); - mbedtls_free( session_data ); -#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) - if( context_buf != NULL ) - mbedtls_platform_zeroize( context_buf, context_buf_len ); - mbedtls_free( context_buf ); -#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) && \ defined(MBEDTLS_USE_PSA_CRYPTO) @@ -3034,12 +3023,25 @@ exit: #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED && MBEDTLS_USE_PSA_CRYPTO */ + mbedtls_ssl_session_free( &saved_session ); + mbedtls_ssl_free( &ssl ); + mbedtls_ssl_config_free( &conf ); + rng_free( &rng ); + if( session_data != NULL ) + mbedtls_platform_zeroize( session_data, session_data_len ); + mbedtls_free( session_data ); +#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) + if( context_buf != NULL ) + mbedtls_platform_zeroize( context_buf, context_buf_len ); + mbedtls_free( context_buf ); +#endif + #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) #if defined(MBEDTLS_MEMORY_DEBUG) mbedtls_memory_buffer_alloc_status(); #endif mbedtls_memory_buffer_alloc_free(); -#endif +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ #if defined(_WIN32) if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE ) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 57c053ce9..08317b5b0 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -1412,10 +1412,10 @@ int main( int argc, char *argv[] ) ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED; goto exit; } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) mbedtls_test_enable_insecure_external_rng( ); #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ -#endif /* MBEDTLS_USE_PSA_CRYPTO */ #if !defined(_WIN32) /* Abort cleanly on SIGTERM and SIGINT */ @@ -2295,7 +2295,8 @@ int main( int argc, char *argv[] ) mbedtls_printf( "\n . Seeding the random number generator..." ); fflush( stdout ); - if( rng_seed( &rng, opt.reproducible, pers ) != 0 ) + ret = rng_seed( &rng, opt.reproducible, pers ); + if( ret != 0 ) goto exit; mbedtls_printf( " ok\n" ); @@ -2683,7 +2684,7 @@ int main( int argc, char *argv[] ) #else fprintf( stderr, "Warning: reproducible option used without constant time\n" ); #endif -#endif +#endif /* MBEDTLS_HAVE_TIME */ } mbedtls_ssl_conf_rng( &conf, rng_get, &rng ); mbedtls_ssl_conf_dbg( &conf, my_debug, stdout ); @@ -4002,7 +4003,7 @@ exit: mbedtls_memory_buffer_alloc_status(); #endif mbedtls_memory_buffer_alloc_free(); -#endif +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE ) { diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c index 46cea144c..6636e9e1a 100644 --- a/programs/ssl/ssl_test_lib.c +++ b/programs/ssl/ssl_test_lib.c @@ -46,6 +46,7 @@ mbedtls_time_t dummy_constant_time( mbedtls_time_t* time ) return 0x5af2a056; } +#if !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) static int dummy_entropy( void *data, unsigned char *output, size_t len ) { size_t i; @@ -60,9 +61,15 @@ static int dummy_entropy( void *data, unsigned char *output, size_t len ) } return( ret ); } +#endif void rng_init( rng_context_t *rng ) { +#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) + (void) rng; + psa_crypto_init( ); +#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ + #if defined(MBEDTLS_CTR_DRBG_C) mbedtls_ctr_drbg_init( &rng->drbg ); #elif defined(MBEDTLS_HMAC_DRBG_C) @@ -72,10 +79,31 @@ void rng_init( rng_context_t *rng ) #endif mbedtls_entropy_init( &rng->entropy ); +#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ } int rng_seed( rng_context_t *rng, int reproducible, const char *pers ) { +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( reproducible ) + { + mbedtls_fprintf( stderr, + "MBEDTLS_USE_PSA_CRYPTO does not support reproducible mode.\n" ); + return( -1 ); + } +#endif +#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) + /* The PSA crypto RNG does its own seeding. */ + (void) rng; + (void) pers; + if( reproducible ) + { + mbedtls_fprintf( stderr, + "The PSA RNG does not support reproducible mode.\n" ); + return( -1 ); + } + return( 0 ); +#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ int ( *f_entropy )( void *, unsigned char *, size_t ) = ( reproducible ? dummy_entropy : mbedtls_entropy_func ); @@ -100,9 +128,9 @@ int rng_seed( rng_context_t *rng, int reproducible, const char *pers ) f_entropy, &rng->entropy, (const unsigned char *) pers, strlen( pers ) ); -#else +#else /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */ #error "No DRBG available" -#endif +#endif /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */ if( ret != 0 ) { @@ -110,12 +138,21 @@ int rng_seed( rng_context_t *rng, int reproducible, const char *pers ) (unsigned int) -ret ); return( ret ); } +#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ return( 0 ); } void rng_free( rng_context_t *rng ) { +#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) + (void) rng; + /* Deinitialize the PSA crypto subsystem. This deactivates all PSA APIs. + * This is ok because none of our applications try to do any crypto after + * deinitializing the RNG. */ + mbedtls_psa_crypto_free( ); +#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ + #if defined(MBEDTLS_CTR_DRBG_C) mbedtls_ctr_drbg_free( &rng->drbg ); #elif defined(MBEDTLS_HMAC_DRBG_C) @@ -125,11 +162,18 @@ void rng_free( rng_context_t *rng ) #endif mbedtls_entropy_free( &rng->entropy ); +#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ } int rng_get( void *p_rng, unsigned char *output, size_t output_len ) { +#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) + (void) p_rng; + return( mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, + output, output_len ) ); +#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ rng_context_t *rng = p_rng; + #if defined(MBEDTLS_CTR_DRBG_C) return( mbedtls_ctr_drbg_random( &rng->drbg, output, output_len ) ); #elif defined(MBEDTLS_HMAC_DRBG_C) @@ -137,6 +181,8 @@ int rng_get( void *p_rng, unsigned char *output, size_t output_len ) #else #error "No DRBG available" #endif + +#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ } #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) diff --git a/programs/ssl/ssl_test_lib.h b/programs/ssl/ssl_test_lib.h index 861e82a00..04ba15874 100644 --- a/programs/ssl/ssl_test_lib.h +++ b/programs/ssl/ssl_test_lib.h @@ -43,23 +43,33 @@ #define MBEDTLS_EXIT_FAILURE EXIT_FAILURE #endif -#if !defined(MBEDTLS_ENTROPY_C) || \ - !defined(MBEDTLS_NET_C) || \ +#undef HAVE_RNG +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) && \ + ( defined(MBEDTLS_USE_PSA_CRYPTO) || \ + defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) ) +#define HAVE_RNG +#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C) +#define HAVE_RNG +#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_HMAC_DRBG_C) && \ + ( defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA512_C) ) +#define HAVE_RNG +#endif + +#if !defined(MBEDTLS_NET_C) || \ !defined(MBEDTLS_SSL_TLS_C) || \ defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) #define MBEDTLS_SSL_TEST_IMPOSSIBLE \ - "MBEDTLS_ENTROPY_C and/or " \ "MBEDTLS_NET_C and/or " \ "MBEDTLS_SSL_TLS_C not defined, " \ "and/or MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined.\n" -#elif !( defined(MBEDTLS_CTR_DRBG_C) || \ - defined(MBEDTLS_HMAC_DRBG_C) && ( defined(MBEDTLS_SHA256_C) || \ - defined(MBEDTLS_SHA512_C) ) ) -#define MBEDTLS_SSL_TEST_IMPOSSIBLE \ - "Neither MBEDTLS_CTR_DRBG_C, nor MBEDTLS_HMAC_DRBG_C and a supported hash defined.\n" +#elif !defined(HAVE_RNG) +#define MBEDTLS_SSL_TEST_IMPOSSIBLE \ + "No random generator is available.\n" #else #undef MBEDTLS_SSL_TEST_IMPOSSIBLE +#undef HAVE_RNG + #include #include #include @@ -76,7 +86,7 @@ #include "mbedtls/timing.h" #include "mbedtls/base64.h" -#if defined(MBEDTLS_USE_PSA_CRYPTO) +#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) #include "psa/crypto.h" #include "mbedtls/psa_util.h" #endif @@ -130,10 +140,38 @@ void my_debug( void *ctx, int level, mbedtls_time_t dummy_constant_time( mbedtls_time_t* time ); +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/* If MBEDTLS_TEST_USE_PSA_CRYPTO_RNG is defined, the SSL test programs will use + * mbedtls_psa_get_random() rather than entropy+DRBG as a random generator. + * + * The constraints are: + * - Without the entropy module, the PSA RNG is the only option. + * - Without at least one of the DRBG modules, the PSA RNG is the only option. + * - The PSA RNG does not support explicit seeding, so it is incompatible with + * the reproducible mode used by test programs. + * - For good overall test coverage, there should be at least one configuration + * where the test programs use the PSA RNG while the PSA RNG is itself based + * on entropy+DRBG, and at least one configuration where the test programs + * do not use the PSA RNG even though it's there. + * + * A simple choice that meets the constraints is to use the PSA RNG whenever + * MBEDTLS_USE_PSA_CRYPTO is enabled. There's no real technical reason the + * choice to use the PSA RNG in the test programs and the choice to use + * PSA crypto when TLS code needs crypto have to be tied together, but it + * happens to be a good match. It's also a good match from an application + * perspective: either PSA is preferred for TLS (both for crypto and for + * random generation) or it isn't. + */ +#define MBEDTLS_TEST_USE_PSA_CRYPTO_RNG +#endif + /** A context for random number generation (RNG). */ typedef struct { +#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) + unsigned char dummy; +#else /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ mbedtls_entropy_context entropy; #if defined(MBEDTLS_CTR_DRBG_C) mbedtls_ctr_drbg_context drbg; @@ -142,6 +180,7 @@ typedef struct #else #error "No DRBG available" #endif +#endif /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */ } rng_context_t; /** Initialize the RNG. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 13f05931a..cefc5c929 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -153,6 +153,7 @@ add_test_suite(psa_crypto_se_driver_hal) add_test_suite(psa_crypto_se_driver_hal_mocks) add_test_suite(psa_crypto_slot_management) add_test_suite(psa_its) +add_test_suite(random) add_test_suite(rsa) add_test_suite(shax) add_test_suite(ssl) diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h index 8b56d3ad9..928c63607 100644 --- a/tests/include/test/helpers.h +++ b/tests/include/test/helpers.h @@ -256,7 +256,7 @@ void* mbedtls_test_param_failed_get_state_buf( void ); void mbedtls_test_param_failed_reset_state( void ); #endif /* MBEDTLS_CHECK_PARAMS */ -#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) #include "test/fake_external_rng_for_test.h" #endif diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 1036a7cfd..43742fd33 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -922,37 +922,61 @@ component_test_rsa_no_crt () { if_build_succeeded tests/context-info.sh } -component_test_no_ctr_drbg () { - msg "build: Full minus CTR_DRBG" +component_test_no_ctr_drbg_classic () { + msg "build: Full minus CTR_DRBG, classic crypto in TLS" scripts/config.py full scripts/config.py unset MBEDTLS_CTR_DRBG_C + scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . make - msg "test: Full minus CTR_DRBG - main suites" + msg "test: Full minus CTR_DRBG, classic crypto - main suites" make test # In this configuration, the TLS test programs use HMAC_DRBG. # The SSL tests are slow, so run a small subset, just enough to get # confidence that the SSL code copes with HMAC_DRBG. - msg "test: Full minus CTR_DRBG - ssl-opt.sh (subset)" + msg "test: Full minus CTR_DRBG, classic crypto - ssl-opt.sh (subset)" if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private.*delay=\|tickets enabled on server' - msg "test: Full minus CTR_DRBG - compat.sh (subset)" + msg "test: Full minus CTR_DRBG, classic crypto - compat.sh (subset)" if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA PSK' -V NO -p OpenSSL } -component_test_no_hmac_drbg () { - msg "build: Full minus HMAC_DRBG" +component_test_no_ctr_drbg_use_psa () { + msg "build: Full minus CTR_DRBG, PSA crypto in TLS" scripts/config.py full - scripts/config.py unset MBEDTLS_HMAC_DRBG_C - scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG + scripts/config.py unset MBEDTLS_CTR_DRBG_C + scripts/config.py set MBEDTLS_USE_PSA_CRYPTO CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . make - msg "test: Full minus HMAC_DRBG - main suites" + msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - main suites" + make test + + # In this configuration, the TLS test programs use HMAC_DRBG. + # The SSL tests are slow, so run a small subset, just enough to get + # confidence that the SSL code copes with HMAC_DRBG. + msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - ssl-opt.sh (subset)" + if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private.*delay=\|tickets enabled on server' + + msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - compat.sh (subset)" + if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA PSK' -V NO -p OpenSSL +} + +component_test_no_hmac_drbg_classic () { + msg "build: Full minus HMAC_DRBG, classic crypto in TLS" + scripts/config.py full + scripts/config.py unset MBEDTLS_HMAC_DRBG_C + scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG + scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO + + CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . + make + + msg "test: Full minus HMAC_DRBG, classic crypto - main suites" make test # Normally our ECDSA implementation uses deterministic ECDSA. But since @@ -960,29 +984,84 @@ component_test_no_hmac_drbg () { # instead. # Test SSL with non-deterministic ECDSA. Only test features that # might be affected by how ECDSA signature is performed. - msg "test: Full minus HMAC_DRBG - ssl-opt.sh (subset)" + msg "test: Full minus HMAC_DRBG, classic crypto - ssl-opt.sh (subset)" if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign' # To save time, only test one protocol version, since this part of # the protocol is identical in (D)TLS up to 1.2. - msg "test: Full minus HMAC_DRBG - compat.sh (ECDSA)" + msg "test: Full minus HMAC_DRBG, classic crypto - compat.sh (ECDSA)" if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA' } -component_test_psa_external_rng_no_drbg () { - msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG" +component_test_no_hmac_drbg_use_psa () { + msg "build: Full minus HMAC_DRBG, PSA crypto in TLS" + scripts/config.py full + scripts/config.py unset MBEDTLS_HMAC_DRBG_C + scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG + scripts/config.py set MBEDTLS_USE_PSA_CRYPTO + + CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . + make + + msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - main suites" + make test + + # Normally our ECDSA implementation uses deterministic ECDSA. But since + # HMAC_DRBG is disabled in this configuration, randomized ECDSA is used + # instead. + # Test SSL with non-deterministic ECDSA. Only test features that + # might be affected by how ECDSA signature is performed. + msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - ssl-opt.sh (subset)" + if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign' + + # To save time, only test one protocol version, since this part of + # the protocol is identical in (D)TLS up to 1.2. + msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - compat.sh (ECDSA)" + if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA' +} + +component_test_psa_external_rng_no_drbg_classic () { + msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto in TLS" + scripts/config.py full + scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO + scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + scripts/config.py unset MBEDTLS_ENTROPY_C + scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED + scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT + 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 + # When MBEDTLS_USE_PSA_CRYPTO is disabled and there is no DRBG, + # the SSL test programs don't have an RNG and can't work. Explicitly + # make them use the PSA RNG with -DMBEDTLS_TEST_USE_PSA_CRYPTO_RNG. + make CFLAGS="$ASAN_CFLAGS -O2 -DMBEDTLS_TEST_USE_PSA_CRYPTO_RNG" LDFLAGS="$ASAN_CFLAGS" + + msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto - main suites" + make test + + msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto - ssl-opt.sh (subset)" + if_build_succeeded tests/ssl-opt.sh -f 'Default' +} + +component_test_psa_external_rng_no_drbg_use_psa () { + msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto in TLS" scripts/config.py full scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + scripts/config.py unset MBEDTLS_ENTROPY_C + scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED + scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT 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" + msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto - main suites" make test - # no SSL tests as they all depend on having a DRBG + msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto - ssl-opt.sh (subset)" + if_build_succeeded tests/ssl-opt.sh -f 'Default\|opaque' } component_test_psa_external_rng_use_psa_crypto () { diff --git a/tests/suites/test_suite_random.data b/tests/suites/test_suite_random.data new file mode 100644 index 000000000..c23d9223f --- /dev/null +++ b/tests/suites/test_suite_random.data @@ -0,0 +1,55 @@ +Generate random twice with CTR_DRBG +random_twice_with_ctr_drbg: + +Generate random twice with HMAC_DRBG(SHA-1) +depends_on:MBEDTLS_SHA1_C +random_twice_with_hmac_drbg:MBEDTLS_MD_SHA1 + +Generate random twice with HMAC_DRBG(SHA-256) +depends_on:MBEDTLS_SHA256_C +random_twice_with_hmac_drbg:MBEDTLS_MD_SHA256 + +Generate random twice with HMAC_DRBG(SHA-512) +depends_on:MBEDTLS_SHA512_C +random_twice_with_hmac_drbg:MBEDTLS_MD_SHA512 + +Generate random twice with PSA classic wrapper +random_twice_with_psa_from_classic: + +Generate random twice with PSA API +random_twice_with_psa_from_psa: + +# This bad-usage test case currently crashes in the default configuration +# because CTR_DRBG crashes when given an unseeded context. This is arguably +# a good thing because it prevents misuse of mbedtls_psa_get_random(). +#PSA classic wrapper: PSA not active +#mbedtls_psa_get_random_no_init: + +PSA classic wrapper: 0 bytes +mbedtls_psa_get_random_length:0 + +PSA classic wrapper: 1 byte +mbedtls_psa_get_random_length:1 + +PSA classic wrapper: 256 bytes +mbedtls_psa_get_random_length:256 + +# An external RNG is supposed to handle arbitrary request lengths. Test it +# with something larger than any RNG call made by Mbed TLS itself expects. +# CTR_DRBG and HMAC_DRBG have their own maximum request lengths which may +# be lower than the value chosen here and are tested separately. +PSA classic wrapper: external RNG large +depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG +mbedtls_psa_get_random_length:1024 + +PSA classic wrapper: CTR_DRBG max +depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:MBEDTLS_CTR_DRBG_C +mbedtls_psa_get_random_length:MBEDTLS_CTR_DRBG_MAX_REQUEST + +PSA classic wrapper: HMAC_DRBG max +depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:!MBEDTLS_CTR_DRBG_C:MBEDTLS_HMAC_DRBG_C +mbedtls_psa_get_random_length:MBEDTLS_HMAC_DRBG_MAX_REQUEST + +PSA classic wrapper: ECDSA signature (SECP256R1) +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +mbedtls_psa_get_random_ecdsa_sign:MBEDTLS_ECP_DP_SECP256R1 diff --git a/tests/suites/test_suite_random.function b/tests/suites/test_suite_random.function new file mode 100644 index 000000000..37fa36ecd --- /dev/null +++ b/tests/suites/test_suite_random.function @@ -0,0 +1,202 @@ +/* BEGIN_HEADER */ + +/* Test random generation as a whole. */ + +#include "mbedtls/bignum.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/ecdsa.h" +#include "mbedtls/entropy.h" +#include "mbedtls/hmac_drbg.h" +#include "mbedtls/psa_util.h" +#include "psa/crypto.h" + +/* How many bytes to generate in each test case for repeated generation. + * This must be high enough that the probability of generating the same + * output twice is infinitesimal, but low enough that random generators + * are willing to deliver that much. */ +#define OUTPUT_SIZE 32 + +/* END_HEADER */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_TEST_NULL_ENTROPY:MBEDTLS_CTR_DRBG_C */ +void random_twice_with_ctr_drbg( ) +{ + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context drbg; + unsigned char output1[OUTPUT_SIZE]; + unsigned char output2[OUTPUT_SIZE]; + + /* First round */ + mbedtls_entropy_init( &entropy ); + mbedtls_ctr_drbg_init( &drbg ); + TEST_EQUAL( 0, mbedtls_ctr_drbg_seed( &drbg, + mbedtls_entropy_func, &entropy, + NULL, 0 ) ); + TEST_EQUAL( 0, mbedtls_ctr_drbg_random( &drbg, + output1, sizeof( output1 ) ) ); + mbedtls_ctr_drbg_free( &drbg ); + mbedtls_entropy_free( &entropy ); + + /* Second round */ + mbedtls_entropy_init( &entropy ); + mbedtls_ctr_drbg_init( &drbg ); + TEST_EQUAL( 0, mbedtls_ctr_drbg_seed( &drbg, + mbedtls_entropy_func, &entropy, + NULL, 0 ) ); + TEST_EQUAL( 0, mbedtls_ctr_drbg_random( &drbg, + output2, sizeof( output2 ) ) ); + mbedtls_ctr_drbg_free( &drbg ); + mbedtls_entropy_free( &entropy ); + + /* The two rounds must generate different random data. */ + TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 ); + +exit: + mbedtls_ctr_drbg_free( &drbg ); + mbedtls_entropy_free( &entropy ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_TEST_NULL_ENTROPY:MBEDTLS_HMAC_DRBG_C */ +void random_twice_with_hmac_drbg( int md_type ) +{ + mbedtls_entropy_context entropy; + mbedtls_hmac_drbg_context drbg; + unsigned char output1[OUTPUT_SIZE]; + unsigned char output2[OUTPUT_SIZE]; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_type ); + + /* First round */ + mbedtls_entropy_init( &entropy ); + mbedtls_hmac_drbg_init( &drbg ); + TEST_EQUAL( 0, mbedtls_hmac_drbg_seed( &drbg, md_info, + mbedtls_entropy_func, &entropy, + NULL, 0 ) ); + TEST_EQUAL( 0, mbedtls_hmac_drbg_random( &drbg, + output1, sizeof( output1 ) ) ); + mbedtls_hmac_drbg_free( &drbg ); + mbedtls_entropy_free( &entropy ); + + /* Second round */ + mbedtls_entropy_init( &entropy ); + mbedtls_hmac_drbg_init( &drbg ); + TEST_EQUAL( 0, mbedtls_hmac_drbg_seed( &drbg, md_info, + mbedtls_entropy_func, &entropy, + NULL, 0 ) ); + TEST_EQUAL( 0, mbedtls_hmac_drbg_random( &drbg, + output2, sizeof( output2 ) ) ); + mbedtls_hmac_drbg_free( &drbg ); + mbedtls_entropy_free( &entropy ); + + /* The two rounds must generate different random data. */ + TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 ); + +exit: + mbedtls_hmac_drbg_free( &drbg ); + mbedtls_entropy_free( &entropy ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!MBEDTLS_TEST_NULL_ENTROPY:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +void random_twice_with_psa_from_classic( ) +{ + unsigned char output1[OUTPUT_SIZE]; + unsigned char output2[OUTPUT_SIZE]; + + /* First round */ + PSA_ASSERT( psa_crypto_init( ) ); + TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, + output1, sizeof( output1 ) ) ); + PSA_DONE( ); + + /* Second round */ + PSA_ASSERT( psa_crypto_init( ) ); + TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, + output2, sizeof( output2 ) ) ); + PSA_DONE( ); + + /* The two rounds must generate different random data. */ + TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 ); + +exit: + PSA_DONE( ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!MBEDTLS_TEST_NULL_ENTROPY:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +void random_twice_with_psa_from_psa( ) +{ + unsigned char output1[OUTPUT_SIZE]; + unsigned char output2[OUTPUT_SIZE]; + + /* First round */ + PSA_ASSERT( psa_crypto_init( ) ); + PSA_ASSERT( psa_generate_random( output1, sizeof( output1 ) ) ); + PSA_DONE( ); + + /* Second round */ + PSA_ASSERT( psa_crypto_init( ) ); + PSA_ASSERT( psa_generate_random( output2, sizeof( output2 ) ) ); + PSA_DONE( ); + + /* The two rounds must generate different random data. */ + TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 ); + +exit: + PSA_DONE( ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */ +void mbedtls_psa_get_random_no_init( ) +{ + unsigned char output[1]; + + TEST_ASSERT( mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, + output, sizeof( output ) ) != 0 ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */ +void mbedtls_psa_get_random_length( int n ) +{ + unsigned char *output = NULL; + + PSA_ASSERT( psa_crypto_init( ) ); + ASSERT_ALLOC( output, n ); + + TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE, + output, n ) ); +exit: + mbedtls_free( output ); + PSA_DONE( ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_ECDSA_C */ +void mbedtls_psa_get_random_ecdsa_sign( int curve ) +{ + mbedtls_ecp_group grp; + mbedtls_mpi d, r, s; + unsigned char buf[] = "This is not a hash."; + + mbedtls_ecp_group_init( &grp ); + mbedtls_mpi_init( &d ); + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + + TEST_EQUAL( 0, mbedtls_mpi_lset( &d, 123456789 ) ); + TEST_EQUAL( 0, mbedtls_ecp_group_load( &grp, curve ) ); + PSA_ASSERT( psa_crypto_init( ) ); + TEST_EQUAL( 0, mbedtls_ecdsa_sign( &grp, &r, &s, &d, + buf, sizeof( buf ), + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE ) ); +exit: + mbedtls_mpi_free( &d ); + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + mbedtls_ecp_group_free( &grp ); + PSA_DONE( ); +} +/* END_CASE */