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 {
13 handle: Handle,
14}
15
16impl PublicKey {
17 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 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 pub fn block_size(&self) -> usize {
38 key::key_block_size(&self.handle)
39 }
40
41 pub fn external_representation(&self) -> Result<Vec<u8>> {
43 key::key_external_representation(&self.handle)
44 }
45
46 pub fn encrypt(&self, algorithm: EncryptionAlgorithm, plaintext: &[u8]) -> Result<Vec<u8>> {
48 key::encrypt_with_public_key(&self.handle, algorithm, plaintext)
49 }
50
51 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)]
84pub 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 pub fn type_id() -> usize {
100 unsafe { bridge::security_certificate_get_type_id() }
101 }
102
103 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}