Merge remote-tracking branch 'purple/openssl' into fix-ntcp-threading-race

pull/1149/head
Jeff Becker 6 years ago
commit ff5c26adf2
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -30,12 +30,12 @@ ifneq (, $(findstring darwin, $(SYS)))
else
include Makefile.osx
endif
else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.linux
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.bsd
else ifneq (, $(findstring linux, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.linux
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32Service.cpp Win32/Win32App.cpp
include Makefile.mingw

@ -94,13 +94,17 @@ endif()
add_library(libi2pd ${LIBI2PD_SRC})
set_target_properties(libi2pd PROPERTIES PREFIX "")
install(TARGETS libi2pd
EXPORT libi2pd
ARCHIVE DESTINATION lib
COMPONENT Libraries)
if (WITH_LIBRARY)
install(TARGETS libi2pd
EXPORT libi2pd
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
COMPONENT Libraries)
# TODO Make libi2pd available to 3rd party projects via CMake as imported target
# FIXME This pulls stdafx
# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
set (CLIENT_SRC
"${LIBI2PD_CLIENT_SRC_DIR}/AddressBook.cpp"
@ -119,7 +123,17 @@ set (CLIENT_SRC
if(WITH_WEBSOCKETS)
list (APPEND CLIENT_SRC "${LIBI2PD_CLIENT_SRC_DIR}/Websocket.cpp")
endif ()
add_library(i2pdclient ${CLIENT_SRC})
add_library(libi2pdclient ${CLIENT_SRC})
set_target_properties(libi2pdclient PROPERTIES PREFIX "")
if (WITH_LIBRARY)
install(TARGETS libi2pdclient
EXPORT libi2pdclient
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
COMPONENT Libraries)
endif()
set(DAEMON_SRC_DIR ../daemon)
@ -303,7 +317,7 @@ if (WITH_PCH)
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
target_compile_options(libi2pd PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
target_compile_options(i2pdclient PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
target_compile_options(libi2pdclient PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
else()
string(TOUPPER ${CMAKE_BUILD_TYPE} BTU)
get_directory_property(DEFS DEFINITIONS)
@ -312,12 +326,12 @@ if (WITH_PCH)
COMMAND ${CMAKE_CXX_COMPILER} ${FLAGS} -c ${CMAKE_CURRENT_SOURCE_DIR}/../libi2pd/stdafx.h -o ${CMAKE_BINARY_DIR}/stdafx.h.gch
)
target_compile_options(libi2pd PRIVATE -include libi2pd/stdafx.h)
target_compile_options(i2pdclient PRIVATE -include libi2pd/stdafx.h)
target_compile_options(libi2pdclient PRIVATE -include libi2pd/stdafx.h)
endif()
target_link_libraries(libi2pd stdafx)
endif()
target_link_libraries(i2pdclient libi2pd)
target_link_libraries(libi2pdclient libi2pd)
find_package ( Boost COMPONENTS system filesystem program_options date_time REQUIRED )
if(NOT DEFINED Boost_INCLUDE_DIRS)
@ -450,7 +464,7 @@ if (WITH_BINARY)
if (WITH_STATIC)
set(DL_LIB ${CMAKE_DL_LIBS})
endif()
target_link_libraries( "${PROJECT_NAME}" libi2pd i2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
target_link_libraries( "${PROJECT_NAME}" libi2pd libi2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set (APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")

@ -8,6 +8,8 @@ User=i2pd
Group=i2pd
RuntimeDirectory=i2pd
RuntimeDirectoryMode=0700
LogsDirectory=i2pd
LogsDirectoryMode=0700
Type=simple
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/kill -HUP $MAINPID

@ -65,6 +65,7 @@ namespace client
m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler;
m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler;
// I2PControl
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
@ -92,6 +93,14 @@ namespace client
// NetworkSetting
m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlService::InboundBandwidthLimit;
m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlService::OutboundBandwidthLimit;
// ClientServicesInfo
m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler;
m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler;
m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler;
m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler;
m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler;
m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler;
}
I2PControlService::~I2PControlService ()
@ -289,6 +298,13 @@ namespace client
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
}
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const
{
std::ostringstream buf;
boost::property_tree::write_json (buf, value, false);
ss << "\"" << name << "\":" << buf.str();
}
void I2PControlService::SendResponse (std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
{
@ -457,6 +473,7 @@ namespace client
InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
}
// RouterManager
void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
@ -586,5 +603,178 @@ namespace client
}
EVP_PKEY_free (pkey);
}
// ClientServicesInfo
void I2PControlService::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
for (auto it = params.begin (); it != params.end (); it++)
{
LogPrint (eLogDebug, "I2PControl: ClientServicesInfo request: ", it->first);
auto it1 = m_ClientServicesInfoHandlers.find (it->first);
if (it1 != m_ClientServicesInfoHandlers.end ())
{
if (it != params.begin ()) results << ",";
(this->*(it1->second))(results);
}
else
LogPrint (eLogError, "I2PControl: ClientServicesInfo unknown request ", it->first);
}
}
void I2PControlService::I2PTunnelInfoHandler (std::ostringstream& results)
{
boost::property_tree::ptree pt;
boost::property_tree::ptree client_tunnels, server_tunnels;
for (auto& it: i2p::client::context.GetClientTunnels ())
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
boost::property_tree::ptree ct;
ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
client_tunnels.add_child(it.second->GetName (), ct);
}
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
if (!serverTunnels.empty ()) {
for (auto& it: serverTunnels)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
boost::property_tree::ptree st;
st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
st.put("port", it.second->GetLocalPort ());
server_tunnels.add_child(it.second->GetName (), st);
}
}
auto& clientForwards = i2p::client::context.GetClientForwards ();
if (!clientForwards.empty ())
{
for (auto& it: clientForwards)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
boost::property_tree::ptree ct;
ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
client_tunnels.add_child(it.second->GetName (), ct);
}
}
auto& serverForwards = i2p::client::context.GetServerForwards ();
if (!serverForwards.empty ())
{
for (auto& it: serverForwards)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
boost::property_tree::ptree st;
st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
server_tunnels.add_child(it.second->GetName (), st);
}
}
pt.add_child("client", client_tunnels);
pt.add_child("server", server_tunnels);
InsertParam (results, "I2PTunnel", pt);
}
void I2PControlService::HTTPProxyInfoHandler (std::ostringstream& results)
{
boost::property_tree::ptree pt;
auto httpProxy = i2p::client::context.GetHttpProxy ();
if (httpProxy)
{
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
pt.put("enabled", true);
pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
}
else
pt.put("enabled", false);
InsertParam (results, "HTTPProxy", pt);
}
void I2PControlService::SOCKSInfoHandler (std::ostringstream& results)
{
boost::property_tree::ptree pt;
auto socksProxy = i2p::client::context.GetSocksProxy ();
if (socksProxy)
{
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
pt.put("enabled", true);
pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
}
else
pt.put("enabled", false);
InsertParam (results, "SOCKS", pt);
}
void I2PControlService::SAMInfoHandler (std::ostringstream& results)
{
boost::property_tree::ptree pt;
auto sam = i2p::client::context.GetSAMBridge ();
if (sam)
{
pt.put("enabled", true);
boost::property_tree::ptree sam_sessions;
for (auto& it: sam->GetSessions ())
{
boost::property_tree::ptree sam_session, sam_session_sockets;
auto& name = it.second->localDestination->GetNickname ();
auto& ident = it.second->localDestination->GetIdentHash();
sam_session.put("name", name);
sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
for (const auto& socket: it.second->ListSockets())
{
boost::property_tree::ptree stream;
stream.put("type", socket->GetSocketType ());
stream.put("peer", socket->GetSocket ().remote_endpoint());
sam_session_sockets.push_back(std::make_pair("", stream));
}
sam_session.add_child("sockets", sam_session_sockets);
sam_sessions.add_child(it.first, sam_session);
}
pt.add_child("sessions", sam_sessions);
}
else
pt.put("enabled", false);
InsertParam (results, "SAM", pt);
}
void I2PControlService::BOBInfoHandler (std::ostringstream& results)
{
boost::property_tree::ptree pt;
auto bob = i2p::client::context.GetBOBCommandChannel ();
if (bob)
{
/* TODO more info */
pt.put("enabled", true);
}
else
pt.put("enabled", false);
InsertParam (results, "BOB", pt);
}
void I2PControlService::I2CPInfoHandler (std::ostringstream& results)
{
boost::property_tree::ptree pt;
auto i2cp = i2p::client::context.GetI2CPServer ();
if (i2cp)
{
/* TODO more info */
pt.put("enabled", true);
}
else
pt.put("enabled", false);
InsertParam (results, "I2CP", pt);
}
}
}

@ -57,6 +57,7 @@ namespace client
void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const;
void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const;
// methods
typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results);
@ -67,6 +68,7 @@ namespace client
void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
// I2PControl
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
@ -98,6 +100,15 @@ namespace client
void InboundBandwidthLimit (const std::string& value, std::ostringstream& results);
void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results);
// ClientServicesInfo
typedef void (I2PControlService::*ClientServicesInfoRequestHandler)(std::ostringstream& results);
void I2PTunnelInfoHandler (std::ostringstream& results);
void HTTPProxyInfoHandler (std::ostringstream& results);
void SOCKSInfoHandler (std::ostringstream& results);
void SAMInfoHandler (std::ostringstream& results);
void BOBInfoHandler (std::ostringstream& results);
void I2CPInfoHandler (std::ostringstream& results);
private:
std::string m_Password;
@ -115,6 +126,7 @@ namespace client
std::map<std::string, RouterInfoRequestHandler> m_RouterInfoHandlers;
std::map<std::string, RouterManagerRequestHandler> m_RouterManagerHandlers;
std::map<std::string, NetworkSettingRequestHandler> m_NetworkSettingHandlers;
std::map<std::string, ClientServicesInfoRequestHandler> m_ClientServicesInfoHandlers;
};
}
}

@ -373,7 +373,7 @@ namespace crypto
}
// ECIES
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx)
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
{
BN_CTX_start (ctx);
BIGNUM * q = BN_CTX_get (ctx);
@ -386,10 +386,19 @@ namespace crypto
EC_POINT_mul (curve, p, k, nullptr, nullptr, ctx);
BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx);
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr);
encrypted[0] = 0;
bn2buf (x, encrypted + 1, len);
bn2buf (y, encrypted + 1 + len, len);
RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len);
if (zeroPadding)
{
encrypted[0] = 0;
bn2buf (x, encrypted + 1, len);
bn2buf (y, encrypted + 1 + len, len);
RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len);
}
else
{
bn2buf (x, encrypted, len);
bn2buf (y, encrypted + len, len);
RAND_bytes (encrypted + 2*len, 256 - 2*len);
}
// ecryption key and iv
EC_POINT_mul (curve, p, nullptr, key, k, ctx);
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr);
@ -403,16 +412,21 @@ namespace crypto
memcpy (m+33, data, 222);
SHA256 (m+33, 222, m+1);
// encrypt
encrypted[257] = 0;
CBCEncryption encryption;
encryption.SetKey (shared);
encryption.SetIV (iv);
encryption.Encrypt (m, 256, encrypted + 258);
if (zeroPadding)
{
encrypted[257] = 0;
encryption.Encrypt (m, 256, encrypted + 258);
}
else
encryption.Encrypt (m, 256, encrypted + 256);
EC_POINT_free (p);
BN_CTX_end (ctx);
}
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
{
bool ret = true;
BN_CTX_start (ctx);
@ -421,8 +435,16 @@ namespace crypto
int len = BN_num_bytes (q);
// point for shared secret
BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx);
BN_bin2bn (encrypted + 1, len, x);
BN_bin2bn (encrypted + 1 + len, len, y);
if (zeroPadding)
{
BN_bin2bn (encrypted + 1, len, x);
BN_bin2bn (encrypted + 1 + len, len, y);
}
else
{
BN_bin2bn (encrypted, len, x);
BN_bin2bn (encrypted + len, len, y);
}
auto p = EC_POINT_new (curve);
if (EC_POINT_set_affine_coordinates_GFp (curve, p, x, y, nullptr))
{
@ -439,7 +461,10 @@ namespace crypto
CBCDecryption decryption;
decryption.SetKey (shared);
decryption.SetIV (iv);
decryption.Decrypt (encrypted + 258, 256, m);
if (zeroPadding)
decryption.Decrypt (encrypted + 258, 256, m);
else
decryption.Decrypt (encrypted + 256, 256, m);
// verify and copy
uint8_t hash[32];
SHA256 (m + 33, 222, hash);

@ -54,8 +54,8 @@ namespace crypto
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub);
// ECIES
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); // 222 bytes data, 514 bytes encrypted
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false); // 222 bytes data, 514 bytes encrypted with zeropadding, 512 without
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false);
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
// HMAC

