Loading src/common/compat_libevent.c +9 −0 Original line number Diff line number Diff line Loading @@ -518,6 +518,15 @@ tor_check_libevent_header_compatibility(void) #endif } /** Wrapper around libevent's event_base_once(). Sets a * timeout-triggered event with no associated file descriptor. */ int tor_event_base_once(void (*cb)(evutil_socket_t, short, void *), void *arg, struct timeval *timer) { return event_base_once(tor_libevent_get_base(), -1, EV_TIMEOUT, cb, arg, timer); } /* If possible, we're going to try to use Libevent's periodic timer support, since it does a pretty good job of making sure that periodic events get Loading src/common/compat_libevent.h +3 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ void tor_event_free(struct event *ev); typedef struct periodic_timer_t periodic_timer_t; int tor_event_base_once(void (*cb)(evutil_socket_t, short, void *), void *arg, struct timeval *timer); periodic_timer_t *periodic_timer_new(struct event_base *base, const struct timeval *tv, void (*cb)(periodic_timer_t *timer, void *data), Loading src/common/tortls.c +29 −28 Original line number Diff line number Diff line Loading @@ -52,7 +52,6 @@ #include <event2/bufferevent_ssl.h> #include <event2/buffer.h> #include <event2/event.h> #include "compat_libevent.h" #endif #define CRYPTO_PRIVATE /* to import prototypes from crypto.h */ Loading @@ -64,6 +63,7 @@ #include "torlog.h" #include "container.h" #include <string.h> #include "compat_libevent.h" /* Enable the "v2" TLS handshake. */ Loading Loading @@ -157,6 +157,11 @@ struct tor_tls_t { /** If set, a callback to invoke whenever the client tries to renegotiate * the handshake. */ void (*negotiated_callback)(tor_tls_t *tls, void *arg); /** Callback to invoke whenever a client tries to renegotiate more than once. */ void (*excess_renegotiations_callback)(evutil_socket_t, short, void *); /** Argument to pass to negotiated_callback. */ void *callback_arg; }; Loading Loading @@ -1228,17 +1233,6 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime) return NULL; } /** Return true if the <b>tls</b> object has completed more * renegotiations than needed for the Tor protocol. */ static INLINE int tor_tls_got_excess_renegotiations(tor_tls_t *tls) { /** The Tor v2 server handshake needs a single renegotiation after the initial SSL handshake. This means that if we ever see more than 2 handshakes, we raise the flag. */ return (tls->server_handshake_count > 2) ? 1 : 0; } #ifdef V2_HANDSHAKE_SERVER /** 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 Loading Loading @@ -1307,6 +1301,20 @@ tor_tls_got_client_hello(tor_tls_t *tls) } tls->got_renegotiate = 1; } else if (tls->server_handshake_count > 2) { /* We got more than one renegotiation requests. The Tor protocol needs just one renegotiation; more than that probably means They are trying to DoS us and we have to stop them. We can't close their connection from in here since it's an OpenSSL callback, so we set a libevent timer that triggers in the next event loop and closes the connection. */ struct timeval zero_seconds_timer = {0,0}; if (tor_event_base_once(tls->excess_renegotiations_callback, tls->callback_arg, &zero_seconds_timer) < 0) { log_warn(LD_GENERAL, "Didn't manage to set a renegotiation limiting callback."); } } /* Now check the cipher list. */ Loading Loading @@ -1523,16 +1531,20 @@ tor_tls_set_logged_address(tor_tls_t *tls, const char *address) tls->address = tor_strdup(address); } /** 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! /** 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. Set <b>cb2</b> to be called with argument <b>arg</b> whenever * <b>tls</b> gets excess renegotiation requests. Do not invoke this * function until <em>after</em> initial handshaking is done! */ void tor_tls_set_renegotiate_callback(tor_tls_t *tls, tor_tls_set_renegotiate_callbacks(tor_tls_t *tls, void (*cb)(tor_tls_t *, void *arg), void (*cb2)(evutil_socket_t, short, void *), void *arg) { tls->negotiated_callback = cb; tls->excess_renegotiations_callback = cb2; tls->callback_arg = arg; tls->got_renegotiate = 0; SSL_set_info_callback(tls->ssl, tor_tls_state_changed_callback); Loading Loading @@ -1592,6 +1604,7 @@ tor_tls_free(tor_tls_t *tls) SSL_free(tls->ssl); tls->ssl = NULL; tls->negotiated_callback = NULL; tls->excess_renegotiations_callback = NULL; if (tls->context) tor_tls_context_decref(tls->context); tor_free(tls->address); Loading Loading @@ -1620,12 +1633,6 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len) err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET); if (tor_tls_got_excess_renegotiations(tls)) { log_info(LD_NET, "Detected excess renegotiation from %s!", ADDR(tls)); return TOR_TLS_ERROR_MISC; } #ifdef V2_HANDSHAKE_SERVER if (tls->got_renegotiate) { if (tls->server_handshake_count != 2) { Loading Loading @@ -1680,12 +1687,6 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n) r = SSL_write(tls->ssl, cp, (int)n); err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET); if (tor_tls_got_excess_renegotiations(tls)) { log_info(LD_NET, "Detected excess renegotiation from %s!", ADDR(tls)); return TOR_TLS_ERROR_MISC; } if (err == TOR_TLS_DONE) { return r; } Loading src/common/tortls.h +3 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include "crypto.h" #include "compat.h" #include "compat_libevent.h" /* Opaque structure to hold a TLS connection. */ typedef struct tor_tls_t tor_tls_t; Loading Loading @@ -60,8 +61,9 @@ int tor_tls_context_init(int is_public_server, unsigned int key_lifetime); tor_tls_t *tor_tls_new(int 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 tor_tls_set_renegotiate_callbacks(tor_tls_t *tls, void (*cb)(tor_tls_t *, void *arg), void (*cb2)(evutil_socket_t, short, void *), void *arg); int tor_tls_is_server(tor_tls_t *tls); void tor_tls_free(tor_tls_t *tls); Loading src/or/connection_or.c +18 −2 Original line number Diff line number Diff line Loading @@ -1146,6 +1146,20 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn) } } /** Invoked on the server side using a timer from inside * tor_tls_got_client_hello() when the server receives excess * renegotiation attempts; probably indicating a DoS. */ static void connection_or_close_connection_cb(evutil_socket_t fd, short what, void *_conn) { or_connection_t *conn = _conn; (void) what; (void) fd; connection_stop_reading(TO_CONN(conn)); connection_mark_for_close(TO_CONN(conn)); } /** Move forward with the tls handshake. If it finishes, hand * <b>conn</b> to connection_tls_finish_handshake(). * Loading Loading @@ -1192,8 +1206,9 @@ connection_tls_continue_handshake(or_connection_t *conn) /* v2/v3 handshake, but 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, tor_tls_set_renegotiate_callbacks(conn->tls, connection_or_tls_renegotiated_cb, connection_or_close_connection_cb, conn); conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING; connection_stop_writing(TO_CONN(conn)); Loading Loading @@ -1255,8 +1270,9 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event, } else if (tor_tls_get_num_server_handshakes(conn->tls) == 1) { /* v2 or v3 handshake, as a server. Only got one handshake, so * wait for the next one. */ tor_tls_set_renegotiate_callback(conn->tls, tor_tls_set_renegotiate_callbacks(conn->tls, connection_or_tls_renegotiated_cb, connection_or_close_connection_cb, conn); conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING; /* return 0; */ Loading Loading
src/common/compat_libevent.c +9 −0 Original line number Diff line number Diff line Loading @@ -518,6 +518,15 @@ tor_check_libevent_header_compatibility(void) #endif } /** Wrapper around libevent's event_base_once(). Sets a * timeout-triggered event with no associated file descriptor. */ int tor_event_base_once(void (*cb)(evutil_socket_t, short, void *), void *arg, struct timeval *timer) { return event_base_once(tor_libevent_get_base(), -1, EV_TIMEOUT, cb, arg, timer); } /* If possible, we're going to try to use Libevent's periodic timer support, since it does a pretty good job of making sure that periodic events get Loading
src/common/compat_libevent.h +3 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ void tor_event_free(struct event *ev); typedef struct periodic_timer_t periodic_timer_t; int tor_event_base_once(void (*cb)(evutil_socket_t, short, void *), void *arg, struct timeval *timer); periodic_timer_t *periodic_timer_new(struct event_base *base, const struct timeval *tv, void (*cb)(periodic_timer_t *timer, void *data), Loading
src/common/tortls.c +29 −28 Original line number Diff line number Diff line Loading @@ -52,7 +52,6 @@ #include <event2/bufferevent_ssl.h> #include <event2/buffer.h> #include <event2/event.h> #include "compat_libevent.h" #endif #define CRYPTO_PRIVATE /* to import prototypes from crypto.h */ Loading @@ -64,6 +63,7 @@ #include "torlog.h" #include "container.h" #include <string.h> #include "compat_libevent.h" /* Enable the "v2" TLS handshake. */ Loading Loading @@ -157,6 +157,11 @@ struct tor_tls_t { /** If set, a callback to invoke whenever the client tries to renegotiate * the handshake. */ void (*negotiated_callback)(tor_tls_t *tls, void *arg); /** Callback to invoke whenever a client tries to renegotiate more than once. */ void (*excess_renegotiations_callback)(evutil_socket_t, short, void *); /** Argument to pass to negotiated_callback. */ void *callback_arg; }; Loading Loading @@ -1228,17 +1233,6 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime) return NULL; } /** Return true if the <b>tls</b> object has completed more * renegotiations than needed for the Tor protocol. */ static INLINE int tor_tls_got_excess_renegotiations(tor_tls_t *tls) { /** The Tor v2 server handshake needs a single renegotiation after the initial SSL handshake. This means that if we ever see more than 2 handshakes, we raise the flag. */ return (tls->server_handshake_count > 2) ? 1 : 0; } #ifdef V2_HANDSHAKE_SERVER /** 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 Loading Loading @@ -1307,6 +1301,20 @@ tor_tls_got_client_hello(tor_tls_t *tls) } tls->got_renegotiate = 1; } else if (tls->server_handshake_count > 2) { /* We got more than one renegotiation requests. The Tor protocol needs just one renegotiation; more than that probably means They are trying to DoS us and we have to stop them. We can't close their connection from in here since it's an OpenSSL callback, so we set a libevent timer that triggers in the next event loop and closes the connection. */ struct timeval zero_seconds_timer = {0,0}; if (tor_event_base_once(tls->excess_renegotiations_callback, tls->callback_arg, &zero_seconds_timer) < 0) { log_warn(LD_GENERAL, "Didn't manage to set a renegotiation limiting callback."); } } /* Now check the cipher list. */ Loading Loading @@ -1523,16 +1531,20 @@ tor_tls_set_logged_address(tor_tls_t *tls, const char *address) tls->address = tor_strdup(address); } /** 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! /** 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. Set <b>cb2</b> to be called with argument <b>arg</b> whenever * <b>tls</b> gets excess renegotiation requests. Do not invoke this * function until <em>after</em> initial handshaking is done! */ void tor_tls_set_renegotiate_callback(tor_tls_t *tls, tor_tls_set_renegotiate_callbacks(tor_tls_t *tls, void (*cb)(tor_tls_t *, void *arg), void (*cb2)(evutil_socket_t, short, void *), void *arg) { tls->negotiated_callback = cb; tls->excess_renegotiations_callback = cb2; tls->callback_arg = arg; tls->got_renegotiate = 0; SSL_set_info_callback(tls->ssl, tor_tls_state_changed_callback); Loading Loading @@ -1592,6 +1604,7 @@ tor_tls_free(tor_tls_t *tls) SSL_free(tls->ssl); tls->ssl = NULL; tls->negotiated_callback = NULL; tls->excess_renegotiations_callback = NULL; if (tls->context) tor_tls_context_decref(tls->context); tor_free(tls->address); Loading Loading @@ -1620,12 +1633,6 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len) err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET); if (tor_tls_got_excess_renegotiations(tls)) { log_info(LD_NET, "Detected excess renegotiation from %s!", ADDR(tls)); return TOR_TLS_ERROR_MISC; } #ifdef V2_HANDSHAKE_SERVER if (tls->got_renegotiate) { if (tls->server_handshake_count != 2) { Loading Loading @@ -1680,12 +1687,6 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n) r = SSL_write(tls->ssl, cp, (int)n); err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET); if (tor_tls_got_excess_renegotiations(tls)) { log_info(LD_NET, "Detected excess renegotiation from %s!", ADDR(tls)); return TOR_TLS_ERROR_MISC; } if (err == TOR_TLS_DONE) { return r; } Loading
src/common/tortls.h +3 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include "crypto.h" #include "compat.h" #include "compat_libevent.h" /* Opaque structure to hold a TLS connection. */ typedef struct tor_tls_t tor_tls_t; Loading Loading @@ -60,8 +61,9 @@ int tor_tls_context_init(int is_public_server, unsigned int key_lifetime); tor_tls_t *tor_tls_new(int 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 tor_tls_set_renegotiate_callbacks(tor_tls_t *tls, void (*cb)(tor_tls_t *, void *arg), void (*cb2)(evutil_socket_t, short, void *), void *arg); int tor_tls_is_server(tor_tls_t *tls); void tor_tls_free(tor_tls_t *tls); Loading
src/or/connection_or.c +18 −2 Original line number Diff line number Diff line Loading @@ -1146,6 +1146,20 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn) } } /** Invoked on the server side using a timer from inside * tor_tls_got_client_hello() when the server receives excess * renegotiation attempts; probably indicating a DoS. */ static void connection_or_close_connection_cb(evutil_socket_t fd, short what, void *_conn) { or_connection_t *conn = _conn; (void) what; (void) fd; connection_stop_reading(TO_CONN(conn)); connection_mark_for_close(TO_CONN(conn)); } /** Move forward with the tls handshake. If it finishes, hand * <b>conn</b> to connection_tls_finish_handshake(). * Loading Loading @@ -1192,8 +1206,9 @@ connection_tls_continue_handshake(or_connection_t *conn) /* v2/v3 handshake, but 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, tor_tls_set_renegotiate_callbacks(conn->tls, connection_or_tls_renegotiated_cb, connection_or_close_connection_cb, conn); conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING; connection_stop_writing(TO_CONN(conn)); Loading Loading @@ -1255,8 +1270,9 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event, } else if (tor_tls_get_num_server_handshakes(conn->tls) == 1) { /* v2 or v3 handshake, as a server. Only got one handshake, so * wait for the next one. */ tor_tls_set_renegotiate_callback(conn->tls, tor_tls_set_renegotiate_callbacks(conn->tls, connection_or_tls_renegotiated_cb, connection_or_close_connection_cb, conn); conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING; /* return 0; */ Loading