|
@@ -58,7 +58,6 @@ static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
|
|
|
static int onion_extend_cpath(origin_circuit_t *circ);
|
|
|
static int count_acceptable_nodes(smartlist_t *routers);
|
|
|
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
|
|
|
-static int circuits_can_use_ntor(void);
|
|
|
|
|
|
/** This function tries to get a channel to the specified endpoint,
|
|
|
* and then calls command_setup_channel() to give it the right
|
|
@@ -365,7 +364,7 @@ circuit_rep_hist_note_result(origin_circuit_t *circ)
|
|
|
} while (hop!=circ->cpath);
|
|
|
}
|
|
|
|
|
|
-/** Return 1 iff at least one node in circ's cpath supports ntor. */
|
|
|
+/** Return 1 iff every node in circ's cpath definitely supports ntor. */
|
|
|
static int
|
|
|
circuit_cpath_supports_ntor(const origin_circuit_t *circ)
|
|
|
{
|
|
@@ -373,16 +372,19 @@ circuit_cpath_supports_ntor(const origin_circuit_t *circ)
|
|
|
|
|
|
cpath = head = circ->cpath;
|
|
|
do {
|
|
|
- if (cpath->extend_info &&
|
|
|
- !tor_mem_is_zero(
|
|
|
- (const char*)cpath->extend_info->curve25519_onion_key.public_key,
|
|
|
- CURVE25519_PUBKEY_LEN))
|
|
|
- return 1;
|
|
|
+ /* if the extend_info is missing, we can't tell if it supports ntor */
|
|
|
+ if (!cpath->extend_info) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
+ /* if the key is blank, it definitely doesn't support ntor */
|
|
|
+ if (!extend_info_supports_ntor(cpath->extend_info)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
cpath = cpath->next;
|
|
|
} while (cpath != head);
|
|
|
|
|
|
- return 0;
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
/** Pick all the entries in our cpath. Stop and return 0 when we're
|
|
@@ -390,41 +392,61 @@ circuit_cpath_supports_ntor(const origin_circuit_t *circ)
|
|
|
static int
|
|
|
onion_populate_cpath(origin_circuit_t *circ)
|
|
|
{
|
|
|
- int n_tries = 0;
|
|
|
- const int using_ntor = circuits_can_use_ntor();
|
|
|
+ int r = 0;
|
|
|
|
|
|
-#define MAX_POPULATE_ATTEMPTS 32
|
|
|
+ /* onion_extend_cpath assumes these are non-NULL */
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(circ->build_state);
|
|
|
|
|
|
- while (1) {
|
|
|
- int r = onion_extend_cpath(circ);
|
|
|
+ while (r == 0) {
|
|
|
+ r = onion_extend_cpath(circ);
|
|
|
if (r < 0) {
|
|
|
log_info(LD_CIRC,"Generating cpath hop failed.");
|
|
|
return -1;
|
|
|
}
|
|
|
- if (r == 1) {
|
|
|
- /* This circuit doesn't need/shouldn't be forced to have an ntor hop */
|
|
|
- if (circ->build_state->desired_path_len <= 1 || ! using_ntor)
|
|
|
- return 0;
|
|
|
+ }
|
|
|
|
|
|
- /* This circuit has an ntor hop. great! */
|
|
|
- if (circuit_cpath_supports_ntor(circ))
|
|
|
- return 0;
|
|
|
+ /* The path is complete */
|
|
|
+ tor_assert(r == 1);
|
|
|
|
|
|
- /* No node in the circuit supports ntor. Have we already tried too many
|
|
|
- * times? */
|
|
|
- if (++n_tries >= MAX_POPULATE_ATTEMPTS)
|
|
|
- break;
|
|
|
+ /* Does every node in this path support ntor? */
|
|
|
+ int path_supports_ntor = circuit_cpath_supports_ntor(circ);
|
|
|
+
|
|
|
+ /* We would like every path to support ntor, but we have to allow for some
|
|
|
+ * edge cases. */
|
|
|
+ tor_assert(circuit_get_cpath_len(circ));
|
|
|
+ if (circuit_can_use_tap(circ)) {
|
|
|
+ /* Circuits from clients to intro points, and hidden services to
|
|
|
+ * rend points do not support ntor, because the hidden service protocol
|
|
|
+ * does not include ntor onion keys. This is also true for Tor2web clients
|
|
|
+ * and Single Onion Services. */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- /* Clear the path and retry */
|
|
|
- circuit_clear_cpath(circ);
|
|
|
+ if (circuit_get_cpath_len(circ) == 1) {
|
|
|
+ /* Allow for bootstrapping: when we're fetching directly from a fallback,
|
|
|
+ * authority, or bridge, we have no way of knowing its ntor onion key
|
|
|
+ * before we connect to it. So instead, we try connecting, and end up using
|
|
|
+ * CREATE_FAST. */
|
|
|
+ tor_assert(circ->cpath);
|
|
|
+ tor_assert(circ->cpath->extend_info);
|
|
|
+ const node_t *node = node_get_by_id(
|
|
|
+ circ->cpath->extend_info->identity_digest);
|
|
|
+ /* If we don't know the node and its descriptor, we must be bootstrapping.
|
|
|
+ */
|
|
|
+ if (!node || !node_has_descriptor(node)) {
|
|
|
+ return 0;
|
|
|
}
|
|
|
}
|
|
|
- log_warn(LD_CIRC, "I tried for %d times, but I couldn't build a %d-hop "
|
|
|
- "circuit with at least one node that supports ntor.",
|
|
|
- MAX_POPULATE_ATTEMPTS,
|
|
|
- circ->build_state->desired_path_len);
|
|
|
|
|
|
- return -1;
|
|
|
+ if (BUG(!path_supports_ntor)) {
|
|
|
+ /* If we're building a multi-hop path, and it's not one of the HS or
|
|
|
+ * bootstrapping exceptions, and it doesn't support ntor, something has
|
|
|
+ * gone wrong. */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/** Create and return a new origin circuit. Initialize its purpose and
|
|
@@ -757,10 +779,13 @@ should_use_create_fast_for_circuit(origin_circuit_t *circ)
|
|
|
tor_assert(circ->cpath);
|
|
|
tor_assert(circ->cpath->extend_info);
|
|
|
|
|
|
- if (!circ->cpath->extend_info->onion_key)
|
|
|
- return 1; /* our hand is forced: only a create_fast will work. */
|
|
|
+ if (!circuit_has_usable_onion_key(circ)) {
|
|
|
+ /* We don't have ntor, and we don't have or can't use TAP,
|
|
|
+ * so our hand is forced: only a create_fast will work. */
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
if (public_server_mode(options)) {
|
|
|
- /* We're a server, and we know an onion key. We can choose.
|
|
|
+ /* We're a server, and we have a usable onion key. We can choose.
|
|
|
* Prefer to blend our circuit into the other circuits we are
|
|
|
* creating on behalf of others. */
|
|
|
return 0;
|
|
@@ -785,30 +810,20 @@ circuit_timeout_want_to_count_circ(origin_circuit_t *circ)
|
|
|
&& circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN;
|
|
|
}
|
|
|
|
|
|
-/** Return true if the ntor handshake is enabled in the configuration, or if
|
|
|
- * it's been set to "auto" in the configuration and it's enabled in the
|
|
|
- * consensus. */
|
|
|
-static int
|
|
|
-circuits_can_use_ntor(void)
|
|
|
-{
|
|
|
- const or_options_t *options = get_options();
|
|
|
- if (options->UseNTorHandshake != -1)
|
|
|
- return options->UseNTorHandshake;
|
|
|
- return networkstatus_get_param(NULL, "UseNTorHandshake", 0, 0, 1);
|
|
|
-}
|
|
|
-
|
|
|
/** Decide whether to use a TAP or ntor handshake for connecting to <b>ei</b>
|
|
|
* directly, and set *<b>cell_type_out</b> and *<b>handshake_type_out</b>
|
|
|
- * accordingly. */
|
|
|
+ * accordingly.
|
|
|
+ * Note that TAP handshakes are only used for direct connections:
|
|
|
+ * - from Tor2web to intro points not in the client's consensus, and
|
|
|
+ * - from Single Onions to rend points not in the service's consensus.
|
|
|
+ * This is checked in onion_populate_cpath. */
|
|
|
static void
|
|
|
circuit_pick_create_handshake(uint8_t *cell_type_out,
|
|
|
uint16_t *handshake_type_out,
|
|
|
const extend_info_t *ei)
|
|
|
{
|
|
|
- /* XXXX029 Remove support for deciding to use TAP. */
|
|
|
- if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key,
|
|
|
- CURVE25519_PUBKEY_LEN) &&
|
|
|
- circuits_can_use_ntor()) {
|
|
|
+ /* XXXX030 Remove support for deciding to use TAP. */
|
|
|
+ if (extend_info_supports_ntor(ei)) {
|
|
|
*cell_type_out = CELL_CREATE2;
|
|
|
*handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
|
|
|
return;
|
|
@@ -822,7 +837,11 @@ circuit_pick_create_handshake(uint8_t *cell_type_out,
|
|
|
* directly, and set *<b>handshake_type_out</b> accordingly. Decide whether,
|
|
|
* in extending through <b>node</b> to do so, we should use an EXTEND2 or an
|
|
|
* EXTEND cell to do so, and set *<b>cell_type_out</b> and
|
|
|
- * *<b>create_cell_type_out</b> accordingly. */
|
|
|
+ * *<b>create_cell_type_out</b> accordingly.
|
|
|
+ * Note that TAP handshakes are only used for extend handshakes:
|
|
|
+ * - from clients to intro points, and
|
|
|
+ * - from hidden services to rend points.
|
|
|
+ * This is checked in onion_populate_cpath. */
|
|
|
static void
|
|
|
circuit_pick_extend_handshake(uint8_t *cell_type_out,
|
|
|
uint8_t *create_cell_type_out,
|
|
@@ -833,17 +852,27 @@ circuit_pick_extend_handshake(uint8_t *cell_type_out,
|
|
|
uint8_t t;
|
|
|
circuit_pick_create_handshake(&t, handshake_type_out, ei);
|
|
|
|
|
|
- /* XXXX029 Remove support for deciding to use TAP. */
|
|
|
+ /* XXXX030 Remove support for deciding to use TAP. */
|
|
|
+
|
|
|
+ /* It is an error to extend if there is no previous node. */
|
|
|
+ tor_assert_nonfatal(node_prev);
|
|
|
+ /* It is an error for a node with a known version to be so old it does not
|
|
|
+ * support ntor. */
|
|
|
+ tor_assert_nonfatal(routerstatus_version_supports_ntor(node_prev->rs, 1));
|
|
|
+
|
|
|
+ /* Assume relays without tor versions or routerstatuses support ntor.
|
|
|
+ * The authorities enforce ntor support, and assuming and failing is better
|
|
|
+ * than allowing a malicious node to perform a protocol downgrade to TAP. */
|
|
|
if (node_prev &&
|
|
|
*handshake_type_out != ONION_HANDSHAKE_TYPE_TAP &&
|
|
|
(node_has_curve25519_onion_key(node_prev) ||
|
|
|
- (node_prev->rs && node_prev->rs->version_supports_extend2_cells))) {
|
|
|
- *cell_type_out = RELAY_COMMAND_EXTEND2;
|
|
|
- *create_cell_type_out = CELL_CREATE2;
|
|
|
- } else {
|
|
|
- *cell_type_out = RELAY_COMMAND_EXTEND;
|
|
|
- *create_cell_type_out = CELL_CREATE;
|
|
|
- }
|
|
|
+ (routerstatus_version_supports_ntor(node_prev->rs, 1)))) {
|
|
|
+ *cell_type_out = RELAY_COMMAND_EXTEND2;
|
|
|
+ *create_cell_type_out = CELL_CREATE2;
|
|
|
+ } else {
|
|
|
+ *cell_type_out = RELAY_COMMAND_EXTEND;
|
|
|
+ *create_cell_type_out = CELL_CREATE;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/** This is the backbone function for building circuits.
|
|
@@ -2058,15 +2087,18 @@ count_acceptable_nodes(smartlist_t *nodes)
|
|
|
if (! node->is_running)
|
|
|
// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i);
|
|
|
continue;
|
|
|
+ /* XXX This clause makes us count incorrectly: if AllowInvalidRouters
|
|
|
+ * allows this node in some places, then we're getting an inaccurate
|
|
|
+ * count. For now, be conservative and don't count it. But later we
|
|
|
+ * should try to be smarter. */
|
|
|
if (! node->is_valid)
|
|
|
// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
|
|
|
continue;
|
|
|
if (! node_has_descriptor(node))
|
|
|
continue;
|
|
|
- /* XXX This clause makes us count incorrectly: if AllowInvalidRouters
|
|
|
- * allows this node in some places, then we're getting an inaccurate
|
|
|
- * count. For now, be conservative and don't count it. But later we
|
|
|
- * should try to be smarter. */
|
|
|
+ /* The node has a descriptor, so we can just check the ntor key directly */
|
|
|
+ if (!node_has_curve25519_onion_key(node))
|
|
|
+ continue;
|
|
|
++num;
|
|
|
} SMARTLIST_FOREACH_END(node);
|
|
|
|
|
@@ -2356,6 +2388,14 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
|
|
|
log_warn(LD_CIRC, "Could not choose valid address for %s",
|
|
|
node->ri ? node->ri->nickname : node->rs->nickname);
|
|
|
|
|
|
+ /* Every node we connect or extend to must support ntor */
|
|
|
+ if (!node_has_curve25519_onion_key(node)) {
|
|
|
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
|
|
|
+ "Attempted to create extend_info for a node that does not support "
|
|
|
+ "ntor: %s", node_describe(node));
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
if (valid_addr && node->ri)
|
|
|
return extend_info_new(node->ri->nickname,
|
|
|
node->identity,
|
|
@@ -2441,3 +2481,65 @@ extend_info_addr_is_allowed(const tor_addr_t *addr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* Does ei have a valid TAP key? */
|
|
|
+int
|
|
|
+extend_info_supports_tap(const extend_info_t* ei)
|
|
|
+{
|
|
|
+ tor_assert(ei);
|
|
|
+ /* Valid TAP keys are not NULL */
|
|
|
+ return ei->onion_key != NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Does ei have a valid ntor key? */
|
|
|
+int
|
|
|
+extend_info_supports_ntor(const extend_info_t* ei)
|
|
|
+{
|
|
|
+ tor_assert(ei);
|
|
|
+ /* Valid ntor keys have at least one non-zero byte */
|
|
|
+ return !tor_mem_is_zero(
|
|
|
+ (const char*)ei->curve25519_onion_key.public_key,
|
|
|
+ CURVE25519_PUBKEY_LEN);
|
|
|
+}
|
|
|
+
|
|
|
+/* Is circuit purpose allowed to use the deprecated TAP encryption protocol?
|
|
|
+ * The hidden service protocol still uses TAP for some connections, because
|
|
|
+ * ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
|
|
|
+static int
|
|
|
+circuit_purpose_can_use_tap_impl(uint8_t purpose)
|
|
|
+{
|
|
|
+ return (purpose == CIRCUIT_PURPOSE_S_CONNECT_REND ||
|
|
|
+ purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
|
|
|
+}
|
|
|
+
|
|
|
+/* Is circ allowed to use the deprecated TAP encryption protocol?
|
|
|
+ * The hidden service protocol still uses TAP for some connections, because
|
|
|
+ * ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
|
|
|
+int
|
|
|
+circuit_can_use_tap(const origin_circuit_t *circ)
|
|
|
+{
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(circ->cpath);
|
|
|
+ tor_assert(circ->cpath->extend_info);
|
|
|
+ return (circuit_purpose_can_use_tap_impl(circ->base_.purpose) &&
|
|
|
+ extend_info_supports_tap(circ->cpath->extend_info));
|
|
|
+}
|
|
|
+
|
|
|
+/* Does circ have an onion key which it's allowed to use? */
|
|
|
+int
|
|
|
+circuit_has_usable_onion_key(const origin_circuit_t *circ)
|
|
|
+{
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(circ->cpath);
|
|
|
+ tor_assert(circ->cpath->extend_info);
|
|
|
+ return (extend_info_supports_ntor(circ->cpath->extend_info) ||
|
|
|
+ circuit_can_use_tap(circ));
|
|
|
+}
|
|
|
+
|
|
|
+/* Does ei have an onion key which it would prefer to use?
|
|
|
+ * Currently, we prefer ntor keys*/
|
|
|
+int
|
|
|
+extend_info_has_preferred_onion_key(const extend_info_t* ei)
|
|
|
+{
|
|
|
+ tor_assert(ei);
|
|
|
+ return extend_info_supports_ntor(ei);
|
|
|
+}
|