mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-07-04 09:13:55 +02:00
Compare commits
32 commits
Author | SHA1 | Date | |
---|---|---|---|
|
1a6051e79b | ||
|
a5631bd1b5 | ||
|
f230c110aa | ||
|
0445a5d775 | ||
|
31b6f07b78 | ||
|
8c89c8368a | ||
|
40b90ccea4 | ||
|
75dd0d72c6 | ||
|
9efdc230a9 | ||
|
6b519c36c5 | ||
|
a6bf6baf1b | ||
|
78357c23d2 | ||
|
5f0262ea2f | ||
|
61588777be | ||
|
588108d7d0 | ||
|
06c9a255fb | ||
|
bb2b34ff4f | ||
|
5974d2b5ac | ||
|
5bef987529 | ||
|
d2296f81ad | ||
|
660dbd27d1 | ||
|
4828d93257 | ||
|
46154dabd5 | ||
|
ba0352e9a0 | ||
|
9c393f50da | ||
|
6363c9202f | ||
|
9c0051e73b | ||
|
cbb5250dd4 | ||
|
6ad6a2501e | ||
|
2631255b46 | ||
|
db67126581 | ||
|
37fd4b4422 |
31 changed files with 779 additions and 397 deletions
|
@ -246,9 +246,9 @@ verify = true
|
|||
# subscriptions = http://reg.i2p/hosts.txt,http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt
|
||||
|
||||
[limits]
|
||||
## Maximum active transit sessions (default: 5000)
|
||||
## Maximum active transit sessions (default: 10000)
|
||||
## This value is doubled if floodfill mode is enabled!
|
||||
# transittunnels = 5000
|
||||
# transittunnels = 10000
|
||||
## Limit number of open file descriptors (0 - use system limit)
|
||||
# openfiles = 0
|
||||
## Maximum size of corefile in Kb (0 - use system limit)
|
||||
|
|
|
@ -10,11 +10,7 @@ License: BSD
|
|||
URL: https://github.com/PurpleI2P/i2pd
|
||||
Source0: https://github.com/PurpleI2P/i2pd/archive/openssl/i2pd-openssl.tar.gz
|
||||
|
||||
%if 0%{?rhel} == 7
|
||||
BuildRequires: cmake3
|
||||
%else
|
||||
BuildRequires: cmake
|
||||
%endif
|
||||
|
||||
BuildRequires: chrpath
|
||||
BuildRequires: gcc-c++
|
||||
|
@ -43,13 +39,6 @@ C++ implementation of I2P.
|
|||
|
||||
%build
|
||||
cd build
|
||||
%if 0%{?rhel} == 7
|
||||
%cmake3 \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
-DWITH_HARDENING=ON \
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
%else
|
||||
%cmake \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
|
@ -60,9 +49,8 @@ cd build
|
|||
%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
|
||||
|
@ -76,7 +64,7 @@ cd build
|
|||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7
|
||||
%if 0%{?rhel} >= 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7
|
||||
popd
|
||||
%endif
|
||||
|
||||
|
@ -84,7 +72,7 @@ make %{?_smp_mflags}
|
|||
%install
|
||||
pushd build
|
||||
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
|
||||
%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln}
|
||||
pushd redhat-linux-build
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
|
|
|
@ -8,11 +8,7 @@ License: BSD
|
|||
URL: https://github.com/PurpleI2P/i2pd
|
||||
Source0: https://github.com/PurpleI2P/i2pd/archive/%{version}/%name-%version.tar.gz
|
||||
|
||||
%if 0%{?rhel} == 7
|
||||
BuildRequires: cmake3
|
||||
%else
|
||||
BuildRequires: cmake
|
||||
%endif
|
||||
|
||||
BuildRequires: chrpath
|
||||
BuildRequires: gcc-c++
|
||||
|
@ -41,13 +37,6 @@ C++ implementation of I2P.
|
|||
|
||||
%build
|
||||
cd build
|
||||
%if 0%{?rhel} == 7
|
||||
%cmake3 \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
-DWITH_HARDENING=ON \
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
%else
|
||||
%cmake \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
|
@ -58,9 +47,8 @@ cd build
|
|||
%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
|
||||
|
@ -74,7 +62,7 @@ cd build
|
|||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7
|
||||
%if 0%{?rhel} >= 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7
|
||||
popd
|
||||
%endif
|
||||
|
||||
|
@ -82,7 +70,7 @@ make %{?_smp_mflags}
|
|||
%install
|
||||
pushd build
|
||||
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
|
||||
%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln}
|
||||
pushd redhat-linux-build
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
|
|
|
@ -661,7 +661,7 @@ namespace http {
|
|||
else
|
||||
{
|
||||
ls.reset (new i2p::data::LeaseSet2 (storeType));
|
||||
ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), false);
|
||||
ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), nullptr, false);
|
||||
}
|
||||
if (!ls) return;
|
||||
s << "<div class=\"leaseset listitem";
|
||||
|
|
|
@ -437,14 +437,22 @@ 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)
|
||||
if (rsa) EVP_PKEY_assign_RSA (pkey, rsa);
|
||||
else
|
||||
{
|
||||
EVP_PKEY_assign_RSA (pkey, rsa);
|
||||
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);
|
||||
|
@ -458,27 +466,25 @@ namespace client
|
|||
X509_sign (x509, pkey, EVP_sha1 ()); // sign, last param must be NULL for EdDSA
|
||||
|
||||
// save cert
|
||||
if ((f = fopen (crt_path, "wb")) != NULL) {
|
||||
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));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PControl: Can't write cert: ", strerror(errno));
|
||||
X509_free (x509);
|
||||
|
||||
// save key
|
||||
if ((f = fopen (key_path, "wb")) != NULL) {
|
||||
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 {
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PControl: Can't write key: ", strerror(errno));
|
||||
}
|
||||
|
||||
X509_free (x509);
|
||||
} else {
|
||||
LogPrint (eLogError, "I2PControl: Can't create RSA key for certificate");
|
||||
}
|
||||
EVP_PKEY_free (pkey);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,6 +305,8 @@ 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");
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
#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>
|
||||
|
@ -784,7 +782,6 @@ namespace crypto
|
|||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info,
|
||||
uint8_t * out, size_t outLen)
|
||||
{
|
||||
#if OPENSSL_HKDF
|
||||
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr);
|
||||
EVP_PKEY_derive_init (pctx);
|
||||
EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256());
|
||||
|
@ -805,18 +802,6 @@ namespace crypto
|
|||
EVP_PKEY_CTX_add1_hkdf_info (pctx, (const uint8_t *)info.c_str (), info.length ());
|
||||
EVP_PKEY_derive (pctx, out, &outLen);
|
||||
EVP_PKEY_CTX_free (pctx);
|
||||
#else
|
||||
uint8_t prk[32]; unsigned int len;
|
||||
HMAC(EVP_sha256(), salt, 32, key, keyLen, prk, &len);
|
||||
auto l = info.length ();
|
||||
memcpy (out, info.c_str (), l); out[l] = 0x01;
|
||||
HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len);
|
||||
if (outLen > 32) // 64
|
||||
{
|
||||
memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02;
|
||||
HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Noise
|
||||
|
|
|
@ -27,15 +27,11 @@
|
|||
#include "Tag.h"
|
||||
|
||||
// recognize openssl version and features
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
||||
# define OPENSSL_HKDF 1
|
||||
# define OPENSSL_EDDSA 1
|
||||
#if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL
|
||||
# define OPENSSL_SIPHASH 1
|
||||
#endif
|
||||
//# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0
|
||||
//# define OPENSSL_PQ 1
|
||||
//# endif
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0
|
||||
# define OPENSSL_PQ 1
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
|
|
|
@ -57,6 +57,15 @@ namespace datagram
|
|||
void DatagramDestination::SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
||||
{
|
||||
if (session)
|
||||
{
|
||||
if (session->GetVersion () == eDatagramV3)
|
||||
{
|
||||
constexpr uint8_t flags[] = { 0x00, 0x03 }; // datagram3, no options
|
||||
auto msg = CreateDataMessage ({{m_Owner->GetIdentity ()->GetIdentHash (), 32},
|
||||
{flags, 2}, {payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM3, false); // datagram3
|
||||
session->SendMsg(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
|
@ -68,15 +77,16 @@ namespace datagram
|
|||
m_Owner->Sign (payload, len, m_Signature.data ());
|
||||
|
||||
auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}},
|
||||
fromPort, toPort, false, !session->IsRatchets ()); // datagram
|
||||
fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM, !session->IsRatchets ()); // datagram1
|
||||
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, true, !session->IsRatchets ())); // raw
|
||||
session->SendMsg(CreateDataMessage ({{payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_RAW, !session->IsRatchets ())); // raw
|
||||
}
|
||||
|
||||
void DatagramDestination::FlushSendQueue (std::shared_ptr<DatagramSession> session)
|
||||
|
@ -85,14 +95,36 @@ namespace datagram
|
|||
session->FlushSendQueue ();
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len)
|
||||
void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,
|
||||
const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from)
|
||||
{
|
||||
i2p::data::IdentityEx identity;
|
||||
size_t identityLen = identity.FromBuffer (buf, len);
|
||||
if (!identityLen) return;
|
||||
const uint8_t * signature = buf + identityLen;
|
||||
size_t headerLen = identityLen + identity.GetSignatureLen ();
|
||||
|
||||
std::shared_ptr<i2p::data::LeaseSet> ls;
|
||||
bool verified = false;
|
||||
if (from)
|
||||
{
|
||||
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];
|
||||
|
@ -101,10 +133,12 @@ namespace datagram
|
|||
}
|
||||
else
|
||||
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
|
||||
}
|
||||
|
||||
if (verified)
|
||||
{
|
||||
auto session = ObtainSession (identity.GetIdentHash());
|
||||
if (ls) session->SetRemoteLeaseSet (ls);
|
||||
session->Ack();
|
||||
auto r = FindReceiver(toPort);
|
||||
if(r)
|
||||
|
@ -126,6 +160,55 @@ namespace datagram
|
|||
LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram");
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len,
|
||||
i2p::garlic::ECIESX25519AEADRatchetSession * from)
|
||||
{
|
||||
if (len < 34)
|
||||
{
|
||||
LogPrint (eLogWarning, "Datagram: datagram3 is too short ", len);
|
||||
return;
|
||||
}
|
||||
if (from)
|
||||
{
|
||||
i2p::data::IdentHash ident(buf);
|
||||
auto ls = m_Owner->FindLeaseSet (ident);
|
||||
if (ls)
|
||||
{
|
||||
uint8_t staticKey[32];
|
||||
ls->Encrypt (nullptr, staticKey);
|
||||
if (!memcmp (from->GetRemoteStaticKey (), staticKey, 32))
|
||||
{
|
||||
auto session = ObtainSession (ident);
|
||||
session->SetVersion (eDatagramV3);
|
||||
session->SetRemoteLeaseSet (ls);
|
||||
session->Ack ();
|
||||
auto r = FindReceiver(toPort);
|
||||
if (r)
|
||||
{
|
||||
uint16_t flags = bufbe16toh (buf + 32);
|
||||
size_t offset = 34;
|
||||
if (flags & DATAGRAM3_FLAG_OPTIONS)
|
||||
offset += bufbe16toh (buf + offset) + 2;
|
||||
if (offset > len)
|
||||
{
|
||||
LogPrint (eLogWarning, "Datagram: datagram3 is too short ", len, " expected ", offset);
|
||||
return;
|
||||
}
|
||||
r(*ls->GetIdentity (), fromPort, toPort, buf + offset, len - offset);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Datagram: no receiver for port ", toPort);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Datagram: Remote LeaseSet static key mismatch for datagram3 from ", ident.ToBase32 ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Datagram: No remote LeaseSet for ", ident.ToBase32 ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "Datagram: datagram3 received from non-ratchets session");
|
||||
}
|
||||
|
||||
void DatagramDestination::SetReceiver (const Receiver& receiver, uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||
|
@ -194,17 +277,31 @@ namespace datagram
|
|||
return r;
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw)
|
||||
void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort,
|
||||
const uint8_t * buf, size_t len, uint8_t protocolType, i2p::garlic::ECIESX25519AEADRatchetSession * from)
|
||||
{
|
||||
// unzip it
|
||||
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
|
||||
size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE);
|
||||
if (uncompressedLen)
|
||||
{
|
||||
if (isRaw)
|
||||
switch (protocolType)
|
||||
{
|
||||
case i2p::client::PROTOCOL_TYPE_RAW:
|
||||
HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||
else
|
||||
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||
break;
|
||||
case i2p::client::PROTOCOL_TYPE_DATAGRAM3:
|
||||
HandleDatagram3 (fromPort, toPort, uncompressed, uncompressedLen, from);
|
||||
break;
|
||||
case i2p::client::PROTOCOL_TYPE_DATAGRAM:
|
||||
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen, from);
|
||||
break;
|
||||
case i2p::client::PROTOCOL_TYPE_DATAGRAM2:
|
||||
// TODO:
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogInfo, "Datagram: unknown protocol type ", protocolType);
|
||||
};
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Datagram: decompression failed");
|
||||
|
@ -212,7 +309,7 @@ namespace datagram
|
|||
|
||||
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (
|
||||
const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
|
||||
uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum)
|
||||
uint16_t fromPort, uint16_t toPort, uint8_t protocolType, bool checksum)
|
||||
{
|
||||
size_t size;
|
||||
auto msg = m_I2NPMsgsPool.AcquireShared ();
|
||||
|
@ -229,7 +326,7 @@ namespace datagram
|
|||
htobe32buf (msg->GetPayload (), size); // length
|
||||
htobe16buf (buf + 4, fromPort); // source port
|
||||
htobe16buf (buf + 6, toPort); // destination port
|
||||
buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol
|
||||
buf[9] = protocolType; // raw or datagram protocol
|
||||
msg->len += size + 4;
|
||||
msg->FillI2NPMessageHeader (eI2NPData, 0, checksum);
|
||||
}
|
||||
|
@ -288,8 +385,7 @@ namespace datagram
|
|||
DatagramSession::DatagramSession(std::shared_ptr<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_LastUse (0), m_LastFlush (0), m_RequestingLS (false), m_Version (eDatagramV1)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "LeaseSet.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "Garlic.h"
|
||||
#include "ECIESX25519AEADRatchetSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -44,6 +45,15 @@ namespace datagram
|
|||
const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds
|
||||
const int DATAGRAM_SESSION_ACK_REQUEST_INTERVAL = 5500; // in milliseconds
|
||||
|
||||
enum DatagramVersion
|
||||
{
|
||||
eDatagramV1 = 1,
|
||||
eDatagramV2 = 2,
|
||||
eDatagramV3 = 3,
|
||||
};
|
||||
|
||||
constexpr uint16_t DATAGRAM3_FLAG_OPTIONS = 0x10;
|
||||
|
||||
class DatagramSession : public std::enable_shared_from_this<DatagramSession>
|
||||
{
|
||||
|
||||
|
@ -65,6 +75,10 @@ namespace datagram
|
|||
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; }
|
||||
|
||||
DatagramVersion GetVersion () const { return m_Version; }
|
||||
void SetVersion (DatagramVersion version) { m_Version = version; }
|
||||
|
||||
struct Info
|
||||
{
|
||||
|
@ -100,6 +114,7 @@ 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;
|
||||
|
@ -124,8 +139,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, bool isRaw = false);
|
||||
|
||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort,
|
||||
const uint8_t * buf, size_t len, uint8_t protocolType, i2p::garlic::ECIESX25519AEADRatchetSession * from);
|
||||
|
||||
void SetReceiver (const Receiver& receiver, uint16_t port);
|
||||
void ResetReceiver (uint16_t port);
|
||||
|
@ -143,10 +158,13 @@ namespace datagram
|
|||
std::shared_ptr<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, bool isRaw = false, bool checksum = true);
|
||||
uint16_t fromPort, uint16_t toPort, uint8_t protocolType, bool checksum = true);
|
||||
|
||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
|
||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len,
|
||||
i2p::garlic::ECIESX25519AEADRatchetSession * from);
|
||||
void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
void HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len,
|
||||
i2p::garlic::ECIESX25519AEADRatchetSession * from);
|
||||
|
||||
Receiver FindReceiver(uint16_t port);
|
||||
RawReceiver FindRawReceiver(uint16_t port);
|
||||
|
|
|
@ -388,7 +388,7 @@ namespace client
|
|||
switch (typeID)
|
||||
{
|
||||
case eI2NPData:
|
||||
HandleDataMessage (payload, len);
|
||||
HandleDataMessage (payload, len, from);
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET));
|
||||
|
@ -450,7 +450,7 @@ namespace client
|
|||
leaseSet = it->second;
|
||||
if (leaseSet->IsNewer (buf + offset, len - offset))
|
||||
{
|
||||
leaseSet->Update (buf + offset, len - offset);
|
||||
leaseSet->Update (buf + offset, len - offset, shared_from_this(), true);
|
||||
if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ())
|
||||
LogPrint (eLogDebug, "Destination: Remote LeaseSet updated");
|
||||
else
|
||||
|
@ -471,7 +471,8 @@ namespace client
|
|||
else
|
||||
{
|
||||
leaseSet = std::make_shared<i2p::data::LeaseSet2> (buf[DATABASE_STORE_TYPE_OFFSET],
|
||||
buf + offset, len - offset, true, from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2
|
||||
buf + offset, len - offset, true, shared_from_this (),
|
||||
from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2
|
||||
if (from)
|
||||
{
|
||||
uint8_t pub[32];
|
||||
|
@ -488,7 +489,9 @@ namespace client
|
|||
if (leaseSet->GetIdentHash () != GetIdentHash ())
|
||||
{
|
||||
LogPrint (eLogDebug, "Destination: New remote LeaseSet added");
|
||||
m_RemoteLeaseSets[key] = leaseSet;
|
||||
m_RemoteLeaseSets.insert_or_assign (key, leaseSet);
|
||||
if (from)
|
||||
from->SetDestination (key);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "Destination: Own remote LeaseSet dropped");
|
||||
|
@ -511,8 +514,8 @@ namespace client
|
|||
if (request->requestedBlindedKey)
|
||||
{
|
||||
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset,
|
||||
request->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr,
|
||||
GetPreferredCryptoType ());
|
||||
request->requestedBlindedKey, shared_from_this (),
|
||||
m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr, GetPreferredCryptoType ());
|
||||
if (ls2->IsValid () && !ls2->IsExpired ())
|
||||
{
|
||||
leaseSet = ls2;
|
||||
|
@ -1157,7 +1160,8 @@ namespace client
|
|||
LogPrint(eLogDebug, "Destination: -> Stopping done");
|
||||
}
|
||||
|
||||
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len,
|
||||
i2p::garlic::ECIESX25519AEADRatchetSession * from)
|
||||
{
|
||||
uint32_t length = bufbe32toh (buf);
|
||||
if(length > len - 4)
|
||||
|
@ -1182,25 +1186,21 @@ namespace client
|
|||
m_LastPort = toPort;
|
||||
}
|
||||
if (m_LastStreamingDestination)
|
||||
m_LastStreamingDestination->HandleDataMessagePayload (buf, length);
|
||||
m_LastStreamingDestination->HandleDataMessagePayload (buf, length, from);
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Missing streaming destination");
|
||||
}
|
||||
break;
|
||||
case PROTOCOL_TYPE_DATAGRAM:
|
||||
case PROTOCOL_TYPE_RAW:
|
||||
case PROTOCOL_TYPE_DATAGRAM2:
|
||||
case PROTOCOL_TYPE_DATAGRAM3:
|
||||
// datagram protocol
|
||||
if (m_DatagramDestination)
|
||||
m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length);
|
||||
m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, buf[9], from);
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Missing datagram destination");
|
||||
break;
|
||||
case PROTOCOL_TYPE_RAW:
|
||||
// raw datagram
|
||||
if (m_DatagramDestination)
|
||||
m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, true);
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Missing raw datagram destination");
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "Destination: Data: Unexpected protocol ", buf[9]);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ namespace client
|
|||
const uint8_t PROTOCOL_TYPE_STREAMING = 6;
|
||||
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
|
||||
const uint8_t PROTOCOL_TYPE_RAW = 18;
|
||||
const uint8_t PROTOCOL_TYPE_DATAGRAM2 = 19;
|
||||
const uint8_t PROTOCOL_TYPE_DATAGRAM3 = 20;
|
||||
const int PUBLISH_CONFIRMATION_TIMEOUT = 1800; // in milliseconds
|
||||
const int PUBLISH_VERIFICATION_TIMEOUT = 5; // in seconds after successful publish
|
||||
const int PUBLISH_VERIFICATION_TIMEOUT_VARIANCE = 3; // in seconds
|
||||
|
@ -174,7 +176,7 @@ namespace client
|
|||
virtual void CleanupDestination () {}; // additional clean up in derived classes
|
||||
virtual i2p::data::CryptoKeyType GetPreferredCryptoType () const = 0;
|
||||
// I2CP
|
||||
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;
|
||||
virtual void HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) = 0;
|
||||
virtual void CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels) = 0;
|
||||
|
||||
private:
|
||||
|
@ -288,7 +290,7 @@ namespace client
|
|||
void CleanupDestination () override;
|
||||
i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; }
|
||||
// I2CP
|
||||
void HandleDataMessage (const uint8_t * buf, size_t len) override;
|
||||
void HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) override;
|
||||
void CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2025, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "Log.h"
|
||||
#include "Crypto.h"
|
||||
#include "Ed25519.h"
|
||||
|
@ -134,22 +134,27 @@ namespace crypto
|
|||
{
|
||||
BN_CTX * bnCtx = BN_CTX_new ();
|
||||
// calculate r
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestInit_ex (ctx, EVP_sha512(), NULL);
|
||||
EVP_DigestUpdate (ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key
|
||||
EVP_DigestUpdate (ctx, buf, len); // data
|
||||
uint8_t digest[64];
|
||||
SHA512_Final (digest, &ctx);
|
||||
unsigned int dl = 64;
|
||||
EVP_DigestFinal_ex (ctx, digest, &dl);
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors
|
||||
// calculate R
|
||||
uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
|
||||
EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors
|
||||
// calculate S
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestInit_ex (ctx, EVP_sha512(), NULL);
|
||||
EVP_DigestUpdate (ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
EVP_DigestUpdate (ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
EVP_DigestUpdate (ctx, buf, len); // data
|
||||
dl = 64;
|
||||
EVP_DigestFinal_ex (ctx, digest, &dl);
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
// S = (r + h*a) % l
|
||||
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key
|
||||
|
@ -169,13 +174,15 @@ namespace crypto
|
|||
uint8_t T[80];
|
||||
RAND_bytes (T, 80);
|
||||
// calculate r = H*(T || publickey || data)
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, T, 80);
|
||||
SHA512_Update (&ctx, publicKeyEncoded, 32);
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestInit_ex (ctx, EVP_sha512(), NULL);
|
||||
EVP_DigestUpdate (ctx, T, 80);
|
||||
EVP_DigestUpdate (ctx, publicKeyEncoded, 32);
|
||||
EVP_DigestUpdate (ctx, buf, len); // data
|
||||
uint8_t digest[64];
|
||||
SHA512_Final (digest, &ctx);
|
||||
unsigned int dl = 64;
|
||||
EVP_DigestFinal_ex (ctx, digest, &dl);
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
BIGNUM * r = DecodeBN<64> (digest);
|
||||
BN_mod (r, r, l, bnCtx); // % l
|
||||
EncodeBN (r, digest, 32);
|
||||
|
@ -183,11 +190,14 @@ namespace crypto
|
|||
uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
|
||||
EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R);
|
||||
// calculate S
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestInit_ex (ctx, EVP_sha512(), NULL);
|
||||
EVP_DigestUpdate (ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
EVP_DigestUpdate (ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
EVP_DigestUpdate (ctx, buf, len); // data
|
||||
dl = 64;
|
||||
EVP_DigestFinal_ex (ctx, digest, &dl);
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
// S = (r + h*a) % l
|
||||
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (privateKey);
|
||||
|
|
|
@ -50,6 +50,16 @@ namespace data
|
|||
if (family) family[0] = 0;
|
||||
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)
|
||||
{
|
||||
|
@ -57,6 +67,9 @@ namespace data
|
|||
LogPrint (eLogError, "Family: Duplicated family name ", cn);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
SSL_free (ssl);
|
||||
|
@ -106,11 +119,17 @@ namespace data
|
|||
memcpy (buf + len, (const uint8_t *)ident, 32);
|
||||
len += 32;
|
||||
auto signatureBufLen = Base64ToByteStream (signature, signatureBuf, 64);
|
||||
if (signatureBufLen)
|
||||
if (signatureBufLen == 64)
|
||||
{
|
||||
ECDSA_SIG * sig = ECDSA_SIG_new();
|
||||
ECDSA_SIG_set0 (sig, BN_bin2bn (signatureBuf, 32, NULL), BN_bin2bn (signatureBuf + 32, 32, NULL));
|
||||
uint8_t sign[72];
|
||||
uint8_t * s = sign;
|
||||
auto l = i2d_ECDSA_SIG (sig, &s);
|
||||
ECDSA_SIG_free(sig);
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, it->second.first);
|
||||
auto ret = EVP_DigestVerify (ctx, signatureBuf, signatureBufLen, buf, len);
|
||||
EVP_DigestVerifyInit (ctx, NULL, EVP_sha256(), NULL, it->second.first);
|
||||
auto ret = EVP_DigestVerify (ctx, sign, l, buf, len) == 1;
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
return ret;
|
||||
}
|
||||
|
@ -137,29 +156,40 @@ namespace data
|
|||
{
|
||||
SSL * ssl = SSL_new (ctx);
|
||||
EVP_PKEY * pkey = SSL_get_privatekey (ssl);
|
||||
EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey);
|
||||
if (ecKey)
|
||||
int curve = 0;
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||
char groupName[20];
|
||||
if (EVP_PKEY_get_group_name(pkey, groupName, sizeof(groupName), NULL) == 1)
|
||||
curve = OBJ_txt2nid (groupName);
|
||||
else
|
||||
curve = -1;
|
||||
#endif
|
||||
if (!curve || curve == NID_X9_62_prime256v1)
|
||||
{
|
||||
auto group = EC_KEY_get0_group (ecKey);
|
||||
if (group)
|
||||
{
|
||||
int curve = EC_GROUP_get_curve_name (group);
|
||||
if (curve == NID_X9_62_prime256v1)
|
||||
{
|
||||
uint8_t signingPrivateKey[32], buf[50], signature[64];
|
||||
i2p::crypto::bn2buf (EC_KEY_get0_private_key (ecKey), signingPrivateKey, 32);
|
||||
i2p::crypto::ECDSAP256Signer signer (signingPrivateKey);
|
||||
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;
|
||||
signer.Sign (buf, len, signature);
|
||||
|
||||
size_t l = 72;
|
||||
EVP_MD_CTX * mdctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestSignInit (mdctx, NULL, EVP_sha256(), NULL, pkey);
|
||||
EVP_DigestSign (mdctx, sign, &l, buf, len);
|
||||
EVP_MD_CTX_destroy (mdctx);
|
||||
|
||||
const uint8_t * s1 = sign;
|
||||
ECDSA_SIG * sig1 = d2i_ECDSA_SIG (NULL, &s1, l);
|
||||
const BIGNUM * r, * s;
|
||||
ECDSA_SIG_get0 (sig1, &r, &s);
|
||||
i2p::crypto::bn2buf (r, signature, 32);
|
||||
i2p::crypto::bn2buf (s, signature + 32, 32);
|
||||
ECDSA_SIG_free(sig1);
|
||||
sig = ByteStreamToBase64 (signature, 64);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -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 = 0, pos;
|
||||
size_t count = 1, pos;
|
||||
while ((pos = line.find (delim)) != line.npos)
|
||||
{
|
||||
count++;
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace data
|
|||
ReadFromBuffer ();
|
||||
}
|
||||
|
||||
void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature)
|
||||
void LeaseSet::Update (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> dest, bool verifySignature)
|
||||
{
|
||||
SetBuffer (buf, len);
|
||||
ReadFromBuffer (false, verifySignature);
|
||||
|
@ -281,28 +281,29 @@ namespace data
|
|||
LogPrint (eLogError, "LeaseSet2: Actual buffer size ", int(len) , " exceeds full buffer size ", int(m_BufferLen));
|
||||
}
|
||||
|
||||
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto):
|
||||
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len,
|
||||
bool storeLeases, std::shared_ptr<LocalDestination> dest, CryptoKeyType preferredCrypto):
|
||||
LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto)
|
||||
{
|
||||
SetBuffer (buf, len);
|
||||
if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||
ReadFromBufferEncrypted (buf, len, nullptr, nullptr);
|
||||
ReadFromBufferEncrypted (buf, len, nullptr, dest, nullptr);
|
||||
else
|
||||
ReadFromBuffer (buf, len);
|
||||
ReadFromBuffer (buf, len, dest);
|
||||
}
|
||||
|
||||
LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key,
|
||||
const uint8_t * secret, CryptoKeyType preferredCrypto):
|
||||
std::shared_ptr<LocalDestination> dest, const uint8_t * secret, CryptoKeyType preferredCrypto):
|
||||
LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto)
|
||||
{
|
||||
ReadFromBufferEncrypted (buf, len, key, secret);
|
||||
ReadFromBufferEncrypted (buf, len, key, dest, secret);
|
||||
}
|
||||
|
||||
void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature)
|
||||
void LeaseSet2::Update (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> dest, bool verifySignature)
|
||||
{
|
||||
SetBuffer (buf, len);
|
||||
if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||
ReadFromBuffer (buf, len, false, verifySignature);
|
||||
ReadFromBuffer (buf, len, dest, false, verifySignature);
|
||||
// TODO: implement encrypted
|
||||
}
|
||||
|
||||
|
@ -312,7 +313,8 @@ namespace data
|
|||
return ExtractPublishedTimestamp (buf, len, expiration) > m_PublishedTimestamp;
|
||||
}
|
||||
|
||||
void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature)
|
||||
void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> dest,
|
||||
bool readIdentity, bool verifySignature)
|
||||
{
|
||||
// standard LS2 header
|
||||
std::shared_ptr<const IdentityEx> identity;
|
||||
|
@ -350,7 +352,7 @@ namespace data
|
|||
switch (m_StoreType)
|
||||
{
|
||||
case NETDB_STORE_TYPE_STANDARD_LEASESET2:
|
||||
s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset);
|
||||
s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset, dest);
|
||||
break;
|
||||
case NETDB_STORE_TYPE_META_LEASESET2:
|
||||
s = ReadMetaLS2TypeSpecificPart (buf + offset, len - offset);
|
||||
|
@ -392,7 +394,8 @@ namespace data
|
|||
return verified;
|
||||
}
|
||||
|
||||
size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len)
|
||||
size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len,
|
||||
std::shared_ptr<LocalDestination> dest)
|
||||
{
|
||||
size_t offset = 0;
|
||||
// properties
|
||||
|
@ -417,7 +420,8 @@ namespace data
|
|||
if (keyType <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // skip PQ keys if not supported
|
||||
#endif
|
||||
{
|
||||
if (keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType)
|
||||
if ((keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) &&
|
||||
(!dest || dest->SupportsEncryptionType (keyType)))
|
||||
{
|
||||
auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
|
||||
if (encryptor)
|
||||
|
@ -498,7 +502,8 @@ namespace data
|
|||
return offset;
|
||||
}
|
||||
|
||||
void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret)
|
||||
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)
|
||||
{
|
||||
size_t offset = 0;
|
||||
// blinded key
|
||||
|
@ -601,7 +606,7 @@ namespace data
|
|||
m_StoreType = innerPlainText[0];
|
||||
SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
|
||||
// parse and verify Layer 2
|
||||
ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
|
||||
ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1, dest);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "LeaseSet2: Unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet");
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace data
|
|||
|
||||
LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true);
|
||||
virtual ~LeaseSet () { delete[] m_EncryptionKey; delete[] m_Buffer; };
|
||||
virtual void Update (const uint8_t * buf, size_t len, bool verifySignature = true);
|
||||
virtual void Update (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> dest, bool verifySignature);
|
||||
virtual bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
void PopulateLeases (); // from buffer
|
||||
|
||||
|
@ -155,31 +155,35 @@ namespace data
|
|||
public:
|
||||
|
||||
LeaseSet2 (uint8_t storeType): LeaseSet (true), m_StoreType (storeType) {}; // for update
|
||||
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD);
|
||||
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<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; };
|
||||
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; };
|
||||
bool IsPublic () const { return m_IsPublic; };
|
||||
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;
|
||||
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;
|
||||
|
||||
// implements RoutingDestination
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
|
||||
CryptoKeyType GetEncryptionType () const { return m_EncryptionType; };
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) const override;
|
||||
CryptoKeyType GetEncryptionType () const override { return m_EncryptionType; };
|
||||
|
||||
private:
|
||||
|
||||
void ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity = true, bool verifySignature = true);
|
||||
void ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret);
|
||||
size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len);
|
||||
void ReadFromBuffer (const uint8_t * buf, size_t len, std::shared_ptr<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);
|
||||
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;
|
||||
uint64_t ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const override;
|
||||
uint64_t ExtractPublishedTimestamp (const uint8_t * buf, size_t len, uint64_t& expiration) const;
|
||||
size_t ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const; // subcredential is subcredential + timestamp, return length of autData without flag
|
||||
|
||||
|
|
|
@ -361,7 +361,7 @@ namespace data
|
|||
{
|
||||
if(it->second->GetExpirationTime() < expires)
|
||||
{
|
||||
it->second->Update (buf, len, false); // signature is verified already
|
||||
it->second->Update (buf, len, nullptr, false); // signature is verified already
|
||||
if (CheckLogLevel (eLogInfo))
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32());
|
||||
updated = true;
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace data
|
|||
const int NETDB_MIN_ROUTERS = 90;
|
||||
const int NETDB_MIN_FLOODFILLS = 5;
|
||||
const int NETDB_MIN_TRANSPORTS = 10 ; // otherwise assume offline
|
||||
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200;
|
||||
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1500;
|
||||
const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD;
|
||||
const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in %
|
||||
const int NETDB_CHECK_FOR_EXPIRATION_UPTIME = 600; // 10 minutes, in seconds
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2025, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -14,6 +14,9 @@
|
|||
#include <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"
|
||||
|
@ -480,9 +483,19 @@ namespace data
|
|||
if (terminator) terminator[0] = 0;
|
||||
}
|
||||
// extract RSA key (we need n only, e = 65537)
|
||||
const RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
|
||||
const BIGNUM * n, * e, * d;
|
||||
EVP_PKEY * pubKey = X509_get_pubkey (cert);
|
||||
const BIGNUM * n = nullptr;
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||
BIGNUM * n1 = BN_new ();
|
||||
if (EVP_PKEY_get_bn_param (pubKey, OSSL_PKEY_PARAM_RSA_N, &n1) > 0)
|
||||
n = n1;
|
||||
#else
|
||||
const RSA * key = EVP_PKEY_get0_RSA (pubKey);
|
||||
const BIGNUM * e, * d;
|
||||
RSA_get0_key(key, &n, &e, &d);
|
||||
#endif
|
||||
if (n)
|
||||
{
|
||||
PublicKey value;
|
||||
i2p::crypto::bn2buf (n, value, 512);
|
||||
if (cn)
|
||||
|
@ -490,6 +503,12 @@ namespace data
|
|||
else
|
||||
LogPrint (eLogError, "Reseed: Can't find CN field in ", filename);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Can't extract RSA key from ", filename);
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||
BN_free (n1);
|
||||
#endif
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -25,7 +25,8 @@ namespace transport
|
|||
m_TerminationTimer (GetService ()), m_CleanupTimer (GetService ()), m_ResendTimer (GetService ()),
|
||||
m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()),
|
||||
m_IsPublished (true), m_IsSyncClockFromPeers (true), m_PendingTimeOffset (0),
|
||||
m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsThroughProxy (false)
|
||||
m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsForcedFirewalled4 (false),
|
||||
m_IsForcedFirewalled6 (false), m_IsThroughProxy (false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -79,6 +80,7 @@ namespace transport
|
|||
if (address->IsV4 ())
|
||||
{
|
||||
found = true;
|
||||
i2p::config::GetOption ("ssu2.firewalled4", m_IsForcedFirewalled4);
|
||||
LogPrint (eLogDebug, "SSU2: Opening IPv4 socket at Start");
|
||||
OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV4, port));
|
||||
boost::asio::post (m_ReceiveService.GetService (),
|
||||
|
@ -91,6 +93,7 @@ namespace transport
|
|||
if (address->IsV6 ())
|
||||
{
|
||||
found = true;
|
||||
i2p::config::GetOption ("ssu2.firewalled6", m_IsForcedFirewalled6);
|
||||
LogPrint (eLogDebug, "SSU2: Opening IPv6 socket at Start");
|
||||
OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV6, port));
|
||||
boost::asio::post (m_ReceiveService.GetService (),
|
||||
|
|
|
@ -79,6 +79,7 @@ namespace transport
|
|||
bool UsesProxy () const { return m_IsThroughProxy; };
|
||||
bool IsSupported (const boost::asio::ip::address& addr) const;
|
||||
uint16_t GetPort (bool v4) const;
|
||||
bool IsForcedFirewalled (bool v4) const { return v4 ? m_IsForcedFirewalled4 : m_IsForcedFirewalled6; }
|
||||
bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true);
|
||||
void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts);
|
||||
std::mt19937& GetRng () { return m_Rng; }
|
||||
|
@ -208,6 +209,7 @@ namespace transport
|
|||
i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor;
|
||||
i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor;
|
||||
i2p::crypto::ChaCha20Context m_ChaCha20;
|
||||
bool m_IsForcedFirewalled4, m_IsForcedFirewalled6;
|
||||
|
||||
// proxy
|
||||
bool m_IsThroughProxy;
|
||||
|
|
|
@ -90,6 +90,9 @@ namespace transport
|
|||
if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ())
|
||||
{
|
||||
m_PeerTestResendTimer.cancel (); // cancel delayed msg 6 if any
|
||||
if (GetServer ().IsForcedFirewalled (GetRemoteEndpoint ().address().is_v4()))
|
||||
// we assume that msg 5 was not received if forced firewalled
|
||||
return;
|
||||
m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ());
|
||||
if (GetAddress ())
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#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"
|
||||
|
@ -41,22 +42,19 @@ namespace crypto
|
|||
|
||||
bool DSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
// calculate SHA1 digest
|
||||
uint8_t digest[20], sign[48];
|
||||
SHA1 (buf, len, digest);
|
||||
// signature
|
||||
DSA_SIG * sig = DSA_SIG_new();
|
||||
DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL));
|
||||
// to DER format
|
||||
uint8_t sign[DSA_SIGNATURE_LENGTH + 8];
|
||||
uint8_t * s = sign;
|
||||
auto l = i2d_DSA_SIG (sig, &s);
|
||||
DSA_SIG_free(sig);
|
||||
// verify
|
||||
auto ctx = EVP_PKEY_CTX_new (m_PublicKey, NULL);
|
||||
EVP_PKEY_verify_init(ctx);
|
||||
EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1());
|
||||
bool ret = EVP_PKEY_verify(ctx, sign, l, digest, 20);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestVerifyInit (ctx, NULL, EVP_sha1(), NULL, m_PublicKey);
|
||||
auto ret = EVP_DigestVerify (ctx, sign, l, buf, len) == 1;
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -75,13 +73,13 @@ namespace crypto
|
|||
|
||||
void DSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[20], sign[48];
|
||||
SHA1 (buf, len, digest);
|
||||
auto ctx = EVP_PKEY_CTX_new (m_PrivateKey, NULL);
|
||||
EVP_PKEY_sign_init(ctx);
|
||||
EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1());
|
||||
size_t l = 48;
|
||||
EVP_PKEY_sign(ctx, sign, &l, digest, 20);
|
||||
uint8_t sign[DSA_SIGNATURE_LENGTH + 8];
|
||||
size_t l = DSA_SIGNATURE_LENGTH + 8;
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestSignInit (ctx, NULL, EVP_sha1(), NULL, m_PrivateKey);
|
||||
EVP_DigestSign (ctx, sign, &l, buf, len);
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
// decode r and s
|
||||
const uint8_t * s1 = sign;
|
||||
DSA_SIG * sig = d2i_DSA_SIG (NULL, &s1, l);
|
||||
const BIGNUM * r, * s;
|
||||
|
@ -89,7 +87,6 @@ namespace crypto
|
|||
bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2);
|
||||
bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2);
|
||||
DSA_SIG_free(sig);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
|
@ -135,7 +132,7 @@ namespace crypto
|
|||
DSA_SIG * sig = DSA_SIG_new();
|
||||
DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL));
|
||||
// DSA verification
|
||||
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey);
|
||||
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey) == 1;
|
||||
DSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
|
@ -175,7 +172,137 @@ namespace crypto
|
|||
}
|
||||
#endif
|
||||
|
||||
#if OPENSSL_EDDSA
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||
ECDSAVerifier::ECDSAVerifier (int curve, size_t keyLen, const EVP_MD * hash):
|
||||
m_Curve(curve), m_KeyLen (keyLen), m_Hash (hash), m_PublicKey (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ECDSAVerifier::~ECDSAVerifier ()
|
||||
{
|
||||
if (m_PublicKey)
|
||||
EVP_PKEY_free (m_PublicKey);
|
||||
}
|
||||
|
||||
void ECDSAVerifier::SetPublicKey (const uint8_t * signingKey)
|
||||
{
|
||||
if (m_PublicKey)
|
||||
{
|
||||
EVP_PKEY_free (m_PublicKey);
|
||||
m_PublicKey = nullptr;
|
||||
}
|
||||
auto plen = GetPublicKeyLen ();
|
||||
std::vector<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
|
||||
|
||||
EDDSA25519Verifier::EDDSA25519Verifier ():
|
||||
m_Pkey (nullptr)
|
||||
{
|
||||
|
@ -198,7 +325,7 @@ namespace crypto
|
|||
{
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, m_Pkey);
|
||||
auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len);
|
||||
auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len) == 1;
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
return ret;
|
||||
}
|
||||
|
@ -207,37 +334,6 @@ namespace crypto
|
|||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
EDDSA25519Verifier::EDDSA25519Verifier ()
|
||||
{
|
||||
}
|
||||
|
||||
EDDSA25519Verifier::~EDDSA25519Verifier ()
|
||||
{
|
||||
}
|
||||
|
||||
void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey)
|
||||
{
|
||||
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[64];
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
|
||||
return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
|
||||
}
|
||||
#endif
|
||||
|
||||
EDDSA25519SignerCompat::EDDSA25519SignerCompat (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
||||
{
|
||||
// expand key
|
||||
|
@ -267,7 +363,6 @@ namespace crypto
|
|||
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||
}
|
||||
|
||||
#if OPENSSL_EDDSA
|
||||
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey):
|
||||
m_Pkey (nullptr), m_Fallback (nullptr)
|
||||
{
|
||||
|
@ -309,7 +404,6 @@ namespace crypto
|
|||
else
|
||||
LogPrint (eLogError, "EdDSA signing key is not set");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x030000000)
|
||||
static const OSSL_PARAM EDDSA25519phParams[] =
|
||||
|
@ -415,7 +509,7 @@ namespace crypto
|
|||
OSSL_PARAM_END
|
||||
};
|
||||
EVP_PKEY_verify_message_init (vctx, sig, params);
|
||||
ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len);
|
||||
ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len) == 1;
|
||||
EVP_SIGNATURE_free (sig);
|
||||
}
|
||||
EVP_PKEY_CTX_free (vctx);
|
||||
|
|
|
@ -92,6 +92,115 @@ 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
|
||||
|
||||
struct SHA256Hash
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
|
@ -154,7 +263,7 @@ namespace crypto
|
|||
auto s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL);
|
||||
ECDSA_SIG_set0(sig, r, s);
|
||||
// ECDSA verification
|
||||
int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey);
|
||||
int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey) == 1;
|
||||
ECDSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
|
@ -217,7 +326,6 @@ namespace crypto
|
|||
}
|
||||
|
||||
// ECDSA_SHA256_P256
|
||||
const size_t ECDSAP256_KEY_LENGTH = 64;
|
||||
typedef ECDSAVerifier<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier;
|
||||
typedef ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer;
|
||||
|
||||
|
@ -227,7 +335,6 @@ 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;
|
||||
|
||||
|
@ -237,7 +344,6 @@ 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;
|
||||
|
||||
|
@ -246,6 +352,7 @@ namespace crypto
|
|||
CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// EdDSA
|
||||
class EDDSA25519Verifier: public Verifier
|
||||
|
@ -263,17 +370,11 @@ namespace crypto
|
|||
|
||||
private:
|
||||
|
||||
#if OPENSSL_EDDSA
|
||||
|
||||
EVP_PKEY * m_Pkey;
|
||||
|
||||
protected:
|
||||
|
||||
EVP_PKEY * GetPkey () const { return m_Pkey; };
|
||||
#else
|
||||
EDDSAPoint m_PublicKey;
|
||||
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
#endif
|
||||
};
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||
|
@ -302,7 +403,6 @@ namespace crypto
|
|||
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
};
|
||||
|
||||
#if OPENSSL_EDDSA
|
||||
class EDDSA25519Signer: public Signer
|
||||
{
|
||||
public:
|
||||
|
@ -322,11 +422,6 @@ namespace crypto
|
|||
EVP_PKEY * m_Pkey;
|
||||
EDDSA25519SignerCompat * m_Fallback;
|
||||
};
|
||||
#else
|
||||
|
||||
typedef EDDSA25519SignerCompat EDDSA25519Signer;
|
||||
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||
class EDDSA25519phSigner: public EDDSA25519Signer
|
||||
|
@ -342,7 +437,6 @@ namespace crypto
|
|||
|
||||
inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
#if OPENSSL_EDDSA
|
||||
EVP_PKEY *pkey = NULL;
|
||||
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_ED25519, NULL);
|
||||
EVP_PKEY_keygen_init (pctx);
|
||||
|
@ -353,11 +447,6 @@ namespace crypto
|
|||
len = EDDSA25519_PRIVATE_KEY_LENGTH;
|
||||
EVP_PKEY_get_raw_private_key (pkey, signingPrivateKey, &len);
|
||||
EVP_PKEY_free (pkey);
|
||||
#else
|
||||
RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH);
|
||||
EDDSA25519Signer signer (signingPrivateKey);
|
||||
memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ namespace stream
|
|||
if (!m_SendStreamID)
|
||||
{
|
||||
m_SendStreamID = packet->GetReceiveStreamID ();
|
||||
if (!m_RemoteIdentity && packet->GetNACKCount () == 8 && // first incoming packet
|
||||
if (!m_RemoteIdentity && !packet->from && packet->GetNACKCount () == 8 && // first incoming packet
|
||||
memcmp (packet->GetNACKs (), m_LocalDestination.GetOwner ()->GetIdentHash (), 32))
|
||||
{
|
||||
LogPrint (eLogWarning, "Streaming: Destination mismatch for ", m_LocalDestination.GetOwner ()->GetIdentHash ().ToBase32 ());
|
||||
|
@ -397,6 +397,7 @@ namespace stream
|
|||
optionData += 2;
|
||||
}
|
||||
|
||||
bool sessionVerified = false;
|
||||
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
||||
{
|
||||
if (m_RemoteLeaseSet) m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity ();
|
||||
|
@ -409,7 +410,24 @@ namespace stream
|
|||
}
|
||||
optionData += m_RemoteIdentity->GetFullLen ();
|
||||
if (!m_RemoteLeaseSet)
|
||||
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
|
||||
{
|
||||
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase32 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
|
||||
if (packet->from) // try to obtain LeaseSet if came from ratchets session
|
||||
m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
}
|
||||
if (packet->from && m_RemoteLeaseSet)
|
||||
{
|
||||
// stream came from ratchets session and static key must match one from LeaseSet
|
||||
uint8_t staticKey[32];
|
||||
m_RemoteLeaseSet->Encrypt (nullptr, staticKey);
|
||||
if (memcmp (packet->from->GetRemoteStaticKey (), staticKey, 32))
|
||||
{
|
||||
LogPrint (eLogError, "Streaming: Remote LeaseSet static key mismatch for stream from ",
|
||||
m_RemoteIdentity->GetIdentHash ().ToBase32 ());
|
||||
return false;
|
||||
}
|
||||
sessionVerified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
|
||||
|
@ -426,6 +444,22 @@ namespace stream
|
|||
LogPrint (eLogInfo, "Streaming: offline signature without identity");
|
||||
return false;
|
||||
}
|
||||
if (sessionVerified)
|
||||
{
|
||||
// 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
|
||||
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)
|
||||
|
@ -448,16 +482,20 @@ namespace stream
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
||||
{
|
||||
bool verified = false;
|
||||
auto signatureLen = m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : m_RemoteIdentity->GetSignatureLen ();
|
||||
if (signatureLen > packet->GetLength ())
|
||||
{
|
||||
LogPrint (eLogError, "Streaming: Signature too big, ", signatureLen, " bytes");
|
||||
return false;
|
||||
}
|
||||
bool verified = sessionVerified;
|
||||
if (!verified) // packet was not verified through session
|
||||
{
|
||||
// verify actual signature
|
||||
if (signatureLen <= 256)
|
||||
{
|
||||
// standard
|
||||
|
@ -480,6 +518,7 @@ namespace stream
|
|||
m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature.data ()) :
|
||||
m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature.data ());
|
||||
}
|
||||
}
|
||||
if (verified)
|
||||
optionData += signatureLen;
|
||||
else
|
||||
|
@ -812,7 +851,7 @@ namespace stream
|
|||
{
|
||||
// initial packet
|
||||
m_Status = eStreamStatusOpen;
|
||||
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());;
|
||||
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming);
|
||||
|
@ -1416,6 +1455,7 @@ namespace stream
|
|||
m_SendTimer.cancel (); // if no ack's in RTO, disable fast retransmit
|
||||
m_IsTimeOutResend = true;
|
||||
m_IsNAcked = false;
|
||||
m_IsClientChoked = false;
|
||||
m_IsResendNeeded = false;
|
||||
m_NumPacketsToSend = 1;
|
||||
ResendPacket (); // send one packet per RTO, waiting for ack
|
||||
|
@ -1538,7 +1578,7 @@ namespace stream
|
|||
}
|
||||
else if (!m_IsClientChoked)
|
||||
SendBuffer ();
|
||||
if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend ();
|
||||
if (!m_IsNAcked && !m_IsResendNeeded && !m_IsClientChoked) ScheduleResend ();
|
||||
if (m_IsClientChoked) ScheduleSend ();
|
||||
}
|
||||
|
||||
|
@ -2053,14 +2093,18 @@ namespace stream
|
|||
}
|
||||
}
|
||||
|
||||
void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
|
||||
void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len,
|
||||
i2p::garlic::ECIESX25519AEADRatchetSession * from)
|
||||
{
|
||||
// unzip it
|
||||
Packet * uncompressed = NewPacket ();
|
||||
uncompressed->offset = 0;
|
||||
uncompressed->len = m_Inflator.Inflate (buf, len, uncompressed->buf, MAX_PACKET_SIZE);
|
||||
if (uncompressed->len)
|
||||
{
|
||||
uncompressed->from = from;
|
||||
HandleNextPacket (uncompressed);
|
||||
}
|
||||
else
|
||||
DeletePacket (uncompressed);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "Garlic.h"
|
||||
#include "Tunnel.h"
|
||||
#include "util.h" // MemoryPool
|
||||
#include "ECIESX25519AEADRatchetSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -88,8 +89,9 @@ namespace stream
|
|||
uint8_t buf[MAX_PACKET_SIZE];
|
||||
uint64_t sendTime;
|
||||
bool resent;
|
||||
i2p::garlic::ECIESX25519AEADRatchetSession * from;
|
||||
|
||||
Packet (): len (0), offset (0), sendTime (0), resent (false) {};
|
||||
Packet (): len (0), offset (0), sendTime (0), resent (false), from (nullptr) {};
|
||||
uint8_t * GetBuffer () { return buf + offset; };
|
||||
size_t GetLength () const { return len > offset ? len - offset : 0; };
|
||||
|
||||
|
@ -340,7 +342,7 @@ namespace stream
|
|||
void SetOwner (std::shared_ptr<i2p::client::ClientDestination> owner) { m_Owner = owner; };
|
||||
uint16_t GetLocalPort () const { return m_LocalPort; };
|
||||
|
||||
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
||||
void HandleDataMessagePayload (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from);
|
||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true, bool gzip = false);
|
||||
|
||||
Packet * NewPacket () { return m_PacketsPool.Acquire(); }
|
||||
|
|
|
@ -86,7 +86,8 @@ namespace client
|
|||
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
||||
}
|
||||
|
||||
void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||
void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len,
|
||||
i2p::garlic::ECIESX25519AEADRatchetSession * from)
|
||||
{
|
||||
uint32_t length = bufbe32toh (buf);
|
||||
if (length > len - 4) length = len - 4;
|
||||
|
@ -623,17 +624,14 @@ namespace client
|
|||
|
||||
void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len)
|
||||
{
|
||||
// get version
|
||||
auto version = ExtractString (buf, len);
|
||||
auto l = version.length () + 1 + 8;
|
||||
uint8_t * payload = new uint8_t[l];
|
||||
constexpr std::string_view version(I2P_VERSION);
|
||||
std::array<uint8_t, version.size() + 8 + 1> payload;
|
||||
// set date
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
htobe64buf (payload, ts);
|
||||
// echo vesrion back
|
||||
PutString (payload + 8, l - 8, version);
|
||||
SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload, l);
|
||||
delete[] payload;
|
||||
htobe64buf (payload.data(), ts);
|
||||
// send our version back
|
||||
PutString (payload.data() + 8, payload.size() - 8, version);
|
||||
SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload.data(), payload.size());
|
||||
}
|
||||
|
||||
void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len)
|
||||
|
|
|
@ -117,7 +117,7 @@ namespace client
|
|||
void CleanupDestination () override;
|
||||
i2p::data::CryptoKeyType GetPreferredCryptoType () const override;
|
||||
// I2CP
|
||||
void HandleDataMessage (const uint8_t * buf, size_t len) override;
|
||||
void HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) override;
|
||||
void CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -11,8 +11,7 @@ int main() {
|
|||
char out[16];
|
||||
|
||||
/* bytes -> b64 */
|
||||
assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0);
|
||||
assert(ByteStreamToBase64(NULL, 0, out, sizeof(out)) == 0);
|
||||
assert(ByteStreamToBase64(NULL, 0) == "");
|
||||
|
||||
assert(Base64EncodingBufferSize(2) == 4);
|
||||
assert(Base64EncodingBufferSize(4) == 8);
|
||||
|
@ -23,19 +22,20 @@ int main() {
|
|||
assert(Base64EncodingBufferSize(12) == 16);
|
||||
assert(Base64EncodingBufferSize(13) == 20);
|
||||
|
||||
assert(ByteStreamToBase64((uint8_t *) in, in_len, out, sizeof(out)) == 8);
|
||||
assert(memcmp(out, "dGVzdA==", 8) == 0);
|
||||
const std::string out_str(ByteStreamToBase64((uint8_t *) in, in_len));
|
||||
assert(out_str.size() == 8);
|
||||
assert(out_str == "dGVzdA==");
|
||||
|
||||
/* b64 -> bytes */
|
||||
assert(Base64ToByteStream(NULL, 0, NULL, 0) == 0);
|
||||
assert(Base64ToByteStream(NULL, 0, (uint8_t *) out, sizeof(out)) == 0);
|
||||
assert(Base64ToByteStream("", NULL, 0) == 0);
|
||||
assert(Base64ToByteStream("", (uint8_t *) out, sizeof(out)) == 0);
|
||||
|
||||
in = "dGVzdA=="; /* valid b64 */
|
||||
assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 4);
|
||||
assert(Base64ToByteStream(in, (uint8_t *) out, sizeof(out)) == 4);
|
||||
assert(memcmp(out, "test", 4) == 0);
|
||||
|
||||
in = "dGVzdA="; /* invalid b64 : not padded */
|
||||
assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 0);
|
||||
assert(Base64ToByteStream(in, (uint8_t *) out, sizeof(out)) == 0);
|
||||
|
||||
in = "dG/z.A=="; /* invalid b64 : char not from alphabet */
|
||||
// assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 0);
|
||||
|
|
|
@ -58,9 +58,7 @@ int main ()
|
|||
uint8_t s[64];
|
||||
i2p::crypto::EDDSA25519Signer signer (key);
|
||||
signer.Sign (msg, 1023, s);
|
||||
#if OPENSSL_EDDSA
|
||||
assert(memcmp (s, sig, 64) == 0);
|
||||
#endif
|
||||
|
||||
i2p::crypto::EDDSA25519Verifier verifier;
|
||||
verifier.SetPublicKey (pub);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue