Line data Source code
1 : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file hs_circuit.c
6 : **/
7 :
8 : #define HS_CIRCUIT_PRIVATE
9 :
10 : #include "core/or/or.h"
11 : #include "app/config/config.h"
12 : #include "core/crypto/hs_ntor.h"
13 : #include "core/or/circuitbuild.h"
14 : #include "core/or/circuitlist.h"
15 : #include "core/or/circuituse.h"
16 : #include "core/or/policies.h"
17 : #include "core/or/relay.h"
18 : #include "core/or/crypt_path.h"
19 : #include "core/or/extendinfo.h"
20 : #include "feature/client/circpathbias.h"
21 : #include "feature/hs/hs_cell.h"
22 : #include "feature/hs/hs_circuit.h"
23 : #include "feature/hs/hs_ob.h"
24 : #include "feature/hs/hs_circuitmap.h"
25 : #include "feature/hs/hs_client.h"
26 : #include "feature/hs/hs_ident.h"
27 : #include "feature/hs/hs_metrics.h"
28 : #include "feature/hs/hs_service.h"
29 : #include "feature/nodelist/describe.h"
30 : #include "feature/nodelist/nodelist.h"
31 : #include "feature/stats/rephist.h"
32 : #include "lib/crypt_ops/crypto_dh.h"
33 : #include "lib/crypt_ops/crypto_rand.h"
34 : #include "lib/crypt_ops/crypto_util.h"
35 :
36 : /* Trunnel. */
37 : #include "trunnel/ed25519_cert.h"
38 : #include "trunnel/hs/cell_common.h"
39 : #include "trunnel/hs/cell_establish_intro.h"
40 :
41 : #include "core/or/cpath_build_state_st.h"
42 : #include "core/or/crypt_path_st.h"
43 : #include "feature/nodelist/node_st.h"
44 : #include "core/or/origin_circuit_st.h"
45 :
46 : /** A circuit is about to become an e2e rendezvous circuit. Check
47 : * <b>circ_purpose</b> and ensure that it's properly set. Return true iff
48 : * circuit purpose is properly set, otherwise return false. */
49 : static int
50 5 : circuit_purpose_is_correct_for_rend(unsigned int circ_purpose,
51 : int is_service_side)
52 : {
53 5 : if (is_service_side) {
54 3 : if (circ_purpose != CIRCUIT_PURPOSE_S_CONNECT_REND) {
55 0 : log_warn(LD_BUG,
56 : "HS e2e circuit setup with wrong purpose (%d)", circ_purpose);
57 0 : return 0;
58 : }
59 : }
60 :
61 5 : if (!is_service_side) {
62 2 : if (circ_purpose != CIRCUIT_PURPOSE_C_REND_READY &&
63 : circ_purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) {
64 0 : log_warn(LD_BUG,
65 : "Client e2e circuit setup with wrong purpose (%d)", circ_purpose);
66 0 : return 0;
67 : }
68 : }
69 :
70 : return 1;
71 : }
72 :
73 : /** Create and return a crypt path for the final hop of a v3 prop224 rendezvous
74 : * circuit. Initialize the crypt path crypto using the output material from the
75 : * ntor key exchange at <b>ntor_key_seed</b>.
76 : *
77 : * If <b>is_service_side</b> is set, we are the hidden service and the final
78 : * hop of the rendezvous circuit is the client on the other side. */
79 : static crypt_path_t *
80 5 : create_rend_cpath(const uint8_t *ntor_key_seed, size_t seed_len,
81 : int is_service_side)
82 : {
83 5 : uint8_t keys[HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN];
84 5 : crypt_path_t *cpath = NULL;
85 :
86 : /* Do the key expansion */
87 5 : if (hs_ntor_circuit_key_expansion(ntor_key_seed, seed_len,
88 : keys, sizeof(keys)) < 0) {
89 0 : goto err;
90 : }
91 :
92 : /* Setup the cpath */
93 5 : cpath = tor_malloc_zero(sizeof(crypt_path_t));
94 5 : cpath->magic = CRYPT_PATH_MAGIC;
95 :
96 5 : if (cpath_init_circuit_crypto(cpath, (char*)keys, sizeof(keys),
97 : is_service_side, 1) < 0) {
98 0 : tor_free(cpath);
99 0 : goto err;
100 : }
101 :
102 5 : err:
103 5 : memwipe(keys, 0, sizeof(keys));
104 5 : return cpath;
105 : }
106 :
107 : /** Append the final <b>hop</b> to the cpath of the rend <b>circ</b>, and mark
108 : * <b>circ</b> ready for use to transfer HS relay cells. */
109 : static void
110 5 : finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
111 : int is_service_side)
112 : {
113 5 : tor_assert(circ);
114 5 : tor_assert(hop);
115 :
116 : /* Notify the circuit state machine that we are splicing this circuit */
117 10 : int new_circ_purpose = is_service_side ?
118 5 : CIRCUIT_PURPOSE_S_REND_JOINED : CIRCUIT_PURPOSE_C_REND_JOINED;
119 5 : circuit_change_purpose(TO_CIRCUIT(circ), new_circ_purpose);
120 :
121 : /* All is well. Extend the circuit. */
122 5 : hop->state = CPATH_STATE_OPEN;
123 : /* Set the windows to default. */
124 5 : hop->package_window = circuit_initial_package_window();
125 5 : hop->deliver_window = CIRCWINDOW_START;
126 :
127 : /* Now that this circuit has finished connecting to its destination,
128 : * make sure circuit_get_open_circ_or_launch is willing to return it
129 : * so we can actually use it. */
130 5 : circ->hs_circ_has_timed_out = 0;
131 :
132 : /* Append the hop to the cpath of this circuit */
133 5 : cpath_extend_linked_list(&circ->cpath, hop);
134 :
135 : /* Finally, mark circuit as ready to be used for client streams */
136 5 : if (!is_service_side) {
137 2 : circuit_try_attaching_streams(circ);
138 : }
139 5 : }
140 :
141 : /** For a given circuit and a service introduction point object, register the
142 : * intro circuit to the circuitmap. */
143 : static void
144 0 : register_intro_circ(const hs_service_intro_point_t *ip,
145 : origin_circuit_t *circ)
146 : {
147 0 : tor_assert(ip);
148 0 : tor_assert(circ);
149 :
150 0 : hs_circuitmap_register_intro_circ_v3_service_side(circ,
151 0 : &ip->auth_key_kp.pubkey);
152 0 : }
153 :
154 : /** Return the number of opened introduction circuit for the given circuit that
155 : * is matching its identity key. */
156 : static unsigned int
157 1 : count_opened_desc_intro_point_circuits(const hs_service_t *service,
158 : const hs_service_descriptor_t *desc)
159 : {
160 1 : unsigned int count = 0;
161 :
162 1 : tor_assert(service);
163 1 : tor_assert(desc);
164 :
165 2 : DIGEST256MAP_FOREACH(desc->intro_points.map, key,
166 : const hs_service_intro_point_t *, ip) {
167 1 : const circuit_t *circ;
168 1 : const origin_circuit_t *ocirc = hs_circ_service_get_intro_circ(ip);
169 1 : if (ocirc == NULL) {
170 1 : continue;
171 : }
172 0 : circ = TO_CIRCUIT(ocirc);
173 0 : tor_assert(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
174 : circ->purpose == CIRCUIT_PURPOSE_S_INTRO);
175 : /* Having a circuit not for the requested service is really bad. */
176 0 : tor_assert(ed25519_pubkey_eq(&service->keys.identity_pk,
177 : ô->hs_ident->identity_pk));
178 : /* Only count opened circuit and skip circuit that will be closed. */
179 0 : if (!circ->marked_for_close && circ->state == CIRCUIT_STATE_OPEN) {
180 0 : count++;
181 : }
182 1 : } DIGEST256MAP_FOREACH_END;
183 1 : return count;
184 : }
185 :
186 : /** From a given service, rendezvous cookie and handshake info, create a
187 : * rendezvous point circuit identifier. This can't fail. */
188 : STATIC hs_ident_circuit_t *
189 1 : create_rp_circuit_identifier(const hs_service_t *service,
190 : const uint8_t *rendezvous_cookie,
191 : const curve25519_public_key_t *server_pk,
192 : const hs_ntor_rend_cell_keys_t *keys)
193 : {
194 1 : hs_ident_circuit_t *ident;
195 1 : uint8_t handshake_info[CURVE25519_PUBKEY_LEN + DIGEST256_LEN];
196 :
197 1 : tor_assert(service);
198 1 : tor_assert(rendezvous_cookie);
199 1 : tor_assert(server_pk);
200 1 : tor_assert(keys);
201 :
202 1 : ident = hs_ident_circuit_new(&service->keys.identity_pk);
203 : /* Copy the RENDEZVOUS_COOKIE which is the unique identifier. */
204 1 : memcpy(ident->rendezvous_cookie, rendezvous_cookie,
205 : sizeof(ident->rendezvous_cookie));
206 : /* Build the HANDSHAKE_INFO which looks like this:
207 : * SERVER_PK [32 bytes]
208 : * AUTH_INPUT_MAC [32 bytes]
209 : */
210 1 : memcpy(handshake_info, server_pk->public_key, CURVE25519_PUBKEY_LEN);
211 1 : memcpy(handshake_info + CURVE25519_PUBKEY_LEN, keys->rend_cell_auth_mac,
212 : DIGEST256_LEN);
213 1 : tor_assert(sizeof(ident->rendezvous_handshake_info) ==
214 : sizeof(handshake_info));
215 1 : memcpy(ident->rendezvous_handshake_info, handshake_info,
216 : sizeof(ident->rendezvous_handshake_info));
217 : /* Finally copy the NTOR_KEY_SEED for e2e encryption on the circuit. */
218 1 : tor_assert(sizeof(ident->rendezvous_ntor_key_seed) ==
219 : sizeof(keys->ntor_key_seed));
220 1 : memcpy(ident->rendezvous_ntor_key_seed, keys->ntor_key_seed,
221 : sizeof(ident->rendezvous_ntor_key_seed));
222 1 : return ident;
223 : }
224 :
225 : /** From a given service and service intro point, create an introduction point
226 : * circuit identifier. This can't fail. */
227 : static hs_ident_circuit_t *
228 0 : create_intro_circuit_identifier(const hs_service_t *service,
229 : const hs_service_intro_point_t *ip)
230 : {
231 0 : hs_ident_circuit_t *ident;
232 :
233 0 : tor_assert(service);
234 0 : tor_assert(ip);
235 :
236 0 : ident = hs_ident_circuit_new(&service->keys.identity_pk);
237 0 : ed25519_pubkey_copy(&ident->intro_auth_pk, &ip->auth_key_kp.pubkey);
238 :
239 0 : return ident;
240 : }
241 :
242 : /** For a given introduction point and an introduction circuit, send the
243 : * ESTABLISH_INTRO cell. The service object is used for logging. This can fail
244 : * and if so, the circuit is closed and the intro point object is flagged
245 : * that the circuit is not established anymore which is important for the
246 : * retry mechanism. */
247 : static void
248 1 : send_establish_intro(const hs_service_t *service,
249 : hs_service_intro_point_t *ip, origin_circuit_t *circ)
250 : {
251 1 : ssize_t cell_len;
252 1 : uint8_t payload[RELAY_PAYLOAD_SIZE];
253 :
254 1 : tor_assert(service);
255 1 : tor_assert(ip);
256 1 : tor_assert(circ);
257 :
258 : /* Encode establish intro cell. */
259 1 : cell_len = hs_cell_build_establish_intro(circ->cpath->prev->rend_circ_nonce,
260 : &service->config, ip, payload);
261 1 : if (cell_len < 0) {
262 0 : log_warn(LD_REND, "Unable to encode ESTABLISH_INTRO cell for service %s "
263 : "on circuit %u. Closing circuit.",
264 : safe_str_client(service->onion_address),
265 : TO_CIRCUIT(circ)->n_circ_id);
266 0 : goto err;
267 : }
268 :
269 : /* Send the cell on the circuit. */
270 1 : if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
271 : RELAY_COMMAND_ESTABLISH_INTRO,
272 : (char *) payload, cell_len,
273 : circ->cpath->prev) < 0) {
274 0 : log_info(LD_REND, "Unable to send ESTABLISH_INTRO cell for service %s "
275 : "on circuit %u.",
276 : safe_str_client(service->onion_address),
277 : TO_CIRCUIT(circ)->n_circ_id);
278 : /* On error, the circuit has been closed. */
279 0 : goto done;
280 : }
281 :
282 : /* Record the attempt to use this circuit. */
283 1 : pathbias_count_use_attempt(circ);
284 1 : goto done;
285 :
286 0 : err:
287 0 : circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
288 1 : done:
289 1 : memwipe(payload, 0, sizeof(payload));
290 1 : }
291 :
292 : /** Return a string constant describing the anonymity of service. */
293 : static const char *
294 0 : get_service_anonymity_string(const hs_service_t *service)
295 : {
296 0 : if (service->config.is_single_onion) {
297 : return "single onion";
298 : } else {
299 0 : return "hidden";
300 : }
301 : }
302 :
303 : /** For a given service, the ntor onion key and a rendezvous cookie, launch a
304 : * circuit to the rendezvous point specified by the link specifiers. On
305 : * success, a circuit identifier is attached to the circuit with the needed
306 : * data. This function will try to open a circuit for a maximum value of
307 : * MAX_REND_FAILURES then it will give up. */
308 0 : MOCK_IMPL(STATIC void,
309 : launch_rendezvous_point_circuit,(const hs_service_t *service,
310 : const hs_service_intro_point_t *ip,
311 : const hs_cell_introduce2_data_t *data))
312 : {
313 0 : int circ_needs_uptime;
314 0 : time_t now = time(NULL);
315 0 : extend_info_t *info = NULL;
316 0 : origin_circuit_t *circ;
317 :
318 0 : tor_assert(service);
319 0 : tor_assert(ip);
320 0 : tor_assert(data);
321 :
322 0 : circ_needs_uptime = hs_service_requires_uptime_circ(service->config.ports);
323 :
324 : /* Get the extend info data structure for the chosen rendezvous point
325 : * specified by the given link specifiers. */
326 0 : info = hs_get_extend_info_from_lspecs(data->link_specifiers,
327 0 : &data->onion_pk,
328 0 : service->config.is_single_onion);
329 0 : if (info == NULL) {
330 : /* We are done here, we can't extend to the rendezvous point. */
331 0 : log_fn(LOG_PROTOCOL_WARN, LD_REND,
332 : "Not enough info to open a circuit to a rendezvous point for "
333 : "%s service %s.",
334 : get_service_anonymity_string(service),
335 : safe_str_client(service->onion_address));
336 0 : goto end;
337 : }
338 :
339 0 : for (int i = 0; i < MAX_REND_FAILURES; i++) {
340 0 : int circ_flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL;
341 0 : if (circ_needs_uptime) {
342 0 : circ_flags |= CIRCLAUNCH_NEED_UPTIME;
343 : }
344 : /* Firewall and policies are checked when getting the extend info.
345 : *
346 : * We only use a one-hop path on the first attempt. If the first attempt
347 : * fails, we use a 3-hop path for reachability / reliability.
348 : * See the comment in retry_service_rendezvous_point() for details. */
349 0 : if (service->config.is_single_onion && i == 0) {
350 0 : circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL;
351 : }
352 :
353 0 : circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, info,
354 : circ_flags);
355 0 : if (circ != NULL) {
356 : /* Stop retrying, we have a circuit! */
357 : break;
358 : }
359 : }
360 0 : if (circ == NULL) {
361 0 : log_warn(LD_REND, "Giving up on launching a rendezvous circuit to %s "
362 : "for %s service %s",
363 : safe_str_client(extend_info_describe(info)),
364 : get_service_anonymity_string(service),
365 : safe_str_client(service->onion_address));
366 0 : goto end;
367 : }
368 : /* Update metrics with this new rendezvous circuit launched. */
369 0 : hs_metrics_new_rdv(&service->keys.identity_pk);
370 :
371 0 : log_info(LD_REND, "Rendezvous circuit launched to %s with cookie %s "
372 : "for %s service %s",
373 : safe_str_client(extend_info_describe(info)),
374 : safe_str_client(hex_str((const char *) data->rendezvous_cookie,
375 : REND_COOKIE_LEN)),
376 : get_service_anonymity_string(service),
377 : safe_str_client(service->onion_address));
378 0 : tor_assert(circ->build_state);
379 : /* Rendezvous circuit have a specific timeout for the time spent on trying
380 : * to connect to the rendezvous point. */
381 0 : circ->build_state->expiry_time = now + MAX_REND_TIMEOUT;
382 :
383 : /* Create circuit identifier and key material. */
384 : {
385 0 : hs_ntor_rend_cell_keys_t keys;
386 0 : curve25519_keypair_t ephemeral_kp;
387 : /* No need for extra strong, this is only for this circuit life time. This
388 : * key will be used for the RENDEZVOUS1 cell that will be sent on the
389 : * circuit once opened. */
390 0 : curve25519_keypair_generate(&ephemeral_kp, 0);
391 0 : if (hs_ntor_service_get_rendezvous1_keys(&ip->auth_key_kp.pubkey,
392 0 : &ip->enc_key_kp,
393 0 : &ephemeral_kp, &data->client_pk,
394 : &keys) < 0) {
395 : /* This should not really happened but just in case, don't make tor
396 : * freak out, close the circuit and move on. */
397 0 : log_info(LD_REND, "Unable to get RENDEZVOUS1 key material for "
398 : "service %s",
399 : safe_str_client(service->onion_address));
400 0 : circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
401 0 : goto end;
402 : }
403 0 : circ->hs_ident = create_rp_circuit_identifier(service,
404 : data->rendezvous_cookie,
405 : &ephemeral_kp.pubkey, &keys);
406 0 : memwipe(&ephemeral_kp, 0, sizeof(ephemeral_kp));
407 0 : memwipe(&keys, 0, sizeof(keys));
408 0 : tor_assert(circ->hs_ident);
409 : }
410 :
411 0 : end:
412 0 : extend_info_free(info);
413 0 : }
414 :
415 : /** Return true iff the given service rendezvous circuit circ is allowed for a
416 : * relaunch to the rendezvous point. */
417 : static int
418 0 : can_relaunch_service_rendezvous_point(const origin_circuit_t *circ)
419 : {
420 0 : tor_assert(circ);
421 : /* This is initialized when allocating an origin circuit. */
422 0 : tor_assert(circ->build_state);
423 0 : tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
424 :
425 : /* XXX: Retrying under certain condition. This is related to #22455. */
426 :
427 : /* Avoid to relaunch twice a circuit to the same rendezvous point at the
428 : * same time. */
429 0 : if (circ->hs_service_side_rend_circ_has_been_relaunched) {
430 0 : log_info(LD_REND, "Rendezvous circuit to %s has already been retried. "
431 : "Skipping retry.",
432 : safe_str_client(
433 : extend_info_describe(circ->build_state->chosen_exit)));
434 0 : goto disallow;
435 : }
436 :
437 : /* We check failure_count >= hs_get_service_max_rend_failures()-1 below, and
438 : * the -1 is because we increment the failure count for our current failure
439 : * *after* this clause. */
440 0 : int max_rend_failures = hs_get_service_max_rend_failures() - 1;
441 :
442 : /* A failure count that has reached maximum allowed or circuit that expired,
443 : * we skip relaunching. */
444 0 : if (circ->build_state->failure_count > max_rend_failures ||
445 0 : circ->build_state->expiry_time <= time(NULL)) {
446 0 : log_info(LD_REND, "Attempt to build a rendezvous circuit to %s has "
447 : "failed with %d attempts and expiry time %ld. "
448 : "Giving up building.",
449 : safe_str_client(
450 : extend_info_describe(circ->build_state->chosen_exit)),
451 : circ->build_state->failure_count,
452 : (long int) circ->build_state->expiry_time);
453 0 : goto disallow;
454 : }
455 :
456 : /* Allowed to relaunch. */
457 : return 1;
458 : disallow:
459 : return 0;
460 : }
461 :
462 : /** Retry the rendezvous point of circ by launching a new circuit to it. */
463 : static void
464 0 : retry_service_rendezvous_point(const origin_circuit_t *circ)
465 : {
466 0 : int flags = 0;
467 0 : origin_circuit_t *new_circ;
468 0 : cpath_build_state_t *bstate;
469 :
470 0 : tor_assert(circ);
471 : /* This is initialized when allocating an origin circuit. */
472 0 : tor_assert(circ->build_state);
473 0 : tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
474 :
475 : /* Ease our life. */
476 0 : bstate = circ->build_state;
477 :
478 0 : log_info(LD_REND, "Retrying rendezvous point circuit to %s",
479 : safe_str_client(extend_info_describe(bstate->chosen_exit)));
480 :
481 : /* Get the current build state flags for the next circuit. */
482 0 : flags |= (bstate->need_uptime) ? CIRCLAUNCH_NEED_UPTIME : 0;
483 0 : flags |= (bstate->need_capacity) ? CIRCLAUNCH_NEED_CAPACITY : 0;
484 0 : flags |= (bstate->is_internal) ? CIRCLAUNCH_IS_INTERNAL : 0;
485 :
486 : /* We do NOT add the onehop tunnel flag even though it might be a single
487 : * onion service. The reason is that if we failed once to connect to the RP
488 : * with a direct connection, we consider that chances are that we will fail
489 : * again so try a 3-hop circuit and hope for the best. Because the service
490 : * has no anonymity (single onion), this change of behavior won't affect
491 : * security directly. */
492 :
493 0 : new_circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND,
494 : bstate->chosen_exit, flags);
495 0 : if (new_circ == NULL) {
496 0 : log_warn(LD_REND, "Failed to launch rendezvous circuit to %s",
497 : safe_str_client(extend_info_describe(bstate->chosen_exit)));
498 0 : goto done;
499 : }
500 :
501 : /* Transfer build state information to the new circuit state in part to
502 : * catch any other failures. */
503 0 : new_circ->build_state->failure_count = bstate->failure_count+1;
504 0 : new_circ->build_state->expiry_time = bstate->expiry_time;
505 0 : new_circ->hs_ident = hs_ident_circuit_dup(circ->hs_ident);
506 :
507 0 : done:
508 0 : return;
509 : }
510 :
511 : /** Using the given descriptor intro point ip, the node of the
512 : * rendezvous point rp_node and the service's subcredential, populate the
513 : * already allocated intro1_data object with the needed key material and link
514 : * specifiers.
515 : *
516 : * Return 0 on success or a negative value if we couldn't properly filled the
517 : * introduce1 data from the RP node. In other word, it means the RP node is
518 : * unusable to use in the introduction. */
519 : static int
520 4 : setup_introduce1_data(const hs_desc_intro_point_t *ip,
521 : const node_t *rp_node,
522 : const hs_subcredential_t *subcredential,
523 : hs_cell_introduce1_data_t *intro1_data)
524 : {
525 4 : int ret = -1;
526 4 : smartlist_t *rp_lspecs;
527 :
528 4 : tor_assert(ip);
529 4 : tor_assert(rp_node);
530 4 : tor_assert(subcredential);
531 4 : tor_assert(intro1_data);
532 :
533 : /* Build the link specifiers from the node at the end of the rendezvous
534 : * circuit that we opened for this introduction. */
535 4 : rp_lspecs = node_get_link_specifier_smartlist(rp_node, 0);
536 4 : if (smartlist_len(rp_lspecs) == 0) {
537 : /* We can't rendezvous without link specifiers. */
538 0 : smartlist_free(rp_lspecs);
539 0 : goto end;
540 : }
541 :
542 : /* Populate the introduce1 data object. */
543 4 : memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
544 4 : intro1_data->auth_pk = &ip->auth_key_cert->signed_key;
545 4 : intro1_data->enc_pk = &ip->enc_key;
546 4 : intro1_data->subcredential = subcredential;
547 4 : intro1_data->link_specifiers = rp_lspecs;
548 4 : intro1_data->onion_pk = node_get_curve25519_onion_key(rp_node);
549 4 : if (intro1_data->onion_pk == NULL) {
550 : /* We can't rendezvous without the curve25519 onion key. */
551 0 : goto end;
552 : }
553 : /* Success, we have valid introduce data. */
554 : ret = 0;
555 :
556 4 : end:
557 4 : return ret;
558 : }
559 :
560 : /** Helper: cleanup function for client circuit. This is for every HS version.
561 : * It is called from hs_circ_cleanup_on_close() entry point. */
562 : static void
563 5 : cleanup_on_close_client_circ(circuit_t *circ)
564 : {
565 5 : tor_assert(circ);
566 :
567 5 : if (circuit_is_hs_v3(circ)) {
568 5 : hs_client_circuit_cleanup_on_close(circ);
569 : }
570 : /* It is possible the circuit has an HS purpose but no identifier (hs_ident).
571 : * Thus possible that this passes through. */
572 5 : }
573 :
574 : /** Helper: cleanup function for client circuit. This is for every HS version.
575 : * It is called from hs_circ_cleanup_on_free() entry point. */
576 : static void
577 11 : cleanup_on_free_client_circ(circuit_t *circ)
578 : {
579 11 : tor_assert(circ);
580 :
581 11 : if (circuit_is_hs_v3(circ)) {
582 9 : hs_client_circuit_cleanup_on_free(circ);
583 : }
584 : /* It is possible the circuit has an HS purpose but no identifier (hs_ident).
585 : * Thus possible that this passes through. */
586 11 : }
587 :
588 : /* ========== */
589 : /* Public API */
590 : /* ========== */
591 :
592 : /** Return an introduction point circuit matching the given intro point object.
593 : * NULL is returned is no such circuit can be found. */
594 : origin_circuit_t *
595 9 : hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip)
596 : {
597 9 : tor_assert(ip);
598 :
599 9 : return hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
600 : }
601 :
602 : /** Return an introduction point established circuit matching the given intro
603 : * point object. The circuit purpose has to be CIRCUIT_PURPOSE_S_INTRO. NULL
604 : * is returned is no such circuit can be found. */
605 : origin_circuit_t *
606 0 : hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip)
607 : {
608 0 : origin_circuit_t *circ;
609 :
610 0 : tor_assert(ip);
611 :
612 0 : circ = hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
613 :
614 : /* Only return circuit if it is established. */
615 0 : return (circ && TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO) ?
616 0 : circ : NULL;
617 : }
618 :
619 : /** Called when we fail building a rendezvous circuit at some point other than
620 : * the last hop: launches a new circuit to the same rendezvous point.
621 : *
622 : * We currently relaunch connections to rendezvous points if:
623 : * - A rendezvous circuit timed out before connecting to RP.
624 : * - The rendezvous circuit failed to connect to the RP.
625 : *
626 : * We avoid relaunching a connection to this rendezvous point if:
627 : * - We have already tried MAX_REND_FAILURES times to connect to this RP,
628 : * - We've been trying to connect to this RP for more than MAX_REND_TIMEOUT
629 : * seconds, or
630 : * - We've already retried this specific rendezvous circuit.
631 : */
632 : void
633 0 : hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ)
634 : {
635 0 : tor_assert(circ);
636 0 : tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
637 :
638 : /* Check if we are allowed to relaunch to the rendezvous point of circ. */
639 0 : if (!can_relaunch_service_rendezvous_point(circ)) {
640 0 : goto done;
641 : }
642 :
643 : /* Flag the circuit that we are relaunching, to avoid to relaunch twice a
644 : * circuit to the same rendezvous point at the same time. */
645 0 : circ->hs_service_side_rend_circ_has_been_relaunched = 1;
646 :
647 : /* Legacy services don't have a hidden service ident. */
648 0 : if (circ->hs_ident) {
649 0 : retry_service_rendezvous_point(circ);
650 : }
651 :
652 0 : done:
653 0 : return;
654 : }
655 :
656 : /** For a given service and a service intro point, launch a circuit to the
657 : * extend info ei. If the service is a single onion, and direct_conn is true,
658 : * a one-hop circuit will be requested.
659 : *
660 : * Return 0 if the circuit was successfully launched and tagged
661 : * with the correct identifier. On error, a negative value is returned. */
662 : int
663 0 : hs_circ_launch_intro_point(hs_service_t *service,
664 : const hs_service_intro_point_t *ip,
665 : extend_info_t *ei,
666 : bool direct_conn)
667 : {
668 : /* Standard flags for introduction circuit. */
669 0 : int ret = -1, circ_flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
670 0 : origin_circuit_t *circ;
671 :
672 0 : tor_assert(service);
673 0 : tor_assert(ip);
674 0 : tor_assert(ei);
675 :
676 : /* Update circuit flags in case of a single onion service that requires a
677 : * direct connection. */
678 0 : tor_assert_nonfatal(ip->circuit_retries > 0);
679 : /* Only single onion services can make direct conns */
680 0 : if (BUG(!service->config.is_single_onion && direct_conn)) {
681 0 : goto end;
682 : }
683 : /* We only use a one-hop path on the first attempt. If the first attempt
684 : * fails, we use a 3-hop path for reachability / reliability. */
685 0 : if (direct_conn && ip->circuit_retries == 1) {
686 0 : circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL;
687 : }
688 :
689 0 : log_info(LD_REND, "Launching a circuit to intro point %s for service %s.",
690 : safe_str_client(extend_info_describe(ei)),
691 : safe_str_client(service->onion_address));
692 :
693 : /* Note down the launch for the retry period. Even if the circuit fails to
694 : * be launched, we still want to respect the retry period to avoid stress on
695 : * the circuit subsystem. */
696 0 : service->state.num_intro_circ_launched++;
697 0 : circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO,
698 : ei, circ_flags);
699 0 : if (circ == NULL) {
700 0 : goto end;
701 : }
702 :
703 : /* Setup the circuit identifier and attach it to it. */
704 0 : circ->hs_ident = create_intro_circuit_identifier(service, ip);
705 0 : tor_assert(circ->hs_ident);
706 : /* Register circuit in the global circuitmap. */
707 0 : register_intro_circ(ip, circ);
708 :
709 : /* Success. */
710 0 : ret = 0;
711 0 : end:
712 0 : return ret;
713 : }
714 :
715 : /** Called when a service introduction point circuit is done building. Given
716 : * the service and intro point object, this function will send the
717 : * ESTABLISH_INTRO cell on the circuit. Return 0 on success. Return 1 if the
718 : * circuit has been repurposed to General because we already have too many
719 : * opened. */
720 : int
721 1 : hs_circ_service_intro_has_opened(hs_service_t *service,
722 : hs_service_intro_point_t *ip,
723 : const hs_service_descriptor_t *desc,
724 : origin_circuit_t *circ)
725 : {
726 1 : int ret = 0;
727 1 : unsigned int num_intro_circ, num_needed_circ;
728 :
729 1 : tor_assert(service);
730 1 : tor_assert(ip);
731 1 : tor_assert(desc);
732 1 : tor_assert(circ);
733 :
734 : /* Count opened circuits that have sent ESTABLISH_INTRO cells or are already
735 : * established introduction circuits */
736 1 : num_intro_circ = count_opened_desc_intro_point_circuits(service, desc);
737 1 : num_needed_circ = service->config.num_intro_points;
738 1 : if (num_intro_circ > num_needed_circ) {
739 : /* There are too many opened valid intro circuit for what the service
740 : * needs so repurpose this one. */
741 :
742 : /* XXX: Legacy code checks options->ExcludeNodes and if not NULL it just
743 : * closes the circuit. I have NO idea why it does that so it hasn't been
744 : * added here. I can only assume in case our ExcludeNodes list changes but
745 : * in that case, all circuit are flagged unusable (config.c). --dgoulet */
746 :
747 0 : log_info(LD_CIRC | LD_REND, "Introduction circuit just opened but we "
748 : "have enough for service %s. Repurposing "
749 : "it to general and leaving internal.",
750 : safe_str_client(service->onion_address));
751 0 : tor_assert(circ->build_state->is_internal);
752 : /* Remove it from the circuitmap. */
753 0 : hs_circuitmap_remove_circuit(TO_CIRCUIT(circ));
754 : /* Cleaning up the hidden service identifier and repurpose. */
755 0 : hs_ident_circuit_free(circ->hs_ident);
756 0 : circ->hs_ident = NULL;
757 0 : if (circuit_should_use_vanguards(TO_CIRCUIT(circ)->purpose))
758 0 : circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_HS_VANGUARDS);
759 : else
760 0 : circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_GENERAL);
761 :
762 : /* Inform that this circuit just opened for this new purpose. */
763 0 : circuit_has_opened(circ);
764 : /* This return value indicate to the caller that the IP object should be
765 : * removed from the service because it's corresponding circuit has just
766 : * been repurposed. */
767 0 : ret = 1;
768 0 : goto done;
769 : }
770 :
771 1 : log_info(LD_REND, "Introduction circuit %u established for service %s.",
772 : TO_CIRCUIT(circ)->n_circ_id,
773 : safe_str_client(service->onion_address));
774 1 : circuit_log_path(LOG_INFO, LD_REND, circ);
775 :
776 : /* Time to send an ESTABLISH_INTRO cell on this circuit. On error, this call
777 : * makes sure the circuit gets closed. */
778 1 : send_establish_intro(service, ip, circ);
779 :
780 1 : done:
781 1 : return ret;
782 : }
783 :
784 : /** Called when a service rendezvous point circuit is done building. Given the
785 : * service and the circuit, this function will send a RENDEZVOUS1 cell on the
786 : * circuit using the information in the circuit identifier. If the cell can't
787 : * be sent, the circuit is closed. */
788 : void
789 2 : hs_circ_service_rp_has_opened(const hs_service_t *service,
790 : origin_circuit_t *circ)
791 : {
792 2 : size_t payload_len;
793 2 : uint8_t payload[RELAY_PAYLOAD_SIZE] = {0};
794 :
795 2 : tor_assert(service);
796 2 : tor_assert(circ);
797 2 : tor_assert(circ->hs_ident);
798 :
799 : /* Some useful logging. */
800 2 : log_info(LD_REND, "Rendezvous circuit %u has opened with cookie %s "
801 : "for service %s",
802 : TO_CIRCUIT(circ)->n_circ_id,
803 : hex_str((const char *) circ->hs_ident->rendezvous_cookie,
804 : REND_COOKIE_LEN),
805 : safe_str_client(service->onion_address));
806 2 : circuit_log_path(LOG_INFO, LD_REND, circ);
807 :
808 : /* This can't fail. */
809 4 : payload_len = hs_cell_build_rendezvous1(
810 2 : circ->hs_ident->rendezvous_cookie,
811 : sizeof(circ->hs_ident->rendezvous_cookie),
812 2 : circ->hs_ident->rendezvous_handshake_info,
813 : sizeof(circ->hs_ident->rendezvous_handshake_info),
814 : payload);
815 :
816 : /* Pad the payload with random bytes so it matches the size of a legacy cell
817 : * which is normally always bigger. Also, the size of a legacy cell is
818 : * always smaller than the RELAY_PAYLOAD_SIZE so this is safe. */
819 2 : if (payload_len < HS_LEGACY_RENDEZVOUS_CELL_SIZE) {
820 2 : crypto_rand((char *) payload + payload_len,
821 : HS_LEGACY_RENDEZVOUS_CELL_SIZE - payload_len);
822 2 : payload_len = HS_LEGACY_RENDEZVOUS_CELL_SIZE;
823 : }
824 :
825 2 : if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
826 : RELAY_COMMAND_RENDEZVOUS1,
827 : (const char *) payload, payload_len,
828 : circ->cpath->prev) < 0) {
829 : /* On error, circuit is closed. */
830 0 : log_warn(LD_REND, "Unable to send RENDEZVOUS1 cell on circuit %u "
831 : "for service %s",
832 : TO_CIRCUIT(circ)->n_circ_id,
833 : safe_str_client(service->onion_address));
834 0 : goto done;
835 : }
836 :
837 : /* Setup end-to-end rendezvous circuit between the client and us. */
838 2 : if (hs_circuit_setup_e2e_rend_circ(circ,
839 2 : circ->hs_ident->rendezvous_ntor_key_seed,
840 : sizeof(circ->hs_ident->rendezvous_ntor_key_seed),
841 : 1) < 0) {
842 0 : log_warn(LD_GENERAL, "Failed to setup circ");
843 0 : goto done;
844 : }
845 :
846 2 : done:
847 2 : memwipe(payload, 0, sizeof(payload));
848 2 : }
849 :
850 : /** Circ has been expecting an INTRO_ESTABLISHED cell that just arrived. Handle
851 : * the INTRO_ESTABLISHED cell payload of length payload_len arriving on the
852 : * given introduction circuit circ. The service is only used for logging
853 : * purposes. Return 0 on success else a negative value. */
854 : int
855 1 : hs_circ_handle_intro_established(const hs_service_t *service,
856 : const hs_service_intro_point_t *ip,
857 : origin_circuit_t *circ,
858 : const uint8_t *payload, size_t payload_len)
859 : {
860 1 : int ret = -1;
861 :
862 1 : tor_assert(service);
863 1 : tor_assert(ip);
864 1 : tor_assert(circ);
865 1 : tor_assert(payload);
866 :
867 1 : if (BUG(TO_CIRCUIT(circ)->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)) {
868 0 : goto done;
869 : }
870 :
871 : /* Try to parse the payload into a cell making sure we do actually have a
872 : * valid cell. */
873 1 : if (hs_cell_parse_intro_established(payload, payload_len) < 0) {
874 0 : log_warn(LD_REND, "Unable to parse the INTRO_ESTABLISHED cell on "
875 : "circuit %u for service %s",
876 : TO_CIRCUIT(circ)->n_circ_id,
877 : safe_str_client(service->onion_address));
878 0 : goto done;
879 : }
880 :
881 : /* Switch the purpose to a fully working intro point. */
882 1 : circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_S_INTRO);
883 : /* Getting a valid INTRODUCE_ESTABLISHED means we've successfully used the
884 : * circuit so update our pathbias subsystem. */
885 1 : pathbias_mark_use_success(circ);
886 : /* Success. */
887 1 : ret = 0;
888 :
889 1 : done:
890 1 : return ret;
891 : }
892 :
893 : /**
894 : * Go into <b>data</b> and add the right subcredential to be able to handle
895 : * this incoming cell.
896 : *
897 : * <b>desc_subcred</b> is the subcredential of the descriptor that corresponds
898 : * to the intro point that received this intro request. This subcredential
899 : * should be used if we are not an onionbalance instance.
900 : *
901 : * Return 0 if everything went well, or -1 in case of internal error.
902 : */
903 : static int
904 8 : get_subcredential_for_handling_intro2_cell(const hs_service_t *service,
905 : hs_cell_introduce2_data_t *data,
906 : const hs_subcredential_t *desc_subcred)
907 : {
908 : /* Handle the simple case first: We are not an onionbalance instance and we
909 : * should just use the regular descriptor subcredential */
910 8 : if (!hs_ob_service_is_instance(service)) {
911 2 : data->n_subcredentials = 1;
912 2 : data->subcredentials = desc_subcred;
913 2 : return 0;
914 : }
915 :
916 : /* This should not happen since we should have made onionbalance
917 : * subcredentials when we created our descriptors. */
918 6 : if (BUG(!service->state.ob_subcreds)) {
919 0 : return -1;
920 : }
921 :
922 : /* We are an onionbalance instance: */
923 6 : data->n_subcredentials = service->state.n_ob_subcreds;
924 6 : data->subcredentials = service->state.ob_subcreds;
925 :
926 6 : return 0;
927 : }
928 :
929 : /** We just received an INTRODUCE2 cell on the established introduction circuit
930 : * circ. Handle the INTRODUCE2 payload of size payload_len for the given
931 : * circuit and service. This cell is associated with the intro point object ip
932 : * and the subcredential. Return 0 on success else a negative value. */
933 : int
934 8 : hs_circ_handle_introduce2(const hs_service_t *service,
935 : const origin_circuit_t *circ,
936 : hs_service_intro_point_t *ip,
937 : const hs_subcredential_t *subcredential,
938 : const uint8_t *payload, size_t payload_len)
939 : {
940 8 : int ret = -1;
941 8 : time_t elapsed;
942 8 : hs_cell_introduce2_data_t data;
943 :
944 8 : tor_assert(service);
945 8 : tor_assert(circ);
946 8 : tor_assert(ip);
947 8 : tor_assert(subcredential);
948 8 : tor_assert(payload);
949 :
950 : /* Populate the data structure with everything we need for the cell to be
951 : * parsed, decrypted and key material computed correctly. */
952 8 : data.auth_pk = &ip->auth_key_kp.pubkey;
953 8 : data.enc_kp = &ip->enc_key_kp;
954 8 : data.payload = payload;
955 8 : data.payload_len = payload_len;
956 8 : data.link_specifiers = smartlist_new();
957 8 : data.replay_cache = ip->replay_cache;
958 :
959 8 : if (get_subcredential_for_handling_intro2_cell(service,
960 : &data, subcredential)) {
961 0 : goto done;
962 : }
963 :
964 8 : if (hs_cell_parse_introduce2(&data, circ, service) < 0) {
965 3 : goto done;
966 : }
967 :
968 : /* Check whether we've seen this REND_COOKIE before to detect repeats. */
969 5 : if (replaycache_add_test_and_elapsed(
970 5 : service->state.replay_cache_rend_cookie,
971 : data.rendezvous_cookie, sizeof(data.rendezvous_cookie),
972 : &elapsed)) {
973 : /* A Tor client will send a new INTRODUCE1 cell with the same REND_COOKIE
974 : * as its previous one if its intro circ times out while in state
975 : * CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT. If we received the first
976 : * INTRODUCE1 cell (the intro-point relay converts it into an INTRODUCE2
977 : * cell), we are already trying to connect to that rend point (and may
978 : * have already succeeded); drop this cell. */
979 1 : log_info(LD_REND, "We received an INTRODUCE2 cell with same REND_COOKIE "
980 : "field %ld seconds ago. Dropping cell.",
981 : (long int) elapsed);
982 1 : goto done;
983 : }
984 :
985 : /* At this point, we just confirmed that the full INTRODUCE2 cell is valid
986 : * so increment our counter that we've seen one on this intro point. */
987 4 : ip->introduce2_count++;
988 :
989 : /* Launch rendezvous circuit with the onion key and rend cookie. */
990 4 : launch_rendezvous_point_circuit(service, ip, &data);
991 : /* Success. */
992 4 : ret = 0;
993 :
994 8 : done:
995 8 : link_specifier_smartlist_free(data.link_specifiers);
996 8 : memwipe(&data, 0, sizeof(data));
997 8 : return ret;
998 : }
999 :
1000 : /** Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key
1001 : * exchange output material at <b>ntor_key_seed</b> and setup <b>circ</b> to
1002 : * serve as a rendezvous end-to-end circuit between the client and the
1003 : * service. If <b>is_service_side</b> is set, then we are the hidden service
1004 : * and the other side is the client.
1005 : *
1006 : * Return 0 if the operation went well; in case of error return -1. */
1007 : int
1008 5 : hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
1009 : const uint8_t *ntor_key_seed, size_t seed_len,
1010 : int is_service_side)
1011 : {
1012 5 : if (BUG(!circuit_purpose_is_correct_for_rend(TO_CIRCUIT(circ)->purpose,
1013 : is_service_side))) {
1014 0 : return -1;
1015 : }
1016 :
1017 5 : crypt_path_t *hop = create_rend_cpath(ntor_key_seed, seed_len,
1018 : is_service_side);
1019 5 : if (!hop) {
1020 0 : log_warn(LD_REND, "Couldn't get v3 %s cpath!",
1021 : is_service_side ? "service-side" : "client-side");
1022 0 : return -1;
1023 : }
1024 :
1025 5 : finalize_rend_circuit(circ, hop, is_service_side);
1026 :
1027 5 : return 0;
1028 : }
1029 :
1030 : /** Given the introduction circuit intro_circ, the rendezvous circuit
1031 : * rend_circ, a descriptor intro point object ip and the service's
1032 : * subcredential, send an INTRODUCE1 cell on intro_circ.
1033 : *
1034 : * This will also setup the circuit identifier on rend_circ containing the key
1035 : * material for the handshake and e2e encryption. Return 0 on success else
1036 : * negative value. Because relay_send_command_from_edge() closes the circuit
1037 : * on error, it is possible that intro_circ is closed on error. */
1038 : int
1039 4 : hs_circ_send_introduce1(origin_circuit_t *intro_circ,
1040 : origin_circuit_t *rend_circ,
1041 : const hs_desc_intro_point_t *ip,
1042 : const hs_subcredential_t *subcredential)
1043 : {
1044 4 : int ret = -1;
1045 4 : ssize_t payload_len;
1046 4 : uint8_t payload[RELAY_PAYLOAD_SIZE] = {0};
1047 4 : hs_cell_introduce1_data_t intro1_data;
1048 :
1049 4 : tor_assert(intro_circ);
1050 4 : tor_assert(rend_circ);
1051 4 : tor_assert(ip);
1052 4 : tor_assert(subcredential);
1053 :
1054 : /* It is undefined behavior in hs_cell_introduce1_data_clear() if intro1_data
1055 : * has been declared on the stack but not initialized. Here, we set it to 0.
1056 : */
1057 4 : memset(&intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
1058 :
1059 : /* This takes various objects in order to populate the introduce1 data
1060 : * object which is used to build the content of the cell. */
1061 4 : const node_t *exit_node = build_state_get_exit_node(rend_circ->build_state);
1062 4 : if (exit_node == NULL) {
1063 0 : log_info(LD_REND, "Unable to get rendezvous point for circuit %u. "
1064 : "Failing.", TO_CIRCUIT(intro_circ)->n_circ_id);
1065 0 : goto done;
1066 : }
1067 :
1068 : /* We should never select an invalid rendezvous point in theory but if we
1069 : * do, this function will fail to populate the introduce data. */
1070 4 : if (setup_introduce1_data(ip, exit_node, subcredential, &intro1_data) < 0) {
1071 0 : log_info(LD_REND, "Unable to setup INTRODUCE1 data. The chosen rendezvous "
1072 : "point is unusable. Closing circuit.");
1073 0 : goto close;
1074 : }
1075 :
1076 : /* Final step before we encode a cell, we setup the circuit identifier which
1077 : * will generate both the rendezvous cookie and client keypair for this
1078 : * connection. Those are put in the ident. */
1079 4 : intro1_data.rendezvous_cookie = rend_circ->hs_ident->rendezvous_cookie;
1080 4 : intro1_data.client_kp = &rend_circ->hs_ident->rendezvous_client_kp;
1081 :
1082 4 : memcpy(intro_circ->hs_ident->rendezvous_cookie,
1083 : rend_circ->hs_ident->rendezvous_cookie,
1084 : sizeof(intro_circ->hs_ident->rendezvous_cookie));
1085 :
1086 : /* From the introduce1 data object, this will encode the INTRODUCE1 cell
1087 : * into payload which is then ready to be sent as is. */
1088 4 : payload_len = hs_cell_build_introduce1(&intro1_data, payload);
1089 4 : if (BUG(payload_len < 0)) {
1090 0 : goto close;
1091 : }
1092 :
1093 4 : if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(intro_circ),
1094 : RELAY_COMMAND_INTRODUCE1,
1095 : (const char *) payload, payload_len,
1096 : intro_circ->cpath->prev) < 0) {
1097 : /* On error, circuit is closed. */
1098 0 : log_warn(LD_REND, "Unable to send INTRODUCE1 cell on circuit %u.",
1099 : TO_CIRCUIT(intro_circ)->n_circ_id);
1100 0 : goto done;
1101 : }
1102 :
1103 : /* Success. */
1104 4 : ret = 0;
1105 4 : goto done;
1106 :
1107 0 : close:
1108 0 : circuit_mark_for_close(TO_CIRCUIT(rend_circ), END_CIRC_REASON_INTERNAL);
1109 4 : done:
1110 4 : hs_cell_introduce1_data_clear(&intro1_data);
1111 4 : memwipe(payload, 0, sizeof(payload));
1112 4 : return ret;
1113 : }
1114 :
1115 : /** Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On
1116 : * success, 0 is returned else -1 and the circuit is marked for close. */
1117 : int
1118 0 : hs_circ_send_establish_rendezvous(origin_circuit_t *circ)
1119 : {
1120 0 : ssize_t cell_len = 0;
1121 0 : uint8_t cell[RELAY_PAYLOAD_SIZE] = {0};
1122 :
1123 0 : tor_assert(circ);
1124 0 : tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
1125 :
1126 0 : log_info(LD_REND, "Send an ESTABLISH_RENDEZVOUS cell on circuit %u",
1127 : TO_CIRCUIT(circ)->n_circ_id);
1128 :
1129 : /* Set timestamp_dirty, because circuit_expire_building expects it,
1130 : * and the rend cookie also means we've used the circ. */
1131 0 : TO_CIRCUIT(circ)->timestamp_dirty = time(NULL);
1132 :
1133 : /* We've attempted to use this circuit. Probe it if we fail */
1134 0 : pathbias_count_use_attempt(circ);
1135 :
1136 : /* Generate the RENDEZVOUS_COOKIE and place it in the identifier so we can
1137 : * complete the handshake when receiving the acknowledgement. */
1138 0 : crypto_rand((char *) circ->hs_ident->rendezvous_cookie, HS_REND_COOKIE_LEN);
1139 : /* Generate the client keypair. No need to be extra strong, not long term */
1140 0 : curve25519_keypair_generate(&circ->hs_ident->rendezvous_client_kp, 0);
1141 :
1142 0 : cell_len =
1143 0 : hs_cell_build_establish_rendezvous(circ->hs_ident->rendezvous_cookie,
1144 : cell);
1145 0 : if (BUG(cell_len < 0)) {
1146 0 : goto err;
1147 : }
1148 :
1149 0 : if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
1150 : RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
1151 : (const char *) cell, cell_len,
1152 : circ->cpath->prev) < 0) {
1153 : /* Circuit has been marked for close */
1154 0 : log_warn(LD_REND, "Unable to send ESTABLISH_RENDEZVOUS cell on "
1155 : "circuit %u", TO_CIRCUIT(circ)->n_circ_id);
1156 0 : memwipe(cell, 0, cell_len);
1157 0 : goto err;
1158 : }
1159 :
1160 0 : memwipe(cell, 0, cell_len);
1161 0 : return 0;
1162 : err:
1163 : return -1;
1164 : }
1165 :
1166 : /** Circuit cleanup strategy:
1167 : *
1168 : * What follows is a series of functions that notifies the HS subsystem of 3
1169 : * different circuit cleanup phase: close, free and repurpose.
1170 : *
1171 : * Tor can call any of those in any orders so they have to be safe between
1172 : * each other. In other words, the free should never depend on close to be
1173 : * called before.
1174 : *
1175 : * The "on_close()" is called from circuit_mark_for_close() which is
1176 : * considered the tor fast path and thus as little work as possible should
1177 : * done in that function. Currently, we only remove the circuit from the HS
1178 : * circuit map and move on.
1179 : *
1180 : * The "on_free()" is called from circuit circuit_free_() and it is very
1181 : * important that at the end of the function, no state or objects related to
1182 : * this circuit remains alive.
1183 : *
1184 : * The "on_repurpose()" is called from circuit_change_purpose() for which we
1185 : * simply remove it from the HS circuit map. We do not have other cleanup
1186 : * requirements after that.
1187 : *
1188 : * NOTE: The onion service code, specifically the service code, cleans up
1189 : * lingering objects or state if any of its circuit disappear which is why
1190 : * our cleanup strategy doesn't involve any service specific actions. As long
1191 : * as the circuit is removed from the HS circuit map, it won't be used.
1192 : */
1193 :
1194 : /** We are about to close this <b>circ</b>. Clean it up from any related HS
1195 : * data structures. This function can be called multiple times safely for the
1196 : * same circuit. */
1197 : void
1198 25 : hs_circ_cleanup_on_close(circuit_t *circ)
1199 : {
1200 25 : tor_assert(circ);
1201 :
1202 25 : if (circuit_purpose_is_hs_client(circ->purpose)) {
1203 5 : cleanup_on_close_client_circ(circ);
1204 : }
1205 :
1206 25 : if (circuit_purpose_is_hs_service(circ->purpose)) {
1207 2 : if (circuit_is_hs_v3(circ)) {
1208 1 : hs_service_circuit_cleanup_on_close(circ);
1209 : }
1210 : }
1211 :
1212 : /* On close, we simply remove it from the circuit map. It can not be used
1213 : * anymore. We keep this code path fast and lean. */
1214 :
1215 25 : if (circ->hs_token) {
1216 2 : hs_circuitmap_remove_circuit(circ);
1217 : }
1218 25 : }
1219 :
1220 : /** We are about to free this <b>circ</b>. Clean it up from any related HS
1221 : * data structures. This function can be called multiple times safely for the
1222 : * same circuit. */
1223 : void
1224 151 : hs_circ_cleanup_on_free(circuit_t *circ)
1225 : {
1226 151 : tor_assert(circ);
1227 :
1228 : /* NOTE: Bulk of the work of cleaning up a circuit is done here. */
1229 :
1230 151 : if (circuit_purpose_is_hs_client(circ->purpose)) {
1231 11 : cleanup_on_free_client_circ(circ);
1232 : }
1233 :
1234 : /* We have no assurance that the given HS circuit has been closed before and
1235 : * thus removed from the HS map. This actually happens in unit tests. */
1236 151 : if (circ->hs_token) {
1237 13 : hs_circuitmap_remove_circuit(circ);
1238 : }
1239 151 : }
1240 :
1241 : /** We are about to repurpose this <b>circ</b>. Clean it up from any related
1242 : * HS data structures. This function can be called multiple times safely for
1243 : * the same circuit. */
1244 : void
1245 0 : hs_circ_cleanup_on_repurpose(circuit_t *circ)
1246 : {
1247 0 : tor_assert(circ);
1248 :
1249 : /* On repurpose, we simply remove it from the circuit map but we do not do
1250 : * the on_free actions since we don't treat a repurpose as something we need
1251 : * to report in the client cache failure. */
1252 :
1253 0 : if (circ->hs_token) {
1254 0 : hs_circuitmap_remove_circuit(circ);
1255 : }
1256 0 : }
1257 :
1258 : /** Return true iff the given established client rendezvous circuit was sent
1259 : * into the INTRODUCE1 cell. This is called so we can take a decision on
1260 : * expiring or not the circuit.
1261 : *
1262 : * The caller MUST make sure the circuit is an established client rendezvous
1263 : * circuit (purpose: CIRCUIT_PURPOSE_C_REND_READY).
1264 : *
1265 : * This function supports all onion service versions. */
1266 : bool
1267 0 : hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ)
1268 : {
1269 0 : tor_assert(circ);
1270 : /* This can only be called for a rendezvous circuit that is an established
1271 : * confirmed rendezsvous circuit but without an introduction ACK. */
1272 0 : tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_REND_READY);
1273 :
1274 : /* When the INTRODUCE1 cell is sent, the introduction encryption public
1275 : * key is copied in the rendezvous circuit hs identifier. If it is a valid
1276 : * key, we know that this circuit is waiting the ACK on the introduction
1277 : * circuit. We want to _not_ spare the circuit if the key was never set. */
1278 :
1279 0 : if (circ->hs_ident) {
1280 : /* v3. */
1281 0 : if (curve25519_public_key_is_ok(&circ->hs_ident->intro_enc_pk)) {
1282 0 : return true;
1283 : }
1284 : } else {
1285 : /* A circuit with an HS purpose without an hs_ident in theory can not
1286 : * happen. In case, scream loudly and return false to the caller that the
1287 : * rendezvous was not sent in the INTRO1 cell. */
1288 0 : tor_assert_nonfatal_unreached();
1289 : }
1290 :
1291 : /* The rendezvous has not been specified in the INTRODUCE1 cell. */
1292 : return false;
1293 : }
|