Rebranding to coffer, restructuring

Signed-off-by: Armin Friedl <dev@friedl.net>
This commit is contained in:
Armin Friedl 2019-11-26 04:00:24 +01:00
parent b39a3ef1ac
commit 3344ca4877
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8
16 changed files with 312 additions and 221 deletions

83
Cargo.lock generated
View file

@ -64,6 +64,43 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "coffer-client"
version = "0.1.0"
dependencies = [
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "coffer-companion"
version = "0.1.0"
dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
"sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "coffer-server"
version = "0.1.0"
dependencies = [
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crc32fast"
version = "1.2.0"
@ -355,43 +392,6 @@ name = "rle-decode-fast"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "secsrv"
version = "0.1.0"
dependencies = [
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "secsrv-client"
version = "0.1.0"
dependencies = [
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "secsrv-util"
version = "0.1.0"
dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
"sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
version = "1.0.102"
@ -522,14 +522,6 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
@ -669,7 +661,6 @@ dependencies = [
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"

View file

@ -1,7 +1,7 @@
[workspace]
members = [
"secsrv",
"secsrv-companion",
"secsrv-client"
"coffer-server",
"coffer-client",
"coffer-companion"
]

View file

@ -1,10 +1 @@
# SecServ
The simple secret service
# Protocol
Alice (secret service): keypair (apk, ask)
Bob (client): keypair (bpk, bsk)
KEY {id: string, keyid: string, nonce: b64, tag: signature}
// alice checks access rights of id for keyid
EKY {nonce1:b64, enc(key, nonce:64, bpk), tag: signature}
# Coffer

View file

@ -1,5 +1,5 @@
[package]
name = "secsrv-client"
name = "coffer-client"
version = "0.1.0"
authors = ["Armin Friedl <dev@friedl.net>"]
edition = "2018"

View file

@ -1,5 +1,5 @@
[package]
name = "secsrv-util"
name = "coffer-companion"
version = "0.1.0"
authors = ["Armin Friedl <dev@friedl.net>"]
edition = "2018"

View file

@ -1,33 +1,30 @@
use serde::{Deserialize, Serialize};
use sodiumoxide::crypto::box_;
use sodiumoxide::crypto::sealedbox;
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use sodiumoxide::crypto::box_;
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use std::io::Write;
#[derive(Debug,Serialize,Deserialize)]
pub enum Key {
MasterKey {
id: String,
public_key: box_::PublicKey,
secret_key: box_::SecretKey
},
#[derive(Debug, Serialize, Deserialize)]
struct MasterKey {
public_key: box_::PublicKey,
secret_key: box_::SecretKey,
}
ClientKey {
id: String,
public_key: box_::PublicKey
}
struct ClientKey {
id: String,
public_key: box_::PublicKey,
}
pub type Secrets = HashMap<String, String>;
pub type Secs = Vec<String>;
fn main() -> Result<(), Box<dyn Error>> {
let keypair = box_::gen_keypair();
let masterkey: Key = Key::MasterKey {
id: "master".to_owned(),
let keypair = box_::gen_keypair();
let masterkey: MasterKey = MasterKey {
public_key: keypair.0,
secret_key: keypair.1
secret_key: keypair.1,
};
let f = File::create("./masterkey.cbor")?;
@ -36,10 +33,16 @@ fn main() -> Result<(), Box<dyn Error>> {
let secrets: Secrets = [
("ABC".to_owned(), "DEF".to_owned()),
("XYZ".to_owned(), "ABC".to_owned()),
].iter().cloned().collect();
]
.iter()
.cloned()
.collect();
let f = File::create("./secrets.cbor")?;
serde_cbor::to_writer(f, &secrets)?;
let sc_res = serde_cbor::to_vec(&secrets)?;
let sc_res = sealedbox::seal(&sc_res, &masterkey.public_key);
let mut f = File::create("./secrets.cbor")?;
f.write(&sc_res)?;
f.flush()?;
let secreta = "ABC".to_owned();
let mut f = File::create("./keyreq_a.cbor")?;
@ -53,7 +56,7 @@ fn main() -> Result<(), Box<dyn Error>> {
f.write(&buf.len().to_be_bytes())?;
f.write(&buf)?;
let secs = vec!{"ABC", "XYZ"};
let secs = vec!["ABC", "XYZ"];
let f = File::create("./secreq.yaml")?;
serde_yaml::to_writer(f, &secs)?;

View file

@ -1,5 +1,5 @@
[package]
name = "secsrv"
name = "coffer-server"
version = "0.1.0"
authors = ["Armin Friedl <dev@friedl.net>"]
edition = "2018"
@ -9,10 +9,10 @@ edition = "2018"
log = "0.4"
env_logger="0.7"
structopt = "0.3"
quick-error = "1.2"
# Key management/Cryptography
sodiumoxide = "0.2.5"
# Communication
serde = { version = "1.0", features = ["derive"]}
serde_cbor = "0.10.2"
toml = "0.5"
futures = { version = "0.3.1", features = ["thread-pool"]}

View file

@ -0,0 +1,83 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use quick_error::quick_error;
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use sodiumoxide::crypto::sealedbox;
use sodiumoxide::crypto::box_;
quick_error! {
#[derive(Debug)]
pub enum KeyringError {
Io(err: std::io::Error) {
from()
}
Cbor(err: serde_cbor::Error) {
from()
}
Crypto {}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MasterKey {
public_key: box_::PublicKey,
secret_key: box_::SecretKey,
}
impl MasterKey {
pub fn decrypt(&self, c: &[u8]) -> Result<Vec<u8>, KeyringError> {
sealedbox::open(c, &self.public_key, &self.secret_key)
.map_err(|_| KeyringError::Crypto)
}
fn encrypt(&self, m: &[u8]) -> Vec<u8> {
sealedbox::seal(m, &self.public_key)
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ClientKey {
id: String,
public_key: box_::PublicKey,
}
pub struct Keyring {
pub master: MasterKey,
pub clients: HashMap<String, ClientKey>,
}
impl Keyring {
pub fn new_from_path(path: &PathBuf, keep: bool) -> Result<Keyring, KeyringError> {
let keyring = Keyring {
master: key_from_path(path, keep)?,
clients: HashMap::new(),
};
Ok(keyring)
}
pub fn add_key_from_path(&mut self, path: &PathBuf, keep: bool) -> Result<(), KeyringError> {
let client_key: ClientKey = key_from_path(path, keep)?;
self.clients.insert(client_key.id.clone(), client_key);
Ok(())
}
}
fn key_from_path<T>(path: &PathBuf, keep: bool) -> Result<T, KeyringError>
where T: serde::de::DeserializeOwned
{
let mk_file = File::open(path)?;
let key = serde_cbor::from_reader(mk_file)?;
if !keep { std::fs::remove_file(path)? };
Ok(key)
}

View file

@ -0,0 +1,70 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use quick_error::quick_error;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;
// do not provide a path to keyring through coffer module. keyring is hence
// effectively private outside coffer
mod keyring;
use keyring::Keyring;
quick_error! {
#[derive(Debug)]
pub enum CofferError {
Keyring(err: keyring::KeyringError) {
from()
}
Io(err: std::io::Error) {
from()
}
Cbor(err: serde_cbor::Error) {
from()
}
Coffer(err: &'static str) {
from()
}
}
}
type Result<T> = std::result::Result<T, CofferError>;
type Secrets = HashMap<String, String>; // move this to a module if it gathers crust
pub struct Coffer {
// do not expose inner structure of coffer
keyring: Keyring,
secrets: Secrets
}
impl Coffer {
/// Create a coffer from a masterkey and secrets encrypted with the masterkey's
/// public key
pub fn new_from_path_encrypted(masterkey: &PathBuf, secrets: &PathBuf, keep: bool) -> Result<Coffer> {
debug!{"Initializing keyring"}
let keyring = Keyring::new_from_path(masterkey, keep)?;
debug!{"Loading secrets"}
let mut sec_data = Vec::new();
File::open(secrets)?.read_to_end(&mut sec_data)?;
debug!{"Removing files"}
if !keep {
std::fs::remove_file(secrets)?;
std::fs::remove_file(masterkey)?;
};
debug!{"Decrypting secrets"}
sec_data = keyring.master.decrypt(&sec_data)?;
let secrets = serde_cbor::from_slice::<Secrets>(&sec_data)?;
debug!{"Filling coffer"};
Ok(Coffer{keyring, secrets})
}
pub fn get_secret(&self, key: &str) -> Result<&String> {
self.secrets.get(key).ok_or("No secret found in coffer for".into())
}
}

View file

@ -7,28 +7,29 @@ use std::io::{Write};
use std::io::Read;
use futures::executor::ThreadPool;
use crate::secrets::{Secrets};
use crate::coffer::Coffer;
pub struct Channel {
pub executor: ThreadPool,
pub address: SocketAddr,
pub coffer: Arc<Coffer>
}
impl Channel {
pub fn listen(self, secrets: Arc<Secrets>) {
pub fn listen(self) {
let listener:TcpListener = TcpListener::bind(self.address).unwrap();
listener.incoming().for_each(|inc| {
match inc {
Ok(tcp_stream) => self.executor.spawn_ok(handler(tcp_stream, secrets.clone())),
Ok(tcp_stream) => self.executor.spawn_ok(handler(tcp_stream, self.coffer.clone())),
Err(e) => error!{"Failed binding incoming connection {}", e}
}
})
}
}
async fn handler(mut stream: TcpStream, secrets: Arc<Secrets>) {
async fn handler(mut stream: TcpStream, coffer: Arc<Coffer>) {
let mut peek_buf = [0x00; 1];
while stream.peek(&mut peek_buf).unwrap() != 0 {
@ -41,12 +42,12 @@ async fn handler(mut stream: TcpStream, secrets: Arc<Secrets>) {
let mut handle = (&stream).take(len);
handle.read_to_end(&mut buf);
debug!{"Read vec {:?}", buf};
let res: Result<String, serde_cbor::Error> = serde_cbor::from_slice(&buf);
match res {
Ok(request) => {
if let Some(secret) = secrets.get(&request) {
if let Ok(secret) = coffer.get_secret(&request) {
writeln!(stream, "{}", secret)
.unwrap_or_else(|err| {error!{"Could not write key response to stream {}", err}});
debug!{"Wrote {:?}", secret}

82
coffer-server/src/main.rs Normal file
View file

@ -0,0 +1,82 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use env_logger;
use std::convert::TryInto;
use futures::executor::ThreadPool;
use std::path::PathBuf;
use structopt::StructOpt;
use std::net::IpAddr;
use std::net::SocketAddr;
use std::sync::Arc;
mod coffer;
mod comm;
use comm::Channel;
#[derive(StructOpt, Debug)]
struct Args {
/// Path to the master key file. Will be deleted after processing.
#[structopt(short, long, parse(from_os_str), env = "SECSRV_MASTER", hide_env_values = true)]
master: PathBuf,
/// Path to the secret keys file. Will be deleted after processing.
/// Must be encrypted with the public key of the master key
#[structopt(short, long, parse(from_os_str), env = "SECSRV_KEYS", hide_env_values = true)]
secrets: PathBuf,
/// The port secsrv listens on
#[structopt(short, long, env = "SECSRV_PORT", default_value = "9187")]
port: u16,
/// The address secsrv binds to
#[structopt(short, long, env = "SECSRV_IP", default_value = "127.0.0.1")]
ip: IpAddr,
/// Prevent deletion of key files
#[structopt(short)]
keep_keys: bool
}
fn main() {
env_logger::init();
let args = Args::from_args();
_print_banner();
info!{"Setting up executor"}
let address: SocketAddr = (args.ip, args.port).try_into()
.expect("Parsing binding address failed");
let executor = ThreadPool::new()
.expect("Setting up executor failed");
info!{"Filling coffer"}
let coffer = coffer::Coffer::new_from_path_encrypted(&args.master, &args.secrets, args.keep_keys)
.expect("Could not fill coffer");
debug!{"Connecting on {}", address}
let channel = Channel {executor, address, coffer: Arc::from(coffer)};
channel.listen();
}
fn _print_banner() {
println!{r#"
@@@@@@@ @@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@
@@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@
!@@ @@! @@@ @@! @@! @@! @@! @@@
!@! !@! @!@ !@! !@! !@! !@! @!@
!@! @!@ !@! @!!!:! @!!!:! @!!!:! @!@!!@!
!!! !@! !!! !!!!!: !!!!!: !!!!!: !!@!@!
:!! !!: !!! !!: !!: !!: !!: :!!
:!: :!: !:! :!: :!: :!: :!: !:!
::: ::: ::::: :: :: :: :: :::: :: :::
:: :: : : : : : : : :: :: : : :
"#}
}

View file

@ -1,33 +0,0 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use serde::{Serialize, Deserialize};
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
use sodiumoxide::crypto::box_;
use std::error::Error;
#[derive(Debug,Serialize,Deserialize)]
pub enum Key {
MasterKey {
id: String,
public_key: box_::PublicKey,
secret_key: box_::SecretKey
},
ClientKey {
id: String,
public_key: box_::PublicKey
}
}
pub fn parse_from_path(path: &PathBuf, keep: bool) -> Result<Key, Box<dyn Error>> {
let mut mk_file = File::open(path)?;
let mut mk_data = Vec::new();
mk_file.read_to_end(&mut mk_data)?;
if !keep { std::fs::remove_file(path)?; };
Ok(serde_cbor::from_slice::<Key>(&mk_data)?)
}

View file

@ -1,77 +0,0 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use env_logger;
use std::convert::TryInto;
use std::error::Error;
use futures::executor::ThreadPool;
use std::path::PathBuf;
use structopt::StructOpt;
use std::net::IpAddr;
use std::net::SocketAddr;
mod comm;
mod keyring;
mod secrets;
use comm::Channel;
#[derive(StructOpt, Debug)]
struct Args {
/// Path to the master key file. Will be deleted after processing.
#[structopt(short, long, parse(from_os_str), env = "SECSRV_MASTER", hide_env_values = true)]
master: PathBuf,
/// Path to the secret keys file. Will be deleted after processing.
#[structopt(long, parse(from_os_str), env = "SECSRV_KEYS", hide_env_values = true)]
keys: PathBuf,
/// The port secsrv is listening on
#[structopt(short, long, env = "SECSRV_PORT", default_value = "9187")]
port: u16,
/// The address secsrv binds to
#[structopt(short, long, env = "SECSRV_IP", default_value = "127.0.0.1")]
ip: IpAddr,
/// Prevent deletion of key files
#[structopt(short)]
keep_keys: bool
}
fn main() -> Result<(), Box<dyn Error>>{
env_logger::init();
let args = Args::from_args();
_print_banner();
debug!{"Parsing master key from {}", args.master.display()}
let _master_key = keyring::parse_from_path(&args.master, args.keep_keys)?;
debug!{"Parsing secrets from {}", args.keys.display()}
let secrets = secrets::parse_from_path(&args.keys, args.keep_keys)?;
info!{"Setting up the connection pool"}
let executor = ThreadPool::new()?;
let address: SocketAddr = (args.ip, args.port).try_into()?;
debug!{"Connecting on {}", address}
let channel = Channel {executor, address};
channel.listen(secrets.into());
Ok(())
}
fn _print_banner() {
info!{r#"
___ ___ ___ ___ ___ _ ____ __
/ __|/ _ \/ __/ __|/ _ \ '__\ \ / /
\__ \ __/ (__\__ \ __/ | \ V /
|___/\___|\___|___/\___|_| \_/
"#}
}

View file

@ -1,20 +0,0 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::collections::HashMap;
use std::error::Error;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
pub type Secrets = HashMap<String, String>;
pub fn parse_from_path(path: &PathBuf, keep: bool) -> Result<Secrets, Box<dyn Error>> {
let mut sec_file = File::open(path)?;
let mut sec_data = Vec::new();
sec_file.read_to_end(&mut sec_data)?;
if !keep { std::fs::remove_file(path)?; };
Ok(serde_cbor::from_slice::<Secrets>(&sec_data)?)
}