GNUnet 0.26.2-44-g5a6b2f9a5
 
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 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.
 
static void peer_id_change_cb (void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *hash)
 Callback for PILS to be called once the peer id changes.
 
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_PILS_Handlepils
 Pils service.
 
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 enum GNUNET_GenericReturnValue init_phase
 Indicates whether we are still in the initialisation phase (waiting for our peer id).
 
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 49 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 54 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 59 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 64 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 69 of file gnunet-service-core_kx.c.

◆ RESEND_TIMEOUT

#define RESEND_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)

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

187{
188 /* Peer is supposed to initiate the key exchange */
189 ROLE_INITIATOR = 0,
190
191 /* Peer is supposed to wait for the key exchange */
192 ROLE_RESPONDER = 1,
193};
194
195
200{
205
210
215
219 struct GNUNET_MQ_Handle *mq;
220
225
230
231 // TODO check ordering - might make it less confusing
232 // TODO consistent naming: ss_e, shared_secret_e or ephemeral_shared_secret?
233 // TODO consider making all the structs here pointers
234 // - they can be checked to be NULL
235 // - valgrind can detect memory issues better (I guess?)
236
241 enum GSC_KX_Role role;
242
243 // TODO
247
252
257
264
270
275 struct GNUNET_ShortHashCode early_traffic_secret; /* Decrypts InitiatorHello */
276
282
288
294
300
305
310
314 uint64_t current_epoch;
315
320
325 uint64_t their_max_epoch;
326
330 uint64_t current_sqn;
331
336
341
346
350 unsigned int resend_tries_left;
351
357
363
368
373 enum GNUNET_CORE_PeerClass class;
374
375};
376
380struct PilsRequest
381{
385 struct PilsRequest *prev;
386
390 struct PilsRequest *next;
391
396};
397
401static struct PilsRequest *pils_requests_head;
402
406static struct PilsRequest *pils_requests_tail;
407
408
412static struct GNUNET_PILS_Handle *pils;
413
414
419
423static struct GSC_KeyExchangeInfo *kx_head;
424
428static struct GSC_KeyExchangeInfo *kx_tail;
429
434static struct GNUNET_SCHEDULER_Task *rekey_task;
435
439static struct GNUNET_NotificationContext *nc;
440
446
450static char *my_services_info = "";
451
452static void
453buffer_clear (void *buf, size_t len)
454{
455#if HAVE_MEMSET_S
456 memset_s (buf, len, 0, len);
457#elif HAVE_EXPLICIT_BZERO
458 explicit_bzero (buf, len);
459#else
460 volatile unsigned char *p = buf;
461 while (len--)
462 *p++ = 0;
463#endif
464}
465
466
467static void
469{
470 buffer_clear (&kx->ihts,
471 sizeof kx->ihts);
472 buffer_clear (&kx->rhts,
473 sizeof kx->rhts);
474 buffer_clear (&kx->sk_e,
475 sizeof kx->sk_e);
476 buffer_clear (&kx->ss_I,
477 sizeof kx->ss_I);
478 buffer_clear (&kx->ss_R,
479 sizeof kx->ss_R);
480 buffer_clear (&kx->ss_e,
481 sizeof kx->ss_e);
483 sizeof kx->master_secret);
485 sizeof kx->early_secret_key);
487 sizeof kx->early_traffic_secret);
489 sizeof kx->handshake_secret);
490}
491
492
493static void
494snapshot_transcript (const struct GNUNET_HashContext *ts_hash,
495 struct GNUNET_HashCode *snapshot)
496{
497 struct GNUNET_HashContext *tmp;
498
499 tmp = GNUNET_CRYPTO_hash_context_copy (ts_hash);
500 GNUNET_CRYPTO_hash_context_finish (tmp, snapshot);
501}
502
503
509static void
511{
513
515 msg.header.size = htons (sizeof(msg));
516 msg.state = htonl ((uint32_t) kx->status);
517 msg.peer = kx->peer;
518 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
521}
522
523
524static void
526
534static void
535send_heartbeat (void *cls)
536{
537 struct GSC_KeyExchangeInfo *kx = cls;
538 struct GNUNET_TIME_Relative retry;
539 struct GNUNET_TIME_Relative left;
540 struct Heartbeat hb;
541
542 kx->heartbeat_task = NULL;
544 if (0 == left.rel_value_us)
545 {
547 gettext_noop ("# sessions terminated by timeout"),
548 1,
549 GNUNET_NO);
550 GSC_SESSIONS_end (&kx->peer);
553 restart_kx (kx);
554 return;
555 }
557 "Sending HEARTBEAT to `%s'\n",
558 GNUNET_i2s (&kx->peer));
560 gettext_noop ("# heartbeat messages sent"),
561 1,
562 GNUNET_NO);
563 hb.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT);
564 hb.header.size = htons (sizeof hb);
565 // FIXME when do we request update?
566 hb.flags = 0;
567 GSC_KX_encrypt_and_transmit (kx, &hb, sizeof hb);
570 kx->heartbeat_task =
572}
573
574
582static void
584{
586
587 kx->timeout =
589 delta =
591 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
592 {
593 /* we only notify monitors about timeout changes if those
594 are bigger than the threshold (5s) */
596 }
597 if (NULL != kx->heartbeat_task)
602 kx);
603}
604
605
611static void
613
614
626static int
627deliver_message (void *cls, const struct GNUNET_MessageHeader *m)
628{
629 struct GSC_KeyExchangeInfo *kx = cls;
630
632 "Decrypted message of type %d from %s\n",
633 ntohs (m->type),
634 GNUNET_i2s (&kx->peer));
636 m,
637 ntohs (m->size),
640 m,
641 sizeof(struct GNUNET_MessageHeader),
643 return GNUNET_OK;
644}
645
646
647static void
649{
650 struct GNUNET_HashCode h1;
651 struct GNUNET_HashCode h2;
652
653 // TODO what happens if we're in the middle of a peer id change?
654 // TODO there's a small chance this gets already called when we don't have a
655 // peer id yet. Add a kx, insert into the list, mark it as to be completed
656 // and let the callback to pils finish the rest once we got the peer id
657
659 "Initiating key exchange with peer %s\n",
660 GNUNET_i2s (&kx->peer));
662 gettext_noop ("# key exchanges initiated"),
663 1,
664 GNUNET_NO);
665
667 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
669 sizeof(struct GNUNET_PeerIdentity),
670 &h2);
671 if (NULL != kx->transcript_hash_ctx)
673 kx->transcript_hash_ctx = NULL;
674 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, &h2))
675 {
676 /* peer with "lower" identity starts KX, otherwise we typically end up
677 with both peers starting the exchange and transmit the 'set key'
678 message twice */
680 "I am the initiator, sending hello\n");
681 kx->role = ROLE_INITIATOR;
683 }
684 else
685 {
686 /* peer with "higher" identity starts a delayed KX, if the "lower" peer
687 * does not start a KX since it sees no reasons to do so */
689 "I am the responder, yielding and await initiator hello\n");
691 kx->role = ROLE_RESPONDER;
693 }
694
695}
696
697
708static void *
710 const struct GNUNET_PeerIdentity *peer_id,
711 struct GNUNET_MQ_Handle *mq)
712{
713 struct GSC_KeyExchangeInfo *kx;
714 (void) cls;
715 if (0 == memcmp (peer_id, &GSC_my_identity, sizeof *peer_id))
716 {
718 "Ignoring connection to self\n");
719 return NULL;
720 }
722 "Incoming connection of peer with %s\n",
724
725 /* Set up kx struct */
726 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
728 kx->mq = mq;
729 GNUNET_memcpy (&kx->peer, peer_id, sizeof (struct GNUNET_PeerIdentity));
731
732 restart_kx (kx);
733 return kx;
734}
735
736
776// TODO find a way to assert that a key is not yet existing before generating
777// TODO find a way to assert that a key is not already existing before using
778/*
779 * Derive early secret and transport secret.
780 * @param kx the key exchange info
781 */
782static void
783derive_es_ets (const struct GNUNET_HashCode *transcript,
784 const struct GNUNET_ShortHashCode *ss_R,
785 struct GNUNET_ShortHashCode *es,
786 struct GNUNET_ShortHashCode *ets)
787{
788 uint64_t ret;
789
790 ret = GNUNET_CRYPTO_hkdf_extract (es, // prk
791 0, // salt
792 0, // salt_len
793 ss_R, // ikm - initial key material
794 sizeof (*ss_R));
795 if (GNUNET_OK != ret)
796 {
797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting ES\n")
798 ;
799 GNUNET_assert (0);
800 }
802 ets,
803 sizeof (*ets),
804 es,
807 GNUNET_CRYPTO_kdf_arg_auto (transcript));
808 if (GNUNET_OK != ret)
809 {
810 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
811 ;
812 GNUNET_assert (0);
813 }
814}
815
816
817/*
818 * Derive early secret and transport secret.
819 * @param kx the key exchange info
820 */
821static void
822derive_sn (const struct GNUNET_ShortHashCode *secret,
823 unsigned char*sn,
824 size_t sn_len)
825{
828 sn,
829 sn_len,
830 secret,
833}
834
835
840static void
841derive_hs (const struct GNUNET_ShortHashCode *es,
842 const struct GNUNET_ShortHashCode *ss_e,
844{
845 uint64_t ret;
846 struct GNUNET_ShortHashCode derived_early_secret;
847
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deriving HS\n");
850 );
851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ss_e: %s\n", GNUNET_B2S (ss_e));
853 &derived_early_secret,
854 sizeof (derived_early_secret),
855 es,
859 derived_early_secret));
860 if (GNUNET_OK != ret)
861 {
862 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dES\n")
863 ;
864 GNUNET_assert (0);
865 }
866 // Handshake secret
867 // TODO check: are dES the salt and ss_e the ikm or other way round?
868 ret = GNUNET_CRYPTO_hkdf_extract (handshake_secret, // prk
869 &derived_early_secret, // salt - dES
870 sizeof (derived_early_secret), // salt_len
871 ss_e, // ikm - initial key material
872 sizeof (*ss_e));
873 if (GNUNET_OK != ret)
874 {
875 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting HS\n")
876 ;
877 GNUNET_assert (0);
878 }
879}
880
881
886static void
887derive_ihts (const struct GNUNET_HashCode *transcript,
888 const struct GNUNET_ShortHashCode *hs,
889 struct GNUNET_ShortHashCode *ihts)
890{
893 ihts, // result
894 sizeof (*ihts), // result len
895 hs, // prk?
898 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
899}
900
901
906static void
907derive_rhts (const struct GNUNET_HashCode *transcript,
908 const struct GNUNET_ShortHashCode *hs,
909 struct GNUNET_ShortHashCode *rhts)
910{
913 rhts,
914 sizeof (*rhts),
915 hs, // prk? TODO
918 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
919}
920
921
926static void
927derive_ms (const struct GNUNET_ShortHashCode *hs,
928 const struct GNUNET_ShortHashCode *ss_I,
929 struct GNUNET_ShortHashCode *ms)
930{
931 uint64_t ret;
932 struct GNUNET_ShortHashCode derived_handshake_secret;
933
935 &derived_handshake_secret,
936 sizeof (derived_handshake_secret),
937 hs,
940 if (GNUNET_OK != ret)
941 {
942 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dHS\n")
943 ;
944 GNUNET_assert (0);
945 }
946 // TODO check: are dHS the salt and ss_I the ikm or other way round?
947 ret = GNUNET_CRYPTO_hkdf_extract (ms, // prk
948 &derived_handshake_secret, // salt - dHS
949 sizeof (derived_handshake_secret), // salt_len
950 ss_I, // ikm - initial key material
951 sizeof (*ss_I));
952 if (GNUNET_OK != ret)
953 {
954 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting MS\n")
955 ;
956 GNUNET_assert (0);
957 }
958}
959
960
966static void
968 uint64_t seq,
969 const uint8_t write_iv[AEAD_NONCE_BYTES],
970 uint8_t per_record_write_iv[AEAD_NONCE_BYTES])
971{
972 uint64_t seq_nbo;
973 uint64_t *write_iv_ptr;
974 unsigned int byte_offset;
975
976 seq_nbo = GNUNET_htonll (seq);
977 memcpy (per_record_write_iv,
978 write_iv,
980 byte_offset =
981 AEAD_NONCE_BYTES - sizeof (uint64_t);
982 write_iv_ptr = (uint64_t*) (write_iv + byte_offset);
983 *write_iv_ptr ^= seq_nbo;
984}
985
986
991static void
993 const struct GNUNET_ShortHashCode *ts,
994 uint64_t seq,
995 unsigned char key[AEAD_KEY_BYTES],
996 unsigned char nonce[AEAD_NONCE_BYTES])
997{
998 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
999 /* derive actual key */
1002 key,
1004 ts,
1007
1008 /* derive nonce */
1011 nonce_tmp,
1013 ts,
1017 nonce_tmp,
1018 nonce);
1019}
1020
1021
1026static void
1027derive_next_ats (const struct GNUNET_ShortHashCode *old_ats,
1028 struct GNUNET_ShortHashCode *new_ats)
1029{
1030 int8_t ret;
1031
1032 // FIXME: Not sure of PRK and output may overlap here!
1034 new_ats,
1035 sizeof (*new_ats),
1036 old_ats,
1039 if (GNUNET_OK != ret)
1040 {
1042 "Something went wrong deriving next *ATS key\n");
1043 GNUNET_assert (0);
1044 }
1045}
1046
1047
1052static void
1053derive_initial_ats (const struct GNUNET_HashCode *transcript,
1054 const struct GNUNET_ShortHashCode *ms,
1055 enum GSC_KX_Role role,
1056 struct GNUNET_ShortHashCode *initial_ats)
1057{
1058 const char *traffic_str;
1059
1060 if (ROLE_INITIATOR == role)
1061 traffic_str = I_AP_TRAFFIC_STR;
1062 else
1063 traffic_str = R_AP_TRAFFIC_STR;
1066 initial_ats, // result
1067 sizeof (*initial_ats), // result len
1068 ms,
1070 GNUNET_CRYPTO_kdf_arg_string (traffic_str),
1071 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
1072}
1073
1074
1081static void
1082generate_responder_finished (const struct GNUNET_HashCode *transcript,
1083 const struct GNUNET_ShortHashCode *ms,
1084 struct GNUNET_HashCode *result)
1085{
1087 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1088
1090 &fk_R, // result
1091 sizeof (fk_R),
1092 ms,
1095 if (GNUNET_OK != ret)
1096 {
1098 "Something went wrong expanding fk_R\n");
1099 GNUNET_assert (0);
1100 }
1101
1102 GNUNET_CRYPTO_hmac (&fk_R,
1103 transcript,
1104 sizeof (*transcript),
1105 result);
1106}
1107
1108
1115static void
1116generate_initiator_finished (const struct GNUNET_HashCode *transcript,
1117 const struct GNUNET_ShortHashCode *ms,
1118 struct GNUNET_HashCode *result)
1119{
1121 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1122
1124 &fk_I, // result
1125 sizeof (fk_I),
1126 ms,
1129 if (GNUNET_OK != ret)
1130 {
1132 "Something went wrong expanding fk_I\n");
1133 GNUNET_assert (0);
1134 }
1135 GNUNET_CRYPTO_hmac (&fk_I,
1136 transcript,
1137 sizeof (*transcript),
1138 result);
1139}
1140
1141
1142struct InitiatorHelloCtx
1143{
1144 struct GSC_KeyExchangeInfo *kx;
1145 struct InitiatorHello *ihm_e;
1146 struct PilsRequest *req;
1147};
1148
1149static void
1150resend_responder_hello (void *cls)
1151{
1152 struct GSC_KeyExchangeInfo *kx = cls;
1153
1154 kx->resend_task = NULL;
1155 if (0 == kx->resend_tries_left)
1156 {
1158 "Restarting KX\n");
1159 restart_kx (kx);
1160 return;
1161 }
1162 kx->resend_tries_left--;
1164 "Resending responder hello. Retries left: %u\n",
1165 kx->resend_tries_left);
1169 kx);
1170}
1171
1172
1173void
1175{
1178 struct ResponderHello *rhm_e; /* responder hello message - encrypted pointer */
1179 struct GNUNET_MQ_Envelope *env;
1180 struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_kem_challenge;
1181 struct GNUNET_ShortHashCode rhts;
1182 struct GNUNET_ShortHashCode ihts;
1183 struct GNUNET_ShortHashCode hs;
1184 struct GNUNET_ShortHashCode ms;
1185 struct GNUNET_ShortHashCode ss_e;
1186 struct GNUNET_ShortHashCode ss_I;
1187 struct GNUNET_HashContext *hc;
1188 unsigned char enc_key[AEAD_KEY_BYTES];
1189 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1190
1191 // 4. encaps -> shared_secret_e, c_e (kemChallenge)
1192 // TODO potentially write this directly into rhm?
1193 ret = GNUNET_CRYPTO_hpke_kem_encaps (&kx->pk_e, // public ephemeral key of initiator
1194 &ephemeral_kem_challenge, // encapsulated key
1195 &ss_e); // key - ss_e
1196 if (GNUNET_OK != ret)
1197 {
1199 "Something went wrong encapsulating ss_e\n");
1200 return;
1201 }
1203 // 6. encaps -> shared_secret_I, c_I
1204 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public key of I
1205 &c_I, // encapsulated key
1206 &ss_I); // where to write the key material
1207 if (GNUNET_OK != ret)
1208 {
1210 "Something went wrong encapsulating ss_I\n");
1212 return;
1213 }
1214 // 7. generate RHTS (responder_handshare_secret_key) and RATS (responder_application_traffic_secret_key) (section 5)
1215 {
1216 struct GNUNET_HashCode transcript;
1217 snapshot_transcript (hc, &transcript);
1218#if DEBUG_KX
1220 "Transcript snapshot for derivation of HS, MS: `%s'\n",
1221 GNUNET_h2s (&transcript));
1222#endif
1224 &ss_e,
1225 &hs);
1226 derive_ms (&hs, &ss_I, &ms);
1227 }
1228
1229 // send ResponderHello
1230 // TODO fill fields / services_info!
1231 // 1. r_R <- random
1232 struct ResponderHelloPayload *rhp;
1233 size_t rhp_len = sizeof (*rhp) + strlen (my_services_info);
1234 unsigned char rhp_buf[rhp_len];
1235 size_t ct_len;
1236
1237 rhp = (struct ResponderHelloPayload*) rhp_buf;
1238 ct_len = rhp_len // ResponderHelloPayload, fist PT msg
1239 + sizeof (struct GNUNET_HashCode) // Finished hash, second PT msg
1240 + AEAD_TAG_BYTES * 2; // Two tags;
1241 env = GNUNET_MQ_msg_extra (rhm_e,
1242 ct_len,
1244
1245 rhm_e->r_R =
1247 UINT64_MAX);
1248
1249 // c_e
1250 GNUNET_memcpy (&rhm_e->c_e,
1251 &ephemeral_kem_challenge,
1252 sizeof (ephemeral_kem_challenge));
1254 rhm_e,
1255 sizeof (struct ResponderHello));
1256 // 2. Encrypt ServicesInfo and c_I with RHTS
1257 // derive RHTS
1258 {
1259 struct GNUNET_HashCode transcript;
1261 &transcript);
1262#if DEBUG_KX
1264 "Transcript snapshot for derivation of *HTS: `%s'\n",
1265 GNUNET_h2s (&transcript));
1266#endif
1267 derive_rhts (&transcript,
1268 &hs,
1269 &rhts);
1270 derive_ihts (&transcript,
1271 &hs,
1272 &ihts);
1274 0,
1275 enc_key,
1276 enc_nonce);
1277 }
1278 // c_I
1279 GNUNET_memcpy (&rhp->c_I, &c_I, sizeof (c_I));
1280 // Services info empty for now.
1281 GNUNET_memcpy (&rhp[1],
1283 strlen (my_services_info));
1284
1285 {
1286 unsigned long long out_ct_len;
1288 struct GNUNET_HashCode transcript;
1289 unsigned char *finished_buf;
1290 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1291 (unsigned char*) &rhm_e[1], /* c - ciphertext */
1292 &out_ct_len, /* clen_p */
1293 rhp_buf, /* rhm_p - plaintext message */
1294 rhp_len, // mlen
1295 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1296 // fields?
1297 NULL, // nsec - unused
1298 enc_nonce, // npub - nonce // FIXME nonce can be reused
1299 enc_key)); // k - key RHTS
1301 "Encrypted and wrote %llu bytes\n",
1302 out_ct_len);
1303 // 3. Create ResponderFinished (Section 6)
1304 // Derive fk_I <- HKDF-Expand (MS, "r finished", NULL)
1305 /* Forward the transcript */
1306 /* {svcinfo, c_I}RHTS */
1308 hc,
1309 &rhm_e[1],
1310 out_ct_len);
1311
1312 finished_buf = ((unsigned char*) &rhm_e[1]) + out_ct_len;
1314 &transcript);
1315#if DEBUG_KX
1317 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1318 GNUNET_h2s (&transcript));
1319#endif
1320 generate_responder_finished (&transcript,
1321 &ms,
1322 &finished);
1323 // 4. Encrypt ResponderFinished
1325 1,
1326 enc_key,
1327 enc_nonce);
1328 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1329 finished_buf, /* c - ciphertext */
1330 &out_ct_len, /* clen_p */
1331 (unsigned char*) &finished, /* rhm_p - plaintext message */
1332 sizeof (finished), // mlen
1333 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1334 // fields?
1335 NULL, // nsec - unused
1336 enc_nonce, // npub
1337 enc_key)); // k - key RHTS
1339 "Encrypted and wrote %llu bytes\n",
1340 out_ct_len);
1341 /* Forward the transcript
1342 * after responder finished,
1343 * before deriving *ATS and generating finished_I
1344 * (finished_I will be generated when receiving the InitiatorFinished message
1345 * in order to check it) */
1347 hc,
1348 finished_buf,
1349 out_ct_len);
1350 // 5. optionally send application data - encrypted with RATS
1351 // We do not really have any application data, instead, we send the ACK
1353 &transcript);
1354#if DEBUG_KX
1356 "Transcript snapshot for derivation of *ATS: `%s'\n",
1357 GNUNET_h2s (&transcript));
1358#endif
1359 derive_initial_ats (&transcript,
1360 &ms,
1362 &kx->current_ats);
1363 }
1364 /* Lock into struct */
1366 kx->transcript_hash_ctx = hc;
1367 kx->master_secret = ms;
1368 kx->handshake_secret = hs;
1369 kx->ss_e = ss_e;
1370 kx->ihts = ihts;
1371 kx->rhts = rhts;
1372 kx->ss_I = ss_I;
1373 kx->current_epoch = 0;
1374 kx->current_sqn = 0;
1376 kx->current_sqn,
1377 enc_key,
1378 enc_nonce);
1379
1380 GNUNET_MQ_send_copy (kx->mq, env);
1381 kx->resend_env = env;
1383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent ResponderHello\n");
1384
1387 kx);
1389 monitor_notify_all (kx);
1390 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1391}
1392
1393
1394static void
1395handle_initiator_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_R)
1396{
1397 struct InitiatorHelloCtx *ihm_ctx = cls;
1398 struct GSC_KeyExchangeInfo *kx = ihm_ctx->kx;
1399 uint32_t ihm_len = ntohs (ihm_ctx->ihm_e->header.size);
1400 unsigned char enc_key[AEAD_KEY_BYTES];
1401 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1402 struct GNUNET_HashCode h1;
1403 struct GNUNET_HashCode h2;
1404 struct GNUNET_HashCode transcript;
1405 struct GNUNET_ShortHashCode es;
1406 struct GNUNET_ShortHashCode ets;
1408
1409 ihm_ctx->req->op = NULL;
1412 ihm_ctx->req);
1413 GNUNET_free (ihm_ctx->req);
1414
1415
1417 &ihm_ctx->ihm_e->pk_e,
1418 sizeof (ihm_ctx->ihm_e->pk_e));
1419 // 5. generate ETS (early_traffic_secret_key, decrypt pk_i
1420 // expand ETS <- expand ES <- extract ss_R
1421 // use ETS to decrypt
1422
1423 /* Forward the transcript hash context over the unencrypted fields to get it
1424 * to the same status that the initiator had when it needed to derive es and
1425 * ets for the encryption */
1428 ihm_ctx->ihm_e,
1429 sizeof (struct InitiatorHello));
1431 &transcript);
1432#if DEBUG_KX
1434 "Transcript snapshot for derivation of ES, ETS: `%s'\n",
1435 GNUNET_h2s (&transcript));
1436#endif
1437 derive_es_ets (&transcript, ss_R, &es, &ets);
1439 0,
1440 enc_key,
1441 enc_nonce);
1442 {
1443 struct InitiatorHelloPayload *ihmp;
1444 size_t ct_len = ihm_len - sizeof (struct InitiatorHello);
1445 unsigned char ihmp_buf[ct_len - AEAD_TAG_BYTES];
1446 ihmp = (struct InitiatorHelloPayload*) ihmp_buf;
1447 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1448 ihmp_buf, // unsigned char *m
1449 NULL, // mlen_p message length
1450 NULL, // unsigned char *nsec - unused: NULL
1451 (unsigned char*) &ihm_ctx->ihm_e[1], // const unsigned char *c - ciphertext
1452 ct_len, // unsigned long long clen - length of ciphertext
1453 // mac, // const unsigned char *mac - authentication tag
1454 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1455 0, // unsigned long long adlen
1456 enc_nonce, // const unsigned char *npub - nonce
1457 enc_key // const unsigned char *k - key
1458 );
1459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pid_sender: %s\n",
1460 GNUNET_i2s (&ihmp->pk_I));
1461 if (0 != ret)
1462 {
1464 "Something went wrong decrypting: %d\n", ret);
1465 GNUNET_break_op (0);
1466 GNUNET_free (ihm_ctx->ihm_e);
1467 GNUNET_free (ihm_ctx);
1469 kx->transcript_hash_ctx = NULL;
1470 return;
1471 }
1472 /* now forward it considering the encrypted messages that the initiator was
1473 * able to send after deriving the es and ets */
1475 &ihm_ctx->ihm_e[1],
1476 ct_len);
1477 GNUNET_memcpy (&kx->peer,
1478 &ihmp->pk_I,
1479 sizeof (struct GNUNET_PeerIdentity));
1480 }
1481 // We could follow with the rest of the Key Schedule (dES, HS, ...) for now
1482 /* Check that we are actually in the receiving role */
1483 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
1485 sizeof(struct GNUNET_PeerIdentity),
1486 &h2);
1487 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, &h2))
1488 {
1489 /* peer with "lower" identity starts KX, otherwise we typically end up
1490 with both peers starting the exchange and transmit the 'set key'
1491 message twice */
1492 /* Something went wrong - we have the lower value and should have sent the
1493 * InitiatorHello, but instead received it. TODO handle this case
1494 * We might end up in this case if the initiator didn't initiate the
1495 * handshake long enough and the 'responder' initiates the handshake */
1497 "Something went wrong - we have the lower value and should have sent the InitiatorHello, but instead received it.\n");
1498 GNUNET_free (ihm_ctx->ihm_e);
1499 GNUNET_free (ihm_ctx);
1501 kx->transcript_hash_ctx = NULL;
1502 return;
1503 }
1504
1505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer ID of other peer: %s\n", GNUNET_i2s
1506 (&kx->peer));
1507 /* We update the monitoring peers here because now we know
1508 * that we can decrypt the message AND know the PID
1509 */
1510 monitor_notify_all (kx);
1511 kx->ss_R = *ss_R;
1512 kx->early_secret_key = es;
1513 kx->early_traffic_secret = ets;
1515}
1516
1517
1518static int
1519check_initiator_hello (void *cls, const struct InitiatorHello *m)
1520{
1521 uint16_t size = ntohs (m->header.size);
1522
1523 if (size < sizeof (*m)
1524 + sizeof (struct InitiatorHelloPayload)
1526 {
1527 return GNUNET_SYSERR;
1528 }
1529 return GNUNET_OK;
1530}
1531
1532
1541static void
1542handle_initiator_hello (void *cls, const struct InitiatorHello *ihm_e)
1543{
1544 struct GSC_KeyExchangeInfo *kx = cls;
1545 struct GNUNET_HashCode hash_compare = { 0 };
1546 struct InitiatorHelloCtx *initiator_hello_cls;
1547 size_t ihm_len;
1548
1549 if (ROLE_INITIATOR == kx->role)
1550 {
1551 GNUNET_break_op (0);
1553 "I am an initiator! Tearing down...\n");
1554 return;
1555 }
1557 {
1558 GNUNET_break_op (0);
1560 "Already received InitiatorHello)\n");
1561 return;
1562 }
1563 GNUNET_assert (NULL == kx->transcript_hash_ctx); // FIXME this triggers sometimes - why?
1566
1567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorHello\n");
1569 gettext_noop ("# key exchanges initiated"),
1570 1,
1571 GNUNET_NO);
1572
1574
1575 // 1. verify type _INITIATOR_HELLO
1576 // - This is implicytly done by arriving within this handler
1577 // - or is this about verifying the 'additional data' part of aead?
1578 // should it check the encryption + mac? (is this implicitly done
1579 // while decrypting?)
1580 // 2. verify H(pk_R) matches pk_R
1582 sizeof (struct GNUNET_PeerIdentity),
1583 &hash_compare); /* result */
1584 if (0 != memcmp (&ihm_e->h_pk_R,
1585 &hash_compare,
1586 sizeof (struct GNUNET_HashCode)))
1587 {
1589 "This message is not meant for us (H(PID) mismatch)\n");
1591 kx->transcript_hash_ctx = NULL;
1592 return;
1593 }
1594 // FIXME this sometimes triggers in the tests - why?
1595 // 3. decaps -> shared_secret_R, c_R (kemChallenge)
1596 ihm_len = ntohs (ihm_e->header.size);
1597 initiator_hello_cls = GNUNET_new (struct InitiatorHelloCtx);
1598 initiator_hello_cls->kx = kx;
1599 initiator_hello_cls->ihm_e = GNUNET_malloc (ihm_len);
1600 GNUNET_memcpy (initiator_hello_cls->ihm_e, ihm_e, ihm_len);
1601 initiator_hello_cls->req = GNUNET_new (struct PilsRequest);
1604 initiator_hello_cls->req);
1605 initiator_hello_cls->req->op =
1607 &ihm_e->c_R,
1608 // encapsulated key
1610 // continuation
1611 initiator_hello_cls);
1612}
1613
1614
1615struct ResponderHelloCls
1616{
1617 /* Current KX session */
1618 struct GSC_KeyExchangeInfo *kx;
1619
1620 /* responder hello message - encrypted */
1621 struct ResponderHello rhm_e;
1622
1623 /* responder hello message - plain/decrypted */
1624 struct ResponderHelloPayload *rhp;
1625
1626 /* Decrypted finish hash */
1628
1629 /* Encrypted finished CT (for transcript later) */
1630 char finished_enc[sizeof (struct GNUNET_HashCode)
1631 + AEAD_TAG_BYTES];
1632
1633 /* Temporary transcript context */
1634 struct GNUNET_HashContext *hc;
1635
1636 /* Temporary handshake secret */
1637 struct GNUNET_ShortHashCode hs;
1638
1639 /* Temporary handshake secret */
1641
1642 /* Temporary handshake secret */
1644
1645 /* Temporary handshake secret */
1647
1648 /* Pending PILS request */
1649 struct PilsRequest *req;
1650};
1651
1652static void
1653resend_initiator_done (void *cls)
1654{
1655 struct GSC_KeyExchangeInfo *kx = cls;
1656
1657 kx->resend_task = NULL;
1658 if (0 == kx->resend_tries_left)
1659 {
1661 "Restarting KX\n");
1662 restart_kx (kx);
1663 return;
1664 }
1665 kx->resend_tries_left--;
1667 "Resending initiator done. Retries left: %u\n",
1668 kx->resend_tries_left);
1672 kx);
1673}
1674
1675
1676static void
1677handle_responder_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_I)
1678{
1679 struct ResponderHelloCls *rh_ctx = cls;
1680 struct GSC_KeyExchangeInfo *kx = rh_ctx->kx;
1681 struct InitiatorDone *idm_e; /* encrypted */
1682 struct InitiatorDone idm_local;
1683 struct InitiatorDone *idm_p; /* plaintext */
1684 struct GNUNET_MQ_Envelope *env;
1685 unsigned char enc_key[AEAD_KEY_BYTES];
1686 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1687 struct ConfirmationAck ack_i;
1688 struct GNUNET_HashCode transcript;
1689 struct GNUNET_ShortHashCode ms;
1690
1691 rh_ctx->req->op = NULL;
1694 rh_ctx->req);
1695 GNUNET_free (rh_ctx->req);
1696 // XXX valgrind reports uninitialized memory
1697 // the following is a way to check whether this memory was meant
1698 // memset (&rhm_local, 0, sizeof (rhm_local)); - adapt to cls if still needed
1699 memset (&idm_local, 0, sizeof (idm_local));
1700
1701 kx->ss_I = *ss_I;
1702
1703 /* derive *ATS */
1704 derive_ms (&rh_ctx->hs, ss_I, &ms);;
1705 // 5. Create ResponderFinished as per Section 6 and check against decrypted payload.
1706 struct GNUNET_HashCode responder_finished;
1707 // Transcript updates, snapshot again
1708 snapshot_transcript (rh_ctx->hc,
1709 &transcript);
1710#if DEBUG_KX
1712 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1713 GNUNET_h2s (&transcript));
1714#endif
1715 generate_responder_finished (&transcript,
1716 &ms,
1717 &responder_finished);
1718 if (0 != memcmp (&rh_ctx->decrypted_finish,
1719 &responder_finished,
1720 sizeof (struct GNUNET_HashCode)))
1721 {
1723 "Could not verify \"responder finished\"\n");
1724 GNUNET_free (rh_ctx->rhp);
1725 GNUNET_free (rh_ctx->hc);
1726 GNUNET_free (rh_ctx);
1727 GNUNET_assert (0);
1728 }
1729
1730
1731 /* Forward the transcript
1732 * after generating finished_R,
1733 * before deriving *ATS */
1735 rh_ctx->hc,
1736 rh_ctx->finished_enc,
1737 sizeof (rh_ctx->finished_enc));
1738
1739 // At this point we cannot fail anymore and may lock into kx
1741 kx->transcript_hash_ctx = rh_ctx->hc;
1742 kx->ss_I = *ss_I;
1743 kx->handshake_secret = rh_ctx->hs;
1744 kx->ss_e = rh_ctx->ss_e;
1745 kx->ihts = rh_ctx->ihts;
1746 kx->rhts = rh_ctx->rhts;
1747 kx->master_secret = ms;
1748 GNUNET_free (rh_ctx->rhp);
1749 GNUNET_free (rh_ctx);
1750 rh_ctx = NULL;
1751
1753 &transcript);
1754#if DEBUG_KX
1756 "Transcript snapshot for derivation of *ATS: `%s'\n",
1757 GNUNET_h2s (&transcript));
1758#endif
1759 derive_initial_ats (&transcript,
1760 &kx->master_secret,
1762 &kx->their_ats[0]);
1763 for (int i = 0; i < MAX_EPOCHS - 1; i++)
1764 {
1765 derive_next_ats (&kx->their_ats[i],
1766 &kx->their_ats[i + 1]);
1767 }
1768 kx->their_max_epoch = MAX_EPOCHS - 1;
1769
1771 0,
1772 enc_key,
1773 enc_nonce);
1774 /* Create InitiatorDone message */
1775 idm_p = &idm_local; /* plaintext */
1776 env = GNUNET_MQ_msg_extra (idm_e,
1777 sizeof (ack_i)
1780 // 6. Create IteratorFinished as per Section 6.
1781 generate_initiator_finished (&transcript,
1782 &kx->master_secret,
1783 &idm_p->finished);
1785 "Ifinished: `%s'\n",
1786 GNUNET_h2s (&idm_p->finished));
1788 "Transcript `%s'\n",
1789 GNUNET_h2s (&transcript));
1790 // 7. Send InteratorFinished message encrypted with the key derived from IHTS to R
1791
1792 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1793 (unsigned char*) &idm_e->finished, /* c - ciphertext */
1794 NULL, /* clen_p */
1795 (unsigned char*) &idm_p->finished, /* idm_p - plaintext message */
1796 sizeof (idm_p->finished), // mlen
1797 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1798 // fields?
1799 NULL, // nsec - unused
1800 enc_nonce, // npub - nonce
1801 enc_key)); // k - key IHTS
1802 /* Forward the transcript hash context
1803 * after generating finished_I and RATS_0
1804 * before deriving IATS_0 */
1806 &idm_e->finished,
1807 sizeof (idm_e->finished)
1808 + AEAD_TAG_BYTES);
1810 &transcript);
1811#if DEBUG_KX
1813 "Transcript snapshot for derivation of *ATS: `%s'\n",
1814 GNUNET_h2s (&transcript));
1815#endif
1816 derive_initial_ats (&transcript,
1817 &kx->master_secret,
1819 &kx->current_ats);
1820 kx->current_epoch = 0;
1821 kx->current_sqn++;
1822 // 8. optionally encrypt payload TODO
1824 kx->current_sqn,
1825 enc_key,
1826 enc_nonce);
1827 kx->current_sqn++;
1828 ack_i.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
1829 ack_i.header.size = htons (sizeof ack_i);
1830 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1831 (unsigned char*) &idm_e[1], /* c - ciphertext */
1832 NULL, /* clen_p */
1833 (unsigned char*) &ack_i, /* rhm_p - plaintext message */
1834 sizeof ack_i, // mlen
1835 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1836 // fields?
1837 NULL, // nsec - unused
1838 enc_nonce, // npub - nonce // FIXME nonce can be reused
1839 enc_key)); // k - key RHTS
1840
1841 GNUNET_MQ_send_copy (kx->mq, env);
1842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent InitiatorDone\n");
1843
1844
1845 kx->resend_env = env;
1849 kx);
1851 monitor_notify_all (kx);
1852 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1853}
1854
1855
1856static int
1857check_responder_hello (void *cls, const struct ResponderHello *m)
1858{
1859 uint16_t size = ntohs (m->header.size);
1860
1861 if (size < sizeof (*m)
1862 + sizeof (struct ResponderHelloPayload)
1863 + sizeof (struct GNUNET_HashCode)
1864 + AEAD_TAG_BYTES * 2)
1865 {
1866 return GNUNET_SYSERR;
1867 }
1868 return GNUNET_OK;
1869}
1870
1871
1877static void
1878handle_responder_hello (void *cls, const struct ResponderHello *rhm_e)
1879{
1880 struct GSC_KeyExchangeInfo *kx = cls;
1881 struct PilsRequest *req;
1882 struct ResponderHelloCls *rh_ctx;
1883 struct GNUNET_HashCode transcript;
1884 struct GNUNET_HashContext *hc;
1885 unsigned char enc_key[AEAD_KEY_BYTES];
1886 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1888
1889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ResponderHello\n");
1890
1892 if (NULL != kx->resend_task)
1893 {
1895 kx->resend_task = NULL;
1896 }
1897 if (NULL != kx->resend_env)
1898 {
1899 GNUNET_free (kx->resend_env);
1900 kx->resend_env = NULL;
1901 }
1902
1903 /* Forward the transcript hash context */
1904 if (ROLE_RESPONDER == kx->role)
1905 {
1906 GNUNET_break_op (0);
1908 "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");
1928 GNUNET_free (hc);
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);
1990 GNUNET_free (hc);
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);
2017 GNUNET_free (hc);
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}
2035
2036
2037static int
2038check_initiator_done (void *cls, const struct InitiatorDone *m)
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}
2048
2049
2055static void
2056handle_initiator_done (void *cls, const struct InitiatorDone *idm_e)
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\n");
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 (int 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],
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);
2554 GNUNET_MST_destroy (kx->mst);
2555 GNUNET_free (kx);
2556}
2557
2558
2559static void
2560resend_initiator_hello (void *cls)
2561{
2562 struct GSC_KeyExchangeInfo *kx = cls;
2563
2564 kx->resend_task = NULL;
2566 "Resending initiator hello.\n");
2568 // FIXME (Exponential) backoff?
2571 kx);
2572}
2573
2574
2580static void
2582{
2583 struct GNUNET_MQ_Envelope *env;
2584 struct GNUNET_ShortHashCode es;
2585 struct GNUNET_ShortHashCode ets;
2586 struct GNUNET_ShortHashCode ss_R;
2587 struct InitiatorHelloPayload *ihmp; /* initiator hello message - buffer on stack */
2588 struct InitiatorHello *ihm_e; /* initiator hello message - encrypted */
2589 long long unsigned int c_len;
2590 unsigned char enc_key[AEAD_KEY_BYTES];
2591 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2593 size_t pt_len;
2594
2595 pt_len = sizeof (*ihmp) + strlen (my_services_info);
2596 c_len = pt_len + AEAD_TAG_BYTES;
2597 env = GNUNET_MQ_msg_extra (ihm_e,
2598 c_len,
2600 ihmp = (struct InitiatorHelloPayload*) &ihm_e[1];
2601 ihmp->peer_class = htons (GNUNET_CORE_CLASS_UNKNOWN); // TODO set this to a meaningful
2602 GNUNET_memcpy (&ihmp->pk_I,
2604 sizeof (GSC_my_identity));
2605 GNUNET_CRYPTO_hash (&kx->peer, /* what to hash */ // TODO do we do this twice?
2606 sizeof (struct GNUNET_PeerIdentity),
2607 &ihm_e->h_pk_R); /* result */
2608 // TODO init hashcontext/transcript_hash
2609 GNUNET_assert (NULL == kx->transcript_hash_ctx);
2611 GNUNET_assert (NULL != kx->transcript_hash_ctx);
2612 // TODO fill services_info
2613
2614 // 1. Encaps
2615 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public ephemeral key of initiator
2616 &ihm_e->c_R, // encapsulated key
2617 &ss_R); // key - ss_R
2618 if (GNUNET_OK != ret)
2619 {
2621 "Something went wrong encapsulating ss_R\n");
2622 // TODO handle
2623 }
2624 // 2. generate rR (uint64_t) - is this the nonce? Naming seems not quite
2625 // consistent
2626 ihm_e->r_I =
2628 UINT64_MAX);
2629 // 3. generate sk_e/pk_e - ephemeral key
2632 &kx->sk_e.ecdhe_key,
2633 &kx->pk_e.ecdhe_key);
2634 GNUNET_memcpy (&ihm_e->pk_e,
2635 &kx->pk_e.ecdhe_key,
2636 sizeof (kx->pk_e.ecdhe_key));
2637 // 4. generate ETS to encrypt
2638 // generate ETS (early_traffic_secret_key, decrypt pk_i
2639 // expand ETS <- expand ES <- extract ss_R
2640 // use ETS to decrypt
2642 ihm_e,
2643 sizeof (struct InitiatorHello));
2644 {
2645 struct GNUNET_HashCode transcript;
2647 &transcript);
2648 derive_es_ets (&transcript,
2649 &ss_R,
2650 &es,
2651 &ets);
2653 0,
2654 enc_key,
2655 enc_nonce);
2656 }
2657 // 5. encrypt
2658
2659 ret = crypto_aead_xchacha20poly1305_ietf_encrypt (
2660 (unsigned char*) &ihm_e[1], /* c - ciphertext */
2661 // mac,
2662 // NULL, // maclen_p
2663 &c_len, /* clen_p */
2664 (unsigned char*) ihmp, /* m - plaintext message */
2665 pt_len, // mlen
2666 NULL, 0, // ad, adlen // FIXME maybe over the unencrypted header?
2667 // fields?
2668 NULL, // nsec - unused
2669 enc_nonce, // npub - nonce
2670 enc_key); // k - key
2671 if (0 != ret)
2672 {
2673 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong encrypting\n");
2675 kx->transcript_hash_ctx = NULL;
2677 return;
2678 }
2679 /* Forward the transcript */
2682 &ihm_e[1],
2683 c_len);
2684
2686 kx->early_secret_key = es;
2687 kx->early_traffic_secret = ets;
2688 kx->ss_R = ss_R;
2689 monitor_notify_all (kx);
2690 GNUNET_MQ_send_copy (kx->mq, env);
2691 kx->resend_env = env;
2695 kx);
2696}
2697
2698
2699static void
2701{
2702 struct GNUNET_ShortHashCode new_ats;
2703
2704 if ((UINT64_MAX == kx->current_sqn) ||
2706 {
2708 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2709 ", incrementing epoch...\n",
2711 kx->current_sqn);
2712 // Can this trigger? Maybe if we receive a lot of
2713 // heartbeats?
2714 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2715 kx->current_epoch++;
2718 kx->current_sqn = 0;
2720 &new_ats);
2721 memcpy (&kx->current_ats,
2722 &new_ats,
2723 sizeof new_ats);
2724 }
2725}
2726
2727
2734void
2736 const void *payload,
2737 size_t payload_size)
2738{
2739 struct GNUNET_MQ_Envelope *env;
2740 struct EncryptedMessage *encrypted_msg;
2741 unsigned char enc_key[AEAD_KEY_BYTES];
2742 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2743 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2744 uint64_t sqn;
2745 uint64_t epoch;
2746 int8_t ret;
2747
2748 encrypted_msg = NULL;
2749
2750 check_rekey (kx);
2751 sqn = kx->current_sqn;
2752 epoch = kx->current_epoch;
2753 /* We are the sender and as we are going to send,
2754 * we are using the initiator key material */
2756 sqn,
2757 enc_key,
2758 enc_nonce);
2759 kx->current_sqn++;
2760 derive_sn (&kx->current_ats,
2761 seq_enc_k,
2762 sizeof seq_enc_k);
2763 env = GNUNET_MQ_msg_extra (encrypted_msg,
2764 payload_size,
2766 // only encrypt the payload for now
2767 // TODO encrypt other fields as well
2768 ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached (
2769 (unsigned char*) &encrypted_msg[1], // c - resulting ciphertext
2770 (unsigned char*) &encrypted_msg->tag, // mac - resulting mac/tag
2771 NULL, // maclen
2772 (unsigned char*) payload, // m - plain message
2773 payload_size, // mlen
2774 NULL, // ad - additional data TODO also cover the unencrypted part (epoch)
2775 0, // adlen
2776 NULL, // nsec - unused
2777 enc_nonce, // npub nonce
2778 enc_key // k - key
2779 );
2780 if (0 != ret)
2781 {
2783 "Something went wrong encrypting message\n");
2784 GNUNET_assert (0);
2785 }
2786 {
2787 /* compute the sequence number */
2788 unsigned char *seq_enc_nonce;
2789 uint64_t seq_nbo;
2790 uint32_t seq_enc_ctr;
2791
2792 seq_nbo = GNUNET_htonll (sqn);
2793 seq_enc_ctr = *((uint32_t*) encrypted_msg->tag);
2794 seq_enc_nonce = &encrypted_msg->tag[sizeof (uint32_t)];
2795 crypto_stream_chacha20_ietf_xor_ic (
2796 (unsigned char*) &encrypted_msg->sequence_number,
2797 (unsigned char*) &seq_nbo,
2798 sizeof seq_nbo,
2799 seq_enc_nonce,
2800 ntohl (seq_enc_ctr),
2801 seq_enc_k);
2802#if DEBUG_KX
2803 GNUNET_print_bytes (seq_enc_k,
2804 sizeof seq_enc_k,
2805 8,
2806 GNUNET_NO);
2807 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2808 sizeof seq_enc_ctr,
2809 8,
2810 GNUNET_NO);
2811#endif
2813 "Sending encrypted message with E(SQN=%" PRIu64 ")=%" PRIu64
2814 "\n",
2815 sqn,
2816 encrypted_msg->sequence_number);
2817 }
2818 encrypted_msg->epoch = GNUNET_htonll (epoch);
2819
2820 // TODO actually copy payload
2821 GNUNET_MQ_send (kx->mq, env);
2822}
2823
2824
2831static void
2832peer_id_change_cb (void *cls,
2833 const struct GNUNET_HELLO_Parser *parser,
2834 const struct GNUNET_HashCode *hash)
2835{
2836 (void) cls;
2838 // TODO check that hash matches last fed hash
2840 "This peer has now a new peer id: %s\n",
2842 // TODO if changing from old peer_id to new peer_id: tear down old
2843 // connections, try restart connections over kept addresses?
2844 /* Continue initialisation of core */
2845 if (GNUNET_YES == init_phase)
2846 {
2849 }
2850}
2851
2852
2858int
2859GSC_KX_init (void)
2860{
2862 GNUNET_MQ_hd_var_size (initiator_hello,
2864 struct InitiatorHello,
2865 NULL),
2866 GNUNET_MQ_hd_var_size (initiator_done,
2868 struct InitiatorDone,
2869 NULL),
2870 GNUNET_MQ_hd_var_size (responder_hello,
2872 struct ResponderHello,
2873 NULL),
2874 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2876 struct EncryptedMessage,
2877 NULL),
2879 };
2880
2884 NULL); // TODO potentially wait
2885 // until we have a peer_id?
2886 // pay attention to whether
2887 // we have one anyways
2888 if (NULL == pils)
2889 {
2890 GSC_KX_done ();
2891 return GNUNET_SYSERR;
2892 }
2893
2895 transport =
2898 handlers,
2899 NULL, // cls - this connection-independant
2900 // cls seems not to be needed.
2901 // the connection-specific cls
2902 // will be set as a return value
2903 // of
2904 // handle_transport_notify_connect
2907 if (NULL == transport)
2908 {
2909 GSC_KX_done ();
2910 return GNUNET_SYSERR;
2911 }
2913 "Connected to TRANSPORT\n");
2914 return GNUNET_OK;
2915}
2916
2917
2921void
2922GSC_KX_done ()
2923{
2924 struct PilsRequest *pr;
2925 while (NULL != (pr = pils_requests_head))
2926 {
2929 pr);
2930 if (NULL != pr->op)
2931 GNUNET_PILS_cancel (pr->op);
2932 GNUNET_free (pr);
2933 }
2934 if (NULL != pils)
2935 {
2937 pils = NULL;
2938 }
2939 if (NULL != transport)
2940 {
2942 transport = NULL;
2943 }
2944 if (NULL != rekey_task)
2945 {
2947 rekey_task = NULL;
2948 }
2949 if (NULL != nc)
2950 {
2952 nc = NULL;
2953 }
2954}
2955
2956
2963unsigned int
2965{
2966 return GNUNET_MQ_get_length (kxinfo->mq);
2967}
2968
2969
2970int
2972{
2973 return kxinfo->has_excess_bandwidth;
2974}
2975
2976
2985void
2987{
2988 struct GNUNET_MQ_Envelope *env;
2989 struct MonitorNotifyMessage *done_msg;
2990 struct GSC_KeyExchangeInfo *kx;
2991
2993 for (kx = kx_head; NULL != kx; kx = kx->next)
2994 {
2995 struct GNUNET_MQ_Envelope *env_notify;
2996 struct MonitorNotifyMessage *msg;
2997
2999 msg->state = htonl ((uint32_t) kx->status);
3000 msg->peer = kx->peer;
3001 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
3002 GNUNET_MQ_send (mq, env_notify);
3003 }
3005 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
3008}
3009
3010
3011/* 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.
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.
struct GNUNET_PeerIdentity GSC_my_identity
Our identity.
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_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.
static void peer_id_change_cb(void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *hash)
Callback for PILS to be called once the peer id changes.
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....
#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.
static enum GNUNET_GenericReturnValue init_phase
Indicates whether we are still in the initialisation phase (waiting for our peer id).
#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.
#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)
static struct GNUNET_PILS_Handle * pils
Pils service.
#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:367
void GNUNET_PILS_disconnect(struct GNUNET_PILS_Handle *handle)
Disconnect from the PILS service.
Definition pils_api.c:390
void GNUNET_PILS_cancel(struct GNUNET_PILS_Operation *op)
Cancel request.
Definition pils_api.c:495
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:468
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(enum GNUNET_CRYPTO_Quality mode, 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
@ GNUNET_CRYPTO_QUALITY_NONCE
Randomness for IVs etc.
#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:41
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.
const struct GNUNET_PeerIdentity * GNUNET_HELLO_parser_get_id(const struct GNUNET_HELLO_Parser *parser)
Get the PeerIdentity for this builder.
Definition hello-uri.c:353
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 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
@ GNUNET_ERROR_TYPE_INFO
#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:232
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
A handle for the PILS service.
Definition pils_api.c:82
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 [1/2]

#define MIN_HEARTBEAT_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)

What is the minimum frequency for a heartbeat message?

What is the minimum frequency for a HEARTBEAT message?

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

◆ MIN_HEARTBEAT_FREQUENCY [2/2]

#define MIN_HEARTBEAT_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)

What is the minimum frequency for a heartbeat message?

What is the minimum frequency for a HEARTBEAT message?

Definition at line 77 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 89 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 98 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 103 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 109 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 116 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 122 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 128 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 134 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 140 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 146 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 152 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 158 of file gnunet-service-core_kx.c.

◆ CAKE_LABEL

#define CAKE_LABEL   "cake10"

Labeled expand label for CAKE.

Definition at line 163 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 169 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 175 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 181 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 187 of file gnunet-service-core_kx.c.

188{
189 /* Peer is supposed to initiate the key exchange */
190 ROLE_INITIATOR = 0,
191
192 /* Peer is supposed to wait for the key exchange */
193 ROLE_RESPONDER = 1,
194};

