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