struct GNUNET_TIME_AbsoluteNBO expiration_time;
/**
- * Ephemeral public ECC key (always for NIST P-521) encoded in a format suitable
- * for network transmission as created using 'gcry_sexp_sprint'.
+ * Ephemeral public ECC key.
*/
struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
*/
struct PingMessage ping;
+ /**
+ * Ephemeral public ECC key of the other peer.
+ */
+ struct GNUNET_CRYPTO_EcdhePublicKey other_ephemeral_key;
+
/**
* Key we use to encrypt our messages for the other peer
* (initialized by us when we do the handshake).
* @param iv initialization vector to use
* @param in ciphertext
* @param out plaintext
- * @param size size of in/out
- * @return GNUNET_OK on success
+ * @param size size of @a in / @a out
+ * @return #GNUNET_OK on success
*/
static int
do_decrypt (struct GSC_KeyExchangeInfo *kx,
GNUNET_STATISTICS_update (GSC_stats,
gettext_noop ("# key exchanges initiated"), 1,
GNUNET_NO);
- kx = GNUNET_malloc (sizeof (struct GSC_KeyExchangeInfo));
+ kx = GNUNET_new (struct GSC_KeyExchangeInfo);
kx->peer = *pid;
kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
GNUNET_CONTAINER_DLL_insert (kx_head,
GNUNET_CRYPTO_hash (pid, sizeof (struct GNUNET_PeerIdentity), &h1);
GNUNET_CRYPTO_hash (&GSC_my_identity, sizeof (struct GNUNET_PeerIdentity), &h2);
+ kx->status = KX_STATE_KEY_SENT;
if (0 < GNUNET_CRYPTO_hash_cmp (&h1,
&h2))
{
/* 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);
}
+ else
+ {
+ /* peer with "higher" identity starts a delayed KX, if the "lower" peer
+ * does not start a KX since he sees no reasons to do so */
+ kx->retry_set_key_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &set_key_retry_task, kx);
+ }
return kx;
}
MIN_PING_FREQUENCY);
}
+
+/**
+ * Derive fresh session keys from the current ephemeral keys.
+ *
+ * @param kx session to derive keys for
+ */
+static void
+derive_session_keys (struct GSC_KeyExchangeInfo *kx)
+{
+ struct GNUNET_HashCode key_material;
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_ecc_ecdh (my_ephemeral_key,
+ &kx->other_ephemeral_key,
+ &key_material))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ derive_aes_key (&GSC_my_identity,
+ &kx->peer,
+ &key_material,
+ &kx->encrypt_key);
+ derive_aes_key (&kx->peer,
+ &GSC_my_identity,
+ &key_material,
+ &kx->decrypt_key);
+ memset (&key_material, 0, sizeof (key_material));
+ /* fresh key, reset sequence numbers */
+ kx->last_sequence_number_received = 0;
+ kx->last_packets_bitmap = 0;
+ setup_fresh_ping (kx);
+}
+
+
/**
* We received a SET_KEY message. Validate and update
* our key material and status.
struct GNUNET_TIME_Absolute now;
enum KxStateMachine sender_status;
uint16_t size;
- struct GNUNET_HashCode key_material;
size = ntohs (msg->size);
if (sizeof (struct EphemeralKeyMessage) != size)
end_t.abs_value_us);
return;
}
- if (GNUNET_OK !=
- GNUNET_CRYPTO_ecc_ecdh (my_ephemeral_key,
- &m->ephemeral_key,
- &key_material))
- {
- GNUNET_break (0);
- return;
- }
+ kx->other_ephemeral_key = m->ephemeral_key;
+ kx->foreign_key_expires = end_t;
+ derive_session_keys (kx);
GNUNET_STATISTICS_update (GSC_stats,
- gettext_noop ("# EPHEMERAL_KEY messages decrypted"), 1,
+ gettext_noop ("# EPHEMERAL_KEY messages received"), 1,
GNUNET_NO);
- derive_aes_key (&GSC_my_identity,
- &kx->peer,
- &key_material,
- &kx->encrypt_key);
- derive_aes_key (&kx->peer,
- &GSC_my_identity,
- &key_material,
- &kx->decrypt_key);
- /* fresh key, reset sequence numbers */
- kx->last_sequence_number_received = 0;
- kx->last_packets_bitmap = 0;
- kx->foreign_key_expires = end_t;
- setup_fresh_ping (kx);
/* check if we still need to send the sender our key */
sender_status = (enum KxStateMachine) ntohl (m->sender_status);
/**
- * Closure for 'deliver_message'
+ * Closure for #deliver_message()
*/
struct DeliverMessageContext
{
return;
}
m = (const struct EncryptedMessage *) msg;
- if (kx->status != KX_STATE_UP)
+ if (KX_STATE_UP != kx->status)
{
GNUNET_STATISTICS_update (GSC_stats,
gettext_noop
do_decrypt (kx, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE],
size - ENCRYPTED_HEADER_SIZE))
return;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypted %u bytes from %s\n",
- size - ENCRYPTED_HEADER_SIZE, GNUNET_i2s (&kx->peer));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Decrypted %u bytes from %s\n",
+ size - ENCRYPTED_HEADER_SIZE,
+ GNUNET_i2s (&kx->peer));
pt = (struct EncryptedMessage *) buf;
/* validate sequence number */
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Message received far too old (%s). Content ignored.\n",
- GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (t), GNUNET_YES));
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (t),
+ GNUNET_YES));
GNUNET_STATISTICS_update (GSC_stats,
gettext_noop
("# bytes dropped (ancient message)"), size,
update_timeout (kx);
GNUNET_STATISTICS_update (GSC_stats,
gettext_noop ("# bytes of payload decrypted"),
- size - sizeof (struct EncryptedMessage), GNUNET_NO);
+ size - sizeof (struct EncryptedMessage),
+ GNUNET_NO);
dmc.kx = kx;
dmc.peer = &kx->peer;
if (GNUNET_OK !=
GNUNET_SERVER_mst_receive (mst, &dmc,
&buf[sizeof (struct EncryptedMessage)],
size - sizeof (struct EncryptedMessage),
- GNUNET_YES, GNUNET_NO))
+ GNUNET_YES,
+ GNUNET_NO))
GNUNET_break_op (0);
}
* @param m the message
*/
static int
-deliver_message (void *cls, void *client, const struct GNUNET_MessageHeader *m)
+deliver_message (void *cls,
+ void *client,
+ const struct GNUNET_MessageHeader *m)
{
struct DeliverMessageContext *dmc = client;
current_ekm.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
sizeof (struct GNUNET_TIME_AbsoluteNBO) +
sizeof (struct GNUNET_TIME_AbsoluteNBO) +
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
+ sizeof (struct GNUNET_PeerIdentity));
current_ekm.creation_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
if (GNUNET_YES ==
GNUNET_CONFIGURATION_get_value_yesno (GSC_cfg,
sign_ephemeral_key ();
for (pos = kx_head; NULL != pos; pos = pos->next)
{
- pos->status = KX_STATE_REKEY_SENT;
+ if (KX_STATE_UP == pos->status)
+ {
+ pos->status = KX_STATE_REKEY_SENT;
+ derive_session_keys (pos);
+ }
+ if (KX_STATE_DOWN == pos->status)
+ {
+ pos->status = KX_STATE_KEY_SENT;
+ }
send_key (pos);
}
}
int
GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
{
- GNUNET_assert (NULL != pk);
my_private_key = pk;
GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
&GSC_my_identity.public_key);