Function Documentation

◆ buffer_clear()

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

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

455{
456#if HAVE_MEMSET_S
457 memset_s (buf, len, 0, len);
458#elif HAVE_EXPLICIT_BZERO
459 explicit_bzero (buf, len);
460#else
461 volatile unsigned char *p = buf;
462 while (len--)
463 *p++ = 0;
464#endif
465}

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 469 of file gnunet-service-core_kx.c.

470{
471 buffer_clear (&kx->ihts,
472 sizeof kx->ihts);
473 buffer_clear (&kx->rhts,
474 sizeof kx->rhts);
475 buffer_clear (&kx->sk_e,
476 sizeof kx->sk_e);
477 buffer_clear (&kx->ss_I,
478 sizeof kx->ss_I);
479 buffer_clear (&kx->ss_R,
480 sizeof kx->ss_R);
481 buffer_clear (&kx->ss_e,
482 sizeof kx->ss_e);
484 sizeof kx->master_secret);
486 sizeof kx->early_secret_key);
488 sizeof kx->early_traffic_secret);
490 sizeof kx->handshake_secret);
491}

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 495 of file gnunet-service-core_kx.c.

497{
498 struct GNUNET_HashContext *tmp;
499
500 tmp = GNUNET_CRYPTO_hash_context_copy (ts_hash);
501 GNUNET_CRYPTO_hash_context_finish (tmp, snapshot);
502}

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 511 of file gnunet-service-core_kx.c.

