prop224: Handle service INTRO_ESTABLISHED cell

Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
David Goulet 2017-03-07 14:33:03 -05:00 committed by Nick Mathewson
parent d765cf30b5
commit 79e8d113d5
7 changed files with 168 additions and 8 deletions

View File

@ -161,3 +161,25 @@ hs_cell_build_establish_intro(const char *circ_nonce,
return cell_len;
}
/* Parse the INTRO_ESTABLISHED cell in the payload of size payload_len. If we
* are successful at parsing it, return the length of the parsed cell else a
* negative value on error. */
ssize_t
hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
{
ssize_t ret;
trn_cell_intro_established_t *cell = NULL;
tor_assert(payload);
/* Try to parse the payload into a cell making sure we do actually have a
* valid cell. */
ret = trn_cell_intro_established_parse(&cell, payload, payload_len);
if (ret >= 0) {
/* On success, we do not keep the cell, we just notify the caller that it
* was successfully parsed. */
trn_cell_intro_established_free(cell);
}
return ret;
}

View File

@ -15,5 +15,8 @@ ssize_t hs_cell_build_establish_intro(const char *circ_nonce,
const hs_service_intro_point_t *ip,
uint8_t *cell_out);
ssize_t hs_cell_parse_intro_established(const uint8_t *payload,
size_t payload_len);
#endif /* TOR_HS_CELL_H */

View File

@ -428,6 +428,46 @@ hs_circ_service_intro_has_opened(hs_service_t *service,
return ret;
}
/* Handle an INTRO_ESTABLISHED cell payload of length payload_len arriving on
* the given introduction circuit circ. The service is only used for logging
* purposes. Return 0 on success else a negative value. */
int
hs_circ_handle_intro_established(const hs_service_t *service,
const hs_service_intro_point_t *ip,
origin_circuit_t *circ,
const uint8_t *payload, size_t payload_len)
{
int ret = -1;
tor_assert(service);
tor_assert(ip);
tor_assert(circ);
tor_assert(payload);
/* Try to parse the payload into a cell making sure we do actually have a
* valid cell. For a legacy node, it's an empty payload so as long as we
* have the cell, we are good. */
if (!ip->base.is_only_legacy &&
hs_cell_parse_intro_established(payload, payload_len) < 0) {
log_warn(LD_REND, "Unable to parse the INTRO_ESTABLISHED cell on "
"circuit %u for service %s",
TO_CIRCUIT(circ)->n_circ_id,
safe_str_client(service->onion_address));
goto done;
}
/* Switch the purpose to a fully working intro point. */
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_S_INTRO);
/* Getting a valid INTRODUCE_ESTABLISHED means we've successfully used the
* circuit so update our pathbias subsystem. */
pathbias_mark_use_success(circ);
/* Success. */
ret = 0;
done:
return ret;
}
/* Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key
* exchange output material at <b>ntor_key_seed</b> and setup <b>circ</b> to
* serve as a rendezvous end-to-end circuit between the client and the
@ -435,7 +475,7 @@ hs_circ_service_intro_has_opened(hs_service_t *service,
* and the other side is the client.
*
* Return 0 if the operation went well; in case of error return -1. */
int
int
hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
const uint8_t *ntor_key_seed, size_t seed_len,
int is_service_side)

View File

