hs_intropoint.c 28.6 KB
Newer Older
1
/* Copyright (c) 2016-2020, The Tor Project, Inc. */
2
3
4
5
6
7
8
9
10
/* See LICENSE for licensing information */

/**
 * \file hs_intropoint.c
 * \brief Implement next generation introductions point functionality
 **/

#define HS_INTROPOINT_PRIVATE

11
12
#include "core/or/or.h"
#include "app/config/config.h"
13
#include "core/or/channel.h"
14
15
16
17
18
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/relay.h"
#include "feature/rend/rendmid.h"
#include "feature/stats/rephist.h"
19
#include "lib/crypt_ops/crypto_format.h"
20

21
/* Trunnel */
Nick Mathewson's avatar
Nick Mathewson committed
22
23
24
25
#include "trunnel/ed25519_cert.h"
#include "trunnel/hs/cell_common.h"
#include "trunnel/hs/cell_establish_intro.h"
#include "trunnel/hs/cell_introduce1.h"
26

27
#include "feature/hs/hs_circuitmap.h"
28
#include "feature/hs/hs_common.h"
29
#include "feature/hs/hs_config.h"
30
#include "feature/hs/hs_descriptor.h"
31
#include "feature/hs/hs_dos.h"
32
#include "feature/hs/hs_intropoint.h"
33

34
#include "core/or/or_circuit_st.h"
35

36
37
38
/** Extract the authentication key from an ESTABLISH_INTRO or INTRODUCE1 using
 * the given <b>cell_type</b> from <b>cell</b> and place it in
 * <b>auth_key_out</b>. */
39
STATIC void
40
41
get_auth_key_from_cell(ed25519_public_key_t *auth_key_out,
                       unsigned int cell_type, const void *cell)
42
{
43
44
45
  size_t auth_key_len;
  const uint8_t *key_array;

46
  tor_assert(auth_key_out);
47
  tor_assert(cell);
48

49
50
51
  switch (cell_type) {
  case RELAY_COMMAND_ESTABLISH_INTRO:
  {
52
53
54
    const trn_cell_establish_intro_t *c_cell = cell;
    key_array = trn_cell_establish_intro_getconstarray_auth_key(c_cell);
    auth_key_len = trn_cell_establish_intro_getlen_auth_key(c_cell);
55
56
57
58
    break;
  }
  case RELAY_COMMAND_INTRODUCE1:
  {
59
60
61
    const trn_cell_introduce1_t *c_cell = cell;
    key_array = trn_cell_introduce1_getconstarray_auth_key(cell);
    auth_key_len = trn_cell_introduce1_getlen_auth_key(c_cell);
62
63
64
65
66
    break;
  }
  default:
    /* Getting here is really bad as it means we got a unknown cell type from
     * this file where every call has an hardcoded value. */
67
    tor_assert_unreached(); /* LCOV_EXCL_LINE */
68
  }
69
  tor_assert(key_array);
70
71
  tor_assert(auth_key_len == sizeof(auth_key_out->pubkey));
  memcpy(auth_key_out->pubkey, key_array, auth_key_len);
72
73
74
75
76
}

/** We received an ESTABLISH_INTRO <b>cell</b>. Verify its signature and MAC,
 *  given <b>circuit_key_material</b>. Return 0 on success else -1 on error. */
STATIC int
77
verify_establish_intro_cell(const trn_cell_establish_intro_t *cell,
78
                            const uint8_t *circuit_key_material,
79
80
81
                            size_t circuit_key_material_len)
{
  /* We only reach this function if the first byte of the cell is 0x02 which
82
   * means that auth_key_type is of ed25519 type, hence this check should
83
   * always pass. See hs_intro_received_establish_intro().  */
84
  if (BUG(cell->auth_key_type != TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519)) {
85
86
87
88
89
90
    return -1;
  }

  /* Make sure the auth key length is of the right size for this type. For
   * EXTRA safety, we check both the size of the array and the length which
   * must be the same. Safety first!*/
91
92
  if (trn_cell_establish_intro_getlen_auth_key(cell) != ED25519_PUBKEY_LEN ||
      trn_cell_establish_intro_get_auth_key_len(cell) != ED25519_PUBKEY_LEN) {
93
94
95
96
97
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "ESTABLISH_INTRO auth key length is invalid");
    return -1;
  }

