J. M. Pierre Langlois

103 papers A* 1A 5B 2C 9Misc 3Journal 42Unranked 41
YearRankTypeTitle / Venue / Authors
2025 J jnl
ACM Trans. Reconfigurable Technol. Syst.
Shervin Vakili, Mobin Vaziri, Amirhossein Zarei, J. M. Pierre Langlois
2024 conf
HPEC
Mobin Vaziri, Shervin Vakili, M. Mehdi Rahimifar, J. M. Pierre Langlois
2024 J jnl
CoRR
Mobin Vaziri, Shervin Vakili, M. Mehdi Rahimifar, J. M. Pierre Langlois
2024 conf
MWSCAS
Aymen-Alaeddine Zeghaida, Dinesh Daultani, J. M. Pierre Langlois, Jean-Pierre David
2023 J jnl
CoRR
Shervin Vakili, Mobin Vaziri, Amirhossein Zarei, J. M. Pierre Langlois
2023 conf
NEWCAS
Amirali Ebrahimi, Vineeth Narayan Pullu, J. M. Pierre Langlois, Jean-Pierre David
2023 J jnl
ACM Trans. Archit. Code Optim.
Thomas Luinaud, J. M. Pierre Langlois, Yvon Savaria
2022 conf
NEWCAS
Moussa Traore, J. M. Pierre Langlois, Jean-Pierre David
2021 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Mehdi Ahmadi, Shervin Vakili, J. M. Pierre Langlois
2021 A conf
FPGA
Thomas Luinaud, Jeferson Santiago da Silva, J. M. Pierre Langlois, Yvon Savaria
2021 J jnl
CoRR
Thomas Luinaud, Jeferson Santiago da Silva, J. M. Pierre Langlois, Yvon Savaria
2020 conf
NEWCAS
Mehdi Ahmadi, Shervin Vakili, J. M. Pierre Langlois
2020 J jnl
CoRR
Mehdi Ahmadi, Shervin Vakili, J. M. Pierre Langlois
2020 C conf
HPSR
Thomas Luinaud, Thibaut Stimpfling, Jeferson Santiago da Silva, Yvon Savaria, J. M. Pierre Langlois
2020 J jnl
CoRR
Thomas Luinaud, Thibaut Stimpfling, Jeferson Santiago da Silva, Yvon Savaria, J. M. Pierre Langlois
2020 J jnl
CoRR
Mehdi Ahmadi, Shervin Vakili, J. M. Pierre Langlois
2020 conf
NEWCAS
Mehdi Ahmadi, Shervin Vakili, J. M. Pierre Langlois
2020 J jnl
J. Signal Process. Syst.
Ahmed M. Abdelsalam, Ahmed Elsheikh, Sivakumar Chidambaram, Jean-Pierre David, J. M. Pierre Langlois
2020 J jnl
CoRR
Sivakumar Chidambaram, J. M. Pierre Langlois, Jean-Pierre David
2020 A conf
FPGA
Thomas Luinaud, Thibaut Stimpfling, Jeferson Santiago da Silva, Yvon Savaria, J. M. Pierre Langlois
2019 Misc conf
FCCM
Jeferson Santiago da Silva, François-Raymond Boyer, J. M. Pierre Langlois
2019 J jnl
CoRR
Jeferson Santiago da Silva, François-Raymond Boyer, J. M. Pierre Langlois
2019 conf
DASIP
Ahmed M. Abdelsalam, Ahmed Elsheikh, Jean-Pierre David, J. M. Pierre Langlois
2019 J jnl
IEEE/ACM Trans. Netw.
Thibaut Stimpfling, Normand Bélanger, J. M. Pierre Langlois, Yvon Savaria
2018 B conf
CCGrid
Thibaut Stimpfling, J. M. Pierre Langlois, Normand Bélanger, Yvon Savaria
2018 conf
DASIP
Sivakumar Chidambaram, Alexandre Riviello, J. M. Pierre Langlois, Jean-Pierre David
2018 conf
ReConFig
Ahmed M. Abdelsalam, Felix Boulet, Gabriel Demers, J. M. Pierre Langlois, Farida Cheriet
2018 C conf
ISCAS
Mathieu Léonardon, Camille Leroux, David Binet, J. M. Pierre Langlois, Christophe Jégo, Yvon Savaria
2018 J jnl
IET Commun.
Shervin Vakili, J. M. Pierre Langlois, Yvon Savaria, Naraig Manjikian
2018 J jnl
IEEE Trans. Image Process.
Ali Mosleh, Yasser Elmi Sola, Farzad Zargari, Emmanuel Onzon, J. M. Pierre Langlois
2018 B conf
NetSoft
Jeferson Santiago da Silva, François-Raymond Boyer, Laurent-Olivier Chiquette, J. M. Pierre Langlois
2018 J jnl
J. Real Time Image Process.
Hamza Bendaoudi, Farida Cheriet, Ashley Manraj, Houssem Ben Tahar, J. M. Pierre Langlois
2018 A conf
FPGA
Jeferson Santiago da Silva, François-Raymond Boyer, J. M. Pierre Langlois
2018 conf
DASIP
Ahmed M. Abdelsalam, Ahmed Elsheikh, Jean-Pierre David, J. M. Pierre Langlois
2018 conf
NEWCAS
Mehdi Ahmadi, Shervin Vakili, J. M. Pierre Langlois, Warren J. Gross
2017 Misc conf
FCCM
Ahmed M. Abdelsalam, J. M. Pierre Langlois, Farida Cheriet
2017 A conf
FPGA
Ahmed M. Abdelsalam, J. M. Pierre Langlois, Farida Cheriet
2017 conf
ACM Great Lakes Symposium on VLSI
Thomas Luinaud, Yvon Savaria, J. M. Pierre Langlois
2017 A conf
FPGA
Thomas Luinaud, Yvon Savaria, J. M. Pierre Langlois
2017 conf
CCECE
Shuli Gao, Dhamin Al-Khalili, J. M. Pierre Langlois, Noureddine Chabini
2017 J jnl
Int. J. Reconfigurable Comput.
Shuli Gao, Dhamin Al-Khalili, J. M. Pierre Langlois, Noureddine Chabini
2017 J jnl
CoRR
Jeferson Santiago da Silva, François-Raymond Boyer, J. M. Pierre Langlois
2017 J jnl
CoRR
Thibaut Stimpfling, Normand Bélanger, J. M. Pierre Langlois, Yvon Savaria
2017 C conf
ISCAS
Ideh Sarbishei, Shervin Vakili, J. M. Pierre Langlois, Yvon Savaria
2016 J jnl
IET Comput. Digit. Tech.
Shervin Vakili, J. M. Pierre Langlois, Guy Bois
2016 J jnl
CoRR
Ahmed M. Abdelsalam, J. M. Pierre Langlois, Farida Cheriet
2016 J jnl
Signal Image Video Process.
Rana Farah, J. M. Pierre Langlois, Guillaume-Alexandre Bilodeau
2016 J jnl
CoRR
Jeferson Santiago da Silva, François-Raymond Boyer, Laurent-Olivier Chiquette, J. M. Pierre Langlois
2016 J jnl
CoRR
Hamza Bendaoudi, Farida Cheriet, J. M. Pierre Langlois
2016 conf
DASIP
Hamza Bendaoudi, Farida Cheriet, J. M. Pierre Langlois
2016 conf
Real-Time Image and Video Processing
Qifeng Gan, Lama Séoud, Houssem Ben Tahar, J. M. Pierre Langlois
2016 conf
ANCS
Shervin Vakili, J. M. Pierre Langlois, Bochra Boughzala, Yvon Savaria
2016 conf
ANCS
Alexsandre B. Lacroix, J. M. Pierre Langlois, François-Raymond Boyer, Antoine Gosselin, Guy Bois
2016 J jnl
IEEE Trans. Medical Imaging
Lama Séoud, Thomas Hurtut, Jihed Chelbi, Farida Cheriet, J. M. Pierre Langlois
2015 conf
ReConFig
Hamza Bendaoudi, Qifeng Gan, Farida Cheriet, Houssem Ben Tahar, J. M. Pierre Langlois
2015 J jnl
Signal Image Video Process.
Guillaume-Alexandre Bilodeau, Sébastien Desgent, Rana Farah, Sandra Duss, J. M. Pierre Langlois, Lionel Carmant
2015 A* conf
CVPR
Ali Mosleh, Paul Green, Emmanuel Onzon, Isabelle Bégin, J. M. Pierre Langlois
2015 conf
AHS
Shervin Vakili, J. M. Pierre Langlois, Guy Bois
2014 J jnl
Circuits Syst. Signal Process.
Qifeng Gan, J. M. Pierre Langlois, Yvon Savaria
2014 J jnl
Mach. Vis. Appl.
Rana Farah, Qifeng Gan, J. M. Pierre Langlois, Guillaume-Alexandre Bilodeau, Yvon Savaria
2014 conf
NEWCAS
Thalie Keklikian, J. M. Pierre Langlois, Yvon Savaria
2014 conf
DASIP
Hamza Bendaoudi, Farida Cheriet, Houssem Ben Tahar, J. M. Pierre Langlois
2014 conf
ISBI
Lama Séoud, Timothée Faucon, Thomas Hurtut, Jihed Chelbi, Farida Cheriet, J. M. Pierre Langlois
2014 J jnl
J. Signal Process. Syst.
Qifeng Gan, J. M. Pierre Langlois, Yvon Savaria
2014 conf
ECCV (4)
Ali Mosleh, J. M. Pierre Langlois, Paul Green
2014 conf
Computer-Aided Diagnosis
Mahnaz Fasih, J. M. Pierre Langlois, Houssem Ben Tahar, Farida Cheriet
2013 conf
MWSCAS
Qifeng Gan, J. M. Pierre Langlois, Yvon Savaria
2013 conf
DASIP
Diana Carolina Gil, J. M. Pierre Langlois, Yvon Savaria
2013 J jnl
IEEE Trans. Image Process.
Rana Farah, J. M. Pierre Langlois, Guillaume-Alexandre Bilodeau
2013 J jnl
IET Comput. Digit. Tech.
Shervin Vakili, J. M. Pierre Langlois, Guy Bois
2013 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Shervin Vakili, J. M. Pierre Langlois, Guy Bois
2013 Misc conf
ICASSP
Shervin Vakili, J. M. Pierre Langlois, Guy Bois
2012 J jnl
IET Comput. Digit. Tech.
Shuli Gao, Dhamin Al-Khalili, Noureddine Chabini, J. M. Pierre Langlois
2012 J jnl
Mach. Vis. Appl.
Guillaume-Alexandre Bilodeau, Atousa Torabi, Maxime Levesque, Charles Ouellet, J. M. Pierre Langlois, Pablo Lema, Lionel Carmant
2012 J jnl
IEEE Trans. Very Large Scale Integr. Syst.
P. Aubertin, J. M. Pierre Langlois, Yvon Savaria
2011 conf
ICECS
Jacques Laurent Athow, Côme Rozon, Dhamin Al-Khalili, J. M. Pierre Langlois
2011 conf
ICECS
Rana Farah, Qifeng Gan, J. M. Pierre Langlois, Guillaume-Alexandre Bilodeau, Yvon Savaria
2011 C conf
ISCAS
Simon Rajotte, Diana Carolina Gil, J. M. Pierre Langlois
2011 C conf
ISCAS
Diana Carolina Gil, Rana Farah, J. M. Pierre Langlois, Guillaume-Alexandre Bilodeau, Yvon Savaria
2011 conf
ICECS
Shervin Vakili, Diana Carolina Gil, J. M. Pierre Langlois, Yvon Savaria, Guy Bois
2011 conf
ROSE
Rana Farah, J. M. Pierre Langlois, Guillaume-Alexandre Bilodeau
2010 J jnl
J. Signal Process. Syst.
Shuli Gao, Noureddine Chabini, Dhamin Al-Khalili, J. M. Pierre Langlois
2010 J jnl
Integr. Comput. Aided Eng.
Azizul Islam, Umar Iqbal, J. M. Pierre Langlois, Aboelmagd Noureldin
2010 conf
IJCCI (ICEC)
J. C. F. Allaire, J. M. Pierre Langlois, Gilles Labonté, Mohamed Tarbouchi
2009 conf
EIT
Azizul Islam, J. M. Pierre Langlois, Aboelmagd Noureldin
2009 conf
BIOSIGNALS
Guillaume-Alexandre Bilodeau, Maxime Levesque, J. M. Pierre Langlois, Pablo Lema, Lionel Carmant
2008 C conf
ICCD
Sebastien Fontaine, Sylvain Goyette, J. M. Pierre Langlois, Guy Bois
2008 C conf
ICCD
Marc-André Daigneault, J. M. Pierre Langlois, Jean-Pierre David
2008 C conf
ISCAS
Man Yan Kong, J. M. Pierre Langlois, Dhamin Al-Khalili
2008 conf
ISVC (1)
Atousa Torabi, Guillaume-Alexandre Bilodeau, Maxime Levesque, J. M. Pierre Langlois, Pablo Lema, Lionel Carmant
2007 J jnl
IEEE Trans. Consumer Electron.
Hossein Mahvash Mohammadi, J. M. Pierre Langlois, Yvon Savaria
2007 conf
ASAP
Shuli Gao, Noureddine Chabini, Dhamin Al-Khalili, J. M. Pierre Langlois
2007 J jnl
IET Comput. Digit. Tech.
Shuli Gao, Noureddine Chabini, Dhamin Al-Khalili, J. M. Pierre Langlois
2006 conf
ICECS
Hossein Mahvash Mohammadi, J. M. Pierre Langlois, Yvon Savaria
2006 C conf
AICCSA
Shuli Gao, Noureddine Chabini, Dhamin Al-Khalili, J. M. Pierre Langlois
2006 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
J. M. Pierre Langlois, Dhamin Al-Khalili
2006 conf
SoCC
Shuli Gao, Dhamin Al-Khalili, Noureddine Chabini, J. M. Pierre Langlois
2006 conf
CCECE
Nasreddine Hireche, J. M. Pierre Langlois, Gabriela Nicolescu
2003 conf
CICC
J. M. Pierre Langlois, Dhamin Al-Khalili
2003 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
J. M. Pierre Langlois, Dhamin Al-Khalili
2002 conf
ACM Great Lakes Symposium on VLSI
J. M. Pierre Langlois, Dhamin Al-Khalili
2002 conf
ISCAS (5)
J. M. Pierre Langlois, Dhamin Al-Khalili
2002 J jnl
J. VLSI Signal Process.
J. M. Pierre Langlois, Dhamin Al-Khalili, Robert J. Inkol
redb/extractors/pe_extractors/pe_signature.py
← Index redb/extractors/pe_extractors/pe_signature.py python
import inspect
import yara_x
from datetime import datetime, timezone
from signify.authenticode import SignedPEFile
from typing import Any, Dict, List, Tuple

