[tor-commits] [tor/master] Teach cpuworker and others about create_cell_t and friends

nickm at torproject.org nickm at torproject.org
Thu Jan 3 16:52:58 UTC 2013


commit 2802ccaeb6b95e693af7736e58e91434d28ac6a2
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Dec 5 22:34:49 2012 -0500

    Teach cpuworker and others about create_cell_t and friends
    
    The unit of work sent to a cpuworker is now a create_cell_t; its
    response is now a created_cell_t.  Several of the things that call or
    get called by this chain of logic now take create_cell_t or
    created_cell_t too.
    
    Since all cpuworkers are forked or spawned by Tor, they don't need a
    stable wire protocol, so we can just send structs.  This saves us some
    insanity, and helps p
---
 src/or/circuitbuild.c |   36 +++-------
 src/or/circuitbuild.h |    8 ++-
 src/or/command.c      |   73 ++++++++++++++-----
 src/or/cpuworker.c    |  189 +++++++++++++++++++++++++++----------------------
 src/or/cpuworker.h    |    3 +-
 src/or/onion.c        |   57 ++++++++++-----
 src/or/onion.h        |   13 ++--
 src/or/or.h           |    1 +
 src/or/relay.c        |   20 ++++--
 9 files changed, 235 insertions(+), 165 deletions(-)

diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 40aad6d..40cb8e4 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1359,7 +1359,7 @@ entry_guard_inc_first_hop_count(entry_guard_t *guard)
 }
 
 /** A created or extended cell came back to us on the circuit, and it included
- * <b>reply</b> as its body.  (If <b>reply_type</b> is CELL_CREATED, the body
+ * reply_cell as its body.  (If <b>reply_type</b> is CELL_CREATED, the body
  * contains (the second DH key, plus KH).  If <b>reply_type</b> is
  * CELL_CREATED_FAST, the body contains a secret y and a hash H(x|y).)
  *
@@ -1369,8 +1369,8 @@ entry_guard_inc_first_hop_count(entry_guard_t *guard)
  * Return - reason if we want to mark circ for close, else return 0.
  */
 int
-circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
-                         const uint8_t *reply)
+circuit_finish_handshake(origin_circuit_t *circ,
+                         const created_cell_t *reply)
 {
   char keys[CPATH_KEY_MATERIAL_LEN];
   crypt_path_t *hop;
@@ -1391,23 +1391,9 @@ circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
   tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
 
   {
-    uint16_t handshake_type = 0xffff;
-    if (reply_type == CELL_CREATED)
-      handshake_type = ONION_HANDSHAKE_TYPE_TAP;
-    else if (reply_type == CELL_CREATED_FAST)
-      handshake_type = ONION_HANDSHAKE_TYPE_FAST;
-
-    if (handshake_type != hop->handshake_state.tag) {
-      log_warn(LD_PROTOCOL,"CREATED cell onionskin type (%u) did not "
-               "match CREATE cell onionskin type (%u).",
-               (unsigned)handshake_type,
-               (unsigned) hop->handshake_state.tag);
-      return -END_CIRC_REASON_TORPROTOCOL;
-    }
-
-    if (onion_skin_client_handshake(handshake_type,
+    if (onion_skin_client_handshake(hop->handshake_state.tag,
                                     &hop->handshake_state,
-                                    reply,
+                                    reply->reply, reply->handshake_len,
                                     (uint8_t*)keys, sizeof(keys),
                                     (uint8_t*)hop->rend_circ_nonce) < 0) {
       log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
@@ -1422,8 +1408,7 @@ circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
   }
 
   hop->state = CPATH_STATE_OPEN;
-  log_info(LD_CIRC,"Finished building %scircuit hop:",
-           (reply_type == CELL_CREATED_FAST) ? "fast " : "");
+  log_info(LD_CIRC,"Finished building circuit hop:");
   circuit_log_path(LOG_INFO,LD_CIRC,circ);
   control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0);
 
@@ -1484,7 +1469,8 @@ circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason)
  */
 int
 onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
-                 size_t payload_len, const char *keys)
+                 size_t payload_len, const char *keys,
+                 const uint8_t *rend_circ_nonce)
 {
   cell_t cell;
   crypt_path_t *tmp_cpath;
@@ -1515,11 +1501,7 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
   tmp_cpath->magic = 0;
   tor_free(tmp_cpath);
 
-  /* XXXX Move responsibility for extracting this. */
-  if (cell_type == CELL_CREATED)
-    memcpy(circ->rend_circ_nonce, cell.payload+DH_KEY_LEN, DIGEST_LEN);
-  else
-    memcpy(circ->rend_circ_nonce, cell.payload+DIGEST_LEN, DIGEST_LEN);
+  memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
 
   circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
 
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index f83cb55..e53e6ba 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -30,13 +30,15 @@ void circuit_note_clock_jumped(int seconds_elapsed);
 int circuit_extend(cell_t *cell, circuit_t *circ);
 int circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
                               int reverse);
