mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +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) \
|
#define CRYPTO_LEGACY(name) \
|
||||||
{ #name, test_crypto_ ## name , 0, NULL, NULL }
|
{ #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,
|
{ "ed25519_fuzz_donna", test_crypto_ed25519_fuzz_donna, TT_FORK, NULL,
|
||||||
NULL },
|
NULL },
|
||||||
{ "siphash", test_crypto_siphash, 0, NULL, NULL },
|
{ "siphash", test_crypto_siphash, 0, NULL, NULL },
|
||||||
|
{ "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL },
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user