Prohibit the use of one entry node with an HS

In a nutshell, since a circuit can not exit at its entry point, it's very
easy for an attacker to find the hidden service guard if only one EntryNodes
is specified since for that guard, the HS will refuse to build a rendezvous
circuit to it.

For now, the best solution is to stop tor to allow a single EntryNodes for
an hidden service.

Fixes #14917

Signed-off-by: David Goulet <dgoulet@ev0ke.net>
This commit is contained in:
David Goulet 2015-09-02 14:53:39 +02:00 committed by Nick Mathewson
parent f6bd8fbb80
commit 07b3028db7
4 changed files with 31 additions and 0 deletions

5
changes/bug14917 Normal file
View File

@ -0,0 +1,5 @@
o Major bugfix
- For an hidden service, it is now prohibited to use one single
EntryNodes to avoid a very easy guard discovery attack. For more
details, see the ticket description here:
https://trac.torproject.org/projects/tor/ticket/14917. Fixes #14917.

View File

@ -3173,6 +3173,20 @@ options_validate(or_options_t *old_options, or_options_t *options,
"http://freehaven.net/anonbib/#hs-attack06 for details."); "http://freehaven.net/anonbib/#hs-attack06 for details.");
} }
if (routerset_is_list(options->EntryNodes) &&
(routerset_len(options->EntryNodes) == 1) &&
(options->RendConfigLines != NULL)) {
tor_asprintf(msg,
"You have one single EntryNodes and at least one hidden service "
"configured. This is bad because it's very easy to locate your "
"entry guard which can then lead to the deanonymization of your "
"hidden service -- for more details, see "
"https://trac.torproject.org/projects/tor/ticket/14917. "
"For this reason, the use of one EntryNodes with an hidden "
"service is prohibited until a better solution is found.");
return -1;
}
if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout && if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout &&
options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) { options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) {
log_warn(LD_CONFIG, log_warn(LD_CONFIG,

View File

@ -162,6 +162,17 @@ routerset_is_empty(const routerset_t *set)
return !set || smartlist_len(set->list) == 0; return !set || smartlist_len(set->list) == 0;
} }
/** Return the number of entries in <b>set</b>. This does NOT return a
* negative value. */
int
routerset_len(const routerset_t *set)
{
if (!set) {
return 0;
}
return smartlist_len(set->list);
}
/** Helper. Return true iff <b>set</b> contains a router based on the other /** Helper. Return true iff <b>set</b> contains a router based on the other
* provided fields. Return higher values for more specific subentries: a * provided fields. Return higher values for more specific subentries: a
* single router is more specific than an address range of routers, which is * single router is more specific than an address range of routers, which is

View File

@ -38,6 +38,7 @@ void routerset_subtract_nodes(smartlist_t *out,
char *routerset_to_string(const routerset_t *routerset); char *routerset_to_string(const routerset_t *routerset);
int routerset_equal(const routerset_t *old, const routerset_t *new); int routerset_equal(const routerset_t *old, const routerset_t *new);
void routerset_free(routerset_t *routerset); void routerset_free(routerset_t *routerset);
int routerset_len(const routerset_t *set);
#ifdef ROUTERSET_PRIVATE #ifdef ROUTERSET_PRIVATE
STATIC char * routerset_get_countryname(const char *c); STATIC char * routerset_get_countryname(const char *c);