@ -12,9 +12,9 @@ namespace crypto
memcpy (m_PublicKey, pub, 256);
}
void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx)
void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
{
ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, true);
ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, zeroPadding);
}
ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv)
@ -22,9 +22,9 @@ namespace crypto
memcpy (m_PrivateKey, priv, 256);
}
bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
{
return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, true);
return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, zeroPadding);
}
ECIESP256Encryptor::ECIESP256Encryptor (const uint8_t * pub)
@ -44,10 +44,10 @@ namespace crypto
if (m_PublicKey) EC_POINT_free (m_PublicKey);
}
void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx)
void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
{
if (m_Curve && m_PublicKey)
ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted, ctx);
ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted, ctx, zeroPadding);
}
ECIESP256Decryptor::ECIESP256Decryptor (const uint8_t * priv)
@ -62,10 +62,10 @@ namespace crypto
if (m_PrivateKey) BN_free (m_PrivateKey);
}
bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
{
if (m_Curve && m_PrivateKey)
return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data, ctx);
return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data, ctx, zeroPadding);
return false;
}
@ -104,10 +104,10 @@ namespace crypto
if (m_PublicKey) EC_POINT_free (m_PublicKey);
}
void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx)
void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
{
if (m_PublicKey)
ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted, ctx);
ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted, ctx, zeroPadding);
}
ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor (const uint8_t * priv)
@ -120,10 +120,10 @@ namespace crypto
if (m_PrivateKey) BN_free (m_PrivateKey);
}
bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
{
if (m_PrivateKey)
return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data, ctx);
return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data, ctx, zeroPadding);
return false;
}

