GNUnet 0.26.2-114-g7c6b613e3
 
Loading...
Searching...
No Matches
gnunet-service-core_kx.c File Reference

TODO: More...

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

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Variables

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

Detailed Description

TODO:

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

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

Author
Christian Grothoff, ch3

Definition in file gnunet-service-core_kx.c.

Macro Definition Documentation

◆ DEBUG_KX

#define DEBUG_KX   0

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

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

◆ RESEND_MAX_TRIES

#define RESEND_MAX_TRIES   4

Number of times we try to resend a handshake flight.

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

◆ AEAD_KEY_BYTES

#define AEAD_KEY_BYTES   crypto_aead_xchacha20poly1305_ietf_KEYBYTES

libsodium has very long symbol names

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

◆ AEAD_NONCE_BYTES

#define AEAD_NONCE_BYTES   crypto_aead_xchacha20poly1305_ietf_NPUBBYTES

libsodium has very long symbol names

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

◆ AEAD_TAG_BYTES

#define AEAD_TAG_BYTES   crypto_aead_xchacha20poly1305_ietf_ABYTES

libsodium has very long symbol names

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

◆ RESEND_TIMEOUT

#define RESEND_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)

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

189{
190 /* Peer is supposed to initiate the key exchange */
191 ROLE_INITIATOR = 0,
192
193 /* Peer is supposed to wait for the key exchange */
194 ROLE_RESPONDER = 1,
195};
196
197
202{
207
212
217
221 struct GNUNET_MQ_Handle *mq;
222
227
232
233 // TODO check ordering - might make it less confusing
234 // TODO consistent naming: ss_e, shared_secret_e or ephemeral_shared_secret?
235 // TODO consider making all the structs here pointers
236 // - they can be checked to be NULL
237 // - valgrind can detect memory issues better (I guess?)
238
243 enum GSC_KX_Role role;
244
245 // TODO
249
254
259
266
272
277 struct GNUNET_ShortHashCode early_traffic_secret; /* Decrypts InitiatorHello */
278
284
290
296
302
307
312
316 uint64_t current_epoch;
317
322
327 uint64_t their_max_epoch;
328
332 uint64_t current_sqn;
333
338
343
348
352 unsigned int resend_tries_left;
353
359
365
370
375 enum GNUNET_CORE_PeerClass class;
376
377};
378
382struct PilsRequest
383{
387 struct PilsRequest *prev;
388
392 struct PilsRequest *next;
393
398};
399
403static struct PilsRequest *pils_requests_head;
404
408static struct PilsRequest *pils_requests_tail;
409
410
415
419static struct GSC_KeyExchangeInfo *kx_head;
420
424static struct GSC_KeyExchangeInfo *kx_tail;
425
430static struct GNUNET_SCHEDULER_Task *rekey_task;
431
435static struct GNUNET_NotificationContext *nc;
436
440static char *my_services_info = "";
441
442static void
443buffer_clear (void *buf, size_t len)
444{
445#if HAVE_MEMSET_S
446 memset_s (buf, len, 0, len);
447#elif HAVE_EXPLICIT_BZERO
448 explicit_bzero (buf, len);
449#else
450 volatile unsigned char *p = buf;
451 while (len--)
452 *p++ = 0;
453#endif
454}
455
456
457static void
459{
460 buffer_clear (&kx->ihts,
461 sizeof kx->ihts);
462 buffer_clear (&kx->rhts,
463 sizeof kx->rhts);
464 buffer_clear (&kx->sk_e,
465 sizeof kx->sk_e);
466 buffer_clear (&kx->ss_I,
467 sizeof kx->ss_I);
468 buffer_clear (&kx->ss_R,
469 sizeof kx->ss_R);
470 buffer_clear (&kx->ss_e,
471 sizeof kx->ss_e);
473 sizeof kx->master_secret);
475 sizeof kx->early_secret_key);
477 sizeof kx->early_traffic_secret);
479 sizeof kx->handshake_secret);
480}
481
482
483static void
484snapshot_transcript (const struct GNUNET_HashContext *ts_hash,
485 struct GNUNET_HashCode *snapshot)
486{
487 struct GNUNET_HashContext *tmp;
488
489 tmp = GNUNET_CRYPTO_hash_context_copy (ts_hash);
490 GNUNET_CRYPTO_hash_context_finish (tmp, snapshot);
491}
492
493
499static void
501{
503
505 msg.header.size = htons (sizeof(msg));
506 msg.state = htonl ((uint32_t) kx->status);
507 msg.peer = kx->peer;
508 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
511}
512
513
514static void
516
524static void
525send_heartbeat (void *cls)
526{
527 struct GSC_KeyExchangeInfo *kx = cls;
528 struct GNUNET_TIME_Relative retry;
529 struct GNUNET_TIME_Relative left;
530 struct Heartbeat hb;
531
532 kx->heartbeat_task = NULL;
534 if (0 == left.rel_value_us)
535 {
537 gettext_noop ("# sessions terminated by timeout"),
538 1,
539 GNUNET_NO);
540 GSC_SESSIONS_end (&kx->peer);
543 restart_kx (kx);
544 return;
545 }
547 "Sending HEARTBEAT to `%s'\n",
548 GNUNET_i2s (&kx->peer));
550 gettext_noop ("# heartbeat messages sent"),
551 1,
552 GNUNET_NO);
553 hb.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT);
554 hb.header.size = htons (sizeof hb);
555 // FIXME when do we request update?
556 hb.flags = 0;
557 GSC_KX_encrypt_and_transmit (kx, &hb, sizeof hb);
560 kx->heartbeat_task =
562}
563
564
572static void
574{
576
577 kx->timeout =
579 delta =
581 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
582 {
583 /* we only notify monitors about timeout changes if those
584 are bigger than the threshold (5s) */
586 }
587 if (NULL != kx->heartbeat_task)
592 kx);
593}
594
595
601static void
603
604
616static int
617deliver_message (void *cls, const struct GNUNET_MessageHeader *m)
618{
619 struct GSC_KeyExchangeInfo *kx = cls;
620
622 "Decrypted message of type %d from %s\n",
623 ntohs (m->type),
624 GNUNET_i2s (&kx->peer));
626 m,
627 ntohs (m->size),
630 m,
631 sizeof(struct GNUNET_MessageHeader),
633 return GNUNET_OK;
634}
635
636
637static void
639{
640 const struct GNUNET_HashCode *my_identity_hash;
641 struct GNUNET_HashCode h1;
642
643 // TODO what happens if we're in the middle of a peer id change?
644 // TODO there's a small chance this gets already called when we don't have a
645 // peer id yet. Add a kx, insert into the list, mark it as to be completed
646 // and let the callback to pils finish the rest once we got the peer id
647
649 "Initiating key exchange with peer %s\n",
650 GNUNET_i2s (&kx->peer));
652 gettext_noop ("# key exchanges initiated"),
653 1,
654 GNUNET_NO);
655
657 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
658 GNUNET_assert (NULL != my_identity_hash);
659 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
660 if (NULL != kx->transcript_hash_ctx)
662 kx->transcript_hash_ctx = NULL;
663 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, my_identity_hash))
664 {
665 /* peer with "lower" identity starts KX, otherwise we typically end up
666 with both peers starting the exchange and transmit the 'set key'
667 message twice */
669 "I am the initiator, sending hello\n");
670 kx->role = ROLE_INITIATOR;
672 }
673 else
674 {
675 /* peer with "higher" identity starts a delayed KX, if the "lower" peer
676 * does not start a KX since it sees no reasons to do so */
678 "I am the responder, yielding and await initiator hello\n");
680 kx->role = ROLE_RESPONDER;
682 }
683}
684
685
696static void *
698 const struct GNUNET_PeerIdentity *peer_id,
699 struct GNUNET_MQ_Handle *mq)
700{
701 const struct GNUNET_PeerIdentity *my_identity;
702 struct GSC_KeyExchangeInfo *kx;
703 (void) cls;
705 GNUNET_assert (NULL != my_identity);
706 if (0 == memcmp (peer_id, my_identity, sizeof *peer_id))
707 {
709 "Ignoring connection to self\n");
710 return NULL;
711 }
713 "Incoming connection of peer with %s\n",
715
716 /* Set up kx struct */
717 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
719 kx->mq = mq;
720 GNUNET_memcpy (&kx->peer, peer_id, sizeof (struct GNUNET_PeerIdentity));
722
723 restart_kx (kx);
724 return kx;
725}
726
727
767// TODO find a way to assert that a key is not yet existing before generating
768// TODO find a way to assert that a key is not already existing before using
769/*
770 * Derive early secret and transport secret.
771 * @param kx the key exchange info
772 */
773static void
774derive_es_ets (const struct GNUNET_HashCode *transcript,
775 const struct GNUNET_ShortHashCode *ss_R,
776 struct GNUNET_ShortHashCode *es,
777 struct GNUNET_ShortHashCode *ets)
778{
779 uint64_t ret;
780
781 ret = GNUNET_CRYPTO_hkdf_extract (es, // prk
782 0, // salt
783 0, // salt_len
784 ss_R, // ikm - initial key material
785 sizeof (*ss_R));
786 if (GNUNET_OK != ret)
787 {
788 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting ES\n")
789 ;
790 GNUNET_assert (0);
791 }
793 ets,
794 sizeof (*ets),
795 es,
798 GNUNET_CRYPTO_kdf_arg_auto (transcript));
799 if (GNUNET_OK != ret)
800 {
801 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
802 ;
803 GNUNET_assert (0);
804 }
805}
806
807
808/*
809 * Derive early secret and transport secret.
810 * @param kx the key exchange info
811 */
812static void
813derive_sn (const struct GNUNET_ShortHashCode *secret,
814 unsigned char*sn,
815 size_t sn_len)
816{
819 sn,
820 sn_len,
821 secret,
824}
825
826
831static void
832derive_hs (const struct GNUNET_ShortHashCode *es,
833 const struct GNUNET_ShortHashCode *ss_e,
835{
836 uint64_t ret;
837 struct GNUNET_ShortHashCode derived_early_secret;
838
839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deriving HS\n");
841 );
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ss_e: %s\n", GNUNET_B2S (ss_e));
844 &derived_early_secret,
845 sizeof (derived_early_secret),
846 es,
850 derived_early_secret));
851 if (GNUNET_OK != ret)
852 {
853 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dES\n")
854 ;
855 GNUNET_assert (0);
856 }
857 // Handshake secret
858 // TODO check: are dES the salt and ss_e the ikm or other way round?
859 ret = GNUNET_CRYPTO_hkdf_extract (handshake_secret, // prk
860 &derived_early_secret, // salt - dES
861 sizeof (derived_early_secret), // salt_len
862 ss_e, // ikm - initial key material
863 sizeof (*ss_e));
864 if (GNUNET_OK != ret)
865 {
866 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting HS\n")
867 ;
868 GNUNET_assert (0);
869 }
870}
871
872
877static void
878derive_ihts (const struct GNUNET_HashCode *transcript,
879 const struct GNUNET_ShortHashCode *hs,
880 struct GNUNET_ShortHashCode *ihts)
881{
884 ihts, // result
885 sizeof (*ihts), // result len
886 hs, // prk?
889 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
890}
891
892
897static void
898derive_rhts (const struct GNUNET_HashCode *transcript,
899 const struct GNUNET_ShortHashCode *hs,
900 struct GNUNET_ShortHashCode *rhts)
901{
904 rhts,
905 sizeof (*rhts),
906 hs, // prk? TODO
909 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
910}
911
912
917static void
918derive_ms (const struct GNUNET_ShortHashCode *hs,
919 const struct GNUNET_ShortHashCode *ss_I,
920 struct GNUNET_ShortHashCode *ms)
921{
922 uint64_t ret;
923 struct GNUNET_ShortHashCode derived_handshake_secret;
924
926 &derived_handshake_secret,
927 sizeof (derived_handshake_secret),
928 hs,
931 if (GNUNET_OK != ret)
932 {
933 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dHS\n")
934 ;
935 GNUNET_assert (0);
936 }
937 // TODO check: are dHS the salt and ss_I the ikm or other way round?
938 ret = GNUNET_CRYPTO_hkdf_extract (ms, // prk
939 &derived_handshake_secret, // salt - dHS
940 sizeof (derived_handshake_secret), // salt_len
941 ss_I, // ikm - initial key material
942 sizeof (*ss_I));
943 if (GNUNET_OK != ret)
944 {
945 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting MS\n")
946 ;
947 GNUNET_assert (0);
948 }
949}
950
951
957static void
959 uint64_t seq,
960 const uint8_t write_iv[AEAD_NONCE_BYTES],
961 uint8_t per_record_write_iv[AEAD_NONCE_BYTES])
962{
963 uint64_t seq_nbo;
964 uint64_t *write_iv_ptr;
965 unsigned int byte_offset;
966
967 seq_nbo = GNUNET_htonll (seq);
968 memcpy (per_record_write_iv,
969 write_iv,
971 byte_offset =
972 AEAD_NONCE_BYTES - sizeof (uint64_t);
973 write_iv_ptr = (uint64_t*) (write_iv + byte_offset);
974 *write_iv_ptr ^= seq_nbo;
975}
976
977
982static void
984 const struct GNUNET_ShortHashCode *ts,
985 uint64_t seq,
986 unsigned char key[AEAD_KEY_BYTES],
987 unsigned char nonce[AEAD_NONCE_BYTES])
988{
989 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
990 /* derive actual key */
993 key,
995 ts,
998
999 /* derive nonce */
1002 nonce_tmp,
1004 ts,
1008 nonce_tmp,
1009 nonce);
1010}
1011
1012
1017static void
1018derive_next_ats (const struct GNUNET_ShortHashCode *old_ats,
1019 struct GNUNET_ShortHashCode *new_ats)
1020{
1021 int8_t ret;
1022
1023 // FIXME: Not sure of PRK and output may overlap here!
1025 new_ats,
1026 sizeof (*new_ats),
1027 old_ats,
1030 if (GNUNET_OK != ret)
1031 {
1033 "Something went wrong deriving next *ATS key\n");
1034 GNUNET_assert (0);
1035 }
1036}
1037
1038
1043static void
1044derive_initial_ats (const struct GNUNET_HashCode *transcript,
1045 const struct GNUNET_ShortHashCode *ms,
1046 enum GSC_KX_Role role,
1047 struct GNUNET_ShortHashCode *initial_ats)
1048{
1049 const char *traffic_str;
1050
1051 if (ROLE_INITIATOR == role)
1052 traffic_str = I_AP_TRAFFIC_STR;
1053 else
1054 traffic_str = R_AP_TRAFFIC_STR;
1057 initial_ats, // result
1058 sizeof (*initial_ats), // result len
1059 ms,
1061 GNUNET_CRYPTO_kdf_arg_string (traffic_str),
1062 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
1063}
1064
1065
1072static void
1073generate_responder_finished (const struct GNUNET_HashCode *transcript,
1074 const struct GNUNET_ShortHashCode *ms,
1075 struct GNUNET_HashCode *result)
1076{
1078 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1079
1081 &fk_R, // result
1082 sizeof (fk_R),
1083 ms,
1086 if (GNUNET_OK != ret)
1087 {
1089 "Something went wrong expanding fk_R\n");
1090 GNUNET_assert (0);
1091 }
1092
1093 GNUNET_CRYPTO_hmac (&fk_R,
1094 transcript,
1095 sizeof (*transcript),
1096 result);
1097}
1098
1099
1106static void
1107generate_initiator_finished (const struct GNUNET_HashCode *transcript,
1108 const struct GNUNET_ShortHashCode *ms,
1109 struct GNUNET_HashCode *result)
1110{
1112 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1113
1115 &fk_I, // result
1116 sizeof (fk_I),
1117 ms,
1120 if (GNUNET_OK != ret)
1121 {
1123 "Something went wrong expanding fk_I\n");
1124 GNUNET_assert (0);
1125 }
1126 GNUNET_CRYPTO_hmac (&fk_I,
1127 transcript,
1128 sizeof (*transcript),
1129 result);
1130}
1131
1132
1133struct InitiatorHelloCtx
1134{
1135 struct GSC_KeyExchangeInfo *kx;
1136 struct InitiatorHello *ihm_e;
1137 struct PilsRequest *req;
1138};
1139
1140static void
1141resend_responder_hello (void *cls)
1142{
1143 struct GSC_KeyExchangeInfo *kx = cls;
1144
1145 kx->resend_task = NULL;
1146 if (0 == kx->resend_tries_left)
1147 {
1149 "Restarting KX\n");
1150 restart_kx (kx);
1151 return;
1152 }
1153 kx->resend_tries_left--;
1155 "Resending responder hello. Retries left: %u\n",
1156 kx->resend_tries_left);
1160 kx);
1161}
1162
1163
1164void
1166{
1169 struct ResponderHello *rhm_e; /* responder hello message - encrypted pointer */
1170 struct GNUNET_MQ_Envelope *env;
1171 struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_kem_challenge;
1172 struct GNUNET_ShortHashCode rhts;
1173 struct GNUNET_ShortHashCode ihts;
1174 struct GNUNET_ShortHashCode hs;
1175 struct GNUNET_ShortHashCode ms;
1176 struct GNUNET_ShortHashCode ss_e;
1177 struct GNUNET_ShortHashCode ss_I;
1178 struct GNUNET_HashContext *hc;
1179 unsigned char enc_key[AEAD_KEY_BYTES];
1180 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1181
1182 // 4. encaps -> shared_secret_e, c_e (kemChallenge)
1183 // TODO potentially write this directly into rhm?
1184 ret = GNUNET_CRYPTO_hpke_kem_encaps (&kx->pk_e, // public ephemeral key of initiator
1185 &ephemeral_kem_challenge, // encapsulated key
1186 &ss_e); // key - ss_e
1187 if (GNUNET_OK != ret)
1188 {
1190 "Something went wrong encapsulating ss_e\n");
1191 return;
1192 }
1194 // 6. encaps -> shared_secret_I, c_I
1195 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public key of I
1196 &c_I, // encapsulated key
1197 &ss_I); // where to write the key material
1198 if (GNUNET_OK != ret)
1199 {
1201 "Something went wrong encapsulating ss_I\n");
1203 return;
1204 }
1205 // 7. generate RHTS (responder_handshare_secret_key) and RATS (responder_application_traffic_secret_key) (section 5)
1206 {
1207 struct GNUNET_HashCode transcript;
1208 snapshot_transcript (hc, &transcript);
1209#if DEBUG_KX
1211 "Transcript snapshot for derivation of HS, MS: `%s'\n",
1212 GNUNET_h2s (&transcript));
1213#endif
1215 &ss_e,
1216 &hs);
1217 derive_ms (&hs, &ss_I, &ms);
1218 }
1219
1220 // send ResponderHello
1221 // TODO fill fields / services_info!
1222 // 1. r_R <- random
1223 struct ResponderHelloPayload *rhp;
1224 size_t rhp_len = sizeof (*rhp) + strlen (my_services_info);
1225 unsigned char rhp_buf[rhp_len];
1226 size_t ct_len;
1227
1228 rhp = (struct ResponderHelloPayload*) rhp_buf;
1229 ct_len = rhp_len // ResponderHelloPayload, fist PT msg
1230 + sizeof (struct GNUNET_HashCode) // Finished hash, second PT msg
1231 + AEAD_TAG_BYTES * 2; // Two tags;
1232 env = GNUNET_MQ_msg_extra (rhm_e,
1233 ct_len,
1235
1236 rhm_e->r_R =
1238 UINT64_MAX);
1239
1240 // c_e
1241 GNUNET_memcpy (&rhm_e->c_e,
1242 &ephemeral_kem_challenge,
1243 sizeof (ephemeral_kem_challenge));
1245 rhm_e,
1246 sizeof (struct ResponderHello));
1247 // 2. Encrypt ServicesInfo and c_I with RHTS
1248 // derive RHTS
1249 {
1250 struct GNUNET_HashCode transcript;
1252 &transcript);
1253#if DEBUG_KX
1255 "Transcript snapshot for derivation of *HTS: `%s'\n",
1256 GNUNET_h2s (&transcript));
1257#endif
1258 derive_rhts (&transcript,
1259 &hs,
1260 &rhts);
1261 derive_ihts (&transcript,
1262 &hs,
1263 &ihts);
1265 0,
1266 enc_key,
1267 enc_nonce);
1268 }
1269 // c_I
1270 GNUNET_memcpy (&rhp->c_I, &c_I, sizeof (c_I));
1271 // Services info empty for now.
1272 GNUNET_memcpy (&rhp[1],
1274 strlen (my_services_info));
1275
1276 {
1277 unsigned long long out_ct_len;
1279 struct GNUNET_HashCode transcript;
1280 unsigned char *finished_buf;
1281 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1282 (unsigned char*) &rhm_e[1], /* c - ciphertext */
1283 &out_ct_len, /* clen_p */
1284 rhp_buf, /* rhm_p - plaintext message */
1285 rhp_len, // mlen
1286 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1287 // fields?
1288 NULL, // nsec - unused
1289 enc_nonce, // npub - nonce // FIXME nonce can be reused
1290 enc_key)); // k - key RHTS
1292 "Encrypted and wrote %llu bytes\n",
1293 out_ct_len);
1294 // 3. Create ResponderFinished (Section 6)
1295 // Derive fk_I <- HKDF-Expand (MS, "r finished", NULL)
1296 /* Forward the transcript */
1297 /* {svcinfo, c_I}RHTS */
1299 hc,
1300 &rhm_e[1],
1301 out_ct_len);
1302
1303 finished_buf = ((unsigned char*) &rhm_e[1]) + out_ct_len;
1305 &transcript);
1306#if DEBUG_KX
1308 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1309 GNUNET_h2s (&transcript));
1310#endif
1311 generate_responder_finished (&transcript,
1312 &ms,
1313 &finished);
1314 // 4. Encrypt ResponderFinished
1316 1,
1317 enc_key,
1318 enc_nonce);
1319 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1320 finished_buf, /* c - ciphertext */
1321 &out_ct_len, /* clen_p */
1322 (unsigned char*) &finished, /* rhm_p - plaintext message */
1323 sizeof (finished), // mlen
1324 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1325 // fields?
1326 NULL, // nsec - unused
1327 enc_nonce, // npub
1328 enc_key)); // k - key RHTS
1330 "Encrypted and wrote %llu bytes\n",
1331 out_ct_len);
1332 /* Forward the transcript
1333 * after responder finished,
1334 * before deriving *ATS and generating finished_I
1335 * (finished_I will be generated when receiving the InitiatorFinished message
1336 * in order to check it) */
1338 hc,
1339 finished_buf,
1340 out_ct_len);
1341 // 5. optionally send application data - encrypted with RATS
1342 // We do not really have any application data, instead, we send the ACK
1344 &transcript);
1345#if DEBUG_KX
1347 "Transcript snapshot for derivation of *ATS: `%s'\n",
1348 GNUNET_h2s (&transcript));
1349#endif
1350 derive_initial_ats (&transcript,
1351 &ms,
1353 &kx->current_ats);
1354 }
1355 /* Lock into struct */
1357 kx->transcript_hash_ctx = hc;
1358 kx->master_secret = ms;
1359 kx->handshake_secret = hs;
1360 kx->ss_e = ss_e;
1361 kx->ihts = ihts;
1362 kx->rhts = rhts;
1363 kx->ss_I = ss_I;
1364 kx->current_epoch = 0;
1365 kx->current_sqn = 0;
1367 kx->current_sqn,
1368 enc_key,
1369 enc_nonce);
1370
1371 GNUNET_MQ_send_copy (kx->mq, env);
1372 kx->resend_env = env;
1374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent ResponderHello: %d %d\n", kx->role,
1375 kx->status);
1376
1379 kx);
1381 monitor_notify_all (kx);
1382 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1383}
1384
1385
1386static void
1387handle_initiator_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_R)
1388{
1389 const struct GNUNET_HashCode *my_identity_hash;
1390 struct InitiatorHelloCtx *ihm_ctx = cls;
1391 struct GSC_KeyExchangeInfo *kx = ihm_ctx->kx;
1392 uint32_t ihm_len = ntohs (ihm_ctx->ihm_e->header.size);
1393 unsigned char enc_key[AEAD_KEY_BYTES];
1394 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1395 struct GNUNET_HashCode h1;
1396 struct GNUNET_HashCode transcript;
1397 struct GNUNET_ShortHashCode es;
1398 struct GNUNET_ShortHashCode ets;
1400
1401 ihm_ctx->req->op = NULL;
1404 ihm_ctx->req);
1405 GNUNET_free (ihm_ctx->req);
1406
1407
1409 &ihm_ctx->ihm_e->pk_e,
1410 sizeof (ihm_ctx->ihm_e->pk_e));
1411 // 5. generate ETS (early_traffic_secret_key, decrypt pk_i
1412 // expand ETS <- expand ES <- extract ss_R
1413 // use ETS to decrypt
1414
1415 /* Forward the transcript hash context over the unencrypted fields to get it
1416 * to the same status that the initiator had when it needed to derive es and
1417 * ets for the encryption */
1420 ihm_ctx->ihm_e,
1421 sizeof (struct InitiatorHello));
1423 &transcript);
1424#if DEBUG_KX
1426 "Transcript snapshot for derivation of ES, ETS: `%s'\n",
1427 GNUNET_h2s (&transcript));
1428#endif
1429 derive_es_ets (&transcript, ss_R, &es, &ets);
1431 0,
1432 enc_key,
1433 enc_nonce);
1434 {
1435 struct InitiatorHelloPayload *ihmp;
1436 size_t ct_len = ihm_len - sizeof (struct InitiatorHello);
1437 unsigned char ihmp_buf[ct_len - AEAD_TAG_BYTES];
1438 ihmp = (struct InitiatorHelloPayload*) ihmp_buf;
1439 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1440 ihmp_buf, // unsigned char *m
1441 NULL, // mlen_p message length
1442 NULL, // unsigned char *nsec - unused: NULL
1443 (unsigned char*) &ihm_ctx->ihm_e[1], // const unsigned char *c - ciphertext
1444 ct_len, // unsigned long long clen - length of ciphertext
1445 // mac, // const unsigned char *mac - authentication tag
1446 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1447 0, // unsigned long long adlen
1448 enc_nonce, // const unsigned char *npub - nonce
1449 enc_key // const unsigned char *k - key
1450 );
1451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pid_sender: %s\n",
1452 GNUNET_i2s (&ihmp->pk_I));
1453 if (0 != ret)
1454 {
1456 "Something went wrong decrypting: %d\n", ret);
1457 GNUNET_break_op (0);
1458 GNUNET_free (ihm_ctx->ihm_e);
1459 GNUNET_free (ihm_ctx);
1460 restart_kx (kx);
1461 return;
1462 }
1463 /* now forward it considering the encrypted messages that the initiator was
1464 * able to send after deriving the es and ets */
1466 &ihm_ctx->ihm_e[1],
1467 ct_len);
1468 GNUNET_memcpy (&kx->peer,
1469 &ihmp->pk_I,
1470 sizeof (struct GNUNET_PeerIdentity));
1471 }
1472
1473 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
1474 GNUNET_assert (NULL != my_identity_hash);
1475
1476 // We could follow with the rest of the Key Schedule (dES, HS, ...) for now
1477 /* Check that we are actually in the receiving role */
1478 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
1479 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, my_identity_hash))
1480 {
1481 /* peer with "lower" identity starts KX, otherwise we typically end up
1482 with both peers starting the exchange and transmit the 'set key'
1483 message twice */
1484 /* Something went wrong - we have the lower value and should have sent the
1485 * InitiatorHello, but instead received it. TODO handle this case
1486 * We might end up in this case if the initiator didn't initiate the
1487 * handshake long enough and the 'responder' initiates the handshake */
1489 "Something went wrong - we have the lower value and should have sent the InitiatorHello, but instead received it.\n");
1490 GNUNET_free (ihm_ctx->ihm_e);
1491 GNUNET_free (ihm_ctx);
1493 kx->transcript_hash_ctx = NULL;
1494 return;
1495 }
1496
1497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer ID of other peer: %s\n", GNUNET_i2s
1498 (&kx->peer));
1499 /* We update the monitoring peers here because now we know
1500 * that we can decrypt the message AND know the PID
1501 */
1502 monitor_notify_all (kx);
1503 kx->ss_R = *ss_R;
1504 kx->early_secret_key = es;
1505 kx->early_traffic_secret = ets;
1507}
1508
1509
1510static int
1511check_initiator_hello (void *cls, const struct InitiatorHello *m)
1512{
1513 uint16_t size = ntohs (m->header.size);
1514
1515 if (size < sizeof (*m)
1516 + sizeof (struct InitiatorHelloPayload)
1518 {
1519 return GNUNET_SYSERR;
1520 }
1521 return GNUNET_OK;
1522}
1523
1524
1533static void
1534handle_initiator_hello (void *cls, const struct InitiatorHello *ihm_e)
1535{
1536 const struct GNUNET_HashCode *my_identity_hash;
1537 struct GSC_KeyExchangeInfo *kx = cls;
1538 struct InitiatorHelloCtx *initiator_hello_cls;
1539 size_t ihm_len;
1540
1541 if (ROLE_INITIATOR == kx->role)
1542 {
1543 GNUNET_break_op (0);
1545 "I am an initiator! Tearing down...\n");
1546 return;
1547 }
1549 {
1550 GNUNET_break_op (0);
1552 "Already received InitiatorHello: %d %d\n", kx->role, kx->status
1553 );
1554 return;
1555 }
1557 (NULL != kx->transcript_hash_ctx))
1558 {
1560 "Already received InitiatorHello and sent ResponderHello: %d %d\n",
1561 kx->role, kx->status);
1562 return;
1563 }
1564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorHello: %d %d\n", kx->
1565 role, kx->status);
1569
1571 gettext_noop ("# key exchanges initiated"),
1572 1,
1573 GNUNET_NO);
1574
1576
1577 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
1578 GNUNET_assert (NULL != my_identity_hash);
1579
1580 // 1. verify type _INITIATOR_HELLO
1581 // - This is implicytly done by arriving within this handler
1582 // - or is this about verifying the 'additional data' part of aead?
1583 // should it check the encryption + mac? (is this implicitly done
1584 // while decrypting?)
1585 // 2. verify H(pk_R) matches pk_R
1586 if (0 != memcmp (&ihm_e->h_pk_R,
1587 my_identity_hash,
1588 sizeof (struct GNUNET_HashCode)))
1589 {
1591 "This message is not meant for us (H(PID) mismatch)\n");
1593 kx->transcript_hash_ctx = NULL;
1594 return;
1595 }
1596 // FIXME this sometimes triggers in the tests - why?
1597 // 3. decaps -> shared_secret_R, c_R (kemChallenge)
1598 ihm_len = ntohs (ihm_e->header.size);
1599 initiator_hello_cls = GNUNET_new (struct InitiatorHelloCtx);
1600 initiator_hello_cls->kx = kx;
1601 initiator_hello_cls->ihm_e = GNUNET_malloc (ihm_len);
1602 GNUNET_memcpy (initiator_hello_cls->ihm_e, ihm_e, ihm_len);
1603 initiator_hello_cls->req = GNUNET_new (struct PilsRequest);
1606 initiator_hello_cls->req);
1607 initiator_hello_cls->req->op =
1609 &ihm_e->c_R,
1610 // encapsulated key
1612 // continuation
1613 initiator_hello_cls);
1614}
1615
1616
1617struct ResponderHelloCls
1618{
1619 /* Current KX session */
1620 struct GSC_KeyExchangeInfo *kx;
1621
1622 /* responder hello message - encrypted */
1623 struct ResponderHello rhm_e;
1624
1625 /* responder hello message - plain/decrypted */
1626 struct ResponderHelloPayload *rhp;
1627
1628 /* Decrypted finish hash */
1630
1631 /* Encrypted finished CT (for transcript later) */
1632 char finished_enc[sizeof (struct GNUNET_HashCode)
1633 + AEAD_TAG_BYTES];
1634
1635 /* Temporary transcript context */
1636 struct GNUNET_HashContext *hc;
1637
1638 /* Temporary handshake secret */
1639 struct GNUNET_ShortHashCode hs;
1640
1641 /* Temporary handshake secret */
1643
1644 /* Temporary handshake secret */
1646
1647 /* Temporary handshake secret */
1649
1650 /* Pending PILS request */
1651 struct PilsRequest *req;
1652};
1653
1654static void
1655resend_initiator_done (void *cls)
1656{
1657 struct GSC_KeyExchangeInfo *kx = cls;
1658
1659 kx->resend_task = NULL;
1660 if (0 == kx->resend_tries_left)
1661 {
1663 "Restarting KX\n");
1664 restart_kx (kx);
1665 return;
1666 }
1667 kx->resend_tries_left--;
1669 "Resending initiator done. Retries left: %u\n",
1670 kx->resend_tries_left);
1674 kx);
1675}
1676
1677
1678static void
1679handle_responder_hello_cont (void *cls, const struct GNUNET_ShortHashCode *ss_I)
1680{
1681 struct ResponderHelloCls *rh_ctx = cls;
1682 struct GSC_KeyExchangeInfo *kx = rh_ctx->kx;
1683 struct InitiatorDone *idm_e; /* encrypted */
1684 struct InitiatorDone idm_local;
1685 struct InitiatorDone *idm_p; /* plaintext */
1686 struct GNUNET_MQ_Envelope *env;
1687 unsigned char enc_key[AEAD_KEY_BYTES];
1688 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1689 struct ConfirmationAck ack_i;
1690 struct GNUNET_HashCode transcript;
1691 struct GNUNET_ShortHashCode ms;
1692
1693 rh_ctx->req->op = NULL;
1696 rh_ctx->req);
1697 GNUNET_free (rh_ctx->req);
1698 // XXX valgrind reports uninitialized memory
1699 // the following is a way to check whether this memory was meant
1700 // memset (&rhm_local, 0, sizeof (rhm_local)); - adapt to cls if still needed
1701 memset (&idm_local, 0, sizeof (idm_local));
1702
1703 kx->ss_I = *ss_I;
1704
1705 /* derive *ATS */
1706 derive_ms (&rh_ctx->hs, ss_I, &ms);;
1707 // 5. Create ResponderFinished as per Section 6 and check against decrypted payload.
1708 struct GNUNET_HashCode responder_finished;
1709 // Transcript updates, snapshot again
1710 snapshot_transcript (rh_ctx->hc,
1711 &transcript);
1712#if DEBUG_KX
1714 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1715 GNUNET_h2s (&transcript));
1716#endif
1717 generate_responder_finished (&transcript,
1718 &ms,
1719 &responder_finished);
1720 if (0 != memcmp (&rh_ctx->decrypted_finish,
1721 &responder_finished,
1722 sizeof (struct GNUNET_HashCode)))
1723 {
1725 "Could not verify \"responder finished\"\n");
1726 GNUNET_free (rh_ctx->rhp);
1728 GNUNET_free (rh_ctx);
1729 GNUNET_assert (0);
1730 return;
1731 }
1732
1733
1734 /* Forward the transcript
1735 * after generating finished_R,
1736 * before deriving *ATS */
1738 rh_ctx->hc,
1739 rh_ctx->finished_enc,
1740 sizeof (rh_ctx->finished_enc));
1741
1742 // At this point we cannot fail anymore and may lock into kx
1744 kx->transcript_hash_ctx = rh_ctx->hc;
1745 kx->ss_I = *ss_I;
1746 kx->handshake_secret = rh_ctx->hs;
1747 kx->ss_e = rh_ctx->ss_e;
1748 kx->ihts = rh_ctx->ihts;
1749 kx->rhts = rh_ctx->rhts;
1750 kx->master_secret = ms;
1751 GNUNET_free (rh_ctx->rhp);
1752 GNUNET_free (rh_ctx);
1753 rh_ctx = NULL;
1754
1756 &transcript);
1757#if DEBUG_KX
1759 "Transcript snapshot for derivation of *ATS: `%s'\n",
1760 GNUNET_h2s (&transcript));
1761#endif
1762 derive_initial_ats (&transcript,
1763 &kx->master_secret,
1765 &kx->their_ats[0]);
1766 for (int i = 0; i < MAX_EPOCHS - 1; i++)
1767 {
1768 derive_next_ats (&kx->their_ats[i],
1769 &kx->their_ats[i + 1]);
1770 }
1771 kx->their_max_epoch = MAX_EPOCHS - 1;
1772
1774 0,
1775 enc_key,
1776 enc_nonce);
1777 /* Create InitiatorDone message */
1778 idm_p = &idm_local; /* plaintext */
1779 env = GNUNET_MQ_msg_extra (idm_e,
1780 sizeof (ack_i)
1783 // 6. Create IteratorFinished as per Section 6.
1784 generate_initiator_finished (&transcript,
1785 &kx->master_secret,
1786 &idm_p->finished);
1788 "InteratorFinished: `%s'\n",
1789 GNUNET_h2s (&idm_p->finished));
1791 "Transcript `%s'\n",
1792 GNUNET_h2s (&transcript));
1793 // 7. Send InteratorFinished message encrypted with the key derived from IHTS to R
1794
1795 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1796 (unsigned char*) &idm_e->finished, /* c - ciphertext */
1797 NULL, /* clen_p */
1798 (unsigned char*) &idm_p->finished, /* idm_p - plaintext message */
1799 sizeof (idm_p->finished), // mlen
1800 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1801 // fields?
1802 NULL, // nsec - unused
1803 enc_nonce, // npub - nonce
1804 enc_key)); // k - key IHTS
1805 /* Forward the transcript hash context
1806 * after generating finished_I and RATS_0
1807 * before deriving IATS_0 */
1809 &idm_e->finished,
1810 sizeof (idm_e->finished)
1811 + AEAD_TAG_BYTES);
1813 &transcript);
1814#if DEBUG_KX
1816 "Transcript snapshot for derivation of *ATS: `%s'\n",
1817 GNUNET_h2s (&transcript));
1818#endif
1819 derive_initial_ats (&transcript,
1820 &kx->master_secret,
1822 &kx->current_ats);
1823 kx->current_epoch = 0;
1824 kx->current_sqn++;
1825 // 8. optionally encrypt payload TODO
1827 kx->current_sqn,
1828 enc_key,
1829 enc_nonce);
1830 kx->current_sqn++;
1831 ack_i.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
1832 ack_i.header.size = htons (sizeof ack_i);
1833 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1834 (unsigned char*) &idm_e[1], /* c - ciphertext */
1835 NULL, /* clen_p */
1836 (unsigned char*) &ack_i, /* rhm_p - plaintext message */
1837 sizeof ack_i, // mlen
1838 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1839 // fields?
1840 NULL, // nsec - unused
1841 enc_nonce, // npub - nonce // FIXME nonce can be reused
1842 enc_key)); // k - key RHTS
1843
1844 GNUNET_MQ_send_copy (kx->mq, env);
1845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent InitiatorDone: %d %d\n", kx->role,
1846 kx->status);
1847
1848
1849 kx->resend_env = env;
1853 kx);
1855 monitor_notify_all (kx);
1856 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1857}
1858
1859
1860static int
1861check_responder_hello (void *cls, const struct ResponderHello *m)
1862{
1863 uint16_t size = ntohs (m->header.size);
1864
1865 if (size < sizeof (*m)
1866 + sizeof (struct ResponderHelloPayload)
1867 + sizeof (struct GNUNET_HashCode)
1868 + AEAD_TAG_BYTES * 2)
1869 {
1870 return GNUNET_SYSERR;
1871 }
1872 return GNUNET_OK;
1873}
1874
1875
1881static void
1882handle_responder_hello (void *cls, const struct ResponderHello *rhm_e)
1883{
1884 struct GSC_KeyExchangeInfo *kx = cls;
1885 struct PilsRequest *req;
1886 struct ResponderHelloCls *rh_ctx;
1887 struct GNUNET_HashCode transcript;
1888 struct GNUNET_HashContext *hc;
1889 unsigned char enc_key[AEAD_KEY_BYTES];
1890 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1892
1893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ResponderHello: %d %d\n", kx->
1894 role, kx->status);
1895
1897 if (NULL != kx->resend_task)
1898 {
1900 kx->resend_task = NULL;
1901 }
1902 if (NULL != kx->resend_env)
1903 {
1904 GNUNET_free (kx->resend_env);
1905 kx->resend_env = NULL;
1906 }
1907
1908 /* Forward the transcript hash context */
1909 if (ROLE_RESPONDER == kx->role)
1910 {
1911 GNUNET_break_op (0);
1913 "I am the responder! Ignoring.\n");
1915 return;
1916 }
1918 rhm_e,
1919 sizeof (struct ResponderHello));
1920 // 1. Verify that the message type is CORE_RESPONDER_HELLO
1921 // - implicitly done by handling this message?
1922 // - or is this about verifying the 'additional data' part of aead?
1923 // should it check the encryption + mac? (is this implicitly done
1924 // while decrypting?)
1925 // 2. sse <- Decaps(ske,ce)
1926 rh_ctx = GNUNET_new (struct ResponderHelloCls);
1927 ret = GNUNET_CRYPTO_hpke_kem_decaps (&kx->sk_e, // secret/private ephemeral key of initiator (us)
1928 &rhm_e->c_e, // encapsulated key
1929 &rh_ctx->ss_e); // key - ss_e
1930 if (GNUNET_OK != ret)
1931 {
1933 "Something went wrong decapsulating ss_e\n");
1935 return;
1936 }
1937 // 3. Generate IHTS and RHTS from Section 5 and decrypt ServicesInfo, cI and ResponderFinished.
1938 snapshot_transcript (hc, &transcript);
1939#if DEBUG_KX
1941 "Transcript snapshot for derivation of HS, *HTS: `%s'\n",
1942 GNUNET_h2s (&transcript));
1943#endif
1945 &rh_ctx->ss_e,
1946 &rh_ctx->hs);
1947 derive_rhts (&transcript,
1948 &rh_ctx->hs,
1949 &rh_ctx->rhts);
1950 derive_ihts (&transcript,
1951 &rh_ctx->hs,
1952 &rh_ctx->ihts);
1954 0,
1955 enc_key,
1956 enc_nonce);
1957 rh_ctx->kx = kx;
1958 GNUNET_memcpy (&rh_ctx->rhm_e, rhm_e, sizeof (*rhm_e));
1959 {
1960 unsigned long long int c_len;
1961 unsigned char *finished_buf;
1962 // use RHTS to decrypt
1963 c_len = ntohs (rhm_e->header.size) - sizeof (*rhm_e)
1964 - sizeof (struct GNUNET_HashCode)
1965 - AEAD_TAG_BYTES; // finished ct
1966 rh_ctx->rhp = GNUNET_malloc (c_len
1967 -
1969 rh_ctx->hc = hc;
1970 finished_buf = ((unsigned char*) &rhm_e[1]) + c_len;
1971 /* Forward the transcript_hash_ctx
1972 * after rhts has been generated,
1973 * before generating finished_R*/
1975 hc,
1976 &rhm_e[1],
1977 c_len);
1978
1979 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1980 (unsigned char*) rh_ctx->rhp, // unsigned char *m
1981 NULL, // mlen_p message length
1982 NULL, // unsigned char *nsec - unused: NULL
1983 (unsigned char*) &rhm_e[1], // const unsigned char *c - ciphertext
1984 c_len, // unsigned long long clen - length of ciphertext
1985 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1986 0, // unsigned long long adlen
1987 enc_nonce, // const unsigned char *npub - nonce
1988 enc_key // const unsigned char *k - key
1989 );
1990 if (0 != ret)
1991 {
1993 "Something went wrong decrypting: %d\n", ret);
1994 GNUNET_free (rh_ctx->rhp);
1995 GNUNET_free (rh_ctx);
1997 return;
1998 }
1999 // FIXME nonce reuse (see encryption)
2001 1,
2002 enc_key,
2003 enc_nonce);
2004 c_len = sizeof (struct GNUNET_HashCode)
2006 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2007 (unsigned char*) &rh_ctx->decrypted_finish, // unsigned char *m
2008 NULL, // mlen_p message length
2009 NULL, // unsigned char *nsec - unused: NULL
2010 finished_buf, // const unsigned char *c - ciphertext
2011 c_len, // unsigned long long clen - length of ciphertext
2012 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2013 0, // unsigned long long adlen
2014 enc_nonce, // const unsigned char *npub - nonce
2015 enc_key // const unsigned char *k - key
2016 );
2017 if (0 != ret)
2018 {
2020 "Something went wrong decrypting finished field: %d\n", ret);
2021 GNUNET_free (rh_ctx->rhp);
2022 GNUNET_free (rh_ctx);
2024 return;
2025 }
2026 GNUNET_memcpy (rh_ctx->finished_enc,
2027 finished_buf,
2028 c_len);
2029 }
2030 // 4. ssI <- Decaps(skI,cI).
2031 req = GNUNET_new (struct PilsRequest);
2032 rh_ctx->req = req;
2035 req);
2037 &rh_ctx->rhp->c_I, // encapsulated key
2038 &handle_responder_hello_cont, // continuation
2039 rh_ctx);
2040}
2041
2042
2043static int
2044check_initiator_done (void *cls, const struct InitiatorDone *m)
2045{
2046 uint16_t size = ntohs (m->header.size);
2047
2048 if (size < sizeof (*m) + sizeof (struct ConfirmationAck))
2049 {
2050 return GNUNET_SYSERR;
2051 }
2052 return GNUNET_OK;
2053}
2054
2055
2061static void
2062handle_initiator_done (void *cls, const struct InitiatorDone *idm_e)
2063{
2064 struct GSC_KeyExchangeInfo *kx = cls;
2065 struct InitiatorDone idm_local;
2066 struct InitiatorDone *idm_p = &idm_local; /* plaintext */
2067 struct GNUNET_HashCode initiator_finished;
2068 struct GNUNET_HashCode transcript;
2069 struct GNUNET_ShortHashCode their_ats;
2070 struct GNUNET_HashContext *hc;
2071 unsigned char enc_key[AEAD_KEY_BYTES];
2072 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2073 struct ConfirmationAck ack_i;
2074 struct ConfirmationAck ack_r;
2075 int8_t ret;
2076
2077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorDone: %d %d\n", kx->
2078 role, kx->status);
2079 if (NULL != kx->resend_task)
2080 {
2082 kx->resend_task = NULL;
2083 }
2084 if (NULL != kx->resend_env)
2085 {
2086 GNUNET_free (kx->resend_env);
2087 kx->resend_env = NULL;
2088 }
2089 if (ROLE_INITIATOR == kx->role)
2090 {
2091 GNUNET_break_op (0);
2093 "I am the initiator! Tearing down...\n");
2094 return;
2095 }
2097 0,
2098 enc_key,
2099 enc_nonce);
2100 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2101 (unsigned char*) &idm_p->finished, // unsigned char *m
2102 NULL, // mlen_p message length
2103 NULL, // unsigned char *nsec - unused: NULL
2104 (unsigned char*) &idm_e->finished, // const unsigned char *c - ciphertext
2105 sizeof (idm_p->finished) // unsigned long long clen - length of ciphertext
2107 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2108 0, // unsigned long long adlen
2109 enc_nonce, // const unsigned char *npub - nonce
2110 enc_key // const unsigned char *k - key
2111 );
2112 if (0 != ret)
2113 {
2115 "Something went wrong decrypting: %d\n", ret);
2116 return;
2117 }
2118
2119 // - verify finished_I
2120 /* Generate finished_I
2121 * after Forwarding until {finished_R}RHTS
2122 * (did so while we prepared responder hello)
2123 * before forwarding to [{payload}RATS and] {finished_I}IHTS */
2124 // (look at the end of handle_initiator_hello())
2125 snapshot_transcript (kx->transcript_hash_ctx, &transcript);
2126 generate_initiator_finished (&transcript,
2127 &kx->master_secret,
2128 &initiator_finished);
2129 if (0 != memcmp (&idm_p->finished,
2130 &initiator_finished,
2131 sizeof (struct GNUNET_HashCode)))
2132 {
2134 "Could not verify \"initiator finished\" hash.\n");
2136 "Want: `%s'\n",
2137 GNUNET_h2s (&initiator_finished));
2139 "Have: `%s'\n",
2140 GNUNET_h2s (&idm_p->finished));
2142 "Transcript `%s'\n",
2143 GNUNET_h2s (&transcript));
2144 return;
2145 }
2146
2147 /* Forward the transcript hash_context_read */
2150 &idm_e->finished,
2151 sizeof (idm_e->finished)
2152 + AEAD_TAG_BYTES);
2153 snapshot_transcript (hc, &transcript);
2154 derive_initial_ats (&transcript,
2155 &kx->master_secret,
2157 &their_ats);
2158 derive_per_message_secrets (&their_ats, // FIXME other HS epoch?
2159 0,
2160 enc_key,
2161 enc_nonce);
2162 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2163 (unsigned char*) &ack_i, // unsigned char *m
2164 NULL, // mlen_p message length
2165 NULL, // unsigned char *nsec - unused: NULL
2166 (unsigned char*) &idm_e[1], // const unsigned char *c - ciphertext
2167 sizeof (ack_i) + AEAD_TAG_BYTES, // unsigned long long clen - length of ciphertext
2168 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2169 0, // unsigned long long adlen
2170 enc_nonce, // const unsigned char *npub - nonce
2171 enc_key // const unsigned char *k - key
2172 );
2173 if (0 != ret)
2174 {
2176 "Something went wrong decrypting the Ack: %d\n", ret);
2178 return;
2179 }
2180 if ((sizeof ack_i != ntohs (ack_i.header.size)) ||
2181 (GNUNET_MESSAGE_TYPE_CORE_ACK != ntohs (ack_i.header.type)))
2182 {
2184 "Ack invalid!\n");
2186 return;
2187 }
2188 GNUNET_memcpy (&kx->their_ats[0],
2189 &their_ats,
2190 sizeof their_ats);
2194 for (int i = 0; i < MAX_EPOCHS - 1; i++)
2195 {
2196 derive_next_ats (&kx->their_ats[i],
2197 &kx->their_ats[i + 1]);
2198 }
2200 kx->transcript_hash_ctx = hc;
2205 monitor_notify_all (kx);
2206 kx->current_sqn = 1;
2207 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2208 GNUNET_assert (NULL == kx->heartbeat_task);
2209 update_timeout (kx);
2210 ack_r.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2211 ack_r.header.size = htons (sizeof ack_r);
2213 &ack_r,
2214 sizeof ack_r);
2215
2216 GNUNET_TRANSPORT_core_receive_continue (transport,
2217 &kx->peer);
2218}
2219
2220
2226static int
2227check_encrypted_message (void *cls, const struct EncryptedMessage *m)
2228{
2229 uint16_t size = ntohs (m->header.size) - sizeof(*m);
2230
2231 // TODO check (see check_encrypted ())
2232 // - check epoch
2233 // - check sequence number
2234 if (size < sizeof(struct GNUNET_MessageHeader))
2235 {
2236 GNUNET_break_op (0);
2237 return GNUNET_SYSERR;
2238 }
2239 return GNUNET_OK;
2240}
2241
2242
2248static void
2250 const struct Heartbeat *m)
2251{
2252 struct GNUNET_ShortHashCode new_ats;
2253 struct ConfirmationAck ack;
2254
2256 {
2257 if (kx->current_epoch == UINT64_MAX)
2258 {
2260 "Max epoch reached (you probably will never see this)\n");
2261 }
2262 else
2263 {
2264 kx->current_epoch++;
2267 kx->current_sqn = 0;
2269 &new_ats);
2270 memcpy (&kx->current_ats,
2271 &new_ats,
2272 sizeof new_ats);
2273 }
2274 }
2275 update_timeout (kx);
2276 ack.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2277 ack.header.size = htons (sizeof ack);
2279 &ack,
2280 sizeof ack);
2281 if (NULL != kx->heartbeat_task)
2282 {
2286 kx);
2287 }
2288 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2289}
2290
2291
2292static enum GNUNET_GenericReturnValue
2294 const char *buf,
2295 size_t buf_len)
2296{
2297 struct GNUNET_MessageHeader *msg;
2298 struct ConfirmationAck *ack;
2299 struct Heartbeat *hb;
2300
2301 if (sizeof *msg > buf_len)
2302 return GNUNET_NO;
2303 msg = (struct GNUNET_MessageHeader*) buf;
2304 if (GNUNET_MESSAGE_TYPE_CORE_ACK == ntohs (msg->type))
2305 {
2306 ack = (struct ConfirmationAck *) buf;
2307 if (sizeof *ack != ntohs (ack->header.size))
2308 return GNUNET_NO;
2309 }
2310 else if (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT == ntohs (msg->type))
2311 {
2312 hb = (struct Heartbeat*) buf;
2313 if (sizeof *hb != ntohs (hb->header.size))
2314 return GNUNET_NO;
2315 handle_heartbeat (kx, hb);
2316 }
2317 else
2318 {
2319 return GNUNET_NO;
2320 }
2321
2326 {
2327 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2332 if (NULL != kx->resend_task)
2334 kx->resend_task = NULL;
2335 if (NULL != kx->resend_env)
2336 GNUNET_free (kx->resend_env);
2337 kx->resend_env = NULL;
2338 monitor_notify_all (kx);
2339 }
2340 update_timeout (kx);
2341
2342 return GNUNET_YES;
2343}
2344
2345
2351static void
2352handle_encrypted_message (void *cls, const struct EncryptedMessage *m)
2353{
2354 struct GSC_KeyExchangeInfo *kx = cls;
2355 uint16_t size = ntohs (m->header.size);
2356 char buf[size - sizeof (*m)] GNUNET_ALIGN;
2357 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2358 const unsigned char *seq_enc_nonce;
2359 unsigned char enc_key[AEAD_KEY_BYTES];
2360 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2361 struct GNUNET_ShortHashCode new_ats[MAX_EPOCHS];
2362 uint32_t seq_enc_ctr;
2363 uint64_t epoch;
2364 uint64_t m_seq;
2365 uint64_t m_seq_nbo;
2366 uint64_t c_len;
2367 int8_t ret;
2368
2369 // TODO look at handle_encrypted
2370 // - statistics
2371
2375 {
2376 GSC_SESSIONS_end (&kx->peer);
2378 monitor_notify_all (kx);
2379 restart_kx (kx);
2380 return;
2381 }
2382 update_timeout (kx);
2383 epoch = GNUNET_ntohll (m->epoch);
2388 memcpy (new_ats,
2389 kx->their_ats,
2390 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2391 // FIXME here we could introduce logic that sends heartbeats
2392 // with key update request if we have not seen a new
2393 // epoch after a while (e.g. EPOCH_EXPIRATION)
2394 if (kx->their_max_epoch < epoch)
2395 {
2400 if ((epoch - kx->their_max_epoch) > 2 * MAX_EPOCHS)
2401 {
2403 "Epoch %" PRIu64 " is too new, will not decrypt...\n",
2404 epoch);
2405 GSC_SESSIONS_end (&kx->peer);
2407 monitor_notify_all (kx);
2408 restart_kx (kx);
2409 return;
2410 }
2411 for (int i = kx->their_max_epoch; i < epoch; i++)
2412 {
2413 derive_next_ats (&new_ats[i % MAX_EPOCHS],
2414 &new_ats[(i + 1) % MAX_EPOCHS]);
2415 }
2416 }
2417 else if ((kx->their_max_epoch - epoch) > MAX_EPOCHS)
2418 {
2420 "Epoch %" PRIu64 " is too old, cannot decrypt...\n",
2421 epoch);
2422 return;
2423 }
2424 derive_sn (
2425 &new_ats[epoch % MAX_EPOCHS],
2426 seq_enc_k,
2427 sizeof seq_enc_k);
2428 /* compute the sequence number */
2429 seq_enc_ctr = *((uint32_t*) m->tag);
2430 seq_enc_nonce = &m->tag[sizeof (uint32_t)];
2431#if DEBUG_KX
2432 GNUNET_print_bytes (&new_ats[epoch % MAX_EPOCHS],
2433 sizeof (struct GNUNET_ShortHashCode),
2434 8,
2435 GNUNET_NO);
2436 GNUNET_print_bytes (seq_enc_k,
2437 sizeof seq_enc_k,
2438 8,
2439 GNUNET_NO);
2440 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2441 sizeof seq_enc_ctr,
2442 8,
2443 GNUNET_NO);
2444#endif
2445 crypto_stream_chacha20_ietf_xor_ic (
2446 (unsigned char*) &m_seq_nbo,
2447 (unsigned char*) &m->sequence_number,
2448 sizeof (uint64_t),
2449 seq_enc_nonce,
2450 ntohl (seq_enc_ctr),
2451 seq_enc_k);
2452 m_seq = GNUNET_ntohll (m_seq_nbo);
2454 "Received encrypted message in epoch %" PRIu64
2455 " with E(SQN=%" PRIu64 ")=%" PRIu64
2456 "\n",
2457 epoch,
2458 m_seq,
2459 m->sequence_number);
2460 /* We are the initiator and as we are going to receive,
2461 * we are using the responder key material */
2462 derive_per_message_secrets (&new_ats[epoch],
2463 m_seq,
2464 enc_key,
2465 enc_nonce);
2466 // TODO checking sequence numbers - handle the case of out-of-sync messages!
2467 // for now only decrypt the payload
2468 // TODO encrypt other fields, too!
2469 // TODO
2470 // c_len = size - offsetof ();
2471 c_len = size - sizeof (struct EncryptedMessage);
2472 ret = crypto_aead_xchacha20poly1305_ietf_decrypt_detached (
2473 (unsigned char*) buf, // m - plain message
2474 NULL, // nsec - unused
2475 (unsigned char*) &m[1], // c - ciphertext
2476 c_len, // clen
2477 (const unsigned char*) &m->tag, // mac
2478 NULL, // ad - additional data TODO
2479 0, // adlen
2480 enc_nonce, // npub
2481 enc_key // k
2482 );
2483 if (0 != ret)
2484 {
2486 "Something went wrong decrypting message\n");
2487 GNUNET_break_op (0); // FIXME handle gracefully
2488 return;
2489 }
2490 kx->their_max_epoch = epoch;
2491 memcpy (&kx->their_ats,
2492 new_ats,
2493 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2494
2496 buf,
2497 sizeof buf))
2498 {
2500 {
2502 "Dropping message as we are still waiting for handshake ACK\n");
2503 GNUNET_break_op (0);
2504 return;
2505 }
2506 if (GNUNET_OK !=
2508 buf,
2509 sizeof buf,
2510 GNUNET_YES,
2511 GNUNET_NO))
2512 GNUNET_break_op (0);
2513 }
2514 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2515}
2516
2517
2527static void
2529 const struct GNUNET_PeerIdentity *peer,
2530 void *handler_cls)
2531{
2532 struct GSC_KeyExchangeInfo *kx = handler_cls;
2533 (void) cls;
2534
2536 "Peer `%s' disconnected from us.\n",
2537 GNUNET_i2s (&kx->peer));
2538 GSC_SESSIONS_end (&kx->peer);
2540 gettext_noop ("# key exchanges stopped"),
2541 1,
2542 GNUNET_NO);
2543 if (NULL != kx->resend_task)
2544 {
2546 kx->resend_task = NULL;
2547 }
2548 if (NULL != kx->resend_env)
2549 {
2550 GNUNET_free (kx->resend_env);
2551 kx->resend_env = NULL;
2552 }
2553 if (NULL != kx->heartbeat_task)
2554 {
2556 kx->heartbeat_task = NULL;
2557 }
2559 monitor_notify_all (kx);
2560 if (kx->transcript_hash_ctx)
2561 {
2563 kx->transcript_hash_ctx = NULL;
2564 }
2566 GNUNET_MST_destroy (kx->mst);
2567 GNUNET_free (kx);
2568}
2569
2570
2571static void
2572resend_initiator_hello (void *cls)
2573{
2574 struct GSC_KeyExchangeInfo *kx = cls;
2575
2576 kx->resend_task = NULL;
2578 "Resending InitiatorHello.\n");
2580 // FIXME (Exponential) backoff?
2583 kx);
2584}
2585
2586
2592static void
2594{
2595 const struct GNUNET_PeerIdentity *my_identity;
2596 struct GNUNET_MQ_Envelope *env;
2597 struct GNUNET_ShortHashCode es;
2598 struct GNUNET_ShortHashCode ets;
2599 struct GNUNET_ShortHashCode ss_R;
2600 struct InitiatorHelloPayload *ihmp; /* initiator hello message - buffer on stack */
2601 struct InitiatorHello *ihm_e; /* initiator hello message - encrypted */
2602 long long unsigned int c_len;
2603 unsigned char enc_key[AEAD_KEY_BYTES];
2604 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2606 size_t pt_len;
2607
2609 GNUNET_assert (NULL != my_identity);
2610
2611 pt_len = sizeof (*ihmp) + strlen (my_services_info);
2612 c_len = pt_len + AEAD_TAG_BYTES;
2613 env = GNUNET_MQ_msg_extra (ihm_e,
2614 c_len,
2616 ihmp = (struct InitiatorHelloPayload*) &ihm_e[1];
2617 ihmp->peer_class = htons (GNUNET_CORE_CLASS_UNKNOWN); // TODO set this to a meaningful
2618 GNUNET_memcpy (&ihmp->pk_I,
2620 sizeof (struct GNUNET_PeerIdentity));
2621 GNUNET_CRYPTO_hash (&kx->peer, /* what to hash */ // TODO do we do this twice?
2622 sizeof (struct GNUNET_PeerIdentity),
2623 &ihm_e->h_pk_R); /* result */
2624 // TODO init hashcontext/transcript_hash
2625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send InitiatorHello: %d %d\n", kx->role,
2626 kx->status);
2627 GNUNET_assert (NULL == kx->transcript_hash_ctx);
2629 GNUNET_assert (NULL != kx->transcript_hash_ctx);
2630 // TODO fill services_info
2631
2632 // 1. Encaps
2633 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public ephemeral key of initiator
2634 &ihm_e->c_R, // encapsulated key
2635 &ss_R); // key - ss_R
2636 if (GNUNET_OK != ret)
2637 {
2639 "Something went wrong encapsulating ss_R\n");
2640 // TODO handle
2641 }
2642 // 2. generate rR (uint64_t) - is this the nonce? Naming seems not quite
2643 // consistent
2644 ihm_e->r_I =
2646 UINT64_MAX);
2647 // 3. generate sk_e/pk_e - ephemeral key
2650 &kx->sk_e.ecdhe_key,
2651 &kx->pk_e.ecdhe_key);
2652 GNUNET_memcpy (&ihm_e->pk_e,
2653 &kx->pk_e.ecdhe_key,
2654 sizeof (kx->pk_e.ecdhe_key));
2655 // 4. generate ETS to encrypt
2656 // generate ETS (early_traffic_secret_key, decrypt pk_i
2657 // expand ETS <- expand ES <- extract ss_R
2658 // use ETS to decrypt
2660 ihm_e,
2661 sizeof (struct InitiatorHello));
2662 {
2663 struct GNUNET_HashCode transcript;
2665 &transcript);
2666 derive_es_ets (&transcript,
2667 &ss_R,
2668 &es,
2669 &ets);
2671 0,
2672 enc_key,
2673 enc_nonce);
2674 }
2675 // 5. encrypt
2676
2677 ret = crypto_aead_xchacha20poly1305_ietf_encrypt (
2678 (unsigned char*) &ihm_e[1], /* c - ciphertext */
2679 // mac,
2680 // NULL, // maclen_p
2681 &c_len, /* clen_p */
2682 (unsigned char*) ihmp, /* m - plaintext message */
2683 pt_len, // mlen
2684 NULL, 0, // ad, adlen // FIXME maybe over the unencrypted header?
2685 // fields?
2686 NULL, // nsec - unused
2687 enc_nonce, // npub - nonce
2688 enc_key); // k - key
2689 if (0 != ret)
2690 {
2691 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong encrypting\n");
2693 kx->transcript_hash_ctx = NULL;
2695 return;
2696 }
2697 /* Forward the transcript */
2700 &ihm_e[1],
2701 c_len);
2702
2704 kx->early_secret_key = es;
2705 kx->early_traffic_secret = ets;
2706 kx->ss_R = ss_R;
2707 monitor_notify_all (kx);
2708 GNUNET_MQ_send_copy (kx->mq, env);
2709 kx->resend_env = env;
2713 kx);
2714}
2715
2716
2717static void
2719{
2720 struct GNUNET_ShortHashCode new_ats;
2721
2722 if ((UINT64_MAX == kx->current_sqn) ||
2724 {
2726 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2727 ", incrementing epoch...\n",
2729 kx->current_sqn);
2730 // Can this trigger? Maybe if we receive a lot of
2731 // heartbeats?
2732 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2733 kx->current_epoch++;
2736 kx->current_sqn = 0;
2738 &new_ats);
2739 memcpy (&kx->current_ats,
2740 &new_ats,
2741 sizeof new_ats);
2742 }
2743}
2744
2745
2752void
2754 const void *payload,
2755 size_t payload_size)
2756{
2757 struct GNUNET_MQ_Envelope *env;
2758 struct EncryptedMessage *encrypted_msg;
2759 unsigned char enc_key[AEAD_KEY_BYTES];
2760 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2761 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2762 uint64_t sqn;
2763 uint64_t epoch;
2764 int8_t ret;
2765
2766 encrypted_msg = NULL;
2767
2768 check_rekey (kx);
2769 sqn = kx->current_sqn;
2770 epoch = kx->current_epoch;
2771 /* We are the sender and as we are going to send,
2772 * we are using the initiator key material */
2774 sqn,
2775 enc_key,
2776 enc_nonce);
2777 kx->current_sqn++;
2778 derive_sn (&kx->current_ats,
2779 seq_enc_k,
2780 sizeof seq_enc_k);
2781 env = GNUNET_MQ_msg_extra (encrypted_msg,
2782 payload_size,
2784 // only encrypt the payload for now
2785 // TODO encrypt other fields as well
2786 ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached (
2787 (unsigned char*) &encrypted_msg[1], // c - resulting ciphertext
2788 (unsigned char*) &encrypted_msg->tag, // mac - resulting mac/tag
2789 NULL, // maclen
2790 (unsigned char*) payload, // m - plain message
2791 payload_size, // mlen
2792 NULL, // ad - additional data TODO also cover the unencrypted part (epoch)
2793 0, // adlen
2794 NULL, // nsec - unused
2795 enc_nonce, // npub nonce
2796 enc_key // k - key
2797 );
2798 if (0 != ret)
2799 {
2801 "Something went wrong encrypting message\n");
2802 GNUNET_assert (0);
2803 }
2804 {
2805 /* compute the sequence number */
2806 unsigned char *seq_enc_nonce;
2807 uint64_t seq_nbo;
2808 uint32_t seq_enc_ctr;
2809
2810 seq_nbo = GNUNET_htonll (sqn);
2811 seq_enc_ctr = *((uint32_t*) encrypted_msg->tag);
2812 seq_enc_nonce = &encrypted_msg->tag[sizeof (uint32_t)];
2813 crypto_stream_chacha20_ietf_xor_ic (
2814 (unsigned char*) &encrypted_msg->sequence_number,
2815 (unsigned char*) &seq_nbo,
2816 sizeof seq_nbo,
2817 seq_enc_nonce,
2818 ntohl (seq_enc_ctr),
2819 seq_enc_k);
2820#if DEBUG_KX
2821 GNUNET_print_bytes (seq_enc_k,
2822 sizeof seq_enc_k,
2823 8,
2824 GNUNET_NO);
2825 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2826 sizeof seq_enc_ctr,
2827 8,
2828 GNUNET_NO);
2829#endif
2831 "Sending encrypted message with E(SQN=%" PRIu64 ")=%" PRIu64
2832 "\n",
2833 sqn,
2834 encrypted_msg->sequence_number);
2835 }
2836 encrypted_msg->epoch = GNUNET_htonll (epoch);
2837
2838 // TODO actually copy payload
2839 GNUNET_MQ_send (kx->mq, env);
2840}
2841
2842
2843void
2844GSC_KX_start (void)
2845{
2846 const struct GNUNET_PeerIdentity *my_identity;
2848 GNUNET_MQ_hd_var_size (initiator_hello,
2850 struct InitiatorHello,
2851 NULL),
2852 GNUNET_MQ_hd_var_size (initiator_done,
2854 struct InitiatorDone,
2855 NULL),
2856 GNUNET_MQ_hd_var_size (responder_hello,
2858 struct ResponderHello,
2859 NULL),
2860 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2862 struct EncryptedMessage,
2863 NULL),
2865 };
2866
2868 GNUNET_assert (NULL != my_identity);
2869
2871 transport =
2874 handlers,
2875 NULL, // cls - this connection-independant
2876 // cls seems not to be needed.
2877 // the connection-specific cls
2878 // will be set as a return value
2879 // of
2880 // handle_transport_notify_connect
2883 if (NULL == transport)
2884 {
2885 GSC_KX_done ();
2886 return;
2887 }
2888
2890 "Connected to TRANSPORT\n");
2891
2893}
2894
2895
2896void
2897pid_change_cb (void *cls,
2898 const struct GNUNET_HELLO_Parser *parser,
2899 const struct GNUNET_HashCode *hash)
2900{
2901 if (NULL != transport)
2902 return;
2903
2904 GSC_KX_start ();
2905}
2906
2907
2913int
2914GSC_KX_init (void)
2915{
2918 NULL);
2919 if (NULL == GSC_pils)
2920 {
2921 GSC_KX_done ();
2922 return GNUNET_SYSERR;
2923 }
2924
2925 return GNUNET_OK;
2926}
2927
2928
2932void
2933GSC_KX_done ()
2934{
2935 struct PilsRequest *pr;
2936 while (NULL != (pr = pils_requests_head))
2937 {
2940 pr);
2941 if (NULL != pr->op)
2942 GNUNET_PILS_cancel (pr->op);
2943 GNUNET_free (pr);
2944 }
2945 if (NULL != GSC_pils)
2946 {
2948 GSC_pils = NULL;
2949 }
2950 if (NULL != transport)
2951 {
2953 transport = NULL;
2954 }
2955 if (NULL != rekey_task)
2956 {
2958 rekey_task = NULL;
2959 }
2960 if (NULL != nc)
2961 {
2963 nc = NULL;
2964 }
2965}
2966
2967
2974unsigned int
2976{
2977 return GNUNET_MQ_get_length (kxinfo->mq);
2978}
2979
2980
2981int
2983{
2984 return kxinfo->has_excess_bandwidth;
2985}
2986
2987
2996void
2998{
2999 struct GNUNET_MQ_Envelope *env;
3000 struct MonitorNotifyMessage *done_msg;
3001 struct GSC_KeyExchangeInfo *kx;
3002
3004 for (kx = kx_head; NULL != kx; kx = kx->next)
3005 {
3006 struct GNUNET_MQ_Envelope *env_notify;
3007 struct MonitorNotifyMessage *msg;
3008
3010 msg->state = htonl ((uint32_t) kx->status);
3011 msg->peer = kx->peer;
3012 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
3013 GNUNET_MQ_send (mq, env_notify);
3014 }
3016 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
3019}
3020
3021
3022/* end of gnunet-service-core_kx.c */
struct GNUNET_MQ_MessageHandlers handlers[]
Definition 003.c:1
struct GNUNET_MessageHeader * msg
Definition 005.c:2
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
#define GNUNET_CORE_OPTION_SEND_FULL_INBOUND
Client wants all inbound messages in full.
Definition core.h:53
#define GNUNET_CORE_OPTION_SEND_HDR_INBOUND
Client just wants the 4-byte message headers of all inbound messages.
Definition core.h:59
#define gettext_noop(String)
Definition gettext.h:74
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition gnunet-arm.c:103
static int ret
Final status code.
Definition gnunet-arm.c:93
static char * peer_id
Option –peer.
static bool finished
Set to true once we are finished and should exit after sending our final message to the parent.
struct GNUNET_HashCode key
The key used in the DHT.
static int result
Global testing status.
static struct GNUNET_PeerIdentity my_identity
Identity of this peer.
const struct GNUNET_CONFIGURATION_Handle * GSC_cfg
Our configuration.
void GSC_complete_initialization_cb(void)
This function is called from GSC_KX_init() once it got its peer id from pils.
void GSC_CLIENTS_deliver_message(const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *msg, uint16_t msize, uint32_t options)
Deliver P2P message to interested clients.
struct GNUNET_PILS_Handle * GSC_pils
For peer identity access.
struct GNUNET_STATISTICS_Handle * GSC_stats
For creating statistics.
#define RESEND_MAX_TRIES
Number of times we try to resend a handshake flight.
static void * handle_transport_notify_connect(void *cls, const struct GNUNET_PeerIdentity *peer_id, struct GNUNET_MQ_Handle *mq)
Function called by transport to notify us that a peer connected to us (on the network level).
static void cleanup_handshake_secrets(struct GSC_KeyExchangeInfo *kx)
unsigned int GSC_NEIGHBOURS_get_queue_length(const struct GSC_KeyExchangeInfo *kxinfo)
Check how many messages are queued for the given neighbour.
int GSC_NEIGHBOURS_check_excess_bandwidth(const struct GSC_KeyExchangeInfo *kxinfo)
Check if the given neighbour has excess bandwidth available.
static int check_initiator_hello(void *cls, const struct InitiatorHello *m)
static int check_responder_hello(void *cls, const struct ResponderHello *m)
static struct GSC_KeyExchangeInfo * kx_tail
DLL tail.
static int check_initiator_done(void *cls, const struct InitiatorDone *m)
void GSC_KX_handle_client_monitor_peers(struct GNUNET_MQ_Handle *mq)
Handle GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request.
static void generate_per_record_nonce(uint64_t seq, const uint8_t write_iv[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES], uint8_t per_record_write_iv[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES])
Generate per record nonce as per https://www.rfc-editor.org/rfc/rfc8446#section-5....
static void handle_responder_hello(void *cls, const struct ResponderHello *rhm_e)
Handle Responder Hello message.
static void send_heartbeat(void *cls)
Task triggered when a neighbour entry is about to time out (and we should prevent this by sending an ...
#define IV_STR
String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-sch...
#define AEAD_TAG_BYTES
libsodium has very long symbol names
#define I_AP_TRAFFIC_STR
String for expanding IATS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
void GSC_KX_start(void)
#define I_FINISHED_STR
String for expanding fk_I used for InitiatorFinished field (See https://lsd.gnunet....
static char * my_services_info
Our services info string TODO.
static void resend_responder_hello(void *cls)
static void handle_transport_notify_disconnect(void *cls, const struct GNUNET_PeerIdentity *peer, void *handler_cls)
Function called by transport telling us that a peer disconnected.
#define MAX_EPOCHS
Maximum number of epochs we keep on hand.
static void derive_ihts(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *hs, struct GNUNET_ShortHashCode *ihts)
Derive the initiator handshake secret.
#define R_FINISHED_STR
String for expanding fk_R used for ResponderFinished field (See https://lsd.gnunet....
static void derive_initial_ats(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, enum GSC_KX_Role role, struct GNUNET_ShortHashCode *initial_ats)
Derive the initiator application secret.
static struct GNUNET_NotificationContext * nc
Notification context for broadcasting to monitors.
#define AEAD_NONCE_BYTES
libsodium has very long symbol names
void GSC_KX_encrypt_and_transmit(struct GSC_KeyExchangeInfo *kx, const void *payload, size_t payload_size)
Encrypt and transmit payload.
static struct PilsRequest * pils_requests_head
PILS Operation DLL.
static void check_rekey(struct GSC_KeyExchangeInfo *kx)
#define R_AP_TRAFFIC_STR
String for expanding RATS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
static void derive_next_ats(const struct GNUNET_ShortHashCode *old_ats, struct GNUNET_ShortHashCode *new_ats)
Derive the next application secret.
static void buffer_clear(void *buf, size_t len)
static void derive_per_message_secrets(const struct GNUNET_ShortHashCode *ts, uint64_t seq, unsigned char key[crypto_aead_xchacha20poly1305_ietf_KEYBYTES], unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES])
key = HKDF-Expand [I,R][A,H]TS, "key", 32) nonce = HKDF-Expand ([I,R][A,H]TS, "iv",...
static void derive_rhts(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *hs, struct GNUNET_ShortHashCode *rhts)
Derive the responder handshake secret.
static void generate_responder_finished(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, struct GNUNET_HashCode *result)
Generate the responder finished field.
static void handle_responder_hello_cont(void *cls, const struct GNUNET_ShortHashCode *ss_I)
static struct GSC_KeyExchangeInfo * kx_head
DLL head.
#define AEAD_KEY_BYTES
libsodium has very long symbol names
GSC_KX_Role
Indicates whether a peer is in the initiating or receiving role.
static void generate_initiator_finished(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ms, struct GNUNET_HashCode *result)
Generate the initiator finished field.
static struct PilsRequest * pils_requests_tail
PILS Operation DLL.
static void snapshot_transcript(const struct GNUNET_HashContext *ts_hash, struct GNUNET_HashCode *snapshot)
static void derive_sn(const struct GNUNET_ShortHashCode *secret, unsigned char *sn, size_t sn_len)
#define MIN_HEARTBEAT_FREQUENCY
What is the minimum frequency for a heartbeat message?
void GSC_KX_done()
Shutdown KX subsystem.
static void derive_ms(const struct GNUNET_ShortHashCode *hs, const struct GNUNET_ShortHashCode *ss_I, struct GNUNET_ShortHashCode *ms)
Derive the master secret.
#define KEY_STR
String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-sch...
static void update_timeout(struct GSC_KeyExchangeInfo *kx)
We've seen a valid message from the other peer.
static void derive_hs(const struct GNUNET_ShortHashCode *es, const struct GNUNET_ShortHashCode *ss_e, struct GNUNET_ShortHashCode *handshake_secret)
Derive the handshake secret.
static void send_initiator_hello(struct GSC_KeyExchangeInfo *kx)
Send initiator hello.
#define I_HS_TRAFFIC_STR
String for expanding IHTS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
#define EARLY_DATA_STR
String for expanding early transport secret (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
static void handle_initiator_hello(void *cls, const struct InitiatorHello *ihm_e)
Handle the InitiatorHello message.
static void handle_encrypted_message(void *cls, const struct EncryptedMessage *m)
handle an encrypted message
static void derive_es_ets(const struct GNUNET_HashCode *transcript, const struct GNUNET_ShortHashCode *ss_R, struct GNUNET_ShortHashCode *es, struct GNUNET_ShortHashCode *ets)
TODO propose a new scheme: don't choose an initiator and responder based on hashing the peer ids,...
static int deliver_message(void *cls, const struct GNUNET_MessageHeader *m)
Deliver P2P message to interested clients.
static enum GNUNET_GenericReturnValue check_if_ack_or_heartbeat(struct GSC_KeyExchangeInfo *kx, const char *buf, size_t buf_len)
#define DERIVED_STR
String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-sch...
static int check_encrypted_message(void *cls, const struct EncryptedMessage *m)
Check an incoming encrypted message before handling it.
static void resend_initiator_hello(void *cls)
#define EPOCH_EXPIRATION
How often do we rekey/switch to a new epoch?
static void resend_initiator_done(void *cls)
static void monitor_notify_all(struct GSC_KeyExchangeInfo *kx)
Inform all monitors about the KX state of the given peer.
static struct GNUNET_SCHEDULER_Task * rekey_task
Task scheduled for periodic re-generation (and thus rekeying) of our ephemeral key.
void pid_change_cb(void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *hash)
#define CAKE_LABEL
Labeled expand label for CAKE.
int GSC_KX_init(void)
Initialize KX subsystem.
static void restart_kx(struct GSC_KeyExchangeInfo *kx)
static void handle_initiator_hello_cont(void *cls, const struct GNUNET_ShortHashCode *ss_R)
static struct GNUNET_TRANSPORT_CoreHandle * transport
Transport service.
static void handle_heartbeat(struct GSC_KeyExchangeInfo *kx, const struct Heartbeat *m)
Handle a key update.
static void handle_initiator_done(void *cls, const struct InitiatorDone *idm_e)
Handle InitiatorDone message.
#define R_HS_TRAFFIC_STR
String for expanding RHTS (See https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
void send_responder_hello(struct GSC_KeyExchangeInfo *kx)
#define RESEND_TIMEOUT
#define TRAFFIC_UPD_STR
String for expanding derived keys (Handshake and Early) (See https://lsd.gnunet.org/lsd0012/draft-sch...
@ GSC_HEARTBEAT_KEY_UPDATE_REQUESTED
A key update is requested.
void GSC_SESSIONS_end(const struct GNUNET_PeerIdentity *pid)
End the session with the given peer (we are no longer connected).
void GSC_SESSIONS_create(const struct GNUNET_PeerIdentity *peer, struct GSC_KeyExchangeInfo *kx, enum GNUNET_CORE_PeerClass class)
Create a session, a key exchange was just completed.
static unsigned long long payload
How much data are we currently storing in the database?
static struct GNUNET_Process * p
Helper process we started.
Definition gnunet-uri.c:38
struct GNUNET_PILS_Handle * GNUNET_PILS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PILS_PidChangeCallback pid_change_cb, void *cls)
Connect to the PILS service.
Definition pils_api.c:465
void GNUNET_PILS_disconnect(struct GNUNET_PILS_Handle *handle)
Disconnect from the PILS service.
Definition pils_api.c:488
const struct GNUNET_HashCode * GNUNET_PILS_get_identity_hash(const struct GNUNET_PILS_Handle *handle)
Return the hash of the current peer identity from a given handle.
Definition pils_api.c:736
void GNUNET_PILS_cancel(struct GNUNET_PILS_Operation *op)
Cancel request.
Definition pils_api.c:623
const struct GNUNET_PeerIdentity * GNUNET_PILS_get_identity(const struct GNUNET_PILS_Handle *handle)
Return the current peer identity of a given handle.
Definition pils_api.c:727
struct GNUNET_PILS_Operation * GNUNET_PILS_kem_decaps(struct GNUNET_PILS_Handle *handle, const struct GNUNET_CRYPTO_HpkeEncapsulation *c, GNUNET_PILS_DecapsResultCallback cb, void *cb_cls)
Decaps an encapsulated key with our private key.
Definition pils_api.c:568
struct GNUNET_TRANSPORT_CoreHandle * GNUNET_TRANSPORT_core_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *self, const struct GNUNET_MQ_MessageHandler *handlers, void *cls, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd)
Connect to the transport service.
void GNUNET_TRANSPORT_core_disconnect(struct GNUNET_TRANSPORT_CoreHandle *handle)
Disconnect from the transport service.
#define GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
After how long do we consider a connection to a peer dead if we don't receive messages from the peer?
GNUNET_CORE_PeerClass
The peer class gives a hint about the capabilities of a peer.
GNUNET_CORE_KxState
TODO how does this harmonize with CAKE_CRYPTO_ENABLED?
@ GNUNET_CORE_CLASS_UNKNOWN
The device's capabilities are currently unknown.
@ GNUNET_CORE_KX_PEER_DISCONNECT
Last state of a KX (when it is being terminated).
@ GNUNET_CORE_KX_STATE_RESPONDER_CONNECTED
Connected as responder.
@ GNUNET_CORE_KX_STATE_DOWN
No handshake yet.
@ GNUNET_CORE_KX_STATE_INITIATOR_DONE_SENT
We sent initiator done.
@ GNUNET_CORE_KX_STATE_INITIATOR_HELLO_RECEIVED
We've received the initiator hello.
@ GNUNET_CORE_KX_STATE_AWAIT_INITIATION
We are awating the initiator hello.
@ GNUNET_CORE_KX_STATE_INITIATOR_CONNECTED
Connected as initiator.
@ GNUNET_CORE_KX_STATE_INITIATOR_HELLO_SENT
We sent the initiator hello.
@ GNUNET_CORE_KX_STATE_RESPONDER_HELLO_SENT
We sent the responder hello.
@ GNUNET_CORE_KX_ITERATION_FINISHED
This is not a state in a peer's state machine, but a special value used with the GNUNET_CORE_MonitorC...
void GNUNET_CRYPTO_ecdhe_key_create(struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
Create a new private key.
Definition crypto_ecc.c:454
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hpke_kem_decaps(const struct GNUNET_CRYPTO_HpkePrivateKey *priv, const struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Decapsulate a key for a private X25519 key.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hpke_kem_encaps(const struct GNUNET_CRYPTO_HpkePublicKey *pkR, struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Encapsulate key material for a X25519 public key.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_eddsa_kem_encaps(const struct GNUNET_CRYPTO_EddsaPublicKey *pub, struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Encapsulate key material for a EdDSA public key.
void GNUNET_CRYPTO_ecdhe_key_get_public(const struct GNUNET_CRYPTO_EcdhePrivateKey *priv, struct GNUNET_CRYPTO_EcdhePublicKey *pub)
Extract the public key for the given private key.
Definition crypto_ecc.c:217
@ GNUNET_CRYPTO_QUALITY_NONCE
Randomness for IVs etc.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hkdf_extract(struct GNUNET_ShortHashCode *prk, const void *salt, size_t salt_len, const void *ikm, size_t ikm_len)
HKDF-Extract using SHA256.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:41
void GNUNET_CRYPTO_hmac(const struct GNUNET_CRYPTO_AuthKey *key, const void *plaintext, size_t plaintext_len, struct GNUNET_HashCode *hmac)
Calculate HMAC of a message (RFC 2104)
#define GNUNET_CRYPTO_hkdf_expand(result, out_len, prk,...)
HKDF-Expand using SHA256.
int GNUNET_CRYPTO_hash_cmp(const struct GNUNET_HashCode *h1, const struct GNUNET_HashCode *h2)
Compare function for HashCodes, producing a total ordering of all hashcodes.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_B2S(obj)
Convert a fixed-sized object to a string using GNUNET_b2s().
void GNUNET_CRYPTO_hash_context_read(struct GNUNET_HashContext *hc, const void *buf, size_t size)
Add data to be hashed.
struct GNUNET_HashContext * GNUNET_CRYPTO_hash_context_copy(const struct GNUNET_HashContext *hc)
Make a copy of the hash computation.
#define GNUNET_CRYPTO_kdf_arg_string(d)
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
void * cls
Closure for mv and cb.
void GNUNET_CRYPTO_hash_context_abort(struct GNUNET_HashContext *hc)
Abort hashing, do not bother calculating final result.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
void GNUNET_CRYPTO_hash_context_finish(struct GNUNET_HashContext *hc, struct GNUNET_HashCode *r_hash)
Finish the hash computation.
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_CRYPTO_kdf_arg_auto(d)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
struct GNUNET_HashContext * GNUNET_CRYPTO_hash_context_start(void)
Start incremental hashing operation.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
void GNUNET_print_bytes(const void *buf, size_t buf_len, int fold, int in_be)
Print a byte string in hexadecimal ascii notation.
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition nc.c:138
void GNUNET_MQ_send_copy(struct GNUNET_MQ_Handle *mq, const struct GNUNET_MQ_Envelope *ev)
Send a copy of a message with the given message queue.
Definition mq.c:384
unsigned int GNUNET_MQ_get_length(struct GNUNET_MQ_Handle *mq)
Obtain the current length of the message queue.
Definition mq.c:293
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:305
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
void GNUNET_MQ_discard(struct GNUNET_MQ_Envelope *mqm)
Discard the message queue message, free all allocated resources.
Definition mq.c:285
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition nc.c:122
void GNUNET_notification_context_broadcast(struct GNUNET_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop)
Send a message to all subscribers of this context.
Definition nc.c:190
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition nc.c:161
#define GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT
Message updating the keys of the peers.
#define GNUNET_MESSAGE_TYPE_CORE_ACK
Acknowledgement of prior messages.
#define GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE_CAKE
Encrypted message.
#define GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY
Reply for monitor by CORE service.
#define GNUNET_MESSAGE_TYPE_CORE_INITIATOR_DONE
Third and final message of the handshake, second of the initiator.
#define GNUNET_MESSAGE_TYPE_CORE_RESPONDER_HELLO
Reply to the first message from the initiator - first message sent by the responder.
#define GNUNET_MESSAGE_TYPE_CORE_INITIATOR_HELLO
for more detail on the following messages see https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1283
enum GNUNET_GenericReturnValue GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition mst.c:101
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition mst.c:86
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition mst.c:404
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_max(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the maximum of two relative time values.
Definition time.c:352
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition time.c:406
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition time.c:316
struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Divide relative time by a given factor.
Definition time.c:548
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_difference(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute end)
Compute the time difference between the given start and end times.
Definition time.c:423
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:636
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition time.c:667
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
static unsigned int size
Size of the "table".
Definition peer.c:68
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
struct GNUNET_MessageHeader header
Message type is GNUNET_MESSAGE_TYPE_CORE_ACK.
type for (message) authentication keys
HPKE DHKEM encapsulation (X25519) See RFC 9180.
A public key used for decryption.
struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_key
An ECDHE/X25519 key.
A public key used for encryption.
struct GNUNET_CRYPTO_EcdhePublicKey ecdhe_key
An ECDHE/X25519 key.
Context for parsing HELLOs.
Definition hello-uri.c:233
A 512-bit hashcode.
Handle to a message queue.
Definition mq.c:87
Message handler for a specific message type.
Header for all communications.
Handle to a message stream tokenizer.
Definition mst.c:45
The notification context is the key datastructure for a convenience API used for transmission of noti...
Definition nc.c:77
The identity of the host (wraps the signing key of the peer).
struct GNUNET_CRYPTO_EddsaPublicKey public_key
Entry in list of pending tasks.
Definition scheduler.c:141
A 256-bit hashcode.
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
Handle for the transport service (includes all of the state for the transport service).
Information about the status of a key exchange with another peer.
struct GSC_KeyExchangeInfo * prev
DLL.
struct GNUNET_ShortHashCode their_ats[10]
*ATS - other peers application traffic secret by epoch
struct GNUNET_ShortHashCode ss_R
struct GNUNET_ShortHashCode ihts
IHTS - Initiator handshake secret TODO.
struct GNUNET_TIME_Absolute current_epoch_expiration
Expiration time of our current epoch.
struct GNUNET_ShortHashCode early_secret_key
ES - Early Secret Key TODO uniform naming: _key?
struct GNUNET_ShortHashCode master_secret
Master secret key TODO.
uint64_t current_sqn
Our current sequence number.
struct GNUNET_TIME_Absolute last_notify_timeout
Last time we notified monitors.
enum GSC_KX_Role role
Own role in the key exchange.
struct GNUNET_MessageStreamTokenizer * mst
Our message stream tokenizer (for encrypted payload).
struct GSC_KeyExchangeInfo * next
DLL.
struct GNUNET_CRYPTO_HpkePrivateKey sk_e
Initiator secret key.
unsigned int resend_tries_left
Resend tries left.
struct GNUNET_SCHEDULER_Task * resend_task
Task for resending messages during handshake.
struct GNUNET_PeerIdentity peer
Identity of the peer.
struct GNUNET_MQ_Handle * mq
Message queue for sending messages to peer.
struct GNUNET_ShortHashCode early_traffic_secret
ETS - Early traffic secret TODO.
uint64_t their_max_epoch
Highest seen (or used) epoch of responder resp initiator.
struct GNUNET_TIME_Absolute timeout
When should the session time out (if there are no Acks to HEARTBEATs)?
struct GNUNET_MQ_Envelope * resend_env
Env for resending messages.
struct GNUNET_ShortHashCode rhts
RHTS - Responder handshake secret TODO.
struct GNUNET_ShortHashCode ss_I
struct GNUNET_ShortHashCode handshake_secret
HS - Handshake secret TODO.
struct GNUNET_ShortHashCode ss_e
int has_excess_bandwidth
GNUNET_YES if this peer currently has excess bandwidth.
enum GNUNET_CORE_KxState status
What is our connection state?
struct GNUNET_CRYPTO_HpkePublicKey pk_e
Initiator ephemeral key.
struct GNUNET_HashContext * transcript_hash_ctx
The transcript hash context.
uint64_t current_epoch
Our currently used epoch for sending.
enum GNUNET_CORE_PeerClass class
Peer class of the other peer TODO still needed?
struct GNUNET_ShortHashCode current_ats
*ATS - our current application traffic secret by epoch
struct GNUNET_SCHEDULER_Task * heartbeat_task
ID of task used for sending keep-alive pings.
struct GNUNET_MessageHeader header
Message type is #GNUNET_MESSAGE_TYPE_CORE_PONG.
struct GNUNET_HashCode finished
TODO {Finished} - encrypted.
struct PilsRequest * req
struct InitiatorHello * ihm_e
struct GSC_KeyExchangeInfo * kx
struct GNUNET_PeerIdentity pk_I
Sender Peer ID.
uint16_t peer_class
The peer class of the sending peer TODO part of services info?
uint64_t r_I
Random number to make replay attacks harder.
struct GNUNET_CRYPTO_EcdhePublicKey pk_e
Ephemeral public edx25519 key.
struct GNUNET_CRYPTO_HpkeEncapsulation c_R
Key encapsulation.
struct GNUNET_MessageHeader header
Message type is #GNUNET_MESSAGE_TYPE_CORE_PONG.
struct GNUNET_HashCode h_pk_R
Hash of the responder peer id.
Message sent by the service to monitor clients to notify them about a peer changing status.
Definition core.h:313
uint32_t state
New peer state, an enum GNUNET_CORE_KxState in NBO.
Definition core.h:322
struct GNUNET_TIME_AbsoluteNBO timeout
How long will we stay in this state (if nothing else happens)?
Definition core.h:332
struct GNUNET_PILS_Operation * op
The pils operation.
struct PilsRequest * next
DLL.
struct PilsRequest * prev
DLL.
struct GNUNET_ShortHashCode ss_e
struct GNUNET_ShortHashCode ihts
struct GNUNET_ShortHashCode rhts
struct ResponderHello rhm_e
struct ResponderHelloPayload * rhp
struct GSC_KeyExchangeInfo * kx
char finished_enc[sizeof(struct GNUNET_HashCode)+crypto_aead_xchacha20poly1305_ietf_ABYTES]
struct GNUNET_HashContext * hc
struct GNUNET_HashCode decrypted_finish
struct GNUNET_ShortHashCode hs
struct PilsRequest * req
struct GNUNET_CRYPTO_HpkeEncapsulation c_I
Challenge encapsulation c_I.
struct GNUNET_CRYPTO_HpkeEncapsulation c_e
Ephemeral key encapsulation c_e.
uint64_t r_R
Random number to make replay attacks harder.
struct GNUNET_MessageHeader header
Message type is #GNUNET_MESSAGE_TYPE_CORE_PONG.

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

◆ HEARTBEAT_FREQUENCY

#define HEARTBEAT_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)

How often do we send a heartbeat?

Definition at line 91 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 100 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 105 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 111 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 118 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 124 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 130 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 136 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 142 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 148 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 154 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 160 of file gnunet-service-core_kx.c.

◆ CAKE_LABEL

#define CAKE_LABEL   "cake10"

Labeled expand label for CAKE.

Definition at line 165 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 171 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 177 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 183 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 189 of file gnunet-service-core_kx.c.

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

Function Documentation

◆ buffer_clear()

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

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

445{
446#if HAVE_MEMSET_S
447 memset_s (buf, len, 0, len);
448#elif HAVE_EXPLICIT_BZERO
449 explicit_bzero (buf, len);
450#else
451 volatile unsigned char *p = buf;
452 while (len--)
453 *p++ = 0;
454#endif
455}

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

460{
461 buffer_clear (&kx->ihts,
462 sizeof kx->ihts);
463 buffer_clear (&kx->rhts,
464 sizeof kx->rhts);
465 buffer_clear (&kx->sk_e,
466 sizeof kx->sk_e);
467 buffer_clear (&kx->ss_I,
468 sizeof kx->ss_I);
469 buffer_clear (&kx->ss_R,
470 sizeof kx->ss_R);
471 buffer_clear (&kx->ss_e,
472 sizeof kx->ss_e);
474 sizeof kx->master_secret);
476 sizeof kx->early_secret_key);
478 sizeof kx->early_traffic_secret);
480 sizeof kx->handshake_secret);
481}

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

487{
488 struct GNUNET_HashContext *tmp;
489
490 tmp = GNUNET_CRYPTO_hash_context_copy (ts_hash);
491 GNUNET_CRYPTO_hash_context_finish (tmp, snapshot);
492}

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

502{
504
506 msg.header.size = htons (sizeof(msg));
507 msg.state = htonl ((uint32_t) kx->status);
508 msg.peer = kx->peer;
509 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
512}

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

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

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

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

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

◆ send_heartbeat()

static void send_heartbeat ( void *  cls)
static

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

Parameters
clsthe struct GSC_KeyExchangeInfo

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

527{
528 struct GSC_KeyExchangeInfo *kx = cls;
529 struct GNUNET_TIME_Relative retry;
530 struct GNUNET_TIME_Relative left;
531 struct Heartbeat hb;
532
533 kx->heartbeat_task = NULL;
535 if (0 == left.rel_value_us)
536 {
538 gettext_noop ("# sessions terminated by timeout"),
539 1,
540 GNUNET_NO);
541 GSC_SESSIONS_end (&kx->peer);
544 restart_kx (kx);
545 return;
546 }
548 "Sending HEARTBEAT to `%s'\n",
549 GNUNET_i2s (&kx->peer));
551 gettext_noop ("# heartbeat messages sent"),
552 1,
553 GNUNET_NO);
554 hb.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT);
555 hb.header.size = htons (sizeof hb);
556 // FIXME when do we request update?
557 hb.flags = 0;
558 GSC_KX_encrypt_and_transmit (kx, &hb, sizeof hb);
561 kx->heartbeat_task =
563}

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

