瀏覽代碼

r16669@catbus: nickm | 2007-11-14 14:50:03 -0500
When we complete an OR handshake, set up all the internal fields and mark the connection as open.


svn:r12495

Nick Mathewson 17 年之前
父節點
當前提交
d483d3144a
共有 6 個文件被更改,包括 120 次插入55 次删除
  1. 3 4
      doc/TODO
  2. 5 7
      src/common/tortls.c
  3. 1 0
      src/common/tortls.h
  4. 48 25
      src/or/command.c
  5. 60 18
      src/or/connection_or.c
  6. 3 1
      src/or/or.h

+ 3 - 4
doc/TODO

@@ -50,11 +50,10 @@ Things we'd like to do in 0.2.0.x:
         o Generate CERT cells
         o Generate CERT cells
         o Keep copies of X509 certs around, not necessarily associated with
         o Keep copies of X509 certs around, not necessarily associated with
           connection.
           connection.
-      . LINK_AUTH cells
+      o LINK_AUTH cells
         o Code to generate
         o Code to generate
           o Remember certificate digests from TLS
           o Remember certificate digests from TLS
         o Code to parse and check
         o Code to parse and check
-        - Unit tests
       - Revised handshake: TLS
       - Revised handshake: TLS
         - Server checks for new cipher types, and if it finds them, sends
         - Server checks for new cipher types, and if it finds them, sends
           only one cert and does not ask for client certs.
           only one cert and does not ask for client certs.
@@ -65,9 +64,9 @@ Things we'd like to do in 0.2.0.x:
         o If in 'handshaking' state (since v2+ conn is in use), accept
         o If in 'handshaking' state (since v2+ conn is in use), accept
           VERSIONS and NETINFO and CERT and LINK_AUTH.
           VERSIONS and NETINFO and CERT and LINK_AUTH.
         o After we send NETINFO, send CERT and LINK_AUTH if needed.
         o After we send NETINFO, send CERT and LINK_AUTH if needed.
-        - Once we get a good LINK_AUTH, the connection is OPEN.
+        o Once we get a good LINK_AUTH, the connection is OPEN.
         - Ban most cell types on a non-OPEN connection.
         - Ban most cell types on a non-OPEN connection.
-        - Close connections on handshake failure.
+        o Close connections on handshake failure.
       o Make code work right wrt TLS context rotation.
       o Make code work right wrt TLS context rotation.
       - NETINFO fallout
       - NETINFO fallout
         - Don't extend a circuit over a noncanonical connection with
         - Don't extend a circuit over a noncanonical connection with

+ 5 - 7
src/common/tortls.c

