Browse Source

Merge pull request #842 from PurpleI2P/openssl

2.13.0
pull/63/merge
orignal 7 years ago committed by GitHub
parent
commit
46cb95f16c
  1. 14
      ChangeLog
  2. 33
      Crypto.h
  3. 2
      Destination.cpp
  4. 14
      FS.cpp
  5. 4
      FS.h
  6. 80
      Garlic.cpp
  7. 32
      Garlic.h
  8. 2
      Win32/installer.iss
  9. 2
      android/AndroidManifest.xml
  10. 2
      appveyor.yml
  11. 9
      debian/changelog
  12. 38
      debian/control
  13. 0
      debian/i2pd.logrotate
  14. 2
      qt/i2pd_qt/android/AndroidManifest.xml
  15. 2
      version.h

14
ChangeLog

@ -1,6 +1,20 @@
# for this file format description, # for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog # see https://github.com/olivierlacan/keep-a-changelog
## [2.13.0] - 2017-04-06
### Added
- Persist local destination's tags
- GOST signature types 9 and 10
- Exploratory tunnels configuration
### Changed
- Reseed servers list
- Inactive NTCP sockets get closed faster
- Some EdDSA speed up
### Fixed
- Multiple acceptors for SAM
- Follow on data after STREAM CREATE for SAM
- Memory leaks
## [2.12.0] - 2017-02-14 ## [2.12.0] - 2017-02-14
### Added ### Added
- Additional HTTP and SOCKS proxy tunnels - Additional HTTP and SOCKS proxy tunnels

33
Crypto.h

