mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
Remove the client-side code for the v1 and v2 tls handshakes.
(This is safe since super-old Tor servers are no longer allowed on the network.) Closes the client-side part of 11150.
This commit is contained in:
parent
4e34ef87a4
commit
bd1a137893
6
changes/11150
Normal file
6
changes/11150
Normal file
@ -0,0 +1,6 @@
|
||||
o Removed features:
|
||||
- Remove client-side support for connecting to Tor servers running
|
||||
versions of Tor before 0.2.3.6-alpha. These servers didn't support
|
||||
the v3 TLS handshake protocol, and
|
||||
are no longer allowed on the Tor network.
|
||||
Implements the client side of ticket 11150.
|
@ -1985,52 +1985,6 @@ tor_tls_finish_handshake(tor_tls_t *tls)
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
/** Put <b>tls</b>, which must be a client connection, into renegotiation
|
||||
* mode. */
|
||||
int
|
||||
tor_tls_start_renegotiating(tor_tls_t *tls)
|
||||
{
|
||||
int r = SSL_renegotiate(tls->ssl);
|
||||
if (r <= 0) {
|
||||
return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN,
|
||||
LD_HANDSHAKE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Client only: Renegotiate a TLS session. When finished, returns
|
||||
* TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, or
|
||||
* TOR_TLS_WANTWRITE.
|
||||
*/
|
||||
int
|
||||
tor_tls_renegotiate(tor_tls_t *tls)
|
||||
{
|
||||
int r;
|
||||
tor_assert(tls);
|
||||
/* We could do server-initiated renegotiation too, but that would be tricky.
|
||||
* Instead of "SSL_renegotiate, then SSL_do_handshake until done" */
|
||||
tor_assert(!tls->isServer);
|
||||
|
||||
check_no_tls_errors();
|
||||
if (tls->state != TOR_TLS_ST_RENEGOTIATE) {
|
||||
int r = SSL_renegotiate(tls->ssl);
|
||||
if (r <= 0) {
|
||||
return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN,
|
||||
LD_HANDSHAKE);
|
||||
}
|
||||
tls->state = TOR_TLS_ST_RENEGOTIATE;
|
||||
}
|
||||
r = SSL_do_handshake(tls->ssl);
|
||||
if (r == 1) {
|
||||
tls->state = TOR_TLS_ST_OPEN;
|
||||
return TOR_TLS_DONE;
|
||||
} else
|
||||
return tor_tls_get_error(tls, r, 0, "renegotiating handshake", LOG_INFO,
|
||||
LD_HANDSHAKE);
|
||||
}
|
||||
|
||||
/** Shut down an open tls connection <b>tls</b>. When finished, returns
|
||||
* TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD,
|
||||
* or TOR_TLS_WANTWRITE.
|
||||
@ -2424,99 +2378,6 @@ tor_tls_used_v1_handshake(tor_tls_t *tls)
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Return true iff <b>name</b> is a DN of a kind that could only
|
||||
* occur in a v3-handshake-indicating certificate */
|
||||
STATIC int
|
||||
dn_indicates_v3_cert(X509_NAME *name)
|
||||
{
|
||||
#ifdef DISABLE_V3_LINKPROTO_CLIENTSIDE
|
||||
(void)name;
|
||||
return 0;
|
||||
#else
|
||||
X509_NAME_ENTRY *entry;
|
||||
int n_entries;
|
||||
ASN1_OBJECT *obj;
|
||||
ASN1_STRING *str;
|
||||
unsigned char *s;
|
||||
int len, r;
|
||||
|
||||
n_entries = X509_NAME_entry_count(name);
|
||||
if (n_entries != 1) {
|
||||
return 1; /* More than one entry in the DN. */
|
||||
}
|
||||
entry = X509_NAME_get_entry(name, 0);
|
||||
|
||||
obj = X509_NAME_ENTRY_get_object(entry);
|
||||
if (OBJ_obj2nid(obj) != OBJ_txt2nid("commonName")) {
|
||||
return 1; /* The entry isn't a commonName. */
|
||||
}
|
||||
|
||||
str = X509_NAME_ENTRY_get_data(entry);
|
||||
len = ASN1_STRING_to_UTF8(&s, str);
|
||||
if (len < 0) {
|
||||
return 0;
|
||||
}
|
||||
r = fast_memneq(s + len - 4, ".net", 4);
|
||||
OPENSSL_free(s);
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Return true iff the peer certificate we're received on <b>tls</b>
|
||||
* indicates that this connection should use the v3 (in-protocol)
|
||||
* authentication handshake.
|
||||
*
|
||||
* Only the connection initiator should use this, and only once the initial
|
||||
* handshake is done; the responder detects a v1 handshake by cipher types,
|
||||
* and a v3/v2 handshake by Versions cell vs renegotiation.
|
||||
*/
|
||||
int
|
||||
tor_tls_received_v3_certificate(tor_tls_t *tls)
|
||||
{
|
||||
check_no_tls_errors();
|
||||
|
||||
X509 *cert = SSL_get_peer_certificate(tls->ssl);
|
||||
EVP_PKEY *key = NULL;
|
||||
X509_NAME *issuer_name, *subject_name;
|
||||
int is_v3 = 0;
|
||||
|
||||
if (!cert) {
|
||||
log_warn(LD_BUG, "Called on a connection with no peer certificate");
|
||||
goto done;
|
||||
}
|
||||
|
||||
subject_name = X509_get_subject_name(cert);
|
||||
issuer_name = X509_get_issuer_name(cert);
|
||||
|
||||
if (X509_name_cmp(subject_name, issuer_name) == 0) {
|
||||
is_v3 = 1; /* purportedly self signed */
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (dn_indicates_v3_cert(subject_name) ||
|
||||
dn_indicates_v3_cert(issuer_name)) {
|
||||
is_v3 = 1; /* DN is fancy */
|
||||
goto done;
|
||||
}
|
||||
|
||||
key = X509_get_pubkey(cert);
|
||||
if (EVP_PKEY_bits(key) != 1024 ||
|
||||
EVP_PKEY_type(key->type) != EVP_PKEY_RSA) {
|
||||
is_v3 = 1; /* Key is fancy */
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
tls_log_errors(tls, LOG_WARN, LD_NET, "checking for a v3 cert");
|
||||
|
||||
if (key)
|
||||
EVP_PKEY_free(key);
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
|
||||
return is_v3;
|
||||
}
|
||||
|
||||
/** Return the number of server handshakes that we've noticed doing on
|
||||
* <b>tls</b>. */
|
||||
int
|
||||
|
@ -135,7 +135,6 @@ STATIC int tor_tls_classify_client_ciphers(const SSL *ssl,
|
||||
STATIC int tor_tls_client_is_using_v2_ciphers(const SSL *ssl);
|
||||
MOCK_DECL(STATIC void, try_to_extract_certs_from_tls,
|
||||
(int severity, tor_tls_t *tls, X509 **cert_out, X509 **id_cert_out));
|
||||
STATIC int dn_indicates_v3_cert(X509_NAME *name);
|
||||
#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
|
||||
STATIC size_t SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out,
|
||||
size_t len);
|
||||
@ -195,7 +194,6 @@ 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);
|
||||
int tor_tls_renegotiate(tor_tls_t *tls);
|
||||
void tor_tls_unblock_renegotiation(tor_tls_t *tls);
|
||||
void tor_tls_block_renegotiation(tor_tls_t *tls);
|
||||
void tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls);
|
||||
@ -213,7 +211,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_received_v3_certificate(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_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out));
|
||||
|
@ -1450,17 +1450,12 @@ connection_tls_continue_handshake(or_connection_t *conn)
|
||||
{
|
||||
int result;
|
||||
check_no_tls_errors();
|
||||
again:
|
||||
if (conn->base_.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) {
|
||||
// log_notice(LD_OR, "Renegotiate with %p", conn->tls);
|
||||
result = tor_tls_renegotiate(conn->tls);
|
||||
// log_notice(LD_OR, "Result: %d", result);
|
||||
} else {
|
||||
tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING);
|
||||
// log_notice(LD_OR, "Continue handshake with %p", conn->tls);
|
||||
result = tor_tls_handshake(conn->tls);
|
||||
// log_notice(LD_OR, "Result: %d", result);
|
||||
}
|
||||
|
||||
tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING);
|
||||
// log_notice(LD_OR, "Continue handshake with %p", conn->tls);
|
||||
result = tor_tls_handshake(conn->tls);
|
||||
// log_notice(LD_OR, "Result: %d", result);
|
||||
|
||||
switch (result) {
|
||||
CASE_TOR_TLS_ERROR_ANY:
|
||||
log_info(LD_OR,"tls error [%s]. breaking connection.",
|
||||
@ -1470,20 +1465,8 @@ connection_tls_continue_handshake(or_connection_t *conn)
|
||||
if (! tor_tls_used_v1_handshake(conn->tls)) {
|
||||
if (!tor_tls_is_server(conn->tls)) {
|
||||
if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
|
||||
if (tor_tls_received_v3_certificate(conn->tls)) {
|
||||
log_info(LD_OR, "Client got a v3 cert! Moving on to v3 "
|
||||
"handshake with ciphersuite %s",
|
||||
tor_tls_get_ciphersuite_name(conn->tls));
|
||||
return connection_or_launch_v3_or_handshake(conn);
|
||||
} else {
|
||||
log_debug(LD_OR, "Done with initial SSL handshake (client-side)."
|
||||
" Requesting renegotiation.");
|
||||
connection_or_change_state(conn,
|
||||
OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
|
||||
goto again;
|
||||
}
|
||||
return connection_or_launch_v3_or_handshake(conn);
|
||||
}
|
||||
// log_notice(LD_OR,"Done. state was %d.", conn->base_.state);
|
||||
} else {
|
||||
/* v2/v3 handshake, but not a client. */
|
||||
log_debug(LD_OR, "Done with initial SSL handshake (server-side). "
|
||||
@ -1533,22 +1516,8 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
|
||||
if (! tor_tls_used_v1_handshake(conn->tls)) {
|
||||
if (!tor_tls_is_server(conn->tls)) {
|
||||
if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
|
||||
if (tor_tls_received_v3_certificate(conn->tls)) {
|
||||
log_info(LD_OR, "Client got a v3 cert!");
|
||||
if (connection_or_launch_v3_or_handshake(conn) < 0)
|
||||
connection_or_close_for_error(conn, 0);
|
||||
return;
|
||||
} else {
|
||||
connection_or_change_state(conn,
|
||||
OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
|
||||
tor_tls_unblock_renegotiation(conn->tls);
|
||||
if (bufferevent_ssl_renegotiate(conn->base_.bufev)<0) {
|
||||
log_warn(LD_OR, "Start_renegotiating went badly.");
|
||||
connection_or_close_for_error(conn, 0);
|
||||
}
|
||||
tor_tls_unblock_renegotiation(conn->tls);
|
||||
return; /* ???? */
|
||||
}
|
||||
if (connection_or_launch_v3_or_handshake(conn) < 0)
|
||||
connection_or_close_for_error(conn, 0);
|
||||
}
|
||||
} else {
|
||||
const int handshakes = tor_tls_get_num_server_handshakes(conn->tls);
|
||||
@ -1844,7 +1813,6 @@ static int
|
||||
connection_or_launch_v3_or_handshake(or_connection_t *conn)
|
||||
{
|
||||
tor_assert(connection_or_nonopen_was_started_here(conn));
|
||||
tor_assert(tor_tls_received_v3_certificate(conn->tls));
|
||||
|
||||
circuit_build_times_network_is_live(get_circuit_build_times_mutable());
|
||||
|
||||
|
@ -1194,143 +1194,6 @@ test_tortls_used_v1_handshake(void *ignored)
|
||||
tor_free(tls);
|
||||
}
|
||||
|
||||
static void
|
||||
test_tortls_dn_indicates_v3_cert(void *ignored)
|
||||
{
|
||||
(void)ignored;
|
||||
int ret;
|
||||
X509_NAME *name;
|
||||
|
||||
name = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
|
||||
(const unsigned char *)"US", -1, -1, 0);
|
||||
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
|
||||
(const unsigned char *)"Foobar", -1, -1, 0);
|
||||
ret = dn_indicates_v3_cert(name);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
X509_NAME_free(name);
|
||||
name = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
|
||||
(const unsigned char *)"US", -1, -1, 0);
|
||||
ret = dn_indicates_v3_cert(name);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
X509_NAME_free(name);
|
||||
name = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(name, "commonName", V_ASN1_REAL,
|
||||
(const unsigned char *)"123", -1, -1, 0);
|
||||
ret = dn_indicates_v3_cert(name);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
|
||||
X509_NAME_free(name);
|
||||
name = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"hello.com", -1, -1, 0);
|
||||
ret = dn_indicates_v3_cert(name);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
X509_NAME_free(name);
|
||||
name = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"hello.net", -1, -1, 0);
|
||||
ret = dn_indicates_v3_cert(name);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
|
||||
X509_NAME_free(name);
|
||||
name = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"x.s", -1, -1, 0);
|
||||
ret = dn_indicates_v3_cert(name);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
done:
|
||||
X509_NAME_free(name);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_OPAQUE
|
||||
static void
|
||||
test_tortls_received_v3_certificate(void *ignored)
|
||||
{
|
||||
(void)ignored;
|
||||
int ret;
|
||||
tor_tls_t *tls;
|
||||
X509 *validCert = read_cert_from(validCertString);
|
||||
X509_NAME *subject=NULL, *issuer=NULL;
|
||||
|
||||
tls = tor_malloc_zero(sizeof(tor_tls_t));
|
||||
tls->ssl = tor_malloc_zero(sizeof(SSL));
|
||||
tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
|
||||
|
||||
ret = tor_tls_received_v3_certificate(tls);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
|
||||
tls->ssl->session->peer = validCert;
|
||||
|
||||
subject = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"same.com", -1, -1, 0);
|
||||
X509_set_subject_name(validCert, subject);
|
||||
|
||||
issuer = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(issuer, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"same.com", -1, -1, 0);
|
||||
X509_set_issuer_name(validCert, issuer);
|
||||
|
||||
ret = tor_tls_received_v3_certificate(tls);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
X509_NAME_free(subject);
|
||||
subject = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"different.net", -1, -1, 0);
|
||||
X509_set_subject_name(validCert, subject);
|
||||
|
||||
ret = tor_tls_received_v3_certificate(tls);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
X509_NAME_free(subject);
|
||||
subject = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"same.com", -1, -1, 0);
|
||||
X509_set_subject_name(validCert, subject);
|
||||
|
||||
X509_NAME_free(issuer);
|
||||
issuer = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(issuer, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"different.net", -1, -1, 0);
|
||||
X509_set_issuer_name(validCert, issuer);
|
||||
|
||||
ret = tor_tls_received_v3_certificate(tls);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
X509_NAME_free(subject);
|
||||
subject = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC,
|
||||
(const unsigned char *)"different2.net", -1, -1, 0);
|
||||
X509_set_subject_name(validCert, subject);
|
||||
ret = tor_tls_received_v3_certificate(tls);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
|
||||
EVP_PKEY *key = X509_get_pubkey(validCert);
|
||||
key->type = 5;
|
||||
ret = tor_tls_received_v3_certificate(tls);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
key->type = 6;
|
||||
key->ameth = NULL;
|
||||
ret = tor_tls_received_v3_certificate(tls);
|
||||
tt_int_op(ret, OP_EQ, 1);
|
||||
|
||||
done:
|
||||
X509_NAME_free(subject);
|
||||
X509_NAME_free(issuer);
|
||||
tor_free(tls->ssl->session);
|
||||
tor_free(tls->ssl);
|
||||
tor_free(tls);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_tortls_get_num_server_handshakes(void *ignored)
|
||||
{
|
||||
@ -2913,8 +2776,6 @@ struct testcase_t tortls_tests[] = {
|
||||
LOCAL_TEST_CASE(get_forced_write_size, 0),
|
||||
LOCAL_TEST_CASE(get_write_overhead_ratio, TT_FORK),
|
||||
LOCAL_TEST_CASE(used_v1_handshake, TT_FORK),
|
||||
LOCAL_TEST_CASE(dn_indicates_v3_cert, 0),
|
||||
INTRUSIVE_TEST_CASE(received_v3_certificate, 0),
|
||||
LOCAL_TEST_CASE(get_num_server_handshakes, 0),
|
||||
LOCAL_TEST_CASE(server_got_renegotiate, 0),
|
||||
INTRUSIVE_TEST_CASE(SSL_SESSION_get_master_key, 0),
|
||||
|
Loading…
Reference in New Issue
Block a user