9#define HS_INTROPOINT_PRIVATE
25#include "trunnel/ed25519_cert.h"
26#include "trunnel/extension.h"
27#include "trunnel/hs/cell_establish_intro.h"
28#include "trunnel/hs/cell_introduce1.h"
37#include "core/or/or_circuit_st.h"
44 unsigned int cell_type,
const void *cell)
47 const uint8_t *key_array;
53 case RELAY_COMMAND_ESTABLISH_INTRO:
55 const trn_cell_establish_intro_t *c_cell = cell;
56 key_array = trn_cell_establish_intro_getconstarray_auth_key(c_cell);
57 auth_key_len = trn_cell_establish_intro_getlen_auth_key(c_cell);
60 case RELAY_COMMAND_INTRODUCE1:
62 const trn_cell_introduce1_t *c_cell = cell;
63 key_array = trn_cell_introduce1_getconstarray_auth_key(cell);
64 auth_key_len = trn_cell_introduce1_getlen_auth_key(c_cell);
70 tor_assert_unreached();
73 tor_assert(auth_key_len ==
sizeof(auth_key_out->pubkey));
74 memcpy(auth_key_out->pubkey, key_array, auth_key_len);
81 const uint8_t *circuit_key_material,
82 size_t circuit_key_material_len)
87 if (BUG(cell->auth_key_type != TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519)) {
97 "ESTABLISH_INTRO auth key length is invalid");
101 const uint8_t *msg = cell->start_cell;
106 const uint8_t *sig_array =
107 trn_cell_establish_intro_getconstarray_sig(cell);
112 if (trn_cell_establish_intro_getlen_sig(cell) !=
sizeof(sig_struct.sig) ||
113 trn_cell_establish_intro_get_sig_len(cell) !=
sizeof(sig_struct.sig)) {
115 "ESTABLISH_INTRO sig len is invalid");
119 memcpy(sig_struct.sig, sig_array, cell->sig_len);
124 const size_t sig_msg_len = cell->end_sig_fields - msg;
131 "ESTABLISH_INTRO signature not as expected");
138 const size_t auth_msg_len = cell->end_mac_fields - msg;
141 circuit_key_material, circuit_key_material_len,
143 if (
tor_memneq(mac, cell->handshake_mac,
sizeof(mac))) {
145 "ESTABLISH_INTRO handshake_auth not as expected");
158 uint8_t *encoded_cell = NULL;
159 ssize_t encoded_len, result_len;
160 trn_cell_intro_established_t *cell;
161 trn_extension_t *ext;
166 cell = trn_cell_intro_established_new();
167 ext = trn_extension_new();
168 trn_extension_set_num(ext, 0);
169 trn_cell_intro_established_set_extensions(cell, ext);
171 encoded_len = trn_cell_intro_established_encoded_len(cell);
173 encoded_cell = tor_malloc_zero(encoded_len);
174 result_len = trn_cell_intro_established_encode(encoded_cell, encoded_len,
178 ret = relay_send_command_from_edge(0,
TO_CIRCUIT(circ),
179 RELAY_COMMAND_INTRO_ESTABLISHED,
180 (
char *) encoded_cell, encoded_len,
183 trn_cell_intro_established_free(cell);
193 uint64_t intro2_burst_per_sec)
199#if HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN > 0
200 if (intro2_rate_per_sec < HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN) {
202 "Intro point DoS defenses rate per second is "
203 "too small. Received value: %" PRIu64, intro2_rate_per_sec);
209 if (intro2_rate_per_sec > HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX) {
211 "Intro point DoS defenses rate per second is "
212 "too big. Received value: %" PRIu64, intro2_rate_per_sec);
217#if HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN > 0
218 if (intro2_burst_per_sec < HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN) {
220 "Intro point DoS defenses burst per second is "
221 "too small. Received value: %" PRIu64, intro2_burst_per_sec);
227 if (intro2_burst_per_sec > HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX) {
229 "Intro point DoS defenses burst per second is "
230 "too big. Received value: %" PRIu64, intro2_burst_per_sec);
236 if (intro2_burst_per_sec < intro2_rate_per_sec) {
237 log_info(
LD_REND,
"Intro point DoS defenses burst is smaller than rate. "
238 "Rate: %" PRIu64
" vs Burst: %" PRIu64,
239 intro2_rate_per_sec, intro2_burst_per_sec);
255 const trn_extension_field_t *field,
259 uint64_t intro2_rate_per_sec = 0, intro2_burst_per_sec = 0;
260 trn_cell_extension_dos_t *dos = NULL;
265 ret = trn_cell_extension_dos_parse(&dos,
266 trn_extension_field_getconstarray_field(field),
267 trn_extension_field_getlen_field(field));
272 for (
size_t i = 0; i < trn_cell_extension_dos_get_n_params(dos); i++) {
273 const trn_cell_extension_dos_param_t *param =
274 trn_cell_extension_dos_getconst_params(dos, i);
275 if (BUG(param == NULL)) {
279 switch (trn_cell_extension_dos_param_get_type(param)) {
280 case TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC:
281 intro2_rate_per_sec = trn_cell_extension_dos_param_get_value(param);
283 case TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC:
284 intro2_burst_per_sec = trn_cell_extension_dos_param_get_value(param);
298 if (intro2_rate_per_sec == 0 || intro2_burst_per_sec == 0) {
299 log_info(
LD_REND,
"Intro point DoS defenses parameter set to 0. "
300 "Disabling INTRO2 DoS defenses on circuit id %u",
308 intro2_burst_per_sec)) {
310 log_info(
LD_REND,
"Disabling INTRO2 DoS defenses on circuit id %u",
320 (uint32_t) intro2_rate_per_sec,
321 (uint32_t) intro2_burst_per_sec,
322 (uint32_t) monotime_coarse_absolute_sec());
323 log_info(
LD_REND,
"Intro point DoS defenses enabled. Rate is %" PRIu64
324 " and Burst is %" PRIu64,
325 intro2_rate_per_sec, intro2_burst_per_sec);
328 trn_cell_extension_dos_free(dos);
335 const trn_cell_establish_intro_t *parsed_cell,
338 const trn_extension_t *extensions;
343 extensions = trn_cell_establish_intro_getconst_extensions(parsed_cell);
344 if (extensions == NULL) {
349 for (
size_t idx = 0; idx < trn_extension_get_num(extensions); idx++) {
350 const trn_extension_field_t *field =
351 trn_extension_getconst_fields(extensions, idx);
352 if (BUG(field == NULL)) {
357 switch (trn_extension_field_get_field_type(field)) {
358 case TRUNNEL_CELL_EXTENSION_TYPE_DOS:
377 const trn_cell_establish_intro_t *parsed_cell)
394 log_warn(
LD_PROTOCOL,
"Couldn't send INTRO_ESTABLISHED cell.");
413 int cell_ok, retval = -1;
414 trn_cell_establish_intro_t *parsed_cell = NULL;
419 log_info(
LD_REND,
"Received an ESTABLISH_INTRO request on circuit %" PRIu32,
424 relay_increment_est_intro_action(EST_INTRO_UNSUITABLE_CIRCUIT);
429 ssize_t parsing_result = trn_cell_establish_intro_parse(&parsed_cell,
430 request, request_len);
431 if (parsing_result < 0) {
432 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
434 "Rejecting %s ESTABLISH_INTRO cell.",
435 parsing_result == -1 ?
"invalid" :
"truncated");
443 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
445 "Failed to verify ESTABLISH_INTRO cell.");
452 relay_increment_est_intro_action(EST_INTRO_CIRCUIT_DEAD);
456 relay_increment_est_intro_action(EST_INTRO_SUCCESS);
465 circuit_mark_for_close(
TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
469 trn_cell_establish_intro_free(parsed_cell);
476 const char *log_cell_type_str)
484 "Rejecting %s on non-OR circuit.", log_cell_type_str);
490 "Rejecting %s on non-edge circuit.", log_cell_type_str);
514 if (request_len == 0) {
515 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
522 const uint8_t first_byte = request[0];
523 switch (first_byte) {
524 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0:
525 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1:
528 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
530 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519:
533 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
535 "Unrecognized AUTH_KEY_TYPE %u.", first_byte);
540 circuit_mark_for_close(
TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
552 uint8_t *encoded_cell = NULL;
553 ssize_t encoded_len, result_len;
554 trn_cell_introduce_ack_t *cell;
555 trn_extension_t *ext;
561 cell = trn_cell_introduce_ack_new();
562 ret = trn_cell_introduce_ack_set_status(cell, status);
564 ext = trn_extension_new();
565 trn_extension_set_num(ext, 0);
566 trn_cell_introduce_ack_set_extensions(cell, ext);
572 encoded_len = trn_cell_introduce_ack_encoded_len(cell);
574 encoded_cell = tor_malloc_zero(encoded_len);
575 result_len = trn_cell_introduce_ack_encode(encoded_cell, encoded_len, cell);
578 ret = relay_send_command_from_edge(CONTROL_CELL_ID,
TO_CIRCUIT(circ),
579 RELAY_COMMAND_INTRODUCE_ACK,
580 (
char *) encoded_cell, encoded_len,
583 trn_cell_introduce_ack_free(cell);
593 size_t legacy_key_id_len;
594 const uint8_t *legacy_key_id;
600 legacy_key_id_len = trn_cell_introduce1_getlen_legacy_key_id(cell);
601 legacy_key_id = trn_cell_introduce1_getconstarray_legacy_key_id(cell);
608 if (trn_cell_introduce1_get_auth_key_type(cell) !=
609 TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519) {
611 "Rejecting invalid INTRODUCE1 cell auth key type. "
612 "Responding with NACK.");
618 "Rejecting invalid INTRODUCE1 cell auth key length. "
619 "Responding with NACK.");
622 if (trn_cell_introduce1_getlen_encrypted(cell) == 0) {
624 "Rejecting invalid INTRODUCE1 cell encrypted length. "
625 "Responding with NACK.");
645 trn_cell_introduce1_t *parsed_cell = NULL;
646 uint16_t status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
663 RELAY_COMMAND_INTRODUCE2)) {
664 relay_increment_intro1_action(INTRO1_MALFORMED);
666 "Rejecting over-long INTRODUCE1 cell. Responding with NACK.");
668 status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
675 ssize_t cell_size = trn_cell_introduce1_parse(&parsed_cell, request,
678 relay_increment_intro1_action(INTRO1_MALFORMED);
680 "Rejecting %s INTRODUCE1 cell. Responding with NACK.",
681 cell_size == -1 ?
"invalid" :
"truncated");
683 status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
689 relay_increment_intro1_action(INTRO1_MALFORMED);
691 status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
700 if (service_circ == NULL) {
701 relay_increment_intro1_action(INTRO1_UNKNOWN_SERVICE);
704 log_info(
LD_REND,
"No intro circuit found for INTRODUCE1 cell "
705 "with auth key %s from circuit %" PRIu32
". "
706 "Responding with NACK.",
707 safe_str(b64_key), client_circ->
p_circ_id);
709 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
717 relay_increment_intro1_action(INTRO1_RATE_LIMITED);
719 static ratelim_t rlimit = RATELIM_INIT(5 * 60);
721 log_info(
LD_PROTOCOL,
"Can't relay INTRODUCE1 v3 cell due to DoS "
722 "limitations. Sending NACK to client.");
725 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
731 if (relay_send_command_from_edge(CONTROL_CELL_ID,
TO_CIRCUIT(service_circ),
732 RELAY_COMMAND_INTRODUCE2,
733 (
char *) request, request_len, NULL)) {
734 relay_increment_intro1_action(INTRO1_CIRCUIT_DEAD);
737 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
741 relay_increment_intro1_action(INTRO1_SUCCESS);
743 status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
749 log_warn(
LD_PROTOCOL,
"Unable to send an INTRODUCE ACK status %d "
750 "to client.", status);
755 trn_cell_introduce1_free(parsed_cell);
771 if (circ->already_received_introduce1) {
772 relay_increment_intro1_action(INTRO1_CIRCUIT_REUSED);
774 "Blocking multiple introductions on the same circuit. "
775 "Someone might be trying to attack a hidden service through "
782 relay_increment_intro1_action(INTRO1_SINGLE_HOP);
784 "Single hop client was rejected while trying to introduce. "
804 relay_increment_intro1_action(INTRO1_MALFORMED);
817 circ->already_received_introduce1 = 1;
823 circuit_mark_for_close(
TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
837 link_specifier_free(ls));
int channel_is_client(const channel_t *chan)
Header file for channel.c.
Header file for circuitlist.c.
#define CIRCUIT_PURPOSE_INTRO_POINT
#define CIRCUIT_PURPOSE_OR
void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
Header file for circuituse.c.
Functions and types for monotonic times.
Header file for config.c.
void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, const uint8_t *key, size_t key_len, const uint8_t *msg, size_t msg_len)
int ed25519_checksig_prefixed(const ed25519_signature_t *signature, const uint8_t *msg, size_t msg_len, const char *prefix_str, const ed25519_public_key_t *pubkey)
#define tor_memneq(a, b, sz)
or_circuit_t * hs_circuitmap_get_intro_circ_v3_relay_side(const ed25519_public_key_t *auth_key)
void hs_circuitmap_register_intro_circ_v3_relay_side(or_circuit_t *circ, const ed25519_public_key_t *auth_key)
Header file for hs_circuitmap.c.
Header file containing common data for the whole HS subsystem.
#define ESTABLISH_INTRO_SIG_PREFIX
Header file containing configuration ABI/API for the HS subsystem.
Header file for hs_descriptor.c.
bool hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
void hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
Header file containing denial of service defenses for the HS subsystem for all versions.
STATIC bool cell_dos_extension_parameters_are_valid(uint64_t intro2_rate_per_sec, uint64_t intro2_burst_per_sec)
static int circuit_is_suitable_intro_point(const or_circuit_t *circ, const char *log_cell_type_str)
static int handle_establish_intro(or_circuit_t *circ, const uint8_t *request, size_t request_len)
STATIC int verify_establish_intro_cell(const trn_cell_establish_intro_t *cell, const uint8_t *circuit_key_material, size_t circuit_key_material_len)
void hs_intropoint_clear(hs_intropoint_t *ip)
int hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request, size_t request_len)
STATIC int handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, size_t request_len)
static void handle_establish_intro_cell_extensions(const trn_cell_establish_intro_t *parsed_cell, or_circuit_t *circ)
int hs_intro_send_intro_established_cell(or_circuit_t *circ)
int hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, size_t request_len)
int hs_intro_circuit_is_suitable_for_establish_intro(const or_circuit_t *circ)
static int send_introduce_ack_cell(or_circuit_t *circ, uint16_t status)
STATIC int validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell)
STATIC void get_auth_key_from_cell(ed25519_public_key_t *auth_key_out, unsigned int cell_type, const void *cell)
static void handle_establish_intro_cell_dos_extension(const trn_extension_field_t *field, or_circuit_t *circ)
STATIC int circuit_is_suitable_for_introduce1(const or_circuit_t *circ)
static int handle_verified_establish_intro_cell(or_circuit_t *circ, const trn_cell_establish_intro_t *parsed_cell)
Header file for hs_intropoint.c.
#define log_fn(severity, domain, args,...)
Master header file for Tor-specific functionality.
char * rate_limit_log(ratelim_t *lim, time_t now)
Header for feature/relay/relay_metrics.c.
Header file for relay_msg.c.
static size_t relay_cell_max_payload_size(relay_cell_fmt_t format, uint8_t relay_command)
Header file for rendmid.c.
Header file for rephist.c.
#define SMARTLIST_FOREACH(sl, type, var, cmd)
tor_cert_t * auth_key_cert
smartlist_t * link_specifiers
unsigned int introduce2_dos_defense_enabled
unsigned int introduce2_dos_defense_explicit
token_bucket_ctr_t introduce2_bucket
char rend_circ_nonce[DIGEST_LEN]
#define MOCK_IMPL(rv, funcname, arglist)
void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, uint32_t burst, uint32_t now_ts_sec)
int fast_mem_is_zero(const char *mem, size_t len)
#define ED25519_BASE64_LEN
#define ED25519_PUBKEY_LEN