1use serde::Serialize;
2use serde_json::Value;
3
4use crate::bridge::{self, Handle};
5use crate::error::{Result, SecurityError};
6
7pub type RevocationFlags = u32;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum PolicyIdentifier {
13 AppleX509Basic,
15 AppleSsl,
17 AppleSmime,
19 AppleEap,
21 AppleIpsec,
23 ApplePkinitClient,
25 ApplePkinitServer,
27 AppleCodeSigning,
29 MacAppStoreReceipt,
31 AppleIdValidation,
33 AppleTimeStamping,
35 AppleRevocation,
37 ApplePassbookSigning,
39 ApplePayIssuerEncryption,
41 AppleSslServer,
43 AppleSslClient,
45 AppleEapServer,
47 AppleEapClient,
49 AppleIpsecServer,
51 AppleIpsecClient,
53}
54
55impl PolicyIdentifier {
56 const fn as_bridge_name(self) -> &'static str {
57 match self {
58 Self::AppleX509Basic => "apple_x509_basic",
59 Self::AppleSsl => "apple_ssl",
60 Self::AppleSmime => "apple_smime",
61 Self::AppleEap => "apple_eap",
62 Self::AppleIpsec => "apple_ipsec",
63 Self::ApplePkinitClient => "apple_pkinit_client",
64 Self::ApplePkinitServer => "apple_pkinit_server",
65 Self::AppleCodeSigning => "apple_code_signing",
66 Self::MacAppStoreReceipt => "mac_app_store_receipt",
67 Self::AppleIdValidation => "apple_id_validation",
68 Self::AppleTimeStamping => "apple_time_stamping",
69 Self::AppleRevocation => "apple_revocation",
70 Self::ApplePassbookSigning => "apple_passbook_signing",
71 Self::ApplePayIssuerEncryption => "apple_pay_issuer_encryption",
72 Self::AppleSslServer => "apple_ssl_server",
73 Self::AppleSslClient => "apple_ssl_client",
74 Self::AppleEapServer => "apple_eap_server",
75 Self::AppleEapClient => "apple_eap_client",
76 Self::AppleIpsecServer => "apple_ipsec_server",
77 Self::AppleIpsecClient => "apple_ipsec_client",
78 }
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
83#[serde(untagged)]
84pub enum PolicyName {
86 Single(String),
88 Multiple(Vec<String>),
90}
91
92impl From<String> for PolicyName {
93 fn from(value: String) -> Self {
94 Self::Single(value)
95 }
96}
97
98impl From<&str> for PolicyName {
99 fn from(value: &str) -> Self {
100 Self::Single(value.to_owned())
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
105pub struct PolicyProperties {
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub name: Option<PolicyName>,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub client: Option<bool>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub revocation_flags: Option<RevocationFlags>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub team_identifier: Option<String>,
119}
120
121impl PolicyProperties {
122 const fn is_empty(&self) -> bool {
123 self.name.is_none()
124 && self.client.is_none()
125 && self.revocation_flags.is_none()
126 && self.team_identifier.is_none()
127 }
128}
129
130#[derive(Debug)]
131pub struct Policy {
133 handle: Handle,
134}
135
136impl Policy {
137 pub fn type_id() -> usize {
139 unsafe { bridge::security_policy_get_type_id() }
140 }
141
142 pub(crate) fn from_handle(handle: Handle) -> Self {
143 Self { handle }
144 }
145
146 pub(crate) fn handle(&self) -> &Handle {
147 &self.handle
148 }
149
150 pub fn basic_x509() -> Result<Self> {
152 let mut status = 0;
153 let mut error = std::ptr::null_mut();
154 let raw = unsafe { bridge::security_policy_create_basic_x509(&mut status, &mut error) };
155 bridge::required_handle("security_policy_create_basic_x509", raw, status, error)
156 .map(Self::from_handle)
157 }
158
159 pub fn ssl(server: bool, hostname: Option<&str>) -> Result<Self> {
161 let hostname = hostname.map(bridge::cstring).transpose()?;
162 let mut status = 0;
163 let mut error = std::ptr::null_mut();
164 let raw = unsafe {
165 bridge::security_policy_create_ssl(
166 server,
167 hostname
168 .as_ref()
169 .map_or(std::ptr::null(), |value| value.as_c_str().as_ptr()),
170 &mut status,
171 &mut error,
172 )
173 };
174 bridge::required_handle("security_policy_create_ssl", raw, status, error)
175 .map(Self::from_handle)
176 }
177
178 pub fn revocation(flags: RevocationFlags) -> Result<Self> {
180 let mut status = 0;
181 let mut error = std::ptr::null_mut();
182 let raw =
183 unsafe { bridge::security_policy_create_revocation(flags, &mut status, &mut error) };
184 bridge::required_handle("security_policy_create_revocation", raw, status, error)
185 .map(Self::from_handle)
186 }
187
188 pub fn with_properties(
190 identifier: PolicyIdentifier,
191 properties: &PolicyProperties,
192 ) -> Result<Self> {
193 let identifier = bridge::cstring(identifier.as_bridge_name())?;
194 let properties = if properties.is_empty() {
195 None
196 } else {
197 let json = serde_json::to_string(properties).map_err(|error| {
198 SecurityError::Serialization(format!("policy properties JSON failed: {error}"))
199 })?;
200 Some(bridge::cstring(&json)?)
201 };
202 let mut status = 0;
203 let mut error = std::ptr::null_mut();
204 let raw = unsafe {
205 bridge::security_policy_create_with_properties(
206 identifier.as_ptr(),
207 properties
208 .as_ref()
209 .map_or(std::ptr::null(), |value| value.as_c_str().as_ptr()),
210 &mut status,
211 &mut error,
212 )
213 };
214 bridge::required_handle("security_policy_create_with_properties", raw, status, error)
215 .map(Self::from_handle)
216 }
217
218 pub fn properties(&self) -> Result<Value> {
220 let mut status = 0;
221 let mut error = std::ptr::null_mut();
222 let raw = unsafe {
223 bridge::security_policy_copy_properties(self.handle.as_ptr(), &mut status, &mut error)
224 };
225 bridge::required_json("security_policy_copy_properties", raw, status, error)
226 }
227}