575{
577
578 kx->timeout =
580 delta =
582 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
583 {
584 /* we only notify monitors about timeout changes if those
585 are bigger than the threshold (5s) */
587 }
588 if (NULL != kx->heartbeat_task)
593 kx);
594}

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

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

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

Referenced by restart_kx().

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

◆ deliver_message()

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

Deliver P2P message to interested clients.

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

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

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

619{
620 struct GSC_KeyExchangeInfo *kx = cls;
621
623 "Decrypted message of type %d from %s\n",
624 ntohs (m->type),
625 GNUNET_i2s (&kx->peer));
627 m,
628 ntohs (m->size),
631 m,
632 sizeof(struct GNUNET_MessageHeader),
634 return GNUNET_OK;
635}

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

701{
702 const struct GNUNET_PeerIdentity *my_identity;
703 struct GSC_KeyExchangeInfo *kx;
704 (void) cls;
706 GNUNET_assert (NULL != my_identity);
707 if (0 == memcmp (peer_id, my_identity, sizeof *peer_id))
708 {
710 "Ignoring connection to self\n");
711 return NULL;
712 }
714 "Incoming connection of peer with %s\n",
716
717 /* Set up kx struct */
718 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
720 kx->mq = mq;
721 GNUNET_memcpy (&kx->peer, peer_id, sizeof (struct GNUNET_PeerIdentity));
723
724 restart_kx (kx);
725 return kx;
726}

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

