Skip to content

Commit

Permalink
Sign telemetry messages (#2618)
Browse files Browse the repository at this point in the history
* Sign telemetry messages

* Stein review comment about reusing ed25519 wrappers

* Remove unused header

* Add IGNORE_GTEST_INCL define to node.cpp
  • Loading branch information
wezrule committed Mar 16, 2020
1 parent 15eebb1 commit 35cca9a
Show file tree
Hide file tree
Showing 15 changed files with 291 additions and 182 deletions.
58 changes: 29 additions & 29 deletions nano/core_test/node_telemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ using namespace std::chrono_literals;
namespace
{
void wait_peer_connections (nano::system & system_a);
void compare_default_test_result_data (nano::telemetry_data const & telemetry_data_a, nano::node const & node_server_a);
}

TEST (node_telemetry, consolidate_data)
Expand Down Expand Up @@ -152,7 +151,7 @@ TEST (node_telemetry, serialize_deserialize_json_optional)
data.timestamp = std::chrono::system_clock::time_point (100ms);

nano::jsonconfig config;
data.serialize_json (config);
data.serialize_json (config, false);

uint8_t val;
ASSERT_FALSE (config.get ("minor_version", val).get_error ());
Expand All @@ -168,7 +167,7 @@ TEST (node_telemetry, serialize_deserialize_json_optional)
ASSERT_EQ (timestamp, 100);

nano::telemetry_data data1;
data1.deserialize_json (config);
data1.deserialize_json (config, false);
ASSERT_EQ (*data1.minor_version, 1);
ASSERT_EQ (*data1.patch_version, 4);
ASSERT_EQ (*data1.pre_release_version, 6);
Expand All @@ -177,15 +176,15 @@ TEST (node_telemetry, serialize_deserialize_json_optional)

nano::telemetry_data no_optional_data;
nano::jsonconfig config1;
no_optional_data.serialize_json (config1);
no_optional_data.serialize_json (config1, false);
ASSERT_FALSE (config1.get_optional<uint8_t> ("minor_version").is_initialized ());
ASSERT_FALSE (config1.get_optional<uint8_t> ("patch_version").is_initialized ());
ASSERT_FALSE (config1.get_optional<uint8_t> ("pre_release_version").is_initialized ());
ASSERT_FALSE (config1.get_optional<uint8_t> ("maker").is_initialized ());
ASSERT_FALSE (config1.get_optional<uint64_t> ("timestamp").is_initialized ());

nano::telemetry_data no_optional_data1;
no_optional_data1.deserialize_json (config1);
no_optional_data1.deserialize_json (config1, false);
ASSERT_FALSE (no_optional_data1.minor_version.is_initialized ());
ASSERT_FALSE (no_optional_data1.patch_version.is_initialized ());
ASSERT_FALSE (no_optional_data1.pre_release_version.is_initialized ());
Expand Down Expand Up @@ -258,6 +257,26 @@ TEST (node_telemetry, consolidate_data_remove_outliers)
ASSERT_EQ (data, consolidated_telemetry_data);
}

TEST (node_telemetry, signatures)
{
nano::keypair node_id;
nano::telemetry_data data;
data.node_id = node_id.pub;
data.major_version = 20;
data.minor_version = 1;
data.patch_version = 5;
data.pre_release_version = 2;
data.maker = 1;
data.timestamp = std::chrono::system_clock::time_point (100ms);
data.sign (node_id);
ASSERT_FALSE (data.validate_signature (nano::telemetry_data::size));
auto signature = data.signature;
// Check that the signature is different if changing a piece of data
data.maker = 2;
data.sign (node_id);
ASSERT_NE (data.signature, signature);
}

TEST (node_telemetry, no_peers)
{
nano::system system (1);
Expand Down Expand Up @@ -296,7 +315,7 @@ TEST (node_telemetry, basic)
}

// Check the metrics are correct
compare_default_test_result_data (telemetry_data, *node_server);
nano::compare_default_telemetry_response_data (telemetry_data, node_server->network_params, node_server->config.bandwidth_limit, node_server->node_id);