@@ -933,6 +933,7 @@ tor_tls_verify_certs_v2(int severity, tor_tls_t *tls,
                         const char *id_cert_str, size_t id_cert_len,
                         const char *id_cert_str, size_t id_cert_len,
                         crypto_pk_env_t **cert_key_out,
                         crypto_pk_env_t **cert_key_out,
                         char *conn_cert_digest_out,
                         char *conn_cert_digest_out,
+                        crypto_pk_env_t **id_key_out,
                         char *id_digest_out)
                         char *id_digest_out)
 {
 {
   X509 *cert = NULL, *id_cert = NULL;
   X509 *cert = NULL, *id_cert = NULL;
@@ -942,6 +943,7 @@ tor_tls_verify_certs_v2(int severity, tor_tls_t *tls,
 
 
   tor_assert(cert_key_out);
   tor_assert(cert_key_out);
   tor_assert(conn_cert_digest_out);
   tor_assert(conn_cert_digest_out);
+  tor_assert(id_key_out);
   tor_assert(id_digest_out);
   tor_assert(id_digest_out);
 
 
   *cert_key_out = NULL;
   *cert_key_out = NULL;
@@ -996,13 +998,9 @@ tor_tls_verify_certs_v2(int severity, tor_tls_t *tls,
     goto done;
     goto done;
   }
   }
 
 
-  {
+  if (!(*id_key_out = _crypto_new_pk_env_evp_pkey(id_pkey)))
-    crypto_pk_env_t *i = _crypto_new_pk_env_evp_pkey(id_pkey);
+    goto done;
-    if (!i)
+  crypto_pk_get_digest(*id_key_out, id_digest_out);
-      goto done;
-    crypto_pk_get_digest(i, id_digest_out);
-    crypto_free_pk_env(i);
-  }
   if (!(cert_pkey = X509_get_pubkey(cert)))
   if (!(cert_pkey = X509_get_pubkey(cert)))
     goto done;
     goto done;
   if (!(*cert_key_out = _crypto_new_pk_env_evp_pkey(cert_pkey)))
   if (!(*cert_key_out = _crypto_new_pk_env_evp_pkey(cert_pkey)))

+ 1 - 0
src/common/tortls.h

@@ -67,6 +67,7 @@ int tor_tls_verify_certs_v2(int severity, tor_tls_t *tls,
                             const char *id_cert_str, size_t id_cert_len,
                             const char *id_cert_str, size_t id_cert_len,
                             crypto_pk_env_t **cert_key_out,
                             crypto_pk_env_t **cert_key_out,
                             char *conn_cert_digest_out,
                             char *conn_cert_digest_out,
+                            crypto_pk_env_t **id_key_out,
                             char *id_digest_out);
                             char *id_digest_out);
 int tor_tls_check_lifetime(tor_tls_t *tls, int tolerance);
 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_read(tor_tls_t *tls, char *cp, size_t len);

+ 48 - 25
src/or/command.c

@@ -475,18 +475,20 @@ command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
   }
   }
   if (!highest_supported_version) {
   if (!highest_supported_version) {
     log_fn(LOG_PROTOCOL_WARN, LD_OR,
     log_fn(LOG_PROTOCOL_WARN, LD_OR,
-           "Couldn't find a version in common; defaulting to v1.");
+           "Couldn't find a version in common between my version list and the "
-    /*XXXX020 just break the connection! */
+           "list in the VERSIONS cell; closing connection.");
-    conn->link_proto = 1;
+    connection_mark_for_close(TO_CONN(conn));
     return;
     return;
   }
   }
   conn->link_proto = highest_supported_version;
   conn->link_proto = highest_supported_version;
   conn->handshake_state->received_versions = 1;
   conn->handshake_state->received_versions = 1;
 
 
   if (highest_supported_version >= 2) {
   if (highest_supported_version >= 2) {
-    /*XXXX020 check return values. */
+    if (connection_or_send_netinfo(conn) < 0 ||
-    connection_or_send_netinfo(conn);
+        connection_or_send_cert(conn) < 0) {
-    connection_or_send_cert(conn);
+      connection_mark_for_close(TO_CONN(conn));
+      return;
+    }
     if (conn->handshake_state->started_here)
     if (conn->handshake_state->started_here)
       connection_or_send_link_auth(conn);
       connection_or_send_link_auth(conn);
   } else {
   } else {
@@ -536,8 +538,8 @@ command_process_netinfo_cell(cell_t *cell, or_connection_t *conn)
   cp = cell->payload + 6 + my_addr_len;
   cp = cell->payload + 6 + my_addr_len;
   if (cp >= end) {
   if (cp >= end) {
     log_fn(LOG_PROTOCOL_WARN, LD_OR,
     log_fn(LOG_PROTOCOL_WARN, LD_OR,
-           "Address too long in netinfo cell; dropping.");
+           "Addresses too long in netinfo cell; closing connection.");
-    /*XXXX020 reject and break OR conn! */
+    connection_mark_for_close(TO_CONN(conn));
     return;
     return;
   } else if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) {
   } else if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) {
     conn->handshake_state->my_apparent_addr = ntohl(get_uint32(my_addr_ptr));
     conn->handshake_state->my_apparent_addr = ntohl(get_uint32(my_addr_ptr));
@@ -549,8 +551,12 @@ command_process_netinfo_cell(cell_t *cell, or_connection_t *conn)
      * "canonical." */
      * "canonical." */
     uint8_t other_addr_type = (uint8_t) *cp++;
     uint8_t other_addr_type = (uint8_t) *cp++;
     uint8_t other_addr_len = (uint8_t) *cp++;
     uint8_t other_addr_len = (uint8_t) *cp++;
-    if (cp + other_addr_len >= end)
+    if (cp + other_addr_len >= end) {
-      break; /*XXXX020 protocol warn. */
+      log_fn(LOG_PROTOCOL_WARN, LD_OR,
+             "Address too long in netinfo cell; closing connection.");
+      connection_mark_for_close(TO_CONN(conn));
+      return;
+    }
     if (other_addr_type == RESOLVED_TYPE_IPV4 && other_addr_len == 4) {
     if (other_addr_type == RESOLVED_TYPE_IPV4 && other_addr_len == 4) {
       uint32_t addr = ntohl(get_uint32(cp));
       uint32_t addr = ntohl(get_uint32(cp));
       if (addr == conn->real_addr) {
       if (addr == conn->real_addr) {
@@ -568,12 +574,12 @@ command_process_netinfo_cell(cell_t *cell, or_connection_t *conn)
 /*XXXX020 move to connection_or.c */
 /*XXXX020 move to connection_or.c */
 /** DOCDOC Called when we're done authenticating; act on stuff we
 /** DOCDOC Called when we're done authenticating; act on stuff we
  * learned in netinfo. */
  * learned in netinfo. */
-void
+int
 connection_or_act_on_netinfo(or_connection_t *conn)
 connection_or_act_on_netinfo(or_connection_t *conn)
 {
 {
   long delta;
   long delta;
   if (!conn->handshake_state)
   if (!conn->handshake_state)
-    return;
+    return -1;
 
 
   tor_assert(conn->handshake_state->authenticated != 0);
   tor_assert(conn->handshake_state->authenticated != 0);
 
 
@@ -601,6 +607,8 @@ connection_or_act_on_netinfo(or_connection_t *conn)
   if (conn->handshake_state->apparently_canonical) {
   if (conn->handshake_state->apparently_canonical) {
     conn->is_canonical = 1;
     conn->is_canonical = 1;
   }
   }
+
+  return 0;
 }
 }
 
 
 /*DOCDOC*/
 /*DOCDOC*/
@@ -611,16 +619,25 @@ command_process_cert_cell(var_cell_t *cell, or_connection_t *conn)
   uint16_t conn_cert_len = 0, id_cert_len = 0;
   uint16_t conn_cert_len = 0, id_cert_len = 0;
   const char *conn_cert = NULL, *id_cert = NULL;
   const char *conn_cert = NULL, *id_cert = NULL;
   const char *cp, *end;
   const char *cp, *end;
-  int authenticated = 0;
+  int done = 0;
 
 
-  /*XXXX020 log messages*/
+  if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING) {
-  if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING)
+    log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got CERT cell when not handshaking. "
-    goto err;
+           "Ignoring.");
+    return;
+  }
   tor_assert(conn->handshake_state);
   tor_assert(conn->handshake_state);
   if (!conn->handshake_state->received_versions ||
   if (!conn->handshake_state->received_versions ||
-      !conn->handshake_state->received_netinfo ||
+      !conn->handshake_state->received_netinfo) {
-      conn->handshake_state->received_certs)
+    log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got CERT cell before VERSIONS and "
+           "NETINFO. Closing the connection.");
+    goto err;
+  }
+  if (conn->handshake_state->received_certs) {
+    log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got duplicate CERT cell. "
+           "Closing the connection.");
     goto err;
     goto err;
+  }
 
 
   cp = cell->payload;
   cp = cell->payload;
   end = cell->payload + cell->payload_len;
   end = cell->payload + cell->payload_len;
@@ -651,6 +668,7 @@ command_process_cert_cell(var_cell_t *cell, or_connection_t *conn)
   /* Now we have 0, 1, or 2 certs. */
   /* Now we have 0, 1, or 2 certs. */
   if (n_certs == 0) {
   if (n_certs == 0) {
     /* The other side is unauthenticated. */
     /* The other side is unauthenticated. */
+    done = 1;
   } else {
   } else {
     int r;
     int r;
     r = tor_tls_verify_certs_v2(LOG_PROTOCOL_WARN, conn->tls,
     r = tor_tls_verify_certs_v2(LOG_PROTOCOL_WARN, conn->tls,
@@ -660,23 +678,27 @@ command_process_cert_cell(var_cell_t *cell, or_connection_t *conn)
                                 (conn->handshake_state->started_here ?
                                 (conn->handshake_state->started_here ?
                                  conn->handshake_state->server_cert_digest :
                                  conn->handshake_state->server_cert_digest :
                                  conn->handshake_state->client_cert_digest),
                                  conn->handshake_state->client_cert_digest),
+                                &conn->handshake_state->identity_key,
                                 conn->handshake_state->cert_id_digest);
                                 conn->handshake_state->cert_id_digest);
     if (r < 0)
     if (r < 0)
       goto err;
       goto err;
-    if (r == 1)
+    if (r == 1) {
-      authenticated = 1;
+      done = 1;
+      conn->handshake_state->authenticated = 1;
+    }
   }
   }
 
 
   conn->handshake_state->received_certs = 1;
   conn->handshake_state->received_certs = 1;
-  if (authenticated) {
+  if (done) {
-    /* XXXX020 make the connection open. */
+    if (connection_or_finish_or_handshake(conn) < 0)
+      goto err;
   }
   }
   if (! conn->handshake_state->signing_key)
   if (! conn->handshake_state->signing_key)
     goto err;
     goto err;
 
 
   return;
   return;
  err:
  err:
-  /*XXXX020 close the connection */;
+  connection_mark_for_close(TO_CONN(conn));
 }
 }
 
 
 #define LINK_AUTH_STRING "Tor initiator certificate verification"
 #define LINK_AUTH_STRING "Tor initiator certificate verification"
