From ef8ec0f51d579c1f5ff92f20c7d2dfa681b3aec3 Mon Sep 17 00:00:00 2001 From: Ravidu Lashan Date: Mon, 20 Apr 2020 05:55:42 +0530 Subject: [PATCH] Added challenge issue and verification for peer connections (#93) Implemented flatbuffer peer challenge issue and verification messages. Replaced session flags with challenge status enum. --- src/comm/comm_session.hpp | 20 +-- src/conf.cpp | 7 - src/conf.hpp | 1 - src/fbschema/p2pmsg_content.fbs | 11 +- src/fbschema/p2pmsg_content_generated.h | 203 ++++++++++++++++-------- src/fbschema/p2pmsg_helpers.cpp | 73 +++++++-- src/fbschema/p2pmsg_helpers.hpp | 17 +- src/p2p/p2p.cpp | 61 ++++--- src/p2p/p2p.hpp | 9 +- src/p2p/peer_session_handler.cpp | 33 ++-- src/usr/user_session_handler.cpp | 10 +- src/usr/usr.cpp | 3 +- 12 files changed, 303 insertions(+), 145 deletions(-) diff --git a/src/comm/comm_session.hpp b/src/comm/comm_session.hpp index 6c594743..b1382358 100644 --- a/src/comm/comm_session.hpp +++ b/src/comm/comm_session.hpp @@ -7,17 +7,11 @@ namespace comm { - -/** - * Set of flags used to mark status information on the session. - * usr and p2p subsystems make use of this to mark status information of user and peer sessions. - * Set flags are stored in 'flags' bitset of comm_session. - */ -enum SESSION_FLAG + +enum CHALLENGE_STATUS { - USER_CHALLENGE_ISSUED, - USER_AUTHED, - PEERID_RESOLVED + CHALLENGE_ISSUED, + CHALLENGE_VERIFIED }; enum SESSION_STATE @@ -57,11 +51,7 @@ public: std::string issued_challenge; conf::ip_port_pair known_ipport; SESSION_STATE state; - - // The set of SESSION_FLAG enum flags that will be set by user-code of this class. - // We mainly use this to store contexual information about this session based on the use case. - // Setting and reading flags to this is completely managed by user-code. - std::bitset<8> flags; + CHALLENGE_STATUS challenge_status; comm_session( std::string_view ip, const int read_fd, const int write_fd, const SESSION_TYPE session_type, diff --git a/src/conf.cpp b/src/conf.cpp index e496724f..b3a9b66d 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -17,7 +17,6 @@ contract_config cfg; const static char *MODE_OBSERVER = "observer"; const static char *MODE_PROPOSER = "proposer"; -constexpr size_t PEERID_LEN = 16; /** * Loads and initializes the contract config for execution. Must be called once during application startup. @@ -36,12 +35,6 @@ int init() // Append self peer to peer list. const std::string portstr = std::to_string(cfg.peerport); - // We calculate the self peer id to be a random string. - // Use libsodium to generate the random challenge bytes. - unsigned char peerid_bytes[PEERID_LEN]; - randombytes_buf(peerid_bytes, PEERID_LEN); - util::bin2hex(cfg.self_peerid, peerid_bytes, PEERID_LEN); - cfg.peers.emplace(std::make_pair(SELF_HOST, cfg.peerport)); // Append self pubkey to unl list. diff --git a/src/conf.hpp b/src/conf.hpp index f0f51efd..e6fe21b2 100644 --- a/src/conf.hpp +++ b/src/conf.hpp @@ -52,7 +52,6 @@ struct contract_config std::vector runtime_binexec_args; // Contract binary execution args used during runtime. std::vector runtime_appbill_args; // Appbill execution args used during runtime. OPERATING_MODE current_mode; // Current operating mode of the contract (Observer/Proposer) - std::string self_peerid; // Peer session id of this node. (format: selfip:port) // Config elements which are loaded from the config file. diff --git a/src/fbschema/p2pmsg_content.fbs b/src/fbschema/p2pmsg_content.fbs index b2a593e9..ba169f34 100644 --- a/src/fbschema/p2pmsg_content.fbs +++ b/src/fbschema/p2pmsg_content.fbs @@ -2,8 +2,13 @@ include "common_schema.fbs"; namespace fbschema.p2pmsg; -table PeerId_Notify_Message { - peerid:[ubyte]; +table Peer_Challenge_Message { + challenge:[ubyte]; +} + +table Peer_Challenge_Response_Message { + challenge:[ubyte]; + sig:[ubyte]; } table UserSubmittedMessage { @@ -16,7 +21,7 @@ table UserSubmittedMessageGroup { messages:[UserSubmittedMessage]; } -union Message { PeerId_Notify_Message, NonUnl_Proposal_Message, Proposal_Message, Npl_Message, State_Request_Message, State_Response_Message, History_Request_Message, History_Response_Message } //message content type +union Message { Peer_Challenge_Response_Message, Peer_Challenge_Message, NonUnl_Proposal_Message, Proposal_Message, Npl_Message, State_Request_Message, State_Response_Message, History_Request_Message, History_Response_Message } //message content type table Content { message:Message; diff --git a/src/fbschema/p2pmsg_content_generated.h b/src/fbschema/p2pmsg_content_generated.h index dd0c91bd..0df19a81 100644 --- a/src/fbschema/p2pmsg_content_generated.h +++ b/src/fbschema/p2pmsg_content_generated.h @@ -11,8 +11,11 @@ namespace fbschema { namespace p2pmsg { -struct PeerId_Notify_Message; -struct PeerId_Notify_MessageBuilder; +struct Peer_Challenge_Message; +struct Peer_Challenge_MessageBuilder; + +struct Peer_Challenge_Response_Message; +struct Peer_Challenge_Response_MessageBuilder; struct UserSubmittedMessage; struct UserSubmittedMessageBuilder; @@ -64,22 +67,24 @@ struct State_FS_Hash_EntryBuilder; enum Message { Message_NONE = 0, - Message_PeerId_Notify_Message = 1, - Message_NonUnl_Proposal_Message = 2, - Message_Proposal_Message = 3, - Message_Npl_Message = 4, - Message_State_Request_Message = 5, - Message_State_Response_Message = 6, - Message_History_Request_Message = 7, - Message_History_Response_Message = 8, + Message_Peer_Challenge_Response_Message = 1, + Message_Peer_Challenge_Message = 2, + Message_NonUnl_Proposal_Message = 3, + Message_Proposal_Message = 4, + Message_Npl_Message = 5, + Message_State_Request_Message = 6, + Message_State_Response_Message = 7, + Message_History_Request_Message = 8, + Message_History_Response_Message = 9, Message_MIN = Message_NONE, Message_MAX = Message_History_Response_Message }; -inline const Message (&EnumValuesMessage())[9] { +inline const Message (&EnumValuesMessage())[10] { static const Message values[] = { Message_NONE, - Message_PeerId_Notify_Message, + Message_Peer_Challenge_Response_Message, + Message_Peer_Challenge_Message, Message_NonUnl_Proposal_Message, Message_Proposal_Message, Message_Npl_Message, @@ -92,9 +97,10 @@ inline const Message (&EnumValuesMessage())[9] { } inline const char * const *EnumNamesMessage() { - static const char * const names[10] = { + static const char * const names[11] = { "NONE", - "PeerId_Notify_Message", + "Peer_Challenge_Response_Message", + "Peer_Challenge_Message", "NonUnl_Proposal_Message", "Proposal_Message", "Npl_Message", @@ -117,8 +123,12 @@ template struct MessageTraits { static const Message enum_value = Message_NONE; }; -template<> struct MessageTraits { - static const Message enum_value = Message_PeerId_Notify_Message; +template<> struct MessageTraits { + static const Message enum_value = Message_Peer_Challenge_Response_Message; +}; + +template<> struct MessageTraits { + static const Message enum_value = Message_Peer_Challenge_Message; }; template<> struct MessageTraits { @@ -240,59 +250,129 @@ template<> struct State_ResponseTraits { bool VerifyState_Response(flatbuffers::Verifier &verifier, const void *obj, State_Response type); bool VerifyState_ResponseVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); -struct PeerId_Notify_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef PeerId_Notify_MessageBuilder Builder; +struct Peer_Challenge_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Peer_Challenge_MessageBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_PEERID = 4 + VT_CHALLENGE = 4 }; - const flatbuffers::Vector *peerid() const { - return GetPointer *>(VT_PEERID); + const flatbuffers::Vector *challenge() const { + return GetPointer *>(VT_CHALLENGE); } - flatbuffers::Vector *mutable_peerid() { - return GetPointer *>(VT_PEERID); + flatbuffers::Vector *mutable_challenge() { + return GetPointer *>(VT_CHALLENGE); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_PEERID) && - verifier.VerifyVector(peerid()) && + VerifyOffset(verifier, VT_CHALLENGE) && + verifier.VerifyVector(challenge()) && verifier.EndTable(); } }; -struct PeerId_Notify_MessageBuilder { - typedef PeerId_Notify_Message Table; +struct Peer_Challenge_MessageBuilder { + typedef Peer_Challenge_Message Table; flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_peerid(flatbuffers::Offset> peerid) { - fbb_.AddOffset(PeerId_Notify_Message::VT_PEERID, peerid); + void add_challenge(flatbuffers::Offset> challenge) { + fbb_.AddOffset(Peer_Challenge_Message::VT_CHALLENGE, challenge); } - explicit PeerId_Notify_MessageBuilder(flatbuffers::FlatBufferBuilder &_fbb) + explicit Peer_Challenge_MessageBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } - PeerId_Notify_MessageBuilder &operator=(const PeerId_Notify_MessageBuilder &); - flatbuffers::Offset Finish() { + flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); + auto o = flatbuffers::Offset(end); return o; } }; -inline flatbuffers::Offset CreatePeerId_Notify_Message( +inline flatbuffers::Offset CreatePeer_Challenge_Message( flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset> peerid = 0) { - PeerId_Notify_MessageBuilder builder_(_fbb); - builder_.add_peerid(peerid); + flatbuffers::Offset> challenge = 0) { + Peer_Challenge_MessageBuilder builder_(_fbb); + builder_.add_challenge(challenge); return builder_.Finish(); } -inline flatbuffers::Offset CreatePeerId_Notify_MessageDirect( +inline flatbuffers::Offset CreatePeer_Challenge_MessageDirect( flatbuffers::FlatBufferBuilder &_fbb, - const std::vector *peerid = nullptr) { - auto peerid__ = peerid ? _fbb.CreateVector(*peerid) : 0; - return fbschema::p2pmsg::CreatePeerId_Notify_Message( + const std::vector *challenge = nullptr) { + auto challenge__ = challenge ? _fbb.CreateVector(*challenge) : 0; + return fbschema::p2pmsg::CreatePeer_Challenge_Message( _fbb, - peerid__); + challenge__); +} + +struct Peer_Challenge_Response_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Peer_Challenge_Response_MessageBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_CHALLENGE = 4, + VT_SIG = 6 + }; + const flatbuffers::Vector *challenge() const { + return GetPointer *>(VT_CHALLENGE); + } + flatbuffers::Vector *mutable_challenge() { + return GetPointer *>(VT_CHALLENGE); + } + const flatbuffers::Vector *sig() const { + return GetPointer *>(VT_SIG); + } + flatbuffers::Vector *mutable_sig() { + return GetPointer *>(VT_SIG); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_CHALLENGE) && + verifier.VerifyVector(challenge()) && + VerifyOffset(verifier, VT_SIG) && + verifier.VerifyVector(sig()) && + verifier.EndTable(); + } +}; + +struct Peer_Challenge_Response_MessageBuilder { + typedef Peer_Challenge_Response_Message Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_challenge(flatbuffers::Offset> challenge) { + fbb_.AddOffset(Peer_Challenge_Response_Message::VT_CHALLENGE, challenge); + } + void add_sig(flatbuffers::Offset> sig) { + fbb_.AddOffset(Peer_Challenge_Response_Message::VT_SIG, sig); + } + explicit Peer_Challenge_Response_MessageBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePeer_Challenge_Response_Message( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> challenge = 0, + flatbuffers::Offset> sig = 0) { + Peer_Challenge_Response_MessageBuilder builder_(_fbb); + builder_.add_sig(sig); + builder_.add_challenge(challenge); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreatePeer_Challenge_Response_MessageDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *challenge = nullptr, + const std::vector *sig = nullptr) { + auto challenge__ = challenge ? _fbb.CreateVector(*challenge) : 0; + auto sig__ = sig ? _fbb.CreateVector(*sig) : 0; + return fbschema::p2pmsg::CreatePeer_Challenge_Response_Message( + _fbb, + challenge__, + sig__); } struct UserSubmittedMessage FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { @@ -337,7 +417,6 @@ struct UserSubmittedMessageBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - UserSubmittedMessageBuilder &operator=(const UserSubmittedMessageBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -410,7 +489,6 @@ struct UserSubmittedMessageGroupBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - UserSubmittedMessageGroupBuilder &operator=(const UserSubmittedMessageGroupBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -453,8 +531,11 @@ struct Content FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { return GetPointer(VT_MESSAGE); } template const T *message_as() const; - const fbschema::p2pmsg::PeerId_Notify_Message *message_as_PeerId_Notify_Message() const { - return message_type() == fbschema::p2pmsg::Message_PeerId_Notify_Message ? static_cast(message()) : nullptr; + const fbschema::p2pmsg::Peer_Challenge_Response_Message *message_as_Peer_Challenge_Response_Message() const { + return message_type() == fbschema::p2pmsg::Message_Peer_Challenge_Response_Message ? static_cast(message()) : nullptr; + } + const fbschema::p2pmsg::Peer_Challenge_Message *message_as_Peer_Challenge_Message() const { + return message_type() == fbschema::p2pmsg::Message_Peer_Challenge_Message ? static_cast(message()) : nullptr; } const fbschema::p2pmsg::NonUnl_Proposal_Message *message_as_NonUnl_Proposal_Message() const { return message_type() == fbschema::p2pmsg::Message_NonUnl_Proposal_Message ? static_cast(message()) : nullptr; @@ -489,8 +570,12 @@ struct Content FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { } }; -template<> inline const fbschema::p2pmsg::PeerId_Notify_Message *Content::message_as() const { - return message_as_PeerId_Notify_Message(); +template<> inline const fbschema::p2pmsg::Peer_Challenge_Response_Message *Content::message_as() const { + return message_as_Peer_Challenge_Response_Message(); +} + +template<> inline const fbschema::p2pmsg::Peer_Challenge_Message *Content::message_as() const { + return message_as_Peer_Challenge_Message(); } template<> inline const fbschema::p2pmsg::NonUnl_Proposal_Message *Content::message_as() const { @@ -535,7 +620,6 @@ struct ContentBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - ContentBuilder &operator=(const ContentBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -584,7 +668,6 @@ struct NonUnl_Proposal_MessageBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - NonUnl_Proposal_MessageBuilder &operator=(const NonUnl_Proposal_MessageBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -700,7 +783,6 @@ struct Proposal_MessageBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - Proposal_MessageBuilder &operator=(const Proposal_MessageBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -778,7 +860,6 @@ struct Npl_MessageBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - Npl_MessageBuilder &operator=(const Npl_MessageBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -845,7 +926,6 @@ struct History_Request_MessageBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - History_Request_MessageBuilder &operator=(const History_Request_MessageBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -917,7 +997,6 @@ struct History_Response_MessageBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - History_Response_MessageBuilder &operator=(const History_Response_MessageBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -987,7 +1066,6 @@ struct HistoryLedgerPairBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - HistoryLedgerPairBuilder &operator=(const HistoryLedgerPairBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -1059,7 +1137,6 @@ struct HistoryLedgerBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - HistoryLedgerBuilder &operator=(const HistoryLedgerBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -1158,7 +1235,6 @@ struct State_Request_MessageBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - State_Request_MessageBuilder &operator=(const State_Request_MessageBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -1268,7 +1344,6 @@ struct State_Response_MessageBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - State_Response_MessageBuilder &operator=(const State_Response_MessageBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -1344,7 +1419,6 @@ struct Fs_Entry_ResponseBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - Fs_Entry_ResponseBuilder &operator=(const Fs_Entry_ResponseBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -1427,7 +1501,6 @@ struct File_HashMap_ResponseBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - File_HashMap_ResponseBuilder &operator=(const File_HashMap_ResponseBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -1514,7 +1587,6 @@ struct Block_ResponseBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - Block_ResponseBuilder &operator=(const Block_ResponseBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -1601,7 +1673,6 @@ struct State_FS_Hash_EntryBuilder { : fbb_(_fbb) { start_ = fbb_.StartTable(); } - State_FS_Hash_EntryBuilder &operator=(const State_FS_Hash_EntryBuilder &); flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_); auto o = flatbuffers::Offset(end); @@ -1640,8 +1711,12 @@ inline bool VerifyMessage(flatbuffers::Verifier &verifier, const void *obj, Mess case Message_NONE: { return true; } - case Message_PeerId_Notify_Message: { - auto ptr = reinterpret_cast(obj); + case Message_Peer_Challenge_Response_Message: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case Message_Peer_Challenge_Message: { + auto ptr = reinterpret_cast(obj); return verifier.VerifyTable(ptr); } case Message_NonUnl_Proposal_Message: { diff --git a/src/fbschema/p2pmsg_helpers.cpp b/src/fbschema/p2pmsg_helpers.cpp index f6ff7250..358eea04 100644 --- a/src/fbschema/p2pmsg_helpers.cpp +++ b/src/fbschema/p2pmsg_helpers.cpp @@ -12,6 +12,8 @@ namespace fbschema::p2pmsg { +constexpr size_t PEERCHALLENGE_LEN = 16; + /** * This section contains Flatbuffer message reading/writing helpers. * These helpers are mainly used by peer_session_handler. @@ -140,9 +142,30 @@ int validate_and_extract_content(const Content **content_ref, const uint8_t *con //---Message reading helpers---/ -std::string_view get_peerid_from_msg(const PeerId_Notify_Message &msg) +/** + * Returns challenge from the peer challenge message. + * @param The Flatbuffer peer challenge message received from the peer. + * @return binary challenge. + */ +const std::string_view get_peer_challenge_from_msg(const Peer_Challenge_Message &msg) { - return flatbuff_bytes_to_sv(msg.peerid()); + return flatbuff_bytes_to_sv(msg.challenge()); +} + +/** + * Creates a peer challenge response struct from the given peer challenge response message. + * @param The Flatbuffer peer challenge response message received from the peer. + * @return A peer challenge response struct representing the message. + */ +const p2p::peer_challenge_response create_peer_challenge_response_from_msg(const Peer_Challenge_Response_Message &msg, const flatbuffers::Vector *pubkey) +{ + p2p::peer_challenge_response pchalresp; + + pchalresp.challenge = flatbuff_bytes_to_sv(msg.challenge()); + pchalresp.signature = flatbuff_bytes_to_sv(msg.sig()); + pchalresp.pubkey = flatbuff_bytes_to_sv(pubkey); + + return pchalresp; } /** @@ -258,21 +281,53 @@ const p2p::block_response create_block_response_from_msg(const Block_Response &m //---Message creation helpers---// -void create_msg_from_peerid(flatbuffers::FlatBufferBuilder &container_builder, std::string_view peerid) +/** + * Create peer challenge message from the given challenge. + * @param container_builder Flatbuffer builder for the container message. + * @param challenge Challenge message needed to convert to flatbuffer message. + */ +void create_msg_from_peer_challenge(flatbuffers::FlatBufferBuilder &container_builder, std::string &challenge) { flatbuffers::FlatBufferBuilder builder(1024); - const flatbuffers::Offset peerid_msg = - CreatePeerId_Notify_Message( - builder, - sv_to_flatbuff_bytes(builder, peerid)); + // We calculate the peer challenge to be a random string. + // Use libsodium to generate the random challenge bytes. + challenge.resize(PEERCHALLENGE_LEN); + randombytes_buf(challenge.data(), PEERCHALLENGE_LEN); - const flatbuffers::Offset message = CreateContent(builder, Message_PeerId_Notify_Message, peerid_msg.Union()); + const flatbuffers::Offset peer_challenge_msg = + CreatePeer_Challenge_Message( + builder, + sv_to_flatbuff_bytes(builder, challenge)); + + const flatbuffers::Offset message = CreateContent(builder, Message_Peer_Challenge_Message, peer_challenge_msg.Union()); + builder.Finish(message); // Finished building message content to get serialised content. + + // Now that we have built the content message + create_containermsg_from_content(container_builder, builder, nullptr, false); +} + +/** + * Create peer challenge response message from the given challenge. + * @param container_builder Flatbuffer builder for the container message. + * @param challenge Message which need to be signed and placed in the container message. + */ +void create_peer_challenge_response_from_challenge(flatbuffers::FlatBufferBuilder &container_builder, const std::string &challenge) +{ + flatbuffers::FlatBufferBuilder builder(1024); + + const flatbuffers::Offset challenge_resp_msg = + CreatePeer_Challenge_Response_Message( + builder, + sv_to_flatbuff_bytes(builder, challenge), + sv_to_flatbuff_bytes(builder, crypto::sign(challenge, conf::cfg.seckey))); + + const flatbuffers::Offset message = CreateContent(builder, Message_Peer_Challenge_Response_Message, challenge_resp_msg.Union()); builder.Finish(message); // Finished building message content to get serialised content. // Now that we have built the content message, // we need to sign it and place it inside a container message. - create_containermsg_from_content(container_builder, builder, nullptr, false); + create_containermsg_from_content(container_builder, builder, nullptr, true); } void create_msg_from_nonunl_proposal(flatbuffers::FlatBufferBuilder &container_builder, const p2p::nonunl_proposal &nup) diff --git a/src/fbschema/p2pmsg_helpers.hpp b/src/fbschema/p2pmsg_helpers.hpp index b3ea8bc6..45986a18 100644 --- a/src/fbschema/p2pmsg_helpers.hpp +++ b/src/fbschema/p2pmsg_helpers.hpp @@ -23,7 +23,9 @@ int validate_and_extract_content(const Content **content_ref, const uint8_t *con //---Message reading helpers---/ -std::string_view get_peerid_from_msg(const PeerId_Notify_Message &msg); +const std::string_view get_peer_challenge_from_msg(const Peer_Challenge_Message &msg); + +const p2p::peer_challenge_response create_peer_challenge_response_from_msg(const Peer_Challenge_Response_Message &msg, const flatbuffers::Vector *pubkey); const p2p::nonunl_proposal create_nonunl_proposal_from_msg(const NonUnl_Proposal_Message &msg, const uint64_t timestamp); @@ -38,8 +40,9 @@ const p2p::state_request create_state_request_from_msg(const State_Request_Messa const p2p::block_response create_block_response_from_msg(const Block_Response &msg); //---Message creation helpers---// +void create_peer_challenge_response_from_challenge(flatbuffers::FlatBufferBuilder &container_builder, const std::string &challenge); -void create_msg_from_peerid(flatbuffers::FlatBufferBuilder &container_builder, std::string_view peerid); +void create_msg_from_peer_challenge(flatbuffers::FlatBufferBuilder &container_builder, std::string &challenge); void create_msg_from_nonunl_proposal(flatbuffers::FlatBufferBuilder &container_builder, const p2p::nonunl_proposal &nup); @@ -53,8 +56,8 @@ void create_msg_from_npl_output(flatbuffers::FlatBufferBuilder &container_builde void create_msg_from_state_request(flatbuffers::FlatBufferBuilder &container_builder, const p2p::state_request &hr, std::string_view lcl); -void create_msg_from_fsentry_response(flatbuffers::FlatBufferBuilder &container_builder, const std::string_view path, -std::unordered_map &fs_entries, hasher::B2H expected_hash, std::string_view lcl); +void create_msg_from_fsentry_response(flatbuffers::FlatBufferBuilder &container_builder, const std::string_view path, + std::unordered_map &fs_entries, hasher::B2H expected_hash, std::string_view lcl); void create_msg_from_filehashmap_response(flatbuffers::FlatBufferBuilder &container_builder, std::string_view path, std::vector &hashmap, std::size_t file_length, hasher::B2H expected_hash, std::string_view lcl); @@ -79,14 +82,12 @@ flatbuf_historyledgermap_to_historyledgermap(const flatbuffers::Vector>> historyledgermap_to_flatbuf_historyledgermap(flatbuffers::FlatBufferBuilder &builder, const std::map &map); -void -flatbuf_statefshashentry_to_statefshashentry(std::unordered_map &fs_entries, -const flatbuffers::Vector> *fhashes); +void flatbuf_statefshashentry_to_statefshashentry(std::unordered_map &fs_entries, + const flatbuffers::Vector> *fhashes); void statefilehash_to_flatbuf_statefilehash(flatbuffers::FlatBufferBuilder &builder, std::vector> &list, std::string_view full_path, bool is_file, std::string_view hash); - flatbuffers::Offset>> statefshashentry_to_flatbuff_statefshashentry(flatbuffers::FlatBufferBuilder &builder, std::unordered_map &fs_entries); diff --git a/src/p2p/p2p.cpp b/src/p2p/p2p.cpp index 66e8ed1f..dc349a76 100644 --- a/src/p2p/p2p.cpp +++ b/src/p2p/p2p.cpp @@ -43,39 +43,60 @@ int start_peer_connections() return 0; } -int resolve_session_peerid(comm::comm_session &session, const std::string &peerid) +int resolve_peer_challenge(comm::comm_session &session, const peer_challenge_response &challenge_resp) { - const int res = peerid.compare(conf::cfg.self_peerid); - // If peerid is same as our (self) peerid, then this is the loopback connection to ourselves. + // Compare the response challenge string with the original issued challenge. + if (session.issued_challenge != challenge_resp.challenge) + { + LOG_DBG << "Peer challenge response, challenge invalid."; + return -1; + } + + // Verify the challenge signature. + if (crypto::verify( + challenge_resp.challenge, + challenge_resp.signature, + challenge_resp.pubkey) != 0) + { + LOG_DBG << "Peer challenge response signature verification failed."; + return -1; + } + + // Converting the binary pub key into hexa decimal string this will be used as the key in storing peer sessions + std::string pubkeyhex; + util::bin2hex(pubkeyhex, reinterpret_cast(challenge_resp.pubkey.data()), challenge_resp.pubkey.length()); + + const int res = challenge_resp.pubkey.compare(conf::cfg.pubkey); + + // If pub key is same as our (self) pub key, then this is the loopback connection to ourselves. // Hence we must keep the connection but only one of two sessions must be added to peer_connections. - // If peerid is greater than our id (< 0), then we should give priority to any existing inbound connection + // If pub key is greater than our id (< 0), then we should give priority to any existing inbound connection // from the same peer and drop the outbound connection. - // If peerid is lower than our id (> 0), then we should give priority to any existing outbound connection + // If pub key is lower than our id (> 0), then we should give priority to any existing outbound connection // from the same peer and drop the inbound connection. std::lock_guard lock(ctx.peer_connections_mutex); - const auto iter = p2p::ctx.peer_connections.find(peerid); + const auto iter = p2p::ctx.peer_connections.find(pubkeyhex); if (iter == p2p::ctx.peer_connections.end()) { // Add the new connection straight away, if we haven't seen it before. - session.uniqueid = peerid; - session.flags.set(comm::SESSION_FLAG::PEERID_RESOLVED); - p2p::ctx.peer_connections.try_emplace(peerid, &session); + session.uniqueid.swap(pubkeyhex); + session.challenge_status = comm::CHALLENGE_VERIFIED; + p2p::ctx.peer_connections.try_emplace(session.uniqueid, &session); return 0; } else if (res == 0) // New connection is self (There can be two sessions for self (inbound/outbound)) { session.is_self = true; - session.uniqueid = peerid; - session.flags.set(comm::SESSION_FLAG::PEERID_RESOLVED); + session.uniqueid.swap(pubkeyhex); + session.challenge_status = comm::CHALLENGE_VERIFIED; return 0; } - else // New connection is not self but with same peer id. + else // New connection is not self but with same pub key. { comm::comm_session &ex_session = *iter->second; - // We don't allow duplicate connections to the same peer to same direction. if (ex_session.is_inbound != session.is_inbound) { @@ -86,14 +107,14 @@ int resolve_session_peerid(comm::comm_session &session, const std::string &peeri // If we happen to replace a peer session with known IP, transfer required details to the new session. if (session.known_ipport.first.empty()) session.known_ipport.swap(ex_session.known_ipport); - session.uniqueid = peerid; - session.flags.set(comm::SESSION_FLAG::PEERID_RESOLVED); + session.uniqueid.swap(pubkeyhex); + session.challenge_status = comm::CHALLENGE_VERIFIED; ex_session.close(false); - p2p::ctx.peer_connections.erase(iter); // remove existing session. - p2p::ctx.peer_connections.try_emplace(peerid, &session); // add new session. + p2p::ctx.peer_connections.erase(iter); // remove existing session. + p2p::ctx.peer_connections.try_emplace(session.uniqueid, &session); // add new session. - LOG_DBG << "Replacing existing connection [" << peerid << "]"; + LOG_DBG << "Replacing existing connection [" << session.uniqueid << "]"; return 0; } else if (ex_session.known_ipport.first.empty() || !session.known_ipport.first.empty()) @@ -104,7 +125,7 @@ int resolve_session_peerid(comm::comm_session &session, const std::string &peeri } // Reaching this point means we don't need the new session. - LOG_DBG << "Rejecting new peer connection because existing connection takes priority [" << peerid << "]"; + LOG_DBG << "Rejecting new peer connection because existing connection takes priority [" << pubkeyhex << "]"; return -1; } } @@ -147,7 +168,7 @@ void send_message_to_self(const flatbuffers::FlatBufferBuilder &fbuf) std::lock_guard lock(p2p::ctx.peer_connections_mutex); // Find the peer session connected to self. - const auto peer_itr = ctx.peer_connections.find(conf::cfg.self_peerid); + const auto peer_itr = ctx.peer_connections.find(conf::cfg.pubkeyhex); if (peer_itr != ctx.peer_connections.end()) { std::string_view msg = std::string_view( diff --git a/src/p2p/p2p.hpp b/src/p2p/p2p.hpp index da0bf178..f601d415 100644 --- a/src/p2p/p2p.hpp +++ b/src/p2p/p2p.hpp @@ -44,6 +44,13 @@ struct history_ledger std::vector raw_ledger; }; +struct peer_challenge_response +{ + std::string challenge; + std::string signature; + std::string pubkey; +}; + enum LEDGER_RESPONSE_ERROR { NONE = 0, @@ -124,7 +131,7 @@ void deinit(); int start_peer_connections(); -int resolve_session_peerid(comm::comm_session &session, const std::string &peerid); +int resolve_peer_challenge(comm::comm_session &session, const peer_challenge_response &challenge_resp); void broadcast_message(const flatbuffers::FlatBufferBuilder &fbuf, const bool send_to_self); diff --git a/src/p2p/peer_session_handler.cpp b/src/p2p/peer_session_handler.cpp index 2b4419c9..8fe9f4f9 100644 --- a/src/p2p/peer_session_handler.cpp +++ b/src/p2p/peer_session_handler.cpp @@ -38,12 +38,14 @@ int peer_session_handler::on_connect(comm::comm_session &session) const } } - // Send our peer id. + // Send peer challenge. flatbuffers::FlatBufferBuilder fbuf(1024); - p2pmsg::create_msg_from_peerid(fbuf, conf::cfg.self_peerid); + p2pmsg::create_msg_from_peer_challenge(fbuf, session.issued_challenge); std::string_view msg = std::string_view( reinterpret_cast(fbuf.GetBufferPointer()), fbuf.GetSize()); - return session.send(msg); + session.send(msg); + session.challenge_status = comm::CHALLENGE_ISSUED; + return 0; } //peer session on message callback method @@ -74,19 +76,30 @@ int peer_session_handler::on_message(comm::comm_session &session, std::string_vi const p2pmsg::Message content_message_type = content->message_type(); //i.e - proposal, npl, state request, state response, etc - if (content_message_type == p2pmsg::Message_PeerId_Notify_Message) // message is a peer id announcement + if (content_message_type == p2pmsg::Message_Peer_Challenge_Message) // message is a peer challenge announcement { - // Ignore if Peer ID is already resolved. - if (!session.flags[comm::SESSION_FLAG::PEERID_RESOLVED]) + // Sending the challenge response to the respected peer. + const std::string challenge = std::string(p2pmsg::get_peer_challenge_from_msg(*content->message_as_Peer_Challenge_Message())); + flatbuffers::FlatBufferBuilder fbuf(1024); + p2pmsg::create_peer_challenge_response_from_challenge(fbuf, challenge); + std::string_view msg = std::string_view( + reinterpret_cast(fbuf.GetBufferPointer()), fbuf.GetSize()); + return session.send(msg); + } + + if (content_message_type == p2pmsg::Message_Peer_Challenge_Response_Message) // message is a peer challenge response + { + // Ignore if challenge is already resolved. + if (session.challenge_status == comm::CHALLENGE_ISSUED) { - const std::string peerid = std::string(p2pmsg::get_peerid_from_msg(*content->message_as_PeerId_Notify_Message())); - return p2p::resolve_session_peerid(session, peerid); + const p2p::peer_challenge_response challenge_resp = p2pmsg::create_peer_challenge_response_from_msg(*content->message_as_Peer_Challenge_Response_Message(), container->pubkey()); + return p2p::resolve_peer_challenge(session, challenge_resp); } } - if (!session.flags[comm::SESSION_FLAG::PEERID_RESOLVED]) + if (session.challenge_status != comm::CHALLENGE_VERIFIED) { - LOG_DBG << "Cannot accept messages. Peer id unresolved. " << session.uniqueid; + LOG_DBG << "Cannot accept messages. Peer challenge unresolved. " << session.uniqueid; return 0; } diff --git a/src/usr/user_session_handler.cpp b/src/usr/user_session_handler.cpp index 2227324b..b6e0d6f0 100644 --- a/src/usr/user_session_handler.cpp +++ b/src/usr/user_session_handler.cpp @@ -29,8 +29,8 @@ int user_session_handler::on_connect(comm::comm_session &session) const jusrmsg::create_user_challenge(msgstr, session.issued_challenge); session.send(msgstr); - // Set the challenge-issued flag to help later checks in on_message. - session.flags.set(comm::SESSION_FLAG::USER_CHALLENGE_ISSUED); + // Set the challenge-issued value to true. + session.challenge_status = comm::CHALLENGE_ISSUED; return 0; } @@ -42,13 +42,13 @@ int user_session_handler::on_message(comm::comm_session &session, std::string_vi { // First check whether this session is pending challenge. // Meaning we have previously issued a challenge to the client. - if (session.flags[comm::SESSION_FLAG::USER_CHALLENGE_ISSUED]) + if (session.challenge_status == comm::CHALLENGE_ISSUED) { if (verify_challenge(message, session) == 0) return 0; } // Check whether this session belongs to an authenticated (challenge-verified) user. - else if (session.flags[comm::SESSION_FLAG::USER_AUTHED]) + else if (session.challenge_status == comm::CHALLENGE_VERIFIED) { // Check whether this user is among authenticated users // and perform authenticated msg processing. @@ -86,7 +86,7 @@ int user_session_handler::on_message(comm::comm_session &session, std::string_vi void user_session_handler::on_close(const comm::comm_session &session) const { // Session belongs to an authed user. - if (session.flags[comm::SESSION_FLAG::USER_AUTHED]) + if (session.challenge_status == comm::CHALLENGE_VERIFIED) remove_user(session.uniqueid); } diff --git a/src/usr/usr.cpp b/src/usr/usr.cpp index 72c7c7d6..7d5bdf47 100644 --- a/src/usr/usr.cpp +++ b/src/usr/usr.cpp @@ -86,8 +86,7 @@ int verify_challenge(std::string_view message, comm::comm_session &session) // All good. Unique public key. // Promote the connection from pending-challenges to authenticated users. - session.flags.reset(comm::SESSION_FLAG::USER_CHALLENGE_ISSUED); // Clear challenge-issued flag - session.flags.set(comm::SESSION_FLAG::USER_AUTHED); // Set the user-authed flag + session.challenge_status = comm::CHALLENGE_VERIFIED; // Set as challenge verified add_user(session, userpubkey); // Add the user to the global authed user list session.issued_challenge.clear(); // Remove the stored challenge