@ -13,7 +13,7 @@ namespace crypto
public:
virtual ~CryptoKeyEncryptor () {};
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) = 0; // 222 bytes data, 512 bytes encrypted
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) = 0; // 222 bytes data, 512/514 bytes encrypted
};
class CryptoKeyDecryptor
@ -21,7 +21,7 @@ namespace crypto
public:
virtual ~CryptoKeyDecryptor () {};
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) = 0; // 512 bytes encrypted, 222 bytes data
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding) = 0; // 512/514 bytes encrypted, 222 bytes data
};
// ElGamal
@ -30,7 +30,7 @@ namespace crypto
public:
ElGamalEncryptor (const uint8_t * pub);
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
private:
@ -42,7 +42,7 @@ namespace crypto
public:
ElGamalDecryptor (const uint8_t * priv);
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
private:
@ -57,7 +57,7 @@ namespace crypto
ECIESP256Encryptor (const uint8_t * pub);
~ECIESP256Encryptor ();
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
private:
@ -72,7 +72,7 @@ namespace crypto
ECIESP256Decryptor (const uint8_t * priv);
~ECIESP256Decryptor ();
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
private:
@ -90,7 +90,7 @@ namespace crypto
ECIESGOSTR3410Encryptor (const uint8_t * pub);
~ECIESGOSTR3410Encryptor ();
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
private:
@ -104,7 +104,7 @@ namespace crypto
ECIESGOSTR3410Decryptor (const uint8_t * priv);
~ECIESGOSTR3410Decryptor ();
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
private:

@ -169,6 +169,46 @@ namespace client
return false;
}
bool LeaseSetDestination::Reconfigure(std::map<std::string, std::string> params)
{
auto itr = params.find("i2cp.dontPublishLeaseSet");
if (itr != params.end())
{
m_IsPublic = itr->second != "true";
}
int inLen, outLen, inQuant, outQuant, numTags, minLatency, maxLatency;
std::map<std::string, int&> intOpts = {
{I2CP_PARAM_INBOUND_TUNNEL_LENGTH, inLen},
{I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, outLen},
{I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, inQuant},
{I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, outQuant},
{I2CP_PARAM_TAGS_TO_SEND, numTags},
{I2CP_PARAM_MIN_TUNNEL_LATENCY, minLatency},
{I2CP_PARAM_MAX_TUNNEL_LATENCY, maxLatency}
};
auto pool = GetTunnelPool();
inLen = pool->GetNumInboundHops();
outLen = pool->GetNumOutboundHops();
inQuant = pool->GetNumInboundTunnels();
outQuant = pool->GetNumOutboundTunnels();
minLatency = 0;
maxLatency = 0;
for (auto & opt : intOpts)
{
itr = params.find(opt.first);
if(itr != params.end())
{
opt.second = std::stoi(itr->second);
}
}
pool->RequireLatency(minLatency, maxLatency);
return pool->Reconfigure(inLen, outLen, inQuant, outQuant);
}
std::shared_ptr<const i2p::data::LeaseSet> LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident)
{
std::shared_ptr<i2p::data::LeaseSet> remoteLS;
@ -241,8 +281,12 @@ namespace client
i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
if (m_IsPublic)
{
m_PublishVerificationTimer.cancel ();
Publish ();
auto s = shared_from_this ();
m_Service.post ([s](void)
{
s->m_PublishVerificationTimer.cancel ();
s->Publish ();
});
}
}
@ -984,7 +1028,7 @@ namespace client
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
{
if (m_Decryptor)
return m_Decryptor->Decrypt (encrypted, data, ctx);
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
else
LogPrint (eLogError, "Destinations: decryptor is not set");
return false;

@ -96,6 +96,10 @@ namespace client
virtual bool Start ();
virtual bool Stop ();
/** i2cp reconfigure */
virtual bool Reconfigure(std::map<std::string, std::string> i2cpOpts);
bool IsRunning () const { return m_IsRunning; };
boost::asio::io_service& GetService () { return m_Service; };
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };

@ -327,7 +327,7 @@ namespace i2p
{
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
BN_CTX * ctx = BN_CTX_new ();
i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKeys ().GetPrivateKey () , record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
BN_CTX_free (ctx);
// replace record to reply
if (i2p::context.AcceptsTunnels () &&

@ -212,7 +212,7 @@ namespace data
{
auto encryptor = m_Identity->CreateEncryptor (m_EncryptionKey);
if (encryptor)
encryptor->Encrypt (data, encrypted, ctx);
encryptor->Encrypt (data, encrypted, ctx, true);
}
LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):

@ -184,7 +184,7 @@ namespace transport
}
// TODO: check for number of pending keys
auto work = new NTCPWork{shared_from_this()};
m_Server.Work(work->session, [work]() -> std::function<void(void)> {
m_Server.Work(work->session, [work, this]() -> std::function<void(void)> {
if (!work->session->m_DHKeysPair)
work->session->m_DHKeysPair = transports.GetNextDHKeysPair ();
work->session->CreateAESKey (work->session->m_Establisher->phase1.pubKey);
@ -250,7 +250,7 @@ namespace transport
else
{
auto work = new NTCPWork{shared_from_this()};
m_Server.Work(work->session, [work]() -> std::function<void(void)> {
m_Server.Work(work->session, [work, this]() -> std::function<void(void)> {
work->session->CreateAESKey (work->session->m_Establisher->phase2.pubKey);
return std::bind(&NTCPSession::HandlePhase2, work->session, work);
});

@ -34,11 +34,7 @@ namespace i2p
void RouterContext::CreateNewRouter ()
{
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
#else
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_DSA_SHA1);
#endif
SaveKeys ();
NewRouterInfo ();
}
@ -482,6 +478,11 @@ namespace i2p
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
{
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx) : false;
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
}
bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
{
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, false) : false;
}
}

@ -61,6 +61,7 @@ namespace i2p
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
int GetNetID () const { return m_NetID; };
void SetNetID (int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon

@ -840,7 +840,7 @@ namespace data
{
auto encryptor = m_RouterIdentity->CreateEncryptor (nullptr);
if (encryptor)
encryptor->Encrypt (data, encrypted, ctx);
encryptor->Encrypt (data, encrypted, ctx, true);
}
}
}

@ -670,10 +670,13 @@ namespace tunnel
{
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
tunnel->SetIsRecreated ();
auto pool = tunnel->GetTunnelPool ();
if (pool)
// let it die if the tunnel pool has been reconfigured and this is old
if (pool && tunnel->GetNumHops() == pool->GetNumOutboundHops())
{
tunnel->SetIsRecreated ();
pool->RecreateOutboundTunnel (tunnel);
}
}
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring);
@ -721,10 +724,13 @@ namespace tunnel
{
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
tunnel->SetIsRecreated ();
auto pool = tunnel->GetTunnelPool ();
if (pool)
// let it die if the tunnel pool was reconfigured and has different number of hops
if (pool && tunnel->GetNumHops() == pool->GetNumInboundHops())
{
tunnel->SetIsRecreated ();
pool->RecreateInboundTunnel (tunnel);
}
}
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)

@ -105,6 +105,7 @@ namespace tunnel
bool IsFailed () const { return m_State == eTunnelStateFailed; };
bool IsRecreated () const { return m_IsRecreated; };
void SetIsRecreated () { m_IsRecreated = true; };
int GetNumHops () const { return m_Hops.size (); };
virtual bool IsInbound() const = 0;
std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; };

@ -5,7 +5,6 @@
#include <sstream>
#include <vector>
#include <memory>
#include "Crypto.h"
#include "Identity.h"
#include "RouterContext.h"
#include "Timestamp.h"
@ -35,6 +34,7 @@ namespace tunnel
RAND_bytes (replyKey, 32);
RAND_bytes (replyIV, 16);
RAND_bytes ((uint8_t *)&tunnelID, 4);
if (!tunnelID) tunnelID = 1; // tunnelID can't be zero
isGateway = true;
isEndpoint = true;
ident = r;
@ -50,6 +50,7 @@ namespace tunnel
nextIdent = ident;
isEndpoint = false;
RAND_bytes ((uint8_t *)&nextTunnelID, 4);
if (!nextTunnelID) nextTunnelID = 1; // tunnelID can't be zero
}
void SetReplyHop (uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent)
@ -101,7 +102,9 @@ namespace tunnel
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET);
i2p::crypto::ElGamalEncrypt (ident->GetEncryptionPublicKey (), clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx);
auto encryptor = ident->CreateEncryptor (nullptr);
if (encryptor)
encryptor->Encrypt (clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx, false);
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
}
};

