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)
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
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 << "
= 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);
}
}
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/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 80650098..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/Datagram.cpp b/libi2pd/Datagram.cpp
index 732efca7..029ab42d 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)
@@ -85,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)
@@ -126,6 +160,55 @@ 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 (len < 34)
+ {
+ LogPrint (eLogWarning, "Datagram: datagram3 is too short ", len);
+ return;
+ }
+ 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->SetVersion (eDatagramV3);
+ session->SetRemoteLeaseSet (ls);
+ session->Ack ();
+ 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 ());
+ }
+ 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 +277,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, from);
+ break;
+ case i2p::client::PROTOCOL_TYPE_DATAGRAM2:
+ // TODO:
+ break;
+ default:
+ LogPrint (eLogInfo, "Datagram: unknown protocol type ", protocolType);
+ };
}
else
LogPrint (eLogWarning, "Datagram: decompression failed");
@@ -212,7 +309,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 ();
@@ -228,8 +325,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);
}
@@ -288,8 +385,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 dd358434..4ff2ef00 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
{
@@ -44,6 +45,15 @@ 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
{
@@ -64,8 +74,12 @@ 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; }
+ DatagramVersion GetVersion () const { return m_Version; }
+ void SetVersion (DatagramVersion version) { m_Version = version; }
+
struct Info
{
std::shared_ptr IBGW;
@@ -100,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;
@@ -124,8 +139,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);
@@ -143,10 +158,13 @@ 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 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);
Receiver FindReceiver(uint16_t port);
RawReceiver FindRawReceiver(uint16_t port);
diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp
index b243ba0a..394435c5 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));
@@ -450,7 +450,7 @@ namespace client
leaseSet = it->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];
@@ -488,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");
@@ -511,8 +514,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;
@@ -1157,7 +1160,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)
@@ -1182,25 +1186,21 @@ 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");
}
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 35557859..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
@@ -174,7 +176,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 +290,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/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);
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
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++;
diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp
index fc0e722d..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..46f40cb5 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,31 +155,35 @@ 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;
- 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:
- 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;
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
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);
}
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 ())
{
diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp
index 3e4b451b..cad7d484 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"
@@ -41,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) == 1;
+ EVP_MD_CTX_destroy (ctx);
return ret;
}
@@ -75,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;
@@ -89,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)
@@ -135,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;
}
@@ -174,8 +171,138 @@ namespace crypto
DSA_free (dsa);
}
#endif
-
-#if OPENSSL_EDDSA
+
+#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
+ {
+ // 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
+ 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) == 1;
+ EVP_MD_CTX_destroy (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
+ {
+ 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)
+ {
+ 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
+
EDDSA25519Verifier::EDDSA25519Verifier ():
m_Pkey (nullptr)
{
@@ -198,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;
}
@@ -207,37 +334,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
@@ -267,7 +363,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)
{
@@ -309,7 +404,6 @@ namespace crypto
else
LogPrint (eLogError, "EdDSA signing key is not set");
}
-#endif
#if (OPENSSL_VERSION_NUMBER >= 0x030000000)
static const OSSL_PARAM EDDSA25519phParams[] =
@@ -415,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 20c7e11b..43f706bd 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)
@@ -154,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;
}
@@ -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
@@ -262,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
@@ -302,7 +403,6 @@ namespace crypto
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
};
-#if OPENSSL_EDDSA
class EDDSA25519Signer: public Signer
{
public:
@@ -322,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
@@ -342,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);
@@ -353,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
}
diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp
index 1f849925..66c8919d 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 ());
@@ -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,24 @@ 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) // try to obtain LeaseSet if came from ratchets session
+ m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
+ }
+ 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;
+ }
}
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
@@ -426,60 +444,81 @@ 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)
{
- 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 +851,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);
@@ -1416,6 +1455,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 +1578,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 ();
}
@@ -2053,14 +2093,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..85c58c48 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;
@@ -623,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)
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:
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);
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);