tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

relay_msg.c (7637B)


      1 /* Copyright (c) 2023, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file relay_msg.c
      6 * \brief Encoding relay messages into cells.
      7 **/
      8 
      9 #define RELAY_MSG_PRIVATE
     10 
     11 #include "app/config/config.h"
     12 
     13 #include "core/or/cell_st.h"
     14 #include "core/or/circuitlist.h"
     15 #include "core/or/relay.h"
     16 #include "core/or/relay_msg.h"
     17 #include "lib/crypt_ops/crypto_rand.h"
     18 
     19 #include "core/or/cell_st.h"
     20 #include "core/or/relay_msg_st.h"
     21 #include "core/or/crypt_path_st.h"
     22 #include "core/or/or_circuit_st.h"
     23 
     24 /*
     25 * Public API
     26 */
     27 
     28 /** Free the given relay message. */
     29 void
     30 relay_msg_free_(relay_msg_t *msg)
     31 {
     32  if (!msg) {
     33    return;
     34  }
     35  tor_free(msg);
     36 }
     37 
     38 /** Clear a relay message as in free its content and reset all fields to 0.
     39 * This is useful for stack allocated memory. */
     40 void
     41 relay_msg_clear(relay_msg_t *msg)
     42 {
     43  tor_assert(msg);
     44  memset(msg, 0, sizeof(*msg));
     45 }
     46 
     47 /* Positions of fields within a v0 message. */
     48 #define V0_CMD_OFFSET 0
     49 #define V0_STREAM_ID_OFFSET 3
     50 #define V0_LEN_OFFSET 9
     51 #define V0_PAYLOAD_OFFSET 11
     52 
     53 /* Positions of fields within a v1 message. */
     54 #define V1_CMD_OFFSET 16
     55 #define V1_LEN_OFFSET 17
     56 #define V1_STREAM_ID_OFFSET 19
     57 #define V1_PAYLOAD_OFFSET_NO_STREAM_ID 19
     58 #define V1_PAYLOAD_OFFSET_WITH_STREAM_ID 21
     59 
     60 /** Allocate a new relay message and copy the content of the given message.
     61 *
     62 * This message allocation _will_ own its body, even if the original did not.
     63 *
     64 * Requires that msg is well-formed, and that its length is within
     65 * allowable bounds.
     66 **/
     67 relay_msg_t *
     68 relay_msg_copy(const relay_msg_t *msg)
     69 {
     70  tor_assert(msg->length <= RELAY_PAYLOAD_SIZE_MAX);
     71  void *alloc = tor_malloc_zero(sizeof(relay_msg_t) + msg->length);
     72  relay_msg_t *new_msg = alloc;
     73  uint8_t *body = ((uint8_t*)alloc) + sizeof(relay_msg_t);
     74 
     75  memcpy(new_msg, msg, sizeof(*msg));
     76  new_msg->body = body;
     77  memcpy(body, msg->body, msg->length);
     78 
     79  return new_msg;
     80 }
     81 
     82 /* Add random bytes to the unused portion of the payload, to foil attacks
     83 * where the other side can predict all of the bytes in the payload and thus
     84 * compute the authenticated SENDME cells without seeing the traffic. See
     85 * proposal 289. */
     86 static void
     87 relay_cell_pad(cell_t *cell, size_t end_of_message)
     88 {
     89  // We add 4 bytes of zero before padding, for forward-compatibility.
     90  const size_t skip = 4;
     91 
     92  if (end_of_message + skip >= CELL_PAYLOAD_SIZE) {
     93    /* nothing to do. */
     94    return;
     95  }
     96 
     97  crypto_fast_rng_getbytes(get_thread_fast_rng(),
     98                           &cell->payload[end_of_message + skip],
     99                           CELL_PAYLOAD_SIZE - (end_of_message + skip));
    100 }
    101 
    102 /** Encode the relay message in 'msg' into cell, according to the
    103 * v0 rules. */
    104 static int
    105 encode_v0_cell(const relay_msg_t *msg,
    106               cell_t *cell_out)
    107 {
    108  size_t maxlen =
    109    relay_cell_max_payload_size(RELAY_CELL_FORMAT_V0, msg->command);
    110  IF_BUG_ONCE(msg->length > maxlen) {
    111    return -1;
    112  }
    113 
    114  uint8_t *out = cell_out->payload;
    115 
    116  out[V0_CMD_OFFSET] = (uint8_t) msg->command;
    117  set_uint16(out+V0_STREAM_ID_OFFSET, htons(msg->stream_id));
    118  set_uint16(out+V0_LEN_OFFSET, htons(msg->length));
    119  memcpy(out + RELAY_HEADER_SIZE_V0, msg->body, msg->length);
    120  relay_cell_pad(cell_out, RELAY_HEADER_SIZE_V0 + msg->length);
    121 
    122  return 0;
    123 }
    124 
    125 /** Encode the relay message in 'msg' into cell, according to the
    126 * v0 rules. */
    127 static int
    128 encode_v1_cell(const relay_msg_t *msg,
    129               cell_t *cell_out)
    130 {
    131  bool expects_streamid = relay_cmd_expects_streamid_in_v1(msg->command);
    132  size_t maxlen =
    133    relay_cell_max_payload_size(RELAY_CELL_FORMAT_V1, msg->command);
    134  IF_BUG_ONCE(msg->length > maxlen) {
    135    return -1;
    136  }
    137 
    138  uint8_t *out = cell_out->payload;
    139  out[V1_CMD_OFFSET] = msg->command;
    140  set_uint16(out+V1_LEN_OFFSET, htons(msg->length));
    141  size_t payload_offset;
    142  if (expects_streamid) {
    143    IF_BUG_ONCE(msg->stream_id == 0) {
    144      return -1;
    145    }
    146    set_uint16(out+V1_STREAM_ID_OFFSET, htons(msg->stream_id));
    147    payload_offset = V1_PAYLOAD_OFFSET_WITH_STREAM_ID;
    148  } else {
    149    IF_BUG_ONCE(msg->stream_id != 0) {
    150      return -1;
    151    }
    152 
    153    payload_offset = V1_PAYLOAD_OFFSET_NO_STREAM_ID;
    154  }
    155 
    156  memcpy(out + payload_offset, msg->body, msg->length);
    157  relay_cell_pad(cell_out, payload_offset + msg->length);
    158  return 0;
    159 }
    160 
    161 /** Try to decode 'cell' into a V0 relay message.
    162 *
    163 * Return 0 on success, -1 on error.
    164 */
    165 static int
    166 decode_v0_cell(const cell_t *cell, relay_msg_t *out)
    167 {
    168  memset(out, 0, sizeof(relay_msg_t));
    169  out->is_relay_early = (cell->command == CELL_RELAY_EARLY);
    170 
    171  const uint8_t *body = cell->payload;
    172  out->command = get_uint8(body + V0_CMD_OFFSET);
    173  out->stream_id = ntohs(get_uint16(body + V0_STREAM_ID_OFFSET));
    174  out->length = ntohs(get_uint16(body + V0_LEN_OFFSET));
    175 
    176  if (out->length > CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0) {
    177    return -1;
    178  }
    179  out->body = body + V0_PAYLOAD_OFFSET;
    180 
    181  return 0;
    182 }
    183 
    184 /** Try to decode 'cell' into a V1 relay message.
    185 *
    186 * Return 0 on success, -1 on error.=
    187 */
    188 static int
    189 decode_v1_cell(const cell_t *cell, relay_msg_t *out)
    190 {
    191  memset(out, 0, sizeof(relay_msg_t));
    192  out->is_relay_early = (cell->command == CELL_RELAY_EARLY);
    193 
    194  const uint8_t *body = cell->payload;
    195  out->command = get_uint8(body + V1_CMD_OFFSET);
    196  if (! is_known_relay_command(out->command))
    197    return -1;
    198 
    199  out->length = ntohs(get_uint16(body + V1_LEN_OFFSET));
    200  size_t payload_offset;
    201  if (relay_cmd_expects_streamid_in_v1(out->command)) {
    202    out->stream_id = ntohs(get_uint16(body + V1_STREAM_ID_OFFSET));
    203    payload_offset = V1_PAYLOAD_OFFSET_WITH_STREAM_ID;
    204  } else {
    205    payload_offset = V1_PAYLOAD_OFFSET_NO_STREAM_ID;
    206  }
    207 
    208  if (out->length > CELL_PAYLOAD_SIZE - payload_offset)
    209    return -1;
    210  out->body = body + payload_offset;
    211 
    212  return 0;
    213 }
    214 /**
    215 * Encode 'msg' into 'cell' according to the rules of 'format'.
    216 *
    217 * Does not set any "recognized", "digest" or "tag" fields,
    218 * since those are necessarily part of the crypto logic.
    219 *
    220 * Clears the circuit ID on the cell.
    221 *
    222 * Return 0 on success, and -1 if 'msg' is not well-formed.
    223 */
    224 int
    225 relay_msg_encode_cell(relay_cell_fmt_t format,
    226                      const relay_msg_t *msg,
    227                      cell_t *cell_out)
    228 {
    229  memset(cell_out, 0, sizeof(cell_t));
    230  cell_out->command = msg->is_relay_early ?
    231    CELL_RELAY_EARLY : CELL_RELAY;
    232 
    233  switch (format) {
    234    case RELAY_CELL_FORMAT_V0:
    235      return encode_v0_cell(msg, cell_out);
    236    case RELAY_CELL_FORMAT_V1:
    237      return encode_v1_cell(msg, cell_out);
    238    default:
    239      tor_fragile_assert();
    240      return -1;
    241  }
    242 }
    243 
    244 /**
    245 * Decode 'cell' (which must be RELAY or RELAY_EARLY) into a newly allocated
    246 * 'relay_msg_t'.
    247 *
    248 * Note that the resulting relay_msg_t will have a reference to 'cell'.
    249 * Do not change 'cell' while the resulting message is still in use!
    250 *
    251 * Return -1 on error, and 0 on success.
    252 */
    253 int
    254 relay_msg_decode_cell_in_place(relay_cell_fmt_t format,
    255                               const cell_t *cell,
    256                               relay_msg_t *msg_out)
    257 {
    258  switch (format) {
    259    case RELAY_CELL_FORMAT_V0:
    260      return decode_v0_cell(cell, msg_out);
    261    case RELAY_CELL_FORMAT_V1:
    262      return decode_v1_cell(cell, msg_out);
    263    default:
    264      tor_fragile_assert();
    265      return -1;
    266  }
    267 }
    268 
    269 /**
    270 * As relay_msg_decode_cell_in_place, but allocate a new relay_msg_t
    271 * on success.
    272 *
    273 * Return NULL on error.
    274 */
    275 relay_msg_t *
    276 relay_msg_decode_cell(relay_cell_fmt_t format,
    277                      const cell_t *cell)
    278 {
    279  relay_msg_t *msg = tor_malloc(sizeof(relay_msg_t));
    280  if (relay_msg_decode_cell_in_place(format, cell, msg) < 0) {
    281    relay_msg_free(msg);
    282    return NULL;
    283  } else {
    284    return msg;
    285  }
    286 }