512{
514
516 msg.header.size = htons (sizeof(msg));
517 msg.state = htonl ((uint32_t) kx->status);
518 msg.peer = kx->peer;
519 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
522}

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 649 of file gnunet-service-core_kx.c.

650{
651 struct GNUNET_HashCode h1;
652 struct GNUNET_HashCode h2;
653
654 // TODO what happens if we're in the middle of a peer id change?
655 // TODO there's a small chance this gets already called when we don't have a
656 // peer id yet. Add a kx, insert into the list, mark it as to be completed
657 // and let the callback to pils finish the rest once we got the peer id
658
660 "Initiating key exchange with peer %s\n",
661 GNUNET_i2s (&kx->peer));
663 gettext_noop ("# key exchanges initiated"),
664 1,
665 GNUNET_NO);
666
668 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
670 sizeof(struct GNUNET_PeerIdentity),
671 &h2);
672 if (NULL != kx->transcript_hash_ctx)
674 kx->transcript_hash_ctx = NULL;
675 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, &h2))
676 {
677 /* peer with "lower" identity starts KX, otherwise we typically end up
678 with both peers starting the exchange and transmit the 'set key'
679 message twice */
681 "I am the initiator, sending hello\n");
682 kx->role = ROLE_INITIATOR;
684 }
685 else
686 {
687 /* peer with "higher" identity starts a delayed KX, if the "lower" peer
688 * does not start a KX since it sees no reasons to do so */
690 "I am the responder, yielding and await initiator hello\n");
692 kx->role = ROLE_RESPONDER;
694 }
695
696}

