codesign_verify/macos/
mod.rs1mod context;
2#[allow(non_upper_case_globals)]
3mod sec_sys;
4
5use super::Error;
6use sec_sys::*;
7
8pub(crate) struct Verifier(SecCodeKind);
9pub(crate) use context::Context;
10
11#[derive(Debug)]
12enum SecCodeKind {
13 Static(SecStaticCode), Dynamic(SecCode), }
16
17impl Verifier {
18 pub fn for_pid(pid: i32) -> Result<Self, Error> {
20 let mut sec: SecCodeRef = std::ptr::null_mut();
21
22 let attributes = unsafe {
23 CFDictionary::from_CFType_pairs(&[(
24 CFString::wrap_under_get_rule(kSecGuestAttributePid),
25 CFNumber::from(pid),
26 )])
27 };
28
29 unsafe {
30 match SecCodeCopyGuestWithAttributes(
31 std::ptr::null_mut(),
32 attributes.as_concrete_TypeRef(),
33 SecCSFlags::kSecCSDefaultFlags,
34 Some(&mut sec),
35 ) {
36 sec_sys::errSecSuccess if !sec.is_null() => Ok(Verifier(SecCodeKind::Dynamic(
37 SecCode::wrap_under_create_rule(sec),
38 ))),
39 err => Err(Error::OsError(err)),
40 }
41 }
42 }
43
44 pub fn for_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self, Error> {
46 let mut sec: SecStaticCodeRef = std::ptr::null_mut();
47 let url = CFURL::from_path(path.as_ref(), false).ok_or(Error::InvalidPath)?;
48
49 unsafe {
50 match SecStaticCodeCreateWithPath(
51 url.as_concrete_TypeRef(),
52 SecCSFlags::kSecCSDefaultFlags,
53 Some(&mut sec),
54 ) {
55 sec_sys::errSecSuccess if !sec.is_null() => Ok(Verifier(SecCodeKind::Static(
56 SecStaticCode::wrap_under_create_rule(sec),
57 ))),
58 err => Err(Error::OsError(err)),
59 }
60 }
61 }
62
63 pub fn verify(&self) -> Result<Context, Error> {
64 self.check_validity("anchor trusted")?; let sec_info = self.get_code_singing_info()?;
66 let cert_key = unsafe { CFString::wrap_under_get_rule(kSecCodeInfoCertificates) };
67
68 let certs_ref = sec_info
69 .find(cert_key.as_CFTypeRef())
70 .ok_or(Error::LeafCertNotFound)?;
71
72 let certs = unsafe { CFArray::<SecCertificate>::wrap_under_get_rule(*certs_ref as _) };
73 let leaf_cert = certs.get(0).ok_or(Error::LeafCertNotFound)?;
74
75 Ok(Context::new(leaf_cert.as_concrete_TypeRef()))
76 }
77
78 fn get_code_singing_info(&self) -> Result<CFDictionary, Error> {
80 let mut dict: CFDictionaryRef = std::ptr::null_mut();
81
82 let sec = match &self.0 {
83 SecCodeKind::Static(sec) => sec.as_concrete_TypeRef(),
84 SecCodeKind::Dynamic(sec) => sec.as_CFTypeRef() as _, };
86
87 unsafe {
88 match SecCodeCopySigningInformation(
89 sec,
90 SecCSFlags::kSecCSSigningInformation,
91 Some(&mut dict),
92 ) {
93 sec_sys::errSecSuccess if !dict.is_null() => {
94 Ok(CFDictionary::wrap_under_create_rule(dict))
95 }
96 err => Err(Error::OsError(err)),
97 }
98 }
99 }
100
101 fn check_validity(&self, requirement: &str) -> Result<(), Error> {
102 let mut req: SecRequirementRef = std::ptr::null_mut();
103 let mut err: CFErrorRef = std::ptr::null_mut();
104
105 let req = unsafe {
107 match SecRequirementCreateWithStringAndErrors(
108 CFString::new(requirement).as_concrete_TypeRef(),
109 SecCSFlags::kSecCSDefaultFlags,
110 Some(&mut err),
111 Some(&mut req),
112 ) {
113 sec_sys::errSecSuccess if !req.is_null() => {
114 SecRequirement::wrap_under_create_rule(req)
115 }
116 status => {
117 if !err.is_null() {
118 return Err(err.into());
119 } else {
120 return Err(Error::OsError(status));
121 }
122 }
123 }
124 };
125
126 let status = match &self.0 {
127 SecCodeKind::Static(sec) => unsafe {
128 SecStaticCodeCheckValidityWithErrors(
129 sec.as_concrete_TypeRef(),
130 SecCSFlags::kSecCSDefaultFlags,
131 req.as_concrete_TypeRef(),
132 Some(&mut err),
133 )
134 },
135 SecCodeKind::Dynamic(sec) => unsafe {
136 SecCodeCheckValidityWithErrors(
137 sec.as_concrete_TypeRef(),
138 SecCSFlags::kSecCSDefaultFlags,
139 req.as_concrete_TypeRef(),
140 Some(&mut err),
141 )
142 },
143 };
144
145 match status {
146 sec_sys::errSecSuccess => Ok(()),
147 sec_sys::errSecCSUnsigned => Err(Error::Unsigned),
148 status => {
149 if !err.is_null() {
150 Err(err.into())
151 } else {
152 Err(Error::OsError(status))
153 }
154 }
155 }
156 }
157}
158
159#[allow(clippy::not_unsafe_ptr_arg_deref)]
160impl From<CFErrorRef> for Error {
161 fn from(err: CFErrorRef) -> Self {
162 if err.is_null() {
163 panic!()
164 }
165
166 unsafe {
167 let err = CFError::wrap_under_get_rule(err);
168
169 let err_dict = CFDictionary::<CFString, CFString>::wrap_under_create_rule(
170 CFErrorCopyUserInfo(err.as_concrete_TypeRef()),
171 );
172
173 if err.code() == -67050 {
174 if err_dict.len() == 1
178 && err_dict.contains_key(&CFString::from_static_string("SecCSArchitecture"))
179 {
180 return Error::Unsigned;
181 }
182 }
183
184 Error::CFError(format!("{err_dict:?}"))
185 }
186 }
187}