@@ -120,24 +120,6 @@ typedef struct tor_tls_context_t {
crypto_pk_t *auth_key;
} tor_tls_context_t;

/** Return values for tor_tls_classify_client_ciphers.
*
* @{
*/
/** An error occurred when examining the client ciphers */
#define CIPHERS_ERR -1
/** The client cipher list indicates that a v1 handshake was in use. */
#define CIPHERS_V1 1
/** The client cipher list indicates that the client is using the v2 or the
* v3 handshake, but that it is (probably!) lying about what ciphers it
* supports */
#define CIPHERS_V2 2
/** The client cipher list indicates that the client is using the v2 or the
* v3 handshake, and that it is telling the truth about what ciphers it
* supports */
#define CIPHERS_UNRESTRICTED 3
/** @} */

#define TOR_TLS_MAGIC 0x71571571

typedef enum {
@@ -167,9 +149,6 @@ struct tor_tls_t {
* one certificate). */
/** True iff we should call negotiated_callback when we're done reading. */
unsigned int got_renegotiate:1;
/** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't
* called that function yet. */
int8_t client_cipher_list_type;
/** 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
@@ -698,16 +677,8 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
#undef SERIAL_NUMBER_SIZE
}

/** List of ciphers that servers should select from when the client might be
* claiming extra unsupported ciphers in order to avoid fingerprinting. */
#define SERVER_CIPHER_LIST \
(TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" \
TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" \
SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)

/** List of ciphers that servers should select from when we actually have
* our choice of what cipher to use. */
const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
/** List of ciphers that servers should select from. */
const char SERVER_CIPHER_LIST[] =
/* This list is autogenerated with the gen_server_ciphers.py script;
* don't hand-edit it. */
#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384
@@ -755,7 +726,6 @@ const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
* (SSL3_TXT_RSA_NULL_SHA). If you do this, you won't be able to communicate
* with any of the "real" Tors, though. */

#ifdef V2_HANDSHAKE_CLIENT
#define CIPHER(id, name) name ":"
#define XCIPHER(id, name)
/** List of ciphers that clients should advertise, omitting items that
@@ -783,13 +753,6 @@ static const cipher_info_t CLIENT_CIPHER_INFO_LIST[] = {

/** The length of CLIENT_CIPHER_INFO_LIST and CLIENT_CIPHER_DUMMIES. */
static const int N_CLIENT_CIPHERS = ARRAY_LENGTH(CLIENT_CIPHER_INFO_LIST);
#endif

#ifndef V2_HANDSHAKE_CLIENT
#undef CLIENT_CIPHER_LIST
#define CLIENT_CIPHER_LIST (TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" \
SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
#endif

/** Free all storage held in <b>cert</b> */
void
@@ -1226,7 +1189,8 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
result->refcnt = 1;
if (!is_client) {
result->my_link_cert = tor_cert_new(X509_dup(cert));
result->my_id_cert = tor_cert_new(X509_dup(idcert));
result->my_id_cert = tor_cert_new(idcert);
if (result->my_id_cert) idcert = NULL;
result->my_auth_cert = tor_cert_new(X509_dup(authcert));
if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
goto error;
@@ -1332,13 +1296,6 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
goto error;
X509_free(cert); /* We just added a reference to cert. */
cert=NULL;
if (idcert) {
X509_STORE *s = SSL_CTX_get_cert_store(result->ctx);
tor_assert(s);
X509_STORE_add_cert(s, idcert);
X509_free(idcert); /* The context now owns the reference to idcert */
idcert = NULL;
}
}
SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
if (!is_client) {
@@ -1430,205 +1387,8 @@ tor_tls_get_ciphersuite_name(tor_tls_t *tls)

#ifdef V2_HANDSHAKE_SERVER

/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to
* 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers
* that it claims to support. We'll prune this list to remove the ciphers
* *we* don't recognize. */
static uint16_t v2_cipher_list[] = {
0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */
0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */
0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */
0x0038, /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */
0xc00f, /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */
0xc005, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */
0x0035, /* TLS1_TXT_RSA_WITH_AES_256_SHA */
0xc007, /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */
0xc009, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */
0xc011, /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */
0xc013, /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */
0x0033, /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */
0x0032, /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */
0xc00c, /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */
0xc00e, /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */
0xc002, /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */
0xc004, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */
0x0004, /* SSL3_TXT_RSA_RC4_128_MD5 */
0x0005, /* SSL3_TXT_RSA_RC4_128_SHA */
0x002f, /* TLS1_TXT_RSA_WITH_AES_128_SHA */
0xc008, /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */
0xc012, /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */
0x0016, /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */
0x0013, /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */
0xc00d, /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */
0xc003, /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */
0xfeff, /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */
0x000a, /* SSL3_TXT_RSA_DES_192_CBC3_SHA */
0
};
/** Have we removed the unrecognized ciphers from v2_cipher_list yet? */
static int v2_cipher_list_pruned = 0;

/** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>;
* return 1 if it does support it, or if we have no way to tell. */
static int
find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher)
{
const SSL_CIPHER *c;
#ifdef HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR
if (m && m->get_cipher_by_char) {
unsigned char cipherid[3];
set_uint16(cipherid, htons(cipher));
cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting
* with a two-byte 'cipherid', it may look for a v2
* cipher with the appropriate 3 bytes. */
c = m->get_cipher_by_char(cipherid);
if (c)
tor_assert((c->id & 0xffff) == cipher);
return c != NULL;
} else
#endif
if (m && m->get_cipher && m->num_ciphers) {
/* It would seem that some of the "let's-clean-up-openssl" forks have
* removed the get_cipher_by_char function. Okay, so now you get a
* quadratic search.
*/
int i;
for (i = 0; i < m->num_ciphers(); ++i) {
c = m->get_cipher(i);
if (c && (c->id & 0xffff) == cipher) {
return 1;
}
}
return 0;
} else {
return 1; /* No way to search */
}
}

/** Remove from v2_cipher_list every cipher that we don't support, so that
* comparing v2_cipher_list to a client's cipher list will give a sensible
* result. */
static void
prune_v2_cipher_list(void)
{
uint16_t *inp, *outp;
const SSL_METHOD *m = SSLv23_method();

inp = outp = v2_cipher_list;
while (*inp) {
if (find_cipher_by_id(m, *inp)) {
*outp++ = *inp++;
} else {
inp++;
}
}
*outp = 0;

v2_cipher_list_pruned = 1;
}

/** Examine the client cipher list in <b>ssl</b>, and determine what kind of
* client it is. Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2,
* CIPHERS_UNRESTRICTED.
**/
static int
tor_tls_classify_client_ciphers(const SSL *ssl,
STACK_OF(SSL_CIPHER) *peer_ciphers)
{
int i, res;
tor_tls_t *tor_tls;
if (PREDICT_UNLIKELY(!v2_cipher_list_pruned))
prune_v2_cipher_list();

tor_tls = tor_tls_get_by_ssl(ssl);
if (tor_tls && tor_tls->client_cipher_list_type)
return tor_tls->client_cipher_list_type;

/* If we reached this point, we just got a client hello. See if there is
* a cipher list. */
if (!peer_ciphers) {
log_info(LD_NET, "No ciphers on session");
res = CIPHERS_ERR;
goto done;
}
/* 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(peer_ciphers); ++i) {
SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
const char *ciphername = SSL_CIPHER_get_name(cipher);
if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) &&
strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) &&
strcmp(ciphername, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) &&
strcmp(ciphername, "(NONE)")) {
log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername);
// return 1;
goto v2_or_higher;
}
}
res = CIPHERS_V1;
goto done;
v2_or_higher:
{
const uint16_t *v2_cipher = v2_cipher_list;
for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
uint16_t id = cipher->id & 0xffff;
if (id == 0x00ff) /* extended renegotiation indicator. */
continue;
if (!id || id != *v2_cipher) {
res = CIPHERS_UNRESTRICTED;
goto dump_ciphers;
}
++v2_cipher;
}
if (*v2_cipher != 0) {
res = CIPHERS_UNRESTRICTED;
goto dump_ciphers;
}
res = CIPHERS_V2;
}

