Skip to main content

security/
policy.rs

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}