security_framework/
trust.rs1use 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::trust::*;
12use std::ptr;
13
14use crate::base::Result;
15use crate::certificate::SecCertificate;
16use crate::cvt;
17use crate::key::SecKey;
18use crate::policy::SecPolicy;
19use core_foundation::error::{CFError, CFErrorRef};
20
21#[derive(Debug, Copy, Clone, PartialEq, Eq)]
23pub struct TrustResult(SecTrustResultType);
24
25impl TrustResult {
26 pub const DENY: Self = Self(kSecTrustResultDeny);
28 pub const FATAL_TRUST_FAILURE: Self = Self(kSecTrustResultFatalTrustFailure);
30 pub const INVALID: Self = Self(kSecTrustResultInvalid);
32 pub const OTHER_ERROR: Self = Self(kSecTrustResultOtherError);
34 pub const PROCEED: Self = Self(kSecTrustResultProceed);
36 pub const RECOVERABLE_TRUST_FAILURE: Self = Self(kSecTrustResultRecoverableTrustFailure);
38 pub const UNSPECIFIED: Self = Self(kSecTrustResultUnspecified);
40}
41
42impl TrustResult {
43 #[inline]
45 #[must_use]
46 pub fn success(self) -> bool {
47 matches!(self, Self::PROCEED | Self::UNSPECIFIED)
48 }
49}
50
51declare_TCFType! {
52 SecTrust, SecTrustRef
54}
55impl_TCFType!(SecTrust, SecTrustRef, SecTrustGetTypeID);
56
57unsafe impl Sync for SecTrust {}
58unsafe impl Send for SecTrust {}
59
60#[cfg(target_os = "macos")]
61bitflags::bitflags! {
62 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
64 pub struct TrustOptions: SecTrustOptionFlags {
65 const ALLOW_EXPIRED = kSecTrustOptionAllowExpired;
67 const LEAF_IS_CA = kSecTrustOptionLeafIsCA;
69 const FETCH_ISSUER_FROM_NET = kSecTrustOptionFetchIssuerFromNet;
71 const ALLOW_EXPIRED_ROOT = kSecTrustOptionAllowExpiredRoot;
73 const REQUIRE_REVOCATION_PER_CERT = kSecTrustOptionRequireRevPerCert;
75 const USE_TRUST_SETTINGS = kSecTrustOptionUseTrustSettings;
77 const IMPLICIT_ANCHORS = kSecTrustOptionImplicitAnchors;
79 }
80}
81
82impl SecTrust {
83 pub fn create_with_certificates(
86 certs: &[SecCertificate],
87 policies: &[SecPolicy],
88 ) -> Result<Self> {
89 let cert_array = CFArray::from_CFTypes(certs);
90 let policy_array = CFArray::from_CFTypes(policies);
91 let mut trust = ptr::null_mut();
92 unsafe {
93 cvt(SecTrustCreateWithCertificates(
94 cert_array.as_CFTypeRef(),
95 policy_array.as_CFTypeRef(),
96 &mut trust,
97 ))?;
98 Ok(Self(trust))
99 }
100 }
101
102 #[inline]
105 pub fn set_trust_verify_date(&mut self, date: &CFDate) -> Result<()> {
106 unsafe { cvt(SecTrustSetVerifyDate(self.0, date.as_concrete_TypeRef())) }
107 }
108
109 pub fn set_anchor_certificates(&mut self, certs: &[SecCertificate]) -> Result<()> {
111 let certs = CFArray::from_CFTypes(certs);
112
113 unsafe {
114 cvt(SecTrustSetAnchorCertificates(
115 self.0,
116 certs.as_concrete_TypeRef(),
117 ))
118 }
119 }
120
121 #[cfg(target_os = "macos")]
123 pub fn copy_anchor_certificates() -> Result<Vec<SecCertificate>> {
124 let mut array: CFArrayRef = ptr::null();
125
126 unsafe {
127 cvt(SecTrustCopyAnchorCertificates(&mut array))?;
128 }
129
130 if array.is_null() {
131 return Ok(vec![]);
132 }
133
134 let array = unsafe { CFArray::<SecCertificate>::wrap_under_create_rule(array) };
135 Ok(array.into_iter().map(|c| c.clone()).collect())
136 }
137
138 #[inline]
142 pub fn set_trust_anchor_certificates_only(&mut self, only: bool) -> Result<()> {
143 unsafe { cvt(SecTrustSetAnchorCertificatesOnly(self.0, Boolean::from(only))) }
144 }
145
146 #[inline]
148 pub fn set_policy(&mut self, policy: &SecPolicy) -> Result<()> {
149 unsafe { cvt(SecTrustSetPolicies(self.0, policy.as_CFTypeRef())) }
150 }
151
152 #[cfg(target_os = "macos")]
154 #[inline]
155 pub fn set_options(&mut self, options: TrustOptions) -> Result<()> {
156 unsafe { cvt(SecTrustSetOptions(self.0, options.bits())) }
157 }
158
159 pub fn get_network_fetch_allowed(&mut self) -> Result<bool> {
162 let mut allowed = 0;
163
164 unsafe { cvt(SecTrustGetNetworkFetchAllowed(self.0, &mut allowed))? };
165
166 Ok(allowed != 0)
167 }
168
169 #[inline]
172 pub fn set_network_fetch_allowed(&mut self, allowed: bool) -> Result<()> {
173 unsafe { cvt(SecTrustSetNetworkFetchAllowed(self.0, u8::from(allowed))) }
174 }
175
176 pub fn set_trust_ocsp_response<I: Iterator<Item = impl AsRef<[u8]>>>(
179 &mut self,
180 ocsp_response: I,
181 ) -> Result<()> {
182 let response: Vec<CFData> = ocsp_response
183 .into_iter()
184 .map(|bytes| CFData::from_buffer(bytes.as_ref()))
185 .collect();
186
187 let response = CFArray::from_CFTypes(&response);
188
189 unsafe { cvt(SecTrustSetOCSPResponse(self.0, response.as_CFTypeRef())) }
190 }
191
192 pub fn set_signed_certificate_timestamps<I: Iterator<Item = impl AsRef<[u8]>>>(
194 &mut self,
195 scts: I,
196 ) -> Result<()> {
197 let scts: Vec<CFData> = scts
198 .into_iter()
199 .map(|bytes| CFData::from_buffer(bytes.as_ref()))
200 .collect();
201
202 let scts = CFArray::from_CFTypes(&scts);
203
204 unsafe { cvt(SecTrustSetSignedCertificateTimestamps(self.0, scts.as_concrete_TypeRef())) }
205 }
206
207 #[inline]
209 pub fn copy_public_key(&mut self) -> Result<SecKey> {
210 unsafe { Ok(SecKey::wrap_under_create_rule(SecTrustCopyPublicKey(self.0))) }
211 }
212
213 #[deprecated(note = "use evaluate_with_error")]
215 pub fn evaluate(&self) -> Result<TrustResult> {
216 #[allow(deprecated)]
217 unsafe {
218 let mut result = kSecTrustResultInvalid;
219 cvt(SecTrustEvaluate(self.0, &mut result))?;
220 Ok(TrustResult(result))
221 }
222 }
223
224 pub fn evaluate_with_error(&self) -> Result<(), CFError> {
227 let mut error: CFErrorRef = ::std::ptr::null_mut();
228 let result = unsafe { SecTrustEvaluateWithError(self.0, &mut error) };
229 if !result {
230 assert!(!error.is_null());
231 let error = unsafe { CFError::wrap_under_create_rule(error) };
234 return Err(error);
235 }
236 Ok(())
237 }
238
239 #[cfg(any(feature = "macos-12", not(target_os = "macos")))]
243 pub fn chain(&self) -> Vec<SecCertificate> {
244 let array = unsafe { SecTrustCopyCertificateChain(self.0) };
245
246 if array.is_null() {
247 return vec![];
248 }
249
250 let array = unsafe { CFArray::<SecCertificate>::wrap_under_create_rule(array) };
251 array.into_iter().map(|c| c.clone()).collect()
252 }
253
254 #[inline(always)]
258 #[must_use]
259 #[deprecated(note = "deprecated by Apple, use chain(), enable macos-12 feature")]
260 pub fn certificate_count(&self) -> CFIndex {
262 unsafe { SecTrustGetCertificateCount(self.0) }
263 }
264
265 #[deprecated(note = "deprecated by Apple, use chain(), enable macos-12 feature")]
269 #[must_use]
270 pub fn certificate_at_index(&self, ix: CFIndex) -> Option<SecCertificate> {
271 #[allow(deprecated)]
272 unsafe {
273 if self.certificate_count() <= ix {
274 None
275 } else {
276 let certificate = SecTrustGetCertificateAtIndex(self.0, ix);
277 Some(SecCertificate::wrap_under_get_rule(certificate.cast()))
278 }
279 }
280 }
281}
282
283#[cfg(test)]
284mod test {
285 use crate::policy::SecPolicy;
286 use crate::secure_transport::SslProtocolSide;
287 use crate::test::certificate;
288 use crate::trust::SecTrust;
289
290 #[test]
291 #[allow(deprecated)]
292 fn create_with_certificates() {
293 let cert = certificate();
294 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
295 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
296 assert!(!trust.evaluate().unwrap().success());
297 }
298
299 #[test]
300 fn create_with_certificates_new() {
301 let cert = certificate();
302 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
303 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
304 assert!(trust.evaluate_with_error().is_err());
305 }
306
307 #[test]
308 #[allow(deprecated)]
309 fn certificate_count_and_at_index() {
310 let cert = certificate();
311 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
312 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
313 trust.evaluate().unwrap();
314
315 let count = trust.certificate_count();
316 assert!(count >= 1);
318
319 let cert_bytes = trust.certificate_at_index(0).unwrap().to_der();
320 assert_eq!(cert_bytes, certificate().to_der());
321 }
322
323 #[test]
324 #[allow(deprecated)]
325 fn certificate_count_and_at_index_new() {
326 let cert = certificate();
327 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
328 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
329 assert!(trust.evaluate_with_error().is_err());
330
331 let count = trust.certificate_count();
332 assert!(count >= 1);
334
335 let cert_bytes = trust.certificate_at_index(0).unwrap().to_der();
336 assert_eq!(cert_bytes, certificate().to_der());
337 }
338
339 #[test]
340 #[allow(deprecated)]
341 fn certificate_at_index_out_of_bounds() {
342 let cert = certificate();
343 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
344
345 let trust = SecTrust::create_with_certificates(std::slice::from_ref(&cert), std::slice::from_ref(&ssl_policy)).unwrap();
346 trust.evaluate().unwrap();
347 assert!(trust.certificate_at_index(10).is_none());
348
349 let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
350 assert!(trust.evaluate_with_error().is_err());
351 assert!(trust.certificate_at_index(10).is_none());
352 }
353
354 #[test]
355 #[allow(deprecated)]
356 fn set_policy() {
357 let cert = certificate();
358 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io.bogus"));
359 let mut trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
360 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
361 trust.set_policy(&ssl_policy).unwrap();
362 assert!(!trust.evaluate().unwrap().success());
363 }
364
365 #[test]
366 fn set_policy_new() {
367 let cert = certificate();
368 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io.bogus"));
369 let mut trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
370 let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
371 trust.set_policy(&ssl_policy).unwrap();
372 assert!(trust.evaluate_with_error().is_err());
373 }
374}