Loading src/or/onion.c +57 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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.) */ Loading @@ -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; 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); memcpy(cell_out->onionskin, cell_in->payload, TAP_ONIONSKIN_CHALLENGE_LEN); } break; case CELL_CREATE_FAST: cell_out->cell_type = CELL_CREATE_FAST; Loading Loading @@ -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 */ Loading Loading @@ -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); 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; Loading Loading @@ -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); Loading Loading @@ -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)); 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; Loading src/test/test_cell_formats.c +46 −0 Original line number Diff line number Diff line Loading @@ -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! */ Loading Loading @@ -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; Loading Loading @@ -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)); Loading Loading
src/or/onion.c +57 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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.) */ Loading @@ -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; 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); memcpy(cell_out->onionskin, cell_in->payload, TAP_ONIONSKIN_CHALLENGE_LEN); } break; case CELL_CREATE_FAST: cell_out->cell_type = CELL_CREATE_FAST; Loading Loading @@ -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 */ Loading Loading @@ -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); 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; Loading Loading @@ -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); Loading Loading @@ -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)); 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; Loading
src/test/test_cell_formats.c +46 −0 Original line number Diff line number Diff line Loading @@ -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! */ Loading Loading @@ -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; Loading Loading @@ -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)); Loading