verifyos_cli/parsers/
macho_parser.rs1use apple_codesign::MachFile;
2use std::path::Path;
3
4#[derive(Debug, thiserror::Error)]
5pub enum MachOError {
6 #[error("Failed to parse Mach-O file: {0}")]
7 ParseError(#[from] Box<apple_codesign::AppleCodesignError>),
8 #[error("No code signature found")]
9 NoSignature,
10 #[error("Entitlements differ across Mach-O architecture slices")]
11 MismatchedEntitlements,
12}
13
14pub struct MachOExecutable {
15 pub entitlements: Option<String>,
16}
17
18impl MachOExecutable {
19 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, MachOError> {
20 let file_data =
21 std::fs::read(path).map_err(|e| Box::new(apple_codesign::AppleCodesignError::Io(e)))?;
22 let mach_file = MachFile::parse(&file_data).map_err(Box::new)?;
23
24 let mut first_entitlements: Option<Option<String>> = None;
25
26 for macho in mach_file.iter_macho() {
27 let mut current_ent = None;
28 if let Some(sig) = macho.code_signature().map_err(Box::new)? {
29 if let Some(ent) = sig.entitlements().map_err(Box::new)? {
30 current_ent = Some(ent.as_str().to_string());
31 }
32 }
33
34 match &first_entitlements {
35 None => {
36 first_entitlements = Some(current_ent);
37 }
38 Some(first) => {
39 if first != ¤t_ent {
40 return Err(MachOError::MismatchedEntitlements);
41 }
42 }
43 }
44 }
45
46 Ok(Self {
47 entitlements: first_entitlements.flatten(),
48 })
49 }
50}