mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
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. svn:r12622
This commit is contained in:
@@ -31,6 +31,20 @@ Things we'd like to do in 0.2.0.x:
|
||||
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
|
||||
|
||||
+107
-4
@@ -34,6 +34,8 @@ const char tortls_c_id[] =
|
||||
#include "./log.h"
|
||||
#include <string.h>
|
||||
|
||||
// #define V2_HANDSHAKE_SERVER
|
||||
|
||||
/* Copied from or.h */
|
||||
#define LEGAL_NICKNAME_CHARACTERS \
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
@@ -59,10 +61,11 @@ struct tor_tls_t {
|
||||
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 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
|
||||
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 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
|
||||
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 @@ tor_tls_new(int sock, int isServer)
|
||||
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_tls_read(tor_tls_t *tls, char *cp, size_t len)
|
||||
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 @@ tor_tls_handshake(tor_tls_t *tls)
|
||||
}
|
||||
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 @@ tor_tls_verify_v1(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
|
||||
return r;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** DOCDOC
|
||||
*
|
||||
* Returns 1 on "verification is done", 0 on "still need LINK_AUTH."
|
||||
@@ -1025,6 +1127,7 @@ tor_tls_verify_certs_v2(int severity, tor_tls_t *tls,
|
||||
|
||||
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>
|
||||
|
||||
@@ -62,6 +62,7 @@ char *tor_tls_encode_my_certificate(tor_tls_t *tls, size_t *size_out,
|
||||
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 @@ int tor_tls_verify_certs_v2(int severity, tor_tls_t *tls,
|
||||
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);
|
||||
|
||||
+7
-12
@@ -38,8 +38,10 @@ static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
|
||||
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 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
|
||||
++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 @@ command_process_var_cell(var_cell_t *cell, or_connection_t *conn)
|
||||
++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 @@ 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) {
|
||||
@@ -495,6 +488,7 @@ command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
|
||||
} else {
|
||||
/* XXXX020 finish v1 verification. */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Process a 'netinfo' cell. DOCDOC say more. */
|
||||
@@ -612,6 +606,7 @@ 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)
|
||||
@@ -780,4 +775,4 @@ command_process_link_auth_cell(cell_t *cell, or_connection_t *conn)
|
||||
tor_free(checked);
|
||||
connection_mark_for_close(TO_CONN(conn));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1057,6 +1057,7 @@ connection_or_send_netinfo(or_connection_t *conn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define LINK_AUTH_STRING "Tor initiator certificate verification"
|
||||
/** DOCDOC */
|
||||
int
|
||||
@@ -1166,4 +1167,5 @@ connection_or_send_link_auth(or_connection_t *conn)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -656,12 +656,17 @@ 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*/
|
||||
|
||||
#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)
|
||||
|
||||
Reference in New Issue
Block a user