aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/or/connection_or.c41
-rw-r--r--src/test/test_link_handshake.c4
2 files changed, 44 insertions, 1 deletions
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 953e9df251..088900ccec 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -75,6 +75,9 @@ static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn);
static void connection_or_change_state(or_connection_t *conn, uint8_t state);
+static void connection_or_check_canonicity(or_connection_t *conn,
+ int started_here);
+
/**************************************************************/
/** Global map between Extended ORPort identifiers and OR
@@ -869,13 +872,38 @@ connection_or_init_conn_from_address(or_connection_t *conn,
ed25519_fmt(ed_id),
started_here);
- const node_t *r = node_get_by_id(id_digest);
connection_or_set_identity_digest(conn, id_digest, ed_id);
connection_or_update_token_buckets_helper(conn, 1, get_options());
conn->base_.port = port;
tor_addr_copy(&conn->base_.addr, addr);
tor_addr_copy(&conn->real_addr, addr);
+
+ connection_or_check_canonicity(conn, started_here);
+}
+
+/** Check whether the identity of <b>conn</b> matches a known node. If it
+ * does, check whether the address of conn matches the expected address, and
+ * update the connection's is_canonical flag, nickname, and address fields as
+ * appropriate. */
+static void
+connection_or_check_canonicity(or_connection_t *conn, int started_here)
+{
+ const char *id_digest = conn->identity_digest;
+ const ed25519_public_key_t *ed_id = NULL;
+ const tor_addr_t *addr = &conn->real_addr;
+ if (conn->chan)
+ ed_id = & TLS_CHAN_TO_BASE(conn->chan)->ed25519_identity;
+
+ const node_t *r = node_get_by_id(id_digest);
+ if (r &&
+ node_supports_ed25519_link_authentication(r) &&
+ ! node_ed25519_id_matches(r, ed_id)) {
+ /* If this node is capable of proving an ed25519 ID,
+ * we can't call this a canonical connection unless both IDs match. */
+ r = NULL;
+ }
+
if (r) {
tor_addr_port_t node_ap;
node_get_pref_orport(r, &node_ap);
@@ -897,10 +925,12 @@ connection_or_init_conn_from_address(or_connection_t *conn,
tor_addr_copy(&conn->base_.addr, &node_ap.addr);
conn->base_.port = node_ap.port;
}
+ tor_free(conn->nickname);
conn->nickname = tor_strdup(node_get_nickname(r));
tor_free(conn->base_.address);
conn->base_.address = tor_addr_to_str_dup(&node_ap.addr);
} else {
+ tor_free(conn->nickname);
conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
conn->nickname[0] = '$';
base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
@@ -1589,6 +1619,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
const or_options_t *options = get_options();
channel_tls_t *chan_tls = conn->chan;
channel_t *chan = channel_tls_to_base(chan_tls);
+ int changed_identity = 0;
tor_assert(chan);
const int expected_rsa_key =
@@ -1619,6 +1650,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
* we do -- remember it for future attempts. */
learned_router_identity(&conn->base_.addr, conn->base_.port,
(const char*)rsa_peer_id, ed_peer_id);
+ changed_identity = 1;
}
const int rsa_mismatch = expected_rsa_key &&
@@ -1706,6 +1738,13 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
"connection.");
connection_or_set_identity_digest(conn,
(const char*)rsa_peer_id, ed_peer_id);
+ changed_identity = 1;
+ }
+
+ if (changed_identity) {
+ /* If we learned an identity for this connection, then we might have
+ * just discovered it to be canonical. */
+ connection_or_check_canonicity(conn, conn->handshake_state->started_here);
}
if (authdir_mode_tests_reachability(options)) {
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index 9931702a34..421f3aaedf 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -117,6 +117,9 @@ test_link_handshake_certs_ok(void *arg)
crypto_pk_t *key1 = NULL, *key2 = NULL;
const int with_ed = !strcmp((const char *)arg, "Ed25519");
+ tor_addr_from_ipv4h(&c1->base_.addr, 0x7f000001);
+ tor_addr_from_ipv4h(&c2->base_.addr, 0x7f000001);
+
scheduler_init();
MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
@@ -354,6 +357,7 @@ recv_certs_setup(const struct testcase_t *test)
d->chan = tor_malloc_zero(sizeof(*d->chan));
d->c->chan = d->chan;
d->c->base_.address = tor_strdup("HaveAnAddress");
+ tor_addr_from_ipv4h(&d->c->base_.addr, 0x801f0127);
d->c->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
d->chan->conn = d->c;
tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0);