References gettext_noop, 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_STATISTICS_update(), GSC_my_identity, 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_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 536 of file gnunet-service-core_kx.c.

537{
538 struct GSC_KeyExchangeInfo *kx = cls;
539 struct GNUNET_TIME_Relative retry;
540 struct GNUNET_TIME_Relative left;
541 struct Heartbeat hb;
542
543 kx->heartbeat_task = NULL;
545 if (0 == left.rel_value_us)
546 {
548 gettext_noop ("# sessions terminated by timeout"),
549 1,
550 GNUNET_NO);
551 GSC_SESSIONS_end (&kx->peer);
554 restart_kx (kx);
555 return;
556 }
558 "Sending HEARTBEAT to `%s'\n",
559 GNUNET_i2s (&kx->peer));
561 gettext_noop ("# heartbeat messages sent"),
562 1,
563 GNUNET_NO);
564 hb.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT);
565 hb.header.size = htons (sizeof hb);
566 // FIXME when do we request update?
567 hb.flags = 0;
568 GSC_KX_encrypt_and_transmit (kx, &hb, sizeof hb);
571 kx->heartbeat_task =
573}

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 584 of file gnunet-service-core_kx.c.

585{
587
588 kx->timeout =
590 delta =
592 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
593 {
594 /* we only notify monitors about timeout changes if those
595 are bigger than the threshold (5s) */
597 }
598 if (NULL != kx->heartbeat_task)
603 kx);
604}

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 2582 of file gnunet-service-core_kx.c.

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

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_QUALITY_NONCE, GNUNET_CRYPTO_random_u64(), 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_SCHEDULER_add_delayed(), GSC_my_identity, InitiatorHello::h_pk_R, monitor_notify_all(), GSC_KeyExchangeInfo::mq, 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::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 628 of file gnunet-service-core_kx.c.

