Skip to content

Commit

Permalink
Use JSON config file instead of arg command line
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Prévost committed Feb 6, 2024
1 parent c9712a3 commit 8822629
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 112 deletions.
76 changes: 76 additions & 0 deletions config_kme1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"this_kme": {
"id": 1,
"sqlite_db_path": ":memory:",
"https_listen_address": "127.0.0.1:3000",
"https_ca_client_cert_path": "certs/CA-zone1.crt",
"https_server_cert_path": "certs/kme1.crt",
"https_server_key_path": "certs/kme1.key"
},
"other_kmes": [
{
"id": 1,
"key_directory_to_watch": "raw_keys",
"ip_address": "127.0.0.1"
},
{
"id": 2,
"key_directory_to_watch": "raw_keys",
"ip_address": "127.0.0.1"
}
],
"saes": [
{
"id": 1,
"kme_id": 1,
"https_client_certificate_serial": [
112,
244,
79,
86,
12,
63,
39,
212,
178,
17,
164,
120,
19,
175,
208,
60,
3,
129,
59,
142
]
},
{
"id": 2,
"kme_id": 1,
"https_client_certificate_serial": [
112,
244,
79,
86,
12,
63,
39,
212,
178,
17,
164,
120,
19,
175,
208,
60,
3,
129,
59,
146
]
}
]
}
73 changes: 73 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//! Configuration module, contains structs used to deserialize JSON configuration and other material extraction functions
use std::io;
use serde::{Deserialize, Serialize};
use crate::{io_err, KmeId, SaeClientCertSerial, SaeId};

/// Whole KME config, to be extracted from JSON
#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
/// Config for this specific KME, including its ID and paths to certificates
#[serde(rename = "this_kme")]
pub this_kme_config: ThisKmeConfig,
/// Configs for other KMEs, including their IDs and paths to directories to watch for new keys
#[serde(rename = "other_kmes")]
pub(crate) other_kme_configs: Vec<OtherKmeConfig>,
/// Configs for SAEs, including their IDs, KMEs they are associated with and optional client certificate serials, if SAEs belong to this KME
#[serde(rename = "saes")]
pub(crate) sae_configs: Vec<SaeConfig>
}

impl Config {
/// Extract configuration from JSON file
pub fn from_json_path(json_config_file_path: &str) -> Result<Self, io::Error> {
let config: Self = match std::fs::read_to_string(json_config_file_path) {
Ok(json) => match serde_json::from_str(&json) {
Ok(config) => config,
Err(_) => return Err(io_err("Error deserializing JSON"))
},
Err(_) => return Err(io_err("Error reading JSON file"))
};
Ok(config)
}
}

/// Config for this specific KME, including its ID and paths to certificates
#[derive(Serialize, Deserialize, Debug)]
pub struct ThisKmeConfig {
/// ID of this KME, in the QKD network
pub(crate) id: KmeId,
/// Path to SQLite database file, used to store keys, certificates and other data
/// You can use `:memory:` to use in-memory database
pub(crate) sqlite_db_path: String,
/// Address to listen for HTTPS connections
pub https_listen_address: String,
/// Server certificate authority certificate path, used to authenticate client SAEs
pub https_ca_client_cert_path: String,
/// Server HTTPS certificate path
pub https_server_cert_path: String,
/// Server HTTPS private key path
pub https_server_key_path: String
}

/// Configs for other KMEs, including their IDs and paths to directories to watch for new keys
#[derive(Serialize, Deserialize, Debug)]
pub struct OtherKmeConfig {
/// ID of the other KME, in the QKD network
pub(crate) id: KmeId,
/// Path to directory to read and watch for new keys, files must have [crate::QKD_KEY_FILE_EXTENSION](crate::QKD_KEY_FILE_EXTENSION) extension
pub(crate) key_directory_to_watch: String,
/// IP address of the other KME, used to send keys to it using "classical channel"
pub(crate) ip_address: String,
}

