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