// Call again straight away. It should use the cache
{
Expand Down Expand Up @@ -454,7 +473,7 @@ TEST (node_telemetry, over_udp)
auto channel = node_client->network.find_channel (node_server->network.endpoint ());
node_client->telemetry->get_metrics_single_peer_async (channel, [&done, &node_server](nano::telemetry_data_response const & response_a) {
ASSERT_FALSE (response_a.error);
compare_default_test_result_data (response_a.telemetry_data, *node_server);
nano::compare_default_telemetry_response_data (response_a.telemetry_data, node_server->network_params, node_server->config.bandwidth_limit, node_server->node_id);
done = true;
});

Expand Down Expand Up @@ -527,7 +546,7 @@ TEST (node_telemetry, blocking_request)
// Now try single request metric
auto telemetry_data_response = node_client->telemetry->get_metrics_single_peer (node_client->network.find_channel (node_server->network.endpoint ()));
ASSERT_FALSE (telemetry_data_response.error);
compare_default_test_result_data (telemetry_data_response.telemetry_data, *node_server);
nano::compare_default_telemetry_response_data (telemetry_data_response.telemetry_data, node_server->network_params, node_server->config.bandwidth_limit, node_server->node_id);

done = true;
promise.get_future ().wait ();
Expand Down Expand Up @@ -754,9 +773,9 @@ TEST (node_telemetry, disable_metrics)
// It should still be able to receive metrics though
done = false;
auto channel1 = node_server->network.find_channel (node_client->network.endpoint ());
node_server->telemetry->get_metrics_single_peer_async (channel1, [&done, node_server](nano::telemetry_data_response const & response_a) {
node_server->telemetry->get_metrics_single_peer_async (channel1, [&done, node_client](nano::telemetry_data_response const & response_a) {
ASSERT_FALSE (response_a.error);
compare_default_test_result_data (response_a.telemetry_data, *node_server);
nano::compare_default_telemetry_response_data (response_a.telemetry_data, node_client->network_params, node_client->config.bandwidth_limit, node_client->node_id);
done = true;
});

Expand Down Expand Up @@ -796,23 +815,4 @@ void wait_peer_connections (nano::system & system_a)
wait_peer_count (true);
wait_peer_count (false);
}

void compare_default_test_result_data (nano::telemetry_data const & telemetry_data_a, nano::node const & node_server_a)
{
ASSERT_EQ (telemetry_data_a.block_count, 1);
ASSERT_EQ (telemetry_data_a.cemented_count, 1);
ASSERT_EQ (telemetry_data_a.bandwidth_cap, node_server_a.config.bandwidth_limit);
ASSERT_EQ (telemetry_data_a.peer_count, 1);
ASSERT_EQ (telemetry_data_a.protocol_version, node_server_a.network_params.protocol.telemetry_protocol_version_min);
ASSERT_EQ (telemetry_data_a.unchecked_count, 0);
ASSERT_EQ (telemetry_data_a.account_count, 1);
ASSERT_LT (telemetry_data_a.uptime, 100);
ASSERT_EQ (telemetry_data_a.genesis_block, node_server_a.network_params.ledger.genesis_hash);
ASSERT_EQ (telemetry_data_a.major_version, nano::get_major_node_version ());
ASSERT_EQ (*telemetry_data_a.minor_version, nano::get_minor_node_version ());
ASSERT_EQ (*telemetry_data_a.patch_version, nano::get_patch_node_version ());
ASSERT_EQ (*telemetry_data_a.pre_release_version, nano::get_pre_release_node_version ());
ASSERT_EQ (*telemetry_data_a.maker, 0);
ASSERT_GT (*telemetry_data_a.timestamp, std::chrono::system_clock::now () - 100s);
}
}
41 changes: 41 additions & 0 deletions nano/core_test/testutil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
#include <nano/lib/locks.hpp>
#include <nano/lib/timer.hpp>

// This test header is unfortunately included in many different files.
// Requires guarding in some cases.
#ifndef IGNORE_GTEST_INCL
#include <nano/node/common.hpp>

#include <gtest/gtest.h>
#endif

#include <boost/iostreams/concepts.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/utility/setup/console.hpp>
Expand Down Expand Up @@ -229,4 +237,37 @@ inline uint16_t get_available_port ()

return available_port;
}

#ifndef IGNORE_GTEST_INCL
inline void compare_default_telemetry_response_data_excluding_signature (nano::telemetry_data const & telemetry_data_a, nano::network_params const & network_params_a, uint64_t bandwidth_limit_a)
{
ASSERT_EQ (telemetry_data_a.block_count, 1);
ASSERT_EQ (telemetry_data_a.cemented_count, 1);
ASSERT_EQ (telemetry_data_a.bandwidth_cap, bandwidth_limit_a);
ASSERT_EQ (telemetry_data_a.peer_count, 1);
ASSERT_EQ (telemetry_data_a.protocol_version, network_params_a.protocol.telemetry_protocol_version_min);
ASSERT_EQ (telemetry_data_a.unchecked_count, 0);
ASSERT_EQ (telemetry_data_a.account_count, 1);
ASSERT_LT (telemetry_data_a.uptime, 100);
ASSERT_EQ (telemetry_data_a.genesis_block, network_params_a.ledger.genesis_hash);
ASSERT_EQ (telemetry_data_a.major_version, nano::get_major_node_version ());
ASSERT_EQ (*telemetry_data_a.minor_version, nano::get_minor_node_version ());
ASSERT_EQ (*telemetry_data_a.patch_version, nano::get_patch_node_version ());
ASSERT_EQ (*telemetry_data_a.pre_release_version, nano::get_pre_release_node_version ());
ASSERT_EQ (*telemetry_data_a.maker, 0);
ASSERT_GT (*telemetry_data_a.timestamp, std::chrono::system_clock::now () - std::chrono::seconds (100));
}

