1use core_foundation::array::CFArray;
3#[cfg(target_os = "macos")]
4use core_foundation::array::CFArrayRef;
5use core_foundation::base::TCFType;
6use core_foundation::data::CFData;
7use core_foundation::date::CFDate;
8use core_foundation::{declare_TCFType, impl_TCFType};
9use core_foundation_sys::base::{Boolean, CFIndex};
10
11use security_framework_sys::base::{errSecNotTrusted, errSecTrustSettingDeny};
12use security_framework_sys::trust::*;
13use std::ptr;
14
15use crate::base::Result;
16use crate::certificate::SecCertificate;
17use crate::cvt;
18use crate::key::SecKey;
19use crate::policy::SecPolicy;
20use core_foundation::error::{CFError, CFErrorRef};
21
22#[derive(Debug, Copy, Clone, PartialEq, Eq)]
24pub struct TrustResult(SecTrustResultType);
25
26impl TrustResult {
27 pub const DENY: Self = Self(kSecTrustResultDeny);
29 pub const FATAL_TRUST_FAILURE: Self = Self(kSecTrustResultFatalTrustFailure);
31 pub const INVALID: Self = Self(kSecTrustResultInvalid);
33 pub const OTHER_ERROR: Self = Self(kSecTrustResultOtherError);
35 pub const PROCEED: Self = Self(kSecTrustResultProceed);
37 pub const RECOVERABLE_TRUST_FAILURE: Self = Self(kSecTrustResultRecoverableTrustFailure);
39 pub const UNSPECIFIED: Self = Self(kSecTrustResultUnspecified);
41}
42
43impl TrustResult {
44 #[inline]
46 #[must_use]
47 pub fn success(self) -> bool {
48 matches!(self, Self::PROCEED | Self::UNSPECIFIED)
49 }
50}
51
52declare_TCFType! {
53 SecTrust, SecTrustRef
55}
56impl_TCFType!(SecTrust, SecTrustRef, SecTrustGetTypeID);
57
58unsafe impl Sync for SecTrust {}
59unsafe impl Send for SecTrust {}
60
61#[cfg(target_os = "macos")]
62bitflags::bitflags! {
63 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65 pub struct TrustOptions: SecTrustOptionFlags {
66 const ALLOW_EXPIRED = kSecTrustOptionAllowExpired;
68 const LEAF_IS_CA = kSecTrustOptionLeafIsCA;
70 const FETCH_ISSUER_FROM_NET = kSecTrustOptionFetchIssuerFromNet;
72 const ALLOW_EXPIRED_ROOT = kSecTrustOptionAllowExpiredRoot;
74 const REQUIRE_REVOCATION_PER_CERT = kSecTrustOptionRequireRevPerCert;
76 const USE_TRUST_SETTINGS = kSecTrustOptionUseTrustSettings;
78 const IMPLICIT_ANCHORS = kSecTrustOptionImplicitAnchors;
80 }
81}
82
83impl SecTrust {
84 pub fn create_with_certificates(
87 certs: &[SecCertificate],
88 policies: &[SecPolicy],
89 ) -> Result<Self> {
90 let cert_array = CFArray::from_CFTypes(certs);
91 let policy_array = CFArray::from_CFTypes(policies);
92 let mut trust = ptr::null_mut();
93 unsafe {
94 cvt(SecTrustCreateWithCertificates(
95 cert_array.as_CFTypeRef(),
96 policy_array.as_CFTypeRef(),
97 &mut trust,
98 ))?;
99 Ok(Self(trust))
100 }
101 }
102
103 #[inline]
106 pub fn set_trust_verify_date(&mut self, date: &CFDate) -> Result<()> {
107 unsafe { cvt(SecTrustSetVerifyDate(self.0, date.as_concrete_TypeRef())) }
108 }
109
110 pub fn set_anchor_certificates(&mut self, certs: &[SecCertificate]) -> Result<()> {
112 let certs = CFArray::from_CFTypes(certs);
113
114 unsafe {
115 cvt(SecTrustSetAnchorCertificates(
116 self.0,
117 certs.as_concrete_TypeRef(),
118 ))
119 }
120 }
121
122 #[cfg(target_os = "macos")]
124 pub fn copy_anchor_certificates() -> Result<Vec<SecCertificate>> {
125 let mut array: CFArrayRef = ptr::null();
126
127 unsafe {
128 cvt(SecTrustCopyAnchorCertificates(&mut array))?;
129 }
130
131 if array.is_null() {
132 return Ok(vec![]);
133 }
134
135 let array = unsafe { CFArray::<SecCertificate>::wrap_under_create_rule(array) };
136 Ok(array.into_iter().map(|c| c.clone()).collect())
137 }
138
139 #[inline]
143 pub fn set_trust_anchor_certificates_only(&mut self, only: bool) -> Result<()> {
144 unsafe { cvt(SecTrustSetAnchorCertificatesOnly(self.0, Boolean::from(only))) }
145 }
146
147 #[inline]
149 pub fn set_policy(&mut self, policy: &SecPolicy) -> Result<()> {
150 unsafe { cvt(SecTrustSetPolicies(self.0, policy.as_CFTypeRef())) }
151 }
152
153 #[cfg(target_os = "macos")]
155 #[inline]
156 pub fn set_options(&mut self, options: TrustOptions) -> Result<()> {
157 unsafe { cvt(SecTrustSetOptions(self.0, options.bits())) }
158 }
159
160 pub fn get_network_fetch_allowed(&mut self) -> Result<bool> {
163 let mut allowed = 0;
164
165 unsafe { cvt(SecTrustGetNetworkFetchAllowed(self.0, &mut allowed))? };
166
167 Ok(allowed != 0)
168 }
169
170 #[inline]
173 pub fn set_network_fetch_allowed(&mut self, allowed: bool) -> Result<()> {
174 unsafe { cvt(SecTrustSetNetworkFetchAllowed(self.0, u8::from(allowed))) }
175 }
176
177 pub fn set_trust_ocsp_response<I: Iterator<Item = impl AsRef<[u8]>>>(
180 &mut self,
181 ocsp_response: I,
182 ) -> Result<()> {
183 let response: Vec<CFData> = ocsp_response
184 .into_iter()
185 .map(|bytes| CFData::from_buffer(bytes.as_ref()))
186 .collect();
187
188 let response = CFArray::from_CFTypes(&response);
189
190 unsafe { cvt(SecTrustSetOCSPResponse(self.0, response.as_CFTypeRef())) }
191 }
192
193 #[cfg(any(feature = "OSX_10_14", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
195 pub fn set_signed_certificate_timestamps<I: Iterator<Item = impl AsRef<[u8]>>>(
196 &mut self,
197 scts: I,
198 ) -> Result<()> {
199 let scts: Vec<CFData> = scts
200 .into_iter()
201 .map(|bytes| CFData::from_buffer(bytes.as_ref()))
202 .collect();
203
204 let scts = CFArray::from_CFTypes(&scts);
205
206 unsafe { cvt(SecTrustSetSignedCertificateTimestamps(self.0, scts.as_concrete_TypeRef())) }
207 }
208
209 #[inline]
211 pub fn copy_public_key(&mut self) -> Result<SecKey> {
212 unsafe { Ok(SecKey::wrap_under_create_rule(SecTrustCopyPublicKey(self.0))) }
213 }
214
215 #[deprecated(note = "use evaluate_with_error")]
217 pub fn evaluate(&self) -> Result<TrustResult> {
218 #[allow(deprecated)]
219 unsafe {
220 let mut result = kSecTrustResultInvalid;
221 cvt(SecTrustEvaluate(self.0, &mut result))?;
222 Ok(TrustResult(result))
223 }
224 }
225
226 pub fn evaluate_with_error(&self) -> Result<(), CFError> {
229 #[cfg(any(feature = "OSX_10_14", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
231 let fnptr = Some(SecTrustEvaluateWithError);
232
233 #[cfg(not(any(feature = "OSX_10_14", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos")))]
235 let fnptr = {
236 let fnptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"SecTrustEvaluateWithError\0".as_ptr().cast()) };
238 unsafe {
243 core::mem::transmute::<
244 *const std::os::raw::c_void,
245 Option<unsafe extern "C" fn(SecTrustRef, *mut CFErrorRef) -> bool>,
246 >(fnptr)
247 }
248 };
249
250 if let Some(fnptr) = fnptr {
252 let mut error: CFErrorRef = ::std::ptr::null_mut();
253 let result = unsafe { fnptr(self.0, &mut error) };
255 if !result {
256 assert!(!error.is_null());
257 let error = unsafe { CFError::wrap_under_create_rule(error) };
260 return Err(error);
261 }
262 Ok(())
263 } else {
264 #[allow(deprecated)]
267 let code = match self.evaluate() {
268 Ok(res) if res.success() => return Ok(()),
269 Ok(TrustResult::DENY) => errSecTrustSettingDeny,
270 Ok(_) => errSecNotTrusted,
271 Err(err) => err.code(),
272 };
273 Err(cferror_from_osstatus(code))
274 }
275 }
276
277 #[inline(always)]
281 #[must_use]
282 pub fn certificate_count(&self) -> CFIndex {
284 unsafe { SecTrustGetCertificateCount(self.0) }
285 }
286
287 #[deprecated(note = "deprecated by Apple")]
291 #[must_use]
292 pub fn certificate_at_index(&self, ix: CFIndex) -> Option<SecCertificate> {
293 #[allow(deprecated)]
294 unsafe {
295 if self.certificate_count() <= ix {
296 None
297 } else {
298 let certificate = SecTrustGetCertificateAtIndex(self.0, ix);
299 Some(SecCertificate::wrap_under_get_rule(certificate.cast()))
300 }
301 }
302 }
303}
304
305extern "C" {
306 fn CFErrorCreate(allocator: core_foundation_sys::base::CFAllocatorRef, domain: core_foundation_sys::string::CFStringRef, code: CFIndex, userInfo: core_foundation_sys::dictionary::CFDictionaryRef) -> CFErrorRef;
307}
308
309fn cferror_from_osstatus(code: core_foundation_sys::base::OSStatus) -> CFError {
310 unsafe {
311 let error = CFErrorCreate(ptr::null_mut(), core_foundation_sys::error::kCFErrorDomainOSStatus, code as _, ptr::null_mut());
312 assert!(!error.is_null());
313 CFError::wrap_under_create_rule(error)
314 }
315}
316
317#[cfg(test)]
318mod test {
319 use crate::policy::SecPolicy;
320 use crate::secure_transport::SslProtocolSide;
321 use crate::test::certificate;
322 use crate::trust::SecTrust;
323
324 #[test]
325 #[allow(deprecated)]
326 fn create_with_certificates() {
327 let cert = certificate();
328 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
329 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
330 assert!(!trust.evaluate().unwrap().success());
331 }
332
333 #[test]
334 fn create_with_certificates_new() {
335 let cert = certificate();
336 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
337 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
338 assert!(trust.evaluate_with_error().is_err());
339 }
340
341 #[test]
342 #[allow(deprecated)]
343 fn certificate_count_and_at_index() {
344 let cert = certificate();
345 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
346 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
347 trust.evaluate().unwrap();
348
349 let count = trust.certificate_count();
350 assert_eq!(count, 1);
351
352 let cert_bytes = trust.certificate_at_index(0).unwrap().to_der();
353 assert_eq!(cert_bytes, certificate().to_der());
354 }
355
356 #[test]
357 #[allow(deprecated)]
358 fn certificate_count_and_at_index_new() {
359 let cert = certificate();
360 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
361 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
362 assert!(trust.evaluate_with_error().is_err());
363
364 let count = trust.certificate_count();
365 assert_eq!(count, 1);
366
367 let cert_bytes = trust.certificate_at_index(0).unwrap().to_der();
368 assert_eq!(cert_bytes, certificate().to_der());
369 }
370
371 #[test]
372 #[allow(deprecated)]
373 fn certificate_at_index_out_of_bounds() {
374 let cert = certificate();
375 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
376
377 let trust = SecTrust::create_with_certificates(std::slice::from_ref(&cert), std::slice::from_ref(&ssl_policy)).unwrap();
378 trust.evaluate().unwrap();
379 assert!(trust.certificate_at_index(1).is_none());
380
381 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
382 assert!(trust.evaluate_with_error().is_err());
383 assert!(trust.certificate_at_index(1).is_none());
384 }
385
386 #[test]
387 #[allow(deprecated)]
388 fn set_policy() {
389 let cert = certificate();
390 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io.bogus"));
391 let mut trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
392 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
393 trust.set_policy(&ssl_policy).unwrap();
394 assert!(!trust.evaluate().unwrap().success());
395 }
396
397 #[test]
398 fn set_policy_new() {
399 let cert = certificate();
400 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io.bogus"));
401 let mut trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
402 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
403 trust.set_policy(&ssl_policy).unwrap();
404 assert!(trust.evaluate_with_error().is_err());
405 }
406}