Loading changes/ticket33139 0 → 100644 +3 −0 Original line number Diff line number Diff line o Minor bugfixes (Onion service client, authorization): - On a NEWNYM signal, purge the ephemeral client authorization cache. The permanent ones are kept. Fixes bug 33139; bugfix on 0.4.3.1-alpha. src/feature/hs/hs_client.c +22 −0 Original line number Diff line number Diff line Loading @@ -1249,6 +1249,26 @@ can_client_refetch_desc(const ed25519_public_key_t *identity_pk, return 0; } /** Purge the client authorization cache of all ephemeral entries that is the * entries that are not flagged with CLIENT_AUTH_FLAG_IS_PERMANENT. * * This is called from the hs_client_purge_state() used by a SIGNEWNYM. */ STATIC void purge_ephemeral_client_auth(void) { DIGEST256MAP_FOREACH_MODIFY(client_auths, key, hs_client_service_authorization_t *, auth) { /* Cleanup every entry that are _NOT_ permanent that is ephemeral. */ if (!(auth->flags & CLIENT_AUTH_FLAG_IS_PERMANENT)) { MAP_DEL_CURRENT(key); client_service_authorization_free(auth); } } DIGESTMAP_FOREACH_END; log_info(LD_REND, "Client onion service ephemeral authorization " "cache has been purged."); } /** Return the client auth in the map using the service identity public key. * Return NULL if it does not exist in the map. */ static hs_client_service_authorization_t * Loading Loading @@ -2433,6 +2453,8 @@ hs_client_purge_state(void) hs_cache_purge_as_client(); /* Purge the last hidden service request cache. */ hs_purge_last_hid_serv_requests(); /* Purge ephemeral client authorization. */ purge_ephemeral_client_auth(); log_info(LD_REND, "Hidden service client state has been purged."); } Loading src/feature/hs/hs_client.h +2 −0 Original line number Diff line number Diff line Loading @@ -162,6 +162,8 @@ MOCK_DECL(STATIC hs_client_fetch_status_t, STATIC void retry_all_socks_conn_waiting_for_desc(void); STATIC void purge_ephemeral_client_auth(void); #ifdef TOR_UNIT_TESTS STATIC void set_hs_client_auths_map(digest256map_t *map); Loading src/test/test_hs_client.c +100 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,23 @@ mock_networkstatus_get_live_consensus(time_t now) return &mock_ns; } static int mock_write_str_to_file(const char *path, const char *str, int bin) { (void) bin; (void) path; (void) str; return 0; } static or_options_t mocked_options; static const or_options_t * mock_get_options(void) { return &mocked_options; } static int helper_config_client(const char *conf, int validate_only) { Loading Loading @@ -1330,6 +1347,85 @@ test_close_intro_circuit_failure(void *arg) hs_free_all(); } static void test_purge_ephemeral_client_auth(void *arg) { ed25519_keypair_t service_kp; hs_client_service_authorization_t *auth = NULL; hs_client_register_auth_status_t status; (void) arg; /* We will try to write on disk client credentials. */ MOCK(check_private_dir, mock_check_private_dir); MOCK(get_options, mock_get_options); MOCK(write_str_to_file, mock_write_str_to_file); /* Boggus directory so when we try to write the permanent client * authorization data to disk, we don't fail. See * store_permanent_client_auth_credentials() for more details. */ mocked_options.ClientOnionAuthDir = tor_strdup("auth_dir"); hs_init(); /* Generate service keypair */ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0)); /* Generate a client authorization object. */ auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); /* Set it up. No flags meaning it is ephemeral. */ curve25519_secret_key_generate(&auth->enc_seckey, 0); hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address); auth->flags = 0; /* Confirm that there is nothing in the client auth map. It is unallocated * until we add the first entry. */ tt_assert(!get_hs_client_auths_map()); /* Add an entry to the client auth list. We loose ownership of the auth * object so nullify it. */ status = hs_client_register_auth_credentials(auth); auth = NULL; tt_int_op(status, OP_EQ, REGISTER_SUCCESS); /* We should have the entry now. */ digest256map_t *client_auths = get_hs_client_auths_map(); tt_assert(client_auths); tt_int_op(digest256map_size(client_auths), OP_EQ, 1); /* Purge the cache that should remove all ephemeral values. */ purge_ephemeral_client_auth(); tt_int_op(digest256map_size(client_auths), OP_EQ, 0); /* Now add a new authorization object but permanent. */ /* Generate a client authorization object. */ auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); curve25519_secret_key_generate(&auth->enc_seckey, 0); hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address); auth->flags = CLIENT_AUTH_FLAG_IS_PERMANENT; /* Add an entry to the client auth list. We loose ownership of the auth * object so nullify it. */ status = hs_client_register_auth_credentials(auth); auth = NULL; tt_int_op(status, OP_EQ, REGISTER_SUCCESS); tt_int_op(digest256map_size(client_auths), OP_EQ, 1); /* Purge again, the entry should still be there. */ purge_ephemeral_client_auth(); tt_int_op(digest256map_size(client_auths), OP_EQ, 1); done: client_service_authorization_free(auth); hs_free_all(); tor_free(mocked_options.ClientOnionAuthDir); UNMOCK(check_private_dir); UNMOCK(get_options); UNMOCK(write_str_to_file); } struct testcase_t hs_client_tests[] = { { "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy, TT_FORK, NULL, NULL }, Loading Loading @@ -1357,5 +1453,9 @@ struct testcase_t hs_client_tests[] = { /* SOCKS5 Extended Error Code. */ { "socks_hs_errors", test_socks_hs_errors, TT_FORK, NULL, NULL }, /* Client authorization. */ { "purge_ephemeral_client_auth", test_purge_ephemeral_client_auth, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; Loading
changes/ticket33139 0 → 100644 +3 −0 Original line number Diff line number Diff line o Minor bugfixes (Onion service client, authorization): - On a NEWNYM signal, purge the ephemeral client authorization cache. The permanent ones are kept. Fixes bug 33139; bugfix on 0.4.3.1-alpha.
src/feature/hs/hs_client.c +22 −0 Original line number Diff line number Diff line Loading @@ -1249,6 +1249,26 @@ can_client_refetch_desc(const ed25519_public_key_t *identity_pk, return 0; } /** Purge the client authorization cache of all ephemeral entries that is the * entries that are not flagged with CLIENT_AUTH_FLAG_IS_PERMANENT. * * This is called from the hs_client_purge_state() used by a SIGNEWNYM. */ STATIC void purge_ephemeral_client_auth(void) { DIGEST256MAP_FOREACH_MODIFY(client_auths, key, hs_client_service_authorization_t *, auth) { /* Cleanup every entry that are _NOT_ permanent that is ephemeral. */ if (!(auth->flags & CLIENT_AUTH_FLAG_IS_PERMANENT)) { MAP_DEL_CURRENT(key); client_service_authorization_free(auth); } } DIGESTMAP_FOREACH_END; log_info(LD_REND, "Client onion service ephemeral authorization " "cache has been purged."); } /** Return the client auth in the map using the service identity public key. * Return NULL if it does not exist in the map. */ static hs_client_service_authorization_t * Loading Loading @@ -2433,6 +2453,8 @@ hs_client_purge_state(void) hs_cache_purge_as_client(); /* Purge the last hidden service request cache. */ hs_purge_last_hid_serv_requests(); /* Purge ephemeral client authorization. */ purge_ephemeral_client_auth(); log_info(LD_REND, "Hidden service client state has been purged."); } Loading
src/feature/hs/hs_client.h +2 −0 Original line number Diff line number Diff line Loading @@ -162,6 +162,8 @@ MOCK_DECL(STATIC hs_client_fetch_status_t, STATIC void retry_all_socks_conn_waiting_for_desc(void); STATIC void purge_ephemeral_client_auth(void); #ifdef TOR_UNIT_TESTS STATIC void set_hs_client_auths_map(digest256map_t *map); Loading
src/test/test_hs_client.c +100 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,23 @@ mock_networkstatus_get_live_consensus(time_t now) return &mock_ns; } static int mock_write_str_to_file(const char *path, const char *str, int bin) { (void) bin; (void) path; (void) str; return 0; } static or_options_t mocked_options; static const or_options_t * mock_get_options(void) { return &mocked_options; } static int helper_config_client(const char *conf, int validate_only) { Loading Loading @@ -1330,6 +1347,85 @@ test_close_intro_circuit_failure(void *arg) hs_free_all(); } static void test_purge_ephemeral_client_auth(void *arg) { ed25519_keypair_t service_kp; hs_client_service_authorization_t *auth = NULL; hs_client_register_auth_status_t status; (void) arg; /* We will try to write on disk client credentials. */ MOCK(check_private_dir, mock_check_private_dir); MOCK(get_options, mock_get_options); MOCK(write_str_to_file, mock_write_str_to_file); /* Boggus directory so when we try to write the permanent client * authorization data to disk, we don't fail. See * store_permanent_client_auth_credentials() for more details. */ mocked_options.ClientOnionAuthDir = tor_strdup("auth_dir"); hs_init(); /* Generate service keypair */ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0)); /* Generate a client authorization object. */ auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); /* Set it up. No flags meaning it is ephemeral. */ curve25519_secret_key_generate(&auth->enc_seckey, 0); hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address); auth->flags = 0; /* Confirm that there is nothing in the client auth map. It is unallocated * until we add the first entry. */ tt_assert(!get_hs_client_auths_map()); /* Add an entry to the client auth list. We loose ownership of the auth * object so nullify it. */ status = hs_client_register_auth_credentials(auth); auth = NULL; tt_int_op(status, OP_EQ, REGISTER_SUCCESS); /* We should have the entry now. */ digest256map_t *client_auths = get_hs_client_auths_map(); tt_assert(client_auths); tt_int_op(digest256map_size(client_auths), OP_EQ, 1); /* Purge the cache that should remove all ephemeral values. */ purge_ephemeral_client_auth(); tt_int_op(digest256map_size(client_auths), OP_EQ, 0); /* Now add a new authorization object but permanent. */ /* Generate a client authorization object. */ auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); curve25519_secret_key_generate(&auth->enc_seckey, 0); hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address); auth->flags = CLIENT_AUTH_FLAG_IS_PERMANENT; /* Add an entry to the client auth list. We loose ownership of the auth * object so nullify it. */ status = hs_client_register_auth_credentials(auth); auth = NULL; tt_int_op(status, OP_EQ, REGISTER_SUCCESS); tt_int_op(digest256map_size(client_auths), OP_EQ, 1); /* Purge again, the entry should still be there. */ purge_ephemeral_client_auth(); tt_int_op(digest256map_size(client_auths), OP_EQ, 1); done: client_service_authorization_free(auth); hs_free_all(); tor_free(mocked_options.ClientOnionAuthDir); UNMOCK(check_private_dir); UNMOCK(get_options); UNMOCK(write_str_to_file); } struct testcase_t hs_client_tests[] = { { "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy, TT_FORK, NULL, NULL }, Loading Loading @@ -1357,5 +1453,9 @@ struct testcase_t hs_client_tests[] = { /* SOCKS5 Extended Error Code. */ { "socks_hs_errors", test_socks_hs_errors, TT_FORK, NULL, NULL }, /* Client authorization. */ { "purge_ephemeral_client_auth", test_purge_ephemeral_client_auth, TT_FORK, NULL, NULL }, END_OF_TESTCASES };