Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2018 The TokTok team. |
3 | | * Copyright © 2013 Tox project. |
4 | | */ |
5 | | |
6 | | /** |
7 | | * Implementation of the onion part of docs/Prevent_Tracking.txt |
8 | | */ |
9 | | #include "onion.h" |
10 | | |
11 | | #include <assert.h> |
12 | | #include <string.h> |
13 | | |
14 | | #include "DHT.h" |
15 | | #include "ccompat.h" |
16 | | #include "crypto_core.h" |
17 | | #include "logger.h" |
18 | | #include "mem.h" |
19 | | #include "mono_time.h" |
20 | | #include "network.h" |
21 | | #include "shared_key_cache.h" |
22 | | #include "util.h" |
23 | | |
24 | 812k | #define RETURN_1 ONION_RETURN_1 |
25 | 942k | #define RETURN_2 ONION_RETURN_2 |
26 | 669k | #define RETURN_3 ONION_RETURN_3 |
27 | | |
28 | 383k | #define SEND_BASE ONION_SEND_BASE |
29 | 68.9k | #define SEND_3 ONION_SEND_3 |
30 | 70.9k | #define SEND_2 ONION_SEND_2 |
31 | 149k | #define SEND_1 ONION_SEND_1 |
32 | | |
33 | 411k | #define KEY_REFRESH_INTERVAL (2 * 60 * 60) |
34 | | |
35 | | |
36 | | // Settings for the shared key cache |
37 | 11.4k | #define MAX_KEYS_PER_SLOT 4 |
38 | 11.4k | #define KEYS_TIMEOUT 600 |
39 | | |
40 | | /** Change symmetric keys every 2 hours to make paths expire eventually. */ |
41 | | non_null() |
42 | | static void change_symmetric_key(Onion *onion) |
43 | 411k | { |
44 | 411k | if (mono_time_is_timeout(onion->mono_time, onion->timestamp, KEY_REFRESH_INTERVAL)) { |
45 | 0 | new_symmetric_key(onion->rng, onion->secret_symmetric_key); |
46 | 0 | onion->timestamp = mono_time_get(onion->mono_time); |
47 | 0 | } |
48 | 411k | } |
49 | | |
50 | | /** packing and unpacking functions */ |
51 | | non_null() |
52 | | static void ip_pack_to_bytes(uint8_t *data, const IP *source) |
53 | 445k | { |
54 | 445k | data[0] = source->family.value; |
55 | | |
56 | 445k | if (net_family_is_ipv4(source->family) || net_family_is_tox_tcp_ipv4(source->family)) { |
57 | 444k | memzero(data + 1, SIZE_IP6); |
58 | 444k | memcpy(data + 1, source->ip.v4.uint8, SIZE_IP4); |
59 | 444k | } else { |
60 | 1.00k | memcpy(data + 1, source->ip.v6.uint8, SIZE_IP6); |
61 | 1.00k | } |
62 | 445k | } |
63 | | |
64 | | /** return 0 on success, -1 on failure. */ |
65 | | non_null() |
66 | | static int ip_unpack_from_bytes(IP *target, const uint8_t *data, unsigned int data_size, bool disable_family_check) |
67 | 411k | { |
68 | 411k | if (data_size < (1 + SIZE_IP6)) { |
69 | 0 | return -1; |
70 | 0 | } |
71 | | |
72 | | // TODO(iphydf): Validate input. |
73 | 411k | target->family.value = data[0]; |
74 | | |
75 | 411k | if (net_family_is_ipv4(target->family) || net_family_is_tox_tcp_ipv4(target->family)) { |
76 | 410k | memcpy(target->ip.v4.uint8, data + 1, SIZE_IP4); |
77 | 410k | } else { |
78 | 845 | memcpy(target->ip.v6.uint8, data + 1, SIZE_IP6); |
79 | 845 | } |
80 | | |
81 | 411k | const bool valid = disable_family_check || |
82 | 411k | net_family_is_ipv4(target->family) || |
83 | 411k | net_family_is_ipv6(target->family); |
84 | | |
85 | 411k | return valid ? 0 : -1; |
86 | 411k | } |
87 | | |
88 | | non_null() |
89 | | static void ipport_pack(uint8_t *data, const IP_Port *source) |
90 | 445k | { |
91 | 445k | ip_pack_to_bytes(data, &source->ip); |
92 | 445k | memcpy(data + SIZE_IP, &source->port, SIZE_PORT); |
93 | 445k | } |
94 | | |
95 | | /** return 0 on success, -1 on failure. */ |
96 | | non_null() |
97 | | static int ipport_unpack(IP_Port *target, const uint8_t *data, unsigned int data_size, bool disable_family_check) |
98 | 411k | { |
99 | 411k | if (data_size < (SIZE_IP + SIZE_PORT)) { |
100 | 0 | return -1; |
101 | 0 | } |
102 | | |
103 | 411k | if (ip_unpack_from_bytes(&target->ip, data, data_size, disable_family_check) == -1) { |
104 | 11 | return -1; |
105 | 11 | } |
106 | | |
107 | 411k | memcpy(&target->port, data + SIZE_IP, SIZE_PORT); |
108 | 411k | return 0; |
109 | 411k | } |
110 | | |
111 | | |
112 | | /** @brief Create a new onion path. |
113 | | * |
114 | | * Create a new onion path out of nodes (nodes is a list of ONION_PATH_LENGTH nodes) |
115 | | * |
116 | | * new_path must be an empty memory location of at least Onion_Path size. |
117 | | * |
118 | | * return -1 on failure. |
119 | | * return 0 on success. |
120 | | */ |
121 | | int create_onion_path(const Random *rng, const DHT *dht, Onion_Path *new_path, const Node_format *nodes) |
122 | 8.42k | { |
123 | 8.42k | if (new_path == nullptr || nodes == nullptr) { |
124 | 0 | return -1; |
125 | 0 | } |
126 | | |
127 | 8.42k | encrypt_precompute(nodes[0].public_key, dht_get_self_secret_key(dht), new_path->shared_key1); |
128 | 8.42k | memcpy(new_path->public_key1, dht_get_self_public_key(dht), CRYPTO_PUBLIC_KEY_SIZE); |
129 | | |
130 | 8.42k | uint8_t random_public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
131 | 8.42k | uint8_t random_secret_key[CRYPTO_SECRET_KEY_SIZE]; |
132 | | |
133 | 8.42k | crypto_new_keypair(rng, random_public_key, random_secret_key); |
134 | 8.42k | encrypt_precompute(nodes[1].public_key, random_secret_key, new_path->shared_key2); |
135 | 8.42k | memcpy(new_path->public_key2, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
136 | | |
137 | 8.42k | crypto_new_keypair(rng, random_public_key, random_secret_key); |
138 | 8.42k | encrypt_precompute(nodes[2].public_key, random_secret_key, new_path->shared_key3); |
139 | 8.42k | memcpy(new_path->public_key3, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
140 | | |
141 | 8.42k | crypto_memzero(random_secret_key, sizeof(random_secret_key)); |
142 | | |
143 | 8.42k | new_path->ip_port1 = nodes[0].ip_port; |
144 | 8.42k | new_path->ip_port2 = nodes[1].ip_port; |
145 | 8.42k | new_path->ip_port3 = nodes[2].ip_port; |
146 | | |
147 | 8.42k | memcpy(new_path->node_public_key1, nodes[0].public_key, CRYPTO_PUBLIC_KEY_SIZE); |
148 | 8.42k | memcpy(new_path->node_public_key2, nodes[1].public_key, CRYPTO_PUBLIC_KEY_SIZE); |
149 | 8.42k | memcpy(new_path->node_public_key3, nodes[2].public_key, CRYPTO_PUBLIC_KEY_SIZE); |
150 | | |
151 | 8.42k | return 0; |
152 | 8.42k | } |
153 | | |
154 | | /** @brief Dump nodes in onion path to nodes of length num_nodes. |
155 | | * |
156 | | * return -1 on failure. |
157 | | * return 0 on success. |
158 | | */ |
159 | | int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path) |
160 | 59.5k | { |
161 | 59.5k | if (num_nodes < ONION_PATH_LENGTH) { |
162 | 0 | return -1; |
163 | 0 | } |
164 | | |
165 | 59.5k | nodes[0].ip_port = path->ip_port1; |
166 | 59.5k | nodes[1].ip_port = path->ip_port2; |
167 | 59.5k | nodes[2].ip_port = path->ip_port3; |
168 | | |
169 | 59.5k | memcpy(nodes[0].public_key, path->node_public_key1, CRYPTO_PUBLIC_KEY_SIZE); |
170 | 59.5k | memcpy(nodes[1].public_key, path->node_public_key2, CRYPTO_PUBLIC_KEY_SIZE); |
171 | 59.5k | memcpy(nodes[2].public_key, path->node_public_key3, CRYPTO_PUBLIC_KEY_SIZE); |
172 | 59.5k | return 0; |
173 | 59.5k | } |
174 | | |
175 | | /** @brief Create a onion packet. |
176 | | * |
177 | | * Use Onion_Path path to create packet for data of length to dest. |
178 | | * Maximum length of data is ONION_MAX_DATA_SIZE. |
179 | | * packet should be at least ONION_MAX_PACKET_SIZE big. |
180 | | * |
181 | | * return -1 on failure. |
182 | | * return length of created packet on success. |
183 | | */ |
184 | | int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_length, |
185 | | const Onion_Path *path, const IP_Port *dest, |
186 | | const uint8_t *data, uint16_t length) |
187 | 76.8k | { |
188 | 76.8k | if (1 + length + SEND_1 > max_packet_length || length == 0) { |
189 | 0 | return -1; |
190 | 0 | } |
191 | | |
192 | 76.8k | const uint16_t step1_size = SIZE_IPPORT + length; |
193 | 76.8k | VLA(uint8_t, step1, step1_size); |
194 | | |
195 | 76.8k | ipport_pack(step1, dest); |
196 | 76.8k | memcpy(step1 + SIZE_IPPORT, data, length); |
197 | | |
198 | 76.8k | uint8_t nonce[CRYPTO_NONCE_SIZE]; |
199 | 76.8k | random_nonce(rng, nonce); |
200 | | |
201 | 76.8k | const uint16_t step2_size = SIZE_IPPORT + SEND_BASE + length; |
202 | 76.8k | VLA(uint8_t, step2, step2_size); |
203 | 76.8k | ipport_pack(step2, &path->ip_port3); |
204 | 76.8k | memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE); |
205 | | |
206 | 76.8k | int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, step1_size, |
207 | 76.8k | step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); |
208 | | |
209 | 76.8k | if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) { |
210 | 99 | return -1; |
211 | 99 | } |
212 | | |
213 | 76.7k | const uint16_t step3_size = SIZE_IPPORT + SEND_BASE * 2 + length; |
214 | 76.7k | VLA(uint8_t, step3, step3_size); |
215 | 76.7k | ipport_pack(step3, &path->ip_port2); |
216 | 76.7k | memcpy(step3 + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE); |
217 | 76.7k | len = encrypt_data_symmetric(path->shared_key2, nonce, step2, step2_size, |
218 | 76.7k | step3 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); |
219 | | |
220 | 76.7k | if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) { |
221 | 100 | return -1; |
222 | 100 | } |
223 | | |
224 | 76.6k | packet[0] = NET_PACKET_ONION_SEND_INITIAL; |
225 | 76.6k | memcpy(packet + 1, nonce, CRYPTO_NONCE_SIZE); |
226 | 76.6k | memcpy(packet + 1 + CRYPTO_NONCE_SIZE, path->public_key1, CRYPTO_PUBLIC_KEY_SIZE); |
227 | | |
228 | 76.6k | len = encrypt_data_symmetric(path->shared_key1, nonce, step3, step3_size, |
229 | 76.6k | packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); |
230 | | |
231 | 76.6k | if (len != SIZE_IPPORT + SEND_BASE * 2 + length + CRYPTO_MAC_SIZE) { |
232 | 100 | return -1; |
233 | 100 | } |
234 | | |
235 | 76.5k | return 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + len; |
236 | 76.6k | } |
237 | | |
238 | | /** @brief Create a onion packet to be sent over tcp. |
239 | | * |
240 | | * Use Onion_Path path to create packet for data of length to dest. |
241 | | * Maximum length of data is ONION_MAX_DATA_SIZE. |
242 | | * packet should be at least ONION_MAX_PACKET_SIZE big. |
243 | | * |
244 | | * return -1 on failure. |
245 | | * return length of created packet on success. |
246 | | */ |
247 | | int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_packet_length, |
248 | | const Onion_Path *path, const IP_Port *dest, |
249 | | const uint8_t *data, uint16_t length) |
250 | 1.02k | { |
251 | 1.02k | if (CRYPTO_NONCE_SIZE + SIZE_IPPORT + SEND_BASE * 2 + length > max_packet_length || length == 0) { |
252 | 0 | return -1; |
253 | 0 | } |
254 | | |
255 | 1.02k | const uint16_t step1_size = SIZE_IPPORT + length; |
256 | 1.02k | VLA(uint8_t, step1, step1_size); |
257 | | |
258 | 1.02k | ipport_pack(step1, dest); |
259 | 1.02k | memcpy(step1 + SIZE_IPPORT, data, length); |
260 | | |
261 | 1.02k | uint8_t nonce[CRYPTO_NONCE_SIZE]; |
262 | 1.02k | random_nonce(rng, nonce); |
263 | | |
264 | 1.02k | const uint16_t step2_size = SIZE_IPPORT + SEND_BASE + length; |
265 | 1.02k | VLA(uint8_t, step2, step2_size); |
266 | 1.02k | ipport_pack(step2, &path->ip_port3); |
267 | 1.02k | memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE); |
268 | | |
269 | 1.02k | int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, step1_size, |
270 | 1.02k | step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); |
271 | | |
272 | 1.02k | if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) { |
273 | 0 | return -1; |
274 | 0 | } |
275 | | |
276 | 1.02k | ipport_pack(packet + CRYPTO_NONCE_SIZE, &path->ip_port2); |
277 | 1.02k | memcpy(packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE); |
278 | 1.02k | len = encrypt_data_symmetric(path->shared_key2, nonce, step2, step2_size, |
279 | 1.02k | packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); |
280 | | |
281 | 1.02k | if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) { |
282 | 0 | return -1; |
283 | 0 | } |
284 | | |
285 | 1.02k | memcpy(packet, nonce, CRYPTO_NONCE_SIZE); |
286 | | |
287 | 1.02k | return CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE + len; |
288 | 1.02k | } |
289 | | |
290 | | /** @brief Create and send a onion response sent initially to dest with. |
291 | | * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. |
292 | | * |
293 | | * return -1 on failure. |
294 | | * return 0 on success. |
295 | | */ |
296 | | int send_onion_response(const Logger *log, const Networking_Core *net, |
297 | | const IP_Port *dest, const uint8_t *data, uint16_t length, |
298 | | const uint8_t *ret) |
299 | 66.6k | { |
300 | 66.6k | if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0) { |
301 | 0 | return -1; |
302 | 0 | } |
303 | | |
304 | 66.6k | const uint16_t packet_size = 1 + RETURN_3 + length; |
305 | 66.6k | VLA(uint8_t, packet, packet_size); |
306 | 66.6k | packet[0] = NET_PACKET_ONION_RECV_3; |
307 | 66.6k | memcpy(packet + 1, ret, RETURN_3); |
308 | 66.6k | memcpy(packet + 1 + RETURN_3, data, length); |
309 | | |
310 | 66.6k | if ((uint16_t)sendpacket(net, dest, packet, packet_size) != packet_size) { |
311 | 36 | return -1; |
312 | 36 | } |
313 | | |
314 | 66.5k | Ip_Ntoa ip_str; |
315 | 66.5k | LOGGER_TRACE(log, "forwarded onion RECV_3 to %s:%d (%02x in %02x, %d bytes)", |
316 | 66.5k | net_ip_ntoa(&dest->ip, &ip_str), net_ntohs(dest->port), data[0], packet[0], packet_size); |
317 | 66.5k | return 0; |
318 | 66.6k | } |
319 | | |
320 | | non_null() |
321 | | static int handle_send_initial(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, |
322 | | void *userdata) |
323 | 72.7k | { |
324 | 72.7k | Onion *onion = (Onion *)object; |
325 | | |
326 | 72.7k | if (length > ONION_MAX_PACKET_SIZE) { |
327 | 4 | LOGGER_TRACE(onion->log, "invalid initial onion packet length: %u (max: %u)", |
328 | 4 | length, ONION_MAX_PACKET_SIZE); |
329 | 4 | return 1; |
330 | 4 | } |
331 | | |
332 | 72.7k | if (length <= 1 + SEND_1) { |
333 | 12 | LOGGER_TRACE(onion->log, "initial onion packet cannot contain SEND_1 packet: %u <= %u", |
334 | 12 | length, 1 + SEND_1); |
335 | 12 | return 1; |
336 | 12 | } |
337 | | |
338 | 72.7k | change_symmetric_key(onion); |
339 | | |
340 | 72.7k | const int nonce_start = 1; |
341 | 72.7k | const int public_key_start = nonce_start + CRYPTO_NONCE_SIZE; |
342 | 72.7k | const int ciphertext_start = public_key_start + CRYPTO_PUBLIC_KEY_SIZE; |
343 | | |
344 | 72.7k | const int ciphertext_length = length - ciphertext_start; |
345 | 72.7k | const int plaintext_length = ciphertext_length - CRYPTO_MAC_SIZE; |
346 | | |
347 | 72.7k | uint8_t plain[ONION_MAX_PACKET_SIZE]; |
348 | 72.7k | const uint8_t *public_key = &packet[public_key_start]; |
349 | 72.7k | const uint8_t *shared_key = shared_key_cache_lookup(onion->shared_keys_1, public_key); |
350 | | |
351 | 72.7k | if (shared_key == nullptr) { |
352 | | /* Error looking up/deriving the shared key */ |
353 | 0 | LOGGER_TRACE(onion->log, "shared onion key lookup failed for pk %02x%02x...", |
354 | 0 | public_key[0], public_key[1]); |
355 | 0 | return 1; |
356 | 0 | } |
357 | | |
358 | 72.7k | const int len = decrypt_data_symmetric( |
359 | 72.7k | shared_key, &packet[nonce_start], &packet[ciphertext_start], ciphertext_length, plain); |
360 | | |
361 | 72.7k | if (len != plaintext_length) { |
362 | 389 | LOGGER_TRACE(onion->log, "decrypt failed: %d != %d", len, plaintext_length); |
363 | 389 | return 1; |
364 | 389 | } |
365 | | |
366 | 72.3k | return onion_send_1(onion, plain, len, source, packet + 1); |
367 | 72.7k | } |
368 | | |
369 | | int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, const IP_Port *source, const uint8_t *nonce) |
370 | 73.3k | { |
371 | 73.3k | const uint16_t max_len = ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + CRYPTO_NONCE_SIZE + ONION_RETURN_1); |
372 | 73.3k | if (len > max_len) { |
373 | 0 | LOGGER_TRACE(onion->log, "invalid SEND_1 length: %d > %d", len, max_len); |
374 | 0 | return 1; |
375 | 0 | } |
376 | | |
377 | 73.3k | if (len <= SIZE_IPPORT + SEND_BASE * 2) { |
378 | 0 | return 1; |
379 | 0 | } |
380 | | |
381 | 73.3k | IP_Port send_to; |
382 | | |
383 | 73.3k | if (ipport_unpack(&send_to, plain, len, false) == -1) { |
384 | 3 | return 1; |
385 | 3 | } |
386 | | |
387 | 73.3k | uint8_t ip_port[SIZE_IPPORT]; |
388 | 73.3k | ipport_pack(ip_port, source); |
389 | | |
390 | 73.3k | uint8_t data[ONION_MAX_PACKET_SIZE] = {0}; |
391 | 73.3k | data[0] = NET_PACKET_ONION_SEND_1; |
392 | 73.3k | memcpy(data + 1, nonce, CRYPTO_NONCE_SIZE); |
393 | 73.3k | memcpy(data + 1 + CRYPTO_NONCE_SIZE, plain + SIZE_IPPORT, len - SIZE_IPPORT); |
394 | 73.3k | uint16_t data_len = 1 + CRYPTO_NONCE_SIZE + (len - SIZE_IPPORT); |
395 | 73.3k | uint8_t *ret_part = data + data_len; |
396 | 73.3k | random_nonce(onion->rng, ret_part); |
397 | 73.3k | len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, |
398 | 73.3k | ret_part + CRYPTO_NONCE_SIZE); |
399 | | |
400 | 73.3k | if (len != SIZE_IPPORT + CRYPTO_MAC_SIZE) { |
401 | 33 | return 1; |
402 | 33 | } |
403 | | |
404 | 73.2k | data_len += CRYPTO_NONCE_SIZE + len; |
405 | | |
406 | 73.2k | if ((uint32_t)sendpacket(onion->net, &send_to, data, data_len) != data_len) { |
407 | 33 | return 1; |
408 | 33 | } |
409 | | |
410 | 73.2k | Ip_Ntoa ip_str; |
411 | 73.2k | LOGGER_TRACE(onion->log, "forwarded onion packet to %s:%d, level 1 (%02x in %02x, %d bytes)", |
412 | 73.2k | net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), plain[0], data[0], data_len); |
413 | 73.2k | return 0; |
414 | 73.2k | } |
415 | | |
416 | | non_null() |
417 | | static int handle_send_1(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) |
418 | 70.9k | { |
419 | 70.9k | Onion *onion = (Onion *)object; |
420 | | |
421 | 70.9k | if (length > ONION_MAX_PACKET_SIZE) { |
422 | 3 | return 1; |
423 | 3 | } |
424 | | |
425 | 70.9k | if (length <= 1 + SEND_2) { |
426 | 12 | return 1; |
427 | 12 | } |
428 | | |
429 | 70.8k | change_symmetric_key(onion); |
430 | | |
431 | 70.8k | uint8_t plain[ONION_MAX_PACKET_SIZE]; |
432 | 70.8k | const uint8_t *public_key = packet + 1 + CRYPTO_NONCE_SIZE; |
433 | 70.8k | const uint8_t *shared_key = shared_key_cache_lookup(onion->shared_keys_2, public_key); |
434 | | |
435 | 70.8k | if (shared_key == nullptr) { |
436 | | /* Error looking up/deriving the shared key */ |
437 | 0 | return 1; |
438 | 0 | } |
439 | | |
440 | 70.8k | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, |
441 | 70.8k | length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1), plain); |
442 | | |
443 | 70.8k | if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1 + CRYPTO_MAC_SIZE)) { |
444 | 499 | return 1; |
445 | 499 | } |
446 | | |
447 | 70.3k | IP_Port send_to; |
448 | | |
449 | 70.3k | if (ipport_unpack(&send_to, plain, len, false) == -1) { |
450 | 1 | return 1; |
451 | 1 | } |
452 | | |
453 | 70.3k | uint8_t data[ONION_MAX_PACKET_SIZE] = {0}; |
454 | 70.3k | data[0] = NET_PACKET_ONION_SEND_2; |
455 | 70.3k | memcpy(data + 1, packet + 1, CRYPTO_NONCE_SIZE); |
456 | 70.3k | memcpy(data + 1 + CRYPTO_NONCE_SIZE, plain + SIZE_IPPORT, len - SIZE_IPPORT); |
457 | 70.3k | uint16_t data_len = 1 + CRYPTO_NONCE_SIZE + (len - SIZE_IPPORT); |
458 | 70.3k | uint8_t *ret_part = data + data_len; |
459 | 70.3k | random_nonce(onion->rng, ret_part); |
460 | 70.3k | uint8_t ret_data[RETURN_1 + SIZE_IPPORT]; |
461 | 70.3k | ipport_pack(ret_data, source); |
462 | 70.3k | memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1); |
463 | 70.3k | len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), |
464 | 70.3k | ret_part + CRYPTO_NONCE_SIZE); |
465 | | |
466 | 70.3k | if (len != RETURN_2 - CRYPTO_NONCE_SIZE) { |
467 | 33 | return 1; |
468 | 33 | } |
469 | | |
470 | 70.3k | data_len += CRYPTO_NONCE_SIZE + len; |
471 | | |
472 | 70.3k | if ((uint32_t)sendpacket(onion->net, &send_to, data, data_len) != data_len) { |
473 | 32 | return 1; |
474 | 32 | } |
475 | | |
476 | 70.3k | Ip_Ntoa ip_str; |
477 | 70.3k | LOGGER_TRACE(onion->log, "forwarded onion packet to %s:%d, level 2 (%02x in %02x, %d bytes)", |
478 | 70.3k | net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), packet[0], data[0], data_len); |
479 | 70.3k | return 0; |
480 | 70.3k | } |
481 | | |
482 | | non_null() |
483 | | static int handle_send_2(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) |
484 | 68.9k | { |
485 | 68.9k | Onion *onion = (Onion *)object; |
486 | | |
487 | 68.9k | if (length > ONION_MAX_PACKET_SIZE) { |
488 | 1 | return 1; |
489 | 1 | } |
490 | | |
491 | 68.9k | if (length <= 1 + SEND_3) { |
492 | 2 | return 1; |
493 | 2 | } |
494 | | |
495 | 68.9k | change_symmetric_key(onion); |
496 | | |
497 | 68.9k | uint8_t plain[ONION_MAX_PACKET_SIZE]; |
498 | 68.9k | const uint8_t *public_key = packet + 1 + CRYPTO_NONCE_SIZE; |
499 | 68.9k | const uint8_t *shared_key = shared_key_cache_lookup(onion->shared_keys_3, public_key); |
500 | | |
501 | 68.9k | if (shared_key == nullptr) { |
502 | | /* Error looking up/deriving the shared key */ |
503 | 0 | return 1; |
504 | 0 | } |
505 | | |
506 | 68.9k | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, |
507 | 68.9k | length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2), plain); |
508 | | |
509 | 68.9k | if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2 + CRYPTO_MAC_SIZE)) { |
510 | 397 | return 1; |
511 | 397 | } |
512 | | |
513 | 68.5k | assert(len > SIZE_IPPORT); |
514 | | |
515 | 68.5k | const uint8_t packet_id = plain[SIZE_IPPORT]; |
516 | | |
517 | 68.5k | if (packet_id != NET_PACKET_ANNOUNCE_REQUEST && packet_id != NET_PACKET_ANNOUNCE_REQUEST_OLD && |
518 | 68.5k | packet_id != NET_PACKET_ONION_DATA_REQUEST) { |
519 | 1 | return 1; |
520 | 1 | } |
521 | | |
522 | 68.5k | IP_Port send_to; |
523 | | |
524 | 68.5k | if (ipport_unpack(&send_to, plain, len, false) == -1) { |
525 | 2 | return 1; |
526 | 2 | } |
527 | | |
528 | 68.5k | uint8_t data[ONION_MAX_PACKET_SIZE] = {0}; |
529 | 68.5k | memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT); |
530 | 68.5k | uint16_t data_len = len - SIZE_IPPORT; |
531 | 68.5k | uint8_t *ret_part = data + (len - SIZE_IPPORT); |
532 | 68.5k | random_nonce(onion->rng, ret_part); |
533 | 68.5k | uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; |
534 | 68.5k | ipport_pack(ret_data, source); |
535 | 68.5k | memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2); |
536 | 68.5k | len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), |
537 | 68.5k | ret_part + CRYPTO_NONCE_SIZE); |
538 | | |
539 | 68.5k | if (len != RETURN_3 - CRYPTO_NONCE_SIZE) { |
540 | 33 | return 1; |
541 | 33 | } |
542 | | |
543 | 68.5k | data_len += RETURN_3; |
544 | | |
545 | 68.5k | if ((uint32_t)sendpacket(onion->net, &send_to, data, data_len) != data_len) { |
546 | 32 | return 1; |
547 | 32 | } |
548 | | |
549 | 68.5k | Ip_Ntoa ip_str; |
550 | 68.5k | LOGGER_TRACE(onion->log, "forwarded onion packet to %s:%d, level 3 (%02x in %02x, %d bytes)", |
551 | 68.5k | net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), packet[0], data[0], data_len); |
552 | 68.5k | return 0; |
553 | 68.5k | } |
554 | | |
555 | | |
556 | | non_null() |
557 | | static int handle_recv_3(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) |
558 | 66.4k | { |
559 | 66.4k | Onion *onion = (Onion *)object; |
560 | | |
561 | 66.4k | if (length > ONION_MAX_PACKET_SIZE) { |
562 | 4 | return 1; |
563 | 4 | } |
564 | | |
565 | 66.4k | if (length <= 1 + RETURN_3) { |
566 | 10 | return 1; |
567 | 10 | } |
568 | | |
569 | 66.4k | const uint8_t packet_id = packet[1 + RETURN_3]; |
570 | | |
571 | 66.4k | if (packet_id != NET_PACKET_ANNOUNCE_RESPONSE && packet_id != NET_PACKET_ANNOUNCE_RESPONSE_OLD && |
572 | 66.4k | packet_id != NET_PACKET_ONION_DATA_RESPONSE) { |
573 | 6 | return 1; |
574 | 6 | } |
575 | | |
576 | 66.4k | change_symmetric_key(onion); |
577 | | |
578 | 66.4k | uint8_t plain[SIZE_IPPORT + RETURN_2]; |
579 | 66.4k | const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, |
580 | 66.4k | SIZE_IPPORT + RETURN_2 + CRYPTO_MAC_SIZE, plain); |
581 | | |
582 | 66.4k | if ((uint32_t)len != sizeof(plain)) { |
583 | 33 | return 1; |
584 | 33 | } |
585 | | |
586 | 66.4k | IP_Port send_to; |
587 | | |
588 | 66.4k | if (ipport_unpack(&send_to, plain, len, false) == -1) { |
589 | 3 | LOGGER_DEBUG(onion->log, "failed to unpack IP/Port"); |
590 | 3 | return 1; |
591 | 3 | } |
592 | | |
593 | 66.4k | uint8_t data[ONION_MAX_PACKET_SIZE] = {0}; |
594 | 66.4k | data[0] = NET_PACKET_ONION_RECV_2; |
595 | 66.4k | memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2); |
596 | 66.4k | memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3)); |
597 | 66.4k | const uint16_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3)); |
598 | | |
599 | 66.4k | if ((uint32_t)sendpacket(onion->net, &send_to, data, data_len) != data_len) { |
600 | 24 | return 1; |
601 | 24 | } |
602 | | |
603 | 66.4k | Ip_Ntoa ip_str; |
604 | 66.4k | LOGGER_TRACE(onion->log, "forwarded onion RECV_2 to %s:%d (%02x in %02x, %d bytes)", |
605 | 66.4k | net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), packet[0], data[0], data_len); |
606 | 66.4k | return 0; |
607 | 66.4k | } |
608 | | |
609 | | non_null() |
610 | | static int handle_recv_2(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) |
611 | 66.3k | { |
612 | 66.3k | Onion *onion = (Onion *)object; |
613 | | |
614 | 66.3k | if (length > ONION_MAX_PACKET_SIZE) { |
615 | 1 | return 1; |
616 | 1 | } |
617 | | |
618 | 66.3k | if (length <= 1 + RETURN_2) { |
619 | 3 | return 1; |
620 | 3 | } |
621 | | |
622 | 66.3k | const uint8_t packet_id = packet[1 + RETURN_2]; |
623 | | |
624 | 66.3k | if (packet_id != NET_PACKET_ANNOUNCE_RESPONSE && packet_id != NET_PACKET_ANNOUNCE_RESPONSE_OLD && |
625 | 66.3k | packet_id != NET_PACKET_ONION_DATA_RESPONSE) { |
626 | 13 | return 1; |
627 | 13 | } |
628 | | |
629 | 66.2k | change_symmetric_key(onion); |
630 | | |
631 | 66.2k | uint8_t plain[SIZE_IPPORT + RETURN_1]; |
632 | 66.2k | const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, |
633 | 66.2k | SIZE_IPPORT + RETURN_1 + CRYPTO_MAC_SIZE, plain); |
634 | | |
635 | 66.2k | if ((uint32_t)len != sizeof(plain)) { |
636 | 33 | return 1; |
637 | 33 | } |
638 | | |
639 | 66.2k | IP_Port send_to; |
640 | | |
641 | 66.2k | if (ipport_unpack(&send_to, plain, len, false) == -1) { |
642 | 2 | return 1; |
643 | 2 | } |
644 | | |
645 | 66.2k | uint8_t data[ONION_MAX_PACKET_SIZE] = {0}; |
646 | 66.2k | data[0] = NET_PACKET_ONION_RECV_1; |
647 | 66.2k | memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1); |
648 | 66.2k | memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2)); |
649 | 66.2k | const uint16_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2)); |
650 | | |
651 | 66.2k | if ((uint32_t)sendpacket(onion->net, &send_to, data, data_len) != data_len) { |
652 | 24 | return 1; |
653 | 24 | } |
654 | | |
655 | 66.2k | Ip_Ntoa ip_str; |
656 | 66.2k | LOGGER_TRACE(onion->log, "forwarded onion RECV_1 to %s:%d (%02x in %02x, %d bytes)", |
657 | 66.2k | net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), packet[0], data[0], data_len); |
658 | 66.2k | return 0; |
659 | 66.2k | } |
660 | | |
661 | | non_null() |
662 | | static int handle_recv_1(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) |
663 | 66.2k | { |
664 | 66.2k | Onion *onion = (Onion *)object; |
665 | | |
666 | 66.2k | if (length > ONION_MAX_PACKET_SIZE) { |
667 | 3 | return 1; |
668 | 3 | } |
669 | | |
670 | 66.2k | if (length <= 1 + RETURN_1) { |
671 | 8 | return 1; |
672 | 8 | } |
673 | | |
674 | 66.2k | const uint8_t packet_id = packet[1 + RETURN_1]; |
675 | | |
676 | 66.2k | if (packet_id != NET_PACKET_ANNOUNCE_RESPONSE && packet_id != NET_PACKET_ANNOUNCE_RESPONSE_OLD && |
677 | 66.2k | packet_id != NET_PACKET_ONION_DATA_RESPONSE) { |
678 | 27 | return 1; |
679 | 27 | } |
680 | | |
681 | 66.2k | change_symmetric_key(onion); |
682 | | |
683 | 66.2k | uint8_t plain[SIZE_IPPORT]; |
684 | 66.2k | const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, |
685 | 66.2k | SIZE_IPPORT + CRYPTO_MAC_SIZE, plain); |
686 | | |
687 | 66.2k | if ((uint32_t)len != SIZE_IPPORT) { |
688 | 23 | return 1; |
689 | 23 | } |
690 | | |
691 | 66.1k | IP_Port send_to; |
692 | | |
693 | 66.1k | if (ipport_unpack(&send_to, plain, len, true) == -1) { |
694 | 0 | LOGGER_DEBUG(onion->log, "failed to unpack IP/Port"); |
695 | 0 | return 1; |
696 | 0 | } |
697 | | |
698 | 66.1k | const uint16_t data_len = length - (1 + RETURN_1); |
699 | | |
700 | 66.1k | if (onion->recv_1_function != nullptr && |
701 | 66.1k | !net_family_is_ipv4(send_to.ip.family) && |
702 | 66.1k | !net_family_is_ipv6(send_to.ip.family)) { |
703 | 808 | return onion->recv_1_function(onion->callback_object, &send_to, packet + (1 + RETURN_1), data_len); |
704 | 808 | } |
705 | | |
706 | 65.3k | if ((uint32_t)sendpacket(onion->net, &send_to, packet + (1 + RETURN_1), data_len) != data_len) { |
707 | 51 | return 1; |
708 | 51 | } |
709 | | |
710 | 65.3k | return 0; |
711 | 65.3k | } |
712 | | |
713 | | void set_callback_handle_recv_1(Onion *onion, onion_recv_1_cb *function, void *object) |
714 | 40 | { |
715 | 40 | onion->recv_1_function = function; |
716 | 40 | onion->callback_object = object; |
717 | 40 | } |
718 | | |
719 | | Onion *new_onion(const Logger *log, const Memory *mem, const Mono_Time *mono_time, const Random *rng, DHT *dht) |
720 | 3.83k | { |
721 | 3.83k | if (dht == nullptr) { |
722 | 0 | return nullptr; |
723 | 0 | } |
724 | | |
725 | 3.83k | Onion *onion = (Onion *)mem_alloc(mem, sizeof(Onion)); |
726 | | |
727 | 3.83k | if (onion == nullptr) { |
728 | 24 | return nullptr; |
729 | 24 | } |
730 | | |
731 | 3.80k | onion->log = log; |
732 | 3.80k | onion->dht = dht; |
733 | 3.80k | onion->net = dht_get_net(dht); |
734 | 3.80k | onion->mono_time = mono_time; |
735 | 3.80k | onion->rng = rng; |
736 | 3.80k | onion->mem = mem; |
737 | 3.80k | new_symmetric_key(rng, onion->secret_symmetric_key); |
738 | 3.80k | onion->timestamp = mono_time_get(onion->mono_time); |
739 | | |
740 | 3.80k | const uint8_t *secret_key = dht_get_self_secret_key(dht); |
741 | 3.80k | onion->shared_keys_1 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT); |
742 | 3.80k | onion->shared_keys_2 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT); |
743 | 3.80k | onion->shared_keys_3 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT); |
744 | | |
745 | 3.80k | if (onion->shared_keys_1 == nullptr || |
746 | 3.80k | onion->shared_keys_2 == nullptr || |
747 | 3.80k | onion->shared_keys_3 == nullptr) { |
748 | | // cppcheck-suppress mismatchAllocDealloc |
749 | 46 | kill_onion(onion); |
750 | 46 | return nullptr; |
751 | 46 | } |
752 | | |
753 | | |
754 | 3.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); |
755 | 3.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion); |
756 | 3.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, &handle_send_2, onion); |
757 | | |
758 | 3.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_3, &handle_recv_3, onion); |
759 | 3.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_2, &handle_recv_2, onion); |
760 | 3.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_1, &handle_recv_1, onion); |
761 | | |
762 | 3.76k | return onion; |
763 | 3.80k | } |
764 | | |
765 | | void kill_onion(Onion *onion) |
766 | 2.83k | { |
767 | 2.83k | if (onion == nullptr) { |
768 | 70 | return; |
769 | 70 | } |
770 | | |
771 | 2.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, nullptr, nullptr); |
772 | 2.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, nullptr, nullptr); |
773 | 2.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, nullptr, nullptr); |
774 | | |
775 | 2.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_3, nullptr, nullptr); |
776 | 2.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_2, nullptr, nullptr); |
777 | 2.76k | networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_1, nullptr, nullptr); |
778 | | |
779 | 2.76k | crypto_memzero(onion->secret_symmetric_key, sizeof(onion->secret_symmetric_key)); |
780 | | |
781 | 2.76k | shared_key_cache_free(onion->shared_keys_1); |
782 | 2.76k | shared_key_cache_free(onion->shared_keys_2); |
783 | 2.76k | shared_key_cache_free(onion->shared_keys_3); |
784 | | |
785 | 2.76k | mem_delete(onion->mem, onion); |
786 | 2.76k | } |