diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/include.am | 31 | ||||
-rw-r--r-- | src/test/log_test_helpers.c | 111 | ||||
-rw-r--r-- | src/test/log_test_helpers.h | 31 | ||||
-rw-r--r-- | src/test/rend_test_helpers.c | 66 | ||||
-rw-r--r-- | src/test/rend_test_helpers.h | 15 | ||||
-rw-r--r-- | src/test/test.c | 13 | ||||
-rw-r--r-- | src/test/test_address.c | 325 | ||||
-rwxr-xr-x | src/test/test_bt.sh | 10 | ||||
-rw-r--r-- | src/test/test_bt.sh.in | 9 | ||||
-rw-r--r-- | src/test/test_bt_cl.c | 11 | ||||
-rw-r--r-- | src/test/test_compat_libevent.c | 238 | ||||
-rw-r--r-- | src/test/test_crypto_slow.c | 2 | ||||
-rw-r--r-- | src/test/test_dir_handle_get.c | 2533 | ||||
-rw-r--r-- | src/test/test_keypin.c | 13 | ||||
-rwxr-xr-x | src/test/test_ntor.sh | 9 | ||||
-rw-r--r-- | src/test/test_ntor.sh.in | 9 | ||||
-rw-r--r-- | src/test/test_policy.c | 192 | ||||
-rw-r--r-- | src/test/test_routerset.c | 109 | ||||
-rw-r--r-- | src/test/test_tortls.c | 2950 | ||||
-rw-r--r-- | src/test/test_util_format.c | 76 | ||||
-rwxr-xr-x | src/test/test_zero_length_keys.sh | 10 | ||||
-rw-r--r-- | src/test/test_zero_length_keys.sh.in | 10 | ||||
-rw-r--r-- | src/test/vote_descriptors.inc | 94 |
23 files changed, 6751 insertions, 116 deletions
diff --git a/src/test/include.am b/src/test/include.am index 762216e6dc..e056138b48 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -1,4 +1,9 @@ +export PYTHON=@PYTHON@ +export SHELL=@SHELL@ +export abs_top_srcdir=@abs_top_srcdir@ +export builddir=@builddir@ + TESTSCRIPTS = src/test/test_zero_length_keys.sh if USEPYTHON @@ -16,18 +21,11 @@ TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min TEST_CHUTNEY_FLAVORS_MIXED = mixed ### This is a lovely feature, but it requires automake >= 1.12, and Tor -### doesn't require that yet. Below is a kludge to work around. +### doesn't require that yet. ### # TEST_EXTENSIONS = .sh # SH_LOG_COMPILER = $(SHELL) -check-am: set-test-permissions - -.PHONY: set-test-permissions -set-test-permissions: $(TESTSCRIPTS) - $(AM_V_at)chmod u+x $(TESTSCRIPTS) - - noinst_PROGRAMS+= src/test/bench if UNITTESTS_ENABLED noinst_PROGRAMS+= \ @@ -51,6 +49,7 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ # matters a lot there, and is quite hard to debug if you forget to do it. src_test_test_SOURCES = \ + src/test/log_test_helpers.c \ src/test/test.c \ src/test/test_accounting.c \ src/test/test_addr.c \ @@ -63,6 +62,7 @@ src_test_test_SOURCES = \ src/test/test_checkdir.c \ src/test/test_circuitlist.c \ src/test/test_circuitmux.c \ + src/test/test_compat_libevent.c \ src/test/test_config.c \ src/test/test_containers.c \ src/test/test_controller.c \ @@ -70,6 +70,7 @@ src_test_test_SOURCES = \ src/test/test_crypto.c \ src/test/test_data.c \ src/test/test_dir.c \ + src/test/test_dir_handle_get.c \ src/test/test_entryconn.c \ src/test/test_entrynodes.c \ src/test/test_guardfraction.c \ @@ -95,10 +96,12 @@ src_test_test_SOURCES = \ src/test/test_socks.c \ src/test/test_status.c \ src/test/test_threads.c \ + src/test/test_tortls.c \ src/test/test_util.c \ src/test/test_util_format.c \ src/test/test_helpers.c \ - src/test/test_dns.c \ + src/test/rend_test_helpers.c \ + src/test/test_dns.c \ src/test/testing_common.c \ src/ext/tinytest.c @@ -164,13 +167,16 @@ src_test_test_workqueue_LDADD = src/or/libtor-testing.a \ noinst_HEADERS+= \ src/test/fakechans.h \ + src/test/log_test_helpers.h \ + src/test/rend_test_helpers.h \ src/test/test.h \ src/test/test_helpers.h \ src/test/test_descriptors.inc \ src/test/example_extrainfo.inc \ src/test/failing_routerdescs.inc \ src/test/ed25519_vectors.inc \ - src/test/test_descriptors.inc + src/test/test_descriptors.inc \ + src/test/vote_descriptors.inc noinst_PROGRAMS+= src/test/test-ntor-cl src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c @@ -195,4 +201,7 @@ EXTRA_DIST += \ src/test/ntor_ref.py \ src/test/slownacl_curve25519.py \ src/test/zero_length_keys.sh \ - src/test/test_keygen.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-network.sh diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c new file mode 100644 index 0000000000..51b5f9b7b1 --- /dev/null +++ b/src/test/log_test_helpers.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2015, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ +#define LOG_PRIVATE +#include "torlog.h" +#include "log_test_helpers.h" + +static smartlist_t *saved_logs = NULL; + +int +setup_capture_of_logs(int new_level) +{ + int previous_log = log_global_min_severity_; + log_global_min_severity_ = new_level; + mock_clean_saved_logs(); + MOCK(logv, mock_saving_logv); + return previous_log; +} + +void +teardown_capture_of_logs(int prev) +{ + UNMOCK(logv); + log_global_min_severity_ = prev; + mock_clean_saved_logs(); +} + +void +mock_clean_saved_logs(void) +{ + if (!saved_logs) + return; + SMARTLIST_FOREACH(saved_logs, mock_saved_log_entry_t *, m, + { tor_free(m->generated_msg); tor_free(m); }); + smartlist_free(saved_logs); + saved_logs = NULL; +} + +static mock_saved_log_entry_t * +mock_get_log_entry(int ix) +{ + int saved_log_count = mock_saved_log_number(); + if (ix < 0) { + ix = saved_log_count + ix; + } + + if (saved_log_count <= ix) + return NULL; + + return smartlist_get(saved_logs, ix); +} + +const char * +mock_saved_log_at(int ix) +{ + mock_saved_log_entry_t *ent = mock_get_log_entry(ix); + if (ent) + return ent->generated_msg; + else + return ""; +} + +int +mock_saved_severity_at(int ix) +{ + mock_saved_log_entry_t *ent = mock_get_log_entry(ix); + if (ent) + return ent->severity; + else + return -1; +} + +int +mock_saved_log_number(void) +{ + if (!saved_logs) + return 0; + return smartlist_len(saved_logs); +} + +const smartlist_t * +mock_saved_logs(void) +{ + return saved_logs; +} + +void +mock_saving_logv(int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, + const char *format, va_list ap) +{ + (void)domain; + char *buf = tor_malloc_zero(10240); + int n; + n = tor_vsnprintf(buf,10240,format,ap); + tor_assert(n < 10240-1); + buf[n]='\n'; + buf[n+1]='\0'; + + mock_saved_log_entry_t *e = tor_malloc_zero(sizeof(mock_saved_log_entry_t)); + e->severity = severity; + e->funcname = funcname; + e->suffix = suffix; + e->format = format; + e->generated_msg = tor_strdup(buf); + tor_free(buf); + + if (!saved_logs) + saved_logs = smartlist_new(); + smartlist_add(saved_logs, e); +} + diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h new file mode 100644 index 0000000000..af8e8a60e7 --- /dev/null +++ b/src/test/log_test_helpers.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2014-2015, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" + +#ifndef TOR_LOG_TEST_HELPERS_H +#define TOR_LOG_TEST_HELPERS_H + +typedef struct mock_saved_log_entry_t { + int severity; + const char *funcname; + const char *suffix; + const char *format; + char *generated_msg; + struct mock_saved_log_entry_t *next; +} mock_saved_log_entry_t; + +void mock_saving_logv(int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, + const char *format, va_list ap) + CHECK_PRINTF(5, 0); +void mock_clean_saved_logs(void); +const smartlist_t *mock_saved_logs(void); +int setup_capture_of_logs(int new_level); +void teardown_capture_of_logs(int prev); +const char *mock_saved_log_at(int ix); +int mock_saved_severity_at(int ix); +int mock_saved_log_number(void); + +#endif + diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c new file mode 100644 index 0000000000..0a1b1c8967 --- /dev/null +++ b/src/test/rend_test_helpers.c @@ -0,0 +1,66 @@ +#include "rend_test_helpers.h" + +#include "test.h" +#include "rendcommon.h" + +void +generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc, + char **service_id, int intro_points) +{ + rend_service_descriptor_t *generated = NULL; + smartlist_t *descs = smartlist_new(); + time_t now; + + now = time(NULL) + time_diff; + create_descriptor(&generated, service_id, intro_points); + generated->timestamp = now; + + rend_encode_v2_descriptors(descs, generated, now, 0, REND_NO_AUTH, NULL, + NULL); + *desc = ((rend_encoded_v2_service_descriptor_t *)smartlist_get(descs, 0)); + + smartlist_free(descs); + rend_service_descriptor_free(generated); +} + +void +create_descriptor(rend_service_descriptor_t **generated, char **service_id, + int intro_points) +{ + crypto_pk_t *pk1 = NULL; + crypto_pk_t *pk2 = NULL; + int i; + + *service_id = tor_malloc(REND_SERVICE_ID_LEN_BASE32+1); + pk1 = pk_generate(0); + pk2 = pk_generate(1); + + *generated = tor_malloc_zero(sizeof(rend_service_descriptor_t)); + (*generated)->pk = crypto_pk_dup_key(pk1); + rend_get_service_id((*generated)->pk, *service_id); + + (*generated)->version = 2; + (*generated)->protocols = 42; + (*generated)->intro_nodes = smartlist_new(); + + for (i = 0; i < intro_points; i++) { + rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t)); + crypto_pk_t *okey = pk_generate(2 + i); + intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); + intro->extend_info->onion_key = okey; + crypto_pk_get_digest(intro->extend_info->onion_key, + intro->extend_info->identity_digest); + intro->extend_info->nickname[0] = '$'; + base16_encode(intro->extend_info->nickname + 1, + sizeof(intro->extend_info->nickname) - 1, + intro->extend_info->identity_digest, DIGEST_LEN); + tor_addr_from_ipv4h(&intro->extend_info->addr, crypto_rand_int(65536)); + intro->extend_info->port = 1 + crypto_rand_int(65535); + intro->intro_key = crypto_pk_dup_key(pk2); + smartlist_add((*generated)->intro_nodes, intro); + } + + crypto_pk_free(pk1); + crypto_pk_free(pk2); +} + diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h new file mode 100644 index 0000000000..1ef03747d7 --- /dev/null +++ b/src/test/rend_test_helpers.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2014-2015, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" + +#ifndef TOR_REND_TEST_HELPERS_H +#define TOR_REND_TEST_HELPERS_H + +void generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc, + char **service_id, int intro_points); +void create_descriptor(rend_service_descriptor_t **generated, + char **service_id, int intro_points); + +#endif + diff --git a/src/test/test.c b/src/test/test.c index aff7d8e048..d8aca276e7 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -47,6 +47,7 @@ double fabs(double x); #include "connection_edge.h" #include "geoip.h" #include "rendcommon.h" +#include "rendcache.h" #include "test.h" #include "torgzip.h" #include "memarea.h" @@ -494,6 +495,9 @@ test_rend_fns(void *arg) tt_str_op(address6,OP_EQ, "abcdefghijklmnop"); tt_assert(BAD_HOSTNAME == parse_extended_hostname(address7)); + /* Initialize the service cache. */ + rend_cache_init(); + pk1 = pk_generate(0); pk2 = pk_generate(1); generated = tor_malloc_zero(sizeof(rend_service_descriptor_t)); @@ -1106,7 +1110,7 @@ static struct testcase_t test_array[] = { ENT(onion_queues), { "ntor_handshake", test_ntor_handshake, 0, NULL, NULL }, ENT(circuit_timeout), - ENT(rend_fns), + FORK(rend_fns), ENT(geoip), FORK(geoip_with_pt), FORK(stats), @@ -1125,12 +1129,14 @@ extern struct testcase_t channeltls_tests[]; extern struct testcase_t checkdir_tests[]; extern struct testcase_t circuitlist_tests[]; extern struct testcase_t circuitmux_tests[]; +extern struct testcase_t compat_libevent_tests[]; extern struct testcase_t config_tests[]; extern struct testcase_t container_tests[]; extern struct testcase_t controller_tests[]; extern struct testcase_t controller_event_tests[]; extern struct testcase_t crypto_tests[]; extern struct testcase_t dir_tests[]; +extern struct testcase_t dir_handle_get_tests[]; extern struct testcase_t entryconn_tests[]; extern struct testcase_t entrynodes_tests[]; extern struct testcase_t guardfraction_tests[]; @@ -1157,6 +1163,7 @@ extern struct testcase_t scheduler_tests[]; extern struct testcase_t socks_tests[]; extern struct testcase_t status_tests[]; extern struct testcase_t thread_tests[]; +extern struct testcase_t tortls_tests[]; extern struct testcase_t util_tests[]; extern struct testcase_t util_format_tests[]; extern struct testcase_t dns_tests[]; @@ -1174,12 +1181,14 @@ struct testgroup_t testgroups[] = { { "checkdir/", checkdir_tests }, { "circuitlist/", circuitlist_tests }, { "circuitmux/", circuitmux_tests }, + { "compat/libevent/", compat_libevent_tests }, { "config/", config_tests }, { "container/", container_tests }, { "control/", controller_tests }, { "control/event/", controller_event_tests }, { "crypto/", crypto_tests }, { "dir/", dir_tests }, + { "dir_handle_get/", dir_handle_get_tests }, { "dir/md/", microdesc_tests }, { "entryconn/", entryconn_tests }, { "entrynodes/", entrynodes_tests }, @@ -1203,6 +1212,7 @@ struct testgroup_t testgroups[] = { { "scheduler/", scheduler_tests }, { "socks/", socks_tests }, { "status/" , status_tests }, + { "tortls/", tortls_tests }, { "util/", util_tests }, { "util/format/", util_format_tests }, { "util/logging/", logging_tests }, @@ -1210,3 +1220,4 @@ struct testgroup_t testgroups[] = { { "dns/", dns_tests }, END_OF_GROUPS }; + diff --git a/src/test/test_address.c b/src/test/test_address.c index 9d6456315c..e48c06a6c4 100644 --- a/src/test/test_address.c +++ b/src/test/test_address.c @@ -74,35 +74,79 @@ sockaddr_in_from_string(const char *ip_str, struct sockaddr_in *out) } /** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure - * that points to 127.0.0.1. Otherwise, return 0. + * that is an IPv4 or IPv6 localhost address. Otherwise, return 0. */ static int smartlist_contains_localhost_tor_addr(smartlist_t *smartlist) { - int found_localhost = 0; + SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { + if (tor_addr_is_loopback(tor_addr)) { + return 1; + } + } SMARTLIST_FOREACH_END(tor_addr); - struct sockaddr_in *sockaddr_localhost; - struct sockaddr_storage *sockaddr_to_check; + return 0; +} - sockaddr_localhost = sockaddr_in_from_string("127.0.0.1",NULL); +/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure + * that is an IPv4 or IPv6 multicast address. Otherwise, return 0. + */ +static int +smartlist_contains_multicast_tor_addr(smartlist_t *smartlist) +{ + SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { + if (tor_addr_is_multicast(tor_addr)) { + return 1; + } + } SMARTLIST_FOREACH_END(tor_addr); - sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in)); + return 0; +} +/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure + * that is an IPv4 or IPv6 internal address. Otherwise, return 0. + */ +static int +smartlist_contains_internal_tor_addr(smartlist_t *smartlist) +{ SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { - tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check, - sizeof(struct sockaddr_in)); + if (tor_addr_is_internal(tor_addr, 0)) { + return 1; + } + } SMARTLIST_FOREACH_END(tor_addr); + + return 0; +} - if (sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check, - sockaddr_localhost)) { - found_localhost = 1; - break; +/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure + * that is an IPv4 address. Otherwise, return 0. + */ +static int +smartlist_contains_ipv4_tor_addr(smartlist_t *smartlist) +{ + SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { + if (tor_addr_is_v4(tor_addr)) { + return 1; } } SMARTLIST_FOREACH_END(tor_addr); - tor_free(sockaddr_localhost); - tor_free(sockaddr_to_check); + return 0; +} + +/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure + * that is an IPv6 address. Otherwise, return 0. + */ +static int +smartlist_contains_ipv6_tor_addr(smartlist_t *smartlist) +{ + SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { + /* Since there's no tor_addr_is_v6, assume all non-v4s are v6 */ + if (!tor_addr_is_v4(tor_addr)) { + return 1; + } + } SMARTLIST_FOREACH_END(tor_addr); - return found_localhost; + return 0; } #ifdef HAVE_IFADDRS_TO_SMARTLIST @@ -634,12 +678,263 @@ test_address_udp_socket_trick_blackbox(void *arg) return; } +static void +test_address_get_if_addrs_list_internal(void *arg) +{ + smartlist_t *results = NULL; + + (void)arg; + + results = get_interface_address_list(LOG_ERR, 1); + + tt_assert(results != NULL); + /* Assume every system has at least 1 non-local non-multicast IPv4 + * interface, even if it is an internal one */ + tt_int_op(smartlist_len(results),>=,1); + + tt_assert(!smartlist_contains_localhost_tor_addr(results)); + tt_assert(!smartlist_contains_multicast_tor_addr(results)); + /* The list may or may not contain internal addresses */ + + tt_assert(smartlist_contains_ipv4_tor_addr(results)); + tt_assert(!smartlist_contains_ipv6_tor_addr(results)); + + done: + free_interface_address_list(results); + return; +} + +static void +test_address_get_if_addrs_list_no_internal(void *arg) +{ + smartlist_t *results = NULL; + + (void)arg; + + results = get_interface_address_list(LOG_ERR, 0); + + tt_assert(results != NULL); + /* Work even on systems with only internal IPv4 addresses */ + tt_int_op(smartlist_len(results),>=,0); + + tt_assert(!smartlist_contains_localhost_tor_addr(results)); + tt_assert(!smartlist_contains_multicast_tor_addr(results)); + tt_assert(!smartlist_contains_internal_tor_addr(results)); + + /* The list may or may not contain IPv4 addresses */ + tt_assert(!smartlist_contains_ipv6_tor_addr(results)); + + done: + free_interface_address_list(results); + return; +} + +static void +test_address_get_if_addrs6_list_internal(void *arg) +{ + smartlist_t *results = NULL; + + (void)arg; + + results = get_interface_address6_list(LOG_ERR, AF_INET6, 1); + + tt_assert(results != NULL); + /* Work even on systems without IPv6 interfaces */ + tt_int_op(smartlist_len(results),>=,0); + + tt_assert(!smartlist_contains_localhost_tor_addr(results)); + tt_assert(!smartlist_contains_multicast_tor_addr(results)); + /* The list may or may not contain internal addresses */ + + tt_assert(!smartlist_contains_ipv4_tor_addr(results)); + /* The list may or may not contain IPv6 addresses */ + + done: + free_interface_address6_list(results); + return; +} + +static void +test_address_get_if_addrs6_list_no_internal(void *arg) +{ + smartlist_t *results = NULL; + + (void)arg; + + results = get_interface_address6_list(LOG_ERR, AF_INET6, 0); + + tt_assert(results != NULL); + /* Work even on systems without IPv6 interfaces */ + tt_int_op(smartlist_len(results),>=,0); + + tt_assert(!smartlist_contains_localhost_tor_addr(results)); + tt_assert(!smartlist_contains_multicast_tor_addr(results)); + tt_assert(!smartlist_contains_internal_tor_addr(results)); + + tt_assert(!smartlist_contains_ipv4_tor_addr(results)); + /* The list may or may not contain IPv6 addresses */ + + done: + free_interface_address6_list(results); + return; +} + +static int called_get_interface_addresses_raw = 0; + +static smartlist_t * +mock_get_interface_addresses_raw_fail(int severity) +{ + (void)severity; + + called_get_interface_addresses_raw++; + return smartlist_new(); +} + +static int called_get_interface_address6_via_udp_socket_hack = 0; + +static int +mock_get_interface_address6_via_udp_socket_hack_fail(int severity, + sa_family_t family, + tor_addr_t *addr) +{ + (void)severity; + (void)family; + (void)addr; + + called_get_interface_address6_via_udp_socket_hack++; + return -1; +} + +static void +test_address_get_if_addrs_internal_fail(void *arg) +{ + smartlist_t *results1 = NULL, *results2 = NULL; + int rv = 0; + uint32_t ipv4h_addr = 0; + tor_addr_t ipv6_addr; + + memset(&ipv6_addr, 0, sizeof(tor_addr_t)); + + (void)arg; + + MOCK(get_interface_addresses_raw, + mock_get_interface_addresses_raw_fail); + MOCK(get_interface_address6_via_udp_socket_hack, + mock_get_interface_address6_via_udp_socket_hack_fail); + + results1 = get_interface_address6_list(LOG_ERR, AF_INET6, 1); + tt_assert(results1 != NULL); + tt_int_op(smartlist_len(results1),==,0); + + results2 = get_interface_address_list(LOG_ERR, 1); + tt_assert(results2 != NULL); + tt_int_op(smartlist_len(results2),==,0); + + rv = get_interface_address6(LOG_ERR, AF_INET6, &ipv6_addr); + tt_assert(rv == -1); + + rv = get_interface_address(LOG_ERR, &ipv4h_addr); + tt_assert(rv == -1); + + done: + UNMOCK(get_interface_addresses_raw); + UNMOCK(get_interface_address6_via_udp_socket_hack); + free_interface_address6_list(results1); + free_interface_address6_list(results2); + return; +} + +static void +test_address_get_if_addrs_no_internal_fail(void *arg) +{ + smartlist_t *results1 = NULL, *results2 = NULL; + + (void)arg; + + MOCK(get_interface_addresses_raw, + mock_get_interface_addresses_raw_fail); + MOCK(get_interface_address6_via_udp_socket_hack, + mock_get_interface_address6_via_udp_socket_hack_fail); + + results1 = get_interface_address6_list(LOG_ERR, AF_INET6, 0); + tt_assert(results1 != NULL); + tt_int_op(smartlist_len(results1),==,0); + + results2 = get_interface_address_list(LOG_ERR, 0); + tt_assert(results2 != NULL); + tt_int_op(smartlist_len(results2),==,0); + + done: + UNMOCK(get_interface_addresses_raw); + UNMOCK(get_interface_address6_via_udp_socket_hack); + free_interface_address6_list(results1); + free_interface_address6_list(results2); + return; +} + +static void +test_address_get_if_addrs(void *arg) +{ + int rv; + uint32_t addr_h = 0; + tor_addr_t tor_addr; + + (void)arg; + + rv = get_interface_address(LOG_ERR, &addr_h); + + /* Assume every system has at least 1 non-local non-multicast IPv4 + * interface, even if it is an internal one */ + tt_assert(rv == 0); + tor_addr_from_ipv4h(&tor_addr, addr_h); + + tt_assert(!tor_addr_is_loopback(&tor_addr)); + tt_assert(!tor_addr_is_multicast(&tor_addr)); + /* The address may or may not be an internal address */ + + tt_assert(tor_addr_is_v4(&tor_addr)); + + done: + return; +} + +static void +test_address_get_if_addrs6(void *arg) +{ + int rv; + tor_addr_t tor_addr; + + (void)arg; + + rv = get_interface_address6(LOG_ERR, AF_INET6, &tor_addr); + + /* Work even on systems without IPv6 interfaces */ + if (rv == 0) { + tt_assert(!tor_addr_is_loopback(&tor_addr)); + tt_assert(!tor_addr_is_multicast(&tor_addr)); + /* The address may or may not be an internal address */ + + tt_assert(!tor_addr_is_v4(&tor_addr)); + } + + done: + return; +} + #define ADDRESS_TEST(name, flags) \ { #name, test_address_ ## name, flags, NULL, NULL } struct testcase_t address_tests[] = { ADDRESS_TEST(udp_socket_trick_whitebox, TT_FORK), ADDRESS_TEST(udp_socket_trick_blackbox, TT_FORK), + ADDRESS_TEST(get_if_addrs_list_internal, 0), + ADDRESS_TEST(get_if_addrs_list_no_internal, 0), + ADDRESS_TEST(get_if_addrs6_list_internal, 0), + ADDRESS_TEST(get_if_addrs6_list_no_internal, 0), + ADDRESS_TEST(get_if_addrs_internal_fail, 0), + ADDRESS_TEST(get_if_addrs_no_internal_fail, 0), + ADDRESS_TEST(get_if_addrs, 0), + ADDRESS_TEST(get_if_addrs6, 0), #ifdef HAVE_IFADDRS_TO_SMARTLIST ADDRESS_TEST(get_if_addrs_ifaddrs, TT_FORK), ADDRESS_TEST(ifaddrs_to_smartlist, 0), diff --git a/src/test/test_bt.sh b/src/test/test_bt.sh new file mode 100755 index 0000000000..f55f451f92 --- /dev/null +++ b/src/test/test_bt.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Test backtrace functionality. + +exitcode=0 + +"${builddir:-.}/src/test/test-bt-cl" backtraces || exit 77 +"${builddir:-.}/src/test/test-bt-cl" assert | "${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/bt_test.py" || exitcode=1 +"${builddir:-.}/src/test/test-bt-cl" crash | "${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/bt_test.py" || exitcode=1 + +exit ${exitcode} diff --git a/src/test/test_bt.sh.in b/src/test/test_bt.sh.in deleted file mode 100644 index ca8be965d4..0000000000 --- a/src/test/test_bt.sh.in +++ /dev/null @@ -1,9 +0,0 @@ -#!@SHELL@ -# Test backtrace functionality. - -exitcode=0 - -@builddir@/src/test/test-bt-cl assert | @PYTHON@ @abs_top_srcdir@/src/test/bt_test.py || exitcode=1 -@builddir@/src/test/test-bt-cl crash | @PYTHON@ @abs_top_srcdir@/src/test/bt_test.py || exitcode=1 - -exit ${exitcode} diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c index 01c621eb0e..dabaee6e0a 100644 --- a/src/test/test_bt_cl.c +++ b/src/test/test_bt_cl.c @@ -84,15 +84,24 @@ main(int argc, char **argv) if (argc < 2) { puts("I take an argument. It should be \"assert\" or \"crash\" or " - "\"none\""); + "\"backtraces\" or \"none\""); return 1; } + +#if !(defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ + defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)) + puts("Backtrace reporting is not supported on this platform"); + return 77; +#endif + if (!strcmp(argv[1], "assert")) { crashtype = 1; } else if (!strcmp(argv[1], "crash")) { crashtype = 0; } else if (!strcmp(argv[1], "none")) { crashtype = -1; + } else if (!strcmp(argv[1], "backtraces")) { + return 0; } else { puts("Argument should be \"assert\" or \"crash\" or \"none\""); return 1; diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c new file mode 100644 index 0000000000..96502df308 --- /dev/null +++ b/src/test/test_compat_libevent.c @@ -0,0 +1,238 @@ +/* Copyright (c) 2010-2015, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define COMPAT_LIBEVENT_PRIVATE +#include "orconfig.h" +#include "or.h" + +#include "test.h" + +#include "compat_libevent.h" + +#ifdef HAVE_EVENT2_EVENT_H +#include <event2/event.h> +#include <event2/thread.h> +#ifdef USE_BUFFEREVENTS +#include <event2/bufferevent.h> +#endif +#else +#include <event.h> +#endif + +#include "log_test_helpers.h" + +#define NS_MODULE compat_libevent + +static void +test_compat_libevent_logging_callback(void *ignored) +{ + (void)ignored; + int previous_log = setup_capture_of_logs(LOG_DEBUG); + + libevent_logging_callback(_EVENT_LOG_DEBUG, "hello world"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, + "Message from libevent: hello world\n"); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_DEBUG); + + mock_clean_saved_logs(); + libevent_logging_callback(_EVENT_LOG_MSG, "hello world another time"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, + "Message from libevent: hello world another time\n"); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + + mock_clean_saved_logs(); + libevent_logging_callback(_EVENT_LOG_WARN, "hello world a third time"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, + "Warning from libevent: hello world a third time\n"); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_WARN); + + mock_clean_saved_logs(); + libevent_logging_callback(_EVENT_LOG_ERR, "hello world a fourth time"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, + "Error from libevent: hello world a fourth time\n"); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_ERR); + + mock_clean_saved_logs(); + libevent_logging_callback(42, "hello world a fifth time"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, + "Message [42] from libevent: hello world a fifth time\n"); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_WARN); + + mock_clean_saved_logs(); + libevent_logging_callback(_EVENT_LOG_DEBUG, + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + ); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "Message from libevent: " + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789" + "012345678901234567890123456789\n"); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_DEBUG); + + mock_clean_saved_logs(); + libevent_logging_callback(42, "xxx\n"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "Message [42] from libevent: xxx\n"); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_WARN); + + suppress_libevent_log_msg("something"); + mock_clean_saved_logs(); + libevent_logging_callback(_EVENT_LOG_MSG, "hello there"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, + "Message from libevent: hello there\n"); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + + mock_clean_saved_logs(); + libevent_logging_callback(_EVENT_LOG_MSG, "hello there something else"); + tt_int_op(mock_saved_log_number(), OP_EQ, 0); + + // No way of verifying the result of this, it seems =/ + configure_libevent_logging(); + + done: + suppress_libevent_log_msg(NULL); + teardown_capture_of_logs(previous_log); +} + +static void +test_compat_libevent_le_versions_compatibility(void *ignored) +{ + (void)ignored; + int res; + + res = le_versions_compatibility(LE_OTHER); + tt_int_op(res, OP_EQ, 0); + + res = le_versions_compatibility(V_OLD(0,9,'c')); + tt_int_op(res, OP_EQ, 1); + + res = le_versions_compatibility(V(1,3,98)); + tt_int_op(res, OP_EQ, 2); + + res = le_versions_compatibility(V(1,4,98)); + tt_int_op(res, OP_EQ, 3); + + res = le_versions_compatibility(V(1,5,0)); + tt_int_op(res, OP_EQ, 4); + + res = le_versions_compatibility(V(2,0,0)); + tt_int_op(res, OP_EQ, 4); + + res = le_versions_compatibility(V(2,0,2)); + tt_int_op(res, OP_EQ, 5); + + done: + (void)0; +} + +static void +test_compat_libevent_tor_decode_libevent_version(void *ignored) +{ + (void)ignored; + le_version_t res; + + res = tor_decode_libevent_version("SOMETHING WRONG"); + tt_int_op(res, OP_EQ, LE_OTHER); + + res = tor_decode_libevent_version("1.4.11"); + tt_int_op(res, OP_EQ, V(1,4,11)); + + res = tor_decode_libevent_version("1.4.12b-stable"); + tt_int_op(res, OP_EQ, V(1,4,12)); + + res = tor_decode_libevent_version("1.4.17b_stable"); + tt_int_op(res, OP_EQ, V(1,4,17)); + + res = tor_decode_libevent_version("1.4.12!stable"); + tt_int_op(res, OP_EQ, LE_OTHER); + + res = tor_decode_libevent_version("1.4.12b!stable"); + tt_int_op(res, OP_EQ, LE_OTHER); + + res = tor_decode_libevent_version("1.4.13-"); + tt_int_op(res, OP_EQ, V(1,4,13)); + + res = tor_decode_libevent_version("1.4.14_"); + tt_int_op(res, OP_EQ, V(1,4,14)); + + res = tor_decode_libevent_version("1.4.15c-"); + tt_int_op(res, OP_EQ, V(1,4,15)); + + res = tor_decode_libevent_version("1.4.16c_"); + tt_int_op(res, OP_EQ, V(1,4,16)); + + res = tor_decode_libevent_version("1.4.17-s"); + tt_int_op(res, OP_EQ, V(1,4,17)); + + res = tor_decode_libevent_version("1.5"); + tt_int_op(res, OP_EQ, V(1,5,0)); + + res = tor_decode_libevent_version("1.2"); + tt_int_op(res, OP_EQ, V(1,2,0)); + + res = tor_decode_libevent_version("1.2-"); + tt_int_op(res, OP_EQ, LE_OTHER); + + res = tor_decode_libevent_version("1.6e"); + tt_int_op(res, OP_EQ, V_OLD(1,6,'e')); + + done: + (void)0; +} + +#if defined(LIBEVENT_VERSION) +#define HEADER_VERSION LIBEVENT_VERSION +#elif defined(_EVENT_VERSION) +#define HEADER_VERSION _EVENT_VERSION +#endif + +static void +test_compat_libevent_header_version(void *ignored) +{ + (void)ignored; + const char *res; + + res = tor_libevent_get_header_version_str(); + tt_str_op(res, OP_EQ, HEADER_VERSION); + + done: + (void)0; +} + +struct testcase_t compat_libevent_tests[] = { + { "logging_callback", test_compat_libevent_logging_callback, + TT_FORK, NULL, NULL }, + { "le_versions_compatibility", + test_compat_libevent_le_versions_compatibility, 0, NULL, NULL }, + { "tor_decode_libevent_version", + test_compat_libevent_tor_decode_libevent_version, 0, NULL, NULL }, + { "header_version", test_compat_libevent_header_version, 0, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c index d0f50f83b9..853a08d886 100644 --- a/src/test/test_crypto_slow.c +++ b/src/test/test_crypto_slow.c @@ -217,7 +217,7 @@ test_libscrypt_eq_openssl(void *arg) memset(buf2,0,64); N = 1048576; - maxmem = 2 * 1024 * 1024 * 1024; // 2 GB + maxmem = 2 * 1024 * 1024 * (uint64_t)1024; // 2 GB libscrypt_retval = libscrypt_scrypt((const uint8_t *)"pleaseletmein", diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c new file mode 100644 index 0000000000..5a84f17c12 --- /dev/null +++ b/src/test/test_dir_handle_get.c @@ -0,0 +1,2533 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2015, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define RENDCOMMON_PRIVATE +#define GEOIP_PRIVATE + +#include "or.h" +#include "config.h" +#include "directory.h" +#include "test.h" +#include "connection.h" +#include "rendcommon.h" +#include "rendcache.h" +#include "router.h" +#include "routerlist.h" +#include "rend_test_helpers.h" +#include "microdesc.h" +#include "test_helpers.h" +#include "nodelist.h" +#include "entrynodes.h" +#include "routerparse.h" +#include "networkstatus.h" +#include "geoip.h" +#include "dirserv.h" +#include "torgzip.h" +#include "dirvote.h" + +#ifdef _WIN32 +/* For mkdir() */ +#include <direct.h> +#else +#include <dirent.h> +#endif + +#include "vote_descriptors.inc" + +#define NS_MODULE dir_handle_get + +static void +connection_write_to_buf_mock(const char *string, size_t len, + connection_t *conn, int zlib) +{ + (void) zlib; + + tor_assert(string); + tor_assert(conn); + + write_to_buf(string, len, conn->outbuf); +} + +#define GET(path) "GET " path " HTTP/1.0\r\n\r\n" +#define NOT_FOUND "HTTP/1.0 404 Not found\r\n\r\n" +#define BAD_REQUEST "HTTP/1.0 400 Bad request\r\n\r\n" +#define SERVER_BUSY "HTTP/1.0 503 Directory busy, try again later\r\n\r\n" +#define NOT_ENOUGH_CONSENSUS_SIGNATURES "HTTP/1.0 404 " \ + "Consensus not signed by sufficient number of requested authorities\r\n\r\n" + +static tor_addr_t MOCK_TOR_ADDR; + +static void +test_dir_handle_get_bad_request(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(directory_handle_command_get(conn, "", NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(header, OP_EQ, BAD_REQUEST); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_v1_command_not_found(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + // no frontpage configured + tt_ptr_op(get_dirportfrontpage(), OP_EQ, NULL); + + /* V1 path */ + tt_int_op(directory_handle_command_get(conn, GET("/tor/"), NULL, 0), + OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static const char* +mock_get_dirportfrontpage(void) +{ + return "HELLO FROM FRONTPAGE"; +} + +static void +test_dir_handle_get_v1_command(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0, body_len = 0; + const char *exp_body = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + MOCK(get_dirportfrontpage, mock_get_dirportfrontpage); + + exp_body = get_dirportfrontpage(); + body_len = strlen(exp_body); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(directory_handle_command_get(conn, GET("/tor/"), NULL, 0), + OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, body_len+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/html\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 20\r\n")); + + tt_int_op(body_used, OP_EQ, strlen(body)); + tt_str_op(body, OP_EQ, exp_body); + + done: + UNMOCK(connection_write_to_buf_impl_); + UNMOCK(get_dirportfrontpage); + tor_free(conn); + tor_free(header); + tor_free(body); +} + +static void +test_dir_handle_get_not_found(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + /* Unrecognized path */ + tt_int_op(directory_handle_command_get(conn, GET("/anything"), NULL, 0), + OP_EQ, 0); + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_robots_txt(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + tt_int_op(directory_handle_command_get(conn, GET("/tor/robots.txt"), + NULL, 0), OP_EQ, 0); + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, 29, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 28\r\n")); + + tt_int_op(body_used, OP_EQ, strlen(body)); + tt_str_op(body, OP_EQ, "User-agent: *\r\nDisallow: /\r\n"); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(body); +} + +static void +test_dir_handle_get_bytes_txt(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0, body_len = 0; + char buff[30]; + char *exp_body = NULL; + (void) data; + + exp_body = directory_dump_request_log(); + body_len = strlen(exp_body); + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + tt_int_op(directory_handle_command_get(conn, GET("/tor/bytes.txt"), NULL, 0), + OP_EQ, 0); + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, body_len+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Pragma: no-cache\r\n")); + + sprintf(buff, "Content-Length: %ld\r\n", (long) body_len); + tt_assert(strstr(header, buff)); + + tt_int_op(body_used, OP_EQ, strlen(body)); + tt_str_op(body, OP_EQ, exp_body); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(body); +} + +#define RENDEZVOUS2_GET(descid) GET("/tor/rendezvous2/" descid) +static void +test_dir_handle_get_rendezvous2_not_found_if_not_encrypted(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + // connection is not encrypted + tt_assert(!connection_dir_is_encrypted(conn)) + + tt_int_op(directory_handle_command_get(conn, RENDEZVOUS2_GET(), NULL, 0), + OP_EQ, 0); + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id( + void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + // connection is encrypted + TO_CONN(conn)->linked = 1; + tt_assert(connection_dir_is_encrypted(conn)); + + tt_int_op(directory_handle_command_get(conn, + RENDEZVOUS2_GET("invalid-desc-id"), NULL, 0), OP_EQ, 0); + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(header, OP_EQ, BAD_REQUEST); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_rendezvous2_on_encrypted_conn_not_well_formed(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + // connection is encrypted + TO_CONN(conn)->linked = 1; + tt_assert(connection_dir_is_encrypted(conn)); + + //TODO: this cant be reached because rend_valid_descriptor_id() prevents this + //case to happen. This test is the same as + //test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id + //We should refactor to remove the case from the switch. + + const char *req = RENDEZVOUS2_GET("1bababababababababababababababab"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(header, OP_EQ, BAD_REQUEST); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_rendezvous2_not_found(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + rend_cache_init(); + + // connection is encrypted + TO_CONN(conn)->linked = 1; + tt_assert(connection_dir_is_encrypted(conn)); + + const char *req = RENDEZVOUS2_GET("3xqunszqnaolrrfmtzgaki7mxelgvkje"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + rend_cache_free_all(); +} + +NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void)); +NS_DECL(int, hid_serv_responsible_for_desc_id, (const char *id)); + +static routerinfo_t *mock_routerinfo; +static int hid_serv_responsible_for_desc_id_response; + +static const routerinfo_t * +NS(router_get_my_routerinfo)(void) +{ + if (!mock_routerinfo) { + mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); + } + + return mock_routerinfo; +} + +static int +NS(hid_serv_responsible_for_desc_id)(const char *id) +{ + (void)id; + return hid_serv_responsible_for_desc_id_response; +} + +static void +test_dir_handle_get_rendezvous2_on_encrypted_conn_success(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + char buff[30]; + char req[70]; + rend_encoded_v2_service_descriptor_t *desc_holder = NULL; + char *service_id = NULL; + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; + size_t body_len = 0; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + NS_MOCK(router_get_my_routerinfo); + NS_MOCK(hid_serv_responsible_for_desc_id); + + rend_cache_init(); + hid_serv_responsible_for_desc_id_response = 1; + + /* create a valid rend service descriptor */ + #define RECENT_TIME -10 + generate_desc(RECENT_TIME, &desc_holder, &service_id, 3); + + tt_int_op(rend_cache_store_v2_desc_as_dir(desc_holder->desc_str), + OP_EQ, RCS_OKAY); + + base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, + DIGEST_LEN); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + // connection is encrypted + TO_CONN(conn)->linked = 1; + tt_assert(connection_dir_is_encrypted(conn)); + + sprintf(req, RENDEZVOUS2_GET("%s"), desc_id_base32); + + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + body_len = strlen(desc_holder->desc_str); + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, body_len+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Pragma: no-cache\r\n")); + sprintf(buff, "Content-Length: %ld\r\n", (long) body_len); + tt_assert(strstr(header, buff)); + + tt_int_op(body_used, OP_EQ, strlen(body)); + tt_str_op(body, OP_EQ, desc_holder->desc_str); + + done: + UNMOCK(connection_write_to_buf_impl_); + NS_UNMOCK(router_get_my_routerinfo); + NS_UNMOCK(hid_serv_responsible_for_desc_id); + + tor_free(conn); + tor_free(header); + tor_free(body); + rend_cache_free_all(); +} + +#define MICRODESC_GET(digest) GET("/tor/micro/d/" digest) +static void +test_dir_handle_get_micro_d_not_found(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + #define B64_256_1 "8/Pz8/u7vz8/Pz+7vz8/Pz+7u/Pz8/P7u/Pz8/P7u78" + #define B64_256_2 "zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMw" + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = MICRODESC_GET(B64_256_1 "-" B64_256_2); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + + tor_free(conn); + tor_free(header); +} + +static or_options_t *mock_options = NULL; +static void +init_mock_options(void) +{ + mock_options = malloc(sizeof(or_options_t)); + memset(mock_options, 0, sizeof(or_options_t)); + mock_options->TestingTorNetwork = 1; +} + +static const or_options_t * +mock_get_options(void) +{ + tor_assert(mock_options); + return mock_options; +} + +static const char microdesc[] = + "onion-key\n" + "-----BEGIN RSA PUBLIC KEY-----\n" + "MIGJAoGBAMjlHH/daN43cSVRaHBwgUfnszzAhg98EvivJ9Qxfv51mvQUxPjQ07es\n" + "gV/3n8fyh3Kqr/ehi9jxkdgSRfSnmF7giaHL1SLZ29kA7KtST+pBvmTpDtHa3ykX\n" + "Xorc7hJvIyTZoc1HU+5XSynj3gsBE5IGK1ZRzrNS688LnuZMVp1tAgMBAAE=\n" + "-----END RSA PUBLIC KEY-----\n"; + +static void +test_dir_handle_get_micro_d(void *data) +{ + dir_connection_t *conn = NULL; + microdesc_cache_t *mc = NULL ; + smartlist_t *list = NULL; + char digest[DIGEST256_LEN]; + char digest_base64[128]; + char path[80]; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + (void) data; + + MOCK(get_options, mock_get_options); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* SETUP */ + init_mock_options(); + const char *fn = get_fname("dir_handle_datadir_test1"); + mock_options->DataDirectory = tor_strdup(fn); + +#ifdef _WIN32 + tt_int_op(0, OP_EQ, mkdir(mock_options->DataDirectory)); +#else + tt_int_op(0, OP_EQ, mkdir(mock_options->DataDirectory, 0700)); +#endif + + /* Add microdesc to cache */ + crypto_digest256(digest, microdesc, strlen(microdesc), DIGEST_SHA256); + base64_encode_nopad(digest_base64, sizeof(digest_base64), + (uint8_t *) digest, DIGEST256_LEN); + + mc = get_microdesc_cache(); + list = microdescs_add_to_cache(mc, microdesc, NULL, SAVED_NOWHERE, 0, + time(NULL), NULL); + tt_int_op(1, OP_EQ, smartlist_len(list)); + + /* Make the request */ + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + sprintf(path, MICRODESC_GET("%s"), digest_base64); + tt_int_op(directory_handle_command_get(conn, path, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(microdesc)+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + + tt_int_op(body_used, OP_EQ, strlen(body)); + tt_str_op(body, OP_EQ, microdesc); + + done: + UNMOCK(get_options); + UNMOCK(connection_write_to_buf_impl_); + + if (mock_options) + tor_free(mock_options->DataDirectory); + tor_free(conn); + tor_free(header); + tor_free(body); + smartlist_free(list); + microdesc_free_all(); +} + +static void +test_dir_handle_get_micro_d_server_busy(void *data) +{ + dir_connection_t *conn = NULL; + microdesc_cache_t *mc = NULL ; + smartlist_t *list = NULL; + char digest[DIGEST256_LEN]; + char digest_base64[128]; + char path[80]; + char *header = NULL; + (void) data; + + MOCK(get_options, mock_get_options); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* SETUP */ + init_mock_options(); + const char *fn = get_fname("dir_handle_datadir_test2"); + mock_options->DataDirectory = tor_strdup(fn); + +#ifdef _WIN32 + tt_int_op(0, OP_EQ, mkdir(mock_options->DataDirectory)); +#else + tt_int_op(0, OP_EQ, mkdir(mock_options->DataDirectory, 0700)); +#endif + + /* Add microdesc to cache */ + crypto_digest256(digest, microdesc, strlen(microdesc), DIGEST_SHA256); + base64_encode_nopad(digest_base64, sizeof(digest_base64), + (uint8_t *) digest, DIGEST256_LEN); + + mc = get_microdesc_cache(); + list = microdescs_add_to_cache(mc, microdesc, NULL, SAVED_NOWHERE, 0, + time(NULL), NULL); + tt_int_op(1, OP_EQ, smartlist_len(list)); + + //Make it busy + mock_options->CountPrivateBandwidth = 1; + + /* Make the request */ + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + sprintf(path, MICRODESC_GET("%s"), digest_base64); + tt_int_op(directory_handle_command_get(conn, path, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(SERVER_BUSY, OP_EQ, header); + + done: + UNMOCK(get_options); + UNMOCK(connection_write_to_buf_impl_); + + if (mock_options) + tor_free(mock_options->DataDirectory); + + tor_free(conn); + tor_free(header); + smartlist_free(list); + microdesc_free_all(); +} + +#define BRIDGES_PATH "/tor/networkstatus-bridges" +static void +test_dir_handle_get_networkstatus_bridges_not_found_without_auth(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(get_options, mock_get_options); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* SETUP */ + init_mock_options(); + mock_options->BridgeAuthoritativeDir = 1; + mock_options->BridgePassword_AuthDigest_ = tor_strdup("digest"); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + TO_CONN(conn)->linked = 1; + + const char *req = GET(BRIDGES_PATH); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(get_options); + UNMOCK(connection_write_to_buf_impl_); + tor_free(mock_options); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_networkstatus_bridges(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(get_options, mock_get_options); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* SETUP */ + init_mock_options(); + mock_options->BridgeAuthoritativeDir = 1; + mock_options->BridgePassword_AuthDigest_ = tor_malloc(DIGEST256_LEN); + crypto_digest256(mock_options->BridgePassword_AuthDigest_, + "abcdefghijklm12345", 18, DIGEST_SHA256); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + TO_CONN(conn)->linked = 1; + + const char *req = "GET " BRIDGES_PATH " HTTP/1.0\r\n" + "Authorization: Basic abcdefghijklm12345\r\n\r\n"; + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 0\r\n")); + + done: + UNMOCK(get_options); + UNMOCK(connection_write_to_buf_impl_); + tor_free(mock_options); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_networkstatus_bridges_not_found_wrong_auth(void *data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(get_options, mock_get_options); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* SETUP */ + init_mock_options(); + mock_options->BridgeAuthoritativeDir = 1; + mock_options->BridgePassword_AuthDigest_ = tor_malloc(DIGEST256_LEN); + crypto_digest256(mock_options->BridgePassword_AuthDigest_, + "abcdefghijklm12345", 18, DIGEST_SHA256); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + TO_CONN(conn)->linked = 1; + + const char *req = "GET " BRIDGES_PATH " HTTP/1.0\r\n" + "Authorization: Basic NOTSAMEDIGEST\r\n\r\n"; + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(get_options); + UNMOCK(connection_write_to_buf_impl_); + tor_free(mock_options); + tor_free(conn); + tor_free(header); +} + +#define SERVER_DESC_GET(id) GET("/tor/server/" id) +static void +test_dir_handle_get_server_descriptors_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = SERVER_DESC_GET("invalid"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_str_op(NOT_FOUND, OP_EQ, header); + tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_SERVER_BY_FP); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(mock_options); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_server_descriptors_all(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + (void) data; + + /* Setup fake routerlist. */ + helper_setup_fake_routerlist(); + + //TODO: change to router_get_my_extrainfo when testing "extra" path + NS_MOCK(router_get_my_routerinfo); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + // We are one of the routers + routerlist_t *our_routerlist = router_get_routerlist(); + tt_int_op(smartlist_len(our_routerlist->routers), OP_GE, 1); + mock_routerinfo = smartlist_get(our_routerlist->routers, 0); + set_server_identity_key(mock_routerinfo->identity_pkey); + + /* Treat "all" requests as if they were unencrypted */ + mock_routerinfo->cache_info.send_unencrypted = 1; + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = SERVER_DESC_GET("all"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + //TODO: Is this a BUG? + //It requires strlen(signed_descriptor_len)+1 as body_len but returns a body + //which is smaller than that by annotation_len bytes + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, + mock_routerinfo->cache_info.signed_descriptor_len+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + + //TODO: Is this a BUG? + //This is what should be expected: tt_int_op(body_used, OP_EQ, strlen(body)); + tt_int_op(body_used, OP_EQ, + mock_routerinfo->cache_info.signed_descriptor_len); + + tt_str_op(body, OP_EQ, mock_routerinfo->cache_info.signed_descriptor_body + + mock_routerinfo->cache_info.annotations_len); + tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE); + + done: + NS_UNMOCK(router_get_my_routerinfo); + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(body); + + routerlist_free_all(); + nodelist_free_all(); + entry_guards_free_all(); +} + +static char +TEST_DESCRIPTOR[] = +"@uploaded-at 2014-06-08 19:20:11\n" +"@source \"127.0.0.1\"\n" +"router test000a 127.0.0.1 5000 0 7000\n" +"platform Tor 0.2.5.3-alpha-dev on Linux\n" +"protocols Link 1 2 Circuit 1\n" +"published 2014-06-08 19:20:11\n" +"fingerprint C7E7 CCB8 179F 8CC3 7F5C 8A04 2B3A 180B 934B 14BA\n" +"uptime 0\n" +"bandwidth 1073741824 1073741824 0\n" +"extra-info-digest 67A152A4C7686FB07664F872620635F194D76D95\n" +"caches-extra-info\n" +"onion-key\n" +"-----BEGIN RSA PUBLIC KEY-----\n" +"MIGJAoGBAOuBUIEBARMkkka/TGyaQNgUEDLP0KG7sy6KNQTNOlZHUresPr/vlVjo\n" +"HPpLMfu9M2z18c51YX/muWwY9x4MyQooD56wI4+AqXQcJRwQfQlPn3Ay82uZViA9\n" +"DpBajRieLlKKkl145KjArpD7F5BVsqccvjErgFYXvhhjSrx7BVLnAgMBAAE=\n" +"-----END RSA PUBLIC KEY-----\n" +"signing-key\n" +"-----BEGIN RSA PUBLIC KEY-----\n" +"MIGJAoGBAN6NLnSxWQnFXxqZi5D3b0BMgV6y9NJLGjYQVP+eWtPZWgqyv4zeYsqv\n" +"O9y6c5lvxyUxmNHfoAbe/s8f2Vf3/YaC17asAVSln4ktrr3e9iY74a9RMWHv1Gzk\n" +"3042nMcqj3PEhRN0PoLkcOZNjjmNbaqki6qy9bWWZDNTdo+uI44dAgMBAAE=\n" +"-----END RSA PUBLIC KEY-----\n" +"hidden-service-dir\n" +"contact auth0@test.test\n" +"ntor-onion-key pK4bs08ERYN591jj7ca17Rn9Q02TIEfhnjR6hSq+fhU=\n" +"reject *:*\n" +"router-signature\n" +"-----BEGIN SIGNATURE-----\n" +"rx88DuM3Y7tODlHNDDEVzKpwh3csaG1or+T4l2Xs1oq3iHHyPEtB6QTLYrC60trG\n" +"aAPsj3DEowGfjga1b248g2dtic8Ab+0exfjMm1RHXfDam5TXXZU3A0wMyoHjqHuf\n" +"eChGPgFNUvEc+5YtD27qEDcUjcinYztTs7/dzxBT4PE=\n" +"-----END SIGNATURE-----\n"; + +static void +test_dir_handle_get_server_descriptors_authority(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + crypto_pk_t *identity_pkey = pk_generate(0); + (void) data; + + NS_MOCK(router_get_my_routerinfo); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* init mock */ + router_get_my_routerinfo(); + crypto_pk_get_digest(identity_pkey, + mock_routerinfo->cache_info.identity_digest); + + // the digest is mine (the channel is unnecrypted, so we must allow sending) + set_server_identity_key(identity_pkey); + mock_routerinfo->cache_info.send_unencrypted = 1; + + /* Setup descriptor */ + long annotation_len = strstr(TEST_DESCRIPTOR, "router ") - TEST_DESCRIPTOR; + mock_routerinfo->cache_info.signed_descriptor_body = + tor_strdup(TEST_DESCRIPTOR); + mock_routerinfo->cache_info.signed_descriptor_len = strlen(TEST_DESCRIPTOR); + mock_routerinfo->cache_info.annotations_len = annotation_len; + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = SERVER_DESC_GET("authority"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + //TODO: Is this a BUG? + //It requires strlen(TEST_DESCRIPTOR)+1 as body_len but returns a body which + //is smaller than that by annotation_len bytes + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(TEST_DESCRIPTOR)+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + + //TODO: Is this a BUG? + //This is what should be expected: + //tt_int_op(body_used, OP_EQ, strlen(body)); + tt_int_op(body_used, OP_EQ, strlen(TEST_DESCRIPTOR)); + + tt_str_op(body, OP_EQ, TEST_DESCRIPTOR + annotation_len); + tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE); + + done: + NS_UNMOCK(router_get_my_routerinfo); + UNMOCK(connection_write_to_buf_impl_); + tor_free(mock_routerinfo); + tor_free(conn); + tor_free(header); + tor_free(body); + crypto_pk_free(identity_pkey); +} + +static void +test_dir_handle_get_server_descriptors_fp(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + crypto_pk_t *identity_pkey = pk_generate(0); + (void) data; + + NS_MOCK(router_get_my_routerinfo); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* init mock */ + router_get_my_routerinfo(); + crypto_pk_get_digest(identity_pkey, + mock_routerinfo->cache_info.identity_digest); + + // the digest is mine (the channel is unnecrypted, so we must allow sending) + set_server_identity_key(identity_pkey); + mock_routerinfo->cache_info.send_unencrypted = 1; + + /* Setup descriptor */ + long annotation_len = strstr(TEST_DESCRIPTOR, "router ") - TEST_DESCRIPTOR; + mock_routerinfo->cache_info.signed_descriptor_body = + tor_strdup(TEST_DESCRIPTOR); + mock_routerinfo->cache_info.signed_descriptor_len = strlen(TEST_DESCRIPTOR); + mock_routerinfo->cache_info.annotations_len = annotation_len; + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + #define HEX1 "Fe0daff89127389bc67558691231234551193EEE" + #define HEX2 "Deadbeef99999991111119999911111111f00ba4" + const char *hex_digest = hex_str(mock_routerinfo->cache_info.identity_digest, + DIGEST_LEN); + + char req[155]; + sprintf(req, SERVER_DESC_GET("fp/%s+" HEX1 "+" HEX2), hex_digest); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + //TODO: Is this a BUG? + //It requires strlen(TEST_DESCRIPTOR)+1 as body_len but returns a body which + //is smaller than that by annotation_len bytes + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(TEST_DESCRIPTOR)+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + + //TODO: Is this a BUG? + //This is what should be expected: + //tt_int_op(body_used, OP_EQ, strlen(body)); + tt_int_op(body_used, OP_EQ, strlen(TEST_DESCRIPTOR)); + + tt_str_op(body, OP_EQ, TEST_DESCRIPTOR + annotation_len); + tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE); + + done: + NS_UNMOCK(router_get_my_routerinfo); + UNMOCK(connection_write_to_buf_impl_); + tor_free(mock_routerinfo); + tor_free(conn); + tor_free(header); + tor_free(body); + crypto_pk_free(identity_pkey); +} + +#define HEX1 "Fe0daff89127389bc67558691231234551193EEE" +#define HEX2 "Deadbeef99999991111119999911111111f00ba4" + +static void +test_dir_handle_get_server_descriptors_d(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + crypto_pk_t *identity_pkey = pk_generate(0); + (void) data; + + /* Setup fake routerlist. */ + helper_setup_fake_routerlist(); + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* Get one router's signed_descriptor_digest */ + routerlist_t *our_routerlist = router_get_routerlist(); + tt_int_op(smartlist_len(our_routerlist->routers), OP_GE, 1); + routerinfo_t *router = smartlist_get(our_routerlist->routers, 0); + const char *hex_digest = hex_str(router->cache_info.signed_descriptor_digest, + DIGEST_LEN); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + char req_header[155]; + sprintf(req_header, SERVER_DESC_GET("d/%s+" HEX1 "+" HEX2), hex_digest); + tt_int_op(directory_handle_command_get(conn, req_header, NULL, 0), OP_EQ, 0); + + //TODO: Is this a BUG? + //It requires strlen(signed_descriptor_len)+1 as body_len but returns a body + //which is smaller than that by annotation_len bytes + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, + router->cache_info.signed_descriptor_len+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + + //TODO: Is this a BUG? + //This is what should be expected: + //tt_int_op(body_used, OP_EQ, strlen(body)); + tt_int_op(body_used, OP_EQ, router->cache_info.signed_descriptor_len); + + tt_str_op(body, OP_EQ, router->cache_info.signed_descriptor_body + + router->cache_info.annotations_len); + tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(mock_routerinfo); + tor_free(conn); + tor_free(header); + tor_free(body); + crypto_pk_free(identity_pkey); + + routerlist_free_all(); + nodelist_free_all(); + entry_guards_free_all(); +} + +static void +test_dir_handle_get_server_descriptors_busy(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + crypto_pk_t *identity_pkey = pk_generate(0); + (void) data; + + /* Setup fake routerlist. */ + helper_setup_fake_routerlist(); + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + //Make it busy + MOCK(get_options, mock_get_options); + init_mock_options(); + mock_options->CountPrivateBandwidth = 1; + + /* Get one router's signed_descriptor_digest */ + routerlist_t *our_routerlist = router_get_routerlist(); + tt_int_op(smartlist_len(our_routerlist->routers), OP_GE, 1); + routerinfo_t *router = smartlist_get(our_routerlist->routers, 0); + const char *hex_digest = hex_str(router->cache_info.signed_descriptor_digest, + DIGEST_LEN); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + #define HEX1 "Fe0daff89127389bc67558691231234551193EEE" + #define HEX2 "Deadbeef99999991111119999911111111f00ba4" + char req_header[155]; + sprintf(req_header, SERVER_DESC_GET("d/%s+" HEX1 "+" HEX2), hex_digest); + tt_int_op(directory_handle_command_get(conn, req_header, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(SERVER_BUSY, OP_EQ, header); + + tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE); + + done: + UNMOCK(get_options); + UNMOCK(connection_write_to_buf_impl_); + tor_free(mock_routerinfo); + tor_free(conn); + tor_free(header); + crypto_pk_free(identity_pkey); + + routerlist_free_all(); + nodelist_free_all(); + entry_guards_free_all(); +} + +static void +test_dir_handle_get_server_keys_bad_req(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = GET("/tor/keys/"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(BAD_REQUEST, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_server_keys_all_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = GET("/tor/keys/all"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +#define TEST_CERTIFICATE AUTHORITY_CERT_3 +#define TEST_SIGNING_KEY AUTHORITY_SIGNKEY_A_DIGEST +extern const char AUTHORITY_CERT_3[]; +extern const char AUTHORITY_SIGNKEY_A_DIGEST[]; + +static const char TEST_CERT_IDENT_KEY[] = + "D867ACF56A9D229B35C25F0090BC9867E906BE69"; + +static void +test_dir_handle_get_server_keys_all(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + + dir_server_t *ds = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + clear_dir_servers(); + routerlist_free_all(); + + /* create a trusted ds */ + ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, "", NULL, + V3_DIRINFO, 1.0); + tt_assert(ds); + dir_server_add(ds); + + /* ds v3_identity_digest is the certificate's identity_key */ + 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)); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = GET("/tor/keys/all"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(TEST_CERTIFICATE)+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 1883\r\n")); + + tt_str_op(TEST_CERTIFICATE, OP_EQ, body); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(body); + + clear_dir_servers(); + routerlist_free_all(); +} + +static void +test_dir_handle_get_server_keys_authority_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = GET("/tor/keys/authority"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static authority_cert_t * mock_cert = NULL; + +static authority_cert_t * +get_my_v3_authority_cert_m(void) +{ + tor_assert(mock_cert); + return mock_cert; +} + +static void +test_dir_handle_get_server_keys_authority(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + (void) data; + + mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL); + + MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = GET("/tor/keys/authority"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(TEST_CERTIFICATE)+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 1883\r\n")); + + tt_str_op(TEST_CERTIFICATE, OP_EQ, body); + + done: + UNMOCK(get_my_v3_authority_cert); + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(body); + tor_free(mock_cert); +} + +static void +test_dir_handle_get_server_keys_fp_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = GET("/tor/keys/fp/somehex"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_server_keys_fp(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + dir_server_t *ds = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + clear_dir_servers(); + routerlist_free_all(); + + /* create a trusted ds */ + ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, "", NULL, + V3_DIRINFO, 1.0); + tt_assert(ds); + dir_server_add(ds); + + /* ds v3_identity_digest is the certificate's identity_key */ + 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)); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + char req[71]; + sprintf(req, GET("/tor/keys/fp/%s"), TEST_CERT_IDENT_KEY); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(TEST_CERTIFICATE)+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 1883\r\n")); + + tt_str_op(TEST_CERTIFICATE, OP_EQ, body); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(body); + clear_dir_servers(); + routerlist_free_all(); +} + +static void +test_dir_handle_get_server_keys_sk_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = GET("/tor/keys/sk/somehex"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_server_keys_sk(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + (void) data; + + mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL); + MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + clear_dir_servers(); + 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)); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + char req[71]; + sprintf(req, GET("/tor/keys/sk/%s"), TEST_SIGNING_KEY); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(TEST_CERTIFICATE)+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 1883\r\n")); + + tt_str_op(TEST_CERTIFICATE, OP_EQ, body); + + done: + UNMOCK(get_my_v3_authority_cert); + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(body); +} + +static void +test_dir_handle_get_server_keys_fpsk_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + const char *req = GET("/tor/keys/fp-sk/somehex"); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_server_keys_fpsk(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + dir_server_t *ds = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + clear_dir_servers(); + routerlist_free_all(); + + /* create a trusted ds */ + ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, "", NULL, + V3_DIRINFO, 1.0); + tt_assert(ds); + + /* ds v3_identity_digest is the certificate's identity_key */ + base16_decode(ds->v3_identity_digest, DIGEST_LEN, + TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN); + 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)); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + char req[115]; + sprintf(req, GET("/tor/keys/fp-sk/%s-%s"), + TEST_CERT_IDENT_KEY, TEST_SIGNING_KEY); + + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(TEST_CERTIFICATE)+1, 0); + + tt_assert(header); + tt_assert(body); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 1883\r\n")); + + tt_str_op(TEST_CERTIFICATE, OP_EQ, body); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(body); + + clear_dir_servers(); + routerlist_free_all(); +} + +static void +test_dir_handle_get_server_keys_busy(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + dir_server_t *ds = NULL; + (void) data; + + clear_dir_servers(); + routerlist_free_all(); + + /* create a trusted ds */ + ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, "", NULL, + V3_DIRINFO, 1.0); + tt_assert(ds); + + /* ds v3_identity_digest is the certificate's identity_key */ + base16_decode(ds->v3_identity_digest, DIGEST_LEN, + TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN); + 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)); + + MOCK(get_options, mock_get_options); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* setup busy server */ + init_mock_options(); + mock_options->CountPrivateBandwidth = 1; + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + char req[71]; + sprintf(req, GET("/tor/keys/fp/%s"), TEST_CERT_IDENT_KEY); + tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(SERVER_BUSY, OP_EQ, header); + + done: + UNMOCK(get_options); + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); + tor_free(mock_options); + + clear_dir_servers(); + routerlist_free_all(); +} + +static networkstatus_t *mock_ns_val = NULL; +static networkstatus_t * +mock_ns_get_by_flavor(consensus_flavor_t f) +{ + (void)f; + return mock_ns_val; +} + +static void +test_dir_handle_get_status_vote_current_consensus_ns_not_enough_sigs(void* d) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) d; + + /* init mock */ + mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t)); + mock_ns_val->flavor = FLAV_NS; + mock_ns_val->voters = smartlist_new(); + + /* init mock */ + init_mock_options(); + + MOCK(get_options, mock_get_options); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor); + + /* start gathering stats */ + mock_options->DirReqStatistics = 1; + geoip_dirreq_stats_init(time(NULL)); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/current/consensus-ns/" HEX1 "+" HEX2), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + + tt_assert(header); + tt_str_op(NOT_ENOUGH_CONSENSUS_SIGNATURES, OP_EQ, header); + + char *stats = geoip_format_dirreq_stats(time(NULL)); + tt_assert(stats); + tt_assert(strstr(stats, "not-enough-sigs=8")); + + done: + UNMOCK(networkstatus_get_latest_consensus_by_flavor); + UNMOCK(connection_write_to_buf_impl_); + UNMOCK(get_options); + + tor_free(conn); + tor_free(header); + smartlist_free(mock_ns_val->voters); + tor_free(mock_ns_val); + tor_free(mock_options); +} + +static void +test_dir_handle_get_status_vote_current_consensus_ns_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + init_mock_options(); + + MOCK(get_options, mock_get_options); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + /* start gathering stats */ + mock_options->DirReqStatistics = 1; + geoip_dirreq_stats_init(time(NULL)); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/current/consensus-ns"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + char *stats = geoip_format_dirreq_stats(time(NULL)); + tt_assert(stats); + tt_assert(strstr(stats, "not-found=8")); + + done: + UNMOCK(connection_write_to_buf_impl_); + UNMOCK(get_options); + tor_free(conn); + tor_free(header); + tor_free(mock_options); +} + +NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr)); + +int +NS(geoip_get_country_by_addr)(const tor_addr_t *addr) +{ + (void)addr; + CALLED(geoip_get_country_by_addr)++; + return 1; +} + +static void +status_vote_current_consensus_ns_test(char **header, char **body, + size_t *body_len) +{ + digests_t digests; + dir_connection_t *conn = NULL; + + #define NETWORK_STATUS "some network status string" + dirserv_set_cached_consensus_networkstatus(NETWORK_STATUS, "ns", &digests, + time(NULL)); + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + tt_assert(mock_options); + mock_options->DirReqStatistics = 1; + geoip_dirreq_stats_init(time(NULL)); + + /* init geoip database */ + geoip_parse_entry("10,50,AB", AF_INET); + tt_str_op("ab", OP_EQ, geoip_get_country_name(1)); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + TO_CONN(conn)->address = tor_strdup("127.0.0.1"); + + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/current/consensus-ns"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, header, MAX_HEADERS_SIZE, + body, body_len, strlen(NETWORK_STATUS)+7, 0); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); +} + +static void +test_dir_handle_get_status_vote_current_consensus_ns(void* data) +{ + char *header = NULL; + char *body = NULL, *comp_body = NULL; + size_t body_used = 0, comp_body_used = 0; + char *stats = NULL, *hist = NULL; + (void) data; + + dirserv_free_all(); + clear_geoip_db(); + + NS_MOCK(geoip_get_country_by_addr); + MOCK(get_options, mock_get_options); + + init_mock_options(); + + status_vote_current_consensus_ns_test(&header, &comp_body, &comp_body_used); + tt_assert(header); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Pragma: no-cache\r\n")); + + compress_method_t compression = detect_compression_method(comp_body, + comp_body_used); + tt_int_op(ZLIB_METHOD, OP_EQ, compression); + + tor_gzip_uncompress(&body, &body_used, comp_body, comp_body_used, + compression, 0, LOG_PROTOCOL_WARN); + + tt_str_op(NETWORK_STATUS, OP_EQ, body); + tt_int_op(strlen(NETWORK_STATUS), OP_EQ, body_used); + + stats = geoip_format_dirreq_stats(time(NULL)); + tt_assert(stats); + + tt_assert(strstr(stats, "ok=8")); + tt_assert(strstr(stats, "dirreq-v3-ips ab=8")); + tt_assert(strstr(stats, "dirreq-v3-reqs ab=8")); + tt_assert(strstr(stats, "dirreq-v3-direct-dl" + " complete=0,timeout=0,running=4")); + + hist = geoip_get_request_history(); + tt_assert(hist); + tt_str_op("ab=8", OP_EQ, hist); + + done: + NS_UNMOCK(geoip_get_country_by_addr); + UNMOCK(get_options); + tor_free(header); + tor_free(comp_body); + tor_free(body); + tor_free(stats); + tor_free(hist); + tor_free(mock_options); + + dirserv_free_all(); + clear_geoip_db(); +} + +static void +test_dir_handle_get_status_vote_current_consensus_ns_busy(void* data) +{ + char *header = NULL; + char *body = NULL; + size_t body_used = 0; + (void) data; + + dirserv_free_all(); + clear_geoip_db(); + + MOCK(get_options, mock_get_options); + + // Make it busy + init_mock_options(); + mock_options->CountPrivateBandwidth = 1; + + status_vote_current_consensus_ns_test(&header, &body, &body_used); + tt_assert(header); + + tt_str_op(SERVER_BUSY, OP_EQ, header); + + char *stats = geoip_format_dirreq_stats(time(NULL)); + tt_assert(stats); + tt_assert(strstr(stats, "busy=8")); + + done: + UNMOCK(get_options); + tor_free(header); + tor_free(body); + tor_free(mock_options); + + dirserv_free_all(); + clear_geoip_db(); +} + +static void +test_dir_handle_get_status_vote_current_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/current/" HEX1), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +#define VOTE_DIGEST "312A4890D4D832597ABBD3089C782DBBFB81E48D" + +static void +status_vote_current_d_test(char **header, char **body, size_t *body_l) +{ + dir_connection_t *conn = NULL; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/current/d/" VOTE_DIGEST), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, header, MAX_HEADERS_SIZE, + body, body_l, strlen(VOTE_BODY_V3)+1, 0); + tt_assert(header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); +} + +static void +status_vote_next_d_test(char **header, char **body, size_t *body_l) +{ + dir_connection_t *conn = NULL; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/next/d/" VOTE_DIGEST), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, header, MAX_HEADERS_SIZE, + body, body_l, strlen(VOTE_BODY_V3)+1, 0); + tt_assert(header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); +} + +static void +test_dir_handle_get_status_vote_current_d_not_found(void* data) +{ + char *header = NULL; + (void) data; + + status_vote_current_d_test(&header, NULL, NULL); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + tor_free(header); +} + +static void +test_dir_handle_get_status_vote_next_d_not_found(void* data) +{ + char *header = NULL; + (void) data; + + status_vote_next_d_test(&header, NULL, NULL); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(header); +} + +static void +test_dir_handle_get_status_vote_d(void* data) +{ + char *header = NULL, *body = NULL; + size_t body_used = 0; + dir_server_t *ds = NULL; + (void) data; + + clear_dir_servers(); + dirvote_free_all(); + + /* create a trusted ds */ + ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, "", NULL, + V3_DIRINFO, 1.0); + tt_assert(ds); + dir_server_add(ds); + + /* ds v3_identity_digest is the certificate's identity_key */ + base16_decode(ds->v3_identity_digest, DIGEST_LEN, + TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN); + + init_mock_options(); + mock_options->AuthoritativeDir = 1; + mock_options->V3AuthoritativeDir = 1; + mock_options->TestingV3AuthVotingStartOffset = 0; + mock_options->TestingV3AuthInitialVotingInterval = 1; + mock_options->TestingV3AuthInitialVoteDelay = 1; + mock_options->TestingV3AuthInitialDistDelay = 1; + + time_t now = 1441223455 -1; + dirvote_recalculate_timing(mock_options, now); + + const char *msg_out = NULL; + int status_out = 0; + struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, &msg_out, + &status_out); + tt_assert(pv); + + status_vote_current_d_test(&header, &body, &body_used); + + tt_assert(header); + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 4135\r\n")); + + tt_str_op(VOTE_BODY_V3, OP_EQ, body); + + tor_free(header); + tor_free(body); + + status_vote_next_d_test(&header, &body, &body_used); + + tt_assert(header); + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 4135\r\n")); + + tt_str_op(VOTE_BODY_V3, OP_EQ, body); + + done: + tor_free(header); + tor_free(body); + tor_free(mock_options); + + clear_dir_servers(); + dirvote_free_all(); +} + +static void +test_dir_handle_get_status_vote_next_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/next/" HEX1), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +status_vote_next_consensus_test(char **header, char **body, size_t *body_used) +{ + dir_connection_t *conn = NULL; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/next/consensus"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, header, MAX_HEADERS_SIZE, + body, body_used, 18, 0); + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); +} + +static void +test_dir_handle_get_status_vote_next_consensus_not_found(void* data) +{ + char *header = NULL, *body = NULL; + size_t body_used; + (void) data; + + status_vote_next_consensus_test(&header, &body, &body_used); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + tor_free(header); + tor_free(body); +} + +static void +test_dir_handle_get_status_vote_current_authority_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/current/authority"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +static void +test_dir_handle_get_status_vote_next_authority_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL; + (void) data; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/next/authority"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + NULL, NULL, 1, 0); + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + UNMOCK(connection_write_to_buf_impl_); + tor_free(conn); + tor_free(header); +} + +NS_DECL(const char*, +dirvote_get_pending_consensus, (consensus_flavor_t flav)); + +const char* +NS(dirvote_get_pending_consensus)(consensus_flavor_t flav) +{ + (void)flav; + return "pending consensus"; +} + +static void +test_dir_handle_get_status_vote_next_consensus(void* data) +{ + char *header = NULL, *body = NULL; + size_t body_used = 0; + (void) data; + + NS_MOCK(dirvote_get_pending_consensus); + + status_vote_next_consensus_test(&header, &body, &body_used); + tt_assert(header); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 17\r\n")); + + tt_str_op("pending consensus", OP_EQ, body); + + done: + NS_UNMOCK(dirvote_get_pending_consensus); + tor_free(header); + tor_free(body); +} + +static void +test_dir_handle_get_status_vote_next_consensus_busy(void* data) +{ + char *header = NULL, *body = NULL; + size_t body_used = 0; + (void) data; + + MOCK(get_options, mock_get_options); + NS_MOCK(dirvote_get_pending_consensus); + + //Make it busy + init_mock_options(); + mock_options->CountPrivateBandwidth = 1; + + status_vote_next_consensus_test(&header, &body, &body_used); + + tt_assert(header); + tt_str_op(SERVER_BUSY, OP_EQ, header); + + done: + NS_UNMOCK(dirvote_get_pending_consensus); + UNMOCK(get_options); + tor_free(header); + tor_free(body); + tor_free(mock_options); +} + +static void +status_vote_next_consensus_signatures_test(char **header, char **body, + size_t *body_used) +{ + dir_connection_t *conn = NULL; + + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/next/consensus-signatures"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, header, MAX_HEADERS_SIZE, + body, body_used, 22, 0); + + done: + UNMOCK(connection_write_to_buf_impl_); +} + +static void +test_dir_handle_get_status_vote_next_consensus_signatures_not_found(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL, *body = NULL; + size_t body_used; + (void) data; + + status_vote_next_consensus_signatures_test(&header, &body, &body_used); + + tt_assert(header); + tt_str_op(NOT_FOUND, OP_EQ, header); + + done: + tor_free(conn); + tor_free(header); + tor_free(body); +} + +NS_DECL(const char*, +dirvote_get_pending_detached_signatures, (void)); + +const char* +NS(dirvote_get_pending_detached_signatures)(void) +{ + return "pending detached sigs"; +} + +static void +test_dir_handle_get_status_vote_next_consensus_signatures(void* data) +{ + char *header = NULL, *body = NULL; + size_t body_used = 0; + (void) data; + + NS_MOCK(dirvote_get_pending_detached_signatures); + + status_vote_next_consensus_signatures_test(&header, &body, &body_used); + tt_assert(header); + + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 21\r\n")); + + tt_str_op("pending detached sigs", OP_EQ, body); + + done: + NS_UNMOCK(dirvote_get_pending_detached_signatures); + tor_free(header); + tor_free(body); +} + +static void +test_dir_handle_get_status_vote_next_consensus_signatures_busy(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL, *body = NULL; + size_t body_used; + (void) data; + + NS_MOCK(dirvote_get_pending_detached_signatures); + MOCK(get_options, mock_get_options); + + //Make it busy + init_mock_options(); + mock_options->CountPrivateBandwidth = 1; + + status_vote_next_consensus_signatures_test(&header, &body, &body_used); + + tt_assert(header); + tt_str_op(SERVER_BUSY, OP_EQ, header); + + done: + UNMOCK(get_options); + NS_UNMOCK(dirvote_get_pending_detached_signatures); + tor_free(conn); + tor_free(header); + tor_free(body); + tor_free(mock_options); +} + +static void +test_dir_handle_get_status_vote_next_authority(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL, *body = NULL; + const char *msg_out = NULL; + int status_out = 0; + size_t body_used = 0; + dir_server_t *ds = NULL; + (void) data; + + clear_dir_servers(); + routerlist_free_all(); + dirvote_free_all(); + + mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL); + + /* create a trusted ds */ + ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, "", NULL, + V3_DIRINFO, 1.0); + tt_assert(ds); + dir_server_add(ds); + + /* ds v3_identity_digest is the certificate's identity_key */ + 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)); + + init_mock_options(); + mock_options->AuthoritativeDir = 1; + mock_options->V3AuthoritativeDir = 1; + mock_options->TestingV3AuthVotingStartOffset = 0; + mock_options->TestingV3AuthInitialVotingInterval = 1; + mock_options->TestingV3AuthInitialVoteDelay = 1; + mock_options->TestingV3AuthInitialDistDelay = 1; + + time_t now = 1441223455 -1; + dirvote_recalculate_timing(mock_options, now); + + struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out, + &status_out); + tt_assert(vote); + + MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/next/authority"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(VOTE_BODY_V3)+1, 0); + + tt_assert(header); + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 4135\r\n")); + + tt_str_op(VOTE_BODY_V3, OP_EQ, body); + + done: + UNMOCK(connection_write_to_buf_impl_); + UNMOCK(get_my_v3_authority_cert); + tor_free(conn); + tor_free(header); + tor_free(mock_cert); + + clear_dir_servers(); + routerlist_free_all(); + dirvote_free_all(); +} + +static void +test_dir_handle_get_status_vote_current_authority(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL, *body = NULL; + const char *msg_out = NULL; + int status_out = 0; + size_t body_used = 0; + + dir_server_t *ds = NULL; + (void) data; + + clear_dir_servers(); + routerlist_free_all(); + dirvote_free_all(); + + mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL); + + /* create a trusted ds */ + ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, "", NULL, + V3_DIRINFO, 1.0); + tt_assert(ds); + dir_server_add(ds); + + /* ds v3_identity_digest is the certificate's identity_key */ + 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)); + + init_mock_options(); + mock_options->AuthoritativeDir = 1; + mock_options->V3AuthoritativeDir = 1; + mock_options->TestingV3AuthVotingStartOffset = 0; + mock_options->TestingV3AuthInitialVotingInterval = 1; + mock_options->TestingV3AuthInitialVoteDelay = 1; + mock_options->TestingV3AuthInitialDistDelay = 1; + + time_t now = 1441223455; + dirvote_recalculate_timing(mock_options, now-1); + + struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out, + &status_out); + tt_assert(vote); + + // move the pending vote to previous vote + dirvote_act(mock_options, now+1); + + MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = dir_connection_new(tor_addr_family(&MOCK_TOR_ADDR)); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/current/authority"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(VOTE_BODY_V3)+1, 0); + + tt_assert(header); + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 4135\r\n")); + + tt_str_op(VOTE_BODY_V3, OP_EQ, body); + + done: + UNMOCK(connection_write_to_buf_impl_); + UNMOCK(get_my_v3_authority_cert); + tor_free(conn); + tor_free(header); + tor_free(mock_cert); + + clear_dir_servers(); + routerlist_free_all(); + dirvote_free_all(); +} + +#define DIR_HANDLE_CMD(name,flags) \ + { #name, test_dir_handle_get_##name, (flags), NULL, NULL } + +struct testcase_t dir_handle_get_tests[] = { + DIR_HANDLE_CMD(not_found, 0), + DIR_HANDLE_CMD(bad_request, 0), + DIR_HANDLE_CMD(v1_command_not_found, 0), + DIR_HANDLE_CMD(v1_command, 0), + DIR_HANDLE_CMD(robots_txt, 0), + DIR_HANDLE_CMD(bytes_txt, 0), + DIR_HANDLE_CMD(rendezvous2_not_found_if_not_encrypted, 0), + DIR_HANDLE_CMD(rendezvous2_not_found, 0), + DIR_HANDLE_CMD(rendezvous2_on_encrypted_conn_with_invalid_desc_id, 0), + DIR_HANDLE_CMD(rendezvous2_on_encrypted_conn_not_well_formed, 0), + DIR_HANDLE_CMD(rendezvous2_on_encrypted_conn_success, 0), + DIR_HANDLE_CMD(micro_d_not_found, 0), + DIR_HANDLE_CMD(micro_d_server_busy, 0), + DIR_HANDLE_CMD(micro_d, 0), + DIR_HANDLE_CMD(networkstatus_bridges_not_found_without_auth, 0), + DIR_HANDLE_CMD(networkstatus_bridges_not_found_wrong_auth, 0), + DIR_HANDLE_CMD(networkstatus_bridges, 0), + DIR_HANDLE_CMD(server_descriptors_not_found, 0), + DIR_HANDLE_CMD(server_descriptors_busy, TT_FORK), + DIR_HANDLE_CMD(server_descriptors_all, TT_FORK), + DIR_HANDLE_CMD(server_descriptors_authority, TT_FORK), + DIR_HANDLE_CMD(server_descriptors_fp, TT_FORK), + DIR_HANDLE_CMD(server_descriptors_d, TT_FORK), + DIR_HANDLE_CMD(server_keys_bad_req, 0), + DIR_HANDLE_CMD(server_keys_busy, 0), + DIR_HANDLE_CMD(server_keys_all_not_found, 0), + DIR_HANDLE_CMD(server_keys_all, 0), + DIR_HANDLE_CMD(server_keys_authority_not_found, 0), + DIR_HANDLE_CMD(server_keys_authority, 0), + DIR_HANDLE_CMD(server_keys_fp_not_found, 0), + DIR_HANDLE_CMD(server_keys_fp, 0), + DIR_HANDLE_CMD(server_keys_sk_not_found, 0), + DIR_HANDLE_CMD(server_keys_sk, 0), + DIR_HANDLE_CMD(server_keys_fpsk_not_found, 0), + DIR_HANDLE_CMD(server_keys_fpsk, 0), + DIR_HANDLE_CMD(status_vote_current_not_found, 0), + DIR_HANDLE_CMD(status_vote_next_not_found, 0), + DIR_HANDLE_CMD(status_vote_current_authority_not_found, 0), + DIR_HANDLE_CMD(status_vote_current_authority, 0), + DIR_HANDLE_CMD(status_vote_next_authority_not_found, 0), + DIR_HANDLE_CMD(status_vote_next_authority, 0), + DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_enough_sigs, 0), + DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_found, 0), + DIR_HANDLE_CMD(status_vote_current_consensus_ns_busy, 0), + DIR_HANDLE_CMD(status_vote_current_consensus_ns, 0), + DIR_HANDLE_CMD(status_vote_current_d_not_found, 0), + DIR_HANDLE_CMD(status_vote_next_d_not_found, 0), + DIR_HANDLE_CMD(status_vote_d, 0), + DIR_HANDLE_CMD(status_vote_next_consensus_not_found, 0), + DIR_HANDLE_CMD(status_vote_next_consensus_busy, 0), + DIR_HANDLE_CMD(status_vote_next_consensus, 0), + DIR_HANDLE_CMD(status_vote_next_consensus_signatures_not_found, 0), + DIR_HANDLE_CMD(status_vote_next_consensus_signatures_busy, 0), + DIR_HANDLE_CMD(status_vote_next_consensus_signatures, 0), + END_OF_TESTCASES +}; + diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c index afd4ca201d..bd0f6fdd52 100644 --- a/src/test/test_keypin.c +++ b/src/test/test_keypin.c @@ -108,21 +108,21 @@ test_keypin_parse_file(void *arg) ; tt_int_op(0, ==, keypin_load_journal_impl(data2, strlen(data2))); - tt_int_op(11, ==, smartlist_len(mock_addent_got)); + tt_int_op(13, ==, smartlist_len(mock_addent_got)); ent = smartlist_get(mock_addent_got, 9); tt_mem_op(ent->rsa_id, ==, "\"You have made a goo", 20); tt_mem_op(ent->ed25519_key, ==, "d beginning.\" But no more. Wizar", 32); - ent = smartlist_get(mock_addent_got, 10); + ent = smartlist_get(mock_addent_got, 12); tt_mem_op(ent->rsa_id, ==, "ds speak truth, and ", 20); - tt_mem_op(ent->ed25519_key, ==, "it was true that all the master\n", 32); + tt_mem_op(ent->ed25519_key, ==, "it was tru\xa5 that all the master\n", 32); /* File truncated before NL */ const char data3[] = "Tm8gZHJhZ29uIGNhbiByZXNpc3Q IHRoZSBmYXNjaW5hdGlvbiBvZiByaWRkbGluZyB0YWw"; tt_int_op(0, ==, keypin_load_journal_impl(data3, strlen(data3))); - tt_int_op(12, ==, smartlist_len(mock_addent_got)); - ent = smartlist_get(mock_addent_got, 11); + tt_int_op(14, ==, smartlist_len(mock_addent_got)); + ent = smartlist_get(mock_addent_got, 13); tt_mem_op(ent->rsa_id, ==, "No dragon can resist", 20); tt_mem_op(ent->ed25519_key, ==, " the fascination of riddling tal", 32); @@ -131,7 +131,8 @@ test_keypin_parse_file(void *arg) smartlist_free(mock_addent_got); } -#define ADD(a,b) keypin_check_and_add((const uint8_t*)(a),(const uint8_t*)(b)) +#define ADD(a,b) keypin_check_and_add((const uint8_t*)(a),\ + (const uint8_t*)(b),0) #define LONE_RSA(a) keypin_check_lone_rsa((const uint8_t*)(a)) static void diff --git a/src/test/test_ntor.sh b/src/test/test_ntor.sh new file mode 100755 index 0000000000..5081dabc54 --- /dev/null +++ b/src/test/test_ntor.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# Validate Tor's ntor implementation. + +exitcode=0 + +"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/ntor_ref.py" test-tor || exitcode=1 +"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/ntor_ref.py" self-test || exitcode=1 + +exit ${exitcode} diff --git a/src/test/test_ntor.sh.in b/src/test/test_ntor.sh.in deleted file mode 100644 index be35384ddf..0000000000 --- a/src/test/test_ntor.sh.in +++ /dev/null @@ -1,9 +0,0 @@ -#!@SHELL@ -# Validate Tor's ntor implementation. - -exitcode=0 - -@PYTHON@ @abs_top_srcdir@/src/test/ntor_ref.py test-tor || exitcode=1 -@PYTHON@ @abs_top_srcdir@/src/test/ntor_ref.py self-test || exitcode=1 - -exit ${exitcode} diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 33f90c7da5..37c36fed99 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -49,7 +49,7 @@ test_policy_summary_helper(const char *policy_str, r = policies_parse_exit_policy(&line, &policy, EXIT_POLICY_IPV6_ENABLED | - EXIT_POLICY_ADD_DEFAULT ,0); + EXIT_POLICY_ADD_DEFAULT, 0, NULL, 0); tt_int_op(r,OP_EQ, 0); summary = policy_summarize(policy, AF_INET); @@ -77,18 +77,21 @@ test_policies_general(void *arg) int i; smartlist_t *policy = NULL, *policy2 = NULL, *policy3 = NULL, *policy4 = NULL, *policy5 = NULL, *policy6 = NULL, - *policy7 = NULL; + *policy7 = NULL, *policy8 = NULL, *policy9 = NULL, + *policy10 = NULL, *policy11 = NULL, *policy12 = NULL; addr_policy_t *p; tor_addr_t tar; config_line_t line; smartlist_t *sm = NULL; char *policy_str = NULL; short_policy_t *short_parsed = NULL; + int malformed_list = -1; (void)arg; policy = smartlist_new(); - p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); + p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*", -1, + &malformed_list); tt_assert(p != NULL); tt_int_op(ADDR_POLICY_REJECT,OP_EQ, p->policy_type); tor_addr_from_ipv4h(&tar, 0xc0a80000u); @@ -112,68 +115,122 @@ test_policies_general(void *arg) tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy2, EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_REJECT_PRIVATE | - EXIT_POLICY_ADD_DEFAULT, 0)); + EXIT_POLICY_ADD_DEFAULT, 0, + NULL, 0)); tt_assert(policy2); + tor_addr_parse(&tar, "[2000::1234]"); + tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy12, + EXIT_POLICY_IPV6_ENABLED | + EXIT_POLICY_REJECT_PRIVATE | + EXIT_POLICY_ADD_DEFAULT, + 0x0306090cu, &tar, 1)); + + tt_assert(policy12); + policy3 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("reject *:*",-1); + p = router_parse_addr_policy_item_from_string("reject *:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy3, p); - p = router_parse_addr_policy_item_from_string("accept *:*",-1); + p = router_parse_addr_policy_item_from_string("accept *:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy3, p); policy4 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept *:443",-1); + p = router_parse_addr_policy_item_from_string("accept *:443", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy4, p); - p = router_parse_addr_policy_item_from_string("accept *:443",-1); + p = router_parse_addr_policy_item_from_string("accept *:443", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy4, p); policy5 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1); + p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1); + p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1); + p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); + p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*", + -1, &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1); + p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1); + p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1); + p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1); + p = router_parse_addr_policy_item_from_string("reject *:1-65534", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject *:65535",-1); + p = router_parse_addr_policy_item_from_string("reject *:65535", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1); + p = router_parse_addr_policy_item_from_string("accept *:1-65535", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); policy6 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1); + p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy6, p); policy7 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1); + p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy7, p); + tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy8, + EXIT_POLICY_IPV6_ENABLED | + EXIT_POLICY_REJECT_PRIVATE | + EXIT_POLICY_ADD_DEFAULT, 0, + NULL, 0)); + + tt_assert(policy8); + + tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy9, + EXIT_POLICY_REJECT_PRIVATE | + EXIT_POLICY_ADD_DEFAULT, 0, + NULL, 0)); + + tt_assert(policy9); + + /* accept6 * and reject6 * produce IPv6 wildcards only */ + policy10 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("accept6 *:*", -1, + &malformed_list); + tt_assert(p != NULL); + smartlist_add(policy10, p); + + policy11 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("reject6 *:*", -1, + &malformed_list); + tt_assert(p != NULL); + smartlist_add(policy11, p); + tt_assert(!exit_policy_is_general_exit(policy)); tt_assert(exit_policy_is_general_exit(policy2)); tt_assert(!exit_policy_is_general_exit(NULL)); @@ -182,6 +239,10 @@ test_policies_general(void *arg) tt_assert(!exit_policy_is_general_exit(policy5)); tt_assert(!exit_policy_is_general_exit(policy6)); tt_assert(!exit_policy_is_general_exit(policy7)); + tt_assert(exit_policy_is_general_exit(policy8)); + tt_assert(exit_policy_is_general_exit(policy9)); + tt_assert(!exit_policy_is_general_exit(policy10)); + tt_assert(!exit_policy_is_general_exit(policy11)); tt_assert(cmp_addr_policies(policy, policy2)); tt_assert(cmp_addr_policies(policy, NULL)); @@ -190,7 +251,12 @@ test_policies_general(void *arg) tt_assert(!policy_is_reject_star(policy2, AF_INET)); tt_assert(policy_is_reject_star(policy, AF_INET)); + tt_assert(policy_is_reject_star(policy10, AF_INET)); + tt_assert(!policy_is_reject_star(policy10, AF_INET6)); + tt_assert(policy_is_reject_star(policy11, AF_INET)); + tt_assert(policy_is_reject_star(policy11, AF_INET6)); tt_assert(policy_is_reject_star(NULL, AF_INET)); + tt_assert(policy_is_reject_star(NULL, AF_INET6)); addr_policy_list_free(policy); policy = NULL; @@ -202,7 +268,8 @@ test_policies_general(void *arg) line.next = NULL; tt_int_op(0, OP_EQ, policies_parse_exit_policy(&line,&policy, EXIT_POLICY_IPV6_ENABLED | - EXIT_POLICY_ADD_DEFAULT,0)); + EXIT_POLICY_ADD_DEFAULT, 0, + NULL, 0)); tt_assert(policy); //test_streq(policy->string, "accept *:80"); @@ -297,6 +364,68 @@ test_policies_general(void *arg) TT_BAD_SHORT_POLICY("accept 1-,3"); TT_BAD_SHORT_POLICY("accept 1-,3"); + /* Make sure that IPv4 addresses are ignored in accept6/reject6 lines. */ + p = router_parse_addr_policy_item_from_string("accept6 1.2.3.4:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(!malformed_list); + + p = router_parse_addr_policy_item_from_string("reject6 2.4.6.0/24:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(!malformed_list); + + p = router_parse_addr_policy_item_from_string("accept6 *4:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(!malformed_list); + + /* Make sure malformed policies are detected as such. */ + p = router_parse_addr_policy_item_from_string("bad_token *4:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("accept6 **:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("accept */15:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("reject6 */:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("accept 127.0.0.1/33:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("accept6 [::1]/129:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("reject 8.8.8.8/-1:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("reject 8.8.4.4:10-5", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("reject 1.2.3.4:-1", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + /* Test a too-long policy. */ { int i; @@ -347,6 +476,11 @@ test_policies_general(void *arg) addr_policy_list_free(policy5); addr_policy_list_free(policy6); addr_policy_list_free(policy7); + addr_policy_list_free(policy8); + addr_policy_list_free(policy9); + addr_policy_list_free(policy10); + addr_policy_list_free(policy11); + addr_policy_list_free(policy12); tor_free(policy_str); if (sm) { SMARTLIST_FOREACH(sm, char *, s, tor_free(s)); @@ -360,6 +494,7 @@ test_dump_exit_policy_to_string(void *arg) { char *ep; addr_policy_t *policy_entry; + int malformed_list = -1; routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t)); @@ -376,7 +511,8 @@ test_dump_exit_policy_to_string(void *arg) ri->exit_policy = smartlist_new(); ri->policy_is_reject_star = 0; - policy_entry = router_parse_addr_policy_item_from_string("accept *:*",-1); + policy_entry = router_parse_addr_policy_item_from_string("accept *:*", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); @@ -386,7 +522,8 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); - policy_entry = router_parse_addr_policy_item_from_string("reject *:25",-1); + policy_entry = router_parse_addr_policy_item_from_string("reject *:25", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); @@ -397,7 +534,8 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); policy_entry = - router_parse_addr_policy_item_from_string("reject 8.8.8.8:*",-1); + router_parse_addr_policy_item_from_string("reject 8.8.8.8:*", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); @@ -407,7 +545,8 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); policy_entry = - router_parse_addr_policy_item_from_string("reject6 [FC00::]/7:*",-1); + router_parse_addr_policy_item_from_string("reject6 [FC00::]/7:*", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); @@ -418,7 +557,8 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); policy_entry = - router_parse_addr_policy_item_from_string("accept6 [c000::]/3:*",-1); + router_parse_addr_policy_item_from_string("accept6 [c000::]/3:*", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c index 9bd0c125c3..74b39c0486 100644 --- a/src/test/test_routerset.c +++ b/src/test/test_routerset.c @@ -423,14 +423,14 @@ NS(test_main)(void *arg) } #undef NS_SUBMODULE -#define NS_SUBMODULE ASPECT(routerset_parse, policy) +#define NS_SUBMODULE ASPECT(routerset_parse, policy_wildcard) /* - * Structural test for routerset_parse, when given a valid policy. + * Structural test for routerset_parse, when given a valid wildcard policy. */ NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string, - (const char *s, int assume_action)); + (const char *s, int assume_action, int *malformed_list)); addr_policy_t *NS(mock_addr_policy); @@ -457,16 +457,113 @@ NS(test_main)(void *arg) } addr_policy_t * -NS(router_parse_addr_policy_item_from_string)(const char *s, int assume_action) +NS(router_parse_addr_policy_item_from_string)(const char *s, + int assume_action, + int *malformed_list) { (void)s; (void)assume_action; + (void)malformed_list; CALLED(router_parse_addr_policy_item_from_string)++; return NS(mock_addr_policy); } #undef NS_SUBMODULE +#define NS_SUBMODULE ASPECT(routerset_parse, policy_ipv4) + +/* + * Structural test for routerset_parse, when given a valid IPv4 address + * literal policy. + */ + +NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string, + (const char *s, int assume_action, int *bogus)); + +addr_policy_t *NS(mock_addr_policy); + +static void +NS(test_main)(void *arg) +{ + routerset_t *set; + const char *s; + int r; + (void)arg; + + NS_MOCK(router_parse_addr_policy_item_from_string); + NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t)); + + set = routerset_new(); + s = "127.0.0.1"; + r = routerset_parse(set, s, ""); + tt_int_op(r, OP_EQ, 0); + tt_int_op(smartlist_len(set->policies), OP_NE, 0); + tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1); + + done: + routerset_free(set); +} + +addr_policy_t * +NS(router_parse_addr_policy_item_from_string)(const char *s, int assume_action, + int *bogus) +{ + (void)s; + (void)assume_action; + CALLED(router_parse_addr_policy_item_from_string)++; + *bogus = 0; + + return NS(mock_addr_policy); +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE ASPECT(routerset_parse, policy_ipv6) + +/* + * Structural test for routerset_parse, when given a valid IPv6 address + * literal policy. + */ + +NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string, + (const char *s, int assume_action, int *bad)); + +addr_policy_t *NS(mock_addr_policy); + +static void +NS(test_main)(void *arg) +{ + routerset_t *set; + const char *s; + int r; + (void)arg; + + NS_MOCK(router_parse_addr_policy_item_from_string); + NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t)); + + set = routerset_new(); + s = "::1"; + r = routerset_parse(set, s, ""); + tt_int_op(r, OP_EQ, 0); + tt_int_op(smartlist_len(set->policies), OP_NE, 0); + tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1); + + done: + routerset_free(set); +} + +addr_policy_t * +NS(router_parse_addr_policy_item_from_string)(const char *s, + int assume_action, int *bad) +{ + (void)s; + (void)assume_action; + CALLED(router_parse_addr_policy_item_from_string)++; + *bad = 0; + + return NS(mock_addr_policy); +} + +#undef NS_SUBMODULE #define NS_SUBMODULE ASPECT(routerset_union, source_bad) /* @@ -2106,7 +2203,9 @@ struct testcase_t routerset_tests[] = { TEST_CASE_ASPECT(routerset_parse, valid_hexdigest), TEST_CASE_ASPECT(routerset_parse, valid_nickname), TEST_CASE_ASPECT(routerset_parse, get_countryname), - TEST_CASE_ASPECT(routerset_parse, policy), + TEST_CASE_ASPECT(routerset_parse, policy_wildcard), + TEST_CASE_ASPECT(routerset_parse, policy_ipv4), + TEST_CASE_ASPECT(routerset_parse, policy_ipv6), TEST_CASE(routerset_subtract_nodes), TEST_CASE_ASPECT(routerset_subtract_nodes, null_routerset), TEST_CASE(routerset_to_string), diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c new file mode 100644 index 0000000000..2e53293373 --- /dev/null +++ b/src/test/test_tortls.c @@ -0,0 +1,2950 @@ +/* Copyright (c) 2010-2015, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define TORTLS_PRIVATE +#define LOG_PRIVATE +#include "orconfig.h" + +#ifdef _WIN32 +#include <winsock2.h> +#endif + +#ifdef __GNUC__ +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + +#if __GNUC__ && GCC_VERSION >= 402 +#if GCC_VERSION >= 406 +#pragma GCC diagnostic push +#endif +/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in + * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + +#include <openssl/opensslv.h> + +#include <openssl/ssl.h> +#include <openssl/ssl3.h> +#include <openssl/err.h> +#include <openssl/asn1t.h> +#include <openssl/x509.h> +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/bn.h> + +#if __GNUC__ && GCC_VERSION >= 402 +#if GCC_VERSION >= 406 +#pragma GCC diagnostic pop +#else +#pragma GCC diagnostic warning "-Wredundant-decls" +#endif +#endif + +#include "or.h" +#include "torlog.h" +#include "config.h" +#include "tortls.h" + +#include "test.h" +#include "log_test_helpers.h" +#define NS_MODULE tortls + +extern tor_tls_context_t *server_tls_context; +extern tor_tls_context_t *client_tls_context; + +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) +#define OPENSSL_OPAQUE +#endif + +#ifndef OPENSSL_OPAQUE +static SSL_METHOD * +give_me_a_test_method(void) +{ + SSL_METHOD *method = tor_malloc_zero(sizeof(SSL_METHOD)); + memcpy(method, TLSv1_method(), sizeof(SSL_METHOD)); + return method; +} + +static int +fake_num_ciphers(void) +{ + return 0; +} +#endif + +static void +test_tortls_errno_to_tls_error(void *data) +{ + (void) data; + tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(ECONNRESET)),OP_EQ, + TOR_TLS_ERROR_CONNRESET); + tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(ETIMEDOUT)),OP_EQ, + TOR_TLS_ERROR_TIMEOUT); + tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(EHOSTUNREACH)),OP_EQ, + TOR_TLS_ERROR_NO_ROUTE); + tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(ENETUNREACH)),OP_EQ, + TOR_TLS_ERROR_NO_ROUTE); + tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(ECONNREFUSED)),OP_EQ, + TOR_TLS_ERROR_CONNREFUSED); + tt_int_op(tor_errno_to_tls_error(0),OP_EQ,TOR_TLS_ERROR_MISC); + done: + (void)1; +} + +static void +test_tortls_err_to_string(void *data) +{ + (void) data; + tt_str_op(tor_tls_err_to_string(1),OP_EQ,"[Not an error.]"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_MISC),OP_EQ,"misc error"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_IO),OP_EQ,"unexpected close"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_CONNREFUSED),OP_EQ, + "connection refused"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_CONNRESET),OP_EQ, + "connection reset"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_NO_ROUTE),OP_EQ, + "host unreachable"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_TIMEOUT),OP_EQ, + "connection timed out"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_CLOSE),OP_EQ,"closed"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_WANTREAD),OP_EQ,"want to read"); + tt_str_op(tor_tls_err_to_string(TOR_TLS_WANTWRITE),OP_EQ,"want to write"); + tt_str_op(tor_tls_err_to_string(-100),OP_EQ,"(unknown error code)"); + done: + (void)1; +} + +static int +mock_tls_cert_matches_key(const tor_tls_t *tls, const tor_x509_cert_t *cert) +{ + (void) tls; + (void) cert; // XXXX look at this. + return 1; +} + +static void +test_tortls_tor_tls_new(void *data) +{ + (void) data; + MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key); + crypto_pk_t *key1 = NULL, *key2 = NULL; + key1 = pk_generate(2); + key2 = pk_generate(3); + + tor_tls_t *tls; + tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER, + key1, key2, 86400), OP_EQ, 0); + tls = tor_tls_new(-1, 0); + tt_want(tls); + + client_tls_context->ctx = NULL; + tls = tor_tls_new(-1, 0); + tt_assert(!tls); + +#ifndef OPENSSL_OPAQUE + SSL_METHOD *method = give_me_a_test_method(); + SSL_CTX *ctx = SSL_CTX_new(method); + method->num_ciphers = fake_num_ciphers; + client_tls_context->ctx = ctx; + tls = tor_tls_new(-1, 0); + tt_assert(!tls); +#endif + + done: + UNMOCK(tor_tls_cert_matches_key); + crypto_pk_free(key1); + crypto_pk_free(key2); +} + +#define NS_MODULE tortls +NS_DECL(void, logv, (int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, + const char *format, va_list ap)); + +static void +NS(logv)(int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, + va_list ap) +{ + (void) severity; + (void) domain; + (void) funcname; + (void) suffix; + (void) format; + (void) ap; // XXXX look at this. + CALLED(logv)++; +} + +static void +test_tortls_tor_tls_get_error(void *data) +{ + (void) data; + MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key); + crypto_pk_t *key1 = NULL, *key2 = NULL; + key1 = pk_generate(2); + key2 = pk_generate(3); + + tor_tls_t *tls; + tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER, + key1, key2, 86400), OP_EQ, 0); + tls = tor_tls_new(-1, 0); + NS_MOCK(logv); + tt_int_op(CALLED(logv), OP_EQ, 0); + tor_tls_get_error(tls, 0, 0, + (const char *)"test", 0, 0); + tt_int_op(CALLED(logv), OP_EQ, 1); + + done: + UNMOCK(tor_tls_cert_matches_key); + NS_UNMOCK(logv); + crypto_pk_free(key1); + crypto_pk_free(key2); +} + +static void +test_tortls_get_state_description(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + char *buf; + SSL_CTX *ctx; + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(SSLv23_method()); + + buf = tor_malloc_zero(1000); + tls = tor_malloc_zero(sizeof(tor_tls_t)); + + tor_tls_get_state_description(NULL, buf, 20); + tt_str_op(buf, OP_EQ, "(No SSL object)"); + + tls->ssl = NULL; + tor_tls_get_state_description(tls, buf, 20); + tt_str_op(buf, OP_EQ, "(No SSL object)"); + + tls->ssl = SSL_new(ctx); + tor_tls_get_state_description(tls, buf, 200); + tt_str_op(buf, OP_EQ, "before/accept initialization in HANDSHAKE"); + + tls->state = TOR_TLS_ST_OPEN; + tor_tls_get_state_description(tls, buf, 200); + tt_str_op(buf, OP_EQ, "before/accept initialization in OPEN"); + + tls->state = TOR_TLS_ST_GOTCLOSE; + tor_tls_get_state_description(tls, buf, 200); + tt_str_op(buf, OP_EQ, "before/accept initialization in GOTCLOSE"); + + tls->state = TOR_TLS_ST_SENTCLOSE; + tor_tls_get_state_description(tls, buf, 200); + tt_str_op(buf, OP_EQ, "before/accept initialization in SENTCLOSE"); + + tls->state = TOR_TLS_ST_CLOSED; + tor_tls_get_state_description(tls, buf, 200); + tt_str_op(buf, OP_EQ, "before/accept initialization in CLOSED"); + + tls->state = TOR_TLS_ST_RENEGOTIATE; + tor_tls_get_state_description(tls, buf, 200); + tt_str_op(buf, OP_EQ, "before/accept initialization in RENEGOTIATE"); + + tls->state = TOR_TLS_ST_BUFFEREVENT; + tor_tls_get_state_description(tls, buf, 200); + tt_str_op(buf, OP_EQ, "before/accept initialization"); + + tls->state = 7; + tor_tls_get_state_description(tls, buf, 200); + tt_str_op(buf, OP_EQ, "before/accept initialization in unknown TLS state"); + + done: + SSL_CTX_free(ctx); + tor_free(buf); + tor_free(tls); +} + +extern int tor_tls_object_ex_data_index; + +static void +test_tortls_get_by_ssl(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + tor_tls_t *res; + SSL_CTX *ctx; + SSL *ssl; + + SSL_library_init(); + SSL_load_error_strings(); + tor_tls_allocate_tor_tls_object_ex_data_index(); + + ctx = SSL_CTX_new(SSLv23_method()); + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->magic = TOR_TLS_MAGIC; + + ssl = SSL_new(ctx); + + res = tor_tls_get_by_ssl(ssl); + tt_assert(!res); + + SSL_set_ex_data(ssl, tor_tls_object_ex_data_index, tls); + + res = tor_tls_get_by_ssl(ssl); + tt_assert(res == tls); + + done: + SSL_free(ssl); + SSL_CTX_free(ctx); + tor_free(tls); +} + +static void +test_tortls_allocate_tor_tls_object_ex_data_index(void *ignored) +{ + (void)ignored; + int first; + + tor_tls_allocate_tor_tls_object_ex_data_index(); + + first = tor_tls_object_ex_data_index; + tor_tls_allocate_tor_tls_object_ex_data_index(); + tt_int_op(first, OP_EQ, tor_tls_object_ex_data_index); + + done: + (void)0; +} + +static void +test_tortls_log_one_error(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + SSL_CTX *ctx; + SSL *ssl = NULL; + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(SSLv23_method()); + tls = tor_malloc_zero(sizeof(tor_tls_t)); + int previous_log = setup_capture_of_logs(LOG_INFO); + + tor_tls_log_one_error(NULL, 0, LOG_WARN, 0, "something"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error while something: " + "(null) (in (null):(null):---)\n"); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error: (null) " + "(in (null):(null):---)\n"); + + mock_clean_saved_logs(); + tls->address = tor_strdup("127.hello"); + tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error with 127.hello: (null) " + "(in (null):(null):---)\n"); + + mock_clean_saved_logs(); + tls->address = tor_strdup("127.hello"); + tor_tls_log_one_error(tls, 0, LOG_WARN, 0, "blarg"); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error while blarg with " + "127.hello: (null) (in (null):(null):---)\n"); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, ERR_PACK(1, 2, 3), LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error with 127.hello: " + "BN lib (in unknown library:(null):---)\n"); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_HTTP_REQUEST), + LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_HTTPS_PROXY_REQUEST), + LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_LENGTH_MISMATCH), + LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_TOO_LARGE), + LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNKNOWN_PROTOCOL), + LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNSUPPORTED_PROTOCOL), + LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + + tls->ssl = SSL_new(ctx); + + mock_clean_saved_logs(); + tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error with 127.hello: (null)" + " (in (null):(null):before/accept initialization)\n"); + + done: + teardown_capture_of_logs(previous_log); + SSL_free(ssl); + SSL_CTX_free(ctx); + tor_free(tls); +} + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_get_error(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + int ret; + SSL_CTX *ctx; + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(SSLv23_method()); + int previous_log = setup_capture_of_logs(LOG_INFO); + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = SSL_new(ctx); + SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL); + + ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_IO); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error: unexpected close while" + " something (before/accept initialization)\n"); + + mock_clean_saved_logs(); + ret = tor_tls_get_error(tls, 2, 0, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(mock_saved_log_number(), OP_EQ, 0); + + mock_clean_saved_logs(); + ret = tor_tls_get_error(tls, 0, 1, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, -11); + tt_int_op(mock_saved_log_number(), OP_EQ, 0); + + mock_clean_saved_logs(); + ERR_clear_error(); + ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99); + ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error while something: (null)" + " (in bignum routines:(null):before/accept initialization)\n"); + + mock_clean_saved_logs(); + ERR_clear_error(); + tls->ssl->rwstate = SSL_READING; + SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_READ; + ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, TOR_TLS_WANTREAD); + tt_int_op(mock_saved_log_number(), OP_EQ, 0); + + mock_clean_saved_logs(); + ERR_clear_error(); + tls->ssl->rwstate = SSL_READING; + SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_WRITE; + ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, TOR_TLS_WANTWRITE); + tt_int_op(mock_saved_log_number(), OP_EQ, 0); + + mock_clean_saved_logs(); + ERR_clear_error(); + tls->ssl->rwstate = 0; + tls->ssl->shutdown = SSL_RECEIVED_SHUTDOWN; + tls->ssl->s3->warn_alert =SSL_AD_CLOSE_NOTIFY; + ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, TOR_TLS_CLOSE); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + + mock_clean_saved_logs(); + ret = tor_tls_get_error(tls, 0, 2, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, -10); + tt_int_op(mock_saved_log_number(), OP_EQ, 0); + + mock_clean_saved_logs(); + ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99); + ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0); + tt_int_op(ret, OP_EQ, -9); + tt_int_op(mock_saved_log_number(), OP_EQ, 2); + tt_str_op(mock_saved_log_at(1), OP_EQ, + "TLS error while something: (null) (in system library:" + "connect:before/accept initialization)\n"); + + done: + teardown_capture_of_logs(previous_log); + tor_free(tls); +} +#endif + +static void +test_tortls_always_accept_verify_cb(void *ignored) +{ + (void)ignored; + int ret; + + ret = always_accept_verify_cb(0, NULL); + tt_int_op(ret, OP_EQ, 1); + + done: + (void)0; +} + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_x509_cert_free(void *ignored) +{ + (void)ignored; + tor_x509_cert_t *cert; + + cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); + tor_x509_cert_free(cert); + + cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); + cert->cert = tor_malloc_zero(sizeof(X509)); + cert->encoded = tor_malloc_zero(1); + tor_x509_cert_free(cert); +} +#endif + +static void +test_tortls_x509_cert_get_id_digests(void *ignored) +{ + (void)ignored; + tor_x509_cert_t *cert; + digests_t *d; + const digests_t *res; + cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); + d = tor_malloc_zero(sizeof(digests_t)); + d->d[0][0] = 42; + + res = tor_x509_cert_get_id_digests(cert); + tt_assert(!res); + + cert->pkey_digests_set = 1; + cert->pkey_digests = *d; + res = tor_x509_cert_get_id_digests(cert); + tt_int_op(res->d[0][0], OP_EQ, 42); + + done: + (void)0; +} + +#ifndef OPENSSL_OPAQUE +static int +fixed_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) +{ + (void) a; (void) b; + return 1; +} + +static void +test_tortls_cert_matches_key(void *ignored) +{ + (void)ignored; + int res; + tor_tls_t *tls; + tor_x509_cert_t *cert; + X509 *one, *two; + EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_new(999, 0, NULL, NULL); + EVP_PKEY_asn1_set_public(meth, NULL, NULL, fixed_pub_cmp, NULL, NULL, NULL); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); + one = tor_malloc_zero(sizeof(X509)); + one->references = 1; + two = tor_malloc_zero(sizeof(X509)); + two->references = 1; + + res = tor_tls_cert_matches_key(tls, cert); + tt_int_op(res, OP_EQ, 0); + + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); + tls->ssl->session->peer = one; + res = tor_tls_cert_matches_key(tls, cert); + tt_int_op(res, OP_EQ, 0); + + cert->cert = two; + res = tor_tls_cert_matches_key(tls, cert); + tt_int_op(res, OP_EQ, 0); + + one->cert_info = tor_malloc_zero(sizeof(X509_CINF)); + one->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY)); + one->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY)); + one->cert_info->key->pkey->references = 1; + one->cert_info->key->pkey->ameth = meth; + one->cert_info->key->pkey->type = 1; + + two->cert_info = tor_malloc_zero(sizeof(X509_CINF)); + two->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY)); + two->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY)); + two->cert_info->key->pkey->references = 1; + two->cert_info->key->pkey->ameth = meth; + two->cert_info->key->pkey->type = 2; + + res = tor_tls_cert_matches_key(tls, cert); + tt_int_op(res, OP_EQ, 0); + + one->cert_info->key->pkey->type = 1; + two->cert_info->key->pkey->type = 1; + res = tor_tls_cert_matches_key(tls, cert); + tt_int_op(res, OP_EQ, 1); + + done: + EVP_PKEY_asn1_free(meth); + tor_free(tls); + tor_free(cert); +} + +static void +test_tortls_cert_get_key(void *ignored) +{ + (void)ignored; + tor_x509_cert_t *cert; + crypto_pk_t *res; + cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); + X509 *key; + key = tor_malloc_zero(sizeof(X509)); + key->references = 1; + + res = tor_tls_cert_get_key(cert); + tt_assert(!res); + + cert->cert = key; + key->cert_info = tor_malloc_zero(sizeof(X509_CINF)); + key->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY)); + key->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY)); + key->cert_info->key->pkey->references = 1; + key->cert_info->key->pkey->type = 2; + res = tor_tls_cert_get_key(cert); + tt_assert(!res); + + done: + (void)0; +} +#endif + +static void +test_tortls_get_my_client_auth_key(void *ignored) +{ + (void)ignored; + crypto_pk_t *ret; + crypto_pk_t *expected; + tor_tls_context_t *ctx; + RSA *k = tor_malloc_zero(sizeof(RSA)); + + ctx = tor_malloc_zero(sizeof(tor_tls_context_t)); + expected = crypto_new_pk_from_rsa_(k); + ctx->auth_key = expected; + + client_tls_context = NULL; + ret = tor_tls_get_my_client_auth_key(); + tt_assert(!ret); + + client_tls_context = ctx; + ret = tor_tls_get_my_client_auth_key(); + tt_assert(ret == expected); + + done: + tor_free(expected); + tor_free(k); + tor_free(ctx); +} + +static void +test_tortls_get_my_certs(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_context_t *ctx; + const tor_x509_cert_t *link_cert_out = NULL; + const tor_x509_cert_t *id_cert_out = NULL; + + ctx = tor_malloc_zero(sizeof(tor_tls_context_t)); + + client_tls_context = NULL; + ret = tor_tls_get_my_certs(0, NULL, NULL); + tt_int_op(ret, OP_EQ, -1); + + server_tls_context = NULL; + ret = tor_tls_get_my_certs(1, NULL, NULL); + tt_int_op(ret, OP_EQ, -1); + + client_tls_context = ctx; + ret = tor_tls_get_my_certs(0, NULL, NULL); + tt_int_op(ret, OP_EQ, 0); + + client_tls_context = ctx; + ret = tor_tls_get_my_certs(0, &link_cert_out, &id_cert_out); + tt_int_op(ret, OP_EQ, 0); + + server_tls_context = ctx; + ret = tor_tls_get_my_certs(1, &link_cert_out, &id_cert_out); + tt_int_op(ret, OP_EQ, 0); + + done: + (void)1; +} + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_get_ciphersuite_name(void *ignored) +{ + (void)ignored; + const char *ret; + tor_tls_t *ctx; + ctx = tor_malloc_zero(sizeof(tor_tls_t)); + ctx->ssl = tor_malloc_zero(sizeof(SSL)); + + ret = tor_tls_get_ciphersuite_name(ctx); + tt_str_op(ret, OP_EQ, "(NONE)"); + + done: + (void)1; +} + +static SSL_CIPHER * +get_cipher_by_name(const char *name) +{ + int i; + const SSL_METHOD *method = SSLv23_method(); + int num = method->num_ciphers(); + for (i = 0; i < num; ++i) { + const SSL_CIPHER *cipher = method->get_cipher(i); + const char *ciphername = SSL_CIPHER_get_name(cipher); + if (!strcmp(ciphername, name)) { + return (SSL_CIPHER *)cipher; + } + } + + return NULL; +} + +static SSL_CIPHER * +get_cipher_by_id(uint16_t id) +{ + int i; + const SSL_METHOD *method = SSLv23_method(); + int num = method->num_ciphers(); + for (i = 0; i < num; ++i) { + const SSL_CIPHER *cipher = method->get_cipher(i); + if (id == (SSL_CIPHER_get_id(cipher) & 0xffff)) { + return (SSL_CIPHER *)cipher; + } + } + + return NULL; +} + +extern uint16_t v2_cipher_list[]; + +static void +test_tortls_classify_client_ciphers(void *ignored) +{ + (void)ignored; + int i; + int ret; + SSL_CTX *ctx; + SSL *ssl; + tor_tls_t *tls; + STACK_OF(SSL_CIPHER) *ciphers; + SSL_CIPHER *tmp_cipher; + + SSL_library_init(); + SSL_load_error_strings(); + tor_tls_allocate_tor_tls_object_ex_data_index(); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->magic = TOR_TLS_MAGIC; + + ctx = SSL_CTX_new(TLSv1_method()); + ssl = SSL_new(ctx); + tls->ssl = ssl; + + ciphers = sk_SSL_CIPHER_new_null(); + + ret = tor_tls_classify_client_ciphers(ssl, NULL); + tt_int_op(ret, OP_EQ, -1); + + SSL_set_ex_data(ssl, tor_tls_object_ex_data_index, tls); + tls->client_cipher_list_type = 42; + + ret = tor_tls_classify_client_ciphers(ssl, NULL); + tt_int_op(ret, OP_EQ, 42); + + tls->client_cipher_list_type = 0; + ret = tor_tls_classify_client_ciphers(ssl, ciphers); + tt_int_op(ret, OP_EQ, 1); + tt_int_op(tls->client_cipher_list_type, OP_EQ, 1); + + tls->client_cipher_list_type = 0; + ret = tor_tls_classify_client_ciphers(ssl, SSL_get_ciphers(ssl)); + tt_int_op(ret, OP_EQ, 3); + tt_int_op(tls->client_cipher_list_type, OP_EQ, 3); + + SSL_CIPHER *one = get_cipher_by_name(TLS1_TXT_DHE_RSA_WITH_AES_128_SHA), + *two = get_cipher_by_name(TLS1_TXT_DHE_RSA_WITH_AES_256_SHA), + *three = get_cipher_by_name(SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA), + *four = NULL; + sk_SSL_CIPHER_push(ciphers, one); + sk_SSL_CIPHER_push(ciphers, two); + sk_SSL_CIPHER_push(ciphers, three); + sk_SSL_CIPHER_push(ciphers, four); + + tls->client_cipher_list_type = 0; + ret = tor_tls_classify_client_ciphers(ssl, ciphers); + tt_int_op(ret, OP_EQ, 1); + tt_int_op(tls->client_cipher_list_type, OP_EQ, 1); + + sk_SSL_CIPHER_zero(ciphers); + + one = get_cipher_by_name("ECDH-RSA-AES256-GCM-SHA384"); + one->id = 0x00ff; + two = get_cipher_by_name("ECDH-RSA-AES128-GCM-SHA256"); + two->id = 0x0000; + sk_SSL_CIPHER_push(ciphers, one); + tls->client_cipher_list_type = 0; + ret = tor_tls_classify_client_ciphers(ssl, ciphers); + tt_int_op(ret, OP_EQ, 3); + tt_int_op(tls->client_cipher_list_type, OP_EQ, 3); + + sk_SSL_CIPHER_push(ciphers, two); + tls->client_cipher_list_type = 0; + ret = tor_tls_classify_client_ciphers(ssl, ciphers); + tt_int_op(ret, OP_EQ, 3); + tt_int_op(tls->client_cipher_list_type, OP_EQ, 3); + + one->id = 0xC00A; + tls->client_cipher_list_type = 0; + ret = tor_tls_classify_client_ciphers(ssl, ciphers); + tt_int_op(ret, OP_EQ, 3); + tt_int_op(tls->client_cipher_list_type, OP_EQ, 3); + + sk_SSL_CIPHER_zero(ciphers); + for (i=0; v2_cipher_list[i]; i++) { + tmp_cipher = get_cipher_by_id(v2_cipher_list[i]); + tt_assert(tmp_cipher); + sk_SSL_CIPHER_push(ciphers, tmp_cipher); + } + tls->client_cipher_list_type = 0; + ret = tor_tls_classify_client_ciphers(ssl, ciphers); + tt_int_op(ret, OP_EQ, 2); + tt_int_op(tls->client_cipher_list_type, OP_EQ, 2); + + done: + (void)1; +} +#endif + +static void +test_tortls_client_is_using_v2_ciphers(void *ignored) +{ + (void)ignored; + +#ifdef HAVE_SSL_GET_CLIENT_CIPHERS + tt_skip(); +#else + + int ret; + SSL_CTX *ctx; + SSL *ssl; + SSL_SESSION *sess; + STACK_OF(SSL_CIPHER) *ciphers; + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(TLSv1_method()); + ssl = SSL_new(ctx); + sess = SSL_SESSION_new(); + + ret = tor_tls_client_is_using_v2_ciphers(ssl); + tt_int_op(ret, OP_EQ, -1); + + ssl->session = sess; + ret = tor_tls_client_is_using_v2_ciphers(ssl); + tt_int_op(ret, OP_EQ, 0); + + ciphers = sk_SSL_CIPHER_new_null(); + SSL_CIPHER *one = get_cipher_by_name("ECDH-RSA-AES256-GCM-SHA384"); + one->id = 0x00ff; + sk_SSL_CIPHER_push(ciphers, one); + sess->ciphers = ciphers; + ret = tor_tls_client_is_using_v2_ciphers(ssl); + tt_int_op(ret, OP_EQ, 1); +#endif + + done: + (void)1; +} + +#ifndef OPENSSL_OPAQUE +static X509 *fixed_try_to_extract_certs_from_tls_cert_out_result = NULL; +static X509 *fixed_try_to_extract_certs_from_tls_id_cert_out_result = NULL; + +static void +fixed_try_to_extract_certs_from_tls(int severity, tor_tls_t *tls, + X509 **cert_out, X509 **id_cert_out) +{ + (void) severity; + (void) tls; + *cert_out = fixed_try_to_extract_certs_from_tls_cert_out_result; + *id_cert_out = fixed_try_to_extract_certs_from_tls_id_cert_out_result; +} +#endif + +#ifndef OPENSSL_OPAQUE +static const char* notCompletelyValidCertString = + "-----BEGIN CERTIFICATE-----\n" + "MIICVjCCAb8CAg37MA0GCSqGSIb3DQEBBQUAMIGbMQswCQYDVQQGEwJKUDEOMAwG\n" + "A1UECBMFVG9reW8xEDAOBgNVBAcTB0NodW8ta3UxETAPBgNVBAoTCEZyYW5rNERE\n" + "MRgwFgYDVQQLEw9XZWJDZXJ0IFN1cHBvcnQxGDAWBgNVBAMTD0ZyYW5rNEREIFdl\n" + "YiBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmcmFuazRkZC5jb20wHhcNMTIw\n" + "ODIyMDUyNzIzWhcNMTcwODIxMDUyNzIzWjBKMQswCQYDVQQGEwJKUDEOMAwGA1UE\n" + "CAwFVG9reW8xETAPBgNVBAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBs\n" + "ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYBBrx5PlP0WNI/ZdzD\n" + "+6Pktmurn+F2kQYbtc7XQh8/LTBvCo+P6iZoLEmUA9e7EXLRxgU1CVqeAi7QcAn9\n" + "MwBlc8ksFJHB0rtf9pmf8Oza9E0Bynlq/4/Kb1x+d+AyhL7oK9tQwB24uHOueHi1\n" + "C/iVv8CSWKiYe6hzN1txYe8rAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAASPdjigJ\n" + "kXCqKWpnZ/Oc75EUcMi6HztaW8abUMlYXPIgkV2F7YanHOB7K4f7OOLjiz8DTPFf\n" + "jC9UeuErhaA/zzWi8ewMTFZW/WshOrm3fNvcMrMLKtH534JKvcdMg6qIdjTFINIr\n" + "evnAhf0cwULaebn+lMs8Pdl7y37+sfluVok=\n" + "-----END CERTIFICATE-----\n"; +#endif + +static const char* validCertString = "-----BEGIN CERTIFICATE-----\n" + "MIIDpTCCAY0CAg3+MA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMREwDwYD\n" + "VQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIGA1UECgwLVG9yIFRl\n" + "c3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkwNjEzMzk1OVoXDTQz\n" + "MDEyMjEzMzk1OVowVjELMAkGA1UEBhMCVVMxEDAOBgNVBAcMB0NoaWNhZ28xFDAS\n" + "BgNVBAoMC1RvciBUZXN0aW5nMR8wHQYDVQQDDBZ0ZXN0aW5nLnRvcnByb2plY3Qu\n" + "b3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoT6uyVVhWyOF3wkHjjYbd\n" + "nKaykyRv4JVtKQdZ4OpEErmX1zw4MmyzpQNV6iR4bQnWiyLfzyVJMZDIC/WILBfX\n" + "w2Pza/yuLgUvDc3twMuhOACzOQVO8PrEF/aVv2+hbCCy2udXvKhnYn+CCXl3ozc8\n" + "XcKYvujTXDyvGWY3xwAjlQIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQCUvnhzQWuQ\n" + "MrN+pERkE+zcTI/9dGS90rUMMLgu8VDNqTa0TUQh8uO0EQ6uDvI8Js6e8tgwS0BR\n" + "UBahqb7ZHv+rejGCBr5OudqD+x4STiiuPNJVs86JTLN8SpM9CHjIBH5WCCN2KOy3\n" + "mevNoRcRRyYJzSFULCunIK6FGulszigMYGscrO4oiTkZiHPh9KvWT40IMiHfL+Lw\n" + "EtEWiLex6064LcA2YQ1AMuSZyCexks63lcfaFmQbkYOKqXa1oLkIRuDsOaSVjTfe\n" + "vec+X6jvf12cFTKS5WIeqkKF2Irt+dJoiHEGTe5RscUMN/f+gqHPzfFz5dR23sxo\n" + "g+HC6MZHlFkLAOx3wW6epPS8A/m1mw3zMPoTnb2U2YYt8T0dJMMlUn/7Y1sEAa+a\n" + "dSTMaeUf6VnJ//11m454EZl1to9Z7oJOgqmFffSrdD4BGIWe8f7hhW6L1Enmqe/J\n" + "BKL3wbzZh80O1W0bndAwhnEEhlzneFY84cbBo9pmVxpODHkUcStpr5Z7pBDrcL21\n" + "Ss/aB/1YrsVXhdvJdOGxl3Mnl9dUY57CympLGlT8f0pPS6GAKOelECOhFMHmJd8L\n" + "dj3XQSmKtYHevZ6IvuMXSlB/fJvSjSlkCuLo5+kJoaqPuRu+i/S1qxeRy3CBwmnE\n" + "LdSNdcX4N79GQJ996PA8+mUCQG7YRtK+WA==\n" + "-----END CERTIFICATE-----\n"; + +static const char* caCertString = "-----BEGIN CERTIFICATE-----\n" + "MIIFjzCCA3egAwIBAgIJAKd5WgyfPMYRMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV\n" + "BAYTAlVTMREwDwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIG\n" + "A1UECgwLVG9yIFRlc3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkw\n" + "NjEzMzc0MVoXDTQzMDEyMjEzMzc0MVowXjELMAkGA1UEBhMCVVMxETAPBgNVBAgM\n" + "CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRQwEgYDVQQKDAtUb3IgVGVzdGlu\n" + "ZzEUMBIGA1UEAwwLVG9yIFRlc3RpbmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" + "ggIKAoICAQCpLMUEiLW5leUgBZoEJms2V7lZRhIAjnJBhVMHD0e3UubNknmaQoxf\n" + "ARz3rvqOaRd0JlV+qM9qE0DjiYcCVP1cAfqAo9d83uS1vwY3YMVJzADlaIiHfyVW\n" + "uEgBy0vvkeUBqaua24dYlcwsemOiXYLu41yM1wkcGHW1AhBNHppY6cznb8TyLgNM\n" + "2x3SGUdzc5XMyAFx51faKGBA3wjs+Hg1PLY7d30nmCgEOBavpm5I1disM/0k+Mcy\n" + "YmAKEo/iHJX/rQzO4b9znP69juLlR8PDBUJEVIG/CYb6+uw8MjjUyiWXYoqfVmN2\n" + "hm/lH8b6rXw1a2Aa3VTeD0DxaWeacMYHY/i01fd5n7hCoDTRNdSw5KJ0L3Z0SKTu\n" + "0lzffKzDaIfyZGlpW5qdouACkWYzsaitQOePVE01PIdO30vUfzNTFDfy42ccx3Di\n" + "59UCu+IXB+eMtrBfsok0Qc63vtF1linJgjHW1z/8ujk8F7/qkOfODhk4l7wngc2A\n" + "EmwWFIFoGaiTEZHB9qteXr4unbXZ0AHpM02uGGwZEGohjFyebEb73M+J57WKKAFb\n" + "PqbLcGUksL1SHNBNAJcVLttX55sO4nbidOS/kA3m+F1R04MBTyQF9qA6YDDHqdI3\n" + "h/3pw0Z4fxVouTYT4/NfRnX4JTP4u+7Mpcoof28VME0qWqD1LnRhFQIDAQABo1Aw\n" + "TjAdBgNVHQ4EFgQUMoAgIXH7pZ3QMRwTjT+DM9Yo/v0wHwYDVR0jBBgwFoAUMoAg\n" + "IXH7pZ3QMRwTjT+DM9Yo/v0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n" + "AgEAUJxacjXR9sT+Xs6ISFiUsyd0T6WVKMnV46xrYJHirGfx+krWHrjxMY+ZtxYD\n" + "DBDGlo11Qc4v6QrclNf5QUBfIiGQsP9Cm6hHcQ+Tpg9HHCgSqG1YNPwCPReCR4br\n" + "BLvLfrfkcBL2IWM0PdQdCze+59DBfipsULD2mEn9fjYRXQEwb2QWtQ9qRc20Yb/x\n" + "Q4b/+CvUodLkaq7B8MHz0BV8HHcBoph6DYaRmO/N+hPauIuSp6XyaGYcEefGKVKj\n" + "G2+fcsdyXsoijNdL8vNKwm4j2gVwCBnw16J00yfFoV46YcbfqEdJB2je0XSvwXqt\n" + "14AOTngxso2h9k9HLtrfpO1ZG/B5AcCMs1lzbZ2fp5DPHtjvvmvA2RJqgo3yjw4W\n" + "4DHAuTglYFlC3mDHNfNtcGP20JvepcQNzNP2UzwcpOc94hfKikOFw+gf9Vf1qd0y\n" + "h/Sk6OZHn2+JVUPiWHIQV98Vtoh4RmUZDJD+b55ia3fQGTGzt4z1XFzQYSva5sfs\n" + "wocS/papthqWldQU7x+3wofNd5CNU1x6WKXG/yw30IT/4F8ADJD6GeygNT8QJYvt\n" + "u/8lAkbOy6B9xGmSvr0Kk1oq9P2NshA6kalxp1Oz/DTNDdL4AeBXV3JmM6WWCjGn\n" + "Yy1RT69d0rwYc5u/vnqODz1IjvT90smsrkBumGt791FAFeg=\n" + "-----END CERTIFICATE-----\n"; + +static X509 * +read_cert_from(const char *str) +{ + BIO *bio = BIO_new(BIO_s_mem()); + BIO_write(bio, str, (int) strlen(str)); + X509 *res = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + return res; +} + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_verify(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + crypto_pk_t *k = NULL; + X509 *cert1 = NULL, *cert2 = NULL, *invalidCert = NULL, + *validCert = NULL, *caCert = NULL; + + cert1 = tor_malloc_zero(sizeof(X509)); + cert1->references = 10; + + cert2 = tor_malloc_zero(sizeof(X509)); + cert2->references = 10; + + validCert = read_cert_from(validCertString); + caCert = read_cert_from(caCertString); + invalidCert = read_cert_from(notCompletelyValidCertString); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + ret = tor_tls_verify(LOG_WARN, tls, &k); + tt_int_op(ret, OP_EQ, -1); + + MOCK(try_to_extract_certs_from_tls, fixed_try_to_extract_certs_from_tls); + + fixed_try_to_extract_certs_from_tls_cert_out_result = cert1; + ret = tor_tls_verify(LOG_WARN, tls, &k); + tt_int_op(ret, OP_EQ, -1); + + fixed_try_to_extract_certs_from_tls_id_cert_out_result = cert2; + ret = tor_tls_verify(LOG_WARN, tls, &k); + tt_int_op(ret, OP_EQ, -1); + + fixed_try_to_extract_certs_from_tls_cert_out_result = invalidCert; + fixed_try_to_extract_certs_from_tls_id_cert_out_result = invalidCert; + + ret = tor_tls_verify(LOG_WARN, tls, &k); + tt_int_op(ret, OP_EQ, -1); + + fixed_try_to_extract_certs_from_tls_cert_out_result = validCert; + fixed_try_to_extract_certs_from_tls_id_cert_out_result = caCert; + + ret = tor_tls_verify(LOG_WARN, tls, &k); + tt_int_op(ret, OP_EQ, 0); + tt_assert(k); + + done: + UNMOCK(try_to_extract_certs_from_tls); + tor_free(cert1); + tor_free(cert2); + tor_free(tls); + tor_free(k); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_check_lifetime(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + X509 *validCert = read_cert_from(validCertString); + time_t now = time(NULL); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, 0); + tt_int_op(ret, OP_EQ, -1); + + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); + tls->ssl->session->peer = validCert; + ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, 0); + tt_int_op(ret, OP_EQ, 0); + + validCert->cert_info->validity->notBefore = ASN1_TIME_set(NULL, now-10); + validCert->cert_info->validity->notAfter = ASN1_TIME_set(NULL, now+60); + + ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, -1000); + tt_int_op(ret, OP_EQ, -1); + + ret = tor_tls_check_lifetime(LOG_WARN, tls, -1000, 0); + tt_int_op(ret, OP_EQ, -1); + + done: + tor_free(tls->ssl->session); + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +static int fixed_ssl_pending_result = 0; + +static int +fixed_ssl_pending(const SSL *ignored) +{ + (void)ignored; + return fixed_ssl_pending_result; +} + +static void +test_tortls_get_pending_bytes(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + SSL_METHOD *method; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + method = tor_malloc_zero(sizeof(SSL_METHOD)); + method->ssl_pending = fixed_ssl_pending; + tls->ssl->method = method; + + fixed_ssl_pending_result = 42; + ret = tor_tls_get_pending_bytes(tls); + tt_int_op(ret, OP_EQ, 42); + + done: + tor_free(method); + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +static void +test_tortls_get_forced_write_size(void *ignored) +{ + (void)ignored; + long ret; + tor_tls_t *tls; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + + tls->wantwrite_n = 43; + ret = tor_tls_get_forced_write_size(tls); + tt_int_op(ret, OP_EQ, 43); + + done: + tor_free(tls); +} + +extern uint64_t total_bytes_written_over_tls; +extern uint64_t total_bytes_written_by_tls; + +static void +test_tortls_get_write_overhead_ratio(void *ignored) +{ + (void)ignored; + double ret; + + total_bytes_written_over_tls = 0; + ret = tls_get_write_overhead_ratio(); + tt_int_op(ret, OP_EQ, 1.0); + + total_bytes_written_by_tls = 10; + total_bytes_written_over_tls = 1; + ret = tls_get_write_overhead_ratio(); + tt_int_op(ret, OP_EQ, 10.0); + + total_bytes_written_by_tls = 10; + total_bytes_written_over_tls = 2; + ret = tls_get_write_overhead_ratio(); + tt_int_op(ret, OP_EQ, 5.0); + + done: + (void)0; +} + +static void +test_tortls_used_v1_handshake(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + tls = tor_malloc_zero(sizeof(tor_tls_t)); + + // These tests assume both V2 handshake server and client are enabled + tls->wasV2Handshake = 0; + ret = tor_tls_used_v1_handshake(tls); + tt_int_op(ret, OP_EQ, 1); + + tls->wasV2Handshake = 1; + ret = tor_tls_used_v1_handshake(tls); + tt_int_op(ret, OP_EQ, 0); + + done: + tor_free(tls); +} + +static void +test_tortls_dn_indicates_v3_cert(void *ignored) +{ + (void)ignored; + int ret; + X509_NAME *name; + + name = X509_NAME_new(); + X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, + (const unsigned char *)"US", -1, -1, 0); + X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, + (const unsigned char *)"Foobar", -1, -1, 0); + ret = dn_indicates_v3_cert(name); + tt_int_op(ret, OP_EQ, 1); + + X509_NAME_free(name); + name = X509_NAME_new(); + X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, + (const unsigned char *)"US", -1, -1, 0); + ret = dn_indicates_v3_cert(name); + tt_int_op(ret, OP_EQ, 1); + + X509_NAME_free(name); + name = X509_NAME_new(); + X509_NAME_add_entry_by_txt(name, "commonName", V_ASN1_REAL, + (const unsigned char *)"123", -1, -1, 0); + ret = dn_indicates_v3_cert(name); + tt_int_op(ret, OP_EQ, 0); + + X509_NAME_free(name); + name = X509_NAME_new(); + X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC, + (const unsigned char *)"hello.com", -1, -1, 0); + ret = dn_indicates_v3_cert(name); + tt_int_op(ret, OP_EQ, 1); + + X509_NAME_free(name); + name = X509_NAME_new(); + X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC, + (const unsigned char *)"hello.net", -1, -1, 0); + ret = dn_indicates_v3_cert(name); + tt_int_op(ret, OP_EQ, 0); + + X509_NAME_free(name); + name = X509_NAME_new(); + X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC, + (const unsigned char *)"x.s", -1, -1, 0); + ret = dn_indicates_v3_cert(name); + tt_int_op(ret, OP_EQ, 1); + + done: + X509_NAME_free(name); +} + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_received_v3_certificate(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + X509 *validCert = read_cert_from(validCertString); + X509_NAME *subject=NULL, *issuer=NULL; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); + + ret = tor_tls_received_v3_certificate(tls); + tt_int_op(ret, OP_EQ, 0); + + tls->ssl->session->peer = validCert; + + subject = X509_NAME_new(); + X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC, + (const unsigned char *)"same.com", -1, -1, 0); + X509_set_subject_name(validCert, subject); + + issuer = X509_NAME_new(); + X509_NAME_add_entry_by_txt(issuer, "commonName", MBSTRING_ASC, + (const unsigned char *)"same.com", -1, -1, 0); + X509_set_issuer_name(validCert, issuer); + + ret = tor_tls_received_v3_certificate(tls); + tt_int_op(ret, OP_EQ, 1); + + X509_NAME_free(subject); + subject = X509_NAME_new(); + X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC, + (const unsigned char *)"different.net", -1, -1, 0); + X509_set_subject_name(validCert, subject); + + ret = tor_tls_received_v3_certificate(tls); + tt_int_op(ret, OP_EQ, 1); + + X509_NAME_free(subject); + subject = X509_NAME_new(); + X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC, + (const unsigned char *)"same.com", -1, -1, 0); + X509_set_subject_name(validCert, subject); + + X509_NAME_free(issuer); + issuer = X509_NAME_new(); + X509_NAME_add_entry_by_txt(issuer, "commonName", MBSTRING_ASC, + (const unsigned char *)"different.net", -1, -1, 0); + X509_set_issuer_name(validCert, issuer); + + ret = tor_tls_received_v3_certificate(tls); + tt_int_op(ret, OP_EQ, 1); + + X509_NAME_free(subject); + subject = X509_NAME_new(); + X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC, + (const unsigned char *)"different2.net", -1, -1, 0); + X509_set_subject_name(validCert, subject); + ret = tor_tls_received_v3_certificate(tls); + tt_int_op(ret, OP_EQ, 0); + + EVP_PKEY *key = X509_get_pubkey(validCert); + key->type = 5; + ret = tor_tls_received_v3_certificate(tls); + tt_int_op(ret, OP_EQ, 1); + + key->type = 6; + key->ameth = NULL; + ret = tor_tls_received_v3_certificate(tls); + tt_int_op(ret, OP_EQ, 1); + + done: + X509_NAME_free(subject); + X509_NAME_free(issuer); + tor_free(tls->ssl->session); + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +static void +test_tortls_get_num_server_handshakes(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + + tls->server_handshake_count = 3; + ret = tor_tls_get_num_server_handshakes(tls); + tt_int_op(ret, OP_EQ, 3); + + done: + tor_free(tls); +} + +static void +test_tortls_server_got_renegotiate(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + + tls->got_renegotiate = 1; + ret = tor_tls_server_got_renegotiate(tls); + tt_int_op(ret, OP_EQ, 1); + + done: + tor_free(tls); +} + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_SSL_SESSION_get_master_key(void *ignored) +{ + (void)ignored; + size_t ret; + tor_tls_t *tls; + uint8_t *out; + out = tor_malloc_zero(1); + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); + tls->ssl->session->master_key_length = 1; + +#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY + tls->ssl->session->master_key[0] = 43; + ret = SSL_SESSION_get_master_key(tls->ssl->session, out, 0); + tt_int_op(ret, OP_EQ, 1); + tt_int_op(out[0], OP_EQ, 0); + + ret = SSL_SESSION_get_master_key(tls->ssl->session, out, 1); + tt_int_op(ret, OP_EQ, 1); + tt_int_op(out[0], OP_EQ, 43); + + done: +#endif + tor_free(tls->ssl->session); + tor_free(tls->ssl); + tor_free(tls); + tor_free(out); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_get_tlssecrets(void *ignored) +{ + (void)ignored; + int ret; + uint8_t *secret_out = tor_malloc_zero(DIGEST256_LEN);; + tor_tls_t *tls; + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); + tls->ssl->session->master_key_length = 1; + tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE)); + + ret = tor_tls_get_tlssecrets(tls, secret_out); + tt_int_op(ret, OP_EQ, 0); + + done: + tor_free(secret_out); + tor_free(tls->ssl->s3); + tor_free(tls->ssl->session); + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_get_buffer_sizes(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + size_t rbuf_c=-1, rbuf_b=-1, wbuf_c=-1, wbuf_b=-1; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE)); + + tls->ssl->s3->rbuf.buf = NULL; + tls->ssl->s3->rbuf.len = 1; + tls->ssl->s3->rbuf.offset = 0; + tls->ssl->s3->rbuf.left = 42; + + tls->ssl->s3->wbuf.buf = NULL; + tls->ssl->s3->wbuf.len = 2; + tls->ssl->s3->wbuf.offset = 0; + tls->ssl->s3->wbuf.left = 43; + +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) + ret = tor_tls_get_buffer_sizes(NULL, NULL, NULL, NULL, NULL); + tt_int_op(ret, OP_EQ, -1); +#else + ret = tor_tls_get_buffer_sizes(tls, &rbuf_c, &rbuf_b, &wbuf_c, &wbuf_b); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(rbuf_c, OP_EQ, 0); + tt_int_op(wbuf_c, OP_EQ, 0); + tt_int_op(rbuf_b, OP_EQ, 42); + tt_int_op(wbuf_b, OP_EQ, 43); + + tls->ssl->s3->rbuf.buf = tor_malloc_zero(1); + tls->ssl->s3->wbuf.buf = tor_malloc_zero(1); + ret = tor_tls_get_buffer_sizes(tls, &rbuf_c, &rbuf_b, &wbuf_c, &wbuf_b); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(rbuf_c, OP_EQ, 1); + tt_int_op(wbuf_c, OP_EQ, 2); + +#endif + + done: + tor_free(tls->ssl->s3->rbuf.buf); + tor_free(tls->ssl->s3->wbuf.buf); + tor_free(tls->ssl->s3); + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +static void +test_tortls_evaluate_ecgroup_for_tls(void *ignored) +{ + (void)ignored; + int ret; + + ret = evaluate_ecgroup_for_tls(NULL); + tt_int_op(ret, OP_EQ, 1); + + ret = evaluate_ecgroup_for_tls("foobar"); + tt_int_op(ret, OP_EQ, 0); + + ret = evaluate_ecgroup_for_tls("P256"); + tt_int_op(ret, OP_EQ, 1); + + ret = evaluate_ecgroup_for_tls("P224"); + // tt_int_op(ret, OP_EQ, 1); This varies between machines + + done: + (void)0; +} + +#ifndef OPENSSL_OPAQUE +typedef struct cert_pkey_st_local +{ + X509 *x509; + EVP_PKEY *privatekey; + const EVP_MD *digest; +} CERT_PKEY_local; + +typedef struct sess_cert_st_local +{ + STACK_OF(X509) *cert_chain; + int peer_cert_type; + CERT_PKEY_local *peer_key; + CERT_PKEY_local peer_pkeys[8]; + int references; +} SESS_CERT_local; + +static void +test_tortls_try_to_extract_certs_from_tls(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + X509 *cert = NULL, *id_cert = NULL, *c1 = NULL, *c2 = NULL; + SESS_CERT_local *sess = NULL; + + c1 = read_cert_from(validCertString); + c2 = read_cert_from(caCertString); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); + sess = tor_malloc_zero(sizeof(SESS_CERT_local)); + tls->ssl->session->sess_cert = (void *)sess; + + try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert); + tt_assert(!cert); + tt_assert(!id_cert); + + tls->ssl->session->peer = c1; + try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert); + tt_assert(cert == c1); + tt_assert(!id_cert); + + sess->cert_chain = sk_X509_new_null(); + try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert); + tt_assert(cert == c1); + tt_assert(!id_cert); + + sk_X509_push(sess->cert_chain, c1); + sk_X509_push(sess->cert_chain, c2); + try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert); + tt_assert(cert == c1); + tt_assert(id_cert); + + done: + tor_free(sess); + tor_free(tls->ssl->session); + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_get_peer_cert(void *ignored) +{ + (void)ignored; + tor_x509_cert_t *ret; + tor_tls_t *tls; + X509 *cert = NULL; + + cert = read_cert_from(validCertString); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); + + ret = tor_tls_get_peer_cert(tls); + tt_assert(!ret); + + tls->ssl->session->peer = cert; + ret = tor_tls_get_peer_cert(tls); + tt_assert(ret); + tt_assert(ret->cert == cert); + + done: + tor_x509_cert_free(ret); + tor_free(tls->ssl->session); + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_peer_has_cert(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + X509 *cert = NULL; + + cert = read_cert_from(validCertString); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); + + ret = tor_tls_peer_has_cert(tls); + tt_assert(!ret); + + tls->ssl->session->peer = cert; + ret = tor_tls_peer_has_cert(tls); + tt_assert(ret); + + done: + tor_free(tls->ssl->session); + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +static void +test_tortls_is_server(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + int ret; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->isServer = 1; + ret = tor_tls_is_server(tls); + tt_int_op(ret, OP_EQ, 1); + + done: + tor_free(tls); +} + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_session_secret_cb(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + SSL_CTX *ctx; + STACK_OF(SSL_CIPHER) *ciphers = NULL; + SSL_CIPHER *one; + + SSL_library_init(); + SSL_load_error_strings(); + tor_tls_allocate_tor_tls_object_ex_data_index(); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + + tls->magic = TOR_TLS_MAGIC; + + ctx = SSL_CTX_new(TLSv1_method()); + tls->ssl = SSL_new(ctx); + SSL_set_ex_data(tls->ssl, tor_tls_object_ex_data_index, tls); + + SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL); + + tor_tls_session_secret_cb(tls->ssl, NULL, NULL, NULL, NULL, NULL); + tt_assert(!tls->ssl->tls_session_secret_cb); + + one = get_cipher_by_name("ECDH-RSA-AES256-GCM-SHA384"); + one->id = 0x00ff; + ciphers = sk_SSL_CIPHER_new_null(); + sk_SSL_CIPHER_push(ciphers, one); + + tls->client_cipher_list_type = 0; + tor_tls_session_secret_cb(tls->ssl, NULL, NULL, ciphers, NULL, NULL); + tt_assert(!tls->ssl->tls_session_secret_cb); + + done: + sk_SSL_CIPHER_free(ciphers); + SSL_free(tls->ssl); + SSL_CTX_free(ctx); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +/* TODO: It seems block_renegotiation and unblock_renegotiation and + * using different blags. This might not be correct */ +static void +test_tortls_block_renegotiation(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE)); + tls->ssl->s3->flags = 0x0010; + + tor_tls_block_renegotiation(tls); + + tt_assert(!(SSL_get_options(tls->ssl) & 0x0010)); + + done: + tor_free(tls->ssl); + tor_free(tls); +} + +static void +test_tortls_unblock_renegotiation(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tor_tls_unblock_renegotiation(tls); + + tt_assert(SSL_get_options(tls->ssl) & 0x00040000L); + + done: + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_assert_renegotiation_unblocked(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tor_tls_unblock_renegotiation(tls); + tor_tls_assert_renegotiation_unblocked(tls); + /* No assertion here - this test will fail if tor_assert is turned on + * and things are bad. */ + + tor_free(tls); +} +#endif + +static void +test_tortls_set_logged_address(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + + tor_tls_set_logged_address(tls, "foo bar"); + + tt_str_op(tls->address, OP_EQ, "foo bar"); + + tor_tls_set_logged_address(tls, "foo bar 2"); + tt_str_op(tls->address, OP_EQ, "foo bar 2"); + + done: + tor_free(tls); +} + +#ifndef OPENSSL_OPAQUE +static void +example_cb(tor_tls_t *t, void *arg) +{ + (void)t; + (void)arg; +} + +static void +test_tortls_set_renegotiate_callback(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + const char *arg = "hello"; + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + + tor_tls_set_renegotiate_callback(tls, example_cb, (void*)arg); + tt_assert(tls->negotiated_callback == example_cb); + tt_assert(tls->callback_arg == arg); + tt_assert(!tls->got_renegotiate); + + /* Assumes V2_HANDSHAKE_SERVER */ + tt_assert(tls->ssl->info_callback == tor_tls_server_info_callback); + + tor_tls_set_renegotiate_callback(tls, NULL, (void*)arg); + tt_assert(tls->ssl->info_callback == tor_tls_debug_state_callback); + + done: + tor_free(tls->ssl); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +static const SSL_CIPHER * +fake_get_cipher(unsigned ncipher) +{ + SSL_CIPHER *fixed = tor_malloc_zero(sizeof(SSL_CIPHER)); + SSL_CIPHER *fixed2 = tor_malloc_zero(sizeof(SSL_CIPHER)); + fixed2->id = 0xC00A; + switch (ncipher) { + case 1: + return fixed; + case 2: + return fixed2; + default: + return NULL; + } +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_find_cipher_by_id(void *ignored) +{ + (void)ignored; + int ret; + SSL *ssl; + SSL_CTX *ctx; + const SSL_METHOD *m = TLSv1_method(); + SSL_METHOD *empty_method = tor_malloc_zero(sizeof(SSL_METHOD)); + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(m); + ssl = SSL_new(ctx); + + ret = find_cipher_by_id(ssl, NULL, 0xC00A); + tt_int_op(ret, OP_EQ, 1); + + ret = find_cipher_by_id(ssl, m, 0xC00A); + tt_int_op(ret, OP_EQ, 1); + + ret = find_cipher_by_id(ssl, m, 0xFFFF); + tt_int_op(ret, OP_EQ, 0); + + ret = find_cipher_by_id(ssl, empty_method, 0xC00A); + tt_int_op(ret, OP_EQ, 1); + + ret = find_cipher_by_id(ssl, empty_method, 0xFFFF); +#ifdef HAVE_SSL_CIPHER_FIND + tt_int_op(ret, OP_EQ, 0); +#else + tt_int_op(ret, OP_EQ, 1); +#endif + + empty_method->get_cipher = fake_get_cipher; + ret = find_cipher_by_id(ssl, empty_method, 0xC00A); + tt_int_op(ret, OP_EQ, 1); + + empty_method->get_cipher = m->get_cipher; + empty_method->num_ciphers = m->num_ciphers; + ret = find_cipher_by_id(ssl, empty_method, 0xC00A); + tt_int_op(ret, OP_EQ, 1); + + empty_method->get_cipher = fake_get_cipher; + empty_method->num_ciphers = m->num_ciphers; + ret = find_cipher_by_id(ssl, empty_method, 0xC00A); + tt_int_op(ret, OP_EQ, 1); + + empty_method->num_ciphers = fake_num_ciphers; + ret = find_cipher_by_id(ssl, empty_method, 0xC00A); +#ifdef HAVE_SSL_CIPHER_FIND + tt_int_op(ret, OP_EQ, 1); +#else + tt_int_op(ret, OP_EQ, 0); +#endif + + done: + tor_free(empty_method); + SSL_free(ssl); + SSL_CTX_free(ctx); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_debug_state_callback(void *ignored) +{ + (void)ignored; + SSL *ssl; + char *buf = tor_malloc_zero(1000); + int n; + + int previous_log = setup_capture_of_logs(LOG_DEBUG); + + ssl = tor_malloc_zero(sizeof(SSL)); + + tor_tls_debug_state_callback(ssl, 32, 45); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + n = snprintf(buf, 1000, "SSL %p is now in state unknown" + " state [type=32,val=45].\n", ssl); + buf[n]='\0'; + if (strcasecmp(mock_saved_log_at(0), buf)) + tt_str_op(mock_saved_log_at(0), OP_EQ, buf); + + done: + teardown_capture_of_logs(previous_log); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_server_info_callback(void *ignored) +{ + (void)ignored; + tor_tls_t *tls; + SSL_CTX *ctx; + SSL *ssl; + int previous_log = setup_capture_of_logs(LOG_WARN); + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(TLSv1_method()); + ssl = SSL_new(ctx); + + tor_tls_allocate_tor_tls_object_ex_data_index(); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->magic = TOR_TLS_MAGIC; + tls->ssl = ssl; + + tor_tls_server_info_callback(NULL, 0, 0); + + SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_A); + mock_clean_saved_logs(); + tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, + "Couldn't look up the tls for an SSL*. How odd!\n"); + + SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_B); + mock_clean_saved_logs(); + tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0); + tt_int_op(mock_saved_log_number(), OP_EQ, 1); + tt_str_op(mock_saved_log_at(0), OP_EQ, + "Couldn't look up the tls for an SSL*. How odd!\n"); + + SSL_set_state(ssl, 99); + mock_clean_saved_logs(); + tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0); + tt_int_op(mock_saved_log_number(), OP_EQ, 0); + + SSL_set_ex_data(tls->ssl, tor_tls_object_ex_data_index, tls); + SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_B); + tls->negotiated_callback = 0; + tls->server_handshake_count = 120; + tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0); + tt_int_op(tls->server_handshake_count, OP_EQ, 121); + + tls->server_handshake_count = 127; + tls->negotiated_callback = (void *)1; + tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0); + tt_int_op(tls->server_handshake_count, OP_EQ, 127); + tt_int_op(tls->got_renegotiate, OP_EQ, 1); + + tls->ssl->session = SSL_SESSION_new(); + tls->wasV2Handshake = 0; + tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0); + tt_int_op(tls->wasV2Handshake, OP_EQ, 0); + + done: + teardown_capture_of_logs(previous_log); + tor_free(ssl); +} +#endif + +#ifndef OPENSSL_OPAQUE +static int fixed_ssl_read_result_index; +static int fixed_ssl_read_result[5]; +static int fixed_ssl_shutdown_result; + +static int +fixed_ssl_read(SSL *s, void *buf, int len) +{ + (void)s; + (void)buf; + (void)len; + return fixed_ssl_read_result[fixed_ssl_read_result_index++]; +} + +static int +fixed_ssl_shutdown(SSL *s) +{ + (void)s; + return fixed_ssl_shutdown_result; +} + +static int fixed_ssl_state_to_set; +static tor_tls_t *fixed_tls; + +static int +setting_version_ssl_shutdown(SSL *s) +{ + s->version = SSL2_VERSION; + return fixed_ssl_shutdown_result; +} + +static int +setting_version_and_state_ssl_shutdown(SSL *s) +{ + fixed_tls->state = fixed_ssl_state_to_set; + s->version = SSL2_VERSION; + return fixed_ssl_shutdown_result; +} + +static int +dummy_handshake_func(SSL *s) +{ + (void)s; + return 1; +} + +static void +test_tortls_shutdown(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + SSL_METHOD *method = give_me_a_test_method(); + int previous_log = setup_capture_of_logs(LOG_WARN); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->ssl->method = method; + method->ssl_read = fixed_ssl_read; + method->ssl_shutdown = fixed_ssl_shutdown; + + ret = tor_tls_shutdown(tls); + tt_int_op(ret, OP_EQ, -9); + + tls->state = TOR_TLS_ST_SENTCLOSE; + fixed_ssl_read_result_index = 0; + fixed_ssl_read_result[0] = 10; + fixed_ssl_read_result[1] = -1; + ret = tor_tls_shutdown(tls); + tt_int_op(ret, OP_EQ, -9); + + tls->ssl->handshake_func = dummy_handshake_func; + + fixed_ssl_read_result_index = 0; + fixed_ssl_read_result[0] = 10; + fixed_ssl_read_result[1] = 42; + fixed_ssl_read_result[2] = 0; + fixed_ssl_shutdown_result = 1; + ERR_clear_error(); + tls->ssl->version = SSL2_VERSION; + ret = tor_tls_shutdown(tls); + tt_int_op(ret, OP_EQ, TOR_TLS_DONE); + tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED); + + fixed_ssl_read_result_index = 0; + fixed_ssl_read_result[0] = 10; + fixed_ssl_read_result[1] = 42; + fixed_ssl_read_result[2] = 0; + fixed_ssl_shutdown_result = 0; + ERR_clear_error(); + tls->ssl->version = 0; + ret = tor_tls_shutdown(tls); + tt_int_op(ret, OP_EQ, TOR_TLS_DONE); + tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED); + + fixed_ssl_read_result_index = 0; + fixed_ssl_read_result[0] = 10; + fixed_ssl_read_result[1] = 42; + fixed_ssl_read_result[2] = 0; + fixed_ssl_shutdown_result = 0; + ERR_clear_error(); + tls->ssl->version = 0; + method->ssl_shutdown = setting_version_ssl_shutdown; + ret = tor_tls_shutdown(tls); + tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC); + + fixed_ssl_read_result_index = 0; + fixed_ssl_read_result[0] = 10; + fixed_ssl_read_result[1] = 42; + fixed_ssl_read_result[2] = 0; + fixed_ssl_shutdown_result = 0; + fixed_tls = tls; + fixed_ssl_state_to_set = TOR_TLS_ST_GOTCLOSE; + ERR_clear_error(); + tls->ssl->version = 0; + method->ssl_shutdown = setting_version_and_state_ssl_shutdown; + ret = tor_tls_shutdown(tls); + tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC); + + fixed_ssl_read_result_index = 0; + fixed_ssl_read_result[0] = 10; + fixed_ssl_read_result[1] = 42; + fixed_ssl_read_result[2] = 0; + fixed_ssl_read_result[3] = -1; + fixed_ssl_shutdown_result = 0; + fixed_tls = tls; + fixed_ssl_state_to_set = 0; + ERR_clear_error(); + tls->ssl->version = 0; + method->ssl_shutdown = setting_version_and_state_ssl_shutdown; + ret = tor_tls_shutdown(tls); + tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC); + + done: + teardown_capture_of_logs(previous_log); + tor_free(method); + tor_free(tls->ssl); + tor_free(tls); +} + +static int negotiated_callback_called; + +static void +negotiated_callback_setter(tor_tls_t *t, void *arg) +{ + (void)t; + (void)arg; + negotiated_callback_called++; +} + +static void +test_tortls_read(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + char buf[100]; + SSL_METHOD *method = give_me_a_test_method(); + int previous_log = setup_capture_of_logs(LOG_WARN); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->state = TOR_TLS_ST_OPEN; + + ret = tor_tls_read(tls, buf, 10); + tt_int_op(ret, OP_EQ, -9); + + /* These tests assume that V2_HANDSHAKE_SERVER is set */ + tls->ssl->handshake_func = dummy_handshake_func; + tls->ssl->method = method; + method->ssl_read = fixed_ssl_read; + fixed_ssl_read_result_index = 0; + fixed_ssl_read_result[0] = 42; + tls->state = TOR_TLS_ST_OPEN; + ERR_clear_error(); + ret = tor_tls_read(tls, buf, 10); + tt_int_op(ret, OP_EQ, 42); + + tls->state = TOR_TLS_ST_OPEN; + tls->got_renegotiate = 1; + fixed_ssl_read_result_index = 0; + ERR_clear_error(); + ret = tor_tls_read(tls, buf, 10); + tt_int_op(tls->got_renegotiate, OP_EQ, 0); + + tls->state = TOR_TLS_ST_OPEN; + tls->got_renegotiate = 1; + negotiated_callback_called = 0; + tls->negotiated_callback = negotiated_callback_setter; + fixed_ssl_read_result_index = 0; + ERR_clear_error(); + ret = tor_tls_read(tls, buf, 10); + tt_int_op(negotiated_callback_called, OP_EQ, 1); + + fixed_ssl_read_result_index = 0; + fixed_ssl_read_result[0] = 0; + tls->ssl->version = SSL2_VERSION; + ERR_clear_error(); + ret = tor_tls_read(tls, buf, 10); + tt_int_op(ret, OP_EQ, TOR_TLS_CLOSE); + tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED); + + // TODO: fill up + + done: + teardown_capture_of_logs(previous_log); + tor_free(tls->ssl); + tor_free(tls); +} + +static int fixed_ssl_write_result; + +static int +fixed_ssl_write(SSL *s, const void *buf, int len) +{ + (void)s; + (void)buf; + (void)len; + return fixed_ssl_write_result; +} + +static void +test_tortls_write(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + SSL_METHOD *method = give_me_a_test_method(); + char buf[100]; + int previous_log = setup_capture_of_logs(LOG_WARN); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = tor_malloc_zero(sizeof(SSL)); + tls->state = TOR_TLS_ST_OPEN; + + ret = tor_tls_write(tls, buf, 0); + tt_int_op(ret, OP_EQ, 0); + + ret = tor_tls_write(tls, buf, 10); + tt_int_op(ret, OP_EQ, -9); + + tls->ssl->method = method; + tls->wantwrite_n = 1; + ret = tor_tls_write(tls, buf, 10); + tt_int_op(tls->wantwrite_n, OP_EQ, 0); + + method->ssl_write = fixed_ssl_write; + tls->ssl->handshake_func = dummy_handshake_func; + fixed_ssl_write_result = 1; + ERR_clear_error(); + ret = tor_tls_write(tls, buf, 10); + tt_int_op(ret, OP_EQ, 1); + + fixed_ssl_write_result = -1; + ERR_clear_error(); + tls->ssl->rwstate = SSL_READING; + SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL); + SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_READ; + ret = tor_tls_write(tls, buf, 10); + tt_int_op(ret, OP_EQ, TOR_TLS_WANTREAD); + + ERR_clear_error(); + tls->ssl->rwstate = SSL_READING; + SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL); + SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_WRITE; + ret = tor_tls_write(tls, buf, 10); + tt_int_op(ret, OP_EQ, TOR_TLS_WANTWRITE); + + done: + teardown_capture_of_logs(previous_log); + tor_free(tls->ssl); + tor_free(tls); +} + +static int fixed_ssl_renegotiate_result; + +static int +fixed_ssl_renegotiate(SSL *s) +{ + (void) s; + return fixed_ssl_renegotiate_result; +} + +static void +test_tortls_renegotiate(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + SSL_CTX *ctx; + SSL_METHOD *method = give_me_a_test_method(); + int previous_log = setup_capture_of_logs(LOG_WARN); + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(TLSv1_method()); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = SSL_new(ctx); + tls->state = TOR_TLS_ST_OPEN; + + ret = tor_tls_renegotiate(tls); + tt_int_op(ret, OP_EQ, -9); + + tls->ssl->method = method; + method->ssl_renegotiate = fixed_ssl_renegotiate; + fixed_ssl_renegotiate_result = 0; + ERR_clear_error(); + ret = tor_tls_renegotiate(tls); + tt_int_op(ret, OP_EQ, -9); + + ERR_clear_error(); + tls->ssl->handshake_func = dummy_handshake_func; + tls->state = TOR_TLS_ST_RENEGOTIATE; + ret = tor_tls_renegotiate(tls); + tt_int_op(ret, OP_EQ, TOR_TLS_DONE); + + ERR_clear_error(); + tls->state = TOR_TLS_ST_OPEN; + fixed_ssl_renegotiate_result = -1; + ret = tor_tls_renegotiate(tls); + tt_int_op(ret, OP_EQ, -9); + + done: + teardown_capture_of_logs(previous_log); + SSL_free(tls->ssl); + SSL_CTX_free(ctx); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +static int fixed_ssl_accept_result; +static int fixed_ssl_connect_result; + +static int +setting_error_ssl_accept(SSL *ssl) +{ + (void)ssl; + ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99); + ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99); + return fixed_ssl_accept_result; +} + +static int +setting_error_ssl_connect(SSL *ssl) +{ + (void)ssl; + ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99); + ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99); + return fixed_ssl_connect_result; +} + +static int +fixed_ssl_accept(SSL *ssl) +{ + (void) ssl; + return fixed_ssl_accept_result; +} + +static void +test_tortls_handshake(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + SSL_CTX *ctx; + SSL_METHOD *method = give_me_a_test_method(); + int previous_log = setup_capture_of_logs(LOG_INFO); + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(TLSv1_method()); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = SSL_new(ctx); + tls->state = TOR_TLS_ST_HANDSHAKE; + + ret = tor_tls_handshake(tls); + tt_int_op(ret, OP_EQ, -9); + + tls->isServer = 1; + tls->state = TOR_TLS_ST_HANDSHAKE; + ret = tor_tls_handshake(tls); + tt_int_op(ret, OP_EQ, -9); + + tls->ssl->method = method; + method->ssl_accept = fixed_ssl_accept; + fixed_ssl_accept_result = 2; + ERR_clear_error(); + tls->state = TOR_TLS_ST_HANDSHAKE; + ret = tor_tls_handshake(tls); + tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_OPEN); + + method->ssl_accept = setting_error_ssl_accept; + fixed_ssl_accept_result = 1; + ERR_clear_error(); + mock_clean_saved_logs(); + tls->state = TOR_TLS_ST_HANDSHAKE; + ret = tor_tls_handshake(tls); + tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC); + tt_int_op(mock_saved_log_number(), OP_EQ, 2); + /* This fails on jessie. Investigate why! */ +#if 0 + tt_str_op(mock_saved_log_at(0), OP_EQ, + "TLS error while handshaking: (null) (in bignum routines:" + "(null):SSLv3 write client hello B)\n"); + tt_str_op(mock_saved_log_at(1), OP_EQ, + "TLS error while handshaking: (null) (in system library:" + "connect:SSLv3 write client hello B)\n"); +#endif + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO); + tt_int_op(mock_saved_severity_at(1), OP_EQ, LOG_INFO); + + tls->isServer = 0; + method->ssl_connect = setting_error_ssl_connect; + fixed_ssl_connect_result = 1; + ERR_clear_error(); + mock_clean_saved_logs(); + tls->state = TOR_TLS_ST_HANDSHAKE; + ret = tor_tls_handshake(tls); + tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC); + tt_int_op(mock_saved_log_number(), OP_EQ, 2); +#if 0 + /* See above */ + tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error while handshaking: " + "(null) (in bignum routines:(null):SSLv3 write client hello B)\n"); + tt_str_op(mock_saved_log_at(1), OP_EQ, "TLS error while handshaking: " + "(null) (in system library:connect:SSLv3 write client hello B)\n"); +#endif + tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_WARN); + tt_int_op(mock_saved_severity_at(1), OP_EQ, LOG_WARN); + + done: + teardown_capture_of_logs(previous_log); + SSL_free(tls->ssl); + SSL_CTX_free(ctx); + tor_free(tls); +} +#endif + +#ifndef OPENSSL_OPAQUE +static void +test_tortls_finish_handshake(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_t *tls; + SSL_CTX *ctx; + SSL_METHOD *method = give_me_a_test_method(); + SSL_library_init(); + SSL_load_error_strings(); + + X509 *c1 = read_cert_from(validCertString); + X509 *c2 = read_cert_from(caCertString); + + ctx = SSL_CTX_new(method); + + tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->ssl = SSL_new(ctx); + tls->state = TOR_TLS_ST_OPEN; + + ret = tor_tls_finish_handshake(tls); + tt_int_op(ret, OP_EQ, 0); + + tls->isServer = 1; + tls->wasV2Handshake = 0; + ret = tor_tls_finish_handshake(tls); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(tls->wasV2Handshake, OP_EQ, 1); + + tls->wasV2Handshake = 1; + ret = tor_tls_finish_handshake(tls); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(tls->wasV2Handshake, OP_EQ, 1); + + tls->wasV2Handshake = 1; + tls->ssl->session = SSL_SESSION_new(); + ret = tor_tls_finish_handshake(tls); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(tls->wasV2Handshake, OP_EQ, 0); + + tls->isServer = 0; + + SESS_CERT_local *sess = tor_malloc_zero(sizeof(SESS_CERT_local)); + tls->ssl->session->sess_cert = (void *)sess; + sess->cert_chain = sk_X509_new_null(); + sk_X509_push(sess->cert_chain, c1); + tls->ssl->session->peer = c1; + tls->wasV2Handshake = 0; + ret = tor_tls_finish_handshake(tls); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(tls->wasV2Handshake, OP_EQ, 1); + + tls->ssl->session->peer = c2; + tls->wasV2Handshake = 1; + ret = tor_tls_finish_handshake(tls); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(tls->wasV2Handshake, OP_EQ, 0); + + sk_X509_push(sess->cert_chain, c2); + tls->wasV2Handshake = 1; + ret = tor_tls_finish_handshake(tls); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(tls->wasV2Handshake, OP_EQ, 0); + + method->num_ciphers = fake_num_ciphers; + ret = tor_tls_finish_handshake(tls); + tt_int_op(ret, OP_EQ, -9); + + done: + SSL_CTX_free(ctx); + tor_free(tls); +} +#endif + +static int fixed_crypto_pk_new_result_index; +static crypto_pk_t *fixed_crypto_pk_new_result[5]; + +static crypto_pk_t * +fixed_crypto_pk_new(void) +{ + return fixed_crypto_pk_new_result[fixed_crypto_pk_new_result_index++]; +} + +#ifndef OPENSSL_OPAQUE +static int fixed_crypto_pk_generate_key_with_bits_result_index; +static int fixed_crypto_pk_generate_key_with_bits_result[5]; +static int fixed_tor_tls_create_certificate_result_index; +static X509 *fixed_tor_tls_create_certificate_result[5]; +static int fixed_tor_x509_cert_new_result_index; +static tor_x509_cert_t *fixed_tor_x509_cert_new_result[5]; + +static int +fixed_crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits) +{ + (void)env; + (void)bits; + return fixed_crypto_pk_generate_key_with_bits_result[ + fixed_crypto_pk_generate_key_with_bits_result_index++]; +} + +static X509 * +fixed_tor_tls_create_certificate(crypto_pk_t *rsa, + crypto_pk_t *rsa_sign, + const char *cname, + const char *cname_sign, + unsigned int cert_lifetime) +{ + (void)rsa; + (void)rsa_sign; + (void)cname; + (void)cname_sign; + (void)cert_lifetime; + return fixed_tor_tls_create_certificate_result[ + fixed_tor_tls_create_certificate_result_index++]; +} + +static tor_x509_cert_t * +fixed_tor_x509_cert_new(X509 *x509_cert) +{ + (void) x509_cert; + return fixed_tor_x509_cert_new_result[ + fixed_tor_x509_cert_new_result_index++]; +} + +static void +test_tortls_context_new(void *ignored) +{ + (void)ignored; + tor_tls_context_t *ret; + crypto_pk_t *pk1, *pk2, *pk3, *pk4, *pk5, *pk6, *pk7, *pk8, *pk9, *pk10, + *pk11, *pk12, *pk13, *pk14, *pk15, *pk16, *pk17, *pk18; + + pk1 = crypto_pk_new(); + pk2 = crypto_pk_new(); + pk3 = crypto_pk_new(); + pk4 = crypto_pk_new(); + pk5 = crypto_pk_new(); + pk6 = crypto_pk_new(); + pk7 = crypto_pk_new(); + pk8 = crypto_pk_new(); + pk9 = crypto_pk_new(); + pk10 = crypto_pk_new(); + pk11 = crypto_pk_new(); + pk12 = crypto_pk_new(); + pk13 = crypto_pk_new(); + pk14 = crypto_pk_new(); + pk15 = crypto_pk_new(); + pk16 = crypto_pk_new(); + pk17 = crypto_pk_new(); + pk18 = crypto_pk_new(); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = NULL; + MOCK(crypto_pk_new, fixed_crypto_pk_new); + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + MOCK(crypto_pk_generate_key_with_bits, + fixed_crypto_pk_generate_key_with_bits); + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk1; + fixed_crypto_pk_new_result[1] = NULL; + fixed_crypto_pk_generate_key_with_bits_result[0] = -1; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk2; + fixed_crypto_pk_new_result[1] = NULL; + fixed_crypto_pk_generate_key_with_bits_result[0] = 0; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk3; + fixed_crypto_pk_new_result[1] = pk4; + fixed_crypto_pk_new_result[2] = NULL; + fixed_crypto_pk_generate_key_with_bits_result[0] = 0; + fixed_crypto_pk_generate_key_with_bits_result[1] = -1; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + MOCK(tor_tls_create_certificate, fixed_tor_tls_create_certificate); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk5; + fixed_crypto_pk_new_result[1] = pk6; + fixed_crypto_pk_new_result[2] = NULL; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + fixed_crypto_pk_generate_key_with_bits_result[1] = 0; + fixed_tor_tls_create_certificate_result_index = 0; + fixed_tor_tls_create_certificate_result[0] = NULL; + fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509)); + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk7; + fixed_crypto_pk_new_result[1] = pk8; + fixed_crypto_pk_new_result[2] = NULL; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + fixed_tor_tls_create_certificate_result_index = 0; + fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[1] = NULL; + fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509)); + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk9; + fixed_crypto_pk_new_result[1] = pk10; + fixed_crypto_pk_new_result[2] = NULL; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + fixed_tor_tls_create_certificate_result_index = 0; + fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[2] = NULL; + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + MOCK(tor_x509_cert_new, fixed_tor_x509_cert_new); + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk11; + fixed_crypto_pk_new_result[1] = pk12; + fixed_crypto_pk_new_result[2] = NULL; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + fixed_tor_tls_create_certificate_result_index = 0; + fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509)); + fixed_tor_x509_cert_new_result_index = 0; + fixed_tor_x509_cert_new_result[0] = NULL; + fixed_tor_x509_cert_new_result[1] = NULL; + fixed_tor_x509_cert_new_result[2] = NULL; + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk13; + fixed_crypto_pk_new_result[1] = pk14; + fixed_crypto_pk_new_result[2] = NULL; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + fixed_tor_tls_create_certificate_result_index = 0; + fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509)); + fixed_tor_x509_cert_new_result_index = 0; + fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t)); + fixed_tor_x509_cert_new_result[1] = NULL; + fixed_tor_x509_cert_new_result[2] = NULL; + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk15; + fixed_crypto_pk_new_result[1] = pk16; + fixed_crypto_pk_new_result[2] = NULL; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + fixed_tor_tls_create_certificate_result_index = 0; + fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509)); + fixed_tor_x509_cert_new_result_index = 0; + fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t)); + fixed_tor_x509_cert_new_result[1] = tor_malloc_zero(sizeof(tor_x509_cert_t)); + fixed_tor_x509_cert_new_result[2] = NULL; + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = pk17; + fixed_crypto_pk_new_result[1] = pk18; + fixed_crypto_pk_new_result[2] = NULL; + fixed_crypto_pk_generate_key_with_bits_result_index = 0; + fixed_tor_tls_create_certificate_result_index = 0; + fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509)); + fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509)); + fixed_tor_x509_cert_new_result_index = 0; + fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t)); + fixed_tor_x509_cert_new_result[1] = tor_malloc_zero(sizeof(tor_x509_cert_t)); + fixed_tor_x509_cert_new_result[2] = tor_malloc_zero(sizeof(tor_x509_cert_t)); + ret = tor_tls_context_new(NULL, 0, 0, 0); + tt_assert(!ret); + + done: + UNMOCK(tor_x509_cert_new); + UNMOCK(tor_tls_create_certificate); + UNMOCK(crypto_pk_generate_key_with_bits); + UNMOCK(crypto_pk_new); +} +#endif + +static int fixed_crypto_pk_get_evp_pkey_result_index = 0; +static EVP_PKEY *fixed_crypto_pk_get_evp_pkey_result[5]; +static int fixed_crypto_rand_result; + +static EVP_PKEY * +fixed_crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private) +{ + (void) env; + (void) private; + return fixed_crypto_pk_get_evp_pkey_result[ + fixed_crypto_pk_get_evp_pkey_result_index++]; +} + +static int +fixed_crypto_rand(char *to, size_t n) +{ + (void)to; + (void)n; + return fixed_crypto_rand_result; +} + +static void +test_tortls_create_certificate(void *ignored) +{ + (void)ignored; + X509 *ret; + crypto_pk_t *pk1, *pk2; + + pk1 = crypto_pk_new(); + pk2 = crypto_pk_new(); + + MOCK(crypto_pk_get_evp_pkey_, fixed_crypto_pk_get_evp_pkey_); + fixed_crypto_pk_get_evp_pkey_result_index = 0; + fixed_crypto_pk_get_evp_pkey_result[0] = NULL; + ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1); + tt_assert(!ret); + + fixed_crypto_pk_get_evp_pkey_result_index = 0; + fixed_crypto_pk_get_evp_pkey_result[0] = tor_malloc_zero(sizeof(EVP_PKEY)); + fixed_crypto_pk_get_evp_pkey_result[1] = NULL; + ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1); + tt_assert(!ret); + + fixed_crypto_pk_get_evp_pkey_result_index = 0; + fixed_crypto_pk_get_evp_pkey_result[0] = tor_malloc_zero(sizeof(EVP_PKEY)); + fixed_crypto_pk_get_evp_pkey_result[1] = tor_malloc_zero(sizeof(EVP_PKEY)); + ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1); + tt_assert(!ret); + + MOCK(crypto_rand, fixed_crypto_rand); + fixed_crypto_rand_result = -1; + fixed_crypto_pk_get_evp_pkey_result_index = 0; + fixed_crypto_pk_get_evp_pkey_result[0] = tor_malloc_zero(sizeof(EVP_PKEY)); + fixed_crypto_pk_get_evp_pkey_result[1] = tor_malloc_zero(sizeof(EVP_PKEY)); + ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1); + tt_assert(!ret); + + done: + UNMOCK(crypto_rand); + UNMOCK(crypto_pk_get_evp_pkey_); +} + +static void +test_tortls_cert_new(void *ignored) +{ + (void)ignored; + tor_x509_cert_t *ret; + X509 *cert = read_cert_from(validCertString); + + ret = tor_x509_cert_new(NULL); + tt_assert(!ret); + + ret = tor_x509_cert_new(cert); + tt_assert(ret); + + X509_get_pubkey(cert)->type = EVP_PKEY_DSA; + ret = tor_x509_cert_new(cert); + tt_assert(ret); + +#ifndef OPENSSL_OPAQUE + cert->cert_info = NULL; + ret = tor_x509_cert_new(cert); + tt_assert(ret); +#endif + + done: + (void)0; +} + +static void +test_tortls_cert_is_valid(void *ignored) +{ + (void)ignored; + int ret; + tor_x509_cert_t *cert = NULL, *scert; + + scert = tor_malloc_zero(sizeof(tor_x509_cert_t)); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0); + tt_int_op(ret, OP_EQ, 0); + + cert = tor_x509_cert_new(read_cert_from(validCertString)); + scert = tor_x509_cert_new(read_cert_from(caCertString)); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0); + tt_int_op(ret, OP_EQ, 1); + +#ifndef OPENSSL_OPAQUE + cert = tor_x509_cert_new(read_cert_from(validCertString)); + scert = tor_x509_cert_new(read_cert_from(caCertString)); + cert->cert->cert_info->validity->notAfter = + ASN1_TIME_set(NULL, time(NULL)-1000000); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0); + tt_int_op(ret, OP_EQ, 0); + + cert = tor_x509_cert_new(read_cert_from(validCertString)); + scert = tor_x509_cert_new(read_cert_from(caCertString)); + cert->cert->cert_info->key = NULL; + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1); + tt_int_op(ret, OP_EQ, 0); +#endif + + cert = tor_x509_cert_new(read_cert_from(validCertString)); + scert = tor_x509_cert_new(read_cert_from(caCertString)); + BN_one(EVP_PKEY_get1_RSA(X509_get_pubkey(cert->cert))->n); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1); + tt_int_op(ret, OP_EQ, 0); + + cert = tor_x509_cert_new(read_cert_from(validCertString)); + scert = tor_x509_cert_new(read_cert_from(caCertString)); + X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC; + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1); + tt_int_op(ret, OP_EQ, 0); + + cert = tor_x509_cert_new(read_cert_from(validCertString)); + scert = tor_x509_cert_new(read_cert_from(caCertString)); + X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC; + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0); + tt_int_op(ret, OP_EQ, 1); + + cert = tor_x509_cert_new(read_cert_from(validCertString)); + scert = tor_x509_cert_new(read_cert_from(caCertString)); + X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC; + X509_get_pubkey(cert->cert)->ameth = NULL; + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0); + tt_int_op(ret, OP_EQ, 0); + + done: + (void)0; +} + +static void +test_tortls_context_init_one(void *ignored) +{ + (void)ignored; + int ret; + tor_tls_context_t *old = NULL; + + MOCK(crypto_pk_new, fixed_crypto_pk_new); + + fixed_crypto_pk_new_result_index = 0; + fixed_crypto_pk_new_result[0] = NULL; + ret = tor_tls_context_init_one(&old, NULL, 0, 0, 0); + tt_int_op(ret, OP_EQ, -1); + + done: + UNMOCK(crypto_pk_new); +} + +#define LOCAL_TEST_CASE(name, flags) \ + { #name, test_tortls_##name, (flags), NULL, NULL } + +#ifdef OPENSSL_OPAQUE +#define INTRUSIVE_TEST_CASE(name, flags) \ + { #name, NULL, TT_SKIP, NULL, NULL } +#else +#define INTRUSIVE_TEST_CASE(name, flags) LOCAL_TEST_CASE(name, flags) +#endif + +struct testcase_t tortls_tests[] = { + LOCAL_TEST_CASE(errno_to_tls_error, 0), + LOCAL_TEST_CASE(err_to_string, 0), + LOCAL_TEST_CASE(tor_tls_new, 0), + LOCAL_TEST_CASE(tor_tls_get_error, 0), + LOCAL_TEST_CASE(get_state_description, TT_FORK), + LOCAL_TEST_CASE(get_by_ssl, TT_FORK), + LOCAL_TEST_CASE(allocate_tor_tls_object_ex_data_index, TT_FORK), + LOCAL_TEST_CASE(log_one_error, TT_FORK), + INTRUSIVE_TEST_CASE(get_error, TT_FORK), + LOCAL_TEST_CASE(always_accept_verify_cb, 0), + INTRUSIVE_TEST_CASE(x509_cert_free, 0), + LOCAL_TEST_CASE(x509_cert_get_id_digests, 0), + INTRUSIVE_TEST_CASE(cert_matches_key, 0), + INTRUSIVE_TEST_CASE(cert_get_key, 0), + LOCAL_TEST_CASE(get_my_client_auth_key, TT_FORK), + LOCAL_TEST_CASE(get_my_certs, TT_FORK), + INTRUSIVE_TEST_CASE(get_ciphersuite_name, 0), + INTRUSIVE_TEST_CASE(classify_client_ciphers, 0), + LOCAL_TEST_CASE(client_is_using_v2_ciphers, 0), + INTRUSIVE_TEST_CASE(verify, 0), + INTRUSIVE_TEST_CASE(check_lifetime, 0), + INTRUSIVE_TEST_CASE(get_pending_bytes, 0), + LOCAL_TEST_CASE(get_forced_write_size, 0), + LOCAL_TEST_CASE(get_write_overhead_ratio, TT_FORK), + LOCAL_TEST_CASE(used_v1_handshake, TT_FORK), + LOCAL_TEST_CASE(dn_indicates_v3_cert, 0), + INTRUSIVE_TEST_CASE(received_v3_certificate, 0), + LOCAL_TEST_CASE(get_num_server_handshakes, 0), + LOCAL_TEST_CASE(server_got_renegotiate, 0), + INTRUSIVE_TEST_CASE(SSL_SESSION_get_master_key, 0), + INTRUSIVE_TEST_CASE(get_tlssecrets, 0), + INTRUSIVE_TEST_CASE(get_buffer_sizes, 0), + LOCAL_TEST_CASE(evaluate_ecgroup_for_tls, 0), + INTRUSIVE_TEST_CASE(try_to_extract_certs_from_tls, 0), + INTRUSIVE_TEST_CASE(get_peer_cert, 0), + INTRUSIVE_TEST_CASE(peer_has_cert, 0), + INTRUSIVE_TEST_CASE(shutdown, 0), + INTRUSIVE_TEST_CASE(renegotiate, 0), + INTRUSIVE_TEST_CASE(finish_handshake, 0), + INTRUSIVE_TEST_CASE(handshake, 0), + INTRUSIVE_TEST_CASE(write, 0), + INTRUSIVE_TEST_CASE(read, 0), + INTRUSIVE_TEST_CASE(server_info_callback, 0), + LOCAL_TEST_CASE(is_server, 0), + INTRUSIVE_TEST_CASE(assert_renegotiation_unblocked, 0), + INTRUSIVE_TEST_CASE(block_renegotiation, 0), + INTRUSIVE_TEST_CASE(unblock_renegotiation, 0), + INTRUSIVE_TEST_CASE(set_renegotiate_callback, 0), + LOCAL_TEST_CASE(set_logged_address, 0), + INTRUSIVE_TEST_CASE(find_cipher_by_id, 0), + INTRUSIVE_TEST_CASE(session_secret_cb, 0), + INTRUSIVE_TEST_CASE(debug_state_callback, 0), + INTRUSIVE_TEST_CASE(context_new, 0), + LOCAL_TEST_CASE(create_certificate, 0), + LOCAL_TEST_CASE(cert_new, 0), + LOCAL_TEST_CASE(cert_is_valid, 0), + LOCAL_TEST_CASE(context_init_one, 0), + END_OF_TESTCASES +}; + diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c index 7be67438f5..705dfcf605 100644 --- a/src/test/test_util_format.c +++ b/src/test/test_util_format.c @@ -44,30 +44,23 @@ test_util_format_base64_encode(void *ignored) res = base64_encode(dst, 1000, src, 256, 0); tt_int_op(res, OP_EQ, 344); - tt_str_op(dst, OP_EQ, - "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8g" - "ISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BB" - "QkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFi" - "Y2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD" - "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOk" - "paanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TF" - "xsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm" - "5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="); + tt_str_op(dst, OP_EQ, "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh" + "8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH" + "SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3" + "BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeY" + "mZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wM" + "HCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp" + "6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="); res = base64_encode(dst, 1000, src, 256, BASE64_ENCODE_MULTILINE); tt_int_op(res, OP_EQ, 350); tt_str_op(dst, OP_EQ, - "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8g" - "ISIjJCUmJygpKissLS4v\n" - "MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9Q" - "UVJTVFVWV1hZWltcXV5f\n" - "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+A" - "gYKDhIWGh4iJiouMjY6P\n" - "kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+w" - "sbKztLW2t7i5uru8vb6/\n" - "wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g" - "4eLj5OXm5+jp6uvs7e7v\n" - "8PHy8/T19vf4+fr7/P3+/w==\n"); + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v\n" + "MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f\n" + "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P\n" + "kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/\n" + "wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v\n" + "8PHy8/T19vf4+fr7/P3+/w==\n"); res = base64_encode(dst, 1000, src+1, 255, BASE64_ENCODE_MULTILINE); tt_int_op(res, OP_EQ, 346); @@ -137,6 +130,16 @@ test_util_format_base64_decode_nopad(void *ignored) res = base64_decode_nopad(dst, 1, src, 5); tt_int_op(res, OP_EQ, -1); + const char *s = "SGVsbG8gd29ybGQ"; + res = base64_decode_nopad(dst, 1000, s, strlen(s)); + tt_int_op(res, OP_EQ, 11); + tt_mem_op(dst, OP_EQ, "Hello world", 11); + + s = "T3BhIG11bmRv"; + res = base64_decode_nopad(dst, 9, s, strlen(s)); + tt_int_op(res, OP_EQ, 9); + tt_mem_op(dst, OP_EQ, "Opa mundo", 9); + res = base64_decode_nopad(real_dst, 10, real_src, 10); tt_int_op(res, OP_EQ, 7); tt_mem_op(real_dst, OP_EQ, expected, 7); @@ -172,6 +175,21 @@ test_util_format_base64_decode(void *ignored) res = base64_decode(dst, SIZE_T_CEILING+1, src, 10); tt_int_op(res, OP_EQ, -1); + const char *s = "T3BhIG11bmRv"; + res = base64_decode(dst, 9, s, strlen(s)); + tt_int_op(res, OP_EQ, 9); + tt_mem_op(dst, OP_EQ, "Opa mundo", 9); + + memset(dst, 0, 1000); + res = base64_decode(dst, 100, s, strlen(s)); + tt_int_op(res, OP_EQ, 9); + tt_mem_op(dst, OP_EQ, "Opa mundo", 9); + + s = "SGVsbG8gd29ybGQ="; + res = base64_decode(dst, 100, s, strlen(s)); + tt_int_op(res, OP_EQ, 11); + tt_mem_op(dst, OP_EQ, "Hello world", 11); + res = base64_decode(real_dst, 10, real_src, 10); tt_int_op(res, OP_EQ, 7); tt_mem_op(real_dst, OP_EQ, expected, 7); @@ -210,6 +228,19 @@ test_util_format_base16_decode(void *ignored) res = base16_decode(dst, SIZE_T_CEILING+2, src, 10); tt_int_op(res, OP_EQ, -1); + res = base16_decode(dst, 1000, "", 0); + tt_int_op(res, OP_EQ, 0); + + res = base16_decode(dst, 1000, "aabc", 4); + tt_int_op(res, OP_EQ, 0); + tt_mem_op(dst, OP_EQ, "\xaa\xbc", 2); + + res = base16_decode(dst, 1000, "aabcd", 6); + tt_int_op(res, OP_EQ, -1); + + res = base16_decode(dst, 1000, "axxx", 4); + tt_int_op(res, OP_EQ, -1); + res = base16_decode(real_dst, 10, real_src, 14); tt_int_op(res, OP_EQ, 0); tt_mem_op(real_dst, OP_EQ, expected, 7); @@ -222,9 +253,10 @@ test_util_format_base16_decode(void *ignored) struct testcase_t util_format_tests[] = { { "base64_encode", test_util_format_base64_encode, 0, NULL, NULL }, - { "base64_decode_nopad", test_util_format_base64_decode_nopad, - 0, NULL, NULL }, + { "base64_decode_nopad", test_util_format_base64_decode_nopad, 0, + NULL, NULL }, { "base64_decode", test_util_format_base64_decode, 0, NULL, NULL }, { "base16_decode", test_util_format_base16_decode, 0, NULL, NULL }, END_OF_TESTCASES }; + diff --git a/src/test/test_zero_length_keys.sh b/src/test/test_zero_length_keys.sh new file mode 100755 index 0000000000..f85edb68db --- /dev/null +++ b/src/test/test_zero_length_keys.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Check that tor regenerates keys when key files are zero-length + +exitcode=0 + +"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/or/tor" -z || exitcode=1 +"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/or/tor" -d || exitcode=1 +"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/or/tor" -e || exitcode=1 + +exit ${exitcode} diff --git a/src/test/test_zero_length_keys.sh.in b/src/test/test_zero_length_keys.sh.in deleted file mode 100644 index d1492d5e20..0000000000 --- a/src/test/test_zero_length_keys.sh.in +++ /dev/null @@ -1,10 +0,0 @@ -#!@SHELL@ -# Check that tor regenerates keys when key files are zero-length - -exitcode=0 - -@SHELL@ @abs_top_srcdir@/src/test/zero_length_keys.sh "@builddir@/src/or/tor" -z || exitcode=1 -@SHELL@ @abs_top_srcdir@/src/test/zero_length_keys.sh "@builddir@/src/or/tor" -d || exitcode=1 -@SHELL@ @abs_top_srcdir@/src/test/zero_length_keys.sh "@builddir@/src/or/tor" -e || exitcode=1 - -exit ${exitcode} diff --git a/src/test/vote_descriptors.inc b/src/test/vote_descriptors.inc new file mode 100644 index 0000000000..c5ce21f744 --- /dev/null +++ b/src/test/vote_descriptors.inc @@ -0,0 +1,94 @@ +const char* VOTE_BODY_V3 = +"network-status-version 3\n" +"vote-status vote\n" +"consensus-methods 13 14 15 16 17 18 19 20 21\n" +"published 2015-09-02 19:34:15\n" +"valid-after 2015-09-02 19:50:55\n" +"fresh-until 2015-09-02 20:07:38\n" +"valid-until 2015-09-02 20:24:15\n" +"voting-delay 100 250\n" +"client-versions 0.1.2.14,0.1.2.17\n" +"server-versions 0.1.2.10,0.1.2.15,0.1.2.16\n" +"known-flags Authority Exit Fast Guard MadeOfCheese MadeOfTin Running Stable V2Dir Valid\n" +"flag-thresholds stable-uptime=0 stable-mtbf=0 fast-speed=0 guard-wfu=0.000% guard-tk=0 guard-bw-inc-exits=0 guard-bw-exc-exits=0 enough-mtbf=0 ignoring-advertised-bws=0\n" +"params circuitwindow=80 foo=660\n" +"dir-source Voter3 D867ACF56A9D229B35C25F0090BC9867E906BE69 3.4.5.6 3.4.5.6 80 9000\n" +"contact voter@example.com\n" +"legacy-dir-key 4141414141414141414141414141414141414141\n" +"dir-key-certificate-version 3\n" +"fingerprint D867ACF56A9D229B35C25F0090BC9867E906BE69\n" +"dir-key-published 2008-12-12 18:07:24\n" +"dir-key-expires 2009-12-12 18:07:24\n" +"dir-identity-key\n" +"-----BEGIN RSA PUBLIC KEY-----\n" +"MIIBigKCAYEAveMpKlw8oD1YqFqpJchuwSR82BDhutbqgHiez3QO9FmzOctJpV+Y\n" +"mpTYIJLS/qC+4GBKFF1VK0C4SoBrS3zri0qdXdE+vBGcyrxrjMklpxoqSKRY2011\n" +"4eqYPghKlo5RzuqteBclGCHyNxWjUJeRKDWgvh+U/gr2uYM6fRm5q0fCzg4aECE7\n" +"VP6fDGZrMbQI8jHpiMSoC9gkUASNEa6chLInlnP8/H5qUEW4TB9CN/q095pefuwL\n" +"P+F+1Nz5hnM7fa5XmeMB8iM4RriUmOQlLBZgpQBMpEfWMIPcR9F1Gh3MxERqqUcH\n" +"tmij+IZdeXg9OkCXykcabaYIhZD3meErn9Tax4oA/THduLfgli9zM0ExwzH1OooN\n" +"L8rIcJ+2eBo3bQiQUbdYW71sl9w7nSPtircbJUa1mUvWYLPWQxFliPiQSetgJLMj\n" +"VQqtPmV2hvN2Xk3lLfJO50qMTK7w7Gsaw8UtV4YDM1Hcjp/hQaIB1xfwhXgl+eUU\n" +"btUa4c+cUTjHAgMBAAE=\n" +"-----END RSA PUBLIC KEY-----\n" +"dir-signing-key\n" +"-----BEGIN RSA PUBLIC KEY-----\n" +"MIGJAoGBALPSUInyuEu6NV3NjozplaniIEBzQXEjv1x9/+mqnwZABpYVmuy9A8nx\n" +"eoyY3sZFsnYwNW/IZjAgG23pEmevu3F+L4myMjjaa6ORl3MgRYQ4gmuFqpefrGdm\n" +"ywRCleh2JerkQ4VxOuq10dn/abITzLyaZzMw30KXWp5pxKXOLtxFAgMBAAE=\n" +"-----END RSA PUBLIC KEY-----\n" +"dir-key-crosscert\n" +"-----BEGIN ID SIGNATURE-----\n" +"FTBJNR/Hlt4T53yUMp1r/QCSMCpkHJCbYBT0R0pvYqhqFfYN5qHRSICRXaFFImIF\n" +"0DGWmwRza6DxPKNzkm5/b7I0de9zJW1jNNdQAQK5xppAtQcAafRdu8cBonnmh9KX\n" +"k1NrAK/X00FYywju3yl/SxCn1GddVNkHYexEudmJMPM=\n" +"-----END ID SIGNATURE-----\n" +"dir-key-certification\n" +"-----BEGIN SIGNATURE-----\n" +"pjWguLFBfELZDc6DywL6Do21SCl7LcutfpM92MEn4WYeSNcTXNR6lRX7reOEJk4e\n" +"NwEaMt+Hl7slgeR5wjnW3OmMmRPZK9bquNWbfD+sAOV9bRFZTpXIdleAQFPlwvMF\n" +"z/Gzwspzn4i2Yh6hySShrctMmW8YL3OM8LsBXzBhp/rG2uHlsxmIsc13DA6HWt61\n" +"ffY72uNE6KckDGsQ4wPGP9q69y6g+X+TNio1KPbsILbePv6EjbO+rS8FiS4njPlg\n" +"SPYry1RaUvxzxTkswIzdE1tjJrUiqpbWlTGxrH9N4OszoLm45Pc784KLULrjKIoi\n" +"Q+vRsGrcMBAa+kDowWU6H1ryKR7KOhzRTcf2uqLE/W3ezaRwmOG+ETmoVFwbhk2X\n" +"OlbXEM9fWP+INvFkr6Z93VYL2jGkCjV7e3xXmre/Lb92fUcYi6t5dwzfV8gJnIoG\n" +"eCHd0K8NrQK0ipVk/7zcPDKOPeo9Y5aj/f6X/pDHtb+Dd5sT+l82G/Tqy4DIYUYR\n" +"-----END SIGNATURE-----\n" +"r router2 AwMDAwMDAwMDAwMDAwMDAwMDAwM Tk5OTk5OTk5OTk5OTk5OTk5OTk4 2015-09-02 19:09:15 153.0.136.1 443 8000\n" +"s Running V2Dir\n" +"v 0.1.2.14\n" +"w Bandwidth=30 Measured=30\n" +"p reject 1-65535\n" +"id ed25519 none\n" +"m 9,10,11,12,13,14,15,16,17 sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa0\n" +"r router1 BQUFBQUFBQUFBQUFBQUFBQUFBQU TU1NTU1NTU1NTU1NTU1NTU1NTU0 2015-09-02 19:17:35 153.0.153.1 443 0\n" +"a [1:2:3::4]:4711\n" +"s Exit Fast Guard Running Stable Valid\n" +"v 0.2.0.5\n" +"w Bandwidth=120 Measured=120\n" +"p reject 1-65535\n" +"id ed25519 none\n" +"m 9,10,11,12,13,14,15,16,17 sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa1\n" +"r router3 MzMzMzMzMzMzMzMzMzMzMzMzMzM T09PT09PT09PT09PT09PT09PT08 2015-09-02 19:17:35 170.0.153.1 400 9999\n" +"s Authority Exit Fast Guard Running Stable V2Dir Valid\n" +"v 0.1.0.3\n" +"w Bandwidth=120\n" +"p reject 1-65535\n" +"id ed25519 none\n" +"m 9,10,11,12,13,14,15,16,17 " +"sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa2\n" +"r router4 NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ Ly8vLy8vLy8vLy8vLy8vLy8vLy8 2015-09-02 19:17:35 192.0.2.3 500 1999\n" +"s Running V2Dir\n" +"v 0.1.6.3\n" +"w Bandwidth=30\n" +"p reject 1-65535\n" +"id ed25519 none\n" +"m 9,10,11,12,13,14,15,16,17 sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa3\n" +"directory-footer\n" +"directory-signature D867ACF56A9D229B35C25F0090BC9867E906BE69 CBF56A83368A5150F1A9AAADAFB4D77F8C4170E2\n" +"-----BEGIN SIGNATURE-----\n" +"AHiWcHe+T3XbnlQqvqSAk6RY3XmEy1+hM2u9Xk6BNi7BpQkEQM1f0vzRpgn5Dnf2\n" +"TXQWGUq9Z7jdSVnzWT3xqPA4zjw6eZkj+DKUtwq+oEDZGlf8eHTFmr0NAWfwZbk9\n" +"NAjbMTUXUP37N2XAZwkoCWwFCrrfMwXrL7OhZbj7ifo=\n" +"-----END SIGNATURE-----\n"; + |