Compare commits

..

15 Commits

Author SHA1 Message Date
orignal
8fde36a4b0 Update version.h
version 0.4.0
2014-11-25 12:46:30 -05:00
orignal
de14f8dcd7 handle Phase3 in two steps 2014-11-25 12:33:51 -05:00
orignal
1e81652a62 send Phase3 with proper identity 2014-11-25 10:59:29 -05:00
orignal
f7ce86e0c4 pass tsA to SendPhase4 2014-11-25 10:35:35 -05:00
orignal
9eb5982ea3 use generic receive buffer for phase 4 2014-11-25 10:14:18 -05:00
orignal
4778c8bdfb fixed excess data for P521 2014-11-24 21:48:01 -05:00
orignal
9574163aeb fixed incorrect certificate length 2014-11-24 21:23:12 -05:00
orignal
199ff0c210 ECDSA P384 and ECDSA P521 support 2014-11-24 20:19:13 -05:00
orignal
e0635548e9 handle EcDSA signatures 2014-11-24 15:26:57 -05:00
orignal
95524c8db3 shared pointer for SSU 2014-11-24 12:26:11 -05:00
orignal
1a0957b571 move WaitForConnect away from constructor 2014-11-24 11:18:12 -05:00
orignal
97656e7349 shared pointer for I2PTunnelConnection 2014-11-23 22:23:17 -05:00
orignal
0262a8b057 replaced boost::bind to std::bind 2014-11-23 17:00:45 -05:00
orignal
4bd8b44ab2 shared pointers for streams 2014-11-23 11:33:58 -05:00
orignal
4dc33a6f45 fixed crash 2014-11-22 21:56:59 -05:00
28 changed files with 564 additions and 323 deletions

View File

@@ -38,7 +38,7 @@ namespace datagram
auto service = m_Owner.GetService ();
if (service)
service->post (boost::bind (&DatagramDestination::SendMsg, this,
service->post (std::bind (&DatagramDestination::SendMsg, this,
CreateDataMessage (buf, len + headerLen), remote));
else
LogPrint (eLogWarning, "Failed to send datagram. Destination is not running");

View File

@@ -190,12 +190,12 @@ namespace client
void ClientDestination::ProcessGarlicMessage (I2NPMessage * msg)
{
m_Service->post (boost::bind (&ClientDestination::HandleGarlicMessage, this, msg));
m_Service->post (std::bind (&ClientDestination::HandleGarlicMessage, this, msg));
}
void ClientDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg)
{
m_Service->post (boost::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg));
m_Service->post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg));
}
void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from)
@@ -274,7 +274,7 @@ namespace client
}
}
i2p::stream::Stream * ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port)
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port)
{
if (m_StreamingDestination)
return m_StreamingDestination->CreateNewOutgoingStream (remote, port);

View File

@@ -3,6 +3,7 @@
#include <thread>
#include <mutex>
#include <memory>
#include "Identity.h"
#include "TunnelPool.h"
#include "CryptoConst.h"
@@ -41,7 +42,7 @@ namespace client
// streaming
i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; };
i2p::stream::Stream * CreateStream (const i2p::data::LeaseSet& remote, int port = 0);
std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::LeaseSet& remote, int port = 0);
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
void StopAcceptingStreams ();
bool IsAcceptingStreams () const;

View File

@@ -518,7 +518,7 @@ namespace util
{
m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
m_Stream.reset ();
}
m_Socket->close ();
//delete this;

View File

@@ -3,6 +3,7 @@
#include <sstream>
#include <thread>
#include <memory>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include "LeaseSet.h"
@@ -79,7 +80,7 @@ namespace util
boost::asio::ip::tcp::socket * m_Socket;
boost::asio::deadline_timer m_Timer;
i2p::stream::Stream * m_Stream;
std::shared_ptr<i2p::stream::Stream> m_Stream;
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
size_t m_BufferLen;
request m_Request;

View File

@@ -1,4 +1,3 @@
#include <boost/bind.hpp>
#include "base64.h"
#include "Log.h"
#include "NetDb.h"
@@ -12,21 +11,15 @@ namespace client
{
I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner,
boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet):
m_Socket (socket), m_Owner (owner)
m_Socket (socket), m_Owner (owner), m_RemoteEndpoint (socket->remote_endpoint ())
{
m_Stream = m_Owner->GetLocalDestination ()->CreateStream (*leaseSet);
m_Stream->Send (m_Buffer, 0); // connect
StreamReceive ();
Receive ();
}
I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner, i2p::stream::Stream * stream,
I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner, std::shared_ptr<i2p::stream::Stream> stream,
boost::asio::ip::tcp::socket * socket, const boost::asio::ip::tcp::endpoint& target):
m_Socket (socket), m_Stream (stream), m_Owner (owner)
m_Socket (socket), m_Stream (stream), m_Owner (owner), m_RemoteEndpoint (target)
{
if (m_Socket)
m_Socket->async_connect (target, boost::bind (&I2PTunnelConnection::HandleConnect,
this, boost::asio::placeholders::error));
}
I2PTunnelConnection::~I2PTunnelConnection ()
@@ -34,25 +27,38 @@ namespace client
delete m_Socket;
}
void I2PTunnelConnection::I2PConnect ()
{
m_Stream->Send (m_Buffer, 0); // connect
StreamReceive ();
Receive ();
}
void I2PTunnelConnection::Connect ()
{
if (m_Socket)
m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect,
shared_from_this (), std::placeholders::_1));
}
void I2PTunnelConnection::Terminate ()
{
if (m_Stream)
{
m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
m_Stream.reset ();
}
m_Socket->close ();
if (m_Owner)
m_Owner->RemoveConnection (this);
//delete this;
m_Owner->RemoveConnection (shared_from_this ());
}
void I2PTunnelConnection::Receive ()
{
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
boost::bind(&I2PTunnelConnection::HandleReceived, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -87,8 +93,8 @@ namespace client
{
if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
boost::bind (&I2PTunnelConnection::HandleStreamReceive, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred),
std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2),
I2P_TUNNEL_CONNECTION_MAX_IDLE);
}
@@ -103,7 +109,7 @@ namespace client
else
{
boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
boost::bind (&I2PTunnelConnection::HandleWrite, this, boost::asio::placeholders::error));
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
}
}
@@ -112,12 +118,7 @@ namespace client
if (ecode)
{
LogPrint ("I2PTunnel connect error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
{
if (m_Stream) m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
Terminate ();
}
else
{
@@ -127,20 +128,18 @@ namespace client
}
}
void I2PTunnel::AddConnection (I2PTunnelConnection * conn)
void I2PTunnel::AddConnection (std::shared_ptr<I2PTunnelConnection> conn)
{
m_Connections.insert (conn);
}
void I2PTunnel::RemoveConnection (I2PTunnelConnection * conn)
void I2PTunnel::RemoveConnection (std::shared_ptr<I2PTunnelConnection> conn)
{
m_Connections.erase (conn);
}
void I2PTunnel::ClearConnections ()
{
for (auto it: m_Connections)
delete it;
m_Connections.clear ();
}
@@ -181,8 +180,8 @@ namespace client
void I2PClientTunnel::Accept ()
{
auto newSocket = new boost::asio::ip::tcp::socket (GetService ());
m_Acceptor.async_accept (*newSocket, boost::bind (&I2PClientTunnel::HandleAccept, this,
boost::asio::placeholders::error, newSocket));
m_Acceptor.async_accept (*newSocket, std::bind (&I2PClientTunnel::HandleAccept, this,
std::placeholders::_1, newSocket));
}
void I2PClientTunnel::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket)
@@ -205,8 +204,8 @@ namespace client
{
i2p::data::netdb.RequestDestination (*m_DestinationIdentHash, true, GetLocalDestination ()->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds (I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT));
m_Timer.async_wait (boost::bind (&I2PClientTunnel::HandleDestinationRequestTimer,
this, boost::asio::placeholders::error, socket));
m_Timer.async_wait (std::bind (&I2PClientTunnel::HandleDestinationRequestTimer,
this, std::placeholders::_1, socket));
}
}
else
@@ -240,8 +239,9 @@ namespace client
if (m_RemoteLeaseSet) // leaseSet found
{
LogPrint ("New I2PTunnel connection");
auto connection = new I2PTunnelConnection (this, socket, m_RemoteLeaseSet);
auto connection = std::make_shared<I2PTunnelConnection>(this, socket, m_RemoteLeaseSet);
AddConnection (connection);
connection->I2PConnect ();
}
else
{
@@ -275,10 +275,14 @@ namespace client
LogPrint ("Local destination not set for server tunnel");
}
void I2PServerTunnel::HandleAccept (i2p::stream::Stream * stream)
void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
{
if (stream)
new I2PTunnelConnection (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint);
{
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint);
AddConnection (conn);
conn->Connect ();
}
}
}
}