-int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
-                             const uint8_t *reply);
+struct created_cell_t;
+int circuit_finish_handshake(origin_circuit_t *circ,
+                             const struct created_cell_t *created_cell);
 int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer,
                       int reason);
 int onionskin_answer(or_circuit_t *circ, uint8_t cell_type,
                      const char *payload, size_t payload_len,
-                     const char *keys);
+                     const char *keys,
+                     const uint8_t *rend_circ_nonce);
 int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
                                         int *need_capacity);
 
diff --git a/src/or/command.c b/src/or/command.c
index a33a9b1..c77e2ec 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -29,9 +29,7 @@
 #include "cpuworker.h"
 #include "hibernate.h"
 #include "nodelist.h"
-//#include "onion.h"
-#include "onion_tap.h"
-#include "onion_fast.h"
+#include "onion.h"
 #include "relay.h"
 #include "router.h"
 #include "routerlist.h"
@@ -189,6 +187,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
   or_circuit_t *circ;
   const or_options_t *options = get_options();
   int id_is_high;
+  create_cell_t *create_cell;
 
   tor_assert(cell);
   tor_assert(chan);
@@ -254,12 +253,18 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
   circ = or_circuit_new(cell->circ_id, chan);
   circ->base_.purpose = CIRCUIT_PURPOSE_OR;
   circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
