From ddfd08012866720f42dc34619d88ffe25472e810 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 17:07:05 +0100 Subject: [PATCH 01/18] Use mbedtls_test_ prefix on all PSA helper functions Signed-off-by: Gilles Peskine --- tests/include/test/psa_crypto_helpers.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h index 01b0547cf..9263a932c 100644 --- a/tests/include/test/psa_crypto_helpers.h +++ b/tests/include/test/psa_crypto_helpers.h @@ -26,7 +26,7 @@ #include #include -static int test_helper_is_psa_pristine( int line, const char *file ) +static int mbedtls_test_helper_is_psa_pristine( int line, const char *file ) { mbedtls_psa_stats_t stats; const char *msg = NULL; @@ -60,21 +60,21 @@ static int test_helper_is_psa_pristine( int line, const char *file ) #define ASSERT_PSA_PRISTINE( ) \ do \ { \ - if( ! test_helper_is_psa_pristine( __LINE__, __FILE__ ) ) \ + if( ! mbedtls_test_helper_is_psa_pristine( __LINE__, __FILE__ ) ) \ goto exit; \ } \ while( 0 ) -static void test_helper_psa_done( int line, const char *file ) +static void mbedtls_test_helper_psa_done( int line, const char *file ) { - (void) test_helper_is_psa_pristine( line, file ); + (void) mbedtls_test_helper_is_psa_pristine( line, file ); mbedtls_psa_crypto_free( ); } /** Shut down the PSA Crypto subsystem. Expect a clean shutdown, with no slots * in use. */ -#define PSA_DONE( ) test_helper_psa_done( __LINE__, __FILE__ ) +#define PSA_DONE( ) mbedtls_test_helper_psa_done( __LINE__, __FILE__ ) @@ -84,10 +84,10 @@ static void test_helper_psa_done( int line, const char *file ) /** Name of the file where return statuses are logged by #RECORD_STATUS. */ #define STATUS_LOG_FILE_NAME "statuses.log" -static psa_status_t record_status( psa_status_t status, - const char *func, - const char *file, int line, - const char *expr ) +static psa_status_t mbedtls_test_record_status( psa_status_t status, + const char *func, + const char *file, int line, + const char *expr ) { /* We open the log file on first use. * We never close the log file, so the record_status feature is not @@ -125,7 +125,7 @@ static psa_status_t record_status( psa_status_t status, * \return The value of \p expr. */ #define RECORD_STATUS( string, expr ) \ - record_status( ( expr ), string, __FILE__, __LINE__, #expr ) + mbedtls_test_record_status( ( expr ), string, __FILE__, __LINE__, #expr ) #include "instrument_record_status.h" From 86cadb37d1869e022f8b0ac4e95b6c22be33aeb1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 17:49:31 +0100 Subject: [PATCH 02/18] Remove now-redundant test result check Since 349eadc58faff851ee8dcbb43c702f0ddecfcbb8, test_fail() reports the first failure. So it's safe to call test_fail() again to report a cleanup failure when we don't want to potentially erase information about an earlier failure. The behavior of mbedtls_test_helper_is_psa_pristine() changes if test_info.result was neither TEST_RESULT_SUCCESS nor TEST_RESULT_FAILED, but this should not matter since a skipped test should not cause mbedtls_test_helper_is_psa_pristine() to fail. Signed-off-by: Gilles Peskine --- tests/include/test/psa_crypto_helpers.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h index 9263a932c..e62bc0401 100644 --- a/tests/include/test/psa_crypto_helpers.h +++ b/tests/include/test/psa_crypto_helpers.h @@ -46,10 +46,7 @@ static int mbedtls_test_helper_is_psa_pristine( int line, const char *file ) msg = "Some slots are still marked as locked."; } - /* If the test has already failed, don't overwrite the failure - * information. Do keep the stats lookup above, because it can be - * convenient to break on it when debugging a failure. */ - if( msg != NULL && test_info.result == TEST_RESULT_SUCCESS ) + if( msg != NULL ) test_fail( msg, line, file ); return( msg == NULL ); From 1e0056511157e2772ce16b90469c2753d464f166 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 17:41:07 +0100 Subject: [PATCH 03/18] Refactor PSA test helpers: don't depend on test_info access Refactor some PSA test helper functions and macros to avoid depending on test_info and test_fail inside functions. These identifiers are only defined in helpers.function, so they're only available in test suites, and not in test helper modules (tests/src/*.c) which are also linked into example programs. This is in preparation for moving function definitions from psa_crypto_helpers.h to psa_crypto_helpers.c. No behavior change. Signed-off-by: Gilles Peskine --- tests/include/test/psa_crypto_helpers.h | 58 ++++++++++++------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h index e62bc0401..361fbbb48 100644 --- a/tests/include/test/psa_crypto_helpers.h +++ b/tests/include/test/psa_crypto_helpers.h @@ -26,52 +26,48 @@ #include #include -static int mbedtls_test_helper_is_psa_pristine( int line, const char *file ) +/** Check for things that have not been cleaned up properly in the + * PSA subsystem. + * + * \return NULL if nothing has leaked. + * \return A string literal explaining what has not been cleaned up + * if applicable. + */ +static const char *mbedtls_test_helper_is_psa_leaking( void ) { mbedtls_psa_stats_t stats; - const char *msg = NULL; mbedtls_psa_get_stats( &stats ); if( stats.volatile_slots != 0 ) - msg = "A volatile slot has not been closed properly."; - else if( stats.persistent_slots != 0 ) - msg = "A persistent slot has not been closed properly."; - else if( stats.external_slots != 0 ) - msg = "An external slot has not been closed properly."; - else if( stats.half_filled_slots != 0 ) - msg = "A half-filled slot has not been cleared properly."; - else if( stats.locked_slots != 0 ) - { - msg = "Some slots are still marked as locked."; - } + return( "A volatile slot has not been closed properly." ); + if( stats.persistent_slots != 0 ) + return( "A persistent slot has not been closed properly." ); + if( stats.external_slots != 0 ) + return( "An external slot has not been closed properly." ); + if( stats.half_filled_slots != 0 ) + return( "A half-filled slot has not been cleared properly." ); + if( stats.locked_slots != 0 ) + return( "Some slots are still marked as locked." ); - if( msg != NULL ) - test_fail( msg, line, file ); - - return( msg == NULL ); + return( NULL ); } /** Check that no PSA Crypto key slots are in use. */ -#define ASSERT_PSA_PRISTINE( ) \ - do \ - { \ - if( ! mbedtls_test_helper_is_psa_pristine( __LINE__, __FILE__ ) ) \ - goto exit; \ - } \ - while( 0 ) - -static void mbedtls_test_helper_psa_done( int line, const char *file ) -{ - (void) mbedtls_test_helper_is_psa_pristine( line, file ); - mbedtls_psa_crypto_free( ); -} +#define ASSERT_PSA_PRISTINE( ) \ + TEST_ASSERT( ! mbedtls_test_helper_is_psa_leaking( ) ) /** Shut down the PSA Crypto subsystem. Expect a clean shutdown, with no slots * in use. */ -#define PSA_DONE( ) mbedtls_test_helper_psa_done( __LINE__, __FILE__ ) +#define PSA_DONE( ) \ + do \ + { \ + ASSERT_PSA_PRISTINE( ); \ + mbedtls_psa_crypto_free( ); \ + } \ + while( 0 ) From d4008d5b383e1c89a8589a33eabfb2eb3282ef83 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 17:34:30 +0100 Subject: [PATCH 04/18] Refactor PSA test helpers: move function definitions from .h to .c Move function definitions from psa_crypto_helpers.h to psa_crypto_helpers.c. No behavior change. Signed-off-by: Gilles Peskine --- tests/include/test/psa_crypto_helpers.h | 44 +++---------------------- tests/src/psa_crypto_helpers.c | 42 +++++++++++++++++++++++ 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h index 361fbbb48..f44a29245 100644 --- a/tests/include/test/psa_crypto_helpers.h +++ b/tests/include/test/psa_crypto_helpers.h @@ -33,25 +33,7 @@ * \return A string literal explaining what has not been cleaned up * if applicable. */ -static const char *mbedtls_test_helper_is_psa_leaking( void ) -{ - mbedtls_psa_stats_t stats; - - mbedtls_psa_get_stats( &stats ); - - if( stats.volatile_slots != 0 ) - return( "A volatile slot has not been closed properly." ); - if( stats.persistent_slots != 0 ) - return( "A persistent slot has not been closed properly." ); - if( stats.external_slots != 0 ) - return( "An external slot has not been closed properly." ); - if( stats.half_filled_slots != 0 ) - return( "A half-filled slot has not been cleared properly." ); - if( stats.locked_slots != 0 ) - return( "Some slots are still marked as locked." ); - - return( NULL ); -} +const char *mbedtls_test_helper_is_psa_leaking( void ); /** Check that no PSA Crypto key slots are in use. */ @@ -72,26 +54,10 @@ static const char *mbedtls_test_helper_is_psa_leaking( void ) #if defined(RECORD_PSA_STATUS_COVERAGE_LOG) -#include - -/** Name of the file where return statuses are logged by #RECORD_STATUS. */ -#define STATUS_LOG_FILE_NAME "statuses.log" - -static psa_status_t mbedtls_test_record_status( psa_status_t status, - const char *func, - const char *file, int line, - const char *expr ) -{ - /* We open the log file on first use. - * We never close the log file, so the record_status feature is not - * compatible with resource leak detectors such as Asan. - */ - static FILE *log; - if( log == NULL ) - log = fopen( STATUS_LOG_FILE_NAME, "a" ); - fprintf( log, "%d:%s:%s:%d:%s\n", (int) status, func, file, line, expr ); - return( status ); -} +psa_status_t mbedtls_test_record_status( psa_status_t status, + const char *func, + const char *file, int line, + const char *expr ); /** Return value logging wrapper macro. * diff --git a/tests/src/psa_crypto_helpers.c b/tests/src/psa_crypto_helpers.c index dacda683a..499f4b328 100644 --- a/tests/src/psa_crypto_helpers.c +++ b/tests/src/psa_crypto_helpers.c @@ -22,11 +22,53 @@ #include #include +#include #if defined(MBEDTLS_PSA_CRYPTO_C) #include +const char *mbedtls_test_helper_is_psa_leaking( void ) +{ + mbedtls_psa_stats_t stats; + + mbedtls_psa_get_stats( &stats ); + + if( stats.volatile_slots != 0 ) + return( "A volatile slot has not been closed properly." ); + if( stats.persistent_slots != 0 ) + return( "A persistent slot has not been closed properly." ); + if( stats.external_slots != 0 ) + return( "An external slot has not been closed properly." ); + if( stats.half_filled_slots != 0 ) + return( "A half-filled slot has not been cleared properly." ); + if( stats.locked_slots != 0 ) + return( "Some slots are still marked as locked." ); + + return( NULL ); +} + +#if defined(RECORD_PSA_STATUS_COVERAGE_LOG) +/** Name of the file where return statuses are logged by #RECORD_STATUS. */ +#define STATUS_LOG_FILE_NAME "statuses.log" + +psa_status_t mbedtls_test_record_status( psa_status_t status, + const char *func, + const char *file, int line, + const char *expr ) +{ + /* We open the log file on first use. + * We never close the log file, so the record_status feature is not + * compatible with resource leak detectors such as Asan. + */ + static FILE *log; + if( log == NULL ) + log = fopen( STATUS_LOG_FILE_NAME, "a" ); + fprintf( log, "%d:%s:%s:%d:%s\n", (int) status, func, file, line, expr ); + return( status ); +} +#endif /* defined(RECORD_PSA_STATUS_COVERAGE_LOG) */ + #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) #include From d71539fd036ad76bb6070fc556017d11a22125df Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Nov 2020 18:17:17 +0100 Subject: [PATCH 05/18] Fix test_psa_collect_statuses: update makefile dependencies `tests/scripts/all.sh test_psa_collect_statuses` calls `tests/scripts/psa_collect_statuses.py` which calls `make -DRECORD_PSA_STATUS_COVERAGE_LOG` which must generate `include/test/instrument_record_status.h`. With the refactoring of `psa_crypto_helpers.{h,c}`, this now needs to be done before building `psa_crypto_helpers.c`. Also, remove `include/test/instrument_record_status.h` unconditionally in `make clean`, which helps keep the build tree clean. Signed-off-by: Gilles Peskine --- tests/Makefile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 511db9db5..b9c55257b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -84,8 +84,13 @@ MBEDTLS_TEST_OBJS=$(patsubst %.c,%.o,$(wildcard src/*.c src/drivers/*.c)) mbedtls_test: $(MBEDTLS_TEST_OBJS) +TEST_OBJS_DEPS = +ifdef RECORD_PSA_STATUS_COVERAGE_LOG +TEST_OBJS_DEPS += include/test/instrument_record_status.h +endif + # Rule to compile common test C files in src folder -src/%.o : src/%.c +src/%.o : src/%.c $(TEST_OBJS_DEPS) echo " CC $<" $(CC) $(LOCAL_CFLAGS) $(CFLAGS) -o $@ -c $< @@ -121,7 +126,7 @@ C_FILES := $(addsuffix .c,$(APPS)) -o . -$(BINARIES): %$(EXEXT): %.c $(MBEDLIBS) $(MBEDTLS_TEST_OBJS) +$(BINARIES): %$(EXEXT): %.c $(MBEDLIBS) $(TEST_OBJS_DEPS) $(MBEDTLS_TEST_OBJS) echo " CC $<" $(CC) $(LOCAL_CFLAGS) $(CFLAGS) $< $(MBEDTLS_TEST_OBJS) $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ @@ -135,6 +140,7 @@ clean: ifndef WINDOWS rm -rf $(BINARIES) *.c *.datax TESTS rm -f src/*.o src/drivers/*.o src/libmbed* + rm -f include/test/instrument_record_status.h else if exist *.c del /Q /F *.c if exist *.exe del /Q /F *.exe @@ -142,6 +148,7 @@ else if exist src/*.o del /Q /F src/*.o if exist src/drivers/*.o del /Q /F src/drivers/*.o if exist src/libmbed* del /Q /F src/libmed* + if exist include/test/instrument_record_status.h del /Q /F include/test/instrument_record_status.h ifneq ($(wildcard TESTS/.*),) rmdir /Q /S TESTS endif @@ -187,7 +194,7 @@ $(foreach app, $(APPS), $(foreach file, $(notdir $(wildcard include/test/*.h)), $(eval $(call copy_header_to_target,$(app),$(file))))) ifdef RECORD_PSA_STATUS_COVERAGE_LOG -$(BINARIES): include/test/instrument_record_status.h include/test/instrument_record_status.h: ../include/psa/crypto.h Makefile + echo " Gen $@" sed <../include/psa/crypto.h >$@ -n 's/^psa_status_t \([A-Za-z0-9_]*\)(.*/#define \1(...) RECORD_STATUS("\1", \1(__VA_ARGS__))/p' endif From 9a4baa13362c60372de6229e8b280162c80c2ebf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 18:31:19 +0100 Subject: [PATCH 06/18] Remove unnecessary precautions around #include psa_crypto_helpers.h psa_crypto_helpers.h no longer defines static functions, so it can be included anywhere without worrying about unused functions. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_x509write.function | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function index 3803377cc..6a28fa108 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -6,24 +6,12 @@ #include "mbedtls/oid.h" #include "mbedtls/rsa.h" -/* These are the same depends as the test function x509_crs_check_opaque(), - * the only function using PSA here. Using a weaker condition would result in - * warnings about the static functions defined in psa_crypto_helpers.h being - * unused. */ -#if defined(MBEDTLS_USE_PSA_CRYPTO) && \ - defined(MBEDTLS_PEM_WRITE_C) && \ - defined(MBEDTLS_X509_CSR_WRITE_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) #include "psa/crypto.h" #include "mbedtls/psa_util.h" #include "test/psa_crypto_helpers.h" #define PSA_INIT( ) PSA_ASSERT( psa_crypto_init( ) ) -#else -/* Define empty macros so that we can use them in the preamble and teardown - * of every test function that uses PSA conditionally based on - * MBEDTLS_USE_PSA_CRYPTO. */ -#define PSA_INIT( ) ( (void) 0 ) -#define PSA_DONE( ) ( (void) 0 ) -#endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_PEM_WRITE_C && MBEDTLS_X509_CSR_WRITE_C */ +#endif /* MBEDTLS_USE_PSA_CRYPTO */ #if defined(MBEDTLS_RSA_C) int mbedtls_rsa_decrypt_func( void *ctx, int mode, size_t *olen, From f6be590bf6dae361a0a16f71227fc2e9c809ce6a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 18:33:13 +0100 Subject: [PATCH 07/18] Include psa_crypto_helpers.h in helpers.function Include psa_crypto_helpers.h automatically if MBEDTLS_PSA_CRYPTO_C is enabled, like helpers.h is included automatically. Signed-off-by: Gilles Peskine --- tests/suites/helpers.function | 3 +++ tests/suites/test_suite_cipher.function | 4 ---- tests/suites/test_suite_pk.function | 2 +- tests/suites/test_suite_psa_crypto.function | 2 -- tests/suites/test_suite_psa_crypto_driver_wrappers.function | 2 -- tests/suites/test_suite_psa_crypto_entropy.function | 1 - tests/suites/test_suite_psa_crypto_hash.function | 2 -- tests/suites/test_suite_psa_crypto_init.function | 1 - tests/suites/test_suite_psa_crypto_persistent_key.function | 1 - tests/suites/test_suite_psa_crypto_se_driver_hal.function | 1 - .../suites/test_suite_psa_crypto_se_driver_hal_mocks.function | 1 - tests/suites/test_suite_psa_crypto_slot_management.function | 1 - tests/suites/test_suite_x509write.function | 1 - 13 files changed, 4 insertions(+), 18 deletions(-) diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function index aafcf5c18..3a9c426b8 100644 --- a/tests/suites/helpers.function +++ b/tests/suites/helpers.function @@ -5,6 +5,9 @@ #include #include #include +#if defined(MBEDTLS_PSA_CRYPTO_C) +#include +#endif #include diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 1d98f3db0..76e474f21 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -9,10 +9,6 @@ #include "mbedtls/gcm.h" #endif -#if defined(MBEDTLS_USE_PSA_CRYPTO) -#include "test/psa_crypto_helpers.h" -#endif - #if defined(MBEDTLS_CIPHER_MODE_AEAD) || defined(MBEDTLS_NIST_KW_C) #define MBEDTLS_CIPHER_AUTH_CRYPT #endif diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index 98016c652..577fb474d 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -17,13 +17,13 @@ #if defined(MBEDTLS_USE_PSA_CRYPTO) #include "mbedtls/psa_util.h" -#include "test/psa_crypto_helpers.h" #define PSA_INIT( ) PSA_ASSERT( psa_crypto_init( ) ) #else /* Define empty macros so that we can use them in the preamble and teardown * of every test function that uses PSA conditionally based on * MBEDTLS_USE_PSA_CRYPTO. */ #define PSA_INIT( ) ( (void) 0 ) +#undef PSA_DONE #define PSA_DONE( ) ( (void) 0 ) #endif diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 8e71610ac..d486dd19c 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -9,8 +9,6 @@ * uses mbedtls_ctr_drbg internally. */ #include "mbedtls/ctr_drbg.h" -#include "test/psa_crypto_helpers.h" - /* Tests that require more than 128kB of RAM plus change have this symbol * as a dependency. Currently we always define this symbol, so the tests * are always executed. In the future we should make this conditional diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.function b/tests/suites/test_suite_psa_crypto_driver_wrappers.function index 6d20effe4..23da0c3a4 100644 --- a/tests/suites/test_suite_psa_crypto_driver_wrappers.function +++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.function @@ -1,6 +1,4 @@ /* BEGIN_HEADER */ -#include "test/psa_crypto_helpers.h" - #include "test/drivers/test_driver.h" /* END_HEADER */ diff --git a/tests/suites/test_suite_psa_crypto_entropy.function b/tests/suites/test_suite_psa_crypto_entropy.function index 66c241e5e..282910658 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.function +++ b/tests/suites/test_suite_psa_crypto_entropy.function @@ -4,7 +4,6 @@ #include "mbedtls/entropy.h" #include "mbedtls/entropy_poll.h" -#include "test/psa_crypto_helpers.h" #if defined(MBEDTLS_PSA_ITS_FILE_C) #include #else diff --git a/tests/suites/test_suite_psa_crypto_hash.function b/tests/suites/test_suite_psa_crypto_hash.function index 1bc93313a..b0da2bf30 100644 --- a/tests/suites/test_suite_psa_crypto_hash.function +++ b/tests/suites/test_suite_psa_crypto_hash.function @@ -2,8 +2,6 @@ #include -#include "test/psa_crypto_helpers.h" - /* END_HEADER */ /* BEGIN_DEPENDENCIES diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function index e6097bb27..40efb87cb 100644 --- a/tests/suites/test_suite_psa_crypto_init.function +++ b/tests/suites/test_suite_psa_crypto_init.function @@ -1,7 +1,6 @@ /* BEGIN_HEADER */ #include -#include "test/psa_crypto_helpers.h" /* Some tests in this module configure entropy sources. */ #include "psa_crypto_invasive.h" diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.function b/tests/suites/test_suite_psa_crypto_persistent_key.function index 8e10158f6..975907785 100644 --- a/tests/suites/test_suite_psa_crypto_persistent_key.function +++ b/tests/suites/test_suite_psa_crypto_persistent_key.function @@ -9,7 +9,6 @@ #include -#include "test/psa_crypto_helpers.h" #include "psa_crypto_slot_management.h" #include "psa_crypto_storage.h" diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function index 1add9b4a7..d623221a5 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -1,5 +1,4 @@ /* BEGIN_HEADER */ -#include "test/psa_crypto_helpers.h" #include "psa/crypto_se_driver.h" #include "psa_crypto_se.h" diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function b/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function index 629c924ed..12c58ebbb 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function @@ -1,5 +1,4 @@ /* BEGIN_HEADER */ -#include "test/psa_crypto_helpers.h" #include "psa/crypto_se_driver.h" #include "psa_crypto_se.h" diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function index 57d478982..b0c660b46 100644 --- a/tests/suites/test_suite_psa_crypto_slot_management.function +++ b/tests/suites/test_suite_psa_crypto_slot_management.function @@ -1,7 +1,6 @@ /* BEGIN_HEADER */ #include -#include "test/psa_crypto_helpers.h" #include "psa_crypto_slot_management.h" #include "psa_crypto_storage.h" diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function index 6a28fa108..9b32cbab9 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -9,7 +9,6 @@ #if defined(MBEDTLS_USE_PSA_CRYPTO) #include "psa/crypto.h" #include "mbedtls/psa_util.h" -#include "test/psa_crypto_helpers.h" #define PSA_INIT( ) PSA_ASSERT( psa_crypto_init( ) ) #endif /* MBEDTLS_USE_PSA_CRYPTO */ From 76175ba785322b0beb4d0cc2a0c1fe406f032dd4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 18:39:12 +0100 Subject: [PATCH 08/18] Disable the insecure PSA test RNG by default To reduce the risk of people accidentally using the test implementation of mbedtls_psa_external_get_random(), which is insecure, require the user to explicitly call mbedtls_test_enable_insecure_external_rng() first. Disabling the test implementation of mbedtls_psa_external_get_random() will also allow negative testing for MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG, which will be added in a subsequent commit. Signed-off-by: Gilles Peskine --- tests/include/test/psa_crypto_helpers.h | 26 +++++++++++++++++++++++++ tests/src/psa_crypto_helpers.c | 18 ++++++++++++++++- tests/suites/main_test.function | 4 ++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h index f44a29245..3e60a9b65 100644 --- a/tests/include/test/psa_crypto_helpers.h +++ b/tests/include/test/psa_crypto_helpers.h @@ -53,6 +53,32 @@ const char *mbedtls_test_helper_is_psa_leaking( void ); +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/** Enable the insecure implementation of mbedtls_psa_external_get_random(). + * + * The insecure implementation of mbedtls_psa_external_get_random() is + * disabled by default. + * + * When MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled and the test + * helpers are linked into a program, you must enable this before any code + * that uses the PSA subsystem to generate random data (including internal + * random generation for purposes such as blinding when the random generation + * is routed through PSA). + * + * You can enable and disable it at any time, regardless of the state + * of the PSA subsystem. You may disable it temporarily to simulate a + * depleted entropy source. + */ +void mbedtls_test_enable_insecure_external_rng( void ); + +/** Disable the insecure implementation of mbedtls_psa_external_get_random(). + * + * See mbedtls_test_enable_insecure_external_rng(). + */ +void mbedtls_test_disable_insecure_external_rng( void ); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + + #if defined(RECORD_PSA_STATUS_COVERAGE_LOG) psa_status_t mbedtls_test_record_status( psa_status_t status, const char *func, diff --git a/tests/src/psa_crypto_helpers.c b/tests/src/psa_crypto_helpers.c index 499f4b328..00098574e 100644 --- a/tests/src/psa_crypto_helpers.c +++ b/tests/src/psa_crypto_helpers.c @@ -72,13 +72,29 @@ psa_status_t mbedtls_test_record_status( psa_status_t status, #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) #include +static int test_insecure_external_rng_enabled = 0; + +void mbedtls_test_enable_insecure_external_rng( void ) +{ + test_insecure_external_rng_enabled = 1; +} + +void mbedtls_test_disable_insecure_external_rng( void ) +{ + test_insecure_external_rng_enabled = 0; +} + 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 ) { + (void) context; + + if( !test_insecure_external_rng_enabled ) + return( PSA_ERROR_INSUFFICIENT_ENTROPY ); + /* 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 ); diff --git a/tests/suites/main_test.function b/tests/suites/main_test.function index 256224e79..98dab3ebb 100644 --- a/tests/suites/main_test.function +++ b/tests/suites/main_test.function @@ -164,6 +164,10 @@ $dispatch_code */ void execute_function_ptr(TestWrapper_t fp, void **params) { +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + mbedtls_test_enable_insecure_external_rng( ); +#endif + #if defined(MBEDTLS_CHECK_PARAMS) mbedtls_test_param_failed_location_record_t location_record; From 8ae012b603a457baa9b1fb62c2388c6a2cb6975d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 18:44:58 +0100 Subject: [PATCH 09/18] Generalize test_suite_psa_crypto_entropy Prepare it for testing aspects of entropy other than MBEDTLS_PSA_INJECT_ENTROPY. Signed-off-by: Gilles Peskine --- .../test_suite_psa_crypto_entropy.function | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_entropy.function b/tests/suites/test_suite_psa_crypto_entropy.function index 282910658..7233b17cd 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.function +++ b/tests/suites/test_suite_psa_crypto_entropy.function @@ -4,15 +4,17 @@ #include "mbedtls/entropy.h" #include "mbedtls/entropy_poll.h" +/* Calculating the minimum allowed entropy size in bytes */ +#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) + +#if defined(MBEDTLS_PSA_INJECT_ENTROPY) + #if defined(MBEDTLS_PSA_ITS_FILE_C) #include #else #include #endif -/* Calculating the minimum allowed entropy size in bytes */ -#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) - /* Remove the entropy seed file. Since the library does not expose a way * to do this (it would be a security risk if such a function was ever * accessible in production), implement this functionality in a white-box @@ -29,14 +31,11 @@ psa_status_t remove_seed_file( void ) #endif } +#endif /* MBEDTLS_PSA_INJECT_ENTROPY */ + /* END_HEADER */ -/* BEGIN_DEPENDENCIES - * depends_on:MBEDTLS_PSA_INJECT_ENTROPY - * END_DEPENDENCIES - */ - -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_PSA_INJECT_ENTROPY */ void validate_entropy_seed_injection( int seed_length_a, int expected_status_a, int seed_length_b, @@ -80,7 +79,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_PSA_INJECT_ENTROPY */ void run_entropy_inject_with_crypto_init( ) { psa_status_t status; From 40d8160c8edf1c0042be5944149a4144cb38eed9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Nov 2020 00:09:47 +0100 Subject: [PATCH 10/18] mbedtls_to_psa_error: fix a copypasta and a missing translation Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 7ea2a1a9a..73f5a6e72 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -344,7 +344,7 @@ psa_status_t mbedtls_to_psa_error( int ret ) case MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE: return( PSA_ERROR_BUFFER_TOO_SMALL ); case MBEDTLS_ERR_RSA_RNG_FAILED: - return( PSA_ERROR_INSUFFICIENT_MEMORY ); + return( PSA_ERROR_INSUFFICIENT_ENTROPY ); case MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION: return( PSA_ERROR_NOT_SUPPORTED ); case MBEDTLS_ERR_RSA_HW_ACCEL_FAILED: @@ -372,8 +372,11 @@ psa_status_t mbedtls_to_psa_error( int ret ) return( PSA_ERROR_INVALID_SIGNATURE ); case MBEDTLS_ERR_ECP_ALLOC_FAILED: return( PSA_ERROR_INSUFFICIENT_MEMORY ); + case MBEDTLS_ERR_ECP_RANDOM_FAILED: + return( PSA_ERROR_INSUFFICIENT_ENTROPY ); case MBEDTLS_ERR_ECP_HW_ACCEL_FAILED: return( PSA_ERROR_HARDWARE_FAILURE ); + case MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED: return( PSA_ERROR_CORRUPTION_DETECTED ); From ae3741e8a440cbfa974a98cb443b26e6ba15f21d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Nov 2020 00:10:31 +0100 Subject: [PATCH 11/18] Fix an incorrect error code if RSA private operation glitched mbedtls_rsa_private() could return the sum of two RSA error codes instead of a valid error code in some rare circumstances: * If rsa_prepare_blinding() returned MBEDTLS_ERR_RSA_RNG_FAILED (indicating a misbehaving or misconfigured RNG). * If the comparison with the public value failed (typically indicating a glitch attack). Make sure not to add two high-level error codes. Signed-off-by: Gilles Peskine --- ChangeLog.d/rsa_private-ret.txt | 2 ++ library/rsa.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 ChangeLog.d/rsa_private-ret.txt diff --git a/ChangeLog.d/rsa_private-ret.txt b/ChangeLog.d/rsa_private-ret.txt new file mode 100644 index 000000000..b965cea77 --- /dev/null +++ b/ChangeLog.d/rsa_private-ret.txt @@ -0,0 +1,2 @@ +Bugfix + * Fix an incorrect error code if an RSA private operation glitched. diff --git a/library/rsa.c b/library/rsa.c index d6abd65d4..9fe551d51 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1076,10 +1076,10 @@ cleanup: mbedtls_mpi_free( &C ); mbedtls_mpi_free( &I ); - if( ret != 0 ) + if( ret != 0 && ret >= -0x007f ) return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret ); - return( 0 ); + return( ret ); } #if defined(MBEDTLS_PKCS1_V21) From f547ce8daa70b6fd8228433f0da56c3a4430ccc3 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Nov 2020 00:16:10 +0100 Subject: [PATCH 12/18] MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG: negative tests Under MBEDTLS_ERR_RSA_RNG_FAILED, add tests where the random generator failed. This commit tests the following operations: * psa_generate_random() * psa_generate_key() for a symmetric key * Deterministic signatures that use blinding (RSA PKCS#1v1.5, deterministic ECDSA). * Randomized signatures (RSA PSS, randomized ECDSA). Signed-off-by: Gilles Peskine --- .../suites/test_suite_psa_crypto_entropy.data | 23 ++++++ .../test_suite_psa_crypto_entropy.function | 78 +++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/tests/suites/test_suite_psa_crypto_entropy.data b/tests/suites/test_suite_psa_crypto_entropy.data index 61593e9d6..eec3f1964 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.data +++ b/tests/suites/test_suite_psa_crypto_entropy.data @@ -1,3 +1,26 @@ +PSA external RNG failure: generate random and key +external_rng_failure_generate: + +PSA external RNG failure: randomized ECDSA +depends_on:PSA_WANT_ALG_ECDSA +external_rng_failure_sign:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA_ANY:32 + +PSA external RNG failure: deterministic ECDSA (software implementation) +# Depend on the built-in implementation which we know uses blinding. +# An external implementation might not use blinding. +depends_on:MBEDTLS_PSA_BUILTIN_ALG_ECDSA:MBEDTLS_SHA256_C:PSA_WANT_ALG_SHA256 +external_rng_failure_sign:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):32 + +PSA external RNG failure: RSA-PSS +depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256 +external_rng_failure_sign:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):32 + +PSA external RNG failure: RSA PKCS#1v1.5 (software implementation) +# Depend on the built-in implementation which we know uses blinding. +# An external implementation might not use blinding. +depends_on:MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN +external_rng_failure_sign:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:32 + PSA validate entropy injection: good, minimum size validate_entropy_seed_injection:MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE:PSA_SUCCESS:MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE:PSA_ERROR_NOT_PERMITTED diff --git a/tests/suites/test_suite_psa_crypto_entropy.function b/tests/suites/test_suite_psa_crypto_entropy.function index 7233b17cd..f7a398c04 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.function +++ b/tests/suites/test_suite_psa_crypto_entropy.function @@ -1,5 +1,8 @@ /* BEGIN_HEADER */ #include +#include + +#include #include "mbedtls/entropy.h" #include "mbedtls/entropy_poll.h" @@ -35,6 +38,81 @@ psa_status_t remove_seed_file( void ) /* END_HEADER */ +/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +void external_rng_failure_generate( ) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_type( &attributes, PSA_KEY_TYPE_DERIVE ); + psa_set_key_bits( &attributes, 128 ); + mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT; + uint8_t output[1]; + + PSA_ASSERT( psa_crypto_init( ) ); + + PSA_ASSERT( psa_generate_random( output, sizeof( output ) ) ); + PSA_ASSERT( psa_generate_key( &attributes, &key ) ); + PSA_ASSERT( psa_destroy_key( key ) ); + + mbedtls_test_disable_insecure_external_rng( ); + TEST_EQUAL( PSA_ERROR_INSUFFICIENT_ENTROPY, + psa_generate_random( output, sizeof( output ) ) ); + TEST_EQUAL( PSA_ERROR_INSUFFICIENT_ENTROPY, + psa_generate_key( &attributes, &key ) ); + +exit: + psa_destroy_key( key ); + PSA_DONE( ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +void external_rng_failure_sign( int key_type, data_t *key_data, int alg, + int input_size_arg ) +{ + /* This test case is only expected to pass if the signature mechanism + * requires randomness, either because it is a randomized signature + * or because the implementation uses blinding. */ + + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_type( &attributes, key_type ); + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN ); + psa_set_key_algorithm( &attributes, alg ); + mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT; + size_t input_size = input_size_arg; + uint8_t signature[PSA_SIGNATURE_MAX_SIZE]; + size_t signature_length; + + TEST_ASSERT( input_size <= sizeof( signature ) ); + + PSA_ASSERT( psa_crypto_init( ) ); + PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, + &key ) ); + memset( signature, 0, input_size ); + PSA_ASSERT( psa_sign_hash( key, alg, + signature, input_size, + signature, sizeof( signature ), + &signature_length ) ); + PSA_ASSERT( psa_destroy_key( key ) ); + + mbedtls_test_disable_insecure_external_rng( ); + /* Import the key again, because for RSA Mbed TLS caches blinding values + * in the key object and this could perturb the test. */ + PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, + &key ) ); + memset( signature, 0, input_size ); + TEST_EQUAL( PSA_ERROR_INSUFFICIENT_ENTROPY, + psa_sign_hash( key, alg, + signature, input_size, + signature, sizeof( signature ), + &signature_length ) ); + PSA_ASSERT( psa_destroy_key( key ) ); + +exit: + psa_destroy_key( key ); + PSA_DONE( ); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_PSA_INJECT_ENTROPY */ void validate_entropy_seed_injection( int seed_length_a, int expected_status_a, From ba0c1ffb72415d806eca45415a849862fe0d93a4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Nov 2020 18:03:51 +0100 Subject: [PATCH 13/18] Depend on the built-in implementation when injecting RNG failure When verifying the impact of a forced RNG failure, depend on the built-in implementation of the algorithm that uses randomization, whether it's because the algorithm is randomized or because our implementation uses randomization for (e.g.) blinding. An external implementation could use its own randomness source which is not affected by the forced failure of the RNG driver. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_psa_crypto_entropy.data | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_entropy.data b/tests/suites/test_suite_psa_crypto_entropy.data index eec3f1964..f8d5303a6 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.data +++ b/tests/suites/test_suite_psa_crypto_entropy.data @@ -1,23 +1,25 @@ PSA external RNG failure: generate random and key external_rng_failure_generate: +# When verifying the impact of a forced RNG failure, depend on the built-in +# implementation of the algorithm that uses randomization, whether it's +# because the algorithm is randomized or because our implementation uses +# randomization for (e.g.) blinding. An external implementation could use +# its own randomness source which is not affected by the forced failure of +# the RNG driver. PSA external RNG failure: randomized ECDSA -depends_on:PSA_WANT_ALG_ECDSA +depends_on:MBEDTLS_PSA_BUILTIN_ALG_ECDSA external_rng_failure_sign:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA_ANY:32 PSA external RNG failure: deterministic ECDSA (software implementation) -# Depend on the built-in implementation which we know uses blinding. -# An external implementation might not use blinding. depends_on:MBEDTLS_PSA_BUILTIN_ALG_ECDSA:MBEDTLS_SHA256_C:PSA_WANT_ALG_SHA256 external_rng_failure_sign:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):32 PSA external RNG failure: RSA-PSS -depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256 +depends_on:MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256 external_rng_failure_sign:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):32 PSA external RNG failure: RSA PKCS#1v1.5 (software implementation) -# Depend on the built-in implementation which we know uses blinding. -# An external implementation might not use blinding. depends_on:MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN external_rng_failure_sign:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:32 From 1631514b8e40add9dc3a946227cbace25c260ec2 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Nov 2020 18:06:51 +0100 Subject: [PATCH 14/18] Add missing dependencies on key types Signed-off-by: Gilles Peskine --- tests/suites/test_suite_psa_crypto_entropy.data | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_entropy.data b/tests/suites/test_suite_psa_crypto_entropy.data index f8d5303a6..210e76880 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.data +++ b/tests/suites/test_suite_psa_crypto_entropy.data @@ -7,20 +7,22 @@ external_rng_failure_generate: # randomization for (e.g.) blinding. An external implementation could use # its own randomness source which is not affected by the forced failure of # the RNG driver. +# Key types and non-randomized auxilary algorithms (in practice, hashes) can +# use an external implementation. PSA external RNG failure: randomized ECDSA -depends_on:MBEDTLS_PSA_BUILTIN_ALG_ECDSA +depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PSA_BUILTIN_ALG_ECDSA:MBEDTLS_ECP_DP_SECP256R1_ENABLED external_rng_failure_sign:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA_ANY:32 PSA external RNG failure: deterministic ECDSA (software implementation) -depends_on:MBEDTLS_PSA_BUILTIN_ALG_ECDSA:MBEDTLS_SHA256_C:PSA_WANT_ALG_SHA256 +depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PSA_BUILTIN_ALG_ECDSA:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:PSA_WANT_ALG_SHA256 external_rng_failure_sign:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):32 PSA external RNG failure: RSA-PSS -depends_on:MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256 +depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256 external_rng_failure_sign:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):32 PSA external RNG failure: RSA PKCS#1v1.5 (software implementation) -depends_on:MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN +depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN external_rng_failure_sign:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:32 PSA validate entropy injection: good, minimum size From dbf6896c827f31cc96b1263596cf7bc3a30cfec5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 6 Jan 2021 20:04:23 +0100 Subject: [PATCH 15/18] mbedtls_to_psa_error: prefer dispatching on the low-level error When an Mbed TLS error code combines a low-level error and a high-level error, the low-level error is usually closer to the root cause (for example HW_ACCEL_FAILED or ENTROPY_SOURCE_FAILED is more informative than RSA_PRIVATE_FAILED). So prioritize the low-level code when converting to a PSA error code, rather than the high-level code as was (rather arbitrarily) done before. Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 73f5a6e72..b7c459166 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -135,9 +135,11 @@ mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state = psa_status_t mbedtls_to_psa_error( int ret ) { - /* If there's both a high-level code and low-level code, dispatch on - * the high-level code. */ - switch( ret < -0x7f ? - ( -ret & 0x7f80 ) : ret ) + /* Mbed TLS error codes can combine a high-level error code and a + * low-level error code. The low-level error usually reflects the + * root cause better, so dispatch on that preferably. */ + int low_level_ret = - ( -ret & 0x007f ); + switch( low_level_ret != 0 ? low_level_ret : ret ) { case 0: return( PSA_SUCCESS ); From 3aa5a6414e531452919855c36f10d97cc34a2ec9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 6 Jan 2021 20:06:36 +0100 Subject: [PATCH 16/18] Fix a test dependency Signed-off-by: Gilles Peskine --- tests/suites/test_suite_psa_crypto_entropy.data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_psa_crypto_entropy.data b/tests/suites/test_suite_psa_crypto_entropy.data index 210e76880..0e53b60f2 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.data +++ b/tests/suites/test_suite_psa_crypto_entropy.data @@ -14,7 +14,7 @@ depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PSA_BUILTIN_ALG_ECDSA:MBEDTLS_ external_rng_failure_sign:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA_ANY:32 PSA external RNG failure: deterministic ECDSA (software implementation) -depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PSA_BUILTIN_ALG_ECDSA:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:PSA_WANT_ALG_SHA256 +depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:PSA_WANT_ALG_SHA_256 external_rng_failure_sign:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):32 PSA external RNG failure: RSA-PSS From 6beb327a5ee1642f7ad471fffa87b9f41d48febd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 6 Jan 2021 20:16:26 +0100 Subject: [PATCH 17/18] external_rng_failure_sign: more robust buffer management Don't microoptimize memory usage in tests: use separate buffers for the input and the output. Allocate the input buffer dynamically because the size is a parameter of the test case. Allocate the output buffer dynamically because it's generally good practice in tests so that a memory sanitizer can detect a buffer overflow. Signed-off-by: Gilles Peskine --- .../test_suite_psa_crypto_entropy.function | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_entropy.function b/tests/suites/test_suite_psa_crypto_entropy.function index f7a398c04..8c1fdab1a 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.function +++ b/tests/suites/test_suite_psa_crypto_entropy.function @@ -79,18 +79,20 @@ void external_rng_failure_sign( int key_type, data_t *key_data, int alg, psa_set_key_algorithm( &attributes, alg ); mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT; size_t input_size = input_size_arg; - uint8_t signature[PSA_SIGNATURE_MAX_SIZE]; + uint8_t *input = NULL; + uint8_t *signature = NULL; + size_t signature_size = PSA_SIGNATURE_MAX_SIZE; size_t signature_length; - TEST_ASSERT( input_size <= sizeof( signature ) ); + ASSERT_ALLOC( input, input_size ); + ASSERT_ALLOC( signature, signature_size ); PSA_ASSERT( psa_crypto_init( ) ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &key ) ); - memset( signature, 0, input_size ); PSA_ASSERT( psa_sign_hash( key, alg, - signature, input_size, - signature, sizeof( signature ), + input, input_size, + signature, signature_size, &signature_length ) ); PSA_ASSERT( psa_destroy_key( key ) ); @@ -99,17 +101,18 @@ void external_rng_failure_sign( int key_type, data_t *key_data, int alg, * in the key object and this could perturb the test. */ PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &key ) ); - memset( signature, 0, input_size ); TEST_EQUAL( PSA_ERROR_INSUFFICIENT_ENTROPY, psa_sign_hash( key, alg, - signature, input_size, - signature, sizeof( signature ), + input, input_size, + signature, signature_size, &signature_length ) ); PSA_ASSERT( psa_destroy_key( key ) ); exit: psa_destroy_key( key ); PSA_DONE( ); + mbedtls_free( input ); + mbedtls_free( signature ); } /* END_CASE */ From c85c20147b6df86eb0cc9de62a5541051fb1c1cf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 6 Jan 2021 20:47:16 +0100 Subject: [PATCH 18/18] Don't call TEST_ASSERT in PSA_DONE TEST_ASSERT jumps to the exit label, so it must not be called from cleanup code executed after the exit label. It's legitimate (and indeed very common) to call PSA_DONE in cleanup code, so PSA_DONE must not jump to exit. Define an auxiliary function test_fail_if_psa_leaking() that calls test_fail() with the error message provided by mbedtls_test_helper_is_psa_leaking(). This function currently needs to be in helpers.function rather than in a PSA-specific helper file because it calls test_fail which is defined in helpers.function. Signed-off-by: Gilles Peskine --- tests/include/test/psa_crypto_helpers.h | 30 ++++++++++++++++--------- tests/suites/helpers.function | 20 +++++++++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h index 3e60a9b65..b8eb4aa5d 100644 --- a/tests/include/test/psa_crypto_helpers.h +++ b/tests/include/test/psa_crypto_helpers.h @@ -36,19 +36,29 @@ const char *mbedtls_test_helper_is_psa_leaking( void ); /** Check that no PSA Crypto key slots are in use. + * + * If any slots are in use, mark the current test as failed and jump to + * the exit label. This is equivalent to + * `TEST_ASSERT( ! mbedtls_test_helper_is_psa_leaking( ) )` + * but with a more informative message. */ -#define ASSERT_PSA_PRISTINE( ) \ - TEST_ASSERT( ! mbedtls_test_helper_is_psa_leaking( ) ) +#define ASSERT_PSA_PRISTINE( ) \ + do \ + { \ + if( test_fail_if_psa_leaking( __LINE__, __FILE__ ) ) \ + goto exit; \ + } \ + while( 0 ) /** Shut down the PSA Crypto subsystem. Expect a clean shutdown, with no slots * in use. */ -#define PSA_DONE( ) \ - do \ - { \ - ASSERT_PSA_PRISTINE( ); \ - mbedtls_psa_crypto_free( ); \ - } \ +#define PSA_DONE( ) \ + do \ + { \ + test_fail_if_psa_leaking( __LINE__, __FILE__ ); \ + mbedtls_psa_crypto_free( ); \ + } \ while( 0 ) @@ -60,8 +70,8 @@ const char *mbedtls_test_helper_is_psa_leaking( void ); * disabled by default. * * When MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled and the test - * helpers are linked into a program, you must enable this before any code - * that uses the PSA subsystem to generate random data (including internal + * helpers are linked into a program, you must enable this before running any + * code that uses the PSA subsystem to generate random data (including internal * random generation for purposes such as blinding when the random generation * is routed through PSA). * diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function index 3a9c426b8..1dc672153 100644 --- a/tests/suites/helpers.function +++ b/tests/suites/helpers.function @@ -421,6 +421,26 @@ void test_skip( const char *test, int line_no, const char* filename ) test_info.filename = filename; } +#if defined(MBEDTLS_PSA_CRYPTO_C) +/** Check that no PSA Crypto key slots are in use. + * + * If any slots are in use, mark the current test as failed. + * + * \return 0 if the key store is empty, 1 otherwise. + */ +int test_fail_if_psa_leaking( int line_no, const char *filename ) +{ + const char *msg = mbedtls_test_helper_is_psa_leaking( ); + if( msg == NULL ) + return 0; + else + { + test_fail( msg, line_no, filename ); + return 1; + } +} +#endif /* defined(MBEDTLS_PSA_CRYPTO_C) */ + #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) static int redirect_output( FILE* out_stream, const char* path ) {