98
  const uint8_t *msg = cell->start_cell;
99
100
101
102

  /* Verify the sig */
  {
    ed25519_signature_t sig_struct;
103
104
    const uint8_t *sig_array =
      trn_cell_establish_intro_getconstarray_sig(cell);
105

106
107
108
    /* Make sure the signature length is of the right size. For EXTRA safety,
     * we check both the size of the array and the length which must be the
     * same. Safety first!*/
109
110
    if (trn_cell_establish_intro_getlen_sig(cell) != sizeof(sig_struct.sig) ||
        trn_cell_establish_intro_get_sig_len(cell) != sizeof(sig_struct.sig)) {
111
112
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "ESTABLISH_INTRO sig len is invalid");
113
114
115
116
117
118
      return -1;
    }
    /* We are now sure that sig_len is of the right size. */
    memcpy(sig_struct.sig, sig_array, cell->sig_len);

    ed25519_public_key_t auth_key;
119
    get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO, cell);
120

121
    const size_t sig_msg_len = cell->end_sig_fields - msg;
122
    int sig_mismatch = ed25519_checksig_prefixed(&sig_struct,
123
                                                 msg, sig_msg_len,
124
125
126
                                                 ESTABLISH_INTRO_SIG_PREFIX,
                                                 &auth_key);
    if (sig_mismatch) {
127
128
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "ESTABLISH_INTRO signature not as expected");
129
130
131
132
133
134
      return -1;
    }
  }

  /* Verify the MAC */
  {
135
136
    const size_t auth_msg_len = cell->end_mac_fields - msg;
    uint8_t mac[DIGEST256_LEN];
137
    crypto_mac_sha3_256(mac, sizeof(mac),
138
139
                        circuit_key_material, circuit_key_material_len,
                        msg, auth_msg_len);
140
    if (tor_memneq(mac, cell->handshake_mac, sizeof(mac))) {
141
142
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "ESTABLISH_INTRO handshake_auth not as expected");
143
144
145
146
147
148
149
      return -1;
    }
  }

  return 0;
}

150
/** Send an INTRO_ESTABLISHED cell to <b>circ</b>. */
151
152
153
154
155
156
MOCK_IMPL(int,
hs_intro_send_intro_established_cell,(or_circuit_t *circ))
{
  int ret;
  uint8_t *encoded_cell = NULL;
  ssize_t encoded_len, result_len;
157
158
  trn_cell_intro_established_t *cell;
  trn_cell_extension_t *ext;
159
160
161
162

  tor_assert(circ);

  /* Build the cell payload. */
163
164
165
166
  cell = trn_cell_intro_established_new();
  ext = trn_cell_extension_new();
  trn_cell_extension_set_num(ext, 0);
  trn_cell_intro_established_set_extensions(cell, ext);
167
  /* Encode the cell to binary format. */
168
  encoded_len = trn_cell_intro_established_encoded_len(cell);
169
170
  tor_assert(encoded_len > 0);
  encoded_cell = tor_malloc_zero(encoded_len);
171
  result_len = trn_cell_intro_established_encode(encoded_cell, encoded_len,
172
173
174
175
176
177
178
179
                                                cell);
  tor_assert(encoded_len == result_len);

  ret = relay_send_command_from_edge(0, TO_CIRCUIT(circ),
                                     RELAY_COMMAND_INTRO_ESTABLISHED,
                                     (char *) encoded_cell, encoded_len,
                                     NULL);
  /* On failure, the above function will close the circuit. */
180
  trn_cell_intro_established_free(cell);
181
182
183
184
  tor_free(encoded_cell);
  return ret;
}

185
/** Validate the cell DoS extension parameters. Return true iff they've been
186
187
188
 * bound check and can be used. Else return false. See proposal 305 for
 * details and reasons about this validation. */
STATIC bool
189
190
cell_dos_extension_parameters_are_valid(uint64_t intro2_rate_per_sec,
                                        uint64_t intro2_burst_per_sec)
