Skip to main content

security/certificate/
mod.rs

1use std::time::{Duration, SystemTime, UNIX_EPOCH};
2
3use base64::Engine;
4use serde_json::Value;
5
6use crate::bridge::{self, Handle};
7use crate::error::{Result, SecurityError};
8use crate::key::{self, EncryptionAlgorithm, ExternalFormat, ExternalItemType, SignatureAlgorithm};
9
10#[derive(Debug)]
11/// Wraps a public `SecKeyRef`.
12pub struct PublicKey {
13    handle: Handle,
14}
15
16impl PublicKey {
17    /// Wraps the corresponding public `SecKeyRef` operation.
18    pub fn type_id() -> usize {
19        key::key_type_id()
20    }
21
22    pub(crate) fn from_handle(handle: Handle) -> Self {
23        Self { handle }
24    }
25
26    /// Wraps the corresponding public `SecKeyRef` operation.
27    pub fn attributes(&self) -> Result<Value> {
28        let mut status = 0;
29        let mut error = std::ptr::null_mut();
30        let raw = unsafe {
31            bridge::security_key_copy_attributes(self.handle.as_ptr(), &mut status, &mut error)
32        };
33        bridge::required_json("security_key_copy_attributes", raw, status, error)
34    }
35
36    /// Wraps the corresponding public `SecKeyRef` operation.
37    pub fn block_size(&self) -> usize {
38        key::key_block_size(&self.handle)
39    }
40
41    /// Wraps the corresponding public `SecKeyRef` operation.
42    pub fn external_representation(&self) -> Result<Vec<u8>> {
43        key::key_external_representation(&self.handle)
44    }
45
46    /// Wraps the corresponding public `SecKeyRef` operation.
47    pub fn encrypt(&self, algorithm: EncryptionAlgorithm, plaintext: &[u8]) -> Result<Vec<u8>> {
48        key::encrypt_with_public_key(&self.handle, algorithm, plaintext)
49    }
50
51    /// Wraps the corresponding public `SecKeyRef` operation.
52    pub fn verify_signature(
53        &self,
54        algorithm: SignatureAlgorithm,
55        signed_data: &[u8],
56        signature: &[u8],
57    ) -> Result<bool> {
58        let mut status = 0;
59        let mut error = std::ptr::null_mut();
60        let valid = unsafe {
61            bridge::security_public_key_verify_signature(
62                self.handle.as_ptr(),
63                algorithm as u32,
64                signed_data.as_ptr().cast(),
65                bridge::len_to_isize(signed_data.len())?,
66                signature.as_ptr().cast(),
67                bridge::len_to_isize(signature.len())?,
68                &mut status,
69                &mut error,
70            )
71        };
72        if status != 0 {
73            return Err(bridge::status_error(
74                "security_public_key_verify_signature",
75                status,
76                error,
77            )?);
78        }
79        Ok(valid)
80    }
81}
82
83#[derive(Debug)]
84/// Wraps `SecCertificateRef`.
85pub struct Certificate {
86    handle: Handle,
87}
88
89impl Certificate {
90    pub(crate) fn from_handle(handle: Handle) -> Self {
91        Self { handle }
92    }
93
94    pub(crate) fn handle(&self) -> &Handle {
95        &self.handle
96    }
97
98    /// Wraps the corresponding `SecCertificateRef` operation.
99    pub fn type_id() -> usize {
100        unsafe { bridge::security_certificate_get_type_id() }
101    }
102
103    /// Wraps the corresponding `SecCertificateRef` operation.
104    pub fn from_der(der: &[u8]) -> Result<Self> {
105        let mut status = 0;
106        let mut error = std::ptr::null_mut();
107        let raw = unsafe {
108            bridge::security_certificate_from_der(
109                der.as_ptr().cast(),
110                bridge::len_to_isize(der.len())?,
111                &mut status,
112                &mut error,
113            )
114        };
115        bridge::required_handle("security_certificate_from_der", raw, status, error)
116            .map(Self::from_handle)
117    }
118
119    /// Wraps the corresponding `SecCertificateRef` operation.
120    pub fn import_item(
121        data: &[u8],
122        file_name_or_extension: Option<&str>,
123        format: ExternalFormat,
124        item_type: ExternalItemType,
125    ) -> Result<Self> {
126        let file_name_or_extension = file_name_or_extension.map(bridge::cstring).transpose()?;
127        let mut status = 0;
128        let mut error = std::ptr::null_mut();
129        let raw = unsafe {
130            bridge::security_certificate_import_item(
131                data.as_ptr().cast(),
132                bridge::len_to_isize(data.len())?,
133                file_name_or_extension
134                    .as_ref()
135                    .map_or(std::ptr::null(), |value| value.as_ptr()),
136                format as u32,
137                item_type as u32,
138                &mut status,
139                &mut error,
140            )
141        };
142        bridge::required_handle("security_certificate_import_item", raw, status, error)
143            .map(Self::from_handle)
144    }
145
146    /// Wraps the corresponding `SecCertificateRef` operation.
147    pub fn export_item(&self, format: ExternalFormat, pem_armour: bool) -> Result<Vec<u8>> {
148        let mut status = 0;
149        let mut error = std::ptr::null_mut();
150        let raw = unsafe {
151            bridge::security_certificate_export_item(
152                self.handle.as_ptr(),
153                format as u32,
154                pem_armour,
155                &mut status,
156                &mut error,
157            )
158        };
159        bridge::required_data("security_certificate_export_item", raw, status, error)
160    }
161
162    /// Wraps the corresponding `SecCertificateRef` operation.
163    pub fn from_pem(pem: &[u8]) -> Result<Self> {
164        let pem = std::str::from_utf8(pem).map_err(|error| {
165            SecurityError::InvalidArgument(format!("PEM input was not valid UTF-8: {error}"))
166        })?;
167        let base64 = pem
168            .lines()
169            .filter(|line| !line.starts_with("-----"))
170            .collect::<String>();
171        let der = base64::engine::general_purpose::STANDARD
172            .decode(base64)
173            .map_err(|error| {
174                SecurityError::InvalidArgument(format!("invalid PEM body: {error}"))
175            })?;
176        Self::from_der(&der)
177    }
178
179    /// Wraps the corresponding `SecCertificateRef` operation.
180    pub fn subject_summary(&self) -> Result<Option<String>> {
181        let raw =
182            unsafe { bridge::security_certificate_copy_subject_summary(self.handle.as_ptr()) };
183        bridge::optional_string(raw)
184    }
185
186    /// Wraps the corresponding `SecCertificateRef` operation.
187    pub fn common_name(&self) -> Result<Option<String>> {
188        let mut status = 0;
189        let mut error = std::ptr::null_mut();
190        let raw = unsafe {
191            bridge::security_certificate_copy_common_name(
192                self.handle.as_ptr(),
193                &mut status,
194                &mut error,
195            )
196        };
197        if raw.is_null() && status == 0 {
198            return Ok(None);
199        }
200        bridge::required_string("security_certificate_copy_common_name", raw, status, error)
201            .map(Some)
202    }
203
204    /// Wraps the corresponding `SecCertificateRef` operation.
205    pub fn email_addresses(&self) -> Result<Vec<String>> {
206        let mut status = 0;
207        let mut error = std::ptr::null_mut();
208        let raw = unsafe {
209            bridge::security_certificate_copy_email_addresses(
210                self.handle.as_ptr(),
211                &mut status,
212                &mut error,
213            )
214        };
215        bridge::required_json(
216            "security_certificate_copy_email_addresses",
217            raw,
218            status,
219            error,
220        )
221    }
222
223    /// Wraps the corresponding `SecCertificateRef` operation.
224    pub fn normalized_subject_sequence(&self) -> Result<Vec<u8>> {
225        let mut status = 0;
226        let mut error = std::ptr::null_mut();
227        let raw = unsafe {
228            bridge::security_certificate_copy_normalized_subject_sequence(
229                self.handle.as_ptr(),
230                &mut status,
231                &mut error,
232            )
233        };
234        bridge::required_data(
235            "security_certificate_copy_normalized_subject_sequence",
236            raw,
237            status,
238            error,
239        )
240    }
241
242    /// Wraps the corresponding `SecCertificateRef` operation.
243    pub fn normalized_issuer_sequence(&self) -> Result<Vec<u8>> {
244        let mut status = 0;
245        let mut error = std::ptr::null_mut();
246        let raw = unsafe {
247            bridge::security_certificate_copy_normalized_issuer_sequence(
248                self.handle.as_ptr(),
249                &mut status,
250                &mut error,
251            )
252        };
253        bridge::required_data(
254            "security_certificate_copy_normalized_issuer_sequence",
255            raw,
256            status,
257            error,
258        )
259    }
260
261    /// Wraps the corresponding `SecCertificateRef` operation.
262    pub fn serial_number(&self) -> Result<Vec<u8>> {
263        let mut status = 0;
264        let mut error = std::ptr::null_mut();
265        let raw = unsafe {
266            bridge::security_certificate_copy_serial_number(
267                self.handle.as_ptr(),
268                &mut status,
269                &mut error,
270            )
271        };
272        bridge::required_data(
273            "security_certificate_copy_serial_number",
274            raw,
275            status,
276            error,
277        )
278    }
279
280    /// Wraps the corresponding `SecCertificateRef` operation.
281    pub fn not_valid_before(&self) -> Result<Option<SystemTime>> {
282        let mut status = 0;
283        let mut error = std::ptr::null_mut();
284        let raw = unsafe {
285            bridge::security_certificate_copy_not_valid_before(
286                self.handle.as_ptr(),
287                &mut status,
288                &mut error,
289            )
290        };
291        if raw.is_null() && status == 0 {
292            return Ok(None);
293        }
294        let value: Value = bridge::required_json(
295            "security_certificate_copy_not_valid_before",
296            raw,
297            status,
298            error,
299        )?;
300        decode_date(value).map(Some)
301    }
302
303    /// Wraps the corresponding `SecCertificateRef` operation.
304    pub fn not_valid_after(&self) -> Result<Option<SystemTime>> {
305        let mut status = 0;
306        let mut error = std::ptr::null_mut();
307        let raw = unsafe {
308            bridge::security_certificate_copy_not_valid_after(
309                self.handle.as_ptr(),
310                &mut status,
311                &mut error,
312            )
313        };
314        if raw.is_null() && status == 0 {
315            return Ok(None);
316        }
317        let value: Value = bridge::required_json(
318            "security_certificate_copy_not_valid_after",
319            raw,
320            status,
321            error,
322        )?;
323        decode_date(value).map(Some)
324    }
325
326    /// Wraps the corresponding `SecCertificateRef` operation.
327    pub fn der_data(&self) -> Result<Vec<u8>> {
328        let mut status = 0;
329        let mut error = std::ptr::null_mut();
330        let raw = unsafe {
331            bridge::security_certificate_copy_der(self.handle.as_ptr(), &mut status, &mut error)
332        };
333        bridge::required_data("security_certificate_copy_der", raw, status, error)
334    }
335
336    /// Wraps the corresponding `SecCertificateRef` operation.
337    pub fn public_key(&self) -> Result<PublicKey> {
338        let mut status = 0;
339        let mut error = std::ptr::null_mut();
340        let raw = unsafe {
341            bridge::security_certificate_copy_public_key(
342                self.handle.as_ptr(),
343                &mut status,
344                &mut error,
345            )
346        };
347        bridge::required_handle("security_certificate_copy_public_key", raw, status, error)
348            .map(PublicKey::from_handle)
349    }
350
351    /// Wraps the corresponding `SecCertificateRef` operation.
352    pub fn add_to_keychain(&self) -> Result<()> {
353        let mut error = std::ptr::null_mut();
354        let status = unsafe {
355            bridge::security_certificate_add_to_keychain(self.handle.as_ptr(), &mut error)
356        };
357        bridge::status_result("security_certificate_add_to_keychain", status, error)
358    }
359
360    /// Wraps the corresponding `SecCertificateRef` operation.
361    pub fn values(&self, keys: &[&str]) -> Result<Value> {
362        let keys = (!keys.is_empty())
363            .then(|| bridge::json_cstring(&keys))
364            .transpose()?;
365        let mut status = 0;
366        let mut error = std::ptr::null_mut();
367        let raw = unsafe {
368            bridge::security_certificate_copy_values(
369                self.handle.as_ptr(),
370                keys.as_ref()
371                    .map_or(std::ptr::null(), |value| value.as_ptr()),
372                &mut status,
373                &mut error,
374            )
375        };
376        bridge::required_json("security_certificate_copy_values", raw, status, error)
377    }
378
379    /// Wraps the corresponding `SecCertificateRef` operation.
380    pub fn long_description(&self) -> Result<String> {
381        let mut status = 0;
382        let mut error = std::ptr::null_mut();
383        let raw = unsafe {
384            bridge::security_certificate_copy_long_description(
385                self.handle.as_ptr(),
386                &mut status,
387                &mut error,
388            )
389        };
390        bridge::required_string(
391            "security_certificate_copy_long_description",
392            raw,
393            status,
394            error,
395        )
396    }
397
398    /// Wraps the corresponding `SecCertificateRef` operation.
399    pub fn short_description(&self) -> Result<String> {
400        let mut status = 0;
401        let mut error = std::ptr::null_mut();
402        let raw = unsafe {
403            bridge::security_certificate_copy_short_description(
404                self.handle.as_ptr(),
405                &mut status,
406                &mut error,
407            )
408        };
409        bridge::required_string(
410            "security_certificate_copy_short_description",
411            raw,
412            status,
413            error,
414        )
415    }
416
417    /// Wraps the corresponding `SecCertificateRef` operation.
418    pub fn preferred(name: &str, key_usage: &[&str]) -> Result<Option<Self>> {
419        let name = bridge::cstring(name)?;
420        let key_usage = (!key_usage.is_empty())
421            .then(|| bridge::json_cstring(&key_usage))
422            .transpose()?;
423        let mut status = 0;
424        let mut error = std::ptr::null_mut();
425        let raw = unsafe {
426            bridge::security_certificate_copy_preferred(
427                name.as_ptr(),
428                key_usage
429                    .as_ref()
430                    .map_or(std::ptr::null(), |value| value.as_ptr()),
431                &mut status,
432                &mut error,
433            )
434        };
435        if raw.is_null() && status == 0 {
436            Ok(None)
437        } else {
438            bridge::required_handle("security_certificate_copy_preferred", raw, status, error)
439                .map(Self::from_handle)
440                .map(Some)
441        }
442    }
443
444    /// Wraps the corresponding `SecCertificateRef` operation.
445    pub fn set_preferred(certificate: Option<&Self>, name: &str, key_usage: &[&str]) -> Result<()> {
446        let name = bridge::cstring(name)?;
447        let key_usage = (!key_usage.is_empty())
448            .then(|| bridge::json_cstring(&key_usage))
449            .transpose()?;
450        let mut error = std::ptr::null_mut();
451        let status = unsafe {
452            bridge::security_certificate_set_preferred(
453                certificate.map_or(std::ptr::null_mut(), |value| value.handle.as_ptr()),
454                name.as_ptr(),
455                key_usage
456                    .as_ref()
457                    .map_or(std::ptr::null(), |value| value.as_ptr()),
458                &mut error,
459            )
460        };
461        bridge::status_result("security_certificate_set_preferred", status, error)
462    }
463}
464
465fn decode_date(value: Value) -> Result<SystemTime> {
466    let unix =
467        value
468            .get("unix")
469            .and_then(Value::as_f64)
470            .ok_or_else(|| SecurityError::UnexpectedType {
471                operation: "security_certificate_copy_not_valid_date",
472                expected: "date JSON object",
473            })?;
474    let duration = Duration::from_secs_f64(unix.abs());
475    if unix >= 0.0 {
476        Ok(UNIX_EPOCH + duration)
477    } else {
478        UNIX_EPOCH.checked_sub(duration).ok_or_else(|| {
479            SecurityError::InvalidArgument(
480                "certificate date preceded UNIX_EPOCH by too much".to_owned(),
481            )
482        })
483    }
484}