aboutsummaryrefslogtreecommitdiff
path: root/src/core/gnunet-service-core_kx.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2023-10-18 14:31:24 +0200
committerMartin Schanzenbach <schanzen@gnunet.org>2023-10-18 14:31:24 +0200
commit2f93ff3b6d3524e1e6dc23f70966fbae3ca9d3af (patch)
tree8c9d286043722488bc12dd3881641d45ac782796 /src/core/gnunet-service-core_kx.c
parent1867346fd2615492fd1392849039f7cc621299f4 (diff)
downloadgnunet-2f93ff3b6d3524e1e6dc23f70966fbae3ca9d3af.tar.gz
gnunet-2f93ff3b6d3524e1e6dc23f70966fbae3ca9d3af.zip
BUILD: Move core to service/cli
Diffstat (limited to 'src/core/gnunet-service-core_kx.c')
-rw-r--r--src/core/gnunet-service-core_kx.c1934
1 files changed, 0 insertions, 1934 deletions
diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c
deleted file mode 100644
index ca7bccbd9..000000000
--- a/src/core/gnunet-service-core_kx.c
+++ /dev/null
@@ -1,1934 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 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/**
22 * @file core/gnunet-service-core_kx.c
23 * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other
24 * peers
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet-service-core_kx.h"
29#include "gnunet_transport_core_service.h"
30#include "gnunet-service-core_sessions.h"
31#include "gnunet-service-core.h"
32#include "gnunet_constants.h"
33#include "gnunet_signatures.h"
34#include "gnunet_protocols.h"
35
36/**
37 * Enable expensive (and possibly problematic for privacy!) logging of KX.
38 */
39#define DEBUG_KX 0
40
41/**
42 * How long do we wait for SET_KEY confirmation initially?
43 */
44#define INITIAL_SET_KEY_RETRY_FREQUENCY \
45 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
46
47/**
48 * What is the minimum frequency for a PING message?
49 */
50#define MIN_PING_FREQUENCY \
51 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
52
53/**
54 * How often do we rekey?
55 */
56#define REKEY_FREQUENCY \
57 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
58
59/**
60 * What time difference do we tolerate?
61 */
62#define REKEY_TOLERANCE \
63 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
64
65/**
66 * What is the maximum age of a message for us to consider processing
67 * it? Note that this looks at the timestamp used by the other peer,
68 * so clock skew between machines does come into play here. So this
69 * should be picked high enough so that a little bit of clock skew
70 * does not prevent peers from connecting to us.
71 */
72#define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS
73
74
75GNUNET_NETWORK_STRUCT_BEGIN
76
77/**
78 * Encapsulation for encrypted messages exchanged between
79 * peers. Followed by the actual encrypted data.
80 */
81struct EncryptedMessage
82{
83 /**
84 * Message type is #GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE.
85 */
86 struct GNUNET_MessageHeader header;
87
88 /**
89 * Random value used for IV generation.
90 */
91 uint32_t iv_seed GNUNET_PACKED;
92
93 /**
94 * MAC of the encrypted message (starting at @e sequence_number),
95 * used to verify message integrity. Everything after this value
96 * (excluding this value itself) will be encrypted and
97 * authenticated. #ENCRYPTED_HEADER_SIZE must be set to the offset
98 * of the *next* field.
99 */
100 struct GNUNET_HashCode hmac;
101
102 /**
103 * Sequence number, in network byte order. This field
104 * must be the first encrypted/decrypted field
105 */
106 uint32_t sequence_number GNUNET_PACKED;
107
108 /**
109 * Reserved, always zero.
110 */
111 uint32_t reserved GNUNET_PACKED;
112
113 /**
114 * Timestamp. Used to prevent replay of ancient messages
115 * (recent messages are caught with the sequence number).
116 */
117 struct GNUNET_TIME_AbsoluteNBO timestamp;
118};
119GNUNET_NETWORK_STRUCT_END
120
121
122/**
123 * Number of bytes (at the beginning) of `struct EncryptedMessage`
124 * that are NOT encrypted.
125 */
126#define ENCRYPTED_HEADER_SIZE \
127 (offsetof (struct EncryptedMessage, sequence_number))
128
129
130/**
131 * Information about the status of a key exchange with another peer.
132 */
133struct GSC_KeyExchangeInfo
134{
135 /**
136 * DLL.
137 */
138 struct GSC_KeyExchangeInfo *next;
139
140 /**
141 * DLL.
142 */
143 struct GSC_KeyExchangeInfo *prev;
144
145 /**
146 * Identity of the peer.
147 */
148 const struct GNUNET_PeerIdentity *peer;
149
150 /**
151 * Message queue for sending messages to @a peer.
152 */
153 struct GNUNET_MQ_Handle *mq;
154
155 /**
156 * Our message stream tokenizer (for encrypted payload).
157 */
158 struct GNUNET_MessageStreamTokenizer *mst;
159
160 /**
161 * PING message we transmit to the other peer.
162 */
163 struct PingMessage ping;
164
165 /**
166 * Ephemeral public ECC key of the other peer.
167 */
168 struct GNUNET_CRYPTO_EcdhePublicKey other_ephemeral_key;
169
170 /**
171 * Key we use to encrypt our messages for the other peer
172 * (initialized by us when we do the handshake).
173 */
174 struct GNUNET_CRYPTO_SymmetricSessionKey encrypt_key;
175
176 /**
177 * Key we use to decrypt messages from the other peer
178 * (given to us by the other peer during the handshake).
179 */
180 struct GNUNET_CRYPTO_SymmetricSessionKey decrypt_key;
181
182 /**
183 * At what time did the other peer generate the decryption key?
184 */
185 struct GNUNET_TIME_Absolute foreign_key_expires;
186
187 /**
188 * When should the session time out (if there are no PONGs)?
189 */
190 struct GNUNET_TIME_Absolute timeout;
191
192 /**
193 * What was the last timeout we informed our monitors about?
194 */
195 struct GNUNET_TIME_Absolute last_notify_timeout;
196
197 /**
198 * At what frequency are we currently re-trying SET_KEY messages?
199 */
200 struct GNUNET_TIME_Relative set_key_retry_frequency;
201
202 /**
203 * ID of task used for re-trying SET_KEY and PING message.
204 */
205 struct GNUNET_SCHEDULER_Task *retry_set_key_task;
206
207 /**
208 * ID of task used for sending keep-alive pings.
209 */
210 struct GNUNET_SCHEDULER_Task *keep_alive_task;
211
212 /**
213 * Bit map indicating which of the 32 sequence numbers before the
214 * last were received (good for accepting out-of-order packets and
215 * estimating reliability of the connection)
216 */
217 uint32_t last_packets_bitmap;
218
219 /**
220 * last sequence number received on this connection (highest)
221 */
222 uint32_t last_sequence_number_received;
223
224 /**
225 * last sequence number transmitted
226 */
227 uint32_t last_sequence_number_sent;
228
229 /**
230 * What was our PING challenge number (for this peer)?
231 */
232 uint32_t ping_challenge;
233
234 /**
235 * #GNUNET_YES if this peer currently has excess bandwidth.
236 */
237 int has_excess_bandwidth;
238
239 /**
240 * What is our connection status?
241 */
242 enum GNUNET_CORE_KxState status;
243};
244
245
246/**
247 * Transport service.
248 */
249static struct GNUNET_TRANSPORT_CoreHandle *transport;
250
251/**
252 * Our private key.
253 */
254static struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key;
255
256/**
257 * Our ephemeral private key.
258 */
259static struct GNUNET_CRYPTO_EcdhePrivateKey my_ephemeral_key;
260
261/**
262 * Current message we send for a key exchange.
263 */
264static struct EphemeralKeyMessage current_ekm;
265
266/**
267 * DLL head.
268 */
269static struct GSC_KeyExchangeInfo *kx_head;
270
271/**
272 * DLL tail.
273 */
274static struct GSC_KeyExchangeInfo *kx_tail;
275
276/**
277 * Task scheduled for periodic re-generation (and thus rekeying) of our
278 * ephemeral key.
279 */
280static struct GNUNET_SCHEDULER_Task *rekey_task;
281
282/**
283 * Notification context for broadcasting to monitors.
284 */
285static struct GNUNET_NotificationContext *nc;
286
287
288/**
289 * Calculate seed value we should use for a message.
290 *
291 * @param kx key exchange context
292 */
293static uint32_t
294calculate_seed (struct GSC_KeyExchangeInfo *kx)
295{
296 /* Note: may want to make this non-random and instead
297 derive from key material to avoid having an undetectable
298 side-channel */
299 return htonl (
300 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
301}
302
303
304/**
305 * Inform all monitors about the KX state of the given peer.
306 *
307 * @param kx key exchange state to inform about
308 */
309static void
310monitor_notify_all (struct GSC_KeyExchangeInfo *kx)
311{
312 struct MonitorNotifyMessage msg;
313
314 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
315 msg.header.size = htons (sizeof(msg));
316 msg.state = htonl ((uint32_t) kx->status);
317 msg.peer = *kx->peer;
318 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
319 GNUNET_notification_context_broadcast (nc, &msg.header, GNUNET_NO);
320 kx->last_notify_timeout = kx->timeout;
321}
322
323
324/**
325 * Derive an authentication key from "set key" information
326 *
327 * @param akey authentication key to derive
328 * @param skey session key to use
329 * @param seed seed to use
330 */
331static void
332derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
333 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
334 uint32_t seed)
335{
336 static const char ctx[] = "authentication key";
337
338#if DEBUG_KX
339 struct GNUNET_HashCode sh;
340
341 GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Deriving Auth key from SKEY %s and seed %u\n",
344 GNUNET_h2s (&sh),
345 (unsigned int) seed);
346#endif
347 GNUNET_CRYPTO_hmac_derive_key (akey,
348 skey,
349 &seed,
350 sizeof(seed),
351 skey,
352 sizeof(
353 struct GNUNET_CRYPTO_SymmetricSessionKey),
354 ctx,
355 sizeof(ctx),
356 NULL);
357}
358
359
360/**
361 * Derive an IV from packet information
362 *
363 * @param iv initialization vector to initialize
364 * @param skey session key to use
365 * @param seed seed to use
366 * @param identity identity of the other peer to use
367 */
368static void
369derive_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
370 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
371 uint32_t seed,
372 const struct GNUNET_PeerIdentity *identity)
373{
374 static const char ctx[] = "initialization vector";
375
376#if DEBUG_KX
377 struct GNUNET_HashCode sh;
378
379 GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
381 "Deriving IV from SKEY %s and seed %u for peer %s\n",
382 GNUNET_h2s (&sh),
383 (unsigned int) seed,
384 GNUNET_i2s (identity));
385#endif
386 GNUNET_CRYPTO_symmetric_derive_iv (iv,
387 skey,
388 &seed,
389 sizeof(seed),
390 identity,
391 sizeof(struct GNUNET_PeerIdentity),
392 ctx,
393 sizeof(ctx),
394 NULL);
395}
396
397
398/**
399 * Derive an IV from pong packet information
400 *
401 * @param iv initialization vector to initialize
402 * @param skey session key to use
403 * @param seed seed to use
404 * @param challenge nonce to use
405 * @param identity identity of the other peer to use
406 */
407static void
408derive_pong_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
409 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
410 uint32_t seed,
411 uint32_t challenge,
412 const struct GNUNET_PeerIdentity *identity)
413{
414 static const char ctx[] = "pong initialization vector";
415
416#if DEBUG_KX
417 struct GNUNET_HashCode sh;
418
419 GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "Deriving PONG IV from SKEY %s and seed %u/%u for %s\n",
422 GNUNET_h2s (&sh),
423 (unsigned int) seed,
424 (unsigned int) challenge,
425 GNUNET_i2s (identity));
426#endif
427 GNUNET_CRYPTO_symmetric_derive_iv (iv,
428 skey,
429 &seed,
430 sizeof(seed),
431 identity,
432 sizeof(struct GNUNET_PeerIdentity),
433 &challenge,
434 sizeof(challenge),
435 ctx,
436 sizeof(ctx),
437 NULL);
438}
439
440
441/**
442 * Derive an AES key from key material
443 *
444 * @param sender peer identity of the sender
445 * @param receiver peer identity of the sender
446 * @param key_material high entropy key material to use
447 * @param skey set to derived session key
448 */
449static void
450derive_aes_key (const struct GNUNET_PeerIdentity *sender,
451 const struct GNUNET_PeerIdentity *receiver,
452 const struct GNUNET_HashCode *key_material,
453 struct GNUNET_CRYPTO_SymmetricSessionKey *skey)
454{
455 static const char ctx[] = "aes key generation vector";
456
457#if DEBUG_KX
458 struct GNUNET_HashCode sh;
459
460 GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462 "Deriving AES Keys for %s to %s from %s\n",
463 GNUNET_i2s (sender),
464 GNUNET_i2s2 (receiver),
465 GNUNET_h2s (key_material));
466#endif
467 GNUNET_CRYPTO_kdf (skey,
468 sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
469 ctx,
470 sizeof(ctx),
471 key_material,
472 sizeof(struct GNUNET_HashCode),
473 sender,
474 sizeof(struct GNUNET_PeerIdentity),
475 receiver,
476 sizeof(struct GNUNET_PeerIdentity),
477 NULL);
478}
479
480
481/**
482 * Encrypt size bytes from @a in and write the result to @a out. Use the
483 * @a kx key for outbound traffic of the given neighbour.
484 *
485 * @param kx key information context
486 * @param iv initialization vector to use
487 * @param in ciphertext
488 * @param out plaintext
489 * @param size size of @a in / @a out
490 *
491 * @return #GNUNET_OK on success
492 */
493static int
494do_encrypt (struct GSC_KeyExchangeInfo *kx,
495 const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
496 const void *in,
497 void *out,
498 size_t size)
499{
500 if (size != (uint16_t) size)
501 {
502 GNUNET_break (0);
503 return GNUNET_NO;
504 }
505 GNUNET_assert (size == GNUNET_CRYPTO_symmetric_encrypt (in,
506 (uint16_t) size,
507 &kx->encrypt_key,
508 iv,
509 out));
510 GNUNET_STATISTICS_update (GSC_stats,
511 gettext_noop ("# bytes encrypted"),
512 size,
513 GNUNET_NO);
514 /* the following is too sensitive to write to log files by accident,
515 so we require manual intervention to get this one... */
516#if DEBUG_KX
517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518 "Encrypted %u bytes for `%s' using key %s, IV %u\n",
519 (unsigned int) size,
520 GNUNET_i2s (kx->peer),
521 kx->encrypt_key.aes_key,
522 GNUNET_CRYPTO_crc32_n (iv, sizeof(iv)));
523#endif
524 return GNUNET_OK;
525}
526
527
528/**
529 * Decrypt size bytes from @a in and write the result to @a out. Use
530 * the @a kx key for inbound traffic of the given neighbour. This
531 * function does NOT do any integrity-checks on the result.
532 *
533 * @param kx key information context
534 * @param iv initialization vector to use
535 * @param in ciphertext
536 * @param out plaintext
537 * @param size size of @a in / @a out
538 * @return #GNUNET_OK on success
539 */
540static int
541do_decrypt (struct GSC_KeyExchangeInfo *kx,
542 const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
543 const void *in,
544 void *out,
545 size_t size)
546{
547 if (size != (uint16_t) size)
548 {
549 GNUNET_break (0);
550 return GNUNET_NO;
551 }
552 if ((kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) &&
553 (kx->status != GNUNET_CORE_KX_STATE_UP) &&
554 (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT))
555 {
556 GNUNET_break_op (0);
557 return GNUNET_SYSERR;
558 }
559 if (size != GNUNET_CRYPTO_symmetric_decrypt (in,
560 (uint16_t) size,
561 &kx->decrypt_key,
562 iv,
563 out))
564 {
565 GNUNET_break (0);
566 return GNUNET_SYSERR;
567 }
568 GNUNET_STATISTICS_update (GSC_stats,
569 gettext_noop ("# bytes decrypted"),
570 size,
571 GNUNET_NO);
572 /* the following is too sensitive to write to log files by accident,
573 so we require manual intervention to get this one... */
574#if DEBUG_KX
575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576 "Decrypted %u bytes from `%s' using key %s, IV %u\n",
577 (unsigned int) size,
578 GNUNET_i2s (kx->peer),
579 kx->decrypt_key.aes_key,
580 GNUNET_CRYPTO_crc32_n (iv, sizeof(*iv)));
581#endif
582 return GNUNET_OK;
583}
584
585
586/**
587 * Send our key (and encrypted PING) to the other peer.
588 *
589 * @param kx key exchange context
590 */
591static void
592send_key (struct GSC_KeyExchangeInfo *kx);
593
594
595/**
596 * Task that will retry #send_key() if our previous attempt failed.
597 *
598 * @param cls our `struct GSC_KeyExchangeInfo`
599 */
600static void
601set_key_retry_task (void *cls)
602{
603 struct GSC_KeyExchangeInfo *kx = cls;
604
605 kx->retry_set_key_task = NULL;
606 kx->set_key_retry_frequency =
607 GNUNET_TIME_STD_BACKOFF (kx->set_key_retry_frequency);
608 GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
609 send_key (kx);
610}
611
612
613/**
614 * Create a fresh PING message for transmission to the other peer.
615 *
616 * @param kx key exchange context to create PING for
617 */
618static void
619setup_fresh_ping (struct GSC_KeyExchangeInfo *kx)
620{
621 struct PingMessage pp;
622 struct PingMessage *pm;
623 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
624
625 pm = &kx->ping;
626 kx->ping_challenge =
627 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
628 pm->header.size = htons (sizeof(struct PingMessage));
629 pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
630 pm->iv_seed = calculate_seed (kx);
631 derive_iv (&iv, &kx->encrypt_key, pm->iv_seed, kx->peer);
632 pp.challenge = kx->ping_challenge;
633 pp.target = *kx->peer;
634 do_encrypt (kx,
635 &iv,
636 &pp.target,
637 &pm->target,
638 sizeof(struct PingMessage)
639 - ((void *) &pm->target - (void *) pm));
640}
641
642
643/**
644 * Deliver P2P message to interested clients. Invokes send twice,
645 * once for clients that want the full message, and once for clients
646 * that only want the header
647 *
648 * @param cls the `struct GSC_KeyExchangeInfo`
649 * @param m the message
650 * @return #GNUNET_OK on success,
651 * #GNUNET_NO to stop further processing (no error)
652 * #GNUNET_SYSERR to stop further processing with error
653 */
654static int
655deliver_message (void *cls, const struct GNUNET_MessageHeader *m)
656{
657 struct GSC_KeyExchangeInfo *kx = cls;
658
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660 "Decrypted message of type %d from %s\n",
661 ntohs (m->type),
662 GNUNET_i2s (kx->peer));
663 if (GNUNET_CORE_KX_STATE_UP != kx->status)
664 {
665 GNUNET_STATISTICS_update (GSC_stats,
666 gettext_noop ("# PAYLOAD dropped (out of order)"),
667 1,
668 GNUNET_NO);
669 return GNUNET_OK;
670 }
671 switch (ntohs (m->type))
672 {
673 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
674 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
675 GSC_SESSIONS_set_typemap (kx->peer, m);
676 return GNUNET_OK;
677
678 case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
679 GSC_SESSIONS_confirm_typemap (kx->peer, m);
680 return GNUNET_OK;
681
682 default:
683 GSC_CLIENTS_deliver_message (kx->peer,
684 m,
685 ntohs (m->size),
686 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
687 GSC_CLIENTS_deliver_message (kx->peer,
688 m,
689 sizeof(struct GNUNET_MessageHeader),
690 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
691 }
692 return GNUNET_OK;
693}
694
695
696/**
697 * Function called by transport to notify us that
698 * a peer connected to us (on the network level).
699 * Starts the key exchange with the given peer.
700 *
701 * @param cls closure (NULL)
702 * @param pid identity of the peer to do a key exchange with
703 * @return key exchange information context
704 */
705static void *
706handle_transport_notify_connect (void *cls,
707 const struct GNUNET_PeerIdentity *pid,
708 struct GNUNET_MQ_Handle *mq)
709{
710 struct GSC_KeyExchangeInfo *kx;
711 struct GNUNET_HashCode h1;
712 struct GNUNET_HashCode h2;
713
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715 "Initiating key exchange with `%s'\n",
716 GNUNET_i2s (pid));
717 GNUNET_STATISTICS_update (GSC_stats,
718 gettext_noop ("# key exchanges initiated"),
719 1,
720 GNUNET_NO);
721 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
722 kx->mst = GNUNET_MST_create (&deliver_message, kx);
723 kx->mq = mq;
724 kx->peer = pid;
725 kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
726 GNUNET_CONTAINER_DLL_insert (kx_head, kx_tail, kx);
727 kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
728 monitor_notify_all (kx);
729 GNUNET_CRYPTO_hash (pid, sizeof(struct GNUNET_PeerIdentity), &h1);
730 GNUNET_CRYPTO_hash (&GSC_my_identity,
731 sizeof(struct GNUNET_PeerIdentity),
732 &h2);
733 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, &h2))
734 {
735 /* peer with "lower" identity starts KX, otherwise we typically end up
736 with both peers starting the exchange and transmit the 'set key'
737 message twice */
738 send_key (kx);
739 }
740 else
741 {
742 /* peer with "higher" identity starts a delayed KX, if the "lower" peer
743 * does not start a KX since it sees no reasons to do so */
744 kx->retry_set_key_task =
745 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
746 &set_key_retry_task,
747 kx);
748 }
749 return kx;
750}
751
752
753/**
754 * Function called by transport telling us that a peer
755 * disconnected.
756 * Stop key exchange with the given peer. Clean up key material.
757 *
758 * @param cls closure
759 * @param peer the peer that disconnected
760 * @param handler_cls the `struct GSC_KeyExchangeInfo` of the peer
761 */
762static void
763handle_transport_notify_disconnect (void *cls,
764 const struct GNUNET_PeerIdentity *peer,
765 void *handler_cls)
766{
767 struct GSC_KeyExchangeInfo *kx = handler_cls;
768
769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
770 "Peer `%s' disconnected from us.\n",
771 GNUNET_i2s (peer));
772 GSC_SESSIONS_end (kx->peer);
773 GNUNET_STATISTICS_update (GSC_stats,
774 gettext_noop ("# key exchanges stopped"),
775 1,
776 GNUNET_NO);
777 if (NULL != kx->retry_set_key_task)
778 {
779 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
780 kx->retry_set_key_task = NULL;
781 }
782 if (NULL != kx->keep_alive_task)
783 {
784 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
785 kx->keep_alive_task = NULL;
786 }
787 kx->status = GNUNET_CORE_KX_PEER_DISCONNECT;
788 monitor_notify_all (kx);
789 GNUNET_CONTAINER_DLL_remove (kx_head, kx_tail, kx);
790 GNUNET_MST_destroy (kx->mst);
791 GNUNET_free (kx);
792}
793
794
795/**
796 * Send our PING to the other peer.
797 *
798 * @param kx key exchange context
799 */
800static void
801send_ping (struct GSC_KeyExchangeInfo *kx)
802{
803 struct GNUNET_MQ_Envelope *env;
804
805 GNUNET_STATISTICS_update (GSC_stats,
806 gettext_noop ("# PING messages transmitted"),
807 1,
808 GNUNET_NO);
809 env = GNUNET_MQ_msg_copy (&kx->ping.header);
810 GNUNET_MQ_send (kx->mq, env);
811}
812
813
814/**
815 * Derive fresh session keys from the current ephemeral keys.
816 *
817 * @param kx session to derive keys for
818 */
819static void
820derive_session_keys (struct GSC_KeyExchangeInfo *kx)
821{
822 struct GNUNET_HashCode key_material;
823
824 if (GNUNET_OK !=
825 GNUNET_CRYPTO_ecc_ecdh (&my_ephemeral_key,
826 &kx->other_ephemeral_key,
827 &key_material))
828 {
829 GNUNET_break (0);
830 return;
831 }
832 derive_aes_key (&GSC_my_identity, kx->peer, &key_material, &kx->encrypt_key);
833 derive_aes_key (kx->peer, &GSC_my_identity, &key_material, &kx->decrypt_key);
834 memset (&key_material, 0, sizeof(key_material));
835 /* fresh key, reset sequence numbers */
836 kx->last_sequence_number_received = 0;
837 kx->last_packets_bitmap = 0;
838 setup_fresh_ping (kx);
839}
840
841
842/**
843 * We received a #GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY message.
844 * Validate and update our key material and status.
845 *
846 * @param cls key exchange status for the corresponding peer
847 * @param m the set key message we received
848 */
849static void
850handle_ephemeral_key (void *cls, const struct EphemeralKeyMessage *m)
851{
852 struct GSC_KeyExchangeInfo *kx = cls;
853 struct GNUNET_TIME_Absolute start_t;
854 struct GNUNET_TIME_Absolute end_t;
855 struct GNUNET_TIME_Absolute now;
856 enum GNUNET_CORE_KxState sender_status;
857
858 end_t = GNUNET_TIME_absolute_ntoh (m->expiration_time);
859 if (((GNUNET_CORE_KX_STATE_KEY_RECEIVED == kx->status) ||
860 (GNUNET_CORE_KX_STATE_UP == kx->status) ||
861 (GNUNET_CORE_KX_STATE_REKEY_SENT == kx->status)) &&
862 (end_t.abs_value_us < kx->foreign_key_expires.abs_value_us))
863 {
864 GNUNET_STATISTICS_update (GSC_stats,
865 gettext_noop ("# old ephemeral keys ignored"),
866 1,
867 GNUNET_NO);
868 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
869 "Received expired EPHEMERAL_KEY from %s\n",
870 GNUNET_i2s (&m->origin_identity));
871 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
872 return;
873 }
874 if (0 == memcmp (&m->ephemeral_key,
875 &kx->other_ephemeral_key,
876 sizeof(m->ephemeral_key)))
877 {
878 GNUNET_STATISTICS_update (GSC_stats,
879 gettext_noop (
880 "# duplicate ephemeral keys ignored"),
881 1,
882 GNUNET_NO);
883 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
884 "Ignoring duplicate EPHEMERAL_KEY from %s\n",
885 GNUNET_i2s (&m->origin_identity));
886 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
887 return;
888 }
889 if (0 != memcmp (&m->origin_identity,
890 kx->peer,
891 sizeof(struct GNUNET_PeerIdentity)))
892 {
893 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
894 "Received EPHEMERAL_KEY from %s, but expected %s\n",
895 GNUNET_i2s (&m->origin_identity),
896 GNUNET_i2s_full (kx->peer));
897 GNUNET_break_op (0);
898 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
899 return;
900 }
901 if ((ntohl (m->purpose.size) !=
902 sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
903 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
904 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
905 + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
906 + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) ||
907 (GNUNET_OK !=
908 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY,
909 &m->purpose,
910 &m->signature,
911 &m->origin_identity.public_key)))
912 {
913 /* invalid signature */
914 GNUNET_break_op (0);
915 GNUNET_STATISTICS_update (GSC_stats,
916 gettext_noop (
917 "# EPHEMERAL_KEYs rejected (bad signature)"),
918 1,
919 GNUNET_NO);
920 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
921 "Received EPHEMERAL_KEY from %s with bad signature\n",
922 GNUNET_i2s (&m->origin_identity));
923 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
924 return;
925 }
926 now = GNUNET_TIME_absolute_get ();
927 start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
928 if ((end_t.abs_value_us <
929 GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value_us) ||
930 (start_t.abs_value_us >
931 GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value_us))
932 {
933 GNUNET_log (
934 GNUNET_ERROR_TYPE_WARNING,
935 _ (
936 "EPHEMERAL_KEY from peer `%s' rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"),
937 GNUNET_i2s (kx->peer),
938 (unsigned long long) now.abs_value_us,
939 (unsigned long long) start_t.abs_value_us,
940 (unsigned long long) end_t.abs_value_us);
941 GNUNET_STATISTICS_update (GSC_stats,
942 gettext_noop (
943 "# EPHEMERAL_KEY messages rejected due to time"),
944 1,
945 GNUNET_NO);
946 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
947 return;
948 }
949#if DEBUG_KX
950 {
951 struct GNUNET_HashCode eh;
952
953 GNUNET_CRYPTO_hash (&m->ephemeral_key, sizeof(m->ephemeral_key), &eh);
954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
955 "Received valid EPHEMERAL_KEY `%s' from `%s' in state %d.\n",
956 GNUNET_h2s (&eh),
957 GNUNET_i2s (kx->peer),
958 kx->status);
959 }
960#endif
961 GNUNET_STATISTICS_update (GSC_stats,
962 gettext_noop ("# valid ephemeral keys received"),
963 1,
964 GNUNET_NO);
965 kx->other_ephemeral_key = m->ephemeral_key;
966 kx->foreign_key_expires = end_t;
967 derive_session_keys (kx);
968
969 /* check if we still need to send the sender our key */
970 sender_status = (enum GNUNET_CORE_KxState) ntohl (m->sender_status);
971 switch (sender_status)
972 {
973 case GNUNET_CORE_KX_STATE_DOWN:
974 GNUNET_break_op (0);
975 break;
976
977 case GNUNET_CORE_KX_STATE_KEY_SENT:
978 /* fine, need to send our key after updating our status, see below */
979 GSC_SESSIONS_reinit (kx->peer);
980 break;
981
982 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
983 /* other peer already got our key, but typemap did go down */
984 GSC_SESSIONS_reinit (kx->peer);
985 break;
986
987 case GNUNET_CORE_KX_STATE_UP:
988 /* other peer already got our key, typemap NOT down */
989 break;
990
991 case GNUNET_CORE_KX_STATE_REKEY_SENT:
992 /* other peer already got our key, typemap NOT down */
993 break;
994
995 default:
996 GNUNET_break (0);
997 break;
998 }
999 /* check if we need to confirm everything is fine via PING + PONG */
1000 switch (kx->status)
1001 {
1002 case GNUNET_CORE_KX_STATE_DOWN:
1003 GNUNET_assert (NULL == kx->keep_alive_task);
1004 kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
1005 monitor_notify_all (kx);
1006 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1007 send_key (kx);
1008 else
1009 send_ping (kx);
1010 break;
1011
1012 case GNUNET_CORE_KX_STATE_KEY_SENT:
1013 GNUNET_assert (NULL == kx->keep_alive_task);
1014 kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
1015 monitor_notify_all (kx);
1016 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1017 send_key (kx);
1018 else
1019 send_ping (kx);
1020 break;
1021
1022 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1023 GNUNET_assert (NULL == kx->keep_alive_task);
1024 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1025 send_key (kx);
1026 else
1027 send_ping (kx);
1028 break;
1029
1030 case GNUNET_CORE_KX_STATE_UP:
1031 kx->status = GNUNET_CORE_KX_STATE_REKEY_SENT;
1032 monitor_notify_all (kx);
1033 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1034 send_key (kx);
1035 else
1036 send_ping (kx);
1037 break;
1038
1039 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1040 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1041 send_key (kx);
1042 else
1043 send_ping (kx);
1044 break;
1045
1046 default:
1047 GNUNET_break (0);
1048 break;
1049 }
1050 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1051}
1052
1053
1054/**
1055 * We received a PING message. Validate and transmit
1056 * a PONG message.
1057 *
1058 * @param cls key exchange status for the corresponding peer
1059 * @param m the encrypted PING message itself
1060 */
1061static void
1062handle_ping (void *cls, const struct PingMessage *m)
1063{
1064 struct GSC_KeyExchangeInfo *kx = cls;
1065 struct PingMessage t;
1066 struct PongMessage tx;
1067 struct PongMessage *tp;
1068 struct GNUNET_MQ_Envelope *env;
1069 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1070
1071 GNUNET_STATISTICS_update (GSC_stats,
1072 gettext_noop ("# PING messages received"),
1073 1,
1074 GNUNET_NO);
1075 if ((kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) &&
1076 (kx->status != GNUNET_CORE_KX_STATE_UP) &&
1077 (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT))
1078 {
1079 /* ignore */
1080 GNUNET_STATISTICS_update (GSC_stats,
1081 gettext_noop (
1082 "# PING messages dropped (out of order)"),
1083 1,
1084 GNUNET_NO);
1085 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1086 return;
1087 }
1088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089 "Core service receives PING request from `%s'.\n",
1090 GNUNET_i2s (kx->peer));
1091 derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity);
1092 if (GNUNET_OK != do_decrypt (kx,
1093 &iv,
1094 &m->target,
1095 &t.target,
1096 sizeof(struct PingMessage)
1097 - ((void *) &m->target - (void *) m)))
1098 {
1099 GNUNET_break_op (0);
1100 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1101 return;
1102 }
1103 if (0 !=
1104 memcmp (&t.target, &GSC_my_identity, sizeof(struct GNUNET_PeerIdentity)))
1105 {
1106 if (GNUNET_CORE_KX_STATE_REKEY_SENT != kx->status)
1107 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1108 "Decryption of PING from peer `%s' failed, PING for `%s'?\n",
1109 GNUNET_i2s (kx->peer),
1110 GNUNET_i2s2 (&t.target));
1111 else
1112 GNUNET_log (
1113 GNUNET_ERROR_TYPE_DEBUG,
1114 "Decryption of PING from peer `%s' failed after rekey (harmless)\n",
1115 GNUNET_i2s (kx->peer));
1116 GNUNET_break_op (0);
1117 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1118 return;
1119 }
1120 /* construct PONG */
1121 tx.reserved = 0;
1122 tx.challenge = t.challenge;
1123 tx.target = t.target;
1124 env = GNUNET_MQ_msg (tp, GNUNET_MESSAGE_TYPE_CORE_PONG);
1125 tp->iv_seed = calculate_seed (kx);
1126 derive_pong_iv (&iv, &kx->encrypt_key, tp->iv_seed, t.challenge, kx->peer);
1127 do_encrypt (kx,
1128 &iv,
1129 &tx.challenge,
1130 &tp->challenge,
1131 sizeof(struct PongMessage)
1132 - ((void *) &tp->challenge - (void *) tp));
1133 GNUNET_STATISTICS_update (GSC_stats,
1134 gettext_noop ("# PONG messages created"),
1135 1,
1136 GNUNET_NO);
1137 GNUNET_MQ_send (kx->mq, env);
1138}
1139
1140
1141/**
1142 * Task triggered when a neighbour entry is about to time out
1143 * (and we should prevent this by sending a PING).
1144 *
1145 * @param cls the `struct GSC_KeyExchangeInfo`
1146 */
1147static void
1148send_keep_alive (void *cls)
1149{
1150 struct GSC_KeyExchangeInfo *kx = cls;
1151 struct GNUNET_TIME_Relative retry;
1152 struct GNUNET_TIME_Relative left;
1153
1154 kx->keep_alive_task = NULL;
1155 left = GNUNET_TIME_absolute_get_remaining (kx->timeout);
1156 if (0 == left.rel_value_us)
1157 {
1158 GNUNET_STATISTICS_update (GSC_stats,
1159 gettext_noop ("# sessions terminated by timeout"),
1160 1,
1161 GNUNET_NO);
1162 GSC_SESSIONS_end (kx->peer);
1163 kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1164 monitor_notify_all (kx);
1165 send_key (kx);
1166 return;
1167 }
1168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1169 "Sending KEEPALIVE to `%s'\n",
1170 GNUNET_i2s (kx->peer));
1171 GNUNET_STATISTICS_update (GSC_stats,
1172 gettext_noop ("# keepalive messages sent"),
1173 1,
1174 GNUNET_NO);
1175 setup_fresh_ping (kx);
1176 send_ping (kx);
1177 retry = GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
1178 MIN_PING_FREQUENCY);
1179 kx->keep_alive_task =
1180 GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, kx);
1181}
1182
1183
1184/**
1185 * We've seen a valid message from the other peer.
1186 * Update the time when the session would time out
1187 * and delay sending our keep alive message further.
1188 *
1189 * @param kx key exchange where we saw activity
1190 */
1191static void
1192update_timeout (struct GSC_KeyExchangeInfo *kx)
1193{
1194 struct GNUNET_TIME_Relative delta;
1195
1196 kx->timeout =
1197 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1198 delta =
1199 GNUNET_TIME_absolute_get_difference (kx->last_notify_timeout, kx->timeout);
1200 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
1201 {
1202 /* we only notify monitors about timeout changes if those
1203 are bigger than the threshold (5s) */
1204 monitor_notify_all (kx);
1205 }
1206 if (NULL != kx->keep_alive_task)
1207 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1208 kx->keep_alive_task = GNUNET_SCHEDULER_add_delayed (
1209 GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
1210 &send_keep_alive,
1211 kx);
1212}
1213
1214
1215/**
1216 * We received a PONG message. Validate and update our status.
1217 *
1218 * @param kx key exchange context for the the PONG
1219 * @param m the encrypted PONG message itself
1220 */
1221static void
1222handle_pong (void *cls, const struct PongMessage *m)
1223{
1224 struct GSC_KeyExchangeInfo *kx = cls;
1225 struct PongMessage t;
1226 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1227
1228 GNUNET_STATISTICS_update (GSC_stats,
1229 gettext_noop ("# PONG messages received"),
1230 1,
1231 GNUNET_NO);
1232 switch (kx->status)
1233 {
1234 case GNUNET_CORE_KX_STATE_DOWN:
1235 GNUNET_STATISTICS_update (GSC_stats,
1236 gettext_noop (
1237 "# PONG messages dropped (connection down)"),
1238 1,
1239 GNUNET_NO);
1240 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1241 return;
1242
1243 case GNUNET_CORE_KX_STATE_KEY_SENT:
1244 GNUNET_STATISTICS_update (GSC_stats,
1245 gettext_noop (
1246 "# PONG messages dropped (out of order)"),
1247 1,
1248 GNUNET_NO);
1249 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1250 return;
1251
1252 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1253 break;
1254
1255 case GNUNET_CORE_KX_STATE_UP:
1256 break;
1257
1258 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1259 break;
1260
1261 default:
1262 GNUNET_break (0);
1263 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1264 return;
1265 }
1266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1267 "Core service receives PONG response from `%s'.\n",
1268 GNUNET_i2s (kx->peer));
1269 /* mark as garbage, just to be sure */
1270 memset (&t, 255, sizeof(t));
1271 derive_pong_iv (&iv,
1272 &kx->decrypt_key,
1273 m->iv_seed,
1274 kx->ping_challenge,
1275 &GSC_my_identity);
1276 if (GNUNET_OK != do_decrypt (kx,
1277 &iv,
1278 &m->challenge,
1279 &t.challenge,
1280 sizeof(struct PongMessage)
1281 - ((void *) &m->challenge - (void *) m)))
1282 {
1283 GNUNET_break_op (0);
1284 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1285 return;
1286 }
1287 GNUNET_STATISTICS_update (GSC_stats,
1288 gettext_noop ("# PONG messages decrypted"),
1289 1,
1290 GNUNET_NO);
1291 if ((0 !=
1292 memcmp (&t.target, kx->peer, sizeof(struct GNUNET_PeerIdentity))) ||
1293 (kx->ping_challenge != t.challenge))
1294 {
1295 /* PONG malformed */
1296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1297 "Received malformed PONG wanted sender `%s' with challenge %u\n",
1298 GNUNET_i2s (kx->peer),
1299 (unsigned int) kx->ping_challenge);
1300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1301 "Received malformed PONG received from `%s' with challenge %u\n",
1302 GNUNET_i2s (&t.target),
1303 (unsigned int) t.challenge);
1304 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1305 return;
1306 }
1307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1308 "Received valid PONG from `%s'\n",
1309 GNUNET_i2s (kx->peer));
1310 /* no need to resend key any longer */
1311 if (NULL != kx->retry_set_key_task)
1312 {
1313 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
1314 kx->retry_set_key_task = NULL;
1315 }
1316 switch (kx->status)
1317 {
1318 case GNUNET_CORE_KX_STATE_DOWN:
1319 GNUNET_assert (0); /* should be impossible */
1320 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1321 return;
1322
1323 case GNUNET_CORE_KX_STATE_KEY_SENT:
1324 GNUNET_assert (0); /* should be impossible */
1325 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1326 return;
1327
1328 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1329 GNUNET_STATISTICS_update (GSC_stats,
1330 gettext_noop (
1331 "# session keys confirmed via PONG"),
1332 1,
1333 GNUNET_NO);
1334 kx->status = GNUNET_CORE_KX_STATE_UP;
1335 monitor_notify_all (kx);
1336 GSC_SESSIONS_create (kx->peer, kx);
1337 GNUNET_assert (NULL == kx->keep_alive_task);
1338 update_timeout (kx);
1339 break;
1340
1341 case GNUNET_CORE_KX_STATE_UP:
1342 GNUNET_STATISTICS_update (GSC_stats,
1343 gettext_noop ("# timeouts prevented via PONG"),
1344 1,
1345 GNUNET_NO);
1346 update_timeout (kx);
1347 break;
1348
1349 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1350 GNUNET_STATISTICS_update (GSC_stats,
1351 gettext_noop (
1352 "# rekey operations confirmed via PONG"),
1353 1,
1354 GNUNET_NO);
1355 kx->status = GNUNET_CORE_KX_STATE_UP;
1356 monitor_notify_all (kx);
1357 update_timeout (kx);
1358 break;
1359
1360 default:
1361 GNUNET_break (0);
1362 break;
1363 }
1364}
1365
1366
1367/**
1368 * Send our key to the other peer.
1369 *
1370 * @param kx key exchange context
1371 */
1372static void
1373send_key (struct GSC_KeyExchangeInfo *kx)
1374{
1375 struct GNUNET_MQ_Envelope *env;
1376
1377 GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
1378 if (NULL != kx->retry_set_key_task)
1379 {
1380 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
1381 kx->retry_set_key_task = NULL;
1382 }
1383 /* always update sender status in SET KEY message */
1384#if DEBUG_KX
1385 {
1386 struct GNUNET_HashCode hc;
1387
1388 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1389 sizeof(current_ekm.ephemeral_key),
1390 &hc);
1391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1392 "Sending EPHEMERAL_KEY %s to `%s' (my status: %d)\n",
1393 GNUNET_h2s (&hc),
1394 GNUNET_i2s (kx->peer),
1395 kx->status);
1396 }
1397#endif
1398 current_ekm.sender_status = htonl ((int32_t) (kx->status));
1399 env = GNUNET_MQ_msg_copy (&current_ekm.header);
1400 GNUNET_MQ_send (kx->mq, env);
1401 if (GNUNET_CORE_KX_STATE_KEY_SENT != kx->status)
1402 send_ping (kx);
1403 kx->retry_set_key_task =
1404 GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency,
1405 &set_key_retry_task,
1406 kx);
1407}
1408
1409
1410void
1411GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
1412 const void *payload,
1413 size_t payload_size)
1414{
1415 size_t used = payload_size + sizeof(struct EncryptedMessage);
1416 char pbuf[used]; /* plaintext */
1417 struct EncryptedMessage *em; /* encrypted message */
1418 struct EncryptedMessage *ph; /* plaintext header */
1419 struct GNUNET_MQ_Envelope *env;
1420 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1421 struct GNUNET_CRYPTO_AuthKey auth_key;
1422
1423 ph = (struct EncryptedMessage *) pbuf;
1424 ph->sequence_number = htonl (++kx->last_sequence_number_sent);
1425 ph->iv_seed = calculate_seed (kx);
1426 ph->reserved = 0;
1427 ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1428 GNUNET_memcpy (&ph[1], payload, payload_size);
1429 env = GNUNET_MQ_msg_extra (em,
1430 payload_size,
1431 GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE);
1432 em->iv_seed = ph->iv_seed;
1433 derive_iv (&iv, &kx->encrypt_key, ph->iv_seed, kx->peer);
1434 GNUNET_assert (GNUNET_OK == do_encrypt (kx,
1435 &iv,
1436 &ph->sequence_number,
1437 &em->sequence_number,
1438 used - ENCRYPTED_HEADER_SIZE));
1439#if DEBUG_KX
1440 {
1441 struct GNUNET_HashCode hc;
1442
1443 GNUNET_CRYPTO_hash (&ph->sequence_number,
1444 used - ENCRYPTED_HEADER_SIZE,
1445 &hc);
1446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447 "Encrypted payload `%s' of %u bytes for %s\n",
1448 GNUNET_h2s (&hc),
1449 (unsigned int) (used - ENCRYPTED_HEADER_SIZE),
1450 GNUNET_i2s (kx->peer));
1451 }
1452#endif
1453 derive_auth_key (&auth_key, &kx->encrypt_key, ph->iv_seed);
1454 GNUNET_CRYPTO_hmac (&auth_key,
1455 &em->sequence_number,
1456 used - ENCRYPTED_HEADER_SIZE,
1457 &em->hmac);
1458#if DEBUG_KX
1459 {
1460 struct GNUNET_HashCode hc;
1461
1462 GNUNET_CRYPTO_hash (&auth_key, sizeof(auth_key), &hc);
1463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1464 "For peer %s, used AC %s to create hmac %s\n",
1465 GNUNET_i2s (kx->peer),
1466 GNUNET_h2s (&hc),
1467 GNUNET_h2s2 (&em->hmac));
1468 }
1469#endif
1470 kx->has_excess_bandwidth = GNUNET_NO;
1471 GNUNET_MQ_send (kx->mq, env);
1472}
1473
1474
1475/**
1476 * We received an encrypted message. Check that it is
1477 * well-formed (size-wise).
1478 *
1479 * @param cls key exchange context for encrypting the message
1480 * @param m encrypted message
1481 * @return #GNUNET_OK if @a msg is well-formed (size-wise)
1482 */
1483static int
1484check_encrypted (void *cls, const struct EncryptedMessage *m)
1485{
1486 uint16_t size = ntohs (m->header.size) - sizeof(*m);
1487
1488 if (size < sizeof(struct GNUNET_MessageHeader))
1489 {
1490 GNUNET_break_op (0);
1491 return GNUNET_SYSERR;
1492 }
1493 return GNUNET_OK;
1494}
1495
1496
1497/**
1498 * We received an encrypted message. Decrypt, validate and
1499 * pass on to the appropriate clients.
1500 *
1501 * @param cls key exchange context for encrypting the message
1502 * @param m encrypted message
1503 */
1504static void
1505handle_encrypted (void *cls, const struct EncryptedMessage *m)
1506{
1507 struct GSC_KeyExchangeInfo *kx = cls;
1508 struct EncryptedMessage *pt; /* plaintext */
1509 struct GNUNET_HashCode ph;
1510 uint32_t snum;
1511 struct GNUNET_TIME_Absolute t;
1512 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1513 struct GNUNET_CRYPTO_AuthKey auth_key;
1514 uint16_t size = ntohs (m->header.size);
1515 char buf[size] GNUNET_ALIGN;
1516
1517 if (GNUNET_CORE_KX_STATE_UP != kx->status)
1518 {
1519 GNUNET_STATISTICS_update (GSC_stats,
1520 gettext_noop (
1521 "# DATA message dropped (out of order)"),
1522 1,
1523 GNUNET_NO);
1524 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1525 return;
1526 }
1527 if (0 ==
1528 GNUNET_TIME_absolute_get_remaining (kx->foreign_key_expires).rel_value_us)
1529 {
1530 GNUNET_log (
1531 GNUNET_ERROR_TYPE_WARNING,
1532 _ (
1533 "Session to peer `%s' went down due to key expiration (should not happen)\n"),
1534 GNUNET_i2s (kx->peer));
1535 GNUNET_STATISTICS_update (GSC_stats,
1536 gettext_noop (
1537 "# sessions terminated by key expiration"),
1538 1,
1539 GNUNET_NO);
1540 GSC_SESSIONS_end (kx->peer);
1541 if (NULL != kx->keep_alive_task)
1542 {
1543 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1544 kx->keep_alive_task = NULL;
1545 }
1546 kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1547 monitor_notify_all (kx);
1548 send_key (kx);
1549 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1550 return;
1551 }
1552
1553 /* validate hash */
1554#if DEBUG_KX
1555 {
1556 struct GNUNET_HashCode hc;
1557
1558 GNUNET_CRYPTO_hash (&m->sequence_number, size - ENCRYPTED_HEADER_SIZE, &hc);
1559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1560 "Received encrypted payload `%s' of %u bytes from %s\n",
1561 GNUNET_h2s (&hc),
1562 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1563 GNUNET_i2s (kx->peer));
1564 }
1565#endif
1566 derive_auth_key (&auth_key, &kx->decrypt_key, m->iv_seed);
1567 GNUNET_CRYPTO_hmac (&auth_key,
1568 &m->sequence_number,
1569 size - ENCRYPTED_HEADER_SIZE,
1570 &ph);
1571#if DEBUG_KX
1572 {
1573 struct GNUNET_HashCode hc;
1574
1575 GNUNET_CRYPTO_hash (&auth_key, sizeof(auth_key), &hc);
1576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1577 "For peer %s, used AC %s to verify hmac %s\n",
1578 GNUNET_i2s (kx->peer),
1579 GNUNET_h2s (&hc),
1580 GNUNET_h2s2 (&m->hmac));
1581 }
1582#endif
1583 if (0 != memcmp (&ph, &m->hmac, sizeof(struct GNUNET_HashCode)))
1584 {
1585 /* checksum failed */
1586 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1587 "Failed checksum validation for a message from `%s'\n",
1588 GNUNET_i2s (kx->peer));
1589 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1590 return;
1591 }
1592 derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity);
1593 /* decrypt */
1594 if (GNUNET_OK != do_decrypt (kx,
1595 &iv,
1596 &m->sequence_number,
1597 &buf[ENCRYPTED_HEADER_SIZE],
1598 size - ENCRYPTED_HEADER_SIZE))
1599 {
1600 GNUNET_break_op (0);
1601 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1602 return;
1603 }
1604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1605 "Decrypted %u bytes from %s\n",
1606 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1607 GNUNET_i2s (kx->peer));
1608 pt = (struct EncryptedMessage *) buf;
1609
1610 /* validate sequence number */
1611 snum = ntohl (pt->sequence_number);
1612 if (kx->last_sequence_number_received == snum)
1613 {
1614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1615 "Received duplicate message, ignoring.\n");
1616 /* duplicate, ignore */
1617 GNUNET_STATISTICS_update (GSC_stats,
1618 gettext_noop ("# bytes dropped (duplicates)"),
1619 size,
1620 GNUNET_NO);
1621 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1622 return;
1623 }
1624 if ((kx->last_sequence_number_received > snum) &&
1625 (kx->last_sequence_number_received - snum > 32))
1626 {
1627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1628 "Received ancient out of sequence message, ignoring.\n");
1629 /* ancient out of sequence, ignore */
1630 GNUNET_STATISTICS_update (GSC_stats,
1631 gettext_noop (
1632 "# bytes dropped (out of sequence)"),
1633 size,
1634 GNUNET_NO);
1635 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1636 return;
1637 }
1638 if (kx->last_sequence_number_received > snum)
1639 {
1640 uint32_t rotbit = 1U << (kx->last_sequence_number_received - snum - 1);
1641
1642 if ((kx->last_packets_bitmap & rotbit) != 0)
1643 {
1644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1645 "Received duplicate message, ignoring.\n");
1646 GNUNET_STATISTICS_update (GSC_stats,
1647 gettext_noop ("# bytes dropped (duplicates)"),
1648 size,
1649 GNUNET_NO);
1650 /* duplicate, ignore */
1651 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1652 return;
1653 }
1654 kx->last_packets_bitmap |= rotbit;
1655 }
1656 if (kx->last_sequence_number_received < snum)
1657 {
1658 unsigned int shift = (snum - kx->last_sequence_number_received);
1659
1660 if (shift >= 8 * sizeof(kx->last_packets_bitmap))
1661 kx->last_packets_bitmap = 0;
1662 else
1663 kx->last_packets_bitmap <<= shift;
1664 kx->last_sequence_number_received = snum;
1665 }
1666
1667 /* check timestamp */
1668 t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
1669 if (GNUNET_TIME_absolute_get_duration (t).rel_value_us >
1670 MAX_MESSAGE_AGE.rel_value_us)
1671 {
1672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1673 "Message received far too old (%s). Content ignored.\n",
1674 GNUNET_STRINGS_relative_time_to_string (
1675 GNUNET_TIME_absolute_get_duration (t),
1676 GNUNET_YES));
1677 GNUNET_STATISTICS_update (GSC_stats,
1678 gettext_noop (
1679 "# bytes dropped (ancient message)"),
1680 size,
1681 GNUNET_NO);
1682 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1683 return;
1684 }
1685
1686 /* process decrypted message(s) */
1687 update_timeout (kx);
1688 GNUNET_STATISTICS_update (GSC_stats,
1689 gettext_noop ("# bytes of payload decrypted"),
1690 size - sizeof(struct EncryptedMessage),
1691 GNUNET_NO);
1692 if (GNUNET_OK !=
1693 GNUNET_MST_from_buffer (kx->mst,
1694 &buf[sizeof(struct EncryptedMessage)],
1695 size - sizeof(struct EncryptedMessage),
1696 GNUNET_YES,
1697 GNUNET_NO))
1698 GNUNET_break_op (0);
1699
1700 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1701}
1702
1703
1704/**
1705 * Setup the message that links the ephemeral key to our persistent
1706 * public key and generate the appropriate signature.
1707 */
1708static void
1709sign_ephemeral_key ()
1710{
1711 current_ekm.header.size = htons (sizeof(struct EphemeralKeyMessage));
1712 current_ekm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY);
1713 current_ekm.sender_status = 0; /* to be set later */
1714 current_ekm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY);
1715 current_ekm.purpose.size =
1716 htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
1717 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1718 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1719 + sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)
1720 + sizeof(struct GNUNET_PeerIdentity));
1721 current_ekm.creation_time =
1722 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1723 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (GSC_cfg,
1724 "core",
1725 "USE_EPHEMERAL_KEYS"))
1726 {
1727 current_ekm.expiration_time =
1728 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (
1729 GNUNET_TIME_relative_add (REKEY_FREQUENCY,
1730 REKEY_TOLERANCE)));
1731 }
1732 else
1733 {
1734 current_ekm.expiration_time =
1735 GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
1736 }
1737 GNUNET_CRYPTO_ecdhe_key_get_public (&my_ephemeral_key,
1738 &current_ekm.ephemeral_key);
1739 current_ekm.origin_identity = GSC_my_identity;
1740 GNUNET_assert (GNUNET_OK ==
1741 GNUNET_CRYPTO_eddsa_sign_ (&my_private_key,
1742 &current_ekm.purpose,
1743 &current_ekm.signature));
1744}
1745
1746
1747/**
1748 * Task run to trigger rekeying.
1749 *
1750 * @param cls closure, NULL
1751 */
1752static void
1753do_rekey (void *cls)
1754{
1755 struct GSC_KeyExchangeInfo *pos;
1756
1757 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &do_rekey, NULL);
1758 GNUNET_CRYPTO_ecdhe_key_create (&my_ephemeral_key);
1759 sign_ephemeral_key ();
1760 {
1761 struct GNUNET_HashCode eh;
1762
1763 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1764 sizeof(current_ekm.ephemeral_key),
1765 &eh);
1766 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Rekeying to %s\n", GNUNET_h2s (&eh));
1767 }
1768 for (pos = kx_head; NULL != pos; pos = pos->next)
1769 {
1770 if (GNUNET_CORE_KX_STATE_UP == pos->status)
1771 {
1772 pos->status = GNUNET_CORE_KX_STATE_REKEY_SENT;
1773 monitor_notify_all (pos);
1774 derive_session_keys (pos);
1775 }
1776 if (GNUNET_CORE_KX_STATE_DOWN == pos->status)
1777 {
1778 pos->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1779 monitor_notify_all (pos);
1780 }
1781 monitor_notify_all (pos);
1782 send_key (pos);
1783 }
1784}
1785
1786
1787/**
1788 * Initialize KX subsystem.
1789 *
1790 * @param pk private key to use for the peer
1791 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1792 */
1793int
1794GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
1795{
1796 struct GNUNET_MQ_MessageHandler handlers[] = {
1797 GNUNET_MQ_hd_fixed_size (ephemeral_key,
1798 GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY,
1799 struct EphemeralKeyMessage,
1800 NULL),
1801 GNUNET_MQ_hd_fixed_size (ping,
1802 GNUNET_MESSAGE_TYPE_CORE_PING,
1803 struct PingMessage,
1804 NULL),
1805 GNUNET_MQ_hd_fixed_size (pong,
1806 GNUNET_MESSAGE_TYPE_CORE_PONG,
1807 struct PongMessage,
1808 NULL),
1809 GNUNET_MQ_hd_var_size (encrypted,
1810 GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE,
1811 struct EncryptedMessage,
1812 NULL),
1813 GNUNET_MQ_handler_end ()
1814 };
1815
1816 my_private_key = *pk;
1817 GNUNET_CRYPTO_eddsa_key_get_public (&my_private_key,
1818 &GSC_my_identity.public_key);
1819 GNUNET_CRYPTO_ecdhe_key_create (&my_ephemeral_key);
1820 sign_ephemeral_key ();
1821 {
1822 struct GNUNET_HashCode eh;
1823
1824 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1825 sizeof(current_ekm.ephemeral_key),
1826 &eh);
1827 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1828 "Starting with ephemeral key %s\n",
1829 GNUNET_h2s (&eh));
1830 }
1831
1832 nc = GNUNET_notification_context_create (1);
1833 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &do_rekey, NULL);
1834 transport =
1835 GNUNET_TRANSPORT_core_connect (GSC_cfg,
1836 &GSC_my_identity,
1837 handlers,
1838 NULL,
1839 &handle_transport_notify_connect,
1840 &handle_transport_notify_disconnect);
1841 if (NULL == transport)
1842 {
1843 GSC_KX_done ();
1844 return GNUNET_SYSERR;
1845 }
1846 return GNUNET_OK;
1847}
1848
1849
1850/**
1851 * Shutdown KX subsystem.
1852 */
1853void
1854GSC_KX_done ()
1855{
1856 if (NULL != transport)
1857 {
1858 GNUNET_TRANSPORT_core_disconnect (transport);
1859 transport = NULL;
1860 }
1861 if (NULL != rekey_task)
1862 {
1863 GNUNET_SCHEDULER_cancel (rekey_task);
1864 rekey_task = NULL;
1865 }
1866 memset (&my_ephemeral_key,
1867 0,
1868 sizeof (my_ephemeral_key));
1869 memset (&my_private_key,
1870 0,
1871 sizeof (my_private_key));
1872 if (NULL != nc)
1873 {
1874 GNUNET_notification_context_destroy (nc);
1875 nc = NULL;
1876 }
1877}
1878
1879
1880/**
1881 * Check how many messages are queued for the given neighbour.
1882 *
1883 * @param kxinfo data about neighbour to check
1884 * @return number of items in the message queue
1885 */
1886unsigned int
1887GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *kxinfo)
1888{
1889 return GNUNET_MQ_get_length (kxinfo->mq);
1890}
1891
1892
1893int
1894GSC_NEIGHBOURS_check_excess_bandwidth (const struct GSC_KeyExchangeInfo *kxinfo)
1895{
1896 return kxinfo->has_excess_bandwidth;
1897}
1898
1899
1900/**
1901 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
1902 * request type, the client does not have to have transmitted an INIT
1903 * request. All current peers are returned, regardless of which
1904 * message types they accept.
1905 *
1906 * @param mq message queue to add for monitoring
1907 */
1908void
1909GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq)
1910{
1911 struct GNUNET_MQ_Envelope *env;
1912 struct MonitorNotifyMessage *done_msg;
1913 struct GSC_KeyExchangeInfo *kx;
1914
1915 GNUNET_notification_context_add (nc, mq);
1916 for (kx = kx_head; NULL != kx; kx = kx->next)
1917 {
1918 struct GNUNET_MQ_Envelope *env;
1919 struct MonitorNotifyMessage *msg;
1920
1921 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
1922 msg->state = htonl ((uint32_t) kx->status);
1923 msg->peer = *kx->peer;
1924 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
1925 GNUNET_MQ_send (mq, env);
1926 }
1927 env = GNUNET_MQ_msg (done_msg, GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
1928 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
1929 done_msg->timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
1930 GNUNET_MQ_send (mq, env);
1931}
1932
1933
1934/* end of gnunet-service-core_kx.c */