浏览代码

Massive refactoring of the various handshake types

The three handshake types are now accessed from a unified interface;
their state is abstracted from the rest of the cpath state, and so on.
Nick Mathewson 13 年之前
父节点
当前提交
f58d4dfcd6
共有 17 个文件被更改,包括 462 次插入135 次删除
  1. 68 54
      src/or/circuitbuild.c
  2. 2 1
      src/or/circuitbuild.h
  3. 4 3
      src/or/circuitlist.c
  4. 6 4
      src/or/command.c
  5. 21 19
      src/or/cpuworker.c
  6. 241 2
      src/or/onion.c
  7. 33 0
      src/or/onion.h
  8. 2 0
      src/or/onion_ntor.h
  9. 15 11
      src/or/onion_tap.c
  10. 8 3
      src/or/onion_tap.h
  11. 27 13
      src/or/or.h
  12. 7 7
      src/or/rendclient.c
  13. 4 4
      src/or/rendservice.c
  14. 7 0
      src/or/router.c
  15. 1 0
      src/or/router.h
  16. 9 7
      src/test/bench.c
  17. 7 7
      src/test/test.c

+ 68 - 54
src/or/circuitbuild.c

@@ -27,6 +27,7 @@
 #include "main.h"
 #include "main.h"
 #include "networkstatus.h"
 #include "networkstatus.h"
 #include "nodelist.h"
 #include "nodelist.h"
+#include "onion.h"
 #include "onion_tap.h"
 #include "onion_tap.h"
 #include "onion_fast.h"
 #include "onion_fast.h"
 #include "policies.h"
 #include "policies.h"
@@ -54,7 +55,9 @@ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
                                                uint16_t port,
                                                uint16_t port,
                                                const char *id_digest);
                                                const char *id_digest);
 static int circuit_deliver_create_cell(circuit_t *circ,
 static int circuit_deliver_create_cell(circuit_t *circ,
-                                       uint8_t cell_type, const char *payload);
+                                       uint8_t cell_type,
+                                       const uint8_t *payload,
+                                       size_t payload_len);
 static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
 static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
 static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
 static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
 static int onion_extend_cpath(origin_circuit_t *circ);
 static int onion_extend_cpath(origin_circuit_t *circ);
@@ -474,7 +477,8 @@ circuit_n_chan_done(channel_t *chan, int status)
         /* pull the create cell out of circ->onionskin, and send it */
         /* pull the create cell out of circ->onionskin, and send it */
         tor_assert(circ->n_chan_onionskin);
         tor_assert(circ->n_chan_onionskin);
         if (circuit_deliver_create_cell(circ,CELL_CREATE,
         if (circuit_deliver_create_cell(circ,CELL_CREATE,
-                                        circ->n_chan_onionskin)<0) {
+                                        (const uint8_t*)circ->n_chan_onionskin,
+                                        circ->n_chan_onionskin_len)<0) {
           circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
           circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
           continue;
           continue;
         }
         }
@@ -491,12 +495,12 @@ circuit_n_chan_done(channel_t *chan, int status)
  * for the outgoing
  * for the outgoing
  * circuit <b>circ</b>, and deliver a cell of type <b>cell_type</b>
  * circuit <b>circ</b>, and deliver a cell of type <b>cell_type</b>
  * (either CELL_CREATE or CELL_CREATE_FAST) with payload <b>payload</b>
  * (either CELL_CREATE or CELL_CREATE_FAST) with payload <b>payload</b>
- * to this circuit.
+ * to this circuit. DOCDOC payload_len
  * Return -1 if we failed to find a suitable circid, else return 0.
  * Return -1 if we failed to find a suitable circid, else return 0.
  */
  */
 static int
 static int
 circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
 circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
-                            const char *payload)
+                            const uint8_t *payload, size_t payload_len)
 {
 {
   cell_t cell;
   cell_t cell;
   circid_t id;
   circid_t id;
@@ -518,7 +522,7 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
   cell.command = cell_type;
   cell.command = cell_type;
   cell.circ_id = circ->n_circ_id;
   cell.circ_id = circ->n_circ_id;
 
 
-  memcpy(cell.payload, payload, ONIONSKIN_CHALLENGE_LEN);
+  memcpy(cell.payload, payload, payload_len);
   append_cell_to_circuit_queue(circ, circ->n_chan, &cell,
   append_cell_to_circuit_queue(circ, circ->n_chan, &cell,
                                CELL_DIRECTION_OUT, 0);
                                CELL_DIRECTION_OUT, 0);
 
 
@@ -611,8 +615,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
 {
 {
   crypt_path_t *hop;
   crypt_path_t *hop;
   const node_t *node;
   const node_t *node;
-  char payload[2+4+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN];
-  char *onionskin;
+  uint8_t payload[2+4+DIGEST_LEN+MAX_ONIONSKIN_CHALLENGE_LEN];
+  uint8_t *onionskin;
+  uint16_t handshake_type;
+  int onionskin_len;
   size_t payload_len;
   size_t payload_len;
 
 
   tor_assert(circ);
   tor_assert(circ);
@@ -633,30 +639,29 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
        * send an old slow create cell.
        * send an old slow create cell.
        */
        */
       cell_type = CELL_CREATE;
       cell_type = CELL_CREATE;
-      if (onion_skin_create(circ->cpath->extend_info->onion_key,
-                            &(circ->cpath->dh_handshake_state),
-                            payload) < 0) {
-        log_warn(LD_CIRC,"onion_skin_create (first hop) failed.");
-        return - END_CIRC_REASON_INTERNAL;
-      }
+      handshake_type = ONION_HANDSHAKE_TYPE_TAP;
       note_request("cell: create", 1);
       note_request("cell: create", 1);
     } else {
     } else {
       /* We are not an OR, and we're building the first hop of a circuit to a
       /* We are not an OR, and we're building the first hop of a circuit to a
        * new OR: we can be speedy and use CREATE_FAST to save an RSA operation
        * new OR: we can be speedy and use CREATE_FAST to save an RSA operation
        * and a DH operation. */
        * and a DH operation. */
       cell_type = CELL_CREATE_FAST;
       cell_type = CELL_CREATE_FAST;
-
-      memset(payload, 0, sizeof(payload));
-      if (fast_onionskin_create(&circ->cpath->fast_handshake_state,
-                                (uint8_t *)payload) < 0) {
-        log_warn(LD_CIRC,"onion_skin_create FAST (first hop) failed.");
-        return - END_CIRC_REASON_INTERNAL;
-      }
-
+      handshake_type = ONION_HANDSHAKE_TYPE_FAST;
       note_request("cell: create fast", 1);
       note_request("cell: create fast", 1);
     }
     }
 
 
-    if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload) < 0)
+    memset(payload, 0, sizeof(payload));
+    onionskin_len = onion_skin_create(handshake_type,
+                                      circ->cpath->extend_info,
+                                      &circ->cpath->handshake_state,
+                                      payload);
+    if (onionskin_len < 0) {
+      log_warn(LD_CIRC,"onion_skin_create (first hop) failed.");
+      return - END_CIRC_REASON_INTERNAL;
+    }
+
+    if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload,
+                                    onionskin_len) < 0)
       return - END_CIRC_REASON_RESOURCELIMIT;
       return - END_CIRC_REASON_RESOURCELIMIT;
 
 
     circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
     circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
@@ -742,12 +747,16 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
     set_uint16(payload+4, htons(hop->extend_info->port));
     set_uint16(payload+4, htons(hop->extend_info->port));
 
 
     onionskin = payload+2+4;
     onionskin = payload+2+4;
-    memcpy(payload+2+4+ONIONSKIN_CHALLENGE_LEN,
+    memcpy(payload+2+4+TAP_ONIONSKIN_CHALLENGE_LEN,
            hop->extend_info->identity_digest, DIGEST_LEN);
            hop->extend_info->identity_digest, DIGEST_LEN);
-    payload_len = 2+4+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN;
+    payload_len = 2+4+TAP_ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN;
+
+    handshake_type = ONION_HANDSHAKE_TYPE_TAP;
 
 
-    if (onion_skin_create(hop->extend_info->onion_key,
-                          &(hop->dh_handshake_state), onionskin) < 0) {
+    if (onion_skin_create(handshake_type,
+                          hop->extend_info,
+                          &hop->handshake_state,
+                          onionskin) < 0) {
       log_warn(LD_CIRC,"onion_skin_create failed.");
       log_warn(LD_CIRC,"onion_skin_create failed.");
       return - END_CIRC_REASON_INTERNAL;
       return - END_CIRC_REASON_INTERNAL;
     }
     }
@@ -758,7 +767,8 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
      * it to a create cell and then send to hop */
      * it to a create cell and then send to hop */
     if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
     if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
                                      RELAY_COMMAND_EXTEND,
                                      RELAY_COMMAND_EXTEND,
-                                     payload, payload_len, hop->prev) < 0)
+                                     (char*)payload, payload_len,
+                                     hop->prev) < 0)
       return 0; /* circuit is closed */
       return 0; /* circuit is closed */
 
 
     hop->state = CPATH_STATE_AWAITING_KEYS;
     hop->state = CPATH_STATE_AWAITING_KEYS;
@@ -826,7 +836,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
 
 
   relay_header_unpack(&rh, cell->payload);
   relay_header_unpack(&rh, cell->payload);
 
 
-  if (rh.length < 4+2+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN) {
+  if (rh.length < 4+2+TAP_ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN) {
     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
            "Wrong length %d on extend cell. Closing circuit.",
            "Wrong length %d on extend cell. Closing circuit.",
            rh.length);
            rh.length);
@@ -837,7 +847,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
   n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4));
   n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4));
   onionskin = (char*) cell->payload+RELAY_HEADER_SIZE+4+2;
   onionskin = (char*) cell->payload+RELAY_HEADER_SIZE+4+2;
   id_digest = (char*) cell->payload+RELAY_HEADER_SIZE+4+2+
   id_digest = (char*) cell->payload+RELAY_HEADER_SIZE+4+2+
-    ONIONSKIN_CHALLENGE_LEN;
+    TAP_ONIONSKIN_CHALLENGE_LEN;
   tor_addr_from_ipv4h(&n_addr, n_addr32);
   tor_addr_from_ipv4h(&n_addr, n_addr32);
 
 
   if (!n_port || !n_addr32) {
   if (!n_port || !n_addr32) {
@@ -890,8 +900,10 @@ circuit_extend(cell_t *cell, circuit_t *circ)
                                     NULL /*onion_key*/,
                                     NULL /*onion_key*/,
                                     &n_addr, n_port);
                                     &n_addr, n_port);
 
 
-    circ->n_chan_onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
-    memcpy(circ->n_chan_onionskin, onionskin, ONIONSKIN_CHALLENGE_LEN);
+    circ->n_chan_onionskin = tor_malloc(TAP_ONIONSKIN_CHALLENGE_LEN);
+    memcpy(circ->n_chan_onionskin, onionskin, TAP_ONIONSKIN_CHALLENGE_LEN);
+    circ->n_chan_onionskin_len = TAP_ONIONSKIN_CHALLENGE_LEN;
+
     circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
     circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
 
 
     if (should_launch) {
     if (should_launch) {
@@ -917,7 +929,8 @@ circuit_extend(cell_t *cell, circuit_t *circ)
             "n_chan is %s",
             "n_chan is %s",
             channel_get_canonical_remote_descr(n_chan));
             channel_get_canonical_remote_descr(n_chan));
 
 
-  if (circuit_deliver_create_cell(circ, CELL_CREATE, onionskin) < 0)
+  if (circuit_deliver_create_cell(circ, CELL_CREATE, (uint8_t*)onionskin,
+                                  TAP_ONIONSKIN_CHALLENGE_LEN) < 0)
     return -1;
     return -1;
   return 0;
   return 0;
 }
 }
@@ -1377,31 +1390,32 @@ circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
   }
   }
   tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
   tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
 
 
-  if (reply_type == CELL_CREATED && hop->dh_handshake_state) {
-    if (onion_skin_client_handshake(hop->dh_handshake_state, (char*)reply,keys,
-                                    DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
-      log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
+  {
+    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;
       return -END_CIRC_REASON_TORPROTOCOL;
     }
     }
-    /* Remember hash of g^xy */
-    memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN);
-  } else if (reply_type == CELL_CREATED_FAST && !hop->dh_handshake_state) {
-    if (fast_client_handshake(hop->fast_handshake_state, reply,
-                              (uint8_t*)keys,
-                              DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
-      log_warn(LD_CIRC,"fast_client_handshake failed.");
+
+    if (onion_skin_client_handshake(handshake_type,
+                                    &hop->handshake_state,
+                                    reply,
+                                    (uint8_t*)keys, sizeof(keys),
+                                    (uint8_t*)hop->handshake_digest) < 0) {
+      log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
       return -END_CIRC_REASON_TORPROTOCOL;
       return -END_CIRC_REASON_TORPROTOCOL;
     }
     }
-    memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN);
-  } else {
-    log_warn(LD_PROTOCOL,"CREATED cell type did not match CREATE cell type.");
-    return -END_CIRC_REASON_TORPROTOCOL;
   }
   }
 
 
-  crypto_dh_free(hop->dh_handshake_state); /* don't need it anymore */
-  hop->dh_handshake_state = NULL;
-
-  memset(hop->fast_handshake_state, 0, sizeof(hop->fast_handshake_state));
+  onion_handshake_state_release(&hop->handshake_state);
 
 
   if (circuit_init_cpath_crypto(hop, keys, 0)<0) {
   if (circuit_init_cpath_crypto(hop, keys, 0)<0) {
     return -END_CIRC_REASON_TORPROTOCOL;
     return -END_CIRC_REASON_TORPROTOCOL;
@@ -1470,7 +1484,7 @@ circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason)
  */
  */
 int
 int
 onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
 onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
-                 const char *keys)
+                 size_t payload_len, const char *keys)
 {
 {
   cell_t cell;
   cell_t cell;
   crypt_path_t *tmp_cpath;
   crypt_path_t *tmp_cpath;
@@ -1484,8 +1498,7 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
 
 
   circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
   circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
 
 
-  memcpy(cell.payload, payload,
-         cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2);
+  memcpy(cell.payload, payload, payload_len);
 
 
   log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
   log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
             (unsigned int)get_uint32(keys),
             (unsigned int)get_uint32(keys),
@@ -1502,6 +1515,7 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
   tmp_cpath->magic = 0;
   tmp_cpath->magic = 0;
   tor_free(tmp_cpath);
   tor_free(tmp_cpath);
 
 
+  /* XXXX Move responsibility for extracting this. */
   if (cell_type == CELL_CREATED)
   if (cell_type == CELL_CREATED)
     memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN);
     memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN);
   else
   else

+ 2 - 1
src/or/circuitbuild.h

@@ -35,7 +35,8 @@ int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
 int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer,
 int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer,
                       int reason);
                       int reason);
 int onionskin_answer(or_circuit_t *circ, uint8_t cell_type,
 int onionskin_answer(or_circuit_t *circ, uint8_t cell_type,
-                     const char *payload, const char *keys);
+                     const char *payload, size_t payload_len,
+                     const char *keys);
 int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
 int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
                                         int *need_capacity);
                                         int *need_capacity);
 
 

+ 4 - 3
src/or/circuitlist.c

@@ -744,8 +744,8 @@ circuit_free_cpath_node(crypt_path_t *victim)
   crypto_cipher_free(victim->b_crypto);
   crypto_cipher_free(victim->b_crypto);
   crypto_digest_free(victim->f_digest);
   crypto_digest_free(victim->f_digest);
   crypto_digest_free(victim->b_digest);
   crypto_digest_free(victim->b_digest);
-  crypto_dh_free(victim->dh_handshake_state);
-  fast_handshake_state_free(victim->fast_handshake_state);
+  onion_handshake_state_release(&victim->handshake_state);
+  crypto_dh_free(victim->rend_dh_handshake_state);
   extend_info_free(victim->extend_info);
   extend_info_free(victim->extend_info);
 
 
   memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */
   memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */
@@ -1494,7 +1494,8 @@ assert_cpath_layer_ok(const crypt_path_t *cp)
       tor_assert(cp->b_crypto);
       tor_assert(cp->b_crypto);
       /* fall through */
       /* fall through */
     case CPATH_STATE_CLOSED:
     case CPATH_STATE_CLOSED:
-      tor_assert(!cp->dh_handshake_state);
+      /*XXXX Assert that there's no handshake_state either. */
+      tor_assert(!cp->rend_dh_handshake_state);
       break;
       break;
     case CPATH_STATE_AWAITING_KEYS:
     case CPATH_STATE_AWAITING_KEYS:
       /* tor_assert(cp->dh_handshake_state); */
       /* tor_assert(cp->dh_handshake_state); */

+ 6 - 4
src/or/command.c

@@ -30,6 +30,7 @@
 #include "hibernate.h"
 #include "hibernate.h"
 #include "nodelist.h"
 #include "nodelist.h"
 //#include "onion.h"
 //#include "onion.h"
+#include "onion_tap.h"
 #include "onion_fast.h"
 #include "onion_fast.h"
 #include "relay.h"
 #include "relay.h"
 #include "router.h"
 #include "router.h"
@@ -254,8 +255,8 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
   circ->base_.purpose = CIRCUIT_PURPOSE_OR;
   circ->base_.purpose = CIRCUIT_PURPOSE_OR;
   circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
   circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
   if (cell->command == CELL_CREATE) {
   if (cell->command == CELL_CREATE) {
-    char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
-    memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
+    char *onionskin = tor_malloc(TAP_ONIONSKIN_CHALLENGE_LEN);
+    memcpy(onionskin, cell->payload, TAP_ONIONSKIN_CHALLENGE_LEN);
 
 
     /* hand it off to the cpuworkers, and then return. */
     /* 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, onionskin) < 0) {
@@ -282,7 +283,8 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       return;
       return;
     }
     }
-    if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
+    if (onionskin_answer(circ, CELL_CREATED_FAST, reply, sizeof(reply),
+                         keys)<0) {
       log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
       log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       return;
       return;
@@ -340,7 +342,7 @@ command_process_created_cell(cell_t *cell, channel_t *chan)
     log_debug(LD_OR,
     log_debug(LD_OR,
               "Converting created cell to extended relay cell, sending.");
               "Converting created cell to extended relay cell, sending.");
     relay_send_command_from_edge(0, circ, RELAY_COMMAND_EXTENDED,
     relay_send_command_from_edge(0, circ, RELAY_COMMAND_EXTENDED,
-                                 (char*)cell->payload, ONIONSKIN_REPLY_LEN,
+                                 (char*)cell->payload, TAP_ONIONSKIN_REPLY_LEN,
                                  NULL);
                                  NULL);
   }
   }
 }
 }

+ 21 - 19
src/or/cpuworker.c

@@ -35,7 +35,7 @@
 #define TAG_LEN 10
 #define TAG_LEN 10
 /** How many bytes are sent from the cpuworker back to tor? */
 /** How many bytes are sent from the cpuworker back to tor? */
 #define LEN_ONION_RESPONSE \
 #define LEN_ONION_RESPONSE \
-  (1+TAG_LEN+ONIONSKIN_REPLY_LEN+CPATH_KEY_MATERIAL_LEN)
+  (1+TAG_LEN+TAP_ONIONSKIN_REPLY_LEN+CPATH_KEY_MATERIAL_LEN)
 
 
 /** How many cpuworkers we have running right now. */
 /** How many cpuworkers we have running right now. */
 static int num_cpuworkers=0;
 static int num_cpuworkers=0;
@@ -185,7 +185,8 @@ connection_cpu_process_inbuf(connection_t *conn)
     }
     }
     tor_assert(! CIRCUIT_IS_ORIGIN(circ));
     tor_assert(! CIRCUIT_IS_ORIGIN(circ));
     if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
     if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
-                         buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
+                         TAP_ONIONSKIN_REPLY_LEN,
+                         buf+TAG_LEN+TAP_ONIONSKIN_REPLY_LEN) < 0) {
       log_warn(LD_OR,"onionskin_answer failed. Closing.");
       log_warn(LD_OR,"onionskin_answer failed. Closing.");
       circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
       circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
       goto done_processing;
       goto done_processing;
@@ -214,11 +215,11 @@ connection_cpu_process_inbuf(connection_t *conn)
  *   Request format:
  *   Request format:
  *          Task type           [1 byte, always CPUWORKER_TASK_ONION]
  *          Task type           [1 byte, always CPUWORKER_TASK_ONION]
  *          Opaque tag          TAG_LEN
  *          Opaque tag          TAG_LEN
- *          Onionskin challenge ONIONSKIN_CHALLENGE_LEN
+ *          Onionskin challenge TAP_ONIONSKIN_CHALLENGE_LEN
  *   Response format:
  *   Response format:
  *          Success/failure     [1 byte, boolean.]
  *          Success/failure     [1 byte, boolean.]
  *          Opaque tag          TAG_LEN
  *          Opaque tag          TAG_LEN
- *          Onionskin challenge ONIONSKIN_REPLY_LEN
+ *          Onionskin challenge TAP_ONIONSKIN_REPLY_LEN
  *          Negotiated keys     KEY_LEN*2+DIGEST_LEN*2
  *          Negotiated keys     KEY_LEN*2+DIGEST_LEN*2
  *
  *
  *  (Note: this _should_ be by addr/port, since we're concerned with specific
  *  (Note: this _should_ be by addr/port, since we're concerned with specific
@@ -227,17 +228,17 @@ connection_cpu_process_inbuf(connection_t *conn)
 static void
 static void
 cpuworker_main(void *data)
 cpuworker_main(void *data)
 {
 {
-  char question[ONIONSKIN_CHALLENGE_LEN];
+  char question[TAP_ONIONSKIN_CHALLENGE_LEN];
   uint8_t question_type;
   uint8_t question_type;
   tor_socket_t *fdarray = data;
   tor_socket_t *fdarray = data;
   tor_socket_t fd;
   tor_socket_t fd;
 
 
   /* variables for onion processing */
   /* variables for onion processing */
   char keys[CPATH_KEY_MATERIAL_LEN];
   char keys[CPATH_KEY_MATERIAL_LEN];
-  char reply_to_proxy[ONIONSKIN_REPLY_LEN];
+  char reply_to_proxy[MAX_ONIONSKIN_REPLY_LEN];
   char buf[LEN_ONION_RESPONSE];
   char buf[LEN_ONION_RESPONSE];
   char tag[TAG_LEN];
   char tag[TAG_LEN];
-  crypto_pk_t *onion_key = NULL, *last_onion_key = NULL;
+  server_onion_keys_t onion_keys;
 
 
   fd = fdarray[1]; /* this side is ours */
   fd = fdarray[1]; /* this side is ours */
 #ifndef TOR_IS_MULTITHREADED
 #ifndef TOR_IS_MULTITHREADED
@@ -248,7 +249,7 @@ cpuworker_main(void *data)
 #endif
 #endif
   tor_free(data);
   tor_free(data);
 
 
-  dup_onion_keys(&onion_key, &last_onion_key);
+  setup_server_onion_keys(&onion_keys);
 
 
   for (;;) {
   for (;;) {
     ssize_t r;
     ssize_t r;
@@ -275,15 +276,18 @@ cpuworker_main(void *data)
       goto end;
       goto end;
     }
     }
 
 
-    if (read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) !=
-        ONIONSKIN_CHALLENGE_LEN) {
+    if (read_all(fd, question, TAP_ONIONSKIN_CHALLENGE_LEN, 1) !=
+        TAP_ONIONSKIN_CHALLENGE_LEN) {
       log_err(LD_BUG,"read question failed. Exiting.");
       log_err(LD_BUG,"read question failed. Exiting.");
       goto end;
       goto end;
     }
     }
 
 
     if (question_type == CPUWORKER_TASK_ONION) {
     if (question_type == CPUWORKER_TASK_ONION) {
-      if (onion_skin_server_handshake(question, onion_key, last_onion_key,
-          reply_to_proxy, keys, CPATH_KEY_MATERIAL_LEN) < 0) {
+      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) {
         /* failure */
         /* failure */
         log_debug(LD_OR,"onion_skin_server_handshake failed.");
         log_debug(LD_OR,"onion_skin_server_handshake failed.");
         *buf = 0; /* indicate failure in first byte */
         *buf = 0; /* indicate failure in first byte */
@@ -295,8 +299,9 @@ cpuworker_main(void *data)
         log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
         log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
         buf[0] = 1; /* 1 means success */
         buf[0] = 1; /* 1 means success */
         memcpy(buf+1,tag,TAG_LEN);
         memcpy(buf+1,tag,TAG_LEN);
-        memcpy(buf+1+TAG_LEN,reply_to_proxy,ONIONSKIN_REPLY_LEN);
-        memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,CPATH_KEY_MATERIAL_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);
       }
       }
       if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) {
       if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) {
         log_err(LD_BUG,"writing response buf failed. Exiting.");
         log_err(LD_BUG,"writing response buf failed. Exiting.");
@@ -306,10 +311,7 @@ cpuworker_main(void *data)
     }
     }
   }
   }
  end:
  end:
-  if (onion_key)
-    crypto_pk_free(onion_key);
-  if (last_onion_key)
-    crypto_pk_free(last_onion_key);
+  release_server_onion_keys(&onion_keys);
   tor_close_socket(fd);
   tor_close_socket(fd);
   crypto_thread_cleanup();
   crypto_thread_cleanup();
   spawn_exit();
   spawn_exit();
@@ -497,7 +499,7 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker,
     qbuf[0] = CPUWORKER_TASK_ONION;
     qbuf[0] = CPUWORKER_TASK_ONION;
     connection_write_to_buf(qbuf, 1, cpuworker);
     connection_write_to_buf(qbuf, 1, cpuworker);
     connection_write_to_buf(tag, sizeof(tag), cpuworker);
     connection_write_to_buf(tag, sizeof(tag), cpuworker);
-    connection_write_to_buf(onionskin, ONIONSKIN_CHALLENGE_LEN, cpuworker);
+    connection_write_to_buf(onionskin, TAP_ONIONSKIN_CHALLENGE_LEN, cpuworker);
     tor_free(onionskin);
     tor_free(onionskin);
   }
   }
   return 0;
   return 0;

+ 241 - 2
src/or/onion.c

@@ -6,15 +6,19 @@
 
 
 /**
 /**
  * \file onion.c
  * \file onion.c
- * \brief Functions to queue create cells, and handle onionskin
- * parsing and creation.
+ * \brief Functions to queue create cells, handle onionskin
+ * parsing and creation, and wrap the various onionskin types.
  **/
  **/
 
 
 #include "or.h"
 #include "or.h"
 #include "circuitlist.h"
 #include "circuitlist.h"
 #include "config.h"
 #include "config.h"
 #include "onion.h"
 #include "onion.h"
+#include "onion_fast.h"
+#include "onion_ntor.h"
+#include "onion_tap.h"
 #include "rephist.h"
 #include "rephist.h"
+#include "router.h"
 
 
 /** Type for a linked list of circuits that are waiting for a free CPU worker
 /** Type for a linked list of circuits that are waiting for a free CPU worker
  * to process a waiting onion handshake. */
  * to process a waiting onion handshake. */
@@ -37,6 +41,8 @@ static onion_queue_t *ol_tail=NULL;
 /** Length of ol_list */
 /** Length of ol_list */
 static int ol_length=0;
 static int ol_length=0;
 
 
+/* XXXX Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN */
+
 /** Add <b>circ</b> to the end of ol_list and return 0, except
 /** Add <b>circ</b> to the end of ol_list and return 0, except
  * if ol_list is too long, in which case do nothing and return -1.
  * if ol_list is too long, in which case do nothing and return -1.
  */
  */
@@ -171,3 +177,236 @@ clear_pending_onions(void)
   ol_length = 0;
   ol_length = 0;
 }
 }
 
 
+/* ============================================================ */
+
+/** Fill in a server_onion_keys_t object at <b>keys</b> with all of the keys
+ * and other info we might need to do onion handshakes.  (We make a copy of
+ * our keys for each cpuworker to avoid race conditions with the main thread,
+ * and to avoid locking) */
+void
+setup_server_onion_keys(server_onion_keys_t *keys)
+{
+  memset(keys, 0, sizeof(server_onion_keys_t));
+  memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN);
+  dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
+#ifdef CURVE25519_ENABLED
+  keys->curve25519_key_map = construct_ntor_key_map();
+#endif
+}
+
+/** Release all storage held in <b>keys</b>, but do not free <b>keys</b>
+ * itself (as it's likely to be stack-allocated.) */
+void
+release_server_onion_keys(server_onion_keys_t *keys)
+{
+  if (! keys)
+    return;
+
+  crypto_pk_free(keys->onion_key);
+  crypto_pk_free(keys->last_onion_key);
+#ifdef CURVE25519_ENABLED
+  ntor_key_map_free(keys->curve25519_key_map);
+#endif
+  memset(keys, 0, sizeof(server_onion_keys_t));
+}
+
+/** Release whatever storage is held in <b>state</b>, depending on its
+ * type, and clear its pointer. */
+void
+onion_handshake_state_release(onion_handshake_state_t *state)
+{
+  switch (state->tag) {
+  case ONION_HANDSHAKE_TYPE_TAP:
+    crypto_dh_free(state->u.tap);
+    state->u.tap = NULL;
+    break;
+  case ONION_HANDSHAKE_TYPE_FAST:
+    fast_handshake_state_free(state->u.fast);
+    state->u.fast = NULL;
+    break;
+#ifdef CURVE25519_ENABLED
+  case ONION_HANDSHAKE_TYPE_NTOR:
+    ntor_handshake_state_free(state->u.ntor);
+    state->u.ntor = NULL;
+    break;
+#endif
+  default:
+    log_warn(LD_BUG, "called with unknown handshake state type %d",
+             (int)state->tag);
+    tor_fragile_assert();
+  }
+}
+
+/** Perform the first step of a circuit-creation handshake of type <b>type</b>
+ * (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in
+ * <b>onion_skin_out</b>, and store any state information in <b>state_out</b>.
+ * Return -1 on failure, and the length of the onionskin on acceptance.
+ */
+int
+onion_skin_create(int type,
+                  const extend_info_t *node,
+                  onion_handshake_state_t *state_out,
+                  uint8_t *onion_skin_out)
+{
+  int r = -1;
+
+  switch (type) {
+  case ONION_HANDSHAKE_TYPE_TAP:
+    if (!node->onion_key)
+      return -1;
+
+    if (onion_skin_TAP_create(node->onion_key,
+                              &state_out->u.tap,
+                              (char*)onion_skin_out) < 0)
+      return -1;
+
+    r = TAP_ONIONSKIN_CHALLENGE_LEN;
+    break;
+  case ONION_HANDSHAKE_TYPE_FAST:
+    if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0)
+      return -1;
+
+    r = CREATE_FAST_LEN;
+    break;
+  case ONION_HANDSHAKE_TYPE_NTOR:
+#ifdef CURVE25519_ENABLED
+    if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key,
+                        CURVE25519_PUBKEY_LEN))
+      return -1;
+    if (onion_skin_ntor_create((const uint8_t*)node->identity_digest,
+                               &node->curve25519_onion_key,
+                               &state_out->u.ntor,
+                               onion_skin_out) < 0)
+      return -1;
+
+    r = NTOR_ONIONSKIN_LEN;
+#else
+    return -1;
+#endif
+    break;
+  default:
+    log_warn(LD_BUG, "called with unknown handshake state type %d", type);
+    tor_fragile_assert();
+    r = -1;
+  }
+
+  if (r > 0)
+    state_out->tag = (uint16_t) type;
+
+  return r;
+}
+
+/** Perform the second (server-side) step of a circuit-creation handshake of
+ * type <b>type</b>, responding to the client request in <b>onion_skin</b>
+ * 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.  */
+int
+onion_skin_server_handshake(int type,
+                      const uint8_t *onion_skin,
+                      const server_onion_keys_t *keys,
+                      uint8_t *reply_out,
+                      uint8_t *keys_out, size_t keys_out_len)
+{
+  int r = -1;
+
+  switch (type) {
+  case ONION_HANDSHAKE_TYPE_TAP:
+    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;
+    break;
+  case ONION_HANDSHAKE_TYPE_FAST:
+    if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0)
+      return -1;
+    r = CREATED_FAST_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)
+      return -1;
+    r = NTOR_REPLY_LEN;
+#else
+    return -1;
+#endif
+    break;
+  default:
+    log_warn(LD_BUG, "called with unknown handshake state type %d", type);
+    tor_fragile_assert();
+    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;
+}
+
+/** Perform the final (client-side) step of a circuit-creation handshake of
+ * type <b>type</b>, using our state in <b>handshake_state</b> and the
+ * server's response in <b>reply</b> On success, generate <b>keys_out_len</b>
+ * bytes worth of key material in <b>keys_out_len</b>, set
+ * <b>rend_authenticator_out</b> to the "KH" field that can be used to
+ * establish introduction points at this hop, and return 0.  On failure,
+ * return -1. */
+int
+onion_skin_client_handshake(int type,
+                      const onion_handshake_state_t *handshake_state,
+                      const uint8_t *reply,
+                      uint8_t *keys_out, size_t keys_out_len,
+                      uint8_t *rend_authenticator_out)
+{
+  if (handshake_state->tag != type)
+    return -1;
+
+  switch (type) {
+  case ONION_HANDSHAKE_TYPE_TAP:
+    if (onion_skin_TAP_client_handshake(handshake_state->u.tap,
+                                        (const char*)reply,
+                                        (char *)keys_out, keys_out_len) < 0)
+      return -1;
+
+    memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN);
+
+    return 0;
+  case ONION_HANDSHAKE_TYPE_FAST:
+    if (fast_client_handshake(handshake_state->u.fast, reply,
+                              keys_out, keys_out_len) < 0)
+      return -1;
+
+    memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN);
+    return 0;
+#ifdef CURVE25519_ENABLED
+  case ONION_HANDSHAKE_TYPE_NTOR:
+    {
+      size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+      uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
+      if (onion_skin_ntor_client_handshake(handshake_state->u.ntor,
+                                           reply,
+                                           keys_tmp, keys_tmp_len) < 0) {
+        tor_free(keys_tmp);
+        return -1;
+      }
+      memcpy(keys_out, keys_tmp, keys_out_len);
+      memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN);
+      memwipe(keys_tmp, 0, keys_tmp_len);
+      tor_free(keys_tmp);
+    }
+    return 0;
+#endif
+  default:
+    log_warn(LD_BUG, "called with unknown handshake state type %d", type);
+    tor_fragile_assert();
+    return -1;
+  }
+}
+

+ 33 - 0
src/or/onion.h

@@ -17,5 +17,38 @@ or_circuit_t *onion_next_task(char **onionskin_out);
 void onion_pending_remove(or_circuit_t *circ);
 void onion_pending_remove(or_circuit_t *circ);
 void clear_pending_onions(void);
 void clear_pending_onions(void);
 
 
+typedef struct server_onion_keys_t {
+  uint8_t my_identity[DIGEST_LEN];
+  crypto_pk_t *onion_key;
+  crypto_pk_t *last_onion_key;
+#ifdef CURVE25519_ENABLED
+  di_digest256_map_t *curve25519_key_map;
+#endif
+} server_onion_keys_t;
+
+#define MAX_ONIONSKIN_CHALLENGE_LEN 255
+#define MAX_ONIONSKIN_REPLY_LEN 255
+
+void setup_server_onion_keys(server_onion_keys_t *keys);
+void release_server_onion_keys(server_onion_keys_t *keys);
+
+void onion_handshake_state_release(onion_handshake_state_t *state);
+
+int onion_skin_create(int type,
+                      const extend_info_t *node,
+                      onion_handshake_state_t *state_out,
+                      uint8_t *onion_skin_out);
+int onion_skin_server_handshake(int type,
+                      const uint8_t *onion_skin,
+                      const server_onion_keys_t *keys,
+                      uint8_t *reply_out,
+                      uint8_t *keys_out, size_t key_out_len);
+//                      uint8_t *rend_authenticator_out);
+int onion_skin_client_handshake(int type,
+                      const onion_handshake_state_t *handshake_state,
+                      const uint8_t *reply,
+                      uint8_t *keys_out, size_t key_out_len,
+                      uint8_t *rend_authenticator_out);
+
 #endif
 #endif
 
 

+ 2 - 0
src/or/onion_ntor.h

@@ -17,6 +17,7 @@ typedef struct ntor_handshake_state_t ntor_handshake_state_t;
 /** Length of an ntor reply, as sent from server to client. */
 /** Length of an ntor reply, as sent from server to client. */
 #define NTOR_REPLY_LEN 64
 #define NTOR_REPLY_LEN 64
 
 
+#ifdef CURVE25519_ENABLED
 void ntor_handshake_state_free(ntor_handshake_state_t *state);
 void ntor_handshake_state_free(ntor_handshake_state_t *state);
 
 
 int onion_skin_ntor_create(const uint8_t *router_id,
 int onion_skin_ntor_create(const uint8_t *router_id,
@@ -36,6 +37,7 @@ int onion_skin_ntor_client_handshake(
                              const uint8_t *handshake_reply,
                              const uint8_t *handshake_reply,
                              uint8_t *key_out,
                              uint8_t *key_out,
                              size_t key_out_len);
                              size_t key_out_len);
+#endif
 
 
 #endif
 #endif
 
 

+ 15 - 11
src/or/onion_tap.c

@@ -35,9 +35,9 @@
  * The meeting point/cookies and auth are zeroed out for now.
  * The meeting point/cookies and auth are zeroed out for now.
  */
  */
 int
 int
-onion_skin_create(crypto_pk_t *dest_router_key,
+onion_skin_TAP_create(crypto_pk_t *dest_router_key,
                   crypto_dh_t **handshake_state_out,
                   crypto_dh_t **handshake_state_out,
-                  char *onion_skin_out) /* ONIONSKIN_CHALLENGE_LEN bytes */
+                  char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
 {
 {
   char challenge[DH_KEY_LEN];
   char challenge[DH_KEY_LEN];
   crypto_dh_t *dh = NULL;
   crypto_dh_t *dh = NULL;
@@ -47,7 +47,7 @@ onion_skin_create(crypto_pk_t *dest_router_key,
   tor_assert(handshake_state_out);
   tor_assert(handshake_state_out);
   tor_assert(onion_skin_out);
   tor_assert(onion_skin_out);
   *handshake_state_out = NULL;
   *handshake_state_out = NULL;
-  memset(onion_skin_out, 0, ONIONSKIN_CHALLENGE_LEN);
+  memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
 
 
   if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
   if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
     goto err;
     goto err;
@@ -64,7 +64,7 @@ onion_skin_create(crypto_pk_t *dest_router_key,
 
 
   /* set meeting point, meeting cookie, etc here. Leave zero for now. */
   /* set meeting point, meeting cookie, etc here. Leave zero for now. */
   if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out,
   if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out,
-                                      ONIONSKIN_CHALLENGE_LEN,
+                                      TAP_ONIONSKIN_CHALLENGE_LEN,
                                       challenge, DH_KEY_LEN,
                                       challenge, DH_KEY_LEN,
                                       PK_PKCS1_OAEP_PADDING, 1)<0)
                                       PK_PKCS1_OAEP_PADDING, 1)<0)
     goto err;
     goto err;
@@ -85,14 +85,17 @@ onion_skin_create(crypto_pk_t *dest_router_key,
  * next key_out_len bytes of key material in key_out.
  * next key_out_len bytes of key material in key_out.
  */
  */
 int
 int
-onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/
+onion_skin_TAP_server_handshake(
+                            /*TAP_ONIONSKIN_CHALLENGE_LEN*/
+                            const char *onion_skin,
                             crypto_pk_t *private_key,
                             crypto_pk_t *private_key,
                             crypto_pk_t *prev_private_key,
                             crypto_pk_t *prev_private_key,
-                            char *handshake_reply_out, /*ONIONSKIN_REPLY_LEN*/
+                            /*TAP_ONIONSKIN_REPLY_LEN*/
+                            char *handshake_reply_out,
                             char *key_out,
                             char *key_out,
                             size_t key_out_len)
                             size_t key_out_len)
 {
 {
-  char challenge[ONIONSKIN_CHALLENGE_LEN];
+  char challenge[TAP_ONIONSKIN_CHALLENGE_LEN];
   crypto_dh_t *dh = NULL;
   crypto_dh_t *dh = NULL;
   ssize_t len;
   ssize_t len;
   char *key_material=NULL;
   char *key_material=NULL;
@@ -107,8 +110,9 @@ onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/
       break;
       break;
     note_crypto_pk_op(DEC_ONIONSKIN);
     note_crypto_pk_op(DEC_ONIONSKIN);
     len = crypto_pk_private_hybrid_decrypt(k, challenge,
     len = crypto_pk_private_hybrid_decrypt(k, challenge,
-                                           ONIONSKIN_CHALLENGE_LEN,
-                                           onion_skin, ONIONSKIN_CHALLENGE_LEN,
+                                           TAP_ONIONSKIN_CHALLENGE_LEN,
+                                           onion_skin,
+                                           TAP_ONIONSKIN_CHALLENGE_LEN,
                                            PK_PKCS1_OAEP_PADDING,0);
                                            PK_PKCS1_OAEP_PADDING,0);
     if (len>0)
     if (len>0)
       break;
       break;
@@ -175,8 +179,8 @@ onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/
  * After the invocation, call crypto_dh_free on handshake_state.
  * After the invocation, call crypto_dh_free on handshake_state.
  */
  */
 int
 int
-onion_skin_client_handshake(crypto_dh_t *handshake_state,
-            const char *handshake_reply, /* ONIONSKIN_REPLY_LEN bytes */
+onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
+            const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */
             char *key_out,
             char *key_out,
             size_t key_out_len)
             size_t key_out_len)
 {
 {

+ 8 - 3
src/or/onion_tap.h

@@ -12,18 +12,23 @@
 #ifndef TOR_ONION_TAP_H
 #ifndef TOR_ONION_TAP_H
 #define TOR_ONION_TAP_H
 #define TOR_ONION_TAP_H
 
 
-int onion_skin_create(crypto_pk_t *router_key,
+#define TAP_ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\
+                                 CIPHER_KEY_LEN+\
+                                 DH_KEY_LEN)
+#define TAP_ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN)
+
+int onion_skin_TAP_create(crypto_pk_t *router_key,
                       crypto_dh_t **handshake_state_out,
                       crypto_dh_t **handshake_state_out,
                       char *onion_skin_out);
                       char *onion_skin_out);
 
 
-int onion_skin_server_handshake(const char *onion_skin,
+int onion_skin_TAP_server_handshake(const char *onion_skin,
                                 crypto_pk_t *private_key,
                                 crypto_pk_t *private_key,
                                 crypto_pk_t *prev_private_key,
                                 crypto_pk_t *prev_private_key,
                                 char *handshake_reply_out,
                                 char *handshake_reply_out,
                                 char *key_out,
                                 char *key_out,
                                 size_t key_out_len);
                                 size_t key_out_len);
 
 
-int onion_skin_client_handshake(crypto_dh_t *handshake_state,
+int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
                                 const char *handshake_reply,
                                 const char *handshake_reply,
                                 char *key_out,
                                 char *key_out,
                                 size_t key_out_len);
                                 size_t key_out_len);

+ 27 - 13
src/or/or.h

@@ -1381,6 +1381,7 @@ typedef struct or_connection_t {
 
 
   or_handshake_state_t *handshake_state; /**< If we are setting this connection
   or_handshake_state_t *handshake_state; /**< If we are setting this connection
                                           * up, state information to do so. */
                                           * up, state information to do so. */
+
   time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/
   time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/
   time_t timestamp_last_added_nonpadding; /** When did we last add a
   time_t timestamp_last_added_nonpadding; /** When did we last add a
                                            * non-padding cell to the outbuf? */
                                            * non-padding cell to the outbuf? */
@@ -2470,6 +2471,9 @@ typedef struct extend_info_t {
   uint16_t port; /**< OR port. */
   uint16_t port; /**< OR port. */
   tor_addr_t addr; /**< IP address. */
   tor_addr_t addr; /**< IP address. */
   crypto_pk_t *onion_key; /**< Current onionskin key. */
   crypto_pk_t *onion_key; /**< Current onionskin key. */
+#ifdef CURVE25519_ENABLED
+  curve25519_public_key_t curve25519_onion_key;
+#endif
 } extend_info_t;
 } extend_info_t;
 
 
 /** Certificate for v3 directory protocol: binds long-term authority identity
 /** Certificate for v3 directory protocol: binds long-term authority identity
@@ -2525,6 +2529,19 @@ typedef enum {
 #define CRYPT_PATH_MAGIC 0x70127012u
 #define CRYPT_PATH_MAGIC 0x70127012u
 
 
 struct fast_handshake_state_t;
 struct fast_handshake_state_t;
+struct ntor_handshake_state_t;
+#define ONION_HANDSHAKE_TYPE_TAP 0x0000
+#define ONION_HANDSHAKE_TYPE_FAST 0x0001
+#define ONION_HANDSHAKE_TYPE_NTOR 0x0002
+typedef struct {
+  uint16_t tag;
+  union {
+    struct fast_handshake_state_t *fast;
+    crypto_dh_t *tap;
+    struct ntor_handshake_state_t *ntor;
+  } u;
+} onion_handshake_state_t;
+
 /** Holds accounting information for a single step in the layered encryption
 /** Holds accounting information for a single step in the layered encryption
  * performed by a circuit.  Used only at the client edge of a circuit. */
  * performed by a circuit.  Used only at the client edge of a circuit. */
 typedef struct crypt_path_t {
 typedef struct crypt_path_t {
@@ -2543,16 +2560,15 @@ typedef struct crypt_path_t {
   /** Digest state for cells heading away from the OR at this step. */
   /** Digest state for cells heading away from the OR at this step. */
   crypto_digest_t *b_digest;
   crypto_digest_t *b_digest;
 
 
-  /** Current state of Diffie-Hellman key negotiation with the OR at this
+  /** Current state of the handshake as performed with the OR at this
    * step. */
    * step. */
-  crypto_dh_t *dh_handshake_state;
-  /** Current state of 'fast' (non-PK) key negotiation with the OR at this
-   * step. Used to save CPU when TLS is already providing all the
-   * authentication, secrecy, and integrity we need, and we're already
-   * distinguishable from an OR.
-   */
-  struct fast_handshake_state_t *fast_handshake_state;
+  onion_handshake_state_t handshake_state;
+  /** Diffie-hellman handshake state for performing an introduction
+   * operations */
+  crypto_dh_t *rend_dh_handshake_state;
+
   /** Negotiated key material shared with the OR at this step. */
   /** Negotiated key material shared with the OR at this step. */
+  /* XXXX RENAME */
   char handshake_digest[DIGEST_LEN];/* KH in tor-spec.txt */
   char handshake_digest[DIGEST_LEN];/* KH in tor-spec.txt */
 
 
   /** Information to extend to the OR at this step. */
   /** Information to extend to the OR at this step. */
@@ -2594,10 +2610,6 @@ typedef struct {
 #define CPATH_KEY_MATERIAL_LEN (20*2+16*2)
 #define CPATH_KEY_MATERIAL_LEN (20*2+16*2)
 
 
 #define DH_KEY_LEN DH_BYTES
 #define DH_KEY_LEN DH_BYTES
-#define ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\
-                                 CIPHER_KEY_LEN+\
-                                 DH_KEY_LEN)
-#define ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN)
 
 
 /** Information used to build a circuit. */
 /** Information used to build a circuit. */
 typedef struct {
 typedef struct {
@@ -2703,9 +2715,10 @@ typedef struct circuit_t {
    * more. */
    * more. */
   int deliver_window;
   int deliver_window;
 
 
+  uint8_t n_chan_onionskin_len; /* XXXX MAKE THIS GET USED. */
   /** For storage while n_chan is pending
   /** For storage while n_chan is pending
     * (state CIRCUIT_STATE_CHAN_WAIT). When defined, it is always
     * (state CIRCUIT_STATE_CHAN_WAIT). When defined, it is always
-    * length ONIONSKIN_CHALLENGE_LEN. */
+    * length n_chan_onionskin_len */
   char *n_chan_onionskin;
   char *n_chan_onionskin;
 
 
   /** When was this circuit created?  We keep this timestamp with a higher
   /** When was this circuit created?  We keep this timestamp with a higher
@@ -2965,6 +2978,7 @@ typedef struct or_circuit_t {
   char rend_token[REND_TOKEN_LEN];
   char rend_token[REND_TOKEN_LEN];
 
 
   /* ???? move to a subtype or adjunct structure? Wastes 20 bytes -NM */
   /* ???? move to a subtype or adjunct structure? Wastes 20 bytes -NM */
+  /* XXXX rename this. */
   char handshake_digest[DIGEST_LEN]; /**< Stores KH for the handshake. */
   char handshake_digest[DIGEST_LEN]; /**< Stores KH for the handshake. */
 
 
   /** How many more relay_early cells can we send on this circuit, according
   /** How many more relay_early cells can we send on this circuit, according

+ 7 - 7
src/or/rendclient.c

@@ -206,12 +206,12 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
     cpath = rendcirc->build_state->pending_final_cpath =
     cpath = rendcirc->build_state->pending_final_cpath =
       tor_malloc_zero(sizeof(crypt_path_t));
       tor_malloc_zero(sizeof(crypt_path_t));
     cpath->magic = CRYPT_PATH_MAGIC;
     cpath->magic = CRYPT_PATH_MAGIC;
-    if (!(cpath->dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
+    if (!(cpath->rend_dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
       log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
       log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
       status = -2;
       status = -2;
       goto perm_err;
       goto perm_err;
     }
     }
-    if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) {
+    if (crypto_dh_generate_public(cpath->rend_dh_handshake_state)<0) {
       log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
       log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
       status = -2;
       status = -2;
       goto perm_err;
       goto perm_err;
@@ -261,7 +261,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
     dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
     dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
   }
   }
 
 
-  if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset,
+  if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset,
                            DH_KEY_LEN)<0) {
                            DH_KEY_LEN)<0) {
     log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
     log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
     status = -2;
     status = -2;
@@ -896,9 +896,9 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
   tor_assert(circ->build_state);
   tor_assert(circ->build_state);
   tor_assert(circ->build_state->pending_final_cpath);
   tor_assert(circ->build_state->pending_final_cpath);
   hop = circ->build_state->pending_final_cpath;
   hop = circ->build_state->pending_final_cpath;
-  tor_assert(hop->dh_handshake_state);
+  tor_assert(hop->rend_dh_handshake_state);
   if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN,
   if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN,
-                               hop->dh_handshake_state, (char*)request,
+                               hop->rend_dh_handshake_state, (char*)request,
                                DH_KEY_LEN,
                                DH_KEY_LEN,
                                keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
                                keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
     log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
     log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
@@ -914,8 +914,8 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
     goto err;
     goto err;
   }
   }
 
 
-  crypto_dh_free(hop->dh_handshake_state);
-  hop->dh_handshake_state = NULL;
+  crypto_dh_free(hop->rend_dh_handshake_state);
+  hop->rend_dh_handshake_state = NULL;
 
 
   /* All is well. Extend the circuit. */
   /* All is well. Extend the circuit. */
   circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_JOINED);
   circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_JOINED);

+ 4 - 4
src/or/rendservice.c

@@ -1378,7 +1378,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
   cpath->magic = CRYPT_PATH_MAGIC;
   cpath->magic = CRYPT_PATH_MAGIC;
   launched->build_state->expiry_time = now + MAX_REND_TIMEOUT;
   launched->build_state->expiry_time = now + MAX_REND_TIMEOUT;
 
 
-  cpath->dh_handshake_state = dh;
+  cpath->rend_dh_handshake_state = dh;
   dh = NULL;
   dh = NULL;
   if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0)
   if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0)
     goto err;
     goto err;
@@ -2624,7 +2624,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
 
 
   /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
   /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
   memcpy(buf, circuit->rend_data->rend_cookie, REND_COOKIE_LEN);
   memcpy(buf, circuit->rend_data->rend_cookie, REND_COOKIE_LEN);
-  if (crypto_dh_get_public(hop->dh_handshake_state,
+  if (crypto_dh_get_public(hop->rend_dh_handshake_state,
                            buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
                            buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
     log_warn(LD_GENERAL,"Couldn't get DH public key.");
     log_warn(LD_GENERAL,"Couldn't get DH public key.");
     reason = END_CIRC_REASON_INTERNAL;
     reason = END_CIRC_REASON_INTERNAL;
@@ -2643,8 +2643,8 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
     goto err;
     goto err;
   }
   }
 
 
-  crypto_dh_free(hop->dh_handshake_state);
-  hop->dh_handshake_state = NULL;
+  crypto_dh_free(hop->rend_dh_handshake_state);
+  hop->rend_dh_handshake_state = NULL;
 
 
   /* Append the cpath entry. */
   /* Append the cpath entry. */
   hop->state = CPATH_STATE_OPEN;
   hop->state = CPATH_STATE_OPEN;

+ 7 - 0
src/or/router.c

@@ -1598,6 +1598,13 @@ router_digest_is_me(const char *digest)
           tor_memeq(server_identitykey_digest, digest, DIGEST_LEN));
           tor_memeq(server_identitykey_digest, digest, DIGEST_LEN));
 }
 }
 
 
+/** DOCDOC */
+const uint8_t *
+router_get_my_id_digest(void)
+{
+  return (const uint8_t *)server_identitykey_digest;
+}
+
 /** Return true iff I'm a server and <b>digest</b> is equal to
 /** Return true iff I'm a server and <b>digest</b> is equal to
  * my identity digest. */
  * my identity digest. */
 int
 int

+ 1 - 0
src/or/router.h

@@ -84,6 +84,7 @@ extrainfo_t *router_get_my_extrainfo(void);
 const char *router_get_my_descriptor(void);
 const char *router_get_my_descriptor(void);
 const char *router_get_descriptor_gen_reason(void);
 const char *router_get_descriptor_gen_reason(void);
 int router_digest_is_me(const char *digest);
 int router_digest_is_me(const char *digest);
+const uint8_t *router_get_my_id_digest(void);
 int router_extrainfo_digest_is_me(const char *digest);
 int router_extrainfo_digest_is_me(const char *digest);
 int router_is_me(const routerinfo_t *router);
 int router_is_me(const routerinfo_t *router);
 int router_fingerprint_is_me(const char *fp);
 int router_fingerprint_is_me(const char *fp);

+ 9 - 7
src/test/bench.c

@@ -110,8 +110,8 @@ bench_onion_TAP(void)
   int i;
   int i;
   crypto_pk_t *key, *key2;
   crypto_pk_t *key, *key2;
   uint64_t start, end;
   uint64_t start, end;
-  char os[ONIONSKIN_CHALLENGE_LEN];
-  char or[ONIONSKIN_REPLY_LEN];
+  char os[TAP_ONIONSKIN_CHALLENGE_LEN];
+  char or[TAP_ONIONSKIN_REPLY_LEN];
   crypto_dh_t *dh_out;
   crypto_dh_t *dh_out;
 
 
   key = crypto_pk_new();
   key = crypto_pk_new();
@@ -122,17 +122,18 @@ bench_onion_TAP(void)
   reset_perftime();
   reset_perftime();
   start = perftime();
   start = perftime();
   for (i = 0; i < iters; ++i) {
   for (i = 0; i < iters; ++i) {
-    onion_skin_create(key, &dh_out, os);
+    onion_skin_TAP_create(key, &dh_out, os);
     crypto_dh_free(dh_out);
     crypto_dh_free(dh_out);
   }
   }
   end = perftime();
   end = perftime();
   printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
   printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
 
 
-  onion_skin_create(key, &dh_out, os);
+  onion_skin_TAP_create(key, &dh_out, os);
   start = perftime();
   start = perftime();
   for (i = 0; i < iters; ++i) {
   for (i = 0; i < iters; ++i) {
     char key_out[CPATH_KEY_MATERIAL_LEN];
     char key_out[CPATH_KEY_MATERIAL_LEN];
-    onion_skin_server_handshake(os, key, NULL, or, key_out, sizeof(key_out));
+    onion_skin_TAP_server_handshake(os, key, NULL, or,
+                                    key_out, sizeof(key_out));
   }
   }
   end = perftime();
   end = perftime();
   printf("Server-side, key guessed right: %f usec\n",
   printf("Server-side, key guessed right: %f usec\n",
@@ -141,7 +142,8 @@ bench_onion_TAP(void)
   start = perftime();
   start = perftime();
   for (i = 0; i < iters; ++i) {
   for (i = 0; i < iters; ++i) {
     char key_out[CPATH_KEY_MATERIAL_LEN];
     char key_out[CPATH_KEY_MATERIAL_LEN];
-    onion_skin_server_handshake(os, key2, key, or, key_out, sizeof(key_out));
+    onion_skin_TAP_server_handshake(os, key2, key, or,
+                                    key_out, sizeof(key_out));
   }
   }
   end = perftime();
   end = perftime();
   printf("Server-side, key guessed wrong: %f usec.\n",
   printf("Server-side, key guessed wrong: %f usec.\n",
@@ -153,7 +155,7 @@ bench_onion_TAP(void)
     char key_out[CPATH_KEY_MATERIAL_LEN];
     char key_out[CPATH_KEY_MATERIAL_LEN];
     int s;
     int s;
     dh = crypto_dh_dup(dh_out);
     dh = crypto_dh_dup(dh_out);
-    s = onion_skin_client_handshake(dh, or, key_out, sizeof(key_out));
+    s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out));
     tor_assert(s == 0);
     tor_assert(s == 0);
   }
   }
   end = perftime();
   end = perftime();

+ 7 - 7
src/test/test.c

@@ -819,11 +819,11 @@ test_onion_handshake(void)
 {
 {
   /* client-side */
   /* client-side */
   crypto_dh_t *c_dh = NULL;
   crypto_dh_t *c_dh = NULL;
-  char c_buf[ONIONSKIN_CHALLENGE_LEN];
+  char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
   char c_keys[40];
   char c_keys[40];
 
 
   /* server-side */
   /* server-side */
-  char s_buf[ONIONSKIN_REPLY_LEN];
+  char s_buf[TAP_ONIONSKIN_REPLY_LEN];
   char s_keys[40];
   char s_keys[40];
 
 
   /* shared */
   /* shared */
@@ -832,18 +832,18 @@ test_onion_handshake(void)
   pk = pk_generate(0);
   pk = pk_generate(0);
 
 
   /* client handshake 1. */
   /* client handshake 1. */
-  memset(c_buf, 0, ONIONSKIN_CHALLENGE_LEN);
-  test_assert(! onion_skin_create(pk, &c_dh, c_buf));
+  memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
+  test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
 
 
   /* server handshake */
   /* server handshake */
-  memset(s_buf, 0, ONIONSKIN_REPLY_LEN);
+  memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN);
   memset(s_keys, 0, 40);
   memset(s_keys, 0, 40);
-  test_assert(! onion_skin_server_handshake(c_buf, pk, NULL,
+  test_assert(! onion_skin_TAP_server_handshake(c_buf, pk, NULL,
                                             s_buf, s_keys, 40));
                                             s_buf, s_keys, 40));
 
 
   /* client handshake 2 */
   /* client handshake 2 */
   memset(c_keys, 0, 40);
   memset(c_keys, 0, 40);
-  test_assert(! onion_skin_client_handshake(c_dh, s_buf, c_keys, 40));
+  test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
 
 
   if (memcmp(c_keys, s_keys, 40)) {
   if (memcmp(c_keys, s_keys, 40)) {
     puts("Aiiiie");
     puts("Aiiiie");