Merge pull request #1240 from PurpleI2P/openssl

eddsa from 1.1.1
This commit is contained in:
orignal 2018-09-08 16:22:12 -04:00 committed by GitHub
commit 5ecd04dd4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 188 additions and 39 deletions

View File

@ -130,6 +130,8 @@ doxygen:
.PHONY: deps
.PHONY: doxygen
.PHONY: dist
.PHONY: last-dist
.PHONY: api
.PHONY: api_client
.PHONY: mk_obj_dir
.PHONY: install

View File

@ -1,7 +1,7 @@
# root directory holding homebrew
BREWROOT = /usr/local
BOOSTROOT = ${BREWROOT}/opt/boost
SSLROOT = ${BREWROOT}/opt/libressl
SSLROOT = ${BREWROOT}/opt/openssl@1.1
UPNPROOT = ${BREWROOT}/opt/miniupnpc
CXXFLAGS = ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
@ -41,9 +41,14 @@ ifeq ($(USE_AVX),1)
CXXFLAGS += -mavx
endif
# Disabled, since it will be the default make rule. I think its better
# to define the default rule in Makefile and not Makefile.<ostype> - torkel
#install: all
# test -d ${PREFIX} || mkdir -p ${PREFIX}/
# cp -r i2p ${PREFIX}/
install: all
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
install -m 755 ${I2PD} ${PREFIX}/bin/
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
@gzip debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf

View File

@ -21,8 +21,10 @@ else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
NEEDED_CXXFLAGS += -std=c++0x
else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0
NEEDED_CXXFLAGS += -std=c++11
LDLIBS = -latomic
else ifeq ($(shell expr match ${CXXVER} "[7-8]"),1) # gcc 7 ubuntu or gcc 8 arch
NEEDED_CXXFLAGS += -std=c++11
LDLIBS = -latomic
else # not supported
$(error Compiler too old)
endif
@ -34,7 +36,7 @@ ifeq ($(USE_STATIC),yes)
# Using 'getaddrinfo' in statically linked applications requires at runtime
# the shared libraries from the glibc version used for linking
LIBDIR := /usr/lib
LDLIBS = $(LIBDIR)/libboost_system.a
LDLIBS += $(LIBDIR)/libboost_system.a
LDLIBS += $(LIBDIR)/libboost_date_time.a
LDLIBS += $(LIBDIR)/libboost_filesystem.a
LDLIBS += $(LIBDIR)/libboost_program_options.a
@ -44,7 +46,7 @@ ifeq ($(USE_STATIC),yes)
LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt -ldl
USE_AESNI := no
else
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
endif
# UPNP Support (miniupnpc 1.5 and higher)

View File

@ -1,7 +1,7 @@
CXX = clang++
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX
INCFLAGS = -I/usr/local/include
LDFLAGS := ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
ifeq ($(USE_STATIC),yes)
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
@ -28,17 +28,3 @@ endif
ifeq ($(USE_AVX),1)
CXXFLAGS += -mavx
endif
# Disabled, since it will be the default make rule. I think its better
# to define the default rule in Makefile and not Makefile.<ostype> - torkel
install-brew: all
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
install -m 755 ${I2PD} ${PREFIX}/bin/
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
@gzip debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf

View File

@ -1,5 +1,5 @@
## Configuration file for a typical i2pd user
## See https://i2pd.readthedocs.org/en/latest/configuration.html
## See https://i2pd.readthedocs.io/en/latest/user-guide/configuration/
## for more options you can use in this file.
#logfile = /sdcard/i2pd/i2pd.log

View File

@ -1,5 +1,5 @@
## Configuration file for a typical i2pd user
## See https://i2pd.readthedocs.org/en/latest/configuration.html
## See https://i2pd.readthedocs.io/en/latest/user-guide/configuration/
## for more options you can use in this file.
## Lines that begin with "## " try to explain what's going on. Lines

View File

@ -266,6 +266,10 @@ namespace crypto
# define LEGACY_OPENSSL 1
#else
# define LEGACY_OPENSSL 0
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
# define OPENSSL_EDDSA 1
# define OPENSSL_X25519 1
# endif
#endif
#if LEGACY_OPENSSL

View File

@ -41,6 +41,9 @@ namespace transport
delete[] m_SessionRequestBuffer;
delete[] m_SessionCreatedBuffer;
delete[] m_SessionConfirmedBuffer;
#if OPENSSL_X25519
EVP_PKEY_free (m_EphemeralPkey);
#endif
}
void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived)
@ -119,7 +122,18 @@ namespace transport
// x25519 between remote pub and priv
uint8_t inputKeyMaterial[32];
i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), GetPriv (), inputKeyMaterial, m_Ctx);
#if OPENSSL_X25519
auto pctx = EVP_PKEY_CTX_new (m_EphemeralPkey, NULL);
EVP_PKEY_derive_init (pctx);
auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, GetRemotePub (), 32);
EVP_PKEY_derive_set_peer (pctx, pkey);
size_t len = 32;
EVP_PKEY_derive (pctx, inputKeyMaterial, &len);
EVP_PKEY_free (pkey);
EVP_PKEY_CTX_free (pctx);
#else
i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), GetPriv (), inputKeyMaterial, m_Ctx);
#endif
MixKey (inputKeyMaterial, m_K);
}
@ -149,8 +163,21 @@ namespace transport
void NTCP2Establisher::CreateEphemeralKey ()
{
#if OPENSSL_X25519
m_EphemeralPkey = nullptr;
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL);
EVP_PKEY_keygen_init (pctx);
EVP_PKEY_keygen (pctx, &m_EphemeralPkey);
EVP_PKEY_CTX_free (pctx);
// TODO: remove, after switch to m_EphemeralPkey
size_t len = 32;
EVP_PKEY_get_raw_public_key (m_EphemeralPkey, m_EphemeralPublicKey, &len);
len = 32;
EVP_PKEY_get_raw_private_key (m_EphemeralPkey, m_EphemeralPrivateKey, &len);
#else
RAND_bytes (m_EphemeralPrivateKey, 32);
i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, m_EphemeralPublicKey, m_Ctx);
#endif
}
void NTCP2Establisher::CreateSessionRequestMessage ()
@ -1179,6 +1206,8 @@ namespace transport
else
{
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetSocket ().remote_endpoint ());
if (conn->GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6
context.UpdateNTCP2V6Address (conn->GetSocket ().local_endpoint ().address ());
conn->ClientLogin ();
}
}

View File

@ -18,6 +18,7 @@
#include <map>
#include <array>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <boost/asio.hpp>
#include "util.h"
#include "RouterInfo.h"
@ -110,6 +111,9 @@ namespace transport
BN_CTX * m_Ctx;
uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519
#if OPENSSL_X25519
EVP_PKEY * m_EphemeralPkey;
#endif
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/;
i2p::data::IdentHash m_RemoteIdentHash;
uint16_t m3p2Len;

View File

@ -453,6 +453,39 @@ namespace i2p
UpdateRouterInfo ();
}
void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host)
{
bool updated = false, found = false;
int port = 0;
auto& addresses = m_RouterInfo.GetAddresses ();
for (auto& addr: addresses)
{
if (addr->IsPublishedNTCP2 ())
{
if (addr->host.is_v6 ())
{
if (addr->host != host)
{
addr->host = host;
updated = true;
}
found = true;
break;
}
else
port = addr->port; // NTCP2 v4
}
}
if (!found && port) // we have found NTCP2 v4 but not v6
{
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, host, port);
updated = true;
}
if (updated)
UpdateRouterInfo ();
}
void RouterContext::UpdateStats ()
{
if (m_IsFloodfill)

View File

@ -100,6 +100,7 @@ namespace i2p
void SetSupportsV4 (bool supportsV4);
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from NTCP2 session
void UpdateStats ();
void CleanupDestination (); // garlic destination

View File

@ -696,17 +696,17 @@ namespace data
m_Caps |= eSSUIntroducer;
}
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv)
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, const boost::asio::ip::address& host, int port)
{
for (const auto& it: *m_Addresses) // don't insert one more NTCP2
if (it->ntcp2) return;
auto addr = std::make_shared<Address>();
addr->port = 0;
addr->host = host;
addr->port = port;
addr->transportStyle = eTransportNTCP;
addr->cost = 3;
addr->date = 0;
addr->ntcp2.reset (new NTCP2Ext ());
addr->ntcp2->isNTCP2Only = true; // NTCP2 only address
if (port) addr->ntcp2->isPublished = true;
memcpy (addr->ntcp2->staticKey, staticKey, 32);
memcpy (addr->ntcp2->iv, iv, 16);
m_Addresses->push_back(std::move(addr));

View File

@ -117,7 +117,8 @@ namespace data
bool operator==(const Address& other) const
{
return transportStyle == other.transportStyle && host == other.host && port == other.port;
return transportStyle == other.transportStyle && IsNTCP2 () == other.IsNTCP2 () &&
host == other.host && port == other.port;
}
bool operator!=(const Address& other) const
@ -150,7 +151,7 @@ namespace data
void AddNTCPAddress (const char * host, int port);
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv);
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0);
bool AddIntroducer (const Introducer& introducer);
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only

View File

