Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/mix ed25519 identity #388

Merged
merged 4 commits into from
Oct 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions mixnode/src/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::commands::override_config;
use crate::config::persistence::pathfinder::MixNodePathfinder;
use clap::{App, Arg, ArgMatches};
use config::NymConfig;
use crypto::asymmetric::encryption;
use crypto::asymmetric::{encryption, identity};
use directory_client::DirectoryClient;
use log::*;
use nymsphinx::params::DEFAULT_NUM_MIX_HOPS;
Expand Down Expand Up @@ -142,8 +142,18 @@ pub fn execute(matches: &ArgMatches) {
config = config.with_layer(layer);
debug!("Choosing layer {}", config.get_layer());

let identity_keys = identity::KeyPair::new();
let sphinx_keys = encryption::KeyPair::new();
let pathfinder = MixNodePathfinder::new_from_config(&config);
pemstore::store_keypair(
&identity_keys,
&pemstore::KeyPairPath::new(
pathfinder.private_identity_key().to_owned(),
pathfinder.public_identity_key().to_owned(),
),
)
.expect("Failed to save identity keys");

pemstore::store_keypair(
&sphinx_keys,
&pemstore::KeyPairPath::new(
Expand All @@ -152,7 +162,8 @@ pub fn execute(matches: &ArgMatches) {
),
)
.expect("Failed to save sphinx keys");
println!("Saved mixnet sphinx keypair");

println!("Saved mixnet identity and sphinx keypairs");
let config_save_location = config.get_config_file_save_location();
config
.save_to_file(None)
Expand Down
18 changes: 16 additions & 2 deletions mixnode/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::config::{persistence::pathfinder::MixNodePathfinder, Config};
use crate::node::MixNode;
use clap::{App, Arg, ArgMatches};
use config::NymConfig;
use crypto::asymmetric::encryption;
use crypto::asymmetric::{encryption, identity};

pub fn command_args<'a, 'b>() -> App<'a, 'b> {
App::new("run")
Expand Down Expand Up @@ -95,6 +95,19 @@ fn special_addresses() -> Vec<&'static str> {
vec!["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]
}

fn load_identity_keys(pathfinder: &MixNodePathfinder) -> identity::KeyPair {
let identity_keypair: identity::KeyPair = pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_identity_key().to_owned(),
pathfinder.public_identity_key().to_owned(),
))
.expect("Failed to read stored identity key files");
println!(
"Public identity key: {}\n",
identity_keypair.public_key().to_base58_string()
);
identity_keypair
}

fn load_sphinx_keys(pathfinder: &MixNodePathfinder) -> encryption::KeyPair {
let sphinx_keypair: encryption::KeyPair = pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_encryption_key().to_owned(),
Expand All @@ -120,6 +133,7 @@ pub fn execute(matches: &ArgMatches) {
config = override_config(config, matches);

let pathfinder = MixNodePathfinder::new_from_config(&config);
let identity_keypair = load_identity_keys(&pathfinder);
let sphinx_keypair = load_sphinx_keys(&pathfinder);

let listening_ip_string = config.get_listening_address().ip().to_string();
Expand All @@ -145,5 +159,5 @@ pub fn execute(matches: &ArgMatches) {
config.get_announce_address()
);

MixNode::new(config, sphinx_keypair).run();
MixNode::new(config, identity_keypair, sphinx_keypair).run();
}
62 changes: 45 additions & 17 deletions mixnode/src/commands/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::config::{Config, MISSING_VALUE};
use crate::config::{missing_string_value, Config};
use clap::{App, Arg, ArgMatches};
use config::NymConfig;
use crypto::asymmetric::identity;
use std::fmt::Display;
use std::path::PathBuf;
use std::process;
use version_checker::{parse_version, Version};

Expand All @@ -41,6 +43,22 @@ fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
}

fn pre_090_upgrade(from: &str, config: Config) -> Config {
// note: current is guaranteed to not have any `build` information suffix (nor pre-release
// information), as this was asserted at the beginning of this command)
//
// upgrade to current (if it's a 0.9.X) or try to upgrade to 0.9.0 as an intermediate
// step in future upgrades (so, for example, we might go 0.8.0 -> 0.9.0 -> 0.10.0)
// this way we don't need to have all the crazy paths on how to upgrade from any version to any
// other version. We just upgrade one minor version at a time.
let current = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
let to_version = if current.major == 0 && current.minor == 9 {
current
} else {
Version::new(0, 9, 0)
};

print_start_upgrade(&from, &to_version);

// this is not extracted to separate function as you only have to manually pass version
// if upgrading from pre090 version
let from = match from.strip_prefix("v") {
Expand All @@ -57,31 +75,41 @@ fn pre_090_upgrade(from: &str, config: Config) -> Config {
if from_version.major == 0 && from_version.minor < 8 {
// technically this could be implemented, but is there any point in that?
eprintln!("upgrading node from before v0.8.0 is not supported. Please run `init` with new binary instead");
print_failed_upgrade(&from_version, &to_version);
process::exit(1)
}

if (from_version.major == 0 && from_version.minor >= 9) || from_version.major >= 1 {
eprintln!("self reported version is higher than 0.9.0. Those releases should have already contained version numbers in config! Make sure you provided correct version");
print_failed_upgrade(&from_version, &to_version);
process::exit(1)
}

// note: current is guaranteed to not have any `build` information suffix (nor pre-release
// information), as this was asserted at the beginning of this command)
//
// upgrade to current (if it's a 0.9.X) or try to upgrade to 0.9.0 as an intermediate
// step in future upgrades (so, for example, we might go 0.8.0 -> 0.9.0 -> 0.10.0)
// this way we don't need to have all the crazy paths on how to upgrade from any version to any
// other version. We just upgrade one minor version at a time.
let current = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
let to_version = if current.major == 0 && current.minor == 9 {
current
} else {
Version::new(0, 9, 0)
};
if config.get_private_identity_key_file() != missing_string_value::<PathBuf>()
|| config.get_public_identity_key_file() != missing_string_value::<PathBuf>()
{
eprintln!("existing config seems to have specified identity keys which were only introduced in 0.9.0! Can't perform upgrade.");
print_failed_upgrade(&from_version, &to_version);
process::exit(1);
}

print_start_upgrade(&from_version, &to_version);
let mut upgraded_config = config.with_custom_version(to_version.to_string().as_ref());

println!("Generating new identity...");
let identity_keys = identity::KeyPair::new();
upgraded_config.set_default_identity_keypair_paths();

if let Err(err) = pemstore::store_keypair(
&identity_keys,
&pemstore::KeyPairPath::new(
upgraded_config.get_private_identity_key_file(),
upgraded_config.get_public_identity_key_file(),
),
) {
eprintln!("Failed to save new identity key files! - {}", err);
process::exit(1);
}

let upgraded_config = config.with_custom_version(to_version.to_string().as_ref());
// TODO: THIS IS INCOMPLETE AS ONCE PRESENCE IS REMOVED IN 0.9.0 IT WILL ALSO NEED
// TO BE PURGED FROM CONFIG

Expand Down Expand Up @@ -135,7 +163,7 @@ pub fn execute(matches: &ArgMatches) {
});

// versions fields were added in 0.9.0
if existing_config.get_version() == MISSING_VALUE {
if existing_config.get_version() == missing_string_value::<String>() {
let self_reported_version = matches.value_of("current version").unwrap_or_else(|| {
eprintln!(
"trying to upgrade from pre v0.9.0 without providing current system version!"
Expand Down
53 changes: 51 additions & 2 deletions mixnode/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ impl NymConfig for Config {
}
}

pub fn missing_string_value() -> String {
MISSING_VALUE.to_string()
pub fn missing_string_value<T: From<String>>() -> T {
MISSING_VALUE.to_string().into()
}

impl Config {
Expand All @@ -98,6 +98,20 @@ impl Config {
// builder methods
pub fn with_id<S: Into<String>>(mut self, id: S) -> Self {
let id = id.into();
if self
.mixnode
.private_identity_key_file
.as_os_str()
.is_empty()
{
self.mixnode.private_identity_key_file =
self::MixNode::default_private_identity_key_file(&id);
}
if self.mixnode.public_identity_key_file.as_os_str().is_empty() {
self.mixnode.public_identity_key_file =
self::MixNode::default_public_identity_key_file(&id);
}

if self.mixnode.private_sphinx_key_file.as_os_str().is_empty() {
self.mixnode.private_sphinx_key_file =
self::MixNode::default_private_sphinx_key_file(&id);
Expand All @@ -106,6 +120,7 @@ impl Config {
self.mixnode.public_sphinx_key_file =
self::MixNode::default_public_sphinx_key_file(&id);
}

self.mixnode.id = id;
self
}
Expand Down Expand Up @@ -218,6 +233,14 @@ impl Config {
self.mixnode.location.clone()
}

pub fn get_private_identity_key_file(&self) -> PathBuf {
self.mixnode.private_identity_key_file.clone()
}

pub fn get_public_identity_key_file(&self) -> PathBuf {
self.mixnode.public_identity_key_file.clone()
}

pub fn get_private_sphinx_key_file(&self) -> PathBuf {
self.mixnode.private_sphinx_key_file.clone()
}
Expand Down Expand Up @@ -277,6 +300,14 @@ impl Config {
pub fn get_version(&self) -> &str {
&self.mixnode.version
}

// upgrade-specific
pub(crate) fn set_default_identity_keypair_paths(&mut self) {
self.mixnode.private_identity_key_file =
self::MixNode::default_private_identity_key_file(&self.mixnode.id);
self.mixnode.public_identity_key_file =
self::MixNode::default_public_identity_key_file(&self.mixnode.id);
}
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
Expand Down Expand Up @@ -309,6 +340,14 @@ pub struct MixNode {
/// `listening_address`.
announce_address: String,

/// Path to file containing private identity key.
#[serde(default = "missing_string_value")]
private_identity_key_file: PathBuf,

/// Path to file containing public identity key.
#[serde(default = "missing_string_value")]
public_identity_key_file: PathBuf,

/// Path to file containing private sphinx key.
private_sphinx_key_file: PathBuf,

Expand All @@ -329,6 +368,14 @@ pub struct MixNode {
}

impl MixNode {
fn default_private_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("private_identity.pem")
}

fn default_public_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("public_identity.pem")
}

fn default_private_sphinx_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("private_sphinx.pem")
}
Expand All @@ -353,6 +400,8 @@ impl Default for MixNode {
.parse()
.unwrap(),
announce_address: format!("127.0.0.1:{}", DEFAULT_LISTENING_PORT),
private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(),
private_sphinx_key_file: Default::default(),
public_sphinx_key_file: Default::default(),
presence_directory_server: DEFAULT_DIRECTORY_SERVER.to_string(),
Expand Down
14 changes: 12 additions & 2 deletions mixnode/src/config/persistence/pathfinder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,30 @@ use std::path::{Path, PathBuf};

#[derive(Debug)]
pub struct MixNodePathfinder {
config_dir: PathBuf,
identity_private_key: PathBuf,
identity_public_key: PathBuf,
private_sphinx_key: PathBuf,
public_sphinx_key: PathBuf,
}

impl MixNodePathfinder {
pub fn new_from_config(config: &Config) -> Self {
MixNodePathfinder {
config_dir: config.get_config_file_save_location(),
identity_private_key: config.get_private_identity_key_file(),
identity_public_key: config.get_public_identity_key_file(),
private_sphinx_key: config.get_private_sphinx_key_file(),
public_sphinx_key: config.get_public_sphinx_key_file(),
}
}

pub fn private_identity_key(&self) -> &Path {
&self.identity_private_key
}

pub fn public_identity_key(&self) -> &Path {
&self.identity_public_key
}

pub fn private_encryption_key(&self) -> &Path {
&self.private_sphinx_key
}
Expand Down
6 changes: 6 additions & 0 deletions mixnode/src/config/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ layer = {{ mixnode.layer }}
# Socket address to which this mixnode will bind to and will be listening for packets.
listening_address = '{{ mixnode.listening_address }}'

# Path to file containing private identity key.
private_identity_key_file = '{{ mixnode.private_identity_key_file }}'

# Path to file containing public identity key.
public_identity_key_file = '{{ mixnode.public_identity_key_file }}'

# Path to file containing private identity key.
private_sphinx_key_file = '{{ mixnode.private_sphinx_key_file }}'

Expand Down
11 changes: 9 additions & 2 deletions mixnode/src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::config::Config;
use crate::node::listener::connection_handler::packet_processing::PacketProcessor;
use crate::node::listener::connection_handler::ConnectionHandler;
use crate::node::listener::Listener;
use crypto::asymmetric::encryption;
use crypto::asymmetric::{encryption, identity};
use directory_client::DirectoryClient;
use log::*;
use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder};
Expand All @@ -30,13 +30,20 @@ mod presence;
// the MixNode will live for whole duration of this program
pub struct MixNode {
config: Config,
#[allow(dead_code)]
identity_keypair: Arc<identity::KeyPair>,
sphinx_keypair: Arc<encryption::KeyPair>,
}

impl MixNode {
pub fn new(config: Config, sphinx_keypair: encryption::KeyPair) -> Self {
pub fn new(
config: Config,
identity_keypair: identity::KeyPair,
sphinx_keypair: encryption::KeyPair,
) -> Self {
MixNode {
config,
identity_keypair: Arc::new(identity_keypair),
sphinx_keypair: Arc::new(sphinx_keypair),
}
}
Expand Down