View File

@@ -4,6 +4,7 @@
#include <inttypes.h>
#include <string>
#include <set>
#include <memory>
#include <boost/asio.hpp>
#include "Identity.h"
#include "Destination.h"
@@ -18,16 +19,19 @@ namespace client
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
class I2PTunnel;
class I2PTunnelConnection
class I2PTunnelConnection: public std::enable_shared_from_this<I2PTunnelConnection>
{
public:
I2PTunnelConnection (I2PTunnel * owner, boost::asio::ip::tcp::socket * socket,
const i2p::data::LeaseSet * leaseSet);
I2PTunnelConnection (I2PTunnel * owner, i2p::stream::Stream * stream, boost::asio::ip::tcp::socket * socket,
I2PTunnelConnection (I2PTunnel * owner, std::shared_ptr<i2p::stream::Stream> stream, boost::asio::ip::tcp::socket * socket,
const boost::asio::ip::tcp::endpoint& target);
~I2PTunnelConnection ();
void I2PConnect ();
void Connect ();
private:
void Terminate ();
@@ -44,8 +48,9 @@ namespace client
uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE];
boost::asio::ip::tcp::socket * m_Socket;
i2p::stream::Stream * m_Stream;
std::shared_ptr<i2p::stream::Stream> m_Stream;
I2PTunnel * m_Owner;
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
};
class I2PTunnel
@@ -56,8 +61,8 @@ namespace client
m_Service (service), m_LocalDestination (localDestination) {};
virtual ~I2PTunnel () { ClearConnections (); };
void AddConnection (I2PTunnelConnection * conn);
void RemoveConnection (I2PTunnelConnection * conn);
void AddConnection (std::shared_ptr<I2PTunnelConnection> conn);
void RemoveConnection (std::shared_ptr<I2PTunnelConnection> conn);
void ClearConnections ();
ClientDestination * GetLocalDestination () { return m_LocalDestination; };
void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; };
@@ -68,7 +73,7 @@ namespace client
boost::asio::io_service& m_Service;
ClientDestination * m_LocalDestination;
std::set<I2PTunnelConnection *> m_Connections;
std::set<std::shared_ptr<I2PTunnelConnection> > m_Connections;
};
class I2PClientTunnel: public I2PTunnel
@@ -111,7 +116,7 @@ namespace client
private:
void Accept ();
void HandleAccept (i2p::stream::Stream * stream);
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
private:

View File

