1use crate::image::manifest::*;
6use crate::image::manifest_ext::ManifestExtId;
7use crate::util::bigint::fixed_size_bigint;
8use crate::util::num_de::HexEncoded;
9use crate::util::parse_int::ParseInt;
10
11use anyhow::{Context, Result, bail};
12use serde::{Deserialize, Serialize};
13use std::convert::{TryFrom, TryInto};
14use std::fmt;
15use std::iter::IntoIterator;
16use std::path::Path;
17use thiserror::Error;
18
19use zerocopy::IntoBytes;
20
21#[derive(Debug, Error)]
22pub enum ManifestError {
23 #[error("Manifest is missing field \"{0}\".")]
24 MissingField(&'static str),
25}
26
27fixed_size_bigint!(ManifestSigverifyBuffer, at_most 3072);
28
29#[derive(Clone, Default, Debug, Deserialize, Serialize)]
30struct ManifestSigverifyBigInt(Option<HexEncoded<ManifestSigverifyBuffer>>);
31
32#[derive(Clone, Default, Debug, Deserialize, Serialize)]
33struct ManifestSmallInt<T: ParseInt + fmt::LowerHex>(Option<HexEncoded<T>>);
34
35impl fmt::LowerHex for ManifestSigverifyBuffer {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
37 fmt::LowerHex::fmt(&self.as_biguint(), f)
38 }
39}
40
41macro_rules! manifest_def {
47 ($access:vis struct $name:ident {
48 $(
49 $(#[$doc:meta])?
50 $field_name:ident: $field_type:ty,
51 )*
52 }, $out_type:ident) => {
53 #[derive(Clone, Default, Deserialize, Serialize, Debug)]
54 $access struct $name {
55 $(
56 $(#[$doc])?
57 #[serde(default)]
58 $field_name: $field_type,
59 )*
60 }
61
62 impl ManifestPacked<$out_type> for $name {
63 fn unpack(self, _name: &'static str) -> Result<$out_type> {
64 Ok($out_type {
65 $($field_name: self.$field_name
68 .unpack(stringify!($field_name))?.try_into()?,)*
69 })
70 }
71
72 fn overwrite(&mut self, o: $name) {
73 $(self.$field_name.overwrite(o.$field_name);)*
74 }
75 }
76
77 impl TryInto<$out_type> for $name {
78 type Error = anyhow::Error;
79
80 fn try_into(self) -> Result<$out_type> {
81 self.unpack("")
82 }
83 }
84
85 impl TryFrom<&$out_type> for $name {
86 type Error = anyhow::Error;
87
88 fn try_from(o: &$out_type) -> Result<Self> {
89 Ok($name {
90 $($field_name: (&o.$field_name).try_into()?,)*
91 })
92 }
93 }
94 }
95}
96
97impl ManifestSpec {
98 pub fn read_from_file(path: &Path) -> Result<ManifestSpec> {
99 Ok(deser_hjson::from_str(
100 &std::fs::read_to_string(path).with_context(|| format!("Failed to open {path:?}"))?,
101 )?)
102 }
103
104 pub fn overwrite_fields(&mut self, other: ManifestSpec) {
105 self.overwrite(other)
106 }
107
108 pub fn update_signature(&mut self, signature: ManifestSigverifyBuffer) {
109 self.signature.0 = Some(HexEncoded(signature))
110 }
111
112 pub fn update_pub_key(&mut self, pub_key: ManifestSigverifyBuffer) {
113 self.pub_key.0 = Some(HexEncoded(pub_key))
114 }
115
116 pub fn signature(&self) -> Option<&ManifestSigverifyBuffer> {
117 self.signature.0.as_ref().map(|v| &v.0)
118 }
119
120 pub fn pub_key(&self) -> Option<&ManifestSigverifyBuffer> {
121 self.pub_key.0.as_ref().map(|v| &v.0)
122 }
123
124 pub fn has_length(&self) -> bool {
125 self.length.0.is_some()
126 }
127}
128
129trait ManifestPacked<T> {
130 fn unpack_err(&self, name: &'static str) -> Result<T> {
132 bail!(ManifestError::MissingField(name))
133 }
134
135 fn unpack(self, name: &'static str) -> Result<T>;
137
138 fn overwrite(&mut self, o: Self);
140}
141
142impl ManifestPacked<ManifestSigverifyBuffer> for ManifestSigverifyBigInt {
143 fn unpack(self, name: &'static str) -> Result<ManifestSigverifyBuffer> {
144 match self.0 {
145 Some(v) => Ok(v.0),
146 None => self.unpack_err(name),
147 }
148 }
149
150 fn overwrite(&mut self, o: Self) {
151 if o.0.is_some() {
152 *self = o;
153 }
154 }
155}
156
157impl ManifestPacked<[ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT]>
158 for [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT]
159{
160 fn unpack(
161 self,
162 _name: &'static str,
163 ) -> Result<[ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT]> {
164 Ok(self.map(|v| match v.0 {
165 ManifestExtEntryVar::Name(name) => ManifestExtTableEntry {
166 identifier: name.into(),
167 offset: 0,
168 },
169 ManifestExtEntryVar::IdOffset { identifier, offset } => ManifestExtTableEntry {
170 identifier: identifier.into(),
171 offset,
172 },
173 _ => ManifestExtTableEntry {
174 identifier: 0,
175 offset: 0,
176 },
177 }))
178 }
179
180 fn overwrite(&mut self, o: Self) {
181 for i in 0..self.len() {
182 match o[i].0 {
183 ManifestExtEntryVar::Name(other_id) => match self[i].0 {
184 ManifestExtEntryVar::IdOffset {
185 identifier: self_id,
186 offset: _,
187 } => {
188 if self_id == other_id {
189 continue;
191 } else {
192 self[i].0 = o[i].0.clone()
193 }
194 }
195 _ => self[i].0 = o[i].0.clone(),
196 },
197 ManifestExtEntryVar::None => (),
198 _ => self[i].0 = o[i].0.clone(),
199 }
200 }
201 }
202}
203
204impl<T: ParseInt + fmt::LowerHex> ManifestPacked<T> for ManifestSmallInt<T> {
205 fn unpack(self, name: &'static str) -> Result<T> {
206 match self.0 {
207 Some(v) => Ok(v.0),
208 None => self.unpack_err(name),
209 }
210 }
211
212 fn overwrite(&mut self, o: Self) {
213 if o.0.is_some() {
214 *self = o;
215 }
216 }
217}
218
219impl<T: ParseInt + fmt::LowerHex, const N: usize> ManifestPacked<[T; N]>
220 for [ManifestSmallInt<T>; N]
221{
222 fn unpack(self, name: &'static str) -> Result<[T; N]> {
223 let results = self.map(|e| e.unpack(name));
224 if let Some(err_idx) = results.iter().position(Result::is_err) {
225 IntoIterator::into_iter(results).nth(err_idx).unwrap()?;
226 unreachable!();
227 } else {
228 Ok(results.map(|x| x.unwrap()))
229 }
230 }
231
232 fn overwrite(&mut self, o: Self) {
233 if o.iter().all(|v| v.0.is_some()) {
235 *self = o;
236 }
237 }
238}
239
240manifest_def! {
241 pub struct ManifestSpec {
242 signature: ManifestSigverifyBigInt,
243 usage_constraints: ManifestUsageConstraintsDef,
244 pub_key: ManifestSigverifyBigInt,
245 address_translation: ManifestSmallInt<u32>,
246 identifier: ManifestSmallInt<u32>,
247 manifest_version: ManifestVersionDef,
248 signed_region_end: ManifestSmallInt<u32>,
249 length: ManifestSmallInt<u32>,
250 version_major: ManifestSmallInt<u32>,
251 version_minor: ManifestSmallInt<u32>,
252 security_version: ManifestSmallInt<u32>,
253 timestamp: [ManifestSmallInt<u32>; 2],
254 binding_value: [ManifestSmallInt<u32>; 8],
255 max_key_version: ManifestSmallInt<u32>,
256 code_start: ManifestSmallInt<u32>,
257 code_end: ManifestSmallInt<u32>,
258 entry_point: ManifestSmallInt<u32>,
259 extensions: [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT],
260 }, Manifest
261}
262
263manifest_def! {
264 pub struct ManifestUsageConstraintsDef {
265 selector_bits: ManifestSmallInt<u32>,
266 device_id: [ManifestSmallInt<u32>; 8],
267 manuf_state_creator: ManifestSmallInt<u32>,
268 manuf_state_owner: ManifestSmallInt<u32>,
269 life_cycle_state: ManifestSmallInt<u32>,
270 }, ManifestUsageConstraints
271}
272
273manifest_def! {
274 pub struct ManifestVersionDef {
275 minor: ManifestSmallInt<u16>,
276 major: ManifestSmallInt<u16>,
277 }, ManifestVersion
278}
279
280#[derive(Clone, Default, Deserialize, Serialize, Debug)]
281#[serde(untagged)]
282enum ManifestExtEntryVar {
283 #[default]
284 None,
285 Name(ManifestExtId),
286 IdOffset {
287 identifier: ManifestExtId,
288 offset: u32,
289 },
290}
291
292#[derive(Clone, Default, Deserialize, Serialize, Debug)]
293pub struct ManifestExtTableEntryDef(ManifestExtEntryVar);
294
295impl TryFrom<ManifestSigverifyBuffer> for SigverifyBuffer {
296 type Error = anyhow::Error;
297
298 fn try_from(buffer: ManifestSigverifyBuffer) -> Result<SigverifyBuffer> {
299 if buffer.eq(&ManifestSigverifyBuffer::from_le_bytes([0])?) {
300 Ok(SigverifyBuffer {
303 data: le_slice_to_arr(&[0]),
304 })
305 } else {
306 Ok(SigverifyBuffer {
308 data: le_bytes_to_word_arr(&buffer.to_le_bytes())?,
309 })
310 }
311 }
312}
313
314pub(crate) fn le_bytes_to_word_arr<const N: usize>(bytes: &[u8]) -> Result<[u32; N]> {
315 Ok(le_slice_to_arr(
316 bytes
317 .chunks(4)
318 .map(|v| Ok(u32::from_le_bytes(le_slice_to_arr(v))))
319 .collect::<Result<Vec<u32>>>()?
320 .as_slice(),
321 ))
322}
323
324fn le_slice_to_arr<T: Default + Copy, const N: usize>(slice: &[T]) -> [T; N] {
329 let mut arr = [T::default(); N];
330 arr[..slice.len()].copy_from_slice(slice);
331 arr
332}
333
334impl TryFrom<[u32; 96]> for SigverifyBuffer {
335 type Error = anyhow::Error;
336
337 fn try_from(words: [u32; 96]) -> Result<SigverifyBuffer> {
338 Ok(SigverifyBuffer { data: words })
339 }
340}
341
342impl TryFrom<[u32; 8]> for KeymgrBindingValue {
343 type Error = anyhow::Error;
344
345 fn try_from(words: [u32; 8]) -> Result<KeymgrBindingValue> {
346 Ok(KeymgrBindingValue { data: words })
347 }
348}
349
350impl TryFrom<[u32; 2]> for Timestamp {
351 type Error = anyhow::Error;
352
353 fn try_from(words: [u32; 2]) -> Result<Timestamp> {
354 Ok(Timestamp {
355 timestamp_low: words[0],
356 timestamp_high: words[1],
357 })
358 }
359}
360
361impl TryFrom<[u32; 8]> for LifecycleDeviceId {
362 type Error = anyhow::Error;
363
364 fn try_from(words: [u32; 8]) -> Result<LifecycleDeviceId> {
365 Ok(LifecycleDeviceId { device_id: words })
366 }
367}
368
369impl TryFrom<SigverifyBuffer> for ManifestSigverifyBigInt {
370 type Error = anyhow::Error;
371
372 fn try_from(o: SigverifyBuffer) -> Result<ManifestSigverifyBigInt> {
373 (&o).try_into()
374 }
375}
376
377impl TryFrom<&SigverifyBuffer> for ManifestSigverifyBigInt {
378 type Error = anyhow::Error;
379
380 fn try_from(o: &SigverifyBuffer) -> Result<ManifestSigverifyBigInt> {
381 let rsa = ManifestSigverifyBuffer::from_le_bytes(o.data.as_bytes())?;
382 Ok(ManifestSigverifyBigInt(Some(HexEncoded(rsa))))
383 }
384}
385
386impl<T> From<&T> for ManifestSmallInt<T>
387where
388 T: ParseInt + fmt::LowerHex + Copy,
389{
390 fn from(o: &T) -> ManifestSmallInt<T> {
391 ManifestSmallInt(Some(HexEncoded(*o)))
392 }
393}
394
395impl From<&KeymgrBindingValue> for [ManifestSmallInt<u32>; 8] {
396 fn from(o: &KeymgrBindingValue) -> [ManifestSmallInt<u32>; 8] {
397 o.data.map(|v| ManifestSmallInt(Some(HexEncoded(v))))
398 }
399}
400impl From<&Timestamp> for [ManifestSmallInt<u32>; 2] {
401 fn from(o: &Timestamp) -> [ManifestSmallInt<u32>; 2] {
402 [
403 ManifestSmallInt(Some(HexEncoded(o.timestamp_low))),
404 ManifestSmallInt(Some(HexEncoded(o.timestamp_high))),
405 ]
406 }
407}
408
409impl From<&LifecycleDeviceId> for [ManifestSmallInt<u32>; 8] {
410 fn from(o: &LifecycleDeviceId) -> [ManifestSmallInt<u32>; 8] {
411 o.device_id.map(|v| ManifestSmallInt(Some(HexEncoded(v))))
412 }
413}
414
415impl From<&ManifestExtTableEntry> for ManifestExtTableEntryDef {
416 fn from(o: &ManifestExtTableEntry) -> ManifestExtTableEntryDef {
417 ManifestExtTableEntryDef(ManifestExtEntryVar::IdOffset {
418 identifier: ManifestExtId(o.identifier),
419 offset: o.offset,
420 })
421 }
422}
423
424impl From<[ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT]> for ManifestExtTable {
425 fn from(o: [ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT]) -> ManifestExtTable {
426 ManifestExtTable { entries: o }
427 }
428}
429
430impl From<&ManifestExtTable> for [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT] {
431 fn from(o: &ManifestExtTable) -> [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT] {
432 o.entries.map(|v| (&v).into())
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439 use crate::util::testdata;
440 use deser_hjson::from_str;
441
442 #[test]
443 fn test_manifest_from_hjson() {
444 let def: ManifestSpec =
445 from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
446
447 let _: Manifest = def.try_into().unwrap();
448 }
449
450 #[test]
451 fn test_manifest_from_hjson_missing() {
452 let def: ManifestSpec =
453 from_str(&std::fs::read_to_string(testdata("image/manifest_missing.hjson")).unwrap())
454 .unwrap();
455
456 let res: Result<Manifest> = def.try_into();
457 assert!(res.is_err())
458 }
459
460 #[test]
461 fn test_manifest_overwrite() {
462 let mut base: ManifestSpec =
463 from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
464 let other = ManifestSpec {
465 identifier: from_str("0xabcd").unwrap(),
466 binding_value: from_str(stringify!(["0", "1", "2", "3", "4", "5", "6", "7"])).unwrap(),
467 ..Default::default()
468 };
469 base.overwrite(other);
470 assert_eq!(base.identifier.0.unwrap().0, 0xabcd);
471 assert_eq!(
472 base.binding_value.map(|v| v.0.unwrap().0)[..],
473 [0, 1, 2, 3, 4, 5, 6, 7]
474 );
475
476 assert_eq!(base.address_translation.0.unwrap().0, 0x739);
478 }
479
480 #[test]
481 fn test_manifest_convert() {
482 let def1: ManifestSpec =
483 from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
484 let def2 = def1.clone();
485
486 let bin1: Manifest = def1.try_into().unwrap();
487 let bin2: Manifest = def2.try_into().unwrap();
488
489 let redef: ManifestSpec = (&bin1).try_into().unwrap();
490 let rebin: Manifest = redef.try_into().unwrap();
491 assert_eq!(bin2.as_bytes(), rebin.as_bytes());
492 }
493}