diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/include.am | 20 | ||||
-rwxr-xr-x | src/test/test_bt.sh | 1 | ||||
-rw-r--r-- | src/test/test_connection.c | 411 | ||||
-rw-r--r-- | src/test/test_crypto.c | 549 | ||||
-rw-r--r-- | src/test/test_crypto_slow.c | 15 | ||||
-rw-r--r-- | src/test/test_dir.c | 253 | ||||
-rw-r--r-- | src/test/test_dir_handle_get.c | 14 | ||||
-rw-r--r-- | src/test/test_microdesc.c | 2 | ||||
-rw-r--r-- | src/test/test_ntor_cl.c | 5 | ||||
-rw-r--r-- | src/test/test_policy.c | 3 | ||||
-rw-r--r-- | src/test/test_routerlist.c | 48 | ||||
-rw-r--r-- | src/test/test_util.c | 17 | ||||
-rw-r--r-- | src/test/testing_common.c | 3 |
13 files changed, 1097 insertions, 244 deletions
diff --git a/src/test/include.am b/src/test/include.am index d1e1cbd7f6..fa660f5302 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -153,6 +153,7 @@ src_test_test_switch_id_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_test_test_switch_id_LDFLAGS = @TOR_LDFLAGS_zlib@ src_test_test_switch_id_LDADD = \ src/common/libor-testing.a \ + src/common/libor-ctime-testing.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @@ -162,6 +163,7 @@ src_test_test_LDADD = src/or/libtor-testing.a \ $(LIBKECCAK_TINY) \ $(LIBDONNA) \ src/common/libor-testing.a \ + src/common/libor-ctime-testing.a \ src/common/libor-event-testing.a \ src/trunnel/libor-trunnel-testing.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @@ -174,13 +176,17 @@ src_test_test_slow_LDADD = $(src_test_test_LDADD) src_test_test_slow_LDFLAGS = $(src_test_test_LDFLAGS) src_test_test_memwipe_CPPFLAGS = $(src_test_test_CPPFLAGS) -src_test_test_memwipe_CFLAGS = $(src_test_test_CFLAGS) +# Don't use bugtrap cflags here: memwipe tests require memory violations. +src_test_test_memwipe_CFLAGS = $(TEST_CFLAGS) src_test_test_memwipe_LDADD = $(src_test_test_LDADD) -src_test_test_memwipe_LDFLAGS = $(src_test_test_LDFLAGS) +# The LDFLAGS need to include the bugtrap cflags, or else we won't link +# successfully with the libraries built with them. +src_test_test_memwipe_LDFLAGS = $(src_test_test_LDFLAGS) @CFLAGS_BUGTRAP@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \ + src/common/libor-ctime.a \ src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ src/common/libor-event.a src/trunnel/libor-trunnel.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @@ -191,6 +197,7 @@ src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ src_test_test_workqueue_LDADD = src/or/libtor-testing.a \ src/common/libor-testing.a \ + src/common/libor-ctime-testing.a \ src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \ src/common/libor-event-testing.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @@ -199,9 +206,10 @@ src_test_test_workqueue_LDADD = src/or/libtor-testing.a \ src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS) src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS) src_test_test_timers_LDADD = \ + src/common/libor-testing.a \ + src/common/libor-ctime-testing.a \ src/common/libor-event-testing.a \ src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-testing.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS) @@ -224,6 +232,7 @@ noinst_PROGRAMS+= src/test/test-ntor-cl src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \ + src/common/libor-ctime.a \ src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @@ -233,6 +242,7 @@ src_test_test_ntor_cl_AM_CPPFLAGS = \ noinst_PROGRAMS += src/test/test-bt-cl src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c src_test_test_bt_cl_LDADD = src/common/libor-testing.a \ + src/common/libor-ctime-testing.a \ @TOR_LIB_MATH@ \ @TOR_LIB_WS32@ @TOR_LIB_GDI@ src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) @@ -244,7 +254,7 @@ EXTRA_DIST += \ src/test/slownacl_curve25519.py \ src/test/zero_length_keys.sh \ src/test/test_keygen.sh \ - src/test/test_zero_length_keys.sh \ - src/test/test_ntor.sh src/test/test_bt.sh \ + src/test/test_zero_length_keys.sh \ + src/test/test_ntor.sh src/test/test_bt.sh \ src/test/test-network.sh \ src/test/test_switch_id.sh diff --git a/src/test/test_bt.sh b/src/test/test_bt.sh index 83fa3ff24b..fe1781659d 100755 --- a/src/test/test_bt.sh +++ b/src/test/test_bt.sh @@ -3,6 +3,7 @@ exitcode=0 +export ASAN_OPTIONS="handle_segv=0:allow_user_segv_handler=1" "${builddir:-.}/src/test/test-bt-cl" backtraces || exit $? "${builddir:-.}/src/test/test-bt-cl" assert 2>&1 | "${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/bt_test.py" || exitcode="$?" "${builddir:-.}/src/test/test-bt-cl" crash 2>&1 | "${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/bt_test.py" || exitcode="$?" diff --git a/src/test/test_connection.c b/src/test/test_connection.c index 6f7aef879c..bf95b0b59f 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -11,6 +11,7 @@ #include "connection.h" #include "main.h" +#include "microdesc.h" #include "networkstatus.h" #include "rendcache.h" #include "directory.h" @@ -54,7 +55,11 @@ static int test_conn_get_rsrc_teardown(const struct testcase_t *tc, #define TEST_CONN_RSRC_STATE_SUCCESSFUL (DIR_CONN_STATE_CLIENT_FINISHED) #define TEST_CONN_RSRC_2 (networkstatus_get_flavor_name(FLAV_NS)) -#define TEST_CONN_DL_STATE (DIR_CONN_STATE_CLIENT_SENDING) +#define TEST_CONN_DL_STATE (DIR_CONN_STATE_CLIENT_READING) + +/* see AP_CONN_STATE_IS_UNATTACHED() */ +#define TEST_CONN_UNATTACHED_STATE (AP_CONN_STATE_CIRCUIT_WAIT) +#define TEST_CONN_ATTACHED_STATE (AP_CONN_STATE_CONNECT_WAIT) #define TEST_CONN_FD_INIT 50 static int mock_connection_connect_sockaddr_called = 0; @@ -109,27 +114,25 @@ test_conn_lookup_addr_helper(const char *address, int family, tor_addr_t *addr) tor_addr_make_null(addr, TEST_CONN_FAMILY); } -static void * -test_conn_get_basic_setup(const struct testcase_t *tc) +static connection_t * +test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose) { connection_t *conn = NULL; tor_addr_t addr; int socket_err = 0; int in_progress = 0; - (void)tc; MOCK(connection_connect_sockaddr, mock_connection_connect_sockaddr); init_connection_lists(); - conn = connection_new(TEST_CONN_TYPE, TEST_CONN_FAMILY); + conn = connection_new(type, TEST_CONN_FAMILY); tt_assert(conn); test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr); tt_assert(!tor_addr_is_null(&addr)); - /* XXXX - connection_connect doesn't set these, should it? */ tor_addr_copy_tight(&conn->addr, &addr); conn->port = TEST_CONN_PORT; mock_connection_connect_sockaddr_called = 0; @@ -140,8 +143,8 @@ test_conn_get_basic_setup(const struct testcase_t *tc) tt_assert(in_progress == 0 || in_progress == 1); /* fake some of the attributes so the connection looks OK */ - conn->state = TEST_CONN_STATE; - conn->purpose = TEST_CONN_BASIC_PURPOSE; + conn->state = state; + conn->purpose = purpose; assert_connection_ok(conn, time(NULL)); UNMOCK(connection_connect_sockaddr); @@ -151,12 +154,17 @@ test_conn_get_basic_setup(const struct testcase_t *tc) /* On failure */ done: UNMOCK(connection_connect_sockaddr); - test_conn_get_basic_teardown(tc, conn); - - /* Returning NULL causes the unit test to fail */ return NULL; } +static void * +test_conn_get_basic_setup(const struct testcase_t *tc) +{ + (void)tc; + return test_conn_get_connection(TEST_CONN_STATE, TEST_CONN_TYPE, + TEST_CONN_BASIC_PURPOSE); +} + static int test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg) { @@ -186,9 +194,8 @@ test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg) connection_close_immediate(conn->linked_conn); connection_mark_for_close(conn->linked_conn); } - conn->linked_conn->linked_conn = NULL; - connection_free(conn->linked_conn); - conn->linked_conn = NULL; + + close_closeable_connections(); } /* We didn't set the events up properly, so we can't use event_del() in @@ -222,7 +229,10 @@ static void * test_conn_get_rend_setup(const struct testcase_t *tc) { dir_connection_t *conn = DOWNCAST(dir_connection_t, - test_conn_get_basic_setup(tc)); + test_conn_get_connection( + TEST_CONN_STATE, + TEST_CONN_TYPE, + TEST_CONN_REND_PURPOSE)); tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); @@ -235,7 +245,6 @@ test_conn_get_rend_setup(const struct testcase_t *tc) TEST_CONN_REND_ADDR, REND_SERVICE_ID_LEN_BASE32+1); conn->rend_data->hsdirs_fp = smartlist_new(); - conn->base_.purpose = TEST_CONN_REND_PURPOSE; assert_connection_ok(&conn->base_, time(NULL)); return conn; @@ -266,42 +275,64 @@ test_conn_get_rend_teardown(const struct testcase_t *tc, void *arg) return rv; } -static void * -test_conn_get_rsrc_setup(const struct testcase_t *tc) +static dir_connection_t * +test_conn_download_status_add_a_connection(const char *resource) { dir_connection_t *conn = DOWNCAST(dir_connection_t, - test_conn_get_basic_setup(tc)); + test_conn_get_connection( + TEST_CONN_STATE, + TEST_CONN_TYPE, + TEST_CONN_RSRC_PURPOSE)); + tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); - /* TODO: use the canonical function to do this - maybe? */ - conn->requested_resource = tor_strdup(TEST_CONN_RSRC); - conn->base_.purpose = TEST_CONN_RSRC_PURPOSE; + /* Replace the existing resource with the one we want */ + if (resource) { + if (conn->requested_resource) { + tor_free(conn->requested_resource); + } + conn->requested_resource = tor_strdup(resource); + assert_connection_ok(&conn->base_, time(NULL)); + } - assert_connection_ok(&conn->base_, time(NULL)); return conn; - /* On failure */ done: - test_conn_get_rend_teardown(tc, conn); - /* Returning NULL causes the unit test to fail */ + test_conn_get_rsrc_teardown(NULL, conn); return NULL; } +static void * +test_conn_get_rsrc_setup(const struct testcase_t *tc) +{ + (void)tc; + return test_conn_download_status_add_a_connection(TEST_CONN_RSRC); +} + static int test_conn_get_rsrc_teardown(const struct testcase_t *tc, void *arg) { - dir_connection_t *conn = DOWNCAST(dir_connection_t, arg); int rv = 0; + connection_t *conn = (connection_t *)arg; tt_assert(conn); - assert_connection_ok(&conn->base_, time(NULL)); + assert_connection_ok(conn, time(NULL)); + + if (conn->type == CONN_TYPE_DIR) { + dir_connection_t *dir_conn = DOWNCAST(dir_connection_t, arg); + + tt_assert(dir_conn); + assert_connection_ok(&dir_conn->base_, time(NULL)); - /* avoid a last-ditch attempt to refetch the consensus */ - conn->base_.state = TEST_CONN_RSRC_STATE_SUCCESSFUL; + /* avoid a last-ditch attempt to refetch the consensus */ + dir_conn->base_.state = TEST_CONN_RSRC_STATE_SUCCESSFUL; + assert_connection_ok(&dir_conn->base_, time(NULL)); + } /* connection_free_() cleans up requested_resource */ - rv = test_conn_get_basic_teardown(tc, arg); + rv = test_conn_get_basic_teardown(tc, conn); + done: return rv; } @@ -336,14 +367,30 @@ test_conn_download_status_teardown(const struct testcase_t *tc, void *arg) return rv; } -static dir_connection_t * -test_conn_download_status_add_a_connection(void) +/* Like connection_ap_make_link(), but does much less */ +static connection_t * +test_conn_get_linked_connection(connection_t *l_conn, uint8_t state) { - dir_connection_t *conn = DOWNCAST(dir_connection_t, - test_conn_get_rsrc_setup(NULL)); + tt_assert(l_conn); + assert_connection_ok(l_conn, time(NULL)); + + /* AP connections don't seem to have purposes */ + connection_t *conn = test_conn_get_connection(state, CONN_TYPE_AP, + 0); tt_assert(conn); - assert_connection_ok(&conn->base_, time(NULL)); + assert_connection_ok(conn, time(NULL)); + + conn->linked = 1; + l_conn->linked = 1; + conn->linked_conn = l_conn; + l_conn->linked_conn = conn; + /* we never opened a real socket, so we can just overwrite it */ + conn->s = TOR_INVALID_SOCKET; + l_conn->s = TOR_INVALID_SOCKET; + + assert_connection_ok(conn, time(NULL)); + assert_connection_ok(l_conn, time(NULL)); return conn; @@ -524,44 +571,6 @@ test_conn_get_rsrc(void *arg) tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); - tt_assert(connection_dir_get_by_purpose_and_resource( - conn->base_.purpose, - conn->requested_resource) - == conn); - tt_assert(connection_dir_get_by_purpose_and_resource( - TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC) - == conn); - tt_assert(connection_dir_get_by_purpose_and_resource( - !conn->base_.purpose, - "") - == NULL); - tt_assert(connection_dir_get_by_purpose_and_resource( - !TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC_2) - == NULL); - - tt_assert(connection_dir_get_by_purpose_resource_and_state( - conn->base_.purpose, - conn->requested_resource, - conn->base_.state) - == conn); - tt_assert(connection_dir_get_by_purpose_resource_and_state( - TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC, - TEST_CONN_STATE) - == conn); - tt_assert(connection_dir_get_by_purpose_resource_and_state( - !conn->base_.purpose, - "", - !conn->base_.state) - == NULL); - tt_assert(connection_dir_get_by_purpose_resource_and_state( - !TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC_2, - !TEST_CONN_STATE) - == NULL); - sl_is_conn_assert(connection_dir_list_by_purpose_and_resource( conn->base_.purpose, conn->requested_resource), @@ -641,120 +650,208 @@ test_conn_get_rsrc(void *arg) static void test_conn_download_status(void *arg) { - (void)arg; dir_connection_t *conn = NULL; dir_connection_t *conn2 = NULL; - dir_connection_t *conn3 = NULL; - - /* no connections, no excess, not downloading */ - tt_assert(networkstatus_consensus_has_excess_connections() == 0); - tt_assert(networkstatus_consensus_is_downloading_usable_flavor() == 0); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 0); - - /* one connection, no excess, not downloading */ - conn = test_conn_download_status_add_a_connection(); - tt_assert(networkstatus_consensus_has_excess_connections() == 0); - tt_assert(networkstatus_consensus_is_downloading_usable_flavor() == 0); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 0); - - /* one connection, no excess, but downloading */ + dir_connection_t *conn4 = NULL; + connection_t *ap_conn = NULL; + + consensus_flavor_t usable_flavor = (consensus_flavor_t)arg; + + /* The "other flavor" trick only works if there are two flavors */ + tor_assert(N_CONSENSUS_FLAVORS == 2); + consensus_flavor_t other_flavor = ((usable_flavor == FLAV_NS) + ? FLAV_MICRODESC + : FLAV_NS); + const char *res = networkstatus_get_flavor_name(usable_flavor); + const char *other_res = networkstatus_get_flavor_name(other_flavor); + + /* no connections */ + tt_assert(networkstatus_consensus_is_already_downloading(res) == 0); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); + + /* one connection, not downloading */ + conn = test_conn_download_status_add_a_connection(res); + tt_assert(networkstatus_consensus_is_already_downloading(res) == 0); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 1); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); + + /* one connection, downloading but not linked (not possible on a client, + * but possible on a relay) */ conn->base_.state = TEST_CONN_DL_STATE; - tt_assert(networkstatus_consensus_has_excess_connections() == 0); - tt_assert(networkstatus_consensus_is_downloading_usable_flavor() == 1); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); - conn->base_.state = TEST_CONN_STATE; + tt_assert(networkstatus_consensus_is_already_downloading(res) == 0); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 1); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); - /* two connections, excess, but not downloading */ - conn2 = test_conn_download_status_add_a_connection(); - tt_assert(networkstatus_consensus_has_excess_connections() == 1); - tt_assert(networkstatus_consensus_is_downloading_usable_flavor() == 0); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 0); + /* one connection, downloading and linked, but not yet attached */ + ap_conn = test_conn_get_linked_connection(TO_CONN(conn), + TEST_CONN_UNATTACHED_STATE); + tt_assert(networkstatus_consensus_is_already_downloading(res) == 0); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 1); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); - /* two connections, excess, downloading */ - conn2->base_.state = TEST_CONN_DL_STATE; - tt_assert(networkstatus_consensus_has_excess_connections() == 1); - tt_assert(networkstatus_consensus_is_downloading_usable_flavor() == 1); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); - conn2->base_.state = TEST_CONN_STATE; - - /* more connections, excess, but not downloading */ - conn3 = test_conn_download_status_add_a_connection(); - tt_assert(networkstatus_consensus_has_excess_connections() == 1); - tt_assert(networkstatus_consensus_is_downloading_usable_flavor() == 0); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 0); - - /* more connections, excess, downloading */ - conn3->base_.state = TEST_CONN_DL_STATE; - tt_assert(networkstatus_consensus_has_excess_connections() == 1); - tt_assert(networkstatus_consensus_is_downloading_usable_flavor() == 1); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); - - /* more connections, more downloading */ - conn2->base_.state = TEST_CONN_DL_STATE; - tt_assert(networkstatus_consensus_has_excess_connections() == 1); - tt_assert(networkstatus_consensus_is_downloading_usable_flavor() == 1); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); + /* one connection, downloading and linked and attached */ + ap_conn->state = TEST_CONN_ATTACHED_STATE; + tt_assert(networkstatus_consensus_is_already_downloading(res) == 1); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 1); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); + + /* one connection, linked and attached but not downloading */ + conn->base_.state = TEST_CONN_STATE; + tt_assert(networkstatus_consensus_is_already_downloading(res) == 0); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 1); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); - /* now try closing the one that isn't downloading: - * these tests won't work unless tor thinks it is bootstrapping */ - tt_assert(networkstatus_consensus_is_bootstrapping(time(NULL))); + /* two connections, both not downloading */ + conn2 = test_conn_download_status_add_a_connection(res); + tt_assert(networkstatus_consensus_is_already_downloading(res) == 0); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 2); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); + /* two connections, one downloading */ + conn->base_.state = TEST_CONN_DL_STATE; + tt_assert(networkstatus_consensus_is_already_downloading(res) == 1); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 2); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); + conn->base_.state = TEST_CONN_STATE; + + /* more connections, all not downloading */ + /* ignore the return value, it's free'd using the connection list */ + (void)test_conn_download_status_add_a_connection(res); + tt_assert(networkstatus_consensus_is_already_downloading(res) == 0); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); tt_assert(connection_dir_count_by_purpose_and_resource( TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC) == 3); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); - tt_assert(connection_dir_close_consensus_conn_if_extra(conn) == -1); + res) == 3); tt_assert(connection_dir_count_by_purpose_and_resource( TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC) == 2); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); + other_res) == 0); - /* now try closing one that is already closed - nothing happens */ - tt_assert(connection_dir_close_consensus_conn_if_extra(conn) == 0); + /* more connections, one downloading */ + conn->base_.state = TEST_CONN_DL_STATE; + tt_assert(networkstatus_consensus_is_already_downloading(res) == 1); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); tt_assert(connection_dir_count_by_purpose_and_resource( TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC) == 2); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); + res) == 3); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 0); - /* now try closing one that is downloading - it stays open */ - tt_assert(connection_dir_close_consensus_conn_if_extra(conn2) == 0); + /* more connections, two downloading (should never happen, but needs + * to be tested for completeness) */ + conn2->base_.state = TEST_CONN_DL_STATE; + /* ignore the return value, it's free'd using the connection list */ + (void)test_conn_get_linked_connection(TO_CONN(conn2), + TEST_CONN_ATTACHED_STATE); + tt_assert(networkstatus_consensus_is_already_downloading(res) == 1); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 3); tt_assert(connection_dir_count_by_purpose_and_resource( TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC) == 2); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); + other_res) == 0); + conn->base_.state = TEST_CONN_STATE; - /* now try closing all excess connections */ - connection_dir_close_extra_consensus_conns(); + /* more connections, a different one downloading */ + tt_assert(networkstatus_consensus_is_already_downloading(res) == 1); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 3); tt_assert(connection_dir_count_by_purpose_and_resource( TEST_CONN_RSRC_PURPOSE, - TEST_CONN_RSRC) == 1); - tt_assert(connection_dir_avoid_extra_connection_for_purpose( - TEST_CONN_RSRC_PURPOSE) == 1); + other_res) == 0); + + /* a connection for the other flavor (could happen if a client is set to + * cache directory documents), one preferred flavor downloading + */ + conn4 = test_conn_download_status_add_a_connection(other_res); + tt_assert(networkstatus_consensus_is_already_downloading(res) == 1); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 3); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 1); + + /* a connection for the other flavor (could happen if a client is set to + * cache directory documents), both flavors downloading + */ + conn4->base_.state = TEST_CONN_DL_STATE; + /* ignore the return value, it's free'd using the connection list */ + (void)test_conn_get_linked_connection(TO_CONN(conn4), + TEST_CONN_ATTACHED_STATE); + tt_assert(networkstatus_consensus_is_already_downloading(res) == 1); + tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 1); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + res) == 3); + tt_assert(connection_dir_count_by_purpose_and_resource( + TEST_CONN_RSRC_PURPOSE, + other_res) == 1); done: - /* the teardown function removes all the connections */; + /* the teardown function removes all the connections in the global list*/; } #define CONNECTION_TESTCASE(name, fork, setup) \ { #name, test_conn_##name, fork, &setup, NULL } +/* where arg is an expression (constant, varaible, compound expression) */ +#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \ + { #name "_" #arg, test_conn_##name, fork, &setup, (void *)arg } + struct testcase_t connection_tests[] = { CONNECTION_TESTCASE(get_basic, TT_FORK, test_conn_get_basic_st), CONNECTION_TESTCASE(get_rend, TT_FORK, test_conn_get_rend_st), CONNECTION_TESTCASE(get_rsrc, TT_FORK, test_conn_get_rsrc_st), - CONNECTION_TESTCASE(download_status, TT_FORK, test_conn_download_status_st), + CONNECTION_TESTCASE_ARG(download_status, TT_FORK, + test_conn_download_status_st, FLAV_MICRODESC), + CONNECTION_TESTCASE_ARG(download_status, TT_FORK, + test_conn_download_status_st, FLAV_NS), //CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair), END_OF_TESTCASES }; diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 6a95e92733..e6b250a677 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -27,6 +27,7 @@ static void test_crypto_dh(void *arg) { crypto_dh_t *dh1 = crypto_dh_new(DH_TYPE_CIRCUIT); + crypto_dh_t *dh1_dup = NULL; crypto_dh_t *dh2 = crypto_dh_new(DH_TYPE_CIRCUIT); char p1[DH_BYTES]; char p2[DH_BYTES]; @@ -41,6 +42,9 @@ test_crypto_dh(void *arg) memset(p1, 0, DH_BYTES); memset(p2, 0, DH_BYTES); tt_mem_op(p1,OP_EQ, p2, DH_BYTES); + + tt_int_op(-1, OP_EQ, crypto_dh_get_public(dh1, p1, 6)); /* too short */ + tt_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES)); tt_mem_op(p1,OP_NE, p2, DH_BYTES); tt_assert(! crypto_dh_get_public(dh2, p2, DH_BYTES)); @@ -54,15 +58,117 @@ test_crypto_dh(void *arg) tt_int_op(s1len,OP_EQ, s2len); tt_mem_op(s1,OP_EQ, s2, s1len); + /* test dh_dup; make sure it works the same. */ + dh1_dup = crypto_dh_dup(dh1); + s1len = crypto_dh_compute_secret(LOG_WARN, dh1_dup, p2, DH_BYTES, s1, 50); + tt_mem_op(s1,OP_EQ, s2, s1len); + { - /* XXXX Now fabricate some bad values and make sure they get caught, - * Check 0, 1, N-1, >= N, etc. - */ + /* Now fabricate some bad values and make sure they get caught. */ + + /* 1 and 0 should both fail. */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, "\x01", 1, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, "\x00", 1, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + memset(p1, 0, DH_BYTES); /* 0 with padding. */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + p1[DH_BYTES-1] = 1; /* 1 with padding*/ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + /* 2 is okay, though weird. */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, "\x02", 1, s1, 50); + tt_int_op(50, OP_EQ, s1len); + + const char P[] = + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE65381FFFFFFFFFFFFFFFF"; + + /* p-1, p, and so on are not okay. */ + base16_decode(p1, sizeof(p1), P, strlen(P)); + + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + p1[DH_BYTES-1] = 0xFE; /* p-1 */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + p1[DH_BYTES-1] = 0xFD; /* p-2 works fine */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(50, OP_EQ, s1len); + + const char P_plus_one[] = + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE653820000000000000000"; + + base16_decode(p1, sizeof(p1), P_plus_one, strlen(P_plus_one)); + + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + p1[DH_BYTES-1] = 0x01; /* p+2 */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + p1[DH_BYTES-1] = 0xff; /* p+256 */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + + memset(p1, 0xff, DH_BYTES), /* 2^1024-1 */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + tt_int_op(-1, OP_EQ, s1len); + } + + { + /* provoke an error in the openssl DH_compute_key function; make sure we + * survive. */ + tt_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES)); + + crypto_dh_free(dh2); + dh2= crypto_dh_new(DH_TYPE_CIRCUIT); /* no private key set */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh2, + p1, DH_BYTES, + s1, 50); + tt_int_op(s1len, OP_EQ, -1); } done: crypto_dh_free(dh1); crypto_dh_free(dh2); + crypto_dh_free(dh1_dup); +} + +static void +test_crypto_openssl_version(void *arg) +{ + (void)arg; + const char *version = crypto_openssl_get_version_str(); + const char *h_version = crypto_openssl_get_header_version_str(); + + tt_assert(version); + tt_assert(h_version); + tt_assert(!strcmpstart(version, h_version)); /* "-fips" suffix, etc */ + tt_assert(!strstr(version, "OpenSSL")); + int a=-1,b=-1,c=-1; + sscanf(version, "%d.%d.%d", &a,&b,&c); + tt_int_op(a, OP_GE, 0); + tt_int_op(b, OP_GE, 0); + tt_int_op(c, OP_GE, 0); + + done: + ; } /** Run unit tests for our random number generation function and its wrappers. @@ -73,6 +179,7 @@ test_crypto_rng(void *arg) int i, j, allok; char data1[100], data2[100]; double d; + char *h=NULL; /* Try out RNG. */ (void)arg; @@ -104,9 +211,16 @@ test_crypto_rng(void *arg) allok = 0; tor_free(host); } + + /* Make sure crypto_random_hostname clips its inputs properly. */ + h = crypto_random_hostname(20000, 9000, "www.", ".onion"); + tt_assert(! strcmpstart(h,"www.")); + tt_assert(! strcmpend(h,".onion")); + tt_int_op(63+4+6, OP_EQ, strlen(h)); + tt_assert(allok); done: - ; + tor_free(h); } static void @@ -125,14 +239,103 @@ test_crypto_rng_range(void *arg) if (x == 8) got_largest = 1; } - /* These fail with probability 1/10^603. */ tt_assert(got_smallest); tt_assert(got_largest); + + got_smallest = got_largest = 0; + const uint64_t ten_billion = 10 * ((uint64_t)1000000000000); + for (i = 0; i < 1000; ++i) { + uint64_t x = crypto_rand_uint64_range(ten_billion, ten_billion+10); + tt_u64_op(x, OP_GE, ten_billion); + tt_u64_op(x, OP_LT, ten_billion+10); + if (x == ten_billion) + got_smallest = 1; + if (x == ten_billion+9) + got_largest = 1; + } + + tt_assert(got_smallest); + tt_assert(got_largest); + + const time_t now = time(NULL); + for (i = 0; i < 2000; ++i) { + time_t x = crypto_rand_time_range(now, now+60); + tt_i64_op(x, OP_GE, now); + tt_i64_op(x, OP_LT, now+60); + if (x == now) + got_smallest = 1; + if (x == now+59) + got_largest = 1; + } + + tt_assert(got_smallest); + tt_assert(got_largest); done: ; } +extern int break_strongest_rng_fallback; +extern int break_strongest_rng_syscall; + +static void +test_crypto_rng_strongest(void *arg) +{ + const char *how = arg; + int broken = 0; + + if (how == NULL) { + ; + } else if (!strcmp(how, "nosyscall")) { + break_strongest_rng_syscall = 1; + } else if (!strcmp(how, "nofallback")) { + break_strongest_rng_fallback = 1; + } else if (!strcmp(how, "broken")) { + broken = break_strongest_rng_syscall = break_strongest_rng_fallback = 1; + } + +#define N 128 + uint8_t combine_and[N]; + uint8_t combine_or[N]; + int i, j; + + memset(combine_and, 0xff, N); + memset(combine_or, 0, N); + + for (i = 0; i < 100; ++i) { /* 2^-100 chances just don't happen. */ + uint8_t output[N]; + memset(output, 0, N); + if (how == NULL) { + /* this one can't fail. */ + crypto_strongest_rand(output, sizeof(output)); + } else { + int r = crypto_strongest_rand_raw(output, sizeof(output)); + if (r == -1) { + if (broken) { + goto done; /* we're fine. */ + } + /* This function is allowed to break, but only if it always breaks. */ + tt_int_op(i, OP_EQ, 0); + tt_skip(); + } else { + tt_assert(! broken); + } + } + for (j = 0; j < N; ++j) { + combine_and[j] &= output[j]; + combine_or[j] |= output[j]; + } + } + + for (j = 0; j < N; ++j) { + tt_int_op(combine_and[j], OP_EQ, 0); + tt_int_op(combine_or[j], OP_EQ, 0xff); + } + done: + ; +#undef N +} + /* Test for rectifying openssl RAND engine. */ static void test_crypto_rng_engine(void *arg) @@ -312,6 +515,42 @@ test_crypto_aes(void *arg) tor_free(data3); } +static void +test_crypto_aes_ctr_testvec(void *arg) +{ + (void)arg; + char *mem_op_hex_tmp=NULL; + + /* from NIST SP800-38a, section F.5 */ + const char key16[] = "2b7e151628aed2a6abf7158809cf4f3c"; + const char ctr16[] = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + const char plaintext16[] = + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"; + const char ciphertext16[] = + "874d6191b620e3261bef6864990db6ce" + "9806f66b7970fdff8617187bb9fffdff" + "5ae4df3edbd5d35e5b4f09020db03eab" + "1e031dda2fbe03d1792170a0f3009cee"; + + char key[16]; + char iv[16]; + char plaintext[16*4]; + base16_decode(key, sizeof(key), key16, strlen(key16)); + base16_decode(iv, sizeof(iv), ctr16, strlen(ctr16)); + base16_decode(plaintext, sizeof(plaintext), plaintext16, strlen(plaintext16)); + + crypto_cipher_t *c = crypto_cipher_new_with_iv(key, iv); + crypto_cipher_crypt_inplace(c, plaintext, sizeof(plaintext)); + test_memeq_hex(plaintext, ciphertext16); + + done: + tor_free(mem_op_hex_tmp); + crypto_cipher_free(c); +} + /** Run unit tests for our SHA-1 functionality */ static void test_crypto_sha(void *arg) @@ -1084,6 +1323,29 @@ test_crypto_pk_base64(void *arg) tor_free(encoded); } +#ifdef HAVE_TRUNCATE +#define do_truncate truncate +#else +static int +do_truncate(const char *fname, size_t len) +{ + struct stat st; + char *bytes; + + bytes = read_file_to_str(fname, RFTS_BIN, &st); + if (!bytes) + return -1; + /* This cast isn't so great, but it should be safe given the actual files + * and lengths we're using. */ + if (st.st_size < (off_t)len) + len = MIN(len, (size_t)st.st_size); + + int r = write_bytes_to_file(fname, bytes, len, 1); + tor_free(bytes); + return r; +} +#endif + /** Sanity check for crypto pk digests */ static void test_crypto_digests(void *arg) @@ -1114,6 +1376,31 @@ test_crypto_digests(void *arg) crypto_pk_free(k); } +static void +test_crypto_digest_names(void *arg) +{ + static const struct { + int a; const char *n; + } names[] = { + { DIGEST_SHA1, "sha1" }, + { DIGEST_SHA256, "sha256" }, + { DIGEST_SHA512, "sha512" }, + { DIGEST_SHA3_256, "sha3-256" }, + { DIGEST_SHA3_512, "sha3-512" }, + { -1, NULL } + }; + (void)arg; + + int i; + for (i = 0; names[i].n; ++i) { + tt_str_op(names[i].n, OP_EQ,crypto_digest_algorithm_get_name(names[i].a)); + tt_int_op(names[i].a, OP_EQ,crypto_digest_algorithm_parse_name(names[i].n)); + } + tt_int_op(-1, OP_EQ, crypto_digest_algorithm_parse_name("TimeCubeHash-4444")); + done: + ; +} + #ifndef OPENSSL_1_1_API #define EVP_ENCODE_CTX_new() tor_malloc_zero(sizeof(EVP_ENCODE_CTX)) #define EVP_ENCODE_CTX_free(ctx) tor_free(ctx) @@ -1507,13 +1794,99 @@ test_crypto_hkdf_sha256(void *arg) "b206fa34e5bc78d063fc291501beec53b36e5a0e434561200c" "5f8bd13e0f88b3459600b4dc21d69363e2895321c06184879d" "94b18f078411be70b767c7fc40679a9440a0c95ea83a23efbf"); - done: tor_free(mem_op_hex_tmp); #undef EXPAND } static void +test_crypto_hkdf_sha256_testvecs(void *arg) +{ + (void) arg; + /* Test vectors from RFC5869, sections A.1 through A.3 */ + const struct { + const char *ikm16, *salt16, *info16; + int L; + const char *okm16; + } vecs[] = { + { /* from A.1 */ + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + 42, + "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + "34007208d5b887185865" + }, + { /* from A.2 */ + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + 82, + "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c" + "59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71" + "cc30c58179ec3e87c14c01d5c1f3434f1d87" + }, + { /* from A.3 */ + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "", + "", + 42, + "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d" + "9d201395faa4b61a96c8", + }, + { NULL, NULL, NULL, -1, NULL } + }; + + int i; + char *ikm = NULL; + char *salt = NULL; + char *info = NULL; + char *okm = NULL; + char *mem_op_hex_tmp = NULL; + + for (i = 0; vecs[i].ikm16; ++i) { + size_t ikm_len = strlen(vecs[i].ikm16)/2; + size_t salt_len = strlen(vecs[i].salt16)/2; + size_t info_len = strlen(vecs[i].info16)/2; + size_t okm_len = vecs[i].L; + + ikm = tor_malloc(ikm_len); + salt = tor_malloc(salt_len); + info = tor_malloc(info_len); + okm = tor_malloc(okm_len); + + base16_decode(ikm, ikm_len, vecs[i].ikm16, strlen(vecs[i].ikm16)); + base16_decode(salt, salt_len, vecs[i].salt16, strlen(vecs[i].salt16)); + base16_decode(info, info_len, vecs[i].info16, strlen(vecs[i].info16)); + + int r = crypto_expand_key_material_rfc5869_sha256( + (const uint8_t*)ikm, ikm_len, + (const uint8_t*)salt, salt_len, + (const uint8_t*)info, info_len, + (uint8_t*)okm, okm_len); + tt_int_op(r, OP_EQ, 0); + test_memeq_hex(okm, vecs[i].okm16); + tor_free(ikm); + tor_free(salt); + tor_free(info); + tor_free(okm); + } + done: + tor_free(ikm); + tor_free(salt); + tor_free(info); + tor_free(okm); + tor_free(mem_op_hex_tmp); +} + + +static void test_crypto_curve25519_impl(void *arg) { /* adapted from curve25519_donna, which adapted it from test-curve25519 @@ -1605,6 +1978,47 @@ test_crypto_curve25519_basepoint(void *arg) } static void +test_crypto_curve25519_testvec(void *arg) +{ + (void)arg; + char *mem_op_hex_tmp = NULL; + + /* From RFC 7748, section 6.1 */ + /* Alice's private key, a: */ + const char a16[] = + "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"; + /* Alice's public key, X25519(a, 9): */ + const char a_pub16[] = + "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"; + /* Bob's private key, b: */ + const char b16[] = + "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"; + /* Bob's public key, X25519(b, 9): */ + const char b_pub16[] = + "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"; + /* Their shared secret, K: */ + const char k16[] = + "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"; + + uint8_t a[32], b[32], a_pub[32], b_pub[32], k1[32], k2[32]; + base16_decode((char*)a, sizeof(a), a16, strlen(a16)); + base16_decode((char*)b, sizeof(b), b16, strlen(b16)); + curve25519_basepoint_impl(a_pub, a); + curve25519_basepoint_impl(b_pub, b); + curve25519_impl(k1, a, b_pub); + curve25519_impl(k2, b, a_pub); + + test_memeq_hex(a, a16); + test_memeq_hex(b, b16); + test_memeq_hex(a_pub, a_pub16); + test_memeq_hex(b_pub, b_pub16); + test_memeq_hex(k1, k16); + test_memeq_hex(k2, k16); + done: + tor_free(mem_op_hex_tmp); +} + +static void test_crypto_curve25519_wrappers(void *arg) { curve25519_public_key_t pubkey1, pubkey2; @@ -1896,7 +2310,67 @@ test_crypto_ed25519_test_vectors(void *arg) "1fbc1e08682f2cc0c92efe8f4985dec61dcbd54d4b94a22547d24451271c8b00", "0a688e79be24f866286d4646b5d81c" }, - + /* These come from draft-irtf-cfrg-eddsa-05 section 7.1 */ + { + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", + "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155" + "5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b", + "" + }, + { + "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", + "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", + "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da" + "085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00", + "72" + }, + { + "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5", + "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e", + "0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350" + "aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03", + "08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98" + "fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d8" + "79de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d" + "658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc" + "1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4fe" + "ba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e" + "06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbef" + "efd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7" + "aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed1" + "85ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2" + "d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24" + "554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f270" + "88d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc" + "2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b07" + "07e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128ba" + "b27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51a" + "ddd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429e" + "c96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb7" + "51fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c" + "42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8" + "ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34df" + "f7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08" + "d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649" + "de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e4" + "88acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a3" + "2ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e" + "6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5f" + "b93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b5" + "0d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1" + "369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380d" + "b2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c" + "0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0" + }, + { + "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42", + "ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf", + "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b589" + "09351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704", + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" + }, { NULL, NULL, NULL, NULL} }; @@ -2183,6 +2657,54 @@ test_crypto_ed25519_fuzz_donna(void *arg) } static void +test_crypto_ed25519_storage(void *arg) +{ + (void)arg; + ed25519_keypair_t *keypair = NULL; + ed25519_public_key_t pub; + ed25519_secret_key_t sec; + char *fname_1 = tor_strdup(get_fname("ed_seckey_1")); + char *fname_2 = tor_strdup(get_fname("ed_pubkey_2")); + char *contents = NULL; + char *tag = NULL; + + keypair = tor_malloc_zero(sizeof(ed25519_keypair_t)); + tt_int_op(0,OP_EQ,ed25519_keypair_generate(keypair, 0)); + tt_int_op(0,OP_EQ, + ed25519_seckey_write_to_file(&keypair->seckey, fname_1, "foo")); + tt_int_op(0,OP_EQ, + ed25519_pubkey_write_to_file(&keypair->pubkey, fname_2, "bar")); + + tt_int_op(-1, OP_EQ, ed25519_pubkey_read_from_file(&pub, &tag, fname_1)); + tt_ptr_op(tag, OP_EQ, NULL); + tt_int_op(-1, OP_EQ, ed25519_seckey_read_from_file(&sec, &tag, fname_2)); + tt_ptr_op(tag, OP_EQ, NULL); + + tt_int_op(0, OP_EQ, ed25519_pubkey_read_from_file(&pub, &tag, fname_2)); + tt_str_op(tag, OP_EQ, "bar"); + tor_free(tag); + tt_int_op(0, OP_EQ, ed25519_seckey_read_from_file(&sec, &tag, fname_1)); + tt_str_op(tag, OP_EQ, "foo"); + tor_free(tag); + + /* whitebox test: truncated keys. */ + tt_int_op(0, ==, do_truncate(fname_1, 40)); + tt_int_op(0, ==, do_truncate(fname_2, 40)); + tt_int_op(-1, OP_EQ, ed25519_pubkey_read_from_file(&pub, &tag, fname_2)); + tt_ptr_op(tag, OP_EQ, NULL); + tor_free(tag); + tt_int_op(-1, OP_EQ, ed25519_seckey_read_from_file(&sec, &tag, fname_1)); + tt_ptr_op(tag, OP_EQ, NULL); + + done: + tor_free(fname_1); + tor_free(fname_2); + tor_free(contents); + tor_free(tag); + ed25519_keypair_free(keypair); +} + +static void test_crypto_siphash(void *arg) { /* From the reference implementation, taking @@ -2398,13 +2920,23 @@ struct testcase_t crypto_tests[] = { CRYPTO_LEGACY(rng), { "rng_range", test_crypto_rng_range, 0, NULL, NULL }, { "rng_engine", test_crypto_rng_engine, TT_FORK, NULL, NULL }, + { "rng_strongest", test_crypto_rng_strongest, TT_FORK, NULL, NULL }, + { "rng_strongest_nosyscall", test_crypto_rng_strongest, TT_FORK, + &passthrough_setup, (void*)"nosyscall" }, + { "rng_strongest_nofallback", test_crypto_rng_strongest, TT_FORK, + &passthrough_setup, (void*)"nofallback" }, + { "rng_strongest_broken", test_crypto_rng_strongest, TT_FORK, + &passthrough_setup, (void*)"broken" }, + { "openssl_version", test_crypto_openssl_version, TT_FORK, NULL, NULL }, { "aes_AES", test_crypto_aes, TT_FORK, &passthrough_setup, (void*)"aes" }, { "aes_EVP", test_crypto_aes, TT_FORK, &passthrough_setup, (void*)"evp" }, + { "aes_ctr_testvec", test_crypto_aes_ctr_testvec, 0, NULL, NULL }, CRYPTO_LEGACY(sha), CRYPTO_LEGACY(pk), { "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL }, { "pk_base64", test_crypto_pk_base64, TT_FORK, NULL, NULL }, CRYPTO_LEGACY(digests), + { "digest_names", test_crypto_digest_names, 0, NULL, NULL }, { "sha3", test_crypto_sha3, TT_FORK, NULL, NULL}, { "sha3_xof", test_crypto_sha3_xof, TT_FORK, NULL, NULL}, CRYPTO_LEGACY(dh), @@ -2415,8 +2947,10 @@ struct testcase_t crypto_tests[] = { CRYPTO_LEGACY(base32_decode), { "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL }, { "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL }, + { "hkdf_sha256_testvecs", test_crypto_hkdf_sha256_testvecs, 0, NULL, NULL }, { "curve25519_impl", test_crypto_curve25519_impl, 0, NULL, NULL }, { "curve25519_impl_hibit", test_crypto_curve25519_impl, 0, NULL, (void*)"y"}, + { "curve25516_testvec", test_crypto_curve25519_testvec, 0, NULL, NULL }, { "curve25519_basepoint", test_crypto_curve25519_basepoint, TT_FORK, NULL, NULL }, { "curve25519_wrappers", test_crypto_curve25519_wrappers, 0, NULL, NULL }, @@ -2429,6 +2963,7 @@ struct testcase_t crypto_tests[] = { ED25519_TEST(blinding, 0), ED25519_TEST(testvectors, 0), ED25519_TEST(fuzz_donna, TT_FORK), + { "ed25519_storage", test_crypto_ed25519_storage, 0, NULL, NULL }, { "siphash", test_crypto_siphash, 0, NULL, NULL }, { "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL }, END_OF_TESTCASES diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c index 9b39199cd0..6f3e40e0ab 100644 --- a/src/test/test_crypto_slow.c +++ b/src/test/test_crypto_slow.c @@ -10,7 +10,8 @@ #include "crypto_s2k.h" #include "crypto_pwbox.h" -#if defined(HAVE_LIBSCRYPT_H) +#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT) +#define HAVE_LIBSCRYPT #include <libscrypt.h> #endif @@ -129,7 +130,7 @@ test_crypto_s2k_general(void *arg) } } -#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_EVP_PBE_SCRYPT) +#if defined(HAVE_LIBSCRYPT) && defined(HAVE_EVP_PBE_SCRYPT) static void test_libscrypt_eq_openssl(void *arg) { @@ -276,7 +277,7 @@ test_crypto_s2k_errors(void *arg) buf, sizeof(buf), "ABC", 3)); /* Truncated output */ -#ifdef HAVE_LIBSCRYPT_H +#ifdef HAVE_LIBSCRYPT tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz, "ABC", 3, 0)); tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz, @@ -287,7 +288,7 @@ test_crypto_s2k_errors(void *arg) tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 29, &sz, "ABC", 3, S2K_FLAG_NO_SCRYPT)); -#ifdef HAVE_LIBSCRYPT_H +#ifdef HAVE_LIBSCRYPT tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 18, 0)); tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 18, S2K_FLAG_LOW_MEM)); @@ -308,7 +309,7 @@ test_crypto_s2k_errors(void *arg) secret_to_key_derivekey(buf2, sizeof(buf2), buf, 18, "ABC", 3)); -#ifdef HAVE_LIBSCRYPT_H +#ifdef HAVE_LIBSCRYPT /* It's a bad scrypt buffer if N would overflow uint64 */ memset(buf, 0, sizeof(buf)); buf[0] = 2; /* scrypt */ @@ -329,7 +330,7 @@ test_crypto_scrypt_vectors(void *arg) uint8_t spec[64], out[64]; (void)arg; -#ifndef HAVE_LIBSCRYPT_H +#ifndef HAVE_LIBSCRYPT if (1) tt_skip(); #endif @@ -507,7 +508,7 @@ test_crypto_pwbox(void *arg) struct testcase_t slow_crypto_tests[] = { CRYPTO_LEGACY(s2k_rfc2440), -#ifdef HAVE_LIBSCRYPT_H +#ifdef HAVE_LIBSCRYPT { "s2k_scrypt", test_crypto_s2k_general, 0, &passthrough_setup, (void*)"scrypt" }, { "s2k_scrypt_low", test_crypto_s2k_general, 0, &passthrough_setup, diff --git a/src/test/test_dir.c b/src/test/test_dir.c index ea179fb02c..bddbe9f18e 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -85,6 +85,15 @@ test_dir_nicknames(void *arg) ; } +static smartlist_t *mocked_configured_ports = NULL; + +/** Returns mocked_configured_ports */ +static const smartlist_t * +mock_get_configured_ports(void) +{ + return mocked_configured_ports; +} + /** Run unit tests for router descriptor generation logic. */ static void test_dir_formats(void *arg) @@ -104,6 +113,7 @@ test_dir_formats(void *arg) or_options_t *options = get_options_mutable(); const addr_policy_t *p; time_t now = time(NULL); + port_cfg_t orport, dirport; (void)arg; pk1 = pk_generate(0); @@ -150,15 +160,15 @@ test_dir_formats(void *arg) ed25519_secret_key_from_seed(&kp2.seckey, (const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey); - r2->signing_key_cert = tor_cert_create(&kp1, + r2->cache_info.signing_key_cert = tor_cert_create(&kp1, CERT_TYPE_ID_SIGNING, &kp2.pubkey, now, 86400, CERT_FLAG_INCLUDE_SIGNING_KEY); char cert_buf[256]; base64_encode(cert_buf, sizeof(cert_buf), - (const char*)r2->signing_key_cert->encoded, - r2->signing_key_cert->encoded_len, + (const char*)r2->cache_info.signing_key_cert->encoded, + r2->cache_info.signing_key_cert->encoded_len, BASE64_ENCODE_MULTILINE); r2->platform = tor_strdup(platform); r2->cache_info.published_on = 5; @@ -185,9 +195,31 @@ test_dir_formats(void *arg) /* XXXX025 router_dump_to_string should really take this from ri.*/ options->ContactInfo = tor_strdup("Magri White " "<magri@elsewhere.example.com>"); + /* Skip reachability checks for DirPort and tunnelled-dir-server */ + options->AssumeReachable = 1; + + /* Fake just enough of an ORPort and DirPort to get by */ + MOCK(get_configured_ports, mock_get_configured_ports); + mocked_configured_ports = smartlist_new(); + + memset(&orport, 0, sizeof(orport)); + orport.type = CONN_TYPE_OR_LISTENER; + orport.addr.family = AF_INET; + orport.port = 9000; + smartlist_add(mocked_configured_ports, &orport); + + memset(&dirport, 0, sizeof(dirport)); + dirport.type = CONN_TYPE_DIR_LISTENER; + dirport.addr.family = AF_INET; + dirport.port = 9003; + smartlist_add(mocked_configured_ports, &dirport); buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL); + UNMOCK(get_configured_ports); + smartlist_free(mocked_configured_ports); + mocked_configured_ports = NULL; + tor_free(options->ContactInfo); tt_assert(buf); @@ -247,7 +279,8 @@ test_dir_formats(void *arg) strlcat(buf2, "master-key-ed25519 ", sizeof(buf2)); { char k[ED25519_BASE64_LEN+1]; - tt_assert(ed25519_public_to_base64(k, &r2->signing_key_cert->signing_key) + tt_assert(ed25519_public_to_base64(k, + &r2->cache_info.signing_key_cert->signing_key) >= 0); strlcat(buf2, k, sizeof(buf2)); strlcat(buf2, "\n", sizeof(buf2)); @@ -308,6 +341,16 @@ test_dir_formats(void *arg) strlcat(buf2, "tunnelled-dir-server\n", sizeof(buf2)); strlcat(buf2, "router-sig-ed25519 ", sizeof(buf2)); + /* Fake just enough of an ORPort to get by */ + MOCK(get_configured_ports, mock_get_configured_ports); + mocked_configured_ports = smartlist_new(); + + memset(&orport, 0, sizeof(orport)); + orport.type = CONN_TYPE_OR_LISTENER; + orport.addr.family = AF_INET; + orport.port = 9005; + smartlist_add(mocked_configured_ports, &orport); + buf = router_dump_router_to_string(r2, pk1, pk2, &r2_onion_keypair, &kp2); tt_assert(buf); buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same @@ -318,6 +361,10 @@ test_dir_formats(void *arg) buf = router_dump_router_to_string(r2, pk1, NULL, NULL, NULL); + UNMOCK(get_configured_ports); + smartlist_free(mocked_configured_ports); + mocked_configured_ports = NULL; + /* Reset for later */ cp = buf; rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); @@ -2149,56 +2196,57 @@ test_dir_scale_bw(void *testdata) 1.0/7, 12.0, 24.0 }; - u64_dbl_t vals[8]; + double vals_dbl[8]; + uint64_t vals_u64[8]; uint64_t total; int i; (void) testdata; for (i=0; i<8; ++i) - vals[i].dbl = v[i]; + vals_dbl[i] = v[i]; - scale_array_elements_to_u64(vals, 8, &total); + scale_array_elements_to_u64(vals_u64, vals_dbl, 8, &total); tt_int_op((int)total, OP_EQ, 48); total = 0; for (i=0; i<8; ++i) { - total += vals[i].u64; + total += vals_u64[i]; } tt_assert(total >= (U64_LITERAL(1)<<60)); tt_assert(total <= (U64_LITERAL(1)<<62)); for (i=0; i<8; ++i) { /* vals[2].u64 is the scaled value of 1.0 */ - double ratio = ((double)vals[i].u64) / vals[2].u64; + double ratio = ((double)vals_u64[i]) / vals_u64[2]; tt_double_op(fabs(ratio - v[i]), OP_LT, .00001); } /* test handling of no entries */ total = 1; - scale_array_elements_to_u64(vals, 0, &total); + scale_array_elements_to_u64(vals_u64, vals_dbl, 0, &total); tt_assert(total == 0); /* make sure we don't read the array when we have no entries * may require compiler flags to catch NULL dereferences */ total = 1; - scale_array_elements_to_u64(NULL, 0, &total); + scale_array_elements_to_u64(NULL, NULL, 0, &total); tt_assert(total == 0); - scale_array_elements_to_u64(NULL, 0, NULL); + scale_array_elements_to_u64(NULL, NULL, 0, NULL); /* test handling of zero totals */ total = 1; - vals[0].dbl = 0.0; - scale_array_elements_to_u64(vals, 1, &total); + vals_dbl[0] = 0.0; + scale_array_elements_to_u64(vals_u64, vals_dbl, 1, &total); tt_assert(total == 0); - tt_assert(vals[0].u64 == 0); + tt_assert(vals_u64[0] == 0); - vals[0].dbl = 0.0; - vals[1].dbl = 0.0; - scale_array_elements_to_u64(vals, 2, NULL); - tt_assert(vals[0].u64 == 0); - tt_assert(vals[1].u64 == 0); + vals_dbl[0] = 0.0; + vals_dbl[1] = 0.0; + scale_array_elements_to_u64(vals_u64, vals_dbl, 2, NULL); + tt_assert(vals_u64[0] == 0); + tt_assert(vals_u64[1] == 0); done: ; @@ -2209,7 +2257,7 @@ test_dir_random_weighted(void *testdata) { int histogram[10]; uint64_t vals[10] = {3,1,2,4,6,0,7,5,8,9}, total=0; - u64_dbl_t inp[10]; + uint64_t inp_u64[10]; int i, choice; const int n = 50000; double max_sq_error; @@ -2219,12 +2267,12 @@ test_dir_random_weighted(void *testdata) * in a scrambled order to make sure we don't depend on order. */ memset(histogram,0,sizeof(histogram)); for (i=0; i<10; ++i) { - inp[i].u64 = vals[i]; + inp_u64[i] = vals[i]; total += vals[i]; } tt_u64_op(total, OP_EQ, 45); for (i=0; i<n; ++i) { - choice = choose_array_element_by_weight(inp, 10); + choice = choose_array_element_by_weight(inp_u64, 10); tt_int_op(choice, OP_GE, 0); tt_int_op(choice, OP_LT, 10); histogram[choice]++; @@ -2251,16 +2299,16 @@ test_dir_random_weighted(void *testdata) /* Now try a singleton; do we choose it? */ for (i = 0; i < 100; ++i) { - choice = choose_array_element_by_weight(inp, 1); + choice = choose_array_element_by_weight(inp_u64, 1); tt_int_op(choice, OP_EQ, 0); } /* Now try an array of zeros. We should choose randomly. */ memset(histogram,0,sizeof(histogram)); for (i = 0; i < 5; ++i) - inp[i].u64 = 0; + inp_u64[i] = 0; for (i = 0; i < n; ++i) { - choice = choose_array_element_by_weight(inp, 5); + choice = choose_array_element_by_weight(inp_u64, 5); tt_int_op(choice, OP_GE, 0); tt_int_op(choice, OP_LT, 5); histogram[choice]++; @@ -3995,12 +4043,56 @@ test_dir_choose_compression_level(void* data) done: ; } +static int mock_networkstatus_consensus_is_bootstrapping_value = 0; +static int +mock_networkstatus_consensus_is_bootstrapping(time_t now) +{ + (void)now; + return mock_networkstatus_consensus_is_bootstrapping_value; +} + +static int mock_networkstatus_consensus_can_use_extra_fallbacks_value = 0; +static int +mock_networkstatus_consensus_can_use_extra_fallbacks( + const or_options_t *options) +{ + (void)options; + return mock_networkstatus_consensus_can_use_extra_fallbacks_value; +} + +/* data is a 2 character nul-terminated string. + * If data[0] is 'b', set bootstrapping, anything else means not bootstrapping + * If data[1] is 'f', set extra fallbacks, anything else means no extra + * fallbacks. + */ static void test_dir_find_dl_schedule(void* data) { + const char *str = (const char *)data; + + tt_assert(strlen(data) == 2); + + if (str[0] == 'b') { + mock_networkstatus_consensus_is_bootstrapping_value = 1; + } else { + mock_networkstatus_consensus_is_bootstrapping_value = 0; + } + + if (str[1] == 'f') { + mock_networkstatus_consensus_can_use_extra_fallbacks_value = 1; + } else { + mock_networkstatus_consensus_can_use_extra_fallbacks_value = 0; + } + + MOCK(networkstatus_consensus_is_bootstrapping, + mock_networkstatus_consensus_is_bootstrapping); + MOCK(networkstatus_consensus_can_use_extra_fallbacks, + mock_networkstatus_consensus_can_use_extra_fallbacks); + download_status_t dls; - smartlist_t server, client, server_cons, client_cons, bridge; - (void)data; + smartlist_t server, client, server_cons, client_cons; + smartlist_t client_boot_auth_only_cons, client_boot_auth_cons; + smartlist_t client_boot_fallback_cons, bridge; mock_options = malloc(sizeof(or_options_t)); reset_options(mock_options, &mock_get_options_calls); @@ -4010,43 +4102,121 @@ test_dir_find_dl_schedule(void* data) mock_options->TestingClientDownloadSchedule = &client; mock_options->TestingServerConsensusDownloadSchedule = &server_cons; mock_options->TestingClientConsensusDownloadSchedule = &client_cons; + mock_options->ClientBootstrapConsensusAuthorityOnlyDownloadSchedule = + &client_boot_auth_only_cons; + mock_options->ClientBootstrapConsensusAuthorityDownloadSchedule = + &client_boot_auth_cons; + mock_options->ClientBootstrapConsensusFallbackDownloadSchedule = + &client_boot_fallback_cons; mock_options->TestingBridgeDownloadSchedule = &bridge; dls.schedule = DL_SCHED_GENERIC; + /* client */ mock_options->ClientOnly = 1; tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &client); mock_options->ClientOnly = 0; + + /* dir mode */ mock_options->DirPort_set = 1; - mock_options->ORPort_set = 1; mock_options->DirCache = 1; tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &server); + mock_options->DirPort_set = 0; + mock_options->DirCache = 0; -#if 0 dls.schedule = DL_SCHED_CONSENSUS; - mock_options->ClientOnly = 1; - mock_options->DirCache = 0; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &client_cons); - mock_options->ClientOnly = 0; - mock_options->DirCache = 1; + /* public server mode */ + mock_options->ORPort_set = 1; tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &server_cons); -#endif + mock_options->ORPort_set = 0; + + /* client and bridge modes */ + if (networkstatus_consensus_is_bootstrapping(time(NULL))) { + if (networkstatus_consensus_can_use_extra_fallbacks(mock_options)) { + dls.want_authority = 1; + /* client */ + mock_options->ClientOnly = 1; + tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, + &client_boot_auth_cons); + mock_options->ClientOnly = 0; + + /* bridge relay */ + mock_options->ORPort_set = 1; + mock_options->BridgeRelay = 1; + tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, + &client_boot_auth_cons); + mock_options->ORPort_set = 0; + mock_options->BridgeRelay = 0; + + dls.want_authority = 0; + /* client */ + mock_options->ClientOnly = 1; + tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, + &client_boot_fallback_cons); + mock_options->ClientOnly = 0; + + /* bridge relay */ + mock_options->ORPort_set = 1; + mock_options->BridgeRelay = 1; + tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, + &client_boot_fallback_cons); + mock_options->ORPort_set = 0; + mock_options->BridgeRelay = 0; + + } else { + /* dls.want_authority is ignored */ + /* client */ + mock_options->ClientOnly = 1; + tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, + &client_boot_auth_only_cons); + mock_options->ClientOnly = 0; + + /* bridge relay */ + mock_options->ORPort_set = 1; + mock_options->BridgeRelay = 1; + tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, + &client_boot_auth_only_cons); + mock_options->ORPort_set = 0; + mock_options->BridgeRelay = 0; + } + } else { + /* client */ + mock_options->ClientOnly = 1; + tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, + &client_cons); + mock_options->ClientOnly = 0; + + /* bridge relay */ + mock_options->ORPort_set = 1; + mock_options->BridgeRelay = 1; + tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, + &client_cons); + mock_options->ORPort_set = 0; + mock_options->BridgeRelay = 0; + } dls.schedule = DL_SCHED_BRIDGE; + /* client */ mock_options->ClientOnly = 1; tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &bridge); - mock_options->ClientOnly = 0; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &bridge); done: + UNMOCK(networkstatus_consensus_is_bootstrapping); + UNMOCK(networkstatus_consensus_can_use_extra_fallbacks); UNMOCK(get_options); + free(mock_options); + mock_options = NULL; } -#define DIR_LEGACY(name) \ +#define DIR_LEGACY(name) \ { #name, test_dir_ ## name , TT_FORK, NULL, NULL } #define DIR(name,flags) \ { #name, test_dir_##name, (flags), NULL, NULL } +/* where arg is a string constant */ +#define DIR_ARG(name,flags,arg) \ + { #name "_" arg, test_dir_##name, (flags), &passthrough_setup, (void*) arg } + struct testcase_t dir_tests[] = { DIR_LEGACY(nicknames), DIR_LEGACY(formats), @@ -4081,7 +4251,10 @@ struct testcase_t dir_tests[] = { DIR(should_not_init_request_to_dir_auths_without_v3_info, 0), DIR(should_init_request_to_dir_auths, 0), DIR(choose_compression_level, 0), - DIR(find_dl_schedule, 0), + DIR_ARG(find_dl_schedule, TT_FORK, "bf"), + DIR_ARG(find_dl_schedule, TT_FORK, "ba"), + DIR_ARG(find_dl_schedule, TT_FORK, "cf"), + DIR_ARG(find_dl_schedule, TT_FORK, "ca"), END_OF_TESTCASES }; diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index 0c6530d4ff..3029e98e2f 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -1192,7 +1192,7 @@ test_dir_handle_get_server_keys_all(void* data) base16_decode(ds->v3_identity_digest, DIGEST_LEN, TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN); tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE, - TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1)); + TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL)); conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); @@ -1351,7 +1351,7 @@ test_dir_handle_get_server_keys_fp(void* data) TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN); tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE, - TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1)); + TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL)); conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); char req[71]; @@ -1423,7 +1423,7 @@ test_dir_handle_get_server_keys_sk(void* data) routerlist_free_all(); tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE, - TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1)); + TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL)); conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); char req[71]; @@ -1505,7 +1505,7 @@ test_dir_handle_get_server_keys_fpsk(void* data) dir_server_add(ds); tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE, - TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1)); + TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL)); conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); @@ -1561,7 +1561,7 @@ test_dir_handle_get_server_keys_busy(void* data) dir_server_add(ds); tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE, - TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1)); + TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL)); MOCK(get_options, mock_get_options); MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); @@ -2299,7 +2299,7 @@ test_dir_handle_get_status_vote_next_authority(void* data) base16_decode(ds->v3_identity_digest, DIGEST_LEN, TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN); tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE, - TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1)); + TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL)); init_mock_options(); mock_options->AuthoritativeDir = 1; @@ -2378,7 +2378,7 @@ test_dir_handle_get_status_vote_current_authority(void* data) TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN); tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE, - TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1)); + TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL)); init_mock_options(); mock_options->AuthoritativeDir = 1; diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 7db819a622..581f58b45f 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -483,7 +483,7 @@ test_md_generate(void *arg) md = dirvote_create_microdescriptor(ri, 21); tt_str_op(md->body, ==, test_md2_21); tt_assert(ed25519_pubkey_eq(md->ed25519_identity_pkey, - &ri->signing_key_cert->signing_key)); + &ri->cache_info.signing_key_cert->signing_key)); done: microdesc_free(md); diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c index 6df123162e..49c9ad76d4 100644 --- a/src/test/test_ntor_cl.c +++ b/src/test/test_ntor_cl.c @@ -153,7 +153,10 @@ main(int argc, char **argv) if (argc < 2) { fprintf(stderr, "I need arguments. Read source for more info.\n"); return 1; - } else if (!strcmp(argv[1], "client1")) { + } + + curve25519_init(); + if (!strcmp(argv[1], "client1")) { return client1(argc, argv); } else if (!strcmp(argv[1], "server1")) { return server1(argc, argv); diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 48e82551e3..a939ebf54f 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -716,10 +716,9 @@ test_policies_reject_exit_address(void *arg) } static smartlist_t *test_configured_ports = NULL; -const smartlist_t *mock_get_configured_ports(void); /** Returns test_configured_ports */ -const smartlist_t * +static const smartlist_t * mock_get_configured_ports(void) { return test_configured_ports; diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index 497606920d..2cffa6e801 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -15,6 +15,7 @@ #include "container.h" #include "directory.h" #include "dirvote.h" +#include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "policies.h" @@ -190,6 +191,14 @@ construct_consensus(char **consensus_text_md) crypto_pk_free(sign_skey_leg); } +static int mock_usable_consensus_flavor_value = FLAV_NS; + +static int +mock_usable_consensus_flavor(void) +{ + return mock_usable_consensus_flavor_value; +} + static void test_router_pick_directory_server_impl(void *arg) { @@ -209,6 +218,22 @@ test_router_pick_directory_server_impl(void *arg) (void)arg; + MOCK(usable_consensus_flavor, mock_usable_consensus_flavor); + + /* With no consensus, we must be bootstrapping, regardless of time or flavor + */ + mock_usable_consensus_flavor_value = FLAV_NS; + tt_assert(networkstatus_consensus_is_bootstrapping(now)); + tt_assert(networkstatus_consensus_is_bootstrapping(now + 2000)); + tt_assert(networkstatus_consensus_is_bootstrapping(now + 2*24*60*60)); + tt_assert(networkstatus_consensus_is_bootstrapping(now - 2*24*60*60)); + + mock_usable_consensus_flavor_value = FLAV_MICRODESC; + tt_assert(networkstatus_consensus_is_bootstrapping(now)); + tt_assert(networkstatus_consensus_is_bootstrapping(now + 2000)); + tt_assert(networkstatus_consensus_is_bootstrapping(now + 2*24*60*60)); + tt_assert(networkstatus_consensus_is_bootstrapping(now - 2*24*60*60)); + /* No consensus available, fail early */ rs = router_pick_directory_server_impl(V3_DIRINFO, (const int) 0, NULL); tt_assert(rs == NULL); @@ -223,6 +248,28 @@ test_router_pick_directory_server_impl(void *arg) tt_int_op(smartlist_len(con_md->routerstatus_list), ==, 3); tt_assert(!networkstatus_set_current_consensus_from_ns(con_md, "microdesc")); + + /* If the consensus time or flavor doesn't match, we are still + * bootstrapping */ + mock_usable_consensus_flavor_value = FLAV_NS; + tt_assert(networkstatus_consensus_is_bootstrapping(now)); + tt_assert(networkstatus_consensus_is_bootstrapping(now + 2000)); + tt_assert(networkstatus_consensus_is_bootstrapping(now + 2*24*60*60)); + tt_assert(networkstatus_consensus_is_bootstrapping(now - 2*24*60*60)); + + /* With a valid consensus for the current time and flavor, we stop + * bootstrapping, even if we have no certificates */ + mock_usable_consensus_flavor_value = FLAV_MICRODESC; + tt_assert(!networkstatus_consensus_is_bootstrapping(now + 2000)); + tt_assert(!networkstatus_consensus_is_bootstrapping(con_md->valid_after)); + tt_assert(!networkstatus_consensus_is_bootstrapping(con_md->valid_until)); + tt_assert(!networkstatus_consensus_is_bootstrapping(con_md->valid_until + + 24*60*60)); + /* These times are outside the test validity period */ + tt_assert(networkstatus_consensus_is_bootstrapping(now)); + tt_assert(networkstatus_consensus_is_bootstrapping(now + 2*24*60*60)); + tt_assert(networkstatus_consensus_is_bootstrapping(now - 2*24*60*60)); + nodelist_set_consensus(con_md); nodelist_assert_ok(); @@ -362,6 +409,7 @@ test_router_pick_directory_server_impl(void *arg) node_router1->rs->last_dir_503_at = 0; done: + UNMOCK(usable_consensus_flavor); if (router1_id) tor_free(router1_id); if (router2_id) diff --git a/src/test/test_util.c b/src/test/test_util.c index 21ff75741a..2726c31fe8 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -4223,21 +4223,6 @@ test_util_round_to_next_multiple_of(void *arg) tt_u64_op(round_uint64_to_next_multiple_of(UINT64_MAX,2), ==, UINT64_MAX); - tt_i64_op(round_int64_to_next_multiple_of(0,1), ==, 0); - tt_i64_op(round_int64_to_next_multiple_of(0,7), ==, 0); - - tt_i64_op(round_int64_to_next_multiple_of(99,1), ==, 99); - tt_i64_op(round_int64_to_next_multiple_of(99,7), ==, 105); - tt_i64_op(round_int64_to_next_multiple_of(99,9), ==, 99); - - tt_i64_op(round_int64_to_next_multiple_of(-99,1), ==, -99); - tt_i64_op(round_int64_to_next_multiple_of(-99,7), ==, -98); - tt_i64_op(round_int64_to_next_multiple_of(-99,9), ==, -99); - - tt_i64_op(round_int64_to_next_multiple_of(INT64_MIN,2), ==, INT64_MIN); - tt_i64_op(round_int64_to_next_multiple_of(INT64_MAX,2), ==, - INT64_MAX); - tt_int_op(round_uint32_to_next_multiple_of(0,1), ==, 0); tt_int_op(round_uint32_to_next_multiple_of(0,7), ==, 0); @@ -4819,7 +4804,7 @@ struct testcase_t util_tests[] = { UTIL_LEGACY(memarea), UTIL_LEGACY(control_formats), UTIL_LEGACY(mmap), - UTIL_LEGACY(sscanf), + UTIL_TEST(sscanf, TT_FORK), UTIL_LEGACY(format_time_interval), UTIL_LEGACY(path_is_relative), UTIL_LEGACY(strtok), diff --git a/src/test/testing_common.c b/src/test/testing_common.c index aeb1fa794d..39c3d02ab1 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -242,6 +242,8 @@ main(int c, const char **v) options = options_new(); tor_threads_init(); + network_init(); + struct tor_libevent_cfg cfg; memset(&cfg, 0, sizeof(cfg)); tor_libevent_initialize(&cfg); @@ -284,7 +286,6 @@ main(int c, const char **v) return 1; } rep_hist_init(); - network_init(); setup_directory(); options_init(options); options->DataDirectory = tor_strdup(temp_dir); |