Referenced by GSC_KX_start().

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

◆ derive_es_ets()

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

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

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

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

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

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

779{
780 uint64_t ret;
781
782 ret = GNUNET_CRYPTO_hkdf_extract (es, // prk
783 0, // salt
784 0, // salt_len
785 ss_R, // ikm - initial key material
786 sizeof (*ss_R));
787 if (GNUNET_OK != ret)
788 {
789 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting ES\n")
790 ;
791 GNUNET_assert (0);
792 }
794 ets,
795 sizeof (*ets),
796 es,
799 GNUNET_CRYPTO_kdf_arg_auto (transcript));
800 if (GNUNET_OK != ret)
801 {
802 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
803 ;
804 GNUNET_assert (0);
805 }
806}

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

Referenced by handle_initiator_hello_cont(), and send_initiator_hello().

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

◆ derive_sn()

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

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

817{
820 sn,
821 sn_len,
822 secret,
825}

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

Referenced by GSC_KX_encrypt_and_transmit(), and handle_encrypted_message().

Here is the caller graph for this function:

◆ derive_hs()

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

Derive the handshake secret.

Parameters
kxkey exchange info

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

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

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

Referenced by handle_responder_hello(), and send_responder_hello().

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

◆ derive_ihts()

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

Derive the initiator handshake secret.

