opentitanlib/image/
manifest_def.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use crate::image::manifest::*;
6use crate::image::manifest_ext::{ManifestExtEntrySpec, 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 512);
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
41/// A macro for wrapping manifest struct definitions that parse from HJSON.
42///
43/// The #[repr(C)] version of `Manifest` can only be built when the fields in `ManifestSpec` are
44/// present. This macro sets up the field by field conversion and provides the field names for
45/// purposes of error reporting.
46macro_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                    // Call `unpack()` on each field with the field's name included for use in
66                    // error messages.
67                    $($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    /// The default error for missing fields.
131    fn unpack_err(&self, name: &'static str) -> Result<T> {
132        bail!(ManifestError::MissingField(name))
133    }
134
135    /// Unpack optional fields in the manifest, and error if the field isn't defined.
136    fn unpack(self, name: &'static str) -> Result<T>;
137
138    /// Overwrite manifest field.
139    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                            // Do not overwrite existing entries with matching IDs.
190                            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        // Only perform the overwrite if all elements of `o` are present.
234        if o.iter().all(|v| v.0.is_some()) {
235            *self = o;
236        }
237    }
238}
239
240#[derive(Clone, Default, Deserialize, Serialize, Debug)]
241pub struct ManifestSpec {
242    #[serde(default)]
243    signature: ManifestSigverifyBigInt,
244
245    #[serde(default)]
246    usage_constraints: ManifestUsageConstraintsDef,
247
248    #[serde(default)]
249    pub_key: ManifestSigverifyBigInt,
250
251    #[serde(default)]
252    address_translation: ManifestSmallInt<u32>,
253
254    #[serde(default)]
255    identifier: ManifestSmallInt<u32>,
256
257    #[serde(default)]
258    manifest_version: ManifestVersionDef,
259
260    #[serde(default)]
261    signed_region_end: ManifestSmallInt<u32>,
262
263    #[serde(default)]
264    length: ManifestSmallInt<u32>,
265
266    #[serde(default)]
267    version_major: ManifestSmallInt<u32>,
268
269    #[serde(default)]
270    version_minor: ManifestSmallInt<u32>,
271
272    #[serde(default)]
273    security_version: ManifestSmallInt<u32>,
274
275    #[serde(default)]
276    timestamp: [ManifestSmallInt<u32>; 2],
277
278    #[serde(default)]
279    binding_value: [ManifestSmallInt<u32>; 8],
280
281    #[serde(default)]
282    max_key_version: ManifestSmallInt<u32>,
283
284    #[serde(default)]
285    code_start: ManifestSmallInt<u32>,
286
287    #[serde(default)]
288    code_end: ManifestSmallInt<u32>,
289
290    #[serde(default)]
291    entry_point: ManifestSmallInt<u32>,
292
293    #[serde(default)]
294    extensions: [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT],
295
296    #[serde(default)]
297    pub extension_params: Vec<ManifestExtEntrySpec>,
298}
299
300impl ManifestPacked<Manifest> for ManifestSpec {
301    fn unpack(self, _name: &'static str) -> Result<Manifest> {
302        Ok(Manifest {
303            // Call `unpack()` on each field with the field's name included for use in
304            // error messages.
305            signature: self.signature.unpack("signature")?.try_into()?,
306            reserved_signature: Default::default(),
307            reserved_unsigned: Default::default(),
308            usage_constraints: self.usage_constraints.unpack("usage_constraints")?,
309            pub_key: self.pub_key.unpack("pub_key")?.try_into()?,
310            reserved_public_key: Default::default(),
311            reserved: Default::default(),
312            address_translation: self.address_translation.unpack("address_translation")?,
313            identifier: self.identifier.unpack("identifier")?,
314            manifest_version: self.manifest_version.unpack("manifest_version")?,
315            signed_region_end: self.signed_region_end.unpack("signed_region_end")?,
316            length: self.length.unpack("length")?,
317            version_major: self.version_major.unpack("version_major")?,
318            version_minor: self.version_minor.unpack("version_minor")?,
319            security_version: self.security_version.unpack("security_version")?,
320            timestamp: self.timestamp.unpack("timestamp")?.try_into()?,
321            binding_value: self.binding_value.unpack("binding_value")?.try_into()?,
322            max_key_version: self.max_key_version.unpack("max_key_version")?,
323            code_start: self.code_start.unpack("code_start")?,
324            code_end: self.code_end.unpack("code_end")?,
325            entry_point: self.entry_point.unpack("entry_point")?,
326            extensions: self.extensions.unpack("extensions")?.into(),
327        })
328    }
329
330    fn overwrite(&mut self, o: ManifestSpec) {
331        self.signature.overwrite(o.signature);
332        self.usage_constraints.overwrite(o.usage_constraints);
333        self.pub_key.overwrite(o.pub_key);
334        self.address_translation.overwrite(o.address_translation);
335        self.identifier.overwrite(o.identifier);
336        self.manifest_version.overwrite(o.manifest_version);
337        self.signed_region_end.overwrite(o.signed_region_end);
338        self.length.overwrite(o.length);
339        self.version_major.overwrite(o.version_major);
340        self.version_minor.overwrite(o.version_minor);
341        self.security_version.overwrite(o.security_version);
342        self.timestamp.overwrite(o.timestamp);
343        self.binding_value.overwrite(o.binding_value);
344        self.max_key_version.overwrite(o.max_key_version);
345        self.code_start.overwrite(o.code_start);
346        self.code_end.overwrite(o.code_end);
347        self.entry_point.overwrite(o.entry_point);
348        self.extensions.overwrite(o.extensions);
349        // TODO(moidx): Implement extension_params overwrite.
350        // Extension params are not overwritten.
351    }
352}
353
354impl TryInto<Manifest> for ManifestSpec {
355    type Error = anyhow::Error;
356
357    fn try_into(self) -> Result<Manifest> {
358        self.unpack("")
359    }
360}
361
362impl TryFrom<&Manifest> for ManifestSpec {
363    type Error = anyhow::Error;
364
365    fn try_from(o: &Manifest) -> Result<Self> {
366        Ok(ManifestSpec {
367            signature: (&o.signature).try_into()?,
368            usage_constraints: (&o.usage_constraints).try_into()?,
369            pub_key: (&o.pub_key).try_into()?,
370            address_translation: (&o.address_translation).into(),
371            identifier: (&o.identifier).into(),
372            manifest_version: (&o.manifest_version).try_into()?,
373            signed_region_end: (&o.signed_region_end).into(),
374            length: (&o.length).into(),
375            version_major: (&o.version_major).into(),
376            version_minor: (&o.version_minor).into(),
377            security_version: (&o.security_version).into(),
378            timestamp: (&o.timestamp).into(),
379            binding_value: (&o.binding_value).into(),
380            max_key_version: (&o.max_key_version).into(),
381            code_start: (&o.code_start).into(),
382            code_end: (&o.code_end).into(),
383            entry_point: (&o.entry_point).into(),
384            extensions: (&o.extensions).into(),
385
386            // TODO(moidx): Implement extension_params extraction from Manifest.
387            extension_params: Vec::new(),
388        })
389    }
390}
391
392manifest_def! {
393    pub struct ManifestUsageConstraintsDef {
394        selector_bits: ManifestSmallInt<u32>,
395        device_id: [ManifestSmallInt<u32>; 8],
396        manuf_state_creator: ManifestSmallInt<u32>,
397        manuf_state_owner: ManifestSmallInt<u32>,
398        life_cycle_state: ManifestSmallInt<u32>,
399    }, ManifestUsageConstraints
400}
401
402manifest_def! {
403    pub struct ManifestVersionDef {
404        minor: ManifestSmallInt<u16>,
405        major: ManifestSmallInt<u16>,
406    }, ManifestVersion
407}
408
409#[derive(Clone, Default, Deserialize, Serialize, Debug)]
410#[serde(untagged)]
411enum ManifestExtEntryVar {
412    #[default]
413    None,
414    Name(ManifestExtId),
415    IdOffset {
416        identifier: ManifestExtId,
417        offset: u32,
418    },
419}
420
421#[derive(Clone, Default, Deserialize, Serialize, Debug)]
422pub struct ManifestExtTableEntryDef(ManifestExtEntryVar);
423
424impl TryFrom<ManifestSigverifyBuffer> for SigverifyBuffer {
425    type Error = anyhow::Error;
426
427    fn try_from(buffer: ManifestSigverifyBuffer) -> Result<SigverifyBuffer> {
428        if buffer.eq(&ManifestSigverifyBuffer::from_le_bytes([0])?) {
429            // In the case where the BigInt fields are defined but == 0 we should just keep it 0.
430            // Without this the conversion to [u32; 16] would fail.
431            Ok(SigverifyBuffer {
432                data: le_slice_to_arr(&[0]),
433            })
434        } else {
435            // Convert between the BigInt byte representation and the manifest word representation.
436            Ok(SigverifyBuffer {
437                data: le_bytes_to_word_arr(&buffer.to_le_bytes())?,
438            })
439        }
440    }
441}
442
443pub(crate) fn le_bytes_to_word_arr<const N: usize>(bytes: &[u8]) -> Result<[u32; N]> {
444    Ok(le_slice_to_arr(
445        bytes
446            .chunks(4)
447            .map(|v| Ok(u32::from_le_bytes(le_slice_to_arr(v))))
448            .collect::<Result<Vec<u32>>>()?
449            .as_slice(),
450    ))
451}
452
453/// Takes a slice with LE element ordering and pads the MSBs with 0 to produce a fixed length array
454///
455/// This is similar to using `try_into()` but does not have the requirement that the slice has
456/// exactly the correct length.
457fn le_slice_to_arr<T: Default + Copy, const N: usize>(slice: &[T]) -> [T; N] {
458    let mut arr = [T::default(); N];
459    arr[..slice.len()].copy_from_slice(slice);
460    arr
461}
462
463impl TryFrom<[u32; 16]> for SigverifyBuffer {
464    type Error = anyhow::Error;
465
466    fn try_from(words: [u32; 16]) -> Result<SigverifyBuffer> {
467        Ok(SigverifyBuffer { data: words })
468    }
469}
470
471impl TryFrom<[u32; 8]> for KeymgrBindingValue {
472    type Error = anyhow::Error;
473
474    fn try_from(words: [u32; 8]) -> Result<KeymgrBindingValue> {
475        Ok(KeymgrBindingValue { data: words })
476    }
477}
478
479impl TryFrom<[u32; 2]> for Timestamp {
480    type Error = anyhow::Error;
481
482    fn try_from(words: [u32; 2]) -> Result<Timestamp> {
483        Ok(Timestamp {
484            timestamp_low: words[0],
485            timestamp_high: words[1],
486        })
487    }
488}
489
490impl TryFrom<[u32; 8]> for LifecycleDeviceId {
491    type Error = anyhow::Error;
492
493    fn try_from(words: [u32; 8]) -> Result<LifecycleDeviceId> {
494        Ok(LifecycleDeviceId { device_id: words })
495    }
496}
497
498impl TryFrom<SigverifyBuffer> for ManifestSigverifyBigInt {
499    type Error = anyhow::Error;
500
501    fn try_from(o: SigverifyBuffer) -> Result<ManifestSigverifyBigInt> {
502        (&o).try_into()
503    }
504}
505
506impl TryFrom<&SigverifyBuffer> for ManifestSigverifyBigInt {
507    type Error = anyhow::Error;
508
509    fn try_from(o: &SigverifyBuffer) -> Result<ManifestSigverifyBigInt> {
510        let rsa = ManifestSigverifyBuffer::from_le_bytes(o.data.as_bytes())?;
511        Ok(ManifestSigverifyBigInt(Some(HexEncoded(rsa))))
512    }
513}
514
515impl<T> From<&T> for ManifestSmallInt<T>
516where
517    T: ParseInt + fmt::LowerHex + Copy,
518{
519    fn from(o: &T) -> ManifestSmallInt<T> {
520        ManifestSmallInt(Some(HexEncoded(*o)))
521    }
522}
523
524impl From<&KeymgrBindingValue> for [ManifestSmallInt<u32>; 8] {
525    fn from(o: &KeymgrBindingValue) -> [ManifestSmallInt<u32>; 8] {
526        o.data.map(|v| ManifestSmallInt(Some(HexEncoded(v))))
527    }
528}
529impl From<&Timestamp> for [ManifestSmallInt<u32>; 2] {
530    fn from(o: &Timestamp) -> [ManifestSmallInt<u32>; 2] {
531        [
532            ManifestSmallInt(Some(HexEncoded(o.timestamp_low))),
533            ManifestSmallInt(Some(HexEncoded(o.timestamp_high))),
534        ]
535    }
536}
537
538impl From<&LifecycleDeviceId> for [ManifestSmallInt<u32>; 8] {
539    fn from(o: &LifecycleDeviceId) -> [ManifestSmallInt<u32>; 8] {
540        o.device_id.map(|v| ManifestSmallInt(Some(HexEncoded(v))))
541    }
542}
543
544impl From<&ManifestExtTableEntry> for ManifestExtTableEntryDef {
545    fn from(o: &ManifestExtTableEntry) -> ManifestExtTableEntryDef {
546        ManifestExtTableEntryDef(ManifestExtEntryVar::IdOffset {
547            identifier: ManifestExtId(o.identifier),
548            offset: o.offset,
549        })
550    }
551}
552
553impl From<[ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT]> for ManifestExtTable {
554    fn from(o: [ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT]) -> ManifestExtTable {
555        ManifestExtTable { entries: o }
556    }
557}
558
559impl From<&ManifestExtTable> for [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT] {
560    fn from(o: &ManifestExtTable) -> [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT] {
561        o.entries.map(|v| (&v).into())
562    }
563}
564
565#[cfg(test)]
566mod tests {
567    use super::*;
568    use crate::util::testdata;
569    use deser_hjson::from_str;
570
571    #[test]
572    fn test_manifest_from_hjson() {
573        let def: ManifestSpec =
574            from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
575
576        let _: Manifest = def.try_into().unwrap();
577    }
578
579    #[test]
580    fn test_manifest_from_hjson_missing() {
581        let def: ManifestSpec =
582            from_str(&std::fs::read_to_string(testdata("image/manifest_missing.hjson")).unwrap())
583                .unwrap();
584
585        let res: Result<Manifest> = def.try_into();
586        assert!(res.is_err())
587    }
588
589    #[test]
590    fn test_manifest_overwrite() {
591        let mut base: ManifestSpec =
592            from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
593        let other = ManifestSpec {
594            identifier: from_str("0xabcd").unwrap(),
595            binding_value: from_str(stringify!(["0", "1", "2", "3", "4", "5", "6", "7"])).unwrap(),
596            ..Default::default()
597        };
598        base.overwrite(other);
599        assert_eq!(base.identifier.0.unwrap().0, 0xabcd);
600        assert_eq!(
601            base.binding_value.map(|v| v.0.unwrap().0)[..],
602            [0, 1, 2, 3, 4, 5, 6, 7]
603        );
604
605        // Ensure unspecified fields are not overwritten.
606        assert_eq!(base.address_translation.0.unwrap().0, 0x739);
607    }
608
609    #[test]
610    fn test_manifest_convert() {
611        let def1: ManifestSpec =
612            from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
613        let def2 = def1.clone();
614
615        let bin1: Manifest = def1.try_into().unwrap();
616        let bin2: Manifest = def2.try_into().unwrap();
617
618        let redef: ManifestSpec = (&bin1).try_into().unwrap();
619        let rebin: Manifest = redef.try_into().unwrap();
620        assert_eq!(bin2.as_bytes(), rebin.as_bytes());
621    }
622}