|
@@ -75,8 +75,8 @@
|
|
|
#include "container.h"
|
|
|
#include <string.h>
|
|
|
|
|
|
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
|
|
|
-#error "We require OpenSSL >= 0.9.8"
|
|
|
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
|
|
|
+#error "We require OpenSSL >= 1.0.0"
|
|
|
#endif
|
|
|
|
|
|
/* Enable the "v2" TLS handshake.
|
|
@@ -93,10 +93,8 @@
|
|
|
|
|
|
#define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer")
|
|
|
|
|
|
-#if (OPENSSL_VERSION_NUMBER < OPENSSL_V(0,9,8,'s') || \
|
|
|
- (OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,9) && \
|
|
|
- OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f')))
|
|
|
-/* This is a version of OpenSSL before 0.9.8s/1.0.0f. It does not have
|
|
|
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f')
|
|
|
+/* This is a version of OpenSSL before 1.0.0f. It does not have
|
|
|
* the CVE-2011-4576 fix, and as such it can't use RELEASE_BUFFERS and
|
|
|
* SSL3 safely at the same time.
|
|
|
*/
|
|
@@ -114,13 +112,6 @@
|
|
|
#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010
|
|
|
#endif
|
|
|
|
|
|
-/** Does the run-time openssl version look like we need
|
|
|
- * SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION? */
|
|
|
-static int use_unsafe_renegotiation_op = 0;
|
|
|
-/** Does the run-time openssl version look like we need
|
|
|
- * SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION? */
|
|
|
-static int use_unsafe_renegotiation_flag = 0;
|
|
|
-
|
|
|
/** Structure that we use for a single certificate. */
|
|
|
struct tor_cert_t {
|
|
|
X509 *cert;
|
|
@@ -485,56 +476,6 @@ tor_tls_init(void)
|
|
|
|
|
|
version = SSLeay();
|
|
|
|
|
|
- /* OpenSSL 0.9.8l introduced SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
|
|
|
- * here, but without thinking too hard about it: it turns out that the
|
|
|
- * flag in question needed to be set at the last minute, and that it
|
|
|
- * conflicted with an existing flag number that had already been added
|
|
|
- * in the OpenSSL 1.0.0 betas. OpenSSL 0.9.8m thoughtfully replaced
|
|
|
- * the flag with an option and (it seems) broke anything that used
|
|
|
- * SSL3_FLAGS_* for the purpose. So we need to know how to do both,
|
|
|
- * and we mustn't use the SSL3_FLAGS option with anything besides
|
|
|
- * OpenSSL 0.9.8l.
|
|
|
- *
|
|
|
- * No, we can't just set flag 0x0010 everywhere. It breaks Tor with
|
|
|
- * OpenSSL 1.0.0beta3 and later. On the other hand, we might be able to
|
|
|
- * set option 0x00040000L everywhere.
|
|
|
- *
|
|
|
- * No, we can't simply detect whether the flag or the option is present
|
|
|
- * in the headers at build-time: some vendors (notably Apple) like to
|
|
|
- * leave their headers out of sync with their libraries.
|
|
|
- *
|
|
|
- * Yes, it _is_ almost as if the OpenSSL developers decided that no
|
|
|
- * program should be allowed to use renegotiation unless it first passed
|
|
|
- * a test of intelligence and determination.
|
|
|
- */
|
|
|
- if (version > OPENSSL_V(0,9,8,'k') && version <= OPENSSL_V(0,9,8,'l')) {
|
|
|
- log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
|
|
|
- "some vendors have backported renegotiation code from "
|
|
|
- "0.9.8m without updating the version number. "
|
|
|
- "I will try SSL3_FLAGS and SSL_OP to enable renegotation.",
|
|
|
- SSLeay_version(SSLEAY_VERSION));
|
|
|
- use_unsafe_renegotiation_flag = 1;
|
|
|
- use_unsafe_renegotiation_op = 1;
|
|
|
- } else if (version > OPENSSL_V(0,9,8,'l')) {
|
|
|
- log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
|
|
|
- "I will try SSL_OP to enable renegotiation",
|
|
|
- SSLeay_version(SSLEAY_VERSION));
|
|
|
- use_unsafe_renegotiation_op = 1;
|
|
|
- } else if (version <= OPENSSL_V(0,9,8,'k')) {
|
|
|
- log_info(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
|
|
|
- "0.9.8l, but some vendors have backported 0.9.8l's "
|
|
|
- "renegotiation code to earlier versions, and some have "
|
|
|
- "backported the code from 0.9.8m or 0.9.8n. I'll set both "
|
|
|
- "SSL3_FLAGS and SSL_OP just to be safe.",
|
|
|
- SSLeay_version(SSLEAY_VERSION), version);
|
|
|
- use_unsafe_renegotiation_flag = 1;
|
|
|
- use_unsafe_renegotiation_op = 1;
|
|
|
- } else {
|
|
|
- /* this is dead code, yes? */
|
|
|
- log_info(LD_GENERAL, "OpenSSL %s has version %lx",
|
|
|
- SSLeay_version(SSLEAY_VERSION), version);
|
|
|
- }
|
|
|
-
|
|
|
#if (SIZEOF_VOID_P >= 8 && \
|
|
|
!defined(OPENSSL_NO_EC) && \
|
|
|
OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
|
|
@@ -1327,24 +1268,6 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- /* XXX This block is now obsolete. */
|
|
|
- if (
|
|
|
-#ifdef DISABLE_SSL3_HANDSHAKE
|
|
|
- 1 ||
|
|
|
-#endif
|
|
|
- SSLeay() < OPENSSL_V(0,9,8,'s') ||
|
|
|
- (SSLeay() >= OPENSSL_V_SERIES(0,9,9) &&
|
|
|
- SSLeay() < OPENSSL_V(1,0,0,'f'))) {
|
|
|
- /* And not SSL3 if it's subject to CVE-2011-4576. */
|
|
|
- log_info(LD_NET, "Disabling SSLv3 because this OpenSSL version "
|
|
|
- "might otherwise be vulnerable to CVE-2011-4576 "
|
|
|
- "(compile-time version %08lx (%s); "
|
|
|
- "runtime version %08lx (%s))",
|
|
|
- (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT,
|
|
|
- (unsigned long)SSLeay(), SSLeay_version(SSLEAY_VERSION));
|
|
|
- SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3);
|
|
|
- }
|
|
|
-
|
|
|
SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE);
|
|
|
SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE);
|
|
|
|
|
@@ -1355,16 +1278,21 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
|
|
|
/* Yes, we know what we are doing here. No, we do not treat a renegotiation
|
|
|
* as authenticating any earlier-received data.
|
|
|
*/
|
|
|
- if (use_unsafe_renegotiation_op) {
|
|
|
+ {
|
|
|
SSL_CTX_set_options(result->ctx,
|
|
|
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
|
|
|
}
|
|
|
+#ifdef SSL_OP_NO_COMPRESSION
|
|
|
+ SSL_CTX_set_options(result->ctx, SSL_OP_NO_COMPRESSION);
|
|
|
+#endif
|
|
|
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
|
|
|
#ifndef OPENSSL_NO_COMP
|
|
|
/* Don't actually allow compression; it uses ram and time, but the data
|
|
|
* we transmit is all encrypted anyway. */
|
|
|
if (result->ctx->comp_methods)
|
|
|
result->ctx->comp_methods = NULL;
|
|
|
#endif
|
|
|
+#endif
|
|
|
#ifdef SSL_MODE_RELEASE_BUFFERS
|
|
|
SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS);
|
|
|
#endif
|
|
@@ -1399,8 +1327,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
|
|
|
SSL_CTX_set_tmp_dh(result->ctx, crypto_dh_get_dh_(dh));
|
|
|
crypto_dh_free(dh);
|
|
|
}
|
|
|
-#if (!defined(OPENSSL_NO_EC) && \
|
|
|
- OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0))
|
|
|
+#if !defined(OPENSSL_NO_EC)
|
|
|
if (! is_client) {
|
|
|
int nid;
|
|
|
EC_KEY *ec_key;
|
|
@@ -1512,10 +1439,23 @@ 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)
|
|
|
+find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
|
|
|
{
|
|
|
const SSL_CIPHER *c;
|
|
|
-#ifdef HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR
|
|
|
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,2)
|
|
|
+ {
|
|
|
+ unsigned char cipherid[3];
|
|
|
+ tor_assert(ssl);
|
|
|
+ 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 = SSL_CIPHER_find((SSL*)ssl, cipherid);
|
|
|
+ if (c)
|
|
|
+ tor_assert((c->id & 0xffff) == cipher);
|
|
|
+ return c != NULL;
|
|
|
+ }
|
|
|
+#elif defined(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));
|
|
@@ -1528,6 +1468,7 @@ find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher)
|
|
|
return c != NULL;
|
|
|
} else
|
|
|
#endif
|
|
|
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
|
|
|
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
|
|
@@ -1541,23 +1482,24 @@ find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher)
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
- } else {
|
|
|
- return 1; /* No way to search */
|
|
|
}
|
|
|
+#endif
|
|
|
+ (void) ssl;
|
|
|
+ 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)
|
|
|
+prune_v2_cipher_list(const SSL *ssl)
|
|
|
{
|
|
|
uint16_t *inp, *outp;
|
|
|
const SSL_METHOD *m = SSLv23_method();
|
|
|
|
|
|
inp = outp = v2_cipher_list;
|
|
|
while (*inp) {
|
|
|
- if (find_cipher_by_id(m, *inp)) {
|
|
|
+ if (find_cipher_by_id(ssl, m, *inp)) {
|
|
|
*outp++ = *inp++;
|
|
|
} else {
|
|
|
inp++;
|
|
@@ -1579,7 +1521,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
|
|
|
int i, res;
|
|
|
tor_tls_t *tor_tls;
|
|
|
if (PREDICT_UNLIKELY(!v2_cipher_list_pruned))
|
|
|
- prune_v2_cipher_list();
|
|
|
+ prune_v2_cipher_list(ssl);
|
|
|
|
|
|
tor_tls = tor_tls_get_by_ssl(ssl);
|
|
|
if (tor_tls && tor_tls->client_cipher_list_type)
|
|
@@ -1613,7 +1555,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
|
|
|
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;
|
|
|
+ uint16_t id = SSL_CIPHER_get_id(cipher) & 0xffff;
|
|
|
if (id == 0x00ff) /* extended renegotiation indicator. */
|
|
|
continue;
|
|
|
if (!id || id != *v2_cipher) {
|
|
@@ -1657,13 +1599,39 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
|
|
|
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;
|
|
|
+ STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
|
|
|
+
|
|
|
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
|
|
|
+ {
|
|
|
+ SSL_SESSION *session;
|
|
|
+ STACK_OF(SSL_CIPHER) *c1;
|
|
|
+ int i;
|
|
|
+ if (!(session = SSL_get_session((SSL *)ssl))) {
|
|
|
+ log_info(LD_NET, "No session on TLS?");
|
|
|
+ return CIPHERS_ERR;
|
|
|
+ }
|
|
|
+ c1 = session->ciphers;
|
|
|
+
|
|
|
+ if (sk_SSL_CIPHER_num(c1) != sk_SSL_CIPHER_num(ciphers)) {
|
|
|
+ log_warn(LD_BUG, "Whoops. session->ciphers doesn't "
|
|
|
+ "match SSL_get_ciphers()");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ for (i = 0; i < sk_SSL_CIPHER_num(c1); ++i) {
|
|
|
+ SSL_CIPHER *a = sk_SSL_CIPHER_value(ciphers, i);
|
|
|
+ SSL_CIPHER *b = sk_SSL_CIPHER_value(c1, i);
|
|
|
+ unsigned long a_id = SSL_CIPHER_get_id(a);
|
|
|
+ unsigned long b_id = SSL_CIPHER_get_id(b);
|
|
|
+ if (a_id != b_id) {
|
|
|
+ log_warn(LD_BUG, "Cipher mismatch between session->ciphers and "
|
|
|
+ "SSL_get_ciphers() at %d: %lx vs %lx", i,
|
|
|
+ a_id, b_id);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
- return tor_tls_classify_client_ciphers(ssl, session->ciphers) >= CIPHERS_V2;
|
|
|
+ return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2;
|
|
|
}
|
|
|
|
|
|
/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection
|
|
@@ -1676,14 +1644,17 @@ static void
|
|
|
tor_tls_server_info_callback(const SSL *ssl, int type, int val)
|
|
|
{
|
|
|
tor_tls_t *tls;
|
|
|
+ int ssl_state;
|
|
|
(void) val;
|
|
|
|
|
|
tor_tls_debug_state_callback(ssl, type, val);
|
|
|
|
|
|
if (type != SSL_CB_ACCEPT_LOOP)
|
|
|
return;
|
|
|
- if ((ssl->state != SSL3_ST_SW_SRVR_HELLO_A) &&
|
|
|
- (ssl->state != SSL3_ST_SW_SRVR_HELLO_B))
|
|
|
+
|
|
|
+ ssl_state = SSL_state(ssl);
|
|
|
+ if ((ssl_state != SSL3_ST_SW_SRVR_HELLO_A) &&
|
|
|
+ (ssl_state != SSL3_ST_SW_SRVR_HELLO_B))
|
|
|
return;
|
|
|
|
|
|
tls = tor_tls_get_by_ssl(ssl);
|
|
@@ -1714,10 +1685,6 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
|
|
|
|
|
|
if (tls) {
|
|
|
tls->wasV2Handshake = 1;
|
|
|
-#ifdef USE_BUFFEREVENTS
|
|
|
- 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!");
|
|
|
}
|
|
@@ -1725,7 +1692,6 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
|
|
|
}
|
|
|
#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.
|
|
|
*
|
|
@@ -1763,9 +1729,6 @@ 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
|
|
@@ -1791,21 +1754,46 @@ log_unsupported_ciphers(smartlist_t *unsupported)
|
|
|
tor_free(joined);
|
|
|
}
|
|
|
|
|
|
-/** Replace *<b>ciphers</b> with a new list of SSL ciphersuites: specifically,
|
|
|
- * a list designed to mimic a common web browser. We might not be able to do
|
|
|
- * that if OpenSSL doesn't support all the ciphers we want. Some of the
|
|
|
- * ciphers in the list won't actually be implemented by OpenSSL: that's okay
|
|
|
- * so long as the server doesn't select them.
|
|
|
+static void
|
|
|
+set_ssl_ciphers_to_list(SSL *ssl, STACK_OF(SSL_CIPHER) *stack)
|
|
|
+{
|
|
|
+ STACK_OF(SSL_CIPHER) *ciphers;
|
|
|
+
|
|
|
+ int r, i;
|
|
|
+ /* #1: ensure that the ssl object has its own list of ciphers. Otherwise we
|
|
|
+ * might be about to stomp the SSL_CTX ciphers list. */
|
|
|
+ r = SSL_set_cipher_list(ssl, "HIGH");
|
|
|
+ tor_assert(r);
|
|
|
+
|
|
|
+ /* #2: Grab ssl_ciphers and clear it. */
|
|
|
+ ciphers = SSL_get_ciphers(ssl);
|
|
|
+ tor_assert(ciphers);
|
|
|
+ sk_SSL_CIPHER_zero(ciphers);
|
|
|
+
|
|
|
+ /* #3: Copy the elements from stack. */
|
|
|
+ for (i = 0; i < sk_SSL_CIPHER_num(stack); ++i) {
|
|
|
+ SSL_CIPHER *c = sk_SSL_CIPHER_value(stack, i);
|
|
|
+ sk_SSL_CIPHER_push(ciphers, c);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** Replace the ciphers on <b>ssl</b> with a new list of SSL ciphersuites:
|
|
|
+ * specifically, a list designed to mimic a common web browser. We might not
|
|
|
+ * be able to do that if OpenSSL doesn't support all the ciphers we want.
|
|
|
+ * Some of the ciphers in the list won't actually be implemented by OpenSSL:
|
|
|
+ * that's okay so long as the server doesn't select them.
|
|
|
*
|
|
|
* [If the server <b>does</b> select a bogus cipher, we won't crash or
|
|
|
* anything; we'll just fail later when we try to look up the cipher in
|
|
|
* ssl->cipher_list_by_id.]
|
|
|
*/
|
|
|
static void
|
|
|
-rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers)
|
|
|
+rectify_client_ciphers(SSL *ssl)
|
|
|
{
|
|
|
#ifdef V2_HANDSHAKE_CLIENT
|
|
|
if (PREDICT_UNLIKELY(!CLIENT_CIPHER_STACK)) {
|
|
|
+ STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
|
|
|
+
|
|
|
/* We need to set CLIENT_CIPHER_STACK to an array of the ciphers
|
|
|
* we want to use/advertise. */
|
|
|
int i = 0, j = 0;
|
|
@@ -1826,32 +1814,33 @@ rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers)
|
|
|
tor_assert(CLIENT_CIPHER_STACK);
|
|
|
|
|
|
log_debug(LD_NET, "List was: %s", CLIENT_CIPHER_LIST);
|
|
|
- for (j = 0; j < sk_SSL_CIPHER_num(*ciphers); ++j) {
|
|
|
- SSL_CIPHER *cipher = sk_SSL_CIPHER_value(*ciphers, j);
|
|
|
- log_debug(LD_NET, "Cipher %d: %lx %s", j, cipher->id, cipher->name);
|
|
|
+ for (j = 0; j < sk_SSL_CIPHER_num(ciphers); ++j) {
|
|
|
+ SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, j);
|
|
|
+ log_debug(LD_NET, "Cipher %d: %lx %s", j,
|
|
|
+ SSL_CIPHER_get_id(cipher), SSL_CIPHER_get_name(cipher));
|
|
|
}
|
|
|
|
|
|
/* Then copy as many ciphers as we can from the good list, inserting
|
|
|
* dummies as needed. Let j be an index into list of ciphers we have
|
|
|
- * (*ciphers) and let i be an index into the ciphers we want
|
|
|
+ * (ciphers) and let i be an index into the ciphers we want
|
|
|
* (CLIENT_INFO_CIPHER_LIST). We are building a list of ciphers in
|
|
|
* CLIENT_CIPHER_STACK.
|
|
|
*/
|
|
|
for (i = j = 0; i < N_CLIENT_CIPHERS; ) {
|
|
|
SSL_CIPHER *cipher = NULL;
|
|
|
- if (j < sk_SSL_CIPHER_num(*ciphers))
|
|
|
- cipher = sk_SSL_CIPHER_value(*ciphers, j);
|
|
|
- if (cipher && ((cipher->id >> 24) & 0xff) != 3) {
|
|
|
+ if (j < sk_SSL_CIPHER_num(ciphers))
|
|
|
+ cipher = sk_SSL_CIPHER_value(ciphers, j);
|
|
|
+ if (cipher && ((SSL_CIPHER_get_id(cipher) >> 24) & 0xff) != 3) {
|
|
|
/* Skip over non-v3 ciphers entirely. (This should no longer be
|
|
|
* needed, thanks to saying !SSLv2 above.) */
|
|
|
log_debug(LD_NET, "Skipping v%d cipher %s",
|
|
|
- (int)((cipher->id>>24) & 0xff),
|
|
|
- cipher->name);
|
|
|
+ (int)((SSL_CIPHER_get_id(cipher)>>24) & 0xff),
|
|
|
+ SSL_CIPHER_get_name(cipher));
|
|
|
++j;
|
|
|
} else if (cipher &&
|
|
|
- (cipher->id & 0xffff) == CLIENT_CIPHER_INFO_LIST[i].id) {
|
|
|
+ (SSL_CIPHER_get_id(cipher) & 0xffff) == CLIENT_CIPHER_INFO_LIST[i].id) {
|
|
|
/* "cipher" is the cipher we expect. Put it on the list. */
|
|
|
- log_debug(LD_NET, "Found cipher %s", cipher->name);
|
|
|
+ log_debug(LD_NET, "Found cipher %s", SSL_CIPHER_get_name(cipher));
|
|
|
sk_SSL_CIPHER_push(CLIENT_CIPHER_STACK, cipher);
|
|
|
++j;
|
|
|
++i;
|
|
@@ -1877,12 +1866,10 @@ rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers)
|
|
|
smartlist_free(unsupported);
|
|
|
}
|
|
|
|
|
|
- sk_SSL_CIPHER_free(*ciphers);
|
|
|
- *ciphers = sk_SSL_CIPHER_dup(CLIENT_CIPHER_STACK);
|
|
|
- tor_assert(*ciphers);
|
|
|
+ set_ssl_ciphers_to_list(ssl, CLIENT_CIPHER_STACK);
|
|
|
|
|
|
#else
|
|
|
- (void)ciphers;
|
|
|
+ (void)ciphers;
|
|
|
#endif
|
|
|
}
|
|
|
|
|
@@ -1926,7 +1913,7 @@ tor_tls_new(int sock, int isServer)
|
|
|
goto err;
|
|
|
}
|
|
|
if (!isServer)
|
|
|
- rectify_client_ciphers(&result->ssl->cipher_list);
|
|
|
+ rectify_client_ciphers(result->ssl);
|
|
|
result->socket = sock;
|
|
|
bio = BIO_new_socket(sock, BIO_NOCLOSE);
|
|
|
if (! bio) {
|
|
@@ -2019,13 +2006,8 @@ tor_tls_unblock_renegotiation(tor_tls_t *tls)
|
|
|
{
|
|
|
/* Yes, we know what we are doing here. No, we do not treat a renegotiation
|
|
|
* as authenticating any earlier-received data. */
|
|
|
- if (use_unsafe_renegotiation_flag) {
|
|
|
- tls->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
|
|
|
- }
|
|
|
- if (use_unsafe_renegotiation_op) {
|
|
|
- SSL_set_options(tls->ssl,
|
|
|
- SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
|
|
|
- }
|
|
|
+ SSL_set_options(tls->ssl,
|
|
|
+ SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
|
|
|
}
|
|
|
|
|
|
/** If this version of openssl supports it, turn off renegotiation on
|
|
@@ -2035,21 +2017,19 @@ tor_tls_unblock_renegotiation(tor_tls_t *tls)
|
|
|
void
|
|
|
tor_tls_block_renegotiation(tor_tls_t *tls)
|
|
|
{
|
|
|
+#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG
|
|
|
tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
|
|
|
+#else
|
|
|
+ (void) tls;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
/** Assert that the flags that allow legacy renegotiation are still set */
|
|
|
void
|
|
|
tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
|
|
|
{
|
|
|
- if (use_unsafe_renegotiation_flag) {
|
|
|
- tor_assert(0 != (tls->ssl->s3->flags &
|
|
|
- SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
|
|
|
- }
|
|
|
- if (use_unsafe_renegotiation_op) {
|
|
|
- long options = SSL_get_options(tls->ssl);
|
|
|
- tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
|
|
|
- }
|
|
|
+ long options = SSL_get_options(tls->ssl);
|
|
|
+ tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
|
|
|
}
|
|
|
|
|
|
/** Return whether this tls initiated the connect (client) or
|
|
@@ -2180,7 +2160,7 @@ tor_tls_handshake(tor_tls_t *tls)
|
|
|
tor_assert(tls->ssl);
|
|
|
tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
|
|
|
check_no_tls_errors();
|
|
|
- oldstate = tls->ssl->state;
|
|
|
+ oldstate = SSL_state(tls->ssl);
|
|
|
if (tls->isServer) {
|
|
|
log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
|
|
|
SSL_state_string_long(tls->ssl));
|
|
@@ -2190,7 +2170,7 @@ tor_tls_handshake(tor_tls_t *tls)
|
|
|
SSL_state_string_long(tls->ssl));
|
|
|
r = SSL_connect(tls->ssl);
|
|
|
}
|
|
|
- if (oldstate != tls->ssl->state)
|
|
|
+ if (oldstate != SSL_state(tls->ssl))
|
|
|
log_debug(LD_HANDSHAKE, "After call, %p was in state %s",
|
|
|
tls, SSL_state_string_long(tls->ssl));
|
|
|
/* We need to call this here and not earlier, since OpenSSL has a penchant
|
|
@@ -2209,6 +2189,14 @@ tor_tls_handshake(tor_tls_t *tls)
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
+/* SSL_clear_mode was introduced in 0.9.8m */
|
|
|
+#ifndef SSL_clear_mode
|
|
|
+static void SSL_clear_mode(SSL *s, unsigned long m)
|
|
|
+{
|
|
|
+ s->mode &= ~m;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
/** Perform the final part of the intial TLS handshake on <b>tls</b>. This
|
|
|
* should be called for the first handshake only: it determines whether the v1
|
|
|
* or the v2 handshake was used, and adjusts things for the renegotiation
|
|
@@ -2225,8 +2213,7 @@ 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;
|
|
|
+ SSL_clear_mode(tls->ssl, 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,
|
|
@@ -2851,12 +2838,23 @@ tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
|
|
|
* Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read
|
|
|
* buffer and *<b>rbuf_bytes</b> to the amount actually used.
|
|
|
* Set *<b>wbuf_capacity</b> to the amount of storage allocated for the write
|
|
|
- * buffer and *<b>wbuf_bytes</b> to the amount actually used. */
|
|
|
-void
|
|
|
+ * buffer and *<b>wbuf_bytes</b> to the amount actually used.
|
|
|
+ *
|
|
|
+ * Return 0 on success, -1 on failure.*/
|
|
|
+int
|
|
|
tor_tls_get_buffer_sizes(tor_tls_t *tls,
|
|
|
size_t *rbuf_capacity, size_t *rbuf_bytes,
|
|
|
size_t *wbuf_capacity, size_t *wbuf_bytes)
|
|
|
{
|
|
|
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
|
|
|
+ (void)tls;
|
|
|
+ (void)rbuf_capacity;
|
|
|
+ (void)rbuf_bytes;
|
|
|
+ (void)wbuf_capacity;
|
|
|
+ (void)wbuf_bytes;
|
|
|
+
|
|
|
+ return -1;
|
|
|
+#else
|
|
|
if (tls->ssl->s3->rbuf.buf)
|
|
|
*rbuf_capacity = tls->ssl->s3->rbuf.len;
|
|
|
else
|
|
@@ -2867,6 +2865,8 @@ tor_tls_get_buffer_sizes(tor_tls_t *tls,
|
|
|
*wbuf_capacity = 0;
|
|
|
*rbuf_bytes = tls->ssl->s3->rbuf.left;
|
|
|
*wbuf_bytes = tls->ssl->s3->wbuf.left;
|
|
|
+ return 0;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
#ifdef USE_BUFFEREVENTS
|