191
192
193
{
  bool ret = false;

194
195
196
197
198
199
200
  /* Check that received value is not below the minimum. Don't check if minimum
     is set to 0, since the param is a positive value and gcc will complain. */
#if HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN > 0
  if (intro2_rate_per_sec < HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN) {
    log_fn(LOG_PROTOCOL_WARN, LD_REND,
           "Intro point DoS defenses rate per second is "
           "too small. Received value: %" PRIu64, intro2_rate_per_sec);
201
202
    goto end;
  }
203
#endif /* HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN > 0 */
204

205
206
207
208
209
  /* Check that received value is not above maximum */
  if (intro2_rate_per_sec > HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX) {
    log_fn(LOG_PROTOCOL_WARN, LD_REND,
           "Intro point DoS defenses rate per second is "
           "too big. Received value: %" PRIu64, intro2_rate_per_sec);
210
211
212
    goto end;
  }

213
214
215
216
217
218
219
220
  /* Check that received value is not below the minimum */
#if HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN > 0
  if (intro2_burst_per_sec < HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN) {
    log_fn(LOG_PROTOCOL_WARN, LD_REND,
           "Intro point DoS defenses burst per second is "
           "too small. Received value: %" PRIu64, intro2_burst_per_sec);
    goto end;
  }
221
#endif /* HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN > 0 */
222
223
224
225
226
227

  /* Check that received value is not above maximum */
  if (intro2_burst_per_sec > HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX) {
    log_fn(LOG_PROTOCOL_WARN, LD_REND,
           "Intro point DoS defenses burst per second is "
           "too big. Received value: %" PRIu64, intro2_burst_per_sec);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
    goto end;
  }

  /* In a rate limiting scenario, burst can never be smaller than the rate. At
   * best it can be equal. */
  if (intro2_burst_per_sec < intro2_rate_per_sec) {
    log_info(LD_REND, "Intro point DoS defenses burst is smaller than rate. "
                      "Rate: %" PRIu64 " vs Burst: %" PRIu64,
             intro2_rate_per_sec, intro2_burst_per_sec);
    goto end;
  }

  /* Passing validation. */
  ret = true;

 end:
  return ret;
}

247
/** Parse the cell DoS extension and apply defenses on the given circuit if
248
249
 * validation passes. If the cell extension is malformed or contains unusable
 * values, the DoS defenses is disabled on the circuit. */
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
static void
handle_establish_intro_cell_dos_extension(
                                const trn_cell_extension_field_t *field,
                                or_circuit_t *circ)
{
  ssize_t ret;
  uint64_t intro2_rate_per_sec = 0, intro2_burst_per_sec = 0;
  trn_cell_extension_dos_t *dos = NULL;

  tor_assert(field);
  tor_assert(circ);

  ret = trn_cell_extension_dos_parse(&dos,
                 trn_cell_extension_field_getconstarray_field(field),
                 trn_cell_extension_field_getlen_field(field));
  if (ret < 0) {
    goto end;
  }

  for (size_t i = 0; i < trn_cell_extension_dos_get_n_params(dos); i++) {
    const trn_cell_extension_dos_param_t *param =
      trn_cell_extension_dos_getconst_params(dos, i);
    if (BUG(param == NULL)) {
      goto end;
    }

    switch (trn_cell_extension_dos_param_get_type(param)) {
    case TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC:
      intro2_rate_per_sec = trn_cell_extension_dos_param_get_value(param);
      break;
    case TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC:
      intro2_burst_per_sec = trn_cell_extension_dos_param_get_value(param);
      break;
    default:
      goto end;
    }
  }

288
289
290
291
292
  /* At this point, the extension is valid so any values out of it implies
   * that it was set explicitly and thus flag the circuit that it should not
   * look at the consensus for that reason for the defenses' values. */
  circ->introduce2_dos_defense_explicit = 1;

293
294
295
296
297
298
299
300
301
302
  /* A value of 0 is valid in the sense that we accept it but we still disable
   * the defenses so return false. */
  if (intro2_rate_per_sec == 0 || intro2_burst_per_sec == 0) {
    log_info(LD_REND, "Intro point DoS defenses parameter set to 0. "
                      "Disabling INTRO2 DoS defenses on circuit id %u",
             circ->p_circ_id);
    circ->introduce2_dos_defense_enabled = 0;
    goto end;
  }

303
  /* If invalid, we disable the defense on the circuit. */
304
305
  if (!cell_dos_extension_parameters_are_valid(intro2_rate_per_sec,
                                               intro2_burst_per_sec)) {
306
    circ->introduce2_dos_defense_enabled = 0;
307
308
309
    log_info(LD_REND, "Disabling INTRO2 DoS defenses on circuit id %u",
             circ->p_circ_id);
    goto end;
310
311
  }

312
313
314
315
316
317
318
319
320
321
322
323
  /* We passed validation, enable defenses and apply rate/burst. */
  circ->introduce2_dos_defense_enabled = 1;

  /* Initialize the INTRODUCE2 token bucket for the rate limiting. */
  token_bucket_ctr_init(&circ->introduce2_bucket,
                        (uint32_t) intro2_rate_per_sec,
                        (uint32_t) intro2_burst_per_sec,
                        (uint32_t) approx_time());
  log_info(LD_REND, "Intro point DoS defenses enabled. Rate is %" PRIu64
                    " and Burst is %" PRIu64,
           intro2_rate_per_sec, intro2_burst_per_sec);

324
325
326
327
328
 end:
  trn_cell_extension_dos_free(dos);
  return;
}

