GNUnet 0.28.0-dev.3-20-gf1136b0b8
 
Loading...
Searching...
No Matches
gnunet-service-core_kx.c File Reference

TODO: More...

Include dependency graph for gnunet-service-core_kx.c:

Go to the source code of this file.

Data Structures

struct  GSC_KeyExchangeInfo
 Information about the status of a key exchange with another peer. More...
 
struct  PilsRequest
 DLL. More...
 
struct  InitiatorHelloCtx
 
struct  ResponderHelloCls
 

Macros

#define DEBUG_KX   0
 Enable expensive (and possibly problematic for privacy!) logging of KX.
 
#define RESEND_MAX_TRIES   4
 Number of times we try to resend a handshake flight.
 
#define AEAD_KEY_BYTES   crypto_aead_xchacha20poly1305_ietf_KEYBYTES
 libsodium has very long symbol names
 
#define AEAD_NONCE_BYTES   crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
 libsodium has very long symbol names
 
#define AEAD_TAG_BYTES   crypto_aead_xchacha20poly1305_ietf_ABYTES
 libsodium has very long symbol names
 
#define RESEND_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
 
#define MIN_HEARTBEAT_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 What is the minimum frequency for a HEARTBEAT message?
 
#define HEARTBEAT_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
 How often do we send a heartbeat?
 
#define MAX_EPOCHS   10
 Maximum number of epochs we keep on hand.
 
#define EPOCH_EXPIRATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
 How often do we rekey/switch to a new epoch?
 
#define REKEY_TOLERANCE    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 What time difference do we tolerate?
 
#define EARLY_DATA_STR   "early data"
 String for expanding early transport secret (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define R_HS_TRAFFIC_STR   "r hs traffic"
 String for expanding RHTS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define I_HS_TRAFFIC_STR   "i hs traffic"
 String for expanding IHTS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define R_AP_TRAFFIC_STR   "r ap traffic"
 String for expanding RATS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define I_AP_TRAFFIC_STR   "i ap traffic"
 String for expanding IATS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define DERIVED_STR   "derived"
 String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define R_FINISHED_STR   "r finished"
 String for expanding fk_R used for ResponderFinished field (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define I_FINISHED_STR   "i finished"
 String for expanding fk_I used for InitiatorFinished field (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define CAKE_LABEL   "cake10"
 Labeled expand label for CAKE.
 
#define KEY_STR   "key"
 String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define TRAFFIC_UPD_STR   "traffic upd"
 String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 
#define IV_STR   "iv"
 String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)
 

Enumerations

enum  GSC_KX_Role { ROLE_INITIATOR = 0 , ROLE_RESPONDER = 1 }
 Indicates whether a peer is in the initiating or receiving role. More...
 

Functions

static void buffer_clear (void *buf, size_t len)
 
static void cleanup_handshake_secrets (struct GSC_KeyExchangeInfo *kx)
 
static void snapshot_transcript (const struct GNUNET_HashContext *ts_hash, struct GNUNET_HashCode *snapshot)
 
static void monitor_notify_all (struct GSC_KeyExchangeInfo *kx)
 Inform all monitors about the KX state of the given peer.
 
static void restart_kx (struct GSC_KeyExchangeInfo *kx)
 
static void send_heartbeat (void *cls)
 Task triggered when a neighbour entry is about to time out (and we should prevent this by sending an Ack in response to a heartbeat).
 
static void update_timeout (struct GSC_KeyExchangeInfo *kx)
 We've seen a valid message from the other peer.
 
static void send_initiator_hello (struct GSC_KeyExchangeInfo *kx)
 Send initiator hello.
 
static int deliver_message (void *cls, const struct GNUNET_MessageHeader *m)
 Deliver P2P message to interested clients.
 
static void * handle_transport_notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer_id, struct GNUNET_MQ_Handle *mq)
 Function called by transport to notify us that a peer connected to us (on the network level).
 
static void derive_es_ets (const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ss_R, struct GNUNET_ShortHashCode *es, struct GNUNET_ShortHashCode *ets)
 TODO propose a new scheme: don't choose an initiator and responder based on hashing the peer ids, but: let each peer be their own initiator (and responder) when opening a channel towards another peer.
 
static void derive_sn (const struct GNUNET_ShortHashCode *secret, unsigned char *sn, size_t sn_len)
 
static void derive_hs (const struct GNUNET_ShortHashCode *es, const struct GNUNET_ShortHashCode *ss_e, struct GNUNET_ShortHashCode *handshake_secret)
 Derive the handshake secret.
 
static void derive_ihts (const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *hs, struct GNUNET_ShortHashCode *ihts)
 Derive the initiator handshake secret.
 
static void derive_rhts (const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *hs, struct GNUNET_ShortHashCode *rhts)
 Derive the responder handshake secret.
 
static void derive_ms (const struct GNUNET_ShortHashCode *hs, const struct GNUNET_ShortHashCode *ss_I, struct GNUNET_ShortHashCode *ms)
 Derive the master secret.
 
static void generate_per_record_nonce (uint64_t seq, const uint8_t write_iv[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES], uint8_t per_record_write_iv[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES])
 Generate per record nonce as per https://www.rfc-editor.org/rfc/rfc8446#section-5.3 using per key nonce and sequence number.
 
static void derive_per_message_secrets (const struct GNUNET_ShortHashCode *ts, uint64_t seq, unsigned char key[crypto_aead_xchacha20poly1305_ietf_KEYBYTES], unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES])
 key = HKDF-Expand [I,R][A,H]TS, "key", 32) nonce = HKDF-Expand ([I,R][A,H]TS, "iv", 24)
 
static void derive_next_ats (const struct GNUNET_ShortHashCode *old_ats, struct GNUNET_ShortHashCode *new_ats)
 Derive the next application secret.
 
static void derive_initial_ats (const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, enum GSC_KX_Role role, struct GNUNET_ShortHashCode *initial_ats)
 Derive the initiator application secret.
 
static void generate_responder_finished (const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, struct GNUNET_HashCode *result)
 Generate the responder finished field.
 
static void generate_initiator_finished (const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, struct GNUNET_HashCode *result)
 Generate the initiator finished field.
 
static void resend_responder_hello (void *cls)
 
void send_responder_hello (struct GSC_KeyExchangeInfo *kx)
 
static void handle_initiator_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_R)
 
static int check_initiator_hello (void *cls, const struct InitiatorHello *m)
 
static void handle_initiator_hello (void *cls, const struct InitiatorHello *ihm_e)
 Handle the InitiatorHello message.
 
static void resend_initiator_done (void *cls)
 
static void handle_responder_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_I)
 
static int check_responder_hello (void *cls, const struct ResponderHello *m)
 
static void handle_responder_hello (void *cls, const struct ResponderHello *rhm_e)
 Handle Responder Hello message.
 
static int check_initiator_done (void *cls, const struct InitiatorDone *m)
 
static void handle_initiator_done (void *cls, const struct InitiatorDone *idm_e)
 Handle InitiatorDone message.
 
static int check_encrypted_message (void *cls, const struct EncryptedMessage *m)
 Check an incoming encrypted message before handling it.
 
static void handle_heartbeat (struct GSC_KeyExchangeInfo *kx, const struct Heartbeat *m)
 Handle a key update.
 
static enum GNUNET_GenericReturnValue check_if_ack_or_heartbeat (struct GSC_KeyExchangeInfo *kx, const char *buf, size_t buf_len)
 
static void handle_encrypted_message (void *cls, const struct EncryptedMessage *m)
 handle an encrypted message
 
static void handle_transport_notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer, void *handler_cls)
 Function called by transport telling us that a peer disconnected.
 
static void resend_initiator_hello (void *cls)
 
static void check_rekey (struct GSC_KeyExchangeInfo *kx)
 
void GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, const void *payload, size_t payload_size)
 Encrypt and transmit payload.
 
void GSC_KX_start (void)
 
void pid_change_cb (void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *hash)
 
int GSC_KX_init (void)
 Initialize KX subsystem.
 
void GSC_KX_done ()
 Shutdown KX subsystem.
 
unsigned int GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *kxinfo)
 Check how many messages are queued for the given neighbour.
 
int GSC_NEIGHBOURS_check_excess_bandwidth (const struct GSC_KeyExchangeInfo *kxinfo)
 Check if the given neighbour has excess bandwidth available.
 
void GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq)
 Handle GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request.
 

Variables

static struct PilsRequestpils_requests_head
 PILS Operation DLL.
 
static struct PilsRequestpils_requests_tail
 PILS Operation DLL.
 
static struct GNUNET_TRANSPORT_CoreHandletransport
 Transport service.
 
static struct GSC_KeyExchangeInfokx_head
 DLL head.
 
static struct GSC_KeyExchangeInfokx_tail
 DLL tail.
 
static struct GNUNET_SCHEDULER_Taskrekey_task
 Task scheduled for periodic re-generation (and thus rekeying) of our ephemeral key.
 
static struct GNUNET_NotificationContextnc
 Notification context for broadcasting to monitors.
 
static char * my_services_info = ""
 Our services info string TODO.
 

Detailed Description

TODO:

  • We need to implement a rekey (+ACK) that periodically rekeys.
  • We may want to reintroduce a heartbeat that needs to be ACKed. Maybe use / merge with KeyUpdate message. It already contains an update_requested field. Maybe rename to Heartbeat and add key_updated field to indicate a field update. That message then always MUST be Acked, if update_requested, then a Heartbeat is expected in response (w/o update_requested of course).

code for managing the key exchange (SET_KEY, PING, PONG) with other peers

Author
Christian Grothoff, ch3

Definition in file gnunet-service-core_kx.c.

Macro Definition Documentation

◆ DEBUG_KX

#define DEBUG_KX   0

Enable expensive (and possibly problematic for privacy!) logging of KX.

Definition at line 51 of file gnunet-service-core_kx.c.

◆ RESEND_MAX_TRIES

#define RESEND_MAX_TRIES   4

Number of times we try to resend a handshake flight.

Definition at line 56 of file gnunet-service-core_kx.c.

◆ AEAD_KEY_BYTES

#define AEAD_KEY_BYTES   crypto_aead_xchacha20poly1305_ietf_KEYBYTES

libsodium has very long symbol names

Definition at line 61 of file gnunet-service-core_kx.c.

◆ AEAD_NONCE_BYTES

#define AEAD_NONCE_BYTES   crypto_aead_xchacha20poly1305_ietf_NPUBBYTES

libsodium has very long symbol names

Definition at line 66 of file gnunet-service-core_kx.c.

◆ AEAD_TAG_BYTES

#define AEAD_TAG_BYTES   crypto_aead_xchacha20poly1305_ietf_ABYTES

libsodium has very long symbol names

Definition at line 71 of file gnunet-service-core_kx.c.

◆ RESEND_TIMEOUT

#define RESEND_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)

Definition at line 73 of file gnunet-service-core_kx.c.