@ -6,6 +6,26 @@ namespace i2p
{
namespace crypto
{
#if OPENSSL_EDDSA
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
{
m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32);
m_MDCtx = EVP_MD_CTX_create ();
EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, m_Pkey);
}
EDDSA25519Verifier::~EDDSA25519Verifier ()
{
EVP_MD_CTX_destroy (m_MDCtx);
EVP_PKEY_free (m_Pkey);
}
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
return EVP_DigestVerify (m_MDCtx, signature, 64, buf, len);
}
#else
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
{
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
@ -14,6 +34,10 @@ namespace crypto
BN_CTX_free (ctx);
}
EDDSA25519Verifier::~EDDSA25519Verifier ()
{
}
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
uint8_t digest[64];
@ -26,7 +50,30 @@ namespace crypto
return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
}
#endif
#if OPENSSL_EDDSA
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
{
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_ED25519, NULL, signingPrivateKey, 32);
// TODO: check public key
m_MDCtx = EVP_MD_CTX_create ();
EVP_DigestSignInit (m_MDCtx, NULL, NULL, NULL, m_Pkey);
}
EDDSA25519Signer::~EDDSA25519Signer ()
{
EVP_MD_CTX_destroy (m_MDCtx);
EVP_PKEY_free (m_Pkey);
}
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
size_t l = 64;
EVP_DigestSign (m_MDCtx, signature, &l, buf, len);
}
#else
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
{
// expand key
@ -47,10 +94,15 @@ namespace crypto
BN_CTX_free (ctx);
}
EDDSA25519Signer::~EDDSA25519Signer ()
{
}
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
}
#endif
}
}

View File

@ -367,6 +367,8 @@ namespace crypto
public:
EDDSA25519Verifier (const uint8_t * signingKey);
~EDDSA25519Verifier ();
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; };
@ -374,8 +376,13 @@ namespace crypto
private:
#if OPENSSL_EDDSA
EVP_PKEY * m_Pkey;
EVP_MD_CTX * m_MDCtx;
#else
EDDSAPoint m_PublicKey;
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
#endif
};
class EDDSA25519Signer: public Signer
@ -384,20 +391,41 @@ namespace crypto
EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr);
// we pass signingPublicKey to check if it matches private key
~EDDSA25519Signer ();
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; };
#if !OPENSSL_EDDSA
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation
#endif
private:
#if OPENSSL_EDDSA
EVP_PKEY * m_Pkey;
EVP_MD_CTX * m_MDCtx;
#else
uint8_t m_ExpandedPrivateKey[64];
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
#endif
};
inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
#if OPENSSL_EDDSA
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_ED25519, NULL);
EVP_PKEY_keygen_init (pctx);
EVP_PKEY_keygen (pctx, &pkey);
EVP_PKEY_CTX_free (pctx);
size_t len = EDDSA25519_PUBLIC_KEY_LENGTH;
EVP_PKEY_get_raw_public_key (pkey, signingPublicKey, &len);
len = EDDSA25519_PRIVATE_KEY_LENGTH;
EVP_PKEY_get_raw_private_key (pkey, signingPrivateKey, &len);
EVP_PKEY_free (pkey);
#else
RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH);
EDDSA25519Signer signer (signingPrivateKey);
memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH);
#endif
}

View File

@ -741,7 +741,7 @@ namespace client
std::string response;
uint8_t recv_buf[4096];
bool end = false;
int numAttempts = 5;
int numAttempts = 0;
while (!end)
{
stream->AsyncReceive (boost::asio::buffer (recv_buf, 4096),
@ -755,7 +755,8 @@ namespace client
},
SUBSCRIPTION_REQUEST_TIMEOUT);
std::unique_lock<std::mutex> l(newDataReceivedMutex);
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
// wait 1 more second
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT + 1)) == std::cv_status::timeout)
{
LogPrint (eLogError, "Addressbook: subscriptions request timeout expired");
numAttempts++;

View File

@ -500,7 +500,8 @@ namespace client
if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS)
{
// socks proxy
auto tun = std::make_shared<i2p::proxy::SOCKSProxy>(name, address, port, false, "", destinationPort, localDestination);
std::string outproxy = section.second.get("outproxy", "");
auto tun = std::make_shared<i2p::proxy::SOCKSProxy>(name, address, port, !outproxy.empty(), outproxy, destinationPort, localDestination);
clientTunnel = tun;
clientEndpoint = tun->GetLocalEndpoint ();
}

View File

@ -46,7 +46,7 @@ namespace client
const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n";
const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%lu\n";
const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n";
const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=INVALID_KEY_NOT_FOUND NAME=%s\n";
const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=KEY_NOT_FOUND NAME=%s\n";
const char SAM_PARAM_MIN[] = "MIN";
const char SAM_PARAM_MAX[] = "MAX";
const char SAM_PARAM_STYLE[] = "STYLE";