-  if (cell->command == CELL_CREATE) {
-    char *onionskin = tor_malloc(TAP_ONIONSKIN_CHALLENGE_LEN);
-    memcpy(onionskin, cell->payload, TAP_ONIONSKIN_CHALLENGE_LEN);
+  create_cell = tor_malloc_zero(sizeof(create_cell_t));
+  if (create_cell_parse(create_cell, cell) < 0) {
+    tor_free(create_cell);
+    log_fn(LOG_PROTOCOL_WARN, LD_OR,
+           "Bogus/unrecognized create cell; closing.");
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
+    return;
+  }
 
+  if (create_cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) {
     /* hand it off to the cpuworkers, and then return. */
-    if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) {
+    if (assign_onionskin_to_cpuworker(NULL, circ, create_cell) < 0) {
       log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing.");
       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
       return;
@@ -268,27 +273,35 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
   } else {
     /* This is a CREATE_FAST cell; we can handle it immediately without using
      * a CPU worker. */
-    char keys[CPATH_KEY_MATERIAL_LEN];
-    char reply[DIGEST_LEN*2];
-
-    tor_assert(cell->command == CELL_CREATE_FAST);
+    uint8_t keys[CPATH_KEY_MATERIAL_LEN];
+    uint8_t reply[MAX_ONIONSKIN_REPLY_LEN];
+    uint8_t rend_circ_nonce[DIGEST_LEN];
+    int len;
 
     /* Make sure we never try to use the OR connection on which we
      * received this cell to satisfy an EXTEND request,  */
     channel_mark_client(chan);
 
-    if (fast_server_handshake(cell->payload, (uint8_t*)reply,
-                              (uint8_t*)keys, sizeof(keys))<0) {
+    len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST,
+                                       create_cell->onionskin,
+                                       create_cell->handshake_len,
+                                       NULL,
+                                       reply, keys, CPATH_KEY_MATERIAL_LEN,
+                                       rend_circ_nonce);
+    tor_free(create_cell);
+    if (len < 0) {
       log_warn(LD_OR,"Failed to generate key material. Closing.");
       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
+      tor_free(create_cell);
       return;
     }
-    if (onionskin_answer(circ, CELL_CREATED_FAST, reply, sizeof(reply),
-                         keys)<0) {
+    if (onionskin_answer(circ, CELL_CREATED_FAST, (const char *)reply, len,
+                         (const char *)keys, rend_circ_nonce)<0) {
       log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       return;
     }
+    memwipe(keys, 0, sizeof(keys));
   }
 }
 
@@ -304,6 +317,7 @@ static void
 command_process_created_cell(cell_t *cell, channel_t *chan)
 {
   circuit_t *circ;
+  extended_cell_t extended_cell;
 
   circ = circuit_get_by_circid_channel(cell->circ_id, chan);
 
@@ -321,12 +335,18 @@ command_process_created_cell(cell_t *cell, channel_t *chan)
     return;
   }
 
+  if (created_cell_parse(&extended_cell.created_cell, cell) < 0) {
+    log_fn(LOG_PROTOCOL_WARN, LD_OR, "Unparseable created cell.");
+    circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
+    return;
+  }
+
   if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
     origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
     int err_reason = 0;
     log_debug(LD_OR,"at OP. Finishing handshake.");
-    if ((err_reason = circuit_finish_handshake(origin_circ, cell->command,
-                                               cell->payload)) < 0) {
+    if ((err_reason = circuit_finish_handshake(origin_circ,
+                                        &extended_cell.created_cell)) < 0) {
       log_warn(LD_OR,"circuit_finish_handshake failed.");
       circuit_mark_for_close(circ, -err_reason);
       return;
@@ -339,11 +359,24 @@ command_process_created_cell(cell_t *cell, channel_t *chan)
       return;
     }
   } else { /* pack it into an extended relay cell, and send it. */
+    uint8_t command=0;
+    uint16_t len=0;
+    uint8_t payload[RELAY_PAYLOAD_SIZE];
     log_debug(LD_OR,
               "Converting created cell to extended relay cell, sending.");
-    relay_send_command_from_edge(0, circ, RELAY_COMMAND_EXTENDED,
-                                 (char*)cell->payload, TAP_ONIONSKIN_REPLY_LEN,
-                                 NULL);
+    memset(payload, 0, sizeof(payload));
+    if (extended_cell.created_cell.cell_type == CELL_CREATED2)
+      extended_cell.cell_type = RELAY_COMMAND_EXTENDED2;
+    else
+      extended_cell.cell_type = RELAY_COMMAND_EXTENDED;
+    if (extended_cell_format(&command, &len, payload, &extended_cell) < 0) {
+      log_fn(LOG_PROTOCOL_WARN, LD_OR, "Can't format extended cell.");
+      circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
+      return;
+    }
+
+    relay_send_command_from_edge(0, circ, command,
+                                 (const char*)payload, len, NULL);
   }
 }
 
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index e8087c2..a8ec027 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -23,7 +23,6 @@
 #include "cpuworker.h"
 #include "main.h"
 #include "onion.h"
-#include "onion_tap.h"
 #include "router.h"
 
 /** The maximum number of cpuworker processes we will keep around. */
@@ -33,9 +32,6 @@
 
 /** The tag specifies which circuit this onionskin was from. */
 #define TAG_LEN 10
-/** How many bytes are sent from the cpuworker back to tor? */
-#define LEN_ONION_RESPONSE \
-  (1+TAG_LEN+TAP_ONIONSKIN_REPLY_LEN+CPATH_KEY_MATERIAL_LEN)
 
 /** How many cpuworkers we have running right now. */
 static int num_cpuworkers=0;
@@ -71,7 +67,7 @@ connection_cpu_finished_flushing(connection_t *conn)
 /** Pack global_id and circ_id; set *tag to the result. (See note on
  * cpuworker_main for wire format.) */
 static void
-tag_pack(char *tag, uint64_t chan_id, circid_t circ_id)
+tag_pack(uint8_t *tag, uint64_t chan_id, circid_t circ_id)
 {
   /*XXXX RETHINK THIS WHOLE MESS !!!! !NM NM NM NM*/
   /*XXXX DOUBLEPLUSTHIS!!!! AS AS AS AS*/
@@ -82,12 +78,38 @@ tag_pack(char *tag, uint64_t chan_id, circid_t circ_id)
 /** Unpack <b>tag</b> into addr, port, and circ_id.
  */
 static void
-tag_unpack(const char *tag, uint64_t *chan_id, circid_t *circ_id)
+tag_unpack(const uint8_t *tag, uint64_t *chan_id, circid_t *circ_id)
 {
   *chan_id = get_uint64(tag);
   *circ_id = get_uint16(tag+8);
 }
 
+/** DOCDOC */
+#define CPUWORKER_REQUEST_MAGIC 0xda4afeed
+#define CPUWORKER_REPLY_MAGIC 0x5eedf00d
+
+/**DOCDOC*/
+typedef struct cpuworker_request_t {
+  uint32_t magic;
+  /** Opaque tag to identify the job */
+  uint8_t tag[TAG_LEN];
+  uint8_t task;
+
+  create_cell_t create_cell;
+  /* Turn the above into a tagged union if needed. */
+} cpuworker_request_t;
+
+/**DOCDOC*/
+typedef struct cpuworker_reply_t {
+  uint32_t magic;
+  uint8_t tag[TAG_LEN];
+  uint8_t success;
+
+  created_cell_t created_cell;
+  uint8_t keys[CPATH_KEY_MATERIAL_LEN];
+  uint8_t rend_auth_material[DIGEST_LEN];
+} cpuworker_reply_t;
+
 /** Called when the onion key has changed and we need to spawn new
  * cpuworkers.  Close all currently idle cpuworkers, and mark the last
  * rotation time as now.
@@ -133,8 +155,6 @@ connection_cpu_reached_eof(connection_t *conn)
 int
 connection_cpu_process_inbuf(connection_t *conn)
 {
-  char success;
-  char buf[LEN_ONION_RESPONSE];
   uint64_t chan_id;
   circid_t circ_id;
   channel_t *p_chan = NULL;
@@ -147,15 +167,16 @@ connection_cpu_process_inbuf(connection_t *conn)
     return 0;
 
   if (conn->state == CPUWORKER_STATE_BUSY_ONION) {
-    if (connection_get_inbuf_len(conn) < LEN_ONION_RESPONSE)
+    cpuworker_reply_t rpl;
+    if (connection_get_inbuf_len(conn) < sizeof(cpuworker_reply_t))
       return 0; /* not yet */
-    tor_assert(connection_get_inbuf_len(conn) == LEN_ONION_RESPONSE);
+    tor_assert(connection_get_inbuf_len(conn) == sizeof(cpuworker_reply_t));
 
-    connection_fetch_from_buf(&success,1,conn);
-    connection_fetch_from_buf(buf,LEN_ONION_RESPONSE-1,conn);
+    connection_fetch_from_buf((void*)&rpl,sizeof(cpuworker_reply_t),conn);
 
+    tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC);
     /* parse out the circ it was talking about */
-    tag_unpack(buf, &chan_id, &circ_id);
+    tag_unpack(rpl.tag, &chan_id, &circ_id);
     circ = NULL;
     log_debug(LD_OR,
               "Unpacking cpuworker reply, chan_id is " U64_FORMAT
@@ -166,7 +187,7 @@ connection_cpu_process_inbuf(connection_t *conn)
     if (p_chan)
       circ = circuit_get_by_circid_channel(circ_id, p_chan);
 
-    if (success == 0) {
+    if (rpl.success == 0) {
       log_debug(LD_OR,
                 "decoding onionskin failed. "
                 "(Old key or bad software.) Closing.");
@@ -184,9 +205,12 @@ connection_cpu_process_inbuf(connection_t *conn)
       goto done_processing;
     }
     tor_assert(! CIRCUIT_IS_ORIGIN(circ));
-    if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
-                         TAP_ONIONSKIN_REPLY_LEN,
-                         buf+TAG_LEN+TAP_ONIONSKIN_REPLY_LEN) < 0) {
+    if (onionskin_answer(TO_OR_CIRCUIT(circ),
+                         rpl.created_cell.cell_type,
+                         (const char*)rpl.created_cell.reply,
+                         rpl.created_cell.handshake_len,
+                         (const char*)rpl.keys,
+                         rpl.rend_auth_material) < 0) {
       log_warn(LD_OR,"onionskin_answer failed. Closing.");
       circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
       goto done_processing;
@@ -213,32 +237,21 @@ connection_cpu_process_inbuf(connection_t *conn)
  * Read and writes from fdarray[1].  Reads requests, writes answers.
  *
  *   Request format:
- *          Task type           [1 byte, always CPUWORKER_TASK_ONION]
- *          Opaque tag          TAG_LEN
- *          Onionskin challenge TAP_ONIONSKIN_CHALLENGE_LEN
+ *          cpuworker_request_t.
  *   Response format:
- *          Success/failure     [1 byte, boolean.]
- *          Opaque tag          TAG_LEN
- *          Onionskin challenge TAP_ONIONSKIN_REPLY_LEN
- *          Negotiated keys     KEY_LEN*2+DIGEST_LEN*2
- *
- *  (Note: this _should_ be by addr/port, since we're concerned with specific
- * connections, not with routers (where we'd use identity).)
+ *          cpuworker_reply_t
  */
 static void
 cpuworker_main(void *data)
 {
-  char question[TAP_ONIONSKIN_CHALLENGE_LEN];
-  uint8_t question_type;
+  /* For talking to the parent thread/process */
   tor_socket_t *fdarray = data;
   tor_socket_t fd;
 
   /* variables for onion processing */
-  char keys[CPATH_KEY_MATERIAL_LEN];
-  char reply_to_proxy[MAX_ONIONSKIN_REPLY_LEN];
-  char buf[LEN_ONION_RESPONSE];
-  char tag[TAG_LEN];
   server_onion_keys_t onion_keys;
+  cpuworker_request_t req;
+  cpuworker_reply_t rpl;
 
   fd = fdarray[1]; /* this side is ours */
 #ifndef TOR_IS_MULTITHREADED
@@ -252,65 +265,64 @@ cpuworker_main(void *data)
   setup_server_onion_keys(&onion_keys);
 
   for (;;) {
-    ssize_t r;
-
-    if ((r = recv(fd, (void *)&question_type, 1, 0)) != 1) {
-//      log_fn(LOG_ERR,"read type failed. Exiting.");
-      if (r == 0) {
-        log_info(LD_OR,
-                 "CPU worker exiting because Tor process closed connection "
-                 "(either rotated keys or died).");
-      } else {
-        log_info(LD_OR,
-                 "CPU worker exiting because of error on connection to Tor "
-                 "process.");
-        log_info(LD_OR,"(Error on %d was %s)",
-                 fd, tor_socket_strerror(tor_socket_errno(fd)));
-      }
+    if (read_all(fd, (void *)&req, sizeof(req), 1) != sizeof(req)) {
+      log_info(LD_OR, "read request failed. Exiting.");
       goto end;
     }
-    tor_assert(question_type == CPUWORKER_TASK_ONION);
-
-    if (read_all(fd, tag, TAG_LEN, 1) != TAG_LEN) {
-      log_err(LD_BUG,"read tag failed. Exiting.");
-      goto end;
-    }
-
-    if (read_all(fd, question, TAP_ONIONSKIN_CHALLENGE_LEN, 1) !=
-        TAP_ONIONSKIN_CHALLENGE_LEN) {
-      log_err(LD_BUG,"read question failed. Exiting.");
-      goto end;
-    }
-
-    if (question_type == CPUWORKER_TASK_ONION) {
-      if (onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_TAP,
-                         (const uint8_t*)question,
-                         &onion_keys,
-                         (uint8_t*)reply_to_proxy,
-                         (uint8_t*)keys, CPATH_KEY_MATERIAL_LEN) < 0) {
+    tor_assert(req.magic == CPUWORKER_REQUEST_MAGIC);
+
+    memset(&rpl, 0, sizeof(rpl));
+
+    if (req.task == CPUWORKER_TASK_ONION) {
+      const create_cell_t *cc = &req.create_cell;
+      created_cell_t *cell_out = &rpl.created_cell;
+      int n;
+      n = onion_skin_server_handshake(cc->handshake_type,
+                                      cc->onionskin, cc->handshake_len,
+                                      &onion_keys,
+                                      cell_out->reply,
+                                      rpl.keys, CPATH_KEY_MATERIAL_LEN,
+                                      rpl.rend_auth_material);
+      if (n < 0) {
         /* failure */
         log_debug(LD_OR,"onion_skin_server_handshake failed.");
-        *buf = 0; /* indicate failure in first byte */
-        memcpy(buf+1,tag,TAG_LEN);
-        /* send all zeros as answer */
-        memset(buf+1+TAG_LEN, 0, LEN_ONION_RESPONSE-(1+TAG_LEN));
+        memset(&rpl, 0, sizeof(rpl));
+        memcpy(rpl.tag, req.tag, TAG_LEN);
+        rpl.success = 0;
       } else {
         /* success */
         log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
-        buf[0] = 1; /* 1 means success */
-        memcpy(buf+1,tag,TAG_LEN);
-        memcpy(buf+1+TAG_LEN,reply_to_proxy,TAP_ONIONSKIN_REPLY_LEN);
-        memcpy(buf+1+TAG_LEN+TAP_ONIONSKIN_REPLY_LEN,keys,
-               CPATH_KEY_MATERIAL_LEN);
+        memcpy(rpl.tag, req.tag, TAG_LEN);
+        cell_out->handshake_len = n;
+        switch (cc->cell_type) {
+        case CELL_CREATE:
+          cell_out->cell_type = CELL_CREATED; break;
+        case CELL_CREATE2:
+          cell_out->cell_type = CELL_CREATED2; break;
+        case CELL_CREATE_FAST:
+          cell_out->cell_type = CELL_CREATED_FAST; break;
+        default:
+          tor_assert(0);
+          goto end;
+        }
+        rpl.success = 1;
       }
-      if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) {
+      rpl.magic = CPUWORKER_REPLY_MAGIC;
+      if (write_all(fd, (void*)&rpl, sizeof(rpl), 1) != sizeof(rpl)) {
         log_err(LD_BUG,"writing response buf failed. Exiting.");
         goto end;
       }
       log_debug(LD_OR,"finished writing response.");
+    } else if (req.task == CPUWORKER_TASK_SHUTDOWN) {
+      log_info(LD_OR,"Clean shutdown: exiting");
+      goto end;
     }
+    memwipe(&req, 0, sizeof(req));
+    memwipe(&rpl, 0, sizeof(req));
   }
  end:
+  memwipe(&req, 0, sizeof(req));
+  memwipe(&rpl, 0, sizeof(req));
   release_server_onion_keys(&onion_keys);
   tor_close_socket(fd);
   crypto_thread_cleanup();
@@ -394,7 +406,7 @@ static void
 process_pending_task(connection_t *cpuworker)
 {
   or_circuit_t *circ;
-  char *onionskin = NULL;
+  create_cell_t *onionskin = NULL;
 
   tor_assert(cpuworker);
 
@@ -447,10 +459,10 @@ cull_wedged_cpuworkers(void)
  */
 int
 assign_onionskin_to_cpuworker(connection_t *cpuworker,
-                              or_circuit_t *circ, char *onionskin)
+                              or_circuit_t *circ,
+                              create_cell_t *onionskin)
 {
-  char qbuf[1];
-  char tag[TAG_LEN];
+  cpuworker_request_t req;
   time_t now = approx_time();
   static time_t last_culled_cpuworkers = 0;
 
@@ -486,7 +498,10 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker,
       tor_free(onionskin);
       return -1;
     }
-    tag_pack(tag, circ->p_chan->global_identifier,
+
+    memset(&req, 0, sizeof(req));
+    req.magic = CPUWORKER_REQUEST_MAGIC;
+    tag_pack(req.tag, circ->p_chan->global_identifier,
              circ->p_circ_id);
 
     cpuworker->state = CPUWORKER_STATE_BUSY_ONION;
@@ -496,11 +511,13 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker,
     cpuworker->timestamp_lastwritten = time(NULL);
     num_cpuworkers_busy++;
 
-    qbuf[0] = CPUWORKER_TASK_ONION;
-    connection_write_to_buf(qbuf, 1, cpuworker);
-    connection_write_to_buf(tag, sizeof(tag), cpuworker);
-    connection_write_to_buf(onionskin, TAP_ONIONSKIN_CHALLENGE_LEN, cpuworker);
+    req.task = CPUWORKER_TASK_ONION;
+    memcpy(&req.create_cell, onionskin, sizeof(create_cell_t));
+
     tor_free(onionskin);
+
+    connection_write_to_buf((void*)&req, sizeof(req), cpuworker);
+    memwipe(&req, 0, sizeof(req));
   }
   return 0;
 }
diff --git a/src/or/cpuworker.h b/src/or/cpuworker.h
index 73c7eef..f607e7d 100644
--- a/src/or/cpuworker.h
+++ b/src/or/cpuworker.h
@@ -17,9 +17,10 @@ void cpuworkers_rotate(void);
 int connection_cpu_finished_flushing(connection_t *conn);
 int connection_cpu_reached_eof(connection_t *conn);
 int connection_cpu_process_inbuf(connection_t *conn);
+struct create_cell_t;
 int assign_onionskin_to_cpuworker(connection_t *cpuworker,
                                   or_circuit_t *circ,
-                                  char *onionskin);
+                                  struct create_cell_t *onionskin);
 
 #endif
 
diff --git a/src/or/onion.c b/src/or/onion.c
index c1f2e5b..9326c2f 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -25,7 +25,7 @@
  * to process a waiting onion handshake. */
 typedef struct onion_queue_t {
   or_circuit_t *circ;
-  char *onionskin;
+  create_cell_t *onionskin;
   time_t when_added;
   struct onion_queue_t *next;
 } onion_queue_t;
@@ -48,7 +48,7 @@ static int ol_length=0;
  * if ol_list is too long, in which case do nothing and return -1.
  */
 int
-onion_pending_add(or_circuit_t *circ, char *onionskin)
+onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
 {
   onion_queue_t *tmp;
   time_t now = time(NULL);
@@ -105,7 +105,7 @@ onion_pending_add(or_circuit_t *circ, char *onionskin)
  * NULL if the list is empty.
  */
 or_circuit_t *
-onion_next_task(char **onionskin_out)
+onion_next_task(create_cell_t **onionskin_out)
 {
   or_circuit_t *circ;
 
@@ -302,37 +302,60 @@ onion_skin_create(int type,
  * using the keys in <b>keys</b>.  On success, write our response into
  * <b>reply_out</b>, generate <b>keys_out_len</b> bytes worth of key material
  * in <b>keys_out_len</b>, and return the length of the reply. On failure,
- * return -1.  */
+ * return -1.
+ * DOCDOC rend_nonce_out
+ */
 int
 onion_skin_server_handshake(int type,
-                      const uint8_t *onion_skin,
+                      const uint8_t *onion_skin, size_t onionskin_len,
                       const server_onion_keys_t *keys,
                       uint8_t *reply_out,
-                      uint8_t *keys_out, size_t keys_out_len)
+                      uint8_t *keys_out, size_t keys_out_len,
+                      uint8_t *rend_nonce_out)
 {
   int r = -1;
 
   switch (type) {
   case ONION_HANDSHAKE_TYPE_TAP:
+    if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN)
+      return -1;
     if (onion_skin_TAP_server_handshake((const char*)onion_skin,
                                         keys->onion_key, keys->last_onion_key,
                                         (char*)reply_out,
                                         (char*)keys_out, keys_out_len)<0)
       return -1;
     r = TAP_ONIONSKIN_REPLY_LEN;
+    memcpy(rend_nonce_out, reply_out+DH_KEY_LEN, DIGEST_LEN);
     break;
   case ONION_HANDSHAKE_TYPE_FAST:
+    if (onionskin_len != CREATE_FAST_LEN)
+      return -1;
     if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0)
       return -1;
     r = CREATED_FAST_LEN;
+    memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN);
     break;
   case ONION_HANDSHAKE_TYPE_NTOR:
 #ifdef CURVE25519_ENABLED
-    if (onion_skin_ntor_server_handshake(onion_skin, keys->curve25519_key_map,
-                                         keys->my_identity,
-                                         reply_out, keys_out, keys_out_len)<0)
+    if (onionskin_len != NTOR_ONIONSKIN_LEN)
       return -1;
-    r = NTOR_REPLY_LEN;
+    {
+      size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+      uint8_t *keys_tmp = tor_malloc(keys_out_len + DIGEST_LEN);
+
+      if (onion_skin_ntor_server_handshake(
+                                   onion_skin, keys->curve25519_key_map,
+                                   keys->my_identity,
+                                   reply_out, keys_tmp, keys_tmp_len)<0) {
+        tor_free(keys_tmp);
+        return -1;
+      }
+      memcpy(keys_out, keys_tmp, keys_out_len);
+      memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN);
+      memwipe(keys_tmp, 0, keys_tmp_len);
+      tor_free(keys_tmp);
+      r = NTOR_REPLY_LEN;
+    }
 #else
     return -1;
 #endif
@@ -343,12 +366,6 @@ onion_skin_server_handshake(int type,
     return -1;
   }
 
-  /* XXXX we should generate the rendezvous nonce stuff too.  Some notes
-   * below */
-    // memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN);
-
-    //memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN);
-
   return r;
 }
 
@@ -362,7 +379,7 @@ onion_skin_server_handshake(int type,
 int
 onion_skin_client_handshake(int type,
                       const onion_handshake_state_t *handshake_state,
-                      const uint8_t *reply,
+                      const uint8_t *reply, size_t reply_len,
                       uint8_t *keys_out, size_t keys_out_len,
                       uint8_t *rend_authenticator_out)
 {
@@ -371,6 +388,8 @@ onion_skin_client_handshake(int type,
 
   switch (type) {
   case ONION_HANDSHAKE_TYPE_TAP:
+    if (reply_len != TAP_ONIONSKIN_REPLY_LEN)
+      return -1;
     if (onion_skin_TAP_client_handshake(handshake_state->u.tap,
                                         (const char*)reply,
                                         (char *)keys_out, keys_out_len) < 0)
@@ -380,6 +399,8 @@ onion_skin_client_handshake(int type,
 
     return 0;
   case ONION_HANDSHAKE_TYPE_FAST:
+    if (reply_len != CREATED_FAST_LEN)
+      return -1;
     if (fast_client_handshake(handshake_state->u.fast, reply,
                               keys_out, keys_out_len) < 0)
       return -1;
@@ -388,6 +409,8 @@ onion_skin_client_handshake(int type,
     return 0;
 #ifdef CURVE25519_ENABLED
   case ONION_HANDSHAKE_TYPE_NTOR:
+    if (reply_len != NTOR_REPLY_LEN)
+      return -1;
     {
       size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
       uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
diff --git a/src/or/onion.h b/src/or/onion.h
index 08e1a22..36cb761 100644
--- a/src/or/onion.h
+++ b/src/or/onion.h
@@ -12,8 +12,9 @@
 #ifndef TOR_ONION_H
 #define TOR_ONION_H
 
-int onion_pending_add(or_circuit_t *circ, char *onionskin);
-or_circuit_t *onion_next_task(char **onionskin_out);
+struct create_cell_t;
+int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin);
+or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out);
 void onion_pending_remove(or_circuit_t *circ);
 void clear_pending_onions(void);
 
@@ -39,14 +40,14 @@ int onion_skin_create(int type,
                       onion_handshake_state_t *state_out,
                       uint8_t *onion_skin_out);
 int onion_skin_server_handshake(int type,
-                      const uint8_t *onion_skin,
+                      const uint8_t *onion_skin, size_t onionskin_len,
                       const server_onion_keys_t *keys,
                       uint8_t *reply_out,
-                      uint8_t *keys_out, size_t key_out_len);
-//                      uint8_t *rend_authenticator_out);
+                      uint8_t *keys_out, size_t key_out_len,
+                      uint8_t *rend_nonce_out);
 int onion_skin_client_handshake(int type,
                       const onion_handshake_state_t *handshake_state,
-                      const uint8_t *reply,
+                      const uint8_t *reply, size_t reply_len,
                       uint8_t *keys_out, size_t key_out_len,
                       uint8_t *rend_authenticator_out);
 
diff --git a/src/or/or.h b/src/or/or.h
index f9b0f1e..5ea420f 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -280,6 +280,7 @@ typedef enum {
 #define CPUWORKER_STATE_MAX_ 2
 
 #define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION
+#define CPUWORKER_TASK_SHUTDOWN 255
 
 #define OR_CONN_STATE_MIN_ 1
 /** State for a connection to an OR: waiting for connect() to finish. */
diff --git a/src/or/relay.c b/src/or/relay.c
index d862e58..d0c8c22 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -27,6 +27,7 @@
 #include "mempool.h"
 #include "networkstatus.h"
 #include "nodelist.h"
+#include "onion.h"
 #include "policies.h"
 #include "reasons.h"
 #include "relay.h"
@@ -1296,11 +1297,20 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
         return 0;
       }
       log_debug(domain,"Got an extended cell! Yay.");
-      if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
-                                       CELL_CREATED,
-                                       cell->payload+RELAY_HEADER_SIZE)) < 0) {
-        log_warn(domain,"circuit_finish_handshake failed.");
-        return reason;
+      {
+        extended_cell_t extended_cell;
+        if (extended_cell_parse(&extended_cell, rh.command,
+                        (const uint8_t*)cell->payload+RELAY_HEADER_SIZE,
+                        rh.length)<0) {
+          log_warn(LD_PROTOCOL,
+                   "Can't parse EXTENDED cell; killing circuit.");
+          return -END_CIRC_REASON_TORPROTOCOL;
+        }
+        if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
+                                         &extended_cell.created_cell)) < 0) {
+          log_warn(domain,"circuit_finish_handshake failed.");
+          return reason;
+        }
       }
       if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) {
         log_info(domain,"circuit_send_next_onion_skin() failed.");





More information about the tor-commits mailing list