dump_ciphers:
{
smartlist_t *elts = smartlist_new();
char *s;
for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
const char *ciphername = SSL_CIPHER_get_name(cipher);
smartlist_add(elts, (char*)ciphername);
}
s = smartlist_join_strings(elts, ":", 0, NULL);
log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s. It is: '%s'",
(res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s);
tor_free(s);
smartlist_free(elts);
}
done:
if (tor_tls)
return tor_tls->client_cipher_list_type = res;

return res;
}

/** Return true iff the cipher list suggested by the client for <b>ssl</b> is
* a list that indicates that the client knows how to do the v2 TLS connection
* handshake. */
static int
tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
{
SSL_SESSION *session;
if (!(session = SSL_get_session((SSL *)ssl))) {
log_info(LD_NET, "No session on TLS?");
return CIPHERS_ERR;
}

return tor_tls_classify_client_ciphers(ssl, session->ciphers) >= CIPHERS_V2;
}

/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection
* changes state. We use this:
* <ul><li>To alter the state of the handshake partway through, so we
* do not send or request extra certificates in v2 handshakes.</li>
* <li>To detect renegotiation</li></ul>
*/
static void
@@ -1658,74 +1418,28 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
}

/* Now check the cipher list. */
if (tor_tls_client_is_using_v2_ciphers(ssl)) {
if (tls->wasV2Handshake)
return; /* We already turned this stuff off for the first handshake;
* This is a renegotiation. */
if (tls->wasV2Handshake)
return; /* We already turned this stuff off for the first handshake;
* This is a renegotiation. */

/* Yes, we're casting away the const from ssl. This is very naughty of us.
* Let's hope openssl doesn't notice! */
/* 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);
/* Don't send a hello request. */
SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL);

