GNUnet 0.28.0-dev.3-20-gf1136b0b8
 
Loading...
Searching...
No Matches
gnunet-service-core_kx.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016, 2024-2026 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
37#include "platform.h"
38#include "gnunet_common.h"
39#include "gnunet_util_lib.h"
43#include "gnunet-service-core.h"
44#include "gnunet_constants.h"
45#include "gnunet_protocols.h"
46#include "gnunet_pils_service.h"
47
51#define DEBUG_KX 0
52
56#define RESEND_MAX_TRIES 4
57
61#define AEAD_KEY_BYTES crypto_aead_xchacha20poly1305_ietf_KEYBYTES
62
66#define AEAD_NONCE_BYTES crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
67
71#define AEAD_TAG_BYTES crypto_aead_xchacha20poly1305_ietf_ABYTES
72
73#define RESEND_TIMEOUT \
74 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
75
79#define MIN_HEARTBEAT_FREQUENCY \
80 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
81
85#define HEARTBEAT_FREQUENCY \
86 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
87
94#define MAX_EPOCHS 10
95
99#define EPOCH_EXPIRATION \
100 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
101
105#define REKEY_TOLERANCE \
106 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
107
112#define EARLY_DATA_STR "early data"
113
118#define R_HS_TRAFFIC_STR "r hs traffic"
119
124#define I_HS_TRAFFIC_STR "i hs traffic"
125
130#define R_AP_TRAFFIC_STR "r ap traffic"
131
136#define I_AP_TRAFFIC_STR "i ap traffic"
137
142#define DERIVED_STR "derived"
143
148#define R_FINISHED_STR "r finished"
149
154#define I_FINISHED_STR "i finished"
155
159#define CAKE_LABEL "cake10"
160
165#define KEY_STR "key"
166
171#define TRAFFIC_UPD_STR "traffic upd"
172
177#define IV_STR "iv"
178
179
184{
185 /* Peer is supposed to initiate the key exchange */
187
188 /* Peer is supposed to wait for the key exchange */
190};
191
192
197{
202
207
212
217
222
227
228 // TODO check ordering - might make it less confusing
229 // TODO consistent naming: ss_e, shared_secret_e or ephemeral_shared_secret?
230 // TODO consider making all the structs here pointers
231 // - they can be checked to be NULL
232 // - valgrind can detect memory issues better (I guess?)
233
239
240 // TODO
244
249
254
261
267
272 struct GNUNET_ShortHashCode early_traffic_secret; /* Decrypts InitiatorHello */
273
279
285
291
297
302
307
312
317
323
327 uint64_t current_sqn;
328
333
338
343
347 unsigned int resend_tries_left;
348
354
360
365
371
372};
373
377struct PilsRequest
378{
382 struct PilsRequest *prev;
383
387 struct PilsRequest *next;
388
393};
394
399
404
405
410
415
420
426
431
435static char *my_services_info = "";
436
437static void
438buffer_clear (void *buf, size_t len)
439{
440#if HAVE_MEMSET_S
441 memset_s (buf, len, 0, len);
442#elif HAVE_EXPLICIT_BZERO
443 explicit_bzero (buf, len);
444#else
445 volatile unsigned char *p = buf;
446 while (len--)
447 *p++ = 0;
448#endif
449}
450
451
452static void
454{
455 buffer_clear (&kx->ihts,
456 sizeof kx->ihts);
457 buffer_clear (&kx->rhts,
458 sizeof kx->rhts);
459 buffer_clear (&kx->sk_e,
460 sizeof kx->sk_e);
461 buffer_clear (&kx->ss_I,
462 sizeof kx->ss_I);
463 buffer_clear (&kx->ss_R,
464 sizeof kx->ss_R);
465 buffer_clear (&kx->ss_e,
466 sizeof kx->ss_e);
468 sizeof kx->master_secret);
470 sizeof kx->early_secret_key);
472 sizeof kx->early_traffic_secret);
474 sizeof kx->handshake_secret);
475}
476
477
478static void
480 struct GNUNET_HashCode *snapshot)
481{
482 struct GNUNET_HashContext *tmp;
483
484 tmp = GNUNET_CRYPTO_hash_context_copy (ts_hash);
485 GNUNET_CRYPTO_hash_context_finish (tmp, snapshot);
486}
487
488
494static void
496{
498
500 msg.header.size = htons (sizeof(msg));
501 msg.state = htonl ((uint32_t) kx->status);
502 msg.peer = kx->peer;
503 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
506}
507
508
509static void
511
519static void
520send_heartbeat (void *cls)
521{
522 struct GSC_KeyExchangeInfo *kx = cls;
523 struct GNUNET_TIME_Relative retry;
524 struct GNUNET_TIME_Relative left;
525 struct Heartbeat hb;
526
527 kx->heartbeat_task = NULL;
529 if (0 == left.rel_value_us)
530 {
532 gettext_noop ("# sessions terminated by timeout"),
533 1,
534 GNUNET_NO);
535 GSC_SESSIONS_end (&kx->peer);
538 restart_kx (kx);
539 return;
540 }
542 "Sending HEARTBEAT to `%s'\n",
543 GNUNET_i2s (&kx->peer));
545 gettext_noop ("# heartbeat messages sent"),
546 1,
547 GNUNET_NO);
549 hb.header.size = htons (sizeof hb);
550 // FIXME when do we request update?
551 hb.flags = 0;
552 GSC_KX_encrypt_and_transmit (kx, &hb, sizeof hb);
555 kx->heartbeat_task =
557}
558
559
567static void
569{
571
572 kx->timeout =
574 delta =
576 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
577 {
578 /* we only notify monitors about timeout changes if those
579 are bigger than the threshold (5s) */
581 }
582 if (NULL != kx->heartbeat_task)
587 kx);
588}
589
590
596static void
598
599
611static int
612deliver_message (void *cls, const struct GNUNET_MessageHeader *m)
613{
614 struct GSC_KeyExchangeInfo *kx = cls;
615
617 "Decrypted message of type %d from %s\n",
618 ntohs (m->type),
619 GNUNET_i2s (&kx->peer));
621 m,
622 ntohs (m->size),
625 m,
626 sizeof(struct GNUNET_MessageHeader),
628 return GNUNET_OK;
629}
630
631
632static void
634{
635 const struct GNUNET_HashCode *my_identity_hash;
636 struct GNUNET_HashCode h1;
637
638 // TODO what happens if we're in the middle of a peer id change?
639 // TODO there's a small chance this gets already called when we don't have a
640 // peer id yet. Add a kx, insert into the list, mark it as to be completed
641 // and let the callback to pils finish the rest once we got the peer id
642
644 "Initiating key exchange with peer %s\n",
645 GNUNET_i2s (&kx->peer));
647 gettext_noop ("# key exchanges initiated"),
648 1,
649 GNUNET_NO);
650
652 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
653 GNUNET_assert (NULL != my_identity_hash);
654 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
655 if (NULL != kx->transcript_hash_ctx)
657 kx->transcript_hash_ctx = NULL;
658 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, my_identity_hash))
659 {
660 /* peer with "lower" identity starts KX, otherwise we typically end up
661 with both peers starting the exchange and transmit the 'set key'
662 message twice */
664 "I am the initiator, sending hello\n");
665 kx->role = ROLE_INITIATOR;
667 }
668 else
669 {
670 /* peer with "higher" identity starts a delayed KX, if the "lower" peer
671 * does not start a KX since it sees no reasons to do so */
673 "I am the responder, yielding and await initiator hello\n");
675 kx->role = ROLE_RESPONDER;
677 }
678}
679
680
691static void *
693 const struct GNUNET_PeerIdentity *peer_id,
694 struct GNUNET_MQ_Handle *mq)
695{
696 const struct GNUNET_PeerIdentity *my_identity;
697 struct GSC_KeyExchangeInfo *kx;
698 (void) cls;
700 GNUNET_assert (NULL != my_identity);
701 if (0 == memcmp (peer_id, my_identity, sizeof *peer_id))
702 {
704 "Ignoring connection to self\n");
705 return NULL;
706 }
708 "Incoming connection of peer with %s\n",
710
711 /* Set up kx struct */
712 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
714 kx->mq = mq;
715 GNUNET_memcpy (&kx->peer, peer_id, sizeof (struct GNUNET_PeerIdentity));
717
718 restart_kx (kx);
719 return kx;
720}
721
722
762// TODO find a way to assert that a key is not yet existing before generating
763// TODO find a way to assert that a key is not already existing before using
764/*
765 * Derive early secret and transport secret.
766 * @param kx the key exchange info
767 */
768static void
769derive_es_ets (const struct GNUNET_HashCode *transcript,
770 const struct GNUNET_ShortHashCode *ss_R,
771 struct GNUNET_ShortHashCode *es,
772 struct GNUNET_ShortHashCode *ets)
773{
774 uint64_t ret;
775
776 ret = GNUNET_CRYPTO_hkdf_extract (es, // prk
777 0, // salt
778 0, // salt_len
779 ss_R, // ikm - initial key material
780 sizeof (*ss_R));
781 if (GNUNET_OK != ret)
782 {
783 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting ES\n")
784 ;
785 GNUNET_assert (0);
786 }
788 ets,
789 sizeof (*ets),
790 es,
793 GNUNET_CRYPTO_kdf_arg_auto (transcript));
794 if (GNUNET_OK != ret)
795 {
796 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding ETS\n")
797 ;
798 GNUNET_assert (0);
799 }
800}
801
802
803/*
804 * Derive early secret and transport secret.
805 * @param kx the key exchange info
806 */
807static void
808derive_sn (const struct GNUNET_ShortHashCode *secret,
809 unsigned char*sn,
810 size_t sn_len)
811{
814 sn,
815 sn_len,
816 secret,
819}
820
821
826static void
828 const struct GNUNET_ShortHashCode *ss_e,
830{
831 uint64_t ret;
832 struct GNUNET_ShortHashCode derived_early_secret;
833
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deriving HS\n");
836 );
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ss_e: %s\n", GNUNET_B2S (ss_e));
839 &derived_early_secret,
840 sizeof (derived_early_secret),
841 es,
845 derived_early_secret));
846 if (GNUNET_OK != ret)
847 {
848 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dES\n")
849 ;
850 GNUNET_assert (0);
851 }
852 // Handshake secret
853 // TODO check: are dES the salt and ss_e the ikm or other way round?
854 ret = GNUNET_CRYPTO_hkdf_extract (handshake_secret, // prk
855 &derived_early_secret, // salt - dES
856 sizeof (derived_early_secret), // salt_len
857 ss_e, // ikm - initial key material
858 sizeof (*ss_e));
859 if (GNUNET_OK != ret)
860 {
861 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting HS\n")
862 ;
863 GNUNET_assert (0);
864 }
865}
866
867
872static void
873derive_ihts (const struct GNUNET_HashCode *transcript,
874 const struct GNUNET_ShortHashCode *hs,
875 struct GNUNET_ShortHashCode *ihts)
876{
879 ihts, // result
880 sizeof (*ihts), // result len
881 hs, // prk?
884 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
885}
886
887
892static void
893derive_rhts (const struct GNUNET_HashCode *transcript,
894 const struct GNUNET_ShortHashCode *hs,
895 struct GNUNET_ShortHashCode *rhts)
896{
899 rhts,
900 sizeof (*rhts),
901 hs, // prk? TODO
904 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
905}
906
907
912static void
914 const struct GNUNET_ShortHashCode *ss_I,
915 struct GNUNET_ShortHashCode *ms)
916{
917 uint64_t ret;
918 struct GNUNET_ShortHashCode derived_handshake_secret;
919
921 &derived_handshake_secret,
922 sizeof (derived_handshake_secret),
923 hs,
926 if (GNUNET_OK != ret)
927 {
928 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong expanding dHS\n")
929 ;
930 GNUNET_assert (0);
931 }
932 // TODO check: are dHS the salt and ss_I the ikm or other way round?
933 ret = GNUNET_CRYPTO_hkdf_extract (ms, // prk
934 &derived_handshake_secret, // salt - dHS
935 sizeof (derived_handshake_secret), // salt_len
936 ss_I, // ikm - initial key material
937 sizeof (*ss_I));
938 if (GNUNET_OK != ret)
939 {
940 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong extracting MS\n")
941 ;
942 GNUNET_assert (0);
943 }
944}
945
946
952static void
954 uint64_t seq,
955 const uint8_t write_iv[AEAD_NONCE_BYTES],
956 uint8_t per_record_write_iv[AEAD_NONCE_BYTES])
957{
958 uint64_t seq_nbo;
959 uint64_t *write_iv_ptr;
960 unsigned int byte_offset;
961
962 seq_nbo = GNUNET_htonll (seq);
963 memcpy (per_record_write_iv,
964 write_iv,
966 byte_offset =
967 AEAD_NONCE_BYTES - sizeof (uint64_t);
968 write_iv_ptr = (uint64_t*) (per_record_write_iv + byte_offset);
969 *write_iv_ptr ^= seq_nbo;
970}
971
972
977static void
979 const struct GNUNET_ShortHashCode *ts,
980 uint64_t seq,
981 unsigned char key[AEAD_KEY_BYTES],
982 unsigned char nonce[AEAD_NONCE_BYTES])
983{
984 unsigned char nonce_tmp[AEAD_NONCE_BYTES];
985 /* derive actual key */
988 key,
990 ts,
993
994 /* derive nonce */
997 nonce_tmp,
999 ts,
1003 nonce_tmp,
1004 nonce);
1005}
1006
1007
1012static void
1014 struct GNUNET_ShortHashCode *new_ats)
1015{
1016 int8_t ret;
1017
1018 // FIXME: Not sure of PRK and output may overlap here!
1020 new_ats,
1021 sizeof (*new_ats),
1022 old_ats,
1025 if (GNUNET_OK != ret)
1026 {
1028 "Something went wrong deriving next *ATS key\n");
1029 GNUNET_assert (0);
1030 }
1031}
1032
1033
1038static void
1039derive_initial_ats (const struct GNUNET_HashCode *transcript,
1040 const struct GNUNET_ShortHashCode *ms,
1041 enum GSC_KX_Role role,
1042 struct GNUNET_ShortHashCode *initial_ats)
1043{
1044 const char *traffic_str;
1045
1046 if (ROLE_INITIATOR == role)
1047 traffic_str = I_AP_TRAFFIC_STR;
1048 else
1049 traffic_str = R_AP_TRAFFIC_STR;
1052 initial_ats, // result
1053 sizeof (*initial_ats), // result len
1054 ms,
1056 GNUNET_CRYPTO_kdf_arg_string (traffic_str),
1057 GNUNET_CRYPTO_kdf_arg_auto (transcript)));
1058}
1059
1060
1067static void
1069 const struct GNUNET_ShortHashCode *ms,
1070 struct GNUNET_HashCode *result)
1071{
1073 struct GNUNET_CRYPTO_AuthKey fk_R; // We might want to save this in kx?
1074
1076 &fk_R, // result
1077 sizeof (fk_R),
1078 ms,
1081 if (GNUNET_OK != ret)
1082 {
1084 "Something went wrong expanding fk_R\n");
1085 GNUNET_assert (0);
1086 }
1087
1088 GNUNET_CRYPTO_hmac (&fk_R,
1089 transcript,
1090 sizeof (*transcript),
1091 result);
1092}
1093
1094
1101static void
1103 const struct GNUNET_ShortHashCode *ms,
1104 struct GNUNET_HashCode *result)
1105{
1107 struct GNUNET_CRYPTO_AuthKey fk_I; // We might want to save this in kx?
1108
1110 &fk_I, // result
1111 sizeof (fk_I),
1112 ms,
1115 if (GNUNET_OK != ret)
1116 {
1118 "Something went wrong expanding fk_I\n");
1119 GNUNET_assert (0);
1120 }
1121 GNUNET_CRYPTO_hmac (&fk_I,
1122 transcript,
1123 sizeof (*transcript),
1124 result);
1125}
1126
1127
1134
1135static void
1137{
1138 struct GSC_KeyExchangeInfo *kx = cls;
1139
1140 kx->resend_task = NULL;
1141 if (0 == kx->resend_tries_left)
1142 {
1144 "Restarting KX\n");
1145 restart_kx (kx);
1146 return;
1147 }
1148 kx->resend_tries_left--;
1150 "Resending responder hello. Retries left: %u\n",
1151 kx->resend_tries_left);
1155 kx);
1156}
1157
1158
1159void
1161{
1164 struct ResponderHello *rhm_e; /* responder hello message - encrypted pointer */
1165 struct GNUNET_MQ_Envelope *env;
1166 struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_kem_challenge;
1167 struct GNUNET_ShortHashCode rhts;
1168 struct GNUNET_ShortHashCode ihts;
1169 struct GNUNET_ShortHashCode hs;
1170 struct GNUNET_ShortHashCode ms;
1171 struct GNUNET_ShortHashCode ss_e;
1172 struct GNUNET_ShortHashCode ss_I;
1173 struct GNUNET_HashContext *hc;
1174 unsigned char enc_key[AEAD_KEY_BYTES];
1175 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1176
1177 // 4. encaps -> shared_secret_e, c_e (kemChallenge)
1178 // TODO potentially write this directly into rhm?
1179 ret = GNUNET_CRYPTO_hpke_kem_encaps (&kx->pk_e, // public ephemeral key of initiator
1180 &ephemeral_kem_challenge, // encapsulated key
1181 &ss_e); // key - ss_e
1182 if (GNUNET_OK != ret)
1183 {
1185 "Something went wrong encapsulating ss_e\n");
1186 return;
1187 }
1189 // 6. encaps -> shared_secret_I, c_I
1190 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public key of I
1191 &c_I, // encapsulated key
1192 &ss_I); // where to write the key material
1193 if (GNUNET_OK != ret)
1194 {
1196 "Something went wrong encapsulating ss_I\n");
1198 return;
1199 }
1200 // 7. generate RHTS (responder_handshare_secret_key) and RATS (responder_application_traffic_secret_key) (section 5)
1201 {
1202 struct GNUNET_HashCode transcript;
1203 snapshot_transcript (hc, &transcript);
1204#if DEBUG_KX
1206 "Transcript snapshot for derivation of HS, MS: `%s'\n",
1207 GNUNET_h2s (&transcript));
1208#endif
1210 &ss_e,
1211 &hs);
1212 derive_ms (&hs, &ss_I, &ms);
1213 }
1214
1215 // send ResponderHello
1216 // TODO fill fields / services_info!
1217 // 1. r_R <- random
1218 struct ResponderHelloPayload *rhp;
1219 size_t rhp_len = sizeof (*rhp) + strlen (my_services_info);
1220 unsigned char rhp_buf[rhp_len];
1221 size_t ct_len;
1222
1223 rhp = (struct ResponderHelloPayload*) rhp_buf;
1224 ct_len = rhp_len // ResponderHelloPayload, fist PT msg
1225 + sizeof (struct GNUNET_HashCode) // Finished hash, second PT msg
1226 + AEAD_TAG_BYTES * 2; // Two tags;
1227 env = GNUNET_MQ_msg_extra (rhm_e,
1228 ct_len,
1230
1231 rhm_e->r_R =
1232 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
1233
1234 // c_e
1235 GNUNET_memcpy (&rhm_e->c_e,
1236 &ephemeral_kem_challenge,
1237 sizeof (ephemeral_kem_challenge));
1239 rhm_e,
1240 sizeof (struct ResponderHello));
1241 // 2. Encrypt ServicesInfo and c_I with RHTS
1242 // derive RHTS
1243 {
1244 struct GNUNET_HashCode transcript;
1246 &transcript);
1247#if DEBUG_KX
1249 "Transcript snapshot for derivation of *HTS: `%s'\n",
1250 GNUNET_h2s (&transcript));
1251#endif
1252 derive_rhts (&transcript,
1253 &hs,
1254 &rhts);
1255 derive_ihts (&transcript,
1256 &hs,
1257 &ihts);
1259 0,
1260 enc_key,
1261 enc_nonce);
1262 }
1263 // c_I
1264 GNUNET_memcpy (&rhp->c_I, &c_I, sizeof (c_I));
1265 // Services info empty for now.
1266 GNUNET_memcpy (&rhp[1],
1268 strlen (my_services_info));
1269
1270 {
1271 unsigned long long out_ct_len;
1273 struct GNUNET_HashCode transcript;
1274 unsigned char *finished_buf;
1275 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1276 (unsigned char*) &rhm_e[1], /* c - ciphertext */
1277 &out_ct_len, /* clen_p */
1278 rhp_buf, /* rhm_p - plaintext message */
1279 rhp_len, // mlen
1280 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1281 // fields?
1282 NULL, // nsec - unused
1283 enc_nonce, // npub - nonce // FIXME nonce can be reused
1284 enc_key)); // k - key RHTS
1286 "Encrypted and wrote %llu bytes\n",
1287 out_ct_len);
1288 // 3. Create ResponderFinished (Section 6)
1289 // Derive fk_I <- HKDF-Expand (MS, "r finished", NULL)
1290 /* Forward the transcript */
1291 /* {svcinfo, c_I}RHTS */
1293 hc,
1294 &rhm_e[1],
1295 out_ct_len);
1296
1297 finished_buf = ((unsigned char*) &rhm_e[1]) + out_ct_len;
1299 &transcript);
1300#if DEBUG_KX
1302 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1303 GNUNET_h2s (&transcript));
1304#endif
1305 generate_responder_finished (&transcript,
1306 &ms,
1307 &finished);
1308 // 4. Encrypt ResponderFinished
1310 1,
1311 enc_key,
1312 enc_nonce);
1313 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1314 finished_buf, /* c - ciphertext */
1315 &out_ct_len, /* clen_p */
1316 (unsigned char*) &finished, /* rhm_p - plaintext message */
1317 sizeof (finished), // mlen
1318 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1319 // fields?
1320 NULL, // nsec - unused
1321 enc_nonce, // npub
1322 enc_key)); // k - key RHTS
1324 "Encrypted and wrote %llu bytes\n",
1325 out_ct_len);
1326 /* Forward the transcript
1327 * after responder finished,
1328 * before deriving *ATS and generating finished_I
1329 * (finished_I will be generated when receiving the InitiatorFinished message
1330 * in order to check it) */
1332 hc,
1333 finished_buf,
1334 out_ct_len);
1335 // 5. optionally send application data - encrypted with RATS
1336 // We do not really have any application data, instead, we send the ACK
1338 &transcript);
1339#if DEBUG_KX
1341 "Transcript snapshot for derivation of *ATS: `%s'\n",
1342 GNUNET_h2s (&transcript));
1343#endif
1344 derive_initial_ats (&transcript,
1345 &ms,
1347 &kx->current_ats);
1348 }
1349 /* Lock into struct */
1351 kx->transcript_hash_ctx = hc;
1352 kx->master_secret = ms;
1353 kx->handshake_secret = hs;
1354 kx->ss_e = ss_e;
1355 kx->ihts = ihts;
1356 kx->rhts = rhts;
1357 kx->ss_I = ss_I;
1358 kx->current_epoch = 0;
1359 kx->current_sqn = 0;
1361 kx->current_sqn,
1362 enc_key,
1363 enc_nonce);
1364
1365 GNUNET_MQ_send_copy (kx->mq, env);
1366 kx->resend_env = env;
1368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent ResponderHello: %d %d\n", kx->role,
1369 kx->status);
1370
1373 kx);
1375 monitor_notify_all (kx);
1376 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1377}
1378
1379
1380static void
1382{
1383 const struct GNUNET_HashCode *my_identity_hash;
1384 struct InitiatorHelloCtx *ihm_ctx = cls;
1385 struct GSC_KeyExchangeInfo *kx = ihm_ctx->kx;
1386 uint32_t ihm_len = ntohs (ihm_ctx->ihm_e->header.size);
1387 unsigned char enc_key[AEAD_KEY_BYTES];
1388 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1389 struct GNUNET_HashCode h1;
1390 struct GNUNET_HashCode transcript;
1391 struct GNUNET_ShortHashCode es;
1392 struct GNUNET_ShortHashCode ets;
1394
1395 ihm_ctx->req->op = NULL;
1398 ihm_ctx->req);
1399 GNUNET_free (ihm_ctx->req);
1400
1401
1403 &ihm_ctx->ihm_e->pk_e,
1404 sizeof (ihm_ctx->ihm_e->pk_e));
1405 // 5. generate ETS (early_traffic_secret_key, decrypt pk_i
1406 // expand ETS <- expand ES <- extract ss_R
1407 // use ETS to decrypt
1408
1409 /* Forward the transcript hash context over the unencrypted fields to get it
1410 * to the same status that the initiator had when it needed to derive es and
1411 * ets for the encryption */
1414 ihm_ctx->ihm_e,
1415 sizeof (struct InitiatorHello));
1417 &transcript);
1418#if DEBUG_KX
1420 "Transcript snapshot for derivation of ES, ETS: `%s'\n",
1421 GNUNET_h2s (&transcript));
1422#endif
1423 derive_es_ets (&transcript, ss_R, &es, &ets);
1425 0,
1426 enc_key,
1427 enc_nonce);
1428 {
1429 struct InitiatorHelloPayload *ihmp;
1430 size_t ct_len = ihm_len - sizeof (struct InitiatorHello);
1431 unsigned char ihmp_buf[ct_len - AEAD_TAG_BYTES];
1432 ihmp = (struct InitiatorHelloPayload*) ihmp_buf;
1433 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1434 ihmp_buf, // unsigned char *m
1435 NULL, // mlen_p message length
1436 NULL, // unsigned char *nsec - unused: NULL
1437 (unsigned char*) &ihm_ctx->ihm_e[1], // const unsigned char *c - ciphertext
1438 ct_len, // unsigned long long clen - length of ciphertext
1439 // mac, // const unsigned char *mac - authentication tag
1440 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1441 0, // unsigned long long adlen
1442 enc_nonce, // const unsigned char *npub - nonce
1443 enc_key // const unsigned char *k - key
1444 );
1445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pid_sender: %s\n",
1446 GNUNET_i2s (&ihmp->pk_I));
1447 if (0 != ret)
1448 {
1450 "Something went wrong decrypting: %d\n", ret);
1451 GNUNET_break_op (0);
1452 GNUNET_free (ihm_ctx->ihm_e);
1453 GNUNET_free (ihm_ctx);
1454 restart_kx (kx);
1455 return;
1456 }
1457 /* now forward it considering the encrypted messages that the initiator was
1458 * able to send after deriving the es and ets */
1460 &ihm_ctx->ihm_e[1],
1461 ct_len);
1462 GNUNET_memcpy (&kx->peer,
1463 &ihmp->pk_I,
1464 sizeof (struct GNUNET_PeerIdentity));
1465 }
1466
1467 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
1468 GNUNET_assert (NULL != my_identity_hash);
1469
1470 // We could follow with the rest of the Key Schedule (dES, HS, ...) for now
1471 /* Check that we are actually in the receiving role */
1472 GNUNET_CRYPTO_hash (&kx->peer, sizeof(struct GNUNET_PeerIdentity), &h1);
1473 if (0 < GNUNET_CRYPTO_hash_cmp (&h1, my_identity_hash))
1474 {
1475 /* peer with "lower" identity starts KX, otherwise we typically end up
1476 with both peers starting the exchange and transmit the 'set key'
1477 message twice */
1478 /* Something went wrong - we have the lower value and should have sent the
1479 * InitiatorHello, but instead received it. TODO handle this case
1480 * We might end up in this case if the initiator didn't initiate the
1481 * handshake long enough and the 'responder' initiates the handshake */
1483 "Something went wrong - we have the lower value and should have sent the InitiatorHello, but instead received it.\n");
1484 GNUNET_free (ihm_ctx->ihm_e);
1485 GNUNET_free (ihm_ctx);
1487 kx->transcript_hash_ctx = NULL;
1488 return;
1489 }
1490
1491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer ID of other peer: %s\n", GNUNET_i2s
1492 (&kx->peer));
1493 /* We update the monitoring peers here because now we know
1494 * that we can decrypt the message AND know the PID
1495 */
1496 monitor_notify_all (kx);
1497 kx->ss_R = *ss_R;
1498 kx->early_secret_key = es;
1499 kx->early_traffic_secret = ets;
1501}
1502
1503
1504static int
1505check_initiator_hello (void *cls, const struct InitiatorHello *m)
1506{
1507 uint16_t size = ntohs (m->header.size);
1508
1509 if (size < sizeof (*m)
1510 + sizeof (struct InitiatorHelloPayload)
1512 {
1513 return GNUNET_SYSERR;
1514 }
1515 return GNUNET_OK;
1516}
1517
1518
1527static void
1528handle_initiator_hello (void *cls, const struct InitiatorHello *ihm_e)
1529{
1530 const struct GNUNET_HashCode *my_identity_hash;
1531 struct GSC_KeyExchangeInfo *kx = cls;
1532 struct InitiatorHelloCtx *initiator_hello_cls;
1533 size_t ihm_len;
1534
1535 if (ROLE_INITIATOR == kx->role)
1536 {
1537 GNUNET_break_op (0);
1539 "I am an initiator! Tearing down...\n");
1540 return;
1541 }
1543 {
1544 GNUNET_break_op (0);
1546 "Already received InitiatorHello: %d %d\n", kx->role, kx->status
1547 );
1548 return;
1549 }
1551 (NULL != kx->transcript_hash_ctx))
1552 {
1554 "Already received InitiatorHello and sent ResponderHello: %d %d\n",
1555 kx->role, kx->status);
1556 return;
1557 }
1558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorHello: %d %d\n", kx->
1559 role, kx->status);
1563
1565 gettext_noop ("# key exchanges initiated"),
1566 1,
1567 GNUNET_NO);
1568
1570
1571 my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
1572 GNUNET_assert (NULL != my_identity_hash);
1573
1574 // 1. verify type _INITIATOR_HELLO
1575 // - This is implicytly done by arriving within this handler
1576 // - or is this about verifying the 'additional data' part of aead?
1577 // should it check the encryption + mac? (is this implicitly done
1578 // while decrypting?)
1579 // 2. verify H(pk_R) matches pk_R
1580 if (0 != memcmp (&ihm_e->h_pk_R,
1581 my_identity_hash,
1582 sizeof (struct GNUNET_HashCode)))
1583 {
1585 "This message is not meant for us (H(PID) mismatch)\n");
1587 kx->transcript_hash_ctx = NULL;
1588 return;
1589 }
1590 // FIXME this sometimes triggers in the tests - why?
1591 // 3. decaps -> shared_secret_R, c_R (kemChallenge)
1592 ihm_len = ntohs (ihm_e->header.size);
1593 initiator_hello_cls = GNUNET_new (struct InitiatorHelloCtx);
1594 initiator_hello_cls->kx = kx;
1595 initiator_hello_cls->ihm_e = GNUNET_malloc (ihm_len);
1596 GNUNET_memcpy (initiator_hello_cls->ihm_e, ihm_e, ihm_len);
1597 initiator_hello_cls->req = GNUNET_new (struct PilsRequest);
1600 initiator_hello_cls->req);
1601 initiator_hello_cls->req->op =
1603 &ihm_e->c_R,
1604 // encapsulated key
1606 // continuation
1607 initiator_hello_cls);
1608}
1609
1610
1612{
1613 /* Current KX session */
1615
1616 /* responder hello message - encrypted */
1618
1619 /* responder hello message - plain/decrypted */
1621
1622 /* Decrypted finish hash */
1624
1625 /* Encrypted finished CT (for transcript later) */
1626 char finished_enc[sizeof (struct GNUNET_HashCode)
1627 + AEAD_TAG_BYTES];
1628
1629 /* Temporary transcript context */
1631
1632 /* Temporary handshake secret */
1634
1635 /* Temporary handshake secret */
1637
1638 /* Temporary handshake secret */
1640
1641 /* Temporary handshake secret */
1643
1644 /* Pending PILS request */
1646};
1647
1648static void
1650{
1651 struct GSC_KeyExchangeInfo *kx = cls;
1652
1653 kx->resend_task = NULL;
1654 if (0 == kx->resend_tries_left)
1655 {
1657 "Restarting KX\n");
1658 restart_kx (kx);
1659 return;
1660 }
1661 kx->resend_tries_left--;
1663 "Resending initiator done. Retries left: %u\n",
1664 kx->resend_tries_left);
1668 kx);
1669}
1670
1671
1672static void
1674{
1675 struct ResponderHelloCls *rh_ctx = cls;
1676 struct GSC_KeyExchangeInfo *kx = rh_ctx->kx;
1677 struct InitiatorDone *idm_e; /* encrypted */
1678 struct InitiatorDone idm_local;
1679 struct InitiatorDone *idm_p; /* plaintext */
1680 struct GNUNET_MQ_Envelope *env;
1681 unsigned char enc_key[AEAD_KEY_BYTES];
1682 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1683 struct ConfirmationAck ack_i;
1684 struct GNUNET_HashCode transcript;
1685 struct GNUNET_ShortHashCode ms;
1686
1687 rh_ctx->req->op = NULL;
1690 rh_ctx->req);
1691 GNUNET_free (rh_ctx->req);
1692 // XXX valgrind reports uninitialized memory
1693 // the following is a way to check whether this memory was meant
1694 // memset (&rhm_local, 0, sizeof (rhm_local)); - adapt to cls if still needed
1695 memset (&idm_local, 0, sizeof (idm_local));
1696
1697 kx->ss_I = *ss_I;
1698
1699 /* derive *ATS */
1700 derive_ms (&rh_ctx->hs, ss_I, &ms);;
1701 // 5. Create ResponderFinished as per Section 6 and check against decrypted payload.
1702 struct GNUNET_HashCode responder_finished;
1703 // Transcript updates, snapshot again
1704 snapshot_transcript (rh_ctx->hc,
1705 &transcript);
1706#if DEBUG_KX
1708 "Transcript snapshot for derivation of Rfinished: `%s'\n",
1709 GNUNET_h2s (&transcript));
1710#endif
1711 generate_responder_finished (&transcript,
1712 &ms,
1713 &responder_finished);
1714 if (0 != memcmp (&rh_ctx->decrypted_finish,
1715 &responder_finished,
1716 sizeof (struct GNUNET_HashCode)))
1717 {
1719 "Could not verify \"responder finished\"\n");
1720 GNUNET_free (rh_ctx->rhp);
1722 GNUNET_free (rh_ctx);
1723 GNUNET_assert (0);
1724 return;
1725 }
1726
1727
1728 /* Forward the transcript
1729 * after generating finished_R,
1730 * before deriving *ATS */
1732 rh_ctx->hc,
1733 rh_ctx->finished_enc,
1734 sizeof (rh_ctx->finished_enc));
1735
1736 // At this point we cannot fail anymore and may lock into kx
1738 kx->transcript_hash_ctx = rh_ctx->hc;
1739 kx->ss_I = *ss_I;
1740 kx->handshake_secret = rh_ctx->hs;
1741 kx->ss_e = rh_ctx->ss_e;
1742 kx->ihts = rh_ctx->ihts;
1743 kx->rhts = rh_ctx->rhts;
1744 kx->master_secret = ms;
1745 GNUNET_free (rh_ctx->rhp);
1746 GNUNET_free (rh_ctx);
1747 rh_ctx = NULL;
1748
1750 &transcript);
1751#if DEBUG_KX
1753 "Transcript snapshot for derivation of *ATS: `%s'\n",
1754 GNUNET_h2s (&transcript));
1755#endif
1756 derive_initial_ats (&transcript,
1757 &kx->master_secret,
1759 &kx->their_ats[0]);
1760 for (int i = 0; i < MAX_EPOCHS - 1; i++)
1761 {
1762 derive_next_ats (&kx->their_ats[i],
1763 &kx->their_ats[i + 1]);
1764 }
1765 kx->their_max_epoch = MAX_EPOCHS - 1;
1766
1768 0,
1769 enc_key,
1770 enc_nonce);
1771 /* Create InitiatorDone message */
1772 idm_p = &idm_local; /* plaintext */
1773 env = GNUNET_MQ_msg_extra (idm_e,
1774 sizeof (ack_i)
1777 // 6. Create IteratorFinished as per Section 6.
1778 generate_initiator_finished (&transcript,
1779 &kx->master_secret,
1780 &idm_p->finished);
1782 "InteratorFinished: `%s'\n",
1783 GNUNET_h2s (&idm_p->finished));
1785 "Transcript `%s'\n",
1786 GNUNET_h2s (&transcript));
1787 // 7. Send InteratorFinished message encrypted with the key derived from IHTS to R
1788
1789 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1790 (unsigned char*) &idm_e->finished, /* c - ciphertext */
1791 NULL, /* clen_p */
1792 (unsigned char*) &idm_p->finished, /* idm_p - plaintext message */
1793 sizeof (idm_p->finished), // mlen
1794 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1795 // fields?
1796 NULL, // nsec - unused
1797 enc_nonce, // npub - nonce
1798 enc_key)); // k - key IHTS
1799 /* Forward the transcript hash context
1800 * after generating finished_I and RATS_0
1801 * before deriving IATS_0 */
1803 &idm_e->finished,
1804 sizeof (idm_e->finished)
1805 + AEAD_TAG_BYTES);
1807 &transcript);
1808#if DEBUG_KX
1810 "Transcript snapshot for derivation of *ATS: `%s'\n",
1811 GNUNET_h2s (&transcript));
1812#endif
1813 derive_initial_ats (&transcript,
1814 &kx->master_secret,
1816 &kx->current_ats);
1817 kx->current_epoch = 0;
1818 kx->current_sqn++;
1819 // 8. optionally encrypt payload TODO
1821 kx->current_sqn,
1822 enc_key,
1823 enc_nonce);
1824 kx->current_sqn++;
1826 ack_i.header.size = htons (sizeof ack_i);
1827 GNUNET_assert (0 == crypto_aead_xchacha20poly1305_ietf_encrypt (
1828 (unsigned char*) &idm_e[1], /* c - ciphertext */
1829 NULL, /* clen_p */
1830 (unsigned char*) &ack_i, /* rhm_p - plaintext message */
1831 sizeof ack_i, // mlen
1832 NULL, 0, // ad, adlen // FIXME should this not be the other, unencrypted
1833 // fields?
1834 NULL, // nsec - unused
1835 enc_nonce, // npub - nonce // FIXME nonce can be reused
1836 enc_key)); // k - key RHTS
1837
1838 GNUNET_MQ_send_copy (kx->mq, env);
1839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent InitiatorDone: %d %d\n", kx->role,
1840 kx->status);
1841
1842
1843 kx->resend_env = env;
1847 kx);
1849 monitor_notify_all (kx);
1850 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
1851}
1852
1853
1854static int
1855check_responder_hello (void *cls, const struct ResponderHello *m)
1856{
1857 uint16_t size = ntohs (m->header.size);
1858
1859 if (size < sizeof (*m)
1860 + sizeof (struct ResponderHelloPayload)
1861 + sizeof (struct GNUNET_HashCode)
1862 + AEAD_TAG_BYTES * 2)
1863 {
1864 return GNUNET_SYSERR;
1865 }
1866 return GNUNET_OK;
1867}
1868
1869
1875static void
1876handle_responder_hello (void *cls, const struct ResponderHello *rhm_e)
1877{
1878 struct GSC_KeyExchangeInfo *kx = cls;
1879 struct PilsRequest *req;
1880 struct ResponderHelloCls *rh_ctx;
1881 struct GNUNET_HashCode transcript;
1882 struct GNUNET_HashContext *hc;
1883 unsigned char enc_key[AEAD_KEY_BYTES];
1884 unsigned char enc_nonce[AEAD_NONCE_BYTES];
1886
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ResponderHello: %d %d\n", kx->
1888 role, kx->status);
1889
1891 if (NULL != kx->resend_task)
1892 {
1894 kx->resend_task = NULL;
1895 }
1896 if (NULL != kx->resend_env)
1897 {
1899 kx->resend_env = NULL;
1900 }
1901
1902 /* Forward the transcript hash context */
1903 if (ROLE_RESPONDER == kx->role)
1904 {
1905 GNUNET_break_op (0);
1907 "I am the responder! Ignoring.\n");
1909 return;
1910 }
1912 rhm_e,
1913 sizeof (struct ResponderHello));
1914 // 1. Verify that the message type is CORE_RESPONDER_HELLO
1915 // - implicitly done by handling this message?
1916 // - or is this about verifying the 'additional data' part of aead?
1917 // should it check the encryption + mac? (is this implicitly done
1918 // while decrypting?)
1919 // 2. sse <- Decaps(ske,ce)
1920 rh_ctx = GNUNET_new (struct ResponderHelloCls);
1921 ret = GNUNET_CRYPTO_hpke_kem_decaps (&kx->sk_e, // secret/private ephemeral key of initiator (us)
1922 &rhm_e->c_e, // encapsulated key
1923 &rh_ctx->ss_e); // key - ss_e
1924 if (GNUNET_OK != ret)
1925 {
1927 "Something went wrong decapsulating ss_e\n");
1929 return;
1930 }
1931 // 3. Generate IHTS and RHTS from Section 5 and decrypt ServicesInfo, cI and ResponderFinished.
1932 snapshot_transcript (hc, &transcript);
1933#if DEBUG_KX
1935 "Transcript snapshot for derivation of HS, *HTS: `%s'\n",
1936 GNUNET_h2s (&transcript));
1937#endif
1939 &rh_ctx->ss_e,
1940 &rh_ctx->hs);
1941 derive_rhts (&transcript,
1942 &rh_ctx->hs,
1943 &rh_ctx->rhts);
1944 derive_ihts (&transcript,
1945 &rh_ctx->hs,
1946 &rh_ctx->ihts);
1948 0,
1949 enc_key,
1950 enc_nonce);
1951 rh_ctx->kx = kx;
1952 GNUNET_memcpy (&rh_ctx->rhm_e, rhm_e, sizeof (*rhm_e));
1953 {
1954 unsigned long long int c_len;
1955 unsigned char *finished_buf;
1956 // use RHTS to decrypt
1957 c_len = ntohs (rhm_e->header.size) - sizeof (*rhm_e)
1958 - sizeof (struct GNUNET_HashCode)
1959 - AEAD_TAG_BYTES; // finished ct
1960 rh_ctx->rhp = GNUNET_malloc (c_len
1961 -
1963 rh_ctx->hc = hc;
1964 finished_buf = ((unsigned char*) &rhm_e[1]) + c_len;
1965 /* Forward the transcript_hash_ctx
1966 * after rhts has been generated,
1967 * before generating finished_R*/
1969 hc,
1970 &rhm_e[1],
1971 c_len);
1972
1973 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
1974 (unsigned char*) rh_ctx->rhp, // unsigned char *m
1975 NULL, // mlen_p message length
1976 NULL, // unsigned char *nsec - unused: NULL
1977 (unsigned char*) &rhm_e[1], // const unsigned char *c - ciphertext
1978 c_len, // unsigned long long clen - length of ciphertext
1979 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
1980 0, // unsigned long long adlen
1981 enc_nonce, // const unsigned char *npub - nonce
1982 enc_key // const unsigned char *k - key
1983 );
1984 if (0 != ret)
1985 {
1987 "Something went wrong decrypting: %d\n", ret);
1988 GNUNET_free (rh_ctx->rhp);
1989 GNUNET_free (rh_ctx);
1991 return;
1992 }
1993 // FIXME nonce reuse (see encryption)
1995 1,
1996 enc_key,
1997 enc_nonce);
1998 c_len = sizeof (struct GNUNET_HashCode)
2000 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2001 (unsigned char*) &rh_ctx->decrypted_finish, // unsigned char *m
2002 NULL, // mlen_p message length
2003 NULL, // unsigned char *nsec - unused: NULL
2004 finished_buf, // const unsigned char *c - ciphertext
2005 c_len, // unsigned long long clen - length of ciphertext
2006 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2007 0, // unsigned long long adlen
2008 enc_nonce, // const unsigned char *npub - nonce
2009 enc_key // const unsigned char *k - key
2010 );
2011 if (0 != ret)
2012 {
2014 "Something went wrong decrypting finished field: %d\n", ret);
2015 GNUNET_free (rh_ctx->rhp);
2016 GNUNET_free (rh_ctx);
2018 return;
2019 }
2020 GNUNET_memcpy (rh_ctx->finished_enc,
2021 finished_buf,
2022 c_len);
2023 }
2024 // 4. ssI <- Decaps(skI,cI).
2025 req = GNUNET_new (struct PilsRequest);
2026 rh_ctx->req = req;
2029 req);
2031 &rh_ctx->rhp->c_I, // encapsulated key
2032 &handle_responder_hello_cont, // continuation
2033 rh_ctx);
2034}
2035
2036
2037static int
2038check_initiator_done (void *cls, const struct InitiatorDone *m)
2039{
2040 uint16_t size = ntohs (m->header.size);
2041
2042 if (size < sizeof (*m) + sizeof (struct ConfirmationAck))
2043 {
2044 return GNUNET_SYSERR;
2045 }
2046 return GNUNET_OK;
2047}
2048
2049
2055static void
2056handle_initiator_done (void *cls, const struct InitiatorDone *idm_e)
2057{
2058 struct GSC_KeyExchangeInfo *kx = cls;
2059 struct InitiatorDone idm_local;
2060 struct InitiatorDone *idm_p = &idm_local; /* plaintext */
2061 struct GNUNET_HashCode initiator_finished;
2062 struct GNUNET_HashCode transcript;
2063 struct GNUNET_ShortHashCode their_ats;
2064 struct GNUNET_HashContext *hc;
2065 unsigned char enc_key[AEAD_KEY_BYTES];
2066 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2067 struct ConfirmationAck ack_i;
2068 struct ConfirmationAck ack_r;
2069 int8_t ret;
2070
2071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received InitiatorDone: %d %d\n", kx->
2072 role, kx->status);
2073 if (NULL != kx->resend_task)
2074 {
2076 kx->resend_task = NULL;
2077 }
2078 if (NULL != kx->resend_env)
2079 {
2080 GNUNET_free (kx->resend_env);
2081 kx->resend_env = NULL;
2082 }
2083 if (ROLE_INITIATOR == kx->role)
2084 {
2085 GNUNET_break_op (0);
2087 "I am the initiator! Tearing down...\n");
2088 return;
2089 }
2091 0,
2092 enc_key,
2093 enc_nonce);
2094 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2095 (unsigned char*) &idm_p->finished, // unsigned char *m
2096 NULL, // mlen_p message length
2097 NULL, // unsigned char *nsec - unused: NULL
2098 (unsigned char*) &idm_e->finished, // const unsigned char *c - ciphertext
2099 sizeof (idm_p->finished) // unsigned long long clen - length of ciphertext
2101 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2102 0, // unsigned long long adlen
2103 enc_nonce, // const unsigned char *npub - nonce
2104 enc_key // const unsigned char *k - key
2105 );
2106 if (0 != ret)
2107 {
2109 "Something went wrong decrypting: %d\n", ret);
2110 return;
2111 }
2112
2113 // - verify finished_I
2114 /* Generate finished_I
2115 * after Forwarding until {finished_R}RHTS
2116 * (did so while we prepared responder hello)
2117 * before forwarding to [{payload}RATS and] {finished_I}IHTS */
2118 // (look at the end of handle_initiator_hello())
2119 snapshot_transcript (kx->transcript_hash_ctx, &transcript);
2120 generate_initiator_finished (&transcript,
2121 &kx->master_secret,
2122 &initiator_finished);
2123 if (0 != memcmp (&idm_p->finished,
2124 &initiator_finished,
2125 sizeof (struct GNUNET_HashCode)))
2126 {
2128 "Could not verify \"initiator finished\" hash.\n");
2130 "Want: `%s'\n",
2131 GNUNET_h2s (&initiator_finished));
2133 "Have: `%s'\n",
2134 GNUNET_h2s (&idm_p->finished));
2136 "Transcript `%s'\n",
2137 GNUNET_h2s (&transcript));
2138 return;
2139 }
2140
2141 /* Forward the transcript hash_context_read */
2144 &idm_e->finished,
2145 sizeof (idm_e->finished)
2146 + AEAD_TAG_BYTES);
2147 snapshot_transcript (hc, &transcript);
2148 derive_initial_ats (&transcript,
2149 &kx->master_secret,
2151 &their_ats);
2152 derive_per_message_secrets (&their_ats, // FIXME other HS epoch?
2153 0,
2154 enc_key,
2155 enc_nonce);
2156 ret = crypto_aead_xchacha20poly1305_ietf_decrypt (
2157 (unsigned char*) &ack_i, // unsigned char *m
2158 NULL, // mlen_p message length
2159 NULL, // unsigned char *nsec - unused: NULL
2160 (unsigned char*) &idm_e[1], // const unsigned char *c - ciphertext
2161 sizeof (ack_i) + AEAD_TAG_BYTES, // unsigned long long clen - length of ciphertext
2162 NULL, // const unsigned char *ad - additional data (optional) TODO those should be used, right?
2163 0, // unsigned long long adlen
2164 enc_nonce, // const unsigned char *npub - nonce
2165 enc_key // const unsigned char *k - key
2166 );
2167 if (0 != ret)
2168 {
2170 "Something went wrong decrypting the Ack: %d\n", ret);
2172 return;
2173 }
2174 if ((sizeof ack_i != ntohs (ack_i.header.size)) ||
2175 (GNUNET_MESSAGE_TYPE_CORE_ACK != ntohs (ack_i.header.type)))
2176 {
2178 "Ack invalid!\n");
2180 return;
2181 }
2182 GNUNET_memcpy (&kx->their_ats[0],
2183 &their_ats,
2184 sizeof their_ats);
2188 for (int i = 0; i < MAX_EPOCHS - 1; i++)
2189 {
2190 derive_next_ats (&kx->their_ats[i],
2191 &kx->their_ats[i + 1]);
2192 }
2194 kx->transcript_hash_ctx = hc;
2199 monitor_notify_all (kx);
2200 kx->current_sqn = 1;
2201 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2202 GNUNET_assert (NULL == kx->heartbeat_task);
2203 update_timeout (kx);
2205 ack_r.header.size = htons (sizeof ack_r);
2207 &ack_r,
2208 sizeof ack_r);
2209
2210 GNUNET_TRANSPORT_core_receive_continue (transport,
2211 &kx->peer);
2212}
2213
2214
2220static int
2222{
2223 uint16_t size = ntohs (m->header.size) - sizeof(*m);
2224
2225 // TODO check (see check_encrypted ())
2226 // - check epoch
2227 // - check sequence number
2228 if (size < sizeof(struct GNUNET_MessageHeader))
2229 {
2230 GNUNET_break_op (0);
2231 return GNUNET_SYSERR;
2232 }
2233 return GNUNET_OK;
2234}
2235
2236
2242static void
2244 const struct Heartbeat *m)
2245{
2246 struct GNUNET_ShortHashCode new_ats;
2247 struct ConfirmationAck ack;
2248
2250 {
2251 if (kx->current_epoch == UINT64_MAX)
2252 {
2254 "Max epoch reached (you probably will never see this)\n");
2255 }
2256 else
2257 {
2258 kx->current_epoch++;
2261 kx->current_sqn = 0;
2263 &new_ats);
2264 memcpy (&kx->current_ats,
2265 &new_ats,
2266 sizeof new_ats);
2267 }
2268 }
2269 update_timeout (kx);
2271 ack.header.size = htons (sizeof ack);
2273 &ack,
2274 sizeof ack);
2275 if (NULL != kx->heartbeat_task)
2276 {
2280 kx);
2281 }
2282 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2283}
2284
2285
2286static enum GNUNET_GenericReturnValue
2288 const char *buf,
2289 size_t buf_len)
2290{
2291 struct GNUNET_MessageHeader *msg;
2292 struct ConfirmationAck *ack;
2293 struct Heartbeat *hb;
2294
2295 if (sizeof *msg > buf_len)
2296 return GNUNET_NO;
2297 msg = (struct GNUNET_MessageHeader*) buf;
2298 if (GNUNET_MESSAGE_TYPE_CORE_ACK == ntohs (msg->type))
2299 {
2300 ack = (struct ConfirmationAck *) buf;
2301 if (sizeof *ack != ntohs (ack->header.size))
2302 return GNUNET_NO;
2303 }
2304 else if (GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT == ntohs (msg->type))
2305 {
2306 hb = (struct Heartbeat*) buf;
2307 if (sizeof *hb != ntohs (hb->header.size))
2308 return GNUNET_NO;
2309 handle_heartbeat (kx, hb);
2310 }
2311 else
2312 {
2313 return GNUNET_NO;
2314 }
2315
2320 {
2321 GSC_SESSIONS_create (&kx->peer, kx, kx->class);
2326 if (NULL != kx->resend_task)
2328 kx->resend_task = NULL;
2329 if (NULL != kx->resend_env)
2330 GNUNET_free (kx->resend_env);
2331 kx->resend_env = NULL;
2332 monitor_notify_all (kx);
2333 }
2334 update_timeout (kx);
2335
2336 return GNUNET_YES;
2337}
2338
2339
2345static void
2347{
2348 struct GSC_KeyExchangeInfo *kx = cls;
2349 uint16_t size = ntohs (m->header.size);
2350 char buf[size - sizeof (*m)] GNUNET_ALIGN;
2351 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2352 const unsigned char *seq_enc_nonce;
2353 unsigned char enc_key[AEAD_KEY_BYTES];
2354 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2355 struct GNUNET_ShortHashCode new_ats[MAX_EPOCHS];
2356 uint32_t seq_enc_ctr;
2357 uint64_t epoch;
2358 uint64_t m_seq;
2359 uint64_t m_seq_nbo;
2360 uint64_t c_len;
2361 int8_t ret;
2362
2363 // TODO look at handle_encrypted
2364 // - statistics
2365
2369 {
2370 GSC_SESSIONS_end (&kx->peer);
2372 monitor_notify_all (kx);
2373 restart_kx (kx);
2374 return;
2375 }
2376 update_timeout (kx);
2377 epoch = GNUNET_ntohll (m->epoch);
2382 memcpy (new_ats,
2383 kx->their_ats,
2384 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2385 // FIXME here we could introduce logic that sends heartbeats
2386 // with key update request if we have not seen a new
2387 // epoch after a while (e.g. EPOCH_EXPIRATION)
2388 if (kx->their_max_epoch < epoch)
2389 {
2394 if ((epoch - kx->their_max_epoch) > 2 * MAX_EPOCHS)
2395 {
2397 "Epoch %" PRIu64 " is too new, will not decrypt...\n",
2398 epoch);
2399 GSC_SESSIONS_end (&kx->peer);
2401 monitor_notify_all (kx);
2402 restart_kx (kx);
2403 return;
2404 }
2405 for (uint64_t i = kx->their_max_epoch; i < epoch; i++)
2406 {
2407 derive_next_ats (&new_ats[i % MAX_EPOCHS],
2408 &new_ats[(i + 1) % MAX_EPOCHS]);
2409 }
2410 }
2411 else if ((kx->their_max_epoch - epoch) > MAX_EPOCHS)
2412 {
2414 "Epoch %" PRIu64 " is too old, cannot decrypt...\n",
2415 epoch);
2416 return;
2417 }
2418 derive_sn (
2419 &new_ats[epoch % MAX_EPOCHS],
2420 seq_enc_k,
2421 sizeof seq_enc_k);
2422 /* compute the sequence number */
2423 seq_enc_ctr = *((uint32_t*) m->tag);
2424 seq_enc_nonce = &m->tag[sizeof (uint32_t)];
2425#if DEBUG_KX
2426 GNUNET_print_bytes (&new_ats[epoch % MAX_EPOCHS],
2427 sizeof (struct GNUNET_ShortHashCode),
2428 8,
2429 GNUNET_NO);
2430 GNUNET_print_bytes (seq_enc_k,
2431 sizeof seq_enc_k,
2432 8,
2433 GNUNET_NO);
2434 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2435 sizeof seq_enc_ctr,
2436 8,
2437 GNUNET_NO);
2438#endif
2439 crypto_stream_chacha20_ietf_xor_ic (
2440 (unsigned char*) &m_seq_nbo,
2441 (unsigned char*) &m->sequence_number,
2442 sizeof (uint64_t),
2443 seq_enc_nonce,
2444 ntohl (seq_enc_ctr),
2445 seq_enc_k);
2446 m_seq = GNUNET_ntohll (m_seq_nbo);
2448 "Received encrypted message in epoch %" PRIu64
2449 " with E(SQN=%" PRIu64 ")=%" PRIu64
2450 "\n",
2451 epoch,
2452 m_seq,
2453 m->sequence_number);
2454 /* We are the initiator and as we are going to receive,
2455 * we are using the responder key material */
2456 derive_per_message_secrets (&new_ats[epoch % MAX_EPOCHS],
2457 m_seq,
2458 enc_key,
2459 enc_nonce);
2460 // TODO checking sequence numbers - handle the case of out-of-sync messages!
2461 // for now only decrypt the payload
2462 // TODO encrypt other fields, too!
2463 // TODO
2464 // c_len = size - offsetof ();
2465 c_len = size - sizeof (struct EncryptedMessage);
2466 ret = crypto_aead_xchacha20poly1305_ietf_decrypt_detached (
2467 (unsigned char*) buf, // m - plain message
2468 NULL, // nsec - unused
2469 (unsigned char*) &m[1], // c - ciphertext
2470 c_len, // clen
2471 (const unsigned char*) &m->tag, // mac
2472 NULL, // ad - additional data TODO
2473 0, // adlen
2474 enc_nonce, // npub
2475 enc_key // k
2476 );
2477 if (0 != ret)
2478 {
2480 "Something went wrong decrypting message\n");
2481 GNUNET_break_op (0); // FIXME handle gracefully
2482 return;
2483 }
2484 kx->their_max_epoch = epoch;
2485 memcpy (&kx->their_ats,
2486 new_ats,
2487 MAX_EPOCHS * sizeof (struct GNUNET_ShortHashCode));
2488
2490 buf,
2491 sizeof buf))
2492 {
2494 {
2496 "Dropping message as we are still waiting for handshake ACK\n");
2497 GNUNET_break_op (0);
2498 return;
2499 }
2500 if (GNUNET_OK !=
2502 buf,
2503 sizeof buf,
2504 GNUNET_YES,
2505 GNUNET_NO))
2506 GNUNET_break_op (0);
2507 }
2508 GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
2509}
2510
2511
2521static void
2523 const struct GNUNET_PeerIdentity *peer,
2524 void *handler_cls)
2525{
2526 struct GSC_KeyExchangeInfo *kx = handler_cls;
2527 (void) cls;
2528
2530 "Peer `%s' disconnected from us.\n",
2531 GNUNET_i2s (&kx->peer));
2532 GSC_SESSIONS_end (&kx->peer);
2534 gettext_noop ("# key exchanges stopped"),
2535 1,
2536 GNUNET_NO);
2537 if (NULL != kx->resend_task)
2538 {
2540 kx->resend_task = NULL;
2541 }
2542 if (NULL != kx->resend_env)
2543 {
2544 GNUNET_free (kx->resend_env);
2545 kx->resend_env = NULL;
2546 }
2547 if (NULL != kx->heartbeat_task)
2548 {
2550 kx->heartbeat_task = NULL;
2551 }
2553 monitor_notify_all (kx);
2554 if (kx->transcript_hash_ctx)
2555 {
2557 kx->transcript_hash_ctx = NULL;
2558 }
2560 GNUNET_MST_destroy (kx->mst);
2561 GNUNET_free (kx);
2562}
2563
2564
2565static void
2567{
2568 struct GSC_KeyExchangeInfo *kx = cls;
2569
2570 kx->resend_task = NULL;
2572 "Resending InitiatorHello.\n");
2574 // FIXME (Exponential) backoff?
2577 kx);
2578}
2579
2580
2586static void
2588{
2589 const struct GNUNET_PeerIdentity *my_identity;
2590 struct GNUNET_MQ_Envelope *env;
2591 struct GNUNET_ShortHashCode es;
2592 struct GNUNET_ShortHashCode ets;
2593 struct GNUNET_ShortHashCode ss_R;
2594 struct InitiatorHelloPayload *ihmp; /* initiator hello message - buffer on stack */
2595 struct InitiatorHello *ihm_e; /* initiator hello message - encrypted */
2596 long long unsigned int c_len;
2597 unsigned char enc_key[AEAD_KEY_BYTES];
2598 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2600 size_t pt_len;
2601
2603 GNUNET_assert (NULL != my_identity);
2604
2605 pt_len = sizeof (*ihmp) + strlen (my_services_info);
2606 c_len = pt_len + AEAD_TAG_BYTES;
2607 env = GNUNET_MQ_msg_extra (ihm_e,
2608 c_len,
2610 ihmp = (struct InitiatorHelloPayload*) &ihm_e[1];
2611 ihmp->peer_class = htons (GNUNET_CORE_CLASS_UNKNOWN); // TODO set this to a meaningful
2612 GNUNET_memcpy (&ihmp->pk_I,
2614 sizeof (struct GNUNET_PeerIdentity));
2615 GNUNET_CRYPTO_hash (&kx->peer, /* what to hash */ // TODO do we do this twice?
2616 sizeof (struct GNUNET_PeerIdentity),
2617 &ihm_e->h_pk_R); /* result */
2618 // TODO init hashcontext/transcript_hash
2619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send InitiatorHello: %d %d\n", kx->role,
2620 kx->status);
2621 GNUNET_assert (NULL == kx->transcript_hash_ctx);
2623 GNUNET_assert (NULL != kx->transcript_hash_ctx);
2624 // TODO fill services_info
2625
2626 // 1. Encaps
2627 ret = GNUNET_CRYPTO_eddsa_kem_encaps (&kx->peer.public_key, // public ephemeral key of initiator
2628 &ihm_e->c_R, // encapsulated key
2629 &ss_R); // key - ss_R
2630 if (GNUNET_OK != ret)
2631 {
2633 "Something went wrong encapsulating ss_R\n");
2634 // TODO handle
2635 }
2636 // 2. generate rR (uint64_t) - is this the nonce? Naming seems not quite
2637 // consistent
2638 ihm_e->r_I =
2639 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
2640 // 3. generate sk_e/pk_e - ephemeral key
2643 &kx->sk_e.ecdhe_key,
2644 &kx->pk_e.ecdhe_key);
2645 GNUNET_memcpy (&ihm_e->pk_e,
2646 &kx->pk_e.ecdhe_key,
2647 sizeof (kx->pk_e.ecdhe_key));
2648 // 4. generate ETS to encrypt
2649 // generate ETS (early_traffic_secret_key, decrypt pk_i
2650 // expand ETS <- expand ES <- extract ss_R
2651 // use ETS to decrypt
2653 ihm_e,
2654 sizeof (struct InitiatorHello));
2655 {
2656 struct GNUNET_HashCode transcript;
2658 &transcript);
2659 derive_es_ets (&transcript,
2660 &ss_R,
2661 &es,
2662 &ets);
2664 0,
2665 enc_key,
2666 enc_nonce);
2667 }
2668 // 5. encrypt
2669
2670 ret = crypto_aead_xchacha20poly1305_ietf_encrypt (
2671 (unsigned char*) &ihm_e[1], /* c - ciphertext */
2672 // mac,
2673 // NULL, // maclen_p
2674 &c_len, /* clen_p */
2675 (unsigned char*) ihmp, /* m - plaintext message */
2676 pt_len, // mlen
2677 NULL, 0, // ad, adlen // FIXME maybe over the unencrypted header?
2678 // fields?
2679 NULL, // nsec - unused
2680 enc_nonce, // npub - nonce
2681 enc_key); // k - key
2682 if (0 != ret)
2683 {
2684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Something went wrong encrypting\n");
2686 kx->transcript_hash_ctx = NULL;
2688 return;
2689 }
2690 /* Forward the transcript */
2693 &ihm_e[1],
2694 c_len);
2695
2697 kx->early_secret_key = es;
2698 kx->early_traffic_secret = ets;
2699 kx->ss_R = ss_R;
2700 monitor_notify_all (kx);
2701 GNUNET_MQ_send_copy (kx->mq, env);
2702 kx->resend_env = env;
2706 kx);
2707}
2708
2709
2710static void
2712{
2713 struct GNUNET_ShortHashCode new_ats;
2714
2715 if ((UINT64_MAX == kx->current_sqn) ||
2717 {
2719 "Epoch expiration %" PRIu64 " SQN %" PRIu64
2720 ", incrementing epoch...\n",
2722 kx->current_sqn);
2723 // Can this trigger? Maybe if we receive a lot of
2724 // heartbeats?
2725 GNUNET_assert (UINT64_MAX > kx->current_epoch);
2726 kx->current_epoch++;
2729 kx->current_sqn = 0;
2731 &new_ats);
2732 memcpy (&kx->current_ats,
2733 &new_ats,
2734 sizeof new_ats);
2735 }
2736}
2737
2738
2745void
2747 const void *payload,
2748 size_t payload_size)
2749{
2750 struct GNUNET_MQ_Envelope *env;
2751 struct EncryptedMessage *encrypted_msg;
2752 unsigned char enc_key[AEAD_KEY_BYTES];
2753 unsigned char enc_nonce[AEAD_NONCE_BYTES];
2754 unsigned char seq_enc_k[crypto_stream_chacha20_ietf_KEYBYTES];
2755 uint64_t sqn;
2756 uint64_t epoch;
2757 int8_t ret;
2758
2759 encrypted_msg = NULL;
2760
2761 check_rekey (kx);
2762 sqn = kx->current_sqn;
2763 epoch = kx->current_epoch;
2764 /* We are the sender and as we are going to send,
2765 * we are using the initiator key material */
2767 sqn,
2768 enc_key,
2769 enc_nonce);
2770 kx->current_sqn++;
2771 derive_sn (&kx->current_ats,
2772 seq_enc_k,
2773 sizeof seq_enc_k);
2774 env = GNUNET_MQ_msg_extra (encrypted_msg,
2775 payload_size,
2777 // only encrypt the payload for now
2778 // TODO encrypt other fields as well
2779 ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached (
2780 (unsigned char*) &encrypted_msg[1], // c - resulting ciphertext
2781 (unsigned char*) &encrypted_msg->tag, // mac - resulting mac/tag
2782 NULL, // maclen
2783 (unsigned char*) payload, // m - plain message
2784 payload_size, // mlen
2785 NULL, // ad - additional data TODO also cover the unencrypted part (epoch)
2786 0, // adlen
2787 NULL, // nsec - unused
2788 enc_nonce, // npub nonce
2789 enc_key // k - key
2790 );
2791 if (0 != ret)
2792 {
2794 "Something went wrong encrypting message\n");
2795 GNUNET_assert (0);
2796 }
2797 {
2798 /* compute the sequence number */
2799 unsigned char *seq_enc_nonce;
2800 uint64_t seq_nbo;
2801 uint32_t seq_enc_ctr;
2802
2803 seq_nbo = GNUNET_htonll (sqn);
2804 seq_enc_ctr = *((uint32_t*) encrypted_msg->tag);
2805 seq_enc_nonce = &encrypted_msg->tag[sizeof (uint32_t)];
2806 crypto_stream_chacha20_ietf_xor_ic (
2807 (unsigned char*) &encrypted_msg->sequence_number,
2808 (unsigned char*) &seq_nbo,
2809 sizeof seq_nbo,
2810 seq_enc_nonce,
2811 ntohl (seq_enc_ctr),
2812 seq_enc_k);
2813#if DEBUG_KX
2814 GNUNET_print_bytes (seq_enc_k,
2815 sizeof seq_enc_k,
2816 8,
2817 GNUNET_NO);
2818 GNUNET_print_bytes ((char*) &seq_enc_ctr,
2819 sizeof seq_enc_ctr,
2820 8,
2821 GNUNET_NO);
2822#endif
2824 "Sending encrypted message with E(SQN=%" PRIu64 ")=%" PRIu64
2825 "\n",
2826 sqn,
2827 encrypted_msg->sequence_number);
2828 }
2829 encrypted_msg->epoch = GNUNET_htonll (epoch);
2830
2831 // TODO actually copy payload
2832 GNUNET_MQ_send (kx->mq, env);
2833}
2834
2835
2836void
2838{
2839 const struct GNUNET_PeerIdentity *my_identity;
2841 GNUNET_MQ_hd_var_size (initiator_hello,
2843 struct InitiatorHello,
2844 NULL),
2845 GNUNET_MQ_hd_var_size (initiator_done,
2847 struct InitiatorDone,
2848 NULL),
2849 GNUNET_MQ_hd_var_size (responder_hello,
2851 struct ResponderHello,
2852 NULL),
2853 GNUNET_MQ_hd_var_size (encrypted_message, // TODO rename?
2855 struct EncryptedMessage,
2856 NULL),
2858 };
2859
2861 GNUNET_assert (NULL != my_identity);
2862
2864 transport =
2867 handlers,
2868 NULL, // cls - this connection-independant
2869 // cls seems not to be needed.
2870 // the connection-specific cls
2871 // will be set as a return value
2872 // of
2873 // handle_transport_notify_connect
2876 if (NULL == transport)
2877 {
2878 GSC_KX_done ();
2879 return;
2880 }
2881
2883 "Connected to TRANSPORT\n");
2884
2886}
2887
2888
2889void
2891 const struct GNUNET_HELLO_Parser *parser,
2892 const struct GNUNET_HashCode *hash)
2893{
2894 if (NULL != transport)
2895 return;
2896
2897 GSC_KX_start ();
2898}
2899
2900
2906int
2908{
2911 NULL);
2912 if (NULL == GSC_pils)
2913 {
2914 GSC_KX_done ();
2915 return GNUNET_SYSERR;
2916 }
2917
2918 return GNUNET_OK;
2919}
2920
2921
2925void
2927{
2928 struct PilsRequest *pr;
2929 while (NULL != (pr = pils_requests_head))
2930 {
2933 pr);
2934 if (NULL != pr->op)
2935 GNUNET_PILS_cancel (pr->op);
2936 GNUNET_free (pr);
2937 }
2938 if (NULL != GSC_pils)
2939 {
2941 GSC_pils = NULL;
2942 }
2943 if (NULL != transport)
2944 {
2946 transport = NULL;
2947 }
2948 if (NULL != rekey_task)
2949 {
2951 rekey_task = NULL;
2952 }
2953 if (NULL != nc)
2954 {
2956 nc = NULL;
2957 }
2958}
2959
2960
2967unsigned int
2969{
2970 return GNUNET_MQ_get_length (kxinfo->mq);
2971}
2972
2973
2974int
2976{
2977 return kxinfo->has_excess_bandwidth;
2978}
2979
2980
2989void
2991{
2992 struct GNUNET_MQ_Envelope *env;
2993 struct MonitorNotifyMessage *done_msg;
2994 struct GSC_KeyExchangeInfo *kx;
2995
2997 for (kx = kx_head; NULL != kx; kx = kx->next)
2998 {
2999 struct GNUNET_MQ_Envelope *env_notify;
3000 struct MonitorNotifyMessage *msg;
3001
3003 msg->state = htonl ((uint32_t) kx->status);
3004 msg->peer = kx->peer;
3005 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
3006 GNUNET_MQ_send (mq, env_notify);
3007 }
3009 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
3012}
3013
3014
3015/* 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.
Globals for gnunet-service-core.
#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...
code for managing the key exchange (SET_KEY, PING, PONG) with other peers
@ 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
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
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
Constants for network protocols.
API of the transport service towards the CORE service (TNG version)
struct GNUNET_TRANSPORT_CoreHandle * GNUNET_TRANSPORT_core_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *self, const struct GNUNET_MQ_MessageHandler *handlers, void *cls, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd)
Connect to the transport service.
void GNUNET_TRANSPORT_core_disconnect(struct GNUNET_TRANSPORT_CoreHandle *handle)
Disconnect from the transport service.
#define GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
After how long do we consider a connection to a peer dead if we don't receive messages from the peer?
GNUNET_CORE_PeerClass
The peer class gives a hint about the capabilities of a peer.
GNUNET_CORE_KxState
TODO how does this harmonize with CAKE_CRYPTO_ENABLED?
@ GNUNET_CORE_CLASS_UNKNOWN
The device's capabilities are currently unknown.
@ GNUNET_CORE_KX_PEER_DISCONNECT
Last state of a KX (when it is being terminated).
@ GNUNET_CORE_KX_STATE_RESPONDER_CONNECTED
Connected as responder.
@ GNUNET_CORE_KX_STATE_DOWN
No handshake yet.
@ GNUNET_CORE_KX_STATE_INITIATOR_DONE_SENT
We sent initiator done.
@ GNUNET_CORE_KX_STATE_INITIATOR_HELLO_RECEIVED
We've received the initiator hello.
@ GNUNET_CORE_KX_STATE_AWAIT_INITIATION
We are awating the initiator hello.
@ GNUNET_CORE_KX_STATE_INITIATOR_CONNECTED
Connected as initiator.
@ GNUNET_CORE_KX_STATE_INITIATOR_HELLO_SENT
We sent the initiator hello.
@ GNUNET_CORE_KX_STATE_RESPONDER_HELLO_SENT
We sent the responder hello.
@ GNUNET_CORE_KX_ITERATION_FINISHED
This is not a state in a peer's state machine, but a special value used with the GNUNET_CORE_MonitorC...
void GNUNET_CRYPTO_ecdhe_key_create(struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
Create a new private key.
Definition crypto_ecc.c:454
uint64_t GNUNET_CRYPTO_random_u64(uint64_t max)
Generate a random unsigned 64-bit value.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hpke_kem_decaps(const struct GNUNET_CRYPTO_HpkePrivateKey *priv, const struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Decapsulate a key for a private X25519 key.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hpke_kem_encaps(const struct GNUNET_CRYPTO_HpkePublicKey *pkR, struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Encapsulate key material for a X25519 public key.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_eddsa_kem_encaps(const struct GNUNET_CRYPTO_EddsaPublicKey *pub, struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Encapsulate key material for a EdDSA public key.
void GNUNET_CRYPTO_ecdhe_key_get_public(const struct GNUNET_CRYPTO_EcdhePrivateKey *priv, struct GNUNET_CRYPTO_EcdhePublicKey *pub)
Extract the public key for the given private key.
Definition crypto_ecc.c:217
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hkdf_extract(struct GNUNET_ShortHashCode *prk, const void *salt, size_t salt_len, const void *ikm, size_t ikm_len)
HKDF-Extract using SHA256.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:40
void GNUNET_CRYPTO_hmac(const struct GNUNET_CRYPTO_AuthKey *key, const void *plaintext, size_t plaintext_len, struct GNUNET_HashCode *hmac)
Calculate HMAC of a message (RFC 2104)
#define GNUNET_CRYPTO_hkdf_expand(result, out_len, prk,...)
HKDF-Expand using SHA256.
int GNUNET_CRYPTO_hash_cmp(const struct GNUNET_HashCode *h1, const struct GNUNET_HashCode *h2)
Compare function for HashCodes, producing a total ordering of all hashcodes.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_B2S(obj)
Convert a fixed-sized object to a string using GNUNET_b2s().
void GNUNET_CRYPTO_hash_context_read(struct GNUNET_HashContext *hc, const void *buf, size_t size)
Add data to be hashed.
struct GNUNET_HashContext * GNUNET_CRYPTO_hash_context_copy(const struct GNUNET_HashContext *hc)
Make a copy of the hash computation.
#define GNUNET_CRYPTO_kdf_arg_string(d)
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
void * cls
Closure for mv and cb.
void GNUNET_CRYPTO_hash_context_abort(struct GNUNET_HashContext *hc)
Abort hashing, do not bother calculating final result.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
void GNUNET_CRYPTO_hash_context_finish(struct GNUNET_HashContext *hc, struct GNUNET_HashCode *r_hash)
Finish the hash computation.
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_CRYPTO_kdf_arg_auto(d)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
struct GNUNET_HashContext * GNUNET_CRYPTO_hash_context_start(void)
Start incremental hashing operation.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
void GNUNET_print_bytes(const void *buf, size_t buf_len, int fold, int in_be)
Print a byte string in hexadecimal ascii notation.
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition nc.c:138
void GNUNET_MQ_send_copy(struct GNUNET_MQ_Handle *mq, const struct GNUNET_MQ_Envelope *ev)
Send a copy of a message with the given message queue.
Definition mq.c:384
unsigned int GNUNET_MQ_get_length(struct GNUNET_MQ_Handle *mq)
Obtain the current length of the message queue.
Definition mq.c:293
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:305
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
void GNUNET_MQ_discard(struct GNUNET_MQ_Envelope *mqm)
Discard the message queue message, free all allocated resources.
Definition mq.c:285
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition nc.c:122
void GNUNET_notification_context_broadcast(struct GNUNET_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop)
Send a message to all subscribers of this context.
Definition nc.c:190
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition nc.c:161
#define GNUNET_MESSAGE_TYPE_CORE_HEARTBEAT
Message updating the keys of the peers.
#define GNUNET_MESSAGE_TYPE_CORE_ACK
Acknowledgement of prior messages.
#define GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE_CAKE
Encrypted message.
#define GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY
Reply for monitor by CORE service.
#define GNUNET_MESSAGE_TYPE_CORE_INITIATOR_DONE
Third and final message of the handshake, second of the initiator.
#define GNUNET_MESSAGE_TYPE_CORE_RESPONDER_HELLO
Reply to the first message from the initiator - first message sent by the responder.
#define GNUNET_MESSAGE_TYPE_CORE_INITIATOR_HELLO
for more detail on the following messages see https://lsd.gnunet.org/lsd0012/draft-schanzen-cake....
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1283
enum GNUNET_GenericReturnValue GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition mst.c:101
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition mst.c:86
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition mst.c:404
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_max(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the maximum of two relative time values.
Definition time.c:352
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition time.c:406
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition time.c:316
struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Divide relative time by a given factor.
Definition time.c:548
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_difference(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute end)
Compute the time difference between the given start and end times.
Definition time.c:423
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:636
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition time.c:667
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
static unsigned int size
Size of the "table".
Definition peer.c:68
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
struct GNUNET_MessageHeader header
Message type is GNUNET_MESSAGE_TYPE_CORE_ACK.
unsigned char tag[crypto_aead_xchacha20poly1305_ietf_ABYTES]
The Poly1305 tag of the encrypted message (which is starting at sequence_number), used to verify mess...
uint64_t sequence_number
Sequence number, in network byte order.
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.
uint32_t flags
Flags.
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.