From 100386e659533cfa92c5bfff93a15fb3535f7970 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 5 Apr 2017 12:26:02 -0400 Subject: [PATCH] prop224: Support legacy INTRODUCE2 cell Also rename some function to follow a bit more the naming convention in that file. Signed-off-by: David Goulet --- src/or/hs_cell.c | 119 +++++++++++++++++++++++++++++++++++++++---- src/or/hs_cell.h | 2 + src/or/hs_circuit.c | 2 + src/or/hs_service.c | 4 +- src/or/rendservice.h | 4 +- 5 files changed, 116 insertions(+), 15 deletions(-) diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c index 68c201b890..9ab83525d4 100644 --- a/src/or/hs_cell.c +++ b/src/or/hs_cell.c @@ -207,6 +207,105 @@ build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key, return cell_len; } +/* Free the given cell pointer. If is_legacy_cell is set, cell_ptr is cast to + * a rend_intro_cell_t else to a trn_cell_introduce1_t. */ +static void +introduce2_free_cell(void *cell_ptr, unsigned int is_legacy_cell) +{ + if (cell_ptr == NULL) { + return; + } + if (is_legacy_cell) { + rend_intro_cell_t *legacy_cell = cell_ptr; + rend_service_free_intro(legacy_cell); + } else { + trn_cell_introduce1_free((trn_cell_introduce1_t *) cell_ptr); + } +} + +/* Return the length of the encrypted section of the cell_ptr. If + * is_legacy_cell is set, cell_ptr is cast to a rend_intro_cell_t else to a + * trn_cell_introduce1_t. */ +static size_t +get_introduce2_encrypted_section_len(const void *cell_ptr, + unsigned int is_legacy_cell) +{ + tor_assert(cell_ptr); + if (is_legacy_cell) { + return ((const rend_intro_cell_t *) cell_ptr)->ciphertext_len; + } + return trn_cell_introduce1_getlen_encrypted( + (const trn_cell_introduce1_t *) cell_ptr); +} + +/* Return the encrypted section pointer from the the cell_ptr. If + * is_legacy_cell is set, cell_ptr is cast to a rend_intro_cell_t else to a + * trn_cell_introduce1_t. */ +static const uint8_t * +get_introduce2_encrypted_section(const void *cell_ptr, + unsigned int is_legacy_cell) +{ + tor_assert(cell_ptr); + if (is_legacy_cell) { + return ((const rend_intro_cell_t *) cell_ptr)->ciphertext; + } + return trn_cell_introduce1_getconstarray_encrypted( + (const trn_cell_introduce1_t *) cell_ptr); +} + +/* Parse an INTRODUCE2 cell from payload of size payload_len for the given + * service and circuit which are used only for logging purposes. The resulting + * parsed cell is put in cell_ptr_out. If is_legacy_cell is set, the type of + * the returned cell is rend_intro_cell_t else trn_cell_introduce1_t. + * + * Return 0 on success else a negative value and cell_ptr_out is untouched. */ +static int +parse_introduce2_cell(const hs_service_t *service, + const origin_circuit_t *circ, const uint8_t *payload, + size_t payload_len, unsigned int is_legacy_cell, + void **cell_ptr_out) +{ + tor_assert(service); + tor_assert(circ); + tor_assert(payload); + tor_assert(cell_ptr_out); + + /* We parse the cell differently for legacy. */ + if (is_legacy_cell) { + char *err_msg; + rend_intro_cell_t *legacy_cell = NULL; + + legacy_cell = rend_service_begin_parse_intro(payload, payload_len, 2, + &err_msg); + if (legacy_cell == NULL) { + log_info(LD_REND, "Unable to parse legacy INTRODUCE2 cell on " + "circuit %u for service %s: %s", + TO_CIRCUIT(circ)->n_circ_id, err_msg, + safe_str_client(service->onion_address)); + tor_free(err_msg); + goto err; + } + *cell_ptr_out = legacy_cell; + } else { + trn_cell_introduce1_t *cell = NULL; + /* Parse the cell so we can start cell validation. */ + if (trn_cell_introduce1_parse(&cell, payload, payload_len) < 0) { + log_info(LD_PROTOCOL, "Unable to parse INTRODUCE2 cell on circuit %u " + "for service %s", + TO_CIRCUIT(circ)->n_circ_id, + safe_str_client(service->onion_address)); + goto err; + } + *cell_ptr_out = cell; + } + + /* On success, we must have set the cell pointer. */ + tor_assert(*cell_ptr_out); + return 0; + err: + return -1; +} + /* ========== */ /* Public API */ /* ========== */ @@ -364,21 +463,17 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, uint8_t *decrypted = NULL; size_t encrypted_section_len; const uint8_t *encrypted_section; - trn_cell_introduce1_t *cell = NULL; trn_cell_introduce_encrypted_t *enc_cell = NULL; hs_ntor_intro_cell_keys_t *intro_keys = NULL; + void *cell_ptr = NULL; tor_assert(data); tor_assert(circ); tor_assert(service); - /* Parse the cell so we can start cell validation. */ - if (trn_cell_introduce1_parse(&cell, data->payload, - data->payload_len) < 0) { - log_info(LD_PROTOCOL, "Unable to parse INTRODUCE2 cell on circuit %u " - "for service %s", - TO_CIRCUIT(circ)->n_circ_id, - safe_str_client(service->onion_address)); + /* Parse the cell into a decoded data structure pointed by cell_ptr. */ + if (parse_introduce2_cell(service, circ, data->payload, data->payload_len, + data->is_legacy, &cell_ptr) < 0) { goto done; } @@ -389,8 +484,10 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, TO_CIRCUIT(circ)->n_circ_id, safe_str_client(service->onion_address)); - encrypted_section = trn_cell_introduce1_getconstarray_encrypted(cell); - encrypted_section_len = trn_cell_introduce1_getlen_encrypted(cell); + encrypted_section = + get_introduce2_encrypted_section(cell_ptr, data->is_legacy); + encrypted_section_len = + get_introduce2_encrypted_section_len(cell_ptr, data->is_legacy); /* Encrypted section must at least contain the CLIENT_PK and MAC which is * defined in section 3.3.2 of the specification. */ @@ -496,8 +593,8 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, tor_free(intro_keys); } tor_free(decrypted); - trn_cell_introduce1_free(cell); trn_cell_introduce_encrypted_free(enc_cell); + introduce2_free_cell(cell_ptr, data->is_legacy); return ret; } diff --git a/src/or/hs_cell.h b/src/or/hs_cell.h index fb4950d519..6114182439 100644 --- a/src/or/hs_cell.h +++ b/src/or/hs_cell.h @@ -34,6 +34,8 @@ typedef struct hs_cell_introduce2_data_t { const uint8_t *payload; /* Size of the payload of the received encoded cell. */ size_t payload_len; + /* Is this a legacy introduction point? */ + unsigned int is_legacy : 1; /*** Muttable Section. ***/ diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c index 22a2c33479..543cbac6d3 100644 --- a/src/or/hs_circuit.c +++ b/src/or/hs_circuit.c @@ -13,6 +13,7 @@ #include "config.h" #include "policies.h" #include "relay.h" +#include "rendservice.h" #include "rephist.h" #include "router.h" @@ -809,6 +810,7 @@ hs_circ_handle_introduce2(const hs_service_t *service, data.payload = payload; data.payload_len = payload_len; data.link_specifiers = smartlist_new(); + data.is_legacy = ip->base.is_only_legacy; if (hs_cell_parse_introduce2(&data, circ, service) < 0) { goto done; diff --git a/src/or/hs_service.c b/src/or/hs_service.c index a2ab0629a8..48724e45cf 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -1914,8 +1914,8 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload, /* If we have an IP object, we MUST have a descriptor object. */ tor_assert(desc); - /* XXX: Handle legacy IP connection. */ - + /* The following will parse, decode and launch the rendezvous point circuit. + * Both current and legacy cells are handled. */ if (hs_circ_handle_introduce2(service, circ, ip, desc->desc->subcredential, payload, payload_len) < 0) { goto err; diff --git a/src/or/rendservice.h b/src/or/rendservice.h index a6d6ec6a46..819dfc176e 100644 --- a/src/or/rendservice.h +++ b/src/or/rendservice.h @@ -17,8 +17,6 @@ typedef struct rend_intro_cell_s rend_intro_cell_t; -#ifdef RENDSERVICE_PRIVATE - /* This can be used for both INTRODUCE1 and INTRODUCE2 */ struct rend_intro_cell_s { @@ -63,6 +61,8 @@ struct rend_intro_cell_s { uint8_t dh[DH_KEY_LEN]; }; +#ifdef RENDSERVICE_PRIVATE + /** Represents a single hidden service running at this OP. */ typedef struct rend_service_t { /* Fields specified in config file */