LCOV - code coverage report
Current view: top level - src/pe - signature.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 38.2 % 136 52
Test Date: 2024-10-27:00:00:00 Functions: 34.2 % 38 13

            Line data    Source code
       1              : //! This module wraps the PKCS #7 PE authenticode signature
       2              : 
       3              : use bitflags::bitflags;
       4              : use lief_ffi as ffi;
       5              : 
       6              : pub mod attributes;
       7              : pub mod content_info;
       8              : pub mod rsa_info;
       9              : pub mod signer_info;
      10              : pub mod x509;
      11              : 
      12              : #[doc(inline)]
      13              : pub use content_info::ContentInfo;
      14              : #[doc(inline)]
      15              : pub use rsa_info::RsaInfo;
      16              : #[doc(inline)]
      17              : pub use signer_info::{SignerInfo, Signers};
      18              : #[doc(inline)]
      19              : pub use x509::{Certificates, X509};
      20              : 
      21              : use std::io::{Read, Seek};
      22              : 
      23              : use crate::pe::Algorithms;
      24              : use crate::common::into_optional;
      25              : use crate::common::FromFFI;
      26              : use crate::declare_iterator;
      27              : use crate::to_slice;
      28              : 
      29              : use std::marker::PhantomData;
      30              : 
      31            0 : bitflags! {
      32            2 :     #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
      33            0 :     pub struct VerificationFlags: u32 {
      34            0 :         const OK = 0;
      35            0 :         const INVALID_SIGNER = 1 << 0;
      36            0 :         const UNSUPPORTED_ALGORITHM = 1 << 1;
      37            0 :         const INCONSISTENT_DIGEST_ALGORITHM = 1 << 2;
      38            0 :         const CERT_NOT_FOUND = 1 << 3;
      39            0 :         const CORRUPTED_CONTENT_INFO = 1 << 4;
      40            0 :         const CORRUPTED_AUTH_DATA = 1 << 5;
      41            0 :         const MISSING_PKCS9_MESSAGE_DIGEST = 1 << 6;
      42            0 :         const BAD_DIGEST = 1 << 7;
      43            0 :         const BAD_SIGNATURE = 1 << 8;
      44            0 :         const NO_SIGNATURE = 1 << 9;
      45            0 :         const CERT_EXPIRED = 1 << 10;
      46            0 :         const CERT_FUTURE = 1 << 11;
      47            0 :     }
      48            0 : }
      49              : 
      50              : impl std::fmt::Display for VerificationFlags {
      51            0 :     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
      52            0 :         bitflags::parser::to_writer(self, f)
      53            0 :     }
      54              : }
      55              : 
      56              : impl From<u32> for VerificationFlags {
      57           16 :     fn from(value: u32) -> Self {
      58           16 :         VerificationFlags::from_bits_truncate(value)
      59           16 :     }
      60              : }
      61              : 
      62              : impl From<VerificationFlags> for u32 {
      63            0 :     fn from(value: VerificationFlags) -> Self {
      64            0 :         value.bits()
      65            0 :     }
      66              : }
      67              : 
      68              : impl VerificationFlags {
      69            0 :     pub fn is_ok(self) -> bool {
      70            0 :         self == VerificationFlags::OK
      71            0 :     }
      72              : }
      73              : 
      74            0 : bitflags! {
      75            0 :     #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
      76            0 :     /// Flags to tweak the verification process of the signature
      77            0 :     ///
      78            0 :     /// See [`Signature::check`] and [`crate::pe::Binary::verify_signature`]
      79            0 :     pub struct VerificationChecks: u32 {
      80            0 :         /// Default behavior that tries to follow the Microsoft verification process as close as
      81            0 :         /// possible
      82            0 :         const DEFAULT = 1 << 0;
      83            0 : 
      84            0 :         /// Only check that [`crate::pe::Binary::authentihash`] matches
      85            0 :         /// [`ContentInfo::digest`] regardless of the signature's validity
      86            0 :         const HASH_ONLY = 1 << 1;
      87            0 : 
      88            0 :         /// Same semantic as
      89            0 :         /// [WTD_LIFETIME_SIGNING_FLAG](https://docs.microsoft.com/en-us/windows/win32/api/wintrust/ns-wintrust-wintrust_data#WTD_LIFETIME_SIGNING_FLAG)
      90            0 :         const LIFETIME_SIGNING = 1 << 2;
      91            0 : 
      92            0 :         /// Skip the verification of the certificates time validities so that even though a
      93            0 :         /// certificate expired, it returns [`VerificationFlags::OK`]
      94            0 :         const SKIP_CERT_TIME = 1 << 3;
      95            0 :     }
      96            0 : }
      97              : 
      98              : impl From<u32> for VerificationChecks {
      99            0 :     fn from(value: u32) -> Self {
     100            0 :         VerificationChecks::from_bits_truncate(value)
     101            0 :     }
     102              : }
     103              : 
     104              : impl From<VerificationChecks> for u32 {
     105           16 :     fn from(value: VerificationChecks) -> Self {
     106           16 :         value.bits()
     107           16 :     }
     108              : }
     109              : 
     110              : 
     111              : pub struct Signature<'a> {
     112              :     ptr: cxx::UniquePtr<ffi::PE_Signature>,
     113              :     _owner: PhantomData<&'a ()>,
     114              : }
     115              : 
     116              : impl<'b, 'a: 'b> From<&'a Signature<'_>> for &'b ffi::PE_Signature {
     117            8 :     fn from(value: &'a Signature<'_>) -> &'b ffi::PE_Signature {
     118            8 :         value.ptr.as_ref().unwrap()
     119            8 :     }
     120              : }
     121              : 
     122              : impl std::fmt::Debug for Signature<'_> {
     123          104 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     124          104 :         f.debug_struct("Signature").finish()
     125          104 :     }
     126              : }
     127              : 
     128              : impl FromFFI<ffi::PE_Signature> for Signature<'_> {
     129          120 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Signature>) -> Self {
     130          120 :         Signature {
     131          120 :             ptr,
     132          120 :             _owner: PhantomData,
     133          120 :         }
     134          120 :     }
     135              : }
     136              : 
     137              : impl<'a> Signature<'a> {
     138              :     /// Create a Signature from a PKCS#7 file path
     139           40 :     pub fn from_file(path: &str) -> Option<Self> {
     140           40 :         let ffi = ffi::PE_Signature::parse(path);
     141           40 :         if ffi.is_null() {
     142            0 :             return None;
     143           40 :         }
     144           40 :         Some(Signature::from_ffi(ffi))
     145           40 :     }
     146              : 
     147              :     /// Create a Signature from a PKCS#7 *reader* implementing the `Read + Seek` traits
     148            1 :     pub fn from<R: Read + Seek>(reader: &mut R) -> Option<Self> {
     149            1 :         let mut buffer = std::vec::Vec::new();
     150            1 :         if reader.read_to_end(&mut buffer).is_err() {
     151            0 :             return None;
     152            1 :         }
     153            1 :         let ffi_stream =
     154            1 :             unsafe { ffi::PE_Signature::from_raw(buffer.as_mut_ptr(), buffer.len()) };
     155            1 :         Some(Signature::from_ffi(ffi_stream))
     156            1 :     }
     157              : 
     158              :     /// Should be 1
     159            0 :     pub fn version(&self) -> u32 {
     160            0 :         self.ptr.version()
     161            0 :     }
     162              : 
     163              :     /// Algorithm used to *digest* the file.
     164              :     ///
     165              :     /// It should match [`SignerInfo::digest_algorithm`]
     166            0 :     pub fn digest_algorithm(&self) -> Algorithms {
     167            0 :         Algorithms::from(self.ptr.digest_algorithm())
     168            0 :     }
     169              : 
     170              :     /// ContentInfo as described in the RFC2315 <https://tools.ietf.org/html/rfc2315#section-7>
     171          208 :     pub fn content_info(&'a self) -> ContentInfo<'a> {
     172          208 :         ContentInfo::from_ffi(self.ptr.content_info())
     173          208 :     }
     174              : 
     175              :     /// Return list of [`X509`] certificates associated with this signature
     176          104 :     pub fn certificates(&'a self) -> Certificates<'a> {
     177          104 :         Certificates::new(self.ptr.certificates())
     178          104 :     }
     179              : 
     180              :     /// Iterator over the signer [`SignerInfo`] defined in the PKCS #7 signature
     181          104 :     pub fn signers(&'a self) -> Signers<'a> {
     182          104 :         Signers::new(self.ptr.signers())
     183          104 :     }
     184              : 
     185              :     /// The original raw signature as a slice of bytes
     186            8 :     pub fn raw_der(&'a self) -> &[u8] {
     187            8 :         to_slice!(self.ptr.raw_der());
     188            8 :     }
     189              : 
     190              :     /// Find x509 certificate according to its serial number
     191            0 :     pub fn crt_by_serial(&self, serial: &[u8]) -> Option<X509> {
     192            0 :         unsafe {
     193            0 :             into_optional(self.ptr.find_crt_by_serial(serial.as_ptr(), serial.len()))
     194            0 :         }
     195            0 :     }
     196              : 
     197              :     /// Find [`X509`] certificate according to its subject
     198            0 :     pub fn crt_by_subject(&self, subject: &str) -> Option<X509> {
     199            0 :         into_optional(self.ptr.find_crt_by_subject(subject))
     200            0 :     }
     201              : 
     202              :     /// Find [`X509`] certificate according to its subject **AND** serial number
     203            0 :     pub fn crt_by_subject_and_serial(&self, subject: &str, serial: &[u8]) -> Option<X509> {
     204            0 :         unsafe {
     205            0 :             into_optional(self.ptr.find_crt_by_subject_and_serial(subject, serial.as_ptr(), serial.len()))
     206            0 :         }
     207            0 :     }
     208              : 
     209              :     /// Find [`X509`] certificate according to its issuer
     210            0 :     pub fn crt_by_issuer(&self, issuer: &str) -> Option<X509> {
     211            0 :         into_optional(self.ptr.find_crt_by_issuer(issuer))
     212            0 :     }
     213              : 
     214              :     /// Find [`X509`] certificate according to its issuer **AND** serial number
     215            0 :     pub fn find_crt_by_issuer_and_serial(&self, issuer: &str, serial: &[u8]) -> Option<X509> {
     216            0 :         unsafe {
     217            0 :             into_optional(self.ptr.find_crt_by_issuer_and_serial(issuer, serial.as_ptr(), serial.len()))
     218            0 :         }
     219            0 :     }
     220              : 
     221              :     /// Check if this signature is valid according to the Authenticode/PKCS #7 verification scheme
     222              :     ///
     223              :     /// By default, it performs the following verifications:
     224              :     ///
     225              :     /// 1. It must contain only **one** signer info
     226              :     /// 2. [`Signature::digest_algorithm`] must match:
     227              :     ///    * [`ContentInfo::digest_algorithm`]
     228              :     ///    * [`SignerInfo::digest_algorithm`]
     229              :     /// 3. The x509 certificate specified by [`SignerInfo::serial_number`] **and** [`SignerInfo::issuer`]
     230              :     ///    must exist within [`Signature::certificates`]
     231              :     /// 4. Given the x509 certificate, compare [`SignerInfo::encrypted_digest`] against either:
     232              :     ///    * hash of authenticated attributes if present
     233              :     ///    * hash of ContentInfo
     234              :     /// 5. If authenticated attributes are present, check that a `PKCS9_MESSAGE_DIGEST` attribute exists
     235              :     ///    and that its value matches hash of ContentInfo
     236              :     /// 6. Check the validity of the PKCS #9 counter signature if present
     237              :     /// 7. If the signature doesn't embed a signing-time in the counter signature, check the certificate
     238              :     ///    validity.
     239              :     ///    (See [`VerificationChecks::LIFETIME_SIGNING`] and [`VerificationChecks::SKIP_CERT_TIME`])
     240              :     ///
     241              :     /// See: [`VerificationChecks`] to tweak the behavior
     242            0 :     pub fn check(&self, checks: VerificationChecks) -> VerificationFlags {
     243            0 :         VerificationFlags::from(self.ptr.check(checks.into()))
     244            0 :     }
     245              : }
     246              : 
     247           48 : declare_iterator!(
     248           48 :     Signatures,
     249           48 :     Signature<'a>,
     250           48 :     ffi::PE_Signature,
     251           48 :     ffi::PE_Binary,
     252           48 :     ffi::PE_Binary_it_signatures
     253           48 : );
        

Generated by: LCOV version 2.1-1