1use alloc::vec::Vec;
10use alloc::string::String;
11use core::mem::size_of;
12
13use crate::crypto::{KeyPair, PUBLIC_KEY_SIZE, SIGNATURE_SIZE};
14use crate::error::{Error, Result};
15
16pub mod header;
17pub mod manifest;
18
19pub use header::{ModuleHeader, HeaderFlags};
20pub use manifest::ModuleManifest;
21
22pub const MAGIC: &[u8] = b"SPK\x02";
24
25pub const FIXED_HEADER_SIZE: usize = 128;
27
28pub const MAX_CODE_SIZE: usize = 1024 * 1024;
30
31pub const FLAG_SIGNED: u32 = 0x0001;
33
34pub const FLAG_COMPRESSED: u32 = 0x0002;
36
37pub const FLAG_HW_LOCKED: u32 = 0x0004;
39
40pub const FLAG_CRITICAL: u32 = 0x0008;
42
43#[derive(Clone, Debug, PartialEq)]
45pub struct Module {
46 pub header: ModuleHeader,
48 pub public_key: [u8; PUBLIC_KEY_SIZE],
50 pub signature: [u8; SIGNATURE_SIZE],
52 pub code: Vec<u8>,
54 pub manifest: Option<ModuleManifest>,
56}
57
58impl Module {
59 pub fn builder() -> ModuleBuilder {
61 ModuleBuilder::default()
62 }
63
64 pub fn to_bytes(&self) -> Result<Vec<u8>> {
66 let mut result = Vec::with_capacity(FIXED_HEADER_SIZE + self.code.len());
67
68 result.extend_from_slice(MAGIC);
70
71 result.extend_from_slice(&self.header.version.to_le_bytes());
73
74 let total_size = FIXED_HEADER_SIZE + self.code.len();
76 result.extend_from_slice(&(total_size as u32).to_le_bytes());
77
78 result.extend_from_slice(&(self.code.len() as u32).to_le_bytes());
80
81 result.extend_from_slice(&self.header.entry_offset.to_le_bytes());
83
84 let flags = self.header.flags;
86 result.extend_from_slice(&flags.to_le_bytes());
87
88 result.extend_from_slice(&self.header.monotonic_version.to_le_bytes());
90
91 result.extend_from_slice(&self.header.hw_revision.to_le_bytes());
93
94 let crc = crc32fast::hash(&self.code);
96 result.extend_from_slice(&crc.to_le_bytes());
97
98 result.extend_from_slice(&[0u8; 8]);
100
101 result.extend_from_slice(&self.public_key);
103
104 result.extend_from_slice(&self.signature);
106
107 result.extend_from_slice(&self.code);
109
110 Ok(result)
111 }
112
113 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
115 if bytes.len() < FIXED_HEADER_SIZE {
116 return Err(Error::invalid_format("data too short for header"));
117 }
118
119 if &bytes[0..4] != MAGIC {
121 return Err(Error::invalid_format(format!(
122 "invalid magic: expected {:?}, got {:?}",
123 MAGIC, &bytes[0..4]
124 )));
125 }
126
127 let version = u16::from_le_bytes([bytes[4], bytes[5]]);
129 if version < crate::MIN_MODULE_VERSION {
130 return Err(Error::VersionMismatch {
131 expected: crate::CURRENT_MODULE_VERSION,
132 found: version,
133 });
134 }
135
136 let total_size = u32::from_le_bytes([bytes[6], bytes[7], bytes[8], bytes[9]]) as usize;
138 let code_size = u32::from_le_bytes([bytes[10], bytes[11], bytes[12], bytes[13]]) as usize;
139
140 if code_size > MAX_CODE_SIZE {
141 return Err(Error::invalid_format(format!(
142 "code size {} exceeds maximum {}", code_size, MAX_CODE_SIZE
143 )));
144 }
145
146 if total_size != FIXED_HEADER_SIZE + code_size {
147 return Err(Error::invalid_format("total size mismatch"));
148 }
149
150 if bytes.len() < total_size {
151 return Err(Error::invalid_format("truncated module data"));
152 }
153
154 let header = ModuleHeader {
155 version,
156 entry_offset: u32::from_le_bytes([bytes[14], bytes[15], bytes[16], bytes[17]]),
157 flags: u32::from_le_bytes([bytes[18], bytes[19], bytes[20], bytes[21]]),
158 monotonic_version: u64::from_le_bytes([
159 bytes[22], bytes[23], bytes[24], bytes[25],
160 bytes[26], bytes[27], bytes[28], bytes[29],
161 ]),
162 hw_revision: u32::from_le_bytes([bytes[30], bytes[31], bytes[32], bytes[33]]),
163 code_crc: u32::from_le_bytes([bytes[34], bytes[35], bytes[36], bytes[37]]),
164 };
165
166 let mut public_key = [0u8; PUBLIC_KEY_SIZE];
167 public_key.copy_from_slice(&bytes[48..80]);
168
169 let mut signature = [0u8; SIGNATURE_SIZE];
170 signature.copy_from_slice(&bytes[80..144]);
171
172 let code = bytes[FIXED_HEADER_SIZE..FIXED_HEADER_SIZE + code_size].to_vec();
173
174 let actual_crc = crc32fast::hash(&code);
176 if actual_crc != header.code_crc {
177 return Err(Error::invalid_format(format!(
178 "CRC mismatch: expected {}, got {}", header.code_crc, actual_crc
179 )));
180 }
181
182 Ok(Self {
183 header,
184 public_key,
185 signature,
186 code,
187 manifest: None,
188 })
189 }
190
191 pub fn verify(&self) -> Result<()> {
193 KeyPair::verify_module(self)
194 }
195
196 pub fn serialized_size(&self) -> usize {
198 FIXED_HEADER_SIZE + self.code.len()
199 }
200
201 pub fn is_signed(&self) -> bool {
203 self.header.flags & FLAG_SIGNED != 0
204 }
205
206 pub fn is_compressed(&self) -> bool {
208 self.header.flags & FLAG_COMPRESSED != 0
209 }
210}
211
212#[derive(Default)]
214pub struct ModuleBuilder {
215 code: Vec<u8>,
216 entry_offset: u32,
217 flags: u32,
218 monotonic_version: u64,
219 hw_revision: u32,
220 manifest: Option<ModuleManifest>,
221}
222
223impl ModuleBuilder {
224 pub fn code(mut self, code: Vec<u8>) -> Self {
226 self.code = code;
227 self
228 }
229
230 pub fn entry_offset(mut self, offset: u32) -> Self {
232 self.entry_offset = offset;
233 self
234 }
235
236 pub fn hw_revision(mut self, rev: u32) -> Self {
238 self.hw_revision = rev;
239 self.flags |= FLAG_HW_LOCKED;
240 self
241 }
242
243 pub fn version(mut self, version: u64) -> Self {
245 self.monotonic_version = version;
246 self
247 }
248
249 pub fn manifest(mut self, manifest: ModuleManifest) -> Self {
251 self.manifest = Some(manifest);
252 self
253 }
254
255 pub fn sign(self, keypair: &KeyPair) -> SignedModuleBuilder {
257 SignedModuleBuilder {
258 inner: self,
259 keypair: keypair.clone(),
260 }
261 }
262
263 pub fn build_unsigned(self) -> Result<Module> {
265 if self.code.is_empty() {
266 return Err(Error::invalid_format("code cannot be empty"));
267 }
268
269 Ok(Module {
270 header: ModuleHeader {
271 version: crate::CURRENT_MODULE_VERSION,
272 entry_offset: self.entry_offset,
273 flags: self.flags,
274 monotonic_version: self.monotonic_version,
275 hw_revision: self.hw_revision,
276 code_crc: crc32fast::hash(&self.code),
277 },
278 public_key: [0u8; PUBLIC_KEY_SIZE],
279 signature: [0u8; SIGNATURE_SIZE],
280 code: self.code,
281 manifest: self.manifest,
282 })
283 }
284}
285
286pub struct SignedModuleBuilder {
288 inner: ModuleBuilder,
289 keypair: KeyPair,
290}
291
292impl SignedModuleBuilder {
293 pub fn build(self) -> Result<Module> {
295 let mut module = self.inner.build_unsigned()?;
296 self.keypair.sign_module(&mut module);
297 Ok(module)
298 }
299}