Kaynağa Gözat

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

Nick Mathewson 16 yıl önce
ebeveyn
işleme
323490303e
2 değiştirilmiş dosya ile 35 ekleme ve 17 silme
  1. 2 2
      doc/TODO
  2. 33 15
      src/common/tortls.c

+ 2 - 2
doc/TODO

@@ -39,7 +39,7 @@ Things we'd like to do in 0.2.0.x:
         - functions to validate a chain of x509 certs, and extract a PK.
         - Parse CERT cells
         - Generate CERT cells
-        - Keep copies of X509 certs around, not necessarily associated with
+        o Keep copies of X509 certs around, not necessarily associated with
           connection.
       - LINK_AUTH cells
         - Code to generate
@@ -58,7 +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.
+      o Make code work right wrt TLS context rotation.
       - NETINFO fallout
         - Don't extend a circuit over a noncanonical connection with
           mismatched address.

+ 33 - 15
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)