Skip to content

Commit 665c102

Browse files
author
Igor Egorov
authored
Fix Plaintext security protocol (#54)
* Refactor and improve plaintext marshallers * Fix and refactor plaintext security protocol Signed-off-by: Igor Egorov <[email protected]>
1 parent cdc092f commit 665c102

File tree

9 files changed

+157
-105
lines changed

9 files changed

+157
-105
lines changed

include/libp2p/security/plaintext/exchange_message_marshaller.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
namespace libp2p::security::plaintext {
1818

19+
namespace protobuf {
20+
class Exchange;
21+
}
22+
1923
/**
2024
* Performs serializing of a Plaintext exchange message to Protobuf format and
2125
* deserializes it back
@@ -24,6 +28,22 @@ namespace libp2p::security::plaintext {
2428
public:
2529
virtual ~ExchangeMessageMarshaller() = default;
2630

31+
/**
32+
* Converts handy Exchange message to its protobuf counterpart
33+
* @param msg handy Exchange message
34+
* @return protobuf Exchange message
35+
*/
36+
virtual outcome::result<protobuf::Exchange> handyToProto(
37+
const ExchangeMessage &msg) const = 0;
38+
39+
/**
40+
* Converts protobuf Exchange message to its handy counterpart
41+
* @param proto_msg protobuf Exchange message
42+
* @return handy Exchange message
43+
*/
44+
virtual outcome::result<std::pair<ExchangeMessage, crypto::ProtobufKey>>
45+
protoToHandy(const protobuf::Exchange &proto_msg) const = 0;
46+
2747
/**
2848
* @param msg exchange message to be marshalled to Protobuf
2949
* @returns a byte array containing a Protobuf representation of an exchange

include/libp2p/security/plaintext/exchange_message_marshaller_impl.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,26 @@ namespace libp2p::security::plaintext {
2626
enum class Error {
2727
PUBLIC_KEY_SERIALIZING_ERROR = 1,
2828
MESSAGE_SERIALIZING_ERROR,
29-
PUBLIC_KEY_DESERIALIZING_ERROR
29+
PUBLIC_KEY_DESERIALIZING_ERROR,
30+
MESSAGE_DESERIALIZING_ERROR,
3031
};
3132

3233
explicit ExchangeMessageMarshallerImpl(
3334
std::shared_ptr<crypto::marshaller::KeyMarshaller> marshaller);
3435

36+
outcome::result<protobuf::Exchange> handyToProto(
37+
const ExchangeMessage &msg) const override;
38+
39+
outcome::result<std::pair<ExchangeMessage, crypto::ProtobufKey>>
40+
protoToHandy(const protobuf::Exchange &proto_msg) const override;
41+
3542
outcome::result<std::vector<uint8_t>> marshal(
3643
const ExchangeMessage &msg) const override;
3744

3845
outcome::result<std::pair<ExchangeMessage, crypto::ProtobufKey>> unmarshal(
3946
gsl::span<const uint8_t> msg_bytes) const override;
4047

4148
private:
42-
outcome::result<std::unique_ptr<crypto::protobuf::PublicKey>>
43-
allocatePubKey(const crypto::PublicKey &pubkey) const;
44-
4549
std::shared_ptr<crypto::marshaller::KeyMarshaller> marshaller_;
4650
};
4751

include/libp2p/security/plaintext/plaintext.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
#include <libp2p/security/plaintext/exchange_message_marshaller.hpp>
1313
#include <libp2p/security/security_adaptor.hpp>
1414

15+
namespace libp2p::basic {
16+
class ProtobufMessageReadWriter;
17+
}
18+
1519
namespace libp2p::security {
1620
/**
1721
* Implementation of security adaptor, which creates plaintext connection.
@@ -51,11 +55,14 @@ namespace libp2p::security {
5155
private:
5256
using MaybePeerId = boost::optional<peer::PeerId>;
5357

54-
void sendExchangeMsg(const std::shared_ptr<connection::RawConnection> &conn,
55-
SecConnCallbackFunc cb) const;
58+
void sendExchangeMsg(
59+
const std::shared_ptr<connection::RawConnection> &conn,
60+
const std::shared_ptr<basic::ProtobufMessageReadWriter> &rw,
61+
SecConnCallbackFunc cb) const;
5662

5763
void receiveExchangeMsg(
5864
const std::shared_ptr<connection::RawConnection> &conn,
65+
const std::shared_ptr<basic::ProtobufMessageReadWriter> &rw,
5966
const MaybePeerId &p, SecConnCallbackFunc cb) const;
6067

6168
// the callback passed to an async read call in receiveExchangeMsg

include/libp2p/security/secio/exchange_message_marshaller.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ namespace libp2p::security::secio {
3434
const ExchangeMessage &msg) const = 0;
3535

3636
/**
37-
* Converts protubuf Exchange message to its handy counterpart
37+
* Converts protobuf Exchange message to its handy counterpart
3838
* @param proto_msg protobuf Exchange message
3939
* @return handy Exchange message
4040
*/

src/security/plaintext/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ libp2p_add_library(p2p_plaintext
1111
)
1212
target_link_libraries(p2p_plaintext
1313
Boost::boost
14-
p2p_security_error
15-
p2p_plaintext_exchange_message_marshaller
1614
p2p_crypto_error
1715
p2p_logger
16+
p2p_plaintext_exchange_message_marshaller
17+
p2p_protobuf_message_read_writer
18+
p2p_security_error
1819
)
1920

2021
libp2p_add_library(p2p_plaintext_exchange_message_marshaller

src/security/plaintext/exchange_message_marshaller_impl.cpp

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ OUTCOME_CPP_DEFINE_CATEGORY(libp2p::security::plaintext,
1717
return "Error while encoding the plaintext exchange message to Protobuf "
1818
"format";
1919
case E::PUBLIC_KEY_DESERIALIZING_ERROR:
20+
return "Error while decoding the public key from Protobuf format";
21+
case E::MESSAGE_DESERIALIZING_ERROR:
2022
return "Error while decoding the plaintext exchange message from "
2123
"Protobuf format";
2224
}
@@ -29,21 +31,51 @@ namespace libp2p::security::plaintext {
2931
std::shared_ptr<crypto::marshaller::KeyMarshaller> marshaller)
3032
: marshaller_{std::move(marshaller)} {};
3133

32-
outcome::result<std::vector<uint8_t>> ExchangeMessageMarshallerImpl::marshal(
34+
outcome::result<protobuf::Exchange>
35+
ExchangeMessageMarshallerImpl::handyToProto(
3336
const ExchangeMessage &msg) const {
3437
plaintext::protobuf::Exchange exchange_msg;
3538

36-
OUTCOME_TRY(pubkey_msg, allocatePubKey(msg.pubkey));
37-
exchange_msg.set_allocated_pubkey(pubkey_msg.get());
39+
OUTCOME_TRY(proto_pubkey_bytes, marshaller_->marshal(msg.pubkey));
40+
if (!exchange_msg.mutable_pubkey()->ParseFromArray(
41+
proto_pubkey_bytes.key.data(), proto_pubkey_bytes.key.size())) {
42+
return Error::PUBLIC_KEY_SERIALIZING_ERROR;
43+
}
3844

3945
auto id = msg.peer_id.toMultihash().toBuffer();
4046
exchange_msg.set_id(id.data(), id.size());
4147

48+
return outcome::success(std::move(exchange_msg));
49+
}
50+
51+
outcome::result<std::pair<ExchangeMessage, crypto::ProtobufKey>>
52+
ExchangeMessageMarshallerImpl::protoToHandy(
53+
const protobuf::Exchange &proto_msg) const {
54+
std::vector<uint8_t> pubkey_message_bytes(
55+
proto_msg.pubkey().ByteSizeLong());
56+
if (!proto_msg.pubkey().SerializeToArray(pubkey_message_bytes.data(),
57+
pubkey_message_bytes.size())) {
58+
return Error::PUBLIC_KEY_SERIALIZING_ERROR;
59+
}
60+
crypto::ProtobufKey proto_pubkey{pubkey_message_bytes};
61+
OUTCOME_TRY(pubkey, marshaller_->unmarshalPublicKey(proto_pubkey));
62+
63+
std::vector<uint8_t> peer_id_bytes(proto_msg.id().begin(),
64+
proto_msg.id().end());
65+
OUTCOME_TRY(peer_id, peer::PeerId::fromBytes(peer_id_bytes));
66+
67+
return {ExchangeMessage{.pubkey = pubkey, .peer_id = peer_id},
68+
proto_pubkey};
69+
}
70+
71+
outcome::result<std::vector<uint8_t>> ExchangeMessageMarshallerImpl::marshal(
72+
const ExchangeMessage &msg) const {
73+
OUTCOME_TRY(exchange_msg, handyToProto(msg));
74+
4275
std::vector<uint8_t> out_msg(exchange_msg.ByteSizeLong());
4376
if (!exchange_msg.SerializeToArray(out_msg.data(), out_msg.size())) {
4477
return Error::MESSAGE_SERIALIZING_ERROR;
4578
}
46-
exchange_msg.release_pubkey();
4779
return out_msg;
4880
}
4981

@@ -55,31 +87,7 @@ namespace libp2p::security::plaintext {
5587
return Error::PUBLIC_KEY_DESERIALIZING_ERROR;
5688
}
5789

58-
std::vector<uint8_t> pubkey_bytes(exchange_msg.pubkey().ByteSizeLong());
59-
exchange_msg.pubkey().SerializeToArray(pubkey_bytes.data(),
60-
pubkey_bytes.size());
61-
OUTCOME_TRY(
62-
pubkey,
63-
marshaller_->unmarshalPublicKey(crypto::ProtobufKey{pubkey_bytes}));
64-
65-
std::vector<uint8_t> peer_id_bytes(exchange_msg.id().begin(),
66-
exchange_msg.id().end());
67-
OUTCOME_TRY(peer_id, peer::PeerId::fromBytes(peer_id_bytes));
68-
return {ExchangeMessage{pubkey, peer_id},
69-
crypto::ProtobufKey{std::move(pubkey_bytes)}};
70-
}
71-
72-
outcome::result<std::unique_ptr<crypto::protobuf::PublicKey>>
73-
ExchangeMessageMarshallerImpl::allocatePubKey(
74-
const crypto::PublicKey &pubkey) const {
75-
OUTCOME_TRY(proto_pub_key_bytes, marshaller_->marshal(pubkey));
76-
std::string str_pubkey(proto_pub_key_bytes.key.begin(),
77-
proto_pub_key_bytes.key.end());
78-
auto pubkey_msg = std::make_unique<crypto::protobuf::PublicKey>();
79-
if (!pubkey_msg->ParseFromString(str_pubkey)) {
80-
return Error::PUBLIC_KEY_SERIALIZING_ERROR;
81-
}
82-
return outcome::success(std::move(pubkey_msg));
90+
return protoToHandy(exchange_msg);
8391
}
8492

8593
} // namespace libp2p::security::plaintext

src/security/plaintext/plaintext.cpp

Lines changed: 51 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,34 @@
77

88
#include <functional>
99

10+
#include <generated/security/plaintext/protobuf/plaintext.pb.h>
11+
#include <libp2p/basic/protobuf_message_read_writer.hpp>
1012
#include <libp2p/peer/peer_id.hpp>
1113
#include <libp2p/security/error.hpp>
1214
#include <libp2p/security/plaintext/plaintext_connection.hpp>
1315

1416
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
15-
# pragma GCC diagnostic ignored "-Wparentheses"
17+
#pragma GCC diagnostic ignored "-Wparentheses"
1618
#endif
1719

18-
#define PLAINTEXT_OUTCOME_TRY(name, res, conn, cb) \
19-
auto(name) = (res); \
20-
if ((name).has_error()) { \
21-
closeConnection(conn, (name).error()); \
22-
cb((name).error()); \
23-
return; \
20+
#define PLAINTEXT_OUTCOME_VOID_TRY(res, conn, cb) \
21+
if ((res).has_error()) { \
22+
closeConnection(conn, (res).error()); \
23+
cb((res).error()); \
24+
return; \
2425
}
2526

27+
#define PLAINTEXT_OUTCOME_TRY(name, res, conn, cb) \
28+
PLAINTEXT_OUTCOME_VOID_TRY((res), (conn), (cb)) \
29+
auto(name) = (res).value();
30+
2631
OUTCOME_CPP_DEFINE_CATEGORY(libp2p::security, Plaintext::Error, e) {
2732
using E = libp2p::security::Plaintext::Error;
2833
switch (e) {
2934
case E::EXCHANGE_SEND_ERROR:
3035
return "Error occured while sending Exchange message to the peer";
3136
case E::EXCHANGE_RECEIVE_ERROR:
32-
return "Error occured while receiving Exchange message to the peer";
37+
return "Error occurred while receiving Exchange message to the peer";
3338
case E::INVALID_PEER_ID:
3439
return "Received peer id doesn't match actual peer id";
3540
case E::EMPTY_PEER_ID:
@@ -61,93 +66,74 @@ namespace libp2p::security {
6166
std::shared_ptr<connection::RawConnection> inbound,
6267
SecConnCallbackFunc cb) {
6368
log_->debug("securing inbound connection");
64-
sendExchangeMsg(inbound, cb);
65-
receiveExchangeMsg(inbound, boost::none, cb);
69+
auto rw = std::make_shared<basic::ProtobufMessageReadWriter>(inbound);
70+
sendExchangeMsg(inbound, rw, cb);
71+
receiveExchangeMsg(inbound, rw, boost::none, cb);
6672
}
6773

6874
void Plaintext::secureOutbound(
6975
std::shared_ptr<connection::RawConnection> outbound,
7076
const peer::PeerId &p, SecConnCallbackFunc cb) {
7177
log_->debug("securing outbound connection");
72-
sendExchangeMsg(outbound, cb);
73-
receiveExchangeMsg(outbound, p, cb);
78+
auto rw = std::make_shared<basic::ProtobufMessageReadWriter>(outbound);
79+
sendExchangeMsg(outbound, rw, cb);
80+
receiveExchangeMsg(outbound, rw, p, cb);
7481
}
7582

7683
void Plaintext::sendExchangeMsg(
7784
const std::shared_ptr<connection::RawConnection> &conn,
85+
const std::shared_ptr<basic::ProtobufMessageReadWriter> &rw,
7886
SecConnCallbackFunc cb) const {
79-
PLAINTEXT_OUTCOME_TRY(out_msg_res,
80-
marshaller_->marshal(plaintext::ExchangeMessage{
81-
.pubkey = idmgr_->getKeyPair().publicKey,
82-
.peer_id = idmgr_->getId()}),
83-
conn, cb)
84-
85-
auto out_msg = out_msg_res.value();
86-
auto len = out_msg.size();
87-
88-
std::vector<uint8_t> len_bytes = {
89-
static_cast<uint8_t>(len >> 24u), static_cast<uint8_t>(len >> 16u),
90-
static_cast<uint8_t>(len >> 8u), static_cast<uint8_t>(len)};
91-
92-
conn->write(len_bytes, 4,
93-
[self{shared_from_this()}, out_msg, conn,
94-
cb{std::move(cb)}](auto &&res) mutable {
95-
if (res.has_error()) {
96-
self->closeConnection(conn, Error::EXCHANGE_SEND_ERROR);
97-
return cb(Error::EXCHANGE_SEND_ERROR);
98-
}
99-
100-
conn->write(
101-
out_msg, out_msg.size(),
102-
[self{std::move(self)}, cb{cb}, conn](auto &&res) {
103-
if (res.has_error()) {
104-
self->closeConnection(conn,
105-
Error::EXCHANGE_SEND_ERROR);
106-
return cb(Error::EXCHANGE_SEND_ERROR);
107-
}
108-
});
109-
});
87+
plaintext::ExchangeMessage exchange_msg{
88+
.pubkey = idmgr_->getKeyPair().publicKey, .peer_id = idmgr_->getId()};
89+
PLAINTEXT_OUTCOME_TRY(proto_exchange_msg,
90+
marshaller_->handyToProto(exchange_msg), conn, cb)
91+
92+
rw->write<plaintext::protobuf::Exchange>(
93+
proto_exchange_msg,
94+
[self{shared_from_this()}, cb{std::move(cb)}, conn](auto &&res) {
95+
if (res.has_error()) {
96+
self->closeConnection(conn, Error::EXCHANGE_SEND_ERROR);
97+
return cb(Error::EXCHANGE_SEND_ERROR);
98+
}
99+
});
110100
}
111101

112102
void Plaintext::receiveExchangeMsg(
113103
const std::shared_ptr<connection::RawConnection> &conn,
104+
const std::shared_ptr<basic::ProtobufMessageReadWriter> &rw,
114105
const MaybePeerId &p, SecConnCallbackFunc cb) const {
115-
constexpr size_t kMaxMsgSize = 4; // we read uint32_t first
116-
auto read_bytes = std::make_shared<std::vector<uint8_t>>(kMaxMsgSize);
117-
118-
conn->read(
119-
*read_bytes, kMaxMsgSize,
106+
auto remote_peer_exchange_bytes = std::make_shared<std::vector<uint8_t>>();
107+
rw->read<plaintext::protobuf::Exchange>(
120108
[self{shared_from_this()}, conn, p, cb{std::move(cb)},
121-
read_bytes](auto &&r) {
122-
auto bytes_size = (static_cast<uint32_t>(read_bytes->at(0)) << 24u)
123-
+ (static_cast<uint32_t>(read_bytes->at(1)) << 16u)
124-
+ (static_cast<uint32_t>(read_bytes->at(2)) << 8u)
125-
+ read_bytes->at(3);
126-
127-
auto received_bytes =
128-
std::make_shared<std::vector<uint8_t>>(bytes_size);
129-
conn->read(*received_bytes, received_bytes->size(),
130-
[self, conn, p, cb, received_bytes](auto &&r) {
131-
self->readCallback(conn, p, cb, received_bytes, r);
132-
});
133-
});
109+
remote_peer_exchange_bytes](auto &&res) {
110+
if (!res) {
111+
return cb(res.error());
112+
}
113+
self->readCallback(conn, p, cb, remote_peer_exchange_bytes,
114+
remote_peer_exchange_bytes->size());
115+
},
116+
remote_peer_exchange_bytes);
134117
}
135118

136119
void Plaintext::readCallback(
137120
const std::shared_ptr<connection::RawConnection> &conn,
138121
const MaybePeerId &p, const SecConnCallbackFunc &cb,
139122
const std::shared_ptr<std::vector<uint8_t>> &read_bytes,
140123
outcome::result<size_t> read_call_res) const {
141-
PLAINTEXT_OUTCOME_TRY(r, read_call_res, conn, cb);
124+
/*
125+
* The method does redundant unmarshalling of message bytes to proto
126+
* exchange message. This could be a subject of further improvement.
127+
*/
128+
PLAINTEXT_OUTCOME_VOID_TRY(read_call_res, conn, cb);
142129
PLAINTEXT_OUTCOME_TRY(in_exchange_msg, marshaller_->unmarshal(*read_bytes),
143130
conn, cb);
144-
auto &msg = in_exchange_msg.value().first;
131+
auto &msg = in_exchange_msg.first;
145132
auto received_pid = msg.peer_id;
146133
auto pkey = msg.pubkey;
147134

148135
// PeerId is derived from the Protobuf-serialized public key, not a raw one
149-
auto derived_pid_res =
150-
peer::PeerId::fromPublicKey(in_exchange_msg.value().second);
136+
auto derived_pid_res = peer::PeerId::fromPublicKey(in_exchange_msg.second);
151137
if (!derived_pid_res) {
152138
log_->error("cannot create a PeerId from the received public key: {}",
153139
derived_pid_res.error().message());

0 commit comments

Comments
 (0)