use crate::error::{Result, SecurityError};
use crate::ffi;
use crate::private::{cf_data, cf_data_to_vec, cf_string_to_string, checked_cf, OwnedCf};
pub struct PublicKey {
raw: ffi::SecKeyRef,
}
impl PublicKey {
#[must_use]
pub const fn as_raw(&self) -> ffi::SecKeyRef {
self.raw
}
}
impl Drop for PublicKey {
fn drop(&mut self) {
if !self.raw.is_null() {
unsafe { ffi::CFRelease(self.raw.cast()) };
}
}
}
impl core::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PublicKey").field("raw", &self.raw).finish()
}
}
pub struct Certificate {
raw: ffi::SecCertificateRef,
}
impl Certificate {
pub fn from_der(der: &[u8]) -> Result<Self> {
let der = cf_data(der)?;
let raw =
unsafe { ffi::SecCertificateCreateWithData(ffi::kCFAllocatorDefault, der.as_data()) };
if raw.is_null() {
return Err(SecurityError::InvalidArgument(
"invalid DER-encoded X.509 certificate".to_owned(),
));
}
Ok(Self { raw })
}
#[must_use]
pub const fn as_raw(&self) -> ffi::SecCertificateRef {
self.raw
}
#[must_use]
pub fn subject_summary(&self) -> Option<String> {
let raw = unsafe { ffi::SecCertificateCopySubjectSummary(self.raw) };
if raw.is_null() {
return None;
}
let owned = OwnedCf::new(raw.cast());
cf_string_to_string(owned.as_string())
}
pub fn der_data(&self) -> Result<Vec<u8>> {
let raw = unsafe { ffi::SecCertificateCopyData(self.raw) };
let data = checked_cf(raw.cast(), "SecCertificateCopyData")?;
Ok(cf_data_to_vec(data.as_data()))
}
pub fn public_key(&self) -> Result<PublicKey> {
let raw = unsafe { ffi::SecCertificateCopyKey(self.raw) };
if raw.is_null() {
return Err(SecurityError::CoreFoundation(apple_cf::CFError::new(
"SecCertificateCopyKey",
)));
}
Ok(PublicKey { raw })
}
}
impl Drop for Certificate {
fn drop(&mut self) {
if !self.raw.is_null() {
unsafe { ffi::CFRelease(self.raw.cast()) };
}
}
}
impl core::fmt::Debug for Certificate {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Certificate")
.field("subject_summary", &self.subject_summary())
.finish()
}
}