GNUnet debian-0.24.3-29-g453fda2cf
 
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   1
 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   1

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, // result
803 sizeof (*ets), // result len
804 es,
805 CAKE_LABEL, strlen (CAKE_LABEL),
807 transcript,
808 sizeof (*transcript),
809 NULL, 0);
810 if (GNUNET_OK != ret)
811 {
812 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
813 ;
814 GNUNET_assert (0);
815 }
816}
817
818
819/*
820 * Derive early secret and transport secret.
821 * @param kx the key exchange info
822 */
823static void
824derive_sn (const struct GNUNET_ShortHashCode *secret,
825 unsigned char*sn,
826 size_t sn_len)
827{
829 GNUNET_CRYPTO_hkdf_expand (sn, // result
830 sn_len,
831 secret,
832 CAKE_LABEL, strlen (CAKE_LABEL),
833 "sn", strlen ("sn"),
834 NULL));
835}
836
837
842static void
843derive_hs (const struct GNUNET_ShortHashCode *es,
844 const struct GNUNET_ShortHashCode *ss_e,
846{
847 uint64_t ret;
848 struct GNUNET_ShortHashCode derived_early_secret;
849
850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deriving HS\n");
852 );
853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ss_e: %s\n", GNUNET_B2S (ss_e));
854 ret = GNUNET_CRYPTO_hkdf_expand (&derived_early_secret, // result
855 sizeof (derived_early_secret),
856 es,
857 CAKE_LABEL, strlen (CAKE_LABEL),
858 DERIVED_STR, strlen (DERIVED_STR),
859 NULL);
861 derived_early_secret));
862 if (GNUNET_OK != ret)
863 {
864 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dES\n")
865 ;
866 GNUNET_assert (0);
867 }
868 // Handshake secret
869 // TODO check: are dES the salt and ss_e the ikm or other way round?
870 ret = GNUNET_CRYPTO_hkdf_extract (handshake_secret, // prk
871 &derived_early_secret, // salt - dES
872 sizeof (derived_early_secret), // salt_len
873 ss_e, // ikm - initial key material
874 sizeof (*ss_e));
875 if (GNUNET_OK != ret)
876 {
877 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting HS\n")
878 ;
879 GNUNET_assert (0);
880 }
881}
882
883
888static void
889derive_ihts (const struct GNUNET_HashCode *transcript,
890 const struct GNUNET_ShortHashCode *hs,
891 struct GNUNET_ShortHashCode *ihts)
892{
894 GNUNET_CRYPTO_hkdf_expand (ihts, // result
895 sizeof (*ihts), // result len
896 hs, // prk?
897 CAKE_LABEL, strlen (CAKE_LABEL),
899 strlen (I_HS_TRAFFIC_STR),
900 transcript,
901 sizeof (*transcript),
902 NULL));
903}
904
905
910static void
911derive_rhts (const struct GNUNET_HashCode *transcript,
912 const struct GNUNET_ShortHashCode *hs,
913 struct GNUNET_ShortHashCode *rhts)
914{
916 GNUNET_CRYPTO_hkdf_expand (rhts, // result
917 sizeof (*rhts), // result len
918 hs, // prk? TODO
919 CAKE_LABEL, strlen (CAKE_LABEL),
921 strlen (R_HS_TRAFFIC_STR),
922 transcript,
923 sizeof (*transcript),
924 NULL));
925}
926
927
932static void
933derive_ms (const struct GNUNET_ShortHashCode *hs,
934 const struct GNUNET_ShortHashCode *ss_I,
935 struct GNUNET_ShortHashCode *ms)
936{
937 uint64_t ret;
938 struct GNUNET_ShortHashCode derived_handshake_secret;
939
940 ret = GNUNET_CRYPTO_hkdf_expand (&derived_handshake_secret, // result
941 sizeof (derived_handshake_secret), // result len
942 hs, // prk? TODO
943 CAKE_LABEL, strlen (CAKE_LABEL),
944 DERIVED_STR, strlen (DERIVED_STR),
945 NULL);
946 if (GNUNET_OK != ret)
947 {
948 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dHS\n")
949 ;
950 GNUNET_assert (0);
951 }
952 // TODO check: are dHS the salt and ss_I the ikm or other way round?
953 ret = GNUNET_CRYPTO_hkdf_extract (ms, // prk
954 &derived_handshake_secret, // salt - dHS
955 sizeof (derived_handshake_secret), // salt_len
956 ss_I, // ikm - initial key material
957 sizeof (*ss_I));
958 if (GNUNET_OK != ret)
959 {
960 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting MS\n")
961 ;
962 GNUNET_assert (0);
963 }
964}
965
966
972static void
974 uint64_t seq,
975 const uint8_t write_iv[AEAD_NONCE_BYTES],
976 uint8_t per_record_write_iv[AEAD_NONCE_BYTES])
977{
978 uint64_t seq_nbo;
979 uint64_t *write_iv_ptr;
980 unsigned int byte_offset;
981
982 seq_nbo = GNUNET_htonll (seq);
983 memcpy (per_record_write_iv,
984 write_iv,
986 byte_offset =
987 AEAD_NONCE_BYTES - sizeof (uint64_t);
988 write_iv_ptr = (uint64_t*) (write_iv + byte_offset);
989 *write_iv_ptr ^= seq_nbo;
990}
991
992
997static void
999 const struct GNUNET_ShortHashCode *ts,
1000 uint64_t seq,
1001 unsigned char key[AEAD_KEY_BYTES],
1002 unsigned char nonce[AEAD_NONCE_BYTES])
1003{
1004 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
1005 /* derive actual key */
1009 ts,
1010 CAKE_LABEL, strlen (CAKE_LABEL),
1011 KEY_STR,
1012 strlen (KEY_STR),
1013 NULL));
1014
1015 /* derive nonce */
1017 GNUNET_CRYPTO_hkdf_expand (nonce_tmp,
1019 ts,
1020 CAKE_LABEL, strlen (CAKE_LABEL),
1021 IV_STR,
1022 strlen (IV_STR),
1023 NULL));
1025 nonce_tmp,
1026 nonce);
1027}
1028
1029
1034static void
1035derive_next_ats (const struct GNUNET_ShortHashCode *old_ats,
1036 struct GNUNET_ShortHashCode *new_ats)
1037{
1038 int8_t ret;
1039
1040 // FIXME: Not sure of PRK and output may overlap here!
1041 ret = GNUNET_CRYPTO_hkdf_expand (new_ats, // result
1042 sizeof (*new_ats), // result len
1043 old_ats,
1044 CAKE_LABEL, strlen (CAKE_LABEL),
1046 NULL);
1047 if (GNUNET_OK != ret)
1048 {
1050 "Something went wrong deriving next *ATS key\n");
1051 GNUNET_assert (0);
1052 }
1053}
1054
1055
1060static void
1061derive_initial_ats (const struct GNUNET_HashCode *transcript,
1062 const struct GNUNET_ShortHashCode *ms,
1063 enum GSC_KX_Role role,
1064 struct GNUNET_ShortHashCode *initial_ats)
1065{
1066 const char *traffic_str;
1067
1068 if (ROLE_INITIATOR == role)
1069 traffic_str = I_AP_TRAFFIC_STR;
1070 else
1071 traffic_str = R_AP_TRAFFIC_STR;
1073 GNUNET_CRYPTO_hkdf_expand (initial_ats, // result
1074 sizeof (*initial_ats), // result len
1075 ms,
1076 CAKE_LABEL, strlen (CAKE_LABEL),
1077 traffic_str,
1078 strlen (traffic_str),
1079 transcript,
1080 sizeof (*transcript),
1081 NULL));
1082}
1083
1084
1091static void
1092generate_responder_finished (const struct GNUNET_HashCode *transcript,
1093 const struct GNUNET_ShortHashCode *ms,
1094 struct GNUNET_HashCode *result)
1095{
1097 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1098
1099 ret = GNUNET_CRYPTO_hkdf_expand (&fk_R, // result
1100 sizeof (fk_R),
1101 ms,
1102 CAKE_LABEL, strlen (CAKE_LABEL),
1104 NULL);
1105 if (GNUNET_OK != ret)
1106 {
1108 "Something went wrong expanding fk_R\n");
1109 GNUNET_assert (0);
1110 }
1111
1112 GNUNET_CRYPTO_hmac (&fk_R,
1113 transcript,
1114 sizeof (*transcript),
1115 result);
1116}
1117
1118
1125static void
1126generate_initiator_finished (const struct GNUNET_HashCode *transcript,
1127 const struct GNUNET_ShortHashCode *ms,
1128 struct GNUNET_HashCode *result)
1129{
1131 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1132
1133 ret = GNUNET_CRYPTO_hkdf_expand (&fk_I, // result
1134 sizeof (fk_I),
1135 ms,
1136 CAKE_LABEL, strlen (CAKE_LABEL),
1138 NULL);
1139 if (GNUNET_OK != ret)
1140 {
1142 "Something went wrong expanding fk_I\n");
1143 GNUNET_assert (0);
1144 }
1145 GNUNET_CRYPTO_hmac (&fk_I,
1146 transcript,
1147 sizeof (*transcript),
1148 result);
1149}
1150
1151
1152struct InitiatorHelloCtx
1153{
1154 struct GSC_KeyExchangeInfo *kx;
1155 struct InitiatorHello *ihm_e;
1156 struct PilsRequest *req;
1157};
1158
1159static void
1160resend_responder_hello (void *cls)
1161{
1162 struct GSC_KeyExchangeInfo *kx = cls;
1163
1164 kx->resend_task = NULL;
1165 if (0 == kx->resend_tries_left)
1166 {
1168 "Restarting KX\n");
1169 restart_kx (kx);
1170 return;
1171 }
1172 kx->resend_tries_left--;
1174 "Resending responder hello. Retries left: %u\n",
1175 kx->resend_tries_left);
1179 kx);
1180}
1181
1182
1183void
1185{
1188 struct ResponderHello *rhm_e; /* responder hello message - encrypted pointer */
1189 struct GNUNET_MQ_Envelope *env;
1190 struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_kem_challenge;
1191 struct GNUNET_ShortHashCode rhts;
1192 struct GNUNET_ShortHashCode ihts;
1193 struct GNUNET_ShortHashCode hs;
1194 struct GNUNET_ShortHashCode ms;
1195 struct GNUNET_ShortHashCode ss_e;
1196 struct GNUNET_ShortHashCode ss_I;
1197 struct GNUNET_HashContext *hc;
1198 unsigned char enc_key[AEAD_KEY_BYTES];
1199 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1200
1201 // 4. encaps -> shared_secret_e, c_e (kemChallenge)
1202 // TODO potentially write this directly into rhm?
1203 ret = GNUNET_CRYPTO_hpke_kem_encaps (&kx->pk_e, // public ephemeral key of initiator
1204 &ephemeral_kem_challenge, // encapsulated key
1205 &ss_e); // key - ss_e
1206 if (GNUNET_OK != ret)
1207 {
1209 "Something went wrong encapsulating ss_e\n");
1210 return;
1211 }
1213 // 6. encaps -> shared_secret_I, c_I
1214 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public key of I
1215 &c_I, // encapsulated key
1216 &ss_I); // where to write the key material
1217 if (GNUNET_OK != ret)
1218 {
1220 "Something went wrong encapsulating ss_I\n");
1222 return;
1223 }
1224 // 7. generate RHTS (responder_handshare_secret_key) and RATS (responder_application_traffic_secret_key) (section 5)
1225 {
1226 struct GNUNET_HashCode transcript;
1227 snapshot_transcript (hc, &transcript);
1228#if DEBUG_KX
1230 "Transcript snapshot for derivation of HS, MS: `%s'\n",
1231 GNUNET_h2s (&transcript));
1232#endif
1234 &ss_e,
1235 &hs);
1236 derive_ms (&hs, &ss_I, &ms);
1237 }
1238
1239 // send ResponderHello
1240 // TODO fill fields / services_info!
1241 // 1. r_R <- random
1242 struct ResponderHelloPayload *rhp;
1243 size_t rhp_len = sizeof (*rhp) + strlen (my_services_info);
1244 unsigned char rhp_buf[rhp_len];
1245 size_t ct_len;
1246
1247 rhp = (struct ResponderHelloPayload*) rhp_buf;
1248 ct_len = rhp_len // ResponderHelloPayload, fist PT msg
1249 + sizeof (struct GNUNET_HashCode) // Finished hash, second PT msg
1250 + AEAD_TAG_BYTES * 2; // Two tags;
1251 env = GNUNET_MQ_msg_extra (rhm_e,
1252 ct_len,
1254
1255 rhm_e->r_R =
1257 UINT64_MAX);
1258
1259 // c_e
1260 GNUNET_memcpy (&rhm_e->c_e,
1261 &ephemeral_kem_challenge,
1262 sizeof (ephemeral_kem_challenge));
1264 rhm_e,
1265 sizeof (struct ResponderHello));
1266 // 2. Encrypt ServicesInfo and c_I with RHTS
1267 // derive RHTS
1268 {
1269 struct GNUNET_HashCode transcript;
1271 &transcript);
1272#if DEBUG_KX
1274 "Transcript snapshot for derivation of *HTS: `%s'\n",
1275 GNUNET_h2s (&transcript));
1276#endif
1277 derive_rhts (&transcript,
1278 &hs,
1279 &rhts);
1280 derive_ihts (&transcript,
1281 &hs,
1282 &ihts);
1284 0,
1285 enc_key,
1286 enc_nonce);
1287 }
1288 // c_I
1289 GNUNET_memcpy (&rhp->c_I, &c_I, sizeof (c_I));
1290 // Services info empty for now.
1291 GNUNET_memcpy (&rhp[1],
1293 strlen (my_services_info));
1294
1295 {
1296 unsigned long long out_ct_len;
1298 struct GNUNET_HashCode transcript;
1299 unsigned char *finished_buf;
1300 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1301 (unsigned char*) &rhm_e[1], /* c - ciphertext */
1302 &out_ct_len, /* clen_p */
1303 rhp_buf, /* rhm_p - plaintext message */
1304 rhp_len, // mlen
1305 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1306 // fields?
1307 NULL, // nsec - unused
1308 enc_nonce, // npub - nonce // FIXME nonce can be reused
1309 enc_key)); // k - key RHTS
1311 "Encrypted and wrote %llu bytes\n",
1312 out_ct_len);
1313 // 3. Create ResponderFinished (Section 6)
1314 // Derive fk_I <- HKDF-Expand (MS, "r finished", NULL)
1315 /* Forward the transcript */
1316 /* {svcinfo, c_I}RHTS */
1318 hc,
1319 &rhm_e[1],
1320 out_ct_len);
1321
1322 finished_buf = ((unsigned char*) &rhm_e[1]) + out_ct_len;
1324 &transcript);
1325#if DEBUG_KX
1327 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1328 GNUNET_h2s (&transcript));
1329#endif
1330 generate_responder_finished (&transcript,
1331 &ms,
1332 &finished);
1333 // 4. Encrypt ResponderFinished
1335 1,
1336 enc_key,
1337 enc_nonce);
1338 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1339 finished_buf, /* c - ciphertext */
1340 &out_ct_len, /* clen_p */
1341 (unsigned char*) &finished, /* rhm_p - plaintext message */
1342 sizeof (finished), // mlen
1343 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1344 // fields?
1345 NULL, // nsec - unused
1346 enc_nonce, // npub
1347 enc_key)); // k - key RHTS
1349 "Encrypted and wrote %llu bytes\n",
1350 out_ct_len);
1351 /* Forward the transcript
1352 * after responder finished,
1353 * before deriving *ATS and generating finished_I
1354 * (finished_I will be generated when receiving the InitiatorFinished message
1355 * in order to check it) */
1357 hc,
1358 finished_buf,
1359 out_ct_len);
1360 // 5. optionally send application data - encrypted with RATS
1361 // We do not really have any application data, instead, we send the ACK
1363 &transcript);
1364#if DEBUG_KX
1366 "Transcript snapshot for derivation of *ATS: `%s'\n",
1367 GNUNET_h2s (&transcript));
1368#endif
1369 derive_initial_ats (&transcript,
1370 &ms,
1372 &kx->current_ats);
1373 }
1374 /* Lock into struct */
1376 kx->transcript_hash_ctx = hc;
1377 kx->master_secret = ms;
1378 kx->handshake_secret = hs;
1379 kx->ss_e = ss_e;
1380 kx->ihts = ihts;
1381 kx->rhts = rhts;
1382 kx->ss_I = ss_I;
1383 kx->current_epoch = 0;
1384 kx->current_sqn = 0;
1386 kx->current_sqn,
1387 enc_key,
1388 enc_nonce);
1389
1390 GNUNET_MQ_send_copy (kx->mq, env);
1391 kx->resend_env = env;
1393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent ResponderHello\n");
1394
1397 kx);
1399 monitor_notify_all (kx);
1400 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1401}
1402
1403
1404static void
1405handle_initiator_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_R)
1406{
1407 struct InitiatorHelloCtx *ihm_ctx = cls;
1408 struct GSC_KeyExchangeInfo *kx = ihm_ctx->kx;
1409 uint32_t ihm_len = ntohs (ihm_ctx->ihm_e->header.size);
1410 unsigned char enc_key[AEAD_KEY_BYTES];
1411 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1412 struct GNUNET_HashCode h1;
1413 struct GNUNET_HashCode h2;
1414 struct GNUNET_HashCode transcript;
1415 struct GNUNET_ShortHashCode es;
1416 struct GNUNET_ShortHashCode ets;
1418
1419 ihm_ctx->req->op = NULL;
1422 ihm_ctx->req);
1423 GNUNET_free (ihm_ctx->req);
1424
1425
1426 GNUNET_memcpy (&kx->pk_e,
1427 &ihm_ctx->ihm_e->pk_e,
1428 sizeof (ihm_ctx->ihm_e->pk_e));
1429 // 5. generate ETS (early_traffic_secret_key, decrypt pk_i
1430 // expand ETS <- expand ES <- extract ss_R
1431 // use ETS to decrypt
1432
1433 /* Forward the transcript hash context over the unencrypted fields to get it
1434 * to the same status that the initiator had when it needed to derive es and
1435 * ets for the encryption */
1438 ihm_ctx->ihm_e,
1439 sizeof (struct InitiatorHello));
1441 &transcript);
1442#if DEBUG_KX
1444 "Transcript snapshot for derivation of ES, ETS: `%s'\n",
1445 GNUNET_h2s (&transcript));
1446#endif
1447 derive_es_ets (&transcript, ss_R, &es, &ets);
1449 0,
1450 enc_key,
1451 enc_nonce);
1452 {
1453 struct InitiatorHelloPayload *ihmp;
1454 size_t ct_len = ihm_len - sizeof (struct InitiatorHello);
1455 unsigned char ihmp_buf[ct_len - AEAD_TAG_BYTES];
1456 ihmp = (struct InitiatorHelloPayload*) ihmp_buf;
1457 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1458 ihmp_buf, // unsigned char *m
1459 NULL, // mlen_p message length
1460 NULL, // unsigned char *nsec - unused: NULL
1461 (unsigned char*) &ihm_ctx->ihm_e[1], // const unsigned char *c - cyphertext
1462 ct_len, // unsigned long long clen - length of cyphertext
1463 // mac, // const unsigned char *mac - authentication tag
1464 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1465 0, // unsigned long long adlen
1466 enc_nonce, // const unsigned char *npub - nonce
1467 enc_key // const unsigned char *k - key
1468 );
1469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pid_sender: %s\n",
1470 GNUNET_i2s (&ihmp->pk_I));
1471 if (0 != ret)
1472 {
1474 "Something went wrong decrypting: %d\n", ret);
1475 GNUNET_break_op (0);
1476 GNUNET_free (ihm_ctx->ihm_e);
1477 GNUNET_free (ihm_ctx);
1479 kx->transcript_hash_ctx = NULL;
1480 return;
1481 }
1482 /* now forward it considering the encrypted messages that the initiator was
1483 * able to send after deriving the es and ets */
1485 &ihm_ctx->ihm_e[1],
1486 ct_len);
1487 GNUNET_memcpy (&kx->peer,
1488 &ihmp->pk_I,
1489 sizeof (struct GNUNET_PeerIdentity));
1490 }
1491 // We could follow with the rest of the Key Schedule (dES, HS, ...) for now
1492 /* Check that we are actually in the receiving role */
1493 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
1495 sizeof(struct GNUNET_PeerIdentity),
1496 &h2);
1497 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, &h2))
1498 {
1499 /* peer with "lower" identity starts KX, otherwise we typically end up
1500 with both peers starting the exchange and transmit the 'set key'
1501 message twice */
1502 /* Something went wrong - we have the lower value and should have sent the
1503 * InitiatorHello, but instead received it. TODO handle this case
1504 * We might end up in this case if the initiator didn't initiate the
1505 * handshake long enough and the 'responder' initiates the handshake */
1507 "Something went wrong - we have the lower value and should have sent the InitiatorHello, but instead received it.\n");
1508 GNUNET_free (ihm_ctx->ihm_e);
1509 GNUNET_free (ihm_ctx);
1511 kx->transcript_hash_ctx = NULL;
1512 return;
1513 }
1514
1515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer ID of other peer: %s\n", GNUNET_i2s
1516 (&kx->peer));
1517 /* We update the monitoring peers here because now we know
1518 * that we can decrypt the message AND know the PID
1519 */
1520 monitor_notify_all (kx);
1521 kx->ss_R = *ss_R;
1522 kx->early_secret_key = es;
1523 kx->early_traffic_secret = ets;
1525}
1526
1527
1528static int
1529check_initiator_hello (void *cls, const struct InitiatorHello *m)
1530{
1531 uint16_t size = ntohs (m->header.size);
1532
1533 if (size < sizeof (*m)
1534 + sizeof (struct InitiatorHelloPayload)
1536 {
1537 return GNUNET_SYSERR;
1538 }
1539 return GNUNET_OK;
1540}
1541
1542
1551static void
1552handle_initiator_hello (void *cls, const struct InitiatorHello *ihm_e)
1553{
1554 struct GSC_KeyExchangeInfo *kx = cls;
1555 struct GNUNET_HashCode hash_compare;
1556 struct InitiatorHelloCtx *initiator_hello_cls;
1557 size_t ihm_len;
1558
1559 if (ROLE_INITIATOR == kx->role)
1560 {
1561 GNUNET_break_op (0);
1563 "I am an initiator! Tearing down...\n");
1564 return;
1565 }
1567 {
1568 GNUNET_break_op (0);
1570 "Already received InitiatorHello)\n");
1571 return;
1572 }
1573 GNUNET_assert (NULL == kx->transcript_hash_ctx); // FIXME this triggers sometimes - why?
1576
1577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorHello\n");
1579 gettext_noop ("# key exchanges initiated"),
1580 1,
1581 GNUNET_NO);
1582
1584
1585 // 1. verify type _INITIATOR_HELLO
1586 // - This is implicytly done by arriving within this handler
1587 // - or is this about verifying the 'additional data' part of aead?
1588 // should it check the encryption + mac? (is this implicitly done
1589 // while decrypting?)
1590 // 2. verify H(pk_R) matches pk_R
1592 sizeof (struct GNUNET_PeerIdentity),
1593 &hash_compare); /* result */
1594 if (0 != memcmp (&ihm_e->h_pk_R,
1595 &hash_compare,
1596 sizeof (struct GNUNET_HashCode)))
1597 {
1599 "This message is not meant for us (H(PID) mismatch)\n");
1601 kx->transcript_hash_ctx = NULL;
1602 return;
1603 }
1604 // FIXME this sometimes triggers in the tests - why?
1605 // 3. decaps -> shared_secret_R, c_R (kemChallenge)
1606 ihm_len = ntohs (ihm_e->header.size);
1607 initiator_hello_cls = GNUNET_new (struct InitiatorHelloCtx);
1608 initiator_hello_cls->kx = kx;
1609 initiator_hello_cls->ihm_e = GNUNET_malloc (ihm_len);
1610 GNUNET_memcpy (initiator_hello_cls->ihm_e, ihm_e, ihm_len);
1611 initiator_hello_cls->req = GNUNET_new (struct PilsRequest);
1614 initiator_hello_cls->req);
1615 initiator_hello_cls->req->op =
1617 &ihm_e->c_R,
1618 // encapsulated key
1620 // continuation
1621 initiator_hello_cls);
1622}
1623
1624
1625struct ResponderHelloCls
1626{
1627 /* Current KX session */
1628 struct GSC_KeyExchangeInfo *kx;
1629
1630 /* responder hello message - encrypted */
1631 struct ResponderHello rhm_e;
1632
1633 /* responder hello message - plain/decrypted */
1634 struct ResponderHelloPayload *rhp;
1635
1636 /* Decrypted finish hash */
1638
1639 /* Encrypted finished CT (for transcript later) */
1640 char finished_enc[sizeof (struct GNUNET_HashCode)
1641 + AEAD_TAG_BYTES];
1642
1643 /* Temporary transcript context */
1644 struct GNUNET_HashContext *hc;
1645
1646 /* Temporary handshake secret */
1647 struct GNUNET_ShortHashCode hs;
1648
1649 /* Temporary handshake secret */
1651
1652 /* Temporary handshake secret */
1654
1655 /* Temporary handshake secret */
1657
1658 /* Pending PILS request */
1659 struct PilsRequest *req;
1660};
1661
1662static void
1663resend_initiator_done (void *cls)
1664{
1665 struct GSC_KeyExchangeInfo *kx = cls;
1666
1667 kx->resend_task = NULL;
1668 if (0 == kx->resend_tries_left)
1669 {
1671 "Restarting KX\n");
1672 restart_kx (kx);
1673 return;
1674 }
1675 kx->resend_tries_left--;
1677 "Resending initiator done. Retries left: %u\n",
1678 kx->resend_tries_left);
1682 kx);
1683}
1684
1685
1686static void
1687handle_responder_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_I)
1688{
1689 struct ResponderHelloCls *rh_ctx = cls;
1690 struct GSC_KeyExchangeInfo *kx = rh_ctx->kx;
1691 struct InitiatorDone *idm_e; /* encrypted */
1692 struct InitiatorDone idm_local;
1693 struct InitiatorDone *idm_p; /* plaintext */
1694 struct GNUNET_MQ_Envelope *env;
1695 unsigned char enc_key[AEAD_KEY_BYTES];
1696 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1697 struct ConfirmationAck ack_i;
1698 struct GNUNET_HashCode transcript;
1699 struct GNUNET_ShortHashCode ms;
1700
1701 rh_ctx->req->op = NULL;
1704 rh_ctx->req);
1705 GNUNET_free (rh_ctx->req);
1706 // XXX valgrind reports uninitialized memory
1707 // the following is a way to check whether this memory was meant
1708 // memset (&rhm_local, 0, sizeof (rhm_local)); - adapt to cls if still needed
1709 memset (&idm_local, 0, sizeof (idm_local));
1710
1711 kx->ss_I = *ss_I;
1712
1713 /* derive *ATS */
1714 derive_ms (&rh_ctx->hs, ss_I, &ms);;
1715 // 5. Create ResponderFinished as per Section 6 and check against decrypted payload.
1716 struct GNUNET_HashCode responder_finished;
1717 // Transcript updates, snapshot again
1718 snapshot_transcript (rh_ctx->hc,
1719 &transcript);
1720#if DEBUG_KX
1722 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1723 GNUNET_h2s (&transcript));
1724#endif
1725 generate_responder_finished (&transcript,
1726 &ms,
1727 &responder_finished);
1728 if (0 != memcmp (&rh_ctx->decrypted_finish,
1729 &responder_finished,
1730 sizeof (struct GNUNET_HashCode)))
1731 {
1733 "Could not verify \"responder finished\"\n");
1734 GNUNET_free (rh_ctx->rhp);
1735 GNUNET_free (rh_ctx->hc);
1736 GNUNET_free (rh_ctx);
1737 GNUNET_assert (0);
1738 }
1739
1740
1741 /* Forward the transcript
1742 * after generating finished_R,
1743 * before deriving *ATS */
1745 rh_ctx->hc,
1746 rh_ctx->finished_enc,
1747 sizeof (rh_ctx->finished_enc));
1748
1749 // At this point we cannot fail anymore and may lock into kx
1751 kx->transcript_hash_ctx = rh_ctx->hc;
1752 kx->ss_I = *ss_I;
1753 kx->handshake_secret = rh_ctx->hs;
1754 kx->ss_e = rh_ctx->ss_e;
1755 kx->ihts = rh_ctx->ihts;
1756 kx->rhts = rh_ctx->rhts;
1757 kx->master_secret = ms;
1758 GNUNET_free (rh_ctx->rhp);
1759 GNUNET_free (rh_ctx);
1760 rh_ctx = NULL;
1761
1763 &transcript);
1764#if DEBUG_KX
1766 "Transcript snapshot for derivation of *ATS: `%s'\n",
1767 GNUNET_h2s (&transcript));
1768#endif
1769 derive_initial_ats (&transcript,
1770 &kx->master_secret,
1772 &kx->their_ats[0]);
1773 for (int i = 0; i < MAX_EPOCHS - 1; i++)
1774 {
1775 derive_next_ats (&kx->their_ats[i],
1776 &kx->their_ats[i + 1]);
1777 }
1778 kx->their_max_epoch = MAX_EPOCHS - 1;
1779
1781 0,
1782 enc_key,
1783 enc_nonce);
1784 /* Create InitiatorDone message */
1785 idm_p = &idm_local; /* plaintext */
1786 env = GNUNET_MQ_msg_extra (idm_e,
1787 sizeof (ack_i)
1790 // 6. Create IteratorFinished as per Section 6.
1791 generate_initiator_finished (&transcript,
1792 &kx->master_secret,
1793 &idm_p->finished);
1795 "Ifinished: `%s'\n",
1796 GNUNET_h2s (&idm_p->finished));
1798 "Transcript `%s'\n",
1799 GNUNET_h2s (&transcript));
1800 // 7. Send InteratorFinished message encrypted with the key derived from IHTS to R
1801
1802 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1803 (unsigned char*) &idm_e->finished, /* c - ciphertext */
1804 NULL, /* clen_p */
1805 (unsigned char*) &idm_p->finished, /* idm_p - plaintext message */
1806 sizeof (idm_p->finished), // mlen
1807 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1808 // fields?
1809 NULL, // nsec - unused
1810 enc_nonce, // npub - nonce
1811 enc_key)); // k - key IHTS
1812 /* Forward the transcript hash context
1813 * after generating finished_I and RATS_0
1814 * before deriving IATS_0 */
1816 &idm_e->finished,
1817 sizeof (idm_e->finished)
1818 + AEAD_TAG_BYTES);
1820 &transcript);
1821#if DEBUG_KX
1823 "Transcript snapshot for derivation of *ATS: `%s'\n",
1824 GNUNET_h2s (&transcript));
1825#endif
1826 derive_initial_ats (&transcript,
1827 &kx->master_secret,
1829 &kx->current_ats);
1830 kx->current_epoch = 0;
1831 kx->current_sqn++;
1832 // 8. optionally encrypt payload TODO
1834 kx->current_sqn,
1835 enc_key,
1836 enc_nonce);
1837 kx->current_sqn++;
1838 ack_i.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
1839 ack_i.header.size = htons (sizeof ack_i);
1840 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1841 (unsigned char*) &idm_e[1], /* c - ciphertext */
1842 NULL, /* clen_p */
1843 (unsigned char*) &ack_i, /* rhm_p - plaintext message */
1844 sizeof ack_i, // mlen
1845 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1846 // fields?
1847 NULL, // nsec - unused
1848 enc_nonce, // npub - nonce // FIXME nonce can be reused
1849 enc_key)); // k - key RHTS
1850
1851 GNUNET_MQ_send_copy (kx->mq, env);
1852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent InitiatorDone\n");
1853
1854
1855 kx->resend_env = env;
1859 kx);
1861 monitor_notify_all (kx);
1862 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1863}
1864
1865
1866static int
1867check_responder_hello (void *cls, const struct ResponderHello *m)
1868{
1869 uint16_t size = ntohs (m->header.size);
1870
1871 if (size < sizeof (*m)
1872 + sizeof (struct ResponderHelloPayload)
1873 + sizeof (struct GNUNET_HashCode)
1874 + AEAD_TAG_BYTES * 2)
1875 {
1876 return GNUNET_SYSERR;
1877 }
1878 return GNUNET_OK;
1879}
1880
1881
1887static void
1888handle_responder_hello (void *cls, const struct ResponderHello *rhm_e)
1889{
1890 struct GSC_KeyExchangeInfo *kx = cls;
1891 struct PilsRequest *req;
1892 struct ResponderHelloCls *rh_ctx;
1893 struct GNUNET_HashCode transcript;
1894 struct GNUNET_HashContext *hc;
1895 unsigned char enc_key[AEAD_KEY_BYTES];
1896 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1898
1899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ResponderHello\n");
1900
1902 if (NULL != kx->resend_task)
1903 {
1905 kx->resend_task = NULL;
1906 }
1907 if (NULL != kx->resend_env)
1908 {
1909 GNUNET_free (kx->resend_env);
1910 kx->resend_env = NULL;
1911 }
1912
1913 /* Forward the transcript hash context */
1914 if (ROLE_RESPONDER == kx->role)
1915 {
1916 GNUNET_break_op (0);
1918 "I am the responder! Ignoring.\n");
1919 return;
1920 }
1922 rhm_e,
1923 sizeof (struct ResponderHello));
1924 // 1. Verify that the message type is CORE_RESPONDER_HELLO
1925 // - implicitly done by handling this message?
1926 // - or is this about verifying the 'additional data' part of aead?
1927 // should it check the encryption + mac? (is this implicitly done
1928 // while decrypting?)
1929 // 2. sse <- Decaps(ske,ce)
1930 rh_ctx = GNUNET_new (struct ResponderHelloCls);
1931 ret = GNUNET_CRYPTO_hpke_kem_decaps (&kx->sk_e, // secret/private ephemeral key of initiator (us)
1932 &rhm_e->c_e, // encapsulated key
1933 &rh_ctx->ss_e); // key - ss_e
1934 if (GNUNET_OK != ret)
1935 {
1937 "Something went wrong decapsulating ss_e\n");
1938 GNUNET_free (hc);
1939 return;
1940 }
1941 // 3. Generate IHTS and RHTS from Section 5 and decrypt ServicesInfo, cI and ResponderFinished.
1942 snapshot_transcript (hc, &transcript);
1943#if DEBUG_KX
1945 "Transcript snapshot for derivation of HS, *HTS: `%s'\n",
1946 GNUNET_h2s (&transcript));
1947#endif
1949 &rh_ctx->ss_e,
1950 &rh_ctx->hs);
1951 derive_rhts (&transcript,
1952 &rh_ctx->hs,
1953 &rh_ctx->rhts);
1954 derive_ihts (&transcript,
1955 &rh_ctx->hs,
1956 &rh_ctx->ihts);
1958 0,
1959 enc_key,
1960 enc_nonce);
1961 rh_ctx->kx = kx;
1962 GNUNET_memcpy (&rh_ctx->rhm_e, rhm_e, sizeof (*rhm_e));
1963 {
1964 unsigned long long int c_len;
1965 unsigned char *finished_buf;
1966 // use RHTS to decrypt
1967 c_len = ntohs (rhm_e->header.size) - sizeof (*rhm_e)
1968 - sizeof (struct GNUNET_HashCode)
1969 - AEAD_TAG_BYTES; // finished ct
1970 rh_ctx->rhp = GNUNET_malloc (c_len
1971 -
1973 rh_ctx->hc = hc;
1974 finished_buf = ((unsigned char*) &rhm_e[1]) + c_len;
1975 /* Forward the transcript_hash_ctx
1976 * after rhts has been generated,
1977 * before generating finished_R*/
1979 hc,
1980 &rhm_e[1],
1981 c_len);
1982
1983 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1984 (unsigned char*) rh_ctx->rhp, // unsigned char *m
1985 NULL, // mlen_p message length
1986 NULL, // unsigned char *nsec - unused: NULL
1987 (unsigned char*) &rhm_e[1], // const unsigned char *c - cyphertext
1988 c_len, // unsigned long long clen - length of cyphertext
1989 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1990 0, // unsigned long long adlen
1991 enc_nonce, // const unsigned char *npub - nonce
1992 enc_key // const unsigned char *k - key
1993 );
1994 if (0 != ret)
1995 {
1997 "Something went wrong decrypting: %d\n", ret);
1998 GNUNET_free (rh_ctx->rhp);
1999 GNUNET_free (rh_ctx);
2000 GNUNET_free (hc);
2001 return;
2002 }
2003 // FIXME nonce reuse (see encryption)
2005 1,
2006 enc_key,
2007 enc_nonce);
2008 c_len = sizeof (struct GNUNET_HashCode)
2010 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2011 (unsigned char*) &rh_ctx->decrypted_finish, // unsigned char *m
2012 NULL, // mlen_p message length
2013 NULL, // unsigned char *nsec - unused: NULL
2014 finished_buf, // const unsigned char *c - cyphertext
2015 c_len, // unsigned long long clen - length of cyphertext
2016 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2017 0, // unsigned long long adlen
2018 enc_nonce, // const unsigned char *npub - nonce
2019 enc_key // const unsigned char *k - key
2020 );
2021 if (0 != ret)
2022 {
2024 "Something went wrong decrypting finished field: %d\n", ret);
2025 GNUNET_free (rh_ctx->rhp);
2026 GNUNET_free (rh_ctx);
2027 GNUNET_free (hc);
2028 return;
2029 }
2030 GNUNET_memcpy (rh_ctx->finished_enc,
2031 finished_buf,
2032 c_len);
2033 }
2034 // 4. ssI <- Decaps(skI,cI).
2035 req = GNUNET_new (struct PilsRequest);
2036 rh_ctx->req = req;
2039 req);
2041 &rh_ctx->rhp->c_I, // encapsulated key
2042 &handle_responder_hello_cont, // continuation
2043 rh_ctx);
2044}
2045
2046
2047static int
2048check_initiator_done (void *cls, const struct InitiatorDone *m)
2049{
2050 uint16_t size = ntohs (m->header.size);
2051
2052 if (size < sizeof (*m) + sizeof (struct ConfirmationAck))
2053 {
2054 return GNUNET_SYSERR;
2055 }
2056 return GNUNET_OK;
2057}
2058
2059
2065static void
2066handle_initiator_done (void *cls, const struct InitiatorDone *idm_e)
2067{
2068 struct GSC_KeyExchangeInfo *kx = cls;
2069 struct InitiatorDone idm_local;
2070 struct InitiatorDone *idm_p = &idm_local; /* plaintext */
2071 struct GNUNET_HashCode initiator_finished;
2072 struct GNUNET_HashCode transcript;
2073 struct GNUNET_ShortHashCode their_ats;
2074 struct GNUNET_HashContext *hc;
2075 unsigned char enc_key[AEAD_KEY_BYTES];
2076 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2077 struct ConfirmationAck ack_i;
2078 struct ConfirmationAck ack_r;
2079 int8_t ret;
2080
2081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorDone\n");
2082 if (NULL != kx->resend_task)
2083 {
2085 kx->resend_task = NULL;
2086 }
2087 if (NULL != kx->resend_env)
2088 {
2089 GNUNET_free (kx->resend_env);
2090 kx->resend_env = NULL;
2091 }
2092 if (ROLE_INITIATOR == kx->role)
2093 {
2094 GNUNET_break_op (0);
2096 "I am the initiator! Tearing down...\n");
2097 return;
2098 }
2100 0,
2101 enc_key,
2102 enc_nonce);
2103 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2104 (unsigned char*) &idm_p->finished, // unsigned char *m
2105 NULL, // mlen_p message length
2106 NULL, // unsigned char *nsec - unused: NULL
2107 (unsigned char*) &idm_e->finished, // const unsigned char *c - cyphertext
2108 sizeof (idm_p->finished) // unsigned long long clen - length of cyphertext
2110 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2111 0, // unsigned long long adlen
2112 enc_nonce, // const unsigned char *npub - nonce
2113 enc_key // const unsigned char *k - key
2114 );
2115 if (0 != ret)
2116 {
2118 "Something went wrong decrypting: %d\n", ret);
2119 return;
2120 }
2121
2122 // - verify finished_I
2123 /* Generate finished_I
2124 * after Forwarding until {finished_R}RHTS
2125 * (did so while we prepared responder hello)
2126 * before forwarding to [{payload}RATS and] {finished_I}IHTS */
2127 // (look at the end of handle_initiator_hello())
2128 snapshot_transcript (kx->transcript_hash_ctx, &transcript);
2129 generate_initiator_finished (&transcript,
2130 &kx->master_secret,
2131 &initiator_finished);
2132 if (0 != memcmp (&idm_p->finished,
2133 &initiator_finished,
2134 sizeof (struct GNUNET_HashCode)))
2135 {
2137 "Could not verify \"initiator finished\" hash.\n");
2139 "Want: `%s'\n",
2140 GNUNET_h2s (&initiator_finished));
2142 "Have: `%s'\n",
2143 GNUNET_h2s (&idm_p->finished));
2145 "Transcript `%s'\n",
2146 GNUNET_h2s (&transcript));
2147 return;
2148 }
2149
2150 /* Forward the transcript hash_context_read */
2153 &idm_e->finished,
2154 sizeof (idm_e->finished)
2155 + AEAD_TAG_BYTES);
2156 snapshot_transcript (hc, &transcript);
2157 derive_initial_ats (&transcript,
2158 &kx->master_secret,
2160 &their_ats);
2161 derive_per_message_secrets (&their_ats, // FIXME other HS epoch?
2162 0,
2163 enc_key,
2164 enc_nonce);
2165 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2166 (unsigned char*) &ack_i, // unsigned char *m
2167 NULL, // mlen_p message length
2168 NULL, // unsigned char *nsec - unused: NULL
2169 (unsigned char*) &idm_e[1], // const unsigned char *c - cyphertext
2170 sizeof (ack_i) + AEAD_TAG_BYTES, // unsigned long long clen - length of cyphertext
2171 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2172 0, // unsigned long long adlen
2173 enc_nonce, // const unsigned char *npub - nonce
2174 enc_key // const unsigned char *k - key
2175 );
2176 if (0 != ret)
2177 {
2179 "Something went wrong decrypting the Ack: %d\n", ret);
2181 return;
2182 }
2183 if ((sizeof ack_i != ntohs (ack_i.header.size)) ||
2184 (GNUNET_MESSAGE_TYPE_CORE_ACK != ntohs (ack_i.header.type)))
2185 {
2187 "Ack invalid!\n");
2189 return;
2190 }
2191 GNUNET_memcpy (&kx->their_ats[0],
2192 &their_ats,
2193 sizeof their_ats);
2197 for (int i = 0; i < MAX_EPOCHS - 1; i++)
2198 {
2199 derive_next_ats (&kx->their_ats[i],
2200 &kx->their_ats[i + 1]);
2201 }
2203 kx->transcript_hash_ctx = hc;
2208 monitor_notify_all (kx);
2209 kx->current_sqn = 1;
2210 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2211 GNUNET_assert (NULL == kx->heartbeat_task);
2212 update_timeout (kx);
2213 ack_r.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2214 ack_r.header.size = htons (sizeof ack_r);
2216 &ack_r,
2217 sizeof ack_r);
2218
2219 GNUNET_TRANSPORT_core_receive_continue (transport,
2220 &kx->peer);
2221}
2222
2223
2229static int
2230check_encrypted_message (void *cls, const struct EncryptedMessage *m)
2231{
2232 uint16_t size = ntohs (m->header.size) - sizeof(*m);
2233
2234 // TODO check (see check_encrypted ())
2235 // - check epoch
2236 // - check sequence number
2237 if (size < sizeof(struct GNUNET_MessageHeader))
2238 {
2239 GNUNET_break_op (0);
2240 return GNUNET_SYSERR;
2241 }
2242 return GNUNET_OK;
2243}
2244
2245
2251static void
2253 const struct Heartbeat *m)
2254{
2255 struct GNUNET_ShortHashCode new_ats;
2256 struct ConfirmationAck ack;
2257
2259 {
2260 if (kx->current_epoch == UINT64_MAX)
2261 {
2263 "Max epoch reached (you probably will never see this)\n");
2264 }
2265 else
2266 {
2267 kx->current_epoch++;
2270 kx->current_sqn = 0;
2272 &new_ats);
2273 memcpy (&kx->current_ats,
2274 &new_ats,
2275 sizeof new_ats);
2276 }
2277 }
2278 update_timeout (kx);
2279 ack.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2280 ack.header.size = htons (sizeof ack);
2282 &ack,
2283 sizeof ack);
2284 if (NULL != kx->heartbeat_task)
2285 {
2289 kx);
2290 }
2291 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2292}
2293
2294
2295static enum GNUNET_GenericReturnValue
2297 const char *buf,
2298 size_t buf_len)
2299{
2300 struct GNUNET_MessageHeader *msg;
2301 struct ConfirmationAck *ack;
2302 struct Heartbeat *hb;
2303
2304 if (sizeof *msg > buf_len)
2305 return GNUNET_NO;
2306 msg = (struct GNUNET_MessageHeader*) buf;
2307 if (GNUNET_MESSAGE_TYPE_CORE_ACK == ntohs (msg->type))
2308 {
2309 ack = (struct ConfirmationAck *) buf;
2310 if (sizeof *ack != ntohs (ack->header.size))
2311 return GNUNET_NO;
2312 }
2313 else if (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT == ntohs (msg->type))
2314 {
2315 hb = (struct Heartbeat*) buf;
2316 if (sizeof *hb != ntohs (hb->header.size))
2317 return GNUNET_NO;
2318 handle_heartbeat (kx, hb);
2319 }
2320 else
2321 {
2322 return GNUNET_NO;
2323 }
2324
2329 {
2330 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2335 if (NULL != kx->resend_task)
2337 kx->resend_task = NULL;
2338 if (NULL != kx->resend_env)
2339 GNUNET_free (kx->resend_env);
2340 kx->resend_env = NULL;
2341 monitor_notify_all (kx);
2342 }
2343 update_timeout (kx);
2344
2345 return GNUNET_YES;
2346}
2347
2348
2354static void
2355handle_encrypted_message (void *cls, const struct EncryptedMessage *m)
2356{
2357 struct GSC_KeyExchangeInfo *kx = cls;
2358 uint16_t size = ntohs (m->header.size);
2359 char buf[size - sizeof (*m)] GNUNET_ALIGN;
2360 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2361 const unsigned char *seq_enc_nonce;
2362 unsigned char enc_key[AEAD_KEY_BYTES];
2363 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2364 struct GNUNET_ShortHashCode new_ats[MAX_EPOCHS];
2365 uint32_t seq_enc_ctr;
2366 uint64_t epoch;
2367 uint64_t m_seq;
2368 uint64_t m_seq_nbo;
2369 uint64_t c_len;
2370 int8_t ret;
2371
2372 // TODO look at handle_encrypted
2373 // - statistics
2374
2378 {
2379 GSC_SESSIONS_end (&kx->peer);
2381 monitor_notify_all (kx);
2382 restart_kx (kx);
2383 return;
2384 }
2385 update_timeout (kx);
2386 epoch = GNUNET_ntohll (m->epoch);
2391 memcpy (new_ats,
2392 kx->their_ats,
2393 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2394 // FIXME here we could introduce logic that sends hearbeats
2395 // with key update request if we have not seen a new
2396 // epoch after a while (e.g. EPOCH_EXPIRATION)
2397 if (kx->their_max_epoch < epoch)
2398 {
2403 if ((epoch - kx->their_max_epoch) > 2 * MAX_EPOCHS)
2404 {
2406 "Epoch %" PRIu64 " is too new, will not decrypt...\n",
2407 epoch);
2408 GSC_SESSIONS_end (&kx->peer);
2410 monitor_notify_all (kx);
2411 restart_kx (kx);
2412 return;
2413 }
2414 for (int i = kx->their_max_epoch; i < epoch; i++)
2415 {
2416 derive_next_ats (&new_ats[i % MAX_EPOCHS],
2417 &new_ats[(i + 1) % MAX_EPOCHS]);
2418 }
2419 }
2420 else if ((kx->their_max_epoch - epoch) > MAX_EPOCHS)
2421 {
2423 "Epoch %" PRIu64 " is too old, cannot decrypt...\n",
2424 epoch);
2425 return;
2426 }
2427 derive_sn (
2428 &new_ats[epoch % MAX_EPOCHS],
2429 seq_enc_k,
2430 sizeof seq_enc_k);
2431 /* compute the sequence number */
2432 seq_enc_ctr = *((uint32_t*) m->tag);
2433 seq_enc_nonce = &m->tag[sizeof (uint32_t)];
2434#if DEBUG_KX
2435 GNUNET_print_bytes (&new_ats[epoch % MAX_EPOCHS],
2436 sizeof (struct GNUNET_ShortHashCode),
2437 8,
2438 GNUNET_NO);
2439 GNUNET_print_bytes (seq_enc_k,
2440 sizeof seq_enc_k,
2441 8,
2442 GNUNET_NO);
2443 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2444 16,
2445 8,
2446 GNUNET_NO);
2447#endif
2448 crypto_stream_chacha20_ietf_xor_ic (
2449 (unsigned char*) &m_seq_nbo,
2450 (unsigned char*) &m->sequence_number,
2451 sizeof (uint64_t),
2452 seq_enc_nonce,
2453 ntohl (seq_enc_ctr),
2454 seq_enc_k);
2455 m_seq = GNUNET_ntohll (m_seq_nbo);
2457 "Received encrypted message in epoch %" PRIu64
2458 " with E(SQN=%" PRIu64 ")=%" PRIu64
2459 "\n",
2460 epoch,
2461 m_seq,
2462 m->sequence_number);
2463 /* We are the initiator and as we are going to receive,
2464 * we are using the responder key material */
2465 derive_per_message_secrets (&new_ats[epoch],
2466 m_seq,
2467 enc_key,
2468 enc_nonce);
2469 // TODO checking sequence numbers - handle the case of out-of-sync messages!
2470 // for now only decrypt the payload
2471 // TODO encrypt other fields, too!
2472 // TODO
2473 // c_len = size - offsetof ();
2474 c_len = size - sizeof (struct EncryptedMessage);
2475 ret = crypto_aead_xchacha20poly1305_ietf_decrypt_detached (
2476 (unsigned char*) buf, // m - plain message
2477 NULL, // nsec - unused
2478 (unsigned char*) &m[1], // c - ciphertext
2479 c_len, // clen
2480 (const unsigned char*) &m->tag, // mac
2481 NULL, // ad - additional data TODO
2482 0, // adlen
2483 enc_nonce, // npub
2484 enc_key // k
2485 );
2486 if (0 != ret)
2487 {
2489 "Something went wrong decrypting message\n");
2490 GNUNET_break_op (0); // FIXME handle gracefully
2491 return;
2492 }
2493 kx->their_max_epoch = epoch;
2494 memcpy (&kx->their_ats,
2495 new_ats,
2496 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2497
2499 buf,
2500 sizeof buf))
2501 {
2503 {
2505 "Dropping message as we are still waiting for handshake ACK\n");
2506 GNUNET_break_op (0);
2507 return;
2508 }
2509 if (GNUNET_OK !=
2511 buf,
2512 sizeof buf,
2513 GNUNET_YES,
2514 GNUNET_NO))
2515 GNUNET_break_op (0);
2516 }
2517 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2518}
2519
2520
2530static void
2532 const struct GNUNET_PeerIdentity *peer,
2533 void *handler_cls)
2534{
2535 struct GSC_KeyExchangeInfo *kx = handler_cls;
2536 (void) cls;
2537
2539 "Peer `%s' disconnected from us.\n",
2540 GNUNET_i2s (&kx->peer));
2541 GSC_SESSIONS_end (&kx->peer);
2543 gettext_noop ("# key exchanges stopped"),
2544 1,
2545 GNUNET_NO);
2546 if (NULL != kx->resend_task)
2547 {
2549 kx->resend_task = NULL;
2550 }
2551 if (NULL != kx->resend_env)
2552 {
2553 GNUNET_free (kx->resend_env);
2554 kx->resend_env = NULL;
2555 }
2556 if (NULL != kx->heartbeat_task)
2557 {
2559 kx->heartbeat_task = NULL;
2560 }
2562 monitor_notify_all (kx);
2564 GNUNET_MST_destroy (kx->mst);
2565 GNUNET_free (kx);
2566}
2567
2568
2569static void
2570resend_initiator_hello (void *cls)
2571{
2572 struct GSC_KeyExchangeInfo *kx = cls;
2573
2574 kx->resend_task = NULL;
2576 "Resending initiator hello.\n");
2578 // FIXME (Exponential) backoff?
2581 kx);
2582}
2583
2584
2590static void
2592{
2593 struct GNUNET_MQ_Envelope *env;
2594 struct GNUNET_ShortHashCode es;
2595 struct GNUNET_ShortHashCode ets;
2596 struct GNUNET_ShortHashCode ss_R;
2597 struct InitiatorHelloPayload *ihmp; /* initiator hello message - buffer on stack */
2598 struct InitiatorHello *ihm_e; /* initiator hello message - encrypted */
2599 long long unsigned int c_len;
2600 unsigned char enc_key[AEAD_KEY_BYTES];
2601 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2603 size_t pt_len;
2604
2605 pt_len = sizeof (*ihmp) + strlen (my_services_info);
2606 c_len = pt_len + AEAD_TAG_BYTES;
2607 env = GNUNET_MQ_msg_extra (ihm_e,
2608 c_len,
2610 ihmp = (struct InitiatorHelloPayload*) &ihm_e[1];
2611 ihmp->peer_class = htons (GNUNET_CORE_CLASS_UNKNOWN); // TODO set this to a meaningful
2612 GNUNET_memcpy (&ihmp->pk_I,
2614 sizeof (GSC_my_identity));
2615 GNUNET_CRYPTO_hash (&kx->peer, /* what to hash */ // TODO do we do this twice?
2616 sizeof (struct GNUNET_PeerIdentity),
2617 &ihm_e->h_pk_R); /* result */
2618 // TODO init hashcontext/transcript_hash
2619 GNUNET_assert (NULL == kx->transcript_hash_ctx);
2621 GNUNET_assert (NULL != kx->transcript_hash_ctx);
2622 // TODO fill services_info
2623
2624 // 1. Encaps
2625 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public ephemeral key of initiator
2626 &ihm_e->c_R, // encapsulated key
2627 &ss_R); // key - ss_R
2628 if (GNUNET_OK != ret)
2629 {
2631 "Something went wrong encapsulating ss_R\n");
2632 // TODO handle
2633 }
2634 // 2. generate rR (uint64_t) - is this the nonce? Naming seems not quite
2635 // consistent
2636 ihm_e->r_I =
2638 UINT64_MAX);
2639 // 3. generate sk_e/pk_e - ephemeral key
2642 &kx->sk_e,
2643 &kx->pk_e);
2644 GNUNET_memcpy (&ihm_e->pk_e, &kx->pk_e, sizeof (kx->pk_e));
2645 // 4. generate ETS to encrypt
2646 // generate ETS (early_traffic_secret_key, decrypt pk_i
2647 // expand ETS <- expand ES <- extract ss_R
2648 // use ETS to decrypt
2650 ihm_e,
2651 sizeof (struct InitiatorHello));
2652 {
2653 struct GNUNET_HashCode transcript;
2655 &transcript);
2656 derive_es_ets (&transcript,
2657 &ss_R,
2658 &es,
2659 &ets);
2661 0,
2662 enc_key,
2663 enc_nonce);
2664 }
2665 // 5. encrypt
2666
2667 ret = crypto_aead_xchacha20poly1305_ietf_encrypt (
2668 (unsigned char*) &ihm_e[1], /* c - ciphertext */
2669 // mac,
2670 // NULL, // maclen_p
2671 &c_len, /* clen_p */
2672 (unsigned char*) ihmp, /* m - plaintext message */
2673 pt_len, // mlen
2674 NULL, 0, // ad, adlen // FIXME maybe over the unencrypted header?
2675 // fields?
2676 NULL, // nsec - unused
2677 enc_nonce, // npub - nonce
2678 enc_key); // k - key
2679 if (0 != ret)
2680 {
2681 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong encrypting\n");
2683 kx->transcript_hash_ctx = NULL;
2684 return;
2685 }
2686 /* Forward the transcript */
2689 &ihm_e[1],
2690 c_len);
2691
2693 kx->early_secret_key = es;
2694 kx->early_traffic_secret = ets;
2695 kx->ss_R = ss_R;
2696 monitor_notify_all (kx);
2697 GNUNET_MQ_send_copy (kx->mq, env);
2698 kx->resend_env = env;
2702 kx);
2703}
2704
2705static void
2707{
2708 struct GNUNET_ShortHashCode new_ats;
2709
2710 if ((UINT64_MAX == kx->current_sqn) ||
2712 {
2714 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2715 ", incrementing epoch...\n",
2717 kx->current_sqn);
2718 // Can this trigger? Maybe if we receive a lot of
2719 // heatbeats?
2720 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2721 kx->current_epoch++;
2724 kx->current_sqn = 0;
2726 &new_ats);
2727 memcpy (&kx->current_ats,
2728 &new_ats,
2729 sizeof new_ats);
2730 }
2731}
2732
2739void
2741 const void *payload,
2742 size_t payload_size)
2743{
2744 struct GNUNET_MQ_Envelope *env;
2745 struct EncryptedMessage *encrypted_msg;
2746 unsigned char enc_key[AEAD_KEY_BYTES];
2747 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2748 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2749 uint64_t sqn;
2750 uint64_t epoch;
2751 int8_t ret;
2752
2753 encrypted_msg = NULL;
2754
2755 check_rekey (kx);
2756 sqn = kx->current_sqn;
2757 epoch = kx->current_epoch;
2758 /* We are the sender and as we are going to send,
2759 * we are using the initiator key material */
2761 sqn,
2762 enc_key,
2763 enc_nonce);
2764 kx->current_sqn++;
2765 derive_sn (&kx->current_ats,
2766 seq_enc_k,
2767 sizeof seq_enc_k);
2768 env = GNUNET_MQ_msg_extra (encrypted_msg,
2769 payload_size,
2771 // only encrypt the payload for now
2772 // TODO encrypt other fields as well
2773 ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached (
2774 (unsigned char*) &encrypted_msg[1], // c - resulting ciphertext
2775 (unsigned char*) &encrypted_msg->tag, // mac - resulting mac/tag
2776 NULL, // maclen
2777 (unsigned char*) payload, // m - plain message
2778 payload_size, // mlen
2779 NULL, // ad - additional data TODO also cover the unencrypted part (epoch)
2780 0, // adlen
2781 NULL, // nsec - unused
2782 enc_nonce, // npub nonce
2783 enc_key // k - key
2784 );
2785 if (0 != ret)
2786 {
2788 "Something went wrong encrypting message\n");
2789 GNUNET_assert (0);
2790 }
2791 {
2792 /* compute the sequence number */
2793 unsigned char *seq_enc_nonce;
2794 uint64_t seq_nbo;
2795 uint32_t seq_enc_ctr;
2796
2797 seq_nbo = GNUNET_htonll (sqn);
2798 seq_enc_ctr = *((uint32_t*) encrypted_msg->tag);
2799 seq_enc_nonce = &encrypted_msg->tag[sizeof (uint32_t)];
2800 crypto_stream_chacha20_ietf_xor_ic (
2801 (unsigned char*) &encrypted_msg->sequence_number,
2802 (unsigned char*) &seq_nbo,
2803 sizeof seq_nbo,
2804 seq_enc_nonce,
2805 ntohl (seq_enc_ctr),
2806 seq_enc_k);
2807#if DEBUG_KX
2808 GNUNET_print_bytes (seq_enc_k,
2809 sizeof seq_enc_k,
2810 8,
2811 GNUNET_NO);
2812 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2813 16,
2814 8,
2815 GNUNET_NO);
2816#endif
2818 "Sending encrypted message with E(SQN=%" PRIu64 ")=%" PRIu64
2819 "\n",
2820 sqn,
2821 encrypted_msg->sequence_number);
2822 }
2823 encrypted_msg->epoch = GNUNET_htonll (epoch);
2824
2825 // TODO actually copy payload
2826 GNUNET_MQ_send (kx->mq, env);
2827}
2828
2829
2836static void
2837peer_id_change_cb (void *cls,
2838 const struct GNUNET_HELLO_Parser *parser,
2839 const struct GNUNET_HashCode *hash)
2840{
2841 (void) cls;
2843 // TODO check that hash matches last fed hash
2845 "This peer has now a new peer id: %s\n",
2847 // TODO if changing from old peer_id to new peer_id: tear down old
2848 // connections, try restart connections over kept addresses?
2849 /* Continue initialisation of core */
2850 if (GNUNET_YES == init_phase)
2851 {
2854 }
2855}
2856
2857
2863int
2864GSC_KX_init (void)
2865{
2867 GNUNET_MQ_hd_var_size (initiator_hello,
2869 struct InitiatorHello,
2870 NULL),
2871 GNUNET_MQ_hd_var_size (initiator_done,
2873 struct InitiatorDone,
2874 NULL),
2875 GNUNET_MQ_hd_var_size (responder_hello,
2877 struct ResponderHello,
2878 NULL),
2879 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2881 struct EncryptedMessage,
2882 NULL),
2884 };
2885
2889 NULL); // TODO potentially wait
2890 // until we have a peer_id?
2891 // pay attention to whether
2892 // we have one anyways
2893 if (NULL == pils)
2894 {
2895 GSC_KX_done ();
2896 return GNUNET_SYSERR;
2897 }
2898
2900 transport =
2903 handlers,
2904 NULL, // cls - this connection-independant
2905 // cls seems not to be needed.
2906 // the connection-specific cls
2907 // will be set as a return value
2908 // of
2909 // handle_transport_notify_connect
2912 if (NULL == transport)
2913 {
2914 GSC_KX_done ();
2915 return GNUNET_SYSERR;
2916 }
2918 "Connected to TRANSPORT\n");
2919 return GNUNET_OK;
2920}
2921
2922
2926void
2927GSC_KX_done ()
2928{
2929 struct PilsRequest *pr;
2930 while (NULL != (pr = pils_requests_head))
2931 {
2934 pr);
2935 if (NULL != pr->op)
2936 GNUNET_PILS_cancel (pr->op);
2937 GNUNET_free (pr);
2938 }
2939 if (NULL != pils)
2940 {
2942 pils = NULL;
2943 }
2944 if (NULL != transport)
2945 {
2947 transport = NULL;
2948 }
2949 if (NULL != rekey_task)
2950 {
2952 rekey_task = NULL;
2953 }
2954 if (NULL != nc)
2955 {
2957 nc = NULL;
2958 }
2959}
2960
2961
2968unsigned int
2970{
2971 return GNUNET_MQ_get_length (kxinfo->mq);
2972}
2973
2974
2975int
2977{
2978 return kxinfo->has_excess_bandwidth;
2979}
2980
2981
2990void
2992{
2993 struct GNUNET_MQ_Envelope *env;
2994 struct MonitorNotifyMessage *done_msg;
2995 struct GSC_KeyExchangeInfo *kx;
2996
2998 for (kx = kx_head; NULL != kx; kx = kx->next)
2999 {
3000 struct GNUNET_MQ_Envelope *env_notify;
3001 struct MonitorNotifyMessage *msg;
3002
3004 msg->state = htonl ((uint32_t) kx->status);
3005 msg->peer = kx->peer;
3006 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
3007 GNUNET_MQ_send (mq, env_notify);
3008 }
3010 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
3013}
3014
3015
3016/* 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_OS_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_encaps(const struct GNUNET_CRYPTO_EcdhePublicKey *pkR, struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Encapsulate key material for a X25519 public key.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hpke_kem_decaps(const struct GNUNET_CRYPTO_EcdhePrivateKey *priv, const struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Decapsulate a key for a private X25519 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)
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.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hkdf_expand(void *result, size_t out_len, const struct GNUNET_ShortHashCode *prk,...)
HKDF-Expand using SHA256.
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.
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_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.
#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:980
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:1277
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:552
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:640
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition time.c:671
#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
Private ECC key encoded for transmission.
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and encr...
HPKE DHKEM encapsulation (X25519) See RFC 9180.
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:136
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.
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_CRYPTO_EcdhePrivateKey sk_e
Initiator secret key.
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_EcdhePublicKey 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 2592 of file gnunet-service-core_kx.c.

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

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, 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_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, // result
804 sizeof (*ets), // result len
805 es,
806 CAKE_LABEL, strlen (CAKE_LABEL),
808 transcript,
809 sizeof (*transcript),
810 NULL, 0);
811 if (GNUNET_OK != ret)
812 {
813 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
814 ;
815 GNUNET_assert (0);
816 }
817}

References CAKE_LABEL, EARLY_DATA_STR, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), GNUNET_CRYPTO_hkdf_extract(), 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 825 of file gnunet-service-core_kx.c.

828{
830 GNUNET_CRYPTO_hkdf_expand (sn, // result
831 sn_len,
832 secret,
833 CAKE_LABEL, strlen (CAKE_LABEL),
834 "sn", strlen ("sn"),
835 NULL));
836}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), and GNUNET_OK.

Referenced by GSC_KX_encrypt_and_transmit(), and handle_encrypted_message().

Here is the call graph for this function:
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 844 of file gnunet-service-core_kx.c.

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

References CAKE_LABEL, DERIVED_STR, GNUNET_assert, GNUNET_B2S, GNUNET_CRYPTO_hkdf_expand(), GNUNET_CRYPTO_hkdf_extract(), 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 890 of file gnunet-service-core_kx.c.

893{
895 GNUNET_CRYPTO_hkdf_expand (ihts, // result
896 sizeof (*ihts), // result len
897 hs, // prk?
898 CAKE_LABEL, strlen (CAKE_LABEL),
900 strlen (I_HS_TRAFFIC_STR),
901 transcript,
902 sizeof (*transcript),
903 NULL));
904}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), GNUNET_OK, and I_HS_TRAFFIC_STR.

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

915{
917 GNUNET_CRYPTO_hkdf_expand (rhts, // result
918 sizeof (*rhts), // result len
919 hs, // prk? TODO
920 CAKE_LABEL, strlen (CAKE_LABEL),
922 strlen (R_HS_TRAFFIC_STR),
923 transcript,
924 sizeof (*transcript),
925 NULL));
926}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), GNUNET_OK, and R_HS_TRAFFIC_STR.

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

937{
938 uint64_t ret;
939 struct GNUNET_ShortHashCode derived_handshake_secret;
940
941 ret = GNUNET_CRYPTO_hkdf_expand (&derived_handshake_secret, // result
942 sizeof (derived_handshake_secret), // result len
943 hs, // prk? TODO
944 CAKE_LABEL, strlen (CAKE_LABEL),
945 DERIVED_STR, strlen (DERIVED_STR),
946 NULL);
947 if (GNUNET_OK != ret)
948 {
949 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dHS\n")
950 ;
951 GNUNET_assert (0);
952 }
953 // TODO check: are dHS the salt and ss_I the ikm or other way round?
954 ret = GNUNET_CRYPTO_hkdf_extract (ms, // prk
955 &derived_handshake_secret, // salt - dHS
956 sizeof (derived_handshake_secret), // salt_len
957 ss_I, // ikm - initial key material
958 sizeof (*ss_I));
959 if (GNUNET_OK != ret)
960 {
961 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting MS\n")
962 ;
963 GNUNET_assert (0);
964 }
965}

References CAKE_LABEL, DERIVED_STR, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), GNUNET_CRYPTO_hkdf_extract(), 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 974 of file gnunet-service-core_kx.c.

978{
979 uint64_t seq_nbo;
980 uint64_t *write_iv_ptr;
981 unsigned int byte_offset;
982
983 seq_nbo = GNUNET_htonll (seq);
984 memcpy (per_record_write_iv,
985 write_iv,
987 byte_offset =
988 AEAD_NONCE_BYTES - sizeof (uint64_t);
989 write_iv_ptr = (uint64_t*) (write_iv + byte_offset);
990 *write_iv_ptr ^= seq_nbo;
991}

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

1004{
1005 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
1006 /* derive actual key */
1010 ts,
1011 CAKE_LABEL, strlen (CAKE_LABEL),
1012 KEY_STR,
1013 strlen (KEY_STR),
1014 NULL));
1015
1016 /* derive nonce */
1018 GNUNET_CRYPTO_hkdf_expand (nonce_tmp,
1020 ts,
1021 CAKE_LABEL, strlen (CAKE_LABEL),
1022 IV_STR,
1023 strlen (IV_STR),
1024 NULL));
1026 nonce_tmp,
1027 nonce);
1028}

