diff options
Diffstat (limited to 'src/messenger/messenger_api_message.c')
-rw-r--r-- | src/messenger/messenger_api_message.c | 944 |
1 files changed, 0 insertions, 944 deletions
diff --git a/src/messenger/messenger_api_message.c b/src/messenger/messenger_api_message.c deleted file mode 100644 index 3814def70..000000000 --- a/src/messenger/messenger_api_message.c +++ /dev/null | |||
@@ -1,944 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2020--2021 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @author Tobias Frisch | ||
22 | * @file src/messenger/messenger_api_message.c | ||
23 | * @brief messenger api: client and service implementation of GNUnet MESSENGER service | ||
24 | */ | ||
25 | |||
26 | #include "messenger_api_message.h" | ||
27 | |||
28 | struct GNUNET_MESSENGER_MessageSignature | ||
29 | { | ||
30 | struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | ||
31 | struct GNUNET_HashCode hash; | ||
32 | }; | ||
33 | |||
34 | struct GNUNET_MESSENGER_ShortMessage | ||
35 | { | ||
36 | enum GNUNET_MESSENGER_MessageKind kind; | ||
37 | struct GNUNET_MESSENGER_MessageBody body; | ||
38 | }; | ||
39 | |||
40 | struct GNUNET_MESSENGER_Message* | ||
41 | create_message (enum GNUNET_MESSENGER_MessageKind kind) | ||
42 | { | ||
43 | struct GNUNET_MESSENGER_Message *message = GNUNET_new(struct GNUNET_MESSENGER_Message); | ||
44 | |||
45 | message->header.kind = kind; | ||
46 | |||
47 | switch (message->header.kind) | ||
48 | { | ||
49 | case GNUNET_MESSENGER_KIND_NAME: | ||
50 | message->body.name.name = NULL; | ||
51 | break; | ||
52 | case GNUNET_MESSENGER_KIND_TEXT: | ||
53 | message->body.text.text = NULL; | ||
54 | break; | ||
55 | case GNUNET_MESSENGER_KIND_FILE: | ||
56 | message->body.file.uri = NULL; | ||
57 | break; | ||
58 | case GNUNET_MESSENGER_KIND_PRIVATE: | ||
59 | message->body.privacy.length = 0; | ||
60 | message->body.privacy.data = NULL; | ||
61 | break; | ||
62 | default: | ||
63 | break; | ||
64 | } | ||
65 | |||
66 | return message; | ||
67 | } | ||
68 | |||
69 | struct GNUNET_MESSENGER_Message* | ||
70 | copy_message (const struct GNUNET_MESSENGER_Message *message) | ||
71 | { | ||
72 | GNUNET_assert(message); | ||
73 | |||
74 | struct GNUNET_MESSENGER_Message *copy = GNUNET_new(struct GNUNET_MESSENGER_Message); | ||
75 | |||
76 | GNUNET_memcpy(copy, message, sizeof(struct GNUNET_MESSENGER_Message)); | ||
77 | |||
78 | switch (message->header.kind) | ||
79 | { | ||
80 | case GNUNET_MESSENGER_KIND_NAME: | ||
81 | copy->body.name.name = GNUNET_strdup(message->body.name.name); | ||
82 | break; | ||
83 | case GNUNET_MESSENGER_KIND_TEXT: | ||
84 | copy->body.text.text = GNUNET_strdup(message->body.text.text); | ||
85 | break; | ||
86 | case GNUNET_MESSENGER_KIND_FILE: | ||
87 | copy->body.file.uri = GNUNET_strdup(message->body.file.uri); | ||
88 | break; | ||
89 | case GNUNET_MESSENGER_KIND_PRIVATE: | ||
90 | copy->body.privacy.data = copy->body.privacy.length ? GNUNET_malloc(copy->body.privacy.length) : NULL; | ||
91 | |||
92 | if (copy->body.privacy.data) | ||
93 | { | ||
94 | GNUNET_memcpy(copy->body.privacy.data, message->body.privacy.data, copy->body.privacy.length); | ||
95 | } | ||
96 | |||
97 | break; | ||
98 | default: | ||
99 | break; | ||
100 | } | ||
101 | |||
102 | return copy; | ||
103 | } | ||
104 | |||
105 | static void | ||
106 | destroy_message_body (enum GNUNET_MESSENGER_MessageKind kind, | ||
107 | struct GNUNET_MESSENGER_MessageBody *body) | ||
108 | { | ||
109 | switch (kind) | ||
110 | { | ||
111 | case GNUNET_MESSENGER_KIND_NAME: | ||
112 | GNUNET_free(body->name.name); | ||
113 | break; | ||
114 | case GNUNET_MESSENGER_KIND_TEXT: | ||
115 | GNUNET_free(body->text.text); | ||
116 | break; | ||
117 | case GNUNET_MESSENGER_KIND_FILE: | ||
118 | GNUNET_free(body->file.uri); | ||
119 | break; | ||
120 | case GNUNET_MESSENGER_KIND_PRIVATE: | ||
121 | GNUNET_free(body->privacy.data); | ||
122 | break; | ||
123 | default: | ||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | void | ||
129 | cleanup_message (struct GNUNET_MESSENGER_Message *message) | ||
130 | { | ||
131 | GNUNET_assert(message); | ||
132 | |||
133 | destroy_message_body (message->header.kind, &(message->body)); | ||
134 | } | ||
135 | |||
136 | void | ||
137 | destroy_message (struct GNUNET_MESSENGER_Message *message) | ||
138 | { | ||
139 | GNUNET_assert(message); | ||
140 | |||
141 | destroy_message_body (message->header.kind, &(message->body)); | ||
142 | |||
143 | GNUNET_free(message); | ||
144 | } | ||
145 | |||
146 | int | ||
147 | is_message_session_bound (const struct GNUNET_MESSENGER_Message *message) | ||
148 | { | ||
149 | GNUNET_assert(message); | ||
150 | |||
151 | if ((GNUNET_MESSENGER_KIND_JOIN == message->header.kind) || | ||
152 | (GNUNET_MESSENGER_KIND_LEAVE == message->header.kind) || | ||
153 | (GNUNET_MESSENGER_KIND_NAME == message->header.kind) || | ||
154 | (GNUNET_MESSENGER_KIND_KEY == message->header.kind) || | ||
155 | (GNUNET_MESSENGER_KIND_ID == message->header.kind)) | ||
156 | return GNUNET_YES; | ||
157 | else | ||
158 | return GNUNET_NO; | ||
159 | } | ||
160 | |||
161 | static void | ||
162 | fold_short_message (const struct GNUNET_MESSENGER_Message *message, | ||
163 | struct GNUNET_MESSENGER_ShortMessage *shortened) | ||
164 | { | ||
165 | shortened->kind = message->header.kind; | ||
166 | |||
167 | GNUNET_memcpy(&(shortened->body), &(message->body), sizeof(struct GNUNET_MESSENGER_MessageBody)); | ||
168 | } | ||
169 | |||
170 | static void | ||
171 | unfold_short_message (struct GNUNET_MESSENGER_ShortMessage *shortened, | ||
172 | struct GNUNET_MESSENGER_Message *message) | ||
173 | { | ||
174 | destroy_message_body (message->header.kind, &(message->body)); | ||
175 | |||
176 | message->header.kind = shortened->kind; | ||
177 | |||
178 | GNUNET_memcpy(&(message->body), &(shortened->body), sizeof(struct GNUNET_MESSENGER_MessageBody)); | ||
179 | } | ||
180 | |||
181 | #define member_size(type, member) sizeof(((type*) NULL)->member) | ||
182 | |||
183 | static uint16_t | ||
184 | get_message_body_kind_size (enum GNUNET_MESSENGER_MessageKind kind) | ||
185 | { | ||
186 | uint16_t length = 0; | ||
187 | |||
188 | switch (kind) | ||
189 | { | ||
190 | case GNUNET_MESSENGER_KIND_INFO: | ||
191 | length += member_size(struct GNUNET_MESSENGER_Message, body.info.messenger_version); | ||
192 | break; | ||
193 | case GNUNET_MESSENGER_KIND_PEER: | ||
194 | length += member_size(struct GNUNET_MESSENGER_Message, body.peer.peer); | ||
195 | break; | ||
196 | case GNUNET_MESSENGER_KIND_ID: | ||
197 | length += member_size(struct GNUNET_MESSENGER_Message, body.id.id); | ||
198 | break; | ||
199 | case GNUNET_MESSENGER_KIND_MISS: | ||
200 | length += member_size(struct GNUNET_MESSENGER_Message, body.miss.peer); | ||
201 | break; | ||
202 | case GNUNET_MESSENGER_KIND_MERGE: | ||
203 | length += member_size(struct GNUNET_MESSENGER_Message, body.merge.previous); | ||
204 | break; | ||
205 | case GNUNET_MESSENGER_KIND_REQUEST: | ||
206 | length += member_size(struct GNUNET_MESSENGER_Message, body.request.hash); | ||
207 | break; | ||
208 | case GNUNET_MESSENGER_KIND_INVITE: | ||
209 | length += member_size(struct GNUNET_MESSENGER_Message, body.invite.door); | ||
210 | length += member_size(struct GNUNET_MESSENGER_Message, body.invite.key); | ||
211 | break; | ||
212 | case GNUNET_MESSENGER_KIND_TEXT: | ||
213 | break; | ||
214 | case GNUNET_MESSENGER_KIND_FILE: | ||
215 | length += member_size(struct GNUNET_MESSENGER_Message, body.file.key); | ||
216 | length += member_size(struct GNUNET_MESSENGER_Message, body.file.hash); | ||
217 | length += member_size(struct GNUNET_MESSENGER_Message, body.file.name); | ||
218 | break; | ||
219 | case GNUNET_MESSENGER_KIND_PRIVATE: | ||
220 | length += member_size(struct GNUNET_MESSENGER_Message, body.privacy.key); | ||
221 | break; | ||
222 | case GNUNET_MESSENGER_KIND_DELETE: | ||
223 | length += member_size(struct GNUNET_MESSENGER_Message, body.deletion.hash); | ||
224 | length += member_size(struct GNUNET_MESSENGER_Message, body.deletion.delay); | ||
225 | break; | ||
226 | default: | ||
227 | break; | ||
228 | } | ||
229 | |||
230 | return length; | ||
231 | } | ||
232 | |||
233 | typedef uint32_t kind_t; | ||
234 | |||
235 | uint16_t | ||
236 | get_message_kind_size (enum GNUNET_MESSENGER_MessageKind kind, | ||
237 | int include_header) | ||
238 | { | ||
239 | uint16_t length = 0; | ||
240 | |||
241 | if (GNUNET_YES == include_header) | ||
242 | { | ||
243 | length += member_size(struct GNUNET_MESSENGER_Message, header.timestamp); | ||
244 | length += member_size(struct GNUNET_MESSENGER_Message, header.sender_id); | ||
245 | length += member_size(struct GNUNET_MESSENGER_Message, header.previous); | ||
246 | } | ||
247 | |||
248 | length += sizeof(kind_t); | ||
249 | |||
250 | return length + get_message_body_kind_size (kind); | ||
251 | } | ||
252 | |||
253 | static uint16_t | ||
254 | get_message_body_size (enum GNUNET_MESSENGER_MessageKind kind, | ||
255 | const struct GNUNET_MESSENGER_MessageBody *body) | ||
256 | { | ||
257 | uint16_t length = 0; | ||
258 | |||
259 | switch (kind) | ||
260 | { | ||
261 | case GNUNET_MESSENGER_KIND_INFO: | ||
262 | length += GNUNET_IDENTITY_key_get_length(&(body->info.host_key)); | ||
263 | break; | ||
264 | case GNUNET_MESSENGER_KIND_JOIN: | ||
265 | length += GNUNET_IDENTITY_key_get_length(&(body->join.key)); | ||
266 | break; | ||
267 | case GNUNET_MESSENGER_KIND_NAME: | ||
268 | length += (body->name.name ? strlen (body->name.name) : 0); | ||
269 | break; | ||
270 | case GNUNET_MESSENGER_KIND_KEY: | ||
271 | length += GNUNET_IDENTITY_key_get_length(&(body->key.key)); | ||
272 | break; | ||
273 | case GNUNET_MESSENGER_KIND_TEXT: | ||
274 | length += strlen (body->text.text); | ||
275 | break; | ||
276 | case GNUNET_MESSENGER_KIND_FILE: | ||
277 | length += strlen (body->file.uri); | ||
278 | break; | ||
279 | case GNUNET_MESSENGER_KIND_PRIVATE: | ||
280 | length += body->privacy.length; | ||
281 | break; | ||
282 | default: | ||
283 | break; | ||
284 | } | ||
285 | |||
286 | return length; | ||
287 | } | ||
288 | |||
289 | uint16_t | ||
290 | get_message_size (const struct GNUNET_MESSENGER_Message *message, | ||
291 | int include_header) | ||
292 | { | ||
293 | GNUNET_assert(message); | ||
294 | |||
295 | uint16_t length = 0; | ||
296 | |||
297 | if (GNUNET_YES == include_header) | ||
298 | length += GNUNET_IDENTITY_signature_get_length(&(message->header.signature)); | ||
299 | |||
300 | length += get_message_kind_size (message->header.kind, include_header); | ||
301 | length += get_message_body_size (message->header.kind, &(message->body)); | ||
302 | |||
303 | return length; | ||
304 | } | ||
305 | |||
306 | static uint16_t | ||
307 | get_short_message_size (const struct GNUNET_MESSENGER_ShortMessage *message, | ||
308 | int include_body) | ||
309 | { | ||
310 | const uint16_t minimum_size = sizeof(struct GNUNET_HashCode) + sizeof(kind_t); | ||
311 | |||
312 | if (message) | ||
313 | return minimum_size + get_message_body_kind_size (message->kind) | ||
314 | + (include_body == GNUNET_YES? get_message_body_size (message->kind, &(message->body)) : 0); | ||
315 | else | ||
316 | return minimum_size; | ||
317 | } | ||
318 | |||
319 | static uint16_t | ||
320 | calc_usual_padding () | ||
321 | { | ||
322 | uint16_t padding = 0; | ||
323 | uint16_t kind_size; | ||
324 | |||
325 | for (int i = 0; i <= GNUNET_MESSENGER_KIND_MAX; i++) { | ||
326 | kind_size = get_message_kind_size ((enum GNUNET_MESSENGER_MessageKind) i, GNUNET_YES); | ||
327 | |||
328 | if (kind_size > padding) | ||
329 | padding = kind_size; | ||
330 | } | ||
331 | |||
332 | return padding + GNUNET_MESSENGER_PADDING_MIN; | ||
333 | } | ||
334 | |||
335 | #define max(x, y) (x > y? x : y) | ||
336 | |||
337 | static uint16_t | ||
338 | calc_padded_length (uint16_t length) | ||
339 | { | ||
340 | static uint16_t usual_padding = 0; | ||
341 | |||
342 | if (!usual_padding) | ||
343 | usual_padding = calc_usual_padding(); | ||
344 | |||
345 | const uint16_t padded_length = max( | ||
346 | length + GNUNET_MESSENGER_PADDING_MIN, | ||
347 | usual_padding | ||
348 | ); | ||
349 | |||
350 | if (padded_length <= GNUNET_MESSENGER_PADDING_LEVEL0) | ||
351 | return GNUNET_MESSENGER_PADDING_LEVEL0; | ||
352 | |||
353 | if (padded_length <= GNUNET_MESSENGER_PADDING_LEVEL1) | ||
354 | return GNUNET_MESSENGER_PADDING_LEVEL1; | ||
355 | |||
356 | if (padded_length <= GNUNET_MESSENGER_PADDING_LEVEL2) | ||
357 | return GNUNET_MESSENGER_PADDING_LEVEL2; | ||
358 | |||
359 | return GNUNET_MESSENGER_MAX_MESSAGE_SIZE; | ||
360 | |||
361 | } | ||
362 | |||
363 | #define min(x, y) (x < y? x : y) | ||
364 | |||
365 | #define encode_step_ext(dst, offset, src, size) do { \ | ||
366 | GNUNET_memcpy(dst + offset, src, size); \ | ||
367 | offset += size; \ | ||
368 | } while (0) | ||
369 | |||
370 | #define encode_step(dst, offset, src) do { \ | ||
371 | encode_step_ext(dst, offset, src, sizeof(*src)); \ | ||
372 | } while (0) | ||
373 | |||
374 | #define encode_step_key(dst, offset, src, length) do { \ | ||
375 | ssize_t result = GNUNET_IDENTITY_write_key_to_buffer( \ | ||
376 | src, dst + offset, length - offset \ | ||
377 | ); \ | ||
378 | if (result < 0) \ | ||
379 | GNUNET_break (0); \ | ||
380 | else \ | ||
381 | offset += result; \ | ||
382 | } while (0) | ||
383 | |||
384 | #define encode_step_signature(dst, offset, src, length) do { \ | ||
385 | ssize_t result = GNUNET_IDENTITY_write_signature_to_buffer( \ | ||
386 | src, dst + offset, length - offset \ | ||
387 | ); \ | ||
388 | if (result < 0) \ | ||
389 | GNUNET_break (0); \ | ||
390 | else \ | ||
391 | offset += result; \ | ||
392 | } while (0) | ||
393 | |||
394 | static void | ||
395 | encode_message_body (enum GNUNET_MESSENGER_MessageKind kind, | ||
396 | const struct GNUNET_MESSENGER_MessageBody *body, | ||
397 | uint16_t length, | ||
398 | char *buffer, | ||
399 | uint16_t offset) | ||
400 | { | ||
401 | uint32_t version; | ||
402 | switch (kind) | ||
403 | { | ||
404 | case GNUNET_MESSENGER_KIND_INFO: | ||
405 | version = GNUNET_htobe32(body->info.messenger_version); | ||
406 | |||
407 | encode_step_key(buffer, offset, &(body->info.host_key), length); | ||
408 | encode_step(buffer, offset, &version); | ||
409 | break; | ||
410 | case GNUNET_MESSENGER_KIND_JOIN: | ||
411 | encode_step_key(buffer, offset, &(body->join.key), length); | ||
412 | break; | ||
413 | case GNUNET_MESSENGER_KIND_NAME: | ||
414 | if (body->name.name) | ||
415 | encode_step_ext(buffer, offset, body->name.name, min(length - offset, strlen(body->name.name))); | ||
416 | break; | ||
417 | case GNUNET_MESSENGER_KIND_KEY: | ||
418 | encode_step_key(buffer, offset, &(body->key.key), length); | ||
419 | break; | ||
420 | case GNUNET_MESSENGER_KIND_PEER: | ||
421 | encode_step(buffer, offset, &(body->peer.peer)); | ||
422 | break; | ||
423 | case GNUNET_MESSENGER_KIND_ID: | ||
424 | encode_step(buffer, offset, &(body->id.id)); | ||
425 | break; | ||
426 | case GNUNET_MESSENGER_KIND_MISS: | ||
427 | encode_step(buffer, offset, &(body->miss.peer)); | ||
428 | break; | ||
429 | case GNUNET_MESSENGER_KIND_MERGE: | ||
430 | encode_step(buffer, offset, &(body->merge.previous)); | ||
431 | break; | ||
432 | case GNUNET_MESSENGER_KIND_REQUEST: | ||
433 | encode_step(buffer, offset, &(body->request.hash)); | ||
434 | break; | ||
435 | case GNUNET_MESSENGER_KIND_INVITE: | ||
436 | encode_step(buffer, offset, &(body->invite.door)); | ||
437 | encode_step(buffer, offset, &(body->invite.key)); | ||
438 | break; | ||
439 | case GNUNET_MESSENGER_KIND_TEXT: | ||
440 | encode_step_ext(buffer, offset, body->text.text, min(length - offset, strlen(body->text.text))); | ||
441 | break; | ||
442 | case GNUNET_MESSENGER_KIND_FILE: | ||
443 | encode_step(buffer, offset, &(body->file.key)); | ||
444 | encode_step(buffer, offset, &(body->file.hash)); | ||
445 | encode_step_ext(buffer, offset, body->file.name, sizeof(body->file.name)); | ||
446 | encode_step_ext(buffer, offset, body->file.uri, min(length - offset, strlen(body->file.uri))); | ||
447 | break; | ||
448 | case GNUNET_MESSENGER_KIND_PRIVATE: | ||
449 | encode_step(buffer, offset, &(body->privacy.key)); | ||
450 | encode_step_ext(buffer, offset, body->privacy.data, min(length - offset, body->privacy.length)); | ||
451 | break; | ||
452 | case GNUNET_MESSENGER_KIND_DELETE: | ||
453 | encode_step(buffer, offset, &(body->deletion.hash)); | ||
454 | encode_step(buffer, offset, &(body->deletion.delay)); | ||
455 | break; | ||
456 | default: | ||
457 | break; | ||
458 | } | ||
459 | |||
460 | if (offset >= length) | ||
461 | return; | ||
462 | |||
463 | const uint16_t padding = length - offset; | ||
464 | const uint16_t used_padding = sizeof(padding) + sizeof(char); | ||
465 | |||
466 | GNUNET_assert(padding >= used_padding); | ||
467 | |||
468 | buffer[offset++] = '\0'; | ||
469 | |||
470 | if (padding > used_padding) | ||
471 | GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, buffer + offset, padding - used_padding); | ||
472 | |||
473 | GNUNET_memcpy(buffer + length - sizeof(padding), &padding, sizeof(padding)); | ||
474 | } | ||
475 | |||
476 | void | ||
477 | encode_message (const struct GNUNET_MESSENGER_Message *message, | ||
478 | uint16_t length, | ||
479 | char *buffer, | ||
480 | int include_header) | ||
481 | { | ||
482 | GNUNET_assert((message) && (buffer)); | ||
483 | |||
484 | uint16_t offset = 0; | ||
485 | |||
486 | if (GNUNET_YES == include_header) | ||
487 | encode_step_signature(buffer, offset, &(message->header.signature), length); | ||
488 | |||
489 | const kind_t kind = GNUNET_htobe32((kind_t) message->header.kind); | ||
490 | |||
491 | if (GNUNET_YES == include_header) | ||
492 | { | ||
493 | encode_step(buffer, offset, &(message->header.timestamp)); | ||
494 | encode_step(buffer, offset, &(message->header.sender_id)); | ||
495 | encode_step(buffer, offset, &(message->header.previous)); | ||
496 | } | ||
497 | |||
498 | encode_step(buffer, offset, &kind); | ||
499 | |||
500 | encode_message_body (message->header.kind, &(message->body), length, buffer, offset); | ||
501 | } | ||
502 | |||
503 | static void | ||
504 | encode_short_message (const struct GNUNET_MESSENGER_ShortMessage *message, | ||
505 | uint16_t length, | ||
506 | char *buffer) | ||
507 | { | ||
508 | struct GNUNET_HashCode hash; | ||
509 | uint16_t offset = sizeof(hash); | ||
510 | |||
511 | const kind_t kind = GNUNET_htobe32((kind_t) message->kind); | ||
512 | |||
513 | encode_step(buffer, offset, &kind); | ||
514 | |||
515 | encode_message_body (message->kind, &(message->body), length, buffer, offset); | ||
516 | |||
517 | GNUNET_CRYPTO_hash( | ||
518 | buffer + sizeof(hash), | ||
519 | length - sizeof(hash), | ||
520 | &hash | ||
521 | ); | ||
522 | |||
523 | GNUNET_memcpy(buffer, &hash, sizeof(hash)); | ||
524 | } | ||
525 | |||
526 | #define decode_step_ext(src, offset, dst, size) do { \ | ||
527 | GNUNET_memcpy(dst, src + offset, size); \ | ||
528 | offset += size; \ | ||
529 | } while (0) | ||
530 | |||
531 | #define decode_step(src, offset, dst) do { \ | ||
532 | decode_step_ext(src, offset, dst, sizeof(*dst)); \ | ||
533 | } while (0) | ||
534 | |||
535 | #define decode_step_malloc(src, offset, dst, size, zero) do { \ | ||
536 | dst = GNUNET_malloc(size + zero); \ | ||
537 | if (zero) dst[size] = 0; \ | ||
538 | decode_step_ext(src, offset, dst, size); \ | ||
539 | } while (0) | ||
540 | |||
541 | #define decode_step_key(src, offset, dst, length) do { \ | ||
542 | ssize_t result = GNUNET_IDENTITY_read_key_from_buffer( \ | ||
543 | dst, src + offset, length - offset \ | ||
544 | ); \ | ||
545 | if (result < 0) \ | ||
546 | GNUNET_break(0); \ | ||
547 | else \ | ||
548 | offset += result; \ | ||
549 | } while (0) | ||
550 | |||
551 | static uint16_t | ||
552 | decode_message_body (enum GNUNET_MESSENGER_MessageKind *kind, | ||
553 | struct GNUNET_MESSENGER_MessageBody *body, | ||
554 | uint16_t length, | ||
555 | const char *buffer, | ||
556 | uint16_t offset) | ||
557 | { | ||
558 | uint16_t padding = 0; | ||
559 | |||
560 | GNUNET_memcpy(&padding, buffer + length - sizeof(padding), sizeof(padding)); | ||
561 | |||
562 | if (padding > length - offset) | ||
563 | padding = 0; | ||
564 | |||
565 | const uint16_t end_zero = length - padding; | ||
566 | |||
567 | if ((padding) && (buffer[end_zero] != '\0')) | ||
568 | padding = 0; | ||
569 | |||
570 | length -= padding; | ||
571 | |||
572 | uint32_t version; | ||
573 | switch (*kind) | ||
574 | { | ||
575 | case GNUNET_MESSENGER_KIND_INFO: { | ||
576 | decode_step_key(buffer, offset, &(body->info.host_key), length); | ||
577 | decode_step(buffer, offset, &version); | ||
578 | |||
579 | body->info.messenger_version = GNUNET_be32toh(version); | ||
580 | break; | ||
581 | } case GNUNET_MESSENGER_KIND_JOIN: { | ||
582 | decode_step_key(buffer, offset, &(body->join.key), length); | ||
583 | break; | ||
584 | } case GNUNET_MESSENGER_KIND_NAME: | ||
585 | if (length - offset > 0) | ||
586 | decode_step_malloc(buffer, offset, body->name.name, length - offset, 1); | ||
587 | else | ||
588 | body->name.name = NULL; | ||
589 | break; | ||
590 | case GNUNET_MESSENGER_KIND_KEY: | ||
591 | decode_step_key(buffer, offset, &(body->key.key), length); | ||
592 | break; | ||
593 | case GNUNET_MESSENGER_KIND_PEER: | ||
594 | decode_step(buffer, offset, &(body->peer.peer)); | ||
595 | break; | ||
596 | case GNUNET_MESSENGER_KIND_ID: | ||
597 | decode_step(buffer, offset, &(body->id.id)); | ||
598 | break; | ||
599 | case GNUNET_MESSENGER_KIND_MISS: | ||
600 | decode_step(buffer, offset, &(body->miss.peer)); | ||
601 | break; | ||
602 | case GNUNET_MESSENGER_KIND_MERGE: | ||
603 | decode_step(buffer, offset, &(body->merge.previous)); | ||
604 | break; | ||
605 | case GNUNET_MESSENGER_KIND_REQUEST: | ||
606 | decode_step(buffer, offset, &(body->request.hash)); | ||
607 | break; | ||
608 | case GNUNET_MESSENGER_KIND_INVITE: | ||
609 | decode_step(buffer, offset, &(body->invite.door)); | ||
610 | decode_step(buffer, offset, &(body->invite.key)); | ||
611 | break; | ||
612 | case GNUNET_MESSENGER_KIND_TEXT: | ||
613 | decode_step_malloc(buffer, offset, body->text.text, length - offset, 1); | ||
614 | break; | ||
615 | case GNUNET_MESSENGER_KIND_FILE: | ||
616 | decode_step(buffer, offset, &(body->file.key)); | ||
617 | decode_step(buffer, offset, &(body->file.hash)); | ||
618 | decode_step_ext(buffer, offset, body->file.name, sizeof(body->file.name)); | ||
619 | decode_step_malloc(buffer, offset, body->file.uri, length - offset, 1); | ||
620 | break; | ||
621 | case GNUNET_MESSENGER_KIND_PRIVATE: | ||
622 | decode_step(buffer, offset, &(body->privacy.key)); | ||
623 | |||
624 | body->privacy.length = (length - offset); | ||
625 | decode_step_malloc(buffer, offset, body->privacy.data, length - offset, 0); | ||
626 | break; | ||
627 | case GNUNET_MESSENGER_KIND_DELETE: | ||
628 | decode_step(buffer, offset, &(body->deletion.hash)); | ||
629 | decode_step(buffer, offset, &(body->deletion.delay)); | ||
630 | break; | ||
631 | default: | ||
632 | *kind = GNUNET_MESSENGER_KIND_UNKNOWN; | ||
633 | break; | ||
634 | } | ||
635 | |||
636 | return padding; | ||
637 | } | ||
638 | |||
639 | int | ||
640 | decode_message (struct GNUNET_MESSENGER_Message *message, | ||
641 | uint16_t length, | ||
642 | const char *buffer, | ||
643 | int include_header, | ||
644 | uint16_t *padding) | ||
645 | { | ||
646 | GNUNET_assert( | ||
647 | (message) && | ||
648 | (buffer) && | ||
649 | (length >= get_message_kind_size(GNUNET_MESSENGER_KIND_UNKNOWN, include_header)) | ||
650 | ); | ||
651 | |||
652 | uint16_t offset = 0; | ||
653 | |||
654 | if (GNUNET_YES == include_header) | ||
655 | { | ||
656 | ssize_t result = GNUNET_IDENTITY_read_signature_from_buffer( | ||
657 | &(message->header.signature), buffer, length - offset | ||
658 | ); | ||
659 | |||
660 | if (result < 0) | ||
661 | return GNUNET_NO; | ||
662 | else | ||
663 | offset += result; | ||
664 | } | ||
665 | |||
666 | const uint16_t count = length - offset; | ||
667 | |||
668 | if (count < get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN, include_header)) | ||
669 | return GNUNET_NO; | ||
670 | |||
671 | kind_t kind; | ||
672 | |||
673 | if (GNUNET_YES == include_header) | ||
674 | { | ||
675 | decode_step(buffer, offset, &(message->header.timestamp)); | ||
676 | decode_step(buffer, offset, &(message->header.sender_id)); | ||
677 | decode_step(buffer, offset, &(message->header.previous)); | ||
678 | } | ||
679 | |||
680 | decode_step(buffer, offset, &kind); | ||
681 | |||
682 | message->header.kind = (enum GNUNET_MESSENGER_MessageKind) GNUNET_be32toh(kind); | ||
683 | |||
684 | if (count < get_message_kind_size (message->header.kind, include_header)) | ||
685 | return GNUNET_NO; | ||
686 | |||
687 | const uint16_t result = decode_message_body (&(message->header.kind), &(message->body), length, buffer, offset); | ||
688 | |||
689 | if (padding) | ||
690 | *padding = result; | ||
691 | |||
692 | return GNUNET_YES; | ||
693 | } | ||
694 | |||
695 | static int | ||
696 | decode_short_message (struct GNUNET_MESSENGER_ShortMessage *message, | ||
697 | uint16_t length, | ||
698 | const char *buffer) | ||
699 | { | ||
700 | struct GNUNET_HashCode expected, hash; | ||
701 | uint16_t offset = sizeof(hash); | ||
702 | |||
703 | if (length < get_short_message_size (NULL, GNUNET_NO)) | ||
704 | return GNUNET_NO; | ||
705 | |||
706 | GNUNET_memcpy(&hash, buffer, sizeof(hash)); | ||
707 | |||
708 | GNUNET_CRYPTO_hash( | ||
709 | buffer + sizeof(hash), | ||
710 | length - sizeof(hash), | ||
711 | &expected | ||
712 | ); | ||
713 | |||
714 | if (0 != GNUNET_CRYPTO_hash_cmp(&hash, &expected)) | ||
715 | return GNUNET_NO; | ||
716 | |||
717 | kind_t kind; | ||
718 | |||
719 | decode_step(buffer, offset, &kind); | ||
720 | |||
721 | message->kind = (enum GNUNET_MESSENGER_MessageKind) GNUNET_be32toh(kind); | ||
722 | |||
723 | if (length < get_short_message_size (message, GNUNET_NO)) | ||
724 | return GNUNET_NO; | ||
725 | |||
726 | decode_message_body (&(message->kind), &(message->body), length, buffer, offset); | ||
727 | |||
728 | if (GNUNET_MESSENGER_KIND_UNKNOWN == message->kind) | ||
729 | return GNUNET_NO; | ||
730 | |||
731 | return GNUNET_YES; | ||
732 | } | ||
733 | |||
734 | void | ||
735 | hash_message (const struct GNUNET_MESSENGER_Message *message, | ||
736 | uint16_t length, | ||
737 | const char *buffer, | ||
738 | struct GNUNET_HashCode *hash) | ||
739 | { | ||
740 | GNUNET_assert((message) && (buffer) && (hash)); | ||
741 | |||
742 | const ssize_t offset = GNUNET_IDENTITY_signature_get_length( | ||
743 | &(message->header.signature) | ||
744 | ); | ||
745 | |||
746 | GNUNET_CRYPTO_hash (buffer + offset, length - offset, hash); | ||
747 | } | ||
748 | |||
749 | void | ||
750 | sign_message (struct GNUNET_MESSENGER_Message *message, | ||
751 | uint16_t length, | ||
752 | char *buffer, | ||
753 | const struct GNUNET_HashCode *hash, | ||
754 | const struct GNUNET_MESSENGER_Ego *ego) | ||
755 | { | ||
756 | GNUNET_assert((message) && (buffer) && (hash) && (ego)); | ||
757 | |||
758 | struct GNUNET_MESSENGER_MessageSignature signature; | ||
759 | |||
760 | signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE); | ||
761 | signature.purpose.size = htonl (sizeof(signature)); | ||
762 | |||
763 | GNUNET_memcpy(&(signature.hash), hash, sizeof(struct GNUNET_HashCode)); | ||
764 | GNUNET_IDENTITY_sign(&(ego->priv), &signature, &(message->header.signature)); | ||
765 | |||
766 | uint16_t offset = 0; | ||
767 | encode_step_signature(buffer, offset, &(message->header.signature), length); | ||
768 | } | ||
769 | |||
770 | int | ||
771 | verify_message (const struct GNUNET_MESSENGER_Message *message, | ||
772 | const struct GNUNET_HashCode *hash, | ||
773 | const struct GNUNET_IDENTITY_PublicKey *key) | ||
774 | { | ||
775 | GNUNET_assert((message) && (hash) && (key)); | ||
776 | |||
777 | if (ntohl (key->type) != ntohl (message->header.signature.type)) | ||
778 | return GNUNET_SYSERR; | ||
779 | |||
780 | struct GNUNET_MESSENGER_MessageSignature signature; | ||
781 | |||
782 | signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE); | ||
783 | signature.purpose.size = htonl (sizeof(signature)); | ||
784 | |||
785 | GNUNET_memcpy(&(signature.hash), hash, sizeof(struct GNUNET_HashCode)); | ||
786 | |||
787 | return GNUNET_IDENTITY_signature_verify(GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE, &signature, | ||
788 | &(message->header.signature), key); | ||
789 | } | ||
790 | |||
791 | int | ||
792 | encrypt_message (struct GNUNET_MESSENGER_Message *message, | ||
793 | const struct GNUNET_IDENTITY_PublicKey *key) | ||
794 | { | ||
795 | GNUNET_assert((message) && (key)); | ||
796 | |||
797 | struct GNUNET_MESSENGER_ShortMessage shortened; | ||
798 | |||
799 | fold_short_message (message, &shortened); | ||
800 | |||
801 | const uint16_t length = get_short_message_size (&shortened, GNUNET_YES); | ||
802 | const uint16_t padded_length = calc_padded_length(length); | ||
803 | |||
804 | message->header.kind = GNUNET_MESSENGER_KIND_PRIVATE; | ||
805 | message->body.privacy.data = GNUNET_malloc(padded_length); | ||
806 | message->body.privacy.length = padded_length; | ||
807 | |||
808 | encode_short_message (&shortened, padded_length, message->body.privacy.data); | ||
809 | |||
810 | if (padded_length == GNUNET_IDENTITY_encrypt (message->body.privacy.data, padded_length, key, | ||
811 | &(message->body.privacy.key), | ||
812 | message->body.privacy.data)) | ||
813 | { | ||
814 | destroy_message_body (shortened.kind, &(shortened.body)); | ||
815 | return GNUNET_YES; | ||
816 | } | ||
817 | else | ||
818 | { | ||
819 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Encrypting message failed!\n"); | ||
820 | |||
821 | unfold_short_message (&shortened, message); | ||
822 | return GNUNET_NO; | ||
823 | } | ||
824 | } | ||
825 | |||
826 | int | ||
827 | decrypt_message (struct GNUNET_MESSENGER_Message *message, | ||
828 | const struct GNUNET_IDENTITY_PrivateKey *key) | ||
829 | { | ||
830 | GNUNET_assert((message) && (key)); | ||
831 | |||
832 | if (message->body.privacy.length != GNUNET_IDENTITY_decrypt (message->body.privacy.data, message->body.privacy.length, | ||
833 | key, &(message->body.privacy.key), | ||
834 | message->body.privacy.data)) | ||
835 | { | ||
836 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Decrypting message failed!\n"); | ||
837 | |||
838 | return GNUNET_NO; | ||
839 | } | ||
840 | |||
841 | struct GNUNET_MESSENGER_ShortMessage shortened; | ||
842 | |||
843 | if (GNUNET_YES != decode_short_message (&shortened, message->body.privacy.length, message->body.privacy.data)) | ||
844 | { | ||
845 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Decoding decrypted message failed!\n"); | ||
846 | |||
847 | return GNUNET_NO; | ||
848 | } | ||
849 | |||
850 | unfold_short_message (&shortened, message); | ||
851 | |||
852 | return GNUNET_YES; | ||
853 | } | ||
854 | |||
855 | struct GNUNET_MQ_Envelope* | ||
856 | pack_message (struct GNUNET_MESSENGER_Message *message, | ||
857 | struct GNUNET_HashCode *hash, | ||
858 | const struct GNUNET_MESSENGER_Ego *ego, | ||
859 | int mode) | ||
860 | { | ||
861 | GNUNET_assert(message); | ||
862 | |||
863 | if (ego) | ||
864 | message->header.signature.type = ego->priv.type; | ||
865 | |||
866 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Packing message kind=%u and sender: %s\n", | ||
867 | message->header.kind, GNUNET_sh2s(&(message->header.sender_id))); | ||
868 | |||
869 | struct GNUNET_MessageHeader *header; | ||
870 | |||
871 | const uint16_t length = get_message_size (message, GNUNET_YES); | ||
872 | const uint16_t padded_length = calc_padded_length(length); | ||
873 | |||
874 | struct GNUNET_MQ_Envelope *env; | ||
875 | char *buffer; | ||
876 | |||
877 | if (GNUNET_MESSENGER_PACK_MODE_ENVELOPE == mode) | ||
878 | { | ||
879 | env = GNUNET_MQ_msg_extra(header, padded_length, GNUNET_MESSAGE_TYPE_CADET_CLI); | ||
880 | |||
881 | buffer = (char*) &(header[1]); | ||
882 | } | ||
883 | else | ||
884 | { | ||
885 | env = NULL; | ||
886 | |||
887 | buffer = GNUNET_malloc(padded_length); | ||
888 | } | ||
889 | |||
890 | encode_message (message, padded_length, buffer, GNUNET_YES); | ||
891 | |||
892 | if (hash) | ||
893 | { | ||
894 | hash_message (message, length, buffer, hash); | ||
895 | |||
896 | if (ego) | ||
897 | sign_message (message, length, buffer, hash, ego); | ||
898 | } | ||
899 | |||
900 | if (GNUNET_MESSENGER_PACK_MODE_ENVELOPE != mode) | ||
901 | GNUNET_free(buffer); | ||
902 | |||
903 | return env; | ||
904 | } | ||
905 | |||
906 | int | ||
907 | filter_message_sending (const struct GNUNET_MESSENGER_Message *message) | ||
908 | { | ||
909 | switch (message->header.kind) | ||
910 | { | ||
911 | case GNUNET_MESSENGER_KIND_INFO: | ||
912 | return GNUNET_SYSERR; // Reserved for connection handling only! | ||
913 | case GNUNET_MESSENGER_KIND_JOIN: | ||
914 | return GNUNET_NO; // Use #GNUNET_MESSENGER_enter_room(...) instead! | ||
915 | case GNUNET_MESSENGER_KIND_LEAVE: | ||
916 | return GNUNET_NO; // Use #GNUNET_MESSENGER_close_room(...) instead! | ||
917 | case GNUNET_MESSENGER_KIND_NAME: | ||
918 | return GNUNET_YES; | ||
919 | case GNUNET_MESSENGER_KIND_KEY: | ||
920 | return GNUNET_NO; // Use #GNUNET_MESSENGER_update(...) instead! | ||
921 | case GNUNET_MESSENGER_KIND_PEER: | ||
922 | return GNUNET_NO; // Use #GNUNET_MESSENGER_open_room(...) instead! | ||
923 | case GNUNET_MESSENGER_KIND_ID: | ||
924 | return GNUNET_SYSERR; // Reserved for member id handling only! | ||
925 | case GNUNET_MESSENGER_KIND_MISS: | ||
926 | return GNUNET_SYSERR; // Reserved for connection handling only! | ||
927 | case GNUNET_MESSENGER_KIND_MERGE: | ||
928 | return GNUNET_YES; | ||
929 | case GNUNET_MESSENGER_KIND_REQUEST: | ||
930 | return GNUNET_YES; | ||
931 | case GNUNET_MESSENGER_KIND_INVITE: | ||
932 | return GNUNET_YES; | ||
933 | case GNUNET_MESSENGER_KIND_TEXT: | ||
934 | return GNUNET_YES; | ||
935 | case GNUNET_MESSENGER_KIND_FILE: | ||
936 | return GNUNET_YES; | ||
937 | case GNUNET_MESSENGER_KIND_PRIVATE: | ||
938 | return GNUNET_NO; // Use #GNUNET_MESSENGER_send_message(...) with a contact instead! | ||
939 | case GNUNET_MESSENGER_KIND_DELETE: | ||
940 | return GNUNET_YES; | ||
941 | default: | ||
942 | return GNUNET_SYSERR; | ||
943 | } | ||
944 | } | ||