/*
This file is part of GNUnet.
- (C) 2009, 2010, 2011, 2012 Christian Grothoff (and other contributing authors)
+ (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
* Ephemeral public ECC key (always for NIST P-521) encoded in a format suitable
* for network transmission as created using 'gcry_sexp_sprint'.
*/
- struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded ephemeral_key;
+ struct GNUNET_CRYPTO_EccPublicKey ephemeral_key;
/**
* Public key of the signing peer (persistent version, not the ephemeral public key).
*/
- struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded origin_public_key;
+ struct GNUNET_CRYPTO_EccPublicKey origin_public_key;
};
KX_STATE_UP,
/**
- * We're rekeying, so we have sent the other peer our new ephemeral
- * key, but we did not get a matching PONG yet.
+ * We're rekeying (or had a timeout), so we have sent the other peer
+ * our new ephemeral key, but we did not get a matching PONG yet.
+ * This is equivalent to being 'KX_STATE_KEY_RECEIVED', except that
+ * the session is marked as 'up' with sessions (as we don't want to
+ * drop and re-establish P2P connections simply due to rekeying).
*/
KX_STATE_REKEY_SENT
/**
* Our public key.
*/
-static struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded my_public_key;
+static struct GNUNET_CRYPTO_EccPublicKey my_public_key;
/**
* Our message stream tokenizer (for encrypted payload).
GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_AesSessionKey),
ctx, sizeof (ctx),
- skey, sizeof (struct GNUNET_CRYPTO_AesSessionKey),
+ key_material, sizeof (struct GNUNET_HashCode),
sender, sizeof (struct GNUNET_PeerIdentity),
receiver, sizeof (struct GNUNET_PeerIdentity),
NULL);
kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
kx->set_key_retry_frequency = GNUNET_TIME_STD_BACKOFF (kx->set_key_retry_frequency);
+ GNUNET_assert (KX_STATE_DOWN != kx->status);
send_key (kx);
}
GNUNET_CONTAINER_DLL_insert (kx_head,
kx_tail,
kx);
- kx->status = KX_STATE_KEY_SENT;
- send_key (kx);
+ if (0 < GNUNET_CRYPTO_hash_cmp (&pid->hashPubKey,
+ &GSC_my_identity.hashPubKey))
+ {
+ /* peer with "lower" identity starts KX, otherwise we typically end up
+ with both peers starting the exchange and transmit the 'set key'
+ message twice */
+ kx->status = KX_STATE_KEY_SENT;
+ send_key (kx);
+ }
return kx;
}
void
GSC_KX_stop (struct GSC_KeyExchangeInfo *kx)
{
+ 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)
return;
}
m = (const struct EphemeralKeyMessage *) msg;
+ end_t = GNUNET_TIME_absolute_ntoh (m->expiration_time);
+ if ( ( (KX_STATE_KEY_RECEIVED == kx->status) ||
+ (KX_STATE_UP == kx->status) ||
+ (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"),
+ 1, GNUNET_NO);
+ return;
+ }
+ start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
+
GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# ephemeral keys received"),
1, GNUNET_NO);
"Core service receives `%s' request from `%4s'.\n", "EPHEMERAL_KEY",
GNUNET_i2s (&kx->peer));
GNUNET_CRYPTO_hash (&m->origin_public_key,
- sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
+ sizeof (struct GNUNET_CRYPTO_EccPublicKey),
&signer_id.hashPubKey);
if (0 !=
memcmp (&signer_id, &kx->peer,
sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
sizeof (struct GNUNET_TIME_AbsoluteNBO) +
sizeof (struct GNUNET_TIME_AbsoluteNBO) +
- sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded) +
- sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) ||
+ sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
+ sizeof (struct GNUNET_CRYPTO_EccPublicKey)) ||
(GNUNET_OK !=
GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY,
&m->purpose,
GNUNET_break_op (0);
return;
}
- start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
- end_t = GNUNET_TIME_absolute_ntoh (m->expiration_time);
now = GNUNET_TIME_absolute_get ();
- if ( (end_t.abs_value < GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value) ||
- (start_t.abs_value > GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value) )
+ if ( (end_t.abs_value_us < GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value_us) ||
+ (start_t.abs_value_us > GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value_us) )
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Ephemeral key message rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"),
- now.abs_value,
- start_t.abs_value,
- end_t.abs_value);
+ _("Ephemeral key message from peer `%s' rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"),
+ GNUNET_i2s (&kx->peer),
+ now.abs_value_us,
+ start_t.abs_value_us,
+ end_t.abs_value_us);
return;
}
if (GNUNET_OK !=
switch (sender_status)
{
case KX_STATE_DOWN:
- /* makes no sense, should be at least KX_STATE_KEY_SENT */
GNUNET_break_op (0);
break;
case KX_STATE_KEY_SENT:
- send_key (kx);
+ /* fine, need to send our key after updating our status, see below */
break;
case KX_STATE_KEY_RECEIVED:
case KX_STATE_UP:
switch (kx->status)
{
case KX_STATE_DOWN:
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->keep_alive_task);
kx->status = KX_STATE_KEY_RECEIVED;
+ if (KX_STATE_KEY_SENT == sender_status)
+ send_key (kx);
send_ping (kx);
break;
case KX_STATE_KEY_SENT:
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->keep_alive_task);
kx->status = KX_STATE_KEY_RECEIVED;
+ if (KX_STATE_KEY_SENT == sender_status)
+ send_key (kx);
send_ping (kx);
break;
case KX_STATE_KEY_RECEIVED:
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->keep_alive_task);
+ if (KX_STATE_KEY_SENT == sender_status)
+ send_key (kx);
send_ping (kx);
break;
case KX_STATE_UP:
- kx->status = KX_STATE_KEY_RECEIVED;
+ kx->status = KX_STATE_REKEY_SENT;
+ if (KX_STATE_KEY_SENT == sender_status)
+ send_key (kx);
/* we got a new key, need to reconfirm! */
send_ping (kx);
break;
case KX_STATE_REKEY_SENT:
- kx->status = KX_STATE_KEY_RECEIVED;
+ if (KX_STATE_KEY_SENT == sender_status)
+ send_key (kx);
/* we got a new key, need to reconfirm! */
send_ping (kx);
break;
kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
left = GNUNET_TIME_absolute_get_remaining (kx->timeout);
- if (0 == left.rel_value)
+ if (0 == left.rel_value_us)
{
GNUNET_STATISTICS_update (GSC_stats,
gettext_noop ("# sessions terminated by timeout"),
static void
send_key (struct GSC_KeyExchangeInfo *kx)
{
+ GNUNET_assert (KX_STATE_DOWN != kx->status);
if (GNUNET_SCHEDULER_NO_TASK != kx->retry_set_key_task)
{
GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
{
/**
- * Performance information for the connection.
+ * Key exchange context.
*/
- const struct GNUNET_ATS_Information *atsi;
+ struct GSC_KeyExchangeInfo *kx;
/**
* Sender of the message.
*/
const struct GNUNET_PeerIdentity *peer;
-
- /**
- * Number of entries in 'atsi' array.
- */
- uint32_t atsi_count;
};
*
* @param kx key exchange context for encrypting the message
* @param msg encrypted message
- * @param atsi performance data
- * @param atsi_count number of entries in ats (excluding 0-termination)
*/
void
GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *kx,
- const struct GNUNET_MessageHeader *msg,
- const struct GNUNET_ATS_Information *atsi,
- uint32_t atsi_count)
+ const struct GNUNET_MessageHeader *msg)
{
const struct EncryptedMessage *m;
struct EncryptedMessage *pt; /* plaintext */
1, GNUNET_NO);
return;
}
- if (0 == GNUNET_TIME_absolute_get_remaining (kx->foreign_key_expires).rel_value)
+ if (0 == GNUNET_TIME_absolute_get_remaining (kx->foreign_key_expires).rel_value_us)
{
- kx->status = KX_STATE_KEY_SENT;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Session to peer `%s' went down due to key expiration (should not happen)\n"),
+ GNUNET_i2s (&kx->peer));
GNUNET_STATISTICS_update (GSC_stats,
- gettext_noop
- ("# DATA message dropped (session key expired)"),
+ gettext_noop ("# sessions terminated by key expiration"),
1, GNUNET_NO);
+ GSC_SESSIONS_end (&kx->peer);
+ if (GNUNET_SCHEDULER_NO_TASK != kx->keep_alive_task)
+ {
+ GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
+ kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ kx->status = KX_STATE_KEY_SENT;
send_key (kx);
return;
}
/* check timestamp */
t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
- if (GNUNET_TIME_absolute_get_duration (t).rel_value >
- MAX_MESSAGE_AGE.rel_value)
+ if (GNUNET_TIME_absolute_get_duration (t).rel_value_us >
+ MAX_MESSAGE_AGE.rel_value_us)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Message received far too old (%s). Content ignored.\n",
GNUNET_STATISTICS_update (GSC_stats,
gettext_noop ("# bytes of payload decrypted"),
size - sizeof (struct EncryptedMessage), GNUNET_NO);
- dmc.atsi = atsi;
- dmc.atsi_count = atsi_count;
+ dmc.kx = kx;
dmc.peer = &kx->peer;
if (GNUNET_OK !=
GNUNET_SERVER_mst_receive (mst, &dmc,
{
struct DeliverMessageContext *dmc = client;
+ if (KX_STATE_UP != dmc->kx->status)
+ {
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop
+ ("# PAYLOAD dropped (out of order)"),
+ 1, GNUNET_NO);
+ return GNUNET_OK;
+ }
switch (ntohs (m->type))
{
case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
GSC_SESSIONS_set_typemap (dmc->peer, m);
return GNUNET_OK;
default:
- GSC_CLIENTS_deliver_message (dmc->peer, dmc->atsi, dmc->atsi_count, m,
+ GSC_CLIENTS_deliver_message (dmc->peer, m,
ntohs (m->size),
GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
- GSC_CLIENTS_deliver_message (dmc->peer, dmc->atsi, dmc->atsi_count, m,
+ GSC_CLIENTS_deliver_message (dmc->peer, m,
sizeof (struct GNUNET_MessageHeader),
GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
}
current_ekm.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
sizeof (struct GNUNET_TIME_AbsoluteNBO) +
sizeof (struct GNUNET_TIME_AbsoluteNBO) +
- sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded) +
- sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
+ sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
+ sizeof (struct GNUNET_CRYPTO_EccPublicKey));
current_ekm.creation_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
- current_ekm.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_add (REKEY_FREQUENCY,
- REKEY_TOLERANCE)));
+ if (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_yesno (GSC_cfg,
+ "core",
+ "USE_EPHEMERAL_KEYS"))
+ {
+ current_ekm.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_add (REKEY_FREQUENCY,
+ REKEY_TOLERANCE)));
+ }
+ else
+ {
+ current_ekm.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
+ }
GNUNET_CRYPTO_ecc_key_get_public (my_ephemeral_key,
¤t_ekm.ephemeral_key);
current_ekm.origin_public_key = my_public_key;
&do_rekey,
NULL);
if (NULL != my_ephemeral_key)
- GNUNET_CRYPTO_ecc_key_free (my_ephemeral_key);
+ GNUNET_free (my_ephemeral_key);
my_ephemeral_key = GNUNET_CRYPTO_ecc_key_create ();
GNUNET_assert (NULL != my_ephemeral_key);
sign_ephemeral_key ();
GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key);
GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
&GSC_my_identity.hashPubKey);
- my_ephemeral_key = GNUNET_CRYPTO_ecc_key_create ();
- if (NULL == my_ephemeral_key)
+ if (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_yesno (GSC_cfg,
+ "core",
+ "USE_EPHEMERAL_KEYS"))
{
- GNUNET_break (0);
- GNUNET_CRYPTO_ecc_key_free (my_private_key);
- my_private_key = NULL;
- return GNUNET_SYSERR;
+ my_ephemeral_key = GNUNET_CRYPTO_ecc_key_create ();
+ if (NULL == my_ephemeral_key)
+ {
+ GNUNET_break (0);
+ GNUNET_free (my_private_key);
+ my_private_key = NULL;
+ return GNUNET_SYSERR;
+ }
+ sign_ephemeral_key ();
+ rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
+ &do_rekey,
+ NULL);
+ }
+ else
+ {
+ my_ephemeral_key = my_private_key;
+ sign_ephemeral_key ();
}
- sign_ephemeral_key ();
mst = GNUNET_SERVER_mst_create (&deliver_message, NULL);
- rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
- &do_rekey,
- NULL);
return GNUNET_OK;
}
GNUNET_SCHEDULER_cancel (rekey_task);
rekey_task = GNUNET_SCHEDULER_NO_TASK;
}
- if (NULL != my_private_key)
+ if ( (NULL != my_ephemeral_key) &&
+ (my_ephemeral_key != my_private_key) )
{
- GNUNET_CRYPTO_ecc_key_free (my_private_key);
- my_private_key = NULL;
+ GNUNET_free (my_ephemeral_key);
+ my_ephemeral_key = NULL;
}
- if (NULL != my_ephemeral_key)
+ if (NULL != my_private_key)
{
- GNUNET_CRYPTO_ecc_key_free (my_ephemeral_key);
- my_ephemeral_key = NULL;
+ GNUNET_free (my_private_key);
+ my_private_key = NULL;
}
if (NULL != mst)
{