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:
Nick Mathewson 2015-10-07 10:04:12 -04:00
parent 4e34ef87a4
commit bd1a137893
5 changed files with 15 additions and 322 deletions

6
changes/11150 Normal file
View 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.

View File

@ -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

View File

@ -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));

View File

@ -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());

View File

@ -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),