Skip to content

Commit

Permalink
Add support for demonstration log message over the web + some refacto…
Browse files Browse the repository at this point in the history
…ring
  • Loading branch information
Thomas Prévost committed Feb 15, 2024
1 parent f23a540 commit ec41d0f
Show file tree
Hide file tree
Showing 22 changed files with 924 additions and 474 deletions.
1 change: 1 addition & 0 deletions config_kme1.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"server_cert_path": "certs/zone1/kme1.crt",
"server_key_path": "certs/zone1/kme1.key"
},
"debugging_http_interface": "0.0.0.0:8080",
"kmes_https_interface": {
"listen_address": "0.0.0.0:3001",
"ca_client_cert_path": "certs/inter_kmes/root-ca-kme1.crt",
Expand Down
5 changes: 4 additions & 1 deletion src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ pub struct ThisKmeConfig {
/// # Note you should listen only on secured internal network
pub saes_https_interface: SAEsHttpsInterfaceConfig,
/// Config for external HTTPS interface for other KMEs
pub kmes_https_interface: KMEsHttpsInterfaceConfig
pub kmes_https_interface: KMEsHttpsInterfaceConfig,
/// Optional HTTP interface to see important debugging events
pub debugging_http_interface: Option<String>,
}

/// Config for internal HTTPS interface for SAEs (likely secured local network)
Expand Down Expand Up @@ -123,6 +125,7 @@ mod tests {
assert_eq!(config.this_kme_config.kmes_https_interface.ca_client_cert_path, "certs/inter_kmes/root-ca-kme1.crt");
assert_eq!(config.this_kme_config.kmes_https_interface.server_cert_path, "certs/zone1/kme1.crt");
assert_eq!(config.this_kme_config.kmes_https_interface.server_key_path, "certs/zone1/kme1.key");
assert_eq!(config.this_kme_config.debugging_http_interface, Some("127.0.0.1:8080".to_string()));
assert_eq!(config.other_kme_configs.len(), 1);
assert_eq!(config.other_kme_configs[0].id, 2);
assert_eq!(config.other_kme_configs[0].key_directory_to_watch, "tests/data/raw_keys/kme-1-2");
Expand Down
14 changes: 14 additions & 0 deletions src/event_subscription/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Interface for important event subscribers, supposed to be used for demonstration purpose
use std::io;

/// Trait that should be implemented by important event subscribers
/// Only events useful for demonstration purpose will be sent to the subscribers
pub trait ImportantEventSubscriber where Self: Sync + Send {
/// Receive a notification for an important event
/// # Arguments
/// * `message` - The notification message that should be sent to the subscriber
/// # Returns
/// An io::Error if the notification could not be sent, likely because of sync issue, or Ok(()) if the notification was sent successfully
fn notify(&self, message: &str) -> Result<(), io::Error>;
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod routes;
pub mod qkd_manager;
pub mod config;
pub(crate) mod entropy;
pub mod event_subscription;


/// Cast a string to an io::Error
Expand Down
62 changes: 42 additions & 20 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::sync::Arc;
use log::error;
use tokio::select;
use qkd_kme_server::event_subscription::ImportantEventSubscriber;
use qkd_kme_server::qkd_manager::QkdManager;
use qkd_kme_server::routes::EtsiSaeQkdRoutesV1;
use qkd_kme_server::routes::sae_zone_routes::EtsiSaeQkdRoutesV1;
use qkd_kme_server::routes::inter_kmes_routes::InterKMEsRoutes;
use qkd_kme_server::server::auth_https_server::AuthHttpsServer;
use qkd_kme_server::server::log_http_server::LoggingHttpServer;

#[tokio::main]
async fn main() {
Expand All @@ -21,29 +25,47 @@ async fn main() {
}
};

let sae_https_server = qkd_kme_server::server::Server {
listen_addr: config.this_kme_config.saes_https_interface.listen_address.clone(),
ca_client_cert_path: config.this_kme_config.saes_https_interface.ca_client_cert_path.clone(),
server_cert_path: config.this_kme_config.saes_https_interface.server_cert_path.clone(),
server_key_path: config.this_kme_config.saes_https_interface.server_key_path.clone(),
};
let sae_https_server = AuthHttpsServer::<EtsiSaeQkdRoutesV1>::new(
&config.this_kme_config.saes_https_interface.listen_address,
&config.this_kme_config.saes_https_interface.ca_client_cert_path,
&config.this_kme_config.saes_https_interface.server_cert_path,
&config.this_kme_config.saes_https_interface.server_key_path
);

let inter_kme_https_server = qkd_kme_server::server::Server {
listen_addr: config.this_kme_config.kmes_https_interface.listen_address.clone(),
ca_client_cert_path: config.this_kme_config.kmes_https_interface.ca_client_cert_path.clone(),
server_cert_path: config.this_kme_config.kmes_https_interface.server_cert_path.clone(),
server_key_path: config.this_kme_config.kmes_https_interface.server_key_path.clone(),
};
let inter_kme_https_server = AuthHttpsServer::<InterKMEsRoutes>::new(
&config.this_kme_config.kmes_https_interface.listen_address,
&config.this_kme_config.kmes_https_interface.ca_client_cert_path,
&config.this_kme_config.kmes_https_interface.server_cert_path,
&config.this_kme_config.kmes_https_interface.server_key_path
);

let qkd_manager = QkdManager::from_config(&config);
let qkd_manager = qkd_manager.unwrap();
let qkd_manager = QkdManager::from_config(&config).unwrap();

select! {
x = inter_kme_https_server.run::<InterKMEsRoutes>(&qkd_manager) => {
error!("Error running inter-KMEs HTTPS server: {:?}", x);
match config.this_kme_config.debugging_http_interface {
Some(listen_addr) => {
let logging_http_server = Arc::new(LoggingHttpServer::new(&listen_addr));
qkd_manager.add_important_event_subscriber(Arc::clone(&logging_http_server) as Arc<dyn ImportantEventSubscriber>).unwrap();
select! {
x = inter_kme_https_server.run(&qkd_manager) => {
error!("Error running inter-KMEs HTTPS server: {:?}", x);
},
x = sae_https_server.run(&qkd_manager) => {
error!("Error running SAEs HTTPS server: {:?}", x);
},
x = logging_http_server.run() => {
error!("Error running logging HTTP server: {:?}", x);
}
}
},
x = sae_https_server.run::<EtsiSaeQkdRoutesV1>(&qkd_manager) => {
error!("Error running SAEs HTTPS server: {:?}", x);
None => {
select! {
x = inter_kme_https_server.run(&qkd_manager) => {
error!("Error running inter-KMEs HTTPS server: {:?}", x);
},
x = sae_https_server.run(&qkd_manager) => {
error!("Error running SAEs HTTPS server: {:?}", x);
}
}
}
}
}
91 changes: 91 additions & 0 deletions src/qkd_manager/key_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use std::convert::identity;
use std::io;
use std::sync::Arc;
use uuid::Bytes;
use x509_parser::nom::AsBytes;
use crate::{io_err, KmeId, qkd_manager, SaeClientCertSerial, SaeId};
Expand All @@ -10,6 +11,8 @@ use base64::{engine::general_purpose, Engine as _};
use log::{error, info, warn};
use crate::qkd_manager::http_response_obj::{ResponseQkdKey, ResponseQkdKeysList};
use crate::ensure_prepared_statement_ok;
use crate::export_important_logging_message;
use crate::event_subscription::ImportantEventSubscriber;

/// Describes the key handler that will check authentication and manage the QKD keys in the database in a separate thread
pub(super) struct KeyHandler {
Expand All @@ -23,6 +26,8 @@ pub(super) struct KeyHandler {
this_kme_id: KmeId,
/// Router on classical network, used to connect to other KMEs over unsecure classical network
qkd_router: router::QkdRouter,
/// Subscribers to important events, for demonstration purpose
event_notification_subscribers: Vec<Arc<dyn ImportantEventSubscriber>>,
}

impl KeyHandler {
Expand All @@ -48,6 +53,7 @@ impl KeyHandler {
})?,
this_kme_id,
qkd_router: router::QkdRouter::new(),
event_notification_subscribers: vec![],
};
// Create the tables if they do not exist
key_handler.sqlite_db.execute(DATABASE_INIT_REQ).map_err(|e| {
Expand Down Expand Up @@ -144,6 +150,9 @@ impl KeyHandler {
error!("Error QKD manager sending response");
}
}
QkdManagerCommand::AddImportantEventSubscriber(subscriber) => {
self.event_notification_subscribers.push(subscriber);
}
}
}
Err(e) => {
Expand Down Expand Up @@ -266,6 +275,8 @@ impl KeyHandler {
let origin_kme_id = self.this_kme_id;
let target_kme_id = self.get_kme_id_from_sae_id(target_sae_id).ok_or(QkdManagerResponse::NotFound)?;

export_important_logging_message!(&self, &format!("[KME {}] SAE {} requested a key to communicate with {}", self.this_kme_id, origin_sae_id, target_sae_id));

let mut stmt = ensure_prepared_statement_ok!(self.sqlite_db, FETCH_PREINIT_KEY_PREPARED_STATEMENT);
stmt.bind((1, target_kme_id)).map_err(|_| {
error!("Error binding target KME ID");
Expand Down Expand Up @@ -301,6 +312,7 @@ impl KeyHandler {
error!("Error activating key on other KME");
qkd_manager_activation_error
})?;
export_important_logging_message!(&self, &format!("[KME {}] As SAE {} belongs to KME {}, activating it through inter KMEs network", self.this_kme_id, target_sae_id, target_kme_id));
}

self.delete_pre_init_key_with_id(id).map_err(|_| {
Expand Down Expand Up @@ -451,6 +463,7 @@ impl KeyHandler {
error!("Error executing SQL statement");
QkdManagerResponse::Ko
})?;
export_important_logging_message!(&self, &format!("[KME {}] Key {} activated between SAEs {} and {}", self.this_kme_id, key_uuid, origin_sae_id, target_sae_id));
Ok(QkdManagerResponse::Ok)
}

Expand Down Expand Up @@ -519,6 +532,8 @@ impl KeyHandler {
QkdManagerResponse::Ko
})?;

export_important_logging_message!(&self, &format!("[KME {}] SAE {} requested key {} (from {})", self.this_kme_id, current_sae_id, key_uuid, origin_sae_id));

// Encode the key in base64
Ok(ResponseQkdKey {
key_ID: key_uuid,
Expand Down Expand Up @@ -647,15 +662,49 @@ macro_rules! ensure_prepared_statement_ok {
}
}

/// Notify all subscribers of an event
/// # Arguments
/// * `key_handler_reference` - The reference to the key handler, like `&self`
/// * `message` - The message to notify, as string slice
#[macro_export]
macro_rules! export_important_logging_message {
($key_handler_reference:expr, $message:expr) => {
info!("{}", $message);
for subscriber in $key_handler_reference.event_notification_subscribers.iter() {
let _ = subscriber.notify($message); // We ignore the result here
}
}
}


#[cfg(test)]
mod tests {
use std::io::Error;
use std::sync::{Arc, Mutex};
use std::thread;
use crate::event_subscription::ImportantEventSubscriber;
use crate::qkd_manager::http_response_obj::HttpResponseBody;
use crate::qkd_manager::QkdManagerResponse;

const CLIENT_CERT_SERIAL_SIZE_BYTES: usize = 20;

struct TestImportantEventSubscriber {
events: Mutex<Vec<String>>,
}
impl TestImportantEventSubscriber {
fn new() -> Self {
Self {
events: Mutex::new(Vec::new()),
}
}
}
impl ImportantEventSubscriber for TestImportantEventSubscriber {
fn notify(&self, message: &str) -> Result<(), Error> {
self.events.lock().unwrap().push(message.to_string());
Ok(())
}
}

#[test]
fn test_get_sae_id_from_certificate() {
let (_, command_channel_rx) = crossbeam_channel::unbounded();
Expand Down Expand Up @@ -900,17 +949,54 @@ mod tests {
key_handler.delete_pre_init_key_with_id(key_id).unwrap();
}

#[test]
fn test_add_important_event_subscriber() {
let (_, command_channel_rx) = crossbeam_channel::unbounded();
let (response_channel_tx, _) = crossbeam_channel::unbounded();
let mut key_handler = super::KeyHandler::new(":memory:", command_channel_rx, response_channel_tx, 1).unwrap();

let subscriber = Arc::new(TestImportantEventSubscriber::new());
let subscriber2 = Arc::new(TestImportantEventSubscriber::new());

key_handler.event_notification_subscribers.push(Arc::clone(&subscriber) as Arc<dyn ImportantEventSubscriber>);
key_handler.event_notification_subscribers.push(Arc::clone(&subscriber2) as Arc<dyn ImportantEventSubscriber>);
assert_eq!(key_handler.event_notification_subscribers.len(), 2);
assert_eq!(subscriber.events.lock().unwrap().len(), 0);
assert_eq!(subscriber2.events.lock().unwrap().len(), 0);

let sae_certificate_serial = vec![0u8; CLIENT_CERT_SERIAL_SIZE_BYTES];
key_handler.add_sae(1, 1, &Some(sae_certificate_serial.clone())).unwrap();
key_handler.add_preinit_qkd_key(crate::qkd_manager::PreInitQkdKeyWrapper {
other_kme_id: 1,
key_uuid: *uuid::Uuid::from_bytes([0u8; 16]).as_bytes(),
key: [0u8; crate::QKD_KEY_SIZE_BITS / 8],
}).unwrap();
key_handler.get_sae_keys(&sae_certificate_serial, 1).unwrap();

assert_eq!(subscriber.events.lock().unwrap().len(), 2);
assert_eq!(subscriber2.events.lock().unwrap().len(), 2);
assert_eq!(subscriber.events.lock().unwrap()[0], "[KME 1] SAE 1 requested a key to communicate with 1");
assert_eq!(subscriber.events.lock().unwrap()[1], "[KME 1] Key 00000000-0000-0000-0000-000000000000 activated between SAEs 1 and 1");
assert_eq!(subscriber2.events.lock().unwrap()[0], "[KME 1] SAE 1 requested a key to communicate with 1");
assert_eq!(subscriber2.events.lock().unwrap()[1], "[KME 1] Key 00000000-0000-0000-0000-000000000000 activated between SAEs 1 and 1");
}

#[test]
fn test_run() {
let (command_tx, command_channel_rx) = crossbeam_channel::unbounded();
let (response_channel_tx, response_rx) = crossbeam_channel::unbounded();
let mut key_handler = super::KeyHandler::new(":memory:", command_channel_rx, response_channel_tx, 1).unwrap();

let subscriber = Arc::new(TestImportantEventSubscriber::new());
key_handler.event_notification_subscribers.push(Arc::clone(&subscriber) as Arc<dyn ImportantEventSubscriber>);

let sae_id = 1;
let kme_id = 1;
let sae_certificate_serial = vec![0u8; CLIENT_CERT_SERIAL_SIZE_BYTES];
let _ = thread::spawn(move || {
key_handler.run();
});

command_tx.send(super::QkdManagerCommand::AddSae(sae_id, kme_id, Some(sae_certificate_serial.clone()))).unwrap();
let qkd_manager_response = response_rx.recv().unwrap();
assert!(matches!(qkd_manager_response, QkdManagerResponse::Ok));
Expand All @@ -933,6 +1019,9 @@ mod tests {
let qkd_manager_response = response_rx.recv().unwrap();
assert!(matches!(qkd_manager_response, QkdManagerResponse::NotFound));

assert_eq!(subscriber.events.lock().unwrap().len(), 1);
assert_eq!(subscriber.events.lock().unwrap()[0], "[KME 1] SAE 1 requested a key to communicate with 1");

command_tx.send(super::QkdManagerCommand::GetStatus(sae_certificate_serial.clone(), 2)).unwrap();
let qkd_manager_response = response_rx.recv().unwrap();
assert!(matches!(qkd_manager_response, QkdManagerResponse::NotFound));
Expand Down Expand Up @@ -982,5 +1071,7 @@ mod tests {
true)).unwrap();
let qkd_manager_response = response_rx.recv().unwrap();
assert!(matches!(qkd_manager_response, QkdManagerResponse::Ok));

assert_eq!(subscriber.events.lock().unwrap().len(), 1);
}
}
Loading

0 comments on commit ec41d0f

Please sign in to comment.