Files
nym/mixnode/src/node/mod.rs
T
Jędrzej Stuczyński d9d549fd0f Feature/reply surbs (#299)
* Changed identity keypair to use ed25519

* Encryption key is now x25519 based + compatibiltiy with sphinx

* Pathing and import fixes

* Moved all asymmetric keys to sub-module in crypto

* Extracted aes to separate module

* kdf module in crypto

* Ability to perform diffie hellman on encryption keys

* ecdsa on identity keys

* Extremely rough and incomplete registration handshake

* Authentication primitives

* Creating new random authenticationIV

* Wrapper type for the derived shared key

* Removed AuthToken in favour of using SharedKey for authentication

* Gateway identity keys

* Registration handshake without error mapping

* Gateway address in client config

* Added extra key for gateway presence

* Updated pemstore to work on borrows instead

* Gateway client trying to perform the handshake

* Gateway changes to allow for handshake and shared key

* Debug trait on sharedkey

* native client using updated gateway client

* Slightly updated gateway API

* Minor cleanup

* Fixed pemstore to correctly save multiple keypairs

* Gateway actually deriving shared key during handshake

* Gateway sending correct mid-handshake message

* Missing quotation mark in client config template

* Fixed template for correct shared key serialization

* Fixed gateway authentication

* Fixed tests

* Using correct gateway key when converting to sphinx node

* "get_all_clients" takes them from gateways as opposed to providers now

* cargo fmt

* Renamed pemstore methods

* Unused import

* Encryption of forward requests between client and gateway

* Updated sphinx dependency to use public revision

* Sending 'error' on handshake processing error

* Removed some dead code

* Dead code I forgot to remove before

* Extracted AckAes128Key into a struct

* Slight pemstore revamp allowing for symmetric key store

* ibid.

* PemStorableKey for SharedKey

* Introduced single location responsible for key management for client

* WIP

* Sphinx version update

* Stop using NodeAddressBytes for two distinct and confusing purposes

* Abstracting away SocketAddr from sphinx forwarding

* Passing the bool for reply surbs

* Attack plan for replies + encryption

* Comment + removed variable binding

* ReplySURB usage

* Topology import in nymsphinx

* Sphinx version update

* Changed 'Recipient' to contain client's encryption key

* Message preparation taking shape!

* reply surb also containing the encryption key

* Very initial message receiver

* Sphinx version update

* A possibly working way of receiving surbs

* Fixed incorrect field name in client config template

* camel casing all request arguments

* Renamed and moved `MessageMode` to more appropriate file

* Restored reconstruction tests

* Removed dead code from chunking

* Made rust examples compilable

* reply SURB key storage

* Replies as an InputMessage

* Forgotten commented code

* No retransmission processing for cover or replies

* Received reply processing

* Renamed client pathfinder to something more appropriate

* Made HasherOutputSize public

* Added key store path to config

* Reply surb attaching key digest when used

* Changes due to previous renaming

* Removed comment

* Fixed insert_encryption_key

* Assigning initial value of key store path

* Computing key digest with correct algorithm

* Initial and presumably temporary request serialization

* hacky way of introducing 'FragmentIdentifier' for replies

* Moved responsibility of reply encryption, padding, etc, to message preparer

* Optional recipient in try_get_valid_topology_ref

* Handling new reply surbs with acks and padding

* Updated go and python examples to include replies in text and binary cases

* Updated rust examples + binaryserverresponse

* Helpers in rust examples

* And updated JS example

* Moved shared key generation function to crypto crate

* Cover traffic encryption!

* hmac computation in crypto

* Updated aes imports due to new dependencies

* hkdf made more generic

* crypto cleanup + algorithms in params

* Clippy cleanup pass

* Generating encryption+mac shared keys between client and gateway

* MACs attached to forward requests to gateway

* Gateway messages encrypted and mac'd

* Lowered logging level

* compiler warning cleanup

* Some minor cleanup

* Generic stream cipher

* Generic shared key derivation + algorithm definitions

* Project-wide AES clean-up

* Comment fix

* Removed commented imports

* Updated comments

* Fixed topology test fixture
2020-08-07 18:16:54 +01:00

148 lines
5.3 KiB
Rust

// Copyright 2020 Nym Technologies SA
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::config::Config;
use crate::node::packet_processing::PacketProcessor;
use crypto::asymmetric::encryption;
use directory_client::DirectoryClient;
use futures::channel::mpsc;
use log::*;
use nymsphinx::{addressing::nodes::NymNodeRoutingAddress, SphinxPacket};
use tokio::runtime::Runtime;
mod listener;
mod metrics;
mod packet_forwarding;
pub(crate) mod packet_processing;
mod presence;
// the MixNode will live for whole duration of this program
pub struct MixNode {
runtime: Runtime,
config: Config,
sphinx_keypair: encryption::KeyPair,
}
impl MixNode {
pub fn new(config: Config, sphinx_keypair: encryption::KeyPair) -> Self {
MixNode {
runtime: Runtime::new().unwrap(),
config,
sphinx_keypair,
}
}
fn start_presence_notifier(&self) {
info!("Starting presence notifier...");
let notifier_config = presence::NotifierConfig::new(
self.config.get_location(),
self.config.get_presence_directory_server(),
self.config.get_announce_address(),
self.sphinx_keypair.public_key().to_base58_string(),
self.config.get_layer(),
self.config.get_presence_sending_delay(),
);
presence::Notifier::new(notifier_config).start(self.runtime.handle());
}
fn start_metrics_reporter(&self) -> metrics::MetricsReporter {
info!("Starting metrics reporter...");
metrics::MetricsController::new(
self.config.get_metrics_directory_server(),
self.sphinx_keypair.public_key().to_base58_string(),
self.config.get_metrics_sending_delay(),
self.config.get_metrics_running_stats_logging_delay(),
)
.start(self.runtime.handle())
}
fn start_socket_listener(
&self,
metrics_reporter: metrics::MetricsReporter,
forwarding_channel: mpsc::UnboundedSender<(NymNodeRoutingAddress, SphinxPacket)>,
) {
info!("Starting socket listener...");
// this is the only location where our private key is going to be copied
// it will be held in memory owned by `MixNode` and inside an Arc of `PacketProcessor`
let packet_processor =
PacketProcessor::new(self.sphinx_keypair.private_key().clone(), metrics_reporter);
listener::run_socket_listener(
self.runtime.handle(),
self.config.get_listening_address(),
packet_processor,
forwarding_channel,
);
}
fn start_packet_forwarder(
&mut self,
) -> mpsc::UnboundedSender<(NymNodeRoutingAddress, SphinxPacket)> {
info!("Starting packet forwarder...");
self.runtime
.enter(|| {
packet_forwarding::PacketForwarder::new(
self.config.get_packet_forwarding_initial_backoff(),
self.config.get_packet_forwarding_maximum_backoff(),
self.config.get_initial_connection_timeout(),
)
})
.start(self.runtime.handle())
}
fn check_if_same_ip_node_exists(&mut self) -> Option<String> {
let directory_client_config =
directory_client::Config::new(self.config.get_presence_directory_server());
let directory_client = directory_client::Client::new(directory_client_config);
let topology = self
.runtime
.block_on(directory_client.get_topology())
.ok()?;
let existing_mixes_presence = topology.mix_nodes;
existing_mixes_presence
.iter()
.find(|node| node.host == self.config.get_announce_address())
.map(|node| node.pub_key.clone())
}
pub fn run(&mut self) {
info!("Starting nym mixnode");
if let Some(duplicate_node_key) = self.check_if_same_ip_node_exists() {
error!(
"Our announce-host is identical to an existing node's announce-host! (its key is {:?}",
duplicate_node_key
);
return;
}
let forwarding_channel = self.start_packet_forwarder();
let metrics_reporter = self.start_metrics_reporter();
self.start_socket_listener(metrics_reporter, forwarding_channel);
self.start_presence_notifier();
info!("Finished nym mixnode startup procedure - it should now be able to receive mix traffic!");
if let Err(e) = self.runtime.block_on(tokio::signal::ctrl_c()) {
error!(
"There was an error while capturing SIGINT - {:?}. We will terminate regardless",
e
);
}
println!(
"Received SIGINT - the mixnode will terminate now (threads are not YET nicely stopped)"
);
}
}