From a646345e3fb61573154c98f703ff1b5dc8cd57e2 Mon Sep 17 00:00:00 2001 From: Simon Butcher Date: Thu, 6 Dec 2018 17:41:56 +0000 Subject: [PATCH] Add additional parameter validation tests for the AES module This adds additional tests to validate the AES module parameter validation checks which are enabled using the MBEDTLS_CHECK_PARAMS option. --- tests/suites/helpers.function | 185 +++++++++++++++++++++++++- tests/suites/test_suite_aes.function | 35 ++++- tests/suites/test_suite_aes.rest.data | 4 + 3 files changed, 213 insertions(+), 11 deletions(-) diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function index 32b1b790d..4c105ed3c 100644 --- a/tests/suites/helpers.function +++ b/tests/suites/helpers.function @@ -23,6 +23,11 @@ #include "mbedtls/memory_buffer_alloc.h" #endif +#if defined(MBEDTLS_CHECK_PARAMS) +#include +#define MBEDTLS_PARAM_FAILED(x) mbedtls_param_failed( #x ) +#endif + #ifdef _MSC_VER #include typedef UINT8 uint8_t; @@ -69,15 +74,166 @@ typedef struct data_tag /*----------------------------------------------------------------------------*/ /* Macros */ -#define TEST_ASSERT( TEST ) \ - do { \ - if( ! (TEST) ) \ - { \ - test_fail( #TEST, __LINE__, __FILE__ ); \ - goto exit; \ - } \ +#if defined(MBEDTLS_CHECK_PARAMS) + +/** + * \brief This macro tests the expression passed to it as a test step or + * individual test in a test case. + * + * It allows a library function to return a value and return an error + * code that can be tested. + * + * When MBEDTLS_CHECK_PARAMS is enabled, calls to the parameter failure + * callback, MBEDTLS_PARAM_FAIL, will be assumed to be a test failure. + * + * This macro is not suitable for negative parameter validation tests, + * as it assumes the test step will not create an error. + * + * \param TEST The test expression to be tested. + */ +#define TEST_ASSERT( TEST ) \ + do { \ + if ( setjmp( param_fail_jmp ) == 0 ) \ + { \ + if( ! (TEST) ) \ + { \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + } \ + else \ + { \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + memset( param_fail_jmp, 0, sizeof(jmp_buf) ); \ } while( 0 ) +/** + * \brief This macro tests and individual function call as a test step or + * individual test in a test case. + * + * It does not require a library function to return a value, and cannot + tets a return error code that can be tested. + * + * When MBEDTLS_CHECK_PARAMS is enabled, calls to the parameter failure + * callback, MBEDTLS_PARAM_FAIL, will be assumed to be a test failure. + * + * This macro is not suitable for negative parameter validation tests + * as it assumes the test step will not create an error. + * + * \param TEST The test statement to be executed. + */ +#define TEST_FN( TEST ) \ + do { \ + if ( setjmp( param_fail_jmp ) == 0 ) \ + { \ + TEST; \ + } \ + else \ + { \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + memset( param_fail_jmp, 0, sizeof(jmp_buf) ); \ + } while( 0 ) + +/** + * \brief This macro tests the statement passed to it as a test step or + * individual test in a test case. The macro assumes the test will fail + * and will generate an error. + * + * It allows a library function to return a value and tests the return + * code on return to confirm the given error code was returned. + * + * When MBEDTLS_CHECK_PARAMS is enabled, calls to the parameter failure + * callback, MBEDTLS_PARAM_FAIL, are assumed to indicate the + * expected failure, and the test will pass. + * + * This macro is intended for negative parameter validation tests, + * where the failing function may return an error value or call + * MBEDTLS_PARAM_FAIL to indicate the error. + * + * \param PARAM_ERROR_VALUE The expected error code. + * + * \param TEST The test expression to be tested. + */ +#define TEST_INVALID_PARAM_RET( PARAM_ERR_VALUE, TEST ) \ + do { \ + if ( setjmp( param_fail_jmp ) == 0 ) \ + { \ + if( (TEST) != PARAM_ERR_VALUE) \ + { \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + } \ + memset( param_fail_jmp, 0, sizeof(jmp_buf) ); \ + } while( 0 ) + +/** + * \brief This macro tests the statement passed to it as a test step or + * individual test in a test case. The macro assumes the test will fail + * and will generate an error. + * + * It assumes the library function under test cannot return a value and + * assumes errors can only be indicated byt calls to + * MBEDTLS_PARAM_FAIL. + * + * When MBEDTLS_CHECK_PARAMS is enabled, calls to the parameter failure + * callback, MBEDTLS_PARAM_FAIL, are assumed to indicate the + * expected failure. If MBEDTLS_CHECK_PARAMS is not enabled, no test + * can be made. + * + * This macro is intended for negative parameter validation tests, + * where the failing function can only return an error by calling + * MBEDTLS_PARAM_FAIL to indicate the error. + * + * \param TEST The test expression to be tested. + */ +#define TEST_INVALID_PARAM( TEST ) \ + do { \ + if ( setjmp( param_fail_jmp ) == 0 ) \ + { \ + TEST; \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + memset( param_fail_jmp, 0, sizeof(jmp_buf) ); \ + } while( 0 ) + +#else + +#define TEST_ASSERT( TEST ) \ + do { \ + if( ! (TEST) ) \ + { \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + } while( 0 ) + +#define TEST_FN( TEST ) \ + do { \ + TEST; \ + } while( 0 ) + +#define TEST_INVALID_PARAM_RET( PARAM_ERR_VALUE, TEST ) \ + do { \ + if( (TEST) != (PARAM_ERR_VALUE) ) \ + { \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + } while( 0 ) + +#define TEST_INVALID_PARAM( TEST ) \ + do { \ + TEST; \ + } while( 0 ) + +#endif /* !defined( MBEDTLS_CHECK_PARAMS ) */ + #define assert(a) if( !( a ) ) \ { \ mbedtls_fprintf( stderr, "Assertion Failed at %s:%d - %s\n", \ @@ -126,6 +282,10 @@ test_info; mbedtls_platform_context platform_ctx; #endif +#if defined(MBEDTLS_CHECK_PARAMS) +jmp_buf param_fail_jmp; +#endif + /*----------------------------------------------------------------------------*/ /* Helper flags for complex dependencies */ @@ -159,6 +319,17 @@ static void platform_teardown() #endif /* MBEDTLS_PLATFORM_C */ } +#if defined(MBEDTLS_CHECK_PARAMS) +void mbedtls_param_failed( char* failure_condition, char* file, int line ) +{ + (void)failure_condition; + (void)file; + (void)line; + + longjmp( param_fail_jmp, 1 ); +} +#endif + #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) static int redirect_output( FILE** out_stream, const char* path ) { diff --git a/tests/suites/test_suite_aes.function b/tests/suites/test_suite_aes.function index a797e699c..24b5e4d6e 100644 --- a/tests/suites/test_suite_aes.function +++ b/tests/suites/test_suite_aes.function @@ -15,8 +15,8 @@ void aes_encrypt_ecb( data_t * key_str, data_t * src_str, mbedtls_aes_context ctx; memset(output, 0x00, 100); - mbedtls_aes_init( &ctx ); + TEST_FN( mbedtls_aes_init( &ctx ) ); TEST_ASSERT( mbedtls_aes_setkey_enc( &ctx, key_str->x, key_str->len * 8 ) == setkey_result ); if( setkey_result == 0 ) @@ -39,8 +39,8 @@ void aes_decrypt_ecb( data_t * key_str, data_t * src_str, mbedtls_aes_context ctx; memset(output, 0x00, 100); - mbedtls_aes_init( &ctx ); + TEST_FN( mbedtls_aes_init( &ctx ) ); TEST_ASSERT( mbedtls_aes_setkey_dec( &ctx, key_str->x, key_str->len * 8 ) == setkey_result ); if( setkey_result == 0 ) @@ -64,8 +64,8 @@ void aes_encrypt_cbc( data_t * key_str, data_t * iv_str, mbedtls_aes_context ctx; memset(output, 0x00, 100); - mbedtls_aes_init( &ctx ); + TEST_FN( mbedtls_aes_init( &ctx ) ); mbedtls_aes_setkey_enc( &ctx, key_str->x, key_str->len * 8 ); TEST_ASSERT( mbedtls_aes_crypt_cbc( &ctx, MBEDTLS_AES_ENCRYPT, src_str->len, iv_str->x, src_str->x, output ) == cbc_result ); @@ -91,7 +91,6 @@ void aes_decrypt_cbc( data_t * key_str, data_t * iv_str, memset(output, 0x00, 100); mbedtls_aes_init( &ctx ); - mbedtls_aes_setkey_dec( &ctx, key_str->x, key_str->len * 8 ); TEST_ASSERT( mbedtls_aes_crypt_cbc( &ctx, MBEDTLS_AES_DECRYPT, src_str->len, iv_str->x, src_str->x, output ) == cbc_result ); if( cbc_result == 0) @@ -372,6 +371,34 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void aes_invalid_param( ) +{ + mbedtls_aes_context dummy_ctx; + const unsigned char key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + + TEST_INVALID_PARAM( mbedtls_aes_init( NULL ) ); + + /* mbedtls_aes_setkey_enc() */ + TEST_INVALID_PARAM_RET( MBEDTLS_ERR_AES_BAD_INPUT_DATA, + mbedtls_aes_setkey_enc( NULL, key, 128 ) ); + + TEST_INVALID_PARAM_RET( MBEDTLS_ERR_AES_BAD_INPUT_DATA, + mbedtls_aes_setkey_enc( &dummy_ctx, NULL, 128 ) ); + + /* mbedtls_aes_setkey_dec() */ + TEST_INVALID_PARAM_RET( MBEDTLS_ERR_AES_BAD_INPUT_DATA, + mbedtls_aes_setkey_dec( NULL, key, 128 ) ); + + TEST_INVALID_PARAM_RET( MBEDTLS_ERR_AES_BAD_INPUT_DATA, + mbedtls_aes_setkey_dec( &dummy_ctx, NULL, 128 ) ); + + +exit: + return; +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */ void aes_selftest( ) { diff --git a/tests/suites/test_suite_aes.rest.data b/tests/suites/test_suite_aes.rest.data index bbb222f10..3ec916ded 100644 --- a/tests/suites/test_suite_aes.rest.data +++ b/tests/suites/test_suite_aes.rest.data @@ -10,6 +10,10 @@ aes_encrypt_cbc:"000000000000000000000000000000000000000000000000000000000000000 AES-256-CBC Decrypt (Invalid input length) aes_decrypt_cbc:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"623a52fcea5d443e48d9181ab32c74":"":MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH +AES - Invalid parameters +depends_on:MBEDTLS_CHECK_PARAMS +aes_invalid_param: + AES Selftest depends_on:MBEDTLS_SELF_TEST aes_selftest: