[tor-commits] [tor/master] Implement scheme to allow ntor requests/responses via older servers

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


commit 1ed4786dba8912ab7a6eb16adf7554cf9a5c1ed1
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Dec 5 23:59:12 2012 -0500

    Implement scheme to allow ntor requests/responses via older servers
---
 src/or/onion.c               |   73 ++++++++++++++++++++++++++++++++---------
 src/test/test_cell_formats.c |   46 ++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 16 deletions(-)

diff --git a/src/or/onion.c b/src/or/onion.c
index ce5eb93..753ddcf 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -337,7 +337,7 @@ onion_skin_server_handshake(int type,
     break;
   case ONION_HANDSHAKE_TYPE_NTOR:
 #ifdef CURVE25519_ENABLED
-    if (onionskin_len != NTOR_ONIONSKIN_LEN)
+    if (onionskin_len < NTOR_ONIONSKIN_LEN)
       return -1;
     {
       size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
@@ -409,7 +409,7 @@ onion_skin_client_handshake(int type,
     return 0;
 #ifdef CURVE25519_ENABLED
   case ONION_HANDSHAKE_TYPE_NTOR:
-    if (reply_len != NTOR_REPLY_LEN)
+    if (reply_len < NTOR_REPLY_LEN)
       return -1;
     {
       size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
@@ -442,7 +442,8 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
 {
   switch (cell->cell_type) {
   case CELL_CREATE:
-    if (cell->handshake_type != ONION_HANDSHAKE_TYPE_TAP)
+    if (cell->handshake_type != ONION_HANDSHAKE_TYPE_TAP &&
+        cell->handshake_type != ONION_HANDSHAKE_TYPE_NTOR)
       return -1;
     break;
   case CELL_CREATE_FAST:
@@ -502,6 +503,14 @@ parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len)
   return 0;
 }
 
+/** Magic string which, in a CREATE or EXTEND cell, indicates that a seeming
+ * TAP payload is really an ntor payload.  We'd do away with this if every
+ * relay supported EXTEND2, but we want to be able to extend from A to B with
+ * ntor even when A doesn't understand EXTEND2 and so can't generate a
+ * CREATE2 cell.
+ **/
+#define NTOR_CREATE_MAGIC "ntorNTORntorNTOR"
+
 /** Parse a CREATE, CREATE_FAST, or CREATE2 cell from <b>cell_in</b> into
  * <b>cell_out</b>. Return 0 on success, -1 on failure. (We reject some
  * syntactically valid CREATE2 cells that we can't generate or react to.) */
@@ -513,9 +522,16 @@ create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in)
   switch (cell_in->command) {
   case CELL_CREATE:
     cell_out->cell_type = CELL_CREATE;
-    cell_out->handshake_type = ONION_HANDSHAKE_TYPE_TAP;
-    cell_out->handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
-    memcpy(cell_out->onionskin, cell_in->payload, TAP_ONIONSKIN_CHALLENGE_LEN);
+    if (tor_memeq(cell_in->payload, NTOR_CREATE_MAGIC, 16)) {
+      cell_out->handshake_type = ONION_HANDSHAKE_TYPE_NTOR;
+      cell_out->handshake_len = NTOR_ONIONSKIN_LEN;
+      memcpy(cell_out->onionskin, cell_in->payload+16, NTOR_ONIONSKIN_LEN);
+    } else {
+      cell_out->handshake_type = ONION_HANDSHAKE_TYPE_TAP;
+      cell_out->handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
+      memcpy(cell_out->onionskin, cell_in->payload,
+             TAP_ONIONSKIN_CHALLENGE_LEN);
+    }
     break;
   case CELL_CREATE_FAST:
     cell_out->cell_type = CELL_CREATE_FAST;
@@ -603,7 +619,8 @@ check_extend_cell(const extend_cell_t *cell)
     if (cell->cell_type != RELAY_COMMAND_EXTEND)
       return -1;
   } else if (cell->create_cell.cell_type == CELL_CREATE2) {
-    if (cell->cell_type != RELAY_COMMAND_EXTEND2)
+    if (cell->cell_type != RELAY_COMMAND_EXTEND2 &&
+        cell->cell_type != RELAY_COMMAND_EXTEND)
       return -1;
   } else {
     /* In particular, no CREATE_FAST cells are allowed */
@@ -647,11 +664,19 @@ extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
       tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr, get_uint32(payload));
       cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4));
       tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
-      cell_out->create_cell.cell_type = CELL_CREATE;
-      cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
-      cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
-      memcpy(cell_out->create_cell.onionskin, payload + 6,
-             TAP_ONIONSKIN_CHALLENGE_LEN);
+      if (tor_memeq(payload + 6, NTOR_CREATE_MAGIC, 16)) {
+        cell_out->create_cell.cell_type = CELL_CREATE2;
+        cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR;
+        cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN;
+        memcpy(cell_out->create_cell.onionskin, payload + 22,
+               NTOR_ONIONSKIN_LEN);
+      } else {
+        cell_out->create_cell.cell_type = CELL_CREATE;
+        cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
+        cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
+        memcpy(cell_out->create_cell.onionskin, payload + 6,
+               TAP_ONIONSKIN_CHALLENGE_LEN);
+      }
       memcpy(cell_out->node_id, payload + 6 + TAP_ONIONSKIN_CHALLENGE_LEN,
              DIGEST_LEN);
       break;
@@ -787,17 +812,28 @@ extended_cell_parse(extended_cell_t *cell_out,
 int
 create_cell_format(cell_t *cell_out, const create_cell_t *cell_in)
 {
+  uint8_t *p;
+  size_t space;
   if (check_create_cell(cell_in, 0) < 0)
     return -1;
 
   memset(cell_out->payload, 0, sizeof(cell_out->payload));
   cell_out->command = cell_in->cell_type;
 
+  p = cell_out->payload;
+  space = sizeof(cell_out->payload);
+
   switch (cell_in->cell_type) {
   case CELL_CREATE:
+    if (cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
+      memcpy(p, NTOR_CREATE_MAGIC, 16);
+      p += 16;
+      space -= 16;
+    }
+    /* Fall through */
   case CELL_CREATE_FAST:
-    tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload));
-    memcpy(cell_out->payload, cell_in->onionskin, cell_in->handshake_len);
+    tor_assert(cell_in->handshake_len <= space);
+    memcpy(p, cell_in->onionskin, cell_in->handshake_len);
     break;
   case CELL_CREATE2:
     tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-4);
@@ -865,8 +901,13 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
       *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN;
       set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr));
       set_uint16(p+4, ntohs(cell_in->orport_ipv4.port));
