mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
Add unit tests that check for common RNG failure modes
Check that crypto_rand doesn't return all zeroes, identical values, or incrementing values (OpenSSL's rand_predictable feature).
This commit is contained in:
parent
943369f927
commit
155fa2dbdb
5
changes/rand-failure-modes
Normal file
5
changes/rand-failure-modes
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor features (unit tests, random number generation):
|
||||
- Add unit tests that check for common RNG failure modes, such as
|
||||
returning all zeroes, identical values, or incrementing values
|
||||
(OpenSSL's rand_predictable feature).
|
||||
Patch by "teor".
|
@ -1803,6 +1803,110 @@ test_crypto_siphash(void *arg)
|
||||
;
|
||||
}
|
||||
|
||||
/* We want the likelihood that the random buffer exhibits any regular pattern
|
||||
* to be far less than the memory bit error rate in the int return value.
|
||||
* Using 2048 bits provides a failure rate of 1/(3 * 10^616), and we call
|
||||
* 3 functions, leading to an overall error rate of 1/10^616.
|
||||
* This is comparable with the 1/10^603 failure rate of test_crypto_rng_range.
|
||||
*/
|
||||
#define FAILURE_MODE_BUFFER_SIZE (2048/8)
|
||||
|
||||
/** Check crypto_rand for a failure mode where it does nothing to the buffer,
|
||||
* or it sets the buffer to all zeroes. Return 0 when the check passes,
|
||||
* or -1 when it fails. */
|
||||
static int
|
||||
crypto_rand_check_failure_mode_zero(void)
|
||||
{
|
||||
char buf[FAILURE_MODE_BUFFER_SIZE];
|
||||
|
||||
memset(buf, 0, FAILURE_MODE_BUFFER_SIZE);
|
||||
crypto_rand(buf, FAILURE_MODE_BUFFER_SIZE);
|
||||
|
||||
for (size_t i = 0; i < FAILURE_MODE_BUFFER_SIZE; i++) {
|
||||
if (buf[i] != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Check crypto_rand for a failure mode where every int64_t in the buffer is
|
||||
* the same. Return 0 when the check passes, or -1 when it fails. */
|
||||
static int
|
||||
crypto_rand_check_failure_mode_identical(void)
|
||||
{
|
||||
/* just in case the buffer size isn't a multiple of sizeof(int64_t) */
|
||||
#define FAILURE_MODE_BUFFER_SIZE_I64 \
|
||||
(FAILURE_MODE_BUFFER_SIZE/SIZEOF_INT64_T)
|
||||
#define FAILURE_MODE_BUFFER_SIZE_I64_BYTES \
|
||||
(FAILURE_MODE_BUFFER_SIZE_I64*SIZEOF_INT64_T)
|
||||
|
||||
#if FAILURE_MODE_BUFFER_SIZE_I64 < 2
|
||||
#error FAILURE_MODE_BUFFER_SIZE needs to be at least 2*SIZEOF_INT64_T
|
||||
#endif
|
||||
|
||||
int64_t buf[FAILURE_MODE_BUFFER_SIZE_I64];
|
||||
|
||||
memset(buf, 0, FAILURE_MODE_BUFFER_SIZE_I64_BYTES);
|
||||
crypto_rand((char *)buf, FAILURE_MODE_BUFFER_SIZE_I64_BYTES);
|
||||
|
||||
for (size_t i = 1; i < FAILURE_MODE_BUFFER_SIZE_I64; i++) {
|
||||
if (buf[i] != buf[i-1]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Check crypto_rand for a failure mode where it increments the "random"
|
||||
* value by 1 for every byte in the buffer. (This is OpenSSL's PREDICT mode.)
|
||||
* Return 0 when the check passes, or -1 when it fails. */
|
||||
static int
|
||||
crypto_rand_check_failure_mode_predict(void)
|
||||
{
|
||||
unsigned char buf[FAILURE_MODE_BUFFER_SIZE];
|
||||
|
||||
memset(buf, 0, FAILURE_MODE_BUFFER_SIZE);
|
||||
crypto_rand((char *)buf, FAILURE_MODE_BUFFER_SIZE);
|
||||
|
||||
for (size_t i = 1; i < FAILURE_MODE_BUFFER_SIZE; i++) {
|
||||
/* check if the last byte was incremented by 1, including integer
|
||||
* wrapping */
|
||||
if (buf[i] - buf[i-1] != 1 && buf[i-1] - buf[i] != 255) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#undef FAILURE_MODE_BUFFER_SIZE
|
||||
|
||||
static void
|
||||
test_crypto_failure_modes(void *arg)
|
||||
{
|
||||
int rv = 0;
|
||||
(void)arg;
|
||||
|
||||
rv = crypto_early_init();
|
||||
tt_assert(rv == 0);
|
||||
|
||||
/* Check random works */
|
||||
rv = crypto_rand_check_failure_mode_zero();
|
||||
tt_assert(rv == 0);
|
||||
|
||||
rv = crypto_rand_check_failure_mode_identical();
|
||||
tt_assert(rv == 0);
|
||||
|
||||
rv = crypto_rand_check_failure_mode_predict();
|
||||
tt_assert(rv == 0);
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
#define CRYPTO_LEGACY(name) \
|
||||
{ #name, test_crypto_ ## name , 0, NULL, NULL }
|
||||
|
||||
@ -1841,6 +1945,7 @@ struct testcase_t crypto_tests[] = {
|
||||
{ "ed25519_fuzz_donna", test_crypto_ed25519_fuzz_donna, TT_FORK, NULL,
|
||||
NULL },
|
||||
{ "siphash", test_crypto_siphash, 0, NULL, NULL },
|
||||
{ "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL },
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user