Browse Source

handle Phase3 in two steps

pull/113/head
orignal 10 years ago
parent
commit
de14f8dcd7
  1. 121
      NTCPSession.cpp
  2. 13
      NTCPSession.h

121
NTCPSession.cpp

@ -44,7 +44,7 @@ namespace transport
uint8_t sharedKey[256]; uint8_t sharedKey[256];
if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey))
{ {
LogPrint ("Couldn't create shared key"); LogPrint (eLogError, "Couldn't create shared key");
Terminate (); Terminate ();
return; return;
}; };
@ -66,7 +66,7 @@ namespace transport
nonZero++; nonZero++;
if (nonZero - sharedKey > 32) 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; return;
} }
} }
@ -89,7 +89,7 @@ namespace transport
} }
m_DelayedMessages.clear (); m_DelayedMessages.clear ();
if (numDelayed > 0) if (numDelayed > 0)
LogPrint ("NTCP session ", numDelayed, " not sent"); LogPrint (eLogWarning, "NTCP session ", numDelayed, " not sent");
// TODO: notify tunnels // TODO: notify tunnels
delete this; delete this;
@ -146,13 +146,13 @@ namespace transport
{ {
if (ecode) 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) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else 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::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase2Received, this, boost::bind(&NTCPSession::HandlePhase2Received, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
@ -163,13 +163,13 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 1 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 1 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 1 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 1 received: ", bytes_transferred);
// verify ident // verify ident
uint8_t digest[32]; uint8_t digest[32];
CryptoPP::SHA256().CalculateDigest(digest, m_Establisher->phase1.pubKey, 256); 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]) if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i])
{ {
LogPrint ("Wrong ident"); LogPrint (eLogError, "Wrong ident");
Terminate (); Terminate ();
return; return;
} }
@ -219,14 +219,14 @@ namespace transport
{ {
if (ecode) 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) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 2 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 2 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase3, sizeof (NTCPPhase3)), boost::asio::transfer_all (), 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::bind(&NTCPSession::HandlePhase3Received, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB)); boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB));
} }
@ -248,7 +248,7 @@ namespace transport
} }
else else
{ {
LogPrint ("Phase 2 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 2 received: ", bytes_transferred);
i2p::crypto::AESKey aesKey; i2p::crypto::AESKey aesKey;
CreateAESKey (m_Establisher->phase2.pubKey, aesKey); CreateAESKey (m_Establisher->phase2.pubKey, aesKey);
@ -265,7 +265,7 @@ namespace transport
CryptoPP::SHA256().CalculateDigest(hxy, xy, 512); CryptoPP::SHA256().CalculateDigest(hxy, xy, 512);
if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32)) if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32))
{ {
LogPrint ("Incorrect hash"); LogPrint (eLogError, "Incorrect hash");
transports.ReuseDHKeysPair (m_DHKeysPair); transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr; m_DHKeysPair = nullptr;
Terminate (); Terminate ();
@ -313,13 +313,13 @@ namespace transport
{ {
if (ecode) 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) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 3 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 3 sent: ", bytes_transferred);
// wait for phase4 // wait for phase4
auto signatureLen = m_RemoteIdentity.GetSignatureLen (); auto signatureLen = m_RemoteIdentity.GetSignatureLen ();
size_t paddingSize = signatureLen & 0x0F; // %16 size_t paddingSize = signatureLen & 0x0F; // %16
@ -334,32 +334,71 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 3 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 3 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 3 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 3 received: ", bytes_transferred);
m_Decryption.Decrypt ((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3); m_Decryption.Decrypt (m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
m_RemoteIdentity = m_Establisher->phase3.ident; uint8_t * buf = m_ReceiveBuffer;
uint32_t tsA = m_Establisher->phase3.timestamp; 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; HandlePhase3 (tsB, paddingLen);
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 void NTCPSession::HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen)
s.Insert (tsB); // tsB {
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase3.signature)) if (ecode)
{ {
LogPrint ("signature verification failed"); LogPrint (eLogError, "Phase 3 extra read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
return; }
} 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;
SendPhase4 (tsA, tsB); 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) void NTCPSession::SendPhase4 (uint32_t tsA, uint32_t tsB)
@ -385,13 +424,13 @@ namespace transport
{ {
if (ecode) 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) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 4 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 4 sent: ", bytes_transferred);
Connected (); Connected ();
m_ReceiveBufferOffset = 0; m_ReceiveBufferOffset = 0;
m_NextMessage = nullptr; m_NextMessage = nullptr;
@ -403,7 +442,7 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 4 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 4 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
// this router doesn't like us // this router doesn't like us
@ -413,7 +452,7 @@ namespace transport
} }
else else
{ {
LogPrint ("Phase 4 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 4 received: ", bytes_transferred);
m_Decryption.Decrypt(m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer); m_Decryption.Decrypt(m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
// verify signature // verify signature
@ -426,7 +465,7 @@ namespace transport
if (!s.Verify (m_RemoteIdentity, m_ReceiveBuffer)) if (!s.Verify (m_RemoteIdentity, m_ReceiveBuffer))
{ {
LogPrint ("signature verification failed"); LogPrint (eLogError, "signature verification failed");
Terminate (); Terminate ();
return; return;
} }
@ -449,7 +488,7 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Read error: ", ecode.message ()); LogPrint (eLogError, "Read error: ", ecode.message ());
//if (ecode != boost::asio::error::operation_aborted) //if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
@ -494,7 +533,7 @@ namespace transport
// new message // new message
if (dataSize > NTCP_MAX_MESSAGE_SIZE) 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); i2p::DeleteI2NPMessage (m_NextMessage);
m_NextMessage = nullptr; m_NextMessage = nullptr;
return false; return false;
@ -537,7 +576,7 @@ namespace transport
// regular I2NP // regular I2NP
if (msg->offset < 2) if (msg->offset < 2)
{ {
LogPrint ("Malformed I2NP message"); LogPrint (eLogError, "Malformed I2NP message");
i2p::DeleteI2NPMessage (msg); i2p::DeleteI2NPMessage (msg);
} }
sendBuffer = msg->GetBuffer () - 2; sendBuffer = msg->GetBuffer () - 2;
@ -571,7 +610,7 @@ namespace transport
i2p::DeleteI2NPMessage (msg); i2p::DeleteI2NPMessage (msg);
if (ecode) 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 // we shouldn't call Terminate () here, because HandleReceive takes care
// TODO: 'delete this' statement in Terminate () must be eliminated later // TODO: 'delete this' statement in Terminate () must be eliminated later
// Terminate (); // Terminate ();

13
NTCPSession.h

@ -35,21 +35,13 @@ namespace transport
uint8_t filler[12]; uint8_t filler[12];
} encrypted; } encrypted;
}; };
struct NTCPPhase3
{
uint16_t size;
i2p::data::Identity ident;
uint32_t timestamp;
uint8_t padding[15];
uint8_t signature[40];
};
#pragma pack() #pragma pack()
const size_t NTCP_MAX_MESSAGE_SIZE = 16384; const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028) const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028)
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes 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 class NTCPSession: public TransportSession
{ {
@ -92,6 +84,8 @@ namespace transport
void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred); 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 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 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); void HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
// common // common
@ -121,7 +115,6 @@ namespace transport
{ {
NTCPPhase1 phase1; NTCPPhase1 phase1;
NTCPPhase2 phase2; NTCPPhase2 phase2;
NTCPPhase3 phase3;
} * m_Establisher; } * m_Establisher;
i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer; i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer;

Loading…
Cancel
Save