629{
630 struct GSC_KeyExchangeInfo *kx = cls;
631
633 "Decrypted message of type %d from %s\n",
634 ntohs (m->type),
635 GNUNET_i2s (&kx->peer));
637 m,
638 ntohs (m->size),
641 m,
642 sizeof(struct GNUNET_MessageHeader),
644 return GNUNET_OK;
645}

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 710 of file gnunet-service-core_kx.c.

713{
714 struct GSC_KeyExchangeInfo *kx;
715 (void) cls;
716 if (0 == memcmp (peer_id, &GSC_my_identity, sizeof *peer_id))
717 {
719 "Ignoring connection to self\n");
720 return NULL;
721 }
723 "Incoming connection of peer with %s\n",
725
726 /* Set up kx struct */
727 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
729 kx->mq = mq;
730 GNUNET_memcpy (&kx->peer, peer_id, sizeof (struct GNUNET_PeerIdentity));
732
733 restart_kx (kx);
734 return kx;
735}

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

Referenced by GSC_KX_init().

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 784 of file gnunet-service-core_kx.c.

788{
789 uint64_t ret;
790
791 ret = GNUNET_CRYPTO_hkdf_extract (es, // prk
792 0, // salt
793 0, // salt_len
794 ss_R, // ikm - initial key material
795 sizeof (*ss_R));
796 if (GNUNET_OK != ret)
797 {
798 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting ES\n")
799 ;
800 GNUNET_assert (0);
801 }
803 ets,
804 sizeof (*ets),
805 es,
808 GNUNET_CRYPTO_kdf_arg_auto (transcript));
809 if (GNUNET_OK != ret)
810 {
811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
812 ;
813 GNUNET_assert (0);
814 }
815}

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 823 of file gnunet-service-core_kx.c.

