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 }