diff --git a/Cargo.toml b/Cargo.toml index d707f86a..dbf17127 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" description = "A mediator for DIDComm messages" authors = ["adorsys GmbH Co. KG"] - [workspace] members = [ "crates/did-utils", @@ -14,9 +13,9 @@ members = [ "crates/plugins/did-endpoint", "crates/plugins/mediator-coordination", "crates/plugins/oob-messages", + "crates/secure-key-storage", # Added path for the secure_key_storage crate ] - [workspace.dependencies] did-utils = { path = "./crates/did-utils", version = "0.1.0" } keystore = { path = "./crates/keystore", version = "0.1.0" } @@ -24,6 +23,7 @@ plugin-api = { path = "./crates/plugin-api", version = "0.1.0" } did-endpoint = { path = "./crates/plugins/did-endpoint", version = "0.1.0" } oob-messages = { path = "./crates/plugins/oob-messages", version = "0.1.0" } mediator-coordination = { path = "./crates/plugins/mediator-coordination", version = "0.1.0" } +secure-key-storage = { path = "./crates/secure-key-storage", version = "0.1.0" } # Added path # Other common dependencies serde = "1.0" @@ -32,7 +32,7 @@ getrandom = "0.2" hyper-tls = "0.5.0" json-patch = "1.0.0" x25519-dalek = "2.0.0-rc.3" -multibase = "0.8.0" # earlier version due to 'did-utils' +multibase = "0.8.0" json-canon = "0.1.3" qrcode = "0.12.0" image = "0.23" @@ -67,10 +67,8 @@ tower-http = "0.4.3" base64ct = { version = "1.6.0", default-features = false } zeroize = { version = "1.6.0", default-features = false } - [dependencies] plugin-api.workspace = true - axum.workspace = true dotenv-flow.workspace = true tracing.workspace = true @@ -80,13 +78,13 @@ hyper.workspace = true tokio = { workspace = true, features = ["full"] } tracing-subscriber = { workspace = true, features = ["json"] } tower-http = { workspace = true, features = ["catch-panic", "trace"] } +secure-key-storage = { path = "./crates/secure-key-storage" } # Added path # optional dependencies chrono = { workspace = true, optional = true } did-endpoint = { workspace = true, optional = true } oob-messages = { workspace = true, optional = true } - [features] default = ["plugin-index", "plugin-did_endpoint", "plugin-oob_messages"] @@ -94,7 +92,13 @@ plugin-index = ["dep:chrono"] plugin-did_endpoint = ["dep:did-endpoint"] plugin-oob_messages = ["dep:oob-messages"] - [dev-dependencies] nix = { version = "0.29.0", features = ["feature"] } tower = { version = "0.4.13", features = ["util"] } + +# Add missing dependencies for `secure_key_storage` +[dependencies.secrecy] +version = "0.9" + +[dependencies.serde_derive] +version = "1.0" # Include this only if the `secure_key_storage` crate uses it directly diff --git a/src/lib.rs b/src/lib.rs index ebf6d838..4b89fa98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,10 @@ pub mod plugins; +pub mod secret_key; +pub mod secure_key; use axum::Router; use plugins::handler::PluginContainer; +use secret_key::SecretBox; use tower_http::{catch_panic::CatchPanicLayer, trace::TraceLayer}; pub fn app() -> (PluginContainer<'static>, Router) { diff --git a/src/main.rs b/src/main.rs index 74c71fde..7c11818f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,45 @@ use axum::Server; use didcomm_mediator::app; use std::net::SocketAddr; +use secure_key_storage::SecretBox; +use zeroize::Zeroize; +use std::env; +use tracing::info; +use dotenv_flow::dotenv_flow; +use tracing_subscriber::{filter, layer::SubscriberExt, util::SubscriberInitExt}; #[tokio::main] async fn main() { // Load dotenv-flow variables - dotenv_flow::dotenv_flow().ok(); + dotenv_flow().ok(); // Enable logging config_tracing(); + // Example: securely loading a secret key + let api_key = load_secret_key().await; + info!("Loaded API key."); + // Start server - let port = std::env::var("SERVER_LOCAL_PORT").unwrap_or("3000".to_owned()); + let port = env::var("SERVER_LOCAL_PORT").unwrap_or("3000".to_owned()); let addr: SocketAddr = format!("127.0.0.1:{port}").parse().unwrap(); - tracing::info!("listening on {addr}"); - generic_server_with_graceful_shutdown(addr).await; + info!("listening on {addr}"); + generic_server_with_graceful_shutdown(addr, api_key).await; +} + +async fn load_secret_key() -> SecretBox { + // Simulate loading a secret key. Replace this with actual key loading. + let secret_key = "supersecretapikey".to_string(); // This should be replaced with actual key retrieval logic + SecretBox::new(secret_key) } -async fn generic_server_with_graceful_shutdown(addr: SocketAddr) { +async fn generic_server_with_graceful_shutdown(addr: SocketAddr, api_key: SecretBox) { // Load plugins let (mut plugin_container, router) = app(); + // Use `api_key` securely as needed in your application, for example in your app's router setup. + // Spawn task for server tokio::spawn(async move { Server::bind(&addr) @@ -32,21 +50,18 @@ async fn generic_server_with_graceful_shutdown(addr: SocketAddr) { tokio::select! { _ = tokio::signal::ctrl_c() => { - tracing::info!("shutting down gracefully"); + info!("shutting down gracefully"); let _ = plugin_container.unload(); } }; } fn config_tracing() { - use tracing::Level; - use tracing_subscriber::{filter, layer::SubscriberExt, util::SubscriberInitExt}; - let tracing_layer = tracing_subscriber::fmt::layer(); let filter = filter::Targets::new() - .with_target("hyper::proto", Level::INFO) - .with_target("tower_http::trace", Level::DEBUG) - .with_default(Level::DEBUG); + .with_target("hyper::proto", tracing::Level::INFO) + .with_target("tower_http::trace", tracing::Level::DEBUG) + .with_default(tracing::Level::DEBUG); tracing_subscriber::registry() .with(tracing_layer) diff --git a/src/secret_key.rs b/src/secret_key.rs new file mode 100644 index 00000000..6efe06d0 --- /dev/null +++ b/src/secret_key.rs @@ -0,0 +1,43 @@ +//! Secure key storage implementation using `SecretBox` +//! +//! This module provides a `SecretBox` wrapper to securely handle secrets, +//! ensuring that they are not exposed, copied, or logged inadvertently. + +use secrecy::Secret; +use zeroize::Zeroize; +use core::fmt; + +pub struct SecretBox { + inner_secret: Secret, +} + +impl SecretBox { + /// Create a new `SecretBox` with the given secret. + pub fn new(secret: S) -> Self { + Self { + inner_secret: Secret::new(secret), + } + } + + /// Expose the inner secret for read-only access. + pub fn expose_secret(&self) -> &S { + self.inner_secret.expose_secret() + } + + /// Expose the inner secret for mutable access. + pub fn expose_secret_mut(&mut self) -> &mut S { + self.inner_secret.expose_secret_mut() + } +} + +impl fmt::Debug for SecretBox { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "SecretBox<{}>([REDACTED])", core::any::type_name::()) + } +} + +impl Drop for SecretBox { + fn drop(&mut self) { + self.inner_secret.zeroize(); + } +} diff --git a/src/secure_key/mod.rs b/src/secure_key/mod.rs new file mode 100644 index 00000000..e69de29b