References AEAD_KEY_BYTES, AEAD_NONCE_BYTES, CAKE_LABEL, generate_per_record_nonce(), GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), 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 1036 of file gnunet-service-core_kx.c.

1038{
1039 int8_t ret;
1040
1041 // FIXME: Not sure of PRK and output may overlap here!
1042 ret = GNUNET_CRYPTO_hkdf_expand (new_ats, // result
1043 sizeof (*new_ats), // result len
1044 old_ats,
1045 CAKE_LABEL, strlen (CAKE_LABEL),
1047 NULL);
1048 if (GNUNET_OK != ret)
1049 {
1051 "Something went wrong deriving next *ATS key\n");
1052 GNUNET_assert (0);
1053 }
1054}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), 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 call graph for this function:
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 1062 of file gnunet-service-core_kx.c.

1066{
1067 const char *traffic_str;
1068
1069 if (ROLE_INITIATOR == role)
1070 traffic_str = I_AP_TRAFFIC_STR;
1071 else
1072 traffic_str = R_AP_TRAFFIC_STR;
1074 GNUNET_CRYPTO_hkdf_expand (initial_ats, // result
1075 sizeof (*initial_ats), // result len
1076 ms,
1077 CAKE_LABEL, strlen (CAKE_LABEL),
1078 traffic_str,
1079 strlen (traffic_str),
1080 transcript,
1081 sizeof (*transcript),
1082 NULL));
1083}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), 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 call graph for this function:
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 1093 of file gnunet-service-core_kx.c.

1096{
1098 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1099
1100 ret = GNUNET_CRYPTO_hkdf_expand (&fk_R, // result
1101 sizeof (fk_R),
1102 ms,
1103 CAKE_LABEL, strlen (CAKE_LABEL),
1105 NULL);
1106 if (GNUNET_OK != ret)
1107 {
1109 "Something went wrong expanding fk_R\n");
1110 GNUNET_assert (0);
1111 }
1112
1113 GNUNET_CRYPTO_hmac (&fk_R,
1114 transcript,
1115 sizeof (*transcript),
1116 result);
1117}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), GNUNET_CRYPTO_hmac(), 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 1127 of file gnunet-service-core_kx.c.

1130{
1132 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1133
1134 ret = GNUNET_CRYPTO_hkdf_expand (&fk_I, // result
1135 sizeof (fk_I),
1136 ms,
1137 CAKE_LABEL, strlen (CAKE_LABEL),
1139 NULL);
1140 if (GNUNET_OK != ret)
1141 {
1143 "Something went wrong expanding fk_I\n");
1144 GNUNET_assert (0);
1145 }
1146 GNUNET_CRYPTO_hmac (&fk_I,
1147 transcript,
1148 sizeof (*transcript),
1149 result);
1150}

References CAKE_LABEL, GNUNET_assert, GNUNET_CRYPTO_hkdf_expand(), GNUNET_CRYPTO_hmac(), 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 1161 of file gnunet-service-core_kx.c.

