From ea1bea5830ad90d9ea14a84ffa4b465827ff8af4 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 5 Nov 2007 18:15:50 +0000 Subject: [PATCH] r16411@catbus: nickm | 2007-11-05 11:27:37 -0500 Remember X509 certificates in the context. Store peer/self certificate digests in handshake state. svn:r12382 --- doc/TODO | 2 ++ src/common/tortls.c | 48 ++++++++++++++++++++++++++++++++++++------ src/common/tortls.h | 7 +++--- src/or/connection_or.c | 39 +++++++++++++++++++++++++++------- src/or/or.h | 6 ++++-- 5 files changed, 83 insertions(+), 19 deletions(-) diff --git a/doc/TODO b/doc/TODO index b32be7a262..9c4fbca972 100644 --- a/doc/TODO +++ b/doc/TODO @@ -43,6 +43,7 @@ Things we'd like to do in 0.2.0.x: connection. - LINK_AUTH cells - Code to generate + o Remember certificate digests from TLS - Code to parse and check - Unit tests - Revised handshake: TLS @@ -57,6 +58,7 @@ Things we'd like to do in 0.2.0.x: - After we send NETINFO, send CERT and LINK_AUTH if needed. - Once we get a good LINK_AUTH, the connection is OPEN. - Ban most cell types on a non-OPEN connection. + - Make code work right wrt TLS context rotation. - NETINFO fallout - Don't extend a circuit over a noncanonical connection with mismatched address. diff --git a/src/common/tortls.c b/src/common/tortls.c index ce5b702a2b..c6ffe12108 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -44,6 +44,8 @@ const char tortls_c_id[] = /** Structure holding the TLS state for a single connection. */ typedef struct tor_tls_context_t { SSL_CTX *ctx; + X509 *my_cert; + X509 *my_id_cert; } tor_tls_context_t; /** Holds a SSL object and its associated data. Members are only @@ -64,6 +66,7 @@ struct tor_tls_t { unsigned long last_read_count; }; +static void tor_tls_context_free(tor_tls_context_t *ctx); static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa, crypto_pk_env_t *rsa_sign, const char *cname, @@ -211,8 +214,7 @@ void tor_tls_free_all(void) { if (global_tls_context) { - SSL_CTX_free(global_tls_context->ctx); - tor_free(global_tls_context); + tor_tls_context_free(global_tls_context); global_tls_context = NULL; } } @@ -341,6 +343,16 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa, #error "Tor requires OpenSSL version 0.9.7 or later, for AES support." #endif +/** DOCDOC */ +static void +tor_tls_context_free(tor_tls_context_t *ctx) +{ + SSL_CTX_free(ctx->ctx); + X509_free(ctx->my_cert); + X509_free(ctx->my_id_cert); + tor_free(ctx); +} + /** Create a new TLS context for use with Tor TLS handshakes. * identity should be set to the identity key used to sign the * certificate, and nickname set to the nickname to use. @@ -382,6 +394,9 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname, } result = tor_malloc_zero(sizeof(tor_tls_context_t)); + result->my_cert = X509_dup(cert); + result->my_id_cert = X509_dup(idcert); + #ifdef EVERYONE_HAS_AES /* Tell OpenSSL to only use TLS1 */ if (!(result->ctx = SSL_CTX_new(TLSv1_method()))) @@ -431,8 +446,7 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname, if (global_tls_context) { /* This is safe even if there are open connections: OpenSSL does * reference counting with SSL and SSL_CTX objects. */ - SSL_CTX_free(global_tls_context->ctx); - tor_free(global_tls_context); + tor_tls_context_free(global_tls_context); } global_tls_context = result; if (rsa) @@ -679,6 +693,29 @@ tor_tls_peer_has_cert(tor_tls_t *tls) return 1; } +/** DOCDOC */ +int +tor_tls_get_cert_digests(tor_tls_t *tls, + char *my_digest_out, + char *peer_digest_out) +{ + X509 *cert; + unsigned int len; + cert = SSL_get_certificate(tls->ssl); + 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; +} + /** Warn that a certificate lifetime extends through a certain range. */ static void log_cert_lifetime(X509 *cert, const char *problem) @@ -736,7 +773,7 @@ log_cert_lifetime(X509 *cert, const char *problem) * 0. Else, return -1 and log complaints with log-level severity. */ int -tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key) +tor_tls_verify_v1(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key) { X509 *cert = NULL, *id_cert = NULL; STACK_OF(X509) *chain = NULL; @@ -932,4 +969,3 @@ tor_tls_hmac_with_master_secret(tor_tls_t *tls, char *hmac_out, return 0; } - diff --git a/src/common/tortls.h b/src/common/tortls.h index eac337b921..cbda57880c 100644 --- a/src/common/tortls.h +++ b/src/common/tortls.h @@ -53,9 +53,10 @@ tor_tls_t *tor_tls_new(int sock, int is_server); int tor_tls_is_server(tor_tls_t *tls); void tor_tls_free(tor_tls_t *tls); int tor_tls_peer_has_cert(tor_tls_t *tls); -int tor_tls_get_peer_cert_nickname(int severity, tor_tls_t *tls, - char *buf, size_t buflen); -int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity); +int tor_tls_get_cert_digests(tor_tls_t *tls, char *my_digest_out, + char *peer_digest_out); +int tor_tls_verify_v1(int severity, tor_tls_t *tls, + crypto_pk_env_t **identity); 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); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 37fe55f97e..11e45fb2a8 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -17,6 +17,8 @@ const char connection_or_c_id[] = static int connection_tls_finish_handshake(or_connection_t *conn); static int connection_or_process_cells_from_inbuf(or_connection_t *conn); static int connection_or_send_versions(or_connection_t *conn); +static int connection_init_or_handshake_state(or_connection_t *conn, + int started_here); /**************************************************************/ @@ -629,8 +631,8 @@ connection_or_check_valid_handshake(or_connection_t *conn, int started_here, check_no_tls_errors(); if (has_cert) { - int v = tor_tls_verify(started_here?severity:LOG_INFO, - conn->tls, &identity_rcvd); + int v = tor_tls_verify_v1(started_here?severity:LOG_INFO, + conn->tls, &identity_rcvd); if (started_here && v<0) { log_fn(severity,LD_OR,"Tried connecting to router at %s:%d: It" " has a cert but it's invalid. Closing.", @@ -725,10 +727,11 @@ connection_tls_finish_handshake(or_connection_t *conn) int started_here = connection_or_nonopen_was_started_here(conn); log_debug(LD_OR,"tls handshake done. verifying."); + /* V1 only XXXX020 */ if (connection_or_check_valid_handshake(conn, started_here, digest_rcvd) < 0) return -1; - if (!started_here) { /* V1 only XXX020 */ + if (!started_here) { /* V1 only XXXX020 */ connection_or_init_conn_from_address(conn,conn->_base.addr, conn->_base.port, digest_rcvd, 0); } @@ -740,16 +743,36 @@ connection_tls_finish_handshake(or_connection_t *conn) return connection_or_set_state_open(conn); } else { conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING; - conn->handshake_state = tor_malloc_zero(sizeof(or_handshake_state_t)); - conn->handshake_state->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) + if (connection_init_or_handshake_state(conn, started_here) < 0) return -1; return connection_or_send_versions(conn); } } +/** DOCDOC */ +static int +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; +} /** DOCDOC */ void diff --git a/src/or/or.h b/src/or/or.h index 0968f6d7d8..dd4d2c54de 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -868,8 +868,10 @@ typedef struct or_handshake_state_t { unsigned int authenticated : 1; /* from tls */ - char client_random[32]; - char server_random[32]; + 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;