Parameters
kxkey exchange info

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

882{
885 ihts, // result
886 sizeof (*ihts), // result len
887 hs, // prk?
890 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
891}

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

Referenced by handle_responder_hello(), and send_responder_hello().

Here is the caller graph for this function:

◆ derive_rhts()

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

Derive the responder handshake secret.

Parameters
kxkey exchange info

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

902{
905 rhts,
906 sizeof (*rhts),
907 hs, // prk? TODO
910 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
911}

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

Referenced by handle_responder_hello(), and send_responder_hello().

Here is the caller graph for this function:

◆ derive_ms()

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

Derive the master secret.

Parameters
kxkey exchange info

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

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

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

Referenced by handle_responder_hello_cont(), and send_responder_hello().

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

◆ generate_per_record_nonce()

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

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

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

963{
964 uint64_t seq_nbo;
965 uint64_t *write_iv_ptr;
966 unsigned int byte_offset;
967
968 seq_nbo = GNUNET_htonll (seq);
969 memcpy (per_record_write_iv,
970 write_iv,
972 byte_offset =
973 AEAD_NONCE_BYTES - sizeof (uint64_t);
974 write_iv_ptr = (uint64_t*) (write_iv + byte_offset);
975 *write_iv_ptr ^= seq_nbo;
976}

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

989{
990 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
991 /* derive actual key */
994 key,
996 ts,
999
1000 /* derive nonce */
1003 nonce_tmp,
1005 ts,
1009 nonce_tmp,
1010 nonce);
1011}

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

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

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