@@ -746,11 +768,12 @@ command_process_link_auth_cell(cell_t *cell, or_connection_t *conn)
     goto err;
     goto err;
   }
   }
 
 
-  /* Okay, we're authenticated. */
   s->authenticated = 1;
   s->authenticated = 1;
 
 
-  /* XXXX020 act on being authenticated: Open the connection. */
+  if (connection_or_finish_or_handshake(conn)<0)
+    goto err;
 
 
+  tor_free(checked);
   return;
   return;
  err:
  err:
   tor_free(checked);
   tor_free(checked);

+ 60 - 18
src/or/connection_or.c

@@ -614,6 +614,8 @@ connection_or_nonopen_was_started_here(or_connection_t *conn)
   tor_assert(conn->_base.type == CONN_TYPE_OR);
   tor_assert(conn->_base.type == CONN_TYPE_OR);
   if (!conn->tls)
   if (!conn->tls)
     return 1; /* it's still in proxy states or something */
     return 1; /* it's still in proxy states or something */
+  if (conn->handshake_state)
+    return conn->handshake_state->started_here;
   return !tor_tls_is_server(conn->tls);
   return !tor_tls_is_server(conn->tls);
 }
 }
 
 
@@ -651,8 +653,15 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
     started_here ? conn->_base.address : safe_str(conn->_base.address);
     started_here ? conn->_base.address : safe_str(conn->_base.address);
   const char *conn_type = started_here ? "outgoing" : "incoming";
   const char *conn_type = started_here ? "outgoing" : "incoming";
   int has_cert = 0, has_identity = 0;
   int has_cert = 0, has_identity = 0;