@@ -42,18 +42,53 @@ namespace data
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type)
{
memcpy (m_StandardIdentity.publicKey, publicKey, sizeof (m_StandardIdentity.publicKey));
if (type == SIGNING_KEY_TYPE_ECDSA_SHA256_P256)
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{
memcpy (m_StandardIdentity.signingKey + 64, signingKey, 64);
size_t excessLen = 0;
uint8_t * excessBuf = nullptr;
switch (type)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
{
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
{
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP384_KEY_LENGTH);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
{
memcpy (m_StandardIdentity.signingKey, signingKey, 128);
excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132 - 128
excessBuf = new uint8_t[excessLen];
memcpy (excessBuf, signingKey + 128, excessLen);
break;
}
default:
LogPrint ("Signing key type ", (int)type, " is not supported");
}
m_ExtendedLen = 4 + excessLen; // 4 bytes extra + excess length
// fill certificate
m_StandardIdentity.certificate.type = CERTIFICATE_TYPE_KEY;
m_ExtendedLen = 4; // 4 bytes extra
m_StandardIdentity.certificate.length = htobe16 (4);
m_StandardIdentity.certificate.length = htobe16 (m_ExtendedLen);
// fill extended buffer
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
*(uint16_t *)m_ExtendedBuffer = htobe16 (SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
*(uint16_t *)m_ExtendedBuffer = htobe16 (type);
*(uint16_t *)(m_ExtendedBuffer + 2) = htobe16 (CRYPTO_KEY_TYPE_ELGAMAL);
uint8_t buf[DEFAULT_IDENTITY_SIZE + 4];
ToBuffer (buf, DEFAULT_IDENTITY_SIZE + 4);
if (excessLen && excessBuf)
{
memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen);
delete[] excessBuf;
}
// calculate ident hash
uint8_t * buf = new uint8_t[GetFullLen ()];
ToBuffer (buf, GetFullLen ());
CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen ());
delete[] buf;
}
else // DSA-SHA1
{
@@ -188,6 +223,13 @@ namespace data
return be16toh (*(const uint16_t *)m_ExtendedBuffer); // signing key
return SIGNING_KEY_TYPE_DSA_SHA1;
}
CryptoKeyType IdentityEx::GetCryptoKeyType () const
{
if (m_StandardIdentity.certificate.type == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
return be16toh (*(const uint16_t *)(m_ExtendedBuffer + 2)); // crypto key
return CRYPTO_KEY_TYPE_ELGAMAL;
}
void IdentityEx::CreateVerifier () const
{
@@ -198,8 +240,26 @@ namespace data
m_Verifier = new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
m_Verifier = new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + 64);
break;
{
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
m_Verifier = new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
{
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
m_Verifier = new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
{
uint8_t signingKey[i2p::crypto::ECDSAP521_KEY_LENGTH];
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier = new i2p::crypto::ECDSAP521Verifier (signingKey);
break;
}
default:
LogPrint ("Signing key type ", (int)keyType, " is not supported");
}
@@ -211,6 +271,7 @@ namespace data
memcpy (m_PrivateKey, keys.privateKey, 256); // 256
memcpy (m_SigningPrivateKey, keys.signingPrivateKey, 20); // 20 - DSA
delete m_Signer;
m_Signer = nullptr;
CreateSigner ();
return *this;
}
@@ -221,6 +282,7 @@ namespace data
memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256
memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, 128); // 128
delete m_Signer;
m_Signer = nullptr;
CreateSigner ();
return *this;
}
@@ -234,6 +296,7 @@ namespace data
memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize);
ret += signingPrivateKeySize;
delete m_Signer;
m_Signer = nullptr;
CreateSigner ();
return ret;
}
@@ -257,26 +320,55 @@ namespace data
void PrivateKeys::CreateSigner ()
{
if (m_Public.GetSigningKeyType () == SIGNING_KEY_TYPE_ECDSA_SHA256_P256)
m_Signer = new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey);
else
m_Signer = new i2p::crypto::DSASigner (m_SigningPrivateKey);
switch (m_Public.GetSigningKeyType ())
{
case SIGNING_KEY_TYPE_DSA_SHA1:
m_Signer = new i2p::crypto::DSASigner (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
m_Signer = new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
m_Signer = new i2p::crypto::ECDSAP384Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
m_Signer = new i2p::crypto::ECDSAP521Signer (m_SigningPrivateKey);
break;
default:
LogPrint ("Signing key type ", (int)m_Public.GetSigningKeyType (), " is not supported");
}
}
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type)
{
if (type == SIGNING_KEY_TYPE_ECDSA_SHA256_P256)
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{
PrivateKeys keys;
auto& rnd = i2p::context.GetRandomNumberGenerator ();
// signature
uint8_t signingPublicKey[i2p::crypto::ECDSAP521_KEY_LENGTH]; // 132 bytes is max key size now
switch (type)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
i2p::crypto::CreateECDSAP256RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
i2p::crypto::CreateECDSAP384RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
i2p::crypto::CreateECDSAP521RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
default:
LogPrint ("Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
}
// encryption
uint8_t publicKey[256];
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(rnd, keys.m_PrivateKey, publicKey);
// signature
uint8_t signingPublicKey[64];
i2p::crypto::CreateECDSAP256RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
keys.m_Public = IdentityEx (publicKey, signingPublicKey, SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
// identity
keys.m_Public = IdentityEx (publicKey, signingPublicKey, type);
keys.CreateSigner ();
return keys;
}

View File

@@ -102,11 +102,14 @@ namespace data
Keys CreateRandomKeys ();
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA384_P384 = 2;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA512_P521 = 3;
typedef uint16_t SigningKeyType;
typedef uint16_t CryptoKeyType;
class IdentityEx
{
@@ -131,6 +134,7 @@ namespace data
size_t GetSignatureLen () const;
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
SigningKeyType GetSigningKeyType () const;
CryptoKeyType GetCryptoKeyType () const;
private:

View File

@@ -44,7 +44,7 @@ namespace transport
uint8_t sharedKey[256];
if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey))
{
LogPrint ("Couldn't create shared key");
LogPrint (eLogError, "Couldn't create shared key");
Terminate ();
return;
};
@@ -66,7 +66,7 @@ namespace transport
nonZero++;
if (nonZero - sharedKey > 32)
{
LogPrint ("First 32 bytes of shared key is all zeros. Ignored");
LogPrint (eLogWarning, "First 32 bytes of shared key is all zeros. Ignored");
return;
}
}
@@ -89,7 +89,7 @@ namespace transport
}
m_DelayedMessages.clear ();
if (numDelayed > 0)
LogPrint ("NTCP session ", numDelayed, " not sent");
LogPrint (eLogWarning, "NTCP session ", numDelayed, " not sent");
// TODO: notify tunnels
delete this;
@@ -146,13 +146,13 @@ namespace transport
{
if (ecode)
{
LogPrint ("Couldn't send Phase 1 message: ", ecode.message ());
LogPrint (eLogWarning, "Couldn't send Phase 1 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint ("Phase 1 sent: ", bytes_transferred);
LogPrint (eLogDebug, "Phase 1 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase2Received, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
@@ -163,13 +163,13 @@ namespace transport
{
if (ecode)
{
LogPrint ("Phase 1 read error: ", ecode.message ());
LogPrint (eLogError, "Phase 1 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint ("Phase 1 received: ", bytes_transferred);
LogPrint (eLogDebug, "Phase 1 received: ", bytes_transferred);
// verify ident
uint8_t digest[32];
CryptoPP::SHA256().CalculateDigest(digest, m_Establisher->phase1.pubKey, 256);
@@ -178,7 +178,7 @@ namespace transport
{
if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i])
{
LogPrint ("Wrong ident");
LogPrint (eLogError, "Wrong ident");
Terminate ();
return;
}
@@ -219,14 +219,14 @@ namespace transport
{
if (ecode)
{
LogPrint ("Couldn't send Phase 2 message: ", ecode.message ());
LogPrint (eLogWarning, "Couldn't send Phase 2 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint ("Phase 2 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase3, sizeof (NTCPPhase3)), boost::asio::transfer_all (),
LogPrint (eLogDebug, "Phase 2 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, NTCP_DEFAULT_PHASE3_SIZE), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase3Received, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB));
}
@@ -248,7 +248,7 @@ namespace transport
}
else
{
LogPrint ("Phase 2 received: ", bytes_transferred);
LogPrint (eLogDebug, "Phase 2 received: ", bytes_transferred);
i2p::crypto::AESKey aesKey;
CreateAESKey (m_Establisher->phase2.pubKey, aesKey);
@@ -265,7 +265,7 @@ namespace transport
CryptoPP::SHA256().CalculateDigest(hxy, xy, 512);
if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32))
{
LogPrint ("Incorrect hash");
LogPrint (eLogError, "Incorrect hash");
transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr;
Terminate ();
@@ -277,22 +277,35 @@ namespace transport
void NTCPSession::SendPhase3 ()
{
m_Establisher->phase3.size = htons (i2p::data::DEFAULT_IDENTITY_SIZE);
memcpy (&m_Establisher->phase3.ident, &i2p::context.GetIdentity ().GetStandardIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE); // TODO:
auto keys = i2p::context.GetPrivateKeys ();
uint8_t * buf = m_ReceiveBuffer;
*(uint16_t *)buf = htobe16 (keys.GetPublic ().GetFullLen ());
buf += 2;
buf += i2p::context.GetIdentity ().ToBuffer (buf, NTCP_BUFFER_SIZE);
uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ());
m_Establisher->phase3.timestamp = tsA;
*(uint32_t *)buf = tsA;
buf += 4;
size_t signatureLen = keys.GetPublic ().GetSignatureLen ();
size_t len = (buf - m_ReceiveBuffer) + signatureLen;
size_t paddingSize = len & 0x0F; // %16
if (paddingSize > 0)
{
paddingSize = 16 - paddingSize;
// TODO: fill padding with random data
buf += paddingSize;
len += paddingSize;
}
SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
s.Sign (i2p::context.GetPrivateKeys (), m_Establisher->phase3.signature);
s.Sign (keys, buf);
m_Encryption.Encrypt((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase3, sizeof (NTCPPhase3)), boost::asio::transfer_all (),
m_Encryption.Encrypt(m_ReceiveBuffer, len, m_ReceiveBuffer);
boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, len), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase3Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA));
}
@@ -300,14 +313,18 @@ namespace transport
{
if (ecode)
{
LogPrint ("Couldn't send Phase 3 message: ", ecode.message ());
LogPrint (eLogWarning, "Couldn't send Phase 3 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint ("Phase 3 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase4, sizeof (NTCPPhase4)), boost::asio::transfer_all (),
LogPrint (eLogDebug, "Phase 3 sent: ", bytes_transferred);
// wait for phase4
auto signatureLen = m_RemoteIdentity.GetSignatureLen ();
size_t paddingSize = signatureLen & 0x0F; // %16
if (paddingSize > 0) signatureLen += (16 - paddingSize);
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase4Received, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA));
}
@@ -317,45 +334,89 @@ namespace transport
{
if (ecode)
{
LogPrint ("Phase 3 read error: ", ecode.message ());
LogPrint (eLogError, "Phase 3 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint ("Phase 3 received: ", bytes_transferred);
m_Decryption.Decrypt ((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3);
m_RemoteIdentity = m_Establisher->phase3.ident;
LogPrint (eLogDebug, "Phase 3 received: ", bytes_transferred);
m_Decryption.Decrypt (m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
uint8_t * buf = m_ReceiveBuffer;
uint16_t size = be16toh (*(uint16_t *)buf);
m_RemoteIdentity.FromBuffer (buf + 2, size);
size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity.GetSignatureLen ();
size_t paddingLen = expectedSize & 0x0F;
if (paddingLen) paddingLen = (16 - paddingLen);
if (expectedSize > NTCP_DEFAULT_PHASE3_SIZE)
{
// we need more bytes for Phase3
expectedSize += paddingLen;
LogPrint (eLogDebug, "Wait for ", expectedSize, " more bytes for Phase3");
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, expectedSize), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase3ExtraReceived, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB, paddingLen));
}
SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident
s.Insert (m_Establisher->phase3.timestamp); // tsA
s.Insert (tsB); // tsB
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase3.signature))
{
LogPrint ("signature verification failed");
Terminate ();
return;
}
SendPhase4 (tsB);
HandlePhase3 (tsB, paddingLen);
}
}
void NTCPSession::SendPhase4 (uint32_t tsB)
void NTCPSession::HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen)
{
if (ecode)
{
LogPrint (eLogError, "Phase 3 extra read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint (eLogDebug, "Phase 3 extra received: ", bytes_transferred);
m_Decryption.Decrypt (m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, bytes_transferred, m_ReceiveBuffer+ NTCP_DEFAULT_PHASE3_SIZE);
HandlePhase3 (tsB, paddingLen);
}
}
void NTCPSession::HandlePhase3 (uint32_t tsB, size_t paddingLen)
{
uint8_t * buf = m_ReceiveBuffer + m_RemoteIdentity.GetFullLen () + 2 /*size*/;
uint32_t tsA = *(uint32_t *)buf;
buf += 4;
buf += paddingLen;
SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA
s.Insert (tsB); // tsB
if (!s.Verify (m_RemoteIdentity, buf))
{
LogPrint (eLogError, "signature verification failed");
Terminate ();
return;
}
SendPhase4 (tsA, tsB);
}
void NTCPSession::SendPhase4 (uint32_t tsA, uint32_t tsB)
{
SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident
s.Insert (m_Establisher->phase3.timestamp); // tsA
s.Insert (tsA); // tsA
s.Insert (tsB); // tsB
s.Sign (i2p::context.GetPrivateKeys (), m_Establisher->phase4.signature);
m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase4, sizeof(NTCPPhase4), (uint8_t *)&m_Establisher->phase4);
auto keys = i2p::context.GetPrivateKeys ();
auto signatureLen = keys.GetPublic ().GetSignatureLen ();
s.Sign (keys, m_ReceiveBuffer);
size_t paddingSize = signatureLen & 0x0F; // %16
if (paddingSize > 0) signatureLen += (16 - paddingSize);
m_Encryption.Encrypt (m_ReceiveBuffer, signatureLen, m_ReceiveBuffer);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase4, sizeof (NTCPPhase4)), boost::asio::transfer_all (),
boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase4Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
@@ -363,13 +424,13 @@ namespace transport
{
if (ecode)
{
LogPrint ("Couldn't send Phase 4 message: ", ecode.message ());
LogPrint (eLogWarning, "Couldn't send Phase 4 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint ("Phase 4 sent: ", bytes_transferred);
LogPrint (eLogDebug, "Phase 4 sent: ", bytes_transferred);
Connected ();
m_ReceiveBufferOffset = 0;
m_NextMessage = nullptr;
@@ -381,7 +442,7 @@ namespace transport
{
if (ecode)
{
LogPrint ("Phase 4 read error: ", ecode.message ());
LogPrint (eLogError, "Phase 4 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
{
// this router doesn't like us
@@ -391,8 +452,8 @@ namespace transport
}
else
{
LogPrint ("Phase 4 received: ", bytes_transferred);
m_Decryption.Decrypt((uint8_t *)&m_Establisher->phase4, sizeof(NTCPPhase4), (uint8_t *)&m_Establisher->phase4);
LogPrint (eLogDebug, "Phase 4 received: ", bytes_transferred);
m_Decryption.Decrypt(m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
// verify signature
SignedData s;
@@ -402,9 +463,9 @@ namespace transport
s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase4.signature))
if (!s.Verify (m_RemoteIdentity, m_ReceiveBuffer))
{
LogPrint ("signature verification failed");
LogPrint (eLogError, "signature verification failed");
Terminate ();
return;
}
@@ -427,7 +488,7 @@ namespace transport
{
if (ecode)
{
LogPrint ("Read error: ", ecode.message ());
LogPrint (eLogError, "Read error: ", ecode.message ());
//if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -472,7 +533,7 @@ namespace transport
// new message
if (dataSize > NTCP_MAX_MESSAGE_SIZE)
{
LogPrint ("NTCP data size ", dataSize, " exceeds max size");
LogPrint (eLogError, "NTCP data size ", dataSize, " exceeds max size");
i2p::DeleteI2NPMessage (m_NextMessage);
m_NextMessage = nullptr;
return false;
@@ -515,7 +576,7 @@ namespace transport
// regular I2NP
if (msg->offset < 2)
{
LogPrint ("Malformed I2NP message");
LogPrint (eLogError, "Malformed I2NP message");
i2p::DeleteI2NPMessage (msg);
}
sendBuffer = msg->GetBuffer () - 2;
@@ -549,7 +610,7 @@ namespace transport
i2p::DeleteI2NPMessage (msg);
if (ecode)
{
LogPrint ("Couldn't send msg: ", ecode.message ());
LogPrint (eLogWarning, "Couldn't send msg: ", ecode.message ());
// we shouldn't call Terminate () here, because HandleReceive takes care
// TODO: 'delete this' statement in Terminate () must be eliminated later
// Terminate ();

View File

@@ -35,28 +35,13 @@ namespace transport
uint8_t filler[12];
} encrypted;
};
struct NTCPPhase3
{
uint16_t size;
i2p::data::Identity ident;
uint32_t timestamp;
uint8_t padding[15];
uint8_t signature[40];
};
struct NTCPPhase4
{
uint8_t signature[40];
uint8_t padding[8];
};
#pragma pack()
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028)
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 428
class NTCPSession: public TransportSession
{
@@ -95,10 +80,12 @@ namespace transport
//server
void SendPhase2 ();
void SendPhase4 (uint32_t tsB);
void SendPhase4 (uint32_t tsA, uint32_t tsB);
void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB);
void HandlePhase3Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB);
void HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen);
void HandlePhase3 (uint32_t tsB, size_t paddingLen);
void HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
// common
@@ -128,11 +115,10 @@ namespace transport
{
NTCPPhase1 phase1;
NTCPPhase2 phase2;
NTCPPhase3 phase3;
NTCPPhase4 phase4;
} * m_Establisher;
uint8_t m_ReceiveBuffer[NTCP_BUFFER_SIZE + 16], m_TimeSyncBuffer[16];
i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer;
i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer;
int m_ReceiveBufferOffset;
i2p::I2NPMessage * m_NextMessage;

84
SAM.cpp
View File

@@ -3,7 +3,6 @@
#ifdef _MSC_VER
#include <stdlib.h>
#endif
#include <boost/bind.hpp>
#include "base64.h"
#include "Identity.h"
#include "Log.h"
@@ -25,18 +24,22 @@ namespace client
SAMSocket::~SAMSocket ()
{
if (m_Stream)
i2p::stream::DeleteStream (m_Stream);
Terminate ();
}
void SAMSocket::Terminate ()
void SAMSocket::CloseStream ()
{
if (m_Stream)
{
m_Stream->Close ();
// TODO: make this swap atomic
auto session = m_Session;
m_Session = nullptr;
i2p::stream::DeleteStream (m_Stream);
m_Stream.reset ();
}
}
void SAMSocket::Terminate ()
{
CloseStream ();
switch (m_SocketType)
{
@@ -45,30 +48,31 @@ namespace client
break;
case eSAMSocketTypeStream:
{
if (session)
session->sockets.remove (shared_from_this ());
if (m_Session)
m_Session->sockets.remove (shared_from_this ());
break;
}
case eSAMSocketTypeAcceptor:
{
if (session)
if (m_Session)
{
session->sockets.remove (shared_from_this ());
session->localDestination->StopAcceptingStreams ();
m_Session->sockets.remove (shared_from_this ());
m_Session->localDestination->StopAcceptingStreams ();
}
break;
}
default:
;
}
m_SocketType = eSAMSocketTypeTerminated;
m_Socket.close ();
}
void SAMSocket::ReceiveHandshake ()
{
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -87,8 +91,8 @@ namespace client
{
// TODO: check version
boost::asio::async_write (m_Socket, boost::asio::buffer (SAM_HANDSHAKE_REPLY, strlen (SAM_HANDSHAKE_REPLY)), boost::asio::transfer_all (),
boost::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
std::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
else
{
@@ -109,8 +113,8 @@ namespace client
else
{
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind(&SAMSocket::HandleMessage, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
std::bind(&SAMSocket::HandleMessage, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
}
@@ -118,8 +122,8 @@ namespace client
{
if (!m_IsSilent || m_SocketType == eSAMSocketTypeAcceptor)
boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (),
boost::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, close));
std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2, close));
else
{
if (close)
@@ -232,8 +236,8 @@ namespace client
else
{
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
shared_from_this (), boost::asio::placeholders::error));
m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
shared_from_this (), std::placeholders::_1));
}
}
else
@@ -249,8 +253,8 @@ namespace client
else
{
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
shared_from_this (), boost::asio::placeholders::error));
m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
shared_from_this (), std::placeholders::_1));
}
}
}
@@ -294,8 +298,8 @@ namespace client
{
i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true, m_Session->localDestination->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleStreamDestinationRequestTimer,
shared_from_this (), boost::asio::placeholders::error, dest.GetIdentHash ()));
m_Timer.async_wait (std::bind (&SAMSocket::HandleStreamDestinationRequestTimer,
shared_from_this (), std::placeholders::_1, dest.GetIdentHash ()));
}
}
else
@@ -417,8 +421,8 @@ namespace client
{
i2p::data::netdb.RequestDestination (ident, true, m_Session->localDestination->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_NAMING_LOOKUP_TIMEOUT));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleNamingLookupDestinationRequestTimer,
shared_from_this (), boost::asio::placeholders::error, ident));
m_Timer.async_wait (std::bind (&SAMSocket::HandleNamingLookupDestinationRequestTimer,
shared_from_this (), std::placeholders::_1, ident));
}
}
else
@@ -470,8 +474,8 @@ namespace client
void SAMSocket::Receive ()
{
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind((m_SocketType == eSAMSocketTypeSession) ? &SAMSocket::HandleMessage : &SAMSocket::HandleReceived,
shared_from_this (), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
std::bind((m_SocketType == eSAMSocketTypeSession) ? &SAMSocket::HandleMessage : &SAMSocket::HandleReceived,
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
}
void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -494,8 +498,8 @@ namespace client
{
if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind (&SAMSocket::HandleI2PReceive, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred),
std::bind (&SAMSocket::HandleI2PReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2),
SAM_SOCKET_CONNECTION_MAX_IDLE);
}
@@ -510,7 +514,7 @@ namespace client
else
{
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
boost::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), boost::asio::placeholders::error));
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
}
}
@@ -526,7 +530,7 @@ namespace client
I2PReceive ();
}
void SAMSocket::HandleI2PAccept (i2p::stream::Stream * stream)
void SAMSocket::HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream)
{
if (stream)
{
@@ -563,7 +567,7 @@ namespace client
{
memcpy (m_StreamBuffer + l2, buf, len);
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len + l2),
boost::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), boost::asio::placeholders::error));
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
}
else
LogPrint (eLogWarning, "Datagram size ", len," exceeds buffer");
@@ -619,8 +623,8 @@ namespace client
void SAMBridge::Accept ()
{
auto newSocket = std::make_shared<SAMSocket> (*this);
m_Acceptor.async_accept (newSocket->GetSocket (), boost::bind (&SAMBridge::HandleAccept, this,
boost::asio::placeholders::error, newSocket));
m_Acceptor.async_accept (newSocket->GetSocket (), std::bind (&SAMBridge::HandleAccept, this,
std::placeholders::_1, newSocket));
}
void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket)
@@ -670,6 +674,8 @@ namespace client
auto it = m_Sessions.find (id);
if (it != m_Sessions.end ())
{
for (auto it1: it->second.sockets)
it1->CloseStream ();
it->second.sockets.clear ();
it->second.localDestination->Stop ();
m_Sessions.erase (it);
@@ -690,7 +696,7 @@ namespace client
m_DatagramSocket.async_receive_from (
boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE),
m_SenderEndpoint,
boost::bind (&SAMBridge::HandleReceivedDatagram, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
std::bind (&SAMBridge::HandleReceivedDatagram, this, std::placeholders::_1, std::placeholders::_2));
}
void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred)

10
SAM.h
View File

@@ -60,7 +60,8 @@ namespace client
eSAMSocketTypeUnknown,
eSAMSocketTypeSession,
eSAMSocketTypeStream,
eSAMSocketTypeAcceptor
eSAMSocketTypeAcceptor,
eSAMSocketTypeTerminated
};
class SAMBridge;
@@ -71,7 +72,8 @@ namespace client
SAMSocket (SAMBridge& owner);
~SAMSocket ();
void CloseStream (); // TODO: implement it better
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
void ReceiveHandshake ();
@@ -88,7 +90,7 @@ namespace client
void I2PReceive ();
void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleI2PAccept (i2p::stream::Stream * stream);
void HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream);
void HandleWriteI2PData (const boost::system::error_code& ecode);
void HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len);
@@ -116,7 +118,7 @@ namespace client
SAMSocketType m_SocketType;
std::string m_ID; // nickname
bool m_IsSilent;
i2p::stream::Stream * m_Stream;
std::shared_ptr<i2p::stream::Stream> m_Stream;
SAMSession * m_Session;
};

View File

@@ -77,8 +77,7 @@ namespace proxy
{
if (m_stream) {
LogPrint("--- socks4a close stream");
delete m_stream;
m_stream = nullptr;
m_stream.reset ();
}
}

