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

[or-cvs] r12622: Start getting freaky with openssl callbacks in tortls.c: det (in tor/trunk: . doc src/common src/or)



Author: nickm
Date: 2007-12-01 03:09:46 -0500 (Sat, 01 Dec 2007)
New Revision: 12622

Modified:
   tor/trunk/
   tor/trunk/doc/TODO
   tor/trunk/src/common/tortls.c
   tor/trunk/src/common/tortls.h
   tor/trunk/src/or/command.c
   tor/trunk/src/or/connection_or.c
   tor/trunk/src/or/or.h
Log:
 r15087@tombo:  nickm | 2007-11-30 22:32:26 -0500
 Start getting freaky with openssl callbacks in tortls.c: detect client ciphers, and if the list doesn't look like the list current Tors use, present only a single cert do not ask for a client cert. Also, support for client-side renegotiation.  None of this is enabled unless you define V2_HANDSHAKE_SERVER.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r15087] on d9e39d38-0f13-419c-a857-e10a0ce2aa0c

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-12-01 04:58:53 UTC (rev 12621)
+++ tor/trunk/doc/TODO	2007-12-01 08:09:46 UTC (rev 12622)
@@ -31,6 +31,20 @@
     D 118 if feasible and obvious
     D Maintain a skew estimate and use ftime consistently.
     - 105+TLS, if possible.
+      . TLS backend work
+        - New list of ciphers for clients
+        o Servers detect new ciphers, and only send ID cert when they
+          get an older cipher list, and only request client cert when
+          they get an older cipher list.
+        - Clients only send certificates when asked for them.
+        o Servers disable callback once negotiation is finished, so
+          that renegotiation happens according to the old rules.
+        - Clients initiate renegotiation immediately on completing
+          a v2 connection.
+        - Servers detect renegotiation, and if there is now a client
+          cert, they adust the client ID.
+          o Detect.
+          - Adjust.
       o Add a separate handshake structure that handles version negotiation,
         and stores netinfo data until authentication is done.
       o Revise versions and netinfo to use separate structure; make

Modified: tor/trunk/src/common/tortls.c
===================================================================
--- tor/trunk/src/common/tortls.c	2007-12-01 04:58:53 UTC (rev 12621)
+++ tor/trunk/src/common/tortls.c	2007-12-01 08:09:46 UTC (rev 12622)
@@ -34,6 +34,8 @@
 #include "./log.h"
 #include <string.h>
 
+// #define V2_HANDSHAKE_SERVER
+
 /* Copied from or.h */
 #define LEGAL_NICKNAME_CHARACTERS \
   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
@@ -59,10 +61,11 @@
   int socket; /**< The underlying file descriptor for this TLS connection. */
   enum {
     TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE,
-    TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED
-  } state : 7; /**< The current SSL state, depending on which operations have
+    TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE,
+  } state : 6; /**< The current SSL state, depending on which operations have
                 * completed successfully. */
   unsigned int isServer:1; /**< True iff this is a server-side connection */
+  unsigned int hadCert:1; /**< Docdoc */
   size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
                        * time. */
   unsigned long last_write_count;
@@ -455,7 +458,7 @@
     goto error;
   X509_free(cert); /* We just added a reference to cert. */
   cert=NULL;
-#if 1
+#if 0
   if (idcert && !SSL_CTX_add_extra_chain_cert(result->ctx,idcert))
     goto error;
 #else
@@ -511,6 +514,55 @@
   return -1;
 }
 
+#ifdef V2_HANDSHAKE_SERVER
+static void
+tor_tls_server_info_callback(const SSL *ssl, int type, int val)
+{
+  int all_ciphers_in_v1_list = 1;
+  int i;
+  SSL_SESSION *session;
+  (void) val;
+  if (type != SSL_CB_ACCEPT_LOOP)
+    return;
+  if (ssl->state != SSL3_ST_SW_SRVR_HELLO_A)
+    return;
+  /* If we reached this point, we just got a client hello.  See if there is
+   * a cipher list. */
+  if (!(session = SSL_get_session(ssl))) {
+    log_warn(LD_NET, "No session on TLS?");
+    return;
+  }
+  if (!session->ciphers) {
+    log_warn(LD_NET, "No ciphers on session");
+    return;
+  }
+  /* Now we need to see if there are any ciphers whose presence means we're
+   * dealing with an updated Tor. */
+  for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
+    SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
+    const char *ciphername = SSL_CIPHER_get_name(cipher);
+    if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) &&
+        strcmp(ciphername, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) &&
+        strcmp(ciphername, "(NONE)")) {
+      /* XXXX should be ld_debug */
+      log_info(LD_NET, "Got a non-version-1 cipher called '%s'",ciphername);
+      all_ciphers_in_v1_list = 0;
+      break;
+    }
+  }
+
+  if (!all_ciphers_in_v1_list) {
+    /* Yes, we're casting away the const from ssl.  This is very naughty of us.
+     * Let's hope openssl doesn't notice! */
+
+    /* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */
+    SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN);
+    /* Don't send a hello request. */
+    SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL);
+  }
+}
+#endif
+
 /** Create a new TLS object from a file descriptor, and a flag to
  * determine whether it is functioning as a server.
  */