826{
829 sn,
830 sn_len,
831 secret,
834}

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 842 of file gnunet-service-core_kx.c.

845{
846 uint64_t ret;
847 struct GNUNET_ShortHashCode derived_early_secret;
848
849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deriving HS\n");
851 );
852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ss_e: %s\n", GNUNET_B2S (ss_e));
854 &derived_early_secret,
855 sizeof (derived_early_secret),
856 es,
860 derived_early_secret));
861 if (GNUNET_OK != ret)
862 {
863 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dES\n")
864 ;
865 GNUNET_assert (0);
866 }
867 // Handshake secret
868 // TODO check: are dES the salt and ss_e the ikm or other way round?
869 ret = GNUNET_CRYPTO_hkdf_extract (handshake_secret, // prk
870 &derived_early_secret, // salt - dES
871 sizeof (derived_early_secret), // salt_len
872 ss_e, // ikm - initial key material
873 sizeof (*ss_e));
874 if (GNUNET_OK != ret)
875 {
876 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting HS\n")
877 ;
878 GNUNET_assert (0);
879 }
880}

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 888 of file gnunet-service-core_kx.c.

891{
894 ihts, // result
895 sizeof (*ihts), // result len
896 hs, // prk?
899 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
900}

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 908 of file gnunet-service-core_kx.c.