329
/** Parse every cell extension in the given ESTABLISH_INTRO cell. */
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
static void
handle_establish_intro_cell_extensions(
                            const trn_cell_establish_intro_t *parsed_cell,
                            or_circuit_t *circ)
{
  const trn_cell_extension_t *extensions;

  tor_assert(parsed_cell);
  tor_assert(circ);

  extensions = trn_cell_establish_intro_getconst_extensions(parsed_cell);
  if (extensions == NULL) {
    goto end;
  }

  /* Go over all extensions. */
  for (size_t idx = 0; idx < trn_cell_extension_get_num(extensions); idx++) {
    const trn_cell_extension_field_t *field =
      trn_cell_extension_getconst_fields(extensions, idx);
    if (BUG(field == NULL)) {
      /* The number of extensions should match the number of fields. */
      break;
    }

    switch (trn_cell_extension_field_get_field_type(field)) {
    case TRUNNEL_CELL_EXTENSION_TYPE_DOS:
      /* After this, the circuit should be set for DoS defenses. */
      handle_establish_intro_cell_dos_extension(field, circ);
      break;
    default:
      /* Unknown extension. Skip over. */
      break;
    }
  }

 end:
  return;
}

369
370
371
372
373
/** We received an ESTABLISH_INTRO <b>parsed_cell</b> on <b>circ</b>. It's
 *  well-formed and passed our verifications. Perform appropriate actions to
 *  establish an intro point. */
static int
handle_verified_establish_intro_cell(or_circuit_t *circ,
374
                               const trn_cell_establish_intro_t *parsed_cell)
375
376
377
{
  /* Get the auth key of this intro point */
  ed25519_public_key_t auth_key;
378
379
  get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
                         parsed_cell);
380

381
382
383
  /* Setup INTRODUCE2 defenses on the circuit. Must be done before parsing the
   * cell extension that can possibly change the defenses' values. */
  hs_dos_setup_default_intro2_defenses(circ);
384
385
386
387

  /* Handle cell extension if any. */
  handle_establish_intro_cell_extensions(parsed_cell, circ);

388
389
390
  /* Then notify the hidden service that the intro point is established by
     sending an INTRO_ESTABLISHED cell */
  if (hs_intro_send_intro_established_cell(circ)) {
391
    log_warn(LD_PROTOCOL, "Couldn't send INTRO_ESTABLISHED cell.");
392
393
394
395
    return -1;
  }

  /* Associate intro point auth key with this circuit. */
396
  hs_circuitmap_register_intro_circ_v3_relay_side(circ, &auth_key);
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  /* Repurpose this circuit into an intro circuit. */
  circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);

  return 0;
}

