diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index 2716dca032..1e7adabdc4 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -2140,4 +2140,10 @@ get_hs_client_auths_map(void) return client_auths; } +STATIC void +set_hs_client_auths_map(digest256map_t *map) +{ + client_auths = map; +} + #endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h index 09bbe51df9..699ce60510 100644 --- a/src/feature/hs/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -115,6 +115,7 @@ STATIC void retry_all_socks_conn_waiting_for_desc(void); #ifdef TOR_UNIT_TESTS STATIC digest256map_t *get_hs_client_auths_map(void); +STATIC void set_hs_client_auths_map(digest256map_t *map); #endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index 0a21fe576b..e7f5ec90b9 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -1,12 +1,16 @@ /* Copyright (c) 2017-2019, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#define HS_CLIENT_PRIVATE + #include "core/or/or.h" #include "lib/crypt_ops/crypto_ed25519.h" #include "test/test.h" #include "feature/nodelist/torcert.h" +#include "feature/hs/hs_client.h" #include "feature/hs/hs_common.h" +#include "feature/hs/hs_service.h" #include "test/hs_test_helpers.h" hs_desc_intro_point_t * @@ -207,6 +211,35 @@ hs_helper_build_hs_desc_no_ip(const ed25519_keypair_t *signing_kp) return hs_helper_build_hs_desc_impl(1, signing_kp); } +hs_descriptor_t * +hs_helper_build_hs_desc_with_client_auth( + const uint8_t *descriptor_cookie, + const curve25519_public_key_t *client_pk, + const ed25519_keypair_t *signing_kp) +{ + curve25519_keypair_t auth_ephemeral_kp; + hs_descriptor_t *desc = hs_helper_build_hs_desc_impl(0, signing_kp); + hs_desc_authorized_client_t *desc_client; + + /* The number of client authorized auth has tobe a multiple of + * HS_DESC_AUTH_CLIENT_MULTIPLE so remove one that we'll replace. */ + desc_client = smartlist_get(desc->superencrypted_data.clients, 0); + smartlist_remove(desc->superencrypted_data.clients, desc_client); + hs_desc_authorized_client_free(desc_client); + + desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t)); + + curve25519_keypair_generate(&auth_ephemeral_kp, 0); + memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey, + &auth_ephemeral_kp.pubkey, sizeof(curve25519_public_key_t)); + + hs_desc_build_authorized_client(desc->subcredential, client_pk, + &auth_ephemeral_kp.seckey, + descriptor_cookie, desc_client); + smartlist_add(desc->superencrypted_data.clients, desc_client); + return desc; +} + void hs_helper_desc_equal(const hs_descriptor_t *desc1, const hs_descriptor_t *desc2) @@ -353,3 +386,19 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1, ; } +void +hs_helper_add_client_auth(const ed25519_public_key_t *service_pk, + const curve25519_secret_key_t *client_sk) +{ + digest256map_t *client_auths = get_hs_client_auths_map(); + if (client_auths == NULL) { + client_auths = digest256map_new(); + set_hs_client_auths_map(client_auths); + } + + hs_client_service_authorization_t *auth = + tor_malloc_zero(sizeof(hs_client_service_authorization_t)); + memcpy(&auth->enc_seckey, client_sk, sizeof(curve25519_secret_key_t)); + hs_build_address(service_pk, HS_VERSION_THREE, auth->onion_address); + digest256map_set(client_auths, service_pk->pubkey, auth); +} diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h index 9662a83ba8..be11a4735f 100644 --- a/src/test/hs_test_helpers.h +++ b/src/test/hs_test_helpers.h @@ -15,11 +15,18 @@ hs_descriptor_t *hs_helper_build_hs_desc_no_ip( const ed25519_keypair_t *signing_kp); hs_descriptor_t *hs_helper_build_hs_desc_with_ip( const ed25519_keypair_t *signing_kp); +hs_descriptor_t *hs_helper_build_hs_desc_with_client_auth( + const uint8_t *descriptor_cookie, + const curve25519_public_key_t *client_pk, + const ed25519_keypair_t *signing_kp); void hs_helper_desc_equal(const hs_descriptor_t *desc1, const hs_descriptor_t *desc2); void hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp, uint8_t *subcred_out); +void hs_helper_add_client_auth(const ed25519_public_key_t *service_pk, + const curve25519_secret_key_t *client_sk); + #endif /* !defined(TOR_HS_TEST_HELPERS_H) */ diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index 88cd4079ee..c39a4b644d 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -20,9 +20,10 @@ #include "feature/nodelist/networkstatus.h" #include "core/mainloop/connection.h" #include "core/proto/proto_http.h" -#include "lib/crypt_ops/crypto_format.h" #include "core/or/circuitlist.h" #include "core/or/channel.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" #include "core/or/edge_connection_st.h" #include "core/or/or_circuit_st.h" @@ -567,6 +568,83 @@ test_client_cache(void *arg) } } +/** Test that we can store HS descriptors in the client HS cache. */ +static void +test_client_cache_decrypt(void *arg) +{ + int ret; + char *desc_encoded = NULL; + uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN]; + curve25519_keypair_t client_kp; + ed25519_keypair_t service_kp; + hs_descriptor_t *desc = NULL; + const hs_descriptor_t *search_desc; + const char *search_desc_encoded; + + (void) arg; + + /* Initialize HSDir cache subsystem */ + hs_init(); + + MOCK(networkstatus_get_live_consensus, + mock_networkstatus_get_live_consensus); + + /* Set consensus time */ + parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", + &mock_ns.valid_after); + parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", + &mock_ns.fresh_until); + parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC", + &mock_ns.valid_until); + + /* Generate a valid descriptor with normal values. */ + { + ret = ed25519_keypair_generate(&service_kp, 0); + tt_int_op(ret, OP_EQ, 0); + ret = curve25519_keypair_generate(&client_kp, 0); + tt_int_op(ret, OP_EQ, 0); + crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie)); + + desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie, + &client_kp.pubkey, + &service_kp); + tt_assert(desc); + ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie, + &desc_encoded); + tt_int_op(ret, OP_EQ, 0); + } + + /* Put it in the cache. Should not be decrypted since the client + * authorization creds were not added to the global map. */ + ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey); + tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH); + + /* We should not be able to decrypt anything. */ + ret = hs_cache_client_new_auth_parse(&service_kp.pubkey); + tt_int_op(ret, OP_EQ, false); + + /* Add client auth to global map. */ + hs_helper_add_client_auth(&service_kp.pubkey, &client_kp.seckey); + + /* We should not be able to decrypt anything. */ + ret = hs_cache_client_new_auth_parse(&service_kp.pubkey); + tt_int_op(ret, OP_EQ, true); + + /* Lookup the cache to make sure it is usable and there. */ + search_desc = hs_cache_lookup_as_client(&service_kp.pubkey); + tt_assert(search_desc); + search_desc_encoded = hs_cache_lookup_encoded_as_client(&service_kp.pubkey); + tt_mem_op(search_desc_encoded, OP_EQ, desc_encoded, strlen(desc_encoded)); + + done: + hs_descriptor_free(desc); + tor_free(desc_encoded); + + hs_free_all(); + + UNMOCK(networkstatus_get_live_consensus); +} + struct testcase_t hs_cache[] = { /* Encoding tests. */ { "directory", test_directory, TT_FORK, @@ -579,6 +657,8 @@ struct testcase_t hs_cache[] = { NULL, NULL }, { "client_cache", test_client_cache, TT_FORK, NULL, NULL }, + { "client_cache_decrypt", test_client_cache_decrypt, TT_FORK, + NULL, NULL }, END_OF_TESTCASES };