inline void compare_default_telemetry_response_data (nano::telemetry_data const & telemetry_data_a, nano::network_params const & network_params_a, uint64_t bandwidth_limit_a, nano::keypair const & node_id_a)
{
ASSERT_FALSE (telemetry_data_a.validate_signature (nano::telemetry_data::size));
nano::telemetry_data telemetry_data_l = telemetry_data_a;
telemetry_data_l.signature.clear ();
telemetry_data_l.sign (node_id_a);
// Signature should be different because uptime/timestamp will have changed.
ASSERT_NE (telemetry_data_a.signature, telemetry_data_l.signature);
compare_default_telemetry_response_data_excluding_signature (telemetry_data_a, network_params_a, bandwidth_limit_a);
ASSERT_EQ (telemetry_data_a.node_id, node_id_a.pub);
}
#endif
}
27 changes: 18 additions & 9 deletions nano/lib/numbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,6 @@ nano::private_key const & nano::raw_key::as_private_key () const
return reinterpret_cast<nano::private_key const &> (data);
}

nano::signature nano::sign_message (nano::raw_key const & private_key, nano::public_key const & public_key, nano::uint256_union const & message)
{
nano::signature result;
ed25519_sign (message.bytes.data (), sizeof (message.bytes), private_key.data.bytes.data (), public_key.bytes.data (), result.bytes.data ());
return result;
}

nano::private_key nano::deterministic_key (nano::raw_key const & seed_a, uint32_t index_a)
{
nano::private_key prv_key;
Expand All @@ -422,12 +415,28 @@ nano::public_key nano::pub_key (nano::private_key const & privatekey_a)
return result;
}

bool nano::validate_message (nano::public_key const & public_key, nano::uint256_union const & message, nano::signature const & signature)
nano::signature nano::sign_message (nano::raw_key const & private_key, nano::public_key const & public_key, uint8_t const * data, size_t size)
{
auto result (0 != ed25519_sign_open (message.bytes.data (), sizeof (message.bytes), public_key.bytes.data (), signature.bytes.data ()));
nano::signature result;
ed25519_sign (data, size, private_key.data.bytes.data (), public_key.bytes.data (), result.bytes.data ());
return result;
}

nano::signature nano::sign_message (nano::raw_key const & private_key, nano::public_key const & public_key, nano::uint256_union const & message)
{
return nano::sign_message (private_key, public_key, message.bytes.data (), sizeof (message.bytes));
}

bool nano::validate_message (nano::public_key const & public_key, uint8_t const * data, size_t size, nano::signature const & signature)
{
return 0 != ed25519_sign_open (data, size, public_key.bytes.data (), signature.bytes.data ());
}

bool nano::validate_message (nano::public_key const & public_key, nano::uint256_union const & message, nano::signature const & signature)
{
return validate_message (public_key, message.bytes.data (), sizeof (message.bytes), signature);
}

bool nano::validate_message_batch (const unsigned char ** m, size_t * mlen, const unsigned char ** pk, const unsigned char ** RS, size_t num, int * valid)
{
for (size_t i{ 0 }; i < num; ++i)
Expand Down
4 changes: 3 additions & 1 deletion nano/lib/numbers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,10 @@ class qualified_root : public uint512_union
};

nano::signature sign_message (nano::raw_key const &, nano::public_key const &, nano::uint256_union const &);
nano::signature sign_message (nano::raw_key const &, nano::public_key const &, uint8_t const *, size_t);
bool validate_message (nano::public_key const &, nano::uint256_union const &, nano::signature const &);
bool validate_message_batch (const unsigned char **, size_t *, const unsigned char **, const unsigned char **, size_t, int *);
bool validate_message (nano::public_key const &, uint8_t const *, size_t, nano::signature const &);
bool validate_message_batch (unsigned const char **, size_t *, unsigned const char **, unsigned const char **, size_t, int *);
nano::private_key deterministic_key (nano::raw_key const &, uint32_t);
nano::public_key pub_key (nano::private_key const &);

Expand Down
1 change: 1 addition & 0 deletions nano/load_test/entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <nano/boost/beast/core/flat_buffer.hpp>
#include <nano/boost/beast/http.hpp>
#include <nano/boost/process/child.hpp>
#define IGNORE_GTEST_INCL
#include <nano/core_test/testutil.hpp>
#include <nano/lib/threading.hpp>
#include <nano/lib/tomlconfig.hpp>
Expand Down
Loading

0 comments on commit 35cca9a

Please sign in to comment.