diff options
author | Nick Mathewson <nickm@torproject.org> | 2008-01-13 00:20:47 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2008-01-13 00:20:47 +0000 |
commit | edf5e70784dc3519b656e12b9b7f7928fa85884a (patch) | |
tree | 243fc111ed3877a894e045508e1c0e84442164d8 /src/or | |
parent | ae6df065ed699278db5a219650cd0037dac2adec (diff) | |
download | tor-edf5e70784dc3519b656e12b9b7f7928fa85884a.tar tor-edf5e70784dc3519b656e12b9b7f7928fa85884a.tar.gz |
r15891@tombo: nickm | 2008-01-12 19:20:24 -0500
Basic hacks to get TLS handshakes working: remove dead code; fix post-handshake logic; keep servers from writing while the client is supposed to be renegotiating. This may work. Needs testing.
svn:r13122
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/command.c | 190 | ||||
-rw-r--r-- | src/or/connection.c | 11 | ||||
-rw-r--r-- | src/or/connection_or.c | 195 | ||||
-rw-r--r-- | src/or/or.h | 36 |
4 files changed, 65 insertions, 367 deletions
diff --git a/src/or/command.c b/src/or/command.c index b39080429..61ff77c80 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -461,10 +461,8 @@ command_process_versions_cell(var_cell_t *cell, or_connection_t *conn) end = cell->payload + cell->payload_len; for (cp = cell->payload; cp+1 < end; ++cp) { uint16_t v = ntohs(get_uint16(cp)); - if (v == 1 || v == 2) { - if (v > highest_supported_version) - highest_supported_version = v; - } + if (is_or_protocol_version_known(v) && v > highest_supported_version) + highest_supported_version = v; } if (!highest_supported_version) { log_fn(LOG_PROTOCOL_WARN, LD_OR, @@ -476,20 +474,15 @@ command_process_versions_cell(var_cell_t *cell, or_connection_t *conn) 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) { + if (connection_or_send_netinfo(conn) < 0) { connection_mark_for_close(TO_CONN(conn)); return; } - if (conn->handshake_state->started_here) - connection_or_send_link_auth(conn); } else { - /* XXXX020 finish v1 verification. */ + /* Should be impossible. */ + tor_fragile_assert(); } -#endif } /** Process a 'netinfo' cell. DOCDOC say more. */ @@ -577,7 +570,7 @@ connection_or_act_on_netinfo(or_connection_t *conn) if (!conn->handshake_state) return -1; - tor_assert(conn->handshake_state->authenticated != 0); + tor_assert(conn->handshake_state->received_versions != 0); delta = conn->handshake_state->apparent_skew; /*XXXX020 magic number 3600 */ @@ -607,174 +600,3 @@ connection_or_act_on_netinfo(or_connection_t *conn) return 0; } -#if 0 -/*DOCDOC*/ -static void -command_process_cert_cell(var_cell_t *cell, or_connection_t *conn) -{ - int n_certs = 0; - uint16_t conn_cert_len = 0, id_cert_len = 0; - const char *conn_cert = NULL, *id_cert = NULL; - const char *cp, *end; - int done = 0; - - if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got CERT cell when not handshaking. " - "Ignoring."); - return; - } - tor_assert(conn->handshake_state); - if (!conn->handshake_state->received_versions || - !conn->handshake_state->received_netinfo) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got CERT cell before VERSIONS and " - "NETINFO. Closing the connection."); - goto err; - } - if (conn->handshake_state->received_certs) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got duplicate CERT cell. " - "Closing the connection."); - goto err; - } - - cp = cell->payload; - end = cell->payload + cell->payload_len; - - while (cp < end) { - uint16_t len; - if (end-cp == 1) - goto err; - len = ntohs(get_uint16(cp)); - cp += 2; - if (end-cp < len) - goto err; - if (n_certs == 0) { - id_cert = cp; - id_cert_len = len; - } else if (n_certs == 1) { - conn_cert = id_cert; - conn_cert_len = id_cert_len; - id_cert = cp; - id_cert_len = len; - } else { - goto err; - } - cp += len; - ++n_certs; - } - - /* Now we have 0, 1, or 2 certs. */ - if (n_certs == 0) { - /* The other side is unauthenticated. */ - done = 1; - } else { - int r; - r = tor_tls_verify_certs_v2(LOG_PROTOCOL_WARN, conn->tls, - conn_cert, conn_cert_len, - id_cert, id_cert_len, - &conn->handshake_state->signing_key, - (conn->handshake_state->started_here ? - conn->handshake_state->server_cert_digest : - conn->handshake_state->client_cert_digest), - &conn->handshake_state->identity_key, - conn->handshake_state->cert_id_digest); - if (r < 0) - goto err; - if (r == 1) { - done = 1; - conn->handshake_state->authenticated = 1; - } - } - - conn->handshake_state->received_certs = 1; - if (done) { - if (connection_or_finish_or_handshake(conn) < 0) - goto err; - } - if (! conn->handshake_state->signing_key) - goto err; - - return; - err: - connection_mark_for_close(TO_CONN(conn)); -} - -#define LINK_AUTH_STRING "Tor initiator certificate verification" - -/** DOCDOC */ -static void -command_process_link_auth_cell(cell_t *cell, or_connection_t *conn) -{ - or_handshake_state_t *s; - char hmac[DIGEST_LEN]; - uint16_t len; - size_t sig_len; - const char *sig; - char *checked = NULL; - int checked_len; - tor_assert(conn); - if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Received a LINK_AUTH cell on connection in the wrong state; " - "dropping."); - return; - } - s = conn->handshake_state; - tor_assert(s); - if (s->started_here) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Got a LINK_AUTH cell from a server; closing the connection."); - goto err; - } - if (!s->received_netinfo || !s->received_versions || !s->received_certs) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got a LINK_AUTH cell too early; " - "closing the connection"); - goto err; - } - len = ntohs(get_uint16(cell->payload)); - if (len < 2 || len > CELL_PAYLOAD_SIZE - 2) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Bad length field (%d) on LINK_AUTH cell;" - " closing the connection", (int)len); - goto err; - } - if (cell->payload[2] != 0x00) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Unrecognized LINK_AUTH signature " - "version; closing the connection"); - goto err; - } - connection_or_compute_link_auth_hmac(conn, hmac); - - tor_assert(s->signing_key); - - sig = cell->payload+3; - sig_len = len-1; - checked = tor_malloc(crypto_pk_keysize(s->signing_key)); - checked_len = crypto_pk_public_checksig(s->signing_key,checked,sig,sig_len); - if (checked_len < 0) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Bad signature on LINK_AUTH cell; " - "closing the connection"); - goto err; - } - if (checked_len != DIGEST_LEN) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Bad length (%d) of signed material in " - "LINK_AUTH cell; closing the connection", checked_len); - goto err; - } - if (memcmp(checked, hmac, DIGEST_LEN) != 0) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Bad signed data in LINK_AUTH cell; " - "closing the connection."); - goto err; - } - - s->authenticated = 1; - - if (connection_or_finish_or_handshake(conn)<0) - goto err; - - tor_free(checked); - return; - err: - tor_free(checked); - connection_mark_for_close(TO_CONN(conn)); -} -#endif - diff --git a/src/or/connection.c b/src/or/connection.c index 69b3f7536..757516c66 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -90,7 +90,10 @@ conn_state_to_string(int type, int state) case OR_CONN_STATE_PROXY_FLUSHING: return "proxy flushing"; case OR_CONN_STATE_PROXY_READING: return "proxy reading"; case OR_CONN_STATE_TLS_HANDSHAKING: return "handshaking (TLS)"; - case OR_CONN_STATE_TLS_RENEGOTIATING: return "renegotiating (TLS)"; + case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING: + return "renegotiating (TLS)"; + case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: + return "waiting for renegotiation (TLS)"; case OR_CONN_STATE_OR_HANDSHAKING: return "handshaking (Tor)"; case OR_CONN_STATE_OPEN: return "open"; } @@ -1896,7 +1899,7 @@ connection_read_to_buf(connection_t *conn, int *max_to_read) int pending; or_connection_t *or_conn = TO_OR_CONN(conn); if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || - conn->state == OR_CONN_STATE_TLS_RENEGOTIATING) { + conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { /* continue handshaking even if global token bucket is empty */ return connection_tls_continue_handshake(or_conn); } @@ -2118,7 +2121,7 @@ connection_handle_write(connection_t *conn, int force) conn->state > OR_CONN_STATE_PROXY_READING) { or_connection_t *or_conn = TO_OR_CONN(conn); if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || - conn->state == OR_CONN_STATE_TLS_RENEGOTIATING) { + conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { connection_stop_writing(conn); if (connection_tls_continue_handshake(or_conn) < 0) { /* Don't flush; connection is dead. */ @@ -2127,6 +2130,8 @@ connection_handle_write(connection_t *conn, int force) return -1; } return 0; + } else if (conn->state == OR_CONN_STATE_TLS_SERVER_RENEGOTIATING) { + return connection_handle_read(conn); } /* else open, or closing */ diff --git a/src/or/connection_or.c b/src/or/connection_or.c index fc5373c92..c639649de 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -584,14 +584,18 @@ static void connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn) { or_connection_t *conn = _conn; - char id_digest[DIGEST_LEN]; + (void)tls; - if (connection_or_check_valid_tls_handshake(conn, - !tor_tls_is_server(tls), - id_digest) < 0) - return; + if (connection_tls_finish_handshake(conn) < 0) { + /* XXXX020 double-check that it's ok to do this from inside read. */ + connection_mark_for_close(TO_CONN(conn)); + } + +#if 0 + /* XXXX020 this happens later, right? */ connection_or_init_conn_from_address(conn, conn->_base.addr, conn->_base.port, id_digest, 0); +#endif } /** Move forward with the tls handshake. If it finishes, hand @@ -605,10 +609,12 @@ connection_tls_continue_handshake(or_connection_t *conn) int result; check_no_tls_errors(); again: - if (conn->_base.state == OR_CONN_STATE_TLS_RENEGOTIATING) + if (conn->_base.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) result = tor_tls_renegotiate(conn->tls); - else + else { + tor_assert(conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING); result = tor_tls_handshake(conn->tls); + } switch (result) { CASE_TOR_TLS_ERROR_ANY: log_info(LD_OR,"tls error [%s]. breaking connection.", @@ -618,7 +624,7 @@ connection_tls_continue_handshake(or_connection_t *conn) if (! tor_tls_used_v1_handshake(conn->tls)) { if (!tor_tls_is_server(conn->tls)) { if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) { - conn->_base.state = OR_CONN_STATE_TLS_RENEGOTIATING; + conn->_base.state = OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING; goto again; } } else { @@ -626,6 +632,10 @@ connection_tls_continue_handshake(or_connection_t *conn) tor_tls_set_renegotiate_callback(conn->tls, connection_or_tls_renegotiated_cb, conn); + conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING; + connection_stop_writing(TO_CONN(conn)); + connection_start_reading(TO_CONN(conn)); + return 0; } } return connection_tls_finish_handshake(conn); @@ -829,22 +839,18 @@ connection_tls_finish_handshake(or_connection_t *conn) directory_set_dirty(); + if (connection_or_check_valid_tls_handshake(conn, started_here, + digest_rcvd) < 0) + return -1; + if (tor_tls_used_v1_handshake(conn->tls)) { conn->link_proto = 1; - if (connection_or_check_valid_tls_handshake(conn, started_here, - digest_rcvd) < 0) - return -1; if (!started_here) { connection_or_init_conn_from_address(conn,conn->_base.addr, conn->_base.port, digest_rcvd, 0); } return connection_or_set_state_open(conn); } else { - if (started_here) { - if (connection_or_check_valid_tls_handshake(conn, started_here, - digest_rcvd) < 0) - return -1; - } conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING; if (connection_init_or_handshake_state(conn, started_here) < 0) return -1; @@ -859,21 +865,6 @@ connection_init_or_handshake_state(or_connection_t *conn, int started_here) or_handshake_state_t *s; s = conn->handshake_state = tor_malloc_zero(sizeof(or_handshake_state_t)); s->started_here = started_here ? 1 : 0; - if (tor_tls_get_random_values(conn->tls, - conn->handshake_state->client_random, - conn->handshake_state->server_random) < 0) - return -1; - if (started_here) { - if (tor_tls_get_cert_digests(conn->tls, - s->client_cert_digest, - s->server_cert_digest)<0) - return -1; - } else { - if (tor_tls_get_cert_digests(conn->tls, - s->server_cert_digest, - s->client_cert_digest)<0) - return -1; - } return 0; } @@ -882,10 +873,6 @@ void or_handshake_state_free(or_handshake_state_t *state) { tor_assert(state); - if (state->signing_key) - crypto_free_pk_env(state->signing_key); - if (state->identity_key) - crypto_free_pk_env(state->identity_key); memset(state, 0xBE, sizeof(or_handshake_state_t)); tor_free(state); } @@ -1036,21 +1023,35 @@ connection_or_send_destroy(uint16_t circ_id, or_connection_t *conn, int reason) return 0; } +/**DOCDOC*/ +static const uint16_t or_protocol_versions[] = { 1, 2 }; +static const int n_or_protocol_versions = + sizeof(or_protocol_versions)/sizeof(uint16_t); + +/**DOCDOC*/ +int +is_or_protocol_version_known(uint16_t v) +{ + int i; + for (i = 0; i < n_or_protocol_versions; ++i) { + if (or_protocol_versions[i] == v) + return 1; + } + return 0; +} + /** DOCDOC */ static int connection_or_send_versions(or_connection_t *conn) { var_cell_t *cell; - uint16_t versions[] = { 1, 2 }; - int n_versions = sizeof(versions) / sizeof(uint8_t); int i; tor_assert(conn->handshake_state && !conn->handshake_state->sent_versions_at); - /*XXXX020 docdoc 2-byte versions */ - cell = var_cell_new(n_versions * 2); + cell = var_cell_new(n_or_protocol_versions * 2); cell->command = CELL_VERSIONS; - for (i = 0; i < n_versions; ++i) { - uint16_t v = versions[i]; + for (i = 0; i < n_or_protocol_versions; ++i) { + uint16_t v = or_protocol_versions[i]; set_uint16(cell->payload+(2*i), htons(v)); } @@ -1093,115 +1094,3 @@ connection_or_send_netinfo(or_connection_t *conn) return 0; } -#if 0 -#define LINK_AUTH_STRING "Tor initiator certificate verification" -/** DOCDOC */ -int -connection_or_compute_link_auth_hmac(or_connection_t *conn, - char *hmac_out) -{ - char buf[64 + 2*TOR_TLS_RANDOM_LEN + 2*DIGEST_LEN]; - char *cp; - or_handshake_state_t *s; - tor_assert(conn); - tor_assert(conn->handshake_state); - tor_assert(conn->tls); - s = conn->handshake_state; - - /* Fill the buffer. */ - strlcpy(buf, LINK_AUTH_STRING, sizeof(buf)); - cp = buf+strlen(buf); - ++cp; /* Skip the NUL */ - memcpy(cp, s->client_random, TOR_TLS_RANDOM_LEN); - cp += TOR_TLS_RANDOM_LEN; - memcpy(cp, s->server_random, TOR_TLS_RANDOM_LEN); - cp += TOR_TLS_RANDOM_LEN; - memcpy(cp, s->client_cert_digest, DIGEST_LEN); - cp += DIGEST_LEN; - memcpy(cp, s->server_cert_digest, DIGEST_LEN); - cp += DIGEST_LEN; - tor_assert(cp < buf+sizeof(buf)); - - if (tor_tls_hmac_with_master_secret(conn->tls, hmac_out, buf, cp-buf) < 0) - return -1; - return 0; -} - -/**DOCDOC*/ -int -connection_or_send_cert(or_connection_t *conn) -{ - size_t conn_cert_len = 0, id_cert_len = 0, total_len = 0; - char *id_cert = NULL, *conn_cert = NULL; - var_cell_t *cell; - char *cp; - - /* If we're a client, we can send no cert at all. XXXXX020 */ - /* DOCDOC length of cert before cert. */ - tor_assert(conn); - tor_assert(conn->handshake_state); - tor_assert(conn->handshake_state->received_versions == 1); - if (conn->handshake_state->started_here) - conn_cert = tor_tls_encode_my_certificate(conn->tls, &conn_cert_len, 1); - id_cert = tor_tls_encode_my_certificate(conn->tls, &id_cert_len, 0); - tor_assert(id_cert); - total_len = id_cert_len + conn_cert_len + conn_cert ? 4 : 2; - - cell = var_cell_new(total_len); - cell->command = CELL_VERSIONS; - cp = cell->payload; - if (conn_cert) { - set_uint16(cp, htons(conn_cert_len)); - cp += 2; - memcpy(cp, conn_cert, conn_cert_len); - cp += conn_cert_len; - } - set_uint16(cp, htons(id_cert_len)); - cp += 2; - memcpy(cp, id_cert, id_cert_len); - cp += id_cert_len; - tor_assert(cp == cell->payload + total_len); - - connection_or_write_var_cell_to_buf(cell, conn); - - tor_free(conn_cert); - tor_free(id_cert); - var_cell_free(cell); - return 0; -} - -/**DOCDOC*/ -int -connection_or_send_link_auth(or_connection_t *conn) -{ - cell_t cell; - char hmac[DIGEST_LEN]; - crypto_pk_env_t *key; - int r, len; - - tor_assert(conn); - tor_assert(conn->tls); - tor_assert(conn->handshake_state); - tor_assert(conn->handshake_state->started_here == 1); - tor_assert(conn->handshake_state->received_certs == 1); - - memset(&cell, 0, sizeof(cell)); - cell.command = CELL_LINK_AUTH; - key = tor_tls_dup_private_key(conn->tls); - connection_or_compute_link_auth_hmac(conn, hmac); - - cell.payload[2] = 0x00; /* Signature version */ - r = crypto_pk_private_sign(key, cell.payload+3, hmac, sizeof(hmac)); - crypto_free_pk_env(key); - if (r<0) - return -1; - len = r + 1; - - set_uint16(cell.payload, htons(len)); - - connection_or_write_cell_to_buf(&cell, conn); - - return 0; -} -#endif - diff --git a/src/or/or.h b/src/or/or.h index b96693260..d19b41b94 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -248,14 +248,16 @@ typedef enum { /** State for a connection to an OR: SSL is handshaking, not done yet. */ #define OR_CONN_STATE_TLS_HANDSHAKING 4 /** DOCDOC */ -#define OR_CONN_STATE_TLS_RENEGOTIATING 5 +#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 5 +/** DOCDOC */ +#define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 6 /** State for a connection to an OR: We're done with our SSL handshake, but we * haven't yet negotiated link protocol versions and finished authenticating. */ -#define OR_CONN_STATE_OR_HANDSHAKING 6 +#define OR_CONN_STATE_OR_HANDSHAKING 7 /** State for a connection to an OR: Ready to send/receive cells. */ -#define OR_CONN_STATE_OPEN 7 -#define _OR_CONN_STATE_MAX 7 +#define OR_CONN_STATE_OPEN 8 +#define _OR_CONN_STATE_MAX 8 #define _EXIT_CONN_STATE_MIN 1 /** State for an exit connection: waiting for response from dns farm. */ @@ -669,16 +671,8 @@ typedef enum { #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*/ +#define CELL_RELAY_EARLY 9 -#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. */ @@ -823,7 +817,7 @@ typedef struct connection_t { * connections. Set once we've set the stream end, * and check in connection_about_to_close_connection(). */ - /** Edge connections only: true if we've blocked writing until the + /** Edge connections only: true if we've blocked reading until the * circuit has fewer queued cells. */ unsigned int edge_blocked_on_circ:1; /** Used for OR conns that shouldn't get any new circs attached to them. */ @@ -895,24 +889,11 @@ typedef struct or_handshake_state_t { unsigned int started_here : 1; unsigned int received_versions : 1; unsigned int received_netinfo : 1; - unsigned int received_certs : 1; - unsigned int authenticated : 1; - - /* from tls */ - char client_random[TOR_TLS_RANDOM_LEN]; - char server_random[TOR_TLS_RANDOM_LEN]; - char client_cert_digest[DIGEST_LEN]; /* may also be set by netinfo */ - char server_cert_digest[DIGEST_LEN]; /* from netinfo */ long apparent_skew; uint32_t my_apparent_addr; unsigned int apparently_canonical; - - /* from certs */ - char cert_id_digest[DIGEST_LEN]; - crypto_pk_env_t *signing_key; - crypto_pk_env_t *identity_key; } or_handshake_state_t; /** Subtype of connection_t for an "OR connection" -- that is, one that speaks @@ -2873,6 +2854,7 @@ int connection_or_send_cert(or_connection_t *conn); int connection_or_send_link_auth(or_connection_t *conn); int connection_or_compute_link_auth_hmac(or_connection_t *conn, char *hmac_out); +int is_or_protocol_version_known(uint16_t version); void cell_pack(packed_cell_t *dest, const cell_t *src); void var_cell_pack_header(const var_cell_t *cell, char *hdr_out); |