183{
184 /* Peer is supposed to initiate the key exchange */
185 ROLE_INITIATOR = 0,
186
187 /* Peer is supposed to wait for the key exchange */
188 ROLE_RESPONDER = 1,
189};
190
191
196{
201
206
211
215 struct GNUNET_MQ_Handle *mq;
216
221
226
227 // TODO check ordering - might make it less confusing
228 // TODO consistent naming: ss_e, shared_secret_e or ephemeral_shared_secret?
229 // TODO consider making all the structs here pointers
230 // - they can be checked to be NULL
231 // - valgrind can detect memory issues better (I guess?)
232
237 enum GSC_KX_Role role;
238
239 // TODO
243
248
253
260
266
271 struct GNUNET_ShortHashCode early_traffic_secret; /* Decrypts InitiatorHello */
272
278
284
290
296
301
306
310 uint64_t current_epoch;
311
316
321 uint64_t their_max_epoch;
322
326 uint64_t current_sqn;
327
332
337
342
346 unsigned int resend_tries_left;
347
353
359
364
369 enum GNUNET_CORE_PeerClass class;
370
371};
372
376struct PilsRequest
377{
381 struct PilsRequest *prev;
382
386 struct PilsRequest *next;
387
392};
393
397static struct PilsRequest *pils_requests_head;
398
402static struct PilsRequest *pils_requests_tail;
403
404
409
413static struct GSC_KeyExchangeInfo *kx_head;
414
418static struct GSC_KeyExchangeInfo *kx_tail;
419
424static struct GNUNET_SCHEDULER_Task *rekey_task;
425
429static struct GNUNET_NotificationContext *nc;
430
434static char *my_services_info = "";
435
436static void
437buffer_clear (void *buf, size_t len)
438{
439#if HAVE_MEMSET_S
440 memset_s (buf, len, 0, len);
441#elif HAVE_EXPLICIT_BZERO
442 explicit_bzero (buf, len);
443#else
444 volatile unsigned char *p = buf;
445 while (len--)
446 *p++ = 0;
447#endif
448}
449
450
451static void
453{
454 buffer_clear (&kx->ihts,
455 sizeof kx->ihts);
456 buffer_clear (&kx->rhts,
457 sizeof kx->rhts);
458 buffer_clear (&kx->sk_e,
459 sizeof kx->sk_e);
460 buffer_clear (&kx->ss_I,
461 sizeof kx->ss_I);
462 buffer_clear (&kx->ss_R,
463 sizeof kx->ss_R);
464 buffer_clear (&kx->ss_e,
465 sizeof kx->ss_e);
467 sizeof kx->master_secret);
469 sizeof kx->early_secret_key);
471 sizeof kx->early_traffic_secret);
473 sizeof kx->handshake_secret);
474}
475
476
477static void
478snapshot_transcript (const struct GNUNET_HashContext *ts_hash,
479 struct GNUNET_HashCode *snapshot)
480{
481 struct GNUNET_HashContext *tmp;
482
483 tmp = GNUNET_CRYPTO_hash_context_copy (ts_hash);
484 GNUNET_CRYPTO_hash_context_finish (tmp, snapshot);
485}
486
487
493static void
495{
497
499 msg.header.size = htons (sizeof(msg));
500 msg.state = htonl ((uint32_t) kx->status);
501 msg.peer = kx->peer;
502 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
505}
506
507
508static void
510
518static void
519send_heartbeat (void *cls)
520{
521 struct GSC_KeyExchangeInfo *kx = cls;
522 struct GNUNET_TIME_Relative retry;
523 struct GNUNET_TIME_Relative left;
524 struct Heartbeat hb;
525
526 kx->heartbeat_task = NULL;
528 if (0 == left.rel_value_us)
529 {
531 gettext_noop ("# sessions terminated by timeout"),
532 1,
533 GNUNET_NO);
534 GSC_SESSIONS_end (&kx->peer);
537 restart_kx (kx);
538 return;
539 }
541 "Sending HEARTBEAT to `%s'\n",
542 GNUNET_i2s (&kx->peer));
544 gettext_noop ("# heartbeat messages sent"),
545 1,
546 GNUNET_NO);
547 hb.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT);
548 hb.header.size = htons (sizeof hb);
549 // FIXME when do we request update?
550 hb.flags = 0;
551 GSC_KX_encrypt_and_transmit (kx, &hb, sizeof hb);
554 kx->heartbeat_task =
556}
557
558
566static void
568{
570
571 kx->timeout =
573 delta =
575 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
576 {
577 /* we only notify monitors about timeout changes if those
578 are bigger than the threshold (5s) */
580 }
581 if (NULL != kx->heartbeat_task)
586 kx);
587}
588
589
595static void
597
598
610static int
611deliver_message (void *cls, const struct GNUNET_MessageHeader *m)
612{
613 struct GSC_KeyExchangeInfo *kx = cls;
614
616 "Decrypted message of type %d from %s\n",
617 ntohs (m->type),
618 GNUNET_i2s (&kx->peer));
620 m,
621 ntohs (m->size),
624 m,
625 sizeof(struct GNUNET_MessageHeader),
627 return GNUNET_OK;
628}
629
630
631static void
633{
634 const struct GNUNET_HashCode *my_identity_hash;
635 struct GNUNET_HashCode h1;
636
637 // TODO what happens if we're in the middle of a peer id change?
638 // TODO there's a small chance this gets already called when we don't have a
639 // peer id yet. Add a kx, insert into the list, mark it as to be completed
640 // and let the callback to pils finish the rest once we got the peer id
641
643 "Initiating key exchange with peer %s\n",
644 GNUNET_i2s (&kx->peer));
646 gettext_noop ("# key exchanges initiated"),
647 1,
648 GNUNET_NO);
649
651 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
652 GNUNET_assert (NULL != my_identity_hash);
653 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
654 if (NULL != kx->transcript_hash_ctx)
656 kx->transcript_hash_ctx = NULL;
657 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, my_identity_hash))
658 {
659 /* peer with "lower" identity starts KX, otherwise we typically end up
660 with both peers starting the exchange and transmit the 'set key'
661 message twice */
663 "I am the initiator, sending hello\n");
664 kx->role = ROLE_INITIATOR;
666 }
667 else
668 {
669 /* peer with "higher" identity starts a delayed KX, if the "lower" peer
670 * does not start a KX since it sees no reasons to do so */
672 "I am the responder, yielding and await initiator hello\n");
674 kx->role = ROLE_RESPONDER;
676 }
677}
678
679
690static void *
692 const struct GNUNET_PeerIdentity *peer_id,
693 struct GNUNET_MQ_Handle *mq)
694{
695 const struct GNUNET_PeerIdentity *my_identity;
696 struct GSC_KeyExchangeInfo *kx;
697 (void) cls;
699 GNUNET_assert (NULL != my_identity);
700 if (0 == memcmp (peer_id, my_identity, sizeof *peer_id))
701 {
703 "Ignoring connection to self\n");
704 return NULL;
705 }
707 "Incoming connection of peer with %s\n",
709
710 /* Set up kx struct */
711 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
713 kx->mq = mq;
714 GNUNET_memcpy (&kx->peer, peer_id, sizeof (struct GNUNET_PeerIdentity));
716
717 restart_kx (kx);
718 return kx;
719}
720
721
761// TODO find a way to assert that a key is not yet existing before generating
762// TODO find a way to assert that a key is not already existing before using
763/*
764 * Derive early secret and transport secret.
765 * @param kx the key exchange info
766 */
767static void
768derive_es_ets (const struct GNUNET_HashCode *transcript,
769 const struct GNUNET_ShortHashCode *ss_R,
770 struct GNUNET_ShortHashCode *es,
771 struct GNUNET_ShortHashCode *ets)
772{
773 uint64_t ret;
774
775 ret = GNUNET_CRYPTO_hkdf_extract (es, // prk
776 0, // salt
777 0, // salt_len
778 ss_R, // ikm - initial key material
779 sizeof (*ss_R));
780 if (GNUNET_OK != ret)
781 {
782 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting ES\n")
783 ;
784 GNUNET_assert (0);
785 }
787 ets,
788 sizeof (*ets),
789 es,
792 GNUNET_CRYPTO_kdf_arg_auto (transcript));
793 if (GNUNET_OK != ret)
794 {
795 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
796 ;
797 GNUNET_assert (0);
798 }
799}
800
801
802/*
803 * Derive early secret and transport secret.
804 * @param kx the key exchange info
805 */
806static void
807derive_sn (const struct GNUNET_ShortHashCode *secret,
808 unsigned char*sn,
809 size_t sn_len)
810{
813 sn,
814 sn_len,
815 secret,
818}
819
820
825static void
826derive_hs (const struct GNUNET_ShortHashCode *es,
827 const struct GNUNET_ShortHashCode *ss_e,
829{
830 uint64_t ret;
831 struct GNUNET_ShortHashCode derived_early_secret;
832
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deriving HS\n");
835 );
836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ss_e: %s\n", GNUNET_B2S (ss_e));
838 &derived_early_secret,
839 sizeof (derived_early_secret),
840 es,
844 derived_early_secret));
845 if (GNUNET_OK != ret)
846 {
847 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dES\n")
848 ;
849 GNUNET_assert (0);
850 }
851 // Handshake secret
852 // TODO check: are dES the salt and ss_e the ikm or other way round?
853 ret = GNUNET_CRYPTO_hkdf_extract (handshake_secret, // prk
854 &derived_early_secret, // salt - dES
855 sizeof (derived_early_secret), // salt_len
856 ss_e, // ikm - initial key material
857 sizeof (*ss_e));
858 if (GNUNET_OK != ret)
859 {
860 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting HS\n")
861 ;
862 GNUNET_assert (0);
863 }
864}
865
866
871static void
872derive_ihts (const struct GNUNET_HashCode *transcript,
873 const struct GNUNET_ShortHashCode *hs,
874 struct GNUNET_ShortHashCode *ihts)
875{
878 ihts, // result
879 sizeof (*ihts), // result len
880 hs, // prk?
883 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
884}
885
886
891static void
892derive_rhts (const struct GNUNET_HashCode *transcript,
893 const struct GNUNET_ShortHashCode *hs,
894 struct GNUNET_ShortHashCode *rhts)
895{
898 rhts,
899 sizeof (*rhts),
900 hs, // prk? TODO
903 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
904}
905
906
911static void
912derive_ms (const struct GNUNET_ShortHashCode *hs,
913 const struct GNUNET_ShortHashCode *ss_I,
914 struct GNUNET_ShortHashCode *ms)
915{
916 uint64_t ret;
917 struct GNUNET_ShortHashCode derived_handshake_secret;
918
920 &derived_handshake_secret,
921 sizeof (derived_handshake_secret),
922 hs,
925 if (GNUNET_OK != ret)
926 {
927 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dHS\n")
928 ;
929 GNUNET_assert (0);
930 }
931 // TODO check: are dHS the salt and ss_I the ikm or other way round?
932 ret = GNUNET_CRYPTO_hkdf_extract (ms, // prk
933 &derived_handshake_secret, // salt - dHS
934 sizeof (derived_handshake_secret), // salt_len
935 ss_I, // ikm - initial key material
936 sizeof (*ss_I));
937 if (GNUNET_OK != ret)
938 {
939 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting MS\n")
940 ;
941 GNUNET_assert (0);
942 }
943}
944
945
951static void
953 uint64_t seq,
954 const uint8_t write_iv[AEAD_NONCE_BYTES],
955 uint8_t per_record_write_iv[AEAD_NONCE_BYTES])
956{
957 uint64_t seq_nbo;
958 uint64_t *write_iv_ptr;
959 unsigned int byte_offset;
960
961 seq_nbo = GNUNET_htonll (seq);
962 memcpy (per_record_write_iv,
963 write_iv,
965 byte_offset =
966 AEAD_NONCE_BYTES - sizeof (uint64_t);
967 write_iv_ptr = (uint64_t*) (per_record_write_iv + byte_offset);
968 *write_iv_ptr ^= seq_nbo;
969}
970
971
976static void
978 const struct GNUNET_ShortHashCode *ts,
979 uint64_t seq,
980 unsigned char key[AEAD_KEY_BYTES],
981 unsigned char nonce[AEAD_NONCE_BYTES])
982{
983 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
984 /* derive actual key */
987 key,
989 ts,
992
993 /* derive nonce */
996 nonce_tmp,
998 ts,
1002 nonce_tmp,
1003 nonce);
1004}
1005
1006
1011static void
1012derive_next_ats (const struct GNUNET_ShortHashCode *old_ats,
1013 struct GNUNET_ShortHashCode *new_ats)
1014{
1015 int8_t ret;
1016
1017 // FIXME: Not sure of PRK and output may overlap here!
1019 new_ats,
1020 sizeof (*new_ats),
1021 old_ats,
1024 if (GNUNET_OK != ret)
1025 {
1027 "Something went wrong deriving next *ATS key\n");
1028 GNUNET_assert (0);
1029 }
1030}
1031
1032
1037static void
1038derive_initial_ats (const struct GNUNET_HashCode *transcript,
1039 const struct GNUNET_ShortHashCode *ms,
1040 enum GSC_KX_Role role,
1041 struct GNUNET_ShortHashCode *initial_ats)
1042{
1043 const char *traffic_str;
1044
1045 if (ROLE_INITIATOR == role)
1046 traffic_str = I_AP_TRAFFIC_STR;
1047 else
1048 traffic_str = R_AP_TRAFFIC_STR;
1051 initial_ats, // result
1052 sizeof (*initial_ats), // result len
1053 ms,
1055 GNUNET_CRYPTO_kdf_arg_string (traffic_str),
1056 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
1057}
1058
1059
1066static void
1067generate_responder_finished (const struct GNUNET_HashCode *transcript,
1068 const struct GNUNET_ShortHashCode *ms,
1069 struct GNUNET_HashCode *result)
1070{
1072 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1073
1075 &fk_R, // result
1076 sizeof (fk_R),
1077 ms,
1080 if (GNUNET_OK != ret)
1081 {
1083 "Something went wrong expanding fk_R\n");
1084 GNUNET_assert (0);
1085 }
1086
1087 GNUNET_CRYPTO_hmac (&fk_R,
1088 transcript,
1089 sizeof (*transcript),
1090 result);
1091}
1092
1093
1100static void
1101generate_initiator_finished (const struct GNUNET_HashCode *transcript,
1102 const struct GNUNET_ShortHashCode *ms,
1103 struct GNUNET_HashCode *result)
1104{
1106 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1107
1109 &fk_I, // result
1110 sizeof (fk_I),
1111 ms,
1114 if (GNUNET_OK != ret)
1115 {
1117 "Something went wrong expanding fk_I\n");
1118 GNUNET_assert (0);
1119 }
1120 GNUNET_CRYPTO_hmac (&fk_I,
1121 transcript,
1122 sizeof (*transcript),
1123 result);
1124}
1125
1126
1127struct InitiatorHelloCtx
1128{
1129 struct GSC_KeyExchangeInfo *kx;
1130 struct InitiatorHello *ihm_e;
1131 struct PilsRequest *req;
1132};
1133
1134static void
1135resend_responder_hello (void *cls)
1136{
1137 struct GSC_KeyExchangeInfo *kx = cls;
1138
1139 kx->resend_task = NULL;
1140 if (0 == kx->resend_tries_left)
1141 {
1143 "Restarting KX\n");
1144 restart_kx (kx);
1145 return;
1146 }
1147 kx->resend_tries_left--;
1149 "Resending responder hello. Retries left: %u\n",
1150 kx->resend_tries_left);
1154 kx);
1155}
1156
1157
1158void
1160{
1163 struct ResponderHello *rhm_e; /* responder hello message - encrypted pointer */
1164 struct GNUNET_MQ_Envelope *env;
1165 struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_kem_challenge;
1166 struct GNUNET_ShortHashCode rhts;
1167 struct GNUNET_ShortHashCode ihts;
1168 struct GNUNET_ShortHashCode hs;
1169 struct GNUNET_ShortHashCode ms;
1170 struct GNUNET_ShortHashCode ss_e;
1171 struct GNUNET_ShortHashCode ss_I;
1172 struct GNUNET_HashContext *hc;
1173 unsigned char enc_key[AEAD_KEY_BYTES];
1174 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1175
1176 // 4. encaps -> shared_secret_e, c_e (kemChallenge)
1177 // TODO potentially write this directly into rhm?
1178 ret = GNUNET_CRYPTO_hpke_kem_encaps (&kx->pk_e, // public ephemeral key of initiator
1179 &ephemeral_kem_challenge, // encapsulated key
1180 &ss_e); // key - ss_e
1181 if (GNUNET_OK != ret)
1182 {
1184 "Something went wrong encapsulating ss_e\n");
1185 return;
1186 }
1188 // 6. encaps -> shared_secret_I, c_I
1189 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public key of I
1190 &c_I, // encapsulated key
1191 &ss_I); // where to write the key material
1192 if (GNUNET_OK != ret)
1193 {
1195 "Something went wrong encapsulating ss_I\n");
1197 return;
1198 }
1199 // 7. generate RHTS (responder_handshare_secret_key) and RATS (responder_application_traffic_secret_key) (section 5)
1200 {
1201 struct GNUNET_HashCode transcript;
1202 snapshot_transcript (hc, &transcript);
1203#if DEBUG_KX
1205 "Transcript snapshot for derivation of HS, MS: `%s'\n",
1206 GNUNET_h2s (&transcript));
1207#endif
1209 &ss_e,
1210 &hs);
1211 derive_ms (&hs, &ss_I, &ms);
1212 }
1213
1214 // send ResponderHello
1215 // TODO fill fields / services_info!
1216 // 1. r_R <- random
1217 struct ResponderHelloPayload *rhp;
1218 size_t rhp_len = sizeof (*rhp) + strlen (my_services_info);
1219 unsigned char rhp_buf[rhp_len];
1220 size_t ct_len;
1221
1222 rhp = (struct ResponderHelloPayload*) rhp_buf;
1223 ct_len = rhp_len // ResponderHelloPayload, fist PT msg
1224 + sizeof (struct GNUNET_HashCode) // Finished hash, second PT msg
1225 + AEAD_TAG_BYTES * 2; // Two tags;
1226 env = GNUNET_MQ_msg_extra (rhm_e,
1227 ct_len,
1229
1230 rhm_e->r_R =
1231 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
1232
1233 // c_e
1234 GNUNET_memcpy (&rhm_e->c_e,
1235 &ephemeral_kem_challenge,
1236 sizeof (ephemeral_kem_challenge));
1238 rhm_e,
1239 sizeof (struct ResponderHello));
1240 // 2. Encrypt ServicesInfo and c_I with RHTS
1241 // derive RHTS
1242 {
1243 struct GNUNET_HashCode transcript;
1245 &transcript);
1246#if DEBUG_KX
1248 "Transcript snapshot for derivation of *HTS: `%s'\n",
1249 GNUNET_h2s (&transcript));
1250#endif
1251 derive_rhts (&transcript,
1252 &hs,
1253 &rhts);
1254 derive_ihts (&transcript,
1255 &hs,
1256 &ihts);
1258 0,
1259 enc_key,
1260 enc_nonce);
1261 }
1262 // c_I
1263 GNUNET_memcpy (&rhp->c_I, &c_I, sizeof (c_I));
1264 // Services info empty for now.
1265 GNUNET_memcpy (&rhp[1],
1267 strlen (my_services_info));
1268
1269 {
1270 unsigned long long out_ct_len;
1272 struct GNUNET_HashCode transcript;
1273 unsigned char *finished_buf;
1274 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1275 (unsigned char*) &rhm_e[1], /* c - ciphertext */
1276 &out_ct_len, /* clen_p */
1277 rhp_buf, /* rhm_p - plaintext message */
1278 rhp_len, // mlen
1279 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1280 // fields?
1281 NULL, // nsec - unused
1282 enc_nonce, // npub - nonce // FIXME nonce can be reused
1283 enc_key)); // k - key RHTS
1285 "Encrypted and wrote %llu bytes\n",
1286 out_ct_len);
1287 // 3. Create ResponderFinished (Section 6)
1288 // Derive fk_I <- HKDF-Expand (MS, "r finished", NULL)
1289 /* Forward the transcript */
1290 /* {svcinfo, c_I}RHTS */
1292 hc,
1293 &rhm_e[1],
1294 out_ct_len);
1295
1296 finished_buf = ((unsigned char*) &rhm_e[1]) + out_ct_len;
1298 &transcript);
1299#if DEBUG_KX
1301 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1302 GNUNET_h2s (&transcript));
1303#endif
1304 generate_responder_finished (&transcript,
1305 &ms,
1306 &finished);
1307 // 4. Encrypt ResponderFinished
1309 1,
1310 enc_key,
1311 enc_nonce);
1312 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1313 finished_buf, /* c - ciphertext */
1314 &out_ct_len, /* clen_p */
1315 (unsigned char*) &finished, /* rhm_p - plaintext message */
1316 sizeof (finished), // mlen
1317 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1318 // fields?
1319 NULL, // nsec - unused
1320 enc_nonce, // npub
1321 enc_key)); // k - key RHTS
1323 "Encrypted and wrote %llu bytes\n",
1324 out_ct_len);
1325 /* Forward the transcript
1326 * after responder finished,
1327 * before deriving *ATS and generating finished_I
1328 * (finished_I will be generated when receiving the InitiatorFinished message
1329 * in order to check it) */
1331 hc,
1332 finished_buf,
1333 out_ct_len);
1334 // 5. optionally send application data - encrypted with RATS
1335 // We do not really have any application data, instead, we send the ACK
1337 &transcript);
1338#if DEBUG_KX
1340 "Transcript snapshot for derivation of *ATS: `%s'\n",
1341 GNUNET_h2s (&transcript));
1342#endif
1343 derive_initial_ats (&transcript,
1344 &ms,
1346 &kx->current_ats);
1347 }
1348 /* Lock into struct */
1350 kx->transcript_hash_ctx = hc;
1351 kx->master_secret = ms;
1352 kx->handshake_secret = hs;
1353 kx->ss_e = ss_e;
1354 kx->ihts = ihts;
1355 kx->rhts = rhts;
1356 kx->ss_I = ss_I;
1357 kx->current_epoch = 0;
1358 kx->current_sqn = 0;
1360 kx->current_sqn,
1361 enc_key,
1362 enc_nonce);
1363
1364 GNUNET_MQ_send_copy (kx->mq, env);
1365 kx->resend_env = env;
1367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent ResponderHello: %d %d\n", kx->role,
1368 kx->status);
1369
1372 kx);
1374 monitor_notify_all (kx);
1375 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1376}
1377
1378
1379static void
1380handle_initiator_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_R)
1381{
1382 const struct GNUNET_HashCode *my_identity_hash;
1383 struct InitiatorHelloCtx *ihm_ctx = cls;
1384 struct GSC_KeyExchangeInfo *kx = ihm_ctx->kx;
1385 uint32_t ihm_len = ntohs (ihm_ctx->ihm_e->header.size);
1386 unsigned char enc_key[AEAD_KEY_BYTES];
1387 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1388 struct GNUNET_HashCode h1;
1389 struct GNUNET_HashCode transcript;
1390 struct GNUNET_ShortHashCode es;
1391 struct GNUNET_ShortHashCode ets;
1393
1394 ihm_ctx->req->op = NULL;
1397 ihm_ctx->req);
1398 GNUNET_free (ihm_ctx->req);
1399
1400
1402 &ihm_ctx->ihm_e->pk_e,
1403 sizeof (ihm_ctx->ihm_e->pk_e));
1404 // 5. generate ETS (early_traffic_secret_key, decrypt pk_i
1405 // expand ETS <- expand ES <- extract ss_R
1406 // use ETS to decrypt
1407
1408 /* Forward the transcript hash context over the unencrypted fields to get it
1409 * to the same status that the initiator had when it needed to derive es and
1410 * ets for the encryption */
1413 ihm_ctx->ihm_e,
1414 sizeof (struct InitiatorHello));
1416 &transcript);
1417#if DEBUG_KX
1419 "Transcript snapshot for derivation of ES, ETS: `%s'\n",
1420 GNUNET_h2s (&transcript));
1421#endif
1422 derive_es_ets (&transcript, ss_R, &es, &ets);
1424 0,
1425 enc_key,
1426 enc_nonce);
1427 {
1428 struct InitiatorHelloPayload *ihmp;
1429 size_t ct_len = ihm_len - sizeof (struct InitiatorHello);
1430 unsigned char ihmp_buf[ct_len - AEAD_TAG_BYTES];
1431 ihmp = (struct InitiatorHelloPayload*) ihmp_buf;
1432 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1433 ihmp_buf, // unsigned char *m
1434 NULL, // mlen_p message length
1435 NULL, // unsigned char *nsec - unused: NULL
1436 (unsigned char*) &ihm_ctx->ihm_e[1], // const unsigned char *c - ciphertext
1437 ct_len, // unsigned long long clen - length of ciphertext
1438 // mac, // const unsigned char *mac - authentication tag
1439 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1440 0, // unsigned long long adlen
1441 enc_nonce, // const unsigned char *npub - nonce
1442 enc_key // const unsigned char *k - key
1443 );
1444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pid_sender: %s\n",
1445 GNUNET_i2s (&ihmp->pk_I));
1446 if (0 != ret)
1447 {
1449 "Something went wrong decrypting: %d\n", ret);
1450 GNUNET_break_op (0);
1451 GNUNET_free (ihm_ctx->ihm_e);
1452 GNUNET_free (ihm_ctx);
1453 restart_kx (kx);
1454 return;
1455 }
1456 /* now forward it considering the encrypted messages that the initiator was
1457 * able to send after deriving the es and ets */
1459 &ihm_ctx->ihm_e[1],
1460 ct_len);
1461 GNUNET_memcpy (&kx->peer,
1462 &ihmp->pk_I,
1463 sizeof (struct GNUNET_PeerIdentity));
1464 }
1465
1466 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
1467 GNUNET_assert (NULL != my_identity_hash);
1468
1469 // We could follow with the rest of the Key Schedule (dES, HS, ...) for now
1470 /* Check that we are actually in the receiving role */
1471 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
1472 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, my_identity_hash))
1473 {
1474 /* peer with "lower" identity starts KX, otherwise we typically end up
1475 with both peers starting the exchange and transmit the 'set key'
1476 message twice */
1477 /* Something went wrong - we have the lower value and should have sent the
1478 * InitiatorHello, but instead received it. TODO handle this case
1479 * We might end up in this case if the initiator didn't initiate the
1480 * handshake long enough and the 'responder' initiates the handshake */
1482 "Something went wrong - we have the lower value and should have sent the InitiatorHello, but instead received it.\n");
1483 GNUNET_free (ihm_ctx->ihm_e);
1484 GNUNET_free (ihm_ctx);
1486 kx->transcript_hash_ctx = NULL;
1487 return;
1488 }
1489
1490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer ID of other peer: %s\n", GNUNET_i2s
1491 (&kx->peer));
1492 /* We update the monitoring peers here because now we know
1493 * that we can decrypt the message AND know the PID
1494 */
1495 monitor_notify_all (kx);
1496 kx->ss_R = *ss_R;
1497 kx->early_secret_key = es;
1498 kx->early_traffic_secret = ets;
1500}
1501
1502
1503static int
1504check_initiator_hello (void *cls, const struct InitiatorHello *m)
1505{
1506 uint16_t size = ntohs (m->header.size);
1507
1508 if (size < sizeof (*m)
1509 + sizeof (struct InitiatorHelloPayload)
1511 {
1512 return GNUNET_SYSERR;
1513 }
1514 return GNUNET_OK;
1515}
1516
1517
1526static void
1527handle_initiator_hello (void *cls, const struct InitiatorHello *ihm_e)
1528{
1529 const struct GNUNET_HashCode *my_identity_hash;
1530 struct GSC_KeyExchangeInfo *kx = cls;
1531 struct InitiatorHelloCtx *initiator_hello_cls;
1532 size_t ihm_len;
1533
1534 if (ROLE_INITIATOR == kx->role)
1535 {
1536 GNUNET_break_op (0);
1538 "I am an initiator! Tearing down...\n");
1539 return;
1540 }
1542 {
1543 GNUNET_break_op (0);
1545 "Already received InitiatorHello: %d %d\n", kx->role, kx->status
1546 );
1547 return;
1548 }
1550 (NULL != kx->transcript_hash_ctx))
1551 {
1553 "Already received InitiatorHello and sent ResponderHello: %d %d\n",
1554 kx->role, kx->status);
1555 return;
1556 }
1557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorHello: %d %d\n", kx->
1558 role, kx->status);
1562
1564 gettext_noop ("# key exchanges initiated"),
1565 1,
1566 GNUNET_NO);
1567
1569
1570 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
1571 GNUNET_assert (NULL != my_identity_hash);
1572
1573 // 1. verify type _INITIATOR_HELLO
1574 // - This is implicytly done by arriving within this handler
1575 // - or is this about verifying the 'additional data' part of aead?
1576 // should it check the encryption + mac? (is this implicitly done
1577 // while decrypting?)
1578 // 2. verify H(pk_R) matches pk_R
1579 if (0 != memcmp (&ihm_e->h_pk_R,
1580 my_identity_hash,
1581 sizeof (struct GNUNET_HashCode)))
1582 {
1584 "This message is not meant for us (H(PID) mismatch)\n");
1586 kx->transcript_hash_ctx = NULL;
1587 return;
1588 }
1589 // FIXME this sometimes triggers in the tests - why?
1590 // 3. decaps -> shared_secret_R, c_R (kemChallenge)
1591 ihm_len = ntohs (ihm_e->header.size);
1592 initiator_hello_cls = GNUNET_new (struct InitiatorHelloCtx);
1593 initiator_hello_cls->kx = kx;
1594 initiator_hello_cls->ihm_e = GNUNET_malloc (ihm_len);
1595 GNUNET_memcpy (initiator_hello_cls->ihm_e, ihm_e, ihm_len);
1596 initiator_hello_cls->req = GNUNET_new (struct PilsRequest);
1599 initiator_hello_cls->req);
1600 initiator_hello_cls->req->op =
1602 &ihm_e->c_R,
1603 // encapsulated key
1605 // continuation
1606 initiator_hello_cls);
1607}
1608
1609
1610struct ResponderHelloCls
1611{
1612 /* Current KX session */
1613 struct GSC_KeyExchangeInfo *kx;
1614
1615 /* responder hello message - encrypted */
1616 struct ResponderHello rhm_e;
1617
1618 /* responder hello message - plain/decrypted */
1619 struct ResponderHelloPayload *rhp;
1620
1621 /* Decrypted finish hash */
1623
1624 /* Encrypted finished CT (for transcript later) */
1625 char finished_enc[sizeof (struct GNUNET_HashCode)
1626 + AEAD_TAG_BYTES];
1627
1628 /* Temporary transcript context */
1629 struct GNUNET_HashContext *hc;
1630
1631 /* Temporary handshake secret */
1632 struct GNUNET_ShortHashCode hs;
1633
1634 /* Temporary handshake secret */
1636
1637 /* Temporary handshake secret */
1639
1640 /* Temporary handshake secret */
1642
1643 /* Pending PILS request */
1644 struct PilsRequest *req;
1645};
1646
1647static void
1648resend_initiator_done (void *cls)
1649{
1650 struct GSC_KeyExchangeInfo *kx = cls;
1651
1652 kx->resend_task = NULL;
1653 if (0 == kx->resend_tries_left)
1654 {
1656 "Restarting KX\n");
1657 restart_kx (kx);
1658 return;
1659 }
1660 kx->resend_tries_left--;
1662 "Resending initiator done. Retries left: %u\n",
1663 kx->resend_tries_left);
1667 kx);
1668}
1669
1670
1671static void
1672handle_responder_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_I)
1673{
1674 struct ResponderHelloCls *rh_ctx = cls;
1675 struct GSC_KeyExchangeInfo *kx = rh_ctx->kx;
1676 struct InitiatorDone *idm_e; /* encrypted */
1677 struct InitiatorDone idm_local;
1678 struct InitiatorDone *idm_p; /* plaintext */
1679 struct GNUNET_MQ_Envelope *env;
1680 unsigned char enc_key[AEAD_KEY_BYTES];
1681 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1682 struct ConfirmationAck ack_i;
1683 struct GNUNET_HashCode transcript;
1684 struct GNUNET_ShortHashCode ms;
1685
1686 rh_ctx->req->op = NULL;
1689 rh_ctx->req);
1690 GNUNET_free (rh_ctx->req);
1691 // XXX valgrind reports uninitialized memory
1692 // the following is a way to check whether this memory was meant
1693 // memset (&rhm_local, 0, sizeof (rhm_local)); - adapt to cls if still needed
1694 memset (&idm_local, 0, sizeof (idm_local));
1695
1696 kx->ss_I = *ss_I;
1697
1698 /* derive *ATS */
1699 derive_ms (&rh_ctx->hs, ss_I, &ms);;
1700 // 5. Create ResponderFinished as per Section 6 and check against decrypted payload.
1701 struct GNUNET_HashCode responder_finished;
1702 // Transcript updates, snapshot again
1703 snapshot_transcript (rh_ctx->hc,
1704 &transcript);
1705#if DEBUG_KX
1707 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1708 GNUNET_h2s (&transcript));
1709#endif
1710 generate_responder_finished (&transcript,
1711 &ms,
1712 &responder_finished);
1713 if (0 != memcmp (&rh_ctx->decrypted_finish,
1714 &responder_finished,
1715 sizeof (struct GNUNET_HashCode)))
1716 {
1718 "Could not verify \"responder finished\"\n");
1719 GNUNET_free (rh_ctx->rhp);
1721 GNUNET_free (rh_ctx);
1722 GNUNET_assert (0);
1723 return;
1724 }
1725
1726
1727 /* Forward the transcript
1728 * after generating finished_R,
1729 * before deriving *ATS */
1731 rh_ctx->hc,
1732 rh_ctx->finished_enc,
1733 sizeof (rh_ctx->finished_enc));
1734
1735 // At this point we cannot fail anymore and may lock into kx
1737 kx->transcript_hash_ctx = rh_ctx->hc;
1738 kx->ss_I = *ss_I;
1739 kx->handshake_secret = rh_ctx->hs;
1740 kx->ss_e = rh_ctx->ss_e;
1741 kx->ihts = rh_ctx->ihts;
1742 kx->rhts = rh_ctx->rhts;
1743 kx->master_secret = ms;
1744 GNUNET_free (rh_ctx->rhp);
1745 GNUNET_free (rh_ctx);
1746 rh_ctx = NULL;
1747
1749 &transcript);
1750#if DEBUG_KX
1752 "Transcript snapshot for derivation of *ATS: `%s'\n",
1753 GNUNET_h2s (&transcript));
1754#endif
1755 derive_initial_ats (&transcript,
1756 &kx->master_secret,
1758 &kx->their_ats[0]);
1759 for (int i = 0; i < MAX_EPOCHS - 1; i++)
1760 {
1761 derive_next_ats (&kx->their_ats[i],
1762 &kx->their_ats[i + 1]);
1763 }
1764 kx->their_max_epoch = MAX_EPOCHS - 1;
1765
1767 0,
1768 enc_key,
1769 enc_nonce);
1770 /* Create InitiatorDone message */
1771 idm_p = &idm_local; /* plaintext */
1772 env = GNUNET_MQ_msg_extra (idm_e,
1773 sizeof (ack_i)
1776 // 6. Create IteratorFinished as per Section 6.
1777 generate_initiator_finished (&transcript,
1778 &kx->master_secret,
1779 &idm_p->finished);
1781 "InteratorFinished: `%s'\n",
1782 GNUNET_h2s (&idm_p->finished));
1784 "Transcript `%s'\n",
1785 GNUNET_h2s (&transcript));
1786 // 7. Send InteratorFinished message encrypted with the key derived from IHTS to R
1787
1788 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1789 (unsigned char*) &idm_e->finished, /* c - ciphertext */
1790 NULL, /* clen_p */
1791 (unsigned char*) &idm_p->finished, /* idm_p - plaintext message */
1792 sizeof (idm_p->finished), // mlen
1793 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1794 // fields?
1795 NULL, // nsec - unused
1796 enc_nonce, // npub - nonce
1797 enc_key)); // k - key IHTS
1798 /* Forward the transcript hash context
1799 * after generating finished_I and RATS_0
1800 * before deriving IATS_0 */
1802 &idm_e->finished,
1803 sizeof (idm_e->finished)
1804 + AEAD_TAG_BYTES);
1806 &transcript);
1807#if DEBUG_KX
1809 "Transcript snapshot for derivation of *ATS: `%s'\n",
1810 GNUNET_h2s (&transcript));
1811#endif
1812 derive_initial_ats (&transcript,
1813 &kx->master_secret,
1815 &kx->current_ats);
1816 kx->current_epoch = 0;
1817 kx->current_sqn++;
1818 // 8. optionally encrypt payload TODO
1820 kx->current_sqn,
1821 enc_key,
1822 enc_nonce);
1823 kx->current_sqn++;
1824 ack_i.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
1825 ack_i.header.size = htons (sizeof ack_i);
1826 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1827 (unsigned char*) &idm_e[1], /* c - ciphertext */
1828 NULL, /* clen_p */
1829 (unsigned char*) &ack_i, /* rhm_p - plaintext message */
1830 sizeof ack_i, // mlen
1831 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1832 // fields?
1833 NULL, // nsec - unused
1834 enc_nonce, // npub - nonce // FIXME nonce can be reused
1835 enc_key)); // k - key RHTS
1836
1837 GNUNET_MQ_send_copy (kx->mq, env);
1838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent InitiatorDone: %d %d\n", kx->role,
1839 kx->status);
1840
1841
1842 kx->resend_env = env;
1846 kx);
1848 monitor_notify_all (kx);
1849 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1850}
1851
1852
1853static int
1854check_responder_hello (void *cls, const struct ResponderHello *m)
1855{
1856 uint16_t size = ntohs (m->header.size);
1857
1858 if (size < sizeof (*m)
1859 + sizeof (struct ResponderHelloPayload)
1860 + sizeof (struct GNUNET_HashCode)
1861 + AEAD_TAG_BYTES * 2)
1862 {
1863 return GNUNET_SYSERR;
1864 }
1865 return GNUNET_OK;
1866}
1867
1868
1874static void
1875handle_responder_hello (void *cls, const struct ResponderHello *rhm_e)
1876{
1877 struct GSC_KeyExchangeInfo *kx = cls;
1878 struct PilsRequest *req;
1879 struct ResponderHelloCls *rh_ctx;
1880 struct GNUNET_HashCode transcript;
1881 struct GNUNET_HashContext *hc;
1882 unsigned char enc_key[AEAD_KEY_BYTES];
1883 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1885
1886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ResponderHello: %d %d\n", kx->
1887 role, kx->status);
1888
1890 if (NULL != kx->resend_task)
1891 {
1893 kx->resend_task = NULL;
1894 }
1895 if (NULL != kx->resend_env)
1896 {
1898 kx->resend_env = NULL;
1899 }
1900
1901 /* Forward the transcript hash context */
1902 if (ROLE_RESPONDER == kx->role)
1903 {
1904 GNUNET_break_op (0);
1906 "I am the responder! Ignoring.\n");
1908 return;
1909 }
1911 rhm_e,
1912 sizeof (struct ResponderHello));
1913 // 1. Verify that the message type is CORE_RESPONDER_HELLO
1914 // - implicitly done by handling this message?
1915 // - or is this about verifying the 'additional data' part of aead?
1916 // should it check the encryption + mac? (is this implicitly done
1917 // while decrypting?)
1918 // 2. sse <- Decaps(ske,ce)
1919 rh_ctx = GNUNET_new (struct ResponderHelloCls);
1920 ret = GNUNET_CRYPTO_hpke_kem_decaps (&kx->sk_e, // secret/private ephemeral key of initiator (us)
1921 &rhm_e->c_e, // encapsulated key
1922 &rh_ctx->ss_e); // key - ss_e
1923 if (GNUNET_OK != ret)
1924 {
1926 "Something went wrong decapsulating ss_e\n");
1928 return;
1929 }
1930 // 3. Generate IHTS and RHTS from Section 5 and decrypt ServicesInfo, cI and ResponderFinished.
1931 snapshot_transcript (hc, &transcript);
1932#if DEBUG_KX
1934 "Transcript snapshot for derivation of HS, *HTS: `%s'\n",
1935 GNUNET_h2s (&transcript));
1936#endif
1938 &rh_ctx->ss_e,
1939 &rh_ctx->hs);
1940 derive_rhts (&transcript,
1941 &rh_ctx->hs,
1942 &rh_ctx->rhts);
1943 derive_ihts (&transcript,
1944 &rh_ctx->hs,
1945 &rh_ctx->ihts);
1947 0,
1948 enc_key,
1949 enc_nonce);
1950 rh_ctx->kx = kx;
1951 GNUNET_memcpy (&rh_ctx->rhm_e, rhm_e, sizeof (*rhm_e));
1952 {
1953 unsigned long long int c_len;
1954 unsigned char *finished_buf;
1955 // use RHTS to decrypt
1956 c_len = ntohs (rhm_e->header.size) - sizeof (*rhm_e)
1957 - sizeof (struct GNUNET_HashCode)
1958 - AEAD_TAG_BYTES; // finished ct
1959 rh_ctx->rhp = GNUNET_malloc (c_len
1960 -
1962 rh_ctx->hc = hc;
1963 finished_buf = ((unsigned char*) &rhm_e[1]) + c_len;
1964 /* Forward the transcript_hash_ctx
1965 * after rhts has been generated,
1966 * before generating finished_R*/
1968 hc,
1969 &rhm_e[1],
1970 c_len);
1971
1972 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1973 (unsigned char*) rh_ctx->rhp, // unsigned char *m
1974 NULL, // mlen_p message length
1975 NULL, // unsigned char *nsec - unused: NULL
1976 (unsigned char*) &rhm_e[1], // const unsigned char *c - ciphertext
1977 c_len, // unsigned long long clen - length of ciphertext
1978 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1979 0, // unsigned long long adlen
1980 enc_nonce, // const unsigned char *npub - nonce
1981 enc_key // const unsigned char *k - key
1982 );
1983 if (0 != ret)
1984 {
1986 "Something went wrong decrypting: %d\n", ret);
1987 GNUNET_free (rh_ctx->rhp);
1988 GNUNET_free (rh_ctx);
1990 return;
1991 }
1992 // FIXME nonce reuse (see encryption)
1994 1,
1995 enc_key,
1996 enc_nonce);
1997 c_len = sizeof (struct GNUNET_HashCode)
1999 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2000 (unsigned char*) &rh_ctx->decrypted_finish, // unsigned char *m
2001 NULL, // mlen_p message length
2002 NULL, // unsigned char *nsec - unused: NULL
2003 finished_buf, // const unsigned char *c - ciphertext
2004 c_len, // unsigned long long clen - length of ciphertext
2005 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2006 0, // unsigned long long adlen
2007 enc_nonce, // const unsigned char *npub - nonce
2008 enc_key // const unsigned char *k - key
2009 );
2010 if (0 != ret)
2011 {
2013 "Something went wrong decrypting finished field: %d\n", ret);
2014 GNUNET_free (rh_ctx->rhp);
2015 GNUNET_free (rh_ctx);
2017 return;
2018 }
2019 GNUNET_memcpy (rh_ctx->finished_enc,
2020 finished_buf,
2021 c_len);
2022 }
2023 // 4. ssI <- Decaps(skI,cI).
2024 req = GNUNET_new (struct PilsRequest);
2025 rh_ctx->req = req;
2028 req);
2030 &rh_ctx->rhp->c_I, // encapsulated key
2031 &handle_responder_hello_cont, // continuation
2032 rh_ctx);
2033}
2034
2035
2036static int
2037check_initiator_done (void *cls, const struct InitiatorDone *m)
2038{
2039 uint16_t size = ntohs (m->header.size);
2040
2041 if (size < sizeof (*m) + sizeof (struct ConfirmationAck))
2042 {
2043 return GNUNET_SYSERR;
2044 }
2045 return GNUNET_OK;
2046}
2047
2048
2054static void
2055handle_initiator_done (void *cls, const struct InitiatorDone *idm_e)
2056{
2057 struct GSC_KeyExchangeInfo *kx = cls;
2058 struct InitiatorDone idm_local;
2059 struct InitiatorDone *idm_p = &idm_local; /* plaintext */
2060 struct GNUNET_HashCode initiator_finished;
2061 struct GNUNET_HashCode transcript;
2062 struct GNUNET_ShortHashCode their_ats;
2063 struct GNUNET_HashContext *hc;
2064 unsigned char enc_key[AEAD_KEY_BYTES];
2065 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2066 struct ConfirmationAck ack_i;
2067 struct ConfirmationAck ack_r;
2068 int8_t ret;
2069
2070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorDone: %d %d\n", kx->
2071 role, kx->status);
2072 if (NULL != kx->resend_task)
2073 {
2075 kx->resend_task = NULL;
2076 }
2077 if (NULL != kx->resend_env)
2078 {
2079 GNUNET_free (kx->resend_env);
2080 kx->resend_env = NULL;
2081 }
2082 if (ROLE_INITIATOR == kx->role)
2083 {
2084 GNUNET_break_op (0);
2086 "I am the initiator! Tearing down...\n");
2087 return;
2088 }
2090 0,
2091 enc_key,
2092 enc_nonce);
2093 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2094 (unsigned char*) &idm_p->finished, // unsigned char *m
2095 NULL, // mlen_p message length
2096 NULL, // unsigned char *nsec - unused: NULL
2097 (unsigned char*) &idm_e->finished, // const unsigned char *c - ciphertext
2098 sizeof (idm_p->finished) // unsigned long long clen - length of ciphertext
2100 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2101 0, // unsigned long long adlen
2102 enc_nonce, // const unsigned char *npub - nonce
2103 enc_key // const unsigned char *k - key
2104 );
2105 if (0 != ret)
2106 {
2108 "Something went wrong decrypting: %d\n", ret);
2109 return;
2110 }
2111
2112 // - verify finished_I
2113 /* Generate finished_I
2114 * after Forwarding until {finished_R}RHTS
2115 * (did so while we prepared responder hello)
2116 * before forwarding to [{payload}RATS and] {finished_I}IHTS */
2117 // (look at the end of handle_initiator_hello())
2118 snapshot_transcript (kx->transcript_hash_ctx, &transcript);
2119 generate_initiator_finished (&transcript,
2120 &kx->master_secret,
2121 &initiator_finished);
2122 if (0 != memcmp (&idm_p->finished,
2123 &initiator_finished,
2124 sizeof (struct GNUNET_HashCode)))
2125 {
2127 "Could not verify \"initiator finished\" hash.\n");
2129 "Want: `%s'\n",
2130 GNUNET_h2s (&initiator_finished));
2132 "Have: `%s'\n",
2133 GNUNET_h2s (&idm_p->finished));
2135 "Transcript `%s'\n",
2136 GNUNET_h2s (&transcript));
2137 return;
2138 }
2139
2140 /* Forward the transcript hash_context_read */
2143 &idm_e->finished,
2144 sizeof (idm_e->finished)
2145 + AEAD_TAG_BYTES);
2146 snapshot_transcript (hc, &transcript);
2147 derive_initial_ats (&transcript,
2148 &kx->master_secret,
2150 &their_ats);
2151 derive_per_message_secrets (&their_ats, // FIXME other HS epoch?
2152 0,
2153 enc_key,
2154 enc_nonce);
2155 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2156 (unsigned char*) &ack_i, // unsigned char *m
2157 NULL, // mlen_p message length
2158 NULL, // unsigned char *nsec - unused: NULL
2159 (unsigned char*) &idm_e[1], // const unsigned char *c - ciphertext
2160 sizeof (ack_i) + AEAD_TAG_BYTES, // unsigned long long clen - length of ciphertext
2161 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2162 0, // unsigned long long adlen
2163 enc_nonce, // const unsigned char *npub - nonce
2164 enc_key // const unsigned char *k - key
2165 );
2166 if (0 != ret)
2167 {
2169 "Something went wrong decrypting the Ack: %d\n", ret);
2171 return;
2172 }
2173 if ((sizeof ack_i != ntohs (ack_i.header.size)) ||
2174 (GNUNET_MESSAGE_TYPE_CORE_ACK != ntohs (ack_i.header.type)))
2175 {
2177 "Ack invalid!\n");
2179 return;
2180 }
2181 GNUNET_memcpy (&kx->their_ats[0],
2182 &their_ats,
2183 sizeof their_ats);
2187 for (int i = 0; i < MAX_EPOCHS - 1; i++)
2188 {
2189 derive_next_ats (&kx->their_ats[i],
2190 &kx->their_ats[i + 1]);
2191 }
2193 kx->transcript_hash_ctx = hc;
2198 monitor_notify_all (kx);
2199 kx->current_sqn = 1;
2200 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2201 GNUNET_assert (NULL == kx->heartbeat_task);
2202 update_timeout (kx);
2203 ack_r.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2204 ack_r.header.size = htons (sizeof ack_r);
2206 &ack_r,
2207 sizeof ack_r);
2208
2209 GNUNET_TRANSPORT_core_receive_continue (transport,
2210 &kx->peer);
2211}
2212
2213
2219static int
2220check_encrypted_message (void *cls, const struct EncryptedMessage *m)
2221{
2222 uint16_t size = ntohs (m->header.size) - sizeof(*m);
2223
2224 // TODO check (see check_encrypted ())
2225 // - check epoch
2226 // - check sequence number
2227 if (size < sizeof(struct GNUNET_MessageHeader))
2228 {
2229 GNUNET_break_op (0);
2230 return GNUNET_SYSERR;
2231 }
2232 return GNUNET_OK;
2233}
2234
2235
2241static void
2243 const struct Heartbeat *m)
2244{
2245 struct GNUNET_ShortHashCode new_ats;
2246 struct ConfirmationAck ack;
2247
2249 {
2250 if (kx->current_epoch == UINT64_MAX)
2251 {
2253 "Max epoch reached (you probably will never see this)\n");
2254 }
2255 else
2256 {
2257 kx->current_epoch++;
2260 kx->current_sqn = 0;
2262 &new_ats);
2263 memcpy (&kx->current_ats,
2264 &new_ats,
2265 sizeof new_ats);
2266 }
2267 }
2268 update_timeout (kx);
2269 ack.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2270 ack.header.size = htons (sizeof ack);
2272 &ack,
2273 sizeof ack);
2274 if (NULL != kx->heartbeat_task)
2275 {
2279 kx);
2280 }
2281 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2282}
2283
2284
2285static enum GNUNET_GenericReturnValue
2287 const char *buf,
2288 size_t buf_len)
2289{
2290 struct GNUNET_MessageHeader *msg;
2291 struct ConfirmationAck *ack;
2292 struct Heartbeat *hb;
2293
2294 if (sizeof *msg > buf_len)
2295 return GNUNET_NO;
2296 msg = (struct GNUNET_MessageHeader*) buf;
2297 if (GNUNET_MESSAGE_TYPE_CORE_ACK == ntohs (msg->type))
2298 {
2299 ack = (struct ConfirmationAck *) buf;
2300 if (sizeof *ack != ntohs (ack->header.size))
2301 return GNUNET_NO;
2302 }
2303 else if (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT == ntohs (msg->type))
2304 {
2305 hb = (struct Heartbeat*) buf;
2306 if (sizeof *hb != ntohs (hb->header.size))
2307 return GNUNET_NO;
2308 handle_heartbeat (kx, hb);
2309 }
2310 else
2311 {
2312 return GNUNET_NO;
2313 }
2314
2319 {
2320 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2325 if (NULL != kx->resend_task)
2327 kx->resend_task = NULL;
2328 if (NULL != kx->resend_env)
2329 GNUNET_free (kx->resend_env);
2330 kx->resend_env = NULL;
2331 monitor_notify_all (kx);
2332 }
2333 update_timeout (kx);
2334
2335 return GNUNET_YES;
2336}
2337
2338
2344static void
2345handle_encrypted_message (void *cls, const struct EncryptedMessage *m)
2346{
2347 struct GSC_KeyExchangeInfo *kx = cls;
2348 uint16_t size = ntohs (m->header.size);
2349 char buf[size - sizeof (*m)] GNUNET_ALIGN;
2350 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2351 const unsigned char *seq_enc_nonce;
2352 unsigned char enc_key[AEAD_KEY_BYTES];
2353 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2354 struct GNUNET_ShortHashCode new_ats[MAX_EPOCHS];
2355 uint32_t seq_enc_ctr;
2356 uint64_t epoch;
2357 uint64_t m_seq;
2358 uint64_t m_seq_nbo;
2359 uint64_t c_len;
2360 int8_t ret;
2361
2362 // TODO look at handle_encrypted
2363 // - statistics
2364
2368 {
2369 GSC_SESSIONS_end (&kx->peer);
2371 monitor_notify_all (kx);
2372 restart_kx (kx);
2373 return;
2374 }
2375 update_timeout (kx);
2376 epoch = GNUNET_ntohll (m->epoch);
2381 memcpy (new_ats,
2382 kx->their_ats,
2383 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2384 // FIXME here we could introduce logic that sends heartbeats
2385 // with key update request if we have not seen a new
2386 // epoch after a while (e.g. EPOCH_EXPIRATION)
2387 if (kx->their_max_epoch < epoch)
2388 {
2393 if ((epoch - kx->their_max_epoch) > 2 * MAX_EPOCHS)
2394 {
2396 "Epoch %" PRIu64 " is too new, will not decrypt...\n",
2397 epoch);
2398 GSC_SESSIONS_end (&kx->peer);
2400 monitor_notify_all (kx);
2401 restart_kx (kx);
2402 return;
2403 }
2404 for (uint64_t i = kx->their_max_epoch; i < epoch; i++)
2405 {
2406 derive_next_ats (&new_ats[i % MAX_EPOCHS],
2407 &new_ats[(i + 1) % MAX_EPOCHS]);
2408 }
2409 }
2410 else if ((kx->their_max_epoch - epoch) > MAX_EPOCHS)
2411 {
2413 "Epoch %" PRIu64 " is too old, cannot decrypt...\n",
2414 epoch);
2415 return;
2416 }
2417 derive_sn (
2418 &new_ats[epoch % MAX_EPOCHS],
2419 seq_enc_k,
2420 sizeof seq_enc_k);
2421 /* compute the sequence number */
2422 seq_enc_ctr = *((uint32_t*) m->tag);
2423 seq_enc_nonce = &m->tag[sizeof (uint32_t)];
2424#if DEBUG_KX
2425 GNUNET_print_bytes (&new_ats[epoch % MAX_EPOCHS],
2426 sizeof (struct GNUNET_ShortHashCode),
2427 8,
2428 GNUNET_NO);
2429 GNUNET_print_bytes (seq_enc_k,
2430 sizeof seq_enc_k,
2431 8,
2432 GNUNET_NO);
2433 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2434 sizeof seq_enc_ctr,
2435 8,
2436 GNUNET_NO);
2437#endif
2438 crypto_stream_chacha20_ietf_xor_ic (
2439 (unsigned char*) &m_seq_nbo,
2440 (unsigned char*) &m->sequence_number,
2441 sizeof (uint64_t),
2442 seq_enc_nonce,
2443 ntohl (seq_enc_ctr),
2444 seq_enc_k);
2445 m_seq = GNUNET_ntohll (m_seq_nbo);
2447 "Received encrypted message in epoch %" PRIu64
2448 " with E(SQN=%" PRIu64 ")=%" PRIu64
2449 "\n",
2450 epoch,
2451 m_seq,
2452 m->sequence_number);
2453 /* We are the initiator and as we are going to receive,
2454 * we are using the responder key material */
2455 derive_per_message_secrets (&new_ats[epoch % MAX_EPOCHS],
2456 m_seq,
2457 enc_key,
2458 enc_nonce);
2459 // TODO checking sequence numbers - handle the case of out-of-sync messages!
2460 // for now only decrypt the payload
2461 // TODO encrypt other fields, too!
2462 // TODO
2463 // c_len = size - offsetof ();
2464 c_len = size - sizeof (struct EncryptedMessage);
2465 ret = crypto_aead_xchacha20poly1305_ietf_decrypt_detached (
2466 (unsigned char*) buf, // m - plain message
2467 NULL, // nsec - unused
2468 (unsigned char*) &m[1], // c - ciphertext
2469 c_len, // clen
2470 (const unsigned char*) &m->tag, // mac
2471 NULL, // ad - additional data TODO
2472 0, // adlen
2473 enc_nonce, // npub
2474 enc_key // k
2475 );
2476 if (0 != ret)
2477 {
2479 "Something went wrong decrypting message\n");
2480 GNUNET_break_op (0); // FIXME handle gracefully
2481 return;
2482 }
2483 kx->their_max_epoch = epoch;
2484 memcpy (&kx->their_ats,
2485 new_ats,
2486 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2487
2489 buf,
2490 sizeof buf))
2491 {
2493 {
2495 "Dropping message as we are still waiting for handshake ACK\n");
2496 GNUNET_break_op (0);
2497 return;
2498 }
2499 if (GNUNET_OK !=
2501 buf,
2502 sizeof buf,
2503 GNUNET_YES,
2504 GNUNET_NO))
2505 GNUNET_break_op (0);
2506 }
2507 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2508}
2509
2510
2520static void
2522 const struct GNUNET_PeerIdentity *peer,
2523 void *handler_cls)
2524{
2525 struct GSC_KeyExchangeInfo *kx = handler_cls;
2526 (void) cls;
2527
2529 "Peer `%s' disconnected from us.\n",
2530 GNUNET_i2s (&kx->peer));
2531 GSC_SESSIONS_end (&kx->peer);
2533 gettext_noop ("# key exchanges stopped"),
2534 1,
2535 GNUNET_NO);
2536 if (NULL != kx->resend_task)
2537 {
2539 kx->resend_task = NULL;
2540 }
2541 if (NULL != kx->resend_env)
2542 {
2543 GNUNET_free (kx->resend_env);
2544 kx->resend_env = NULL;
2545 }
2546 if (NULL != kx->heartbeat_task)
2547 {
2549 kx->heartbeat_task = NULL;
2550 }
2552 monitor_notify_all (kx);
2553 if (kx->transcript_hash_ctx)
2554 {
2556 kx->transcript_hash_ctx = NULL;
2557 }
2559 GNUNET_MST_destroy (kx->mst);
2560 GNUNET_free (kx);
2561}
2562
2563
2564static void
2565resend_initiator_hello (void *cls)
2566{
2567 struct GSC_KeyExchangeInfo *kx = cls;
2568
2569 kx->resend_task = NULL;
2571 "Resending InitiatorHello.\n");
2573 // FIXME (Exponential) backoff?
2576 kx);
2577}
2578
2579
2585static void
2587{
2588 const struct GNUNET_PeerIdentity *my_identity;
2589 struct GNUNET_MQ_Envelope *env;
2590 struct GNUNET_ShortHashCode es;
2591 struct GNUNET_ShortHashCode ets;
2592 struct GNUNET_ShortHashCode ss_R;
2593 struct InitiatorHelloPayload *ihmp; /* initiator hello message - buffer on stack */
2594 struct InitiatorHello *ihm_e; /* initiator hello message - encrypted */
2595 long long unsigned int c_len;
2596 unsigned char enc_key[AEAD_KEY_BYTES];
2597 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2599 size_t pt_len;
2600
2602 GNUNET_assert (NULL != my_identity);
2603
2604 pt_len = sizeof (*ihmp) + strlen (my_services_info);
2605 c_len = pt_len + AEAD_TAG_BYTES;
2606 env = GNUNET_MQ_msg_extra (ihm_e,
2607 c_len,
2609 ihmp = (struct InitiatorHelloPayload*) &ihm_e[1];
2610 ihmp->peer_class = htons (GNUNET_CORE_CLASS_UNKNOWN); // TODO set this to a meaningful
2611 GNUNET_memcpy (&ihmp->pk_I,
2613 sizeof (struct GNUNET_PeerIdentity));
2614 GNUNET_CRYPTO_hash (&kx->peer, /* what to hash */ // TODO do we do this twice?
2615 sizeof (struct GNUNET_PeerIdentity),
2616 &ihm_e->h_pk_R); /* result */
2617 // TODO init hashcontext/transcript_hash
2618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send InitiatorHello: %d %d\n", kx->role,
2619 kx->status);
2620 GNUNET_assert (NULL == kx->transcript_hash_ctx);
2622 GNUNET_assert (NULL != kx->transcript_hash_ctx);
2623 // TODO fill services_info
2624
2625 // 1. Encaps
2626 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public ephemeral key of initiator
2627 &ihm_e->c_R, // encapsulated key
2628 &ss_R); // key - ss_R
2629 if (GNUNET_OK != ret)
2630 {
2632 "Something went wrong encapsulating ss_R\n");
2633 // TODO handle
2634 }
2635 // 2. generate rR (uint64_t) - is this the nonce? Naming seems not quite
2636 // consistent
2637 ihm_e->r_I =
2638 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
2639 // 3. generate sk_e/pk_e - ephemeral key
2642 &kx->sk_e.ecdhe_key,
2643 &kx->pk_e.ecdhe_key);
2644 GNUNET_memcpy (&ihm_e->pk_e,
2645 &kx->pk_e.ecdhe_key,
2646 sizeof (kx->pk_e.ecdhe_key));
2647 // 4. generate ETS to encrypt
2648 // generate ETS (early_traffic_secret_key, decrypt pk_i
2649 // expand ETS <- expand ES <- extract ss_R
2650 // use ETS to decrypt
2652 ihm_e,
2653 sizeof (struct InitiatorHello));
2654 {
2655 struct GNUNET_HashCode transcript;
2657 &transcript);
2658 derive_es_ets (&transcript,
2659 &ss_R,
2660 &es,
2661 &ets);
2663 0,
2664 enc_key,
2665 enc_nonce);
2666 }
2667 // 5. encrypt
2668
2669 ret = crypto_aead_xchacha20poly1305_ietf_encrypt (
2670 (unsigned char*) &ihm_e[1], /* c - ciphertext */
2671 // mac,
2672 // NULL, // maclen_p
2673 &c_len, /* clen_p */
2674 (unsigned char*) ihmp, /* m - plaintext message */
2675 pt_len, // mlen
2676 NULL, 0, // ad, adlen // FIXME maybe over the unencrypted header?
2677 // fields?
2678 NULL, // nsec - unused
2679 enc_nonce, // npub - nonce
2680 enc_key); // k - key
2681 if (0 != ret)
2682 {
2683 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong encrypting\n");
2685 kx->transcript_hash_ctx = NULL;
2687 return;
2688 }
2689 /* Forward the transcript */
2692 &ihm_e[1],
2693 c_len);
2694
2696 kx->early_secret_key = es;
2697 kx->early_traffic_secret = ets;
2698 kx->ss_R = ss_R;
2699 monitor_notify_all (kx);
2700 GNUNET_MQ_send_copy (kx->mq, env);
2701 kx->resend_env = env;
2705 kx);
2706}
2707
2708
2709static void
2711{
2712 struct GNUNET_ShortHashCode new_ats;
2713
2714 if ((UINT64_MAX == kx->current_sqn) ||
2716 {
2718 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2719 ", incrementing epoch...\n",
2721 kx->current_sqn);
2722 // Can this trigger? Maybe if we receive a lot of
2723 // heartbeats?
2724 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2725 kx->current_epoch++;
2728 kx->current_sqn = 0;
2730 &new_ats);
2731 memcpy (&kx->current_ats,
2732 &new_ats,
2733 sizeof new_ats);
2734 }
2735}
2736
2737
2744void
2746 const void *payload,
2747 size_t payload_size)
2748{
2749 struct GNUNET_MQ_Envelope *env;
2750 struct EncryptedMessage *encrypted_msg;
2751 unsigned char enc_key[AEAD_KEY_BYTES];
2752 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2753 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2754 uint64_t sqn;
2755 uint64_t epoch;
2756 int8_t ret;
2757
2758 encrypted_msg = NULL;
2759
2760 check_rekey (kx);
2761 sqn = kx->current_sqn;
2762 epoch = kx->current_epoch;
2763 /* We are the sender and as we are going to send,
2764 * we are using the initiator key material */
2766 sqn,
2767 enc_key,
2768 enc_nonce);
2769 kx->current_sqn++;
2770 derive_sn (&kx->current_ats,
2771 seq_enc_k,
2772 sizeof seq_enc_k);
2773 env = GNUNET_MQ_msg_extra (encrypted_msg,
2774 payload_size,
2776 // only encrypt the payload for now
2777 // TODO encrypt other fields as well
2778 ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached (
2779 (unsigned char*) &encrypted_msg[1], // c - resulting ciphertext
2780 (unsigned char*) &encrypted_msg->tag, // mac - resulting mac/tag
2781 NULL, // maclen
2782 (unsigned char*) payload, // m - plain message
2783 payload_size, // mlen
2784 NULL, // ad - additional data TODO also cover the unencrypted part (epoch)
2785 0, // adlen
2786 NULL, // nsec - unused
2787 enc_nonce, // npub nonce
2788 enc_key // k - key
2789 );
2790 if (0 != ret)
2791 {
2793 "Something went wrong encrypting message\n");
2794 GNUNET_assert (0);
2795 }
2796 {
2797 /* compute the sequence number */
2798 unsigned char *seq_enc_nonce;
2799 uint64_t seq_nbo;
2800 uint32_t seq_enc_ctr;
2801
2802 seq_nbo = GNUNET_htonll (sqn);
2803 seq_enc_ctr = *((uint32_t*) encrypted_msg->tag);
2804 seq_enc_nonce = &encrypted_msg->tag[sizeof (uint32_t)];
2805 crypto_stream_chacha20_ietf_xor_ic (
2806 (unsigned char*) &encrypted_msg->sequence_number,
2807 (unsigned char*) &seq_nbo,
2808 sizeof seq_nbo,
2809 seq_enc_nonce,
2810 ntohl (seq_enc_ctr),
2811 seq_enc_k);
2812#if DEBUG_KX
2813 GNUNET_print_bytes (seq_enc_k,
2814 sizeof seq_enc_k,
2815 8,
2816 GNUNET_NO);
2817 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2818 sizeof seq_enc_ctr,
2819 8,
2820 GNUNET_NO);
2821#endif
2823 "Sending encrypted message with E(SQN=%" PRIu64 ")=%" PRIu64
2824 "\n",
2825 sqn,
2826 encrypted_msg->sequence_number);
2827 }
2828 encrypted_msg->epoch = GNUNET_htonll (epoch);
2829
2830 // TODO actually copy payload
2831 GNUNET_MQ_send (kx->mq, env);
2832}
2833
2834
2835void
2836GSC_KX_start (void)
2837{
2838 const struct GNUNET_PeerIdentity *my_identity;
2840 GNUNET_MQ_hd_var_size (initiator_hello,
2842 struct InitiatorHello,
2843 NULL),
2844 GNUNET_MQ_hd_var_size (initiator_done,
2846 struct InitiatorDone,
2847 NULL),
2848 GNUNET_MQ_hd_var_size (responder_hello,
2850 struct ResponderHello,
2851 NULL),
2852 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2854 struct EncryptedMessage,
2855 NULL),
2857 };
2858
2860 GNUNET_assert (NULL != my_identity);
2861
2863 transport =
2866 handlers,
2867 NULL, // cls - this connection-independant
2868 // cls seems not to be needed.
2869 // the connection-specific cls
2870 // will be set as a return value
2871 // of
2872 // handle_transport_notify_connect
2875 if (NULL == transport)
2876 {
2877 GSC_KX_done ();
2878 return;
2879 }
2880
2882 "Connected to TRANSPORT\n");
2883
2885}
2886
2887
2888void
2889pid_change_cb (void *cls,
2890 const struct GNUNET_HELLO_Parser *parser,
2891 const struct GNUNET_HashCode *hash)
2892{
2893 if (NULL != transport)
2894 return;
2895
2896 GSC_KX_start ();
2897}
2898
2899
2905int
2906GSC_KX_init (void)
2907{
2910 NULL);
2911 if (NULL == GSC_pils)
2912 {
2913 GSC_KX_done ();
2914 return GNUNET_SYSERR;
2915 }
2916
2917 return GNUNET_OK;
2918}
2919
2920
2924void
2925GSC_KX_done ()
2926{
2927 struct PilsRequest *pr;
2928 while (NULL != (pr = pils_requests_head))
2929 {
2932 pr);
2933 if (NULL != pr->op)
2934 GNUNET_PILS_cancel (pr->op);
2935 GNUNET_free (pr);
2936 }
2937 if (NULL != GSC_pils)
2938 {
2940 GSC_pils = NULL;
2941 }
2942 if (NULL != transport)
2943 {
2945 transport = NULL;
2946 }
2947 if (NULL != rekey_task)
2948 {
2950 rekey_task = NULL;
2951 }
2952 if (NULL != nc)
2953 {
2955 nc = NULL;
2956 }
2957}
2958
2959
2966unsigned int
2968{
2969 return GNUNET_MQ_get_length (kxinfo->mq);
2970}
2971
2972
2973int
2975{
2976 return kxinfo->has_excess_bandwidth;
2977}
2978
2979
2988void
2990{
2991 struct GNUNET_MQ_Envelope *env;
2992 struct MonitorNotifyMessage *done_msg;
2993 struct GSC_KeyExchangeInfo *kx;
2994
2996 for (kx = kx_head; NULL != kx; kx = kx->next)
2997 {
2998 struct GNUNET_MQ_Envelope *env_notify;
2999 struct MonitorNotifyMessage *msg;
3000
3002 msg->state = htonl ((uint32_t) kx->status);
3003 msg->peer = kx->peer;
3004 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
3005 GNUNET_MQ_send (mq, env_notify);
3006 }
3008 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
3011}
3012
3013
3014/* end of gnunet-service-core_kx.c */
struct GNUNET_MQ_MessageHandlers handlers[]
Definition 003.c:1
struct GNUNET_MessageHeader * msg
Definition 005.c:2
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
#define GNUNET_CORE_OPTION_SEND_FULL_INBOUND
Client wants all inbound messages in full.
Definition core.h:53
#define GNUNET_CORE_OPTION_SEND_HDR_INBOUND
Client just wants the 4-byte message headers of all inbound messages.
Definition core.h:59
#define gettext_noop(String)
Definition gettext.h:74
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition gnunet-arm.c:103
static int ret
Final status code.
Definition gnunet-arm.c:93
static char * peer_id
Option –peer.
static bool finished
Set to true once we are finished and should exit after sending our final message to the parent.
struct GNUNET_HashCode key
The key used in the DHT.
static int result
Global testing status.
static struct GNUNET_PeerIdentity my_identity
Identity of this peer.
const struct GNUNET_CONFIGURATION_Handle * GSC_cfg
Our configuration.
void GSC_complete_initialization_cb(void)
This function is called from GSC_KX_init() once it got its peer id from pils.
void GSC_CLIENTS_deliver_message(const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *msg, uint16_t msize, uint32_t options)
Deliver P2P message to interested clients.
struct GNUNET_PILS_Handle * GSC_pils
For peer identity access.
struct GNUNET_STATISTICS_Handle * GSC_stats
For creating statistics.
#define RESEND_MAX_TRIES
Number of times we try to resend a handshake flight.
static void * handle_transport_notify_connect(void *cls, const struct GNUNET_PeerIdentity *peer_id, struct GNUNET_MQ_Handle *mq)
Function called by transport to notify us that a peer connected to us (on the network level).
static void cleanup_handshake_secrets(struct GSC_KeyExchangeInfo *kx)
unsigned int GSC_NEIGHBOURS_get_queue_length(const struct GSC_KeyExchangeInfo *kxinfo)
Check how many messages are queued for the given neighbour.
int GSC_NEIGHBOURS_check_excess_bandwidth(const struct GSC_KeyExchangeInfo *kxinfo)
Check if the given neighbour has excess bandwidth available.
static int check_initiator_hello(void *cls, const struct InitiatorHello *m)
static int check_responder_hello(void *cls, const struct ResponderHello *m)
static struct GSC_KeyExchangeInfo * kx_tail
DLL tail.
static int check_initiator_done(void *cls, const struct InitiatorDone *m)
void GSC_KX_handle_client_monitor_peers(struct GNUNET_MQ_Handle *mq)
Handle GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request.
static void generate_per_record_nonce(uint64_t seq, const uint8_t write_iv[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES], uint8_t per_record_write_iv[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES])
Generate per record nonce as per https://www.rfc-editor.org/rfc/rfc8446#section-5....
static void handle_responder_hello(void *cls, const struct ResponderHello *rhm_e)
Handle Responder Hello message.
static void send_heartbeat(void *cls)
Task triggered when a neighbour entry is about to time out (and we should prevent this by sending an ...
#define IV_STR
String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-sch...
#define AEAD_TAG_BYTES
libsodium has very long symbol names
#define I_AP_TRAFFIC_STR
String for expanding IATS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
void GSC_KX_start(void)
#define I_FINISHED_STR
String for expanding fk_I used for InitiatorFinished field (See https://lsd.gnunet....
static char * my_services_info
Our services info string TODO.
static void resend_responder_hello(void *cls)
static void handle_transport_notify_disconnect(void *cls, const struct GNUNET_PeerIdentity *peer, void *handler_cls)
Function called by transport telling us that a peer disconnected.
#define MAX_EPOCHS
Maximum number of epochs we keep on hand.
static void derive_ihts(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *hs, struct GNUNET_ShortHashCode *ihts)
Derive the initiator handshake secret.
#define R_FINISHED_STR
String for expanding fk_R used for ResponderFinished field (See https://lsd.gnunet....
static void derive_initial_ats(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, enum GSC_KX_Role role, struct GNUNET_ShortHashCode *initial_ats)
Derive the initiator application secret.
static struct GNUNET_NotificationContext * nc
Notification context for broadcasting to monitors.
#define AEAD_NONCE_BYTES
libsodium has very long symbol names
void GSC_KX_encrypt_and_transmit(struct GSC_KeyExchangeInfo *kx, const void *payload, size_t payload_size)
Encrypt and transmit payload.
static struct PilsRequest * pils_requests_head
PILS Operation DLL.
static void check_rekey(struct GSC_KeyExchangeInfo *kx)
#define R_AP_TRAFFIC_STR
String for expanding RATS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
static void derive_next_ats(const struct GNUNET_ShortHashCode *old_ats, struct GNUNET_ShortHashCode *new_ats)
Derive the next application secret.
static void buffer_clear(void *buf, size_t len)
static void derive_per_message_secrets(const struct GNUNET_ShortHashCode *ts, uint64_t seq, unsigned char key[crypto_aead_xchacha20poly1305_ietf_KEYBYTES], unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES])
key = HKDF-Expand [I,R][A,H]TS, "key", 32) nonce = HKDF-Expand ([I,R][A,H]TS, "iv",...
static void derive_rhts(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *hs, struct GNUNET_ShortHashCode *rhts)
Derive the responder handshake secret.
static void generate_responder_finished(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, struct GNUNET_HashCode *result)
Generate the responder finished field.
static void handle_responder_hello_cont(void *cls, const struct GNUNET_ShortHashCode *ss_I)
static struct GSC_KeyExchangeInfo * kx_head
DLL head.
#define AEAD_KEY_BYTES
libsodium has very long symbol names
GSC_KX_Role
Indicates whether a peer is in the initiating or receiving role.
static void generate_initiator_finished(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, struct GNUNET_HashCode *result)
Generate the initiator finished field.
static struct PilsRequest * pils_requests_tail
PILS Operation DLL.
static void snapshot_transcript(const struct GNUNET_HashContext *ts_hash, struct GNUNET_HashCode *snapshot)
static void derive_sn(const struct GNUNET_ShortHashCode *secret, unsigned char *sn, size_t sn_len)
#define MIN_HEARTBEAT_FREQUENCY
What is the minimum frequency for a HEARTBEAT message?
void GSC_KX_done()
Shutdown KX subsystem.
static void derive_ms(const struct GNUNET_ShortHashCode *hs, const struct GNUNET_ShortHashCode *ss_I, struct GNUNET_ShortHashCode *ms)
Derive the master secret.
#define KEY_STR
String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-sch...
static void update_timeout(struct GSC_KeyExchangeInfo *kx)
We've seen a valid message from the other peer.
static void derive_hs(const struct GNUNET_ShortHashCode *es, const struct GNUNET_ShortHashCode *ss_e, struct GNUNET_ShortHashCode *handshake_secret)
Derive the handshake secret.
static void send_initiator_hello(struct GSC_KeyExchangeInfo *kx)
Send initiator hello.
#define I_HS_TRAFFIC_STR
String for expanding IHTS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
#define EARLY_DATA_STR
String for expanding early transport secret (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
static void handle_initiator_hello(void *cls, const struct InitiatorHello *ihm_e)
Handle the InitiatorHello message.
static void handle_encrypted_message(void *cls, const struct EncryptedMessage *m)
handle an encrypted message
static void derive_es_ets(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ss_R, struct GNUNET_ShortHashCode *es, struct GNUNET_ShortHashCode *ets)
TODO propose a new scheme: don't choose an initiator and responder based on hashing the peer ids,...
static int deliver_message(void *cls, const struct GNUNET_MessageHeader *m)
Deliver P2P message to interested clients.
static enum GNUNET_GenericReturnValue check_if_ack_or_heartbeat(struct GSC_KeyExchangeInfo *kx, const char *buf, size_t buf_len)
#define DERIVED_STR
String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-sch...
static int check_encrypted_message(void *cls, const struct EncryptedMessage *m)
Check an incoming encrypted message before handling it.
static void resend_initiator_hello(void *cls)
#define EPOCH_EXPIRATION
How often do we rekey/switch to a new epoch?
static void resend_initiator_done(void *cls)
static void monitor_notify_all(struct GSC_KeyExchangeInfo *kx)
Inform all monitors about the KX state of the given peer.
static struct GNUNET_SCHEDULER_Task * rekey_task
Task scheduled for periodic re-generation (and thus rekeying) of our ephemeral key.
void pid_change_cb(void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *hash)
#define CAKE_LABEL
Labeled expand label for CAKE.
int GSC_KX_init(void)
Initialize KX subsystem.
static void restart_kx(struct GSC_KeyExchangeInfo *kx)
static void handle_initiator_hello_cont(void *cls, const struct GNUNET_ShortHashCode *ss_R)
static struct GNUNET_TRANSPORT_CoreHandle * transport
Transport service.
static void handle_heartbeat(struct GSC_KeyExchangeInfo *kx, const struct Heartbeat *m)
Handle a key update.
static void handle_initiator_done(void *cls, const struct InitiatorDone *idm_e)
Handle InitiatorDone message.
#define R_HS_TRAFFIC_STR
String for expanding RHTS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
void send_responder_hello(struct GSC_KeyExchangeInfo *kx)
#define RESEND_TIMEOUT
#define TRAFFIC_UPD_STR
String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-sch...
@ GSC_HEARTBEAT_KEY_UPDATE_REQUESTED
A key update is requested.
void GSC_SESSIONS_end(const struct GNUNET_PeerIdentity *pid)
End the session with the given peer (we are no longer connected).
void GSC_SESSIONS_create(const struct GNUNET_PeerIdentity *peer, struct GSC_KeyExchangeInfo *kx, enum GNUNET_CORE_PeerClass class)
Create a session, a key exchange was just completed.
static unsigned long long payload
How much data are we currently storing in the database?
static struct GNUNET_Process * p
Helper process we started.
Definition gnunet-uri.c:38
struct GNUNET_PILS_Handle * GNUNET_PILS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PILS_PidChangeCallback pid_change_cb, void *cls)
Connect to the PILS service.
Definition pils_api.c:465
void GNUNET_PILS_disconnect(struct GNUNET_PILS_Handle *handle)
Disconnect from the PILS service.
Definition pils_api.c:488
const struct GNUNET_HashCode * GNUNET_PILS_get_identity_hash(const struct GNUNET_PILS_Handle *handle)
Return the hash of the current peer identity from a given handle.
Definition pils_api.c:736
void GNUNET_PILS_cancel(struct GNUNET_PILS_Operation *op)
Cancel request.
Definition pils_api.c:623
const struct GNUNET_PeerIdentity * GNUNET_PILS_get_identity(const struct GNUNET_PILS_Handle *handle)
Return the current peer identity of a given handle.
Definition pils_api.c:727
struct GNUNET_PILS_Operation * GNUNET_PILS_kem_decaps(struct GNUNET_PILS_Handle *handle, const struct GNUNET_CRYPTO_HpkeEncapsulation *c, GNUNET_PILS_DecapsResultCallback cb, void *cb_cls)
Decaps an encapsulated key with our private key.
Definition pils_api.c:568
struct GNUNET_TRANSPORT_CoreHandle * GNUNET_TRANSPORT_core_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *self, const struct GNUNET_MQ_MessageHandler *handlers, void *cls, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd)
Connect to the transport service.
void GNUNET_TRANSPORT_core_disconnect(struct GNUNET_TRANSPORT_CoreHandle *handle)
Disconnect from the transport service.
#define GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
After how long do we consider a connection to a peer dead if we don't receive messages from the peer?
GNUNET_CORE_PeerClass
The peer class gives a hint about the capabilities of a peer.
GNUNET_CORE_KxState
TODO how does this harmonize with CAKE_CRYPTO_ENABLED?
@ GNUNET_CORE_CLASS_UNKNOWN
The device's capabilities are currently unknown.
@ GNUNET_CORE_KX_PEER_DISCONNECT
Last state of a KX (when it is being terminated).
@ GNUNET_CORE_KX_STATE_RESPONDER_CONNECTED
Connected as responder.
@ GNUNET_CORE_KX_STATE_DOWN
No handshake yet.
@ GNUNET_CORE_KX_STATE_INITIATOR_DONE_SENT
We sent initiator done.
@ GNUNET_CORE_KX_STATE_INITIATOR_HELLO_RECEIVED
We've received the initiator hello.
@ GNUNET_CORE_KX_STATE_AWAIT_INITIATION
We are awating the initiator hello.
@ GNUNET_CORE_KX_STATE_INITIATOR_CONNECTED
Connected as initiator.
@ GNUNET_CORE_KX_STATE_INITIATOR_HELLO_SENT
We sent the initiator hello.
@ GNUNET_CORE_KX_STATE_RESPONDER_HELLO_SENT
We sent the responder hello.
@ GNUNET_CORE_KX_ITERATION_FINISHED
This is not a state in a peer's state machine, but a special value used with the GNUNET_CORE_MonitorC...
void GNUNET_CRYPTO_ecdhe_key_create(struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
Create a new private key.
Definition crypto_ecc.c:454
uint64_t GNUNET_CRYPTO_random_u64(uint64_t max)
Generate a random unsigned 64-bit value.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hpke_kem_decaps(const struct GNUNET_CRYPTO_HpkePrivateKey *priv, const struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Decapsulate a key for a private X25519 key.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hpke_kem_encaps(const struct GNUNET_CRYPTO_HpkePublicKey *pkR, struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Encapsulate key material for a X25519 public key.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_eddsa_kem_encaps(const struct GNUNET_CRYPTO_EddsaPublicKey *pub, struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Encapsulate key material for a EdDSA public key.
void GNUNET_CRYPTO_ecdhe_key_get_public(const struct GNUNET_CRYPTO_EcdhePrivateKey *priv, struct GNUNET_CRYPTO_EcdhePublicKey *pub)
Extract the public key for the given private key.
Definition crypto_ecc.c:217
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hkdf_extract(struct GNUNET_ShortHashCode *prk, const void *salt, size_t salt_len, const void *ikm, size_t ikm_len)
HKDF-Extract using SHA256.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:40
void GNUNET_CRYPTO_hmac(const struct GNUNET_CRYPTO_AuthKey *key, const void *plaintext, size_t plaintext_len, struct GNUNET_HashCode *hmac)
Calculate HMAC of a message (RFC 2104)
#define GNUNET_CRYPTO_hkdf_expand(result, out_len, prk,...)
HKDF-Expand using SHA256.
int GNUNET_CRYPTO_hash_cmp(const struct GNUNET_HashCode *h1, const struct GNUNET_HashCode *h2)
Compare function for HashCodes, producing a total ordering of all hashcodes.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_B2S(obj)
Convert a fixed-sized object to a string using GNUNET_b2s().
void GNUNET_CRYPTO_hash_context_read(struct GNUNET_HashContext *hc, const void *buf, size_t size)
Add data to be hashed.
struct GNUNET_HashContext * GNUNET_CRYPTO_hash_context_copy(const struct GNUNET_HashContext *hc)
Make a copy of the hash computation.
#define GNUNET_CRYPTO_kdf_arg_string(d)
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
void * cls
Closure for mv and cb.
void GNUNET_CRYPTO_hash_context_abort(struct GNUNET_HashContext *hc)
Abort hashing, do not bother calculating final result.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
void GNUNET_CRYPTO_hash_context_finish(struct GNUNET_HashContext *hc, struct GNUNET_HashCode *r_hash)
Finish the hash computation.
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_CRYPTO_kdf_arg_auto(d)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
struct GNUNET_HashContext * GNUNET_CRYPTO_hash_context_start(void)
Start incremental hashing operation.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
void GNUNET_print_bytes(const void *buf, size_t buf_len, int fold, int in_be)
Print a byte string in hexadecimal ascii notation.
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition nc.c:138
void GNUNET_MQ_send_copy(struct GNUNET_MQ_Handle *mq, const struct GNUNET_MQ_Envelope *ev)
Send a copy of a message with the given message queue.
Definition mq.c:384
unsigned int GNUNET_MQ_get_length(struct GNUNET_MQ_Handle *mq)
Obtain the current length of the message queue.
Definition mq.c:293
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:305
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
void GNUNET_MQ_discard(struct GNUNET_MQ_Envelope *mqm)
Discard the message queue message, free all allocated resources.
Definition mq.c:285
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition nc.c:122
void GNUNET_notification_context_broadcast(struct GNUNET_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop)
Send a message to all subscribers of this context.
Definition nc.c:190
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition nc.c:161
#define GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT
Message updating the keys of the peers.
#define GNUNET_MESSAGE_TYPE_CORE_ACK
Acknowledgement of prior messages.
#define GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE_CAKE
Encrypted message.
#define GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY
Reply for monitor by CORE service.
#define GNUNET_MESSAGE_TYPE_CORE_INITIATOR_DONE
Third and final message of the handshake, second of the initiator.
#define GNUNET_MESSAGE_TYPE_CORE_RESPONDER_HELLO
Reply to the first message from the initiator - first message sent by the responder.
#define GNUNET_MESSAGE_TYPE_CORE_INITIATOR_HELLO
for more detail on the following messages see https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1283
enum GNUNET_GenericReturnValue GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition mst.c:101
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition mst.c:86
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition mst.c:404
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_max(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the maximum of two relative time values.
Definition time.c:352
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition time.c:406
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition time.c:316
struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Divide relative time by a given factor.
Definition time.c:548
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_difference(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute end)
Compute the time difference between the given start and end times.
Definition time.c:423
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:636
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition time.c:667
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
static unsigned int size
Size of the "table".
Definition peer.c:68
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
struct GNUNET_MessageHeader header
Message type is GNUNET_MESSAGE_TYPE_CORE_ACK.
type for (message) authentication keys
HPKE DHKEM encapsulation (X25519) See RFC 9180.
A public key used for decryption.
struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_key
An ECDHE/X25519 key.
A public key used for encryption.
struct GNUNET_CRYPTO_EcdhePublicKey ecdhe_key
An ECDHE/X25519 key.
Context for parsing HELLOs.
Definition hello-uri.c:233
A 512-bit hashcode.
Handle to a message queue.
Definition mq.c:87
Message handler for a specific message type.
Header for all communications.
Handle to a message stream tokenizer.
Definition mst.c:45
The notification context is the key datastructure for a convenience API used for transmission of noti...
Definition nc.c:77
The identity of the host (wraps the signing key of the peer).
struct GNUNET_CRYPTO_EddsaPublicKey public_key
Entry in list of pending tasks.
Definition scheduler.c:141
A 256-bit hashcode.
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
Handle for the transport service (includes all of the state for the transport service).
Information about the status of a key exchange with another peer.
struct GSC_KeyExchangeInfo * prev
DLL.
struct GNUNET_ShortHashCode their_ats[10]
*ATS - other peers application traffic secret by epoch
struct GNUNET_ShortHashCode ss_R
struct GNUNET_ShortHashCode ihts
IHTS - Initiator handshake secret TODO.
struct GNUNET_TIME_Absolute current_epoch_expiration
Expiration time of our current epoch.
struct GNUNET_ShortHashCode early_secret_key
ES - Early Secret Key TODO uniform naming: _key?
struct GNUNET_ShortHashCode master_secret
Master secret key TODO.
uint64_t current_sqn
Our current sequence number.
struct GNUNET_TIME_Absolute last_notify_timeout
Last time we notified monitors.
enum GSC_KX_Role role
Own role in the key exchange.
struct GNUNET_MessageStreamTokenizer * mst
Our message stream tokenizer (for encrypted payload).
struct GSC_KeyExchangeInfo * next
DLL.
struct GNUNET_CRYPTO_HpkePrivateKey sk_e
Initiator secret key.
unsigned int resend_tries_left
Resend tries left.
struct GNUNET_SCHEDULER_Task * resend_task
Task for resending messages during handshake.
struct GNUNET_PeerIdentity peer
Identity of the peer.
struct GNUNET_MQ_Handle * mq
Message queue for sending messages to peer.
struct GNUNET_ShortHashCode early_traffic_secret
ETS - Early traffic secret TODO.
uint64_t their_max_epoch
Highest seen (or used) epoch of responder resp initiator.
struct GNUNET_TIME_Absolute timeout
When should the session time out (if there are no Acks to HEARTBEATs)?
struct GNUNET_MQ_Envelope * resend_env
Env for resending messages.
struct GNUNET_ShortHashCode rhts
RHTS - Responder handshake secret TODO.
struct GNUNET_ShortHashCode ss_I
struct GNUNET_ShortHashCode handshake_secret
HS - Handshake secret TODO.
struct GNUNET_ShortHashCode ss_e
int has_excess_bandwidth
GNUNET_YES if this peer currently has excess bandwidth.
enum GNUNET_CORE_KxState status
What is our connection state?
struct GNUNET_CRYPTO_HpkePublicKey pk_e
Initiator ephemeral key.
struct GNUNET_HashContext * transcript_hash_ctx
The transcript hash context.
uint64_t current_epoch
Our currently used epoch for sending.
enum GNUNET_CORE_PeerClass class
Peer class of the other peer TODO still needed?
struct GNUNET_ShortHashCode current_ats
*ATS - our current application traffic secret by epoch
struct GNUNET_SCHEDULER_Task * heartbeat_task
ID of task used for sending keep-alive pings.
struct GNUNET_MessageHeader header
Message type is #GNUNET_MESSAGE_TYPE_CORE_PONG.
struct GNUNET_HashCode finished
TODO {Finished} - encrypted.
struct PilsRequest * req
struct InitiatorHello * ihm_e
struct GSC_KeyExchangeInfo * kx
struct GNUNET_PeerIdentity pk_I
Sender Peer ID.
uint16_t peer_class
The peer class of the sending peer TODO part of services info?
uint64_t r_I
Random number to make replay attacks harder.
struct GNUNET_CRYPTO_EcdhePublicKey pk_e
Ephemeral public edx25519 key.
struct GNUNET_CRYPTO_HpkeEncapsulation c_R
Key encapsulation.
struct GNUNET_MessageHeader header
Message type is #GNUNET_MESSAGE_TYPE_CORE_PONG.
struct GNUNET_HashCode h_pk_R
Hash of the responder peer id.
Message sent by the service to monitor clients to notify them about a peer changing status.
Definition core.h:313
uint32_t state
New peer state, an enum GNUNET_CORE_KxState in NBO.
Definition core.h:322
struct GNUNET_TIME_AbsoluteNBO timeout
How long will we stay in this state (if nothing else happens)?
Definition core.h:332
struct GNUNET_PILS_Operation * op
The pils operation.
struct PilsRequest * next
DLL.
struct PilsRequest * prev
DLL.
struct GNUNET_ShortHashCode ss_e
struct GNUNET_ShortHashCode ihts
struct GNUNET_ShortHashCode rhts
struct ResponderHello rhm_e
struct ResponderHelloPayload * rhp
struct GSC_KeyExchangeInfo * kx
char finished_enc[sizeof(struct GNUNET_HashCode)+crypto_aead_xchacha20poly1305_ietf_ABYTES]
struct GNUNET_HashContext * hc
struct GNUNET_HashCode decrypted_finish
struct GNUNET_ShortHashCode hs
struct PilsRequest * req
struct GNUNET_CRYPTO_HpkeEncapsulation c_I
Challenge encapsulation c_I.
struct GNUNET_CRYPTO_HpkeEncapsulation c_e
Ephemeral key encapsulation c_e.
uint64_t r_R
Random number to make replay attacks harder.
struct GNUNET_MessageHeader header
Message type is #GNUNET_MESSAGE_TYPE_CORE_PONG.

◆ MIN_HEARTBEAT_FREQUENCY

#define MIN_HEARTBEAT_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)

What is the minimum frequency for a HEARTBEAT message?

Definition at line 79 of file gnunet-service-core_kx.c.

◆ HEARTBEAT_FREQUENCY

#define HEARTBEAT_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)

How often do we send a heartbeat?

Definition at line 85 of file gnunet-service-core_kx.c.

◆ MAX_EPOCHS

#define MAX_EPOCHS   10

Maximum number of epochs we keep on hand.

This implicitly defines the maximum age of messages we accept from other peers, depending on their rekey interval.

Definition at line 94 of file gnunet-service-core_kx.c.

◆ EPOCH_EXPIRATION

#define EPOCH_EXPIRATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)

How often do we rekey/switch to a new epoch?

Definition at line 99 of file gnunet-service-core_kx.c.

◆ REKEY_TOLERANCE

#define REKEY_TOLERANCE    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)

What time difference do we tolerate?

Definition at line 105 of file gnunet-service-core_kx.c.

◆ EARLY_DATA_STR

#define EARLY_DATA_STR   "early data"

String for expanding early transport secret (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 112 of file gnunet-service-core_kx.c.

◆ R_HS_TRAFFIC_STR

#define R_HS_TRAFFIC_STR   "r hs traffic"

String for expanding RHTS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 118 of file gnunet-service-core_kx.c.

◆ I_HS_TRAFFIC_STR

#define I_HS_TRAFFIC_STR   "i hs traffic"

String for expanding IHTS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 124 of file gnunet-service-core_kx.c.

◆ R_AP_TRAFFIC_STR

#define R_AP_TRAFFIC_STR   "r ap traffic"

String for expanding RATS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 130 of file gnunet-service-core_kx.c.

◆ I_AP_TRAFFIC_STR

#define I_AP_TRAFFIC_STR   "i ap traffic"

String for expanding IATS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 136 of file gnunet-service-core_kx.c.

◆ DERIVED_STR

#define DERIVED_STR   "derived"

String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 142 of file gnunet-service-core_kx.c.

◆ R_FINISHED_STR

#define R_FINISHED_STR   "r finished"

String for expanding fk_R used for ResponderFinished field (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 148 of file gnunet-service-core_kx.c.

◆ I_FINISHED_STR

#define I_FINISHED_STR   "i finished"

String for expanding fk_I used for InitiatorFinished field (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 154 of file gnunet-service-core_kx.c.

◆ CAKE_LABEL

#define CAKE_LABEL   "cake10"

Labeled expand label for CAKE.

Definition at line 159 of file gnunet-service-core_kx.c.

◆ KEY_STR

#define KEY_STR   "key"

String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 165 of file gnunet-service-core_kx.c.

◆ TRAFFIC_UPD_STR

#define TRAFFIC_UPD_STR   "traffic upd"

String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 171 of file gnunet-service-core_kx.c.

◆ IV_STR

#define IV_STR   "iv"

String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake.html)

Definition at line 177 of file gnunet-service-core_kx.c.

Enumeration Type Documentation

◆ GSC_KX_Role

Indicates whether a peer is in the initiating or receiving role.

Enumerator
ROLE_INITIATOR 
ROLE_RESPONDER 

Definition at line 183 of file gnunet-service-core_kx.c.

184{
185 /* Peer is supposed to initiate the key exchange */
186 ROLE_INITIATOR = 0,
187
188 /* Peer is supposed to wait for the key exchange */
189 ROLE_RESPONDER = 1,
190};

Function Documentation

◆ buffer_clear()

static void buffer_clear ( void *  buf,
size_t  len 
)
static

Definition at line 438 of file gnunet-service-core_kx.c.

439{
440#if HAVE_MEMSET_S
441 memset_s (buf, len, 0, len);
442#elif HAVE_EXPLICIT_BZERO
443 explicit_bzero (buf, len);
444#else
445 volatile unsigned char *p = buf;
446 while (len--)
447 *p++ = 0;
448#endif
449}

References p.

Referenced by cleanup_handshake_secrets().

Here is the caller graph for this function:

◆ cleanup_handshake_secrets()

static void cleanup_handshake_secrets ( struct GSC_KeyExchangeInfo kx)
static

Definition at line 453 of file gnunet-service-core_kx.c.

454{
455 buffer_clear (&kx->ihts,
456 sizeof kx->ihts);
457 buffer_clear (&kx->rhts,
458 sizeof kx->rhts);
459 buffer_clear (&kx->sk_e,
460 sizeof kx->sk_e);
461 buffer_clear (&kx->ss_I,
462 sizeof kx->ss_I);
463 buffer_clear (&kx->ss_R,
464 sizeof kx->ss_R);
465 buffer_clear (&kx->ss_e,
466 sizeof kx->ss_e);
468 sizeof kx->master_secret);
470 sizeof kx->early_secret_key);
472 sizeof kx->early_traffic_secret);
474 sizeof kx->handshake_secret);
475}

References buffer_clear(), GSC_KeyExchangeInfo::early_secret_key, GSC_KeyExchangeInfo::early_traffic_secret, GSC_KeyExchangeInfo::handshake_secret, GSC_KeyExchangeInfo::ihts, GSC_KeyExchangeInfo::master_secret, GSC_KeyExchangeInfo::rhts, GSC_KeyExchangeInfo::sk_e, GSC_KeyExchangeInfo::ss_e, GSC_KeyExchangeInfo::ss_I, and GSC_KeyExchangeInfo::ss_R.

Referenced by check_if_ack_or_heartbeat(), and handle_initiator_done().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ snapshot_transcript()

static void snapshot_transcript ( const struct GNUNET_HashContext ts_hash,
struct GNUNET_HashCode snapshot 
)
static

Definition at line 479 of file gnunet-service-core_kx.c.

481{
482 struct GNUNET_HashContext *tmp;
483
484 tmp = GNUNET_CRYPTO_hash_context_copy (ts_hash);
485 GNUNET_CRYPTO_hash_context_finish (tmp, snapshot);
486}

References GNUNET_CRYPTO_hash_context_copy(), and GNUNET_CRYPTO_hash_context_finish().

Referenced by handle_initiator_done(), handle_initiator_hello_cont(), handle_responder_hello(), handle_responder_hello_cont(), send_initiator_hello(), and send_responder_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ monitor_notify_all()

static void monitor_notify_all ( struct GSC_KeyExchangeInfo kx)
static

Inform all monitors about the KX state of the given peer.

Parameters
kxkey exchange state to inform about

Definition at line 495 of file gnunet-service-core_kx.c.

496{
498
500 msg.header.size = htons (sizeof(msg));
501 msg.state = htonl ((uint32_t) kx->status);
502 msg.peer = kx->peer;
503 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
506}

References GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY, GNUNET_NO, GNUNET_notification_context_broadcast(), GNUNET_TIME_absolute_hton(), GSC_KeyExchangeInfo::last_notify_timeout, msg, nc, GSC_KeyExchangeInfo::peer, GNUNET_MessageHeader::size, GSC_KeyExchangeInfo::status, GSC_KeyExchangeInfo::timeout, and GNUNET_MessageHeader::type.

Referenced by check_if_ack_or_heartbeat(), handle_encrypted_message(), handle_initiator_done(), handle_initiator_hello_cont(), handle_responder_hello_cont(), handle_transport_notify_disconnect(), restart_kx(), send_heartbeat(), send_initiator_hello(), send_responder_hello(), and update_timeout().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ restart_kx()

static void restart_kx ( struct GSC_KeyExchangeInfo kx)
static

Definition at line 633 of file gnunet-service-core_kx.c.

634{
635 const struct GNUNET_HashCode *my_identity_hash;
636 struct GNUNET_HashCode h1;
637
638 // TODO what happens if we're in the middle of a peer id change?
639 // TODO there's a small chance this gets already called when we don't have a
640 // peer id yet. Add a kx, insert into the list, mark it as to be completed
641 // and let the callback to pils finish the rest once we got the peer id
642
644 "Initiating key exchange with peer %s\n",
645 GNUNET_i2s (&kx->peer));
647 gettext_noop ("# key exchanges initiated"),
648 1,
649 GNUNET_NO);
650
652 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
653 GNUNET_assert (NULL != my_identity_hash);
654 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
655 if (NULL != kx->transcript_hash_ctx)
657 kx->transcript_hash_ctx = NULL;
658 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, my_identity_hash))
659 {
660 /* peer with "lower" identity starts KX, otherwise we typically end up
661 with both peers starting the exchange and transmit the 'set key'
662 message twice */
664 "I am the initiator, sending hello\n");
665 kx->role = ROLE_INITIATOR;
667 }
668 else
669 {
670 /* peer with "higher" identity starts a delayed KX, if the "lower" peer
671 * does not start a KX since it sees no reasons to do so */
673 "I am the responder, yielding and await initiator hello\n");
675 kx->role = ROLE_RESPONDER;
677 }
678}

