| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 1 | /* BEGIN_HEADER */ | 
|  | 2 | /* Dedicated test suite for mbedtls_mpi_core_random() and the upper-layer | 
|  | 3 | * functions. Due to the complexity of how these functions are tested, | 
|  | 4 | * we test all the layers in a single test suite, unlike the way other | 
|  | 5 | * functions are tested with each layer in its own test suite. | 
| Gilles Peskine | 071f473 | 2022-12-14 19:00:56 +0100 | [diff] [blame] | 6 | * | 
|  | 7 | * Test strategy | 
|  | 8 | * ============= | 
|  | 9 | * | 
|  | 10 | * There are three main goals for testing random() functions: | 
|  | 11 | * - Parameter validation. | 
|  | 12 | * - Correctness of outputs (well-formed, in range). | 
|  | 13 | * - Distribution of outputs. | 
|  | 14 | * | 
|  | 15 | * We test parameter validation in a standard way, with unit tests with | 
|  | 16 | * positive and negative cases: | 
|  | 17 | * - mbedtls_mpi_core_random(): negative cases for mpi_core_random_basic. | 
|  | 18 | * - mbedtls_mpi_mod_raw_random(),  mbedtls_mpi_mod_random(): negative | 
|  | 19 | *   cases for mpi_mod_random_validation. | 
|  | 20 | * - mbedtls_mpi_random(): mpi_random_fail. | 
|  | 21 | * | 
|  | 22 | * We test the correctness of outputs in positive tests: | 
|  | 23 | * - mbedtls_mpi_core_random(): positive cases for mpi_core_random_basic, | 
|  | 24 | *   and mpi_random_many. | 
|  | 25 | * - mbedtls_mpi_mod_raw_random(), mbedtls_mpi_mod_random(): tested indirectly | 
|  | 26 | *   via mpi_mod_random_values. | 
|  | 27 | * - mbedtls_mpi_random(): mpi_random_sizes, plus indirectly via | 
|  | 28 | *   mpi_random_values. | 
|  | 29 | * | 
|  | 30 | * We test the distribution of outputs only for mbedtls_mpi_core_random(), | 
|  | 31 | * in mpi_random_many, which runs the function multiple times. This also | 
|  | 32 | * helps in validating the output range, through test cases with a small | 
|  | 33 | * range where any output out of range would be very likely to lead to a | 
|  | 34 | * test failure. For the other functions, we validate the distribution | 
|  | 35 | * indirectly by testing that these functions consume the random generator | 
|  | 36 | * in the same way as mbedtls_mpi_core_random(). This is done in | 
|  | 37 | * mpi_mod_random_values and mpi_legacy_random_values. | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 38 | */ | 
|  | 39 |  | 
|  | 40 | #include "mbedtls/bignum.h" | 
|  | 41 | #include "mbedtls/entropy.h" | 
|  | 42 | #include "bignum_core.h" | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 43 | #include "bignum_mod_raw.h" | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 44 | #include "constant_time_internal.h" | 
|  | 45 |  | 
|  | 46 | /* This test suite only manipulates non-negative bignums. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 47 | static int sign_is_valid(const mbedtls_mpi *X) | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 48 | { | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 49 | return X->s == 1; | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 50 | } | 
|  | 51 |  | 
| Gilles Peskine | acdefdd | 2022-12-15 15:10:36 +0100 | [diff] [blame] | 52 | /* A common initializer for test functions that should generate the same | 
|  | 53 | * sequences for reproducibility and good coverage. */ | 
|  | 54 | const mbedtls_test_rnd_pseudo_info rnd_pseudo_seed = { | 
|  | 55 | /* 16-word key */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 56 | { 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', | 
|  | 57 | 'a', ' ', 's', 'e', 'e', 'd', '!', 0 }, | 
| Gilles Peskine | acdefdd | 2022-12-15 15:10:36 +0100 | [diff] [blame] | 58 | /* 2-word initial state, should be zero */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 59 | 0, 0 | 
|  | 60 | }; | 
| Gilles Peskine | acdefdd | 2022-12-15 15:10:36 +0100 | [diff] [blame] | 61 |  | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 62 | /* Test whether bytes represents (in big-endian base 256) a number b that | 
|  | 63 | * is significantly above a power of 2. That is, b must not have a long run | 
|  | 64 | * of unset bits after the most significant bit. | 
|  | 65 | * | 
|  | 66 | * Let n be the bit-size of b, i.e. the integer such that 2^n <= b < 2^{n+1}. | 
|  | 67 | * This function returns 1 if, when drawing a number between 0 and b, | 
|  | 68 | * the probability that this number is at least 2^n is not negligible. | 
|  | 69 | * This probability is (b - 2^n) / b and this function checks that this | 
|  | 70 | * number is above some threshold A. The threshold value is heuristic and | 
|  | 71 | * based on the needs of mpi_random_many(). | 
|  | 72 | */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 73 | static int is_significantly_above_a_power_of_2(data_t *bytes) | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 74 | { | 
|  | 75 | const uint8_t *p = bytes->x; | 
|  | 76 | size_t len = bytes->len; | 
|  | 77 | unsigned x; | 
|  | 78 |  | 
|  | 79 | /* Skip leading null bytes */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 80 | while (len > 0 && p[0] == 0) { | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 81 | ++p; | 
|  | 82 | --len; | 
|  | 83 | } | 
|  | 84 | /* 0 is not significantly above a power of 2 */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 85 | if (len == 0) { | 
|  | 86 | return 0; | 
|  | 87 | } | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 88 | /* Extract the (up to) 2 most significant bytes */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 89 | if (len == 1) { | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 90 | x = p[0]; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 91 | } else { | 
|  | 92 | x = (p[0] << 8) | p[1]; | 
|  | 93 | } | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 94 |  | 
|  | 95 | /* Shift the most significant bit of x to position 8 and mask it out */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 96 | while ((x & 0xfe00) != 0) { | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 97 | x >>= 1; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 98 | } | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 99 | x &= 0x00ff; | 
|  | 100 |  | 
|  | 101 | /* At this point, x = floor((b - 2^n) / 2^(n-8)). b is significantly above | 
|  | 102 | * a power of 2 iff x is significantly above 0 compared to 2^8. | 
|  | 103 | * Testing x >= 2^4 amounts to picking A = 1/16 in the function | 
|  | 104 | * description above. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 105 | return x >= 0x10; | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 106 | } | 
|  | 107 |  | 
|  | 108 | /* END_HEADER */ | 
|  | 109 |  | 
|  | 110 | /* BEGIN_DEPENDENCIES | 
|  | 111 | * depends_on:MBEDTLS_BIGNUM_C | 
|  | 112 | * END_DEPENDENCIES | 
|  | 113 | */ | 
|  | 114 |  | 
|  | 115 | /* BEGIN_CASE */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 116 | void mpi_core_random_basic(int min, char *bound_bytes, int expected_ret) | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 117 | { | 
|  | 118 | /* Same RNG as in mpi_random_values */ | 
| Gilles Peskine | acdefdd | 2022-12-15 15:10:36 +0100 | [diff] [blame] | 119 | mbedtls_test_rnd_pseudo_info rnd = rnd_pseudo_seed; | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 120 | size_t limbs; | 
|  | 121 | mbedtls_mpi_uint *lower_bound = NULL; | 
|  | 122 | mbedtls_mpi_uint *upper_bound = NULL; | 
|  | 123 | mbedtls_mpi_uint *result = NULL; | 
|  | 124 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 125 | TEST_EQUAL(0, mbedtls_test_read_mpi_core(&upper_bound, &limbs, | 
|  | 126 | bound_bytes)); | 
| Tom Cosgrove | 05b2a87 | 2023-07-21 11:31:13 +0100 | [diff] [blame] | 127 | TEST_CALLOC(lower_bound, limbs); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 128 | lower_bound[0] = min; | 
| Tom Cosgrove | 05b2a87 | 2023-07-21 11:31:13 +0100 | [diff] [blame] | 129 | TEST_CALLOC(result, limbs); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 130 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 131 | TEST_EQUAL(expected_ret, | 
|  | 132 | mbedtls_mpi_core_random(result, min, upper_bound, limbs, | 
|  | 133 | mbedtls_test_rnd_pseudo_rand, &rnd)); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 134 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 135 | if (expected_ret == 0) { | 
|  | 136 | TEST_EQUAL(0, mbedtls_mpi_core_lt_ct(result, lower_bound, limbs)); | 
| Dave Rodgman | 14bec14 | 2023-05-11 16:19:27 +0100 | [diff] [blame] | 137 | TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result, upper_bound, limbs)); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 138 | } | 
|  | 139 |  | 
|  | 140 | exit: | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 141 | mbedtls_free(lower_bound); | 
|  | 142 | mbedtls_free(upper_bound); | 
|  | 143 | mbedtls_free(result); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 144 | } | 
|  | 145 | /* END_CASE */ | 
|  | 146 |  | 
|  | 147 | /* BEGIN_CASE */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 148 | void mpi_legacy_random_values(int min, char *max_hex) | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 149 | { | 
|  | 150 | /* Same RNG as in mpi_core_random_basic */ | 
| Gilles Peskine | acdefdd | 2022-12-15 15:10:36 +0100 | [diff] [blame] | 151 | mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed; | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 152 | mbedtls_test_rnd_pseudo_info rnd_legacy; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 153 | memcpy(&rnd_legacy, &rnd_core, sizeof(rnd_core)); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 154 | mbedtls_mpi max_legacy; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 155 | mbedtls_mpi_init(&max_legacy); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 156 | mbedtls_mpi_uint *R_core = NULL; | 
|  | 157 | mbedtls_mpi R_legacy; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 158 | mbedtls_mpi_init(&R_legacy); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 159 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 160 | TEST_EQUAL(0, mbedtls_test_read_mpi(&max_legacy, max_hex)); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 161 | size_t limbs = max_legacy.n; | 
| Tom Cosgrove | 05b2a87 | 2023-07-21 11:31:13 +0100 | [diff] [blame] | 162 | TEST_CALLOC(R_core, limbs); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 163 |  | 
|  | 164 | /* Call the legacy function and the core function with the same random | 
|  | 165 | * stream. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 166 | int core_ret = mbedtls_mpi_core_random(R_core, min, max_legacy.p, limbs, | 
|  | 167 | mbedtls_test_rnd_pseudo_rand, | 
|  | 168 | &rnd_core); | 
|  | 169 | int legacy_ret = mbedtls_mpi_random(&R_legacy, min, &max_legacy, | 
|  | 170 | mbedtls_test_rnd_pseudo_rand, | 
|  | 171 | &rnd_legacy); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 172 |  | 
|  | 173 | /* They must return the same status, and, on success, output the | 
|  | 174 | * same number, with the same limb count. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 175 | TEST_EQUAL(core_ret, legacy_ret); | 
|  | 176 | if (core_ret == 0) { | 
| Tom Cosgrove | e4e9e7d | 2023-07-21 11:40:20 +0100 | [diff] [blame] | 177 | TEST_MEMORY_COMPARE(R_core, limbs * ciL, | 
| Tom Cosgrove | 0540fe7 | 2023-07-27 14:17:27 +0100 | [diff] [blame] | 178 | R_legacy.p, R_legacy.n * ciL); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 179 | } | 
|  | 180 |  | 
|  | 181 | /* Also check that they have consumed the RNG in the same way. */ | 
|  | 182 | /* This may theoretically fail on rare platforms with padding in | 
|  | 183 | * the structure! If this is a problem in practice, change to a | 
|  | 184 | * field-by-field comparison. */ | 
| Tom Cosgrove | e4e9e7d | 2023-07-21 11:40:20 +0100 | [diff] [blame] | 185 | TEST_MEMORY_COMPARE(&rnd_core, sizeof(rnd_core), | 
| Tom Cosgrove | 0540fe7 | 2023-07-27 14:17:27 +0100 | [diff] [blame] | 186 | &rnd_legacy, sizeof(rnd_legacy)); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 187 |  | 
|  | 188 | exit: | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 189 | mbedtls_mpi_free(&max_legacy); | 
|  | 190 | mbedtls_free(R_core); | 
|  | 191 | mbedtls_mpi_free(&R_legacy); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 192 | } | 
|  | 193 | /* END_CASE */ | 
|  | 194 |  | 
| Janos Follath | f2334b7 | 2023-08-17 12:24:46 +0000 | [diff] [blame] | 195 | /* BEGIN_CASE depends_on:MBEDTLS_ECP_WITH_MPI_UINT */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 196 | void mpi_mod_random_values(int min, char *max_hex, int rep) | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 197 | { | 
|  | 198 | /* Same RNG as in mpi_core_random_basic */ | 
| Gilles Peskine | d1aa75d | 2022-12-20 22:01:27 +0100 | [diff] [blame] | 199 | mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed; | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 200 | mbedtls_test_rnd_pseudo_info rnd_mod_raw; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 201 | memcpy(&rnd_mod_raw, &rnd_core, sizeof(rnd_core)); | 
| Gilles Peskine | b1eea02 | 2022-12-07 22:59:27 +0100 | [diff] [blame] | 202 | mbedtls_test_rnd_pseudo_info rnd_mod; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 203 | memcpy(&rnd_mod, &rnd_core, sizeof(rnd_core)); | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 204 | mbedtls_mpi_uint *R_core = NULL; | 
|  | 205 | mbedtls_mpi_uint *R_mod_raw = NULL; | 
| Gilles Peskine | b1eea02 | 2022-12-07 22:59:27 +0100 | [diff] [blame] | 206 | mbedtls_mpi_uint *R_mod_digits = NULL; | 
|  | 207 | mbedtls_mpi_mod_residue R_mod; | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 208 | mbedtls_mpi_mod_modulus N; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 209 | mbedtls_mpi_mod_modulus_init(&N); | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 210 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 211 | TEST_EQUAL(mbedtls_test_read_mpi_modulus(&N, max_hex, rep), 0); | 
| Tom Cosgrove | 05b2a87 | 2023-07-21 11:31:13 +0100 | [diff] [blame] | 212 | TEST_CALLOC(R_core, N.limbs); | 
|  | 213 | TEST_CALLOC(R_mod_raw, N.limbs); | 
|  | 214 | TEST_CALLOC(R_mod_digits, N.limbs); | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 215 | TEST_EQUAL(mbedtls_mpi_mod_residue_setup(&R_mod, &N, | 
|  | 216 | R_mod_digits, N.limbs), | 
|  | 217 | 0); | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 218 |  | 
|  | 219 | /* Call the core and mod random() functions with the same random stream. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 220 | int core_ret = mbedtls_mpi_core_random(R_core, | 
|  | 221 | min, N.p, N.limbs, | 
|  | 222 | mbedtls_test_rnd_pseudo_rand, | 
|  | 223 | &rnd_core); | 
|  | 224 | int mod_raw_ret = mbedtls_mpi_mod_raw_random(R_mod_raw, | 
|  | 225 | min, &N, | 
|  | 226 | mbedtls_test_rnd_pseudo_rand, | 
|  | 227 | &rnd_mod_raw); | 
|  | 228 | int mod_ret = mbedtls_mpi_mod_random(&R_mod, | 
|  | 229 | min, &N, | 
|  | 230 | mbedtls_test_rnd_pseudo_rand, | 
|  | 231 | &rnd_mod); | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 232 |  | 
|  | 233 | /* They must return the same status, and, on success, output the | 
|  | 234 | * same number, with the same limb count. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 235 | TEST_EQUAL(core_ret, mod_raw_ret); | 
|  | 236 | TEST_EQUAL(core_ret, mod_ret); | 
|  | 237 | if (core_ret == 0) { | 
|  | 238 | TEST_EQUAL(mbedtls_mpi_mod_raw_modulus_to_canonical_rep(R_mod_raw, &N), | 
|  | 239 | 0); | 
| Tom Cosgrove | e4e9e7d | 2023-07-21 11:40:20 +0100 | [diff] [blame] | 240 | TEST_MEMORY_COMPARE(R_core, N.limbs * ciL, | 
| Tom Cosgrove | 0540fe7 | 2023-07-27 14:17:27 +0100 | [diff] [blame] | 241 | R_mod_raw, N.limbs * ciL); | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 242 | TEST_EQUAL(mbedtls_mpi_mod_raw_modulus_to_canonical_rep(R_mod_digits, &N), | 
|  | 243 | 0); | 
| Tom Cosgrove | e4e9e7d | 2023-07-21 11:40:20 +0100 | [diff] [blame] | 244 | TEST_MEMORY_COMPARE(R_core, N.limbs * ciL, | 
| Tom Cosgrove | 0540fe7 | 2023-07-27 14:17:27 +0100 | [diff] [blame] | 245 | R_mod_digits, N.limbs * ciL); | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 246 | } | 
|  | 247 |  | 
|  | 248 | /* Also check that they have consumed the RNG in the same way. */ | 
|  | 249 | /* This may theoretically fail on rare platforms with padding in | 
|  | 250 | * the structure! If this is a problem in practice, change to a | 
|  | 251 | * field-by-field comparison. */ | 
| Tom Cosgrove | e4e9e7d | 2023-07-21 11:40:20 +0100 | [diff] [blame] | 252 | TEST_MEMORY_COMPARE(&rnd_core, sizeof(rnd_core), | 
| Tom Cosgrove | 0540fe7 | 2023-07-27 14:17:27 +0100 | [diff] [blame] | 253 | &rnd_mod_raw, sizeof(rnd_mod_raw)); | 
| Tom Cosgrove | e4e9e7d | 2023-07-21 11:40:20 +0100 | [diff] [blame] | 254 | TEST_MEMORY_COMPARE(&rnd_core, sizeof(rnd_core), | 
| Tom Cosgrove | 0540fe7 | 2023-07-27 14:17:27 +0100 | [diff] [blame] | 255 | &rnd_mod, sizeof(rnd_mod)); | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 256 |  | 
|  | 257 | exit: | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 258 | mbedtls_test_mpi_mod_modulus_free_with_limbs(&N); | 
|  | 259 | mbedtls_free(R_core); | 
|  | 260 | mbedtls_free(R_mod_raw); | 
|  | 261 | mbedtls_free(R_mod_digits); | 
| Gilles Peskine | a57cf98 | 2022-12-06 22:54:09 +0100 | [diff] [blame] | 262 | } | 
|  | 263 | /* END_CASE */ | 
|  | 264 |  | 
|  | 265 | /* BEGIN_CASE */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 266 | void mpi_random_many(int min, char *bound_hex, int iterations) | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 267 | { | 
|  | 268 | /* Generate numbers in the range 1..bound-1. Do it iterations times. | 
|  | 269 | * This function assumes that the value of bound is at least 2 and | 
|  | 270 | * that iterations is large enough that a one-in-2^iterations chance | 
|  | 271 | * effectively never occurs. | 
|  | 272 | */ | 
|  | 273 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 274 | data_t bound_bytes = { NULL, 0 }; | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 275 | mbedtls_mpi_uint *upper_bound = NULL; | 
|  | 276 | size_t limbs; | 
|  | 277 | size_t n_bits; | 
|  | 278 | mbedtls_mpi_uint *result = NULL; | 
|  | 279 | size_t b; | 
|  | 280 | /* If upper_bound is small, stats[b] is the number of times the value b | 
|  | 281 | * has been generated. Otherwise stats[b] is the number of times a | 
|  | 282 | * value with bit b set has been generated. */ | 
|  | 283 | size_t *stats = NULL; | 
|  | 284 | size_t stats_len; | 
|  | 285 | int full_stats; | 
|  | 286 | size_t i; | 
|  | 287 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 288 | TEST_EQUAL(0, mbedtls_test_read_mpi_core(&upper_bound, &limbs, | 
|  | 289 | bound_hex)); | 
| Tom Cosgrove | 05b2a87 | 2023-07-21 11:31:13 +0100 | [diff] [blame] | 290 | TEST_CALLOC(result, limbs); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 291 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 292 | n_bits = mbedtls_mpi_core_bitlen(upper_bound, limbs); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 293 | /* Consider a bound "small" if it's less than 2^5. This value is chosen | 
|  | 294 | * to be small enough that the probability of missing one value is | 
|  | 295 | * negligible given the number of iterations. It must be less than | 
|  | 296 | * 256 because some of the code below assumes that "small" values | 
|  | 297 | * fit in a byte. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 298 | if (n_bits <= 5) { | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 299 | full_stats = 1; | 
|  | 300 | stats_len = (uint8_t) upper_bound[0]; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 301 | } else { | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 302 | full_stats = 0; | 
|  | 303 | stats_len = n_bits; | 
|  | 304 | } | 
| Tom Cosgrove | 05b2a87 | 2023-07-21 11:31:13 +0100 | [diff] [blame] | 305 | TEST_CALLOC(stats, stats_len); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 306 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 307 | for (i = 0; i < (size_t) iterations; i++) { | 
|  | 308 | mbedtls_test_set_step(i); | 
|  | 309 | TEST_EQUAL(0, mbedtls_mpi_core_random(result, | 
|  | 310 | min, upper_bound, limbs, | 
|  | 311 | mbedtls_test_rnd_std_rand, NULL)); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 312 |  | 
|  | 313 | /* Temporarily use a legacy MPI for analysis, because the | 
|  | 314 | * necessary auxiliary functions don't exist yet in core. */ | 
| Dave Rodgman | 84eaefa | 2023-07-11 09:52:31 +0100 | [diff] [blame] | 315 | mbedtls_mpi B = { .s = 1, .n = limbs, .p = upper_bound }; | 
|  | 316 | mbedtls_mpi R = { .s = 1, .n = limbs, .p = result }; | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 317 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 318 | TEST_ASSERT(mbedtls_mpi_cmp_mpi(&R, &B) < 0); | 
|  | 319 | TEST_ASSERT(mbedtls_mpi_cmp_int(&R, min) >= 0); | 
|  | 320 | if (full_stats) { | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 321 | uint8_t value; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 322 | TEST_EQUAL(0, mbedtls_mpi_write_binary(&R, &value, 1)); | 
|  | 323 | TEST_ASSERT(value < stats_len); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 324 | ++stats[value]; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 325 | } else { | 
|  | 326 | for (b = 0; b < n_bits; b++) { | 
|  | 327 | stats[b] += mbedtls_mpi_get_bit(&R, b); | 
|  | 328 | } | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 329 | } | 
|  | 330 | } | 
|  | 331 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 332 | if (full_stats) { | 
|  | 333 | for (b = min; b < stats_len; b++) { | 
|  | 334 | mbedtls_test_set_step(1000000 + b); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 335 | /* Assert that each value has been reached at least once. | 
|  | 336 | * This is almost guaranteed if the iteration count is large | 
|  | 337 | * enough. This is a very crude way of checking the distribution. | 
|  | 338 | */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 339 | TEST_ASSERT(stats[b] > 0); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 340 | } | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 341 | } else { | 
|  | 342 | bound_bytes.len = limbs * sizeof(mbedtls_mpi_uint); | 
| Tom Cosgrove | 05b2a87 | 2023-07-21 11:31:13 +0100 | [diff] [blame] | 343 | TEST_CALLOC(bound_bytes.x, bound_bytes.len); | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 344 | mbedtls_mpi_core_write_be(upper_bound, limbs, | 
|  | 345 | bound_bytes.x, bound_bytes.len); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 346 | int statistically_safe_all_the_way = | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 347 | is_significantly_above_a_power_of_2(&bound_bytes); | 
|  | 348 | for (b = 0; b < n_bits; b++) { | 
|  | 349 | mbedtls_test_set_step(1000000 + b); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 350 | /* Assert that each bit has been set in at least one result and | 
|  | 351 | * clear in at least one result. Provided that iterations is not | 
|  | 352 | * too small, it would be extremely unlikely for this not to be | 
|  | 353 | * the case if the results are uniformly distributed. | 
|  | 354 | * | 
|  | 355 | * As an exception, the top bit may legitimately never be set | 
|  | 356 | * if bound is a power of 2 or only slightly above. | 
|  | 357 | */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 358 | if (statistically_safe_all_the_way || b != n_bits - 1) { | 
|  | 359 | TEST_ASSERT(stats[b] > 0); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 360 | } | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 361 | TEST_ASSERT(stats[b] < (size_t) iterations); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 362 | } | 
|  | 363 | } | 
|  | 364 |  | 
|  | 365 | exit: | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 366 | mbedtls_free(bound_bytes.x); | 
|  | 367 | mbedtls_free(upper_bound); | 
|  | 368 | mbedtls_free(result); | 
|  | 369 | mbedtls_free(stats); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 370 | } | 
|  | 371 | /* END_CASE */ | 
|  | 372 |  | 
|  | 373 | /* BEGIN_CASE */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 374 | void mpi_random_sizes(int min, data_t *bound_bytes, int nlimbs, int before) | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 375 | { | 
|  | 376 | mbedtls_mpi upper_bound; | 
|  | 377 | mbedtls_mpi result; | 
|  | 378 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 379 | mbedtls_mpi_init(&upper_bound); | 
|  | 380 | mbedtls_mpi_init(&result); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 381 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 382 | if (before != 0) { | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 383 | /* Set result to sign(before) * 2^(|before|-1) */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 384 | TEST_ASSERT(mbedtls_mpi_lset(&result, before > 0 ? 1 : -1) == 0); | 
|  | 385 | if (before < 0) { | 
|  | 386 | before = -before; | 
|  | 387 | } | 
|  | 388 | TEST_ASSERT(mbedtls_mpi_shift_l(&result, before - 1) == 0); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 389 | } | 
|  | 390 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 391 | TEST_EQUAL(0, mbedtls_mpi_grow(&result, nlimbs)); | 
|  | 392 | TEST_EQUAL(0, mbedtls_mpi_read_binary(&upper_bound, | 
|  | 393 | bound_bytes->x, bound_bytes->len)); | 
|  | 394 | TEST_EQUAL(0, mbedtls_mpi_random(&result, min, &upper_bound, | 
|  | 395 | mbedtls_test_rnd_std_rand, NULL)); | 
|  | 396 | TEST_ASSERT(sign_is_valid(&result)); | 
|  | 397 | TEST_ASSERT(mbedtls_mpi_cmp_mpi(&result, &upper_bound) < 0); | 
|  | 398 | TEST_ASSERT(mbedtls_mpi_cmp_int(&result, min) >= 0); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 399 |  | 
|  | 400 | exit: | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 401 | mbedtls_mpi_free(&upper_bound); | 
|  | 402 | mbedtls_mpi_free(&result); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 403 | } | 
|  | 404 | /* END_CASE */ | 
|  | 405 |  | 
| Janos Follath | f2334b7 | 2023-08-17 12:24:46 +0000 | [diff] [blame] | 406 | /* BEGIN_CASE depends_on:MBEDTLS_ECP_WITH_MPI_UINT */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 407 | void mpi_mod_random_validation(int min, char *bound_hex, | 
|  | 408 | int result_limbs_delta, | 
|  | 409 | int expected_ret) | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 410 | { | 
|  | 411 | mbedtls_mpi_uint *result_digits = NULL; | 
|  | 412 | mbedtls_mpi_mod_modulus N; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 413 | mbedtls_mpi_mod_modulus_init(&N); | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 414 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 415 | TEST_EQUAL(mbedtls_test_read_mpi_modulus(&N, bound_hex, | 
|  | 416 | MBEDTLS_MPI_MOD_REP_OPT_RED), | 
|  | 417 | 0); | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 418 | size_t result_limbs = N.limbs + result_limbs_delta; | 
| Tom Cosgrove | 05b2a87 | 2023-07-21 11:31:13 +0100 | [diff] [blame] | 419 | TEST_CALLOC(result_digits, result_limbs); | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 420 | /* Build a reside that might not match the modulus, to test that | 
|  | 421 | * the library function rejects that as expected. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 422 | mbedtls_mpi_mod_residue result = { result_digits, result_limbs }; | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 423 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 424 | TEST_EQUAL(mbedtls_mpi_mod_random(&result, min, &N, | 
|  | 425 | mbedtls_test_rnd_std_rand, NULL), | 
|  | 426 | expected_ret); | 
|  | 427 | if (expected_ret == 0) { | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 428 | /* Success should only be expected when the result has the same | 
|  | 429 | * size as the modulus, otherwise it's a mistake in the test data. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 430 | TEST_EQUAL(result_limbs, N.limbs); | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 431 | /* Sanity check: check that the result is in range */ | 
| Dave Rodgman | 14bec14 | 2023-05-11 16:19:27 +0100 | [diff] [blame] | 432 | TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs)); | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 433 | /* Check result >= min (changes result) */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 434 | TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result_digits, min, | 
|  | 435 | result_limbs), | 
|  | 436 | 0); | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 437 | } | 
|  | 438 |  | 
|  | 439 | /* When the result has the right number of limbs, also test mod_raw | 
|  | 440 | * (for which this is an unchecked precondition). */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 441 | if (result_limbs_delta == 0) { | 
|  | 442 | TEST_EQUAL(mbedtls_mpi_mod_raw_random(result_digits, min, &N, | 
|  | 443 | mbedtls_test_rnd_std_rand, NULL), | 
|  | 444 | expected_ret); | 
|  | 445 | if (expected_ret == 0) { | 
| Dave Rodgman | 14bec14 | 2023-05-11 16:19:27 +0100 | [diff] [blame] | 446 | TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs)); | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 447 | TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result.p, min, | 
|  | 448 | result_limbs), | 
|  | 449 | 0); | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 450 | } | 
|  | 451 | } | 
|  | 452 |  | 
|  | 453 | exit: | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 454 | mbedtls_test_mpi_mod_modulus_free_with_limbs(&N); | 
|  | 455 | mbedtls_free(result_digits); | 
| Gilles Peskine | d878d1c | 2022-12-08 12:59:51 +0100 | [diff] [blame] | 456 | } | 
|  | 457 | /* END_CASE */ | 
|  | 458 |  | 
|  | 459 | /* BEGIN_CASE */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 460 | void mpi_random_fail(int min, data_t *bound_bytes, int expected_ret) | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 461 | { | 
|  | 462 | mbedtls_mpi upper_bound; | 
|  | 463 | mbedtls_mpi result; | 
|  | 464 | int actual_ret; | 
|  | 465 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 466 | mbedtls_mpi_init(&upper_bound); | 
|  | 467 | mbedtls_mpi_init(&result); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 468 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 469 | TEST_EQUAL(0, mbedtls_mpi_read_binary(&upper_bound, | 
|  | 470 | bound_bytes->x, bound_bytes->len)); | 
|  | 471 | actual_ret = mbedtls_mpi_random(&result, min, &upper_bound, | 
|  | 472 | mbedtls_test_rnd_std_rand, NULL); | 
|  | 473 | TEST_EQUAL(expected_ret, actual_ret); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 474 |  | 
|  | 475 | exit: | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 476 | mbedtls_mpi_free(&upper_bound); | 
|  | 477 | mbedtls_mpi_free(&result); | 
| Gilles Peskine | de09ddd | 2022-12-06 13:20:55 +0100 | [diff] [blame] | 478 | } | 
|  | 479 | /* END_CASE */ |