|
@@ -2,7 +2,11 @@
|
|
|
|
|
|
mod tpm;
|
|
|
|
|
|
-use crate::Decompose;
|
|
|
+use crate::{
|
|
|
+ Decompose,
|
|
|
+ SECTOR_SZ_DEFAULT,
|
|
|
+ SectoredBuf
|
|
|
+};
|
|
|
|
|
|
use super::{
|
|
|
Block,
|
|
@@ -17,7 +21,6 @@ use super::{
|
|
|
Owned,
|
|
|
Principal,
|
|
|
Path,
|
|
|
- HashMap,
|
|
|
Epoch,
|
|
|
io,
|
|
|
Read,
|
|
@@ -1167,7 +1170,7 @@ fn exp2(x: isize) -> usize {
|
|
|
}
|
|
|
|
|
|
/// Trait for types which can be used as nodes in a `MerkleTree`.
|
|
|
-trait MerkleNode: Default + Serialize + for<'de> Deserialize<'de> {
|
|
|
+pub trait MerkleNode: Default + Serialize + for<'de> Deserialize<'de> {
|
|
|
/// The kind of hash algorithm that this `HashData` uses.
|
|
|
const KIND: HashKind;
|
|
|
|
|
@@ -1364,7 +1367,7 @@ impl BinTreeIndex {
|
|
|
/// Each sector corresponds to an offset into the protected data, and in order to verify that a
|
|
|
/// sector has not been modified, you must supply the offset of the sector.
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
-struct MerkleTree<T> {
|
|
|
+pub struct MerkleTree<T> {
|
|
|
nodes: Vec<T>,
|
|
|
/// The size of the sectors of data that this tree will protect.
|
|
|
sector_sz: usize,
|
|
@@ -1776,35 +1779,17 @@ impl<T: Seek> Seek for SecretStream<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub(crate) fn encrypt_block<C: Encrypter + Decrypter>(
|
|
|
- mut block: Block, principal: &Principal, creds: &C
|
|
|
-) -> Result<Block> {
|
|
|
- let body = match block.body {
|
|
|
- Cryptotext::Cipher(_) => return Ok(block),
|
|
|
- Cryptotext::Plain(body) => body
|
|
|
- };
|
|
|
- let (principal_owned, read_cap) = block.readcaps.remove_entry(principal)
|
|
|
- .ok_or(Error::NoReadCap)?;
|
|
|
- let block_key = decrypt(read_cap, creds)?;
|
|
|
- let new_body = block_key.encrypt(&body)?;
|
|
|
- block.body = Cryptotext::Cipher(new_body);
|
|
|
- block.readcaps.insert(principal_owned, encrypt(&block_key, creds)?);
|
|
|
- Ok(block)
|
|
|
-}
|
|
|
-
|
|
|
-pub(crate) fn decrypt_block<C: Decrypter>(
|
|
|
- mut block: Block, principal: &Principal, creds: &C
|
|
|
-) -> Result<Block> {
|
|
|
- let body = match block.body {
|
|
|
- Cryptotext::Plain(_) => return Ok(block),
|
|
|
- Cryptotext::Cipher(body) => body
|
|
|
- };
|
|
|
- let (principal_owned, read_cap) = block.readcaps.remove_entry(principal)
|
|
|
+pub(crate) fn unveil<T: Read + Write + Seek, C: Encrypter + Decrypter>(
|
|
|
+ mut block: Block<T>, principal: &Principal, creds: &C
|
|
|
+) -> Result<Block<impl Read + Write + Seek>> {
|
|
|
+ let (principal_owned, read_cap) = block.header.readcaps.remove_entry(principal)
|
|
|
.ok_or(Error::NoReadCap)?;
|
|
|
let block_key = decrypt(read_cap, creds)?;
|
|
|
- let new_body = block_key.decrypt(&body)?;
|
|
|
- block.body = Cryptotext::Plain(new_body);
|
|
|
- block.readcaps.insert(principal_owned, Cryptotext::Plain(block_key));
|
|
|
+ let mut block = block
|
|
|
+ .compose_body(MerkleStream::new(MerkleTree::<Sha2_256>::empty(SECTOR_SZ_DEFAULT)))
|
|
|
+ .try_compose_body(SecretStream::new(block_key.clone()))?
|
|
|
+ .try_compose_body(SectoredBuf::new())?;
|
|
|
+ block.header.readcaps.insert(principal_owned, encrypt(&block_key, creds)?);
|
|
|
Ok(block)
|
|
|
}
|
|
|
|
|
@@ -1825,51 +1810,22 @@ fn decrypt<T: Serialize + DeserializeOwned, K: Decrypter>(
|
|
|
Ok(from_vec(&vec?)?)
|
|
|
}
|
|
|
|
|
|
-#[derive(Serialize)]
|
|
|
-struct HeaderSigInput<'a> {
|
|
|
- path: &'a Path,
|
|
|
- readcaps: &'a HashMap<Principal, Cryptotext<SymKey>>,
|
|
|
- writecap: &'a Writecap,
|
|
|
-}
|
|
|
-
|
|
|
-impl<'a> From<&'a Block> for HeaderSigInput<'a> {
|
|
|
- fn from(block: &'a Block) -> HeaderSigInput<'a> {
|
|
|
- HeaderSigInput {
|
|
|
- path: &block.path,
|
|
|
- readcaps: &block.readcaps,
|
|
|
- writecap: &block.writecap,
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-fn get_body(block: &Block) -> Result<&[u8]> {
|
|
|
- let body = match &block.body {
|
|
|
- Cryptotext::Cipher(body) => body,
|
|
|
- Cryptotext::Plain(_) => {
|
|
|
- return Err(Error::BlockNotEncrypted);
|
|
|
- }
|
|
|
- };
|
|
|
- Ok(body)
|
|
|
-}
|
|
|
-
|
|
|
-pub(crate) fn sign_block<K: Signer>(
|
|
|
- block: &mut Block, priv_key: &K
|
|
|
+pub(crate) fn sign_block<T, K: Signer>(
|
|
|
+ block: &mut Block<T>, priv_key: &K
|
|
|
) -> Result<()> {
|
|
|
- let body = get_body(block)?;
|
|
|
- let sig_input = HeaderSigInput::from(&*block);
|
|
|
- let header = to_vec(&sig_input)?;
|
|
|
- let signature = priv_key.sign([header.as_slice(), body].into_iter())?;
|
|
|
- block.signature = signature;
|
|
|
+ let header = to_vec(&block.header)?;
|
|
|
+ let signature = priv_key.sign(std::iter::once(header.as_slice()))?;
|
|
|
+ block.sig = signature;
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
-pub(crate) fn verify_block(block: &Block) -> Result<()> {
|
|
|
- verify_writecap(&block.writecap, &block.path)?;
|
|
|
- let body = get_body(block)?;
|
|
|
- let sig_input = HeaderSigInput::from(block);
|
|
|
- let header = to_vec(&sig_input)?;
|
|
|
- let parts = [header.as_slice(), body].into_iter();
|
|
|
- block.writecap.signing_key.verify(parts, block.signature.as_slice())
|
|
|
+pub(crate) fn verify_block<T>(block: &Block<T>) -> Result<()> {
|
|
|
+ verify_writecap(&block.header.writecap, &block.header.path)?;
|
|
|
+ let header_data = to_vec(&block.header)?;
|
|
|
+ block.header.writecap.signing_key.verify(
|
|
|
+ std::iter::once(header_data.as_slice()),
|
|
|
+ block.sig.as_slice()
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
#[derive(Serialize)]
|
|
@@ -1976,35 +1932,33 @@ mod tests {
|
|
|
time::Duration, io::{Cursor, SeekFrom},
|
|
|
};
|
|
|
|
|
|
- fn encrypt_decrypt_block_test_case<C: Creds>(
|
|
|
- mut actual: Block, principal: &Principal, creds: &C
|
|
|
- ) -> Result<()> {
|
|
|
- let expected = actual.clone();
|
|
|
- actual = encrypt_block(actual, principal, creds)?;
|
|
|
- let encrypted = match &actual.body {
|
|
|
- Cryptotext::Cipher(_) => true,
|
|
|
- Cryptotext::Plain(_) => false
|
|
|
+ fn encrypt_decrypt_block_test_case<T: Read + Write + Seek, C: Creds>(
|
|
|
+ mut block: Block<T>, principal: &Principal, creds: &C
|
|
|
+ ) {
|
|
|
+ let expected = {
|
|
|
+ let mut dest = Vec::new();
|
|
|
+ block.seek(SeekFrom::Start(0)).expect("seek failed");
|
|
|
+ block.body.read_to_end(&mut dest).expect("read_to_end failed");
|
|
|
+ block.seek(SeekFrom::Start(0)).expect("seek failed");
|
|
|
+ dest
|
|
|
+ };
|
|
|
+ let mut block = unveil(block, principal, creds).expect("unveil failed");
|
|
|
+ block.write_all(&expected).expect("write_all failed");
|
|
|
+ block.flush().expect("flush failed");
|
|
|
+ block.seek(SeekFrom::Start(0)).expect("seek failed");
|
|
|
+ let actual = {
|
|
|
+ let mut actual = Vec::new();
|
|
|
+ block.read_to_end(&mut actual).expect("failed to read actual block contents");
|
|
|
+ actual
|
|
|
};
|
|
|
- assert!(encrypted);
|
|
|
- actual = decrypt_block(actual, principal, creds)?;
|
|
|
assert_eq!(expected, actual);
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn encrypt_decrypt_block_aes256cbc() -> Result<()> {
|
|
|
- let readcap = make_readcap();
|
|
|
- let principal = readcap.issued_to.clone();
|
|
|
- let block = make_block_with(readcap)?;
|
|
|
- let key = make_key_pair();
|
|
|
- encrypt_decrypt_block_test_case(block, &principal, &key)
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
- fn encrypt_decrypt_block_aes256ctr() -> Result<()> {
|
|
|
+ fn encrypt_decrypt_block() {
|
|
|
let readcap = make_readcap();
|
|
|
let principal = readcap.issued_to.clone();
|
|
|
- let block = make_block_with(readcap)?;
|
|
|
+ let block = make_block_with(readcap);
|
|
|
let key = make_key_pair();
|
|
|
encrypt_decrypt_block_test_case(block, &principal, &key)
|
|
|
}
|
|
@@ -2022,9 +1976,9 @@ mod tests {
|
|
|
fn sign_verify_block_rsa() -> Result<()> {
|
|
|
let readcap = make_readcap();
|
|
|
let principal = readcap.issued_to.clone();
|
|
|
- let mut block = make_block_with(readcap)?;
|
|
|
+ let block = make_block_with(readcap);
|
|
|
let key = make_key_pair();
|
|
|
- block = encrypt_block(block, &principal, &key)?;
|
|
|
+ let mut block = unveil(block, &principal, &key).expect("unveil failed");
|
|
|
sign_block(&mut block, &key)?;
|
|
|
verify_block(&block)?;
|
|
|
Ok(())
|
|
@@ -2047,14 +2001,14 @@ mod tests {
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
- fn verify_writecap_valid() -> Result<()> {
|
|
|
- let writecap = make_writecap(vec!["apps", "verse"])?;
|
|
|
- verify_writecap(&writecap, &writecap.path)
|
|
|
+ fn verify_writecap_valid() {
|
|
|
+ let writecap = make_writecap(vec!["apps", "verse"]);
|
|
|
+ verify_writecap(&writecap, &writecap.path).expect("failed to verify writecap");
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_signature() -> Result<()> {
|
|
|
- let mut writecap = make_writecap(vec!["apps", "verse"])?;
|
|
|
+ let mut writecap = make_writecap(vec!["apps", "verse"]);
|
|
|
writecap.signature = Signature::empty(Sign::RSA_PSS_3072_SHA_256);
|
|
|
let result = verify_writecap(&writecap, &writecap.path);
|
|
|
if let Err(Error::InvalidSignature) = result {
|
|
@@ -2078,7 +2032,7 @@ mod tests {
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_path_not_contained() -> Result<()> {
|
|
|
- let writecap = make_writecap(vec!["apps", "verse"])?;
|
|
|
+ let writecap = make_writecap(vec!["apps", "verse"]);
|
|
|
let mut path = writecap.path.clone();
|
|
|
path.components.pop();
|
|
|
// `path` is now a superpath of `writecap.path`, thus the writecap is not authorized to
|
|
@@ -2089,7 +2043,7 @@ mod tests {
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_expired() -> Result<()> {
|
|
|
- let mut writecap = make_writecap(vec!["apps", "verse"])?;
|
|
|
+ let mut writecap = make_writecap(vec!["apps", "verse"]);
|
|
|
writecap.expires = Epoch::now() - Duration::from_secs(1);
|
|
|
let result = verify_writecap(&writecap, &writecap.path);
|
|
|
assert_authz_err(WritecapAuthzErr::Expired, result)
|
|
@@ -2097,27 +2051,27 @@ mod tests {
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_not_chained() -> Result<()> {
|
|
|
- let (mut root_writecap, root_key) = make_self_signed_writecap()?;
|
|
|
+ let (mut root_writecap, root_key) = make_self_signed_writecap();
|
|
|
root_writecap.issued_to = Principal(Hash::Sha2_256([0; 32]));
|
|
|
sign_writecap(&mut root_writecap, &root_key)?;
|
|
|
let node_key = AsymKeyPub::new(Sign::RSA_PSS_3072_SHA_256, NODE_PUBLIC_KEY.as_slice())?;
|
|
|
let node_principal = node_key.owner();
|
|
|
let writecap = make_writecap_trusted_by(
|
|
|
- root_writecap, root_key, node_principal, vec!["apps", "contacts"])?;
|
|
|
+ root_writecap, root_key, node_principal, vec!["apps", "contacts"]);
|
|
|
let result = verify_writecap(&writecap, &writecap.path);
|
|
|
assert_authz_err(WritecapAuthzErr::NotChained, result)
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_root_doesnt_own_path() -> Result<()> {
|
|
|
- let (mut root_writecap, root_key) = make_self_signed_writecap()?;
|
|
|
+ let (mut root_writecap, root_key) = make_self_signed_writecap();
|
|
|
let owner = Principal(Hash::Sha2_256([0; 32]));
|
|
|
root_writecap.path = make_path_with_owner(owner, vec![]);
|
|
|
sign_writecap(&mut root_writecap, &root_key)?;
|
|
|
let node_key = AsymKeyPub::new(Sign::RSA_PSS_3072_SHA_256, NODE_PUBLIC_KEY.as_slice())?;
|
|
|
let node_owner = node_key.owner();
|
|
|
let writecap = make_writecap_trusted_by(
|
|
|
- root_writecap, root_key, node_owner, vec!["apps", "contacts"])?;
|
|
|
+ root_writecap, root_key, node_owner, vec!["apps", "contacts"]);
|
|
|
let result = verify_writecap(&writecap, &writecap.path);
|
|
|
assert_authz_err(WritecapAuthzErr::RootDoesNotOwnPath, result)
|
|
|
}
|