#line 2 "suites/helpers.function" /*----------------------------------------------------------------------------*/ /* Headers */ #include #include #include #include #if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" #else #include #define mbedtls_fprintf fprintf #define mbedtls_snprintf snprintf #define mbedtls_calloc calloc #define mbedtls_free free #define mbedtls_exit exit #define mbedtls_time time #define mbedtls_time_t time_t #define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS #define MBEDTLS_EXIT_FAILURE EXIT_FAILURE #endif #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) #include "mbedtls/memory_buffer_alloc.h" #endif #if defined(MBEDTLS_CHECK_PARAMS) #include "mbedtls/platform_util.h" #include #endif #ifdef _MSC_VER #include typedef UINT8 uint8_t; typedef INT32 int32_t; typedef UINT32 uint32_t; #define strncasecmp _strnicmp #define strcasecmp _stricmp #else #include #endif #include #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include #include #endif /* Type for Hex parameters */ typedef struct data_tag { uint8_t * x; uint32_t len; } data_t; /*----------------------------------------------------------------------------*/ /* Status and error constants */ #define DEPENDENCY_SUPPORTED 0 /* Dependency supported by build */ #define KEY_VALUE_MAPPING_FOUND 0 /* Integer expression found */ #define DISPATCH_TEST_SUCCESS 0 /* Test dispatch successful */ #define KEY_VALUE_MAPPING_NOT_FOUND -1 /* Integer expression not found */ #define DEPENDENCY_NOT_SUPPORTED -2 /* Dependency not supported */ #define DISPATCH_TEST_FN_NOT_FOUND -3 /* Test function not found */ #define DISPATCH_INVALID_TEST_DATA -4 /* Invalid test parameter type. Only int, string, binary data and integer expressions are allowed */ #define DISPATCH_UNSUPPORTED_SUITE -5 /* Test suite not supported by the build */ /*----------------------------------------------------------------------------*/ /* Macros */ /** * \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_FAILED(), 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. * * Failing the test means: * - Mark this test case as failed. * - Print a message identifying the failure. * - Jump to the \c exit label. * * This macro expands to an instruction, not an expression. * It may jump to the \c exit label. * * \param TEST The test expression to be tested. */ #define TEST_ASSERT( TEST ) \ do { \ if( ! (TEST) ) \ { \ test_fail( #TEST, __LINE__, __FILE__ ); \ goto exit; \ } \ } while( 0 ) /** Evaluate two expressions and fail the test case if they have different * values. * * \param expr1 An expression to evaluate. * \param expr2 The expected value of \p expr1. This can be any * expression, but it is typically a constant. */ #define TEST_EQUAL( expr1, expr2 ) \ TEST_ASSERT( ( expr1 ) == ( expr2 ) ) /** Allocate memory dynamically and fail the test case if this fails. * * You must set \p pointer to \c NULL before calling this macro and * put `mbedtls_free( pointer )` in the test's cleanup code. * * If \p length is zero, the resulting \p pointer will be \c NULL. * This is usually what we want in tests since API functions are * supposed to accept null pointers when a buffer size is zero. * * This macro expands to an instruction, not an expression. * It may jump to the \c exit label. * * \param pointer An lvalue where the address of the allocated buffer * will be stored. * This expression may be evaluated multiple times. * \param length Number of elements to allocate. * This expression may be evaluated multiple times. * */ #define ASSERT_ALLOC( pointer, length ) \ do \ { \ TEST_ASSERT( ( pointer ) == NULL ); \ if( ( length ) != 0 ) \ { \ ( pointer ) = mbedtls_calloc( sizeof( *( pointer ) ), \ ( length ) ); \ TEST_ASSERT( ( pointer ) != NULL ); \ } \ } \ while( 0 ) /** Allocate memory dynamically. If the allocation fails, skip the test case. * * This macro behaves like #ASSERT_ALLOC, except that if the allocation * fails, it marks the test as skipped rather than failed. */ #define ASSERT_ALLOC_WEAK( pointer, length ) \ do \ { \ TEST_ASSERT( ( pointer ) == NULL ); \ if( ( length ) != 0 ) \ { \ ( pointer ) = mbedtls_calloc( sizeof( *( pointer ) ), \ ( length ) ); \ TEST_ASSUME( ( pointer ) != NULL ); \ } \ } \ while( 0 ) /** Compare two buffers and fail the test case if they differ. * * This macro expands to an instruction, not an expression. * It may jump to the \c exit label. * * \param p1 Pointer to the start of the first buffer. * \param size1 Size of the first buffer in bytes. * This expression may be evaluated multiple times. * \param p2 Pointer to the start of the second buffer. * \param size2 Size of the second buffer in bytes. * This expression may be evaluated multiple times. */ #define ASSERT_COMPARE( p1, size1, p2, size2 ) \ do \ { \ TEST_ASSERT( ( size1 ) == ( size2 ) ); \ if( ( size1 ) != 0 ) \ TEST_ASSERT( memcmp( ( p1 ), ( p2 ), ( size1 ) ) == 0 ); \ } \ while( 0 ) /** * \brief This macro tests the expression passed to it and skips the * running test if it doesn't evaluate to 'true'. * * \param TEST The test expression to be tested. */ #define TEST_ASSUME( TEST ) \ do { \ if( ! (TEST) ) \ { \ test_skip( #TEST, __LINE__, __FILE__ ); \ goto exit; \ } \ } while( 0 ) #if defined(MBEDTLS_CHECK_PARAMS) && !defined(MBEDTLS_PARAM_FAILED_ALT) /** * \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_FAILED(), 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_FAILED() 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 { \ mbedtls_test_param_failed_expect_call( ); \ if( ( ( TEST ) != ( PARAM_ERR_VALUE ) ) || \ ( mbedtls_test_param_failed_check_expected_call( ) != 0 ) ) \ { \ test_fail( #TEST, __LINE__, __FILE__ ); \ goto exit; \ } \ mbedtls_test_param_failed_check_expected_call( ); \ } 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_FAILED(). * * When MBEDTLS_CHECK_PARAMS is enabled, calls to the parameter failure * callback, MBEDTLS_PARAM_FAILED(), 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_FAILED() to indicate the error. * * \param TEST The test expression to be tested. */ #define TEST_INVALID_PARAM( TEST ) \ do { \ memcpy( jmp_tmp, mbedtls_test_param_failed_get_state_buf( ), \ sizeof( jmp_tmp ) ); \ if( setjmp( mbedtls_test_param_failed_get_state_buf( ) ) == 0 ) \ { \ TEST; \ test_fail( #TEST, __LINE__, __FILE__ ); \ goto exit; \ } \ mbedtls_test_param_failed_reset_state( ); \ } while( 0 ) #endif /* MBEDTLS_CHECK_PARAMS && !MBEDTLS_PARAM_FAILED_ALT */ /** * \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 not fail. * * It assumes the library function under test cannot return a value and * assumes errors can only be indicated by calls to * MBEDTLS_PARAM_FAILED(). * * When MBEDTLS_CHECK_PARAMS is enabled, calls to the parameter failure * callback, MBEDTLS_PARAM_FAILED(), are assumed to indicate the * expected failure. If MBEDTLS_CHECK_PARAMS is not enabled, no test * can be made. * * This macro is intended to test that functions returning void * accept all of the parameter values they're supposed to accept - eg * that they don't call MBEDTLS_PARAM_FAILED() when a parameter * that's allowed to be NULL happens to be NULL. * * Note: for functions that return something other that void, * checking that they accept all the parameters they're supposed to * accept is best done by using TEST_ASSERT() and checking the return * value as well. * * Note: this macro is available even when #MBEDTLS_CHECK_PARAMS is * disabled, as it makes sense to check that the functions accept all * legal values even if this option is disabled - only in that case, * the test is more about whether the function segfaults than about * whether it invokes MBEDTLS_PARAM_FAILED(). * * \param TEST The test expression to be tested. */ #define TEST_VALID_PARAM( TEST ) \ TEST_ASSERT( ( TEST, 1 ) ); /** Allocate memory dynamically and fail the test case if this fails. * * You must set \p pointer to \c NULL before calling this macro and * put `mbedtls_free( pointer )` in the test's cleanup code. * * If \p length is zero, the resulting \p pointer will be \c NULL. * This is usually what we want in tests since API functions are * supposed to accept null pointers when a buffer size is zero. * * This macro expands to an instruction, not an expression. * It may jump to the \c exit label. * * \param pointer An lvalue where the address of the allocated buffer * will be stored. * This expression may be evaluated multiple times. * \param length Number of elements to allocate. * This expression may be evaluated multiple times. * */ #define ASSERT_ALLOC( pointer, length ) \ do \ { \ TEST_ASSERT( ( pointer ) == NULL ); \ if( ( length ) != 0 ) \ { \ ( pointer ) = mbedtls_calloc( sizeof( *( pointer ) ), \ ( length ) ); \ TEST_ASSERT( ( pointer ) != NULL ); \ } \ } \ while( 0 ) /*----------------------------------------------------------------------------*/ /* Global variables */ typedef enum { TEST_RESULT_SUCCESS = 0, TEST_RESULT_FAILED, TEST_RESULT_SKIPPED } test_result_t; typedef struct { test_result_t result; const char *test; const char *filename; int line_no; unsigned long step; } test_info_t; static test_info_t test_info; #if defined(MBEDTLS_CHECK_PARAMS) typedef struct { const char *failure_condition; const char *file; int line; } mbedtls_test_param_failed_location_record_t; typedef struct { uint8_t expected_call; uint8_t expected_call_happened; jmp_buf state; mbedtls_test_param_failed_location_record_t location_record; } param_failed_ctx_t; static param_failed_ctx_t param_failed_ctx; jmp_buf jmp_tmp; #endif /*----------------------------------------------------------------------------*/ /* Helper flags for complex dependencies */ /* Indicates whether we expect mbedtls_entropy_init * to initialize some strong entropy source. */ #if defined(MBEDTLS_TEST_NULL_ENTROPY) || \ ( !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) && \ ( !defined(MBEDTLS_NO_PLATFORM_ENTROPY) || \ defined(MBEDTLS_HAVEGE_C) || \ defined(MBEDTLS_ENTROPY_HARDWARE_ALT) || \ defined(ENTROPY_NV_SEED) ) ) #define ENTROPY_HAVE_STRONG #endif /*----------------------------------------------------------------------------*/ /* Helper Functions */ /** Set the test step number for failure reports. * * Call this function to display "step NNN" in addition to the line number * and file name if a test fails. Typically the "step number" is the index * of a for loop but it can be whatever you want. * * \param step The step number to report. */ void test_set_step( unsigned long step ) { test_info.step = step; } void test_fail( const char *test, int line_no, const char* filename ) { test_info.result = TEST_RESULT_FAILED; test_info.test = test; test_info.line_no = line_no; test_info.filename = filename; } void test_skip( const char *test, int line_no, const char* filename ) { test_info.result = TEST_RESULT_SKIPPED; test_info.test = test; test_info.line_no = line_no; test_info.filename = filename; } #if defined(MBEDTLS_CHECK_PARAMS) /** * \brief Get the location record of the last call to * mbedtls_test_param_failed(). * * \note The call expectation is set up and active until the next call to * mbedtls_test_param_failed_check_expected_call() or * mbedtls_param_failed() that cancels it. */ void mbedtls_test_param_failed_get_location_record( mbedtls_test_param_failed_location_record_t *location_record ) { *location_record = param_failed_ctx.location_record; } /** * \brief State that a call to mbedtls_param_failed() is expected. * * \note The call expectation is set up and active until the next call to * mbedtls_test_param_failed_check_expected_call() or * mbedtls_param_failed that cancel it. */ void mbedtls_test_param_failed_expect_call( void ) { param_failed_ctx.expected_call_happened = 0; param_failed_ctx.expected_call = 1; } /** * \brief Check whether mbedtls_param_failed() has been called as expected. * * \note Check whether mbedtls_param_failed() has been called between the * last call to mbedtls_test_param_failed_expect_call() and the call * to this function. * * \return \c 0 Since the last call to mbedtls_param_failed_expect_call(), * mbedtls_param_failed() has been called. * \c -1 Otherwise. */ int mbedtls_test_param_failed_check_expected_call( void ) { param_failed_ctx.expected_call = 0; if( param_failed_ctx.expected_call_happened != 0 ) return( 0 ); return( -1 ); } /** * \brief Get a pointer to the object of type jmp_buf holding the execution * state information used by mbedtls_param_failed() to do a long jump. * * \note If a call to mbedtls_param_failed() is not expected in the sense * that there is no call to mbedtls_test_param_failed_expect_call() * preceding it, then mbedtls_param_failed() will try to restore the * execution to the state stored in the jmp_buf object whose address * is returned by the present function. * * \note The returned pointer is of type void* as its type is opaque, * implementation dependent (jmp_buf is an array type not the type of * one element of an array). * * \return Address of the object of type jmp_buf holding the execution state * information used by mbedtls_param_failed() to do a long jump. */ void* mbedtls_test_param_failed_get_state_buf( void ) { return ¶m_failed_ctx.state[0]; } /** * \brief Reset the execution state used by mbedtls_param_failed() to do a * long jump. * * \note If a call to mbedtls_param_failed() is not expected in the sense * that there is no call to mbedtls_test_param_failed_expect_call() * preceding it, then mbedtls_param_failed() will try to restore the * execution state that this function reset. * * \note It is recommended to reset the execution state when the state * is not relevant anymore. That way an unexpected call to * mbedtls_param_failed() will not trigger a long jump with * undefined behavior but rather a long jump that will rather fault. */ void mbedtls_test_param_failed_reset_state( void ) { memset( param_failed_ctx.state, 0, sizeof( param_failed_ctx.state ) ); } void mbedtls_param_failed( const char *failure_condition, const char *file, int line ) { /* Record the location of the failure */ param_failed_ctx.location_record.failure_condition = failure_condition; param_failed_ctx.location_record.file = file; param_failed_ctx.location_record.line = line; /* If we are testing the callback function... */ if( param_failed_ctx.expected_call != 0 ) { param_failed_ctx.expected_call = 0; param_failed_ctx.expected_call_happened = 1; } else { /* ...else try a long jump. If the execution state has not been set-up * or reset then the long jump buffer is all zero's and the call will * with high probability fault, emphasizing there is something to look * at. */ longjmp( param_failed_ctx.state, 1 ); } } #endif #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) static int redirect_output( FILE** out_stream, const char* path ) { int stdout_fd = dup( fileno( *out_stream ) ); if( stdout_fd == -1 ) { return -1; } fflush( *out_stream ); fclose( *out_stream ); *out_stream = fopen( path, "w" ); if( *out_stream == NULL ) { close( stdout_fd ); return -1; } return stdout_fd; } static int restore_output( FILE** out_stream, int old_fd ) { fflush( *out_stream ); fclose( *out_stream ); *out_stream = fdopen( old_fd, "w" ); if( *out_stream == NULL ) { return -1; } return 0; } static void close_output( FILE* out_stream ) { fclose( out_stream ); } #endif /* __unix__ || __APPLE__ __MACH__ */