1#![deny(warnings)]
11#![deny(unused)]
12#![deny(unsafe_code)]
13
14use crate::with_unknown;
15use anyhow::Result;
16use byteorder::{LittleEndian, WriteBytesExt};
17use serde::{Deserialize, Serialize};
18use serde_annotate::Annotate;
19use std::io::Write;
20use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
21
22pub const CHIP_MANIFEST_SIZE: u32 = 1024;
35
36pub const CHIP_MANIFEST_VERSION_MAJOR2: u16 = 0x0002;
39pub const CHIP_MANIFEST_VERSION_MINOR1: u16 = 0x6c47;
40pub const CHIP_MANIFEST_VERSION_MAJOR1: u16 = 0x71c3;
41pub const CHIP_MANIFEST_EXT_TABLE_COUNT: usize = 15;
42pub const MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL: u32 = 0xa5a5a5a5;
43pub const MANIFEST_EXT_ID_SPX_KEY: u32 = 0x94ac01ec;
44pub const MANIFEST_EXT_ID_SPX_SIGNATURE: u32 = 0xad77f84a;
45pub const MANIFEST_EXT_ID_IMAGE_TYPE: u32 = 0x494d4754;
46pub const MANIFEST_EXT_ID_SECVER_WRITE: u32 = 0x3f086a41;
47pub const MANIFEST_EXT_ID_ISFB: u32 = 0x42465349;
48pub const MANIFEST_EXT_ID_ISFB_ERASE: u32 = 0x45465349;
49pub const MANIFEST_EXT_NAME_SPX_KEY: u32 = 0x30545845;
50pub const MANIFEST_EXT_NAME_SPX_SIGNATURE: u32 = 0x31545845;
51pub const MANIFEST_EXT_NAME_IMAGE_TYPE: u32 = 0x494d4754;
52pub const MANIFEST_EXT_NAME_SECVER_WRITE: u32 = 0x56434553;
53pub const MANIFEST_EXT_NAME_ISFB: u32 = 0x42465349;
54pub const MANIFEST_EXT_NAME_ISFB_ERASE: u32 = 0x45465349;
55pub const CHIP_ROM_EXT_IDENTIFIER: u32 = 0x4552544f;
56pub const CHIP_BL0_IDENTIFIER: u32 = 0x3042544f;
57pub const CHIP_ROM_EXT_SIZE_MIN: u32 = 8788;
58pub const CHIP_ROM_EXT_SIZE_MAX: u32 = 0x10000;
59pub const CHIP_BL0_SIZE_MIN: u32 = 8788;
60pub const CHIP_BL0_SIZE_MAX: u32 = 0x70000;
61
62with_unknown! {
63 pub enum ManifestKind: u32 {
64 RomExt = CHIP_ROM_EXT_IDENTIFIER,
65 Application = CHIP_BL0_IDENTIFIER,
66 }
67}
68
69#[repr(C)]
74#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Clone, Copy)]
75pub struct ReservedBuffer<const COUNT: usize> {
76 a: [u8; COUNT],
77}
78
79impl<const COUNT: usize> Default for ReservedBuffer<COUNT> {
80 fn default() -> Self {
81 Self {
82 a: std::array::from_fn(|_| 0xa5),
83 }
84 }
85}
86
87#[repr(C)]
89#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default)]
90pub struct Manifest {
91 pub signature: SigverifyBuffer,
92 pub reserved_signature: ReservedBuffer<160>,
93 pub reserved_unsigned: ReservedBuffer<160>,
94 pub usage_constraints: ManifestUsageConstraints,
95 pub pub_key: SigverifyBuffer,
96 pub reserved_public_key: ReservedBuffer<160>,
97 pub reserved: ReservedBuffer<160>,
98 pub address_translation: u32,
99 pub identifier: u32,
100 pub manifest_version: ManifestVersion,
101 pub signed_region_end: u32,
102 pub length: u32,
103 pub version_major: u32,
104 pub version_minor: u32,
105 pub security_version: u32,
106 pub timestamp: Timestamp,
107 pub binding_value: KeymgrBindingValue,
108 pub max_key_version: u32,
109 pub code_start: u32,
110 pub code_end: u32,
111 pub entry_point: u32,
112 pub extensions: ManifestExtTable,
113}
114
115#[repr(C)]
117#[derive(Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
118pub struct ManifestVersion {
119 pub minor: u16,
120 pub major: u16,
121}
122
123#[repr(C)]
125#[derive(Immutable, IntoBytes, FromBytes, Debug, Copy, Clone)]
126pub struct SigverifySpxSignature {
127 pub data: [u32; 1964usize],
128}
129
130impl Default for SigverifySpxSignature {
131 fn default() -> Self {
132 Self {
133 data: [0; 1964usize],
134 }
135 }
136}
137
138#[repr(C)]
140#[derive(Immutable, IntoBytes, FromBytes, Debug, Default, Serialize, Deserialize)]
141pub struct ManifestExtHeader {
142 pub identifier: u32,
143 pub name: u32,
144}
145
146impl ManifestExtHeader {
147 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
148 dest.write_all(self.as_bytes())?;
149 Ok(())
150 }
151}
152
153#[repr(C)]
155#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
156pub struct ManifestExtSpxSignature {
157 pub header: ManifestExtHeader,
158 pub signature: SigverifySpxSignature,
159}
160
161#[repr(C)]
163#[derive(Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
164pub struct SigverifySpxKey {
165 pub data: [u32; 8usize],
166}
167
168#[repr(C)]
170#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
171pub struct ManifestExtSpxKey {
172 pub header: ManifestExtHeader,
173 pub key: SigverifySpxKey,
174}
175
176#[repr(C)]
178#[derive(Immutable, IntoBytes, FromBytes, Debug, Clone, Copy, Default)]
179pub struct SigverifyBuffer {
180 pub data: [u32; 16usize],
181}
182
183#[repr(C)]
184#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
185pub struct ManifestExtImageType {
186 pub header: ManifestExtHeader,
187 pub image_type: u32,
188}
189
190#[repr(C)]
192#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
193pub struct ManifestExtSecVerWrite {
194 pub header: ManifestExtHeader,
195 pub write: u32,
196}
197
198#[derive(Debug, Deserialize, Annotate)]
200pub struct ManifestExtIsfbProductExpr {
201 pub mask: u32,
202 pub value: u32,
203}
204
205#[derive(Debug, Serialize, Deserialize)]
207pub struct ManifestExtIsfb {
208 pub header: ManifestExtHeader,
209 pub strike_mask: u128,
210 pub product_expr_count: u32,
211 pub product_expr: Vec<ManifestExtIsfbProductExpr>,
212}
213
214impl ManifestExtIsfb {
215 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
216 self.header.write(dest)?;
217 dest.write_u128::<LittleEndian>(self.strike_mask)?;
218 dest.write_u32::<LittleEndian>(self.product_expr_count)?;
219 for x in &self.product_expr {
220 dest.write_u32::<LittleEndian>(x.mask)?;
221 dest.write_u32::<LittleEndian>(x.value)?;
222 }
223 Ok(())
224 }
225
226 pub fn to_vec(&self) -> Result<Vec<u8>> {
227 let mut buf = Vec::new();
228 self.write(&mut buf)?;
229 Ok(buf)
230 }
231}
232
233#[repr(C)]
234#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
235pub struct ManifestExtIsfbErasePolicy {
236 pub header: ManifestExtHeader,
237 pub erase_allowed: u32,
238}
239
240#[repr(C)]
242#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
243pub struct LifecycleDeviceId {
244 pub device_id: [u32; 8usize],
245}
246
247#[repr(C)]
249#[derive(Immutable, IntoBytes, FromBytes, Debug)]
250pub struct ManifestUsageConstraints {
251 pub selector_bits: u32,
252 pub device_id: LifecycleDeviceId,
253 pub manuf_state_creator: u32,
254 pub manuf_state_owner: u32,
255 pub life_cycle_state: u32,
256}
257
258impl Default for ManifestUsageConstraints {
259 fn default() -> Self {
260 Self {
261 selector_bits: 0,
262 device_id: LifecycleDeviceId {
263 device_id: [MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL; 8usize],
264 },
265 manuf_state_creator: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
266 manuf_state_owner: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
267 life_cycle_state: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
268 }
269 }
270}
271
272#[repr(C)]
274#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
275pub struct Timestamp {
276 pub timestamp_low: u32,
277 pub timestamp_high: u32,
278}
279
280#[repr(C)]
281#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
282pub struct KeymgrBindingValue {
283 pub data: [u32; 8usize],
284}
285
286#[repr(C)]
287#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
288pub struct ManifestExtTableEntry {
289 pub identifier: u32,
290 pub offset: u32,
291}
292
293#[repr(C)]
294#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
295pub struct ManifestExtTable {
296 pub entries: [ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT],
297}
298
299#[cfg(test)]
300mod tests {
301 use super::*;
302 use std::mem::{offset_of, size_of};
303
304 #[test]
309 pub fn test_manifest_layout() {
310 assert_eq!(offset_of!(Manifest, signature), 0);
311 assert_eq!(offset_of!(Manifest, reserved_signature), 64);
312 assert_eq!(offset_of!(Manifest, reserved_unsigned), 224);
313 assert_eq!(offset_of!(Manifest, usage_constraints), 384);
314 assert_eq!(offset_of!(Manifest, pub_key), 432);
315 assert_eq!(offset_of!(Manifest, reserved_public_key), 496);
316 assert_eq!(offset_of!(Manifest, reserved), 656);
317 assert_eq!(offset_of!(Manifest, address_translation), 816);
318 assert_eq!(offset_of!(Manifest, identifier), 820);
319 assert_eq!(offset_of!(Manifest, manifest_version), 824);
320 assert_eq!(offset_of!(Manifest, signed_region_end), 828);
321 assert_eq!(offset_of!(Manifest, length), 832);
322 assert_eq!(offset_of!(Manifest, version_major), 836);
323 assert_eq!(offset_of!(Manifest, version_minor), 840);
324 assert_eq!(offset_of!(Manifest, security_version), 844);
325 assert_eq!(offset_of!(Manifest, timestamp), 848);
326 assert_eq!(offset_of!(Manifest, binding_value), 856);
327 assert_eq!(offset_of!(Manifest, max_key_version), 888);
328 assert_eq!(offset_of!(Manifest, code_start), 892);
329 assert_eq!(offset_of!(Manifest, code_end), 896);
330 assert_eq!(offset_of!(Manifest, entry_point), 900);
331 assert_eq!(offset_of!(Manifest, extensions), 904);
332 assert_eq!(size_of::<Manifest>(), CHIP_MANIFEST_SIZE as usize);
333 }
334}