mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 04:13:28 +01:00
Merge remote-tracking branch 'teor/reject-tap-v6'
This commit is contained in:
commit
bbaa7d09a0
15
changes/reject-tap
Normal file
15
changes/reject-tap
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
o Major bug fixes (circuit building):
|
||||||
|
- Tor authorities, relays, and clients only use ntor, except for
|
||||||
|
rare cases in the hidden service protocol.
|
||||||
|
- Authorities, relays and clients specifically check that each
|
||||||
|
descriptor has an ntor key.
|
||||||
|
- Clients avoid downloading a descriptor if the relay version is
|
||||||
|
too old to support ntor.
|
||||||
|
- Client code never chooses nodes without ntor keys: they will not
|
||||||
|
be selected during circuit-building, or as guards, or as directory
|
||||||
|
mirrors, or as introduction or rendezvous points.
|
||||||
|
- Circuit-building code assumes that all hops can use ntor,
|
||||||
|
except for rare hidden service protocol cases.
|
||||||
|
- Hidden service client to intro point and service to rendezvous point
|
||||||
|
connections use the TAP key supplied by the protocol.
|
||||||
|
Fixes bug 19163; bugfix on 0.2.4.18-rc.
|
@ -1452,16 +1452,6 @@ The following options are useful only for clients (that is, if
|
|||||||
"auto" (recommended) then it is on for all clients that do not set
|
"auto" (recommended) then it is on for all clients that do not set
|
||||||
FetchUselessDescriptors. (Default: auto)
|
FetchUselessDescriptors. (Default: auto)
|
||||||
|
|
||||||
[[UseNTorHandshake]] **UseNTorHandshake** **0**|**1**|**auto**::
|
|
||||||
The "ntor" circuit-creation handshake is faster and (we think) more
|
|
||||||
secure than the original ("TAP") circuit handshake, but starting to use
|
|
||||||
it too early might make your client stand out. If this option is 0, your
|
|
||||||
Tor client won't use the ntor handshake. If it's 1, your Tor client
|
|
||||||
will use the ntor handshake to extend circuits through servers that
|
|
||||||
support it. If this option is "auto", then your client
|
|
||||||
will use the ntor handshake once enough directory authorities recommend
|
|
||||||
it. (Default: 1)
|
|
||||||
|
|
||||||
[[PathBiasCircThreshold]] **PathBiasCircThreshold** __NUM__ +
|
[[PathBiasCircThreshold]] **PathBiasCircThreshold** __NUM__ +
|
||||||
|
|
||||||
[[PathBiasNoticeRate]] **PathBiasNoticeRate** __NUM__ +
|
[[PathBiasNoticeRate]] **PathBiasNoticeRate** __NUM__ +
|
||||||
|
@ -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 onion_extend_cpath(origin_circuit_t *circ);
|
||||||
static int count_acceptable_nodes(smartlist_t *routers);
|
static int count_acceptable_nodes(smartlist_t *routers);
|
||||||
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
|
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,
|
/** This function tries to get a channel to the specified endpoint,
|
||||||
* and then calls command_setup_channel() to give it the right
|
* 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);
|
} 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
|
static int
|
||||||
circuit_cpath_supports_ntor(const origin_circuit_t *circ)
|
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;
|
cpath = head = circ->cpath;
|
||||||
do {
|
do {
|
||||||
if (cpath->extend_info &&
|
/* if the extend_info is missing, we can't tell if it supports ntor */
|
||||||
!tor_mem_is_zero(
|
if (!cpath->extend_info) {
|
||||||
(const char*)cpath->extend_info->curve25519_onion_key.public_key,
|
return 0;
|
||||||
CURVE25519_PUBKEY_LEN))
|
}
|
||||||
return 1;
|
|
||||||
|
|
||||||
|
/* if the key is blank, it definitely doesn't support ntor */
|
||||||
|
if (!extend_info_supports_ntor(cpath->extend_info)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
cpath = cpath->next;
|
cpath = cpath->next;
|
||||||
} while (cpath != head);
|
} while (cpath != head);
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Pick all the entries in our cpath. Stop and return 0 when we're
|
/** 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
|
static int
|
||||||
onion_populate_cpath(origin_circuit_t *circ)
|
onion_populate_cpath(origin_circuit_t *circ)
|
||||||
{
|
{
|
||||||
int n_tries = 0;
|
int r = 0;
|
||||||
const int using_ntor = circuits_can_use_ntor();
|
|
||||||
|
|
||||||
#define MAX_POPULATE_ATTEMPTS 32
|
/* onion_extend_cpath assumes these are non-NULL */
|
||||||
|
tor_assert(circ);
|
||||||
|
tor_assert(circ->build_state);
|
||||||
|
|
||||||
while (1) {
|
while (r == 0) {
|
||||||
int r = onion_extend_cpath(circ);
|
r = onion_extend_cpath(circ);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_info(LD_CIRC,"Generating cpath hop failed.");
|
log_info(LD_CIRC,"Generating cpath hop failed.");
|
||||||
return -1;
|
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! */
|
/* The path is complete */
|
||||||
if (circuit_cpath_supports_ntor(circ))
|
tor_assert(r == 1);
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* No node in the circuit supports ntor. Have we already tried too many
|
/* Does every node in this path support ntor? */
|
||||||
* times? */
|
int path_supports_ntor = circuit_cpath_supports_ntor(circ);
|
||||||
if (++n_tries >= MAX_POPULATE_ATTEMPTS)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Clear the path and retry */
|
/* We would like every path to support ntor, but we have to allow for some
|
||||||
circuit_clear_cpath(circ);
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
/** 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);
|
||||||
tor_assert(circ->cpath->extend_info);
|
tor_assert(circ->cpath->extend_info);
|
||||||
|
|
||||||
if (!circ->cpath->extend_info->onion_key)
|
if (!circuit_has_usable_onion_key(circ)) {
|
||||||
return 1; /* our hand is forced: only a create_fast will work. */
|
/* 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)) {
|
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
|
* Prefer to blend our circuit into the other circuits we are
|
||||||
* creating on behalf of others. */
|
* creating on behalf of others. */
|
||||||
return 0;
|
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;
|
&& 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>
|
/** 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>
|
* 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
|
static void
|
||||||
circuit_pick_create_handshake(uint8_t *cell_type_out,
|
circuit_pick_create_handshake(uint8_t *cell_type_out,
|
||||||
uint16_t *handshake_type_out,
|
uint16_t *handshake_type_out,
|
||||||
const extend_info_t *ei)
|
const extend_info_t *ei)
|
||||||
{
|
{
|
||||||
/* XXXX029 Remove support for deciding to use TAP. */
|
/* XXXX030 Remove support for deciding to use TAP. */
|
||||||
if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key,
|
if (extend_info_supports_ntor(ei)) {
|
||||||
CURVE25519_PUBKEY_LEN) &&
|
|
||||||
circuits_can_use_ntor()) {
|
|
||||||
*cell_type_out = CELL_CREATE2;
|
*cell_type_out = CELL_CREATE2;
|
||||||
*handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
|
*handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
|
||||||
return;
|
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,
|
* 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
|
* 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
|
* 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
|
static void
|
||||||
circuit_pick_extend_handshake(uint8_t *cell_type_out,
|
circuit_pick_extend_handshake(uint8_t *cell_type_out,
|
||||||
uint8_t *create_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;
|
uint8_t t;
|
||||||
circuit_pick_create_handshake(&t, handshake_type_out, ei);
|
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 &&
|
if (node_prev &&
|
||||||
*handshake_type_out != ONION_HANDSHAKE_TYPE_TAP &&
|
*handshake_type_out != ONION_HANDSHAKE_TYPE_TAP &&
|
||||||
(node_has_curve25519_onion_key(node_prev) ||
|
(node_has_curve25519_onion_key(node_prev) ||
|
||||||
(node_prev->rs && node_prev->rs->version_supports_extend2_cells))) {
|
(routerstatus_version_supports_ntor(node_prev->rs, 1)))) {
|
||||||
*cell_type_out = RELAY_COMMAND_EXTEND2;
|
*cell_type_out = RELAY_COMMAND_EXTEND2;
|
||||||
*create_cell_type_out = CELL_CREATE2;
|
*create_cell_type_out = CELL_CREATE2;
|
||||||
} else {
|
} else {
|
||||||
*cell_type_out = RELAY_COMMAND_EXTEND;
|
*cell_type_out = RELAY_COMMAND_EXTEND;
|
||||||
*create_cell_type_out = CELL_CREATE;
|
*create_cell_type_out = CELL_CREATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This is the backbone function for building circuits.
|
/** This is the backbone function for building circuits.
|
||||||
@ -2058,15 +2087,18 @@ count_acceptable_nodes(smartlist_t *nodes)
|
|||||||
if (! node->is_running)
|
if (! node->is_running)
|
||||||
// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i);
|
// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i);
|
||||||
continue;
|
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)
|
if (! node->is_valid)
|
||||||
// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
|
// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
|
||||||
continue;
|
continue;
|
||||||
if (! node_has_descriptor(node))
|
if (! node_has_descriptor(node))
|
||||||
continue;
|
continue;
|
||||||
/* XXX This clause makes us count incorrectly: if AllowInvalidRouters
|
/* The node has a descriptor, so we can just check the ntor key directly */
|
||||||
* allows this node in some places, then we're getting an inaccurate
|
if (!node_has_curve25519_onion_key(node))
|
||||||
* count. For now, be conservative and don't count it. But later we
|
continue;
|
||||||
* should try to be smarter. */
|
|
||||||
++num;
|
++num;
|
||||||
} SMARTLIST_FOREACH_END(node);
|
} 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",
|
log_warn(LD_CIRC, "Could not choose valid address for %s",
|
||||||
node->ri ? node->ri->nickname : node->rs->nickname);
|
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)
|
if (valid_addr && node->ri)
|
||||||
return extend_info_new(node->ri->nickname,
|
return extend_info_new(node->ri->nickname,
|
||||||
node->identity,
|
node->identity,
|
||||||
@ -2441,3 +2481,65 @@ extend_info_addr_is_allowed(const tor_addr_t *addr)
|
|||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
|
@ -54,6 +54,11 @@ extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
|
|||||||
extend_info_t *extend_info_dup(extend_info_t *info);
|
extend_info_t *extend_info_dup(extend_info_t *info);
|
||||||
void extend_info_free(extend_info_t *info);
|
void extend_info_free(extend_info_t *info);
|
||||||
int extend_info_addr_is_allowed(const tor_addr_t *addr);
|
int extend_info_addr_is_allowed(const tor_addr_t *addr);
|
||||||
|
int extend_info_supports_tap(const extend_info_t* ei);
|
||||||
|
int extend_info_supports_ntor(const extend_info_t* ei);
|
||||||
|
int circuit_can_use_tap(const origin_circuit_t *circ);
|
||||||
|
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
|
||||||
|
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
|
||||||
const node_t *build_state_get_exit_node(cpath_build_state_t *state);
|
const node_t *build_state_get_exit_node(cpath_build_state_t *state);
|
||||||
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
|
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
|
||||||
|
|
||||||
|
@ -1613,7 +1613,8 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
|
|||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the number of hops in circuit's path. */
|
/** Return the number of hops in circuit's path. If circ has no entries,
|
||||||
|
* or is NULL, returns 0. */
|
||||||
int
|
int
|
||||||
circuit_get_cpath_len(origin_circuit_t *circ)
|
circuit_get_cpath_len(origin_circuit_t *circ)
|
||||||
{
|
{
|
||||||
@ -1629,7 +1630,8 @@ circuit_get_cpath_len(origin_circuit_t *circ)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Return the <b>hopnum</b>th hop in <b>circ</b>->cpath, or NULL if there
|
/** Return the <b>hopnum</b>th hop in <b>circ</b>->cpath, or NULL if there
|
||||||
* aren't that many hops in the list. */
|
* aren't that many hops in the list. <b>hopnum</b> starts at 1.
|
||||||
|
* Returns NULL if <b>hopnum</b> is 0 or negative. */
|
||||||
crypt_path_t *
|
crypt_path_t *
|
||||||
circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum)
|
circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum)
|
||||||
{
|
{
|
||||||
|
@ -438,7 +438,7 @@ static config_var_t option_vars_[] = {
|
|||||||
V(UseEntryGuardsAsDirGuards, BOOL, "1"),
|
V(UseEntryGuardsAsDirGuards, BOOL, "1"),
|
||||||
V(UseGuardFraction, AUTOBOOL, "auto"),
|
V(UseGuardFraction, AUTOBOOL, "auto"),
|
||||||
V(UseMicrodescriptors, AUTOBOOL, "auto"),
|
V(UseMicrodescriptors, AUTOBOOL, "auto"),
|
||||||
V(UseNTorHandshake, AUTOBOOL, "1"),
|
OBSOLETE("UseNTorHandshake"),
|
||||||
V(User, STRING, NULL),
|
V(User, STRING, NULL),
|
||||||
OBSOLETE("UserspaceIOCPBuffers"),
|
OBSOLETE("UserspaceIOCPBuffers"),
|
||||||
V(AuthDirSharedRandomness, BOOL, "1"),
|
V(AuthDirSharedRandomness, BOOL, "1"),
|
||||||
|
@ -255,6 +255,20 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
|
|||||||
return FP_REJECT;
|
return FP_REJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* dirserv_get_status_impl already rejects versions older than 0.2.4.18-rc,
|
||||||
|
* and onion_curve25519_pkey was introduced in 0.2.4.8-alpha.
|
||||||
|
* But just in case a relay doesn't provide or lies about its version, or
|
||||||
|
* doesn't include an ntor key in its descriptor, check that it exists,
|
||||||
|
* and is non-zero (clients check that it's non-zero before using it). */
|
||||||
|
if (!routerinfo_has_curve25519_onion_key(router)) {
|
||||||
|
log_fn(severity, LD_DIR,
|
||||||
|
"Descriptor from router %s is missing an ntor curve25519 onion "
|
||||||
|
"key.", router_describe(router));
|
||||||
|
if (msg)
|
||||||
|
*msg = "Missing ntor curve25519 onion key. Please upgrade!";
|
||||||
|
return FP_REJECT;
|
||||||
|
}
|
||||||
|
|
||||||
if (router->cache_info.signing_key_cert) {
|
if (router->cache_info.signing_key_cert) {
|
||||||
/* This has an ed25519 identity key. */
|
/* This has an ed25519 identity key. */
|
||||||
if (KEYPIN_MISMATCH ==
|
if (KEYPIN_MISMATCH ==
|
||||||
|
@ -2275,6 +2275,12 @@ client_would_use_router(const routerstatus_t *rs, time_t now,
|
|||||||
/* We'd drop it immediately for being too old. */
|
/* We'd drop it immediately for being too old. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!routerstatus_version_supports_ntor(rs, 1)) {
|
||||||
|
/* We'd ignore it because it doesn't support ntor.
|
||||||
|
* If we don't know the version, download the descriptor so we can
|
||||||
|
* check if it supports ntor. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1173,14 +1173,38 @@ node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return true iff <b>md</b> has a curve25519 onion key.
|
||||||
|
* Use node_has_curve25519_onion_key() instead of calling this directly. */
|
||||||
|
static int
|
||||||
|
microdesc_has_curve25519_onion_key(const microdesc_t *md)
|
||||||
|
{
|
||||||
|
if (!md) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!md->onion_curve25519_pkey) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tor_mem_is_zero((const char*)md->onion_curve25519_pkey->public_key,
|
||||||
|
CURVE25519_PUBKEY_LEN)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/** Return true iff <b>node</b> has a curve25519 onion key. */
|
/** Return true iff <b>node</b> has a curve25519 onion key. */
|
||||||
int
|
int
|
||||||
node_has_curve25519_onion_key(const node_t *node)
|
node_has_curve25519_onion_key(const node_t *node)
|
||||||
{
|
{
|
||||||
|
if (!node)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (node->ri)
|
if (node->ri)
|
||||||
return node->ri->onion_curve25519_pkey != NULL;
|
return routerinfo_has_curve25519_onion_key(node->ri);
|
||||||
else if (node->md)
|
else if (node->md)
|
||||||
return node->md->onion_curve25519_pkey != NULL;
|
return microdesc_has_curve25519_onion_key(node->md);
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
#include "circuitbuild.h"
|
||||||
#include "circuitlist.h"
|
#include "circuitlist.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "cpuworker.h"
|
#include "cpuworker.h"
|
||||||
@ -438,8 +439,7 @@ onion_skin_create(int type,
|
|||||||
r = CREATE_FAST_LEN;
|
r = CREATE_FAST_LEN;
|
||||||
break;
|
break;
|
||||||
case ONION_HANDSHAKE_TYPE_NTOR:
|
case ONION_HANDSHAKE_TYPE_NTOR:
|
||||||
if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key,
|
if (!extend_info_supports_ntor(node))
|
||||||
CURVE25519_PUBKEY_LEN))
|
|
||||||
return -1;
|
return -1;
|
||||||
if (onion_skin_ntor_create((const uint8_t*)node->identity_digest,
|
if (onion_skin_ntor_create((const uint8_t*)node->identity_digest,
|
||||||
&node->curve25519_onion_key,
|
&node->curve25519_onion_key,
|
||||||
|
@ -4384,9 +4384,6 @@ typedef struct {
|
|||||||
|
|
||||||
char *TLSECGroup; /**< One of "P256", "P224", or nil for auto */
|
char *TLSECGroup; /**< One of "P256", "P224", or nil for auto */
|
||||||
|
|
||||||
/** Autobool: should we use the ntor handshake if we can? */
|
|
||||||
int UseNTorHandshake;
|
|
||||||
|
|
||||||
/** Fraction: */
|
/** Fraction: */
|
||||||
double PathsNeededToBuildCircuits;
|
double PathsNeededToBuildCircuits;
|
||||||
|
|
||||||
|
@ -1368,8 +1368,13 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
|
|||||||
|
|
||||||
i = crypto_rand_int(smartlist_len(usable_nodes));
|
i = crypto_rand_int(smartlist_len(usable_nodes));
|
||||||
intro = smartlist_get(usable_nodes, i);
|
intro = smartlist_get(usable_nodes, i);
|
||||||
|
if (BUG(!intro->extend_info)) {
|
||||||
|
/* This should never happen, but it isn't fatal, just try another */
|
||||||
|
smartlist_del(usable_nodes, i);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
/* Do we need to look up the router or is the extend info complete? */
|
/* Do we need to look up the router or is the extend info complete? */
|
||||||
if (!intro->extend_info->onion_key) {
|
if (!extend_info_supports_tap(intro->extend_info)) {
|
||||||
const node_t *node;
|
const node_t *node;
|
||||||
extend_info_t *new_extend_info;
|
extend_info_t *new_extend_info;
|
||||||
if (tor_digest_is_zero(intro->extend_info->identity_digest))
|
if (tor_digest_is_zero(intro->extend_info->identity_digest))
|
||||||
|
@ -3896,3 +3896,11 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
|
|||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stub that should be replaced with the #17178 version of the function
|
||||||
|
* when merging. */
|
||||||
|
int
|
||||||
|
rend_service_allow_direct_connection(const or_options_t *options)
|
||||||
|
{
|
||||||
|
(void)options;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -131,5 +131,7 @@ void directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
|
|||||||
const char *service_id, int seconds_valid);
|
const char *service_id, int seconds_valid);
|
||||||
void rend_service_desc_has_uploaded(const rend_data_t *rend_data);
|
void rend_service_desc_has_uploaded(const rend_data_t *rend_data);
|
||||||
|
|
||||||
|
int rend_service_allow_direct_connection(const or_options_t *options);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2836,6 +2836,10 @@ router_dump_router_to_string(routerinfo_t *router,
|
|||||||
(const char *)router->onion_curve25519_pkey->public_key,
|
(const char *)router->onion_curve25519_pkey->public_key,
|
||||||
CURVE25519_PUBKEY_LEN, BASE64_ENCODE_MULTILINE);
|
CURVE25519_PUBKEY_LEN, BASE64_ENCODE_MULTILINE);
|
||||||
smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
|
smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
|
||||||
|
} else {
|
||||||
|
/* Authorities will start rejecting relays without ntor keys in 0.2.9 */
|
||||||
|
log_err(LD_BUG, "A relay must have an ntor onion key");
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the exit policy to the end of 's'. */
|
/* Write the exit policy to the end of 's'. */
|
||||||
|
@ -2260,10 +2260,16 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
|
|||||||
continue;
|
continue;
|
||||||
if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
|
if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
|
||||||
continue;
|
continue;
|
||||||
/* Choose a node with an OR address that matches the firewall rules,
|
/* Don't choose nodes if we are certain they can't do ntor */
|
||||||
* if we are making a direct connection */
|
if (node->rs && !routerstatus_version_supports_ntor(node->rs, 1))
|
||||||
|
continue;
|
||||||
|
if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
|
||||||
|
continue;
|
||||||
|
/* Choose a node with an OR address that matches the firewall rules */
|
||||||
if (direct_conn && check_reach &&
|
if (direct_conn && check_reach &&
|
||||||
!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, pref_addr))
|
!fascist_firewall_allows_node(node,
|
||||||
|
FIREWALL_OR_CONNECTION,
|
||||||
|
pref_addr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
smartlist_add(sl, (void *)node);
|
smartlist_add(sl, (void *)node);
|
||||||
@ -5497,6 +5503,45 @@ routerinfo_incompatible_with_extrainfo(const crypto_pk_t *identity_pkey,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Does ri have a valid ntor onion key?
|
||||||
|
* Valid ntor onion keys exist and have at least one non-zero byte. */
|
||||||
|
int
|
||||||
|
routerinfo_has_curve25519_onion_key(const routerinfo_t *ri)
|
||||||
|
{
|
||||||
|
if (!ri) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ri->onion_curve25519_pkey) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tor_mem_is_zero((const char*)ri->onion_curve25519_pkey->public_key,
|
||||||
|
CURVE25519_PUBKEY_LEN)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is rs running a tor version known to support ntor?
|
||||||
|
* If allow_unknown_versions is true, return true if the version is unknown.
|
||||||
|
* Otherwise, return false if the version is unknown. */
|
||||||
|
int
|
||||||
|
routerstatus_version_supports_ntor(const routerstatus_t *rs,
|
||||||
|
int allow_unknown_versions)
|
||||||
|
{
|
||||||
|
if (!rs) {
|
||||||
|
return allow_unknown_versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rs->version_known) {
|
||||||
|
return allow_unknown_versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs->version_supports_extend2_cells;
|
||||||
|
}
|
||||||
|
|
||||||
/** Assert that the internal representation of <b>rl</b> is
|
/** Assert that the internal representation of <b>rl</b> is
|
||||||
* self-consistent. */
|
* self-consistent. */
|
||||||
void
|
void
|
||||||
|
@ -206,6 +206,9 @@ int routerinfo_incompatible_with_extrainfo(const crypto_pk_t *ri,
|
|||||||
extrainfo_t *ei,
|
extrainfo_t *ei,
|
||||||
signed_descriptor_t *sd,
|
signed_descriptor_t *sd,
|
||||||
const char **msg);
|
const char **msg);
|
||||||
|
int routerinfo_has_curve25519_onion_key(const routerinfo_t *ri);
|
||||||
|
int routerstatus_version_supports_ntor(const routerstatus_t *rs,
|
||||||
|
int allow_unknown_versions);
|
||||||
|
|
||||||
void routerlist_assert_ok(const routerlist_t *rl);
|
void routerlist_assert_ok(const routerlist_t *rl);
|
||||||
const char *esc_router_info(const routerinfo_t *router);
|
const char *esc_router_info(const routerinfo_t *router);
|
||||||
|
@ -116,6 +116,7 @@ test_dir_formats(void *arg)
|
|||||||
const addr_policy_t *p;
|
const addr_policy_t *p;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
port_cfg_t orport, dirport;
|
port_cfg_t orport, dirport;
|
||||||
|
char cert_buf[256];
|
||||||
|
|
||||||
(void)arg;
|
(void)arg;
|
||||||
pk1 = pk_generate(0);
|
pk1 = pk_generate(0);
|
||||||
@ -135,6 +136,11 @@ test_dir_formats(void *arg)
|
|||||||
tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
|
tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
|
||||||
r1->ipv6_orport = 9999;
|
r1->ipv6_orport = 9999;
|
||||||
r1->onion_pkey = crypto_pk_dup_key(pk1);
|
r1->onion_pkey = crypto_pk_dup_key(pk1);
|
||||||
|
/* Fake just enough of an ntor key to get by */
|
||||||
|
curve25519_keypair_t r1_onion_keypair;
|
||||||
|
curve25519_keypair_generate(&r1_onion_keypair, 0);
|
||||||
|
r1->onion_curve25519_pkey = tor_memdup(&r1_onion_keypair.pubkey,
|
||||||
|
sizeof(curve25519_public_key_t));
|
||||||
r1->identity_pkey = crypto_pk_dup_key(pk2);
|
r1->identity_pkey = crypto_pk_dup_key(pk2);
|
||||||
r1->bandwidthrate = 1000;
|
r1->bandwidthrate = 1000;
|
||||||
r1->bandwidthburst = 5000;
|
r1->bandwidthburst = 5000;
|
||||||
@ -167,11 +173,6 @@ test_dir_formats(void *arg)
|
|||||||
&kp2.pubkey,
|
&kp2.pubkey,
|
||||||
now, 86400,
|
now, 86400,
|
||||||
CERT_FLAG_INCLUDE_SIGNING_KEY);
|
CERT_FLAG_INCLUDE_SIGNING_KEY);
|
||||||
char cert_buf[256];
|
|
||||||
base64_encode(cert_buf, sizeof(cert_buf),
|
|
||||||
(const char*)r2->cache_info.signing_key_cert->encoded,
|
|
||||||
r2->cache_info.signing_key_cert->encoded_len,
|
|
||||||
BASE64_ENCODE_MULTILINE);
|
|
||||||
r2->platform = tor_strdup(platform);
|
r2->platform = tor_strdup(platform);
|
||||||
r2->cache_info.published_on = 5;
|
r2->cache_info.published_on = 5;
|
||||||
r2->or_port = 9005;
|
r2->or_port = 9005;
|
||||||
@ -247,6 +248,11 @@ test_dir_formats(void *arg)
|
|||||||
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
|
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
|
||||||
strlcat(buf2, "contact Magri White <magri@elsewhere.example.com>\n",
|
strlcat(buf2, "contact Magri White <magri@elsewhere.example.com>\n",
|
||||||
sizeof(buf2));
|
sizeof(buf2));
|
||||||
|
strlcat(buf2, "ntor-onion-key ", sizeof(buf2));
|
||||||
|
base64_encode(cert_buf, sizeof(cert_buf),
|
||||||
|
(const char*)r1_onion_keypair.pubkey.public_key, 32,
|
||||||
|
BASE64_ENCODE_MULTILINE);
|
||||||
|
strlcat(buf2, cert_buf, sizeof(buf2));
|
||||||
strlcat(buf2, "reject *:*\n", sizeof(buf2));
|
strlcat(buf2, "reject *:*\n", sizeof(buf2));
|
||||||
strlcat(buf2, "tunnelled-dir-server\nrouter-signature\n", sizeof(buf2));
|
strlcat(buf2, "tunnelled-dir-server\nrouter-signature\n", sizeof(buf2));
|
||||||
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
|
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
|
||||||
@ -276,6 +282,10 @@ test_dir_formats(void *arg)
|
|||||||
"router Fred 10.3.2.1 9005 0 0\n"
|
"router Fred 10.3.2.1 9005 0 0\n"
|
||||||
"identity-ed25519\n"
|
"identity-ed25519\n"
|
||||||
"-----BEGIN ED25519 CERT-----\n", sizeof(buf2));
|
"-----BEGIN ED25519 CERT-----\n", sizeof(buf2));
|
||||||
|
base64_encode(cert_buf, sizeof(cert_buf),
|
||||||
|
(const char*)r2->cache_info.signing_key_cert->encoded,
|
||||||
|
r2->cache_info.signing_key_cert->encoded_len,
|
||||||
|
BASE64_ENCODE_MULTILINE);
|
||||||
strlcat(buf2, cert_buf, sizeof(buf2));
|
strlcat(buf2, cert_buf, sizeof(buf2));
|
||||||
strlcat(buf2, "-----END ED25519 CERT-----\n", sizeof(buf2));
|
strlcat(buf2, "-----END ED25519 CERT-----\n", sizeof(buf2));
|
||||||
strlcat(buf2, "master-key-ed25519 ", sizeof(buf2));
|
strlcat(buf2, "master-key-ed25519 ", sizeof(buf2));
|
||||||
|
Loading…
Reference in New Issue
Block a user