[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)