pe-sign 0.1.8

pe-sign is a cross-platform tool developed in Rust, designed for parsing and verifying digital signatures in PE files. It provides a simple command-line interface that supports extracting certificates, verifying digital signatures, calculating Authenticode digests, and printing certificate information.
Documentation
use std::fmt::Display;

use der::oid::{
    db::rfc5280::{ID_CE_BASIC_CONSTRAINTS, ID_CE_NAME_CONSTRAINTS, ID_CE_POLICY_CONSTRAINTS},
    AssociatedOid, ObjectIdentifier,
};

use crate::utils::{IndentString, OptionInto, VecInto};

use super::name::GeneralName;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BasicConstraints {
    pub ca: bool,
    pub path_len_constraint: Option<u8>,
}

impl AssociatedOid for BasicConstraints {
    const OID: ObjectIdentifier = ID_CE_BASIC_CONSTRAINTS;
}

impl From<x509_cert::ext::pkix::BasicConstraints> for BasicConstraints {
    fn from(value: x509_cert::ext::pkix::BasicConstraints) -> Self {
        Self {
            ca: value.ca,
            path_len_constraint: value.path_len_constraint,
        }
    }
}

impl Display for BasicConstraints {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        writeln!(f, "Basic Constraints:")?;
        match self.path_len_constraint {
            Some(len) => {
                write!(
                    f,
                    "{}",
                    format!("CA:{}, pathlen:{}", self.ca.to_string().to_uppercase(), len).indent(4)
                )
            }
            None => {
                write!(
                    f,
                    "{}",
                    format!("CA:{}", self.ca.to_string().to_uppercase()).indent(4)
                )
            }
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PolicyConstraints {
    pub require_explicit_policy: Option<u32>,
    pub inhibit_policy_mapping: Option<u32>,
}

impl AssociatedOid for PolicyConstraints {
    const OID: ObjectIdentifier = ID_CE_POLICY_CONSTRAINTS;
}

impl From<x509_cert::ext::pkix::PolicyConstraints> for PolicyConstraints {
    fn from(value: x509_cert::ext::pkix::PolicyConstraints) -> Self {
        Self {
            require_explicit_policy: value.require_explicit_policy,
            inhibit_policy_mapping: value.require_explicit_policy,
        }
    }
}

impl Display for PolicyConstraints {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Policy Constraints:")?;
        if self.require_explicit_policy.is_some() {
            write!(
                f,
                "\n{}",
                format!(
                    "Require Explicit Policy: {}",
                    self.require_explicit_policy.unwrap()
                )
                .indent(4)
            )?;
        }
        if self.inhibit_policy_mapping.is_some() {
            write!(
                f,
                "\n{}",
                format!(
                    "Inhibit Policy Mapping: {}",
                    self.inhibit_policy_mapping.unwrap()
                )
                .indent(4)
            )?;
        }

        Ok(())
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NameConstraints {
    pub permitted_subtrees: Option<GeneralSubtrees>,
    pub excluded_subtrees: Option<GeneralSubtrees>,
}

impl AssociatedOid for NameConstraints {
    const OID: ObjectIdentifier = ID_CE_NAME_CONSTRAINTS;
}

impl From<x509_cert::ext::pkix::NameConstraints> for NameConstraints {
    fn from(value: x509_cert::ext::pkix::NameConstraints) -> Self {
        Self {
            permitted_subtrees: value.permitted_subtrees.opt_into(),
            excluded_subtrees: value.excluded_subtrees.opt_into(),
        }
    }
}

impl Display for NameConstraints {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.permitted_subtrees {
            Some(permitted) => {
                writeln!(f, "Permitted:")?;
                write!(f, "{}", permitted.to_string().indent(4))?;
            }
            None => {}
        }

        match &self.excluded_subtrees {
            Some(excluded) => {
                if self.permitted_subtrees.is_some() {
                    writeln!(f)?;
                }
                writeln!(f, "Excluded:")?;
                write!(f, "{}", excluded.to_string().indent(4))?;
            }
            None => {}
        }

        Ok(())
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GeneralSubtrees(pub Vec<GeneralSubtree>);

impl From<x509_cert::ext::pkix::constraints::name::GeneralSubtrees> for GeneralSubtrees {
    fn from(value: x509_cert::ext::pkix::constraints::name::GeneralSubtrees) -> Self {
        Self(value.vec_into())
    }
}

impl Display for GeneralSubtrees {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            self.0
                .clone()
                .iter()
                .map(|v| v.to_string())
                .collect::<Vec<String>>()
                .join("\n")
                .indent(4)
        )
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GeneralSubtree {
    pub base: GeneralName,
    pub minimum: u32,
    pub maximum: Option<u32>,
}

impl From<x509_cert::ext::pkix::constraints::name::GeneralSubtree> for GeneralSubtree {
    fn from(value: x509_cert::ext::pkix::constraints::name::GeneralSubtree) -> Self {
        Self {
            base: value.base.into(),
            minimum: value.minimum,
            maximum: value.maximum,
        }
    }
}

impl Display for GeneralSubtree {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.base)
    }
}