1use apple_cf::CFError;
4
5use crate::certificate::Certificate;
6use crate::error::{Result, SecurityError};
7use crate::ffi;
8use crate::private::{cf_array, cf_error_description, cf_string, sec_error_message, OwnedCf};
9
10pub struct Policy {
12 raw: ffi::SecPolicyRef,
13}
14
15impl Policy {
16 pub fn basic_x509() -> Result<Self> {
22 let raw = unsafe { ffi::SecPolicyCreateBasicX509() };
23 if raw.is_null() {
24 return Err(SecurityError::CoreFoundation(CFError::new(
25 "SecPolicyCreateBasicX509",
26 )));
27 }
28 Ok(Self { raw })
29 }
30
31 pub fn ssl(server: bool, hostname: Option<&str>) -> Result<Self> {
37 let hostname = hostname.map(cf_string).transpose()?;
38 let raw = unsafe {
39 ffi::SecPolicyCreateSSL(
40 u8::from(server),
41 hostname
42 .as_ref()
43 .map_or(std::ptr::null(), OwnedCf::as_string),
44 )
45 };
46 if raw.is_null() {
47 return Err(SecurityError::CoreFoundation(CFError::new(
48 "SecPolicyCreateSSL",
49 )));
50 }
51 Ok(Self { raw })
52 }
53
54 #[must_use]
56 pub const fn as_raw(&self) -> ffi::SecPolicyRef {
57 self.raw
58 }
59}
60
61impl Drop for Policy {
62 fn drop(&mut self) {
63 if !self.raw.is_null() {
64 unsafe { ffi::CFRelease(self.raw.cast()) };
65 }
66 }
67}
68
69impl core::fmt::Debug for Policy {
70 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
71 f.debug_struct("Policy").field("raw", &self.raw).finish()
72 }
73}
74
75pub struct Trust {
77 raw: ffi::SecTrustRef,
78}
79
80impl Trust {
81 pub fn new(certificate: &Certificate, policies: &[Policy]) -> Result<Self> {
87 if policies.is_empty() {
88 return Err(SecurityError::InvalidArgument(
89 "at least one trust policy is required".to_owned(),
90 ));
91 }
92
93 let policy_input = policy_input(policies)?;
94 let mut trust = std::ptr::null();
95 let status = unsafe {
96 ffi::SecTrustCreateWithCertificates(
97 certificate.as_raw().cast(),
98 policy_input.raw,
99 &mut trust,
100 )
101 };
102 if status != ffi::status::SUCCESS {
103 return Err(SecurityError::from_status(
104 "SecTrustCreateWithCertificates",
105 status,
106 sec_error_message(status),
107 ));
108 }
109 if trust.is_null() {
110 return Err(SecurityError::CoreFoundation(CFError::new(
111 "SecTrustCreateWithCertificates",
112 )));
113 }
114 Ok(Self { raw: trust })
115 }
116
117 pub fn set_policies(&mut self, policies: &[Policy]) -> Result<()> {
123 if policies.is_empty() {
124 return Err(SecurityError::InvalidArgument(
125 "at least one trust policy is required".to_owned(),
126 ));
127 }
128 let policy_input = policy_input(policies)?;
129 let status = unsafe { ffi::SecTrustSetPolicies(self.raw, policy_input.raw) };
130 if status == ffi::status::SUCCESS {
131 Ok(())
132 } else {
133 Err(SecurityError::from_status(
134 "SecTrustSetPolicies",
135 status,
136 sec_error_message(status),
137 ))
138 }
139 }
140
141 pub fn evaluate(&self) -> Result<()> {
147 let mut error = std::ptr::null();
148 let ok = unsafe { ffi::SecTrustEvaluateWithError(self.raw, &mut error) };
149 if ok != 0 {
150 Ok(())
151 } else {
152 Err(SecurityError::TrustEvaluationFailed(cf_error_description(
153 error,
154 )))
155 }
156 }
157
158 #[must_use]
160 pub const fn as_raw(&self) -> ffi::SecTrustRef {
161 self.raw
162 }
163}
164
165impl Drop for Trust {
166 fn drop(&mut self) {
167 if !self.raw.is_null() {
168 unsafe { ffi::CFRelease(self.raw.cast()) };
169 }
170 }
171}
172
173impl core::fmt::Debug for Trust {
174 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
175 f.debug_struct("Trust").field("raw", &self.raw).finish()
176 }
177}
178
179struct PolicyInput {
180 raw: ffi::CFTypeRef,
181 _array: Option<OwnedCf>,
182}
183
184fn policy_input(policies: &[Policy]) -> Result<PolicyInput> {
185 if policies.len() == 1 {
186 return Ok(PolicyInput {
187 raw: policies[0].as_raw().cast(),
188 _array: None,
189 });
190 }
191
192 let policy_refs = policies
193 .iter()
194 .map(|policy| policy.as_raw().cast())
195 .collect::<Vec<_>>();
196 let array = cf_array(&policy_refs)?;
197 Ok(PolicyInput {
198 raw: array.as_ptr(),
199 _array: Some(array),
200 })
201}