Skip to main content

localauthentication/
la_persisted_right.rs

1//! `LAPersistedRight`, `LAPrivateKey`, and `LASecret` wrappers.
2
3use crate::ffi;
4use crate::la_error::{LAError, Result};
5use crate::la_public_key::{LAPublicKey, SecKeyAlgorithm};
6use crate::la_right::LARightState;
7use crate::private::{
8    bridge_bool, bridge_bytes, bridge_i32, bridge_i64, bridge_ptr, bridge_unit, cstring,
9    OwnedHandle,
10};
11
12/// Managed wrapper around Apple's `LAPersistedRight`.
13#[derive(Debug)]
14pub struct LAPersistedRight {
15    handle: OwnedHandle,
16}
17
18impl LAPersistedRight {
19    pub(crate) fn from_raw(raw: std::ptr::NonNull<core::ffi::c_void>) -> Self {
20        Self {
21            handle: OwnedHandle::new(raw, ffi::la_persisted_right::la_persisted_right_release),
22        }
23    }
24
25    pub(crate) const fn as_ptr(&self) -> *mut core::ffi::c_void {
26        self.handle.as_ptr()
27    }
28
29    /// The current authorization state.
30    ///
31    /// # Errors
32    ///
33    /// Returns an error if the Swift bridge rejects the request.
34    pub fn state(&self) -> Result<LARightState> {
35        let raw = bridge_i32(|out, error_out| unsafe {
36            ffi::la_persisted_right::la_persisted_right_get_state(
37                self.handle.as_ptr(),
38                out,
39                error_out,
40            )
41        })?;
42        Ok(LARightState::from_ffi(raw))
43    }
44
45    /// Application-controlled integer tag.
46    ///
47    /// # Errors
48    ///
49    /// Returns an error if the Swift bridge rejects the request.
50    pub fn tag(&self) -> Result<i64> {
51        bridge_i64(|out, error_out| unsafe {
52            ffi::la_persisted_right::la_persisted_right_get_tag(
53                self.handle.as_ptr(),
54                out,
55                error_out,
56            )
57        })
58    }
59
60    /// Update the application-controlled integer tag.
61    ///
62    /// # Errors
63    ///
64    /// Returns an error if the Swift bridge rejects the request.
65    pub fn set_tag(&self, tag: i64) -> Result<()> {
66        bridge_unit(|error_out| unsafe {
67            ffi::la_persisted_right::la_persisted_right_set_tag(
68                self.handle.as_ptr(),
69                tag,
70                error_out,
71            )
72        })
73    }
74
75    /// Attempt to authorize the persisted right.
76    ///
77    /// # Errors
78    ///
79    /// Returns a mapped framework or bridge error when authorization fails.
80    pub fn authorize(&self, localized_reason: &str) -> Result<()> {
81        if localized_reason.is_empty() {
82            return Err(LAError::InvalidArgument(
83                "localized reason must not be empty".to_owned(),
84            ));
85        }
86        let localized_reason = cstring(localized_reason)?;
87        bridge_unit(|error_out| unsafe {
88            ffi::la_persisted_right::la_persisted_right_authorize(
89                self.handle.as_ptr(),
90                localized_reason.as_ptr(),
91                error_out,
92            )
93        })
94    }
95
96    /// Preflight whether the persisted right can eventually be authorized.
97    ///
98    /// # Errors
99    ///
100    /// Returns a mapped framework or bridge error when authorization is not possible.
101    pub fn check_can_authorize(&self) -> Result<()> {
102        bridge_unit(|error_out| unsafe {
103            ffi::la_persisted_right::la_persisted_right_check_can_authorize(
104                self.handle.as_ptr(),
105                error_out,
106            )
107        })
108    }
109
110    /// Deauthorize the persisted right.
111    ///
112    /// # Errors
113    ///
114    /// Returns an error if the Swift bridge rejects the request.
115    pub fn deauthorize(&self) -> Result<()> {
116        bridge_unit(|error_out| unsafe {
117            ffi::la_persisted_right::la_persisted_right_deauthorize(self.handle.as_ptr(), error_out)
118        })
119    }
120
121    /// Borrow the managed private key associated with this persisted right.
122    ///
123    /// # Errors
124    ///
125    /// Returns an error if the Swift bridge rejects the request.
126    pub fn key(&self) -> Result<LAPrivateKey> {
127        Ok(LAPrivateKey::from_raw(bridge_ptr(
128            |out, error_out| unsafe {
129                ffi::la_persisted_right::la_persisted_right_get_key(
130                    self.handle.as_ptr(),
131                    out,
132                    error_out,
133                )
134            },
135        )?))
136    }
137
138    /// Borrow the generic secret associated with this persisted right.
139    ///
140    /// # Errors
141    ///
142    /// Returns an error if the Swift bridge rejects the request.
143    pub fn secret(&self) -> Result<LASecret> {
144        Ok(LASecret::from_raw(bridge_ptr(|out, error_out| unsafe {
145            ffi::la_persisted_right::la_persisted_right_get_secret(
146                self.handle.as_ptr(),
147                out,
148                error_out,
149            )
150        })?))
151    }
152
153    /// Convenience helper returning `self.key()?.public_key()`.
154    ///
155    /// # Errors
156    ///
157    /// Returns an error if the Swift bridge rejects the request.
158    pub fn public_key(&self) -> Result<LAPublicKey> {
159        self.key()?.public_key()
160    }
161}
162
163/// Managed wrapper around Apple's `LASecret`.
164#[derive(Debug)]
165pub struct LASecret {
166    handle: OwnedHandle,
167}
168
169impl LASecret {
170    pub(crate) fn from_raw(raw: std::ptr::NonNull<core::ffi::c_void>) -> Self {
171        Self {
172            handle: OwnedHandle::new(raw, ffi::la_persisted_right::la_secret_release),
173        }
174    }
175
176    /// Load the secret bytes.
177    ///
178    /// # Errors
179    ///
180    /// Returns a mapped framework or bridge error if loading fails.
181    pub fn load_data(&self) -> Result<Vec<u8>> {
182        bridge_bytes(|out, out_len, error_out| unsafe {
183            ffi::la_persisted_right::la_secret_load_data(
184                self.handle.as_ptr(),
185                out,
186                out_len,
187                error_out,
188            )
189        })
190    }
191}
192
193/// Managed wrapper around Apple's `LAPrivateKey`.
194#[derive(Debug)]
195pub struct LAPrivateKey {
196    handle: OwnedHandle,
197}
198
199impl LAPrivateKey {
200    pub(crate) fn from_raw(raw: std::ptr::NonNull<core::ffi::c_void>) -> Self {
201        Self {
202            handle: OwnedHandle::new(raw, ffi::la_persisted_right::la_private_key_release),
203        }
204    }
205
206    /// Borrow the public-key counterpart of this private key.
207    ///
208    /// # Errors
209    ///
210    /// Returns an error if the Swift bridge rejects the request.
211    pub fn public_key(&self) -> Result<LAPublicKey> {
212        Ok(LAPublicKey::from_raw(bridge_ptr(
213            |out, error_out| unsafe {
214                ffi::la_persisted_right::la_private_key_get_public_key(
215                    self.handle.as_ptr(),
216                    out,
217                    error_out,
218                )
219            },
220        )?))
221    }
222
223    /// Check whether an algorithm can sign with this key.
224    ///
225    /// # Errors
226    ///
227    /// Returns an error if the Swift bridge rejects the request.
228    pub fn can_sign_using(&self, algorithm: &SecKeyAlgorithm) -> Result<bool> {
229        let algorithm = cstring(algorithm.raw_name())?;
230        bridge_bool(|out, error_out| unsafe {
231            ffi::la_persisted_right::la_private_key_can_sign_using_algorithm(
232                self.handle.as_ptr(),
233                algorithm.as_ptr(),
234                out,
235                error_out,
236            )
237        })
238    }
239
240    /// Sign data with this key.
241    ///
242    /// # Errors
243    ///
244    /// Returns a mapped framework or bridge error if signing fails.
245    pub fn sign(&self, data: &[u8], algorithm: &SecKeyAlgorithm) -> Result<Vec<u8>> {
246        let algorithm = cstring(algorithm.raw_name())?;
247        bridge_bytes(|out, out_len, error_out| unsafe {
248            ffi::la_persisted_right::la_private_key_sign_data(
249                self.handle.as_ptr(),
250                data.as_ptr(),
251                data.len(),
252                algorithm.as_ptr(),
253                out,
254                out_len,
255                error_out,
256            )
257        })
258    }
259
260    /// Check whether an algorithm can decrypt with this key.
261    ///
262    /// # Errors
263    ///
264    /// Returns an error if the Swift bridge rejects the request.
265    pub fn can_decrypt_using(&self, algorithm: &SecKeyAlgorithm) -> Result<bool> {
266        let algorithm = cstring(algorithm.raw_name())?;
267        bridge_bool(|out, error_out| unsafe {
268            ffi::la_persisted_right::la_private_key_can_decrypt_using_algorithm(
269                self.handle.as_ptr(),
270                algorithm.as_ptr(),
271                out,
272                error_out,
273            )
274        })
275    }
276
277    /// Decrypt data with this key.
278    ///
279    /// # Errors
280    ///
281    /// Returns a mapped framework or bridge error if decryption fails.
282    pub fn decrypt(&self, data: &[u8], algorithm: &SecKeyAlgorithm) -> Result<Vec<u8>> {
283        let algorithm = cstring(algorithm.raw_name())?;
284        bridge_bytes(|out, out_len, error_out| unsafe {
285            ffi::la_persisted_right::la_private_key_decrypt_data(
286                self.handle.as_ptr(),
287                data.as_ptr(),
288                data.len(),
289                algorithm.as_ptr(),
290                out,
291                out_len,
292                error_out,
293            )
294        })
295    }
296
297    /// Check whether an algorithm can be used for key exchange.
298    ///
299    /// # Errors
300    ///
301    /// Returns an error if the Swift bridge rejects the request.
302    pub fn can_exchange_keys_using(&self, algorithm: &SecKeyAlgorithm) -> Result<bool> {
303        let algorithm = cstring(algorithm.raw_name())?;
304        bridge_bool(|out, error_out| unsafe {
305            ffi::la_persisted_right::la_private_key_can_exchange_keys_using_algorithm(
306                self.handle.as_ptr(),
307                algorithm.as_ptr(),
308                out,
309                error_out,
310            )
311        })
312    }
313}