From: Christian Grothoff Date: Sat, 28 Jan 2017 18:12:02 +0000 (+0100) Subject: KEY_REKEY state was dead in old code, remove in new code; refactor KX logic in prepar... X-Git-Tag: taler-0.2.1~266 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=7b2e8cd1090059768603444aff364317f955874d;p=oweals%2Fgnunet.git KEY_REKEY state was dead in old code, remove in new code; refactor KX logic in preparation for KX_AUTH --- diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet-new_tunnels.c index ea8559eb4..4d4cdc2dc 100644 --- a/src/cadet/gnunet-service-cadet-new_tunnels.c +++ b/src/cadet/gnunet-service-cadet-new_tunnels.c @@ -468,8 +468,6 @@ estate2s (enum CadetTunnelEState es) return "CADET_TUNNEL_KEY_PING"; case CADET_TUNNEL_KEY_OK: return "CADET_TUNNEL_KEY_OK"; - case CADET_TUNNEL_KEY_REKEY: - return "CADET_TUNNEL_KEY_REKEY"; default: SPRINTF (buf, "%u (UNKNOWN STATE)", es); return buf; @@ -1034,7 +1032,7 @@ store_skipped_key (struct CadetTunnelAxolotl *ax, * @param HKr Header key. * @param Np Received meesage number. * @return #GNUNET_OK if keys were stored. - * #GNUNET_SYSERR if an error ocurred (Np not expected). + * #GNUNET_SYSERR if an error ocurred (@a Np not expected). */ static int store_ax_keys (struct CadetTunnelAxolotl *ax, @@ -1050,7 +1048,7 @@ store_ax_keys (struct CadetTunnelAxolotl *ax, Np); if (MAX_KEY_GAP < gap) { - /* Avoid DoS (forcing peer to do 2^33 chain HMAC operations) */ + /* Avoid DoS (forcing peer to do more than #MAX_KEY_GAP HMAC operations) */ /* TODO: start new key exchange on return */ GNUNET_break_op (0); LOG (GNUNET_ERROR_TYPE_WARNING, @@ -1242,15 +1240,10 @@ GCT_change_estate (struct CadetTunnel *t, GNUNET_SCHEDULER_cancel (t->kx_task); t->kx_task = NULL; } - if (CADET_TUNNEL_KEY_REKEY != old) - { - /* notify all channels that have been waiting */ - GNUNET_CONTAINER_multihashmap32_iterate (t->channels, - ¬ify_tunnel_up_cb, - t); - } - - /* FIXME: schedule rekey task! */ + /* notify all channels that have been waiting */ + GNUNET_CONTAINER_multihashmap32_iterate (t->channels, + ¬ify_tunnel_up_cb, + t); } } @@ -1330,49 +1323,29 @@ cleanup_ax (struct CadetTunnelAxolotl *ax) /** - * Handle KX message that lacks authentication (and which will thus - * only be considered authenticated after we respond with our own - * KX_AUTH and finally successfully decrypt payload). + * Update our Axolotl key state based on the KX data we received. + * Computes the new chain keys, and root keys, etc, and also checks + * wether this is a replay of the current chain. * - * @param ct connection/tunnel combo that received encrypted message - * @param msg the key exchange message + * @param[in|out] axolotl chain key state to recompute + * @param pid peer identity of the other peer + * @param ephemeral_key ephemeral public key of the other peer + * @param ratchet_key senders next ephemeral public key + * @return #GNUNET_OK on success, #GNUNET_NO if the resulting + * root key is already in @a ax and thus the KX is useless; + * #GNUNET_SYSERR on hard errors (i.e. @a pid is #my_full_id) */ -void -GCT_handle_kx (struct CadetTConnection *ct, - const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) +static int +update_ax_by_kx (struct CadetTunnelAxolotl *ax, + const struct GNUNET_PeerIdentity *pid, + const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key, + const struct GNUNET_CRYPTO_EcdhePublicKey *ratchet_key) { - struct CadetTunnel *t = ct->t; - struct CadetTunnelAxolotl *ax; struct GNUNET_HashCode key_material[3]; struct GNUNET_CRYPTO_SymmetricSessionKey keys[5]; const char salt[] = "CADET Axolotl salt"; - const struct GNUNET_PeerIdentity *pid; int am_I_alice; - /* We only keep ONE unverified KX around, so if there is an existing one, - clean it up. */ - if (NULL != t->unverified_ax) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Dropping old unverified KX state, got a fresh one.\n", - t->unverified_attempts); - cleanup_ax (t->unverified_ax); - memset (t->unverified_ax, - 0, - sizeof (struct CadetTunnelAxolotl)); - new_ephemeral (t->unverified_ax); - t->unverified_ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create (); - } - else - { - t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl); - new_ephemeral (t->unverified_ax); - t->unverified_ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create (); - } - t->unverified_attempts = 0; - ax = t->unverified_ax; - - pid = GCP_get_id (t->destination); if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid)) am_I_alice = GNUNET_YES; @@ -1382,37 +1355,25 @@ GCT_handle_kx (struct CadetTConnection *ct, else { GNUNET_break_op (0); - return; - } - - if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags))) - { - if (NULL != t->kx_task) - { - GNUNET_SCHEDULER_cancel (t->kx_task); - t->kx_task = NULL; - } - send_kx (t, - ax, - GNUNET_NO); + return GNUNET_SYSERR; } if (0 == memcmp (&ax->DHRr, - &msg->ratchet_key, - sizeof (msg->ratchet_key))) + ratchet_key, + sizeof (*ratchet_key))) { LOG (GNUNET_ERROR_TYPE_DEBUG, - " known ratchet key, exit\n"); - return; + "Ratchet key already known. Ignoring KX.\n"); + return GNUNET_NO; } - ax->DHRr = msg->ratchet_key; + ax->DHRr = *ratchet_key; /* ECDH A B0 */ if (GNUNET_YES == am_I_alice) { GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */ - &msg->ephemeral_key, /* B0 */ + ephemeral_key, /* B0 */ &key_material[0]); } else @@ -1432,7 +1393,7 @@ GCT_handle_kx (struct CadetTConnection *ct, else { GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */ - &msg->ephemeral_key, /* B0 */ + ephemeral_key, /* B0 */ &key_material[1]); @@ -1442,7 +1403,7 @@ GCT_handle_kx (struct CadetTConnection *ct, /* (This is the triple-DH, we could probably safely skip this, as A0/B0 are already in the key material.) */ GNUNET_CRYPTO_ecc_ecdh (ax->kx_0, /* A0 or B0 */ - &msg->ephemeral_key, /* B0 or A0 */ + ephemeral_key, /* B0 or A0 */ &key_material[2]); /* KDF */ @@ -1455,13 +1416,10 @@ GCT_handle_kx (struct CadetTConnection *ct, &keys[0], sizeof (ax->RK))) { - LOG (GNUNET_ERROR_TYPE_INFO, - " known handshake key, exit\n"); - return; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Root key of handshake already known. Ignoring KX.\n"); + return GNUNET_NO; } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Handling KX message for tunnel %s\n", - GCT_2s (t)); ax->RK = keys[0]; if (GNUNET_YES == am_I_alice) @@ -1479,16 +1437,84 @@ GCT_handle_kx (struct CadetTConnection *ct, ax->NHKs = keys[3]; ax->CKs = keys[4]; ax->ratchet_flag = GNUNET_NO; - ax->ratchet_allowed = GNUNET_NO; - ax->ratchet_counter = 0; ax->ratchet_expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time); } - ax->PNs = 0; - ax->Nr = 0; - ax->Ns = 0; + return GNUNET_OK; +} + + +/** + * Handle KX message that lacks authentication (and which will thus + * only be considered authenticated after we respond with our own + * KX_AUTH and finally successfully decrypt payload). + * + * @param ct connection/tunnel combo that received encrypted message + * @param msg the key exchange message + */ +void +GCT_handle_kx (struct CadetTConnection *ct, + const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) +{ + struct CadetTunnel *t = ct->t; + struct CadetTunnelAxolotl *ax; + int ret; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Handling KX message for tunnel %s\n", + GCT_2s (t)); + /* We only keep ONE unverified KX around, so if there is an existing one, + clean it up. */ + if (NULL != t->unverified_ax) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Dropping old unverified KX state, got a fresh one.\n", + t->unverified_attempts); + cleanup_ax (t->unverified_ax); + memset (t->unverified_ax, + 0, + sizeof (struct CadetTunnelAxolotl)); + new_ephemeral (t->unverified_ax); + t->unverified_ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create (); + } + else + { + t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl); + new_ephemeral (t->unverified_ax); + t->unverified_ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create (); + } + /* Set as the 'current' RK the one we are currently using, + so that the duplicate-detection logic of + #update_ax_by_kx can work. */ + t->unverified_ax->RK = t->ax.RK; + t->unverified_attempts = 0; + ax = t->unverified_ax; + + /* FIXME: why this? Investigate use of kx_task! */ + if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags))) + { + if (NULL != t->kx_task) + { + GNUNET_SCHEDULER_cancel (t->kx_task); + t->kx_task = NULL; + } + send_kx (t, + ax, + GNUNET_NO); + } + + /* Update 'ax' by the new key material */ + ret = update_ax_by_kx (ax, + GCP_get_id (t->destination), + &msg->ephemeral_key, + &msg->ratchet_key); + GNUNET_break (GNUNET_SYSERR != ret); + if (GNUNET_OK != ret) + return; /* duplicate KX, nothing to do */ + + /* move ahead in our state machine */ switch (t->estate) { case CADET_TUNNEL_KEY_UNINITIALIZED: @@ -1506,14 +1532,12 @@ GCT_handle_kx (struct CadetTConnection *ct, t); break; case CADET_TUNNEL_KEY_PING: - /* Got a key yet again; need encrypted payload to advance */ + /* Got a key yet again; need encrypted payload or KX_AUTH + to advance to #CADET_TUNNEL_KEY_OK! */ break; case CADET_TUNNEL_KEY_OK: /* Did not expect a key, but so what. */ break; - case CADET_TUNNEL_KEY_REKEY: - /* Got a key yet again; need encrypted payload to advance */ - break; } } @@ -1582,8 +1606,7 @@ GCT_add_channel (struct CadetTunnel *t, "Adding channel %s to tunnel %s\n", GCCH_2s (ch), GCT_2s (t)); - if ( (CADET_TUNNEL_KEY_OK == t->estate) || - (CADET_TUNNEL_KEY_REKEY == t->estate) ) + if (CADET_TUNNEL_KEY_OK == t->estate) GCCH_tunnel_up (ch); return ctn; } @@ -1858,12 +1881,6 @@ connection_ready_cb (void *cls, try_send_normal_payload (t, ct); break; - case CADET_TUNNEL_KEY_REKEY: - send_kx (t, - &t->ax, - GNUNET_NO); - t->estate = CADET_TUNNEL_KEY_OK; - break; } } @@ -2466,7 +2483,6 @@ GCT_handle_encrypted (struct CadetTConnection *ct, case CADET_TUNNEL_KEY_PING: /* Great, first payload, we might graduate to OK */ case CADET_TUNNEL_KEY_OK: - case CADET_TUNNEL_KEY_REKEY: break; } @@ -2475,8 +2491,7 @@ GCT_handle_encrypted (struct CadetTConnection *ct, 1, GNUNET_NO); decrypted_size = -1; - if ( (CADET_TUNNEL_KEY_OK == t->estate) || - (CADET_TUNNEL_KEY_REKEY == t->estate) ) + if (CADET_TUNNEL_KEY_OK == t->estate) { /* We have well-established key material available, try that. (This is the common case.) */ @@ -2580,8 +2595,7 @@ GCT_send (struct CadetTunnel *t, struct GNUNET_MQ_Envelope *env; struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg; - if ( (CADET_TUNNEL_KEY_OK != t->estate) && - (CADET_TUNNEL_KEY_REKEY != t->estate) ) + if (CADET_TUNNEL_KEY_OK != t->estate) { GNUNET_break (0); return NULL; diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h b/src/cadet/gnunet-service-cadet-new_tunnels.h index 080de0fc3..09688eb70 100644 --- a/src/cadet/gnunet-service-cadet-new_tunnels.h +++ b/src/cadet/gnunet-service-cadet-new_tunnels.h @@ -65,14 +65,8 @@ enum CadetTunnelEState /** * Handshake completed: session key available. */ - CADET_TUNNEL_KEY_OK, + CADET_TUNNEL_KEY_OK - /** - * New ephemeral key and ping sent, waiting for pong. Unlike KEY_PING, - * we still have a valid session key and therefore we *can* still send - * traffic on the tunnel. - */ - CADET_TUNNEL_KEY_REKEY };