diff options
Diffstat (limited to 'src/core/or/connection_or.c')
-rw-r--r-- | src/core/or/connection_or.c | 861 |
1 files changed, 191 insertions, 670 deletions
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c index 67157d8d0b..b88d1b6afb 100644 --- a/src/core/or/connection_or.c +++ b/src/core/or/connection_or.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,17 +18,19 @@ * tortls.c) which it uses as its TLS stream. It is responsible for * sending and receiving cells over that TLS. * - * This module also implements the client side of the v3 Tor link handshake, + * This module also implements the client side of the v3 (and greater) Tor + * link handshake. **/ #include "core/or/or.h" #include "feature/client/bridges.h" -#include "lib/container/buffers.h" +#include "lib/buf/buffers.h" /* * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ -#define TOR_CHANNEL_INTERNAL_ +#define CHANNEL_OBJECT_PRIVATE #define CONNECTION_OR_PRIVATE +#define ORCONN_EVENT_PRIVATE #include "core/or/channel.h" #include "core/or/channeltls.h" #include "core/or/circuitbuild.h" @@ -38,14 +40,14 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" #include "core/or/connection_or.h" -#include "feature/control/control.h" -#include "lib/crypt_ops/crypto_rand.h" +#include "feature/relay/relay_handshake.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/dirauth/reachability.h" #include "feature/client/entrynodes.h" #include "lib/geoip/geoip.h" #include "core/mainloop/mainloop.h" -#include "trunnel/link_handshake.h" +#include "trunnel/netinfo.h" #include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" @@ -76,7 +78,8 @@ #include "lib/crypt_ops/crypto_format.h" #include "lib/tls/tortls.h" -#include "lib/tls/x509.h" + +#include "core/or/orconn_event.h" static int connection_tls_finish_handshake(or_connection_t *conn); static int connection_or_launch_v3_or_handshake(or_connection_t *conn); @@ -91,13 +94,6 @@ static unsigned int connection_or_is_bad_for_new_circs(or_connection_t *or_conn); static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn); -/* - * Call this when changing connection state, so notifications to the owning - * channel can be handled. - */ - -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); @@ -112,10 +108,6 @@ TO_OR_CONN(connection_t *c) return DOWNCAST(or_connection_t, c); } -/** Global map between Extended ORPort identifiers and OR - * connections. */ -static digestmap_t *orconn_ext_or_id_map = NULL; - /** Clear clear conn->identity_digest and update other data * structures as appropriate.*/ void @@ -201,71 +193,6 @@ connection_or_set_identity_digest(or_connection_t *conn, channel_set_identity_digest(chan, rsa_digest, ed_id); } -/** Remove the Extended ORPort identifier of <b>conn</b> from the - * global identifier list. Also, clear the identifier from the - * connection itself. */ -void -connection_or_remove_from_ext_or_id_map(or_connection_t *conn) -{ - or_connection_t *tmp; - if (!orconn_ext_or_id_map) - return; - if (!conn->ext_or_conn_id) - return; - - tmp = digestmap_remove(orconn_ext_or_id_map, conn->ext_or_conn_id); - if (!tor_digest_is_zero(conn->ext_or_conn_id)) - tor_assert(tmp == conn); - - memset(conn->ext_or_conn_id, 0, EXT_OR_CONN_ID_LEN); -} - -/** Return the connection whose ext_or_id is <b>id</b>. Return NULL if no such - * connection is found. */ -or_connection_t * -connection_or_get_by_ext_or_id(const char *id) -{ - if (!orconn_ext_or_id_map) - return NULL; - return digestmap_get(orconn_ext_or_id_map, id); -} - -/** Deallocate the global Extended ORPort identifier list */ -void -connection_or_clear_ext_or_id_map(void) -{ - digestmap_free(orconn_ext_or_id_map, NULL); - orconn_ext_or_id_map = NULL; -} - -/** Creates an Extended ORPort identifier for <b>conn</b> and deposits - * it into the global list of identifiers. */ -void -connection_or_set_ext_or_identifier(or_connection_t *conn) -{ - char random_id[EXT_OR_CONN_ID_LEN]; - or_connection_t *tmp; - - if (!orconn_ext_or_id_map) - orconn_ext_or_id_map = digestmap_new(); - - /* Remove any previous identifiers: */ - if (conn->ext_or_conn_id && !tor_digest_is_zero(conn->ext_or_conn_id)) - connection_or_remove_from_ext_or_id_map(conn); - - do { - crypto_rand(random_id, sizeof(random_id)); - } while (digestmap_get(orconn_ext_or_id_map, random_id)); - - if (!conn->ext_or_conn_id) - conn->ext_or_conn_id = tor_malloc_zero(EXT_OR_CONN_ID_LEN); - - memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN); - - tmp = digestmap_set(orconn_ext_or_id_map, random_id, conn); - tor_assert(!tmp); -} - /**************************************************************/ /** Map from a string describing what a non-open OR connection was doing when @@ -400,23 +327,69 @@ connection_or_report_broken_states(int severity, int domain) smartlist_free(items); } +/** + * Helper function to publish an OR connection status event + * + * Publishes a messages to subscribers of ORCONN messages, and sends + * the control event. + **/ +void +connection_or_event_status(or_connection_t *conn, or_conn_status_event_t tp, + int reason) +{ + orconn_status_msg_t *msg = tor_malloc(sizeof(*msg)); + + msg->gid = conn->base_.global_identifier; + msg->status = tp; + msg->reason = reason; + orconn_status_publish(msg); + control_event_or_conn_status(conn, tp, reason); +} + +/** + * Helper function to publish a state change message + * + * connection_or_change_state() calls this to notify subscribers about + * a change of an OR connection state. + **/ +static void +connection_or_state_publish(const or_connection_t *conn, uint8_t state) +{ + orconn_state_msg_t *msg = tor_malloc(sizeof(*msg)); + + msg->gid = conn->base_.global_identifier; + if (conn->is_pt) { + /* Do extra decoding because conn->proxy_type indicates the proxy + * protocol that tor uses to talk with the transport plugin, + * instead of PROXY_PLUGGABLE. */ + tor_assert_nonfatal(conn->proxy_type != PROXY_NONE); + msg->proxy_type = PROXY_PLUGGABLE; + } else { + msg->proxy_type = conn->proxy_type; + } + msg->state = state; + if (conn->chan) { + msg->chan = TLS_CHAN_TO_BASE(conn->chan)->global_identifier; + } else { + msg->chan = 0; + } + orconn_state_publish(msg); +} + /** Call this to change or_connection_t states, so the owning channel_tls_t can * be notified. */ -static void -connection_or_change_state(or_connection_t *conn, uint8_t state) +MOCK_IMPL(STATIC void, +connection_or_change_state,(or_connection_t *conn, uint8_t state)) { - uint8_t old_state; - tor_assert(conn); - old_state = conn->base_.state; conn->base_.state = state; + connection_or_state_publish(conn, state); if (conn->chan) - channel_tls_handle_state_change_on_orconn(conn->chan, conn, - old_state, state); + channel_tls_handle_state_change_on_orconn(conn->chan, conn, state); } /** Return the number of circuits using an or_connection_t; this used to @@ -676,6 +649,19 @@ connection_or_finished_flushing(or_connection_t *conn) switch (conn->base_.state) { case OR_CONN_STATE_PROXY_HANDSHAKING: + /* PROXY_HAPROXY gets connected by receiving an ack. */ + if (conn->proxy_type == PROXY_HAPROXY) { + tor_assert(TO_CONN(conn)->proxy_state == PROXY_HAPROXY_WAIT_FOR_FLUSH); + TO_CONN(conn)->proxy_state = PROXY_CONNECTED; + + if (connection_tls_start_handshake(conn, 0) < 0) { + /* TLS handshaking error of some kind. */ + connection_or_close_for_error(conn, 0); + return -1; + } + break; + } + break; case OR_CONN_STATE_OPEN: case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: @@ -707,8 +693,6 @@ connection_or_finished_connecting(or_connection_t *or_conn) log_debug(LD_HANDSHAKE,"OR connect() to router at %s:%u finished.", conn->address,conn->port); - control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0); - control_event_boot_first_orconn(); if (proxy_type != PROXY_NONE) { /* start proxy handshake */ @@ -717,8 +701,9 @@ connection_or_finished_connecting(or_connection_t *or_conn) return -1; } - connection_start_reading(conn); connection_or_change_state(or_conn, OR_CONN_STATE_PROXY_HANDSHAKING); + connection_start_reading(conn); + return 0; } @@ -758,21 +743,27 @@ connection_or_about_to_close(or_connection_t *or_conn) entry_guard_chan_failed(TLS_CHAN_TO_BASE(or_conn->chan)); if (conn->state >= OR_CONN_STATE_TLS_HANDSHAKING) { int reason = tls_error_to_orconn_end_reason(or_conn->tls_error); - control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED, - reason); - if (!authdir_mode_tests_reachability(options)) - control_event_bootstrap_prob_or( - orconn_end_reason_to_control_string(reason), - reason, or_conn); + connection_or_event_status(or_conn, OR_CONN_EVENT_FAILED, + reason); + if (!authdir_mode_tests_reachability(options)) { + const char *warning = NULL; + if (reason == END_OR_CONN_REASON_TLS_ERROR && or_conn->tls) { + warning = tor_tls_get_last_error_msg(or_conn->tls); + } + if (warning == NULL) { + warning = orconn_end_reason_to_control_string(reason); + } + control_event_bootstrap_prob_or(warning, reason, or_conn); + } } } } else if (conn->hold_open_until_flushed) { /* We only set hold_open_until_flushed when we're intentionally * closing a connection. */ - control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED, + connection_or_event_status(or_conn, OR_CONN_EVENT_CLOSED, tls_error_to_orconn_end_reason(or_conn->tls_error)); } else if (!tor_digest_is_zero(or_conn->identity_digest)) { - control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED, + connection_or_event_status(or_conn, OR_CONN_EVENT_CLOSED, tls_error_to_orconn_end_reason(or_conn->tls_error)); } } @@ -918,12 +909,21 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here) } if (r) { - tor_addr_port_t node_ap; - node_get_pref_orport(r, &node_ap); - /* XXXX proposal 186 is making this more complex. For now, a conn - is canonical when it uses the _preferred_ address. */ - if (tor_addr_eq(&conn->base_.addr, &node_ap.addr)) + tor_addr_port_t node_ipv4_ap; + tor_addr_port_t node_ipv6_ap; + node_get_prim_orport(r, &node_ipv4_ap); + node_get_pref_ipv6_orport(r, &node_ipv6_ap); + if (tor_addr_eq(&conn->base_.addr, &node_ipv4_ap.addr) || + tor_addr_eq(&conn->base_.addr, &node_ipv6_ap.addr)) { connection_or_set_canonical(conn, 1); + } + /* Choose the correct canonical address and port. */ + tor_addr_port_t *node_ap; + if (tor_addr_family(&conn->base_.addr) == AF_INET) { + node_ap = &node_ipv4_ap; + } else { + node_ap = &node_ipv6_ap; + } if (!started_here) { /* Override the addr/port, so our log messages will make sense. * This is dangerous, since if we ever try looking up a conn by @@ -935,13 +935,14 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here) * right IP address and port 56244, that wouldn't be as helpful. now we * log the "right" port too, so we know if it's moria1 or moria2. */ - tor_addr_copy(&conn->base_.addr, &node_ap.addr); - conn->base_.port = node_ap.port; + /* See #33898 for a ticket that resolves this technical debt. */ + 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); + conn->base_.address = tor_addr_to_str_dup(&node_ap->addr); } else { tor_free(conn->nickname); conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); @@ -1229,11 +1230,11 @@ or_connect_failure_ht_hash(const or_connect_failure_entry_t *entry) } HT_PROTOTYPE(or_connect_failure_ht, or_connect_failure_entry_t, node, - or_connect_failure_ht_hash, or_connect_failure_ht_eq) + or_connect_failure_ht_hash, or_connect_failure_ht_eq); HT_GENERATE2(or_connect_failure_ht, or_connect_failure_entry_t, node, or_connect_failure_ht_hash, or_connect_failure_ht_eq, - 0.6, tor_reallocarray_, tor_free_) + 0.6, tor_reallocarray_, tor_free_); /* Initialize a given connect failure entry with the given identity_digest, * addr and port. All field are optional except ocf. */ @@ -1364,7 +1365,7 @@ void connection_or_connect_failed(or_connection_t *conn, int reason, const char *msg) { - control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, reason); + connection_or_event_status(conn, OR_CONN_EVENT_FAILED, reason); if (!authdir_mode_tests_reachability(get_options())) control_event_bootstrap_prob_or(msg, reason, conn); note_or_connect_failed(conn); @@ -1430,7 +1431,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port, int r; tor_addr_t proxy_addr; uint16_t proxy_port; - int proxy_type; + int proxy_type, is_pt = 0; tor_assert(_addr); tor_assert(id_digest); @@ -1471,21 +1472,27 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port, return NULL; } - connection_or_change_state(conn, OR_CONN_STATE_CONNECTING); - control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0); - conn->is_outgoing = 1; /* If we are using a proxy server, find it and use it. */ - r = get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, TO_CONN(conn)); + r = get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, &is_pt, + TO_CONN(conn)); if (r == 0) { conn->proxy_type = proxy_type; if (proxy_type != PROXY_NONE) { tor_addr_copy(&addr, &proxy_addr); port = proxy_port; conn->base_.proxy_state = PROXY_INFANT; + conn->is_pt = is_pt; } + connection_or_change_state(conn, OR_CONN_STATE_CONNECTING); + connection_or_event_status(conn, OR_CONN_EVENT_LAUNCHED, 0); } else { + /* This duplication of state change calls is necessary in case we + * run into an error condition below */ + connection_or_change_state(conn, OR_CONN_STATE_CONNECTING); + connection_or_event_status(conn, OR_CONN_EVENT_LAUNCHED, 0); + /* get_proxy_addrport() might fail if we have a Bridge line that references a transport, but no ClientTransportPlugin lines defining its transport proxy. If this is the case, let's try to @@ -1691,7 +1698,8 @@ connection_tls_continue_handshake(or_connection_t *conn) switch (result) { CASE_TOR_TLS_ERROR_ANY: - log_info(LD_OR,"tls error [%s]. breaking connection.", + conn->tls_error = result; + log_info(LD_OR,"tls error [%s]. breaking connection.", tor_tls_err_to_string(result)); return -1; case TOR_TLS_DONE: @@ -1723,6 +1731,7 @@ connection_tls_continue_handshake(or_connection_t *conn) log_debug(LD_OR,"wanted read"); return 0; case TOR_TLS_CLOSE: + conn->tls_error = result; log_info(LD_OR,"tls closed. breaking connection."); return -1; } @@ -1981,8 +1990,8 @@ connection_or_client_learned_peer_id(or_connection_t *conn, /* Tell the new guard API about the channel failure */ entry_guard_chan_failed(TLS_CHAN_TO_BASE(conn->chan)); - control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, - END_OR_CONN_REASON_OR_IDENTITY); + connection_or_event_status(conn, OR_CONN_EVENT_FAILED, + END_OR_CONN_REASON_OR_IDENTITY); if (!authdir_mode_tests_reachability(options)) control_event_bootstrap_prob_or( "Unexpected identity in router certificate", @@ -2222,7 +2231,7 @@ int connection_or_set_state_open(or_connection_t *conn) { connection_or_change_state(conn, OR_CONN_STATE_OPEN); - control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED, 0); + connection_or_event_status(conn, OR_CONN_EVENT_CONNECTED, 0); /* Link protocol 3 appeared in Tor 0.2.3.6-alpha, so any connection * that uses an earlier link protocol should not be treated as a relay. */ @@ -2252,6 +2261,8 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn) cell_pack(&networkcell, cell, conn->wide_circ_ids); + /* We need to count padding cells from this non-packed code path + * since they are sent via chan->write_cell() (which is not packed) */ rep_hist_padding_count_write(PADDING_TYPE_TOTAL); if (cell->command == CELL_PADDING) rep_hist_padding_count_write(PADDING_TYPE_CELL); @@ -2262,7 +2273,7 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn) if (conn->chan) { channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); - if (TLS_CHAN_TO_BASE(conn->chan)->currently_padding) { + if (TLS_CHAN_TO_BASE(conn->chan)->padding_enabled) { rep_hist_padding_count_write(PADDING_TYPE_ENABLED_TOTAL); if (cell->command == CELL_PADDING) rep_hist_padding_count_write(PADDING_TYPE_ENABLED_CELL); @@ -2292,6 +2303,7 @@ connection_or_write_var_cell_to_buf,(const var_cell_t *cell, if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) or_handshake_state_record_var_cell(conn, conn->handshake_state, cell, 0); + rep_hist_padding_count_write(PADDING_TYPE_TOTAL); /* Touch the channel's active timestamp if there is one */ if (conn->chan) channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); @@ -2428,6 +2440,31 @@ connection_or_send_versions(or_connection_t *conn, int v3_plus) return 0; } +static netinfo_addr_t * +netinfo_addr_from_tor_addr(const tor_addr_t *tor_addr) +{ + sa_family_t addr_family = tor_addr_family(tor_addr); + + if (BUG(addr_family != AF_INET && addr_family != AF_INET6)) + return NULL; + + netinfo_addr_t *netinfo_addr = netinfo_addr_new(); + + if (addr_family == AF_INET) { + netinfo_addr_set_addr_type(netinfo_addr, NETINFO_ADDR_TYPE_IPV4); + netinfo_addr_set_len(netinfo_addr, 4); + netinfo_addr_set_addr_ipv4(netinfo_addr, tor_addr_to_ipv4h(tor_addr)); + } else if (addr_family == AF_INET6) { + netinfo_addr_set_addr_type(netinfo_addr, NETINFO_ADDR_TYPE_IPV6); + netinfo_addr_set_len(netinfo_addr, 16); + uint8_t *ipv6_buf = netinfo_addr_getarray_addr_ipv6(netinfo_addr); + const uint8_t *in6_addr = tor_addr_to_in6_addr8(tor_addr); + memcpy(ipv6_buf, in6_addr, 16); + } + + return netinfo_addr; +} + /** Send a NETINFO cell on <b>conn</b>, telling the other server what we know * about their address, our address, and the current time. */ MOCK_IMPL(int, @@ -2436,8 +2473,7 @@ connection_or_send_netinfo,(or_connection_t *conn)) cell_t cell; time_t now = time(NULL); const routerinfo_t *me; - int len; - uint8_t *out; + int r = -1; tor_assert(conn->handshake_state); @@ -2450,20 +2486,21 @@ connection_or_send_netinfo,(or_connection_t *conn)) memset(&cell, 0, sizeof(cell_t)); cell.command = CELL_NETINFO; + netinfo_cell_t *netinfo_cell = netinfo_cell_new(); + /* Timestamp, if we're a relay. */ if (public_server_mode(get_options()) || ! conn->is_outgoing) - set_uint32(cell.payload, htonl((uint32_t)now)); + netinfo_cell_set_timestamp(netinfo_cell, (uint32_t)now); /* Their address. */ - out = cell.payload + 4; + const tor_addr_t *remote_tor_addr = + !tor_addr_is_null(&conn->real_addr) ? &conn->real_addr : &conn->base_.addr; /* We use &conn->real_addr below, unless it hasn't yet been set. If it * hasn't yet been set, we know that base_.addr hasn't been tampered with * yet either. */ - len = append_address_to_payload(out, !tor_addr_is_null(&conn->real_addr) - ? &conn->real_addr : &conn->base_.addr); - if (len<0) - return -1; - out += len; + netinfo_addr_t *their_addr = netinfo_addr_from_tor_addr(remote_tor_addr); + + netinfo_cell_set_other_addr(netinfo_cell, their_addr); /* My address -- only include it if I'm a public relay, or if I'm a * bridge and this is an incoming connection. If I'm a bridge and this @@ -2471,556 +2508,40 @@ connection_or_send_netinfo,(or_connection_t *conn)) if ((public_server_mode(get_options()) || !conn->is_outgoing) && (me = router_get_my_routerinfo())) { tor_addr_t my_addr; - *out++ = 1 + !tor_addr_is_null(&me->ipv6_addr); - tor_addr_from_ipv4h(&my_addr, me->addr); - len = append_address_to_payload(out, &my_addr); - if (len < 0) - return -1; - out += len; - - if (!tor_addr_is_null(&me->ipv6_addr)) { - len = append_address_to_payload(out, &me->ipv6_addr); - if (len < 0) - return -1; - } - } else { - *out = 0; - } - - conn->handshake_state->digest_sent_data = 0; - conn->handshake_state->sent_netinfo = 1; - connection_or_write_cell_to_buf(&cell, conn); - - return 0; -} - -/** Helper used to add an encoded certs to a cert cell */ -static void -add_certs_cell_cert_helper(certs_cell_t *certs_cell, - uint8_t cert_type, - const uint8_t *cert_encoded, - size_t cert_len) -{ - tor_assert(cert_len <= UINT16_MAX); - certs_cell_cert_t *ccc = certs_cell_cert_new(); - ccc->cert_type = cert_type; - ccc->cert_len = cert_len; - certs_cell_cert_setlen_body(ccc, cert_len); - memcpy(certs_cell_cert_getarray_body(ccc), cert_encoded, cert_len); - - certs_cell_add_certs(certs_cell, ccc); -} - -/** Add an encoded X509 cert (stored as <b>cert_len</b> bytes at - * <b>cert_encoded</b>) to the trunnel certs_cell_t object that we are - * building in <b>certs_cell</b>. Set its type field to <b>cert_type</b>. - * (If <b>cert</b> is NULL, take no action.) */ -static void -add_x509_cert(certs_cell_t *certs_cell, - uint8_t cert_type, - const tor_x509_cert_t *cert) -{ - if (NULL == cert) - return; - const uint8_t *cert_encoded = NULL; - size_t cert_len; - tor_x509_cert_get_der(cert, &cert_encoded, &cert_len); + uint8_t n_my_addrs = 1 + !tor_addr_is_null(&me->ipv6_addr); + netinfo_cell_set_n_my_addrs(netinfo_cell, n_my_addrs); - add_certs_cell_cert_helper(certs_cell, cert_type, cert_encoded, cert_len); -} + netinfo_cell_add_my_addrs(netinfo_cell, + netinfo_addr_from_tor_addr(&my_addr)); -/** Add an Ed25519 cert from <b>cert</b> to the trunnel certs_cell_t object - * that we are building in <b>certs_cell</b>. Set its type field to - * <b>cert_type</b>. (If <b>cert</b> is NULL, take no action.) */ -static void -add_ed25519_cert(certs_cell_t *certs_cell, - uint8_t cert_type, - const tor_cert_t *cert) -{ - if (NULL == cert) - return; - - add_certs_cell_cert_helper(certs_cell, cert_type, - cert->encoded, cert->encoded_len); -} - -#ifdef TOR_UNIT_TESTS -int certs_cell_ed25519_disabled_for_testing = 0; -#else -#define certs_cell_ed25519_disabled_for_testing 0 -#endif - -/** Send a CERTS cell on the connection <b>conn</b>. Return 0 on success, -1 - * on failure. */ -int -connection_or_send_certs_cell(or_connection_t *conn) -{ - const tor_x509_cert_t *global_link_cert = NULL, *id_cert = NULL; - tor_x509_cert_t *own_link_cert = NULL; - var_cell_t *cell; - - certs_cell_t *certs_cell = NULL; - - tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3); - - if (! conn->handshake_state) - return -1; - - const int conn_in_server_mode = ! conn->handshake_state->started_here; - - /* Get the encoded values of the X509 certificates */ - if (tor_tls_get_my_certs(conn_in_server_mode, - &global_link_cert, &id_cert) < 0) - return -1; - - if (conn_in_server_mode) { - own_link_cert = tor_tls_get_own_cert(conn->tls); - } - tor_assert(id_cert); - - certs_cell = certs_cell_new(); - - /* Start adding certs. First the link cert or auth1024 cert. */ - if (conn_in_server_mode) { - tor_assert_nonfatal(own_link_cert); - add_x509_cert(certs_cell, - OR_CERT_TYPE_TLS_LINK, own_link_cert); - } else { - tor_assert(global_link_cert); - add_x509_cert(certs_cell, - OR_CERT_TYPE_AUTH_1024, global_link_cert); - } - - /* Next the RSA->RSA ID cert */ - add_x509_cert(certs_cell, - OR_CERT_TYPE_ID_1024, id_cert); - - /* Next the Ed25519 certs */ - add_ed25519_cert(certs_cell, - CERTTYPE_ED_ID_SIGN, - get_master_signing_key_cert()); - if (conn_in_server_mode) { - tor_assert_nonfatal(conn->handshake_state->own_link_cert || - certs_cell_ed25519_disabled_for_testing); - add_ed25519_cert(certs_cell, - CERTTYPE_ED_SIGN_LINK, - conn->handshake_state->own_link_cert); - } else { - add_ed25519_cert(certs_cell, - CERTTYPE_ED_SIGN_AUTH, - get_current_auth_key_cert()); - } - - /* And finally the crosscert. */ - { - const uint8_t *crosscert=NULL; - size_t crosscert_len; - get_master_rsa_crosscert(&crosscert, &crosscert_len); - if (crosscert) { - add_certs_cell_cert_helper(certs_cell, - CERTTYPE_RSA1024_ID_EDID, - crosscert, crosscert_len); + if (!tor_addr_is_null(&me->ipv6_addr)) { + netinfo_cell_add_my_addrs(netinfo_cell, + netinfo_addr_from_tor_addr(&me->ipv6_addr)); } } - /* We've added all the certs; make the cell. */ - certs_cell->n_certs = certs_cell_getlen_certs(certs_cell); - - ssize_t alloc_len = certs_cell_encoded_len(certs_cell); - tor_assert(alloc_len >= 0 && alloc_len <= UINT16_MAX); - cell = var_cell_new(alloc_len); - cell->command = CELL_CERTS; - ssize_t enc_len = certs_cell_encode(cell->payload, alloc_len, certs_cell); - tor_assert(enc_len > 0 && enc_len <= alloc_len); - cell->payload_len = enc_len; - - connection_or_write_var_cell_to_buf(cell, conn); - var_cell_free(cell); - certs_cell_free(certs_cell); - tor_x509_cert_free(own_link_cert); - - return 0; -} - -#ifdef TOR_UNIT_TESTS -int testing__connection_or_pretend_TLSSECRET_is_supported = 0; -#else -#define testing__connection_or_pretend_TLSSECRET_is_supported 0 -#endif - -/** Return true iff <b>challenge_type</b> is an AUTHCHALLENGE type that - * we can send and receive. */ -int -authchallenge_type_is_supported(uint16_t challenge_type) -{ - switch (challenge_type) { - case AUTHTYPE_RSA_SHA256_TLSSECRET: -#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS - return 1; -#else - return testing__connection_or_pretend_TLSSECRET_is_supported; -#endif - case AUTHTYPE_ED25519_SHA256_RFC5705: - return 1; - case AUTHTYPE_RSA_SHA256_RFC5705: - default: - return 0; + const char *errmsg = NULL; + if ((errmsg = netinfo_cell_check(netinfo_cell))) { + log_warn(LD_OR, "Failed to validate NETINFO cell with error: %s", + errmsg); + goto cleanup; } -} - -/** Return true iff <b>challenge_type_a</b> is one that we would rather - * use than <b>challenge_type_b</b>. */ -int -authchallenge_type_is_better(uint16_t challenge_type_a, - uint16_t challenge_type_b) -{ - /* Any supported type is better than an unsupported one; - * all unsupported types are equally bad. */ - if (!authchallenge_type_is_supported(challenge_type_a)) - return 0; - if (!authchallenge_type_is_supported(challenge_type_b)) - return 1; - /* It happens that types are superior in numerically ascending order. - * If that ever changes, this must change too. */ - return (challenge_type_a > challenge_type_b); -} - -/** Send an AUTH_CHALLENGE cell on the connection <b>conn</b>. Return 0 - * on success, -1 on failure. */ -int -connection_or_send_auth_challenge_cell(or_connection_t *conn) -{ - var_cell_t *cell = NULL; - int r = -1; - tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3); - - if (! conn->handshake_state) - return -1; - - auth_challenge_cell_t *ac = auth_challenge_cell_new(); - tor_assert(sizeof(ac->challenge) == 32); - crypto_rand((char*)ac->challenge, sizeof(ac->challenge)); - - if (authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET)) - auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET); - /* Disabled, because everything that supports this method also supports - * the much-superior ED25519_SHA256_RFC5705 */ - /* auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_RFC5705); */ - if (authchallenge_type_is_supported(AUTHTYPE_ED25519_SHA256_RFC5705)) - auth_challenge_cell_add_methods(ac, AUTHTYPE_ED25519_SHA256_RFC5705); - auth_challenge_cell_set_n_methods(ac, - auth_challenge_cell_getlen_methods(ac)); - - cell = var_cell_new(auth_challenge_cell_encoded_len(ac)); - ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len, - ac); - if (len != cell->payload_len) { - /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Encoded auth challenge cell length not as expected"); - goto done; - /* LCOV_EXCL_STOP */ + if (netinfo_cell_encode(cell.payload, CELL_PAYLOAD_SIZE, + netinfo_cell) < 0) { + log_warn(LD_OR, "Failed generating NETINFO cell"); + goto cleanup; } - cell->command = CELL_AUTH_CHALLENGE; - connection_or_write_var_cell_to_buf(cell, conn); - r = 0; + conn->handshake_state->digest_sent_data = 0; + conn->handshake_state->sent_netinfo = 1; + connection_or_write_cell_to_buf(&cell, conn); - done: - var_cell_free(cell); - auth_challenge_cell_free(ac); + r = 0; + cleanup: + netinfo_cell_free(netinfo_cell); return r; } - -/** Compute the main body of an AUTHENTICATE cell that a client can use - * to authenticate itself on a v3 handshake for <b>conn</b>. Return it - * in a var_cell_t. - * - * If <b>server</b> is true, only calculate the first - * V3_AUTH_FIXED_PART_LEN bytes -- the part of the authenticator that's - * determined by the rest of the handshake, and which match the provided value - * exactly. - * - * If <b>server</b> is false and <b>signing_key</b> is NULL, calculate the - * first V3_AUTH_BODY_LEN bytes of the authenticator (that is, everything - * that should be signed), but don't actually sign it. - * - * If <b>server</b> is false and <b>signing_key</b> is provided, calculate the - * entire authenticator, signed with <b>signing_key</b>. - * - * Return the length of the cell body on success, and -1 on failure. - */ -var_cell_t * -connection_or_compute_authenticate_cell_body(or_connection_t *conn, - const int authtype, - crypto_pk_t *signing_key, - const ed25519_keypair_t *ed_signing_key, - int server) -{ - auth1_t *auth = NULL; - auth_ctx_t *ctx = auth_ctx_new(); - var_cell_t *result = NULL; - int old_tlssecrets_algorithm = 0; - const char *authtype_str = NULL; - - int is_ed = 0; - - /* assert state is reasonable XXXX */ - switch (authtype) { - case AUTHTYPE_RSA_SHA256_TLSSECRET: - authtype_str = "AUTH0001"; - old_tlssecrets_algorithm = 1; - break; - case AUTHTYPE_RSA_SHA256_RFC5705: - authtype_str = "AUTH0002"; - break; - case AUTHTYPE_ED25519_SHA256_RFC5705: - authtype_str = "AUTH0003"; - is_ed = 1; - break; - default: - tor_assert(0); - break; - } - - auth = auth1_new(); - ctx->is_ed = is_ed; - - /* Type: 8 bytes. */ - memcpy(auth1_getarray_type(auth), authtype_str, 8); - - { - const tor_x509_cert_t *id_cert=NULL; - const common_digests_t *my_digests, *their_digests; - const uint8_t *my_id, *their_id, *client_id, *server_id; - if (tor_tls_get_my_certs(server, NULL, &id_cert)) - goto err; - my_digests = tor_x509_cert_get_id_digests(id_cert); - their_digests = - tor_x509_cert_get_id_digests(conn->handshake_state->certs->id_cert); - tor_assert(my_digests); - tor_assert(their_digests); - my_id = (uint8_t*)my_digests->d[DIGEST_SHA256]; - their_id = (uint8_t*)their_digests->d[DIGEST_SHA256]; - - client_id = server ? their_id : my_id; - server_id = server ? my_id : their_id; - - /* Client ID digest: 32 octets. */ - memcpy(auth->cid, client_id, 32); - - /* Server ID digest: 32 octets. */ - memcpy(auth->sid, server_id, 32); - } - - if (is_ed) { - const ed25519_public_key_t *my_ed_id, *their_ed_id; - if (!conn->handshake_state->certs->ed_id_sign) { - log_warn(LD_OR, "Ed authenticate without Ed ID cert from peer."); - goto err; - } - my_ed_id = get_master_identity_key(); - their_ed_id = &conn->handshake_state->certs->ed_id_sign->signing_key; - - const uint8_t *cid_ed = (server ? their_ed_id : my_ed_id)->pubkey; - const uint8_t *sid_ed = (server ? my_ed_id : their_ed_id)->pubkey; - - memcpy(auth->u1_cid_ed, cid_ed, ED25519_PUBKEY_LEN); - memcpy(auth->u1_sid_ed, sid_ed, ED25519_PUBKEY_LEN); - } - - { - crypto_digest_t *server_d, *client_d; - if (server) { - server_d = conn->handshake_state->digest_sent; - client_d = conn->handshake_state->digest_received; - } else { - client_d = conn->handshake_state->digest_sent; - server_d = conn->handshake_state->digest_received; - } - - /* Server log digest : 32 octets */ - crypto_digest_get_digest(server_d, (char*)auth->slog, 32); - - /* Client log digest : 32 octets */ - crypto_digest_get_digest(client_d, (char*)auth->clog, 32); - } - - { - /* Digest of cert used on TLS link : 32 octets. */ - tor_x509_cert_t *cert = NULL; - if (server) { - cert = tor_tls_get_own_cert(conn->tls); - } else { - cert = tor_tls_get_peer_cert(conn->tls); - } - if (!cert) { - log_warn(LD_OR, "Unable to find cert when making %s data.", - authtype_str); - goto err; - } - - memcpy(auth->scert, - tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32); - - tor_x509_cert_free(cert); - } - - /* HMAC of clientrandom and serverrandom using master key : 32 octets */ - if (old_tlssecrets_algorithm) { - if (tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets) < 0) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Somebody asked us for an older TLS " - "authentication method (AUTHTYPE_RSA_SHA256_TLSSECRET) " - "which we don't support."); - } - } else { - char label[128]; - tor_snprintf(label, sizeof(label), - "EXPORTER FOR TOR TLS CLIENT BINDING %s", authtype_str); - int r = tor_tls_export_key_material(conn->tls, auth->tlssecrets, - auth->cid, sizeof(auth->cid), - label); - if (r < 0) { - if (r != -2) - log_warn(LD_BUG, "TLS key export failed for unknown reason."); - // If r == -2, this was openssl bug 7712. - goto err; - } - } - - /* 8 octets were reserved for the current time, but we're trying to get out - * of the habit of sending time around willynilly. Fortunately, nothing - * checks it. That's followed by 16 bytes of nonce. */ - crypto_rand((char*)auth->rand, 24); - - ssize_t maxlen = auth1_encoded_len(auth, ctx); - if (ed_signing_key && is_ed) { - maxlen += ED25519_SIG_LEN; - } else if (signing_key && !is_ed) { - maxlen += crypto_pk_keysize(signing_key); - } - - const int AUTH_CELL_HEADER_LEN = 4; /* 2 bytes of type, 2 bytes of length */ - result = var_cell_new(AUTH_CELL_HEADER_LEN + maxlen); - uint8_t *const out = result->payload + AUTH_CELL_HEADER_LEN; - const size_t outlen = maxlen; - ssize_t len; - - result->command = CELL_AUTHENTICATE; - set_uint16(result->payload, htons(authtype)); - - if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) { - /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Unable to encode signed part of AUTH1 data."); - goto err; - /* LCOV_EXCL_STOP */ - } - - if (server) { - auth1_t *tmp = NULL; - ssize_t len2 = auth1_parse(&tmp, out, len, ctx); - if (!tmp) { - /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Unable to parse signed part of AUTH1 data that " - "we just encoded"); - goto err; - /* LCOV_EXCL_STOP */ - } - result->payload_len = (tmp->end_of_signed - result->payload); - - auth1_free(tmp); - if (len2 != len) { - /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Mismatched length when re-parsing AUTH1 data."); - goto err; - /* LCOV_EXCL_STOP */ - } - goto done; - } - - if (ed_signing_key && is_ed) { - ed25519_signature_t sig; - if (ed25519_sign(&sig, out, len, ed_signing_key) < 0) { - /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Unable to sign ed25519 authentication data"); - goto err; - /* LCOV_EXCL_STOP */ - } - auth1_setlen_sig(auth, ED25519_SIG_LEN); - memcpy(auth1_getarray_sig(auth), sig.sig, ED25519_SIG_LEN); - - } else if (signing_key && !is_ed) { - auth1_setlen_sig(auth, crypto_pk_keysize(signing_key)); - - char d[32]; - crypto_digest256(d, (char*)out, len, DIGEST_SHA256); - int siglen = crypto_pk_private_sign(signing_key, - (char*)auth1_getarray_sig(auth), - auth1_getlen_sig(auth), - d, 32); - if (siglen < 0) { - log_warn(LD_OR, "Unable to sign AUTH1 data."); - goto err; - } - - auth1_setlen_sig(auth, siglen); - } - - len = auth1_encode(out, outlen, auth, ctx); - if (len < 0) { - /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Unable to encode signed AUTH1 data."); - goto err; - /* LCOV_EXCL_STOP */ - } - tor_assert(len + AUTH_CELL_HEADER_LEN <= result->payload_len); - result->payload_len = len + AUTH_CELL_HEADER_LEN; - set_uint16(result->payload+2, htons(len)); - - goto done; - - err: - var_cell_free(result); - result = NULL; - done: - auth1_free(auth); - auth_ctx_free(ctx); - return result; -} - -/** Send an AUTHENTICATE cell on the connection <b>conn</b>. Return 0 on - * success, -1 on failure */ -MOCK_IMPL(int, -connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype)) -{ - var_cell_t *cell; - crypto_pk_t *pk = tor_tls_get_my_client_auth_key(); - /* XXXX make sure we're actually supposed to send this! */ - - if (!pk) { - log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key"); - return -1; - } - if (! authchallenge_type_is_supported(authtype)) { - log_warn(LD_BUG, "Tried to send authenticate cell with unknown " - "authentication type %d", authtype); - return -1; - } - - cell = connection_or_compute_authenticate_cell_body(conn, - authtype, - pk, - get_current_auth_keypair(), - 0 /* not server */); - if (! cell) { - log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unable to compute authenticate cell!"); - return -1; - } - connection_or_write_var_cell_to_buf(cell, conn); - var_cell_free(cell); - - return 0; -} |