From 881447d4113d2903cee3446fa1df4c725bde1a5c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Dec 2022 15:24:52 +0100 Subject: [PATCH 01/31] 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 0000000000..22ce7f76fc --- /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 5f9bde697b..b64bfcbcef 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 0000000000..575bd03de3 --- /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 7c83714f19..be5c465fd9 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 fe33f9bf9b..82495644e3 100644 --- a/tests/suites/helpers.function +++ b/tests/suites/helpers.function @@ -5,6 +5,7 @@ #include #include #include +#include #include #include From 195f998107d59dffb11cd422680042302c9d5ea7 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Dec 2022 22:59:54 +0100 Subject: [PATCH 02/31] New helper function to allocate and read a modulus When including , the library/ directory now needs to be on the include path. Signed-off-by: Gilles Peskine --- tests/include/test/bignum_helpers.h | 20 ++++++++++++++++++++ tests/src/bignum_helpers.c | 17 +++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/tests/include/test/bignum_helpers.h b/tests/include/test/bignum_helpers.h index 22ce7f76fc..ab3c86a12f 100644 --- a/tests/include/test/bignum_helpers.h +++ b/tests/include/test/bignum_helpers.h @@ -30,6 +30,7 @@ #if defined(MBEDTLS_BIGNUM_C) #include +#include /** Allocate and populate a core MPI from a test case argument. * @@ -54,6 +55,25 @@ int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs, const char *input ); +/** Read a modulus from a hexadecimal string. + * + * 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] N A modulus structure. It must be initialized, but + * not set up. + * \param[in] s The null-terminated hexadecimal string to read from. + * \param int_rep The desired representation of residues. + * + * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise. + */ +int mbedtls_test_read_mpi_modulus( mbedtls_mpi_mod_modulus *N, + const char *s, + mbedtls_mpi_mod_rep_selector int_rep ); + /** Read an MPI from a hexadecimal string. * * Like mbedtls_mpi_read_string(), but with tighter guarantees around diff --git a/tests/src/bignum_helpers.c b/tests/src/bignum_helpers.c index 575bd03de3..eb819f5ce1 100644 --- a/tests/src/bignum_helpers.c +++ b/tests/src/bignum_helpers.c @@ -85,6 +85,23 @@ exit: return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); } +int mbedtls_test_read_mpi_modulus( mbedtls_mpi_mod_modulus *N, + const char *s, + mbedtls_mpi_mod_rep_selector int_rep ) +{ + mbedtls_mpi_uint *p = NULL; + size_t limbs = 0; + if( N->limbs != 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + int ret = mbedtls_test_read_mpi_core( &p, &limbs, s ); + if( ret != 0 ) + return( ret ); + ret = mbedtls_mpi_mod_modulus_setup( N, p, limbs, int_rep ); + if( ret != 0 ) + mbedtls_free( p ); + return( ret ); +} + int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s ) { int negative = 0; From 8c32b24a3580a4e7ae390b8c69b12edce3f788c8 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Dec 2022 23:01:44 +0100 Subject: [PATCH 03/31] Rename MPI-legacy test function for clarity A mod version of the function will be added very soon. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_bignum_random.data | 26 +++++++++---------- .../suites/test_suite_bignum_random.function | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/suites/test_suite_bignum_random.data b/tests/suites/test_suite_bignum_random.data index fe290531a9..bf51b0f0a5 100644 --- a/tests/suites/test_suite_bignum_random.data +++ b/tests/suites/test_suite_bignum_random.data @@ -17,31 +17,31 @@ MPI core random basic: 2^30..2^129 mpi_core_random_basic:0x40000000:"0200000000000000000000000000000000":0 # Use the same data values for mpi_core_random_basic->NOT_ACCEPTABLE -# and for mpi_random_values where we want to return NOT_ACCEPTABLE but -# this isn't checked at runtime. +# and for mpi_legacy_random_values where we want to return NOT_ACCEPTABLE +# but this isn't checked at runtime. MPI core random basic: 2^28-1..2^28 (NOT_ACCEPTABLE) mpi_core_random_basic:0x0fffffff:"10000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE MPI random legacy=core: 2^28-1..2^28 (NOT_ACCEPTABLE) -mpi_random_values:0x0fffffff:"10000000" +mpi_legacy_random_values:0x0fffffff:"10000000" MPI core random basic: 2^29-1..2^29 (NOT_ACCEPTABLE) mpi_core_random_basic:0x1fffffff:"20000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE MPI random legacy=core: 2^29-1..2^29 (NOT_ACCEPTABLE) -mpi_random_values:0x1fffffff:"20000000" +mpi_legacy_random_values:0x1fffffff:"20000000" MPI core random basic: 2^30-1..2^30 (NOT_ACCEPTABLE) mpi_core_random_basic:0x3fffffff:"40000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE MPI random legacy=core: 2^30-1..2^30 (NOT_ACCEPTABLE) -mpi_random_values:0x3fffffff:"40000000" +mpi_legacy_random_values:0x3fffffff:"40000000" MPI core random basic: 2^31-1..2^31 (NOT_ACCEPTABLE) mpi_core_random_basic:0x7fffffff:"80000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE MPI random legacy=core: 2^31-1..2^31 (NOT_ACCEPTABLE) -mpi_random_values:0x7fffffff:"80000000" +mpi_legacy_random_values:0x7fffffff:"80000000" MPI random in range: 1..2 mpi_random_many:1:"02":1000 @@ -214,22 +214,22 @@ MPI random bad arguments: min > N = 1, 0 limb in upper bound mpi_random_fail:2:"000000000000000001":MBEDTLS_ERR_MPI_BAD_INPUT_DATA MPI random legacy=core: 0..1 -mpi_random_values:0:"01" +mpi_legacy_random_values:0:"01" MPI random legacy=core: 0..2 -mpi_random_values:0:"02" +mpi_legacy_random_values:0:"02" MPI random legacy=core: 1..2 -mpi_random_values:1:"02" +mpi_legacy_random_values:1:"02" MPI random legacy=core: 2^30..2^31 -mpi_random_values:0x40000000:"80000000" +mpi_legacy_random_values:0x40000000:"80000000" MPI random legacy=core: 2^31-1..2^32-1 -mpi_random_values:0x7fffffff:"ffffffff" +mpi_legacy_random_values:0x7fffffff:"ffffffff" MPI random legacy=core: 0..2^256 -mpi_random_values:0:"010000000000000000000000000000000000000000000000000000000000000000" +mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000000" MPI random legacy=core: 0..2^256+1 -mpi_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" +mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index 184de5a405..2250e8c5de 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -110,7 +110,7 @@ exit: /* END_CASE */ /* BEGIN_CASE */ -void mpi_random_values( int min, char *max_hex ) +void mpi_legacy_random_values( int min, char *max_hex ) { /* Same RNG as in mpi_core_random_basic */ mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed; From a57cf9813a932c3a0a6a9c526b94560d36da39bd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 6 Dec 2022 22:54:09 +0100 Subject: [PATCH 04/31] Implement and test mbedtls_mpi_mod_raw_random In the basic/XXX=core test cases, use odd upper bounds, because the mod version of random() only supports odd upper bounds (the upper bound is a modulus and the mod modules only support odd moduli). Signed-off-by: Gilles Peskine --- library/bignum_mod_raw.c | 12 ++++ library/bignum_mod_raw.h | 34 ++++++++++ tests/suites/test_suite_bignum_random.data | 64 ++++++++++++++----- .../suites/test_suite_bignum_random.function | 56 ++++++++++++++++ 4 files changed, 149 insertions(+), 17 deletions(-) diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c index c98a1c1cbf..fbd90bf22d 100644 --- a/library/bignum_mod_raw.c +++ b/library/bignum_mod_raw.c @@ -176,6 +176,18 @@ void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X, /* BEGIN MERGE SLOT 6 */ +int mbedtls_mpi_mod_raw_random( mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret = mbedtls_mpi_core_random( X, min, N->p, N->limbs, f_rng, p_rng ); + if( ret != 0 ) + return( ret ); + return( mbedtls_mpi_mod_raw_to_mont_rep( X, N ) ); +} + /* END MERGE SLOT 6 */ /* BEGIN MERGE SLOT 7 */ diff --git a/library/bignum_mod_raw.h b/library/bignum_mod_raw.h index e6237b3593..87e241fa5c 100644 --- a/library/bignum_mod_raw.h +++ b/library/bignum_mod_raw.h @@ -297,6 +297,40 @@ void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X, /* BEGIN MERGE SLOT 6 */ +/** Generate a random number uniformly in a range. + * + * This function generates a random number between \p min inclusive and + * \p N exclusive. + * + * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA) + * when the RNG is a suitably parametrized instance of HMAC_DRBG + * and \p min is \c 1. + * + * \note There are `N - min` possible outputs. The lower bound + * \p min can be reached, but the upper bound \p N cannot. + * + * \param X The destination MPI, in canonical representation modulo \p N. + * It must not be aliased with \p N or otherwise overlap it. + * \param min The minimum value to return. It must be strictly smaller + * than \b N. + * \param N The modulus. + * This is the upper bound of the output range, exclusive. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was + * unable to find a suitable value within a limited number + * of attempts. This has a negligible probability if \p N + * is significantly larger than \p min, which is the case + * for all usual cryptographic applications. + */ +int mbedtls_mpi_mod_raw_random( mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + /* END MERGE SLOT 6 */ /* BEGIN MERGE SLOT 7 */ diff --git a/tests/suites/test_suite_bignum_random.data b/tests/suites/test_suite_bignum_random.data index bf51b0f0a5..b51254b5a3 100644 --- a/tests/suites/test_suite_bignum_random.data +++ b/tests/suites/test_suite_bignum_random.data @@ -17,31 +17,43 @@ MPI core random basic: 2^30..2^129 mpi_core_random_basic:0x40000000:"0200000000000000000000000000000000":0 # Use the same data values for mpi_core_random_basic->NOT_ACCEPTABLE -# and for mpi_legacy_random_values where we want to return NOT_ACCEPTABLE +# and for mpi_XXX_random_values where we want to return NOT_ACCEPTABLE # but this isn't checked at runtime. -MPI core random basic: 2^28-1..2^28 (NOT_ACCEPTABLE) -mpi_core_random_basic:0x0fffffff:"10000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +MPI core random basic: 2^28-1..2^28+1 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x0fffffff:"10000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -MPI random legacy=core: 2^28-1..2^28 (NOT_ACCEPTABLE) -mpi_legacy_random_values:0x0fffffff:"10000000" +MPI random legacy=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) +mpi_legacy_random_values:0x0fffffff:"10000001" -MPI core random basic: 2^29-1..2^29 (NOT_ACCEPTABLE) -mpi_core_random_basic:0x1fffffff:"20000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) +mpi_mod_random_values:0x0fffffff:"10000001" -MPI random legacy=core: 2^29-1..2^29 (NOT_ACCEPTABLE) -mpi_legacy_random_values:0x1fffffff:"20000000" +MPI core random basic: 2^29-1..2^29+1 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x1fffffff:"20000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -MPI core random basic: 2^30-1..2^30 (NOT_ACCEPTABLE) -mpi_core_random_basic:0x3fffffff:"40000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +MPI random legacy=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) +mpi_legacy_random_values:0x1fffffff:"20000001" -MPI random legacy=core: 2^30-1..2^30 (NOT_ACCEPTABLE) -mpi_legacy_random_values:0x3fffffff:"40000000" +MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) +mpi_mod_random_values:0x1fffffff:"20000001" -MPI core random basic: 2^31-1..2^31 (NOT_ACCEPTABLE) -mpi_core_random_basic:0x7fffffff:"80000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +MPI core random basic: 2^30-1..2^30+1 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x3fffffff:"40000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -MPI random legacy=core: 2^31-1..2^31 (NOT_ACCEPTABLE) -mpi_legacy_random_values:0x7fffffff:"80000000" +MPI random legacy=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) +mpi_legacy_random_values:0x3fffffff:"40000001" + +MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) +mpi_mod_random_values:0x3fffffff:"40000001" + +MPI core random basic: 2^31-1..2^31+1 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x7fffffff:"80000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE + +MPI random legacy=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) +mpi_legacy_random_values:0x7fffffff:"80000001" + +MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) +mpi_mod_random_values:0x7fffffff:"80000001" MPI random in range: 1..2 mpi_random_many:1:"02":1000 @@ -233,3 +245,21 @@ mpi_legacy_random_values:0:"0100000000000000000000000000000000000000000000000000 MPI random legacy=core: 0..2^256+1 mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" + +MPI random mod=core: 0..1 +mpi_mod_random_values:0:"01" + +MPI random mod=core: 0..3 +mpi_mod_random_values:0:"03" + +MPI random mod=core: 1..3 +mpi_mod_random_values:1:"03" + +MPI random mod=core: 2^30..2^31-1 +mpi_mod_random_values:0x40000000:"7fffffff" + +MPI random mod=core: 2^31-1..2^32-1 +mpi_mod_random_values:0x7fffffff:"ffffffff" + +MPI random mod=core: 0..2^256+1 +mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index 2250e8c5de..a837e1b04b 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -8,6 +8,7 @@ #include "mbedtls/bignum.h" #include "mbedtls/entropy.h" #include "bignum_core.h" +#include "bignum_mod_raw.h" #include "constant_time_internal.h" /* This test suite only manipulates non-negative bignums. */ @@ -158,6 +159,61 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void mpi_mod_random_values( int min, char *max_hex ) +{ + /* Same RNG as in mpi_core_random_basic */ + mbedtls_test_rnd_pseudo_info rnd_core = { + {'T', 'h', 'i', 's', ' ', 'i', ',', 'a', + 's', 'e', 'e', 'd', '!', 0}, + 0, 0}; + mbedtls_test_rnd_pseudo_info rnd_mod_raw; + memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) ); + mbedtls_mpi_uint *R_core = NULL; + mbedtls_mpi_uint *R_mod_raw = NULL; + mbedtls_mpi_mod_modulus N; + mbedtls_mpi_mod_modulus_init( &N ); + + TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex, + MBEDTLS_MPI_MOD_REP_MONTGOMERY ), + 0 ); + ASSERT_ALLOC( R_core, N.limbs ); + ASSERT_ALLOC( R_mod_raw, N.limbs ); + + /* Call the core and mod random() functions with the same random stream. */ + int core_ret = mbedtls_mpi_core_random( R_core, + min, N.p, N.limbs, + mbedtls_test_rnd_pseudo_rand, + &rnd_core ); + int mod_raw_ret = mbedtls_mpi_mod_raw_random( R_mod_raw, + min, &N, + mbedtls_test_rnd_pseudo_rand, + &rnd_mod_raw ); + + /* They must return the same status, and, on success, output the + * same number, with the same limb count. */ + TEST_EQUAL( core_ret, mod_raw_ret ); + if( core_ret == 0 ) + { + TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_raw, &N ), 0 ); + ASSERT_COMPARE( R_core, N.limbs * ciL, + R_mod_raw, N.limbs * ciL ); + } + + /* Also check that they have consumed the RNG in the same way. */ + /* This may theoretically fail on rare platforms with padding in + * the structure! If this is a problem in practice, change to a + * field-by-field comparison. */ + ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ), + &rnd_mod_raw, sizeof( rnd_mod_raw ) ); + +exit: + mbedtls_mpi_mod_modulus_free( &N ); + mbedtls_free( R_core ); + mbedtls_free( R_mod_raw ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mpi_random_many( int min, char *bound_hex, int iterations ) { From d008abbc4f4df748a64aa436e499c7a9270f0522 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Dec 2022 19:50:29 +0100 Subject: [PATCH 05/31] Fix leak of modulus structures in tests Signed-off-by: Gilles Peskine --- tests/include/test/bignum_helpers.h | 10 +++++++++- tests/src/bignum_helpers.c | 6 ++++++ tests/suites/test_suite_bignum_random.function | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/include/test/bignum_helpers.h b/tests/include/test/bignum_helpers.h index ab3c86a12f..164017e69f 100644 --- a/tests/include/test/bignum_helpers.h +++ b/tests/include/test/bignum_helpers.h @@ -61,7 +61,8 @@ int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs, * 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(). + * freed with mbedtls_free(). You can do that by calling + * mbedtls_test_mpi_mod_modulus_free_with_limbs(). * * \param[in,out] N A modulus structure. It must be initialized, but * not set up. @@ -74,6 +75,13 @@ int mbedtls_test_read_mpi_modulus( mbedtls_mpi_mod_modulus *N, const char *s, mbedtls_mpi_mod_rep_selector int_rep ); +/** Free a modulus and its limbs. + * + * \param[in] N A modulus structure such that there is no other + * reference to `N->p`. + */ +void mbedtls_test_mpi_mod_modulus_free_with_limbs( mbedtls_mpi_mod_modulus *N ); + /** Read an MPI from a hexadecimal string. * * Like mbedtls_mpi_read_string(), but with tighter guarantees around diff --git a/tests/src/bignum_helpers.c b/tests/src/bignum_helpers.c index eb819f5ce1..d6ec9bd3cc 100644 --- a/tests/src/bignum_helpers.c +++ b/tests/src/bignum_helpers.c @@ -102,6 +102,12 @@ int mbedtls_test_read_mpi_modulus( mbedtls_mpi_mod_modulus *N, return( ret ); } +void mbedtls_test_mpi_mod_modulus_free_with_limbs( mbedtls_mpi_mod_modulus *N ) +{ + mbedtls_free( (mbedtls_mpi_uint*) N->p ); + mbedtls_mpi_mod_modulus_free( N ); +} + int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s ) { int negative = 0; diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index a837e1b04b..5064a62d0b 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -208,7 +208,7 @@ void mpi_mod_random_values( int min, char *max_hex ) &rnd_mod_raw, sizeof( rnd_mod_raw ) ); exit: - mbedtls_mpi_mod_modulus_free( &N ); + mbedtls_test_mpi_mod_modulus_free_with_limbs( &N ); mbedtls_free( R_core ); mbedtls_free( R_mod_raw ); } From b1eea02f745fc978ad37e9749ed6dee509351116 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Dec 2022 22:59:27 +0100 Subject: [PATCH 06/31] Implement and test mbedtls_mpi_mod_random Signed-off-by: Gilles Peskine --- library/bignum_mod.c | 11 +++++++ library/bignum_mod.h | 33 +++++++++++++++++++ .../suites/test_suite_bignum_random.function | 19 +++++++++++ 3 files changed, 63 insertions(+) diff --git a/library/bignum_mod.c b/library/bignum_mod.c index 0057ebae21..3eef4e7002 100644 --- a/library/bignum_mod.c +++ b/library/bignum_mod.c @@ -214,6 +214,17 @@ int mbedtls_mpi_mod_add( mbedtls_mpi_mod_residue *X, /* BEGIN MERGE SLOT 6 */ +int mbedtls_mpi_mod_random( mbedtls_mpi_mod_residue *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + if( X->limbs != N->limbs ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + return( mbedtls_mpi_mod_raw_random( X->p, min, N, f_rng, p_rng ) ); +} + /* END MERGE SLOT 6 */ /* BEGIN MERGE SLOT 7 */ diff --git a/library/bignum_mod.h b/library/bignum_mod.h index f089f650ef..bf00a36fcc 100644 --- a/library/bignum_mod.h +++ b/library/bignum_mod.h @@ -290,6 +290,39 @@ int mbedtls_mpi_mod_add( mbedtls_mpi_mod_residue *X, /* BEGIN MERGE SLOT 6 */ +/** Generate a random number uniformly in a range. + * + * This function generates a random number between \p min inclusive and + * \p N exclusive. + * + * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA) + * when the RNG is a suitably parametrized instance of HMAC_DRBG + * and \p min is \c 1. + * + * \note There are `N - min` possible outputs. The lower bound + * \p min can be reached, but the upper bound \p N cannot. + * + * \param X The destination residue. + * \param min The minimum value to return. It must be strictly smaller + * than \b N. + * \param N The modulus. + * This is the upper bound of the output range, exclusive. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was + * unable to find a suitable value within a limited number + * of attempts. This has a negligible probability if \p N + * is significantly larger than \p min, which is the case + * for all usual cryptographic applications. + */ +int mbedtls_mpi_mod_random( mbedtls_mpi_mod_residue *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + /* END MERGE SLOT 6 */ /* BEGIN MERGE SLOT 7 */ diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index 5064a62d0b..4ee26adb7f 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -169,8 +169,12 @@ void mpi_mod_random_values( int min, char *max_hex ) 0, 0}; mbedtls_test_rnd_pseudo_info rnd_mod_raw; memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) ); + mbedtls_test_rnd_pseudo_info rnd_mod; + memcpy( &rnd_mod, &rnd_core, sizeof( rnd_core ) ); mbedtls_mpi_uint *R_core = NULL; mbedtls_mpi_uint *R_mod_raw = NULL; + mbedtls_mpi_uint *R_mod_digits = NULL; + mbedtls_mpi_mod_residue R_mod; mbedtls_mpi_mod_modulus N; mbedtls_mpi_mod_modulus_init( &N ); @@ -179,6 +183,10 @@ void mpi_mod_random_values( int min, char *max_hex ) 0 ); ASSERT_ALLOC( R_core, N.limbs ); ASSERT_ALLOC( R_mod_raw, N.limbs ); + ASSERT_ALLOC( R_mod_digits, N.limbs ); + TEST_EQUAL( mbedtls_mpi_mod_residue_setup( &R_mod, &N, + R_mod_digits, N.limbs ), + 0 ); /* Call the core and mod random() functions with the same random stream. */ int core_ret = mbedtls_mpi_core_random( R_core, @@ -189,15 +197,23 @@ void mpi_mod_random_values( int min, char *max_hex ) min, &N, mbedtls_test_rnd_pseudo_rand, &rnd_mod_raw ); + int mod_ret = mbedtls_mpi_mod_random( &R_mod, + min, &N, + mbedtls_test_rnd_pseudo_rand, + &rnd_mod ); /* They must return the same status, and, on success, output the * same number, with the same limb count. */ TEST_EQUAL( core_ret, mod_raw_ret ); + TEST_EQUAL( core_ret, mod_ret ); if( core_ret == 0 ) { TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_raw, &N ), 0 ); ASSERT_COMPARE( R_core, N.limbs * ciL, R_mod_raw, N.limbs * ciL ); + TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_digits, &N ), 0 ); + ASSERT_COMPARE( R_core, N.limbs * ciL, + R_mod_digits, N.limbs * ciL ); } /* Also check that they have consumed the RNG in the same way. */ @@ -206,11 +222,14 @@ void mpi_mod_random_values( int min, char *max_hex ) * field-by-field comparison. */ ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ), &rnd_mod_raw, sizeof( rnd_mod_raw ) ); + ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ), + &rnd_mod, sizeof( rnd_mod ) ); exit: mbedtls_test_mpi_mod_modulus_free_with_limbs( &N ); mbedtls_free( R_core ); mbedtls_free( R_mod_raw ); + mbedtls_free( R_mod_digits ); } /* END_CASE */ From d878d1c638c550a03dabd3e9c45a50533b79249b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Dec 2022 12:59:51 +0100 Subject: [PATCH 07/31] Add validation tests for mbedtls_mpi_{mod,mod_raw}_random Signed-off-by: Gilles Peskine --- tests/suites/test_suite_bignum_random.data | 45 ++++++++++++++ .../suites/test_suite_bignum_random.function | 60 +++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/tests/suites/test_suite_bignum_random.data b/tests/suites/test_suite_bignum_random.data index b51254b5a3..b486f3866a 100644 --- a/tests/suites/test_suite_bignum_random.data +++ b/tests/suites/test_suite_bignum_random.data @@ -263,3 +263,48 @@ mpi_mod_random_values:0x7fffffff:"ffffffff" MPI random mod=core: 0..2^256+1 mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" + +MPI random mod validation: 1 limb, good, 0..1 +mpi_mod_random_validation:0:"1":0:0 + +MPI random mod validation: 1 limb, good, 1..3 +mpi_mod_random_validation:1:"3":0:0 + +MPI random mod validation: 1 limb, good, 2..3 +mpi_mod_random_validation:2:"3":0:0 + +MPI random mod validation: 1 limb, good, 3..5 +mpi_mod_random_validation:3:"5":0:0 + +MPI random mod validation: 1 limb, good, 4..5 +mpi_mod_random_validation:4:"5":0:0 + +MPI random mod validation: 1 limb, good, 5..7 +mpi_mod_random_validation:5:"7":0:0 + +MPI random mod validation: 1 limb, good, 6..7 +mpi_mod_random_validation:6:"7":0:0 + +MPI random mod validation: 1 limb, good, 0..0x123 +mpi_mod_random_validation:0:"123":0:0 + +MPI random mod validation: 2+ limbs, good +mpi_mod_random_validation:0:"01234567890123456789":0:0 + +MPI random mod validation: 1 limb, output null +mpi_mod_random_validation:0:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random mod validation: 1 limb, output too large +mpi_mod_random_validation:0:"123":1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random mod validation: 2+ limbs, output too small +mpi_mod_random_validation:0:"01234567890123456789":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random mod validation: 2+ limbs, output too large +mpi_mod_random_validation:0:"01234567890123456789":1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random mod validation: min == upper bound +mpi_mod_random_validation:0x123:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random mod validation: min > upper bound +mpi_mod_random_validation:0x124:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index 4ee26adb7f..61db40d276 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -386,6 +386,66 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void mpi_mod_random_validation( int min, char *bound_hex, + int result_limbs_delta, + int expected_ret ) +{ + mbedtls_mpi_uint *result_digits = NULL; + mbedtls_mpi_mod_modulus N; + mbedtls_mpi_mod_modulus_init( &N ); + + TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, bound_hex, + MBEDTLS_MPI_MOD_REP_MONTGOMERY ), + 0 ); + size_t result_limbs = N.limbs + result_limbs_delta; + ASSERT_ALLOC( result_digits, result_limbs ); + /* Build a reside that might not match the modulus, to test that + * the library function rejects that as expected. */ + mbedtls_mpi_mod_residue result = {result_digits, result_limbs}; + + TEST_EQUAL( mbedtls_mpi_mod_random( &result, min, &N, + mbedtls_test_rnd_std_rand, NULL ), + expected_ret ); + if( expected_ret == 0 ) + { + /* Success should only be expected when the result has the same + * size as the modulus, otherwise it's a mistake in the test data. */ + TEST_EQUAL( result_limbs, N.limbs ); + /* Sanity check: check that the result is in range */ + TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( result_digits, &N ), 0 ); + TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ), + 1 ); + /* Check result >= min (changes result) */ + TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result_digits, min, + result_limbs ), + 0 ); + } + + /* When the result has the right number of limbs, also test mod_raw + * (for which this is an unchecked precondition). */ + if( result_limbs_delta == 0 ) + { + TEST_EQUAL( mbedtls_mpi_mod_raw_random( result_digits, min, &N, + mbedtls_test_rnd_std_rand, NULL ), + expected_ret ); + if( expected_ret == 0 ) + { + TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( result_digits, &N ), 0 ); + TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ), + 1 ); + TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result.p, min, + result_limbs ), + 0 ); + } + } + +exit: + mbedtls_test_mpi_mod_modulus_free_with_limbs( &N ); + mbedtls_free( result_digits ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret ) { From 071f47343b2d57d65dd64059db04849b4d30084e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 14 Dec 2022 19:00:56 +0100 Subject: [PATCH 08/31] Document the test strategy Signed-off-by: Gilles Peskine --- .../suites/test_suite_bignum_random.function | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index 61db40d276..0f431cd6d2 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -3,6 +3,38 @@ * functions. Due to the complexity of how these functions are tested, * we test all the layers in a single test suite, unlike the way other * functions are tested with each layer in its own test suite. + * + * Test strategy + * ============= + * + * There are three main goals for testing random() functions: + * - Parameter validation. + * - Correctness of outputs (well-formed, in range). + * - Distribution of outputs. + * + * We test parameter validation in a standard way, with unit tests with + * positive and negative cases: + * - mbedtls_mpi_core_random(): negative cases for mpi_core_random_basic. + * - mbedtls_mpi_mod_raw_random(), mbedtls_mpi_mod_random(): negative + * cases for mpi_mod_random_validation. + * - mbedtls_mpi_random(): mpi_random_fail. + * + * We test the correctness of outputs in positive tests: + * - mbedtls_mpi_core_random(): positive cases for mpi_core_random_basic, + * and mpi_random_many. + * - mbedtls_mpi_mod_raw_random(), mbedtls_mpi_mod_random(): tested indirectly + * via mpi_mod_random_values. + * - mbedtls_mpi_random(): mpi_random_sizes, plus indirectly via + * mpi_random_values. + * + * We test the distribution of outputs only for mbedtls_mpi_core_random(), + * in mpi_random_many, which runs the function multiple times. This also + * helps in validating the output range, through test cases with a small + * range where any output out of range would be very likely to lead to a + * test failure. For the other functions, we validate the distribution + * indirectly by testing that these functions consume the random generator + * in the same way as mbedtls_mpi_core_random(). This is done in + * mpi_mod_random_values and mpi_legacy_random_values. */ #include "mbedtls/bignum.h" From c377f31ad95fc83be433a640750806a2b8dba0d0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:13:42 +0100 Subject: [PATCH 09/31] Remove unused import This wasn't reported by pylint due to a pylint bug (apparently): `pylint A B` doesn't complain about an unused import in B if A happens to import and use the same module, which happens to be the case when we run pylint on the CI. Signed-off-by: Gilles Peskine --- tests/scripts/generate_bignum_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/scripts/generate_bignum_tests.py b/tests/scripts/generate_bignum_tests.py index 0b84711861..6ee6ab39ad 100755 --- a/tests/scripts/generate_bignum_tests.py +++ b/tests/scripts/generate_bignum_tests.py @@ -60,7 +60,6 @@ from abc import ABCMeta from typing import List import scripts_path # pylint: disable=unused-import -from mbedtls_dev import test_case from mbedtls_dev import test_data_generation from mbedtls_dev import bignum_common # Import modules containing additional test classes From f8a4463bd6320c769acf81f4c8853f3f1dcf4d2a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:12:22 +0100 Subject: [PATCH 10/31] Add some missing type annotations Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_common.py b/scripts/mbedtls_dev/bignum_common.py index 0339b1ad18..9db567b7c4 100644 --- a/scripts/mbedtls_dev/bignum_common.py +++ b/scripts/mbedtls_dev/bignum_common.py @@ -48,7 +48,7 @@ def hex_to_int(val: str) -> int: return 0 return int(val, 16) -def quote_str(val) -> str: +def quote_str(val: str) -> str: return "\"{}\"".format(val) def bound_mpi(val: int, bits_in_limb: int) -> int: @@ -134,7 +134,7 @@ class OperationCommon(test_data_generation.BaseTest): def hex_digits(self) -> int: return 2 * (self.limbs * self.bits_in_limb // 8) - def format_arg(self, val) -> str: + def format_arg(self, val: str) -> str: if self.input_style not in self.input_styles: raise ValueError("Unknown input style!") if self.input_style == "variable": @@ -142,7 +142,7 @@ class OperationCommon(test_data_generation.BaseTest): else: return val.zfill(self.hex_digits) - def format_result(self, res) -> str: + def format_result(self, res: int) -> str: res_str = '{:x}'.format(res) return quote_str(self.format_arg(res_str)) From 5623ecc2d62bcdd2c4bd2dd501591502713a7725 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:16:54 +0100 Subject: [PATCH 11/31] Mod operations: fill arguments to the width of the modulus With the default input style (which is "variable"), fill all bignum test case arguments to the same width as the modulus. Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_common.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/mbedtls_dev/bignum_common.py b/scripts/mbedtls_dev/bignum_common.py index 9db567b7c4..03055f02b4 100644 --- a/scripts/mbedtls_dev/bignum_common.py +++ b/scripts/mbedtls_dev/bignum_common.py @@ -267,6 +267,12 @@ class ModOperationCommon(OperationCommon): def arg_n(self) -> str: return self.format_arg(self.val_n) + def format_arg(self, val: str) -> str: + if self.input_style == "variable": + return val.zfill(len(hex(self.int_n)) - 2) + else: + return super().format_arg(val) + def arguments(self) -> List[str]: return [quote_str(self.arg_n)] + super().arguments() From 7a708fd49f6d002415cb8e94052a540bf705120d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:19:18 +0100 Subject: [PATCH 12/31] Helpers for generating representation-aware test cases Add a class for modulus representations (mbedtls_mpi_mod_rep_selector). Add a method to convert a number to any representation. Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_common.py | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/scripts/mbedtls_dev/bignum_common.py b/scripts/mbedtls_dev/bignum_common.py index 03055f02b4..7b2669af72 100644 --- a/scripts/mbedtls_dev/bignum_common.py +++ b/scripts/mbedtls_dev/bignum_common.py @@ -15,6 +15,7 @@ # limitations under the License. from abc import abstractmethod +import enum from typing import Iterator, List, Tuple, TypeVar, Any from itertools import chain @@ -240,6 +241,23 @@ class OperationCommon(test_data_generation.BaseTest): ) +class ModulusRepresentation(enum.Enum): + """Representation selector of a modulus.""" + # Numerical values aligned with the type mbedtls_mpi_mod_rep_selector + INVALID = 0 + MONTGOMERY = 2 + OPT_RED = 3 + + def symbol(self) -> str: + """The C symbol for this representation selector.""" + return 'MBEDTLS_MPI_MOD_REP_' + self.name + + @classmethod + def supported_representations(cls) -> List['ModulusRepresentation']: + """Return all representations that are supported in positive test cases.""" + return [cls.MONTGOMERY, cls.OPT_RED] + + class ModOperationCommon(OperationCommon): #pylint: disable=abstract-method """Target for bignum mod_raw test case generation.""" @@ -259,6 +277,17 @@ class ModOperationCommon(OperationCommon): def from_montgomery(self, val: int) -> int: return (val * self.r_inv) % self.int_n + def convert_from_canonical(self, canonical: int, + rep: ModulusRepresentation) -> int: + """Convert values from canonical representation to the given representation.""" + if rep is ModulusRepresentation.MONTGOMERY: + return self.to_montgomery(canonical) + elif rep is ModulusRepresentation.OPT_RED: + return canonical + else: + raise ValueError('Modulus representation not supported: {}' + .format(rep.name)) + @property def boundary(self) -> int: return self.int_n From 1e2a4d4089f6e2e87d13868e62e2b0b2e02391b6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:21:17 +0100 Subject: [PATCH 13/31] Functions to convert raw residues to/from the modulus representation Test cases will be generated automatically by a subsequent commit. Signed-off-by: Gilles Peskine --- library/bignum_mod_raw.c | 30 +++++++++++ library/bignum_mod_raw.h | 34 ++++++++++++ .../suites/test_suite_bignum_mod_raw.function | 52 +++++++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c index fbd90bf22d..721efc8538 100644 --- a/library/bignum_mod_raw.c +++ b/library/bignum_mod_raw.c @@ -176,6 +176,36 @@ void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X, /* BEGIN MERGE SLOT 6 */ +int mbedtls_mpi_mod_raw_canonical_to_modulus_rep( + mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N ) +{ + switch( N->int_rep ) + { + case MBEDTLS_MPI_MOD_REP_MONTGOMERY: + return( mbedtls_mpi_mod_raw_to_mont_rep( X, N ) ); + case MBEDTLS_MPI_MOD_REP_OPT_RED: + return( 0 ); + default: + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + } +} + +int mbedtls_mpi_mod_raw_modulus_to_canonical_rep( + mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N ) +{ + switch( N->int_rep ) + { + case MBEDTLS_MPI_MOD_REP_MONTGOMERY: + return( mbedtls_mpi_mod_raw_from_mont_rep( X, N ) ); + case MBEDTLS_MPI_MOD_REP_OPT_RED: + return( 0 ); + default: + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + } +} + int mbedtls_mpi_mod_raw_random( mbedtls_mpi_uint *X, mbedtls_mpi_uint min, const mbedtls_mpi_mod_modulus *N, diff --git a/library/bignum_mod_raw.h b/library/bignum_mod_raw.h index 87e241fa5c..dad060b3c6 100644 --- a/library/bignum_mod_raw.h +++ b/library/bignum_mod_raw.h @@ -297,6 +297,40 @@ void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X, /* BEGIN MERGE SLOT 6 */ +/** Convert an MPI from canonical representation (little-endian limb array) + * to the representation associated with the modulus. + * + * \param[in,out] X The limb array to convert. + * It must have as many limbs as \p N. + * It is converted in place. + * If this function returns an error, the content of \p X + * is unspecified. + * \param[in] N The modulus structure. + * + *\ return \c 0 if successful. + * Otherwise an \c MBEDTLS_ERR_MPI_xxx error code. + */ +int mbedtls_mpi_mod_raw_canonical_to_modulus_rep( + mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N ); + +/** Convert an MPI from the representation associated with the modulus + * to canonical representation (little-endian limb array). + * + * \param[in,out] X The limb array to convert. + * It must have as many limbs as \p N. + * It is converted in place. + * If this function returns an error, the content of \p X + * is unspecified. + * \param[in] N The modulus structure. + * + *\ return \c 0 if successful. + * Otherwise an \c MBEDTLS_ERR_MPI_xxx error code. + */ +int mbedtls_mpi_mod_raw_modulus_to_canonical_rep( + mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N ); + /** Generate a random number uniformly in a range. * * This function generates a random number between \p min inclusive and diff --git a/tests/suites/test_suite_bignum_mod_raw.function b/tests/suites/test_suite_bignum_mod_raw.function index 83e1f543e5..51d096e908 100644 --- a/tests/suites/test_suite_bignum_mod_raw.function +++ b/tests/suites/test_suite_bignum_mod_raw.function @@ -520,7 +520,59 @@ exit: /* END MERGE SLOT 5 */ /* BEGIN MERGE SLOT 6 */ +/* BEGIN_CASE */ +void mpi_mod_raw_canonical_to_modulus_rep( const char *input_N, int rep, + const char *input_A, + const char *input_X ) +{ + mbedtls_mpi_mod_modulus N; + mbedtls_mpi_mod_modulus_init( &N ); + mbedtls_mpi_uint *A = NULL; + size_t A_limbs = 0;; + mbedtls_mpi_uint *X = NULL; + size_t X_limbs = 0; + TEST_EQUAL( 0, mbedtls_test_read_mpi_modulus( &N, input_N, rep ) ); + TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) ); + TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) ); + + TEST_EQUAL( 0, mbedtls_mpi_mod_raw_canonical_to_modulus_rep( A, &N ) ); + ASSERT_COMPARE( A, A_limbs * sizeof( mbedtls_mpi_uint ), + X, X_limbs * sizeof( mbedtls_mpi_uint ) ); + +exit: + mbedtls_test_mpi_mod_modulus_free_with_limbs( &N ); + mbedtls_free( A ); + mbedtls_free( X ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void mpi_mod_raw_modulus_to_canonical_rep( const char *input_N, int rep, + const char *input_A, + const char *input_X ) +{ + mbedtls_mpi_mod_modulus N; + mbedtls_mpi_mod_modulus_init( &N ); + mbedtls_mpi_uint *A = NULL; + size_t A_limbs = 0;; + mbedtls_mpi_uint *X = NULL; + size_t X_limbs = 0; + + TEST_EQUAL( 0, mbedtls_test_read_mpi_modulus( &N, input_N, rep ) ); + TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) ); + TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) ); + + TEST_EQUAL( 0, mbedtls_mpi_mod_raw_modulus_to_canonical_rep( A, &N ) ); + ASSERT_COMPARE( A, A_limbs * sizeof( mbedtls_mpi_uint ), + X, X_limbs * sizeof( mbedtls_mpi_uint ) ); + +exit: + mbedtls_test_mpi_mod_modulus_free_with_limbs( &N ); + mbedtls_free( A ); + mbedtls_free( X ); +} +/* END_CASE */ /* END MERGE SLOT 6 */ /* BEGIN MERGE SLOT 7 */ From eb2e77f6170de7ae8738f0dfdbd261dbf6347006 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:22:44 +0100 Subject: [PATCH 14/31] Document modulus representation selectors Signed-off-by: Gilles Peskine --- library/bignum_mod.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/library/bignum_mod.h b/library/bignum_mod.h index bf00a36fcc..9c2043d9af 100644 --- a/library/bignum_mod.h +++ b/library/bignum_mod.h @@ -87,12 +87,23 @@ #include "mbedtls/bignum.h" #endif -/* Skip 1 as it is slightly easier to accidentally pass to functions. */ +/** How residues associated with a modulus are represented. + * + * This also determines which fields of the modulus structure are valid and + * what their contents are (see #mbedtls_mpi_mod_modulus). + */ typedef enum { + /** Representation not chosen (makes the modulus structure invalid). */ MBEDTLS_MPI_MOD_REP_INVALID = 0, + /* Skip 1 as it is slightly easier to accidentally pass to functions. */ + /** Montgomery representation. */ MBEDTLS_MPI_MOD_REP_MONTGOMERY = 2, - MBEDTLS_MPI_MOD_REP_OPT_RED + /** TODO: document this. + * + * Residues are in canonical representation. + */ + MBEDTLS_MPI_MOD_REP_OPT_RED, } mbedtls_mpi_mod_rep_selector; /* Make mbedtls_mpi_mod_rep_selector and mbedtls_mpi_mod_ext_rep disjoint to @@ -124,7 +135,9 @@ typedef struct { mbedtls_mpi_mod_rep_selector int_rep; // selector to signal the active member of the union union rep { + /* if int_rep == #MBEDTLS_MPI_MOD_REP_MONTGOMERY */ mbedtls_mpi_mont_struct mont; + /* if int_rep == #MBEDTLS_MPI_MOD_REP_OPT_RED */ mbedtls_mpi_opt_red_struct ored; } rep; } mbedtls_mpi_mod_modulus; From e655479528b8dff247d3c67e310c8f9067ad12e4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:24:27 +0100 Subject: [PATCH 15/31] Generalize representation handling in mbedtls_mpi_mod_read Call mbedtls_mpi_mod_raw_canonical_to_modulus_rep instead of assuming that anything that isn't MBEDTLS_MPI_MOD_REP_MONTGOMERY is canonical. mbedtls_mpi_mod_write should get the same treatment, but I'm holding off until https://github.com/Mbed-TLS/mbedtls/issues/6679 is done. Signed-off-by: Gilles Peskine --- library/bignum_mod.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/bignum_mod.c b/library/bignum_mod.c index 3eef4e7002..4ac6277b3b 100644 --- a/library/bignum_mod.c +++ b/library/bignum_mod.c @@ -248,8 +248,7 @@ int mbedtls_mpi_mod_read( mbedtls_mpi_mod_residue *r, r->limbs = m->limbs; - if( m->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY ) - ret = mbedtls_mpi_mod_raw_to_mont_rep( r->p, m ); + ret = mbedtls_mpi_mod_raw_canonical_to_modulus_rep( r->p, m ); cleanup: return ( ret ); From 23636aca984746a6af71ded27f986002f74224da Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:30:47 +0100 Subject: [PATCH 16/31] Generate test cases for mpi_mod_raw_canonical_to_modulus_rep Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_mod_raw.py | 36 ++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index 6fc4c919bc..c504581493 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -14,8 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, List +from typing import Dict, Iterator, List +from . import test_case from . import test_data_generation from . import bignum_common from .bignum_data import ONLY_PRIME_MODULI @@ -107,6 +108,39 @@ class BignumModRawAdd(bignum_common.ModOperationCommon, # BEGIN MERGE SLOT 6 +class BignumModRawCanonicalToModulusRep(bignum_common.ModOperationCommon, + BignumModRawTarget): + """Test cases for mpi_mod_raw_canonical_to_modulus_rep.""" + test_function = "mpi_mod_raw_canonical_to_modulus_rep" + test_name = "Rep canon->mod" + arity = 1 + + def __init__(self, + val_n: str, val_a: str, + rep: bignum_common.ModulusRepresentation) -> None: + super().__init__(val_n=val_n, val_a=val_a) + self.rep = rep + + def result(self) -> List[str]: + result = self.convert_from_canonical(self.int_a, self.rep) + return [self.format_result(result)] + + def arguments(self) -> List[str]: + return ([bignum_common.quote_str(self.arg_n), self.rep.symbol(), + bignum_common.quote_str(self.arg_a)] + + self.result()) + + @classmethod + def generate_function_tests(cls) -> Iterator[test_case.TestCase]: + representations = \ + bignum_common.ModulusRepresentation.supported_representations() + for rep in representations: + for n in cls.moduli: + for a in cls.input_values: + test_object = cls(n, a, rep) + if test_object.is_valid: + yield test_object.create_test_case() + # END MERGE SLOT 6 # BEGIN MERGE SLOT 7 From be69c7d5594255ea9e9c34721987666561a7bf86 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:51:22 +0100 Subject: [PATCH 17/31] Generate test cases for mpi_mod_raw_modulus_to_canonical_rep as well Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_mod_raw.py | 39 +++++++++++++++++++-------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index c504581493..800bcb13e1 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -108,23 +108,18 @@ class BignumModRawAdd(bignum_common.ModOperationCommon, # BEGIN MERGE SLOT 6 -class BignumModRawCanonicalToModulusRep(bignum_common.ModOperationCommon, - BignumModRawTarget): - """Test cases for mpi_mod_raw_canonical_to_modulus_rep.""" - test_function = "mpi_mod_raw_canonical_to_modulus_rep" - test_name = "Rep canon->mod" +class BignumModRawConvertRep(bignum_common.ModOperationCommon, + BignumModRawTarget): + # This is an abstract class, it's ok to have unimplemented methods. + #pylint: disable=abstract-method + """Test cases for representation conversion.""" arity = 1 - def __init__(self, - val_n: str, val_a: str, + def __init__(self, val_n: str, val_a: str, rep: bignum_common.ModulusRepresentation) -> None: super().__init__(val_n=val_n, val_a=val_a) self.rep = rep - def result(self) -> List[str]: - result = self.convert_from_canonical(self.int_a, self.rep) - return [self.format_result(result)] - def arguments(self) -> List[str]: return ([bignum_common.quote_str(self.arg_n), self.rep.symbol(), bignum_common.quote_str(self.arg_a)] + @@ -141,6 +136,28 @@ class BignumModRawCanonicalToModulusRep(bignum_common.ModOperationCommon, if test_object.is_valid: yield test_object.create_test_case() +class BignumModRawCanonicalToModulusRep(BignumModRawConvertRep): + """Test cases for mpi_mod_raw_canonical_to_modulus_rep.""" + test_function = "mpi_mod_raw_canonical_to_modulus_rep" + test_name = "Rep canon->mod" + + def result(self) -> List[str]: + result = self.convert_from_canonical(self.int_a, self.rep) + return [self.format_result(result)] + +class BignumModRawModulusToCanonicalRep(BignumModRawConvertRep): + """Test cases for mpi_mod_raw_modulus_to_canonical_rep.""" + test_function = "mpi_mod_raw_modulus_to_canonical_rep" + test_name = "Rep mod->canon" + + @property + def arg_a(self) -> str: + converted_a = self.convert_from_canonical(self.int_a, self.rep) + return self.format_arg(hex(converted_a)[2:]) + + def result(self) -> List[str]: + return [self.format_result(self.int_a)] + # END MERGE SLOT 6 # BEGIN MERGE SLOT 7 From e1d8326e9068ca0b937a1aa8fbd1345d79471985 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 19:31:09 +0100 Subject: [PATCH 18/31] Fix representation of mod-random output mbedtls_mpi_mod_raw_random() and mbedtls_mpi_mod_random() were producing output in the Montgomery representation, instead of obeying the representation chosen in the modulus structure. Fix this. Duplicate the test cases for mod-random output to have separate test cases for each representation. Signed-off-by: Gilles Peskine --- library/bignum_mod_raw.c | 2 +- tests/suites/test_suite_bignum_random.data | 70 +++++++++++++------ .../suites/test_suite_bignum_random.function | 16 ++--- 3 files changed, 58 insertions(+), 30 deletions(-) diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c index 721efc8538..d811740059 100644 --- a/library/bignum_mod_raw.c +++ b/library/bignum_mod_raw.c @@ -215,7 +215,7 @@ int mbedtls_mpi_mod_raw_random( mbedtls_mpi_uint *X, int ret = mbedtls_mpi_core_random( X, min, N->p, N->limbs, f_rng, p_rng ); if( ret != 0 ) return( ret ); - return( mbedtls_mpi_mod_raw_to_mont_rep( X, N ) ); + return( mbedtls_mpi_mod_raw_canonical_to_modulus_rep( X, N ) ); } /* END MERGE SLOT 6 */ diff --git a/tests/suites/test_suite_bignum_random.data b/tests/suites/test_suite_bignum_random.data index b486f3866a..ee5e397781 100644 --- a/tests/suites/test_suite_bignum_random.data +++ b/tests/suites/test_suite_bignum_random.data @@ -25,8 +25,11 @@ mpi_core_random_basic:0x0fffffff:"10000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE MPI random legacy=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) mpi_legacy_random_values:0x0fffffff:"10000001" -MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) -mpi_mod_random_values:0x0fffffff:"10000001" +MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) (Mont) +mpi_mod_random_values:0x0fffffff:"10000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY + +MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) (canon) +mpi_mod_random_values:0x0fffffff:"10000001":MBEDTLS_MPI_MOD_REP_OPT_RED MPI core random basic: 2^29-1..2^29+1 (NOT_ACCEPTABLE) mpi_core_random_basic:0x1fffffff:"20000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE @@ -34,8 +37,11 @@ mpi_core_random_basic:0x1fffffff:"20000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE MPI random legacy=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) mpi_legacy_random_values:0x1fffffff:"20000001" -MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) -mpi_mod_random_values:0x1fffffff:"20000001" +MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) (Mont) +mpi_mod_random_values:0x1fffffff:"20000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY + +MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) (canon) +mpi_mod_random_values:0x1fffffff:"20000001":MBEDTLS_MPI_MOD_REP_OPT_RED MPI core random basic: 2^30-1..2^30+1 (NOT_ACCEPTABLE) mpi_core_random_basic:0x3fffffff:"40000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE @@ -43,8 +49,11 @@ mpi_core_random_basic:0x3fffffff:"40000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE MPI random legacy=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) mpi_legacy_random_values:0x3fffffff:"40000001" -MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) -mpi_mod_random_values:0x3fffffff:"40000001" +MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) (Mont) +mpi_mod_random_values:0x3fffffff:"40000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY + +MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) (canon) +mpi_mod_random_values:0x3fffffff:"40000001":MBEDTLS_MPI_MOD_REP_OPT_RED MPI core random basic: 2^31-1..2^31+1 (NOT_ACCEPTABLE) mpi_core_random_basic:0x7fffffff:"80000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE @@ -52,8 +61,11 @@ mpi_core_random_basic:0x7fffffff:"80000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE MPI random legacy=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) mpi_legacy_random_values:0x7fffffff:"80000001" -MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) -mpi_mod_random_values:0x7fffffff:"80000001" +MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) (Mont) +mpi_mod_random_values:0x7fffffff:"80000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY + +MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) (canon) +mpi_mod_random_values:0x7fffffff:"80000001":MBEDTLS_MPI_MOD_REP_OPT_RED MPI random in range: 1..2 mpi_random_many:1:"02":1000 @@ -246,23 +258,41 @@ mpi_legacy_random_values:0:"0100000000000000000000000000000000000000000000000000 MPI random legacy=core: 0..2^256+1 mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" -MPI random mod=core: 0..1 -mpi_mod_random_values:0:"01" +MPI random mod=core: 0..1 (Mont) +mpi_mod_random_values:0:"01":MBEDTLS_MPI_MOD_REP_MONTGOMERY -MPI random mod=core: 0..3 -mpi_mod_random_values:0:"03" +MPI random mod=core: 0..1 (canon) +mpi_mod_random_values:0:"01":MBEDTLS_MPI_MOD_REP_OPT_RED -MPI random mod=core: 1..3 -mpi_mod_random_values:1:"03" +MPI random mod=core: 0..3 (Mont) +mpi_mod_random_values:0:"03":MBEDTLS_MPI_MOD_REP_MONTGOMERY -MPI random mod=core: 2^30..2^31-1 -mpi_mod_random_values:0x40000000:"7fffffff" +MPI random mod=core: 0..3 (canon) +mpi_mod_random_values:0:"03":MBEDTLS_MPI_MOD_REP_OPT_RED -MPI random mod=core: 2^31-1..2^32-1 -mpi_mod_random_values:0x7fffffff:"ffffffff" +MPI random mod=core: 1..3 (Mont) +mpi_mod_random_values:1:"03":MBEDTLS_MPI_MOD_REP_MONTGOMERY -MPI random mod=core: 0..2^256+1 -mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" +MPI random mod=core: 1..3 (canon) +mpi_mod_random_values:1:"03":MBEDTLS_MPI_MOD_REP_OPT_RED + +MPI random mod=core: 2^30..2^31-1 (Mont) +mpi_mod_random_values:0x40000000:"7fffffff":MBEDTLS_MPI_MOD_REP_MONTGOMERY + +MPI random mod=core: 2^30..2^31-1 (canon) +mpi_mod_random_values:0x40000000:"7fffffff":MBEDTLS_MPI_MOD_REP_OPT_RED + +MPI random mod=core: 2^31-1..2^32-1 (Mont) +mpi_mod_random_values:0x7fffffff:"ffffffff":MBEDTLS_MPI_MOD_REP_MONTGOMERY + +MPI random mod=core: 2^31-1..2^32-1 (canon) +mpi_mod_random_values:0x7fffffff:"ffffffff":MBEDTLS_MPI_MOD_REP_OPT_RED + +MPI random mod=core: 0..2^256+1 (Mont) +mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY + +MPI random mod=core: 0..2^256+1 (canon) +mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_REP_OPT_RED MPI random mod validation: 1 limb, good, 0..1 mpi_mod_random_validation:0:"1":0:0 diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index 0f431cd6d2..f2cb206fc7 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -192,7 +192,7 @@ exit: /* END_CASE */ /* BEGIN_CASE */ -void mpi_mod_random_values( int min, char *max_hex ) +void mpi_mod_random_values( int min, char *max_hex, int rep ) { /* Same RNG as in mpi_core_random_basic */ mbedtls_test_rnd_pseudo_info rnd_core = { @@ -210,9 +210,7 @@ void mpi_mod_random_values( int min, char *max_hex ) mbedtls_mpi_mod_modulus N; mbedtls_mpi_mod_modulus_init( &N ); - TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex, - MBEDTLS_MPI_MOD_REP_MONTGOMERY ), - 0 ); + TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex, rep ), 0 ); ASSERT_ALLOC( R_core, N.limbs ); ASSERT_ALLOC( R_mod_raw, N.limbs ); ASSERT_ALLOC( R_mod_digits, N.limbs ); @@ -240,10 +238,12 @@ void mpi_mod_random_values( int min, char *max_hex ) TEST_EQUAL( core_ret, mod_ret ); if( core_ret == 0 ) { - TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_raw, &N ), 0 ); + TEST_EQUAL( mbedtls_mpi_mod_raw_modulus_to_canonical_rep( R_mod_raw, &N ), + 0 ); ASSERT_COMPARE( R_core, N.limbs * ciL, R_mod_raw, N.limbs * ciL ); - TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_digits, &N ), 0 ); + TEST_EQUAL( mbedtls_mpi_mod_raw_modulus_to_canonical_rep( R_mod_digits, &N ), + 0 ); ASSERT_COMPARE( R_core, N.limbs * ciL, R_mod_digits, N.limbs * ciL ); } @@ -428,7 +428,7 @@ void mpi_mod_random_validation( int min, char *bound_hex, mbedtls_mpi_mod_modulus_init( &N ); TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, bound_hex, - MBEDTLS_MPI_MOD_REP_MONTGOMERY ), + MBEDTLS_MPI_MOD_REP_OPT_RED ), 0 ); size_t result_limbs = N.limbs + result_limbs_delta; ASSERT_ALLOC( result_digits, result_limbs ); @@ -445,7 +445,6 @@ void mpi_mod_random_validation( int min, char *bound_hex, * size as the modulus, otherwise it's a mistake in the test data. */ TEST_EQUAL( result_limbs, N.limbs ); /* Sanity check: check that the result is in range */ - TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( result_digits, &N ), 0 ); TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ), 1 ); /* Check result >= min (changes result) */ @@ -463,7 +462,6 @@ void mpi_mod_random_validation( int min, char *bound_hex, expected_ret ); if( expected_ret == 0 ) { - TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( result_digits, &N ), 0 ); TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ), 1 ); TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result.p, min, From d1aa75d7b2168a4d48a2b6f433ce343715e6508a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 22:01:27 +0100 Subject: [PATCH 19/31] Update of the RNG seed in mpi_mod_random_values The code had an earlier version. Update to the new seed that mpi_core_random_basic has moved to. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_bignum_random.function | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index f2cb206fc7..4709148900 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -195,10 +195,7 @@ exit: void mpi_mod_random_values( int min, char *max_hex, int rep ) { /* Same RNG as in mpi_core_random_basic */ - mbedtls_test_rnd_pseudo_info rnd_core = { - {'T', 'h', 'i', 's', ' ', 'i', ',', 'a', - 's', 'e', 'e', 'd', '!', 0}, - 0, 0}; + mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed; mbedtls_test_rnd_pseudo_info rnd_mod_raw; memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) ); mbedtls_test_rnd_pseudo_info rnd_mod; From 4c950d5ff10dea62c095b76a74d0f363b49e3f95 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 22:02:55 +0100 Subject: [PATCH 20/31] Cosmetic fix Signed-off-by: Gilles Peskine --- tests/suites/test_suite_bignum_mod_raw.function | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_bignum_mod_raw.function b/tests/suites/test_suite_bignum_mod_raw.function index 51d096e908..244c85465b 100644 --- a/tests/suites/test_suite_bignum_mod_raw.function +++ b/tests/suites/test_suite_bignum_mod_raw.function @@ -555,7 +555,7 @@ void mpi_mod_raw_modulus_to_canonical_rep( const char *input_N, int rep, mbedtls_mpi_mod_modulus N; mbedtls_mpi_mod_modulus_init( &N ); mbedtls_mpi_uint *A = NULL; - size_t A_limbs = 0;; + size_t A_limbs = 0; mbedtls_mpi_uint *X = NULL; size_t X_limbs = 0; From ad335b55ff7e3c33ba02d49af1c144e23177c173 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Dec 2022 22:39:15 +0100 Subject: [PATCH 21/31] Fix representation conversion with 32-bit limbs The Montgomery representation depends on the limb size. So the representation conversion test cases need separate 64-bit and 32-bit cases when the representation is Montgomery. Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_mod_raw.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index 800bcb13e1..e108fe3a01 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Iterator, List +from typing import Iterator, List, Optional, Union from . import test_case from . import test_data_generation @@ -115,9 +115,13 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, """Test cases for representation conversion.""" arity = 1 - def __init__(self, val_n: str, val_a: str, + def __init__(self, val_n: str, val_a: str, bits_in_limb: Optional[int], rep: bignum_common.ModulusRepresentation) -> None: - super().__init__(val_n=val_n, val_a=val_a) + if bits_in_limb is None: + super().__init__(val_n=val_n, val_a=val_a) + else: + self.input_style = "arch_split" + super().__init__(val_n=val_n, val_a=val_a, bits_in_limb=bits_in_limb) self.rep = rep def arguments(self) -> List[str]: @@ -125,16 +129,26 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, bignum_common.quote_str(self.arg_a)] + self.result()) + def description(self) -> str: + base = super().description() + mod_with_rep = 'mod({})'.format(self.rep.name) + return base.replace('mod', mod_with_rep, 1) + @classmethod def generate_function_tests(cls) -> Iterator[test_case.TestCase]: representations = \ bignum_common.ModulusRepresentation.supported_representations() for rep in representations: + if rep is bignum_common.ModulusRepresentation.MONTGOMERY: + limb_sizes = cls.limb_sizes #type: Union[List[int], List[None]] + else: + limb_sizes = [None] # no dependency on limb size for n in cls.moduli: for a in cls.input_values: - test_object = cls(n, a, rep) - if test_object.is_valid: - yield test_object.create_test_case() + for bil in limb_sizes: + test_object = cls(n, a, bil, rep) + if test_object.is_valid: + yield test_object.create_test_case() class BignumModRawCanonicalToModulusRep(BignumModRawConvertRep): """Test cases for mpi_mod_raw_canonical_to_modulus_rep.""" From 3d2aab891b6f185b08485d362cb1217ad0b5b036 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 21 Dec 2022 17:30:10 +0000 Subject: [PATCH 22/31] bignum_common: Adjusted `format_arg` to always size input according to modulo. Signed-off-by: Minos Galanakis --- scripts/mbedtls_dev/bignum_common.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_common.py b/scripts/mbedtls_dev/bignum_common.py index 7b2669af72..bb64ce0796 100644 --- a/scripts/mbedtls_dev/bignum_common.py +++ b/scripts/mbedtls_dev/bignum_common.py @@ -297,10 +297,7 @@ class ModOperationCommon(OperationCommon): return self.format_arg(self.val_n) def format_arg(self, val: str) -> str: - if self.input_style == "variable": - return val.zfill(len(hex(self.int_n)) - 2) - else: - return super().format_arg(val) + return super().format_arg(val).zfill(self.hex_digits) def arguments(self) -> List[str]: return [quote_str(self.arg_n)] + super().arguments() From 5689410083137d0052c19f321ad460d3b690b15f Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 21 Dec 2022 17:31:56 +0000 Subject: [PATCH 23/31] bignum_mod_raw: Simplified `BignumModRawCanonicalToFromModulusRep` output expressions. Signed-off-by: Minos Galanakis --- scripts/mbedtls_dev/bignum_mod_raw.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index e108fe3a01..a2336f95a6 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -156,8 +156,7 @@ class BignumModRawCanonicalToModulusRep(BignumModRawConvertRep): test_name = "Rep canon->mod" def result(self) -> List[str]: - result = self.convert_from_canonical(self.int_a, self.rep) - return [self.format_result(result)] + return [self.format_result(self.convert_from_canonical(self.int_a, self.rep))] class BignumModRawModulusToCanonicalRep(BignumModRawConvertRep): """Test cases for mpi_mod_raw_modulus_to_canonical_rep.""" @@ -166,8 +165,7 @@ class BignumModRawModulusToCanonicalRep(BignumModRawConvertRep): @property def arg_a(self) -> str: - converted_a = self.convert_from_canonical(self.int_a, self.rep) - return self.format_arg(hex(converted_a)[2:]) + return self.format_arg("{:x}".format(self.convert_from_canonical(self.int_a, self.rep))) def result(self) -> List[str]: return [self.format_result(self.int_a)] From ae4d2cf3e3879be0fee1d3027826129776d99373 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 21 Dec 2022 17:34:15 +0000 Subject: [PATCH 24/31] bignum_common.py: Introduce the set_representation setter. This patch adds the default representation attribute through a setter() method in `BignumModRawConvertRep()` It also adds standard common template properties: symbol = "" input_style = "arch_split" arity = 1 Signed-off-by: Minos Galanakis --- scripts/mbedtls_dev/bignum_mod_raw.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index a2336f95a6..b244e09732 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -113,16 +113,13 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, # This is an abstract class, it's ok to have unimplemented methods. #pylint: disable=abstract-method """Test cases for representation conversion.""" + symbol = "" + input_style = "arch_split" arity = 1 + rep = bignum_common.ModulusRepresentation.INVALID - def __init__(self, val_n: str, val_a: str, bits_in_limb: Optional[int], - rep: bignum_common.ModulusRepresentation) -> None: - if bits_in_limb is None: - super().__init__(val_n=val_n, val_a=val_a) - else: - self.input_style = "arch_split" - super().__init__(val_n=val_n, val_a=val_a, bits_in_limb=bits_in_limb) - self.rep = rep + def set_representation(self, r: bignum_common.ModulusRepresentation) -> bool: + self.rep = r def arguments(self) -> List[str]: return ([bignum_common.quote_str(self.arg_n), self.rep.symbol(), From afa7c04105813ded8972893144355a1999942acc Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 21 Dec 2022 17:38:16 +0000 Subject: [PATCH 25/31] bignum_common.py: Refactored `BignumModRawConvertRep.generate_function_tests()` This patch adjusts the test generating method to calculate all possible combinations for (modulo, input, limb_sizes, representation). Signed-off-by: Minos Galanakis --- scripts/mbedtls_dev/bignum_mod_raw.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index b244e09732..ebbc970e52 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -133,17 +133,13 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, @classmethod def generate_function_tests(cls) -> Iterator[test_case.TestCase]: - representations = \ - bignum_common.ModulusRepresentation.supported_representations() - for rep in representations: - if rep is bignum_common.ModulusRepresentation.MONTGOMERY: - limb_sizes = cls.limb_sizes #type: Union[List[int], List[None]] - else: - limb_sizes = [None] # no dependency on limb size + + for rep in bignum_common.ModulusRepresentation.supported_representations(): for n in cls.moduli: for a in cls.input_values: - for bil in limb_sizes: - test_object = cls(n, a, bil, rep) + for bil in cls.limb_sizes: + test_object = cls(n, a, bits_in_limb=bil) + test_object.set_representation(rep) if test_object.is_valid: yield test_object.create_test_case() From 342b9a903d459f22226633c405c03b186978660d Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 21 Dec 2022 17:41:30 +0000 Subject: [PATCH 26/31] bignum_mod_raw.py: Added a filtering logic to `BignumModRawConvertRep.generate_function_tests()` This patch introduces a hybrid approach to input_styles, and will remove the dependency requirements from test cases with `ModulusRepresentation.OPT_RED` As a result it is reducing testing input duplication. Signed-off-by: Minos Galanakis --- scripts/mbedtls_dev/bignum_mod_raw.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index ebbc970e52..98605d6551 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -140,6 +140,11 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, for bil in cls.limb_sizes: test_object = cls(n, a, bits_in_limb=bil) test_object.set_representation(rep) + #Filters out the duplicate + if rep == bignum_common.ModulusRepresentation.OPT_RED: + test_object.dependencies= [] + if bil == 64: + continue if test_object.is_valid: yield test_object.create_test_case() From 636809f2b98872bd278d8ad9175329231a38f02f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 21 Dec 2022 20:12:31 +0100 Subject: [PATCH 27/31] Fix type declaration Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_mod_raw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index 98605d6551..89ae825fc4 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -118,7 +118,7 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, arity = 1 rep = bignum_common.ModulusRepresentation.INVALID - def set_representation(self, r: bignum_common.ModulusRepresentation) -> bool: + def set_representation(self, r: bignum_common.ModulusRepresentation) -> None: self.rep = r def arguments(self) -> List[str]: From 6d40e54db0cf3e7e16ea9fe3ca4a03d85e04c4fc Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 21 Dec 2022 20:18:23 +0100 Subject: [PATCH 28/31] Split the high nesting of BignumModRawConvertRep.generate_function_tests Pylint complains about the nesting. It's not wrong. No behavior change. Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_mod_raw.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index 89ae825fc4..352e438ab9 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -131,22 +131,27 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, mod_with_rep = 'mod({})'.format(self.rep.name) return base.replace('mod', mod_with_rep, 1) + @classmethod + def test_cases_for_values(cls, rep: bignum_common.ModulusRepresentation, + n: str, a: str) -> Iterator[test_case.TestCase]: + for bil in cls.limb_sizes: + test_object = cls(n, a, bits_in_limb=bil) + test_object.set_representation(rep) + #Filters out the duplicate + if rep == bignum_common.ModulusRepresentation.OPT_RED: + test_object.dependencies= [] + if bil == 64: + continue + if test_object.is_valid: + yield test_object.create_test_case() + @classmethod def generate_function_tests(cls) -> Iterator[test_case.TestCase]: for rep in bignum_common.ModulusRepresentation.supported_representations(): for n in cls.moduli: for a in cls.input_values: - for bil in cls.limb_sizes: - test_object = cls(n, a, bits_in_limb=bil) - test_object.set_representation(rep) - #Filters out the duplicate - if rep == bignum_common.ModulusRepresentation.OPT_RED: - test_object.dependencies= [] - if bil == 64: - continue - if test_object.is_valid: - yield test_object.create_test_case() + yield from cls.test_cases_for_values(rep, n, a) class BignumModRawCanonicalToModulusRep(BignumModRawConvertRep): """Test cases for mpi_mod_raw_canonical_to_modulus_rep.""" From 394da2d8576d3b450b310f3b2420953eec27c765 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 21 Dec 2022 20:20:44 +0100 Subject: [PATCH 29/31] Pacify pylint Except for missing documentation, which will come in a subsequent commit. Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_mod_raw.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index 352e438ab9..4628bffe41 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Iterator, List, Optional, Union +from typing import Iterator, List from . import test_case from . import test_data_generation @@ -139,7 +139,7 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, test_object.set_representation(rep) #Filters out the duplicate if rep == bignum_common.ModulusRepresentation.OPT_RED: - test_object.dependencies= [] + test_object.dependencies = [] if bil == 64: continue if test_object.is_valid: From f287366376b337b7294f6c8f27efbc38a62035c9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 21 Dec 2022 20:28:29 +0100 Subject: [PATCH 30/31] Simplify logic and document test_cases_for_values Explain what's going on in BignumModRawConvertRep.test_case_for_values. Simplify the logic and the interdependencies related to limb sizes: * Montgomery is the special case, so base the decisions on it. * As soon as we've encountered one limb size, no matter what it is, give up. No behavior change, other than changing the numbering of test cases (which previously included more skipped test cases). Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_mod_raw.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index 4628bffe41..21add3baae 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -134,17 +134,32 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, @classmethod def test_cases_for_values(cls, rep: bignum_common.ModulusRepresentation, n: str, a: str) -> Iterator[test_case.TestCase]: + """Emit test cases for the given values (if any). + + This may emit no test cases if a isn't valid for the modulus n, + or multiple test cases if rep requires different data depending + on the limb size. + """ for bil in cls.limb_sizes: test_object = cls(n, a, bits_in_limb=bil) test_object.set_representation(rep) - #Filters out the duplicate - if rep == bignum_common.ModulusRepresentation.OPT_RED: + # The class is set to having separate test cases for each limb + # size, because the Montgomery representation requires it. + # But other representations don't require it. So for other + # representations, emit a single test case with no dependency + # on the limb size. + if rep is not bignum_common.ModulusRepresentation.MONTGOMERY: test_object.dependencies = [] - if bil == 64: - continue if test_object.is_valid: yield test_object.create_test_case() + if rep is not bignum_common.ModulusRepresentation.MONTGOMERY: + # A single test case (emitted, or skipped due to invalidity) + # is enough, since this test case doesn't depend on the + # limb size. + break + # The parent class doesn't support non-bignum parameters. So we override + # test generation, in order to have the representation as a parameter. @classmethod def generate_function_tests(cls) -> Iterator[test_case.TestCase]: From 5efe449a6af1bb1f77c19bfd913e7506d2234aa9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 21 Dec 2022 20:33:30 +0100 Subject: [PATCH 31/31] More robust dependency filtering Only remove the MBEDTLS_HAVE_INTnn dependency, not any other dependency that might be present. No behavior change, this is just robustness. Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/bignum_mod_raw.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py index 21add3baae..fa95e24fd3 100644 --- a/scripts/mbedtls_dev/bignum_mod_raw.py +++ b/scripts/mbedtls_dev/bignum_mod_raw.py @@ -149,7 +149,9 @@ class BignumModRawConvertRep(bignum_common.ModOperationCommon, # representations, emit a single test case with no dependency # on the limb size. if rep is not bignum_common.ModulusRepresentation.MONTGOMERY: - test_object.dependencies = [] + test_object.dependencies = \ + [dep for dep in test_object.dependencies + if not dep.startswith('MBEDTLS_HAVE_INT')] if test_object.is_valid: yield test_object.create_test_case() if rep is not bignum_common.ModulusRepresentation.MONTGOMERY: