[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] [tor/master 1/2] Actually call connection_tls_finish_handshake() with bufferevents



Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Mon, 11 Oct 2010 13:45:27 -0400
Subject: Actually call connection_tls_finish_handshake() with bufferevents
Commit: a9172c87beaf94119b0c0dc280267d9c76b957b7

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 fc671c7..d560cbf 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
+ * <b>tls</b>. */
+int
+tor_tls_get_num_server_handshakes(tor_tls_t *tls)
+{
+  return tls->server_handshake_count;
+}
+
+/** Return true iff the server TLS connection <b>tls</b> 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 <b>tls</b>.
  * Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read
  * buffer and *<b>rbuf_bytes</b> to the amount actually used.
diff --git a/src/common/tortls.h b/src/common/tortls.h
index c52b6fd..950d430 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 9bd5b9b..d63cce6 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();
-- 
1.7.1