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::{ExternalFormat, ExternalItemType, SignatureAlgorithm};
9
10#[derive(Debug)]
11pub struct PublicKey {
12    handle: Handle,
13}
14
15impl PublicKey {
16    pub(crate) fn from_handle(handle: Handle) -> Self {
17        Self { handle }
18    }
19
20    pub fn attributes(&self) -> Result<Value> {
21        let mut status = 0;
22        let mut error = std::ptr::null_mut();
23        let raw = unsafe {
24            bridge::security_key_copy_attributes(self.handle.as_ptr(), &mut status, &mut error)
25        };
26        bridge::required_json("security_key_copy_attributes", raw, status, error)
27    }
28
29    pub fn verify_signature(
30        &self,
31        algorithm: SignatureAlgorithm,
32        signed_data: &[u8],
33        signature: &[u8],
34    ) -> Result<bool> {
35        let mut status = 0;
36        let mut error = std::ptr::null_mut();
37        let valid = unsafe {
38            bridge::security_public_key_verify_signature(
39                self.handle.as_ptr(),
40                algorithm as u32,
41                signed_data.as_ptr().cast(),
42                bridge::len_to_isize(signed_data.len())?,
43                signature.as_ptr().cast(),
44                bridge::len_to_isize(signature.len())?,
45                &mut status,
46                &mut error,
47            )
48        };
49        if status != 0 {
50            return Err(bridge::status_error(
51                "security_public_key_verify_signature",
52                status,
53                error,
54            )?);
55        }
56        Ok(valid)
57    }
58}
59
60#[derive(Debug)]
61pub struct Certificate {
62    handle: Handle,
63}
64
65impl Certificate {
66    pub(crate) fn from_handle(handle: Handle) -> Self {
67        Self { handle }
68    }
69
70    pub(crate) fn handle(&self) -> &Handle {
71        &self.handle
72    }
73
74    pub fn from_der(der: &[u8]) -> Result<Self> {
75        let mut status = 0;
76        let mut error = std::ptr::null_mut();
77        let raw = unsafe {
78            bridge::security_certificate_from_der(
79                der.as_ptr().cast(),
80                bridge::len_to_isize(der.len())?,
81                &mut status,
82                &mut error,
83            )
84        };
85        bridge::required_handle("security_certificate_from_der", raw, status, error)
86            .map(Self::from_handle)
87    }
88
89    pub fn import_item(
90        data: &[u8],
91        file_name_or_extension: Option<&str>,
92        format: ExternalFormat,
93        item_type: ExternalItemType,
94    ) -> Result<Self> {
95        let file_name_or_extension = file_name_or_extension.map(bridge::cstring).transpose()?;
96        let mut status = 0;
97        let mut error = std::ptr::null_mut();
98        let raw = unsafe {
99            bridge::security_certificate_import_item(
100                data.as_ptr().cast(),
101                bridge::len_to_isize(data.len())?,
102                file_name_or_extension
103                    .as_ref()
104                    .map_or(std::ptr::null(), |value| value.as_ptr()),
105                format as u32,
106                item_type as u32,
107                &mut status,
108                &mut error,
109            )
110        };
111        bridge::required_handle("security_certificate_import_item", raw, status, error)
112            .map(Self::from_handle)
113    }
114
115    pub fn export_item(&self, format: ExternalFormat, pem_armour: bool) -> Result<Vec<u8>> {
116        let mut status = 0;
117        let mut error = std::ptr::null_mut();
118        let raw = unsafe {
119            bridge::security_certificate_export_item(
120                self.handle.as_ptr(),
121                format as u32,
122                pem_armour,
123                &mut status,
124                &mut error,
125            )
126        };
127        bridge::required_data("security_certificate_export_item", raw, status, error)
128    }
129
130    pub fn from_pem(pem: &[u8]) -> Result<Self> {
131        let pem = std::str::from_utf8(pem).map_err(|error| {
132            SecurityError::InvalidArgument(format!("PEM input was not valid UTF-8: {error}"))
133        })?;
134        let base64 = pem
135            .lines()
136            .filter(|line| !line.starts_with("-----"))
137            .collect::<String>();
138        let der = base64::engine::general_purpose::STANDARD
139            .decode(base64)
140            .map_err(|error| {
141                SecurityError::InvalidArgument(format!("invalid PEM body: {error}"))
142            })?;
143        Self::from_der(&der)
144    }
145
146    pub fn subject_summary(&self) -> Result<Option<String>> {
147        let raw =
148            unsafe { bridge::security_certificate_copy_subject_summary(self.handle.as_ptr()) };
149        bridge::optional_string(raw)
150    }
151
152    pub fn common_name(&self) -> Result<Option<String>> {
153        let mut status = 0;
154        let mut error = std::ptr::null_mut();
155        let raw = unsafe {
156            bridge::security_certificate_copy_common_name(
157                self.handle.as_ptr(),
158                &mut status,
159                &mut error,
160            )
161        };
162        if raw.is_null() && status == 0 {
163            return Ok(None);
164        }
165        bridge::required_string("security_certificate_copy_common_name", raw, status, error)
166            .map(Some)
167    }
168
169    pub fn email_addresses(&self) -> Result<Vec<String>> {
170        let mut status = 0;
171        let mut error = std::ptr::null_mut();
172        let raw = unsafe {
173            bridge::security_certificate_copy_email_addresses(
174                self.handle.as_ptr(),
175                &mut status,
176                &mut error,
177            )
178        };
179        bridge::required_json(
180            "security_certificate_copy_email_addresses",
181            raw,
182            status,
183            error,
184        )
185    }
186
187    pub fn normalized_subject_sequence(&self) -> Result<Vec<u8>> {
188        let mut status = 0;
189        let mut error = std::ptr::null_mut();
190        let raw = unsafe {
191            bridge::security_certificate_copy_normalized_subject_sequence(
192                self.handle.as_ptr(),
193                &mut status,
194                &mut error,
195            )
196        };
197        bridge::required_data(
198            "security_certificate_copy_normalized_subject_sequence",
199            raw,
200            status,
201            error,
202        )
203    }
204
205    pub fn normalized_issuer_sequence(&self) -> Result<Vec<u8>> {
206        let mut status = 0;
207        let mut error = std::ptr::null_mut();
208        let raw = unsafe {
209            bridge::security_certificate_copy_normalized_issuer_sequence(
210                self.handle.as_ptr(),
211                &mut status,
212                &mut error,
213            )
214        };
215        bridge::required_data(
216            "security_certificate_copy_normalized_issuer_sequence",
217            raw,
218            status,
219            error,
220        )
221    }
222
223    pub fn serial_number(&self) -> Result<Vec<u8>> {
224        let mut status = 0;
225        let mut error = std::ptr::null_mut();
226        let raw = unsafe {
227            bridge::security_certificate_copy_serial_number(
228                self.handle.as_ptr(),
229                &mut status,
230                &mut error,
231            )
232        };
233        bridge::required_data(
234            "security_certificate_copy_serial_number",
235            raw,
236            status,
237            error,
238        )
239    }
240
241    pub fn not_valid_before(&self) -> Result<Option<SystemTime>> {
242        let mut status = 0;
243        let mut error = std::ptr::null_mut();
244        let raw = unsafe {
245            bridge::security_certificate_copy_not_valid_before(
246                self.handle.as_ptr(),
247                &mut status,
248                &mut error,
249            )
250        };
251        if raw.is_null() && status == 0 {
252            return Ok(None);
253        }
254        let value: Value = bridge::required_json(
255            "security_certificate_copy_not_valid_before",
256            raw,
257            status,
258            error,
259        )?;
260        decode_date(value).map(Some)
261    }
262
263    pub fn not_valid_after(&self) -> Result<Option<SystemTime>> {
264        let mut status = 0;
265        let mut error = std::ptr::null_mut();
266        let raw = unsafe {
267            bridge::security_certificate_copy_not_valid_after(
268                self.handle.as_ptr(),
269                &mut status,
270                &mut error,
271            )
272        };
273        if raw.is_null() && status == 0 {
274            return Ok(None);
275        }
276        let value: Value = bridge::required_json(
277            "security_certificate_copy_not_valid_after",
278            raw,
279            status,
280            error,
281        )?;
282        decode_date(value).map(Some)
283    }
284
285    pub fn der_data(&self) -> Result<Vec<u8>> {
286        let mut status = 0;
287        let mut error = std::ptr::null_mut();
288        let raw = unsafe {
289            bridge::security_certificate_copy_der(self.handle.as_ptr(), &mut status, &mut error)
290        };
291        bridge::required_data("security_certificate_copy_der", raw, status, error)
292    }
293
294    pub fn public_key(&self) -> Result<PublicKey> {
295        let mut status = 0;
296        let mut error = std::ptr::null_mut();
297        let raw = unsafe {
298            bridge::security_certificate_copy_public_key(
299                self.handle.as_ptr(),
300                &mut status,
301                &mut error,
302            )
303        };
304        bridge::required_handle("security_certificate_copy_public_key", raw, status, error)
305            .map(PublicKey::from_handle)
306    }
307}
308
309fn decode_date(value: Value) -> Result<SystemTime> {
310    let unix =
311        value
312            .get("unix")
313            .and_then(Value::as_f64)
314            .ok_or_else(|| SecurityError::UnexpectedType {
315                operation: "security_certificate_copy_not_valid_date",
316                expected: "date JSON object",
317            })?;
318    let duration = Duration::from_secs_f64(unix.abs());
319    if unix >= 0.0 {
320        Ok(UNIX_EPOCH + duration)
321    } else {
322        UNIX_EPOCH.checked_sub(duration).ok_or_else(|| {
323            SecurityError::InvalidArgument(
324                "certificate date preceded UNIX_EPOCH by too much".to_owned(),
325            )
326        })
327    }
328}