Skip to content

Commit de0259c

Browse files
author
Igor Egorov
authored
SECIO (#41)
* Fix public key part in echo server example * Remove unused Plaintext session class * Rename Plaintext header guards * Fix illegal comparison in crypto provider impl * Implement SECIO * Switch Kademlia to boost::optional instead of std * Add -insecure option to echo server * Add MessageReadWriterBigEndian * Add SECIO cases to host_integration_test * Add SECIO marshallers tests Possible Drawbacks Not possible to perform cross-implementation testing by now (go implementation of libp2p got updated much so c++ implementation needs to be changed too). P521 curve-based algorithm could be faulty - needs to be tested when cross-implementation testing gets possible. User's callback could be called twice in case of error inside secureInbound and secureOutbound methods - this could be easily fixed if we count this as an issue. Signed-off-by: Igor Egorov <[email protected]>
1 parent 77ca408 commit de0259c

File tree

90 files changed

+2750
-308
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+2750
-308
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ include/generated/*
3131
peers.list
3232
cmake-build*
3333

34-
cmake-build*
34+
deps
3535
.gtm
3636
/.gtm/
3737

example/01-echo/README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,31 @@
11
# Example Libp2p Echo
2+
23
## General description
34

4-
This example shows you how to create a simple Echo client and server in cpp-libp2p. There are three ways to launch this example: C++ to C++, C++ Client to Go Server and C++ Server to Go Client. The last two examples can be used to test a compatibility between the implementations and should be moved to some separate repository to produce automatic tests.
5+
This example shows you how to create a simple Echo client and server in cpp-libp2p.
6+
There are three ways to launch this example: C++ to C++, C++ Client to Go Server and C++ Server to Go Client.
7+
The last two examples can be used to test a compatibility between the implementations and should be moved to some separate repository to produce automatic tests.
8+
9+
10+
## C++ Server and Client
11+
12+
Currently, `libp2p_echo_server` can operate in two modes - via Plaintext or SECIO security protocols.
13+
By default, it is launched in SECIO secured mode.
14+
To run it with Plaintext exclusive mode just add `-insecure` command-line argument.
15+
16+
```bash
17+
libp2p_echo_server -insecure
18+
```
19+
20+
The client application does **not** have such an option and supports both types of connection at any time.
21+
Which security type is going to be used is defined by the server's working mode and its preferences.
22+
23+
## Golang Implementation Compatibility Note
24+
25+
The `libp2p_client.go` which is an echo server source from `go-libp2p-examples` can be built only when `go.mod` file is present.
26+
The current version of the `go.mod` is outdated, and only Plaintext security could be cross-tested.
27+
To update the `go.mod` file there are changes required in c++ implementation of libp2p.
28+
Those changes are the subject of ongoin work.
529

630
## C++ to C++
731

@@ -23,6 +47,6 @@ This example shows you how to create a simple Echo client and server in cpp-libp
2347

2448
1. Build C++ target `libp2p_echo_server`
2549
2. Build a Go example via `go build libp2p_client.go`
26-
3. Execute `../../cmake-build-debug/example/01-echo/libp2p_echo_server`. It will start a C++ server.
50+
3. Execute `../../cmake-build-debug/example/01-echo/libp2p_echo_server -insecure`. It will start a C++ server.
2751
4. Execute `./libp2p_client -insecure -l 40011 -d /ip4/127.0.0.1/tcp/40010/ipfs/12D3KooWLs7RC93EGXZzn9YdKyZYYx3f9UjTLYNX1reThpCkFb83`
2852
5. Watch how message is exchanged

example/01-echo/go.mod

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module github.com/libp2p/go-libp2p-examples
2+
3+
require (
4+
github.com/gogo/protobuf v1.3.1
5+
github.com/google/uuid v1.1.1
6+
github.com/ipfs/go-datastore v0.3.1
7+
github.com/ipfs/go-log v0.0.1
8+
github.com/libp2p/go-libp2p v0.5.0
9+
github.com/libp2p/go-libp2p-autonat-svc v0.1.0
10+
github.com/libp2p/go-libp2p-circuit v0.1.4
11+
github.com/libp2p/go-libp2p-connmgr v0.2.1
12+
github.com/libp2p/go-libp2p-core v0.3.0
13+
github.com/libp2p/go-libp2p-discovery v0.2.0
14+
github.com/libp2p/go-libp2p-kad-dht v0.4.1
15+
github.com/libp2p/go-libp2p-quic-transport v0.2.2
16+
github.com/libp2p/go-libp2p-routing v0.1.0
17+
github.com/libp2p/go-libp2p-secio v0.2.1
18+
github.com/libp2p/go-libp2p-swarm v0.2.2
19+
github.com/libp2p/go-libp2p-tls v0.1.2
20+
github.com/multiformats/go-multiaddr v0.2.0
21+
github.com/multiformats/go-multiaddr-net v0.1.1
22+
github.com/whyrusleeping/go-logging v0.0.1
23+
)
24+
25+
go 1.13

example/01-echo/libp2p_echo_client.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ int main(int argc, char *argv[]) {
6363

6464
auto peer_info = libp2p::peer::PeerInfo{server_peer_id, {server_ma}};
6565

66-
// create Host object an open a stream through it
66+
// create Host object and open a stream through it
6767
host->newStream(
6868
peer_info, echo.getProtocolId(), [&echo](auto &&stream_res) {
6969
if (!stream_res) {

example/01-echo/libp2p_echo_server.cpp

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,88 @@
66
#include <chrono>
77
#include <iostream>
88
#include <memory>
9+
#include <string>
910

11+
#include <gsl/multi_span>
1012
#include <libp2p/common/literals.hpp>
1113
#include <libp2p/host/basic_host.hpp>
1214
#include <libp2p/injector/host_injector.hpp>
1315
#include <libp2p/protocol/echo.hpp>
16+
#include <libp2p/security/plaintext.hpp>
17+
#include <libp2p/security/secio.hpp>
1418

15-
int main() {
19+
bool isInsecure(int argc, char **argv) {
20+
if (2 == argc) {
21+
const std::string insecure{"-insecure"};
22+
auto args = gsl::multi_span<char *>(argv, argc);
23+
if (insecure == args[1]) {
24+
return true;
25+
}
26+
}
27+
return false;
28+
}
29+
30+
struct ServerContext {
31+
std::shared_ptr<libp2p::Host> host;
32+
std::shared_ptr<boost::asio::io_context> io_context;
33+
};
34+
35+
ServerContext initSecureServer(const libp2p::crypto::KeyPair &keypair) {
36+
auto injector = libp2p::injector::makeHostInjector(
37+
libp2p::injector::useKeyPair(keypair),
38+
libp2p::injector::useSecurityAdaptors<libp2p::security::Secio>());
39+
auto host = injector.create<std::shared_ptr<libp2p::Host>>();
40+
auto context = injector.create<std::shared_ptr<boost::asio::io_context>>();
41+
return {.host = host, .io_context = context};
42+
}
43+
44+
ServerContext initInsecureServer(const libp2p::crypto::KeyPair &keypair) {
45+
auto injector = libp2p::injector::makeHostInjector(
46+
libp2p::injector::useKeyPair(keypair),
47+
libp2p::injector::useSecurityAdaptors<libp2p::security::Plaintext>());
48+
auto host = injector.create<std::shared_ptr<libp2p::Host>>();
49+
auto context = injector.create<std::shared_ptr<boost::asio::io_context>>();
50+
return {.host = host, .io_context = context};
51+
}
52+
53+
int main(int argc, char **argv) {
1654
using libp2p::crypto::Key;
1755
using libp2p::crypto::KeyPair;
1856
using libp2p::crypto::PrivateKey;
1957
using libp2p::crypto::PublicKey;
2058
using libp2p::common::operator""_unhex;
2159

22-
// this keypair generates a PeerId
23-
// "12D3KooWLs7RC93EGXZzn9YdKyZYYx3f9UjTLYNX1reThpCkFb83"
60+
// resulting PeerId should be
61+
// 12D3KooWEgUjBV5FJAuBSoNMRYFRHjV7PjZwRQ7b43EKX9g7D6xV
2462
KeyPair keypair{PublicKey{{Key::Type::Ed25519,
25-
"a4249ea6d62bdd8bccf62257ac4899ff284796"
26-
"3228b388fda288db5d64e517e0"_unhex}},
63+
"48453469c62f4885373099421a7365520b5ffb"
64+
"0d93726c124166be4b81d852e6"_unhex}},
2765
PrivateKey{{Key::Type::Ed25519,
2866
"4a9361c525840f7086b893d584ebbe475b4ec"
2967
"7069951d2e897e8bceb0a3f35ce"_unhex}}};
3068

69+
bool insecure_mode{isInsecure(argc, argv)};
70+
if (insecure_mode) {
71+
std::cout << "Starting in insecure mode" << std::endl;
72+
} else {
73+
std::cout << "Starting in secure mode" << std::endl;
74+
}
75+
3176
// create a default Host via an injector, overriding a random-generated
3277
// keypair with ours
33-
auto injector =
34-
libp2p::injector::makeHostInjector(libp2p::injector::useKeyPair(keypair));
35-
auto host = injector.create<std::shared_ptr<libp2p::Host>>();
78+
ServerContext server =
79+
insecure_mode ? initInsecureServer(keypair) : initSecureServer(keypair);
3680

3781
// set a handler for Echo protocol
3882
libp2p::protocol::Echo echo{libp2p::protocol::EchoConfig{1}};
39-
host->setProtocolHandler(
83+
server.host->setProtocolHandler(
4084
echo.getProtocolId(),
4185
[&echo](std::shared_ptr<libp2p::connection::Stream> received_stream) {
4286
echo.handle(std::move(received_stream));
4387
});
4488

4589
// launch a Listener part of the Host
46-
auto context = injector.create<std::shared_ptr<boost::asio::io_context>>();
47-
context->post([host{std::move(host)}] {
90+
server.io_context->post([host{std::move(server.host)}] {
4891
auto ma =
4992
libp2p::multi::Multiaddress::create("/ip4/127.0.0.1/tcp/40010").value();
5093
auto listen_res = host->listen(ma);
@@ -56,9 +99,18 @@ int main() {
5699

57100
host->start();
58101
std::cout << "Server started\nListening on: " << ma.getStringAddress()
59-
<< "\nPeer id: " << host->getPeerInfo().id.toBase58() << "\n";
102+
<< "\nPeer id: " << host->getPeerInfo().id.toBase58()
103+
<< std::endl;
104+
std::cout << "Connection string: " << ma.getStringAddress() << "/ipfs/"
105+
<< host->getPeerInfo().id.toBase58() << std::endl;
60106
});
61107

62108
// run the IO context
63-
context->run();
109+
try {
110+
server.io_context->run();
111+
} catch (const boost::system::error_code &ec) {
112+
std::cout << "Server cannot run: " << ec.message() << std::endl;
113+
} catch (...) {
114+
std::cout << "Unknown error happened" << std::endl;
115+
}
64116
}

example/02-kad/factory.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <libp2p/crypto/crypto_provider/crypto_provider_impl.hpp>
1111
#include <libp2p/crypto/ecdsa_provider/ecdsa_provider_impl.hpp>
1212
#include <libp2p/crypto/ed25519_provider/ed25519_provider_impl.hpp>
13+
#include <libp2p/crypto/hmac_provider/hmac_provider_impl.hpp>
1314
#include <libp2p/crypto/key_marshaller/key_marshaller_impl.hpp>
1415
#include <libp2p/crypto/key_validator/key_validator_impl.hpp>
1516
#include <libp2p/crypto/random_generator/boost_generator.hpp>
@@ -84,10 +85,12 @@ namespace libp2p::protocol::kademlia::example {
8485
std::make_shared<crypto::ecdsa::EcdsaProviderImpl>();
8586
auto secp256k1_provider =
8687
std::make_shared<crypto::secp256k1::Secp256k1ProviderImpl>();
88+
auto hmac_provider = std::make_shared<crypto::hmac::HmacProviderImpl>();
89+
8790
std::shared_ptr<crypto::CryptoProvider> crypto_provider =
8891
std::make_shared<crypto::CryptoProviderImpl>(
8992
csprng, ed25519_provider, rsa_provider, ecdsa_provider,
90-
secp256k1_provider);
93+
secp256k1_provider, hmac_provider);
9194
auto validator = std::make_shared<crypto::validator::KeyValidatorImpl>(
9295
crypto_provider);
9396

include/libp2p/basic/message_read_writer.hpp

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,31 @@
1515

1616
namespace libp2p::basic {
1717
/**
18-
* Allows to read and write messages, which are prepended with a varint -
19-
* standard, for example, for Protobuf messages in Libp2p
18+
* An interface for message read writers for messages prepended with its
19+
* length that is somehow encoded.
2020
*/
21-
class MessageReadWriter
22-
: public std::enable_shared_from_this<MessageReadWriter> {
21+
class MessageReadWriter {
2322
public:
2423
using ReadCallback = outcome::result<std::shared_ptr<std::vector<uint8_t>>>;
2524
using ReadCallbackFunc = std::function<void(ReadCallback)>;
2625

27-
/**
28-
* Create an instance of MessageReadWriter
29-
* @param conn, from which to read/write messages
30-
*/
31-
explicit MessageReadWriter(std::shared_ptr<ReadWriter> conn);
26+
virtual ~MessageReadWriter() = default;
3227

3328
/**
34-
* Read a message, which is prepended with a varint
35-
* @param cb, which is called, when the message is read or error happens
29+
* Reads a message that is prepended with its length
30+
* @param cb is called when read gets done. Read bytes or an error will be
31+
* passed as an argument in case of success
3632
*/
37-
void read(ReadCallbackFunc cb);
33+
virtual void read(ReadCallbackFunc cb) = 0;
3834

3935
/**
40-
* Write a message; varint with its length will be prepended to it
41-
* @param buffer - the message to be written
42-
* @param cb, which is called, when the message is read or error happens
36+
* Writes a message and preprends its length
37+
* @param buffer - bytes to be written
38+
* @param cb is called when the message is written or an error happened.
39+
* Quantity of bytes written is passed as an argument in case of success
4340
*/
44-
void write(gsl::span<const uint8_t> buffer, Writer::WriteCallbackFunc cb);
45-
46-
private:
47-
std::shared_ptr<ReadWriter> conn_;
41+
virtual void write(gsl::span<const uint8_t> buffer,
42+
Writer::WriteCallbackFunc cb) = 0;
4843
};
4944
} // namespace libp2p::basic
5045

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef LIBP2P_MESSAGE_READ_WRITER_BIGENDIAN_HPP
7+
#define LIBP2P_MESSAGE_READ_WRITER_BIGENDIAN_HPP
8+
9+
#include <memory>
10+
#include <vector>
11+
12+
#include <gsl/span>
13+
#include <libp2p/basic/message_read_writer.hpp>
14+
#include <libp2p/basic/readwriter.hpp>
15+
#include <libp2p/outcome/outcome.hpp>
16+
17+
namespace libp2p::basic {
18+
/**
19+
* Allows to read and write messages, which are prepended with a message
20+
* length as 32-byte number passed in network byte order (Big Endian). For
21+
* example, this is used in SECIO security protocol.
22+
*/
23+
class MessageReadWriterBigEndian
24+
: public MessageReadWriter,
25+
public std::enable_shared_from_this<MessageReadWriterBigEndian> {
26+
public:
27+
static constexpr auto kLenMarkerSize = sizeof(uint32_t);
28+
29+
/**
30+
* Create an instance of MessageReadWriter
31+
* @param conn, from which to read/write messages
32+
*/
33+
explicit MessageReadWriterBigEndian(std::shared_ptr<ReadWriter> conn);
34+
35+
/**
36+
* Read a message, which is prepended with a 32-byte Big Endian lenght
37+
* @param cb, which is called, when the message is read or error happens
38+
*/
39+
void read(ReadCallbackFunc cb) override;
40+
41+
/**
42+
* Write a message; 32-byte Big Endian number with its length will be
43+
* prepended to it
44+
* @param buffer - the message to be written
45+
* @param cb, which is called, when the message is read or error happens
46+
*/
47+
void write(gsl::span<const uint8_t> buffer,
48+
Writer::WriteCallbackFunc cb) override;
49+
50+
private:
51+
std::shared_ptr<ReadWriter> conn_;
52+
};
53+
} // namespace libp2p::basic
54+
55+
#endif // LIBP2P_MESSAGE_READ_WRITER_BIGENDIAN_HPP
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef LIBP2P_MESSAGE_READ_WRITER_UVARINT_HPP
7+
#define LIBP2P_MESSAGE_READ_WRITER_UVARINT_HPP
8+
9+
#include <memory>
10+
#include <vector>
11+
12+
#include <gsl/span>
13+
#include <libp2p/basic/message_read_writer.hpp>
14+
#include <libp2p/basic/readwriter.hpp>
15+
#include <libp2p/outcome/outcome.hpp>
16+
17+
namespace libp2p::basic {
18+
/**
19+
* Allows to read and write messages, which are prepended with a uvarint -
20+
* standard, for example, for Protobuf messages in Libp2p
21+
*/
22+
class MessageReadWriterUvarint
23+
: public MessageReadWriter,
24+
public std::enable_shared_from_this<MessageReadWriterUvarint> {
25+
public:
26+
/**
27+
* Create an instance of MessageReadWriter
28+
* @param conn, from which to read/write messages
29+
*/
30+
explicit MessageReadWriterUvarint(std::shared_ptr<ReadWriter> conn);
31+
32+
/**
33+
* Read a message, which is prepended with a uvarint
34+
* @param cb, which is called, when the message is read or error happens
35+
*/
36+
void read(ReadCallbackFunc cb) override;
37+
38+
/**
39+
* Write a message; uvarint with its length will be prepended to it
40+
* @param buffer - the message to be written
41+
* @param cb, which is called, when the message is read or error happens
42+
*/
43+
void write(gsl::span<const uint8_t> buffer,
44+
Writer::WriteCallbackFunc cb) override;
45+
46+
private:
47+
std::shared_ptr<ReadWriter> conn_;
48+
};
49+
} // namespace libp2p::basic
50+
51+
#endif // LIBP2P_MESSAGE_READ_WRITER_UVARINT_HPP

0 commit comments

Comments
 (0)