From 78357c23d22f8a62290b02f745e97f9e987cb166 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jun 2025 20:39:48 -0400 Subject: [PATCH] don't verify signature in incoming SYN packet if came from ECIESx25519 session. Compare static key instead --- libi2pd/Destination.cpp | 7 ++-- libi2pd/Destination.h | 4 +- libi2pd/Streaming.cpp | 83 ++++++++++++++++++++++++++++------------- libi2pd/Streaming.h | 6 ++- libi2pd_client/I2CP.cpp | 3 +- libi2pd_client/I2CP.h | 2 +- 6 files changed, 70 insertions(+), 35 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 52418471..e1ccbc92 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -388,7 +388,7 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (payload, len); + HandleDataMessage (payload, len, from); break; case eI2NPDeliveryStatus: HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET)); @@ -1158,7 +1158,8 @@ namespace client LogPrint(eLogDebug, "Destination: -> Stopping done"); } - void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) + void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) { uint32_t length = bufbe32toh (buf); if(length > len - 4) @@ -1183,7 +1184,7 @@ namespace client m_LastPort = toPort; } if (m_LastStreamingDestination) - m_LastStreamingDestination->HandleDataMessagePayload (buf, length); + m_LastStreamingDestination->HandleDataMessagePayload (buf, length, from); else LogPrint (eLogError, "Destination: Missing streaming destination"); } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 35557859..f2bef491 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -174,7 +174,7 @@ namespace client virtual void CleanupDestination () {}; // additional clean up in derived classes virtual i2p::data::CryptoKeyType GetPreferredCryptoType () const = 0; // I2CP - virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; + virtual void HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) = 0; virtual void CreateNewLeaseSet (const std::vector >& tunnels) = 0; private: @@ -288,7 +288,7 @@ namespace client void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; } // I2CP - void HandleDataMessage (const uint8_t * buf, size_t len) override; + void HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) override; void CreateNewLeaseSet (const std::vector >& tunnels) override; private: diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 8d125e6f..cb401b06 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -397,6 +397,7 @@ namespace stream optionData += 2; } + bool sessionVerified = false; if (flags & PACKET_FLAG_FROM_INCLUDED) { if (m_RemoteLeaseSet) m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity (); @@ -409,7 +410,29 @@ namespace stream } optionData += m_RemoteIdentity->GetFullLen (); if (!m_RemoteLeaseSet) - LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); + { + LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase32 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); + if (packet->from) + { + // stream came from ratchets session and static key must match one from LeaseSet + m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); + if (!m_RemoteLeaseSet) + { + LogPrint (eLogInfo, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase32 (), + " without LeaseSet. sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); + return false; + } + uint8_t staticKey[32]; + m_RemoteLeaseSet->Encrypt (nullptr, staticKey); + if (memcmp (packet->from->GetRemoteStaticKey (), staticKey, 32)) + { + LogPrint (eLogError, "Streaming: Remote LeaseSet static key mismatch for incoming stream from ", + m_RemoteIdentity->GetIdentHash ().ToBase32 ()); + return false; + } + sessionVerified = true; + } + } } if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED) @@ -451,35 +474,39 @@ namespace stream if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) { - bool verified = false; auto signatureLen = m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : m_RemoteIdentity->GetSignatureLen (); if (signatureLen > packet->GetLength ()) { LogPrint (eLogError, "Streaming: Signature too big, ", signatureLen, " bytes"); return false; } - if(signatureLen <= 256) - { - // standard - uint8_t signature[256]; - memcpy (signature, optionData, signatureLen); - memset (const_cast(optionData), 0, signatureLen); - verified = m_TransientVerifier ? - m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature) : - m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature); - if (verified) - memcpy (const_cast(optionData), signature, signatureLen); - } - else - { - // post quantum - std::vector signature(signatureLen); - memcpy (signature.data (), optionData, signatureLen); - memset (const_cast(optionData), 0, signatureLen); - verified = m_TransientVerifier ? - m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature.data ()) : - m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature.data ()); - } + bool verified = sessionVerified; + if (!verified) // packet was not verified through session + { + // verify actual signature + if (signatureLen <= 256) + { + // standard + uint8_t signature[256]; + memcpy (signature, optionData, signatureLen); + memset (const_cast(optionData), 0, signatureLen); + verified = m_TransientVerifier ? + m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature) : + m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature); + if (verified) + memcpy (const_cast(optionData), signature, signatureLen); + } + else + { + // post quantum + std::vector signature(signatureLen); + memcpy (signature.data (), optionData, signatureLen); + memset (const_cast(optionData), 0, signatureLen); + verified = m_TransientVerifier ? + m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature.data ()) : + m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature.data ()); + } + } if (verified) optionData += signatureLen; else @@ -812,7 +839,7 @@ namespace stream { // initial packet m_Status = eStreamStatusOpen; - if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());; + if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); if (m_RemoteLeaseSet) { m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming); @@ -2054,14 +2081,18 @@ namespace stream } } - void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len) + void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) { // unzip it Packet * uncompressed = NewPacket (); uncompressed->offset = 0; uncompressed->len = m_Inflator.Inflate (buf, len, uncompressed->buf, MAX_PACKET_SIZE); if (uncompressed->len) + { + uncompressed->from = from; HandleNextPacket (uncompressed); + } else DeletePacket (uncompressed); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 9fbcb178..eae43c0e 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -27,6 +27,7 @@ #include "Garlic.h" #include "Tunnel.h" #include "util.h" // MemoryPool +#include "ECIESX25519AEADRatchetSession.h" namespace i2p { @@ -88,8 +89,9 @@ namespace stream uint8_t buf[MAX_PACKET_SIZE]; uint64_t sendTime; bool resent; + i2p::garlic::ECIESX25519AEADRatchetSession * from; - Packet (): len (0), offset (0), sendTime (0), resent (false) {}; + Packet (): len (0), offset (0), sendTime (0), resent (false), from (nullptr) {}; uint8_t * GetBuffer () { return buf + offset; }; size_t GetLength () const { return len > offset ? len - offset : 0; }; @@ -340,7 +342,7 @@ namespace stream void SetOwner (std::shared_ptr owner) { m_Owner = owner; }; uint16_t GetLocalPort () const { return m_LocalPort; }; - void HandleDataMessagePayload (const uint8_t * buf, size_t len); + void HandleDataMessagePayload (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from); std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true, bool gzip = false); Packet * NewPacket () { return m_PacketsPool.Acquire(); } diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 11278e7a..f2e9be57 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -86,7 +86,8 @@ namespace client return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; } - void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len) + void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) { uint32_t length = bufbe32toh (buf); if (length > len - 4) length = len - 4; diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 37c14dbb..0bfa49f2 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -117,7 +117,7 @@ namespace client void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override; // I2CP - void HandleDataMessage (const uint8_t * buf, size_t len) override; + void HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) override; void CreateNewLeaseSet (const std::vector >& tunnels) override; private: