1use std::fmt;
15use std::io::{Cursor, Read, Seek, SeekFrom, Write};
16
17use binrw::io::TakeSeekExt;
18use binrw::{BinRead, BinResult, BinWrite, Endian};
19
20use super::VerifyError;
21use crate::archive::SIGNING_BLOCK_MAGIC;
22
23#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
25pub struct BlockId(pub u32);
26
27impl BlockId {
28 pub const V2: Self = Self(0x7109_871a);
30 pub const V3: Self = Self(0xf053_68c0);
32 pub const V3_1: Self = Self(0x1b93_ad61);
34 pub const VERITY_PADDING: Self = Self(0x4272_6577);
36 pub const DEPENDENCY_INFO: Self = Self(0x504b_4453);
38 pub const SOURCE_STAMP: Self = Self(0x6dff_800d);
40 pub const SOURCE_STAMP_V1: Self = Self(0x2b09_189e);
42
43 pub fn is_signature_data(self) -> bool {
46 [Self::V2, Self::V3, Self::V3_1, Self::VERITY_PADDING, Self::SOURCE_STAMP, Self::SOURCE_STAMP_V1]
47 .contains(&self)
48 }
49}
50
51impl fmt::Debug for BlockId {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 write!(f, "BlockId({:#010x})", self.0)
54 }
55}
56
57#[derive(Clone, Debug, Default, Eq, PartialEq)]
59pub struct SigningBlock {
60 pub pairs: Vec<(BlockId, Vec<u8>)>,
61}
62
63const FRAME: usize = 8 + 8 + 16;
65
66impl SigningBlock {
67 pub fn parse(block: &[u8]) -> Result<Self, VerifyError> {
71 let len = block.len();
72 if len < FRAME || block[len - 16..] != SIGNING_BLOCK_MAGIC {
73 return Err(VerifyError::MalformedBlock);
74 }
75 let size = |at: usize| u64::from_le_bytes(block[at..at + 8].try_into().expect("eight bytes"));
76 if size(0) != (len - 8) as u64 || size(len - 24) != (len - 8) as u64 {
77 return Err(VerifyError::MalformedBlock);
78 }
79 let mut body = &block[8..len - 24];
80 let mut offset = 8u64;
81 let mut pairs = Vec::new();
82 while !body.is_empty() {
83 let invalid = |len| VerifyError::InvalidBlockPair { offset, len };
84 let len_bytes: [u8; 8] = body.get(..8).ok_or(invalid(0))?.try_into().expect("eight bytes");
85 let len = u64::from_le_bytes(len_bytes);
86 let value_end = usize::try_from(len)
87 .ok()
88 .and_then(|len| len.checked_add(8))
89 .filter(|&end| len >= 4 && end <= body.len());
90 let end = value_end.ok_or(invalid(len))?;
91 let id = BlockId(u32::from_le_bytes(body[8..12].try_into().expect("four bytes")));
92 pairs.push((id, body[12..end].to_vec()));
93 body = &body[end..];
94 offset += end as u64;
95 }
96 Ok(Self { pairs })
97 }
98
99 pub fn get(&self, id: BlockId) -> Option<&[u8]> {
101 self.pairs.iter().find(|(i, _)| *i == id).map(|(_, v)| v.as_slice())
102 }
103
104 pub fn encode(&self) -> Vec<u8> {
106 let pairs_len: usize = self.pairs.iter().map(|(_, v)| 12 + v.len()).sum();
107 let size = (pairs_len + 8 + 16) as u64;
108 let mut out = Vec::with_capacity(pairs_len + FRAME);
109 out.extend_from_slice(&size.to_le_bytes());
110 for (id, value) in &self.pairs {
111 out.extend_from_slice(&(value.len() as u64 + 4).to_le_bytes());
112 out.extend_from_slice(&id.0.to_le_bytes());
113 out.extend_from_slice(value);
114 }
115 out.extend_from_slice(&size.to_le_bytes());
116 out.extend_from_slice(&SIGNING_BLOCK_MAGIC);
117 out
118 }
119}
120
121#[derive(Clone, Debug, Default, Eq, PartialEq)]
123pub(crate) struct Prefixed<T>(pub T);
124
125impl<T> BinRead for Prefixed<T>
126where
127 T: BinRead,
128{
129 type Args<'a> = T::Args<'a>;
130
131 fn read_options<R: Read + Seek>(reader: &mut R, endian: Endian, args: Self::Args<'_>) -> BinResult<Self> {
132 let len = u32::read_options(reader, endian, ())?;
133 let start = reader.stream_position()?;
134 let mut bounded = reader.take_seek(u64::from(len));
135 let value = T::read_options(&mut bounded, endian, args)?;
136 if bounded.limit() != 0 {
137 return Err(binrw::Error::AssertFail { pos: start, message: "record has trailing bytes".into() });
138 }
139 Ok(Self(value))
140 }
141}
142
143impl<T> BinWrite for Prefixed<T>
144where
145 T: BinWrite,
146{
147 type Args<'a> = T::Args<'a>;
148
149 fn write_options<W: Write + Seek>(&self, writer: &mut W, endian: Endian, args: Self::Args<'_>) -> BinResult<()> {
150 let mut buffer = Cursor::new(Vec::new());
151 self.0.write_options(&mut buffer, endian, args)?;
152 let bytes = buffer.into_inner();
153 let len = u32::try_from(bytes.len())
154 .map_err(|_| binrw::Error::AssertFail { pos: 0, message: "record exceeds 4 GiB".into() })?;
155 len.write_options(writer, endian, ())?;
156 writer.write_all(&bytes)?;
157 Ok(())
158 }
159}
160
161#[derive(Clone, Debug, Default, Eq, PartialEq)]
163pub(crate) struct Seq<T>(pub Vec<T>);
164
165impl<T> BinRead for Seq<T>
166where
167 T: BinRead,
168 for<'a> T::Args<'a>: Clone,
169{
170 type Args<'a> = T::Args<'a>;
171
172 fn read_options<R: Read + Seek>(reader: &mut R, endian: Endian, args: Self::Args<'_>) -> BinResult<Self> {
173 let start = reader.stream_position()?;
174 let end = reader.seek(SeekFrom::End(0))?;
175 reader.seek(SeekFrom::Start(start))?;
176 let mut items = Vec::new();
177 while reader.stream_position()? < end {
178 items.push(T::read_options(reader, endian, args.clone())?);
179 }
180 Ok(Self(items))
181 }
182}
183
184impl<T> BinWrite for Seq<T>
185where
186 T: BinWrite,
187 for<'a> T::Args<'a>: Clone,
188{
189 type Args<'a> = T::Args<'a>;
190
191 fn write_options<W: Write + Seek>(&self, writer: &mut W, endian: Endian, args: Self::Args<'_>) -> BinResult<()> {
192 self.0.iter().try_for_each(|item| item.write_options(writer, endian, args.clone()))
193 }
194}
195
196#[derive(Clone, Default, Eq, PartialEq)]
198pub(crate) struct Blob(pub Vec<u8>);
199
200impl fmt::Debug for Blob {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 write!(f, "Blob({} bytes)", self.0.len())
203 }
204}
205
206impl BinRead for Blob {
207 type Args<'a> = ();
208
209 fn read_options<R: Read + Seek>(reader: &mut R, _: Endian, (): ()) -> BinResult<Self> {
210 let mut bytes = Vec::new();
211 reader.read_to_end(&mut bytes)?;
212 Ok(Self(bytes))
213 }
214}
215
216impl BinWrite for Blob {
217 type Args<'a> = ();
218
219 fn write_options<W: Write + Seek>(&self, writer: &mut W, _: Endian, (): ()) -> BinResult<()> {
220 writer.write_all(&self.0)?;
221 Ok(())
222 }
223}
224
225pub(crate) fn read_exact<T>(bytes: &[u8], args: T::Args<'_>) -> Result<T, u64>
227where
228 T: BinRead,
229{
230 let mut cursor = Cursor::new(bytes);
231 let value = T::read_options(&mut cursor, Endian::Little, args).map_err(|error| error_offset(&error))?;
232 if cursor.position() as usize != bytes.len() {
233 return Err(cursor.position());
234 }
235 Ok(value)
236}
237
238pub(crate) fn read_leading<T>(bytes: &[u8], args: T::Args<'_>) -> Result<T, u64>
241where
242 T: BinRead,
243{
244 T::read_options(&mut Cursor::new(bytes), Endian::Little, args).map_err(|error| error_offset(&error))
245}
246
247pub(crate) fn write_vec<T>(value: &T, args: T::Args<'_>) -> Vec<u8>
249where
250 T: BinWrite,
251{
252 let mut cursor = Cursor::new(Vec::new());
253 value.write_options(&mut cursor, Endian::Little, args).expect("signature records fit in memory and under 4 GiB");
254 cursor.into_inner()
255}
256
257fn error_offset(error: &binrw::Error) -> u64 {
258 match error {
259 binrw::Error::BadMagic { pos, .. }
260 | binrw::Error::AssertFail { pos, .. }
261 | binrw::Error::Custom { pos, .. }
262 | binrw::Error::NoVariantMatch { pos }
263 | binrw::Error::EnumErrors { pos, .. } => *pos,
264 binrw::Error::Backtrace(backtrace) => error_offset(&backtrace.error),
265 _ => 0,
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn signing_block_round_trips_and_bounds_pairs() {
275 let block = SigningBlock { pairs: vec![(BlockId::V2, vec![1, 2, 3]), (BlockId::V3, vec![])] };
276 let bytes = block.encode();
277 assert_eq!(SigningBlock::parse(&bytes).unwrap(), block);
278 let mut corrupt = bytes.clone();
279 corrupt[8..16].copy_from_slice(&u64::MAX.to_le_bytes());
280 assert!(matches!(SigningBlock::parse(&corrupt), Err(VerifyError::InvalidBlockPair { offset: 8, .. })));
281 for size_field in [0, bytes.len() - 24] {
282 let mut corrupt = bytes.clone();
283 corrupt[size_field..size_field + 8].copy_from_slice(&u64::MAX.to_le_bytes());
284 assert!(matches!(SigningBlock::parse(&corrupt), Err(VerifyError::MalformedBlock)), "{size_field}");
285 }
286 }
287
288 #[test]
289 fn prefixed_records_must_be_exact() {
290 let bytes = [1, 0, 0, 0, b'a', 2, 0, 0, 0, b'b', b'c'];
292 let parsed: Seq<Prefixed<Blob>> = read_exact(&bytes, ()).unwrap();
293 assert_eq!(parsed.0.iter().map(|p| p.0.0.clone()).collect::<Vec<_>>(), [b"a".to_vec(), b"bc".to_vec()]);
294 assert_eq!(write_vec(&parsed, ()), bytes);
295 assert!(read_exact::<Prefixed<Blob>>(&[9, 0, 0, 0, b'x'], ()).is_err());
297 assert!(read_exact::<Prefixed<u32>>(&[1, 0, 0, 0, 7], ()).is_err());
299 assert!(read_exact::<Prefixed<u8>>(&[2, 0, 0, 0, 7, 7], ()).is_err());
301 }
302}