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:
Armin Friedl 2020-01-08 23:03:49 +01:00
parent 86212f244f
commit 076447cce7
20 changed files with 348 additions and 297 deletions

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
/target **target/
**/*.rs.bk **/*.rs.bk
*.cbor *.cbor
*.yaml *.yaml

48
Cargo.lock generated
View file

@ -103,13 +103,16 @@ dependencies = [
"seckey 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "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 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_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)", "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]] [[package]]
name = "coffer-companion" name = "coffer-companion"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"coffer-common 0.1.0",
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -127,13 +130,14 @@ dependencies = [
"coffer-common 0.1.0", "coffer-common 0.1.0",
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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 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_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)", "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)", "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]] [[package]]
@ -354,6 +358,11 @@ dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "kernel32-sys" name = "kernel32-sys"
version = "0.2.2" version = "0.2.2"
@ -596,6 +605,11 @@ name = "rle-decode-fast"
version = "1.0.1" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "seckey" name = "seckey"
version = "0.9.1" version = "0.9.1"
@ -632,6 +646,16 @@ dependencies = [
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "serde_yaml" name = "serde_yaml"
version = "0.8.11" version = "0.8.11"
@ -756,7 +780,7 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "0.2.6" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "0.2.1" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.6.0" 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 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 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 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 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 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" "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 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 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 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 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 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_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_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 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 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" "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 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 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 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 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "a9d5acfe1b1130d50ac2286a2f1f8cf49309680366ceb7609ce369b75c9058d4"
"checksum tokio-macros 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7de6c21a09bab0ce34614bb1071403ad9996db62715eb61e63be5d82f91342bc" "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-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-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" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"

View file

@ -12,6 +12,8 @@ log = "^0.4"
env_logger = "^0.7" env_logger = "^0.7"
serde = { version = "^1.0", features = ["derive"]} serde = { version = "^1.0", features = ["derive"]}
serde_cbor = "^0.10" serde_cbor = "^0.10"
serde_json = "^1.0"
toml = "^0.5"
quick-error = "^1.2" quick-error = "^1.2"
# Key management/Cryptography # Key management/Cryptography
sodiumoxide = "^0.2" sodiumoxide = "^0.2"

View file

@ -40,6 +40,9 @@ pub struct Certificate {
inner: SecKey<CertificateInner> inner: SecKey<CertificateInner>
} }
unsafe impl Send for Certificate {}
unsafe impl Sync for Certificate {}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct CertificateInner { struct CertificateInner {
public_key: box_::PublicKey, public_key: box_::PublicKey,
@ -73,21 +76,19 @@ impl Certificate {
Ok(Certificate{inner}) 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> { pub fn open(&self, c: &[u8]) -> Result<Vec<u8>, CertificateError> {
let pk = &self.inner.read().public_key; let pk = &self.inner.read().public_key;
let sk = &self.inner.read().private_key; let sk = &self.inner.read().private_key;
debug!{"Opening sealed box"};
sealedbox::open(c, pk, sk) sealedbox::open(c, pk, sk)
.map_err(|_| CertificateError::Crypto) .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 { impl <T: AsRef<Path>> From<T> for Certificate {

View file

@ -8,13 +8,20 @@ use quick_error::quick_error;
quick_error! { quick_error! {
#[derive(Debug)] #[derive(Debug)]
pub enum CofferError { 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>; pub type CofferResult<T> = Result<T, CofferError>;
/// Values supported by a `Coffer` /// Values supported by a `Coffer`
#[derive(Clone, Debug)]
pub enum CofferValue { pub enum CofferValue {
/// A UTF-8 encoded string /// A UTF-8 encoded string
String(String), String(String),
@ -25,22 +32,33 @@ pub enum CofferValue {
} }
/// A path to a value /// A path to a value
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct CofferPath(Vec<String>); pub struct CofferPath(Vec<String>);
/// Interface for interacting with a `Coffer` /// Interface for interacting with a `Coffer`
pub trait Coffer { pub trait Coffer {
/// Put `value` at `path`. Errors if there is already a value at `path`. /// 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. /// 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. /// 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> 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(); let col = val.iter().map(|p| {(*p).as_ref().to_owned()}).collect();
CofferPath(col) CofferPath(col)
} }

View 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))
}
}

View file

@ -5,6 +5,7 @@ use log::{debug, error, info, trace, warn};
pub mod certificate; pub mod certificate;
pub mod coffer; pub mod coffer;
pub mod keyring;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View file

@ -18,3 +18,5 @@ sodiumoxide = "0.2.5"
serde = { version = "1.0", features = ["derive"]} serde = { version = "1.0", features = ["derive"]}
serde_cbor = "0.10.2" serde_cbor = "0.10.2"
serde_yaml = "0.8" serde_yaml = "0.8"
coffer-common = { path = "../coffer-common" }

View file

@ -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()});
}

View file

@ -1,33 +1,17 @@
use sodiumoxide::crypto::box_; use coffer_common::certificate::Certificate;
use serde::{Deserialize, Serialize};
use std::path::PathBuf; use std::path::PathBuf;
use std::fs::File; use std::fs::File;
use std::io::Write;
#[derive(Debug, Serialize, Deserialize)]
pub struct MasterKey {
pub public_key: box_::PublicKey,
secret_key: box_::SecretKey,
}
pub fn generate_key(out: PathBuf) { pub fn generate_key(out: PathBuf) {
let keypair = box_::gen_keypair(); let certificate = Certificate::new().unwrap();
let masterkey: MasterKey = MasterKey {
public_key: keypair.0,
secret_key: keypair.1,
};
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()}); .expect(&format!{"Could not create out file {}", &out.display()});
serde_cbor::to_writer(writer, &masterkey) writer.write_all(&cert);
.expect(&format!{"Couldn't deserialize to key file {}", &out.display()});
}
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()
}
} }

