New structure
- [server] Reworked for new Coffer trait, common keyring implementation and tokio - [companion] Certificate generation - [common] Keyring implementation Signed-off-by: Armin Friedl <dev@friedl.net>
This commit is contained in:
parent
86212f244f
commit
076447cce7
20 changed files with 348 additions and 297 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
/target
|
||||
**target/
|
||||
**/*.rs.bk
|
||||
*.cbor
|
||||
*.yaml
|
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -103,13 +103,16 @@ dependencies = [
|
|||
"seckey 0.9.1 (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_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coffer-companion"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"coffer-common 0.1.0",
|
||||
"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)",
|
||||
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -127,13 +130,14 @@ dependencies = [
|
|||
"coffer-common 0.1.0",
|
||||
"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)",
|
||||
"lazy_static 1.4.0 (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)",
|
||||
"tokio 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -354,6 +358,11 @@ dependencies = [
|
|||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
|
@ -596,6 +605,11 @@ name = "rle-decode-fast"
|
|||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "seckey"
|
||||
version = "0.9.1"
|
||||
|
@ -632,6 +646,16 @@ dependencies = [
|
|||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.11"
|
||||
|
@ -756,7 +780,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "0.2.6"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -773,19 +797,27 @@ dependencies = [
|
|||
"pin-project-lite 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-macros 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-macros 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (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"
|
||||
|
@ -926,6 +958,7 @@ dependencies = [
|
|||
"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120"
|
||||
"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
|
||||
|
@ -956,10 +989,12 @@ dependencies = [
|
|||
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
|
||||
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
|
||||
"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum seckey 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c819d0a699db7622e4ee55a651f992242f754481f97de3024dc548adcce13237"
|
||||
"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0"
|
||||
"checksum serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7081ed758ec726a6ed8ee7e92f5d3f6e6f8c3901b1f972e3a4a2f2599fad14f"
|
||||
"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8"
|
||||
"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
|
||||
"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
|
||||
"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
@ -974,8 +1009,9 @@ 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 tokio 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1bef565a52394086ecac0a6fa3b8ace4cb3a138ee1d96bd2b93283b56824e3"
|
||||
"checksum tokio-macros 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7de6c21a09bab0ce34614bb1071403ad9996db62715eb61e63be5d82f91342bc"
|
||||
"checksum tokio 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "a9d5acfe1b1130d50ac2286a2f1f8cf49309680366ceb7609ce369b75c9058d4"
|
||||
"checksum tokio-macros 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "50a61f268a3db2acee8dcab514efc813dc6dbe8a00e86076f935f94304b59a7a"
|
||||
"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"
|
||||
|
|
|
@ -12,6 +12,8 @@ log = "^0.4"
|
|||
env_logger = "^0.7"
|
||||
serde = { version = "^1.0", features = ["derive"]}
|
||||
serde_cbor = "^0.10"
|
||||
serde_json = "^1.0"
|
||||
toml = "^0.5"
|
||||
quick-error = "^1.2"
|
||||
# Key management/Cryptography
|
||||
sodiumoxide = "^0.2"
|
||||
|
|
|
@ -40,6 +40,9 @@ pub struct Certificate {
|
|||
inner: SecKey<CertificateInner>
|
||||
}
|
||||
|
||||
unsafe impl Send for Certificate {}
|
||||
unsafe impl Sync for Certificate {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct CertificateInner {
|
||||
public_key: box_::PublicKey,
|
||||
|
@ -73,21 +76,19 @@ impl Certificate {
|
|||
Ok(Certificate{inner})
|
||||
}
|
||||
|
||||
pub fn to_cbor(&self) -> Result<Vec<u8>, CertificateError> {
|
||||
let inner_cert = &*self.inner.read();
|
||||
let cbor = serde_cbor::to_vec(inner_cert)?;
|
||||
Ok(cbor)
|
||||
}
|
||||
|
||||
pub fn open(&self, c: &[u8]) -> Result<Vec<u8>, CertificateError> {
|
||||
let pk = &self.inner.read().public_key;
|
||||
let sk = &self.inner.read().private_key;
|
||||
|
||||
debug!{"Opening sealed box"};
|
||||
sealedbox::open(c, pk, sk)
|
||||
.map_err(|_| CertificateError::Crypto)
|
||||
}
|
||||
|
||||
fn seal(&self, m: &[u8]) -> Vec<u8> {
|
||||
let pk = &self.inner.read().public_key;
|
||||
|
||||
debug!{"Sealing box"}
|
||||
sealedbox::seal(m, pk)
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: AsRef<Path>> From<T> for Certificate {
|
||||
|
|
|
@ -8,13 +8,20 @@ use quick_error::quick_error;
|
|||
quick_error! {
|
||||
#[derive(Debug)]
|
||||
pub enum CofferError {
|
||||
Coffer
|
||||
Msg(err: &'static str) {
|
||||
from(err)
|
||||
display("{}", err)
|
||||
}
|
||||
Other(err: Box<dyn std::error::Error>) {
|
||||
cause(&**err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type CofferResult<T> = Result<T, CofferError>;
|
||||
|
||||
/// Values supported by a `Coffer`
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CofferValue {
|
||||
/// A UTF-8 encoded string
|
||||
String(String),
|
||||
|
@ -25,22 +32,33 @@ pub enum CofferValue {
|
|||
}
|
||||
|
||||
/// A path to a value
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct CofferPath(Vec<String>);
|
||||
|
||||
/// Interface for interacting with a `Coffer`
|
||||
pub trait Coffer {
|
||||
/// Put `value` at `path`. Errors if there is already a value at `path`.
|
||||
fn put(path: CofferPath, value: CofferValue) -> CofferResult<()>;
|
||||
fn put(&mut self, path: CofferPath, value: CofferValue) -> CofferResult<()>;
|
||||
|
||||
/// Push `value` to `path`. Replaces existing values silently.
|
||||
fn push(path: CofferPath, value: CofferValue);
|
||||
fn push(&mut self, path: CofferPath, value: CofferValue);
|
||||
|
||||
/// Retrieve `value` at path. Errors if there is no `value` at path.
|
||||
fn get(path: CofferPath) -> CofferResult<CofferValue>;
|
||||
fn get(&self, path: CofferPath) -> CofferResult<CofferValue>;
|
||||
}
|
||||
|
||||
impl <T> From<&[T]> for CofferPath
|
||||
impl <T> From<Vec<T>> for CofferPath
|
||||
where T: AsRef<str>
|
||||
{
|
||||
fn from(val: &[T]) -> Self {
|
||||
fn from(val: Vec<T>) -> Self {
|
||||
CofferPath::from(&val)
|
||||
}
|
||||
}
|
||||
|
||||
impl <T> From<&Vec<T>> for CofferPath
|
||||
where T: AsRef<str>
|
||||
{
|
||||
fn from(val: &Vec<T>) -> Self {
|
||||
let col = val.iter().map(|p| {(*p).as_ref().to_owned()}).collect();
|
||||
CofferPath(col)
|
||||
}
|
||||
|
|
62
coffer-common/src/keyring.rs
Normal file
62
coffer-common/src/keyring.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use quick_error::quick_error;
|
||||
use sodiumoxide::crypto::box_;
|
||||
use sodiumoxide::crypto::sealedbox;
|
||||
|
||||
use crate::certificate::{Certificate, CertificateError};
|
||||
|
||||
quick_error! {
|
||||
#[derive(Debug)]
|
||||
pub enum KeyringError {
|
||||
UnkownClientKey
|
||||
InvalidClientKey
|
||||
Certificate(err: CertificateError) {
|
||||
from()
|
||||
}
|
||||
Msg(err: &'static str) {
|
||||
from(err)
|
||||
display("{}", err)
|
||||
}
|
||||
Other(err: Box<dyn std::error::Error>) {
|
||||
cause(&**err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Keyring {
|
||||
certificate: Certificate,
|
||||
known_keys: HashMap<Vec<u8>, box_::PublicKey>
|
||||
}
|
||||
|
||||
impl Keyring {
|
||||
pub fn new(certificate: Certificate) -> Keyring {
|
||||
Keyring {
|
||||
certificate: certificate,
|
||||
known_keys: HashMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_known_key(&mut self, key: &[u8]) -> Result<(), KeyringError> {
|
||||
let public_key = box_::PublicKey::from_slice(key)
|
||||
.ok_or(KeyringError::InvalidClientKey)?;
|
||||
|
||||
self.known_keys.insert(Vec::from(key), public_key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn open(&self, message: &[u8]) -> Result<Vec<u8>, KeyringError> {
|
||||
self.certificate.open(message)
|
||||
.map_err(|e| KeyringError::from(e))
|
||||
}
|
||||
|
||||
pub fn seal(&self, client: &[u8], message: &[u8]) -> Result<Vec<u8>, KeyringError> {
|
||||
let client_key = self.known_keys.get(client)
|
||||
.ok_or(KeyringError::UnkownClientKey)?;
|
||||
|
||||
Ok(sealedbox::seal(message, client_key))
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ use log::{debug, error, info, trace, warn};
|
|||
|
||||
pub mod certificate;
|
||||
pub mod coffer;
|
||||
pub mod keyring;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -18,3 +18,5 @@ sodiumoxide = "0.2.5"
|
|||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde_cbor = "0.10.2"
|
||||
serde_yaml = "0.8"
|
||||
|
||||
coffer-common = { path = "../coffer-common" }
|
|
@ -1,26 +0,0 @@
|
|||
use sodiumoxide::crypto::sealedbox;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::generate::MasterKey;
|
||||
|
||||
type Secrets = HashMap<String, String>;
|
||||
|
||||
pub fn generate_encrypted_secrets(yaml: PathBuf, out: PathBuf, masterkey: PathBuf) {
|
||||
let reader = File::open(&yaml)
|
||||
.expect(&format!{"Could not read file {}", masterkey.display()});
|
||||
|
||||
let secrets: Secrets = serde_yaml::from_reader(reader)
|
||||
.expect(&format!{"Could not deserialize secrets from {}", &yaml.display()});
|
||||
|
||||
let masterkey: MasterKey = (&masterkey).into();
|
||||
|
||||
let secrets_bin = serde_cbor::to_vec(&secrets).unwrap();
|
||||
let sealed_secrets_bin = sealedbox::seal(&secrets_bin, &masterkey.public_key);
|
||||
|
||||
File::create(&out)
|
||||
.and_then(|mut f| f.write(&sealed_secrets_bin))
|
||||
.expect(&format!{"Could not create out file {}", &out.display()});
|
||||
}
|
|
@ -1,33 +1,17 @@
|
|||
use sodiumoxide::crypto::box_;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use coffer_common::certificate::Certificate;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::fs::File;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct MasterKey {
|
||||
pub public_key: box_::PublicKey,
|
||||
secret_key: box_::SecretKey,
|
||||
}
|
||||
use std::io::Write;
|
||||
|
||||
pub fn generate_key(out: PathBuf) {
|
||||
let keypair = box_::gen_keypair();
|
||||
let masterkey: MasterKey = MasterKey {
|
||||
public_key: keypair.0,
|
||||
secret_key: keypair.1,
|
||||
};
|
||||
let certificate = Certificate::new().unwrap();
|
||||
|
||||
let writer = File::create(&out)
|
||||
let cert = certificate.to_cbor().unwrap();
|
||||
|
||||
let mut writer = File::create(&out)
|
||||
.expect(&format!{"Could not create out file {}", &out.display()});
|
||||
|
||||
serde_cbor::to_writer(writer, &masterkey)
|
||||
.expect(&format!{"Couldn't deserialize to key file {}", &out.display()});
|
||||
}
|
||||
writer.write_all(&cert);
|
||||
|
||||
impl From<&PathBuf> for MasterKey {
|
||||
fn from(masterkey: &PathBuf) -> Self {
|
||||
let reader = File::open(masterkey)
|
||||
.expect(&format!{"Could not read file {}", masterkey.display()});
|
||||
|
||||
serde_cbor::from_reader(reader).unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,6 @@ fn main() {
|
|||
|
||||
match args {
|
||||
Args::Generate {out} => generate::generate_key(out),
|
||||
Args::Encrypt {yaml, out, masterkey} => encrypt::generate_encrypted_secrets(yaml, out, masterkey)
|
||||
Args::Encrypt {yaml, out, masterkey} => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,12 @@ log = "^0.4"
|
|||
env_logger = "^0.7"
|
||||
structopt = "^0.3"
|
||||
quick-error = "^1.2"
|
||||
lazy_static = "^1.4"
|
||||
|
||||
# Key management/Cryptography
|
||||
sodiumoxide = "^0.2"
|
||||
# Communication
|
||||
tokio = { version="^0.2", features = ["full"]}
|
||||
tokio = { version="^0.2.8", features = ["full"]}
|
||||
serde = { version = "^1.0", features = ["derive"]}
|
||||
serde_cbor = "^0.10.2"
|
||||
futures = { version = "0.3.1", features = ["thread-pool"]}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use coffer_common::certificate::Certificate;
|
||||
|
||||
pub struct Coffer {
|
||||
certificate: Certificate,
|
||||
}
|
||||
|
||||
impl Coffer {
|
||||
/// Create a new, empty `Coffer` with a generated certificate
|
||||
pub fn new() -> Coffer {
|
||||
Coffer {certificate: Certificate::new()}
|
||||
}
|
||||
|
||||
/// Create a new `Coffer` with certificate
|
||||
pub fn new_with_certificate (certificate: Certificate) {
|
||||
Coffer {certificate.into()}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
#[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) -> Result<Keyring, KeyringError> {
|
||||
let keyring = Keyring {
|
||||
master: key_from_path(path)?,
|
||||
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)?;
|
||||
self.clients.insert(client_key.id.clone(), client_key);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn key_from_path<T>(path: &PathBuf) -> Result<T, KeyringError>
|
||||
where T: serde::de::DeserializeOwned
|
||||
{
|
||||
|
||||
let mk_file = File::open(path)?;
|
||||
let key = serde_cbor::from_reader(mk_file)?;
|
||||
|
||||
Ok(key)
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
#[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
|
||||
|
52
coffer-server/src/coffer_map.rs
Normal file
52
coffer-server/src/coffer_map.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
//! A simple, thread-safe coffer implementation backed by a hash map
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::sync::RwLock;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use coffer_common::coffer::*;
|
||||
|
||||
pub struct CofferMap {
|
||||
coffer: RwLock<HashMap<CofferPath, CofferValue>>
|
||||
}
|
||||
|
||||
impl CofferMap {
|
||||
pub fn new() -> CofferMap {
|
||||
CofferMap {
|
||||
coffer: RwLock::new(HashMap::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Coffer for CofferMap {
|
||||
fn put(&mut self, path: CofferPath, value: CofferValue) -> CofferResult<()> {
|
||||
let mut lock = self.coffer.write().unwrap();
|
||||
|
||||
match (*lock).contains_key(&path) {
|
||||
true => Err(CofferError::Msg("test")),
|
||||
false => {(*lock).insert(path, value); Ok(())}
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, path: CofferPath, value: CofferValue) {
|
||||
let mut lock = self.coffer.write().unwrap();
|
||||
|
||||
(*lock).insert(path, value);
|
||||
}
|
||||
|
||||
fn get(&self, path: CofferPath) -> CofferResult<CofferValue> {
|
||||
let lock = self.coffer.read().unwrap();
|
||||
|
||||
(*lock).get(&path)
|
||||
.and_then(|v| Some(v.clone()))
|
||||
.ok_or(CofferError::Msg("Key not found"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CofferMap {
|
||||
fn default() -> Self {
|
||||
CofferMap::new()
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::net::{TcpListener, SocketAddr, TcpStream};
|
||||
use std::sync::Arc;
|
||||
use std::io::{Write};
|
||||
use std::io::Read;
|
||||
use futures::executor::ThreadPool;
|
||||
|
||||
use crate::coffer::Coffer;
|
||||
|
||||
pub struct Channel {
|
||||
pub executor: ThreadPool,
|
||||
pub address: SocketAddr,
|
||||
pub coffer: Arc<Coffer>
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
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, self.coffer.clone())),
|
||||
Err(e) => error!{"Failed binding incoming connection {}", e}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn handler(mut stream: TcpStream, coffer: Arc<Coffer>) {
|
||||
let mut peek_buf = [0x00; 1];
|
||||
|
||||
while stream.peek(&mut peek_buf).unwrap() != 0 {
|
||||
let mut len_buffer = [0x00; std::mem::size_of::<usize>()];
|
||||
stream.read_exact(&mut len_buffer);
|
||||
let len = usize::from_be_bytes(len_buffer) as u64;
|
||||
debug!{"Length {}", len}
|
||||
|
||||
let mut buf: Vec<u8> = Vec::with_capacity(len as usize);
|
||||
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 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}
|
||||
} else {
|
||||
writeln!(stream, "")
|
||||
.unwrap_or_else(|err| {error!{"Could not write key response to stream {}", err}})
|
||||
}
|
||||
},
|
||||
Err(e) => error!{"Could not parse secret request: {}", e}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -3,20 +3,18 @@ use log::{debug, error, info, trace, warn};
|
|||
|
||||
use env_logger;
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::path::PathBuf;
|
||||
use structopt::StructOpt;
|
||||
use std::net::IpAddr;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::prelude::*;
|
||||
use coffer_common::certificate::Certificate;
|
||||
use coffer_common::keyring::Keyring;
|
||||
|
||||
mod coffer;
|
||||
mod server;
|
||||
mod comm;
|
||||
mod coffer_map;
|
||||
|
||||
use comm::Channel;
|
||||
use server::ServerBuilder;
|
||||
use coffer_map::CofferMap;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
struct Args {
|
||||
|
@ -29,13 +27,9 @@ struct Args {
|
|||
#[structopt(short, long, parse(from_os_str), env = "COFFER_SERVER_SECRETS", hide_env_values = true)]
|
||||
secrets: Option<PathBuf>,
|
||||
|
||||
/// Port the coffer server listens on
|
||||
#[structopt(short, long, env = "COFFER_SERVER_PORT", default_value = "9187")]
|
||||
port: u16,
|
||||
|
||||
/// Address coffer server should bind to
|
||||
/// Address the coffer server should bind to
|
||||
#[structopt(short, long, parse(try_from_str), env = "COFFER_SERVER_ADDRESS", default_value = "127.0.0.1:9187")]
|
||||
ip: SocketAddr,
|
||||
address: SocketAddr,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
|
@ -45,9 +39,13 @@ async fn main() {
|
|||
|
||||
_print_banner();
|
||||
|
||||
info!{"Filling coffer"}
|
||||
let coffer = coffer::Coffer::new_from_path_encrypted(&args.master, &args.secrets)
|
||||
.expect("Could not fill coffer");
|
||||
let server = ServerBuilder::new()
|
||||
.with_keyring(args.certificate.and_then(|cert_path| Some(Keyring::new(Certificate::from(cert_path)))))
|
||||
.with_coffer(Some(CofferMap::new()))
|
||||
.build()
|
||||
.expect("Couldn't build server");
|
||||
|
||||
server.run(args.address).await;
|
||||
}
|
||||
|
||||
fn _print_banner() {
|
||||
|
|
127
coffer-server/src/server.rs
Normal file
127
coffer-server/src/server.rs
Normal file
|
@ -0,0 +1,127 @@
|
|||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use quick_error::quick_error;
|
||||
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::net::{ToSocketAddrs, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
|
||||
use coffer_common::keyring::Keyring;
|
||||
use coffer_common::coffer::Coffer;
|
||||
use coffer_common::certificate::{Certificate, CertificateError};
|
||||
|
||||
quick_error! {
|
||||
#[derive(Debug)]
|
||||
pub enum ServerError {
|
||||
Cert(err: CertificateError) {
|
||||
from()
|
||||
}
|
||||
Msg(err: &'static str) {
|
||||
from(err)
|
||||
display("{}", err)
|
||||
}
|
||||
Other(err: Box<dyn std::error::Error>) {
|
||||
cause(&**err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Server<C>
|
||||
where C: Coffer
|
||||
{
|
||||
keyring: Arc<RwLock<Keyring>>,
|
||||
coffer: Arc<RwLock<C>>
|
||||
}
|
||||
|
||||
impl <C> Server<C>
|
||||
where C: Coffer + Send + Sync + 'static
|
||||
{
|
||||
pub async fn run<T>(self, addr: T)
|
||||
where T: ToSocketAddrs
|
||||
{
|
||||
debug!{"Building socket"}
|
||||
let socket: SocketAddr = addr
|
||||
.to_socket_addrs()
|
||||
.expect("Could not convert to socket")
|
||||
.next()
|
||||
.expect("No socket could be built");
|
||||
|
||||
debug!{"Binding to socket {:?}", socket}
|
||||
let mut listener = TcpListener::bind(socket).await
|
||||
.expect(format!{"Could not bind to socket {}", socket}.as_str());
|
||||
|
||||
let server = async move {
|
||||
let mut incoming = listener.incoming();
|
||||
|
||||
debug!{"Starting connection loop"}
|
||||
while let Some(connection) = incoming.next().await {
|
||||
debug!{"New incoming connection"}
|
||||
match connection {
|
||||
Ok(mut tcp_stream) => {
|
||||
debug!{"Connection ok"}
|
||||
debug!{"Spawning off connection handler"}
|
||||
|
||||
let keyring = self.keyring.clone();
|
||||
let coffer = self.coffer.clone();
|
||||
tokio::spawn(Self::handle_connection(keyring, coffer, tcp_stream));
|
||||
}
|
||||
Err(err) => error!{"Connection could not be established {}", err}
|
||||
}
|
||||
debug!{"Waiting for new connections"}
|
||||
}
|
||||
};
|
||||
|
||||
server.await
|
||||
}
|
||||
|
||||
async fn handle_connection(keyring: Arc<RwLock<Keyring>>,
|
||||
coffer: Arc<RwLock<C>>,
|
||||
mut tcp_stream: TcpStream)
|
||||
{
|
||||
let (reader, mut writer) = tcp_stream.split();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ServerBuilder<C>
|
||||
where C: Coffer
|
||||
{
|
||||
keyring: Option<Keyring>,
|
||||
coffer: Option<C>
|
||||
}
|
||||
|
||||
impl <'a, C> ServerBuilder<C>
|
||||
where C: Coffer + Default
|
||||
{
|
||||
pub fn new() -> ServerBuilder<C> {
|
||||
ServerBuilder {
|
||||
keyring: None,
|
||||
coffer: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_keyring(mut self, keyring: Option<Keyring>) -> ServerBuilder<C> {
|
||||
self.keyring = keyring;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_coffer(mut self, coffer: Option<C>) -> ServerBuilder<C> {
|
||||
self.coffer = coffer;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<Server<C>, ServerError> {
|
||||
let keyring = match self.keyring {
|
||||
Some(k) => Arc::new(RwLock::new(k)),
|
||||
None => {let cert = Certificate::new()?;
|
||||
Arc::new(RwLock::new(Keyring::new(cert)))}
|
||||
};
|
||||
|
||||
let coffer = Arc::new(RwLock::new(self.coffer.unwrap_or_else(|| { C::default() } )));
|
||||
|
||||
Ok(Server {keyring, coffer})
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
//! Public APIs for `coffer-server`
|
||||
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
use tokio::prelude::*;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
async fn run_server<T: ToSocketAddrs>(sock_addrs: T) {
|
||||
let addr = sock_addrs.to_socket_addrs().unwrap().next().unwrap();
|
||||
let listener = TcpListener::bind(addr);
|
||||
}
|
Loading…
Reference in a new issue