References gettext_noop, GNUNET_assert, GNUNET_CORE_KX_STATE_AWAIT_INITIATION, GNUNET_CRYPTO_hash(), GNUNET_CRYPTO_hash_cmp(), GNUNET_CRYPTO_hash_context_abort(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_PILS_get_identity_hash(), GNUNET_STATISTICS_update(), GSC_pils, GSC_stats, monitor_notify_all(), GSC_KeyExchangeInfo::peer, GSC_KeyExchangeInfo::role, ROLE_INITIATOR, ROLE_RESPONDER, send_initiator_hello(), GSC_KeyExchangeInfo::status, and GSC_KeyExchangeInfo::transcript_hash_ctx.

Referenced by handle_encrypted_message(), handle_initiator_hello_cont(), handle_transport_notify_connect(), resend_initiator_done(), resend_responder_hello(), and send_heartbeat().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_heartbeat()

static void send_heartbeat ( void *  cls)
static

Task triggered when a neighbour entry is about to time out (and we should prevent this by sending an Ack in response to a heartbeat).

Parameters
clsthe struct GSC_KeyExchangeInfo

Definition at line 520 of file gnunet-service-core_kx.c.

521{
522 struct GSC_KeyExchangeInfo *kx = cls;
523 struct GNUNET_TIME_Relative retry;
524 struct GNUNET_TIME_Relative left;
525 struct Heartbeat hb;
526
527 kx->heartbeat_task = NULL;
529 if (0 == left.rel_value_us)
530 {
532 gettext_noop ("# sessions terminated by timeout"),
533 1,
534 GNUNET_NO);
535 GSC_SESSIONS_end (&kx->peer);
538 restart_kx (kx);
539 return;
540 }
542 "Sending HEARTBEAT to `%s'\n",
543 GNUNET_i2s (&kx->peer));
545 gettext_noop ("# heartbeat messages sent"),
546 1,
547 GNUNET_NO);
548 hb.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT);
549 hb.header.size = htons (sizeof hb);
550 // FIXME when do we request update?
551 hb.flags = 0;
552 GSC_KX_encrypt_and_transmit (kx, &hb, sizeof hb);
555 kx->heartbeat_task =
557}

References Heartbeat::flags, gettext_noop, GNUNET_CORE_KX_STATE_DOWN, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT, GNUNET_NO, GNUNET_SCHEDULER_add_delayed(), GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_max(), GSC_KX_encrypt_and_transmit(), GSC_SESSIONS_end(), GSC_stats, Heartbeat::header, GSC_KeyExchangeInfo::heartbeat_task, MIN_HEARTBEAT_FREQUENCY, monitor_notify_all(), GSC_KeyExchangeInfo::peer, GNUNET_TIME_Relative::rel_value_us, restart_kx(), send_heartbeat(), GNUNET_MessageHeader::size, GSC_KeyExchangeInfo::status, GSC_KeyExchangeInfo::timeout, and GNUNET_MessageHeader::type.

Referenced by handle_heartbeat(), send_heartbeat(), and update_timeout().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_timeout()

static void update_timeout ( struct GSC_KeyExchangeInfo kx)
static

We've seen a valid message from the other peer.

Update the time when the session would time out and delay sending our keep alive message further.

Parameters
kxkey exchange where we saw activity

Definition at line 568 of file gnunet-service-core_kx.c.

569{
571
572 kx->timeout =
574 delta =
576 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
577 {
578 /* we only notify monitors about timeout changes if those
579 are bigger than the threshold (5s) */
581 }
582 if (NULL != kx->heartbeat_task)
587 kx);
588}

