mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +01:00
Merge branch 'tor-github/pr/909'
Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
commit
e543c4e20c
5
changes/ticket29732
Normal file
5
changes/ticket29732
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor features (testing):
|
||||
- Tor's unit test code now contains a standard set of functions to
|
||||
replace the PRNG with a deterministic or reproducible version for
|
||||
testing. Previously, various tests implemented this in various ways.
|
||||
Implements ticket 29732.
|
@ -92,6 +92,10 @@ void crypto_rand_fast_shutdown(void);
|
||||
#if defined(TOR_UNIT_TESTS)
|
||||
/* Used for white-box testing */
|
||||
size_t crypto_fast_rng_get_bytes_used_per_stream(void);
|
||||
/* For deterministic prng implementations */
|
||||
void crypto_fast_rng_disable_reseed(crypto_fast_rng_t *rng);
|
||||
/* To override the prng for testing. */
|
||||
crypto_fast_rng_t *crypto_replace_thread_fast_rng(crypto_fast_rng_t *rng);
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTO_RAND_PRIVATE
|
||||
|
@ -95,8 +95,13 @@ CTASSERT(KEY_BITS == 128 || KEY_BITS == 192 || KEY_BITS == 256);
|
||||
|
||||
struct crypto_fast_rng_t {
|
||||
/** How many more fills does this buffer have before we should mix
|
||||
* in the output of crypto_rand()? */
|
||||
uint16_t n_till_reseed;
|
||||
* in the output of crypto_strongest_rand()?
|
||||
*
|
||||
* This value may be negative if unit tests are enabled. If so, it
|
||||
* indicates that we should never mix in extra data from
|
||||
* crypto_strongest_rand().
|
||||
*/
|
||||
int16_t n_till_reseed;
|
||||
/** How many bytes are remaining in cbuf.bytes? */
|
||||
uint16_t bytes_left;
|
||||
#ifdef CHECK_PID
|
||||
@ -181,6 +186,18 @@ crypto_fast_rng_new_from_seed(const uint8_t *seed)
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
/**
|
||||
* Unit tests only: prevent a crypto_fast_rng_t from ever mixing in more
|
||||
* entropy.
|
||||
*/
|
||||
void
|
||||
crypto_fast_rng_disable_reseed(crypto_fast_rng_t *rng)
|
||||
{
|
||||
rng->n_till_reseed = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper: create a crypto_cipher_t object from SEED_LEN bytes of
|
||||
* input. The first KEY_LEN bytes are used as the stream cipher's key,
|
||||
@ -192,6 +209,26 @@ cipher_from_seed(const uint8_t *seed)
|
||||
return crypto_cipher_new_with_iv_and_bits(seed, seed+KEY_LEN, KEY_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: mix additional entropy into <b>rng</b> by using our XOF to mix the
|
||||
* old value for the seed with some additional bytes from
|
||||
* crypto_strongest_rand().
|
||||
**/
|
||||
static void
|
||||
crypto_fast_rng_add_entopy(crypto_fast_rng_t *rng)
|
||||
{
|
||||
crypto_xof_t *xof = crypto_xof_new();
|
||||
crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN);
|
||||
{
|
||||
uint8_t seedbuf[SEED_LEN];
|
||||
crypto_strongest_rand(seedbuf, SEED_LEN);
|
||||
crypto_xof_add_bytes(xof, seedbuf, SEED_LEN);
|
||||
memwipe(seedbuf, 0, SEED_LEN);
|
||||
}
|
||||
crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN);
|
||||
crypto_xof_free(xof);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: refill the seed bytes and output buffer of <b>rng</b>, using
|
||||
* the input seed bytes as input (key and IV) for the stream cipher.
|
||||
@ -202,22 +239,19 @@ cipher_from_seed(const uint8_t *seed)
|
||||
static void
|
||||
crypto_fast_rng_refill(crypto_fast_rng_t *rng)
|
||||
{
|
||||
if (rng->n_till_reseed-- == 0) {
|
||||
/* It's time to reseed the RNG. We'll do this by using our XOF to mix the
|
||||
* old value for the seed with some additional bytes from
|
||||
* crypto_strongest_rand(). */
|
||||
crypto_xof_t *xof = crypto_xof_new();
|
||||
crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN);
|
||||
{
|
||||
uint8_t seedbuf[SEED_LEN];
|
||||
crypto_strongest_rand(seedbuf, SEED_LEN);
|
||||
crypto_xof_add_bytes(xof, seedbuf, SEED_LEN);
|
||||
memwipe(seedbuf, 0, SEED_LEN);
|
||||
}
|
||||
crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN);
|
||||
crypto_xof_free(xof);
|
||||
|
||||
rng->n_till_reseed--;
|
||||
if (rng->n_till_reseed == 0) {
|
||||
/* It's time to reseed the RNG. */
|
||||
crypto_fast_rng_add_entopy(rng);
|
||||
rng->n_till_reseed = RESEED_AFTER;
|
||||
} else if (rng->n_till_reseed < 0) {
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
/* Reseeding is disabled for testing; never do it on this prng. */
|
||||
rng->n_till_reseed = -1;
|
||||
#else
|
||||
/* If testing is disabled, this shouldn't be able to become negative. */
|
||||
tor_assert_unreached();
|
||||
#endif
|
||||
}
|
||||
/* Now fill rng->buf with output from our stream cipher, initialized from
|
||||
* that seed value. */
|
||||
@ -363,6 +397,20 @@ destroy_thread_fast_rng(void)
|
||||
tor_threadlocal_set(&thread_rng, NULL);
|
||||
}
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
/**
|
||||
* Replace the current thread's rng with <b>rng</b>. For use by the
|
||||
* unit tests only. Returns the previous thread rng.
|
||||
**/
|
||||
crypto_fast_rng_t *
|
||||
crypto_replace_thread_fast_rng(crypto_fast_rng_t *rng)
|
||||
{
|
||||
crypto_fast_rng_t *old_rng = tor_threadlocal_get(&thread_rng);
|
||||
tor_threadlocal_set(&thread_rng, rng);
|
||||
return old_rng;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize the global thread-local key that will be used to keep track
|
||||
* of per-thread fast RNG instances. Called from the crypto subsystem's
|
||||
|
@ -89,6 +89,7 @@ src_test_test_SOURCES += \
|
||||
src/test/log_test_helpers.c \
|
||||
src/test/hs_test_helpers.c \
|
||||
src/test/rend_test_helpers.c \
|
||||
src/test/rng_test_helpers.c \
|
||||
src/test/test.c \
|
||||
src/test/test_accounting.c \
|
||||
src/test/test_addr.c \
|
||||
@ -211,6 +212,7 @@ endif
|
||||
src_test_test_slow_SOURCES =
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_test_slow_SOURCES += \
|
||||
src/test/rng_test_helpers.c \
|
||||
src/test/test_slow.c \
|
||||
src/test/test_crypto_slow.c \
|
||||
src/test/test_process_slow.c \
|
||||
@ -319,6 +321,7 @@ noinst_HEADERS+= \
|
||||
src/test/hs_test_helpers.h \
|
||||
src/test/log_test_helpers.h \
|
||||
src/test/rend_test_helpers.h \
|
||||
src/test/rng_test_helpers.h \
|
||||
src/test/test.h \
|
||||
src/test/ptr_helpers.h \
|
||||
src/test/test_helpers.h \
|
||||
|
226
src/test/rng_test_helpers.c
Normal file
226
src/test/rng_test_helpers.c
Normal file
@ -0,0 +1,226 @@
|
||||
/* Copyright (c) 2018-2019, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file rng_test_helpers.c
|
||||
* \brief Helpers for overriding PRNGs during unit tests.
|
||||
*
|
||||
* We define two PRNG overrides: a "reproducible PRNG" where the seed is
|
||||
* chosen randomly but the stream can be replayed later on in case a bug is
|
||||
* found, and a "deterministic PRNG" where the seed is fixed in the unit
|
||||
* tests.
|
||||
*
|
||||
* Obviously, this code is testing-only.
|
||||
*/
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "core/or/or.h"
|
||||
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
|
||||
#include "test/rng_test_helpers.h"
|
||||
|
||||
#ifndef TOR_UNIT_TESTS
|
||||
#error "No. Never link this code into Tor proper."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* True iff the RNG is currently replaced. Prevents double-replacement.
|
||||
**/
|
||||
static bool rng_is_replaced = false;
|
||||
|
||||
/**
|
||||
* Mutex to protect deterministic prng.
|
||||
*
|
||||
* Note that if you actually _use_ the prng from two threads at the same time,
|
||||
* the results will probably be nondeterministic anyway.
|
||||
*/
|
||||
static tor_mutex_t *rng_mutex = NULL;
|
||||
|
||||
/**
|
||||
* Cached old value for the thread prng.
|
||||
**/
|
||||
static crypto_fast_rng_t *stored_fast_rng = NULL;
|
||||
|
||||
/** replacement for crypto_strongest_rand that delegates to crypto_rand. */
|
||||
static void
|
||||
mock_crypto_strongest_rand(uint8_t *out, size_t len)
|
||||
{
|
||||
crypto_rand((char *)out, len);
|
||||
}
|
||||
|
||||
/* This is the seed of the deterministic randomness. */
|
||||
static uint8_t rng_seed[16];
|
||||
static crypto_xof_t *rng_xof = NULL;
|
||||
|
||||
/**
|
||||
* Print the seed for our PRNG to stdout. We use this when we're
|
||||
**/
|
||||
void
|
||||
testing_dump_reproducible_rng_seed(void)
|
||||
{
|
||||
printf("\n"
|
||||
"Seed: %s\n",
|
||||
hex_str((const char*)rng_seed, sizeof(rng_seed)));
|
||||
}
|
||||
|
||||
/** Produce deterministic randomness for the stochastic tests using the global
|
||||
* rng_xof output.
|
||||
*
|
||||
* This function produces deterministic data over multiple calls iff it's
|
||||
* called in the same call order with the same 'n' parameter.
|
||||
* If not, outputs will deviate. */
|
||||
static void
|
||||
crypto_rand_deterministic(char *out, size_t n)
|
||||
{
|
||||
tor_assert(rng_xof);
|
||||
tor_mutex_acquire(rng_mutex);
|
||||
crypto_xof_squeeze_bytes(rng_xof, (uint8_t*)out, n);
|
||||
tor_mutex_release(rng_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation helper: override our crypto_rand() PRNG with a given seed of
|
||||
* length <b>seed_len</b>. Overlong seeds are truncated; short ones are
|
||||
* padded.
|
||||
**/
|
||||
static void
|
||||
enable_deterministic_rng_impl(const uint8_t *seed, size_t seed_len)
|
||||
{
|
||||
tor_assert(!rng_is_replaced);
|
||||
tor_assert(crypto_rand == crypto_rand__real);
|
||||
|
||||
memset(rng_seed, 0, sizeof(rng_seed));
|
||||
memcpy(rng_seed, seed, MIN(seed_len, sizeof(rng_seed)));
|
||||
|
||||
rng_mutex = tor_mutex_new();
|
||||
|
||||
crypto_xof_free(rng_xof);
|
||||
rng_xof = crypto_xof_new();
|
||||
crypto_xof_add_bytes(rng_xof, rng_seed, sizeof(rng_seed));
|
||||
MOCK(crypto_rand, crypto_rand_deterministic);
|
||||
MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand);
|
||||
|
||||
uint8_t fast_rng_seed[CRYPTO_FAST_RNG_SEED_LEN];
|
||||
memset(fast_rng_seed, 0xff, sizeof(fast_rng_seed));
|
||||
memcpy(fast_rng_seed, rng_seed, MIN(sizeof(rng_seed),
|
||||
sizeof(fast_rng_seed)));
|
||||
crypto_fast_rng_t *fast_rng = crypto_fast_rng_new_from_seed(fast_rng_seed);
|
||||
crypto_fast_rng_disable_reseed(fast_rng);
|
||||
stored_fast_rng = crypto_replace_thread_fast_rng(fast_rng);
|
||||
|
||||
rng_is_replaced = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace our get_thread_fast_rng(), crypto_rand() and
|
||||
* crypto_strongest_rand() prngs with a variant that generates all of its
|
||||
* output deterministically from a randomly chosen seed. In the event of an
|
||||
* error, you can log the seed later on with
|
||||
* testing_dump_reproducible_rng_seed.
|
||||
**/
|
||||
void
|
||||
testing_enable_reproducible_rng(void)
|
||||
{
|
||||
uint8_t seed[16];
|
||||
crypto_rand((char*)seed, sizeof(seed));
|
||||
enable_deterministic_rng_impl(seed, sizeof(seed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace our get_thread_fast_rng(), crypto_rand() and
|
||||
* crypto_strongest_rand() prngs with a variant that generates all of its
|
||||
* output deterministically from a fixed seed. This variant is mainly useful
|
||||
* for cases when we don't want coverage to change between runs.
|
||||
*
|
||||
* USAGE NOTE: Test correctness SHOULD NOT depend on the specific output of
|
||||
* this "rng". If you need a specific output, use
|
||||
* testing_enable_prefilled_rng() instead.
|
||||
**/
|
||||
void
|
||||
testing_enable_deterministic_rng(void)
|
||||
{
|
||||
static const uint8_t quotation[] =
|
||||
"What will it be? A tree? A weed? "
|
||||
"Each one is started from a seed."; // -- Mary Ann Hoberman
|
||||
enable_deterministic_rng_impl(quotation, sizeof(quotation));
|
||||
}
|
||||
|
||||
static uint8_t *prefilled_rng_buffer = NULL;
|
||||
static size_t prefilled_rng_buflen;
|
||||
static size_t prefilled_rng_idx;
|
||||
|
||||
/**
|
||||
* crypto_rand() replacement that returns canned data.
|
||||
**/
|
||||
static void
|
||||
crypto_rand_prefilled(char *out, size_t n)
|
||||
{
|
||||
tor_mutex_acquire(rng_mutex);
|
||||
while (n) {
|
||||
size_t n_to_copy = MIN(prefilled_rng_buflen - prefilled_rng_idx, n);
|
||||
memcpy(out, prefilled_rng_buffer + prefilled_rng_idx, n_to_copy);
|
||||
out += n_to_copy;
|
||||
n -= n_to_copy;
|
||||
prefilled_rng_idx += n_to_copy;
|
||||
|
||||
if (prefilled_rng_idx == prefilled_rng_buflen) {
|
||||
prefilled_rng_idx = 0;
|
||||
}
|
||||
}
|
||||
tor_mutex_release(rng_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace our crypto_rand() and crypto_strongest_rand() prngs with a variant
|
||||
* that yields output from a buffer. If it reaches the end of the buffer, it
|
||||
* starts over.
|
||||
*
|
||||
* Note: the get_thread_fast_rng() prng is not replaced by this; we'll need
|
||||
* more code to support that.
|
||||
**/
|
||||
void
|
||||
testing_enable_prefilled_rng(const void *buffer, size_t buflen)
|
||||
{
|
||||
tor_assert(buflen > 0);
|
||||
rng_mutex = tor_mutex_new();
|
||||
|
||||
prefilled_rng_buffer = tor_memdup(buffer, buflen);
|
||||
prefilled_rng_buflen = buflen;
|
||||
prefilled_rng_idx = 0;
|
||||
|
||||
MOCK(crypto_rand, crypto_rand_prefilled);
|
||||
MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the position in the prefilled RNG buffer to the start.
|
||||
*/
|
||||
void
|
||||
testing_prefilled_rng_reset(void)
|
||||
{
|
||||
tor_mutex_acquire(rng_mutex);
|
||||
prefilled_rng_idx = 0;
|
||||
tor_mutex_release(rng_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo the overrides for our PRNG. To be used at the end of testing.
|
||||
*
|
||||
* Note that this function should be safe to call even if the rng has not
|
||||
* yet been replaced.
|
||||
**/
|
||||
void
|
||||
testing_disable_rng_override(void)
|
||||
{
|
||||
crypto_xof_free(rng_xof);
|
||||
tor_free(prefilled_rng_buffer);
|
||||
UNMOCK(crypto_rand);
|
||||
UNMOCK(crypto_strongest_rand_);
|
||||
tor_mutex_free(rng_mutex);
|
||||
|
||||
crypto_fast_rng_t *rng = crypto_replace_thread_fast_rng(stored_fast_rng);
|
||||
crypto_fast_rng_free(rng);
|
||||
|
||||
rng_is_replaced = false;
|
||||
}
|
26
src/test/rng_test_helpers.h
Normal file
26
src/test/rng_test_helpers.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* Copyright (c) 2017-2019, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_RNG_TEST_HELPERS_H
|
||||
#define TOR_RNG_TEST_HELPERS_H
|
||||
|
||||
#include "core/or/or.h"
|
||||
|
||||
void testing_enable_deterministic_rng(void);
|
||||
void testing_enable_reproducible_rng(void);
|
||||
void testing_enable_prefilled_rng(const void *buffer, size_t buflen);
|
||||
|
||||
void testing_prefilled_rng_reset(void);
|
||||
|
||||
void testing_disable_rng_override(void);
|
||||
|
||||
#define testing_disable_reproducible_rng() \
|
||||
testing_disable_rng_override()
|
||||
#define testing_disable_deterministic_rng() \
|
||||
testing_disable_rng_override()
|
||||
#define testing_disable_prefilled_rng() \
|
||||
testing_disable_rng_override()
|
||||
|
||||
void testing_dump_reproducible_rng_seed(void);
|
||||
|
||||
#endif /* !defined(TOR_RNG_TEST_HELPERS_H) */
|
@ -12,6 +12,7 @@
|
||||
#include "lib/crypt_ops/crypto_dh.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "app/config/or_state_st.h"
|
||||
#include "test/rng_test_helpers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_FCNTL_H
|
||||
@ -354,18 +355,6 @@ test_onion_queues(void *arg)
|
||||
tor_free(onionskin);
|
||||
}
|
||||
|
||||
static crypto_cipher_t *crypto_rand_aes_cipher = NULL;
|
||||
|
||||
// Mock replacement for crypto_rand: Generates bytes from a provided AES_CTR
|
||||
// cipher in <b>crypto_rand_aes_cipher</b>.
|
||||
static void
|
||||
crypto_rand_deterministic_aes(char *out, size_t n)
|
||||
{
|
||||
tor_assert(crypto_rand_aes_cipher);
|
||||
memset(out, 0, n);
|
||||
crypto_cipher_crypt_inplace(crypto_rand_aes_cipher, out, n);
|
||||
}
|
||||
|
||||
static void
|
||||
test_circuit_timeout(void *arg)
|
||||
{
|
||||
@ -397,8 +386,7 @@ test_circuit_timeout(void *arg)
|
||||
|
||||
// Use a deterministic RNG here, or else we'll get nondeterministic
|
||||
// coverage in some of the circuitstats functions.
|
||||
MOCK(crypto_rand, crypto_rand_deterministic_aes);
|
||||
crypto_rand_aes_cipher = crypto_cipher_new("xyzzyplughplover");
|
||||
testing_enable_deterministic_rng();
|
||||
|
||||
circuitbuild_running_unit_tests();
|
||||
#define timeout0 (build_time_t)(30*1000.0)
|
||||
@ -534,8 +522,8 @@ test_circuit_timeout(void *arg)
|
||||
circuit_build_times_free_timeouts(&final);
|
||||
or_state_free(state);
|
||||
teardown_periodic_events();
|
||||
UNMOCK(crypto_rand);
|
||||
crypto_cipher_free(crypto_rand_aes_cipher);
|
||||
|
||||
testing_disable_deterministic_rng();
|
||||
}
|
||||
|
||||
/** Test encoding and parsing of rendezvous service descriptors. */
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "feature/client/addressmap.h"
|
||||
#include "test/log_test_helpers.h"
|
||||
#include "lib/net/resolve.h"
|
||||
#include "test/rng_test_helpers.h"
|
||||
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
@ -945,27 +946,6 @@ test_virtaddrmap(void *data)
|
||||
;
|
||||
}
|
||||
|
||||
static const char *canned_data = NULL;
|
||||
static size_t canned_data_len = 0;
|
||||
|
||||
/* Mock replacement for crypto_rand() that returns canned data from
|
||||
* canned_data above. */
|
||||
static void
|
||||
crypto_canned(char *ptr, size_t n)
|
||||
{
|
||||
if (canned_data_len) {
|
||||
size_t to_copy = MIN(n, canned_data_len);
|
||||
memcpy(ptr, canned_data, to_copy);
|
||||
canned_data += to_copy;
|
||||
canned_data_len -= to_copy;
|
||||
n -= to_copy;
|
||||
ptr += to_copy;
|
||||
}
|
||||
if (n) {
|
||||
crypto_rand_unmocked(ptr, n);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_virtaddrmap_persist(void *data)
|
||||
{
|
||||
@ -973,6 +953,8 @@ test_virtaddrmap_persist(void *data)
|
||||
const char *a, *b, *c;
|
||||
tor_addr_t addr;
|
||||
char *ones = NULL;
|
||||
const char *canned_data;
|
||||
size_t canned_data_len;
|
||||
|
||||
addressmap_init();
|
||||
|
||||
@ -991,7 +973,7 @@ test_virtaddrmap_persist(void *data)
|
||||
"1234567890" // the second call returns this.
|
||||
"abcdefghij"; // the third call returns this.
|
||||
canned_data_len = 30;
|
||||
MOCK(crypto_rand, crypto_canned);
|
||||
testing_enable_prefilled_rng(canned_data, canned_data_len);
|
||||
|
||||
a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
|
||||
tor_strdup("quuxit.baz"));
|
||||
@ -1001,9 +983,9 @@ test_virtaddrmap_persist(void *data)
|
||||
tt_assert(b);
|
||||
tt_str_op(a, OP_EQ, "gezdgnbvgy3tqojq.virtual");
|
||||
tt_str_op(b, OP_EQ, "mfrggzdfmztwq2lk.virtual");
|
||||
testing_disable_prefilled_rng();
|
||||
|
||||
// Now try something to get us an ipv4 address
|
||||
UNMOCK(crypto_rand);
|
||||
tt_int_op(0,OP_EQ, parse_virtual_addr_network("192.168.0.0/16",
|
||||
AF_INET, 0, NULL));
|
||||
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
|
||||
@ -1020,22 +1002,23 @@ test_virtaddrmap_persist(void *data)
|
||||
|
||||
// Try some canned entropy and verify all the we discard duplicates,
|
||||
// addresses that end with 0, and addresses that end with 255.
|
||||
MOCK(crypto_rand, crypto_canned);
|
||||
canned_data = "\x01\x02\x03\x04" // okay
|
||||
"\x01\x02\x03\x04" // duplicate
|
||||
"\x03\x04\x00\x00" // bad ending 1
|
||||
"\x05\x05\x00\xff" // bad ending 2
|
||||
"\x05\x06\x07\xf0"; // okay
|
||||
canned_data_len = 20;
|
||||
testing_enable_prefilled_rng(canned_data, canned_data_len);
|
||||
|
||||
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
|
||||
tor_strdup("wumble.onion"));
|
||||
b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
|
||||
tor_strdup("wumpus.onion"));
|
||||
tt_str_op(a, OP_EQ, "192.168.3.4");
|
||||
tt_str_op(b, OP_EQ, "192.168.7.240");
|
||||
testing_disable_prefilled_rng();
|
||||
|
||||
// Now try IPv6!
|
||||
UNMOCK(crypto_rand);
|
||||
tt_int_op(0,OP_EQ, parse_virtual_addr_network("1010:F000::/20",
|
||||
AF_INET6, 0, NULL));
|
||||
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
|
||||
@ -1051,7 +1034,7 @@ test_virtaddrmap_persist(void *data)
|
||||
tt_assert(!strcmpstart(b, "[1010:f"));
|
||||
|
||||
// Try IPv6 with canned entropy, to make sure we detect duplicates.
|
||||
MOCK(crypto_rand, crypto_canned);
|
||||
|
||||
canned_data = "acanthopterygian" // okay
|
||||
"cinematographist" // okay
|
||||
"acanthopterygian" // duplicate
|
||||
@ -1060,6 +1043,8 @@ test_virtaddrmap_persist(void *data)
|
||||
"cinematographist" // duplicate
|
||||
"coadministration"; // okay
|
||||
canned_data_len = 16 * 7;
|
||||
testing_enable_prefilled_rng(canned_data, canned_data_len);
|
||||
|
||||
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
|
||||
tor_strdup("wuffle.baz"));
|
||||
b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
|
||||
@ -1072,9 +1057,11 @@ test_virtaddrmap_persist(void *data)
|
||||
|
||||
// Try address exhaustion: make sure we can actually fail if we
|
||||
// get too many already-existing addresses.
|
||||
testing_disable_prefilled_rng();
|
||||
canned_data_len = 128*1024;
|
||||
canned_data = ones = tor_malloc(canned_data_len);
|
||||
memset(ones, 1, canned_data_len);
|
||||
testing_enable_prefilled_rng(canned_data, canned_data_len);
|
||||
// There is some chance this one will fail if a previous random
|
||||
// allocation gave out the address already.
|
||||
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
|
||||
@ -1091,7 +1078,7 @@ test_virtaddrmap_persist(void *data)
|
||||
expect_single_log_msg_containing("Ran out of virtual addresses!");
|
||||
|
||||
done:
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_prefilled_rng();
|
||||
tor_free(ones);
|
||||
addressmap_free_all();
|
||||
teardown_capture_of_logs();
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "test/test.h"
|
||||
#include "test/test_helpers.h"
|
||||
#include "test/rng_test_helpers.h"
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
@ -302,16 +303,6 @@ test_ext_or_cookie_auth(void *arg)
|
||||
tor_free(client_hash2);
|
||||
}
|
||||
|
||||
static void
|
||||
crypto_rand_return_tse_str(char *to, size_t n)
|
||||
{
|
||||
if (n != 32) {
|
||||
TT_FAIL(("Asked for %d bytes, not 32", (int)n));
|
||||
return;
|
||||
}
|
||||
memcpy(to, "te road There is always another ", 32);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ext_or_cookie_auth_testvec(void *arg)
|
||||
{
|
||||
@ -326,7 +317,7 @@ test_ext_or_cookie_auth_testvec(void *arg)
|
||||
memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
|
||||
ext_or_auth_cookie_is_set = 1;
|
||||
|
||||
MOCK(crypto_rand, crypto_rand_return_tse_str);
|
||||
testing_enable_prefilled_rng("te road There is always another ", 32);
|
||||
|
||||
tt_int_op(0, OP_EQ,
|
||||
handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
|
||||
@ -351,7 +342,7 @@ test_ext_or_cookie_auth_testvec(void *arg)
|
||||
"33b3cd77ff79bd80c2074bbf438119a2");
|
||||
|
||||
done:
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_prefilled_rng();
|
||||
tor_free(reply);
|
||||
tor_free(client_hash);
|
||||
tor_free(mem_op_hex_tmp);
|
||||
@ -414,9 +405,9 @@ do_ext_or_handshake(or_connection_t *conn)
|
||||
CONTAINS("\x01\x00", 2);
|
||||
WRITE("\x01", 1);
|
||||
WRITE("But when I look ahead up the whi", 32);
|
||||
MOCK(crypto_rand, crypto_rand_return_tse_str);
|
||||
testing_enable_prefilled_rng("te road There is always another ", 32);
|
||||
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_prefilled_rng();
|
||||
tt_int_op(TO_CONN(conn)->state, OP_EQ,
|
||||
EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
|
||||
CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
|
||||
@ -481,9 +472,9 @@ test_ext_or_handshake(void *arg)
|
||||
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
|
||||
/* send the rest of the nonce. */
|
||||
WRITE("ahead up the whi", 16);
|
||||
MOCK(crypto_rand, crypto_rand_return_tse_str);
|
||||
testing_enable_prefilled_rng("te road There is always another ", 32);
|
||||
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_prefilled_rng();
|
||||
/* We should get the right reply from the server. */
|
||||
CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
|
||||
"\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
|
||||
@ -582,7 +573,7 @@ test_ext_or_handshake(void *arg)
|
||||
|
||||
done:
|
||||
UNMOCK(connection_write_to_buf_impl_);
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_prefilled_rng();
|
||||
if (conn)
|
||||
connection_free_minimal(TO_CONN(conn));
|
||||
#undef CONTAINS
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "test/hs_test_helpers.h"
|
||||
#include "test/test_helpers.h"
|
||||
#include "test/log_test_helpers.h"
|
||||
#include "test/rng_test_helpers.h"
|
||||
|
||||
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
|
||||
DISABLE_GCC_WARNING(overlength-strings)
|
||||
@ -30,13 +31,6 @@ DISABLE_GCC_WARNING(overlength-strings)
|
||||
#include "test_hs_descriptor.inc"
|
||||
ENABLE_GCC_WARNING(overlength-strings)
|
||||
|
||||
/* Mock function to fill all bytes with 1 */
|
||||
static void
|
||||
mock_crypto_strongest_rand(uint8_t *out, size_t out_len)
|
||||
{
|
||||
memset(out, 1, out_len);
|
||||
}
|
||||
|
||||
/* Test certificate encoding put in a descriptor. */
|
||||
static void
|
||||
test_cert_encoding(void *arg)
|
||||
@ -799,7 +793,7 @@ test_build_authorized_client(void *arg)
|
||||
client_pubkey_b16,
|
||||
strlen(client_pubkey_b16));
|
||||
|
||||
MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand);
|
||||
testing_enable_prefilled_rng("\x01", 1);
|
||||
|
||||
hs_desc_build_authorized_client(subcredential,
|
||||
&client_auth_pk, &auth_ephemeral_sk,
|
||||
@ -815,7 +809,7 @@ test_build_authorized_client(void *arg)
|
||||
done:
|
||||
tor_free(desc_client);
|
||||
tor_free(mem_op_hex_tmp);
|
||||
UNMOCK(crypto_strongest_rand_);
|
||||
testing_disable_prefilled_rng();
|
||||
}
|
||||
|
||||
struct testcase_t hs_descriptor[] = {
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "lib/math/prob_distr.h"
|
||||
#include "lib/math/fp.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "test/rng_test_helpers.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
@ -1117,49 +1118,14 @@ test_psi_dist_sample(const struct dist *dist)
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the seed of the deterministic randomness */
|
||||
static uint8_t rng_seed[16];
|
||||
static crypto_xof_t *rng_xof = NULL;
|
||||
|
||||
/** Initialize the seed of the deterministic randomness. */
|
||||
static void
|
||||
init_deterministic_rand(void)
|
||||
{
|
||||
crypto_rand((char*)rng_seed, sizeof(rng_seed));
|
||||
crypto_xof_free(rng_xof);
|
||||
rng_xof = crypto_xof_new();
|
||||
crypto_xof_add_bytes(rng_xof, rng_seed, sizeof(rng_seed));
|
||||
}
|
||||
|
||||
static void
|
||||
teardown_deterministic_rand(void)
|
||||
{
|
||||
crypto_xof_free(rng_xof);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_seed(void)
|
||||
{
|
||||
printf("\n"
|
||||
"NOTE: This is a stochastic test, and we expect it to fail from\n"
|
||||
"time to time, with some low probability. If you see it fail more\n"
|
||||
"than one trial in 100, though, please tell us.\n\n"
|
||||
"Seed: %s\n",
|
||||
hex_str((const char*)rng_seed, sizeof(rng_seed)));
|
||||
}
|
||||
|
||||
/** Produce deterministic randomness for the stochastic tests using the global
|
||||
* deterministic_rand_counter seed
|
||||
*
|
||||
* This function produces deterministic data over multiple calls iff it's
|
||||
* called in the same call order with the same 'n' parameter (which is the
|
||||
* case for the psi test). If not, outputs will deviate. */
|
||||
static void
|
||||
crypto_rand_deterministic(char *out, size_t n)
|
||||
{
|
||||
/* Use a XOF to squeeze bytes out of that silly counter */
|
||||
tor_assert(rng_xof);
|
||||
crypto_xof_squeeze_bytes(rng_xof, (uint8_t*)out, n);
|
||||
"than one trial in 100, though, please tell us.\n\n");
|
||||
testing_dump_reproducible_rng_seed();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1199,8 +1165,7 @@ test_stochastic_uniform(void *arg)
|
||||
};
|
||||
bool ok = true, tests_failed = true;
|
||||
|
||||
init_deterministic_rand();
|
||||
MOCK(crypto_rand, crypto_rand_deterministic);
|
||||
testing_enable_reproducible_rng();
|
||||
|
||||
ok &= test_psi_dist_sample(&uniform01.base);
|
||||
ok &= test_psi_dist_sample(&uniform_pos.base);
|
||||
@ -1217,8 +1182,7 @@ test_stochastic_uniform(void *arg)
|
||||
if (tests_failed) {
|
||||
dump_seed();
|
||||
}
|
||||
teardown_deterministic_rand();
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_reproducible_rng();
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1288,8 +1252,7 @@ test_stochastic_genpareto(void *arg)
|
||||
bool tests_failed = true;
|
||||
(void) arg;
|
||||
|
||||
init_deterministic_rand();
|
||||
MOCK(crypto_rand, crypto_rand_deterministic);
|
||||
testing_enable_reproducible_rng();
|
||||
|
||||
ok = test_stochastic_genpareto_impl(0, 1, -0.25);
|
||||
tt_assert(ok);
|
||||
@ -1312,8 +1275,7 @@ test_stochastic_genpareto(void *arg)
|
||||
if (tests_failed) {
|
||||
dump_seed();
|
||||
}
|
||||
teardown_deterministic_rand();
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_reproducible_rng();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1324,8 +1286,7 @@ test_stochastic_geometric(void *arg)
|
||||
|
||||
(void) arg;
|
||||
|
||||
init_deterministic_rand();
|
||||
MOCK(crypto_rand, crypto_rand_deterministic);
|
||||
testing_enable_reproducible_rng();
|
||||
|
||||
ok = test_stochastic_geometric_impl(0.1);
|
||||
tt_assert(ok);
|
||||
@ -1342,8 +1303,7 @@ test_stochastic_geometric(void *arg)
|
||||
if (tests_failed) {
|
||||
dump_seed();
|
||||
}
|
||||
teardown_deterministic_rand();
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_reproducible_rng();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1353,8 +1313,7 @@ test_stochastic_logistic(void *arg)
|
||||
bool tests_failed = true;
|
||||
(void) arg;
|
||||
|
||||
init_deterministic_rand();
|
||||
MOCK(crypto_rand, crypto_rand_deterministic);
|
||||
testing_enable_reproducible_rng();
|
||||
|
||||
ok = test_stochastic_logistic_impl(0, 1);
|
||||
tt_assert(ok);
|
||||
@ -1371,8 +1330,7 @@ test_stochastic_logistic(void *arg)
|
||||
if (tests_failed) {
|
||||
dump_seed();
|
||||
}
|
||||
teardown_deterministic_rand();
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_reproducible_rng();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1382,8 +1340,7 @@ test_stochastic_log_logistic(void *arg)
|
||||
bool tests_failed = true;
|
||||
(void) arg;
|
||||
|
||||
init_deterministic_rand();
|
||||
MOCK(crypto_rand, crypto_rand_deterministic);
|
||||
testing_enable_reproducible_rng();
|
||||
|
||||
ok = test_stochastic_log_logistic_impl(1, 1);
|
||||
tt_assert(ok);
|
||||
@ -1400,8 +1357,7 @@ test_stochastic_log_logistic(void *arg)
|
||||
if (tests_failed) {
|
||||
dump_seed();
|
||||
}
|
||||
teardown_deterministic_rand();
|
||||
UNMOCK(crypto_rand);
|
||||
testing_disable_reproducible_rng();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1411,8 +1367,7 @@ test_stochastic_weibull(void *arg)
|
||||
bool tests_failed = true;
|
||||
(void) arg;
|
||||
|
||||
init_deterministic_rand();
|
||||
MOCK(crypto_rand, crypto_rand_deterministic);
|
||||
testing_enable_reproducible_rng();
|
||||
|
||||
ok = test_stochastic_weibull_impl(1, 0.5);
|
||||
tt_assert(ok);
|
||||
@ -1431,7 +1386,7 @@ test_stochastic_weibull(void *arg)
|
||||
if (tests_failed) {
|
||||
dump_seed();
|
||||
}
|
||||
teardown_deterministic_rand();
|
||||
testing_disable_reproducible_rng();
|
||||
UNMOCK(crypto_rand);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user