opentitanlib/image/
manifest.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
5//! Structs for reading and writing manifests of flash boot stage images.
6//!
7//! Note: The structs below must match the definitions in
8//! sw/device/silicon_creator/lib/manifest.h.
9
10#![deny(warnings)]
11#![deny(unused)]
12#![deny(unsafe_code)]
13
14use crate::with_unknown;
15use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
16
17// Currently, these definitions must be updated manually but they can be
18// generated using the following commands (requires bindgen):
19//   cargo install bindgen
20//   cd "${REPO_TOP}"
21//   bindgen --allowlist-type manifest_t --allowlist-var "MANIFEST_.*" \
22//      --allowlist-var "CHIP_.*" \
23//      --no-doc-comments --no-layout-tests \
24//      sw/device/silicon_creator/lib/manifest.h \
25//      sw/device/silicon_creator/lib/base/chip.h \
26//      -- -I./ -Isw/device/lib/base/freestanding
27// TODO: Generate some constants as hex if possible, replacing manually for now.
28
29pub const CHIP_MANIFEST_SIZE: u32 = 1024;
30
31// TODO(moidx): Update to a valid number once we figure out a manifest
32// versioning scheme.
33pub const CHIP_MANIFEST_VERSION_MAJOR2: u16 = 0x0002;
34pub const CHIP_MANIFEST_VERSION_MINOR1: u16 = 0x6c47;
35pub const CHIP_MANIFEST_VERSION_MAJOR1: u16 = 0x71c3;
36pub const CHIP_MANIFEST_EXT_TABLE_COUNT: usize = 15;
37pub const MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL: u32 = 0xa5a5a5a5;
38pub const MANIFEST_EXT_ID_SPX_KEY: u32 = 0x94ac01ec;
39pub const MANIFEST_EXT_ID_SPX_SIGNATURE: u32 = 0xad77f84a;
40pub const MANIFEST_EXT_ID_IMAGE_TYPE: u32 = 0x494d4754;
41pub const MANIFEST_EXT_NAME_SPX_KEY: u32 = 0x30545845;
42pub const MANIFEST_EXT_NAME_SPX_SIGNATURE: u32 = 0x31545845;
43pub const MANIFEST_EXT_NAME_IMAGE_TYPE: u32 = 0x494d4754;
44pub const CHIP_ROM_EXT_IDENTIFIER: u32 = 0x4552544f;
45pub const CHIP_BL0_IDENTIFIER: u32 = 0x3042544f;
46pub const CHIP_ROM_EXT_SIZE_MIN: u32 = 8788;
47pub const CHIP_ROM_EXT_SIZE_MAX: u32 = 0x10000;
48pub const CHIP_BL0_SIZE_MIN: u32 = 8788;
49pub const CHIP_BL0_SIZE_MAX: u32 = 0x70000;
50
51with_unknown! {
52    pub enum ManifestKind: u32 {
53        RomExt = CHIP_ROM_EXT_IDENTIFIER,
54        Application = CHIP_BL0_IDENTIFIER,
55    }
56}
57
58/// Manifest for boot stage images stored in flash.
59#[repr(C)]
60#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default)]
61pub struct Manifest {
62    pub signature: SigverifyBuffer,
63    pub usage_constraints: ManifestUsageConstraints,
64    pub pub_key: SigverifyBuffer,
65    pub address_translation: u32,
66    pub identifier: u32,
67    pub manifest_version: ManifestVersion,
68    pub signed_region_end: u32,
69    pub length: u32,
70    pub version_major: u32,
71    pub version_minor: u32,
72    pub security_version: u32,
73    pub timestamp: Timestamp,
74    pub binding_value: KeymgrBindingValue,
75    pub max_key_version: u32,
76    pub code_start: u32,
77    pub code_end: u32,
78    pub entry_point: u32,
79    pub extensions: ManifestExtTable,
80}
81
82/// A type that holds 2 16-bit values for manifest major and minor format versions.
83#[repr(C)]
84#[derive(Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
85pub struct ManifestVersion {
86    pub minor: u16,
87    pub major: u16,
88}
89
90/// A type that holds 1964 32-bit words for SPHINCS+ signatures.
91#[repr(C)]
92#[derive(Immutable, IntoBytes, FromBytes, Debug, Copy, Clone)]
93pub struct SigverifySpxSignature {
94    pub data: [u32; 1964usize],
95}
96
97impl Default for SigverifySpxSignature {
98    fn default() -> Self {
99        Self {
100            data: [0; 1964usize],
101        }
102    }
103}
104
105/// Extension header.
106#[repr(C)]
107#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
108pub struct ManifestExtHeader {
109    pub identifier: u32,
110    pub name: u32,
111}
112
113/// SPHINCS+ signature manifest extension.
114#[repr(C)]
115#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
116pub struct ManifestExtSpxSignature {
117    pub header: ManifestExtHeader,
118    pub signature: SigverifySpxSignature,
119}
120
121/// A type that holds 8 32-bit words for SPHINCS+ public keys.
122#[repr(C)]
123#[derive(Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
124pub struct SigverifySpxKey {
125    pub data: [u32; 8usize],
126}
127
128/// SPHINCS+ public key manifest extension.
129#[repr(C)]
130#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
131pub struct ManifestExtSpxKey {
132    pub header: ManifestExtHeader,
133    pub key: SigverifySpxKey,
134}
135
136/// A type that holds 96 32-bit words for RSA-3072.
137#[repr(C)]
138#[derive(Immutable, IntoBytes, FromBytes, Debug)]
139pub struct SigverifyBuffer {
140    pub data: [u32; 96usize],
141}
142
143impl Default for SigverifyBuffer {
144    fn default() -> Self {
145        Self { data: [0; 96usize] }
146    }
147}
148
149#[repr(C)]
150#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
151pub struct ManifestExtImageType {
152    pub header: ManifestExtHeader,
153    pub image_type: u32,
154}
155
156/// A type that holds the 256-bit device identifier.
157#[repr(C)]
158#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
159pub struct LifecycleDeviceId {
160    pub device_id: [u32; 8usize],
161}
162
163/// Manifest usage constraints.
164#[repr(C)]
165#[derive(Immutable, IntoBytes, FromBytes, Debug)]
166pub struct ManifestUsageConstraints {
167    pub selector_bits: u32,
168    pub device_id: LifecycleDeviceId,
169    pub manuf_state_creator: u32,
170    pub manuf_state_owner: u32,
171    pub life_cycle_state: u32,
172}
173
174impl Default for ManifestUsageConstraints {
175    fn default() -> Self {
176        Self {
177            selector_bits: 0,
178            device_id: LifecycleDeviceId {
179                device_id: [MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL; 8usize],
180            },
181            manuf_state_creator: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
182            manuf_state_owner: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
183            life_cycle_state: MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD_VAL,
184        }
185    }
186}
187
188/// Manifest timestamp
189#[repr(C)]
190#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
191pub struct Timestamp {
192    pub timestamp_low: u32,
193    pub timestamp_high: u32,
194}
195
196#[repr(C)]
197#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
198pub struct KeymgrBindingValue {
199    pub data: [u32; 8usize],
200}
201
202#[repr(C)]
203#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
204pub struct ManifestExtTableEntry {
205    pub identifier: u32,
206    pub offset: u32,
207}
208
209#[repr(C)]
210#[derive(KnownLayout, Immutable, IntoBytes, FromBytes, Debug, Default, Copy, Clone)]
211pub struct ManifestExtTable {
212    pub entries: [ManifestExtTableEntry; CHIP_MANIFEST_EXT_TABLE_COUNT],
213}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218    use std::mem::{offset_of, size_of};
219
220    /// Checks the layout of the manifest struct.
221    ///
222    /// Implemented as a function because using `offset_of!` at compile-time
223    /// requires a nightly compiler.
224    #[test]
225    pub fn test_manifest_layout() {
226        assert_eq!(offset_of!(Manifest, signature), 0);
227        assert_eq!(offset_of!(Manifest, usage_constraints), 384);
228        assert_eq!(offset_of!(Manifest, pub_key), 432);
229        assert_eq!(offset_of!(Manifest, address_translation), 816);
230        assert_eq!(offset_of!(Manifest, identifier), 820);
231        assert_eq!(offset_of!(Manifest, manifest_version), 824);
232        assert_eq!(offset_of!(Manifest, signed_region_end), 828);
233        assert_eq!(offset_of!(Manifest, length), 832);
234        assert_eq!(offset_of!(Manifest, version_major), 836);
235        assert_eq!(offset_of!(Manifest, version_minor), 840);
236        assert_eq!(offset_of!(Manifest, security_version), 844);
237        assert_eq!(offset_of!(Manifest, timestamp), 848);
238        assert_eq!(offset_of!(Manifest, binding_value), 856);
239        assert_eq!(offset_of!(Manifest, max_key_version), 888);
240        assert_eq!(offset_of!(Manifest, code_start), 892);
241        assert_eq!(offset_of!(Manifest, code_end), 896);
242        assert_eq!(offset_of!(Manifest, entry_point), 900);
243        assert_eq!(offset_of!(Manifest, extensions), 904);
244        assert_eq!(size_of::<Manifest>(), CHIP_MANIFEST_SIZE as usize);
245    }
246}