@@ -544,6 +596,11 @@
   result->state = TOR_TLS_ST_HANDSHAKE;
   result->isServer = isServer;
   result->wantwrite_n = 0;
+#ifdef V2_HANDSHAKE_SERVER
+  if (isServer) {
+    SSL_set_info_callback(result->ssl, tor_tls_server_info_callback);
+  }
+#endif
   /* Not expected to get called. */
   tls_log_errors(LOG_WARN, "generating TLS context");
   return result;
@@ -585,8 +642,17 @@
   tor_assert(tls->ssl);
   tor_assert(tls->state == TOR_TLS_ST_OPEN);
   r = SSL_read(tls->ssl, cp, len);
-  if (r > 0)
+  if (r > 0) {
+#ifdef V2_HANDSHAKE_SERVER
+    if (!tls->hadCert && tls->ssl->session && tls->ssl->session->peer) {
+      tls->hadCert = 1;
+      /* New certificate! */
+      log_info(LD_NET, "Got a TLS renegotiation.");
+      /* XXXX020 call some kind of 'there was a renegotiation' callback. */
+    }
+#endif
     return r;
+  }
   err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG);
   if (err == _TOR_TLS_ZERORETURN) {
     log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
@@ -657,10 +723,45 @@
   }
   if (r == TOR_TLS_DONE) {
     tls->state = TOR_TLS_ST_OPEN;
+    tls->hadCert = tor_tls_peer_has_cert(tls) ? 1 : 0;
+    if (tls->isServer) {
+      SSL_set_info_callback(tls->ssl, NULL);
+      SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, always_accept_verify_cb);
+      tls->ssl->mode &= ~SSL_MODE_NO_AUTO_CHAIN;
+    }
   }
   return r;
 }
 