◆ derive_next_ats()

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

Derive the next application secret.

Parameters
kxkey exchange info

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

1021{
1022 int8_t ret;
1023
1024 // FIXME: Not sure of PRK and output may overlap here!
1026 new_ats,
1027 sizeof (*new_ats),
1028 old_ats,
1031 if (GNUNET_OK != ret)
1032 {
1034 "Something went wrong deriving next *ATS key\n");
1035 GNUNET_assert (0);
1036 }
1037}

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

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

Here is the caller graph for this function:

◆ derive_initial_ats()

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

Derive the initiator application secret.

Parameters
kxkey exchange info

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

1049{
1050 const char *traffic_str;
1051
1052 if (ROLE_INITIATOR == role)
1053 traffic_str = I_AP_TRAFFIC_STR;
1054 else
1055 traffic_str = R_AP_TRAFFIC_STR;
1058 initial_ats, // result
1059 sizeof (*initial_ats), // result len
1060 ms,
1062 GNUNET_CRYPTO_kdf_arg_string (traffic_str),
1063 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
1064}

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

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

Here is the caller graph for this function:

◆ generate_responder_finished()

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

Generate the responder finished field.

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

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

1077{
1079 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1080
1082 &fk_R, // result
1083 sizeof (fk_R),
1084 ms,
1087 if (GNUNET_OK != ret)
1088 {
1090 "Something went wrong expanding fk_R\n");
1091 GNUNET_assert (0);
1092 }
1093
1094 GNUNET_CRYPTO_hmac (&fk_R,
1095 transcript,
1096 sizeof (*transcript),
1097 result);
1098}

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