/** We just received an ESTABLISH_INTRO cell in <b>circ</b> with payload in
 *  <b>request</b>. Handle it by making <b>circ</b> an intro circuit. Return 0
 *  if everything went well, or -1 if there were errors. */
static int
handle_establish_intro(or_circuit_t *circ, const uint8_t *request,
                       size_t request_len)
{
  int cell_ok, retval = -1;
411
  trn_cell_establish_intro_t *parsed_cell = NULL;
412
413
414
415
416
417
418
419

  tor_assert(circ);
  tor_assert(request);

  log_info(LD_REND, "Received an ESTABLISH_INTRO request on circuit %" PRIu32,
           circ->p_circ_id);

  /* Check that the circuit is in shape to become an intro point */
420
  if (!hs_intro_circuit_is_suitable_for_establish_intro(circ)) {
421
422
423
424
    goto err;
  }

  /* Parse the cell */
425
  ssize_t parsing_result = trn_cell_establish_intro_parse(&parsed_cell,
426
427
                                                         request, request_len);
  if (parsing_result < 0) {
428
429
430
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Rejecting %s ESTABLISH_INTRO cell.",
           parsing_result == -1 ? "invalid" : "truncated");
431
432
433
434
    goto err;
  }

  cell_ok = verify_establish_intro_cell(parsed_cell,
435
436
                                        (uint8_t *) circ->rend_circ_nonce,
                                        sizeof(circ->rend_circ_nonce));
437
  if (cell_ok < 0) {
438
439
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Failed to verify ESTABLISH_INTRO cell.");
440
441
442
443
444
445
446
447
448
449
450
451
452
453
    goto err;
  }

  /* This cell is legit. Take the appropriate actions. */
  cell_ok = handle_verified_establish_intro_cell(circ, parsed_cell);
  if (cell_ok < 0) {
    goto err;
  }

  /* We are done! */
  retval = 0;
  goto done;

 err:
454
455
456
457
458
  /* When sending the intro establish ack, on error the circuit can be marked
   * as closed so avoid a double close. */
  if (!TO_CIRCUIT(circ)->marked_for_close) {
    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
  }
459
460

 done:
461
  trn_cell_establish_intro_free(parsed_cell);
462
463
464
  return retval;
}

465
/** Return True if circuit is suitable for being an intro circuit. */
466
467
468
static int
circuit_is_suitable_intro_point(const or_circuit_t *circ,
                                const char *log_cell_type_str)
469
{
470
471
472
  tor_assert(circ);
  tor_assert(log_cell_type_str);

473
474
  /* Basic circuit state sanity checks. */
  if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) {
475
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
476
           "Rejecting %s on non-OR circuit.", log_cell_type_str);
477
478
479
480
    return 0;
  }

  if (circ->base_.n_chan) {
481
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
482
           "Rejecting %s on non-edge circuit.", log_cell_type_str);
483
484
485
    return 0;
  }

486
  /* Suitable. */
487
488
489
  return 1;
}

490
/** Return True if circuit is suitable for being service-side intro circuit. */
491
int
492
hs_intro_circuit_is_suitable_for_establish_intro(const or_circuit_t *circ)
493
494
495
496
{
  return circuit_is_suitable_intro_point(circ, "ESTABLISH_INTRO");
}

497
/** We just received an ESTABLISH_INTRO cell in <b>circ</b>. Figure out of it's
498
499
500
501
502
503
504
505
506
 * a legacy or a next gen cell, and pass it to the appropriate handler. */
int
hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
                            size_t request_len)
{
  tor_assert(circ);
  tor_assert(request);

  if (request_len == 0) {
507
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Empty ESTABLISH_INTRO cell.");
508
509
510
511
512
513
514
    goto err;
  }

  /* Using the first byte of the cell, figure out the version of
   * ESTABLISH_INTRO and pass it to the appropriate cell handler */
  const uint8_t first_byte = request[0];
  switch (first_byte) {
515
516
    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0:
    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1:
517
      return rend_mid_establish_intro_legacy(circ, request, request_len);
518
    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519:
519
520
      return handle_establish_intro(circ, request, request_len);
    default:
521
522
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "Unrecognized AUTH_KEY_TYPE %u.", first_byte);
523
524
525
526
527
528
529
      goto err;
  }

 err:
  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
  return -1;
}
Nick Mathewson's avatar
Nick Mathewson committed
530