if (tls) {
tls->wasV2Handshake = 1;
if (tls) {
tls->wasV2Handshake = 1;
#ifdef USE_BUFFEREVENTS
if (use_unsafe_renegotiation_flag)
tls->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
if (use_unsafe_renegotiation_flag)
tls->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
#endif
} else {
log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
}
} else {
log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
}
}
#endif

#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
/** Callback to get invoked on a server after we've read the list of ciphers
* the client supports, but before we pick our own ciphersuite.
*
* We can't abuse an info_cb for this, since by the time one of the
* client_hello info_cbs is called, we've already picked which ciphersuite to
* use.
*
* Technically, this function is an abuse of this callback, since the point of
* a session_secret_cb is to try to set up and/or verify a shared-secret for
* authentication on the fly. But as long as we return 0, we won't actually be
* setting up a shared secret, and all will be fine.
*/
static int
tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
SSL_CIPHER **cipher, void *arg)
{
(void) secret;
(void) secret_len;
(void) peer_ciphers;
(void) cipher;
(void) arg;

if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) ==
CIPHERS_UNRESTRICTED) {
SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST);
}

SSL_set_session_secret_cb(ssl, NULL, NULL);

return 0;
}
static void
tor_tls_setup_session_secret_cb(tor_tls_t *tls)
{
SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
}
#else
#define tor_tls_setup_session_secret_cb(tls) STMT_NIL
#endif

/** Explain which ciphers we're missing. */
static void
log_unsupported_ciphers(smartlist_t *unsupported)
@@ -1925,9 +1639,6 @@ tor_tls_new(int sock, int isServer)
SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
}

if (isServer)
tor_tls_setup_session_secret_cb(result);

/* Not expected to get called. */
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
return result;
@@ -2178,43 +1889,18 @@ tor_tls_finish_handshake(tor_tls_t *tls)
if (tls->isServer) {
SSL_set_info_callback(tls->ssl, NULL);
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb);
/* There doesn't seem to be a clear OpenSSL API to clear mode flags. */
tls->ssl->mode &= ~SSL_MODE_NO_AUTO_CHAIN;
#ifdef V2_HANDSHAKE_SERVER
if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) {
/* This check is redundant, but back when we did it in the callback,
* we might have not been able to look up the tor_tls_t if the code
* was buggy. Fixing that. */
if (!tls->wasV2Handshake) {
log_warn(LD_BUG, "For some reason, wasV2Handshake didn't"
" get set. Fixing that.");
}
tls->wasV2Handshake = 1;
log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting"
" for renegotiation.");
} else {
tls->wasV2Handshake = 0;
/* This check is redundant, but back when we did it in the callback,
* we might have not been able to look up the tor_tls_t if the code
* was buggy. Fixing that. */
if (!tls->wasV2Handshake) {
log_warn(LD_BUG, "For some reason, wasV2Handshake didn't"
" get set. Fixing that.");
}
#endif
tls->wasV2Handshake = 1;
log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting"
" for renegotiation.");
} else {
#ifdef V2_HANDSHAKE_CLIENT
/* If we got no ID cert, we're a v2 handshake. */
X509 *cert = SSL_get_peer_certificate(tls->ssl);
STACK_OF(X509) *chain = SSL_get_peer_cert_chain(tls->ssl);
int n_certs = sk_X509_num(chain);
if (n_certs > 1 || (n_certs == 1 && cert != sk_X509_value(chain, 0))) {
log_debug(LD_HANDSHAKE, "Server sent back multiple certificates; it "
"looks like a v1 handshake on %p", tls);
tls->wasV2Handshake = 0;
} else {
log_debug(LD_HANDSHAKE,
"Server sent back a single certificate; looks like "
"a v2 handshake on %p.", tls);
tls->wasV2Handshake = 1;
}
if (cert)
X509_free(cert);
#endif
tls->wasV2Handshake = 1;
if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) {
tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers");
r = TOR_TLS_ERROR_MISC;
@@ -2638,27 +2324,6 @@ check_no_tls_errors_(const char *fname, int line)
tls_log_errors(NULL, LOG_WARN, LD_NET, NULL);
}

/** Return true iff the initial TLS connection at <b>tls</b> did not use a v2
* TLS handshake. Output is undefined if the handshake isn't finished. */
int
tor_tls_used_v1_handshake(tor_tls_t *tls)
{
#if defined(V2_HANDSHAKE_SERVER) && defined(V2_HANDSHAKE_CLIENT)
return ! tls->wasV2Handshake;
#else
if (tls->isServer) {
# ifdef V2_HANDSHAKE_SERVER
return ! tls->wasV2Handshake;
# endif
} else {
# ifdef V2_HANDSHAKE_CLIENT
return ! tls->wasV2Handshake;
# endif
}
return 1;
#endif
}

/** Return true iff <b>name</b> is a DN of a kind that could only
* occur in a v3-handshake-indicating certificate */
static int
@@ -98,7 +98,6 @@ void tor_tls_get_buffer_sizes(tor_tls_t *tls,

MOCK_DECL(double, tls_get_write_overhead_ratio, (void));

int tor_tls_used_v1_handshake(tor_tls_t *tls);
int tor_tls_received_v3_certificate(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);
@@ -1466,37 +1466,36 @@ connection_tls_continue_handshake(or_connection_t *conn)
tor_tls_err_to_string(result));
return -1;
case TOR_TLS_DONE:
if (! tor_tls_used_v1_handshake(conn->tls)) {
if (!tor_tls_is_server(conn->tls)) {
if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_received_v3_certificate(conn->tls)) {
log_info(LD_OR, "Client got a v3 cert! Moving on to v3 "
"handshake with ciphersuite %s",
tor_tls_get_ciphersuite_name(conn->tls));
return connection_or_launch_v3_or_handshake(conn);
} else {
log_debug(LD_OR, "Done with initial SSL handshake (client-side)."
" Requesting renegotiation.");
connection_or_change_state(conn,
OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
goto again;
}
if (!tor_tls_is_server(conn->tls)) {
if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_received_v3_certificate(conn->tls)) {
log_info(LD_OR, "Client got a v3 cert! Moving on to v3 "
"handshake with ciphersuite %s",
tor_tls_get_ciphersuite_name(conn->tls));
return connection_or_launch_v3_or_handshake(conn);
} else {
log_debug(LD_OR, "Done with initial SSL handshake (client-side)."
" Requesting renegotiation.");
connection_or_change_state(conn,
OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
goto again;
}
// log_notice(LD_OR,"Done. state was %d.", conn->base_.state);
} else {
/* v2/v3 handshake, but not a client. */
log_debug(LD_OR, "Done with initial SSL handshake (server-side). "
"Expecting renegotiation or VERSIONS cell");
tor_tls_set_renegotiate_callback(conn->tls,
connection_or_tls_renegotiated_cb,
conn);
connection_or_change_state(conn,
OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
connection_stop_writing(TO_CONN(conn));
connection_start_reading(TO_CONN(conn));
return 0;
}
// log_notice(LD_OR,"Done. state was %d.", conn->base_.state);
} else {
/* v2/v3 handshake, but not a client. */
log_debug(LD_OR, "Done with initial SSL handshake (server-side). "
"Expecting renegotiation or VERSIONS cell");
tor_tls_set_renegotiate_callback(conn->tls,
connection_or_tls_renegotiated_cb,
conn);
connection_or_change_state(conn,
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);
case TOR_TLS_WANTWRITE:
connection_start_writing(TO_CONN(conn));
@@ -1529,54 +1528,53 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
}
}

if (! tor_tls_used_v1_handshake(conn->tls)) {
if (!tor_tls_is_server(conn->tls)) {
if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_received_v3_certificate(conn->tls)) {
log_info(LD_OR, "Client got a v3 cert!");
if (connection_or_launch_v3_or_handshake(conn) < 0)
connection_or_close_for_error(conn, 0);
return;
} else {
connection_or_change_state(conn,
OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
tor_tls_unblock_renegotiation(conn->tls);
if (bufferevent_ssl_renegotiate(conn->base_.bufev)<0) {
log_warn(LD_OR, "Start_renegotiating went badly.");
connection_or_close_for_error(conn, 0);
}
tor_tls_unblock_renegotiation(conn->tls);
return; /* ???? */
if (!tor_tls_is_server(conn->tls)) {
if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_received_v3_certificate(conn->tls)) {
log_info(LD_OR, "Client got a v3 cert!");
if (connection_or_launch_v3_or_handshake(conn) < 0)
connection_or_close_for_error(conn, 0);
return;
} else {
connection_or_change_state(conn,
OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
tor_tls_unblock_renegotiation(conn->tls);
if (bufferevent_ssl_renegotiate(conn->base_.bufev)<0) {
log_warn(LD_OR, "Start_renegotiating went badly.");
connection_or_close_for_error(conn, 0);
}
tor_tls_unblock_renegotiation(conn->tls);
return; /* ???? */
}
}
} else {
const int handshakes = tor_tls_get_num_server_handshakes(conn->tls);

if (handshakes == 1) {
/* v2 or v3 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);
connection_or_change_state(conn,
OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
} else if (handshakes == 2) {
/* v2 handshake, as a server. Two handshakes happened already,
* so we treat renegotiation as done.
*/
connection_or_tls_renegotiated_cb(conn->tls, conn);
} else if (handshakes > 2) {
log_warn(LD_OR, "More than two handshakes done on connection. "
"Closing.");
connection_or_close_for_error(conn, 0);
} else {
const int handshakes = tor_tls_get_num_server_handshakes(conn->tls);

if (handshakes == 1) {
/* v2 or v3 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);
connection_or_change_state(conn,
OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
} else if (handshakes == 2) {
/* v2 handshake, as a server. Two handshakes happened already,
* so we treat renegotiation as done.
*/
connection_or_tls_renegotiated_cb(conn->tls, conn);
} else if (handshakes > 2) {
log_warn(LD_OR, "More than two handshakes done on connection. "
"Closing.");
connection_or_close_for_error(conn, 0);
} else {
log_warn(LD_BUG, "We were unexpectedly told that a connection "
"got %d handshakes. Closing.", handshakes);
connection_or_close_for_error(conn, 0);
}
return;
log_warn(LD_BUG, "We were unexpectedly told that a connection "
"got %d handshakes. Closing.", handshakes);
connection_or_close_for_error(conn, 0);
}
return;
}

connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT);
if (connection_tls_finish_handshake(conn) < 0)
connection_or_close_for_error(conn, 0); /* ???? */
@@ -1812,24 +1810,14 @@ connection_tls_finish_handshake(or_connection_t *conn)

circuit_build_times_network_is_live(get_circuit_build_times_mutable());

if (tor_tls_used_v1_handshake(conn->tls)) {
conn->link_proto = 1;
if (!started_here) {
connection_or_init_conn_from_address(conn, &conn->base_.addr,
conn->base_.port, digest_rcvd, 0);
}
tor_tls_block_renegotiation(conn->tls);
return connection_or_set_state_open(conn);
} else {
connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2);
if (connection_init_or_handshake_state(conn, started_here) < 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_send_versions(conn, 0);
connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2);
if (connection_init_or_handshake_state(conn, started_here) < 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_send_versions(conn, 0);
}

/**