/// Config for specific SAE: its ID, KME ID and optional client certificate serial
#[derive(Serialize, Deserialize, Debug)]
pub struct SaeConfig {
/// ID of the SAE in QKD network
pub(crate) id: SaeId,
/// ID of the KME this SAE belongs to
pub(crate) kme_id: KmeId,
/// Client certificate serial number, used to authenticate SAEs to this KME if it belongs to, None otherwise
pub(crate) https_client_certificate_serial: Option<SaeClientCertSerial>
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::io;
pub mod server;
pub mod routes;
pub mod qkd_manager;
pub mod config;


/// Cast a string to an io::Error
Expand Down Expand Up @@ -53,6 +54,9 @@ pub const CLIENT_CERT_SERIAL_SIZE_BYTES: usize = 20;
/// Location of the SQLite database file used by the KME to store keys, use ":memory:" for in-memory database
pub const MEMORY_SQLITE_DB_PATH: &'static str = ":memory:";

/// File extension for newly exchanged QKD keys
pub const QKD_KEY_FILE_EXTENSION: &'static str = "cor";

/// The type of SAE ID
pub type SaeId = i64;

Expand Down
131 changes: 19 additions & 112 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,130 +1,37 @@
use std::io::{BufReader, Read};
use std::path::Path;
use std::sync::Arc;
use log::error;
use clap::Parser;
use notify::{EventKind, RecursiveMode, Watcher};
use notify::event::{AccessKind, AccessMode};
use qkd_kme_server::qkd_manager::{PreInitQkdKeyWrapper, QkdManager};
use qkd_kme_server::qkd_manager::QkdManager;
use qkd_kme_server::routes::QKDKMERoutesV1;

#[tokio::main]
async fn main() {
simple_logger::SimpleLogger::new().init().unwrap();
let args = Args::parse();

println!("{:?}", args);


let server = qkd_kme_server::server::Server {
listen_addr: "127.0.0.1:3000".to_string(),
ca_client_cert_path: "certs/CA-zone1.crt".to_string(),
server_cert_path: "certs/kme1.crt".to_string(),
server_key_path: "certs/kme1.key".to_string(),
};

let qkd_manager = Arc::new(QkdManager::new(qkd_kme_server::MEMORY_SQLITE_DB_PATH, args.this_kme_id));
if qkd_manager.add_sae(1,
1,
&Some([0x70, 0xf4, 0x4f, 0x56, 0x0c, 0x3f, 0x27, 0xd4, 0xb2, 0x11, 0xa4, 0x78, 0x13, 0xaf, 0xd0, 0x3c, 0x03, 0x81, 0x3b, 0x8e])
).is_err() {
error!("Error adding SAE to QKD manager");
return;
}
if qkd_manager.add_sae(2,
1,
&Some([0x70, 0xf4, 0x4f, 0x56, 0x0c, 0x3f, 0x27, 0xd4, 0xb2, 0x11, 0xa4, 0x78, 0x13, 0xaf, 0xd0, 0x3c, 0x03, 0x81, 0x3b, 0x92])
).is_err() {
error!("Error adding SAE to QKD manager");
if std::env::args().len() != 2 {
eprintln!("Usage: {} <path to json config file>", std::env::args().nth(0).unwrap());
return;
}

let mut watchers: Vec<notify::RecommendedWatcher> = Vec::new();

for kme_dir in args.dirs_to_watch_other_kme_ids {
extract_all_keys_from_dir(&kme_dir.dir, kme_dir.kme_id, &qkd_manager);
let kme_id = kme_dir.kme_id;
let qkd_manager = Arc::clone(&qkd_manager);
watchers.push(match notify::recommended_watcher(move |res: Result<notify::Event, notify::Error>| {
match res {
Ok(event) => {
if let EventKind::Access(AccessKind::Close(AccessMode::Write)) = event.kind {
extract_all_keys_from_file(&event.paths[0].to_str().unwrap(), kme_id, &qkd_manager);
}
}
Err(e) => {
println!("Watch error: {:?}", e);
return;
}
}
}) {
Ok(watcher) => watcher,
Err(e) => {
error!("Error creating watcher: {:?}", e);
return;
}
});
if watchers.iter_mut().last().unwrap().watch(Path::new(&kme_dir.dir), RecursiveMode::NonRecursive).is_err() {
error!("Error watching directory: {:?}", kme_dir.dir);
let config = match qkd_kme_server::config::Config::from_json_path(&std::env::args().nth(1).unwrap()) {
Ok(config) => config,
Err(e) => {
eprintln!("Error reading config: {:?}", e);
return;
}
}
};

let server = qkd_kme_server::server::Server {
listen_addr: config.this_kme_config.https_listen_address.clone(),
ca_client_cert_path: config.this_kme_config.https_ca_client_cert_path.clone(),
server_cert_path: config.this_kme_config.https_server_cert_path.clone(),
server_key_path: config.this_kme_config.https_server_key_path.clone(),
};

let qkd_manager= QkdManager::from_config(&config);
println!("{:?}", qkd_manager.is_err());
let qkd_manager = qkd_manager.unwrap();

if server.run::<QKDKMERoutesV1>(&qkd_manager).await.is_err() {
error!("Error running HTTP server");
return;
}
}

#[derive(Parser, Debug)]
struct Args {
#[arg(long)]
this_kme_id: i64,
#[arg(long("kme_id,dir_watch"))]
dirs_to_watch_other_kme_ids: Vec<DirWatchOtherKmesArgs>,
}

#[derive(Debug, Clone)]
struct DirWatchOtherKmesArgs {
dir: String,
kme_id: i64,
}

impl std::str::FromStr for DirWatchOtherKmesArgs {
type Err = std::io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let kme_id_and_dir = s.split(",").collect::<Vec<&str>>();
if kme_id_and_dir.len() != 2 {
return Err(std::io::Error::other("Invalid format"));
}
let kme_id = i64::from_str(kme_id_and_dir[0]).map_err(|_| std::io::Error::other("Invalid format"))?;
Ok(Self {
dir: kme_id_and_dir[1].to_string(),
kme_id,
})
}
}

// TODO: move to QKD manager struct
fn extract_all_keys_from_file(file_path: &str, other_kme_id: i64, qkd_manager: &QkdManager) {
let file = std::fs::File::open(file_path).unwrap();
let mut reader = BufReader::with_capacity(32, file);
let mut buffer = [0; 32];
while let Ok(_) = reader.read_exact(&mut buffer) {
let qkd_key = PreInitQkdKeyWrapper::new(
other_kme_id,
&buffer,
).unwrap();
qkd_manager.add_pre_init_qkd_key(qkd_key).unwrap();
}
}

fn extract_all_keys_from_dir(dir_path: &str, other_kme_id: i64, qkd_manager: &QkdManager) {
let paths = std::fs::read_dir(dir_path).unwrap();
for path in paths {
let path = path.unwrap().path();
if path.is_file() {
extract_all_keys_from_file(path.to_str().unwrap(), other_kme_id, qkd_manager);
}
}
}
Loading

0 comments on commit 8822629

Please sign in to comment.