[tor-commits] [tor/master] prop224: Introduce e2e rendezvous circuit code.

nickm at torproject.org nickm at torproject.org
Fri Jul 7 15:19:28 UTC 2017


commit 0cb66fc900f5198fb063454801af3b4b22867e50
Author: David Goulet <dgoulet at torproject.org>
Date:   Fri May 12 12:00:43 2017 -0400

    prop224: Introduce e2e rendezvous circuit code.
    
    This commit adds most of the work of #21859. It introduces hs_circuit.c
    functions that can handle the setup of e2e circuits for prop224 hidden
    services, and also for legacy hidden service clients. Entry points are:
    
    		prop224 circuits: hs_circuit_setup_e2e_rend_circ()
    		legacy client-side circuits: hs_circuit_setup_e2e_rend_circ_legacy_client()
    
    This commit swaps the old rendclient code to use the new API.
    
    I didn't try to accomodate the legacy service-side code in this API, since
    that's too tangled up and it would mess up the new API considerably IMO (all
    this service_pending_final_cpath_ref stuff is complicated and I didn't want to
    change it).
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 src/or/hs_circuit.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/or/hs_circuit.h |  23 ++++++
 src/or/include.am   |   2 +
 src/or/rendclient.c |  52 +------------
 4 files changed, 244 insertions(+), 48 deletions(-)

diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
new file mode 100644
index 0000000..f8c95f7
--- /dev/null
+++ b/src/or/hs_circuit.c
@@ -0,0 +1,215 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_circuit.c
+ **/
+
+#include "or.h"
+#include "circuitbuild.h"
+#include "circuitlist.h"
+#include "circuituse.h"
+#include "config.h"
+
+#include "hs_circuit.h"
+#include "hs_ident.h"
+#include "hs_ntor.h"
+
+/* A circuit is about to become an e2e rendezvous circuit. Check
+ * <b>circ_purpose</b> and ensure that it's properly set.  Return 0 if circuit
+ * purpose is properly set, otherwise return -1. */
+static int
+rend_circuit_validate_purpose(unsigned int circ_purpose, int is_service_side)
+{
+  if (is_service_side) {
+    if (circ_purpose != CIRCUIT_PURPOSE_S_CONNECT_REND) {
+      log_warn(LD_GENERAL, "HS e2e circuit setup with wrong purpose(%d)",
+               circ_purpose);
+      return -1;
+    }
+  }
+
+  if (!is_service_side) {
+    if (circ_purpose != CIRCUIT_PURPOSE_C_REND_READY &&
+        circ_purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) {
+      log_warn(LD_GENERAL, "Client e2e circuit setup with wrong purpose(%d)",
+               circ_purpose);
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+/* Create and return a crypt path for the final hop of a v3 prop224 rendezvous
+ * circuit. Initialize the crypt path crypto using the output material from the
+ * ntor key exchange at <b>ntor_key_seed</b>.
+ *
+ * If <b>is_service_side</b> is set, we are the hidden service and the final
+ * hop of the rendezvous circuit is the client on the other side. */
+static crypt_path_t *
+get_rend_cpath(const uint8_t *ntor_key_seed, int is_service_side)
+{
+  uint8_t keys[HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN];
+  crypt_path_t *cpath = NULL;
+
+  /* Do the key expansion */
+  hs_ntor_circuit_key_expansion(ntor_key_seed, keys);
+
+  /* Setup the cpath */
+  cpath = tor_malloc_zero(sizeof(crypt_path_t));
+  cpath->magic = CRYPT_PATH_MAGIC;
+
+  if (circuit_init_cpath_crypto(cpath, (char*)keys,
+                                is_service_side, 1) < 0) {
+    tor_free(cpath);
+    goto err;
+  }
+
+ err:
+  memwipe(keys, 0, sizeof(keys));
+  return cpath;
+}
+
+/* We are a v2 legacy HS client: Create and return a crypt path for the hidden
+ * service on the other side of the rendezvous circuit <b>circ</b>. Initialize
+ * the crypt path crypto using the body of the RENDEZVOUS1 cell at
+ * <b>rend_cell_body</b> (which must be at least DH_KEY_LEN+DIGEST_LEN bytes).
+ */
+static crypt_path_t *
+get_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body)
+{
+  crypt_path_t *hop = NULL;
+  char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
+
+  /* first DH_KEY_LEN bytes are g^y from the service. Finish the dh
+   * handshake...*/
+  tor_assert(circ->build_state);
+  tor_assert(circ->build_state->pending_final_cpath);
+  hop = circ->build_state->pending_final_cpath;
+
+  tor_assert(hop->rend_dh_handshake_state);
+  if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, hop->rend_dh_handshake_state,
+                               (char*)rend_cell_body, DH_KEY_LEN,
+                               keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
+    log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
+    goto err;
+  }
+  /* ... and set up cpath. */
+  if (circuit_init_cpath_crypto(hop, keys+DIGEST_LEN, 0, 0)<0)
+    goto err;
+
+  /* Check whether the digest is right... */
+  if (tor_memneq(keys, rend_cell_body+DH_KEY_LEN, DIGEST_LEN)) {
+    log_warn(LD_PROTOCOL, "Incorrect digest of key material.");
+    goto err;
+  }
+
+  /* clean up the crypto stuff we just made */
+  crypto_dh_free(hop->rend_dh_handshake_state);
+  hop->rend_dh_handshake_state = NULL;
+
+  goto done;
+
+ err:
+  hop = NULL;
+
+ done:
+  memwipe(keys, 0, sizeof(keys));
+  return hop;
+}
+
+/* Append the final <b>hop</b> to the cpath of the rend <b>circ</b>, and mark
+ * <b>circ</b> ready for use to transfer HS relay cells. */
+static void
+finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
+                      int is_service_side)
+{
+  tor_assert(circ);
+  tor_assert(hop);
+
+  /* Notify the circuit state machine that we are splicing this circuit */
+  int new_circ_purpose = is_service_side ?
+    CIRCUIT_PURPOSE_S_REND_JOINED : CIRCUIT_PURPOSE_C_REND_JOINED;
+  circuit_change_purpose(TO_CIRCUIT(circ), new_circ_purpose);
+
+  /* All is well. Extend the circuit. */
+  hop->state = CPATH_STATE_OPEN;
+  /* Set the windows to default. These are the windows that the client thinks
+   * the service has. */
+  hop->package_window = circuit_initial_package_window();
+  hop->deliver_window = CIRCWINDOW_START;
+
+  /* Now that this circuit has finished connecting to its destination,
+   * make sure circuit_get_open_circ_or_launch is willing to return it
+   * so we can actually use it. */
+  circ->hs_circ_has_timed_out = 0;
+
+  /* Append the hop to the cpath of this circuit */
+  onion_append_to_cpath(&circ->cpath, hop);
+
+  /* In legacy code, 'pending_final_cpath' points to the final hop we just
+   * appended to the cpath. We set the original pointer to NULL so that we
+   * don't double free it. */
+  if (circ->build_state) {
+    circ->build_state->pending_final_cpath = NULL;
+  }
+
+  /* Finally, mark circuit as ready to be used for client streams */
+  if (!is_service_side) {
+    circuit_try_attaching_streams(circ);
+  }
+}
+
+/* Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key
+ * exchange output material at <b>ntor_key_seed</b> and setup <b>circ</b> to
+ * serve as a rendezvous end-to-end circuit between the client and the
+ * service. If <b>is_service_side</b> is set, then we are the hidden service
+ * and the other side is the client.
+ *
+ * Return 0 if the operation went well; in case of error return -1. */
+int
+hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
+                               const uint8_t *ntor_key_seed,
+                               int is_service_side)
+{
+  if (BUG(rend_circuit_validate_purpose(TO_CIRCUIT(circ)->purpose,
+                                        is_service_side)) < 0) {
+    return -1;
+  }
+
+  crypt_path_t *hop = get_rend_cpath(ntor_key_seed, is_service_side);
+  if (!hop) {
+    log_warn(LD_REND, "Couldn't get v3 %s cpath!",
+             is_service_side ? "service-side" : "client-side");
+    return -1;
+  }
+
+  finalize_rend_circuit(circ, hop, is_service_side);
+
+  return 0;
+}
+
+/* We are a v2 legacy HS client and we just received a RENDEZVOUS1 cell
+ * <b>rend_cell_body</b> on <b>circ</b>. Finish up the DH key exchange and then
+ * extend the crypt path of <b>circ</b> so that the hidden service is on the
+ * other side. */
+int
+hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
+                                             const uint8_t *rend_cell_body)
+{
+  if (BUG(rend_circuit_validate_purpose(TO_CIRCUIT(circ)->purpose, 0)) < 0) {
+    return -1;
+  }
+
+  crypt_path_t *hop = get_rend_cpath_legacy(circ, rend_cell_body);
+  if (!hop) {
+    log_warn(LD_GENERAL, "Couldn't get v2 cpath.");
+    return -1;
+  }
+
+  finalize_rend_circuit(circ, hop, 0);
+
+  return 0;
+}
+
diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h
new file mode 100644
index 0000000..1c2924c
--- /dev/null
+++ b/src/or/hs_circuit.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_circuit.h
+ * \brief Header file containing circuit data for the whole HS subsytem.
+ **/
+
+#ifndef TOR_HS_CIRCUIT_H
+#define TOR_HS_CIRCUIT_H
+
+#include "or.h"
+
+/* e2e circuit API. */
+
+int hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
+                                   const uint8_t *ntor_key_seed,
+                                   int is_service_side);
+int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
+                                          const uint8_t *rend_cell_body);
+
+#endif /* TOR_HS_CIRCUIT_H */
+
diff --git a/src/or/include.am b/src/or/include.am
index e800db5..18868e4 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -53,6 +53,7 @@ LIBTOR_A_SOURCES = \
 	src/or/hs_cache.c				\
 	src/or/hs_circuitmap.c				\
 	src/or/hs_common.c				\
