mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 04:13:28 +01:00
hs-v2: Removal of service and relay support
This is unfortunately massive but both functionalities were extremely intertwined and it would have required us to actually change the HSv2 code in order to be able to split this into multiple commits. After this commit, there are still artefacts of v2 in the code but there is no more support for service, intro point and HSDir. The v2 support for rendezvous circuit is still available since that code is the same for the v3 and we will leave it in so if a client is able to rendezvous on v2 then it can still transfer traffic. Once the entire network has moved away from v2, we can remove v2 rendezvous point support. Related to #40266 Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
a34885bc80
commit
2c865542b6
@ -103,8 +103,6 @@
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/relay/relay_config.h"
|
||||
#include "feature/relay/transport_config.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
#include "feature/stats/geoip_stats.h"
|
||||
#include "lib/compress/compress.h"
|
||||
@ -2089,7 +2087,7 @@ options_act,(const or_options_t *old_options))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rend_non_anonymous_mode_enabled(options)) {
|
||||
if (hs_service_non_anonymous_mode_enabled(options)) {
|
||||
log_warn(LD_GENERAL, "This copy of Tor was compiled or configured to run "
|
||||
"in a non-anonymous mode. It will provide NO ANONYMITY.");
|
||||
}
|
||||
@ -3199,7 +3197,7 @@ options_validate_single_onion(or_options_t *options, char **msg)
|
||||
}
|
||||
|
||||
/* Now that we've checked that the two options are consistent, we can safely
|
||||
* call the rend_service_* functions that abstract these options. */
|
||||
* call the hs_service_* functions that abstract these options. */
|
||||
|
||||
/* If you run an anonymous client with an active Single Onion service, the
|
||||
* client loses anonymity. */
|
||||
@ -3208,13 +3206,13 @@ options_validate_single_onion(or_options_t *options, char **msg)
|
||||
options->NATDPort_set ||
|
||||
options->DNSPort_set ||
|
||||
options->HTTPTunnelPort_set);
|
||||
if (rend_service_non_anonymous_mode_enabled(options) && client_port_set) {
|
||||
if (hs_service_non_anonymous_mode_enabled(options) && client_port_set) {
|
||||
REJECT("HiddenServiceNonAnonymousMode is incompatible with using Tor as "
|
||||
"an anonymous client. Please set Socks/Trans/NATD/DNSPort to 0, or "
|
||||
"revert HiddenServiceNonAnonymousMode to 0.");
|
||||
}
|
||||
|
||||
if (rend_service_allow_non_anonymous_connection(options)
|
||||
if (hs_service_allow_non_anonymous_connection(options)
|
||||
&& options->UseEntryGuards) {
|
||||
/* Single Onion services only use entry guards when uploading descriptors;
|
||||
* all other connections are one-hop. Further, Single Onions causes the
|
||||
@ -3564,7 +3562,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
|
||||
|
||||
if (!(options->UseEntryGuards) &&
|
||||
(options->RendConfigLines != NULL) &&
|
||||
!rend_service_allow_non_anonymous_connection(options)) {
|
||||
!hs_service_allow_non_anonymous_connection(options)) {
|
||||
log_warn(LD_CONFIG,
|
||||
"UseEntryGuards is disabled, but you have configured one or more "
|
||||
"hidden services on this Tor instance. Your hidden services "
|
||||
@ -3607,7 +3605,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
|
||||
}
|
||||
|
||||
/* Single Onion Services: non-anonymous hidden services */
|
||||
if (rend_service_non_anonymous_mode_enabled(options)) {
|
||||
if (hs_service_non_anonymous_mode_enabled(options)) {
|
||||
log_warn(LD_CONFIG,
|
||||
"HiddenServiceNonAnonymousMode is set. Every hidden service on "
|
||||
"this tor instance is NON-ANONYMOUS. If "
|
||||
|
@ -336,7 +336,7 @@ struct or_options_t {
|
||||
/* Makes hidden service clients and servers non-anonymous on this tor
|
||||
* instance. Allows the non-anonymous HiddenServiceSingleHopMode. Enables
|
||||
* non-anonymous behaviour in the hidden service protocol.
|
||||
* Use rend_service_non_anonymous_mode_enabled() instead of using this option
|
||||
* Use hs_service_non_anonymous_mode_enabled() instead of using this option
|
||||
* directly.
|
||||
*/
|
||||
int HiddenServiceNonAnonymousMode;
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/hibernate/hibernate.h"
|
||||
#include "feature/hs/hs_dos.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
@ -51,8 +52,6 @@
|
||||
#include "feature/relay/ext_orport.h"
|
||||
#include "feature/relay/routerkeys.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "feature/stats/bwhist.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
@ -427,7 +426,6 @@ dumpstats(int severity)
|
||||
dumpmemusage(severity);
|
||||
|
||||
rep_hist_dump_stats(now,severity);
|
||||
rend_service_dump_stats(severity);
|
||||
hs_service_dump_stats(severity);
|
||||
}
|
||||
|
||||
@ -553,7 +551,6 @@ tor_init(int argc, char *argv[])
|
||||
rep_hist_init();
|
||||
bwhist_init();
|
||||
/* Initialize the service cache. */
|
||||
rend_cache_init();
|
||||
addressmap_init(); /* Init the client dns cache. Do it always, since it's
|
||||
* cheap. */
|
||||
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/relay/ext_orport.h"
|
||||
#include "feature/relay/relay_config.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/stats/bwhist.h"
|
||||
#include "feature/stats/geoip_stats.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
@ -118,7 +117,6 @@ tor_free_all(int postfork)
|
||||
networkstatus_free_all();
|
||||
addressmap_free_all();
|
||||
dirserv_free_all();
|
||||
rend_cache_free_all();
|
||||
rep_hist_free_all();
|
||||
bwhist_free_all();
|
||||
circuit_free_all();
|
||||
|
@ -897,7 +897,6 @@ connection_free_minimal(connection_t *conn)
|
||||
}
|
||||
}
|
||||
if (CONN_IS_EDGE(conn)) {
|
||||
rend_data_free(TO_EDGE_CONN(conn)->rend_data);
|
||||
hs_ident_edge_conn_free(TO_EDGE_CONN(conn)->hs_ident);
|
||||
}
|
||||
if (conn->type == CONN_TYPE_CONTROL) {
|
||||
@ -926,7 +925,6 @@ connection_free_minimal(connection_t *conn)
|
||||
tor_compress_free(dir_conn->compress_state);
|
||||
dir_conn_clear_spool(dir_conn);
|
||||
|
||||
rend_data_free(dir_conn->rend_data);
|
||||
hs_ident_dir_conn_free(dir_conn->hs_ident);
|
||||
if (dir_conn->guard_state) {
|
||||
/* Cancel before freeing, if it's still there. */
|
||||
@ -4804,34 +4802,6 @@ connection_get_by_type_nonlinked,(int type))
|
||||
CONN_GET_TEMPLATE(conn, conn->type == type && !conn->linked);
|
||||
}
|
||||
|
||||
/** Return a connection of type <b>type</b> that has rendquery equal
|
||||
* to <b>rendquery</b>, and that is not marked for close. If state
|
||||
* is non-zero, conn must be of that state too.
|
||||
*/
|
||||
connection_t *
|
||||
connection_get_by_type_state_rendquery(int type, int state,
|
||||
const char *rendquery)
|
||||
{
|
||||
tor_assert(type == CONN_TYPE_DIR ||
|
||||
type == CONN_TYPE_AP || type == CONN_TYPE_EXIT);
|
||||
tor_assert(rendquery);
|
||||
|
||||
CONN_GET_TEMPLATE(conn,
|
||||
(conn->type == type &&
|
||||
(!state || state == conn->state)) &&
|
||||
(
|
||||
(type == CONN_TYPE_DIR &&
|
||||
TO_DIR_CONN(conn)->rend_data &&
|
||||
!rend_cmp_service_ids(rendquery,
|
||||
rend_data_get_address(TO_DIR_CONN(conn)->rend_data)))
|
||||
||
|
||||
(CONN_IS_EDGE(conn) &&
|
||||
TO_EDGE_CONN(conn)->rend_data &&
|
||||
!rend_cmp_service_ids(rendquery,
|
||||
rend_data_get_address(TO_EDGE_CONN(conn)->rend_data)))
|
||||
));
|
||||
}
|
||||
|
||||
/** Return a new smartlist of dir_connection_t * from get_connection_array()
|
||||
* that satisfy conn_test on connection_t *conn_var, and dirconn_test on
|
||||
* dir_connection_t *dirconn_var. conn_var must be of CONN_TYPE_DIR and not
|
||||
|
@ -91,8 +91,6 @@
|
||||
#include "feature/relay/routerkeys.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/relay/selftest.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/geoip_stats.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "feature/stats/connstats.h"
|
||||
@ -1468,8 +1466,7 @@ get_my_roles(const or_options_t *options)
|
||||
int is_relay = server_mode(options);
|
||||
int is_dirauth = authdir_mode_v3(options);
|
||||
int is_bridgeauth = authdir_mode_bridge(options);
|
||||
int is_hidden_service = !!hs_service_get_num_services() ||
|
||||
!!rend_num_services();
|
||||
int is_hidden_service = !!hs_service_get_num_services();
|
||||
int is_dirserver = dir_server_mode(options);
|
||||
int sending_control_events = control_any_per_second_event_enabled();
|
||||
|
||||
@ -1826,7 +1823,7 @@ check_network_participation_callback(time_t now, const or_options_t *options)
|
||||
/* If we're running an onion service, we can't become dormant. */
|
||||
/* XXXX this would be nice to change, so that we can be dormant with a
|
||||
* service. */
|
||||
if (hs_service_get_num_services() || rend_num_services()) {
|
||||
if (hs_service_get_num_services()) {
|
||||
goto found_activity;
|
||||
}
|
||||
|
||||
@ -2013,7 +2010,6 @@ clean_caches_callback(time_t now, const or_options_t *options)
|
||||
{
|
||||
/* Remove old information from rephist and the rend cache. */
|
||||
rep_history_clean(now - options->RephistTrackTime);
|
||||
rend_cache_clean(now, REND_CACHE_TYPE_SERVICE);
|
||||
hs_cache_clean_as_client(now);
|
||||
hs_cache_clean_as_dir(now);
|
||||
microdesc_cache_rebuild(NULL, 0);
|
||||
@ -2032,7 +2028,6 @@ rend_cache_failure_clean_callback(time_t now, const or_options_t *options)
|
||||
/* We don't keep entries that are more than five minutes old so we try to
|
||||
* clean it as soon as we can since we want to make sure the client waits
|
||||
* as little as possible for reachability reasons. */
|
||||
rend_cache_failure_clean(now);
|
||||
hs_cache_client_intro_state_clean(now);
|
||||
return 30;
|
||||
}
|
||||
|
@ -71,12 +71,12 @@
|
||||
#include "core/or/relay.h"
|
||||
#include "core/or/scheduler.h"
|
||||
#include "feature/client/entrynodes.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/geoip_stats.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "lib/evloop/timers.h"
|
||||
@ -1897,7 +1897,7 @@ channel_do_open_actions(channel_t *chan)
|
||||
if (!get_options()->ConnectionPadding) {
|
||||
/* Disable if torrc disabled */
|
||||
channelpadding_disable_padding_on_channel(chan);
|
||||
} else if (rend_service_allow_non_anonymous_connection(get_options()) &&
|
||||
} else if (hs_service_allow_non_anonymous_connection(get_options()) &&
|
||||
!networkstatus_get_param(NULL,
|
||||
CHANNELPADDING_SOS_PARAM,
|
||||
CHANNELPADDING_SOS_DEFAULT, 0, 1)) {
|
||||
|
@ -27,8 +27,8 @@
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "lib/time/compat_time.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "lib/evloop/timers.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
|
||||
#include "core/or/cell_st.h"
|
||||
#include "core/or/or_connection_st.h"
|
||||
@ -744,7 +744,7 @@ channelpadding_decide_to_pad_channel(channel_t *chan)
|
||||
return CHANNELPADDING_WONTPAD;
|
||||
}
|
||||
|
||||
if (rend_service_allow_non_anonymous_connection(options) &&
|
||||
if (hs_service_allow_non_anonymous_connection(options) &&
|
||||
!consensus_nf_pad_single_onion) {
|
||||
/* If the consensus just changed values, this channel may still
|
||||
* think padding is enabled. Negotiate it off. */
|
||||
|
@ -69,7 +69,6 @@
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/relay/selftest.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/trace/events.h"
|
||||
@ -1331,16 +1330,13 @@ circuit_truncated(origin_circuit_t *circ, int reason)
|
||||
* CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
|
||||
*
|
||||
* - A hidden service connecting to a rendezvous point, which the
|
||||
* client picked (CIRCUIT_PURPOSE_S_CONNECT_REND, via
|
||||
* rend_service_receive_introduction() and
|
||||
* rend_service_relaunch_rendezvous)
|
||||
* client picked (CIRCUIT_PURPOSE_S_CONNECT_REND.
|
||||
*
|
||||
* There are currently two situations where we picked the exit node
|
||||
* ourselves, making DEFAULT_ROUTE_LEN a safe circuit length:
|
||||
*
|
||||
* - We are a hidden service connecting to an introduction point
|
||||
* (CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, via
|
||||
* rend_service_launch_establish_intro())
|
||||
* (CIRCUIT_PURPOSE_S_ESTABLISH_INTRO).
|
||||
*
|
||||
* - We are a router testing its own reachabiity
|
||||
* (CIRCUIT_PURPOSE_TESTING, via router_do_reachability_checks())
|
||||
@ -2030,7 +2026,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
|
||||
|
||||
if (state->onehop_tunnel) {
|
||||
log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel%s.",
|
||||
(rend_allow_non_anonymous_connection(get_options()) ?
|
||||
(hs_service_allow_non_anonymous_connection(get_options()) ?
|
||||
", or intro or rendezvous connection" : ""));
|
||||
state->desired_path_len = 1;
|
||||
} else {
|
||||
|
@ -43,7 +43,6 @@
|
||||
* For hidden services, we need to be able to look up introduction point
|
||||
* circuits and rendezvous circuits by cookie, key, etc. These are
|
||||
* currently handled with linear searches in
|
||||
* circuit_get_ready_rend_circuit_by_rend_data(),
|
||||
* circuit_get_next_by_pk_and_purpose(), and with hash lookups in
|
||||
* circuit_get_rendezvous() and circuit_get_intro_point().
|
||||
*
|
||||
@ -77,6 +76,7 @@
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/client/entrynodes.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "feature/hs/hs_cache.h"
|
||||
#include "feature/hs/hs_circuit.h"
|
||||
#include "feature/hs/hs_circuitmap.h"
|
||||
#include "feature/hs/hs_ident.h"
|
||||
@ -88,7 +88,6 @@
|
||||
#include "core/or/policies.h"
|
||||
#include "core/or/relay.h"
|
||||
#include "core/crypto/relay_crypto.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "feature/stats/bwhist.h"
|
||||
@ -135,7 +134,6 @@ static smartlist_t *circuits_pending_other_guards = NULL;
|
||||
* circuit_mark_for_close and which are waiting for circuit_about_to_free. */
|
||||
static smartlist_t *circuits_pending_close = NULL;
|
||||
|
||||
static void cpath_ref_decref(crypt_path_reference_t *cpath_ref);
|
||||
static void circuit_about_to_free_atexit(circuit_t *circ);
|
||||
static void circuit_about_to_free(circuit_t *circ);
|
||||
|
||||
@ -1163,8 +1161,6 @@ circuit_free_(circuit_t *circ)
|
||||
|
||||
if (ocirc->build_state) {
|
||||
extend_info_free(ocirc->build_state->chosen_exit);
|
||||
cpath_free(ocirc->build_state->pending_final_cpath);
|
||||
cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref);
|
||||
}
|
||||
tor_free(ocirc->build_state);
|
||||
|
||||
@ -1177,7 +1173,6 @@ circuit_free_(circuit_t *circ)
|
||||
circuit_clear_cpath(ocirc);
|
||||
|
||||
crypto_pk_free(ocirc->intro_key);
|
||||
rend_data_free(ocirc->rend_data);
|
||||
|
||||
/* Finally, free the identifier of the circuit and nullify it so multiple
|
||||
* cleanup will work. */
|
||||
@ -1354,18 +1349,6 @@ circuit_free_all(void)
|
||||
HT_CLEAR(chan_circid_map, &chan_circid_map);
|
||||
}
|
||||
|
||||
/** Release a crypt_path_reference_t*, which may be NULL. */
|
||||
static void
|
||||
cpath_ref_decref(crypt_path_reference_t *cpath_ref)
|
||||
{
|
||||
if (cpath_ref != NULL) {
|
||||
if (--(cpath_ref->refcount) == 0) {
|
||||
cpath_free(cpath_ref->cpath);
|
||||
tor_free(cpath_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A helper function for circuit_dump_by_conn() below. Log a bunch
|
||||
* of information about circuit <b>circ</b>.
|
||||
*/
|
||||
@ -1684,37 +1667,6 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason)
|
||||
smartlist_free(detached);
|
||||
}
|
||||
|
||||
/** Return a circ such that
|
||||
* - circ-\>rend_data-\>onion_address is equal to
|
||||
* <b>rend_data</b>-\>onion_address,
|
||||
* - circ-\>rend_data-\>rend_cookie is equal to
|
||||
* <b>rend_data</b>-\>rend_cookie, and
|
||||
* - circ-\>purpose is equal to CIRCUIT_PURPOSE_C_REND_READY.
|
||||
*
|
||||
* Return NULL if no such circuit exists.
|
||||
*/
|
||||
origin_circuit_t *
|
||||
circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
|
||||
{
|
||||
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
|
||||
if (!circ->marked_for_close &&
|
||||
circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
|
||||
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
|
||||
if (ocirc->rend_data == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (!rend_cmp_service_ids(rend_data_get_address(rend_data),
|
||||
rend_data_get_address(ocirc->rend_data)) &&
|
||||
tor_memeq(ocirc->rend_data->rend_cookie,
|
||||
rend_data->rend_cookie,
|
||||
REND_COOKIE_LEN))
|
||||
return ocirc;
|
||||
}
|
||||
}
|
||||
SMARTLIST_FOREACH_END(circ);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return the first introduction circuit originating from the global circuit
|
||||
* list after <b>start</b> or at the start of the list if <b>start</b> is
|
||||
* NULL. Return NULL if no circuit is found.
|
||||
@ -1811,14 +1763,10 @@ circuit_get_next_service_rp_circ(origin_circuit_t *start)
|
||||
}
|
||||
|
||||
/** Return the first circuit originating here in global_circuitlist after
|
||||
* <b>start</b> whose purpose is <b>purpose</b>, and where <b>digest</b> (if
|
||||
* set) matches the private key digest of the rend data associated with the
|
||||
* circuit. Return NULL if no circuit is found. If <b>start</b> is NULL,
|
||||
* begin at the start of the list.
|
||||
*/
|
||||
* <b>start</b> whose purpose is <b>purpose</b>. Return NULL if no circuit is
|
||||
* found. If <b>start</b> is NULL, begin at the start of the list. */
|
||||
origin_circuit_t *
|
||||
circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
|
||||
const uint8_t *digest, uint8_t purpose)
|
||||
circuit_get_next_by_purpose(origin_circuit_t *start, uint8_t purpose)
|
||||
{
|
||||
int idx;
|
||||
smartlist_t *lst = circuit_get_global_list();
|
||||
@ -1830,7 +1778,6 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
|
||||
|
||||
for ( ; idx < smartlist_len(lst); ++idx) {
|
||||
circuit_t *circ = smartlist_get(lst, idx);
|
||||
origin_circuit_t *ocirc;
|
||||
|
||||
if (circ->marked_for_close)
|
||||
continue;
|
||||
@ -1841,12 +1788,7 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
|
||||
if (BUG(!CIRCUIT_PURPOSE_IS_ORIGIN(circ->purpose))) {
|
||||
break;
|
||||
}
|
||||
ocirc = TO_ORIGIN_CIRCUIT(circ);
|
||||
if (!digest)
|
||||
return ocirc;
|
||||
if (rend_circuit_pk_digest_eq(ocirc, digest)) {
|
||||
return ocirc;
|
||||
}
|
||||
return TO_ORIGIN_CIRCUIT(circ);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -2670,7 +2612,7 @@ circuits_handle_oom(size_t current_allocation)
|
||||
tor_zlib_get_total_allocation(),
|
||||
tor_zstd_get_total_allocation(),
|
||||
tor_lzma_get_total_allocation(),
|
||||
rend_cache_get_total_allocation());
|
||||
hs_cache_get_total_allocation());
|
||||
|
||||
{
|
||||
size_t mem_target = (size_t)(get_options()->MaxMemInQueues *
|
||||
|
@ -60,9 +60,7 @@
|
||||
* to becoming open, or they are open and have sent the
|
||||
* establish_rendezvous cell but haven't received an ack.
|
||||
* circuits that are c_rend_ready are open and have received a
|
||||
* rend ack, but haven't heard from the service yet. if they have a
|
||||
* buildstate->pending_final_cpath then they're expecting a
|
||||
* cell from the service, else they're not.
|
||||
* rend ack, but haven't heard from the service yet.
|
||||
* circuits that are c_rend_ready_intro_acked are open, and
|
||||
* some intro circ has sent its intro and received an ack.
|
||||
* circuits that are c_rend_joined are open, have heard from
|
||||
@ -206,10 +204,8 @@ int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan);
|
||||
circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn);
|
||||
void circuit_unlink_all_from_channel(channel_t *chan, int reason);
|
||||
origin_circuit_t *circuit_get_by_global_id(uint32_t id);
|
||||
origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data(
|
||||
const rend_data_t *rend_data);
|
||||
origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
|
||||
const uint8_t *digest, uint8_t purpose);
|
||||
origin_circuit_t *circuit_get_next_by_purpose(origin_circuit_t *start,
|
||||
uint8_t purpose);
|
||||
origin_circuit_t *circuit_get_next_intro_circ(const origin_circuit_t *start,
|
||||
bool want_client_circ);
|
||||
origin_circuit_t *circuit_get_next_service_rp_circ(origin_circuit_t *start);
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "app/config/statefile.h"
|
||||
#include "core/or/circuitlist.h"
|
||||
@ -43,6 +42,7 @@
|
||||
#include "lib/time/tvdiff.h"
|
||||
#include "lib/encoding/confline.h"
|
||||
#include "feature/dirauth/authmode.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "feature/relay/relay_periodic.h"
|
||||
|
||||
#include "core/or/crypt_path_st.h"
|
||||
@ -145,8 +145,8 @@ circuit_build_times_disabled_(const or_options_t *options,
|
||||
*
|
||||
* If we fix both of these issues someday, we should test
|
||||
* these modes with LearnCircuitBuildTimeout on again. */
|
||||
int single_onion_disabled = rend_service_allow_non_anonymous_connection(
|
||||
options);
|
||||
int single_onion_disabled = hs_service_allow_non_anonymous_connection(
|
||||
options);
|
||||
|
||||
if (consensus_disabled || config_disabled || dirauth_disabled ||
|
||||
state_disabled || single_onion_disabled) {
|
||||
|
@ -58,8 +58,6 @@
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/relay/selftest.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "lib/math/fp.h"
|
||||
#include "lib/time/tvdiff.h"
|
||||
@ -83,16 +81,6 @@ static int
|
||||
circuit_matches_with_rend_stream(const edge_connection_t *edge_conn,
|
||||
const origin_circuit_t *origin_circ)
|
||||
{
|
||||
/* Check if this is a v2 rendezvous circ/stream */
|
||||
if ((edge_conn->rend_data && !origin_circ->rend_data) ||
|
||||
(!edge_conn->rend_data && origin_circ->rend_data) ||
|
||||
(edge_conn->rend_data && origin_circ->rend_data &&
|
||||
rend_cmp_service_ids(rend_data_get_address(edge_conn->rend_data),
|
||||
rend_data_get_address(origin_circ->rend_data)))) {
|
||||
/* this circ is not for this conn */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if this is a v3 rendezvous circ/stream */
|
||||
if ((edge_conn->hs_ident && !origin_circ->hs_ident) ||
|
||||
(!edge_conn->hs_ident && origin_circ->hs_ident) ||
|
||||
@ -688,8 +676,7 @@ circuit_expire_building(void)
|
||||
/* c_rend_ready circs measure age since timestamp_dirty,
|
||||
* because that's set when they switch purposes
|
||||
*/
|
||||
if (TO_ORIGIN_CIRCUIT(victim)->rend_data ||
|
||||
TO_ORIGIN_CIRCUIT(victim)->hs_ident ||
|
||||
if (TO_ORIGIN_CIRCUIT(victim)->hs_ident ||
|
||||
victim->timestamp_dirty > cutoff.tv_sec)
|
||||
continue;
|
||||
break;
|
||||
@ -896,7 +883,7 @@ circuit_log_ancient_one_hop_circuits(int age)
|
||||
continue;
|
||||
/* Single Onion Services deliberately make long term one-hop intro
|
||||
* and rendezvous connections. Don't log the established ones. */
|
||||
if (rend_service_allow_non_anonymous_connection(options) &&
|
||||
if (hs_service_allow_non_anonymous_connection(options) &&
|
||||
(circ->purpose == CIRCUIT_PURPOSE_S_INTRO ||
|
||||
circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED))
|
||||
continue;
|
||||
@ -1141,7 +1128,7 @@ needs_exit_circuits(time_t now, int *needs_uptime, int *needs_capacity)
|
||||
STATIC int
|
||||
needs_hs_server_circuits(time_t now, int num_uptime_internal)
|
||||
{
|
||||
if (!rend_num_services() && !hs_service_get_num_services()) {
|
||||
if (!hs_service_get_num_services()) {
|
||||
/* No services, we don't need anything. */
|
||||
goto no_need;
|
||||
}
|
||||
@ -2013,14 +2000,6 @@ circuit_purpose_is_hs_vanguards(const uint8_t purpose)
|
||||
return (purpose == CIRCUIT_PURPOSE_HS_VANGUARDS);
|
||||
}
|
||||
|
||||
/** Return true iff the given circuit is an HS v2 circuit. */
|
||||
bool
|
||||
circuit_is_hs_v2(const circuit_t *circ)
|
||||
{
|
||||
return (CIRCUIT_IS_ORIGIN(circ) &&
|
||||
(CONST_TO_ORIGIN_CIRCUIT(circ)->rend_data != NULL));
|
||||
}
|
||||
|
||||
/** Return true iff the given circuit is an HS v3 circuit. */
|
||||
bool
|
||||
circuit_is_hs_v3(const circuit_t *circ)
|
||||
@ -2451,11 +2430,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
|
||||
connection_ap_mark_as_waiting_for_renddesc(conn);
|
||||
return 0;
|
||||
}
|
||||
log_info(LD_REND,"Chose %s as intro point for '%s'.",
|
||||
extend_info_describe(extend_info),
|
||||
(edge_conn->rend_data) ?
|
||||
safe_str_client(rend_data_get_address(edge_conn->rend_data)) :
|
||||
"service");
|
||||
log_info(LD_REND,"Chose %s as intro point for service",
|
||||
extend_info_describe(extend_info));
|
||||
}
|
||||
|
||||
/* If we have specified a particular exit node for our
|
||||
@ -2579,10 +2555,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
|
||||
rep_hist_note_used_internal(time(NULL), need_uptime, 1);
|
||||
if (circ) {
|
||||
const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
|
||||
if (edge_conn->rend_data) {
|
||||
/* write the service_id into circ */
|
||||
circ->rend_data = rend_data_dup(edge_conn->rend_data);
|
||||
} else if (edge_conn->hs_ident) {
|
||||
if (edge_conn->hs_ident) {
|
||||
circ->hs_ident =
|
||||
hs_ident_circuit_new(&edge_conn->hs_ident->identity_pk);
|
||||
}
|
||||
@ -2829,13 +2802,9 @@ connection_ap_get_nonrend_circ_purpose(const entry_connection_t *conn)
|
||||
if (base_conn->linked_conn &&
|
||||
base_conn->linked_conn->type == CONN_TYPE_DIR) {
|
||||
/* Set a custom purpose for hsdir activity */
|
||||
if (base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2 ||
|
||||
base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_HSDESC) {
|
||||
if (base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_HSDESC) {
|
||||
return CIRCUIT_PURPOSE_S_HSDIR_POST;
|
||||
} else if (base_conn->linked_conn->purpose
|
||||
== DIR_PURPOSE_FETCH_RENDDESC_V2 ||
|
||||
base_conn->linked_conn->purpose
|
||||
== DIR_PURPOSE_FETCH_HSDESC) {
|
||||
} else if (base_conn->linked_conn->purpose == DIR_PURPOSE_FETCH_HSDESC) {
|
||||
return CIRCUIT_PURPOSE_C_HSDIR_GET;
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,6 @@
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "lib/buf/buffers.h"
|
||||
@ -3823,13 +3822,7 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
|
||||
conn->base_.address = tor_strdup("(rendezvous)");
|
||||
conn->base_.state = EXIT_CONN_STATE_CONNECTING;
|
||||
|
||||
/* The circuit either has an hs identifier for v3+ or a rend_data for legacy
|
||||
* service. */
|
||||
if (origin_circ->rend_data) {
|
||||
conn->rend_data = rend_data_dup(origin_circ->rend_data);
|
||||
tor_assert(connection_edge_is_rendezvous_stream(conn));
|
||||
ret = rend_service_set_connection_addr_port(conn, origin_circ);
|
||||
} else if (origin_circ->hs_ident) {
|
||||
if (origin_circ->hs_ident) {
|
||||
/* Setup the identifier to be the one for the circuit service. */
|
||||
conn->hs_ident =
|
||||
hs_ident_edge_conn_new(&origin_circ->hs_ident->identity_pk);
|
||||
@ -4392,10 +4385,8 @@ int
|
||||
connection_edge_is_rendezvous_stream(const edge_connection_t *conn)
|
||||
{
|
||||
tor_assert(conn);
|
||||
/* It should not be possible to set both of these structs */
|
||||
tor_assert_nonfatal(!(conn->rend_data && conn->hs_ident));
|
||||
|
||||
if (conn->rend_data || conn->hs_ident) {
|
||||
if (conn->hs_ident) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -66,6 +66,7 @@
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "core/or/channelpadding.h"
|
||||
#include "feature/dirauth/authmode.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
|
||||
#include "core/or/cell_st.h"
|
||||
#include "core/or/cell_queue_st.h"
|
||||
@ -1979,7 +1980,8 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
|
||||
conn->identity_digest);
|
||||
const int is_authority_fingerprint = router_digest_is_trusted_dir(
|
||||
conn->identity_digest);
|
||||
const int non_anonymous_mode = rend_non_anonymous_mode_enabled(options);
|
||||
const int non_anonymous_mode =
|
||||
hs_service_non_anonymous_mode_enabled(options);
|
||||
int severity;
|
||||
const char *extra_log = "";
|
||||
|
||||
|
@ -30,11 +30,6 @@ struct cpath_build_state_t {
|
||||
* These are for encrypted dir conns that exit to this router, not
|
||||
* for arbitrary exits from the circuit. */
|
||||
unsigned int onehop_tunnel : 1;
|
||||
/** The crypt_path_t to append after rendezvous: used for rendezvous. */
|
||||
crypt_path_t *pending_final_cpath;
|
||||
/** A ref-counted reference to the crypt_path_t to append after
|
||||
* rendezvous; used on the service side. */
|
||||
crypt_path_reference_t *service_pending_final_cpath_ref;
|
||||
/** How many times has building a circuit for this task failed? */
|
||||
int failure_count;
|
||||
/** At what time should we give up on this task? */
|
||||
|
@ -33,9 +33,6 @@ struct edge_connection_t {
|
||||
/** A pointer to which node in the circ this conn exits at. Set for AP
|
||||
* connections and for hidden service exit connections. */
|
||||
struct crypt_path_t *cpath_layer;
|
||||
/** What rendezvous service are we querying for (if an AP) or providing (if
|
||||
* an exit)? */
|
||||
rend_data_t *rend_data;
|
||||
|
||||
/* Hidden service connection identifier for edge connections. Used by the HS
|
||||
* client-side code to identify client SOCKS connections and by the
|
||||
|
@ -415,60 +415,6 @@ typedef struct rend_service_authorization_t {
|
||||
rend_auth_type_t auth_type;
|
||||
} rend_service_authorization_t;
|
||||
|
||||
/** Client- and server-side data that is used for hidden service connection
|
||||
* establishment. Not all fields contain data depending on where this struct
|
||||
* is used. */
|
||||
typedef struct rend_data_t {
|
||||
/* Hidden service protocol version of this base object. */
|
||||
uint32_t version;
|
||||
|
||||
/** List of HSDir fingerprints on which this request has been sent to. This
|
||||
* contains binary identity digest of the directory of size DIGEST_LEN. */
|
||||
smartlist_t *hsdirs_fp;
|
||||
|
||||
/** Rendezvous cookie used by both, client and service. */
|
||||
char rend_cookie[REND_COOKIE_LEN];
|
||||
|
||||
/** Number of streams associated with this rendezvous circuit. */
|
||||
int nr_streams;
|
||||
} rend_data_t;
|
||||
|
||||
typedef struct rend_data_v2_t {
|
||||
/* Rendezvous base data. */
|
||||
rend_data_t base_;
|
||||
|
||||
/** Onion address (without the .onion part) that a client requests. */
|
||||
char onion_address[REND_SERVICE_ID_LEN_BASE32+1];
|
||||
|
||||
/** Descriptor ID for each replicas computed from the onion address. If
|
||||
* the onion address is empty, this array MUST be empty. We keep them so
|
||||
* we know when to purge our entry in the last hsdir request table. */
|
||||
char descriptor_id[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS][DIGEST_LEN];
|
||||
|
||||
/** (Optional) descriptor cookie that is used by a client. */
|
||||
char descriptor_cookie[REND_DESC_COOKIE_LEN];
|
||||
|
||||
/** Authorization type for accessing a service used by a client. */
|
||||
rend_auth_type_t auth_type;
|
||||
|
||||
/** Descriptor ID for a client request. The control port command HSFETCH
|
||||
* uses this. It's set if the descriptor query should only use this
|
||||
* descriptor ID. */
|
||||
char desc_id_fetch[DIGEST_LEN];
|
||||
|
||||
/** Hash of the hidden service's PK used by a service. */
|
||||
char rend_pk_digest[DIGEST_LEN];
|
||||
} rend_data_v2_t;
|
||||
|
||||
/* From a base rend_data_t object <b>d</d>, return the v2 object. */
|
||||
static inline
|
||||
rend_data_v2_t *TO_REND_DATA_V2(const rend_data_t *d)
|
||||
{
|
||||
tor_assert(d);
|
||||
tor_assert(d->version == 2);
|
||||
return DOWNCAST(rend_data_v2_t, d);
|
||||
}
|
||||
|
||||
/* Stub because we can't include hs_ident.h. */
|
||||
struct hs_ident_edge_conn_t;
|
||||
struct hs_ident_dir_conn_t;
|
||||
|
@ -128,9 +128,6 @@ struct origin_circuit_t {
|
||||
*/
|
||||
crypt_path_t *cpath;
|
||||
|
||||
/** Holds all rendezvous data on either client or service side. */
|
||||
rend_data_t *rend_data;
|
||||
|
||||
/** Holds hidden service identifier on either client or service side. This
|
||||
* is for both introduction and rendezvous circuit. */
|
||||
struct hs_ident_circuit_t *hs_ident;
|
||||
|
@ -78,7 +78,6 @@
|
||||
#include "core/or/reasons.h"
|
||||
#include "core/or/relay.h"
|
||||
#include "core/crypto/relay_crypto.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/nodelist/describe.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
@ -2711,8 +2710,8 @@ cell_queues_check_size(void)
|
||||
alloc += half_streams_get_total_allocation();
|
||||
alloc += buf_get_total_allocation();
|
||||
alloc += tor_compress_get_total_allocation();
|
||||
const size_t rend_cache_total = rend_cache_get_total_allocation();
|
||||
alloc += rend_cache_total;
|
||||
const size_t hs_cache_total = hs_cache_get_total_allocation();
|
||||
alloc += hs_cache_total;
|
||||
const size_t geoip_client_cache_total =
|
||||
geoip_client_cache_total_allocation();
|
||||
alloc += geoip_client_cache_total;
|
||||
@ -2724,9 +2723,9 @@ cell_queues_check_size(void)
|
||||
/* If we're spending over 20% of the memory limit on hidden service
|
||||
* descriptors, free them until we're down to 10%. Do the same for geoip
|
||||
* client cache. */
|
||||
if (rend_cache_total > get_options()->MaxMemInQueues / 5) {
|
||||
if (hs_cache_total > get_options()->MaxMemInQueues / 5) {
|
||||
const size_t bytes_to_remove =
|
||||
rend_cache_total - (size_t)(get_options()->MaxMemInQueues / 10);
|
||||
hs_cache_total - (size_t)(get_options()->MaxMemInQueues / 10);
|
||||
alloc -= hs_cache_handle_oom(now, bytes_to_remove);
|
||||
}
|
||||
if (geoip_client_cache_total > get_options()->MaxMemInQueues / 5) {
|
||||
|
@ -48,8 +48,8 @@
|
||||
#include "feature/control/control_cmd.h"
|
||||
#include "feature/control/control_events.h"
|
||||
#include "feature/control/control_proto.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/hs/hs_common.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "lib/evloop/procmon.h"
|
||||
|
||||
#include "feature/control/control_connection_st.h"
|
||||
@ -240,9 +240,7 @@ connection_control_closed(control_connection_t *conn)
|
||||
*/
|
||||
if (conn->ephemeral_onion_services) {
|
||||
SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) {
|
||||
if (rend_valid_v2_service_id(cp)) {
|
||||
rend_service_del_ephemeral(cp);
|
||||
} else if (hs_address_is_valid(cp)) {
|
||||
if (hs_address_is_valid(cp)) {
|
||||
hs_service_del_ephemeral(cp);
|
||||
} else {
|
||||
/* An invalid .onion in our list should NEVER happen */
|
||||
|
@ -38,8 +38,6 @@
|
||||
#include "feature/nodelist/routerinfo.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
#include "lib/encoding/confline.h"
|
||||
@ -53,9 +51,6 @@
|
||||
#include "feature/control/control_connection_st.h"
|
||||
#include "feature/nodelist/node_st.h"
|
||||
#include "feature/nodelist/routerinfo_st.h"
|
||||
#include "feature/rend/rend_authorized_client_st.h"
|
||||
#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
|
||||
#include "feature/rend/rend_service_descriptor_st.h"
|
||||
|
||||
#include "src/app/config/statefile.h"
|
||||
|
||||
@ -1442,31 +1437,15 @@ handle_control_hsfetch(control_connection_t *conn,
|
||||
const control_cmd_args_t *args)
|
||||
|
||||
{
|
||||
char digest[DIGEST_LEN], *desc_id = NULL;
|
||||
char *desc_id = NULL;
|
||||
smartlist_t *hsdirs = NULL;
|
||||
static const char *v2_str = "v2-";
|
||||
const size_t v2_str_len = strlen(v2_str);
|
||||
rend_data_t *rend_query = NULL;
|
||||
ed25519_public_key_t v3_pk;
|
||||
uint32_t version;
|
||||
const char *hsaddress = NULL;
|
||||
|
||||
/* Extract the first argument (either HSAddress or DescID). */
|
||||
const char *arg1 = smartlist_get(args->args, 0);
|
||||
/* Test if it's an HS address without the .onion part. */
|
||||
if (rend_valid_v2_service_id(arg1)) {
|
||||
hsaddress = arg1;
|
||||
version = HS_VERSION_TWO;
|
||||
} else if (strcmpstart(arg1, v2_str) == 0 &&
|
||||
rend_valid_descriptor_id(arg1 + v2_str_len) &&
|
||||
base32_decode(digest, sizeof(digest), arg1 + v2_str_len,
|
||||
REND_DESC_ID_V2_LEN_BASE32) ==
|
||||
sizeof(digest)) {
|
||||
/* We have a well formed version 2 descriptor ID. Keep the decoded value
|
||||
* of the id. */
|
||||
desc_id = digest;
|
||||
version = HS_VERSION_TWO;
|
||||
} else if (hs_address_is_valid(arg1)) {
|
||||
if (hs_address_is_valid(arg1)) {
|
||||
hsaddress = arg1;
|
||||
version = HS_VERSION_THREE;
|
||||
hs_parse_address(hsaddress, &v3_pk, NULL, NULL);
|
||||
@ -1495,15 +1474,6 @@ handle_control_hsfetch(control_connection_t *conn,
|
||||
}
|
||||
}
|
||||
|
||||
if (version == HS_VERSION_TWO) {
|
||||
rend_query = rend_data_client_create(hsaddress, desc_id, NULL,
|
||||
REND_NO_AUTH);
|
||||
if (rend_query == NULL) {
|
||||
control_write_endreply(conn, 551, "Error creating the HS query");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Using a descriptor ID, we force the user to provide at least one
|
||||
* hsdir server using the SERVER= option. */
|
||||
if (desc_id && (!hsdirs || !smartlist_len(hsdirs))) {
|
||||
@ -1526,7 +1496,6 @@ handle_control_hsfetch(control_connection_t *conn,
|
||||
done:
|
||||
/* Contains data pointer that we don't own thus no cleanup. */
|
||||
smartlist_free(hsdirs);
|
||||
rend_data_free(rend_query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1547,7 +1516,6 @@ handle_control_hspost(control_connection_t *conn,
|
||||
{
|
||||
smartlist_t *hs_dirs = NULL;
|
||||
const char *encoded_desc = args->cmddata;
|
||||
size_t encoded_desc_len = args->cmddata_len;
|
||||
const char *onion_address = NULL;
|
||||
const config_line_t *line;
|
||||
|
||||
@ -1587,44 +1555,6 @@ handle_control_hspost(control_connection_t *conn,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* From this point on, it is only v2. */
|
||||
|
||||
/* parse it. */
|
||||
rend_encoded_v2_service_descriptor_t *desc =
|
||||
tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
|
||||
desc->desc_str = tor_memdup_nulterm(encoded_desc, encoded_desc_len);
|
||||
|
||||
rend_service_descriptor_t *parsed = NULL;
|
||||
char *intro_content = NULL;
|
||||
size_t intro_size;
|
||||
size_t encoded_size;
|
||||
const char *next_desc;
|
||||
if (!rend_parse_v2_service_descriptor(&parsed, desc->desc_id, &intro_content,
|
||||
&intro_size, &encoded_size,
|
||||
&next_desc, desc->desc_str, 1)) {
|
||||
/* Post the descriptor. */
|
||||
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
|
||||
if (!rend_get_service_id(parsed->pk, serviceid)) {
|
||||
smartlist_t *descs = smartlist_new();
|
||||
smartlist_add(descs, desc);
|
||||
|
||||
/* We are about to trigger HS descriptor upload so send the OK now
|
||||
* because after that 650 event(s) are possible so better to have the
|
||||
* 250 OK before them to avoid out of order replies. */
|
||||
send_control_done(conn);
|
||||
|
||||
/* Trigger the descriptor upload */
|
||||
directory_post_to_hs_dir(parsed, descs, hs_dirs, serviceid, 0);
|
||||
smartlist_free(descs);
|
||||
}
|
||||
|
||||
rend_service_descriptor_free(parsed);
|
||||
} else {
|
||||
control_write_endreply(conn, 554, "Invalid descriptor");
|
||||
}
|
||||
|
||||
tor_free(intro_content);
|
||||
rend_encoded_v2_service_descriptor_free(desc);
|
||||
done:
|
||||
smartlist_free(hs_dirs); /* Contents belong to the rend service code. */
|
||||
return 0;
|
||||
@ -1640,7 +1570,6 @@ handle_control_hspost(control_connection_t *conn,
|
||||
* The port_cfgs is a list of service port. Ownership transferred to service.
|
||||
* The max_streams refers to the MaxStreams= key.
|
||||
* The max_streams_close_circuit refers to the MaxStreamsCloseCircuit key.
|
||||
* The auth_type is the authentication type of the clients in auth_clients.
|
||||
* The ownership of that list is transferred to the service.
|
||||
*
|
||||
* On success (RSAE_OKAY), the address_out points to a newly allocated string
|
||||
@ -1650,8 +1579,7 @@ STATIC hs_service_add_ephemeral_status_t
|
||||
add_onion_helper_add_service(int hs_version,
|
||||
add_onion_secret_key_t *pk,
|
||||
smartlist_t *port_cfgs, int max_streams,
|
||||
int max_streams_close_circuit, int auth_type,
|
||||
smartlist_t *auth_clients,
|
||||
int max_streams_close_circuit,
|
||||
smartlist_t *auth_clients_v3, char **address_out)
|
||||
{
|
||||
hs_service_add_ephemeral_status_t ret;
|
||||
@ -1661,11 +1589,6 @@ add_onion_helper_add_service(int hs_version,
|
||||
tor_assert(address_out);
|
||||
|
||||
switch (hs_version) {
|
||||
case HS_VERSION_TWO:
|
||||
ret = rend_service_add_ephemeral(pk->v2, port_cfgs, max_streams,
|
||||
max_streams_close_circuit, auth_type,
|
||||
auth_clients, address_out);
|
||||
break;
|
||||
case HS_VERSION_THREE:
|
||||
ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams,
|
||||
max_streams_close_circuit,
|
||||
@ -1711,16 +1634,14 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
* material first, since there's no reason to touch that at all if any of
|
||||
* the other arguments are malformed.
|
||||
*/
|
||||
rend_auth_type_t auth_type = REND_NO_AUTH;
|
||||
smartlist_t *port_cfgs = smartlist_new();
|
||||
smartlist_t *auth_clients = NULL;
|
||||
smartlist_t *auth_created_clients = NULL;
|
||||
smartlist_t *auth_clients_v3 = NULL;
|
||||
smartlist_t *auth_clients_v3_str = NULL;
|
||||
int discard_pk = 0;
|
||||
int detach = 0;
|
||||
int max_streams = 0;
|
||||
int max_streams_close_circuit = 0;
|
||||
rend_auth_type_t auth_type = REND_NO_AUTH;
|
||||
int non_anonymous = 0;
|
||||
const config_line_t *arg;
|
||||
|
||||
@ -1758,7 +1679,6 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
static const char *discard_flag = "DiscardPK";
|
||||
static const char *detach_flag = "Detach";
|
||||
static const char *max_s_close_flag = "MaxStreamsCloseCircuit";
|
||||
static const char *basicauth_flag = "BasicAuth";
|
||||
static const char *v3auth_flag = "V3Auth";
|
||||
static const char *non_anonymous_flag = "NonAnonymous";
|
||||
|
||||
@ -1778,8 +1698,6 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
detach = 1;
|
||||
} else if (!strcasecmp(flag, max_s_close_flag)) {
|
||||
max_streams_close_circuit = 1;
|
||||
} else if (!strcasecmp(flag, basicauth_flag)) {
|
||||
auth_type = REND_BASIC_AUTH;
|
||||
} else if (!strcasecmp(flag, v3auth_flag)) {
|
||||
auth_type = REND_V3_AUTH;
|
||||
} else if (!strcasecmp(flag, non_anonymous_flag)) {
|
||||
@ -1795,36 +1713,6 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
smartlist_free(flags);
|
||||
if (bad)
|
||||
goto out;
|
||||
|
||||
} else if (!strcasecmp(arg->key, "ClientAuth")) {
|
||||
int created = 0;
|
||||
rend_authorized_client_t *client =
|
||||
add_onion_helper_clientauth(arg->value, &created, conn);
|
||||
if (!client) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (auth_clients != NULL) {
|
||||
int bad = 0;
|
||||
SMARTLIST_FOREACH_BEGIN(auth_clients, rend_authorized_client_t *, ac) {
|
||||
if (strcmp(ac->client_name, client->client_name) == 0) {
|
||||
bad = 1;
|
||||
break;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ac);
|
||||
if (bad) {
|
||||
control_write_endreply(conn, 512, "Duplicate name in ClientAuth");
|
||||
rend_authorized_client_free(client);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
auth_clients = smartlist_new();
|
||||
auth_created_clients = smartlist_new();
|
||||
}
|
||||
smartlist_add(auth_clients, client);
|
||||
if (created) {
|
||||
smartlist_add(auth_created_clients, client);
|
||||
}
|
||||
} else if (!strcasecmp(arg->key, "ClientAuthV3")) {
|
||||
hs_service_authorized_client_t *client_v3 =
|
||||
parse_authorized_client_key(arg->value, LOG_INFO);
|
||||
@ -1848,31 +1736,14 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
if (smartlist_len(port_cfgs) == 0) {
|
||||
control_write_endreply(conn, 512, "Missing 'Port' argument");
|
||||
goto out;
|
||||
} else if (auth_type == REND_NO_AUTH &&
|
||||
(auth_clients != NULL && auth_clients_v3 != NULL)) {
|
||||
} else if (auth_type == REND_NO_AUTH && auth_clients_v3 != NULL) {
|
||||
control_write_endreply(conn, 512, "No auth type specified");
|
||||
goto out;
|
||||
} else if (auth_type != REND_NO_AUTH &&
|
||||
(auth_clients == NULL && auth_clients_v3 == NULL)) {
|
||||
} else if (auth_type != REND_NO_AUTH && auth_clients_v3 == NULL) {
|
||||
control_write_endreply(conn, 512, "No auth clients specified");
|
||||
goto out;
|
||||
} else if ((auth_type == REND_BASIC_AUTH &&
|
||||
smartlist_len(auth_clients) > 512) ||
|
||||
(auth_type == REND_STEALTH_AUTH &&
|
||||
smartlist_len(auth_clients) > 16)) {
|
||||
control_write_endreply(conn, 512, "Too many auth clients");
|
||||
goto out;
|
||||
} else if ((auth_type == REND_BASIC_AUTH ||
|
||||
auth_type == REND_STEALTH_AUTH) && auth_clients_v3) {
|
||||
control_write_endreply(conn, 512,
|
||||
"ClientAuthV3 does not support basic or stealth auth");
|
||||
goto out;
|
||||
} else if (auth_type == REND_V3_AUTH && auth_clients) {
|
||||
control_write_endreply(conn, 512, "ClientAuth does not support v3 auth");
|
||||
goto out;
|
||||
|
||||
} else if (non_anonymous != rend_service_non_anonymous_mode_enabled(
|
||||
get_options())) {
|
||||
} else if (non_anonymous != hs_service_non_anonymous_mode_enabled(
|
||||
get_options())) {
|
||||
/* If we failed, and the non-anonymous flag is set, Tor must be in
|
||||
* anonymous hidden service mode.
|
||||
* The error message changes based on the current Tor config:
|
||||
@ -1899,29 +1770,15 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We can't mix ClientAuth and Version 3 Onion Services, or ClientAuthV3 and
|
||||
* Version 2. If that's the case, send back an error. */
|
||||
if (hs_version == HS_VERSION_THREE && auth_clients) {
|
||||
control_write_endreply(conn, 513, "ClientAuth not supported");
|
||||
goto out;
|
||||
}
|
||||
if (hs_version == HS_VERSION_TWO && auth_clients_v3) {
|
||||
control_write_endreply(conn, 513, "ClientAuthV3 not supported");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Create the HS, using private key pk, client authentication auth_type,
|
||||
* the list of auth_clients, and port config port_cfg.
|
||||
* rend_service_add_ephemeral() will take ownership of pk and port_cfg,
|
||||
* regardless of success/failure.
|
||||
*/
|
||||
/* Create the HS, using private key pk and port config port_cfg.
|
||||
* hs_service_add_ephemeral() will take ownership of pk and port_cfg,
|
||||
* regardless of success/failure. */
|
||||
char *service_id = NULL;
|
||||
int ret =
|
||||
add_onion_helper_add_service(hs_version, &pk, port_cfgs, max_streams,
|
||||
max_streams_close_circuit, auth_type,
|
||||
auth_clients, auth_clients_v3, &service_id);
|
||||
port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
|
||||
auth_clients = NULL; /* so is auth_clients */
|
||||
int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs,
|
||||
max_streams,
|
||||
max_streams_close_circuit,
|
||||
auth_clients_v3, &service_id);
|
||||
port_cfgs = NULL; /* port_cfgs is now owned by the hs_service code. */
|
||||
auth_clients_v3 = NULL; /* so is auth_clients_v3 */
|
||||
switch (ret) {
|
||||
case RSAE_OKAY:
|
||||
@ -1943,17 +1800,6 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
control_printf_midreply(conn, 250, "PrivateKey=%s:%s",
|
||||
key_new_alg, key_new_blob);
|
||||
}
|
||||
if (auth_created_clients) {
|
||||
SMARTLIST_FOREACH(auth_created_clients, rend_authorized_client_t *, ac, {
|
||||
char *encoded = rend_auth_encode_cookie(ac->descriptor_cookie,
|
||||
auth_type);
|
||||
tor_assert(encoded);
|
||||
control_printf_midreply(conn, 250, "ClientAuth=%s:%s",
|
||||
ac->client_name, encoded);
|
||||
memwipe(encoded, 0, strlen(encoded));
|
||||
tor_free(encoded);
|
||||
});
|
||||
}
|
||||
if (auth_clients_v3_str) {
|
||||
SMARTLIST_FOREACH(auth_clients_v3_str, char *, client_str, {
|
||||
control_printf_midreply(conn, 250, "ClientAuthV3=%s", client_str);
|
||||
@ -1990,12 +1836,6 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
hs_port_config_free(p));
|
||||
smartlist_free(port_cfgs);
|
||||
}
|
||||
|
||||
if (auth_clients) {
|
||||
SMARTLIST_FOREACH(auth_clients, rend_authorized_client_t *, ac,
|
||||
rend_authorized_client_free(ac));
|
||||
smartlist_free(auth_clients);
|
||||
}
|
||||
if (auth_clients_v3) {
|
||||
SMARTLIST_FOREACH(auth_clients_v3, hs_service_authorized_client_t *, ac,
|
||||
service_authorized_client_free(ac));
|
||||
@ -2007,10 +1847,6 @@ handle_control_add_onion(control_connection_t *conn,
|
||||
smartlist_free(auth_clients_v3_str);
|
||||
}
|
||||
|
||||
if (auth_created_clients) {
|
||||
// Do not free entries; they are the same as auth_clients
|
||||
smartlist_free(auth_created_clients);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2034,7 +1870,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
|
||||
control_connection_t *conn)
|
||||
{
|
||||
smartlist_t *key_args = smartlist_new();
|
||||
crypto_pk_t *pk = NULL;
|
||||
const char *key_new_alg = NULL;
|
||||
char *key_new_blob = NULL;
|
||||
int ret = -1;
|
||||
@ -2048,27 +1883,12 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
|
||||
/* The format is "KeyType:KeyBlob". */
|
||||
static const char *key_type_new = "NEW";
|
||||
static const char *key_type_best = "BEST";
|
||||
static const char *key_type_rsa1024 = "RSA1024";
|
||||
static const char *key_type_ed25519_v3 = "ED25519-V3";
|
||||
|
||||
const char *key_type = smartlist_get(key_args, 0);
|
||||
const char *key_blob = smartlist_get(key_args, 1);
|
||||
|
||||
if (!strcasecmp(key_type_rsa1024, key_type)) {
|
||||
/* "RSA:<Base64 Blob>" - Loading a pre-existing RSA1024 key. */
|
||||
pk = crypto_pk_base64_decode_private(key_blob, strlen(key_blob));
|
||||
if (!pk) {
|
||||
control_write_endreply(conn, 512, "Failed to decode RSA key");
|
||||
goto err;
|
||||
}
|
||||
if (crypto_pk_num_bits(pk) != PK_BYTES*8) {
|
||||
crypto_pk_free(pk);
|
||||
control_write_endreply(conn, 512, "Invalid RSA key size");
|
||||
goto err;
|
||||
}
|
||||
decoded_key->v2 = pk;
|
||||
*hs_version = HS_VERSION_TWO;
|
||||
} else if (!strcasecmp(key_type_ed25519_v3, key_type)) {
|
||||
if (!strcasecmp(key_type_ed25519_v3, key_type)) {
|
||||
/* parsing of private ed25519 key */
|
||||
/* "ED25519-V3:<Base64 Blob>" - Loading a pre-existing ed25519 key. */
|
||||
ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
|
||||
@ -2082,27 +1902,8 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
|
||||
*hs_version = HS_VERSION_THREE;
|
||||
} else if (!strcasecmp(key_type_new, key_type)) {
|
||||
/* "NEW:<Algorithm>" - Generating a new key, blob as algorithm. */
|
||||
if (!strcasecmp(key_type_rsa1024, key_blob)) {
|
||||
/* "RSA1024", RSA 1024 bit, also currently "BEST" by default. */
|
||||
pk = crypto_pk_new();
|
||||
if (crypto_pk_generate_key(pk)) {
|
||||
control_printf_endreply(conn, 551, "Failed to generate %s key",
|
||||
key_type_rsa1024);
|
||||
goto err;
|
||||
}
|
||||
if (!discard_pk) {
|
||||
if (crypto_pk_base64_encode_private(pk, &key_new_blob)) {
|
||||
crypto_pk_free(pk);
|
||||
control_printf_endreply(conn, 551, "Failed to encode %s key",
|
||||
key_type_rsa1024);
|
||||
goto err;
|
||||
}
|
||||
key_new_alg = key_type_rsa1024;
|
||||
}
|
||||
decoded_key->v2 = pk;
|
||||
*hs_version = HS_VERSION_TWO;
|
||||
} else if (!strcasecmp(key_type_ed25519_v3, key_blob) ||
|
||||
!strcasecmp(key_type_best, key_blob)) {
|
||||
if (!strcasecmp(key_type_ed25519_v3, key_blob) ||
|
||||
!strcasecmp(key_type_best, key_blob)) {
|
||||
/* "ED25519-V3", ed25519 key, also currently "BEST" by default. */
|
||||
ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
|
||||
if (ed25519_secret_key_generate(sk, 1) < 0) {
|
||||
@ -2151,68 +1952,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Helper function to handle parsing a ClientAuth argument to the
|
||||
* ADD_ONION command. Return a new rend_authorized_client_t, or NULL
|
||||
* and an optional control protocol error message on failure. The
|
||||
* caller is responsible for freeing the returned auth_client.
|
||||
*
|
||||
* If 'created' is specified, it will be set to 1 when a new cookie has
|
||||
* been generated.
|
||||
*
|
||||
* Note: conn is only used for writing control replies. For testing
|
||||
* purposes, it can be NULL if control_write_reply() is appropriately
|
||||
* mocked.
|
||||
*/
|
||||
STATIC rend_authorized_client_t *
|
||||
add_onion_helper_clientauth(const char *arg, int *created,
|
||||
control_connection_t *conn)
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
tor_assert(arg);
|
||||
tor_assert(created);
|
||||
|
||||
smartlist_t *auth_args = smartlist_new();
|
||||
rend_authorized_client_t *client =
|
||||
tor_malloc_zero(sizeof(rend_authorized_client_t));
|
||||
smartlist_split_string(auth_args, arg, ":", 0, 0);
|
||||
if (smartlist_len(auth_args) < 1 || smartlist_len(auth_args) > 2) {
|
||||
control_write_endreply(conn, 512, "Invalid ClientAuth syntax");
|
||||
goto err;
|
||||
}
|
||||
client->client_name = tor_strdup(smartlist_get(auth_args, 0));
|
||||
if (smartlist_len(auth_args) == 2) {
|
||||
char *decode_err_msg = NULL;
|
||||
if (rend_auth_decode_cookie(smartlist_get(auth_args, 1),
|
||||
client->descriptor_cookie,
|
||||
NULL, &decode_err_msg) < 0) {
|
||||
tor_assert(decode_err_msg);
|
||||
control_write_endreply(conn, 512, decode_err_msg);
|
||||
tor_free(decode_err_msg);
|
||||
goto err;
|
||||
}
|
||||
*created = 0;
|
||||
} else {
|
||||
crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN);
|
||||
*created = 1;
|
||||
}
|
||||
|
||||
if (!rend_valid_client_name(client->client_name)) {
|
||||
control_write_endreply(conn, 512, "Invalid name in ClientAuth");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ok = 1;
|
||||
err:
|
||||
SMARTLIST_FOREACH(auth_args, char *, item, tor_free(item));
|
||||
smartlist_free(auth_args);
|
||||
if (!ok) {
|
||||
rend_authorized_client_free(client);
|
||||
client = NULL;
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
static const control_cmd_syntax_t del_onion_syntax = {
|
||||
.min_args = 1, .max_args = 1,
|
||||
};
|
||||
@ -2228,9 +1967,7 @@ handle_control_del_onion(control_connection_t *conn,
|
||||
tor_assert(smartlist_len(args) == 1);
|
||||
|
||||
const char *service_id = smartlist_get(args, 0);
|
||||
if (rend_valid_v2_service_id(service_id)) {
|
||||
hs_version = HS_VERSION_TWO;
|
||||
} else if (hs_address_is_valid(service_id)) {
|
||||
if (hs_address_is_valid(service_id)) {
|
||||
hs_version = HS_VERSION_THREE;
|
||||
} else {
|
||||
control_write_endreply(conn, 512, "Malformed Onion Service id");
|
||||
@ -2261,9 +1998,6 @@ handle_control_del_onion(control_connection_t *conn,
|
||||
} else {
|
||||
int ret = -1;
|
||||
switch (hs_version) {
|
||||
case HS_VERSION_TWO:
|
||||
ret = rend_service_del_ephemeral(service_id);
|
||||
break;
|
||||
case HS_VERSION_THREE:
|
||||
ret = hs_service_del_ephemeral(service_id);
|
||||
break;
|
||||
|
@ -99,13 +99,9 @@ STATIC hs_service_add_ephemeral_status_t add_onion_helper_add_service(
|
||||
int hs_version,
|
||||
add_onion_secret_key_t *pk,
|
||||
smartlist_t *port_cfgs, int max_streams,
|
||||
int max_streams_close_circuit, int auth_type,
|
||||
smartlist_t *auth_clients,
|
||||
int max_streams_close_circuit,
|
||||
smartlist_t *auth_clients_v3, char **address_out);
|
||||
|
||||
STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg,
|
||||
int *created, control_connection_t *conn);
|
||||
|
||||
STATIC control_cmd_args_t *control_cmd_parse_args(
|
||||
const char *command,
|
||||
const control_cmd_syntax_t *syntax,
|
||||
|
@ -2066,8 +2066,6 @@ control_event_hs_descriptor_upload(const char *onion_address,
|
||||
/** send HS_DESC event after got response from hs directory.
|
||||
*
|
||||
* NOTE: this is an internal function used by following functions:
|
||||
* control_event_hsv2_descriptor_received
|
||||
* control_event_hsv2_descriptor_failed
|
||||
* control_event_hsv3_descriptor_failed
|
||||
*
|
||||
* So do not call this function directly.
|
||||
@ -2138,82 +2136,6 @@ control_event_hs_descriptor_upload_end(const char *action,
|
||||
tor_free(reason_field);
|
||||
}
|
||||
|
||||
/** For an HS descriptor query <b>rend_data</b>, using the
|
||||
* <b>onion_address</b> and HSDir fingerprint <b>hsdir_fp</b>, find out
|
||||
* which descriptor ID in the query is the right one.
|
||||
*
|
||||
* Return a pointer of the binary descriptor ID found in the query's object
|
||||
* or NULL if not found. */
|
||||
static const char *
|
||||
get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp)
|
||||
{
|
||||
int replica;
|
||||
const char *desc_id = NULL;
|
||||
const rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data);
|
||||
|
||||
/* Possible if the fetch was done using a descriptor ID. This means that
|
||||
* the HSFETCH command was used. */
|
||||
if (!tor_digest_is_zero(rend_data_v2->desc_id_fetch)) {
|
||||
desc_id = rend_data_v2->desc_id_fetch;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Without a directory fingerprint at this stage, we can't do much. */
|
||||
if (hsdir_fp == NULL) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* OK, we have an onion address so now let's find which descriptor ID
|
||||
* is the one associated with the HSDir fingerprint. */
|
||||
for (replica = 0; replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
|
||||
replica++) {
|
||||
const char *digest = rend_data_get_desc_id(rend_data, replica, NULL);
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(rend_data->hsdirs_fp, char *, fingerprint) {
|
||||
if (tor_memcmp(fingerprint, hsdir_fp, DIGEST_LEN) == 0) {
|
||||
/* Found it! This descriptor ID is the right one. */
|
||||
desc_id = digest;
|
||||
goto end;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(fingerprint);
|
||||
}
|
||||
|
||||
end:
|
||||
return desc_id;
|
||||
}
|
||||
|
||||
/** send HS_DESC RECEIVED event
|
||||
*
|
||||
* called when we successfully received a hidden service descriptor.
|
||||
*/
|
||||
void
|
||||
control_event_hsv2_descriptor_received(const char *onion_address,
|
||||
const rend_data_t *rend_data,
|
||||
const char *hsdir_id_digest)
|
||||
{
|
||||
char *desc_id_field = NULL;
|
||||
const char *desc_id;
|
||||
|
||||
if (BUG(!rend_data || !hsdir_id_digest || !onion_address)) {
|
||||
return;
|
||||
}
|
||||
|
||||
desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest);
|
||||
if (desc_id != NULL) {
|
||||
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
|
||||
/* Set the descriptor ID digest to base32 so we can send it. */
|
||||
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
|
||||
DIGEST_LEN);
|
||||
/* Extra whitespace is needed before the value. */
|
||||
tor_asprintf(&desc_id_field, " %s", desc_id_base32);
|
||||
}
|
||||
|
||||
event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field,
|
||||
TO_REND_DATA_V2(rend_data)->auth_type,
|
||||
hsdir_id_digest, NULL);
|
||||
tor_free(desc_id_field);
|
||||
}
|
||||
|
||||
/* Send HS_DESC RECEIVED event
|
||||
*
|
||||
* Called when we successfully received a hidden service descriptor. */
|
||||
@ -2253,40 +2175,6 @@ control_event_hs_descriptor_uploaded(const char *id_digest,
|
||||
id_digest, NULL);
|
||||
}
|
||||
|
||||
/** Send HS_DESC event to inform controller that query <b>rend_data</b>
|
||||
* failed to retrieve hidden service descriptor from directory identified by
|
||||
* <b>id_digest</b>. If NULL, "UNKNOWN" is used. If <b>reason</b> is not NULL,
|
||||
* add it to REASON= field.
|
||||
*/
|
||||
void
|
||||
control_event_hsv2_descriptor_failed(const rend_data_t *rend_data,
|
||||
const char *hsdir_id_digest,
|
||||
const char *reason)
|
||||
{
|
||||
char *desc_id_field = NULL;
|
||||
const char *desc_id;
|
||||
|
||||
if (BUG(!rend_data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest);
|
||||
if (desc_id != NULL) {
|
||||
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
|
||||
/* Set the descriptor ID digest to base32 so we can send it. */
|
||||
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
|
||||
DIGEST_LEN);
|
||||
/* Extra whitespace is needed before the value. */
|
||||
tor_asprintf(&desc_id_field, " %s", desc_id_base32);
|
||||
}
|
||||
|
||||
event_hs_descriptor_receive_end("FAILED", rend_data_get_address(rend_data),
|
||||
desc_id_field,
|
||||
TO_REND_DATA_V2(rend_data)->auth_type,
|
||||
hsdir_id_digest, reason);
|
||||
tor_free(desc_id_field);
|
||||
}
|
||||
|
||||
/** Send HS_DESC event to inform controller that the query to
|
||||
* <b>onion_address</b> failed to retrieve hidden service descriptor
|
||||
* <b>desc_id</b> from directory identified by <b>hsdir_id_digest</b>. If
|
||||
|
@ -202,13 +202,6 @@ void control_event_hs_descriptor_upload_end(const char *action,
|
||||
const char *reason);
|
||||
void control_event_hs_descriptor_uploaded(const char *hs_dir,
|
||||
const char *onion_address);
|
||||
/* Hidden service v2 HS_DESC specific. */
|
||||
void control_event_hsv2_descriptor_failed(const rend_data_t *rend_data,
|
||||
const char *id_digest,
|
||||
const char *reason);
|
||||
void control_event_hsv2_descriptor_received(const char *onion_address,
|
||||
const rend_data_t *rend_data,
|
||||
const char *id_digest);
|
||||
/* Hidden service v3 HS_DESC specific. */
|
||||
void control_event_hsv3_descriptor_failed(const char *onion_address,
|
||||
const char *desc_id,
|
||||
|
@ -122,15 +122,11 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
|
||||
}
|
||||
}
|
||||
|
||||
if (circ->rend_data != NULL || circ->hs_ident != NULL) {
|
||||
if (circ->hs_ident != NULL) {
|
||||
char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
|
||||
const char *onion_address;
|
||||
if (circ->rend_data) {
|
||||
onion_address = rend_data_get_address(circ->rend_data);
|
||||
} else {
|
||||
hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr);
|
||||
onion_address = addr;
|
||||
}
|
||||
hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr);
|
||||
onion_address = addr;
|
||||
smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address);
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/relay/selftest.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/stats/geoip_stats.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/relay/relay_config.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/stats/geoip_stats.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "lib/compress/compress.h"
|
||||
@ -353,8 +352,6 @@ static int handle_get_descriptor(dir_connection_t *conn,
|
||||
const get_handler_args_t *args);
|
||||
static int handle_get_keys(dir_connection_t *conn,
|
||||
const get_handler_args_t *args);
|
||||
static int handle_get_hs_descriptor_v2(dir_connection_t *conn,
|
||||
const get_handler_args_t *args);
|
||||
static int handle_get_robots(dir_connection_t *conn,
|
||||
const get_handler_args_t *args);
|
||||
static int handle_get_networkstatus_bridges(dir_connection_t *conn,
|
||||
@ -373,7 +370,6 @@ static const url_table_ent_t url_table[] = {
|
||||
{ "/tor/server/", 1, handle_get_descriptor },
|
||||
{ "/tor/extra/", 1, handle_get_descriptor },
|
||||
{ "/tor/keys/", 1, handle_get_keys },
|
||||
{ "/tor/rendezvous2/", 1, handle_get_hs_descriptor_v2 },
|
||||
{ "/tor/hs/3/", 1, handle_get_hs_descriptor_v3 },
|
||||
{ "/tor/robots.txt", 0, handle_get_robots },
|
||||
{ "/tor/networkstatus-bridges", 0, handle_get_networkstatus_bridges },
|
||||
@ -1347,44 +1343,6 @@ handle_get_keys(dir_connection_t *conn, const get_handler_args_t *args)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Helper function for GET /tor/rendezvous2/
|
||||
*/
|
||||
static int
|
||||
handle_get_hs_descriptor_v2(dir_connection_t *conn,
|
||||
const get_handler_args_t *args)
|
||||
{
|
||||
const char *url = args->url;
|
||||
if (connection_dir_is_encrypted(conn)) {
|
||||
/* Handle v2 rendezvous descriptor fetch request. */
|
||||
const char *descp;
|
||||
const char *query = url + strlen("/tor/rendezvous2/");
|
||||
if (rend_valid_descriptor_id(query)) {
|
||||
log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'",
|
||||
safe_str(escaped(query)));
|
||||
switch (rend_cache_lookup_v2_desc_as_dir(query, &descp)) {
|
||||
case 1: /* valid */
|
||||
write_http_response_header(conn, strlen(descp), NO_METHOD, 0);
|
||||
connection_buf_add(descp, strlen(descp), TO_CONN(conn));
|
||||
break;
|
||||
case 0: /* well-formed but not present */
|
||||
write_short_http_response(conn, 404, "Not found");
|
||||
break;
|
||||
case -1: /* not well-formed */
|
||||
write_short_http_response(conn, 400, "Bad request");
|
||||
break;
|
||||
}
|
||||
} else { /* not well-formed */
|
||||
write_short_http_response(conn, 400, "Bad request");
|
||||
}
|
||||
goto done;
|
||||
} else {
|
||||
/* Not encrypted! */
|
||||
write_short_http_response(conn, 404, "Not found");
|
||||
}
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Helper function for GET `/tor/hs/3/...`. Only for version 3.
|
||||
*/
|
||||
STATIC int
|
||||
@ -1626,22 +1584,6 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
|
||||
}
|
||||
log_debug(LD_DIRSERV,"rewritten url as '%s'.", escaped(url));
|
||||
|
||||
/* Handle v2 rendezvous service publish request. */
|
||||
if (connection_dir_is_encrypted(conn) &&
|
||||
!strcmpstart(url,"/tor/rendezvous2/publish")) {
|
||||
if (rend_cache_store_v2_desc_as_dir(body) < 0) {
|
||||
log_warn(LD_REND, "Rejected v2 rend descriptor (body size %d) from %s.",
|
||||
(int)body_len,
|
||||
connection_describe_peer(TO_CONN(conn)));
|
||||
write_short_http_response(conn, 400,
|
||||
"Invalid v2 service descriptor rejected");
|
||||
} else {
|
||||
write_short_http_response(conn, 200, "Service descriptor (v2) stored");
|
||||
log_info(LD_REND, "Handled v2 rendezvous descriptor post: accepted");
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Handle HS descriptor publish request. We force an anonymous connection
|
||||
* (which also tests for encrypted). We do not allow single-hop client to
|
||||
* post a descriptor onto an HSDir. */
|
||||
|
@ -47,9 +47,7 @@
|
||||
#include "feature/relay/relay_find_addr.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/relay/selftest.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
|
||||
#include "lib/cc/ctassert.h"
|
||||
@ -66,7 +64,6 @@
|
||||
#include "feature/nodelist/networkstatus_st.h"
|
||||
#include "feature/nodelist/node_st.h"
|
||||
#include "feature/nodelist/routerinfo_st.h"
|
||||
#include "feature/rend/rend_service_descriptor_st.h"
|
||||
|
||||
/** Maximum size, in bytes, for any directory object that we've downloaded. */
|
||||
#define MAX_DIR_DL_SIZE ((1<<24)-1) /* 16 MB - 1 */
|
||||
@ -119,10 +116,6 @@ dir_conn_purpose_to_string(int purpose)
|
||||
return "status vote fetch";
|
||||
case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
|
||||
return "consensus signature fetch";
|
||||
case DIR_PURPOSE_FETCH_RENDDESC_V2:
|
||||
return "hidden-service v2 descriptor fetch";
|
||||
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
||||
return "hidden-service v2 descriptor upload";
|
||||
case DIR_PURPOSE_FETCH_HSDESC:
|
||||
return "hidden-service descriptor fetch";
|
||||
case DIR_PURPOSE_UPLOAD_HSDESC:
|
||||
@ -949,7 +942,6 @@ directory_request_new(uint8_t dir_purpose)
|
||||
tor_assert(dir_purpose >= DIR_PURPOSE_MIN_);
|
||||
tor_assert(dir_purpose <= DIR_PURPOSE_MAX_);
|
||||
tor_assert(dir_purpose != DIR_PURPOSE_SERVER);
|
||||
tor_assert(dir_purpose != DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2);
|
||||
tor_assert(dir_purpose != DIR_PURPOSE_HAS_FETCHED_HSDESC);
|
||||
|
||||
directory_request_t *result = tor_malloc_zero(sizeof(*result));
|
||||
@ -1086,21 +1078,6 @@ directory_request_add_header(directory_request_t *req,
|
||||
{
|
||||
config_line_prepend(&req->additional_headers, key, val);
|
||||
}
|
||||
/**
|
||||
* Set an object containing HS data to be associated with this request. Note
|
||||
* that only an alias to <b>query</b> is stored, so the <b>query</b> object
|
||||
* must outlive the request.
|
||||
*/
|
||||
void
|
||||
directory_request_set_rend_query(directory_request_t *req,
|
||||
const rend_data_t *query)
|
||||
{
|
||||
if (query) {
|
||||
tor_assert(req->dir_purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 ||
|
||||
req->dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2);
|
||||
}
|
||||
req->rend_query = query;
|
||||
}
|
||||
/**
|
||||
* Set an object containing HS connection identifier to be associated with
|
||||
* this request. Note that only an alias to <b>ident</b> is stored, so the
|
||||
@ -1249,7 +1226,6 @@ directory_initiate_request,(directory_request_t *request))
|
||||
const uint8_t router_purpose = request->router_purpose;
|
||||
const dir_indirection_t indirection = request->indirection;
|
||||
const char *resource = request->resource;
|
||||
const rend_data_t *rend_query = request->rend_query;
|
||||
const hs_ident_dir_conn_t *hs_ident = request->hs_ident;
|
||||
circuit_guard_state_t *guard_state = request->guard_state;
|
||||
|
||||
@ -1285,7 +1261,7 @@ directory_initiate_request,(directory_request_t *request))
|
||||
|
||||
if (purpose_needs_anonymity(dir_purpose, router_purpose, resource)) {
|
||||
tor_assert(anonymized_connection ||
|
||||
rend_non_anonymous_mode_enabled(options));
|
||||
hs_service_non_anonymous_mode_enabled(options));
|
||||
}
|
||||
|
||||
/* use encrypted begindir connections for everything except relays
|
||||
@ -1337,15 +1313,7 @@ directory_initiate_request,(directory_request_t *request))
|
||||
/* XXXX This is a bad name for this field now. */
|
||||
conn->dirconn_direct = !anonymized_connection;
|
||||
|
||||
/* copy rendezvous data, if any */
|
||||
if (rend_query) {
|
||||
/* We can't have both v2 and v3+ identifier. */
|
||||
tor_assert_nonfatal(!hs_ident);
|
||||
conn->rend_data = rend_data_dup(rend_query);
|
||||
}
|
||||
if (hs_ident) {
|
||||
/* We can't have both v2 and v3+ identifier. */
|
||||
tor_assert_nonfatal(!rend_query);
|
||||
conn->hs_ident = hs_ident_dir_conn_dup(hs_ident);
|
||||
}
|
||||
|
||||
@ -1680,13 +1648,6 @@ directory_send_command(dir_connection_t *conn,
|
||||
httpcommand = "POST";
|
||||
url = tor_strdup("/tor/post/consensus-signature");
|
||||
break;
|
||||
case DIR_PURPOSE_FETCH_RENDDESC_V2:
|
||||
tor_assert(resource);
|
||||
tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32);
|
||||
tor_assert(!payload);
|
||||
httpcommand = "GET";
|
||||
tor_asprintf(&url, "/tor/rendezvous2/%s", resource);
|
||||
break;
|
||||
case DIR_PURPOSE_FETCH_HSDESC:
|
||||
tor_assert(resource);
|
||||
tor_assert(strlen(resource) <= ED25519_BASE64_LEN);
|
||||
@ -1694,12 +1655,6 @@ directory_send_command(dir_connection_t *conn,
|
||||
httpcommand = "GET";
|
||||
tor_asprintf(&url, "/tor/hs/3/%s", resource);
|
||||
break;
|
||||
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
||||
tor_assert(!resource);
|
||||
tor_assert(payload);
|
||||
httpcommand = "POST";
|
||||
url = tor_strdup("/tor/rendezvous2/publish");
|
||||
break;
|
||||
case DIR_PURPOSE_UPLOAD_HSDESC:
|
||||
tor_assert(resource);
|
||||
tor_assert(payload);
|
||||
@ -1843,10 +1798,6 @@ static int handle_response_upload_vote(dir_connection_t *,
|
||||
const response_handler_args_t *);
|
||||
static int handle_response_upload_signatures(dir_connection_t *,
|
||||
const response_handler_args_t *);
|
||||
static int handle_response_fetch_renddesc_v2(dir_connection_t *,
|
||||
const response_handler_args_t *);
|
||||
static int handle_response_upload_renddesc_v2(dir_connection_t *,
|
||||
const response_handler_args_t *);
|
||||
static int handle_response_upload_hsdesc(dir_connection_t *,
|
||||
const response_handler_args_t *);
|
||||
|
||||
@ -2193,9 +2144,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
||||
case DIR_PURPOSE_FETCH_MICRODESC:
|
||||
rv = handle_response_fetch_microdesc(conn, &args);
|
||||
break;
|
||||
case DIR_PURPOSE_FETCH_RENDDESC_V2:
|
||||
rv = handle_response_fetch_renddesc_v2(conn, &args);
|
||||
break;
|
||||
case DIR_PURPOSE_UPLOAD_DIR:
|
||||
rv = handle_response_upload_dir(conn, &args);
|
||||
break;
|
||||
@ -2205,9 +2153,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
||||
case DIR_PURPOSE_UPLOAD_VOTE:
|
||||
rv = handle_response_upload_vote(conn, &args);
|
||||
break;
|
||||
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
||||
rv = handle_response_upload_renddesc_v2(conn, &args);
|
||||
break;
|
||||
case DIR_PURPOSE_UPLOAD_HSDESC:
|
||||
rv = handle_response_upload_hsdesc(conn, &args);
|
||||
break;
|
||||
@ -2800,152 +2745,6 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler function: processes a response to a request for a v2 hidden service
|
||||
* descriptor.
|
||||
**/
|
||||
static int
|
||||
handle_response_fetch_renddesc_v2(dir_connection_t *conn,
|
||||
const response_handler_args_t *args)
|
||||
{
|
||||
tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2);
|
||||
const int status_code = args->status_code;
|
||||
const char *reason = args->reason;
|
||||
const char *body = args->body;
|
||||
const size_t body_len = args->body_len;
|
||||
|
||||
#define SEND_HS_DESC_FAILED_EVENT(reason) \
|
||||
(control_event_hsv2_descriptor_failed(conn->rend_data, \
|
||||
conn->identity_digest, \
|
||||
reason))
|
||||
#define SEND_HS_DESC_FAILED_CONTENT() \
|
||||
(control_event_hs_descriptor_content( \
|
||||
rend_data_get_address(conn->rend_data), \
|
||||
conn->requested_resource, \
|
||||
conn->identity_digest, \
|
||||
NULL))
|
||||
|
||||
tor_assert(conn->rend_data);
|
||||
log_info(LD_REND,"Received rendezvous descriptor (body size %d, status %d "
|
||||
"(%s))",
|
||||
(int)body_len, status_code, escaped(reason));
|
||||
switch (status_code) {
|
||||
case 200:
|
||||
{
|
||||
rend_cache_entry_t *entry = NULL;
|
||||
|
||||
if (rend_cache_store_v2_desc_as_client(body,
|
||||
conn->requested_resource,
|
||||
conn->rend_data, &entry) < 0) {
|
||||
log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. "
|
||||
"Retrying at another directory.");
|
||||
/* We'll retry when connection_about_to_close_connection()
|
||||
* cleans this dir conn up. */
|
||||
SEND_HS_DESC_FAILED_EVENT("BAD_DESC");
|
||||
SEND_HS_DESC_FAILED_CONTENT();
|
||||
} else {
|
||||
char service_id[REND_SERVICE_ID_LEN_BASE32 + 1];
|
||||
/* Should never be NULL here if we found the descriptor. */
|
||||
tor_assert(entry);
|
||||
rend_get_service_id(entry->parsed->pk, service_id);
|
||||
|
||||
/* success. notify pending connections about this. */
|
||||
log_info(LD_REND, "Successfully fetched v2 rendezvous "
|
||||
"descriptor.");
|
||||
control_event_hsv2_descriptor_received(service_id,
|
||||
conn->rend_data,
|
||||
conn->identity_digest);
|
||||
control_event_hs_descriptor_content(service_id,
|
||||
conn->requested_resource,
|
||||
conn->identity_digest,
|
||||
body);
|
||||
conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2;
|
||||
memwipe(service_id, 0, sizeof(service_id));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 404:
|
||||
/* Not there. We'll retry when
|
||||
* connection_about_to_close_connection() cleans this conn up. */
|
||||
log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: "
|
||||
"Retrying at another directory.");
|
||||
SEND_HS_DESC_FAILED_EVENT("NOT_FOUND");
|
||||
SEND_HS_DESC_FAILED_CONTENT();
|
||||
break;
|
||||
case 400:
|
||||
log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
|
||||
"http status 400 (%s). Dirserver didn't like our "
|
||||
"v2 rendezvous query? Retrying at another directory.",
|
||||
escaped(reason));
|
||||
SEND_HS_DESC_FAILED_EVENT("QUERY_REJECTED");
|
||||
SEND_HS_DESC_FAILED_CONTENT();
|
||||
break;
|
||||
default:
|
||||
log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
|
||||
"http status %d (%s) response unexpected while "
|
||||
"fetching v2 hidden service descriptor (server %s). "
|
||||
"Retrying at another directory.",
|
||||
status_code, escaped(reason),
|
||||
connection_describe_peer(TO_CONN(conn)));
|
||||
SEND_HS_DESC_FAILED_EVENT("UNEXPECTED");
|
||||
SEND_HS_DESC_FAILED_CONTENT();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler function: processes a response to a POST request to upload a v2
|
||||
* hidden service descriptor.
|
||||
**/
|
||||
static int
|
||||
handle_response_upload_renddesc_v2(dir_connection_t *conn,
|
||||
const response_handler_args_t *args)
|
||||
{
|
||||
tor_assert(conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2);
|
||||
const int status_code = args->status_code;
|
||||
const char *reason = args->reason;
|
||||
|
||||
#define SEND_HS_DESC_UPLOAD_FAILED_EVENT(reason) \
|
||||
(control_event_hs_descriptor_upload_failed( \
|
||||
conn->identity_digest, \
|
||||
rend_data_get_address(conn->rend_data), \
|
||||
reason))
|
||||
|
||||
log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
|
||||
"(%s))",
|
||||
status_code, escaped(reason));
|
||||
/* Without the rend data, we'll have a problem identifying what has been
|
||||
* uploaded for which service. */
|
||||
tor_assert(conn->rend_data);
|
||||
switch (status_code) {
|
||||
case 200:
|
||||
log_info(LD_REND,
|
||||
"Uploading rendezvous descriptor: finished with status "
|
||||
"200 (%s)", escaped(reason));
|
||||
control_event_hs_descriptor_uploaded(conn->identity_digest,
|
||||
rend_data_get_address(conn->rend_data));
|
||||
rend_service_desc_has_uploaded(conn->rend_data);
|
||||
break;
|
||||
case 400:
|
||||
log_warn(LD_REND,"http status 400 (%s) response from dirserver "
|
||||
"%s. Malformed rendezvous descriptor?",
|
||||
escaped(reason), connection_describe_peer(TO_CONN(conn)));
|
||||
SEND_HS_DESC_UPLOAD_FAILED_EVENT("UPLOAD_REJECTED");
|
||||
break;
|
||||
default:
|
||||
log_warn(LD_REND,"http status %d (%s) response unexpected (server "
|
||||
"%s).",
|
||||
status_code, escaped(reason),
|
||||
connection_describe_peer(TO_CONN(conn)));
|
||||
SEND_HS_DESC_UPLOAD_FAILED_EVENT("UNEXPECTED");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler function: processes a response to a POST request to upload an
|
||||
* hidden service descriptor.
|
||||
|
@ -74,8 +74,6 @@ void directory_request_set_payload(directory_request_t *req,
|
||||
size_t payload_len);
|
||||
void directory_request_set_if_modified_since(directory_request_t *req,
|
||||
time_t if_modified_since);
|
||||
void directory_request_set_rend_query(directory_request_t *req,
|
||||
const rend_data_t *query);
|
||||
void directory_request_upload_set_hs_ident(directory_request_t *req,
|
||||
const hs_ident_dir_conn_t *ident);
|
||||
void directory_request_fetch_set_hs_ident(directory_request_t *req,
|
||||
@ -125,8 +123,6 @@ struct directory_request_t {
|
||||
size_t payload_len;
|
||||
/** Value to send in an if-modified-since header, or 0 for none. */
|
||||
time_t if_modified_since;
|
||||
/** Hidden-service-specific information v2. */
|
||||
const rend_data_t *rend_query;
|
||||
/** Extra headers to append to the request */
|
||||
struct config_line_t *additional_headers;
|
||||
/** Hidden-service-specific information for v3+. */
|
||||
|
@ -42,9 +42,6 @@ struct dir_connection_t {
|
||||
/** The compression object doing on-the-fly compression for spooled data. */
|
||||
struct tor_compress_state_t *compress_state;
|
||||
|
||||
/** What rendezvous service are we querying for? */
|
||||
rend_data_t *rend_data;
|
||||
|
||||
/* Hidden service connection identifier for dir connections: Used by HS
|
||||
client-side code to fetch HS descriptors, and by the service-side code to
|
||||
upload descriptors. */
|
||||
|
@ -142,9 +142,6 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose,
|
||||
case DIR_PURPOSE_FETCH_MICRODESC:
|
||||
return 0;
|
||||
case DIR_PURPOSE_HAS_FETCHED_HSDESC:
|
||||
case DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2:
|
||||
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
||||
case DIR_PURPOSE_FETCH_RENDDESC_V2:
|
||||
case DIR_PURPOSE_FETCH_HSDESC:
|
||||
case DIR_PURPOSE_UPLOAD_HSDESC:
|
||||
return 1;
|
||||
|
@ -30,10 +30,7 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c);
|
||||
#define DIR_CONN_STATE_SERVER_WRITING 6
|
||||
#define DIR_CONN_STATE_MAX_ 6
|
||||
|
||||
#define DIR_PURPOSE_MIN_ 4
|
||||
/** A connection to a directory server: set after a v2 rendezvous
|
||||
* descriptor is downloaded. */
|
||||
#define DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2 4
|
||||
#define DIR_PURPOSE_MIN_ 6
|
||||
/** A connection to a directory server: download one or more server
|
||||
* descriptors. */
|
||||
#define DIR_PURPOSE_FETCH_SERVERDESC 6
|
||||
@ -61,12 +58,9 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c);
|
||||
|
||||
/** Purpose for connection at a directory server. */
|
||||
#define DIR_PURPOSE_SERVER 16
|
||||
/** A connection to a hidden service directory server: upload a v2 rendezvous
|
||||
* descriptor. */
|
||||
#define DIR_PURPOSE_UPLOAD_RENDDESC_V2 17
|
||||
/** A connection to a hidden service directory server: download a v2 rendezvous
|
||||
* descriptor. */
|
||||
#define DIR_PURPOSE_FETCH_RENDDESC_V2 18
|
||||
|
||||
/** Value 17 and 18 were onion service v2 purposes. */
|
||||
|
||||
/** A connection to a directory server: download a microdescriptor. */
|
||||
#define DIR_PURPOSE_FETCH_MICRODESC 19
|
||||
/** A connection to a hidden service directory: upload a v3 descriptor. */
|
||||
@ -84,7 +78,6 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c);
|
||||
((p)==DIR_PURPOSE_UPLOAD_DIR || \
|
||||
(p)==DIR_PURPOSE_UPLOAD_VOTE || \
|
||||
(p)==DIR_PURPOSE_UPLOAD_SIGNATURES || \
|
||||
(p)==DIR_PURPOSE_UPLOAD_RENDDESC_V2 || \
|
||||
(p)==DIR_PURPOSE_UPLOAD_HSDESC)
|
||||
|
||||
enum compress_method_t;
|
||||
|
@ -19,13 +19,15 @@
|
||||
#include "feature/hs/hs_descriptor.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
|
||||
#include "feature/hs/hs_cache.h"
|
||||
|
||||
#include "feature/nodelist/networkstatus_st.h"
|
||||
|
||||
/* Total counter of the cache size. */
|
||||
static size_t hs_cache_total_allocation = 0;
|
||||
|
||||
static int cached_client_descriptor_has_expired(time_t now,
|
||||
const hs_cache_client_descriptor_t *cached_desc);
|
||||
|
||||
@ -164,7 +166,7 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
|
||||
* remove the entry we currently have from our cache so we can then
|
||||
* store the new one. */
|
||||
remove_v3_desc_as_dir(cache_entry);
|
||||
rend_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry));
|
||||
hs_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry));
|
||||
cache_dir_desc_free(cache_entry);
|
||||
}
|
||||
/* Store the descriptor we just got. We are sure here that either we
|
||||
@ -174,7 +176,7 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
|
||||
|
||||
/* Update our total cache size with this entry for the OOM. This uses the
|
||||
* old HS protocol cache subsystem for which we are tied with. */
|
||||
rend_cache_increment_allocation(cache_get_dir_entry_size(desc));
|
||||
hs_cache_increment_allocation(cache_get_dir_entry_size(desc));
|
||||
|
||||
/* Update HSv3 statistics */
|
||||
if (get_options()->HiddenServiceStatistics) {
|
||||
@ -259,7 +261,7 @@ cache_clean_v3_as_dir(time_t now, time_t global_cutoff)
|
||||
/* Entry is not in the cache anymore, destroy it. */
|
||||
cache_dir_desc_free(entry);
|
||||
/* Update our cache entry allocation size for the OOM. */
|
||||
rend_cache_decrement_allocation(entry_size);
|
||||
hs_cache_decrement_allocation(entry_size);
|
||||
/* Logging. */
|
||||
{
|
||||
char key_b64[BASE64_DIGEST256_LEN + 1];
|
||||
@ -336,12 +338,6 @@ hs_cache_lookup_as_dir(uint32_t version, const char *query,
|
||||
void
|
||||
hs_cache_clean_as_dir(time_t now)
|
||||
{
|
||||
time_t cutoff;
|
||||
|
||||
/* Start with v2 cache cleaning. */
|
||||
cutoff = now - rend_cache_max_entry_lifetime();
|
||||
rend_cache_clean_v2_descs_as_dir(cutoff);
|
||||
|
||||
/* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
|
||||
* to compute the cutoff by itself using the lifetime value. */
|
||||
cache_clean_v3_as_dir(now, 0);
|
||||
@ -387,7 +383,7 @@ remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc)
|
||||
tor_assert(desc);
|
||||
digest256map_remove(hs_cache_v3_client, desc->key.pubkey);
|
||||
/* Update cache size with this entry for the OOM handler. */
|
||||
rend_cache_decrement_allocation(cache_get_client_entry_size(desc));
|
||||
hs_cache_decrement_allocation(cache_get_client_entry_size(desc));
|
||||
}
|
||||
|
||||
/** Store a given descriptor in our cache. */
|
||||
@ -397,7 +393,7 @@ store_v3_desc_as_client(hs_cache_client_descriptor_t *desc)
|
||||
tor_assert(desc);
|
||||
digest256map_set(hs_cache_v3_client, desc->key.pubkey, desc);
|
||||
/* Update cache size with this entry for the OOM handler. */
|
||||
rend_cache_increment_allocation(cache_get_client_entry_size(desc));
|
||||
hs_cache_increment_allocation(cache_get_client_entry_size(desc));
|
||||
}
|
||||
|
||||
/** Query our cache and return the entry or NULL if not found or if expired. */
|
||||
@ -796,7 +792,7 @@ cache_clean_v3_as_client(time_t now)
|
||||
cache_client_desc_free(entry);
|
||||
/* Update our OOM. We didn't use the remove() function because we are in
|
||||
* a loop so we have to explicitly decrement. */
|
||||
rend_cache_decrement_allocation(entry_size);
|
||||
hs_cache_decrement_allocation(entry_size);
|
||||
/* Logging. */
|
||||
{
|
||||
char key_b64[BASE64_DIGEST256_LEN + 1];
|
||||
@ -934,8 +930,6 @@ hs_cache_remove_as_client(const ed25519_public_key_t *key)
|
||||
void
|
||||
hs_cache_clean_as_client(time_t now)
|
||||
{
|
||||
/* Start with v2 cache cleaning. */
|
||||
rend_cache_clean(now, REND_CACHE_TYPE_CLIENT);
|
||||
/* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
|
||||
* to compute the cutoff by itself using the lifetime value. */
|
||||
cache_clean_v3_as_client(now);
|
||||
@ -952,7 +946,7 @@ hs_cache_purge_as_client(void)
|
||||
cache_client_desc_free(entry);
|
||||
/* Update our OOM. We didn't use the remove() function because we are in
|
||||
* a loop so we have to explicitly decrement. */
|
||||
rend_cache_decrement_allocation(entry_size);
|
||||
hs_cache_decrement_allocation(entry_size);
|
||||
} DIGEST256MAP_FOREACH_END;
|
||||
|
||||
log_info(LD_REND, "Hidden service client descriptor cache purged.");
|
||||
@ -1074,19 +1068,16 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
|
||||
|
||||
/* The algorithm is as follow. K is the oldest expected descriptor age.
|
||||
*
|
||||
* 1) Deallocate all entries from v2 cache that are older than K hours.
|
||||
* 1.1) If the amount of remove bytes has been reached, stop.
|
||||
* 2) Deallocate all entries from v3 cache that are older than K hours
|
||||
* 1) Deallocate all entries from v3 cache that are older than K hours
|
||||
* 2.1) If the amount of remove bytes has been reached, stop.
|
||||
* 3) Set K = K - RendPostPeriod and repeat process until K is < 0.
|
||||
* 2) Set K = K - RendPostPeriod and repeat process until K is < 0.
|
||||
*
|
||||
* This ends up being O(Kn).
|
||||
*/
|
||||
|
||||
/* Set K to the oldest expected age in seconds which is the maximum
|
||||
* lifetime of a cache entry. We'll use the v2 lifetime because it's much
|
||||
* bigger than the v3 thus leading to cleaning older descriptors. */
|
||||
k = rend_cache_max_entry_lifetime();
|
||||
* lifetime of a cache entry. */
|
||||
k = hs_cache_max_entry_lifetime();
|
||||
|
||||
do {
|
||||
time_t cutoff;
|
||||
@ -1099,9 +1090,6 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
|
||||
/* Compute a cutoff value with K and the current time. */
|
||||
cutoff = now - k;
|
||||
|
||||
/* Start by cleaning the v2 cache with that cutoff. */
|
||||
bytes_removed += rend_cache_clean_v2_descs_as_dir(cutoff);
|
||||
|
||||
if (bytes_removed < min_remove_bytes) {
|
||||
/* We haven't remove enough bytes so clean v3 cache. */
|
||||
bytes_removed += cache_clean_v3_as_dir(now, cutoff);
|
||||
@ -1150,4 +1138,45 @@ hs_cache_free_all(void)
|
||||
digest256map_free(hs_cache_client_intro_state,
|
||||
cache_client_intro_state_free_void);
|
||||
hs_cache_client_intro_state = NULL;
|
||||
hs_cache_total_allocation = 0;
|
||||
}
|
||||
|
||||
/* Return total size of the cache. */
|
||||
size_t
|
||||
hs_cache_get_total_allocation(void)
|
||||
{
|
||||
return hs_cache_total_allocation;
|
||||
}
|
||||
|
||||
/** Decrement the total bytes attributed to the rendezvous cache by n. */
|
||||
void
|
||||
hs_cache_decrement_allocation(size_t n)
|
||||
{
|
||||
static int have_underflowed = 0;
|
||||
|
||||
if (hs_cache_total_allocation >= n) {
|
||||
hs_cache_total_allocation -= n;
|
||||
} else {
|
||||
hs_cache_total_allocation = 0;
|
||||
if (! have_underflowed) {
|
||||
have_underflowed = 1;
|
||||
log_warn(LD_BUG, "Underflow in hs_cache_decrement_allocation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Increase the total bytes attributed to the rendezvous cache by n. */
|
||||
void
|
||||
hs_cache_increment_allocation(size_t n)
|
||||
{
|
||||
static int have_overflowed = 0;
|
||||
if (hs_cache_total_allocation <= SIZE_MAX - n) {
|
||||
hs_cache_total_allocation += n;
|
||||
} else {
|
||||
hs_cache_total_allocation = SIZE_MAX;
|
||||
if (! have_overflowed) {
|
||||
have_overflowed = 1;
|
||||
log_warn(LD_BUG, "Overflow in hs_cache_increment_allocation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,14 @@ struct ed25519_public_key_t;
|
||||
/** This is the maximum time an introduction point state object can stay in the
|
||||
* client cache in seconds (2 mins or 120 seconds). */
|
||||
#define HS_CACHE_CLIENT_INTRO_STATE_MAX_AGE (2 * 60)
|
||||
/** How old do we let hidden service descriptors get before discarding
|
||||
* them as too old? */
|
||||
#define HS_CACHE_MAX_AGE (2*24*60*60)
|
||||
/** How wrong do we assume our clock may be when checking whether hidden
|
||||
* services are too old or too new? */
|
||||
#define HS_CACHE_MAX_SKEW (24*60*60)
|
||||
/** How old do we keep an intro point failure entry in the failure cache? */
|
||||
#define HS_CACHE_FAILURE_MAX_AGE (5*60)
|
||||
|
||||
/** Introduction point state. */
|
||||
typedef struct hs_cache_intro_state_t {
|
||||
@ -57,7 +65,6 @@ typedef struct hs_cache_dir_descriptor_t {
|
||||
/** Descriptor plaintext information. Obviously, we can't decrypt the
|
||||
* encrypted part of the descriptor. */
|
||||
hs_desc_plaintext_data_t *plaintext_data;
|
||||
|
||||
/** Encoded descriptor which is basically in text form. It's a NUL terminated
|
||||
* string thus safe to strlen(). */
|
||||
char *encoded_desc;
|
||||
@ -65,6 +72,13 @@ typedef struct hs_cache_dir_descriptor_t {
|
||||
|
||||
/* Public API */
|
||||
|
||||
/* Return maximum lifetime in seconds of a cache entry. */
|
||||
static inline time_t
|
||||
hs_cache_max_entry_lifetime(void)
|
||||
{
|
||||
return HS_CACHE_MAX_AGE + HS_CACHE_MAX_SKEW;
|
||||
}
|
||||
|
||||
void hs_cache_init(void);
|
||||
void hs_cache_free_all(void);
|
||||
void hs_cache_clean_as_dir(time_t now);
|
||||
@ -102,6 +116,10 @@ void hs_cache_client_intro_state_purge(void);
|
||||
|
||||
bool hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk);
|
||||
|
||||
size_t hs_cache_get_total_allocation(void);
|
||||
void hs_cache_decrement_allocation(size_t n);
|
||||
void hs_cache_increment_allocation(size_t n);
|
||||
|
||||
#ifdef HS_CACHE_PRIVATE
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "core/or/or.h"
|
||||
#include "app/config/config.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/hs_common/replaycache.h"
|
||||
|
||||
#include "feature/hs/hs_cell.h"
|
||||
@ -194,37 +193,10 @@ parse_introduce2_encrypted(const uint8_t *decrypted_data,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA
|
||||
* encryption key. The encoded cell is put in cell_out that MUST at least be
|
||||
* of the size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on
|
||||
* success else a negative value and cell_out is untouched. */
|
||||
static ssize_t
|
||||
build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key,
|
||||
uint8_t *cell_out)
|
||||
{
|
||||
ssize_t cell_len;
|
||||
|
||||
tor_assert(circ_nonce);
|
||||
tor_assert(enc_key);
|
||||
tor_assert(cell_out);
|
||||
|
||||
memwipe(cell_out, 0, RELAY_PAYLOAD_SIZE);
|
||||
|
||||
cell_len = rend_service_encode_establish_intro_cell((char*)cell_out,
|
||||
RELAY_PAYLOAD_SIZE,
|
||||
enc_key, circ_nonce);
|
||||
return cell_len;
|
||||
}
|
||||
|
||||
/** Parse an INTRODUCE2 cell from payload of size payload_len for the given
|
||||
* service and circuit which are used only for logging purposes. The resulting
|
||||
* parsed cell is put in cell_ptr_out.
|
||||
*
|
||||
* This function only parses prop224 INTRODUCE2 cells even when the intro point
|
||||
* is a legacy intro point. That's because intro points don't actually care
|
||||
* about the contents of the introduce cell. Legacy INTRODUCE cells are only
|
||||
* used by the legacy system now.
|
||||
*
|
||||
* Return 0 on success else a negative value and cell_ptr_out is untouched. */
|
||||
static int
|
||||
parse_introduce2_cell(const hs_service_t *service,
|
||||
@ -457,28 +429,6 @@ introduce1_set_auth_key(trn_cell_introduce1_t *cell,
|
||||
data->auth_pk->pubkey, trn_cell_introduce1_getlen_auth_key(cell));
|
||||
}
|
||||
|
||||
/** Set the legacy ID field in the INTRODUCE1 cell from the given data. */
|
||||
static void
|
||||
introduce1_set_legacy_id(trn_cell_introduce1_t *cell,
|
||||
const hs_cell_introduce1_data_t *data)
|
||||
{
|
||||
tor_assert(cell);
|
||||
tor_assert(data);
|
||||
|
||||
if (data->is_legacy) {
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
if (BUG(crypto_pk_get_digest(data->legacy_key, (char *) digest) < 0)) {
|
||||
return;
|
||||
}
|
||||
memcpy(trn_cell_introduce1_getarray_legacy_key_id(cell),
|
||||
digest, trn_cell_introduce1_getlen_legacy_key_id(cell));
|
||||
} else {
|
||||
/* We have to zeroed the LEGACY_KEY_ID field. */
|
||||
memset(trn_cell_introduce1_getarray_legacy_key_id(cell), 0,
|
||||
trn_cell_introduce1_getlen_legacy_key_id(cell));
|
||||
}
|
||||
}
|
||||
|
||||
/** Build and add to the given DoS cell extension the given parameter type and
|
||||
* value. */
|
||||
static void
|
||||
@ -608,8 +558,7 @@ build_establish_intro_extensions(const hs_service_config_t *service_config,
|
||||
/** Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
|
||||
* object. The encoded cell is put in cell_out that MUST at least be of the
|
||||
* size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
|
||||
* a negative value and cell_out is untouched. This function also supports
|
||||
* legacy cell creation. */
|
||||
* a negative value and cell_out is untouched. */
|
||||
ssize_t
|
||||
hs_cell_build_establish_intro(const char *circ_nonce,
|
||||
const hs_service_config_t *service_config,
|
||||
@ -625,16 +574,6 @@ hs_cell_build_establish_intro(const char *circ_nonce,
|
||||
tor_assert(service_config);
|
||||
tor_assert(ip);
|
||||
|
||||
/* Quickly handle the legacy IP. */
|
||||
if (ip->base.is_only_legacy) {
|
||||
tor_assert(ip->legacy_key);
|
||||
cell_len = build_legacy_establish_intro(circ_nonce, ip->legacy_key,
|
||||
cell_out);
|
||||
tor_assert(cell_len <= RELAY_PAYLOAD_SIZE);
|
||||
/* Success or not we are done here. */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Build the extensions, if any. */
|
||||
extensions = build_establish_intro_extensions(service_config, ip);
|
||||
|
||||
@ -1022,9 +961,6 @@ hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data,
|
||||
trn_cell_extension_set_num(ext, 0);
|
||||
trn_cell_introduce1_set_extensions(cell, ext);
|
||||
|
||||
/* Set the legacy ID field. */
|
||||
introduce1_set_legacy_id(cell, data);
|
||||
|
||||
/* Set the authentication key. */
|
||||
introduce1_set_auth_key(cell, data);
|
||||
|
||||
@ -1067,18 +1003,6 @@ hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len)
|
||||
|
||||
tor_assert(payload);
|
||||
|
||||
/* If it is a legacy IP, rend-spec.txt specifies that a ACK is 0 byte and a
|
||||
* NACK is 1 byte. We can't use the legacy function for this so we have to
|
||||
* do a special case. */
|
||||
if (payload_len <= 1) {
|
||||
if (payload_len == 0) {
|
||||
ret = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
|
||||
} else {
|
||||
ret = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (trn_cell_introduce_ack_parse(&cell, payload, payload_len) < 0) {
|
||||
log_info(LD_REND, "Invalid INTRODUCE_ACK cell. Unable to parse it.");
|
||||
goto end;
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "feature/nodelist/describe.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "lib/crypt_ops/crypto_dh.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
@ -105,57 +104,6 @@ create_rend_cpath(const uint8_t *ntor_key_seed, size_t seed_len,
|
||||
return cpath;
|
||||
}
|
||||
|
||||
/** We are a v2 legacy HS client: Create and return a crypt path for the hidden
|
||||
* service on the other side of the rendezvous circuit <b>circ</b>. Initialize
|
||||
* the crypt path crypto using the body of the RENDEZVOUS1 cell at
|
||||
* <b>rend_cell_body</b> (which must be at least DH1024_KEY_LEN+DIGEST_LEN
|
||||
* bytes).
|
||||
*/
|
||||
static crypt_path_t *
|
||||
create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body)
|
||||
{
|
||||
crypt_path_t *hop = NULL;
|
||||
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
|
||||
|
||||
/* first DH1024_KEY_LEN bytes are g^y from the service. Finish the dh
|
||||
* handshake...*/
|
||||
tor_assert(circ->build_state);
|
||||
tor_assert(circ->build_state->pending_final_cpath);
|
||||
hop = circ->build_state->pending_final_cpath;
|
||||
|
||||
tor_assert(hop->rend_dh_handshake_state);
|
||||
if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, hop->rend_dh_handshake_state,
|
||||
(char*)rend_cell_body, DH1024_KEY_LEN,
|
||||
keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
|
||||
log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
|
||||
goto err;
|
||||
}
|
||||
/* ... and set up cpath. */
|
||||
if (cpath_init_circuit_crypto(hop,
|
||||
keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN,
|
||||
0, 0) < 0)
|
||||
goto err;
|
||||
|
||||
/* Check whether the digest is right... */
|
||||
if (tor_memneq(keys, rend_cell_body+DH1024_KEY_LEN, DIGEST_LEN)) {
|
||||
log_warn(LD_PROTOCOL, "Incorrect digest of key material.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* clean up the crypto stuff we just made */
|
||||
crypto_dh_free(hop->rend_dh_handshake_state);
|
||||
hop->rend_dh_handshake_state = NULL;
|
||||
|
||||
goto done;
|
||||
|
||||
err:
|
||||
hop = NULL;
|
||||
|
||||
done:
|
||||
memwipe(keys, 0, sizeof(keys));
|
||||
return hop;
|
||||
}
|
||||
|
||||
/** Append the final <b>hop</b> to the cpath of the rend <b>circ</b>, and mark
|
||||
* <b>circ</b> ready for use to transfer HS relay cells. */
|
||||
static void
|
||||
@ -184,13 +132,6 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
|
||||
/* Append the hop to the cpath of this circuit */
|
||||
cpath_extend_linked_list(&circ->cpath, hop);
|
||||
|
||||
/* In legacy code, 'pending_final_cpath' points to the final hop we just
|
||||
* appended to the cpath. We set the original pointer to NULL so that we
|
||||
* don't double free it. */
|
||||
if (circ->build_state) {
|
||||
circ->build_state->pending_final_cpath = NULL;
|
||||
}
|
||||
|
||||
/* Finally, mark circuit as ready to be used for client streams */
|
||||
if (!is_service_side) {
|
||||
circuit_try_attaching_streams(circ);
|
||||
@ -198,7 +139,7 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
|
||||
}
|
||||
|
||||
/** For a given circuit and a service introduction point object, register the
|
||||
* intro circuit to the circuitmap. This supports legacy intro point. */
|
||||
* intro circuit to the circuitmap. */
|
||||
static void
|
||||
register_intro_circ(const hs_service_intro_point_t *ip,
|
||||
origin_circuit_t *circ)
|
||||
@ -206,13 +147,8 @@ register_intro_circ(const hs_service_intro_point_t *ip,
|
||||
tor_assert(ip);
|
||||
tor_assert(circ);
|
||||
|
||||
if (ip->base.is_only_legacy) {
|
||||
hs_circuitmap_register_intro_circ_v2_service_side(circ,
|
||||
ip->legacy_key_digest);
|
||||
} else {
|
||||
hs_circuitmap_register_intro_circ_v3_service_side(circ,
|
||||
&ip->auth_key_kp.pubkey);
|
||||
}
|
||||
hs_circuitmap_register_intro_circ_v3_service_side(circ,
|
||||
&ip->auth_key_kp.pubkey);
|
||||
}
|
||||
|
||||
/** Return the number of opened introduction circuit for the given circuit that
|
||||
@ -605,10 +541,6 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
|
||||
|
||||
/* Populate the introduce1 data object. */
|
||||
memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
|
||||
if (ip->legacy.key != NULL) {
|
||||
intro1_data->is_legacy = 1;
|
||||
intro1_data->legacy_key = ip->legacy.key;
|
||||
}
|
||||
intro1_data->auth_pk = &ip->auth_key_cert->signed_key;
|
||||
intro1_data->enc_pk = &ip->enc_key;
|
||||
intro1_data->subcredential = subcredential;
|
||||
@ -635,8 +567,8 @@ cleanup_on_close_client_circ(circuit_t *circ)
|
||||
if (circuit_is_hs_v3(circ)) {
|
||||
hs_client_circuit_cleanup_on_close(circ);
|
||||
}
|
||||
/* It is possible the circuit has an HS purpose but no identifier (rend_data
|
||||
* or hs_ident). Thus possible that this passes through. */
|
||||
/* It is possible the circuit has an HS purpose but no identifier (hs_ident).
|
||||
* Thus possible that this passes through. */
|
||||
}
|
||||
|
||||
/** Helper: cleanup function for client circuit. This is for every HS version.
|
||||
@ -649,8 +581,8 @@ cleanup_on_free_client_circ(circuit_t *circ)
|
||||
if (circuit_is_hs_v3(circ)) {
|
||||
hs_client_circuit_cleanup_on_free(circ);
|
||||
}
|
||||
/* It is possible the circuit has an HS purpose but no identifier (rend_data
|
||||
* or hs_ident). Thus possible that this passes through. */
|
||||
/* It is possible the circuit has an HS purpose but no identifier (hs_ident).
|
||||
* Thus possible that this passes through. */
|
||||
}
|
||||
|
||||
/* ========== */
|
||||
@ -664,12 +596,7 @@ hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip)
|
||||
{
|
||||
tor_assert(ip);
|
||||
|
||||
if (ip->base.is_only_legacy) {
|
||||
return hs_circuitmap_get_intro_circ_v2_service_side(ip->legacy_key_digest);
|
||||
} else {
|
||||
return hs_circuitmap_get_intro_circ_v3_service_side(
|
||||
&ip->auth_key_kp.pubkey);
|
||||
}
|
||||
return hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
|
||||
}
|
||||
|
||||
/** Return an introduction point established circuit matching the given intro
|
||||
@ -682,12 +609,7 @@ hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip)
|
||||
|
||||
tor_assert(ip);
|
||||
|
||||
if (ip->base.is_only_legacy) {
|
||||
circ = hs_circuitmap_get_intro_circ_v2_service_side(ip->legacy_key_digest);
|
||||
} else {
|
||||
circ = hs_circuitmap_get_intro_circ_v3_service_side(
|
||||
&ip->auth_key_kp.pubkey);
|
||||
}
|
||||
circ = hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
|
||||
|
||||
/* Only return circuit if it is established. */
|
||||
return (circ && TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO) ?
|
||||
@ -695,8 +617,7 @@ hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip)
|
||||
}
|
||||
|
||||
/** Called when we fail building a rendezvous circuit at some point other than
|
||||
* the last hop: launches a new circuit to the same rendezvous point. This
|
||||
* supports legacy service.
|
||||
* the last hop: launches a new circuit to the same rendezvous point.
|
||||
*
|
||||
* We currently relaunch connections to rendezvous points if:
|
||||
* - A rendezvous circuit timed out before connecting to RP.
|
||||
@ -726,8 +647,6 @@ hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ)
|
||||
/* Legacy services don't have a hidden service ident. */
|
||||
if (circ->hs_ident) {
|
||||
retry_service_rendezvous_point(circ);
|
||||
} else {
|
||||
rend_service_relaunch_rendezvous(circ);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -762,9 +681,7 @@ hs_circ_launch_intro_point(hs_service_t *service,
|
||||
goto end;
|
||||
}
|
||||
/* We only use a one-hop path on the first attempt. If the first attempt
|
||||
* fails, we use a 3-hop path for reachability / reliability.
|
||||
* (Unlike v2, retries is incremented by the caller before it calls this
|
||||
* function.) */
|
||||
* fails, we use a 3-hop path for reachability / reliability. */
|
||||
if (direct_conn && ip->circuit_retries == 1) {
|
||||
circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL;
|
||||
}
|
||||
@ -952,10 +869,8 @@ hs_circ_handle_intro_established(const hs_service_t *service,
|
||||
}
|
||||
|
||||
/* Try to parse the payload into a cell making sure we do actually have a
|
||||
* valid cell. For a legacy node, it's an empty payload so as long as we
|
||||
* have the cell, we are good. */
|
||||
if (!ip->base.is_only_legacy &&
|
||||
hs_cell_parse_intro_established(payload, payload_len) < 0) {
|
||||
* valid cell. */
|
||||
if (hs_cell_parse_intro_established(payload, payload_len) < 0) {
|
||||
log_warn(LD_REND, "Unable to parse the INTRO_ESTABLISHED cell on "
|
||||
"circuit %u for service %s",
|
||||
TO_CIRCUIT(circ)->n_circ_id,
|
||||
@ -1112,31 +1027,6 @@ hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** We are a v2 legacy HS client and we just received a RENDEZVOUS1 cell
|
||||
* <b>rend_cell_body</b> on <b>circ</b>. Finish up the DH key exchange and then
|
||||
* extend the crypt path of <b>circ</b> so that the hidden service is on the
|
||||
* other side. */
|
||||
int
|
||||
hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
|
||||
const uint8_t *rend_cell_body)
|
||||
{
|
||||
|
||||
if (BUG(!circuit_purpose_is_correct_for_rend(
|
||||
TO_CIRCUIT(circ)->purpose, 0))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypt_path_t *hop = create_rend_cpath_legacy(circ, rend_cell_body);
|
||||
if (!hop) {
|
||||
log_warn(LD_GENERAL, "Couldn't get v2 cpath.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
finalize_rend_circuit(circ, hop, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Given the introduction circuit intro_circ, the rendezvous circuit
|
||||
* rend_circ, a descriptor intro point object ip and the service's
|
||||
* subcredential, send an INTRODUCE1 cell on intro_circ.
|
||||
@ -1381,31 +1271,20 @@ hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ)
|
||||
* confirmed rendezsvous circuit but without an introduction ACK. */
|
||||
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_REND_READY);
|
||||
|
||||
/* The v2 and v3 circuit are handled differently:
|
||||
*
|
||||
* v2: A circ's pending_final_cpath field is non-NULL iff it is a rend circ
|
||||
* and we have tried to send an INTRODUCE1 cell specifying it. Thus, if the
|
||||
* pending_final_cpath field *is* NULL, then we want to not spare it.
|
||||
*
|
||||
* v3: When the INTRODUCE1 cell is sent, the introduction encryption public
|
||||
/* When the INTRODUCE1 cell is sent, the introduction encryption public
|
||||
* key is copied in the rendezvous circuit hs identifier. If it is a valid
|
||||
* key, we know that this circuit is waiting the ACK on the introduction
|
||||
* circuit. We want to _not_ spare the circuit if the key was never set. */
|
||||
|
||||
if (circ->rend_data) {
|
||||
/* v2. */
|
||||
if (circ->build_state && circ->build_state->pending_final_cpath != NULL) {
|
||||
return true;
|
||||
}
|
||||
} else if (circ->hs_ident) {
|
||||
if (circ->hs_ident) {
|
||||
/* v3. */
|
||||
if (curve25519_public_key_is_ok(&circ->hs_ident->intro_enc_pk)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
/* A circuit with an HS purpose without an hs_ident or rend_data in theory
|
||||
* can not happen. In case, scream loudly and return false to the caller
|
||||
* that the rendezvous was not sent in the INTRO1 cell. */
|
||||
/* A circuit with an HS purpose without an hs_ident in theory can not
|
||||
* happen. In case, scream loudly and return false to the caller that the
|
||||
* rendezvous was not sent in the INTRO1 cell. */
|
||||
tor_assert_nonfatal_unreached();
|
||||
}
|
||||
|
||||
|
@ -1950,11 +1950,6 @@ hs_client_note_connection_attempt_succeeded(const edge_connection_t *conn)
|
||||
{
|
||||
tor_assert(connection_edge_is_rendezvous_stream(conn));
|
||||
|
||||
if (BUG(conn->rend_data && conn->hs_ident)) {
|
||||
log_warn(LD_BUG, "Stream had both rend_data and hs_ident..."
|
||||
"Prioritizing hs_ident");
|
||||
}
|
||||
|
||||
if (conn->hs_ident) { /* It's v3: pass it to the prop224 handler */
|
||||
note_connection_attempt_succeeded(conn->hs_ident);
|
||||
return;
|
||||
@ -2094,8 +2089,6 @@ hs_client_circuit_has_opened(origin_circuit_t *circ)
|
||||
{
|
||||
tor_assert(circ);
|
||||
|
||||
/* Handle both version. v2 uses rend_data and v3 uses the hs circuit
|
||||
* identifier hs_ident. Can't be both. */
|
||||
switch (TO_CIRCUIT(circ)->purpose) {
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
||||
if (circ->hs_ident) {
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
@ -337,258 +336,6 @@ hs_get_start_time_of_next_time_period(time_t now)
|
||||
return (time_t)(start_of_next_tp_in_mins * 60 + time_period_rotation_offset);
|
||||
}
|
||||
|
||||
/** Create a new rend_data_t for a specific given <b>version</b>.
|
||||
* Return a pointer to the newly allocated data structure. */
|
||||
static rend_data_t *
|
||||
rend_data_alloc(uint32_t version)
|
||||
{
|
||||
rend_data_t *rend_data = NULL;
|
||||
|
||||
switch (version) {
|
||||
case HS_VERSION_TWO:
|
||||
{
|
||||
rend_data_v2_t *v2 = tor_malloc_zero(sizeof(*v2));
|
||||
v2->base_.version = HS_VERSION_TWO;
|
||||
v2->base_.hsdirs_fp = smartlist_new();
|
||||
rend_data = &v2->base_;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tor_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return rend_data;
|
||||
}
|
||||
|
||||
/** Free all storage associated with <b>data</b> */
|
||||
void
|
||||
rend_data_free_(rend_data_t *data)
|
||||
{
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* By using our allocation function, this should always be set. */
|
||||
tor_assert(data->hsdirs_fp);
|
||||
/* Cleanup the HSDir identity digest. */
|
||||
SMARTLIST_FOREACH(data->hsdirs_fp, char *, d, tor_free(d));
|
||||
smartlist_free(data->hsdirs_fp);
|
||||
/* Depending on the version, cleanup. */
|
||||
switch (data->version) {
|
||||
case HS_VERSION_TWO:
|
||||
{
|
||||
rend_data_v2_t *v2_data = TO_REND_DATA_V2(data);
|
||||
tor_free(v2_data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tor_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Allocate and return a deep copy of <b>data</b>. */
|
||||
rend_data_t *
|
||||
rend_data_dup(const rend_data_t *data)
|
||||
{
|
||||
rend_data_t *data_dup = NULL;
|
||||
smartlist_t *hsdirs_fp = smartlist_new();
|
||||
|
||||
tor_assert(data);
|
||||
tor_assert(data->hsdirs_fp);
|
||||
|
||||
SMARTLIST_FOREACH(data->hsdirs_fp, char *, fp,
|
||||
smartlist_add(hsdirs_fp, tor_memdup(fp, DIGEST_LEN)));
|
||||
|
||||
switch (data->version) {
|
||||
case HS_VERSION_TWO:
|
||||
{
|
||||
rend_data_v2_t *v2_data = tor_memdup(TO_REND_DATA_V2(data),
|
||||
sizeof(*v2_data));
|
||||
data_dup = &v2_data->base_;
|
||||
data_dup->hsdirs_fp = hsdirs_fp;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tor_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return data_dup;
|
||||
}
|
||||
|
||||
/** Compute the descriptor ID for each HS descriptor replica and save them. A
|
||||
* valid onion address must be present in the <b>rend_data</b>.
|
||||
*
|
||||
* Return 0 on success else -1. */
|
||||
static int
|
||||
compute_desc_id(rend_data_t *rend_data)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned replica;
|
||||
time_t now = time(NULL);
|
||||
|
||||
tor_assert(rend_data);
|
||||
|
||||
switch (rend_data->version) {
|
||||
case HS_VERSION_TWO:
|
||||
{
|
||||
rend_data_v2_t *v2_data = TO_REND_DATA_V2(rend_data);
|
||||
/* Compute descriptor ID for each replicas. */
|
||||
for (replica = 0; replica < ARRAY_LENGTH(v2_data->descriptor_id);
|
||||
replica++) {
|
||||
ret = rend_compute_v2_desc_id(v2_data->descriptor_id[replica],
|
||||
v2_data->onion_address,
|
||||
v2_data->descriptor_cookie,
|
||||
now, replica);
|
||||
if (ret < 0) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tor_assert(0);
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Allocate and initialize a rend_data_t object for a service using the
|
||||
* provided arguments. All arguments are optional (can be NULL), except from
|
||||
* <b>onion_address</b> which MUST be set. The <b>pk_digest</b> is the hash of
|
||||
* the service private key. The <b>cookie</b> is the rendezvous cookie and
|
||||
* <b>auth_type</b> is which authentiation this service is configured with.
|
||||
*
|
||||
* Return a valid rend_data_t pointer. This only returns a version 2 object of
|
||||
* rend_data_t. */
|
||||
rend_data_t *
|
||||
rend_data_service_create(const char *onion_address, const char *pk_digest,
|
||||
const uint8_t *cookie, rend_auth_type_t auth_type)
|
||||
{
|
||||
/* Create a rend_data_t object for version 2. */
|
||||
rend_data_t *rend_data = rend_data_alloc(HS_VERSION_TWO);
|
||||
rend_data_v2_t *v2= TO_REND_DATA_V2(rend_data);
|
||||
|
||||
/* We need at least one else the call is wrong. */
|
||||
tor_assert(onion_address != NULL);
|
||||
|
||||
if (pk_digest) {
|
||||
memcpy(v2->rend_pk_digest, pk_digest, sizeof(v2->rend_pk_digest));
|
||||
}
|
||||
if (cookie) {
|
||||
memcpy(rend_data->rend_cookie, cookie, sizeof(rend_data->rend_cookie));
|
||||
}
|
||||
|
||||
strlcpy(v2->onion_address, onion_address, sizeof(v2->onion_address));
|
||||
v2->auth_type = auth_type;
|
||||
|
||||
return rend_data;
|
||||
}
|
||||
|
||||
/** Allocate and initialize a rend_data_t object for a client request using the
|
||||
* given arguments. Either an onion address or a descriptor ID is needed. Both
|
||||
* can be given but in this case only the onion address will be used to make
|
||||
* the descriptor fetch. The <b>cookie</b> is the rendezvous cookie and
|
||||
* <b>auth_type</b> is which authentiation the service is configured with.
|
||||
*
|
||||
* Return a valid rend_data_t pointer or NULL on error meaning the
|
||||
* descriptor IDs couldn't be computed from the given data. */
|
||||
rend_data_t *
|
||||
rend_data_client_create(const char *onion_address, const char *desc_id,
|
||||
const char *cookie, rend_auth_type_t auth_type)
|
||||
{
|
||||
/* Create a rend_data_t object for version 2. */
|
||||
rend_data_t *rend_data = rend_data_alloc(HS_VERSION_TWO);
|
||||
rend_data_v2_t *v2= TO_REND_DATA_V2(rend_data);
|
||||
|
||||
/* We need at least one else the call is wrong. */
|
||||
tor_assert(onion_address != NULL || desc_id != NULL);
|
||||
|
||||
if (cookie) {
|
||||
memcpy(v2->descriptor_cookie, cookie, sizeof(v2->descriptor_cookie));
|
||||
}
|
||||
if (desc_id) {
|
||||
memcpy(v2->desc_id_fetch, desc_id, sizeof(v2->desc_id_fetch));
|
||||
}
|
||||
if (onion_address) {
|
||||
strlcpy(v2->onion_address, onion_address, sizeof(v2->onion_address));
|
||||
if (compute_desc_id(rend_data) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
v2->auth_type = auth_type;
|
||||
|
||||
return rend_data;
|
||||
|
||||
error:
|
||||
rend_data_free(rend_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return the onion address from the rend data. Depending on the version,
|
||||
* the size of the address can vary but it's always NUL terminated. */
|
||||
const char *
|
||||
rend_data_get_address(const rend_data_t *rend_data)
|
||||
{
|
||||
tor_assert(rend_data);
|
||||
|
||||
switch (rend_data->version) {
|
||||
case HS_VERSION_TWO:
|
||||
return TO_REND_DATA_V2(rend_data)->onion_address;
|
||||
default:
|
||||
/* We should always have a supported version. */
|
||||
tor_assert_unreached();
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the descriptor ID for a specific replica number from the rend
|
||||
* data. The returned data is a binary digest and depending on the version its
|
||||
* size can vary. The size of the descriptor ID is put in <b>len_out</b> if
|
||||
* non NULL. */
|
||||
const char *
|
||||
rend_data_get_desc_id(const rend_data_t *rend_data, uint8_t replica,
|
||||
size_t *len_out)
|
||||
{
|
||||
tor_assert(rend_data);
|
||||
|
||||
switch (rend_data->version) {
|
||||
case HS_VERSION_TWO:
|
||||
tor_assert(replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS);
|
||||
if (len_out) {
|
||||
*len_out = DIGEST_LEN;
|
||||
}
|
||||
return TO_REND_DATA_V2(rend_data)->descriptor_id[replica];
|
||||
default:
|
||||
/* We should always have a supported version. */
|
||||
tor_assert_unreached();
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the public key digest using the given <b>rend_data</b>. The size of
|
||||
* the digest is put in <b>len_out</b> (if set) which can differ depending on
|
||||
* the version. */
|
||||
const uint8_t *
|
||||
rend_data_get_pk_digest(const rend_data_t *rend_data, size_t *len_out)
|
||||
{
|
||||
tor_assert(rend_data);
|
||||
|
||||
switch (rend_data->version) {
|
||||
case HS_VERSION_TWO:
|
||||
{
|
||||
const rend_data_v2_t *v2_data = TO_REND_DATA_V2(rend_data);
|
||||
if (len_out) {
|
||||
*len_out = sizeof(v2_data->rend_pk_digest);
|
||||
}
|
||||
return (const uint8_t *) v2_data->rend_pk_digest;
|
||||
}
|
||||
default:
|
||||
/* We should always have a supported version. */
|
||||
tor_assert_unreached();
|
||||
}
|
||||
}
|
||||
|
||||
/** Using the given time period number, compute the disaster shared random
|
||||
* value and put it in srv_out. It MUST be at least DIGEST256_LEN bytes. */
|
||||
static void
|
||||
@ -1981,9 +1728,7 @@ hs_dec_rdv_stream_counter(origin_circuit_t *circ)
|
||||
{
|
||||
tor_assert(circ);
|
||||
|
||||
if (circ->rend_data) {
|
||||
circ->rend_data->nr_streams--;
|
||||
} else if (circ->hs_ident) {
|
||||
if (circ->hs_ident) {
|
||||
circ->hs_ident->num_rdv_streams--;
|
||||
} else {
|
||||
/* Should not be called if this circuit is not for hidden service. */
|
||||
@ -1998,9 +1743,7 @@ hs_inc_rdv_stream_counter(origin_circuit_t *circ)
|
||||
{
|
||||
tor_assert(circ);
|
||||
|
||||
if (circ->rend_data) {
|
||||
circ->rend_data->nr_streams++;
|
||||
} else if (circ->hs_ident) {
|
||||
if (circ->hs_ident) {
|
||||
circ->hs_ident->num_rdv_streams++;
|
||||
} else {
|
||||
/* Should not be called if this circuit is not for hidden service. */
|
||||
|
@ -19,13 +19,10 @@ struct ed25519_keypair_t;
|
||||
/* Trunnel */
|
||||
#include "trunnel/ed25519_cert.h"
|
||||
|
||||
/** Protocol version 2. Use this instead of hardcoding "2" in the code base,
|
||||
* this adds a clearer semantic to the value when used. */
|
||||
#define HS_VERSION_TWO 2
|
||||
/** Version 3 of the protocol (prop224). */
|
||||
#define HS_VERSION_THREE 3
|
||||
/** Earliest version we support. */
|
||||
#define HS_VERSION_MIN HS_VERSION_TWO
|
||||
#define HS_VERSION_MIN HS_VERSION_THREE
|
||||
/** Latest version we support. */
|
||||
#define HS_VERSION_MAX HS_VERSION_THREE
|
||||
|
||||
@ -194,24 +191,6 @@ void hs_build_blinded_keypair(const struct ed25519_keypair_t *kp,
|
||||
struct ed25519_keypair_t *kp_out);
|
||||
int hs_service_requires_uptime_circ(const smartlist_t *ports);
|
||||
|
||||
void rend_data_free_(rend_data_t *data);
|
||||
#define rend_data_free(data) \
|
||||
FREE_AND_NULL(rend_data_t, rend_data_free_, (data))
|
||||
rend_data_t *rend_data_dup(const rend_data_t *data);
|
||||
rend_data_t *rend_data_client_create(const char *onion_address,
|
||||
const char *desc_id,
|
||||
const char *cookie,
|
||||
rend_auth_type_t auth_type);
|
||||
rend_data_t *rend_data_service_create(const char *onion_address,
|
||||
const char *pk_digest,
|
||||
const uint8_t *cookie,
|
||||
rend_auth_type_t auth_type);
|
||||
const char *rend_data_get_address(const rend_data_t *rend_data);
|
||||
const char *rend_data_get_desc_id(const rend_data_t *rend_data,
|
||||
uint8_t replica, size_t *len_out);
|
||||
const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data,
|
||||
size_t *len_out);
|
||||
|
||||
routerstatus_t *pick_hsdir(const char *desc_id, const char *desc_id_base32);
|
||||
|
||||
struct hs_subcredential_t;
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "feature/hs/hs_client.h"
|
||||
#include "feature/hs/hs_ob.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "lib/encoding/confline.h"
|
||||
#include "lib/conf/confdecl.h"
|
||||
#include "lib/confmgt/confmgt.h"
|
||||
@ -101,23 +100,6 @@ stage_services(smartlist_t *service_list)
|
||||
{
|
||||
tor_assert(service_list);
|
||||
|
||||
/* This is v2 specific. Trigger service pruning which will make sure the
|
||||
* just configured services end up in the main global list. It should only
|
||||
* be done in non validation mode because v2 subsystem handles service
|
||||
* object differently. */
|
||||
rend_service_prune_list();
|
||||
|
||||
/* Cleanup v2 service from the list, we don't need those object anymore
|
||||
* because we validated them all against the others and we want to stage
|
||||
* only >= v3 service. And remember, v2 has a different object type which is
|
||||
* shadow copied from an hs_service_t type. */
|
||||
SMARTLIST_FOREACH_BEGIN(service_list, hs_service_t *, s) {
|
||||
if (s->config.version == HS_VERSION_TWO) {
|
||||
SMARTLIST_DEL_CURRENT(service_list, s);
|
||||
hs_service_free(s);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(s);
|
||||
|
||||
/* This is >= v3 specific. Using the newly configured service list, stage
|
||||
* them into our global state. Every object ownership is lost after. */
|
||||
hs_service_stage_services(service_list);
|
||||
@ -145,8 +127,7 @@ service_is_duplicate_in_list(const smartlist_t *service_list,
|
||||
/* XXX: Validate if we have any service that has the given service dir path.
|
||||
* This has two problems:
|
||||
*
|
||||
* a) It's O(n^2), but the same comment from the bottom of
|
||||
* rend_config_services() should apply.
|
||||
* a) It's O(n^2)
|
||||
*
|
||||
* b) We only compare directory paths as strings, so we can't
|
||||
* detect two distinct paths that specify the same directory
|
||||
@ -269,15 +250,6 @@ config_has_invalid_options(const config_line_t *line_,
|
||||
NULL /* End marker. */
|
||||
};
|
||||
|
||||
const char *opts_exclude_v2[] = {
|
||||
"HiddenServiceExportCircuitID",
|
||||
"HiddenServiceEnableIntroDoSDefense",
|
||||
"HiddenServiceEnableIntroDoSRatePerSec",
|
||||
"HiddenServiceEnableIntroDoSBurstPerSec",
|
||||
"HiddenServiceOnionBalanceInstance",
|
||||
NULL /* End marker. */
|
||||
};
|
||||
|
||||
/* Defining the size explicitly allows us to take advantage of the compiler
|
||||
* which warns us if we ever bump the max version but forget to grow this
|
||||
* array. The plus one is because we have a version 0 :). */
|
||||
@ -286,7 +258,7 @@ config_has_invalid_options(const config_line_t *line_,
|
||||
} exclude_lists[HS_VERSION_MAX + 1] = {
|
||||
{ NULL }, /* v0. */
|
||||
{ NULL }, /* v1. */
|
||||
{ opts_exclude_v2 }, /* v2 */
|
||||
{ NULL }, /* v2. */
|
||||
{ opts_exclude_v3 }, /* v3. */
|
||||
};
|
||||
|
||||
@ -310,16 +282,6 @@ config_has_invalid_options(const config_line_t *line_,
|
||||
"version %" PRIu32 " of service in %s",
|
||||
opt, service->config.version,
|
||||
service->config.directory_path);
|
||||
|
||||
if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
|
||||
/* Special case this v2 option so that we can offer alternatives.
|
||||
* If more such special cases appear, it would be good to
|
||||
* generalize the exception mechanism here. */
|
||||
log_warn(LD_CONFIG, "For v3 onion service client authorization, "
|
||||
"please read the 'CLIENT AUTHORIZATION' section in the "
|
||||
"manual.");
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
/* Continue the loop so we can find all possible options. */
|
||||
continue;
|
||||
@ -521,7 +483,7 @@ config_generic_service(const hs_opts_t *hs_opts,
|
||||
|
||||
/* Check if we are configured in non anonymous mode meaning every service
|
||||
* becomes a single onion service. */
|
||||
if (rend_service_non_anonymous_mode_enabled(options)) {
|
||||
if (hs_service_non_anonymous_mode_enabled(options)) {
|
||||
config->is_single_onion = 1;
|
||||
}
|
||||
|
||||
@ -594,8 +556,7 @@ config_service(config_line_t *line, const or_options_t *options,
|
||||
service->config.version = config_learn_service_version(service);
|
||||
}
|
||||
|
||||
/* We make sure that this set of options for a service are valid that is for
|
||||
* instance an option only for v2 is not used for v3. */
|
||||
/* We make sure that this set of options for a service are valid. */
|
||||
if (config_has_invalid_options(line->next, service)) {
|
||||
goto err;
|
||||
}
|
||||
@ -604,9 +565,6 @@ config_service(config_line_t *line, const or_options_t *options,
|
||||
* start just after the service directory line so once we hit another
|
||||
* directory line, the function knows that it has to stop parsing. */
|
||||
switch (service->config.version) {
|
||||
case HS_VERSION_TWO:
|
||||
ret = rend_config_service(hs_opts, options, &service->config);
|
||||
break;
|
||||
case HS_VERSION_THREE:
|
||||
ret = config_service_v3(hs_opts, &service->config);
|
||||
break;
|
||||
@ -687,11 +645,6 @@ hs_config_service_all(const or_options_t *options, int validate_only)
|
||||
* services. We don't need those objects anymore. */
|
||||
SMARTLIST_FOREACH(new_service_list, hs_service_t *, s,
|
||||
hs_service_free(s));
|
||||
/* For the v2 subsystem, the configuration function adds the service
|
||||
* object to the staging list and it is transferred in the main list
|
||||
* through the prunning process. In validation mode, we thus have to purge
|
||||
* the staging list so it's not kept in memory as valid service. */
|
||||
rend_service_free_staging_list();
|
||||
}
|
||||
|
||||
/* Success. Note that the service list has no ownership of its content. */
|
||||
|
@ -64,7 +64,6 @@
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/hs/hs_cache.h"
|
||||
#include "feature/hs/hs_config.h"
|
||||
#include "feature/nodelist/torcert.h" /* tor_cert_encode_ed22519() */
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "feature/nodelist/nickname.h"
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "lib/crypt_ops/crypto_ope.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
@ -2666,8 +2665,6 @@ run_housekeeping_event(time_t now)
|
||||
static void
|
||||
run_build_descriptor_event(time_t now)
|
||||
{
|
||||
/* For v2 services, this step happens in the upload event. */
|
||||
|
||||
/* Run v3+ events. */
|
||||
/* We start by rotating the descriptors only if needed. */
|
||||
rotate_all_descriptors(now);
|
||||
@ -2840,11 +2837,6 @@ run_build_circuit_event(time_t now)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Run v2 check. */
|
||||
if (rend_num_services() > 0) {
|
||||
rend_consider_services_intro_points(now);
|
||||
}
|
||||
|
||||
/* Run v3+ check. */
|
||||
FOR_EACH_SERVICE_BEGIN(service) {
|
||||
/* For introduction circuit, we need to make sure we don't stress too much
|
||||
@ -3280,13 +3272,6 @@ refresh_service_descriptor(const hs_service_t *service,
|
||||
STATIC void
|
||||
run_upload_descriptor_event(time_t now)
|
||||
{
|
||||
/* v2 services use the same function for descriptor creation and upload so
|
||||
* we do everything here because the intro circuits were checked before. */
|
||||
if (rend_num_services() > 0) {
|
||||
rend_consider_services_upload(now);
|
||||
rend_consider_descriptor_republication();
|
||||
}
|
||||
|
||||
/* Run v3+ check. */
|
||||
FOR_EACH_SERVICE_BEGIN(service) {
|
||||
FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
|
||||
@ -3615,6 +3600,54 @@ service_encode_descriptor(const hs_service_t *service,
|
||||
/* Public API */
|
||||
/* ========== */
|
||||
|
||||
/* Are HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode consistent?
|
||||
*/
|
||||
static int
|
||||
hs_service_non_anonymous_mode_consistent(const or_options_t *options)
|
||||
{
|
||||
/* !! is used to make these options boolean */
|
||||
return (!! options->HiddenServiceSingleHopMode ==
|
||||
!! options->HiddenServiceNonAnonymousMode);
|
||||
}
|
||||
|
||||
/* Do the options allow onion services to make direct (non-anonymous)
|
||||
* connections to introduction or rendezvous points?
|
||||
* Must only be called after options_validate_single_onion() has successfully
|
||||
* checked onion service option consistency.
|
||||
* Returns true if tor is in HiddenServiceSingleHopMode. */
|
||||
int
|
||||
hs_service_allow_non_anonymous_connection(const or_options_t *options)
|
||||
{
|
||||
tor_assert(hs_service_non_anonymous_mode_consistent(options));
|
||||
return options->HiddenServiceSingleHopMode ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Do the options allow us to reveal the exact startup time of the onion
|
||||
* service?
|
||||
* Single Onion Services prioritise availability over hiding their
|
||||
* startup time, as their IP address is publicly discoverable anyway.
|
||||
* Must only be called after options_validate_single_onion() has successfully
|
||||
* checked onion service option consistency.
|
||||
* Returns true if tor is in non-anonymous hidden service mode. */
|
||||
int
|
||||
hs_service_reveal_startup_time(const or_options_t *options)
|
||||
{
|
||||
tor_assert(hs_service_non_anonymous_mode_consistent(options));
|
||||
return hs_service_non_anonymous_mode_enabled(options);
|
||||
}
|
||||
|
||||
/* Is non-anonymous mode enabled using the HiddenServiceNonAnonymousMode
|
||||
* config option?
|
||||
* Must only be called after options_validate_single_onion() has successfully
|
||||
* checked onion service option consistency.
|
||||
*/
|
||||
int
|
||||
hs_service_non_anonymous_mode_enabled(const or_options_t *options)
|
||||
{
|
||||
tor_assert(hs_service_non_anonymous_mode_consistent(options));
|
||||
return options->HiddenServiceNonAnonymousMode ? 1 : 0;
|
||||
}
|
||||
|
||||
/** Called when a circuit was just cleaned up. This is done right before the
|
||||
* circuit is marked for close. */
|
||||
void
|
||||
@ -3641,7 +3674,7 @@ hs_service_circuit_cleanup_on_close(const circuit_t *circ)
|
||||
}
|
||||
}
|
||||
|
||||
/** This is called every time the service map (v2 or v3) changes that is if an
|
||||
/** This is called every time the service map changes that is if an
|
||||
* element is added or removed. */
|
||||
void
|
||||
hs_service_map_has_changed(void)
|
||||
@ -3992,9 +4025,6 @@ hs_service_lists_fnames_for_sandbox(smartlist_t *file_list,
|
||||
tor_assert(file_list);
|
||||
tor_assert(dir_list);
|
||||
|
||||
/* Add files and dirs for legacy services. */
|
||||
rend_services_add_filenames_to_lists(file_list, dir_list);
|
||||
|
||||
/* Add files and dirs for v3+. */
|
||||
FOR_EACH_SERVICE_BEGIN(service) {
|
||||
/* Skip ephemeral service, they don't touch the disk. */
|
||||
@ -4046,9 +4076,6 @@ hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload,
|
||||
if (circ->hs_ident) {
|
||||
ret = service_handle_introduce2(circ, payload, payload_len);
|
||||
hs_stats_note_introduce2_cell(1);
|
||||
} else {
|
||||
ret = rend_service_receive_introduction(circ, payload, payload_len);
|
||||
hs_stats_note_introduce2_cell(0);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -4075,12 +4102,8 @@ hs_service_receive_intro_established(origin_circuit_t *circ,
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Handle both version. v2 uses rend_data and v3 uses the hs circuit
|
||||
* identifier hs_ident. Can't be both. */
|
||||
if (circ->hs_ident) {
|
||||
ret = service_handle_intro_established(circ, payload, payload_len);
|
||||
} else {
|
||||
ret = rend_service_intro_established(circ, payload, payload_len);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
@ -4099,21 +4122,15 @@ hs_service_circuit_has_opened(origin_circuit_t *circ)
|
||||
{
|
||||
tor_assert(circ);
|
||||
|
||||
/* Handle both version. v2 uses rend_data and v3 uses the hs circuit
|
||||
* identifier hs_ident. Can't be both. */
|
||||
switch (TO_CIRCUIT(circ)->purpose) {
|
||||
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
|
||||
if (circ->hs_ident) {
|
||||
service_intro_circ_has_opened(circ);
|
||||
} else {
|
||||
rend_service_intro_has_opened(circ);
|
||||
}
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_S_CONNECT_REND:
|
||||
if (circ->hs_ident) {
|
||||
service_rendezvous_circ_has_opened(circ);
|
||||
} else {
|
||||
rend_service_rendezvous_has_opened(circ);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -4141,11 +4158,6 @@ hs_service_get_version_from_key(const hs_service_t *service)
|
||||
version = HS_VERSION_THREE;
|
||||
goto end;
|
||||
}
|
||||
/* Version 2 check. */
|
||||
if (rend_service_key_on_disk(directory_path)) {
|
||||
version = HS_VERSION_TWO;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
return version;
|
||||
@ -4156,13 +4168,6 @@ hs_service_get_version_from_key(const hs_service_t *service)
|
||||
int
|
||||
hs_service_load_all_keys(void)
|
||||
{
|
||||
/* Load v2 service keys if we have v2. */
|
||||
if (rend_num_services() != 0) {
|
||||
if (rend_service_load_all_keys(NULL) < 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load or/and generate them for v3+. */
|
||||
SMARTLIST_FOREACH_BEGIN(hs_service_staging_list, hs_service_t *, service) {
|
||||
/* Ignore ephemeral service, they already have their keys set. */
|
||||
@ -4362,9 +4367,6 @@ hs_service_init(void)
|
||||
tor_assert(!hs_service_map);
|
||||
tor_assert(!hs_service_staging_list);
|
||||
|
||||
/* v2 specific. */
|
||||
rend_service_init();
|
||||
|
||||
hs_service_map = tor_malloc_zero(sizeof(struct hs_service_ht));
|
||||
HT_INIT(hs_service_ht, hs_service_map);
|
||||
|
||||
@ -4375,7 +4377,6 @@ hs_service_init(void)
|
||||
void
|
||||
hs_service_free_all(void)
|
||||
{
|
||||
rend_service_free_all();
|
||||
service_free_all();
|
||||
hs_config_free_all();
|
||||
}
|
||||
|
@ -398,6 +398,11 @@ service_authorized_client_free_(hs_service_authorized_client_t *client);
|
||||
FREE_AND_NULL(hs_service_authorized_client_t, \
|
||||
service_authorized_client_free_, (c))
|
||||
|
||||
/* Config options. */
|
||||
int hs_service_allow_non_anonymous_connection(const or_options_t *options);
|
||||
int hs_service_non_anonymous_mode_enabled(const or_options_t *options);
|
||||
int hs_service_reveal_startup_time(const or_options_t *options);
|
||||
|
||||
#ifdef HS_SERVICE_PRIVATE
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
|
@ -64,7 +64,6 @@
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "lib/encoding/binascii.h"
|
||||
#include "lib/err/backtrace.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
@ -2471,7 +2470,6 @@ void
|
||||
router_dir_info_changed(void)
|
||||
{
|
||||
need_to_update_have_min_dir_info = 1;
|
||||
rend_hsdir_routers_changed();
|
||||
hs_service_dir_info_changed();
|
||||
hs_client_dir_info_changed();
|
||||
}
|
||||
|
@ -526,8 +526,8 @@ router_perform_bandwidth_test(int num_circs, time_t now)
|
||||
origin_circuit_t *circ = NULL;
|
||||
|
||||
log_notice(LD_OR,"Performing bandwidth self-test...done.");
|
||||
while ((circ = circuit_get_next_by_pk_and_purpose(circ, NULL,
|
||||
CIRCUIT_PURPOSE_TESTING))) {
|
||||
while ((circ = circuit_get_next_by_purpose(circ,
|
||||
CIRCUIT_PURPOSE_TESTING))) {
|
||||
/* dump cells_per_circuit drop cells onto this circ */
|
||||
int i = cells_per_circuit;
|
||||
if (circ->base_.state != CIRCUIT_STATE_OPEN)
|
||||
|
@ -1,7 +0,0 @@
|
||||
@dir /feature/rend
|
||||
@brief feature/rend: version 2 (old) hidden services
|
||||
|
||||
This directory implements the v2 onion service protocol,
|
||||
as specified in
|
||||
[rend-spec-v2.txt](https://gitweb.torproject.org/torspec.git/tree/rend-spec-v2.txt).
|
||||
|
@ -1,20 +1,10 @@
|
||||
|
||||
# ADD_C_FILE: INSERT SOURCES HERE.
|
||||
LIBTOR_APP_A_SOURCES += \
|
||||
src/feature/rend/rendcache.c \
|
||||
src/feature/rend/rendcommon.c \
|
||||
src/feature/rend/rendmid.c \
|
||||
src/feature/rend/rendparse.c \
|
||||
src/feature/rend/rendservice.c
|
||||
src/feature/rend/rendmid.c
|
||||
|
||||
# ADD_C_FILE: INSERT HEADERS HERE.
|
||||
noinst_HEADERS += \
|
||||
src/feature/rend/rend_authorized_client_st.h \
|
||||
src/feature/rend/rend_encoded_v2_service_descriptor_st.h \
|
||||
src/feature/rend/rend_intro_point_st.h \
|
||||
src/feature/rend/rend_service_descriptor_st.h \
|
||||
src/feature/rend/rendcache.h \
|
||||
src/feature/rend/rendcommon.h \
|
||||
src/feature/rend/rendmid.h \
|
||||
src/feature/rend/rendparse.h \
|
||||
src/feature/rend/rendservice.h
|
||||
src/feature/rend/rendmid.h
|
||||
|
@ -1,22 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* @file rend_authorized_client_st.h
|
||||
* @brief Hidden-service authorized client structure.
|
||||
**/
|
||||
|
||||
#ifndef REND_AUTHORIZED_CLIENT_ST_H
|
||||
#define REND_AUTHORIZED_CLIENT_ST_H
|
||||
|
||||
/** Hidden-service side configuration of client authorization. */
|
||||
struct rend_authorized_client_t {
|
||||
char *client_name;
|
||||
uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN];
|
||||
crypto_pk_t *client_key;
|
||||
};
|
||||
|
||||
#endif /* !defined(REND_AUTHORIZED_CLIENT_ST_H) */
|
@ -1,21 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* @file rend_encoded_v2_service_descriptor_st.h
|
||||
* @brief Encoded v2 HS descriptor structure.
|
||||
**/
|
||||
|
||||
#ifndef REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H
|
||||
#define REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H
|
||||
|
||||
/** ASCII-encoded v2 hidden service descriptor. */
|
||||
struct rend_encoded_v2_service_descriptor_t {
|
||||
char desc_id[DIGEST_LEN]; /**< Descriptor ID. */
|
||||
char *desc_str; /**< Descriptor string. */
|
||||
};
|
||||
|
||||
#endif /* !defined(REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H) */
|
@ -1,81 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* @file rend_intro_point_st.h
|
||||
* @brief v2 hidden service introduction point structure.
|
||||
**/
|
||||
|
||||
#ifndef REND_INTRO_POINT_ST_H
|
||||
#define REND_INTRO_POINT_ST_H
|
||||
|
||||
struct replaycache_t;
|
||||
struct crypto_pk_t;
|
||||
|
||||
/** Introduction point information. Used both in rend_service_t (on
|
||||
* the service side) and in rend_service_descriptor_t (on both the
|
||||
* client and service side). */
|
||||
struct rend_intro_point_t {
|
||||
extend_info_t *extend_info; /**< Extend info for connecting to this
|
||||
* introduction point via a multi-hop path. */
|
||||
struct crypto_pk_t *intro_key; /**< Introduction key that replaces the
|
||||
* service key, if this descriptor is V2. */
|
||||
|
||||
/** (Client side only) Flag indicating that a timeout has occurred
|
||||
* after sending an INTRODUCE cell to this intro point. After a
|
||||
* timeout, an intro point should not be tried again during the same
|
||||
* hidden service connection attempt, but it may be tried again
|
||||
* during a future connection attempt. */
|
||||
unsigned int timed_out : 1;
|
||||
|
||||
/** (Client side only) The number of times we have failed to build a
|
||||
* circuit to this intro point for some reason other than our
|
||||
* circuit-build timeout. See also MAX_INTRO_POINT_REACHABILITY_FAILURES. */
|
||||
unsigned int unreachable_count : 3;
|
||||
|
||||
/** (Service side only) Flag indicating that this intro point was
|
||||
* included in the last HS descriptor we generated. */
|
||||
unsigned int listed_in_last_desc : 1;
|
||||
|
||||
/** (Service side only) A replay cache recording the RSA-encrypted parts
|
||||
* of INTRODUCE2 cells this intro point's circuit has received. This is
|
||||
* used to prevent replay attacks. */
|
||||
struct replaycache_t *accepted_intro_rsa_parts;
|
||||
|
||||
/** (Service side only) Count of INTRODUCE2 cells accepted from this
|
||||
* intro point.
|
||||
*/
|
||||
int accepted_introduce2_count;
|
||||
|
||||
/** (Service side only) Maximum number of INTRODUCE2 cells that this IP
|
||||
* will accept. This is a random value between
|
||||
* INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS and
|
||||
* INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS. */
|
||||
int max_introductions;
|
||||
|
||||
/** (Service side only) The time at which this intro point was first
|
||||
* published, or -1 if this intro point has not yet been
|
||||
* published. */
|
||||
time_t time_published;
|
||||
|
||||
/** (Service side only) The time at which this intro point should
|
||||
* (start to) expire, or -1 if we haven't decided when this intro
|
||||
* point should expire. */
|
||||
time_t time_to_expire;
|
||||
|
||||
/** (Service side only) The amount of circuit creation we've made to this
|
||||
* intro point. This is incremented every time we do a circuit relaunch on
|
||||
* this object which is triggered when the circuit dies but the node is
|
||||
* still in the consensus. After MAX_INTRO_POINT_CIRCUIT_RETRIES, we give
|
||||
* up on it. */
|
||||
unsigned int circuit_retries;
|
||||
|
||||
/** (Service side only) Set if this intro point has an established circuit
|
||||
* and unset if it doesn't. */
|
||||
unsigned int circuit_established:1;
|
||||
};
|
||||
|
||||
#endif /* !defined(REND_INTRO_POINT_ST_H) */
|
@ -1,38 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* @file rend_service_descriptor_st.h
|
||||
* @brief Parsed v2 HS descriptor structure.
|
||||
**/
|
||||
|
||||
#ifndef REND_SERVICE_DESCRIPTOR_ST_H
|
||||
#define REND_SERVICE_DESCRIPTOR_ST_H
|
||||
|
||||
#define REND_PROTOCOL_VERSION_BITMASK_WIDTH 16
|
||||
|
||||
/** Information used to connect to a hidden service. Used on both the
|
||||
* service side and the client side. */
|
||||
struct rend_service_descriptor_t {
|
||||
crypto_pk_t *pk; /**< This service's public key. */
|
||||
int version; /**< Version of the descriptor format: 0 or 2. */
|
||||
time_t timestamp; /**< Time when the descriptor was generated. */
|
||||
/** Bitmask: which introduce/rendezvous protocols are supported?
|
||||
* (We allow bits '0', '1', '2' and '3' to be set.) */
|
||||
unsigned protocols : REND_PROTOCOL_VERSION_BITMASK_WIDTH;
|
||||
/** List of the service's introduction points. Elements are removed if
|
||||
* introduction attempts fail. */
|
||||
smartlist_t *intro_nodes;
|
||||
/** Has descriptor been uploaded to all hidden service directories? */
|
||||
int all_uploads_performed;
|
||||
/** List of hidden service directories to which an upload request for
|
||||
* this descriptor could be sent. Smartlist exists only when at least one
|
||||
* of the previous upload requests failed (otherwise it's not important
|
||||
* to know which uploads succeeded and which not). */
|
||||
smartlist_t *successful_uploads;
|
||||
};
|
||||
|
||||
#endif /* !defined(REND_SERVICE_DESCRIPTOR_ST_H) */
|
File diff suppressed because it is too large
Load Diff
@ -1,132 +0,0 @@
|
||||
/* Copyright (c) 2015-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file rendcache.h
|
||||
* \brief Header file for rendcache.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_RENDCACHE_H
|
||||
#define TOR_RENDCACHE_H
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
|
||||
/** How old do we let hidden service descriptors get before discarding
|
||||
* them as too old? */
|
||||
#define REND_CACHE_MAX_AGE (2*24*60*60)
|
||||
/** How wrong do we assume our clock may be when checking whether hidden
|
||||
* services are too old or too new? */
|
||||
#define REND_CACHE_MAX_SKEW (24*60*60)
|
||||
/** How old do we keep an intro point failure entry in the failure cache? */
|
||||
#define REND_CACHE_FAILURE_MAX_AGE (5*60)
|
||||
|
||||
/* Do not allow more than this many introduction points in a hidden service
|
||||
* descriptor */
|
||||
#define MAX_INTRO_POINTS 10
|
||||
|
||||
/** A cached rendezvous descriptor. */
|
||||
typedef struct rend_cache_entry_t {
|
||||
size_t len; /**< Length of <b>desc</b> */
|
||||
time_t last_served; /**< When did we last write this one to somebody?
|
||||
* (HSDir only) */
|
||||
char *desc; /**< Service descriptor */
|
||||
rend_service_descriptor_t *parsed; /**< Parsed value of 'desc' */
|
||||
} rend_cache_entry_t;
|
||||
|
||||
/* Introduction point failure type. */
|
||||
typedef struct rend_cache_failure_intro_t {
|
||||
/* When this intro point failure occurred thus we allocated this object and
|
||||
* cache it. */
|
||||
time_t created_ts;
|
||||
rend_intro_point_failure_t failure_type;
|
||||
} rend_cache_failure_intro_t;
|
||||
|
||||
/** Cache failure object indexed by service ID. */
|
||||
typedef struct rend_cache_failure_t {
|
||||
/* Contains rend_cache_failure_intro_t indexed by identity digest. */
|
||||
digestmap_t *intro_failures;
|
||||
} rend_cache_failure_t;
|
||||
|
||||
typedef enum {
|
||||
REND_CACHE_TYPE_CLIENT = 1,
|
||||
REND_CACHE_TYPE_SERVICE = 2,
|
||||
} rend_cache_type_t;
|
||||
|
||||
/* Return maximum lifetime in seconds of a cache entry. */
|
||||
static inline time_t
|
||||
rend_cache_max_entry_lifetime(void)
|
||||
{
|
||||
return REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW;
|
||||
}
|
||||
|
||||
void rend_cache_init(void);
|
||||
void rend_cache_clean(time_t now, rend_cache_type_t cache_type);
|
||||
void rend_cache_failure_clean(time_t now);
|
||||
size_t rend_cache_clean_v2_descs_as_dir(time_t cutoff);
|
||||
void rend_cache_purge(void);
|
||||
void rend_cache_free_all(void);
|
||||
int rend_cache_lookup_entry(const char *query, int version,
|
||||
rend_cache_entry_t **entry_out);
|
||||
int rend_cache_lookup_v2_desc_as_service(const char *query,
|
||||
rend_cache_entry_t **entry_out);
|
||||
int rend_cache_lookup_v2_desc_as_dir(const char *query, const char **desc);
|
||||
|
||||
int rend_cache_store_v2_desc_as_dir(const char *desc);
|
||||
int rend_cache_store_v2_desc_as_service(const char *desc);
|
||||
int rend_cache_store_v2_desc_as_client(const char *desc,
|
||||
const char *desc_id_base32,
|
||||
const rend_data_t *rend_query,
|
||||
rend_cache_entry_t **entry);
|
||||
size_t rend_cache_get_total_allocation(void);
|
||||
|
||||
bool rend_cache_intro_failure_exists(const char *service_id,
|
||||
const uint8_t *intro_identity);
|
||||
void rend_cache_intro_failure_note(rend_intro_point_failure_t failure,
|
||||
const uint8_t *identity,
|
||||
const char *service_id);
|
||||
void rend_cache_failure_purge(void);
|
||||
void rend_cache_decrement_allocation(size_t n);
|
||||
void rend_cache_increment_allocation(size_t n);
|
||||
|
||||
#ifdef RENDCACHE_PRIVATE
|
||||
|
||||
STATIC size_t rend_cache_entry_allocation(const rend_cache_entry_t *e);
|
||||
STATIC void rend_cache_entry_free_(rend_cache_entry_t *e);
|
||||
#define rend_cache_entry_free(e) \
|
||||
FREE_AND_NULL(rend_cache_entry_t, rend_cache_entry_free_, (e))
|
||||
STATIC void rend_cache_failure_intro_entry_free_(rend_cache_failure_intro_t
|
||||
*entry);
|
||||
#define rend_cache_failure_intro_entry_free(e) \
|
||||
FREE_AND_NULL(rend_cache_failure_intro_t, \
|
||||
rend_cache_failure_intro_entry_free_, (e))
|
||||
STATIC void rend_cache_failure_entry_free_(rend_cache_failure_t *entry);
|
||||
#define rend_cache_failure_entry_free(e) \
|
||||
FREE_AND_NULL(rend_cache_failure_t, \
|
||||
rend_cache_failure_entry_free_, (e))
|
||||
STATIC int cache_failure_intro_lookup(const uint8_t *identity,
|
||||
const char *service_id,
|
||||
rend_cache_failure_intro_t
|
||||
**intro_entry);
|
||||
STATIC rend_cache_failure_intro_t *rend_cache_failure_intro_entry_new(
|
||||
rend_intro_point_failure_t failure);
|
||||
STATIC rend_cache_failure_t *rend_cache_failure_entry_new(void);
|
||||
STATIC void rend_cache_failure_remove(rend_service_descriptor_t *desc);
|
||||
STATIC void cache_failure_intro_add(const uint8_t *identity,
|
||||
const char *service_id,
|
||||
rend_intro_point_failure_t failure);
|
||||
STATIC void validate_intro_point_failure(const rend_service_descriptor_t *desc,
|
||||
const char *service_id);
|
||||
|
||||
STATIC void rend_cache_failure_entry_free_void(void *entry);
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
extern strmap_t *rend_cache;
|
||||
extern strmap_t *rend_cache_failure;
|
||||
extern digestmap_t *rend_cache_v2_dir;
|
||||
extern size_t rend_cache_total_allocation;
|
||||
#endif /* defined(TOR_UNIT_TESTS) */
|
||||
#endif /* defined(RENDCACHE_PRIVATE) */
|
||||
|
||||
#endif /* !defined(TOR_RENDCACHE_H) */
|
||||
|
@ -11,763 +11,22 @@
|
||||
#define RENDCOMMON_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "core/or/circuitbuild.h"
|
||||
|
||||
#include "app/config/config.h"
|
||||
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuituse.h"
|
||||
#include "core/or/extendinfo.h"
|
||||
#include "app/config/config.h"
|
||||
#include "feature/control/control_events.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
|
||||
#include "feature/hs/hs_client.h"
|
||||
#include "feature/hs/hs_common.h"
|
||||
#include "feature/hs/hs_intropoint.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendmid.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "feature/hs_common/replaycache.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/dirparse/signing.h"
|
||||
|
||||
#include "core/or/circuit_st.h"
|
||||
#include "core/or/cpath_build_state_st.h"
|
||||
#include "core/or/crypt_path_st.h"
|
||||
#include "core/or/extend_info_st.h"
|
||||
#include "feature/nodelist/networkstatus_st.h"
|
||||
#include "core/or/origin_circuit_st.h"
|
||||
#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
|
||||
#include "feature/rend/rend_intro_point_st.h"
|
||||
#include "feature/rend/rend_service_descriptor_st.h"
|
||||
#include "feature/nodelist/routerstatus_st.h"
|
||||
|
||||
/** Return 0 if one and two are the same service ids, else -1 or 1 */
|
||||
int
|
||||
rend_cmp_service_ids(const char *one, const char *two)
|
||||
{
|
||||
return strcasecmp(one,two);
|
||||
}
|
||||
|
||||
/** Free the storage held by the service descriptor <b>desc</b>.
|
||||
*/
|
||||
void
|
||||
rend_service_descriptor_free_(rend_service_descriptor_t *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return;
|
||||
if (desc->pk)
|
||||
crypto_pk_free(desc->pk);
|
||||
if (desc->intro_nodes) {
|
||||
SMARTLIST_FOREACH(desc->intro_nodes, rend_intro_point_t *, intro,
|
||||
rend_intro_point_free(intro););
|
||||
smartlist_free(desc->intro_nodes);
|
||||
}
|
||||
if (desc->successful_uploads) {
|
||||
SMARTLIST_FOREACH(desc->successful_uploads, char *, c, tor_free(c););
|
||||
smartlist_free(desc->successful_uploads);
|
||||
}
|
||||
tor_free(desc);
|
||||
}
|
||||
|
||||
/** Length of the descriptor cookie that is used for versioned hidden
|
||||
* service descriptors. */
|
||||
#define REND_DESC_COOKIE_LEN 16
|
||||
|
||||
/** Length of the replica number that is used to determine the secret ID
|
||||
* part of versioned hidden service descriptors. */
|
||||
#define REND_REPLICA_LEN 1
|
||||
|
||||
/** Compute the descriptor ID for <b>service_id</b> of length
|
||||
* <b>REND_SERVICE_ID_LEN</b> and <b>secret_id_part</b> of length
|
||||
* <b>DIGEST_LEN</b>, and write it to <b>descriptor_id_out</b> of length
|
||||
* <b>DIGEST_LEN</b>. */
|
||||
void
|
||||
rend_get_descriptor_id_bytes(char *descriptor_id_out,
|
||||
const char *service_id,
|
||||
const char *secret_id_part)
|
||||
{
|
||||
crypto_digest_t *digest = crypto_digest_new();
|
||||
crypto_digest_add_bytes(digest, service_id, REND_SERVICE_ID_LEN);
|
||||
crypto_digest_add_bytes(digest, secret_id_part, DIGEST_LEN);
|
||||
crypto_digest_get_digest(digest, descriptor_id_out, DIGEST_LEN);
|
||||
crypto_digest_free(digest);
|
||||
}
|
||||
|
||||
/** Compute the secret ID part for time_period,
|
||||
* a <b>descriptor_cookie</b> of length
|
||||
* <b>REND_DESC_COOKIE_LEN</b> which may also be <b>NULL</b> if no
|
||||
* descriptor_cookie shall be used, and <b>replica</b>, and write it to
|
||||
* <b>secret_id_part</b> of length DIGEST_LEN. */
|
||||
static void
|
||||
get_secret_id_part_bytes(char *secret_id_part, uint32_t time_period,
|
||||
const char *descriptor_cookie, uint8_t replica)
|
||||
{
|
||||
crypto_digest_t *digest = crypto_digest_new();
|
||||
time_period = htonl(time_period);
|
||||
crypto_digest_add_bytes(digest, (char*)&time_period, sizeof(uint32_t));
|
||||
if (descriptor_cookie) {
|
||||
crypto_digest_add_bytes(digest, descriptor_cookie,
|
||||
REND_DESC_COOKIE_LEN);
|
||||
}
|
||||
crypto_digest_add_bytes(digest, (const char *)&replica, REND_REPLICA_LEN);
|
||||
crypto_digest_get_digest(digest, secret_id_part, DIGEST_LEN);
|
||||
crypto_digest_free(digest);
|
||||
}
|
||||
|
||||
/** Return the time period for time <b>now</b> plus a potentially
|
||||
* intended <b>deviation</b> of one or more periods, based on the first byte
|
||||
* of <b>service_id</b>. */
|
||||
static uint32_t
|
||||
get_time_period(time_t now, uint8_t deviation, const char *service_id)
|
||||
{
|
||||
/* The time period is the number of REND_TIME_PERIOD_V2_DESC_VALIDITY
|
||||
* intervals that have passed since the epoch, offset slightly so that
|
||||
* each service's time periods start and end at a fraction of that
|
||||
* period based on their first byte. */
|
||||
return (uint32_t)
|
||||
(now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256)
|
||||
/ REND_TIME_PERIOD_V2_DESC_VALIDITY + deviation;
|
||||
}
|
||||
|
||||
/** Compute the time in seconds that a descriptor that is generated
|
||||
* <b>now</b> for <b>service_id</b> will be valid. */
|
||||
static uint32_t
|
||||
get_seconds_valid(time_t now, const char *service_id)
|
||||
{
|
||||
uint32_t result = REND_TIME_PERIOD_V2_DESC_VALIDITY -
|
||||
((uint32_t)
|
||||
(now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256)
|
||||
% REND_TIME_PERIOD_V2_DESC_VALIDITY);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Compute the binary <b>desc_id_out</b> (DIGEST_LEN bytes long) for a given
|
||||
* base32-encoded <b>service_id</b> and optional unencoded
|
||||
* <b>descriptor_cookie</b> of length REND_DESC_COOKIE_LEN,
|
||||
* at time <b>now</b> for replica number
|
||||
* <b>replica</b>. <b>desc_id</b> needs to have <b>DIGEST_LEN</b> bytes
|
||||
* free. Return 0 for success, -1 otherwise. */
|
||||
int
|
||||
rend_compute_v2_desc_id(char *desc_id_out, const char *service_id,
|
||||
const char *descriptor_cookie, time_t now,
|
||||
uint8_t replica)
|
||||
{
|
||||
char service_id_binary[REND_SERVICE_ID_LEN];
|
||||
char secret_id_part[DIGEST_LEN];
|
||||
uint32_t time_period;
|
||||
if (!service_id ||
|
||||
strlen(service_id) != REND_SERVICE_ID_LEN_BASE32) {
|
||||
log_warn(LD_REND, "Could not compute v2 descriptor ID: "
|
||||
"Illegal service ID: %s",
|
||||
safe_str(service_id));
|
||||
return -1;
|
||||
}
|
||||
if (replica >= REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS) {
|
||||
log_warn(LD_REND, "Could not compute v2 descriptor ID: "
|
||||
"Replica number out of range: %d", replica);
|
||||
return -1;
|
||||
}
|
||||
/* Convert service ID to binary. */
|
||||
if (base32_decode(service_id_binary, REND_SERVICE_ID_LEN,
|
||||
service_id, REND_SERVICE_ID_LEN_BASE32) !=
|
||||
REND_SERVICE_ID_LEN) {
|
||||
log_warn(LD_REND, "Could not compute v2 descriptor ID: "
|
||||
"Illegal characters or wrong length for service ID: %s",
|
||||
safe_str_client(service_id));
|
||||
return -1;
|
||||
}
|
||||
/* Calculate current time-period. */
|
||||
time_period = get_time_period(now, 0, service_id_binary);
|
||||
/* Calculate secret-id-part = h(time-period | desc-cookie | replica). */
|
||||
get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
|
||||
replica);
|
||||
/* Calculate descriptor ID: H(permanent-id | secret-id-part) */
|
||||
rend_get_descriptor_id_bytes(desc_id_out, service_id_binary, secret_id_part);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Encode the introduction points in <b>desc</b> and write the result to a
|
||||
* newly allocated string pointed to by <b>encoded</b>. Return 0 for
|
||||
* success, -1 otherwise. */
|
||||
static int
|
||||
rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
|
||||
{
|
||||
size_t unenc_len;
|
||||
char *unenc = NULL;
|
||||
size_t unenc_written = 0;
|
||||
int i;
|
||||
int r = -1;
|
||||
/* Assemble unencrypted list of introduction points. */
|
||||
unenc_len = smartlist_len(desc->intro_nodes) * 1000; /* too long, but ok. */
|
||||
unenc = tor_malloc_zero(unenc_len);
|
||||
for (i = 0; i < smartlist_len(desc->intro_nodes); i++) {
|
||||
char id_base32[REND_INTRO_POINT_ID_LEN_BASE32 + 1];
|
||||
char *onion_key = NULL;
|
||||
size_t onion_key_len;
|
||||
crypto_pk_t *intro_key;
|
||||
char *service_key = NULL;
|
||||
char *address = NULL;
|
||||
size_t service_key_len;
|
||||
int res;
|
||||
rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i);
|
||||
/* Obtain extend info with introduction point details. */
|
||||
extend_info_t *info = intro->extend_info;
|
||||
/* Encode introduction point ID. */
|
||||
base32_encode(id_base32, sizeof(id_base32),
|
||||
info->identity_digest, DIGEST_LEN);
|
||||
/* Encode onion key. */
|
||||
if (crypto_pk_write_public_key_to_string(info->onion_key, &onion_key,
|
||||
&onion_key_len) < 0) {
|
||||
log_warn(LD_REND, "Could not write onion key.");
|
||||
goto done;
|
||||
}
|
||||
/* Encode intro key. */
|
||||
intro_key = intro->intro_key;
|
||||
if (!intro_key ||
|
||||
crypto_pk_write_public_key_to_string(intro_key, &service_key,
|
||||
&service_key_len) < 0) {
|
||||
log_warn(LD_REND, "Could not write intro key.");
|
||||
tor_free(onion_key);
|
||||
goto done;
|
||||
}
|
||||
/* Assemble everything for this introduction point. */
|
||||
const tor_addr_port_t *orport = extend_info_get_orport(info, AF_INET);
|
||||
IF_BUG_ONCE(!orport) {
|
||||
/* There must be an IPv4 address for v2 hs. */
|
||||
goto done;
|
||||
}
|
||||
address = tor_addr_to_str_dup(&orport->addr);
|
||||
res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written,
|
||||
"introduction-point %s\n"
|
||||
"ip-address %s\n"
|
||||
"onion-port %d\n"
|
||||
"onion-key\n%s"
|
||||
"service-key\n%s",
|
||||
id_base32,
|
||||
address,
|
||||
orport->port,
|
||||
onion_key,
|
||||
service_key);
|
||||
tor_free(address);
|
||||
tor_free(onion_key);
|
||||
tor_free(service_key);
|
||||
if (res < 0) {
|
||||
log_warn(LD_REND, "Not enough space for writing introduction point "
|
||||
"string.");
|
||||
goto done;
|
||||
}
|
||||
/* Update total number of written bytes for unencrypted intro points. */
|
||||
unenc_written += res;
|
||||
}
|
||||
/* Finalize unencrypted introduction points. */
|
||||
if (unenc_len < unenc_written + 2) {
|
||||
log_warn(LD_REND, "Not enough space for finalizing introduction point "
|
||||
"string.");
|
||||
goto done;
|
||||
}
|
||||
unenc[unenc_written++] = '\n';
|
||||
unenc[unenc_written++] = 0;
|
||||
*encoded = unenc;
|
||||
r = 0;
|
||||
done:
|
||||
if (r<0)
|
||||
tor_free(unenc);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Encrypt the encoded introduction points in <b>encoded</b> using
|
||||
* authorization type 'basic' with <b>client_cookies</b> and write the
|
||||
* result to a newly allocated string pointed to by <b>encrypted_out</b> of
|
||||
* length <b>encrypted_len_out</b>. Return 0 for success, -1 otherwise. */
|
||||
static int
|
||||
rend_encrypt_v2_intro_points_basic(char **encrypted_out,
|
||||
size_t *encrypted_len_out,
|
||||
const char *encoded,
|
||||
smartlist_t *client_cookies)
|
||||
{
|
||||
int r = -1, i, pos, enclen, client_blocks;
|
||||
size_t len, client_entries_len;
|
||||
char *enc = NULL, iv[CIPHER_IV_LEN], *client_part = NULL,
|
||||
session_key[CIPHER_KEY_LEN];
|
||||
smartlist_t *encrypted_session_keys = NULL;
|
||||
crypto_digest_t *digest;
|
||||
crypto_cipher_t *cipher;
|
||||
tor_assert(encoded);
|
||||
tor_assert(client_cookies && smartlist_len(client_cookies) > 0);
|
||||
|
||||
/* Generate session key. */
|
||||
crypto_rand(session_key, CIPHER_KEY_LEN);
|
||||
|
||||
/* Determine length of encrypted introduction points including session
|
||||
* keys. */
|
||||
client_blocks = 1 + ((smartlist_len(client_cookies) - 1) /
|
||||
REND_BASIC_AUTH_CLIENT_MULTIPLE);
|
||||
client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
|
||||
REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
|
||||
len = 2 + client_entries_len + CIPHER_IV_LEN + strlen(encoded);
|
||||
if (client_blocks >= 256) {
|
||||
log_warn(LD_REND, "Too many clients in introduction point string.");
|
||||
goto done;
|
||||
}
|
||||
enc = tor_malloc_zero(len);
|
||||
enc[0] = 0x01; /* type of authorization. */
|
||||
enc[1] = (uint8_t)client_blocks;
|
||||
|
||||
/* Encrypt with random session key. */
|
||||
enclen = crypto_cipher_encrypt_with_iv(session_key,
|
||||
enc + 2 + client_entries_len,
|
||||
CIPHER_IV_LEN + strlen(encoded), encoded, strlen(encoded));
|
||||
|
||||
if (enclen < 0) {
|
||||
log_warn(LD_REND, "Could not encrypt introduction point string.");
|
||||
goto done;
|
||||
}
|
||||
memcpy(iv, enc + 2 + client_entries_len, CIPHER_IV_LEN);
|
||||
|
||||
/* Encrypt session key for cookies, determine client IDs, and put both
|
||||
* in a smartlist. */
|
||||
encrypted_session_keys = smartlist_new();
|
||||
SMARTLIST_FOREACH_BEGIN(client_cookies, const char *, cookie) {
|
||||
client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
|
||||
/* Encrypt session key. */
|
||||
cipher = crypto_cipher_new(cookie);
|
||||
if (crypto_cipher_encrypt(cipher, client_part +
|
||||
REND_BASIC_AUTH_CLIENT_ID_LEN,
|
||||
session_key, CIPHER_KEY_LEN) < 0) {
|
||||
log_warn(LD_REND, "Could not encrypt session key for client.");
|
||||
crypto_cipher_free(cipher);
|
||||
tor_free(client_part);
|
||||
goto done;
|
||||
}
|
||||
crypto_cipher_free(cipher);
|
||||
|
||||
/* Determine client ID. */
|
||||
digest = crypto_digest_new();
|
||||
crypto_digest_add_bytes(digest, cookie, REND_DESC_COOKIE_LEN);
|
||||
crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
|
||||
crypto_digest_get_digest(digest, client_part,
|
||||
REND_BASIC_AUTH_CLIENT_ID_LEN);
|
||||
crypto_digest_free(digest);
|
||||
|
||||
/* Put both together. */
|
||||
smartlist_add(encrypted_session_keys, client_part);
|
||||
} SMARTLIST_FOREACH_END(cookie);
|
||||
|
||||
/* Add some fake client IDs and encrypted session keys. */
|
||||
for (i = (smartlist_len(client_cookies) - 1) %
|
||||
REND_BASIC_AUTH_CLIENT_MULTIPLE;
|
||||
i < REND_BASIC_AUTH_CLIENT_MULTIPLE - 1; i++) {
|
||||
client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
|
||||
crypto_rand(client_part, REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
|
||||
smartlist_add(encrypted_session_keys, client_part);
|
||||
}
|
||||
/* Sort smartlist and put elements in result in order. */
|
||||
smartlist_sort_digests(encrypted_session_keys);
|
||||
pos = 2;
|
||||
SMARTLIST_FOREACH(encrypted_session_keys, const char *, entry, {
|
||||
memcpy(enc + pos, entry, REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
|
||||
pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
|
||||
});
|
||||
*encrypted_out = enc;
|
||||
*encrypted_len_out = len;
|
||||
enc = NULL; /* prevent free. */
|
||||
r = 0;
|
||||
done:
|
||||
tor_free(enc);
|
||||
if (encrypted_session_keys) {
|
||||
SMARTLIST_FOREACH(encrypted_session_keys, char *, d, tor_free(d););
|
||||
smartlist_free(encrypted_session_keys);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Encrypt the encoded introduction points in <b>encoded</b> using
|
||||
* authorization type 'stealth' with <b>descriptor_cookie</b> of length
|
||||
* REND_DESC_COOKIE_LEN and write the result to a newly allocated string
|
||||
* pointed to by <b>encrypted_out</b> of length <b>encrypted_len_out</b>.
|
||||
* Return 0 for success, -1 otherwise. */
|
||||
static int
|
||||
rend_encrypt_v2_intro_points_stealth(char **encrypted_out,
|
||||
size_t *encrypted_len_out,
|
||||
const char *encoded,
|
||||
const char *descriptor_cookie)
|
||||
{
|
||||
int r = -1, enclen;
|
||||
char *enc;
|
||||
tor_assert(encoded);
|
||||
tor_assert(descriptor_cookie);
|
||||
|
||||
enc = tor_malloc_zero(1 + CIPHER_IV_LEN + strlen(encoded));
|
||||
enc[0] = 0x02; /* Auth type */
|
||||
enclen = crypto_cipher_encrypt_with_iv(descriptor_cookie,
|
||||
enc + 1,
|
||||
CIPHER_IV_LEN+strlen(encoded),
|
||||
encoded, strlen(encoded));
|
||||
if (enclen < 0) {
|
||||
log_warn(LD_REND, "Could not encrypt introduction point string.");
|
||||
goto done;
|
||||
}
|
||||
*encrypted_out = enc;
|
||||
*encrypted_len_out = enclen;
|
||||
enc = NULL; /* prevent free */
|
||||
r = 0;
|
||||
done:
|
||||
tor_free(enc);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Attempt to parse the given <b>desc_str</b> and return true if this
|
||||
* succeeds, false otherwise. */
|
||||
STATIC int
|
||||
rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc)
|
||||
{
|
||||
rend_service_descriptor_t *test_parsed = NULL;
|
||||
char test_desc_id[DIGEST_LEN];
|
||||
char *test_intro_content = NULL;
|
||||
size_t test_intro_size;
|
||||
size_t test_encoded_size;
|
||||
const char *test_next;
|
||||
int res = rend_parse_v2_service_descriptor(&test_parsed, test_desc_id,
|
||||
&test_intro_content,
|
||||
&test_intro_size,
|
||||
&test_encoded_size,
|
||||
&test_next, desc->desc_str, 1);
|
||||
rend_service_descriptor_free(test_parsed);
|
||||
tor_free(test_intro_content);
|
||||
return (res >= 0);
|
||||
}
|
||||
|
||||
/** Free the storage held by an encoded v2 service descriptor. */
|
||||
void
|
||||
rend_encoded_v2_service_descriptor_free_(
|
||||
rend_encoded_v2_service_descriptor_t *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return;
|
||||
tor_free(desc->desc_str);
|
||||
tor_free(desc);
|
||||
}
|
||||
|
||||
/** Free the storage held by an introduction point info. */
|
||||
void
|
||||
rend_intro_point_free_(rend_intro_point_t *intro)
|
||||
{
|
||||
if (!intro)
|
||||
return;
|
||||
|
||||
extend_info_free(intro->extend_info);
|
||||
crypto_pk_free(intro->intro_key);
|
||||
|
||||
if (intro->accepted_intro_rsa_parts != NULL) {
|
||||
replaycache_free(intro->accepted_intro_rsa_parts);
|
||||
}
|
||||
|
||||
tor_free(intro);
|
||||
}
|
||||
|
||||
/** Encode a set of rend_encoded_v2_service_descriptor_t's for <b>desc</b>
|
||||
* at time <b>now</b> using <b>service_key</b>, depending on
|
||||
* <b>auth_type</b> a <b>descriptor_cookie</b> and a list of
|
||||
* <b>client_cookies</b> (which are both <b>NULL</b> if no client
|
||||
* authorization is performed), and <b>period</b> (e.g. 0 for the current
|
||||
* period, 1 for the next period, etc.) and add them to the existing list
|
||||
* <b>descs_out</b>; return the number of seconds that the descriptors will
|
||||
* be found by clients, or -1 if the encoding was not successful. */
|
||||
int
|
||||
rend_encode_v2_descriptors(smartlist_t *descs_out,
|
||||
rend_service_descriptor_t *desc, time_t now,
|
||||
uint8_t period, rend_auth_type_t auth_type,
|
||||
crypto_pk_t *client_key,
|
||||
smartlist_t *client_cookies)
|
||||
{
|
||||
char service_id[DIGEST_LEN];
|
||||
char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1];
|
||||
uint32_t time_period;
|
||||
char *ipos_base64 = NULL, *ipos = NULL, *ipos_encrypted = NULL,
|
||||
*descriptor_cookie = NULL;
|
||||
size_t ipos_len = 0, ipos_encrypted_len = 0;
|
||||
int k;
|
||||
uint32_t seconds_valid;
|
||||
crypto_pk_t *service_key;
|
||||
if (!desc) {
|
||||
log_warn(LD_BUG, "Could not encode v2 descriptor: No desc given.");
|
||||
return -1;
|
||||
}
|
||||
service_key = (auth_type == REND_STEALTH_AUTH) ? client_key : desc->pk;
|
||||
tor_assert(service_key);
|
||||
if (auth_type == REND_STEALTH_AUTH) {
|
||||
descriptor_cookie = smartlist_get(client_cookies, 0);
|
||||
tor_assert(descriptor_cookie);
|
||||
}
|
||||
/* Obtain service_id from public key. */
|
||||
if (crypto_pk_get_digest(service_key, service_id) < 0) {
|
||||
log_warn(LD_BUG, "Couldn't compute service key digest.");
|
||||
return -1;
|
||||
}
|
||||
/* Calculate current time-period. */
|
||||
time_period = get_time_period(now, period, service_id);
|
||||
/* Determine how many seconds the descriptor will be valid. */
|
||||
seconds_valid = period * REND_TIME_PERIOD_V2_DESC_VALIDITY +
|
||||
get_seconds_valid(now, service_id);
|
||||
/* Assemble, possibly encrypt, and encode introduction points. */
|
||||
if (smartlist_len(desc->intro_nodes) > 0) {
|
||||
if (rend_encode_v2_intro_points(&ipos, desc) < 0) {
|
||||
log_warn(LD_REND, "Encoding of introduction points did not succeed.");
|
||||
return -1;
|
||||
}
|
||||
switch (auth_type) {
|
||||
case REND_NO_AUTH:
|
||||
ipos_len = strlen(ipos);
|
||||
break;
|
||||
case REND_BASIC_AUTH:
|
||||
if (rend_encrypt_v2_intro_points_basic(&ipos_encrypted,
|
||||
&ipos_encrypted_len, ipos,
|
||||
client_cookies) < 0) {
|
||||
log_warn(LD_REND, "Encrypting of introduction points did not "
|
||||
"succeed.");
|
||||
tor_free(ipos);
|
||||
return -1;
|
||||
}
|
||||
tor_free(ipos);
|
||||
ipos = ipos_encrypted;
|
||||
ipos_len = ipos_encrypted_len;
|
||||
break;
|
||||
case REND_STEALTH_AUTH:
|
||||
if (rend_encrypt_v2_intro_points_stealth(&ipos_encrypted,
|
||||
&ipos_encrypted_len, ipos,
|
||||
descriptor_cookie) < 0) {
|
||||
log_warn(LD_REND, "Encrypting of introduction points did not "
|
||||
"succeed.");
|
||||
tor_free(ipos);
|
||||
return -1;
|
||||
}
|
||||
tor_free(ipos);
|
||||
ipos = ipos_encrypted;
|
||||
ipos_len = ipos_encrypted_len;
|
||||
break;
|
||||
case REND_V3_AUTH:
|
||||
break; /* v3 service, break. */
|
||||
default:
|
||||
log_warn(LD_REND|LD_BUG, "Unrecognized authorization type %d",
|
||||
(int)auth_type);
|
||||
tor_free(ipos);
|
||||
return -1;
|
||||
}
|
||||
/* Base64-encode introduction points. */
|
||||
ipos_base64 = tor_calloc(ipos_len, 2);
|
||||
if (base64_encode(ipos_base64, ipos_len * 2, ipos, ipos_len,
|
||||
BASE64_ENCODE_MULTILINE)<0) {
|
||||
log_warn(LD_REND, "Could not encode introduction point string to "
|
||||
"base64. length=%d", (int)ipos_len);
|
||||
tor_free(ipos_base64);
|
||||
tor_free(ipos);
|
||||
return -1;
|
||||
}
|
||||
tor_free(ipos);
|
||||
}
|
||||
/* Encode REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS descriptors. */
|
||||
for (k = 0; k < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; k++) {
|
||||
char secret_id_part[DIGEST_LEN];
|
||||
char secret_id_part_base32[REND_SECRET_ID_PART_LEN_BASE32 + 1];
|
||||
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
|
||||
char *permanent_key = NULL;
|
||||
size_t permanent_key_len;
|
||||
char published[ISO_TIME_LEN+1];
|
||||
int i;
|
||||
char protocol_versions_string[16]; /* max len: "0,1,2,3,4,5,6,7\0" */
|
||||
size_t protocol_versions_written;
|
||||
size_t desc_len;
|
||||
char *desc_str = NULL;
|
||||
int result = 0;
|
||||
size_t written = 0;
|
||||
char desc_digest[DIGEST_LEN];
|
||||
rend_encoded_v2_service_descriptor_t *enc =
|
||||
tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
|
||||
/* Calculate secret-id-part = h(time-period | cookie | replica). */
|
||||
get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
|
||||
k);
|
||||
base32_encode(secret_id_part_base32, sizeof(secret_id_part_base32),
|
||||
secret_id_part, DIGEST_LEN);
|
||||
/* Calculate descriptor ID. */
|
||||
rend_get_descriptor_id_bytes(enc->desc_id, service_id, secret_id_part);
|
||||
base32_encode(desc_id_base32, sizeof(desc_id_base32),
|
||||
enc->desc_id, DIGEST_LEN);
|
||||
/* PEM-encode the public key */
|
||||
if (crypto_pk_write_public_key_to_string(service_key, &permanent_key,
|
||||
&permanent_key_len) < 0) {
|
||||
log_warn(LD_BUG, "Could not write public key to string.");
|
||||
rend_encoded_v2_service_descriptor_free(enc);
|
||||
goto err;
|
||||
}
|
||||
/* Encode timestamp. */
|
||||
format_iso_time(published, desc->timestamp);
|
||||
/* Write protocol-versions bitmask to comma-separated value string. */
|
||||
protocol_versions_written = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (desc->protocols & 1 << i) {
|
||||
tor_snprintf(protocol_versions_string + protocol_versions_written,
|
||||
16 - protocol_versions_written, "%d,", i);
|
||||
protocol_versions_written += 2;
|
||||
}
|
||||
}
|
||||
if (protocol_versions_written)
|
||||
protocol_versions_string[protocol_versions_written - 1] = '\0';
|
||||
else
|
||||
protocol_versions_string[0]= '\0';
|
||||
/* Assemble complete descriptor. */
|
||||
desc_len = 2000 + smartlist_len(desc->intro_nodes) * 1000; /* far too long,
|
||||
but okay.*/
|
||||
enc->desc_str = desc_str = tor_malloc_zero(desc_len);
|
||||
result = tor_snprintf(desc_str, desc_len,
|
||||
"rendezvous-service-descriptor %s\n"
|
||||
"version 2\n"
|
||||
"permanent-key\n%s"
|
||||
"secret-id-part %s\n"
|
||||
"publication-time %s\n"
|
||||
"protocol-versions %s\n",
|
||||
desc_id_base32,
|
||||
permanent_key,
|
||||
secret_id_part_base32,
|
||||
published,
|
||||
protocol_versions_string);
|
||||
tor_free(permanent_key);
|
||||
if (result < 0) {
|
||||
log_warn(LD_BUG, "Descriptor ran out of room.");
|
||||
rend_encoded_v2_service_descriptor_free(enc);
|
||||
goto err;
|
||||
}
|
||||
written = result;
|
||||
/* Add introduction points. */
|
||||
if (ipos_base64) {
|
||||
result = tor_snprintf(desc_str + written, desc_len - written,
|
||||
"introduction-points\n"
|
||||
"-----BEGIN MESSAGE-----\n%s"
|
||||
"-----END MESSAGE-----\n",
|
||||
ipos_base64);
|
||||
if (result < 0) {
|
||||
log_warn(LD_BUG, "could not write introduction points.");
|
||||
rend_encoded_v2_service_descriptor_free(enc);
|
||||
goto err;
|
||||
}
|
||||
written += result;
|
||||
}
|
||||
/* Add signature. */
|
||||
strlcpy(desc_str + written, "signature\n", desc_len - written);
|
||||
written += strlen(desc_str + written);
|
||||
if (crypto_digest(desc_digest, desc_str, written) < 0) {
|
||||
log_warn(LD_BUG, "could not create digest.");
|
||||
rend_encoded_v2_service_descriptor_free(enc);
|
||||
goto err;
|
||||
}
|
||||
if (router_append_dirobj_signature(desc_str + written,
|
||||
desc_len - written,
|
||||
desc_digest, DIGEST_LEN,
|
||||
service_key) < 0) {
|
||||
log_warn(LD_BUG, "Couldn't sign desc.");
|
||||
rend_encoded_v2_service_descriptor_free(enc);
|
||||
goto err;
|
||||
}
|
||||
written += strlen(desc_str+written);
|
||||
if (written+2 > desc_len) {
|
||||
log_warn(LD_BUG, "Could not finish desc.");
|
||||
rend_encoded_v2_service_descriptor_free(enc);
|
||||
goto err;
|
||||
}
|
||||
desc_str[written++] = 0;
|
||||
/* Check if we can parse our own descriptor. */
|
||||
if (!rend_desc_v2_is_parsable(enc)) {
|
||||
log_warn(LD_BUG, "Could not parse my own descriptor: %s", desc_str);
|
||||
rend_encoded_v2_service_descriptor_free(enc);
|
||||
goto err;
|
||||
}
|
||||
smartlist_add(descs_out, enc);
|
||||
/* Add the uploaded descriptor to the local service's descriptor cache */
|
||||
rend_cache_store_v2_desc_as_service(enc->desc_str);
|
||||
base32_encode(service_id_base32, sizeof(service_id_base32),
|
||||
service_id, REND_SERVICE_ID_LEN);
|
||||
control_event_hs_descriptor_created(service_id_base32, desc_id_base32, k);
|
||||
}
|
||||
|
||||
log_info(LD_REND, "Successfully encoded a v2 descriptor and "
|
||||
"confirmed that it is parsable.");
|
||||
goto done;
|
||||
|
||||
err:
|
||||
SMARTLIST_FOREACH(descs_out, rend_encoded_v2_service_descriptor_t *, d,
|
||||
rend_encoded_v2_service_descriptor_free(d););
|
||||
smartlist_clear(descs_out);
|
||||
seconds_valid = -1;
|
||||
|
||||
done:
|
||||
tor_free(ipos_base64);
|
||||
return seconds_valid;
|
||||
}
|
||||
|
||||
/** Sets <b>out</b> to the first 10 bytes of the digest of <b>pk</b>,
|
||||
* base32 encoded. NUL-terminates out. (We use this string to
|
||||
* identify services in directory requests and .onion URLs.)
|
||||
*/
|
||||
int
|
||||
rend_get_service_id(crypto_pk_t *pk, char *out)
|
||||
{
|
||||
char buf[DIGEST_LEN];
|
||||
tor_assert(pk);
|
||||
if (crypto_pk_get_digest(pk, buf) < 0)
|
||||
return -1;
|
||||
base32_encode(out, REND_SERVICE_ID_LEN_BASE32+1, buf, REND_SERVICE_ID_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return true iff <b>query</b> is a syntactically valid service ID (as
|
||||
* generated by rend_get_service_id). */
|
||||
int
|
||||
rend_valid_v2_service_id(const char *query)
|
||||
{
|
||||
if (strlen(query) != REND_SERVICE_ID_LEN_BASE32)
|
||||
return 0;
|
||||
|
||||
if (strspn(query, BASE32_CHARS) != REND_SERVICE_ID_LEN_BASE32)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Return true iff <b>query</b> is a syntactically valid descriptor ID.
|
||||
* (as generated by rend_get_descriptor_id_bytes). */
|
||||
int
|
||||
rend_valid_descriptor_id(const char *query)
|
||||
{
|
||||
if (strlen(query) != REND_DESC_ID_V2_LEN_BASE32) {
|
||||
goto invalid;
|
||||
}
|
||||
if (strspn(query, BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
invalid:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return true iff <b>client_name</b> is a syntactically valid name
|
||||
* for rendezvous client authentication. */
|
||||
int
|
||||
rend_valid_client_name(const char *client_name)
|
||||
{
|
||||
size_t len = strlen(client_name);
|
||||
if (len < 1 || len > REND_CLIENTNAME_MAX_LEN) {
|
||||
return 0;
|
||||
}
|
||||
if (strspn(client_name, REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Called when we get a rendezvous-related relay cell on circuit
|
||||
* <b>circ</b>. Dispatch on rendezvous relay command. */
|
||||
@ -842,168 +101,6 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
|
||||
command);
|
||||
}
|
||||
|
||||
/** Determine the routers that are responsible for <b>id</b> (binary) and
|
||||
* add pointers to those routers' routerstatus_t to <b>responsible_dirs</b>.
|
||||
* Return -1 if we're returning an empty smartlist, else return 0.
|
||||
*/
|
||||
int
|
||||
hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
|
||||
const char *id)
|
||||
{
|
||||
int start, found, n_added = 0, i;
|
||||
networkstatus_t *c = networkstatus_get_latest_consensus();
|
||||
if (!c || !smartlist_len(c->routerstatus_list)) {
|
||||
log_info(LD_REND, "We don't have a consensus, so we can't perform v2 "
|
||||
"rendezvous operations.");
|
||||
return -1;
|
||||
}
|
||||
tor_assert(id);
|
||||
start = networkstatus_vote_find_entry_idx(c, id, &found);
|
||||
if (start == smartlist_len(c->routerstatus_list)) start = 0;
|
||||
i = start;
|
||||
do {
|
||||
routerstatus_t *r = smartlist_get(c->routerstatus_list, i);
|
||||
if (r->is_hs_dir) {
|
||||
smartlist_add(responsible_dirs, r);
|
||||
if (++n_added == REND_NUMBER_OF_CONSECUTIVE_REPLICAS)
|
||||
return 0;
|
||||
}
|
||||
if (++i == smartlist_len(c->routerstatus_list))
|
||||
i = 0;
|
||||
} while (i != start);
|
||||
|
||||
/* Even though we don't have the desired number of hidden service
|
||||
* directories, be happy if we got any. */
|
||||
return smartlist_len(responsible_dirs) ? 0 : -1;
|
||||
}
|
||||
|
||||
/* Length of the 'extended' auth cookie used to encode auth type before
|
||||
* base64 encoding. */
|
||||
#define REND_DESC_COOKIE_LEN_EXT (REND_DESC_COOKIE_LEN + 1)
|
||||
/* Length of the zero-padded auth cookie when base64 encoded. These two
|
||||
* padding bytes always (A=) are stripped off of the returned cookie. */
|
||||
#define REND_DESC_COOKIE_LEN_EXT_BASE64 (REND_DESC_COOKIE_LEN_BASE64 + 2)
|
||||
|
||||
/** Encode a client authorization descriptor cookie.
|
||||
* The result of this function is suitable for use in the HidServAuth
|
||||
* option. The trailing padding characters are removed, and the
|
||||
* auth type is encoded into the cookie.
|
||||
*
|
||||
* Returns a new base64-encoded cookie. This function cannot fail.
|
||||
* The caller is responsible for freeing the returned value.
|
||||
*/
|
||||
char *
|
||||
rend_auth_encode_cookie(const uint8_t *cookie_in, rend_auth_type_t auth_type)
|
||||
{
|
||||
uint8_t extended_cookie[REND_DESC_COOKIE_LEN_EXT];
|
||||
char *cookie_out = tor_malloc_zero(REND_DESC_COOKIE_LEN_EXT_BASE64 + 1);
|
||||
int re;
|
||||
|
||||
tor_assert(cookie_in);
|
||||
|
||||
memcpy(extended_cookie, cookie_in, REND_DESC_COOKIE_LEN);
|
||||
extended_cookie[REND_DESC_COOKIE_LEN] = ((int)auth_type - 1) << 4;
|
||||
re = base64_encode(cookie_out, REND_DESC_COOKIE_LEN_EXT_BASE64 + 1,
|
||||
(const char *) extended_cookie, REND_DESC_COOKIE_LEN_EXT,
|
||||
0);
|
||||
tor_assert(re == REND_DESC_COOKIE_LEN_EXT_BASE64);
|
||||
|
||||
/* Remove the trailing 'A='. Auth type is encoded in the high bits
|
||||
* of the last byte, so the last base64 character will always be zero
|
||||
* (A). This is subtly different behavior from base64_encode_nopad. */
|
||||
cookie_out[REND_DESC_COOKIE_LEN_BASE64] = '\0';
|
||||
memwipe(extended_cookie, 0, sizeof(extended_cookie));
|
||||
return cookie_out;
|
||||
}
|
||||
|
||||
/** Decode a base64-encoded client authorization descriptor cookie.
|
||||
* The descriptor_cookie can be truncated to REND_DESC_COOKIE_LEN_BASE64
|
||||
* characters (as given to clients), or may include the two padding
|
||||
* characters (as stored by the service).
|
||||
*
|
||||
* The result is stored in REND_DESC_COOKIE_LEN bytes of cookie_out.
|
||||
* The rend_auth_type_t decoded from the cookie is stored in the
|
||||
* optional auth_type_out parameter.
|
||||
*
|
||||
* Return 0 on success, or -1 on error. The caller is responsible for
|
||||
* freeing the returned err_msg.
|
||||
*/
|
||||
int
|
||||
rend_auth_decode_cookie(const char *cookie_in, uint8_t *cookie_out,
|
||||
rend_auth_type_t *auth_type_out, char **err_msg_out)
|
||||
{
|
||||
uint8_t descriptor_cookie_decoded[REND_DESC_COOKIE_LEN_EXT + 1] = { 0 };
|
||||
char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_EXT_BASE64 + 1];
|
||||
const char *descriptor_cookie = cookie_in;
|
||||
char *err_msg = NULL;
|
||||
int auth_type_val = 0;
|
||||
int res = -1;
|
||||
int decoded_len;
|
||||
|
||||
size_t len = strlen(descriptor_cookie);
|
||||
if (len == REND_DESC_COOKIE_LEN_BASE64) {
|
||||
/* Add a trailing zero byte to make base64-decoding happy. */
|
||||
tor_snprintf(descriptor_cookie_base64ext,
|
||||
sizeof(descriptor_cookie_base64ext),
|
||||
"%sA=", descriptor_cookie);
|
||||
descriptor_cookie = descriptor_cookie_base64ext;
|
||||
} else if (len != REND_DESC_COOKIE_LEN_EXT_BASE64) {
|
||||
tor_asprintf(&err_msg, "Authorization cookie has wrong length: %s",
|
||||
escaped(cookie_in));
|
||||
goto err;
|
||||
}
|
||||
|
||||
decoded_len = base64_decode((char *) descriptor_cookie_decoded,
|
||||
sizeof(descriptor_cookie_decoded),
|
||||
descriptor_cookie,
|
||||
REND_DESC_COOKIE_LEN_EXT_BASE64);
|
||||
if (decoded_len != REND_DESC_COOKIE_LEN &&
|
||||
decoded_len != REND_DESC_COOKIE_LEN_EXT) {
|
||||
tor_asprintf(&err_msg, "Authorization cookie has invalid characters: %s",
|
||||
escaped(cookie_in));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (auth_type_out) {
|
||||
auth_type_val = (descriptor_cookie_decoded[REND_DESC_COOKIE_LEN] >> 4) + 1;
|
||||
if (auth_type_val < 1 || auth_type_val > 2) {
|
||||
tor_asprintf(&err_msg, "Authorization cookie type is unknown: %s",
|
||||
escaped(cookie_in));
|
||||
goto err;
|
||||
}
|
||||
*auth_type_out = auth_type_val == 1 ? REND_BASIC_AUTH : REND_STEALTH_AUTH;
|
||||
}
|
||||
|
||||
memcpy(cookie_out, descriptor_cookie_decoded, REND_DESC_COOKIE_LEN);
|
||||
res = 0;
|
||||
err:
|
||||
if (err_msg_out) {
|
||||
*err_msg_out = err_msg;
|
||||
} else {
|
||||
tor_free(err_msg);
|
||||
}
|
||||
memwipe(descriptor_cookie_decoded, 0, sizeof(descriptor_cookie_decoded));
|
||||
memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext));
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Is this a rend client or server that allows direct (non-anonymous)
|
||||
* connections?
|
||||
* Onion services can be configured to start in this mode for single onion. */
|
||||
int
|
||||
rend_allow_non_anonymous_connection(const or_options_t* options)
|
||||
{
|
||||
return rend_service_allow_non_anonymous_connection(options);
|
||||
}
|
||||
|
||||
/* Is this a rend client or server in non-anonymous mode?
|
||||
* Onion services can be configured to start in this mode for single onion. */
|
||||
int
|
||||
rend_non_anonymous_mode_enabled(const or_options_t *options)
|
||||
{
|
||||
return rend_service_non_anonymous_mode_enabled(options);
|
||||
}
|
||||
|
||||
/* Make sure that tor only builds one-hop circuits when they would not
|
||||
* compromise user anonymity.
|
||||
*
|
||||
@ -1022,35 +119,6 @@ assert_circ_anonymity_ok(const origin_circuit_t *circ,
|
||||
tor_assert(circ->build_state);
|
||||
|
||||
if (circ->build_state->onehop_tunnel) {
|
||||
tor_assert(rend_allow_non_anonymous_connection(options));
|
||||
tor_assert(hs_service_allow_non_anonymous_connection(options));
|
||||
}
|
||||
}
|
||||
|
||||
/* Return 1 iff the given <b>digest</b> of a permenanent hidden service key is
|
||||
* equal to the digest in the origin circuit <b>ocirc</b> of its rend data .
|
||||
* If the rend data doesn't exist, 0 is returned. This function is agnostic to
|
||||
* the rend data version. */
|
||||
int
|
||||
rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc,
|
||||
const uint8_t *digest)
|
||||
{
|
||||
size_t rend_pk_digest_len;
|
||||
const uint8_t *rend_pk_digest;
|
||||
|
||||
tor_assert(ocirc);
|
||||
tor_assert(digest);
|
||||
|
||||
if (ocirc->rend_data == NULL) {
|
||||
goto no_match;
|
||||
}
|
||||
|
||||
rend_pk_digest = rend_data_get_pk_digest(ocirc->rend_data,
|
||||
&rend_pk_digest_len);
|
||||
if (tor_memeq(rend_pk_digest, digest, rend_pk_digest_len)) {
|
||||
goto match;
|
||||
}
|
||||
no_match:
|
||||
return 0;
|
||||
match:
|
||||
return 1;
|
||||
}
|
||||
|
@ -18,65 +18,12 @@ typedef enum rend_intro_point_failure_t {
|
||||
INTRO_POINT_FAILURE_UNREACHABLE = 2,
|
||||
} rend_intro_point_failure_t;
|
||||
|
||||
int rend_cmp_service_ids(const char *one, const char *two);
|
||||
|
||||
void rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
|
||||
int command, size_t length,
|
||||
const uint8_t *payload);
|
||||
|
||||
void rend_service_descriptor_free_(rend_service_descriptor_t *desc);
|
||||
#define rend_service_descriptor_free(desc) \
|
||||
FREE_AND_NULL(rend_service_descriptor_t, rend_service_descriptor_free_, \
|
||||
(desc))
|
||||
int rend_get_service_id(crypto_pk_t *pk, char *out);
|
||||
void rend_encoded_v2_service_descriptor_free_(
|
||||
rend_encoded_v2_service_descriptor_t *desc);
|
||||
#define rend_encoded_v2_service_descriptor_free(desc) \
|
||||
FREE_AND_NULL(rend_encoded_v2_service_descriptor_t, \
|
||||
rend_encoded_v2_service_descriptor_free_, (desc))
|
||||
void rend_intro_point_free_(rend_intro_point_t *intro);
|
||||
#define rend_intro_point_free(intro) \
|
||||
FREE_AND_NULL(rend_intro_point_t, rend_intro_point_free_, (intro))
|
||||
|
||||
int rend_valid_v2_service_id(const char *query);
|
||||
int rend_valid_descriptor_id(const char *query);
|
||||
int rend_valid_client_name(const char *client_name);
|
||||
int rend_encode_v2_descriptors(smartlist_t *descs_out,
|
||||
rend_service_descriptor_t *desc, time_t now,
|
||||
uint8_t period, rend_auth_type_t auth_type,
|
||||
crypto_pk_t *client_key,
|
||||
smartlist_t *client_cookies);
|
||||
int rend_compute_v2_desc_id(char *desc_id_out, const char *service_id,
|
||||
const char *descriptor_cookie,
|
||||
time_t now, uint8_t replica);
|
||||
void rend_get_descriptor_id_bytes(char *descriptor_id_out,
|
||||
const char *service_id,
|
||||
const char *secret_id_part);
|
||||
int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
|
||||
const char *id);
|
||||
|
||||
int rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc,
|
||||
const uint8_t *digest);
|
||||
|
||||
char *rend_auth_encode_cookie(const uint8_t *cookie_in,
|
||||
rend_auth_type_t auth_type);
|
||||
int rend_auth_decode_cookie(const char *cookie_in,
|
||||
uint8_t *cookie_out,
|
||||
rend_auth_type_t *auth_type_out,
|
||||
char **err_msg_out);
|
||||
|
||||
int rend_allow_non_anonymous_connection(const or_options_t* options);
|
||||
int rend_non_anonymous_mode_enabled(const or_options_t *options);
|
||||
|
||||
void assert_circ_anonymity_ok(const origin_circuit_t *circ,
|
||||
const or_options_t *options);
|
||||
|
||||
#ifdef RENDCOMMON_PRIVATE
|
||||
|
||||
STATIC int
|
||||
rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc);
|
||||
|
||||
#endif /* defined(RENDCOMMON_PRIVATE) */
|
||||
|
||||
#endif /* !defined(TOR_RENDCOMMON_H) */
|
||||
|
||||
|
@ -1,612 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file rendparse.c
|
||||
* \brief Code to parse and validate v2 hidden service descriptors.
|
||||
**/
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "core/or/extendinfo.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/dirparse/sigcommon.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
|
||||
#include "core/or/extend_info_st.h"
|
||||
#include "feature/rend/rend_authorized_client_st.h"
|
||||
#include "feature/rend/rend_intro_point_st.h"
|
||||
#include "feature/rend/rend_service_descriptor_st.h"
|
||||
|
||||
/** List of tokens recognized in rendezvous service descriptors */
|
||||
static token_rule_t desc_token_table[] = {
|
||||
T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
|
||||
EQ(1), NO_OBJ),
|
||||
T1("version", R_VERSION, EQ(1), NO_OBJ),
|
||||
T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
|
||||
T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
|
||||
T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
|
||||
T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
|
||||
T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
|
||||
T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** List of tokens recognized in the (encrypted) list of introduction points of
|
||||
* rendezvous service descriptors */
|
||||
static token_rule_t ipo_token_table[] = {
|
||||
T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
|
||||
T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
|
||||
T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
|
||||
T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
|
||||
T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** List of tokens recognized in the (possibly encrypted) list of introduction
|
||||
* points of rendezvous service descriptors */
|
||||
static token_rule_t client_keys_token_table[] = {
|
||||
T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
|
||||
T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
|
||||
T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
|
||||
* write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
|
||||
* binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
|
||||
* encrypted introduction points to the newly allocated
|
||||
* *<b>intro_points_encrypted_out</b>, their encrypted size to
|
||||
* *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor
|
||||
* to *<b>encoded_size_out</b>, and a pointer to the possibly next
|
||||
* descriptor to *<b>next_out</b>; return 0 for success (including validation)
|
||||
* and -1 for failure.
|
||||
*
|
||||
* If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should
|
||||
* be strict about time formats.
|
||||
*/
|
||||
int
|
||||
rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
|
||||
char *desc_id_out,
|
||||
char **intro_points_encrypted_out,
|
||||
size_t *intro_points_encrypted_size_out,
|
||||
size_t *encoded_size_out,
|
||||
const char **next_out, const char *desc,
|
||||
int as_hsdir)
|
||||
{
|
||||
rend_service_descriptor_t *result =
|
||||
tor_malloc_zero(sizeof(rend_service_descriptor_t));
|
||||
char desc_hash[DIGEST_LEN];
|
||||
const char *eos;
|
||||
smartlist_t *tokens = smartlist_new();
|
||||
directory_token_t *tok;
|
||||
char secret_id_part[DIGEST_LEN];
|
||||
int i, version, num_ok=1;
|
||||
smartlist_t *versions;
|
||||
char public_key_hash[DIGEST_LEN];
|
||||
char test_desc_id[DIGEST_LEN];
|
||||
memarea_t *area = NULL;
|
||||
const int strict_time_fmt = as_hsdir;
|
||||
|
||||
tor_assert(desc);
|
||||
/* Check if desc starts correctly. */
|
||||
if (strcmpstart(desc, "rendezvous-service-descriptor ")) {
|
||||
log_info(LD_REND, "Descriptor does not start correctly.");
|
||||
goto err;
|
||||
}
|
||||
/* Compute descriptor hash for later validation. */
|
||||
if (router_get_hash_impl(desc, strlen(desc), desc_hash,
|
||||
"rendezvous-service-descriptor ",
|
||||
"\nsignature", '\n', DIGEST_SHA1) < 0) {
|
||||
log_warn(LD_REND, "Couldn't compute descriptor hash.");
|
||||
goto err;
|
||||
}
|
||||
/* Determine end of string. */
|
||||
eos = strstr(desc, "\nrendezvous-service-descriptor ");
|
||||
if (!eos)
|
||||
eos = desc + strlen(desc);
|
||||
else
|
||||
eos = eos + 1;
|
||||
/* Check length. */
|
||||
if (eos-desc > REND_DESC_MAX_SIZE) {
|
||||
/* XXXX+ If we are parsing this descriptor as a server, this
|
||||
* should be a protocol warning. */
|
||||
log_warn(LD_REND, "Descriptor length is %d which exceeds "
|
||||
"maximum rendezvous descriptor size of %d bytes.",
|
||||
(int)(eos-desc), REND_DESC_MAX_SIZE);
|
||||
goto err;
|
||||
}
|
||||
/* Tokenize descriptor. */
|
||||
area = memarea_new();
|
||||
if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
|
||||
log_warn(LD_REND, "Error tokenizing descriptor.");
|
||||
goto err;
|
||||
}
|
||||
/* Set next to next descriptor, if available. */
|
||||
*next_out = eos;
|
||||
/* Set length of encoded descriptor. */
|
||||
*encoded_size_out = eos - desc;
|
||||
/* Check min allowed length of token list. */
|
||||
if (smartlist_len(tokens) < 7) {
|
||||
log_warn(LD_REND, "Impossibly short descriptor.");
|
||||
goto err;
|
||||
}
|
||||
/* Parse base32-encoded descriptor ID. */
|
||||
tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
|
||||
tor_assert(tok == smartlist_get(tokens, 0));
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (!rend_valid_descriptor_id(tok->args[0])) {
|
||||
log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
if (base32_decode(desc_id_out, DIGEST_LEN,
|
||||
tok->args[0], REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) {
|
||||
log_warn(LD_REND,
|
||||
"Descriptor ID has wrong length or illegal characters: %s",
|
||||
tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
/* Parse descriptor version. */
|
||||
tok = find_by_keyword(tokens, R_VERSION);
|
||||
tor_assert(tok->n_args == 1);
|
||||
result->version =
|
||||
(int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
|
||||
if (result->version != 2 || !num_ok) {
|
||||
/* If it's <2, it shouldn't be under this format. If the number
|
||||
* is greater than 2, we bumped it because we broke backward
|
||||
* compatibility. See how version numbers in our other formats
|
||||
* work. */
|
||||
log_warn(LD_REND, "Unrecognized descriptor version: %s",
|
||||
escaped(tok->args[0]));
|
||||
goto err;
|
||||
}
|
||||
/* Parse public key. */
|
||||
tok = find_by_keyword(tokens, R_PERMANENT_KEY);
|
||||
result->pk = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
/* Parse secret ID part. */
|
||||
tok = find_by_keyword(tokens, R_SECRET_ID_PART);
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
|
||||
strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
|
||||
log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) !=
|
||||
DIGEST_LEN) {
|
||||
log_warn(LD_REND,
|
||||
"Secret ID part has wrong length or illegal characters: %s",
|
||||
tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
/* Parse publication time -- up-to-date check is done when storing the
|
||||
* descriptor. */
|
||||
tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (parse_iso_time_(tok->args[0], &result->timestamp,
|
||||
strict_time_fmt, 0) < 0) {
|
||||
log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
/* Parse protocol versions. */
|
||||
tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
|
||||
tor_assert(tok->n_args == 1);
|
||||
versions = smartlist_new();
|
||||
smartlist_split_string(versions, tok->args[0], ",",
|
||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
for (i = 0; i < smartlist_len(versions); i++) {
|
||||
version = (int) tor_parse_long(smartlist_get(versions, i),
|
||||
10, 0, INT_MAX, &num_ok, NULL);
|
||||
if (!num_ok) /* It's a string; let's ignore it. */
|
||||
continue;
|
||||
if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH)
|
||||
/* Avoid undefined left-shift behaviour. */
|
||||
continue;
|
||||
result->protocols |= 1 << version;
|
||||
}
|
||||
SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
|
||||
smartlist_free(versions);
|
||||
/* Parse encrypted introduction points. Don't verify. */
|
||||
tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
|
||||
if (tok) {
|
||||
if (strcmp(tok->object_type, "MESSAGE")) {
|
||||
log_warn(LD_DIR, "Bad object type: introduction points should be of "
|
||||
"type MESSAGE");
|
||||
goto err;
|
||||
}
|
||||
*intro_points_encrypted_out = tor_memdup(tok->object_body,
|
||||
tok->object_size);
|
||||
*intro_points_encrypted_size_out = tok->object_size;
|
||||
} else {
|
||||
*intro_points_encrypted_out = NULL;
|
||||
*intro_points_encrypted_size_out = 0;
|
||||
}
|
||||
/* Parse and verify signature. */
|
||||
tok = find_by_keyword(tokens, R_SIGNATURE);
|
||||
if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0,
|
||||
"v2 rendezvous service descriptor") < 0)
|
||||
goto err;
|
||||
/* Verify that descriptor ID belongs to public key and secret ID part. */
|
||||
if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) {
|
||||
log_warn(LD_REND, "Unable to compute rend descriptor public key digest");
|
||||
goto err;
|
||||
}
|
||||
rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
|
||||
secret_id_part);
|
||||
if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) {
|
||||
log_warn(LD_REND, "Parsed descriptor ID does not match "
|
||||
"computed descriptor ID.");
|
||||
goto err;
|
||||
}
|
||||
goto done;
|
||||
err:
|
||||
rend_service_descriptor_free(result);
|
||||
result = NULL;
|
||||
done:
|
||||
if (tokens) {
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
}
|
||||
if (area)
|
||||
memarea_drop_all(area);
|
||||
*parsed_out = result;
|
||||
if (result)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of
|
||||
* length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and
|
||||
* write the result to a newly allocated string that is pointed to by
|
||||
* <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>.
|
||||
* Return 0 if decryption was successful and -1 otherwise. */
|
||||
int
|
||||
rend_decrypt_introduction_points(char **ipos_decrypted,
|
||||
size_t *ipos_decrypted_size,
|
||||
const char *descriptor_cookie,
|
||||
const char *ipos_encrypted,
|
||||
size_t ipos_encrypted_size)
|
||||
{
|
||||
tor_assert(ipos_encrypted);
|
||||
tor_assert(descriptor_cookie);
|
||||
if (ipos_encrypted_size < 2) {
|
||||
log_warn(LD_REND, "Size of encrypted introduction points is too "
|
||||
"small.");
|
||||
return -1;
|
||||
}
|
||||
if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) {
|
||||
char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN],
|
||||
session_key[CIPHER_KEY_LEN], *dec;
|
||||
int declen, client_blocks;
|
||||
size_t pos = 0, len, client_entries_len;
|
||||
crypto_digest_t *digest;
|
||||
crypto_cipher_t *cipher;
|
||||
client_blocks = (int) ipos_encrypted[1];
|
||||
client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
|
||||
REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
|
||||
if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) {
|
||||
log_warn(LD_REND, "Size of encrypted introduction points is too "
|
||||
"small.");
|
||||
return -1;
|
||||
}
|
||||
memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN);
|
||||
digest = crypto_digest_new();
|
||||
crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN);
|
||||
crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
|
||||
crypto_digest_get_digest(digest, client_id,
|
||||
REND_BASIC_AUTH_CLIENT_ID_LEN);
|
||||
crypto_digest_free(digest);
|
||||
for (pos = 2; pos < 2 + client_entries_len;
|
||||
pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) {
|
||||
if (tor_memeq(ipos_encrypted + pos, client_id,
|
||||
REND_BASIC_AUTH_CLIENT_ID_LEN)) {
|
||||
/* Attempt to decrypt introduction points. */
|
||||
cipher = crypto_cipher_new(descriptor_cookie);
|
||||
if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
|
||||
+ pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
|
||||
CIPHER_KEY_LEN) < 0) {
|
||||
log_warn(LD_REND, "Could not decrypt session key for client.");
|
||||
crypto_cipher_free(cipher);
|
||||
return -1;
|
||||
}
|
||||
crypto_cipher_free(cipher);
|
||||
|
||||
len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
|
||||
dec = tor_malloc_zero(len + 1);
|
||||
declen = crypto_cipher_decrypt_with_iv(session_key, dec, len,
|
||||
ipos_encrypted + 2 + client_entries_len,
|
||||
ipos_encrypted_size - 2 - client_entries_len);
|
||||
|
||||
if (declen < 0) {
|
||||
log_warn(LD_REND, "Could not decrypt introduction point string.");
|
||||
tor_free(dec);
|
||||
return -1;
|
||||
}
|
||||
if (fast_memcmpstart(dec, declen, "introduction-point ")) {
|
||||
log_warn(LD_REND, "Decrypted introduction points don't "
|
||||
"look like we could parse them.");
|
||||
tor_free(dec);
|
||||
continue;
|
||||
}
|
||||
*ipos_decrypted = dec;
|
||||
*ipos_decrypted_size = declen;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
log_warn(LD_REND, "Could not decrypt introduction points. Please "
|
||||
"check your authorization for this service!");
|
||||
return -1;
|
||||
} else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
|
||||
char *dec;
|
||||
int declen;
|
||||
if (ipos_encrypted_size < CIPHER_IV_LEN + 2) {
|
||||
log_warn(LD_REND, "Size of encrypted introduction points is too "
|
||||
"small.");
|
||||
return -1;
|
||||
}
|
||||
dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1);
|
||||
|
||||
declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec,
|
||||
ipos_encrypted_size -
|
||||
CIPHER_IV_LEN - 1,
|
||||
ipos_encrypted + 1,
|
||||
ipos_encrypted_size - 1);
|
||||
|
||||
if (declen < 0) {
|
||||
log_warn(LD_REND, "Decrypting introduction points failed!");
|
||||
tor_free(dec);
|
||||
return -1;
|
||||
}
|
||||
*ipos_decrypted = dec;
|
||||
*ipos_decrypted_size = declen;
|
||||
return 0;
|
||||
} else {
|
||||
log_warn(LD_REND, "Unknown authorization type number: %d",
|
||||
ipos_encrypted[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse the encoded introduction points in <b>intro_points_encoded</b> of
|
||||
* length <b>intro_points_encoded_size</b> and write the result to the
|
||||
* descriptor in <b>parsed</b>; return the number of successfully parsed
|
||||
* introduction points or -1 in case of a failure. */
|
||||
int
|
||||
rend_parse_introduction_points(rend_service_descriptor_t *parsed,
|
||||
const char *intro_points_encoded,
|
||||
size_t intro_points_encoded_size)
|
||||
{
|
||||
const char *current_ipo, *end_of_intro_points;
|
||||
smartlist_t *tokens = NULL;
|
||||
directory_token_t *tok;
|
||||
rend_intro_point_t *intro;
|
||||
extend_info_t *info;
|
||||
int result, num_ok=1;
|
||||
memarea_t *area = NULL;
|
||||
tor_assert(parsed);
|
||||
/** Function may only be invoked once. */
|
||||
tor_assert(!parsed->intro_nodes);
|
||||
if (!intro_points_encoded || intro_points_encoded_size == 0) {
|
||||
log_warn(LD_REND, "Empty or zero size introduction point list");
|
||||
goto err;
|
||||
}
|
||||
/* Consider one intro point after the other. */
|
||||
current_ipo = intro_points_encoded;
|
||||
end_of_intro_points = intro_points_encoded + intro_points_encoded_size;
|
||||
tokens = smartlist_new();
|
||||
parsed->intro_nodes = smartlist_new();
|
||||
area = memarea_new();
|
||||
|
||||
while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo,
|
||||
"introduction-point ")) {
|
||||
/* Determine end of string. */
|
||||
const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo,
|
||||
"\nintroduction-point ");
|
||||
if (!eos)
|
||||
eos = end_of_intro_points;
|
||||
else
|
||||
eos = eos+1;
|
||||
tor_assert(eos <= intro_points_encoded+intro_points_encoded_size);
|
||||
/* Free tokens and clear token list. */
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_clear(tokens);
|
||||
memarea_clear(area);
|
||||
/* Tokenize string. */
|
||||
if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) {
|
||||
log_warn(LD_REND, "Error tokenizing introduction point");
|
||||
goto err;
|
||||
}
|
||||
/* Advance to next introduction point, if available. */
|
||||
current_ipo = eos;
|
||||
/* Check minimum allowed length of introduction point. */
|
||||
if (smartlist_len(tokens) < 5) {
|
||||
log_warn(LD_REND, "Impossibly short introduction point.");
|
||||
goto err;
|
||||
}
|
||||
/* Allocate new intro point and extend info. */
|
||||
intro = tor_malloc_zero(sizeof(rend_intro_point_t));
|
||||
info = intro->extend_info =
|
||||
extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
|
||||
/* Parse identifier. */
|
||||
tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
|
||||
if (base32_decode(info->identity_digest, DIGEST_LEN,
|
||||
tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) !=
|
||||
DIGEST_LEN) {
|
||||
log_warn(LD_REND,
|
||||
"Identity digest has wrong length or illegal characters: %s",
|
||||
tok->args[0]);
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
/* Write identifier to nickname. */
|
||||
info->nickname[0] = '$';
|
||||
base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
|
||||
info->identity_digest, DIGEST_LEN);
|
||||
/* Parse IP address. */
|
||||
tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
|
||||
tor_addr_t addr;
|
||||
if (tor_addr_parse(&addr, tok->args[0])<0) {
|
||||
log_warn(LD_REND, "Could not parse introduction point address.");
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
if (tor_addr_family(&addr) != AF_INET) {
|
||||
log_warn(LD_REND, "Introduction point address was not ipv4.");
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Parse onion port. */
|
||||
tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
|
||||
uint16_t port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
|
||||
&num_ok,NULL);
|
||||
if (!port || !num_ok) {
|
||||
log_warn(LD_REND, "Introduction point onion port %s is invalid",
|
||||
escaped(tok->args[0]));
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Add the address and port. */
|
||||
extend_info_add_orport(info, &addr, port);
|
||||
|
||||
/* Parse onion key. */
|
||||
tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
|
||||
if (!crypto_pk_public_exponent_ok(tok->key)) {
|
||||
log_warn(LD_REND,
|
||||
"Introduction point's onion key had invalid exponent.");
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
info->onion_key = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
/* Parse service key. */
|
||||
tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
|
||||
if (!crypto_pk_public_exponent_ok(tok->key)) {
|
||||
log_warn(LD_REND,
|
||||
"Introduction point key had invalid exponent.");
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
intro->intro_key = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
/* Add extend info to list of introduction points. */
|
||||
smartlist_add(parsed->intro_nodes, intro);
|
||||
}
|
||||
result = smartlist_len(parsed->intro_nodes);
|
||||
goto done;
|
||||
|
||||
err:
|
||||
result = -1;
|
||||
|
||||
done:
|
||||
/* Free tokens and clear token list. */
|
||||
if (tokens) {
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
}
|
||||
if (area)
|
||||
memarea_drop_all(area);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Parse the content of a client_key file in <b>ckstr</b> and add
|
||||
* rend_authorized_client_t's for each parsed client to
|
||||
* <b>parsed_clients</b>. Return the number of parsed clients as result
|
||||
* or -1 for failure. */
|
||||
int
|
||||
rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
|
||||
{
|
||||
int result = -1;
|
||||
smartlist_t *tokens;
|
||||
directory_token_t *tok;
|
||||
const char *current_entry = NULL;
|
||||
memarea_t *area = NULL;
|
||||
char *err_msg = NULL;
|
||||
if (!ckstr || strlen(ckstr) == 0)
|
||||
return -1;
|
||||
tokens = smartlist_new();
|
||||
/* Begin parsing with first entry, skipping comments or whitespace at the
|
||||
* beginning. */
|
||||
area = memarea_new();
|
||||
current_entry = eat_whitespace(ckstr);
|
||||
while (!strcmpstart(current_entry, "client-name ")) {
|
||||
rend_authorized_client_t *parsed_entry;
|
||||
/* Determine end of string. */
|
||||
const char *eos = strstr(current_entry, "\nclient-name ");
|
||||
if (!eos)
|
||||
eos = current_entry + strlen(current_entry);
|
||||
else
|
||||
eos = eos + 1;
|
||||
/* Free tokens and clear token list. */
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_clear(tokens);
|
||||
memarea_clear(area);
|
||||
/* Tokenize string. */
|
||||
if (tokenize_string(area, current_entry, eos, tokens,
|
||||
client_keys_token_table, 0)) {
|
||||
log_warn(LD_REND, "Error tokenizing client keys file.");
|
||||
goto err;
|
||||
}
|
||||
/* Advance to next entry, if available. */
|
||||
current_entry = eos;
|
||||
/* Check minimum allowed length of token list. */
|
||||
if (smartlist_len(tokens) < 2) {
|
||||
log_warn(LD_REND, "Impossibly short client key entry.");
|
||||
goto err;
|
||||
}
|
||||
/* Parse client name. */
|
||||
tok = find_by_keyword(tokens, C_CLIENT_NAME);
|
||||
tor_assert(tok == smartlist_get(tokens, 0));
|
||||
tor_assert(tok->n_args == 1);
|
||||
|
||||
if (!rend_valid_client_name(tok->args[0])) {
|
||||
log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
|
||||
"between 1 and %d, and valid characters are "
|
||||
"[A-Za-z0-9+-_].)", tok->args[0], REND_CLIENTNAME_MAX_LEN);
|
||||
goto err;
|
||||
}
|
||||
/* Check if client name is duplicate. */
|
||||
if (strmap_get(parsed_clients, tok->args[0])) {
|
||||
log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
|
||||
"duplicate client name: '%s'. Ignoring.", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
|
||||
parsed_entry->client_name = tor_strdup(tok->args[0]);
|
||||
strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
|
||||
/* Parse client key. */
|
||||
tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
|
||||
if (tok) {
|
||||
parsed_entry->client_key = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
}
|
||||
|
||||
/* Parse descriptor cookie. */
|
||||
tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (rend_auth_decode_cookie(tok->args[0], parsed_entry->descriptor_cookie,
|
||||
NULL, &err_msg) < 0) {
|
||||
tor_assert(err_msg);
|
||||
log_warn(LD_REND, "%s", err_msg);
|
||||
tor_free(err_msg);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
result = strmap_size(parsed_clients);
|
||||
goto done;
|
||||
err:
|
||||
result = -1;
|
||||
done:
|
||||
/* Free tokens and clear token list. */
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
if (area)
|
||||
memarea_drop_all(area);
|
||||
return result;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file rendparse.h
|
||||
* \brief Header file for rendparse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_REND_PARSE_H
|
||||
#define TOR_REND_PARSE_H
|
||||
|
||||
int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
|
||||
char *desc_id_out,
|
||||
char **intro_points_encrypted_out,
|
||||
size_t *intro_points_encrypted_size_out,
|
||||
size_t *encoded_size_out,
|
||||
const char **next_out, const char *desc,
|
||||
int as_hsdir);
|
||||
int rend_decrypt_introduction_points(char **ipos_decrypted,
|
||||
size_t *ipos_decrypted_size,
|
||||
const char *descriptor_cookie,
|
||||
const char *ipos_encrypted,
|
||||
size_t ipos_encrypted_size);
|
||||
int rend_parse_introduction_points(rend_service_descriptor_t *parsed,
|
||||
const char *intro_points_encoded,
|
||||
size_t intro_points_encoded_size);
|
||||
int rend_parse_client_keys(strmap_t *parsed_clients, const char *str);
|
||||
|
||||
#endif /* !defined(TOR_REND_PARSE_H) */
|
File diff suppressed because it is too large
Load Diff
@ -1,215 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file rendservice.h
|
||||
* \brief Header file for rendservice.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_RENDSERVICE_H
|
||||
#define TOR_RENDSERVICE_H
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
|
||||
typedef struct rend_intro_cell_t rend_intro_cell_t;
|
||||
struct config_line_t;
|
||||
|
||||
/* This can be used for both INTRODUCE1 and INTRODUCE2 */
|
||||
|
||||
struct rend_intro_cell_t {
|
||||
/* Is this an INTRODUCE1 or INTRODUCE2? (set to 1 or 2) */
|
||||
uint8_t type;
|
||||
/* Public key digest */
|
||||
uint8_t pk[DIGEST_LEN];
|
||||
/* Optionally, store ciphertext here */
|
||||
uint8_t *ciphertext;
|
||||
ssize_t ciphertext_len;
|
||||
/* Optionally, store plaintext */
|
||||
uint8_t *plaintext;
|
||||
ssize_t plaintext_len;
|
||||
/* Have we parsed the plaintext? */
|
||||
uint8_t parsed;
|
||||
/* intro protocol version (0, 1, 2 or 3) */
|
||||
uint8_t version;
|
||||
/* Version-specific parts */
|
||||
union {
|
||||
struct {
|
||||
/* Rendezvous point nickname or hex-encoded key digest */
|
||||
uint8_t rp[42];
|
||||
} v0_v1;
|
||||
struct {
|
||||
/* The extend_info_t struct has everything v2 uses */
|
||||
extend_info_t *extend_info;
|
||||
} v2;
|
||||
struct {
|
||||
/* Auth type used */
|
||||
uint8_t auth_type;
|
||||
/* Length of auth data */
|
||||
uint16_t auth_len;
|
||||
/* Auth data */
|
||||
uint8_t *auth_data;
|
||||
/* Rendezvous point's IP address/port, identity digest and onion key */
|
||||
extend_info_t *extend_info;
|
||||
} v3;
|
||||
} u;
|
||||
/* Rendezvous cookie */
|
||||
uint8_t rc[REND_COOKIE_LEN];
|
||||
/* Diffie-Hellman data */
|
||||
uint8_t dh[DH1024_KEY_LEN];
|
||||
};
|
||||
|
||||
#ifdef RENDSERVICE_PRIVATE
|
||||
|
||||
/** Represents a single hidden service running at this OP. */
|
||||
typedef struct rend_service_t {
|
||||
/* Fields specified in config file */
|
||||
char *directory; /**< where in the filesystem it stores it. Will be NULL if
|
||||
* this service is ephemeral. */
|
||||
int dir_group_readable; /**< if 1, allow group read
|
||||
permissions on directory */
|
||||
smartlist_t *ports; /**< List of hs_port_config_t */
|
||||
rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client
|
||||
* authorization is performed. */
|
||||
smartlist_t *clients; /**< List of rend_authorized_client_t's of
|
||||
* clients that may access our service. Can be NULL
|
||||
* if no client authorization is performed. */
|
||||
/* Other fields */
|
||||
crypto_pk_t *private_key; /**< Permanent hidden-service key. */
|
||||
char service_id[REND_SERVICE_ID_LEN_BASE32+1]; /**< Onion address without
|
||||
* '.onion' */
|
||||
char pk_digest[DIGEST_LEN]; /**< Hash of permanent hidden-service key. */
|
||||
smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have,
|
||||
* or are trying to establish. */
|
||||
/** List of rend_intro_point_t that are expiring. They are removed once
|
||||
* the new descriptor is successfully uploaded. A node in this list CAN
|
||||
* NOT appear in the intro_nodes list. */
|
||||
smartlist_t *expiring_nodes;
|
||||
time_t intro_period_started; /**< Start of the current period to build
|
||||
* introduction points. */
|
||||
int n_intro_circuits_launched; /**< Count of intro circuits we have
|
||||
* established in this period. */
|
||||
unsigned int n_intro_points_wanted; /**< Number of intro points this
|
||||
* service wants to have open. */
|
||||
rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */
|
||||
time_t desc_is_dirty; /**< Time at which changes to the hidden service
|
||||
* descriptor content occurred, or 0 if it's
|
||||
* up-to-date. */
|
||||
time_t next_upload_time; /**< Scheduled next hidden service descriptor
|
||||
* upload time. */
|
||||
/** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, to
|
||||
* detect repeats. Clients may send INTRODUCE1 cells for the same
|
||||
* rendezvous point through two or more different introduction points;
|
||||
* when they do, this keeps us from launching multiple simultaneous attempts
|
||||
* to connect to the same rend point. */
|
||||
replaycache_t *accepted_intro_dh_parts;
|
||||
/** If true, we don't close circuits for making requests to unsupported
|
||||
* ports. */
|
||||
int allow_unknown_ports;
|
||||
/** The maximum number of simultaneous streams-per-circuit that are allowed
|
||||
* to be established, or 0 if no limit is set.
|
||||
*/
|
||||
int max_streams_per_circuit;
|
||||
/** If true, we close circuits that exceed the max_streams_per_circuit
|
||||
* limit. */
|
||||
int max_streams_close_circuit;
|
||||
} rend_service_t;
|
||||
|
||||
STATIC void rend_service_free_(rend_service_t *service);
|
||||
#define rend_service_free(s) \
|
||||
FREE_AND_NULL(rend_service_t, rend_service_free_, (s))
|
||||
STATIC char *rend_service_sos_poison_path(const rend_service_t *service);
|
||||
STATIC int rend_service_verify_single_onion_poison(
|
||||
const rend_service_t *s,
|
||||
const or_options_t *options);
|
||||
STATIC int rend_service_poison_new_single_onion_dir(
|
||||
const rend_service_t *s,
|
||||
const or_options_t* options);
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
|
||||
STATIC void set_rend_service_list(smartlist_t *new_list);
|
||||
STATIC void set_rend_rend_service_staging_list(smartlist_t *new_list);
|
||||
STATIC void rend_service_prune_list_impl_(void);
|
||||
|
||||
#endif /* defined(TOR_UNIT_TESTS) */
|
||||
|
||||
#endif /* defined(RENDSERVICE_PRIVATE) */
|
||||
|
||||
int rend_num_services(void);
|
||||
struct hs_opts_t;
|
||||
int rend_config_service(const struct hs_opts_t *hs_opts,
|
||||
const or_options_t *options,
|
||||
hs_service_config_t *config);
|
||||
void rend_service_prune_list(void);
|
||||
void rend_service_free_staging_list(void);
|
||||
int rend_service_load_all_keys(const smartlist_t *service_list);
|
||||
int rend_service_key_on_disk(const char *directory_path);
|
||||
void rend_services_add_filenames_to_lists(smartlist_t *open_lst,
|
||||
smartlist_t *stat_lst);
|
||||
void rend_consider_services_intro_points(time_t now);
|
||||
void rend_consider_services_upload(time_t now);
|
||||
void rend_hsdir_routers_changed(void);
|
||||
void rend_consider_descriptor_republication(void);
|
||||
|
||||
void rend_service_intro_has_opened(origin_circuit_t *circuit);
|
||||
int rend_service_intro_established(origin_circuit_t *circuit,
|
||||
const uint8_t *request,
|
||||
size_t request_len);
|
||||
void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
|
||||
int rend_service_receive_introduction(origin_circuit_t *circuit,
|
||||
const uint8_t *request,
|
||||
size_t request_len);
|
||||
int rend_service_decrypt_intro(rend_intro_cell_t *request,
|
||||
crypto_pk_t *key,
|
||||
char **err_msg_out);
|
||||
void rend_service_free_intro_(rend_intro_cell_t *request);
|
||||
#define rend_service_free_intro(req) do { \
|
||||
rend_service_free_intro_(req); \
|
||||
(req) = NULL; \
|
||||
} while (0)
|
||||
rend_intro_cell_t * rend_service_begin_parse_intro(const uint8_t *request,
|
||||
size_t request_len,
|
||||
uint8_t type,
|
||||
char **err_msg_out);
|
||||
int rend_service_parse_intro_plaintext(rend_intro_cell_t *intro,
|
||||
char **err_msg_out);
|
||||
ssize_t rend_service_encode_establish_intro_cell(char *cell_body_out,
|
||||
size_t cell_body_out_len,
|
||||
crypto_pk_t *intro_key,
|
||||
const char *rend_circ_nonce);
|
||||
int rend_service_validate_intro_late(const rend_intro_cell_t *intro,
|
||||
char **err_msg_out);
|
||||
void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
|
||||
int rend_service_set_connection_addr_port(edge_connection_t *conn,
|
||||
origin_circuit_t *circ);
|
||||
void rend_service_dump_stats(int severity);
|
||||
void rend_service_free_all(void);
|
||||
void rend_service_init(void);
|
||||
|
||||
void rend_authorized_client_free_(rend_authorized_client_t *client);
|
||||
#define rend_authorized_client_free(client) \
|
||||
FREE_AND_NULL(rend_authorized_client_t, rend_authorized_client_free_, \
|
||||
(client))
|
||||
|
||||
hs_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
|
||||
smartlist_t *ports,
|
||||
int max_streams_per_circuit,
|
||||
int max_streams_close_circuit,
|
||||
rend_auth_type_t auth_type,
|
||||
smartlist_t *auth_clients,
|
||||
char **service_id_out);
|
||||
int rend_service_del_ephemeral(const char *service_id);
|
||||
|
||||
void directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
|
||||
smartlist_t *descs, smartlist_t *hs_dirs,
|
||||
const char *service_id, int seconds_valid);
|
||||
void rend_service_desc_has_uploaded(const rend_data_t *rend_data);
|
||||
|
||||
int rend_service_allow_non_anonymous_connection(const or_options_t *options);
|
||||
int rend_service_reveal_startup_time(const or_options_t *options);
|
||||
int rend_service_non_anonymous_mode_enabled(const or_options_t *options);
|
||||
|
||||
#endif /* !defined(TOR_RENDSERVICE_H) */
|
@ -1,52 +0,0 @@
|
||||
/* Copyright (c) 2016-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
#include "test/fuzz/fuzzing.h"
|
||||
|
||||
static void
|
||||
mock_dump_desc__nodump(const char *desc, const char *type)
|
||||
{
|
||||
(void)desc;
|
||||
(void)type;
|
||||
}
|
||||
|
||||
int
|
||||
fuzz_init(void)
|
||||
{
|
||||
disable_signature_checking();
|
||||
MOCK(dump_desc, mock_dump_desc__nodump);
|
||||
ed25519_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fuzz_cleanup(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fuzz_main(const uint8_t *data, size_t sz)
|
||||
{
|
||||
rend_service_descriptor_t *desc = NULL;
|
||||
char desc_id[64];
|
||||
char *ipts = NULL;
|
||||
size_t ipts_size, esize;
|
||||
const char *next;
|
||||
char *str = tor_memdup_nulterm(data, sz);
|
||||
(void) rend_parse_v2_service_descriptor(&desc, desc_id, &ipts, &ipts_size,
|
||||
&esize, &next, str, 1);
|
||||
if (desc) {
|
||||
log_debug(LD_GENERAL, "Parsing okay");
|
||||
rend_service_descriptor_free(desc);
|
||||
} else {
|
||||
log_debug(LD_GENERAL, "Parsing failed");
|
||||
}
|
||||
tor_free(ipts);
|
||||
tor_free(str);
|
||||
return 0;
|
||||
}
|
@ -83,16 +83,6 @@ src_test_fuzz_fuzz_extrainfo_LDFLAGS = $(FUZZING_LDFLAG)
|
||||
src_test_fuzz_fuzz_extrainfo_LDADD = $(FUZZING_LIBS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_fuzz_hsdescv2_SOURCES = \
|
||||
src/test/fuzz/fuzzing_common.c \
|
||||
src/test/fuzz/fuzz_hsdescv2.c
|
||||
src_test_fuzz_fuzz_hsdescv2_CPPFLAGS = $(FUZZING_CPPFLAGS)
|
||||
src_test_fuzz_fuzz_hsdescv2_CFLAGS = $(FUZZING_CFLAGS)
|
||||
src_test_fuzz_fuzz_hsdescv2_LDFLAGS = $(FUZZING_LDFLAG)
|
||||
src_test_fuzz_fuzz_hsdescv2_LDADD = $(FUZZING_LIBS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_fuzz_hsdescv3_SOURCES = \
|
||||
src/test/fuzz/fuzzing_common.c \
|
||||
@ -123,16 +113,6 @@ src_test_fuzz_fuzz_http_connect_LDFLAGS = $(FUZZING_LDFLAG)
|
||||
src_test_fuzz_fuzz_http_connect_LDADD = $(FUZZING_LIBS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_fuzz_iptsv2_SOURCES = \
|
||||
src/test/fuzz/fuzzing_common.c \
|
||||
src/test/fuzz/fuzz_iptsv2.c
|
||||
src_test_fuzz_fuzz_iptsv2_CPPFLAGS = $(FUZZING_CPPFLAGS)
|
||||
src_test_fuzz_fuzz_iptsv2_CFLAGS = $(FUZZING_CFLAGS)
|
||||
src_test_fuzz_fuzz_iptsv2_LDFLAGS = $(FUZZING_LDFLAG)
|
||||
src_test_fuzz_fuzz_iptsv2_LDADD = $(FUZZING_LIBS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_fuzz_microdesc_SOURCES = \
|
||||
src/test/fuzz/fuzzing_common.c \
|
||||
@ -180,11 +160,9 @@ FUZZERS = \
|
||||
src/test/fuzz/fuzz-diff \
|
||||
src/test/fuzz/fuzz-diff-apply \
|
||||
src/test/fuzz/fuzz-extrainfo \
|
||||
src/test/fuzz/fuzz-hsdescv2 \
|
||||
src/test/fuzz/fuzz-hsdescv3 \
|
||||
src/test/fuzz/fuzz-http \
|
||||
src/test/fuzz/fuzz-http-connect \
|
||||
src/test/fuzz/fuzz-iptsv2 \
|
||||
src/test/fuzz/fuzz-microdesc \
|
||||
src/test/fuzz/fuzz-socks \
|
||||
src/test/fuzz/fuzz-strops \
|
||||
@ -239,15 +217,6 @@ src_test_fuzz_lf_fuzz_extrainfo_LDFLAGS = $(LIBFUZZER_LDFLAG)
|
||||
src_test_fuzz_lf_fuzz_extrainfo_LDADD = $(LIBFUZZER_LIBS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_lf_fuzz_hsdescv2_SOURCES = \
|
||||
$(src_test_fuzz_fuzz_hsdescv2_SOURCES)
|
||||
src_test_fuzz_lf_fuzz_hsdescv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
|
||||
src_test_fuzz_lf_fuzz_hsdescv2_CFLAGS = $(LIBFUZZER_CFLAGS)
|
||||
src_test_fuzz_lf_fuzz_hsdescv2_LDFLAGS = $(LIBFUZZER_LDFLAG)
|
||||
src_test_fuzz_lf_fuzz_hsdescv2_LDADD = $(LIBFUZZER_LIBS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_lf_fuzz_hsdescv3_SOURCES = \
|
||||
$(src_test_fuzz_fuzz_hsdescv3_SOURCES)
|
||||
@ -275,15 +244,6 @@ src_test_fuzz_lf_fuzz_http_connect_LDFLAGS = $(LIBFUZZER_LDFLAG)
|
||||
src_test_fuzz_lf_fuzz_http_connect_LDADD = $(LIBFUZZER_LIBS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_lf_fuzz_iptsv2_SOURCES = \
|
||||
$(src_test_fuzz_fuzz_iptsv2_SOURCES)
|
||||
src_test_fuzz_lf_fuzz_iptsv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
|
||||
src_test_fuzz_lf_fuzz_iptsv2_CFLAGS = $(LIBFUZZER_CFLAGS)
|
||||
src_test_fuzz_lf_fuzz_iptsv2_LDFLAGS = $(LIBFUZZER_LDFLAG)
|
||||
src_test_fuzz_lf_fuzz_iptsv2_LDADD = $(LIBFUZZER_LIBS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_lf_fuzz_microdesc_SOURCES = \
|
||||
$(src_test_fuzz_fuzz_microdesc_SOURCES)
|
||||
@ -326,11 +286,9 @@ LIBFUZZER_FUZZERS = \
|
||||
src/test/fuzz/lf-fuzz-diff \
|
||||
src/test/fuzz/lf-fuzz-diff-apply \
|
||||
src/test/fuzz/lf-fuzz-extrainfo \
|
||||
src/test/fuzz/lf-fuzz-hsdescv2 \
|
||||
src/test/fuzz/lf-fuzz-hsdescv3 \
|
||||
src/test/fuzz/lf-fuzz-http \
|
||||
src/test/fuzz/lf-fuzz-http-connect \
|
||||
src/test/fuzz/lf-fuzz-iptsv2 \
|
||||
src/test/fuzz/lf-fuzz-microdesc \
|
||||
src/test/fuzz/lf-fuzz-socks \
|
||||
src/test/fuzz/lf-fuzz-strops \
|
||||
@ -378,13 +336,6 @@ src_test_fuzz_liboss_fuzz_extrainfo_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
|
||||
src_test_fuzz_liboss_fuzz_extrainfo_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_liboss_fuzz_hsdescv2_a_SOURCES = \
|
||||
$(src_test_fuzz_fuzz_hsdescv2_SOURCES)
|
||||
src_test_fuzz_liboss_fuzz_hsdescv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
|
||||
src_test_fuzz_liboss_fuzz_hsdescv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_liboss_fuzz_hsdescv3_a_SOURCES = \
|
||||
$(src_test_fuzz_fuzz_hsdescv3_SOURCES)
|
||||
@ -406,13 +357,6 @@ src_test_fuzz_liboss_fuzz_http_connect_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
|
||||
src_test_fuzz_liboss_fuzz_http_connect_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_liboss_fuzz_iptsv2_a_SOURCES = \
|
||||
$(src_test_fuzz_fuzz_iptsv2_SOURCES)
|
||||
src_test_fuzz_liboss_fuzz_iptsv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
|
||||
src_test_fuzz_liboss_fuzz_iptsv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
|
||||
endif
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
src_test_fuzz_liboss_fuzz_microdesc_a_SOURCES = \
|
||||
$(src_test_fuzz_fuzz_microdesc_SOURCES)
|
||||
@ -447,11 +391,9 @@ OSS_FUZZ_FUZZERS = \
|
||||
src/test/fuzz/liboss-fuzz-diff.a \
|
||||
src/test/fuzz/liboss-fuzz-diff-apply.a \
|
||||
src/test/fuzz/liboss-fuzz-extrainfo.a \
|
||||
src/test/fuzz/liboss-fuzz-hsdescv2.a \
|
||||
src/test/fuzz/liboss-fuzz-hsdescv3.a \
|
||||
src/test/fuzz/liboss-fuzz-http.a \
|
||||
src/test/fuzz/liboss-fuzz-http-connect.a \
|
||||
src/test/fuzz/liboss-fuzz-iptsv2.a \
|
||||
src/test/fuzz/liboss-fuzz-microdesc.a \
|
||||
src/test/fuzz/liboss-fuzz-socks.a \
|
||||
src/test/fuzz/liboss-fuzz-strops.a \
|
||||
|
@ -130,7 +130,6 @@ src_test_test_SOURCES += \
|
||||
src/test/log_test_helpers.c \
|
||||
src/test/hs_test_helpers.c \
|
||||
src/test/opts_test_helpers.c \
|
||||
src/test/rend_test_helpers.c \
|
||||
src/test/resolve_test_helpers.c \
|
||||
src/test/rng_test_helpers.c \
|
||||
src/test/test.c \
|
||||
@ -181,7 +180,6 @@ src_test_test_SOURCES += \
|
||||
src/test/test_geoip.c \
|
||||
src/test/test_guardfraction.c \
|
||||
src/test/test_extorport.c \
|
||||
src/test/test_hs.c \
|
||||
src/test/test_hs_common.c \
|
||||
src/test/test_hs_config.c \
|
||||
src/test/test_hs_cell.c \
|
||||
@ -196,7 +194,6 @@ src_test_test_SOURCES += \
|
||||
src/test/test_hs_descriptor.c \
|
||||
src/test/test_hs_dos.c \
|
||||
src/test/test_hs_metrics.c \
|
||||
src/test/test_introduce.c \
|
||||
src/test/test_keypin.c \
|
||||
src/test/test_link_handshake.c \
|
||||
src/test/test_logging.c \
|
||||
@ -227,7 +224,6 @@ src_test_test_SOURCES += \
|
||||
src/test/test_relay.c \
|
||||
src/test/test_relaycell.c \
|
||||
src/test/test_relaycrypt.c \
|
||||
src/test/test_rendcache.c \
|
||||
src/test/test_replay.c \
|
||||
src/test/test_router.c \
|
||||
src/test/test_routerkeys.c \
|
||||
@ -380,7 +376,6 @@ noinst_HEADERS+= \
|
||||
src/test/hs_test_helpers.h \
|
||||
src/test/log_test_helpers.h \
|
||||
src/test/opts_test_helpers.h \
|
||||
src/test/rend_test_helpers.h \
|
||||
src/test/resolve_test_helpers.h \
|
||||
src/test/rng_test_helpers.h \
|
||||
src/test/test.h \
|
||||
|
@ -1,99 +0,0 @@
|
||||
/* Copyright (c) 2014-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "core/or/extendinfo.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "test/test.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "test/rend_test_helpers.h"
|
||||
|
||||
#include "core/or/extend_info_st.h"
|
||||
#include "feature/rend/rend_intro_point_st.h"
|
||||
#include "feature/rend/rend_service_descriptor_st.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);
|
||||
tor_assert(smartlist_len(descs) > 1);
|
||||
*desc = smartlist_get(descs, 0);
|
||||
smartlist_set(descs, 0, NULL);
|
||||
|
||||
SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d,
|
||||
rend_encoded_v2_service_descriptor_free(d));
|
||||
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 =
|
||||
extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
|
||||
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_t addr;
|
||||
uint16_t port;
|
||||
/* Does not cover all IP addresses. */
|
||||
tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
|
||||
port = 1 + crypto_rand_int(65535);
|
||||
extend_info_add_orport(intro->extend_info, &addr, port);
|
||||
intro->intro_key = crypto_pk_dup_key(pk2);
|
||||
smartlist_add((*generated)->intro_nodes, intro);
|
||||
}
|
||||
|
||||
crypto_pk_free(pk1);
|
||||
crypto_pk_free(pk2);
|
||||
}
|
||||
|
||||
rend_data_t *
|
||||
mock_rend_data(const char *onion_address)
|
||||
{
|
||||
rend_data_v2_t *v2_data = tor_malloc_zero(sizeof(*v2_data));
|
||||
rend_data_t *rend_query = &v2_data->base_;
|
||||
rend_query->version = 2;
|
||||
|
||||
strlcpy(v2_data->onion_address, onion_address,
|
||||
sizeof(v2_data->onion_address));
|
||||
v2_data->auth_type = REND_NO_AUTH;
|
||||
rend_query->hsdirs_fp = smartlist_new();
|
||||
smartlist_add(rend_query->hsdirs_fp, tor_memdup("aaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
DIGEST_LEN));
|
||||
return rend_query;
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
/* Copyright (c) 2014-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "core/or/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);
|
||||
rend_data_t *mock_rend_data(const char *onion_address);
|
||||
|
||||
#endif /* !defined(TOR_REND_TEST_HELPERS_H) */
|
||||
|
131
src/test/test.c
131
src/test/test.c
@ -45,9 +45,6 @@
|
||||
#include "app/config/config.h"
|
||||
#include "core/or/connection_edge.h"
|
||||
#include "core/or/extendinfo.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "test/test.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
@ -62,9 +59,6 @@
|
||||
|
||||
#include "core/or/extend_info_st.h"
|
||||
#include "core/or/or_circuit_st.h"
|
||||
#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
|
||||
#include "feature/rend/rend_intro_point_st.h"
|
||||
#include "feature/rend/rend_service_descriptor_st.h"
|
||||
#include "feature/relay/onion_queue.h"
|
||||
|
||||
/** Run unit tests for the onion handshake code. */
|
||||
@ -619,127 +613,6 @@ test_circuit_timeout(void *arg)
|
||||
testing_disable_deterministic_rng();
|
||||
}
|
||||
|
||||
/** Test encoding and parsing of rendezvous service descriptors. */
|
||||
static void
|
||||
test_rend_fns(void *arg)
|
||||
{
|
||||
rend_service_descriptor_t *generated = NULL, *parsed = NULL;
|
||||
char service_id[DIGEST_LEN];
|
||||
char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1];
|
||||
const char *next_desc;
|
||||
smartlist_t *descs = smartlist_new();
|
||||
char computed_desc_id[DIGEST_LEN];
|
||||
char parsed_desc_id[DIGEST_LEN];
|
||||
crypto_pk_t *pk1 = NULL, *pk2 = NULL;
|
||||
time_t now;
|
||||
char *intro_points_encrypted = NULL;
|
||||
size_t intro_points_size;
|
||||
size_t encoded_size;
|
||||
int i;
|
||||
|
||||
(void)arg;
|
||||
|
||||
/* Initialize the service cache. */
|
||||
rend_cache_init();
|
||||
|
||||
pk1 = pk_generate(0);
|
||||
pk2 = pk_generate(1);
|
||||
generated = tor_malloc_zero(sizeof(rend_service_descriptor_t));
|
||||
generated->pk = crypto_pk_dup_key(pk1);
|
||||
crypto_pk_get_digest(generated->pk, service_id);
|
||||
base32_encode(service_id_base32, REND_SERVICE_ID_LEN_BASE32+1,
|
||||
service_id, REND_SERVICE_ID_LEN);
|
||||
now = time(NULL);
|
||||
generated->timestamp = now;
|
||||
generated->version = 2;
|
||||
generated->protocols = 42;
|
||||
generated->intro_nodes = smartlist_new();
|
||||
|
||||
for (i = 0; i < 3; 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 =
|
||||
extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
|
||||
intro->extend_info->onion_key = okey;
|
||||
crypto_pk_get_digest(intro->extend_info->onion_key,
|
||||
intro->extend_info->identity_digest);
|
||||
//crypto_rand(info->identity_digest, DIGEST_LEN); /* Would this work? */
|
||||
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_t addr;
|
||||
uint16_t port;
|
||||
/* Does not cover all IP addresses. */
|
||||
tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
|
||||
port = 1 + crypto_rand_int(65535);
|
||||
extend_info_add_orport(intro->extend_info, &addr, port);
|
||||
intro->intro_key = crypto_pk_dup_key(pk2);
|
||||
smartlist_add(generated->intro_nodes, intro);
|
||||
}
|
||||
int rv = rend_encode_v2_descriptors(descs, generated, now, 0,
|
||||
REND_NO_AUTH, NULL, NULL);
|
||||
tt_int_op(rv, OP_GT, 0);
|
||||
rv = rend_compute_v2_desc_id(computed_desc_id, service_id_base32, NULL,
|
||||
now, 0);
|
||||
tt_int_op(rv, OP_EQ, 0);
|
||||
tt_mem_op(((rend_encoded_v2_service_descriptor_t *)
|
||||
smartlist_get(descs, 0))->desc_id, OP_EQ,
|
||||
computed_desc_id, DIGEST_LEN);
|
||||
rv = rend_parse_v2_service_descriptor(&parsed, parsed_desc_id,
|
||||
&intro_points_encrypted, &intro_points_size, &encoded_size,
|
||||
&next_desc,
|
||||
((rend_encoded_v2_service_descriptor_t *)smartlist_get(descs, 0))
|
||||
->desc_str, 1);
|
||||
tt_int_op(rv, OP_EQ, 0);
|
||||
tt_assert(parsed);
|
||||
tt_mem_op(((rend_encoded_v2_service_descriptor_t *)
|
||||
smartlist_get(descs, 0))->desc_id,OP_EQ, parsed_desc_id, DIGEST_LEN);
|
||||
tt_int_op(rend_parse_introduction_points(parsed, intro_points_encrypted,
|
||||
intro_points_size),OP_EQ, 3);
|
||||
tt_assert(!crypto_pk_cmp_keys(generated->pk, parsed->pk));
|
||||
tt_int_op(parsed->timestamp,OP_EQ, now);
|
||||
tt_int_op(parsed->version,OP_EQ, 2);
|
||||
tt_int_op(parsed->protocols,OP_EQ, 42);
|
||||
tt_int_op(smartlist_len(parsed->intro_nodes),OP_EQ, 3);
|
||||
for (i = 0; i < smartlist_len(parsed->intro_nodes); i++) {
|
||||
rend_intro_point_t *par_intro = smartlist_get(parsed->intro_nodes, i),
|
||||
*gen_intro = smartlist_get(generated->intro_nodes, i);
|
||||
extend_info_t *par_info = par_intro->extend_info;
|
||||
extend_info_t *gen_info = gen_intro->extend_info;
|
||||
tt_assert(!crypto_pk_cmp_keys(gen_info->onion_key, par_info->onion_key));
|
||||
tt_mem_op(gen_info->identity_digest,OP_EQ, par_info->identity_digest,
|
||||
DIGEST_LEN);
|
||||
tt_str_op(gen_info->nickname,OP_EQ, par_info->nickname);
|
||||
const tor_addr_port_t *a1, *a2;
|
||||
a1 = extend_info_get_orport(gen_info, AF_INET);
|
||||
a2 = extend_info_get_orport(par_info, AF_INET);
|
||||
tt_assert(a1 && a2);
|
||||
tt_assert(tor_addr_eq(&a1->addr, &a2->addr));
|
||||
tt_int_op(a2->port,OP_EQ, a2->port);
|
||||
}
|
||||
|
||||
rend_service_descriptor_free(parsed);
|
||||
rend_service_descriptor_free(generated);
|
||||
parsed = generated = NULL;
|
||||
|
||||
done:
|
||||
if (descs) {
|
||||
for (i = 0; i < smartlist_len(descs); i++)
|
||||
rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i));
|
||||
smartlist_free(descs);
|
||||
}
|
||||
if (parsed)
|
||||
rend_service_descriptor_free(parsed);
|
||||
if (generated)
|
||||
rend_service_descriptor_free(generated);
|
||||
if (pk1)
|
||||
crypto_pk_free(pk1);
|
||||
if (pk2)
|
||||
crypto_pk_free(pk2);
|
||||
tor_free(intro_points_encrypted);
|
||||
}
|
||||
|
||||
#define ENT(name) \
|
||||
{ #name, test_ ## name , 0, NULL, NULL }
|
||||
#define FORK(name) \
|
||||
@ -753,7 +626,6 @@ static struct testcase_t test_array[] = {
|
||||
{ "fast_handshake", test_fast_handshake, 0, NULL, NULL },
|
||||
FORK(circuit_timeout),
|
||||
FORK(circuit_timeout_xm_alpha),
|
||||
FORK(rend_fns),
|
||||
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
@ -828,9 +700,7 @@ struct testgroup_t testgroups[] = {
|
||||
{ "hs_ntor/", hs_ntor_tests },
|
||||
{ "hs_ob/", hs_ob_tests },
|
||||
{ "hs_service/", hs_service_tests },
|
||||
{ "introduce/", introduce_tests },
|
||||
{ "keypin/", keypin_tests },
|
||||
{ "legacy_hs/", hs_tests },
|
||||
{ "link-handshake/", link_handshake_tests },
|
||||
{ "mainloop/", mainloop_tests },
|
||||
{ "metrics/", metrics_tests },
|
||||
@ -856,7 +726,6 @@ struct testgroup_t testgroups[] = {
|
||||
{ "relay/" , relay_tests },
|
||||
{ "relaycell/", relaycell_tests },
|
||||
{ "relaycrypt/", relaycrypt_tests },
|
||||
{ "rend_cache/", rend_cache_tests },
|
||||
{ "replaycache/", replaycache_tests },
|
||||
{ "router/", router_tests },
|
||||
{ "routerkeys/", routerkeys_tests },
|
||||
|
@ -145,8 +145,6 @@ extern struct testcase_t hs_metrics_tests[];
|
||||
extern struct testcase_t hs_ntor_tests[];
|
||||
extern struct testcase_t hs_ob_tests[];
|
||||
extern struct testcase_t hs_service_tests[];
|
||||
extern struct testcase_t hs_tests[];
|
||||
extern struct testcase_t introduce_tests[];
|
||||
extern struct testcase_t keypin_tests[];
|
||||
extern struct testcase_t link_handshake_tests[];
|
||||
extern struct testcase_t logging_tests[];
|
||||
@ -179,7 +177,6 @@ extern struct testcase_t pubsub_msg_tests[];
|
||||
extern struct testcase_t relay_tests[];
|
||||
extern struct testcase_t relaycell_tests[];
|
||||
extern struct testcase_t relaycrypt_tests[];
|
||||
extern struct testcase_t rend_cache_tests[];
|
||||
extern struct testcase_t replaycache_tests[];
|
||||
extern struct testcase_t router_tests[];
|
||||
extern struct testcase_t routerkeys_tests[];
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/relay/relay_find_addr.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "core/or/connection_or.h"
|
||||
#include "lib/net/resolve.h"
|
||||
@ -38,10 +37,6 @@ static void * test_conn_get_basic_setup(const struct testcase_t *tc);
|
||||
static int test_conn_get_basic_teardown(const struct testcase_t *tc,
|
||||
void *arg);
|
||||
|
||||
static void * test_conn_get_rend_setup(const struct testcase_t *tc);
|
||||
static int test_conn_get_rend_teardown(const struct testcase_t *tc,
|
||||
void *arg);
|
||||
|
||||
static void * test_conn_get_rsrc_setup(const struct testcase_t *tc);
|
||||
static int test_conn_get_rsrc_teardown(const struct testcase_t *tc,
|
||||
void *arg);
|
||||
@ -179,52 +174,6 @@ test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_conn_get_rend_setup(const struct testcase_t *tc)
|
||||
{
|
||||
dir_connection_t *conn = DOWNCAST(dir_connection_t,
|
||||
test_conn_get_connection(
|
||||
TEST_CONN_STATE,
|
||||
TEST_CONN_TYPE,
|
||||
TEST_CONN_REND_PURPOSE));
|
||||
tt_assert(conn);
|
||||
assert_connection_ok(&conn->base_, time(NULL));
|
||||
|
||||
rend_cache_init();
|
||||
|
||||
/* TODO: use directory_initiate_request() to do this - maybe? */
|
||||
tor_assert(strlen(TEST_CONN_REND_ADDR) == REND_SERVICE_ID_LEN_BASE32);
|
||||
conn->rend_data = rend_data_client_create(TEST_CONN_REND_ADDR, NULL, NULL,
|
||||
REND_NO_AUTH);
|
||||
assert_connection_ok(&conn->base_, time(NULL));
|
||||
return conn;
|
||||
|
||||
/* On failure */
|
||||
done:
|
||||
test_conn_get_rend_teardown(tc, conn);
|
||||
/* Returning NULL causes the unit test to fail */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
test_conn_get_rend_teardown(const struct testcase_t *tc, void *arg)
|
||||
{
|
||||
dir_connection_t *conn = DOWNCAST(dir_connection_t, arg);
|
||||
int rv = 0;
|
||||
|
||||
tt_assert(conn);
|
||||
assert_connection_ok(&conn->base_, time(NULL));
|
||||
|
||||
/* avoid a last-ditch attempt to refetch the descriptor */
|
||||
conn->base_.purpose = TEST_CONN_REND_PURPOSE_SUCCESSFUL;
|
||||
|
||||
/* connection_free_() cleans up rend_data */
|
||||
rv = test_conn_get_basic_teardown(tc, arg);
|
||||
done:
|
||||
rend_cache_free_all();
|
||||
return rv;
|
||||
}
|
||||
|
||||
static dir_connection_t *
|
||||
test_conn_download_status_add_a_connection(const char *resource)
|
||||
{
|
||||
@ -369,10 +318,6 @@ static struct testcase_setup_t test_conn_get_basic_st = {
|
||||
test_conn_get_basic_setup, test_conn_get_basic_teardown
|
||||
};
|
||||
|
||||
static struct testcase_setup_t test_conn_get_rend_st = {
|
||||
test_conn_get_rend_setup, test_conn_get_rend_teardown
|
||||
};
|
||||
|
||||
static struct testcase_setup_t test_conn_get_rsrc_st = {
|
||||
test_conn_get_rsrc_setup, test_conn_get_rsrc_teardown
|
||||
};
|
||||
@ -489,37 +434,6 @@ test_conn_get_basic(void *arg)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_conn_get_rend(void *arg)
|
||||
{
|
||||
dir_connection_t *conn = DOWNCAST(dir_connection_t, arg);
|
||||
tt_assert(conn);
|
||||
assert_connection_ok(&conn->base_, time(NULL));
|
||||
|
||||
tt_assert(connection_get_by_type_state_rendquery(
|
||||
conn->base_.type,
|
||||
conn->base_.state,
|
||||
rend_data_get_address(
|
||||
conn->rend_data))
|
||||
== TO_CONN(conn));
|
||||
tt_assert(connection_get_by_type_state_rendquery(
|
||||
TEST_CONN_TYPE,
|
||||
TEST_CONN_STATE,
|
||||
TEST_CONN_REND_ADDR)
|
||||
== TO_CONN(conn));
|
||||
tt_assert(connection_get_by_type_state_rendquery(TEST_CONN_REND_TYPE_2,
|
||||
!conn->base_.state,
|
||||
"")
|
||||
== NULL);
|
||||
tt_assert(connection_get_by_type_state_rendquery(TEST_CONN_REND_TYPE_2,
|
||||
!TEST_CONN_STATE,
|
||||
TEST_CONN_REND_ADDR_2)
|
||||
== NULL);
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
#define sl_is_conn_assert(sl_input, conn) \
|
||||
do { \
|
||||
the_sl = (sl_input); \
|
||||
@ -1091,7 +1005,6 @@ static const unsigned int PROXY_HAPROXY_ARG = PROXY_HAPROXY;
|
||||
|
||||
struct testcase_t connection_tests[] = {
|
||||
CONNECTION_TESTCASE(get_basic, TT_FORK, test_conn_get_basic_st),
|
||||
CONNECTION_TESTCASE(get_rend, TT_FORK, test_conn_get_rend_st),
|
||||
CONNECTION_TESTCASE(get_rsrc, TT_FORK, test_conn_get_rsrc_st),
|
||||
|
||||
CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "feature/dircache/dirserv.h"
|
||||
#include "feature/hs/hs_common.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
@ -316,110 +315,6 @@ test_add_onion_helper_keyarg_v3(void *arg)
|
||||
UNMOCK(control_write_reply);
|
||||
}
|
||||
|
||||
static void
|
||||
test_add_onion_helper_keyarg_v2(void *arg)
|
||||
{
|
||||
int ret, hs_version;
|
||||
add_onion_secret_key_t pk;
|
||||
crypto_pk_t *pk1 = NULL;
|
||||
const char *key_new_alg = NULL;
|
||||
char *key_new_blob = NULL;
|
||||
char *encoded = NULL;
|
||||
char *arg_str = NULL;
|
||||
|
||||
(void) arg;
|
||||
MOCK(control_write_reply, mock_control_write_reply);
|
||||
|
||||
memset(&pk, 0, sizeof(pk));
|
||||
|
||||
/* Test explicit RSA1024 key generation. */
|
||||
tor_free(reply_str);
|
||||
ret = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob,
|
||||
&pk, &hs_version, NULL);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
|
||||
tt_assert(pk.v2);
|
||||
tt_str_op(key_new_alg, OP_EQ, "RSA1024");
|
||||
tt_assert(key_new_blob);
|
||||
tt_ptr_op(reply_str, OP_EQ, NULL);
|
||||
|
||||
/* Test discarding the private key. */
|
||||
crypto_pk_free(pk.v2); pk.v2 = NULL;
|
||||
tor_free(key_new_blob);
|
||||
ret = add_onion_helper_keyarg("NEW:RSA1024", 1, &key_new_alg, &key_new_blob,
|
||||
&pk, &hs_version, NULL);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
|
||||
tt_assert(pk.v2);
|
||||
tt_ptr_op(key_new_alg, OP_EQ, NULL);
|
||||
tt_ptr_op(key_new_blob, OP_EQ, NULL);
|
||||
tt_ptr_op(reply_str, OP_EQ, NULL);
|
||||
|
||||
/* Test generating a invalid key type. */
|
||||
crypto_pk_free(pk.v2); pk.v2 = NULL;
|
||||
ret = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob,
|
||||
&pk, &hs_version, NULL);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
|
||||
tt_assert(!pk.v2);
|
||||
tt_ptr_op(key_new_alg, OP_EQ, NULL);
|
||||
tt_ptr_op(key_new_blob, OP_EQ, NULL);
|
||||
tt_assert(reply_str);
|
||||
|
||||
/* Test loading a RSA1024 key. */
|
||||
tor_free(reply_str);
|
||||
pk1 = pk_generate(0);
|
||||
tt_int_op(0, OP_EQ, crypto_pk_base64_encode_private(pk1, &encoded));
|
||||
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
|
||||
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
|
||||
&pk, &hs_version, NULL);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
|
||||
tt_assert(pk.v2);
|
||||
tt_ptr_op(key_new_alg, OP_EQ, NULL);
|
||||
tt_ptr_op(key_new_blob, OP_EQ, NULL);
|
||||
tt_ptr_op(reply_str, OP_EQ, NULL);
|
||||
tt_int_op(crypto_pk_cmp_keys(pk1, pk.v2), OP_EQ, 0);
|
||||
|
||||
/* Test loading a invalid key type. */
|
||||
tor_free(arg_str);
|
||||
crypto_pk_free(pk1); pk1 = NULL;
|
||||
crypto_pk_free(pk.v2); pk.v2 = NULL;
|
||||
tor_asprintf(&arg_str, "RSA512:%s", encoded);
|
||||
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
|
||||
&pk, &hs_version, NULL);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
|
||||
tt_assert(!pk.v2);
|
||||
tt_ptr_op(key_new_alg, OP_EQ, NULL);
|
||||
tt_ptr_op(key_new_blob, OP_EQ, NULL);
|
||||
tt_assert(reply_str);
|
||||
|
||||
/* Test loading a invalid key. */
|
||||
tor_free(arg_str);
|
||||
crypto_pk_free(pk.v2); pk.v2 = NULL;
|
||||
tor_free(reply_str);
|
||||
encoded[strlen(encoded)/2] = '\0';
|
||||
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
|
||||
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
|
||||
&pk, &hs_version, NULL);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
|
||||
tt_assert(!pk.v2);
|
||||
tt_ptr_op(key_new_alg, OP_EQ, NULL);
|
||||
tt_ptr_op(key_new_blob, OP_EQ, NULL);
|
||||
tt_assert(reply_str);
|
||||
|
||||
done:
|
||||
crypto_pk_free(pk1);
|
||||
crypto_pk_free(pk.v2);
|
||||
tor_free(key_new_blob);
|
||||
tor_free(reply_str);
|
||||
tor_free(encoded);
|
||||
tor_free(arg_str);
|
||||
UNMOCK(control_write_reply);
|
||||
}
|
||||
|
||||
static void
|
||||
test_getinfo_helper_onion(void *arg)
|
||||
{
|
||||
@ -567,58 +462,6 @@ test_hs_parse_port_config(void *arg)
|
||||
tor_free(err_msg);
|
||||
}
|
||||
|
||||
static void
|
||||
test_add_onion_helper_clientauth(void *arg)
|
||||
{
|
||||
rend_authorized_client_t *client = NULL;
|
||||
int created = 0;
|
||||
|
||||
(void)arg;
|
||||
|
||||
MOCK(control_write_reply, mock_control_write_reply);
|
||||
/* Test "ClientName" only. */
|
||||
tor_free(reply_str);
|
||||
client = add_onion_helper_clientauth("alice", &created, NULL);
|
||||
tt_assert(client);
|
||||
tt_assert(created);
|
||||
tt_ptr_op(reply_str, OP_EQ, NULL);
|
||||
rend_authorized_client_free(client);
|
||||
|
||||
/* Test "ClientName:Blob" */
|
||||
tor_free(reply_str);
|
||||
client = add_onion_helper_clientauth("alice:475hGBHPlq7Mc0cRZitK/B",
|
||||
&created, NULL);
|
||||
tt_assert(client);
|
||||
tt_assert(!created);
|
||||
tt_ptr_op(reply_str, OP_EQ, NULL);
|
||||
rend_authorized_client_free(client);
|
||||
|
||||
/* Test invalid client names */
|
||||
tor_free(reply_str);
|
||||
client = add_onion_helper_clientauth("no*asterisks*allowed", &created,
|
||||
NULL);
|
||||
tt_ptr_op(client, OP_EQ, NULL);
|
||||
tt_assert(reply_str);
|
||||
|
||||
/* Test invalid auth cookie */
|
||||
tor_free(reply_str);
|
||||
client = add_onion_helper_clientauth("alice:12345", &created, NULL);
|
||||
tt_ptr_op(client, OP_EQ, NULL);
|
||||
tt_assert(reply_str);
|
||||
|
||||
/* Test invalid syntax */
|
||||
tor_free(reply_str);
|
||||
client = add_onion_helper_clientauth(":475hGBHPlq7Mc0cRZitK/B", &created,
|
||||
NULL);
|
||||
tt_ptr_op(client, OP_EQ, NULL);
|
||||
tt_assert(reply_str);
|
||||
|
||||
done:
|
||||
rend_authorized_client_free(client);
|
||||
tor_free(reply_str);
|
||||
UNMOCK(control_write_reply);
|
||||
}
|
||||
|
||||
/* Mocks and data/variables used for GETINFO download status tests */
|
||||
|
||||
static const download_status_t dl_status_default =
|
||||
@ -2209,15 +2052,11 @@ struct testcase_t controller_tests[] = {
|
||||
PARSER_TEST(no_args_one_obj),
|
||||
PARSER_TEST(no_args_kwargs),
|
||||
PARSER_TEST(one_arg_kwargs),
|
||||
{ "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0,
|
||||
NULL, NULL },
|
||||
{ "add_onion_helper_keyarg_v3", test_add_onion_helper_keyarg_v3, 0,
|
||||
NULL, NULL },
|
||||
{ "getinfo_helper_onion", test_getinfo_helper_onion, 0, NULL, NULL },
|
||||
{ "hs_parse_port_config", test_hs_parse_port_config, 0,
|
||||
NULL, NULL },
|
||||
{ "add_onion_helper_clientauth", test_add_onion_helper_clientauth, 0, NULL,
|
||||
NULL },
|
||||
{ "download_status_consensus", test_download_status_consensus, 0, NULL,
|
||||
NULL },
|
||||
{"getinfo_helper_current_consensus_from_cache",
|
||||
|
@ -4848,9 +4848,6 @@ test_dir_purpose_needs_anonymity_returns_true_for_bridges(void *arg)
|
||||
tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE, NULL));
|
||||
tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE,
|
||||
"foobar"));
|
||||
tt_int_op(1, OP_EQ,
|
||||
purpose_needs_anonymity(DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2,
|
||||
ROUTER_PURPOSE_BRIDGE, NULL));
|
||||
done: ;
|
||||
}
|
||||
|
||||
@ -4864,21 +4861,6 @@ test_dir_purpose_needs_anonymity_returns_false_for_own_bridge_desc(void *arg)
|
||||
done: ;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dir_purpose_needs_anonymity_returns_true_for_sensitive_purpose(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
tt_int_op(1, OP_EQ, purpose_needs_anonymity(
|
||||
DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2,
|
||||
ROUTER_PURPOSE_GENERAL, NULL));
|
||||
tt_int_op(1, OP_EQ, purpose_needs_anonymity(
|
||||
DIR_PURPOSE_UPLOAD_RENDDESC_V2, 0, NULL));
|
||||
tt_int_op(1, OP_EQ, purpose_needs_anonymity(
|
||||
DIR_PURPOSE_FETCH_RENDDESC_V2, 0, NULL));
|
||||
done: ;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dir_purpose_needs_anonymity_ret_false_for_non_sensitive_conn(void *arg)
|
||||
{
|
||||
@ -4937,12 +4919,6 @@ test_dir_fetch_type(void *arg)
|
||||
tt_int_op(dir_fetch_type(DIR_PURPOSE_FETCH_MICRODESC, ROUTER_PURPOSE_GENERAL,
|
||||
NULL), OP_EQ, MICRODESC_DIRINFO);
|
||||
|
||||
/* This will give a warning, because this function isn't supposed to be
|
||||
* used for HS descriptors. */
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
tt_int_op(dir_fetch_type(DIR_PURPOSE_FETCH_RENDDESC_V2,
|
||||
ROUTER_PURPOSE_GENERAL, NULL), OP_EQ, NO_DIRINFO);
|
||||
expect_single_log_msg_containing("Unexpected purpose");
|
||||
done:
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
@ -5300,10 +5276,6 @@ test_dir_conn_purpose_to_string(void *data)
|
||||
EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_STATUS_VOTE, "status vote fetch");
|
||||
EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES,
|
||||
"consensus signature fetch");
|
||||
EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_RENDDESC_V2,
|
||||
"hidden-service v2 descriptor fetch");
|
||||
EXPECT_CONN_PURPOSE(DIR_PURPOSE_UPLOAD_RENDDESC_V2,
|
||||
"hidden-service v2 descriptor upload");
|
||||
EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_MICRODESC, "microdescriptor fetch");
|
||||
|
||||
/* This will give a warning, because there is no purpose 1024. */
|
||||
@ -7311,7 +7283,6 @@ struct testcase_t dir_tests[] = {
|
||||
DIR(purpose_needs_anonymity_returns_true_for_bridges, 0),
|
||||
DIR(purpose_needs_anonymity_returns_false_for_own_bridge_desc, 0),
|
||||
DIR(purpose_needs_anonymity_returns_true_by_default, 0),
|
||||
DIR(purpose_needs_anonymity_returns_true_for_sensitive_purpose, 0),
|
||||
DIR(purpose_needs_anonymity_ret_false_for_non_sensitive_conn, 0),
|
||||
DIR(post_parsing, 0),
|
||||
DIR(fetch_type, 0),
|
||||
|
@ -18,14 +18,11 @@
|
||||
#include "feature/dircache/dircache.h"
|
||||
#include "test/test.h"
|
||||
#include "lib/compress/compress.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/relay/relay_config.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "test/rend_test_helpers.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "test/test_helpers.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
@ -44,7 +41,6 @@
|
||||
#include "feature/dircommon/dir_connection_st.h"
|
||||
#include "feature/dirclient/dir_server_st.h"
|
||||
#include "feature/nodelist/networkstatus_st.h"
|
||||
#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
|
||||
#include "feature/nodelist/routerinfo_st.h"
|
||||
#include "feature/nodelist/routerlist_st.h"
|
||||
|
||||
@ -261,125 +257,6 @@ test_dir_handle_get_robots_txt(void *data)
|
||||
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 = new_dir_conn();
|
||||
|
||||
// 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_);
|
||||
connection_free_minimal(TO_CONN(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 = new_dir_conn();
|
||||
|
||||
// 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_);
|
||||
connection_free_minimal(TO_CONN(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 = new_dir_conn();
|
||||
|
||||
// connection is encrypted
|
||||
TO_CONN(conn)->linked = 1;
|
||||
tt_assert(connection_dir_is_encrypted(conn));
|
||||
|
||||
//TODO: this can't 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_);
|
||||
connection_free_minimal(TO_CONN(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 = new_dir_conn();
|
||||
|
||||
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_);
|
||||
connection_free_minimal(TO_CONN(conn));
|
||||
tor_free(header);
|
||||
rend_cache_free_all();
|
||||
}
|
||||
|
||||
static const routerinfo_t * dhg_tests_router_get_my_routerinfo(void);
|
||||
ATTR_UNUSED static int dhg_tests_router_get_my_routerinfo_called = 0;
|
||||
|
||||
@ -395,76 +272,6 @@ dhg_tests_router_get_my_routerinfo(void)
|
||||
return mock_routerinfo;
|
||||
}
|
||||
|
||||
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);
|
||||
MOCK(router_get_my_routerinfo,
|
||||
dhg_tests_router_get_my_routerinfo);
|
||||
|
||||
rend_cache_init();
|
||||
|
||||
/* 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, 0);
|
||||
|
||||
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
|
||||
DIGEST_LEN);
|
||||
|
||||
conn = new_dir_conn();
|
||||
|
||||
// connection is encrypted
|
||||
TO_CONN(conn)->linked = 1;
|
||||
tt_assert(connection_dir_is_encrypted(conn));
|
||||
|
||||
tor_snprintf(req, sizeof(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"));
|
||||
tor_snprintf(buff, sizeof(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_);
|
||||
UNMOCK(router_get_my_routerinfo);
|
||||
|
||||
connection_free_minimal(TO_CONN(conn));
|
||||
tor_free(header);
|
||||
tor_free(body);
|
||||
rend_encoded_v2_service_descriptor_free(desc_holder);
|
||||
tor_free(service_id);
|
||||
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)
|
||||
@ -2934,11 +2741,6 @@ struct testcase_t dir_handle_get_tests[] = {
|
||||
DIR_HANDLE_CMD(v1_command_not_found, 0),
|
||||
DIR_HANDLE_CMD(v1_command, 0),
|
||||
DIR_HANDLE_CMD(robots_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),
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
|
||||
#include "feature/hs/hs_cache.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
|
||||
#include "core/or/entry_connection_st.h"
|
||||
#include "core/or/socks_request_st.h"
|
||||
@ -748,7 +747,6 @@ test_entryconn_rewrite_onion_v3(void *arg)
|
||||
/* Make an onion connection using the SOCKS request */
|
||||
conn->entry_cfg.onion_traffic = 1;
|
||||
ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_SOCKS_WAIT;
|
||||
tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data);
|
||||
tt_assert(!ENTRY_TO_EDGE_CONN(conn)->hs_ident);
|
||||
|
||||
/* Handle SOCKS and rewrite! */
|
||||
@ -763,7 +761,6 @@ test_entryconn_rewrite_onion_v3(void *arg)
|
||||
"25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
|
||||
/* check that HS information got attached to the connection */
|
||||
tt_assert(ENTRY_TO_EDGE_CONN(conn)->hs_ident);
|
||||
tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data);
|
||||
|
||||
done:
|
||||
hs_free_all();
|
||||
|
1003
src/test/test_hs.c
1003
src/test/test_hs.c
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,6 @@
|
||||
|
||||
#include "trunnel/ed25519_cert.h"
|
||||
#include "feature/hs/hs_cache.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/dircache/dircache.h"
|
||||
#include "feature/dirclient/dirclient.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
@ -51,8 +50,6 @@ init_test(void)
|
||||
{
|
||||
/* Always needed. Initialize the subsystem. */
|
||||
hs_cache_init();
|
||||
/* We need the v2 cache since our OOM and cache cleanup does poke at it. */
|
||||
rend_cache_init();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "test/test.h"
|
||||
#include "test/test_helpers.h"
|
||||
#include "test/log_test_helpers.h"
|
||||
#include "test/rend_test_helpers.h"
|
||||
#include "test/hs_test_helpers.h"
|
||||
|
||||
#include "app/config/config.h"
|
||||
@ -38,7 +37,6 @@
|
||||
#include "feature/hs/hs_config.h"
|
||||
#include "feature/hs/hs_ident.h"
|
||||
#include "feature/hs/hs_cache.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuitbuild.h"
|
||||
#include "core/or/extendinfo.h"
|
||||
@ -137,12 +135,9 @@ helper_add_random_client_auth(const ed25519_public_key_t *service_pk)
|
||||
* hidden service. */
|
||||
static int
|
||||
helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
|
||||
connection_t **conn_out,
|
||||
int is_legacy)
|
||||
connection_t **conn_out)
|
||||
{
|
||||
int retval;
|
||||
channel_tls_t *n_chan=NULL;
|
||||
rend_data_t *conn_rend_data = NULL;
|
||||
origin_circuit_t *or_circ = NULL;
|
||||
connection_t *conn = NULL;
|
||||
ed25519_public_key_t service_pk;
|
||||
@ -151,20 +146,13 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
|
||||
conn = test_conn_get_connection(AP_CONN_STATE_CIRCUIT_WAIT,
|
||||
CONN_TYPE_AP /* ??? */,
|
||||
0);
|
||||
if (is_legacy) {
|
||||
/* Legacy: Setup rend_data of stream */
|
||||
char service_id[REND_SERVICE_ID_LEN_BASE32+1] = {0};
|
||||
TO_EDGE_CONN(conn)->rend_data = mock_rend_data(service_id);
|
||||
conn_rend_data = TO_EDGE_CONN(conn)->rend_data;
|
||||
} else {
|
||||
/* prop224: Setup hs conn identifier on the stream */
|
||||
ed25519_secret_key_t sk;
|
||||
tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
|
||||
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
|
||||
/* prop224: Setup hs conn identifier on the stream */
|
||||
ed25519_secret_key_t sk;
|
||||
tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
|
||||
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
|
||||
|
||||
/* Setup hs_conn_identifier of stream */
|
||||
TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk);
|
||||
}
|
||||
/* Setup hs_conn_identifier of stream */
|
||||
TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk);
|
||||
|
||||
/* Make it wait for circuit */
|
||||
connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn));
|
||||
@ -184,23 +172,8 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
|
||||
or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
|
||||
or_circ->build_state->is_internal = 1;
|
||||
|
||||
if (is_legacy) {
|
||||
/* Legacy: Setup rend data and final cpath */
|
||||
or_circ->build_state->pending_final_cpath =
|
||||
tor_malloc_zero(sizeof(crypt_path_t));
|
||||
or_circ->build_state->pending_final_cpath->magic = CRYPT_PATH_MAGIC;
|
||||
or_circ->build_state->pending_final_cpath->rend_dh_handshake_state =
|
||||
crypto_dh_new(DH_TYPE_REND);
|
||||
tt_assert(
|
||||
or_circ->build_state->pending_final_cpath->rend_dh_handshake_state);
|
||||
retval = crypto_dh_generate_public(
|
||||
or_circ->build_state->pending_final_cpath->rend_dh_handshake_state);
|
||||
tt_int_op(retval, OP_EQ, 0);
|
||||
or_circ->rend_data = rend_data_dup(conn_rend_data);
|
||||
} else {
|
||||
/* prop224: Setup hs ident on the circuit */
|
||||
or_circ->hs_ident = hs_ident_circuit_new(&service_pk);
|
||||
}
|
||||
/* prop224: Setup hs ident on the circuit */
|
||||
or_circ->hs_ident = hs_ident_circuit_new(&service_pk);
|
||||
|
||||
TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
|
||||
|
||||
@ -219,91 +192,6 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Test: Ensure that setting up legacy e2e rendezvous circuits works
|
||||
* correctly. */
|
||||
static void
|
||||
test_e2e_rend_circuit_setup_legacy(void *arg)
|
||||
{
|
||||
ssize_t retval;
|
||||
origin_circuit_t *or_circ = NULL;
|
||||
connection_t *conn = NULL;
|
||||
|
||||
(void) arg;
|
||||
|
||||
/** In this test we create a v2 legacy HS stream and a circuit with the same
|
||||
* hidden service destination. We make the stream wait for circuits to be
|
||||
* established to the hidden service, and then we complete the circuit using
|
||||
* the hs_circuit_setup_e2e_rend_circ_legacy_client() function. We then
|
||||
* check that the end-to-end cpath was setup correctly and that the stream
|
||||
* was attached to the circuit as expected. */
|
||||
|
||||
MOCK(connection_ap_handshake_send_begin,
|
||||
mock_connection_ap_handshake_send_begin);
|
||||
|
||||
/* Setup */
|
||||
retval = helper_get_circ_and_stream_for_test( &or_circ, &conn, 1);
|
||||
tt_int_op(retval, OP_EQ, 0);
|
||||
tt_assert(or_circ);
|
||||
tt_assert(conn);
|
||||
|
||||
/* Check number of hops */
|
||||
retval = cpath_get_n_hops(&or_circ->cpath);
|
||||
tt_int_op(retval, OP_EQ, 0);
|
||||
|
||||
/* Check that our stream is not attached on any circuits */
|
||||
tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, NULL);
|
||||
|
||||
/********************************************** */
|
||||
|
||||
/* Make a good RENDEZVOUS1 cell body because it needs to pass key exchange
|
||||
* digest verification... */
|
||||
uint8_t rend_cell_body[DH1024_KEY_LEN+DIGEST_LEN] = {2};
|
||||
{
|
||||
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
|
||||
crypto_dh_t *dh_state =
|
||||
or_circ->build_state->pending_final_cpath->rend_dh_handshake_state;
|
||||
/* compute and overwrite digest of cell body with the right value */
|
||||
retval = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh_state,
|
||||
(char*)rend_cell_body, DH1024_KEY_LEN,
|
||||
keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN);
|
||||
tt_int_op(retval, OP_GT, 0);
|
||||
memcpy(rend_cell_body+DH1024_KEY_LEN, keys, DIGEST_LEN);
|
||||
}
|
||||
|
||||
/* Setup the circuit */
|
||||
retval = hs_circuit_setup_e2e_rend_circ_legacy_client(or_circ,
|
||||
rend_cell_body);
|
||||
tt_int_op(retval, OP_EQ, 0);
|
||||
|
||||
/**********************************************/
|
||||
|
||||
/* See that a hop was added to the circuit's cpath */
|
||||
retval = cpath_get_n_hops(&or_circ->cpath);
|
||||
tt_int_op(retval, OP_EQ, 1);
|
||||
|
||||
/* Check the digest algo */
|
||||
tt_int_op(
|
||||
crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
|
||||
OP_EQ, DIGEST_SHA1);
|
||||
tt_int_op(
|
||||
crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
|
||||
OP_EQ, DIGEST_SHA1);
|
||||
tt_assert(or_circ->cpath->pvt_crypto.f_crypto);
|
||||
tt_assert(or_circ->cpath->pvt_crypto.b_crypto);
|
||||
|
||||
/* Ensure that circ purpose was changed */
|
||||
tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
|
||||
|
||||
/* Test that stream got attached */
|
||||
tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ));
|
||||
|
||||
done:
|
||||
connection_free_minimal(conn);
|
||||
if (or_circ)
|
||||
tor_free(TO_CIRCUIT(or_circ)->n_chan);
|
||||
circuit_free_(TO_CIRCUIT(or_circ));
|
||||
}
|
||||
|
||||
/* Test: Ensure that setting up v3 rendezvous circuits works correctly. */
|
||||
static void
|
||||
test_e2e_rend_circuit_setup(void *arg)
|
||||
@ -326,7 +214,7 @@ test_e2e_rend_circuit_setup(void *arg)
|
||||
mock_connection_ap_handshake_send_begin);
|
||||
|
||||
/* Setup */
|
||||
retval = helper_get_circ_and_stream_for_test(&or_circ, &conn, 0);
|
||||
retval = helper_get_circ_and_stream_for_test(&or_circ, &conn);
|
||||
tt_int_op(retval, OP_EQ, 0);
|
||||
tt_assert(or_circ);
|
||||
tt_assert(conn);
|
||||
@ -974,7 +862,6 @@ test_close_intro_circuits_new_desc(void *arg)
|
||||
(void) arg;
|
||||
|
||||
hs_init();
|
||||
rend_cache_init();
|
||||
|
||||
/* This is needed because of the client cache expiration timestamp is based
|
||||
* on having a consensus. See cached_client_descriptor_has_expired(). */
|
||||
@ -1120,7 +1007,6 @@ test_close_intro_circuits_cache_clean(void *arg)
|
||||
(void) arg;
|
||||
|
||||
hs_init();
|
||||
rend_cache_init();
|
||||
|
||||
/* This is needed because of the client cache expiration timestamp is based
|
||||
* on having a consensus. See cached_client_descriptor_has_expired(). */
|
||||
@ -1189,7 +1075,6 @@ test_close_intro_circuits_cache_clean(void *arg)
|
||||
circuit_free(circ);
|
||||
hs_descriptor_free(desc1);
|
||||
hs_free_all();
|
||||
rend_cache_free_all();
|
||||
UNMOCK(networkstatus_get_reasonably_live_consensus);
|
||||
}
|
||||
|
||||
@ -1554,8 +1439,6 @@ test_purge_ephemeral_client_auth(void *arg)
|
||||
}
|
||||
|
||||
struct testcase_t hs_client_tests[] = {
|
||||
{ "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
|
||||
TT_FORK, NULL, NULL },
|
||||
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup,
|
||||
TT_FORK, NULL, NULL },
|
||||
{ "client_pick_intro", test_client_pick_intro,
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "feature/hs/hs_common.h"
|
||||
#include "feature/hs/hs_config.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
|
||||
static int
|
||||
helper_config_service(const char *conf, int validate_only)
|
||||
@ -49,7 +48,7 @@ test_invalid_service(void *arg)
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, 1);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
expect_log_msg_containing("HiddenServiceVersion must be between 2 and 3");
|
||||
expect_log_msg_containing("HiddenServiceVersion must be between 3 and 3");
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
|
||||
@ -57,7 +56,7 @@ test_invalid_service(void *arg)
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServiceAllowUnknownPorts 2\n"; /* Should be 0 or 1. */
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, 1);
|
||||
@ -72,7 +71,7 @@ test_invalid_service(void *arg)
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServiceDirGroupReadable 2\n"; /* Should be 0 or 1. */
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, 1);
|
||||
@ -87,7 +86,7 @@ test_invalid_service(void *arg)
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServiceMaxStreamsCloseCircuit 2\n"; /* Should be 0 or 1. */
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, 1);
|
||||
@ -102,7 +101,7 @@ test_invalid_service(void *arg)
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServicePort 80\n"
|
||||
"HiddenServiceMaxStreams 65536\n"; /* One too many. */
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
@ -117,10 +116,10 @@ test_invalid_service(void *arg)
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServicePort 80\n"
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServicePort 81\n";
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, 1);
|
||||
@ -134,7 +133,7 @@ test_invalid_service(void *arg)
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServicePort 65536\n";
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, 1);
|
||||
@ -147,7 +146,7 @@ test_invalid_service(void *arg)
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServicePort 80 127.0.0.1 8000\n";
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, 1);
|
||||
@ -160,7 +159,7 @@ test_invalid_service(void *arg)
|
||||
/* Out of order directives. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServicePort 80\n";
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
@ -182,18 +181,11 @@ test_valid_service(void *arg)
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* Mix of v2 and v3. Still valid. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 80\n"
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServicePort 81\n"
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 82\n";
|
||||
"HiddenServicePort 81\n";
|
||||
ret = helper_config_service(conf, 1);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
}
|
||||
@ -202,127 +194,6 @@ test_valid_service(void *arg)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_service_v2(void *arg)
|
||||
{
|
||||
int validate_only = 1, ret;
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* Try with a missing port configuration. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n";
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, validate_only);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
expect_log_msg_containing("with no ports configured.");
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
|
||||
/* Too many introduction points. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 80\n"
|
||||
"HiddenServiceNumIntroductionPoints 11\n"; /* One too many. */
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, validate_only);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
expect_log_msg_containing("HiddenServiceNumIntroductionPoints must "
|
||||
"be between 0 and 10, not 11.");
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
|
||||
/* Too little introduction points. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 80\n"
|
||||
"HiddenServiceNumIntroductionPoints -1\n";
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, validate_only);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
expect_log_msg_containing("Could not parse "
|
||||
"HiddenServiceNumIntroductionPoints: "
|
||||
"Integer -1 is malformed or out of bounds.");
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
|
||||
/* Bad authorized client type. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 80\n"
|
||||
"HiddenServiceAuthorizeClient blah alice,bob\n"; /* blah is no good. */
|
||||
setup_full_capture_of_logs(LOG_WARN);
|
||||
ret = helper_config_service(conf, validate_only);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
expect_log_msg_containing("HiddenServiceAuthorizeClient contains "
|
||||
"unrecognized auth-type");
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_valid_service_v2(void *arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
(void) arg;
|
||||
mock_hostname_resolver();
|
||||
|
||||
/* Valid complex configuration. Basic client authorization. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 80\n"
|
||||
"HiddenServicePort 22 localhost:22\n"
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
"HiddenServicePort 42 unix:/path/to/socket\n"
|
||||
#endif
|
||||
"HiddenServiceAuthorizeClient basic alice,bob,eve\n"
|
||||
"HiddenServiceAllowUnknownPorts 1\n"
|
||||
"HiddenServiceMaxStreams 42\n"
|
||||
"HiddenServiceMaxStreamsCloseCircuit 0\n"
|
||||
"HiddenServiceDirGroupReadable 1\n"
|
||||
"HiddenServiceNumIntroductionPoints 7\n";
|
||||
ret = helper_config_service(conf, 1);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
}
|
||||
|
||||
/* Valid complex configuration. Stealth client authorization. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 65535\n"
|
||||
"HiddenServicePort 22 1.1.1.1:22\n"
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
"HiddenServicePort 9000 unix:/path/to/socket\n"
|
||||
#endif
|
||||
"HiddenServiceAuthorizeClient stealth charlie,romeo\n"
|
||||
"HiddenServiceAllowUnknownPorts 0\n"
|
||||
"HiddenServiceMaxStreams 42\n"
|
||||
"HiddenServiceMaxStreamsCloseCircuit 0\n"
|
||||
"HiddenServiceDirGroupReadable 1\n"
|
||||
"HiddenServiceNumIntroductionPoints 8\n";
|
||||
ret = helper_config_service(conf, 1);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
}
|
||||
|
||||
done:
|
||||
unmock_hostname_resolver();
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_service_v3(void *arg)
|
||||
{
|
||||
@ -438,22 +309,6 @@ test_valid_service_v3(void *arg)
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
}
|
||||
|
||||
/* Mix of v2 and v3. Still valid. */
|
||||
{
|
||||
const char *conf =
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 80\n"
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
|
||||
"HiddenServiceVersion 3\n"
|
||||
"HiddenServicePort 81\n"
|
||||
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
|
||||
"HiddenServiceVersion 2\n"
|
||||
"HiddenServicePort 82\n";
|
||||
ret = helper_config_service(conf, 1);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
}
|
||||
|
||||
done:
|
||||
unmock_hostname_resolver();
|
||||
}
|
||||
@ -489,8 +344,6 @@ test_staging_service_v3(void *arg)
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
/* Ok, we have a service in our map! Registration went well. */
|
||||
tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
|
||||
/* Make sure we don't have a magic v2 service out of this. */
|
||||
tt_int_op(rend_num_services(), OP_EQ, 0);
|
||||
|
||||
done:
|
||||
hs_free_all();
|
||||
@ -611,12 +464,6 @@ struct testcase_t hs_config_tests[] = {
|
||||
{ "valid_service", test_valid_service, TT_FORK,
|
||||
NULL, NULL },
|
||||
|
||||
/* Test case only for version 2. */
|
||||
{ "invalid_service_v2", test_invalid_service_v2, TT_FORK,
|
||||
NULL, NULL },
|
||||
{ "valid_service_v2", test_valid_service_v2, TT_FORK,
|
||||
NULL, NULL },
|
||||
|
||||
/* Test case only for version 3. */
|
||||
{ "invalid_service_v3", test_invalid_service_v3, TT_FORK,
|
||||
NULL, NULL },
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "feature/hs/hs_client.h"
|
||||
#include "feature/hs/hs_control.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
|
||||
#include "feature/nodelist/node_st.h"
|
||||
#include "feature/nodelist/routerstatus_st.h"
|
||||
@ -797,7 +796,7 @@ test_hs_control_add_onion_helper_add_service(void *arg)
|
||||
hs_service_authorized_client_t *client_good, *client_bad;
|
||||
smartlist_t *list_good, *list_bad;
|
||||
hs_service_ht *global_map;
|
||||
rend_service_port_config_t *portcfg;
|
||||
hs_port_config_t *portcfg;
|
||||
smartlist_t *portcfgs;
|
||||
char *address_out_good, *address_out_bad;
|
||||
hs_service_t *service_good = NULL;
|
||||
@ -808,7 +807,7 @@ test_hs_control_add_onion_helper_add_service(void *arg)
|
||||
hs_init();
|
||||
global_map = get_hs_service_map();
|
||||
|
||||
portcfg = rend_service_parse_port_config("8080", ",", NULL);
|
||||
portcfg = hs_parse_port_config("8080", ",", NULL);
|
||||
portcfgs = smartlist_new();
|
||||
smartlist_add(portcfgs, portcfg);
|
||||
|
||||
@ -831,7 +830,7 @@ test_hs_control_add_onion_helper_add_service(void *arg)
|
||||
smartlist_add(list_good, client_good);
|
||||
|
||||
add_onion_helper_add_service(HS_VERSION_THREE, &sk_good, portcfgs, 1, 1,
|
||||
REND_V3_AUTH, NULL, list_good, &address_out_good);
|
||||
list_good, &address_out_good);
|
||||
|
||||
service_good = find_service(global_map, &pk_good);
|
||||
tt_int_op(smartlist_len(service_good->config.clients), OP_EQ, 1);
|
||||
@ -841,12 +840,12 @@ test_hs_control_add_onion_helper_add_service(void *arg)
|
||||
list_bad = smartlist_new();
|
||||
smartlist_add(list_bad, client_bad);
|
||||
|
||||
portcfg = rend_service_parse_port_config("8080", ",", NULL);
|
||||
portcfg = hs_parse_port_config("8080", ",", NULL);
|
||||
portcfgs = smartlist_new();
|
||||
smartlist_add(portcfgs, portcfg);
|
||||
|
||||
add_onion_helper_add_service(HS_VERSION_THREE, &sk_bad, portcfgs, 1, 1,
|
||||
REND_V3_AUTH, NULL, list_bad, &address_out_bad);
|
||||
list_bad, &address_out_bad);
|
||||
|
||||
service_bad = find_service(global_map, &pk_bad);
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "core/or/circuituse.h"
|
||||
#include "ht.h"
|
||||
#include "core/or/relay.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
|
||||
#include "feature/hs/hs_cell.h"
|
||||
#include "feature/hs/hs_circuitmap.h"
|
||||
@ -517,42 +516,6 @@ helper_establish_intro_v3(or_circuit_t *intro_circ)
|
||||
return cell;
|
||||
}
|
||||
|
||||
/* Helper function: Send a well-formed v2 ESTABLISH_INTRO cell to
|
||||
* <b>intro_circ</b>. Return the public key advertised in the cell. */
|
||||
static crypto_pk_t *
|
||||
helper_establish_intro_v2(or_circuit_t *intro_circ)
|
||||
{
|
||||
crypto_pk_t *key1 = NULL;
|
||||
int retval;
|
||||
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
|
||||
ssize_t cell_len = 0;
|
||||
char circ_nonce[DIGEST_LEN] = {0};
|
||||
|
||||
tt_assert(intro_circ);
|
||||
|
||||
/* Prepare the circuit for the incoming ESTABLISH_INTRO */
|
||||
crypto_rand(circ_nonce, sizeof(circ_nonce));
|
||||
helper_prepare_circ_for_intro(intro_circ, circ_nonce);
|
||||
|
||||
/* Send legacy establish_intro */
|
||||
key1 = pk_generate(0);
|
||||
|
||||
/* Use old circ_nonce why not */
|
||||
cell_len = rend_service_encode_establish_intro_cell(
|
||||
(char*)cell_body,
|
||||
sizeof(cell_body), key1,
|
||||
circ_nonce);
|
||||
tt_int_op(cell_len, OP_GT, 0);
|
||||
|
||||
/* Receive legacy establish_intro */
|
||||
retval = hs_intro_received_establish_intro(intro_circ,
|
||||
cell_body, (size_t) cell_len);
|
||||
tt_int_op(retval, OP_EQ, 0);
|
||||
|
||||
done:
|
||||
return key1;
|
||||
}
|
||||
|
||||
/* Helper function: test circuitmap free_all function outside of
|
||||
* test_intro_point_registration to prevent Coverity from seeing a
|
||||
* double free if the assertion hypothetically fails.
|
||||
@ -571,21 +534,17 @@ test_circuitmap_free_all(void)
|
||||
;
|
||||
}
|
||||
|
||||
/** Successfully register a v2 intro point and a v3 intro point. Ensure that HS
|
||||
/** Successfully register a v3 intro point. Ensure that HS
|
||||
* circuitmap is maintained properly. */
|
||||
static void
|
||||
test_intro_point_registration(void *arg)
|
||||
{
|
||||
int retval;
|
||||
hs_circuitmap_ht *the_hs_circuitmap = NULL;
|
||||
|
||||
or_circuit_t *intro_circ = NULL;
|
||||
trn_cell_establish_intro_t *establish_intro_cell = NULL;
|
||||
ed25519_public_key_t auth_key;
|
||||
|
||||
crypto_pk_t *legacy_auth_key = NULL;
|
||||
or_circuit_t *legacy_intro_circ = NULL;
|
||||
|
||||
or_circuit_t *returned_intro_circ = NULL;
|
||||
|
||||
(void) arg;
|
||||
@ -621,35 +580,11 @@ test_intro_point_registration(void *arg)
|
||||
tt_ptr_op(intro_circ, OP_EQ, returned_intro_circ);
|
||||
}
|
||||
|
||||
/* Create a v2 intro point */
|
||||
{
|
||||
char key_digest[DIGEST_LEN];
|
||||
|
||||
legacy_intro_circ = or_circuit_new(1, NULL);
|
||||
tt_assert(legacy_intro_circ);
|
||||
legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ);
|
||||
tt_assert(legacy_auth_key);
|
||||
|
||||
/* Check that the circuitmap now has two elements */
|
||||
the_hs_circuitmap = get_hs_circuitmap();
|
||||
tt_assert(the_hs_circuitmap);
|
||||
tt_int_op(2, OP_EQ, HT_SIZE(the_hs_circuitmap));
|
||||
|
||||
/* Check that the new element is our legacy intro circuit. */
|
||||
retval = crypto_pk_get_digest(legacy_auth_key, key_digest);
|
||||
tt_int_op(retval, OP_EQ, 0);
|
||||
returned_intro_circ =
|
||||
hs_circuitmap_get_intro_circ_v2_relay_side((uint8_t*)key_digest);
|
||||
tt_ptr_op(legacy_intro_circ, OP_EQ, returned_intro_circ);
|
||||
}
|
||||
|
||||
/* XXX Continue test and try to register a second v3 intro point with the
|
||||
* same auth key. Make sure that old intro circuit gets closed. */
|
||||
|
||||
done:
|
||||
crypto_pk_free(legacy_auth_key);
|
||||
circuit_free_(TO_CIRCUIT(intro_circ));
|
||||
circuit_free_(TO_CIRCUIT(legacy_intro_circ));
|
||||
trn_cell_establish_intro_free(establish_intro_cell);
|
||||
test_circuitmap_free_all();
|
||||
|
||||
@ -719,31 +654,6 @@ test_introduce1_suitable_circuit(void *arg)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_introduce1_is_legacy(void *arg)
|
||||
{
|
||||
int ret;
|
||||
uint8_t request[256];
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* For a cell to be considered legacy, according to the specification, the
|
||||
* first 20 bytes MUST BE non-zero else it's a v3 cell. */
|
||||
memset(request, 'a', DIGEST_LEN);
|
||||
memset(request + DIGEST_LEN, 0, sizeof(request) - DIGEST_LEN);
|
||||
ret = introduce1_cell_is_legacy(request);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
/* This is a NON legacy cell. */
|
||||
memset(request, 0, DIGEST_LEN);
|
||||
memset(request + DIGEST_LEN, 'a', sizeof(request) - DIGEST_LEN);
|
||||
ret = introduce1_cell_is_legacy(request);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_introduce1_validation(void *arg)
|
||||
{
|
||||
@ -757,20 +667,6 @@ test_introduce1_validation(void *arg)
|
||||
cell = helper_create_introduce1_cell();
|
||||
tt_assert(cell);
|
||||
|
||||
#ifndef ALL_BUGS_ARE_FATAL
|
||||
/* It should NOT be a legacy cell which will trigger a BUG(). */
|
||||
memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id));
|
||||
tor_capture_bugs_(1);
|
||||
ret = validate_introduce1_parsed_cell(cell);
|
||||
tor_end_capture_bugs_();
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
|
||||
|
||||
/* Reset legacy ID and make sure it's correct. */
|
||||
memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id));
|
||||
ret = validate_introduce1_parsed_cell(cell);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
|
||||
/* Non existing auth key type. */
|
||||
cell->auth_key_type = 42;
|
||||
ret = validate_introduce1_parsed_cell(cell);
|
||||
@ -877,35 +773,6 @@ test_received_introduce1_handling(void *arg)
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
}
|
||||
|
||||
/* Valid legacy cell. */
|
||||
{
|
||||
tor_free(request);
|
||||
trn_cell_introduce1_free(cell);
|
||||
cell = helper_create_introduce1_cell();
|
||||
uint8_t *legacy_key_id = trn_cell_introduce1_getarray_legacy_key_id(cell);
|
||||
memset(legacy_key_id, 'a', DIGEST_LEN);
|
||||
/* Add an arbitrary amount of data for the payload of a v2 cell. */
|
||||
size_t request_len = trn_cell_introduce1_encoded_len(cell) + 256;
|
||||
tt_size_op(request_len, OP_GT, 0);
|
||||
request = tor_malloc_zero(request_len + 256);
|
||||
ssize_t encoded_len =
|
||||
trn_cell_introduce1_encode(request, request_len, cell);
|
||||
tt_int_op((int)encoded_len, OP_GT, 0);
|
||||
|
||||
circ = helper_create_intro_circuit();
|
||||
or_circuit_t *service_circ = helper_create_intro_circuit();
|
||||
circuit_change_purpose(TO_CIRCUIT(service_circ),
|
||||
CIRCUIT_PURPOSE_INTRO_POINT);
|
||||
/* Register the circuit in the map for the auth key of the cell. */
|
||||
uint8_t token[REND_TOKEN_LEN];
|
||||
memcpy(token, legacy_key_id, sizeof(token));
|
||||
hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token);
|
||||
ret = hs_intro_received_introduce1(circ, request, request_len);
|
||||
circuit_free_(TO_CIRCUIT(circ));
|
||||
circuit_free_(TO_CIRCUIT(service_circ));
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
}
|
||||
|
||||
done:
|
||||
trn_cell_introduce1_free(cell);
|
||||
tor_free(request);
|
||||
@ -1109,9 +976,6 @@ struct testcase_t hs_intropoint_tests[] = {
|
||||
{ "introduce1_suitable_circuit",
|
||||
test_introduce1_suitable_circuit, TT_FORK, NULL, &test_setup},
|
||||
|
||||
{ "introduce1_is_legacy",
|
||||
test_introduce1_is_legacy, TT_FORK, NULL, &test_setup},
|
||||
|
||||
{ "introduce1_validation",
|
||||
test_introduce1_validation, TT_FORK, NULL, &test_setup},
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "test/test.h"
|
||||
#include "test/test_helpers.h"
|
||||
#include "test/log_test_helpers.h"
|
||||
#include "test/rend_test_helpers.h"
|
||||
#include "test/hs_test_helpers.h"
|
||||
|
||||
#include "core/or/or.h"
|
||||
@ -58,7 +57,6 @@
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/fs/dir.h"
|
||||
|
||||
@ -383,14 +381,13 @@ test_load_keys(void *arg)
|
||||
{
|
||||
int ret;
|
||||
char *conf = NULL;
|
||||
char *hsdir_v2 = tor_strdup(get_fname("hs2"));
|
||||
char *hsdir_v3 = tor_strdup(get_fname("hs3"));
|
||||
char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* We'll register two services, a v2 and a v3, then we'll load keys and
|
||||
* validate that both are in a correct state. */
|
||||
/* We'll register one service then we'll load keys and validate that both
|
||||
* are in a correct state. */
|
||||
|
||||
hs_init();
|
||||
|
||||
@ -399,15 +396,6 @@ test_load_keys(void *arg)
|
||||
"HiddenServiceVersion %d\n" \
|
||||
"HiddenServicePort 65535\n"
|
||||
|
||||
/* v2 service. */
|
||||
tor_asprintf(&conf, conf_fmt, hsdir_v2, HS_VERSION_TWO);
|
||||
ret = helper_config_service(conf);
|
||||
tor_free(conf);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
/* This one should now be registered into the v2 list. */
|
||||
tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 0);
|
||||
tt_int_op(rend_num_services(), OP_EQ, 1);
|
||||
|
||||
/* v3 service. */
|
||||
tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE);
|
||||
ret = helper_config_service(conf);
|
||||
@ -441,7 +429,6 @@ test_load_keys(void *arg)
|
||||
tt_assert(!s->config.is_client_auth_enabled);
|
||||
|
||||
done:
|
||||
tor_free(hsdir_v2);
|
||||
tor_free(hsdir_v3);
|
||||
hs_free_all();
|
||||
}
|
||||
@ -634,8 +621,8 @@ test_access_service(void *arg)
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* We'll register two services, a v2 and a v3, then we'll load keys and
|
||||
* validate that both are in a correct state. */
|
||||
/* We'll register one service then we'll load keys and validate that both
|
||||
* are in a correct state. */
|
||||
|
||||
hs_init();
|
||||
|
||||
|
@ -1,539 +0,0 @@
|
||||
/* Copyright (c) 2012-2020, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "lib/crypt_ops/crypto_cipher.h"
|
||||
#include "core/or/or.h"
|
||||
#include "test/test.h"
|
||||
|
||||
#define RENDSERVICE_PRIVATE
|
||||
#include "feature/rend/rendservice.h"
|
||||
|
||||
static uint8_t v0_test_plaintext[] =
|
||||
/* 20 bytes of rendezvous point nickname */
|
||||
{ 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
/* 20 bytes dummy rendezvous cookie */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
/* 128 bytes dummy DH handshake data */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
|
||||
|
||||
static uint8_t v1_test_plaintext[] =
|
||||
/* Version byte */
|
||||
{ 0x01,
|
||||
/* 42 bytes of dummy rendezvous point hex digest */
|
||||
0x24, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30,
|
||||
0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30,
|
||||
0x37, 0x30, 0x38, 0x30, 0x39, 0x30, 0x41, 0x30,
|
||||
0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30,
|
||||
0x46, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31,
|
||||
0x33, 0x00,
|
||||
/* 20 bytes dummy rendezvous cookie */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
/* 128 bytes dummy DH handshake data */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
|
||||
|
||||
static uint8_t v2_test_plaintext[] =
|
||||
/* Version byte */
|
||||
{ 0x02,
|
||||
/* 4 bytes rendezvous point's IP address */
|
||||
0xc0, 0xa8, 0x00, 0x01,
|
||||
/* 2 bytes rendezvous point's OR port */
|
||||
0x23, 0x5a,
|
||||
/* 20 bytes dummy rendezvous point's identity digest */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
/* 2 bytes length of onion key */
|
||||
0x00, 0x8c,
|
||||
/* Onion key (140 bytes taken from live test) */
|
||||
0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
|
||||
0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
|
||||
0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
|
||||
0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
|
||||
0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
|
||||
0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
|
||||
0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
|
||||
0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
|
||||
0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
|
||||
0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
|
||||
0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
|
||||
0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
|
||||
0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
|
||||
0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
|
||||
0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
|
||||
0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
|
||||
0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
|
||||
0x03, 0x01, 0x00, 0x01,
|
||||
/* 20 bytes dummy rendezvous cookie */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
/* 128 bytes dummy DH handshake data */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
|
||||
|
||||
static uint8_t v3_no_auth_test_plaintext[] =
|
||||
/* Version byte */
|
||||
{ 0x03,
|
||||
/* Auth type (0 for no auth len/auth data) */
|
||||
0x00,
|
||||
/* Timestamp */
|
||||
0x50, 0x0b, 0xb5, 0xaa,
|
||||
/* 4 bytes rendezvous point's IP address */
|
||||
0xc0, 0xa8, 0x00, 0x01,
|
||||
/* 2 bytes rendezvous point's OR port */
|
||||
0x23, 0x5a,
|
||||
/* 20 bytes dummy rendezvous point's identity digest */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
/* 2 bytes length of onion key */
|
||||
0x00, 0x8c,
|
||||
/* Onion key (140 bytes taken from live test) */
|
||||
0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
|
||||
0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
|
||||
0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
|
||||
0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
|
||||
0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
|
||||
0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
|
||||
0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
|
||||
0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
|
||||
0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
|
||||
0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
|
||||
0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
|
||||
0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
|
||||
0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
|
||||
0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
|
||||
0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
|
||||
0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
|
||||
0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
|
||||
0x03, 0x01, 0x00, 0x01,
|
||||
/* 20 bytes dummy rendezvous cookie */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
/* 128 bytes dummy DH handshake data */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
|
||||
|
||||
static uint8_t v3_basic_auth_test_plaintext[] =
|
||||
/* Version byte */
|
||||
{ 0x03,
|
||||
/* Auth type (1 for REND_BASIC_AUTH) */
|
||||
0x01,
|
||||
/* Auth len (must be 16 bytes for REND_BASIC_AUTH) */
|
||||
0x00, 0x10,
|
||||
/* Auth data (a 16-byte dummy descriptor cookie) */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
/* Timestamp */
|
||||
0x50, 0x0b, 0xb5, 0xaa,
|
||||
/* 4 bytes rendezvous point's IP address */
|
||||
0xc0, 0xa8, 0x00, 0x01,
|
||||
/* 2 bytes rendezvous point's OR port */
|
||||
0x23, 0x5a,
|
||||
/* 20 bytes dummy rendezvous point's identity digest */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
/* 2 bytes length of onion key */
|
||||
0x00, 0x8c,
|
||||
/* Onion key (140 bytes taken from live test) */
|
||||
0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
|
||||
0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
|
||||
0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
|
||||
0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
|
||||
0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
|
||||
0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
|
||||
0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
|
||||
0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
|
||||
0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
|
||||
0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
|
||||
0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
|
||||
0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
|
||||
0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
|
||||
0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
|
||||
0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
|
||||
0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
|
||||
0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
|
||||
0x03, 0x01, 0x00, 0x01,
|
||||
/* 20 bytes dummy rendezvous cookie */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
/* 128 bytes dummy DH handshake data */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
|
||||
|
||||
static void do_decrypt_test(uint8_t *plaintext, size_t plaintext_len);
|
||||
static void do_early_parse_test(uint8_t *plaintext, size_t plaintext_len);
|
||||
static void do_late_parse_test(uint8_t *plaintext, size_t plaintext_len);
|
||||
static void do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase);
|
||||
static ssize_t make_intro_from_plaintext(
|
||||
void *buf, size_t len, crypto_pk_t *key, void **cell_out);
|
||||
|
||||
#define EARLY_PARSE_ONLY 1
|
||||
#define DECRYPT_ONLY 2
|
||||
#define ALL_PARSING 3
|
||||
|
||||
static void
|
||||
do_early_parse_test(uint8_t *plaintext, size_t plaintext_len)
|
||||
{
|
||||
do_parse_test(plaintext, plaintext_len, EARLY_PARSE_ONLY);
|
||||
}
|
||||
|
||||
static void
|
||||
do_decrypt_test(uint8_t *plaintext, size_t plaintext_len)
|
||||
{
|
||||
do_parse_test(plaintext, plaintext_len, DECRYPT_ONLY);
|
||||
}
|
||||
|
||||
static void
|
||||
do_late_parse_test(uint8_t *plaintext, size_t plaintext_len)
|
||||
{
|
||||
do_parse_test(plaintext, plaintext_len, ALL_PARSING);
|
||||
}
|
||||
|
||||
/** Test utility function: checks that the <b>plaintext_len</b>-byte string at
|
||||
* <b>plaintext</b> is at least superficially parseable.
|
||||
*/
|
||||
static void
|
||||
do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
|
||||
{
|
||||
crypto_pk_t *k = NULL;
|
||||
ssize_t r;
|
||||
uint8_t *cell = NULL;
|
||||
size_t cell_len;
|
||||
rend_intro_cell_t *parsed_req = NULL;
|
||||
char *err_msg = NULL;
|
||||
char digest[DIGEST_LEN];
|
||||
|
||||
/* Get a key */
|
||||
k = crypto_pk_new();
|
||||
tt_assert(k);
|
||||
r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1);
|
||||
tt_assert(!r);
|
||||
|
||||
/* Get digest for future comparison */
|
||||
r = crypto_pk_get_digest(k, digest);
|
||||
tt_assert(r >= 0);
|
||||
|
||||
/* Make a cell out of it */
|
||||
r = make_intro_from_plaintext(
|
||||
plaintext, plaintext_len,
|
||||
k, (void **)(&cell));
|
||||
tt_assert(r > 0);
|
||||
tt_assert(cell);
|
||||
cell_len = r;
|
||||
|
||||
/* Do early parsing */
|
||||
parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg);
|
||||
tt_assert(parsed_req);
|
||||
tt_ptr_op(err_msg, OP_EQ, NULL);
|
||||
tt_mem_op(parsed_req->pk,OP_EQ, digest, DIGEST_LEN);
|
||||
tt_assert(parsed_req->ciphertext);
|
||||
tt_assert(parsed_req->ciphertext_len > 0);
|
||||
|
||||
if (phase == EARLY_PARSE_ONLY)
|
||||
goto done;
|
||||
|
||||
/* Do decryption */
|
||||
r = rend_service_decrypt_intro(parsed_req, k, &err_msg);
|
||||
tt_assert(!r);
|
||||
tt_ptr_op(err_msg, OP_EQ, NULL);
|
||||
tt_assert(parsed_req->plaintext);
|
||||
tt_assert(parsed_req->plaintext_len > 0);
|
||||
|
||||
if (phase == DECRYPT_ONLY)
|
||||
goto done;
|
||||
|
||||
/* Do late parsing */
|
||||
r = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
|
||||
tt_assert(!r);
|
||||
tt_ptr_op(err_msg, OP_EQ, NULL);
|
||||
tt_assert(parsed_req->parsed);
|
||||
|
||||
done:
|
||||
tor_free(cell);
|
||||
crypto_pk_free(k);
|
||||
rend_service_free_intro(parsed_req);
|
||||
tor_free(err_msg);
|
||||
}
|
||||
|
||||
/** Given the plaintext of the encrypted part of an INTRODUCE1/2 and a key,
|
||||
* construct the encrypted cell for testing.
|
||||
*/
|
||||
|
||||
static ssize_t
|
||||
make_intro_from_plaintext(
|
||||
void *buf, size_t len, crypto_pk_t *key, void **cell_out)
|
||||
{
|
||||
char *cell = NULL;
|
||||
ssize_t cell_len = -1, r;
|
||||
/* Assemble key digest and ciphertext, then construct the cell */
|
||||
ssize_t ciphertext_size;
|
||||
|
||||
if (!(buf && key && len > 0 && cell_out)) goto done;
|
||||
|
||||
/*
|
||||
* Figure out an upper bound on how big the ciphertext will be
|
||||
* (see crypto_pk_obsolete_public_hybrid_encrypt())
|
||||
*/
|
||||
ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD;
|
||||
ciphertext_size += crypto_pk_keysize(key);
|
||||
ciphertext_size += CIPHER_KEY_LEN;
|
||||
ciphertext_size += len;
|
||||
|
||||
/*
|
||||
* Allocate space for the cell
|
||||
*/
|
||||
cell = tor_malloc(DIGEST_LEN + ciphertext_size);
|
||||
|
||||
/* Compute key digest (will be first DIGEST_LEN octets of cell) */
|
||||
r = crypto_pk_get_digest(key, cell);
|
||||
tt_assert(r >= 0);
|
||||
|
||||
/* Do encryption */
|
||||
r = crypto_pk_obsolete_public_hybrid_encrypt(
|
||||
key, cell + DIGEST_LEN, ciphertext_size,
|
||||
buf, len,
|
||||
PK_PKCS1_OAEP_PADDING, 0);
|
||||
tt_assert(r >= 0);
|
||||
|
||||
/* Figure out cell length */
|
||||
cell_len = DIGEST_LEN + r;
|
||||
|
||||
/* Output the cell */
|
||||
*cell_out = cell;
|
||||
cell = NULL;
|
||||
|
||||
done:
|
||||
tor_free(cell);
|
||||
return cell_len;
|
||||
}
|
||||
|
||||
/** Test v0 INTRODUCE2 parsing through decryption only
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_decrypt_v0(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_decrypt_test(v0_test_plaintext, sizeof(v0_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v1 INTRODUCE2 parsing through decryption only
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_decrypt_v1(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_decrypt_test(v1_test_plaintext, sizeof(v1_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v2 INTRODUCE2 parsing through decryption only
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_decrypt_v2(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_decrypt_test(v2_test_plaintext, sizeof(v2_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v3 INTRODUCE2 parsing through decryption only
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_decrypt_v3(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_decrypt_test(
|
||||
v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
|
||||
do_decrypt_test(
|
||||
v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v0 INTRODUCE2 parsing through early parsing only
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_early_parse_v0(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_early_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v1 INTRODUCE2 parsing through early parsing only
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_early_parse_v1(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_early_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v2 INTRODUCE2 parsing through early parsing only
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_early_parse_v2(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_early_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v3 INTRODUCE2 parsing through early parsing only
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_early_parse_v3(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_early_parse_test(
|
||||
v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
|
||||
do_early_parse_test(
|
||||
v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v0 INTRODUCE2 parsing
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_late_parse_v0(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_late_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v1 INTRODUCE2 parsing
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_late_parse_v1(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_late_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v2 INTRODUCE2 parsing
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_late_parse_v2(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_late_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
|
||||
}
|
||||
|
||||
/** Test v3 INTRODUCE2 parsing
|
||||
*/
|
||||
|
||||
static void
|
||||
test_introduce_late_parse_v3(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
do_late_parse_test(
|
||||
v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
|
||||
do_late_parse_test(
|
||||
v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
|
||||
}
|
||||
|
||||
#define INTRODUCE_LEGACY(name) \
|
||||
{ #name, test_introduce_ ## name , 0, NULL, NULL }
|
||||
|
||||
struct testcase_t introduce_tests[] = {
|
||||
INTRODUCE_LEGACY(early_parse_v0),
|
||||
INTRODUCE_LEGACY(early_parse_v1),
|
||||
INTRODUCE_LEGACY(early_parse_v2),
|
||||
INTRODUCE_LEGACY(early_parse_v3),
|
||||
INTRODUCE_LEGACY(decrypt_v0),
|
||||
INTRODUCE_LEGACY(decrypt_v1),
|
||||
INTRODUCE_LEGACY(decrypt_v2),
|
||||
INTRODUCE_LEGACY(decrypt_v3),
|
||||
INTRODUCE_LEGACY(late_parse_v0),
|
||||
INTRODUCE_LEGACY(late_parse_v1),
|
||||
INTRODUCE_LEGACY(late_parse_v2),
|
||||
INTRODUCE_LEGACY(late_parse_v3),
|
||||
END_OF_TESTCASES
|
||||
};
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user