Referenced by handle_responder_hello_cont(), and send_responder_hello().

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

◆ generate_initiator_finished()

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

Generate the initiator finished field.

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

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

1111{
1113 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1114
1116 &fk_I, // result
1117 sizeof (fk_I),
1118 ms,
1121 if (GNUNET_OK != ret)
1122 {
1124 "Something went wrong expanding fk_I\n");
1125 GNUNET_assert (0);
1126 }
1127 GNUNET_CRYPTO_hmac (&fk_I,
1128 transcript,
1129 sizeof (*transcript),
1130 result);
1131}

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

Referenced by handle_initiator_done(), and handle_responder_hello_cont().

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

◆ resend_responder_hello()

static void resend_responder_hello ( void *  cls)
static

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

1143{
1144 struct GSC_KeyExchangeInfo *kx = cls;
1145
1146 kx->resend_task = NULL;
1147 if (0 == kx->resend_tries_left)
1148 {
1150 "Restarting KX\n");
1151 restart_kx (kx);
1152 return;
1153 }
1154 kx->resend_tries_left--;
1156 "Resending responder hello. Retries left: %u\n",
1157 kx->resend_tries_left);
1161 kx);
1162}

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

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

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, GSC_KeyExchangeInfo::role, ROLE_RESPONDER, snapshot_transcript(), GSC_KeyExchangeInfo::ss_e, GSC_KeyExchangeInfo::ss_I, GSC_KeyExchangeInfo::status, GSC_KeyExchangeInfo::transcript_hash_ctx, and transport.

