use alloc::boxed::Box;
use super::common::{PcStatus, guard, out_write, slice};
use crate::x509::Certificate;
pub struct PcCert(Certificate);
pub(super) fn pc_cert_inner(c: &PcCert) -> &Certificate {
&c.0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_cert_from_pem(pem: *const u8, len: usize) -> *mut PcCert {
crate::ffi::common::guard_ptr(|| {
let Some(bytes) = (unsafe { slice(pem, len) }) else {
return core::ptr::null_mut();
};
let Ok(s) = core::str::from_utf8(bytes) else {
return core::ptr::null_mut();
};
match Certificate::from_pem(s) {
Ok(c) => Box::into_raw(Box::new(PcCert(c))),
Err(_) => core::ptr::null_mut(),
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_cert_from_der(der: *const u8, len: usize) -> *mut PcCert {
crate::ffi::common::guard_ptr(|| {
let Some(bytes) = (unsafe { slice(der, len) }) else {
return core::ptr::null_mut();
};
match Certificate::from_der(bytes.to_vec()) {
Ok(c) => Box::into_raw(Box::new(PcCert(c))),
Err(_) => core::ptr::null_mut(),
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_cert_to_der(
cert: *const PcCert,
out: *mut u8,
out_len: *mut usize,
) -> PcStatus {
guard(|| {
if cert.is_null() {
return PcStatus::NullPointer;
}
let der = unsafe { &*cert }.0.to_der();
unsafe { out_write(der, out, out_len) }
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_cert_public_key_spki(
cert: *const PcCert,
out: *mut u8,
out_len: *mut usize,
) -> PcStatus {
guard(|| {
if cert.is_null() {
return PcStatus::NullPointer;
}
match unsafe { &*cert }.0.subject_public_key() {
Ok(k) => unsafe { out_write(&k.to_spki_der(), out, out_len) },
Err(_) => PcStatus::BadEncoding,
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_cert_verify(cert: *const PcCert, issuer: *const PcCert) -> PcStatus {
guard(|| {
if cert.is_null() || issuer.is_null() {
return PcStatus::NullPointer;
}
let issuer_key = match unsafe { &*issuer }.0.subject_public_key() {
Ok(k) => k,
Err(_) => return PcStatus::BadEncoding,
};
match unsafe { &*cert }.0.verify_signature_with(&issuer_key) {
Ok(()) => PcStatus::Ok,
Err(_) => PcStatus::Verification,
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_cert_free(cert: *mut PcCert) {
if !cert.is_null() {
drop(unsafe { Box::from_raw(cert) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_ec_self_signed_pem(
key: *const super::ec::PcEcKey,
cn: *const core::ffi::c_char,
days: u32,
out: *mut u8,
out_len: *mut usize,
) -> PcStatus {
use crate::x509::{CertSigner, DistinguishedName, Time, Validity};
guard(|| {
if key.is_null() || cn.is_null() {
return PcStatus::NullPointer;
}
let cs = unsafe { core::ffi::CStr::from_ptr(cn) };
let Ok(cn) = cs.to_str() else {
return PcStatus::BadEncoding;
};
let sk = super::ec::pc_ec_inner_key(unsafe { &*key });
let signer = CertSigner::Ecdsa(sk);
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(1_700_000_000);
let validity = Validity::new(
Time::from_unix(now),
Time::from_unix(now + (days as u64) * 86_400),
);
let subject = DistinguishedName::common_name(cn);
let cert =
match Certificate::self_signed_general(&signer, &subject, &validity, 1, false, &[cn]) {
Ok(c) => c,
Err(_) => return PcStatus::Internal,
};
let pem = crate::der::pem_encode("CERTIFICATE", cert.to_der());
unsafe { out_write(pem.as_bytes(), out, out_len) }
})
}