1162{
1163 struct GSC_KeyExchangeInfo *kx = cls;
1164
1165 kx->resend_task = NULL;
1166 if (0 == kx->resend_tries_left)
1167 {
1169 "Restarting KX\n");
1170 restart_kx (kx);
1171 return;
1172 }
1173 kx->resend_tries_left--;
1175 "Resending responder hello. Retries left: %u\n",
1176 kx->resend_tries_left);
1180 kx);
1181}

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

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

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

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

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

1531{
1532 uint16_t size = ntohs (m->header.size);
1533
1534 if (size < sizeof (*m)
1535 + sizeof (struct InitiatorHelloPayload)
1537 {
1538 return GNUNET_SYSERR;
1539 }
1540 return GNUNET_OK;
1541}

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
  • replys with ResponderHello message
    Parameters
    clsthe key exchange info
    ihm_eInitiatorHello message

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

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

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

1665{
1666 struct GSC_KeyExchangeInfo *kx = cls;
1667
1668 kx->resend_task = NULL;
1669 if (0 == kx->resend_tries_left)
1670 {
1672 "Restarting KX\n");
1673 restart_kx (kx);
1674 return;
1675 }
1676 kx->resend_tries_left--;
1678 "Resending initiator done. Retries left: %u\n",
1679 kx->resend_tries_left);
1683 kx);
1684}

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

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

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

