summaryrefslogtreecommitdiff
path: root/src/common/tortls.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2007-11-05 18:15:52 +0000
committerNick Mathewson <nickm@torproject.org>2007-11-05 18:15:52 +0000
commit323490303e9864e9116e5a740a48316ada801983 (patch)
treec63afeb5b9f02f8e38e84e01b96a9116a9a27e64 /src/common/tortls.c
parentea1bea5830ad90d9ea14a84ffa4b465827ff8af4 (diff)
downloadtor-323490303e9864e9116e5a740a48316ada801983.tar.gz
tor-323490303e9864e9116e5a740a48316ada801983.zip
r16412@catbus: nickm | 2007-11-05 11:45:17 -0500
Make TLS contexts reference-counted, and add a reference from TLS objects to their corresponding context. This lets us reliably get the certificates for a given TLS connection, even if we have rotated TLS contexts. svn:r12383
Diffstat (limited to 'src/common/tortls.c')
-rw-r--r--src/common/tortls.c48
1 files changed, 33 insertions, 15 deletions
diff --git a/src/common/tortls.c b/src/common/tortls.c
index c6ffe12108..512847f1de 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -43,6 +43,7 @@ const char tortls_c_id[] =
/** Structure holding the TLS state for a single connection. */
typedef struct tor_tls_context_t {
+ int refcnt;
SSL_CTX *ctx;
X509 *my_cert;
X509 *my_id_cert;
@@ -52,21 +53,23 @@ typedef struct tor_tls_context_t {
* accessed from within tortls.c.
*/
struct tor_tls_t {
+ tor_tls_context_t *context; /**DOCDOC */
SSL *ssl; /**< An OpenSSL SSL object. */
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; /**< The current SSL state, depending on which operations have
- * completed successfully. */
- int isServer; /**< True iff this is a server-side connection */
+ } state : 7; /**< The current SSL state, depending on which operations have
+ * completed successfully. */
+ unsigned int isServer:1; /**< True iff this is a server-side connection */
size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
* time. */
unsigned long last_write_count;
unsigned long last_read_count;
};
-static void tor_tls_context_free(tor_tls_context_t *ctx);
+static void tor_tls_context_decref(tor_tls_context_t *ctx);
+static void tor_tls_context_incref(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,
@@ -214,7 +217,7 @@ void
tor_tls_free_all(void)
{
if (global_tls_context) {
- tor_tls_context_free(global_tls_context);
+ tor_tls_context_decref(global_tls_context);
global_tls_context = NULL;
}
}
@@ -345,12 +348,22 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
/** DOCDOC */
static void
-tor_tls_context_free(tor_tls_context_t *ctx)
+tor_tls_context_decref(tor_tls_context_t *ctx)
{
- SSL_CTX_free(ctx->ctx);
- X509_free(ctx->my_cert);
- X509_free(ctx->my_id_cert);
- tor_free(ctx);
+ tor_assert(ctx);
+ if (--ctx->refcnt == 0) {
+ SSL_CTX_free(ctx->ctx);
+ X509_free(ctx->my_cert);
+ X509_free(ctx->my_id_cert);
+ tor_free(ctx);
+ }
+}
+
+/** DOCDOC */
+static void
+tor_tls_context_incref(tor_tls_context_t *ctx)
+{
+ ++ctx->refcnt;
}
/** Create a new TLS context for use with Tor TLS handshakes.
@@ -394,6 +407,7 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
}
result = tor_malloc_zero(sizeof(tor_tls_context_t));
+ result->refcnt = 1;
result->my_cert = X509_dup(cert);
result->my_id_cert = X509_dup(idcert);
@@ -446,7 +460,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. */
- tor_tls_context_free(global_tls_context);
+ tor_tls_context_decref(global_tls_context);
}
global_tls_context = result;
if (rsa)
@@ -461,10 +475,8 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
crypto_free_pk_env(rsa);
if (dh)
crypto_dh_free(dh);
- if (result && result->ctx)
- SSL_CTX_free(result->ctx);
if (result)
- tor_free(result);
+ tor_tls_context_decref(result);
if (cert)
X509_free(cert);
if (idcert)
@@ -495,10 +507,13 @@ tor_tls_new(int sock, int isServer)
#endif
if (! bio) {
tls_log_errors(LOG_WARN, "opening BIO");
+ SSL_free(result->ssl);
tor_free(result);
return NULL;
}
SSL_set_bio(result->ssl, bio, bio);
+ tor_tls_context_incref(global_tls_context);
+ result->context = global_tls_context;
result->state = TOR_TLS_ST_HANDSHAKE;
result->isServer = isServer;
result->wantwrite_n = 0;
@@ -525,6 +540,8 @@ tor_tls_free(tor_tls_t *tls)
tor_assert(tls && tls->ssl);
SSL_free(tls->ssl);
tls->ssl = NULL;
+ if (tls->context)
+ tor_tls_context_decref(tls->context);
tor_free(tls);
}
@@ -701,7 +718,8 @@ tor_tls_get_cert_digests(tor_tls_t *tls,
{
X509 *cert;
unsigned int len;
- cert = SSL_get_certificate(tls->ssl);
+ tor_assert(tls->context);
+ cert = tls->context->my_cert;
if (cert) {
X509_digest(cert, EVP_sha1(), (unsigned char*)my_digest_out, &len);
if (len != DIGEST_LEN)