diff --git a/src/api2/backup/upload_chunk.rs b/src/api2/backup/upload_chunk.rs index 3cd85890..3ed54c9c 100644 --- a/src/api2/backup/upload_chunk.rs +++ b/src/api2/backup/upload_chunk.rs @@ -55,6 +55,8 @@ impl Future for UploadChunk { let chunk = DataChunk::from_raw(raw_data, self.digest)?; + chunk.verify_unencrypted(self.size as usize)?; + let (is_duplicate, compressed_size) = self.store.insert_chunk(&chunk)?; return Ok(Async::Ready((self.digest, self.size, compressed_size as u32, is_duplicate))) diff --git a/src/backup/data_chunk.rs b/src/backup/data_chunk.rs index 426cf4d7..85d894c1 100644 --- a/src/backup/data_chunk.rs +++ b/src/backup/data_chunk.rs @@ -159,6 +159,35 @@ impl DataChunk { bail!("unable to parse raw chunk - wrong magic"); } } + + /// Verify digest and data length for unencrypted chunks. + /// + /// To do that, we need to decompress data first. Please note that + /// this is noth possible for encrypted chunks. + pub fn verify_unencrypted(&self, expected_chunk_size: usize) -> Result<(), Error> { + + let magic = &self.raw_data[0..8]; + + let verify_raw_data = |data: &[u8]| { + if expected_chunk_size != data.len() { + bail!("detected chunk with wrong length ({} != {})", expected_chunk_size, data.len()); + } + let digest = openssl::sha::sha256(data); + if digest != self.digest { + bail!("detected chunk with wrong digest."); + } + Ok(()) + }; + + if magic == COMPRESSED_CHUNK_MAGIC_1_0 { + let data = zstd::block::decompress(&self.raw_data[8..], 16*1024*1024)?; + verify_raw_data(&data)?; + } else if magic == UNCOMPRESSED_CHUNK_MAGIC_1_0 { + verify_raw_data(&self.raw_data[8..])?; + } + + Ok(()) + } } /// Builder for DataChunk