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 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
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            usage_constraints: self.usage_constraints.unpack("usage_constraints")?,
307            pub_key: self.pub_key.unpack("pub_key")?.try_into()?,
308            address_translation: self.address_translation.unpack("address_translation")?,
309            identifier: self.identifier.unpack("identifier")?,
310            manifest_version: self.manifest_version.unpack("manifest_version")?,
311            signed_region_end: self.signed_region_end.unpack("signed_region_end")?,
312            length: self.length.unpack("length")?,
313            version_major: self.version_major.unpack("version_major")?,
314            version_minor: self.version_minor.unpack("version_minor")?,
315            security_version: self.security_version.unpack("security_version")?,
316            timestamp: self.timestamp.unpack("timestamp")?.try_into()?,
317            binding_value: self.binding_value.unpack("binding_value")?.try_into()?,
318            max_key_version: self.max_key_version.unpack("max_key_version")?,
319            code_start: self.code_start.unpack("code_start")?,
320            code_end: self.code_end.unpack("code_end")?,
321            entry_point: self.entry_point.unpack("entry_point")?,
322            extensions: self.extensions.unpack("extensions")?.into(),
323        })
324    }
325
326    fn overwrite(&mut self, o: ManifestSpec) {
327        self.signature.overwrite(o.signature);
328        self.usage_constraints.overwrite(o.usage_constraints);
329        self.pub_key.overwrite(o.pub_key);
330        self.address_translation.overwrite(o.address_translation);
331        self.identifier.overwrite(o.identifier);
332        self.manifest_version.overwrite(o.manifest_version);
333        self.signed_region_end.overwrite(o.signed_region_end);
334        self.length.overwrite(o.length);
335        self.version_major.overwrite(o.version_major);
336        self.version_minor.overwrite(o.version_minor);
337        self.security_version.overwrite(o.security_version);
338        self.timestamp.overwrite(o.timestamp);
339        self.binding_value.overwrite(o.binding_value);
340        self.max_key_version.overwrite(o.max_key_version);
341        self.code_start.overwrite(o.code_start);
342        self.code_end.overwrite(o.code_end);
343        self.entry_point.overwrite(o.entry_point);
344        self.extensions.overwrite(o.extensions);
345        // TODO(moidx): Implement extension_params overwrite.
346        // Extension params are not overwritten.
347    }
348}
349
350impl TryInto<Manifest> for ManifestSpec {
351    type Error = anyhow::Error;
352
353    fn try_into(self) -> Result<Manifest> {
354        self.unpack("")
355    }
356}
357
358impl TryFrom<&Manifest> for ManifestSpec {
359    type Error = anyhow::Error;
360
361    fn try_from(o: &Manifest) -> Result<Self> {
362        Ok(ManifestSpec {
363            signature: (&o.signature).try_into()?,
364            usage_constraints: (&o.usage_constraints).try_into()?,
365            pub_key: (&o.pub_key).try_into()?,
366            address_translation: (&o.address_translation).into(),
367            identifier: (&o.identifier).into(),
368            manifest_version: (&o.manifest_version).try_into()?,
369            signed_region_end: (&o.signed_region_end).into(),
370            length: (&o.length).into(),
371            version_major: (&o.version_major).into(),
372            version_minor: (&o.version_minor).into(),
373            security_version: (&o.security_version).into(),
374            timestamp: (&o.timestamp).into(),
375            binding_value: (&o.binding_value).into(),
376            max_key_version: (&o.max_key_version).into(),
377            code_start: (&o.code_start).into(),
378            code_end: (&o.code_end).into(),
379            entry_point: (&o.entry_point).into(),
380            extensions: (&o.extensions).into(),
381
382            // TODO(moidx): Implement extension_params extraction from Manifest.
383            extension_params: Vec::new(),
384        })
385    }
386}
387
388manifest_def! {
389    pub struct ManifestUsageConstraintsDef {
390        selector_bits: ManifestSmallInt<u32>,
391        device_id: [ManifestSmallInt<u32>; 8],
392        manuf_state_creator: ManifestSmallInt<u32>,
393        manuf_state_owner: ManifestSmallInt<u32>,
394        life_cycle_state: ManifestSmallInt<u32>,
395    }, ManifestUsageConstraints
396}
397
398manifest_def! {
399    pub struct ManifestVersionDef {
400        minor: ManifestSmallInt<u16>,
401        major: ManifestSmallInt<u16>,
402    }, ManifestVersion
403}
404
405#[derive(Clone, Default, Deserialize, Serialize, Debug)]
406#[serde(untagged)]
407enum ManifestExtEntryVar {
408    #[default]
409    None,
410    Name(ManifestExtId),
411    IdOffset {
412        identifier: ManifestExtId,
413        offset: u32,
414    },
415}
416
417#[derive(Clone, Default, Deserialize, Serialize, Debug)]
418pub struct ManifestExtTableEntryDef(ManifestExtEntryVar);
419
420impl TryFrom<ManifestSigverifyBuffer> for SigverifyBuffer {
421    type Error = anyhow::Error;
422
423    fn try_from(buffer: ManifestSigverifyBuffer) -> Result<SigverifyBuffer> {
424        if buffer.eq(&ManifestSigverifyBuffer::from_le_bytes([0])?) {
425            // In the case where the BigInt fields are defined but == 0 we should just keep it 0.
426            // Without this the conversion to [u32; 96] would fail.
427            Ok(SigverifyBuffer {
428                data: le_slice_to_arr(&[0]),
429            })
430        } else {
431            // Convert between the BigInt byte representation and the manifest word representation.
432            Ok(SigverifyBuffer {
433                data: le_bytes_to_word_arr(&buffer.to_le_bytes())?,
434            })
435        }
436    }
437}
438
439pub(crate) fn le_bytes_to_word_arr<const N: usize>(bytes: &[u8]) -> Result<[u32; N]> {
440    Ok(le_slice_to_arr(
441        bytes
442            .chunks(4)
443            .map(|v| Ok(u32::from_le_bytes(le_slice_to_arr(v))))
444            .collect::<Result<Vec<u32>>>()?
445            .as_slice(),
446    ))
447}
448
449/// Takes a slice with LE element ordering and pads the MSBs with 0 to produce a fixed length array
450///
451/// This is similar to using `try_into()` but does not have the requirement that the slice has
452/// exactly the correct length.
453fn le_slice_to_arr<T: Default + Copy, const N: usize>(slice: &[T]) -> [T; N] {
454    let mut arr = [T::default(); N];
455    arr[..slice.len()].copy_from_slice(slice);
456    arr
457}
458
459impl TryFrom<[u32; 96]> for SigverifyBuffer {
460    type Error = anyhow::Error;
461
462    fn try_from(words: [u32; 96]) -> Result<SigverifyBuffer> {
463        Ok(SigverifyBuffer { data: words })
464    }
465}
466
467impl TryFrom<[u32; 8]> for KeymgrBindingValue {
468    type Error = anyhow::Error;
469
470    fn try_from(words: [u32; 8]) -> Result<KeymgrBindingValue> {
471        Ok(KeymgrBindingValue { data: words })
472    }
473}
474
475impl TryFrom<[u32; 2]> for Timestamp {
476    type Error = anyhow::Error;
477
478    fn try_from(words: [u32; 2]) -> Result<Timestamp> {
479        Ok(Timestamp {
480            timestamp_low: words[0],
481            timestamp_high: words[1],
482        })
483    }
484}
485
486impl TryFrom<[u32; 8]> for LifecycleDeviceId {
487    type Error = anyhow::Error;
488
489    fn try_from(words: [u32; 8]) -> Result<LifecycleDeviceId> {
490        Ok(LifecycleDeviceId { device_id: words })
491    }
492}
493
494impl TryFrom<SigverifyBuffer> for ManifestSigverifyBigInt {
495    type Error = anyhow::Error;
496
497    fn try_from(o: SigverifyBuffer) -> Result<ManifestSigverifyBigInt> {
498        (&o).try_into()
499    }
500}
501
502impl TryFrom<&SigverifyBuffer> for ManifestSigverifyBigInt {
503    type Error = anyhow::Error;
504
505    fn try_from(o: &SigverifyBuffer) -> Result<ManifestSigverifyBigInt> {
506        let rsa = ManifestSigverifyBuffer::from_le_bytes(o.data.as_bytes())?;
507        Ok(ManifestSigverifyBigInt(Some(HexEncoded(rsa))))
508    }
509}
510
511impl<T> From<&T> for ManifestSmallInt<T>
512where
513    T: ParseInt + fmt::LowerHex + Copy,
514{
515    fn from(o: &T) -> ManifestSmallInt<T> {
516        ManifestSmallInt(Some(HexEncoded(*o)))
517    }
518}
519
520impl From<&KeymgrBindingValue> for [ManifestSmallInt<u32>; 8] {
521    fn from(o: &KeymgrBindingValue) -> [ManifestSmallInt<u32>; 8] {
522        o.data.map(|v| ManifestSmallInt(Some(HexEncoded(v))))
523    }
524}
525impl From<&Timestamp> for [ManifestSmallInt<u32>; 2] {
526    fn from(o: &Timestamp) -> [ManifestSmallInt<u32>; 2] {
527        [
528            ManifestSmallInt(Some(HexEncoded(o.timestamp_low))),
529            ManifestSmallInt(Some(HexEncoded(o.timestamp_high))),
530        ]
531    }
532}
533
534impl From<&LifecycleDeviceId> for [ManifestSmallInt<u32>; 8] {
535    fn from(o: &LifecycleDeviceId) -> [ManifestSmallInt<u32>; 8] {
536        o.device_id.map(|v| ManifestSmallInt(Some(HexEncoded(v))))
537    }
538}
539
540impl From<&ManifestExtTableEntry> for ManifestExtTableEntryDef {
541    fn from(o: &ManifestExtTableEntry) -> ManifestExtTableEntryDef {
542        ManifestExtTableEntryDef(ManifestExtEntryVar::IdOffset {
543            identifier: ManifestExtId(o.identifier),
544            offset: o.offset,
545        })
546    }
547}
548
549impl From<[ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT]> for ManifestExtTable {
550    fn from(o: [ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT]) -> ManifestExtTable {
551        ManifestExtTable { entries: o }
552    }
553}
554
555impl From<&ManifestExtTable> for [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT] {
556    fn from(o: &ManifestExtTable) -> [ManifestExtTableEntryDef; CHIP_MANIFEST_EXT_TABLE_COUNT] {
557        o.entries.map(|v| (&v).into())
558    }
559}
560
561#[cfg(test)]
562mod tests {
563    use super::*;
564    use crate::util::testdata;
565    use deser_hjson::from_str;
566
567    #[test]
568    fn test_manifest_from_hjson() {
569        let def: ManifestSpec =
570            from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
571
572        let _: Manifest = def.try_into().unwrap();
573    }
574
575    #[test]
576    fn test_manifest_from_hjson_missing() {
577        let def: ManifestSpec =
578            from_str(&std::fs::read_to_string(testdata("image/manifest_missing.hjson")).unwrap())
579                .unwrap();
580
581        let res: Result<Manifest> = def.try_into();
582        assert!(res.is_err())
583    }
584
585    #[test]
586    fn test_manifest_overwrite() {
587        let mut base: ManifestSpec =
588            from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
589        let other = ManifestSpec {
590            identifier: from_str("0xabcd").unwrap(),
591            binding_value: from_str(stringify!(["0", "1", "2", "3", "4", "5", "6", "7"])).unwrap(),
592            ..Default::default()
593        };
594        base.overwrite(other);
595        assert_eq!(base.identifier.0.unwrap().0, 0xabcd);
596        assert_eq!(
597            base.binding_value.map(|v| v.0.unwrap().0)[..],
598            [0, 1, 2, 3, 4, 5, 6, 7]
599        );
600
601        // Ensure unspecified fields are not overwritten.
602        assert_eq!(base.address_translation.0.unwrap().0, 0x739);
603    }
604
605    #[test]
606    fn test_manifest_convert() {
607        let def1: ManifestSpec =
608            from_str(&std::fs::read_to_string(testdata("image/manifest.hjson")).unwrap()).unwrap();
609        let def2 = def1.clone();
610
611        let bin1: Manifest = def1.try_into().unwrap();
612        let bin2: Manifest = def2.try_into().unwrap();
613
614        let redef: ManifestSpec = (&bin1).try_into().unwrap();
615        let rebin: Manifest = redef.try_into().unwrap();
616        assert_eq!(bin2.as_bytes(), rebin.as_bytes());
617    }
618}