View File

@@ -5,7 +5,7 @@
#include <boost/asio.hpp>
#include <vector>
#include <mutex>
#include <memory>
#include "Identity.h"
#include "Streaming.h"
@@ -47,7 +47,7 @@ namespace proxy
boost::asio::io_service * m_ios;
boost::asio::ip::tcp::socket * m_sock;
boost::asio::deadline_timer m_ls_timer;
i2p::stream::Stream * m_stream;
std::shared_ptr<i2p::stream::Stream> m_stream;
i2p::data::LeaseSet * m_ls;
i2p::data::IdentHash m_dest;
state m_state;

54
SSU.cpp
View File

@@ -27,17 +27,15 @@ namespace transport
SSUServer::~SSUServer ()
{
for (auto it: m_Sessions)
delete it.second;
}
void SSUServer::Start ()
{
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
m_Service.post (boost::bind (&SSUServer::Receive, this));
m_Service.post (std::bind (&SSUServer::Receive, this));
if (context.SupportsV6 ())
m_Service.post (boost::bind (&SSUServer::ReceiveV6, this));
m_Service.post (std::bind (&SSUServer::ReceiveV6, this));
if (i2p::context.IsUnreachable ())
ScheduleIntroducersUpdateTimer ();
}
@@ -76,7 +74,7 @@ namespace transport
m_Relays[tag] = relay;
}
SSUSession * SSUServer::FindRelaySession (uint32_t tag)
std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag)
{
auto it = m_Relays.find (tag);
if (it != m_Relays.end ())
@@ -128,20 +126,21 @@ namespace transport
void SSUServer::HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred)
{
SSUSession * session = nullptr;
std::shared_ptr<SSUSession> session;
auto it = m_Sessions.find (from);
if (it != m_Sessions.end ())
session = it->second;
if (!session)
{
session = new SSUSession (*this, from);
session = std::make_shared<SSUSession> (*this, from);
session->WaitForConnect ();
m_Sessions[from] = session;
LogPrint ("New SSU session from ", from.address ().to_string (), ":", from.port (), " created");
}
session->ProcessNextMessage (buf, bytes_transferred, from);
}
SSUSession * SSUServer::FindSession (const i2p::data::RouterInfo * router) const
std::shared_ptr<SSUSession> SSUServer::FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const
{
if (!router) return nullptr;
auto address = router->GetSSUAddress (true); // v4 only
@@ -155,7 +154,7 @@ namespace transport
return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port));
}
SSUSession * SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
{
auto it = m_Sessions.find (e);
if (it != m_Sessions.end ())
@@ -164,9 +163,9 @@ namespace transport
return nullptr;
}
SSUSession * SSUServer::GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
std::shared_ptr<SSUSession> SSUServer::GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
{
SSUSession * session = nullptr;
std::shared_ptr<SSUSession> session;
if (router)
{
auto address = router->GetSSUAddress (!context.SupportsV6 ());
@@ -179,7 +178,7 @@ namespace transport
else
{
// otherwise create new session
session = new SSUSession (*this, remoteEndpoint, router, peerTest);
session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
m_Sessions[remoteEndpoint] = session;
if (!router->UsesIntroducer ())
@@ -195,7 +194,7 @@ namespace transport
int numIntroducers = address->introducers.size ();
if (numIntroducers > 0)
{
SSUSession * introducerSession = nullptr;
std::shared_ptr<SSUSession> introducerSession;
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
// we might have a session to introducer already
for (int i = 0; i < numIntroducers; i++)
@@ -216,7 +215,7 @@ namespace transport
LogPrint ("Creating new session to introducer");
introducer = &(address->introducers[0]); // TODO:
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
introducerSession = new SSUSession (*this, introducerEndpoint, router);
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = introducerSession;
}
// introduce
@@ -231,8 +230,7 @@ namespace transport
{
LogPrint (eLogWarning, "Can't connect to unreachable router. No introducers presented");
m_Sessions.erase (remoteEndpoint);
delete session;
session = nullptr;
session.reset ();
}
}
}
@@ -243,30 +241,26 @@ namespace transport
return session;
}
void SSUServer::DeleteSession (SSUSession * session)
void SSUServer::DeleteSession (std::shared_ptr<SSUSession> session)
{
if (session)
{
session->Close ();
m_Sessions.erase (session->GetRemoteEndpoint ());
delete session;
}
}
void SSUServer::DeleteAllSessions ()
{
for (auto it: m_Sessions)
{
it.second->Close ();
delete it.second;
}
m_Sessions.clear ();
}
template<typename Filter>
SSUSession * SSUServer::GetRandomSession (Filter filter)
std::shared_ptr<SSUSession> SSUServer::GetRandomSession (Filter filter)
{
std::vector<SSUSession *> filteredSessions;
std::vector<std::shared_ptr<SSUSession> > filteredSessions;
for (auto s :m_Sessions)
if (filter (s.second)) filteredSessions.push_back (s.second);
if (filteredSessions.size () > 0)
@@ -277,10 +271,10 @@ namespace transport
return nullptr;
}
SSUSession * SSUServer::GetRandomEstablishedSession (const SSUSession * excluded)
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded)
{
return GetRandomSession (
[excluded](SSUSession * session)->bool
[excluded](std::shared_ptr<SSUSession> session)->bool
{
return session->GetState () == eSessionStateEstablished &&
session != excluded;
@@ -295,16 +289,16 @@ namespace transport
for (int i = 0; i < maxNumIntroducers; i++)
{
auto session = GetRandomSession (
[&ret, ts](SSUSession * session)->bool
[&ret, ts](std::shared_ptr<SSUSession> session)->bool
{
return session->GetRelayTag () && !ret.count (session) &&
return session->GetRelayTag () && !ret.count (session.get ()) &&
session->GetState () == eSessionStateEstablished &&
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
}
);
if (session)
{
ret.insert (session);
ret.insert (session.get ());
break;
}
}
@@ -314,8 +308,8 @@ namespace transport
void SSUServer::ScheduleIntroducersUpdateTimer ()
{
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
m_IntroducersUpdateTimer.async_wait (boost::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, boost::asio::placeholders::error));
m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, std::placeholders::_1));
}
void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode)