-      memcpy(p+6, cell_in->create_cell.onionskin,
-             TAP_ONIONSKIN_CHALLENGE_LEN);
+      if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
+        memcpy(p+6, NTOR_CREATE_MAGIC, 16);
+        memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN);
+      } else {
+        memcpy(p+6, cell_in->create_cell.onionskin,
+               TAP_ONIONSKIN_CHALLENGE_LEN);
+      }
       memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN);
     }
     break;
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index 2af87af..bdbc555 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -456,6 +456,26 @@ test_cfmt_create_cells(void *arg)
   tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
 #endif
 
+  /* A valid create cell with an ntor payload, in legacy format. */
+  memset(&cell, 0, sizeof(cell));
+  memset(b, 0, sizeof(b));
+  crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+  cell.command = CELL_CREATE;
+  memcpy(cell.payload, "ntorNTORntorNTOR", 16);
+  memcpy(cell.payload+16, b, NTOR_ONIONSKIN_LEN);
+#ifdef CURVE25519_ENABLED
+  tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+  tt_int_op(CELL_CREATE, ==, cc.cell_type);
+  tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
+  tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
+  test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
+  tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+  tt_int_op(cell.command, ==, cell2.command);
+  test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+#else
+  tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+#endif
+
   /* == Okay, now let's try to parse some impossible stuff. */
 
   /* It has to be some kind of a create cell! */
@@ -573,6 +593,7 @@ test_cfmt_created_cells(void *arg)
 static void
 test_cfmt_extend_cells(void *arg)
 {
+  cell_t cell;
   uint8_t b[512];
   extend_cell_t ec;
   create_cell_t *cc = &ec.create_cell;
@@ -607,6 +628,31 @@ test_cfmt_extend_cells(void *arg)
   tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
   test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
 
+  /* Let's do an ntor stuffed in a legacy EXTEND cell */
+  memset(p, 0, sizeof(p));
+  memset(b, 0, sizeof(b));
+  crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+  memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
+  memcpy(p+6,"ntorNTORntorNTOR", 16);
+  memcpy(p+22, b, NTOR_ONIONSKIN_LEN);
+  memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
+  tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
+                                     p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
+  tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
+  tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+  tt_int_op(258, ==, ec.orport_ipv4.port);
+  tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
+  test_memeq(ec.node_id, "electroencephalogram", 20);
+  tt_int_op(cc->cell_type, ==, CELL_CREATE2);
+  tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
+  tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
+  test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
+  tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+  tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
+  tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
+  test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+  tt_int_op(0, ==, create_cell_format(&cell, cc));
+
   /* Now let's do a minimal ntor EXTEND2 cell. */
   memset(&ec, 0xff, sizeof(ec));
   memset(p, 0, sizeof(p));





More information about the tor-commits mailing list