Skip to content

Commit 211c493

Browse files
committed
let Manifest own its remaining data
Split out the header and manifest key/signature material. Signed-off-by: Daniel Maslowski <[email protected]>
1 parent bf02f62 commit 211c493

File tree

6 files changed

+76
-66
lines changed

6 files changed

+76
-66
lines changed

src/dir/gen2.rs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use zerocopy::{FromBytes, Ref};
88
use zerocopy_derive::{FromBytes, Immutable, IntoBytes};
99

1010
use crate::Removables;
11-
use crate::dir::man::{self, Manifest};
11+
use crate::dir::man::Manifest;
1212

1313
// These must never be removed. They are essential for platform initialization.
1414
pub const ALWAYS_RETAIN: &[&str] = &[
@@ -197,7 +197,7 @@ pub struct Header {
197197
#[derive(Serialize, Deserialize, Clone, Debug)]
198198
#[repr(C)]
199199
pub struct Directory {
200-
pub manifest: (Manifest, Vec<u8>),
200+
pub manifest: Manifest,
201201
pub header: Header,
202202
pub modules: Vec<Module>,
203203
pub offset: usize,
@@ -210,7 +210,7 @@ impl Display for Directory {
210210
let n = &self.name;
211211
let o = self.offset;
212212
let s = self.size;
213-
let (m, _) = self.manifest;
213+
let m = &self.manifest;
214214
write!(f, "{n} @ {o:08x}, {s} bytes, {m}")
215215
}
216216
}
@@ -222,11 +222,7 @@ impl Directory {
222222
let Ok(manifest) = Manifest::new(data) else {
223223
return Err("cannot parse Gen 2 directory manifest".to_string());
224224
};
225-
226-
let data_len = manifest.data_len();
227-
let mdata = &data[man::MANIFEST_SIZE..man::MANIFEST_SIZE + data_len];
228-
229-
let Ok((header, _)) = Header::read_from_prefix(mdata) else {
225+
let Ok((header, _)) = Header::read_from_prefix(&manifest.mdata) else {
230226
return Err("cannot parse ME FW Gen 2 directory header".to_string());
231227
};
232228
let name = match from_utf8(&header.name) {
@@ -236,20 +232,17 @@ impl Directory {
236232

237233
// Check magic bytes of first entry.
238234
let pos = HEADER_SIZE;
239-
let m = &mdata[pos..pos + 4];
235+
let slice = &manifest.mdata[pos..];
236+
let m = &slice[..4];
240237
if !m.eq(MODULE_MAGIC_BYTES) {
241238
return Err(format!(
242239
"entry magic not found, got {m:02x?}, wanted {MODULE_MAGIC_BYTES:02x?} ({MODULE_MAGIC})"
243240
));
244241
}
245242
// Parse the entries themselves.
246-
let slice = &mdata[pos..];
247243
let count = manifest.header.entries as usize;
248244
let Ok((r, _)) = Ref::<_, [Entry]>::from_prefix_with_elems(slice, count) else {
249-
return Err(format!(
250-
"cannot parse ME FW Gen 2 directory entries @ {:08x}",
251-
pos
252-
));
245+
return Err(format!("cannot parse ME FW Gen 2 directory entries",));
253246
};
254247
let entries = r.to_vec();
255248

@@ -299,7 +292,7 @@ impl Directory {
299292

300293
let size = data.len();
301294
Ok(Self {
302-
manifest: (manifest, mdata.to_vec()),
295+
manifest,
303296
header,
304297
modules,
305298
offset,

src/dir/gen3.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl Display for CPDEntry {
104104
#[repr(C)]
105105
pub struct CodePartitionDirectory {
106106
pub header: CPDHeader,
107-
pub manifest: Result<(Manifest, Vec<u8>), String>,
107+
pub manifest: Result<Manifest, String>,
108108
pub entries: Vec<CPDEntry>,
109109
pub offset: usize,
110110
pub size: usize,
@@ -125,7 +125,7 @@ impl Display for CodePartitionDirectory {
125125
let n = &self.name;
126126
let l1 = format!("{n} @ {o:08x}, checksum or version: {checksum:08x}");
127127
let l2 = match &self.manifest {
128-
Ok((m, _)) => {
128+
Ok(m) => {
129129
let h = stringify_vec(m.hash_key());
130130
let m = format!("{m}");
131131
let kh = format!("Key hash: {h}");
@@ -174,16 +174,7 @@ impl CodePartitionDirectory {
174174
if let Some(e) = entries.iter().find(|e| e.name() == manifest_name) {
175175
let o = e.flags_and_offset.offset() as usize;
176176
let end = o + e.size as usize;
177-
match Manifest::new(&data[o..end]) {
178-
Ok(m) => {
179-
// The manifest carries additional data after its header
180-
// and key material.
181-
let header_len = m.header_len();
182-
let mdata = data[o + header_len..end].to_vec();
183-
Ok((m, mdata))
184-
}
185-
Err(e) => Err(e),
186-
}
177+
Manifest::new(&data[o..end])
187178
} else {
188179
Err("no manifest found".to_string())
189180
}

src/dir/man.rs

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub struct Header {
6464
pub flags: u32,
6565
pub vendor: Vendor,
6666
pub date: Date,
67-
pub size: u32, // in dwords, dword size is 32bit
67+
pub manifest_len: u32, // in dwords, dword size is 32bit
6868
pub magic: [u8; 4],
6969
// NOTE: only for Gen 2 ME firmware
7070
pub entries: u32,
@@ -93,79 +93,106 @@ impl Display for Header {
9393
}
9494
}
9595

96+
impl Header {
97+
/// Get the header length including signature
98+
pub fn header_len(&self) -> usize {
99+
self.header_len as usize * 4
100+
}
101+
102+
/// Get the length of the manifest including its data
103+
pub fn manifest_len(&self) -> usize {
104+
self.manifest_len as usize * 4
105+
}
106+
107+
/// Get the length of the data after the header
108+
pub fn data_len(&self) -> usize {
109+
let mlen = self.manifest_len();
110+
let hlen = self.header_len();
111+
mlen - hlen
112+
}
113+
}
114+
96115
#[derive(Immutable, IntoBytes, FromBytes, Serialize, Deserialize, Clone, Copy, Debug)]
97116
#[repr(C)]
98-
pub struct Manifest {
99-
pub header: Header,
117+
pub struct Signature {
100118
#[serde(with = "serde_bytes")]
101119
pub rsa_pub_key: [u8; 0x100],
102120
pub rsa_pub_exp: u32,
103121
#[serde(with = "serde_bytes")]
104122
pub rsa_sig: [u8; 0x100],
105123
}
106124

125+
#[derive(Serialize, Deserialize, Clone, Debug)]
126+
#[repr(C)]
127+
pub struct Manifest {
128+
pub header: Header,
129+
pub signature: Signature,
130+
pub mdata: Vec<u8>,
131+
}
132+
107133
pub const MANIFEST_SIZE: usize = core::mem::size_of::<Manifest>();
108134

109135
impl<'a> Manifest {
110136
pub fn new(data: &'a [u8]) -> Result<Self, String> {
111-
let (manifest, _) = match Self::read_from_prefix(data) {
137+
let (header, slice) = match Header::read_from_prefix(data) {
112138
Ok(r) => r,
113139
Err(e) => {
114140
let err = format!("Manifest cannot be parsed: {e:?}");
115141
return Err(err);
116142
}
117143
};
118144

119-
if manifest.header.magic != MANIFEST2_MAGIC_BYTES {
145+
if header.magic != MANIFEST2_MAGIC_BYTES {
120146
let err = format!(
121147
"Manifest magic not found: wanted {MANIFEST2_MAGIC_BYTES:02x?} ({MANIFEST2_MAGIC}), got {:02x?}",
122-
manifest.header.magic
148+
header.magic
123149
);
124150
return Err(err);
125151
}
126152

127-
Ok(manifest)
128-
}
129-
130-
/// Get the header length
131-
pub fn header_len(&self) -> usize {
132-
self.header.header_len as usize * 4
133-
}
134-
135-
/// Get the size of the manifest and its data
136-
pub fn size(&self) -> usize {
137-
self.header.size as usize * 4
138-
}
153+
let (signature, _) = match Signature::read_from_prefix(slice) {
154+
Ok(r) => r,
155+
Err(e) => {
156+
let err = format!("Signature cannot be parsed: {e:?}");
157+
return Err(err);
158+
}
159+
};
139160

140-
/// Get the length of the data after the manifest
141-
pub fn data_len(&self) -> usize {
142-
let mlen = self.size();
143-
let hlen = self.header_len();
144-
mlen - hlen
161+
// The manifest carries additional data after its header and signature.
162+
// Note that header_len includes the signature.
163+
let header_len = header.header_len();
164+
let size = header.manifest_len();
165+
let mdata = &data[header_len..size];
166+
167+
Ok(Self {
168+
header,
169+
signature,
170+
mdata: mdata.to_vec(),
171+
})
145172
}
146173

147174
/// Get the MD5 hash over the RSA public key and exponent.
148-
pub fn hash_key(self: Self) -> Vec<u8> {
149-
let k = self.rsa_pub_key.as_bytes();
150-
let e = self.rsa_pub_exp;
175+
pub fn hash_key(&self) -> Vec<u8> {
176+
let k = self.signature.rsa_pub_key.as_bytes();
177+
let e = self.signature.rsa_pub_exp;
151178
let ke = [k, &e.to_le_bytes()].concat();
152179
md5::compute(ke).to_vec()
153180
}
154181

155-
/// Verify the manifest. Pass extra bytes from after the manifest.
156-
pub fn verify(&self, ebytes: &[u8]) -> bool {
182+
/// Verify the manifest.
183+
pub fn verify(&self) -> bool {
157184
use num_bigint::BigUint;
158185
use sha2::{Digest, Sha256};
159186

160-
let modulus = BigUint::from_bytes_le(&self.rsa_pub_key);
161-
let exponent = BigUint::from(self.rsa_pub_exp);
162-
let signature = BigUint::from_bytes_le(&self.rsa_sig);
187+
let modulus = BigUint::from_bytes_le(&self.signature.rsa_pub_key);
188+
let exponent = BigUint::from(self.signature.rsa_pub_exp);
189+
let signature = BigUint::from_bytes_le(&self.signature.rsa_sig);
163190
let sb = signature.modpow(&exponent, &modulus).to_bytes_be();
164191

165192
let header = self.header.as_bytes();
166193
let mut hasher = Sha256::new();
167194
hasher.update(&header);
168-
hasher.update(&ebytes);
195+
hasher.update(&self.mdata);
169196
let hash = hasher.finalize();
170197
let hb = hash.as_bytes();
171198

@@ -177,7 +204,7 @@ impl<'a> Manifest {
177204
impl Display for Manifest {
178205
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179206
let h = self.header;
180-
let exp = self.rsa_pub_exp;
207+
let exp = self.signature.rsa_pub_exp;
181208
write!(f, "{h}, RSA exp {exp}")
182209
}
183210
}

src/part/gen2.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ pub struct DirPartition {
2020

2121
impl DirPartition {
2222
pub fn check_signature(&self) -> Result<(), String> {
23-
let (m, mdata) = &self.dir.manifest;
24-
if m.verify(&mdata) {
23+
if self.dir.manifest.verify() {
2524
return Ok(());
2625
} else {
2726
return Err("hash mismatch".into());

src/part/gen3.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ pub struct CPDPartition {
2121

2222
impl CPDPartition {
2323
pub fn check_signature(&self) -> Result<(), String> {
24-
if let Ok((m, mdata)) = &self.cpd.manifest {
25-
if m.verify(&mdata) {
24+
if let Ok(m) = &self.cpd.manifest {
25+
if m.verify() {
2626
return Ok(());
2727
} else {
2828
return Err("hash mismatch".into());

src/part/partitions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl Partitions {
7979
if let Some(Gen2Partition::Dir(d)) =
8080
parts.iter().find(|p| matches!(p, Gen2Partition::Dir(_)))
8181
{
82-
let (m, _) = d.dir.manifest;
82+
let m = &d.dir.manifest;
8383
Some(m.header.version)
8484
} else {
8585
None
@@ -89,7 +89,7 @@ impl Partitions {
8989
if let Some(Gen3Partition::Dir(d)) =
9090
parts.iter().find(|p| matches!(p, Gen3Partition::Dir(_)))
9191
{
92-
if let Ok((m, _)) = d.cpd.manifest {
92+
if let Ok(m) = &d.cpd.manifest {
9393
Some(m.header.version)
9494
} else {
9595
None

0 commit comments

Comments
 (0)