@ -69,6 +69,18 @@ namespace tunnel
m_Tests.clear ();
}
bool TunnelPool::Reconfigure(int inHops, int outHops, int inQuant, int outQuant) {
if( inHops >= 0 && outHops >= 0 && inQuant > 0 && outQuant > 0)
{
m_NumInboundHops = inHops;
m_NumOutboundHops = outHops;
m_NumInboundTunnels = inQuant;
m_NumOutboundTunnels = outQuant;
return true;
}
return false;
}
void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel)
{
if (!m_IsActive) return;
@ -479,11 +491,17 @@ namespace tunnel
outboundTunnel = tunnels.GetNextOutboundTunnel ();
LogPrint (eLogDebug, "Tunnels: Re-creating destination inbound tunnel...");
std::shared_ptr<TunnelConfig> config;
if (m_NumInboundHops > 0) config = std::make_shared<TunnelConfig>(tunnel->GetPeers ());
auto newTunnel = tunnels.CreateInboundTunnel (config, outboundTunnel);
newTunnel->SetTunnelPool (shared_from_this());
if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel);
if (m_NumInboundHops > 0 && tunnel->GetPeers().size())
{
config = std::make_shared<TunnelConfig>(tunnel->GetPeers ());
}
if (m_NumInboundHops == 0 || config)
{
auto newTunnel = tunnels.CreateInboundTunnel (config, outboundTunnel);
newTunnel->SetTunnelPool (shared_from_this());
if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel);
}
}
void TunnelPool::CreateOutboundTunnel ()
@ -521,12 +539,17 @@ namespace tunnel
{
LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel...");
std::shared_ptr<TunnelConfig> config;
if (m_NumOutboundHops > 0)
if (m_NumOutboundHops > 0 && tunnel->GetPeers().size())
{
config = std::make_shared<TunnelConfig>(tunnel->GetPeers (), inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ());
auto newTunnel = tunnels.CreateOutboundTunnel (config);
newTunnel->SetTunnelPool (shared_from_this ());
if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel);
}
if(m_NumOutboundHops == 0 || config)
{
auto newTunnel = tunnels.CreateOutboundTunnel (config);
newTunnel->SetTunnelPool (shared_from_this ());
if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel);
}
}
else
LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found");

@ -78,7 +78,12 @@ namespace tunnel
int GetNumInboundTunnels () const { return m_NumInboundTunnels; };
int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; };
int GetNumInboundHops() const { return m_NumInboundHops; };
int GetNumOutboundHops() const { return m_NumOutboundHops; };
/** i2cp reconfigure */
bool Reconfigure(int inboundHops, int outboundHops, int inboundQuant, int outboundQuant);
void SetCustomPeerSelector(ITunnelPeerSelector * selector);
void UnsetCustomPeerSelector();
bool HasCustomPeerSelector();