References delta, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_TIME_absolute_get_difference(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_to_absolute(), GSC_KeyExchangeInfo::heartbeat_task, GSC_KeyExchangeInfo::last_notify_timeout, monitor_notify_all(), GNUNET_TIME_Relative::rel_value_us, send_heartbeat(), and GSC_KeyExchangeInfo::timeout.

Referenced by check_if_ack_or_heartbeat(), handle_encrypted_message(), handle_heartbeat(), and handle_initiator_done().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_initiator_hello()

static void send_initiator_hello ( struct GSC_KeyExchangeInfo kx)
static

Send initiator hello.

Parameters
kxkey exchange context

Definition at line 2587 of file gnunet-service-core_kx.c.

2588{
2589 const struct GNUNET_PeerIdentity *my_identity;
2590 struct GNUNET_MQ_Envelope *env;
2591 struct GNUNET_ShortHashCode es;
2592 struct GNUNET_ShortHashCode ets;
2593 struct GNUNET_ShortHashCode ss_R;
2594 struct InitiatorHelloPayload *ihmp; /* initiator hello message - buffer on stack */
2595 struct InitiatorHello *ihm_e; /* initiator hello message - encrypted */
2596 long long unsigned int c_len;
2597 unsigned char enc_key[AEAD_KEY_BYTES];
2598 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2600 size_t pt_len;
2601
2603 GNUNET_assert (NULL != my_identity);
2604
2605 pt_len = sizeof (*ihmp) + strlen (my_services_info);
2606 c_len = pt_len + AEAD_TAG_BYTES;
2607 env = GNUNET_MQ_msg_extra (ihm_e,
2608 c_len,
2610 ihmp = (struct InitiatorHelloPayload*) &ihm_e[1];
2611 ihmp->peer_class = htons (GNUNET_CORE_CLASS_UNKNOWN); // TODO set this to a meaningful
2612 GNUNET_memcpy (&ihmp->pk_I,
2614 sizeof (struct GNUNET_PeerIdentity));
2615 GNUNET_CRYPTO_hash (&kx->peer, /* what to hash */ // TODO do we do this twice?
2616 sizeof (struct GNUNET_PeerIdentity),
2617 &ihm_e->h_pk_R); /* result */
2618 // TODO init hashcontext/transcript_hash
2619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send InitiatorHello: %d %d\n", kx->role,
2620 kx->status);
2621 GNUNET_assert (NULL == kx->transcript_hash_ctx);
2623 GNUNET_assert (NULL != kx->transcript_hash_ctx);
2624 // TODO fill services_info
2625
2626 // 1. Encaps
2627 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public ephemeral key of initiator
2628 &ihm_e->c_R, // encapsulated key
2629 &ss_R); // key - ss_R
2630 if (GNUNET_OK != ret)
2631 {
2633 "Something went wrong encapsulating ss_R\n");
2634 // TODO handle
2635 }
2636 // 2. generate rR (uint64_t) - is this the nonce? Naming seems not quite
2637 // consistent
2638 ihm_e->r_I =
2639 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
2640 // 3. generate sk_e/pk_e - ephemeral key
2643 &kx->sk_e.ecdhe_key,
2644 &kx->pk_e.ecdhe_key);
2645 GNUNET_memcpy (&ihm_e->pk_e,
2646 &kx->pk_e.ecdhe_key,
2647 sizeof (kx->pk_e.ecdhe_key));
2648 // 4. generate ETS to encrypt
2649 // generate ETS (early_traffic_secret_key, decrypt pk_i
2650 // expand ETS <- expand ES <- extract ss_R
2651 // use ETS to decrypt
2653 ihm_e,
2654 sizeof (struct InitiatorHello));
2655 {
2656 struct GNUNET_HashCode transcript;
2658 &transcript);
2659 derive_es_ets (&transcript,
2660 &ss_R,
2661 &es,
2662 &ets);
2664 0,
2665 enc_key,
2666 enc_nonce);
2667 }
2668 // 5. encrypt
2669
2670 ret = crypto_aead_xchacha20poly1305_ietf_encrypt (
2671 (unsigned char*) &ihm_e[1], /* c - ciphertext */
2672 // mac,
2673 // NULL, // maclen_p
2674 &c_len, /* clen_p */
2675 (unsigned char*) ihmp, /* m - plaintext message */
2676 pt_len, // mlen
2677 NULL, 0, // ad, adlen // FIXME maybe over the unencrypted header?
2678 // fields?
2679 NULL, // nsec - unused
2680 enc_nonce, // npub - nonce
2681 enc_key); // k - key
2682 if (0 != ret)
2683 {
2684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong encrypting\n");
2686 kx->transcript_hash_ctx = NULL;
2688 return;
2689 }
2690 /* Forward the transcript */
2693 &ihm_e[1],
2694 c_len);
2695
2697 kx->early_secret_key = es;
2698 kx->early_traffic_secret = ets;
2699 kx->ss_R = ss_R;
2700 monitor_notify_all (kx);
2701 GNUNET_MQ_send_copy (kx->mq, env);
2702 kx->resend_env = env;
2706 kx);
2707}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, AEAD_TAG_BYTES, InitiatorHello::c_R, derive_es_ets(), derive_per_message_secrets(), GSC_KeyExchangeInfo::early_secret_key, GSC_KeyExchangeInfo::early_traffic_secret, GNUNET_CRYPTO_HpkePrivateKey::ecdhe_key, GNUNET_CRYPTO_HpkePublicKey::ecdhe_key, env, GNUNET_assert, GNUNET_CORE_CLASS_UNKNOWN, GNUNET_CORE_KX_STATE_INITIATOR_HELLO_SENT, GNUNET_CRYPTO_ecdhe_key_create(), GNUNET_CRYPTO_ecdhe_key_get_public(), GNUNET_CRYPTO_eddsa_kem_encaps(), GNUNET_CRYPTO_hash(), GNUNET_CRYPTO_hash_context_abort(), GNUNET_CRYPTO_hash_context_read(), GNUNET_CRYPTO_hash_context_start(), GNUNET_CRYPTO_random_u64(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_CORE_INITIATOR_HELLO, GNUNET_MQ_discard(), GNUNET_MQ_msg_extra, GNUNET_MQ_send_copy(), GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_SCHEDULER_add_delayed(), GSC_pils, InitiatorHello::h_pk_R, monitor_notify_all(), GSC_KeyExchangeInfo::mq, my_identity, my_services_info, GSC_KeyExchangeInfo::peer, InitiatorHelloPayload::peer_class, GSC_KeyExchangeInfo::pk_e, InitiatorHello::pk_e, InitiatorHelloPayload::pk_I, GNUNET_PeerIdentity::public_key, InitiatorHello::r_I, GSC_KeyExchangeInfo::resend_env, resend_initiator_hello(), RESEND_MAX_TRIES, GSC_KeyExchangeInfo::resend_task, RESEND_TIMEOUT, GSC_KeyExchangeInfo::resend_tries_left, ret, GSC_KeyExchangeInfo::role, GSC_KeyExchangeInfo::sk_e, snapshot_transcript(), GSC_KeyExchangeInfo::ss_R, GSC_KeyExchangeInfo::status, and GSC_KeyExchangeInfo::transcript_hash_ctx.

Referenced by restart_kx().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ deliver_message()

static int deliver_message ( void *  cls,
const struct GNUNET_MessageHeader m 
)
static

Deliver P2P message to interested clients.

Invokes send twice, once for clients that want the full message, and once for clients that only want the header

Parameters
clsthe struct GSC_KeyExchangeInfo
mthe message
Returns
GNUNET_OK on success, GNUNET_NO to stop further processing (no error) GNUNET_SYSERR to stop further processing with error

Definition at line 612 of file gnunet-service-core_kx.c.

613{
614 struct GSC_KeyExchangeInfo *kx = cls;
615
617 "Decrypted message of type %d from %s\n",
618 ntohs (m->type),
619 GNUNET_i2s (&kx->peer));
621 m,
622 ntohs (m->size),
625 m,
626 sizeof(struct GNUNET_MessageHeader),
628 return GNUNET_OK;
629}

References GNUNET_CORE_OPTION_SEND_FULL_INBOUND, GNUNET_CORE_OPTION_SEND_HDR_INBOUND, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_OK, GSC_CLIENTS_deliver_message(), m, and GSC_KeyExchangeInfo::peer.

Referenced by handle_transport_notify_connect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_transport_notify_connect()

static void * handle_transport_notify_connect ( void *  cls,
const struct GNUNET_PeerIdentity peer_id,
struct GNUNET_MQ_Handle mq 
)
static

Function called by transport to notify us that a peer connected to us (on the network level).

Starts the key exchange with the given peer.

Parameters
clsclosure (NULL)
mqmessage queue towards peer
peer_id(optional, may be NULL) the peer id of the connecting peer
Returns
key exchange information context

Definition at line 692 of file gnunet-service-core_kx.c.

695{
696 const struct GNUNET_PeerIdentity *my_identity;
697 struct GSC_KeyExchangeInfo *kx;
698 (void) cls;
700 GNUNET_assert (NULL != my_identity);
701 if (0 == memcmp (peer_id, my_identity, sizeof *peer_id))
702 {
704 "Ignoring connection to self\n");
705 return NULL;
706 }
708 "Incoming connection of peer with %s\n",
710
711 /* Set up kx struct */
712 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
714 kx->mq = mq;
715 GNUNET_memcpy (&kx->peer, peer_id, sizeof (struct GNUNET_PeerIdentity));
717
718 restart_kx (kx);
719 return kx;
720}

References deliver_message(), GNUNET_assert, GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_memcpy, GNUNET_MST_create(), GNUNET_new, GNUNET_PILS_get_identity(), GSC_pils, kx_head, kx_tail, mq, GSC_KeyExchangeInfo::mq, GSC_KeyExchangeInfo::mst, my_identity, GSC_KeyExchangeInfo::peer, peer_id, and restart_kx().

Referenced by GSC_KX_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ derive_es_ets()

static void derive_es_ets ( const struct GNUNET_HashCode transcript,
const struct GNUNET_ShortHashCode ss_R,
struct GNUNET_ShortHashCode es,
struct GNUNET_ShortHashCode ets 
)
static

TODO propose a new scheme: don't choose an initiator and responder based on hashing the peer ids, but: let each peer be their own initiator (and responder) when opening a channel towards another peer.

It should be fine to have two channels in 'both directions' (one as responder, one as initiator) under the hood. This can be opaque to the upper layers. FIXME: (MSC) This is probably a bad idea in terms of security of the AKE! Schedule for

  • forwarding the transcript hash context and
  • deriving/generating keys/finished fields

Forwarding: Deriving Messages -> pk_e -> c_R -> r_I -> H(pk_R) -> ETS -> {pk_I, svcinfo_I}ETS -------------------------------------------------— send InitiatorHello -> c_e -> r_R -> *HTS -> {svcinfo_R, c_I}RHTS -> finished_R -> {finished_R}RHTS -> finished_I -> RATS_0 -> [{payload}RATS] -------------------------------------------------— send ResponderHello -> {finished_I}IHTS -> IATS_0 -------------------------------------------------— send InitiatorDone

Definition at line 769 of file gnunet-service-core_kx.c.

773{
774 uint64_t ret;
775
776 ret = GNUNET_CRYPTO_hkdf_extract (es, // prk
777 0, // salt
778 0, // salt_len
779 ss_R, // ikm - initial key material
780 sizeof (*ss_R));
781 if (GNUNET_OK != ret)
782 {
783 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting ES\n")
784 ;
785 GNUNET_assert (0);
786 }
788 ets,
789 sizeof (*ets),
790 es,
793 GNUNET_CRYPTO_kdf_arg_auto (transcript));
794 if (GNUNET_OK != ret)
795 {
796 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
797 ;
798 GNUNET_assert (0);
799 }
800}

References CAKE_LABEL, EARLY_DATA_STR, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_hkdf_extract(), GNUNET_CRYPTO_kdf_arg_auto, GNUNET_CRYPTO_kdf_arg_string, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_OK, ret, and GSC_KeyExchangeInfo::ss_R.

Referenced by handle_initiator_hello_cont(), and send_initiator_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ derive_sn()

static void derive_sn ( const struct GNUNET_ShortHashCode secret,
unsigned char *  sn,
size_t  sn_len 
)
static

Definition at line 808 of file gnunet-service-core_kx.c.

811{
814 sn,
815 sn_len,
816 secret,
819}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_kdf_arg_string, and GNUNET_OK.

Referenced by GSC_KX_encrypt_and_transmit(), and handle_encrypted_message().

Here is the caller graph for this function:

◆ derive_hs()

static void derive_hs ( const struct GNUNET_ShortHashCode es,
const struct GNUNET_ShortHashCode ss_e,
struct GNUNET_ShortHashCode handshake_secret 
)
static

Derive the handshake secret.

Parameters
kxkey exchange info

Definition at line 827 of file gnunet-service-core_kx.c.

830{
831 uint64_t ret;
832 struct GNUNET_ShortHashCode derived_early_secret;
833
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deriving HS\n");
836 );
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ss_e: %s\n", GNUNET_B2S (ss_e));
839 &derived_early_secret,
840 sizeof (derived_early_secret),
841 es,
845 derived_early_secret));
846 if (GNUNET_OK != ret)
847 {
848 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dES\n")
849 ;
850 GNUNET_assert (0);
851 }
852 // Handshake secret
853 // TODO check: are dES the salt and ss_e the ikm or other way round?
854 ret = GNUNET_CRYPTO_hkdf_extract (handshake_secret, // prk
855 &derived_early_secret, // salt - dES
856 sizeof (derived_early_secret), // salt_len
857 ss_e, // ikm - initial key material
858 sizeof (*ss_e));
859 if (GNUNET_OK != ret)
860 {
861 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting HS\n")
862 ;
863 GNUNET_assert (0);
864 }
865}

References CAKE_LABEL, DERIVED_STR, GNUNET_assert, GNUNET_B2S, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_hkdf_extract(), GNUNET_CRYPTO_kdf_arg_string, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_OK, and ret.

Referenced by handle_responder_hello(), and send_responder_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ derive_ihts()

static void derive_ihts ( const struct GNUNET_HashCode transcript,
const struct GNUNET_ShortHashCode hs,
struct GNUNET_ShortHashCode ihts 
)
static

Derive the initiator handshake secret.

Parameters
kxkey exchange info

Definition at line 873 of file gnunet-service-core_kx.c.

876{
879 ihts, // result
880 sizeof (*ihts), // result len
881 hs, // prk?
884 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
885}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_kdf_arg_auto, GNUNET_CRYPTO_kdf_arg_string, GNUNET_OK, and I_HS_TRAFFIC_STR.

Referenced by handle_responder_hello(), and send_responder_hello().

Here is the caller graph for this function:

◆ derive_rhts()

static void derive_rhts ( const struct GNUNET_HashCode transcript,
const struct GNUNET_ShortHashCode hs,
struct GNUNET_ShortHashCode rhts 
)
static

Derive the responder handshake secret.

Parameters
kxkey exchange info

Definition at line 893 of file gnunet-service-core_kx.c.

896{
899 rhts,
900 sizeof (*rhts),
901 hs, // prk? TODO
904 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
905}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_kdf_arg_auto, GNUNET_CRYPTO_kdf_arg_string, GNUNET_OK, and R_HS_TRAFFIC_STR.

Referenced by handle_responder_hello(), and send_responder_hello().

Here is the caller graph for this function:

◆ derive_ms()

static void derive_ms ( const struct GNUNET_ShortHashCode hs,
const struct GNUNET_ShortHashCode ss_I,
struct GNUNET_ShortHashCode ms 
)
static

Derive the master secret.

Parameters
kxkey exchange info

Definition at line 913 of file gnunet-service-core_kx.c.

916{
917 uint64_t ret;
918 struct GNUNET_ShortHashCode derived_handshake_secret;
919
921 &derived_handshake_secret,
922 sizeof (derived_handshake_secret),
923 hs,
926 if (GNUNET_OK != ret)
927 {
928 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dHS\n")
929 ;
930 GNUNET_assert (0);
931 }
932 // TODO check: are dHS the salt and ss_I the ikm or other way round?
933 ret = GNUNET_CRYPTO_hkdf_extract (ms, // prk
934 &derived_handshake_secret, // salt - dHS
935 sizeof (derived_handshake_secret), // salt_len
936 ss_I, // ikm - initial key material
937 sizeof (*ss_I));
938 if (GNUNET_OK != ret)
939 {
940 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting MS\n")
941 ;
942 GNUNET_assert (0);
943 }
944}

References CAKE_LABEL, DERIVED_STR, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_hkdf_extract(), GNUNET_CRYPTO_kdf_arg_string, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_OK, and ret.

