Browse Source

Merge branch 'maint-0.2.1_secfix' into maint-0.2.2_secfix

Conflicts:
	src/or/connection_or.c
Sebastian Hahn 12 years ago
parent
commit
df05e5ef4d
6 changed files with 108 additions and 41 deletions
  1. 21 0
      changes/issue-2011-10-19L
  2. 9 0
      changes/issue-2011-10-23G
  3. 54 39
      src/common/tortls.c
  4. 11 2
      src/or/command.c
  5. 7 0
      src/or/connection_or.c
  6. 6 0
      src/or/or.h

+ 21 - 0
changes/issue-2011-10-19L

@@ -0,0 +1,21 @@
+  o Security fixes:
+
+    - Don't send TLS certificate chains on outgoing OR connections
+      from clients and bridges.  Previously, each client or bridge
+      would use a single cert chain for all outgoing OR connections
+      for up to 24 hours, which allowed any relay connected to by a
+      client or bridge to determine which entry guards it is using.
+      This is a potential user-tracing bug for *all* users; everyone
+      who uses Tor's client or hidden service functionality should
+      upgrade.  Fixes CVE-2011-2768.  Bugfix on FIXME; found by
+      frosty_un.
+
+    - Don't use any OR connection on which we have received a
+      CREATE_FAST cell to satisfy an EXTEND request.  Previously, we
+      would not consider whether a connection appears to be from a
+      client or bridge when deciding whether to use that connection to
+      satisfy an EXTEND request.  Mitigates CVE-2011-2768, by
+      preventing an attacker from determining whether an unpatched
+      client is connected to a patched relay.  Bugfix on FIXME; found
+      by frosty_un.
+

+ 9 - 0
changes/issue-2011-10-23G

@@ -0,0 +1,9 @@
+  o Security fixes:
+
+    - Reject CREATE and CREATE_FAST cells on outgoing OR connections
+      from a bridge to a relay.  Previously, we would accept them and
+      handle them normally, thereby allowing a malicious relay to
+      easily distinguish bridges which connect to it from clients.
+      Fixes CVE-2011-2769.  Bugfix on 0.2.0.3-alpha, when bridges were
+      implemented; found by frosty_un.
+

+ 54 - 39
src/common/tortls.c

@@ -192,9 +192,11 @@ static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa,
 static void tor_tls_unblock_renegotiation(tor_tls_t *tls);
 static int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
                                     crypto_pk_env_t *identity,
-                                    unsigned int key_lifetime);
+                                    unsigned int key_lifetime,
+                                    int is_client);
 static tor_tls_context_t *tor_tls_context_new(crypto_pk_env_t *identity,
-                                              unsigned int key_lifetime);
+                                              unsigned int key_lifetime,
+                                              int is_client);
 
 /** Global TLS contexts. We keep them here because nobody else needs
  * to touch them. */
@@ -653,7 +655,7 @@ tor_tls_context_init(int is_public_server,
 
     rv1 = tor_tls_context_init_one(&server_tls_context,
                                    server_identity,
-                                   key_lifetime);
+                                   key_lifetime, 0);
 
     if (rv1 >= 0) {
       new_ctx = server_tls_context;
@@ -669,7 +671,8 @@ tor_tls_context_init(int is_public_server,
     if (server_identity != NULL) {
       rv1 = tor_tls_context_init_one(&server_tls_context,
                                      server_identity,
-                                     key_lifetime);
+                                     key_lifetime,
+                                     0);
     } else {
       tor_tls_context_t *old_ctx = server_tls_context;
       server_tls_context = NULL;
@@ -681,7 +684,8 @@ tor_tls_context_init(int is_public_server,
 
     rv2 = tor_tls_context_init_one(&client_tls_context,
                                    client_identity,
-                                   key_lifetime);
+                                   key_lifetime,
+                                   1);
   }
 
   return MIN(rv1, rv2);
@@ -696,10 +700,12 @@ tor_tls_context_init(int is_public_server,
 static int
 tor_tls_context_init_one(tor_tls_context_t **ppcontext,
                          crypto_pk_env_t *identity,
-                         unsigned int key_lifetime)
+                         unsigned int key_lifetime,
+                         int is_client)
 {
   tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
-                                                   key_lifetime);
+                                                   key_lifetime,
+                                                   is_client);
   tor_tls_context_t *old_ctx = *ppcontext;
 
   if (new_ctx != NULL) {
@@ -721,7 +727,8 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
  * certificate.
  */
 static tor_tls_context_t *
-tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime)
+tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
+                    int is_client)
 {
   crypto_pk_env_t *rsa = NULL;
   EVP_PKEY *pkey = NULL;
@@ -738,22 +745,26 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime)
     goto error;
   if (crypto_pk_generate_key(rsa)<0)
     goto error;
-  /* Create certificate signed by identity key. */
-  cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
-                                    key_lifetime);
-  /* Create self-signed certificate for identity key. */
-  idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
-                                      IDENTITY_CERT_LIFETIME);
-  if (!cert || !idcert) {
-    log(LOG_WARN, LD_CRYPTO, "Error creating certificate");
-    goto error;
+  if (!is_client) {
+    /* Create certificate signed by identity key. */
+    cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
+                                      key_lifetime);
+    /* Create self-signed certificate for identity key. */
+    idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
+                                        IDENTITY_CERT_LIFETIME);
+    if (!cert || !idcert) {
+      log(LOG_WARN, LD_CRYPTO, "Error creating certificate");
+      goto error;
+    }
   }
 
   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);
