handle TokenRequest

This commit is contained in:
orignal 2022-03-23 21:48:41 -04:00
parent 861166d8a9
commit fb6ecdde1e
2 changed files with 119 additions and 18 deletions

View File

@ -61,6 +61,27 @@ namespace transport
SendTokenRequest (); SendTokenRequest ();
} }
void SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len)
{
// we are Bob
m_SourceConnID = connID;
Header header;
header.h.connID = connID;
memcpy (header.buf + 8, buf + 8, 8);
header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12));
switch (header.h.type)
{
case eSSU2SessionRequest:
ProcessSessionRequest (header, buf, len);
break;
case eSSU2TokenRequest:
ProcessTokenRequest (header, buf, len);
break;
default:
LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type);
}
}
void SSU2Session::SendSessionRequest (uint64_t token) void SSU2Session::SendSessionRequest (uint64_t token)
{ {
// we are Alice // we are Alice
@ -106,19 +127,9 @@ namespace transport
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
} }
void SSU2Session::ProcessSessionRequest (uint64_t connID, uint8_t * buf, size_t len) void SSU2Session::ProcessSessionRequest (Header& header, uint8_t * buf, size_t len)
{ {
// we are Bob // we are Bob
m_SourceConnID = connID;
Header header;
header.h.connID = connID;
memcpy (header.buf + 8, buf + 8, 8);
header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12));
if (header.h.type != eSSU2SessionRequest)
{
LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type);
return;
}
const uint8_t nonce[12] = {0}; const uint8_t nonce[12] = {0};
uint8_t headerX[48]; uint8_t headerX[48];
i2p::crypto::ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX); i2p::crypto::ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX);
@ -406,6 +417,67 @@ namespace transport
m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint); m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint);
} }
void SSU2Session::ProcessTokenRequest (Header& header, uint8_t * buf, size_t len)
{
// we are Bob
const uint8_t nonce[12] = {0};
uint8_t h[32];
memcpy (h, header.buf, 16);
i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16);
memcpy (&m_DestConnID, h, 8);
// decrypt
uint8_t * payload = buf + 32;
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32,
i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false))
{
LogPrint (eLogWarning, "SSU2: TokenRequest AEAD verification failed ");
return;
}
// payload
HandlePayload (payload, len - 48);
SendRetry ();
}
void SSU2Session::SendRetry ()
{
// we are Bob
Header header;
uint8_t h[32], payload[64];
// fill packet
header.h.connID = m_DestConnID; // dest id
header.h.packetNum = 0;
header.h.type = eSSU2Retry;
header.h.flags[0] = 2; // ver
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
header.h.flags[2] = 0; // flag
memcpy (h, header.buf, 16);
memcpy (h + 16, &m_SourceConnID, 8); // source id
uint64_t token = m_Server.GetIncomingToken (m_RemoteEndpoint);
memcpy (h + 24, &token, 8); // token
// payload
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
size_t payloadSize = 7;
payloadSize += CreateAddressBlock (m_RemoteEndpoint, payload, 57);
uint8_t paddingSize = rand () & 0x0F; // 0 - 15
if (paddingSize)
{
payload[payloadSize] = eSSU2BlkPadding;
htobe16buf (payload + payloadSize + 1, paddingSize);
payloadSize += paddingSize + 3;
}
// encrypt
const uint8_t nonce[12] = {0};
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, i2p::context.GetSSU2IntroKey (), nonce, payload, payloadSize + 16, true);
payloadSize += 16;
header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 12));
i2p::crypto::ChaCha20 (h + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16);
// send
m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint);
}
bool SSU2Session::ProcessRetry (uint8_t * buf, size_t len) bool SSU2Session::ProcessRetry (uint8_t * buf, size_t len)
{ {
// we are Alice // we are Alice
@ -418,11 +490,24 @@ namespace transport
LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type); LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type);
return false; return false;
} }
const uint8_t nonce[12] = {0}; uint8_t nonce[12] = {0};
uint64_t headerX[2]; // sourceConnID, token uint64_t headerX[2]; // sourceConnID, token
i2p::crypto::ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX); i2p::crypto::ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX);
m_Server.UpdateOutgoingToken (m_RemoteEndpoint, headerX[1], i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); m_Server.UpdateOutgoingToken (m_RemoteEndpoint, headerX[1], i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
// TODO: decrypt and handle payload // decrypt and handle payload
uint8_t * payload = buf + 32;
CreateNonce (be32toh (header.h.packetNum), nonce);
uint8_t h[32];
memcpy (h, header.buf, 16);
memcpy (h + 16, &headerX, 16);
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32,
m_Address->i, nonce, payload, len - 48, false))
{
LogPrint (eLogWarning, "SSU2: Retry AEAD verification failed ");
return false;
}
HandlePayload (payload, len - 48);
InitNoiseXKState1 (*m_NoiseState, m_Address->s); // reset Noise TODO: check state InitNoiseXKState1 (*m_NoiseState, m_Address->s); // reset Noise TODO: check state
SendSessionRequest (headerX[1]); SendSessionRequest (headerX[1]);
return true; return true;
@ -733,7 +818,7 @@ namespace transport
// assume new incoming session // assume new incoming session
auto session = std::make_shared<SSU2Session> (*this); auto session = std::make_shared<SSU2Session> (*this);
session->SetRemoteEndpoint (senderEndpoint); session->SetRemoteEndpoint (senderEndpoint);
session->ProcessSessionRequest (connID, buf, len); session->ProcessFirstIncomingMessage (connID, buf, len);
} }
} }
} }
@ -828,12 +913,23 @@ namespace transport
m_OutgoingTokens[ep] = {token, exp}; m_OutgoingTokens[ep] = {token, exp};
} }
uint64_t SSU2Server::FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) uint64_t SSU2Server::FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const
{ {
auto it = m_OutgoingTokens.find (ep); auto it = m_OutgoingTokens.find (ep);
if (it != m_OutgoingTokens.end ()) if (it != m_OutgoingTokens.end ())
return it->second.first; return it->second.first;
return 0; return 0;
} }
uint64_t SSU2Server::GetIncomingToken (const boost::asio::ip::udp::endpoint& ep)
{
auto it = m_IncomingTokens.find (ep);
if (it != m_IncomingTokens.end ())
return it->second.first;
uint64_t token;
RAND_bytes ((uint8_t *)&token, 8);
m_IncomingTokens.emplace (ep, std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT));
return token;
}
} }
} }