+	src/or/hs_circuit.c				\
 	src/or/hs_descriptor.c				\
 	src/or/hs_ident.c				\
 	src/or/hs_intropoint.c				\
@@ -182,6 +183,7 @@ ORHEADERS = \
 	src/or/hibernate.h				\
 	src/or/hs_cache.h				\
 	src/or/hs_common.h				\
+	src/or/hs_circuit.h				\
 	src/or/hs_descriptor.h				\
 	src/or/hs_ident.h				\
 	src/or/hs_intropoint.h          \
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 3cf67b5..3d160bd 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -17,6 +17,7 @@
 #include "connection_edge.h"
 #include "directory.h"
 #include "hs_common.h"
+#include "hs_circuit.h"
 #include "main.h"
 #include "networkstatus.h"
 #include "nodelist.h"
@@ -1150,9 +1151,6 @@ int
 rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
                                size_t request_len)
 {
-  crypt_path_t *hop;
-  char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
-
   if ((circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
        circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
       || !circ->build_state->pending_final_cpath) {
@@ -1170,55 +1168,13 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
 
   log_info(LD_REND,"Got RENDEZVOUS2 cell from hidden service.");
 
-  /* first DH_KEY_LEN bytes are g^y from the service. Finish the dh
-   * handshake...*/
-  tor_assert(circ->build_state);
-  tor_assert(circ->build_state->pending_final_cpath);
-  hop = circ->build_state->pending_final_cpath;
-  tor_assert(hop->rend_dh_handshake_state);
-  if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN,
-                               hop->rend_dh_handshake_state, (char*)request,
-                               DH_KEY_LEN,
-                               keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
-    log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
+  if (hs_circuit_setup_e2e_rend_circ_legacy_client(circ, request) < 0) {
+    log_warn(LD_GENERAL, "Failed to setup circ");
     goto err;
   }
-  /* ... and set up cpath. */
-  if (circuit_init_cpath_crypto(hop, keys+DIGEST_LEN, 0, 0)<0)
-    goto err;
-
-  /* Check whether the digest is right... */
-  if (tor_memneq(keys, request+DH_KEY_LEN, DIGEST_LEN)) {
-    log_warn(LD_PROTOCOL, "Incorrect digest of key material.");
-    goto err;
-  }
-
-  crypto_dh_free(hop->rend_dh_handshake_state);
-  hop->rend_dh_handshake_state = NULL;
-
-  /* All is well. Extend the circuit. */
-  circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_JOINED);
-  hop->state = CPATH_STATE_OPEN;
-  /* set the windows to default. these are the windows
-   * that the client thinks the service has.
-   */
-  hop->package_window = circuit_initial_package_window();
-  hop->deliver_window = CIRCWINDOW_START;
-
-  /* Now that this circuit has finished connecting to its destination,
-   * make sure circuit_get_open_circ_or_launch is willing to return it
-   * so we can actually use it. */
-  circ->hs_circ_has_timed_out = 0;
-
-  onion_append_to_cpath(&circ->cpath, hop);
-  circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
-
-  circuit_try_attaching_streams(circ);
-
-  memwipe(keys, 0, sizeof(keys));
   return 0;
+
  err:
-  memwipe(keys, 0, sizeof(keys));
   circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
   return -1;
 }





More information about the tor-commits mailing list