911{
914 rhts,
915 sizeof (*rhts),
916 hs, // prk? TODO
919 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
920}

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 928 of file gnunet-service-core_kx.c.

931{
932 uint64_t ret;
933 struct GNUNET_ShortHashCode derived_handshake_secret;
934
936 &derived_handshake_secret,
937 sizeof (derived_handshake_secret),
938 hs,
941 if (GNUNET_OK != ret)
942 {
943 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dHS\n")
944 ;
945 GNUNET_assert (0);
946 }
947 // TODO check: are dHS the salt and ss_I the ikm or other way round?
948 ret = GNUNET_CRYPTO_hkdf_extract (ms, // prk
949 &derived_handshake_secret, // salt - dHS
950 sizeof (derived_handshake_secret), // salt_len
951 ss_I, // ikm - initial key material
952 sizeof (*ss_I));
953 if (GNUNET_OK != ret)
954 {
955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting MS\n")
956 ;
957 GNUNET_assert (0);
958 }
959}

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 968 of file gnunet-service-core_kx.c.

972{
973 uint64_t seq_nbo;
974 uint64_t *write_iv_ptr;
975 unsigned int byte_offset;
976
977 seq_nbo = GNUNET_htonll (seq);
978 memcpy (per_record_write_iv,
979 write_iv,
981 byte_offset =
982 AEAD_NONCE_BYTES - sizeof (uint64_t);
983 write_iv_ptr = (uint64_t*) (write_iv + byte_offset);
984 *write_iv_ptr ^= seq_nbo;
985}

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 993 of file gnunet-service-core_kx.c.

998{
999 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
1000 /* derive actual key */
1003 key,
1005 ts,
1008
1009 /* derive nonce */
1012 nonce_tmp,
1014 ts,
1018 nonce_tmp,
1019 nonce);
1020}

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 1028 of file gnunet-service-core_kx.c.

1030{
1031 int8_t ret;
1032
1033 // FIXME: Not sure of PRK and output may overlap here!
1035 new_ats,
1036 sizeof (*new_ats),
1037 old_ats,
1040 if (GNUNET_OK != ret)
1041 {
1043 "Something went wrong deriving next *ATS key\n");
1044 GNUNET_assert (0);
1045 }
1046}

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 1054 of file gnunet-service-core_kx.c.

1058{
1059 const char *traffic_str;
1060
1061 if (ROLE_INITIATOR == role)
1062 traffic_str = I_AP_TRAFFIC_STR;
1063 else
1064 traffic_str = R_AP_TRAFFIC_STR;
1067 initial_ats, // result
1068 sizeof (*initial_ats), // result len
1069 ms,
1071 GNUNET_CRYPTO_kdf_arg_string (traffic_str),
1072 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
1073}

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 1083 of file gnunet-service-core_kx.c.

1086{
1088 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1089
1091 &fk_R, // result
1092 sizeof (fk_R),
1093 ms,
1096 if (GNUNET_OK != ret)
1097 {
1099 "Something went wrong expanding fk_R\n");
1100 GNUNET_assert (0);
1101 }
1102
1103 GNUNET_CRYPTO_hmac (&fk_R,
1104 transcript,
1105 sizeof (*transcript),
1106 result);
1107}

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 1117 of file gnunet-service-core_kx.c.

1120{
1122 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1123
1125 &fk_I, // result
1126 sizeof (fk_I),
1127 ms,
1130 if (GNUNET_OK != ret)
1131 {
1133 "Something went wrong expanding fk_I\n");
1134 GNUNET_assert (0);
1135 }
1136 GNUNET_CRYPTO_hmac (&fk_I,
1137 transcript,
1138 sizeof (*transcript),
1139 result);
1140}

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 1151 of file gnunet-service-core_kx.c.

1152{
1153 struct GSC_KeyExchangeInfo *kx = cls;
1154
1155 kx->resend_task = NULL;
1156 if (0 == kx->resend_tries_left)
1157 {
1159 "Restarting KX\n");
1160 restart_kx (kx);
1161 return;
1162 }
1163 kx->resend_tries_left--;
1165 "Resending responder hello. Retries left: %u\n",
1166 kx->resend_tries_left);
1170 kx);
1171}

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 1175 of file gnunet-service-core_kx.c.

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

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_QUALITY_NONCE, 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, 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 1396 of file gnunet-service-core_kx.c.

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

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_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, GSC_my_identity, 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, 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 1520 of file gnunet-service-core_kx.c.

