Loading src/or/command.c +61 −8 Original line number Diff line number Diff line Loading @@ -70,7 +70,9 @@ static void command_handle_incoming_channel(channel_listener_t *listener, /* These are the main functions for processing cells */ static void command_process_create_cell(cell_t *cell, channel_t *chan); static void command_process_create2v_cell(var_cell_t *cell, channel_t *chan); static void command_process_created_cell(cell_t *cell, channel_t *chan); static void command_process_created2v_cell(var_cell_t *cell, channel_t *chan); static void command_process_relay_cell(cell_t *cell, channel_t *chan); static void command_process_destroy_cell(cell_t *cell, channel_t *chan); Loading @@ -91,7 +93,9 @@ cell_command_to_string(uint8_t command) case CELL_NETINFO: return "netinfo"; case CELL_RELAY_EARLY: return "relay_early"; case CELL_CREATE2: return "create2"; case CELL_CREATE2V: return "create2v"; case CELL_CREATED2: return "created2"; case CELL_CREATED2V: return "created2v"; case CELL_VPADDING: return "vpadding"; case CELL_CERTS: return "certs"; case CELL_AUTH_CHALLENGE: return "auth_challenge"; Loading Loading @@ -209,21 +213,40 @@ command_process_cell(channel_t *chan, cell_t *cell) } } /** Process an incoming var_cell from a channel; in the current protocol all * the var_cells are handshake-related and handled below the channel layer, * so this just logs a warning and drops the cell. /** * Process an incoming <b>var_cell</b> from a channel, <b>chan</b>. * * In the current protocol nearly all the var_cells are link handshake-related * and handled below the channel layer. However, a few types of var_cell_t are * handled here, namely those which contain: * * <ul> * <li> CREATE2V data * <li> CREATED2V data * </ul> */ void command_process_var_cell(channel_t *chan, var_cell_t *var_cell) { tor_assert(chan); tor_assert(var_cell); switch (var_cell->headers.command) { case CELL_CREATE2V: ++stats_n_create_cells_processed; PROCESS_CELL(create2v, var_cell, chan); break; case CELL_CREATED2V: ++stats_n_created_cells_processed; PROCESS_CELL(created2v, var_cell, chan); break; default: log_info(LD_PROTOCOL, "Received unexpected var_cell above the channel layer of type %d" "; dropping it.", "Received unknown or unexpected var_cell above the " "channel layer of type %d; dropping it.", var_cell->headers.command); break; } } /** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a Loading Loading @@ -391,6 +414,19 @@ command_process_create_cell(cell_t *cell, channel_t *chan) } } /** * Process a 'create2v' <b>cell</b> that just arrived from <b>chan</b>. Make a * new circuit with the p_circ_id specified in cell. Put the circuit in state * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get * picked up again when the cpuworker finishes decrypting it. */ static void command_process_create2v_cell(var_cell_t *cell, channel_t *chan) { (void)cell, (void)chan; // XXXisis } /** Process a 'created' <b>cell</b> that just arrived from <b>chan</b>. * Find the circuit * that it's intended for. If we're not the origin of the circuit, package Loading Loading @@ -465,6 +501,23 @@ command_process_created_cell(cell_t *cell, channel_t *chan) } } /** * Process a created2v <b>cell</b> that just arrived from <b>chan</b>. * * Find the circuit that it's intended for. If we're not the origin of the * circuit, package the 'created2v' cell in an 'extended2' relay cell and pass * it back. If we are the origin of the circuit, send it to * circuit_finish_handshake() to finish processing keys, and then call * circuit_send_next_onion_skin() to extend to the next hop in the circuit if * necessary. */ static void command_process_created2v_cell(var_cell_t *cell, channel_t *chan) { (void)cell, (void)chan; // XXXisis } /** Process a 'relay' or 'relay_early' <b>cell</b> that just arrived from * <b>conn</b>. Make sure it came in with a recognized circ_id. Pass it on to * circuit_receive_relay_cell() for actual processing. Loading src/or/onion.c +467 −1 Original line number Diff line number Diff line Loading @@ -53,7 +53,8 @@ * too long. * <li>Packaging private keys on the server side in order to pass * them to worker threads. * <li>Encoding and decoding CREATE, CREATED, CREATE2, and CREATED2 cells. * <li>Encoding and decoding CREATE, CREATED, CREATE2, CREATED2, CREATE2V, * and CREATED2V cells. * <li>Encoding and decodign EXTEND, EXTENDED, EXTEND2, and EXTENDED2 * relay cells. * </ul> Loading Loading @@ -691,6 +692,8 @@ check_create_cell(const create_cell_t *cell, int unknown_ok) break; case CELL_CREATE2: break; case CELL_CREATE2V: break; default: return -1; } Loading Loading @@ -1339,3 +1342,466 @@ extended_cell_format(uint8_t *command_out, uint16_t *len_out, return 0; } /***************************************************************************** * CREATE2V CELL HANDLING * *****************************************************************************/ /** * Allocate memory and create a new <b>create2v_cell_t</b>. * * All variable length fields in the CREATE2V cell's body will be set * to NULL, and all their corresponding lengths set to 0x00. */ create2v_cell_t* create2v_cell_new(void) { create2v_cell_t *cell; cell = tor_malloc(sizeof(create2v_cell_t)); cell->body = create2v_cell_body_new(); return cell; } /** * Conduct various length checks on some handshake and padding data lengths for * a given <b>handshake_type</b>. * * If <b>is_initiator</b> is true, then lengths are checked for the Alice side * of the handshake, otherwise, if false, the checks are run for Bob's * response. */ // XXXisis should this instead return bool and report errors rather than // asserting? static void check_handshake_and_padding_len(const uint16_t handshake_type, const uint16_t handshake_len, const uint16_t padding_len, const bool is_initiator) { (void)is_initiator; /* TODO: Check lengths once we have a handshake.--isis */ switch (handshake_type) { /* TODO: When we have handshake types which use wide cells, we should check * that their lengths match the expected lengths here. --isis */ default: /* If we've been given handshake_data, make sure we were given a * length in (0,10240]. */ tor_assert(handshake_len > 0); tor_assert(handshake_len <= 10240); /* If we've been given both handshake_data and padding_data, make * sure their combined reported lengths are not greater than the * maximum. */ tor_assert(handshake_len + padding_len <= 10240); } } /** * Initialise a CREATE2V cell. * * Copies <b>handshake_len</b> bytes of <b>handshake_data</b> into the * <b>cell_out</b>'s body.hdata member, and then copies <b>padding_len</b> * bytes of <b>padding_data</b> into the <b>cell_out</b>'s body.ignored member. * Also sets cell_out->body.htype to <b>handshake_type</b>. */ void create2v_cell_init(create2v_cell_t *cell_out, const uint16_t handshake_type, const uint8_t *handshake_data, const uint16_t handshake_len, const uint8_t *padding_data, const uint16_t padding_len) { tor_assert(cell_out); check_handshake_and_padding_len(handshake_type, handshake_len, padding_len, true); create2v_cell_body_set_htype(cell_out->body, handshake_type); create2v_cell_body_set_hlen(cell_out->body, handshake_len); create2v_cell_body_setlen_hdata(cell_out->body, (size_t)handshake_len); create2v_cell_body_setlen_ignored(cell_out->body, (size_t)padding_len); if (handshake_len) memcpy(create2v_cell_body_getarray_hdata(cell_out->body), handshake_data, handshake_len); if (padding_len) memcpy(create2v_cell_body_getarray_ignored(cell_out->body), padding_data, padding_len); } /** * Deallocate a CREATE2V cell. */ void create2v_cell_free(create2v_cell_t *cell) { create2v_cell_body_free(cell->body); tor_free(cell); } /** * Given the Create2VMaximumData consensus parameter, calculate the * total maximum allowable size of an incoming CREATE(D)2V buffer. */ static int create2v_cell_calculate_maximum_total(void) { return networkstatus_get_create2v_maximum_data(NULL) // XXXisis what about these extra bits of stuff? are we only counting // "ignored" and "hdata" as data? or should we also count all of this? + 2 // for the uint16_t htype + 2 // for the uint16_t hlen + sizeof(size_t) * 4 // for n_ and allocated_ in TRUNNEL_DYNARRAY_HEADs + 1; // for the uint8_t trunnel_error_code_ } /** * Check that the encoded length of an incoming CREATE2V or CREATED2V cell is * less than the maximum allowed. * * Returns true if it's okay, and false otherwise. */ static bool create2v_cell_check_encoded_length(const size_t len) { const uint16_t max_len = create2v_cell_calculate_maximum_total(); /* If the incoming buffer is reportedly way larger than that which would fill * the allowable space for hdata and the ignored padding, then fail parsing * early. */ if (len > max_len) { log_info(LD_OR, "Received a suspicious CREATE(D)2V cell whose reported " "length (%zd bytes) was greater that the maximum allowed (%hd " "bytes). This is either an attempted DoS, or there exist " "newer/other onion routers speaking a circuit handshake we " "don't know about.", len, max_len); return false; } if (len == 0) { log_info(LD_OR, "Received a strange CREATE(D)2V cell whose reported " "length was 0 bytes."); return false; } return true; } /** * Parse the CREATE2V payload at <b>p</b>, which could be up to <b>p_len</b> * bytes long, and use it to fill the fields of <b>cell_out->body</b>. * * Note that part of the body of an EXTEND2V cell is a CREATE2V payload, so * this function is also used for parsing those. * * Returns true if parsing was successful, and false otherwise. */ static bool parse_create2v_payload(create2v_cell_t *cell_out, const uint8_t *p, const size_t p_len) { create2v_cell_body_t *body; /* Check the length before even attempting to parse it. */ if (!create2v_cell_check_encoded_length(p_len)) { return false; } create2v_cell_body_parse(&body, p, p_len); cell_out->body = body; return create2v_cell_check(cell_out, true); } /** * Parse a CREATE2V cell from <b>cell_in</b> into <b>cell_out</b>. * * Returns true if parsing was successful, and false otherwise. */ bool create2v_cell_parse(create2v_cell_t *cell_out, const var_cell_t *cell_in) { switch (cell_in->headers.command) { case CELL_CREATE2V: return parse_create2v_payload(cell_out, cell_in->payload, cell_in->payload_len); default: return false; } } /** * Run various checks to ensure that a create2v_cell_t, <b>cell</b>, is * well-formed. * * If <b>unknown_ok</b> is true, then handshake types we don't know about yet * are okay. * * In the future, checks such as verifying that the handshake data (for a * particular handshake) should go here. * * Returns true if the <b>cell</b> is okay, and false otherwise. */ bool create2v_cell_check(const create2v_cell_t *cell, bool unknown_ok) { const char *not_okay; not_okay = create2v_cell_body_check(cell->body); if (not_okay) { log_warn(LD_BUG, "Unable to parse a CREATE2V cell: %s", not_okay); return false; } switch (create2v_cell_body_get_htype(cell->body)) { case ONION_HANDSHAKE_TYPE_NTOR2_NULL: if (create2v_cell_body_get_hlen(cell->body) > ONION_HANDSHAKE_TYPE_NTOR2_NULL_MAXLEN) { return false; } break; default: if (! unknown_ok) return false; } return true; } /** * Fill <b>cell_out</b> with up to <b>payload_len</b> bytes of a correctly * formatted version of the CREATE2V cell in <b>cell_in</b>. * * If <b>relayed</b> is true, then this is a cell not originating from us. * * Returns true if the formatting was successful, and false otherwise. */ static bool create2v_cell_format_impl(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in, const bool relayed) { size_t body_len; tor_assert(cell_out); tor_assert(cell_in); tor_assert(cell_in->body); body_len = create2v_cell_body_encoded_len(cell_in->body); if (!create2v_cell_check(cell_in, relayed)) return false; if (body_len > networkstatus_get_create2v_maximum_data(NULL)) return false; if (body_len > payload_len) return false; memset(cell_out->payload, 0, payload_len); cell_out->headers.command = CELL_CREATE2V; cell_out->payload_len = payload_len; if (create2v_cell_body_encode(cell_out->payload, (size_t)payload_len, cell_in->body) < 0) { return false; } return true; } /** * Fill <b>cell_out</b> with up to <b>payload_len</b> bytes of a correctly * formatted version of a CREATE2V cell originating from here in * <b>cell_in</b>. * * Returns true if the formatting was successful, and false otherwise. */ bool create2v_cell_format(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in) { return create2v_cell_format_impl(cell_out, payload_len, cell_in, false); } /** * Fill <b>cell_out</b> with up to <b>payload_len</b> bytes of a correctly * formatted version of a relayed CREATE2V cell in <b>cell_in</b>. * * Returns true if the formatting was successful, and false otherwise. */ bool create2v_cell_format_relayed(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in) { return create2v_cell_format_impl(cell_out, payload_len, cell_in, true); } /***************************************************************************** * CREATED2V CELL HANDLING * *****************************************************************************/ /** * Allocate memory and create a new <b>created2v_cell_t</b>. * * All variable length fields in the CREATED2V cell's body will be set * to NULL, and all their corresponding lengths set to 0x00. */ created2v_cell_t* created2v_cell_new(void) { created2v_cell_t *cell; cell = tor_malloc(sizeof(created2v_cell_t)); cell->body = created2v_cell_body_new(); return cell; } /** * Initialise a created2v cell, <b>cell_out</b> with some <b>handshake_data</b> * (of <b>handshake_len</b> bytes) for <b>handshake_type</b> and, optionally, * some <b>padding_data</b> (of <b>padding_len</b> bytes). */ void created2v_cell_init(created2v_cell_t *cell_out, const uint16_t handshake_type, // XXXisis do we have this? const uint8_t *handshake_data, const uint16_t handshake_len, const uint8_t *padding_data, const uint16_t padding_len) { tor_assert(cell_out); check_handshake_and_padding_len(handshake_type, handshake_len, padding_len, false); created2v_cell_body_set_hlen(cell_out->body, handshake_len); created2v_cell_body_setlen_hdata(cell_out->body, (size_t)handshake_len); created2v_cell_body_setlen_ignored(cell_out->body, (size_t)padding_len); if (handshake_len) memcpy(created2v_cell_body_getarray_hdata(cell_out->body), handshake_data, handshake_len); if (padding_len) memcpy(created2v_cell_body_getarray_ignored(cell_out->body), padding_data, padding_len); } /** * Deallocate a CREATED2V cell. */ void created2v_cell_free(created2v_cell_t *cell) { created2v_cell_body_free(cell->body); tor_free(cell); } /** * Run various checks to ensure that a created2v_cell_t, <b>cell</b>, is * well-formed. * * In the future, checks such as verifying that the handshake data (for a * particular handshake) should go here. */ bool created2v_cell_check(const created2v_cell_t *cell) { const created2v_cell_body_t *body = cell->body; const char *not_okay = created2v_cell_body_check(body); if (not_okay != NULL) { log_warn(LD_BUG, "Unable to parse a CREATED2V cell: %s", not_okay); return false; } /* Do not allow empty responses. */ if (!created2v_cell_body_get_hlen(body)) return false; return true; } /** * Parse the CREATED2V payload at <b>p</b>, which could be up to <b>p_len</b> * bytes long, and use it to fill the fields of <b>cell_out->body</b>. * * Note that part of the body of an EXTENDED2V cell is a CREATED2V payload, so * this function is also used for parsing those. * * Returns true if parsing was successful, and false otherwise. */ static bool parse_created2v_payload(created2v_cell_t *cell_out, const uint8_t *p, const size_t p_len) { created2v_cell_body_t *body; create2v_cell_check_encoded_length(p_len); created2v_cell_body_parse(&body, p, p_len); cell_out->body = body; if (created2v_cell_check(cell_out)) return true; return false; } /** * Parse a CREATED2V cell from <b>cell_in</b> into <b>cell_out</b>. * * Returns true if parsing was successful, and false otherwise. */ bool created2v_cell_parse(created2v_cell_t *cell_out, const var_cell_t *cell_in) { switch (cell_in->headers.command) { case CELL_CREATED2V: return parse_created2v_payload(cell_out, cell_in->payload, cell_in->payload_len); default: return false; } } /** * Fill <b>cell_out</b> with a correctly formatted version of the CREATED2V * cell in <b>cell_in</b>, up to <b>payload_len</b> bytes long. * * Returns true upon success, otherwise false if something went wrong. */ bool created2v_cell_format(var_cell_t *cell_out, const size_t payload_len, const created2v_cell_t *cell_in) { size_t body_len; body_len = created2v_cell_body_encoded_len(cell_in->body); if (!created2v_cell_check(cell_in)) return false; if (body_len > networkstatus_get_create2v_maximum_data(NULL)) return false; if (body_len > payload_len) return false; memset(cell_out->payload, 0, payload_len); cell_out->headers.command = CELL_CREATED2V; cell_out->payload_len = payload_len; if (created2v_cell_body_encode(cell_out->payload, (size_t)payload_len, cell_in->body) < 0) { return false; } return true; } src/or/onion.h +84 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,14 @@ #ifndef TOR_ONION_H #define TOR_ONION_H #include "torint.h" /* Trunnel */ #include "cell_created2v.h" struct create2v_cell_body_t; struct created2v_cell_body_t; 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); Loading Loading @@ -66,6 +74,25 @@ typedef struct create_cell_t { uint8_t onionskin[CELL_PAYLOAD_SIZE - 4]; } create_cell_t; /** * A parsed CREATE2V cell. */ typedef struct create2v_cell_t { /** * The body of the cell, containing the htype, hlen, hdata, and ignored * (padding) fields. Note that the body->hdata is not ready for actual * parsing by handshake code until this struct's <b>finished</b> bit is set. */ create2v_cell_body_t *body; /** * Whether or not we're done parsing incoming fragments of this cell. If the * bit is set to 1, then we've collected all the data that the first cell * fragment specified as the length of all fragments combined. Otherwise, if * 0, we're still waiting on incoming data. */ unsigned int finished: 1; } create2v_cell_t; /** A parsed CREATED, CREATED_FAST, or CREATED2 cell. */ typedef struct created_cell_t { /** The cell command. One of CREATED{,_FAST,2} */ Loading @@ -76,6 +103,18 @@ typedef struct created_cell_t { uint8_t reply[CELL_PAYLOAD_SIZE - 2]; } created_cell_t; /** * A parsed CREATED2V cell. */ typedef struct created2v_cell_t { /** * The body of the cell, containing the htype, hlen, hdata, and ignored * (padding) fields. Note that the body->hdata is not ready for actual * parsing by handshake code until this struct's <b>finished</b> bit is set. */ created2v_cell_body_t *body; } created2v_cell_t; /** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */ typedef struct extend_cell_t { /** One of RELAY_EXTEND or RELAY_EXTEND2 */ Loading Loading @@ -121,5 +160,50 @@ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, int extended_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extended_cell_t *cell_in); // TODO: Remove these defines when we implement the first handshake that uses // CREATE(D)2V cells. --isis #ifndef ONION_HANDSHAKE_TYPE_NTOR2_NULL #define ONION_HANDSHAKE_TYPE_NTOR2_NULL 0x0003 #endif #ifndef ONION_HANDSHAKE_TYPE_NTOR2_NULL_MAXLEN /** * ONION_HANDSHAKE_TYPE_NTOR2_NULL should be defined as equal to * NTOR_ONIONSKIN_LEN. */ #define ONION_HANDSHAKE_TYPE_NTOR2_NULL_MAXLEN 84 #endif create2v_cell_t* create2v_cell_new(void); void create2v_cell_init(create2v_cell_t *cell_out, const uint16_t handshake_type, const uint8_t *handshake_data, const uint16_t handshake_len, const uint8_t *padding_data, const uint16_t padding_len); void create2v_cell_free(create2v_cell_t *cell); bool create2v_cell_parse(create2v_cell_t *cell_out, const var_cell_t *cell_in); bool create2v_cell_check(const create2v_cell_t *cell, bool unknown_ok); bool create2v_cell_format(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in); bool create2v_cell_format_relayed(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in); created2v_cell_t* created2v_cell_new(void); void created2v_cell_init(created2v_cell_t *cell_out, const uint16_t handshake_type, const uint8_t *handshake_data, const uint16_t handshake_len, const uint8_t *padding_data, const uint16_t padding_len); void created2v_cell_free(created2v_cell_t *cell); bool created2v_cell_check(const created2v_cell_t *cell); bool created2v_cell_parse(created2v_cell_t *cell_out, const var_cell_t *cell_in); bool created2v_cell_format(var_cell_t *cell_out, const size_t payload_len, const created2v_cell_t *cell_in); #endif /* !defined(TOR_ONION_H) */ src/or/or.h +2 −0 Original line number Diff line number Diff line Loading @@ -959,6 +959,8 @@ typedef enum { #define CELL_CREATE2 10 #define CELL_CREATED2 11 #define CELL_PADDING_NEGOTIATE 12 #define CELL_CREATE2V 13 #define CELL_CREATED2V 14 #define CELL_VPADDING 128 #define CELL_CERTS 129 Loading Loading
src/or/command.c +61 −8 Original line number Diff line number Diff line Loading @@ -70,7 +70,9 @@ static void command_handle_incoming_channel(channel_listener_t *listener, /* These are the main functions for processing cells */ static void command_process_create_cell(cell_t *cell, channel_t *chan); static void command_process_create2v_cell(var_cell_t *cell, channel_t *chan); static void command_process_created_cell(cell_t *cell, channel_t *chan); static void command_process_created2v_cell(var_cell_t *cell, channel_t *chan); static void command_process_relay_cell(cell_t *cell, channel_t *chan); static void command_process_destroy_cell(cell_t *cell, channel_t *chan); Loading @@ -91,7 +93,9 @@ cell_command_to_string(uint8_t command) case CELL_NETINFO: return "netinfo"; case CELL_RELAY_EARLY: return "relay_early"; case CELL_CREATE2: return "create2"; case CELL_CREATE2V: return "create2v"; case CELL_CREATED2: return "created2"; case CELL_CREATED2V: return "created2v"; case CELL_VPADDING: return "vpadding"; case CELL_CERTS: return "certs"; case CELL_AUTH_CHALLENGE: return "auth_challenge"; Loading Loading @@ -209,21 +213,40 @@ command_process_cell(channel_t *chan, cell_t *cell) } } /** Process an incoming var_cell from a channel; in the current protocol all * the var_cells are handshake-related and handled below the channel layer, * so this just logs a warning and drops the cell. /** * Process an incoming <b>var_cell</b> from a channel, <b>chan</b>. * * In the current protocol nearly all the var_cells are link handshake-related * and handled below the channel layer. However, a few types of var_cell_t are * handled here, namely those which contain: * * <ul> * <li> CREATE2V data * <li> CREATED2V data * </ul> */ void command_process_var_cell(channel_t *chan, var_cell_t *var_cell) { tor_assert(chan); tor_assert(var_cell); switch (var_cell->headers.command) { case CELL_CREATE2V: ++stats_n_create_cells_processed; PROCESS_CELL(create2v, var_cell, chan); break; case CELL_CREATED2V: ++stats_n_created_cells_processed; PROCESS_CELL(created2v, var_cell, chan); break; default: log_info(LD_PROTOCOL, "Received unexpected var_cell above the channel layer of type %d" "; dropping it.", "Received unknown or unexpected var_cell above the " "channel layer of type %d; dropping it.", var_cell->headers.command); break; } } /** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a Loading Loading @@ -391,6 +414,19 @@ command_process_create_cell(cell_t *cell, channel_t *chan) } } /** * Process a 'create2v' <b>cell</b> that just arrived from <b>chan</b>. Make a * new circuit with the p_circ_id specified in cell. Put the circuit in state * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get * picked up again when the cpuworker finishes decrypting it. */ static void command_process_create2v_cell(var_cell_t *cell, channel_t *chan) { (void)cell, (void)chan; // XXXisis } /** Process a 'created' <b>cell</b> that just arrived from <b>chan</b>. * Find the circuit * that it's intended for. If we're not the origin of the circuit, package Loading Loading @@ -465,6 +501,23 @@ command_process_created_cell(cell_t *cell, channel_t *chan) } } /** * Process a created2v <b>cell</b> that just arrived from <b>chan</b>. * * Find the circuit that it's intended for. If we're not the origin of the * circuit, package the 'created2v' cell in an 'extended2' relay cell and pass * it back. If we are the origin of the circuit, send it to * circuit_finish_handshake() to finish processing keys, and then call * circuit_send_next_onion_skin() to extend to the next hop in the circuit if * necessary. */ static void command_process_created2v_cell(var_cell_t *cell, channel_t *chan) { (void)cell, (void)chan; // XXXisis } /** Process a 'relay' or 'relay_early' <b>cell</b> that just arrived from * <b>conn</b>. Make sure it came in with a recognized circ_id. Pass it on to * circuit_receive_relay_cell() for actual processing. Loading
src/or/onion.c +467 −1 Original line number Diff line number Diff line Loading @@ -53,7 +53,8 @@ * too long. * <li>Packaging private keys on the server side in order to pass * them to worker threads. * <li>Encoding and decoding CREATE, CREATED, CREATE2, and CREATED2 cells. * <li>Encoding and decoding CREATE, CREATED, CREATE2, CREATED2, CREATE2V, * and CREATED2V cells. * <li>Encoding and decodign EXTEND, EXTENDED, EXTEND2, and EXTENDED2 * relay cells. * </ul> Loading Loading @@ -691,6 +692,8 @@ check_create_cell(const create_cell_t *cell, int unknown_ok) break; case CELL_CREATE2: break; case CELL_CREATE2V: break; default: return -1; } Loading Loading @@ -1339,3 +1342,466 @@ extended_cell_format(uint8_t *command_out, uint16_t *len_out, return 0; } /***************************************************************************** * CREATE2V CELL HANDLING * *****************************************************************************/ /** * Allocate memory and create a new <b>create2v_cell_t</b>. * * All variable length fields in the CREATE2V cell's body will be set * to NULL, and all their corresponding lengths set to 0x00. */ create2v_cell_t* create2v_cell_new(void) { create2v_cell_t *cell; cell = tor_malloc(sizeof(create2v_cell_t)); cell->body = create2v_cell_body_new(); return cell; } /** * Conduct various length checks on some handshake and padding data lengths for * a given <b>handshake_type</b>. * * If <b>is_initiator</b> is true, then lengths are checked for the Alice side * of the handshake, otherwise, if false, the checks are run for Bob's * response. */ // XXXisis should this instead return bool and report errors rather than // asserting? static void check_handshake_and_padding_len(const uint16_t handshake_type, const uint16_t handshake_len, const uint16_t padding_len, const bool is_initiator) { (void)is_initiator; /* TODO: Check lengths once we have a handshake.--isis */ switch (handshake_type) { /* TODO: When we have handshake types which use wide cells, we should check * that their lengths match the expected lengths here. --isis */ default: /* If we've been given handshake_data, make sure we were given a * length in (0,10240]. */ tor_assert(handshake_len > 0); tor_assert(handshake_len <= 10240); /* If we've been given both handshake_data and padding_data, make * sure their combined reported lengths are not greater than the * maximum. */ tor_assert(handshake_len + padding_len <= 10240); } } /** * Initialise a CREATE2V cell. * * Copies <b>handshake_len</b> bytes of <b>handshake_data</b> into the * <b>cell_out</b>'s body.hdata member, and then copies <b>padding_len</b> * bytes of <b>padding_data</b> into the <b>cell_out</b>'s body.ignored member. * Also sets cell_out->body.htype to <b>handshake_type</b>. */ void create2v_cell_init(create2v_cell_t *cell_out, const uint16_t handshake_type, const uint8_t *handshake_data, const uint16_t handshake_len, const uint8_t *padding_data, const uint16_t padding_len) { tor_assert(cell_out); check_handshake_and_padding_len(handshake_type, handshake_len, padding_len, true); create2v_cell_body_set_htype(cell_out->body, handshake_type); create2v_cell_body_set_hlen(cell_out->body, handshake_len); create2v_cell_body_setlen_hdata(cell_out->body, (size_t)handshake_len); create2v_cell_body_setlen_ignored(cell_out->body, (size_t)padding_len); if (handshake_len) memcpy(create2v_cell_body_getarray_hdata(cell_out->body), handshake_data, handshake_len); if (padding_len) memcpy(create2v_cell_body_getarray_ignored(cell_out->body), padding_data, padding_len); } /** * Deallocate a CREATE2V cell. */ void create2v_cell_free(create2v_cell_t *cell) { create2v_cell_body_free(cell->body); tor_free(cell); } /** * Given the Create2VMaximumData consensus parameter, calculate the * total maximum allowable size of an incoming CREATE(D)2V buffer. */ static int create2v_cell_calculate_maximum_total(void) { return networkstatus_get_create2v_maximum_data(NULL) // XXXisis what about these extra bits of stuff? are we only counting // "ignored" and "hdata" as data? or should we also count all of this? + 2 // for the uint16_t htype + 2 // for the uint16_t hlen + sizeof(size_t) * 4 // for n_ and allocated_ in TRUNNEL_DYNARRAY_HEADs + 1; // for the uint8_t trunnel_error_code_ } /** * Check that the encoded length of an incoming CREATE2V or CREATED2V cell is * less than the maximum allowed. * * Returns true if it's okay, and false otherwise. */ static bool create2v_cell_check_encoded_length(const size_t len) { const uint16_t max_len = create2v_cell_calculate_maximum_total(); /* If the incoming buffer is reportedly way larger than that which would fill * the allowable space for hdata and the ignored padding, then fail parsing * early. */ if (len > max_len) { log_info(LD_OR, "Received a suspicious CREATE(D)2V cell whose reported " "length (%zd bytes) was greater that the maximum allowed (%hd " "bytes). This is either an attempted DoS, or there exist " "newer/other onion routers speaking a circuit handshake we " "don't know about.", len, max_len); return false; } if (len == 0) { log_info(LD_OR, "Received a strange CREATE(D)2V cell whose reported " "length was 0 bytes."); return false; } return true; } /** * Parse the CREATE2V payload at <b>p</b>, which could be up to <b>p_len</b> * bytes long, and use it to fill the fields of <b>cell_out->body</b>. * * Note that part of the body of an EXTEND2V cell is a CREATE2V payload, so * this function is also used for parsing those. * * Returns true if parsing was successful, and false otherwise. */ static bool parse_create2v_payload(create2v_cell_t *cell_out, const uint8_t *p, const size_t p_len) { create2v_cell_body_t *body; /* Check the length before even attempting to parse it. */ if (!create2v_cell_check_encoded_length(p_len)) { return false; } create2v_cell_body_parse(&body, p, p_len); cell_out->body = body; return create2v_cell_check(cell_out, true); } /** * Parse a CREATE2V cell from <b>cell_in</b> into <b>cell_out</b>. * * Returns true if parsing was successful, and false otherwise. */ bool create2v_cell_parse(create2v_cell_t *cell_out, const var_cell_t *cell_in) { switch (cell_in->headers.command) { case CELL_CREATE2V: return parse_create2v_payload(cell_out, cell_in->payload, cell_in->payload_len); default: return false; } } /** * Run various checks to ensure that a create2v_cell_t, <b>cell</b>, is * well-formed. * * If <b>unknown_ok</b> is true, then handshake types we don't know about yet * are okay. * * In the future, checks such as verifying that the handshake data (for a * particular handshake) should go here. * * Returns true if the <b>cell</b> is okay, and false otherwise. */ bool create2v_cell_check(const create2v_cell_t *cell, bool unknown_ok) { const char *not_okay; not_okay = create2v_cell_body_check(cell->body); if (not_okay) { log_warn(LD_BUG, "Unable to parse a CREATE2V cell: %s", not_okay); return false; } switch (create2v_cell_body_get_htype(cell->body)) { case ONION_HANDSHAKE_TYPE_NTOR2_NULL: if (create2v_cell_body_get_hlen(cell->body) > ONION_HANDSHAKE_TYPE_NTOR2_NULL_MAXLEN) { return false; } break; default: if (! unknown_ok) return false; } return true; } /** * Fill <b>cell_out</b> with up to <b>payload_len</b> bytes of a correctly * formatted version of the CREATE2V cell in <b>cell_in</b>. * * If <b>relayed</b> is true, then this is a cell not originating from us. * * Returns true if the formatting was successful, and false otherwise. */ static bool create2v_cell_format_impl(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in, const bool relayed) { size_t body_len; tor_assert(cell_out); tor_assert(cell_in); tor_assert(cell_in->body); body_len = create2v_cell_body_encoded_len(cell_in->body); if (!create2v_cell_check(cell_in, relayed)) return false; if (body_len > networkstatus_get_create2v_maximum_data(NULL)) return false; if (body_len > payload_len) return false; memset(cell_out->payload, 0, payload_len); cell_out->headers.command = CELL_CREATE2V; cell_out->payload_len = payload_len; if (create2v_cell_body_encode(cell_out->payload, (size_t)payload_len, cell_in->body) < 0) { return false; } return true; } /** * Fill <b>cell_out</b> with up to <b>payload_len</b> bytes of a correctly * formatted version of a CREATE2V cell originating from here in * <b>cell_in</b>. * * Returns true if the formatting was successful, and false otherwise. */ bool create2v_cell_format(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in) { return create2v_cell_format_impl(cell_out, payload_len, cell_in, false); } /** * Fill <b>cell_out</b> with up to <b>payload_len</b> bytes of a correctly * formatted version of a relayed CREATE2V cell in <b>cell_in</b>. * * Returns true if the formatting was successful, and false otherwise. */ bool create2v_cell_format_relayed(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in) { return create2v_cell_format_impl(cell_out, payload_len, cell_in, true); } /***************************************************************************** * CREATED2V CELL HANDLING * *****************************************************************************/ /** * Allocate memory and create a new <b>created2v_cell_t</b>. * * All variable length fields in the CREATED2V cell's body will be set * to NULL, and all their corresponding lengths set to 0x00. */ created2v_cell_t* created2v_cell_new(void) { created2v_cell_t *cell; cell = tor_malloc(sizeof(created2v_cell_t)); cell->body = created2v_cell_body_new(); return cell; } /** * Initialise a created2v cell, <b>cell_out</b> with some <b>handshake_data</b> * (of <b>handshake_len</b> bytes) for <b>handshake_type</b> and, optionally, * some <b>padding_data</b> (of <b>padding_len</b> bytes). */ void created2v_cell_init(created2v_cell_t *cell_out, const uint16_t handshake_type, // XXXisis do we have this? const uint8_t *handshake_data, const uint16_t handshake_len, const uint8_t *padding_data, const uint16_t padding_len) { tor_assert(cell_out); check_handshake_and_padding_len(handshake_type, handshake_len, padding_len, false); created2v_cell_body_set_hlen(cell_out->body, handshake_len); created2v_cell_body_setlen_hdata(cell_out->body, (size_t)handshake_len); created2v_cell_body_setlen_ignored(cell_out->body, (size_t)padding_len); if (handshake_len) memcpy(created2v_cell_body_getarray_hdata(cell_out->body), handshake_data, handshake_len); if (padding_len) memcpy(created2v_cell_body_getarray_ignored(cell_out->body), padding_data, padding_len); } /** * Deallocate a CREATED2V cell. */ void created2v_cell_free(created2v_cell_t *cell) { created2v_cell_body_free(cell->body); tor_free(cell); } /** * Run various checks to ensure that a created2v_cell_t, <b>cell</b>, is * well-formed. * * In the future, checks such as verifying that the handshake data (for a * particular handshake) should go here. */ bool created2v_cell_check(const created2v_cell_t *cell) { const created2v_cell_body_t *body = cell->body; const char *not_okay = created2v_cell_body_check(body); if (not_okay != NULL) { log_warn(LD_BUG, "Unable to parse a CREATED2V cell: %s", not_okay); return false; } /* Do not allow empty responses. */ if (!created2v_cell_body_get_hlen(body)) return false; return true; } /** * Parse the CREATED2V payload at <b>p</b>, which could be up to <b>p_len</b> * bytes long, and use it to fill the fields of <b>cell_out->body</b>. * * Note that part of the body of an EXTENDED2V cell is a CREATED2V payload, so * this function is also used for parsing those. * * Returns true if parsing was successful, and false otherwise. */ static bool parse_created2v_payload(created2v_cell_t *cell_out, const uint8_t *p, const size_t p_len) { created2v_cell_body_t *body; create2v_cell_check_encoded_length(p_len); created2v_cell_body_parse(&body, p, p_len); cell_out->body = body; if (created2v_cell_check(cell_out)) return true; return false; } /** * Parse a CREATED2V cell from <b>cell_in</b> into <b>cell_out</b>. * * Returns true if parsing was successful, and false otherwise. */ bool created2v_cell_parse(created2v_cell_t *cell_out, const var_cell_t *cell_in) { switch (cell_in->headers.command) { case CELL_CREATED2V: return parse_created2v_payload(cell_out, cell_in->payload, cell_in->payload_len); default: return false; } } /** * Fill <b>cell_out</b> with a correctly formatted version of the CREATED2V * cell in <b>cell_in</b>, up to <b>payload_len</b> bytes long. * * Returns true upon success, otherwise false if something went wrong. */ bool created2v_cell_format(var_cell_t *cell_out, const size_t payload_len, const created2v_cell_t *cell_in) { size_t body_len; body_len = created2v_cell_body_encoded_len(cell_in->body); if (!created2v_cell_check(cell_in)) return false; if (body_len > networkstatus_get_create2v_maximum_data(NULL)) return false; if (body_len > payload_len) return false; memset(cell_out->payload, 0, payload_len); cell_out->headers.command = CELL_CREATED2V; cell_out->payload_len = payload_len; if (created2v_cell_body_encode(cell_out->payload, (size_t)payload_len, cell_in->body) < 0) { return false; } return true; }
src/or/onion.h +84 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,14 @@ #ifndef TOR_ONION_H #define TOR_ONION_H #include "torint.h" /* Trunnel */ #include "cell_created2v.h" struct create2v_cell_body_t; struct created2v_cell_body_t; 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); Loading Loading @@ -66,6 +74,25 @@ typedef struct create_cell_t { uint8_t onionskin[CELL_PAYLOAD_SIZE - 4]; } create_cell_t; /** * A parsed CREATE2V cell. */ typedef struct create2v_cell_t { /** * The body of the cell, containing the htype, hlen, hdata, and ignored * (padding) fields. Note that the body->hdata is not ready for actual * parsing by handshake code until this struct's <b>finished</b> bit is set. */ create2v_cell_body_t *body; /** * Whether or not we're done parsing incoming fragments of this cell. If the * bit is set to 1, then we've collected all the data that the first cell * fragment specified as the length of all fragments combined. Otherwise, if * 0, we're still waiting on incoming data. */ unsigned int finished: 1; } create2v_cell_t; /** A parsed CREATED, CREATED_FAST, or CREATED2 cell. */ typedef struct created_cell_t { /** The cell command. One of CREATED{,_FAST,2} */ Loading @@ -76,6 +103,18 @@ typedef struct created_cell_t { uint8_t reply[CELL_PAYLOAD_SIZE - 2]; } created_cell_t; /** * A parsed CREATED2V cell. */ typedef struct created2v_cell_t { /** * The body of the cell, containing the htype, hlen, hdata, and ignored * (padding) fields. Note that the body->hdata is not ready for actual * parsing by handshake code until this struct's <b>finished</b> bit is set. */ created2v_cell_body_t *body; } created2v_cell_t; /** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */ typedef struct extend_cell_t { /** One of RELAY_EXTEND or RELAY_EXTEND2 */ Loading Loading @@ -121,5 +160,50 @@ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, int extended_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extended_cell_t *cell_in); // TODO: Remove these defines when we implement the first handshake that uses // CREATE(D)2V cells. --isis #ifndef ONION_HANDSHAKE_TYPE_NTOR2_NULL #define ONION_HANDSHAKE_TYPE_NTOR2_NULL 0x0003 #endif #ifndef ONION_HANDSHAKE_TYPE_NTOR2_NULL_MAXLEN /** * ONION_HANDSHAKE_TYPE_NTOR2_NULL should be defined as equal to * NTOR_ONIONSKIN_LEN. */ #define ONION_HANDSHAKE_TYPE_NTOR2_NULL_MAXLEN 84 #endif create2v_cell_t* create2v_cell_new(void); void create2v_cell_init(create2v_cell_t *cell_out, const uint16_t handshake_type, const uint8_t *handshake_data, const uint16_t handshake_len, const uint8_t *padding_data, const uint16_t padding_len); void create2v_cell_free(create2v_cell_t *cell); bool create2v_cell_parse(create2v_cell_t *cell_out, const var_cell_t *cell_in); bool create2v_cell_check(const create2v_cell_t *cell, bool unknown_ok); bool create2v_cell_format(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in); bool create2v_cell_format_relayed(var_cell_t *cell_out, const size_t payload_len, const create2v_cell_t *cell_in); created2v_cell_t* created2v_cell_new(void); void created2v_cell_init(created2v_cell_t *cell_out, const uint16_t handshake_type, const uint8_t *handshake_data, const uint16_t handshake_len, const uint8_t *padding_data, const uint16_t padding_len); void created2v_cell_free(created2v_cell_t *cell); bool created2v_cell_check(const created2v_cell_t *cell); bool created2v_cell_parse(created2v_cell_t *cell_out, const var_cell_t *cell_in); bool created2v_cell_format(var_cell_t *cell_out, const size_t payload_len, const created2v_cell_t *cell_in); #endif /* !defined(TOR_ONION_H) */
src/or/or.h +2 −0 Original line number Diff line number Diff line Loading @@ -959,6 +959,8 @@ typedef enum { #define CELL_CREATE2 10 #define CELL_CREATED2 11 #define CELL_PADDING_NEGOTIATE 12 #define CELL_CREATE2V 13 #define CELL_CREATED2V 14 #define CELL_VPADDING 128 #define CELL_CERTS 129 Loading