|
@@ -66,7 +66,7 @@ typedef struct tor_tls_context_t {
|
|
|
*/
|
|
|
struct tor_tls_t {
|
|
|
HT_ENTRY(tor_tls_t) node;
|
|
|
- tor_tls_context_t *context;
|
|
|
+ tor_tls_context_t *context;
|
|
|
SSL *ssl;
|
|
|
int socket;
|
|
|
enum {
|
|
@@ -75,12 +75,24 @@ struct tor_tls_t {
|
|
|
} state : 3;
|
|
|
* completed successfully. */
|
|
|
unsigned int isServer:1;
|
|
|
- unsigned int wasV2Handshake:1;
|
|
|
+ unsigned int wasV2Handshake:1;
|
|
|
+ * this connection used the updated version
|
|
|
+ * of the connection protocol (client sends
|
|
|
+ * different cipher list, server sends only
|
|
|
+ * one certificate). */
|
|
|
+ int got_renegotiate:1;
|
|
|
+ * when we're done reading. */
|
|
|
size_t wantwrite_n;
|
|
|
* time. */
|
|
|
+
|
|
|
+ * tor_tls_get_n_raw_bytes() for usage.
|
|
|
+ */
|
|
|
unsigned long last_write_count;
|
|
|
unsigned long last_read_count;
|
|
|
+
|
|
|
+ * the handshake. */
|
|
|
void (*negotiated_callback)(tor_tls_t *tls, void *arg);
|
|
|
+
|
|
|
void *callback_arg;
|
|
|
};
|
|
|
|
|
@@ -199,7 +211,7 @@ tor_errno_to_tls_error(int e)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
const char *
|
|
|
tor_tls_err_to_string(int err)
|
|
|
{
|
|
@@ -305,9 +317,8 @@ static int
|
|
|
always_accept_verify_cb(int preverify_ok,
|
|
|
X509_STORE_CTX *x509_ctx)
|
|
|
{
|
|
|
-
|
|
|
- preverify_ok = 0;
|
|
|
- x509_ctx = NULL;
|
|
|
+ (void) preverify_ok;
|
|
|
+ (void) x509_ctx;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -467,7 +478,8 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
|
|
|
SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
|
|
|
#endif
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+ * references. */
|
|
|
static void
|
|
|
tor_tls_context_decref(tor_tls_context_t *ctx)
|
|
|
{
|
|
@@ -481,7 +493,7 @@ tor_tls_context_decref(tor_tls_context_t *ctx)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
static void
|
|
|
tor_tls_context_incref(tor_tls_context_t *ctx)
|
|
|
{
|
|
@@ -602,7 +614,9 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
|
|
|
}
|
|
|
|
|
|
#ifdef V2_HANDSHAKE_SERVER
|
|
|
-
|
|
|
+
|
|
|
+ * a list that indicates that the client know how to do the v2 TLS connection
|
|
|
+ * handshake. */
|
|
|
static int
|
|
|
tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
|
|
|
{
|
|
@@ -651,18 +665,35 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+ * 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
|
|
|
tor_tls_server_info_callback(const SSL *ssl, int type, int val)
|
|
|
{
|
|
|
+ tor_tls_t *tls;
|
|
|
(void) val;
|
|
|
if (type != SSL_CB_ACCEPT_LOOP)
|
|
|
return;
|
|
|
if (ssl->state != SSL3_ST_SW_SRVR_HELLO_A)
|
|
|
return;
|
|
|
|
|
|
+ tls = tor_tls_get_by_ssl(ssl);
|
|
|
+ if (tls) {
|
|
|
+
|
|
|
+ if (tls->negotiated_callback)
|
|
|
+ tls->got_renegotiate = 1;
|
|
|
+ } else {
|
|
|
+ log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
if (tor_tls_client_is_using_v2_ciphers(ssl)) {
|
|
|
- tor_tls_t *tls;
|
|
|
+
|
|
|
+
|
|
|
|
|
|
* Let's hope openssl doesn't notice! */
|
|
|
|
|
@@ -671,7 +702,6 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
|
|
|
|
|
|
SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL);
|
|
|
|
|
|
- tls = tor_tls_get_by_ssl((SSL*)ssl);
|
|
|
if (tls) {
|
|
|
tls->wasV2Handshake = 1;
|
|
|
} else {
|
|
@@ -731,7 +761,10 @@ tor_tls_new(int sock, int isServer)
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+ * next gets a client-side renegotiate in the middle of a read. Do not
|
|
|
+ * invoke this function untile <em>after</em> initial handshaking is done!
|
|
|
+ */
|
|
|
void
|
|
|
tor_tls_set_renegotiate_callback(tor_tls_t *tls,
|
|
|
void (*cb)(tor_tls_t *, void *arg),
|
|
@@ -739,6 +772,14 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls,
|
|
|
{
|
|
|
tls->negotiated_callback = cb;
|
|
|
tls->callback_arg = arg;
|
|
|
+ tls->got_renegotiate = 0;
|
|
|
+#ifdef V2_HANDSHAKE_SERVER
|
|
|
+ if (cb) {
|
|
|
+ SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback);
|
|
|
+ } else {
|
|
|
+ SSL_set_info_callback(tls->ssl, NULL);
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
|
|
@@ -785,12 +826,12 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
|
|
|
r = SSL_read(tls->ssl, cp, len);
|
|
|
if (r > 0) {
|
|
|
#ifdef V2_HANDSHAKE_SERVER
|
|
|
- if (SSL_num_renegotiations(tls->ssl)) {
|
|
|
-
|
|
|
+ if (tls->got_renegotiate) {
|
|
|
+
|
|
|
log_notice(LD_NET, "Got a TLS renegotiation from %p", tls);
|
|
|
if (tls->negotiated_callback)
|
|
|
tls->negotiated_callback(tls, tls->callback_arg);
|
|
|
- SSL_clear_num_renegotiations(tls->ssl);
|
|
|
+ tls->got_renegotiate = 0;
|
|
|
}
|
|
|
#endif
|
|
|
return r;
|
|
@@ -1010,57 +1051,6 @@ tor_tls_peer_has_cert(tor_tls_t *tls)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-int
|
|
|
-tor_tls_get_cert_digests(tor_tls_t *tls,
|
|
|
- char *my_digest_out,
|
|
|
- char *peer_digest_out)
|
|
|
-{
|
|
|
- X509 *cert;
|
|
|
- unsigned int len;
|
|
|
- tor_assert(tls && tls->context);
|
|
|
- cert = tls->context->my_cert;
|
|
|
- if (cert) {
|
|
|
- X509_digest(cert, EVP_sha1(), (unsigned char*)my_digest_out, &len);
|
|
|
- if (len != DIGEST_LEN)
|
|
|
- return -1;
|
|
|
- }
|
|
|
- cert = SSL_get_peer_certificate(tls->ssl);
|
|
|
- if (cert) {
|
|
|
- X509_digest(cert, EVP_sha1(), (unsigned char*)peer_digest_out, &len);
|
|
|
- if (len != DIGEST_LEN)
|
|
|
- return -1;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-crypto_pk_env_t *
|
|
|
-tor_tls_dup_private_key(tor_tls_t *tls)
|
|
|
-{
|
|
|
- return crypto_pk_dup_key(tls->context->key);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-char *
|
|
|
-tor_tls_encode_my_certificate(tor_tls_t *tls, size_t *size_out,
|
|
|
- int conn_cert)
|
|
|
-{
|
|
|
- unsigned char *result, *cp;
|
|
|
- int certlen;
|
|
|
- X509 *cert;
|
|
|
- tor_assert(tls && tls->context);
|
|
|
- cert = conn_cert ? tls->context->my_cert : tls->context->my_id_cert;
|
|
|
- tor_assert(cert);
|
|
|
- certlen = i2d_X509(cert, NULL);
|
|
|
- tor_assert(certlen >= 0);
|
|
|
- cp = result = tor_malloc(certlen);
|
|
|
- i2d_X509(cert, &cp);
|
|
|
- tor_assert(cp-result == certlen);
|
|
|
- *size_out = (size_t)certlen;
|
|
|
- return (char*) result;
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
static void
|
|
|
log_cert_lifetime(X509 *cert, const char *problem)
|