tor

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

commit d57d00143c7fb45733e7f92b4e2d02d3b47ee10a
parent 7ae5e798d6f9d96de928370a1e7b6fdb0b03d394
Author: Nick Mathewson <nickm@torproject.org>
Date:   Thu, 24 Apr 2025 13:18:32 -0400

Remove server support for the v1 link handshake.

In the v1 handshake we would send two very specialized certificates.
We'd identify that the client wanted to use this handshake by
the ciphers that it sent, or didn't sent.

We already removed client-side support for the v1 link handshake
back in 0.2.8.1-alpha, with ticket 11150.

Diffstat:
Msrc/core/or/connection_or.c | 12++----------
Msrc/lib/tls/tortls.h | 1-
Msrc/lib/tls/tortls_internal.h | 1-
Msrc/lib/tls/tortls_nss.c | 9---------
Msrc/lib/tls/tortls_openssl.c | 59++++++++++++++---------------------------------------------
Msrc/test/test_tortls.c | 22----------------------
Msrc/test/test_tortls_openssl.c | 44--------------------------------------------
7 files changed, 16 insertions(+), 132 deletions(-)

diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c @@ -1742,7 +1742,7 @@ connection_tls_continue_handshake(or_connection_t *conn) tor_tls_err_to_string(result)); return -1; case TOR_TLS_DONE: - if (! tor_tls_used_v1_handshake(conn->tls)) { + { if (!tor_tls_is_server(conn->tls)) { tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING); return connection_or_launch_v3_or_handshake(conn); @@ -2112,15 +2112,7 @@ connection_tls_finish_handshake(or_connection_t *conn) circuit_build_times_network_is_live(get_circuit_build_times_mutable()); - if (tor_tls_used_v1_handshake(conn->tls)) { - conn->link_proto = 1; - connection_or_init_conn_from_address(conn, &conn->base_.addr, - conn->base_.port, digest_rcvd, - NULL, 0); - tor_tls_block_renegotiation(conn->tls); - rep_hist_note_negotiated_link_proto(1, started_here); - return connection_or_set_state_open(conn); - } else { + { connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2); if (connection_init_or_handshake_state(conn, started_here) < 0) return -1; diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h @@ -119,7 +119,6 @@ int tor_tls_get_buffer_sizes(tor_tls_t *tls, MOCK_DECL(double, tls_get_write_overhead_ratio, (void)); -int tor_tls_used_v1_handshake(tor_tls_t *tls); 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, diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h @@ -44,7 +44,6 @@ void tor_tls_context_impl_free_(tor_tls_context_impl_t *); #ifdef ENABLE_OPENSSL tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl); -int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl); void tor_tls_debug_state_callback(const struct ssl_st *ssl, int type, int val); void tor_tls_server_info_callback(const struct ssl_st *ssl, diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c @@ -714,15 +714,6 @@ tls_get_write_overhead_ratio, (void)) } int -tor_tls_used_v1_handshake(tor_tls_t *tls) -{ - tor_assert(tls); - /* We don't support or allow the V1 handshake with NSS. - */ - return 0; -} - -int tor_tls_server_got_renegotiate(tor_tls_t *tls) { tor_assert(tls); diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c @@ -641,11 +641,10 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, result->my_link_cert->cert)) { goto error; } - if (result->my_id_cert) { - X509_STORE *s = SSL_CTX_get_cert_store(result->ctx); - tor_assert(s); - X509_STORE_add_cert(s, result->my_id_cert->cert); - } + // Here we would once add my_id_cert too via X509_STORE_add_cert. + // + // We no longer do that, since we no longer send multiple certs; + // that was part of the obsolete v1 handshake. } SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF); if (!is_client) { @@ -735,8 +734,14 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, EC_KEY_free(ec_key); } #endif /* defined(SSL_CTX_set1_groups_list) || defined(HAVE_SSL_CTX_SET1...) */ - SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, - always_accept_verify_cb); + + if (is_client) { + SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, + 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); + } /* let us realloc bufs that we're writing from */ SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); @@ -978,27 +983,6 @@ tor_tls_classify_client_ciphers(const SSL *ssl, return res; } -/** Return true iff the cipher list suggested by the client for <b>ssl</b> is - * a list that indicates that the client knows how to do the v2 TLS connection - * handshake. */ -int -tor_tls_client_is_using_v2_ciphers(const SSL *ssl) -{ - STACK_OF(SSL_CIPHER) *ciphers; -#ifdef HAVE_SSL_GET_CLIENT_CIPHERS - ciphers = SSL_get_client_ciphers(ssl); -#else - SSL_SESSION *session; - if (!(session = SSL_get_session((SSL *)ssl))) { - log_info(LD_NET, "No session on TLS?"); - return CIPHERS_ERR; - } - ciphers = session->ciphers; -#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */ - - return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2; -} - /** 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 @@ -1034,7 +1018,7 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) } /* Now check the cipher list. */ - if (tor_tls_client_is_using_v2_ciphers(ssl)) { + { if (tls->wasV2Handshake) return; /* We already turned this stuff off for the first handshake; * This is a renegotiation. */ @@ -1042,11 +1026,6 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) /* Yes, we're casting away the const from ssl. This is very naughty of us. * Let's hope openssl doesn't notice! */ - /* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */ - SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN); - /* Don't send a hello request. */ - SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL); - if (tls) { tls->wasV2Handshake = 1; } else { @@ -1411,7 +1390,7 @@ tor_tls_finish_handshake(tor_tls_t *tls) 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); - if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) { + { /* 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. */ @@ -1422,8 +1401,6 @@ tor_tls_finish_handshake(tor_tls_t *tls) tls->wasV2Handshake = 1; log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting" " for renegotiation."); - } else { - tls->wasV2Handshake = 0; } } else { /* Client-side */ @@ -1610,14 +1587,6 @@ check_no_tls_errors_(const char *fname, int line) tls_log_errors(NULL, LOG_WARN, LD_NET, NULL); } -/** Return true iff the initial TLS connection at <b>tls</b> did not use a v2 - * TLS handshake. Output is undefined if the handshake isn't finished. */ -int -tor_tls_used_v1_handshake(tor_tls_t *tls) -{ - return ! tls->wasV2Handshake; -} - /** Return true iff the server TLS connection <b>tls</b> got the renegotiation * request it was waiting for. */ int diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c @@ -329,27 +329,6 @@ test_tortls_get_forced_write_size(void *ignored) } static void -test_tortls_used_v1_handshake(void *ignored) -{ - (void)ignored; - int ret; - tor_tls_t *tls; - tls = tor_malloc_zero(sizeof(tor_tls_t)); - - // These tests assume both V2 handshake server and client are enabled - tls->wasV2Handshake = 0; - ret = tor_tls_used_v1_handshake(tls); - tt_int_op(ret, OP_EQ, 1); - - tls->wasV2Handshake = 1; - ret = tor_tls_used_v1_handshake(tls); - tt_int_op(ret, OP_EQ, 0); - - done: - tor_free(tls); -} - -static void test_tortls_server_got_renegotiate(void *ignored) { (void)ignored; @@ -615,7 +594,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(used_v1_handshake, TT_FORK), LOCAL_TEST_CASE(server_got_renegotiate, 0), #endif /* defined(ENABLE_OPENSSL) */ LOCAL_TEST_CASE(evaluate_ecgroup_for_tls, 0), diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c @@ -662,49 +662,6 @@ test_tortls_classify_client_ciphers(void *ignored) } #endif /* !defined(OPENSSL_OPAQUE) */ -static void -test_tortls_client_is_using_v2_ciphers(void *ignored) -{ - (void)ignored; - -#ifdef HAVE_SSL_GET_CLIENT_CIPHERS - tt_skip(); - done: - (void)1; -#else - int ret; - SSL_CTX *ctx; - SSL *ssl; - SSL_SESSION *sess; - STACK_OF(SSL_CIPHER) *ciphers; - - library_init(); - - ctx = SSL_CTX_new(TLSv1_method()); - ssl = SSL_new(ctx); - sess = SSL_SESSION_new(); - - ret = tor_tls_client_is_using_v2_ciphers(ssl); - tt_int_op(ret, OP_EQ, -1); - - ssl->session = sess; - ret = tor_tls_client_is_using_v2_ciphers(ssl); - tt_int_op(ret, OP_EQ, 0); - - ciphers = sk_SSL_CIPHER_new_null(); - SSL_CIPHER *one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384"); - tt_assert(one); - one->id = 0x00ff; - sk_SSL_CIPHER_push(ciphers, one); - sess->ciphers = ciphers; - ret = tor_tls_client_is_using_v2_ciphers(ssl); - tt_int_op(ret, OP_EQ, 1); - done: - SSL_free(ssl); - SSL_CTX_free(ctx); -#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */ -} - #ifndef OPENSSL_OPAQUE static int fixed_ssl_pending_result = 0; @@ -2105,7 +2062,6 @@ struct testcase_t tortls_openssl_tests[] = { INTRUSIVE_TEST_CASE(cert_get_key, 0), INTRUSIVE_TEST_CASE(get_ciphersuite_name, 0), INTRUSIVE_TEST_CASE(classify_client_ciphers, 0), - LOCAL_TEST_CASE(client_is_using_v2_ciphers, 0), INTRUSIVE_TEST_CASE(get_pending_bytes, 0), INTRUSIVE_TEST_CASE(get_buffer_sizes, 0), INTRUSIVE_TEST_CASE(try_to_extract_certs_from_tls, 0),