+  int v1 = (conn->link_proto == 1);
 
 
   check_no_tls_errors();
   check_no_tls_errors();
+  if (v1) {
+    has_cert = tor_tls_peer_has_cert(conn->tls);
+  } else {
+    tor_assert(conn->handshake_state);
+    has_cert = !tor_digest_is_zero(conn->handshake_state->cert_id_digest);
+  }
   has_cert = tor_tls_peer_has_cert(conn->tls);
   has_cert = tor_tls_peer_has_cert(conn->tls);
   if (started_here && !has_cert) {
   if (started_here && !has_cert) {
     log_info(LD_PROTOCOL,"Tried connecting to router at %s:%d, but it didn't "
     log_info(LD_PROTOCOL,"Tried connecting to router at %s:%d, but it didn't "
@@ -665,28 +674,34 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
   }
   }
   check_no_tls_errors();
   check_no_tls_errors();
 
 
-  if (has_cert) {
+  if (v1) {
-    int v = tor_tls_verify_v1(started_here?severity:LOG_INFO,
+    if (has_cert) {
-                              conn->tls, &identity_rcvd);
+      int v = tor_tls_verify_v1(started_here?severity:LOG_INFO,
-    if (started_here && v<0) {
+                                conn->tls, &identity_rcvd);
-      log_fn(severity,LD_OR,"Tried connecting to router at %s:%d: It"
+      if (started_here && v<0) {
-             " has a cert but it's invalid. Closing.",
+        log_fn(severity,LD_OR,"Tried connecting to router at %s:%d: It"
-             safe_address, conn->_base.port);
+               " has a cert but it's invalid. Closing.",
-      return -1;
+               safe_address, conn->_base.port);
-    } else if (v<0) {
+        return -1;
-      log_info(LD_PROTOCOL,"Incoming connection gave us an invalid cert "
+      } else if (v<0) {
-               "chain; ignoring.");
+        log_info(LD_PROTOCOL,"Incoming connection gave us an invalid cert "
-    } else {
+                 "chain; ignoring.");
-      log_debug(LD_OR,"The certificate seems to be valid on %s connection "
+      } else {
-                "with %s:%d", conn_type, safe_address, conn->_base.port);
+        log_debug(LD_OR,"The certificate seems to be valid on %s connection "
+                  "with %s:%d", conn_type, safe_address, conn->_base.port);
+      }
+      check_no_tls_errors();
+    }
+  } else {
+    if (conn->handshake_state->authenticated &&
+        conn->handshake_state->identity_key) {
+      identity_rcvd = crypto_pk_dup_key(conn->handshake_state->identity_key);
     }
     }
-    check_no_tls_errors();
   }
   }
 
 
   if (identity_rcvd) {
   if (identity_rcvd) {
     has_identity=1;
     has_identity=1;
     crypto_pk_get_digest(identity_rcvd, digest_rcvd_out);
     crypto_pk_get_digest(identity_rcvd, digest_rcvd_out);
-
     if (crypto_pk_cmp_keys(get_identity_key(), identity_rcvd)<0) {
     if (crypto_pk_cmp_keys(get_identity_key(), identity_rcvd)<0) {
       conn->circ_id_type = CIRC_ID_TYPE_LOWER;
       conn->circ_id_type = CIRC_ID_TYPE_LOWER;
     } else {
     } else {
@@ -744,6 +759,29 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
   return 0;
   return 0;
 }
 }
 
 
+/** DOCDOC */
+int
+connection_or_finish_or_handshake(or_connection_t *conn)
+{
+  char id_digest[DIGEST_LEN];
+  tor_assert(conn);
+  tor_assert(conn->handshake_state);
+  tor_assert(conn->link_proto >= 2);
+  tor_assert(conn->handshake_state->received_versions != 0);
+  tor_assert(conn->handshake_state->received_netinfo != 0);
+  tor_assert(conn->handshake_state->received_certs != 0);
+
+  if (connection_or_check_valid_tls_handshake(conn,
+                                  conn->handshake_state->started_here,
+                                              id_digest) < 0)
+    return -1;
+  connection_or_init_conn_from_address(conn, conn->_base.addr,
+                                       conn->_base.port, id_digest, 0);
+  if (connection_or_act_on_netinfo(conn)<0)
+    return -1;
+  return connection_or_set_state_open(conn);
+}
+
 /** The tls handshake is finished.
 /** The tls handshake is finished.
  *
  *
  * Make sure we are happy with the person we just handshaked with.
  * Make sure we are happy with the person we just handshaked with.
@@ -815,6 +853,8 @@ or_handshake_state_free(or_handshake_state_t *state)
   tor_assert(state);
   tor_assert(state);
   if (state->signing_key)
   if (state->signing_key)
     crypto_free_pk_env(state->signing_key);
     crypto_free_pk_env(state->signing_key);
+  if (state->identity_key)
+    crypto_free_pk_env(state->identity_key);
   memset(state, 0xBE, sizeof(or_handshake_state_t));
   memset(state, 0xBE, sizeof(or_handshake_state_t));
   tor_free(state);
   tor_free(state);
 }
 }
@@ -836,6 +876,10 @@ connection_or_set_state_open(or_connection_t *conn)
     }
     }
     router_set_status(conn->identity_digest, 1);
     router_set_status(conn->identity_digest, 1);
   }
   }
+  if (conn->handshake_state) {
+    or_handshake_state_free(conn->handshake_state);
+    conn->handshake_state = NULL;
+  }
   connection_watch_events(TO_CONN(conn), EV_READ);
   connection_watch_events(TO_CONN(conn), EV_READ);
   circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
   circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
 
 
@@ -1120,8 +1164,6 @@ connection_or_send_link_auth(or_connection_t *conn)
 
 
   connection_or_write_cell_to_buf(&cell, conn);
   connection_or_write_cell_to_buf(&cell, conn);
 
 
-  /* XXXX020 at this point, as a client, we can consider ourself
-   * authenticated. */
   return 0;
   return 0;
 }
 }
 
 

+ 3 - 1
src/or/or.h

@@ -894,6 +894,7 @@ typedef struct or_handshake_state_t {
   /* from certs */
   /* from certs */
   char cert_id_digest[DIGEST_LEN];
   char cert_id_digest[DIGEST_LEN];
   crypto_pk_env_t *signing_key;
   crypto_pk_env_t *signing_key;
+  crypto_pk_env_t *identity_key;
 } or_handshake_state_t;
 } or_handshake_state_t;
 
 
 /** Subtype of connection_t for an "OR connection" -- that is, one that speaks
 /** Subtype of connection_t for an "OR connection" -- that is, one that speaks
@@ -2561,7 +2562,7 @@ int connection_ap_handshake_attach_circuit(edge_connection_t *conn);
 
 
 void command_process_cell(cell_t *cell, or_connection_t *conn);
 void command_process_cell(cell_t *cell, or_connection_t *conn);
 void command_process_var_cell(var_cell_t *cell, or_connection_t *conn);
 void command_process_var_cell(var_cell_t *cell, or_connection_t *conn);
-void connection_or_act_on_netinfo(or_connection_t *conn);
+int connection_or_act_on_netinfo(or_connection_t *conn);
 
 
 extern uint64_t stats_n_padding_cells_processed;
 extern uint64_t stats_n_padding_cells_processed;
 extern uint64_t stats_n_create_cells_processed;
 extern uint64_t stats_n_create_cells_processed;
@@ -2781,6 +2782,7 @@ int connection_or_process_inbuf(or_connection_t *conn);
 int connection_or_flushed_some(or_connection_t *conn);
 int connection_or_flushed_some(or_connection_t *conn);
 int connection_or_finished_flushing(or_connection_t *conn);
 int connection_or_finished_flushing(or_connection_t *conn);
 int connection_or_finished_connecting(or_connection_t *conn);
 int connection_or_finished_connecting(or_connection_t *conn);
+int connection_or_finish_or_handshake(or_connection_t *conn);
 
 
 or_connection_t *connection_or_connect(uint32_t addr, uint16_t port,
 or_connection_t *connection_or_connect(uint32_t addr, uint16_t port,
                                     const char *id_digest);
                                     const char *id_digest);