tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
January 2013
- 19 participants
- 1125 discussions

[tor/master] Use new wrappers for making, sending, processing create/extend cells
by nickm@torproject.org 03 Jan '13
by nickm@torproject.org 03 Jan '13
03 Jan '13
commit 6c69b16c93bd7156dcda246128b96209616c3ead
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Dec 5 23:07:49 2012 -0500
Use new wrappers for making,sending,processing create/extend cells
---
src/or/circuitbuild.c | 169 +++++++++++++++++++++++++------------------------
src/or/circuitlist.c | 6 +-
src/or/or.h | 9 +--
3 files changed, 93 insertions(+), 91 deletions(-)
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 40cb8e4..5ac2692 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -55,9 +55,7 @@ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
uint16_t port,
const char *id_digest);
static int circuit_deliver_create_cell(circuit_t *circ,
- uint8_t cell_type,
- const uint8_t *payload,
- size_t payload_len);
+ const create_cell_t *create_cell);
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 int onion_extend_cpath(origin_circuit_t *circ);
@@ -474,15 +472,13 @@ circuit_n_chan_done(channel_t *chan, int status)
* died? */
}
} else {
- /* pull the create cell out of circ->onionskin, and send it */
- tor_assert(circ->n_chan_onionskin);
- if (circuit_deliver_create_cell(circ,CELL_CREATE,
- (const uint8_t*)circ->n_chan_onionskin,
- circ->n_chan_onionskin_len)<0) {
+ /* pull the create cell out of circ->n_chan_create_cell, and send it */
+ tor_assert(circ->n_chan_create_cell);
+ if (circuit_deliver_create_cell(circ, circ->n_chan_create_cell)<0) {
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
continue;
}
- tor_free(circ->n_chan_onionskin);
+ tor_free(circ->n_chan_create_cell);
circuit_set_state(circ, CIRCUIT_STATE_OPEN);
}
}
@@ -499,16 +495,17 @@ circuit_n_chan_done(channel_t *chan, int status)
* Return -1 if we failed to find a suitable circid, else return 0.
*/
static int
-circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
- const uint8_t *payload, size_t payload_len)
+circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell)
{
cell_t cell;
circid_t id;
tor_assert(circ);
tor_assert(circ->n_chan);
- tor_assert(payload);
- tor_assert(cell_type == CELL_CREATE || cell_type == CELL_CREATE_FAST);
+ tor_assert(create_cell);
+ tor_assert(create_cell->cell_type == CELL_CREATE ||
+ create_cell->cell_type == CELL_CREATE_FAST ||
+ create_cell->cell_type == CELL_CREATE2);
id = get_unique_circ_id_by_chan(circ->n_chan);
if (!id) {
@@ -519,10 +516,12 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
circuit_set_n_circid_chan(circ, id, circ->n_chan);
memset(&cell, 0, sizeof(cell_t));
- cell.command = cell_type;
+ if (create_cell_format(&cell, create_cell) < 0) {
+ log_warn(LD_CIRC,"Couldn't format create cell");
+ return -1;
+ }
cell.circ_id = circ->n_circ_id;
- memcpy(cell.payload, payload, payload_len);
append_cell_to_circuit_queue(circ, circ->n_chan, &cell,
CELL_DIRECTION_OUT, 0);
@@ -615,18 +614,16 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
{
crypt_path_t *hop;
const node_t *node;
- 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;
tor_assert(circ);
if (circ->cpath->state == CPATH_STATE_CLOSED) {
+ /* This is the first hop. */
+ create_cell_t cc;
int fast;
- uint8_t cell_type;
+ int len;
log_debug(LD_CIRC,"First skin; sending create cell.");
+ memset(&cc, 0, sizeof(cc));
if (circ->build_state->onehop_tunnel)
control_event_bootstrap(BOOTSTRAP_STATUS_ONEHOP_CREATE, 0);
else
@@ -638,30 +635,29 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
/* We are an OR and we know the right onion key: we should
* send an old slow create cell.
*/
- cell_type = CELL_CREATE;
- handshake_type = ONION_HANDSHAKE_TYPE_TAP;
+ cc.cell_type = CELL_CREATE;
+ cc.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
note_request("cell: create", 1);
} else {
/* 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
* and a DH operation. */
- cell_type = CELL_CREATE_FAST;
- handshake_type = ONION_HANDSHAKE_TYPE_FAST;
+ cc.cell_type = CELL_CREATE_FAST;
+ cc.handshake_type = ONION_HANDSHAKE_TYPE_FAST;
note_request("cell: create fast", 1);
}
- 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) {
+ len = onion_skin_create(cc.handshake_type,
+ circ->cpath->extend_info,
+ &circ->cpath->handshake_state,
+ cc.onionskin);
+ if (len < 0) {
log_warn(LD_CIRC,"onion_skin_create (first hop) failed.");
return - END_CIRC_REASON_INTERNAL;
}
+ cc.handshake_len = len;
- if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload,
- onionskin_len) < 0)
+ if (circuit_deliver_create_cell(TO_CIRCUIT(circ), &cc) < 0)
return - END_CIRC_REASON_RESOURCELIMIT;
circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
@@ -670,10 +666,13 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
fast ? "CREATE_FAST" : "CREATE",
node ? node_describe(node) : "<unnamed>");
} else {
+ extend_cell_t ec;
+ int len;
tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING);
log_debug(LD_CIRC,"starting to send subsequent skin.");
hop = onion_next_hop_in_cpath(circ->cpath);
+ memset(&ec, 0, sizeof(ec));
if (!hop) {
/* done building the circuit. whew. */
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
@@ -743,34 +742,44 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
return - END_CIRC_REASON_INTERNAL;
}
- set_uint32(payload, tor_addr_to_ipv4n(&hop->extend_info->addr));
- set_uint16(payload+4, htons(hop->extend_info->port));
-
- onionskin = payload+2+4;
- memcpy(payload+2+4+TAP_ONIONSKIN_CHALLENGE_LEN,
- hop->extend_info->identity_digest, DIGEST_LEN);
- payload_len = 2+4+TAP_ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN;
+ ec.cell_type = RELAY_COMMAND_EXTEND;
+ tor_addr_copy(&ec.orport_ipv4.addr, &hop->extend_info->addr);
+ ec.orport_ipv4.port = hop->extend_info->port;
+ tor_addr_make_unspec(&ec.orport_ipv6.addr);
+ memcpy(ec.node_id, hop->extend_info->identity_digest, DIGEST_LEN);
- handshake_type = ONION_HANDSHAKE_TYPE_TAP;
+ ec.create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
+ ec.create_cell.cell_type = CELL_CREATE;
- if (onion_skin_create(handshake_type,
- hop->extend_info,
- &hop->handshake_state,
- onionskin) < 0) {
+ len = onion_skin_create(ec.create_cell.handshake_type,
+ hop->extend_info,
+ &hop->handshake_state,
+ ec.create_cell.onionskin);
+ if (len < 0) {
log_warn(LD_CIRC,"onion_skin_create failed.");
return - END_CIRC_REASON_INTERNAL;
}
+ ec.create_cell.handshake_len = len;
log_info(LD_CIRC,"Sending extend relay cell.");
note_request("cell: extend", 1);
- /* send it to hop->prev, because it will transfer
- * it to a create cell and then send to hop */
- if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
- RELAY_COMMAND_EXTEND,
- (char*)payload, payload_len,
- hop->prev) < 0)
- return 0; /* circuit is closed */
+ {
+ uint8_t command = 0;
+ uint16_t payload_len=0;
+ uint8_t payload[RELAY_PAYLOAD_SIZE];
+ if (extend_cell_format(&command, &payload_len, payload, &ec)<0) {
+ log_warn(LD_CIRC,"Couldn't format extend cell");
+ return -END_CIRC_REASON_INTERNAL;
+ }
+ /* send it to hop->prev, because it will transfer
+ * it to a create cell and then send to hop */
+ if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
+ command,
+ (char*)payload, payload_len,
+ hop->prev) < 0)
+ return 0; /* circuit is closed */
+ }
hop->state = CPATH_STATE_AWAITING_KEYS;
}
return 0;
@@ -809,11 +818,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
{
channel_t *n_chan;
relay_header_t rh;
- char *onionskin;
- char *id_digest=NULL;
- uint32_t n_addr32;
- uint16_t n_port;
- tor_addr_t n_addr;
+ extend_cell_t ec;
const char *msg = NULL;
int should_launch = 0;
@@ -836,27 +841,21 @@ circuit_extend(cell_t *cell, circuit_t *circ)
relay_header_unpack(&rh, cell->payload);
- if (rh.length < 4+2+TAP_ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN) {
+ if (extend_cell_parse(&ec, rh.command,
+ cell->payload+RELAY_HEADER_SIZE,
+ rh.length) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Wrong length %d on extend cell. Closing circuit.",
- rh.length);
+ "Can't parse extend cell. Closing circuit.");
return -1;
}
- n_addr32 = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
- n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4));
- onionskin = (char*) cell->payload+RELAY_HEADER_SIZE+4+2;
- id_digest = (char*) cell->payload+RELAY_HEADER_SIZE+4+2+
- TAP_ONIONSKIN_CHALLENGE_LEN;
- tor_addr_from_ipv4h(&n_addr, n_addr32);
-
- if (!n_port || !n_addr32) {
+ if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend to zero destination port or addr.");
return -1;
}
- if (tor_addr_is_internal(&n_addr, 0) &&
+ if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) &&
!get_options()->ExtendAllowPrivateAddresses) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend to a private address");
@@ -869,7 +868,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
* fingerprints -- a) because it opens the user up to a mitm attack,
* and b) because it lets an attacker force the relay to hold open a
* new TLS connection for each extend request. */
- if (tor_digest_is_zero(id_digest)) {
+ if (tor_digest_is_zero((const char*)ec.node_id)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend without specifying an id_digest.");
return -1;
@@ -878,7 +877,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
/* Next, check if we're being asked to connect to the hop that the
* extend cell came from. There isn't any reason for that, and it can
* assist circular-path attacks. */
- if (tor_memeq(id_digest,
+ if (tor_memeq(ec.node_id,
TO_OR_CIRCUIT(circ)->p_chan->identity_digest,
DIGEST_LEN)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -886,29 +885,34 @@ circuit_extend(cell_t *cell, circuit_t *circ)
return -1;
}
- n_chan = channel_get_for_extend(id_digest,
- &n_addr,
+ n_chan = channel_get_for_extend((const char*)ec.node_id,
+ &ec.orport_ipv4.addr,
&msg,
&should_launch);
if (!n_chan) {
log_debug(LD_CIRC|LD_OR,"Next router (%s): %s",
- fmt_addrport(&n_addr, n_port), msg?msg:"????");
+ fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port),
+ msg?msg:"????");
circ->n_hop = extend_info_new(NULL /*nickname*/,
- id_digest,
- NULL /*onion_key*/,
- &n_addr, n_port);
+ (const char*)ec.node_id,
+ NULL /*onion_key*/,
+ &ec.orport_ipv4.addr,
+ ec.orport_ipv4.port);
- 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;
+ /* XXXX Make sure we can eventually deliver create cell with weird
+ * content */
+ circ->n_chan_create_cell = tor_memdup(&ec.create_cell,
+ sizeof(ec.create_cell));
circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
if (should_launch) {
/* we should try to open a connection */
- n_chan = channel_connect_for_circuit(&n_addr, n_port, id_digest);
+ n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr,
+ ec.orport_ipv4.port,
+ (const char*)ec.node_id);
if (!n_chan) {
log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
@@ -929,8 +933,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
"n_chan is %s",
channel_get_canonical_remote_descr(n_chan));
- if (circuit_deliver_create_cell(circ, CELL_CREATE, (uint8_t*)onionskin,
- TAP_ONIONSKIN_CHALLENGE_LEN) < 0)
+ if (circuit_deliver_create_cell(circ, &ec.create_cell) < 0)
return -1;
return 0;
}
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 2565470..1acb417 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -252,7 +252,7 @@ circuit_set_state(circuit_t *circ, uint8_t state)
smartlist_add(circuits_pending_chans, circ);
}
if (state == CIRCUIT_STATE_OPEN)
- tor_assert(!circ->n_chan_onionskin);
+ tor_assert(!circ->n_chan_create_cell);
circ->state = state;
}
@@ -674,7 +674,7 @@ circuit_free(circuit_t *circ)
}
extend_info_free(circ->n_hop);
- tor_free(circ->n_chan_onionskin);
+ tor_free(circ->n_chan_create_cell);
/* Remove from map. */
circuit_set_n_circid_chan(circ, 0, NULL);
@@ -1582,7 +1582,7 @@ assert_circuit_ok(const circuit_t *c)
tor_assert(c->deliver_window >= 0);
tor_assert(c->package_window >= 0);
if (c->state == CIRCUIT_STATE_OPEN) {
- tor_assert(!c->n_chan_onionskin);
+ tor_assert(!c->n_chan_create_cell);
if (or_circ) {
tor_assert(or_circ->n_crypto);
tor_assert(or_circ->p_crypto);
diff --git a/src/or/or.h b/src/or/or.h
index 5ea420f..66e9054 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2645,6 +2645,8 @@ typedef struct {
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
+struct create_cell_t;
+
/**
* A circuit is a path over the onion routing
* network. Applications can connect to one end of the circuit, and can
@@ -2719,11 +2721,8 @@ typedef struct circuit_t {
* more. */
int deliver_window;
- uint8_t n_chan_onionskin_len; /* XXXX MAKE THIS GET USED. */
- /** For storage while n_chan is pending
- * (state CIRCUIT_STATE_CHAN_WAIT). When defined, it is always
- * length n_chan_onionskin_len */
- char *n_chan_onionskin;
+ /** For storage while n_chan is pending (state CIRCUIT_STATE_CHAN_WAIT). */
+ struct create_cell_t *n_chan_create_cell;
/** When was this circuit created? We keep this timestamp with a higher
* resolution than most so that the circuit-build-time tracking code can
1
0

03 Jan '13
commit 18c7d3f157957a5c8034e165d0fc09490c25b0ba
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Dec 4 21:39:54 2012 -0500
Rename handshake_digest to rend_circ_nonce
The handshake_digest field was never meaningfully a digest *of* the
handshake, but rather is a digest *from* the handshake that we exapted
to prevent replays of ESTABLISH_INTRO cells. The ntor handshake will
generate it as more key material rather than taking it from any part
of the circuit handshake reply..
---
src/or/circuitbuild.c | 6 +++---
src/or/or.h | 7 +++----
src/or/rendmid.c | 4 ++--
src/or/rendservice.c | 6 +++---
4 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 8393ba1..40aad6d 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1409,7 +1409,7 @@ circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
&hop->handshake_state,
reply,
(uint8_t*)keys, sizeof(keys),
- (uint8_t*)hop->handshake_digest) < 0) {
+ (uint8_t*)hop->rend_circ_nonce) < 0) {
log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
return -END_CIRC_REASON_TORPROTOCOL;
}
@@ -1517,9 +1517,9 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
/* XXXX Move responsibility for extracting this. */
if (cell_type == CELL_CREATED)
- memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN);
+ memcpy(circ->rend_circ_nonce, cell.payload+DH_KEY_LEN, DIGEST_LEN);
else
- memcpy(circ->handshake_digest, cell.payload+DIGEST_LEN, DIGEST_LEN);
+ memcpy(circ->rend_circ_nonce, cell.payload+DIGEST_LEN, DIGEST_LEN);
circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
diff --git a/src/or/or.h b/src/or/or.h
index f7407a8..d349d11 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2568,8 +2568,7 @@ typedef struct crypt_path_t {
crypto_dh_t *rend_dh_handshake_state;
/** Negotiated key material shared with the OR at this step. */
- /* XXXX RENAME */
- char handshake_digest[DIGEST_LEN];/* KH in tor-spec.txt */
+ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */
/** Information to extend to the OR at this step. */
extend_info_t *extend_info;
@@ -2978,8 +2977,8 @@ typedef struct or_circuit_t {
char rend_token[REND_TOKEN_LEN];
/* ???? move to a subtype or adjunct structure? Wastes 20 bytes -NM */
- /* XXXX rename this. */
- char handshake_digest[DIGEST_LEN]; /**< Stores KH for the handshake. */
+ /** Stores KH for the handshake. */
+ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */
/** How many more relay_early cells can we send on this circuit, according
* to the specification? */
diff --git a/src/or/rendmid.c b/src/or/rendmid.c
index dc2dc1d..8234265 100644
--- a/src/or/rendmid.c
+++ b/src/or/rendmid.c
@@ -56,8 +56,8 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request,
goto err;
}
- /* Next 20 bytes: Hash of handshake_digest | "INTRODUCE" */
- memcpy(buf, circ->handshake_digest, DIGEST_LEN);
+ /* Next 20 bytes: Hash of rend_circ_nonce | "INTRODUCE" */
+ memcpy(buf, circ->rend_circ_nonce, DIGEST_LEN);
memcpy(buf+DIGEST_LEN, "INTRODUCE", 9);
if (crypto_digest(expected_digest, buf, DIGEST_LEN+9) < 0) {
log_warn(LD_BUG, "Internal error computing digest.");
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 08a7feb..4f3fdf4 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -1382,7 +1382,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
dh = NULL;
if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0)
goto err;
- memcpy(cpath->handshake_digest, keys, DIGEST_LEN);
+ memcpy(cpath->rend_circ_nonce, keys, DIGEST_LEN);
goto done;
@@ -2483,7 +2483,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
len = r;
set_uint16(buf, htons((uint16_t)len));
len += 2;
- memcpy(auth, circuit->cpath->prev->handshake_digest, DIGEST_LEN);
+ memcpy(auth, circuit->cpath->prev->rend_circ_nonce, DIGEST_LEN);
memcpy(auth+DIGEST_LEN, "INTRODUCE", 9);
if (crypto_digest(buf+len, auth, DIGEST_LEN+9))
goto err;
@@ -2630,7 +2630,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
- memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->handshake_digest,
+ memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->rend_circ_nonce,
DIGEST_LEN);
/* Send the cell */
1
0

[tor/master] Implement scheme to allow ntor requests/responses via older servers
by nickm@torproject.org 03 Jan '13
by nickm@torproject.org 03 Jan '13
03 Jan '13
commit 1ed4786dba8912ab7a6eb16adf7554cf9a5c1ed1
Author: Nick Mathewson <nickm(a)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));
1
0

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

[tor/master] Use always_inline only with inline; otherwise GCC gripes
by nickm@torproject.org 03 Jan '13
by nickm@torproject.org 03 Jan '13
03 Jan '13
commit 095c70b7af571a61970ff8d212828b000c26eea2
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu Dec 6 12:08:04 2012 -0500
Use always_inline only with inline; otherwise GCC gripes
---
src/ext/curve25519_donna/curve25519-donna-c64.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/ext/curve25519_donna/curve25519-donna-c64.c b/src/ext/curve25519_donna/curve25519-donna-c64.c
index b8ad62e..38b94e7 100644
--- a/src/ext/curve25519_donna/curve25519-donna-c64.c
+++ b/src/ext/curve25519_donna/curve25519-donna-c64.c
@@ -36,7 +36,7 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
#define force_inline __attribute__((always_inline))
/* Sum two numbers: output += in */
-static void force_inline
+static inline void force_inline
fsum(limb *output, const limb *in) {
output[0] += in[0];
output[1] += in[1];
@@ -51,7 +51,7 @@ fsum(limb *output, const limb *in) {
* Assumes that out[i] < 2**52
* On return, out[i] < 2**55
*/
-static void force_inline
+static inline void force_inline
fdifference_backwards(felem out, const felem in) {
/* 152 is 19 << 3 */
static const limb two54m152 = (((limb)1) << 54) - 152;
@@ -65,7 +65,7 @@ fdifference_backwards(felem out, const felem in) {
}
/* Multiply a number by a scalar: output = in * scalar */
-static void force_inline
+static inline void force_inline
fscalar_product(felem output, const felem in, const limb scalar) {
uint128_t a;
@@ -95,7 +95,7 @@ fscalar_product(felem output, const felem in, const limb scalar) {
* Assumes that in[i] < 2**55 and likewise for in2.
* On return, output[i] < 2**52
*/
-static void force_inline
+static inline void force_inline
fmul(felem output, const felem in2, const felem in) {
uint128_t t[5];
limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;
@@ -144,7 +144,7 @@ fmul(felem output, const felem in2, const felem in) {
output[4] = r4;
}
-static void force_inline
+static inline void force_inline
fsquare_times(felem output, const felem in, limb count) {
uint128_t t[5];
limb r0,r1,r2,r3,r4,c;
1
0

03 Jan '13
commit d907fca29b188be5c8eaf01d086bac754bace400
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu Dec 6 12:07:58 2012 -0500
Make libcurve25519_donna get built as a .a
This lets us give it compiler flags differing from the rest of
libor-crypto.a
---
src/common/include.am | 22 ++++++++++++++--------
src/or/include.am | 3 ++-
src/test/include.am | 6 ++++--
src/tools/include.am | 2 ++
4 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/src/common/include.am b/src/common/include.am
index f986ba6..808238d 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -15,19 +15,25 @@ libor_extra_source=
endif
if BUILD_CURVE25519_DONNA
-libcrypto_extra_source= \
- src/ext/curve25519_donna/curve25519-donna.c \
- src/common/crypto_curve25519.c
+src_common_libcurve25519_donna_a_SOURCES=\
+ src/ext/curve25519_donna/curve25519-donna.c
+noinst_LIBRARIES+=src/common/libcurve25519_donna.a
+LIBDONNA=src/common/libcurve25519_donna.a
else
if BUILD_CURVE25519_DONNA_C64
-libcrypto_extra_source= \
- src/ext/curve25519_donna/curve25519-donna-c64.c \
- src/common/crypto_curve25519.c
+src_common_libcurve25519_donna_a_SOURCES=\
+ src/ext/curve25519_donna/curve25519-donna-c64.c
+noinst_LIBRARIES+=src/common/libcurve25519_donna.a
+LIBDONNA=src/common/libcurve25519_donna.a
else
-if CURVE25519_ENABLED
-libcrypto_extra_source=src/common/crypto_curve25519.c
+LIBDONNA=
endif
endif
+
+src_common_libcurve25519_donna_a_CFLAGS =
+
+if CURVE25519_ENABLED
+libcrypto_extra_source=src/common/crypto_curve25519.c
endif
src_common_libor_a_SOURCES = \
diff --git a/src/or/include.am b/src/or/include.am
index 600f9d5..08a27e1 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -95,7 +95,8 @@ AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \
src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
-src_or_tor_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypto.a \
+src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
src/common/libor-event.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_LIB_WS32@ @TOR_LIB_GDI@
diff --git a/src/test/include.am b/src/test/include.am
index 075df36..e4f2897 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -36,14 +36,16 @@ src_test_bench_CPPFLAGS= $(src_test_AM_CPPFLAGS)
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
-src_test_test_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypto.a \
+src_test_test_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
src/common/libor-event.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
-src_test_bench_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypto.a \
+src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
src/common/libor-event.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
diff --git a/src/tools/include.am b/src/tools/include.am
index 7337eff..610864f 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -8,12 +8,14 @@ src_tools_tor_resolve_LDADD = src/common/libor.a @TOR_LIB_MATH@ @TOR_LIB_WS32@
src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c
src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
src_tools_tor_gencert_LDADD = src/common/libor.a src/common/libor-crypto.a \
+ $(LIBDONNA) \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_LIB_WS32@ @TOR_LIB_GDI@
src_tools_tor_checkkey_SOURCES = src/tools/tor-checkkey.c
src_tools_tor_checkkey_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
src_tools_tor_checkkey_LDADD = src/common/libor.a src/common/libor-crypto.a \
+ $(LIBDONNA) \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_LIB_WS32@ @TOR_LIB_GDI@
1
0

[tor/master] Code to parse and format CREATE{, 2, _FAST} cells and their allies
by nickm@torproject.org 03 Jan '13
by nickm@torproject.org 03 Jan '13
03 Jan '13
commit 5d15d597a9059d0f87ced081e187db622caa7978
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Dec 5 16:47:22 2012 -0500
Code to parse and format CREATE{,2,_FAST} cells and their allies
As elsewhere, it makes sense when adding or extending a cell type to
actually make the code to parse it into a separate tested function.
This commit doesn't actually make anything use these new functions;
that's for a later commit.
---
src/or/onion.c | 519 +++++++++++++++++++++++++++++++++++++++++-
src/or/onion.h | 61 +++++
src/or/or.h | 4 +
src/test/test_cell_formats.c | 455 ++++++++++++++++++++++++++++++++++++
4 files changed, 1037 insertions(+), 2 deletions(-)
diff --git a/src/or/onion.c b/src/or/onion.c
index 90fc830..c1f2e5b 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -6,8 +6,8 @@
/**
* \file onion.c
- * \brief Functions to queue create cells, handle onionskin
- * parsing and creation, and wrap the various onionskin types.
+ * \brief Functions to queue create cells, wrap the various onionskin types,
+ * and parse and create the CREATE cell and its allies.
**/
#include "or.h"
@@ -17,6 +17,7 @@
#include "onion_fast.h"
#include "onion_ntor.h"
#include "onion_tap.h"
+#include "relay.h"
#include "rephist.h"
#include "router.h"
@@ -410,3 +411,517 @@ onion_skin_client_handshake(int type,
}
}
+/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. If
+ * <b>unknown_ok</b> is true, allow cells with handshake types we don't
+ * recognize. */
+static int
+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)
+ return -1;
+ break;
+ case CELL_CREATE_FAST:
+ if (cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST)
+ return -1;
+ break;
+ case CELL_CREATE2:
+ break;
+ default:
+ return -1;
+ }
+
+ switch (cell->handshake_type) {
+ case ONION_HANDSHAKE_TYPE_TAP:
+ if (cell->handshake_len != TAP_ONIONSKIN_CHALLENGE_LEN)
+ return -1;
+ break;
+ case ONION_HANDSHAKE_TYPE_FAST:
+ if (cell->handshake_len != CREATE_FAST_LEN)
+ return -1;
+ break;
+#ifdef CURVE25519_ENABLED
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ if (cell->handshake_len != NTOR_ONIONSKIN_LEN)
+ return -1;
+ break;
+#endif
+ default:
+ if (! unknown_ok)
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Helper: parse the CREATE2 payload at <b>p</b>, which could be up to
+ * <b>p_len</b> bytes long, and use it to fill the fields of
+ * <b>cell_out</b>. Return 0 on success and -1 on failure.
+ *
+ * Note that part of the body of an EXTEND2 cell is a CREATE2 payload, so
+ * this function is also used for parsing those.
+ */
+static int
+parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len)
+{
+ if (p_len < 4)
+ return -1;
+ cell_out->cell_type = CELL_CREATE2;
+ cell_out->handshake_type = ntohs(get_uint16(p));
+ cell_out->handshake_len = ntohs(get_uint16(p+2));
+ if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 4 ||
+ cell_out->handshake_len > p_len - 4)
+ return -1;
+ memcpy(cell_out->onionskin, p+4, cell_out->handshake_len);
+ return 0;
+}
+
+/** 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.) */
+int
+create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in)
+{
+ memset(cell_out, 0, sizeof(*cell_out));
+
+ 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);
+ break;
+ case CELL_CREATE_FAST:
+ cell_out->cell_type = CELL_CREATE_FAST;
+ cell_out->handshake_type = ONION_HANDSHAKE_TYPE_FAST;
+ cell_out->handshake_len = CREATE_FAST_LEN;
+ memcpy(cell_out->onionskin, cell_in->payload, CREATE_FAST_LEN);
+ break;
+ case CELL_CREATE2:
+ if (parse_create2_payload(cell_out, cell_in->payload,
+ CELL_PAYLOAD_SIZE) < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ return check_create_cell(cell_out, 0);
+}
+
+/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. */
+static int
+check_created_cell(const created_cell_t *cell)
+{
+ switch (cell->cell_type) {
+ case CELL_CREATED:
+ if (cell->handshake_len != TAP_ONIONSKIN_REPLY_LEN)
+ return -1;
+ break;
+ case CELL_CREATED_FAST:
+ if (cell->handshake_len != CREATED_FAST_LEN)
+ return -1;
+ break;
+ case CELL_CREATED2:
+ if (cell->handshake_len > RELAY_PAYLOAD_SIZE-2)
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+/** Parse a CREATED, CREATED_FAST, or CREATED2 cell from <b>cell_in</b> into
+ * <b>cell_out</b>. Return 0 on success, -1 on failure. */
+int
+created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
+{
+ memset(cell_out, 0, sizeof(*cell_out));
+
+ switch (cell_in->command) {
+ case CELL_CREATED:
+ cell_out->cell_type = CELL_CREATED;
+ cell_out->handshake_len = TAP_ONIONSKIN_REPLY_LEN;
+ memcpy(cell_out->reply, cell_in->payload, TAP_ONIONSKIN_REPLY_LEN);
+ break;
+ case CELL_CREATED_FAST:
+ cell_out->cell_type = CELL_CREATED_FAST;
+ cell_out->handshake_len = CREATED_FAST_LEN;
+ memcpy(cell_out->reply, cell_in->payload, CREATED_FAST_LEN);
+ break;
+ case CELL_CREATED2:
+ {
+ const uint8_t *p = cell_in->payload;
+ cell_out->cell_type = CELL_CREATED2;
+ cell_out->handshake_len = ntohs(get_uint16(p));
+ if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 2)
+ return -1;
+ memcpy(cell_out->reply, p+2, cell_out->handshake_len);
+ break;
+ }
+ }
+
+ return check_created_cell(cell_out);
+}
+
+/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. */
+static int
+check_extend_cell(const extend_cell_t *cell)
+{
+ if (tor_digest_is_zero((const char*)cell->node_id))
+ return -1;
+ /* We don't currently allow EXTEND2 cells without an IPv4 address */
+ if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC)
+ return -1;
+ if (cell->create_cell.cell_type == CELL_CREATE) {
+ 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)
+ return -1;
+ } else {
+ /* In particular, no CREATE_FAST cells are allowed */
+ return -1;
+ }
+ if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST)
+ return -1;
+
+ return check_create_cell(&cell->create_cell, 1);
+}
+
+/** Protocol constants for specifier types in EXTEND2
+ * @{
+ */
+#define SPECTYPE_IPV4 0
+#define SPECTYPE_IPV6 1
+#define SPECTYPE_LEGACY_ID 2
+/** @} */
+
+/** Parse an EXTEND or EXTEND2 cell (according to <b>command</b>) from the
+ * <b>payload_length</b> bytes of <b>payload</b> into <b>cell_out</b>. Return
+ * 0 on success, -1 on failure. */
+int
+extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
+ const uint8_t *payload, size_t payload_length)
+{
+ const uint8_t *eop;
+
+ memset(cell_out, 0, sizeof(*cell_out));
+ if (payload_length > RELAY_PAYLOAD_SIZE)
+ return -1;
+ eop = payload + payload_length;
+
+ switch (command) {
+ case RELAY_COMMAND_EXTEND:
+ {
+ if (payload_length != 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN)
+ return -1;
+
+ cell_out->cell_type = RELAY_COMMAND_EXTEND;
+ 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);
+ memcpy(cell_out->node_id, payload + 6 + TAP_ONIONSKIN_CHALLENGE_LEN,
+ DIGEST_LEN);
+ break;
+ }
+ case RELAY_COMMAND_EXTEND2:
+ {
+ uint8_t n_specs = *payload, spectype, speclen;
+ int i;
+ int found_ipv4 = 0, found_ipv6 = 0, found_id = 0;
+ tor_addr_make_unspec(&cell_out->orport_ipv4.addr);
+ tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
+
+ cell_out->cell_type = RELAY_COMMAND_EXTEND2;
+ ++payload;
+ /* Parse the specifiers. We'll only take the first IPv4 and first IPv6
+ * addres, and the node ID, and ignore everything else */
+ for (i = 0; i < n_specs; ++i) {
+ if (eop - payload < 2)
+ return -1;
+ spectype = payload[0];
+ speclen = payload[1];
+ payload += 2;
+ if (eop - payload < speclen)
+ return -1;
+ switch (spectype) {
+ case SPECTYPE_IPV4:
+ if (speclen != 6)
+ return -1;
+ if (!found_ipv4) {
+ tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr,
+ get_uint32(payload));
+ cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4));
+ found_ipv4 = 1;
+ }
+ break;
+ case SPECTYPE_IPV6:
+ if (speclen != 18)
+ return -1;
+ if (!found_ipv6) {
+ tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr,
+ (const char*)payload);
+ cell_out->orport_ipv6.port = ntohs(get_uint16(payload+16));
+ found_ipv6 = 1;
+ }
+ break;
+ case SPECTYPE_LEGACY_ID:
+ if (speclen != 20)
+ return -1;
+ if (found_id)
+ return -1;
+ memcpy(cell_out->node_id, payload, 20);
+ found_id = 1;
+ break;
+ }
+ payload += speclen;
+ }
+ if (!found_id || !found_ipv4)
+ return -1;
+ if (parse_create2_payload(&cell_out->create_cell,payload,eop-payload)<0)
+ return -1;
+
+ break;
+ }
+ default:
+ return -1;
+ }
+
+ return check_extend_cell(cell_out);
+}
+
+/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. */
+static int
+check_extended_cell(const extended_cell_t *cell)
+{
+ if (cell->created_cell.cell_type == CELL_CREATED) {
+ if (cell->cell_type != RELAY_COMMAND_EXTENDED)
+ return -1;
+ } else if (cell->created_cell.cell_type == CELL_CREATED2) {
+ if (cell->cell_type != RELAY_COMMAND_EXTENDED2)
+ return -1;
+ } else {
+ return -1;
+ }
+
+ return check_created_cell(&cell->created_cell);
+}
+
+/** Parse an EXTENDED or EXTENDED2 cell (according to <b>command</b>) from the
+ * <b>payload_length</b> bytes of <b>payload</b> into <b>cell_out</b>. Return
+ * 0 on success, -1 on failure. */
+int
+extended_cell_parse(extended_cell_t *cell_out,
+ const uint8_t command, const uint8_t *payload,
+ size_t payload_len)
+{
+ const uint8_t *eop;
+
+ memset(cell_out, 0, sizeof(*cell_out));
+ if (payload_len > RELAY_PAYLOAD_SIZE)
+ return -1;
+ eop = payload + payload_len;
+
+ switch (command) {
+ case RELAY_COMMAND_EXTENDED:
+ if (payload_len != TAP_ONIONSKIN_REPLY_LEN)
+ return -1;
+ cell_out->cell_type = RELAY_COMMAND_EXTENDED;
+ cell_out->created_cell.cell_type = CELL_CREATED;
+ cell_out->created_cell.handshake_len = TAP_ONIONSKIN_REPLY_LEN;
+ memcpy(cell_out->created_cell.reply, payload, TAP_ONIONSKIN_REPLY_LEN);
+ break;
+ case RELAY_COMMAND_EXTENDED2:
+ {
+ cell_out->cell_type = RELAY_COMMAND_EXTENDED2;
+ cell_out->created_cell.cell_type = CELL_CREATED2;
+ cell_out->created_cell.handshake_len = ntohs(get_uint16(payload));
+ if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE - 2 ||
+ cell_out->created_cell.handshake_len > payload_len - 2)
+ return -1;
+ memcpy(cell_out->created_cell.reply, payload+2,
+ cell_out->created_cell.handshake_len);
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return check_extended_cell(cell_out);
+}
+
+/** Fill <b>cell_out</b> with a correctly formatted version of the
+ * CREATE{,_FAST,2} cell in <b>cell_in</b>. Return 0 on success, -1 on
+ * failure. */
+int
+create_cell_format(cell_t *cell_out, const create_cell_t *cell_in)
+{
+ 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;
+
+ switch (cell_in->cell_type) {
+ case CELL_CREATE:
+ 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);
+ break;
+ case CELL_CREATE2:
+ tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-4);
+ set_uint16(cell_out->payload, htons(cell_in->handshake_type));
+ set_uint16(cell_out->payload+2, htons(cell_in->handshake_len));
+ memcpy(cell_out->payload + 4, cell_in->onionskin, cell_in->handshake_len);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Fill <b>cell_out</b> with a correctly formatted version of the
+ * CREATED{,_FAST,2} cell in <b>cell_in</b>. Return 0 on success, -1 on
+ * failure. */
+int
+created_cell_format(cell_t *cell_out, const created_cell_t *cell_in)
+{
+ if (check_created_cell(cell_in) < 0)
+ return -1;
+
+ memset(cell_out->payload, 0, sizeof(cell_out->payload));
+ cell_out->command = cell_in->cell_type;
+
+ switch (cell_in->cell_type) {
+ case CELL_CREATED:
+ case CELL_CREATED_FAST:
+ tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload));
+ memcpy(cell_out->payload, cell_in->reply, cell_in->handshake_len);
+ break;
+ case CELL_CREATED2:
+ tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-2);
+ set_uint16(cell_out->payload, htons(cell_in->handshake_len));
+ memcpy(cell_out->payload + 2, cell_in->reply, cell_in->handshake_len);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/** Format the EXTEND{,2} cell in <b>cell_in</b>, storing its relay payload in
+ * <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the
+ * relay command in *<b>command_out</b>. The <b>payload_out</b> must have
+ * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */
+int
+extend_cell_format(uint8_t *command_out, uint16_t *len_out,
+ uint8_t *payload_out, const extend_cell_t *cell_in)
+{
+ uint8_t *p, *eop;
+ if (check_extend_cell(cell_in) < 0)
+ return -1;
+
+ p = payload_out;
+ eop = payload_out + RELAY_PAYLOAD_SIZE;
+
+ memset(p, 0, RELAY_PAYLOAD_SIZE);
+
+ switch (cell_in->cell_type) {
+ case RELAY_COMMAND_EXTEND:
+ {
+ *command_out = RELAY_COMMAND_EXTEND;
+ *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);
+ memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN);
+ }
+ break;
+ case RELAY_COMMAND_EXTEND2:
+ {
+ uint8_t n = 2;
+ *command_out = RELAY_COMMAND_EXTEND2;
+
+ *p++ = n; /* 2 identifiers */
+ *p++ = SPECTYPE_IPV4; /* First is IPV4. */
+ *p++ = 6; /* It's 6 bytes long. */
+ set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr));
+ set_uint16(p+4, htons(cell_in->orport_ipv4.port));
+ p += 6;
+ *p++ = SPECTYPE_LEGACY_ID; /* Next is an identity digest. */
+ *p++ = 20; /* It's 20 bytes long */
+ memcpy(p, cell_in->node_id, DIGEST_LEN);
+ p += 20;
+
+ /* Now we can send the handshake */
+ set_uint16(p, htons(cell_in->create_cell.handshake_type));
+ set_uint16(p+2, htons(cell_in->create_cell.handshake_len));
+ p += 4;
+
+ if (cell_in->create_cell.handshake_len > eop - p)
+ return -1;
+
+ memcpy(p, cell_in->create_cell.onionskin,
+ cell_in->create_cell.handshake_len);
+
+ p += cell_in->create_cell.handshake_len;
+ *len_out = p - payload_out;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Format the EXTENDED{,2} cell in <b>cell_in</b>, storing its relay payload
+ * in <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the
+ * relay command in *<b>command_out</b>. The <b>payload_out</b> must have
+ * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */
+int
+extended_cell_format(uint8_t *command_out, uint16_t *len_out,
+ uint8_t *payload_out, const extended_cell_t *cell_in)
+{
+ uint8_t *p, *eop;
+ if (check_extended_cell(cell_in) < 0)
+ return -1;
+
+ p = payload_out;
+ eop = payload_out + RELAY_PAYLOAD_SIZE;
+ memset(p, 0, RELAY_PAYLOAD_SIZE);
+
+ switch (cell_in->cell_type) {
+ case RELAY_COMMAND_EXTENDED:
+ {
+ *command_out = RELAY_COMMAND_EXTENDED;
+ *len_out = TAP_ONIONSKIN_REPLY_LEN;
+ memcpy(payload_out, cell_in->created_cell.reply,
+ TAP_ONIONSKIN_REPLY_LEN);
+ }
+ break;
+ case RELAY_COMMAND_EXTENDED2:
+ {
+ *command_out = RELAY_COMMAND_EXTENDED2;
+ *len_out = 2 + cell_in->created_cell.handshake_len;
+ set_uint16(payload_out, htons(cell_in->created_cell.handshake_len));
+ memcpy(payload_out+2, cell_in->created_cell.reply,
+ cell_in->created_cell.handshake_len);
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/src/or/onion.h b/src/or/onion.h
index 3c12e1f..08e1a22 100644
--- a/src/or/onion.h
+++ b/src/or/onion.h
@@ -50,5 +50,66 @@ int onion_skin_client_handshake(int type,
uint8_t *keys_out, size_t key_out_len,
uint8_t *rend_authenticator_out);
+/** A parsed CREATE, CREATE_FAST, or CREATE2 cell. */
+typedef struct create_cell_t {
+ /** The cell command. One of CREATE{,_FAST,2} */
+ uint8_t cell_type;
+ /** One of the ONION_HANDSHAKE_TYPE_* values */
+ uint16_t handshake_type;
+ /** The number of bytes used in <b>onionskin</b>. */
+ uint16_t handshake_len;
+ /** The client-side message for the circuit creation handshake. */
+ uint8_t onionskin[CELL_PAYLOAD_SIZE - 4];
+} create_cell_t;
+
+/** A parsed CREATED, CREATED_FAST, or CREATED2 cell. */
+typedef struct created_cell_t {
+ /** The cell command. One of CREATED{,_FAST,2} */
+ uint8_t cell_type;
+ /** The number of bytes used in <b>reply</b>. */
+ uint16_t handshake_len;
+ /** The server-side message for the circuit creation handshake. */
+ uint8_t reply[CELL_PAYLOAD_SIZE - 2];
+} created_cell_t;
+
+/** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */
+typedef struct extend_cell_t {
+ /** One of RELAY_EXTEND or RELAY_EXTEND2 */
+ uint8_t cell_type;
+ /** An IPv4 address and port for the node we're connecting to. */
+ tor_addr_port_t orport_ipv4;
+ /** An IPv6 address and port for the node we're connecting to. Not currently
+ * used. */
+ tor_addr_port_t orport_ipv6;
+ /** Identity fingerprint of the node we're conecting to.*/
+ uint8_t node_id[DIGEST_LEN];
+ /** The "create cell" embedded in this extend cell. Note that unlike the
+ * create cells we generate ourself, this once can have a handshake type we
+ * don't recognize. */
+ create_cell_t create_cell;
+} extend_cell_t;
+
+/** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */
+typedef struct extended_cell_t {
+ /** One of RELAY_EXTENDED or RELAY_EXTENDED2. */
+ uint8_t cell_type;
+ /** The "created cell" embedded in this extended cell. */
+ created_cell_t created_cell;
+} extended_cell_t;
+
+int create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in);
+int created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in);
+int extend_cell_parse(extend_cell_t *cell_out, uint8_t command,
+ const uint8_t *payload_in, size_t payload_len);
+int extended_cell_parse(extended_cell_t *cell_out, uint8_t command,
+ const uint8_t *payload_in, size_t payload_len);
+
+int create_cell_format(cell_t *cell_out, const create_cell_t *cell_in);
+int created_cell_format(cell_t *cell_out, const created_cell_t *cell_in);
+int extend_cell_format(uint8_t *command_out, uint16_t *len_out,
+ uint8_t *payload_out, const extend_cell_t *cell_in);
+int extended_cell_format(uint8_t *command_out, uint16_t *len_out,
+ uint8_t *payload_out, const extended_cell_t *cell_in);
+
#endif
diff --git a/src/or/or.h b/src/or/or.h
index d349d11..f9b0f1e 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -561,6 +561,8 @@ typedef enum {
#define RELAY_COMMAND_RESOLVE 11
#define RELAY_COMMAND_RESOLVED 12
#define RELAY_COMMAND_BEGIN_DIR 13
+#define RELAY_COMMAND_EXTEND2 14
+#define RELAY_COMMAND_EXTENDED2 15
#define RELAY_COMMAND_ESTABLISH_INTRO 32
#define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33
@@ -827,6 +829,8 @@ typedef enum {
#define CELL_VERSIONS 7
#define CELL_NETINFO 8
#define CELL_RELAY_EARLY 9
+#define CELL_CREATE2 10
+#define CELL_CREATED2 11
#define CELL_VPADDING 128
#define CELL_CERTS 129
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index 4222c79..2af87af 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -9,6 +9,10 @@
#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"
@@ -374,6 +378,453 @@ test_cfmt_connected_cells(void *arg)
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
+
+ /* == 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)
+{
+ 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);
+
+ /* 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);
+
+ /* == 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 }
@@ -381,6 +832,10 @@ 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
};
1
0
commit ed3c8d9d448d1e1143c8cc9f5878b6fa92ff05d0
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Sat Dec 8 01:19:15 2012 -0500
Document UseNTorHandshake
---
doc/tor.1.txt | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 1a7f8d5..2af3572 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1163,6 +1163,16 @@ The following options are useful only for clients (that is, if
"auto" (recommended) then it is on for all clients that do not set
FetchUselessDescriptors. (Default: auto)
+**UseNTorHandshake** **0**|**1**|**auto**::
+ The "ntor" circuit-creation handshake is faster and (we think) more
+ secure than the original ("TAP") circuit handshake, but starting to use
+ it too early might make your client stand out. If this option is 0, your
+ Tor client won't use the ntor handshake. If it's 1, your Tor client
+ will use the ntor handshake to extend circuits through servers that
+ support it. If this option is "auto" (recommended), then your client
+ will use the ntor handshake once enough directory authorities recommend
+ it. (Default: auto)
+
**PathBiasCircThreshold** __NUM__ +
**PathBiasNoticeRate** __NUM__ +
1
0
commit ef13bf44327464c5600fdba12726fce00156d2b2
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu Dec 6 11:49:39 2012 -0500
Fix an unused-variable warning
---
src/or/onion.c | 8 +++-----
1 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/or/onion.c b/src/or/onion.c
index b42a66c..3f0b0b1 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -771,12 +771,9 @@ extended_cell_parse(extended_cell_t *cell_out,
const uint8_t command, const uint8_t *payload,
size_t payload_len)
{
- const uint8_t *eop;
-
memset(cell_out, 0, sizeof(*cell_out));
if (payload_len > RELAY_PAYLOAD_SIZE)
return -1;
- eop = payload + payload_len;
switch (command) {
case RELAY_COMMAND_EXTENDED:
@@ -970,12 +967,11 @@ int
extended_cell_format(uint8_t *command_out, uint16_t *len_out,
uint8_t *payload_out, const extended_cell_t *cell_in)
{
- uint8_t *p, *eop;
+ uint8_t *p;
if (check_extended_cell(cell_in) < 0)
return -1;
p = payload_out;
- eop = payload_out + RELAY_PAYLOAD_SIZE;
memset(p, 0, RELAY_PAYLOAD_SIZE);
switch (cell_in->cell_type) {
@@ -992,6 +988,8 @@ extended_cell_format(uint8_t *command_out, uint16_t *len_out,
*command_out = RELAY_COMMAND_EXTENDED2;
*len_out = 2 + cell_in->created_cell.handshake_len;
set_uint16(payload_out, htons(cell_in->created_cell.handshake_len));
+ if (2+cell_in->created_cell.handshake_len > RELAY_PAYLOAD_SIZE)
+ return -1;
memcpy(payload_out+2, cell_in->created_cell.reply,
cell_in->created_cell.handshake_len);
}
1
0

03 Jan '13
commit 115e8fe9a5342d9f04e14d155d11e8c88f551c84
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Dec 5 23:44:27 2012 -0500
Use created_cell_format where appropriate
---
src/or/circuitbuild.c | 19 ++++++++++---------
src/or/circuitbuild.h | 4 ++--
src/or/command.c | 11 ++++++++---
src/or/cpuworker.c | 4 +---
src/or/onion.c | 3 ++-
5 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 5ac2692..43ad9f4 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1471,24 +1471,25 @@ circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason)
* cell back.
*/
int
-onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
- size_t payload_len, const char *keys,
+onionskin_answer(or_circuit_t *circ,
+ const created_cell_t *created_cell,
+ const char *keys,
const uint8_t *rend_circ_nonce)
{
cell_t cell;
crypt_path_t *tmp_cpath;
+ if (created_cell_format(&cell, created_cell) < 0) {
+ log_warn(LD_BUG,"couldn't format created cell");
+ return -1;
+ }
+ cell.circ_id = circ->p_circ_id;
+
tmp_cpath = tor_malloc_zero(sizeof(crypt_path_t));
tmp_cpath->magic = CRYPT_PATH_MAGIC;
- memset(&cell, 0, sizeof(cell_t));
- cell.command = cell_type;
- cell.circ_id = circ->p_circ_id;
-
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
- memcpy(cell.payload, payload, payload_len);
-
log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
(unsigned int)get_uint32(keys),
(unsigned int)get_uint32(keys+20));
@@ -1506,7 +1507,7 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
- circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
+ circ->is_first_hop = (created_cell->cell_type == CELL_CREATED_FAST);
append_cell_to_circuit_queue(TO_CIRCUIT(circ),
circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index e53e6ba..23213e8 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -35,8 +35,8 @@ int circuit_finish_handshake(origin_circuit_t *circ,
const struct created_cell_t *created_cell);
int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer,
int reason);
-int onionskin_answer(or_circuit_t *circ, uint8_t cell_type,
- const char *payload, size_t payload_len,
+int onionskin_answer(or_circuit_t *circ,
+ const struct created_cell_t *created_cell,
const char *keys,
const uint8_t *rend_circ_nonce);
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
diff --git a/src/or/command.c b/src/or/command.c
index c77e2ec..773d19c 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -274,19 +274,21 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
/* This is a CREATE_FAST cell; we can handle it immediately without using
* a CPU worker. */
uint8_t keys[CPATH_KEY_MATERIAL_LEN];
- uint8_t reply[MAX_ONIONSKIN_REPLY_LEN];
uint8_t rend_circ_nonce[DIGEST_LEN];
int len;
+ created_cell_t created_cell;
/* Make sure we never try to use the OR connection on which we
* received this cell to satisfy an EXTEND request, */
channel_mark_client(chan);
+ memset(&created_cell, 0, sizeof(created_cell));
len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST,
create_cell->onionskin,
create_cell->handshake_len,
NULL,
- reply, keys, CPATH_KEY_MATERIAL_LEN,
+ created_cell.reply,
+ keys, CPATH_KEY_MATERIAL_LEN,
rend_circ_nonce);
tor_free(create_cell);
if (len < 0) {
@@ -295,7 +297,10 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
tor_free(create_cell);
return;
}
- if (onionskin_answer(circ, CELL_CREATED_FAST, (const char *)reply, len,
+ created_cell.cell_type = CELL_CREATED_FAST;
+ created_cell.handshake_len = len;
+
+ if (onionskin_answer(circ, &created_cell,
(const char *)keys, rend_circ_nonce)<0) {
log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index a8ec027..1ac8cd5 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -206,9 +206,7 @@ connection_cpu_process_inbuf(connection_t *conn)
}
tor_assert(! CIRCUIT_IS_ORIGIN(circ));
if (onionskin_answer(TO_OR_CIRCUIT(circ),
- rpl.created_cell.cell_type,
- (const char*)rpl.created_cell.reply,
- rpl.created_cell.handshake_len,
+ &rpl.created_cell,
(const char*)rpl.keys,
rpl.rend_auth_material) < 0) {
log_warn(LD_OR,"onionskin_answer failed. Closing.");
diff --git a/src/or/onion.c b/src/or/onion.c
index 9326c2f..ce5eb93 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -496,6 +496,8 @@ parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len)
if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 4 ||
cell_out->handshake_len > p_len - 4)
return -1;
+ if (cell_out->handshake_type == ONION_HANDSHAKE_TYPE_FAST)
+ return -1;
memcpy(cell_out->onionskin, p+4, cell_out->handshake_len);
return 0;
}
@@ -710,7 +712,6 @@ extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
return -1;
if (parse_create2_payload(&cell_out->create_cell,payload,eop-payload)<0)
return -1;
-
break;
}
default:
1
0