use crate::crypto::key::{AbstractKey, Key, Nonce};
use crate::crypto::secret::Secret;
use crate::crypto::wrap::WrappedKey;
use crate::error::*;
use data_encoding;
use once_cell::sync::Lazy;
use rmp_serde;
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::{Read, Write};
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use tracing::{debug, error};
static AUTH_TOKEN_CONTENTS: Lazy<Secret> = Lazy::new(|| {
let data: Vec<u8> = "3c017f717b39247c351154a41d2850e4187284da4b928f13c723d54440ba2dfe"
.bytes()
.collect();
let mut secret = Secret::with_len(data.len()).unwrap();
unsafe { secret.as_mut_slice() }.copy_from_slice(data.as_slice());
secret
});
fn is_master_key<K: AbstractKey>(key: &K, nonce: Option<&Nonce>, token: &[u8]) -> bool {
let decrypted = match key.decrypt(nonce, token) {
Err(_) => return false,
Ok(d) => d,
};
unsafe { decrypted.as_slice() == AUTH_TOKEN_CONTENTS.as_slice() }
}
#[derive(Deserialize, Serialize)]
pub struct KeyStore {
#[serde(skip_serializing, skip_deserializing)]
master_key: Option<Key>,
token_nonce: Option<Nonce>,
token: Vec<u8>,
wrapped_keys: Vec<WrappedKey>,
}
impl KeyStore {
pub fn new() -> Result<Self> {
let master_key = Key::new_random()?;
let (nonce, ciphertext) = master_key.encrypt(&AUTH_TOKEN_CONTENTS, None)?;
Ok(KeyStore {
master_key: Some(master_key),
token_nonce: nonce,
token: ciphertext,
wrapped_keys: Vec::new(),
})
}
pub fn load_slice(data: &[u8]) -> Result<Self> {
Ok(rmp_serde::from_slice(data)?)
}
pub fn load_read<R: Read>(rd: R) -> Result<Self> {
Ok(rmp_serde::from_read(rd)?)
}
pub fn get_id(&self) -> String {
data_encoding::HEXLOWER.encode(&self.token)
}
pub fn is_open(&self) -> bool {
self.master_key.is_some()
}
pub fn is_persistable(&self) -> bool {
!self.wrapped_keys.is_empty()
}
pub fn open<K: AbstractKey>(&mut self, key: &K) -> Result<()> {
if self.master_key.is_some() {
return Ok(());
}
let mut master_key: Option<Key> = None;
for wrapped_key in self.wrapped_keys.iter() {
match wrapped_key.unwrap(key) {
Ok(k) => {
if is_master_key(&k, self.token_nonce.as_ref(), self.token.as_slice()) {
master_key = Some(k);
break;
} else {
debug!(
"unwrapped key {:?}, but unwrapped key doesn't match our expected master key",
wrapped_key.get_digest()
);
}
}
Err(e) => debug!(
"failed to unwrap key {:?}: {:?}",
wrapped_key.get_digest(),
e
),
}
}
if master_key.is_none() {
return Err(Error::InvalidArgument(format!(
"KeyStore unlocking failed: the given key is not present in this KeyStore"
)));
}
self.master_key = master_key;
Ok(())
}
pub fn to_vec(&self) -> Result<Vec<u8>> {
Ok(rmp_serde::to_vec(self)?)
}
pub fn get_master_key(&self) -> Result<&Key> {
if let Some(k) = self.master_key.as_ref() {
return Ok(k);
}
Err(Error::Precondition(format!(
"KeyStore must be opened before you can access the master key"
)))
}
pub fn add_key<K: AbstractKey>(&mut self, key: &K) -> Result<bool> {
let wrapped_key = match self.master_key.as_ref() {
None => {
return Err(Error::Precondition(format!(
"KeyStore must be `new` or opened to add keys"
)));
}
Some(mk) => WrappedKey::wrap( mk, key)?,
};
if self
.wrapped_keys
.iter()
.filter(|k| k.get_wrapping_digest() == wrapped_key.get_wrapping_digest())
.next()
.is_some()
{
return Ok(false);
}
self.wrapped_keys.push(wrapped_key);
Ok(true)
}
pub fn remove_key<K: AbstractKey>(&mut self, key: &K) -> Result<bool> {
if self.wrapped_keys.len() == 1 {
if let Some(wrapped_key) = self.wrapped_keys.first() {
if *wrapped_key.get_wrapping_digest() == key.get_digest() {
return Err(Error::Precondition(format!(
"refusing to remove all valid keys from this KeyStore"
)));
}
}
}
let original_length = self.wrapped_keys.len();
let wrapped_keys = self
.wrapped_keys
.drain(..)
.filter(|k| *k.get_wrapping_digest() != key.get_digest())
.collect();
self.wrapped_keys = wrapped_keys;
Ok(original_length != self.wrapped_keys.len())
}
pub fn iter_wrapped_keys(&self) -> impl Iterator<Item = &WrappedKey> {
self.wrapped_keys.iter()
}
}
fn persist_key_store<P: AsRef<Path>>(path: P, keystore: &KeyStore) -> Result<()> {
if !keystore.is_persistable() {
return Err(Error::Precondition(format!(
"KeyStore with no wrapping keys cannot be persisted"
)));
}
let mut f = fs::File::create(path.as_ref())?;
let data = keystore.to_vec()?;
f.write_all(data.as_slice())?;
Ok(())
}
pub struct DiskKeyStore {
path: PathBuf,
inner: KeyStore,
}
impl DiskKeyStore {
pub fn new<P: AsRef<Path>>(path: P, force_overwrite: bool) -> Result<Self> {
let mut f = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(force_overwrite)
.open(path.as_ref())?;
Ok(DiskKeyStore {
path: path.as_ref().to_path_buf(),
inner: if f.metadata()?.len() == 0 {
fs::remove_file(path.as_ref())?;
KeyStore::new()?
} else {
KeyStore::load_read(&mut f)?
},
})
}
}
impl Deref for DiskKeyStore {
type Target = KeyStore;
fn deref(&self) -> &KeyStore {
&self.inner
}
}
impl DerefMut for DiskKeyStore {
fn deref_mut(&mut self) -> &mut KeyStore {
&mut self.inner
}
}
impl Drop for DiskKeyStore {
fn drop(&mut self) {
if let Err(e) = persist_key_store(&self.path, &self.inner) {
error!("{} (KeyStore {})", e, self.inner.get_id());
}
}
}