16
SSU.h
View File

@@ -31,18 +31,18 @@ namespace transport
~SSUServer ();
void Start ();
void Stop ();
SSUSession * GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
SSUSession * FindSession (const i2p::data::RouterInfo * router) const;
SSUSession * FindSession (const boost::asio::ip::udp::endpoint& e) const;
SSUSession * GetRandomEstablishedSession (const SSUSession * excluded);
void DeleteSession (SSUSession * session);
std::shared_ptr<SSUSession> GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
std::shared_ptr<SSUSession> GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded);
void DeleteSession (std::shared_ptr<SSUSession> session);
void DeleteAllSessions ();
boost::asio::io_service& GetService () { return m_Socket.get_io_service(); };
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay);
SSUSession * FindRelaySession (uint32_t tag);
std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
private:
@@ -54,7 +54,7 @@ namespace transport
void HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred);
template<typename Filter>
SSUSession * GetRandomSession (Filter filter);
std::shared_ptr<SSUSession> GetRandomSession (Filter filter);
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
void ScheduleIntroducersUpdateTimer ();
@@ -73,7 +73,7 @@ namespace transport
std::list<boost::asio::ip::udp::endpoint> m_Introducers; // introducers we are connected to
i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V4> m_ReceiveBuffer;
i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V6> m_ReceiveBufferV6;
std::map<boost::asio::ip::udp::endpoint, SSUSession *> m_Sessions;
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions;
std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer
public:

View File

@@ -401,8 +401,9 @@ namespace transport
{
m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
m_ResendTimer.async_wait (boost::bind (&SSUData::HandleResendTimer,
this, boost::asio::placeholders::error));
auto s = m_Session.shared_from_this();
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
{ s->m_Data.HandleResendTimer (ecode); });
}
void SSUData::HandleResendTimer (const boost::system::error_code& ecode)

View File

