|
@@ -7,9 +7,6 @@ mod crypto;
|
|
|
#[cfg(test)]
|
|
|
mod test_helpers;
|
|
|
|
|
|
-#[cfg(test)]
|
|
|
-mod serde_tests;
|
|
|
-
|
|
|
#[macro_use]
|
|
|
extern crate static_assertions;
|
|
|
|
|
@@ -31,7 +28,6 @@ use std::{
|
|
|
collections::HashMap,
|
|
|
convert::{Infallible, TryFrom},
|
|
|
fmt::{self, Display, Formatter},
|
|
|
- fs::{File, OpenOptions},
|
|
|
hash::Hash as Hashable,
|
|
|
io::{self, Read, Seek, SeekFrom, Write},
|
|
|
marker::PhantomData,
|
|
@@ -133,9 +129,11 @@ impl<T, E: Display> StrInIoErr<T> for std::result::Result<T, E> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/// The default sector size to use for new blocks.
|
|
|
const SECTOR_SZ_DEFAULT: usize = 4096;
|
|
|
|
|
|
-trait Block: Read + Write + Seek + HeaderAccess {}
|
|
|
+/// Trait for types which provide read and write access to blocks.
|
|
|
+pub trait Block: Read + Write + Seek + MetaAccess {}
|
|
|
|
|
|
// A trait for streams which only allow reads and writes in fixed sized units called sectors.
|
|
|
trait Sectored {
|
|
@@ -178,7 +176,7 @@ impl<T, U: Decompose<T>, S: TryCompose<T, U, Error = Infallible>> Compose<T, U>
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub trait HeaderAccess {
|
|
|
+pub trait MetaAccess {
|
|
|
fn block_key(&self) -> Result<SymKey>;
|
|
|
fn add_readcap_for(&mut self, owner: Principal, key: &dyn Encrypter) -> Result<()>;
|
|
|
/// Returns the integrity value used to protect the contents of the block.
|
|
@@ -219,8 +217,11 @@ trait ReadExt: Read {
|
|
|
|
|
|
impl<T: Read> ReadExt for T {}
|
|
|
|
|
|
+/// This struct contains all of the metadata fields associated with a block, except for its
|
|
|
+/// signature. Since this struct implements `Serialize`, this allows for convenient signature
|
|
|
+/// calculations.
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
|
|
-pub struct Header {
|
|
|
+pub struct BlockMetaBody {
|
|
|
path: Path,
|
|
|
readcaps: HashMap<Principal, Ciphertext<SymKey>>,
|
|
|
writecap: Option<Writecap>,
|
|
@@ -230,9 +231,9 @@ pub struct Header {
|
|
|
signing_key: AsymKeyPub<Sign>,
|
|
|
}
|
|
|
|
|
|
-impl Header {
|
|
|
- fn new<C: Creds>(creds: &C) -> Header {
|
|
|
- Header {
|
|
|
+impl BlockMetaBody {
|
|
|
+ fn new<C: Creds>(creds: &C) -> BlockMetaBody {
|
|
|
+ BlockMetaBody {
|
|
|
path: Path::default(),
|
|
|
readcaps: HashMap::new(),
|
|
|
writecap: creds.writecap().map(|e| e.to_owned()),
|
|
@@ -242,62 +243,55 @@ impl Header {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/// Signed metadata associated with a block.
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
-struct BlockTrailer {
|
|
|
- header: Header,
|
|
|
+struct BlockMeta {
|
|
|
+ body: BlockMetaBody,
|
|
|
sig: Signature,
|
|
|
}
|
|
|
|
|
|
-impl BlockTrailer {
|
|
|
- fn new<C: Creds>(creds: &C) -> BlockTrailer {
|
|
|
- let header = Header::new(creds);
|
|
|
- let sig = Signature::empty(header.signing_key.scheme());
|
|
|
- BlockTrailer { header, sig }
|
|
|
+impl BlockMeta {
|
|
|
+ fn new<C: Creds>(creds: &C) -> BlockMeta {
|
|
|
+ let body = BlockMetaBody::new(creds);
|
|
|
+ let sig = Signature::empty(body.signing_key.scheme());
|
|
|
+ BlockMeta { body, sig }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
struct BlockStream<T, C> {
|
|
|
- trailered: Trailered<T, BlockTrailer>,
|
|
|
- trailer: BlockTrailer,
|
|
|
- header_buf: Vec<u8>,
|
|
|
+ trailered: Trailered<T, BlockMeta>,
|
|
|
+ meta: BlockMeta,
|
|
|
+ meta_body_buf: Vec<u8>,
|
|
|
creds: C,
|
|
|
}
|
|
|
|
|
|
impl<T: Read + Seek, C: Creds> BlockStream<T, C> {
|
|
|
fn new(inner: T, creds: C) -> Result<BlockStream<T, C>> {
|
|
|
- let (trailered, trailer) = Trailered::<_, BlockTrailer>::new(inner)?;
|
|
|
+ let (trailered, trailer) = Trailered::<_, BlockMeta>::new(inner)?;
|
|
|
let trailer = match trailer {
|
|
|
Some(trailer) => {
|
|
|
- crypto::verify_header(&trailer.header, &trailer.sig)?;
|
|
|
+ crypto::verify_header(&trailer.body, &trailer.sig)?;
|
|
|
trailer
|
|
|
}
|
|
|
None => {
|
|
|
- let mut trailer = BlockTrailer::new(&creds);
|
|
|
+ let mut meta = BlockMeta::new(&creds);
|
|
|
let block_key = SymKey::generate(SymKeyKind::default())?;
|
|
|
- trailer
|
|
|
- .header
|
|
|
+ meta.body
|
|
|
.readcaps
|
|
|
.insert(creds.principal(), creds.ser_encrypt(&block_key)?);
|
|
|
- trailer.header.writecap = creds.writecap().map(|e| e.to_owned());
|
|
|
- trailer
|
|
|
+ meta.body.writecap = creds.writecap().map(|e| e.to_owned());
|
|
|
+ meta
|
|
|
}
|
|
|
};
|
|
|
Ok(BlockStream {
|
|
|
trailered,
|
|
|
- trailer,
|
|
|
- header_buf: Vec::new(),
|
|
|
+ meta: trailer,
|
|
|
+ meta_body_buf: Vec::new(),
|
|
|
creds,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<C: Creds> BlockStream<File, C> {
|
|
|
- fn open<P: AsRef<std::path::Path>>(path: P, creds: C) -> Result<BlockStream<File, C>> {
|
|
|
- let inner = OpenOptions::new().read(true).write(true).open(path)?;
|
|
|
- BlockStream::new(inner, creds)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
impl<T: Write + Seek, C: Signer> Write for BlockStream<T, C> {
|
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
|
self.trailered.write(buf)
|
|
@@ -313,15 +307,15 @@ impl<T: Write + Seek, C: Signer> Write for BlockStream<T, C> {
|
|
|
|
|
|
impl<T: Write + Seek, C: Signer> WriteInteg for BlockStream<T, C> {
|
|
|
fn flush_integ(&mut self, integrity: &[u8]) -> io::Result<()> {
|
|
|
- let header = &mut self.trailer.header;
|
|
|
- let integ = header.integrity.get_or_insert_with(Hash::default);
|
|
|
+ let meta_body = &mut self.meta.body;
|
|
|
+ let integ = meta_body.integrity.get_or_insert_with(Hash::default);
|
|
|
integ.as_mut().copy_from_slice(integrity);
|
|
|
- self.header_buf.clear();
|
|
|
- write_to(&header, &mut self.header_buf).box_err()?;
|
|
|
- self.trailer.sig = self
|
|
|
+ self.meta_body_buf.clear();
|
|
|
+ write_to(&meta_body, &mut self.meta_body_buf).box_err()?;
|
|
|
+ self.meta.sig = self
|
|
|
.creds
|
|
|
- .sign(std::iter::once(self.header_buf.as_slice()))?;
|
|
|
- self.trailered.flush(&self.trailer)?;
|
|
|
+ .sign(std::iter::once(self.meta_body_buf.as_slice()))?;
|
|
|
+ self.trailered.flush(&self.meta)?;
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
@@ -340,11 +334,11 @@ impl<T: Seek, C> Seek for BlockStream<T, C> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T, C: Decrypter + Principaled> HeaderAccess for BlockStream<T, C> {
|
|
|
+impl<T, C: Decrypter + Principaled> MetaAccess for BlockStream<T, C> {
|
|
|
fn block_key(&self) -> Result<SymKey> {
|
|
|
let readcap = self
|
|
|
- .trailer
|
|
|
- .header
|
|
|
+ .meta
|
|
|
+ .body
|
|
|
.readcaps
|
|
|
.get(&self.creds.principal())
|
|
|
.ok_or(Error::Crypto(crypto::Error::NoReadCap))?;
|
|
@@ -354,20 +348,16 @@ impl<T, C: Decrypter + Principaled> HeaderAccess for BlockStream<T, C> {
|
|
|
fn add_readcap_for(&mut self, owner: Principal, key: &dyn Encrypter) -> Result<()> {
|
|
|
let block_key = self.block_key()?;
|
|
|
let readcap = key.ser_encrypt(&block_key)?;
|
|
|
- self.trailer.header.readcaps.insert(owner, readcap);
|
|
|
+ self.meta.body.readcaps.insert(owner, readcap);
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
fn integrity(&self) -> Option<&[u8]> {
|
|
|
- self.trailer
|
|
|
- .header
|
|
|
- .integrity
|
|
|
- .as_ref()
|
|
|
- .map(|hash| hash.as_ref())
|
|
|
+ self.meta.body.integrity.as_ref().map(|hash| hash.as_ref())
|
|
|
}
|
|
|
|
|
|
fn set_path(&mut self, path: Path) {
|
|
|
- self.trailer.header.path = path;
|
|
|
+ self.meta.body.path = path;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -897,7 +887,7 @@ impl<T: Seek + Read + Write> Seek for SectoredBuf<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: HeaderAccess> HeaderAccess for SectoredBuf<T> {
|
|
|
+impl<T: MetaAccess> MetaAccess for SectoredBuf<T> {
|
|
|
fn block_key(&self) -> Result<SymKey> {
|
|
|
self.inner.block_key()
|
|
|
}
|
|
@@ -915,7 +905,7 @@ impl<T: HeaderAccess> HeaderAccess for SectoredBuf<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Read + Write + Seek + HeaderAccess> Block for SectoredBuf<T> {}
|
|
|
+impl<T: Read + Write + Seek + MetaAccess> Block for SectoredBuf<T> {}
|
|
|
|
|
|
/// An envelopment of a key, which is tagged with the principal who the key is meant for.
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
@@ -1217,7 +1207,7 @@ struct FragmentSerial(u32);
|
|
|
|
|
|
#[cfg(test)]
|
|
|
mod tests {
|
|
|
- use std::io::Cursor;
|
|
|
+ use std::{fs::OpenOptions, io::Cursor};
|
|
|
|
|
|
use crate::crypto::{tpm::TpmCredStore, CredStore, CredsPriv};
|
|
|
|
|
@@ -1691,7 +1681,6 @@ mod tests {
|
|
|
#[test]
|
|
|
fn block_contents_persisted() {
|
|
|
const EXPECTED: &[u8] = b"Silly sordid sulking sultans.";
|
|
|
- const PASSWORD: &str = "(1337Prestidigitation7331)";
|
|
|
let temp_dir = TempDir::new("btlib").expect("failed to create temp dir");
|
|
|
let file_path = temp_dir.path().join("test.blk").to_owned();
|
|
|
let harness = SwtpmHarness::new().expect("failed to start swtpm");
|
|
@@ -1699,7 +1688,7 @@ mod tests {
|
|
|
let cred_store = TpmCredStore::new(context, harness.state_path())
|
|
|
.expect("failed to create TpmCredStore");
|
|
|
let root_creds = cred_store
|
|
|
- .gen_root_creds(PASSWORD)
|
|
|
+ .gen_root_creds("(1337Prestidigitation7331)")
|
|
|
.expect("failed to get root creds");
|
|
|
let mut node_creds = cred_store.node_creds().expect("failed to get node creds");
|
|
|
let writecap = root_creds
|