gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/service/core/gnunet-service-core_kx.c | 30++++++++++++++++++++++++++++++
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; }