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(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}