signalscreen-checker 0.2.1

Windows code-signing hygiene checker. Reads the Authenticode signature in a PE file and grades it A-F. Pure Rust, no Windows dependency.
Documentation
//! PE entry point: parse the file and extract the signer's signature facts.
use crate::signature::{self, SignatureInfo};
use anyhow::Result;
use authenticode::{AttributeCertificateIterator, PeTrait};
use object::read::pe::{PeFile32, PeFile64};

/// Parse PE bytes and return the signer's `SignatureInfo`, or `None` if the file
/// carries no embedded Authenticode signature. Errors only if the bytes are not a PE.
pub fn extract(data: &[u8]) -> Result<Option<SignatureInfo>> {
    // `AttributeCertificateIterator` takes `&dyn PeTrait`, so width only matters here.
    let pe: Box<dyn PeTrait + '_> = match PeFile64::parse(data) {
        Ok(pe) => Box::new(pe),
        Err(e) => match PeFile32::parse(data) {
            Ok(pe) => Box::new(pe),
            Err(_) => return Err(anyhow::anyhow!("not a PE: {e}")),
        },
    };
    let Some(mut iter) = AttributeCertificateIterator::new(pe.as_ref())
        .map_err(|e| anyhow::anyhow!("cert table: {e:?}"))?
    else {
        return Ok(None);
    };
    // The signer's signature is the first attribute certificate (if any).
    match iter.next() {
        Some(cert) => {
            let cert = cert.map_err(|e| anyhow::anyhow!("attribute certificate: {e:?}"))?;
            let sig = cert
                .get_authenticode_signature()
                .map_err(|e| anyhow::anyhow!("authenticode signature: {e:?}"))?;
            Ok(Some(signature::from_authenticode(&sig)))
        }
        None => Ok(None),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn unsigned_has_no_signature() {
        let data = std::fs::read("fixtures/unsigned.exe").unwrap();
        assert!(extract(&data).unwrap().is_none());
    }

    #[test]
    fn pe32_is_parsed_not_rejected() {
        // PE32 must parse, not error out as "not a PE".
        let data = std::fs::read("fixtures/unsigned-pe32.exe").unwrap();
        assert!(extract(&data).unwrap().is_none());
    }

    #[test]
    fn garbage_is_still_rejected() {
        // The fallback must not swallow genuine non-PE input.
        assert!(extract(b"not an executable at all").is_err());
    }

    #[test]
    fn signed_fixture_parses() {
        let data = std::fs::read("fixtures/selfsigned-sha256.exe").unwrap();
        let info = extract(&data).unwrap().expect("should be signed");
        assert_eq!(info.digest_algo_oid, "2.16.840.1.101.3.4.2.1"); // SHA-256
        assert!(!info.has_timestamp); // signed without a timestamp
        assert!(info.leaf_cert.is_some());
    }
}