9 #define HS_INTROPOINT_PRIVATE
22 #include "trunnel/ed25519_cert.h"
23 #include "trunnel/hs/cell_common.h"
24 #include "trunnel/hs/cell_establish_intro.h"
25 #include "trunnel/hs/cell_introduce1.h"
34 #include "core/or/or_circuit_st.h"
41 unsigned int cell_type,
const void *cell)
44 const uint8_t *key_array;
50 case RELAY_COMMAND_ESTABLISH_INTRO:
52 const trn_cell_establish_intro_t *c_cell = cell;
53 key_array = trn_cell_establish_intro_getconstarray_auth_key(c_cell);
54 auth_key_len = trn_cell_establish_intro_getlen_auth_key(c_cell);
57 case RELAY_COMMAND_INTRODUCE1:
59 const trn_cell_introduce1_t *c_cell = cell;
60 key_array = trn_cell_introduce1_getconstarray_auth_key(cell);
61 auth_key_len = trn_cell_introduce1_getlen_auth_key(c_cell);
67 tor_assert_unreached();
70 tor_assert(auth_key_len ==
sizeof(auth_key_out->pubkey));
71 memcpy(auth_key_out->pubkey, key_array, auth_key_len);
78 const uint8_t *circuit_key_material,
79 size_t circuit_key_material_len)
84 if (BUG(cell->auth_key_type != TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519)) {
94 "ESTABLISH_INTRO auth key length is invalid");
98 const uint8_t *msg = cell->start_cell;
103 const uint8_t *sig_array =
104 trn_cell_establish_intro_getconstarray_sig(cell);
109 if (trn_cell_establish_intro_getlen_sig(cell) !=
sizeof(sig_struct.sig) ||
110 trn_cell_establish_intro_get_sig_len(cell) !=
sizeof(sig_struct.sig)) {
112 "ESTABLISH_INTRO sig len is invalid");
116 memcpy(sig_struct.sig, sig_array, cell->sig_len);
121 const size_t sig_msg_len = cell->end_sig_fields - msg;
128 "ESTABLISH_INTRO signature not as expected");
135 const size_t auth_msg_len = cell->end_mac_fields - msg;
138 circuit_key_material, circuit_key_material_len,
140 if (
tor_memneq(mac, cell->handshake_mac,
sizeof(mac))) {
142 "ESTABLISH_INTRO handshake_auth not as expected");
155 uint8_t *encoded_cell = NULL;
156 ssize_t encoded_len, result_len;
157 trn_cell_intro_established_t *cell;
158 trn_cell_extension_t *ext;
163 cell = trn_cell_intro_established_new();
164 ext = trn_cell_extension_new();
165 trn_cell_extension_set_num(ext, 0);
166 trn_cell_intro_established_set_extensions(cell, ext);
168 encoded_len = trn_cell_intro_established_encoded_len(cell);
170 encoded_cell = tor_malloc_zero(encoded_len);
171 result_len = trn_cell_intro_established_encode(encoded_cell, encoded_len,
175 ret = relay_send_command_from_edge(0,
TO_CIRCUIT(circ),
176 RELAY_COMMAND_INTRO_ESTABLISHED,
177 (
char *) encoded_cell, encoded_len,
180 trn_cell_intro_established_free(cell);
190 uint64_t intro2_burst_per_sec)
196 #if HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN > 0
197 if (intro2_rate_per_sec < HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN) {
199 "Intro point DoS defenses rate per second is "
200 "too small. Received value: %" PRIu64, intro2_rate_per_sec);
206 if (intro2_rate_per_sec > HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX) {
208 "Intro point DoS defenses rate per second is "
209 "too big. Received value: %" PRIu64, intro2_rate_per_sec);
214 #if HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN > 0
215 if (intro2_burst_per_sec < HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN) {
217 "Intro point DoS defenses burst per second is "
218 "too small. Received value: %" PRIu64, intro2_burst_per_sec);
224 if (intro2_burst_per_sec > HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX) {
226 "Intro point DoS defenses burst per second is "
227 "too big. Received value: %" PRIu64, intro2_burst_per_sec);
233 if (intro2_burst_per_sec < intro2_rate_per_sec) {
234 log_info(
LD_REND,
"Intro point DoS defenses burst is smaller than rate. "
235 "Rate: %" PRIu64
" vs Burst: %" PRIu64,
236 intro2_rate_per_sec, intro2_burst_per_sec);
252 const trn_cell_extension_field_t *field,
256 uint64_t intro2_rate_per_sec = 0, intro2_burst_per_sec = 0;
257 trn_cell_extension_dos_t *dos = NULL;
262 ret = trn_cell_extension_dos_parse(&dos,
263 trn_cell_extension_field_getconstarray_field(field),
264 trn_cell_extension_field_getlen_field(field));
269 for (
size_t i = 0; i < trn_cell_extension_dos_get_n_params(dos); i++) {
270 const trn_cell_extension_dos_param_t *param =
271 trn_cell_extension_dos_getconst_params(dos, i);
272 if (BUG(param == NULL)) {
276 switch (trn_cell_extension_dos_param_get_type(param)) {
277 case TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC:
278 intro2_rate_per_sec = trn_cell_extension_dos_param_get_value(param);
280 case TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC:
281 intro2_burst_per_sec = trn_cell_extension_dos_param_get_value(param);
295 if (intro2_rate_per_sec == 0 || intro2_burst_per_sec == 0) {
296 log_info(
LD_REND,
"Intro point DoS defenses parameter set to 0. "
297 "Disabling INTRO2 DoS defenses on circuit id %u",
305 intro2_burst_per_sec)) {
307 log_info(
LD_REND,
"Disabling INTRO2 DoS defenses on circuit id %u",
317 (uint32_t) intro2_rate_per_sec,
318 (uint32_t) intro2_burst_per_sec,
320 log_info(
LD_REND,
"Intro point DoS defenses enabled. Rate is %" PRIu64
321 " and Burst is %" PRIu64,
322 intro2_rate_per_sec, intro2_burst_per_sec);
325 trn_cell_extension_dos_free(dos);
332 const trn_cell_establish_intro_t *parsed_cell,
335 const trn_cell_extension_t *extensions;
340 extensions = trn_cell_establish_intro_getconst_extensions(parsed_cell);
341 if (extensions == NULL) {
346 for (
size_t idx = 0; idx < trn_cell_extension_get_num(extensions); idx++) {
347 const trn_cell_extension_field_t *field =
348 trn_cell_extension_getconst_fields(extensions, idx);
349 if (BUG(field == NULL)) {
354 switch (trn_cell_extension_field_get_field_type(field)) {
355 case TRUNNEL_CELL_EXTENSION_TYPE_DOS:
374 const trn_cell_establish_intro_t *parsed_cell)
391 log_warn(
LD_PROTOCOL,
"Couldn't send INTRO_ESTABLISHED cell.");
410 int cell_ok, retval = -1;
411 trn_cell_establish_intro_t *parsed_cell = NULL;
416 log_info(
LD_REND,
"Received an ESTABLISH_INTRO request on circuit %" PRIu32,
425 ssize_t parsing_result = trn_cell_establish_intro_parse(&parsed_cell,
426 request, request_len);
427 if (parsing_result < 0) {
429 "Rejecting %s ESTABLISH_INTRO cell.",
430 parsing_result == -1 ?
"invalid" :
"truncated");
439 "Failed to verify ESTABLISH_INTRO cell.");
457 circuit_mark_for_close(
TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
461 trn_cell_establish_intro_free(parsed_cell);
468 const char *log_cell_type_str)
476 "Rejecting %s on non-OR circuit.", log_cell_type_str);
482 "Rejecting %s on non-edge circuit.", log_cell_type_str);
506 if (request_len == 0) {
513 const uint8_t first_byte = request[0];
514 switch (first_byte) {
515 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0:
516 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1:
520 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519:
524 "Unrecognized AUTH_KEY_TYPE %u.", first_byte);
529 circuit_mark_for_close(
TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
541 uint8_t *encoded_cell = NULL;
542 ssize_t encoded_len, result_len;
543 trn_cell_introduce_ack_t *cell;
544 trn_cell_extension_t *ext;
550 cell = trn_cell_introduce_ack_new();
551 ret = trn_cell_introduce_ack_set_status(cell, status);
553 ext = trn_cell_extension_new();
554 trn_cell_extension_set_num(ext, 0);
555 trn_cell_introduce_ack_set_extensions(cell, ext);
561 encoded_len = trn_cell_introduce_ack_encoded_len(cell);
563 encoded_cell = tor_malloc_zero(encoded_len);
564 result_len = trn_cell_introduce_ack_encode(encoded_cell, encoded_len, cell);
567 ret = relay_send_command_from_edge(CONTROL_CELL_ID,
TO_CIRCUIT(circ),
568 RELAY_COMMAND_INTRODUCE_ACK,
569 (
char *) encoded_cell, encoded_len,
572 trn_cell_introduce_ack_free(cell);
582 size_t legacy_key_id_len;
583 const uint8_t *legacy_key_id;
589 legacy_key_id_len = trn_cell_introduce1_getlen_legacy_key_id(cell);
590 legacy_key_id = trn_cell_introduce1_getconstarray_legacy_key_id(cell);
597 if (trn_cell_introduce1_get_auth_key_type(cell) !=
598 TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519) {
600 "Rejecting invalid INTRODUCE1 cell auth key type. "
601 "Responding with NACK.");
607 "Rejecting invalid INTRODUCE1 cell auth key length. "
608 "Responding with NACK.");
611 if (trn_cell_introduce1_getlen_encrypted(cell) == 0) {
613 "Rejecting invalid INTRODUCE1 cell encrypted length. "
614 "Responding with NACK.");
634 trn_cell_introduce1_t *parsed_cell;
635 uint16_t status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
643 ssize_t cell_size = trn_cell_introduce1_parse(&parsed_cell, request,
647 "Rejecting %s INTRODUCE1 cell. Responding with NACK.",
648 cell_size == -1 ?
"invalid" :
"truncated");
650 status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
657 status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
666 if (service_circ == NULL) {
669 log_info(
LD_REND,
"No intro circuit found for INTRODUCE1 cell "
670 "with auth key %s from circuit %" PRIu32
". "
671 "Responding with NACK.",
672 safe_str(b64_key), client_circ->
p_circ_id);
674 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
683 static ratelim_t rlimit = RATELIM_INIT(5 * 60);
685 log_info(
LD_PROTOCOL,
"Can't relay INTRODUCE1 v3 cell due to DoS "
686 "limitations. Sending NACK to client.");
689 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
695 if (relay_send_command_from_edge(CONTROL_CELL_ID,
TO_CIRCUIT(service_circ),
696 RELAY_COMMAND_INTRODUCE2,
697 (
char *) request, request_len, NULL)) {
698 log_warn(
LD_PROTOCOL,
"Unable to send INTRODUCE2 cell to the service.");
701 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
706 status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
712 log_warn(
LD_PROTOCOL,
"Unable to send an INTRODUCE ACK status %d "
713 "to client.", status);
718 trn_cell_introduce1_free(parsed_cell);
734 if (circ->already_received_introduce1) {
736 "Blocking multiple introductions on the same circuit. "
737 "Someone might be trying to attack a hidden service through "
745 "Single hop client was rejected while trying to introduce. "
777 circ->already_received_introduce1 = 1;
783 circuit_mark_for_close(
TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
797 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.
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 handle_establish_intro_cell_dos_extension(const trn_cell_extension_field_t *field, or_circuit_t *circ)
STATIC void get_auth_key_from_cell(ed25519_public_key_t *auth_key_out, unsigned int cell_type, const void *cell)
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 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)
int fast_mem_is_zero(const char *mem, size_t len)
#define ED25519_BASE64_LEN
#define ED25519_PUBKEY_LEN