Referenced by handle_responder_hello_cont(), and send_responder_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_per_record_nonce()

static void generate_per_record_nonce ( uint64_t  seq,
const uint8_t  write_iv[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES],
uint8_t  per_record_write_iv[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] 
)
static

Generate per record nonce as per https://www.rfc-editor.org/rfc/rfc8446#section-5.3 using per key nonce and sequence number.

Definition at line 953 of file gnunet-service-core_kx.c.

957{
958 uint64_t seq_nbo;
959 uint64_t *write_iv_ptr;
960 unsigned int byte_offset;
961
962 seq_nbo = GNUNET_htonll (seq);
963 memcpy (per_record_write_iv,
964 write_iv,
966 byte_offset =
967 AEAD_NONCE_BYTES - sizeof (uint64_t);
968 write_iv_ptr = (uint64_t*) (per_record_write_iv + byte_offset);
969 *write_iv_ptr ^= seq_nbo;
970}

References AEAD_NONCE_BYTES, and GNUNET_htonll().

Referenced by derive_per_message_secrets().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ derive_per_message_secrets()

static void derive_per_message_secrets ( const struct GNUNET_ShortHashCode ts,
uint64_t  seq,
unsigned char  key[crypto_aead_xchacha20poly1305_ietf_KEYBYTES],
unsigned char  nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] 
)
static

key = HKDF-Expand [I,R][A,H]TS, "key", 32) nonce = HKDF-Expand ([I,R][A,H]TS, "iv", 24)

Definition at line 978 of file gnunet-service-core_kx.c.

983{
984 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
985 /* derive actual key */
988 key,
990 ts,
993
994 /* derive nonce */
997 nonce_tmp,
999 ts,
1003 nonce_tmp,
1004 nonce);
1005}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, CAKE_LABEL, generate_per_record_nonce(), GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_kdf_arg_string, GNUNET_OK, IV_STR, key, and KEY_STR.

Referenced by GSC_KX_encrypt_and_transmit(), handle_encrypted_message(), handle_initiator_done(), handle_initiator_hello_cont(), handle_responder_hello(), handle_responder_hello_cont(), send_initiator_hello(), and send_responder_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ derive_next_ats()

static void derive_next_ats ( const struct GNUNET_ShortHashCode old_ats,
struct GNUNET_ShortHashCode new_ats 
)
static

Derive the next application secret.

Parameters
kxkey exchange info

Definition at line 1013 of file gnunet-service-core_kx.c.

1015{
1016 int8_t ret;
1017
1018 // FIXME: Not sure of PRK and output may overlap here!
1020 new_ats,
1021 sizeof (*new_ats),
1022 old_ats,
1025 if (GNUNET_OK != ret)
1026 {
1028 "Something went wrong deriving next *ATS key\n");
1029 GNUNET_assert (0);
1030 }
1031}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_kdf_arg_string, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_OK, ret, and TRAFFIC_UPD_STR.

Referenced by check_rekey(), handle_encrypted_message(), handle_heartbeat(), handle_initiator_done(), and handle_responder_hello_cont().

Here is the caller graph for this function:

◆ derive_initial_ats()

static void derive_initial_ats ( const struct GNUNET_HashCode transcript,
const struct GNUNET_ShortHashCode ms,
enum GSC_KX_Role  role,
struct GNUNET_ShortHashCode initial_ats 
)
static

Derive the initiator application secret.

Parameters
kxkey exchange info

Definition at line 1039 of file gnunet-service-core_kx.c.

1043{
1044 const char *traffic_str;
1045
1046 if (ROLE_INITIATOR == role)
1047 traffic_str = I_AP_TRAFFIC_STR;
1048 else
1049 traffic_str = R_AP_TRAFFIC_STR;
1052 initial_ats, // result
1053 sizeof (*initial_ats), // result len
1054 ms,
1056 GNUNET_CRYPTO_kdf_arg_string (traffic_str),
1057 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
1058}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_kdf_arg_auto, GNUNET_CRYPTO_kdf_arg_string, GNUNET_OK, I_AP_TRAFFIC_STR, R_AP_TRAFFIC_STR, and ROLE_INITIATOR.

Referenced by handle_initiator_done(), handle_responder_hello_cont(), and send_responder_hello().

Here is the caller graph for this function:

◆ generate_responder_finished()

static void generate_responder_finished ( const struct GNUNET_HashCode transcript,
const struct GNUNET_ShortHashCode ms,
struct GNUNET_HashCode result 
)
static

Generate the responder finished field.

Parameters
kxkey exchange info
resultlocation to which the responder finished field will be written to

Definition at line 1068 of file gnunet-service-core_kx.c.

1071{
1073 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1074
1076 &fk_R, // result
1077 sizeof (fk_R),
1078 ms,
1081 if (GNUNET_OK != ret)
1082 {
1084 "Something went wrong expanding fk_R\n");
1085 GNUNET_assert (0);
1086 }
1087
1088 GNUNET_CRYPTO_hmac (&fk_R,
1089 transcript,
1090 sizeof (*transcript),
1091 result);
1092}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_hmac(), GNUNET_CRYPTO_kdf_arg_string, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_OK, R_FINISHED_STR, result, and ret.

Referenced by handle_responder_hello_cont(), and send_responder_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_initiator_finished()

static void generate_initiator_finished ( const struct GNUNET_HashCode transcript,
const struct GNUNET_ShortHashCode ms,
struct GNUNET_HashCode result 
)
static

Generate the initiator finished field.

Parameters
kxkey exchange info
resultlocation to which the initiator finished field will be written to

Definition at line 1102 of file gnunet-service-core_kx.c.

1105{
1107 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1108
1110 &fk_I, // result
1111 sizeof (fk_I),
1112 ms,
1115 if (GNUNET_OK != ret)
1116 {
1118 "Something went wrong expanding fk_I\n");
1119 GNUNET_assert (0);
1120 }
1121 GNUNET_CRYPTO_hmac (&fk_I,
1122 transcript,
1123 sizeof (*transcript),
1124 result);
1125}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand, GNUNET_CRYPTO_hmac(), GNUNET_CRYPTO_kdf_arg_string, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_OK, I_FINISHED_STR, result, and ret.

Referenced by handle_initiator_done(), and handle_responder_hello_cont().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resend_responder_hello()

static void resend_responder_hello ( void *  cls)
static

Definition at line 1136 of file gnunet-service-core_kx.c.

1137{
1138 struct GSC_KeyExchangeInfo *kx = cls;
1139
1140 kx->resend_task = NULL;
1141 if (0 == kx->resend_tries_left)
1142 {
1144 "Restarting KX\n");
1145 restart_kx (kx);
1146 return;
1147 }
1148 kx->resend_tries_left--;
1150 "Resending responder hello. Retries left: %u\n",
1151 kx->resend_tries_left);
1155 kx);
1156}

References GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_MQ_send_copy(), GNUNET_SCHEDULER_add_delayed(), GSC_KeyExchangeInfo::mq, GSC_KeyExchangeInfo::resend_env, resend_responder_hello(), GSC_KeyExchangeInfo::resend_task, RESEND_TIMEOUT, GSC_KeyExchangeInfo::resend_tries_left, and restart_kx().

Referenced by resend_responder_hello(), and send_responder_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_responder_hello()

void send_responder_hello ( struct GSC_KeyExchangeInfo kx)

Definition at line 1160 of file gnunet-service-core_kx.c.

1161{
1164 struct ResponderHello *rhm_e; /* responder hello message - encrypted pointer */
1165 struct GNUNET_MQ_Envelope *env;
1166 struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_kem_challenge;
1167 struct GNUNET_ShortHashCode rhts;
1168 struct GNUNET_ShortHashCode ihts;
1169 struct GNUNET_ShortHashCode hs;
1170 struct GNUNET_ShortHashCode ms;
1171 struct GNUNET_ShortHashCode ss_e;
1172 struct GNUNET_ShortHashCode ss_I;
1173 struct GNUNET_HashContext *hc;
1174 unsigned char enc_key[AEAD_KEY_BYTES];
1175 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1176
1177 // 4. encaps -> shared_secret_e, c_e (kemChallenge)
1178 // TODO potentially write this directly into rhm?
1179 ret = GNUNET_CRYPTO_hpke_kem_encaps (&kx->pk_e, // public ephemeral key of initiator
1180 &ephemeral_kem_challenge, // encapsulated key
1181 &ss_e); // key - ss_e
1182 if (GNUNET_OK != ret)
1183 {
1185 "Something went wrong encapsulating ss_e\n");
1186 return;
1187 }
1189 // 6. encaps -> shared_secret_I, c_I
1190 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public key of I
1191 &c_I, // encapsulated key
1192 &ss_I); // where to write the key material
1193 if (GNUNET_OK != ret)
1194 {
1196 "Something went wrong encapsulating ss_I\n");
1198 return;
1199 }
1200 // 7. generate RHTS (responder_handshare_secret_key) and RATS (responder_application_traffic_secret_key) (section 5)
1201 {
1202 struct GNUNET_HashCode transcript;
1203 snapshot_transcript (hc, &transcript);
1204#if DEBUG_KX
1206 "Transcript snapshot for derivation of HS, MS: `%s'\n",
1207 GNUNET_h2s (&transcript));
1208#endif
1210 &ss_e,
1211 &hs);
1212 derive_ms (&hs, &ss_I, &ms);
1213 }
1214
1215 // send ResponderHello
1216 // TODO fill fields / services_info!
1217 // 1. r_R <- random
1218 struct ResponderHelloPayload *rhp;
1219 size_t rhp_len = sizeof (*rhp) + strlen (my_services_info);
1220 unsigned char rhp_buf[rhp_len];
1221 size_t ct_len;
1222
1223 rhp = (struct ResponderHelloPayload*) rhp_buf;
1224 ct_len = rhp_len // ResponderHelloPayload, fist PT msg
1225 + sizeof (struct GNUNET_HashCode) // Finished hash, second PT msg
1226 + AEAD_TAG_BYTES * 2; // Two tags;
1227 env = GNUNET_MQ_msg_extra (rhm_e,
1228 ct_len,
1230
1231 rhm_e->r_R =
1232 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
1233
1234 // c_e
1235 GNUNET_memcpy (&rhm_e->c_e,
1236 &ephemeral_kem_challenge,
1237 sizeof (ephemeral_kem_challenge));
1239 rhm_e,
1240 sizeof (struct ResponderHello));
1241 // 2. Encrypt ServicesInfo and c_I with RHTS
1242 // derive RHTS
1243 {
1244 struct GNUNET_HashCode transcript;
1246 &transcript);
1247#if DEBUG_KX
1249 "Transcript snapshot for derivation of *HTS: `%s'\n",
1250 GNUNET_h2s (&transcript));
1251#endif
1252 derive_rhts (&transcript,
1253 &hs,
1254 &rhts);
1255 derive_ihts (&transcript,
1256 &hs,
1257 &ihts);
1259 0,
1260 enc_key,
1261 enc_nonce);
1262 }
1263 // c_I
1264 GNUNET_memcpy (&rhp->c_I, &c_I, sizeof (c_I));
1265 // Services info empty for now.
1266 GNUNET_memcpy (&rhp[1],
1268 strlen (my_services_info));
1269
1270 {
1271 unsigned long long out_ct_len;
1273 struct GNUNET_HashCode transcript;
1274 unsigned char *finished_buf;
1275 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1276 (unsigned char*) &rhm_e[1], /* c - ciphertext */
1277 &out_ct_len, /* clen_p */
1278 rhp_buf, /* rhm_p - plaintext message */
1279 rhp_len, // mlen
1280 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1281 // fields?
1282 NULL, // nsec - unused
1283 enc_nonce, // npub - nonce // FIXME nonce can be reused
1284 enc_key)); // k - key RHTS
1286 "Encrypted and wrote %llu bytes\n",
1287 out_ct_len);
1288 // 3. Create ResponderFinished (Section 6)
1289 // Derive fk_I <- HKDF-Expand (MS, "r finished", NULL)
1290 /* Forward the transcript */
1291 /* {svcinfo, c_I}RHTS */
1293 hc,
1294 &rhm_e[1],
1295 out_ct_len);
1296
1297 finished_buf = ((unsigned char*) &rhm_e[1]) + out_ct_len;
1299 &transcript);
1300#if DEBUG_KX
1302 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1303 GNUNET_h2s (&transcript));
1304#endif
1305 generate_responder_finished (&transcript,
1306 &ms,
1307 &finished);
1308 // 4. Encrypt ResponderFinished
1310 1,
1311 enc_key,
1312 enc_nonce);
1313 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1314 finished_buf, /* c - ciphertext */
1315 &out_ct_len, /* clen_p */
1316 (unsigned char*) &finished, /* rhm_p - plaintext message */
1317 sizeof (finished), // mlen
1318 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1319 // fields?
1320 NULL, // nsec - unused
1321 enc_nonce, // npub
1322 enc_key)); // k - key RHTS
1324 "Encrypted and wrote %llu bytes\n",
1325 out_ct_len);
1326 /* Forward the transcript
1327 * after responder finished,
1328 * before deriving *ATS and generating finished_I
1329 * (finished_I will be generated when receiving the InitiatorFinished message
1330 * in order to check it) */
1332 hc,
1333 finished_buf,
1334 out_ct_len);
1335 // 5. optionally send application data - encrypted with RATS
1336 // We do not really have any application data, instead, we send the ACK
1338 &transcript);
1339#if DEBUG_KX
1341 "Transcript snapshot for derivation of *ATS: `%s'\n",
1342 GNUNET_h2s (&transcript));
1343#endif
1344 derive_initial_ats (&transcript,
1345 &ms,
1347 &kx->current_ats);
1348 }
1349 /* Lock into struct */
1351 kx->transcript_hash_ctx = hc;
1352 kx->master_secret = ms;
1353 kx->handshake_secret = hs;
1354 kx->ss_e = ss_e;
1355 kx->ihts = ihts;
1356 kx->rhts = rhts;
1357 kx->ss_I = ss_I;
1358 kx->current_epoch = 0;
1359 kx->current_sqn = 0;
1361 kx->current_sqn,
1362 enc_key,
1363 enc_nonce);
1364
1365 GNUNET_MQ_send_copy (kx->mq, env);
1366 kx->resend_env = env;
1368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent ResponderHello: %d %d\n", kx->role,
1369 kx->status);
1370
1373 kx);
1375 monitor_notify_all (kx);
1376 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1377}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, AEAD_TAG_BYTES, ResponderHello::c_e, ResponderHelloPayload::c_I, GSC_KeyExchangeInfo::current_ats, GSC_KeyExchangeInfo::current_epoch, GSC_KeyExchangeInfo::current_sqn, derive_hs(), derive_ihts(), derive_initial_ats(), derive_ms(), derive_per_message_secrets(), derive_rhts(), GSC_KeyExchangeInfo::early_secret_key, env, finished, generate_responder_finished(), GNUNET_assert, GNUNET_CORE_KX_STATE_RESPONDER_HELLO_SENT, GNUNET_CRYPTO_eddsa_kem_encaps(), GNUNET_CRYPTO_hash_context_abort(), GNUNET_CRYPTO_hash_context_copy(), GNUNET_CRYPTO_hash_context_read(), GNUNET_CRYPTO_hpke_kem_encaps(), GNUNET_CRYPTO_random_u64(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_h2s(), GNUNET_log, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_CORE_RESPONDER_HELLO, GNUNET_MQ_msg_extra, GNUNET_MQ_send_copy(), GNUNET_OK, GNUNET_SCHEDULER_add_delayed(), GSC_KeyExchangeInfo::handshake_secret, GSC_KeyExchangeInfo::ihts, GSC_KeyExchangeInfo::master_secret, monitor_notify_all(), GSC_KeyExchangeInfo::mq, my_services_info, GSC_KeyExchangeInfo::peer, GSC_KeyExchangeInfo::pk_e, GNUNET_PeerIdentity::public_key, ResponderHello::r_R, GSC_KeyExchangeInfo::resend_env, RESEND_MAX_TRIES, resend_responder_hello(), GSC_KeyExchangeInfo::resend_task, RESEND_TIMEOUT, GSC_KeyExchangeInfo::resend_tries_left, ret, GSC_KeyExchangeInfo::rhts, GSC_KeyExchangeInfo::role, ROLE_RESPONDER, snapshot_transcript(), GSC_KeyExchangeInfo::ss_e, GSC_KeyExchangeInfo::ss_I, GSC_KeyExchangeInfo::status, GSC_KeyExchangeInfo::transcript_hash_ctx, and transport.

Referenced by handle_initiator_hello_cont().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_initiator_hello_cont()

static void handle_initiator_hello_cont ( void *  cls,
const struct GNUNET_ShortHashCode ss_R 
)
static

Definition at line 1381 of file gnunet-service-core_kx.c.

1382{
1383 const struct GNUNET_HashCode *my_identity_hash;
1384 struct InitiatorHelloCtx *ihm_ctx = cls;
1385 struct GSC_KeyExchangeInfo *kx = ihm_ctx->kx;
1386 uint32_t ihm_len = ntohs (ihm_ctx->ihm_e->header.size);
1387 unsigned char enc_key[AEAD_KEY_BYTES];
1388 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1389 struct GNUNET_HashCode h1;
1390 struct GNUNET_HashCode transcript;
1391 struct GNUNET_ShortHashCode es;
1392 struct GNUNET_ShortHashCode ets;
1394
1395 ihm_ctx->req->op = NULL;
1398 ihm_ctx->req);
1399 GNUNET_free (ihm_ctx->req);
1400
1401
1403 &ihm_ctx->ihm_e->pk_e,
1404 sizeof (ihm_ctx->ihm_e->pk_e));
1405 // 5. generate ETS (early_traffic_secret_key, decrypt pk_i
1406 // expand ETS <- expand ES <- extract ss_R
1407 // use ETS to decrypt
1408
1409 /* Forward the transcript hash context over the unencrypted fields to get it
1410 * to the same status that the initiator had when it needed to derive es and
1411 * ets for the encryption */
1414 ihm_ctx->ihm_e,
1415 sizeof (struct InitiatorHello));
1417 &transcript);
1418#if DEBUG_KX
1420 "Transcript snapshot for derivation of ES, ETS: `%s'\n",
1421 GNUNET_h2s (&transcript));
1422#endif
1423 derive_es_ets (&transcript, ss_R, &es, &ets);
1425 0,
1426 enc_key,
1427 enc_nonce);
1428 {
1429 struct InitiatorHelloPayload *ihmp;
1430 size_t ct_len = ihm_len - sizeof (struct InitiatorHello);
1431 unsigned char ihmp_buf[ct_len - AEAD_TAG_BYTES];
1432 ihmp = (struct InitiatorHelloPayload*) ihmp_buf;
1433 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1434 ihmp_buf, // unsigned char *m
1435 NULL, // mlen_p message length
1436 NULL, // unsigned char *nsec - unused: NULL
1437 (unsigned char*) &ihm_ctx->ihm_e[1], // const unsigned char *c - ciphertext
1438 ct_len, // unsigned long long clen - length of ciphertext
1439 // mac, // const unsigned char *mac - authentication tag
1440 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1441 0, // unsigned long long adlen
1442 enc_nonce, // const unsigned char *npub - nonce
1443 enc_key // const unsigned char *k - key
1444 );
1445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pid_sender: %s\n",
1446 GNUNET_i2s (&ihmp->pk_I));
1447 if (0 != ret)
1448 {
1450 "Something went wrong decrypting: %d\n", ret);
1451 GNUNET_break_op (0);
1452 GNUNET_free (ihm_ctx->ihm_e);
1453 GNUNET_free (ihm_ctx);
1454 restart_kx (kx);
1455 return;
1456 }
1457 /* now forward it considering the encrypted messages that the initiator was
1458 * able to send after deriving the es and ets */
1460 &ihm_ctx->ihm_e[1],
1461 ct_len);
1462 GNUNET_memcpy (&kx->peer,
1463 &ihmp->pk_I,
1464 sizeof (struct GNUNET_PeerIdentity));
1465 }
1466
1467 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
1468 GNUNET_assert (NULL != my_identity_hash);
1469
1470 // We could follow with the rest of the Key Schedule (dES, HS, ...) for now
1471 /* Check that we are actually in the receiving role */
1472 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
1473 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, my_identity_hash))
1474 {
1475 /* peer with "lower" identity starts KX, otherwise we typically end up
1476 with both peers starting the exchange and transmit the 'set key'
1477 message twice */
1478 /* Something went wrong - we have the lower value and should have sent the
1479 * InitiatorHello, but instead received it. TODO handle this case
1480 * We might end up in this case if the initiator didn't initiate the
1481 * handshake long enough and the 'responder' initiates the handshake */
1483 "Something went wrong - we have the lower value and should have sent the InitiatorHello, but instead received it.\n");
1484 GNUNET_free (ihm_ctx->ihm_e);
1485 GNUNET_free (ihm_ctx);
1487 kx->transcript_hash_ctx = NULL;
1488 return;
1489 }
1490
1491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer ID of other peer: %s\n", GNUNET_i2s
1492 (&kx->peer));
1493 /* We update the monitoring peers here because now we know
1494 * that we can decrypt the message AND know the PID
1495 */
1496 monitor_notify_all (kx);
1497 kx->ss_R = *ss_R;
1498 kx->early_secret_key = es;
1499 kx->early_traffic_secret = ets;
1501}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, AEAD_TAG_BYTES, derive_es_ets(), derive_per_message_secrets(), GSC_KeyExchangeInfo::early_secret_key, GSC_KeyExchangeInfo::early_traffic_secret, GNUNET_CRYPTO_HpkePublicKey::ecdhe_key, GNUNET_assert, GNUNET_break_op, GNUNET_CONTAINER_DLL_remove, GNUNET_CRYPTO_hash(), GNUNET_CRYPTO_hash_cmp(), GNUNET_CRYPTO_hash_context_abort(), GNUNET_CRYPTO_hash_context_read(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_memcpy, GNUNET_PILS_get_identity_hash(), GSC_pils, InitiatorHello::header, InitiatorHelloCtx::ihm_e, InitiatorHelloCtx::kx, monitor_notify_all(), PilsRequest::op, GSC_KeyExchangeInfo::peer, pils_requests_head, pils_requests_tail, GSC_KeyExchangeInfo::pk_e, InitiatorHello::pk_e, InitiatorHelloPayload::pk_I, InitiatorHelloCtx::req, restart_kx(), ret, send_responder_hello(), GNUNET_MessageHeader::size, snapshot_transcript(), GSC_KeyExchangeInfo::ss_R, and GSC_KeyExchangeInfo::transcript_hash_ctx.

Referenced by handle_initiator_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_initiator_hello()

static int check_initiator_hello ( void *  cls,
const struct InitiatorHello m 
)
static

Definition at line 1505 of file gnunet-service-core_kx.c.

1506{
1507 uint16_t size = ntohs (m->header.size);
1508
1509 if (size < sizeof (*m)
1510 + sizeof (struct InitiatorHelloPayload)
1512 {
1513 return GNUNET_SYSERR;
1514 }
1515 return GNUNET_OK;
1516}

References AEAD_TAG_BYTES, GNUNET_OK, GNUNET_SYSERR, m, and size.

◆ handle_initiator_hello()

static void handle_initiator_hello ( void *  cls,
const struct InitiatorHello ihm_e 
)
static

Handle the InitiatorHello message.

  • derives necessary keys from the plaintext parts
  • decrypts the encrypted part
  • replies with ResponderHello message
    Parameters
    clsthe key exchange info
    ihm_eInitiatorHello message

Definition at line 1528 of file gnunet-service-core_kx.c.

1529{
1530 const struct GNUNET_HashCode *my_identity_hash;
1531 struct GSC_KeyExchangeInfo *kx = cls;
1532 struct InitiatorHelloCtx *initiator_hello_cls;
1533 size_t ihm_len;
1534
1535 if (ROLE_INITIATOR == kx->role)
1536 {
1537 GNUNET_break_op (0);
1539 "I am an initiator! Tearing down...\n");
1540 return;
1541 }
1543 {
1544 GNUNET_break_op (0);
1546 "Already received InitiatorHello: %d %d\n", kx->role, kx->status
1547 );
1548 return;
1549 }
1551 (NULL != kx->transcript_hash_ctx))
1552 {
1554 "Already received InitiatorHello and sent ResponderHello: %d %d\n",
1555 kx->role, kx->status);
1556 return;
1557 }
1558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorHello: %d %d\n", kx->
1559 role, kx->status);
1563
1565 gettext_noop ("# key exchanges initiated"),
1566 1,
1567 GNUNET_NO);
1568
1570
1571 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
1572 GNUNET_assert (NULL != my_identity_hash);
1573
1574 // 1. verify type _INITIATOR_HELLO
1575 // - This is implicytly done by arriving within this handler
1576 // - or is this about verifying the 'additional data' part of aead?
1577 // should it check the encryption + mac? (is this implicitly done
1578 // while decrypting?)
1579 // 2. verify H(pk_R) matches pk_R
1580 if (0 != memcmp (&ihm_e->h_pk_R,
1581 my_identity_hash,
1582 sizeof (struct GNUNET_HashCode)))
1583 {
1585 "This message is not meant for us (H(PID) mismatch)\n");
1587 kx->transcript_hash_ctx = NULL;
1588 return;
1589 }
1590 // FIXME this sometimes triggers in the tests - why?
1591 // 3. decaps -> shared_secret_R, c_R (kemChallenge)
1592 ihm_len = ntohs (ihm_e->header.size);
1593 initiator_hello_cls = GNUNET_new (struct InitiatorHelloCtx);
1594 initiator_hello_cls->kx = kx;
1595 initiator_hello_cls->ihm_e = GNUNET_malloc (ihm_len);
1596 GNUNET_memcpy (initiator_hello_cls->ihm_e, ihm_e, ihm_len);
1597 initiator_hello_cls->req = GNUNET_new (struct PilsRequest);
1600 initiator_hello_cls->req);
1601 initiator_hello_cls->req->op =
1603 &ihm_e->c_R,
1604 // encapsulated key
1606 // continuation
1607 initiator_hello_cls);
1608}

