From 857b9171af07a9cf4e25ca67636d2bf46c120012 Mon Sep 17 00:00:00 2001 From: "Federico Pasqua (eisterman)" Date: Mon, 12 Feb 2024 17:33:56 +0100 Subject: [PATCH] Use the real structure with Server-Broker-Client instead of Client-Server-Requester previously used in Bonk v1 --- .gitignore | 2 +- Cargo.lock | 243 +++++++++++++++++- Cargo.toml | 1 + bonknet_broker/Cargo.toml | 27 ++ .../src/bin/init_certs.rs | 87 +++++-- bonknet_broker/src/main.rs | 200 ++++++++++++++ bonknet_client/src/bin/client.rs | 3 +- bonknet_client/src/bin/requester.rs | 2 - bonknet_server/src/bin/server.rs | 158 +++--------- libbonknet/Cargo.toml | 1 + libbonknet/src/lib.rs | 37 +++ 11 files changed, 604 insertions(+), 157 deletions(-) create mode 100644 bonknet_broker/Cargo.toml rename {bonknet_server => bonknet_broker}/src/bin/init_certs.rs (59%) create mode 100644 bonknet_broker/src/main.rs delete mode 100644 bonknet_client/src/bin/requester.rs diff --git a/.gitignore b/.gitignore index d61b266..f728d17 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /target # Experiments with certificates -/*.pem \ No newline at end of file +certs \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 2d372f5..bb6fc1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,120 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "actix" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb72882332b6d6282f428b77ba0358cb2687e61a6f6df6a6d3871e8a177c2d4f" +dependencies = [ + "actix-macros", + "actix-rt", + "actix_derive", + "bitflags 2.4.2", + "bytes", + "crossbeam-channel", + "futures-core", + "futures-sink", + "futures-task", + "futures-util", + "log", + "once_cell", + "parking_lot", + "pin-project-lite", + "smallvec", + "tokio", + "tokio-util", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "actix-rt" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +dependencies = [ + "actix-macros", + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-tls" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4cce60a2f2b477bc72e5cde0af1812a6e82d8fd85b5570a5dcf2a5bf2c5be5f" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "impl-more", + "pin-project-lite", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -79,7 +193,7 @@ checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", @@ -143,6 +257,32 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bonknet_broker" +version = "0.1.0" +dependencies = [ + "actix", + "actix-rt", + "actix-server", + "actix-service", + "actix-tls", + "futures-util", + "libbonknet", + "rcgen", + "rmp-serde", + "rustls", + "thiserror", + "tokio-util", + "tracing", + "tracing-subscriber", +] + [[package]] name = "bonknet_client" version = "0.1.0" @@ -531,6 +671,12 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "impl-more" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" + [[package]] name = "indexmap" version = "1.9.3" @@ -577,6 +723,7 @@ name = "libbonknet" version = "0.1.0" dependencies = [ "rustls-pemfile", + "serde", "tokio-rustls", ] @@ -586,6 +733,12 @@ version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + [[package]] name = "lock_api" version = "0.4.11" @@ -651,6 +804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", + "log", "wasi", "windows-sys", ] @@ -665,6 +819,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -699,6 +863,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -870,9 +1040,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d918c80c5a4c7560db726763020bd16db179e4d5b828078842274a443addb5d" +checksum = "48406db8ac1f3cbc7dcdb56ec355343817958a356ff430259bb07baf7607e1e1" dependencies = [ "pem", "ring", @@ -886,7 +1056,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1001,15 +1171,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a" +checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" [[package]] name = "rustls-webpki" -version = "0.102.1" +version = "0.102.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4ca26037c909dedb327b48c3327d0ba91d3dd3c4e05dad328f210ffb68e95b" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" dependencies = [ "ring", "rustls-pki-types", @@ -1137,6 +1307,26 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.7" @@ -1307,6 +1497,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1333,6 +1524,17 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -1340,12 +1542,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", + "nu-ansi-term", "once_cell", "regex", "sharded-slab", + "smallvec", "thread_local", "tracing", "tracing-core", + "tracing-log", ] [[package]] @@ -1387,6 +1592,28 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index e20cc00..f70f9b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] resolver = "2" members = [ + "bonknet_broker", "bonknet_client", "bonknet_server", "libbonknet", diff --git a/bonknet_broker/Cargo.toml b/bonknet_broker/Cargo.toml new file mode 100644 index 0000000..4375f11 --- /dev/null +++ b/bonknet_broker/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "bonknet_broker" +version = "0.1.0" +edition = "2021" +default-run = "bonknet_broker" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libbonknet = { path = "../libbonknet" } +actix = "0.13.3" +actix-rt = "2.9.0" +actix-server = "2.3.0" +actix-service = "2.0.2" +actix-tls = { version = "3.3.0", features = ["rustls-0_22"] } +rustls = "0.22.2" +tracing = "0.1" +tracing-subscriber = "0.3" +futures-util = "0.3.30" +thiserror = "1.0.56" +tokio-util = { version = "0.7.10", features = ["codec"] } +rmp-serde = "1.1.2" +rcgen = "0.12.1" + +[[bin]] +name = "init_certs" +path = "src/bin/init_certs.rs" diff --git a/bonknet_server/src/bin/init_certs.rs b/bonknet_broker/src/bin/init_certs.rs similarity index 59% rename from bonknet_server/src/bin/init_certs.rs rename to bonknet_broker/src/bin/init_certs.rs index 0de4c72..b1206ee 100644 --- a/bonknet_server/src/bin/init_certs.rs +++ b/bonknet_broker/src/bin/init_certs.rs @@ -14,13 +14,35 @@ fn server_root_cert() -> Certificate { } fn server_cert() -> Certificate { - let mut params = CertificateParams::new(vec!["entity.other.host".into(), "localhost".into()]); - params.distinguished_name.push(DnType::CommonName, "localhost"); + let mut params = CertificateParams::new(vec!["entity.other.host".into(), "bonk.server.1".into()]); + params.distinguished_name.push(DnType::CommonName, "Server 1"); params.use_authority_key_identifier_extension = true; params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature); params .extended_key_usages - .push(rcgen::ExtendedKeyUsagePurpose::ServerAuth); + .push(rcgen::ExtendedKeyUsagePurpose::ClientAuth); + Certificate::from_params(params).unwrap() +} + +fn guestserver_root_cert() -> Certificate { + let subject_alt_names = vec!["hello.world.example".into()]; + let mut certparams = CertificateParams::new(subject_alt_names); + certparams.is_ca = rcgen::IsCa::Ca(BasicConstraints::Unconstrained); + let mut distname = rcgen::DistinguishedName::new(); + distname.push(DnType::OrganizationName, "Eister Corporation"); + distname.push(DnType::CommonName, "Bonknet Guest Server Root Cert CA"); + certparams.distinguished_name = distname; + Certificate::from_params(certparams).unwrap() +} + +fn guestserver_cert() -> Certificate { + let mut params = CertificateParams::new(vec!["entity.other.host".into(), "bonk.guestserver.1".into()]); + params.distinguished_name.push(DnType::CommonName, "Guest Server 1"); + params.use_authority_key_identifier_extension = true; + params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature); + params + .extended_key_usages + .push(rcgen::ExtendedKeyUsagePurpose::ClientAuth); Certificate::from_params(params).unwrap() } @@ -46,25 +68,25 @@ fn client_cert() -> Certificate { Certificate::from_params(params).unwrap() } -fn requester_root_cert() -> Certificate { +fn broker_root_cert() -> Certificate { let subject_alt_names = vec!["hello.world.example".into()]; let mut certparams = CertificateParams::new(subject_alt_names); certparams.is_ca = rcgen::IsCa::Ca(BasicConstraints::Unconstrained); let mut distname = rcgen::DistinguishedName::new(); distname.push(DnType::OrganizationName, "Eister Corporation"); - distname.push(DnType::CommonName, "Bonknet Requester Root Cert CA"); + distname.push(DnType::CommonName, "Bonknet Broker Root Cert CA"); certparams.distinguished_name = distname; Certificate::from_params(certparams).unwrap() } -fn requester_cert() -> Certificate { - let mut params = CertificateParams::new(vec!["entity.other.host".into(), "bonk.client.1".into()]); - params.distinguished_name.push(DnType::CommonName, "Requester 1"); +fn broker_cert() -> Certificate { + let mut params = CertificateParams::new(vec!["entity.other.host".into(), "localhost".into()]); + params.distinguished_name.push(DnType::CommonName, "localhost"); params.use_authority_key_identifier_extension = true; params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature); params .extended_key_usages - .push(rcgen::ExtendedKeyUsagePurpose::ClientAuth); + .push(rcgen::ExtendedKeyUsagePurpose::ServerAuth); Certificate::from_params(params).unwrap() } @@ -73,51 +95,68 @@ fn main() -> std::io::Result<()> { let server_root_cert = server_root_cert(); // The certificate is now valid for localhost and the domain "hello.world.example" { - let mut certfile = File::create("server_root_cert.pem")?; + let mut certfile = File::create("certs/server_root_cert.pem")?; certfile.write_all(server_root_cert.serialize_pem().unwrap().as_bytes())?; - let mut privkfile = File::create("server_root_key.pem")?; + let mut privkfile = File::create("certs/server_root_key.pem")?; privkfile.write_all(server_root_cert.serialize_private_key_pem().as_bytes())?; } // Now create the leaf let server_leaf_cert = server_cert(); { - let mut certfile = File::create("server_cert.pem")?; + let mut certfile = File::create("certs/server_cert.pem")?; certfile.write_all(server_leaf_cert.serialize_pem_with_signer(&server_root_cert).unwrap().as_bytes())?; - let mut privkfile = File::create("server_key.pem")?; + let mut privkfile = File::create("certs/server_key.pem")?; privkfile.write_all(server_leaf_cert.serialize_private_key_pem().as_bytes())?; } + // GUESTSERVER + let guestserver_root_cert = guestserver_root_cert(); + // The certificate is now valid for localhost and the domain "hello.world.example" + { + let mut certfile = File::create("certs/guestserver_root_cert.pem")?; + certfile.write_all(guestserver_root_cert.serialize_pem().unwrap().as_bytes())?; + let mut privkfile = File::create("certs/guestserver_root_key.pem")?; + privkfile.write_all(guestserver_root_cert.serialize_private_key_pem().as_bytes())?; + } + // Now create the leaf + let guestserver_leaf_cert = guestserver_cert(); + { + let mut certfile = File::create("certs/guestserver_cert.pem")?; + certfile.write_all(guestserver_leaf_cert.serialize_pem_with_signer(&guestserver_root_cert).unwrap().as_bytes())?; + let mut privkfile = File::create("certs/guestserver_key.pem")?; + privkfile.write_all(guestserver_leaf_cert.serialize_private_key_pem().as_bytes())?; + } // CLIENT let client_root_cert = client_root_cert(); // The certificate is now valid for localhost and the domain "hello.world.example" { - let mut certfile = File::create("client_root_cert.pem")?; + let mut certfile = File::create("certs/client_root_cert.pem")?; certfile.write_all(client_root_cert.serialize_pem().unwrap().as_bytes())?; - let mut privkfile = File::create("client_root_key.pem")?; + let mut privkfile = File::create("certs/client_root_key.pem")?; privkfile.write_all(client_root_cert.serialize_private_key_pem().as_bytes())?; } // Now create the leaf let client_leaf_cert = client_cert(); { - let mut certfile = File::create("client_cert.pem")?; + let mut certfile = File::create("certs/client_cert.pem")?; certfile.write_all(client_leaf_cert.serialize_pem_with_signer(&client_root_cert).unwrap().as_bytes())?; - let mut privkfile = File::create("client_key.pem")?; + let mut privkfile = File::create("certs/client_key.pem")?; privkfile.write_all(client_leaf_cert.serialize_private_key_pem().as_bytes())?; } - // CLIENT - let requester_root_cert = requester_root_cert(); + // BROKER + let requester_root_cert = broker_root_cert(); // The certificate is now valid for localhost and the domain "hello.world.example" { - let mut certfile = File::create("requester_root_cert.pem")?; + let mut certfile = File::create("certs/broker_root_cert.pem")?; certfile.write_all(requester_root_cert.serialize_pem().unwrap().as_bytes())?; - let mut privkfile = File::create("requester_root_key.pem")?; + let mut privkfile = File::create("certs/broker_root_key.pem")?; privkfile.write_all(requester_root_cert.serialize_private_key_pem().as_bytes())?; } // Now create the leaf - let requester_leaf_cert = requester_cert(); + let requester_leaf_cert = broker_cert(); { - let mut certfile = File::create("requester_cert.pem")?; + let mut certfile = File::create("certs/broker_cert.pem")?; certfile.write_all(requester_leaf_cert.serialize_pem_with_signer(&requester_root_cert).unwrap().as_bytes())?; - let mut privkfile = File::create("requester_key.pem")?; + let mut privkfile = File::create("certs/broker_key.pem")?; privkfile.write_all(requester_leaf_cert.serialize_private_key_pem().as_bytes())?; } println!("Certificates created"); diff --git a/bonknet_broker/src/main.rs b/bonknet_broker/src/main.rs new file mode 100644 index 0000000..b839bde --- /dev/null +++ b/bonknet_broker/src/main.rs @@ -0,0 +1,200 @@ +use actix::prelude::*; +use std::collections::HashMap; +use std::sync::Arc; +use libbonknet::{load_cert, load_prkey, FromServerMessage, RequiredReplyValues, FromGuestServerMessage}; +use rustls::{RootCertStore, ServerConfig}; +use rustls::server::WebPkiClientVerifier; +use actix_tls::accept::rustls_0_22::{Acceptor as RustlsAcceptor, TlsStream}; +use actix_server::Server; +use actix_rt::net::TcpStream; +use actix_service::{ServiceFactoryExt as _}; +use futures_util::{StreamExt}; +use thiserror::Error; +use tokio_util::codec::{Framed, LengthDelimitedCodec}; +use tracing::{info, error}; + +#[derive(Error, Debug)] +enum DBError { + #[error("Certificate is already registered with name {0}")] + CertAlreadyRegistered(String), + // #[error("Generic Failure")] + // GenericFailure, +} + +#[derive(Message)] +#[rtype(result = "Result<(), DBError>")] +struct RegisterServer { + cert: Vec, + name: String, +} + +// TODO: Move into Sqlite DB with unique check on col1 and col2!!!! Right now name is not unique +struct ServerCertDB { + db: HashMap, String>, // Cert to Name +} + +impl Actor for ServerCertDB { + type Context = Context; +} + +impl Handler for ServerCertDB { + type Result = Result<(), DBError>; + + fn handle(&mut self, msg: RegisterServer, _ctx: &mut Self::Context) -> Self::Result { + match self.db.get(&msg.cert) { + None => { + self.db.insert(msg.cert, msg.name); + Ok(()) + } + Some(name) => { + Err(DBError::CertAlreadyRegistered(name.clone())) + } + } + } +} + +struct GuestServerConnection { + stream: TlsStream, +} + +impl Actor for GuestServerConnection { + type Context = Context; +} + +struct ServerConnection { + stream: Framed, T>, + name: String +} + +impl ServerConnection { + fn new(stream: TlsStream, codec: T) -> Self { + let stream = Framed::new(stream, codec); + ServerConnection { + stream, + name: "Polnareffland1".into(), + } + } +} + +impl Actor for ServerConnection { + type Context = Context; +} + +#[actix_rt::main] +async fn main() { + // Tracing Subscriber + let subscriber = tracing_subscriber::FmtSubscriber::new(); + tracing::subscriber::set_global_default(subscriber).unwrap(); + // BROKER CERTS + let broker_root_cert_der = load_cert("certs/broker_root_cert.pem").unwrap(); + let broker_cert_der = load_cert("certs/broker_cert.pem").unwrap(); + let broker_prkey_der = load_prkey("certs/broker_key.pem").unwrap(); + // SERVER ROOT + let server_root_cert_der = load_cert("certs/server_root_cert.pem").unwrap(); + // GUESTSERVER ROOT + let guestserver_root_cert_der = load_cert("certs/guestserver_root_cert.pem").unwrap(); + // CLIENT ROOT + let client_root_cert_der = load_cert("certs/client_root_cert.pem").unwrap(); + // Client Verifier + let mut broker_root_store = RootCertStore::empty(); + broker_root_store.add(server_root_cert_der.clone()).unwrap(); + broker_root_store.add(client_root_cert_der.clone()).unwrap(); + broker_root_store.add(guestserver_root_cert_der.clone()).unwrap(); + let server_verifier = WebPkiClientVerifier::builder(Arc::new(broker_root_store)).build().unwrap(); + // Configure TLS + let server_tlsconfig = ServerConfig::builder() + // .with_no_client_auth() + .with_client_cert_verifier(server_verifier) + .with_single_cert(vec![broker_cert_der.clone(), broker_root_cert_der.clone()], broker_prkey_der.into()) + .unwrap(); + let server_acceptor = RustlsAcceptor::new(server_tlsconfig); + + let server_root_cert_der = Arc::new(server_root_cert_der); + let client_root_cert_der = Arc::new(client_root_cert_der); + let guestserver_root_cert_der = Arc::new(guestserver_root_cert_der); + + Server::build() + .bind("server-command", ("localhost", 2541), move || { + let server_root_cert_der = Arc::clone(&server_root_cert_der); + let client_root_cert_der = Arc::clone(&client_root_cert_der); + let guestserver_root_cert_der = Arc::clone(&guestserver_root_cert_der); + let _server_db_addr = ServerCertDB { + db: HashMap::new(), + }.start(); + + // Set up TLS service factory + server_acceptor + .clone() + .map_err(|err| println!("Rustls error: {:?}", err)) + .and_then(move |stream: TlsStream| { + let server_root_cert_der = Arc::clone(&server_root_cert_der); + let client_root_cert_der = Arc::clone(&client_root_cert_der); + let guestserver_root_cert_der = Arc::clone(&guestserver_root_cert_der); + async move { + let peer_cert_der = stream.get_ref().1.peer_certificates().unwrap().last().unwrap().clone(); + if peer_cert_der == *server_root_cert_der { + info!("Server connection"); + let framed = Framed::new(stream, LengthDelimitedCodec::new()); + framed.for_each(|item| async move { + match item { + Ok(buf) => { + use FromServerMessage::*; + let msg: FromServerMessage = rmp_serde::from_slice(&buf).unwrap(); + info!("{:?}", msg); + match msg { + RequiredReply(v) => match v { + RequiredReplyValues::Ok => { + info!("Required Reply OK") + } + RequiredReplyValues::GenericFailure { .. } => { + info!("Required Reply Generic Failure") + } + } + ChangeName { name } => { + info!("Requested Change Name to Name {}", name); + } + WhoAmI => { + info!("Requested WhoAmI"); + } + } + }, + Err(e) => { + info!("Disconnection: {:?}", e); + } + } + }).await; + info!("Disconnection!"); + } else if peer_cert_der == *guestserver_root_cert_der { + info!("GuestServer connection"); + let framed = Framed::new(stream, LengthDelimitedCodec::new()); + framed.for_each(|item| async move { + match item { + Ok(buf) => { + use FromGuestServerMessage::*; + let msg: FromGuestServerMessage = rmp_serde::from_slice(&buf).unwrap(); + info!("{:?}", msg); + match msg { + Announce { name } => { + info!("Announced with name {}", name); + } + } + } + Err(e) => { + info!("Disconnection: {:?}", e); + } + } + }).await; + } else if peer_cert_der == *client_root_cert_der { + info!("Client connection"); + } else { + error!("Unknown Root Certificate"); + } + Ok(()) + } + }) + }).unwrap() + .workers(1) + .run() + .await + .unwrap(); +} diff --git a/bonknet_client/src/bin/client.rs b/bonknet_client/src/bin/client.rs index 5e2a76d..d3df96b 100644 --- a/bonknet_client/src/bin/client.rs +++ b/bonknet_client/src/bin/client.rs @@ -16,6 +16,7 @@ enum ClientMessage { NotRequired { id: String }, } +// TODO: This is an old examples #[tokio::main] async fn main() -> std::io::Result<()> { let client_name = "Polnareffland1"; @@ -36,7 +37,7 @@ async fn main() -> std::io::Result<()> { let connector = TlsConnector::from(Arc::new(tlsconfig)); let dnsname = ServerName::try_from("localhost").unwrap(); - let stream = TcpStream::connect("localhost:6379").await?; + let stream = TcpStream::connect("localhost:2541").await?; let stream = connector.connect(dnsname, stream).await?; let mut transport = Framed::new(stream, LengthDelimitedCodec::new()); diff --git a/bonknet_client/src/bin/requester.rs b/bonknet_client/src/bin/requester.rs deleted file mode 100644 index 7f755fb..0000000 --- a/bonknet_client/src/bin/requester.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[tokio::main] -async fn main() {} diff --git a/bonknet_server/src/bin/server.rs b/bonknet_server/src/bin/server.rs index 2ce4e2d..89f1ccd 100644 --- a/bonknet_server/src/bin/server.rs +++ b/bonknet_server/src/bin/server.rs @@ -1,19 +1,12 @@ -use std::collections::HashMap; -use tokio::net::{TcpListener, TcpStream}; -use std::net::{SocketAddr}; -use std::sync::{Arc}; -use std::time::Instant; -use futures::stream::{Stream, StreamExt}; -use tokio_rustls::{TlsAcceptor}; -use tokio_rustls::rustls::{RootCertStore, ServerConfig}; -use tokio_rustls::rustls::server::WebPkiClientVerifier; -use serde::{Serialize, Deserialize}; -use tokio::task::JoinHandle; -use tokio_rustls::server::TlsStream; +use std::sync::Arc; +use futures::SinkExt; +use tokio::net::TcpStream; +use tokio_rustls::rustls::{ClientConfig, RootCertStore}; +use tokio_rustls::rustls::pki_types::{ServerName}; +use tokio_rustls::TlsConnector; use tokio_util::codec::{Framed, LengthDelimitedCodec}; -use libbonknet::{load_prkey, load_cert}; - -type FramedStream = Framed,LengthDelimitedCodec>; +use serde::{Serialize, Deserialize}; +use libbonknet::{load_cert, load_prkey, FromServerMessage}; #[derive(Debug, Serialize, Deserialize)] enum ClientMessage { @@ -23,115 +16,38 @@ enum ClientMessage { NotRequired { id: String }, } -async fn process_client(stream: TlsStream, peer_addr: SocketAddr) { - let transport = Framed::new(stream, LengthDelimitedCodec::new()); - transport.for_each(|item| async move { - match item { - Ok(frame) => { - let a: ClientMessage = rmp_serde::from_slice(&frame).unwrap(); - println!("{:?}: {:?}", peer_addr, a); - }, - Err(e) => { - println!("{:?}: ERROR: {}", peer_addr, e); - } - } - }).await; -} - -struct ClientState { - framedstream: FramedStream, - last_life_signal: Instant, -} - -struct ClientConnectionManager { - registered_clients: Arc>, - unreg_clients: Arc>, -} - -impl ClientConnectionManager { - async fn new_and_initialize(port: u16, tlsconfig: ServerConfig) -> ClientConnectionManager { - let acceptor = TlsAcceptor::from(Arc::new(tlsconfig)); - let listener = TcpListener::bind(format!("localhost:{}", port)).await.unwrap(); - let registered_clients = Arc::new(HashMap::new()); - let unreg_clients = Arc::new(Vec::new()); - tokio::spawn(async move { - let task_acceptor = acceptor; - loop { - let (stream, peer_addr) = listener.accept().await.unwrap(); - let acceptor = task_acceptor.clone(); - let stream = acceptor.accept(stream).await.unwrap(); - - tokio::spawn(async move { - //let transport = Framed::new(stream, LengthDelimitedCodec::new()); - process_client(stream, peer_addr).await; - }); - } - }); - let ccm = ClientConnectionManager { registered_clients, unreg_clients}; - ccm - } - - async fn process_new_client(&mut self, transport: FramedStream, _peer_addr: SocketAddr) { - let state = ClientState{ - framedstream: transport, - last_life_signal: Instant::now(), - }; - self.unreg_clients.push(state); - } -} - #[tokio::main] -async fn main() { - let server_root_cert_der = load_cert("server_root_cert.pem").unwrap(); - let server_cert_der = load_cert("server_cert.pem").unwrap(); - let server_prkey_der = load_prkey("server_key.pem").unwrap(); - // CLIENT ROOT - let client_root_cert_der = load_cert("client_root_cert.pem").unwrap(); - // Client Verifier - let mut clientrootstore = RootCertStore::empty(); - clientrootstore.add(client_root_cert_der).unwrap(); - let client_verifier = WebPkiClientVerifier::builder(Arc::new(clientrootstore)).build().unwrap(); - // Configure TLS - let tlsconfig = ServerConfig::builder() - // .with_no_client_auth() - .with_client_cert_verifier(client_verifier) - .with_single_cert(vec![server_cert_der.clone(), server_root_cert_der.clone()], server_prkey_der.into()) +async fn main() -> std::io::Result<()> { + let client_name = "Polnareffland1"; + // Root certs to verify the server is the right one + let mut broker_root_cert_store = RootCertStore::empty(); + let broker_root_cert_der = load_cert("certs/broker_root_cert.pem").unwrap(); + broker_root_cert_store.add(broker_root_cert_der).unwrap(); + // Auth Cert to send the server who am I + let root_server_cert = load_cert("certs/server_root_cert.pem").unwrap(); + let server_cert = load_cert("certs/server_cert.pem").unwrap(); + let server_prkey = load_prkey("certs/server_key.pem").unwrap(); + // Load TLS Config + let tlsconfig = ClientConfig::builder() + .with_root_certificates(broker_root_cert_store) + // .with_no_client_auth(); + .with_client_auth_cert(vec![server_cert, root_server_cert], server_prkey.into()) .unwrap(); - let acceptor = TlsAcceptor::from(Arc::new(tlsconfig)); + let connector = TlsConnector::from(Arc::new(tlsconfig)); + let dnsname = ServerName::try_from("localhost").unwrap(); - let listener = TcpListener::bind("localhost:6379").await.unwrap(); + let stream = TcpStream::connect("localhost:2541").await?; + let stream = connector.connect(dnsname, stream).await?; - // Create Queue Binder + let mut transport = Framed::new(stream, LengthDelimitedCodec::new()); - loop { - let (stream, peer_addr) = listener.accept().await.unwrap(); - let acceptor = acceptor.clone(); - let stream = acceptor.accept(stream).await.unwrap(); - - tokio::spawn(async move { - //let transport = Framed::new(stream, LengthDelimitedCodec::new()); - process_client(stream, peer_addr).await; - }); - - // let msg1 = ClientMessage::Required { id: "Testo".into() }; - // let msg2 = ClientMessage::NotRequired { id: "Testo2".into() }; - // transport.send(rmp_serde::to_vec(&msg1).unwrap().into()).await.unwrap(); - // transport.send(rmp_serde::to_vec(&msg2).unwrap().into()).await.unwrap(); - - // let fut = async move { - // let stream = acceptor.accept(stream).await?; - // let (mut reader, mut writer) = split(stream); - // let n = copy(&mut reader, &mut writer).await?; - // writer.flush().await?; - // println!("Echo: {} - {}", peer_addr, n); - // - // Ok(()) as std::io::Result<()> - // }; - // - // tokio::spawn(async move { - // if let Err(err) = fut.await { - // eprintln!("{:?}", err); - // } - // }); + let msg1 = FromServerMessage::WhoAmI; + transport.send(rmp_serde::to_vec(&msg1).unwrap().into()).await.unwrap(); + for i in 0..10 { + let msg = FromServerMessage::ChangeName { name: format!("{client_name}-{i}") }; + transport.send(rmp_serde::to_vec(&msg).unwrap().into()).await.unwrap(); + tokio::time::sleep(std::time::Duration::from_secs(1)).await; } -} + + Ok(()) +} \ No newline at end of file diff --git a/libbonknet/Cargo.toml b/libbonknet/Cargo.toml index 0fcb0e0..1ecabcd 100644 --- a/libbonknet/Cargo.toml +++ b/libbonknet/Cargo.toml @@ -8,3 +8,4 @@ edition = "2021" [dependencies] tokio-rustls = "0.25.0" rustls-pemfile = "2.0.0" +serde = { version = "1.0", features = ["derive"] } diff --git a/libbonknet/src/lib.rs b/libbonknet/src/lib.rs index 8ed59b3..4568656 100644 --- a/libbonknet/src/lib.rs +++ b/libbonknet/src/lib.rs @@ -1,5 +1,6 @@ use std::io::{BufReader, Error, ErrorKind}; use rustls_pemfile::{read_one, Item}; +use serde::{Deserialize, Serialize}; use tokio_rustls::rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer}; pub fn load_cert(filename: &str) -> std::io::Result { @@ -23,3 +24,39 @@ pub fn load_prkey(filename: &str) -> std::io::Result { Err(Error::new(ErrorKind::InvalidInput, "no pkcs8key")) } } + +#[derive(Debug, Serialize, Deserialize)] +pub enum RequiredReplyValues { + Ok, + GenericFailure { status_code: u32, msg: Option }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum FromServerMessage { + RequiredReply(RequiredReplyValues), + ChangeName { name: String }, + WhoAmI, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum YouAreValues { + Registered { name: String }, + NotRegistered, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum ToServerMessage { + Required { id: String }, + YouAre(YouAreValues), +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum FromGuestServerMessage { + Announce { name: String } +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum ToGuestServerMessage { + OkAnnounce {}, + FailedAnnounce { status_code: u32, msg: Option }, // TODO: make it better? +}