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};
8
9#[derive(Debug)]
10pub struct PublicKey {
11    handle: Handle,
12}
13
14impl PublicKey {
15    pub(crate) fn from_handle(handle: Handle) -> Self {
16        Self { handle }
17    }
18
19    pub fn attributes(&self) -> Result<Value> {
20        let mut status = 0;
21        let mut error = std::ptr::null_mut();
22        let raw = unsafe {
23            bridge::security_key_copy_attributes(self.handle.as_ptr(), &mut status, &mut error)
24        };
25        bridge::required_json("security_key_copy_attributes", raw, status, error)
26    }
27}
28
29#[derive(Debug)]
30pub struct Certificate {
31    handle: Handle,
32}
33
34impl Certificate {
35    pub(crate) fn from_handle(handle: Handle) -> Self {
36        Self { handle }
37    }
38
39    pub(crate) fn handle(&self) -> &Handle {
40        &self.handle
41    }
42
43    pub fn from_der(der: &[u8]) -> Result<Self> {
44        let mut status = 0;
45        let mut error = std::ptr::null_mut();
46        let raw = unsafe {
47            bridge::security_certificate_from_der(
48                der.as_ptr().cast(),
49                bridge::len_to_isize(der.len())?,
50                &mut status,
51                &mut error,
52            )
53        };
54        bridge::required_handle("security_certificate_from_der", raw, status, error)
55            .map(Self::from_handle)
56    }
57
58    pub fn from_pem(pem: &[u8]) -> Result<Self> {
59        let pem = std::str::from_utf8(pem).map_err(|error| {
60            SecurityError::InvalidArgument(format!("PEM input was not valid UTF-8: {error}"))
61        })?;
62        let base64 = pem
63            .lines()
64            .filter(|line| !line.starts_with("-----"))
65            .collect::<String>();
66        let der = base64::engine::general_purpose::STANDARD
67            .decode(base64)
68            .map_err(|error| SecurityError::InvalidArgument(format!("invalid PEM body: {error}")))?;
69        Self::from_der(&der)
70    }
71
72    pub fn subject_summary(&self) -> Result<Option<String>> {
73        let raw = unsafe { bridge::security_certificate_copy_subject_summary(self.handle.as_ptr()) };
74        bridge::optional_string(raw)
75    }
76
77    pub fn common_name(&self) -> Result<Option<String>> {
78        let mut status = 0;
79        let mut error = std::ptr::null_mut();
80        let raw = unsafe {
81            bridge::security_certificate_copy_common_name(self.handle.as_ptr(), &mut status, &mut error)
82        };
83        if raw.is_null() && status == 0 {
84            return Ok(None);
85        }
86        bridge::required_string("security_certificate_copy_common_name", raw, status, error)
87            .map(Some)
88    }
89
90    pub fn email_addresses(&self) -> Result<Vec<String>> {
91        let mut status = 0;
92        let mut error = std::ptr::null_mut();
93        let raw = unsafe {
94            bridge::security_certificate_copy_email_addresses(
95                self.handle.as_ptr(),
96                &mut status,
97                &mut error,
98            )
99        };
100        bridge::required_json("security_certificate_copy_email_addresses", raw, status, error)
101    }
102
103    pub fn normalized_subject_sequence(&self) -> Result<Vec<u8>> {
104        let mut status = 0;
105        let mut error = std::ptr::null_mut();
106        let raw = unsafe {
107            bridge::security_certificate_copy_normalized_subject_sequence(
108                self.handle.as_ptr(),
109                &mut status,
110                &mut error,
111            )
112        };
113        bridge::required_data(
114            "security_certificate_copy_normalized_subject_sequence",
115            raw,
116            status,
117            error,
118        )
119    }
120
121    pub fn normalized_issuer_sequence(&self) -> Result<Vec<u8>> {
122        let mut status = 0;
123        let mut error = std::ptr::null_mut();
124        let raw = unsafe {
125            bridge::security_certificate_copy_normalized_issuer_sequence(
126                self.handle.as_ptr(),
127                &mut status,
128                &mut error,
129            )
130        };
131        bridge::required_data(
132            "security_certificate_copy_normalized_issuer_sequence",
133            raw,
134            status,
135            error,
136        )
137    }
138
139    pub fn serial_number(&self) -> Result<Vec<u8>> {
140        let mut status = 0;
141        let mut error = std::ptr::null_mut();
142        let raw = unsafe {
143            bridge::security_certificate_copy_serial_number(
144                self.handle.as_ptr(),
145                &mut status,
146                &mut error,
147            )
148        };
149        bridge::required_data("security_certificate_copy_serial_number", raw, status, error)
150    }
151
152    pub fn not_valid_before(&self) -> Result<Option<SystemTime>> {
153        let mut status = 0;
154        let mut error = std::ptr::null_mut();
155        let raw = unsafe {
156            bridge::security_certificate_copy_not_valid_before(
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        let value: Value = bridge::required_json(
166            "security_certificate_copy_not_valid_before",
167            raw,
168            status,
169            error,
170        )?;
171        decode_date(value).map(Some)
172    }
173
174    pub fn not_valid_after(&self) -> Result<Option<SystemTime>> {
175        let mut status = 0;
176        let mut error = std::ptr::null_mut();
177        let raw = unsafe {
178            bridge::security_certificate_copy_not_valid_after(
179                self.handle.as_ptr(),
180                &mut status,
181                &mut error,
182            )
183        };
184        if raw.is_null() && status == 0 {
185            return Ok(None);
186        }
187        let value: Value = bridge::required_json(
188            "security_certificate_copy_not_valid_after",
189            raw,
190            status,
191            error,
192        )?;
193        decode_date(value).map(Some)
194    }
195
196    pub fn der_data(&self) -> Result<Vec<u8>> {
197        let mut status = 0;
198        let mut error = std::ptr::null_mut();
199        let raw = unsafe {
200            bridge::security_certificate_copy_der(self.handle.as_ptr(), &mut status, &mut error)
201        };
202        bridge::required_data("security_certificate_copy_der", raw, status, error)
203    }
204
205    pub fn public_key(&self) -> Result<PublicKey> {
206        let mut status = 0;
207        let mut error = std::ptr::null_mut();
208        let raw = unsafe {
209            bridge::security_certificate_copy_public_key(self.handle.as_ptr(), &mut status, &mut error)
210        };
211        bridge::required_handle("security_certificate_copy_public_key", raw, status, error)
212            .map(PublicKey::from_handle)
213    }
214}
215
216fn decode_date(value: Value) -> Result<SystemTime> {
217    let unix = value
218        .get("unix")
219        .and_then(Value::as_f64)
220        .ok_or_else(|| SecurityError::UnexpectedType {
221            operation: "security_certificate_copy_not_valid_date",
222            expected: "date JSON object",
223        })?;
224    let duration = Duration::from_secs_f64(unix.abs());
225    if unix >= 0.0 {
226        Ok(UNIX_EPOCH + duration)
227    } else {
228        UNIX_EPOCH.checked_sub(duration).ok_or_else(|| {
229            SecurityError::InvalidArgument("certificate date preceded UNIX_EPOCH by too much".to_owned())
230        })
231    }
232}