/*
This file is part of GNUnet.
- (C) 2009-2013 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2009-2013 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
struct GNUNET_MessageHeader header;
/**
- * Status of the sender (should be in "enum PeerStateMachine"), nbo.
+ * Status of the sender (should be in `enum PeerStateMachine`), nbo.
*/
int32_t sender_status GNUNET_PACKED;
/**
- * An ECC signature of the 'origin' asserting the validity of
+ * An ECC signature of the @e origin_identity asserting the validity of
* the given ephemeral key.
*/
struct GNUNET_CRYPTO_EddsaSignature signature;
/**
- * Number of bytes (at the beginning) of "struct EncryptedMessage"
+ * Number of bytes (at the beginning) of `struct EncryptedMessage`
* that are NOT encrypted.
*/
#define ENCRYPTED_HEADER_SIZE (offsetof(struct EncryptedMessage, sequence_number))
*/
struct GNUNET_TIME_Absolute timeout;
+ /**
+ * What was the last timeout we informed our monitors about?
+ */
+ struct GNUNET_TIME_Absolute last_notify_timeout;
+
/**
* At what frequency are we currently re-trying SET_KEY messages?
*/
/**
* ID of task used for re-trying SET_KEY and PING message.
*/
- GNUNET_SCHEDULER_TaskIdentifier retry_set_key_task;
+ struct GNUNET_SCHEDULER_Task * retry_set_key_task;
/**
* ID of task used for sending keep-alive pings.
*/
- GNUNET_SCHEDULER_TaskIdentifier keep_alive_task;
+ struct GNUNET_SCHEDULER_Task * keep_alive_task;
/**
* Bit map indicating which of the 32 sequence numbers before the last
* Task scheduled for periodic re-generation (and thus rekeying) of our
* ephemeral key.
*/
-static GNUNET_SCHEDULER_TaskIdentifier rekey_task;
+static struct GNUNET_SCHEDULER_Task * rekey_task;
/**
* Notification context for all monitors.
* Inform the given monitor about the KX state of
* the given peer.
*
- * @param mc monitor to inform
+ * @param client client to inform
* @param kx key exchange state to inform about
*/
static void
}
+/**
+ * Calculate seed value we should use for a message.
+ *
+ * @param kx key exchange context
+ */
+static uint32_t
+calculate_seed (struct GSC_KeyExchangeInfo *kx)
+{
+ /* Note: may want to make this non-random and instead
+ derive from key material to avoid having an undetectable
+ side-channel */
+ return htonl (GNUNET_CRYPTO_random_u32
+ (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
+}
+
+
/**
* Inform all monitors about the KX state of the given peer.
*
GNUNET_SERVER_notification_context_broadcast (nc,
&msg.header,
GNUNET_NO);
+ kx->last_notify_timeout = kx->timeout;
}
*/
static void
derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
- const struct GNUNET_CRYPTO_SymmetricSessionKey *skey, uint32_t seed)
+ const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
+ uint32_t seed)
{
static const char ctx[] = "authentication key";
{
struct GSC_KeyExchangeInfo *kx = cls;
- kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
+ kx->retry_set_key_task = NULL;
kx->set_key_retry_frequency = GNUNET_TIME_STD_BACKOFF (kx->set_key_retry_frequency);
GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
send_key (kx);
pm = &kx->ping;
pm->header.size = htons (sizeof (struct PingMessage));
pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
- pm->iv_seed =
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ pm->iv_seed = calculate_seed (kx);
derive_iv (&iv, &kx->encrypt_key, pm->iv_seed, &kx->peer);
pp.challenge = kx->ping_challenge;
pp.target = kx->peer;
GSC_SESSIONS_end (&kx->peer);
GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# key exchanges stopped"),
1, GNUNET_NO);
- if (kx->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
+ if (kx->retry_set_key_task != NULL)
{
GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
- kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
+ kx->retry_set_key_task = NULL;
}
- if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
+ if (kx->keep_alive_task != NULL)
{
GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
- kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
+ kx->keep_alive_task = NULL;
}
kx->status = GNUNET_CORE_KX_PEER_DISCONNECT;
monitor_notify_all (kx);
static void
send_ping (struct GSC_KeyExchangeInfo *kx)
{
- GSC_NEIGHBOURS_transmit (&kx->peer, &kx->ping.header,
+ GSC_NEIGHBOURS_transmit (&kx->peer,
+ &kx->ping.header,
MIN_PING_FREQUENCY);
}
(GNUNET_CORE_KX_STATE_REKEY_SENT == kx->status) ) &&
(end_t.abs_value_us <= kx->foreign_key_expires.abs_value_us) )
{
- GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# old ephemeral keys ignored"),
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop ("# old ephemeral keys ignored"),
1, GNUNET_NO);
return;
}
start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
- GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# ephemeral keys received"),
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop ("# ephemeral keys received"),
1, GNUNET_NO);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
break;
case GNUNET_CORE_KX_STATE_KEY_SENT:
/* fine, need to send our key after updating our status, see below */
+ GSC_SESSIONS_reinit (&kx->peer);
break;
case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
+ /* other peer already got our key, but typemap did go down */
+ GSC_SESSIONS_reinit (&kx->peer);
+ break;
case GNUNET_CORE_KX_STATE_UP:
+ /* other peer already got our key, typemap NOT down */
+ break;
case GNUNET_CORE_KX_STATE_REKEY_SENT:
- /* other peer already got our key */
+ /* other peer already got our key, typemap NOT down */
break;
default:
GNUNET_break (0);
switch (kx->status)
{
case GNUNET_CORE_KX_STATE_DOWN:
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->keep_alive_task);
+ GNUNET_assert (NULL == kx->keep_alive_task);
kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
monitor_notify_all (kx);
if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
send_ping (kx);
break;
case GNUNET_CORE_KX_STATE_KEY_SENT:
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->keep_alive_task);
+ GNUNET_assert (NULL == kx->keep_alive_task);
kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
monitor_notify_all (kx);
if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
send_ping (kx);
break;
case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->keep_alive_task);
+ GNUNET_assert (NULL == kx->keep_alive_task);
if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
send_key (kx);
send_ping (kx);
tx.target = t.target;
tp.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG);
tp.header.size = htons (sizeof (struct PongMessage));
- tp.iv_seed =
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ tp.iv_seed = calculate_seed (kx);
derive_pong_iv (&iv, &kx->encrypt_key, tp.iv_seed, t.challenge, &kx->peer);
do_encrypt (kx, &iv, &tx.challenge, &tp.challenge,
sizeof (struct PongMessage) - ((void *) &tp.challenge -
(void *) &tp));
GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# PONG messages created"),
1, GNUNET_NO);
- GSC_NEIGHBOURS_transmit (&kx->peer, &tp.header,
+ GSC_NEIGHBOURS_transmit (&kx->peer,
+ &tp.header,
GNUNET_TIME_UNIT_FOREVER_REL /* FIXME: timeout */ );
}
struct GNUNET_TIME_Relative retry;
struct GNUNET_TIME_Relative left;
- kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
+ kx->keep_alive_task = NULL;
left = GNUNET_TIME_absolute_get_remaining (kx->timeout);
if (0 == left.rel_value_us)
{
gettext_noop ("# keepalive messages sent"), 1,
GNUNET_NO);
setup_fresh_ping (kx);
- GSC_NEIGHBOURS_transmit (&kx->peer, &kx->ping.header,
+ GSC_NEIGHBOURS_transmit (&kx->peer,
+ &kx->ping.header,
kx->set_key_retry_frequency);
retry =
GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
static void
update_timeout (struct GSC_KeyExchangeInfo *kx)
{
+ struct GNUNET_TIME_Relative delta;
+
kx->timeout =
GNUNET_TIME_relative_to_absolute
(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
- monitor_notify_all (kx);
- if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
+ delta = GNUNET_TIME_absolute_get_difference (kx->last_notify_timeout,
+ kx->timeout);
+ if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
+ {
+ /* we only notify monitors about timeout changes if those
+ are bigger than the threshold (5s) */
+ monitor_notify_all (kx);
+ }
+ if (kx->keep_alive_task != NULL)
GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
kx->keep_alive_task =
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
"PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge);
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received PONG from `%s'\n",
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received PONG from `%s'\n",
GNUNET_i2s (&kx->peer));
/* no need to resend key any longer */
- if (GNUNET_SCHEDULER_NO_TASK != kx->retry_set_key_task)
+ if (NULL != kx->retry_set_key_task)
{
GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
- kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
+ kx->retry_set_key_task = NULL;
}
switch (kx->status)
{
kx->status = GNUNET_CORE_KX_STATE_UP;
monitor_notify_all (kx);
GSC_SESSIONS_create (&kx->peer, kx);
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->keep_alive_task);
+ GNUNET_assert (NULL == kx->keep_alive_task);
update_timeout (kx);
break;
case GNUNET_CORE_KX_STATE_UP:
send_key (struct GSC_KeyExchangeInfo *kx)
{
GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
- if (GNUNET_SCHEDULER_NO_TASK != kx->retry_set_key_task)
+ if (NULL != kx->retry_set_key_task)
{
GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
- kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
+ kx->retry_set_key_task = NULL;
}
/* always update sender status in SET KEY message */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
GNUNET_i2s (&kx->peer),
kx->status);
current_ekm.sender_status = htonl ((int32_t) (kx->status));
- GSC_NEIGHBOURS_transmit (&kx->peer, ¤t_ekm.header,
+ GSC_NEIGHBOURS_transmit (&kx->peer,
+ ¤t_ekm.header,
kx->set_key_retry_frequency);
kx->retry_set_key_task =
GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency,
*
* @param kx key exchange context
* @param payload payload of the message
- * @param payload_size number of bytes in 'payload'
+ * @param payload_size number of bytes in @a payload
*/
void
GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
- const void *payload, size_t payload_size)
+ const void *payload,
+ size_t payload_size)
{
size_t used = payload_size + sizeof (struct EncryptedMessage);
char pbuf[used]; /* plaintext */
struct GNUNET_CRYPTO_AuthKey auth_key;
ph = (struct EncryptedMessage *) pbuf;
- ph->iv_seed =
- htonl (GNUNET_CRYPTO_random_u32
- (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
ph->sequence_number = htonl (++kx->last_sequence_number_sent);
+ ph->iv_seed = calculate_seed (kx);
ph->reserved = 0;
ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
memcpy (&ph[1], payload, payload_size);
ph->iv_seed);
GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number,
used - ENCRYPTED_HEADER_SIZE, &em->hmac);
- GSC_NEIGHBOURS_transmit (&kx->peer, &em->header,
+ GSC_NEIGHBOURS_transmit (&kx->peer,
+ &em->header,
GNUNET_TIME_UNIT_FOREVER_REL);
}
gettext_noop ("# sessions terminated by key expiration"),
1, GNUNET_NO);
GSC_SESSIONS_end (&kx->peer);
- if (GNUNET_SCHEDULER_NO_TASK != kx->keep_alive_task)
+ if (NULL != kx->keep_alive_task)
{
GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
- kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
+ kx->keep_alive_task = NULL;
}
kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
monitor_notify_all (kx);
case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
GSC_SESSIONS_set_typemap (dmc->peer, m);
return GNUNET_OK;
+ case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
+ GSC_SESSIONS_confirm_typemap (dmc->peer, m);
+ return GNUNET_OK;
default:
GSC_CLIENTS_deliver_message (dmc->peer, m,
ntohs (m->size),
void
GSC_KX_done ()
{
- if (GNUNET_SCHEDULER_NO_TASK != rekey_task)
+ if (NULL != rekey_task)
{
GNUNET_SCHEDULER_cancel (rekey_task);
- rekey_task = GNUNET_SCHEDULER_NO_TASK;
+ rekey_task = NULL;
}
if (NULL != my_ephemeral_key)
{