1869{
1870 uint16_t size = ntohs (m->header.size);
1871
1872 if (size < sizeof (*m)
1873 + sizeof (struct ResponderHelloPayload)
1874 + sizeof (struct GNUNET_HashCode)
1875 + AEAD_TAG_BYTES * 2)
1876 {
1877 return GNUNET_SYSERR;
1878 }
1879 return GNUNET_OK;
1880}

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

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

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

2050{
2051 uint16_t size = ntohs (m->header.size);
2052
2053 if (size < sizeof (*m) + sizeof (struct ConfirmationAck))
2054 {
2055 return GNUNET_SYSERR;
2056 }
2057 return GNUNET_OK;
2058}

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

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

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

2232{
2233 uint16_t size = ntohs (m->header.size) - sizeof(*m);
2234
2235 // TODO check (see check_encrypted ())
2236 // - check epoch
2237 // - check sequence number
2238 if (size < sizeof(struct GNUNET_MessageHeader))
2239 {
2240 GNUNET_break_op (0);
2241 return GNUNET_SYSERR;
2242 }
2243 return GNUNET_OK;
2244}

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

2255{
2256 struct GNUNET_ShortHashCode new_ats;
2257 struct ConfirmationAck ack;
2258
2260 {
2261 if (kx->current_epoch == UINT64_MAX)
2262 {
2264 "Max epoch reached (you probably will never see this)\n");
2265 }
2266 else
2267 {
2268 kx->current_epoch++;
2271 kx->current_sqn = 0;
2273 &new_ats);
2274 memcpy (&kx->current_ats,
2275 &new_ats,
2276 sizeof new_ats);
2277 }
2278 }
2279 update_timeout (kx);
2280 ack.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2281 ack.header.size = htons (sizeof ack);
2283 &ack,
2284 sizeof ack);
2285 if (NULL != kx->heartbeat_task)
2286 {
2290 kx);
2291 }
2292 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2293}

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

