diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 57a503ba..f9c91465 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -276,9 +276,21 @@ namespace client auto it = m_MethodHandlers.find (method); if (it != m_MethodHandlers.end ()) { - response << "{\"id\":" << id << ",\"result\":{"; - (this->*(it->second))(pt.get_child ("params"), response); - response << "},\"jsonrpc\":\"2.0\"}\n"; + auto params = pt.get_child ("params"); + if (method != "Authenticate" && + !m_Tokens.count (params.get ("Token", ""))) + { + LogPrint (eLogWarning, "I2PControl: Invalid or missing token for method ", method); + response << "{\"id\":null,\"error\":"; + response << "{\"code\":-32602,\"message\":\"Invalid or missing token\"},"; + response << "\"jsonrpc\":\"2.0\"}\n"; + } + else + { + response << "{\"id\":" << id << ",\"result\":{"; + (this->*(it->second))(params, response); + response << "},\"jsonrpc\":\"2.0\"}\n"; + } } else { diff --git a/libi2pd/Blinding.cpp b/libi2pd/Blinding.cpp index 9622db5e..11111707 100644 --- a/libi2pd/Blinding.cpp +++ b/libi2pd/Blinding.cpp @@ -81,6 +81,18 @@ namespace data LogPrint (eLogError, "Blinding: Unknown signature type ", (int)m_SigType, " in b33"); } + bool BlindedPublicKey::IsValid () const + { + switch (m_SigType) + { + case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: + case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: + return true; + default: + return false; + } + } + std::string BlindedPublicKey::ToB33 () const { if (m_PublicKey.size () > 32) return ""; // assume 25519 @@ -183,7 +195,7 @@ namespace data i2p::data::IdentHash BlindedPublicKey::GetStoreHash (const char * date) const { - i2p::data::IdentHash hash; + i2p::data::IdentHash hash{}; uint8_t blinded[i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH]; // 32 max size_t publicKeyLength = 0; if (date) diff --git a/libi2pd/Blinding.h b/libi2pd/Blinding.h index c684fd1c..1fc138f8 100644 --- a/libi2pd/Blinding.h +++ b/libi2pd/Blinding.h @@ -32,7 +32,7 @@ namespace data size_t GetPublicKeyLen () const { return m_PublicKey.size (); }; SigningKeyType GetSigType () const { return m_SigType; }; SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; }; - bool IsValid () const { return GetSigType (); }; // signature type 0 means invalid + bool IsValid () const; // signature type must be blindable void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes size_t GetBlindedKey (const char * date, uint8_t * blindedKey) const; // date is 8 chars "YYYYMMDD", return public key length diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index c36cca5a..5b40a3d5 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -575,6 +575,11 @@ namespace garlic void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, std::shared_ptr from) { + if (len < 2) + { + LogPrint (eLogError, "Garlic: AES block length ", len, " is too short"); + return; + } uint16_t tagCount = bufbe16toh (buf); buf += 2; len -= 2; if (tagCount > 0) @@ -590,18 +595,30 @@ namespace garlic } buf += tagCount*32; len -= tagCount*32; + if (len < 37) // 4 (payload size) + 32 (payload hash) + 1 (flag) + { + LogPrint (eLogError, "Garlic: AES block is too short for payload header, length ", len); + return; + } uint32_t payloadSize = bufbe32toh (buf); + buf += 4; len -= 4; + uint8_t * payloadHash = buf; + buf += 32; len -= 32; // payload hash. + if (*buf) // session key? + { + if (len < 33) // 32 (new session key) + 1 (flag) + { + LogPrint (eLogError, "Garlic: AES block is too short for session key, length ", len); + return; + } + buf += 32; len -= 32; // new session key + } + buf++; len--; // flag if (payloadSize > len) { LogPrint (eLogError, "Garlic: Unexpected payload size ", payloadSize); return; } - buf += 4; - uint8_t * payloadHash = buf; - buf += 32;// payload hash. - if (*buf) // session key? - buf += 32; // new session key - buf++; // flag // payload uint8_t digest[32]; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index bcf39dd9..950b5e3c 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -661,12 +661,18 @@ namespace data size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const { + if (len < 1) return 0; size_t offset = 0; uint8_t flag = buf[offset]; offset++; // flag if (flag & 0x01) // client auth { if (!(flag & 0x0E)) // DH, bit 1-3 all zeroes { + if (offset + 34 > len) // ephemeralPublicKey(32) + numClients(2) + { + LogPrint (eLogError, "LeaseSet2: Buffer too short for DH auth data header"); + return 0; + } const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients @@ -693,6 +699,11 @@ namespace data } else if (flag & 0x02) // PSK, bit 1 is set to 1 { + if (offset + 34 > len) // authSalt(32) + numClients(2) + { + LogPrint (eLogError, "LeaseSet2: Buffer too short for PSK auth data header"); + return 0; + } const uint8_t * authSalt = buf + offset; offset += 32; // authSalt uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients @@ -854,6 +865,11 @@ namespace data size += 256; // signing key (unused) size += ident.GetSigningPublicKeyLen (); + if (size + 1 > sz) + { + LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", sz); + return false; + } uint8_t numLeases = ptr[size]; ++size; if (!numLeases || numLeases > MAX_NUM_LEASES) @@ -861,6 +877,11 @@ namespace data LogPrint (eLogError, "LeaseSet: Incorrect number of leases", (int)numLeases); return false; } + if (size + numLeases*LEASE_SIZE > sz) + { + LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", sz); + return false; + } const uint8_t * leases = ptr + size; expires = 0; /** find lease with the max expiration timestamp */ @@ -872,6 +893,11 @@ namespace data if(endDate > expires) expires = endDate; } + if ((size_t)(leases - ptr) + ident.GetSignatureLen () > sz) + { + LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", sz); + return false; + } return ident.Verify(ptr, leases - ptr, leases); } diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 61014dd9..d2e888b5 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2283,7 +2283,8 @@ namespace transport if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); - packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; + size_t riMaxLen = (len + 32 < m_MaxPayloadSize) ? m_MaxPayloadSize - len - 32 : 0; + packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, riMaxLen, r) : 0; if (!packet->payloadSize && r) session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len - 1); @@ -2526,7 +2527,8 @@ namespace transport // Alice's RouterInfo auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; - packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; + size_t riMaxLen = (len + 32 < m_MaxPayloadSize) ? m_MaxPayloadSize - len - 32 : 0; + packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, riMaxLen, r) : 0; if (!packet->payloadSize && r) session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); if (packet->payloadSize + len + 48 > m_MaxPayloadSize) @@ -2645,7 +2647,8 @@ namespace transport // Charlie's RouterInfo auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; - packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; + size_t riMaxLen = (len + 32 < m_MaxPayloadSize) ? m_MaxPayloadSize - len - 32 : 0; + packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, riMaxLen, r) : 0; if (!packet->payloadSize && r) aliceSession->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); if (packet->payloadSize + len + 16 > m_MaxPayloadSize) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 049bb5aa..48c31d86 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -779,7 +779,7 @@ namespace client auto res = std::from_chars(sizeStr.data(), sizeStr.data() + sizeStr.size(), size); if (res.ec != std::errc()) size = 0; size_t offset = data - buf; - if (offset + size <= len) + if (offset <= len && size <= len - offset) { auto session = m_Owner.FindSession(m_ID); if (session)