View File

@ -96,17 +96,21 @@ namespace transport
void Done () override {}; void Done () override {};
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override {}; void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override {};
void ProcessSessionRequest (uint64_t connID, uint8_t * buf, size_t len); void ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len);
bool ProcessSessionCreated (uint8_t * buf, size_t len); bool ProcessSessionCreated (uint8_t * buf, size_t len);
bool ProcessSessionConfirmed (uint8_t * buf, size_t len); bool ProcessSessionConfirmed (uint8_t * buf, size_t len);
bool ProcessRetry (uint8_t * buf, size_t len); bool ProcessRetry (uint8_t * buf, size_t len);
private: private:
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
void SendSessionRequest (uint64_t token = 0); void SendSessionRequest (uint64_t token = 0);
void SendSessionCreated (const uint8_t * X); void SendSessionCreated (const uint8_t * X);
void SendSessionConfirmed (const uint8_t * Y); void SendSessionConfirmed (const uint8_t * Y);
void SendTokenRequest (); void SendTokenRequest ();
void SendRetry ();
void HandlePayload (const uint8_t * buf, size_t len); void HandlePayload (const uint8_t * buf, size_t len);
bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep);
@ -152,7 +156,8 @@ namespace transport
std::shared_ptr<const i2p::data::RouterInfo::Address> address); std::shared_ptr<const i2p::data::RouterInfo::Address> address);
void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp); void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp);
uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep); uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const;
uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep);
private: private: