diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index fa6b1f8b..c26f8af0 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: 10000) +## Maximum active transit sessions (default: 5000) ## This value is doubled if floodfill mode is enabled! -# transittunnels = 10000 +# transittunnels = 5000 ## 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 d9393f47..fd431347 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -10,7 +10,11 @@ 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++ @@ -39,18 +43,26 @@ C++ implementation of I2P. %build cd build -%cmake \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ -%if 0%{?fedora} > 29 - -DBUILD_SHARED_LIBS:BOOL=OFF \ - . +%if 0%{?rhel} == 7 + %cmake3 \ + -DWITH_LIBRARY=OFF \ + -DWITH_UPNP=ON \ + -DWITH_HARDENING=ON \ + -DBUILD_SHARED_LIBS:BOOL=OFF %else - -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 + -DBUILD_SHARED_LIBS:BOOL=OFF + %endif %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 @@ -64,7 +76,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 @@ -72,7 +84,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 e094c3b7..2d3d4cbb 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -8,7 +8,11 @@ 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++ @@ -37,18 +41,26 @@ C++ implementation of I2P. %build cd build -%cmake \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ -%if 0%{?fedora} > 29 - -DBUILD_SHARED_LIBS:BOOL=OFF \ - . +%if 0%{?rhel} == 7 + %cmake3 \ + -DWITH_LIBRARY=OFF \ + -DWITH_UPNP=ON \ + -DWITH_HARDENING=ON \ + -DBUILD_SHARED_LIBS:BOOL=OFF %else - -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 + -DBUILD_SHARED_LIBS:BOOL=OFF + %endif %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 @@ -62,7 +74,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 @@ -70,7 +82,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 167b8c95..be1ec4ac 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(), nullptr, false); + ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), 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); - 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 + 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)); - 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); + // 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 { + LogPrint (eLogError, "I2PControl: Can't create RSA key for certificate"); } - 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 3d88ff21..939cd9ff 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -305,8 +305,6 @@ 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 94f47ca9..c41b4c10 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -16,7 +16,9 @@ #include #include "TunnelBase.h" #include +#if OPENSSL_HKDF #include +#endif #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 #include #include @@ -782,6 +784,7 @@ 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()); @@ -802,6 +805,18 @@ 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 5bf4d534..80650098 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -27,11 +27,15 @@ #include "Tag.h" // recognize openssl version and features -#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 +#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 #endif namespace i2p diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 029ab42d..732efca7 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -58,35 +58,25 @@ namespace datagram { if (session) { - if (session->GetVersion () == eDatagramV3) + if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) { - 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); + uint8_t hash[32]; + SHA256(payload, len, hash); + m_Owner->Sign (hash, 32, m_Signature.data ()); } else - { - 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 ()); + 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, i2p::client::PROTOCOL_TYPE_DATAGRAM, !session->IsRatchets ()); // datagram1 - session->SendMsg(msg); - } + 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); } } 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, i2p::client::PROTOCOL_TYPE_RAW, !session->IsRatchets ())); // raw + session->SendMsg(CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ())); // raw } void DatagramDestination::FlushSendQueue (std::shared_ptr session) @@ -95,50 +85,26 @@ namespace datagram session->FlushSendQueue (); } - void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort, - const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) + void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len) { 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 (from) + if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) { - 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); - } + 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) @@ -160,55 +126,6 @@ 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); @@ -277,31 +194,17 @@ namespace datagram return r; } - void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, - const uint8_t * buf, size_t len, uint8_t protocolType, i2p::garlic::ECIESX25519AEADRatchetSession * from) + void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw) { // unzip it uint8_t uncompressed[MAX_DATAGRAM_SIZE]; size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE); if (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); - }; + if (isRaw) + HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen); + else + HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); } else LogPrint (eLogWarning, "Datagram: decompression failed"); @@ -309,7 +212,7 @@ namespace datagram std::shared_ptr DatagramDestination::CreateDataMessage ( const std::vector >& payloads, - uint16_t fromPort, uint16_t toPort, uint8_t protocolType, bool checksum) + uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum) { size_t size; auto msg = m_I2NPMsgsPool.AcquireShared (); @@ -325,8 +228,8 @@ namespace datagram { htobe32buf (msg->GetPayload (), size); // length htobe16buf (buf + 4, fromPort); // source port - htobe16buf (buf + 6, toPort); // destination port - buf[9] = protocolType; // raw or datagram protocol + htobe16buf (buf + 6, toPort); // destination port + buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol msg->len += size + 4; msg->FillI2NPMessageHeader (eI2NPData, 0, checksum); } @@ -385,7 +288,8 @@ 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_Version (eDatagramV1) + m_LastUse (0), m_LastFlush (0), + m_RequestingLS(false) { } diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index 4ff2ef00..dd358434 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -20,7 +20,6 @@ #include "LeaseSet.h" #include "I2NPProtocol.h" #include "Garlic.h" -#include "ECIESX25519AEADRatchetSession.h" namespace i2p { @@ -45,15 +44,6 @@ 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 { @@ -74,12 +64,8 @@ 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 (); } - void SetRemoteLeaseSet (std::shared_ptr ls) { m_RemoteLeaseSet = ls; } + bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); } - DatagramVersion GetVersion () const { return m_Version; } - void SetVersion (DatagramVersion version) { m_Version = version; } - struct Info { std::shared_ptr IBGW; @@ -114,7 +100,6 @@ 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; @@ -139,8 +124,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, uint8_t protocolType, i2p::garlic::ECIESX25519AEADRatchetSession * from); + void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); + void SetReceiver (const Receiver& receiver, uint16_t port); void ResetReceiver (uint16_t port); @@ -158,13 +143,10 @@ 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, uint8_t protocolType, bool checksum = true); + uint16_t fromPort, uint16_t toPort, bool isRaw = false, bool checksum = true); - void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, - i2p::garlic::ECIESX25519AEADRatchetSession * from); + 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 394435c5..b243ba0a 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -388,7 +388,7 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (payload, len, from); + HandleDataMessage (payload, len); 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, shared_from_this(), true); + leaseSet->Update (buf + offset, len - offset); if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ()) LogPrint (eLogDebug, "Destination: Remote LeaseSet updated"); else @@ -471,8 +471,7 @@ namespace client else { leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], - buf + offset, len - offset, true, shared_from_this (), - from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2 + buf + offset, len - offset, true, from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2 if (from) { uint8_t pub[32]; @@ -489,9 +488,7 @@ namespace client if (leaseSet->GetIdentHash () != GetIdentHash ()) { LogPrint (eLogDebug, "Destination: New remote LeaseSet added"); - m_RemoteLeaseSets.insert_or_assign (key, leaseSet); - if (from) - from->SetDestination (key); + m_RemoteLeaseSets[key] = leaseSet; } else LogPrint (eLogDebug, "Destination: Own remote LeaseSet dropped"); @@ -514,8 +511,8 @@ namespace client if (request->requestedBlindedKey) { auto ls2 = std::make_shared (buf + offset, len - offset, - request->requestedBlindedKey, shared_from_this (), - m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr, GetPreferredCryptoType ()); + request->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr, + GetPreferredCryptoType ()); if (ls2->IsValid () && !ls2->IsExpired ()) { leaseSet = ls2; @@ -1160,8 +1157,7 @@ namespace client LogPrint(eLogDebug, "Destination: -> Stopping done"); } - void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len, - i2p::garlic::ECIESX25519AEADRatchetSession * from) + void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) { uint32_t length = bufbe32toh (buf); if(length > len - 4) @@ -1186,21 +1182,25 @@ namespace client m_LastPort = toPort; } if (m_LastStreamingDestination) - m_LastStreamingDestination->HandleDataMessagePayload (buf, length, from); + m_LastStreamingDestination->HandleDataMessagePayload (buf, length); 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, buf[9], from); + m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length); 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 717f35ce..35557859 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -37,8 +37,6 @@ 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 @@ -176,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, i2p::garlic::ECIESX25519AEADRatchetSession * from) = 0; + virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; virtual void CreateNewLeaseSet (const std::vector >& tunnels) = 0; private: @@ -290,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, i2p::garlic::ECIESX25519AEADRatchetSession * from) override; + void HandleDataMessage (const uint8_t * buf, size_t len) override; void CreateNewLeaseSet (const std::vector >& tunnels) override; private: diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 55d7711d..47edb755 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -1,12 +1,12 @@ /* -* Copyright (c) 2013-2025, The PurpleI2P Project +* Copyright (c) 2013-2024, 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,27 +134,22 @@ namespace crypto { BN_CTX * bnCtx = BN_CTX_new (); // calculate r - 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 + 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 uint8_t digest[64]; - unsigned int dl = 64; - EVP_DigestFinal_ex (ctx, digest, &dl); - EVP_MD_CTX_destroy (ctx); + SHA512_Final (digest, &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 - 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); + 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); BIGNUM * h = DecodeBN<64> (digest); // S = (r + h*a) % l BIGNUM * a = DecodeBN (expandedPrivateKey); // left half of expanded key @@ -174,15 +169,13 @@ namespace crypto uint8_t T[80]; RAND_bytes (T, 80); // calculate r = H*(T || publickey || 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 + SHA512_CTX ctx; + SHA512_Init (&ctx); + SHA512_Update (&ctx, T, 80); + SHA512_Update (&ctx, publicKeyEncoded, 32); + SHA512_Update (&ctx, buf, len); // data uint8_t digest[64]; - unsigned int dl = 64; - EVP_DigestFinal_ex (ctx, digest, &dl); - EVP_MD_CTX_destroy (ctx); + SHA512_Final (digest, &ctx); BIGNUM * r = DecodeBN<64> (digest); BN_mod (r, r, l, bnCtx); // % l EncodeBN (r, digest, 32); @@ -190,14 +183,11 @@ 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 - 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); + 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); 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 3a4e8890..300a50ab 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.cpp @@ -51,24 +51,11 @@ namespace data auto pkey = X509_get_pubkey (cert); if (pkey) { - 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"); + 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); + } } } } @@ -119,17 +106,11 @@ namespace data memcpy (buf + len, (const uint8_t *)ident, 32); len += 32; auto signatureBufLen = Base64ToByteStream (signature, signatureBuf, 64); - if (signatureBufLen == 64) + if (signatureBufLen) { - 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, EVP_sha256(), NULL, it->second.first); - auto ret = EVP_DigestVerify (ctx, sign, l, buf, len) == 1; + EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, it->second.first); + auto ret = EVP_DigestVerify (ctx, signatureBuf, signatureBufLen, buf, len); EVP_MD_CTX_destroy (ctx); return ret; } @@ -156,40 +137,29 @@ namespace data { SSL * ssl = SSL_new (ctx); EVP_PKEY * pkey = SSL_get_privatekey (ssl); - 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) + EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey); + if (ecKey) { - 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"); - + 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"); + } + } SSL_free (ssl); } else diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 8c7c8491..3cd5c193 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 = 1, pos; + size_t count = 0, pos; while ((pos = line.find (delim)) != line.npos) { count++; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 3001bdfb..fc0e722d 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, std::shared_ptr dest, bool verifySignature) + void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature) { SetBuffer (buf, len); ReadFromBuffer (false, verifySignature); @@ -281,29 +281,28 @@ 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, std::shared_ptr dest, CryptoKeyType preferredCrypto): + LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto): LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto) { SetBuffer (buf, len); if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) - ReadFromBufferEncrypted (buf, len, nullptr, dest, nullptr); + ReadFromBufferEncrypted (buf, len, nullptr, nullptr); else - ReadFromBuffer (buf, len, dest); + ReadFromBuffer (buf, len); } LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, - std::shared_ptr dest, const uint8_t * secret, CryptoKeyType preferredCrypto): + const uint8_t * secret, CryptoKeyType preferredCrypto): LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto) { - ReadFromBufferEncrypted (buf, len, key, dest, secret); + ReadFromBufferEncrypted (buf, len, key, secret); } - void LeaseSet2::Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature) + void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature) { SetBuffer (buf, len); if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) - ReadFromBuffer (buf, len, dest, false, verifySignature); + ReadFromBuffer (buf, len, false, verifySignature); // TODO: implement encrypted } @@ -313,8 +312,7 @@ namespace data return ExtractPublishedTimestamp (buf, len, expiration) > m_PublishedTimestamp; } - void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, std::shared_ptr dest, - bool readIdentity, bool verifySignature) + void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature) { // standard LS2 header std::shared_ptr identity; @@ -352,7 +350,7 @@ namespace data switch (m_StoreType) { case NETDB_STORE_TYPE_STANDARD_LEASESET2: - s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset, dest); + s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset); break; case NETDB_STORE_TYPE_META_LEASESET2: s = ReadMetaLS2TypeSpecificPart (buf + offset, len - offset); @@ -394,8 +392,7 @@ namespace data return verified; } - size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len, - std::shared_ptr dest) + size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len) { size_t offset = 0; // properties @@ -420,8 +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) && - (!dest || dest->SupportsEncryptionType (keyType))) + if (keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) { auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); if (encryptor) @@ -502,8 +498,7 @@ namespace data return offset; } - void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, - std::shared_ptr key, std::shared_ptr dest, const uint8_t * secret) + void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret) { size_t offset = 0; // blinded key @@ -606,7 +601,7 @@ namespace data m_StoreType = innerPlainText[0]; SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); // parse and verify Layer 2 - ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1, dest); + ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); } else LogPrint (eLogError, "LeaseSet2: Unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet"); diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 46f40cb5..f5197eb5 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, std::shared_ptr dest, bool verifySignature); + virtual void Update (const uint8_t * buf, size_t len, bool verifySignature = true); virtual bool IsNewer (const uint8_t * buf, size_t len) const; void PopulateLeases (); // from buffer @@ -155,35 +155,31 @@ 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, - 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; }; + 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; }; bool IsPublic () const { return m_IsPublic; }; - 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; + 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; // implements RoutingDestination - void Encrypt (const uint8_t * data, uint8_t * encrypted) const override; - CryptoKeyType GetEncryptionType () const override { return m_EncryptionType; }; + void Encrypt (const uint8_t * data, uint8_t * encrypted) const; + CryptoKeyType GetEncryptionType () const { return m_EncryptionType; }; private: - 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); + 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); 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 override; + uint64_t ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const; 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 cab40e43..e53738e5 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, nullptr, false); // signature is verified already + it->second->Update (buf, len, 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 8d17628f..f2a7019b 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 = 1500; + const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200; 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 23dae8ff..e58e898b 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2025, The PurpleI2P Project +* Copyright (c) 2013-2024, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -14,9 +14,6 @@ #include #include #include -#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 -#include -#endif #include #include "Crypto.h" @@ -483,31 +480,15 @@ namespace data if (terminator) terminator[0] = 0; } // extract RSA key (we need n only, e = 65537) - 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; + const RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert)); + const BIGNUM * n, * e, * d; RSA_get0_key(key, &n, &e, &d); -#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); - } + PublicKey value; + i2p::crypto::bn2buf (n, value, 512); + if (cn) + m_SigningKeys[cn] = value; else - LogPrint (eLogError, "Reseed: Can't extract RSA key from ", filename); -#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 - BN_free (n1); -#endif + LogPrint (eLogError, "Reseed: Can't find CN field in ", filename); } SSL_free (ssl); } diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 4540b4d2..fc2355a5 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -25,8 +25,7 @@ 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_IsForcedFirewalled4 (false), - m_IsForcedFirewalled6 (false), m_IsThroughProxy (false) + m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsThroughProxy (false) { } @@ -80,7 +79,6 @@ 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 (), @@ -93,7 +91,6 @@ 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 b7214480..a8598ce3 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -79,7 +79,6 @@ 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; } @@ -209,7 +208,6 @@ 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 dc626b16..3760e329 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -90,9 +90,6 @@ 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 cad7d484..3e4b451b 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -10,7 +10,6 @@ #include #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 #include -#include #endif #include "Log.h" #include "Signature.h" @@ -42,19 +41,22 @@ 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 - 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); + 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); return ret; } @@ -73,13 +75,13 @@ namespace crypto void DSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const { - 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 + 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); const uint8_t * s1 = sign; DSA_SIG * sig = d2i_DSA_SIG (NULL, &s1, l); const BIGNUM * r, * s; @@ -87,6 +89,7 @@ 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) @@ -132,7 +135,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) == 1; + int ret = DSA_do_verify (digest, 20, sig, m_PublicKey); DSA_SIG_free(sig); return ret; } @@ -171,138 +174,8 @@ 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 - { - // 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 - + +#if OPENSSL_EDDSA EDDSA25519Verifier::EDDSA25519Verifier (): m_Pkey (nullptr) { @@ -325,7 +198,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) == 1; + auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len); EVP_MD_CTX_destroy (ctx); return ret; } @@ -334,6 +207,37 @@ 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 @@ -363,6 +267,7 @@ 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) { @@ -404,6 +309,7 @@ namespace crypto else LogPrint (eLogError, "EdDSA signing key is not set"); } +#endif #if (OPENSSL_VERSION_NUMBER >= 0x030000000) static const OSSL_PARAM EDDSA25519phParams[] = @@ -509,7 +415,7 @@ namespace crypto OSSL_PARAM_END }; EVP_PKEY_verify_message_init (vctx, sig, params); - ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len) == 1; + ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len); EVP_SIGNATURE_free (sig); } EVP_PKEY_CTX_free (vctx); diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 43f706bd..20c7e11b 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -91,116 +91,7 @@ namespace crypto void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey); - // 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 - + // ECDSA struct SHA256Hash { static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) @@ -263,7 +154,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) == 1; + int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey); ECDSA_SIG_free(sig); return ret; } @@ -326,6 +217,7 @@ namespace crypto } // ECDSA_SHA256_P256 + const size_t ECDSAP256_KEY_LENGTH = 64; typedef ECDSAVerifier ECDSAP256Verifier; typedef ECDSASigner ECDSAP256Signer; @@ -335,6 +227,7 @@ namespace crypto } // ECDSA_SHA384_P384 + const size_t ECDSAP384_KEY_LENGTH = 96; typedef ECDSAVerifier ECDSAP384Verifier; typedef ECDSASigner ECDSAP384Signer; @@ -344,6 +237,7 @@ namespace crypto } // ECDSA_SHA512_P521 + const size_t ECDSAP521_KEY_LENGTH = 132; typedef ECDSAVerifier ECDSAP521Verifier; typedef ECDSASigner ECDSAP521Signer; @@ -351,8 +245,7 @@ namespace crypto { CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); } - -#endif + // EdDSA class EDDSA25519Verifier: public Verifier @@ -369,12 +262,18 @@ 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 @@ -403,6 +302,7 @@ namespace crypto uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; }; +#if OPENSSL_EDDSA class EDDSA25519Signer: public Signer { public: @@ -422,6 +322,11 @@ 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 @@ -437,6 +342,7 @@ 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); @@ -447,6 +353,11 @@ 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 66c8919d..1f849925 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->from && packet->GetNACKCount () == 8 && // first incoming packet + if (!m_RemoteIdentity && 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,7 +397,6 @@ namespace stream optionData += 2; } - bool sessionVerified = false; if (flags & PACKET_FLAG_FROM_INCLUDED) { if (m_RemoteLeaseSet) m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity (); @@ -410,24 +409,7 @@ namespace stream } optionData += m_RemoteIdentity->GetFullLen (); if (!m_RemoteLeaseSet) - { - 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; - } + LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); } if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED) @@ -444,81 +426,60 @@ namespace stream LogPrint (eLogInfo, "Streaming: offline signature without identity"); return false; } - if (sessionVerified) + // 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) { - // 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 + // skip option data + optionData += 6; // timestamp and key type + optionData += m_TransientVerifier->GetPublicKeyLen (); // public key optionData += m_RemoteIdentity->GetSignatureLen (); // signature } else - { - // 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) + { + // transient key + size_t offset = 0; + m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset); + optionData += offset; + if (!m_TransientVerifier) { - // skip option data - optionData += 6; // timestamp and key type - optionData += m_TransientVerifier->GetPublicKeyLen (); // public key - optionData += m_RemoteIdentity->GetSignatureLen (); // signature + LogPrint (eLogError, "Streaming: offline signature failed"); + return false; } - 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; } - 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(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 @@ -851,7 +812,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); @@ -1455,7 +1416,6 @@ 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 @@ -1578,7 +1538,7 @@ namespace stream } else if (!m_IsClientChoked) SendBuffer (); - if (!m_IsNAcked && !m_IsResendNeeded && !m_IsClientChoked) ScheduleResend (); + if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend (); if (m_IsClientChoked) ScheduleSend (); } @@ -2093,18 +2053,14 @@ namespace stream } } - void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len, - i2p::garlic::ECIESX25519AEADRatchetSession * from) + void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len) { // 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 eae43c0e..9fbcb178 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -27,7 +27,6 @@ #include "Garlic.h" #include "Tunnel.h" #include "util.h" // MemoryPool -#include "ECIESX25519AEADRatchetSession.h" namespace i2p { @@ -89,9 +88,8 @@ 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), from (nullptr) {}; + Packet (): len (0), offset (0), sendTime (0), resent (false) {}; uint8_t * GetBuffer () { return buf + offset; }; size_t GetLength () const { return len > offset ? len - offset : 0; }; @@ -342,7 +340,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, i2p::garlic::ECIESX25519AEADRatchetSession * from); + void HandleDataMessagePayload (const uint8_t * buf, size_t len); 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 85c58c48..11278e7a 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -86,8 +86,7 @@ namespace client return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; } - void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len, - i2p::garlic::ECIESX25519AEADRatchetSession * from) + void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len) { uint32_t length = bufbe32toh (buf); if (length > len - 4) length = len - 4; @@ -624,14 +623,17 @@ namespace client void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len) { - constexpr std::string_view version(I2P_VERSION); - std::array payload; + // get version + auto version = ExtractString (buf, len); + auto l = version.length () + 1 + 8; + uint8_t * payload = new uint8_t[l]; // set date auto ts = i2p::util::GetMillisecondsSinceEpoch (); - 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()); + htobe64buf (payload, ts); + // echo vesrion back + PutString (payload + 8, l - 8, version); + SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload, l); + delete[] payload; } void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len) diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 0bfa49f2..37c14dbb 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, i2p::garlic::ECIESX25519AEADRatchetSession * from) override; + void HandleDataMessage (const uint8_t * buf, size_t len) override; void CreateNewLeaseSet (const std::vector >& tunnels) override; private: diff --git a/tests/test-base-64.cpp b/tests/test-base-64.cpp index 63817bf4..0ab46c06 100644 --- a/tests/test-base-64.cpp +++ b/tests/test-base-64.cpp @@ -11,7 +11,8 @@ int main() { char out[16]; /* bytes -> b64 */ - assert(ByteStreamToBase64(NULL, 0) == ""); + assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0); + assert(ByteStreamToBase64(NULL, 0, out, sizeof(out)) == 0); assert(Base64EncodingBufferSize(2) == 4); assert(Base64EncodingBufferSize(4) == 8); @@ -22,20 +23,19 @@ int main() { assert(Base64EncodingBufferSize(12) == 16); assert(Base64EncodingBufferSize(13) == 20); - const std::string out_str(ByteStreamToBase64((uint8_t *) in, in_len)); - assert(out_str.size() == 8); - assert(out_str == "dGVzdA=="); + assert(ByteStreamToBase64((uint8_t *) in, in_len, out, sizeof(out)) == 8); + assert(memcmp(out, "dGVzdA==", 8) == 0); /* b64 -> bytes */ - assert(Base64ToByteStream("", NULL, 0) == 0); - assert(Base64ToByteStream("", (uint8_t *) out, sizeof(out)) == 0); + assert(Base64ToByteStream(NULL, 0, NULL, 0) == 0); + assert(Base64ToByteStream(NULL, 0, (uint8_t *) out, sizeof(out)) == 0); in = "dGVzdA=="; /* valid b64 */ - assert(Base64ToByteStream(in, (uint8_t *) out, sizeof(out)) == 4); + assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 4); assert(memcmp(out, "test", 4) == 0); in = "dGVzdA="; /* invalid b64 : not padded */ - assert(Base64ToByteStream(in, (uint8_t *) out, sizeof(out)) == 0); + assert(Base64ToByteStream(in, strlen(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 9de2c088..b3895e2b 100644 --- a/tests/test-eddsa.cpp +++ b/tests/test-eddsa.cpp @@ -58,7 +58,9 @@ 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);