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. 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. 38 */ 39 40#include "mbedtls/bignum.h" 41#include "mbedtls/entropy.h" 42#include "bignum_core.h" 43#include "bignum_mod_raw.h" 44#include "constant_time_internal.h" 45 46/* This test suite only manipulates non-negative bignums. */ 47static int sign_is_valid(const mbedtls_mpi *X) 48{ 49 return X->s == 1; 50} 51 52/* A common initializer for test functions that should generate the same 53 * sequences for reproducibility and good coverage. */ 54const mbedtls_test_rnd_pseudo_info rnd_pseudo_seed = { 55 /* 16-word key */ 56 { 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 57 'a', ' ', 's', 'e', 'e', 'd', '!', 0 }, 58 /* 2-word initial state, should be zero */ 59 0, 0 60}; 61 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 */ 73static int is_significantly_above_a_power_of_2(data_t *bytes) 74{ 75 const uint8_t *p = bytes->x; 76 size_t len = bytes->len; 77 unsigned x; 78 79 /* Skip leading null bytes */ 80 while (len > 0 && p[0] == 0) { 81 ++p; 82 --len; 83 } 84 /* 0 is not significantly above a power of 2 */ 85 if (len == 0) { 86 return 0; 87 } 88 /* Extract the (up to) 2 most significant bytes */ 89 if (len == 1) { 90 x = p[0]; 91 } else { 92 x = (p[0] << 8) | p[1]; 93 } 94 95 /* Shift the most significant bit of x to position 8 and mask it out */ 96 while ((x & 0xfe00) != 0) { 97 x >>= 1; 98 } 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. */ 105 return x >= 0x10; 106} 107 108/* END_HEADER */ 109 110/* BEGIN_DEPENDENCIES 111 * depends_on:MBEDTLS_BIGNUM_C 112 * END_DEPENDENCIES 113 */ 114 115/* BEGIN_CASE */ 116void mpi_core_random_basic(int min, char *bound_bytes, int expected_ret) 117{ 118 /* Same RNG as in mpi_random_values */ 119 mbedtls_test_rnd_pseudo_info rnd = rnd_pseudo_seed; 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 125 TEST_EQUAL(0, mbedtls_test_read_mpi_core(&upper_bound, &limbs, 126 bound_bytes)); 127 TEST_CALLOC(lower_bound, limbs); 128 lower_bound[0] = min; 129 TEST_CALLOC(result, limbs); 130 131 TEST_EQUAL(expected_ret, 132 mbedtls_mpi_core_random(result, min, upper_bound, limbs, 133 mbedtls_test_rnd_pseudo_rand, &rnd)); 134 135 if (expected_ret == 0) { 136 TEST_EQUAL(0, mbedtls_mpi_core_lt_ct(result, lower_bound, limbs)); 137 TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result, upper_bound, limbs)); 138 } 139 140exit: 141 mbedtls_free(lower_bound); 142 mbedtls_free(upper_bound); 143 mbedtls_free(result); 144} 145/* END_CASE */ 146 147/* BEGIN_CASE */ 148void mpi_legacy_random_values(int min, char *max_hex) 149{ 150 /* Same RNG as in mpi_core_random_basic */ 151 mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed; 152 mbedtls_test_rnd_pseudo_info rnd_legacy; 153 memcpy(&rnd_legacy, &rnd_core, sizeof(rnd_core)); 154 mbedtls_mpi max_legacy; 155 mbedtls_mpi_init(&max_legacy); 156 mbedtls_mpi_uint *R_core = NULL; 157 mbedtls_mpi R_legacy; 158 mbedtls_mpi_init(&R_legacy); 159 160 TEST_EQUAL(0, mbedtls_test_read_mpi(&max_legacy, max_hex)); 161 size_t limbs = max_legacy.n; 162 TEST_CALLOC(R_core, limbs); 163 164 /* Call the legacy function and the core function with the same random 165 * stream. */ 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); 172 173 /* They must return the same status, and, on success, output the 174 * same number, with the same limb count. */ 175 TEST_EQUAL(core_ret, legacy_ret); 176 if (core_ret == 0) { 177 TEST_MEMORY_COMPARE(R_core, limbs * ciL, 178 R_legacy.p, R_legacy.n * ciL); 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. */ 185 TEST_MEMORY_COMPARE(&rnd_core, sizeof(rnd_core), 186 &rnd_legacy, sizeof(rnd_legacy)); 187 188exit: 189 mbedtls_mpi_free(&max_legacy); 190 mbedtls_free(R_core); 191 mbedtls_mpi_free(&R_legacy); 192} 193/* END_CASE */ 194 195/* BEGIN_CASE depends_on:MBEDTLS_ECP_WITH_MPI_UINT */ 196void mpi_mod_random_values(int min, char *max_hex, int rep) 197{ 198 /* Same RNG as in mpi_core_random_basic */ 199 mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed; 200 mbedtls_test_rnd_pseudo_info rnd_mod_raw; 201 memcpy(&rnd_mod_raw, &rnd_core, sizeof(rnd_core)); 202 mbedtls_test_rnd_pseudo_info rnd_mod; 203 memcpy(&rnd_mod, &rnd_core, sizeof(rnd_core)); 204 mbedtls_mpi_uint *R_core = NULL; 205 mbedtls_mpi_uint *R_mod_raw = NULL; 206 mbedtls_mpi_uint *R_mod_digits = NULL; 207 mbedtls_mpi_mod_residue R_mod; 208 mbedtls_mpi_mod_modulus N; 209 mbedtls_mpi_mod_modulus_init(&N); 210 211 TEST_EQUAL(mbedtls_test_read_mpi_modulus(&N, max_hex, rep), 0); 212 TEST_CALLOC(R_core, N.limbs); 213 TEST_CALLOC(R_mod_raw, N.limbs); 214 TEST_CALLOC(R_mod_digits, N.limbs); 215 TEST_EQUAL(mbedtls_mpi_mod_residue_setup(&R_mod, &N, 216 R_mod_digits, N.limbs), 217 0); 218 219 /* Call the core and mod random() functions with the same random stream. */ 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); 232 233 /* They must return the same status, and, on success, output the 234 * same number, with the same limb count. */ 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); 240 TEST_MEMORY_COMPARE(R_core, N.limbs * ciL, 241 R_mod_raw, N.limbs * ciL); 242 TEST_EQUAL(mbedtls_mpi_mod_raw_modulus_to_canonical_rep(R_mod_digits, &N), 243 0); 244 TEST_MEMORY_COMPARE(R_core, N.limbs * ciL, 245 R_mod_digits, N.limbs * ciL); 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. */ 252 TEST_MEMORY_COMPARE(&rnd_core, sizeof(rnd_core), 253 &rnd_mod_raw, sizeof(rnd_mod_raw)); 254 TEST_MEMORY_COMPARE(&rnd_core, sizeof(rnd_core), 255 &rnd_mod, sizeof(rnd_mod)); 256 257exit: 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); 262} 263/* END_CASE */ 264 265/* BEGIN_CASE */ 266void mpi_random_many(int min, char *bound_hex, int iterations) 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 274 data_t bound_bytes = { NULL, 0 }; 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 288 TEST_EQUAL(0, mbedtls_test_read_mpi_core(&upper_bound, &limbs, 289 bound_hex)); 290 TEST_CALLOC(result, limbs); 291 292 n_bits = mbedtls_mpi_core_bitlen(upper_bound, limbs); 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. */ 298 if (n_bits <= 5) { 299 full_stats = 1; 300 stats_len = (uint8_t) upper_bound[0]; 301 } else { 302 full_stats = 0; 303 stats_len = n_bits; 304 } 305 TEST_CALLOC(stats, stats_len); 306 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)); 312 313 /* Temporarily use a legacy MPI for analysis, because the 314 * necessary auxiliary functions don't exist yet in core. */ 315 mbedtls_mpi B = { .s = 1, .n = limbs, .p = upper_bound }; 316 mbedtls_mpi R = { .s = 1, .n = limbs, .p = result }; 317 318 TEST_ASSERT(mbedtls_mpi_cmp_mpi(&R, &B) < 0); 319 TEST_ASSERT(mbedtls_mpi_cmp_int(&R, min) >= 0); 320 if (full_stats) { 321 uint8_t value; 322 TEST_EQUAL(0, mbedtls_mpi_write_binary(&R, &value, 1)); 323 TEST_ASSERT(value < stats_len); 324 ++stats[value]; 325 } else { 326 for (b = 0; b < n_bits; b++) { 327 stats[b] += mbedtls_mpi_get_bit(&R, b); 328 } 329 } 330 } 331 332 if (full_stats) { 333 for (b = min; b < stats_len; b++) { 334 mbedtls_test_set_step(1000000 + b); 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 */ 339 TEST_ASSERT(stats[b] > 0); 340 } 341 } else { 342 bound_bytes.len = limbs * sizeof(mbedtls_mpi_uint); 343 TEST_CALLOC(bound_bytes.x, bound_bytes.len); 344 mbedtls_mpi_core_write_be(upper_bound, limbs, 345 bound_bytes.x, bound_bytes.len); 346 int statistically_safe_all_the_way = 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); 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 */ 358 if (statistically_safe_all_the_way || b != n_bits - 1) { 359 TEST_ASSERT(stats[b] > 0); 360 } 361 TEST_ASSERT(stats[b] < (size_t) iterations); 362 } 363 } 364 365exit: 366 mbedtls_free(bound_bytes.x); 367 mbedtls_free(upper_bound); 368 mbedtls_free(result); 369 mbedtls_free(stats); 370} 371/* END_CASE */ 372 373/* BEGIN_CASE */ 374void mpi_random_sizes(int min, data_t *bound_bytes, int nlimbs, int before) 375{ 376 mbedtls_mpi upper_bound; 377 mbedtls_mpi result; 378 379 mbedtls_mpi_init(&upper_bound); 380 mbedtls_mpi_init(&result); 381 382 if (before != 0) { 383 /* Set result to sign(before) * 2^(|before|-1) */ 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); 389 } 390 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); 399 400exit: 401 mbedtls_mpi_free(&upper_bound); 402 mbedtls_mpi_free(&result); 403} 404/* END_CASE */ 405 406/* BEGIN_CASE depends_on:MBEDTLS_ECP_WITH_MPI_UINT */ 407void mpi_mod_random_validation(int min, char *bound_hex, 408 int result_limbs_delta, 409 int expected_ret) 410{ 411 mbedtls_mpi_uint *result_digits = NULL; 412 mbedtls_mpi_mod_modulus N; 413 mbedtls_mpi_mod_modulus_init(&N); 414 415 TEST_EQUAL(mbedtls_test_read_mpi_modulus(&N, bound_hex, 416 MBEDTLS_MPI_MOD_REP_OPT_RED), 417 0); 418 size_t result_limbs = N.limbs + result_limbs_delta; 419 TEST_CALLOC(result_digits, result_limbs); 420 /* Build a reside that might not match the modulus, to test that 421 * the library function rejects that as expected. */ 422 mbedtls_mpi_mod_residue result = { result_digits, result_limbs }; 423 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) { 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. */ 430 TEST_EQUAL(result_limbs, N.limbs); 431 /* Sanity check: check that the result is in range */ 432 TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs)); 433 /* Check result >= min (changes result) */ 434 TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result_digits, min, 435 result_limbs), 436 0); 437 } 438 439 /* When the result has the right number of limbs, also test mod_raw 440 * (for which this is an unchecked precondition). */ 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) { 446 TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs)); 447 TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result.p, min, 448 result_limbs), 449 0); 450 } 451 } 452 453exit: 454 mbedtls_test_mpi_mod_modulus_free_with_limbs(&N); 455 mbedtls_free(result_digits); 456} 457/* END_CASE */ 458 459/* BEGIN_CASE */ 460void mpi_random_fail(int min, data_t *bound_bytes, int expected_ret) 461{ 462 mbedtls_mpi upper_bound; 463 mbedtls_mpi result; 464 int actual_ret; 465 466 mbedtls_mpi_init(&upper_bound); 467 mbedtls_mpi_init(&result); 468 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); 474 475exit: 476 mbedtls_mpi_free(&upper_bound); 477 mbedtls_mpi_free(&result); 478} 479/* END_CASE */ 480