diff --git a/Makefile.linux b/Makefile.linux index 9db660c2..fa2f2fdf 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -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 diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 2bdfb396..1a459bf8 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -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 diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 5eac08a9..f93c3531 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -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; diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 46d3fc57..98c4b323 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -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(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); diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index f26200a0..83a38816 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -8,9 +8,6 @@ #include #include #include -#ifdef I2LUA -#include -#endif #include #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 > 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 * 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 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 GetSharedFromThis () - { return std::static_pointer_cast(shared_from_this ()); } + std::shared_ptr GetSharedFromThis () { + return std::static_pointer_cast(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 * params); private: diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index c57553d4..4371124e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -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 WrapECIESX25519AEADRatchetMessage (std::shared_ptr 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; + } + } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 56fb48cf..3185a7fc 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -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 CreatePayload (std::shared_ptr 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 m_Destination;// TODO: might not need it - std::list > m_AckRequests; // (key_id, indeX) + std::list > m_AckRequests; // (tagsetid, index) }; + + std::shared_ptr WrapECIESX25519AEADRatchetMessage (std::shared_ptr msg, const uint8_t * key, uint64_t tag); } } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index ae6599fc..fd6e8fee 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -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(elGamal.sessionKey); uint8_t iv[32]; // IV is first 16 bytes diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index ca074aed..5714afce 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -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 diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 3f9633ed..1026eb02 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -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 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 l(m_VerifierMutex); + verifier = m_Verifier; + m_Verifier = nullptr; + } + delete verifier; } std::shared_ptr IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key) diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 9c78f552..663f46b5 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -7,6 +7,7 @@ #include #include #include +#include #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 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 GetIdentity () const = 0; const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); }; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 3dfd6250..85d83bf0 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -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 (); }); } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 6d69f131..5d452d1d 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -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"); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 6c63ef79..b86ed8f2 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -724,7 +724,7 @@ namespace i2p return std::chrono::duration_cast (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; } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index dfc05fe7..28c324c4 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -108,7 +108,7 @@ namespace i2p // implements LocalDestination std::shared_ptr 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 () {}; diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index 49067ce2..55c39c7a 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -5,6 +5,7 @@ #include #include #include +#include #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 GetRemoteIdentity () { return m_RemoteIdentity; }; - void SetRemoteIdentity (std::shared_ptr ident) { m_RemoteIdentity = ident; }; + std::shared_ptr GetRemoteIdentity () + { + std::lock_guard l(m_RemoteIdentityMutex); + return m_RemoteIdentity; + } + void SetRemoteIdentity (std::shared_ptr ident) + { + std::lock_guard 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 m_RemoteIdentity; + mutable std::mutex m_RemoteIdentityMutex; std::shared_ptr m_DHKeysPair; // X - for client and Y - for server size_t m_NumSentBytes, m_NumReceivedBytes; bool m_IsOutgoing; diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 9dacddac..879ee2d3 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -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; diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index b3e3c7d2..7256b2db 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -88,8 +88,6 @@ namespace tunnel } if (m_LocalDestination) m_LocalDestination->SetLeaseSetUpdated (); - - OnTunnelBuildResult(createdTunnel, eBuildResultOkay); } void TunnelPool::TunnelExpired (std::shared_ptr expiredTunnel) @@ -112,8 +110,6 @@ namespace tunnel std::unique_lock 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, TunnelBuildResult result) - { - auto peers = tunnel->GetPeers(); - if(m_CustomPeerSelector) m_CustomPeerSelector->OnBuildResult(peers, tunnel->IsInbound(), result); - } } } diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index fc46930c..d6fb91cc 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -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 Peer; typedef std::vector 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 GetLowestLatencyInboundTunnel(std::shared_ptr exclude=nullptr) const; std::shared_ptr GetLowestLatencyOutboundTunnel(std::shared_ptr exclude=nullptr) const; - void OnTunnelBuildResult(std::shared_ptr tunnel, TunnelBuildResult result); - // for overriding tunnel peer selection std::shared_ptr SelectNextHop (std::shared_ptr prevHop) const; diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index eec21f06..f4c8a91e 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -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); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index f675318f..7f590555 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -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 GetIdentity () const { return m_Identity; }; diff --git a/libi2pd_client/MatchedDestination.cpp b/libi2pd_client/MatchedDestination.cpp index 3d75a3ca..5cec178f 100644 --- a/libi2pd_client/MatchedDestination.cpp +++ b/libi2pd_client/MatchedDestination.cpp @@ -94,10 +94,5 @@ namespace client } return true; } - - bool MatchedTunnelDestination::OnBuildResult(const i2p::tunnel::Path & path, bool inbound, i2p::tunnel::TunnelBuildResult result) - { - return true; - } } } diff --git a/libi2pd_client/MatchedDestination.h b/libi2pd_client/MatchedDestination.h index 67b874e6..9d61799a 100644 --- a/libi2pd_client/MatchedDestination.h +++ b/libi2pd_client/MatchedDestination.h @@ -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();