use alloc::boxed::Box;
use alloc::vec::Vec;
use super::common::{PcStatus, guard, out_write, slice};
use super::rsa::PcRsaKey;
use crate::x509::{CertSigner, CertificationRequest, DistinguishedName};
pub struct PcCsr(CertificationRequest);
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_csr_create_rsa(
rsa_key: *const PcRsaKey,
subject_cn: *const core::ffi::c_char,
dns_names: *const *const core::ffi::c_char,
dns_count: usize,
) -> *mut PcCsr {
crate::ffi::common::guard_ptr(|| {
if rsa_key.is_null() || subject_cn.is_null() {
return core::ptr::null_mut();
}
let cn = unsafe { core::ffi::CStr::from_ptr(subject_cn) };
let Ok(cn) = cn.to_str() else {
return core::ptr::null_mut();
};
let mut dns: Vec<&str> = Vec::with_capacity(dns_count);
if dns_count > 0 {
if dns_names.is_null() {
return core::ptr::null_mut();
}
for i in 0..dns_count {
let p = unsafe { *dns_names.add(i) };
if p.is_null() {
return core::ptr::null_mut();
}
let s = unsafe { core::ffi::CStr::from_ptr(p) };
let Ok(s) = s.to_str() else {
return core::ptr::null_mut();
};
dns.push(s);
}
}
let subject = DistinguishedName::common_name(cn);
let key_ref = unsafe { rsa_key_inner(&*rsa_key) };
let signer = CertSigner::Rsa(key_ref);
match CertificationRequest::create(&signer, &subject, &dns) {
Ok(csr) => Box::into_raw(Box::new(PcCsr(csr))),
Err(_) => core::ptr::null_mut(),
}
})
}
fn rsa_key_inner(k: &PcRsaKey) -> &crate::rsa::BoxedRsaPrivateKey {
k.key()
}
trait PcRsaKeyAccess {
fn key(&self) -> &crate::rsa::BoxedRsaPrivateKey;
}
impl PcRsaKeyAccess for PcRsaKey {
fn key(&self) -> &crate::rsa::BoxedRsaPrivateKey {
super::rsa::pc_rsa_inner_key(self)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_csr_from_pem(pem: *const u8, len: usize) -> *mut PcCsr {
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 CertificationRequest::from_pem(s) {
Ok(csr) => Box::into_raw(Box::new(PcCsr(csr))),
Err(_) => core::ptr::null_mut(),
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_csr_to_pem(
csr: *const PcCsr,
out: *mut u8,
out_len: *mut usize,
) -> PcStatus {
guard(|| {
if csr.is_null() {
return PcStatus::NullPointer;
}
let pem = unsafe { &*csr }.0.to_pem();
unsafe { out_write(pem.as_bytes(), out, out_len) }
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_csr_verify_self_signed(csr: *const PcCsr) -> PcStatus {
guard(|| {
if csr.is_null() {
return PcStatus::NullPointer;
}
match unsafe { &*csr }.0.verify_self_signed() {
Ok(()) => PcStatus::Ok,
Err(_) => PcStatus::Verification,
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_csr_subject_cn(
csr: *const PcCsr,
out: *mut u8,
out_len: *mut usize,
) -> PcStatus {
guard(|| {
if csr.is_null() {
return PcStatus::NullPointer;
}
let subject = match unsafe { &*csr }.0.subject() {
Ok(s) => s,
Err(_) => return PcStatus::BadEncoding,
};
let Some(cn) = subject.common_name else {
return PcStatus::BadEncoding;
};
unsafe { out_write(cn.as_bytes(), out, out_len) }
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pc_csr_free(csr: *mut PcCsr) {
if !csr.is_null() {
drop(unsafe { Box::from_raw(csr) });
}
}