Referenced by handle_initiator_hello_cont().

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

◆ handle_initiator_hello_cont()

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

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

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

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

Referenced by handle_initiator_hello().

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

◆ check_initiator_hello()

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

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

1513{
1514 uint16_t size = ntohs (m->header.size);
1515
1516 if (size < sizeof (*m)
1517 + sizeof (struct InitiatorHelloPayload)
1519 {
1520 return GNUNET_SYSERR;
1521 }
1522 return GNUNET_OK;
1523}

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

◆ handle_initiator_hello()

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

Handle the InitiatorHello message.

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

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

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

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

Here is the call graph for this function:

◆ resend_initiator_done()

static void resend_initiator_done ( void *  cls)
static

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

1657{
1658 struct GSC_KeyExchangeInfo *kx = cls;
1659
1660 kx->resend_task = NULL;
1661 if (0 == kx->resend_tries_left)
1662 {
1664 "Restarting KX\n");
1665 restart_kx (kx);
1666 return;
1667 }
1668 kx->resend_tries_left--;
1670 "Resending initiator done. Retries left: %u\n",
1671 kx->resend_tries_left);
1675 kx);
1676}

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

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

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

Referenced by handle_responder_hello().

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

◆ check_responder_hello()

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

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

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

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

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

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

Here is the call graph for this function:

◆ check_initiator_done()

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

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

2046{
2047 uint16_t size = ntohs (m->header.size);
2048
2049 if (size < sizeof (*m) + sizeof (struct ConfirmationAck))
2050 {
2051 return GNUNET_SYSERR;
2052 }
2053 return GNUNET_OK;
2054}

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

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

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

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

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

2252{
2253 struct GNUNET_ShortHashCode new_ats;
2254 struct ConfirmationAck ack;
2255
2257 {
2258 if (kx->current_epoch == UINT64_MAX)
2259 {
2261 "Max epoch reached (you probably will never see this)\n");
2262 }
2263 else
2264 {
2265 kx->current_epoch++;
2268 kx->current_sqn = 0;
2270 &new_ats);
2271 memcpy (&kx->current_ats,
2272 &new_ats,
2273 sizeof new_ats);
2274 }
2275 }
2276 update_timeout (kx);
2277 ack.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ACK);
2278 ack.header.size = htons (sizeof ack);
2280 &ack,
2281 sizeof ack);
2282 if (NULL != kx->heartbeat_task)
2283 {
2287 kx);
2288 }
2289 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2290}

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

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

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

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

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

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

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

Referenced by GSC_KX_start().

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

◆ resend_initiator_hello()

static void resend_initiator_hello ( void *  cls)
static

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

2574{
2575 struct GSC_KeyExchangeInfo *kx = cls;
2576
2577 kx->resend_task = NULL;
2579 "Resending InitiatorHello.\n");
2581 // FIXME (Exponential) backoff?
2584 kx);
2585}

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

2720{
2721 struct GNUNET_ShortHashCode new_ats;
2722
2723 if ((UINT64_MAX == kx->current_sqn) ||
2725 {
2727 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2728 ", incrementing epoch...\n",
2730 kx->current_sqn);
2731 // Can this trigger? Maybe if we receive a lot of
2732 // heartbeats?
2733 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2734 kx->current_epoch++;
2737 kx->current_sqn = 0;
2739 &new_ats);
2740 memcpy (&kx->current_ats,
2741 &new_ats,
2742 sizeof new_ats);
2743 }
2744}

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

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

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

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

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

◆ GSC_KX_start()

void GSC_KX_start ( void  )

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

2846{
2847 const struct GNUNET_PeerIdentity *my_identity;
2849 GNUNET_MQ_hd_var_size (initiator_hello,
2851 struct InitiatorHello,
2852 NULL),
2853 GNUNET_MQ_hd_var_size (initiator_done,
2855 struct InitiatorDone,
2856 NULL),
2857 GNUNET_MQ_hd_var_size (responder_hello,
2859 struct ResponderHello,
2860 NULL),
2861 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2863 struct EncryptedMessage,
2864 NULL),
2866 };
2867
2869 GNUNET_assert (NULL != my_identity);
2870
2872 transport =
2875 handlers,
2876 NULL, // cls - this connection-independant
2877 // cls seems not to be needed.
2878 // the connection-specific cls
2879 // will be set as a return value
2880 // of
2881 // handle_transport_notify_connect
2884 if (NULL == transport)
2885 {
2886 GSC_KX_done ();
2887 return;
2888 }
2889
2891 "Connected to TRANSPORT\n");
2892
2894}

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

Referenced by pid_change_cb().

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

◆ pid_change_cb()

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

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

2901{
2902 if (NULL != transport)
2903 return;
2904
2905 GSC_KX_start ();
2906}

References GSC_KX_start(), and transport.

Referenced by GSC_KX_init().

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

◆ GSC_KX_init()

int GSC_KX_init ( void  )

Initialize KX subsystem.

Returns
GNUNET_OK on success, GNUNET_SYSERR on failure

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

2916{
2919 NULL);
2920 if (NULL == GSC_pils)
2921 {
2922 GSC_KX_done ();
2923 return GNUNET_SYSERR;
2924 }
2925
2926 return GNUNET_OK;
2927}

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

Referenced by run().

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

◆ GSC_KX_done()

void GSC_KX_done ( void  )

Shutdown KX subsystem.

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

2935{
2936 struct PilsRequest *pr;
2937 while (NULL != (pr = pils_requests_head))
2938 {
2941 pr);
2942 if (NULL != pr->op)
2943 GNUNET_PILS_cancel (pr->op);
2944 GNUNET_free (pr);
2945 }
2946 if (NULL != GSC_pils)
2947 {
2949 GSC_pils = NULL;
2950 }
2951 if (NULL != transport)
2952 {
2954 transport = NULL;
2955 }
2956 if (NULL != rekey_task)
2957 {
2959 rekey_task = NULL;
2960 }
2961 if (NULL != nc)
2962 {
2964 nc = NULL;
2965 }
2966}

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

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

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

◆ GSC_NEIGHBOURS_get_queue_length()

unsigned int GSC_NEIGHBOURS_get_queue_length ( const struct GSC_KeyExchangeInfo kxinfo)

Check how many messages are queued for the given neighbour.

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

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

2977{
2978 return GNUNET_MQ_get_length (kxinfo->mq);
2979}

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

2984{
2985 return kxinfo->has_excess_bandwidth;
2986}

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

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

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

Referenced by handle_client_monitor_peers().

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

Variable Documentation

◆ pils_requests_head

◆ pils_requests_tail

◆ transport

◆ kx_head

◆ kx_tail

struct GSC_KeyExchangeInfo* kx_tail
static

◆ rekey_task

struct GNUNET_SCHEDULER_Task* rekey_task
static

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

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

Referenced by GSC_KX_done().

◆ nc

◆ my_services_info

char* my_services_info = ""
static

Our services info string TODO.

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

Referenced by send_initiator_hello(), and send_responder_hello().