From a9172c87beaf94119b0c0dc280267d9c76b957b7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 11 Oct 2010 13:45:27 -0400 Subject: [PATCH] Actually call connection_tls_finish_handshake() with bufferevents First start of a fix for bug2001, but my test network still isn't working: the client and the server send each other VERSIONS cells, but never notice that they got them. --- src/common/tortls.c | 22 +++++++++++++++++++++- src/common/tortls.h | 2 ++ src/or/connection_or.c | 31 ++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/common/tortls.c b/src/common/tortls.c index fc671c73c2..d560cbf940 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -125,8 +125,10 @@ struct tor_tls_t { * 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. */ + /** True iff we should call negotiated_callback when we're done reading. */ unsigned int got_renegotiate:1; + /** Incremented every time we start the server side of a handshake. */ + uint8_t server_handshake_count; size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last * time. */ /** Last values retrieved from BIO_number_read()/write(); see @@ -841,6 +843,8 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) /* Check whether we're watching for renegotiates. If so, this is one! */ if (tls->negotiated_callback) tls->got_renegotiate = 1; + if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/ + ++tls->server_handshake_count; } else { log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); } @@ -1658,6 +1662,22 @@ tor_tls_used_v1_handshake(tor_tls_t *tls) return 1; } +/** Return the number of server handshakes that we've noticed doing on + * tls. */ +int +tor_tls_get_num_server_handshakes(tor_tls_t *tls) +{ + return tls->server_handshake_count; +} + +/** Return true iff the server TLS connection tls got the renegotiation + * request it was waiting for. */ +int +tor_tls_server_got_renegotiate(tor_tls_t *tls) +{ + return tls->got_renegotiate; +} + /** Examine the amount of memory used and available for buffers in tls. * Set *rbuf_capacity to the amount of storage allocated for the read * buffer and *rbuf_bytes to the amount actually used. diff --git a/src/common/tortls.h b/src/common/tortls.h index c52b6fd2a2..950d430788 100644 --- a/src/common/tortls.h +++ b/src/common/tortls.h @@ -80,6 +80,8 @@ void tor_tls_get_buffer_sizes(tor_tls_t *tls, size_t *wbuf_capacity, size_t *wbuf_bytes); 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); /* Log and abort if there are unhandled TLS errors in OpenSSL's error stack. */ diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 9bd5b9b207..d63cce6519 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -41,6 +41,8 @@ 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); + #ifdef USE_BUFFEREVENTS static void connection_or_handle_event_cb(struct bufferevent *bufev, short event, void *arg); @@ -237,6 +239,12 @@ connection_or_process_inbuf(or_connection_t *conn) } return ret; + case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: + if (tor_tls_server_got_renegotiate(conn->tls)) + connection_or_tls_renegotiated_cb(conn->tls, conn); + if (conn->_base.marked_for_close) + return 0; + /* fall through. */ case OR_CONN_STATE_OPEN: case OR_CONN_STATE_OR_HANDSHAKING: return connection_or_process_cells_from_inbuf(conn); @@ -1034,14 +1042,29 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event, tor_tls_unblock_renegotiation(conn->tls); return; /* ???? */ } - } else { - /* improved handshake, but not a client. */ + } else if (tor_tls_get_num_server_handshakes(conn->tls) == 1) { + /* improved handshake, as a server. Only got one handshake, so + * wait for the next one. */ tor_tls_set_renegotiate_callback(conn->tls, connection_or_tls_renegotiated_cb, conn); conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING; /* return 0; */ return; /* ???? */ + } else { + const int handshakes = tor_tls_get_num_server_handshakes(conn->tls); + tor_assert(handshakes >= 2); + if (handshakes == 2) { + /* improved handshake, as a server. Two handshakes happened already, + * so we treat renegotiation as done. + */ + connection_or_tls_renegotiated_cb(conn->tls, conn); + } else { + log_warn(LD_OR, "More than two handshakes done on connection. " + "Closing."); + connection_mark_for_close(TO_CONN(conn)); + } + return; } } connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT); @@ -1230,7 +1253,9 @@ connection_tls_finish_handshake(or_connection_t *conn) char digest_rcvd[DIGEST_LEN]; int started_here = connection_or_nonopen_was_started_here(conn); - log_debug(LD_HANDSHAKE,"tls handshake with %s done. verifying.", + log_debug(LD_HANDSHAKE,"%s tls handshake on %p with %s done. verifying.", + started_here?"outgoing":"incoming", + conn, safe_str_client(conn->_base.address)); directory_set_dirty();