mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-25 07:07:52 +01:00
hs-v3: Encode DoS ESTABLISH_INTRO cell extension
This commit makes tor add the DoS cell extension to the ESTABLISH_INTRO cell if the defense is enabled on the service side with a torrc option. Furthermore, the cell extension is only added if the introduction point supports it. The protover version HSIntro=5 is looked for. Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
7faf10495f
commit
d692c5fd03
9 changed files with 138 additions and 9 deletions
|
@ -473,10 +473,110 @@ introduce1_set_legacy_id(trn_cell_introduce1_t *cell,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Build and add to the given DoS cell extension the given parameter type and
|
||||||
|
* value. */
|
||||||
|
static void
|
||||||
|
build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext,
|
||||||
|
uint8_t param_type, uint64_t param_value)
|
||||||
|
{
|
||||||
|
trn_cell_extension_dos_param_t *dos_param =
|
||||||
|
trn_cell_extension_dos_param_new();
|
||||||
|
|
||||||
|
/* Extra safety. We should never send an unknown parameter type. */
|
||||||
|
tor_assert(param_type == TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC ||
|
||||||
|
param_type == TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
|
||||||
|
|
||||||
|
trn_cell_extension_dos_param_set_type(dos_param, param_type);
|
||||||
|
trn_cell_extension_dos_param_set_value(dos_param, param_value);
|
||||||
|
trn_cell_extension_dos_add_params(dos_ext, dos_param);
|
||||||
|
|
||||||
|
/* Not freeing the trunnel object because it is now owned by dos_ext. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build the DoS defense cell extension and put it in the given extensions
|
||||||
|
* object. This can't fail. */
|
||||||
|
static void
|
||||||
|
build_establish_intro_dos_extension(const hs_service_config_t *service_config,
|
||||||
|
trn_cell_extension_t *extensions)
|
||||||
|
{
|
||||||
|
ssize_t ret, dos_ext_encoded_len;
|
||||||
|
uint8_t *field_array;
|
||||||
|
trn_cell_extension_field_t *field;
|
||||||
|
trn_cell_extension_dos_t *dos_ext;
|
||||||
|
|
||||||
|
tor_assert(service_config);
|
||||||
|
tor_assert(extensions);
|
||||||
|
|
||||||
|
/* We are creating a cell extension field of the type DoS. */
|
||||||
|
field = trn_cell_extension_field_new();
|
||||||
|
trn_cell_extension_field_set_field_type(field,
|
||||||
|
TRUNNEL_CELL_EXTENSION_TYPE_DOS);
|
||||||
|
|
||||||
|
/* Build DoS extension field. We will put in two parameters. */
|
||||||
|
dos_ext = trn_cell_extension_dos_new();
|
||||||
|
trn_cell_extension_dos_set_n_params(dos_ext, 2);
|
||||||
|
|
||||||
|
/* Build DoS parameter INTRO2 rate per second. */
|
||||||
|
build_establish_intro_dos_param(dos_ext,
|
||||||
|
TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC,
|
||||||
|
service_config->intro_dos_rate_per_sec);
|
||||||
|
/* Build DoS parameter INTRO2 burst per second. */
|
||||||
|
build_establish_intro_dos_param(dos_ext,
|
||||||
|
TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC,
|
||||||
|
service_config->intro_dos_burst_per_sec);
|
||||||
|
|
||||||
|
/* Set the field with the encoded DoS extension. */
|
||||||
|
dos_ext_encoded_len = trn_cell_extension_dos_encoded_len(dos_ext);
|
||||||
|
/* Set length field and the field array size length. */
|
||||||
|
trn_cell_extension_field_set_field_len(field, dos_ext_encoded_len);
|
||||||
|
trn_cell_extension_field_setlen_field(field, dos_ext_encoded_len);
|
||||||
|
/* Encode the DoS extension into the cell extension field. */
|
||||||
|
field_array = trn_cell_extension_field_getarray_field(field);
|
||||||
|
ret = trn_cell_extension_dos_encode(field_array,
|
||||||
|
trn_cell_extension_field_getlen_field(field), dos_ext);
|
||||||
|
tor_assert(ret == dos_ext_encoded_len);
|
||||||
|
|
||||||
|
/* Finally, encode field into the cell extension. */
|
||||||
|
trn_cell_extension_add_fields(extensions, field);
|
||||||
|
|
||||||
|
/* We've just add an extension field to the cell extensions so increment the
|
||||||
|
* total number. */
|
||||||
|
trn_cell_extension_set_num(extensions,
|
||||||
|
trn_cell_extension_get_num(extensions) + 1);
|
||||||
|
|
||||||
|
/* Cleanup. DoS extension has been encoded at this point. */
|
||||||
|
trn_cell_extension_dos_free(dos_ext);
|
||||||
|
}
|
||||||
|
|
||||||
/* ========== */
|
/* ========== */
|
||||||
/* Public API */
|
/* Public API */
|
||||||
/* ========== */
|
/* ========== */
|
||||||
|
|
||||||
|
/* Allocate and build all the ESTABLISH_INTRO cell extension. The given
|
||||||
|
* extensions pointer is always set to a valid cell extension object. */
|
||||||
|
static trn_cell_extension_t *
|
||||||
|
build_establish_intro_extensions(const hs_service_config_t *service_config,
|
||||||
|
const hs_service_intro_point_t *ip)
|
||||||
|
{
|
||||||
|
trn_cell_extension_t *extensions;
|
||||||
|
|
||||||
|
tor_assert(service_config);
|
||||||
|
tor_assert(ip);
|
||||||
|
|
||||||
|
extensions = trn_cell_extension_new();
|
||||||
|
trn_cell_extension_set_num(extensions, 0);
|
||||||
|
|
||||||
|
/* If the defense has been enabled service side (by the operator with a
|
||||||
|
* torrc option) and the intro point does support it. */
|
||||||
|
if (service_config->has_dos_defense_enabled &&
|
||||||
|
ip->support_intro2_dos_defense) {
|
||||||
|
/* This function takes care to increment the number of extensions. */
|
||||||
|
build_establish_intro_dos_extension(service_config, extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
/* Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
|
/* Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
|
||||||
* object. The encoded cell is put in cell_out that MUST at least be of the
|
* object. The encoded cell is put in cell_out that MUST at least be of the
|
||||||
* size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
|
* size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
|
||||||
|
@ -484,15 +584,17 @@ introduce1_set_legacy_id(trn_cell_introduce1_t *cell,
|
||||||
* legacy cell creation. */
|
* legacy cell creation. */
|
||||||
ssize_t
|
ssize_t
|
||||||
hs_cell_build_establish_intro(const char *circ_nonce,
|
hs_cell_build_establish_intro(const char *circ_nonce,
|
||||||
|
const hs_service_config_t *service_config,
|
||||||
const hs_service_intro_point_t *ip,
|
const hs_service_intro_point_t *ip,
|
||||||
uint8_t *cell_out)
|
uint8_t *cell_out)
|
||||||
{
|
{
|
||||||
ssize_t cell_len = -1;
|
ssize_t cell_len = -1;
|
||||||
uint16_t sig_len = ED25519_SIG_LEN;
|
uint16_t sig_len = ED25519_SIG_LEN;
|
||||||
trn_cell_extension_t *ext;
|
|
||||||
trn_cell_establish_intro_t *cell = NULL;
|
trn_cell_establish_intro_t *cell = NULL;
|
||||||
|
trn_cell_extension_t *extensions;
|
||||||
|
|
||||||
tor_assert(circ_nonce);
|
tor_assert(circ_nonce);
|
||||||
|
tor_assert(service_config);
|
||||||
tor_assert(ip);
|
tor_assert(ip);
|
||||||
|
|
||||||
/* Quickly handle the legacy IP. */
|
/* Quickly handle the legacy IP. */
|
||||||
|
@ -505,11 +607,12 @@ hs_cell_build_establish_intro(const char *circ_nonce,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Build the extensions, if any. */
|
||||||
|
extensions = build_establish_intro_extensions(service_config, ip);
|
||||||
|
|
||||||
/* Set extension data. None used here. */
|
/* Set extension data. None used here. */
|
||||||
ext = trn_cell_extension_new();
|
|
||||||
trn_cell_extension_set_num(ext, 0);
|
|
||||||
cell = trn_cell_establish_intro_new();
|
cell = trn_cell_establish_intro_new();
|
||||||
trn_cell_establish_intro_set_extensions(cell, ext);
|
trn_cell_establish_intro_set_extensions(cell, extensions);
|
||||||
/* Set signature size. Array is then allocated in the cell. We need to do
|
/* Set signature size. Array is then allocated in the cell. We need to do
|
||||||
* this early so we can use trunnel API to get the signature length. */
|
* this early so we can use trunnel API to get the signature length. */
|
||||||
trn_cell_establish_intro_set_sig_len(cell, sig_len);
|
trn_cell_establish_intro_set_sig_len(cell, sig_len);
|
||||||
|
|
|
@ -79,6 +79,7 @@ typedef struct hs_cell_introduce2_data_t {
|
||||||
|
|
||||||
/* Build cell API. */
|
/* Build cell API. */
|
||||||
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_config_t *config,
|
||||||
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_build_rendezvous1(const uint8_t *rendezvous_cookie,
|
ssize_t hs_cell_build_rendezvous1(const uint8_t *rendezvous_cookie,
|
||||||
|
|
|
@ -319,7 +319,7 @@ send_establish_intro(const hs_service_t *service,
|
||||||
|
|
||||||
/* Encode establish intro cell. */
|
/* Encode establish intro cell. */
|
||||||
cell_len = hs_cell_build_establish_intro(circ->cpath->prev->rend_circ_nonce,
|
cell_len = hs_cell_build_establish_intro(circ->cpath->prev->rend_circ_nonce,
|
||||||
ip, payload);
|
&service->config, ip, payload);
|
||||||
if (cell_len < 0) {
|
if (cell_len < 0) {
|
||||||
log_warn(LD_REND, "Unable to encode ESTABLISH_INTRO cell for service %s "
|
log_warn(LD_REND, "Unable to encode ESTABLISH_INTRO cell for service %s "
|
||||||
"on circuit %u. Closing circuit.",
|
"on circuit %u. Closing circuit.",
|
||||||
|
|
|
@ -492,6 +492,10 @@ service_intro_point_new(const node_t *node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Flag if this intro point supports the INTRO2 dos defenses. */
|
||||||
|
ip->support_intro2_dos_defense =
|
||||||
|
node_supports_establish_intro_dos_extension(node);
|
||||||
|
|
||||||
/* Finally, copy onion key from the node. */
|
/* Finally, copy onion key from the node. */
|
||||||
memcpy(&ip->onion_key, node_get_curve25519_onion_key(node),
|
memcpy(&ip->onion_key, node_get_curve25519_onion_key(node),
|
||||||
sizeof(ip->onion_key));
|
sizeof(ip->onion_key));
|
||||||
|
|
|
@ -76,6 +76,10 @@ typedef struct hs_service_intro_point_t {
|
||||||
* circuit associated with this intro point has received. This is used to
|
* circuit associated with this intro point has received. This is used to
|
||||||
* prevent replay attacks. */
|
* prevent replay attacks. */
|
||||||
replaycache_t *replay_cache;
|
replaycache_t *replay_cache;
|
||||||
|
|
||||||
|
/* Support the INTRO2 DoS defense. If set, the DoS extension described by
|
||||||
|
* proposal 305 is sent. */
|
||||||
|
unsigned int support_intro2_dos_defense : 1;
|
||||||
} hs_service_intro_point_t;
|
} hs_service_intro_point_t;
|
||||||
|
|
||||||
/* Object handling introduction points of a service. */
|
/* Object handling introduction points of a service. */
|
||||||
|
|
|
@ -38,11 +38,13 @@ test_gen_establish_intro_cell(void *arg)
|
||||||
/* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
|
/* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
|
||||||
attempt to parse it. */
|
attempt to parse it. */
|
||||||
{
|
{
|
||||||
|
hs_service_config_t config;
|
||||||
|
memset(&config, 0, sizeof(config));
|
||||||
/* We only need the auth key pair here. */
|
/* We only need the auth key pair here. */
|
||||||
hs_service_intro_point_t *ip = service_intro_point_new(NULL);
|
hs_service_intro_point_t *ip = service_intro_point_new(NULL);
|
||||||
/* Auth key pair is generated in the constructor so we are all set for
|
/* Auth key pair is generated in the constructor so we are all set for
|
||||||
* using this IP object. */
|
* using this IP object. */
|
||||||
ret = hs_cell_build_establish_intro(circ_nonce, ip, buf);
|
ret = hs_cell_build_establish_intro(circ_nonce, &config, ip, buf);
|
||||||
service_intro_point_free(ip);
|
service_intro_point_free(ip);
|
||||||
tt_u64_op(ret, OP_GT, 0);
|
tt_u64_op(ret, OP_GT, 0);
|
||||||
}
|
}
|
||||||
|
@ -97,6 +99,9 @@ test_gen_establish_intro_cell_bad(void *arg)
|
||||||
trn_cell_establish_intro_t *cell = NULL;
|
trn_cell_establish_intro_t *cell = NULL;
|
||||||
char circ_nonce[DIGEST_LEN] = {0};
|
char circ_nonce[DIGEST_LEN] = {0};
|
||||||
hs_service_intro_point_t *ip = NULL;
|
hs_service_intro_point_t *ip = NULL;
|
||||||
|
hs_service_config_t config;
|
||||||
|
|
||||||
|
memset(&config, 0, sizeof(config));
|
||||||
|
|
||||||
MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed);
|
MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed);
|
||||||
|
|
||||||
|
@ -108,7 +113,7 @@ test_gen_establish_intro_cell_bad(void *arg)
|
||||||
cell = trn_cell_establish_intro_new();
|
cell = trn_cell_establish_intro_new();
|
||||||
tt_assert(cell);
|
tt_assert(cell);
|
||||||
ip = service_intro_point_new(NULL);
|
ip = service_intro_point_new(NULL);
|
||||||
cell_len = hs_cell_build_establish_intro(circ_nonce, ip, NULL);
|
cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, NULL);
|
||||||
service_intro_point_free(ip);
|
service_intro_point_free(ip);
|
||||||
expect_log_msg_containing("Unable to make signature for "
|
expect_log_msg_containing("Unable to make signature for "
|
||||||
"ESTABLISH_INTRO cell.");
|
"ESTABLISH_INTRO cell.");
|
||||||
|
|
|
@ -45,6 +45,9 @@ new_establish_intro_cell(const char *circ_nonce,
|
||||||
uint8_t buf[RELAY_PAYLOAD_SIZE] = {0};
|
uint8_t buf[RELAY_PAYLOAD_SIZE] = {0};
|
||||||
trn_cell_establish_intro_t *cell = NULL;
|
trn_cell_establish_intro_t *cell = NULL;
|
||||||
hs_service_intro_point_t *ip = NULL;
|
hs_service_intro_point_t *ip = NULL;
|
||||||
|
hs_service_config_t config;
|
||||||
|
|
||||||
|
memset(&config, 0, sizeof(config));
|
||||||
|
|
||||||
/* Ensure that *cell_out is NULL such that we can use to check if we need to
|
/* Ensure that *cell_out is NULL such that we can use to check if we need to
|
||||||
* free `cell` in case of an error. */
|
* free `cell` in case of an error. */
|
||||||
|
@ -54,7 +57,7 @@ new_establish_intro_cell(const char *circ_nonce,
|
||||||
* using this IP object. */
|
* using this IP object. */
|
||||||
ip = service_intro_point_new(NULL);
|
ip = service_intro_point_new(NULL);
|
||||||
tt_assert(ip);
|
tt_assert(ip);
|
||||||
cell_len = hs_cell_build_establish_intro(circ_nonce, ip, buf);
|
cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, buf);
|
||||||
tt_i64_op(cell_len, OP_GT, 0);
|
tt_i64_op(cell_len, OP_GT, 0);
|
||||||
|
|
||||||
cell_len = trn_cell_establish_intro_parse(&cell, buf, sizeof(buf));
|
cell_len = trn_cell_establish_intro_parse(&cell, buf, sizeof(buf));
|
||||||
|
@ -75,12 +78,15 @@ new_establish_intro_encoded_cell(const char *circ_nonce, uint8_t *cell_out)
|
||||||
{
|
{
|
||||||
ssize_t cell_len = 0;
|
ssize_t cell_len = 0;
|
||||||
hs_service_intro_point_t *ip = NULL;
|
hs_service_intro_point_t *ip = NULL;
|
||||||
|
hs_service_config_t config;
|
||||||
|
|
||||||
|
memset(&config, 0, sizeof(config));
|
||||||
|
|
||||||
/* Auth key pair is generated in the constructor so we are all set for
|
/* Auth key pair is generated in the constructor so we are all set for
|
||||||
* using this IP object. */
|
* using this IP object. */
|
||||||
ip = service_intro_point_new(NULL);
|
ip = service_intro_point_new(NULL);
|
||||||
tt_assert(ip);
|
tt_assert(ip);
|
||||||
cell_len = hs_cell_build_establish_intro(circ_nonce, ip, cell_out);
|
cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell_out);
|
||||||
tt_i64_op(cell_len, OP_GT, 0);
|
tt_i64_op(cell_len, OP_GT, 0);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
struct trn_cell_extension_st;
|
struct trn_cell_extension_st;
|
||||||
#define TRUNNEL_SHA3_256_LEN 32
|
#define TRUNNEL_SHA3_256_LEN 32
|
||||||
#define TRUNNEL_CELL_EXTENSION_TYPE_DOS 1
|
#define TRUNNEL_CELL_EXTENSION_TYPE_DOS 1
|
||||||
|
#define TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC 1
|
||||||
|
#define TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC 2
|
||||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_EXTENSION_DOS_PARAM)
|
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_EXTENSION_DOS_PARAM)
|
||||||
struct trn_cell_extension_dos_param_st {
|
struct trn_cell_extension_dos_param_st {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
|
|
@ -46,6 +46,10 @@ struct trn_cell_intro_established {
|
||||||
|
|
||||||
const TRUNNEL_CELL_EXTENSION_TYPE_DOS = 0x01;
|
const TRUNNEL_CELL_EXTENSION_TYPE_DOS = 0x01;
|
||||||
|
|
||||||
|
/* DoS Parameter types. */
|
||||||
|
const TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC = 0x01;
|
||||||
|
const TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC = 0x02;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DoS Parameters Extension. See proposal 305 for more details.
|
* DoS Parameters Extension. See proposal 305 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Reference in a new issue