commit 1c6cd7f4061eb00ecc1d5f81114680ecb61eacde
parent 0375b6fa00553baf6f521ff6a43744c1f9fe42da
Author: mauricefisher64 <92736594+mauricefisher64@users.noreply.github.com>
Date: Thu, 10 Aug 2023 16:03:39 -0400
Fix for overly harsh checks when checking Merkle trees. (#289)
* Fix for overly harsh checks when checking Merkle trees.
* Code simplification
* Fix missing id field from jumbf box reading.
* clippy fixes
Diffstat:
2 files changed, 55 insertions(+), 70 deletions(-)
diff --git a/sdk/src/assertions/bmff_hash.rs b/sdk/src/assertions/bmff_hash.rs
@@ -609,33 +609,13 @@ impl BmffHash {
}
};
- let sample_cnt = mp4.sample_count(mm.local_id).map_err(|_e| {
- Error::InvalidAsset("Could not parse BMFF track sample".to_string())
- })?;
-
+ let sample_cnt = track.sample_count();
if sample_cnt == 0 {
return Err(Error::InvalidAsset("No samples".to_string()));
}
let track_id = track.track_id();
- // get the chunk count
- let stbl_box = &track.trak.mdia.minf.stbl;
- let chunk_cnt = match &stbl_box.stco {
- Some(stco) => stco.entries.len(),
- None => match &stbl_box.co64 {
- Some(co64) => co64.entries.len(),
- None => 0,
- },
- };
-
- // the Merkle count is the number of chunks for timed media
- if mm.count != chunk_cnt as u32 {
- return Err(Error::HashMismatch(
- "Track count does not match Merkle map count".to_string(),
- ));
- }
-
// create sample to chunk mapping
// create the Merkle tree per samples in a chunk
let mut chunk_hash_map: HashMap<u32, Hasher> = HashMap::new();
@@ -684,19 +664,13 @@ impl BmffHash {
}
}
- if chunk_cnt != chunk_hash_map.len() {
- return Err(Error::HashMismatch(
- "Incorrect number of Merkle trees".to_string(),
- ));
- }
-
// finalize leaf hashes
let mut leaf_hashes = Vec::new();
for chunk_bmff_mm in &track_to_bmff_merkle_map[&track_id] {
match chunk_hash_map.remove(&(chunk_bmff_mm.location + 1)) {
Some(h) => {
let h = Hasher::finalize(h);
- leaf_hashes.push(h.clone());
+ leaf_hashes.push(h);
}
None => {
return Err(Error::HashMismatch(
diff --git a/sdk/src/jumbf/boxes.rs b/sdk/src/jumbf/boxes.rs
@@ -30,6 +30,7 @@ use std::{
io::{Read, Result as IoResult, Seek, SeekFrom, Write},
};
+use byteorder::{BigEndian, ReadBytesExt};
use hex::FromHex;
use log::debug;
use thiserror::Error;
@@ -1910,10 +1911,10 @@ impl BoxReader {
reader.read_exact(&mut togs)?;
bytes_left -= 1;
+ let mut sbuf = Vec::with_capacity(64);
if togs[0] & 0x03 == 0x03 {
// must be requestable and labeled
// read label
- let mut sbuf = Vec::with_capacity(64);
loop {
let mut buf = [0; 1];
reader.read_exact(&mut buf)?;
@@ -1924,54 +1925,64 @@ impl BoxReader {
sbuf.push(buf[0]);
}
}
+ } else {
+ return Err(JumbfParseError::InvalidDescriptionBox);
+ }
- // if there is a signature, we need to read it...
- let sig = if togs[0] & 0x08 == 0x08 {
- let mut sigbuf: [u8; 32] = [0; 32];
- reader.read_exact(&mut sigbuf)?;
- bytes_left -= 32;
- Some(sigbuf)
- } else {
- None
- };
-
- // read private box if necessary
- let private = if togs[0] & 0x10 == 0x10 {
- let header = BoxReader::read_header(reader)
- .map_err(|_| JumbfParseError::InvalidBoxHeader)?;
- if header.size == 0 {
- // bad read,
- return Err(JumbfParseError::InvalidBoxHeader);
- } else if header.size != bytes_left - HEADER_SIZE {
- // this means that we started w/o the header...
- unread_bytes(reader, HEADER_SIZE)?;
- }
+ // box id
+ let bxid = if togs[0] & 0x04 == 0x04 {
+ let idbuf = reader.read_u32::<BigEndian>()?;
+ bytes_left -= 4;
+ Some(idbuf)
+ } else {
+ None
+ };
- if header.name == BoxType::SaltHash {
- let data_len = header.size - HEADER_SIZE;
- let mut buf = vec![0u8; data_len as usize];
- reader.read_exact(&mut buf)?;
+ // if there is a signature, we need to read it...
+ let sig = if togs[0] & 0x08 == 0x08 {
+ let mut sigbuf: [u8; 32] = [0; 32];
+ reader.read_exact(&mut sigbuf)?;
+ bytes_left -= 32;
+ Some(sigbuf)
+ } else {
+ None
+ };
- bytes_left -= header.size;
+ // read private box if necessary
+ let private = if togs[0] & 0x10 == 0x10 {
+ let header =
+ BoxReader::read_header(reader).map_err(|_| JumbfParseError::InvalidBoxHeader)?;
+ if header.size == 0 {
+ // bad read,
+ return Err(JumbfParseError::InvalidBoxHeader);
+ } else if header.size != bytes_left - HEADER_SIZE {
+ // this means that we started w/o the header...
+ unread_bytes(reader, HEADER_SIZE)?;
+ }
- Some(CAISaltContentBox::new(buf))
- } else {
- return Err(JumbfParseError::InvalidBoxHeader);
- }
- } else {
- None
- };
+ if header.name == BoxType::SaltHash {
+ let data_len = header.size - HEADER_SIZE;
+ let mut buf = vec![0u8; data_len as usize];
+ reader.read_exact(&mut buf)?;
- if bytes_left != HEADER_SIZE {
- // make sure we have consumed the entire box
+ bytes_left -= header.size;
+
+ Some(CAISaltContentBox::new(buf))
+ } else {
return Err(JumbfParseError::InvalidBoxHeader);
}
+ } else {
+ None
+ };
- return Ok(JUMBFDescriptionBox::from(
- &uuid, togs[0], sbuf, None, sig, private,
- ));
+ if bytes_left != HEADER_SIZE {
+ // make sure we have consumed the entire box
+ return Err(JumbfParseError::InvalidBoxHeader);
}
- Err(JumbfParseError::InvalidDescriptionBox)
+
+ Ok(JUMBFDescriptionBox::from(
+ &uuid, togs[0], sbuf, bxid, sig, private,
+ ))
}
pub fn read_json_box<R: Read + Seek>(
@@ -2192,6 +2203,7 @@ impl BoxReader {
// load the description box & create a new superbox from it
let jdesc = BoxReader::read_desc_box(reader, jumd_header.size)
.map_err(|_| JumbfParseError::UnexpectedEof)?;
+
if jdesc.label().is_empty() {
return Err(JumbfParseError::UnexpectedEof);
}
@@ -2213,8 +2225,7 @@ impl BoxReader {
unread_bytes(reader, HEADER_SIZE)?; // seek back to the beginning of the box
let next_box: Box<dyn BMFFBox> = match box_header.name {
BoxType::Jumb => Box::new(
- BoxReader::read_super_box(reader)
- .map_err(|_| JumbfParseError::InvalidJumbBox)?,
+ BoxReader::read_super_box(reader)?, //.map_err(|_| JumbfParseError::InvalidJumbBox)?,
),
BoxType::Json => Box::new(
BoxReader::read_json_box(reader, box_header.size)