commit 53b49d1a35d2e7abf1cc7aff15553c23dde0f352 Author: teor teor@torproject.org Date: Mon Feb 18 15:24:26 2019 +1000
test_dir: Unit tests for RSA-only router and extrainfo descriptor creation
Tests 29017 and 29018. --- src/feature/nodelist/torcert.c | 4 +- src/feature/nodelist/torcert.h | 2 +- src/feature/relay/router.c | 18 +++--- src/feature/relay/router.h | 12 +++- src/test/test_dir.c | 134 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 146 insertions(+), 24 deletions(-)
diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c index b0197e9f1..56f1a8ac9 100644 --- a/src/feature/nodelist/torcert.c +++ b/src/feature/nodelist/torcert.c @@ -290,8 +290,8 @@ tor_cert_describe_signature_status(const tor_cert_t *cert) }
/** Return a new copy of <b>cert</b> */ -tor_cert_t * -tor_cert_dup(const tor_cert_t *cert) +MOCK_IMPL(tor_cert_t *, +tor_cert_dup,(const tor_cert_t *cert)) { tor_cert_t *newcert = tor_memdup(cert, sizeof(tor_cert_t)); if (cert->encoded) diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h index 492275b51..03d5bdca9 100644 --- a/src/feature/nodelist/torcert.h +++ b/src/feature/nodelist/torcert.h @@ -71,7 +71,7 @@ int tor_cert_checksig(tor_cert_t *cert, const ed25519_public_key_t *pubkey, time_t now); const char *tor_cert_describe_signature_status(const tor_cert_t *cert);
-tor_cert_t *tor_cert_dup(const tor_cert_t *cert); +MOCK_DECL(tor_cert_t *,tor_cert_dup,(const tor_cert_t *cert)); int tor_cert_eq(const tor_cert_t *cert1, const tor_cert_t *cert2); int tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2);
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 7e2161ef3..18c837529 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -196,8 +196,8 @@ set_onion_key(crypto_pk_t *k)
/** Return the current onion key. Requires that the onion key has been * loaded or generated. */ -crypto_pk_t * -get_onion_key(void) +MOCK_IMPL(crypto_pk_t *, +get_onion_key,(void)) { tor_assert(onionkey); return onionkey; @@ -376,8 +376,8 @@ assert_identity_keys_ok(void) /** Returns the current server identity key; requires that the key has * been set, and that we are running as a Tor server. */ -crypto_pk_t * -get_server_identity_key(void) +MOCK_IMPL(crypto_pk_t *, +get_server_identity_key,(void)) { tor_assert(server_identitykey); tor_assert(server_mode(get_options())); @@ -1951,8 +1951,8 @@ get_my_declared_family(const or_options_t *options) * * Returns a negative value and sets ri_out to NULL on temporary error. */ -static int -router_build_fresh_unsigned_routerinfo(routerinfo_t **ri_out) +MOCK_IMPL(STATIC int, +router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)) { routerinfo_t *ri = NULL; uint32_t addr; @@ -2171,7 +2171,7 @@ router_dump_and_sign_extrainfo_descriptor_body(extrainfo_t *ei) * If ri is NULL, logs a BUG() warning and returns NULL. * Caller is responsible for freeing the generated extrainfo. */ -static extrainfo_t * +STATIC extrainfo_t * router_build_fresh_signed_extrainfo(const routerinfo_t *ri) { int result = -1; @@ -2203,7 +2203,7 @@ router_build_fresh_signed_extrainfo(const routerinfo_t *ri) * * If ei is NULL, logs a BUG() warning and zeroes the relevant fields. */ -static void +STATIC void router_update_routerinfo_from_extrainfo(routerinfo_t *ri, const extrainfo_t *ei) { @@ -2231,7 +2231,7 @@ router_update_routerinfo_from_extrainfo(routerinfo_t *ri, * If ri is NULL, logs a BUG() warning and returns a negative value. * On error, ri->cache_info is not modified. */ -static int +STATIC int router_dump_and_sign_routerinfo_descriptor_body(routerinfo_t *ri) { if (BUG(!ri)) diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h index 497d8d243..d4ad52c9d 100644 --- a/src/feature/relay/router.h +++ b/src/feature/relay/router.h @@ -25,10 +25,10 @@ struct ed25519_keypair_t; #define TOR_ROUTERINFO_ERROR_DESC_REBUILDING (-6) #define TOR_ROUTERINFO_ERROR_INTERNAL_BUG (-7)
-crypto_pk_t *get_onion_key(void); +MOCK_DECL(crypto_pk_t *,get_onion_key,(void)); time_t get_onion_key_set_at(void); void set_server_identity_key(crypto_pk_t *k); -crypto_pk_t *get_server_identity_key(void); +MOCK_DECL(crypto_pk_t *,get_server_identity_key,(void)); int server_identity_key_is_set(void); void set_client_identity_key(crypto_pk_t *k); crypto_pk_t *get_tlsclient_identity_key(void); @@ -124,6 +124,14 @@ STATIC smartlist_t *get_my_declared_family(const or_options_t *options); extern time_t desc_clean_since; extern const char *desc_dirty_reason; void set_server_identity_key_digest_testing(const uint8_t *digest); + +MOCK_DECL(STATIC int, + router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)); +STATIC extrainfo_t *router_build_fresh_signed_extrainfo( + const routerinfo_t *ri); +STATIC void router_update_routerinfo_from_extrainfo(routerinfo_t *ri, + const extrainfo_t *ei); +STATIC int router_dump_and_sign_routerinfo_descriptor_body(routerinfo_t *ri); #endif
#endif diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 4132d42d1..57adee414 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -171,6 +171,31 @@ mock_get_configured_ports(void) return mocked_configured_ports; }
+static tor_cert_t * +mock_tor_cert_dup_null(const tor_cert_t *cert) +{ + (void)cert; + return NULL; +} + +static crypto_pk_t *mocked_server_identitykey = NULL; + +/* Returns mocked_server_identitykey with no checks. */ +static crypto_pk_t * +mock_get_server_identity_key(void) +{ + return mocked_server_identitykey; +} + +static crypto_pk_t *mocked_onionkey = NULL; + +/* Returns mocked_onionkey with no checks. */ +static crypto_pk_t * +mock_get_onion_key(void) +{ + return mocked_onionkey; +} + /** Run unit tests for router descriptor generation logic. */ static void test_dir_formats(void *arg) @@ -182,8 +207,11 @@ test_dir_formats(void *arg) char *pk1_str = NULL, *pk2_str = NULL, *cp; size_t pk1_str_len, pk2_str_len; routerinfo_t *r1=NULL, *r2=NULL; + extrainfo_t *e1 = NULL, *e2 = NULL; crypto_pk_t *pk1 = NULL, *pk2 = NULL; + routerinfo_t *r2_out = NULL; routerinfo_t *rp1 = NULL, *rp2 = NULL; + extrainfo_t *ep1 = NULL, *ep2 = NULL; addr_policy_t *ex1, *ex2; routerlist_t *dir1 = NULL, *dir2 = NULL; uint8_t *rsa_cc = NULL; @@ -192,6 +220,8 @@ test_dir_formats(void *arg) time_t now = time(NULL); port_cfg_t orport, dirport; char cert_buf[256]; + int rv = -1; + const char *msg = NULL;
(void)arg; pk1 = pk_generate(0); @@ -202,6 +232,8 @@ test_dir_formats(void *arg) hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
get_platform_str(platform, sizeof(platform)); + + /* r1 is a minimal, RSA-only descriptor */ r1 = tor_malloc_zero(sizeof(routerinfo_t)); r1->addr = 0xc0a80001u; /* 192.168.0.1 */ r1->cache_info.published_on = 0; @@ -224,6 +256,7 @@ test_dir_formats(void *arg) r1->nickname = tor_strdup("Magri"); r1->platform = tor_strdup(platform);
+ /* r2 is a RSA + ed25519 descriptor, with an exit policy */ ex1 = tor_malloc_zero(sizeof(addr_policy_t)); ex2 = tor_malloc_zero(sizeof(addr_policy_t)); ex1->policy_type = ADDR_POLICY_ACCEPT; @@ -352,8 +385,86 @@ test_dir_formats(void *arg) crypto_pk_free(onion_pkey); tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, pk2), OP_EQ, 0); tt_assert(rp1->supports_tunnelled_dir_requests); - //tt_assert(rp1->exit_policy == NULL); + tt_assert(rp1->policy_is_reject_star); + tor_free(buf); + routerinfo_free(rp1); + + /* Test extrainfo creation. + * We avoid calling router_build_fresh_unsigned_routerinfo(), because it's + * too complex. Instead, we re-use the manually-created routerinfos. + */ + + /* router_build_fresh_signed_extrainfo() requires options->Nickname */ + tor_free(options->Nickname); + options->Nickname = tor_strdup(r1->nickname); + /* router_build_fresh_signed_extrainfo() passes the result of + * get_master_signing_key_cert() directly to tor_cert_dup(), which fails on + * NULL. But we want a NULL ei->cache_info.signing_key_cert to test the + * non-ed key path. + */ + MOCK(tor_cert_dup, mock_tor_cert_dup_null); + /* router_build_fresh_signed_extrainfo() requires get_server_identity_key(). + * Use the same one as the call to router_dump_router_to_string() above. + */ + mocked_server_identitykey = pk2; + MOCK(get_server_identity_key, mock_get_server_identity_key); + /* router_dump_and_sign_routerinfo_descriptor_body() requires + * get_onion_key(). Use the same one as r1. + */ + mocked_onionkey = pk1; + MOCK(get_onion_key, mock_get_onion_key); + + /* Test some of the low-level static functions. */ + e1 = router_build_fresh_signed_extrainfo(r1); + tt_assert(e1); + router_update_routerinfo_from_extrainfo(r1, e1); + rv = router_dump_and_sign_routerinfo_descriptor_body(r1); + tt_assert(rv == 0); + msg = ""; + rv = routerinfo_incompatible_with_extrainfo(r1->identity_pkey, e1, + &r1->cache_info, &msg); + tt_str_op(msg, OP_EQ, ""); + tt_assert(rv == 0); + + /* Now cleanup */ + tor_free(options->Nickname); + UNMOCK(tor_cert_dup); + mocked_server_identitykey = NULL; + UNMOCK(get_server_identity_key); + mocked_onionkey = NULL; + UNMOCK(get_onion_key); + + /* Test that the signed ri is parseable */ + tt_assert(r1->cache_info.signed_descriptor_body); + cp = r1->cache_info.signed_descriptor_body; + rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); + tt_assert(rp1); + tt_int_op(rp1->addr,OP_EQ, r1->addr); + tt_int_op(rp1->or_port,OP_EQ, r1->or_port); + tt_int_op(rp1->dir_port,OP_EQ, r1->dir_port); + tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate); + tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst); + tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity); + onion_pkey = router_get_rsa_onion_pkey(rp1->onion_pkey, + rp1->onion_pkey_len); + tt_int_op(crypto_pk_cmp_keys(onion_pkey, pk1), OP_EQ, 0); + crypto_pk_free(onion_pkey); + tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, pk2), OP_EQ, 0); + tt_assert(rp1->supports_tunnelled_dir_requests); + tt_assert(rp1->policy_is_reject_star); + + routerinfo_free(rp1); + + /* Test that the signed ei is parseable */ + tt_assert(e1->cache_info.signed_descriptor_body); + cp = e1->cache_info.signed_descriptor_body; + ep1 = extrainfo_parse_entry_from_string((const char*)cp,NULL,1,NULL,NULL); + tt_assert(ep1); + tt_str_op(ep1->nickname, OP_EQ, r1->nickname); + /* In future tests, we could check the actual extrainfo statistics. */ + + extrainfo_free(ep1);
strlcpy(buf2, "router Fred 10.3.2.1 9005 0 0\n" @@ -503,20 +614,23 @@ test_dir_formats(void *arg) dirserv_free_fingerprint_list();
done: - if (r1) - routerinfo_free(r1); - if (r2) - routerinfo_free(r2); - if (rp2) - routerinfo_free(rp2); + routerinfo_free(r1); + routerinfo_free(r2); + routerinfo_free(r2_out); + routerinfo_free(rp1); + routerinfo_free(rp2); + + extrainfo_free(e1); + extrainfo_free(e2); + extrainfo_free(ep1); + extrainfo_free(ep2);
tor_free(rsa_cc); tor_free(buf); tor_free(pk1_str); tor_free(pk2_str); - if (pk1) crypto_pk_free(pk1); - if (pk2) crypto_pk_free(pk2); - if (rp1) routerinfo_free(rp1); + crypto_pk_free(pk1); + crypto_pk_free(pk2); tor_free(dir1); /* XXXX And more !*/ tor_free(dir2); /* And more !*/ }