diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10502ff..df9a3ed 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -325,6 +325,9 @@ if(LIEF_FROZEN_ENABLED)
   add_dependencies(LIB_LIEF lief_frozen)
 endif()
 
+# =======================================
+# Leaf
+# =======================================
 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/boost/leaf/all.hpp
   COMMAND
     ${CMAKE_COMMAND} -E copy_directory ${LEAF_INCLUDE_DIR}/
@@ -334,6 +337,9 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/b
 target_sources(LIB_LIEF PRIVATE
   ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/boost/leaf/all.hpp)
 
+# =======================================
+# utfcpp
+# =======================================
 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/utfcpp/utf8.h
   COMMAND
     ${CMAKE_COMMAND} -E copy_directory ${UTFCPP_INCLUDE_DIR}/
@@ -375,6 +381,7 @@ target_compile_definitions(LIB_LIEF PUBLIC -D_GLIBCXX_USE_CXX11_ABI=1)
 # extension.
 add_definitions(-DMBEDTLS_MD2_C -DMBEDTLS_MD4_C -DMBEDTLS_PEM_PARSE_C
                 -DMBEDTLS_X509_CRT_PARSE_C -DMBEDTLS_PEM_WRITE_C
+                -DMBEDTLS_PKCS1_V15 -DMBEDTLS_PKCS1_V21
                 -DMBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
 
 # ASAN - LSAN - TSAN - USAN
diff --git a/api/python/PE/objects/pyBinary.cpp b/api/python/PE/objects/pyBinary.cpp
index e13d92c..492323d 100644
--- a/api/python/PE/objects/pyBinary.cpp
+++ b/api/python/PE/objects/pyBinary.cpp
@@ -166,15 +166,22 @@ void create<Binary>(py::module& m) {
         "algorithm"_a)
 
     .def("verify_signature",
-        static_cast<Signature::VERIFICATION_FLAGS(Binary::*)() const>(&Binary::verify_signature),
+        static_cast<Signature::VERIFICATION_FLAGS(Binary::*)(Signature::VERIFICATION_CHECKS) const>(&Binary::verify_signature),
         R"delim(
         Verify the binary against the embedded signature(s) (if any)
         Firstly, it checks that the embedded signatures are correct (c.f. :meth:`lief.PE.Signature.check`)
         and then it checks that the authentihash matches :attr:`lief.PE.ContentInfo.digest`
-        )delim")
+
+        One can tweak the verification process with the :class:`lief.PE.Signature.VERIFICATION_CHECKS` flags
+
+        .. seealso::
+
+            :meth:`lief.PE.Signature.check`
+        )delim",
+        "checks"_a = Signature::VERIFICATION_CHECKS::DEFAULT)
 
     .def("verify_signature",
-        static_cast<Signature::VERIFICATION_FLAGS(Binary::*)(const Signature&) const>(&Binary::verify_signature),
+        static_cast<Signature::VERIFICATION_FLAGS(Binary::*)(const Signature&, Signature::VERIFICATION_CHECKS) const>(&Binary::verify_signature),
         R"delim(
         Verify the binary with the Signature object provided in the first parameter
         It can be used to verify a detached signature:
@@ -184,7 +191,7 @@ void create<Binary>(py::module& m) {
             detached = lief.PE.Signature.parse("sig.pkcs7")
             binary.verify_signature(detached)
         )delim",
-        "signature"_a)
+        "signature"_a, "checks"_a = Signature::VERIFICATION_CHECKS::DEFAULT)
 
     .def_property_readonly("authentihash_md5",
         [] (const Binary& bin) {
diff --git a/api/python/PE/objects/signature/attributes/pyPKCS9CounterSignature.cpp b/api/python/PE/objects/signature/attributes/pyPKCS9CounterSignature.cpp
index d43612c..1e8f96e 100644
--- a/api/python/PE/objects/signature/attributes/pyPKCS9CounterSignature.cpp
+++ b/api/python/PE/objects/signature/attributes/pyPKCS9CounterSignature.cpp
@@ -49,9 +49,10 @@ void create<PKCS9CounterSignature>(py::module& m) {
         }
 
     )delim")
-    .def_property_readonly("signers",
-        &PKCS9CounterSignature::signers,
-        "Iterator over the " RST_CLASS_REF(lief.PE.SignerInfo) " as described in the RFC")
+    .def_property_readonly("signer",
+        &PKCS9CounterSignature::signer,
+        "Return the " RST_CLASS_REF(lief.PE.SignerInfo) " as described in the RFC #2985",
+        py::return_value_policy::reference)
 
     .def("__hash__",
         [] (const PKCS9CounterSignature& obj) {
diff --git a/api/python/PE/objects/signature/pySignature.cpp b/api/python/PE/objects/signature/pySignature.cpp
index 831b467..373c618 100644
--- a/api/python/PE/objects/signature/pySignature.cpp
+++ b/api/python/PE/objects/signature/pySignature.cpp
@@ -51,7 +51,24 @@ void create<Signature>(py::module& m) {
     .value("MISSING_PKCS9_MESSAGE_DIGEST",  Signature::VERIFICATION_FLAGS::MISSING_PKCS9_MESSAGE_DIGEST)
     .value("BAD_DIGEST",                    Signature::VERIFICATION_FLAGS::BAD_DIGEST)
     .value("BAD_SIGNATURE",                 Signature::VERIFICATION_FLAGS::BAD_SIGNATURE)
-    .value("NO_SIGNATURE",                  Signature::VERIFICATION_FLAGS::NO_SIGNATURE);
+    .value("NO_SIGNATURE",                  Signature::VERIFICATION_FLAGS::NO_SIGNATURE)
+    .value("CERT_EXPIRED",                  Signature::VERIFICATION_FLAGS::CERT_EXPIRED)
+    .value("CERT_FUTURE",                   Signature::VERIFICATION_FLAGS::CERT_FUTURE);
+
+
+  LIEF::enum_<Signature::VERIFICATION_CHECKS>(signature, "VERIFICATION_CHECKS", py::arithmetic(),
+    R"delim(
+    Flags to tweak the verification process of the signature
+    See :meth:`lief.PE.Signature.check` and :meth:`lief.PE.Binary.verify_signature`
+    )delim")
+    .value("DEFAULT", Signature::VERIFICATION_CHECKS::DEFAULT,
+        "Default behavior that tries to follow the Microsoft verification process as close as possible")
+    .value("HASH_ONLY", Signature::VERIFICATION_CHECKS::HASH_ONLY,
+        "Only check that :meth:`lief.PE.Binary.authentihash` matches :attr:`lief.PE.ContentInfo.digest` regardless of the signature's validity")
+    .value("LIFETIME_SIGNING", Signature::VERIFICATION_CHECKS::LIFETIME_SIGNING,
+        "Same semantic as `WTD_LIFETIME_SIGNING_FLAG <https://docs.microsoft.com/en-us/windows/win32/api/wintrust/ns-wintrust-wintrust_data#WTD_LIFETIME_SIGNING_FLAG>`")
+    .value("SKIP_CERT_TIME", Signature::VERIFICATION_CHECKS::SKIP_CERT_TIME,
+        "Skip the verification of the certificates time validities so that even though a certificate expired, it returns :attr:`lief.PE.Signature.VERIFICATION_FLAGS.OK`");
 
   signature
     .def_static("parse",
@@ -78,37 +95,65 @@ void create<Signature>(py::module& m) {
 
     .def_property_readonly("version",
         &Signature::version,
-        "Should be 1")
+        "Version of the signature. It should be 1")
 
     .def_property_readonly("digest_algorithm",
         &Signature::digest_algorithm,
         "Return the algorithm (" RST_CLASS_REF(lief.PE.ALGORITHMS) ") \
         used to sign the content of " RST_CLASS_REF(lief.PE.ContentInfo) "")
 
-
     .def_property_readonly("content_info",
         &Signature::content_info,
         "Return the " RST_CLASS_REF(lief.PE.ContentInfo) "",
         py::return_value_policy::reference)
 
-
     .def_property_readonly("certificates",
         &Signature::certificates,
         "Return an iterator over " RST_CLASS_REF(lief.PE.x509) " certificates",
         py::return_value_policy::reference)
 
-
     .def_property_readonly("signers",
         &Signature::signers,
         "Return an iterator over the signers: " RST_CLASS_REF(lief.PE.SignerInfo) "",
         py::return_value_policy::reference)
 
+    .def("find_crt",
+        static_cast<const x509*(Signature::*)(const std::vector<uint8_t>&) const>(&Signature::find_crt),
+        "Find the " RST_CLASS_REF(lief.PE.x509) " certificate according to its serial number",
+        py::return_value_policy::reference,
+        "serialno"_a)
+
+    .def("find_crt_subject",
+        static_cast<const x509*(Signature::*)(const std::string&) const>(&Signature::find_crt_subject),
+        "Find the " RST_CLASS_REF(lief.PE.x509) " certificate according to its subject",
+        py::return_value_policy::reference,
+        "subject"_a)
+
+    .def("find_crt_subject",
+        static_cast<const x509*(Signature::*)(const std::string&, const std::vector<uint8_t>&) const>(&Signature::find_crt_subject),
+        "Find the " RST_CLASS_REF(lief.PE.x509) " certificate according to its subject **AND** its serial number",
+        py::return_value_policy::reference,
+        "subject"_a, "serialno"_a)
+
+    .def("find_crt_issuer",
+        static_cast<const x509*(Signature::*)(const std::string&) const>(&Signature::find_crt_issuer),
+        "Find the " RST_CLASS_REF(lief.PE.x509) " certificate according to its issuer",
+        py::return_value_policy::reference,
+        "issuer"_a)
+
+    .def("find_crt_issuer",
+        static_cast<const x509*(Signature::*)(const std::string&, const std::vector<uint8_t>&) const>(&Signature::find_crt_issuer),
+        "Find the " RST_CLASS_REF(lief.PE.x509) " certificate according to its issuer **AND** its serial number",
+        py::return_value_policy::reference,
+        "issuer"_a, "serialno"_a)
+
     .def("check",
         &Signature::check,
+        // Note: This documentation needs to be sync with LIEF::PE::Signature::check
         R"delim(
         Check the integrity of the signature and return a :class:`lief.PE.Signature.VERIFICATION_FLAGS`
 
-        It performs the following verifications:
+        By default, it performs the following verifications:
 
         1. It must contain only **one** signer info (:attr:`~lief.PE.Signature.signers`)
         2. :attr:`lief.PE.Signature.digest_algorithm` must match:
@@ -125,8 +170,15 @@ void create<Signature>(py::module& m) {
 
         5. If they are Authenticated attributes, check that a PKCS9_MESSAGE_DIGEST (:class:`lief.PE.PKCS9MessageDigest`) attribute exists
            and that its value matches hash of ContentInfo
+        6. Check the validity of the PKCS #9 counter signature if present
+        7. If the signature doesn't embed a signing-time in the counter signature, check the certificate
+           validity. (See :attr:`lief.PE.Signature.VERIFICATION_CHECKS.LIFETIME_SIGNING` and :attr:`lief.pe.Signature.VERIFICATION_CHECKS.SKIP_CERT_TIME`)
 
-        )delim")
+        See: :class:`lief.PE.Signature.VERIFICATION_CHECKS` to tweak the behavior
+
+        )delim",
+        "checks"_a = Signature::VERIFICATION_CHECKS::DEFAULT
+    )
 
     .def_property_readonly("raw_der",
         [] (const Signature& sig) {
diff --git a/api/python/PE/objects/signature/pySignerInfo.cpp b/api/python/PE/objects/signature/pySignerInfo.cpp
index 77fd665..84f87d2 100644
--- a/api/python/PE/objects/signature/pySignerInfo.cpp
+++ b/api/python/PE/objects/signature/pySignerInfo.cpp
@@ -102,10 +102,34 @@ void create<SignerInfo>(py::module& m) {
 
     .def("get_attribute",
         &SignerInfo::get_attribute,
-        "Return the authenticated or un-authenticated attribute matching the "
-        "given " RST_CLASS_REF(lief.PE.SIG_ATTRIBUTE_TYPES) " \n\n"
-        "It returns **the first** entry that matches the given type. If it can't be "
-        "found, it returns a nullptr",
+        R"delim(
+        Return the authenticated or un-authenticated attribute matching the
+        given :class:`lief.PE.SIG_ATTRIBUTE_TYPES`
+        It returns **the first** entry that matches the given type. If it can't be
+        found, it returns None
+        )delim",
+        "type"_a,
+        py::return_value_policy::reference)
+
+    .def("get_auth_attribute",
+        &SignerInfo::get_auth_attribute,
+        R"delim(
+        Return the authenticated attribute matching the
+        given :class:`lief.PE.SIG_ATTRIBUTE_TYPES`
+        It returns **the first** entry that matches the given type. If it can't be
+        found, it returns None
+        )delim",
+        "type"_a,
+        py::return_value_policy::reference)
+
+    .def("get_unauth_attribute",
+        &SignerInfo::get_unauth_attribute,
+        R"delim(
+        Return the un-authenticated attribute matching the
+        given :class:`lief.PE.SIG_ATTRIBUTE_TYPES`
+        It returns **the first** entry that matches the given type. If it can't be
+        found, it returns a nullptr
+        )delim",
         "type"_a,
         py::return_value_policy::reference)
 
diff --git a/api/python/PE/objects/signature/pyx509.cpp b/api/python/PE/objects/signature/pyx509.cpp
index cefaa9d..071dd52 100644
--- a/api/python/PE/objects/signature/pyx509.cpp
+++ b/api/python/PE/objects/signature/pyx509.cpp
@@ -72,6 +72,17 @@ void create<x509>(py::module& m) {
     .value("RSA_ALT",    x509::KEY_TYPES::RSA_ALT,    "RSA scheme with an alternative implementation for signing and decrypting")
     .value("RSASSA_PSS", x509::KEY_TYPES::RSASSA_PSS, "RSA Probabilistic signature scheme");
 
+  LIEF::enum_<x509::KEY_USAGE>(cls_x509, "KEY_USAGE", "Key usage as defined in `RFC #5280 - section-4.2.1.3 <https://tools.ietf.org/html/rfc5280#section-4.2.1.3>`_")
+    .value("DIGITAL_SIGNATURE", x509::KEY_USAGE::DIGITAL_SIGNATURE,  "The key is used for digital signature")
+    .value("NON_REPUDIATION",   x509::KEY_USAGE::NON_REPUDIATION,    "The key is used for digital signature AND to protects against falsely denying some action")
+    .value("KEY_ENCIPHERMENT",  x509::KEY_USAGE::KEY_ENCIPHERMENT,   "The key is used for enciphering private or secret keys")
+    .value("DATA_ENCIPHERMENT", x509::KEY_USAGE::DATA_ENCIPHERMENT,  "The key is used for directly enciphering raw user data without the use of an intermediate symmetric cipher")
+    .value("KEY_AGREEMENT",     x509::KEY_USAGE::KEY_AGREEMENT,      "The Key is used for key agreement. (e.g. with Diffie-Hellman)")
+    .value("KEY_CERT_SIGN",     x509::KEY_USAGE::KEY_CERT_SIGN,      "The key is used for verifying signatures on public key certificates")
+    .value("CRL_SIGN",          x509::KEY_USAGE::CRL_SIGN,           "The key is used for verifying signatures on certificate revocation lists")
+    .value("ENCIPHER_ONLY",     x509::KEY_USAGE::ENCIPHER_ONLY,      "In **association with** KEY_AGREEMENT (otherwise the meaning is undefined), the key is only used for enciphering data while performing key agreement")
+    .value("DECIPHER_ONLY",     x509::KEY_USAGE::DECIPHER_ONLY,      "In **association with** KEY_AGREEMENT (otherwise the meaning is undefined), the key is only used for deciphering data while performing key agreement");
+
   cls_x509
     .def_static("parse",
         static_cast<x509::certificates_t(*)(const std::string&)>(&x509::parse),
@@ -137,6 +148,27 @@ void create<x509>(py::module& m) {
         "Otherwise, return None",
         py::return_value_policy::take_ownership)
 
+    .def_property_readonly("key_usage",
+        &x509::key_usage,
+        "Purpose of the key contained in the certificate (see " RST_CLASS_REF(lief.PE.x509.KEY_USAGE) ")")
+
+    .def_property_readonly("ext_key_usage",
+        &x509::ext_key_usage,
+        "Indicates one or more purposes for which the certified public key may be used (list of OID)")
+
+    .def_property_readonly("certificate_policies",
+        &x509::certificate_policies,
+        "Policy information terms as list of OID (see RFC #5280)")
+
+    .def_property_readonly("is_ca",
+        &x509::is_ca)
+
+    .def_property_readonly("signature",
+        [] (const x509& cert) -> py::bytes {
+          const std::vector<uint8_t>& sig = cert.signature();
+          return py::bytes(reinterpret_cast<const char*>(sig.data()), sig.size());
+        }, "The signature of the certificate")
+
     .def("verify",
         static_cast<x509::VERIFICATION_FLAGS(x509::*)(const x509&) const>(&x509::verify),
         R"delim(
diff --git a/api/python/PE/pyPE.cpp b/api/python/PE/pyPE.cpp
index 29a63b7..c50d648 100644
--- a/api/python/PE/pyPE.cpp
+++ b/api/python/PE/pyPE.cpp
@@ -41,7 +41,6 @@ void init_python_module(py::module& m) {
 void init_objects(py::module& m) {
   CREATE(Parser, m);
 
-  CREATE(Binary, m);
   CREATE(DosHeader, m);
   CREATE(Header, m);
   CREATE(OptionalHeader, m);
@@ -103,6 +102,7 @@ void init_objects(py::module& m) {
   CREATE(LoadConfigurationV6, m);
   CREATE(LoadConfigurationV7, m);
 
+  CREATE(Binary, m);
   CREATE(Builder, m);
 
 }
diff --git a/examples/python/pe_sign/authenticode.py b/examples/python/authenticode/api_example.py
similarity index 100%
rename from examples/python/pe_sign/authenticode.py
rename to examples/python/authenticode/api_example.py
diff --git a/examples/python/authenticode/authenticode_reader.py b/examples/python/authenticode/authenticode_reader.py
new file mode 100644
index 0000000..f71b5e1
--- /dev/null
+++ b/examples/python/authenticode/authenticode_reader.py
@@ -0,0 +1,302 @@
+#!/usr/bin/env python
+import lief
+from lief.PE import oid_to_string
+import argparse
+import json
+import sys
+import string
+import argparse
+import traceback
+import pathlib
+
+try:
+    from prettyprinter import pprint
+except ImportError:
+    from pprint import pprint
+
+class exceptions_handler(object):
+    func = None
+
+    def __init__(self, exceptions, on_except_callback=None):
+        self.exceptions         = exceptions
+        self.on_except_callback = on_except_callback
+
+    def __call__(self, *args, **kwargs):
+        if self.func is None:
+            self.func = args[0]
+            return self
+        try:
+            return self.func(*args, **kwargs)
+        except self.exceptions as e:
+            if self.on_except_callback is not None:
+                self.on_except_callback(e)
+            else:
+                print("-" * 60)
+                print("Exception in {}: {}".format(self.func.__name__, e))
+                exc_type, exc_value, exc_traceback = sys.exc_info()
+                traceback.print_tb(exc_traceback)
+                print("-" * 60)
+
+@exceptions_handler(Exception)
+def print_attr(indent: int, auth: lief.PE.Attribute):
+    if auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.CONTENT_TYPE:
+        print_content_type(indent, auth)
+    elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_SIGNING_TIME:
+        print_signing_time(indent, auth)
+    elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.MS_SPC_STATEMENT_TYPE:
+        print_ms_statement_type(indent, auth)
+    elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_MESSAGE_DIGEST:
+        print_pkcs_msg_dg(indent, auth)
+    elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_COUNTER_SIGNATURE:
+        print_pkcs_counter_sig(indent, auth)
+    elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.GENERIC_TYPE:
+        print_generic_type(indent, auth)
+    elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.SPC_SP_OPUS_INFO:
+        print_spc_sp_opus_info(indent, auth)
+    elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.MS_SPC_NESTED_SIGN:
+        print_ms_nested_sig(indent, auth)
+    elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_AT_SEQUENCE_NUMBER:
+        print_pkcs9_at_seq_number(indent, auth)
+    else:
+        print(" " * indent, type(auth), auth)
+
+
+@exceptions_handler(Exception)
+def print_pkcs9_at_seq_number(indent: int, auth: lief.PE.PKCS9AtSequenceNumber):
+    print("{} PKCS #9 sequence number: {}".format(" " * indent, auth.number))
+
+@exceptions_handler(Exception)
+def print_ms_nested_sig(indent: int, auth: lief.PE.MsSpcNestedSignature):
+    print("{} MS Nested Signature:".format(" " * indent))
+    print_all(auth.signature, indent + 2)
+
+@exceptions_handler(Exception)
+def print_spc_sp_opus_info(indent: int, auth: lief.PE.SpcSpOpusInfo):
+    if len(auth.program_name) > 0 and len(auth.more_info) > 0:
+        print("{} Info: {} {}".format(" " * indent, auth.program_name, auth.more_info))
+    elif len(auth.program_name) > 0 and len(auth.more_info) == 0:
+        print("{} Info: {}".format(" " * indent, auth.program_name))
+    elif len(auth.program_name) == 0 and len(auth.more_info) > 0:
+        print("{} Info: {}".format(" " * indent, auth.more_info))
+    else:
+        print("{} Info: <empty>".format(" " * indent))
+
+@exceptions_handler(Exception)
+def print_generic_type(indent: int, auth: lief.PE.GenericType):
+    print("{} Generic Type {} ({})".format(" " * indent, auth.oid, lief.PE.oid_to_string(auth.oid)))
+
+@exceptions_handler(Exception)
+def print_content_type(indent: int, auth: lief.PE.ContentType):
+    print("{} Content Type OID: {} ({})".format(" " * indent, auth.oid, lief.PE.oid_to_string(auth.oid)))
+
+@exceptions_handler(Exception)
+def print_signing_time(indent: int, auth: lief.PE.PKCS9SigningTime):
+    print("{} Signing Time: {}/{:02}/{:02} - {:02}:{:02}:{:02}".format(" " * indent, *auth.time))
+
+@exceptions_handler(Exception)
+def print_ms_statement_type(indent: int, auth: lief.PE.MsSpcStatementType):
+    print("{} MS Statement type OID: {} ({})".format(" " * indent, auth.oid, lief.PE.oid_to_string(auth.oid)))
+
+@exceptions_handler(Exception)
+def print_pkcs_msg_dg(indent: int, auth: lief.PE.PKCS9MessageDigest):
+    print("{} PKCS9 Message Digest: {}".format(" " * indent, auth.digest.hex()))
+
+@exceptions_handler(Exception)
+def print_crt(indent: int, crt: lief.PE.x509):
+    print("{}  Version            : {:d}".format(" " * indent, crt.version))
+    print("{}  Issuer             : {}".format(" " * indent, crt.issuer))
+    print("{}  Subject            : {}".format(" " * indent, crt.subject))
+    print("{}  Serial Number      : {}".format(" " * indent, crt.serial_number.hex()))
+    print("{}  Signature Algorithm: {}".format(" " * indent, lief.PE.oid_to_string(crt.signature_algorithm)))
+    print("{}  Valid from         : {}/{:02d}/{:02d} - {:02d}:{:02d}:{:02d}".format(" " * indent, *crt.valid_from))
+    print("{}  Valid to           : {}/{:02d}/{:02d} - {:02d}:{:02d}:{:02d}".format(" " * indent, *crt.valid_to))
+    if len(crt.key_usage) > 0:
+        print("{}  Key usage          : {}".format(" " * indent, " - ".join(str(e).split(".")[-1] for e in crt.key_usage)))
+    if len(crt.ext_key_usage) > 0:
+        print("{}  Ext key usage      : {}".format(" " * indent, " - ".join(lief.PE.oid_to_string(e) for e in crt.ext_key_usage)))
+    if crt.rsa_info is not None:
+        rsa_info = crt.rsa_info
+        print("{}  RSA key size       : {}".format(" " * indent, rsa_info.key_size))
+    print("{}  ===========================================".format(" " * indent))
+
+@exceptions_handler(Exception)
+def print_pkcs_counter_sig(indent: int, auth: lief.PE.PKCS9CounterSignature):
+    print("{} PKCS9 counter signature".format(" " * indent))
+    signer = auth.signer
+    print("{}   Version             : {:d}".format(" " * indent, signer.version))
+    print("{}   Serial Number       : {}".format(" " * indent, signer.serial_number.hex()))
+    print("{}   Issuer              : {}".format(" " * indent, signer.issuer))
+    print("{}   Digest Algorithm    : {}".format(" " * indent, signer.digest_algorithm))
+    print("{}   Encryption Algorithm: {}".format(" " * indent, signer.encryption_algorithm))
+    print("{}   Encrypted Digest    : {} ...".format(" " * indent, signer.encrypted_digest.hex()[:20]))
+
+    if len(signer.authenticated_attributes) > 0:
+        print("{}   Authenticated attributes:".format(" " * indent))
+        for auth in signer.authenticated_attributes:
+            print_attr(indent + 4, auth)
+
+    if len(signer.unauthenticated_attributes) > 0:
+        print("{}   Un-Authenticated attributes:".format(" " * indent))
+        for auth in signer.unauthenticated_attributes:
+            print_attr(indent + 4, auth)
+@exceptions_handler(Exception)
+def print_all(sig: lief.PE.Signature, indent: int = 2):
+    ci: lief.PE.ContentInfo = sig.content_info
+    print("{}Signature version : {}".format(" " * indent, sig.version))
+    print("{}Digest Algorithm  : {!s}".format(" " * indent, sig.digest_algorithm))
+    print("{}Content Info:".format(" " * indent))
+    print("{}  Content Type    : {!s} ({})".format(" " * indent, ci.content_type, lief.PE.oid_to_string(ci.content_type)))
+    print("{}  Digest Algorithm: {!s}".format(" " * indent, ci.digest_algorithm))
+    print("{}  Digest          : {!s}".format(" " * indent, ci.digest.hex()))
+    print("{}Certificates".format(" " * indent))
+    for crt in sig.certificates:
+        print_crt(indent, crt)
+    print("{}Signer(s)".format(" " * indent))
+    for signer in sig.signers:
+        print("{}  Version             : {:d}".format(" " * indent, signer.version))
+        print("{}  Serial Number       : {}".format(" " * indent, signer.serial_number.hex()))
+        print("{}  Issuer              : {}".format(" " * indent, signer.issuer))
+        print("{}  Digest Algorithm    : {}".format(" " * indent, signer.digest_algorithm))
+        print("{}  Encryption Algorithm: {}".format(" " * indent, signer.encryption_algorithm))
+        print("{}  Encrypted Digest    : {} ...".format(" " * indent, signer.encrypted_digest.hex()[:20]))
+        if len(signer.authenticated_attributes) > 0:
+            print("{}  Authenticated attributes:".format(" " * indent))
+            for auth in signer.authenticated_attributes:
+                print_attr(indent + 4, auth)
+
+        if len(signer.unauthenticated_attributes) > 0:
+            print("{}  Un-authenticated attributes:".format(" " * indent))
+            for auth in signer.unauthenticated_attributes:
+                print_attr(indent + 4, auth)
+
+
+@exceptions_handler(Exception)
+def show_crts(sig: lief.PE.Signature, args):
+    for crt in sig.certificates:
+        print_crt(0, crt)
+
+@exceptions_handler(Exception)
+def process_signature(sig: lief.PE.Signature, args):
+    if args.show_all:
+        print_all(sig)
+
+    if args.show_crt:
+        show_crts(sig, args)
+
+    if args.show_hash:
+        print("Authentihash: {}".format(sig.content_info.digest.hex()))
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("file")
+
+    parser.add_argument('-a', '--all',
+            action='store_true', dest='show_all',
+            help='Show all information')
+
+    parser.add_argument('-c', '--crt',
+            action='store_true', dest='show_crt',
+            help='Show embedded x509 certificates')
+
+    parser.add_argument('-H', '--hash',
+            action='store_true', dest='show_hash',
+            help='Show the autentihash value')
+
+    parser.add_argument('-C', '--check',
+            action='store_true', dest='check_sig',
+            help='Check the signature')
+
+    parser.add_argument('-D', '--allow-expired',
+            action='store_true', dest='allow_expired',
+            help='Allow expired certificates')
+
+    parser.add_argument('-s', '--save',
+            dest='ext_file_path',
+            help='Extract and save the PKCS #7')
+
+
+    # Logging setup
+    logger_group = parser.add_argument_group('Logger')
+    verbosity = logger_group.add_mutually_exclusive_group()
+
+    verbosity.add_argument('--debug',
+            dest='main_verbosity',
+            action='store_const',
+            const=lief.logging.LOGGING_LEVEL.DEBUG)
+
+    verbosity.add_argument('--trace',
+            dest='main_verbosity',
+            action='store_const',
+            const=lief.logging.LOGGING_LEVEL.TRACE)
+
+    verbosity.add_argument('--info',
+            dest='main_verbosity',
+            action='store_const',
+            const=lief.logging.LOGGING_LEVEL.INFO)
+
+    verbosity.add_argument('--warn',
+            dest='main_verbosity',
+            action='store_const',
+            const=lief.logging.LOGGING_LEVEL.WARNING)
+
+    verbosity.add_argument('--err',
+            dest='main_verbosity',
+            action='store_const',
+            const=lief.logging.LOGGING_LEVEL.ERROR)
+
+    verbosity.add_argument('--critical',
+            dest='main_verbosity',
+            action='store_const',
+            const=lief.logging.LOGGING_LEVEL.CRITICAL)
+
+    parser.set_defaults(main_verbosity=lief.logging.LOGGING_LEVEL.WARNING)
+
+    args = parser.parse_args()
+    lief.logging.set_level(args.main_verbosity)
+
+    if lief.PE.is_pe(args.file):
+        binary = None
+        try:
+            binary: lief.PE.Binary = lief.PE.parse(args.file)
+            if binary is None:
+                print("Error while parsing {}".format(args.file))
+                sys.exit(1)
+        except lief.exception as e:
+            print(e)
+            sys.exit(1)
+
+        if args.check_sig:
+            flags = lief.PE.Signature.VERIFICATION_CHECKS.DEFAULT
+            if args.allow_expired:
+                flags = lief.PE.Signature.VERIFICATION_CHECKS.SKIP_CERT_TIME
+            res = binary.verify_signature(flags)
+            print(res)
+
+        if args.show_hash:
+            print("Binary MD5     authentihash: {}".format(binary.authentihash_md5.hex()))
+            print("Binary SHA-1   authentihash: {}".format(binary.authentihash_sha1.hex()))
+            print("Binary SHA-256 authentihash: {}".format(binary.authentihash_sha256.hex()))
+
+        for idx, sig in enumerate(binary.signatures):
+            process_signature(sig, args)
+            if args.ext_file_path:
+                path = args.ext_file_path
+                if idx > 0:
+                    path += str(idx)
+                if not path.endswith(".p7b"):
+                    path += ".p7b"
+                outpath = pathlib.Path(path)
+                outpath.write_bytes(sig.raw_der)
+                print("Signature saved to {}".format(outpath))
+    else:
+        # Try as a regular p7b signature
+        sig = lief.PE.Signature.parse(args.file)
+        if sig is None:
+            print("Fail to parse the signature")
+            sys.exit(1)
+        process_signature(sig, args)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/python/pe_sign/sig_info.py b/examples/python/pe_sign/sig_info.py
deleted file mode 100644
index 87e2992..0000000
--- a/examples/python/pe_sign/sig_info.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-import lief
-import argparse
-import json
-import sys
-from prettyprinter import pprint
-
-def main():
-    parser = argparse.ArgumentParser()
-    parser.add_argument("pe_file")
-
-    # Logging setup
-    logger_group = parser.add_argument_group('Logger')
-    verbosity = logger_group.add_mutually_exclusive_group()
-
-    verbosity.add_argument('--debug',
-            dest='main_verbosity',
-            action='store_const',
-            const=lief.logging.LOGGING_LEVEL.DEBUG)
-
-    verbosity.add_argument('--trace',
-            dest='main_verbosity',
-            action='store_const',
-            const=lief.logging.LOGGING_LEVEL.TRACE)
-
-    verbosity.add_argument('--info',
-            dest='main_verbosity',
-            action='store_const',
-            const=lief.logging.LOGGING_LEVEL.INFO)
-
-    verbosity.add_argument('--warn',
-            dest='main_verbosity',
-            action='store_const',
-            const=lief.logging.LOGGING_LEVEL.WARNING)
-
-    verbosity.add_argument('--err',
-            dest='main_verbosity',
-            action='store_const',
-            const=lief.logging.LOGGING_LEVEL.ERROR)
-
-    verbosity.add_argument('--critical',
-            dest='main_verbosity',
-            action='store_const',
-            const=lief.logging.LOGGING_LEVEL.CRITICAL)
-
-    parser.set_defaults(main_verbosity=lief.logging.LOGGING_LEVEL.WARNING)
-
-    args = parser.parse_args()
-    lief.logging.set_level(args.main_verbosity)
-
-    binary = None
-    try:
-        binary = lief.PE.parse(args.pe_file)
-    except lief.exception as e:
-        print(e)
-        sys.exit(1)
-
-    for sig in binary.signatures:
-        print(sig)
-
-if __name__ == "__main__":
-    main()
diff --git a/include/LIEF/BinaryStream/VectorStream.hpp b/include/LIEF/BinaryStream/VectorStream.hpp
index f2b3bed..80f7b3c 100644
--- a/include/LIEF/BinaryStream/VectorStream.hpp
+++ b/include/LIEF/BinaryStream/VectorStream.hpp
@@ -40,6 +40,14 @@ class VectorStream : public BinaryStream {
   }
 
 
+  inline uint8_t* start() {
+    return this->binary_.data();
+  }
+
+  inline const uint8_t* start() const {
+    return this->binary_.data();
+  }
+
   inline uint8_t* end() {
     return this->binary_.data() + this->binary_.size();
   }
diff --git a/include/LIEF/PE/Binary.hpp b/include/LIEF/PE/Binary.hpp
index 8cc806d..023e277 100644
--- a/include/LIEF/PE/Binary.hpp
+++ b/include/LIEF/PE/Binary.hpp
@@ -145,9 +145,14 @@ class LIEF_API Binary : public LIEF::Binary {
   it_const_signatures signatures(void) const;
 
   //! Verify the binary against the embedded signature(s) (if any)
-  //! Firstly, it checks that the embedded signatures are correct (c.f. Signature::check)
+  //! First, it checks that the embedded signatures are correct (c.f. Signature::check)
   //! and then it checks that the authentihash matches ContentInfo::digest
-  Signature::VERIFICATION_FLAGS verify_signature() const;
+  //!
+  //! One can tweak the verification process with the Signature::VERIFICATION_CHECKS flags
+  //!
+  //! @see LIEF::PE::Signature::check
+  Signature::VERIFICATION_FLAGS verify_signature(
+      Signature::VERIFICATION_CHECKS checks = Signature::VERIFICATION_CHECKS::DEFAULT) const;
 
   //! Verify the binary with the Signature object provided in the first parameter
   //! It can be used to verify a detached signature:
@@ -158,7 +163,8 @@ class LIEF_API Binary : public LIEF::Binary {
   //!   binary->verify_signature(detached.value());
   //! }
   //! \endcode
-  Signature::VERIFICATION_FLAGS verify_signature(const Signature& sig) const;
+  Signature::VERIFICATION_FLAGS verify_signature(const Signature& sig,
+      Signature::VERIFICATION_CHECKS checks = Signature::VERIFICATION_CHECKS::DEFAULT) const;
 
   //! Compute the authentihash according to the algorithm provided in the first
   //! parameter
diff --git a/include/LIEF/PE/signature/Signature.hpp b/include/LIEF/PE/signature/Signature.hpp
index e3237d5..7d11404 100644
--- a/include/LIEF/PE/signature/Signature.hpp
+++ b/include/LIEF/PE/signature/Signature.hpp
@@ -45,7 +45,7 @@ class LIEF_API Signature : public Object {
   static std::vector<uint8_t> hash(const std::vector<uint8_t>& input, ALGORITHMS algo);
 
   public:
-  //! Flags returned by verification fonctions
+  //! Flags returned by verification functions
   enum class VERIFICATION_FLAGS {
     OK = 0,
     INVALID_SIGNER                = 1 << 0,
@@ -58,6 +58,18 @@ class LIEF_API Signature : public Object {
     BAD_DIGEST                    = 1 << 7,
     BAD_SIGNATURE                 = 1 << 8,
     NO_SIGNATURE                  = 1 << 9,
+    CERT_EXPIRED                  = 1 << 10,
+    CERT_FUTURE                   = 1 << 11,
+  };
+
+  //! Flags to tweak the verification process of the signature
+  //!
+  //! See Signature::check and LIEF::PE::Binary::verify_signature
+  enum class VERIFICATION_CHECKS {
+    DEFAULT          = 1 << 0, /**< Default behavior that tries to follow the Microsoft verification process as close as possible */
+    HASH_ONLY        = 1 << 1, /**< Only check that Binary::authentihash matches ContentInfo::digest regardless of the signature's validity */
+    LIFETIME_SIGNING = 1 << 2, /**< Same semantic as [WTD_LIFETIME_SIGNING_FLAG](https://docs.microsoft.com/en-us/windows/win32/api/wintrust/ns-wintrust-wintrust_data#WTD_LIFETIME_SIGNING_FLAG) */
+    SKIP_CERT_TIME   = 1 << 3, /**< Skip the verification of the certificates time validities so that even though a certificate expired, it returns VERIFICATION_FLAGS::OK */
   };
 
   Signature(void);
@@ -86,10 +98,25 @@ class LIEF_API Signature : public Object {
   //! Return the raw original PKCS7 signature
   const std::vector<uint8_t>& raw_der(void) const;
 
-  virtual void accept(Visitor& visitor) const override;
+  //! Find x509 certificate according to its serial number
+  const x509* find_crt(const std::vector<uint8_t>& serialno) const;
+
+  //! Find x509 certificate according to its subject
+  const x509* find_crt_subject(const std::string& subject) const;
+
+  //! Find x509 certificate according to its subject **AND** serial number
+  const x509* find_crt_subject(const std::string& subject, const std::vector<uint8_t>& serialno) const;
+
+  //! Find x509 certificate according to its issuer
+  const x509* find_crt_issuer(const std::string& issuer) const;
+
+  //! Find x509 certificate according to its issuer **AND** serial number
+  const x509* find_crt_issuer(const std::string& issuer, const std::vector<uint8_t>& serialno) const;
 
   //! Check if this signature is valid according to the Authenticode/PKCS #7 verification scheme
   //!
+  //! By default, it performs the following verifications:
+  //!
   //! 1. It must contain only **one** signer info
   //! 2. Signature::digest_algorithm must match:
   //!    * ContentInfo::digest_algorithm
@@ -99,16 +126,22 @@ class LIEF_API Signature : public Object {
   //! 4. Given the x509 certificate, compare SignerInfo::encrypted_digest against either:
   //!    * hash of authenticated attributes if present
   //!    * hash of ContentInfo
-  //! 5. If they are Authenticated attributes, check that a PKCS9_MESSAGE_DIGEST attribute exists
+  //! 5. If authenticated attributes are present, check that a PKCS9_MESSAGE_DIGEST attribute exists
   //!    and that its value matches hash of ContentInfo
-  VERIFICATION_FLAGS check() const;
+  //! 6. Check the validity of the PKCS #9 counter signature if present
+  //! 7. If the signature doesn't embed a signing-time in the counter signature, check the certificate
+  //!    validity. (See LIEF::PE::Signature::VERIFICATION_CHECKS::LIFETIME_SIGNING and LIEF::PE::Signature::VERIFICATION_CHECKS::SKIP_CERT_TIME)
+  //!
+  //! See: LIEF::PE::Signature::VERIFICATION_CHECKS to tweak the behavior
+  VERIFICATION_FLAGS check(VERIFICATION_CHECKS checks = VERIFICATION_CHECKS::DEFAULT) const;
+
+  virtual void accept(Visitor& visitor) const override;
 
   virtual ~Signature(void);
 
   LIEF_API friend std::ostream& operator<<(std::ostream& os, const Signature& signature);
 
   private:
-
   uint32_t                version_ = 0;
   ALGORITHMS              digest_algorithm_ = ALGORITHMS::UNKNOWN;
   ContentInfo             content_info_;
@@ -118,9 +151,6 @@ class LIEF_API Signature : public Object {
   uint64_t                content_info_start_ = 0;
   uint64_t                content_info_end_ = 0;
 
-  uint64_t                auth_start_ = 0;
-  uint64_t                auth_end_ = 0;
-
   std::vector<uint8_t> original_raw_signature_;
 };
 
@@ -129,6 +159,7 @@ class LIEF_API Signature : public Object {
 }
 
 ENABLE_BITMASK_OPERATORS(LIEF::PE::Signature::VERIFICATION_FLAGS);
+ENABLE_BITMASK_OPERATORS(LIEF::PE::Signature::VERIFICATION_CHECKS);
 
 
 #endif
diff --git a/include/LIEF/PE/signature/SignatureParser.hpp b/include/LIEF/PE/signature/SignatureParser.hpp
index 0511fb0..9a6c43c 100644
--- a/include/LIEF/PE/signature/SignatureParser.hpp
+++ b/include/LIEF/PE/signature/SignatureParser.hpp
@@ -68,7 +68,7 @@ class LIEF_API SignatureParser {
 
   result<ContentInfo> parse_content_info(VectorStream& stream, range_t& range);
   result<x509_certificates_t> parse_certificates(VectorStream& stream);
-  result<signer_infos_t> parse_signer_infos(VectorStream& stream, range_t& auth_attr);
+  result<signer_infos_t> parse_signer_infos(VectorStream& stream);
   result<attributes_t> parse_attributes(VectorStream& stream);
   result<std::unique_ptr<Attribute>> parse_content_type(VectorStream& stream);
 
diff --git a/include/LIEF/PE/signature/SignerInfo.hpp b/include/LIEF/PE/signature/SignerInfo.hpp
index 82a25c2..7eac60f 100644
--- a/include/LIEF/PE/signature/SignerInfo.hpp
+++ b/include/LIEF/PE/signature/SignerInfo.hpp
@@ -27,6 +27,7 @@
 namespace LIEF {
 namespace PE {
 
+class Signature;
 class Attribute;
 class Parser;
 class SignatureParser;
@@ -52,6 +53,7 @@ class LIEF_API SignerInfo : public Object {
 
   friend class Parser;
   friend class SignatureParser;
+  friend class Signature;
 
   public:
   using encrypted_digest_t = std::vector<uint8_t>;
@@ -110,6 +112,18 @@ class LIEF_API SignerInfo : public Object {
   //! found, it returns a nullptr.
   const Attribute* get_attribute(PE::SIG_ATTRIBUTE_TYPES type) const;
 
+  //! Return the authenticated attribute matching the given PE::SIG_ATTRIBUTE_TYPES.
+  //!
+  //! It returns **the first** entry that matches the given type. If it can't be
+  //! found, it returns a nullptr.
+  const Attribute* get_auth_attribute(PE::SIG_ATTRIBUTE_TYPES type) const;
+
+  //! Return the un-authenticated attribute matching the given PE::SIG_ATTRIBUTE_TYPES.
+  //!
+  //! It returns **the first** entry that matches the given type. If it can't be
+  //! found, it returns a nullptr.
+  const Attribute* get_unauth_attribute(PE::SIG_ATTRIBUTE_TYPES type) const;
+
   //! x509 certificate used by this signer. If it can't be found, it returns a nullptr
   inline const x509* cert() const {
     return this->cert_.get();
@@ -120,6 +134,11 @@ class LIEF_API SignerInfo : public Object {
     return this->cert_.get();
   }
 
+  //! Raw blob that is signed by the signer certificate
+  const std::vector<uint8_t> raw_auth_data() const {
+    return this->raw_auth_data_;
+  }
+
   virtual void accept(Visitor& visitor) const override;
 
   virtual ~SignerInfo(void);
@@ -127,7 +146,7 @@ class LIEF_API SignerInfo : public Object {
   LIEF_API friend std::ostream& operator<<(std::ostream& os, const SignerInfo& signer_info);
 
   private:
-  uint32_t version_;
+  uint32_t version_ = 0;
   std::string issuer_;
   std::vector<uint8_t> serialno_;
 
@@ -135,11 +154,13 @@ class LIEF_API SignerInfo : public Object {
   ALGORITHMS digest_enc_algorithm_ = ALGORITHMS::UNKNOWN;
 
   encrypted_digest_t encrypted_digest_;
+
+  std::vector<uint8_t> raw_auth_data_;
+
   std::vector<std::unique_ptr<Attribute>> authenticated_attributes_;
   std::vector<std::unique_ptr<Attribute>> unauthenticated_attributes_;
 
   std::unique_ptr<x509> cert_;
-
 };
 
 }
diff --git a/include/LIEF/PE/signature/attributes/PKCS9CounterSignature.hpp b/include/LIEF/PE/signature/attributes/PKCS9CounterSignature.hpp
index 7a76705..c65e91e 100644
--- a/include/LIEF/PE/signature/attributes/PKCS9CounterSignature.hpp
+++ b/include/LIEF/PE/signature/attributes/PKCS9CounterSignature.hpp
@@ -48,15 +48,15 @@ class LIEF_API PKCS9CounterSignature : public Attribute {
 
   public:
   PKCS9CounterSignature();
-  PKCS9CounterSignature(std::vector<SignerInfo> signers);
+  PKCS9CounterSignature(SignerInfo signer);
   PKCS9CounterSignature(const PKCS9CounterSignature&);
   PKCS9CounterSignature& operator=(const PKCS9CounterSignature&);
 
   virtual std::unique_ptr<Attribute> clone(void) const override;
 
-  //! Iterator over the SignerInfo as described in the RFC
-  inline it_const_signers_t signers() const {
-    return this->signers_;
+  //! SignerInfo as described in the RFC #2985
+  inline const SignerInfo& signer() const {
+    return this->signer_;
   }
 
   //! Print information about the attribute
@@ -67,7 +67,7 @@ class LIEF_API PKCS9CounterSignature : public Attribute {
   virtual ~PKCS9CounterSignature();
 
   private:
-  std::vector<SignerInfo> signers_;
+  SignerInfo signer_;
 };
 
 }
diff --git a/include/LIEF/PE/signature/x509.hpp b/include/LIEF/PE/signature/x509.hpp
index acca9b1..0a1ee07 100644
--- a/include/LIEF/PE/signature/x509.hpp
+++ b/include/LIEF/PE/signature/x509.hpp
@@ -34,6 +34,7 @@ namespace PE {
 
 class Parser;
 class SignatureParser;
+class Signature;
 
 class RsaInfo;
 
@@ -42,6 +43,7 @@ class LIEF_API x509 : public Object {
 
   friend class Parser;
   friend class SignatureParser;
+  friend class Signature;
 
   public:
   //! Tuple (Year, Month, Day, Hour, Minute, Second)
@@ -55,6 +57,15 @@ class LIEF_API x509 : public Object {
   //! Parse x500 certificate(s) from raw blob
   static certificates_t parse(const std::vector<uint8_t>& content);
 
+  //! Return True if ``before`` is *before* than ``after``. False otherwise
+  static bool check_time(const date_t& before, const date_t& after);
+
+  //! True if the given time is in the **past** according to the clock's system
+  static bool time_is_past(const date_t& to);
+
+  //! True if the given time is in the future according to the clock's system
+  static bool time_is_future(const date_t& from);
+
   //! Public key scheme
   enum class KEY_TYPES  {
     NONE = 0,    ///< Unknown scheme
@@ -93,6 +104,19 @@ class LIEF_API x509 : public Object {
     BADCRL_BAD_KEY         = 1 << 19, /**< The CRL is signed with an unacceptable key (eg bad curve, RSA too short). */
   };
 
+  //! Key usage as defined in [RFC #5280 - section-4.2.1.3](https://tools.ietf.org/html/rfc5280#section-4.2.1.3)
+  enum class KEY_USAGE {
+    DIGITAL_SIGNATURE = 0, /**< The key is used for digital signature */
+    NON_REPUDIATION,       /**< The key is used for digital signature AND to protects against falsely denying some action */
+    KEY_ENCIPHERMENT,      /**< The key is used for enciphering private or secret keys */
+    DATA_ENCIPHERMENT,     /**< The key is used for directly enciphering raw user data without the use of an intermediate symmetric cipher */
+    KEY_AGREEMENT,         /**< The Key is used for key agreement. (e.g. with Diffie-Hellman) */
+    KEY_CERT_SIGN,         /**< The key is used for verifying signatures on public key certificates */
+    CRL_SIGN,              /**< The key is used for verifying signatures on certificate revocation lists */
+    ENCIPHER_ONLY,         /**< In **association with** KEY_AGREEMENT (otherwise the meaning is undefined), the key is only used for enciphering data while performing key agreement */
+    DECIPHER_ONLY,         /**< In **association with** KEY_AGREEMENT (otherwise the meaning is undefined), the key is only used for deciphering data while performing key agreement */
+  };
+
   x509(mbedtls_x509_crt* ca);
   x509(const x509& other);
   x509& operator=(x509 other);
@@ -108,10 +132,10 @@ class LIEF_API x509 : public Object {
   oid_t signature_algorithm(void) const;
 
   //! Start time of certificate validity
-  x509::date_t valid_from(void) const;
+  date_t valid_from(void) const;
 
   //! End time of certificate validity
-  x509::date_t valid_to(void) const;
+  date_t valid_to(void) const;
 
   //! Issuer informations
   std::string issuer(void) const;
@@ -139,6 +163,20 @@ class LIEF_API x509 : public Object {
   //! Verify that this certificate **is trusted** by the given CA list
   VERIFICATION_FLAGS is_trusted_by(const std::vector<x509>& ca) const;
 
+  //! Policy information terms as OID (see RFC #5280)
+  std::vector<oid_t> certificate_policies() const;
+
+  //! Purpose of the key contained in the certificate
+  std::vector<KEY_USAGE> key_usage() const;
+
+  //! Indicates one or more purposes for which the certified public key may be used (OID types)
+  std::vector<oid_t> ext_key_usage() const;
+
+  bool is_ca() const;
+
+  //! The signature of the certificate
+  std::vector<uint8_t> signature() const;
+
   virtual void accept(Visitor& visitor) const override;
 
   virtual ~x509(void);
diff --git a/include/LIEF/enums.hpp b/include/LIEF/enums.hpp
index 52f5e19..3153480 100644
--- a/include/LIEF/enums.hpp
+++ b/include/LIEF/enums.hpp
@@ -67,4 +67,11 @@ operator &=(Enum& lhs, Enum rhs)
     return lhs;
 }
 
+template<typename Enum>
+typename std::enable_if<EnableBitMaskOperators<Enum>::bit_mask_enabled, bool>::type
+is_true(Enum e)
+{
+  using underlying = typename std::underlying_type<Enum>::type;
+  return static_cast<underlying>(e) > 0;
+}
 #endif
diff --git a/src/BinaryStream/VectorStream.cpp b/src/BinaryStream/VectorStream.cpp
index 087490e..2867ac2 100644
--- a/src/BinaryStream/VectorStream.cpp
+++ b/src/BinaryStream/VectorStream.cpp
@@ -253,7 +253,9 @@ result<std::unique_ptr<mbedtls_x509_crt>> VectorStream::asn1_read_cert() {
 
   int ret = mbedtls_x509_crt_parse_der(ca.get(), p, /* buff len */ buff_len);
   if (ret != 0) {
-    LIEF_DEBUG("asn1_read_cert(): {:x}", ret);
+    std::string strerr(1024, 0);
+    mbedtls_strerror(ret, const_cast<char*>(strerr.data()), strerr.size());
+    LIEF_DEBUG("asn1_read_cert(): {}", strerr);
     return make_error_code(lief_errors::read_error);
   }
   if (ca->raw.len <= 0) {
diff --git a/src/PE/Binary.cpp b/src/PE/Binary.cpp
index 37296b8..635bf62 100644
--- a/src/PE/Binary.cpp
+++ b/src/PE/Binary.cpp
@@ -1202,14 +1202,14 @@ std::vector<uint8_t> Binary::authentihash(ALGORITHMS algo) const {
   return hash;
 }
 
-Signature::VERIFICATION_FLAGS Binary::verify_signature() const {
+Signature::VERIFICATION_FLAGS Binary::verify_signature(Signature::VERIFICATION_CHECKS checks) const {
   if (not this->has_signatures()) {
     return Signature::VERIFICATION_FLAGS::NO_SIGNATURE;
   }
 
   for (size_t i = 0; i < this->signatures_.size(); ++i) {
     const Signature& sig = this->signatures_[i];
-    Signature::VERIFICATION_FLAGS flags = this->verify_signature(sig);
+    Signature::VERIFICATION_FLAGS flags = this->verify_signature(sig, checks);
     if (flags != Signature::VERIFICATION_FLAGS::OK) {
       LIEF_INFO("Verification failed for signature #{:d} (0b{:b})", i, static_cast<uintptr_t>(flags));
       return flags;
@@ -1218,11 +1218,13 @@ Signature::VERIFICATION_FLAGS Binary::verify_signature() const {
   return Signature::VERIFICATION_FLAGS::OK;
 }
 
-Signature::VERIFICATION_FLAGS Binary::verify_signature(const Signature& sig) const {
-  const Signature::VERIFICATION_FLAGS value = sig.check();
-  if (value != Signature::VERIFICATION_FLAGS::OK) {
-    LIEF_INFO("Bad signature (0b{:b})", static_cast<uintptr_t>(value));
-    return value;
+Signature::VERIFICATION_FLAGS Binary::verify_signature(const Signature& sig, Signature::VERIFICATION_CHECKS checks) const {
+  if (not is_true(checks & Signature::VERIFICATION_CHECKS::HASH_ONLY)) {
+    const Signature::VERIFICATION_FLAGS value = sig.check(checks);
+    if (value != Signature::VERIFICATION_FLAGS::OK) {
+      LIEF_INFO("Bad signature (0b{:b})", static_cast<uintptr_t>(value));
+      return value;
+    }
   }
 
   // Check that the authentihash matches Content Info's digest
diff --git a/src/PE/hash.cpp b/src/PE/hash.cpp
index 16c8519..9cfd460 100644
--- a/src/PE/hash.cpp
+++ b/src/PE/hash.cpp
@@ -501,8 +501,7 @@ void Hash::visit(const PKCS9AtSequenceNumber& attr) {
 }
 void Hash::visit(const PKCS9CounterSignature& attr) {
   this->visit(*attr.as<Attribute>());
-  it_const_signers_t signers = attr.signers();
-  this->process(std::begin(signers), std::end(signers));
+  this->process(attr.signer());
 }
 void Hash::visit(const PKCS9MessageDigest& attr) {
   this->visit(*attr.as<Attribute>());
diff --git a/src/PE/json.cpp b/src/PE/json.cpp
index 35d2e94..1702055 100644
--- a/src/PE/json.cpp
+++ b/src/PE/json.cpp
@@ -864,13 +864,9 @@ void JsonVisitor::visit(const PKCS9AtSequenceNumber& attr) {
 void JsonVisitor::visit(const PKCS9CounterSignature& attr) {
   this->visit(*attr.as<Attribute>());
 
-  std::vector<json> signers;
-  for (const SignerInfo& signer : attr.signers()) {
-    JsonVisitor visitor;
-    visitor(signer);
-    signers.emplace_back(std::move(visitor.get()));
-  }
-  this->node_["signers"] = std::move(signers);
+  JsonVisitor visitor;
+  visitor(attr.signer());
+  this->node_["signer"] = std::move(visitor.get());
 }
 
 void JsonVisitor::visit(const PKCS9MessageDigest& attr) {
diff --git a/src/PE/signature/Signature.cpp b/src/PE/signature/Signature.cpp
index 0e2e29c..8c7d802 100644
--- a/src/PE/signature/Signature.cpp
+++ b/src/PE/signature/Signature.cpp
@@ -27,6 +27,8 @@
 #include "LIEF/PE/signature/Attribute.hpp"
 #include "LIEF/PE/signature/attributes.hpp"
 
+#include <mbedtls/asn1write.h>
+
 #include <mbedtls/sha512.h>
 #include <mbedtls/sha256.h>
 #include <mbedtls/sha1.h>
@@ -36,11 +38,107 @@
 #include <mbedtls/md5.h>
 
 #include "mbedtls/x509_crt.h"
+#include "mbedtls/x509.h"
 
 
 namespace LIEF {
 namespace PE {
 
+inline std::string time_to_string(const x509::date_t& date) {
+  return fmt::format("{:d}/{:02d}/{:02d} - {:02d}:{:02d}:{:02d}",
+      date[0], date[1], date[2],
+      date[3], date[4], date[5]);
+}
+
+
+Signature::VERIFICATION_FLAGS verify_ts_counter_signature(const SignerInfo& signer,
+    const PKCS9CounterSignature& cs, Signature::VERIFICATION_CHECKS checks) {
+  LIEF_DEBUG("PKCS #9 Counter signature found");
+  Signature::VERIFICATION_FLAGS flags = Signature::VERIFICATION_FLAGS::OK;
+   const SignerInfo& cs_signer = cs.signer();
+  if (cs_signer.cert() == nullptr) {
+    LIEF_WARN("Can't find x509 certificate associated with Counter Signature's signer");
+    return flags | Signature::VERIFICATION_FLAGS::CERT_NOT_FOUND;
+  }
+  const x509& cs_cert = *cs_signer.cert();
+  const SignerInfo::encrypted_digest_t& cs_enc_digest = cs_signer.encrypted_digest();
+
+  std::vector<uint8_t> cs_auth_data = cs_signer.raw_auth_data();
+  // According to the RFC:
+  //
+  // "[...] The Attributes value's tag is SET OF, and the DER encoding of
+  // the SET OF tag, rather than of the IMPLICIT [0] tag [...]"
+  cs_auth_data[0] = /* SET OF */ 0x31;
+  const ALGORITHMS cs_digest_algo = cs_signer.digest_algorithm();
+  const std::vector<uint8_t>& cs_hash = Signature::hash(cs_auth_data, cs_digest_algo);
+  LIEF_DEBUG("Signed data digest: {}", hex_dump(cs_hash));
+  bool check_sig = cs_cert.check_signature(cs_hash, cs_enc_digest, cs_digest_algo);
+
+  if (not check_sig) {
+    LIEF_WARN("Authenticated signature (counter signature) mismatch");
+    //return flags | VERIFICATION_FLAGS::BAD_SIGNATURE;
+  }
+
+
+  /* According to Microsoft documentation:
+   * The Authenticode timestamp SignerInfo structure contains the following authenticated attributes values:
+   * 1. ContentType (1.2.840.113549.1.9.3) is set to PKCS #7 Data (1.2.840.113549.1.7.1).
+   * 2. Signing Time (1.2.840.113549.1.9.5) is set to the UTC time of timestamp generation time.
+   * 3. Message Digest (1.2.840.113549.1.9.4) is set to the hash value of the
+   *    SignerInfo structure's encryptedDigest value. The hash algorithm that
+   *    is used to calculate the hash value is the same as that specified in the
+   *    SignerInfo structure’s digestAlgorithm value of the timestamp.
+   */
+
+  // Verify 1.
+  const auto* content_type_data = reinterpret_cast<const ContentType*>(cs_signer.get_auth_attribute(SIG_ATTRIBUTE_TYPES::CONTENT_TYPE));
+  if (content_type_data == nullptr) {
+    LIEF_WARN("Missing ContentType in authenticated attributes in the counter signature's signer");
+    return flags | Signature::VERIFICATION_FLAGS::INVALID_SIGNER;
+  }
+
+  if (content_type_data->oid() != /* PKCS #7 Data */ "1.2.840.113549.1.7.1") {
+    LIEF_WARN("Bad OID for ContentType in authenticated attributes in the counter signature's signer ({})",
+               content_type_data->oid());
+    return flags | Signature::VERIFICATION_FLAGS::INVALID_SIGNER;
+  }
+
+  // Verify 3.
+  const auto* message_dg = reinterpret_cast<const PKCS9MessageDigest*>(cs_signer.get_auth_attribute(SIG_ATTRIBUTE_TYPES::PKCS9_MESSAGE_DIGEST));
+  if (message_dg == nullptr) {
+    LIEF_WARN("Missing MessageDigest in authenticated attributes in the counter signature's signer");
+    return flags | Signature::VERIFICATION_FLAGS::INVALID_SIGNER;
+  }
+  const std::vector<uint8_t>& dg_value = message_dg->digest();
+  const std::vector<uint8_t> dg_cs_hash = Signature::hash(signer.encrypted_digest(), cs_digest_algo);
+  if (dg_value != dg_cs_hash) {
+    LIEF_WARN("MessageDigest mismatch with Hash(signer ED)");
+    return flags | Signature::VERIFICATION_FLAGS::INVALID_SIGNER;
+  }
+
+  /*
+   * Verify that signing's time is valid within the signer's certificate
+   * validity window.
+   */
+  const auto* signing_time = reinterpret_cast<const PKCS9SigningTime*>(cs_signer.get_auth_attribute(SIG_ATTRIBUTE_TYPES::PKCS9_SIGNING_TIME));
+  if (signing_time != nullptr and not is_true(checks & Signature::VERIFICATION_CHECKS::SKIP_CERT_TIME)) {
+    LIEF_DEBUG("PKCS #9 signing time found");
+    PKCS9SigningTime::time_t time = signing_time->time();
+    if (not x509::check_time(time, cs_cert.valid_to())) {
+      LIEF_WARN("Signing time: {} is above the certificate validity: {}",
+          time_to_string(time), time_to_string(cs_cert.valid_to()));
+      return flags | Signature::VERIFICATION_FLAGS::CERT_EXPIRED;
+    }
+
+    if (not x509::check_time(cs_cert.valid_from(), time)) {
+      LIEF_WARN("Signing time: {} is below the certificate validity: {}",
+          time_to_string(time), time_to_string(cs_cert.valid_to()));
+      return flags | Signature::VERIFICATION_FLAGS::CERT_FUTURE;
+    }
+  }
+  return flags;
+}
+
 
 Signature::Signature(void) = default;
 Signature::Signature(const Signature&) = default;
@@ -153,7 +251,7 @@ it_const_signers_t Signature::signers(void) const {
   return this->signers_;
 }
 
-Signature::VERIFICATION_FLAGS Signature::check() const {
+Signature::VERIFICATION_FLAGS Signature::check(VERIFICATION_CHECKS checks) const {
   // According to the Authenticode documentation,
   // *SignerInfos contains one SignerInfo structure*
   const size_t nb_signers = this->signers_.size();
@@ -197,6 +295,18 @@ Signature::VERIFICATION_FLAGS Signature::check() const {
   const x509& cert = *signer.cert();
   const SignerInfo::encrypted_digest_t& enc_digest = signer.encrypted_digest();
 
+  /*
+   * Check the following condition:
+   *  "The signing certificate must contain either the extended key usage (EKU)
+   *   value for code signing, or the entire certificate chain must contain no
+   *   EKUs. The following is the EKU value for code signing"
+   */
+  //TODO(romain)
+
+  /*
+   * Verify certificate validity
+   */
+
   if (this->content_info_start_ == 0 or this->content_info_end_ == 0) {
     return flags | VERIFICATION_FLAGS::CORRUPTED_CONTENT_INFO;
   }
@@ -208,19 +318,12 @@ Signature::VERIFICATION_FLAGS Signature::check() const {
 
   const std::vector<uint8_t> content_info_hash = Signature::hash(std::move(raw_content_info), digest_algo);
 
-  if (this->auth_start_ == 0 or this->auth_end_ == 0) {
-    flags |= VERIFICATION_FLAGS::CORRUPTED_AUTH_DATA;
-  }
 
   // Copy authenticated attributes
   it_const_attributes_t auth_attrs = signer.authenticated_attributes();
-  if (auth_attrs.size() > 0 and
-      (flags & VERIFICATION_FLAGS::CORRUPTED_AUTH_DATA) != VERIFICATION_FLAGS::CORRUPTED_AUTH_DATA) {
-    std::vector<uint8_t> auth_data = {
-      std::begin(this->original_raw_signature_) + this->auth_start_,
-      std::begin(this->original_raw_signature_) + this->auth_end_
-    };
+  if (auth_attrs.size() > 0) {
 
+    std::vector<uint8_t> auth_data = signer.raw_auth_data_;
     // According to the RFC:
     //
     // "[...] The Attributes value's tag is SET OF, and the DER encoding of
@@ -232,6 +335,7 @@ Signature::VERIFICATION_FLAGS Signature::check() const {
     bool check_sig = cert.check_signature(auth_attr_hash, enc_digest, digest_algo);
 
     if (not check_sig) {
+      LIEF_WARN("Authenticated signature mismatch");
       return flags | VERIFICATION_FLAGS::BAD_SIGNATURE;
     }
 
@@ -242,6 +346,7 @@ Signature::VERIFICATION_FLAGS Signature::check() const {
         });
 
     if (it_pkcs9_digest == std::end(auth_attrs)) {
+      LIEF_WARN("Can't find the authenticated attribute: 'pkcs9-message-digest'");
       return flags | VERIFICATION_FLAGS::MISSING_PKCS9_MESSAGE_DIGEST;
     }
 
@@ -250,14 +355,53 @@ Signature::VERIFICATION_FLAGS Signature::check() const {
     if (digest_attr.digest() != content_info_hash) {
       return flags | VERIFICATION_FLAGS::BAD_DIGEST;
     }
-
-    return flags;
+  } else {
+    /*
+     * If there is no authenticated attributes, then the encrypted digested should match ENC(content_info_hash)
+     */
+    if (not cert.check_signature(content_info_hash, enc_digest, digest_algo)) {
+      return flags | VERIFICATION_FLAGS::BAD_SIGNATURE;
+    }
   }
+
   /*
-   * If there is no authenticated attributes, then encrypted digested should match ENC(content_info_hash)
+   * CounterSignature Checks
    */
-  if (not cert.check_signature(content_info_hash, enc_digest, digest_algo)) {
-    return flags | VERIFICATION_FLAGS::BAD_SIGNATURE;
+  const auto* counter = reinterpret_cast<const PKCS9CounterSignature*>(signer.get_unauth_attribute(SIG_ATTRIBUTE_TYPES::PKCS9_COUNTER_SIGNATURE));
+  bool has_ms_counter_sig = false;
+  for (const Attribute& attr : signer.unauthenticated_attributes()) {
+    if (attr.type() == SIG_ATTRIBUTE_TYPES::GENERIC_TYPE) {
+      if (reinterpret_cast<const GenericType&>(attr).oid() == /* Ms-CounterSign */ "1.3.6.1.4.1.311.3.3.1") {
+        has_ms_counter_sig = true;
+        break;
+      }
+    }
+  }
+  bool timeless_signature = false;
+  if (counter != nullptr) {
+    VERIFICATION_FLAGS cs_flags = verify_ts_counter_signature(signer, *counter, checks);
+    if (cs_flags == VERIFICATION_FLAGS::OK) {
+      timeless_signature = true;
+    }
+  } else if (not timeless_signature and has_ms_counter_sig) {
+    timeless_signature = true;
+  }
+  bool should_check_cert_time = not timeless_signature or is_true(checks & VERIFICATION_CHECKS::LIFETIME_SIGNING);
+  if (is_true(checks & VERIFICATION_CHECKS::SKIP_CERT_TIME)) {
+      should_check_cert_time = false;
+  }
+  if (should_check_cert_time) {
+    /*
+     * Verify certificate validities
+     */
+    if (x509::time_is_past(cert.valid_to())) {
+      return flags | VERIFICATION_FLAGS::CERT_EXPIRED;
+    }
+
+    if (x509::time_is_future(cert.valid_from())) {
+      return flags | VERIFICATION_FLAGS::CERT_FUTURE;
+    }
+
   }
   return flags;
 }
@@ -267,6 +411,63 @@ const std::vector<uint8_t>& Signature::raw_der(void) const {
   return this->original_raw_signature_;
 }
 
+
+const x509* Signature::find_crt(const std::vector<uint8_t>& serialno) const {
+  auto it_cert = std::find_if(std::begin(this->certificates_), std::end(this->certificates_),
+      [&serialno] (const x509& cert) {
+        return cert.serial_number() == serialno;
+      });
+  if (it_cert == std::end(this->certificates_)) {
+    return nullptr;
+  }
+  return &(*it_cert);
+}
+
+
+const x509* Signature::find_crt_subject(const std::string& subject) const {
+  auto it_cert = std::find_if(std::begin(this->certificates_), std::end(this->certificates_),
+      [&subject] (const x509& cert) {
+        return cert.subject() == subject;
+      });
+  if (it_cert == std::end(this->certificates_)) {
+    return nullptr;
+  }
+  return &(*it_cert);
+}
+
+const x509* Signature::find_crt_subject(const std::string& subject, const std::vector<uint8_t>& serialno) const {
+  auto it_cert = std::find_if(std::begin(this->certificates_), std::end(this->certificates_),
+      [&subject, &serialno] (const x509& cert) {
+        return cert.subject() == subject and cert.serial_number() == serialno;
+      });
+  if (it_cert == std::end(this->certificates_)) {
+    return nullptr;
+  }
+  return &(*it_cert);
+}
+
+const x509* Signature::find_crt_issuer(const std::string& issuer) const {
+  auto it_cert = std::find_if(std::begin(this->certificates_), std::end(this->certificates_),
+      [&issuer] (const x509& cert) {
+        return cert.issuer() == issuer;
+      });
+  if (it_cert == std::end(this->certificates_)) {
+    return nullptr;
+  }
+  return &(*it_cert);
+}
+
+const x509* Signature::find_crt_issuer(const std::string& issuer, const std::vector<uint8_t>& serialno) const {
+  auto it_cert = std::find_if(std::begin(this->certificates_), std::end(this->certificates_),
+      [&issuer, &serialno] (const x509& cert) {
+        return cert.issuer() == issuer and cert.serial_number() == serialno;
+      });
+  if (it_cert == std::end(this->certificates_)) {
+    return nullptr;
+  }
+  return &(*it_cert);
+}
+
 void Signature::accept(Visitor& visitor) const {
   visitor.visit(*this);
 }
@@ -342,13 +543,7 @@ inline void print_attr(it_const_attributes_t& attrs, std::ostream& os) {
       case SIG_ATTRIBUTE_TYPES::PKCS9_COUNTER_SIGNATURE:
         {
           const auto& ct = reinterpret_cast<const PKCS9CounterSignature&>(attr);
-          it_const_signers_t signers = ct.signers();
-
-          if (signers.size() > 1 or signers.size() == 0) {
-            suffix = std::to_string(signers.size()) + " signers";
-            break;
-          }
-          const SignerInfo& signer = signers[0];
+          const SignerInfo& signer = ct.signer();
           suffix = signer.issuer();
           break;
         }
diff --git a/src/PE/signature/SignatureParser.cpp b/src/PE/signature/SignatureParser.cpp
index bed1723..fe45ab8 100644
--- a/src/PE/signature/SignatureParser.cpp
+++ b/src/PE/signature/SignatureParser.cpp
@@ -279,11 +279,6 @@ result<Signature> SignatureParser::parse_signature() {
     } else {
       // Makes chain
       std::vector<x509> certs = certificates.value();
-      //mbedtls_x509_crt* next = certs.back().x509_cert_;
-      //for (size_t i = 1; i < certs.size(); ++i) {
-      //  certs[certs.size() - i - 1].x509_cert_->next = next;
-      //  next = certs[certs.size() - i - 1].x509_cert_->next;
-      //}
       signature.certificates_ = std::move(certs);
     }
   }
@@ -304,17 +299,12 @@ result<Signature> SignatureParser::parse_signature() {
   // =========================================================
   tag = this->stream_->asn1_read_tag(MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET);
   if (tag) {
-    const uint64_t current_pos = this->stream_->pos();
     LIEF_DEBUG("Parse pkcs7-signed-data.signer-infos offset: {:d}", this->stream_->pos());
     std::vector<uint8_t> raw_content =
       {this->stream_->p(), this->stream_->p() + tag.value()};
     VectorStream stream{std::move(raw_content)};
     this->stream_->increment_pos(raw_content.size());
-    range_t auth_attr;
-    auto signer_info = this->parse_signer_infos(stream, auth_attr);
-    signature.auth_start_ = current_pos + auth_attr.start;
-    signature.auth_end_   = current_pos + auth_attr.end;
-    LIEF_DEBUG("Authenticated attributes: {} -> {}", signature.auth_start_, signature.auth_end_);
+    auto signer_info = this->parse_signer_infos(stream);
     if (not signer_info) {
       LIEF_INFO("Fail to parse pkcs7-signed-data.signer-infos");
     } else {
@@ -324,15 +314,22 @@ result<Signature> SignatureParser::parse_signature() {
 
   // Tied signer info with x509 certificates
   for (SignerInfo& signer : signature.signers_) {
-    auto it_cert = std::find_if(std::begin(signature.certificates_), std::end(signature.certificates_),
-        [&signer] (const x509& cert) {
-          return cert.issuer() == signer.issuer() and cert.serial_number() == signer.serial_number();
-        });
-    if (it_cert == std::end(signature.certificates_)) {
+    const x509* crt = signature.find_crt_issuer(signer.issuer(), signer.serial_number());
+    if (crt != nullptr) {
+      signer.cert_ = std::unique_ptr<x509>(new x509{*crt});
+    } else {
       LIEF_INFO("Can't find x509 certificate associated with signer '{}'", signer.issuer());
-      continue;
     }
-    signer.cert_ = std::unique_ptr<x509>(new x509{*it_cert});
+    const auto* cs = reinterpret_cast<const PKCS9CounterSignature*>(signer.get_attribute(SIG_ATTRIBUTE_TYPES::PKCS9_COUNTER_SIGNATURE));
+    if (cs != nullptr) {
+      SignerInfo& cs_signer = const_cast<PKCS9CounterSignature*>(cs)->signer_;
+      const x509* crt = signature.find_crt_issuer(cs_signer.issuer(), cs_signer.serial_number());
+      if (crt != nullptr) {
+        cs_signer.cert_ = std::unique_ptr<x509>(new x509{*crt});
+      } else {
+        LIEF_INFO("Can't find x509 certificate associated with signer '{}'", signer.issuer());
+      }
+    }
   }
 
   return signature;
@@ -524,7 +521,7 @@ result<SignatureParser::x509_certificates_t> SignatureParser::parse_certificates
 }
 
 
-result<SignatureParser::signer_infos_t> SignatureParser::parse_signer_infos(VectorStream& stream, range_t& auth_attr) {
+result<SignatureParser::signer_infos_t> SignatureParser::parse_signer_infos(VectorStream& stream) {
   const uintptr_t end_set = stream.size();
 
   signer_infos_t infos;
@@ -621,11 +618,11 @@ result<SignatureParser::signer_infos_t> SignatureParser::parse_signer_infos(Vect
     // Authenticated Attributes
     // =======================================================
     {
-      auth_attr.start = stream.pos();
+      const uint64_t auth_attr_start = stream.pos();
       tag = stream.asn1_read_tag(/* authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL */
                                  MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED);
       if (tag) {
-        auth_attr.end   = stream.pos() + tag.value();
+        const uint64_t auth_attr_end = stream.pos() + tag.value();
         std::vector<uint8_t> raw_authenticated_attributes =
           {stream.p(), stream.p() + tag.value()};
         VectorStream auth_stream(std::move(raw_authenticated_attributes));
@@ -634,10 +631,9 @@ result<SignatureParser::signer_infos_t> SignatureParser::parse_signer_infos(Vect
         if (not authenticated_attributes) {
           LIEF_INFO("Fail to parse pkcs7-signed-data.signer-infos.authenticated-attributes");
         } else {
+          signer.raw_auth_data_ = {stream.start() + auth_attr_start, stream.start() + auth_attr_end};
           signer.authenticated_attributes_ = std::move(authenticated_attributes.value());
         }
-      } else {
-        auth_attr.start = 0;
       }
     }
 
@@ -672,7 +668,7 @@ result<SignatureParser::signer_infos_t> SignatureParser::parse_signer_infos(Vect
             stream.pos());
         return enc_digest.error();
       }
-      LIEF_DEBUG("pkcs7-signed-data.signer-infos.encrypted-digest: {}", hex_dump(enc_digest.value()));
+      LIEF_DEBUG("pkcs7-signed-data.signer-infos.encrypted-digest: {}", hex_dump(enc_digest.value()).substr(0, 10));
       signer.encrypted_digest_ = enc_digest.value();
     }
 
@@ -775,7 +771,14 @@ result<SignatureParser::attributes_t> SignatureParser::parse_attributes(VectorSt
         if (not res) {
           LIEF_INFO("Can't parse pkcs9-counter-sign attribute");
         } else {
-          attributes.emplace_back(new PKCS9CounterSignature(std::move(res.value())));
+          const std::vector<SignerInfo>& signers = res.value();
+          if (signers.size() == 0) {
+            LIEF_INFO("Can't parse signer info associated with the pkcs9-counter-sign");
+          } else if (signers.size() > 1) {
+            LIEF_INFO("More than one signer info associated with the pkcs9-counter-sign");
+          } else {
+            attributes.emplace_back(new PKCS9CounterSignature(std::move(signers.back())));
+          }
         }
       }
 
@@ -916,8 +919,7 @@ result<SignatureParser::signer_infos_t> SignatureParser::parse_pkcs9_counter_sig
   //          ID pkcs-9-at-counterSignature
   //  }
   LIEF_DEBUG("Parsing pkcs9-CounterSign ({} bytes)", stream.size());
-  range_t auth_attr;
-  auto counter_sig = this->parse_signer_infos(stream, auth_attr);
+  auto counter_sig = this->parse_signer_infos(stream);
   if (not counter_sig) {
     LIEF_INFO("Fail to parse pkcs9-counter-signature");
     return counter_sig.error();
@@ -1075,7 +1077,7 @@ result<SignatureParser::time_t> SignatureParser::parse_pkcs9_signing_time(Vector
     return tm.error();
   }
   std::unique_ptr<mbedtls_x509_time> time = std::move(tm.value());
-  LIEF_INFO("pkcs9-signing-time {}/{}/{}", time->day, time->mon, time->year);
+  LIEF_DEBUG("pkcs9-signing-time {}/{}/{}", time->day, time->mon, time->year);
   return SignatureParser::time_t{time->year, time->mon, time->day, time->hour, time->min, time->sec};
 }
 
diff --git a/src/PE/signature/SignerInfo.cpp b/src/PE/signature/SignerInfo.cpp
index bb22656..33c1857 100644
--- a/src/PE/signature/SignerInfo.cpp
+++ b/src/PE/signature/SignerInfo.cpp
@@ -43,7 +43,8 @@ SignerInfo::SignerInfo(const SignerInfo& other) :
   serialno_{other.serialno_},
   digest_algorithm_{other.digest_algorithm_},
   digest_enc_algorithm_{other.digest_enc_algorithm_},
-  encrypted_digest_{other.encrypted_digest_}
+  encrypted_digest_{other.encrypted_digest_},
+  raw_auth_data_{other.raw_auth_data_}
 {
   for (const std::unique_ptr<Attribute>& attr : other.authenticated_attributes_) {
     this->authenticated_attributes_.push_back(attr->clone());
@@ -70,6 +71,7 @@ void SignerInfo::swap(SignerInfo& other) {
   std::swap(this->digest_algorithm_,           other.digest_algorithm_);
   std::swap(this->digest_enc_algorithm_,       other.digest_enc_algorithm_);
   std::swap(this->encrypted_digest_,           other.encrypted_digest_);
+  std::swap(this->raw_auth_data_,              other.raw_auth_data_);
   std::swap(this->authenticated_attributes_,   other.authenticated_attributes_);
   std::swap(this->unauthenticated_attributes_, other.unauthenticated_attributes_);
   std::swap(this->cert_,                       other.cert_);
@@ -110,7 +112,22 @@ it_const_attributes_t SignerInfo::unauthenticated_attributes() const {
 
 
 const Attribute* SignerInfo::get_attribute(PE::SIG_ATTRIBUTE_TYPES type) const {
-  // First look for the attribute in the authenticated ones
+  const Attribute* attr = this->get_auth_attribute(type);
+  if (attr != nullptr) {
+    return attr;
+  }
+
+  attr = this->get_unauth_attribute(type);
+
+  if (attr != nullptr) {
+    return attr;
+  }
+
+  // ... not found -> return nullptr
+  return nullptr;
+}
+
+const Attribute* SignerInfo::get_auth_attribute(PE::SIG_ATTRIBUTE_TYPES type) const {
   auto it_auth = std::find_if(std::begin(this->authenticated_attributes_), std::end(this->authenticated_attributes_),
       [type] (const std::unique_ptr<Attribute>& attr) {
         return attr->type() == type;
@@ -118,8 +135,10 @@ const Attribute* SignerInfo::get_attribute(PE::SIG_ATTRIBUTE_TYPES type) const {
   if (it_auth != std::end(this->authenticated_attributes_)) {
     return it_auth->get();
   }
+  return nullptr;
+}
 
-  // Then in the UN-authenticated ones
+const Attribute* SignerInfo::get_unauth_attribute(PE::SIG_ATTRIBUTE_TYPES type) const {
   auto it_uauth = std::find_if(std::begin(this->unauthenticated_attributes_), std::end(this->unauthenticated_attributes_),
       [type] (const std::unique_ptr<Attribute>& attr) {
         return attr->type() == type;
@@ -127,11 +146,10 @@ const Attribute* SignerInfo::get_attribute(PE::SIG_ATTRIBUTE_TYPES type) const {
   if (it_uauth != std::end(this->unauthenticated_attributes_)) {
     return it_uauth->get();
   }
-
-  // ... not found -> return nullptr
   return nullptr;
 }
 
+
 void SignerInfo::accept(Visitor& visitor) const {
   visitor.visit(*this);
 }
diff --git a/src/PE/signature/attributes/PKCS9CounterSignature.cpp b/src/PE/signature/attributes/PKCS9CounterSignature.cpp
index 0fc29f2..0de78d5 100644
--- a/src/PE/signature/attributes/PKCS9CounterSignature.cpp
+++ b/src/PE/signature/attributes/PKCS9CounterSignature.cpp
@@ -10,27 +10,22 @@ PKCS9CounterSignature::PKCS9CounterSignature() :
 PKCS9CounterSignature::PKCS9CounterSignature(const PKCS9CounterSignature&) = default;
 PKCS9CounterSignature& PKCS9CounterSignature::operator=(const PKCS9CounterSignature&) = default;
 
-PKCS9CounterSignature::PKCS9CounterSignature(std::vector<SignerInfo> signers) :
+PKCS9CounterSignature::PKCS9CounterSignature(SignerInfo signer) :
   Attribute(SIG_ATTRIBUTE_TYPES::PKCS9_COUNTER_SIGNATURE),
-  signers_{std::move(signers)}
+  signer_{std::move(signer)}
 {}
 
 std::unique_ptr<Attribute> PKCS9CounterSignature::clone(void) const {
   return std::unique_ptr<Attribute>(new PKCS9CounterSignature{*this});
 }
 
-
 void PKCS9CounterSignature::accept(Visitor& visitor) const {
   visitor.visit(*this);
 }
 
 std::string PKCS9CounterSignature::print() const {
   std::ostringstream oss;
-  it_const_signers_t signers = this->signers();
-  oss << std::to_string(signers.size()) << " signer(s): \n";
-  for (const SignerInfo& signer : signers) {
-    oss << signer << "\n";
-  }
+  oss << this->signer() << "\n";
   return oss.str();
 }
 
diff --git a/src/PE/signature/x509.cpp b/src/PE/signature/x509.cpp
index 498caff..a86d966 100644
--- a/src/PE/signature/x509.cpp
+++ b/src/PE/signature/x509.cpp
@@ -32,9 +32,50 @@
 #include "LIEF/PE/signature/RsaInfo.hpp"
 #include "LIEF/PE/EnumToString.hpp"
 
+#include "LIEF/utils.hpp"
+
+namespace {
+  // Copy this function from mbedtls sinc it is not exported
+  inline int x509_get_current_time( mbedtls_x509_time *now )
+  {
+      struct tm *lt, tm_buf;
+      mbedtls_time_t tt;
+      int ret = 0;
+
+      tt = mbedtls_time( NULL );
+      lt = mbedtls_platform_gmtime_r( &tt, &tm_buf );
+
+      if( lt == NULL )
+          ret = -1;
+      else
+      {
+          now->year = lt->tm_year + 1900;
+          now->mon  = lt->tm_mon  + 1;
+          now->day  = lt->tm_mday;
+          now->hour = lt->tm_hour;
+          now->min  = lt->tm_min;
+          now->sec  = lt->tm_sec;
+      }
+
+      return( ret );
+  }
+}
+
+
 namespace LIEF {
 namespace PE {
 
+inline x509::date_t from_mbedtls(const mbedtls_x509_time& time) {
+  return {
+    time.year,
+    time.mon,
+    time.day,
+    time.hour,
+    time.min,
+    time.sec
+  };
+}
+
 x509::certificates_t x509::parse(const std::string& path) {
 
   std::ifstream cert_fs(path);
@@ -77,6 +118,106 @@ x509::certificates_t x509::parse(const std::vector<uint8_t>& content) {
   return crts;
 }
 
+
+bool x509::check_time(const date_t& before, const date_t& after) {
+  // Implementation taken
+  // from https://github.com/ARMmbed/mbedtls/blob/1c54b5410fd48d6bcada97e30cac417c5c7eea67/library/x509.c#L926-L962
+  if (before[0] > after[0]) {
+    LIEF_DEBUG("{} > {}", before[0], after[0]);
+    return false;
+  }
+
+  if (
+      before[0] == after[0] and
+      before[1]  > after[1]
+     )
+  {
+    LIEF_DEBUG("{} > {}", before[1], after[1]);
+    return false;
+  }
+
+  if (
+      before[0] == after[0] and
+      before[1] == after[1] and
+      before[2]  > after[2]
+     )
+  {
+    LIEF_DEBUG("{} > {}", before[2], after[2]);
+    return false;
+  }
+
+  if (
+      before[0] == after[0] and
+      before[1] == after[1] and
+      before[2] == after[2] and
+      before[3]  > after[3]
+     )
+  {
+    LIEF_DEBUG("{} > {}", before[3], after[3]);
+    return false;
+  }
+
+  if (
+      before[0] == after[0] and
+      before[1] == after[1] and
+      before[2] == after[2] and
+      before[3] == after[3] and
+      before[4]  > after[4]
+     )
+  {
+    LIEF_DEBUG("{} > {}", before[4], after[4]);
+    return false;
+  }
+
+  if (
+      before[0] == after[0] and
+      before[1] == after[1] and
+      before[2] == after[2] and
+      before[3] == after[3] and
+      before[4] == after[4] and
+      before[5]  > after[5]
+     )
+  {
+    LIEF_DEBUG("{} > {}", before[5], after[5]);
+    return false;
+  }
+
+  if (
+      before[0] == after[0] and
+      before[1] == after[1] and
+      before[2] == after[2] and
+      before[3] == after[3] and
+      before[4] == after[4] and
+      before[5] == after[5] and
+      before[6]  > after[6]
+     )
+  {
+    LIEF_DEBUG("{} > {}", before[6], after[6]);
+    return false;
+  }
+
+  return true;
+}
+
+bool x509::time_is_past(const date_t& to) {
+  mbedtls_x509_time now;
+
+  if (x509_get_current_time(&now) != 0) {
+    return true;
+  }
+  // check_time(): true if now < to else false
+  return not check_time(from_mbedtls(now), to);
+}
+
+bool x509::time_is_future(const date_t& from) {
+  mbedtls_x509_time now;
+
+  if (x509_get_current_time(&now) != 0) {
+    return true;
+  }
+  return check_time(from_mbedtls(now), from);
+}
+
 x509::x509() = default;
 
 x509::x509(mbedtls_x509_crt* ca) :
@@ -119,25 +260,11 @@ oid_t x509::signature_algorithm(void) const {
 }
 
 x509::date_t x509::valid_from(void) const {
-  return {{
-    this->x509_cert_->valid_from.year,
-    this->x509_cert_->valid_from.mon,
-    this->x509_cert_->valid_from.day,
-    this->x509_cert_->valid_from.hour,
-    this->x509_cert_->valid_from.min,
-    this->x509_cert_->valid_from.sec
-  }};
+  return from_mbedtls(this->x509_cert_->valid_from);
 }
 
 x509::date_t x509::valid_to(void) const {
-  return {{
-    this->x509_cert_->valid_to.year,
-    this->x509_cert_->valid_to.mon,
-    this->x509_cert_->valid_to.day,
-    this->x509_cert_->valid_to.hour,
-    this->x509_cert_->valid_to.min,
-    this->x509_cert_->valid_to.sec
-  }};
+  return from_mbedtls(this->x509_cert_->valid_to);
 }
 
 
@@ -206,17 +333,63 @@ bool x509::check_signature(const std::vector<uint8_t>& hash, const std::vector<u
     return false;
   }
   mbedtls_pk_context& ctx = this->x509_cert_->pk;
-
   int ret = mbedtls_pk_verify(&ctx,
     /* MD_HASH_ALGO       */ it_md->second,
     /* Input Hash         */ hash.data(), hash.size(),
     /* Signature provided */ signature.data(), signature.size());
 
+  /* If the verification failed with mbedtls_pk_verify it
+   * does not necessity means that the signatures don't match.
+   *
+   * For RSA public-key scheme, mbedtls encodes the hash with rsa_rsassa_pkcs1_v15_encode() so that it expands
+   * the hash value with encoded data. On some samples, this encoding failed.
+   *
+   * In the approach below, we manually decrypt and unpad the output of the DEC(signature)
+   * as defined in the RFC #2313
+   */
   if (ret != 0) {
-    std::string strerr(1024, 0);
-    mbedtls_strerror(ret, const_cast<char*>(strerr.data()), strerr.size());
-    LIEF_INFO("decrypt() failed with error: '{}'", strerr);
-    return false;
+    if (mbedtls_pk_get_type(&ctx) == MBEDTLS_PK_RSA) {
+      auto* ctx_rsa = reinterpret_cast<mbedtls_rsa_context*>(ctx.pk_ctx);
+      if ((ctx_rsa->len * 8) < 100 or (ctx_rsa->len * 8) > 2048 * 10) {
+        LIEF_INFO("RSA Key length is not valid ({} bits)", ctx_rsa->len * 8);
+        return false;
+      }
+      std::vector<uint8_t> decrypted(ctx_rsa->len);
+
+      int ret_rsa_public = mbedtls_rsa_public(ctx_rsa, signature.data(), decrypted.data());
+      if (ret_rsa_public != 0) {
+        std::string strerr(1024, 0);
+        mbedtls_strerror(ret_rsa_public, const_cast<char*>(strerr.data()), strerr.size());
+        LIEF_INFO("RSA public key operation failed: '{}'", strerr);
+        return false;
+      }
+
+      // Check padding header
+      if (decrypted[0] != 0x00 and decrypted[1] != 0x01 and decrypted[2] != 0xff) {
+        return false;
+      }
+
+      std::vector<uint8_t> unpadded;
+      for (size_t i = 2; i < decrypted.size(); ++i) {
+        if (decrypted[i] == 0) {
+          unpadded = std::vector<uint8_t>(std::begin(decrypted) + i + 1, std::end(decrypted));
+          break;
+        }
+        if (decrypted[i] != 0xFF) {
+          return false;
+        }
+      }
+      if (unpadded == hash) {
+        return true;
+      }
+    }
+    if (ret != 0) {
+      std::string strerr(1024, 0);
+      mbedtls_strerror(ret, const_cast<char*>(strerr.data()), strerr.size());
+      LIEF_INFO("decrypt() failed with error: '{}'", strerr);
+      return false;
+    }
+    return true;
   }
   return true;
 }
@@ -228,6 +401,7 @@ x509::VERIFICATION_FLAGS x509::is_trusted_by(const std::vector<x509>& ca) const
     ca_list[i].x509_cert_->next = ca_list[i + 1].x509_cert_;
   }
 
+  VERIFICATION_FLAGS result = VERIFICATION_FLAGS::OK;
   uint32_t flags = 0;
   mbedtls_x509_crt_profile profile = {
     MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_MD5)   |
@@ -257,17 +431,19 @@ x509::VERIFICATION_FLAGS x509::is_trusted_by(const std::vector<x509>& ca) const
     std::string out(1024, 0);
     mbedtls_x509_crt_verify_info(const_cast<char*>(out.data()), out.size(), "", flags);
     LIEF_WARN("X509 verify failed with: {} (0x{:x})\n{}", strerr, ret, out);
+    result = VERIFICATION_FLAGS::BADCERT_NOT_TRUSTED;
   }
 
   // Clear the chain since ~x509() will delete each object
   for (size_t i = 0; i < ca_list.size(); ++i) {
     ca_list[i].x509_cert_->next = nullptr;
   }
-  return static_cast<VERIFICATION_FLAGS>(flags);
+  return result;
 }
 
 x509::VERIFICATION_FLAGS x509::verify(const x509& ca) const {
   uint32_t flags = 0;
+  VERIFICATION_FLAGS result = VERIFICATION_FLAGS::OK;
   mbedtls_x509_crt_profile profile = {
     MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1)   |
     MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
@@ -295,8 +471,99 @@ x509::VERIFICATION_FLAGS x509::verify(const x509& ca) const {
     std::string out(1024, 0);
     mbedtls_x509_crt_verify_info(const_cast<char*>(out.data()), out.size(), "", flags);
     LIEF_WARN("X509 verify failed with: {} (0x{:x})\n{}", strerr, ret, out);
+    result = VERIFICATION_FLAGS::BADCERT_NOT_TRUSTED;
   }
-  return static_cast<VERIFICATION_FLAGS>(flags);
+  return result;
+}
+
+std::vector<oid_t> x509::ext_key_usage() const {
+  if ((this->x509_cert_->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) == 0) {
+    return {};
+  }
+  mbedtls_asn1_sequence* current = &this->x509_cert_->ext_key_usage;
+  std::vector<oid_t> oids;
+  while (current != nullptr) {
+    char oid_str[256] = {0};
+    int ret = mbedtls_oid_get_numeric_string(oid_str, sizeof(oid_str), &current->buf);
+    if (ret != MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
+      LIEF_DEBUG("OID: {}", oid_str);
+      oids.push_back(oid_str);
+    } else {
+      std::string strerr(1024, 0);
+      mbedtls_strerror(ret, const_cast<char*>(strerr.data()), strerr.size());
+      LIEF_WARN("{}", strerr);
+    }
+    if (current->next == current) {
+      break;
+    }
+    current = current->next;
+  }
+  return oids;
+}
+
+std::vector<oid_t> x509::certificate_policies() const {
+  if ((this->x509_cert_->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES) == 0) {
+    return {};
+  }
+
+  mbedtls_x509_sequence& policies = this->x509_cert_->certificate_policies;
+  mbedtls_asn1_sequence* current = &policies;
+  std::vector<oid_t> oids;
+  while (current != nullptr) {
+    char oid_str[256] = {0};
+    int ret = mbedtls_oid_get_numeric_string(oid_str, sizeof(oid_str), &current->buf);
+    if (ret != MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
+      oids.push_back(oid_str);
+    } else {
+      std::string strerr(1024, 0);
+      mbedtls_strerror(ret, const_cast<char*>(strerr.data()), strerr.size());
+      LIEF_WARN("{}", strerr);
+    }
+    if (current->next == current) {
+      break;
+    }
+    current = current->next;
+  }
+  return oids;
+}
+
+bool x509::is_ca() const {
+  if ((this->x509_cert_->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) == 0) {
+    return true;
+  }
+  return this->x509_cert_->ca_istrue;
+}
+
+std::vector<x509::KEY_USAGE> x509::key_usage() const {
+  static const std::map<uint32_t, KEY_USAGE> MBEDTLS_MAP = {
+    {MBEDTLS_X509_KU_DIGITAL_SIGNATURE, KEY_USAGE::DIGITAL_SIGNATURE},
+    {MBEDTLS_X509_KU_NON_REPUDIATION,   KEY_USAGE::NON_REPUDIATION},
+    {MBEDTLS_X509_KU_KEY_ENCIPHERMENT,  KEY_USAGE::KEY_ENCIPHERMENT},
+    {MBEDTLS_X509_KU_DATA_ENCIPHERMENT, KEY_USAGE::DATA_ENCIPHERMENT},
+    {MBEDTLS_X509_KU_KEY_AGREEMENT,     KEY_USAGE::KEY_AGREEMENT},
+    {MBEDTLS_X509_KU_KEY_CERT_SIGN,     KEY_USAGE::KEY_CERT_SIGN},
+    {MBEDTLS_X509_KU_CRL_SIGN,          KEY_USAGE::CRL_SIGN},
+    {MBEDTLS_X509_KU_ENCIPHER_ONLY,     KEY_USAGE::ENCIPHER_ONLY},
+    {MBEDTLS_X509_KU_DECIPHER_ONLY,     KEY_USAGE::DECIPHER_ONLY},
+  };
+
+  if ((this->x509_cert_->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) == 0) {
+    return {};
+  }
+
+  const uint32_t ku = this->x509_cert_->key_usage;
+  std::vector<KEY_USAGE> usages;
+  for (const auto& p : MBEDTLS_MAP) {
+    if ((ku & p.first) > 0) {
+      usages.push_back(p.second);
+    }
+  }
+  return usages;
+}
+
+std::vector<uint8_t> x509::signature() const {
+  mbedtls_x509_buf sig =  this->x509_cert_->sig;
+  return {sig.p, sig.p + sig.len};
 }
 
 void x509::accept(Visitor& visitor) const {
diff --git a/tests/pe/test_authenticode.py b/tests/pe/test_authenticode.py
index e4ab66e..678bf7d 100644
--- a/tests/pe/test_authenticode.py
+++ b/tests/pe/test_authenticode.py
@@ -14,7 +14,7 @@ from unittest import TestCase
 import lief
 from utils import get_sample
 
-lief.logging.set_level(lief.logging.LOGGING_LEVEL.INFO)
+lief.logging.set_level(lief.logging.LOGGING_LEVEL.WARNING)
 
 def from_hex(x):
     return bytes.fromhex(x.replace(":", ""))
@@ -180,8 +180,7 @@ class TestAuthenticode(TestCase):
         sig = lief.PE.Signature.parse(get_sample("pkcs7/cert10.p7b"))
         counter_sign = sig.signers[0].get_attribute(lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_COUNTER_SIGNATURE)
 
-        self.assertEqual(len(counter_sign.signers), 1)
-        signer = counter_sign.signers[0]
+        signer = counter_sign.signer
 
         self.assertEqual(signer.version, 1)
         self.assertEqual(signer.serial_number, from_hex("0e:cf:f4:38:c8:fe:bf:35:6e:04:d8:6a:98:1b:1a:50"))