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}