diff options
Diffstat (limited to 'src/test/test_cell_formats.c')
-rw-r--r-- | src/test/test_cell_formats.c | 888 |
1 files changed, 888 insertions, 0 deletions
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c new file mode 100644 index 000000000..55d8d0f00 --- /dev/null +++ b/src/test/test_cell_formats.c @@ -0,0 +1,888 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" + +#define CONNECTION_EDGE_PRIVATE +#define RELAY_PRIVATE +#include "or.h" +#include "connection_edge.h" +#include "onion.h" +#include "onion_tap.h" +#include "onion_fast.h" +#include "onion_ntor.h" +#include "relay.h" +#include "test.h" + +#include <stdlib.h> +#include <string.h> + +static void +test_cfmt_relay_header(void *arg) +{ + relay_header_t rh; + const uint8_t hdr_1[RELAY_HEADER_SIZE] = + "\x03" "\x00\x00" "\x21\x22" "ABCD" "\x01\x03"; + uint8_t hdr_out[RELAY_HEADER_SIZE]; + (void)arg; + + tt_int_op(sizeof(hdr_1), ==, RELAY_HEADER_SIZE); + relay_header_unpack(&rh, hdr_1); + tt_int_op(rh.command, ==, 3); + tt_int_op(rh.recognized, ==, 0); + tt_int_op(rh.stream_id, ==, 0x2122); + test_mem_op(rh.integrity, ==, "ABCD", 4); + tt_int_op(rh.length, ==, 0x103); + + relay_header_pack(hdr_out, &rh); + test_mem_op(hdr_out, ==, hdr_1, RELAY_HEADER_SIZE); + + done: + ; +} + +static void +make_relay_cell(cell_t *out, uint8_t command, + const void *body, size_t bodylen) +{ + relay_header_t rh; + + memset(&rh, 0, sizeof(rh)); + rh.stream_id = 5; + rh.command = command; + rh.length = bodylen; + + out->command = CELL_RELAY; + out->circ_id = 10; + relay_header_pack(out->payload, &rh); + + memcpy(out->payload + RELAY_HEADER_SIZE, body, bodylen); +} + +static void +test_cfmt_begin_cells(void *arg) +{ + cell_t cell; + begin_cell_t bcell; + uint8_t end_reason; + (void)arg; + + /* Try begindir. */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "", 0); + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_ptr_op(NULL, ==, bcell.address); + tt_int_op(0, ==, bcell.flags); + tt_int_op(0, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(1, ==, bcell.is_begindir); + + /* A Begindir with extra stuff. */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "12345", 5); + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_ptr_op(NULL, ==, bcell.address); + tt_int_op(0, ==, bcell.flags); + tt_int_op(0, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(1, ==, bcell.is_begindir); + + /* A short but valid begin cell */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:9", 6); + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_str_op("a.b", ==, bcell.address); + tt_int_op(0, ==, bcell.flags); + tt_int_op(9, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(0, ==, bcell.is_begindir); + tor_free(bcell.address); + + /* A significantly loner begin cell */ + memset(&bcell, 0x7f, sizeof(bcell)); + { + const char c[] = "here-is-a-nice-long.hostname.com:65535"; + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, strlen(c)+1); + } + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_str_op("here-is-a-nice-long.hostname.com", ==, bcell.address); + tt_int_op(0, ==, bcell.flags); + tt_int_op(65535, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(0, ==, bcell.is_begindir); + tor_free(bcell.address); + + /* An IPv4 begin cell. */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15); + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_str_op("18.9.22.169", ==, bcell.address); + tt_int_op(0, ==, bcell.flags); + tt_int_op(80, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(0, ==, bcell.is_begindir); + tor_free(bcell.address); + + /* An IPv6 begin cell. Let's make sure we handle colons*/ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, + "[2620::6b0:b:1a1a:0:26e5:480e]:80", 34); + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", ==, bcell.address); + tt_int_op(0, ==, bcell.flags); + tt_int_op(80, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(0, ==, bcell.is_begindir); + tor_free(bcell.address); + + /* a begin cell with extra junk but not enough for flags. */ + memset(&bcell, 0x7f, sizeof(bcell)); + { + const char c[] = "another.example.com:80\x00\x01\x02"; + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + } + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_str_op("another.example.com", ==, bcell.address); + tt_int_op(0, ==, bcell.flags); + tt_int_op(80, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(0, ==, bcell.is_begindir); + tor_free(bcell.address); + + /* a begin cell with flags. */ + memset(&bcell, 0x7f, sizeof(bcell)); + { + const char c[] = "another.example.com:443\x00\x01\x02\x03\x04"; + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + } + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_str_op("another.example.com", ==, bcell.address); + tt_int_op(0x1020304, ==, bcell.flags); + tt_int_op(443, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(0, ==, bcell.is_begindir); + tor_free(bcell.address); + + /* a begin cell with flags and even more cruft after that. */ + memset(&bcell, 0x7f, sizeof(bcell)); + { + const char c[] = "a-further.example.com:22\x00\xee\xaa\x00\xffHi mom"; + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + } + tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_str_op("a-further.example.com", ==, bcell.address); + tt_int_op(0xeeaa00ff, ==, bcell.flags); + tt_int_op(22, ==, bcell.port); + tt_int_op(5, ==, bcell.stream_id); + tt_int_op(0, ==, bcell.is_begindir); + tor_free(bcell.address); + + /* bad begin cell: impossible length. */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 7); + cell.payload[9] = 0x01; /* Set length to 510 */ + cell.payload[10] = 0xfe; + { + relay_header_t rh; + relay_header_unpack(&rh, cell.payload); + tt_int_op(rh.length, ==, 510); + } + tt_int_op(-2, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + + /* Bad begin cell: no body. */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0); + tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + + /* bad begin cell: no body. */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0); + tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + + /* bad begin cell: no colon */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b", 4); + tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + + /* bad begin cell: no ports */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:", 5); + tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + + /* bad begin cell: bad port */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:xyz", 8); + tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:100000", 11); + tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + + /* bad begin cell: no nul */ + memset(&bcell, 0x7f, sizeof(bcell)); + make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 6); + tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); + + done: + tor_free(bcell.address); +} + +static void +test_cfmt_connected_cells(void *arg) +{ + relay_header_t rh; + cell_t cell; + tor_addr_t addr; + int ttl, r; + char *mem_op_hex_tmp = NULL; + (void)arg; + + /* Let's try an oldschool one with nothing in it. */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "", 0); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_UNSPEC); + tt_int_op(ttl, ==, -1); + + /* A slightly less oldschool one: only an IPv4 address */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_INET); + tt_str_op(fmt_addr(&addr), ==, "32.48.64.80"); + tt_int_op(ttl, ==, -1); + + /* Bogus but understandable: truncated TTL */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_INET); + tt_str_op(fmt_addr(&addr), ==, "17.18.19.20"); + tt_int_op(ttl, ==, -1); + + /* Regular IPv4 one: address and TTL */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + "\x02\x03\x04\x05\x00\x00\x0e\x10", 8); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_INET); + tt_str_op(fmt_addr(&addr), ==, "2.3.4.5"); + tt_int_op(ttl, ==, 3600); + + /* IPv4 with too-big TTL */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + "\x02\x03\x04\x05\xf0\x00\x00\x00", 8); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_INET); + tt_str_op(fmt_addr(&addr), ==, "2.3.4.5"); + tt_int_op(ttl, ==, -1); + + /* IPv6 (ttl is mandatory) */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + "\x00\x00\x00\x00\x06" + "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" + "\x00\x00\x00\x00\x00\x00\x00\x68" + "\x00\x00\x02\x58", 25); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_INET6); + tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68"); + tt_int_op(ttl, ==, 600); + + /* IPv6 (ttl too big) */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + "\x00\x00\x00\x00\x06" + "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" + "\x00\x00\x00\x00\x00\x00\x00\x68" + "\x90\x00\x02\x58", 25); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_INET6); + tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68"); + tt_int_op(ttl, ==, -1); + + /* Bogus size: 3. */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + "\x00\x01\x02", 3); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, -1); + + /* Bogus family: 7. */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + "\x00\x00\x00\x00\x07" + "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" + "\x00\x00\x00\x00\x00\x00\x00\x68" + "\x90\x00\x02\x58", 25); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, -1); + + /* Truncated IPv6. */ + make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + "\x00\x00\x00\x00\x06" + "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" + "\x00\x00\x00\x00\x00\x00\x00\x68" + "\x00\x00\x02", 24); + relay_header_unpack(&rh, cell.payload); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, -1); + + /* Now make sure we can generate connected cells correctly. */ + /* Try an IPv4 address */ + memset(&rh, 0, sizeof(rh)); + memset(&cell, 0, sizeof(cell)); + tor_addr_parse(&addr, "30.40.50.60"); + rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, + &addr, 128); + tt_int_op(rh.length, ==, 8); + test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000080"); + + /* Try parsing it. */ + tor_addr_make_unspec(&addr); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_INET); + tt_str_op(fmt_addr(&addr), ==, "30.40.50.60"); + tt_int_op(ttl, ==, 128); + + /* Try an IPv6 address */ + memset(&rh, 0, sizeof(rh)); + memset(&cell, 0, sizeof(cell)); + tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e"); + rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, + &addr, 3600); + tt_int_op(rh.length, ==, 25); + test_memeq_hex(cell.payload + RELAY_HEADER_SIZE, + "00000000" "06" + "2620000006b0000b1a1a000026e5480e" "00000e10"); + + /* Try parsing it. */ + tor_addr_make_unspec(&addr); + r = connected_cell_parse(&rh, &cell, &addr, &ttl); + tt_int_op(r, ==, 0); + tt_int_op(tor_addr_family(&addr), ==, AF_INET6); + tt_str_op(fmt_addr(&addr), ==, "2620:0:6b0:b:1a1a:0:26e5:480e"); + tt_int_op(ttl, ==, 3600); + + done: + tor_free(mem_op_hex_tmp); +} + +static void +test_cfmt_create_cells(void *arg) +{ + uint8_t b[MAX_ONIONSKIN_CHALLENGE_LEN]; + create_cell_t cc; + cell_t cell; + cell_t cell2; + + (void)arg; + + /* === Let's try parsing some good cells! */ + + /* A valid create cell. */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); + cell.command = CELL_CREATE; + memcpy(cell.payload, b, TAP_ONIONSKIN_CHALLENGE_LEN); + tt_int_op(0, ==, create_cell_parse(&cc, &cell)); + tt_int_op(CELL_CREATE, ==, cc.cell_type); + tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type); + tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len); + test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_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); + + /* A valid create_fast cell. */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, CREATE_FAST_LEN); + cell.command = CELL_CREATE_FAST; + memcpy(cell.payload, b, CREATE_FAST_LEN); + tt_int_op(0, ==, create_cell_parse(&cc, &cell)); + tt_int_op(CELL_CREATE_FAST, ==, cc.cell_type); + tt_int_op(ONION_HANDSHAKE_TYPE_FAST, ==, cc.handshake_type); + tt_int_op(CREATE_FAST_LEN, ==, cc.handshake_len); + test_memeq(cc.onionskin, b, CREATE_FAST_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); + + /* A valid create2 cell with a TAP payload */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); + cell.command = CELL_CREATE2; + memcpy(cell.payload, "\x00\x00\x00\xBA", 4); /* TAP, 186 bytes long */ + memcpy(cell.payload+4, b, TAP_ONIONSKIN_CHALLENGE_LEN); + tt_int_op(0, ==, create_cell_parse(&cc, &cell)); + tt_int_op(CELL_CREATE2, ==, cc.cell_type); + tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type); + tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len); + test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_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); + + /* A valid create2 cell with an ntor payload */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, NTOR_ONIONSKIN_LEN); + cell.command = CELL_CREATE2; + memcpy(cell.payload, "\x00\x02\x00\x54", 4); /* ntor, 84 bytes long */ + memcpy(cell.payload+4, b, NTOR_ONIONSKIN_LEN); +#ifdef CURVE25519_ENABLED + tt_int_op(0, ==, create_cell_parse(&cc, &cell)); + tt_int_op(CELL_CREATE2, ==, 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 + + /* 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! */ + cell.command = CELL_CREATED; + tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); + + /* You can't acutally make an unparseable CREATE or CREATE_FAST cell. */ + + /* Try some CREATE2 cells. First with a bad type. */ + cell.command = CELL_CREATE2; + memcpy(cell.payload, "\x00\x50\x00\x99", 4); /* Type 0x50???? */ + tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); + /* Now a good type with an incorrect length. */ + memcpy(cell.payload, "\x00\x00\x00\xBC", 4); /* TAP, 187 bytes.*/ + tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); + /* Now a good type with a ridiculous length. */ + memcpy(cell.payload, "\x00\x00\x02\x00", 4); /* TAP, 512 bytes.*/ + tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); + + /* == Time to try formatting bad cells. The important thing is that + we reject big lengths, so just check that for now. */ + cc.handshake_len = 512; + tt_int_op(-1, ==, create_cell_format(&cell2, &cc)); + + /* == Try formatting a create2 cell we don't understand. XXXX */ + + done: + ; +} + +static void +test_cfmt_created_cells(void *arg) +{ + uint8_t b[512]; + created_cell_t cc; + cell_t cell; + cell_t cell2; + + (void)arg; + + /* A good CREATED cell */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN); + cell.command = CELL_CREATED; + memcpy(cell.payload, b, TAP_ONIONSKIN_REPLY_LEN); + tt_int_op(0, ==, created_cell_parse(&cc, &cell)); + tt_int_op(CELL_CREATED, ==, cc.cell_type); + tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, cc.handshake_len); + test_memeq(cc.reply, b, TAP_ONIONSKIN_REPLY_LEN + 10); + tt_int_op(0, ==, created_cell_format(&cell2, &cc)); + tt_int_op(cell.command, ==, cell2.command); + test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); + + /* A good CREATED_FAST cell */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, CREATED_FAST_LEN); + cell.command = CELL_CREATED_FAST; + memcpy(cell.payload, b, CREATED_FAST_LEN); + tt_int_op(0, ==, created_cell_parse(&cc, &cell)); + tt_int_op(CELL_CREATED_FAST, ==, cc.cell_type); + tt_int_op(CREATED_FAST_LEN, ==, cc.handshake_len); + test_memeq(cc.reply, b, CREATED_FAST_LEN + 10); + tt_int_op(0, ==, created_cell_format(&cell2, &cc)); + tt_int_op(cell.command, ==, cell2.command); + test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); + + /* A good CREATED2 cell with short reply */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, 64); + cell.command = CELL_CREATED2; + memcpy(cell.payload, "\x00\x40", 2); + memcpy(cell.payload+2, b, 64); + tt_int_op(0, ==, created_cell_parse(&cc, &cell)); + tt_int_op(CELL_CREATED2, ==, cc.cell_type); + tt_int_op(64, ==, cc.handshake_len); + test_memeq(cc.reply, b, 80); + tt_int_op(0, ==, created_cell_format(&cell2, &cc)); + tt_int_op(cell.command, ==, cell2.command); + test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); + + /* A good CREATED2 cell with maximal reply */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, 496); + cell.command = CELL_CREATED2; + memcpy(cell.payload, "\x01\xF0", 2); + memcpy(cell.payload+2, b, 496); + tt_int_op(0, ==, created_cell_parse(&cc, &cell)); + tt_int_op(CELL_CREATED2, ==, cc.cell_type); + tt_int_op(496, ==, cc.handshake_len); + test_memeq(cc.reply, b, 496); + tt_int_op(0, ==, created_cell_format(&cell2, &cc)); + tt_int_op(cell.command, ==, cell2.command); + test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); + + /* Bogus CREATED2 cell: too long! */ + memset(&cell, 0, sizeof(cell)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, 496); + cell.command = CELL_CREATED2; + memcpy(cell.payload, "\x01\xF1", 2); + tt_int_op(-1, ==, created_cell_parse(&cc, &cell)); + + /* Unformattable CREATED2 cell: too long! */ + cc.handshake_len = 497; + tt_int_op(-1, ==, created_cell_format(&cell2, &cc)); + + done: + ; +} + +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; + uint8_t p[RELAY_PAYLOAD_SIZE]; + uint8_t p2[RELAY_PAYLOAD_SIZE]; + uint8_t p2_cmd; + uint16_t p2_len; + char *mem_op_hex_tmp = NULL; + + (void) arg; + + /* Let's start with a simple EXTEND cell. */ + memset(p, 0, sizeof(p)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); + memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */ + memcpy(p+6,b,TAP_ONIONSKIN_CHALLENGE_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_CREATE); + tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_TAP); + tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_CHALLENGE_LEN); + test_memeq(cc->onionskin, b, TAP_ONIONSKIN_CHALLENGE_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); + + /* 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_relayed(&cell, cc)); + + /* Now let's do a minimal ntor EXTEND2 cell. */ + memset(&ec, 0xff, sizeof(ec)); + memset(p, 0, sizeof(p)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, NTOR_ONIONSKIN_LEN); + /* 2 items; one 18.244.0.1:61681 */ + memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); + /* The other is a digest. */ + memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); + /* Prep for the handshake: type and length */ + memcpy(p+31, "\x00\x02\x00\x54", 4); + memcpy(p+35, b, NTOR_ONIONSKIN_LEN); + tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, 35+NTOR_ONIONSKIN_LEN)); + tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type); + tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr)); + tt_int_op(61681, ==, ec.orport_ipv4.port); + tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr)); + test_memeq(ec.node_id, "anarchoindividualist", 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_EXTEND2); + tt_int_op(p2_len, ==, 35+NTOR_ONIONSKIN_LEN); + test_memeq(p2, p, RELAY_PAYLOAD_SIZE); + + /* Now let's do a fanciful EXTEND2 cell. */ + memset(&ec, 0xff, sizeof(ec)); + memset(p, 0, sizeof(p)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, 99); + /* 4 items; one 18 244 0 1 61681 */ + memcpy(p, "\x04\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); + /* One is a digest. */ + memcpy(p+9, "\x02\x14" "anthropomorphization", 22); + /* One is an ipv6 address */ + memcpy(p+31, "\x01\x12\x20\x02\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\xf0\xc5\x1e\x11\x12", 20); + /* One is the Konami code. */ + memcpy(p+51, "\xf0\x20upupdowndownleftrightleftrightba", 34); + /* Prep for the handshake: weird type and length */ + memcpy(p+85, "\x01\x05\x00\x63", 4); + memcpy(p+89, b, 99); + tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, 89+99)); + tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type); + tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr)); + tt_int_op(61681, ==, ec.orport_ipv4.port); + tt_str_op("2002::f0:c51e", ==, fmt_addr(&ec.orport_ipv6.addr)); + tt_int_op(4370, ==, ec.orport_ipv6.port); + test_memeq(ec.node_id, "anthropomorphization", 20); + tt_int_op(cc->cell_type, ==, CELL_CREATE2); + tt_int_op(cc->handshake_type, ==, 0x105); + tt_int_op(cc->handshake_len, ==, 99); + test_memeq(cc->onionskin, b, 99+20); + tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); + tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2); + /* We'll generate it minus the IPv6 address and minus the konami code */ + tt_int_op(p2_len, ==, 89+99-34-20); + test_memeq_hex(p2, + /* Two items: one that same darn IP address. */ + "02000612F40001F0F1" + /* The next is a digest : anthropomorphization */ + "0214616e7468726f706f6d6f727068697a6174696f6e" + /* Now the handshake prologue */ + "01050063"); + test_memeq(p2+1+8+22+4, b, 99+20); + tt_int_op(0, ==, create_cell_format_relayed(&cell, cc)); + + /* == Now try parsing some junk */ + + /* Try a too-long handshake */ + memset(p, 0, sizeof(p)); + memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); + memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); + memcpy(p+31, "\xff\xff\x01\xd0", 4); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + + /* Try two identities. */ + memset(p, 0, sizeof(p)); + memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); + memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); + memcpy(p+31, "\x02\x14" "autodepolymerization", 22); + memcpy(p+53, "\xff\xff\x00\x10", 4); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + + /* No identities. */ + memset(p, 0, sizeof(p)); + memcpy(p, "\x01\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); + memcpy(p+53, "\xff\xff\x00\x10", 4); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + + /* Try a bad IPv4 address (too long, too short)*/ + memset(p, 0, sizeof(p)); + memcpy(p, "\x02\x00\x07\x12\xf4\x00\x01\xf0\xf1\xff", 10); + memcpy(p+10, "\x02\x14" "anarchoindividualist", 22); + memcpy(p+32, "\xff\xff\x00\x10", 4); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + memset(p, 0, sizeof(p)); + memcpy(p, "\x02\x00\x05\x12\xf4\x00\x01\xf0", 8); + memcpy(p+8, "\x02\x14" "anarchoindividualist", 22); + memcpy(p+30, "\xff\xff\x00\x10", 4); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + + /* IPv6 address (too long, too short, no IPv4)*/ + memset(p, 0, sizeof(p)); + memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); + memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); + memcpy(p+31, "\x01\x13" "xxxxxxxxxxxxxxxxYYZ", 19); + memcpy(p+50, "\xff\xff\x00\x20", 4); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + memset(p, 0, sizeof(p)); + memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); + memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); + memcpy(p+31, "\x01\x11" "xxxxxxxxxxxxxxxxY", 17); + memcpy(p+48, "\xff\xff\x00\x20", 4); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + memset(p, 0, sizeof(p)); + memcpy(p, "\x02", 1); + memcpy(p+1, "\x02\x14" "anarchoindividualist", 22); + memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18); + memcpy(p+41, "\xff\xff\x00\x20", 4); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + + /* Running out of space in specifiers */ + memset(p,0,sizeof(p)); + memcpy(p, "\x05\x0a\xff", 3); + memcpy(p+3+255, "\x0a\xff", 2); + tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + + /* Fuzz, because why not. */ + memset(&ec, 0xff, sizeof(ec)); + { + int i; + memset(p, 0, sizeof(p)); + for (i = 0; i < 10000; ++i) { + int n = crypto_rand_int(sizeof(p)); + crypto_rand((char *)p, n); + extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, n); + } + } + + done: + tor_free(mem_op_hex_tmp); +} + +static void +test_cfmt_extended_cells(void *arg) +{ + uint8_t b[512]; + extended_cell_t ec; + created_cell_t *cc = &ec.created_cell; + uint8_t p[RELAY_PAYLOAD_SIZE]; + uint8_t p2[RELAY_PAYLOAD_SIZE]; + uint8_t p2_cmd; + uint16_t p2_len; + char *mem_op_hex_tmp = NULL; + + (void) arg; + + /* Try a regular EXTENDED cell. */ + memset(&ec, 0xff, sizeof(ec)); + memset(p, 0, sizeof(p)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN); + memcpy(p,b,TAP_ONIONSKIN_REPLY_LEN); + tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p, + TAP_ONIONSKIN_REPLY_LEN)); + tt_int_op(RELAY_COMMAND_EXTENDED, ==, ec.cell_type); + tt_int_op(cc->cell_type, ==, CELL_CREATED); + tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_REPLY_LEN); + test_memeq(cc->reply, b, TAP_ONIONSKIN_REPLY_LEN); + tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec)); + tt_int_op(RELAY_COMMAND_EXTENDED, ==, p2_cmd); + tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, p2_len); + test_memeq(p2, p, sizeof(p2)); + + /* Try an EXTENDED2 cell */ + memset(&ec, 0xff, sizeof(ec)); + memset(p, 0, sizeof(p)); + memset(b, 0, sizeof(b)); + crypto_rand((char*)b, 42); + memcpy(p,"\x00\x2a",2); + memcpy(p+2,b,42); + tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, 2+42)); + tt_int_op(RELAY_COMMAND_EXTENDED2, ==, ec.cell_type); + tt_int_op(cc->cell_type, ==, CELL_CREATED2); + tt_int_op(cc->handshake_len, ==, 42); + test_memeq(cc->reply, b, 42+10); + tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec)); + tt_int_op(RELAY_COMMAND_EXTENDED2, ==, p2_cmd); + tt_int_op(2+42, ==, p2_len); + test_memeq(p2, p, sizeof(p2)); + + /* Try an almost-too-long EXTENDED2 cell */ + memcpy(p, "\x01\xf0", 2); + tt_int_op(0, ==, + extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p))); + + /* Now try a too-long extended2 cell. That's the only misparse I can think + * of. */ + memcpy(p, "\x01\xf1", 2); + tt_int_op(-1, ==, + extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p))); + + done: + tor_free(mem_op_hex_tmp); +} + +#define TEST(name, flags) \ + { #name, test_cfmt_ ## name, flags, 0, NULL } + +struct testcase_t cell_format_tests[] = { + TEST(relay_header, 0), + TEST(begin_cells, 0), + TEST(connected_cells, 0), + TEST(create_cells, 0), + TEST(created_cells, 0), + TEST(extend_cells, 0), + TEST(extended_cells, 0), + END_OF_TESTCASES +}; + |