From 5b3dd1610cf2147509167332bf298fc821e6a102 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 4 Dec 2012 15:58:18 -0500 Subject: Wrangle curve25519 onion keys: generate, store, load, publish, republish Here we try to handle curve25519 onion keys from generating them, loading and storing them, publishing them in our descriptors, putting them in microdescriptors, and so on. This commit is untested and probably buggy like whoa --- src/or/or.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/or/or.h') diff --git a/src/or/or.h b/src/or/or.h index 2ac9f6bde..219336bf7 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -99,6 +99,7 @@ #include "compat_libevent.h" #include "ht.h" #include "replaycache.h" +#include "crypto_curve25519.h" /* These signals are defined to help handle_control_signal work. */ @@ -1893,6 +1894,8 @@ typedef struct { crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */ crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ + /** Public curve25519 key for onions */ + curve25519_public_key_t *onion_curve25519_pkey; char *platform; /**< What software/operating system is this OR using? */ @@ -2106,6 +2109,8 @@ typedef struct microdesc_t { /** As routerinfo_t.onion_pkey */ crypto_pk_t *onion_pkey; + /** As routerinfo_t.onion_curve25519_pkey */ + curve25519_public_key_t *onion_curve25519_pkey; /** As routerinfo_t.ipv6_add */ tor_addr_t ipv6_addr; /** As routerinfo_t.ipv6_orport */ -- cgit v1.2.3 From 5fa1c7484cba293e6467acbca06a4143ce9da68d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 4 Dec 2012 16:51:31 -0500 Subject: Refactor the CREATE_FAST handshake code to match the others. --- src/or/circuitbuild.c | 11 +++++++---- src/or/circuitlist.c | 2 ++ src/or/onion_fast.c | 26 ++++++++++++++++++++++++-- src/or/onion_fast.h | 16 ++++++++++++++-- src/or/or.h | 3 ++- 5 files changed, 49 insertions(+), 9 deletions(-) (limited to 'src/or/or.h') diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 33a13515e..b6cf1252f 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -645,11 +645,14 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) * new OR: we can be speedy and use CREATE_FAST to save an RSA operation * and a DH operation. */ cell_type = CELL_CREATE_FAST; + memset(payload, 0, sizeof(payload)); - crypto_rand((char*) circ->cpath->fast_handshake_state, - sizeof(circ->cpath->fast_handshake_state)); - memcpy(payload, circ->cpath->fast_handshake_state, - sizeof(circ->cpath->fast_handshake_state)); + if (fast_onionskin_create(&circ->cpath->fast_handshake_state, + (uint8_t *)payload) < 0) { + log_warn(LD_CIRC,"onion_skin_create FAST (first hop) failed."); + return - END_CIRC_REASON_INTERNAL; + } + note_request("cell: create fast", 1); } diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index abb83954a..2c17fd2bb 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -23,6 +23,7 @@ #include "networkstatus.h" #include "nodelist.h" #include "onion.h" +#include "onion_fast.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" @@ -744,6 +745,7 @@ circuit_free_cpath_node(crypt_path_t *victim) crypto_digest_free(victim->f_digest); crypto_digest_free(victim->b_digest); crypto_dh_free(victim->dh_handshake_state); + fast_handshake_state_free(victim->fast_handshake_state); extend_info_free(victim->extend_info); memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */ diff --git a/src/or/onion_fast.c b/src/or/onion_fast.c index 8d09de7b7..f33b048c2 100644 --- a/src/or/onion_fast.c +++ b/src/or/onion_fast.c @@ -12,6 +12,28 @@ #include "or.h" #include "onion_fast.h" +/**DOCDOC*/ +void +fast_handshake_state_free(fast_handshake_state_t *victim) +{ + if (! victim) + return; + memwipe(victim, 0, sizeof(fast_handshake_state_t)); + tor_free(victim); +} + +/** DOCDOC */ +int +fast_onionskin_create(fast_handshake_state_t **handshake_state_out, + uint8_t *handshake_out) +{ + fast_handshake_state_t *s; + *handshake_state_out = s =tor_malloc(sizeof(fast_handshake_state_t)); + crypto_rand((char*)s->state, sizeof(s->state)); + memcpy(handshake_out, s->state, DIGEST_LEN); + return 0; +} + /** Implement the server side of the CREATE_FAST abbreviated handshake. The * client has provided DIGEST_LEN key bytes in key_in ("x"). We * generate a reply of DIGEST_LEN*2 bytes in key_out, consisting of a @@ -63,7 +85,7 @@ fast_server_handshake(const uint8_t *key_in, /* DIGEST_LEN bytes */ * and protected by TLS). */ int -fast_client_handshake(const uint8_t *handshake_state,/*DIGEST_LEN bytes*/ +fast_client_handshake(const fast_handshake_state_t *handshake_state, const uint8_t *handshake_reply_out,/*DIGEST_LEN*2 bytes*/ uint8_t *key_out, size_t key_out_len) @@ -73,7 +95,7 @@ fast_client_handshake(const uint8_t *handshake_state,/*DIGEST_LEN bytes*/ size_t out_len; int r = -1; - memcpy(tmp, handshake_state, DIGEST_LEN); + memcpy(tmp, handshake_state->state, DIGEST_LEN); memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN); out_len = key_out_len+DIGEST_LEN; out = tor_malloc(out_len); diff --git a/src/or/onion_fast.h b/src/or/onion_fast.h index 5c9d59ec6..2d652cc53 100644 --- a/src/or/onion_fast.h +++ b/src/or/onion_fast.h @@ -12,12 +12,24 @@ #ifndef TOR_ONION_FAST_H #define TOR_ONION_FAST_H -int fast_server_handshake(const uint8_t *key_in, +#define CREATE_FAST_LEN DIGEST_LEN +#define CREATED_FAST_LEN DIGEST_LEN*2 + +typedef struct fast_handshake_state_t { + uint8_t state[DIGEST_LEN]; +} fast_handshake_state_t; + +void fast_handshake_state_free(fast_handshake_state_t *victim); + +int fast_onionskin_create(fast_handshake_state_t **handshake_state_out, + uint8_t *handshake_out); + +int fast_server_handshake(const uint8_t *message_in, uint8_t *handshake_reply_out, uint8_t *key_out, size_t key_out_len); -int fast_client_handshake(const uint8_t *handshake_state, +int fast_client_handshake(const fast_handshake_state_t *handshake_state, const uint8_t *handshake_reply_out, uint8_t *key_out, size_t key_out_len); diff --git a/src/or/or.h b/src/or/or.h index 219336bf7..6fada7700 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2524,6 +2524,7 @@ typedef enum { #define CRYPT_PATH_MAGIC 0x70127012u +struct fast_handshake_state_t; /** Holds accounting information for a single step in the layered encryption * performed by a circuit. Used only at the client edge of a circuit. */ typedef struct crypt_path_t { @@ -2550,7 +2551,7 @@ typedef struct crypt_path_t { * authentication, secrecy, and integrity we need, and we're already * distinguishable from an OR. */ - uint8_t fast_handshake_state[DIGEST_LEN]; + struct fast_handshake_state_t *fast_handshake_state; /** Negotiated key material shared with the OR at this step. */ char handshake_digest[DIGEST_LEN];/* KH in tor-spec.txt */ -- cgit v1.2.3 From f58d4dfcd61aec7ea1900873ca08ecc31d7a7ef7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 4 Dec 2012 21:27:07 -0500 Subject: Massive refactoring of the various handshake types The three handshake types are now accessed from a unified interface; their state is abstracted from the rest of the cpath state, and so on. --- src/or/circuitbuild.c | 122 ++++++++++++++----------- src/or/circuitbuild.h | 3 +- src/or/circuitlist.c | 7 +- src/or/command.c | 10 ++- src/or/cpuworker.c | 40 +++++---- src/or/onion.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++- src/or/onion.h | 33 +++++++ src/or/onion_ntor.h | 2 + src/or/onion_tap.c | 26 +++--- src/or/onion_tap.h | 11 ++- src/or/or.h | 40 ++++++--- src/or/rendclient.c | 14 +-- src/or/rendservice.c | 8 +- src/or/router.c | 7 ++ src/or/router.h | 1 + src/test/bench.c | 16 ++-- src/test/test.c | 14 +-- 17 files changed, 462 insertions(+), 135 deletions(-) (limited to 'src/or/or.h') diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index b6cf1252f..8393ba171 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -27,6 +27,7 @@ #include "main.h" #include "networkstatus.h" #include "nodelist.h" +#include "onion.h" #include "onion_tap.h" #include "onion_fast.h" #include "policies.h" @@ -54,7 +55,9 @@ 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 char *payload); + uint8_t cell_type, + const uint8_t *payload, + size_t payload_len); static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit); static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); static int onion_extend_cpath(origin_circuit_t *circ); @@ -474,7 +477,8 @@ circuit_n_chan_done(channel_t *chan, int status) /* pull the create cell out of circ->onionskin, and send it */ tor_assert(circ->n_chan_onionskin); if (circuit_deliver_create_cell(circ,CELL_CREATE, - circ->n_chan_onionskin)<0) { + (const uint8_t*)circ->n_chan_onionskin, + circ->n_chan_onionskin_len)<0) { circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); continue; } @@ -491,12 +495,12 @@ circuit_n_chan_done(channel_t *chan, int status) * for the outgoing * circuit circ, and deliver a cell of type cell_type * (either CELL_CREATE or CELL_CREATE_FAST) with payload payload - * to this circuit. + * to this circuit. DOCDOC payload_len * 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 char *payload) + const uint8_t *payload, size_t payload_len) { cell_t cell; circid_t id; @@ -518,7 +522,7 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, cell.command = cell_type; cell.circ_id = circ->n_circ_id; - memcpy(cell.payload, payload, ONIONSKIN_CHALLENGE_LEN); + memcpy(cell.payload, payload, payload_len); append_cell_to_circuit_queue(circ, circ->n_chan, &cell, CELL_DIRECTION_OUT, 0); @@ -611,8 +615,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) { crypt_path_t *hop; const node_t *node; - char payload[2+4+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN]; - char *onionskin; + uint8_t payload[2+4+DIGEST_LEN+MAX_ONIONSKIN_CHALLENGE_LEN]; + uint8_t *onionskin; + uint16_t handshake_type; + int onionskin_len; size_t payload_len; tor_assert(circ); @@ -633,30 +639,29 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) * send an old slow create cell. */ cell_type = CELL_CREATE; - if (onion_skin_create(circ->cpath->extend_info->onion_key, - &(circ->cpath->dh_handshake_state), - payload) < 0) { - log_warn(LD_CIRC,"onion_skin_create (first hop) failed."); - return - END_CIRC_REASON_INTERNAL; - } + handshake_type = ONION_HANDSHAKE_TYPE_TAP; note_request("cell: create", 1); } 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; - - memset(payload, 0, sizeof(payload)); - if (fast_onionskin_create(&circ->cpath->fast_handshake_state, - (uint8_t *)payload) < 0) { - log_warn(LD_CIRC,"onion_skin_create FAST (first hop) failed."); - return - END_CIRC_REASON_INTERNAL; - } - + handshake_type = ONION_HANDSHAKE_TYPE_FAST; note_request("cell: create fast", 1); } - if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload) < 0) + memset(payload, 0, sizeof(payload)); + onionskin_len = onion_skin_create(handshake_type, + circ->cpath->extend_info, + &circ->cpath->handshake_state, + payload); + if (onionskin_len < 0) { + log_warn(LD_CIRC,"onion_skin_create (first hop) failed."); + return - END_CIRC_REASON_INTERNAL; + } + + if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload, + onionskin_len) < 0) return - END_CIRC_REASON_RESOURCELIMIT; circ->cpath->state = CPATH_STATE_AWAITING_KEYS; @@ -742,12 +747,16 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) set_uint16(payload+4, htons(hop->extend_info->port)); onionskin = payload+2+4; - memcpy(payload+2+4+ONIONSKIN_CHALLENGE_LEN, + memcpy(payload+2+4+TAP_ONIONSKIN_CHALLENGE_LEN, hop->extend_info->identity_digest, DIGEST_LEN); - payload_len = 2+4+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN; + payload_len = 2+4+TAP_ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN; + + handshake_type = ONION_HANDSHAKE_TYPE_TAP; - if (onion_skin_create(hop->extend_info->onion_key, - &(hop->dh_handshake_state), onionskin) < 0) { + if (onion_skin_create(handshake_type, + hop->extend_info, + &hop->handshake_state, + onionskin) < 0) { log_warn(LD_CIRC,"onion_skin_create failed."); return - END_CIRC_REASON_INTERNAL; } @@ -758,7 +767,8 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) * it to a create cell and then send to hop */ if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), RELAY_COMMAND_EXTEND, - payload, payload_len, hop->prev) < 0) + (char*)payload, payload_len, + hop->prev) < 0) return 0; /* circuit is closed */ hop->state = CPATH_STATE_AWAITING_KEYS; @@ -826,7 +836,7 @@ circuit_extend(cell_t *cell, circuit_t *circ) relay_header_unpack(&rh, cell->payload); - if (rh.length < 4+2+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN) { + if (rh.length < 4+2+TAP_ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Wrong length %d on extend cell. Closing circuit.", rh.length); @@ -837,7 +847,7 @@ circuit_extend(cell_t *cell, circuit_t *circ) n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4)); onionskin = (char*) cell->payload+RELAY_HEADER_SIZE+4+2; id_digest = (char*) cell->payload+RELAY_HEADER_SIZE+4+2+ - ONIONSKIN_CHALLENGE_LEN; + TAP_ONIONSKIN_CHALLENGE_LEN; tor_addr_from_ipv4h(&n_addr, n_addr32); if (!n_port || !n_addr32) { @@ -890,8 +900,10 @@ circuit_extend(cell_t *cell, circuit_t *circ) NULL /*onion_key*/, &n_addr, n_port); - circ->n_chan_onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); - memcpy(circ->n_chan_onionskin, onionskin, ONIONSKIN_CHALLENGE_LEN); + circ->n_chan_onionskin = tor_malloc(TAP_ONIONSKIN_CHALLENGE_LEN); + memcpy(circ->n_chan_onionskin, onionskin, TAP_ONIONSKIN_CHALLENGE_LEN); + circ->n_chan_onionskin_len = TAP_ONIONSKIN_CHALLENGE_LEN; + circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT); if (should_launch) { @@ -917,7 +929,8 @@ 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, onionskin) < 0) + if (circuit_deliver_create_cell(circ, CELL_CREATE, (uint8_t*)onionskin, + TAP_ONIONSKIN_CHALLENGE_LEN) < 0) return -1; return 0; } @@ -1377,31 +1390,32 @@ circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type, } tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS); - if (reply_type == CELL_CREATED && hop->dh_handshake_state) { - if (onion_skin_client_handshake(hop->dh_handshake_state, (char*)reply,keys, - DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) { - log_warn(LD_CIRC,"onion_skin_client_handshake failed."); + { + uint16_t handshake_type = 0xffff; + if (reply_type == CELL_CREATED) + handshake_type = ONION_HANDSHAKE_TYPE_TAP; + else if (reply_type == CELL_CREATED_FAST) + handshake_type = ONION_HANDSHAKE_TYPE_FAST; + + if (handshake_type != hop->handshake_state.tag) { + log_warn(LD_PROTOCOL,"CREATED cell onionskin type (%u) did not " + "match CREATE cell onionskin type (%u).", + (unsigned)handshake_type, + (unsigned) hop->handshake_state.tag); return -END_CIRC_REASON_TORPROTOCOL; } - /* Remember hash of g^xy */ - memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN); - } else if (reply_type == CELL_CREATED_FAST && !hop->dh_handshake_state) { - if (fast_client_handshake(hop->fast_handshake_state, reply, - (uint8_t*)keys, - DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) { - log_warn(LD_CIRC,"fast_client_handshake failed."); + + if (onion_skin_client_handshake(handshake_type, + &hop->handshake_state, + reply, + (uint8_t*)keys, sizeof(keys), + (uint8_t*)hop->handshake_digest) < 0) { + log_warn(LD_CIRC,"onion_skin_client_handshake failed."); return -END_CIRC_REASON_TORPROTOCOL; } - memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN); - } else { - log_warn(LD_PROTOCOL,"CREATED cell type did not match CREATE cell type."); - return -END_CIRC_REASON_TORPROTOCOL; } - crypto_dh_free(hop->dh_handshake_state); /* don't need it anymore */ - hop->dh_handshake_state = NULL; - - memset(hop->fast_handshake_state, 0, sizeof(hop->fast_handshake_state)); + onion_handshake_state_release(&hop->handshake_state); if (circuit_init_cpath_crypto(hop, keys, 0)<0) { return -END_CIRC_REASON_TORPROTOCOL; @@ -1470,7 +1484,7 @@ 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, - const char *keys) + size_t payload_len, const char *keys) { cell_t cell; crypt_path_t *tmp_cpath; @@ -1484,8 +1498,7 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload, circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); - memcpy(cell.payload, payload, - cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2); + memcpy(cell.payload, payload, payload_len); log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.", (unsigned int)get_uint32(keys), @@ -1502,6 +1515,7 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload, tmp_cpath->magic = 0; tor_free(tmp_cpath); + /* XXXX Move responsibility for extracting this. */ if (cell_type == CELL_CREATED) memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN); else diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 78575afcf..f83cb554c 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -35,7 +35,8 @@ int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type, int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason); int onionskin_answer(or_circuit_t *circ, uint8_t cell_type, - const char *payload, const char *keys); + const char *payload, size_t payload_len, + const char *keys); int circuit_all_predicted_ports_handled(time_t now, int *need_uptime, int *need_capacity); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 2c17fd2bb..2565470e2 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -744,8 +744,8 @@ circuit_free_cpath_node(crypt_path_t *victim) crypto_cipher_free(victim->b_crypto); crypto_digest_free(victim->f_digest); crypto_digest_free(victim->b_digest); - crypto_dh_free(victim->dh_handshake_state); - fast_handshake_state_free(victim->fast_handshake_state); + onion_handshake_state_release(&victim->handshake_state); + crypto_dh_free(victim->rend_dh_handshake_state); extend_info_free(victim->extend_info); memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */ @@ -1494,7 +1494,8 @@ assert_cpath_layer_ok(const crypt_path_t *cp) tor_assert(cp->b_crypto); /* fall through */ case CPATH_STATE_CLOSED: - tor_assert(!cp->dh_handshake_state); + /*XXXX Assert that there's no handshake_state either. */ + tor_assert(!cp->rend_dh_handshake_state); break; case CPATH_STATE_AWAITING_KEYS: /* tor_assert(cp->dh_handshake_state); */ diff --git a/src/or/command.c b/src/or/command.c index 2718ec92b..a33a9b182 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -30,6 +30,7 @@ #include "hibernate.h" #include "nodelist.h" //#include "onion.h" +#include "onion_tap.h" #include "onion_fast.h" #include "relay.h" #include "router.h" @@ -254,8 +255,8 @@ command_process_create_cell(cell_t *cell, channel_t *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(ONIONSKIN_CHALLENGE_LEN); - memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN); + char *onionskin = tor_malloc(TAP_ONIONSKIN_CHALLENGE_LEN); + memcpy(onionskin, cell->payload, TAP_ONIONSKIN_CHALLENGE_LEN); /* hand it off to the cpuworkers, and then return. */ if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) { @@ -282,7 +283,8 @@ command_process_create_cell(cell_t *cell, channel_t *chan) circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } - if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) { + if (onionskin_answer(circ, CELL_CREATED_FAST, reply, sizeof(reply), + keys)<0) { log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; @@ -340,7 +342,7 @@ command_process_created_cell(cell_t *cell, channel_t *chan) 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, ONIONSKIN_REPLY_LEN, + (char*)cell->payload, TAP_ONIONSKIN_REPLY_LEN, NULL); } } diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index 3a3d68724..e8087c2b8 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -35,7 +35,7 @@ #define TAG_LEN 10 /** How many bytes are sent from the cpuworker back to tor? */ #define LEN_ONION_RESPONSE \ - (1+TAG_LEN+ONIONSKIN_REPLY_LEN+CPATH_KEY_MATERIAL_LEN) + (1+TAG_LEN+TAP_ONIONSKIN_REPLY_LEN+CPATH_KEY_MATERIAL_LEN) /** How many cpuworkers we have running right now. */ static int num_cpuworkers=0; @@ -185,7 +185,8 @@ connection_cpu_process_inbuf(connection_t *conn) } tor_assert(! CIRCUIT_IS_ORIGIN(circ)); if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN, - buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) { + TAP_ONIONSKIN_REPLY_LEN, + buf+TAG_LEN+TAP_ONIONSKIN_REPLY_LEN) < 0) { log_warn(LD_OR,"onionskin_answer failed. Closing."); circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); goto done_processing; @@ -214,11 +215,11 @@ connection_cpu_process_inbuf(connection_t *conn) * Request format: * Task type [1 byte, always CPUWORKER_TASK_ONION] * Opaque tag TAG_LEN - * Onionskin challenge ONIONSKIN_CHALLENGE_LEN + * Onionskin challenge TAP_ONIONSKIN_CHALLENGE_LEN * Response format: * Success/failure [1 byte, boolean.] * Opaque tag TAG_LEN - * Onionskin challenge ONIONSKIN_REPLY_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 @@ -227,17 +228,17 @@ connection_cpu_process_inbuf(connection_t *conn) static void cpuworker_main(void *data) { - char question[ONIONSKIN_CHALLENGE_LEN]; + char question[TAP_ONIONSKIN_CHALLENGE_LEN]; uint8_t question_type; tor_socket_t *fdarray = data; tor_socket_t fd; /* variables for onion processing */ char keys[CPATH_KEY_MATERIAL_LEN]; - char reply_to_proxy[ONIONSKIN_REPLY_LEN]; + char reply_to_proxy[MAX_ONIONSKIN_REPLY_LEN]; char buf[LEN_ONION_RESPONSE]; char tag[TAG_LEN]; - crypto_pk_t *onion_key = NULL, *last_onion_key = NULL; + server_onion_keys_t onion_keys; fd = fdarray[1]; /* this side is ours */ #ifndef TOR_IS_MULTITHREADED @@ -248,7 +249,7 @@ cpuworker_main(void *data) #endif tor_free(data); - dup_onion_keys(&onion_key, &last_onion_key); + setup_server_onion_keys(&onion_keys); for (;;) { ssize_t r; @@ -275,15 +276,18 @@ cpuworker_main(void *data) goto end; } - if (read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) != - ONIONSKIN_CHALLENGE_LEN) { + if (read_all(fd, question, TAP_ONIONSKIN_CHALLENGE_LEN, 1) != + TAP_ONIONSKIN_CHALLENGE_LEN) { log_err(LD_BUG,"read question failed. Exiting."); goto end; } if (question_type == CPUWORKER_TASK_ONION) { - if (onion_skin_server_handshake(question, onion_key, last_onion_key, - reply_to_proxy, keys, CPATH_KEY_MATERIAL_LEN) < 0) { + if (onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_TAP, + (const uint8_t*)question, + &onion_keys, + (uint8_t*)reply_to_proxy, + (uint8_t*)keys, CPATH_KEY_MATERIAL_LEN) < 0) { /* failure */ log_debug(LD_OR,"onion_skin_server_handshake failed."); *buf = 0; /* indicate failure in first byte */ @@ -295,8 +299,9 @@ cpuworker_main(void *data) 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,ONIONSKIN_REPLY_LEN); - memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,CPATH_KEY_MATERIAL_LEN); + memcpy(buf+1+TAG_LEN,reply_to_proxy,TAP_ONIONSKIN_REPLY_LEN); + memcpy(buf+1+TAG_LEN+TAP_ONIONSKIN_REPLY_LEN,keys, + CPATH_KEY_MATERIAL_LEN); } if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) { log_err(LD_BUG,"writing response buf failed. Exiting."); @@ -306,10 +311,7 @@ cpuworker_main(void *data) } } end: - if (onion_key) - crypto_pk_free(onion_key); - if (last_onion_key) - crypto_pk_free(last_onion_key); + release_server_onion_keys(&onion_keys); tor_close_socket(fd); crypto_thread_cleanup(); spawn_exit(); @@ -497,7 +499,7 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker, 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, ONIONSKIN_CHALLENGE_LEN, cpuworker); + connection_write_to_buf(onionskin, TAP_ONIONSKIN_CHALLENGE_LEN, cpuworker); tor_free(onionskin); } return 0; diff --git a/src/or/onion.c b/src/or/onion.c index f468adab2..90fc830dd 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -6,15 +6,19 @@ /** * \file onion.c - * \brief Functions to queue create cells, and handle onionskin - * parsing and creation. + * \brief Functions to queue create cells, handle onionskin + * parsing and creation, and wrap the various onionskin types. **/ #include "or.h" #include "circuitlist.h" #include "config.h" #include "onion.h" +#include "onion_fast.h" +#include "onion_ntor.h" +#include "onion_tap.h" #include "rephist.h" +#include "router.h" /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ @@ -37,6 +41,8 @@ static onion_queue_t *ol_tail=NULL; /** Length of ol_list */ static int ol_length=0; +/* XXXX Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN */ + /** Add circ to the end of ol_list and return 0, except * if ol_list is too long, in which case do nothing and return -1. */ @@ -171,3 +177,236 @@ clear_pending_onions(void) ol_length = 0; } +/* ============================================================ */ + +/** Fill in a server_onion_keys_t object at keys with all of the keys + * and other info we might need to do onion handshakes. (We make a copy of + * our keys for each cpuworker to avoid race conditions with the main thread, + * and to avoid locking) */ +void +setup_server_onion_keys(server_onion_keys_t *keys) +{ + memset(keys, 0, sizeof(server_onion_keys_t)); + memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN); + dup_onion_keys(&keys->onion_key, &keys->last_onion_key); +#ifdef CURVE25519_ENABLED + keys->curve25519_key_map = construct_ntor_key_map(); +#endif +} + +/** Release all storage held in keys, but do not free keys + * itself (as it's likely to be stack-allocated.) */ +void +release_server_onion_keys(server_onion_keys_t *keys) +{ + if (! keys) + return; + + crypto_pk_free(keys->onion_key); + crypto_pk_free(keys->last_onion_key); +#ifdef CURVE25519_ENABLED + ntor_key_map_free(keys->curve25519_key_map); +#endif + memset(keys, 0, sizeof(server_onion_keys_t)); +} + +/** Release whatever storage is held in state, depending on its + * type, and clear its pointer. */ +void +onion_handshake_state_release(onion_handshake_state_t *state) +{ + switch (state->tag) { + case ONION_HANDSHAKE_TYPE_TAP: + crypto_dh_free(state->u.tap); + state->u.tap = NULL; + break; + case ONION_HANDSHAKE_TYPE_FAST: + fast_handshake_state_free(state->u.fast); + state->u.fast = NULL; + break; +#ifdef CURVE25519_ENABLED + case ONION_HANDSHAKE_TYPE_NTOR: + ntor_handshake_state_free(state->u.ntor); + state->u.ntor = NULL; + break; +#endif + default: + log_warn(LD_BUG, "called with unknown handshake state type %d", + (int)state->tag); + tor_fragile_assert(); + } +} + +/** Perform the first step of a circuit-creation handshake of type type + * (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in + * onion_skin_out, and store any state information in state_out. + * Return -1 on failure, and the length of the onionskin on acceptance. + */ +int +onion_skin_create(int type, + const extend_info_t *node, + onion_handshake_state_t *state_out, + uint8_t *onion_skin_out) +{ + int r = -1; + + switch (type) { + case ONION_HANDSHAKE_TYPE_TAP: + if (!node->onion_key) + return -1; + + if (onion_skin_TAP_create(node->onion_key, + &state_out->u.tap, + (char*)onion_skin_out) < 0) + return -1; + + r = TAP_ONIONSKIN_CHALLENGE_LEN; + break; + case ONION_HANDSHAKE_TYPE_FAST: + if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0) + return -1; + + r = CREATE_FAST_LEN; + break; + case ONION_HANDSHAKE_TYPE_NTOR: +#ifdef CURVE25519_ENABLED + if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key, + CURVE25519_PUBKEY_LEN)) + return -1; + if (onion_skin_ntor_create((const uint8_t*)node->identity_digest, + &node->curve25519_onion_key, + &state_out->u.ntor, + onion_skin_out) < 0) + return -1; + + r = NTOR_ONIONSKIN_LEN; +#else + return -1; +#endif + break; + default: + log_warn(LD_BUG, "called with unknown handshake state type %d", type); + tor_fragile_assert(); + r = -1; + } + + if (r > 0) + state_out->tag = (uint16_t) type; + + return r; +} + +/** Perform the second (server-side) step of a circuit-creation handshake of + * type type, responding to the client request in onion_skin + * using the keys in keys. On success, write our response into + * reply_out, generate keys_out_len bytes worth of key material + * in keys_out_len, and return the length of the reply. On failure, + * return -1. */ +int +onion_skin_server_handshake(int type, + const uint8_t *onion_skin, + const server_onion_keys_t *keys, + uint8_t *reply_out, + uint8_t *keys_out, size_t keys_out_len) +{ + int r = -1; + + switch (type) { + case ONION_HANDSHAKE_TYPE_TAP: + if (onion_skin_TAP_server_handshake((const char*)onion_skin, + keys->onion_key, keys->last_onion_key, + (char*)reply_out, + (char*)keys_out, keys_out_len)<0) + return -1; + r = TAP_ONIONSKIN_REPLY_LEN; + break; + case ONION_HANDSHAKE_TYPE_FAST: + if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0) + return -1; + r = CREATED_FAST_LEN; + break; + case ONION_HANDSHAKE_TYPE_NTOR: +#ifdef CURVE25519_ENABLED + if (onion_skin_ntor_server_handshake(onion_skin, keys->curve25519_key_map, + keys->my_identity, + reply_out, keys_out, keys_out_len)<0) + return -1; + r = NTOR_REPLY_LEN; +#else + return -1; +#endif + break; + default: + log_warn(LD_BUG, "called with unknown handshake state type %d", type); + tor_fragile_assert(); + return -1; + } + + /* XXXX we should generate the rendezvous nonce stuff too. Some notes + * below */ + // memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN); + + //memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN); + + return r; +} + +/** Perform the final (client-side) step of a circuit-creation handshake of + * type type, using our state in handshake_state and the + * server's response in reply On success, generate keys_out_len + * bytes worth of key material in keys_out_len, set + * rend_authenticator_out to the "KH" field that can be used to + * establish introduction points at this hop, and return 0. On failure, + * return -1. */ +int +onion_skin_client_handshake(int type, + const onion_handshake_state_t *handshake_state, + const uint8_t *reply, + uint8_t *keys_out, size_t keys_out_len, + uint8_t *rend_authenticator_out) +{ + if (handshake_state->tag != type) + return -1; + + switch (type) { + case ONION_HANDSHAKE_TYPE_TAP: + if (onion_skin_TAP_client_handshake(handshake_state->u.tap, + (const char*)reply, + (char *)keys_out, keys_out_len) < 0) + return -1; + + memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN); + + return 0; + case ONION_HANDSHAKE_TYPE_FAST: + if (fast_client_handshake(handshake_state->u.fast, reply, + keys_out, keys_out_len) < 0) + return -1; + + memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN); + return 0; +#ifdef CURVE25519_ENABLED + case ONION_HANDSHAKE_TYPE_NTOR: + { + size_t keys_tmp_len = keys_out_len + DIGEST_LEN; + uint8_t *keys_tmp = tor_malloc(keys_tmp_len); + if (onion_skin_ntor_client_handshake(handshake_state->u.ntor, + reply, + keys_tmp, keys_tmp_len) < 0) { + tor_free(keys_tmp); + return -1; + } + memcpy(keys_out, keys_tmp, keys_out_len); + memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN); + memwipe(keys_tmp, 0, keys_tmp_len); + tor_free(keys_tmp); + } + return 0; +#endif + default: + log_warn(LD_BUG, "called with unknown handshake state type %d", type); + tor_fragile_assert(); + return -1; + } +} + diff --git a/src/or/onion.h b/src/or/onion.h index 55ea3f930..3c12e1f85 100644 --- a/src/or/onion.h +++ b/src/or/onion.h @@ -17,5 +17,38 @@ or_circuit_t *onion_next_task(char **onionskin_out); void onion_pending_remove(or_circuit_t *circ); void clear_pending_onions(void); +typedef struct server_onion_keys_t { + uint8_t my_identity[DIGEST_LEN]; + crypto_pk_t *onion_key; + crypto_pk_t *last_onion_key; +#ifdef CURVE25519_ENABLED + di_digest256_map_t *curve25519_key_map; +#endif +} server_onion_keys_t; + +#define MAX_ONIONSKIN_CHALLENGE_LEN 255 +#define MAX_ONIONSKIN_REPLY_LEN 255 + +void setup_server_onion_keys(server_onion_keys_t *keys); +void release_server_onion_keys(server_onion_keys_t *keys); + +void onion_handshake_state_release(onion_handshake_state_t *state); + +int onion_skin_create(int type, + const extend_info_t *node, + onion_handshake_state_t *state_out, + uint8_t *onion_skin_out); +int onion_skin_server_handshake(int type, + const uint8_t *onion_skin, + const server_onion_keys_t *keys, + uint8_t *reply_out, + uint8_t *keys_out, size_t key_out_len); +// uint8_t *rend_authenticator_out); +int onion_skin_client_handshake(int type, + const onion_handshake_state_t *handshake_state, + const uint8_t *reply, + uint8_t *keys_out, size_t key_out_len, + uint8_t *rend_authenticator_out); + #endif diff --git a/src/or/onion_ntor.h b/src/or/onion_ntor.h index 4f305a49e..80015fd3f 100644 --- a/src/or/onion_ntor.h +++ b/src/or/onion_ntor.h @@ -17,6 +17,7 @@ typedef struct ntor_handshake_state_t ntor_handshake_state_t; /** Length of an ntor reply, as sent from server to client. */ #define NTOR_REPLY_LEN 64 +#ifdef CURVE25519_ENABLED void ntor_handshake_state_free(ntor_handshake_state_t *state); int onion_skin_ntor_create(const uint8_t *router_id, @@ -36,6 +37,7 @@ int onion_skin_ntor_client_handshake( const uint8_t *handshake_reply, uint8_t *key_out, size_t key_out_len); +#endif #endif diff --git a/src/or/onion_tap.c b/src/or/onion_tap.c index 464b8451d..0ec526cd0 100644 --- a/src/or/onion_tap.c +++ b/src/or/onion_tap.c @@ -35,9 +35,9 @@ * The meeting point/cookies and auth are zeroed out for now. */ int -onion_skin_create(crypto_pk_t *dest_router_key, +onion_skin_TAP_create(crypto_pk_t *dest_router_key, crypto_dh_t **handshake_state_out, - char *onion_skin_out) /* ONIONSKIN_CHALLENGE_LEN bytes */ + char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */ { char challenge[DH_KEY_LEN]; crypto_dh_t *dh = NULL; @@ -47,7 +47,7 @@ onion_skin_create(crypto_pk_t *dest_router_key, tor_assert(handshake_state_out); tor_assert(onion_skin_out); *handshake_state_out = NULL; - memset(onion_skin_out, 0, ONIONSKIN_CHALLENGE_LEN); + memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN); if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT))) goto err; @@ -64,7 +64,7 @@ onion_skin_create(crypto_pk_t *dest_router_key, /* set meeting point, meeting cookie, etc here. Leave zero for now. */ if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out, - ONIONSKIN_CHALLENGE_LEN, + TAP_ONIONSKIN_CHALLENGE_LEN, challenge, DH_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1)<0) goto err; @@ -85,14 +85,17 @@ onion_skin_create(crypto_pk_t *dest_router_key, * next key_out_len bytes of key material in key_out. */ int -onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/ +onion_skin_TAP_server_handshake( + /*TAP_ONIONSKIN_CHALLENGE_LEN*/ + const char *onion_skin, crypto_pk_t *private_key, crypto_pk_t *prev_private_key, - char *handshake_reply_out, /*ONIONSKIN_REPLY_LEN*/ + /*TAP_ONIONSKIN_REPLY_LEN*/ + char *handshake_reply_out, char *key_out, size_t key_out_len) { - char challenge[ONIONSKIN_CHALLENGE_LEN]; + char challenge[TAP_ONIONSKIN_CHALLENGE_LEN]; crypto_dh_t *dh = NULL; ssize_t len; char *key_material=NULL; @@ -107,8 +110,9 @@ onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/ break; note_crypto_pk_op(DEC_ONIONSKIN); len = crypto_pk_private_hybrid_decrypt(k, challenge, - ONIONSKIN_CHALLENGE_LEN, - onion_skin, ONIONSKIN_CHALLENGE_LEN, + TAP_ONIONSKIN_CHALLENGE_LEN, + onion_skin, + TAP_ONIONSKIN_CHALLENGE_LEN, PK_PKCS1_OAEP_PADDING,0); if (len>0) break; @@ -175,8 +179,8 @@ onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/ * After the invocation, call crypto_dh_free on handshake_state. */ int -onion_skin_client_handshake(crypto_dh_t *handshake_state, - const char *handshake_reply, /* ONIONSKIN_REPLY_LEN bytes */ +onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, + const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */ char *key_out, size_t key_out_len) { diff --git a/src/or/onion_tap.h b/src/or/onion_tap.h index 3bd90c95e..deae1bf8c 100644 --- a/src/or/onion_tap.h +++ b/src/or/onion_tap.h @@ -12,18 +12,23 @@ #ifndef TOR_ONION_TAP_H #define TOR_ONION_TAP_H -int onion_skin_create(crypto_pk_t *router_key, +#define TAP_ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\ + CIPHER_KEY_LEN+\ + DH_KEY_LEN) +#define TAP_ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN) + +int onion_skin_TAP_create(crypto_pk_t *router_key, crypto_dh_t **handshake_state_out, char *onion_skin_out); -int onion_skin_server_handshake(const char *onion_skin, +int onion_skin_TAP_server_handshake(const char *onion_skin, crypto_pk_t *private_key, crypto_pk_t *prev_private_key, char *handshake_reply_out, char *key_out, size_t key_out_len); -int onion_skin_client_handshake(crypto_dh_t *handshake_state, +int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, const char *handshake_reply, char *key_out, size_t key_out_len); diff --git a/src/or/or.h b/src/or/or.h index 6fada7700..f7407a8e9 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1381,6 +1381,7 @@ typedef struct or_connection_t { or_handshake_state_t *handshake_state; /**< If we are setting this connection * up, state information to do so. */ + time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/ time_t timestamp_last_added_nonpadding; /** When did we last add a * non-padding cell to the outbuf? */ @@ -2470,6 +2471,9 @@ typedef struct extend_info_t { uint16_t port; /**< OR port. */ tor_addr_t addr; /**< IP address. */ crypto_pk_t *onion_key; /**< Current onionskin key. */ +#ifdef CURVE25519_ENABLED + curve25519_public_key_t curve25519_onion_key; +#endif } extend_info_t; /** Certificate for v3 directory protocol: binds long-term authority identity @@ -2525,6 +2529,19 @@ typedef enum { #define CRYPT_PATH_MAGIC 0x70127012u struct fast_handshake_state_t; +struct ntor_handshake_state_t; +#define ONION_HANDSHAKE_TYPE_TAP 0x0000 +#define ONION_HANDSHAKE_TYPE_FAST 0x0001 +#define ONION_HANDSHAKE_TYPE_NTOR 0x0002 +typedef struct { + uint16_t tag; + union { + struct fast_handshake_state_t *fast; + crypto_dh_t *tap; + struct ntor_handshake_state_t *ntor; + } u; +} onion_handshake_state_t; + /** Holds accounting information for a single step in the layered encryption * performed by a circuit. Used only at the client edge of a circuit. */ typedef struct crypt_path_t { @@ -2543,16 +2560,15 @@ typedef struct crypt_path_t { /** Digest state for cells heading away from the OR at this step. */ crypto_digest_t *b_digest; - /** Current state of Diffie-Hellman key negotiation with the OR at this + /** Current state of the handshake as performed with the OR at this * step. */ - crypto_dh_t *dh_handshake_state; - /** Current state of 'fast' (non-PK) key negotiation with the OR at this - * step. Used to save CPU when TLS is already providing all the - * authentication, secrecy, and integrity we need, and we're already - * distinguishable from an OR. - */ - struct fast_handshake_state_t *fast_handshake_state; + onion_handshake_state_t handshake_state; + /** Diffie-hellman handshake state for performing an introduction + * operations */ + crypto_dh_t *rend_dh_handshake_state; + /** Negotiated key material shared with the OR at this step. */ + /* XXXX RENAME */ char handshake_digest[DIGEST_LEN];/* KH in tor-spec.txt */ /** Information to extend to the OR at this step. */ @@ -2594,10 +2610,6 @@ typedef struct { #define CPATH_KEY_MATERIAL_LEN (20*2+16*2) #define DH_KEY_LEN DH_BYTES -#define ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\ - CIPHER_KEY_LEN+\ - DH_KEY_LEN) -#define ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN) /** Information used to build a circuit. */ typedef struct { @@ -2703,9 +2715,10 @@ 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 ONIONSKIN_CHALLENGE_LEN. */ + * length n_chan_onionskin_len */ char *n_chan_onionskin; /** When was this circuit created? We keep this timestamp with a higher @@ -2965,6 +2978,7 @@ typedef struct or_circuit_t { char rend_token[REND_TOKEN_LEN]; /* ???? move to a subtype or adjunct structure? Wastes 20 bytes -NM */ + /* XXXX rename this. */ char handshake_digest[DIGEST_LEN]; /**< Stores KH for the handshake. */ /** How many more relay_early cells can we send on this circuit, according diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 3fb4025e6..61fb3aad8 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -206,12 +206,12 @@ rend_client_send_introduction(origin_circuit_t *introcirc, cpath = rendcirc->build_state->pending_final_cpath = tor_malloc_zero(sizeof(crypt_path_t)); cpath->magic = CRYPT_PATH_MAGIC; - if (!(cpath->dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) { + if (!(cpath->rend_dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) { log_warn(LD_BUG, "Internal error: couldn't allocate DH."); status = -2; goto perm_err; } - if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) { + if (crypto_dh_generate_public(cpath->rend_dh_handshake_state)<0) { log_warn(LD_BUG, "Internal error: couldn't generate g^x."); status = -2; goto perm_err; @@ -261,7 +261,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc, dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN; } - if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset, + if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset, DH_KEY_LEN)<0) { log_warn(LD_BUG, "Internal error: couldn't extract g^x."); status = -2; @@ -896,9 +896,9 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, tor_assert(circ->build_state); tor_assert(circ->build_state->pending_final_cpath); hop = circ->build_state->pending_final_cpath; - tor_assert(hop->dh_handshake_state); + tor_assert(hop->rend_dh_handshake_state); if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, - hop->dh_handshake_state, (char*)request, + hop->rend_dh_handshake_state, (char*)request, DH_KEY_LEN, keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) { log_warn(LD_GENERAL, "Couldn't complete DH handshake."); @@ -914,8 +914,8 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, goto err; } - crypto_dh_free(hop->dh_handshake_state); - hop->dh_handshake_state = NULL; + crypto_dh_free(hop->rend_dh_handshake_state); + hop->rend_dh_handshake_state = NULL; /* All is well. Extend the circuit. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_JOINED); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 09792bd1d..08a7feb3e 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -1378,7 +1378,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, cpath->magic = CRYPT_PATH_MAGIC; launched->build_state->expiry_time = now + MAX_REND_TIMEOUT; - cpath->dh_handshake_state = dh; + cpath->rend_dh_handshake_state = dh; dh = NULL; if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0) goto err; @@ -2624,7 +2624,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */ memcpy(buf, circuit->rend_data->rend_cookie, REND_COOKIE_LEN); - if (crypto_dh_get_public(hop->dh_handshake_state, + if (crypto_dh_get_public(hop->rend_dh_handshake_state, buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) { log_warn(LD_GENERAL,"Couldn't get DH public key."); reason = END_CIRC_REASON_INTERNAL; @@ -2643,8 +2643,8 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) goto err; } - crypto_dh_free(hop->dh_handshake_state); - hop->dh_handshake_state = NULL; + crypto_dh_free(hop->rend_dh_handshake_state); + hop->rend_dh_handshake_state = NULL; /* Append the cpath entry. */ hop->state = CPATH_STATE_OPEN; diff --git a/src/or/router.c b/src/or/router.c index 954304dd2..3733bec4d 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1598,6 +1598,13 @@ router_digest_is_me(const char *digest) tor_memeq(server_identitykey_digest, digest, DIGEST_LEN)); } +/** DOCDOC */ +const uint8_t * +router_get_my_id_digest(void) +{ + return (const uint8_t *)server_identitykey_digest; +} + /** Return true iff I'm a server and digest is equal to * my identity digest. */ int diff --git a/src/or/router.h b/src/or/router.h index 85c7d351d..ea0b2ab4e 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -84,6 +84,7 @@ extrainfo_t *router_get_my_extrainfo(void); const char *router_get_my_descriptor(void); const char *router_get_descriptor_gen_reason(void); int router_digest_is_me(const char *digest); +const uint8_t *router_get_my_id_digest(void); int router_extrainfo_digest_is_me(const char *digest); int router_is_me(const routerinfo_t *router); int router_fingerprint_is_me(const char *fp); diff --git a/src/test/bench.c b/src/test/bench.c index 567b1a4d7..23560cd43 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -110,8 +110,8 @@ bench_onion_TAP(void) int i; crypto_pk_t *key, *key2; uint64_t start, end; - char os[ONIONSKIN_CHALLENGE_LEN]; - char or[ONIONSKIN_REPLY_LEN]; + char os[TAP_ONIONSKIN_CHALLENGE_LEN]; + char or[TAP_ONIONSKIN_REPLY_LEN]; crypto_dh_t *dh_out; key = crypto_pk_new(); @@ -122,17 +122,18 @@ bench_onion_TAP(void) reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { - onion_skin_create(key, &dh_out, os); + onion_skin_TAP_create(key, &dh_out, os); crypto_dh_free(dh_out); } end = perftime(); printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); - onion_skin_create(key, &dh_out, os); + onion_skin_TAP_create(key, &dh_out, os); start = perftime(); for (i = 0; i < iters; ++i) { char key_out[CPATH_KEY_MATERIAL_LEN]; - onion_skin_server_handshake(os, key, NULL, or, key_out, sizeof(key_out)); + onion_skin_TAP_server_handshake(os, key, NULL, or, + key_out, sizeof(key_out)); } end = perftime(); printf("Server-side, key guessed right: %f usec\n", @@ -141,7 +142,8 @@ bench_onion_TAP(void) start = perftime(); for (i = 0; i < iters; ++i) { char key_out[CPATH_KEY_MATERIAL_LEN]; - onion_skin_server_handshake(os, key2, key, or, key_out, sizeof(key_out)); + onion_skin_TAP_server_handshake(os, key2, key, or, + key_out, sizeof(key_out)); } end = perftime(); printf("Server-side, key guessed wrong: %f usec.\n", @@ -153,7 +155,7 @@ bench_onion_TAP(void) char key_out[CPATH_KEY_MATERIAL_LEN]; int s; dh = crypto_dh_dup(dh_out); - s = onion_skin_client_handshake(dh, or, key_out, sizeof(key_out)); + s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out)); tor_assert(s == 0); } end = perftime(); diff --git a/src/test/test.c b/src/test/test.c index cc2d481c7..daac67ee4 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -819,11 +819,11 @@ test_onion_handshake(void) { /* client-side */ crypto_dh_t *c_dh = NULL; - char c_buf[ONIONSKIN_CHALLENGE_LEN]; + char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; char c_keys[40]; /* server-side */ - char s_buf[ONIONSKIN_REPLY_LEN]; + char s_buf[TAP_ONIONSKIN_REPLY_LEN]; char s_keys[40]; /* shared */ @@ -832,18 +832,18 @@ test_onion_handshake(void) pk = pk_generate(0); /* client handshake 1. */ - memset(c_buf, 0, ONIONSKIN_CHALLENGE_LEN); - test_assert(! onion_skin_create(pk, &c_dh, c_buf)); + memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN); + test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf)); /* server handshake */ - memset(s_buf, 0, ONIONSKIN_REPLY_LEN); + memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN); memset(s_keys, 0, 40); - test_assert(! onion_skin_server_handshake(c_buf, pk, NULL, + test_assert(! onion_skin_TAP_server_handshake(c_buf, pk, NULL, s_buf, s_keys, 40)); /* client handshake 2 */ memset(c_keys, 0, 40); - test_assert(! onion_skin_client_handshake(c_dh, s_buf, c_keys, 40)); + test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40)); if (memcmp(c_keys, s_keys, 40)) { puts("Aiiiie"); -- cgit v1.2.3 From 18c7d3f157957a5c8034e165d0fc09490c25b0ba Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 4 Dec 2012 21:39:54 -0500 Subject: 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(-) (limited to 'src/or/or.h') diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 8393ba171..40aad6d99 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 f7407a8e9..d349d1134 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 dc2dc1d9e..8234265ca 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 08a7feb3e..4f3fdf45e 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 */ -- cgit v1.2.3 From 5d15d597a9059d0f87ced081e187db622caa7978 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 5 Dec 2012 16:47:22 -0500 Subject: 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(-) (limited to 'src/or/or.h') diff --git a/src/or/onion.c b/src/or/onion.c index 90fc830dd..c1f2e5bec 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 cell appears valid, -1 otherwise. If + * unknown_ok 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 p, which could be up to + * p_len bytes long, and use it to fill the fields of + * cell_out. 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 cell_in into + * cell_out. 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 cell 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 cell_in into + * cell_out. 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 cell 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 command) from the + * payload_length bytes of payload into cell_out. 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 cell 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 command) from the + * payload_length bytes of payload into cell_out. 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 cell_out with a correctly formatted version of the + * CREATE{,_FAST,2} cell in cell_in. 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 cell_out with a correctly formatted version of the + * CREATED{,_FAST,2} cell in cell_in. 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 cell_in, storing its relay payload in + * payload_out, the number of bytes used in *len_out, and the + * relay command in *command_out. The payload_out 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 cell_in, storing its relay payload + * in payload_out, the number of bytes used in *len_out, and the + * relay command in *command_out. The payload_out 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 3c12e1f85..08e1a22ec 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 onionskin. */ + 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 reply. */ + 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 d349d1134..f9b0f1e0f 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 4222c79d9..2af87af72 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 }; -- cgit v1.2.3 From 2802ccaeb6b95e693af7736e58e91434d28ac6a2 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 5 Dec 2012 22:34:49 -0500 Subject: 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(-) (limited to 'src/or/or.h') diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 40aad6d99..40cb8e43a 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 - * reply as its body. (If reply_type is CELL_CREATED, the body + * reply_cell as its body. (If reply_type is CELL_CREATED, the body * contains (the second DH key, plus KH). If reply_type 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 f83cb554c..e53e6ba87 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 a33a9b182..c77e2ec8b 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 e8087c2b8..a8ec0275a 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 tag 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 73c7eefd4..f607e7d48 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 c1f2e5bec..9326c2fff 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 keys. On success, write our response into * reply_out, generate keys_out_len bytes worth of key material * in keys_out_len, 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 08e1a22ec..36cb76118 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 f9b0f1e0f..5ea420f73 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 d862e5834..d0c8c2291 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."); -- cgit v1.2.3 From 6c69b16c93bd7156dcda246128b96209616c3ead Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 5 Dec 2012 23:07:49 -0500 Subject: 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(-) (limited to 'src/or/or.h') diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 40cb8e43a..5ac2692bd 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) : ""); } 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 2565470e2..1acb41787 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 5ea420f73..66e905449 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 -- cgit v1.2.3 From b2863739083125d332cf1166ae6b095df7d0f155 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 6 Dec 2012 01:53:29 -0500 Subject: Enable the ntor handshake on the client side. "works for me" --- src/or/channeltls.c | 2 + src/or/circuitbuild.c | 103 +++++++++++++++++++++++++++++++++++++++++++++----- src/or/circuitbuild.h | 5 ++- src/or/circuituse.c | 4 +- src/or/config.c | 1 + src/or/entrynodes.c | 2 +- src/or/nodelist.c | 12 ++++++ src/or/nodelist.h | 1 + src/or/or.h | 5 +++ src/or/relay.c | 4 +- src/or/router.c | 3 +- src/or/routerparse.c | 2 + 12 files changed, 128 insertions(+), 16 deletions(-) (limited to 'src/or/or.h') diff --git a/src/or/channeltls.c b/src/or/channeltls.c index ede245894..f6069e003 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -914,6 +914,8 @@ channel_tls_handle_cell(cell_t *cell, or_connection_t *conn) case CELL_RELAY: case CELL_RELAY_EARLY: case CELL_DESTROY: + case CELL_CREATE2: + case CELL_CREATED2: /* * These are all transport independent and we pass them up through the * channel_t mechanism. They are ultimately handled in command.c. diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index b7ab47f55..9300b049c 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -604,6 +604,73 @@ circuit_timeout_want_to_count_circ(origin_circuit_t *circ) && circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN; } +#ifdef CURVE25519_ENABLED +/** Return true if the ntor handshake is enabled in the configuration, or if + * it's been set to "auto" in the configuration and it's enabled in the + * consensus. */ +static int +circuits_can_use_ntor(void) +{ + const or_options_t *options = get_options(); + if (options->UseNTorHandshake != -1) + return options->UseNTorHandshake; + return networkstatus_get_param(NULL, "UseNTorHandshake", 0, 0, 1); +} +#endif + +/** Decide whether to use a TAP or ntor handshake for connecting to ei + * directly, and set *cell_type_out and *handshake_type_out + * accordingly. */ +static void +circuit_pick_create_handshake(uint8_t *cell_type_out, + uint16_t *handshake_type_out, + const extend_info_t *ei) +{ +#ifdef CURVE25519_ENABLED + if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key, + CURVE25519_PUBKEY_LEN) && + circuits_can_use_ntor()) { + *cell_type_out = CELL_CREATE2; + *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; + return; + } +#else + (void) ei; +#endif + + *cell_type_out = CELL_CREATE; + *handshake_type_out = ONION_HANDSHAKE_TYPE_TAP; +} + +/** Decide whether to use a TAP or ntor handshake for connecting to ei + * directly, and set *handshake_type_out accordingly. Decide whether, + * in extending through node to do so, we should use an EXTEND2 or an + * EXTEND cell to do so, and set *cell_type_out and + * *create_cell_type_out accordingly. */ +static void +circuit_pick_extend_handshake(uint8_t *cell_type_out, + uint8_t *create_cell_type_out, + uint16_t *handshake_type_out, + const node_t *node_prev, + const extend_info_t *ei) +{ + uint8_t t; + circuit_pick_create_handshake(&t, handshake_type_out, ei); + /* XXXX024 The check for whether the node has a curve25519 key is a bad + * proxy for whether it can do extend2 cells; once a version that + * handles extend2 cells is out, remove it. */ + if (node_prev && + *handshake_type_out != ONION_HANDSHAKE_TYPE_TAP && + (node_has_curve25519_onion_key(node_prev) || + (node_prev->rs && node_prev->rs->version_supports_extend2_cells))) { + *cell_type_out = RELAY_COMMAND_EXTEND2; + *create_cell_type_out = CELL_CREATE2; + } else { + *cell_type_out = RELAY_COMMAND_EXTEND; + *create_cell_type_out = CELL_CREATE; + } +} + /** This is the backbone function for building circuits. * * If circ's first hop is closed, then we need to build a create @@ -638,10 +705,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) fast = should_use_create_fast_for_circuit(circ); if (!fast) { /* We are an OR and we know the right onion key: we should - * send an old slow create cell. + * send a create cell. */ - cc.cell_type = CELL_CREATE; - cc.handshake_type = ONION_HANDSHAKE_TYPE_TAP; + circuit_pick_create_handshake(&cc.cell_type, &cc.handshake_type, + circ->cpath->extend_info); note_request("cell: create", 1); } else { /* We are not an OR, and we're building the first hop of a circuit to a @@ -747,15 +814,21 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) return - END_CIRC_REASON_INTERNAL; } - ec.cell_type = RELAY_COMMAND_EXTEND; + { + const node_t *prev_node; + prev_node = node_get_by_id(hop->prev->extend_info->identity_digest); + circuit_pick_extend_handshake(&ec.cell_type, + &ec.create_cell.cell_type, + &ec.create_cell.handshake_type, + prev_node, + hop->extend_info); + } + 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); - ec.create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP; - ec.create_cell.cell_type = CELL_CREATE; - len = onion_skin_create(ec.create_cell.handshake_type, hop->extend_info, &hop->handshake_state, @@ -903,6 +976,7 @@ circuit_extend(cell_t *cell, circuit_t *circ) circ->n_hop = extend_info_new(NULL /*nickname*/, (const char*)ec.node_id, NULL /*onion_key*/, + NULL /*curve25519_key*/, &ec.orport_ipv4.addr, ec.orport_ipv4.port); @@ -938,6 +1012,7 @@ circuit_extend(cell_t *cell, circuit_t *circ) if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0) return -1; + return 0; } @@ -2310,8 +2385,9 @@ onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) /** Allocate a new extend_info object based on the various arguments. */ extend_info_t * extend_info_new(const char *nickname, const char *digest, - crypto_pk_t *onion_key, - const tor_addr_t *addr, uint16_t port) + crypto_pk_t *onion_key, + const curve25519_public_key_t *curve25519_key, + const tor_addr_t *addr, uint16_t port) { extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t)); memcpy(info->identity_digest, digest, DIGEST_LEN); @@ -2319,6 +2395,13 @@ extend_info_new(const char *nickname, const char *digest, strlcpy(info->nickname, nickname, sizeof(info->nickname)); if (onion_key) info->onion_key = crypto_pk_dup_key(onion_key); +#ifdef CURVE25519_ENABLED + if (curve25519_key) + memcpy(&info->curve25519_onion_key, curve25519_key, + sizeof(curve25519_public_key_t)); +#else + (void)curve25519_key; +#endif tor_addr_copy(&info->addr, addr); info->port = port; return info; @@ -2353,12 +2436,14 @@ extend_info_from_node(const node_t *node, int for_direct_connect) return extend_info_new(node->ri->nickname, node->identity, node->ri->onion_pkey, + node->ri->onion_curve25519_pkey, &ap.addr, ap.port); else if (node->rs && node->md) return extend_info_new(node->rs->nickname, node->identity, node->md->onion_pkey, + node->md->onion_curve25519_pkey, &ap.addr, ap.port); else diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 23213e8e8..d4f7926ca 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -46,8 +46,9 @@ int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info); int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info); void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop); extend_info_t *extend_info_new(const char *nickname, const char *digest, - crypto_pk_t *onion_key, - const tor_addr_t *addr, uint16_t port); + crypto_pk_t *onion_key, + const curve25519_public_key_t *curve25519_key, + const tor_addr_t *addr, uint16_t port); extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect); extend_info_t *extend_info_dup(extend_info_t *info); void extend_info_free(extend_info_t *info); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index d3cde1d66..6a733d6d1 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1577,8 +1577,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, return -1; } extend_info = extend_info_new(conn->chosen_exit_name+1, - digest, NULL, &addr, - conn->socks_request->port); + digest, NULL, NULL, &addr, + conn->socks_request->port); } else { /* We will need an onion key for the router, and we * don't have one. Refuse or relax requirements. */ diff --git a/src/or/config.c b/src/or/config.c index 75f619335..979d09c7c 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -383,6 +383,7 @@ static config_var_t option_vars_[] = { V(UseBridges, BOOL, "0"), V(UseEntryGuards, BOOL, "1"), V(UseMicrodescriptors, AUTOBOOL, "auto"), + V(UseNTorHandshake, AUTOBOOL, "auto"), V(User, STRING, NULL), V(UserspaceIOCPBuffers, BOOL, "0"), VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"), diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index edb26dc08..a4e18d04f 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -1502,7 +1502,7 @@ routerset_contains_bridge(const routerset_t *routerset, return 0; extinfo = extend_info_new( - NULL, bridge->identity, NULL, &bridge->addr, bridge->port); + NULL, bridge->identity, NULL, NULL, &bridge->addr, bridge->port); result = routerset_contains_extendinfo(routerset, extinfo); extend_info_free(extinfo); return result; diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 95345fb26..fa3828fc2 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -916,6 +916,18 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out) } } +/** Return true iff node has a curve25519 onion key. */ +int +node_has_curve25519_onion_key(const node_t *node) +{ + if (node->ri) + return node->ri->onion_curve25519_pkey != NULL; + else if (node->md) + return node->md->onion_curve25519_pkey != NULL; + else + return 0; +} + /** Refresh the country code of ri. This function MUST be called on * each router when the GeoIP database is reloaded, and on all new routers. */ void diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 13a384741..39f094877 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -54,6 +54,7 @@ int node_ipv6_preferred(const node_t *node); int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out); +int node_has_curve25519_onion_key(const node_t *node); smartlist_t *nodelist_get_list(void); diff --git a/src/or/or.h b/src/or/or.h index 66e905449..b5718a83d 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2025,6 +2025,9 @@ typedef struct routerstatus_t { /** True iff this router is a version that allows DATA cells to arrive on * a stream before it has sent a CONNECTED cell. */ unsigned int version_supports_optimistic_data:1; + /** True iff this router has a version that allows it to accept EXTEND2 + * cells */ + unsigned int version_supports_extend2_cells:1; unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */ unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */ @@ -3799,6 +3802,8 @@ typedef struct { int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */ + /** Autobool: should we use the ntor handshake if we can? */ + int UseNTorHandshake; } or_options_t; /** Persistent state for an onion router, as saved to disk. */ diff --git a/src/or/relay.c b/src/or/relay.c index 5d87b270f..ddeec4e78 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -572,6 +572,7 @@ relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ, origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); if (origin_circ->remaining_relay_early_cells > 0 && (relay_command == RELAY_COMMAND_EXTEND || + relay_command == RELAY_COMMAND_EXTEND2 || cpath_layer != origin_circ->cpath)) { /* If we've got any relay_early cells left and (we're sending * an extend cell or we're not talking to the first hop), use @@ -585,7 +586,8 @@ relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ, * task 878. */ origin_circ->relay_early_commands[ origin_circ->relay_early_cells_sent++] = relay_command; - } else if (relay_command == RELAY_COMMAND_EXTEND) { + } else if (relay_command == RELAY_COMMAND_EXTEND || + relay_command == RELAY_COMMAND_EXTEND2) { /* If no RELAY_EARLY cells can be sent over this circuit, log which * commands have been sent as RELAY_EARLY cells before; helps debug * task 878. */ diff --git a/src/or/router.c b/src/or/router.c index 3733bec4d..a97db858b 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1071,7 +1071,8 @@ extend_info_from_router(const routerinfo_t *r) router_get_prim_orport(r, &ap); return extend_info_new(r->nickname, r->cache_info.identity_digest, - r->onion_pkey, &ap.addr, ap.port); + r->onion_pkey, r->onion_curve25519_pkey, + &ap.addr, ap.port); } /** Some time has passed, or we just got new directory information. diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 17902d9d0..1be237406 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -2188,6 +2188,8 @@ routerstatus_parse_entry_from_string(memarea_t *area, tor_version_supports_microdescriptors(tok->args[0]); rs->version_supports_optimistic_data = tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha"); + rs->version_supports_extend2_cells = + tor_version_as_new_as(tok->args[0], "0.2.4.7-alpha"); } if (vote_rs) { vote_rs->version = tor_strdup(tok->args[0]); -- cgit v1.2.3