aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-01-28 13:10:29 +0100
committerChristian Grothoff <christian@grothoff.org>2019-01-28 13:10:29 +0100
commit0157a38006025eecbed40d04153817a5df0d0e6a (patch)
tree1b1f33a0fd095d43546e278dce7cbab96c3cf443 /src/transport
parent07533eec5c7b1637374ea1496595918861ac8b6d (diff)
downloadgnunet-0157a38006025eecbed40d04153817a5df0d0e6a.tar.gz
gnunet-0157a38006025eecbed40d04153817a5df0d0e6a.zip
rekeys
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/Makefile.am1
-rw-r--r--src/transport/gnunet-communicator-tcp.c298
2 files changed, 190 insertions, 109 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index ead9beeec..80b7f2252 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -257,6 +257,7 @@ gnunet_communicator_tcp_SOURCES = \
257gnunet_communicator_tcp_LDADD = \ 257gnunet_communicator_tcp_LDADD = \
258 libgnunettransportcommunicator.la \ 258 libgnunettransportcommunicator.la \
259 $(top_builddir)/src/nat/libgnunetnatnew.la \ 259 $(top_builddir)/src/nat/libgnunetnatnew.la \
260 $(top_builddir)/src/nt/libgnunetnt.la \
260 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 261 $(top_builddir)/src/statistics/libgnunetstatistics.la \
261 $(top_builddir)/src/util/libgnunetutil.la \ 262 $(top_builddir)/src/util/libgnunetutil.la \
262 $(LIBGCRYPT_LIBS) 263 $(LIBGCRYPT_LIBS)
diff --git a/src/transport/gnunet-communicator-tcp.c b/src/transport/gnunet-communicator-tcp.c
index 050a5f225..7d52a41db 100644
--- a/src/transport/gnunet-communicator-tcp.c
+++ b/src/transport/gnunet-communicator-tcp.c
@@ -25,7 +25,7 @@
25 * 25 *
26 * TODO: 26 * TODO:
27 * - NAT service API change to handle address stops! 27 * - NAT service API change to handle address stops!
28 * - handling of rekeys! 28 * - address construction for HELLOs (FIXMEs, easy)
29 */ 29 */
30#include "platform.h" 30#include "platform.h"
31#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
@@ -423,6 +423,12 @@ struct Queue
423 * means we must switch to the new key material. 423 * means we must switch to the new key material.
424 */ 424 */
425 int rekey_state; 425 int rekey_state;
426
427 /**
428 * #GNUNET_YES if we just rekeyed and must thus possibly
429 * re-decrypt ciphertext.
430 */
431 int rekeyed;
426}; 432};
427 433
428 434
@@ -527,6 +533,11 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
527static const struct GNUNET_CONFIGURATION_Handle *cfg; 533static const struct GNUNET_CONFIGURATION_Handle *cfg;
528 534
529/** 535/**
536 * Network scanner to determine network types.
537 */
538static struct GNUNET_NT_InterfaceScanner *is;
539
540/**
530 * Connection to NAT service. 541 * Connection to NAT service.
531 */ 542 */
532static struct GNUNET_NAT_Handle *nat; 543static struct GNUNET_NAT_Handle *nat;
@@ -776,12 +787,133 @@ pass_plaintext_to_core (struct Queue *queue,
776 787
777 788
778/** 789/**
790 * Setup @a cipher based on shared secret @a dh and decrypting
791 * peer @a pid.
792 *
793 * @param dh shared secret
794 * @param pid decrypting peer's identity
795 * @param cipher[out] cipher to initialize
796 * @param hmac_key[out] HMAC key to initialize
797 */
798static void
799setup_cipher (const struct GNUNET_HashCode *dh,
800 const struct GNUNET_PeerIdentity *pid,
801 gcry_cipher_hd_t *cipher,
802 struct GNUNET_HashCode *hmac_key)
803{
804 char key[256/8];
805 char ctr[128/8];
806
807 gcry_cipher_open (cipher,
808 GCRY_CIPHER_AES256 /* low level: go for speed */,
809 GCRY_CIPHER_MODE_CTR,
810 0 /* flags */);
811 GNUNET_assert (GNUNET_YES ==
812 GNUNET_CRYPTO_kdf (key,
813 sizeof (key),
814 "TCP-key",
815 strlen ("TCP-key"),
816 dh,
817 sizeof (*dh),
818 pid,
819 sizeof (*pid),
820 NULL, 0));
821 gcry_cipher_setkey (*cipher,
822 key,
823 sizeof (key));
824 GNUNET_assert (GNUNET_YES ==
825 GNUNET_CRYPTO_kdf (ctr,
826 sizeof (ctr),
827 "TCP-ctr",
828 strlen ("TCP-ctr"),
829 dh,
830 sizeof (*dh),
831 pid,
832 sizeof (*pid),
833 NULL, 0));
834 gcry_cipher_setctr (*cipher,
835 ctr,
836 sizeof (ctr));
837 GNUNET_assert (GNUNET_YES ==
838 GNUNET_CRYPTO_kdf (hmac_key,
839 sizeof (struct GNUNET_HashCode),
840 "TCP-hmac",
841 strlen ("TCP-hmac"),
842 dh,
843 sizeof (*dh),
844 pid,
845 sizeof (*pid),
846 NULL, 0));
847}
848
849
850/**
851 * Setup cipher of @a queue for decryption.
852 *
853 * @param ephemeral ephemeral key we received from the other peer
854 * @param queue[in,out] queue to initialize decryption cipher for
855 */
856static void
857setup_in_cipher (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
858 struct Queue *queue)
859{
860 struct GNUNET_HashCode dh;
861
862 GNUNET_CRYPTO_eddsa_ecdh (my_private_key,
863 ephemeral,
864 &dh);
865 setup_cipher (&dh,
866 &my_identity,
867 &queue->in_cipher,
868 &queue->in_hmac);
869}
870
871
872/**
873 * Handle @a rekey message on @a queue. The message was already
874 * HMAC'ed, but we should additionally still check the signature.
875 * Then we need to stop the old cipher and start afresh.
876 *
877 * @param queue the queue @a rekey was received on
878 * @param rekey the rekey message
879 */
880static void
881do_rekey (struct Queue *queue,
882 const struct TCPRekey *rekey)
883{
884 struct TcpHandshakeSignature thp;
885
886 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY);
887 thp.purpose.size = htonl (sizeof (thp));
888 thp.sender = queue->target;
889 thp.receiver = my_identity;
890 thp.ephemeral = rekey->ephemeral;
891 thp.monotonic_time = rekey->monotonic_time;
892 if (GNUNET_OK !=
893 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY,
894 &thp.purpose,
895 &rekey->sender_sig,
896 &queue->target.public_key))
897 {
898 GNUNET_break (0);
899 queue_finish (queue);
900 return;
901 }
902 gcry_cipher_close (queue->in_cipher);
903 queue->rekeyed = GNUNET_YES;
904 setup_in_cipher (&rekey->ephemeral,
905 queue);
906}
907
908
909/**
779 * Test if we have received a full message in plaintext. 910 * Test if we have received a full message in plaintext.
780 * If so, handle it. 911 * If so, handle it.
781 * 912 *
782 * @param queue queue to process inbound plaintext for 913 * @param queue queue to process inbound plaintext for
914 * @return number of bytes of plaintext handled, 0 for none
783 */ 915 */
784static void 916static size_t
785try_handle_plaintext (struct Queue *queue) 917try_handle_plaintext (struct Queue *queue)
786{ 918{
787 const struct GNUNET_MessageHeader *hdr 919 const struct GNUNET_MessageHeader *hdr
@@ -799,14 +931,14 @@ try_handle_plaintext (struct Queue *queue)
799 size_t size = 0; /* make compiler happy */ 931 size_t size = 0; /* make compiler happy */
800 932
801 if (sizeof (*hdr) > queue->pread_off) 933 if (sizeof (*hdr) > queue->pread_off)
802 return; /* not even a header */ 934 return 0; /* not even a header */
803 type = ntohs (hdr->type); 935 type = ntohs (hdr->type);
804 switch (type) 936 switch (type)
805 { 937 {
806 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX: 938 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX:
807 /* Special case: header size excludes box itself! */ 939 /* Special case: header size excludes box itself! */
808 if (ntohs (hdr->size) + sizeof (struct TCPBox) > queue->pread_off) 940 if (ntohs (hdr->size) + sizeof (struct TCPBox) > queue->pread_off)
809 return; 941 return 0;
810 hmac (&queue->in_hmac, 942 hmac (&queue->in_hmac,
811 &box[1], 943 &box[1],
812 ntohs (hdr->size), 944 ntohs (hdr->size),
@@ -817,7 +949,7 @@ try_handle_plaintext (struct Queue *queue)
817 { 949 {
818 GNUNET_break_op (0); 950 GNUNET_break_op (0);
819 queue_finish (queue); 951 queue_finish (queue);
820 return; 952 return 0;
821 } 953 }
822 pass_plaintext_to_core (queue, 954 pass_plaintext_to_core (queue,
823 (const void *) &box[1], 955 (const void *) &box[1],
@@ -826,12 +958,12 @@ try_handle_plaintext (struct Queue *queue)
826 break; 958 break;
827 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY: 959 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY:
828 if (sizeof (*rekey) > queue->pread_off) 960 if (sizeof (*rekey) > queue->pread_off)
829 return; 961 return 0;
830 if (ntohs (hdr->size) != sizeof (*rekey)) 962 if (ntohs (hdr->size) != sizeof (*rekey))
831 { 963 {
832 GNUNET_break_op (0); 964 GNUNET_break_op (0);
833 queue_finish (queue); 965 queue_finish (queue);
834 return; 966 return 0;
835 } 967 }
836 rekeyz = *rekey; 968 rekeyz = *rekey;
837 memset (&rekeyz.hmac, 969 memset (&rekeyz.hmac,
@@ -847,20 +979,20 @@ try_handle_plaintext (struct Queue *queue)
847 { 979 {
848 GNUNET_break_op (0); 980 GNUNET_break_op (0);
849 queue_finish (queue); 981 queue_finish (queue);
850 return; 982 return 0;
851 } 983 }
852 // FIXME: handle rekey! 984 do_rekey (queue,
853 985 rekey);
854 size = ntohs (hdr->size); 986 size = ntohs (hdr->size);
855 break; 987 break;
856 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH: 988 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH:
857 if (sizeof (*fin) > queue->pread_off) 989 if (sizeof (*fin) > queue->pread_off)
858 return; 990 return 0;
859 if (ntohs (hdr->size) != sizeof (*fin)) 991 if (ntohs (hdr->size) != sizeof (*fin))
860 { 992 {
861 GNUNET_break_op (0); 993 GNUNET_break_op (0);
862 queue_finish (queue); 994 queue_finish (queue);
863 return; 995 return 0;
864 } 996 }
865 finz = *fin; 997 finz = *fin;
866 memset (&finz.hmac, 998 memset (&finz.hmac,
@@ -876,7 +1008,7 @@ try_handle_plaintext (struct Queue *queue)
876 { 1008 {
877 GNUNET_break_op (0); 1009 GNUNET_break_op (0);
878 queue_finish (queue); 1010 queue_finish (queue);
879 return; 1011 return 0;
880 } 1012 }
881 /* handle FINISH by destroying queue */ 1013 /* handle FINISH by destroying queue */
882 queue_destroy (queue); 1014 queue_destroy (queue);
@@ -884,15 +1016,10 @@ try_handle_plaintext (struct Queue *queue)
884 default: 1016 default:
885 GNUNET_break_op (0); 1017 GNUNET_break_op (0);
886 queue_finish (queue); 1018 queue_finish (queue);
887 return; 1019 return 0;
888 } 1020 }
889 GNUNET_assert (0 != size); 1021 GNUNET_assert (0 != size);
890 /* 'size' bytes of plaintext were used, shift buffer */ 1022 return size;
891 GNUNET_assert (size <= queue->pread_off);
892 memmove (queue->pread_buf,
893 &queue->pread_buf[size],
894 queue->pread_off - size);
895 queue->pread_off -= size;
896} 1023}
897 1024
898 1025
@@ -933,10 +1060,14 @@ queue_read (void *cls)
933 if (0 != rcvd) 1060 if (0 != rcvd)
934 reschedule_queue_timeout (queue); 1061 reschedule_queue_timeout (queue);
935 queue->cread_off += rcvd; 1062 queue->cread_off += rcvd;
936 if (queue->pread_off < sizeof (queue->pread_buf)) 1063 while ( (queue->pread_off < sizeof (queue->pread_buf)) &&
1064 (queue->cread_off > 0) )
937 { 1065 {
938 size_t max = GNUNET_MIN (sizeof (queue->pread_buf) - queue->pread_off, 1066 size_t max = GNUNET_MIN (sizeof (queue->pread_buf) - queue->pread_off,
939 queue->cread_off); 1067 queue->cread_off);
1068 size_t done;
1069 size_t total;
1070
940 GNUNET_assert (0 == 1071 GNUNET_assert (0 ==
941 gcry_cipher_decrypt (queue->in_cipher, 1072 gcry_cipher_decrypt (queue->in_cipher,
942 &queue->pread_buf[queue->pread_off], 1073 &queue->pread_buf[queue->pread_off],
@@ -944,11 +1075,35 @@ queue_read (void *cls)
944 queue->cread_buf, 1075 queue->cread_buf,
945 max)); 1076 max));
946 queue->pread_off += max; 1077 queue->pread_off += max;
1078 total = 0;
1079 while ( (GNUNET_NO == queue->rekeyed) &&
1080 (0 != (done = try_handle_plaintext (queue))) )
1081 {
1082 /* 'done' bytes of plaintext were used, shift buffer */
1083 GNUNET_assert (done <= queue->pread_off);
1084 /* NOTE: this memmove() could possibly sometimes be
1085 avoided if we pass 'total' into try_handle_plaintext()
1086 and use it at an offset into the buffer there! */
1087 memmove (queue->pread_buf,
1088 &queue->pread_buf[done],
1089 queue->pread_off - done);
1090 queue->pread_off -= done;
1091 total += done;
1092 }
1093 /* when we encounter a rekey message, the decryption above uses the
1094 wrong key for everything after the rekey; in that case, we have
1095 to re-do the decryption at 'total' instead of at 'max'. If there
1096 is no rekey and the last message is incomplete (max > total),
1097 it is safe to keep the decryption so we shift by 'max' */
1098 if (GNUNET_YES == queue->rekeyed)
1099 {
1100 max = total;
1101 queue->rekeyed = GNUNET_NO;
1102 }
947 memmove (queue->cread_buf, 1103 memmove (queue->cread_buf,
948 &queue->cread_buf[max], 1104 &queue->cread_buf[max],
949 queue->cread_off - max); 1105 queue->cread_off - max);
950 queue->cread_off -= max; 1106 queue->cread_off -= max;
951 try_handle_plaintext (queue);
952 } 1107 }
953 1108
954 if (BUF_SIZE == queue->cread_off) 1109 if (BUF_SIZE == queue->cread_off)
@@ -1106,89 +1261,6 @@ tcp_address_to_sockaddr (const char *bindto,
1106 1261
1107 1262
1108/** 1263/**
1109 * Setup @a cipher based on shared secret @a dh and decrypting
1110 * peer @a pid.
1111 *
1112 * @param dh shared secret
1113 * @param pid decrypting peer's identity
1114 * @param cipher[out] cipher to initialize
1115 * @param hmac_key[out] HMAC key to initialize
1116 */
1117static void
1118setup_cipher (const struct GNUNET_HashCode *dh,
1119 const struct GNUNET_PeerIdentity *pid,
1120 gcry_cipher_hd_t *cipher,
1121 struct GNUNET_HashCode *hmac_key)
1122{
1123 char key[256/8];
1124 char ctr[128/8];
1125
1126 gcry_cipher_open (cipher,
1127 GCRY_CIPHER_AES256 /* low level: go for speed */,
1128 GCRY_CIPHER_MODE_CTR,
1129 0 /* flags */);
1130 GNUNET_assert (GNUNET_YES ==
1131 GNUNET_CRYPTO_kdf (key,
1132 sizeof (key),
1133 "TCP-key",
1134 strlen ("TCP-key"),
1135 dh,
1136 sizeof (*dh),
1137 pid,
1138 sizeof (*pid),
1139 NULL, 0));
1140 gcry_cipher_setkey (*cipher,
1141 key,
1142 sizeof (key));
1143 GNUNET_assert (GNUNET_YES ==
1144 GNUNET_CRYPTO_kdf (ctr,
1145 sizeof (ctr),
1146 "TCP-ctr",
1147 strlen ("TCP-ctr"),
1148 dh,
1149 sizeof (*dh),
1150 pid,
1151 sizeof (*pid),
1152 NULL, 0));
1153 gcry_cipher_setctr (*cipher,
1154 ctr,
1155 sizeof (ctr));
1156 GNUNET_assert (GNUNET_YES ==
1157 GNUNET_CRYPTO_kdf (hmac_key,
1158 sizeof (struct GNUNET_HashCode),
1159 "TCP-hmac",
1160 strlen ("TCP-hmac"),
1161 dh,
1162 sizeof (*dh),
1163 pid,
1164 sizeof (*pid),
1165 NULL, 0));
1166}
1167
1168
1169/**
1170 * Setup cipher of @a queue for decryption.
1171 *
1172 * @param ephemeral ephemeral key we received from the other peer
1173 * @param queue[in,out] queue to initialize decryption cipher for
1174 */
1175static void
1176setup_in_cipher (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
1177 struct Queue *queue)
1178{
1179 struct GNUNET_HashCode dh;
1180
1181 GNUNET_CRYPTO_eddsa_ecdh (my_private_key,
1182 ephemeral,
1183 &dh);
1184 setup_cipher (&dh,
1185 &my_identity,
1186 &queue->in_cipher,
1187 &queue->in_hmac);
1188}
1189
1190
1191/**
1192 * Setup cipher for outgoing data stream based on target and 1264 * Setup cipher for outgoing data stream based on target and
1193 * our ephemeral private key. 1265 * our ephemeral private key.
1194 * 1266 *
@@ -1474,7 +1546,9 @@ static void
1474boot_queue (struct Queue *queue, 1546boot_queue (struct Queue *queue,
1475 enum GNUNET_TRANSPORT_ConnectionStatus cs) 1547 enum GNUNET_TRANSPORT_ConnectionStatus cs)
1476{ 1548{
1477 queue->nt = 0; // FIXME: determine NT! 1549 queue->nt = GNUNET_NT_scanner_get_type (is,
1550 queue->address,
1551 queue->address_len);
1478 (void) GNUNET_CONTAINER_multipeermap_put (queue_map, 1552 (void) GNUNET_CONTAINER_multipeermap_put (queue_map,
1479 &queue->target, 1553 &queue->target,
1480 queue, 1554 queue,
@@ -1502,14 +1576,14 @@ boot_queue (struct Queue *queue,
1502 GNUNET_asprintf (&foreign_addr, 1576 GNUNET_asprintf (&foreign_addr,
1503 "%s-%s:%d", 1577 "%s-%s:%d",
1504 COMMUNICATOR_ADDRESS_PREFIX, 1578 COMMUNICATOR_ADDRESS_PREFIX,
1505 "inet-ntop-fixme", 1579 "inet-ntop-FIXME",
1506 4242); 1580 4242);
1507 break; 1581 break;
1508 case AF_INET6: 1582 case AF_INET6:
1509 GNUNET_asprintf (&foreign_addr, 1583 GNUNET_asprintf (&foreign_addr,
1510 "%s-%s:%d", 1584 "%s-%s:%d",
1511 COMMUNICATOR_ADDRESS_PREFIX, 1585 COMMUNICATOR_ADDRESS_PREFIX,
1512 "inet-ntop-fixme", 1586 "inet-ntop-FIXME",
1513 4242); 1587 4242);
1514 break; 1588 break;
1515 default: 1589 default:
@@ -2044,6 +2118,11 @@ do_shutdown (void *cls)
2044 GNUNET_free (my_private_key); 2118 GNUNET_free (my_private_key);
2045 my_private_key = NULL; 2119 my_private_key = NULL;
2046 } 2120 }
2121 if (NULL != is)
2122 {
2123 GNUNET_NT_scanner_done (is);
2124 is = NULL;
2125 }
2047} 2126}
2048 2127
2049 2128
@@ -2197,6 +2276,7 @@ run (void *cls,
2197 cfg); 2276 cfg);
2198 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 2277 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
2199 NULL); 2278 NULL);
2279 is = GNUNET_NT_scanner_init ();
2200 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg); 2280 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
2201 if (NULL == my_private_key) 2281 if (NULL == my_private_key)
2202 { 2282 {