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