[server] Allow nested clients

Tables can be nested arbitrary, only tables with `id` attribute
are considered
This commit is contained in:
Armin Friedl 2020-02-02 05:40:07 +01:00
parent 9ae5a72fce
commit 90142ec5c1
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8
11 changed files with 94 additions and 57 deletions

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
*.enc filter=lfs diff=lfs merge=lfs -text
*.cert filter=lfs diff=lfs merge=lfs -text

View file

@ -75,7 +75,7 @@ fn main() -> Result<(), Box<dyn Error>> {
Err("Could not spawn sub-command".into()) Err("Could not spawn sub-command".into())
} }
fn reap_coffer(cmd: &str, args: &Vec<String>) { fn reap_coffer(cmd: &str, args: &[String]) {
let mut cmd = exec::Command::new(cmd); let mut cmd = exec::Command::new(cmd);
// TODO Push cmd as first arg if not already set? // TODO Push cmd as first arg if not already set?

View file

@ -2,6 +2,7 @@
#[allow(unused_imports)] #[allow(unused_imports)]
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use std::fmt::Debug;
use std::path::Path; use std::path::Path;
use std::fs::File; use std::fs::File;
use std::io::{BufReader, Read}; use std::io::{BufReader, Read};
@ -87,51 +88,51 @@ pub trait Coffer {
_ => panic!{"Invalid secrets file"} _ => panic!{"Invalid secrets file"}
}; };
/* coffer.from_toml_table(&clients);
* Walk through the table of clients, where each client is a table which
* is either empty, or contains a table with at least an id and any
* number of secrets
*
* # Example:
*
* files.id = "AAAA-BBBB-CCCC"
* pad.id = "FFFF-EEEE-DDDD"
*
* [files]
* secret_string = "secret value1"
* secret_int = 12345
* secret_bool = true
*/
for (_k, v) in clients {
let client = match v { coffer
TomlValue::Table(t) => t, }
_ => panic!{"Invalid secrets file"}
};
for (k, v) in client.iter() { fn from_toml_table(&mut self, toml_table: &toml::value::Table) {
// table has an no id, recourse into subtables
if "id" == k { continue } // ids are for sharding if toml_table.get("id").is_none() {
for (_key, val) in toml_table.iter() {
let value = match v { match val {
TomlValue::String(s) => CofferValue::String(s.to_owned()), TomlValue::Table(subtable) => {
TomlValue::Integer(i) => CofferValue::Integer(*i as i32), self.from_toml_table(subtable);
TomlValue::Float(f) => CofferValue::Float(*f as f32),
TomlValue::Boolean(b) => CofferValue::Boolean(*b),
_ => panic!{"Value {:?} unsupported", v}
};
match client.get("id") {
Some(TomlValue::String(shard)) => {
let shard = shard.to_owned();
let key = k.to_owned();
coffer.put(CofferKey{shard, key}, value).unwrap();
}, },
_ => panic!{"Invalid secrets file"} _ => panic!{"Invalid secrets file"}
} }
} }
return;
} }
return coffer; /*
* Parse a single shard/table, this is known to have an id
*
* [files]
* id = "ABC-DEF-GHE"
* secret_string = "secret value1"
* secret_int = 12345
* secret_bool = true
*/
let shard = toml_table.get("id").and_then(|id| id.as_str()).unwrap();
for (key, val) in toml_table {
if "id" == key { continue } // ids are for sharding
let value = match val {
TomlValue::String(s) => CofferValue::String(s.to_owned()),
TomlValue::Integer(i) => CofferValue::Integer(*i as i32),
TomlValue::Float(f) => CofferValue::Float(*f as f32),
TomlValue::Boolean(b) => CofferValue::Boolean(*b),
_ => panic!{"Value {:?} unsupported", val}
};
let key = key.to_owned();
let shard = shard.to_string();
self.put(CofferKey{shard, key}, value).unwrap();
}
} }
} }

View file

@ -65,25 +65,33 @@ impl Keyring {
_ => panic!{"Invalid secrets file"} _ => panic!{"Invalid secrets file"}
}; };
for (_k, v) in clients { self.add_known_keys_toml_table(&clients)?;
let client = match v { debug!{"Known keys {:?}", self.known_keys}
TomlValue::Table(client) => client,
_ => panic!{"Invalid secrets file"}
};
match client.get("id") {
Some(TomlValue::String(id)) => {
let id = id.to_owned();
self.add_known_key(&hex::decode(id)?)?;
},
_ => panic!{"Invalid id, only hex encoded ids supported"}
}
}
Ok(()) Ok(())
} }
fn add_known_keys_toml_table(&mut self, toml_table: &toml::value::Table) -> Result<(), KeyringError> {
// table has an no id, recourse into subtables
if toml_table.get("id").is_none() {
debug!{"{:?}", toml_table}
for (_key, val) in toml_table.iter() {
match val {
TomlValue::Table(subtable) => {
self.add_known_keys_toml_table(subtable)?;
},
_ => panic!{"Invalid secrets file"}
}
}
return Ok(());
}
let shard = toml_table.get("id").and_then(|id| id.as_str()).ok_or(KeyringError::Msg("Invalid key parsing state"))?;
self.add_known_key(&hex::decode(shard)?)
}
pub fn add_known_key(&mut self, key: &[u8]) -> Result<(), KeyringError> { pub fn add_known_key(&mut self, key: &[u8]) -> Result<(), KeyringError> {
let public_key = box_::PublicKey::from_slice(key) let public_key = box_::PublicKey::from_slice(key)
.ok_or(KeyringError::InvalidClientKey)?; .ok_or(KeyringError::InvalidClientKey)?;
@ -94,7 +102,7 @@ impl Keyring {
pub fn open(&self, message: &[u8]) -> Result<Vec<u8>, KeyringError> { pub fn open(&self, message: &[u8]) -> Result<Vec<u8>, KeyringError> {
self.certificate.open(message) self.certificate.open(message)
.map_err(|e| KeyringError::from(e)) .map_err(KeyringError::from)
} }
pub fn seal(&self, client: &[u8], message: &[u8]) -> Result<Vec<u8>, KeyringError> { pub fn seal(&self, client: &[u8], message: &[u8]) -> Result<Vec<u8>, KeyringError> {

BIN
testcoffer/client.cert (Stored with Git LFS)

Binary file not shown.

BIN
testcoffer/client1.cert (Stored with Git LFS) Normal file

Binary file not shown.

BIN
testcoffer/client2.cert (Stored with Git LFS) Normal file

Binary file not shown.

BIN
testcoffer/coffer.enc (Stored with Git LFS)

Binary file not shown.

View file

@ -2,3 +2,14 @@
id = "F11C86D52A70977D866F813903BC73DB4CB8AC40249DF668475B1BFE48AD1E41" id = "F11C86D52A70977D866F813903BC73DB4CB8AC40249DF668475B1BFE48AD1E41"
key1 = "secret1" key1 = "secret1"
key2 = "secret2" key2 = "secret2"
[clients]
[client.1]
id = "00E4A58C6905C2932F73F4D3AB449507E0166E53ED52F769721618F8C836E736"
client1key1 = "client1secret"
client1key2 = "client1secret2"
[client.2]
id = "D4A39CD8C4695A70F758252E9D877ACE24BD3DE98BC09E90C37C06F99061CD5B"
client2key1 = "client2secret"
client2key2 = "client2secret2"

BIN
testcoffer/no_keys_client.cert (Stored with Git LFS) Normal file

Binary file not shown.

BIN
testcoffer/server.cert (Stored with Git LFS)

Binary file not shown.