tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit e952b56820f932cb37a7dca71a3fb1f54cd3f114
parent d57d00143c7fb45733e7f92b4e2d02d3b47ee10a
Author: Nick Mathewson <nickm@torproject.org>
Date:   Thu, 24 Apr 2025 14:06:12 -0400

Completely remove support for the v2 link handshake

The v2 link handshake was one of the silliest things we ever did:
in an attempt to avoid sending our funny-looking certs back and forth,
we would first negotiate with a dummy set of certs and ciphers,
and then renegotiate with the ciphersuites we _really_ wanted.

We removed client-side support for this handshake back in
0.2.8.1-alpha, with ticket 11150.

Diffstat:
Msrc/core/mainloop/connection.c | 11+++--------
Msrc/core/or/channeltls.c | 34+---------------------------------
Msrc/core/or/connection_or.c | 193+++----------------------------------------------------------------------------
Msrc/core/or/connection_or.h | 1-
Msrc/core/or/orconn_event.h | 8+-------
Msrc/core/or/protover.c | 2+-
Msrc/feature/control/btrack_orconn_cevent.c | 4----
Msrc/lib/tls/tortls.h | 7-------
Msrc/lib/tls/tortls_nss.c | 33---------------------------------
Msrc/lib/tls/tortls_openssl.c | 188+++----------------------------------------------------------------------------
Msrc/lib/tls/tortls_st.h | 7-------
Msrc/test/test_protover.c | 6+++---
Msrc/test/test_tortls.c | 18------------------
13 files changed, 19 insertions(+), 493 deletions(-)

diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c @@ -314,12 +314,8 @@ conn_state_to_string(int type, int state) case OR_CONN_STATE_CONNECTING: return "connect()ing"; case OR_CONN_STATE_PROXY_HANDSHAKING: return "handshaking (proxy)"; case OR_CONN_STATE_TLS_HANDSHAKING: return "handshaking (TLS)"; - case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING: - return "renegotiating (TLS, v2 handshake)"; case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: return "waiting for renegotiation or V3 handshake"; - case OR_CONN_STATE_OR_HANDSHAKING_V2: - return "handshaking (Tor, v2 handshake)"; case OR_CONN_STATE_OR_HANDSHAKING_V3: return "handshaking (Tor, v3 handshake)"; case OR_CONN_STATE_OPEN: return "open"; @@ -4163,8 +4159,7 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read, int pending; or_connection_t *or_conn = TO_OR_CONN(conn); size_t initial_size; - if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || - conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { + if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING) { /* continue handshaking even if global token bucket is empty */ return connection_tls_continue_handshake(or_conn); } @@ -4206,6 +4201,7 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read, * again. Stop waiting for write events now, or else we'll * busy-loop until data arrives for us to read. * XXX: remove this when v2 handshakes support is dropped. */ + // XXXX Try to make sense of what is going on here. connection_stop_writing(conn); if (!connection_is_reading(conn)) connection_start_reading(conn); @@ -4493,8 +4489,7 @@ connection_handle_write_impl(connection_t *conn, int force) conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) { or_connection_t *or_conn = TO_OR_CONN(conn); size_t initial_size; - if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || - conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { + if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING) { connection_stop_writing(conn); if (connection_tls_continue_handshake(or_conn) < 0) { /* Don't flush; connection is dead. */ diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c @@ -1238,26 +1238,6 @@ channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn) return; switch (TO_CONN(conn)->state) { - case OR_CONN_STATE_OR_HANDSHAKING_V2: - if (var_cell->command != CELL_VERSIONS) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received a cell with command %d in unexpected " - "orconn state \"%s\" [%d], channel state \"%s\" [%d]; " - "closing the connection.", - (int)(var_cell->command), - conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state), - TO_CONN(conn)->state, - channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state), - (int)(TLS_CHAN_TO_BASE(chan)->state)); - /* - * The code in connection_or.c will tell channel_t to close for - * error; it will go to CHANNEL_STATE_CLOSING, and then to - * CHANNEL_STATE_ERROR when conn is closed. - */ - connection_or_close_for_error(conn, 0); - return; - } - break; case OR_CONN_STATE_TLS_HANDSHAKING: /* If we're using bufferevents, it's entirely possible for us to * notice "hey, data arrived!" before we notice "hey, the handshake @@ -1443,7 +1423,6 @@ enter_v3_handshake_with_cell(var_cell_t *cell, channel_tls_t *chan) "Received a cell while TLS-handshaking, not in " "OR_HANDSHAKING_V3, on a connection we originated."); } - connection_or_block_renegotiation(chan->conn); connection_or_change_state(chan->conn, OR_CONN_STATE_OR_HANDSHAKING_V3); if (connection_init_or_handshake_state(chan->conn, started_here) < 0) { connection_or_close_for_error(chan->conn, 0); @@ -1494,7 +1473,6 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) } switch (chan->conn->base_.state) { - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: break; case OR_CONN_STATE_TLS_HANDSHAKING: @@ -1537,15 +1515,6 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) "handshake. Closing connection."); connection_or_close_for_error(chan->conn, 0); return; - } else if (highest_supported_version != 2 && - chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V2) { - /* XXXX This should eventually be a log_protocol_warn */ - log_fn(LOG_WARN, LD_OR, - "Negotiated link with non-2 protocol after doing a v2 TLS " - "handshake with %s. Closing connection.", - connection_describe_peer(TO_CONN(chan->conn))); - connection_or_close_for_error(chan->conn, 0); - return; } rep_hist_note_negotiated_link_proto(highest_supported_version, started_here); @@ -1733,8 +1702,7 @@ can_process_netinfo_cell(const channel_tls_t *chan) } /* Can't process a NETINFO cell if the connection is not handshaking. */ - if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 && - chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) { + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) { log_fn(LOG_PROTOCOL_WARN, LD_OR, "Received a NETINFO cell on non-handshaking connection; dropping."); return false; diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c @@ -83,14 +83,8 @@ #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); static int connection_or_process_cells_from_inbuf(or_connection_t *conn); -static int connection_or_check_valid_tls_handshake(or_connection_t *conn, - int started_here, - char *digest_rcvd_out); - -static void connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn); static unsigned int connection_or_is_bad_for_new_circs(or_connection_t *or_conn); @@ -602,9 +596,7 @@ connection_or_process_inbuf(or_connection_t *conn) } return ret; - case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: case OR_CONN_STATE_OPEN: - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: return connection_or_process_cells_from_inbuf(conn); default: @@ -708,7 +700,6 @@ connection_or_finished_flushing(or_connection_t *conn) } break; case OR_CONN_STATE_OPEN: - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: break; default: @@ -1690,35 +1681,6 @@ connection_tls_start_handshake,(or_connection_t *conn, int receiving)) return 0; } -/** Block all future attempts to renegotiate on 'conn' */ -void -connection_or_block_renegotiation(or_connection_t *conn) -{ - tor_tls_t *tls = conn->tls; - if (!tls) - return; - tor_tls_set_renegotiate_callback(tls, NULL, NULL); - tor_tls_block_renegotiation(tls); -} - -/** Invoked on the server side from inside tor_tls_read() when the server - * gets a successful TLS renegotiation from the client. */ -static void -connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn) -{ - or_connection_t *conn = _conn; - (void)tls; - - /* Don't invoke this again. */ - connection_or_block_renegotiation(conn); - - if (connection_tls_finish_handshake(conn) < 0) { - /* XXXX_TLS double-check that it's ok to do this from inside read. */ - /* XXXX_TLS double-check that this verifies certificates. */ - connection_or_close_for_error(conn, 0); - } -} - /** Move forward with the tls handshake. If it finishes, hand * <b>conn</b> to connection_tls_finish_handshake(). * @@ -1747,21 +1709,16 @@ connection_tls_continue_handshake(or_connection_t *conn) tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING); return connection_or_launch_v3_or_handshake(conn); } else { - /* v2/v3 handshake, but we are not a client. */ + /* v3 handshake, but we are not a client. */ log_debug(LD_OR, "Done with initial SSL handshake (server-side). " - "Expecting renegotiation or VERSIONS cell"); - tor_tls_set_renegotiate_callback(conn->tls, - connection_or_tls_renegotiated_cb, - conn); + "Expecting VERSIONS cell"); connection_or_change_state(conn, - OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); + OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); connection_stop_writing(TO_CONN(conn)); connection_start_reading(TO_CONN(conn)); return 0; } } - tor_assert(tor_tls_is_server(conn->tls)); - return connection_tls_finish_handshake(conn); case TOR_TLS_WANTWRITE: connection_start_writing(TO_CONN(conn)); log_debug(LD_OR,"wanted write"); @@ -1792,102 +1749,6 @@ connection_or_nonopen_was_started_here(or_connection_t *conn) return !tor_tls_is_server(conn->tls); } -/** <b>Conn</b> just completed its handshake. Return 0 if all is well, and - * return -1 if they are lying, broken, or otherwise something is wrong. - * - * If we initiated this connection (<b>started_here</b> is true), make sure - * the other side sent a correctly formed certificate. If I initiated the - * connection, make sure it's the right relay by checking the certificate. - * - * Otherwise (if we _didn't_ initiate this connection), it's okay for - * the certificate to be weird or absent. - * - * If we return 0, and the certificate is as expected, write a hash of the - * identity key into <b>digest_rcvd_out</b>, which must have DIGEST_LEN - * space in it. - * If the certificate is invalid or missing on an incoming connection, - * we return 0 and set <b>digest_rcvd_out</b> to DIGEST_LEN NUL bytes. - * (If we return -1, the contents of this buffer are undefined.) - * - * As side effects, - * 1) Set conn->circ_id_type according to tor-spec.txt. - * 2) If we're an authdirserver and we initiated the connection: drop all - * descriptors that claim to be on that IP/port but that aren't - * this relay; and note that this relay is reachable. - * 3) If this is a bridge and we didn't configure its identity - * fingerprint, remember the keyid we just learned. - */ -static int -connection_or_check_valid_tls_handshake(or_connection_t *conn, - int started_here, - char *digest_rcvd_out) -{ - crypto_pk_t *identity_rcvd=NULL; - const or_options_t *options = get_options(); - int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; - const char *conn_type = started_here ? "outgoing" : "incoming"; - int has_cert = 0; - - check_no_tls_errors(); - has_cert = tor_tls_peer_has_cert(conn->tls); - if (started_here && !has_cert) { - log_info(LD_HANDSHAKE,"Tried connecting to router at %s, but it didn't " - "send a cert! Closing.", - connection_describe_peer(TO_CONN(conn))); - return -1; - } else if (!has_cert) { - log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. " - "That's ok."); - } - check_no_tls_errors(); - - if (has_cert) { - int v = tor_tls_verify(started_here?severity:LOG_INFO, - conn->tls, time(NULL), &identity_rcvd); - if (started_here && v<0) { - log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s: It" - " has a cert but it's invalid. Closing.", - connection_describe_peer(TO_CONN(conn))); - return -1; - } else if (v<0) { - log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert " - "chain; ignoring."); - } else { - log_debug(LD_HANDSHAKE, - "The certificate seems to be valid on %s connection " - "with %s", conn_type, - connection_describe_peer(TO_CONN(conn))); - } - check_no_tls_errors(); - } - - if (identity_rcvd) { - if (crypto_pk_get_digest(identity_rcvd, digest_rcvd_out) < 0) { - crypto_pk_free(identity_rcvd); - return -1; - } - } else { - memset(digest_rcvd_out, 0, DIGEST_LEN); - } - - tor_assert(conn->chan); - channel_set_circid_type(TLS_CHAN_TO_BASE(conn->chan), identity_rcvd, 1); - - crypto_pk_free(identity_rcvd); - - if (started_here) { - /* A TLS handshake can't teach us an Ed25519 ID, so we set it to NULL - * here. */ - log_debug(LD_HANDSHAKE, "Calling client_learned_peer_id from " - "check_valid_tls_handshake"); - return connection_or_client_learned_peer_id(conn, - (const uint8_t*)digest_rcvd_out, - NULL); - } - - return 0; -} - /** Called when we (as a connection initiator) have definitively, * authenticatedly, learned that ID of the Tor instance on the other * side of <b>conn</b> is <b>rsa_peer_id</b> and optionally <b>ed_peer_id</b>. @@ -2079,50 +1940,6 @@ connection_or_client_used(or_connection_t *conn) } else return 0; } -/** The v1/v2 TLS handshake is finished. - * - * Make sure we are happy with the peer we just handshaked with. - * - * If they initiated the connection, make sure they're not already connected, - * then initialize conn from the information in router. - * - * If all is successful, call circuit_n_conn_done() to handle events - * that have been pending on the <tls handshake completion. Also set the - * directory to be dirty (only matters if I'm an authdirserver). - * - * If this is a v2 TLS handshake, send a versions cell. - */ -static int -connection_tls_finish_handshake(or_connection_t *conn) -{ - char digest_rcvd[DIGEST_LEN]; - int started_here = connection_or_nonopen_was_started_here(conn); - - tor_assert(!started_here); - - log_debug(LD_HANDSHAKE,"%s tls handshake on %s done, using " - "ciphersuite %s. verifying.", - started_here?"outgoing":"incoming", - connection_describe_peer(TO_CONN(conn)), - tor_tls_get_ciphersuite_name(conn->tls)); - - if (connection_or_check_valid_tls_handshake(conn, started_here, - digest_rcvd) < 0) - return -1; - - circuit_build_times_network_is_live(get_circuit_build_times_mutable()); - - { - connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2); - if (connection_init_or_handshake_state(conn, started_here) < 0) - return -1; - connection_or_init_conn_from_address(conn, &conn->base_.addr, - conn->base_.port, digest_rcvd, - NULL, 0); - return connection_or_send_versions(conn, 0); - } -} - /** * Called as client when initial TLS handshake is done, and we notice * that we got a v3-handshake signalling certificate from the server. @@ -2419,8 +2236,8 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn) } } -/** Array of recognized link protocol versions. */ -static const uint16_t or_protocol_versions[] = { 1, 2, 3, 4, 5 }; +/** Array of supported link protocol versions. */ +static const uint16_t or_protocol_versions[] = { 3, 4, 5 }; /** Number of versions in <b>or_protocol_versions</b>. */ static const int n_or_protocol_versions = (int)( sizeof(or_protocol_versions)/sizeof(uint16_t) ); diff --git a/src/core/or/connection_or.h b/src/core/or/connection_or.h @@ -24,7 +24,6 @@ void connection_or_clear_identity(or_connection_t *conn); void connection_or_clear_identity_map(void); void clear_broken_connection_map(int disable); -void connection_or_block_renegotiation(or_connection_t *conn); int connection_or_reached_eof(or_connection_t *conn); int connection_or_process_inbuf(or_connection_t *conn); ssize_t connection_or_num_cells_writeable(or_connection_t *conn); diff --git a/src/core/or/orconn_event.h b/src/core/or/orconn_event.h @@ -34,17 +34,11 @@ /** State for an OR connection client: SSL is handshaking, not done * yet. */ #define OR_CONN_STATE_TLS_HANDSHAKING 3 -/** State for a connection to an OR: We're doing a second SSL handshake for - * renegotiation purposes. (V2 handshake only.) */ -#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4 /** State for a connection at an OR: We're waiting for the client to * renegotiate (to indicate a v2 handshake) or send a versions cell (to * indicate a v3 handshake) */ +// XXXX Rename. #define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5 -/** State for an OR connection: We're done with our SSL handshake, we've done - * renegotiation, but we haven't yet negotiated link protocol versions and - * sent a netinfo cell. */ -#define OR_CONN_STATE_OR_HANDSHAKING_V2 6 /** State for an OR connection: We're done with our SSL handshake, but we * haven't yet negotiated link protocol versions, done a V3 handshake, and * sent a netinfo cell. */ diff --git a/src/core/or/protover.c b/src/core/or/protover.c @@ -395,7 +395,7 @@ protocol_list_supports_protocol_or_later(const char *list, #define PR_HSDIR_V "2" #define PR_HSINTRO_V "4-5" #define PR_HSREND_V "1-2" -#define PR_LINK_V "1-5" +#define PR_LINK_V "3-5" #define PR_LINKAUTH_V "3" #define PR_MICRODESC_V "1-3" #define PR_PADDING_V "2" diff --git a/src/feature/control/btrack_orconn_cevent.c b/src/feature/control/btrack_orconn_cevent.c @@ -86,8 +86,6 @@ bto_cevent_anyconn(const bt_orconn_t *bto) case OR_CONN_STATE_TLS_HANDSHAKING: control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE, 0); break; - case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING: - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0); break; @@ -140,8 +138,6 @@ bto_cevent_apconn(const bt_orconn_t *bto) case OR_CONN_STATE_TLS_HANDSHAKING: control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE, 0); break; - case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING: - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE, 0); break; diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h @@ -89,9 +89,6 @@ void tor_tls_context_decref(tor_tls_context_t *ctx); tor_tls_context_t *tor_tls_context_get(int is_server); tor_tls_t *tor_tls_new(tor_socket_t sock, int is_server); void tor_tls_set_logged_address(tor_tls_t *tls, const char *address); -void tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg); int tor_tls_is_server(tor_tls_t *tls); void tor_tls_release_socket(tor_tls_t *tls); void tor_tls_free_(tor_tls_t *tls); @@ -104,9 +101,6 @@ int tor_tls_verify(int severity, tor_tls_t *tls, time_t now, MOCK_DECL(int, tor_tls_read, (tor_tls_t *tls, char *cp, size_t len)); int tor_tls_write(tor_tls_t *tls, const char *cp, size_t n); int tor_tls_handshake(tor_tls_t *tls); -int tor_tls_finish_handshake(tor_tls_t *tls); -void tor_tls_unblock_renegotiation(tor_tls_t *tls); -void tor_tls_block_renegotiation(tor_tls_t *tls); int tor_tls_get_pending_bytes(tor_tls_t *tls); size_t tor_tls_get_forced_write_size(tor_tls_t *tls); @@ -120,7 +114,6 @@ int tor_tls_get_buffer_sizes(tor_tls_t *tls, MOCK_DECL(double, tls_get_write_overhead_ratio, (void)); int tor_tls_get_num_server_handshakes(tor_tls_t *tls); -int tor_tls_server_got_renegotiate(tor_tls_t *tls); MOCK_DECL(int,tor_tls_cert_matches_key,(const tor_tls_t *tls, const struct tor_x509_cert_t *cert)); MOCK_DECL(int,tor_tls_export_key_material,( diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c @@ -464,18 +464,6 @@ tor_tls_new(tor_socket_t sock, int is_server) return tls; } -void -tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg) -{ - tor_assert(tls); - (void)cb; - (void)arg; - - /* We don't support renegotiation-based TLS with NSS. */ -} - /** * Tell the TLS library that the underlying socket for <b>tls</b> has been * closed, and the library should not attempt to free that socket itself. @@ -636,20 +624,6 @@ tor_tls_finish_handshake(tor_tls_t *tls) return TOR_TLS_DONE; } -void -tor_tls_unblock_renegotiation(tor_tls_t *tls) -{ - tor_assert(tls); - /* We don't support renegotiation with NSS. */ -} - -void -tor_tls_block_renegotiation(tor_tls_t *tls) -{ - tor_assert(tls); - /* We don't support renegotiation with NSS. */ -} - int tor_tls_get_pending_bytes(tor_tls_t *tls) { @@ -713,13 +687,6 @@ tls_get_write_overhead_ratio, (void)) return 0.95; } -int -tor_tls_server_got_renegotiate(tor_tls_t *tls) -{ - tor_assert(tls); - return 0; /* We don't support renegotiation with NSS */ -} - MOCK_IMPL(int, tor_tls_cert_matches_key,(const tor_tls_t *tls, const struct tor_x509_cert_t *cert)) diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c @@ -88,17 +88,6 @@ ENABLE_GCC_WARNING("-Wredundant-decls") #define DISABLE_SSL3_HANDSHAKE #endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f') */ -/* We redefine these so that we can run correctly even if the vendor gives us - * a version of OpenSSL that does not match its header files. (Apple: I am - * looking at you.) - */ -#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION -#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L -#endif -#ifndef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION -#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010 -#endif - /** Set to true iff openssl bug 7712 has been detected. */ static int openssl_bug_7712_is_present = 0; @@ -611,13 +600,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, SSL_CTX_set_options(result->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif - /* Yes, we know what we are doing here. No, we do not treat a renegotiation - * as authenticating any earlier-received data. - */ - { - SSL_CTX_set_options(result->ctx, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); - } + SSL_CTX_set_options(result->ctx, SSL_OP_NO_RENEGOTIATION); /* Don't actually allow compression; it uses RAM and time, it makes TLS * vulnerable to CRIME-style attacks, and most of the data we transmit over @@ -740,7 +723,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, always_accept_verify_cb); } else { /* Don't send a certificate request at all if we're not a client. */ - SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_verify(result->ctx, SSL_VERIFY_NONE, NULL); } /* let us realloc bufs that we're writing from */ SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); @@ -983,59 +966,6 @@ tor_tls_classify_client_ciphers(const SSL *ssl, return res; } -/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection - * changes state. We use this: - * <ul><li>To alter the state of the handshake partway through, so we - * do not send or request extra certificates in v2 handshakes.</li> - * <li>To detect renegotiation</li></ul> - */ -void -tor_tls_server_info_callback(const SSL *ssl, int type, int val) -{ - tor_tls_t *tls; - (void) val; - - IF_BUG_ONCE(ssl == NULL) { - return; // LCOV_EXCL_LINE - } - - tor_tls_debug_state_callback(ssl, type, val); - - if (type != SSL_CB_ACCEPT_LOOP) - return; - - OSSL_HANDSHAKE_STATE ssl_state = SSL_get_state(ssl); - if (! STATE_IS_SW_SERVER_HELLO(ssl_state)) - return; - tls = tor_tls_get_by_ssl(ssl); - if (tls) { - /* Check whether we're watching for renegotiates. If so, this is one! */ - if (tls->negotiated_callback) - tls->got_renegotiate = 1; - } else { - log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); - return; - } - - /* Now check the cipher list. */ - { - if (tls->wasV2Handshake) - return; /* We already turned this stuff off for the first handshake; - * This is a renegotiation. */ - - /* Yes, we're casting away the const from ssl. This is very naughty of us. - * Let's hope openssl doesn't notice! */ - - if (tls) { - tls->wasV2Handshake = 1; - } else { - /* LCOV_EXCL_START this line is not reachable */ - log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); - /* LCOV_EXCL_STOP */ - } - } -} - /** Callback to get invoked on a server after we've read the list of ciphers * the client supports, but before we pick our own ciphersuite. * @@ -1151,11 +1081,8 @@ tor_tls_new(tor_socket_t sock, int isServer) log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu", result->last_read_count, result->last_write_count); } - if (isServer) { - SSL_set_info_callback(result->ssl, tor_tls_server_info_callback); - } else { - SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback); - } + + SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback); if (isServer) tor_tls_setup_session_secret_cb(result); @@ -1169,51 +1096,6 @@ tor_tls_new(tor_socket_t sock, int isServer) return result; } -/** Set <b>cb</b> to be called with argument <b>arg</b> whenever <b>tls</b> - * next gets a client-side renegotiate in the middle of a read. Do not - * invoke this function until <em>after</em> initial handshaking is done! - */ -void -tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg) -{ - tls->negotiated_callback = cb; - tls->callback_arg = arg; - tls->got_renegotiate = 0; - if (cb) { - SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback); - } else { - SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback); - } -} - -/** If this version of openssl requires it, turn on renegotiation on - * <b>tls</b>. - */ -void -tor_tls_unblock_renegotiation(tor_tls_t *tls) -{ - /* Yes, we know what we are doing here. No, we do not treat a renegotiation - * as authenticating any earlier-received data. */ - SSL_set_options(tls->ssl, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); -} - -/** If this version of openssl supports it, turn off renegotiation on - * <b>tls</b>. (Our protocol never requires this for security, but it's nice - * to use belt-and-suspenders here.) - */ -void -tor_tls_block_renegotiation(tor_tls_t *tls) -{ -#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG - tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; -#else - (void) tls; -#endif -} - /** * Tell the TLS library that the underlying socket for <b>tls</b> has been * closed, and the library should not attempt to free that socket itself. @@ -1263,13 +1145,6 @@ tor_tls_read,(tor_tls_t *tls, char *cp, size_t len)) tor_assert(len<INT_MAX); r = SSL_read(tls->ssl, cp, (int)len); if (r > 0) { - if (tls->got_renegotiate) { - /* Renegotiation happened! */ - log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls)); - if (tls->negotiated_callback) - tls->negotiated_callback(tls, tls->callback_arg); - tls->got_renegotiate = 0; - } return r; } err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET); @@ -1357,9 +1232,7 @@ tor_tls_handshake(tor_tls_t *tls) if (oldstate != newstate) log_debug(LD_HANDSHAKE, "After call, %p was in state %s", tls, SSL_state_string_long(tls->ssl)); - /* We need to call this here and not earlier, since OpenSSL has a penchant - * for clearing its flags when you say accept or connect. */ - tor_tls_unblock_renegotiation(tls); + r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE); if (ERR_peek_error() != 0) { tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE, @@ -1368,53 +1241,10 @@ tor_tls_handshake(tor_tls_t *tls) } if (r == TOR_TLS_DONE) { tls->state = TOR_TLS_ST_OPEN; - return tor_tls_finish_handshake(tls); } return r; } -/** Perform the final part of the initial TLS handshake on <b>tls</b>. This - * should be called for the first handshake only: it determines whether the v1 - * or the v2 handshake was used, and adjusts things for the renegotiation - * handshake as appropriate. - * - * tor_tls_handshake() calls this on its own; you only need to call this if - * bufferevent is doing the handshake for you. - */ -int -tor_tls_finish_handshake(tor_tls_t *tls) -{ - int r = TOR_TLS_DONE; - check_no_tls_errors(); - if (tls->isServer) { - SSL_set_info_callback(tls->ssl, NULL); - SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb); - SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN); - { - /* This check is redundant, but back when we did it in the callback, - * we might have not been able to look up the tor_tls_t if the code - * was buggy. Fixing that. */ - if (!tls->wasV2Handshake) { - log_warn(LD_BUG, "For some reason, wasV2Handshake didn't" - " get set. Fixing that."); - } - tls->wasV2Handshake = 1; - log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting" - " for renegotiation."); - } - } else { - /* Client-side */ - tls->wasV2Handshake = 1; - /* XXXX this can move, probably? -NM */ - if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) { - tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers"); - r = TOR_TLS_ERROR_MISC; - } - } - tls_log_errors(NULL, LOG_WARN, LD_NET, "finishing the handshake"); - return r; -} - /** Return true iff this TLS connection is authenticated. */ int @@ -1587,14 +1417,6 @@ check_no_tls_errors_(const char *fname, int line) tls_log_errors(NULL, LOG_WARN, LD_NET, NULL); } -/** Return true iff the server TLS connection <b>tls</b> got the renegotiation - * request it was waiting for. */ -int -tor_tls_server_got_renegotiate(tor_tls_t *tls) -{ - return tls->got_renegotiate; -} - /** Using the RFC5705 key material exporting construction, and the * provided <b>context</b> (<b>context_len</b> bytes long) and * <b>label</b> (a NUL-terminated string), compute a 32-byte secret in diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h @@ -49,13 +49,6 @@ struct tor_tls_t { * depending on which operations * have completed successfully. */ unsigned int isServer:1; /**< True iff this is a server-side connection */ - unsigned int wasV2Handshake:1; /**< True iff the original handshake for - * this connection used the updated version - * of the connection protocol (client sends - * different cipher list, server sends only - * one certificate). */ - /** True iff we should call negotiated_callback when we're done reading. */ - unsigned int got_renegotiate:1; #ifdef ENABLE_OPENSSL /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't * called that function yet. */ diff --git a/src/test/test_protover.c b/src/test/test_protover.c @@ -219,15 +219,15 @@ test_protover_all_supported(void *arg) tt_str_op(msg, OP_EQ, "Link=6-60"); tor_free(msg); tt_assert(! protover_all_supported("Link=1-3,50-63", &msg)); - tt_str_op(msg, OP_EQ, "Link=50-63"); + tt_str_op(msg, OP_EQ, "Link=1-2,50-63"); tor_free(msg); tt_assert(! protover_all_supported("Link=1-3,5-12", &msg)); - tt_str_op(msg, OP_EQ, "Link=6-12"); + tt_str_op(msg, OP_EQ, "Link=1-2,6-12"); tor_free(msg); /* Mix of protocols we do support and some we don't, where the protocols * we do support have some versions we don't support. */ - tt_assert(! protover_all_supported("Link=1-3,5-12 Quokka=40-41", &msg)); + tt_assert(! protover_all_supported("Link=3,5-12 Quokka=40-41", &msg)); tt_str_op(msg, OP_EQ, "Link=6-12 Quokka=40-41"); tor_free(msg); diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c @@ -327,23 +327,6 @@ test_tortls_get_forced_write_size(void *ignored) done: tor_free(tls); } - -static void -test_tortls_server_got_renegotiate(void *ignored) -{ - (void)ignored; - int ret; - tor_tls_t *tls; - - tls = tor_malloc_zero(sizeof(tor_tls_t)); - - tls->got_renegotiate = 1; - ret = tor_tls_server_got_renegotiate(tls); - tt_int_op(ret, OP_EQ, 1); - - done: - tor_free(tls); -} #endif /* defined(ENABLE_OPENSSL) */ static void @@ -594,7 +577,6 @@ struct testcase_t tortls_tests[] = { #ifdef ENABLE_OPENSSL LOCAL_TEST_CASE(tor_tls_get_error, 0), LOCAL_TEST_CASE(get_forced_write_size, 0), - LOCAL_TEST_CASE(server_got_renegotiate, 0), #endif /* defined(ENABLE_OPENSSL) */ LOCAL_TEST_CASE(evaluate_ecgroup_for_tls, 0), LOCAL_TEST_CASE(double_init, TT_FORK),