Tor 0.4.9.0-alpha-dev
hs_intropoint.c
Go to the documentation of this file.
1/* Copyright (c) 2016-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file hs_intropoint.c
6 * \brief Implement next generation introductions point functionality
7 **/
8
9#define HS_INTROPOINT_PRIVATE
10
11#include "core/or/or.h"
12#include "app/config/config.h"
13#include "core/or/channel.h"
14#include "core/or/circuitlist.h"
15#include "core/or/circuituse.h"
16#include "core/or/relay.h"
22
23/* Trunnel */
24#include "trunnel/ed25519_cert.h"
25#include "trunnel/extension.h"
26#include "trunnel/hs/cell_establish_intro.h"
27#include "trunnel/hs/cell_introduce1.h"
28
33#include "feature/hs/hs_dos.h"
35
36#include "core/or/or_circuit_st.h"
37
38/** Extract the authentication key from an ESTABLISH_INTRO or INTRODUCE1 using
39 * the given <b>cell_type</b> from <b>cell</b> and place it in
40 * <b>auth_key_out</b>. */
41STATIC void
43 unsigned int cell_type, const void *cell)
44{
45 size_t auth_key_len;
46 const uint8_t *key_array;
47
48 tor_assert(auth_key_out);
49 tor_assert(cell);
50
51 switch (cell_type) {
52 case RELAY_COMMAND_ESTABLISH_INTRO:
53 {
54 const trn_cell_establish_intro_t *c_cell = cell;
55 key_array = trn_cell_establish_intro_getconstarray_auth_key(c_cell);
56 auth_key_len = trn_cell_establish_intro_getlen_auth_key(c_cell);
57 break;
58 }
59 case RELAY_COMMAND_INTRODUCE1:
60 {
61 const trn_cell_introduce1_t *c_cell = cell;
62 key_array = trn_cell_introduce1_getconstarray_auth_key(cell);
63 auth_key_len = trn_cell_introduce1_getlen_auth_key(c_cell);
64 break;
65 }
66 default:
67 /* Getting here is really bad as it means we got a unknown cell type from
68 * this file where every call has an hardcoded value. */
69 tor_assert_unreached(); /* LCOV_EXCL_LINE */
70 }
71 tor_assert(key_array);
72 tor_assert(auth_key_len == sizeof(auth_key_out->pubkey));
73 memcpy(auth_key_out->pubkey, key_array, auth_key_len);
74}
75
76/** We received an ESTABLISH_INTRO <b>cell</b>. Verify its signature and MAC,
77 * given <b>circuit_key_material</b>. Return 0 on success else -1 on error. */
78STATIC int
79verify_establish_intro_cell(const trn_cell_establish_intro_t *cell,
80 const uint8_t *circuit_key_material,
81 size_t circuit_key_material_len)
82{
83 /* We only reach this function if the first byte of the cell is 0x02 which
84 * means that auth_key_type is of ed25519 type, hence this check should
85 * always pass. See hs_intro_received_establish_intro(). */
86 if (BUG(cell->auth_key_type != TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519)) {
87 return -1;
88 }
89
90 /* Make sure the auth key length is of the right size for this type. For
91 * EXTRA safety, we check both the size of the array and the length which
92 * must be the same. Safety first!*/
93 if (trn_cell_establish_intro_getlen_auth_key(cell) != ED25519_PUBKEY_LEN ||
94 trn_cell_establish_intro_get_auth_key_len(cell) != ED25519_PUBKEY_LEN) {
95 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
96 "ESTABLISH_INTRO auth key length is invalid");
97 return -1;
98 }
99
100 const uint8_t *msg = cell->start_cell;
101
102 /* Verify the sig */
103 {
104 ed25519_signature_t sig_struct;
105 const uint8_t *sig_array =
106 trn_cell_establish_intro_getconstarray_sig(cell);
107
108 /* Make sure the signature length is of the right size. For EXTRA safety,
109 * we check both the size of the array and the length which must be the
110 * same. Safety first!*/
111 if (trn_cell_establish_intro_getlen_sig(cell) != sizeof(sig_struct.sig) ||
112 trn_cell_establish_intro_get_sig_len(cell) != sizeof(sig_struct.sig)) {
113 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
114 "ESTABLISH_INTRO sig len is invalid");
115 return -1;
116 }
117 /* We are now sure that sig_len is of the right size. */
118 memcpy(sig_struct.sig, sig_array, cell->sig_len);
119
120 ed25519_public_key_t auth_key;
121 get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO, cell);
122
123 const size_t sig_msg_len = cell->end_sig_fields - msg;
124 int sig_mismatch = ed25519_checksig_prefixed(&sig_struct,
125 msg, sig_msg_len,
127 &auth_key);
128 if (sig_mismatch) {
129 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
130 "ESTABLISH_INTRO signature not as expected");
131 return -1;
132 }
133 }
134
135 /* Verify the MAC */
136 {
137 const size_t auth_msg_len = cell->end_mac_fields - msg;
138 uint8_t mac[DIGEST256_LEN];
139 crypto_mac_sha3_256(mac, sizeof(mac),
140 circuit_key_material, circuit_key_material_len,
141 msg, auth_msg_len);
142 if (tor_memneq(mac, cell->handshake_mac, sizeof(mac))) {
143 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
144 "ESTABLISH_INTRO handshake_auth not as expected");
145 return -1;
146 }
147 }
148
149 return 0;
150}
151
152/** Send an INTRO_ESTABLISHED cell to <b>circ</b>. */
153MOCK_IMPL(int,
155{
156 int ret;
157 uint8_t *encoded_cell = NULL;
158 ssize_t encoded_len, result_len;
159 trn_cell_intro_established_t *cell;
160 trn_extension_t *ext;
161
162 tor_assert(circ);
163
164 /* Build the cell payload. */
165 cell = trn_cell_intro_established_new();
166 ext = trn_extension_new();
167 trn_extension_set_num(ext, 0);
168 trn_cell_intro_established_set_extensions(cell, ext);
169 /* Encode the cell to binary format. */
170 encoded_len = trn_cell_intro_established_encoded_len(cell);
171 tor_assert(encoded_len > 0);
172 encoded_cell = tor_malloc_zero(encoded_len);
173 result_len = trn_cell_intro_established_encode(encoded_cell, encoded_len,
174 cell);
175 tor_assert(encoded_len == result_len);
176
177 ret = relay_send_command_from_edge(0, TO_CIRCUIT(circ),
178 RELAY_COMMAND_INTRO_ESTABLISHED,
179 (char *) encoded_cell, encoded_len,
180 NULL);
181 /* On failure, the above function will close the circuit. */
182 trn_cell_intro_established_free(cell);
183 tor_free(encoded_cell);
184 return ret;
185}
186
187/** Validate the cell DoS extension parameters. Return true iff they've been
188 * bound check and can be used. Else return false. See proposal 305 for
189 * details and reasons about this validation. */
190STATIC bool
191cell_dos_extension_parameters_are_valid(uint64_t intro2_rate_per_sec,
192 uint64_t intro2_burst_per_sec)
193{
194 bool ret = false;
195
196 /* Check that received value is not below the minimum. Don't check if minimum
197 is set to 0, since the param is a positive value and gcc will complain. */
198#if HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN > 0
199 if (intro2_rate_per_sec < HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN) {
200 log_fn(LOG_PROTOCOL_WARN, LD_REND,
201 "Intro point DoS defenses rate per second is "
202 "too small. Received value: %" PRIu64, intro2_rate_per_sec);
203 goto end;
204 }
205#endif /* HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN > 0 */
206
207 /* Check that received value is not above maximum */
208 if (intro2_rate_per_sec > HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX) {
209 log_fn(LOG_PROTOCOL_WARN, LD_REND,
210 "Intro point DoS defenses rate per second is "
211 "too big. Received value: %" PRIu64, intro2_rate_per_sec);
212 goto end;
213 }
214
215 /* Check that received value is not below the minimum */
216#if HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN > 0
217 if (intro2_burst_per_sec < HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN) {
218 log_fn(LOG_PROTOCOL_WARN, LD_REND,
219 "Intro point DoS defenses burst per second is "
220 "too small. Received value: %" PRIu64, intro2_burst_per_sec);
221 goto end;
222 }
223#endif /* HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN > 0 */
224
225 /* Check that received value is not above maximum */
226 if (intro2_burst_per_sec > HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX) {
227 log_fn(LOG_PROTOCOL_WARN, LD_REND,
228 "Intro point DoS defenses burst per second is "
229 "too big. Received value: %" PRIu64, intro2_burst_per_sec);
230 goto end;
231 }
232
233 /* In a rate limiting scenario, burst can never be smaller than the rate. At
234 * best it can be equal. */
235 if (intro2_burst_per_sec < intro2_rate_per_sec) {
236 log_info(LD_REND, "Intro point DoS defenses burst is smaller than rate. "
237 "Rate: %" PRIu64 " vs Burst: %" PRIu64,
238 intro2_rate_per_sec, intro2_burst_per_sec);
239 goto end;
240 }
241
242 /* Passing validation. */
243 ret = true;
244
245 end:
246 return ret;
247}
248
249/** Parse the cell DoS extension and apply defenses on the given circuit if
250 * validation passes. If the cell extension is malformed or contains unusable
251 * values, the DoS defenses is disabled on the circuit. */
252static void
254 const trn_extension_field_t *field,
255 or_circuit_t *circ)
256{
257 ssize_t ret;
258 uint64_t intro2_rate_per_sec = 0, intro2_burst_per_sec = 0;
259 trn_cell_extension_dos_t *dos = NULL;
260
261 tor_assert(field);
262 tor_assert(circ);
263
264 ret = trn_cell_extension_dos_parse(&dos,
265 trn_extension_field_getconstarray_field(field),
266 trn_extension_field_getlen_field(field));
267 if (ret < 0) {
268 goto end;
269 }
270
271 for (size_t i = 0; i < trn_cell_extension_dos_get_n_params(dos); i++) {
272 const trn_cell_extension_dos_param_t *param =
273 trn_cell_extension_dos_getconst_params(dos, i);
274 if (BUG(param == NULL)) {
275 goto end;
276 }
277
278 switch (trn_cell_extension_dos_param_get_type(param)) {
279 case TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC:
280 intro2_rate_per_sec = trn_cell_extension_dos_param_get_value(param);
281 break;
282 case TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC:
283 intro2_burst_per_sec = trn_cell_extension_dos_param_get_value(param);
284 break;
285 default:
286 goto end;
287 }
288 }
289
290 /* At this point, the extension is valid so any values out of it implies
291 * that it was set explicitly and thus flag the circuit that it should not
292 * look at the consensus for that reason for the defenses' values. */
294
295 /* A value of 0 is valid in the sense that we accept it but we still disable
296 * the defenses so return false. */
297 if (intro2_rate_per_sec == 0 || intro2_burst_per_sec == 0) {
298 log_info(LD_REND, "Intro point DoS defenses parameter set to 0. "
299 "Disabling INTRO2 DoS defenses on circuit id %u",
300 circ->p_circ_id);
302 goto end;
303 }
304
305 /* If invalid, we disable the defense on the circuit. */
306 if (!cell_dos_extension_parameters_are_valid(intro2_rate_per_sec,
307 intro2_burst_per_sec)) {
309 log_info(LD_REND, "Disabling INTRO2 DoS defenses on circuit id %u",
310 circ->p_circ_id);
311 goto end;
312 }
313
314 /* We passed validation, enable defenses and apply rate/burst. */
316
317 /* Initialize the INTRODUCE2 token bucket for the rate limiting. */
319 (uint32_t) intro2_rate_per_sec,
320 (uint32_t) intro2_burst_per_sec,
321 (uint32_t) monotime_coarse_absolute_sec());
322 log_info(LD_REND, "Intro point DoS defenses enabled. Rate is %" PRIu64
323 " and Burst is %" PRIu64,
324 intro2_rate_per_sec, intro2_burst_per_sec);
325
326 end:
327 trn_cell_extension_dos_free(dos);
328 return;
329}
330
331/** Parse every cell extension in the given ESTABLISH_INTRO cell. */
332static void
334 const trn_cell_establish_intro_t *parsed_cell,
335 or_circuit_t *circ)
336{
337 const trn_extension_t *extensions;
338
339 tor_assert(parsed_cell);
340 tor_assert(circ);
341
342 extensions = trn_cell_establish_intro_getconst_extensions(parsed_cell);
343 if (extensions == NULL) {
344 goto end;
345 }
346
347 /* Go over all extensions. */
348 for (size_t idx = 0; idx < trn_extension_get_num(extensions); idx++) {
349 const trn_extension_field_t *field =
350 trn_extension_getconst_fields(extensions, idx);
351 if (BUG(field == NULL)) {
352 /* The number of extensions should match the number of fields. */
353 break;
354 }
355
356 switch (trn_extension_field_get_field_type(field)) {
357 case TRUNNEL_CELL_EXTENSION_TYPE_DOS:
358 /* After this, the circuit should be set for DoS defenses. */
360 break;
361 default:
362 /* Unknown extension. Skip over. */
363 break;
364 }
365 }
366
367 end:
368 return;
369}
370
371/** We received an ESTABLISH_INTRO <b>parsed_cell</b> on <b>circ</b>. It's
372 * well-formed and passed our verifications. Perform appropriate actions to
373 * establish an intro point. */
374static int
376 const trn_cell_establish_intro_t *parsed_cell)
377{
378 /* Get the auth key of this intro point */
379 ed25519_public_key_t auth_key;
380 get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
381 parsed_cell);
382
383 /* Setup INTRODUCE2 defenses on the circuit. Must be done before parsing the
384 * cell extension that can possibly change the defenses' values. */
386
387 /* Handle cell extension if any. */
389
390 /* Then notify the hidden service that the intro point is established by
391 sending an INTRO_ESTABLISHED cell */
393 log_warn(LD_PROTOCOL, "Couldn't send INTRO_ESTABLISHED cell.");
394 return -1;
395 }
396
397 /* Associate intro point auth key with this circuit. */
399 /* Repurpose this circuit into an intro circuit. */
401
402 return 0;
403}
404
405/** We just received an ESTABLISH_INTRO cell in <b>circ</b> with payload in
406 * <b>request</b>. Handle it by making <b>circ</b> an intro circuit. Return 0
407 * if everything went well, or -1 if there were errors. */
408static int
409handle_establish_intro(or_circuit_t *circ, const uint8_t *request,
410 size_t request_len)
411{
412 int cell_ok, retval = -1;
413 trn_cell_establish_intro_t *parsed_cell = NULL;
414
415 tor_assert(circ);
416 tor_assert(request);
417
418 log_info(LD_REND, "Received an ESTABLISH_INTRO request on circuit %" PRIu32,
419 circ->p_circ_id);
420
421 /* Check that the circuit is in shape to become an intro point */
423 relay_increment_est_intro_action(EST_INTRO_UNSUITABLE_CIRCUIT);
424 goto err;
425 }
426
427 /* Parse the cell */
428 ssize_t parsing_result = trn_cell_establish_intro_parse(&parsed_cell,
429 request, request_len);
430 if (parsing_result < 0) {
431 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
432 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
433 "Rejecting %s ESTABLISH_INTRO cell.",
434 parsing_result == -1 ? "invalid" : "truncated");
435 goto err;
436 }
437
438 cell_ok = verify_establish_intro_cell(parsed_cell,
439 (uint8_t *) circ->rend_circ_nonce,
440 sizeof(circ->rend_circ_nonce));
441 if (cell_ok < 0) {
442 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
443 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
444 "Failed to verify ESTABLISH_INTRO cell.");
445 goto err;
446 }
447
448 /* This cell is legit. Take the appropriate actions. */
449 cell_ok = handle_verified_establish_intro_cell(circ, parsed_cell);
450 if (cell_ok < 0) {
451 relay_increment_est_intro_action(EST_INTRO_CIRCUIT_DEAD);
452 goto err;
453 }
454
455 relay_increment_est_intro_action(EST_INTRO_SUCCESS);
456 /* We are done! */
457 retval = 0;
458 goto done;
459
460 err:
461 /* When sending the intro establish ack, on error the circuit can be marked
462 * as closed so avoid a double close. */
463 if (!TO_CIRCUIT(circ)->marked_for_close) {
464 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
465 }
466
467 done:
468 trn_cell_establish_intro_free(parsed_cell);
469 return retval;
470}
471
472/** Return True if circuit is suitable for being an intro circuit. */
473static int
475 const char *log_cell_type_str)
476{
477 tor_assert(circ);
478 tor_assert(log_cell_type_str);
479
480 /* Basic circuit state sanity checks. */
481 if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) {
482 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
483 "Rejecting %s on non-OR circuit.", log_cell_type_str);
484 return 0;
485 }
486
487 if (circ->base_.n_chan) {
488 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
489 "Rejecting %s on non-edge circuit.", log_cell_type_str);
490 return 0;
491 }
492
493 /* Suitable. */
494 return 1;
495}
496
497/** Return True if circuit is suitable for being service-side intro circuit. */
498int
500{
501 return circuit_is_suitable_intro_point(circ, "ESTABLISH_INTRO");
502}
503
504/** We just received an ESTABLISH_INTRO cell in <b>circ</b>. Pass it to the
505 * appropriate handler. */
506int
508 size_t request_len)
509{
510 tor_assert(circ);
511 tor_assert(request);
512
513 if (request_len == 0) {
514 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
515 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Empty ESTABLISH_INTRO cell.");
516 goto err;
517 }
518
519 /* Using the first byte of the cell, figure out the version of
520 * ESTABLISH_INTRO and pass it to the appropriate cell handler */
521 const uint8_t first_byte = request[0];
522 switch (first_byte) {
523 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0:
524 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1:
525 /* Likely version 2 onion service which is now obsolete. Avoid a
526 * protocol warning considering they still exists on the network. */
527 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
528 goto err;
529 case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519:
530 return handle_establish_intro(circ, request, request_len);
531 default:
532 relay_increment_est_intro_action(EST_INTRO_MALFORMED);
533 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
534 "Unrecognized AUTH_KEY_TYPE %u.", first_byte);
535 goto err;
536 }
537
538 err:
539 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
540 return -1;
541}
542
543/** Send an INTRODUCE_ACK cell onto the circuit <b>circ</b> with the status
544 * value in <b>status</b>. Depending on the status, it can be ACK or a NACK.
545 * Return 0 on success else a negative value on error which will close the
546 * circuit. */
547static int
549{
550 int ret = -1;
551 uint8_t *encoded_cell = NULL;
552 ssize_t encoded_len, result_len;
553 trn_cell_introduce_ack_t *cell;
554 trn_extension_t *ext;
555
556 tor_assert(circ);
557
558 /* Setup the INTRODUCE_ACK cell. We have no extensions so the N_EXTENSIONS
559 * field is set to 0 by default with a new object. */
560 cell = trn_cell_introduce_ack_new();
561 ret = trn_cell_introduce_ack_set_status(cell, status);
562 /* We have no cell extensions in an INTRODUCE_ACK cell. */
563 ext = trn_extension_new();
564 trn_extension_set_num(ext, 0);
565 trn_cell_introduce_ack_set_extensions(cell, ext);
566 /* A wrong status is a very bad code flow error as this value is controlled
567 * by the code in this file and not an external input. This means we use a
568 * code that is not known by the trunnel ABI. */
569 tor_assert(ret == 0);
570 /* Encode the payload. We should never fail to get the encoded length. */
571 encoded_len = trn_cell_introduce_ack_encoded_len(cell);
572 tor_assert(encoded_len > 0);
573 encoded_cell = tor_malloc_zero(encoded_len);
574 result_len = trn_cell_introduce_ack_encode(encoded_cell, encoded_len, cell);
575 tor_assert(encoded_len == result_len);
576
577 ret = relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
578 RELAY_COMMAND_INTRODUCE_ACK,
579 (char *) encoded_cell, encoded_len,
580 NULL);
581 /* On failure, the above function will close the circuit. */
582 trn_cell_introduce_ack_free(cell);
583 tor_free(encoded_cell);
584 return ret;
585}
586
587/** Validate a parsed INTRODUCE1 <b>cell</b>. Return 0 if valid or else a
588 * negative value for an invalid cell that should be NACKed. */
589STATIC int
590validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell)
591{
592 size_t legacy_key_id_len;
593 const uint8_t *legacy_key_id;
594
595 tor_assert(cell);
596
597 /* This code path SHOULD NEVER be reached if the cell is a legacy type so
598 * safety net here. The legacy ID must be zeroes in this case. */
599 legacy_key_id_len = trn_cell_introduce1_getlen_legacy_key_id(cell);
600 legacy_key_id = trn_cell_introduce1_getconstarray_legacy_key_id(cell);
601 if (BUG(!fast_mem_is_zero((char *) legacy_key_id, legacy_key_id_len))) {
602 goto invalid;
603 }
604
605 /* The auth key of an INTRODUCE1 should be of type ed25519 thus leading to a
606 * known fixed length as well. */
607 if (trn_cell_introduce1_get_auth_key_type(cell) !=
608 TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519) {
609 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
610 "Rejecting invalid INTRODUCE1 cell auth key type. "
611 "Responding with NACK.");
612 goto invalid;
613 }
614 if (trn_cell_introduce1_get_auth_key_len(cell) != ED25519_PUBKEY_LEN ||
615 trn_cell_introduce1_getlen_auth_key(cell) != ED25519_PUBKEY_LEN) {
616 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
617 "Rejecting invalid INTRODUCE1 cell auth key length. "
618 "Responding with NACK.");
619 goto invalid;
620 }
621 if (trn_cell_introduce1_getlen_encrypted(cell) == 0) {
622 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
623 "Rejecting invalid INTRODUCE1 cell encrypted length. "
624 "Responding with NACK.");
625 goto invalid;
626 }
627
628 return 0;
629 invalid:
630 return -1;
631}
632
633/** We just received a non legacy INTRODUCE1 cell on <b>client_circ</b> with
634 * the payload in <b>request</b> of size <b>request_len</b>. Return 0 if
635 * everything went well, or -1 if an error occurred. This function is in charge
636 * of sending back an INTRODUCE_ACK cell and will close client_circ on error.
637 */
638STATIC int
639handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
640 size_t request_len)
641{
642 int ret = -1;
643 or_circuit_t *service_circ;
644 trn_cell_introduce1_t *parsed_cell;
645 uint16_t status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
646
647 tor_assert(client_circ);
648 tor_assert(request);
649
650 /* Parse cell. Note that we can only parse the non encrypted section for
651 * which we'll use the authentication key to find the service introduction
652 * circuit and relay the cell on it. */
653 ssize_t cell_size = trn_cell_introduce1_parse(&parsed_cell, request,
654 request_len);
655 if (cell_size < 0) {
656 relay_increment_intro1_action(INTRO1_MALFORMED);
657 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
658 "Rejecting %s INTRODUCE1 cell. Responding with NACK.",
659 cell_size == -1 ? "invalid" : "truncated");
660 /* Inform client that the INTRODUCE1 has a bad format. */
661 status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
662 goto send_ack;
663 }
664
665 /* Once parsed validate the cell format. */
666 if (validate_introduce1_parsed_cell(parsed_cell) < 0) {
667 relay_increment_intro1_action(INTRO1_MALFORMED);
668 /* Inform client that the INTRODUCE1 has bad format. */
669 status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
670 goto send_ack;
671 }
672
673 /* Find introduction circuit through our circuit map. */
674 {
675 ed25519_public_key_t auth_key;
676 get_auth_key_from_cell(&auth_key, RELAY_COMMAND_INTRODUCE1, parsed_cell);
677 service_circ = hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
678 if (service_circ == NULL) {
679 relay_increment_intro1_action(INTRO1_UNKNOWN_SERVICE);
680 char b64_key[ED25519_BASE64_LEN + 1];
681 ed25519_public_to_base64(b64_key, &auth_key);
682 log_info(LD_REND, "No intro circuit found for INTRODUCE1 cell "
683 "with auth key %s from circuit %" PRIu32 ". "
684 "Responding with NACK.",
685 safe_str(b64_key), client_circ->p_circ_id);
686 /* Inform the client that we don't know the requested service ID. */
687 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
688 goto send_ack;
689 }
690 }
691
692 /* Before sending, lets make sure this cell can be sent on the service
693 * circuit asking the DoS defenses. */
694 if (!hs_dos_can_send_intro2(service_circ)) {
695 relay_increment_intro1_action(INTRO1_RATE_LIMITED);
696 char *msg;
697 static ratelim_t rlimit = RATELIM_INIT(5 * 60);
698 if ((msg = rate_limit_log(&rlimit, approx_time()))) {
699 log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v3 cell due to DoS "
700 "limitations. Sending NACK to client.");
701 tor_free(msg);
702 }
703 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
704 goto send_ack;
705 }
706
707 /* Relay the cell to the service on its intro circuit with an INTRODUCE2
708 * cell which is the same exact payload. */
709 if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(service_circ),
710 RELAY_COMMAND_INTRODUCE2,
711 (char *) request, request_len, NULL)) {
712 relay_increment_intro1_action(INTRO1_CIRCUIT_DEAD);
713 log_warn(LD_PROTOCOL, "Unable to send INTRODUCE2 cell to the service.");
714 /* Inform the client that we can't relay the cell. Use the unknown ID
715 * status code since it means that we do not know the service. */
716 status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
717 goto send_ack;
718 }
719
720 relay_increment_intro1_action(INTRO1_SUCCESS);
721 /* Success! Send an INTRODUCE_ACK success status onto the client circuit. */
722 status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
723 ret = 0;
724
725 send_ack:
726 /* Send INTRODUCE_ACK or INTRODUCE_NACK to client */
727 if (send_introduce_ack_cell(client_circ, status) < 0) {
728 log_warn(LD_PROTOCOL, "Unable to send an INTRODUCE ACK status %d "
729 "to client.", status);
730 /* Circuit has been closed on failure of transmission. */
731 goto done;
732 }
733 done:
734 trn_cell_introduce1_free(parsed_cell);
735 return ret;
736}
737
738/** Return true iff the circuit <b>circ</b> is suitable for receiving an
739 * INTRODUCE1 cell. */
740STATIC int
742{
743 tor_assert(circ);
744
745 /* Is this circuit an intro point circuit? */
746 if (!circuit_is_suitable_intro_point(circ, "INTRODUCE1")) {
747 return 0;
748 }
749
750 if (circ->already_received_introduce1) {
751 relay_increment_intro1_action(INTRO1_CIRCUIT_REUSED);
752 log_fn(LOG_PROTOCOL_WARN, LD_REND,
753 "Blocking multiple introductions on the same circuit. "
754 "Someone might be trying to attack a hidden service through "
755 "this relay.");
756 return 0;
757 }
758
759 /* Disallow single hop client circuit. */
760 if (circ->p_chan && channel_is_client(circ->p_chan)) {
761 relay_increment_intro1_action(INTRO1_SINGLE_HOP);
762 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
763 "Single hop client was rejected while trying to introduce. "
764 "Closing circuit.");
765 return 0;
766 }
767
768 return 1;
769}
770
771/** We just received an INTRODUCE1 cell on <b>circ</b>. Figure out which type
772 * it is and pass it to the appropriate handler. Return 0 on success else a
773 * negative value and the circuit is closed. */
774int
775hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request,
776 size_t request_len)
777{
778 tor_assert(circ);
779 tor_assert(request);
780
781 /* A cell that can't hold a DIGEST_LEN is invalid. */
782 if (request_len < DIGEST_LEN) {
783 relay_increment_intro1_action(INTRO1_MALFORMED);
784 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid INTRODUCE1 cell length.");
785 goto err;
786 }
787
788 /* Make sure we have a circuit that can have an INTRODUCE1 cell on it. */
790 /* We do not send a NACK because the circuit is not suitable for any kind
791 * of response or transmission as it's a violation of the protocol. */
792 goto err;
793 }
794 /* Mark the circuit that we got this cell. None are allowed after this as a
795 * DoS mitigation since one circuit with one client can hammer a service. */
796 circ->already_received_introduce1 = 1;
797
798 /* Handle the cell. */
799 return handle_introduce1(circ, request, request_len);
800
801 err:
802 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
803 return -1;
804}
805
806/** Clear memory allocated by the given intropoint object ip (but don't free
807 * the object itself). */
808void
810{
811 if (ip == NULL) {
812 return;
813 }
814 tor_cert_free(ip->auth_key_cert);
815 SMARTLIST_FOREACH(ip->link_specifiers, link_specifier_t *, ls,
816 link_specifier_free(ls));
817 smartlist_free(ip->link_specifiers);
818 memset(ip, 0, sizeof(hs_intropoint_t));
819}
time_t approx_time(void)
Definition: approx_time.c:32
int channel_is_client(const channel_t *chan)
Definition: channel.c:2918
Header file for channel.c.
Header file for circuitlist.c.
#define CIRCUIT_PURPOSE_INTRO_POINT
Definition: circuitlist.h:42
#define CIRCUIT_PURPOSE_OR
Definition: circuitlist.h:39
void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
Definition: circuituse.c:3095
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)
void ed25519_public_to_base64(char *output, const ed25519_public_key_t *pkey)
Header for crypto_format.c.
#define tor_memneq(a, b, sz)
Definition: di_ops.h:21
#define DIGEST_LEN
Definition: digest_sizes.h:20
#define DIGEST256_LEN
Definition: digest_sizes.h:23
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
Definition: hs_common.h:50
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)
Definition: hs_dos.c:167
void hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
Definition: hs_dos.c:138
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)
Definition: hs_intropoint.c:79
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)
Definition: hs_intropoint.c:42
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,...)
Definition: log.h:283
#define LD_REND
Definition: log.h:84
#define LD_PROTOCOL
Definition: log.h:72
#define tor_free(p)
Definition: malloc.h:56
Master header file for Tor-specific functionality.
#define TO_CIRCUIT(x)
Definition: or.h:848
char * rate_limit_log(ratelim_t *lim, time_t now)
Definition: ratelim.c:42
Header file for relay.c.
Header for feature/relay/relay_metrics.c.
Header file for rendmid.c.
Header file for rephist.c.
#define SMARTLIST_FOREACH(sl, type, var, cmd)
uint8_t purpose
Definition: circuit_st.h:112
channel_t * n_chan
Definition: circuit_st.h:70
tor_cert_t * auth_key_cert
Definition: hs_intropoint.h:22
smartlist_t * link_specifiers
Definition: hs_intropoint.h:24
channel_t * p_chan
Definition: or_circuit_st.h:37
unsigned int introduce2_dos_defense_enabled
Definition: or_circuit_st.h:95
circid_t p_circ_id
Definition: or_circuit_st.h:33
unsigned int introduce2_dos_defense_explicit
Definition: or_circuit_st.h:99
token_bucket_ctr_t introduce2_bucket
char rend_circ_nonce[DIGEST_LEN]
Definition: or_circuit_st.h:61
#define STATIC
Definition: testsupport.h:32
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, uint32_t burst, uint32_t now_ts_sec)
Definition: token_bucket.c:267
#define tor_assert(expr)
Definition: util_bug.h:103
int fast_mem_is_zero(const char *mem, size_t len)
Definition: util_string.c:76
#define ED25519_BASE64_LEN
Definition: x25519_sizes.h:43
#define ED25519_PUBKEY_LEN
Definition: x25519_sizes.h:27