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(crate) fn from_handle(handle: Handle) -> Self {
107 Self { handle }
108 }
109
110 pub(crate) fn handle(&self) -> &Handle {
111 &self.handle
112 }
113
114 pub fn basic_x509() -> Result<Self> {
115 let mut status = 0;
116 let mut error = std::ptr::null_mut();
117 let raw = unsafe { bridge::security_policy_create_basic_x509(&mut status, &mut error) };
118 bridge::required_handle("security_policy_create_basic_x509", raw, status, error)
119 .map(Self::from_handle)
120 }
121
122 pub fn ssl(server: bool, hostname: Option<&str>) -> Result<Self> {
123 let hostname = hostname.map(bridge::cstring).transpose()?;
124 let mut status = 0;
125 let mut error = std::ptr::null_mut();
126 let raw = unsafe {
127 bridge::security_policy_create_ssl(
128 server,
129 hostname
130 .as_ref()
131 .map_or(std::ptr::null(), |value| value.as_c_str().as_ptr()),
132 &mut status,
133 &mut error,
134 )
135 };
136 bridge::required_handle("security_policy_create_ssl", raw, status, error)
137 .map(Self::from_handle)
138 }
139
140 pub fn revocation(flags: RevocationFlags) -> Result<Self> {
141 let mut status = 0;
142 let mut error = std::ptr::null_mut();
143 let raw =
144 unsafe { bridge::security_policy_create_revocation(flags, &mut status, &mut error) };
145 bridge::required_handle("security_policy_create_revocation", raw, status, error)
146 .map(Self::from_handle)
147 }
148
149 pub fn with_properties(
150 identifier: PolicyIdentifier,
151 properties: &PolicyProperties,
152 ) -> Result<Self> {
153 let identifier = bridge::cstring(identifier.as_bridge_name())?;
154 let properties = if properties.is_empty() {
155 None
156 } else {
157 let json = serde_json::to_string(properties).map_err(|error| {
158 SecurityError::Serialization(format!("policy properties JSON failed: {error}"))
159 })?;
160 Some(bridge::cstring(&json)?)
161 };
162 let mut status = 0;
163 let mut error = std::ptr::null_mut();
164 let raw = unsafe {
165 bridge::security_policy_create_with_properties(
166 identifier.as_ptr(),
167 properties
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_with_properties", raw, status, error)
175 .map(Self::from_handle)
176 }
177
178 pub fn properties(&self) -> Result<Value> {
179 let mut status = 0;
180 let mut error = std::ptr::null_mut();
181 let raw = unsafe {
182 bridge::security_policy_copy_properties(self.handle.as_ptr(), &mut status, &mut error)
183 };
184 bridge::required_json("security_policy_copy_properties", raw, status, error)
185 }
186}