@ -289,13 +289,26 @@ namespace crypto
#if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL #if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL
// define getters and setters introduced in 1.1.0 // define getters and setters introduced in 1.1.0
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{ d->p = p; d->q = q; d->g = g; return 1; } {
if (d->p) BN_free (d->p);
if (d->q) BN_free (d->q);
if (d->g) BN_free (d->g);
d->p = p; d->q = q; d->g = g; return 1;
}
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{ d->pub_key = pub_key; d->priv_key = priv_key; return 1; } {
if (d->pub_key) BN_free (d->pub_key);
if (d->priv_key) BN_free (d->priv_key);
d->pub_key = pub_key; d->priv_key = priv_key; return 1;
}
inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
{ *pub_key = d->pub_key; *priv_key = d->priv_key; } { *pub_key = d->pub_key; *priv_key = d->priv_key; }
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{ sig->r = r; sig->s = s; return 1; } {
if (sig->r) BN_free (sig->r);
if (sig->s) BN_free (sig->s);
sig->r = r; sig->s = s; return 1;
}
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; } { *pr = sig->r; *ps = sig->s; }
@ -309,12 +322,22 @@ inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM
{ *pr = sig->r; *ps = sig->s; } { *pr = sig->r; *ps = sig->s; }
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{ r->n = n; r->e = e; r->d = d; return 1; } {
if (r->n) BN_free (r->n);
if (r->e) BN_free (r->e);
if (r->d) BN_free (r->d);
r->n = n; r->e = e; r->d = d; return 1;
}
inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{ *n = r->n; *e = r->e; *d = r->d; } { *n = r->n; *e = r->e; *d = r->d; }
inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{ dh->p = p; dh->q = q; dh->g = g; return 1; } {
if (dh->p) BN_free (dh->p);
if (dh->q) BN_free (dh->q);
if (dh->g) BN_free (dh->g);
dh->p = p; dh->q = q; dh->g = g; return 1;
}
inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
{ {
if (dh->pub_key) BN_free (dh->pub_key); if (dh->pub_key) BN_free (dh->pub_key);

2
Destination.cpp

@ -110,6 +110,7 @@ namespace client
{ {
if (!m_IsRunning) if (!m_IsRunning)
{ {
LoadTags ();
m_IsRunning = true; m_IsRunning = true;
m_Pool->SetLocalDestination (shared_from_this ()); m_Pool->SetLocalDestination (shared_from_this ());
m_Pool->SetActive (true); m_Pool->SetActive (true);
@ -145,6 +146,7 @@ namespace client
delete m_Thread; delete m_Thread;
m_Thread = 0; m_Thread = 0;
} }
SaveTags ();
CleanUp (); // GarlicDestination CleanUp (); // GarlicDestination
return true; return true;
} }

14
FS.cpp

@ -16,6 +16,7 @@
#include "Base.h" #include "Base.h"
#include "FS.h" #include "FS.h"
#include "Log.h" #include "Log.h"
#include "Garlic.h"
namespace i2p { namespace i2p {
namespace fs { namespace fs {
@ -93,6 +94,11 @@ namespace fs {
std::string destinations = DataDirPath("destinations"); std::string destinations = DataDirPath("destinations");
if (!boost::filesystem::exists(destinations)) if (!boost::filesystem::exists(destinations))
boost::filesystem::create_directory(destinations); boost::filesystem::create_directory(destinations);
std::string tags = DataDirPath("tags");
if (!boost::filesystem::exists(tags))
boost::filesystem::create_directory(tags);
else
i2p::garlic::CleanUpTagsFiles ();
return true; return true;
} }
@ -116,6 +122,14 @@ namespace fs {
return boost::filesystem::exists(path); return boost::filesystem::exists(path);
} }
uint32_t GetLastUpdateTime (const std::string & path)
{
if (!boost::filesystem::exists(path)) return 0;
boost::system::error_code ec;
auto t = boost::filesystem::last_write_time (path, ec);
return ec ? 0 : t;
}
bool Remove(const std::string & path) { bool Remove(const std::string & path) {
if (!boost::filesystem::exists(path)) if (!boost::filesystem::exists(path))
return false; return false;

4
FS.h

@ -97,7 +97,7 @@ namespace fs {
* @param files Vector to store found files * @param files Vector to store found files
* @return true on success and false if directory not exists * @return true on success and false if directory not exists
*/ */
bool ReadDir(const std::string & path, std::vector<std::string> & files); bool ReadDir(const std::string & path, std::vector<std::string> & files);
/** /**
* @brief Remove file with given path * @brief Remove file with given path
@ -112,6 +112,8 @@ namespace fs {
* @return true if file exists, false otherwise * @return true if file exists, false otherwise
*/ */
bool Exists(const std::string & path); bool Exists(const std::string & path);
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
bool CreateDirectory (const std::string& path); bool CreateDirectory (const std::string& path);

80
Garlic.cpp

@ -10,6 +10,7 @@
#include "Transports.h" #include "Transports.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "Log.h" #include "Log.h"
#include "FS.h"
#include "Garlic.h" #include "Garlic.h"
namespace i2p namespace i2p
@ -412,9 +413,7 @@ namespace garlic
if (key) if (key)
{ {
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
auto decryption = std::make_shared<i2p::crypto::CBCDecryption>(); m_Tags[SessionTag(tag, ts)] = std::make_shared<AESDecryption>(key);
decryption->SetKey (key);
m_Tags[SessionTag(tag, ts)] = decryption;
} }
} }
@ -456,8 +455,7 @@ namespace garlic
ElGamalBlock elGamal; ElGamalBlock elGamal;
if (length >= 514 && i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, m_Ctx, true)) if (length >= 514 && i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, m_Ctx, true))
{ {
auto decryption = std::make_shared<i2p::crypto::CBCDecryption>(); auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
decryption->SetKey (elGamal.sessionKey);
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(elGamal.preIV, 32, iv); SHA256(elGamal.preIV, 32, iv);
decryption->SetIV (iv); decryption->SetIV (iv);
@ -469,7 +467,7 @@ namespace garlic
} }
} }
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<i2p::crypto::CBCDecryption> decryption, void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from) std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
uint16_t tagCount = bufbe16toh (buf); uint16_t tagCount = bufbe16toh (buf);
@ -714,5 +712,75 @@ namespace garlic
HandleDeliveryStatusMessage (msg); HandleDeliveryStatusMessage (msg);
} }
void GarlicDestination::SaveTags ()
{
if (m_Tags.empty ()) return;
std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags"));
std::ofstream f (path, std::ofstream::binary | std::ofstream::out | std::ofstream::trunc);
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
// 4 bytes timestamp, 32 bytes tag, 32 bytes key
for (auto it: m_Tags)
{
if (ts < it.first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
f.write ((char *)&it.first.creationTime, 4);
f.write ((char *)it.first.data (), 32);
f.write ((char *)it.second->GetKey ().data (), 32);
}
}
}
void GarlicDestination::LoadTags ()
{
std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags"));
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
// might contain non-expired tags
std::ifstream f (path, std::ifstream::binary);
if (f)
{
std::map<i2p::crypto::AESKey, std::shared_ptr<AESDecryption> > keys;
// 4 bytes timestamp, 32 bytes tag, 32 bytes key
while (!f.eof ())
{
uint32_t t;
uint8_t tag[32], key[32];
f.read ((char *)&t, 4); if (f.eof ()) break;
if (ts < t + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
f.read ((char *)tag, 32);
f.read ((char *)key, 32);
}
else
f.seekg (64, std::ios::cur); // skip
if (f.eof ()) break;
std::shared_ptr<AESDecryption> decryption;
auto it = keys.find (key);
if (it != keys.end ())
decryption = it->second;
else
decryption = std::make_shared<AESDecryption>(key);
m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
}
if (!m_Tags.empty ())
LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
}
}
i2p::fs::Remove (path);
}
void CleanUpTagsFiles ()
{
std::vector<std::string> files;
i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files);
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it: files)
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
i2p::fs::Remove (it);
}
} }
} }