531
/** Send an INTRODUCE_ACK cell onto the circuit <b>circ</b> with the status
532
533
534
535
 * value in <b>status</b>. Depending on the status, it can be ACK or a NACK.
 * Return 0 on success else a negative value on error which will close the
 * circuit. */
static int
536
send_introduce_ack_cell(or_circuit_t *circ, uint16_t status)
537
538
539
540
{
  int ret = -1;
  uint8_t *encoded_cell = NULL;
  ssize_t encoded_len, result_len;
541
542
  trn_cell_introduce_ack_t *cell;
  trn_cell_extension_t *ext;
543
544
545
546
547

  tor_assert(circ);

  /* Setup the INTRODUCE_ACK cell. We have no extensions so the N_EXTENSIONS
   * field is set to 0 by default with a new object. */
548
549
  cell = trn_cell_introduce_ack_new();
  ret = trn_cell_introduce_ack_set_status(cell, status);
550
  /* We have no cell extensions in an INTRODUCE_ACK cell. */
551
552
553
  ext = trn_cell_extension_new();
  trn_cell_extension_set_num(ext, 0);
  trn_cell_introduce_ack_set_extensions(cell, ext);
554
555
556
557
558
  /* A wrong status is a very bad code flow error as this value is controlled
   * by the code in this file and not an external input. This means we use a
   * code that is not known by the trunnel ABI. */
  tor_assert(ret == 0);
  /* Encode the payload. We should never fail to get the encoded length. */
559
  encoded_len = trn_cell_introduce_ack_encoded_len(cell);
560
561
  tor_assert(encoded_len > 0);
  encoded_cell = tor_malloc_zero(encoded_len);
562
  result_len = trn_cell_introduce_ack_encode(encoded_cell, encoded_len, cell);
563
564
565
566
567
568
569
  tor_assert(encoded_len == result_len);

  ret = relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
                                     RELAY_COMMAND_INTRODUCE_ACK,
                                     (char *) encoded_cell, encoded_len,
                                     NULL);
  /* On failure, the above function will close the circuit. */
570
  trn_cell_introduce_ack_free(cell);
571
572
573
574
  tor_free(encoded_cell);
  return ret;
}

575
/** Validate a parsed INTRODUCE1 <b>cell</b>. Return 0 if valid or else a
576
 * negative value for an invalid cell that should be NACKed. */
577
STATIC int
578
validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell)
579
580
581
582
583
584
585
586
{
  size_t legacy_key_id_len;
  const uint8_t *legacy_key_id;

  tor_assert(cell);

  /* This code path SHOULD NEVER be reached if the cell is a legacy type so
   * safety net here. The legacy ID must be zeroes in this case. */
587
588
  legacy_key_id_len = trn_cell_introduce1_getlen_legacy_key_id(cell);
  legacy_key_id = trn_cell_introduce1_getconstarray_legacy_key_id(cell);
589
  if (BUG(!fast_mem_is_zero((char *) legacy_key_id, legacy_key_id_len))) {
590
591
592
593
594
    goto invalid;
  }

  /* The auth key of an INTRODUCE1 should be of type ed25519 thus leading to a
   * known fixed length as well. */
595
  if (trn_cell_introduce1_get_auth_key_type(cell) !=
596
      TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519) {
597
598
599
600
601
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Rejecting invalid INTRODUCE1 cell auth key type. "
           "Responding with NACK.");
    goto invalid;
  }
602
603
  if (trn_cell_introduce1_get_auth_key_len(cell) != ED25519_PUBKEY_LEN ||
      trn_cell_introduce1_getlen_auth_key(cell) != ED25519_PUBKEY_LEN) {
604
605
606
607
608
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Rejecting invalid INTRODUCE1 cell auth key length. "
           "Responding with NACK.");
    goto invalid;
  }
609
  if (trn_cell_introduce1_getlen_encrypted(cell) == 0) {
610
611
612
613
614
615
616
617
618
619
620
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Rejecting invalid INTRODUCE1 cell encrypted length. "
           "Responding with NACK.");
    goto invalid;
  }

  return 0;
 invalid:
  return -1;
}