2300{
2301 struct GNUNET_MessageHeader *msg;
2302 struct ConfirmationAck *ack;
2303 struct Heartbeat *hb;
2304
2305 if (sizeof *msg > buf_len)
2306 return GNUNET_NO;
2307 msg = (struct GNUNET_MessageHeader*) buf;
2308 if (GNUNET_MESSAGE_TYPE_CORE_ACK == ntohs (msg->type))
2309 {
2310 ack = (struct ConfirmationAck *) buf;
2311 if (sizeof *ack != ntohs (ack->header.size))
2312 return GNUNET_NO;
2313 }
2314 else if (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT == ntohs (msg->type))
2315 {
2316 hb = (struct Heartbeat*) buf;
2317 if (sizeof *hb != ntohs (hb->header.size))
2318 return GNUNET_NO;
2319 handle_heartbeat (kx, hb);
2320 }
2321 else
2322 {
2323 return GNUNET_NO;
2324 }
2325
2330 {
2331 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2336 if (NULL != kx->resend_task)
2338 kx->resend_task = NULL;
2339 if (NULL != kx->resend_env)
2340 GNUNET_free (kx->resend_env);
2341 kx->resend_env = NULL;
2342 monitor_notify_all (kx);
2343 }
2344 update_timeout (kx);
2345
2346 return GNUNET_YES;
2347}

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

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

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

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

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

