use nom7::Err;
use std;
use std::fmt;
use x509_parser::prelude::*;
use crate::x509::GeneralName;
mod time;
mod log;
#[repr(u32)]
pub enum X509DecodeError {
_Success = 0,
InvalidCert,
InvalidLength,
InvalidVersion,
InvalidSerial,
InvalidAlgorithmIdentifier,
InvalidX509Name,
InvalidDate,
InvalidExtensions,
InvalidDER,
}
pub struct X509(X509Certificate<'static>);
pub struct SCGeneralName<'a>(&'a GeneralName<'a>);
impl fmt::Display for SCGeneralName<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
GeneralName::DNSName(s) => write!(f, "{}", s),
GeneralName::URI(s) => write!(f, "{}", s),
GeneralName::IPAddress(s) => write!(f, "{:?}", s),
_ => write!(f, "{}", self.0)
}
}
}
#[no_mangle]
pub unsafe extern "C" fn SCX509Decode(
input: *const u8,
input_len: u32,
err_code: *mut u32,
) -> *mut X509 {
let slice = std::slice::from_raw_parts(input, input_len as usize);
let res = X509Certificate::from_der(slice);
match res {
Ok((_rem, cert)) => Box::into_raw(Box::new(X509(cert))),
Err(e) => {
let error = x509_parse_error_to_errcode(&e);
*err_code = error as u32;
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn SCX509GetSubject(ptr: *const X509, subject_name: *mut *mut u8, subject_len: *mut u32) {
if ptr.is_null() {
*subject_len = 0;
*subject_name = std::ptr::null_mut();
return;
}
let x509 = cast_pointer! {ptr, X509};
let subject = x509.0.tbs_certificate.subject().to_string().into_bytes();
*subject_len = subject.len() as u32;
*subject_name = Box::into_raw(subject.into_boxed_slice()) as *mut u8;
}
#[no_mangle]
pub unsafe extern "C" fn SCX509GetSubjectAltNameLen(ptr: *const X509) -> u16 {
if ptr.is_null() {
return 0;
}
let x509 = cast_pointer! {ptr, X509};
let san_list = x509.0.tbs_certificate.subject_alternative_name();
if let Ok(Some(sans)) = san_list {
debug_validate_bug_on!(sans.value.general_names.len() == usize::from(u16::MAX));
return sans.value.general_names.len() as u16;
}
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn SCX509GetSubjectAltNameAt(ptr: *const X509, idx: u16, san: *mut *mut u8, san_len: *mut u32) {
if ptr.is_null() {
*san_len = 0;
*san = std::ptr::null_mut();
return;
}
let x509 = cast_pointer! {ptr, X509};
let san_list = x509.0.tbs_certificate.subject_alternative_name();
if let Ok(Some(sans)) = san_list {
let general_name = &sans.value.general_names[idx as usize];
let dns_name = SCGeneralName(general_name);
let dn = dns_name.to_string().into_bytes();
*san_len = dn.len() as u32;
*san = Box::into_raw(dn.into_boxed_slice()) as *mut u8;
}
}
#[no_mangle]
pub unsafe extern "C" fn SCX509GetIssuer(ptr: *const X509, issuer_name: *mut *mut u8, issuer_len: *mut u32) {
if ptr.is_null() {
*issuer_len = 0;
*issuer_name = std::ptr::null_mut();
return;
}
let x509 = cast_pointer! {ptr, X509};
let issuer = x509.0.tbs_certificate.issuer.to_string().into_bytes();
*issuer_len = issuer.len() as u32;
*issuer_name = Box::into_raw(issuer.into_boxed_slice()) as *mut u8;
}
#[no_mangle]
pub unsafe extern "C" fn SCX509GetSerial(ptr: *const X509, serial_num: *mut *mut u8, serial_len: *mut u32) {
if ptr.is_null() {
*serial_len = 0;
*serial_num = std::ptr::null_mut();
return;
}
let x509 = cast_pointer! {ptr, X509};
let raw_serial = x509.0.tbs_certificate.raw_serial();
let v: Vec<_> = raw_serial.iter().map(|x| format!("{:02X}", x)).collect();
let serial = v.join(":");
*serial_len = serial.len() as u32;
*serial_num = Box::into_raw(serial.into_bytes().into_boxed_slice()) as *mut u8;
}
#[no_mangle]
pub unsafe extern "C" fn SCX509GetValidity(
ptr: *const X509,
not_before: *mut i64,
not_after: *mut i64,
) -> i32 {
if ptr.is_null() {
return -1;
}
let x509 = &*ptr;
let n_b = x509.0.validity().not_before.timestamp();
let n_a = x509.0.validity().not_after.timestamp();
*not_before = n_b;
*not_after = n_a;
0
}
#[no_mangle]
pub unsafe extern "C" fn SCX509Free(ptr: *mut X509) {
if ptr.is_null() {
return;
}
drop(Box::from_raw(ptr));
}
#[no_mangle]
pub unsafe extern "C" fn SCX509ArrayFree(ptr: *mut u8, len: u32) {
if ptr.is_null() {
return;
}
drop(Box::from_raw(std::ptr::slice_from_raw_parts_mut(ptr, len as usize)));
}
fn x509_parse_error_to_errcode(e: &Err<X509Error>) -> X509DecodeError {
match e {
Err::Incomplete(_) => X509DecodeError::InvalidLength,
Err::Error(e) | Err::Failure(e) => match e {
X509Error::InvalidVersion => X509DecodeError::InvalidVersion,
X509Error::InvalidSerial => X509DecodeError::InvalidSerial,
X509Error::InvalidAlgorithmIdentifier => X509DecodeError::InvalidAlgorithmIdentifier,
X509Error::InvalidX509Name => X509DecodeError::InvalidX509Name,
X509Error::InvalidDate => X509DecodeError::InvalidDate,
X509Error::InvalidExtensions => X509DecodeError::InvalidExtensions,
X509Error::Der(_) => X509DecodeError::InvalidDER,
_ => X509DecodeError::InvalidCert,
},
}
}