621
/** We just received a non legacy INTRODUCE1 cell on <b>client_circ</b> with
622
 * the payload in <b>request</b> of size <b>request_len</b>. Return 0 if
623
 * everything went well, or -1 if an error occurred. This function is in charge
624
625
 * of sending back an INTRODUCE_ACK cell and will close client_circ on error.
 */
626
STATIC int
627
628
629
630
631
handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
                  size_t request_len)
{
  int ret = -1;
  or_circuit_t *service_circ;
632
  trn_cell_introduce1_t *parsed_cell;
633
  uint16_t status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
634
635
636
637
638
639
640

  tor_assert(client_circ);
  tor_assert(request);

  /* Parse cell. Note that we can only parse the non encrypted section for
   * which we'll use the authentication key to find the service introduction
   * circuit and relay the cell on it. */
641
  ssize_t cell_size = trn_cell_introduce1_parse(&parsed_cell, request,
642
643
644
645
646
647
                                               request_len);
  if (cell_size < 0) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Rejecting %s INTRODUCE1 cell. Responding with NACK.",
           cell_size == -1 ? "invalid" : "truncated");
    /* Inform client that the INTRODUCE1 has a bad format. */
648
    status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
649
650
651
    goto send_ack;
  }

George Kadianakis's avatar
George Kadianakis committed
652
  /* Once parsed validate the cell format. */
653
654
  if (validate_introduce1_parsed_cell(parsed_cell) < 0) {
    /* Inform client that the INTRODUCE1 has bad format. */
655
    status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
656
657
658
659
660
661
662
    goto send_ack;
  }

  /* Find introduction circuit through our circuit map. */
  {
    ed25519_public_key_t auth_key;
    get_auth_key_from_cell(&auth_key, RELAY_COMMAND_INTRODUCE1, parsed_cell);
663
    service_circ = hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
664
665
666
667
668
669
670
671
    if (service_circ == NULL) {
      char b64_key[ED25519_BASE64_LEN + 1];
      ed25519_public_to_base64(b64_key, &auth_key);
      log_info(LD_REND, "No intro circuit found for INTRODUCE1 cell "
                        "with auth key %s from circuit %" PRIu32 ". "
                        "Responding with NACK.",
               safe_str(b64_key), client_circ->p_circ_id);
      /* Inform the client that we don't know the requested service ID. */
672
      status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
673
674
675
676
      goto send_ack;
    }
  }

677
678
679
680
681
682
683
684
685
686
687
688
689
690
  /* Before sending, lets make sure this cell can be sent on the service
   * circuit asking the DoS defenses. */
  if (!hs_dos_can_send_intro2(service_circ)) {
    char *msg;
    static ratelim_t rlimit = RATELIM_INIT(5 * 60);
    if ((msg = rate_limit_log(&rlimit, approx_time()))) {
      log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v3 cell due to DoS "
                            "limitations. Sending NACK to client.");
      tor_free(msg);
    }
    status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
    goto send_ack;
  }

691
692
693
694
695
  /* Relay the cell to the service on its intro circuit with an INTRODUCE2
   * cell which is the same exact payload. */
  if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(service_circ),
                                   RELAY_COMMAND_INTRODUCE2,
                                   (char *) request, request_len, NULL)) {
696
    log_warn(LD_PROTOCOL, "Unable to send INTRODUCE2 cell to the service.");
697
698
    /* Inform the client that we can't relay the cell. Use the unknown ID
     * status code since it means that we do not know the service. */
699
    status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
700
701
702
703
    goto send_ack;
  }

  /* Success! Send an INTRODUCE_ACK success status onto the client circuit. */
704
  status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
705
706
707
  ret = 0;

 send_ack:
George Kadianakis's avatar
George Kadianakis committed
708
  /* Send INTRODUCE_ACK or INTRODUCE_NACK to client */
709
  if (send_introduce_ack_cell(client_circ, status) < 0) {
710
711
    log_warn(LD_PROTOCOL, "Unable to send an INTRODUCE ACK status %d "
                          "to client.", status);
712
713
714
715
    /* Circuit has been closed on failure of transmission. */
    goto done;
  }
 done:
