mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2026-09-01 22:18:31 +00:00
libi2pd: fix parsing crashes
This commit is contained in:
@@ -243,9 +243,9 @@ namespace datagram
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (offset > len)
|
||||
if (offset > len || signatureLen > len - offset)
|
||||
{
|
||||
LogPrint (eLogWarning, "Datagram: datagram2 is too short ", len, " expected ", offset);
|
||||
LogPrint (eLogWarning, "Datagram: datagram2 is too short ", len, " expected ", offset + signatureLen);
|
||||
return;
|
||||
}
|
||||
if (!verified)
|
||||
@@ -261,6 +261,11 @@ namespace datagram
|
||||
}
|
||||
signatureLen = transientVerifier->GetSignatureLen ();
|
||||
}
|
||||
if (offset > len || signatureLen > len - offset)
|
||||
{
|
||||
LogPrint (eLogWarning, "Datagram: datagram2 is too short ", len, " expected ", offset + signatureLen);
|
||||
return;
|
||||
}
|
||||
std::vector<uint8_t> signedData (len + 32 - identityLen - signatureLen);
|
||||
memcpy (signedData.data (), identity.GetIdentHash (), 32);
|
||||
memcpy (signedData.data () + 32, buf + identityLen, signedData.size () - 32);
|
||||
|
||||
@@ -1338,6 +1338,11 @@ namespace transport
|
||||
LogPrint (eLogError, "NTCP2: I2NP block is too long ", size);
|
||||
break;
|
||||
}
|
||||
if (size < 9)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: I2NP block is too short ", size);
|
||||
break;
|
||||
}
|
||||
auto nextMsg = (frame[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPMessage (size);
|
||||
nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
|
||||
if (nextMsg->len <= nextMsg->maxLen)
|
||||
|
||||
+30
-17
@@ -804,7 +804,7 @@ namespace data
|
||||
void NetDb::HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> m)
|
||||
{
|
||||
const uint8_t * buf = m->GetPayload ();
|
||||
size_t len = m->GetSize ();
|
||||
size_t len = m->GetPayloadLength ();
|
||||
if (len < DATABASE_STORE_HEADER_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: Database store msg is too short ", len, ". Dropped");
|
||||
@@ -964,6 +964,12 @@ namespace data
|
||||
|
||||
LogPrint (eLogDebug, "NetDb: DatabaseLookup for ", key, " received flags=", (int)flag);
|
||||
uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK;
|
||||
size_t minLen = 65 + ((flag & DATABASE_LOOKUP_DELIVERY_FLAG) ? 4 : 0) + 2;
|
||||
if (msg->GetPayloadLength () < minLen)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: DatabaseLookup message is too short for its flags");
|
||||
return;
|
||||
}
|
||||
const uint8_t * excluded = buf + 65;
|
||||
uint32_t replyTunnelID = 0;
|
||||
if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) //reply to tunnel
|
||||
@@ -1061,27 +1067,34 @@ namespace data
|
||||
// encryption might be used though tunnel only
|
||||
if (flag & (DATABASE_LOOKUP_ENCRYPTION_FLAG | DATABASE_LOOKUP_ECIES_FLAG)) // encrypted reply requested
|
||||
{
|
||||
const uint8_t * sessionKey = excluded;
|
||||
const uint8_t numTags = excluded[32];
|
||||
if (numTags)
|
||||
// session key (32) + numTags (1), then the tag itself: 8 bytes for ECIES, 32 for ElGamal
|
||||
size_t tagLen = (flag & DATABASE_LOOKUP_ECIES_FLAG) ? 8 : 32;
|
||||
if ((size_t)(excluded - buf) + 33 + tagLen > msg->GetPayloadLength ())
|
||||
LogPrint (eLogWarning, "NetDb: DatabaseLookup reply key block is truncated");
|
||||
else
|
||||
{
|
||||
if (flag & DATABASE_LOOKUP_ECIES_FLAG)
|
||||
const uint8_t * sessionKey = excluded;
|
||||
const uint8_t numTags = excluded[32];
|
||||
if (numTags)
|
||||
{
|
||||
uint64_t tag;
|
||||
memcpy (&tag, excluded + 33, 8);
|
||||
replyMsg = i2p::garlic::WrapECIESX25519Message (replyMsg, sessionKey, tag);
|
||||
if (flag & DATABASE_LOOKUP_ECIES_FLAG)
|
||||
{
|
||||
uint64_t tag;
|
||||
memcpy (&tag, excluded + 33, 8);
|
||||
replyMsg = i2p::garlic::WrapECIESX25519Message (replyMsg, sessionKey, tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag
|
||||
i2p::garlic::ElGamalAESSession garlic (sessionKey, sessionTag);
|
||||
replyMsg = garlic.WrapSingleMessage (replyMsg);
|
||||
}
|
||||
if (!replyMsg)
|
||||
LogPrint (eLogError, "NetDb: Failed to wrap message");
|
||||
}
|
||||
else
|
||||
{
|
||||
const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag
|
||||
i2p::garlic::ElGamalAESSession garlic (sessionKey, sessionTag);
|
||||
replyMsg = garlic.WrapSingleMessage (replyMsg);
|
||||
}
|
||||
if (!replyMsg)
|
||||
LogPrint (eLogError, "NetDb: Failed to wrap message");
|
||||
LogPrint(eLogWarning, "NetDb: Encrypted reply requested but no tags provided");
|
||||
}
|
||||
else
|
||||
LogPrint(eLogWarning, "NetDb: Encrypted reply requested but no tags provided");
|
||||
}
|
||||
bool direct = true;
|
||||
if (!i2p::transport::transports.IsConnected (replyIdent))
|
||||
|
||||
@@ -324,7 +324,7 @@ namespace data
|
||||
}
|
||||
else if (address->transportStyle == eTransportSSU2)
|
||||
{
|
||||
if (value[0] >= '3' && value[0] <= '4') // only 3,4 allowed, TODO: support multiple values
|
||||
if (value.size () == 1 && value[0] >= '3' && value[0] <= '4') // only 3,4 allowed, TODO: support multiple values
|
||||
address->v = value[0] - '0';
|
||||
}
|
||||
}
|
||||
|
||||
+26
-4
@@ -1707,9 +1707,9 @@ namespace transport
|
||||
|
||||
uint32_t SSU2Session::SendData (const uint8_t * buf, size_t len, uint8_t flags)
|
||||
{
|
||||
if (len < 8)
|
||||
if (len < 8 || len + 16 > SSU2_MAX_PACKET_SIZE)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: Data message payload is too short ", (int)len);
|
||||
LogPrint (eLogWarning, "SSU2: Data message payload length ", (int)len, " is out of range");
|
||||
return 0;
|
||||
}
|
||||
Header header;
|
||||
@@ -1721,7 +1721,11 @@ namespace transport
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (m_SendPacketNum, nonce);
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||
m_Server.AEADChaCha20Poly1305Encrypt (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE);
|
||||
if (!m_Server.AEADChaCha20Poly1305Encrypt (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE))
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Data message AEAD encryption failed");
|
||||
return 0;
|
||||
}
|
||||
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8));
|
||||
header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4));
|
||||
m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint);
|
||||
@@ -1804,6 +1808,12 @@ namespace transport
|
||||
case eSSU2BlkI2NPMessage:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU2: I2NP message");
|
||||
if (size < 9)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: I2NP message block size ", size, " is too short");
|
||||
m_IsInvalidMessage = true;
|
||||
break;
|
||||
}
|
||||
auto nextMsg = (buf[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage ();
|
||||
if (nextMsg->offset + size + 7 > nextMsg->maxLen) // 7 more bytes for full I2NP header
|
||||
{
|
||||
@@ -2157,6 +2167,12 @@ namespace transport
|
||||
|
||||
void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (len < 9)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: First fragment size ", len, " is too short");
|
||||
m_IsInvalidMessage = true;
|
||||
return;
|
||||
}
|
||||
auto msg = (buf[0] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage ();
|
||||
if (msg->offset + len + 7 > msg->maxLen)
|
||||
{
|
||||
@@ -2434,13 +2450,19 @@ namespace transport
|
||||
if (relaySession && relaySession->IsEstablished ())
|
||||
{
|
||||
// we are Bob, message from Charlie
|
||||
size_t maxPayloadSize = relaySession->GetMaxPayloadSize ();
|
||||
if (len + 3 > maxPayloadSize)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: RelayResponse block size ", len, " is too long");
|
||||
return;
|
||||
}
|
||||
auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
|
||||
uint8_t * payload = packet->payload;
|
||||
payload[0] = eSSU2BlkRelayResponse;
|
||||
htobe16buf (payload + 1, len);
|
||||
memcpy (payload + 3, buf, len); // forward to Alice as is
|
||||
packet->payloadSize = len + 3;
|
||||
packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
|
||||
packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, maxPayloadSize - packet->payloadSize);
|
||||
uint32_t packetNum = relaySession->SendData (packet->payload, packet->payloadSize);
|
||||
if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION)
|
||||
{
|
||||
|
||||
@@ -1008,7 +1008,7 @@ namespace stream
|
||||
else if (numMsgs > m_NumPacketsToSend)
|
||||
numMsgs = m_NumPacketsToSend;
|
||||
|
||||
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
if (!m_RemoteLeaseSet && m_RemoteIdentity) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
if (!m_RoutingSession)
|
||||
@@ -1082,7 +1082,7 @@ namespace stream
|
||||
{
|
||||
// initial packet
|
||||
m_Status = eStreamStatusOpen;
|
||||
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
if (!m_RemoteLeaseSet && m_RemoteIdentity) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming);
|
||||
@@ -1972,6 +1972,13 @@ namespace stream
|
||||
bool isLeaseChanged = true;
|
||||
if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired ())
|
||||
{
|
||||
if (!m_RemoteIdentity)
|
||||
{
|
||||
// no remote identity established yet, nothing to look up
|
||||
m_Status = eStreamStatusClosed;
|
||||
AsyncClose ();
|
||||
return;
|
||||
}
|
||||
auto remoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
if (!remoteLeaseSet)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user