1521{
1522 uint16_t size = ntohs (m->header.size);
1523
1524 if (size < sizeof (*m)
1525 + sizeof (struct InitiatorHelloPayload)
1527 {
1528 return GNUNET_SYSERR;
1529 }
1530 return GNUNET_OK;
1531}

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 1543 of file gnunet-service-core_kx.c.

1544{
1545 struct GSC_KeyExchangeInfo *kx = cls;
1546 struct GNUNET_HashCode hash_compare = { 0 };
1547 struct InitiatorHelloCtx *initiator_hello_cls;
1548 size_t ihm_len;
1549
1550 if (ROLE_INITIATOR == kx->role)
1551 {
1552 GNUNET_break_op (0);
1554 "I am an initiator! Tearing down...\n");
1555 return;
1556 }
1558 {
1559 GNUNET_break_op (0);
1561 "Already received InitiatorHello)\n");
1562 return;
1563 }
1564 GNUNET_assert (NULL == kx->transcript_hash_ctx); // FIXME this triggers sometimes - why?
1567
1568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorHello\n");
1570 gettext_noop ("# key exchanges initiated"),
1571 1,
1572 GNUNET_NO);
1573
1575
1576 // 1. verify type _INITIATOR_HELLO
1577 // - This is implicytly done by arriving within this handler
1578 // - or is this about verifying the 'additional data' part of aead?
1579 // should it check the encryption + mac? (is this implicitly done
1580 // while decrypting?)
1581 // 2. verify H(pk_R) matches pk_R
1583 sizeof (struct GNUNET_PeerIdentity),
1584 &hash_compare); /* result */
1585 if (0 != memcmp (&ihm_e->h_pk_R,
1586 &hash_compare,
1587 sizeof (struct GNUNET_HashCode)))
1588 {
1590 "This message is not meant for us (H(PID) mismatch)\n");
1592 kx->transcript_hash_ctx = NULL;
1593 return;
1594 }
1595 // FIXME this sometimes triggers in the tests - why?
1596 // 3. decaps -> shared_secret_R, c_R (kemChallenge)
1597 ihm_len = ntohs (ihm_e->header.size);
1598 initiator_hello_cls = GNUNET_new (struct InitiatorHelloCtx);
1599 initiator_hello_cls->kx = kx;
1600 initiator_hello_cls->ihm_e = GNUNET_malloc (ihm_len);
1601 GNUNET_memcpy (initiator_hello_cls->ihm_e, ihm_e, ihm_len);
1602 initiator_hello_cls->req = GNUNET_new (struct PilsRequest);
1605 initiator_hello_cls->req);
1606 initiator_hello_cls->req->op =
1608 &ihm_e->c_R,
1609 // encapsulated key
1611 // continuation
1612 initiator_hello_cls);
1613}

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(), 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_kem_decaps(), GNUNET_STATISTICS_update(), GSC_my_identity, GSC_stats, InitiatorHello::h_pk_R, handle_initiator_hello_cont(), InitiatorHello::header, InitiatorHelloCtx::ihm_e, InitiatorHelloCtx::kx, PilsRequest::op, pils, 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 1654 of file gnunet-service-core_kx.c.

1655{
1656 struct GSC_KeyExchangeInfo *kx = cls;
1657
1658 kx->resend_task = NULL;
1659 if (0 == kx->resend_tries_left)
1660 {
1662 "Restarting KX\n");
1663 restart_kx (kx);
1664 return;
1665 }
1666 kx->resend_tries_left--;
1668 "Resending initiator done. Retries left: %u\n",
1669 kx->resend_tries_left);
1673 kx);
1674}

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 1678 of file gnunet-service-core_kx.c.

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

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, 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 1858 of file gnunet-service-core_kx.c.

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

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 1879 of file gnunet-service-core_kx.c.

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

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_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_new, GNUNET_OK, GNUNET_PILS_kem_decaps(), GNUNET_SCHEDULER_cancel(), handle_responder_hello_cont(), ResponderHelloCls::hc, ResponderHello::header, ResponderHelloCls::hs, ResponderHelloCls::ihts, ResponderHelloCls::kx, PilsRequest::op, pils, 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, 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 2039 of file gnunet-service-core_kx.c.

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

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 2057 of file gnunet-service-core_kx.c.

2058{
2059 struct GSC_KeyExchangeInfo *kx = cls;
2060 struct InitiatorDone idm_local;
2061 struct InitiatorDone *idm_p = &idm_local; /* plaintext */
2062 struct GNUNET_HashCode initiator_finished;
2063 struct GNUNET_HashCode transcript;
2064 struct GNUNET_ShortHashCode their_ats;
2065 struct GNUNET_HashContext *hc;
2066 unsigned char enc_key[AEAD_KEY_BYTES];
2067 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2068 struct ConfirmationAck ack_i;
2069 struct ConfirmationAck ack_r;
2070 int8_t ret;
2071
2072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorDone\n");
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 (int 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],
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);
2555 GNUNET_MST_destroy (kx->mst);
2556 GNUNET_free (kx);
2557}

References gettext_noop, GNUNET_CONTAINER_DLL_remove, GNUNET_CORE_KX_PEER_DISCONNECT, 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, and GSC_KeyExchangeInfo::status.

Referenced by GSC_KX_init().

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 2561 of file gnunet-service-core_kx.c.

2562{
2563 struct GSC_KeyExchangeInfo *kx = cls;
2564
2565 kx->resend_task = NULL;
2567 "Resending initiator hello.\n");
2569 // FIXME (Exponential) backoff?
2572 kx);
2573}

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 2701 of file gnunet-service-core_kx.c.

2702{
2703 struct GNUNET_ShortHashCode new_ats;
2704
2705 if ((UINT64_MAX == kx->current_sqn) ||
2707 {
2709 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2710 ", incrementing epoch...\n",
2712 kx->current_sqn);
2713 // Can this trigger? Maybe if we receive a lot of
2714 // heartbeats?
2715 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2716 kx->current_epoch++;
2719 kx->current_sqn = 0;
2721 &new_ats);
2722 memcpy (&kx->current_ats,
2723 &new_ats,
2724 sizeof new_ats);
2725 }
2726}

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 2736 of file gnunet-service-core_kx.c.

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

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:

◆ peer_id_change_cb()

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

Callback for PILS to be called once the peer id changes.

Parameters
clsunused
peer_idthe new peer id
hashthe hash of the addresses corresponding to the fed addresses

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

2836{
2837 (void) cls;
2839 // TODO check that hash matches last fed hash
2841 "This peer has now a new peer id: %s\n",
2843 // TODO if changing from old peer_id to new peer_id: tear down old
2844 // connections, try restart connections over kept addresses?
2845 /* Continue initialisation of core */
2846 if (GNUNET_YES == init_phase)
2847 {
2850 }
2851}

References GNUNET_ERROR_TYPE_INFO, GNUNET_HELLO_parser_get_id(), GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_YES, GSC_complete_initialization_cb(), GSC_my_identity, and init_phase.

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 2860 of file gnunet-service-core_kx.c.

2861{
2863 GNUNET_MQ_hd_var_size (initiator_hello,
2865 struct InitiatorHello,
2866 NULL),
2867 GNUNET_MQ_hd_var_size (initiator_done,
2869 struct InitiatorDone,
2870 NULL),
2871 GNUNET_MQ_hd_var_size (responder_hello,
2873 struct ResponderHello,
2874 NULL),
2875 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2877 struct EncryptedMessage,
2878 NULL),
2880 };
2881
2885 NULL); // TODO potentially wait
2886 // until we have a peer_id?
2887 // pay attention to whether
2888 // we have one anyways
2889 if (NULL == pils)
2890 {
2891 GSC_KX_done ();
2892 return GNUNET_SYSERR;
2893 }
2894
2896 transport =
2899 handlers,
2900 NULL, // cls - this connection-independant
2901 // cls seems not to be needed.
2902 // the connection-specific cls
2903 // will be set as a return value
2904 // of
2905 // handle_transport_notify_connect
2908 if (NULL == transport)
2909 {
2910 GSC_KX_done ();
2911 return GNUNET_SYSERR;
2912 }
2914 "Connected to TRANSPORT\n");
2915 return GNUNET_OK;
2916}

References 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_OK, GNUNET_PILS_connect(), GNUNET_SYSERR, GNUNET_TRANSPORT_core_connect(), GNUNET_YES, GSC_cfg, GSC_KX_done(), GSC_my_identity, handle_transport_notify_connect(), handle_transport_notify_disconnect(), handlers, init_phase, nc, peer_id_change_cb(), pils, and transport.

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 2923 of file gnunet-service-core_kx.c.

2924{
2925 struct PilsRequest *pr;
2926 while (NULL != (pr = pils_requests_head))
2927 {
2930 pr);
2931 if (NULL != pr->op)
2932 GNUNET_PILS_cancel (pr->op);
2933 GNUNET_free (pr);
2934 }
2935 if (NULL != pils)
2936 {
2938 pils = NULL;
2939 }
2940 if (NULL != transport)
2941 {
2943 transport = NULL;
2944 }
2945 if (NULL != rekey_task)
2946 {
2948 rekey_task = NULL;
2949 }
2950 if (NULL != nc)
2951 {
2953 nc = NULL;
2954 }
2955}

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

Referenced by GSC_KX_init(), 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 2965 of file gnunet-service-core_kx.c.

2966{
2967 return GNUNET_MQ_get_length (kxinfo->mq);
2968}

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 2972 of file gnunet-service-core_kx.c.

2973{
2974 return kxinfo->has_excess_bandwidth;
2975}

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 2987 of file gnunet-service-core_kx.c.

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

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

◆ pils

struct GNUNET_PILS_Handle* pils
static

Pils service.

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

Referenced by GSC_KX_done(), GSC_KX_init(), handle_initiator_hello(), and handle_responder_hello().

◆ 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 435 of file gnunet-service-core_kx.c.

Referenced by GSC_KX_done().

◆ nc

◆ init_phase

enum GNUNET_GenericReturnValue init_phase
static

Indicates whether we are still in the initialisation phase (waiting for our peer id).

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

Referenced by GSC_KX_init(), and peer_id_change_cb().

◆ my_services_info

char* my_services_info = ""
static

Our services info string TODO.

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

Referenced by send_initiator_hello(), and send_responder_hello().