View file

@ -25,6 +25,6 @@ fn main() {
match args { match args {
Args::Generate {out} => generate::generate_key(out), Args::Generate {out} => generate::generate_key(out),
Args::Encrypt {yaml, out, masterkey} => encrypt::generate_encrypted_secrets(yaml, out, masterkey) Args::Encrypt {yaml, out, masterkey} => {}
} }
} }

View file

@ -10,10 +10,12 @@ log = "^0.4"
env_logger = "^0.7" env_logger = "^0.7"
structopt = "^0.3" structopt = "^0.3"
quick-error = "^1.2" quick-error = "^1.2"
lazy_static = "^1.4"
# Key management/Cryptography # Key management/Cryptography
sodiumoxide = "^0.2" sodiumoxide = "^0.2"
# Communication # Communication
tokio = { version="^0.2", features = ["full"]} tokio = { version="^0.2.8", features = ["full"]}
serde = { version = "^1.0", features = ["derive"]} serde = { version = "^1.0", features = ["derive"]}
serde_cbor = "^0.10.2" serde_cbor = "^0.10.2"
futures = { version = "0.3.1", features = ["thread-pool"]} futures = { version = "0.3.1", features = ["thread-pool"]}

View file

@ -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()}
}
}

View file

@ -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)
}

View file

@ -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

View 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()
}
}

View file

@ -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}
};
}
}

View file

@ -3,20 +3,18 @@ use log::{debug, error, info, trace, warn};
use env_logger; use env_logger;
use std::convert::TryInto;
use std::path::PathBuf; use std::path::PathBuf;
use structopt::StructOpt; use structopt::StructOpt;
use std::net::IpAddr;
use std::net::SocketAddr; 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 server;
mod comm; mod coffer_map;
use comm::Channel; use server::ServerBuilder;
use coffer_map::CofferMap;
#[derive(StructOpt, Debug)] #[derive(StructOpt, Debug)]
struct Args { struct Args {
@ -29,13 +27,9 @@ struct Args {
#[structopt(short, long, parse(from_os_str), env = "COFFER_SERVER_SECRETS", hide_env_values = true)] #[structopt(short, long, parse(from_os_str), env = "COFFER_SERVER_SECRETS", hide_env_values = true)]
secrets: Option<PathBuf>, secrets: Option<PathBuf>,
/// Port the coffer server listens on /// Address the coffer server should bind to
#[structopt(short, long, env = "COFFER_SERVER_PORT", default_value = "9187")]
port: u16,
/// Address coffer server should bind to
#[structopt(short, long, parse(try_from_str), env = "COFFER_SERVER_ADDRESS", default_value = "127.0.0.1:9187")] #[structopt(short, long, parse(try_from_str), env = "COFFER_SERVER_ADDRESS", default_value = "127.0.0.1:9187")]
ip: SocketAddr, address: SocketAddr,
} }
#[tokio::main] #[tokio::main]
@ -45,9 +39,13 @@ async fn main() {
_print_banner(); _print_banner();
info!{"Filling coffer"} let server = ServerBuilder::new()
let coffer = coffer::Coffer::new_from_path_encrypted(&args.master, &args.secrets) .with_keyring(args.certificate.and_then(|cert_path| Some(Keyring::new(Certificate::from(cert_path)))))
.expect("Could not fill coffer"); .with_coffer(Some(CofferMap::new()))
.build()
.expect("Couldn't build server");
server.run(args.address).await;
} }
fn _print_banner() { fn _print_banner() {

127
coffer-server/src/server.rs Normal file
View 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})
}
}

View file

@ -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);
}