32
Garlic.h

@ -59,6 +59,22 @@ namespace garlic
uint32_t creationTime; // seconds since epoch uint32_t creationTime; // seconds since epoch
}; };
// AESDecryption is associated with session tags and store key
class AESDecryption: public i2p::crypto::CBCDecryption
{
public:
AESDecryption (const uint8_t * key): m_Key (key)
{
SetKey (key);
}
const i2p::crypto::AESKey& GetKey () const { return m_Key; };
private:
i2p::crypto::AESKey m_Key;
};
struct GarlicRoutingPath struct GarlicRoutingPath
{ {
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel; std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
@ -67,7 +83,7 @@ namespace garlic
uint32_t updateTime; // seconds since epoch uint32_t updateTime; // seconds since epoch
int numTimesUsed; int numTimesUsed;
}; };
class GarlicDestination; class GarlicDestination;
class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession> class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession>
{ {
@ -180,10 +196,13 @@ namespace garlic
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg); void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void SaveTags ();
void LoadTags ();
private: private:
void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<i2p::crypto::CBCDecryption> decryption, void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from); std::shared_ptr<i2p::tunnel::InboundTunnel> from);
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from); void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
@ -195,7 +214,7 @@ namespace garlic
std::mutex m_SessionsMutex; std::mutex m_SessionsMutex;
std::map<i2p::data::IdentHash, GarlicRoutingSessionPtr> m_Sessions; std::map<i2p::data::IdentHash, GarlicRoutingSessionPtr> m_Sessions;
// incoming // incoming
std::map<SessionTag, std::shared_ptr<i2p::crypto::CBCDecryption>> m_Tags; std::map<SessionTag, std::shared_ptr<AESDecryption> > m_Tags;
// DeliveryStatus // DeliveryStatus
std::mutex m_DeliveryStatusSessionsMutex; std::mutex m_DeliveryStatusSessionsMutex;
std::map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session std::map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
@ -205,7 +224,10 @@ namespace garlic
// for HTTP only // for HTTP only
size_t GetNumIncomingTags () const { return m_Tags.size (); } size_t GetNumIncomingTags () const { return m_Tags.size (); }
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
}; };
void CleanUpTagsFiles ();
} }
} }

2
Win32/installer.iss

@ -1,5 +1,5 @@
#define I2Pd_AppName "i2pd" #define I2Pd_AppName "i2pd"
#define I2Pd_ver "2.12.0" #define I2Pd_ver "2.13.0"
#define I2Pd_Publisher "PurpleI2P" #define I2Pd_Publisher "PurpleI2P"
[Setup] [Setup]

2
android/AndroidManifest.xml

@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.purplei2p.i2pd" package="org.purplei2p.i2pd"
android:versionCode="1" android:versionCode="1"
android:versionName="2.12.0"> android:versionName="2.13.0">
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/> <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>