from redb.extractors.enum import Tag
from redb.extractors.pe_extractor import PEExtractor
from redb.models.dataclasses import PECertificate, PESigner, PECodeSigningInfo


class PESignatureExtractor(PEExtractor):
    """
    RFC 3161 - Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)
    Section 2.4.2 defines the TSTInfo structure.
    https://tools.ietf.org/html/rfc3161#section-2.4.2

    Microsoft Authenticode Time Stamping Specification
    https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx
    """

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
        pe=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious,
            pe,
        )
        self.elastic_index = self.index_prefix + "-pe_signature"
        self.log.debug(inspect.currentframe().f_code.co_name)
        self.code_signing_info = None

    def tag(self):
        return [Tag.PE_CERTIFICATE.value, Tag.PE_SIGNER.value, Tag.PE_SIGNATURE.value]

    def _extract_certificate_info(self, certificate):
        self.log.debug(inspect.currentframe().f_code.co_name)

        # YARA-X returns datetime objects directly, not Unix timestamps
        not_before = certificate["not_before"]
        not_after = certificate["not_after"]

        # Handle both datetime objects and Unix timestamps for compatibility
        if isinstance(not_before, datetime):
            valid_from = not_before.strftime("%Y-%m-%d %H:%M:%S")
        else:
            valid_from = datetime.fromtimestamp(int(not_before), timezone.utc).strftime("%Y-%m-%d %H:%M:%S")

        if isinstance(not_after, datetime):
            valid_to = not_after.strftime("%Y-%m-%d %H:%M:%S")
        else:
            valid_to = datetime.fromtimestamp(int(not_after), timezone.utc).strftime("%Y-%m-%d %H:%M:%S")

        return PECertificate(
            certificate_serial_number=certificate["serial"],
            certificate_subject=certificate["subject"],
            certificate_issuer=certificate["issuer"],
            certificate_valid_from=valid_from,
            certificate_valid_to=valid_to,
            certificate_thumbprint=certificate["thumbprint"].upper(),
            certificate_algorithm=certificate["algorithm"],
        )

    def _extract_signer_info(self, signer):
        self.log.debug(inspect.currentframe().f_code.co_name)

        # YARA-X returns datetime objects directly, not Unix timestamps
        not_before = signer["not_before"]
        not_after = signer["not_after"]

        # Handle both datetime objects and Unix timestamps for compatibility
        if isinstance(not_before, datetime):
            valid_from = not_before.strftime("%Y-%m-%d %H:%M:%S")
        else:
            valid_from = datetime.fromtimestamp(int(not_before), timezone.utc).strftime("%Y-%m-%d %H:%M:%S")

        if isinstance(not_after, datetime):
            valid_to = not_after.strftime("%Y-%m-%d %H:%M:%S")
        else:
            valid_to = datetime.fromtimestamp(int(not_after), timezone.utc).strftime("%Y-%m-%d %H:%M:%S")

        return PESigner(
            signer_serial_number=signer["serial"],
            signer_subject=signer["subject"],
            signer_issuer=signer["issuer"],
            signer_valid_from=valid_from,
            signer_valid_to=valid_to,
            signer_thumbprint=signer["thumbprint"].upper(),
            signer_algorithm=signer["algorithm"],
        )

    def _extract_signature_info(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        pe_rules = """
            import "pe"
            rule is_pe {
                condition: 
                    pe.is_pe
            }
        """
        rule = yara_x.compile(pe_rules)
        results = rule.scan(self.binary)
        yara_output = results.module_outputs

        signature_info = yara_output["pe"]["signatures"][0]
        number_of_certificates = signature_info["number_of_certificates"]
        signature_verified = signature_info["verified"]
        self.code_signing_info = PECodeSigningInfo(
            _id=self.sha256,
            signature_verified=signature_verified,
            number_of_certificates=int(number_of_certificates),
        )

        keys = signature_info.keys()
        if "certificates" in keys:
            self.log.debug("Extracting PE Signing Certificates")
            certificates = signature_info["certificates"]
            certificates_list = []
            for cert in certificates:
                cert_info = self._extract_certificate_info(cert)
                certificates_list.append(cert_info)
            self.code_signing_info.x509_certificates = certificates_list

        if "signer_info" in keys:
            self.log.debug("Extracting PE Signing Signer Info")
            signers = signature_info["signer_info"]["chain"]
            signers_list = []
            for signer in signers:
                sig = self._extract_signer_info(signer)
                signers_list.append(sig)
            self.code_signing_info.signers = signers_list

        if "countersignatures" in keys:
            self.log.debug("Extracting PE Signing Countersignatures")
            countersignatures = signature_info["countersignatures"][0]["chain"]
            countersigners_list = []
            for csigner in countersignatures:
                csig = self._extract_signer_info(csigner)
                countersigners_list.append(csig)
            self.code_signing_info.countersigners = countersigners_list

        with open(self.filepath, "rb") as f:
            self.log.debug("Extracting PE Signing spcSpOpusInfo")
            sig_pefile = SignedPEFile(f)
            try:
                spc_opusinfo = {}
                for signed_data in sig_pefile.signed_datas:
                    spc_opusinfo["ProgramName"] = signed_data.signer_info.program_name
                    spc_opusinfo["MoreInfo"] = signed_data.signer_info.more_info
                    self.code_signing_info.spcSpOpusInfo = spc_opusinfo

                    if signed_data.signer_info.countersigner is not None:
                        stime = signed_data.signer_info.countersigner.signing_time
                        self.code_signing_info.date_signed = stime.strftime(
                            "%Y-%m-%d %H:%M:%S"
                        )
            except Exception as e:
                self.log.error(
                    f"Error while extracting spcSpOpusInfo or signing date: {e}"
                )

    def extract(self):
        try:
            self.log.debug(inspect.currentframe().f_code.co_name)
            if self._is_signed():
                self._extract_signature_info()
                # self.export_to_elastic([self.code_signing_info])
                return self.code_signing_info
            return None
        except Exception as e:
            self.log.error(f"Error extracting PE Signature: {e}")
            return None

    # def prepare_export_data(self, exporter_type: str) -> Any:
    #     self.log.debug(inspect.currentframe().f_code.co_name)
    #     if exporter_type == "ElasticsearchExporter":
    #         return self.extract()
    #     elif exporter_type == "ClickHouseExporter":
    #         signing_info = self.extract()
    #         if signing_info is None:
    #             return None
                
    #         current_time = datetime.now(timezone.utc)
            
    #         # Prepare data for redb_pe_signatures table
    #         signatures_data = [[
    #             self.sha256,                                    # sha256
    #             self.md5,                                       # md5
    #             self.sha1,                                      # sha1
    #             signing_info.signature_verified,                # signature_verified
    #             datetime.strptime(signing_info.date_signed, "%Y-%m-%d %H:%M:%S") if signing_info.date_signed else None,  # date_signed
    #             signing_info.number_of_certificates,            # number_of_certificates
    #             signing_info.spcSpOpusInfo.get('ProgramName', None) if signing_info.spcSpOpusInfo else None,  # program_name
    #             signing_info.spcSpOpusInfo.get('MoreInfo', None) if signing_info.spcSpOpusInfo else None,    # more_info
    #             current_time                                    # analysis_date
    #         ]]

    #         certificates_data = []
            
    #         # Process signers
    #         if signing_info.signers:
    #             for signer in signing_info.signers:
    #                 certificates_data.append(self._prepare_certificate_data(signer, 'signer', current_time))
            
    #         # Process countersigners
    #         if signing_info.countersigners:
    #             for csigner in signing_info.countersigners:
    #                 certificates_data.append(self._prepare_certificate_data(csigner, 'countersigner', current_time))
            
    #         # Process x509 certificates
    #         if signing_info.x509_certificates:
    #             for cert in signing_info.x509_certificates:
    #                 certificates_data.append(self._prepare_certificate_data(cert, 'chain', current_time))
            
    #         return {
    #             'multi_table': True,
    #             'signatures': {
    #                 'table': 'redb_pe_signatures',
    #                 'data': signatures_data,
    #                 'column_names': [
    #                     'sha256', 'md5', 'sha1', 'signature_verified', 'date_signed',
    #                     'number_of_certificates', 'spcSpOpusInfo_program_name', 'spcSpOpusInfo_more_info', 'analysis_date'
    #                 ],
    #                 'column_type_names': [
    #                     'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
    #                     'Boolean', 'DateTime64(3, \'UTC\')', 'UInt8',
    #                     'Nullable(String)', 'Nullable(String)', 'DateTime64(3, \'UTC\')'
    #                 ]
    #             },
    #             'certificates': {
    #                 'table': 'redb_pe_certificates',
    #                 'data': certificates_data,
    #                 'column_names': [
    #                     'sha256', 'md5', 'sha1', 'certificate_type', 'certificate_algorithm',
    #                     'certificate_issuer', 'certificate_subject', 'certificate_serial_number',
    #                     'certificate_thumbprint', 'certificate_valid_from', 'certificate_valid_to',
    #                     'analysis_date'
    #                 ],
    #                 'column_type_names': [
    #                     'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
    #                     'Enum(\'signer\', \'countersigner\', \'chain\')', 'LowCardinality(String)',
    #                     'LowCardinality(String)', 'LowCardinality(String)', 'String',
    #                     'String', 'DateTime64(3, \'UTC\')', 'DateTime64(3, \'UTC\')',
    #                     'DateTime64(3, \'UTC\')'
    #                 ]
    #             }
    #         }

    # def _prepare_certificate_data(self, cert, cert_type: str, analysis_time: datetime) -> List:
    #     """Helper method to prepare certificate data for ClickHouse"""
    #     self.log.debug(inspect.currentframe().f_code.co_name)
    #     prefix = "certificate_" if hasattr(cert, "certificate_algorithm") else "signer_"
        
    #     # Get serial number and clean it up
    #     serial_number = getattr(cert, f"{prefix}serial_number")
    #     if serial_number:
    #         serial_number = serial_number.replace(':', '')
        
    #     return [
    #         self.sha256,                          # sha256
    #         self.md5,                             # md5
    #         self.sha1,                            # sha1
    #         cert_type,                            # certificate_type
    #         getattr(cert, f"{prefix}algorithm"),   # certificate_algorithm
    #         getattr(cert, f"{prefix}issuer"),     # certificate_issuer
    #         getattr(cert, f"{prefix}subject"),    # certificate_subject
    #         serial_number,                        # certificate_serial_number
    #         getattr(cert, f"{prefix}thumbprint"),  # certificate_thumbprint
    #         datetime.strptime(getattr(cert, f"{prefix}valid_from"), "%Y-%m-%d %H:%M:%S"),  # certificate_valid_from
    #         datetime.strptime(getattr(cert, f"{prefix}valid_to"), "%Y-%m-%d %H:%M:%S"),    # certificate_valid_to
    #         analysis_time                         # analysis_date
    #     ]
    def prepare_export_data(self, exporter_type: str) -> Any:
        self.log.debug(inspect.currentframe().f_code.co_name)
        if exporter_type == "ElasticsearchExporter":
            return self.extract()
        elif exporter_type == "ClickHouseExporter":
            signing_info = self.extract()
            if signing_info is None:
                return None
                
            current_time = datetime.now(timezone.utc)
            
            # Prepare data for redb_pe_signatures table
            signatures_data = [[
                self.sha256,                                    # sha256
                self.md5,                                       # md5
                self.sha1,                                      # sha1
                signing_info.signature_verified,                # signature_verified
                datetime.strptime(signing_info.date_signed, "%Y-%m-%d %H:%M:%S") if signing_info.date_signed else None,  # date_signed
                signing_info.number_of_certificates,            # number_of_certificates
                signing_info.spcSpOpusInfo.get('ProgramName', None) if signing_info.spcSpOpusInfo else None,  # program_name
                signing_info.spcSpOpusInfo.get('MoreInfo', None) if signing_info.spcSpOpusInfo else None,    # more_info
                current_time                                    # analysis_date
            ]]

            # Prepare data for redb_pe_certificates table
            certificates_data = []
            
            # Process signers
            if signing_info.signers:
                for signer in signing_info.signers:
                    certificates_data.append(self._prepare_certificate_data(signer, 'signer', current_time))
            
            # Process countersigners
            if signing_info.countersigners:
                for csigner in signing_info.countersigners:
                    certificates_data.append(self._prepare_certificate_data(csigner, 'countersigner', current_time))
            
            # Process x509 certificates
            if signing_info.x509_certificates:
                for cert in signing_info.x509_certificates:
                    certificates_data.append(self._prepare_certificate_data(cert, 'chain', current_time))
            
            return {
                'multi_table': True,
                'signatures': {
                    'table': 'redb_pe_signatures',
                    'data': signatures_data,
                    'column_names': [
                        'sha256', 'md5', 'sha1', 'signature_verified', 'date_signed',
                        'number_of_certificates', 'spcSpOpusInfo_program_name', 'spcSpOpusInfo_more_info', 'analysis_date'
                    ],
                    'column_type_names': [
                        'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
                        'Boolean', 'DateTime64(3, \'UTC\')', 'UInt8',
                        'Nullable(String)', 'Nullable(String)', 'DateTime64(3, \'UTC\')'
                    ]
                },
                'certificates': {
                    'table': 'redb_pe_certificates',
                    'data': certificates_data,
                    'column_names': [
                        'sha256', 'md5', 'sha1', 'certificate_type', 'certificate_algorithm',
                        'certificate_issuer', 'certificate_subject', 'certificate_serial_number',
                        'certificate_thumbprint', 'certificate_valid_from', 'certificate_valid_to',
                        'analysis_date'
                    ],
                    'column_type_names': [
                        'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
                        'Enum8(\'signer\' = 1, \'countersigner\' = 2, \'chain\' = 3)', 'LowCardinality(String)',
                        'LowCardinality(String)', 'LowCardinality(String)', 'String',
                        'String', 'DateTime64(3, \'UTC\')', 'DateTime64(3, \'UTC\')',
                        'DateTime64(3, \'UTC\')'
                    ]
                }
            }

    # def _prepare_certificate_data(self, cert, cert_type: str, analysis_time: datetime) -> List:
    #     """Helper method to prepare certificate data for ClickHouse"""
    #     self.log.debug(inspect.currentframe().f_code.co_name)
    #     prefix = "certificate_" if hasattr(cert, "certificate_algorithm") else "signer_"
        
    #     # Get serial number and clean it up - with strict handling
    #     serial_number = getattr(cert, f"{prefix}serial_number", "UNKNOWN")
    #     if not serial_number or not str(serial_number).strip():
    #         serial_number = "UNKNOWN"
    #     else:
    #         serial_number = serial_number.replace(':', '')
    #         if not serial_number.strip():  # Double check after cleaning
    #             serial_number = "UNKNOWN"
        
    #     return [
    #         self.sha256,                          # sha256
    #         self.md5,                             # md5
    #         self.sha1,                            # sha1
    #         cert_type,                            # certificate_type
    #         getattr(cert, f"{prefix}algorithm"),   # certificate_algorithm
    #         getattr(cert, f"{prefix}issuer"),     # certificate_issuer
    #         getattr(cert, f"{prefix}subject"),    # certificate_subject
    #         serial_number,                        # certificate_serial_number
    #         getattr(cert, f"{prefix}thumbprint"),  # certificate_thumbprint
    #         datetime.strptime(getattr(cert, f"{prefix}valid_from"), "%Y-%m-%d %H:%M:%S"),  # certificate_valid_from
    #         datetime.strptime(getattr(cert, f"{prefix}valid_to"), "%Y-%m-%d %H:%M:%S"),    # certificate_valid_to
    #         analysis_time                         # analysis_date
    #     ]

    def _prepare_certificate_data(self, cert, cert_type: str, analysis_time: datetime) -> List:
        """Helper method to prepare certificate data for ClickHouse"""
        self.log.debug(inspect.currentframe().f_code.co_name)
        prefix = "certificate_" if hasattr(cert, "certificate_algorithm") else "signer_"
        
        def clean_string(value, field_name):
            if value is None or (isinstance(value, str) and not value.strip()):
                self.log.warning(f"Empty or None value found for {field_name}")
                return "UNKNOWN"
            return str(value).strip()
        
        try:
            serial_number = getattr(cert, f"{prefix}serial_number", "UNKNOWN")
            serial_number = clean_string(serial_number, "serial_number")
            if serial_number != "UNKNOWN":
                serial_number = serial_number.replace(':', '')
        
            return [
                clean_string(self.sha256, "sha256"),
                clean_string(self.md5, "md5"),
                clean_string(self.sha1, "sha1"),
                cert_type,
                clean_string(getattr(cert, f"{prefix}algorithm"), "algorithm"),
                clean_string(getattr(cert, f"{prefix}issuer"), "issuer"),
                clean_string(getattr(cert, f"{prefix}subject"), "subject"),
                serial_number,
                clean_string(getattr(cert, f"{prefix}thumbprint"), "thumbprint"),
                datetime.strptime(getattr(cert, f"{prefix}valid_from"), "%Y-%m-%d %H:%M:%S"),
                datetime.strptime(getattr(cert, f"{prefix}valid_to"), "%Y-%m-%d %H:%M:%S"),
                analysis_time
            ]
        except Exception as e:
            self.log.error(f"Error preparing certificate data: {str(e)}")
            self.log.error(f"Certificate data that caused error: {cert}")
            raise

    def get_clickhouse_table(self) -> str:
        """Required by PEExtractor abstract base class"""
        return "redb_pe_signatures"  # Return the primary table

    def get_clickhouse_tables(self) -> Dict[str, str]:
        """Additional method for multi-table support"""
        return {
            'signatures': 'redb_pe_signatures',
            'certificates': 'redb_pe_certificates'
        }