+/** 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);
+  if (tls->state != TOR_TLS_ST_RENEGOTIATE) {
+    int r = SSL_renegotiate(tls->ssl);
+    if (r <= 0) {
+      return tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO,
+                               "renegotiating", LOG_WARN);
+    }
+    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, CATCH_SYSCALL|CATCH_ZERO,
+                             "renegotiating handshake", LOG_WARN);
+}
+
 /** 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.
@@ -923,6 +1024,7 @@
   return r;
 }
 
+#if 0
 /** DOCDOC
  *
  * Returns 1 on "verification is done", 0 on "still need LINK_AUTH."
@@ -1025,6 +1127,7 @@
 
   return r;
 }
+#endif
 
 /** Check whether the certificate set on the connection <b>tls</b> is
  * expired or not-yet-valid, give or take <b>tolerance</b>

Modified: tor/trunk/src/common/tortls.h
===================================================================
--- tor/trunk/src/common/tortls.h	2007-12-01 04:58:53 UTC (rev 12621)
+++ tor/trunk/src/common/tortls.h	2007-12-01 08:09:46 UTC (rev 12622)
@@ -62,6 +62,7 @@
 crypto_pk_env_t *tor_tls_dup_private_key(tor_tls_t *tls);
 int tor_tls_verify_v1(int severity, tor_tls_t *tls,
                       crypto_pk_env_t **identity);
+#if 0
 int tor_tls_verify_certs_v2(int severity, tor_tls_t *tls,
                             const char *cert_str, size_t cert_len,
                             const char *id_cert_str, size_t id_cert_len,
@@ -69,10 +70,12 @@
                             char *conn_cert_digest_out,
                             crypto_pk_env_t **id_key_out,
                             char *id_digest_out);
+#endif
 int tor_tls_check_lifetime(tor_tls_t *tls, int tolerance);
 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_renegotiate(tor_tls_t *tls);
 int tor_tls_shutdown(tor_tls_t *tls);
 int tor_tls_get_pending_bytes(tor_tls_t *tls);
 size_t tor_tls_get_forced_write_size(tor_tls_t *tls);

Modified: tor/trunk/src/or/command.c
===================================================================
--- tor/trunk/src/or/command.c	2007-12-01 04:58:53 UTC (rev 12621)
+++ tor/trunk/src/or/command.c	2007-12-01 08:09:46 UTC (rev 12622)
@@ -38,8 +38,10 @@
 static void command_process_versions_cell(var_cell_t *cell,
                                           or_connection_t *conn);
 static void command_process_netinfo_cell(cell_t *cell, or_connection_t *conn);
+#if 0
 static void command_process_cert_cell(var_cell_t *cell, or_connection_t *conn);
 static void command_process_link_auth_cell(cell_t *cell,or_connection_t *conn);
+#endif
 
 #ifdef KEEP_TIMING_STATS
 /** This is a wrapper function around the actual function that processes the
@@ -151,13 +153,6 @@
       ++stats_n_netinfo_cells_processed;
       PROCESS_CELL(netinfo, cell, conn);
       break;
-    case CELL_CERT:
-      tor_fragile_assert();
-      break;
-    case CELL_LINK_AUTH:
-      ++stats_n_link_auth_cells_processed;
-      PROCESS_CELL(link_auth, cell, conn);
-      break;
     default:
       log_fn(LOG_INFO, LD_PROTOCOL,
              "Cell of unknown type (%d) received. Dropping.", cell->command);
@@ -201,10 +196,6 @@
       ++stats_n_versions_cells_processed;
       PROCESS_CELL(versions, cell, conn);
       break;
-    case CELL_CERT:
-      ++stats_n_cert_cells_processed;
-      PROCESS_CELL(cert, cell, conn);
-      break;
     default:
       log_warn(LD_BUG,
                "Variable-length cell of unknown type (%d) received.",
@@ -484,6 +475,8 @@
   conn->link_proto = highest_supported_version;
   conn->handshake_state->received_versions = 1;
 
+#if 0
+  /*XXXX020 not right; references dead functions */
   if (highest_supported_version >= 2) {
     if (connection_or_send_netinfo(conn) < 0 ||
         connection_or_send_cert(conn) < 0) {
@@ -495,6 +488,7 @@
   } else {
     /* XXXX020 finish v1 verification. */
   }
+#endif
 }
 
 /** Process a 'netinfo' cell. DOCDOC say more. */
@@ -612,6 +606,7 @@
   return 0;
 }
 
+#if 0
 /*DOCDOC*/
 static void
 command_process_cert_cell(var_cell_t *cell, or_connection_t *conn)
@@ -780,4 +775,4 @@
   tor_free(checked);
   connection_mark_for_close(TO_CONN(conn));
 }
-
+#endif

Modified: tor/trunk/src/or/connection_or.c
===================================================================
--- tor/trunk/src/or/connection_or.c	2007-12-01 04:58:53 UTC (rev 12621)
+++ tor/trunk/src/or/connection_or.c	2007-12-01 08:09:46 UTC (rev 12622)
@@ -1057,6 +1057,7 @@
   return 0;
 }
 
+#if 0
 #define LINK_AUTH_STRING "Tor initiator certificate verification"
 /** DOCDOC */
 int
@@ -1166,4 +1167,5 @@
 
   return 0;
 }
+#endif
 

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-12-01 04:58:53 UTC (rev 12621)
+++ tor/trunk/src/or/or.h	2007-12-01 08:09:46 UTC (rev 12622)
@@ -656,12 +656,17 @@
 #define CELL_CREATED_FAST 6
 #define CELL_VERSIONS 7
 #define CELL_NETINFO 8
+#if 0
 #define CELL_CERT 9
 #define CELL_LINK_AUTH 10
+#endif
 #define CELL_RELAY_EARLY 11 /*DOCDOC*/
 
+#if 0
 #define CELL_COMMAND_IS_VAR_LENGTH(x) \
   ((x) == CELL_CERT || (x) == CELL_VERSIONS)
+#endif
+#define CELL_COMMAND_IS_VAR_LENGTH(x) ((x) == CELL_VERSIONS)
 
 /** How long to test reachability before complaining to the user. */
 #define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60)