From 97782d1a85e43d55626b150c06b6479afd8d20d6 Mon Sep 17 00:00:00 2001 From: t3sserakt Date: Tue, 24 Nov 2020 12:36:05 +0100 Subject: - added inband udp communicator rekey logic --- src/transport/gnunet-communicator-udp.c | 810 +++++++++++++++++---- src/transport/test_communicator_basic.c | 31 +- .../test_communicator_udp_rekey_peer1.conf | 8 + .../test_communicator_udp_rekey_peer2.conf | 8 + 4 files changed, 706 insertions(+), 151 deletions(-) diff --git a/src/transport/gnunet-communicator-udp.c b/src/transport/gnunet-communicator-udp.c index e967e8e9a..849adf4ab 100644 --- a/src/transport/gnunet-communicator-udp.c +++ b/src/transport/gnunet-communicator-udp.c @@ -51,7 +51,7 @@ /** * How often do we rekey based on time (at least) */ -#define REKEY_TIME_INTERVAL GNUNET_TIME_UNIT_DAYS +#define DEFAULT_REKEY_TIME_INTERVAL GNUNET_TIME_UNIT_DAYS /** * How long do we wait until we must have received the initial KX? @@ -207,6 +207,11 @@ struct InitialKX * key derived from the handshake with sequence number zero. */ char gcm_tag[GCM_TAG_SIZE]; + + /** + * A flag indicating, if the sender is doing rekeying. + */ + int rekeying; }; @@ -339,8 +344,42 @@ struct UDPBox * `struct UdpHandshakeSignature`. */ char gcm_tag[GCM_TAG_SIZE]; + + /** + * A flag indicating, if the sender is doing rekeying. + */ + int rekeying; }; +/** + * UDP message box. Always sent encrypted, only allowed after + * the receiver sent a `struct UDPAck` for the base key! + */ +struct UDPRekey +{ + /** + * Key and IV identification code. KDF applied to an acknowledged + * base key and a sequence number. Sequence numbers must be used + * monotonically increasing up to the maximum specified in + * `struct UDPAck`. Without further `struct UDPAck`s, the sender + * must fall back to sending handshakes! + */ + struct GNUNET_ShortHashCode kid; + + /** + * 128-bit authentication tag for the following encrypted message, + * from GCM. MAC starts at the @e body_start that follows and + * extends until the end of the UDP payload. If the @e hmac is + * wrong, the receiver should check if the message might be a + * `struct UdpHandshakeSignature`. + */ + char gcm_tag[GCM_TAG_SIZE]; + + /** + * Sender's identity + */ + struct GNUNET_PeerIdentity sender; +}; GNUNET_NETWORK_STRUCT_END @@ -470,6 +509,11 @@ struct SharedSecret */ struct SenderAddress { + /** + * Flag indicating sender is initiated rekeying for this receiver. + */ + int rekeying; + /** * To whom are we talking to. */ @@ -520,6 +564,11 @@ struct SenderAddress * Which network type does this queue use? */ enum GNUNET_NetworkType nt; + + /** + * sender_destroy already called on sender. + */ + int sender_destroy_called; }; @@ -529,6 +578,37 @@ struct SenderAddress */ struct ReceiverAddress { + + /** + * Shared secret we use with @e target for rekeying. + */ + struct SharedSecret *ss_rekey; + + /** + * Acks available when we started rekeying. + */ + unsigned int rekey_acks_available; + + /** + * Send bytes for this receiver address. + */ + uint64_t rekey_send_bytes; + + /** + * Timeout for this receiver address. + */ + struct GNUNET_TIME_Absolute rekey_timeout; + + /** + * Flag indicating sender is initiated rekeying for this receiver. + */ + int rekeying; + + /** + * Numer of kce we retain for sending the rekeying shared secret. + */ + int number_rekeying_kce; + /** * To whom are we talking to. */ @@ -615,8 +695,12 @@ struct ReceiverAddress * Which network type does this queue use? */ enum GNUNET_NetworkType nt; -}; + /** + * receiver_destroy already called on receiver. + */ + int receiver_destroy_called; +}; /** * Interface we broadcast our presence on. @@ -671,9 +755,9 @@ struct BroadcastInterface }; /** - * Timeout for this receiver address. - */ -struct GNUNET_TIME_Absolute *rekey_timeout; + * The rekey interval + */ +static struct GNUNET_TIME_Relative rekey_interval; /** * Shared secret we finished the last kce working queue for. @@ -700,6 +784,11 @@ static struct GNUNET_SCHEDULER_Task *timeout_task; */ static struct GNUNET_SCHEDULER_Task *kce_task; +/** + * ID of kce rekey working queue task + */ +static struct GNUNET_SCHEDULER_Task *kce_task_rekey; + /** * Is the kce_task finished? */ @@ -832,26 +921,28 @@ bi_destroy (struct BroadcastInterface *bi) static void receiver_destroy (struct ReceiverAddress *receiver) { - struct GNUNET_MQ_Handle *mq; + + receiver->receiver_destroy_called = GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting receiver for peer `%s'\n", GNUNET_i2s (&receiver->target)); - if (NULL != (mq = receiver->kx_mq)) + /*if (NULL != (mq = receiver->kx_mq)) { receiver->kx_mq = NULL; GNUNET_MQ_destroy (mq); - } + }*/ if (NULL != receiver->kx_qh) { GNUNET_TRANSPORT_communicator_mq_del (receiver->kx_qh); receiver->kx_qh = NULL; + receiver->kx_mq = NULL; } - if (NULL != (mq = receiver->d_mq)) + /*if (NULL != (mq = receiver->d_mq)) { receiver->d_mq = NULL; GNUNET_MQ_destroy (mq); - } + }*/ if (NULL != receiver->d_qh) { GNUNET_TRANSPORT_communicator_mq_del (receiver->d_qh); @@ -956,8 +1047,9 @@ kce_generate (struct SharedSecret *ss, uint32_t seq) * Destroy @a ss and associated key cache entries. * * @param ss shared secret to destroy + * @param withoutKce If GNUNET_YES shared secrets with kce will not be destroyed. */ -static void +static int secret_destroy (struct SharedSecret *ss, int withoutKce) { struct SenderAddress *sender; @@ -970,7 +1062,7 @@ secret_destroy (struct SharedSecret *ss, int withoutKce) ss->sequence_allowed); if (withoutKce && (ss->sequence_allowed > 0)) - return; + return GNUNET_NO; if (NULL != (sender = ss->sender)) { @@ -993,6 +1085,7 @@ secret_destroy (struct SharedSecret *ss, int withoutKce) GNUNET_CONTAINER_multishortmap_size (key_cache), GNUNET_NO); GNUNET_free (ss); + return GNUNET_YES; } @@ -1005,6 +1098,7 @@ secret_destroy (struct SharedSecret *ss, int withoutKce) static void sender_destroy (struct SenderAddress *sender) { + sender->sender_destroy_called = GNUNET_YES; GNUNET_assert ( GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (senders, &sender->target, sender)); @@ -1100,20 +1194,26 @@ check_timeouts (void *cls) rt = GNUNET_TIME_UNIT_FOREVER_REL; while (NULL != (receiver = GNUNET_CONTAINER_heap_peek (receivers_heap))) { - rt = GNUNET_TIME_absolute_get_remaining (receiver->timeout); - if (0 != rt.rel_value_us) - break; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Receiver timed out\n"); - receiver_destroy (receiver); + if (GNUNET_YES != receiver->receiver_destroy_called) + { + rt = GNUNET_TIME_absolute_get_remaining (receiver->timeout); + if (0 != rt.rel_value_us) + break; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiver timed out\n"); + receiver_destroy (receiver); + } } st = GNUNET_TIME_UNIT_FOREVER_REL; while (NULL != (sender = GNUNET_CONTAINER_heap_peek (senders_heap))) { - st = GNUNET_TIME_absolute_get_remaining (sender->timeout); - if (0 != st.rel_value_us) - break; - sender_destroy (sender); + if (GNUNET_YES != sender->sender_destroy_called) + { + st = GNUNET_TIME_absolute_get_remaining (sender->timeout); + if (0 != st.rel_value_us) + break; + sender_destroy (sender); + } } delay = GNUNET_TIME_relative_min (rt, st); if (delay.rel_value_us < GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) @@ -1289,7 +1389,7 @@ setup_shared_secret_dec (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral) */ static struct SharedSecret * setup_shared_secret_enc (const struct GNUNET_CRYPTO_EcdhePrivateKey *ephemeral, - struct ReceiverAddress *receiver) + struct ReceiverAddress *receiver, int add_to_receiver) { struct SharedSecret *ss; @@ -1316,6 +1416,114 @@ setup_shared_secret_enc (const struct GNUNET_CRYPTO_EcdhePrivateKey *ephemeral, static void setup_receiver_mq (struct ReceiverAddress *receiver); +/** + * Destroying all secrets. Depending on parameter we keep those secrets having a kce. + * + * @param ss The secret we will not destroy. + * @param withoutKce If GNUNET_YES shared secrets with kce will not be destroyed. + */ +static void +destroy_all_secrets (struct SharedSecret *ss, int withoutKce) +{ + struct SenderAddress *sender; + struct ReceiverAddress *receiver; + struct SharedSecret *ss_to_destroy; + struct SharedSecret *ss_start; + struct SharedSecret *pos; + int at_least_one_destroyed = GNUNET_NO; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting destroy all.\n"); + + if (NULL != (sender = ss->sender)) + { + ss_start = sender->ss_head; + } + else if (NULL != (receiver = ss->receiver)) + { + ss_start = receiver->ss_head; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Shared secret has no sender or receiver!\n"); + return; + } + + pos = ss_start; + while ( NULL != pos) + { + ss_to_destroy = pos; + pos = pos->next; + + if (ss != ss_to_destroy) + at_least_one_destroyed = secret_destroy (ss_to_destroy, withoutKce); + } + + if ((ss != ss_start) && ! at_least_one_destroyed) + { + destroy_all_secrets (ss_start, GNUNET_NO); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished destroy all.\n"); +} + +static void +add_acks (struct SharedSecret *ss, int acks_to_add, int remove_from_receiver) +{ + + struct ReceiverAddress *receiver = ss->receiver; + + if (NULL == ss) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "secret NULL!\n"); + + if (NULL == receiver) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiver NULL!\n"); + if (NULL == receiver->d_qh) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Queue NULL!\n"); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Tell transport we have %u more acks!\n", + acks_to_add); + GNUNET_TRANSPORT_communicator_mq_update (ch, + receiver->d_qh, + acks_to_add, + 1); + // Until here for alternativ 1 + + /* move ss to head to avoid discarding it anytime soon! */ + if (remove_from_receiver) + GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss); + GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss); + destroy_all_secrets (ss, GNUNET_YES); + + + // Uncomment this for alternativ 2 of backchannel functionality + /*if (receiver->acks_available != ack->acks_available) + { + receiver->acks_available = ack->acks_available; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Tell transport we have different number of acks!\n"); + GNUNET_TRANSPORT_communicator_mq_update (ch, + receiver->d_qh, + receiver->acks_available, + 1); + }*/ + // Until here for alternativ 2 +} + +static void +add_acks_rekey (struct ReceiverAddress *receiver) +{ + add_acks (receiver->ss_rekey, receiver->ss_rekey->sequence_allowed - 3, + GNUNET_NO); + receiver->acks_available = receiver->ss_rekey->sequence_allowed; + receiver->ss_rekey = NULL; +} /** * We received an ACK for @a pid. Check if it is for @@ -1332,18 +1540,48 @@ handle_ack (void *cls, const struct GNUNET_PeerIdentity *pid, void *value) { const struct UDPAck *ack = cls; struct ReceiverAddress *receiver = value; - struct SharedSecret *pos; + int acks_to_add; + uint32_t allowed; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "in handle ack\n"); - struct SharedSecret *ss_to_destroy; + + if (NULL != receiver->ss_rekey) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received secret with cmac %s \n", + GNUNET_h2s (&receiver->ss_rekey->cmac)); + + if ((NULL != receiver->ss_rekey) && (0 == memcmp (&ack->cmac, + &receiver->ss_rekey->cmac, + sizeof(struct + GNUNET_HashCode))) ) + { + allowed = ntohl (ack->sequence_max); + + if (allowed > receiver->ss_rekey->sequence_allowed) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%u > %u (%u %u) for rekey secrect %s\n", allowed, + receiver->ss_rekey->sequence_allowed, + receiver->acks_available, + ack->acks_available, + GNUNET_h2s (&receiver->ss_rekey->master)); + + receiver->ss_rekey->sequence_allowed = allowed; + + if (GNUNET_NO == receiver->rekeying) + add_acks_rekey (receiver); + + return GNUNET_NO; + } + } (void) pid; for (struct SharedSecret *ss = receiver->ss_head; NULL != ss; ss = ss->next) { if (0 == memcmp (&ack->cmac, &ss->cmac, sizeof(struct GNUNET_HashCode))) { - uint32_t allowed; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found matching mac\n"); @@ -1358,41 +1596,19 @@ handle_ack (void *cls, const struct GNUNET_PeerIdentity *pid, void *value) ack->acks_available, GNUNET_h2s (&ss->master)); // Uncomment this for alternativ 1 of backchannel functionality + acks_to_add = (allowed - ss->sequence_allowed); + if ((GNUNET_NO == receiver->rekeying) && + (receiver->number_rekeying_kce < + 3) ) + { + acks_to_add -= (3 - receiver->number_rekeying_kce); + receiver->number_rekeying_kce = 3; + } receiver->acks_available += (allowed - ss->sequence_allowed); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Tell transport we have more acks!\n"); - GNUNET_TRANSPORT_communicator_mq_update (ch, - receiver->d_qh, - (allowed - - ss->sequence_allowed), - 1); - // Until here for alternativ 1 ss->sequence_allowed = allowed; - /* move ss to head to avoid discarding it anytime soon! */ - GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss); - GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss); - pos = receiver->ss_head; - while ( NULL != pos) - { - ss_to_destroy = pos; - pos = pos->next; - secret_destroy (ss_to_destroy, GNUNET_YES); - } + add_acks (ss, acks_to_add, GNUNET_YES); } - - // Uncomment this for alternativ 2 of backchannel functionality - /*if (receiver->acks_available != ack->acks_available) - { - receiver->acks_available = ack->acks_available; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Tell transport we have different number of acks!\n"); - GNUNET_TRANSPORT_communicator_mq_update (ch, - receiver->d_qh, - receiver->acks_available, - 1); - }*/ - // Until here for alternativ 2 return GNUNET_NO; } } @@ -1446,6 +1662,8 @@ try_handle_plaintext (struct SenderAddress *sender, } } + + static void kce_generate_cb (void *cls) { @@ -1477,6 +1695,30 @@ kce_generate_cb (void *cls) } +static void +kce_generate_rekey_cb (void *cls) +{ + struct SharedSecret *ss = cls; + + if (NULL == kce_task) + { + for (int i = 0; i < GENERATE_AT_ONCE; i++) + kce_generate (ss, ++ss->sequence_allowed); + + kce_task = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL, + kce_generate_cb, + ss); + kce_task_rekey = NULL; + } + else + { + kce_task_rekey = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL, + kce_generate_rekey_cb, + ss); + } +} + + /** * We established a shared secret with a sender. We should try to send * the sender an `struct UDPAck` at the next opportunity to allow the @@ -1489,9 +1731,6 @@ kce_generate_cb (void *cls) static void consider_ss_ack (struct SharedSecret *ss, int initial) { - struct SharedSecret *ss_to_destroy; - struct SharedSecret *pos; - GNUNET_assert (NULL != ss->sender); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering SS UDPAck %s\n", @@ -1535,18 +1774,13 @@ consider_ss_ack (struct SharedSecret *ss, int initial) &ss_finished->sender->target, COMMUNICATOR_ADDRESS_PREFIX, &ack.header); - pos = ss->sender->ss_head; - while ( NULL != pos) - { - ss_to_destroy = pos; - pos = pos->next; - secret_destroy (ss_to_destroy, GNUNET_YES); - } + destroy_all_secrets (ss, GNUNET_YES); kce_task = NULL; + kce_task_finished = GNUNET_NO; } - else if (((NULL == kce_task) && (KCN_THRESHOLD > - ss->sender->acks_available)) || - (ss->sender->num_secrets > MAX_SECRETS) ) + else if ((NULL == kce_task) && ((KCN_THRESHOLD > ss->sender->acks_available)|| + (GNUNET_YES == ss->sender->rekeying) || + (ss->sender->num_secrets > MAX_SECRETS) )) { // kce_generate (ss, ++ss->sequence_allowed); @@ -1556,39 +1790,13 @@ consider_ss_ack (struct SharedSecret *ss, int initial) ss); } - - - /*if (ss->active_kce_count < KCN_THRESHOLD) + else if ((NULL == kce_task_rekey) && (GNUNET_YES == + ss->sender->rekeying) ) { - struct UDPAck ack; - - /** - * If we previously have seen this ss - * we now generate KCN_TARGET KCEs. - * For the initial KX (active_kce_count==0), - * we only generate a single KCE to prevent - * unnecessary overhead. - - if (0 < ss->active_kce_count) - { - while (ss->active_kce_count < KCN_TARGET) - kce_generate (ss, ++ss->sequence_allowed); - } - else { - kce_generate (ss, ++ss->sequence_allowed); - } - ack.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK); - ack.header.size = htons (sizeof(ack)); - ack.sequence_max = htonl (ss->sequence_allowed); - ack.cmac = ss->cmac; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Notifying transport of UDPAck %s\n", - GNUNET_i2s_full (&ss->sender->target)); - GNUNET_TRANSPORT_communicator_notify (ch, - &ss->sender->target, - COMMUNICATOR_ADDRESS_PREFIX, - &ack.header); - }*/ + kce_task_rekey = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL, + kce_generate_rekey_cb, + ss); + } } @@ -1631,9 +1839,107 @@ decrypt_box (const struct UDPBox *box, "decrypted UDPBox with kid %s\n", GNUNET_sh2s (&box->kid)); try_handle_plaintext (ss->sender, out_buf, sizeof(out_buf)); - consider_ss_ack (ss, GNUNET_NO); + if ((GNUNET_NO == box->rekeying) && (GNUNET_YES == ss->sender->rekeying)) + { + ss->sender->rekeying = GNUNET_NO; + // destroy_all_secrets (ss, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiver stopped rekeying.\n"); + } + else if (GNUNET_NO == box->rekeying) + consider_ss_ack (ss, GNUNET_YES); + else{ + ss->sender->rekeying = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiver started rekeying.\n"); + } } +/** + * We received a @a rekey with matching @a kce. Decrypt and process it. + * + * @param rekey the data we received + * @param rekey_len number of bytes in @a rekey + * @param kce key index to decrypt @a rekey + */ +static void +decrypt_rekey (const struct UDPRekey *rekey, + size_t rekey_len, + struct KeyCacheEntry *kce, + struct SenderAddress *sender) +{ + struct SharedSecret *ss = kce->ss; + struct SharedSecret *ss_rekey; + char out_buf[rekey_len - sizeof(*rekey)]; + struct GNUNET_HashCode *master; + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "decrypt_rekey.\n"); + + GNUNET_assert (NULL != ss->sender); + if (GNUNET_OK != try_decrypt (ss, + rekey->gcm_tag, + kce->sequence_number, + (const char *) &rekey[1], + sizeof(out_buf), + out_buf)) + { + GNUNET_STATISTICS_update (stats, + "# Decryption failures with valid KCE", + 1, + GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Decryption with kid %s failed\n", + GNUNET_sh2s (&rekey->kid)); + kce_destroy (kce); + return; + } + kce_destroy (kce); + GNUNET_STATISTICS_update (stats, + "# bytes decrypted with Rekey", + sizeof(out_buf), + GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "decrypted UDPRekey with kid %s\n", + GNUNET_sh2s (&rekey->kid)); + /*cmac = (struct GNUNET_HashCode *) out_buf; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received secret with cmac %s \n", + GNUNET_h2s (&cmac));*/ + // ss_rekey = (struct SharedSecret *) out_buf; + master = (struct GNUNET_HashCode *) out_buf; + ss_rekey = GNUNET_new (struct SharedSecret); + ss_rekey->master = *master; + calculate_cmac (ss_rekey); + ss_rekey->sender = sender; + // ss_rekey->sequence_used = 0; + // ss_rekey->sequence_allowed = 0; + /* ss_rekey->active_kce_count = 0; */ + /* ss_rekey->prev = NULL; */ + /* ss_rekey->next = NULL; */ + /* GNUNET_assert (ss_rekey->prev == NULL && sender->ss_head != ss_rekey); */ + /* GNUNET_assert (ss_rekey->next == NULL && sender->ss_tail != ss_rekey); */ + GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss_rekey); + sender->num_secrets++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received secret with cmac %s\n", + GNUNET_h2s (&(ss_rekey->cmac))); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received secret with master %s.\n", + GNUNET_h2s (&(ss_rekey->master))); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "We have %u sequence_allowed.\n", + ss_rekey->sequence_allowed); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "We have a sender %p\n", + ss_rekey->sender); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "We have %u acks available.\n", + ss_rekey->sender->acks_available); + consider_ss_ack (ss_rekey, GNUNET_YES); + +} /** * Closure for #find_sender_by_address() @@ -1832,6 +2138,38 @@ sock_read (void *cls) } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %lu bytes\n", rcvd); + + if (rcvd > sizeof(struct UDPRekey)) + { + const struct UDPRekey *rekey; + const struct UDPBox *box; + struct KeyCacheEntry *kce; + struct SenderAddress *sender; + int do_decrypt = GNUNET_NO; + + rekey = (const struct UDPRekey *) buf; + box = (const struct UDPBox *) buf; + kce = GNUNET_CONTAINER_multishortmap_get (key_cache, &rekey->kid); + + if ((GNUNET_YES == box->rekeying)||(GNUNET_NO == box->rekeying)) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "UDPRekey has rekeying %u\n", + box->rekeying); + else + do_decrypt = GNUNET_YES; + if ((GNUNET_YES == do_decrypt)&& (NULL != kce) && (GNUNET_YES == + kce->ss->sender->rekeying)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "UDPRekey with kid %s\n", + GNUNET_sh2s (&rekey->kid)); + sender = setup_sender (&rekey->sender, (const struct sockaddr *) &sa, + salen); + decrypt_rekey (rekey, (size_t) rcvd, kce, sender); + return; + } + } + /* first, see if it is a UDPBox */ if (rcvd > sizeof(struct UDPBox)) { @@ -1949,7 +2287,20 @@ sock_read (void *cls) 1, GNUNET_NO); try_handle_plaintext (sender, &uc[1], sizeof(pbuf) - sizeof(*uc)); - consider_ss_ack (ss, GNUNET_YES); + if ((GNUNET_NO == kx->rekeying) && (GNUNET_YES == ss->sender->rekeying)) + { + ss->sender->rekeying = GNUNET_NO; + // destroy_all_secrets (ss, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiver stopped rekeying.\n"); + } + else if (GNUNET_NO == kx->rekeying) + consider_ss_ack (ss, GNUNET_YES); + else{ + ss->sender->rekeying = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiver started rekeying.\n"); + } /*if (sender->num_secrets > MAX_SECRETS) secret_destroy (sender->ss_tail);*/ } @@ -2138,26 +2489,13 @@ mq_send_kx (struct GNUNET_MQ_Handle *mq, size_t dpos; gcry_cipher_hd_t out_cipher; struct SharedSecret *ss; - struct SharedSecret *ss_to_destroy; - struct SharedSecret *pos; - - if (receiver->num_secrets > MAX_SECRETS) - { - pos = receiver->ss_head; - while ( NULL != pos) - { - ss_to_destroy = pos; - pos = pos->next; - secret_destroy (ss_to_destroy, GNUNET_YES); - } - } - GNUNET_assert (mq == receiver->kx_mq); if (msize > receiver->kx_mtu) { GNUNET_break (0); - receiver_destroy (receiver); + if (GNUNET_YES != receiver->receiver_destroy_called) + receiver_destroy (receiver); return; } reschedule_receiver_timeout (receiver); @@ -2165,7 +2503,13 @@ mq_send_kx (struct GNUNET_MQ_Handle *mq, /* setup key material */ GNUNET_CRYPTO_ecdhe_key_create (&epriv); - ss = setup_shared_secret_enc (&epriv, receiver); + ss = setup_shared_secret_enc (&epriv, receiver, GNUNET_YES); + + if (receiver->num_secrets > MAX_SECRETS) + { + destroy_all_secrets (ss, GNUNET_YES); + } + setup_cipher (&ss->master, 0, &out_cipher); /* compute 'uc' */ uc.sender = my_identity; @@ -2199,6 +2543,10 @@ mq_send_kx (struct GNUNET_MQ_Handle *mq, GNUNET_assert ( 0 == gcry_cipher_gettag (out_cipher, kx.gcm_tag, sizeof(kx.gcm_tag))); gcry_cipher_close (out_cipher); + if (GNUNET_NO == receiver->rekeying) + kx.rekeying = GNUNET_NO; + else + kx.rekeying = GNUNET_YES; memcpy (dgram, &kx, sizeof(kx)); if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock, dgram, @@ -2212,6 +2560,162 @@ mq_send_kx (struct GNUNET_MQ_Handle *mq, GNUNET_MQ_impl_send_continue (mq); } +static void +check_for_rekeying (struct ReceiverAddress *receiver, struct UDPBox *box) +{ + + struct GNUNET_TIME_Relative rt; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout is %lu\n.", + receiver->rekey_timeout.abs_value_us); + + if (0 == receiver->rekey_timeout.abs_value_us) + { + receiver->rekey_timeout = GNUNET_TIME_relative_to_absolute ( + rekey_interval); + } + else + { + rt = GNUNET_TIME_absolute_get_remaining (receiver->rekey_timeout); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Relative time is %lu and timeout is %lu\n.", + rt.rel_value_us, + receiver->rekey_timeout.abs_value_us); + + if ((0 == rt.rel_value_us)||(receiver->rekey_send_bytes > + REKEY_MAX_BYTES) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Bytes send %lu greater than %llu max bytes\n.", + receiver->rekey_send_bytes, + REKEY_MAX_BYTES); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Relative time is %lu and timeout is %lu\n.", + rt.rel_value_us, + receiver->rekey_timeout.abs_value_us); + + receiver->rekey_timeout.abs_value_us = 0; + receiver->rekey_send_bytes = 0; + receiver->ss_rekey = NULL; + // destroy_all_secrets (ss, GNUNET_NO); + receiver->rekeying = GNUNET_YES; + receiver->rekey_acks_available = receiver->acks_available; + box->rekeying = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sender started rekeying.\n"); + if (GNUNET_YES == box->rekeying) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending rekeying with kid %s\n", + GNUNET_sh2s (&box->kid)); + } + } +} + +static void +send_UDPRekey (struct ReceiverAddress *receiver, struct SharedSecret *ss) +{ + uint8_t is_ss_rekey_sequence_allowed_zero = GNUNET_NO; + uint8_t is_acks_available_below = GNUNET_NO; + uint8_t send_rekey = GNUNET_NO; + uint16_t not_below; + struct GNUNET_CRYPTO_EcdhePrivateKey epriv; + struct UDPRekey *rekey; + size_t dpos; + + char rekey_dgram[sizeof(struct UDPRekey) + receiver->d_mtu]; + + if (NULL != receiver->ss_rekey) + { + not_below = (receiver->rekey_acks_available + - (receiver->rekey_acks_available % 3)) / 3; + is_ss_rekey_sequence_allowed_zero = (0 == + receiver->ss_rekey->sequence_allowed); + is_acks_available_below = (receiver->acks_available > not_below); + send_rekey = (0 == (receiver->acks_available - not_below) % not_below) && + is_acks_available_below && is_ss_rekey_sequence_allowed_zero; + } + else if (NULL == receiver->ss_rekey) + { + /* setup key material */ + GNUNET_CRYPTO_ecdhe_key_create (&epriv); + receiver->ss_rekey = setup_shared_secret_enc (&epriv, receiver, + GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setup secret with cmac %s\n", + GNUNET_h2s (&(receiver->ss_rekey->cmac))); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setup secret with master %s.\n", + GNUNET_h2s (&(receiver->ss_rekey->master))); + } + + if (send_rekey) + { + GNUNET_assert (0 != receiver->number_rekeying_kce); + gcry_cipher_hd_t rekey_out_cipher; + + while (NULL != ss && ss->sequence_used >= ss->sequence_allowed) + { + ss = ss->prev; + } + + if (NULL != ss) + { + rekey = (struct UDPRekey *) rekey_dgram; + rekey->sender = my_identity; + ss->sequence_used++; + get_kid (&ss->master, ss->sequence_used, &rekey->kid); + receiver->number_rekeying_kce--; + setup_cipher (&ss->master, ss->sequence_used, &rekey_out_cipher); + /* Append encrypted payload to dgram */ + dpos = sizeof(struct UDPRekey); + + GNUNET_assert ( + 0 == gcry_cipher_encrypt (rekey_out_cipher, &rekey_dgram[dpos], + sizeof(receiver->ss_rekey->master), + &(receiver->ss_rekey->master), + sizeof(receiver->ss_rekey->master))); + dpos += sizeof(receiver->ss_rekey->master); + /* GNUNET_assert ( */ + /* 0 == gcry_cipher_encrypt (rekey_out_cipher, &rekey_dgram[dpos], */ + /* /\*sizeof(receiver->ss_rekey->cmac), */ + /* &(receiver->ss_rekey->cmac), */ + /* sizeof(receiver->ss_rekey->cmac))); */ + /* dpos += sizeof(receiver->ss_rekey->cmac);*\/ */ + /* sizeof(receiver->ss_rekey), */ + /* receiver->ss_rekey, */ + /* sizeof(receiver->ss_rekey))); */ + /* dpos += sizeof(receiver->ss_rekey); */ + do_pad (rekey_out_cipher, &rekey_dgram[dpos], sizeof(rekey_dgram) + - dpos); + GNUNET_assert (0 == gcry_cipher_gettag (rekey_out_cipher, + rekey->gcm_tag, + sizeof(rekey->gcm_tag))); + gcry_cipher_close (rekey_out_cipher); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending rekey with kid %s and master %s\n", + GNUNET_sh2s (&rekey->kid), + GNUNET_h2s (&(receiver->ss_rekey->master))); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending rekey with cmac %s\n", + GNUNET_h2s (&(receiver->ss_rekey->cmac))); + + if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock, + rekey_dgram, + sizeof(rekey_dgram), + receiver->address, + receiver->address_len)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send"); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending UDPRekey to %s\n", GNUNET_a2s (receiver->address, + receiver-> + address_len)); + } + } +} + /** * Signature of functions implementing the sending functionality of a @@ -2228,15 +2732,14 @@ mq_send_d (struct GNUNET_MQ_Handle *mq, { struct ReceiverAddress *receiver = impl_state; uint16_t msize = ntohs (msg->size); - struct GNUNET_TIME_Relative rt; - struct SharedSecret *pos; GNUNET_assert (mq == receiver->d_mq); if ((msize > receiver->d_mtu) || (0 == receiver->acks_available)) { GNUNET_break (0); - receiver_destroy (receiver); + if (GNUNET_YES != receiver->receiver_destroy_called) + receiver_destroy (receiver); return; } reschedule_receiver_timeout (receiver); @@ -2278,6 +2781,16 @@ mq_send_d (struct GNUNET_MQ_Handle *mq, box->gcm_tag, sizeof(box->gcm_tag))); gcry_cipher_close (out_cipher); + + receiver->rekey_send_bytes += sizeof(struct UDPBox) + receiver->d_mtu; + + if (GNUNET_NO == receiver->rekeying) + box->rekeying = GNUNET_NO; + else + box->rekeying = GNUNET_YES; + + check_for_rekeying (receiver, box); + if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock, dgram, sizeof(dgram), @@ -2288,38 +2801,26 @@ mq_send_d (struct GNUNET_MQ_Handle *mq, "Sending UDPBox to %s\n", GNUNET_a2s (receiver->address, receiver->address_len)); GNUNET_MQ_impl_send_continue (mq); - // receiver->acks_available--; + receiver->acks_available--; if (0 == receiver->acks_available) { /* We have no more ACKs */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No more acks\n"); - } - - /* (NULL == rekey_timeout) - rekey_timeout = GNUNET_TIME_relative_to_absolute (REKEY_TIME_INTERVAL); - else - { - rt = GNUNET_TIME_absolute_get_remaining (rekey_timeout); - if (0 == rt.rel_value_us) + if (GNUNET_YES == receiver->rekeying) { - rekey_timeout = NULL; - pos = receiver->ss_head; - while ( NULL != pos) - { - ss_to_destroy = pos; - pos = pos->next; - secret_destroy (ss_to_destroy, GNUNET_NO); - } - if (0 != receiver->acks_available) - GNUNET_TRANSPORT_communicator_mq_update (ch, - receiver->d_qh, - // TODO We can not do this. But how can we signal this queue is not able to handle a message. Test code interprets q-len as additional length. - -receiver->acks_available, - 1); - } - }*/ + receiver->rekeying = GNUNET_NO; + if ((NULL != receiver->ss_rekey) && (0 < + receiver->ss_rekey-> + sequence_allowed) ) + add_acks_rekey (receiver); + } + } + else if ((GNUNET_YES == receiver->rekeying) ) + { + send_UDPRekey (receiver, ss); + } return; } @@ -2343,7 +2844,8 @@ mq_destroy_d (struct GNUNET_MQ_Handle *mq, void *impl_state) if (mq == receiver->d_mq) { receiver->d_mq = NULL; - receiver_destroy (receiver); + if (GNUNET_YES != receiver->receiver_destroy_called) + receiver_destroy (receiver); } } @@ -2365,7 +2867,8 @@ mq_destroy_kx (struct GNUNET_MQ_Handle *mq, void *impl_state) if (mq == receiver->kx_mq) { receiver->kx_mq = NULL; - receiver_destroy (receiver); + if (GNUNET_YES != receiver->receiver_destroy_called) + receiver_destroy (receiver); } } @@ -2997,6 +3500,13 @@ run (void *cls, return; } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, + COMMUNICATOR_CONFIG_SECTION, + "REKEY_INTERVAL", + &rekey_interval)) + rekey_interval = DEFAULT_REKEY_TIME_INTERVAL; + in = udp_address_to_sockaddr (bindto, &in_len); if (NULL == in) { diff --git a/src/transport/test_communicator_basic.c b/src/transport/test_communicator_basic.c index 8251a5169..df3c73b20 100644 --- a/src/transport/test_communicator_basic.c +++ b/src/transport/test_communicator_basic.c @@ -31,6 +31,7 @@ #include "gnunet_signatures.h" #include "gnunet_testing_lib.h" #include "transport.h" +#include "gnunet_statistics_service.h" #include @@ -54,6 +55,8 @@ GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_hs[NUM_PEERS]; static struct GNUNET_CONFIGURATION_Handle *cfg_peers[NUM_PEERS]; +static struct GNUNET_STATISTICS_Handle *stats[NUM_PEERS]; + static char *cfg_peers_name[NUM_PEERS]; static int ret; @@ -68,6 +71,8 @@ static struct GNUNET_TIME_Absolute timeout; static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *my_tc; +static char *test_name; + #define SHORT_MESSAGE_SIZE 128 #define LONG_MESSAGE_SIZE 32000 /* FIXME */ @@ -509,6 +514,16 @@ update_avg_latency (const char*payload) } +static int +process_statistics (void *cls, + const char *subsystem, + const char *name, + uint64_t value, + int is_persistent) +{ + return GNUNET_OK; +} + /** * @brief Handle an incoming message * @@ -645,6 +660,15 @@ incoming_message_cb (void *cls, short_test (NULL); break; } + /* if (("rekey" == test_name) || ("backchannel" == test_name)) */ + /* { */ + /* GNUNET_STATISTICS_get (stats[1], */ + /* "C-UDP", */ + /* "# bytes decrypted with Rekey", */ + /* NULL, */ + /* &process_statistics, */ + /* NULL); */ + /* } */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished\n"); GNUNET_SCHEDULER_shutdown (); @@ -695,6 +719,12 @@ run (void *cls) &incoming_message_cb, &handle_backchannel_cb, cfg_peers_name[i]); /* cls */ + + /* if (("rekey" == test_name) || ("backchannel" == test_name)) */ + /* { */ + /* stats[i] = GNUNET_STATISTICS_create ("C-UDP", */ + /* cfg_peers[i]); */ + /* } */ } GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); @@ -708,7 +738,6 @@ main (int argc, struct GNUNET_CRYPTO_EddsaPrivateKey *private_key; char *communicator_name; char *test_mode; - char *test_name; char *cfg_peer; phase = TP_INIT; diff --git a/src/transport/test_communicator_udp_rekey_peer1.conf b/src/transport/test_communicator_udp_rekey_peer1.conf index e7161e488..8fede6f8c 100644 --- a/src/transport/test_communicator_udp_rekey_peer1.conf +++ b/src/transport/test_communicator_udp_rekey_peer1.conf @@ -36,4 +36,12 @@ DISABLE_V6 = YES REKEY_INTERVAL = 100ms [communicator-udp] +#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args +#PREFIX = valgrind --leak-check=full --track-origins=yes BINDTO = 60002 +DISABLE_V6 = YES +MAX_QUEUE_LENGTH=5000 +REKEY_INTERVAL = 1s + +[communicator-test] +BACKCHANNEL_ENABLED = YES diff --git a/src/transport/test_communicator_udp_rekey_peer2.conf b/src/transport/test_communicator_udp_rekey_peer2.conf index 8f175a405..f545ba07a 100644 --- a/src/transport/test_communicator_udp_rekey_peer2.conf +++ b/src/transport/test_communicator_udp_rekey_peer2.conf @@ -36,4 +36,12 @@ DISABLE_V6 = YES REKEY_INTERVAL = 100ms [communicator-udp] +#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args +#PREFIX = valgrind --leak-check=full --track-origins=yes BINDTO = 60003 +DISABLE_V6 = YES +MAX_QUEUE_LENGTH=5000 +REKEY_INTERVAL = 1s + +[communicator-test] +BACKCHANNEL_ENABLED = YES -- cgit v1.2.3