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