2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
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.
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.
17 * @file core/gnunet-service-core_kx.c
18 * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other peers
19 * @author Christian Grothoff
22 #include "gnunet-service-core_kx.h"
23 #include "gnunet-service-core.h"
24 #include "gnunet-service-core_sessions.h"
25 #include "gnunet_statistics_service.h"
26 #include "gnunet_transport_core_service.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_signatures.h"
29 #include "gnunet_protocols.h"
33 * Enable expensive (and possibly problematic for privacy!) logging of KX.
38 * How long do we wait for SET_KEY confirmation initially?
40 #define INITIAL_SET_KEY_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
43 * What is the minimum frequency for a PING message?
45 #define MIN_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
48 * How often do we rekey?
50 #define REKEY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
53 * What time difference do we tolerate?
55 #define REKEY_TOLERANCE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
58 * What is the maximum age of a message for us to consider processing
59 * it? Note that this looks at the timestamp used by the other peer,
60 * so clock skew between machines does come into play here. So this
61 * should be picked high enough so that a little bit of clock skew
62 * does not prevent peers from connecting to us.
64 #define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS
68 GNUNET_NETWORK_STRUCT_BEGIN
71 * Message transmitted with the signed ephemeral key of a peer. The
72 * session key is then derived from the two ephemeral keys (ECDHE).
74 struct EphemeralKeyMessage
78 * Message type is #GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY.
80 struct GNUNET_MessageHeader header;
83 * Status of the sender (should be in `enum PeerStateMachine`), nbo.
85 int32_t sender_status GNUNET_PACKED;
88 * An ECC signature of the @e origin_identity asserting the validity
89 * of the given ephemeral key.
91 struct GNUNET_CRYPTO_EddsaSignature signature;
94 * Information about what is being signed.
96 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
99 * At what time was this key created (beginning of validity).
101 struct GNUNET_TIME_AbsoluteNBO creation_time;
104 * When does the given ephemeral key expire (end of validity).
106 struct GNUNET_TIME_AbsoluteNBO expiration_time;
109 * Ephemeral public ECC key.
111 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
114 * Public key of the signing peer (persistent version, not the
115 * ephemeral public key).
117 struct GNUNET_PeerIdentity origin_identity;
123 * We're sending an (encrypted) PING to the other peer to check if he
124 * can decrypt. The other peer should respond with a PONG with the
125 * same content, except this time encrypted with the receiver's key.
130 * Message type is #GNUNET_MESSAGE_TYPE_CORE_PING.
132 struct GNUNET_MessageHeader header;
137 uint32_t iv_seed GNUNET_PACKED;
140 * Intended target of the PING, used primarily to check
141 * that decryption actually worked.
143 struct GNUNET_PeerIdentity target;
146 * Random number chosen to make replay harder.
148 uint32_t challenge GNUNET_PACKED;
153 * Response to a PING. Includes data from the original PING.
158 * Message type is #GNUNET_MESSAGE_TYPE_CORE_PONG.
160 struct GNUNET_MessageHeader header;
165 uint32_t iv_seed GNUNET_PACKED;
168 * Random number to make replay attacks harder.
170 uint32_t challenge GNUNET_PACKED;
173 * Reserved, always zero.
178 * Intended target of the PING, used primarily to check
179 * that decryption actually worked.
181 struct GNUNET_PeerIdentity target;
186 * Encapsulation for encrypted messages exchanged between
187 * peers. Followed by the actual encrypted data.
189 struct EncryptedMessage
192 * Message type is #GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE.
194 struct GNUNET_MessageHeader header;
197 * Random value used for IV generation.
199 uint32_t iv_seed GNUNET_PACKED;
202 * MAC of the encrypted message (starting at @e sequence_number),
203 * used to verify message integrity. Everything after this value
204 * (excluding this value itself) will be encrypted and
205 * authenticated. #ENCRYPTED_HEADER_SIZE must be set to the offset
206 * of the *next* field.
208 struct GNUNET_HashCode hmac;
211 * Sequence number, in network byte order. This field
212 * must be the first encrypted/decrypted field
214 uint32_t sequence_number GNUNET_PACKED;
217 * Reserved, always zero.
219 uint32_t reserved GNUNET_PACKED;
222 * Timestamp. Used to prevent replay of ancient messages
223 * (recent messages are caught with the sequence number).
225 struct GNUNET_TIME_AbsoluteNBO timestamp;
228 GNUNET_NETWORK_STRUCT_END
232 * Number of bytes (at the beginning) of `struct EncryptedMessage`
233 * that are NOT encrypted.
235 #define ENCRYPTED_HEADER_SIZE (offsetof(struct EncryptedMessage, sequence_number))
239 * Information about the status of a key exchange with another peer.
241 struct GSC_KeyExchangeInfo
247 struct GSC_KeyExchangeInfo *next;
252 struct GSC_KeyExchangeInfo *prev;
255 * Identity of the peer.
257 const struct GNUNET_PeerIdentity *peer;
260 * Message queue for sending messages to @a peer.
262 struct GNUNET_MQ_Handle *mq;
265 * Our message stream tokenizer (for encrypted payload).
267 struct GNUNET_MessageStreamTokenizer *mst;
270 * PING message we transmit to the other peer.
272 struct PingMessage ping;
275 * Ephemeral public ECC key of the other peer.
277 struct GNUNET_CRYPTO_EcdhePublicKey other_ephemeral_key;
280 * Key we use to encrypt our messages for the other peer
281 * (initialized by us when we do the handshake).
283 struct GNUNET_CRYPTO_SymmetricSessionKey encrypt_key;
286 * Key we use to decrypt messages from the other peer
287 * (given to us by the other peer during the handshake).
289 struct GNUNET_CRYPTO_SymmetricSessionKey decrypt_key;
292 * At what time did the other peer generate the decryption key?
294 struct GNUNET_TIME_Absolute foreign_key_expires;
297 * When should the session time out (if there are no PONGs)?
299 struct GNUNET_TIME_Absolute timeout;
302 * What was the last timeout we informed our monitors about?
304 struct GNUNET_TIME_Absolute last_notify_timeout;
307 * At what frequency are we currently re-trying SET_KEY messages?
309 struct GNUNET_TIME_Relative set_key_retry_frequency;
312 * ID of task used for re-trying SET_KEY and PING message.
314 struct GNUNET_SCHEDULER_Task *retry_set_key_task;
317 * ID of task used for sending keep-alive pings.
319 struct GNUNET_SCHEDULER_Task *keep_alive_task;
322 * Bit map indicating which of the 32 sequence numbers before the
323 * last were received (good for accepting out-of-order packets and
324 * estimating reliability of the connection)
326 uint32_t last_packets_bitmap;
329 * last sequence number received on this connection (highest)
331 uint32_t last_sequence_number_received;
334 * last sequence number transmitted
336 uint32_t last_sequence_number_sent;
339 * What was our PING challenge number (for this peer)?
341 uint32_t ping_challenge;
344 * #GNUNET_YES if this peer currently has excess bandwidth.
346 int has_excess_bandwidth;
349 * What is our connection status?
351 enum GNUNET_CORE_KxState status;
359 static struct GNUNET_TRANSPORT_CoreHandle *transport;
364 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
367 * Our ephemeral private key.
369 static struct GNUNET_CRYPTO_EcdhePrivateKey *my_ephemeral_key;
372 * Current message we send for a key exchange.
374 static struct EphemeralKeyMessage current_ekm;
379 static struct GSC_KeyExchangeInfo *kx_head;
384 static struct GSC_KeyExchangeInfo *kx_tail;
387 * Task scheduled for periodic re-generation (and thus rekeying) of our
390 static struct GNUNET_SCHEDULER_Task *rekey_task;
393 * Notification context for broadcasting to monitors.
395 static struct GNUNET_NotificationContext *nc;
399 * Calculate seed value we should use for a message.
401 * @param kx key exchange context
404 calculate_seed (struct GSC_KeyExchangeInfo *kx)
406 /* Note: may want to make this non-random and instead
407 derive from key material to avoid having an undetectable
409 return htonl (GNUNET_CRYPTO_random_u32
410 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
415 * Inform all monitors about the KX state of the given peer.
417 * @param kx key exchange state to inform about
420 monitor_notify_all (struct GSC_KeyExchangeInfo *kx)
422 struct MonitorNotifyMessage msg;
424 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
425 msg.header.size = htons (sizeof (msg));
426 msg.state = htonl ((uint32_t) kx->status);
427 msg.peer = *kx->peer;
428 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
429 GNUNET_notification_context_broadcast (nc,
432 kx->last_notify_timeout = kx->timeout;
437 * Derive an authentication key from "set key" information
439 * @param akey authentication key to derive
440 * @param skey session key to use
441 * @param seed seed to use
444 derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
445 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
448 static const char ctx[] = "authentication key";
450 struct GNUNET_HashCode sh;
452 GNUNET_CRYPTO_hash (skey,
455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456 "Deriving Auth key from SKEY %s and seed %u\n",
458 (unsigned int) seed);
460 GNUNET_CRYPTO_hmac_derive_key (akey,
462 &seed, sizeof (seed),
463 skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
470 * Derive an IV from packet information
472 * @param iv initialization vector to initialize
473 * @param skey session key to use
474 * @param seed seed to use
475 * @param identity identity of the other peer to use
478 derive_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
479 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
481 const struct GNUNET_PeerIdentity *identity)
483 static const char ctx[] = "initialization vector";
485 struct GNUNET_HashCode sh;
487 GNUNET_CRYPTO_hash (skey,
490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
491 "Deriving IV from SKEY %s and seed %u for peer %s\n",
494 GNUNET_i2s (identity));
496 GNUNET_CRYPTO_symmetric_derive_iv (iv,
498 &seed, sizeof (seed),
500 sizeof (struct GNUNET_PeerIdentity), ctx,
506 * Derive an IV from pong packet information
508 * @param iv initialization vector to initialize
509 * @param skey session key to use
510 * @param seed seed to use
511 * @param challenge nonce to use
512 * @param identity identity of the other peer to use
515 derive_pong_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
516 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
519 const struct GNUNET_PeerIdentity *identity)
521 static const char ctx[] = "pong initialization vector";
523 struct GNUNET_HashCode sh;
525 GNUNET_CRYPTO_hash (skey,
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 "Deriving PONG IV from SKEY %s and seed %u/%u for %s\n",
532 (unsigned int) challenge,
533 GNUNET_i2s (identity));
535 GNUNET_CRYPTO_symmetric_derive_iv (iv,
537 &seed, sizeof (seed),
539 sizeof (struct GNUNET_PeerIdentity),
540 &challenge, sizeof (challenge),
547 * Derive an AES key from key material
549 * @param sender peer identity of the sender
550 * @param receiver peer identity of the sender
551 * @param key_material high entropy key material to use
552 * @param skey set to derived session key
555 derive_aes_key (const struct GNUNET_PeerIdentity *sender,
556 const struct GNUNET_PeerIdentity *receiver,
557 const struct GNUNET_HashCode *key_material,
558 struct GNUNET_CRYPTO_SymmetricSessionKey *skey)
560 static const char ctx[] = "aes key generation vector";
562 struct GNUNET_HashCode sh;
564 GNUNET_CRYPTO_hash (skey,
567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
568 "Deriving AES Keys for %s to %s from %s\n",
570 GNUNET_i2s2 (receiver),
571 GNUNET_h2s (key_material));
573 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
575 key_material, sizeof (struct GNUNET_HashCode),
576 sender, sizeof (struct GNUNET_PeerIdentity),
577 receiver, sizeof (struct GNUNET_PeerIdentity),
583 * Encrypt size bytes from @a in and write the result to @a out. Use the
584 * @a kx key for outbound traffic of the given neighbour.
586 * @param kx key information context
587 * @param iv initialization vector to use
588 * @param in ciphertext
589 * @param out plaintext
590 * @param size size of @a in/@a out
591 * @return #GNUNET_OK on success
594 do_encrypt (struct GSC_KeyExchangeInfo *kx,
595 const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
600 if (size != (uint16_t) size)
605 GNUNET_assert (size ==
606 GNUNET_CRYPTO_symmetric_encrypt (in,
611 GNUNET_STATISTICS_update (GSC_stats,
612 gettext_noop ("# bytes encrypted"),
615 /* the following is too sensitive to write to log files by accident,
616 so we require manual intervention to get this one... */
618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
619 "Encrypted %u bytes for `%s' using key %u, IV %u\n",
621 GNUNET_i2s (kx->peer),
622 (unsigned int) kx->encrypt_key.crc32,
623 GNUNET_CRYPTO_crc32_n (iv,
631 * Decrypt size bytes from @a in and write the result to @a out. Use
632 * the @a kx key for inbound traffic of the given neighbour. This
633 * function does NOT do any integrity-checks on the result.
635 * @param kx key information context
636 * @param iv initialization vector to use
637 * @param in ciphertext
638 * @param out plaintext
639 * @param size size of @a in / @a out
640 * @return #GNUNET_OK on success
643 do_decrypt (struct GSC_KeyExchangeInfo *kx,
644 const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
649 if (size != (uint16_t) size)
654 if ( (kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) &&
655 (kx->status != GNUNET_CORE_KX_STATE_UP) &&
656 (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT) )
659 return GNUNET_SYSERR;
662 GNUNET_CRYPTO_symmetric_decrypt (in,
669 return GNUNET_SYSERR;
671 GNUNET_STATISTICS_update (GSC_stats,
672 gettext_noop ("# bytes decrypted"),
675 /* the following is too sensitive to write to log files by accident,
676 so we require manual intervention to get this one... */
678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
679 "Decrypted %u bytes from `%s' using key %u, IV %u\n",
681 GNUNET_i2s (kx->peer),
682 (unsigned int) kx->decrypt_key.crc32,
683 GNUNET_CRYPTO_crc32_n (iv,
692 * Send our key (and encrypted PING) to the other peer.
694 * @param kx key exchange context
697 send_key (struct GSC_KeyExchangeInfo *kx);
701 * Task that will retry #send_key() if our previous attempt failed.
703 * @param cls our `struct GSC_KeyExchangeInfo`
706 set_key_retry_task (void *cls)
708 struct GSC_KeyExchangeInfo *kx = cls;
710 kx->retry_set_key_task = NULL;
711 kx->set_key_retry_frequency = GNUNET_TIME_STD_BACKOFF (kx->set_key_retry_frequency);
712 GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
718 * Create a fresh PING message for transmission to the other peer.
720 * @param kx key exchange context to create PING for
723 setup_fresh_ping (struct GSC_KeyExchangeInfo *kx)
725 struct PingMessage pp;
726 struct PingMessage *pm;
727 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
730 kx->ping_challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
732 pm->header.size = htons (sizeof (struct PingMessage));
733 pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
734 pm->iv_seed = calculate_seed (kx);
739 pp.challenge = kx->ping_challenge;
740 pp.target = *kx->peer;
745 sizeof (struct PingMessage) - ((void *) &pm->target -
751 * Deliver P2P message to interested clients. Invokes send twice,
752 * once for clients that want the full message, and once for clients
753 * that only want the header
755 * @param cls the `struct GSC_KeyExchangeInfo`
756 * @param m the message
757 * @return #GNUNET_OK on success,
758 * #GNUNET_NO to stop further processing (no error)
759 * #GNUNET_SYSERR to stop further processing with error
762 deliver_message (void *cls,
763 const struct GNUNET_MessageHeader *m)
765 struct GSC_KeyExchangeInfo *kx = cls;
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768 "Decrypted message of type %d from %s\n",
770 GNUNET_i2s (kx->peer));
771 if (GNUNET_CORE_KX_STATE_UP != kx->status)
773 GNUNET_STATISTICS_update (GSC_stats,
774 gettext_noop ("# PAYLOAD dropped (out of order)"),
779 switch (ntohs (m->type))
781 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
782 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
783 GSC_SESSIONS_set_typemap (kx->peer, m);
785 case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
786 GSC_SESSIONS_confirm_typemap (kx->peer, m);
789 GSC_CLIENTS_deliver_message (kx->peer,
792 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
793 GSC_CLIENTS_deliver_message (kx->peer,
795 sizeof (struct GNUNET_MessageHeader),
796 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
803 * Function called by transport to notify us that
804 * a peer connected to us (on the network level).
805 * Starts the key exchange with the given peer.
807 * @param cls closure (NULL)
808 * @param pid identity of the peer to do a key exchange with
809 * @return key exchange information context
812 handle_transport_notify_connect (void *cls,
813 const struct GNUNET_PeerIdentity *pid,
814 struct GNUNET_MQ_Handle *mq)
816 struct GSC_KeyExchangeInfo *kx;
817 struct GNUNET_HashCode h1;
818 struct GNUNET_HashCode h2;
820 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
821 "Initiating key exchange with `%s'\n",
823 GNUNET_STATISTICS_update (GSC_stats,
824 gettext_noop ("# key exchanges initiated"),
827 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
828 kx->mst = GNUNET_MST_create (&deliver_message,
832 kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
833 GNUNET_CONTAINER_DLL_insert (kx_head,
836 kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
837 monitor_notify_all (kx);
838 GNUNET_CRYPTO_hash (pid,
839 sizeof (struct GNUNET_PeerIdentity),
841 GNUNET_CRYPTO_hash (&GSC_my_identity,
842 sizeof (struct GNUNET_PeerIdentity),
844 if (0 < GNUNET_CRYPTO_hash_cmp (&h1,
847 /* peer with "lower" identity starts KX, otherwise we typically end up
848 with both peers starting the exchange and transmit the 'set key'
854 /* peer with "higher" identity starts a delayed KX, if the "lower" peer
855 * does not start a KX since he sees no reasons to do so */
856 kx->retry_set_key_task
857 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
866 * Function called by transport telling us that a peer
868 * Stop key exchange with the given peer. Clean up key material.
871 * @param peer the peer that disconnected
872 * @param handler_cls the `struct GSC_KeyExchangeInfo` of the peer
875 handle_transport_notify_disconnect (void *cls,
876 const struct GNUNET_PeerIdentity *peer,
879 struct GSC_KeyExchangeInfo *kx = handler_cls;
881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
882 "Peer `%s' disconnected from us.\n",
884 GSC_SESSIONS_end (kx->peer);
885 GNUNET_STATISTICS_update (GSC_stats,
886 gettext_noop ("# key exchanges stopped"),
889 if (NULL != kx->retry_set_key_task)
891 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
892 kx->retry_set_key_task = NULL;
894 if (NULL != kx->keep_alive_task)
896 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
897 kx->keep_alive_task = NULL;
899 kx->status = GNUNET_CORE_KX_PEER_DISCONNECT;
900 monitor_notify_all (kx);
901 GNUNET_CONTAINER_DLL_remove (kx_head,
904 GNUNET_MST_destroy (kx->mst);
910 * Send our PING to the other peer.
912 * @param kx key exchange context
915 send_ping (struct GSC_KeyExchangeInfo *kx)
917 struct GNUNET_MQ_Envelope *env;
919 GNUNET_STATISTICS_update (GSC_stats,
920 gettext_noop ("# PING messages transmitted"),
923 env = GNUNET_MQ_msg_copy (&kx->ping.header);
924 GNUNET_MQ_send (kx->mq,
930 * Derive fresh session keys from the current ephemeral keys.
932 * @param kx session to derive keys for
935 derive_session_keys (struct GSC_KeyExchangeInfo *kx)
937 struct GNUNET_HashCode key_material;
940 GNUNET_CRYPTO_ecc_ecdh (my_ephemeral_key,
941 &kx->other_ephemeral_key,
947 derive_aes_key (&GSC_my_identity,
951 derive_aes_key (kx->peer,
955 memset (&key_material, 0, sizeof (key_material));
956 /* fresh key, reset sequence numbers */
957 kx->last_sequence_number_received = 0;
958 kx->last_packets_bitmap = 0;
959 setup_fresh_ping (kx);
964 * We received a #GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY message.
965 * Validate and update our key material and status.
967 * @param cls key exchange status for the corresponding peer
968 * @param m the set key message we received
971 handle_ephemeral_key (void *cls,
972 const struct EphemeralKeyMessage *m)
974 struct GSC_KeyExchangeInfo *kx = cls;
975 struct GNUNET_TIME_Absolute start_t;
976 struct GNUNET_TIME_Absolute end_t;
977 struct GNUNET_TIME_Absolute now;
978 enum GNUNET_CORE_KxState sender_status;
980 end_t = GNUNET_TIME_absolute_ntoh (m->expiration_time);
981 if ( ( (GNUNET_CORE_KX_STATE_KEY_RECEIVED == kx->status) ||
982 (GNUNET_CORE_KX_STATE_UP == kx->status) ||
983 (GNUNET_CORE_KX_STATE_REKEY_SENT == kx->status) ) &&
984 (end_t.abs_value_us < kx->foreign_key_expires.abs_value_us) )
986 GNUNET_STATISTICS_update (GSC_stats,
987 gettext_noop ("# old ephemeral keys ignored"),
990 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
991 "Received expired EPHEMERAL_KEY from %s\n",
992 GNUNET_i2s (&m->origin_identity));
995 if (0 == memcmp (&m->ephemeral_key,
996 &kx->other_ephemeral_key,
997 sizeof (m->ephemeral_key)))
999 GNUNET_STATISTICS_update (GSC_stats,
1000 gettext_noop ("# duplicate ephemeral keys ignored"),
1003 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1004 "Ignoring duplicate EPHEMERAL_KEY from %s\n",
1005 GNUNET_i2s (&m->origin_identity));
1009 memcmp (&m->origin_identity,
1011 sizeof (struct GNUNET_PeerIdentity)))
1013 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1014 "Received EPHEMERAL_KEY from %s, but expected %s\n",
1015 GNUNET_i2s (&m->origin_identity),
1016 GNUNET_i2s_full (kx->peer));
1017 GNUNET_break_op (0);
1020 if ((ntohl (m->purpose.size) !=
1021 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
1022 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
1023 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
1024 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
1025 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) ||
1027 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY,
1030 &m->origin_identity.public_key)))
1032 /* invalid signature */
1033 GNUNET_break_op (0);
1034 GNUNET_STATISTICS_update (GSC_stats,
1035 gettext_noop ("# EPHEMERAL_KEYs rejected (bad signature)"),
1038 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1039 "Received EPHEMERAL_KEY from %s with bad signature\n",
1040 GNUNET_i2s (&m->origin_identity));
1043 now = GNUNET_TIME_absolute_get ();
1044 start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
1045 if ( (end_t.abs_value_us < GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value_us) ||
1046 (start_t.abs_value_us > GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value_us) )
1048 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1049 _("EPHEMERAL_KEY from peer `%s' rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"),
1050 GNUNET_i2s (kx->peer),
1051 (unsigned long long) now.abs_value_us,
1052 (unsigned long long) start_t.abs_value_us,
1053 (unsigned long long) end_t.abs_value_us);
1054 GNUNET_STATISTICS_update (GSC_stats,
1055 gettext_noop ("# EPHEMERAL_KEY messages rejected due to time"),
1062 struct GNUNET_HashCode eh;
1064 GNUNET_CRYPTO_hash (&m->ephemeral_key,
1065 sizeof (m->ephemeral_key),
1067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068 "Received valid EPHEMERAL_KEY `%s' from `%s' in state %d.\n",
1070 GNUNET_i2s (kx->peer),
1074 GNUNET_STATISTICS_update (GSC_stats,
1075 gettext_noop ("# valid ephemeral keys received"),
1078 kx->other_ephemeral_key = m->ephemeral_key;
1079 kx->foreign_key_expires = end_t;
1080 derive_session_keys (kx);
1082 /* check if we still need to send the sender our key */
1083 sender_status = (enum GNUNET_CORE_KxState) ntohl (m->sender_status);
1084 switch (sender_status)
1086 case GNUNET_CORE_KX_STATE_DOWN:
1087 GNUNET_break_op (0);
1089 case GNUNET_CORE_KX_STATE_KEY_SENT:
1090 /* fine, need to send our key after updating our status, see below */
1091 GSC_SESSIONS_reinit (kx->peer);
1093 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1094 /* other peer already got our key, but typemap did go down */
1095 GSC_SESSIONS_reinit (kx->peer);
1097 case GNUNET_CORE_KX_STATE_UP:
1098 /* other peer already got our key, typemap NOT down */
1100 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1101 /* other peer already got our key, typemap NOT down */
1107 /* check if we need to confirm everything is fine via PING + PONG */
1110 case GNUNET_CORE_KX_STATE_DOWN:
1111 GNUNET_assert (NULL == kx->keep_alive_task);
1112 kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
1113 monitor_notify_all (kx);
1114 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1119 case GNUNET_CORE_KX_STATE_KEY_SENT:
1120 GNUNET_assert (NULL == kx->keep_alive_task);
1121 kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
1122 monitor_notify_all (kx);
1123 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1128 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1129 GNUNET_assert (NULL == kx->keep_alive_task);
1130 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1135 case GNUNET_CORE_KX_STATE_UP:
1136 kx->status = GNUNET_CORE_KX_STATE_REKEY_SENT;
1137 monitor_notify_all (kx);
1138 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1143 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1144 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1157 * We received a PING message. Validate and transmit
1160 * @param cls key exchange status for the corresponding peer
1161 * @param m the encrypted PING message itself
1164 handle_ping (void *cls,
1165 const struct PingMessage *m)
1167 struct GSC_KeyExchangeInfo *kx = cls;
1168 struct PingMessage t;
1169 struct PongMessage tx;
1170 struct PongMessage *tp;
1171 struct GNUNET_MQ_Envelope *env;
1172 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1174 GNUNET_STATISTICS_update (GSC_stats,
1175 gettext_noop ("# PING messages received"),
1178 if ( (kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) &&
1179 (kx->status != GNUNET_CORE_KX_STATE_UP) &&
1180 (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT))
1183 GNUNET_STATISTICS_update (GSC_stats,
1184 gettext_noop ("# PING messages dropped (out of order)"),
1189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1190 "Core service receives PING request from `%s'.\n",
1191 GNUNET_i2s (kx->peer));
1201 sizeof (struct PingMessage) - ((void *) &m->target -
1204 GNUNET_break_op (0);
1210 sizeof (struct GNUNET_PeerIdentity)))
1212 if (GNUNET_CORE_KX_STATE_REKEY_SENT != kx->status)
1213 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1214 "Decryption of PING from peer `%s' failed, PING for `%s'?\n",
1215 GNUNET_i2s (kx->peer),
1216 GNUNET_i2s2 (&t.target));
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "Decryption of PING from peer `%s' failed after rekey (harmless)\n",
1220 GNUNET_i2s (kx->peer));
1221 GNUNET_break_op (0);
1224 /* construct PONG */
1226 tx.challenge = t.challenge;
1227 tx.target = t.target;
1228 env = GNUNET_MQ_msg (tp,
1229 GNUNET_MESSAGE_TYPE_CORE_PONG);
1230 tp->iv_seed = calculate_seed (kx);
1231 derive_pong_iv (&iv,
1240 sizeof (struct PongMessage) - ((void *) &tp->challenge -
1242 GNUNET_STATISTICS_update (GSC_stats,
1243 gettext_noop ("# PONG messages created"),
1246 GNUNET_MQ_send (kx->mq,
1252 * Task triggered when a neighbour entry is about to time out
1253 * (and we should prevent this by sending a PING).
1255 * @param cls the `struct GSC_KeyExchangeInfo`
1258 send_keep_alive (void *cls)
1260 struct GSC_KeyExchangeInfo *kx = cls;
1261 struct GNUNET_TIME_Relative retry;
1262 struct GNUNET_TIME_Relative left;
1264 kx->keep_alive_task = NULL;
1265 left = GNUNET_TIME_absolute_get_remaining (kx->timeout);
1266 if (0 == left.rel_value_us)
1268 GNUNET_STATISTICS_update (GSC_stats,
1269 gettext_noop ("# sessions terminated by timeout"),
1272 GSC_SESSIONS_end (kx->peer);
1273 kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1274 monitor_notify_all (kx);
1278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1279 "Sending KEEPALIVE to `%s'\n",
1280 GNUNET_i2s (kx->peer));
1281 GNUNET_STATISTICS_update (GSC_stats,
1282 gettext_noop ("# keepalive messages sent"),
1285 setup_fresh_ping (kx);
1288 GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
1289 MIN_PING_FREQUENCY);
1290 kx->keep_alive_task =
1291 GNUNET_SCHEDULER_add_delayed (retry,
1298 * We've seen a valid message from the other peer.
1299 * Update the time when the session would time out
1300 * and delay sending our keep alive message further.
1302 * @param kx key exchange where we saw activity
1305 update_timeout (struct GSC_KeyExchangeInfo *kx)
1307 struct GNUNET_TIME_Relative delta;
1310 GNUNET_TIME_relative_to_absolute
1311 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1312 delta = GNUNET_TIME_absolute_get_difference (kx->last_notify_timeout,
1314 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
1316 /* we only notify monitors about timeout changes if those
1317 are bigger than the threshold (5s) */
1318 monitor_notify_all (kx);
1320 if (NULL != kx->keep_alive_task)
1321 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1322 kx->keep_alive_task =
1323 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
1324 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1332 * We received a PONG message. Validate and update our status.
1334 * @param kx key exchange context for the the PONG
1335 * @param m the encrypted PONG message itself
1338 handle_pong (void *cls,
1339 const struct PongMessage *m)
1341 struct GSC_KeyExchangeInfo *kx = cls;
1342 struct PongMessage t;
1343 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1345 GNUNET_STATISTICS_update (GSC_stats,
1346 gettext_noop ("# PONG messages received"),
1351 case GNUNET_CORE_KX_STATE_DOWN:
1352 GNUNET_STATISTICS_update (GSC_stats,
1353 gettext_noop ("# PONG messages dropped (connection down)"), 1,
1356 case GNUNET_CORE_KX_STATE_KEY_SENT:
1357 GNUNET_STATISTICS_update (GSC_stats,
1358 gettext_noop ("# PONG messages dropped (out of order)"), 1,
1361 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1363 case GNUNET_CORE_KX_STATE_UP:
1365 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1372 "Core service receives PONG response from `%s'.\n",
1373 GNUNET_i2s (kx->peer));
1374 /* mark as garbage, just to be sure */
1375 memset (&t, 255, sizeof (t));
1376 derive_pong_iv (&iv,
1386 sizeof (struct PongMessage) - ((void *) &m->challenge -
1389 GNUNET_break_op (0);
1392 GNUNET_STATISTICS_update (GSC_stats,
1393 gettext_noop ("# PONG messages decrypted"),
1396 if ((0 != memcmp (&t.target,
1398 sizeof (struct GNUNET_PeerIdentity))) ||
1399 (kx->ping_challenge != t.challenge))
1401 /* PONG malformed */
1402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1403 "Received malformed PONG wanted sender `%s' with challenge %u\n",
1404 GNUNET_i2s (kx->peer),
1405 (unsigned int) kx->ping_challenge);
1406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1407 "Received malformed PONG received from `%s' with challenge %u\n",
1408 GNUNET_i2s (&t.target),
1409 (unsigned int) t.challenge);
1412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1413 "Received valid PONG from `%s'\n",
1414 GNUNET_i2s (kx->peer));
1415 /* no need to resend key any longer */
1416 if (NULL != kx->retry_set_key_task)
1418 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
1419 kx->retry_set_key_task = NULL;
1423 case GNUNET_CORE_KX_STATE_DOWN:
1424 GNUNET_assert (0); /* should be impossible */
1426 case GNUNET_CORE_KX_STATE_KEY_SENT:
1427 GNUNET_assert (0); /* should be impossible */
1429 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1430 GNUNET_STATISTICS_update (GSC_stats,
1431 gettext_noop ("# session keys confirmed via PONG"),
1434 kx->status = GNUNET_CORE_KX_STATE_UP;
1435 monitor_notify_all (kx);
1436 GSC_SESSIONS_create (kx->peer, kx);
1437 GNUNET_assert (NULL == kx->keep_alive_task);
1438 update_timeout (kx);
1440 case GNUNET_CORE_KX_STATE_UP:
1441 GNUNET_STATISTICS_update (GSC_stats,
1442 gettext_noop ("# timeouts prevented via PONG"),
1445 update_timeout (kx);
1447 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1448 GNUNET_STATISTICS_update (GSC_stats,
1449 gettext_noop ("# rekey operations confirmed via PONG"),
1452 kx->status = GNUNET_CORE_KX_STATE_UP;
1453 monitor_notify_all (kx);
1454 update_timeout (kx);
1464 * Send our key to the other peer.
1466 * @param kx key exchange context
1469 send_key (struct GSC_KeyExchangeInfo *kx)
1471 struct GNUNET_MQ_Envelope *env;
1473 GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
1474 if (NULL != kx->retry_set_key_task)
1476 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
1477 kx->retry_set_key_task = NULL;
1479 /* always update sender status in SET KEY message */
1482 struct GNUNET_HashCode hc;
1484 GNUNET_CRYPTO_hash (¤t_ekm.ephemeral_key,
1485 sizeof (current_ekm.ephemeral_key),
1487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1488 "Sending EPHEMERAL_KEY %s to `%s' (my status: %d)\n",
1490 GNUNET_i2s (kx->peer),
1494 current_ekm.sender_status = htonl ((int32_t) (kx->status));
1495 env = GNUNET_MQ_msg_copy (¤t_ekm.header);
1496 GNUNET_MQ_send (kx->mq,
1498 if (GNUNET_CORE_KX_STATE_KEY_SENT != kx->status)
1500 kx->retry_set_key_task =
1501 GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency,
1502 &set_key_retry_task,
1508 * Encrypt and transmit a message with the given payload.
1510 * @param kx key exchange context
1511 * @param payload payload of the message
1512 * @param payload_size number of bytes in @a payload
1515 GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
1516 const void *payload,
1517 size_t payload_size)
1519 size_t used = payload_size + sizeof (struct EncryptedMessage);
1520 char pbuf[used]; /* plaintext */
1521 struct EncryptedMessage *em; /* encrypted message */
1522 struct EncryptedMessage *ph; /* plaintext header */
1523 struct GNUNET_MQ_Envelope *env;
1524 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1525 struct GNUNET_CRYPTO_AuthKey auth_key;
1527 ph = (struct EncryptedMessage *) pbuf;
1528 ph->sequence_number = htonl (++kx->last_sequence_number_sent);
1529 ph->iv_seed = calculate_seed (kx);
1531 ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1532 GNUNET_memcpy (&ph[1],
1535 env = GNUNET_MQ_msg_extra (em,
1537 GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE);
1538 em->iv_seed = ph->iv_seed;
1543 GNUNET_assert (GNUNET_OK ==
1546 &ph->sequence_number,
1547 &em->sequence_number,
1548 used - ENCRYPTED_HEADER_SIZE));
1551 struct GNUNET_HashCode hc;
1553 GNUNET_CRYPTO_hash (&ph->sequence_number,
1554 used - ENCRYPTED_HEADER_SIZE,
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1557 "Encrypted payload `%s' of %u bytes for %s\n",
1559 (unsigned int) (used - ENCRYPTED_HEADER_SIZE),
1560 GNUNET_i2s (kx->peer));
1563 derive_auth_key (&auth_key,
1566 GNUNET_CRYPTO_hmac (&auth_key,
1567 &em->sequence_number,
1568 used - ENCRYPTED_HEADER_SIZE,
1572 struct GNUNET_HashCode hc;
1574 GNUNET_CRYPTO_hash (&auth_key,
1577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1578 "For peer %s, used AC %s to create hmac %s\n",
1579 GNUNET_i2s (kx->peer),
1581 GNUNET_h2s2 (&em->hmac));
1584 kx->has_excess_bandwidth = GNUNET_NO;
1585 GNUNET_MQ_send (kx->mq,
1591 * We received an encrypted message. Check that it is
1592 * well-formed (size-wise).
1594 * @param cls key exchange context for encrypting the message
1595 * @param m encrypted message
1596 * @return #GNUNET_OK if @a msg is well-formed (size-wise)
1599 check_encrypted (void *cls,
1600 const struct EncryptedMessage *m)
1602 uint16_t size = ntohs (m->header.size) - sizeof (*m);
1604 if (size < sizeof (struct GNUNET_MessageHeader))
1606 GNUNET_break_op (0);
1607 return GNUNET_SYSERR;
1614 * We received an encrypted message. Decrypt, validate and
1615 * pass on to the appropriate clients.
1617 * @param cls key exchange context for encrypting the message
1618 * @param m encrypted message
1621 handle_encrypted (void *cls,
1622 const struct EncryptedMessage *m)
1624 struct GSC_KeyExchangeInfo *kx = cls;
1625 struct EncryptedMessage *pt; /* plaintext */
1626 struct GNUNET_HashCode ph;
1628 struct GNUNET_TIME_Absolute t;
1629 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1630 struct GNUNET_CRYPTO_AuthKey auth_key;
1631 uint16_t size = ntohs (m->header.size);
1632 char buf[size] GNUNET_ALIGN;
1634 if (GNUNET_CORE_KX_STATE_UP != kx->status)
1636 GNUNET_STATISTICS_update (GSC_stats,
1637 gettext_noop ("# DATA message dropped (out of order)"),
1642 if (0 == GNUNET_TIME_absolute_get_remaining (kx->foreign_key_expires).rel_value_us)
1644 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1645 _("Session to peer `%s' went down due to key expiration (should not happen)\n"),
1646 GNUNET_i2s (kx->peer));
1647 GNUNET_STATISTICS_update (GSC_stats,
1648 gettext_noop ("# sessions terminated by key expiration"),
1650 GSC_SESSIONS_end (kx->peer);
1651 if (NULL != kx->keep_alive_task)
1653 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1654 kx->keep_alive_task = NULL;
1656 kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1657 monitor_notify_all (kx);
1665 struct GNUNET_HashCode hc;
1667 GNUNET_CRYPTO_hash (&m->sequence_number,
1668 size - ENCRYPTED_HEADER_SIZE,
1670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1671 "Received encrypted payload `%s' of %u bytes from %s\n",
1673 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1674 GNUNET_i2s (kx->peer));
1677 derive_auth_key (&auth_key,
1680 GNUNET_CRYPTO_hmac (&auth_key,
1681 &m->sequence_number,
1682 size - ENCRYPTED_HEADER_SIZE,
1686 struct GNUNET_HashCode hc;
1688 GNUNET_CRYPTO_hash (&auth_key,
1691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1692 "For peer %s, used AC %s to verify hmac %s\n",
1693 GNUNET_i2s (kx->peer),
1695 GNUNET_h2s2 (&m->hmac));
1698 if (0 != memcmp (&ph,
1700 sizeof (struct GNUNET_HashCode)))
1702 /* checksum failed */
1703 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1704 "Failed checksum validation for a message from `%s'\n",
1705 GNUNET_i2s (kx->peer));
1716 &m->sequence_number,
1717 &buf[ENCRYPTED_HEADER_SIZE],
1718 size - ENCRYPTED_HEADER_SIZE))
1720 GNUNET_break_op (0);
1723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1724 "Decrypted %u bytes from %s\n",
1725 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1726 GNUNET_i2s (kx->peer));
1727 pt = (struct EncryptedMessage *) buf;
1729 /* validate sequence number */
1730 snum = ntohl (pt->sequence_number);
1731 if (kx->last_sequence_number_received == snum)
1733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1734 "Received duplicate message, ignoring.\n");
1735 /* duplicate, ignore */
1736 GNUNET_STATISTICS_update (GSC_stats,
1737 gettext_noop ("# bytes dropped (duplicates)"),
1742 if ((kx->last_sequence_number_received > snum) &&
1743 (kx->last_sequence_number_received - snum > 32))
1745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1746 "Received ancient out of sequence message, ignoring.\n");
1747 /* ancient out of sequence, ignore */
1748 GNUNET_STATISTICS_update (GSC_stats,
1750 ("# bytes dropped (out of sequence)"), size,
1754 if (kx->last_sequence_number_received > snum)
1756 uint32_t rotbit = 1U << (kx->last_sequence_number_received - snum - 1);
1758 if ((kx->last_packets_bitmap & rotbit) != 0)
1760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1761 "Received duplicate message, ignoring.\n");
1762 GNUNET_STATISTICS_update (GSC_stats,
1763 gettext_noop ("# bytes dropped (duplicates)"),
1765 /* duplicate, ignore */
1768 kx->last_packets_bitmap |= rotbit;
1770 if (kx->last_sequence_number_received < snum)
1772 unsigned int shift = (snum - kx->last_sequence_number_received);
1774 if (shift >= 8 * sizeof (kx->last_packets_bitmap))
1775 kx->last_packets_bitmap = 0;
1777 kx->last_packets_bitmap <<= shift;
1778 kx->last_sequence_number_received = snum;
1781 /* check timestamp */
1782 t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
1783 if (GNUNET_TIME_absolute_get_duration (t).rel_value_us >
1784 MAX_MESSAGE_AGE.rel_value_us)
1786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1787 "Message received far too old (%s). Content ignored.\n",
1788 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (t),
1790 GNUNET_STATISTICS_update (GSC_stats,
1792 ("# bytes dropped (ancient message)"), size,
1797 /* process decrypted message(s) */
1798 update_timeout (kx);
1799 GNUNET_STATISTICS_update (GSC_stats,
1800 gettext_noop ("# bytes of payload decrypted"),
1801 size - sizeof (struct EncryptedMessage),
1804 GNUNET_MST_from_buffer (kx->mst,
1805 &buf[sizeof (struct EncryptedMessage)],
1806 size - sizeof (struct EncryptedMessage),
1809 GNUNET_break_op (0);
1814 * One of our neighbours has excess bandwidth, remember this.
1817 * @param pid identity of the peer with excess bandwidth
1818 * @param connect_cls the `struct Neighbour`
1821 handle_transport_notify_excess_bw (void *cls,
1822 const struct GNUNET_PeerIdentity *pid,
1825 struct GSC_KeyExchangeInfo *kx = connect_cls;
1827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1828 "Peer %s has excess bandwidth available\n",
1830 kx->has_excess_bandwidth = GNUNET_YES;
1831 GSC_SESSIONS_solicit (pid);
1836 * Setup the message that links the ephemeral key to our persistent
1837 * public key and generate the appropriate signature.
1840 sign_ephemeral_key ()
1842 current_ekm.header.size = htons (sizeof (struct EphemeralKeyMessage));
1843 current_ekm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY);
1844 current_ekm.sender_status = 0; /* to be set later */
1845 current_ekm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY);
1846 current_ekm.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
1847 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
1848 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
1849 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
1850 sizeof (struct GNUNET_PeerIdentity));
1851 current_ekm.creation_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1853 GNUNET_CONFIGURATION_get_value_yesno (GSC_cfg,
1855 "USE_EPHEMERAL_KEYS"))
1857 current_ekm.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_add (REKEY_FREQUENCY,
1862 current_ekm.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
1864 GNUNET_CRYPTO_ecdhe_key_get_public (my_ephemeral_key,
1865 ¤t_ekm.ephemeral_key);
1866 current_ekm.origin_identity = GSC_my_identity;
1867 GNUNET_assert (GNUNET_OK ==
1868 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1869 ¤t_ekm.purpose,
1870 ¤t_ekm.signature));
1875 * Task run to trigger rekeying.
1877 * @param cls closure, NULL
1880 do_rekey (void *cls)
1882 struct GSC_KeyExchangeInfo *pos;
1884 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
1887 if (NULL != my_ephemeral_key)
1888 GNUNET_free (my_ephemeral_key);
1889 my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create ();
1890 GNUNET_assert (NULL != my_ephemeral_key);
1891 sign_ephemeral_key ();
1893 struct GNUNET_HashCode eh;
1895 GNUNET_CRYPTO_hash (¤t_ekm.ephemeral_key,
1896 sizeof (current_ekm.ephemeral_key),
1898 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1902 for (pos = kx_head; NULL != pos; pos = pos->next)
1904 if (GNUNET_CORE_KX_STATE_UP == pos->status)
1906 pos->status = GNUNET_CORE_KX_STATE_REKEY_SENT;
1907 monitor_notify_all (pos);
1908 derive_session_keys (pos);
1910 if (GNUNET_CORE_KX_STATE_DOWN == pos->status)
1912 pos->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1913 monitor_notify_all (pos);
1915 monitor_notify_all (pos);
1922 * Initialize KX subsystem.
1924 * @param pk private key to use for the peer
1925 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1928 GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
1930 struct GNUNET_MQ_MessageHandler handlers[] = {
1931 GNUNET_MQ_hd_fixed_size (ephemeral_key,
1932 GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY,
1933 struct EphemeralKeyMessage,
1935 GNUNET_MQ_hd_fixed_size (ping,
1936 GNUNET_MESSAGE_TYPE_CORE_PING,
1939 GNUNET_MQ_hd_fixed_size (pong,
1940 GNUNET_MESSAGE_TYPE_CORE_PONG,
1943 GNUNET_MQ_hd_var_size (encrypted,
1944 GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE,
1945 struct EncryptedMessage,
1947 GNUNET_MQ_handler_end()
1950 my_private_key = pk;
1951 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
1952 &GSC_my_identity.public_key);
1953 my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create ();
1954 if (NULL == my_ephemeral_key)
1957 GNUNET_free (my_private_key);
1958 my_private_key = NULL;
1959 return GNUNET_SYSERR;
1961 sign_ephemeral_key ();
1963 struct GNUNET_HashCode eh;
1965 GNUNET_CRYPTO_hash (¤t_ekm.ephemeral_key,
1966 sizeof (current_ekm.ephemeral_key),
1968 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1969 "Starting with ephemeral key %s\n",
1973 nc = GNUNET_notification_context_create (1);
1974 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
1978 = GNUNET_TRANSPORT_core_connect (GSC_cfg,
1982 &handle_transport_notify_connect,
1983 &handle_transport_notify_disconnect,
1984 &handle_transport_notify_excess_bw);
1985 if (NULL == transport)
1988 return GNUNET_SYSERR;
1995 * Shutdown KX subsystem.
2000 if (NULL != transport)
2002 GNUNET_TRANSPORT_core_disconnect (transport);
2005 if (NULL != rekey_task)
2007 GNUNET_SCHEDULER_cancel (rekey_task);
2010 if (NULL != my_ephemeral_key)
2012 GNUNET_free (my_ephemeral_key);
2013 my_ephemeral_key = NULL;
2015 if (NULL != my_private_key)
2017 GNUNET_free (my_private_key);
2018 my_private_key = NULL;
2022 GNUNET_notification_context_destroy (nc);
2029 * Check how many messages are queued for the given neighbour.
2031 * @param kxinfo data about neighbour to check
2032 * @return number of items in the message queue
2035 GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *kxinfo)
2037 return GNUNET_MQ_get_length (kxinfo->mq);
2042 * Check if the given neighbour has excess bandwidth available.
2044 * @param target neighbour to check
2045 * @return #GNUNET_YES if excess bandwidth is available, #GNUNET_NO if not
2048 GSC_NEIGHBOURS_check_excess_bandwidth (const struct GSC_KeyExchangeInfo *kxinfo)
2050 return kxinfo->has_excess_bandwidth;
2055 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
2056 * request type, the client does not have to have transmitted an INIT
2057 * request. All current peers are returned, regardless of which
2058 * message types they accept.
2060 * @param mq message queue to add for monitoring
2063 GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq)
2065 struct GNUNET_MQ_Envelope *env;
2066 struct MonitorNotifyMessage *done_msg;
2067 struct GSC_KeyExchangeInfo *kx;
2069 GNUNET_notification_context_add (nc,
2071 for (kx = kx_head; NULL != kx; kx = kx->next)
2073 struct GNUNET_MQ_Envelope *env;
2074 struct MonitorNotifyMessage *msg;
2076 env = GNUNET_MQ_msg (msg,
2077 GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
2078 msg->state = htonl ((uint32_t) kx->status);
2079 msg->peer = *kx->peer;
2080 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
2084 env = GNUNET_MQ_msg (done_msg,
2085 GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
2086 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
2087 done_msg->timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
2093 /* end of gnunet-service-core_kx.c */