From 881447d4113d2903cee3446fa1df4c725bde1a5c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Dec 2022 15:24:52 +0100 Subject: [PATCH] Move bignum helpers to their own module Move bignum-related helper functions to their own files under tests/include and tests/src. The primary motivation is that a subsequent commit will make bignum_helpers.h include library/bignum*.h, but we want to be able to include without having the library directory on the include path (we do this in some programs under programs/ intended for testing). Signed-off-by: Gilles Peskine --- tests/include/test/bignum_helpers.h | 90 +++++++++++++++++++++ tests/include/test/helpers.h | 67 +++------------- tests/src/bignum_helpers.c | 119 ++++++++++++++++++++++++++++ tests/src/helpers.c | 87 +------------------- tests/suites/helpers.function | 1 + 5 files changed, 224 insertions(+), 140 deletions(-) create mode 100644 tests/include/test/bignum_helpers.h create mode 100644 tests/src/bignum_helpers.c diff --git a/tests/include/test/bignum_helpers.h b/tests/include/test/bignum_helpers.h new file mode 100644 index 000000000..22ce7f76f --- /dev/null +++ b/tests/include/test/bignum_helpers.h @@ -0,0 +1,90 @@ +/** + * \file bignum_helpers.h + * + * \brief This file contains the prototypes of helper functions for + * bignum-related testing. + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEST_BIGNUM_HELPERS_H +#define TEST_BIGNUM_HELPERS_H + +#include + +#if defined(MBEDTLS_BIGNUM_C) + +#include + +/** Allocate and populate a core MPI from a test case argument. + * + * This function allocates exactly as many limbs as necessary to fit + * the length of the input. In other words, it preserves leading zeros. + * + * The limb array is allocated with mbedtls_calloc() and must later be + * freed with mbedtls_free(). + * + * \param[in,out] pX The address where a pointer to the allocated limb + * array will be stored. + * \c *pX must be null on entry. + * On exit, \c *pX is null on error or if the number + * of limbs is 0. + * \param[out] plimbs The address where the number of limbs will be stored. + * \param[in] input The test argument to read. + * It is interpreted as a hexadecimal representation + * of a non-negative integer. + * + * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise. + */ +int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs, + const char *input ); + +/** Read an MPI from a hexadecimal string. + * + * Like mbedtls_mpi_read_string(), but with tighter guarantees around + * edge cases. + * + * - This function guarantees that if \p s begins with '-' then the sign + * bit of the result will be negative, even if the value is 0. + * When this function encounters such a "negative 0", it + * increments #mbedtls_test_case_uses_negative_0. + * - The size of the result is exactly the minimum number of limbs needed + * to fit the digits in the input. In particular, this function constructs + * a bignum with 0 limbs for an empty string, and a bignum with leading 0 + * limbs if the string has sufficiently many leading 0 digits. + * This is important so that the "0 (null)" and "0 (1 limb)" and + * "leading zeros" test cases do what they claim. + * + * \param[out] X The MPI object to populate. It must be initialized. + * \param[in] s The null-terminated hexadecimal string to read from. + * + * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise. + */ +int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s ); + +/** Nonzero if the current test case had an input parsed with + * mbedtls_test_read_mpi() that is a negative 0 (`"-"`, `"-0"`, `"-00"`, etc., + * constructing a result with the sign bit set to -1 and the value being + * all-limbs-0, which is not a valid representation in #mbedtls_mpi but is + * tested for robustness). + */ +extern unsigned mbedtls_test_case_uses_negative_0; + +#endif /* MBEDTLS_BIGNUM_C */ + +#endif /* TEST_BIGNUM_HELPERS_H */ diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h index 5f9bde697..b64bfcbce 100644 --- a/tests/include/test/helpers.h +++ b/tests/include/test/helpers.h @@ -215,6 +215,17 @@ void mbedtls_test_hexify( unsigned char *obuf, const unsigned char *ibuf, int len ); +/** + * \brief Convert hexadecimal digit to an integer. + * + * \param c The digit to convert (`'0'` to `'9'`, `'A'` to `'F'` or + * `'a'` to `'f'`). + * \param[out] uc On success, the value of the digit (0 to 15). + * + * \return 0 on success, -1 if \p c is not a hexadecimal digit. + */ +int mbedtls_test_ascii2uc(const char c, unsigned char *uc); + /** * Allocate and zeroize a buffer. * @@ -269,60 +280,4 @@ void mbedtls_test_err_add_check( int high, int low, const char *file, int line); #endif -#if defined(MBEDTLS_BIGNUM_C) -/** Allocate and populate a core MPI from a test case argument. - * - * This function allocates exactly as many limbs as necessary to fit - * the length of the input. In other words, it preserves leading zeros. - * - * The limb array is allocated with mbedtls_calloc() and must later be - * freed with mbedtls_free(). - * - * \param[in,out] pX The address where a pointer to the allocated limb - * array will be stored. - * \c *pX must be null on entry. - * On exit, \c *pX is null on error or if the number - * of limbs is 0. - * \param[out] plimbs The address where the number of limbs will be stored. - * \param[in] input The test argument to read. - * It is interpreted as a hexadecimal representation - * of a non-negative integer. - * - * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise. - */ -int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs, - const char *input ); - -/** Read an MPI from a hexadecimal string. - * - * Like mbedtls_mpi_read_string(), but with tighter guarantees around - * edge cases. - * - * - This function guarantees that if \p s begins with '-' then the sign - * bit of the result will be negative, even if the value is 0. - * When this function encounters such a "negative 0", it - * increments #mbedtls_test_case_uses_negative_0. - * - The size of the result is exactly the minimum number of limbs needed - * to fit the digits in the input. In particular, this function constructs - * a bignum with 0 limbs for an empty string, and a bignum with leading 0 - * limbs if the string has sufficiently many leading 0 digits. - * This is important so that the "0 (null)" and "0 (1 limb)" and - * "leading zeros" test cases do what they claim. - * - * \param[out] X The MPI object to populate. It must be initialized. - * \param[in] s The null-terminated hexadecimal string to read from. - * - * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise. - */ -int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s ); - -/** Nonzero if the current test case had an input parsed with - * mbedtls_test_read_mpi() that is a negative 0 (`"-"`, `"-0"`, `"-00"`, etc., - * constructing a result with the sign bit set to -1 and the value being - * all-limbs-0, which is not a valid representation in #mbedtls_mpi but is - * tested for robustness). - */ -extern unsigned mbedtls_test_case_uses_negative_0; -#endif /* MBEDTLS_BIGNUM_C */ - #endif /* TEST_HELPERS_H */ diff --git a/tests/src/bignum_helpers.c b/tests/src/bignum_helpers.c new file mode 100644 index 000000000..575bd03de --- /dev/null +++ b/tests/src/bignum_helpers.c @@ -0,0 +1,119 @@ +/** + * \file bignum_helpers.c + * + * \brief This file contains the prototypes of helper functions for + * bignum-related testing. + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define MBEDTLS_ALLOW_PRIVATE_ACCESS +#include + +#if defined(MBEDTLS_BIGNUM_C) + +#include +#include + +#include +#include +#include +#include + +#include +#include + +int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs, + const char *input ) +{ + /* Sanity check */ + if( *pX != NULL ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + size_t hex_len = strlen( input ); + size_t byte_len = ( hex_len + 1 ) / 2; + *plimbs = CHARS_TO_LIMBS( byte_len ); + + /* A core bignum is not allowed to be empty. Forbid it as test data, + * this way static analyzers have a chance of knowing we don't expect + * the bignum functions to support empty inputs. */ + if( *plimbs == 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + *pX = mbedtls_calloc( *plimbs, sizeof( **pX ) ); + if( *pX == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + unsigned char *byte_start = ( unsigned char * ) *pX; + if( byte_len % sizeof( mbedtls_mpi_uint ) != 0 ) + { + byte_start += sizeof( mbedtls_mpi_uint ) - byte_len % sizeof( mbedtls_mpi_uint ); + } + if( ( hex_len & 1 ) != 0 ) + { + /* mbedtls_test_unhexify wants an even number of hex digits */ + TEST_ASSERT( mbedtls_test_ascii2uc( *input, byte_start ) == 0 ); + ++byte_start; + ++input; + --byte_len; + } + TEST_ASSERT( mbedtls_test_unhexify( byte_start, + byte_len, + input, + &byte_len ) == 0 ); + + mbedtls_mpi_core_bigendian_to_host( *pX, *plimbs ); + return( 0 ); + +exit: + mbedtls_free( *pX ); + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); +} + +int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s ) +{ + int negative = 0; + /* Always set the sign bit to -1 if the input has a minus sign, even for 0. + * This creates an invalid representation, which mbedtls_mpi_read_string() + * avoids but we want to be able to create that in test data. */ + if( s[0] == '-' ) + { + ++s; + negative = 1; + } + /* mbedtls_mpi_read_string() currently retains leading zeros. + * It always allocates at least one limb for the value 0. */ + if( s[0] == 0 ) + { + mbedtls_mpi_free( X ); + return( 0 ); + } + int ret = mbedtls_mpi_read_string( X, 16, s ); + if( ret != 0 ) + return( ret ); + if( negative ) + { + if( mbedtls_mpi_cmp_int( X, 0 ) == 0 ) + ++mbedtls_test_case_uses_negative_0; + X->s = -1; + } + return( 0 ); +} + +#endif /* MBEDTLS_BIGNUM_C */ + diff --git a/tests/src/helpers.c b/tests/src/helpers.c index 7c83714f1..be5c465fd 100644 --- a/tests/src/helpers.c +++ b/tests/src/helpers.c @@ -48,7 +48,7 @@ void mbedtls_test_platform_teardown( void ) #endif /* MBEDTLS_PLATFORM_C */ } -static int ascii2uc(const char c, unsigned char *uc) +int mbedtls_test_ascii2uc(const char c, unsigned char *uc) { if( ( c >= '0' ) && ( c <= '9' ) ) *uc = c - '0'; @@ -207,10 +207,10 @@ int mbedtls_test_unhexify( unsigned char *obuf, while( *ibuf != 0 ) { - if ( ascii2uc( *(ibuf++), &uc ) != 0 ) + if ( mbedtls_test_ascii2uc( *(ibuf++), &uc ) != 0 ) return( -1 ); - if ( ascii2uc( *(ibuf++), &uc2 ) != 0 ) + if ( mbedtls_test_ascii2uc( *(ibuf++), &uc2 ) != 0 ) return( -1 ); *(obuf++) = ( uc << 4 ) | uc2; @@ -350,84 +350,3 @@ void mbedtls_test_err_add_check( int high, int low, } } #endif /* MBEDTLS_TEST_HOOKS */ - -#if defined(MBEDTLS_BIGNUM_C) -#include "bignum_core.h" - -int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs, - const char *input ) -{ - /* Sanity check */ - if( *pX != NULL ) - return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); - - size_t hex_len = strlen( input ); - size_t byte_len = ( hex_len + 1 ) / 2; - *plimbs = CHARS_TO_LIMBS( byte_len ); - - /* A core bignum is not allowed to be empty. Forbid it as test data, - * this way static analyzers have a chance of knowing we don't expect - * the bignum functions to support empty inputs. */ - if( *plimbs == 0 ) - return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); - - *pX = mbedtls_calloc( *plimbs, sizeof( **pX ) ); - if( *pX == NULL ) - return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); - - unsigned char *byte_start = ( unsigned char * ) *pX; - if( byte_len % sizeof( mbedtls_mpi_uint ) != 0 ) - { - byte_start += sizeof( mbedtls_mpi_uint ) - byte_len % sizeof( mbedtls_mpi_uint ); - } - if( ( hex_len & 1 ) != 0 ) - { - /* mbedtls_test_unhexify wants an even number of hex digits */ - TEST_ASSERT( ascii2uc( *input, byte_start ) == 0 ); - ++byte_start; - ++input; - --byte_len; - } - TEST_ASSERT( mbedtls_test_unhexify( byte_start, - byte_len, - input, - &byte_len ) == 0 ); - - mbedtls_mpi_core_bigendian_to_host( *pX, *plimbs ); - return( 0 ); - -exit: - mbedtls_free( *pX ); - return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); -} - -int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s ) -{ - int negative = 0; - /* Always set the sign bit to -1 if the input has a minus sign, even for 0. - * This creates an invalid representation, which mbedtls_mpi_read_string() - * avoids but we want to be able to create that in test data. */ - if( s[0] == '-' ) - { - ++s; - negative = 1; - } - /* mbedtls_mpi_read_string() currently retains leading zeros. - * It always allocates at least one limb for the value 0. */ - if( s[0] == 0 ) - { - mbedtls_mpi_free( X ); - return( 0 ); - } - int ret = mbedtls_mpi_read_string( X, 16, s ); - if( ret != 0 ) - return( ret ); - if( negative ) - { - if( mbedtls_mpi_cmp_int( X, 0 ) == 0 ) - ++mbedtls_test_case_uses_negative_0; - X->s = -1; - } - return( 0 ); -} -#endif diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function index fe33f9bf9..82495644e 100644 --- a/tests/suites/helpers.function +++ b/tests/suites/helpers.function @@ -5,6 +5,7 @@ #include #include #include +#include #include #include