716
  trn_cell_introduce1_free(parsed_cell);
717
718
719
  return ret;
}

720
/** Identify if the encoded cell we just received is a legacy one or not. The
721
 * <b>request</b> should be at least DIGEST_LEN bytes long. */
722
STATIC int
723
724
725
726
727
728
introduce1_cell_is_legacy(const uint8_t *request)
{
  tor_assert(request);

  /* If the first 20 bytes of the cell (DIGEST_LEN) are NOT zeroes, it
   * indicates a legacy cell (v2). */
729
  if (!fast_mem_is_zero((const char *) request, DIGEST_LEN)) {
730
731
732
733
734
735
736
    /* Legacy cell. */
    return 1;
  }
  /* Not a legacy cell. */
  return 0;
}

737
/** Return true iff the circuit <b>circ</b> is suitable for receiving an
738
 * INTRODUCE1 cell. */
739
STATIC int
740
741
742
743
circuit_is_suitable_for_introduce1(const or_circuit_t *circ)
{
  tor_assert(circ);

George Kadianakis's avatar
George Kadianakis committed
744
  /* Is this circuit an intro point circuit? */
745
746
747
748
749
750
751
752
753
754
755
756
  if (!circuit_is_suitable_intro_point(circ, "INTRODUCE1")) {
    return 0;
  }

  if (circ->already_received_introduce1) {
    log_fn(LOG_PROTOCOL_WARN, LD_REND,
           "Blocking multiple introductions on the same circuit. "
           "Someone might be trying to attack a hidden service through "
           "this relay.");
    return 0;
  }

757
  /* Disallow single hop client circuit. */
758
  if (circ->p_chan && channel_is_client(circ->p_chan)) {
759
760
761
762
763
764
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Single hop client was rejected while trying to introduce. "
           "Closing circuit.");
    return 0;
  }

765
766
767
  return 1;
}

768
/** We just received an INTRODUCE1 cell on <b>circ</b>. Figure out which type
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
 * it is and pass it to the appropriate handler. Return 0 on success else a
 * negative value and the circuit is closed. */
int
hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request,
                             size_t request_len)
{
  int ret;

  tor_assert(circ);
  tor_assert(request);

  /* A cell that can't hold a DIGEST_LEN is invalid as we need to check if
   * it's a legacy cell or not using the first DIGEST_LEN bytes. */
  if (request_len < DIGEST_LEN) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid INTRODUCE1 cell length.");
    goto err;
  }

  /* Make sure we have a circuit that can have an INTRODUCE1 cell on it. */
  if (!circuit_is_suitable_for_introduce1(circ)) {
    /* We do not send a NACK because the circuit is not suitable for any kind
     * of response or transmission as it's a violation of the protocol. */
    goto err;
  }
  /* Mark the circuit that we got this cell. None are allowed after this as a
   * DoS mitigation since one circuit with one client can hammer a service. */
  circ->already_received_introduce1 = 1;

  /* We are sure here to have at least DIGEST_LEN bytes. */
  if (introduce1_cell_is_legacy(request)) {
    /* Handle a legacy cell. */
800
    ret = rend_mid_introduce_legacy(circ, request, request_len);
801
802
803
804
805
806
807
808
809
810
  } else {
    /* Handle a non legacy cell. */
    ret = handle_introduce1(circ, request, request_len);
  }
  return ret;

 err:
  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
  return -1;
}
Nick Mathewson's avatar
Nick Mathewson committed
811

812
813
/** Clear memory allocated by the given intropoint object ip (but don't free
 * the object itself). */
814
void
815
hs_intropoint_clear(hs_intropoint_t *ip)
816
817
818
819
820
{
  if (ip == NULL) {
    return;
  }
  tor_cert_free(ip->auth_key_cert);
teor's avatar
teor committed
821
822
  SMARTLIST_FOREACH(ip->link_specifiers, link_specifier_t *, ls,
                    link_specifier_free(ls));
823
  smartlist_free(ip->link_specifiers);
824
  memset(ip, 0, sizeof(hs_intropoint_t));
825
}