@@ -21,8 +21,6 @@ namespace transport
m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0)
{
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
if (!router) // incoming session
ScheduleConnectTimer ();
}
SSUSession::~SSUSession ()
@@ -111,7 +109,7 @@ namespace transport
else
{
LogPrint (eLogError, "MAC verification failed ", len, " bytes from ", senderEndpoint);
m_Server.DeleteSession (this);
m_Server.DeleteSession (shared_from_this ());
return;
}
}
@@ -146,13 +144,13 @@ namespace transport
case PAYLOAD_TYPE_SESSION_DESTROYED:
{
LogPrint (eLogDebug, "SSU session destroy received");
m_Server.DeleteSession (this); // delete this
m_Server.DeleteSession (shared_from_this ());
break;
}
case PAYLOAD_TYPE_RELAY_RESPONSE:
ProcessRelayResponse (buf, len);
if (m_State != eSessionStateEstablished)
m_Server.DeleteSession (this);
m_Server.DeleteSession (shared_from_this ());
break;
case PAYLOAD_TYPE_RELAY_REQUEST:
LogPrint (eLogDebug, "SSU relay request received");
@@ -461,7 +459,7 @@ namespace transport
buf += 32; // introkey
uint32_t nonce = be32toh (*(uint32_t *)buf);
SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
SendRelayIntro (session, from);
SendRelayIntro (session.get (), from);
}
}
@@ -701,12 +699,20 @@ namespace transport
}
}
void SSUSession::WaitForConnect ()
{
if (!m_RemoteRouter) // incoming session
ScheduleConnectTimer ();
else
LogPrint (eLogError, "SSU wait for connect for outgoing session");
}
void SSUSession::ScheduleConnectTimer ()
{
m_Timer.cancel ();
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error));
m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
shared_from_this (), std::placeholders::_1));
}
void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode)
@@ -725,8 +731,8 @@ namespace transport
{
// set connect timer
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error));
m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
shared_from_this (), std::placeholders::_1));
}
SendRelayRequest (iTag, iKey);
}
@@ -736,8 +742,8 @@ namespace transport
m_State = eSessionStateIntroduced;
// set connect timer
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error));
m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
shared_from_this (), std::placeholders::_1));
}
void SSUSession::Close ()
@@ -776,7 +782,7 @@ namespace transport
if (m_State != eSessionStateFailed)
{
m_State = eSessionStateFailed;
m_Server.DeleteSession (this); // delete this
m_Server.DeleteSession (shared_from_this ());
}
}
@@ -784,8 +790,8 @@ namespace transport
{
m_Timer.cancel ();
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleTerminationTimer,
this, boost::asio::placeholders::error));
m_Timer.async_wait (std::bind (&SSUSession::HandleTerminationTimer,
shared_from_this (), std::placeholders::_1));
}
void SSUSession::HandleTerminationTimer (const boost::system::error_code& ecode)
@@ -815,7 +821,7 @@ namespace transport
void SSUSession::SendI2NPMessage (I2NPMessage * msg)
{
m_Server.GetService ().post (boost::bind (&SSUSession::PostI2NPMessage, this, msg));
m_Server.GetService ().post (std::bind (&SSUSession::PostI2NPMessage, shared_from_this (), msg));
}
void SSUSession::PostI2NPMessage (I2NPMessage * msg)
@@ -891,7 +897,7 @@ namespace transport
else
{
LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob");
auto session = m_Server.GetRandomEstablishedSession (this); // charlie
auto session = m_Server.GetRandomEstablishedSession (shared_from_this ()); // charlie
if (session)
session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (),
senderEndpoint.port (), introKey, false);

View File

@@ -4,7 +4,7 @@
#include <inttypes.h>
#include <set>
#include <list>
#include <boost/asio.hpp>
#include <memory>
#include "aes.h"
#include "hmac.h"
#include "I2NPProtocol.h"
@@ -50,7 +50,7 @@ namespace transport
};
class SSUServer;
class SSUSession: public TransportSession
class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
{
public:
@@ -60,6 +60,7 @@ namespace transport
~SSUSession ();
void Connect ();
void WaitForConnect ();
void Introduce (uint32_t iTag, const uint8_t * iKey);
void WaitForIntroduction ();
void Close ();

View File

@@ -87,67 +87,150 @@ namespace crypto
publicKey.GetPublicElement ().Encode (signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
}
const size_t ECDSAP256_PUBLIC_KEY_LENGTH = 64;
const size_t ECDSAP256_PUBLIC_KEY_HALF_LENGTH = ECDSAP256_PUBLIC_KEY_LENGTH/2;
const size_t ECDSAP256_SIGNATURE_LENGTH = 64;
const size_t ECDSAP256_PRIVATE_KEY_LENGTH = ECDSAP256_SIGNATURE_LENGTH/2;
class ECDSAP256Verifier: public Verifier
{
template<typename Hash, size_t keyLen>
class ECDSAVerifier: public Verifier
{
public:
ECDSAP256Verifier (const uint8_t * signingKey)
template<typename Curve>
ECDSAVerifier (Curve curve, const uint8_t * signingKey)
{
m_PublicKey.Initialize (CryptoPP::ASN1::secp256r1(),
CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, ECDSAP256_PUBLIC_KEY_HALF_LENGTH),
CryptoPP::Integer (signingKey + ECDSAP256_PUBLIC_KEY_HALF_LENGTH, ECDSAP256_PUBLIC_KEY_HALF_LENGTH)));
}
m_PublicKey.Initialize (curve,
CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, keyLen/2),
CryptoPP::Integer (signingKey + keyLen/2, keyLen/2)));
}
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::Verifier verifier (m_PublicKey);
return verifier.VerifyMessage (buf, len, signature, ECDSAP256_SIGNATURE_LENGTH);
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::Verifier verifier (m_PublicKey);
return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length
}
size_t GetPublicKeyLen () const { return ECDSAP256_PUBLIC_KEY_LENGTH; };
size_t GetSignatureLen () const { return ECDSAP256_SIGNATURE_LENGTH; };
size_t GetPublicKeyLen () const { return keyLen; };
size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
private:
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PublicKey m_PublicKey;
};
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey m_PublicKey;
};
class ECDSAP256Signer: public Signer
template<typename Hash>
class ECDSASigner: public Signer
{
public:
ECDSAP256Signer (const uint8_t * signingPrivateKey)
template<typename Curve>
ECDSASigner (Curve curve, const uint8_t * signingPrivateKey, size_t keyLen)
{
m_PrivateKey.Initialize (CryptoPP::ASN1::secp256r1(), CryptoPP::Integer (signingPrivateKey, ECDSAP256_PRIVATE_KEY_LENGTH));
m_PrivateKey.Initialize (curve, CryptoPP::Integer (signingPrivateKey, keyLen/2)); // private key length
}
void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const
{
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::Signer signer (m_PrivateKey);
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::Signer signer (m_PrivateKey);
signer.SignMessage (rnd, buf, len, signature);
}
private:
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PrivateKey m_PrivateKey;
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey m_PrivateKey;
};
template<typename Hash, typename Curve>
inline void CreateECDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, Curve curve,
size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey privateKey;
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey publicKey;
privateKey.Initialize (rnd, curve);
privateKey.MakePublicKey (publicKey);
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, keyLen/2);
auto q = publicKey.GetPublicElement ();
q.x.Encode (signingPublicKey, keyLen/2);
q.y.Encode (signingPublicKey + keyLen/2, keyLen/2);
}
// ECDSA_SHA256_P256
const size_t ECDSAP256_KEY_LENGTH = 64;
class ECDSAP256Verifier: public ECDSAVerifier<CryptoPP::SHA256, ECDSAP256_KEY_LENGTH>
{
public:
ECDSAP256Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp256r1(), signingKey)
{
}
};
class ECDSAP256Signer: public ECDSASigner<CryptoPP::SHA256>
{
public:
ECDSAP256Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp256r1(), signingPrivateKey, ECDSAP256_KEY_LENGTH)
{
}
};
inline void CreateECDSAP256RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PrivateKey privateKey;
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PublicKey publicKey;
privateKey.Initialize (rnd, CryptoPP::ASN1::secp256r1());
privateKey.MakePublicKey (publicKey);
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, ECDSAP256_PRIVATE_KEY_LENGTH);
auto q = publicKey.GetPublicElement ();
q.x.Encode (signingPublicKey, ECDSAP256_PUBLIC_KEY_HALF_LENGTH);
q.y.Encode (signingPublicKey + ECDSAP256_PUBLIC_KEY_HALF_LENGTH, ECDSAP256_PUBLIC_KEY_HALF_LENGTH);
CreateECDSARandomKeys<CryptoPP::SHA256> (rnd, CryptoPP::ASN1::secp256r1(), ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
// ECDSA_SHA384_P384
const size_t ECDSAP384_KEY_LENGTH = 96;
class ECDSAP384Verifier: public ECDSAVerifier<CryptoPP::SHA384, ECDSAP384_KEY_LENGTH>
{
public:
ECDSAP384Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp384r1(), signingKey)
{
}
};
class ECDSAP384Signer: public ECDSASigner<CryptoPP::SHA384>
{
public:
ECDSAP384Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp384r1(), signingPrivateKey, ECDSAP384_KEY_LENGTH)
{
}
};
inline void CreateECDSAP384RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CreateECDSARandomKeys<CryptoPP::SHA384> (rnd, CryptoPP::ASN1::secp384r1(), ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
// ECDSA_SHA512_P521
const size_t ECDSAP521_KEY_LENGTH = 132;
class ECDSAP521Verifier: public ECDSAVerifier<CryptoPP::SHA512, ECDSAP521_KEY_LENGTH>
{
public:
ECDSAP521Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp521r1(), signingKey)
{
}
};
class ECDSAP521Signer: public ECDSASigner<CryptoPP::SHA512>
{
public:
ECDSAP521Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp521r1(), signingPrivateKey, ECDSAP521_KEY_LENGTH)
{
}
};
inline void CreateECDSAP521RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CreateECDSARandomKeys<CryptoPP::SHA512> (rnd, CryptoPP::ASN1::secp521r1(), ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
}
}

