Compare commits

..

No commits in common. "openssl" and "2.57.0" have entirely different histories.

31 changed files with 397 additions and 779 deletions

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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 << "<div class=\"leaseset listitem";

View file

@ -437,54 +437,48 @@ namespace client
void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
{
FILE *f = NULL;
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
EVP_PKEY * pkey = EVP_RSA_gen(4096); // e = 65537
#else
EVP_PKEY * pkey = EVP_PKEY_new ();
RSA * rsa = RSA_new ();
BIGNUM * e = BN_dup (i2p::crypto::GetRSAE ());
RSA_generate_key_ex (rsa, 4096, e, NULL);
BN_free (e);
if (rsa) EVP_PKEY_assign_RSA (pkey, rsa);
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);
}
}

View file

@ -305,8 +305,6 @@ namespace config {
("ssu2.mtu4", value<uint16_t>()->default_value(0), "MTU for ipv4 address (default: detect)")
("ssu2.mtu6", value<uint16_t>()->default_value(0), "MTU for ipv6 address (default: detect)")
("ssu2.proxy", value<std::string>()->default_value(""), "Socks5 proxy URL for SSU2 transport")
("ssu2.firewalled4", value<bool>()->default_value(false), "Set ipv4 network status to Firewalled even if OK (default: disabled)")
("ssu2.firewalled6", value<bool>()->default_value(false), "Set ipv6 network status to Firewalled even if OK (default: disabled)")
;
options_description nettime("Time sync options");

View file

@ -16,7 +16,9 @@
#include <openssl/crypto.h>
#include "TunnelBase.h"
#include <openssl/ssl.h>
#if OPENSSL_HKDF
#include <openssl/kdf.h>
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
#include <openssl/param_build.h>
#include <openssl/core_names.h>
@ -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

View file

@ -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

View file

@ -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<DatagramSession> 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<DatagramSession> 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<i2p::data::LeaseSet> 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<std::mutex> 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<I2NPMessage> DatagramDestination::CreateDataMessage (
const std::vector<std::pair<const uint8_t *, size_t> >& 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<i2p::client::ClientDestination> 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)
{
}

View file

@ -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<DatagramSession>
{
@ -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<const i2p::data::LeaseSet> 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<const i2p::data::IdentHash> IBGW;
@ -114,7 +100,6 @@ namespace datagram
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
uint64_t m_LastUse, m_LastFlush; // milliseconds
bool m_RequestingLS;
DatagramVersion m_Version;
};
typedef std::shared_ptr<DatagramSession> DatagramSession_ptr;
@ -139,8 +124,8 @@ namespace datagram
void SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void FlushSendQueue (std::shared_ptr<DatagramSession> 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<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
std::shared_ptr<I2NPMessage> CreateDataMessage (const std::vector<std::pair<const uint8_t *, size_t> >& 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);

View file

@ -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<i2p::data::LeaseSet2> (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<i2p::data::LeaseSet2> (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]);
}

View file

@ -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<std::shared_ptr<i2p::tunnel::InboundTunnel> >& 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<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels) override;
private:

View file

@ -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 <openssl/evp.h>
#include <openssl/sha.h>
#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<EDDSA25519_PRIVATE_KEY_LENGTH> (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<EDDSA25519_PRIVATE_KEY_LENGTH> (privateKey);

View file

@ -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

View file

@ -55,7 +55,7 @@ namespace http
static void strsplit(std::string_view line, std::vector<std::string_view> &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++;

View file

@ -36,7 +36,7 @@ namespace data
ReadFromBuffer ();
}
void LeaseSet::Update (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> 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<LocalDestination> 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<const BlindedPublicKey> key,
std::shared_ptr<LocalDestination> 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<LocalDestination> 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<LocalDestination> 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<const IdentityEx> 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<LocalDestination> 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<const BlindedPublicKey> key, std::shared_ptr<LocalDestination> dest, const uint8_t * secret)
void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> 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");

View file

@ -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<LocalDestination> 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<LocalDestination> dest = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD);
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key,
std::shared_ptr<LocalDestination> 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<const BlindedPublicKey> 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<const i2p::crypto::Verifier> GetTransientVerifier () const override { return m_TransientVerifier; };
void Update (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> dest, bool verifySignature) override;
bool IsNewer (const uint8_t * buf, size_t len) const override;
bool IsPublishedEncrypted () const { return m_IsPublishedEncrypted; };
std::shared_ptr<const i2p::crypto::Verifier> 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<LocalDestination> dest,
bool readIdentity = true, bool verifySignature = true);
void ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key,
std::shared_ptr<LocalDestination> dest, const uint8_t * secret);
size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> 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<const BlindedPublicKey> 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<typename Verifier>
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

View file

@ -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;

View file

@ -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

View file

@ -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 <boost/algorithm/string.hpp>
#include <openssl/ssl.h>
#include <openssl/err.h>
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
#include <openssl/core_names.h>
#endif
#include <zlib.h>
#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);
}

View file

@ -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 (),

View file

@ -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;

View file

@ -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 ())
{

View file

@ -10,7 +10,6 @@
#include <openssl/evp.h>
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
#include <openssl/core_names.h>
#include <openssl/param_build.h>
#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<uint8_t> 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<uint8_t> 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<uint8_t> 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);

View file

@ -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<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier;
typedef ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer;
@ -335,6 +227,7 @@ namespace crypto
}
// ECDSA_SHA384_P384
const size_t ECDSAP384_KEY_LENGTH = 96;
typedef ECDSAVerifier<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Verifier;
typedef ECDSASigner<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Signer;
@ -344,6 +237,7 @@ namespace crypto
}
// ECDSA_SHA512_P521
const size_t ECDSAP521_KEY_LENGTH = 132;
typedef ECDSAVerifier<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> ECDSAP521Verifier;
typedef ECDSASigner<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> 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
}

View file

@ -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<i2p::crypto::Verifier> 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<uint8_t *>(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<uint8_t *>(optionData), signature, signatureLen);
}
else
{
// post quantum
std::vector<uint8_t> signature(signatureLen);
memcpy (signature.data (), optionData, signatureLen);
memset (const_cast<uint8_t *>(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<uint8_t *>(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<uint8_t *>(optionData), signature, signatureLen);
}
else
{
// post quantum
std::vector<uint8_t> signature(signatureLen);
memcpy (signature.data (), optionData, signatureLen);
memset (const_cast<uint8_t *>(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);
}

View file

@ -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<i2p::client::ClientDestination> 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<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true, bool gzip = false);
Packet * NewPacket () { return m_PacketsPool.Acquire(); }

View file

@ -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<uint8_t, version.size() + 8 + 1> 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)

View file

@ -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<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels) override;
private:

View file

@ -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);

View file

@ -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);