@ -37,7 +37,7 @@ namespace client
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
{
if (m_Decryptor)
return m_Decryptor->Decrypt (encrypted, data, ctx);
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
else
LogPrint (eLogError, "I2CP: decryptor is not set");
return false;
@ -416,9 +416,60 @@ namespace client
void I2CPSession::ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len)
{
// TODO: implement actual reconfiguration
SendSessionStatusMessage (2); // updated
}
uint8_t status = 3; // rejected
if(len > sizeof(uint16_t))
{
uint16_t sessionID = bufbe16toh(buf);
if(sessionID == m_SessionID)
{
buf += sizeof(uint16_t);
const uint8_t * body = buf;
i2p::data::IdentityEx ident;
if(ident.FromBuffer(buf, len - sizeof(uint16_t)))
{
if (ident == *m_Destination->GetIdentity())
{
size_t identsz = ident.GetFullLen();
buf += identsz;
uint16_t optssize = bufbe16toh(buf);
if (optssize <= len - sizeof(uint16_t) - sizeof(uint64_t) - identsz - ident.GetSignatureLen() - sizeof(uint16_t))
{
buf += sizeof(uint16_t);
std::map<std::string, std::string> opts;
ExtractMapping(buf, optssize, opts);
buf += optssize;
//uint64_t date = bufbe64toh(buf);
buf += sizeof(uint64_t);
const uint8_t * sig = buf;
if(ident.Verify(body, len - sizeof(uint16_t) - ident.GetSignatureLen(), sig))
{
if(m_Destination->Reconfigure(opts))
{
LogPrint(eLogInfo, "I2CP: reconfigured destination");
status = 2; // updated
}
else
LogPrint(eLogWarning, "I2CP: failed to reconfigure destination");
}
else
LogPrint(eLogError, "I2CP: invalid reconfigure message signature");
}
else
LogPrint(eLogError, "I2CP: mapping size missmatch");
}
else
LogPrint(eLogError, "I2CP: destination missmatch");
}
else
LogPrint(eLogError, "I2CP: malfromed destination");
}
else
LogPrint(eLogError, "I2CP: session missmatch");
}
else
LogPrint(eLogError, "I2CP: short message");
SendSessionStatusMessage (status);
}
void I2CPSession::SendSessionStatusMessage (uint8_t status)
{

@ -107,6 +107,21 @@ namespace client
std::placeholders::_1, std::placeholders::_2));
}
static bool SAMVersionAcceptable(const std::string & ver)
{
return ver == "3.0" || ver == "3.1";
}
static bool SAMVersionTooLow(const std::string & ver)
{
return ver.size() && ver[0] < '3';
}
static bool SAMVersionTooHigh(const std::string & ver)
{
return ver.size() && ver > "3.1";
}
void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
@ -132,19 +147,37 @@ namespace client
if (!strcmp (m_Buffer, SAM_HANDSHAKE))
{
std::string version("3.0");
std::string maxver("3.1");
std::string minver("3.0");
// try to find MIN and MAX, 3.0 if not found
if (separator)
{
separator++;
std::map<std::string, std::string> params;
ExtractParams (separator, params);
//auto it = params.find (SAM_PARAM_MAX);
// TODO: check MIN as well
//if (it != params.end ())
// version = it->second;
auto it = params.find (SAM_PARAM_MAX);
if (it != params.end ())
maxver = it->second;
it = params.find(SAM_PARAM_MIN);
if (it != params.end ())
minver = it->second;
}
// version negotiation
std::string version;
if (SAMVersionAcceptable(maxver))
{
version = maxver;
}
else if (SAMVersionAcceptable(minver))
{
version = minver;
}
else if (SAMVersionTooLow(minver) && SAMVersionTooHigh(maxver))
{
version = "3.0";
}
if (version[0] == '3') // we support v3 (3.0 and 3.1) only
if (SAMVersionAcceptable(version))
{
#ifdef _MSC_VER
size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ());
@ -156,7 +189,7 @@ namespace client
std::placeholders::_1, std::placeholders::_2));
}
else
SendMessageReply (SAM_HANDSHAKE_I2P_ERROR, strlen (SAM_HANDSHAKE_I2P_ERROR), true);
SendMessageReply (SAM_HANDSHAKE_NOVERSION, strlen (SAM_HANDSHAKE_NOVERSION), true);
}
else
{

@ -23,6 +23,7 @@ namespace client
const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
const char SAM_HANDSHAKE[] = "HELLO VERSION";
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
const char SAM_HANDSHAKE_NOVERSION[] = "HELLO REPLY RESULT=NOVERSION\n";
const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\n";
const char SAM_SESSION_CREATE[] = "SESSION CREATE";
const char SAM_SESSION_CREATE_REPLY_OK[] = "SESSION STATUS RESULT=OK DESTINATION=%s\n";

Loading…
Cancel
Save