mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-17 07:29:58 +00:00
commit
ddf3774aec
@ -1,5 +1,5 @@
|
||||
# set defaults instead redefine
|
||||
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation
|
||||
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation -Wno-psabi
|
||||
LDFLAGS ?= ${LD_DEBUG}
|
||||
|
||||
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
|
||||
|
@ -19,7 +19,6 @@ option(WITH_GUI "Include GUI (currently MS Windows only)" ON)
|
||||
option(WITH_MESHNET "Build for cjdns test network" OFF)
|
||||
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
|
||||
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
|
||||
option(WITH_I2LUA "Build for i2lua" OFF)
|
||||
|
||||
# paths
|
||||
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
|
||||
@ -88,10 +87,6 @@ if (WIN32 OR MSYS)
|
||||
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
|
||||
endif ()
|
||||
|
||||
if (WITH_I2LUA)
|
||||
add_definitions(-DI2LUA)
|
||||
endif()
|
||||
|
||||
add_library(libi2pd ${LIBI2PD_SRC})
|
||||
set_target_properties(libi2pd PROPERTIES PREFIX "")
|
||||
|
||||
@ -414,7 +409,6 @@ message(STATUS " PCH : ${WITH_PCH}")
|
||||
message(STATUS " MESHNET : ${WITH_MESHNET}")
|
||||
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
||||
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
||||
message(STATUS " I2LUA : ${WITH_I2LUA}")
|
||||
message(STATUS "---------------------------------------")
|
||||
|
||||
#Handle paths nicely
|
||||
|
@ -1141,6 +1141,8 @@ namespace http {
|
||||
void HTTPConnection::SendReply (HTTPRes& reply, std::string& content)
|
||||
{
|
||||
reply.add_header("X-Frame-Options", "SAMEORIGIN");
|
||||
reply.add_header("X-Content-Type-Options", "nosniff");
|
||||
reply.add_header("X-XSS-Protection", "1; mode=block");
|
||||
reply.add_header("Content-Type", "text/html");
|
||||
reply.body = content;
|
||||
|
||||
|
@ -931,32 +931,6 @@ namespace client
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef I2LUA
|
||||
void ClientDestination::Ready(ReadyPromise & p)
|
||||
{
|
||||
ScheduleCheckForReady(&p);
|
||||
}
|
||||
|
||||
void ClientDestination::ScheduleCheckForReady(ReadyPromise * p)
|
||||
{
|
||||
// tick every 100ms
|
||||
m_ReadyChecker.expires_from_now(boost::posix_time::milliseconds(100));
|
||||
m_ReadyChecker.async_wait([&, p] (const boost::system::error_code & ecode) {
|
||||
HandleCheckForReady(ecode, p);
|
||||
});
|
||||
}
|
||||
|
||||
void ClientDestination::HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p)
|
||||
{
|
||||
if(ecode) // error happened
|
||||
p->set_value(nullptr);
|
||||
else if(IsReady()) // we are ready
|
||||
p->set_value(std::shared_ptr<ClientDestination>(this));
|
||||
else // we are not ready
|
||||
ScheduleCheckForReady(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
uint32_t length = bufbe32toh (buf);
|
||||
@ -1173,7 +1147,7 @@ namespace client
|
||||
if (m_DatagramDestination) m_DatagramDestination->CleanUp ();
|
||||
}
|
||||
|
||||
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
||||
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||
{
|
||||
if (m_Decryptor)
|
||||
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||
|
@ -8,9 +8,6 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#ifdef I2LUA
|
||||
#include <future>
|
||||
#endif
|
||||
#include <boost/asio.hpp>
|
||||
#include "Identity.h"
|
||||
#include "TunnelPool.h"
|
||||
@ -196,13 +193,6 @@ namespace client
|
||||
class ClientDestination: public LeaseSetDestination
|
||||
{
|
||||
public:
|
||||
#ifdef I2LUA
|
||||
// type for informing that a client destination is ready
|
||||
typedef std::promise<std::shared_ptr<ClientDestination> > ReadyPromise;
|
||||
// informs promise with shared_from_this() when this destination is ready to use
|
||||
// if cancelled before ready, informs promise with nullptr
|
||||
void Ready(ReadyPromise & p);
|
||||
#endif
|
||||
|
||||
ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
|
||||
bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||
@ -237,7 +227,7 @@ namespace client
|
||||
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
|
||||
|
||||
// implements LocalDestination
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { return m_EncryptionKeyType == keyType; };
|
||||
const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { return m_EncryptionPublicKey; };
|
||||
@ -251,14 +241,10 @@ namespace client
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<ClientDestination> GetSharedFromThis ()
|
||||
{ return std::static_pointer_cast<ClientDestination>(shared_from_this ()); }
|
||||
std::shared_ptr<ClientDestination> GetSharedFromThis () {
|
||||
return std::static_pointer_cast<ClientDestination>(shared_from_this ());
|
||||
}
|
||||
void PersistTemporaryKeys ();
|
||||
#ifdef I2LUA
|
||||
void ScheduleCheckForReady(ReadyPromise * p);
|
||||
void HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p);
|
||||
#endif
|
||||
|
||||
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
|
||||
|
||||
private:
|
||||
|
@ -138,7 +138,7 @@ namespace garlic
|
||||
MixHash (m_Aepk, 32); // h = SHA256(h || aepk)
|
||||
|
||||
uint8_t sharedSecret[32];
|
||||
GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr); // x25519(bsk, aepk)
|
||||
GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET); // x25519(bsk, aepk)
|
||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||
|
||||
// decrypt flags/static
|
||||
@ -160,7 +160,7 @@ namespace garlic
|
||||
{
|
||||
// static key, fs is apk
|
||||
memcpy (m_RemoteStaticKey, fs, 32);
|
||||
GetOwner ()->Decrypt (fs, sharedSecret, nullptr); // x25519(bsk, apk)
|
||||
GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET); // x25519(bsk, apk)
|
||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||
}
|
||||
else // all zeros flags
|
||||
@ -211,7 +211,7 @@ namespace garlic
|
||||
case eECIESx25519BlkAckRequest:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: ack request");
|
||||
m_AckRequests.push_back ( {bufbe16toh (buf + offset), index});
|
||||
m_AckRequests.push_back ({0, index}); // TODO: use actual tagsetid
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -250,7 +250,7 @@ namespace garlic
|
||||
MixHash (out + offset, 48); // h = SHA256(h || ciphertext)
|
||||
offset += 48;
|
||||
// KDF2
|
||||
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr); // x25519 (ask, bpk)
|
||||
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET); // x25519 (ask, bpk)
|
||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||
// encrypt payload
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt
|
||||
@ -298,7 +298,8 @@ namespace garlic
|
||||
return false;
|
||||
}
|
||||
MixHash (out + offset, 16); // h = SHA256(h || ciphertext)
|
||||
out += 16;
|
||||
offset += 16;
|
||||
memcpy (m_NSRHeader, out, 56); // for possible next NSR
|
||||
// KDF for payload
|
||||
uint8_t keydata[64];
|
||||
i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64)
|
||||
@ -308,18 +309,33 @@ namespace garlic
|
||||
m_SendTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
|
||||
m_SendTagset.NextSessionTagRatchet ();
|
||||
GenerateMoreReceiveTags (GetOwner ()->GetNumTags ());
|
||||
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
|
||||
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", m_NSRKey, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
|
||||
// encrypt payload
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, keydata, nonce, out + offset, len + 16, true)) // encrypt
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + offset, len + 16, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
||||
LogPrint (eLogWarning, "Garlic: NSR payload section AEAD encryption failed");
|
||||
return false;
|
||||
}
|
||||
m_State = eSessionStateEstablished;
|
||||
m_State = eSessionStateNewSessionReplySent;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||
{
|
||||
// we are Bob and sent NSR already
|
||||
memcpy (out, m_NSRHeader, 56);
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (0, nonce);
|
||||
// encrypt payload
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + 56, len + 16, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Next NSR payload section AEAD encryption failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len)
|
||||
{
|
||||
// we are Alice
|
||||
@ -339,7 +355,7 @@ namespace garlic
|
||||
uint8_t sharedSecret[32];
|
||||
m_EphemeralKeys.Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk)
|
||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32)
|
||||
GetOwner ()->Decrypt (bepk, sharedSecret, nullptr); // x25519 (ask, bepk)
|
||||
GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET); // x25519 (ask, bepk)
|
||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (0, nonce);
|
||||
@ -419,6 +435,11 @@ namespace garlic
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
switch (m_State)
|
||||
{
|
||||
case eSessionStateNewSessionReplySent:
|
||||
m_State = eSessionStateEstablished;
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
case eSessionStateEstablished:
|
||||
return HandleExistingSessionMessage (buf, len, index);
|
||||
case eSessionStateNew:
|
||||
@ -456,6 +477,11 @@ namespace garlic
|
||||
return nullptr;
|
||||
len += 72;
|
||||
break;
|
||||
case eSessionStateNewSessionReplySent:
|
||||
if (!NextNewSessionReplyMessage (payload.data (), payload.size (), buf, m->maxLen))
|
||||
return nullptr;
|
||||
len += 72;
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
@ -597,6 +623,41 @@ namespace garlic
|
||||
CleanupUnconfirmedLeaseSet (ts);
|
||||
return ts > m_LastActivityTimestamp + ECIESX25519_EXPIRATION_TIMEOUT;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519AEADRatchetMessage (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
auto m = NewI2NPMessage ();
|
||||
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
|
||||
uint8_t nonce[12];
|
||||
memset (nonce, 0, 12); // n = 0
|
||||
size_t offset = 0;
|
||||
memcpy (buf + offset, &tag, 8); offset += 8;
|
||||
auto payload = buf + offset;
|
||||
uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1;
|
||||
size_t len = cloveSize + 3;
|
||||
payload[0] = eECIESx25519BlkGalicClove; // clove type
|
||||
htobe16buf (payload + 1, cloveSize); // size
|
||||
payload += 3;
|
||||
*payload = 0; payload++; // flag and delivery instructions
|
||||
*payload = msg->GetTypeID (); // I2NP msg type
|
||||
htobe32buf (payload + 1, msg->GetMsgID ()); // msgID
|
||||
htobe32buf (payload + 5, msg->GetExpiration ()/1000); // expiration in seconds
|
||||
memcpy (payload + 9, msg->GetPayload (), msg->GetPayloadLength ());
|
||||
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len, buf, 8, key, nonce, buf + offset, len + 16, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
||||
return nullptr;
|
||||
}
|
||||
offset += len + 16;
|
||||
|
||||
htobe32buf (m->GetPayload (), offset);
|
||||
m->len += offset + 4;
|
||||
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ namespace garlic
|
||||
eSessionStateNew =0,
|
||||
eSessionStateNewSessionReceived,
|
||||
eSessionStateNewSessionSent,
|
||||
eSessionStateNewSessionReplySent,
|
||||
eSessionStateEstablished
|
||||
};
|
||||
|
||||
@ -106,6 +107,7 @@ namespace garlic
|
||||
|
||||
bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||
bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||
bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||
bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||
|
||||
std::vector<uint8_t> CreatePayload (std::shared_ptr<const I2NPMessage> msg);
|
||||
@ -117,14 +119,17 @@ namespace garlic
|
||||
private:
|
||||
|
||||
uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32];
|
||||
uint8_t m_Aepk[32]; // Alice's ephemeral keys TODO: for incoming only
|
||||
uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only
|
||||
uint8_t m_NSRHeader[56], m_NSRKey[32]; // new session reply, for incoming only
|
||||
i2p::crypto::X25519Keys m_EphemeralKeys;
|
||||
SessionState m_State = eSessionStateNew;
|
||||
uint64_t m_LastActivityTimestamp = 0; // incoming
|
||||
RatchetTagSet m_SendTagset, m_ReceiveTagset;
|
||||
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
|
||||
std::list<std::pair<uint16_t, int> > m_AckRequests; // (key_id, indeX)
|
||||
std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index)
|
||||
};
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519AEADRatchetMessage (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,7 +495,7 @@ namespace garlic
|
||||
}
|
||||
// otherwise assume ElGamal/AES
|
||||
ElGamalBlock elGamal;
|
||||
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx))
|
||||
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL))
|
||||
{
|
||||
auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
|
||||
uint8_t iv[32]; // IV is first 16 bytes
|
||||
|
@ -95,6 +95,7 @@ namespace i2p
|
||||
// DatabaseLookup flags
|
||||
const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01;
|
||||
const uint8_t DATABASE_LOOKUP_ENCRYPTION_FLAG = 0x02;
|
||||
const uint8_t DATABASE_LOOKUP_ECIES_FLAG = 0x10;
|
||||
const uint8_t DATABASE_LOOKUP_TYPE_FLAGS_MASK = 0x0C;
|
||||
const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0;
|
||||
const uint8_t DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP = 0x04; // 0100
|
||||
|
@ -34,12 +34,11 @@ namespace data
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx ():
|
||||
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType):
|
||||
m_IsVerifierCreated (false)
|
||||
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType)
|
||||
{
|
||||
memcpy (m_StandardIdentity.publicKey, publicKey, 256); // publicKey in awlays assumed 256 regardless actual size, padding must be taken care of
|
||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
@ -141,19 +140,19 @@ namespace data
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx (const uint8_t * buf, size_t len):
|
||||
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
{
|
||||
FromBuffer (buf, len);
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx (const IdentityEx& other):
|
||||
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx (const Identity& standard):
|
||||
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
{
|
||||
*this = standard;
|
||||
}
|
||||
@ -161,6 +160,7 @@ namespace data
|
||||
IdentityEx::~IdentityEx ()
|
||||
{
|
||||
delete[] m_ExtendedBuffer;
|
||||
delete m_Verifier;
|
||||
}
|
||||
|
||||
IdentityEx& IdentityEx::operator=(const IdentityEx& other)
|
||||
@ -178,8 +178,8 @@ namespace data
|
||||
else
|
||||
m_ExtendedBuffer = nullptr;
|
||||
|
||||
delete m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
m_IsVerifierCreated = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -193,8 +193,8 @@ namespace data
|
||||
m_ExtendedBuffer = nullptr;
|
||||
m_ExtendedLen = 0;
|
||||
|
||||
delete m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
m_IsVerifierCreated = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -233,6 +233,7 @@ namespace data
|
||||
}
|
||||
SHA256(buf, GetFullLen (), m_IdentHash);
|
||||
|
||||
delete m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
|
||||
return GetFullLen ();
|
||||
@ -381,33 +382,27 @@ namespace data
|
||||
|
||||
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
|
||||
{
|
||||
if (!m_Verifier)
|
||||
bool del = false;
|
||||
{
|
||||
auto created = m_IsVerifierCreated.exchange (true);
|
||||
if (!created)
|
||||
m_Verifier.reset (verifier);
|
||||
std::lock_guard<std::mutex> l(m_VerifierMutex);
|
||||
if (!m_Verifier)
|
||||
m_Verifier = verifier;
|
||||
else
|
||||
{
|
||||
delete verifier;
|
||||
int count = 0;
|
||||
while (!m_Verifier && count < 500) // 5 seconds
|
||||
{
|
||||
std::this_thread::sleep_for (std::chrono::milliseconds(10));
|
||||
count++;
|
||||
}
|
||||
if (!m_Verifier)
|
||||
LogPrint (eLogError, "Identity: couldn't get verifier in 5 seconds");
|
||||
}
|
||||
del = true;
|
||||
}
|
||||
else
|
||||
if (del)
|
||||
delete verifier;
|
||||
}
|
||||
|
||||
void IdentityEx::DropVerifier () const
|
||||
{
|
||||
// TODO: potential race condition with Verify
|
||||
m_IsVerifierCreated = false;
|
||||
m_Verifier = nullptr;
|
||||
i2p::crypto::Verifier * verifier;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_VerifierMutex);
|
||||
verifier = m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
}
|
||||
delete verifier;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include "Base.h"
|
||||
#include "Signature.h"
|
||||
#include "CryptoKey.h"
|
||||
@ -125,8 +126,8 @@ namespace data
|
||||
|
||||
Identity m_StandardIdentity;
|
||||
IdentHash m_IdentHash;
|
||||
mutable std::unique_ptr<i2p::crypto::Verifier> m_Verifier;
|
||||
mutable std::atomic_bool m_IsVerifierCreated; // make sure we don't create twice
|
||||
mutable i2p::crypto::Verifier * m_Verifier = nullptr;
|
||||
mutable std::mutex m_VerifierMutex;
|
||||
size_t m_ExtendedLen;
|
||||
uint8_t * m_ExtendedBuffer;
|
||||
};
|
||||
@ -224,7 +225,7 @@ namespace data
|
||||
public:
|
||||
|
||||
virtual ~LocalDestination() {};
|
||||
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const = 0;
|
||||
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL) const = 0;
|
||||
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
|
||||
|
||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||
|
@ -706,9 +706,13 @@ namespace transport
|
||||
// ready to communicate
|
||||
auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already
|
||||
SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ());
|
||||
m_Server.AddNTCP2Session (shared_from_this (), true);
|
||||
Established ();
|
||||
ReceiveLength ();
|
||||
if (m_Server.AddNTCP2Session (shared_from_this (), true))
|
||||
{
|
||||
Established ();
|
||||
ReceiveLength ();
|
||||
}
|
||||
else
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
Terminate ();
|
||||
@ -1258,8 +1262,11 @@ namespace transport
|
||||
if (it != m_NTCP2Sessions.end ())
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: session to ", ident.ToBase64 (), " already exists");
|
||||
session->Terminate();
|
||||
return false;
|
||||
if (incoming)
|
||||
// replace by new session
|
||||
it->second->Terminate ();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
m_NTCP2Sessions.insert (std::make_pair (ident, session));
|
||||
return true;
|
||||
@ -1301,6 +1308,8 @@ namespace transport
|
||||
});
|
||||
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer));
|
||||
}
|
||||
else
|
||||
conn->Terminate ();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,9 @@
|
||||
#include "NTCP2.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Garlic.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "ECIESX25519AEADRatchetSession.h"
|
||||
#include "Config.h"
|
||||
#include "NetDb.hpp"
|
||||
|
||||
using namespace i2p::transport;
|
||||
|
||||
@ -949,10 +950,20 @@ namespace data
|
||||
const uint8_t numTags = excluded[32];
|
||||
if (numTags)
|
||||
{
|
||||
const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag
|
||||
i2p::garlic::ElGamalAESSession garlic (sessionKey, sessionTag);
|
||||
replyMsg = garlic.WrapSingleMessage (replyMsg);
|
||||
if(replyMsg == nullptr) LogPrint(eLogError, "NetDb: failed to wrap message");
|
||||
if (flag & DATABASE_LOOKUP_ECIES_FLAG)
|
||||
{
|
||||
uint64_t tag;
|
||||
memcpy (&tag, excluded + 33, 8);
|
||||
replyMsg = i2p::garlic::WrapECIESX25519AEADRatchetMessage (replyMsg, sessionKey, tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag
|
||||
i2p::garlic::ElGamalAESSession garlic (sessionKey, sessionTag);
|
||||
replyMsg = garlic.WrapSingleMessage (replyMsg);
|
||||
}
|
||||
if (!replyMsg)
|
||||
LogPrint (eLogError, "NetDb: failed to wrap message");
|
||||
}
|
||||
else
|
||||
LogPrint(eLogWarning, "NetDb: encrypted reply requested but no tags provided");
|
||||
|
@ -724,7 +724,7 @@ namespace i2p
|
||||
return std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now() - m_StartupTime).count ();
|
||||
}
|
||||
|
||||
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
||||
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||
{
|
||||
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ namespace i2p
|
||||
|
||||
// implements LocalDestination
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||
void SetLeaseSetUpdated () {};
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include "Identity.h"
|
||||
#include "Crypto.h"
|
||||
#include "RouterInfo.h"
|
||||
@ -67,8 +68,16 @@ namespace transport
|
||||
|
||||
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () { return m_RemoteIdentity; };
|
||||
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) { m_RemoteIdentity = ident; };
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity ()
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex);
|
||||
return m_RemoteIdentity;
|
||||
}
|
||||
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex);
|
||||
m_RemoteIdentity = ident;
|
||||
}
|
||||
|
||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||
@ -85,6 +94,7 @@ namespace transport
|
||||
protected:
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
||||
mutable std::mutex m_RemoteIdentityMutex;
|
||||
std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
|
||||
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||
bool m_IsOutgoing;
|
||||
|
@ -576,7 +576,6 @@ namespace tunnel
|
||||
for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();)
|
||||
{
|
||||
auto tunnel = it->second;
|
||||
auto pool = tunnel->GetTunnelPool();
|
||||
switch (tunnel->GetState ())
|
||||
{
|
||||
case eTunnelStatePending:
|
||||
@ -599,8 +598,6 @@ namespace tunnel
|
||||
hop = hop->next;
|
||||
}
|
||||
}
|
||||
// for i2lua
|
||||
if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultTimeout);
|
||||
// delete
|
||||
it = pendingTunnels.erase (it);
|
||||
m_NumFailedTunnelCreations++;
|
||||
@ -610,9 +607,6 @@ namespace tunnel
|
||||
break;
|
||||
case eTunnelStateBuildFailed:
|
||||
LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted");
|
||||
// for i2lua
|
||||
if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultRejected);
|
||||
|
||||
it = pendingTunnels.erase (it);
|
||||
m_NumFailedTunnelCreations++;
|
||||
break;
|
||||
|
@ -88,8 +88,6 @@ namespace tunnel
|
||||
}
|
||||
if (m_LocalDestination)
|
||||
m_LocalDestination->SetLeaseSetUpdated ();
|
||||
|
||||
OnTunnelBuildResult(createdTunnel, eBuildResultOkay);
|
||||
}
|
||||
|
||||
void TunnelPool::TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel)
|
||||
@ -112,8 +110,6 @@ namespace tunnel
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
m_OutboundTunnels.insert (createdTunnel);
|
||||
}
|
||||
OnTunnelBuildResult(createdTunnel, eBuildResultOkay);
|
||||
|
||||
//CreatePairedInboundTunnel (createdTunnel);
|
||||
}
|
||||
|
||||
@ -596,11 +592,5 @@ namespace tunnel
|
||||
}
|
||||
return tun;
|
||||
}
|
||||
|
||||
void TunnelPool::OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result)
|
||||
{
|
||||
auto peers = tunnel->GetPeers();
|
||||
if(m_CustomPeerSelector) m_CustomPeerSelector->OnBuildResult(peers, tunnel->IsInbound(), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,6 @@ namespace tunnel
|
||||
class InboundTunnel;
|
||||
class OutboundTunnel;
|
||||
|
||||
|
||||
enum TunnelBuildResult {
|
||||
eBuildResultOkay, // tunnel was built okay
|
||||
eBuildResultRejected, // tunnel build was explicitly rejected
|
||||
eBuildResultTimeout // tunnel build timed out
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer;
|
||||
typedef std::vector<Peer> Path;
|
||||
|
||||
@ -38,7 +31,6 @@ namespace tunnel
|
||||
{
|
||||
virtual ~ITunnelPeerSelector() {};
|
||||
virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
|
||||
virtual bool OnBuildResult(const Path & peers, bool isInbound, TunnelBuildResult result) = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -98,8 +90,6 @@ namespace tunnel
|
||||
std::shared_ptr<InboundTunnel> GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude=nullptr) const;
|
||||
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const;
|
||||
|
||||
void OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result);
|
||||
|
||||
// for overriding tunnel peer selection
|
||||
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
|
||||
|
||||
|
@ -59,7 +59,7 @@ namespace client
|
||||
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), m_EncryptionPrivateKey);
|
||||
}
|
||||
|
||||
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
||||
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||
{
|
||||
if (m_Decryptor)
|
||||
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||
|
@ -80,7 +80,7 @@ namespace client
|
||||
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
|
||||
|
||||
// implements LocalDestination
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { return m_EncryptionKeyType == keyType; };
|
||||
// TODO: implement GetEncryptionPublicKey
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; };
|
||||
|
@ -94,10 +94,5 @@ namespace client
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MatchedTunnelDestination::OnBuildResult(const i2p::tunnel::Path & path, bool inbound, i2p::tunnel::TunnelBuildResult result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ namespace client
|
||||
void Stop();
|
||||
|
||||
bool SelectPeers(i2p::tunnel::Path & peers, int hops, bool inbound);
|
||||
bool OnBuildResult(const i2p::tunnel::Path & peers, bool inbound, i2p::tunnel::TunnelBuildResult result);
|
||||
|
||||
private:
|
||||
void ResolveCurrentLeaseSet();
|
||||
|
Loading…
x
Reference in New Issue
Block a user