@ -28,6 +28,11 @@ int hs_circ_launch_intro_point(hs_service_t *service,
void hs_circ_send_establish_intro(const hs_service_t *service,
hs_service_intro_point_t *ip,
origin_circuit_t *circ);
int hs_circ_handle_intro_established(const hs_service_t *service,
const hs_service_intro_point_t *ip,
origin_circuit_t *circ,
const uint8_t *payload,
size_t payload_len);
/* e2e circuit API. */

View File

@ -1725,14 +1725,8 @@ service_intro_circ_has_opened(origin_circuit_t *circ)
goto err;
}
/* From the service object, get the intro point object of that circuit. The
* following will query both descriptors intro points list. */
ip = service_intro_point_find(service, &circ->hs_ident->intro_auth_pk);
if (ip == NULL) {
log_warn(LD_REND, "Unknown authentication key on the introduction "
"circuit %u for service %s",
TO_CIRCUIT(circ)->n_circ_id,
safe_str_client(service->onion_address));
/* Closing this circuit because we don't recognize the key. */
close_reason = END_CIRC_REASON_NOSUCHSERVICE;
goto err;
@ -1764,10 +1758,103 @@ service_rendezvous_circ_has_opened(origin_circuit_t *circ)
/* XXX: Implement rendezvous support. */
}
/* Handle an INTRO_ESTABLISHED cell arriving on the given introduction
* circuit. Return 0 on success else a negative value. */
static int
service_handle_intro_established(origin_circuit_t *circ,
const uint8_t *payload,
size_t payload_len)
{
hs_service_t *service = NULL;
hs_service_intro_point_t *ip = NULL;
tor_assert(circ);
tor_assert(payload);
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
/* Get service object from the circuit identifier. */
service = find_service(hs_service_map, &circ->hs_ident->identity_pk);
if (service == NULL) {
log_warn(LD_REND, "Unknown service identity key %s on the introduction "
"circuit %u. Can't find onion service.",
safe_str_client(ed25519_fmt(&circ->hs_ident->identity_pk)),
TO_CIRCUIT(circ)->n_circ_id);
goto err;
}
/* From the service object, get the intro point object of that circuit. The
* following will query both descriptors intro points list. */
ip = service_intro_point_find(service, &circ->hs_ident->intro_auth_pk);
if (ip == NULL) {
/* We don't recognize the key. */
log_warn(LD_REND, "Introduction circuit established without an intro "
"point object on circuit %u for service %s",
TO_CIRCUIT(circ)->n_circ_id,
safe_str_client(service->onion_address));
goto err;
}
/* Try to parse the payload into a cell making sure we do actually have a
* valid cell. On success, the ip object is updated. */
if (hs_circ_handle_intro_established(service, ip, circ, payload,
payload_len) < 0) {
goto err;
}
/* Flag that we have an established circuit for this intro point. This value
* is what indicates the upload scheduled event if we are ready to build the
* intro point into the descriptor and upload. */
ip->circuit_established = 1;
log_info(LD_REND, "Successfully received an INTRO_ESTABLISHED cell "
"on circuit %u for service %s",
TO_CIRCUIT(circ)->n_circ_id,
safe_str_client(service->onion_address));
return 0;
err:
return -1;
}
/* ========== */
/* Public API */
/* ========== */
/* Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an
* established introduction point. Return 0 on success else a negative value
* and the circuit is closed. */
int
hs_service_receive_intro_established(origin_circuit_t *circ,
const uint8_t *payload,
size_t payload_len)
{
int ret = -1;
tor_assert(circ);
tor_assert(payload);
if (TO_CIRCUIT(circ)->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_warn(LD_PROTOCOL, "Received an INTRO_ESTABLISHED cell on a "
"non introduction circuit of purpose %d",
TO_CIRCUIT(circ)->purpose);
goto err;
}
/* Handle both version. v2 uses rend_data and v3 uses the hs circuit
* identifier hs_ident. Can't be both. */
ret = (circ->hs_ident) ? service_handle_intro_established(circ, payload,
payload_len) :
rend_service_intro_established(circ, payload,
payload_len);
if (ret < 0) {
goto err;
}
return 0;
err:
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
return -1;
}
/* Called when any kind of hidden service circuit is done building thus
* opened. This is the entry point from the circuit subsystem. */
void

View File

@ -232,6 +232,9 @@ int hs_service_load_all_keys(void);
void hs_service_run_scheduled_events(time_t now);
void hs_service_circuit_has_opened(origin_circuit_t *circ);
int hs_service_receive_intro_established(origin_circuit_t *circ,
const uint8_t *payload,
size_t payload_len);
/* These functions are only used by unit tests and we need to expose them else
* hs_service.o ends up with no symbols in libor.a which makes clang throw a

View File

@ -793,7 +793,7 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
break;
case RELAY_COMMAND_INTRO_ESTABLISHED:
if (origin_circ)
r = rend_service_intro_established(origin_circ,payload,length);
r = hs_service_receive_intro_established(origin_circ,payload,length);
break;
case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
if (origin_circ)