diff --git a/src/backup/data_blob.rs b/src/backup/data_blob.rs index 3706104d..2bc11faf 100644 --- a/src/backup/data_blob.rs +++ b/src/backup/data_blob.rs @@ -294,17 +294,22 @@ impl DataBlob { use std::io::{Read, BufRead, Write, Seek, SeekFrom}; -enum BlobWriterState { +enum BlobWriterState<'a, W: Write> { Uncompressed { writer: W, hasher: crc32fast::Hasher }, Compressed { compr: zstd::stream::write::Encoder, hasher: crc32fast::Hasher }, + Signed { + writer: W, + hasher: crc32fast::Hasher, + signer: openssl::sign::Signer<'a>, + }, } /// Write compressed data blobs -pub struct DataBlobWriter { - state: BlobWriterState, +pub struct DataBlobWriter<'a, W: Write> { + state: BlobWriterState<'a, W>, } -impl DataBlobWriter { +impl <'a, W: Write + Seek> DataBlobWriter<'a, W> { pub fn new_uncompressed(mut writer: W) -> Result { let hasher = crc32fast::Hasher::new(); @@ -329,6 +334,22 @@ impl DataBlobWriter { Ok(Self { state }) } + pub fn new_signed(mut writer: W, config: &'a CryptConfig) -> Result { + let hasher = crc32fast::Hasher::new(); + writer.seek(SeekFrom::Start(0))?; + let head = AuthenticatedDataBlobHeader { + head: DataBlobHeader { magic: AUTHENTICATED_BLOB_MAGIC_1_0, crc: [0; 4] }, + tag: [0u8; 32], + }; + unsafe { + writer.write_le_value(head)?; + } + let signer = config.data_signer(); + + let state = BlobWriterState::Signed { writer, hasher, signer }; + Ok(Self { state }) + } + pub fn finish(self) -> Result { match self.state { BlobWriterState::Uncompressed { mut writer, hasher } => { @@ -355,13 +376,30 @@ impl DataBlobWriter { writer.write_le_value(head)?; } + return Ok(writer) + } + BlobWriterState::Signed { mut writer, hasher, signer, .. } => { + // write CRC and hmac + let crc = hasher.finalize(); + + let mut head = AuthenticatedDataBlobHeader { + head: DataBlobHeader { magic: AUTHENTICATED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() }, + tag: [0u8; 32], + }; + signer.sign(&mut head.tag)?; + + writer.seek(SeekFrom::Start(0))?; + unsafe { + writer.write_le_value(head)?; + } + return Ok(writer) } } } } -impl Write for DataBlobWriter { +impl <'a, W: Write + Seek> Write for DataBlobWriter<'a, W> { fn write(&mut self, buf: &[u8]) -> Result { match self.state { @@ -373,6 +411,16 @@ impl Write for DataBlobWriter { hasher.update(buf); compr.write(buf) } + BlobWriterState::Signed { ref mut writer, ref mut hasher, ref mut signer, .. } => { + hasher.update(buf); + signer.update(buf). + map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("hmac update failed - {}", err)) + })?; + writer.write(buf) + } } } @@ -384,6 +432,9 @@ impl Write for DataBlobWriter { BlobWriterState::Compressed { ref mut compr, .. } => { compr.flush() } + BlobWriterState::Signed { ref mut writer, .. } => { + writer.flush() + } } } }