mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 20:33:31 +01:00
prop224: Handle service INTRODUCE2 cell
At this commit, launching rendezvous circuit is not implemented, only a placeholder. Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
faadbafba3
commit
5e710368b3
318
src/or/hs_cell.c
318
src/or/hs_cell.c
@ -7,13 +7,180 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
#include "config.h"
|
||||||
#include "rendservice.h"
|
#include "rendservice.h"
|
||||||
|
|
||||||
#include "hs_cell.h"
|
#include "hs_cell.h"
|
||||||
|
#include "hs_ntor.h"
|
||||||
|
|
||||||
/* Trunnel. */
|
/* Trunnel. */
|
||||||
|
#include "ed25519_cert.h"
|
||||||
#include "hs/cell_common.h"
|
#include "hs/cell_common.h"
|
||||||
#include "hs/cell_establish_intro.h"
|
#include "hs/cell_establish_intro.h"
|
||||||
|
#include "hs/cell_introduce1.h"
|
||||||
|
|
||||||
|
/* Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is
|
||||||
|
* the cell content up to the ENCRYPTED section of length encoded_cell_len.
|
||||||
|
* The encrypted param is the start of the ENCRYPTED section of length
|
||||||
|
* encrypted_len. The mac_key is the key needed for the computation of the MAC
|
||||||
|
* derived from the ntor handshake of length mac_key_len.
|
||||||
|
*
|
||||||
|
* The length mac_out_len must be at least DIGEST256_LEN. */
|
||||||
|
static void
|
||||||
|
compute_introduce_mac(const uint8_t *encoded_cell, size_t encoded_cell_len,
|
||||||
|
const uint8_t *encrypted, size_t encrypted_len,
|
||||||
|
const uint8_t *mac_key, size_t mac_key_len,
|
||||||
|
uint8_t *mac_out, size_t mac_out_len)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t mac_msg_len;
|
||||||
|
uint8_t mac_msg[RELAY_PAYLOAD_SIZE] = {0};
|
||||||
|
|
||||||
|
tor_assert(encoded_cell);
|
||||||
|
tor_assert(encrypted);
|
||||||
|
tor_assert(mac_key);
|
||||||
|
tor_assert(mac_out);
|
||||||
|
tor_assert(mac_out_len >= DIGEST256_LEN);
|
||||||
|
|
||||||
|
/* Compute the size of the message which is basically the entire cell until
|
||||||
|
* the MAC field of course. */
|
||||||
|
mac_msg_len = encoded_cell_len + (encrypted_len - DIGEST256_LEN);
|
||||||
|
tor_assert(mac_msg_len <= sizeof(mac_msg));
|
||||||
|
|
||||||
|
/* First, put the encoded cell in the msg. */
|
||||||
|
memcpy(mac_msg, encoded_cell, encoded_cell_len);
|
||||||
|
offset += encoded_cell_len;
|
||||||
|
/* Second, put the CLIENT_PK + ENCRYPTED_DATA but ommit the MAC field (which
|
||||||
|
* is junk at this point). */
|
||||||
|
memcpy(mac_msg + offset, encrypted, (encrypted_len - DIGEST256_LEN));
|
||||||
|
offset += (encrypted_len - DIGEST256_LEN);
|
||||||
|
tor_assert(offset == mac_msg_len);
|
||||||
|
|
||||||
|
crypto_mac_sha3_256(mac_out, mac_out_len,
|
||||||
|
mac_key, mac_key_len,
|
||||||
|
mac_msg, mac_msg_len);
|
||||||
|
memwipe(mac_msg, 0, sizeof(mac_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* From a set of keys, subcredential and the ENCRYPTED section of an
|
||||||
|
* INTRODUCE2 cell, return a newly allocated intro cell keys structure.
|
||||||
|
* Finally, the client public key is copied in client_pk. On error, return
|
||||||
|
* NULL. */
|
||||||
|
static hs_ntor_intro_cell_keys_t *
|
||||||
|
get_introduce2_key_material(const ed25519_public_key_t *auth_key,
|
||||||
|
const curve25519_keypair_t *enc_key,
|
||||||
|
const uint8_t *subcredential,
|
||||||
|
const uint8_t *encrypted_section,
|
||||||
|
curve25519_public_key_t *client_pk)
|
||||||
|
{
|
||||||
|
hs_ntor_intro_cell_keys_t *keys;
|
||||||
|
|
||||||
|
tor_assert(auth_key);
|
||||||
|
tor_assert(enc_key);
|
||||||
|
tor_assert(subcredential);
|
||||||
|
tor_assert(encrypted_section);
|
||||||
|
tor_assert(client_pk);
|
||||||
|
|
||||||
|
keys = tor_malloc_zero(sizeof(*keys));
|
||||||
|
|
||||||
|
/* First bytes of the ENCRYPTED section are the client public key. */
|
||||||
|
memcpy(client_pk->public_key, encrypted_section, CURVE25519_PUBKEY_LEN);
|
||||||
|
|
||||||
|
if (hs_ntor_service_get_introduce1_keys(auth_key, enc_key, client_pk,
|
||||||
|
subcredential, keys) < 0) {
|
||||||
|
/* Don't rely on the caller to wipe this on error. */
|
||||||
|
memwipe(client_pk, 0, sizeof(curve25519_public_key_t));
|
||||||
|
tor_free(keys);
|
||||||
|
keys = NULL;
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Using the given encryption key, decrypt the encrypted_section of length
|
||||||
|
* encrypted_section_len of an INTRODUCE2 cell and return a newly allocated
|
||||||
|
* buffer containing the decrypted data. On decryption failure, NULL is
|
||||||
|
* returned. */
|
||||||
|
static uint8_t *
|
||||||
|
decrypt_introduce2(const uint8_t *enc_key, const uint8_t *encrypted_section,
|
||||||
|
size_t encrypted_section_len)
|
||||||
|
{
|
||||||
|
uint8_t *decrypted = NULL;
|
||||||
|
crypto_cipher_t *cipher = NULL;
|
||||||
|
|
||||||
|
tor_assert(enc_key);
|
||||||
|
tor_assert(encrypted_section);
|
||||||
|
|
||||||
|
/* Decrypt ENCRYPTED section. */
|
||||||
|
cipher = crypto_cipher_new_with_bits((char *) enc_key,
|
||||||
|
CURVE25519_PUBKEY_LEN * 8);
|
||||||
|
tor_assert(cipher);
|
||||||
|
|
||||||
|
/* This is symmetric encryption so can't be bigger than the encrypted
|
||||||
|
* section length. */
|
||||||
|
decrypted = tor_malloc_zero(encrypted_section_len);
|
||||||
|
if (crypto_cipher_decrypt(cipher, (char *) decrypted,
|
||||||
|
(const char *) encrypted_section,
|
||||||
|
encrypted_section_len) < 0) {
|
||||||
|
tor_free(decrypted);
|
||||||
|
decrypted = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
crypto_cipher_free(cipher);
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a pointer to the decrypted data of the ENCRYPTED section of an
|
||||||
|
* INTRODUCE2 cell of length decrypted_len, parse and validate the cell
|
||||||
|
* content. Return a newly allocated cell structure or NULL on error. The
|
||||||
|
* circuit and service object are only used for logging purposes. */
|
||||||
|
static trn_cell_introduce_encrypted_t *
|
||||||
|
parse_introduce2_encrypted(const uint8_t *decrypted_data,
|
||||||
|
size_t decrypted_len, const origin_circuit_t *circ,
|
||||||
|
const hs_service_t *service)
|
||||||
|
{
|
||||||
|
trn_cell_introduce_encrypted_t *enc_cell = NULL;
|
||||||
|
|
||||||
|
tor_assert(decrypted_data);
|
||||||
|
tor_assert(circ);
|
||||||
|
tor_assert(service);
|
||||||
|
|
||||||
|
if (trn_cell_introduce_encrypted_parse(&enc_cell, decrypted_data,
|
||||||
|
decrypted_len) < 0) {
|
||||||
|
log_info(LD_REND, "Unable to parse the decrypted ENCRYPTED section of "
|
||||||
|
"the INTRODUCE2 cell on circuit %u for service %s",
|
||||||
|
TO_CIRCUIT(circ)->n_circ_id,
|
||||||
|
safe_str_client(service->onion_address));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trn_cell_introduce_encrypted_get_onion_key_type(enc_cell) !=
|
||||||
|
HS_CELL_ONION_KEY_TYPE_NTOR) {
|
||||||
|
log_info(LD_REND, "INTRODUCE2 onion key type is invalid. Got %u but "
|
||||||
|
"expected %u on circuit %u for service %s",
|
||||||
|
trn_cell_introduce_encrypted_get_onion_key_type(enc_cell),
|
||||||
|
HS_CELL_ONION_KEY_TYPE_NTOR, TO_CIRCUIT(circ)->n_circ_id,
|
||||||
|
safe_str_client(service->onion_address));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trn_cell_introduce_encrypted_getlen_onion_key(enc_cell) !=
|
||||||
|
CURVE25519_PUBKEY_LEN) {
|
||||||
|
log_info(LD_REND, "INTRODUCE2 onion key length is invalid. Got %ld but "
|
||||||
|
"expected %d on circuit %u for service %s",
|
||||||
|
trn_cell_introduce_encrypted_getlen_onion_key(enc_cell),
|
||||||
|
CURVE25519_PUBKEY_LEN, TO_CIRCUIT(circ)->n_circ_id,
|
||||||
|
safe_str_client(service->onion_address));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
/* XXX: Validate NSPEC field as well. */
|
||||||
|
|
||||||
|
return enc_cell;
|
||||||
|
err:
|
||||||
|
trn_cell_introduce_encrypted_free(enc_cell);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA
|
/* Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA
|
||||||
* encryption key. The encoded cell is put in cell_out that MUST at least be
|
* encryption key. The encoded cell is put in cell_out that MUST at least be
|
||||||
@ -183,3 +350,154 @@ hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parsse the INTRODUCE2 cell using data which contains everything we need to
|
||||||
|
* do so and contains the destination buffers of information we extract and
|
||||||
|
* compute from the cell. Return 0 on success else a negative value. The
|
||||||
|
* service and circ are only used for logging purposes. */
|
||||||
|
ssize_t
|
||||||
|
hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
|
||||||
|
const origin_circuit_t *circ,
|
||||||
|
const hs_service_t *service)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
uint8_t *decrypted = NULL;
|
||||||
|
size_t encrypted_section_len;
|
||||||
|
const uint8_t *encrypted_section;
|
||||||
|
curve25519_public_key_t client_pk;
|
||||||
|
trn_cell_introduce1_t *cell = NULL;
|
||||||
|
trn_cell_introduce_encrypted_t *enc_cell = NULL;
|
||||||
|
hs_ntor_intro_cell_keys_t *intro_keys = 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));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: Add/Test replaycache. */
|
||||||
|
|
||||||
|
log_info(LD_REND, "Received a decodable INTRODUCE2 cell on circuit %u "
|
||||||
|
"for service %s. Decoding encrypted section...",
|
||||||
|
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 must at least contain the CLIENT_PK and MAC which is
|
||||||
|
* defined in section 3.3.2 of the specification. */
|
||||||
|
if (encrypted_section_len < (CURVE25519_PUBKEY_LEN + DIGEST256_LEN)) {
|
||||||
|
log_info(LD_REND, "Invalid INTRODUCE2 encrypted section length "
|
||||||
|
"for service %s. Dropping cell.",
|
||||||
|
safe_str_client(service->onion_address));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build the key material out of the key material found in the cell. */
|
||||||
|
intro_keys = get_introduce2_key_material(data->auth_pk, data->enc_kp,
|
||||||
|
data->subcredential,
|
||||||
|
encrypted_section, &client_pk);
|
||||||
|
if (intro_keys == NULL) {
|
||||||
|
log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to "
|
||||||
|
"compute key material on circuit %u for service %s",
|
||||||
|
TO_CIRCUIT(circ)->n_circ_id,
|
||||||
|
safe_str_client(service->onion_address));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate MAC from the cell and our computed key material. The MAC field
|
||||||
|
* in the cell is at the end of the encrypted section. */
|
||||||
|
{
|
||||||
|
uint8_t mac[DIGEST256_LEN];
|
||||||
|
/* The MAC field is at the very end of the ENCRYPTED section. */
|
||||||
|
size_t mac_offset = encrypted_section_len - sizeof(mac);
|
||||||
|
/* Compute the MAC. Use the entire encoded payload with a length up to the
|
||||||
|
* ENCRYPTED section. */
|
||||||
|
compute_introduce_mac(data->payload,
|
||||||
|
data->payload_len - encrypted_section_len,
|
||||||
|
encrypted_section, encrypted_section_len,
|
||||||
|
intro_keys->mac_key, sizeof(intro_keys->mac_key),
|
||||||
|
mac, sizeof(mac));
|
||||||
|
if (tor_memcmp(mac, encrypted_section + mac_offset, sizeof(mac))) {
|
||||||
|
log_info(LD_REND, "Invalid MAC validation for INTRODUCE2 cell on "
|
||||||
|
"circuit %u for service %s",
|
||||||
|
TO_CIRCUIT(circ)->n_circ_id,
|
||||||
|
safe_str_client(service->onion_address));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* The ENCRYPTED_DATA section starts just after the CLIENT_PK. */
|
||||||
|
const uint8_t *encrypted_data =
|
||||||
|
encrypted_section + sizeof(data->client_pk);
|
||||||
|
/* It's symmetric encryption so it's correct to use the ENCRYPTED length
|
||||||
|
* for decryption. Computes the length of ENCRYPTED_DATA meaning removing
|
||||||
|
* the CLIENT_PK and MAC length. */
|
||||||
|
size_t encrypted_data_len =
|
||||||
|
encrypted_section_len - (sizeof(data->client_pk) + DIGEST256_LEN);
|
||||||
|
|
||||||
|
/* This decrypts the ENCRYPTED_DATA section of the cell. */
|
||||||
|
decrypted = decrypt_introduce2(intro_keys->enc_key,
|
||||||
|
encrypted_data, encrypted_data_len);
|
||||||
|
if (decrypted == NULL) {
|
||||||
|
log_info(LD_REND, "Unable to decrypt the ENCRYPTED section of an "
|
||||||
|
"INTRODUCE2 cell on circuit %u for service %s",
|
||||||
|
TO_CIRCUIT(circ)->n_circ_id,
|
||||||
|
safe_str_client(service->onion_address));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse this blob into an encrypted cell structure so we can then extract
|
||||||
|
* the data we need out of it. */
|
||||||
|
enc_cell = parse_introduce2_encrypted(decrypted, encrypted_data_len,
|
||||||
|
circ, service);
|
||||||
|
memwipe(decrypted, 0, encrypted_data_len);
|
||||||
|
if (enc_cell == NULL) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: Implement client authorization checks. */
|
||||||
|
|
||||||
|
/* Extract onion key and rendezvous cookie from the cell used for the
|
||||||
|
* rendezvous point circuit e2e encryption. */
|
||||||
|
memcpy(data->onion_pk.public_key,
|
||||||
|
trn_cell_introduce_encrypted_getconstarray_onion_key(enc_cell),
|
||||||
|
CURVE25519_PUBKEY_LEN);
|
||||||
|
memcpy(data->rendezvous_cookie,
|
||||||
|
trn_cell_introduce_encrypted_getconstarray_rend_cookie(enc_cell),
|
||||||
|
sizeof(data->rendezvous_cookie));
|
||||||
|
|
||||||
|
/* Extract rendezvous link specifiers. */
|
||||||
|
for (size_t idx = 0;
|
||||||
|
idx < trn_cell_introduce_encrypted_get_nspec(enc_cell); idx++) {
|
||||||
|
link_specifier_t *lspec =
|
||||||
|
trn_cell_introduce_encrypted_get_nspecs(enc_cell, idx);
|
||||||
|
smartlist_add(data->link_specifiers, hs_link_specifier_dup(lspec));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success. */
|
||||||
|
ret = 0;
|
||||||
|
log_info(LD_REND, "Valid INTRODUCE2 cell. Launching rendezvous circuit.");
|
||||||
|
|
||||||
|
done:
|
||||||
|
memwipe(&client_pk, 0, sizeof(client_pk));
|
||||||
|
if (intro_keys) {
|
||||||
|
memwipe(intro_keys, 0, sizeof(hs_ntor_intro_cell_keys_t));
|
||||||
|
tor_free(intro_keys);
|
||||||
|
}
|
||||||
|
tor_free(decrypted);
|
||||||
|
trn_cell_introduce1_free(cell);
|
||||||
|
trn_cell_introduce_encrypted_free(enc_cell);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -9,14 +9,53 @@
|
|||||||
#ifndef TOR_HS_CELL_H
|
#ifndef TOR_HS_CELL_H
|
||||||
#define TOR_HS_CELL_H
|
#define TOR_HS_CELL_H
|
||||||
|
|
||||||
|
#include "or.h"
|
||||||
#include "hs_service.h"
|
#include "hs_service.h"
|
||||||
|
|
||||||
|
/* Onion key type found in the INTRODUCE1 cell. */
|
||||||
|
typedef enum {
|
||||||
|
HS_CELL_ONION_KEY_TYPE_NTOR = 1,
|
||||||
|
} hs_cell_onion_key_type_t;
|
||||||
|
|
||||||
|
/* This data structure contains data that we need to parse an INTRODUCE2 cell
|
||||||
|
* which is used by the INTRODUCE2 cell parsing function. On a successful
|
||||||
|
* parsing, the onion_pk and rendezvous_cookie will be populated with the
|
||||||
|
* computed key material from the cell data. */
|
||||||
|
typedef struct hs_cell_introduce2_data_t {
|
||||||
|
/*** Immutable Section. ***/
|
||||||
|
|
||||||
|
/* Introduction point authentication public key. */
|
||||||
|
const ed25519_public_key_t *auth_pk;
|
||||||
|
/* Introduction point encryption keypair for the ntor handshake. */
|
||||||
|
const curve25519_keypair_t *enc_kp;
|
||||||
|
/* Subcredentials of the service. */
|
||||||
|
const uint8_t *subcredential;
|
||||||
|
/* Payload of the received encoded cell. */
|
||||||
|
const uint8_t *payload;
|
||||||
|
/* Size of the payload of the received encoded cell. */
|
||||||
|
size_t payload_len;
|
||||||
|
|
||||||
|
/*** Muttable Section. ***/
|
||||||
|
|
||||||
|
/* Onion public key computed using the INTRODUCE2 encrypted section. */
|
||||||
|
curve25519_public_key_t onion_pk;
|
||||||
|
/* Rendezvous cookie taken from the INTRODUCE2 encrypted section. */
|
||||||
|
uint8_t rendezvous_cookie[REND_COOKIE_LEN];
|
||||||
|
/* Client public key from the INTRODUCE2 encrypted section. */
|
||||||
|
curve25519_public_key_t client_pk;
|
||||||
|
/* Link specifiers of the rendezvous point. Contains link_specifier_t. */
|
||||||
|
smartlist_t *link_specifiers;
|
||||||
|
} hs_cell_introduce2_data_t;
|
||||||
|
|
||||||
ssize_t hs_cell_build_establish_intro(const char *circ_nonce,
|
ssize_t hs_cell_build_establish_intro(const char *circ_nonce,
|
||||||
const hs_service_intro_point_t *ip,
|
const hs_service_intro_point_t *ip,
|
||||||
uint8_t *cell_out);
|
uint8_t *cell_out);
|
||||||
|
|
||||||
ssize_t hs_cell_parse_intro_established(const uint8_t *payload,
|
ssize_t hs_cell_parse_intro_established(const uint8_t *payload,
|
||||||
size_t payload_len);
|
size_t payload_len);
|
||||||
|
ssize_t hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
|
||||||
|
const origin_circuit_t *circ,
|
||||||
|
const hs_service_t *service);
|
||||||
|
|
||||||
#endif /* TOR_HS_CELL_H */
|
#endif /* TOR_HS_CELL_H */
|
||||||
|
|
||||||
|
@ -312,6 +312,18 @@ send_establish_intro(const hs_service_t *service,
|
|||||||
/* Public API */
|
/* Public API */
|
||||||
/* ========== */
|
/* ========== */
|
||||||
|
|
||||||
|
int
|
||||||
|
hs_circ_launch_rendezvous_point(const hs_service_t *service,
|
||||||
|
const curve25519_public_key_t *onion_key,
|
||||||
|
const uint8_t *rendezvous_cookie)
|
||||||
|
{
|
||||||
|
tor_assert(service);
|
||||||
|
tor_assert(onion_key);
|
||||||
|
tor_assert(rendezvous_cookie);
|
||||||
|
/* XXX: Implement rendezvous launch support. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* For a given service and a service intro point, launch a circuit to the
|
/* For a given service and a service intro point, launch a circuit to the
|
||||||
* extend info ei. If the service is a single onion, a one-hop circuit will be
|
* extend info ei. If the service is a single onion, a one-hop circuit will be
|
||||||
* requested. Return 0 if the circuit was successfully launched and tagged
|
* requested. Return 0 if the circuit was successfully launched and tagged
|
||||||
@ -468,6 +480,60 @@ hs_circ_handle_intro_established(const hs_service_t *service,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle an INTRODUCE2 unparsed payload of payload_len for the given circuit
|
||||||
|
* and service. This cell is associated with the intro point object ip and the
|
||||||
|
* subcredential. Return 0 on success else a negative value. */
|
||||||
|
int
|
||||||
|
hs_circ_handle_introduce2(const hs_service_t *service,
|
||||||
|
const origin_circuit_t *circ,
|
||||||
|
hs_service_intro_point_t *ip,
|
||||||
|
const uint8_t *subcredential,
|
||||||
|
const uint8_t *payload, size_t payload_len)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
hs_cell_introduce2_data_t data;
|
||||||
|
|
||||||
|
tor_assert(service);
|
||||||
|
tor_assert(circ);
|
||||||
|
tor_assert(ip);
|
||||||
|
tor_assert(subcredential);
|
||||||
|
tor_assert(payload);
|
||||||
|
|
||||||
|
/* Populate the data structure with everything we need for the cell to be
|
||||||
|
* parsed, decrypted and key material computed correctly. */
|
||||||
|
data.auth_pk = &ip->auth_key_kp.pubkey;
|
||||||
|
data.enc_kp = &ip->enc_key_kp;
|
||||||
|
data.subcredential = subcredential;
|
||||||
|
data.payload = payload;
|
||||||
|
data.payload_len = payload_len;
|
||||||
|
data.link_specifiers = smartlist_new();
|
||||||
|
|
||||||
|
if (hs_cell_parse_introduce2(&data, circ, service) < 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point, we just confirmed that the full INTRODUCE2 cell is valid
|
||||||
|
* so increment our counter that we've seen one on this intro point. */
|
||||||
|
ip->introduce2_count++;
|
||||||
|
|
||||||
|
/* Launch rendezvous circuit with the onion key and rend cookie. */
|
||||||
|
ret = hs_circ_launch_rendezvous_point(service, &data.onion_pk,
|
||||||
|
data.rendezvous_cookie);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success. */
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
SMARTLIST_FOREACH(data.link_specifiers, link_specifier_t *, lspec,
|
||||||
|
link_specifier_free(lspec));
|
||||||
|
smartlist_free(data.link_specifiers);
|
||||||
|
memwipe(&data, 0, sizeof(data));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key
|
/* 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
|
* 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
|
* serve as a rendezvous end-to-end circuit between the client and the
|
||||||
|
@ -23,6 +23,9 @@ int hs_circ_service_intro_has_opened(hs_service_t *service,
|
|||||||
int hs_circ_launch_intro_point(hs_service_t *service,
|
int hs_circ_launch_intro_point(hs_service_t *service,
|
||||||
const hs_service_intro_point_t *ip,
|
const hs_service_intro_point_t *ip,
|
||||||
extend_info_t *ei, time_t now);
|
extend_info_t *ei, time_t now);
|
||||||
|
int hs_circ_launch_rendezvous_point(const hs_service_t *service,
|
||||||
|
const curve25519_public_key_t *onion_key,
|
||||||
|
const uint8_t *rendezvous_cookie);
|
||||||
|
|
||||||
/* Cell API. */
|
/* Cell API. */
|
||||||
void hs_circ_send_establish_intro(const hs_service_t *service,
|
void hs_circ_send_establish_intro(const hs_service_t *service,
|
||||||
@ -33,6 +36,11 @@ int hs_circ_handle_intro_established(const hs_service_t *service,
|
|||||||
origin_circuit_t *circ,
|
origin_circuit_t *circ,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload,
|
||||||
size_t payload_len);
|
size_t payload_len);
|
||||||
|
int hs_circ_handle_introduce2(const hs_service_t *service,
|
||||||
|
const origin_circuit_t *circ,
|
||||||
|
hs_service_intro_point_t *ip,
|
||||||
|
const uint8_t *subcredential,
|
||||||
|
const uint8_t *payload, size_t payload_len);
|
||||||
|
|
||||||
/* e2e circuit API. */
|
/* e2e circuit API. */
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@
|
|||||||
|
|
||||||
/* Trunnel */
|
/* Trunnel */
|
||||||
#include "ed25519_cert.h"
|
#include "ed25519_cert.h"
|
||||||
#include "hs/cell_establish_intro.h"
|
|
||||||
#include "hs/cell_common.h"
|
#include "hs/cell_common.h"
|
||||||
|
#include "hs/cell_establish_intro.h"
|
||||||
|
|
||||||
/* Helper macro. Iterate over every service in the global map. The var is the
|
/* Helper macro. Iterate over every service in the global map. The var is the
|
||||||
* name of the service pointer. */
|
* name of the service pointer. */
|
||||||
@ -1845,10 +1845,85 @@ service_handle_intro_established(origin_circuit_t *circ,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle an INTRODUCE2 cell arriving on the given introduction circuit.
|
||||||
|
* Return 0 on success else a negative value. */
|
||||||
|
static int
|
||||||
|
service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload,
|
||||||
|
size_t payload_len)
|
||||||
|
{
|
||||||
|
hs_service_t *service = NULL;
|
||||||
|
hs_service_intro_point_t *ip = NULL;
|
||||||
|
hs_service_descriptor_t *desc = NULL;
|
||||||
|
|
||||||
|
tor_assert(circ);
|
||||||
|
tor_assert(payload);
|
||||||
|
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO);
|
||||||
|
|
||||||
|
/* We'll need every object associated with this circuit. */
|
||||||
|
get_objects_from_ident(circ->hs_ident, &service, &ip, &desc);
|
||||||
|
|
||||||
|
/* Get service object from the circuit identifier. */
|
||||||
|
if (service == NULL) {
|
||||||
|
log_warn(LD_BUG, "Unknown service identity key %s when handling "
|
||||||
|
"an INTRODUCE2 cell on circuit %u",
|
||||||
|
safe_str_client(ed25519_fmt(&circ->hs_ident->identity_pk)),
|
||||||
|
TO_CIRCUIT(circ)->n_circ_id);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (ip == NULL) {
|
||||||
|
/* We don't recognize the key. */
|
||||||
|
log_warn(LD_BUG, "Unknown introduction auth key when handling "
|
||||||
|
"an INTRODUCE2 cell on circuit %u for service %s",
|
||||||
|
TO_CIRCUIT(circ)->n_circ_id,
|
||||||
|
safe_str_client(service->onion_address));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
/* If we have an IP object, we MUST have a descriptor object. */
|
||||||
|
tor_assert(desc);
|
||||||
|
|
||||||
|
/* XXX: Handle legacy IP connection. */
|
||||||
|
|
||||||
|
if (hs_circ_handle_introduce2(service, circ, ip, desc->desc->subcredential,
|
||||||
|
payload, payload_len) < 0) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* ========== */
|
/* ========== */
|
||||||
/* Public API */
|
/* Public API */
|
||||||
/* ========== */
|
/* ========== */
|
||||||
|
|
||||||
|
/* Called when we get an INTRODUCE2 cell on the circ. Respond to the cell and
|
||||||
|
* launch a circuit to the rendezvous point. */
|
||||||
|
int
|
||||||
|
hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload,
|
||||||
|
size_t payload_len)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
tor_assert(circ);
|
||||||
|
tor_assert(payload);
|
||||||
|
|
||||||
|
/* Do some initial validation and logging before we parse the cell */
|
||||||
|
if (TO_CIRCUIT(circ)->purpose != CIRCUIT_PURPOSE_S_INTRO) {
|
||||||
|
log_warn(LD_PROTOCOL, "Received an INTRODUCE2 cell on a "
|
||||||
|
"non introduction circuit of purpose %d",
|
||||||
|
TO_CIRCUIT(circ)->purpose);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = (circ->hs_ident) ? service_handle_introduce2(circ, payload,
|
||||||
|
payload_len) :
|
||||||
|
rend_service_receive_introduction(circ, payload,
|
||||||
|
payload_len);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an
|
/* Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an
|
||||||
* established introduction point. Return 0 on success else a negative value
|
* established introduction point. Return 0 on success else a negative value
|
||||||
* and the circuit is closed. */
|
* and the circuit is closed. */
|
||||||
|
@ -235,6 +235,9 @@ void hs_service_circuit_has_opened(origin_circuit_t *circ);
|
|||||||
int hs_service_receive_intro_established(origin_circuit_t *circ,
|
int hs_service_receive_intro_established(origin_circuit_t *circ,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload,
|
||||||
size_t payload_len);
|
size_t payload_len);
|
||||||
|
int hs_service_receive_introduce2(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
|
/* 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
|
* hs_service.o ends up with no symbols in libor.a which makes clang throw a
|
||||||
|
@ -777,7 +777,7 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
|
|||||||
break;
|
break;
|
||||||
case RELAY_COMMAND_INTRODUCE2:
|
case RELAY_COMMAND_INTRODUCE2:
|
||||||
if (origin_circ)
|
if (origin_circ)
|
||||||
r = rend_service_receive_introduction(origin_circ,payload,length);
|
r = hs_service_receive_introduce2(origin_circ,payload,length);
|
||||||
break;
|
break;
|
||||||
case RELAY_COMMAND_INTRODUCE_ACK:
|
case RELAY_COMMAND_INTRODUCE_ACK:
|
||||||
if (origin_circ)
|
if (origin_circ)
|
||||||
|
Loading…
Reference in New Issue
Block a user