2572{
2573 struct GSC_KeyExchangeInfo *kx = cls;
2574
2575 kx->resend_task = NULL;
2577 "Resending initiator hello.\n");
2579 // FIXME (Exponential) backoff?
2582 kx);
2583}

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

2708{
2709 struct GNUNET_ShortHashCode new_ats;
2710
2711 if ((UINT64_MAX == kx->current_sqn) ||
2713 {
2715 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2716 ", incrementing epoch...\n",
2718 kx->current_sqn);
2719 // Can this trigger? Maybe if we receive a lot of
2720 // heatbeats?
2721 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2722 kx->current_epoch++;
2725 kx->current_sqn = 0;
2727 &new_ats);
2728 memcpy (&kx->current_ats,
2729 &new_ats,
2730 sizeof new_ats);
2731 }
2732}

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

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

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

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

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

2866{
2868 GNUNET_MQ_hd_var_size (initiator_hello,
2870 struct InitiatorHello,
2871 NULL),
2872 GNUNET_MQ_hd_var_size (initiator_done,
2874 struct InitiatorDone,
2875 NULL),
2876 GNUNET_MQ_hd_var_size (responder_hello,
2878 struct ResponderHello,
2879 NULL),
2880 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2882 struct EncryptedMessage,
2883 NULL),
2885 };
2886
2890 NULL); // TODO potentially wait
2891 // until we have a peer_id?
2892 // pay attention to whether
2893 // we have one anyways
2894 if (NULL == pils)
2895 {
2896 GSC_KX_done ();
2897 return GNUNET_SYSERR;
2898 }
2899
2901 transport =
2904 handlers,
2905 NULL, // cls - this connection-independant
2906 // cls seems not to be needed.
2907 // the connection-specific cls
2908 // will be set as a return value
2909 // of
2910 // handle_transport_notify_connect
2913 if (NULL == transport)
2914 {
2915 GSC_KX_done ();
2916 return GNUNET_SYSERR;
2917 }
2919 "Connected to TRANSPORT\n");
2920 return GNUNET_OK;
2921}

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

2929{
2930 struct PilsRequest *pr;
2931 while (NULL != (pr = pils_requests_head))
2932 {
2935 pr);
2936 if (NULL != pr->op)
2937 GNUNET_PILS_cancel (pr->op);
2938 GNUNET_free (pr);
2939 }
2940 if (NULL != pils)
2941 {
2943 pils = NULL;
2944 }
2945 if (NULL != transport)
2946 {
2948 transport = NULL;
2949 }
2950 if (NULL != rekey_task)
2951 {
2953 rekey_task = NULL;
2954 }
2955 if (NULL != nc)
2956 {
2958 nc = NULL;
2959 }
2960}

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

2971{
2972 return GNUNET_MQ_get_length (kxinfo->mq);
2973}

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

2978{
2979 return kxinfo->has_excess_bandwidth;
2980}

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

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

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().