2
appveyor.yml

@ -1,4 +1,4 @@
version: 2.12.{build} version: 2.13.{build}
pull_requests: pull_requests:
do_not_increment_build_number: true do_not_increment_build_number: true
branches: branches:

9
debian/changelog vendored

@ -1,3 +1,12 @@
i2pd (2.13.0-1) unstable; urgency=low
* updated to version 2.13.0/0.9.29
* updated debian/control
* renamed logrotate to i2pd.logrotate
* fixed init.d script
-- orignal <orignal@i2pmail.org> Tue, 6 Apr 2017 14:00:00 +0000
i2pd (2.12.0-1) unstable; urgency=low i2pd (2.12.0-1) unstable; urgency=low
* updated to version 2.12.0/0.9.28 * updated to version 2.12.0/0.9.28

38
debian/control vendored

@ -1,17 +1,10 @@
Source: i2pd Source: i2pd
Section: net Section: net
Priority: extra Priority: optional
Maintainer: R4SAS <r4sas@i2pmail.org> Maintainer: R4SAS <r4sas@i2pmail.org>
Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev, libboost-filesystem-dev, libboost-program-options-dev, libminiupnpc-dev, libssl-dev
gcc (>= 4.7) | clang (>= 3.3), Standards-Version: 3.9.6
libboost-system-dev (>= 1.46), Homepage: http://i2pd.website/
libboost-date-time-dev,
libboost-filesystem-dev,
libboost-program-options-dev,
libminiupnpc-dev,
libssl-dev
Standards-Version: 3.9.3
Homepage: https://github.com/PurpleI2P/i2pd
Vcs-Git: git://github.com/PurpleI2P/i2pd.git Vcs-Git: git://github.com/PurpleI2P/i2pd.git
Vcs-Browser: https://github.com/PurpleI2P/i2pd.git Vcs-Browser: https://github.com/PurpleI2P/i2pd.git
@ -19,26 +12,23 @@ Package: i2pd
Architecture: any Architecture: any
Pre-Depends: adduser Pre-Depends: adduser
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}
Recommends: privoxy Suggests: tor, privoxy
Suggests: tor Description: i2pd is a full-featured C++ implementation of I2P client.
Description: load-balanced unspoofable packet switching network - C++ port I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
I2P is an anonymizing network, offering a simple layer that identity-sensitive communications over I2P are anonymous and end-to-end encrypted, participants
applications can use to securely communicate. All data is wrapped with several don't reveal their real IP addresses.
layers of encryption, and the network is both distributed and dynamic, with no
trusted parties.
. .
This package contains the port of the I2P router to C++. Unless willing This package contains the full-featured C++ implementation of I2P router.
to test and report problems, you should install the 'i2p' package instead.
Package: i2pd-dbg Package: i2pd-dbg
Architecture: any Architecture: any
Priority: extra Priority: extra
Section: debug Section: debug
Depends: i2pd (= ${binary:Version}), ${misc:Depends} Depends: i2pd (= ${binary:Version}), ${misc:Depends}
Suggests: gdb
Description: i2pd debugging symbols Description: i2pd debugging symbols
I2P is an anonymizing network, offering a simple layer that identity-sensitive I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
applications can use to securely communicate. All data is wrapped with several communications over I2P are anonymous and end-to-end encrypted, participants
layers of encryption, and the network is both distributed and dynamic, with no don't reveal their real IP addresses.
trusted parties.
. .
This package contains symbols required for debugging. This package contains symbols required for debugging.

0
debian/logrotate → debian/i2pd.logrotate vendored

2
qt/i2pd_qt/android/AndroidManifest.xml

@ -1,5 +1,5 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.12.0" android:versionCode="2" android:installLocation="auto"> <manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.13.0" android:versionCode="2" android:installLocation="auto">
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/> <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- <application android:hardwareAccelerated="true" --> <!-- <application android:hardwareAccelerated="true" -->

2
version.h

@ -7,7 +7,7 @@
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 12 #define I2PD_VERSION_MINOR 13
#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)

Loading…
Cancel
Save