commit cbd8837dad91195c20058a59ac3e29c34f397308
parent 9a3bc1794dc457563b55f2e7a44619fa279b72b3
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date: Tue, 11 Aug 2026 16:21:14 +0200
core: do not let an unexpected InitiatorHello wedge the key exchange
Diffstat:
1 file changed, 30 insertions(+), 0 deletions(-)
diff --git a/src/service/core/gnunet-service-core_kx.c b/src/service/core/gnunet-service-core_kx.c
@@ -1712,6 +1712,7 @@ handle_initiator_hello_cont (struct GSC_KeyExchangeInfo *kx,
uint32_t ihm_len = ntohs (ihm_e->header.size);
unsigned char enc_key[AEAD_KEY_BYTES];
unsigned char enc_nonce[AEAD_NONCE_BYTES];
+ struct GNUNET_PeerIdentity peer_before = kx->peer;
struct GNUNET_HashCode h1;
struct GNUNET_HashCode transcript;
struct GNUNET_ShortHashCode es;
@@ -1782,6 +1783,29 @@ handle_initiator_hello_cont (struct GSC_KeyExchangeInfo *kx,
sizeof (struct GNUNET_PeerIdentity));
}
+ /* @e pk_I is the initiator's *claim* about who it is, and nothing has
+ checked it. It must be the peer transport handed us this @a kx for:
+ @e role was derived from that identity, GSC_SESSIONS_create() below
+ keys the session on it, and transport routes everything we send by it.
+ Letting the claim through means one peer can make us run a session
+ under another peer's identity, and -- via the role comparison right
+ below, which is computed over exactly this value -- can pick a @e pk_I
+ that sends us down the reject path at will. */
+ if (0 != GNUNET_memcmp (&kx->peer, &peer_before))
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "InitiatorHello from `%s' claims to be `%s'\n",
+ GNUNET_i2s (&peer_before),
+ GNUNET_i2s2 (&kx->peer));
+ kx->peer = peer_before;
+ GNUNET_CRYPTO_hash_context_abort (kx->transcript_hash_ctx);
+ kx->transcript_hash_ctx = NULL;
+ kx->status = GNUNET_CORE_KX_STATE_AWAIT_INITIATION;
+ GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
+ return;
+ }
+
my_identity_hash = GNUNET_PILS_get_identity_hash (GSC_pils);
GNUNET_assert (NULL != my_identity_hash);
@@ -1801,6 +1825,12 @@ handle_initiator_hello_cont (struct GSC_KeyExchangeInfo *kx,
"Something went wrong - we have the lower value and should have sent the InitiatorHello, but instead received it.\n");
GNUNET_CRYPTO_hash_context_abort (kx->transcript_hash_ctx);
kx->transcript_hash_ctx = NULL;
+ /* Same reason the three other reject paths in #handle_initiator_hello()
+ do this: that function set @e status to INITIATOR_HELLO_RECEIVED
+ before calling us, and leaving it there makes every *later* hello hit
+ the "Already received InitiatorHello" guard and be dropped, forever.
+ Rejecting this hello must not cost us the next one. */
+ kx->status = GNUNET_CORE_KX_STATE_AWAIT_INITIATION;
GNUNET_TRANSPORT_core_receive_continue (transport, &kx->peer);
return;
}