View File

@@ -102,8 +102,8 @@ namespace stream
{
m_IsAckSendScheduled = true;
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ACK_SEND_TIMEOUT));
m_AckSendTimer.async_wait (boost::bind (&Stream::HandleAckSendTimer,
this, boost::asio::placeholders::error));
m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
shared_from_this (), std::placeholders::_1));
}
}
else if (isSyn)
@@ -309,7 +309,7 @@ namespace stream
size += sentLen; // payload
}
p->len = size;
m_Service.post (boost::bind (&Stream::SendPacket, this, p));
m_Service.post (std::bind (&Stream::SendPacket, this, p));
}
return len;
@@ -460,8 +460,8 @@ namespace stream
{
m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_TIMEOUT));
m_ResendTimer.async_wait (boost::bind (&Stream::HandleResendTimer,
this, boost::asio::placeholders::error));
m_ResendTimer.async_wait (std::bind (&Stream::HandleResendTimer,
shared_from_this (), std::placeholders::_1));
}
void Stream::HandleResendTimer (const boost::system::error_code& ecode)
@@ -563,8 +563,6 @@ namespace stream
ResetAcceptor ();
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
for (auto it: m_Streams)
delete it.second;
m_Streams.clear ();
}
}
@@ -597,36 +595,30 @@ namespace stream
}
}
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port)
std::shared_ptr<Stream> StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port)
{
Stream * s = new Stream (*m_Owner.GetService (), *this, remote, port);
auto s = std::make_shared<Stream> (*m_Owner.GetService (), *this, remote, port);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
}
Stream * StreamingDestination::CreateNewIncomingStream ()
std::shared_ptr<Stream> StreamingDestination::CreateNewIncomingStream ()
{
Stream * s = new Stream (*m_Owner.GetService (), *this);
auto s = std::make_shared<Stream> (*m_Owner.GetService (), *this);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
}
void StreamingDestination::DeleteStream (Stream * stream)
void StreamingDestination::DeleteStream (std::shared_ptr<Stream> stream)
{
if (stream)
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
auto it = m_Streams.find (stream->GetRecvStreamID ());
if (it != m_Streams.end ())
{
m_Streams.erase (it);
if (m_Owner.GetService ())
m_Owner.GetService ()->post ([stream](void) { delete stream; });
else
delete stream;
}
}
}
@@ -651,7 +643,7 @@ namespace stream
}
}
void DeleteStream (Stream * stream)
void DeleteStream (std::shared_ptr<Stream> stream)
{
if (stream)
stream->GetLocalDestination ().DeleteStream (stream);

View File

@@ -7,8 +7,8 @@
#include <set>
#include <queue>
#include <functional>
#include <memory>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include "I2PEndian.h"
#include "Identity.h"
#include "LeaseSet.h"
@@ -78,7 +78,7 @@ namespace stream
};
class StreamingDestination;
class Stream
class Stream: public std::enable_shared_from_this<Stream>
{
public:
@@ -153,7 +153,7 @@ namespace stream
{
public:
typedef std::function<void (Stream *)> Acceptor;
typedef std::function<void (std::shared_ptr<Stream>)> Acceptor;
StreamingDestination (i2p::client::ClientDestination& owner): m_Owner (owner) {};
~StreamingDestination () {};
@@ -161,8 +161,8 @@ namespace stream
void Start ();
void Stop ();
Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0);
void DeleteStream (Stream * stream);
std::shared_ptr<Stream> CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0);
void DeleteStream (std::shared_ptr<Stream> stream);
void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; };
void ResetAcceptor () { m_Acceptor = nullptr; };
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
@@ -173,13 +173,13 @@ namespace stream
private:
void HandleNextPacket (Packet * packet);
Stream * CreateNewIncomingStream ();
std::shared_ptr<Stream> CreateNewIncomingStream ();
private:
i2p::client::ClientDestination& m_Owner;
std::mutex m_StreamsMutex;
std::map<uint32_t, Stream *> m_Streams;
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams;
Acceptor m_Acceptor;
public:
@@ -188,7 +188,7 @@ namespace stream
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
};
void DeleteStream (Stream * stream);
void DeleteStream (std::shared_ptr<Stream> stream);
//-------------------------------------------------
@@ -197,15 +197,17 @@ namespace stream
{
if (!m_ReceiveQueue.empty ())
{
m_Service.post ([=](void) { this->HandleReceiveTimer (
auto s = shared_from_this();
m_Service.post ([=](void) { s->HandleReceiveTimer (
boost::asio::error::make_error_code (boost::asio::error::operation_aborted),
buffer, handler); });
}
else
{
m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
auto s = shared_from_this();
m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
{ this->HandleReceiveTimer (ecode, buffer, handler); });
{ s->HandleReceiveTimer (ecode, buffer, handler); });
}
}

View File

@@ -280,7 +280,7 @@ namespace transport
auto r = netdb.FindRouter (ident);
if (r)
{
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (r.get ()) : nullptr;
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (r) : nullptr;
if (ssuSession)
ssuSession->SendI2NPMessage (msg);
else
@@ -337,13 +337,13 @@ namespace transport
delete timer;
}
void Transports::CloseSession (const i2p::data::RouterInfo * router)
void Transports::CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
{
if (!router) return;
m_Service.post (boost::bind (&Transports::PostCloseSession, this, router));
}
void Transports::PostCloseSession (const i2p::data::RouterInfo * router)
void Transports::PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
{
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr;
if (ssuSession) // try SSU first

View File

@@ -70,7 +70,7 @@ namespace transport
NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void CloseSession (const i2p::data::RouterInfo * router);
void CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
private:
@@ -80,7 +80,7 @@ namespace transport
void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer,
const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostCloseSession (const i2p::data::RouterInfo * router);
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
void DetectExternalIP ();

View File

@@ -73,7 +73,7 @@ namespace api
i2p::data::netdb.RequestDestination (remote, true, dest->GetTunnelPool ());
}
i2p::stream::Stream * CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote)
std::shared_ptr<i2p::stream::Stream> CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote)
{
auto leaseSet = i2p::data::netdb.FindLeaseSet (remote);
if (leaseSet)
@@ -95,7 +95,7 @@ namespace api
dest->AcceptStreams (acceptor);
}
void DestroyStream (i2p::stream::Stream * stream)
void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream)
{
if (stream)
{

View File

@@ -1,6 +1,7 @@
#ifndef API_H__
#define API_H__
#include <memory>
#include "Identity.h"
#include "Destination.h"
#include "Streaming.h"
@@ -16,14 +17,14 @@ namespace api
// destinations
i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true);
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient destinations usually not published
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); // transient destinations usually not published
void DestoroyLocalDestination (i2p::client::ClientDestination * dest);
// streams
void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote);
i2p::stream::Stream * CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote);
std::shared_ptr<i2p::stream::Stream> CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote);
void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor);
void DestroyStream (i2p::stream::Stream * stream);
void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream);
}
}

View File

@@ -2,7 +2,7 @@
#define _VERSION_H_
#define CODENAME "Purple"
#define VERSION "0.3.0"
#define VERSION "0.4.0"
#define I2P_VERSION "0.9.16"
#endif