#include "cmixclient.hpp" #include "senderreceiver.hpp" #include "cmix.pb.h" #include #include #include #include #include #include using namespace boost::asio::ip; using namespace boost::asio; void CMixClient::key_exchange(size_t node_id) { BOOST_LOG_TRIVIAL(trace) << "Sending KeyExchange for node: " << node_id; unsigned char* buffer; size_t len; api.element_to_array(&buffer, &len, keypair.pub); cmix_proto::KeyExchange ke; ke.set_public_key(buffer, len); api.free_buffer(buffer); data.at(node_id).secret_value = api.get_group_element(true); GroupElement shared_value = api.get_key_exchange_value(data.at(node_id).secret_value); api.element_to_array(&buffer, &len, shared_value); ke.set_value(buffer, len); api.free_buffer(buffer); api.free_group_element(shared_value); network_connections.at(node_id).async_send(ke); network_connections.at(node_id).async_receive([node_id, this](cmix_proto::CMixMessage message) { handle_message(node_id, message); }); } void CMixClient::initialize_connections() { size_t nr_nodes = network_details.node_details.size(); network_connections.reserve(nr_nodes); data.resize(nr_nodes); for(size_t i = 0; i < nr_nodes; ++i) { auto handler = [this, i]() { cmix_proto::ImAClient imaclient; imaclient.set_id("A"); BOOST_LOG_TRIVIAL(trace) << "sending imaclient to node: " << i; network_connections.at(i).async_send(imaclient); network_connections.at(i).async_receive([i, this](cmix_proto::CMixMessage message) { handle_message(i, message); }); }; network_connections.emplace_back(std::unique_ptr>(new ssl::stream(io_service, *ctx))); network_connections.back().async_connect(network_details.node_details[i].host, network_details.node_details[i].port, handler); } } void CMixClient::handle_key_exchange(size_t node_id, cmix_proto::KeyExchange const& ke) { data.at(node_id).shared_value = api.derive_shared_key(keypair, reinterpret_cast(ke.public_key().c_str()), ke.public_key().size(), reinterpret_cast(ke.value().c_str()), ke.value().size(), data.at(node_id).secret_value, false); cmix_proto::Bye bye; network_connections.at(node_id).async_send(bye); } void CMixClient::handle_message(size_t node_id, cmix_proto::CMixMessage message) { switch(message.contents_case()) { case cmix_proto::CMixMessage::ContentsCase::kKeyexchange: { BOOST_LOG_TRIVIAL(trace) << "handling keyexchange for node: " << node_id; handle_key_exchange(node_id, *message.mutable_keyexchange()); return; } case cmix_proto::CMixMessage::ContentsCase::kBye: { BOOST_LOG_TRIVIAL(trace) << "handling bye for node: " << node_id; network_connections.at(node_id).close(); if(std::all_of(network_connections.begin(), network_connections.end(), [](SSLSenderReceiver const& c) { return !c.is_open(); })) { break; } else { return; } } case cmix_proto::CMixMessage::ContentsCase::kNodeready: { BOOST_LOG_TRIVIAL(trace) << "handling NodeReady: " << node_id; key_exchange(node_id); return; } default: { BOOST_LOG_TRIVIAL(error) << "Received unknown message"; } } io_service.stop(); } CMixClient::CMixClient(NetworkDetails details) : io_service() , ctx(std::make_shared(boost::asio::ssl::context::sslv23)) , network_details(details) , network_connections() , api(get_implementation()) , keypair(api.create_key_pair()) { if(!details.certdir.empty()) { ctx->add_verify_path(details.certdir); } initialize_connections(); } CMixClient::~CMixClient() { api.free_key_pair(&keypair); for(auto&& d : data) { api.free_shared_key(&d.shared_value); api.free_group_element(d.secret_value); } api.deinitialize(); } void CMixClient::run() { io_service.run(); }