References InitiatorHello::c_R, gettext_noop, GNUNET_assert, GNUNET_break_op, GNUNET_CONTAINER_DLL_insert, GNUNET_CORE_KX_STATE_INITIATOR_HELLO_RECEIVED, GNUNET_CRYPTO_hash_context_abort(), GNUNET_CRYPTO_hash_context_start(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_new, GNUNET_NO, GNUNET_PILS_get_identity_hash(), GNUNET_PILS_kem_decaps(), GNUNET_STATISTICS_update(), GSC_pils, GSC_stats, InitiatorHello::h_pk_R, handle_initiator_hello_cont(), InitiatorHello::header, InitiatorHelloCtx::ihm_e, InitiatorHelloCtx::kx, PilsRequest::op, pils_requests_head, pils_requests_tail, InitiatorHelloCtx::req, GSC_KeyExchangeInfo::role, ROLE_INITIATOR, GNUNET_MessageHeader::size, GSC_KeyExchangeInfo::status, and GSC_KeyExchangeInfo::transcript_hash_ctx.

Here is the call graph for this function:

◆ resend_initiator_done()

static void resend_initiator_done ( void *  cls)
static

Definition at line 1649 of file gnunet-service-core_kx.c.

1650{
1651 struct GSC_KeyExchangeInfo *kx = cls;
1652
1653 kx->resend_task = NULL;
1654 if (0 == kx->resend_tries_left)
1655 {
1657 "Restarting KX\n");
1658 restart_kx (kx);
1659 return;
1660 }
1661 kx->resend_tries_left--;
1663 "Resending initiator done. Retries left: %u\n",
1664 kx->resend_tries_left);
1668 kx);
1669}

References GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_MQ_send_copy(), GNUNET_SCHEDULER_add_delayed(), GSC_KeyExchangeInfo::mq, GSC_KeyExchangeInfo::resend_env, resend_initiator_done(), GSC_KeyExchangeInfo::resend_task, RESEND_TIMEOUT, GSC_KeyExchangeInfo::resend_tries_left, and restart_kx().

Referenced by handle_responder_hello_cont(), and resend_initiator_done().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_responder_hello_cont()

static void handle_responder_hello_cont ( void *  cls,
const struct GNUNET_ShortHashCode ss_I 
)
static

Definition at line 1673 of file gnunet-service-core_kx.c.

1674{
1675 struct ResponderHelloCls *rh_ctx = cls;
1676 struct GSC_KeyExchangeInfo *kx = rh_ctx->kx;
1677 struct InitiatorDone *idm_e; /* encrypted */
1678 struct InitiatorDone idm_local;
1679 struct InitiatorDone *idm_p; /* plaintext */
1680 struct GNUNET_MQ_Envelope *env;
1681 unsigned char enc_key[AEAD_KEY_BYTES];
1682 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1683 struct ConfirmationAck ack_i;
1684 struct GNUNET_HashCode transcript;
1685 struct GNUNET_ShortHashCode ms;
1686
1687 rh_ctx->req->op = NULL;
1690 rh_ctx->req);
1691 GNUNET_free (rh_ctx->req);
1692 // XXX valgrind reports uninitialized memory
1693 // the following is a way to check whether this memory was meant
1694 // memset (&rhm_local, 0, sizeof (rhm_local)); - adapt to cls if still needed
1695 memset (&idm_local, 0, sizeof (idm_local));
1696
1697 kx->ss_I = *ss_I;
1698
1699 /* derive *ATS */
1700 derive_ms (&rh_ctx->hs, ss_I, &ms);;
1701 // 5. Create ResponderFinished as per Section 6 and check against decrypted payload.
1702 struct GNUNET_HashCode responder_finished;
1703 // Transcript updates, snapshot again
1704 snapshot_transcript (rh_ctx->hc,
1705 &transcript);
1706#if DEBUG_KX
1708 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1709 GNUNET_h2s (&transcript));
1710#endif
1711 generate_responder_finished (&transcript,
1712 &ms,
1713 &responder_finished);
1714 if (0 != memcmp (&rh_ctx->decrypted_finish,
1715 &responder_finished,
1716 sizeof (struct GNUNET_HashCode)))
1717 {
1719 "Could not verify \"responder finished\"\n");
1720 GNUNET_free (rh_ctx->rhp);
1722 GNUNET_free (rh_ctx);
1723 GNUNET_assert (0);
1724 return;
1725 }
1726
1727
1728 /* Forward the transcript
1729 * after generating finished_R,
1730 * before deriving *ATS */
1732 rh_ctx->hc,
1733 rh_ctx->finished_enc,
1734 sizeof (rh_ctx->finished_enc));
1735
1736 // At this point we cannot fail anymore and may lock into kx
1738 kx->transcript_hash_ctx = rh_ctx->hc;
1739 kx->ss_I = *ss_I;
1740 kx->handshake_secret = rh_ctx->hs;
1741 kx->ss_e = rh_ctx->ss_e;
1742 kx->ihts = rh_ctx->ihts;
1743 kx->rhts = rh_ctx->rhts;
1744 kx->master_secret = ms;
1745 GNUNET_free (rh_ctx->rhp);
1746 GNUNET_free (rh_ctx);
1747 rh_ctx = NULL;
1748
1750 &transcript);
1751#if DEBUG_KX
1753 "Transcript snapshot for derivation of *ATS: `%s'\n",
1754 GNUNET_h2s (&transcript));
1755#endif
1756 derive_initial_ats (&transcript,
1757 &kx->master_secret,
1759 &kx->their_ats[0]);
1760 for (int i = 0; i < MAX_EPOCHS - 1; i++)
1761 {
1762 derive_next_ats (&kx->their_ats[i],
1763 &kx->their_ats[i + 1]);
1764 }
1765 kx->their_max_epoch = MAX_EPOCHS - 1;
1766
1768 0,
1769 enc_key,
1770 enc_nonce);
1771 /* Create InitiatorDone message */
1772 idm_p = &idm_local; /* plaintext */
1773 env = GNUNET_MQ_msg_extra (idm_e,
1774 sizeof (ack_i)
1777 // 6. Create IteratorFinished as per Section 6.
1778 generate_initiator_finished (&transcript,
1779 &kx->master_secret,
1780 &idm_p->finished);
1782 "InteratorFinished: `%s'\n",
1783 GNUNET_h2s (&idm_p->finished));
1785 "Transcript `%s'\n",
1786 GNUNET_h2s (&transcript));
1787 // 7. Send InteratorFinished message encrypted with the key derived from IHTS to R
1788
1789 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1790 (unsigned char*) &idm_e->finished, /* c - ciphertext */
1791 NULL, /* clen_p */
1792 (unsigned char*) &idm_p->finished, /* idm_p - plaintext message */
1793 sizeof (idm_p->finished), // mlen
1794 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1795 // fields?
1796 NULL, // nsec - unused
1797 enc_nonce, // npub - nonce
1798 enc_key)); // k - key IHTS
1799 /* Forward the transcript hash context
1800 * after generating finished_I and RATS_0
1801 * before deriving IATS_0 */
1803 &idm_e->finished,
1804 sizeof (idm_e->finished)
1805 + AEAD_TAG_BYTES);
1807 &transcript);
1808#if DEBUG_KX
1810 "Transcript snapshot for derivation of *ATS: `%s'\n",
1811 GNUNET_h2s (&transcript));
1812#endif
1813 derive_initial_ats (&transcript,
1814 &kx->master_secret,
1816 &kx->current_ats);
1817 kx->current_epoch = 0;
1818 kx->current_sqn++;
1819 // 8. optionally encrypt payload TODO
1821 kx->current_sqn,
1822 enc_key,
1823 enc_nonce);
1824 kx->current_sqn++;
1825 ack_i.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
1826 ack_i.header.size = htons (sizeof ack_i);
1827 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1828 (unsigned char*) &idm_e[1], /* c - ciphertext */
1829 NULL, /* clen_p */
1830 (unsigned char*) &ack_i, /* rhm_p - plaintext message */
1831 sizeof ack_i, // mlen
1832 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1833 // fields?
1834 NULL, // nsec - unused
1835 enc_nonce, // npub - nonce // FIXME nonce can be reused
1836 enc_key)); // k - key RHTS
1837
1838 GNUNET_MQ_send_copy (kx->mq, env);
1839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent InitiatorDone: %d %d\n", kx->role,
1840 kx->status);
1841
1842
1843 kx->resend_env = env;
1847 kx);
1849 monitor_notify_all (kx);
1850 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1851}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, AEAD_TAG_BYTES, GSC_KeyExchangeInfo::current_ats, GSC_KeyExchangeInfo::current_epoch, GSC_KeyExchangeInfo::current_sqn, ResponderHelloCls::decrypted_finish, derive_initial_ats(), derive_ms(), derive_next_ats(), derive_per_message_secrets(), env, InitiatorDone::finished, ResponderHelloCls::finished_enc, generate_initiator_finished(), generate_responder_finished(), GNUNET_assert, GNUNET_CONTAINER_DLL_remove, GNUNET_CORE_KX_STATE_INITIATOR_DONE_SENT, GNUNET_CRYPTO_hash_context_abort(), GNUNET_CRYPTO_hash_context_read(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_h2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_CORE_ACK, GNUNET_MESSAGE_TYPE_CORE_INITIATOR_DONE, GNUNET_MQ_msg_extra, GNUNET_MQ_send_copy(), GNUNET_SCHEDULER_add_delayed(), GSC_KeyExchangeInfo::handshake_secret, ResponderHelloCls::hc, ConfirmationAck::header, ResponderHelloCls::hs, GSC_KeyExchangeInfo::ihts, ResponderHelloCls::ihts, ResponderHelloCls::kx, GSC_KeyExchangeInfo::master_secret, MAX_EPOCHS, monitor_notify_all(), GSC_KeyExchangeInfo::mq, PilsRequest::op, GSC_KeyExchangeInfo::peer, pils_requests_head, pils_requests_tail, ResponderHelloCls::req, GSC_KeyExchangeInfo::resend_env, resend_initiator_done(), RESEND_MAX_TRIES, GSC_KeyExchangeInfo::resend_task, RESEND_TIMEOUT, GSC_KeyExchangeInfo::resend_tries_left, ResponderHelloCls::rhp, GSC_KeyExchangeInfo::rhts, ResponderHelloCls::rhts, GSC_KeyExchangeInfo::role, ROLE_INITIATOR, ROLE_RESPONDER, GNUNET_MessageHeader::size, snapshot_transcript(), GSC_KeyExchangeInfo::ss_e, ResponderHelloCls::ss_e, GSC_KeyExchangeInfo::ss_I, GSC_KeyExchangeInfo::status, GSC_KeyExchangeInfo::their_ats, GSC_KeyExchangeInfo::their_max_epoch, GSC_KeyExchangeInfo::transcript_hash_ctx, transport, and GNUNET_MessageHeader::type.

Referenced by handle_responder_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_responder_hello()

static int check_responder_hello ( void *  cls,
const struct ResponderHello m 
)
static

Definition at line 1855 of file gnunet-service-core_kx.c.

1856{
1857 uint16_t size = ntohs (m->header.size);
1858
1859 if (size < sizeof (*m)
1860 + sizeof (struct ResponderHelloPayload)
1861 + sizeof (struct GNUNET_HashCode)
1862 + AEAD_TAG_BYTES * 2)
1863 {
1864 return GNUNET_SYSERR;
1865 }
1866 return GNUNET_OK;
1867}

References AEAD_TAG_BYTES, GNUNET_OK, GNUNET_SYSERR, m, and size.

◆ handle_responder_hello()

static void handle_responder_hello ( void *  cls,
const struct ResponderHello rhm_e 
)
static

Handle Responder Hello message.

Parameters
clskey exchange info
rhm_eResponderHello message

Definition at line 1876 of file gnunet-service-core_kx.c.

1877{
1878 struct GSC_KeyExchangeInfo *kx = cls;
1879 struct PilsRequest *req;
1880 struct ResponderHelloCls *rh_ctx;
1881 struct GNUNET_HashCode transcript;
1882 struct GNUNET_HashContext *hc;
1883 unsigned char enc_key[AEAD_KEY_BYTES];
1884 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1886
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ResponderHello: %d %d\n", kx->
1888 role, kx->status);
1889
1891 if (NULL != kx->resend_task)
1892 {
1894 kx->resend_task = NULL;
1895 }
1896 if (NULL != kx->resend_env)
1897 {
1899 kx->resend_env = NULL;
1900 }
1901
1902 /* Forward the transcript hash context */
1903 if (ROLE_RESPONDER == kx->role)
1904 {
1905 GNUNET_break_op (0);
1907 "I am the responder! Ignoring.\n");
1909 return;
1910 }
1912 rhm_e,
1913 sizeof (struct ResponderHello));
1914 // 1. Verify that the message type is CORE_RESPONDER_HELLO
1915 // - implicitly done by handling this message?
1916 // - or is this about verifying the 'additional data' part of aead?
1917 // should it check the encryption + mac? (is this implicitly done
1918 // while decrypting?)
1919 // 2. sse <- Decaps(ske,ce)
1920 rh_ctx = GNUNET_new (struct ResponderHelloCls);
1921 ret = GNUNET_CRYPTO_hpke_kem_decaps (&kx->sk_e, // secret/private ephemeral key of initiator (us)
1922 &rhm_e->c_e, // encapsulated key
1923 &rh_ctx->ss_e); // key - ss_e
1924 if (GNUNET_OK != ret)
1925 {
1927 "Something went wrong decapsulating ss_e\n");
1929 return;
1930 }
1931 // 3. Generate IHTS and RHTS from Section 5 and decrypt ServicesInfo, cI and ResponderFinished.
1932 snapshot_transcript (hc, &transcript);
1933#if DEBUG_KX
1935 "Transcript snapshot for derivation of HS, *HTS: `%s'\n",
1936 GNUNET_h2s (&transcript));
1937#endif
1939 &rh_ctx->ss_e,
1940 &rh_ctx->hs);
1941 derive_rhts (&transcript,
1942 &rh_ctx->hs,
1943 &rh_ctx->rhts);
1944 derive_ihts (&transcript,
1945 &rh_ctx->hs,
1946 &rh_ctx->ihts);
1948 0,
1949 enc_key,
1950 enc_nonce);
1951 rh_ctx->kx = kx;
1952 GNUNET_memcpy (&rh_ctx->rhm_e, rhm_e, sizeof (*rhm_e));
1953 {
1954 unsigned long long int c_len;
1955 unsigned char *finished_buf;
1956 // use RHTS to decrypt
1957 c_len = ntohs (rhm_e->header.size) - sizeof (*rhm_e)
1958 - sizeof (struct GNUNET_HashCode)
1959 - AEAD_TAG_BYTES; // finished ct
1960 rh_ctx->rhp = GNUNET_malloc (c_len
1961 -
1963 rh_ctx->hc = hc;
1964 finished_buf = ((unsigned char*) &rhm_e[1]) + c_len;
1965 /* Forward the transcript_hash_ctx
1966 * after rhts has been generated,
1967 * before generating finished_R*/
1969 hc,
1970 &rhm_e[1],
1971 c_len);
1972
1973 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1974 (unsigned char*) rh_ctx->rhp, // unsigned char *m
1975 NULL, // mlen_p message length
1976 NULL, // unsigned char *nsec - unused: NULL
1977 (unsigned char*) &rhm_e[1], // const unsigned char *c - ciphertext
1978 c_len, // unsigned long long clen - length of ciphertext
1979 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1980 0, // unsigned long long adlen
1981 enc_nonce, // const unsigned char *npub - nonce
1982 enc_key // const unsigned char *k - key
1983 );
1984 if (0 != ret)
1985 {
1987 "Something went wrong decrypting: %d\n", ret);
1988 GNUNET_free (rh_ctx->rhp);
1989 GNUNET_free (rh_ctx);
1991 return;
1992 }
1993 // FIXME nonce reuse (see encryption)
1995 1,
1996 enc_key,
1997 enc_nonce);
1998 c_len = sizeof (struct GNUNET_HashCode)
2000 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2001 (unsigned char*) &rh_ctx->decrypted_finish, // unsigned char *m
2002 NULL, // mlen_p message length
2003 NULL, // unsigned char *nsec - unused: NULL
2004 finished_buf, // const unsigned char *c - ciphertext
2005 c_len, // unsigned long long clen - length of ciphertext
2006 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2007 0, // unsigned long long adlen
2008 enc_nonce, // const unsigned char *npub - nonce
2009 enc_key // const unsigned char *k - key
2010 );
2011 if (0 != ret)
2012 {
2014 "Something went wrong decrypting finished field: %d\n", ret);
2015 GNUNET_free (rh_ctx->rhp);
2016 GNUNET_free (rh_ctx);
2018 return;
2019 }
2020 GNUNET_memcpy (rh_ctx->finished_enc,
2021 finished_buf,
2022 c_len);
2023 }
2024 // 4. ssI <- Decaps(skI,cI).
2025 req = GNUNET_new (struct PilsRequest);
2026 rh_ctx->req = req;
2029 req);
2031 &rh_ctx->rhp->c_I, // encapsulated key
2032 &handle_responder_hello_cont, // continuation
2033 rh_ctx);
2034}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, AEAD_TAG_BYTES, ResponderHello::c_e, ResponderHelloPayload::c_I, ResponderHelloCls::decrypted_finish, derive_hs(), derive_ihts(), derive_per_message_secrets(), derive_rhts(), GSC_KeyExchangeInfo::early_secret_key, ResponderHelloCls::finished_enc, GNUNET_break_op, GNUNET_CONTAINER_DLL_insert, GNUNET_CRYPTO_hash_context_abort(), GNUNET_CRYPTO_hash_context_copy(), GNUNET_CRYPTO_hash_context_read(), GNUNET_CRYPTO_hpke_kem_decaps(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_h2s(), GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_MQ_discard(), GNUNET_new, GNUNET_OK, GNUNET_PILS_kem_decaps(), GNUNET_SCHEDULER_cancel(), GSC_pils, handle_responder_hello_cont(), ResponderHelloCls::hc, ResponderHello::header, ResponderHelloCls::hs, ResponderHelloCls::ihts, ResponderHelloCls::kx, PilsRequest::op, pils_requests_head, pils_requests_tail, ResponderHelloCls::req, GSC_KeyExchangeInfo::resend_env, GSC_KeyExchangeInfo::resend_task, ret, ResponderHelloCls::rhm_e, ResponderHelloCls::rhp, ResponderHelloCls::rhts, GSC_KeyExchangeInfo::role, ROLE_RESPONDER, GNUNET_MessageHeader::size, GSC_KeyExchangeInfo::sk_e, snapshot_transcript(), ResponderHelloCls::ss_e, GSC_KeyExchangeInfo::status, and GSC_KeyExchangeInfo::transcript_hash_ctx.

Here is the call graph for this function:

◆ check_initiator_done()

static int check_initiator_done ( void *  cls,
const struct InitiatorDone m 
)
static

Definition at line 2038 of file gnunet-service-core_kx.c.

2039{
2040 uint16_t size = ntohs (m->header.size);
2041
2042 if (size < sizeof (*m) + sizeof (struct ConfirmationAck))
2043 {
2044 return GNUNET_SYSERR;
2045 }
2046 return GNUNET_OK;
2047}

References GNUNET_OK, GNUNET_SYSERR, m, and size.

◆ handle_initiator_done()

static void handle_initiator_done ( void *  cls,
const struct InitiatorDone idm_e 
)
static

Handle InitiatorDone message.

Parameters
clskey exchange info
idm_eInitiatorDone message

FIXME we do not really have to calculate all this now

Definition at line 2056 of file gnunet-service-core_kx.c.

2057{
2058 struct GSC_KeyExchangeInfo *kx = cls;
2059 struct InitiatorDone idm_local;
2060 struct InitiatorDone *idm_p = &idm_local; /* plaintext */
2061 struct GNUNET_HashCode initiator_finished;
2062 struct GNUNET_HashCode transcript;
2063 struct GNUNET_ShortHashCode their_ats;
2064 struct GNUNET_HashContext *hc;
2065 unsigned char enc_key[AEAD_KEY_BYTES];
2066 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2067 struct ConfirmationAck ack_i;
2068 struct ConfirmationAck ack_r;
2069 int8_t ret;
2070
2071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorDone: %d %d\n", kx->
2072 role, kx->status);
2073 if (NULL != kx->resend_task)
2074 {
2076 kx->resend_task = NULL;
2077 }
2078 if (NULL != kx->resend_env)
2079 {
2080 GNUNET_free (kx->resend_env);
2081 kx->resend_env = NULL;
2082 }
2083 if (ROLE_INITIATOR == kx->role)
2084 {
2085 GNUNET_break_op (0);
2087 "I am the initiator! Tearing down...\n");
2088 return;
2089 }
2091 0,
2092 enc_key,
2093 enc_nonce);
2094 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2095 (unsigned char*) &idm_p->finished, // unsigned char *m
2096 NULL, // mlen_p message length
2097 NULL, // unsigned char *nsec - unused: NULL
2098 (unsigned char*) &idm_e->finished, // const unsigned char *c - ciphertext
2099 sizeof (idm_p->finished) // unsigned long long clen - length of ciphertext
2101 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2102 0, // unsigned long long adlen
2103 enc_nonce, // const unsigned char *npub - nonce
2104 enc_key // const unsigned char *k - key
2105 );
2106 if (0 != ret)
2107 {
2109 "Something went wrong decrypting: %d\n", ret);
2110 return;
2111 }
2112
2113 // - verify finished_I
2114 /* Generate finished_I
2115 * after Forwarding until {finished_R}RHTS
2116 * (did so while we prepared responder hello)
2117 * before forwarding to [{payload}RATS and] {finished_I}IHTS */
2118 // (look at the end of handle_initiator_hello())
2119 snapshot_transcript (kx->transcript_hash_ctx, &transcript);
2120 generate_initiator_finished (&transcript,
2121 &kx->master_secret,
2122 &initiator_finished);
2123 if (0 != memcmp (&idm_p->finished,
2124 &initiator_finished,
2125 sizeof (struct GNUNET_HashCode)))
2126 {
2128 "Could not verify \"initiator finished\" hash.\n");
2130 "Want: `%s'\n",
2131 GNUNET_h2s (&initiator_finished));
2133 "Have: `%s'\n",
2134 GNUNET_h2s (&idm_p->finished));
2136 "Transcript `%s'\n",
2137 GNUNET_h2s (&transcript));
2138 return;
2139 }
2140
2141 /* Forward the transcript hash_context_read */
2144 &idm_e->finished,
2145 sizeof (idm_e->finished)
2146 + AEAD_TAG_BYTES);
2147 snapshot_transcript (hc, &transcript);
2148 derive_initial_ats (&transcript,
2149 &kx->master_secret,
2151 &their_ats);
2152 derive_per_message_secrets (&their_ats, // FIXME other HS epoch?
2153 0,
2154 enc_key,
2155 enc_nonce);
2156 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2157 (unsigned char*) &ack_i, // unsigned char *m
2158 NULL, // mlen_p message length
2159 NULL, // unsigned char *nsec - unused: NULL
2160 (unsigned char*) &idm_e[1], // const unsigned char *c - ciphertext
2161 sizeof (ack_i) + AEAD_TAG_BYTES, // unsigned long long clen - length of ciphertext
2162 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2163 0, // unsigned long long adlen
2164 enc_nonce, // const unsigned char *npub - nonce
2165 enc_key // const unsigned char *k - key
2166 );
2167 if (0 != ret)
2168 {
2170 "Something went wrong decrypting the Ack: %d\n", ret);
2172 return;
2173 }
2174 if ((sizeof ack_i != ntohs (ack_i.header.size)) ||
2175 (GNUNET_MESSAGE_TYPE_CORE_ACK != ntohs (ack_i.header.type)))
2176 {
2178 "Ack invalid!\n");
2180 return;
2181 }
2182 GNUNET_memcpy (&kx->their_ats[0],
2183 &their_ats,
2184 sizeof their_ats);
2188 for (int i = 0; i < MAX_EPOCHS - 1; i++)
2189 {
2190 derive_next_ats (&kx->their_ats[i],
2191 &kx->their_ats[i + 1]);
2192 }
2194 kx->transcript_hash_ctx = hc;
2199 monitor_notify_all (kx);
2200 kx->current_sqn = 1;
2201 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2202 GNUNET_assert (NULL == kx->heartbeat_task);
2203 update_timeout (kx);
2204 ack_r.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2205 ack_r.header.size = htons (sizeof ack_r);
2207 &ack_r,
2208 sizeof ack_r);
2209
2210 GNUNET_TRANSPORT_core_receive_continue (transport,
2211 &kx->peer);
2212}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, AEAD_TAG_BYTES, GSC_KeyExchangeInfo::class, cleanup_handshake_secrets(), GSC_KeyExchangeInfo::current_epoch_expiration, GSC_KeyExchangeInfo::current_sqn, derive_initial_ats(), derive_next_ats(), derive_per_message_secrets(), EPOCH_EXPIRATION, InitiatorDone::finished, generate_initiator_finished(), GNUNET_assert, GNUNET_break_op, GNUNET_CORE_KX_STATE_RESPONDER_CONNECTED, GNUNET_CRYPTO_hash_context_abort(), GNUNET_CRYPTO_hash_context_copy(), GNUNET_CRYPTO_hash_context_read(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_h2s(), GNUNET_log, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_CORE_ACK, GNUNET_SCHEDULER_cancel(), GNUNET_TIME_relative_to_absolute(), GSC_KX_encrypt_and_transmit(), GSC_SESSIONS_create(), ConfirmationAck::header, GSC_KeyExchangeInfo::heartbeat_task, GSC_KeyExchangeInfo::ihts, GSC_KeyExchangeInfo::master_secret, MAX_EPOCHS, monitor_notify_all(), GSC_KeyExchangeInfo::peer, GSC_KeyExchangeInfo::resend_env, GSC_KeyExchangeInfo::resend_task, ret, GSC_KeyExchangeInfo::role, ROLE_INITIATOR, GNUNET_MessageHeader::size, snapshot_transcript(), GSC_KeyExchangeInfo::status, GSC_KeyExchangeInfo::their_ats, GSC_KeyExchangeInfo::transcript_hash_ctx, transport, GNUNET_MessageHeader::type, and update_timeout().

Here is the call graph for this function:

◆ check_encrypted_message()

static int check_encrypted_message ( void *  cls,
const struct EncryptedMessage m 
)
static

Check an incoming encrypted message before handling it.

Parameters
clskey exchange info
mthe encrypted message

Definition at line 2221 of file gnunet-service-core_kx.c.

2222{
2223 uint16_t size = ntohs (m->header.size) - sizeof(*m);
2224
2225 // TODO check (see check_encrypted ())
2226 // - check epoch
2227 // - check sequence number
2228 if (size < sizeof(struct GNUNET_MessageHeader))
2229 {
2230 GNUNET_break_op (0);
2231 return GNUNET_SYSERR;
2232 }
2233 return GNUNET_OK;
2234}

References GNUNET_break_op, GNUNET_OK, GNUNET_SYSERR, m, and size.

◆ handle_heartbeat()

static void handle_heartbeat ( struct GSC_KeyExchangeInfo kx,
const struct Heartbeat m 
)
static

Handle a key update.

Parameters
clskey exchange info
mKeyUpdate message

Definition at line 2243 of file gnunet-service-core_kx.c.

2245{
2246 struct GNUNET_ShortHashCode new_ats;
2247 struct ConfirmationAck ack;
2248
2250 {
2251 if (kx->current_epoch == UINT64_MAX)
2252 {
2254 "Max epoch reached (you probably will never see this)\n");
2255 }
2256 else
2257 {
2258 kx->current_epoch++;
2261 kx->current_sqn = 0;
2263 &new_ats);
2264 memcpy (&kx->current_ats,
2265 &new_ats,
2266 sizeof new_ats);
2267 }
2268 }
2269 update_timeout (kx);
2270 ack.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2271 ack.header.size = htons (sizeof ack);
2273 &ack,
2274 sizeof ack);
2275 if (NULL != kx->heartbeat_task)
2276 {
2280 kx);
2281 }
2282 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2283}

References GSC_KeyExchangeInfo::current_ats, GSC_KeyExchangeInfo::current_epoch, GSC_KeyExchangeInfo::current_epoch_expiration, GSC_KeyExchangeInfo::current_sqn, derive_next_ats(), EPOCH_EXPIRATION, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_MESSAGE_TYPE_CORE_ACK, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_TIME_relative_to_absolute(), GSC_HEARTBEAT_KEY_UPDATE_REQUESTED, GSC_KX_encrypt_and_transmit(), ConfirmationAck::header, GSC_KeyExchangeInfo::heartbeat_task, m, MIN_HEARTBEAT_FREQUENCY, GSC_KeyExchangeInfo::peer, send_heartbeat(), GNUNET_MessageHeader::size, transport, GNUNET_MessageHeader::type, and update_timeout().

Referenced by check_if_ack_or_heartbeat().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_if_ack_or_heartbeat()

static enum GNUNET_GenericReturnValue check_if_ack_or_heartbeat ( struct GSC_KeyExchangeInfo kx,
const char *  buf,
size_t  buf_len 
)
static

Waiting for ACK or heartbeat

Definition at line 2287 of file gnunet-service-core_kx.c.

2290{
2291 struct GNUNET_MessageHeader *msg;
2292 struct ConfirmationAck *ack;
2293 struct Heartbeat *hb;
2294
2295 if (sizeof *msg > buf_len)
2296 return GNUNET_NO;
2297 msg = (struct GNUNET_MessageHeader*) buf;
2298 if (GNUNET_MESSAGE_TYPE_CORE_ACK == ntohs (msg->type))
2299 {
2300 ack = (struct ConfirmationAck *) buf;
2301 if (sizeof *ack != ntohs (ack->header.size))
2302 return GNUNET_NO;
2303 }
2304 else if (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT == ntohs (msg->type))
2305 {
2306 hb = (struct Heartbeat*) buf;
2307 if (sizeof *hb != ntohs (hb->header.size))
2308 return GNUNET_NO;
2309 handle_heartbeat (kx, hb);
2310 }
2311 else
2312 {
2313 return GNUNET_NO;
2314 }
2315
2320 {
2321 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2326 if (NULL != kx->resend_task)
2328 kx->resend_task = NULL;
2329 if (NULL != kx->resend_env)
2330 GNUNET_free (kx->resend_env);
2331 kx->resend_env = NULL;
2332 monitor_notify_all (kx);
2333 }
2334 update_timeout (kx);
2335
2336 return GNUNET_YES;
2337}

References GSC_KeyExchangeInfo::class, cleanup_handshake_secrets(), GSC_KeyExchangeInfo::current_epoch_expiration, EPOCH_EXPIRATION, GNUNET_CORE_KX_STATE_INITIATOR_CONNECTED, GNUNET_CORE_KX_STATE_INITIATOR_DONE_SENT, GNUNET_free, GNUNET_MESSAGE_TYPE_CORE_ACK, GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT, GNUNET_NO, GNUNET_SCHEDULER_cancel(), GNUNET_TIME_relative_to_absolute(), GNUNET_YES, GSC_SESSIONS_create(), handle_heartbeat(), ConfirmationAck::header, Heartbeat::header, monitor_notify_all(), msg, GSC_KeyExchangeInfo::peer, GSC_KeyExchangeInfo::resend_env, GSC_KeyExchangeInfo::resend_task, GNUNET_MessageHeader::size, GSC_KeyExchangeInfo::status, GNUNET_MessageHeader::type, and update_timeout().

Referenced by handle_encrypted_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_encrypted_message()

static void handle_encrypted_message ( void *  cls,
const struct EncryptedMessage m 
)
static

handle an encrypted message

Parameters
clskey exchange info
mencrypted message

Derive temporarily as we want to discard on decryption failure(s)

Prevent DoS FIXME maybe requires its own limit.

Definition at line 2346 of file gnunet-service-core_kx.c.

2347{
2348 struct GSC_KeyExchangeInfo *kx = cls;
2349 uint16_t size = ntohs (m->header.size);
2350 char buf[size - sizeof (*m)] GNUNET_ALIGN;
2351 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2352 const unsigned char *seq_enc_nonce;
2353 unsigned char enc_key[AEAD_KEY_BYTES];
2354 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2355 struct GNUNET_ShortHashCode new_ats[MAX_EPOCHS];
2356 uint32_t seq_enc_ctr;
2357 uint64_t epoch;
2358 uint64_t m_seq;
2359 uint64_t m_seq_nbo;
2360 uint64_t c_len;
2361 int8_t ret;
2362
2363 // TODO look at handle_encrypted
2364 // - statistics
2365
2369 {
2370 GSC_SESSIONS_end (&kx->peer);
2372 monitor_notify_all (kx);
2373 restart_kx (kx);
2374 return;
2375 }
2376 update_timeout (kx);
2377 epoch = GNUNET_ntohll (m->epoch);
2382 memcpy (new_ats,
2383 kx->their_ats,
2384 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2385 // FIXME here we could introduce logic that sends heartbeats
2386 // with key update request if we have not seen a new
2387 // epoch after a while (e.g. EPOCH_EXPIRATION)
2388 if (kx->their_max_epoch < epoch)
2389 {
2394 if ((epoch - kx->their_max_epoch) > 2 * MAX_EPOCHS)
2395 {
2397 "Epoch %" PRIu64 " is too new, will not decrypt...\n",
2398 epoch);
2399 GSC_SESSIONS_end (&kx->peer);
2401 monitor_notify_all (kx);
2402 restart_kx (kx);
2403 return;
2404 }
2405 for (uint64_t i = kx->their_max_epoch; i < epoch; i++)
2406 {
2407 derive_next_ats (&new_ats[i % MAX_EPOCHS],
2408 &new_ats[(i + 1) % MAX_EPOCHS]);
2409 }
2410 }
2411 else if ((kx->their_max_epoch - epoch) > MAX_EPOCHS)
2412 {
2414 "Epoch %" PRIu64 " is too old, cannot decrypt...\n",
2415 epoch);
2416 return;
2417 }
2418 derive_sn (
2419 &new_ats[epoch % MAX_EPOCHS],
2420 seq_enc_k,
2421 sizeof seq_enc_k);
2422 /* compute the sequence number */
2423 seq_enc_ctr = *((uint32_t*) m->tag);
2424 seq_enc_nonce = &m->tag[sizeof (uint32_t)];
2425#if DEBUG_KX
2426 GNUNET_print_bytes (&new_ats[epoch % MAX_EPOCHS],
2427 sizeof (struct GNUNET_ShortHashCode),
2428 8,
2429 GNUNET_NO);
2430 GNUNET_print_bytes (seq_enc_k,
2431 sizeof seq_enc_k,
2432 8,
2433 GNUNET_NO);
2434 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2435 sizeof seq_enc_ctr,
2436 8,
2437 GNUNET_NO);
2438#endif
2439 crypto_stream_chacha20_ietf_xor_ic (
2440 (unsigned char*) &m_seq_nbo,
2441 (unsigned char*) &m->sequence_number,
2442 sizeof (uint64_t),
2443 seq_enc_nonce,
2444 ntohl (seq_enc_ctr),
2445 seq_enc_k);
2446 m_seq = GNUNET_ntohll (m_seq_nbo);
2448 "Received encrypted message in epoch %" PRIu64
2449 " with E(SQN=%" PRIu64 ")=%" PRIu64
2450 "\n",
2451 epoch,
2452 m_seq,
2453 m->sequence_number);
2454 /* We are the initiator and as we are going to receive,
2455 * we are using the responder key material */
2456 derive_per_message_secrets (&new_ats[epoch % MAX_EPOCHS],
2457 m_seq,
2458 enc_key,
2459 enc_nonce);
2460 // TODO checking sequence numbers - handle the case of out-of-sync messages!
2461 // for now only decrypt the payload
2462 // TODO encrypt other fields, too!
2463 // TODO
2464 // c_len = size - offsetof ();
2465 c_len = size - sizeof (struct EncryptedMessage);
2466 ret = crypto_aead_xchacha20poly1305_ietf_decrypt_detached (
2467 (unsigned char*) buf, // m - plain message
2468 NULL, // nsec - unused
2469 (unsigned char*) &m[1], // c - ciphertext
2470 c_len, // clen
2471 (const unsigned char*) &m->tag, // mac
2472 NULL, // ad - additional data TODO
2473 0, // adlen
2474 enc_nonce, // npub
2475 enc_key // k
2476 );
2477 if (0 != ret)
2478 {
2480 "Something went wrong decrypting message\n");
2481 GNUNET_break_op (0); // FIXME handle gracefully
2482 return;
2483 }
2484 kx->their_max_epoch = epoch;
2485 memcpy (&kx->their_ats,
2486 new_ats,
2487 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2488
2490 buf,
2491 sizeof buf))
2492 {
2494 {
2496 "Dropping message as we are still waiting for handshake ACK\n");
2497 GNUNET_break_op (0);
2498 return;
2499 }
2500 if (GNUNET_OK !=
2502 buf,
2503 sizeof buf,
2504 GNUNET_YES,
2505 GNUNET_NO))
2506 GNUNET_break_op (0);
2507 }
2508 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2509}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, check_if_ack_or_heartbeat(), derive_next_ats(), derive_per_message_secrets(), derive_sn(), EncryptedMessage::epoch, GNUNET_ALIGN, GNUNET_break_op, GNUNET_CORE_KX_STATE_DOWN, GNUNET_CORE_KX_STATE_INITIATOR_CONNECTED, GNUNET_CORE_KX_STATE_INITIATOR_DONE_SENT, GNUNET_CORE_KX_STATE_RESPONDER_CONNECTED, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_MST_from_buffer(), GNUNET_NO, GNUNET_ntohll(), GNUNET_OK, GNUNET_print_bytes(), GNUNET_YES, GSC_SESSIONS_end(), m, MAX_EPOCHS, monitor_notify_all(), GSC_KeyExchangeInfo::mst, GSC_KeyExchangeInfo::peer, restart_kx(), ret, size, GSC_KeyExchangeInfo::status, GSC_KeyExchangeInfo::their_ats, GSC_KeyExchangeInfo::their_max_epoch, transport, and update_timeout().

Here is the call graph for this function:

◆ handle_transport_notify_disconnect()

static void handle_transport_notify_disconnect ( void *  cls,
const struct GNUNET_PeerIdentity peer,
void *  handler_cls 
)
static

Function called by transport telling us that a peer disconnected.

Stop key exchange with the given peer. Clean up key material.

Parameters
clsclosure
peerthe peer that disconnected
handler_clsthe struct GSC_KeyExchangeInfo of the peer

Definition at line 2522 of file gnunet-service-core_kx.c.

2525{
2526 struct GSC_KeyExchangeInfo *kx = handler_cls;
2527 (void) cls;
2528
2530 "Peer `%s' disconnected from us.\n",
2531 GNUNET_i2s (&kx->peer));
2532 GSC_SESSIONS_end (&kx->peer);
2534 gettext_noop ("# key exchanges stopped"),
2535 1,
2536 GNUNET_NO);
2537 if (NULL != kx->resend_task)
2538 {
2540 kx->resend_task = NULL;
2541 }
2542 if (NULL != kx->resend_env)
2543 {
2544 GNUNET_free (kx->resend_env);
2545 kx->resend_env = NULL;
2546 }
2547 if (NULL != kx->heartbeat_task)
2548 {
2550 kx->heartbeat_task = NULL;
2551 }
2553 monitor_notify_all (kx);
2554 if (kx->transcript_hash_ctx)
2555 {
2557 kx->transcript_hash_ctx = NULL;
2558 }
2560 GNUNET_MST_destroy (kx->mst);
2561 GNUNET_free (kx);
2562}

References gettext_noop, GNUNET_CONTAINER_DLL_remove, GNUNET_CORE_KX_PEER_DISCONNECT, GNUNET_CRYPTO_hash_context_abort(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_MST_destroy(), GNUNET_NO, GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_update(), GSC_SESSIONS_end(), GSC_stats, GSC_KeyExchangeInfo::heartbeat_task, kx_head, kx_tail, monitor_notify_all(), GSC_KeyExchangeInfo::mst, GSC_KeyExchangeInfo::peer, GSC_KeyExchangeInfo::resend_env, GSC_KeyExchangeInfo::resend_task, GSC_KeyExchangeInfo::status, and GSC_KeyExchangeInfo::transcript_hash_ctx.

Referenced by GSC_KX_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resend_initiator_hello()

static void resend_initiator_hello ( void *  cls)
static

Definition at line 2566 of file gnunet-service-core_kx.c.

2567{
2568 struct GSC_KeyExchangeInfo *kx = cls;
2569
2570 kx->resend_task = NULL;
2572 "Resending InitiatorHello.\n");
2574 // FIXME (Exponential) backoff?
2577 kx);
2578}

References GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_MQ_send_copy(), GNUNET_SCHEDULER_add_delayed(), GSC_KeyExchangeInfo::mq, GSC_KeyExchangeInfo::resend_env, resend_initiator_hello(), GSC_KeyExchangeInfo::resend_task, and RESEND_TIMEOUT.

Referenced by resend_initiator_hello(), and send_initiator_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_rekey()

static void check_rekey ( struct GSC_KeyExchangeInfo kx)
static

Definition at line 2711 of file gnunet-service-core_kx.c.

2712{
2713 struct GNUNET_ShortHashCode new_ats;
2714
2715 if ((UINT64_MAX == kx->current_sqn) ||
2717 {
2719 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2720 ", incrementing epoch...\n",
2722 kx->current_sqn);
2723 // Can this trigger? Maybe if we receive a lot of
2724 // heartbeats?
2725 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2726 kx->current_epoch++;
2729 kx->current_sqn = 0;
2731 &new_ats);
2732 memcpy (&kx->current_ats,
2733 &new_ats,
2734 sizeof new_ats);
2735 }
2736}

References GNUNET_TIME_Absolute::abs_value_us, GSC_KeyExchangeInfo::current_ats, GSC_KeyExchangeInfo::current_epoch, GSC_KeyExchangeInfo::current_epoch_expiration, GSC_KeyExchangeInfo::current_sqn, derive_next_ats(), EPOCH_EXPIRATION, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_TIME_absolute_is_past(), and GNUNET_TIME_relative_to_absolute().

Referenced by GSC_KX_encrypt_and_transmit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GSC_KX_encrypt_and_transmit()

void GSC_KX_encrypt_and_transmit ( struct GSC_KeyExchangeInfo kx,
const void *  payload,
size_t  payload_size 
)

Encrypt and transmit payload.

Encrypt and transmit a message with the given payload.

Parameters
kxkey exchange info
payloadthe payload
payload_sizesize of the payload

Definition at line 2746 of file gnunet-service-core_kx.c.

2749{
2750 struct GNUNET_MQ_Envelope *env;
2751 struct EncryptedMessage *encrypted_msg;
2752 unsigned char enc_key[AEAD_KEY_BYTES];
2753 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2754 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2755 uint64_t sqn;
2756 uint64_t epoch;
2757 int8_t ret;
2758
2759 encrypted_msg = NULL;
2760
2761 check_rekey (kx);
2762 sqn = kx->current_sqn;
2763 epoch = kx->current_epoch;
2764 /* We are the sender and as we are going to send,
2765 * we are using the initiator key material */
2767 sqn,
2768 enc_key,
2769 enc_nonce);
2770 kx->current_sqn++;
2771 derive_sn (&kx->current_ats,
2772 seq_enc_k,
2773 sizeof seq_enc_k);
2774 env = GNUNET_MQ_msg_extra (encrypted_msg,
2775 payload_size,
2777 // only encrypt the payload for now
2778 // TODO encrypt other fields as well
2779 ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached (
2780 (unsigned char*) &encrypted_msg[1], // c - resulting ciphertext
2781 (unsigned char*) &encrypted_msg->tag, // mac - resulting mac/tag
2782 NULL, // maclen
2783 (unsigned char*) payload, // m - plain message
2784 payload_size, // mlen
2785 NULL, // ad - additional data TODO also cover the unencrypted part (epoch)
2786 0, // adlen
2787 NULL, // nsec - unused
2788 enc_nonce, // npub nonce
2789 enc_key // k - key
2790 );
2791 if (0 != ret)
2792 {
2794 "Something went wrong encrypting message\n");
2795 GNUNET_assert (0);
2796 }
2797 {
2798 /* compute the sequence number */
2799 unsigned char *seq_enc_nonce;
2800 uint64_t seq_nbo;
2801 uint32_t seq_enc_ctr;
2802
2803 seq_nbo = GNUNET_htonll (sqn);
2804 seq_enc_ctr = *((uint32_t*) encrypted_msg->tag);
2805 seq_enc_nonce = &encrypted_msg->tag[sizeof (uint32_t)];
2806 crypto_stream_chacha20_ietf_xor_ic (
2807 (unsigned char*) &encrypted_msg->sequence_number,
2808 (unsigned char*) &seq_nbo,
2809 sizeof seq_nbo,
2810 seq_enc_nonce,
2811 ntohl (seq_enc_ctr),
2812 seq_enc_k);
2813#if DEBUG_KX
2814 GNUNET_print_bytes (seq_enc_k,
2815 sizeof seq_enc_k,
2816 8,
2817 GNUNET_NO);
2818 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2819 sizeof seq_enc_ctr,
2820 8,
2821 GNUNET_NO);
2822#endif
2824 "Sending encrypted message with E(SQN=%" PRIu64 ")=%" PRIu64
2825 "\n",
2826 sqn,
2827 encrypted_msg->sequence_number);
2828 }
2829 encrypted_msg->epoch = GNUNET_htonll (epoch);
2830
2831 // TODO actually copy payload
2832 GNUNET_MQ_send (kx->mq, env);
2833}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, check_rekey(), GSC_KeyExchangeInfo::current_ats, GSC_KeyExchangeInfo::current_epoch, GSC_KeyExchangeInfo::current_sqn, derive_per_message_secrets(), derive_sn(), env, EncryptedMessage::epoch, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_htonll(), GNUNET_log, GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE_CAKE, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_NO, GNUNET_print_bytes(), GSC_KeyExchangeInfo::mq, payload, ret, EncryptedMessage::sequence_number, and EncryptedMessage::tag.

Referenced by handle_heartbeat(), handle_initiator_done(), send_heartbeat(), and try_transmission().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GSC_KX_start()

void GSC_KX_start ( void  )

Definition at line 2837 of file gnunet-service-core_kx.c.

2838{
2839 const struct GNUNET_PeerIdentity *my_identity;
2841 GNUNET_MQ_hd_var_size (initiator_hello,
2843 struct InitiatorHello,
2844 NULL),
2845 GNUNET_MQ_hd_var_size (initiator_done,
2847 struct InitiatorDone,
2848 NULL),
2849 GNUNET_MQ_hd_var_size (responder_hello,
2851 struct ResponderHello,
2852 NULL),
2853 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2855 struct EncryptedMessage,
2856 NULL),
2858 };
2859
2861 GNUNET_assert (NULL != my_identity);
2862
2864 transport =
2867 handlers,
2868 NULL, // cls - this connection-independant
2869 // cls seems not to be needed.
2870 // the connection-specific cls
2871 // will be set as a return value
2872 // of
2873 // handle_transport_notify_connect
2876 if (NULL == transport)
2877 {
2878 GSC_KX_done ();
2879 return;
2880 }
2881
2883 "Connected to TRANSPORT\n");
2884
2886}

References GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE_CAKE, GNUNET_MESSAGE_TYPE_CORE_INITIATOR_DONE, GNUNET_MESSAGE_TYPE_CORE_INITIATOR_HELLO, GNUNET_MESSAGE_TYPE_CORE_RESPONDER_HELLO, GNUNET_MQ_handler_end, GNUNET_MQ_hd_var_size, GNUNET_notification_context_create(), GNUNET_PILS_get_identity(), GNUNET_TRANSPORT_core_connect(), GSC_cfg, GSC_complete_initialization_cb(), GSC_KX_done(), GSC_pils, handle_transport_notify_connect(), handle_transport_notify_disconnect(), handlers, my_identity, nc, and transport.

Referenced by pid_change_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pid_change_cb()

void pid_change_cb ( void *  cls,
const struct GNUNET_HELLO_Parser parser,
const struct GNUNET_HashCode hash 
)

Definition at line 2890 of file gnunet-service-core_kx.c.

2893{
2894 if (NULL != transport)
2895 return;
2896
2897 GSC_KX_start ();
2898}

References GSC_KX_start(), and transport.

Referenced by GSC_KX_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GSC_KX_init()

int GSC_KX_init ( void  )

Initialize KX subsystem.

Returns
GNUNET_OK on success, GNUNET_SYSERR on failure

Definition at line 2907 of file gnunet-service-core_kx.c.

2908{
2911 NULL);
2912 if (NULL == GSC_pils)
2913 {
2914 GSC_KX_done ();
2915 return GNUNET_SYSERR;
2916 }
2917
2918 return GNUNET_OK;
2919}

References GNUNET_OK, GNUNET_PILS_connect(), GNUNET_SYSERR, GSC_cfg, GSC_KX_done(), GSC_pils, and pid_change_cb().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GSC_KX_done()

void GSC_KX_done ( void  )

Shutdown KX subsystem.

Definition at line 2926 of file gnunet-service-core_kx.c.

2927{
2928 struct PilsRequest *pr;
2929 while (NULL != (pr = pils_requests_head))
2930 {
2933 pr);
2934 if (NULL != pr->op)
2935 GNUNET_PILS_cancel (pr->op);
2936 GNUNET_free (pr);
2937 }
2938 if (NULL != GSC_pils)
2939 {
2941 GSC_pils = NULL;
2942 }
2943 if (NULL != transport)
2944 {
2946 transport = NULL;
2947 }
2948 if (NULL != rekey_task)
2949 {
2951 rekey_task = NULL;
2952 }
2953 if (NULL != nc)
2954 {
2956 nc = NULL;
2957 }
2958}

References GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_notification_context_destroy(), GNUNET_PILS_cancel(), GNUNET_PILS_disconnect(), GNUNET_SCHEDULER_cancel(), GNUNET_TRANSPORT_core_disconnect(), GSC_pils, nc, PilsRequest::op, pils_requests_head, pils_requests_tail, rekey_task, and transport.

Referenced by GSC_KX_init(), GSC_KX_start(), and shutdown_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GSC_NEIGHBOURS_get_queue_length()

unsigned int GSC_NEIGHBOURS_get_queue_length ( const struct GSC_KeyExchangeInfo kxinfo)

Check how many messages are queued for the given neighbour.

Parameters
kxinfodata about neighbour to check
Returns
number of items in the message queue

Definition at line 2968 of file gnunet-service-core_kx.c.

2969{
2970 return GNUNET_MQ_get_length (kxinfo->mq);
2971}

References GNUNET_MQ_get_length(), and GSC_KeyExchangeInfo::mq.

Referenced by try_transmission().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GSC_NEIGHBOURS_check_excess_bandwidth()

int GSC_NEIGHBOURS_check_excess_bandwidth ( const struct GSC_KeyExchangeInfo target)

Check if the given neighbour has excess bandwidth available.

Parameters
targetneighbour to check
Returns
GNUNET_YES if excess bandwidth is available, GNUNET_NO if not

Definition at line 2975 of file gnunet-service-core_kx.c.

2976{
2977 return kxinfo->has_excess_bandwidth;
2978}

References GSC_KeyExchangeInfo::has_excess_bandwidth.

Referenced by try_transmission().

Here is the caller graph for this function:

◆ GSC_KX_handle_client_monitor_peers()

void GSC_KX_handle_client_monitor_peers ( struct GNUNET_MQ_Handle mq)

Handle GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request.

For this request type, the client does not have to have transmitted an INIT request. All current peers are returned, regardless of which message types they accept.

Parameters
mqmessage queue to add for monitoring

Definition at line 2990 of file gnunet-service-core_kx.c.

2991{
2992 struct GNUNET_MQ_Envelope *env;
2993 struct MonitorNotifyMessage *done_msg;
2994 struct GSC_KeyExchangeInfo *kx;
2995
2997 for (kx = kx_head; NULL != kx; kx = kx->next)
2998 {
2999 struct GNUNET_MQ_Envelope *env_notify;
3000 struct MonitorNotifyMessage *msg;
3001
3003 msg->state = htonl ((uint32_t) kx->status);
3004 msg->peer = kx->peer;
3005 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
3006 GNUNET_MQ_send (mq, env_notify);
3007 }
3009 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
3012}

References env, GNUNET_CORE_KX_ITERATION_FINISHED, GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY, GNUNET_MQ_msg, GNUNET_MQ_send(), GNUNET_notification_context_add(), GNUNET_TIME_absolute_hton(), GNUNET_TIME_UNIT_FOREVER_ABS, kx_head, mq, msg, nc, GSC_KeyExchangeInfo::next, GSC_KeyExchangeInfo::peer, MonitorNotifyMessage::state, GSC_KeyExchangeInfo::status, MonitorNotifyMessage::timeout, and GSC_KeyExchangeInfo::timeout.

Referenced by handle_client_monitor_peers().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ pils_requests_head

◆ pils_requests_tail

◆ transport

◆ kx_head

◆ kx_tail

struct GSC_KeyExchangeInfo* kx_tail
static

◆ rekey_task

struct GNUNET_SCHEDULER_Task* rekey_task
static

Task scheduled for periodic re-generation (and thus rekeying) of our ephemeral key.

Definition at line 425 of file gnunet-service-core_kx.c.

Referenced by GSC_KX_done().

◆ nc

◆ my_services_info

char* my_services_info = ""
static

Our services info string TODO.

Definition at line 435 of file gnunet-service-core_kx.c.

Referenced by send_initiator_hello(), and send_responder_hello().