#![deny(clippy::all)]
#![deny(clippy::pedantic)]
#![deny(missing_docs)]
#![deny(clippy::cargo)]
#![deny(clippy::arithmetic_side_effects)]
#![deny(clippy::as_conversions)]
#![deny(clippy::as_underscore)]
#![deny(clippy::integer_arithmetic)]
#![deny(clippy::undocumented_unsafe_blocks)]
use authenticode_parser_sys as sys;
#[derive(Copy, Clone, Debug)]
pub struct InitializationToken(());
impl InitializationToken {
#[must_use]
pub unsafe fn new() -> InitializationToken {
sys::ap_initialize_authenticode_parser();
InitializationToken(())
}
}
#[must_use]
pub fn parse(_token: &InitializationToken, data: &[u8]) -> Option<AuthenticodeArray> {
let len = u64::try_from(data.len()).unwrap_or(u64::MAX);
let res = unsafe { sys::ap_authenticode_new(data.as_ptr(), len) };
if res.is_null() {
None
} else {
Some(AuthenticodeArray(res))
}
}
#[must_use]
pub fn parse_pe(_token: &InitializationToken, data: &[u8]) -> Option<AuthenticodeArray> {
let len = u64::try_from(data.len()).unwrap_or(u64::MAX);
let res = unsafe { sys::ap_parse_authenticode(data.as_ptr(), len) };
if res.is_null() {
None
} else {
Some(AuthenticodeArray(res))
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct AuthenticodeArray(*mut sys::AuthenticodeArray);
impl Drop for AuthenticodeArray {
fn drop(&mut self) {
unsafe {
sys::ap_authenticode_array_free(self.0);
}
}
}
impl AuthenticodeArray {
#[must_use]
pub fn signatures(&self) -> &[Authenticode] {
let this = unsafe { &(*self.0) };
if this.signatures.is_null() {
&[]
} else {
let signatures = this.signatures.cast::<Authenticode>();
unsafe { std::slice::from_raw_parts(signatures, this.count) }
}
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct Authenticode<'a>(&'a sys::Authenticode);
impl Authenticode<'_> {
#[must_use]
pub fn verify_flags(&self) -> Option<AuthenticodeVerify> {
match self.0.verify_flags {
0 => Some(AuthenticodeVerify::Valid),
1 => Some(AuthenticodeVerify::CantParse),
2 => Some(AuthenticodeVerify::NoSignerCert),
3 => Some(AuthenticodeVerify::DigestMissing),
4 => Some(AuthenticodeVerify::InternalError),
5 => Some(AuthenticodeVerify::NoSignerInfo),
6 => Some(AuthenticodeVerify::WrongPkcs7Type),
7 => Some(AuthenticodeVerify::BadContent),
8 => Some(AuthenticodeVerify::Invalid),
9 => Some(AuthenticodeVerify::WrongFileDigest),
10 => Some(AuthenticodeVerify::UnknownAlgorithm),
_ => None,
}
}
#[must_use]
pub fn version(&self) -> i32 {
self.0.version
}
#[must_use]
pub fn digest_alg(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.digest_alg) }
}
#[must_use]
pub fn digest(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.digest)
}
#[must_use]
pub fn file_digest(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.file_digest)
}
#[must_use]
pub fn signer(&self) -> Option<Signer> {
if self.0.signer.is_null() {
None
} else {
Some(Signer(unsafe { &*self.0.signer }))
}
}
#[must_use]
pub fn certs(&self) -> &[Certificate] {
if self.0.certs.is_null() {
&[]
} else {
let this = unsafe { &(*self.0.certs) };
let certs = this.certs.cast::<Certificate>();
unsafe { std::slice::from_raw_parts(certs, this.count) }
}
}
#[must_use]
pub fn countersigs(&self) -> &[Countersignature] {
if self.0.countersigs.is_null() {
&[]
} else {
let this = unsafe { &(*self.0.countersigs) };
let counters = this.counters.cast::<Countersignature>();
unsafe { std::slice::from_raw_parts(counters, this.count) }
}
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct Signer<'a>(&'a sys::Signer);
impl Signer<'_> {
#[must_use]
pub fn digest(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.digest)
}
#[must_use]
pub fn digest_alg(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.digest_alg) }
}
#[must_use]
pub fn program_name(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.program_name) }
}
#[must_use]
pub fn certificate_chain(&self) -> &[Certificate] {
if self.0.chain.is_null() {
&[]
} else {
let this = unsafe { &(*self.0.chain) };
let certs = this.certs.cast::<Certificate>();
unsafe { std::slice::from_raw_parts(certs, this.count) }
}
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct Countersignature<'a>(&'a sys::Countersignature);
impl Countersignature<'_> {
#[must_use]
pub fn verify_flags(&self) -> Option<CounterSignatureVerify> {
match self.0.verify_flags {
0 => Some(CounterSignatureVerify::Valid),
1 => Some(CounterSignatureVerify::CantParse),
2 => Some(CounterSignatureVerify::NoSignerCert),
3 => Some(CounterSignatureVerify::UnknownAlgorithm),
4 => Some(CounterSignatureVerify::Invalid),
5 => Some(CounterSignatureVerify::CantDecryptDigest),
6 => Some(CounterSignatureVerify::DigestMissing),
7 => Some(CounterSignatureVerify::DoesntMatchSignature),
8 => Some(CounterSignatureVerify::InternalError),
9 => Some(CounterSignatureVerify::TimeMissing),
_ => None,
}
}
#[must_use]
pub fn sign_time(&self) -> i64 {
self.0.sign_time
}
#[must_use]
pub fn digest_alg(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.digest_alg) }
}
#[must_use]
pub fn digest(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.digest)
}
#[must_use]
pub fn certificate_chain(&self) -> &[Certificate] {
if self.0.chain.is_null() {
&[]
} else {
let this = unsafe { &(*self.0.chain) };
let certs = this.certs.cast::<Certificate>();
unsafe { std::slice::from_raw_parts(certs, this.count) }
}
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct Certificate<'a>(&'a sys::Certificate);
impl Certificate<'_> {
#[must_use]
pub fn version(&self) -> i64 {
#[allow(clippy::useless_conversion)]
i64::from(self.0.version)
}
#[must_use]
pub fn issuer(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.issuer) }
}
#[must_use]
pub fn subject(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.subject) }
}
#[must_use]
pub fn serial(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.serial) }
}
#[must_use]
pub fn sha1(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.sha1)
}
#[must_use]
pub fn sha256(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.sha256)
}
#[must_use]
pub fn key_alg(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.key_alg) }
}
#[must_use]
pub fn sig_alg(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.sig_alg) }
}
#[must_use]
pub fn sig_alg_oid(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.sig_alg_oid) }
}
#[must_use]
pub fn not_before(&self) -> i64 {
self.0.not_before
}
#[must_use]
pub fn not_after(&self) -> i64 {
self.0.not_after
}
#[must_use]
pub fn key(&self) -> Option<&[u8]> {
unsafe { cstr_ptr_to_slice(&self.0.key) }
}
#[must_use]
pub fn issuer_attrs(&self) -> Attributes {
Attributes(&self.0.issuer_attrs)
}
#[must_use]
pub fn subject_attrs(&self) -> Attributes {
Attributes(&self.0.subject_attrs)
}
}
pub struct Attributes<'a>(&'a sys::Attributes);
impl Attributes<'_> {
#[must_use]
pub fn country(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.country)
}
#[must_use]
pub fn organization(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.organization)
}
#[must_use]
pub fn organizational_unit(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.organizationalUnit)
}
#[must_use]
pub fn name_qualifier(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.nameQualifier)
}
#[must_use]
pub fn state(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.state)
}
#[must_use]
pub fn common_name(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.commonName)
}
#[must_use]
pub fn serial_number(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.serialNumber)
}
#[must_use]
pub fn locality(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.locality)
}
#[must_use]
pub fn title(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.title)
}
#[must_use]
pub fn surname(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.surname)
}
#[must_use]
pub fn given_name(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.givenName)
}
#[must_use]
pub fn initials(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.initials)
}
#[must_use]
pub fn pseudonym(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.pseudonym)
}
#[must_use]
pub fn generation_qualifier(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.generationQualifier)
}
#[must_use]
pub fn email_address(&self) -> Option<&[u8]> {
byte_array_to_slice(&self.0.emailAddress)
}
}
fn byte_array_to_slice(digest: &sys::ByteArray) -> Option<&[u8]> {
if digest.data.is_null() {
None
} else {
let len = if digest.len <= 0 {
0
} else {
match usize::try_from(digest.len) {
Ok(v) => v,
Err(_) => usize::MAX,
}
};
Some(unsafe { std::slice::from_raw_parts(digest.data, len) })
}
}
unsafe fn cstr_ptr_to_slice(ptr: &*mut i8) -> Option<&[u8]> {
if ptr.is_null() {
None
} else {
let cstr = unsafe { std::ffi::CStr::from_ptr(ptr.cast_const()) };
Some(cstr.to_bytes())
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum CounterSignatureVerify {
Valid,
CantParse,
NoSignerCert,
UnknownAlgorithm,
Invalid,
CantDecryptDigest,
DigestMissing,
DoesntMatchSignature,
InternalError,
TimeMissing,
}
#[derive(Debug, PartialEq, Eq)]
pub enum AuthenticodeVerify {
Valid,
CantParse,
NoSignerCert,
DigestMissing,
InternalError,
NoSignerInfo,
WrongPkcs7Type,
BadContent,
Invalid,
WrongFileDigest,
UnknownAlgorithm,
}