From 37fd4b4422cc0c1fbe8321d4de9fcaaff2220cdc Mon Sep 17 00:00:00 2001 From: Daniel Bermond Date: Mon, 2 Jun 2025 23:28:51 -0300 Subject: [PATCH 01/31] tests: fix test-base-64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test-base-64 was not updated after the following commits: https://github.com/PurpleI2P/i2pd/commit/93cc810f2987cc90b7a4f8699655af43b36c6c23 https://github.com/PurpleI2P/i2pd/commit/bbf5c1655a5f331b36cc7e16ad0bba86bb36eed4 This leads to errors like: In file included from /usr/include/c++/15.1.1/cassert:46, from /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp:1: /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp: In function ‘int main()’: /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp:14:28: error: too many arguments to function ‘std::string i2p::data::ByteStreamToBase64(const uint8_t*, size_t)’ 14 | assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0); | ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ and: In file included from /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp:4: /build/i2pd/src/i2pd-2.57.0/build/../libi2pd/Base.h:21:21: note: declared here 21 | std::string ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount); | ^~~~~~~~~~~~~~~~~~ /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp:14:47: error: no match for ‘operator==’ (operand types are ‘std::string’ {aka ‘std::__cxx11::basic_string’} and ‘int’) 14 | assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~ ~ | | | | | int | std::string {aka std::__cxx11::basic_string} among others. --- tests/test-base-64.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test-base-64.cpp b/tests/test-base-64.cpp index 0ab46c06..63817bf4 100644 --- a/tests/test-base-64.cpp +++ b/tests/test-base-64.cpp @@ -11,8 +11,7 @@ int main() { char out[16]; /* bytes -> b64 */ - assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0); - assert(ByteStreamToBase64(NULL, 0, out, sizeof(out)) == 0); + assert(ByteStreamToBase64(NULL, 0) == ""); assert(Base64EncodingBufferSize(2) == 4); assert(Base64EncodingBufferSize(4) == 8); @@ -23,19 +22,20 @@ int main() { assert(Base64EncodingBufferSize(12) == 16); assert(Base64EncodingBufferSize(13) == 20); - assert(ByteStreamToBase64((uint8_t *) in, in_len, out, sizeof(out)) == 8); - assert(memcmp(out, "dGVzdA==", 8) == 0); + const std::string out_str(ByteStreamToBase64((uint8_t *) in, in_len)); + assert(out_str.size() == 8); + assert(out_str == "dGVzdA=="); /* b64 -> bytes */ - assert(Base64ToByteStream(NULL, 0, NULL, 0) == 0); - assert(Base64ToByteStream(NULL, 0, (uint8_t *) out, sizeof(out)) == 0); + assert(Base64ToByteStream("", NULL, 0) == 0); + assert(Base64ToByteStream("", (uint8_t *) out, sizeof(out)) == 0); in = "dGVzdA=="; /* valid b64 */ - assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 4); + assert(Base64ToByteStream(in, (uint8_t *) out, sizeof(out)) == 4); assert(memcmp(out, "test", 4) == 0); in = "dGVzdA="; /* invalid b64 : not padded */ - assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 0); + assert(Base64ToByteStream(in, (uint8_t *) out, sizeof(out)) == 0); in = "dG/z.A=="; /* invalid b64 : char not from alphabet */ // assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 0); From 2631255b467760d978f3cbd02e1d65e902b9e378 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jun 2025 07:57:08 -0400 Subject: [PATCH 02/31] enable post quantum back --- libi2pd/Crypto.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 80650098..125a217c 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -33,9 +33,9 @@ # if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL # define OPENSSL_SIPHASH 1 # endif -//# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 -//# define OPENSSL_PQ 1 -//# endif +# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 +# define OPENSSL_PQ 1 +# endif #endif namespace i2p From 6ad6a2501eac86623db303bceee70a1989e538e6 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jun 2025 07:58:31 -0400 Subject: [PATCH 03/31] fixed incorrect limit in strsplit --- libi2pd/HTTP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 3cd5c193..8c7c8491 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -55,7 +55,7 @@ namespace http static void strsplit(std::string_view line, std::vector &tokens, char delim, std::size_t limit = 0) { - size_t count = 0, pos; + size_t count = 1, pos; while ((pos = line.find (delim)) != line.npos) { count++; From cbb5250dd4f929f9b0f408186b4d74b745e7d49a Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jun 2025 18:46:22 -0400 Subject: [PATCH 04/31] don't schedule resend timer while choked --- libi2pd/Streaming.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 1f849925..8d125e6f 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1416,6 +1416,7 @@ namespace stream m_SendTimer.cancel (); // if no ack's in RTO, disable fast retransmit m_IsTimeOutResend = true; m_IsNAcked = false; + m_IsClientChoked = false; m_IsResendNeeded = false; m_NumPacketsToSend = 1; ResendPacket (); // send one packet per RTO, waiting for ack @@ -1538,7 +1539,7 @@ namespace stream } else if (!m_IsClientChoked) SendBuffer (); - if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend (); + if (!m_IsNAcked && !m_IsResendNeeded && !m_IsClientChoked) ScheduleResend (); if (m_IsClientChoked) ScheduleSend (); } From 9c0051e73b9f56013ea613af621a53eab47d6ae5 Mon Sep 17 00:00:00 2001 From: r4sas Date: Wed, 4 Jun 2025 13:49:44 +0300 Subject: [PATCH 05/31] [rpm] fix build on centos 10, drop 7th support Signed-off-by: r4sas --- contrib/rpm/i2pd-git.spec | 34 +++++++++++----------------------- contrib/rpm/i2pd.spec | 34 +++++++++++----------------------- 2 files changed, 22 insertions(+), 46 deletions(-) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index fd431347..d9393f47 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -10,11 +10,7 @@ License: BSD URL: https://github.com/PurpleI2P/i2pd Source0: https://github.com/PurpleI2P/i2pd/archive/openssl/i2pd-openssl.tar.gz -%if 0%{?rhel} == 7 -BuildRequires: cmake3 -%else BuildRequires: cmake -%endif BuildRequires: chrpath BuildRequires: gcc-c++ @@ -43,26 +39,18 @@ C++ implementation of I2P. %build cd build -%if 0%{?rhel} == 7 - %cmake3 \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ - -DBUILD_SHARED_LIBS:BOOL=OFF +%cmake \ + -DWITH_LIBRARY=OFF \ + -DWITH_UPNP=ON \ + -DWITH_HARDENING=ON \ +%if 0%{?fedora} > 29 + -DBUILD_SHARED_LIBS:BOOL=OFF \ + . %else - %cmake \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ - %if 0%{?fedora} > 29 - -DBUILD_SHARED_LIBS:BOOL=OFF \ - . - %else - -DBUILD_SHARED_LIBS:BOOL=OFF - %endif + -DBUILD_SHARED_LIBS:BOOL=OFF %endif -%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln} pushd redhat-linux-build %else %if 0%{?fedora} >= 33 @@ -76,7 +64,7 @@ cd build make %{?_smp_mflags} -%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 popd %endif @@ -84,7 +72,7 @@ make %{?_smp_mflags} %install pushd build -%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln} pushd redhat-linux-build %else %if 0%{?fedora} >= 33 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 2d3d4cbb..e094c3b7 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -8,11 +8,7 @@ License: BSD URL: https://github.com/PurpleI2P/i2pd Source0: https://github.com/PurpleI2P/i2pd/archive/%{version}/%name-%version.tar.gz -%if 0%{?rhel} == 7 -BuildRequires: cmake3 -%else BuildRequires: cmake -%endif BuildRequires: chrpath BuildRequires: gcc-c++ @@ -41,26 +37,18 @@ C++ implementation of I2P. %build cd build -%if 0%{?rhel} == 7 - %cmake3 \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ - -DBUILD_SHARED_LIBS:BOOL=OFF +%cmake \ + -DWITH_LIBRARY=OFF \ + -DWITH_UPNP=ON \ + -DWITH_HARDENING=ON \ +%if 0%{?fedora} > 29 + -DBUILD_SHARED_LIBS:BOOL=OFF \ + . %else - %cmake \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ - %if 0%{?fedora} > 29 - -DBUILD_SHARED_LIBS:BOOL=OFF \ - . - %else - -DBUILD_SHARED_LIBS:BOOL=OFF - %endif + -DBUILD_SHARED_LIBS:BOOL=OFF %endif -%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln} pushd redhat-linux-build %else %if 0%{?fedora} >= 33 @@ -74,7 +62,7 @@ cd build make %{?_smp_mflags} -%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 popd %endif @@ -82,7 +70,7 @@ make %{?_smp_mflags} %install pushd build -%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln} pushd redhat-linux-build %else %if 0%{?fedora} >= 33 From 6363c9202f2e4816215e89548123f3aaee9f73c9 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Jun 2025 11:28:21 -0400 Subject: [PATCH 06/31] drop crypto types higher than ours --- libi2pd/LeaseSet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index fc0e722d..bf07924f 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -417,7 +417,7 @@ namespace data if (keyType <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // skip PQ keys if not supported #endif { - if (keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) + if (keyType == preferredKeyType || !m_Encryptor || (keyType > m_EncryptionType && keyType < preferredKeyType)) { auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); if (encryptor) From 9c393f50da3a8cb1d51af5992d302452d10c2d1a Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Jun 2025 12:06:47 -0400 Subject: [PATCH 07/31] drop crypto types higher than ours --- libi2pd/LeaseSet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index bf07924f..eb337b63 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -417,7 +417,7 @@ namespace data if (keyType <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // skip PQ keys if not supported #endif { - if (keyType == preferredKeyType || !m_Encryptor || (keyType > m_EncryptionType && keyType < preferredKeyType)) + if (keyType <= preferredKeyType && (!m_Encryptor || keyType > m_EncryptionType)) { auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); if (encryptor) From ba0352e9a04e504529ab7ce0a7e40362543463de Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Jun 2025 20:52:35 -0400 Subject: [PATCH 08/31] check for compatibility of LeaseSet encryption keys with local destination's encryption type --- daemon/HTTPServer.cpp | 2 +- libi2pd/Destination.cpp | 9 +++++---- libi2pd/LeaseSet.cpp | 33 +++++++++++++++++++-------------- libi2pd/LeaseSet.h | 30 +++++++++++++++++------------- libi2pd/NetDb.cpp | 2 +- 5 files changed, 43 insertions(+), 33 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index be1ec4ac..167b8c95 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -661,7 +661,7 @@ namespace http { else { ls.reset (new i2p::data::LeaseSet2 (storeType)); - ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), false); + ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), nullptr, false); } if (!ls) return; s << "
second; if (leaseSet->IsNewer (buf + offset, len - offset)) { - leaseSet->Update (buf + offset, len - offset); + leaseSet->Update (buf + offset, len - offset, shared_from_this(), true); if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ()) LogPrint (eLogDebug, "Destination: Remote LeaseSet updated"); else @@ -471,7 +471,8 @@ namespace client else { leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], - buf + offset, len - offset, true, from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2 + buf + offset, len - offset, true, shared_from_this (), + from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2 if (from) { uint8_t pub[32]; @@ -511,8 +512,8 @@ namespace client if (request->requestedBlindedKey) { auto ls2 = std::make_shared (buf + offset, len - offset, - request->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr, - GetPreferredCryptoType ()); + request->requestedBlindedKey, shared_from_this (), + m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr, GetPreferredCryptoType ()); if (ls2->IsValid () && !ls2->IsExpired ()) { leaseSet = ls2; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index eb337b63..3001bdfb 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -36,7 +36,7 @@ namespace data ReadFromBuffer (); } - void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature) + void LeaseSet::Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature) { SetBuffer (buf, len); ReadFromBuffer (false, verifySignature); @@ -281,28 +281,29 @@ namespace data LogPrint (eLogError, "LeaseSet2: Actual buffer size ", int(len) , " exceeds full buffer size ", int(m_BufferLen)); } - LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto): + LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, + bool storeLeases, std::shared_ptr dest, CryptoKeyType preferredCrypto): LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto) { SetBuffer (buf, len); if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) - ReadFromBufferEncrypted (buf, len, nullptr, nullptr); + ReadFromBufferEncrypted (buf, len, nullptr, dest, nullptr); else - ReadFromBuffer (buf, len); + ReadFromBuffer (buf, len, dest); } LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, - const uint8_t * secret, CryptoKeyType preferredCrypto): + std::shared_ptr dest, const uint8_t * secret, CryptoKeyType preferredCrypto): LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto) { - ReadFromBufferEncrypted (buf, len, key, secret); + ReadFromBufferEncrypted (buf, len, key, dest, secret); } - void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature) + void LeaseSet2::Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature) { SetBuffer (buf, len); if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) - ReadFromBuffer (buf, len, false, verifySignature); + ReadFromBuffer (buf, len, dest, false, verifySignature); // TODO: implement encrypted } @@ -312,7 +313,8 @@ namespace data return ExtractPublishedTimestamp (buf, len, expiration) > m_PublishedTimestamp; } - void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature) + void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, std::shared_ptr dest, + bool readIdentity, bool verifySignature) { // standard LS2 header std::shared_ptr identity; @@ -350,7 +352,7 @@ namespace data switch (m_StoreType) { case NETDB_STORE_TYPE_STANDARD_LEASESET2: - s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset); + s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset, dest); break; case NETDB_STORE_TYPE_META_LEASESET2: s = ReadMetaLS2TypeSpecificPart (buf + offset, len - offset); @@ -392,7 +394,8 @@ namespace data return verified; } - size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len) + size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len, + std::shared_ptr dest) { size_t offset = 0; // properties @@ -417,7 +420,8 @@ namespace data if (keyType <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // skip PQ keys if not supported #endif { - if (keyType <= preferredKeyType && (!m_Encryptor || keyType > m_EncryptionType)) + if ((keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) && + (!dest || dest->SupportsEncryptionType (keyType))) { auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); if (encryptor) @@ -498,7 +502,8 @@ namespace data return offset; } - void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret) + void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, + std::shared_ptr key, std::shared_ptr dest, const uint8_t * secret) { size_t offset = 0; // blinded key @@ -601,7 +606,7 @@ namespace data m_StoreType = innerPlainText[0]; SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); // parse and verify Layer 2 - ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); + ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1, dest); } else LogPrint (eLogError, "LeaseSet2: Unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet"); diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index f5197eb5..f6f5f6da 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -76,7 +76,7 @@ namespace data LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true); virtual ~LeaseSet () { delete[] m_EncryptionKey; delete[] m_Buffer; }; - virtual void Update (const uint8_t * buf, size_t len, bool verifySignature = true); + virtual void Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature); virtual bool IsNewer (const uint8_t * buf, size_t len) const; void PopulateLeases (); // from buffer @@ -155,15 +155,17 @@ namespace data public: LeaseSet2 (uint8_t storeType): LeaseSet (true), m_StoreType (storeType) {}; // for update - LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); - LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // store type 5, called from local netdb only - uint8_t GetStoreType () const { return m_StoreType; }; - uint32_t GetPublishedTimestamp () const { return m_PublishedTimestamp; }; + LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, + std::shared_ptr dest = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); + LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, + std::shared_ptr dest = nullptr, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // store type 5, called from local netdb only + uint8_t GetStoreType () const override { return m_StoreType; }; + uint32_t GetPublishedTimestamp () const override { return m_PublishedTimestamp; }; bool IsPublic () const { return m_IsPublic; }; - bool IsPublishedEncrypted () const { return m_IsPublishedEncrypted; }; - std::shared_ptr GetTransientVerifier () const { return m_TransientVerifier; }; - void Update (const uint8_t * buf, size_t len, bool verifySignature); - bool IsNewer (const uint8_t * buf, size_t len) const; + bool IsPublishedEncrypted () const override { return m_IsPublishedEncrypted; }; + std::shared_ptr GetTransientVerifier () const override { return m_TransientVerifier; }; + void Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature) override; + bool IsNewer (const uint8_t * buf, size_t len) const override; // implements RoutingDestination void Encrypt (const uint8_t * data, uint8_t * encrypted) const; @@ -171,15 +173,17 @@ namespace data private: - void ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity = true, bool verifySignature = true); - void ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret); - size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len); + void ReadFromBuffer (const uint8_t * buf, size_t len, std::shared_ptr dest, + bool readIdentity = true, bool verifySignature = true); + void ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr key, + std::shared_ptr dest, const uint8_t * secret); + size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len, std::shared_ptr dest); size_t ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len); template bool VerifySignature (Verifier& verifier, const uint8_t * buf, size_t len, size_t signatureOffset); - uint64_t ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const; + uint64_t ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const override; uint64_t ExtractPublishedTimestamp (const uint8_t * buf, size_t len, uint64_t& expiration) const; size_t ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const; // subcredential is subcredential + timestamp, return length of autData without flag diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index e53738e5..cab40e43 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -361,7 +361,7 @@ namespace data { if(it->second->GetExpirationTime() < expires) { - it->second->Update (buf, len, false); // signature is verified already + it->second->Update (buf, len, nullptr, false); // signature is verified already if (CheckLogLevel (eLogInfo)) LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32()); updated = true; From 46154dabd563852b332d97f98c8b35f960362315 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 8 Jun 2025 07:19:03 -0400 Subject: [PATCH 09/31] fixed warnings --- libi2pd/LeaseSet.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index f6f5f6da..46f40cb5 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -168,8 +168,8 @@ namespace data bool IsNewer (const uint8_t * buf, size_t len) const override; // implements RoutingDestination - void Encrypt (const uint8_t * data, uint8_t * encrypted) const; - CryptoKeyType GetEncryptionType () const { return m_EncryptionType; }; + void Encrypt (const uint8_t * data, uint8_t * encrypted) const override; + CryptoKeyType GetEncryptionType () const override { return m_EncryptionType; }; private: From 4828d93257769536aa6cacfc0013a61748f3385a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Jun 2025 16:05:56 -0400 Subject: [PATCH 10/31] implemented ssu2.firewalled4 and ssu2.firewalled6 params --- libi2pd/Config.cpp | 2 ++ libi2pd/SSU2.cpp | 5 ++++- libi2pd/SSU2.h | 2 ++ libi2pd/SSU2OutOfSession.cpp | 3 +++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 939cd9ff..3d88ff21 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -305,6 +305,8 @@ namespace config { ("ssu2.mtu4", value()->default_value(0), "MTU for ipv4 address (default: detect)") ("ssu2.mtu6", value()->default_value(0), "MTU for ipv6 address (default: detect)") ("ssu2.proxy", value()->default_value(""), "Socks5 proxy URL for SSU2 transport") + ("ssu2.firewalled4", value()->default_value(false), "Set ipv4 network status to Firewalled even if OK (default: disabled)") + ("ssu2.firewalled6", value()->default_value(false), "Set ipv6 network status to Firewalled even if OK (default: disabled)") ; options_description nettime("Time sync options"); diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index fc2355a5..4540b4d2 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -25,7 +25,8 @@ namespace transport m_TerminationTimer (GetService ()), m_CleanupTimer (GetService ()), m_ResendTimer (GetService ()), m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), m_IsPublished (true), m_IsSyncClockFromPeers (true), m_PendingTimeOffset (0), - m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsThroughProxy (false) + m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsForcedFirewalled4 (false), + m_IsForcedFirewalled6 (false), m_IsThroughProxy (false) { } @@ -79,6 +80,7 @@ namespace transport if (address->IsV4 ()) { found = true; + i2p::config::GetOption ("ssu2.firewalled4", m_IsForcedFirewalled4); LogPrint (eLogDebug, "SSU2: Opening IPv4 socket at Start"); OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV4, port)); boost::asio::post (m_ReceiveService.GetService (), @@ -91,6 +93,7 @@ namespace transport if (address->IsV6 ()) { found = true; + i2p::config::GetOption ("ssu2.firewalled6", m_IsForcedFirewalled6); LogPrint (eLogDebug, "SSU2: Opening IPv6 socket at Start"); OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV6, port)); boost::asio::post (m_ReceiveService.GetService (), diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index a8598ce3..b7214480 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -79,6 +79,7 @@ namespace transport bool UsesProxy () const { return m_IsThroughProxy; }; bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; + bool IsForcedFirewalled (bool v4) const { return v4 ? m_IsForcedFirewalled4 : m_IsForcedFirewalled6; } bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true); void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); std::mt19937& GetRng () { return m_Rng; } @@ -208,6 +209,7 @@ namespace transport i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor; i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor; i2p::crypto::ChaCha20Context m_ChaCha20; + bool m_IsForcedFirewalled4, m_IsForcedFirewalled6; // proxy bool m_IsThroughProxy; diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index 3760e329..dc626b16 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -90,6 +90,9 @@ namespace transport if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) { m_PeerTestResendTimer.cancel (); // cancel delayed msg 6 if any + if (GetServer ().IsForcedFirewalled (GetRemoteEndpoint ().address().is_v4())) + // we assume that msg 5 was not received if forced firewalled + return; m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); if (GetAddress ()) { From 660dbd27d1bedfc0c9b0741d68d7c27902ccead1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Jun 2025 21:11:06 -0400 Subject: [PATCH 11/31] use EVP interface for ECDSA signatures if openssl 3 --- libi2pd/Signature.cpp | 174 +++++++++++++++++++++++++++++++++++++++++- libi2pd/Signature.h | 117 ++++++++++++++++++++++++++-- 2 files changed, 285 insertions(+), 6 deletions(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 3e4b451b..aa712c9a 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -10,6 +10,7 @@ #include #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 #include +#include #endif #include "Log.h" #include "Signature.h" @@ -174,7 +175,178 @@ namespace crypto DSA_free (dsa); } #endif - + +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + ECDSAVerifier::ECDSAVerifier (int curve, size_t keyLen, const EVP_MD * hash): + m_Curve(curve), m_KeyLen (keyLen), m_Hash (hash), m_PublicKey (nullptr) + { + } + + ECDSAVerifier::~ECDSAVerifier () + { + if (m_PublicKey) + EVP_PKEY_free (m_PublicKey); + } + + void ECDSAVerifier::SetPublicKey (const uint8_t * signingKey) + { + if (m_PublicKey) + { + EVP_PKEY_free (m_PublicKey); + m_PublicKey = nullptr; + } + auto plen = GetPublicKeyLen (); + std::vector pub(plen + 1); + pub[0] = POINT_CONVERSION_UNCOMPRESSED; + memcpy (pub.data() + 1, signingKey, plen); // 0x04|x|y + OSSL_PARAM_BLD * paramBld = OSSL_PARAM_BLD_new (); + OSSL_PARAM_BLD_push_utf8_string (paramBld, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2ln(m_Curve), 0); + OSSL_PARAM_BLD_push_octet_string (paramBld, OSSL_PKEY_PARAM_PUB_KEY, pub.data (), pub.size ()); + OSSL_PARAM * params = OSSL_PARAM_BLD_to_param(paramBld); + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "EC", NULL); + if (ctx) + { + if (EVP_PKEY_fromdata_init (ctx) <= 0 || + EVP_PKEY_fromdata (ctx, &m_PublicKey, EVP_PKEY_PUBLIC_KEY, params) <= 0) + LogPrint (eLogError, "ECDSA can't create PKEY from params"); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "ECDSA can't create PKEY context"); + + OSSL_PARAM_free (params); + OSSL_PARAM_BLD_free (paramBld); + } + + bool ECDSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const + { + bool ret = false; + EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new (m_PublicKey, NULL); + if (!ctx) + { + LogPrint (eLogError, "ECDSA can't create verification context"); + return false; + } + // digest + unsigned int digestLen = EVP_MD_size(m_Hash); + std::vector digest(digestLen), sign(GetSignatureLen () + 8); + EVP_MD_CTX * mdCtx = EVP_MD_CTX_create (); + EVP_DigestInit (mdCtx, m_Hash); + EVP_DigestUpdate (mdCtx, buf, len); + EVP_DigestFinal (mdCtx, digest.data (), &digestLen); + EVP_MD_CTX_destroy (mdCtx); + // signature + ECDSA_SIG * sig = ECDSA_SIG_new(); + ECDSA_SIG_set0 (sig, BN_bin2bn (signature, GetSignatureLen ()/2, NULL), + BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL)); + // to DER format + uint8_t * s = sign.data (); + auto l = i2d_ECDSA_SIG (sig, &s); + ECDSA_SIG_free(sig); + //verify + if (EVP_PKEY_verify_init (ctx) > 0 && EVP_PKEY_public_check (ctx) > 0) + { + if (EVP_PKEY_CTX_set_signature_md (ctx, m_Hash) > 0) + ret = EVP_PKEY_verify (ctx, sign.data (), l, digest.data (), digestLen); + else + LogPrint (eLogError, "ECDSA can't set signature md"); + } + else + LogPrint (eLogError, "ECDSA invalid public key"); + EVP_PKEY_CTX_free (ctx); + return ret; + } + + ECDSASigner::ECDSASigner (int curve, size_t keyLen, const EVP_MD * hash, const uint8_t * signingPrivateKey): + m_KeyLen (keyLen), m_Hash(hash), m_PrivateKey (nullptr) + { + BIGNUM * priv = BN_bin2bn (signingPrivateKey, keyLen/2, NULL); + OSSL_PARAM_BLD * paramBld = OSSL_PARAM_BLD_new (); + OSSL_PARAM_BLD_push_utf8_string (paramBld, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2ln(curve), 0); + OSSL_PARAM_BLD_push_BN (paramBld, OSSL_PKEY_PARAM_PRIV_KEY, priv); + OSSL_PARAM * params = OSSL_PARAM_BLD_to_param(paramBld); + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "EC", NULL); + if (ctx) + { + if (EVP_PKEY_fromdata_init (ctx) <= 0 || + EVP_PKEY_fromdata (ctx, &m_PrivateKey, EVP_PKEY_KEYPAIR, params) <= 0) + LogPrint (eLogError, "ECDSA can't create PKEY from params"); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "ECDSA can't create PKEY context"); + + OSSL_PARAM_free (params); + OSSL_PARAM_BLD_free (paramBld); + BN_free (priv); + } + + ECDSASigner::~ECDSASigner () + { + if (m_PrivateKey) + EVP_PKEY_free (m_PrivateKey); + } + + void ECDSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const + { + unsigned int digestLen = EVP_MD_size(m_Hash); + std::vector digest(digestLen), sign(m_KeyLen + 8); + EVP_MD_CTX * mdCtx = EVP_MD_CTX_create (); + EVP_DigestInit (mdCtx, m_Hash); + EVP_DigestUpdate (mdCtx, buf, len); + EVP_DigestFinal (mdCtx, digest.data (), &digestLen); + EVP_MD_CTX_destroy (mdCtx); + + EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new (m_PrivateKey, NULL); + if (!ctx) + { + LogPrint (eLogError, "ECDSA can't create signing context"); + return; + } + if (EVP_PKEY_sign_init (ctx) > 0 && EVP_PKEY_private_check (ctx) > 0) + { + if (EVP_PKEY_CTX_set_signature_md (ctx, m_Hash) > 0) + { + size_t l = sign.size (); + EVP_PKEY_sign (ctx, sign.data (), &l, digest.data (), digest.size ()); + const uint8_t * s1 = sign.data (); + ECDSA_SIG * sig = d2i_ECDSA_SIG (NULL, &s1, l); + const BIGNUM * r, * s; + ECDSA_SIG_get0 (sig, &r, &s); + bn2buf (r, signature, m_KeyLen/2); + bn2buf (s, signature + m_KeyLen/2, m_KeyLen/2); + ECDSA_SIG_free(sig); + } + else + LogPrint (eLogError, "ECDSA can't set signature md"); + } + else + LogPrint (eLogError, "ECDSA invalid private key"); + EVP_PKEY_CTX_free (ctx); + } + + void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + EVP_PKEY * pkey = EVP_EC_gen (OBJ_nid2ln(curve)); + // private + BIGNUM * priv = BN_new (); + EVP_PKEY_get_bn_param (pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv); + bn2buf (priv, signingPrivateKey, keyLen/2); + BN_free (priv); + // public + BIGNUM * x = BN_new (), * y = BN_new (); + EVP_PKEY_get_bn_param (pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x); + EVP_PKEY_get_bn_param (pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y); + bn2buf (x, signingPublicKey, keyLen/2); + bn2buf (y, signingPublicKey + keyLen/2, keyLen/2); + BN_free (x); BN_free (y); + EVP_PKEY_free (pkey); + } + +#endif + #if OPENSSL_EDDSA EDDSA25519Verifier::EDDSA25519Verifier (): m_Pkey (nullptr) diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 20c7e11b..bd704738 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -91,7 +91,116 @@ namespace crypto void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey); - // ECDSA + // ECDSA + constexpr size_t ECDSAP256_KEY_LENGTH = 64; + constexpr size_t ECDSAP384_KEY_LENGTH = 96; + constexpr size_t ECDSAP521_KEY_LENGTH = 132; + +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + class ECDSAVerifier: public Verifier + { + public: + + ECDSAVerifier (int curve, size_t keyLen, const EVP_MD * hash); + ~ECDSAVerifier (); + + void SetPublicKey (const uint8_t * signingKey); + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; + + size_t GetPublicKeyLen () const { return m_KeyLen; }; + size_t GetSignatureLen () const { return m_KeyLen; }; // signature length = key length + + private: + + int m_Curve; + size_t m_KeyLen; + const EVP_MD * m_Hash; + EVP_PKEY * m_PublicKey; + }; + + class ECDSASigner: public Signer + { + public: + + ECDSASigner (int curve, size_t keyLen, const EVP_MD * hash, const uint8_t * signingPrivateKey); + ~ECDSASigner (); + + void Sign (const uint8_t * buf, int len, uint8_t * signature) const; + + private: + + size_t m_KeyLen; + const EVP_MD * m_Hash; + EVP_PKEY * m_PrivateKey; + }; + + void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey); + +// ECDSA_SHA256_P256 + class ECDSAP256Verifier: public ECDSAVerifier + { + public: + + ECDSAP256Verifier (): ECDSAVerifier (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, EVP_sha256()) {}; + }; + + class ECDSAP256Signer: public ECDSASigner + { + public: + + ECDSAP256Signer (const uint8_t * signingPrivateKey): + ECDSASigner (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, EVP_sha256(), signingPrivateKey) {}; + }; + + inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey); + } + +// ECDSA_SHA384_P384 + class ECDSAP384Verifier: public ECDSAVerifier + { + public: + + ECDSAP384Verifier (): ECDSAVerifier (NID_secp384r1, ECDSAP384_KEY_LENGTH, EVP_sha384()) {}; + }; + + class ECDSAP384Signer: public ECDSASigner + { + public: + + ECDSAP384Signer (const uint8_t * signingPrivateKey): + ECDSASigner (NID_secp384r1, ECDSAP384_KEY_LENGTH, EVP_sha384(), signingPrivateKey) {}; + }; + + inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey); + } + +// ECDSA_SHA512_P521 + class ECDSAP521Verifier: public ECDSAVerifier + { + public: + + ECDSAP521Verifier (): ECDSAVerifier (NID_secp521r1, ECDSAP521_KEY_LENGTH, EVP_sha512()) {}; + }; + + class ECDSAP521Signer: public ECDSASigner + { + public: + + ECDSAP521Signer (const uint8_t * signingPrivateKey): + ECDSASigner (NID_secp521r1, ECDSAP521_KEY_LENGTH, EVP_sha512(), signingPrivateKey) {}; + }; + + inline void CreateECDSAP521RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); + } + +#else + struct SHA256Hash { static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) @@ -217,7 +326,6 @@ namespace crypto } // ECDSA_SHA256_P256 - const size_t ECDSAP256_KEY_LENGTH = 64; typedef ECDSAVerifier ECDSAP256Verifier; typedef ECDSASigner ECDSAP256Signer; @@ -227,7 +335,6 @@ namespace crypto } // ECDSA_SHA384_P384 - const size_t ECDSAP384_KEY_LENGTH = 96; typedef ECDSAVerifier ECDSAP384Verifier; typedef ECDSASigner ECDSAP384Signer; @@ -237,7 +344,6 @@ namespace crypto } // ECDSA_SHA512_P521 - const size_t ECDSAP521_KEY_LENGTH = 132; typedef ECDSAVerifier ECDSAP521Verifier; typedef ECDSASigner ECDSAP521Signer; @@ -245,7 +351,8 @@ namespace crypto { CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); } - + +#endif // EdDSA class EDDSA25519Verifier: public Verifier From d2296f81ad77bbf1c7742cefe5a1d750e0f6765f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 09:44:55 -0400 Subject: [PATCH 12/31] use EVP functions to extract RSA keys if openssl 3 --- libi2pd/Reseed.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index e58e898b..23dae8ff 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -14,6 +14,9 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 +#include +#endif #include #include "Crypto.h" @@ -480,15 +483,31 @@ namespace data if (terminator) terminator[0] = 0; } // extract RSA key (we need n only, e = 65537) - const RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert)); - const BIGNUM * n, * e, * d; + EVP_PKEY * pubKey = X509_get_pubkey (cert); + const BIGNUM * n = nullptr; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + BIGNUM * n1 = BN_new (); + if (EVP_PKEY_get_bn_param (pubKey, OSSL_PKEY_PARAM_RSA_N, &n1) > 0) + n = n1; +#else + const RSA * key = EVP_PKEY_get0_RSA (pubKey); + const BIGNUM * e, * d; RSA_get0_key(key, &n, &e, &d); - PublicKey value; - i2p::crypto::bn2buf (n, value, 512); - if (cn) - m_SigningKeys[cn] = value; +#endif + if (n) + { + PublicKey value; + i2p::crypto::bn2buf (n, value, 512); + if (cn) + m_SigningKeys[cn] = value; + else + LogPrint (eLogError, "Reseed: Can't find CN field in ", filename); + } else - LogPrint (eLogError, "Reseed: Can't find CN field in ", filename); + LogPrint (eLogError, "Reseed: Can't extract RSA key from ", filename); +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + BN_free (n1); +#endif } SSL_free (ssl); } From 5bef9875292f15c08b9d2155f8b308dbeac70f78 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 11:22:39 -0400 Subject: [PATCH 13/31] stop suporting openssl below 1.1.1 --- libi2pd/Crypto.cpp | 15 --------------- libi2pd/Crypto.h | 14 +++++--------- libi2pd/Signature.cpp | 34 ---------------------------------- libi2pd/Signature.h | 18 ------------------ 4 files changed, 5 insertions(+), 76 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index c41b4c10..94f47ca9 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -16,9 +16,7 @@ #include #include "TunnelBase.h" #include -#if OPENSSL_HKDF #include -#endif #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 #include #include @@ -784,7 +782,6 @@ namespace crypto void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen) { -#if OPENSSL_HKDF EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr); EVP_PKEY_derive_init (pctx); EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256()); @@ -805,18 +802,6 @@ namespace crypto EVP_PKEY_CTX_add1_hkdf_info (pctx, (const uint8_t *)info.c_str (), info.length ()); EVP_PKEY_derive (pctx, out, &outLen); EVP_PKEY_CTX_free (pctx); -#else - uint8_t prk[32]; unsigned int len; - HMAC(EVP_sha256(), salt, 32, key, keyLen, prk, &len); - auto l = info.length (); - memcpy (out, info.c_str (), l); out[l] = 0x01; - HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len); - if (outLen > 32) // 64 - { - memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02; - HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len); - } -#endif } // Noise diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 125a217c..5bf4d534 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -27,15 +27,11 @@ #include "Tag.h" // recognize openssl version and features -#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 -# define OPENSSL_HKDF 1 -# define OPENSSL_EDDSA 1 -# if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL -# define OPENSSL_SIPHASH 1 -# endif -# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 -# define OPENSSL_PQ 1 -# endif +#if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL +# define OPENSSL_SIPHASH 1 +#endif +#if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 +# define OPENSSL_PQ 1 #endif namespace i2p diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index aa712c9a..24374e5b 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -347,7 +347,6 @@ namespace crypto #endif -#if OPENSSL_EDDSA EDDSA25519Verifier::EDDSA25519Verifier (): m_Pkey (nullptr) { @@ -379,37 +378,6 @@ namespace crypto return false; } -#else - EDDSA25519Verifier::EDDSA25519Verifier () - { - } - - EDDSA25519Verifier::~EDDSA25519Verifier () - { - } - - void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey) - { - memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); - BN_CTX * ctx = BN_CTX_new (); - m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx); - BN_CTX_free (ctx); - } - - bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const - { - uint8_t digest[64]; - SHA512_CTX ctx; - SHA512_Init (&ctx); - SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R - SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key - SHA512_Update (&ctx, buf, len); // data - SHA512_Final (digest, &ctx); - - return GetEd25519 ()->Verify (m_PublicKey, digest, signature); - } -#endif - EDDSA25519SignerCompat::EDDSA25519SignerCompat (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) { // expand key @@ -439,7 +407,6 @@ namespace crypto GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature); } -#if OPENSSL_EDDSA EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey): m_Pkey (nullptr), m_Fallback (nullptr) { @@ -481,7 +448,6 @@ namespace crypto else LogPrint (eLogError, "EdDSA signing key is not set"); } -#endif #if (OPENSSL_VERSION_NUMBER >= 0x030000000) static const OSSL_PARAM EDDSA25519phParams[] = diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index bd704738..b1942d0c 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -369,18 +369,12 @@ namespace crypto size_t GetSignatureLen () const { return EDDSA25519_SIGNATURE_LENGTH; }; private: - -#if OPENSSL_EDDSA EVP_PKEY * m_Pkey; protected: EVP_PKEY * GetPkey () const { return m_Pkey; }; -#else - EDDSAPoint m_PublicKey; - uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; -#endif }; #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 @@ -409,7 +403,6 @@ namespace crypto uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; }; -#if OPENSSL_EDDSA class EDDSA25519Signer: public Signer { public: @@ -429,11 +422,6 @@ namespace crypto EVP_PKEY * m_Pkey; EDDSA25519SignerCompat * m_Fallback; }; -#else - - typedef EDDSA25519SignerCompat EDDSA25519Signer; - -#endif #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 class EDDSA25519phSigner: public EDDSA25519Signer @@ -449,7 +437,6 @@ namespace crypto inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { -#if OPENSSL_EDDSA EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_ED25519, NULL); EVP_PKEY_keygen_init (pctx); @@ -460,11 +447,6 @@ namespace crypto len = EDDSA25519_PRIVATE_KEY_LENGTH; EVP_PKEY_get_raw_private_key (pkey, signingPrivateKey, &len); EVP_PKEY_free (pkey); -#else - RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); - EDDSA25519Signer signer (signingPrivateKey); - memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); -#endif } From 5974d2b5ac65222560499d2680880afdb160cc85 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 13:35:47 -0400 Subject: [PATCH 14/31] use EVP_DigestVerify/EVP_DigestSign for ECDSA and DSA signatures if openssl 3 --- libi2pd/Signature.cpp | 108 +++++++++++++----------------------------- 1 file changed, 32 insertions(+), 76 deletions(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 24374e5b..b8cfaf2c 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -42,22 +42,19 @@ namespace crypto bool DSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { - // calculate SHA1 digest - uint8_t digest[20], sign[48]; - SHA1 (buf, len, digest); // signature DSA_SIG * sig = DSA_SIG_new(); DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL)); // to DER format + uint8_t sign[DSA_SIGNATURE_LENGTH + 8]; uint8_t * s = sign; auto l = i2d_DSA_SIG (sig, &s); DSA_SIG_free(sig); // verify - auto ctx = EVP_PKEY_CTX_new (m_PublicKey, NULL); - EVP_PKEY_verify_init(ctx); - EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1()); - bool ret = EVP_PKEY_verify(ctx, sign, l, digest, 20); - EVP_PKEY_CTX_free(ctx); + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestVerifyInit (ctx, NULL, EVP_sha1(), NULL, m_PublicKey); + auto ret = EVP_DigestVerify (ctx, sign, l, buf, len); + EVP_MD_CTX_destroy (ctx); return ret; } @@ -76,13 +73,13 @@ namespace crypto void DSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const { - uint8_t digest[20], sign[48]; - SHA1 (buf, len, digest); - auto ctx = EVP_PKEY_CTX_new (m_PrivateKey, NULL); - EVP_PKEY_sign_init(ctx); - EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1()); - size_t l = 48; - EVP_PKEY_sign(ctx, sign, &l, digest, 20); + uint8_t sign[DSA_SIGNATURE_LENGTH + 8]; + size_t l = DSA_SIGNATURE_LENGTH + 8; + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestSignInit (ctx, NULL, EVP_sha1(), NULL, m_PrivateKey); + EVP_DigestSign (ctx, sign, &l, buf, len); + EVP_MD_CTX_destroy (ctx); + // decode r and s const uint8_t * s1 = sign; DSA_SIG * sig = d2i_DSA_SIG (NULL, &s1, l); const BIGNUM * r, * s; @@ -90,7 +87,6 @@ namespace crypto bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2); bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2); DSA_SIG_free(sig); - EVP_PKEY_CTX_free(ctx); } void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) @@ -221,40 +217,20 @@ namespace crypto bool ECDSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { - bool ret = false; - EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new (m_PublicKey, NULL); - if (!ctx) - { - LogPrint (eLogError, "ECDSA can't create verification context"); - return false; - } - // digest - unsigned int digestLen = EVP_MD_size(m_Hash); - std::vector digest(digestLen), sign(GetSignatureLen () + 8); - EVP_MD_CTX * mdCtx = EVP_MD_CTX_create (); - EVP_DigestInit (mdCtx, m_Hash); - EVP_DigestUpdate (mdCtx, buf, len); - EVP_DigestFinal (mdCtx, digest.data (), &digestLen); - EVP_MD_CTX_destroy (mdCtx); // signature ECDSA_SIG * sig = ECDSA_SIG_new(); ECDSA_SIG_set0 (sig, BN_bin2bn (signature, GetSignatureLen ()/2, NULL), BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL)); // to DER format + std::vector sign(GetSignatureLen () + 8); uint8_t * s = sign.data (); auto l = i2d_ECDSA_SIG (sig, &s); ECDSA_SIG_free(sig); - //verify - if (EVP_PKEY_verify_init (ctx) > 0 && EVP_PKEY_public_check (ctx) > 0) - { - if (EVP_PKEY_CTX_set_signature_md (ctx, m_Hash) > 0) - ret = EVP_PKEY_verify (ctx, sign.data (), l, digest.data (), digestLen); - else - LogPrint (eLogError, "ECDSA can't set signature md"); - } - else - LogPrint (eLogError, "ECDSA invalid public key"); - EVP_PKEY_CTX_free (ctx); + // verify + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestVerifyInit (ctx, NULL, m_Hash, NULL, m_PublicKey); + auto ret = EVP_DigestVerify (ctx, sign.data (), l, buf, len); + EVP_MD_CTX_destroy (ctx); return ret; } @@ -291,40 +267,20 @@ namespace crypto void ECDSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const { - unsigned int digestLen = EVP_MD_size(m_Hash); - std::vector digest(digestLen), sign(m_KeyLen + 8); - EVP_MD_CTX * mdCtx = EVP_MD_CTX_create (); - EVP_DigestInit (mdCtx, m_Hash); - EVP_DigestUpdate (mdCtx, buf, len); - EVP_DigestFinal (mdCtx, digest.data (), &digestLen); - EVP_MD_CTX_destroy (mdCtx); - - EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new (m_PrivateKey, NULL); - if (!ctx) - { - LogPrint (eLogError, "ECDSA can't create signing context"); - return; - } - if (EVP_PKEY_sign_init (ctx) > 0 && EVP_PKEY_private_check (ctx) > 0) - { - if (EVP_PKEY_CTX_set_signature_md (ctx, m_Hash) > 0) - { - size_t l = sign.size (); - EVP_PKEY_sign (ctx, sign.data (), &l, digest.data (), digest.size ()); - const uint8_t * s1 = sign.data (); - ECDSA_SIG * sig = d2i_ECDSA_SIG (NULL, &s1, l); - const BIGNUM * r, * s; - ECDSA_SIG_get0 (sig, &r, &s); - bn2buf (r, signature, m_KeyLen/2); - bn2buf (s, signature + m_KeyLen/2, m_KeyLen/2); - ECDSA_SIG_free(sig); - } - else - LogPrint (eLogError, "ECDSA can't set signature md"); - } - else - LogPrint (eLogError, "ECDSA invalid private key"); - EVP_PKEY_CTX_free (ctx); + std::vector sign(m_KeyLen + 8); + size_t l = sign.size (); + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestSignInit (ctx, NULL, m_Hash, NULL, m_PrivateKey); + EVP_DigestSign (ctx, sign.data(), &l, buf, len); + EVP_MD_CTX_destroy (ctx); + // decode r and s + const uint8_t * s1 = sign.data (); + ECDSA_SIG * sig = d2i_ECDSA_SIG (NULL, &s1, l); + const BIGNUM * r, * s; + ECDSA_SIG_get0 (sig, &r, &s); + bn2buf (r, signature, m_KeyLen/2); + bn2buf (s, signature + m_KeyLen/2, m_KeyLen/2); + ECDSA_SIG_free(sig); } void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) From bb2b34ff4fd186ac55bd3654f265415a1691b7ab Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 16:05:17 -0400 Subject: [PATCH 15/31] check more precise result of EVP_DigestVerify --- libi2pd/Signature.cpp | 10 +++++----- libi2pd/Signature.h | 2 +- tests/test-eddsa.cpp | 2 -- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index b8cfaf2c..cad7d484 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -53,7 +53,7 @@ namespace crypto // verify EVP_MD_CTX * ctx = EVP_MD_CTX_create (); EVP_DigestVerifyInit (ctx, NULL, EVP_sha1(), NULL, m_PublicKey); - auto ret = EVP_DigestVerify (ctx, sign, l, buf, len); + auto ret = EVP_DigestVerify (ctx, sign, l, buf, len) == 1; EVP_MD_CTX_destroy (ctx); return ret; } @@ -132,7 +132,7 @@ namespace crypto DSA_SIG * sig = DSA_SIG_new(); DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL)); // DSA verification - int ret = DSA_do_verify (digest, 20, sig, m_PublicKey); + int ret = DSA_do_verify (digest, 20, sig, m_PublicKey) == 1; DSA_SIG_free(sig); return ret; } @@ -229,7 +229,7 @@ namespace crypto // verify EVP_MD_CTX * ctx = EVP_MD_CTX_create (); EVP_DigestVerifyInit (ctx, NULL, m_Hash, NULL, m_PublicKey); - auto ret = EVP_DigestVerify (ctx, sign.data (), l, buf, len); + auto ret = EVP_DigestVerify (ctx, sign.data (), l, buf, len) == 1; EVP_MD_CTX_destroy (ctx); return ret; } @@ -325,7 +325,7 @@ namespace crypto { EVP_MD_CTX * ctx = EVP_MD_CTX_create (); EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, m_Pkey); - auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len); + auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len) == 1; EVP_MD_CTX_destroy (ctx); return ret; } @@ -509,7 +509,7 @@ namespace crypto OSSL_PARAM_END }; EVP_PKEY_verify_message_init (vctx, sig, params); - ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len); + ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len) == 1; EVP_SIGNATURE_free (sig); } EVP_PKEY_CTX_free (vctx); diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index b1942d0c..43f706bd 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -263,7 +263,7 @@ namespace crypto auto s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL); ECDSA_SIG_set0(sig, r, s); // ECDSA verification - int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey); + int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey) == 1; ECDSA_SIG_free(sig); return ret; } diff --git a/tests/test-eddsa.cpp b/tests/test-eddsa.cpp index b3895e2b..9de2c088 100644 --- a/tests/test-eddsa.cpp +++ b/tests/test-eddsa.cpp @@ -58,9 +58,7 @@ int main () uint8_t s[64]; i2p::crypto::EDDSA25519Signer signer (key); signer.Sign (msg, 1023, s); -#if OPENSSL_EDDSA assert(memcmp (s, sig, 64) == 0); -#endif i2p::crypto::EDDSA25519Verifier verifier; verifier.SetPublicKey (pub); From 06c9a255fb4f5dbb5670f3872f77cb525a0a1211 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 18:58:37 -0400 Subject: [PATCH 16/31] use EVP_DigestSign/EVP_DigestVerify for family signatures --- libi2pd/Family.cpp | 90 ++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index 300a50ab..3a4e8890 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.cpp @@ -51,11 +51,24 @@ namespace data auto pkey = X509_get_pubkey (cert); if (pkey) { - if (!m_SigningKeys.emplace (cn, std::make_pair(pkey, (int)m_SigningKeys.size () + 1)).second) - { - EVP_PKEY_free (pkey); - LogPrint (eLogError, "Family: Duplicated family name ", cn); - } + int curve = 0; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + char groupName[20]; + if (EVP_PKEY_get_group_name(pkey, groupName, sizeof(groupName), NULL) == 1) + curve = OBJ_txt2nid (groupName); + else + curve = -1; +#endif + if (!curve || curve == NID_X9_62_prime256v1) + { + if (!m_SigningKeys.emplace (cn, std::make_pair(pkey, (int)m_SigningKeys.size () + 1)).second) + { + EVP_PKEY_free (pkey); + LogPrint (eLogError, "Family: Duplicated family name ", cn); + } + } + else + LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); } } } @@ -106,11 +119,17 @@ namespace data memcpy (buf + len, (const uint8_t *)ident, 32); len += 32; auto signatureBufLen = Base64ToByteStream (signature, signatureBuf, 64); - if (signatureBufLen) + if (signatureBufLen == 64) { + ECDSA_SIG * sig = ECDSA_SIG_new(); + ECDSA_SIG_set0 (sig, BN_bin2bn (signatureBuf, 32, NULL), BN_bin2bn (signatureBuf + 32, 32, NULL)); + uint8_t sign[72]; + uint8_t * s = sign; + auto l = i2d_ECDSA_SIG (sig, &s); + ECDSA_SIG_free(sig); EVP_MD_CTX * ctx = EVP_MD_CTX_create (); - EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, it->second.first); - auto ret = EVP_DigestVerify (ctx, signatureBuf, signatureBufLen, buf, len); + EVP_DigestVerifyInit (ctx, NULL, EVP_sha256(), NULL, it->second.first); + auto ret = EVP_DigestVerify (ctx, sign, l, buf, len) == 1; EVP_MD_CTX_destroy (ctx); return ret; } @@ -137,29 +156,40 @@ namespace data { SSL * ssl = SSL_new (ctx); EVP_PKEY * pkey = SSL_get_privatekey (ssl); - EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey); - if (ecKey) + int curve = 0; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + char groupName[20]; + if (EVP_PKEY_get_group_name(pkey, groupName, sizeof(groupName), NULL) == 1) + curve = OBJ_txt2nid (groupName); + else + curve = -1; +#endif + if (!curve || curve == NID_X9_62_prime256v1) { - auto group = EC_KEY_get0_group (ecKey); - if (group) - { - int curve = EC_GROUP_get_curve_name (group); - if (curve == NID_X9_62_prime256v1) - { - uint8_t signingPrivateKey[32], buf[50], signature[64]; - i2p::crypto::bn2buf (EC_KEY_get0_private_key (ecKey), signingPrivateKey, 32); - i2p::crypto::ECDSAP256Signer signer (signingPrivateKey); - size_t len = family.length (); - memcpy (buf, family.c_str (), len); - memcpy (buf + len, (const uint8_t *)ident, 32); - len += 32; - signer.Sign (buf, len, signature); - sig = ByteStreamToBase64 (signature, 64); - } - else - LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); - } - } + uint8_t buf[100], sign[72], signature[64]; + size_t len = family.length (); + memcpy (buf, family.c_str (), len); + memcpy (buf + len, (const uint8_t *)ident, 32); + len += 32; + + size_t l = 72; + EVP_MD_CTX * mdctx = EVP_MD_CTX_create (); + EVP_DigestSignInit (mdctx, NULL, EVP_sha256(), NULL, pkey); + EVP_DigestSign (mdctx, sign, &l, buf, len); + EVP_MD_CTX_destroy (mdctx); + + const uint8_t * s1 = sign; + ECDSA_SIG * sig1 = d2i_ECDSA_SIG (NULL, &s1, l); + const BIGNUM * r, * s; + ECDSA_SIG_get0 (sig1, &r, &s); + i2p::crypto::bn2buf (r, signature, 32); + i2p::crypto::bn2buf (s, signature + 32, 32); + ECDSA_SIG_free(sig1); + sig = ByteStreamToBase64 (signature, 64); + } + else + LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); + SSL_free (ssl); } else From 588108d7d0e19516eadbd8f22e16df6a4608d146 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Jun 2025 12:48:25 -0400 Subject: [PATCH 17/31] use EVP_RSA_gen if openssl 3 --- daemon/I2PControl.cpp | 78 +++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 6261a14c..9babce93 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -437,48 +437,54 @@ namespace client void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path) { FILE *f = NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + EVP_PKEY * pkey = EVP_RSA_gen(4096); // e = 65537 +#else EVP_PKEY * pkey = EVP_PKEY_new (); RSA * rsa = RSA_new (); BIGNUM * e = BN_dup (i2p::crypto::GetRSAE ()); RSA_generate_key_ex (rsa, 4096, e, NULL); - BN_free (e); - if (rsa) - { - EVP_PKEY_assign_RSA (pkey, rsa); - X509 * x509 = X509_new (); - ASN1_INTEGER_set (X509_get_serialNumber (x509), 1); - X509_gmtime_adj (X509_getm_notBefore (x509), 0); - X509_gmtime_adj (X509_getm_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration - X509_set_pubkey (x509, pkey); // public key - X509_NAME * name = X509_get_subject_name (x509); - X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"A1", -1, -1, 0); // country (Anonymous proxy) - X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization - X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name - X509_set_issuer_name (x509, name); // set issuer to ourselves - X509_sign (x509, pkey, EVP_sha1 ()); // sign, last param must be NULL for EdDSA - - // save cert - if ((f = fopen (crt_path, "wb")) != NULL) { - LogPrint (eLogInfo, "I2PControl: Saving new cert to ", crt_path); - PEM_write_X509 (f, x509); - fclose (f); - } else { - LogPrint (eLogError, "I2PControl: Can't write cert: ", strerror(errno)); - } - - // save key - if ((f = fopen (key_path, "wb")) != NULL) { - LogPrint (eLogInfo, "I2PControl: saving cert key to ", key_path); - PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL); - fclose (f); - } else { - LogPrint (eLogError, "I2PControl: Can't write key: ", strerror(errno)); - } - - X509_free (x509); - } else { + BN_free (e); + if (rsa) EVP_PKEY_assign_RSA (pkey, rsa); + else + { LogPrint (eLogError, "I2PControl: Can't create RSA key for certificate"); + EVP_PKEY_free (pkey); + return; + } +#endif + X509 * x509 = X509_new (); + ASN1_INTEGER_set (X509_get_serialNumber (x509), 1); + X509_gmtime_adj (X509_getm_notBefore (x509), 0); + X509_gmtime_adj (X509_getm_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration + X509_set_pubkey (x509, pkey); // public key + X509_NAME * name = X509_get_subject_name (x509); + X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"A1", -1, -1, 0); // country (Anonymous proxy) + X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization + X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name + X509_set_issuer_name (x509, name); // set issuer to ourselves + X509_sign (x509, pkey, EVP_sha1 ()); // sign, last param must be NULL for EdDSA + + // save cert + if ((f = fopen (crt_path, "wb")) != NULL) + { + LogPrint (eLogInfo, "I2PControl: Saving new cert to ", crt_path); + PEM_write_X509 (f, x509); + fclose (f); + } + else + LogPrint (eLogError, "I2PControl: Can't write cert: ", strerror(errno)); + X509_free (x509); + + // save key + if ((f = fopen (key_path, "wb")) != NULL) + { + LogPrint (eLogInfo, "I2PControl: saving cert key to ", key_path); + PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL); + fclose (f); } + else + LogPrint (eLogError, "I2PControl: Can't write key: ", strerror(errno)); EVP_PKEY_free (pkey); } } From 61588777beb8b2bc3865476ee8670ddb93572c64 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Jun 2025 08:06:34 -0400 Subject: [PATCH 18/31] set default transit tunnels limit to 10000 --- contrib/i2pd.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index c26f8af0..fa6b1f8b 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -246,9 +246,9 @@ verify = true # subscriptions = http://reg.i2p/hosts.txt,http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt [limits] -## Maximum active transit sessions (default: 5000) +## Maximum active transit sessions (default: 10000) ## This value is doubled if floodfill mode is enabled! -# transittunnels = 5000 +# transittunnels = 10000 ## Limit number of open file descriptors (0 - use system limit) # openfiles = 0 ## Maximum size of corefile in Kb (0 - use system limit) From 5f0262ea2f60cf50dc600929ae6db738a0a19020 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jun 2025 13:19:49 -0400 Subject: [PATCH 19/31] use EVP_Digest_ insted deprecated SHA512_ functions --- libi2pd/Ed25519.cpp | 56 ++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 47edb755..55d7711d 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -1,12 +1,12 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * * See full license text in LICENSE file at top of project tree */ -#include +#include #include "Log.h" #include "Crypto.h" #include "Ed25519.h" @@ -134,22 +134,27 @@ namespace crypto { BN_CTX * bnCtx = BN_CTX_new (); // calculate r - SHA512_CTX ctx; - SHA512_Init (&ctx); - SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key - SHA512_Update (&ctx, buf, len); // data + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestInit_ex (ctx, EVP_sha512(), NULL); + EVP_DigestUpdate (ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key + EVP_DigestUpdate (ctx, buf, len); // data uint8_t digest[64]; - SHA512_Final (digest, &ctx); + unsigned int dl = 64; + EVP_DigestFinal_ex (ctx, digest, &dl); + EVP_MD_CTX_destroy (ctx); BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors // calculate R uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors // calculate S - SHA512_Init (&ctx); - SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R - SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key - SHA512_Update (&ctx, buf, len); // data - SHA512_Final (digest, &ctx); + ctx = EVP_MD_CTX_create (); + EVP_DigestInit_ex (ctx, EVP_sha512(), NULL); + EVP_DigestUpdate (ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R + EVP_DigestUpdate (ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key + EVP_DigestUpdate (ctx, buf, len); // data + dl = 64; + EVP_DigestFinal_ex (ctx, digest, &dl); + EVP_MD_CTX_destroy (ctx); BIGNUM * h = DecodeBN<64> (digest); // S = (r + h*a) % l BIGNUM * a = DecodeBN (expandedPrivateKey); // left half of expanded key @@ -169,13 +174,15 @@ namespace crypto uint8_t T[80]; RAND_bytes (T, 80); // calculate r = H*(T || publickey || data) - SHA512_CTX ctx; - SHA512_Init (&ctx); - SHA512_Update (&ctx, T, 80); - SHA512_Update (&ctx, publicKeyEncoded, 32); - SHA512_Update (&ctx, buf, len); // data + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestInit_ex (ctx, EVP_sha512(), NULL); + EVP_DigestUpdate (ctx, T, 80); + EVP_DigestUpdate (ctx, publicKeyEncoded, 32); + EVP_DigestUpdate (ctx, buf, len); // data uint8_t digest[64]; - SHA512_Final (digest, &ctx); + unsigned int dl = 64; + EVP_DigestFinal_ex (ctx, digest, &dl); + EVP_MD_CTX_destroy (ctx); BIGNUM * r = DecodeBN<64> (digest); BN_mod (r, r, l, bnCtx); // % l EncodeBN (r, digest, 32); @@ -183,11 +190,14 @@ namespace crypto uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // calculate S - SHA512_Init (&ctx); - SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R - SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key - SHA512_Update (&ctx, buf, len); // data - SHA512_Final (digest, &ctx); + ctx = EVP_MD_CTX_create (); + EVP_DigestInit_ex (ctx, EVP_sha512(), NULL); + EVP_DigestUpdate (ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R + EVP_DigestUpdate (ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key + EVP_DigestUpdate (ctx, buf, len); // data + dl = 64; + EVP_DigestFinal_ex (ctx, digest, &dl); + EVP_MD_CTX_destroy (ctx); BIGNUM * h = DecodeBN<64> (digest); // S = (r + h*a) % l BIGNUM * a = DecodeBN (privateKey); From 78357c23d22f8a62290b02f745e97f9e987cb166 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jun 2025 20:39:48 -0400 Subject: [PATCH 20/31] 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: From a6bf6baf1ba8ebecda82001fdcab0d1422caded4 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Jun 2025 18:32:43 -0400 Subject: [PATCH 21/31] don't verify signature for SYN-ACK if comes from ECIESx25519 session --- libi2pd/Streaming.cpp | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index cb401b06..ae14a38d 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -412,26 +412,21 @@ namespace stream if (!m_RemoteLeaseSet) { 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 + if (packet->from) // try to obtain LeaseSet if came from ratchets session 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 (packet->from && m_RemoteLeaseSet) + { + // stream came from ratchets session and static key must match one from LeaseSet + 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 stream from ", + m_RemoteIdentity->GetIdentHash ().ToBase32 ()); + return false; } + sessionVerified = true; } } From 6b519c36c5f1f2f47286d9625af4a37760478fcf Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 20 Jun 2025 13:34:20 -0400 Subject: [PATCH 22/31] increased number of floodfills threshold --- libi2pd/NetDb.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index f2a7019b..8d17628f 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -41,7 +41,7 @@ namespace data const int NETDB_MIN_ROUTERS = 90; const int NETDB_MIN_FLOODFILLS = 5; const int NETDB_MIN_TRANSPORTS = 10 ; // otherwise assume offline - const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200; + const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1500; const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD; const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in % const int NETDB_CHECK_FOR_EXPIRATION_UPTIME = 600; // 10 minutes, in seconds From 9efdc230a912f51fafe577d4a2cb91d216870685 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Jun 2025 22:07:59 -0400 Subject: [PATCH 23/31] don't check destination if first packet comes from ECIESx25519 session --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index ae14a38d..e2790288 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -187,7 +187,7 @@ namespace stream if (!m_SendStreamID) { m_SendStreamID = packet->GetReceiveStreamID (); - if (!m_RemoteIdentity && packet->GetNACKCount () == 8 && // first incoming packet + if (!m_RemoteIdentity && !packet->from && packet->GetNACKCount () == 8 && // first incoming packet memcmp (packet->GetNACKs (), m_LocalDestination.GetOwner ()->GetIdentHash (), 32)) { LogPrint (eLogWarning, "Streaming: Destination mismatch for ", m_LocalDestination.GetOwner ()->GetIdentHash ().ToBase32 ()); From 75dd0d72c66c9c86d71ee6efbd2b58103bea7589 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Jun 2025 21:53:44 -0400 Subject: [PATCH 24/31] skip transient signature verification if verified through ECIESx25519 session --- libi2pd/Streaming.cpp | 47 +++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index e2790288..66c8919d 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -444,27 +444,44 @@ namespace stream LogPrint (eLogInfo, "Streaming: offline signature without identity"); return false; } - // if we have it in LeaseSet already we don't need to parse it again - if (m_RemoteLeaseSet) m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier (); - if (m_TransientVerifier) + if (sessionVerified) { - // skip option data - optionData += 6; // timestamp and key type - optionData += m_TransientVerifier->GetPublicKeyLen (); // public key + // skip offline signature + optionData += 4; // timestamp + uint16_t keyType = bufbe16toh (optionData); optionData += 2; // key type + std::unique_ptr transientVerifier (i2p::data::IdentityEx::CreateVerifier (keyType)); + if (!transientVerifier) + { + LogPrint (eLogInfo, "Streaming: Unknown offline signature key type ", (int)keyType); + return false; + } + optionData += transientVerifier->GetPublicKeyLen (); // public key optionData += m_RemoteIdentity->GetSignatureLen (); // signature } else - { - // transient key - size_t offset = 0; - m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset); - optionData += offset; - if (!m_TransientVerifier) + { + // if we have it in LeaseSet already we don't need to parse it again + if (m_RemoteLeaseSet) m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier (); + if (m_TransientVerifier) { - LogPrint (eLogError, "Streaming: offline signature failed"); - return false; + // skip option data + optionData += 6; // timestamp and key type + optionData += m_TransientVerifier->GetPublicKeyLen (); // public key + optionData += m_RemoteIdentity->GetSignatureLen (); // signature } - } + else + { + // transient key + size_t offset = 0; + m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset); + optionData += offset; + if (!m_TransientVerifier) + { + LogPrint (eLogError, "Streaming: offline signature failed"); + return false; + } + } + } } if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) From 40b90ccea4750f579b02289fae0a6fbce3e9eb48 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Jun 2025 18:00:02 -0400 Subject: [PATCH 25/31] recognize and verify datagram3 --- libi2pd/Datagram.cpp | 52 +++++++++++++++++++++++++++++++++++++---- libi2pd/Datagram.h | 12 ++++++---- libi2pd/Destination.cpp | 12 ++++------ libi2pd/Destination.h | 2 ++ 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 732efca7..1903f7ae 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -126,6 +126,34 @@ namespace datagram LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram"); } + void DatagramDestination::HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) + { + if (from) + { + i2p::data::IdentHash ident(buf); + auto ls = m_Owner->FindLeaseSet (ident); + if (ls) + { + uint8_t staticKey[32]; + ls->Encrypt (nullptr, staticKey); + if (!memcmp (from->GetRemoteStaticKey (), staticKey, 32)) + { + auto session = ObtainSession (ident); + session->SetRemoteLeaseSet (ls); + session->Ack (); + // TODO: + } + else + LogPrint (eLogError, "Datagram: Remote LeaseSet static key mismatch for datagram3 from ", ident.ToBase32 ()); + } + else + LogPrint (eLogError, "Datagram: No remote LeaseSet for ", ident.ToBase32 ()); + } + else + LogPrint (eLogInfo, "Datagram: datagram3 received from non-ratchets session"); + } + void DatagramDestination::SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard lock(m_ReceiversMutex); @@ -194,17 +222,31 @@ namespace datagram return r; } - void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw) + void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, uint8_t protocolType, i2p::garlic::ECIESX25519AEADRatchetSession * from) { // unzip it uint8_t uncompressed[MAX_DATAGRAM_SIZE]; size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE); if (uncompressedLen) { - if (isRaw) - HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen); - else - HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); + switch (protocolType) + { + case i2p::client::PROTOCOL_TYPE_RAW: + HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen); + break; + case i2p::client::PROTOCOL_TYPE_DATAGRAM3: + HandleDatagram3 (fromPort, toPort, uncompressed, uncompressedLen, from); + break; + case i2p::client::PROTOCOL_TYPE_DATAGRAM: + HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); + break; + case i2p::client::PROTOCOL_TYPE_DATAGRAM2: + // TODO: + break; + default: + LogPrint (eLogInfo, "Datagram: unknown protocol type ", protocolType); + }; } else LogPrint (eLogWarning, "Datagram: decompression failed"); diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index dd358434..d68bdd07 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -20,6 +20,7 @@ #include "LeaseSet.h" #include "I2NPProtocol.h" #include "Garlic.h" +#include "ECIESX25519AEADRatchetSession.h" namespace i2p { @@ -64,8 +65,9 @@ namespace datagram /** get the last time in milliseconds for when we used this datagram session */ uint64_t LastActivity() const { return m_LastUse; } - bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); } - + bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); } + void SetRemoteLeaseSet (std::shared_ptr ls) { m_RemoteLeaseSet = ls; } + struct Info { std::shared_ptr IBGW; @@ -124,8 +126,8 @@ namespace datagram void SendRawDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void FlushSendQueue (std::shared_ptr session); - void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); - + void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, uint8_t protocolType, i2p::garlic::ECIESX25519AEADRatchetSession * from); void SetReceiver (const Receiver& receiver, uint16_t port); void ResetReceiver (uint16_t port); @@ -147,6 +149,8 @@ namespace datagram void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from); Receiver FindReceiver(uint16_t port); RawReceiver FindRawReceiver(uint16_t port); diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index e1ccbc92..4ce825a6 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1190,19 +1190,15 @@ namespace client } break; case PROTOCOL_TYPE_DATAGRAM: + case PROTOCOL_TYPE_RAW: + case PROTOCOL_TYPE_DATAGRAM2: + case PROTOCOL_TYPE_DATAGRAM3: // datagram protocol if (m_DatagramDestination) - m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length); + m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, buf[9], from); else LogPrint (eLogError, "Destination: Missing datagram destination"); break; - case PROTOCOL_TYPE_RAW: - // raw datagram - if (m_DatagramDestination) - m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, true); - else - LogPrint (eLogError, "Destination: Missing raw datagram destination"); - break; default: LogPrint (eLogError, "Destination: Data: Unexpected protocol ", buf[9]); } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index f2bef491..717f35ce 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -37,6 +37,8 @@ namespace client const uint8_t PROTOCOL_TYPE_STREAMING = 6; const uint8_t PROTOCOL_TYPE_DATAGRAM = 17; const uint8_t PROTOCOL_TYPE_RAW = 18; + const uint8_t PROTOCOL_TYPE_DATAGRAM2 = 19; + const uint8_t PROTOCOL_TYPE_DATAGRAM3 = 20; const int PUBLISH_CONFIRMATION_TIMEOUT = 1800; // in milliseconds const int PUBLISH_VERIFICATION_TIMEOUT = 5; // in seconds after successful publish const int PUBLISH_VERIFICATION_TIMEOUT_VARIANCE = 3; // in seconds From 8c89c8368af4d8739024956f5d63096f2e6f637b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Jun 2025 22:06:36 -0400 Subject: [PATCH 26/31] handle Datagram3 --- libi2pd/Datagram.cpp | 22 +++++++++++++++++++++- libi2pd/Datagram.h | 2 ++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 1903f7ae..de4b5674 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -129,6 +129,11 @@ namespace datagram void DatagramDestination::HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) { + if (len < 34) + { + LogPrint (eLogWarning, "Datagram: datagram3 is too short ", len); + return; + } if (from) { i2p::data::IdentHash ident(buf); @@ -142,7 +147,22 @@ namespace datagram auto session = ObtainSession (ident); session->SetRemoteLeaseSet (ls); session->Ack (); - // TODO: + auto r = FindReceiver(toPort); + if (r) + { + uint16_t flags = bufbe16toh (buf + 32); + size_t offset = 34; + if (flags & DATAGRAM3_FLAG_OPTIONS) + offset += bufbe16toh (buf + offset) + 2; + if (offset > len) + { + LogPrint (eLogWarning, "Datagram: datagram3 is too short ", len, " expected ", offset); + return; + } + r(*ls->GetIdentity (), fromPort, toPort, buf + offset, len - offset); + } + else + LogPrint (eLogWarning, "Datagram: no receiver for port ", toPort); } else LogPrint (eLogError, "Datagram: Remote LeaseSet static key mismatch for datagram3 from ", ident.ToBase32 ()); diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index d68bdd07..a293c84b 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -45,6 +45,8 @@ namespace datagram const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds const int DATAGRAM_SESSION_ACK_REQUEST_INTERVAL = 5500; // in milliseconds + constexpr uint16_t DATAGRAM3_FLAG_OPTIONS = 0x10; + class DatagramSession : public std::enable_shared_from_this { From 31b6f07b788e6813ca128149cb25878f2edef72c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 Jun 2025 18:01:03 -0400 Subject: [PATCH 27/31] set ECIESx25519 session's destination from LeaseSet --- libi2pd/Destination.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 4ce825a6..394435c5 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -489,7 +489,9 @@ namespace client if (leaseSet->GetIdentHash () != GetIdentHash ()) { LogPrint (eLogDebug, "Destination: New remote LeaseSet added"); - m_RemoteLeaseSets[key] = leaseSet; + m_RemoteLeaseSets.insert_or_assign (key, leaseSet); + if (from) + from->SetDestination (key); } else LogPrint (eLogDebug, "Destination: Own remote LeaseSet dropped"); From 0445a5d775ec9c5cfb140baef5e47d393826ac16 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Jun 2025 15:47:19 -0400 Subject: [PATCH 28/31] send actual version in SetDate --- libi2pd_client/I2CP.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index f2e9be57..5603697d 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -624,17 +624,14 @@ namespace client void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len) { - // get version - auto version = ExtractString (buf, len); - auto l = version.length () + 1 + 8; - uint8_t * payload = new uint8_t[l]; + constexpr std::string_view version(I2P_VERSION); + std::array payload; // set date auto ts = i2p::util::GetMillisecondsSinceEpoch (); - htobe64buf (payload, ts); - // echo vesrion back - PutString (payload + 8, l - 8, version); - SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload, l); - delete[] payload; + htobe64buf (payload.data(), ts); + // send our version back + PutString (payload.data() + 8, payload.size() - 8, version); + SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload.data(), payload.size()); } void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len) From f230c110aa25bebe63be175ccb9825c8d6bfa0bf Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Jun 2025 15:49:42 -0400 Subject: [PATCH 29/31] send actual version in SetDate --- libi2pd_client/I2CP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 5603697d..85c58c48 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -625,7 +625,7 @@ namespace client void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len) { constexpr std::string_view version(I2P_VERSION); - std::array payload; + std::array payload; // set date auto ts = i2p::util::GetMillisecondsSinceEpoch (); htobe64buf (payload.data(), ts); From a5631bd1b5169a8fd60fc30ddfc8b18cf8bb6e50 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Jun 2025 15:57:17 -0400 Subject: [PATCH 30/31] send Datagram3 --- libi2pd/Datagram.cpp | 38 ++++++++++++++++++++++++-------------- libi2pd/Datagram.h | 13 ++++++++++++- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index de4b5674..2f3d5eef 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -58,25 +58,35 @@ namespace datagram { if (session) { - if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + if (session->GetVersion () == eDatagramV3) { - uint8_t hash[32]; - SHA256(payload, len, hash); - m_Owner->Sign (hash, 32, m_Signature.data ()); + constexpr uint8_t flags[] = { 0x00, 0x03 }; // datagram3, no options + auto msg = CreateDataMessage ({{m_Owner->GetIdentity ()->GetIdentHash (), 32}, + {flags, 2}, {payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM3, false); // datagram3 + session->SendMsg(msg); } else - m_Owner->Sign (payload, len, m_Signature.data ()); + { + if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + { + uint8_t hash[32]; + SHA256(payload, len, hash); + m_Owner->Sign (hash, 32, m_Signature.data ()); + } + else + m_Owner->Sign (payload, len, m_Signature.data ()); - auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}}, - fromPort, toPort, false, !session->IsRatchets ()); // datagram - session->SendMsg(msg); + auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}}, + fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM, !session->IsRatchets ()); // datagram1 + session->SendMsg(msg); + } } } void DatagramDestination::SendRawDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort) { if (session) - session->SendMsg(CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ())); // raw + session->SendMsg(CreateDataMessage ({{payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_RAW, !session->IsRatchets ())); // raw } void DatagramDestination::FlushSendQueue (std::shared_ptr session) @@ -145,6 +155,7 @@ namespace datagram if (!memcmp (from->GetRemoteStaticKey (), staticKey, 32)) { auto session = ObtainSession (ident); + session->SetVersion (eDatagramV3); session->SetRemoteLeaseSet (ls); session->Ack (); auto r = FindReceiver(toPort); @@ -274,7 +285,7 @@ namespace datagram std::shared_ptr DatagramDestination::CreateDataMessage ( const std::vector >& payloads, - uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum) + uint16_t fromPort, uint16_t toPort, uint8_t protocolType, bool checksum) { size_t size; auto msg = m_I2NPMsgsPool.AcquireShared (); @@ -290,8 +301,8 @@ namespace datagram { htobe32buf (msg->GetPayload (), size); // length htobe16buf (buf + 4, fromPort); // source port - htobe16buf (buf + 6, toPort); // destination port - buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol + htobe16buf (buf + 6, toPort); // destination port + buf[9] = protocolType; // raw or datagram protocol msg->len += size + 4; msg->FillI2NPMessageHeader (eI2NPData, 0, checksum); } @@ -350,8 +361,7 @@ namespace datagram DatagramSession::DatagramSession(std::shared_ptr localDestination, const i2p::data::IdentHash & remoteIdent) : m_LocalDestination(localDestination), m_RemoteIdent(remoteIdent), - m_LastUse (0), m_LastFlush (0), - m_RequestingLS(false) + m_LastUse (0), m_LastFlush (0), m_RequestingLS (false), m_Version (eDatagramV1) { } diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index a293c84b..a6fc130d 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -45,6 +45,13 @@ namespace datagram const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds const int DATAGRAM_SESSION_ACK_REQUEST_INTERVAL = 5500; // in milliseconds + enum DatagramVersion + { + eDatagramV1 = 1, + eDatagramV2 = 2, + eDatagramV3 = 3, + }; + constexpr uint16_t DATAGRAM3_FLAG_OPTIONS = 0x10; class DatagramSession : public std::enable_shared_from_this @@ -69,6 +76,9 @@ namespace datagram bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); } void SetRemoteLeaseSet (std::shared_ptr ls) { m_RemoteLeaseSet = ls; } + + DatagramVersion GetVersion () const { return m_Version; } + void SetVersion (DatagramVersion version) { m_Version = version; } struct Info { @@ -104,6 +114,7 @@ namespace datagram std::vector > m_SendQueue; uint64_t m_LastUse, m_LastFlush; // milliseconds bool m_RequestingLS; + DatagramVersion m_Version; }; typedef std::shared_ptr DatagramSession_ptr; @@ -147,7 +158,7 @@ namespace datagram std::shared_ptr ObtainSession(const i2p::data::IdentHash & ident); std::shared_ptr CreateDataMessage (const std::vector >& payloads, - uint16_t fromPort, uint16_t toPort, bool isRaw = false, bool checksum = true); + uint16_t fromPort, uint16_t toPort, uint8_t protocolType, bool checksum = true); void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); From 1a6051e79b811fcb9313af43db563e43969fc45f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 3 Jul 2025 20:40:39 -0400 Subject: [PATCH 31/31] don't verify signature of Datagram1 if comes from ECIESx25519 session --- libi2pd/Datagram.cpp | 42 +++++++++++++++++++++++++++++++++--------- libi2pd/Datagram.h | 3 ++- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 2f3d5eef..029ab42d 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -95,26 +95,50 @@ namespace datagram session->FlushSendQueue (); } - void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len) + void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) { i2p::data::IdentityEx identity; size_t identityLen = identity.FromBuffer (buf, len); + if (!identityLen) return; const uint8_t * signature = buf + identityLen; size_t headerLen = identityLen + identity.GetSignatureLen (); + std::shared_ptr ls; bool verified = false; - if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + if (from) { - uint8_t hash[32]; - SHA256(buf + headerLen, len - headerLen, hash); - verified = identity.Verify (hash, 32, signature); - } - else - verified = identity.Verify (buf + headerLen, len - headerLen, signature); + ls = m_Owner->FindLeaseSet (identity.GetIdentHash ()); + if (ls) + { + uint8_t staticKey[32]; + ls->Encrypt (nullptr, staticKey); + if (!memcmp (from->GetRemoteStaticKey (), staticKey, 32)) + verified = true; + else + { + LogPrint (eLogError, "Datagram: Remote LeaseSet static key mismatch for datagram from ", + identity.GetIdentHash ().ToBase32 ()); + return; + } + } + } + if (!verified) + { + if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + { + uint8_t hash[32]; + SHA256(buf + headerLen, len - headerLen, hash); + verified = identity.Verify (hash, 32, signature); + } + else + verified = identity.Verify (buf + headerLen, len - headerLen, signature); + } if (verified) { auto session = ObtainSession (identity.GetIdentHash()); + if (ls) session->SetRemoteLeaseSet (ls); session->Ack(); auto r = FindReceiver(toPort); if(r) @@ -270,7 +294,7 @@ namespace datagram HandleDatagram3 (fromPort, toPort, uncompressed, uncompressedLen, from); break; case i2p::client::PROTOCOL_TYPE_DATAGRAM: - HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); + HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen, from); break; case i2p::client::PROTOCOL_TYPE_DATAGRAM2: // TODO: diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index a6fc130d..4ff2ef00 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -160,7 +160,8 @@ namespace datagram std::shared_ptr CreateDataMessage (const std::vector >& payloads, uint16_t fromPort, uint16_t toPort, uint8_t protocolType, bool checksum = true); - void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); + void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from); void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from);