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_ID_OWNER_TRANSFER_BLOB: u32 = 0x4254574f;
50pub const MANIFEST_EXT_ID_MLDSA87_KEY: u32 = 0xa3e247b8;
51pub const MANIFEST_EXT_ID_MLDSA87_SIGNATURE: u32 = 0x4714ac7d;
52pub const MANIFEST_EXT_NAME_SPX_KEY: u32 = 0x30545845;
53pub const MANIFEST_EXT_NAME_SPX_SIGNATURE: u32 = 0x31545845;
54pub const MANIFEST_EXT_NAME_IMAGE_TYPE: u32 = 0x494d4754;
55pub const MANIFEST_EXT_NAME_SECVER_WRITE: u32 = 0x56434553;
56pub const MANIFEST_EXT_NAME_ISFB: u32 = 0x42465349;
57pub const MANIFEST_EXT_NAME_ISFB_ERASE: u32 = 0x45465349;
58pub const MANIFEST_EXT_NAME_OWNER_TRANSFER_BLOB: u32 = 0x4254574f;
59pub const MANIFEST_EXT_NAME_MLDSA87_KEY: u32 = 0x4b384c4d;
60pub const MANIFEST_EXT_NAME_MLDSA87_SIGNATURE: u32 = 0x53384c4d;
61pub const CHIP_ROM_EXT_IDENTIFIER: u32 = 0x4552544f;
62pub const CHIP_BL0_IDENTIFIER: u32 = 0x3042544f;
63pub const CHIP_ROM_EXT_SIZE_MIN: u32 = 8788;
64pub const CHIP_ROM_EXT_SIZE_MAX: u32 = 0x10000;
65pub const CHIP_BL0_SIZE_MIN: u32 = 8788;
66pub const CHIP_BL0_SIZE_MAX: u32 = 0x70000;
67
68with_unknown! {
69 pub enum ManifestKind: u32 {
70 RomExt = CHIP_ROM_EXT_IDENTIFIER,
71 Application = CHIP_BL0_IDENTIFIER,
72 }
73}
74
75#[repr(C)]
80#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Clone, Copy)]
81pub struct ReservedBuffer<const COUNT: usize> {
82 a: [u8; COUNT],
83}
84
85impl<const COUNT: usize> Default for ReservedBuffer<COUNT> {
86 fn default() -> Self {
87 Self {
88 a: std::array::from_fn(|_| 0xa5),
89 }
90 }
91}
92
93#[repr(C)]
95#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default)]
96pub struct Manifest {
97 pub signature: SigverifyBuffer,
98 pub reserved_signature: ReservedBuffer<160>,
99 pub reserved_unsigned: ReservedBuffer<160>,
100 pub usage_constraints: ManifestUsageConstraints,
101 pub pub_key: SigverifyBuffer,
102 pub reserved_public_key: ReservedBuffer<160>,
103 pub reserved: ReservedBuffer<160>,
104 pub address_translation: u32,
105 pub identifier: u32,
106 pub manifest_version: ManifestVersion,
107 pub signed_region_end: u32,
108 pub length: u32,
109 pub version_major: u32,
110 pub version_minor: u32,
111 pub security_version: u32,
112 pub timestamp: Timestamp,
113 pub binding_value: KeymgrBindingValue,
114 pub max_key_version: u32,
115 pub code_start: u32,
116 pub code_end: u32,
117 pub entry_point: u32,
118 pub extensions: ManifestExtTable,
119}
120
121#[repr(C)]
123#[derive(Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
124pub struct ManifestVersion {
125 pub minor: u16,
126 pub major: u16,
127}
128
129#[repr(C)]
131#[derive(Immutable, IntoBytes, FromBytes, Debug, Copy, Clone)]
132pub struct SigverifySpxSignature {
133 pub data: [u32; 1964usize],
134}
135
136impl Default for SigverifySpxSignature {
137 fn default() -> Self {
138 Self {
139 data: [0; 1964usize],
140 }
141 }
142}
143
144#[repr(C)]
146#[derive(Immutable, IntoBytes, FromBytes, Debug, Default, Serialize, Deserialize)]
147pub struct ManifestExtHeader {
148 pub identifier: u32,
149 pub name: u32,
150}
151
152impl ManifestExtHeader {
153 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
154 dest.write_all(self.as_bytes())?;
155 Ok(())
156 }
157}
158
159#[repr(C)]
161#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
162pub struct ManifestExtSpxSignature {
163 pub header: ManifestExtHeader,
164 pub signature: SigverifySpxSignature,
165}
166
167#[repr(C)]
169#[derive(Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
170pub struct SigverifySpxKey {
171 pub data: [u32; 8usize],
172}
173
174#[repr(C)]
176#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
177pub struct ManifestExtSpxKey {
178 pub header: ManifestExtHeader,
179 pub key: SigverifySpxKey,
180}
181
182pub const MLDSA87_PUBLIC_KEY_BYTES: usize = 2592;
184pub const MLDSA87_SIGNATURE_BYTES: usize = 4627;
186pub const MLDSA87_IMAGE_CONTEXT: &[u8] = b"OT-MLDSA-IMAGE";
189
190#[repr(C)]
192#[derive(Immutable, IntoBytes, FromBytes, Debug, Copy, Clone)]
193pub struct SigverifyMldsa87Signature {
194 pub data: [u32; MLDSA87_SIGNATURE_BYTES.div_ceil(size_of::<u32>())],
195}
196
197impl Default for SigverifyMldsa87Signature {
198 fn default() -> Self {
199 Self {
200 data: [0; MLDSA87_SIGNATURE_BYTES.div_ceil(size_of::<u32>())],
201 }
202 }
203}
204
205#[repr(C)]
207#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
208pub struct ManifestExtMldsa87Signature {
209 pub header: ManifestExtHeader,
210 pub signature: SigverifyMldsa87Signature,
211}
212
213#[repr(C)]
215#[derive(Immutable, IntoBytes, FromBytes, Debug, Copy, Clone)]
216pub struct SigverifyMldsa87Key {
217 pub data: [u32; MLDSA87_PUBLIC_KEY_BYTES / size_of::<u32>()],
218}
219
220impl Default for SigverifyMldsa87Key {
221 fn default() -> Self {
222 Self {
223 data: [0; MLDSA87_PUBLIC_KEY_BYTES / size_of::<u32>()],
224 }
225 }
226}
227
228#[repr(C)]
230#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
231pub struct ManifestExtMldsa87Key {
232 pub header: ManifestExtHeader,
233 pub key: SigverifyMldsa87Key,
234}
235
236#[repr(C)]
238#[derive(Immutable, IntoBytes, FromBytes, Debug, Clone, Copy, Default)]
239pub struct SigverifyBuffer {
240 pub data: [u32; 16usize],
241}
242
243#[repr(C)]
244#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
245pub struct ManifestExtImageType {
246 pub header: ManifestExtHeader,
247 pub image_type: u32,
248}
249
250#[repr(C)]
252#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
253pub struct ManifestExtSecVerWrite {
254 pub header: ManifestExtHeader,
255 pub write: u32,
256}
257
258#[derive(Debug, Deserialize, Annotate)]
260pub struct ManifestExtIsfbProductExpr {
261 pub mask: u32,
262 pub value: u32,
263}
264
265#[derive(Debug, Serialize, Deserialize)]
267pub struct ManifestExtIsfb {
268 pub header: ManifestExtHeader,
269 pub strike_mask: u128,
270 pub product_expr_count: u32,
271 pub product_expr: Vec<ManifestExtIsfbProductExpr>,
272}
273
274impl ManifestExtIsfb {
275 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
276 self.header.write(dest)?;
277 dest.write_u128::<LittleEndian>(self.strike_mask)?;
278 dest.write_u32::<LittleEndian>(self.product_expr_count)?;
279 for x in &self.product_expr {
280 dest.write_u32::<LittleEndian>(x.mask)?;
281 dest.write_u32::<LittleEndian>(x.value)?;
282 }
283 Ok(())
284 }
285
286 pub fn to_vec(&self) -> Result<Vec<u8>> {
287 let mut buf = Vec::new();
288 self.write(&mut buf)?;
289 Ok(buf)
290 }
291}
292
293#[repr(C)]
294#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
295pub struct ManifestExtIsfbErasePolicy {
296 pub header: ManifestExtHeader,
297 pub erase_allowed: u32,
298}
299
300#[repr(C)]
302#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
303pub struct LifecycleDeviceId {
304 pub device_id: [u32; 8usize],
305}
306
307#[repr(C)]
309#[derive(Immutable, IntoBytes, FromBytes, Debug)]
310pub struct ManifestUsageConstraints {
311 pub selector_bits: u32,
312 pub device_id: LifecycleDeviceId,
313 pub manuf_state_creator: u32,
314 pub manuf_state_owner: u32,
315 pub life_cycle_state: u32,
316}
317
318impl Default for ManifestUsageConstraints {
319 fn default() -> Self {
320 Self {
321 selector_bits: 0,
322 device_id: LifecycleDeviceId {
323 device_id: [MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL; 8usize],
324 },
325 manuf_state_creator: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
326 manuf_state_owner: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
327 life_cycle_state: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
328 }
329 }
330}
331
332#[repr(C)]
334#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
335pub struct Timestamp {
336 pub timestamp_low: u32,
337 pub timestamp_high: u32,
338}
339
340#[repr(C)]
341#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
342pub struct KeymgrBindingValue {
343 pub data: [u32; 8usize],
344}
345
346#[repr(C)]
347#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
348pub struct ManifestExtTableEntry {
349 pub identifier: u32,
350 pub offset: u32,
351}
352
353#[repr(C)]
354#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
355pub struct ManifestExtTable {
356 pub entries: [ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT],
357}
358
359#[cfg(test)]
360mod tests {
361 use super::*;
362 use std::mem::{offset_of, size_of};
363
364 #[test]
369 pub fn test_manifest_layout() {
370 assert_eq!(offset_of!(Manifest, signature), 0);
371 assert_eq!(offset_of!(Manifest, reserved_signature), 64);
372 assert_eq!(offset_of!(Manifest, reserved_unsigned), 224);
373 assert_eq!(offset_of!(Manifest, usage_constraints), 384);
374 assert_eq!(offset_of!(Manifest, pub_key), 432);
375 assert_eq!(offset_of!(Manifest, reserved_public_key), 496);
376 assert_eq!(offset_of!(Manifest, reserved), 656);
377 assert_eq!(offset_of!(Manifest, address_translation), 816);
378 assert_eq!(offset_of!(Manifest, identifier), 820);
379 assert_eq!(offset_of!(Manifest, manifest_version), 824);
380 assert_eq!(offset_of!(Manifest, signed_region_end), 828);
381 assert_eq!(offset_of!(Manifest, length), 832);
382 assert_eq!(offset_of!(Manifest, version_major), 836);
383 assert_eq!(offset_of!(Manifest, version_minor), 840);
384 assert_eq!(offset_of!(Manifest, security_version), 844);
385 assert_eq!(offset_of!(Manifest, timestamp), 848);
386 assert_eq!(offset_of!(Manifest, binding_value), 856);
387 assert_eq!(offset_of!(Manifest, max_key_version), 888);
388 assert_eq!(offset_of!(Manifest, code_start), 892);
389 assert_eq!(offset_of!(Manifest, code_end), 896);
390 assert_eq!(offset_of!(Manifest, entry_point), 900);
391 assert_eq!(offset_of!(Manifest, extensions), 904);
392 assert_eq!(size_of::<Manifest>(), CHIP_MANIFEST_SIZE as usize);
393 }
394}