-  result->key = crypto_pk_dup_key(rsa);
+  if (!is_client) {
+    result->my_cert = X509_dup(cert);
+    result->my_id_cert = X509_dup(idcert);
+    result->key = crypto_pk_dup_key(rsa);
+  }
 
 #ifdef EVERYONE_HAS_AES
   /* Tell OpenSSL to only use TLS1 */
@@ -785,27 +796,31 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime)
 #ifdef SSL_MODE_RELEASE_BUFFERS
   SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS);
 #endif
-  if (cert && !SSL_CTX_use_certificate(result->ctx,cert))
-    goto error;
-  X509_free(cert); /* We just added a reference to cert. */
-  cert=NULL;
-  if (idcert) {
-    X509_STORE *s = SSL_CTX_get_cert_store(result->ctx);
-    tor_assert(s);
-    X509_STORE_add_cert(s, idcert);
-    X509_free(idcert); /* The context now owns the reference to idcert */
-    idcert = NULL;
+  if (! is_client) {
+    if (cert && !SSL_CTX_use_certificate(result->ctx,cert))
+      goto error;
+    X509_free(cert); /* We just added a reference to cert. */
+    cert=NULL;
+    if (idcert) {
+      X509_STORE *s = SSL_CTX_get_cert_store(result->ctx);
+      tor_assert(s);
+      X509_STORE_add_cert(s, idcert);
+      X509_free(idcert); /* The context now owns the reference to idcert */
+      idcert = NULL;
+    }
   }
   SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
-  tor_assert(rsa);
-  if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1)))
-    goto error;
-  if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
-    goto error;
-  EVP_PKEY_free(pkey);
-  pkey = NULL;
-  if (!SSL_CTX_check_private_key(result->ctx))
-    goto error;
+  if (!is_client) {
+    tor_assert(rsa);
+    if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1)))
+      goto error;
+    if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
+      goto error;
+    EVP_PKEY_free(pkey);
+    pkey = NULL;
+    if (!SSL_CTX_check_private_key(result->ctx))
+      goto error;
+  }
   {
     crypto_dh_env_t *dh = crypto_dh_new(DH_TYPE_TLS);
     tor_assert(dh);

+ 11 - 2
src/or/command.c

@@ -232,6 +232,7 @@ static void
 command_process_create_cell(cell_t *cell, or_connection_t *conn)
 {
   or_circuit_t *circ;
+  or_options_t *options = get_options();
   int id_is_high;
 
   if (we_are_hibernating()) {
@@ -243,9 +244,11 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
     return;
   }
 
-  if (!server_mode(get_options())) {
+  if (!server_mode(options) ||
+      (!public_server_mode(options) && conn->is_outgoing)) {
     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "Received create cell (type %d) from %s:%d, but we're a client. "
+           "Received create cell (type %d) from %s:%d, but we're connected "
+           "to it as a client. "
            "Sending back a destroy.",
            (int)cell->command, conn->_base.address, conn->_base.port);
     connection_or_send_destroy(cell->circ_id, conn,
@@ -305,7 +308,13 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
      * a CPU worker. */
     char keys[CPATH_KEY_MATERIAL_LEN];
     char reply[DIGEST_LEN*2];
+
     tor_assert(cell->command == CELL_CREATE_FAST);
+
+    /* Make sure we never try to use the OR connection on which we
+     * received this cell to satisfy an EXTEND request,  */
+    conn->is_connection_with_client = 1;
+
     if (fast_server_handshake(cell->payload, (uint8_t*)reply,
                               (uint8_t*)keys, sizeof(keys))<0) {
       log_warn(LD_OR,"Failed to generate key material. Closing.");

+ 7 - 0
src/or/connection_or.c

@@ -548,6 +548,11 @@ connection_or_get_for_extend(const char *digest,
     tor_assert(tor_memeq(conn->identity_digest, digest, DIGEST_LEN));
     if (conn->_base.marked_for_close)
       continue;
+    /* Never return a connection on which the other end appears to be
+     * a client. */
+    if (conn->is_connection_with_client) {
+      continue;
+    }
     /* Never return a non-open connection. */
     if (conn->_base.state != OR_CONN_STATE_OPEN) {
       /* If the address matches, don't launch a new connection for this
@@ -808,6 +813,8 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
   conn->_base.state = OR_CONN_STATE_CONNECTING;
   control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0);
 
+  conn->is_outgoing = 1;
+
   /* use a proxy server if available */
   if (options->HTTPSProxy) {
     using_proxy = 1;

+ 6 - 0
src/or/or.h

@@ -1068,6 +1068,12 @@ typedef struct or_connection_t {
    * router itself has a problem.
    */
   unsigned int is_bad_for_new_circs:1;
+  /** True iff we have decided that the other end of this connection
+   * is a client.  Connections with this flag set should never be used
+   * to satisfy an EXTEND request.  */
+  unsigned int is_connection_with_client:1;
+  /** True iff this is an outgoing connection. */
+  unsigned int is_outgoing:1;
   uint8_t link_proto; /**< What protocol version are we using? 0 for
                        * "none negotiated yet." */
   circid_t next_circ_id; /**< Which circ_id do we try to use next on