diff --git a/CMakeLists.txt b/CMakeLists.txt index dce1bde..10502ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,6 +334,16 @@ 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) +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/utfcpp/utf8.h + COMMAND + ${CMAKE_COMMAND} -E copy_directory ${UTFCPP_INCLUDE_DIR}/ + ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/utfcpp + DEPENDS lief_utfcpp) + +target_sources(LIB_LIEF PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/utfcpp/utf8.h) + + add_dependencies(LIB_LIEF lief_spdlog lief_mbed_tls) # Flags definition diff --git a/api/python/CMakeLists.txt b/api/python/CMakeLists.txt index ddbbb0e..9ee8da4 100644 --- a/api/python/CMakeLists.txt +++ b/api/python/CMakeLists.txt @@ -25,8 +25,8 @@ message(STATUS "Python lib: ${PYTHON_LIBRARY}") message(STATUS "Python include: ${PYTHON_INCLUDE_DIR}") message(STATUS "Python interpreter: ${PYTHON_EXECUTABLE}") -set(PYBIND11_VERSION 2.6.0) -set(PYBIND11_SHA256 SHA256=c2ed3fc84db08f40a36ce1d03331624ed6977497b35dfed36a1423396928559a) +set(PYBIND11_VERSION 2.6.1) +set(PYBIND11_SHA256 SHA256=e3f9408fca4e8ebf2d22229d5256adb49098073832aad87f3f6078d91a6942b2) set(PYBIND11_URL "${THIRD_PARTY_DIRECTORY}/pybind11-${PYBIND11_VERSION}.zip" CACHE STRING "URL to the Pybind11 repo") ExternalProject_Add(lief_pybind11 URL ${PYBIND11_URL} diff --git a/api/python/PE/objects/pySection.cpp b/api/python/PE/objects/pySection.cpp index 3deefee..c82b7b6 100644 --- a/api/python/PE/objects/pySection.cpp +++ b/api/python/PE/objects/pySection.cpp @@ -110,6 +110,13 @@ void create
(py::module& m) { "``True`` if the a section has the given " RST_CLASS_REF(lief.PE.SECTION_CHARACTERISTICS) "", "characteristic"_a) + .def_property_readonly("padding", + [] (const Section& sec) { + const std::vector& data = sec.padding(); + return py::bytes(reinterpret_cast(data.data()), data.size()); + }, + "Section padding content as bytes") + .def("__eq__", &Section::operator==) .def("__ne__", &Section::operator!=) .def("__hash__", diff --git a/api/python/PE/objects/signature/CMakeLists.txt b/api/python/PE/objects/signature/CMakeLists.txt index 48c5923..1ff2c0e 100644 --- a/api/python/PE/objects/signature/CMakeLists.txt +++ b/api/python/PE/objects/signature/CMakeLists.txt @@ -1,6 +1,7 @@ set(LIEF_PYTHON_PE_SIG_SRC "${CMAKE_CURRENT_LIST_DIR}/pySignerInfo.cpp" "${CMAKE_CURRENT_LIST_DIR}/pyAttribute.cpp" + "${CMAKE_CURRENT_LIST_DIR}/pyRsaInfo.cpp" "${CMAKE_CURRENT_LIST_DIR}/pyx509.cpp" "${CMAKE_CURRENT_LIST_DIR}/pyContentInfo.cpp" "${CMAKE_CURRENT_LIST_DIR}/pySignature.cpp" diff --git a/api/python/PE/objects/signature/attributes/pyContentType.cpp b/api/python/PE/objects/signature/attributes/pyContentType.cpp index 6937768..cc12136 100644 --- a/api/python/PE/objects/signature/attributes/pyContentType.cpp +++ b/api/python/PE/objects/signature/attributes/pyContentType.cpp @@ -34,9 +34,19 @@ using setter_t = void (ContentType::*)(T); template<> void create(py::module& m) { - py::class_(m, "ContentType") + py::class_(m, "ContentType", + R"delim( + Interface over the structure described by the OID ``1.2.840.113549.1.9.3`` (PKCS #9) + The internal structure is described in the: + `RFC #2985: PKCS #9 - Selected Object Classes and Attribute Types Version 2.0 `_ + + .. code-block:: text + + ContentType ::= OBJECT IDENTIFIER + + )delim") .def_property_readonly("oid", - &ContentType::oid) + &ContentType::oid, "OID as described in RFC #2985 (string object)") .def("__hash__", [] (const ContentType& obj) { diff --git a/api/python/PE/objects/signature/attributes/pyGenericType.cpp b/api/python/PE/objects/signature/attributes/pyGenericType.cpp index 5d10570..df0dcec 100644 --- a/api/python/PE/objects/signature/attributes/pyGenericType.cpp +++ b/api/python/PE/objects/signature/attributes/pyGenericType.cpp @@ -34,12 +34,20 @@ using setter_t = void (GenericType::*)(T); template<> void create(py::module& m) { - py::class_(m, "GenericType") + py::class_(m, "GenericType", + R"delim( + Interface over an attribute whose the internal structure is not supported by LIEF + )delim") .def_property_readonly("oid", - &GenericType::oid) + &GenericType::oid, + "OID of the original attribute") .def_property_readonly("raw_content", - &GenericType::raw_content) + [] (const GenericType& type) -> py::bytes { + const std::vector& raw = type.raw_content(); + return py::bytes(reinterpret_cast(raw.data()), raw.size()); + }, + "Original DER blob of the attribute") .def("__hash__", [] (const GenericType& obj) { diff --git a/api/python/PE/objects/signature/attributes/pyMsSpcNestedSignature.cpp b/api/python/PE/objects/signature/attributes/pyMsSpcNestedSignature.cpp index 17acd53..67633fa 100644 --- a/api/python/PE/objects/signature/attributes/pyMsSpcNestedSignature.cpp +++ b/api/python/PE/objects/signature/attributes/pyMsSpcNestedSignature.cpp @@ -34,9 +34,21 @@ using setter_t = void (MsSpcNestedSignature::*)(T); template<> void create(py::module& m) { - py::class_(m, "MsSpcNestedSignature") + py::class_(m, "MsSpcNestedSignature", + R"delim( + Interface over the structure described by the OID ``1.3.6.1.4.1.311.2.4.1`` + + The internal structure is not documented but we can infer the following structure: + + .. code-block:: text + + MsSpcNestedSignature ::= SET OF SignedData + + With ``SignedData``, the structure described in PKCS #7 RFC (See: :class:`lief.PE.Signature`) + )delim") .def_property_readonly("signature", &MsSpcNestedSignature::sig, + "Underlying " RST_CLASS_REF(lief.PE.Signature) " object", py::return_value_policy::reference) .def("__hash__", diff --git a/api/python/PE/objects/signature/attributes/pyMsSpcStatementType.cpp b/api/python/PE/objects/signature/attributes/pyMsSpcStatementType.cpp index 1602f14..c6ac5d1 100644 --- a/api/python/PE/objects/signature/attributes/pyMsSpcStatementType.cpp +++ b/api/python/PE/objects/signature/attributes/pyMsSpcStatementType.cpp @@ -34,9 +34,30 @@ using setter_t = void (MsSpcStatementType::*)(T); template<> void create(py::module& m) { - py::class_(m, "MsSpcStatementType") + py::class_(m, "MsSpcStatementType", + R"delim( + Interface over the structure described by the OID ``1.3.6.1.4.1.311.2.1.11`` + + The internal structure is described in the official document: + `Windows Authenticode Portable Executable Signature Format `_ + + .. code-block:: text + + SpcStatementType ::= SEQUENCE of OBJECT IDENTIFIER + + )delim") + .def_property_readonly("oid", - &MsSpcStatementType::oid) + &MsSpcStatementType::oid, + R"delim( + According to the documentation: + + :: + + The SpcStatementType MUST contain one Object Identifier with either + the value ``1.3.6.1.4.1.311.2.1.21 (SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID)`` or + ``1.3.6.1.4.1.311.2.1.22 (SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID)``. + )delim") .def("__hash__", [] (const MsSpcStatementType& obj) { diff --git a/api/python/PE/objects/signature/attributes/pyPKCS9AtSequenceNumber.cpp b/api/python/PE/objects/signature/attributes/pyPKCS9AtSequenceNumber.cpp index 059d939..bb7e2cc 100644 --- a/api/python/PE/objects/signature/attributes/pyPKCS9AtSequenceNumber.cpp +++ b/api/python/PE/objects/signature/attributes/pyPKCS9AtSequenceNumber.cpp @@ -34,9 +34,29 @@ using setter_t = void (PKCS9AtSequenceNumber::*)(T); template<> void create(py::module& m) { - py::class_(m, "PKCS9AtSequenceNumber") + py::class_(m, "PKCS9AtSequenceNumber", + R"delim( + Interface over the structure described by the OID ``1.2.840.113549.1.9.25.4`` (PKCS #9) + + The internal structure is described in the + `RFC #2985: PKCS #9 - Selected Object Classes and Attribute Types Version 2.0 `_ + + .. code-block:: text + + sequenceNumber ATTRIBUTE ::= { + WITH SYNTAX SequenceNumber + EQUALITY MATCHING RULE integerMat + SINGLE VALUE TRUE + ID pkcs-9-at-sequenceNumber + } + + SequenceNumber ::= INTEGER (1..MAX) + + )delim") + .def_property_readonly("number", - &PKCS9AtSequenceNumber::number) + &PKCS9AtSequenceNumber::number, + "Number as described in the RFC") .def("__hash__", [] (const PKCS9AtSequenceNumber& obj) { diff --git a/api/python/PE/objects/signature/attributes/pyPKCS9CounterSignature.cpp b/api/python/PE/objects/signature/attributes/pyPKCS9CounterSignature.cpp index fe9a2db..d43612c 100644 --- a/api/python/PE/objects/signature/attributes/pyPKCS9CounterSignature.cpp +++ b/api/python/PE/objects/signature/attributes/pyPKCS9CounterSignature.cpp @@ -34,9 +34,24 @@ using setter_t = void (PKCS9CounterSignature::*)(T); template<> void create(py::module& m) { - py::class_(m, "PKCS9CounterSignature") + py::class_(m, "PKCS9CounterSignature", + R"delim( + Interface over the structure described by the OID ``1.2.840.113549.1.9.6`` (PKCS #9) + + The internal structure is described in the + `RFC #2985: PKCS #9 - Selected Object Classes and Attribute Types Version 2.0 `_ + + .. code-block:: text + + counterSignature ATTRIBUTE ::= { + WITH SYNTAX SignerInfo + ID pkcs-9-at-counterSignature + } + + )delim") .def_property_readonly("signers", - &PKCS9CounterSignature::signers) + &PKCS9CounterSignature::signers, + "Iterator over the " RST_CLASS_REF(lief.PE.SignerInfo) " as described in the RFC") .def("__hash__", [] (const PKCS9CounterSignature& obj) { diff --git a/api/python/PE/objects/signature/attributes/pyPKCS9MessageDigest.cpp b/api/python/PE/objects/signature/attributes/pyPKCS9MessageDigest.cpp index 2afdbb5..35731ce 100644 --- a/api/python/PE/objects/signature/attributes/pyPKCS9MessageDigest.cpp +++ b/api/python/PE/objects/signature/attributes/pyPKCS9MessageDigest.cpp @@ -34,19 +34,38 @@ using setter_t = void (PKCS9MessageDigest::*)(T); template<> void create(py::module& m) { - py::class_(m, "PKCS9MessageDigest") + py::class_(m, "PKCS9MessageDigest", + R"delim( + Interface over the structure described by the OID ``1.2.840.113549.1.9.4`` (PKCS #9) + + The internal structure is described in the + `RFC #2985: PKCS #9 - Selected Object Classes and Attribute Types Version 2.0 `_ + + .. code-block:: text + + messageDigest ATTRIBUTE ::= { + WITH SYNTAX MessageDigest + EQUALITY MATCHING RULE octet + SINGLE VALUE TRUE + ID pkcs-9-at-messageDigest + } + + MessageDigest ::= OCTET STRING + + )delim") + .def_property_readonly("digest", [] (const PKCS9MessageDigest& digest) -> py::object { const std::vector& data = digest.digest(); return py::bytes(reinterpret_cast(data.data()), data.size()); - }) + }, + "Message digeset as a blob of bytes as described in the RFC") .def("__hash__", [] (const PKCS9MessageDigest& obj) { return Hash::hash(obj); }) - .def("__str__", &PKCS9MessageDigest::print); } diff --git a/api/python/PE/objects/signature/attributes/pyPKCS9SigningTime.cpp b/api/python/PE/objects/signature/attributes/pyPKCS9SigningTime.cpp index c8e7c06..2cbce51 100644 --- a/api/python/PE/objects/signature/attributes/pyPKCS9SigningTime.cpp +++ b/api/python/PE/objects/signature/attributes/pyPKCS9SigningTime.cpp @@ -34,9 +34,29 @@ using setter_t = void (PKCS9SigningTime::*)(T); template<> void create(py::module& m) { - py::class_(m, "PKCS9SigningTime") + py::class_(m, "PKCS9SigningTime", + R"delim( + Interface over the structure described by the OID ``1.2.840.113549.1.9.5`` (PKCS #9) + + The internal structure is described in the + `RFC #2985: PKCS #9 - Selected Object Classes and Attribute Types Version 2.0 `_ + + .. code-block:: text + + signingTime ATTRIBUTE ::= { + WITH SYNTAX SigningTime + EQUALITY MATCHING RULE signingTimeMatch + SINGLE VALUE TRUE + ID pkcs-9-at-signingTime + } + + SigningTime ::= Time -- imported from ISO/IEC 9594-8 + + )delim") + .def_property_readonly("time", - &PKCS9SigningTime::time) + &PKCS9SigningTime::time, + "Time as a list [year, month, day, hour, min, sec]") .def("__hash__", [] (const PKCS9SigningTime& obj) { diff --git a/api/python/PE/objects/signature/attributes/pySpcSpOpusInfo.cpp b/api/python/PE/objects/signature/attributes/pySpcSpOpusInfo.cpp index 2c3b8b8..946f37f 100644 --- a/api/python/PE/objects/signature/attributes/pySpcSpOpusInfo.cpp +++ b/api/python/PE/objects/signature/attributes/pySpcSpOpusInfo.cpp @@ -34,16 +34,28 @@ using setter_t = void (SpcSpOpusInfo::*)(T); template<> void create(py::module& m) { - py::class_(m, "SpcSpOpusInfo") + py::class_(m, "SpcSpOpusInfo", + R"delim( + Interface over the structure described by the OID ``1.3.6.1.4.1.311.2.1.12`` + The internal structure is described in the official document: `Windows Authenticode Portable Executable Signature Format `_ + + .. code-block:: text + + SpcSpOpusInfo ::= SEQUENCE { + programName [0] EXPLICIT SpcString OPTIONAL, + moreInfo [1] EXPLICIT SpcLink OPTIONAL + } + )delim" + ) .def_property_readonly("program_name", [] (const SpcSpOpusInfo& info) { return safe_string_converter(info.program_name()); - }) + }, "Program description provided by the publisher") .def_property_readonly("more_info", [] (const SpcSpOpusInfo& info) { return safe_string_converter(info.more_info()); - }) + }, "Other information such as an URL") .def("__hash__", [] (const SpcSpOpusInfo& obj) { diff --git a/api/python/PE/objects/signature/pyAttribute.cpp b/api/python/PE/objects/signature/pyAttribute.cpp index 033b219..a1d0875 100644 --- a/api/python/PE/objects/signature/pyAttribute.cpp +++ b/api/python/PE/objects/signature/pyAttribute.cpp @@ -33,17 +33,14 @@ using setter_t = void (Attribute::*)(T); template<> void create(py::module& m) { - py::class_(m, "Attribute") + py::class_(m, "Attribute", "Interface over PKCS #7 attribute") .def_property_readonly("type", - &Attribute::type) - + &Attribute::type, + "Concrete type (" RST_CLASS_REF(lief.PE.SIG_ATTRIBUTE_TYPES) ") of the attribute") .def("__str__", [] (const Attribute& attr) { - std::ostringstream stream; - //stream << config; - //std::string str = stream.str(); - return stream.str(); + return attr.print(); }); } diff --git a/api/python/PE/objects/signature/pyContentInfo.cpp b/api/python/PE/objects/signature/pyContentInfo.cpp index 451c854..98a477b 100644 --- a/api/python/PE/objects/signature/pyContentInfo.cpp +++ b/api/python/PE/objects/signature/pyContentInfo.cpp @@ -34,7 +34,50 @@ using setter_t = void (ContentInfo::*)(T); template<> void create(py::module& m) { - py::class_(m, "ContentInfo") + py::class_(m, "ContentInfo", + R"delim( + ContentInfo as described in the `RFC 2315 `_ + + .. code-block:: text + + ContentInfo ::= SEQUENCE { + contentType ContentType, + content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL + } + + ContentType ::= OBJECT IDENTIFIER + + In the case of PE signature, ContentType **must** be set to SPC_INDIRECT_DATA_OBJID + OID: ``1.3.6.1.4.1.311.2.1.4`` and content is defined by the structure: ``SpcIndirectDataContent`` + + .. code-block:: text + + SpcIndirectDataContent ::= SEQUENCE { + data SpcAttributeTypeAndOptionalValue, + messageDigest DigestInfo + } + + SpcAttributeTypeAndOptionalValue ::= SEQUENCE { + type ObjectID, + value [0] EXPLICIT ANY OPTIONAL + } + + For PE signature, ``SpcAttributeTypeAndOptionalValue.type`` + is set to ``SPC_PE_IMAGE_DATAOBJ`` (OID: ``1.3.6.1.4.1.311.2.1.15``) and the value is defined by + ``SpcPeImageData`` + + .. code-block:: text + + DigestInfo ::= SEQUENCE { + digestAlgorithm AlgorithmIdentifier, + digest OCTETSTRING + } + + AlgorithmIdentifier ::= SEQUENCE { + algorithm ObjectID, + parameters [0] EXPLICIT ANY OPTIONAL + } + )delim") .def_property_readonly("content_type", &ContentInfo::content_type, @@ -51,7 +94,7 @@ void create(py::module& m) { const std::vector& dg = info.digest(); return py::bytes(reinterpret_cast(dg.data()), dg.size()); }, - "The digest as ``bytes`` ") + "The digest as ``bytes``. It should match the binary :meth:`~lief.PE.Binary.authentihash`") .def("__hash__", [] (const ContentInfo& info) { diff --git a/api/python/PE/objects/signature/pyRsaInfo.cpp b/api/python/PE/objects/signature/pyRsaInfo.cpp new file mode 100644 index 0000000..a0a606c --- /dev/null +++ b/api/python/PE/objects/signature/pyRsaInfo.cpp @@ -0,0 +1,93 @@ +/* Copyright 2017 R. Thomas + * Copyright 2017 Quarkslab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include "LIEF/PE/signature/RsaInfo.hpp" + +#include "pyPE.hpp" + +namespace LIEF { +namespace PE { + +template +using getter_t = T (RsaInfo::*)(void) const; + +template +using setter_t = void (RsaInfo::*)(T); + + +template<> +void create(py::module& m) { + + py::class_(m, "RsaInfo", "Object representing a RSA key") + .def_property_readonly("has_public_key", + &RsaInfo::has_public_key, + "True if it embeds a public key") + + .def_property_readonly("has_private_key", + &RsaInfo::has_private_key, + "True if it embeds a private key") + + .def_property_readonly("N", + [] (const RsaInfo& info) { + const std::vector& data = info.N(); + return py::bytes(reinterpret_cast(data.data()), data.size()); + }, + "RSA public modulus (in bytes)") + + .def_property_readonly("E", + [] (const RsaInfo& info) { + const std::vector& data = info.E(); + return py::bytes(reinterpret_cast(data.data()), data.size()); + }, "RSA public exponent (in bytes)") + + .def_property_readonly("D", + [] (const RsaInfo& info) { + const std::vector& data = info.D(); + return py::bytes(reinterpret_cast(data.data()), data.size()); + }, "RSA private exponent (in bytes)") + + .def_property_readonly("P", + [] (const RsaInfo& info) { + const std::vector& data = info.P(); + return py::bytes(reinterpret_cast(data.data()), data.size()); + }, "First prime factor (in bytes)") + + .def_property_readonly("Q", + [] (const RsaInfo& info) { + const std::vector& data = info.Q(); + return py::bytes(reinterpret_cast(data.data()), data.size()); + }, "Second prime factor (in bytes)") + + .def_property_readonly("key_size", + &RsaInfo::key_size, "Size of the public modulus in bits") + + .def_property_readonly("__len__", + &RsaInfo::key_size) + + .def("__str__", + [] (const RsaInfo& info) + { + std::ostringstream stream; + stream << info; + return safe_string_converter(stream.str()); + }); +} + +} +} + diff --git a/api/python/PE/objects/signature/pySignature.cpp b/api/python/PE/objects/signature/pySignature.cpp index 860c1fb..831b467 100644 --- a/api/python/PE/objects/signature/pySignature.cpp +++ b/api/python/PE/objects/signature/pySignature.cpp @@ -105,14 +105,35 @@ void create(py::module& m) { .def("check", &Signature::check, - "Check the integrity of the signature and return a " RST_CLASS_REF(lief.PE.Signature.VERIFICATION_FLAGS) "") + R"delim( + Check the integrity of the signature and return a :class:`lief.PE.Signature.VERIFICATION_FLAGS` + + 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: + + * :attr:`lief.PE.ContentInfo.digest_algorithm` + * :attr:`lief.PE.SignerInfo.digest_algorithm` + + 3. The x509 certificate specified by :attr:`lief.PE.SignerInfo.serial_number` **and** :attr:`lief.PE.SignerInfo.issuer` + must exist within :attr:`lief.PE.Signature.certificates` + 4. Given the x509 certificate, compare :attr:`lief.PE.SignerInfo.encrypted_digest` against either: + + * hash of authenticated attributes (:attr:`~lief.PE.SignerInfo.authenticated_attributes`) if present + * hash of ContentInfo + + 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 + + )delim") .def_property_readonly("raw_der", [] (const Signature& sig) { const std::vector& raw = sig.raw_der(); return py::bytes(reinterpret_cast(raw.data()), raw.size()); }, - "Return the raw original signature", + "Return the raw original signature as a byte object", py::return_value_policy::reference_internal) .def("__hash__", diff --git a/api/python/PE/objects/signature/pySignerInfo.cpp b/api/python/PE/objects/signature/pySignerInfo.cpp index b247e3f..77fd665 100644 --- a/api/python/PE/objects/signature/pySignerInfo.cpp +++ b/api/python/PE/objects/signature/pySignerInfo.cpp @@ -34,7 +34,24 @@ using setter_t = void (SignerInfo::*)(T); template<> void create(py::module& m) { - py::class_(m, "SignerInfo") + py::class_(m, "SignerInfo", + R"delim( + SignerInfo as described in the `RFC 2315 #Section 9.2 `_ + + .. code-block:: text + + SignerInfo ::= SEQUENCE { + version Version, + issuerAndSerialNumber IssuerAndSerialNumber, + digestAlgorithm DigestAlgorithmIdentifier, + authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + encryptedDigest EncryptedDigest, + unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + } + + EncryptedDigest ::= OCTET STRING + )delim") .def_property_readonly("version", &SignerInfo::version, @@ -45,13 +62,13 @@ void create(py::module& m) { const std::vector& data = info.serial_number(); return py::bytes(reinterpret_cast(data.data()), data.size()); }, - "The X509 serial number used to sign the signed-data") + "The X509 serial number used to sign the signed-data (see: :attr:`lief.PE.x509.serial_number`)") .def_property_readonly("issuer", [] (const SignerInfo& object) { return safe_string_converter(object.issuer()); }, - "Issuer and serial number", + "The X509 issuer used to sign the signed-data (see: :attr:`lief.PE.x509.issuer`)", py::return_value_policy::copy) .def_property_readonly("digest_algorithm", diff --git a/api/python/PE/objects/signature/pyx509.cpp b/api/python/PE/objects/signature/pyx509.cpp index 2ca5e66..cefaa9d 100644 --- a/api/python/PE/objects/signature/pyx509.cpp +++ b/api/python/PE/objects/signature/pyx509.cpp @@ -20,6 +20,7 @@ #include "LIEF/PE/hash.hpp" #include "LIEF/PE/signature/x509.hpp" +#include "LIEF/PE/signature/RsaInfo.hpp" #include "pyPE.hpp" @@ -36,7 +37,7 @@ using setter_t = void (x509::*)(T); template<> void create(py::module& m) { - py::class_ cls_x509(m, "x509"); + py::class_ cls_x509(m, "x509", "Interface over a x509 certificate"); LIEF::enum_(cls_x509, "VERIFICATION_FLAGS", py::arithmetic(), "Verification flags associated with " RST_METH_REF(lief.PE.x509.verify) "") @@ -62,6 +63,15 @@ void create(py::module& m) { .value("BADCRL_BAD_PK", x509::VERIFICATION_FLAGS::BADCRL_BAD_PK, "The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA).") .value("BADCRL_BAD_KEY", x509::VERIFICATION_FLAGS::BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)."); + LIEF::enum_(cls_x509, "KEY_TYPES", "Public key scheme used by the x509 certificate") + .value("NONE", x509::KEY_TYPES::NONE, "Unknown scheme") + .value("RSA", x509::KEY_TYPES::RSA, "RSA scheme") + .value("ECKEY", x509::KEY_TYPES::ECKEY, "Elliptic-curve scheme") + .value("ECKEY_DH", x509::KEY_TYPES::ECKEY_DH, "Elliptic-curve Diffie-Hellman") + .value("ECDSA", x509::KEY_TYPES::ECDSA, "Elliptic-curve Digital Signature Algorithm") + .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"); + cls_x509 .def_static("parse", static_cast(&x509::parse), @@ -90,12 +100,10 @@ void create(py::module& m) { &x509::signature_algorithm, "Signature algorithm (OID)") - .def_property_readonly("valid_from", &x509::valid_from, "Start time of certificate validity") - .def_property_readonly("valid_to", &x509::valid_to, "End time of certificate validity") @@ -104,13 +112,13 @@ void create(py::module& m) { [] (const x509& object) { return safe_string_converter(object.issuer()); }, - "Issuer informations") + "Issuer of the certificate") .def_property_readonly("subject", [] (const x509& object) { return safe_string_converter(object.subject()); }, - "Subject informations") + "Subject of the certificate") .def_property_readonly("raw", [] (const x509& crt) -> py::bytes { @@ -119,16 +127,48 @@ void create(py::module& m) { }, "The raw bytes associated with this x509 cert (DER encoded)") + .def_property_readonly("key_type", + &x509::key_type, + "Return the underlying public-key scheme (" RST_CLASS_REF(lief.PE.x509.KEY_TYPES) ")") + + .def_property_readonly("rsa_info", + &x509::rsa_info, + "If the underlying public-key scheme is RSA, return the " RST_CLASS_REF(lief.PE.RsaInfo) " associated with this certificate. " + "Otherwise, return None", + py::return_value_policy::take_ownership) + .def("verify", static_cast(&x509::verify), - "Verify that this certificate has been used **to trust** the given certificate (" RST_CLASS_REF(lief.PE.x509) " object) " - "It returns a set of flags defined by " RST_CLASS_REF(lief.PE.x509.VERIFICATION_FLAGS) "", + R"delim( + Verify that this certificate has been used **to trust** the given :class:`~lief.PE.x509` certificate + + It returns a set of flags defined by :class:`~lief.PE.x509.VERIFICATION_FLAGS` + + :Example: + + .. code-block:: python + + ca = lief.PE.x509.parse("ca.crt")[0] + signer = lief.PE.x509.parse("signer.crt")[0] + print(ca.verify(signer)) # lief.PE.x509.VERIFICATION_FLAGS.OK + + )delim", "ca"_a) .def("is_trusted_by", &x509::is_trusted_by, - "Verify this certificate against a list of root CA (list of " RST_CLASS_REF(lief.PE.x509) " object) " - "It returns a set of flags defined by " RST_CLASS_REF(lief.PE.x509.VERIFICATION_FLAGS) "", + R"delim( + Verify this certificate against a list of root CA (list of :class:`~lief.PE.x509` objects) + It returns a set of flags defined by :class:`~lief.PE.x509.VERIFICATION_FLAGS` + + :Example: + + .. code-block:: python + + signer = binary.signatures[0].signers[0] + microsoft_ca_bundle lief.PE.x509.parse("bundle.pem") + print(signer.cert.is_trusted_by(microsoft_ca_bundle)) + )delim", "ca_list"_a) .def("__hash__", diff --git a/api/python/PE/pyPE.cpp b/api/python/PE/pyPE.cpp index ce892c9..29a63b7 100644 --- a/api/python/PE/pyPE.cpp +++ b/api/python/PE/pyPE.cpp @@ -77,6 +77,7 @@ void init_objects(py::module& m) { CREATE(ResourceStringTable, m); CREATE(ResourceAccelerator, m); CREATE(Signature, m); + CREATE(RsaInfo, m); CREATE(x509, m); CREATE(ContentInfo, m); CREATE(SignerInfo, m); diff --git a/api/python/PE/pyPE.hpp b/api/python/PE/pyPE.hpp index 6381ac8..27bcab0 100644 --- a/api/python/PE/pyPE.hpp +++ b/api/python/PE/pyPE.hpp @@ -83,6 +83,7 @@ SPECIALIZE_CREATE(ResourceDialogItem); SPECIALIZE_CREATE(ResourceAccelerator); SPECIALIZE_CREATE(Signature); +SPECIALIZE_CREATE(RsaInfo); SPECIALIZE_CREATE(x509); SPECIALIZE_CREATE(SignerInfo); SPECIALIZE_CREATE(Attribute); diff --git a/cmake/LIEFDependencies.cmake b/cmake/LIEFDependencies.cmake index 639668f..e75326f 100644 --- a/cmake/LIEFDependencies.cmake +++ b/cmake/LIEFDependencies.cmake @@ -29,8 +29,8 @@ endif() # mbed TLS # -------- -set(MBED_TLS_VERSION 2.7.17) -set(MBED_TLS_SHA256 SHA256=a009059b0b4b882b884e8ef7013ff068b1254d8a2d98243e000c67b1737956b6) +set(MBED_TLS_VERSION 2.25.0) +set(MBED_TLS_SHA256 SHA256=6bf01ef178925f7db3c9027344a50855b116f2defe4a24cbdc0220111a371597) set(MBED_TLS_URL "${THIRD_PARTY_DIRECTORY}/mbedtls-${MBED_TLS_VERSION}.zip" CACHE STRING "URL to MbedTLS") set(MBED_TLS_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/mbed_tls") @@ -53,6 +53,7 @@ set(mbedtls_src_crypto "${MBEDTLS_SOURCE_DIR}/library/aes.c" "${MBEDTLS_SOURCE_DIR}/library/aesni.c" "${MBEDTLS_SOURCE_DIR}/library/arc4.c" + "${MBEDTLS_SOURCE_DIR}/library/aria.c" "${MBEDTLS_SOURCE_DIR}/library/asn1parse.c" "${MBEDTLS_SOURCE_DIR}/library/asn1write.c" "${MBEDTLS_SOURCE_DIR}/library/base64.c" @@ -60,6 +61,8 @@ set(mbedtls_src_crypto "${MBEDTLS_SOURCE_DIR}/library/blowfish.c" "${MBEDTLS_SOURCE_DIR}/library/camellia.c" "${MBEDTLS_SOURCE_DIR}/library/ccm.c" + "${MBEDTLS_SOURCE_DIR}/library/chacha20.c" + "${MBEDTLS_SOURCE_DIR}/library/chachapoly.c" "${MBEDTLS_SOURCE_DIR}/library/cipher.c" "${MBEDTLS_SOURCE_DIR}/library/cipher_wrap.c" "${MBEDTLS_SOURCE_DIR}/library/cmac.c" @@ -76,13 +79,14 @@ set(mbedtls_src_crypto "${MBEDTLS_SOURCE_DIR}/library/error.c" "${MBEDTLS_SOURCE_DIR}/library/gcm.c" "${MBEDTLS_SOURCE_DIR}/library/havege.c" + "${MBEDTLS_SOURCE_DIR}/library/hkdf.c" "${MBEDTLS_SOURCE_DIR}/library/hmac_drbg.c" "${MBEDTLS_SOURCE_DIR}/library/md.c" "${MBEDTLS_SOURCE_DIR}/library/md2.c" "${MBEDTLS_SOURCE_DIR}/library/md4.c" "${MBEDTLS_SOURCE_DIR}/library/md5.c" - "${MBEDTLS_SOURCE_DIR}/library/md_wrap.c" "${MBEDTLS_SOURCE_DIR}/library/memory_buffer_alloc.c" + "${MBEDTLS_SOURCE_DIR}/library/nist_kw.c" "${MBEDTLS_SOURCE_DIR}/library/oid.c" "${MBEDTLS_SOURCE_DIR}/library/padlock.c" "${MBEDTLS_SOURCE_DIR}/library/pem.c" @@ -93,6 +97,14 @@ set(mbedtls_src_crypto "${MBEDTLS_SOURCE_DIR}/library/pkparse.c" "${MBEDTLS_SOURCE_DIR}/library/pkwrite.c" "${MBEDTLS_SOURCE_DIR}/library/platform.c" + "${MBEDTLS_SOURCE_DIR}/library/platform_util.c" + "${MBEDTLS_SOURCE_DIR}/library/poly1305.c" + "${MBEDTLS_SOURCE_DIR}/library/psa_crypto.c" + "${MBEDTLS_SOURCE_DIR}/library/psa_crypto_driver_wrappers.c" + "${MBEDTLS_SOURCE_DIR}/library/psa_crypto_se.c" + "${MBEDTLS_SOURCE_DIR}/library/psa_crypto_slot_management.c" + "${MBEDTLS_SOURCE_DIR}/library/psa_crypto_storage.c" + "${MBEDTLS_SOURCE_DIR}/library/psa_its_file.c" "${MBEDTLS_SOURCE_DIR}/library/ripemd160.c" "${MBEDTLS_SOURCE_DIR}/library/rsa.c" "${MBEDTLS_SOURCE_DIR}/library/rsa_internal.c" @@ -119,21 +131,23 @@ set(mbedtls_src_x509 ) set(mbedtls_src_tls - "${MBEDTLS_SOURCE_DIR}/library/debug.c" - "${MBEDTLS_SOURCE_DIR}/library/net_sockets.c" - "${MBEDTLS_SOURCE_DIR}/library/ssl_cache.c" - "${MBEDTLS_SOURCE_DIR}/library/ssl_ciphersuites.c" - "${MBEDTLS_SOURCE_DIR}/library/ssl_cli.c" - "${MBEDTLS_SOURCE_DIR}/library/ssl_cookie.c" - "${MBEDTLS_SOURCE_DIR}/library/ssl_srv.c" - "${MBEDTLS_SOURCE_DIR}/library/ssl_ticket.c" - "${MBEDTLS_SOURCE_DIR}/library/ssl_tls.c" + "${MBEDTLS_SOURCE_DIR}/library/debug.c" + "${MBEDTLS_SOURCE_DIR}/library/net_sockets.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_cache.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_ciphersuites.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_cli.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_cookie.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_msg.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_srv.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_ticket.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_tls.c" + "${MBEDTLS_SOURCE_DIR}/library/ssl_tls13_keys.c" ) #set_source_files_properties("${MBEDTLS_SOURCE_DIR}/library/bignum.c" PROPERTIES COMPILE_FLAGS -Wno-overlength-strings) -set(SPDLOG_VERSION 1.8.1) -set(SPDLOG_SHA256 SHA256=eed0095a1d52d08a0834feda146d4f9148fa4125620cd04d8ea57e0238fa39cd) +set(SPDLOG_VERSION 1.8.2) +set(SPDLOG_SHA256 SHA256=f0410b12b526065802b40db01304783550d3d20b4b6fe2f8da55f9d08ed2035d) set(SPDLOG_URL "${THIRD_PARTY_DIRECTORY}/spdlog-${SPDLOG_VERSION}.zip" CACHE STRING "URL to the spdlog lib repo") ExternalProject_Add(lief_spdlog URL ${SPDLOG_URL} @@ -210,8 +224,8 @@ set(LIEF_FROZEN_ENABLED 0) if (LIEF_SUPPORT_CXX14 AND NOT LIEF_DISABLE_FROZEN) message(STATUS "Enable Frozen (C++14 support)") set(LIEF_FROZEN_ENABLED 1) - set(FROZEN_VERSION 1.0.0) - set(FROZEN_SHA256 SHA256=35ed00f6e2eb718415bf7c3e62e7708318fa684b9cc736c3fe08cf4cb2f08305) + set(FROZEN_VERSION e6ddc43) + set(FROZEN_SHA256 SHA256=7aa0ab44eb91fc2c2431bd2e78bd3545aae750793a880064f6df0ef84c819065) set(FROZEN_URL "${THIRD_PARTY_DIRECTORY}/frozen-${FROZEN_VERSION}.zip" CACHE STRING "URL to Frozen") ExternalProject_Add(lief_frozen URL ${FROZEN_URL} @@ -241,3 +255,20 @@ ExternalProject_Add(lief_leaf # :) ExternalProject_get_property(lief_leaf SOURCE_DIR) set(LEAF_INCLUDE_DIR "${SOURCE_DIR}/include") + +# utfcpp +# ------ +set(UTFCPP_VERSION 3.1.2) # Custom fix to remove use of SUBLANG_DEFAULT in common.hpp and all.hpp +set(UTFCPP_SHA256 SHA256=b77bff122a6d4f2a7a1ab409086bbb59bf899a2fdde12e1a85a4305fa91764c4) +set(UTFCPP_URL "${THIRD_PARTY_DIRECTORY}/utfcpp-${UTFCPP_VERSION}.zip" CACHE STRING "URL to UTFCPP") +ExternalProject_Add(lief_utfcpp + URL ${UTFCPP_URL} + URL_HASH ${UTFCPP_SHA256} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + UPDATE_COMMAND "" + INSTALL_COMMAND "") + +ExternalProject_get_property(lief_utfcpp SOURCE_DIR) +set(UTFCPP_INCLUDE_DIR "${SOURCE_DIR}/source") + diff --git a/doc/sphinx/api/python/pe.rst b/doc/sphinx/api/python/pe.rst index 66fb7f8..b7e8cd5 100644 --- a/doc/sphinx/api/python/pe.rst +++ b/doc/sphinx/api/python/pe.rst @@ -253,6 +253,27 @@ Signature PKCS9SigningTime ---------- +Signature SpcSpOpusInfo +*********************** + +.. autoclass:: lief.PE.SpcSpOpusInfo + :members: + :inherited-members: + :undoc-members: + +---------- + + +RsaInfo +******* + +.. autoclass:: lief.PE.RsaInfo + :members: + :inherited-members: + :undoc-members: + +---------- + x509 **** diff --git a/doc/sphinx/tutorials/13_pe_authenticode.rst b/doc/sphinx/tutorials/13_pe_authenticode.rst index 90d19cf..efe39e8 100644 --- a/doc/sphinx/tutorials/13_pe_authenticode.rst +++ b/doc/sphinx/tutorials/13_pe_authenticode.rst @@ -19,6 +19,12 @@ Introduction .. TODO + https://github.com/ralphje/signify + https://signify.readthedocs.io/en/latest/authenticode.html + + https://github.com/trailofbits/uthenticode + https://blog.trailofbits.com/2020/05/27/verifying-windows-binaries-without-windows/ + .. rubric:: API @@ -37,7 +43,6 @@ Introduction * :class:`lief.PE.Attribute` * :class:`lief.PE.ContentType` * :class:`lief.PE.GenericType` -* :class:`lief.PE.MsCounterSign` * :class:`lief.PE.MsSpcNestedSignature` * :class:`lief.PE.MsSpcStatementType` * :class:`lief.PE.PKCS9AtSequenceNumber` diff --git a/include/LIEF/PE/Section.hpp b/include/LIEF/PE/Section.hpp index 0a75073..e28a741 100644 --- a/include/LIEF/PE/Section.hpp +++ b/include/LIEF/PE/Section.hpp @@ -58,11 +58,12 @@ class LIEF_API Section : public LIEF::Section { // LIEF::Section implementation // ============================ virtual std::vector content(void) const override; + + //! Content of the section's padding inline const std::vector& padding() const { return this->padding_; } - uint32_t pointerto_raw_data(void) const; uint32_t pointerto_relocation(void) const; uint32_t pointerto_line_numbers(void) const; diff --git a/include/LIEF/PE/signature/ContentInfo.hpp b/include/LIEF/PE/signature/ContentInfo.hpp index 4539299..2bf8eb8 100644 --- a/include/LIEF/PE/signature/ContentInfo.hpp +++ b/include/LIEF/PE/signature/ContentInfo.hpp @@ -37,10 +37,11 @@ class SignatureParser; * } * * ContentType ::= OBJECT IDENTIFIER + * ``` * * In the case of PE signature, ContentType **must** be set to SPC_INDIRECT_DATA_OBJID * OID: ``1.3.6.1.4.1.311.2.1.4`` and content is defined by the structure: ``SpcIndirectDataContent`` - * + * ```raw * SpcIndirectDataContent ::= SEQUENCE { * data SpcAttributeTypeAndOptionalValue, * messageDigest DigestInfo @@ -50,11 +51,13 @@ class SignatureParser; * type ObjectID, * value [0] EXPLICIT ANY OPTIONAL * } + * ``` * * For PE signature, ``SpcAttributeTypeAndOptionalValue.type`` * is set to ``SPC_PE_IMAGE_DATAOBJ`` (OID: ``1.3.6.1.4.1.311.2.1.15``) and the value is defined by * ``SpcPeImageData`` * + * ```raw * DigestInfo ::= SEQUENCE { * digestAlgorithm AlgorithmIdentifier, * digest OCTETSTRING diff --git a/include/LIEF/PE/signature/RsaInfo.hpp b/include/LIEF/PE/signature/RsaInfo.hpp index 3889d23..3a9df3c 100644 --- a/include/LIEF/PE/signature/RsaInfo.hpp +++ b/include/LIEF/PE/signature/RsaInfo.hpp @@ -25,28 +25,43 @@ namespace LIEF { namespace PE { class x509; +//! Object that wraps a RSA key class LIEF_API RsaInfo { friend class x509; public: using rsa_ctx_handle = void*; - using bignum_wrapper_t = std::vector; + using bignum_wrapper_t = std::vector; ///< Container for BigInt public: RsaInfo(const RsaInfo& other); RsaInfo(RsaInfo&& other); RsaInfo& operator=(RsaInfo other); + //! True if it embeds a public key bool has_public_key(void) const; + + //! True if it embeds a private key bool has_private_key(void) const; + //! RSA public modulus bignum_wrapper_t N(void) const; + + //! RSA public exponent bignum_wrapper_t E(void) const; + //! RSA private exponent bignum_wrapper_t D(void) const; + + //! First prime factor bignum_wrapper_t P(void) const; + + //! Second prime factor bignum_wrapper_t Q(void) const; + //! Size of the public modulus (in bits) + size_t key_size(void) const; + void swap(RsaInfo& other); operator bool() const; diff --git a/include/LIEF/PE/signature/Signature.hpp b/include/LIEF/PE/signature/Signature.hpp index a94f366..e3237d5 100644 --- a/include/LIEF/PE/signature/Signature.hpp +++ b/include/LIEF/PE/signature/Signature.hpp @@ -95,11 +95,11 @@ class LIEF_API Signature : public Object { //! * ContentInfo::digest_algorithm //! * SignerInfo::digest_algorithm //! 3. The x509 certificate specified by SignerInfo::serial_number **and** SignerInfo::issuer - //! must exists within Signature::certificates + //! must exist within Signature::certificates //! 4. Given the x509 certificate, compare SignerInfo::encrypted_digest against either: - //! * hash of authenticated attributes if present there are authenticated attributes - //! * hash ContentInfo - //! 5. If the are Authenticated attributes, check that a PKCS9_MESSAGE_DIGEST attribute exists + //! * hash of authenticated attributes if present + //! * hash of ContentInfo + //! 5. If they are Authenticated attributes, check that a PKCS9_MESSAGE_DIGEST attribute exists //! and that its value matches hash of ContentInfo VERIFICATION_FLAGS check() const; diff --git a/include/LIEF/PE/signature/SignerInfo.hpp b/include/LIEF/PE/signature/SignerInfo.hpp index 977fa67..82a25c2 100644 --- a/include/LIEF/PE/signature/SignerInfo.hpp +++ b/include/LIEF/PE/signature/SignerInfo.hpp @@ -32,6 +32,22 @@ class Parser; class SignatureParser; class x509; +/** SignerInfo as described in the [RFC 2315](https://tools.ietf.org/html/rfc2315#section-9.2) + * + * ```raw + * SignerInfo ::= SEQUENCE { + * version Version, + * issuerAndSerialNumber IssuerAndSerialNumber, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + * } + * + * EncryptedDigest ::= OCTET STRING + * ``` + */ class LIEF_API SignerInfo : public Object { friend class Parser; diff --git a/include/LIEF/PE/signature/attributes/MsSpcStatementType.hpp b/include/LIEF/PE/signature/attributes/MsSpcStatementType.hpp index 463a1c4..75eb86d 100644 --- a/include/LIEF/PE/signature/attributes/MsSpcStatementType.hpp +++ b/include/LIEF/PE/signature/attributes/MsSpcStatementType.hpp @@ -49,7 +49,7 @@ class LIEF_API MsSpcStatementType : public Attribute { virtual std::unique_ptr clone(void) const override; //! According to the documentation: - //! > The SpcStatementType MUST contain one Object Identifier with either + //! > The SpcStatementType MUST contain one Object Identifier with either //! > the value ``1.3.6.1.4.1.311.2.1.21 (SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID)`` or //! > ``1.3.6.1.4.1.311.2.1.22 (SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID)``. inline const oid_t& oid() const { diff --git a/include/LIEF/PE/signature/x509.hpp b/include/LIEF/PE/signature/x509.hpp index 2c2c4c8..acca9b1 100644 --- a/include/LIEF/PE/signature/x509.hpp +++ b/include/LIEF/PE/signature/x509.hpp @@ -37,6 +37,7 @@ class SignatureParser; class RsaInfo; +//! Interface over a x509 certificate class LIEF_API x509 : public Object { friend class Parser; @@ -48,18 +49,21 @@ class LIEF_API x509 : public Object { using certificates_t = std::vector; + //! Parse x509 certificate(s) from file path static certificates_t parse(const std::string& path); + + //! Parse x500 certificate(s) from raw blob static certificates_t parse(const std::vector& content); //! Public key scheme enum class KEY_TYPES { - NONE = 0, - RSA, - ECKEY, - ECKEY_DH, - ECDSA, - RSA_ALT, - RSASSA_PSS, + NONE = 0, ///< Unknown scheme + RSA, ///< RSA Scheme + ECKEY, ///< Elliptic-curve scheme + ECKEY_DH, ///< Elliptic-curve Diffie-Hellman + ECDSA, ///< Elliptic-curve Digital Signature Algorithm + RSA_ALT, ///< RSA scheme with an alternative implementation for signing and decrypting + RSASSA_PSS, ///< RSA Probabilistic signature scheme }; //! Mirror of mbedtls's X509 Verify codes: MBEDTLS_X509_XX @@ -125,7 +129,7 @@ class LIEF_API x509 : public Object { //! Return the underlying public-key scheme KEY_TYPES key_type() const; - //! **If** the underlying public-key scheme is RSA, return the Rsa information. + //! **If** the underlying public-key scheme is RSA, return the RSA information. //! Otherwise, return a nullptr std::unique_ptr rsa_info() const; diff --git a/src/BinaryStream/BinaryStream.cpp b/src/BinaryStream/BinaryStream.cpp index 27b75ce..a8df3d8 100644 --- a/src/BinaryStream/BinaryStream.cpp +++ b/src/BinaryStream/BinaryStream.cpp @@ -16,7 +16,7 @@ #include "LIEF/BinaryStream/BinaryStream.hpp" #include "LIEF/DWARF/enums.hpp" #include "LIEF/utils.hpp" -#include "utf8/checked.h" +#include "LIEF/third-party/utfcpp/utf8/checked.h" #include #include @@ -172,7 +172,7 @@ std::u16string BinaryStream::peek_u16string(void) const { size_t count = 0; do { - c = this->peek(off); + c = this->peek_conv(off); off += sizeof(char16_t); result.push_back(c); ++count; @@ -192,11 +192,11 @@ std::u16string BinaryStream::peek_u16string(size_t length) const { if (length == static_cast(-1u)) { return this->peek_u16string(); } - const char16_t* raw = this->peek_array(this->pos(), length, /* check */false); + std::unique_ptr raw = this->peek_conv_array(this->pos(), length, /* check */false); if (raw == nullptr) { return {}; } - return {raw, length}; + return {raw.get(), length}; } std::u16string BinaryStream::peek_u16string_at(size_t offset, size_t length) const { diff --git a/src/BinaryStream/Convert.cpp b/src/BinaryStream/Convert.cpp index 4a18344..d620751 100644 --- a/src/BinaryStream/Convert.cpp +++ b/src/BinaryStream/Convert.cpp @@ -18,6 +18,7 @@ void swap_endian(T *v) { template void swap_endian(uint16_t *v); template void swap_endian(uint32_t *v); template void swap_endian(uint64_t *v); +template void swap_endian(char16_t *v); } } diff --git a/src/PE/Builder.cpp b/src/PE/Builder.cpp index 26f33e1..c82e04e 100644 --- a/src/PE/Builder.cpp +++ b/src/PE/Builder.cpp @@ -21,7 +21,7 @@ #include "logging.hpp" -#include "utf8.h" +#include "LIEF/third-party/utfcpp/utf8.h" #include "LIEF/exception.hpp" #include "LIEF/PE/Builder.hpp" diff --git a/src/PE/signature/RsaInfo.cpp b/src/PE/signature/RsaInfo.cpp index 4f38dc2..d1d3c28 100644 --- a/src/PE/signature/RsaInfo.cpp +++ b/src/PE/signature/RsaInfo.cpp @@ -20,17 +20,19 @@ RsaInfo::RsaInfo(const RsaInfo::rsa_ctx_handle ctx) { const mbedtls_rsa_context* pctx = reinterpret_cast(ctx); mbedtls_rsa_context* local_ctx = new mbedtls_rsa_context{}; mbedtls_rsa_init(local_ctx, pctx->padding, pctx->hash_id); - mbedtls_rsa_copy(local_ctx, pctx); + mbedtls_rsa_copy(local_ctx, pctx); + mbedtls_rsa_complete(local_ctx); this->ctx_ = reinterpret_cast(local_ctx); } RsaInfo::RsaInfo(const RsaInfo& other) { - if (other) { + if (other.ctx_ != nullptr) { const mbedtls_rsa_context* octx = reinterpret_cast(other.ctx_); mbedtls_rsa_context* local_ctx = new mbedtls_rsa_context{}; mbedtls_rsa_init(local_ctx, octx->padding, octx->hash_id); mbedtls_rsa_copy(local_ctx, octx); + mbedtls_rsa_complete(local_ctx); this->ctx_ = reinterpret_cast(local_ctx); } } @@ -99,9 +101,14 @@ RsaInfo::bignum_wrapper_t RsaInfo::Q(void) const { return Q; } +size_t RsaInfo::key_size(void) const { + mbedtls_rsa_context* lctx = reinterpret_cast(this->ctx_); + return mbedtls_rsa_get_len(lctx) * 8; +} + RsaInfo::~RsaInfo(void) { - if (this->ctx_) { + if (this->ctx_ != nullptr) { mbedtls_rsa_context* lctx = reinterpret_cast(this->ctx_); mbedtls_rsa_free(lctx); delete lctx; diff --git a/src/PE/signature/SignatureParser.cpp b/src/PE/signature/SignatureParser.cpp index d7e4d70..49f40b9 100644 --- a/src/PE/signature/SignatureParser.cpp +++ b/src/PE/signature/SignatureParser.cpp @@ -44,7 +44,7 @@ #include "LIEF/PE/signature/OIDToString.hpp" -#include "utf8.h" +#include "LIEF/third-party/utfcpp/utf8.h" #include "logging.hpp" #include "pkcs7.h" @@ -995,22 +995,21 @@ result SignatureParser::parse_spc_string(VectorStream& stream) { LIEF_DEBUG("SpcString: Unicode choice"); const size_t length = choice.value(); LIEF_DEBUG("spc-string.program-name length: {} (pos: {})", length, stream.pos()); - const char* str = stream.read_array(length); - if (str == nullptr) { + + if (not stream.can_read(length / sizeof(char16_t))) { LIEF_INFO("Can't read spc-string.program-name"); return make_error_code(lief_errors::read_error); } + stream.set_endian_swap(true); + std::u16string progname = stream.read_u16string(length / sizeof(char16_t)); + stream.set_endian_swap(false); - std::string u8progname = {str, str + length}; - std::u16string progname; try { - progname = u8tou16(u8progname); + return utf8::utf16to8(progname); } catch (const utf8::exception&) { LIEF_INFO("Error while converting utf-8 spc-string.program-name to utf16"); return make_error_code(lief_errors::conversion_error); } - LIEF_DEBUG("spc-string.program-name: {}", u16tou8(progname)); - return u16tou8(progname); } else if ((choice = stream.asn1_read_tag(MBEDTLS_ASN1_CONTEXT_SPECIFIC | 1))) { LIEF_DEBUG("SpcString: ASCII choice"); diff --git a/src/PE/signature/x509.cpp b/src/PE/signature/x509.cpp index f9aa118..498caff 100644 --- a/src/PE/signature/x509.cpp +++ b/src/PE/signature/x509.cpp @@ -182,8 +182,7 @@ x509::KEY_TYPES x509::key_type() const { std::unique_ptr x509::rsa_info(void) const { if (this->key_type() == KEY_TYPES::RSA) { - mbedtls_pk_context& ctx = this->x509_cert_->pk; - mbedtls_rsa_context* rsa_ctx = mbedtls_pk_rsa(ctx); + mbedtls_rsa_context* rsa_ctx = mbedtls_pk_rsa(this->x509_cert_->pk); return std::unique_ptr{new RsaInfo{rsa_ctx}}; } return nullptr; diff --git a/src/utf8.h b/src/utf8.h deleted file mode 100644 index 4e44514..0000000 --- a/src/utf8.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2006 Nemanja Trifunovic - -/* -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 - -#include "utf8/checked.h" -#include "utf8/unchecked.h" - -#endif // header guard diff --git a/src/utf8/checked.h b/src/utf8/checked.h deleted file mode 100644 index 1331155..0000000 --- a/src/utf8/checked.h +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2006 Nemanja Trifunovic - -/* -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 - -#include "core.h" -#include - -namespace utf8 -{ - // Base for the exceptions that may be thrown from the library - class exception : public ::std::exception { - }; - - // Exceptions that may be thrown from the library functions. - class invalid_code_point : public exception { - uint32_t cp; - public: - invalid_code_point(uint32_t cp) : cp(cp) {} - virtual const char* what() const throw() { return "Invalid code point"; } - uint32_t code_point() const {return cp;} - }; - - class invalid_utf8 : public exception { - uint8_t u8; - public: - invalid_utf8 (uint8_t u) : u8(u) {} - virtual const char* what() const throw() { return "Invalid UTF-8"; } - uint8_t utf8_octet() const {return u8;} - }; - - class invalid_utf16 : public exception { - uint16_t u16; - public: - invalid_utf16 (uint16_t u) : u16(u) {} - virtual const char* what() const throw() { return "Invalid UTF-16"; } - uint16_t utf16_word() const {return u16;} - }; - - class not_enough_room : public exception { - public: - virtual const char* what() const throw() { return "Not enough space"; } - }; - - /// The library API - functions intended to be called by the users - - template - octet_iterator append(uint32_t cp, octet_iterator result) - { - if (!utf8::internal::is_code_point_valid(cp)) - throw invalid_code_point(cp); - - if (cp < 0x80) // one octet - *(result++) = static_cast(cp); - else if (cp < 0x800) { // two octets - *(result++) = static_cast((cp >> 6) | 0xc0); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - else if (cp < 0x10000) { // three octets - *(result++) = static_cast((cp >> 12) | 0xe0); - *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - else { // four octets - *(result++) = static_cast((cp >> 18) | 0xf0); - *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); - *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - return result; - } - - template - output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) - { - while (start != end) { - octet_iterator sequence_start = start; - internal::utf_error err_code = utf8::internal::validate_next(start, end); - switch (err_code) { - case internal::UTF8_OK : - for (octet_iterator it = sequence_start; it != start; ++it) - *out++ = *it; - break; - case internal::NOT_ENOUGH_ROOM: - throw not_enough_room(); - case internal::INVALID_LEAD: - out = utf8::append (replacement, out); - ++start; - break; - case internal::INCOMPLETE_SEQUENCE: - case internal::OVERLONG_SEQUENCE: - case internal::INVALID_CODE_POINT: - out = utf8::append (replacement, out); - ++start; - // just one replacement mark for the sequence - while (start != end && utf8::internal::is_trail(*start)) - ++start; - break; - } - } - return out; - } - - template - inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) - { - static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); - return utf8::replace_invalid(start, end, out, replacement_marker); - } - - template - uint32_t next(octet_iterator& it, octet_iterator end) - { - uint32_t cp = 0; - internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); - switch (err_code) { - case internal::UTF8_OK : - break; - case internal::NOT_ENOUGH_ROOM : - throw not_enough_room(); - case internal::INVALID_LEAD : - case internal::INCOMPLETE_SEQUENCE : - case internal::OVERLONG_SEQUENCE : - throw invalid_utf8(*it); - case internal::INVALID_CODE_POINT : - throw invalid_code_point(cp); - } - return cp; - } - - template - uint32_t peek_next(octet_iterator it, octet_iterator end) - { - return utf8::next(it, end); - } - - template - uint32_t prior(octet_iterator& it, octet_iterator start) - { - // can't do much if it == start - if (it == start) - throw not_enough_room(); - - octet_iterator end = it; - // Go back until we hit either a lead octet or start - while (utf8::internal::is_trail(*(--it))) - if (it == start) - throw invalid_utf8(*it); // error - no lead byte in the sequence - return utf8::peek_next(it, end); - } - - /// Deprecated in versions that include "prior" - template - uint32_t previous(octet_iterator& it, octet_iterator pass_start) - { - octet_iterator end = it; - while (utf8::internal::is_trail(*(--it))) - if (it == pass_start) - throw invalid_utf8(*it); // error - no lead byte in the sequence - octet_iterator temp = it; - return utf8::next(temp, end); - } - - template - void advance (octet_iterator& it, distance_type n, octet_iterator end) - { - for (distance_type i = 0; i < n; ++i) - utf8::next(it, end); - } - - template - typename std::iterator_traits::difference_type - distance (octet_iterator first, octet_iterator last) - { - typename std::iterator_traits::difference_type dist; - for (dist = 0; first < last; ++dist) - utf8::next(first, last); - return dist; - } - - template - octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) - { - while (start != end) { - uint32_t cp = utf8::internal::mask16(*start++); - // Take care of surrogate pairs first - if (utf8::internal::is_lead_surrogate(cp)) { - if (start != end) { - uint32_t trail_surrogate = utf8::internal::mask16(*start++); - if (utf8::internal::is_trail_surrogate(trail_surrogate)) - cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; - else - throw invalid_utf16(static_cast(trail_surrogate)); - } - else - throw invalid_utf16(static_cast(cp)); - - } - // Lone trail surrogate - else if (utf8::internal::is_trail_surrogate(cp)) - throw invalid_utf16(static_cast(cp)); - - result = utf8::append(cp, result); - } - return result; - } - - template - u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) - { - while (start != end) { - uint32_t cp = utf8::next(start, end); - if (cp > 0xffff) { //make a surrogate pair - *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); - *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); - } - else - *result++ = static_cast(cp); - } - return result; - } - - template - octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) - { - while (start != end) - result = utf8::append(*(start++), result); - - return result; - } - - template - u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) - { - while (start != end) - (*result++) = utf8::next(start, end); - - return result; - } - - // The iterator class - template - class iterator : public std::iterator { - octet_iterator it; - octet_iterator range_start; - octet_iterator range_end; - public: - iterator () {} - explicit iterator (const octet_iterator& octet_it, - const octet_iterator& range_start, - const octet_iterator& range_end) : - it(octet_it), range_start(range_start), range_end(range_end) - { - if (it < range_start || it > range_end) - throw std::out_of_range("Invalid utf-8 iterator position"); - } - // the default "big three" are OK - octet_iterator base () const { return it; } - uint32_t operator * () const - { - octet_iterator temp = it; - return utf8::next(temp, range_end); - } - bool operator == (const iterator& rhs) const - { - if (range_start != rhs.range_start || range_end != rhs.range_end) - throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); - return (it == rhs.it); - } - bool operator != (const iterator& rhs) const - { - return !(operator == (rhs)); - } - iterator& operator ++ () - { - utf8::next(it, range_end); - return *this; - } - iterator operator ++ (int) - { - iterator temp = *this; - utf8::next(it, range_end); - return temp; - } - iterator& operator -- () - { - utf8::prior(it, range_start); - return *this; - } - iterator operator -- (int) - { - iterator temp = *this; - utf8::prior(it, range_start); - return temp; - } - }; // class iterator - -} // namespace utf8 - -#endif //header guard - - diff --git a/src/utf8/core.h b/src/utf8/core.h deleted file mode 100644 index f85081f..0000000 --- a/src/utf8/core.h +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2006 Nemanja Trifunovic - -/* -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 - -#include - -namespace utf8 -{ - // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers - // You may need to change them to match your system. - // These typedefs have the same names as ones from cstdint, or boost/cstdint - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; - -// Helper code - not intended to be directly called by the library users. May be changed at any time -namespace internal -{ - // Unicode constants - // Leading (high) surrogates: 0xd800 - 0xdbff - // Trailing (low) surrogates: 0xdc00 - 0xdfff - const uint16_t LEAD_SURROGATE_MIN = 0xd800u; - const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; - const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; - const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; - const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); - const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; - - // Maximum valid value for a Unicode code point - const uint32_t CODE_POINT_MAX = 0x0010ffffu; - - template - inline uint8_t mask8(octet_type oc) - { - return static_cast(0xff & oc); - } - template - inline uint16_t mask16(u16_type oc) - { - return static_cast(0xffff & oc); - } - template - inline bool is_trail(octet_type oc) - { - return ((utf8::internal::mask8(oc) >> 6) == 0x2); - } - - template - inline bool is_lead_surrogate(u16 cp) - { - return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); - } - - template - inline bool is_trail_surrogate(u16 cp) - { - return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); - } - - template - inline bool is_surrogate(u16 cp) - { - return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); - } - - template - inline bool is_code_point_valid(u32 cp) - { - return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); - } - - template - inline typename std::iterator_traits::difference_type - sequence_length(octet_iterator lead_it) - { - uint8_t lead = utf8::internal::mask8(*lead_it); - if (lead < 0x80) - return 1; - else if ((lead >> 5) == 0x6) - return 2; - else if ((lead >> 4) == 0xe) - return 3; - else if ((lead >> 3) == 0x1e) - return 4; - else - return 0; - } - - template - inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) - { - if (cp < 0x80) { - if (length != 1) - return true; - } - else if (cp < 0x800) { - if (length != 2) - return true; - } - else if (cp < 0x10000) { - if (length != 3) - return true; - } - - return false; - } - - enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; - - /// Helper for get_sequence_x - template - utf_error increase_safely(octet_iterator& it, octet_iterator end) - { - if (++it == end) - return NOT_ENOUGH_ROOM; - - if (!utf8::internal::is_trail(*it)) - return INCOMPLETE_SEQUENCE; - - return UTF8_OK; - } - - #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} - - /// get_sequence_x functions decode utf-8 sequences of the length x - template - utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - if (it == end) - return NOT_ENOUGH_ROOM; - - code_point = utf8::internal::mask8(*it); - - return UTF8_OK; - } - - template - utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - if (it == end) - return NOT_ENOUGH_ROOM; - - code_point = utf8::internal::mask8(*it); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); - - return UTF8_OK; - } - - template - utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - if (it == end) - return NOT_ENOUGH_ROOM; - - code_point = utf8::internal::mask8(*it); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point += (*it) & 0x3f; - - return UTF8_OK; - } - - template - utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - if (it == end) - return NOT_ENOUGH_ROOM; - - code_point = utf8::internal::mask8(*it); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point += (*it) & 0x3f; - - return UTF8_OK; - } - - #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR - - template - utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - // Save the original value of it so we can go back in case of failure - // Of course, it does not make much sense with i.e. stream iterators - octet_iterator original_it = it; - - uint32_t cp = 0; - // Determine the sequence length based on the lead octet - typedef typename std::iterator_traits::difference_type octet_difference_type; - const octet_difference_type length = utf8::internal::sequence_length(it); - - // Get trail octets and calculate the code point - utf_error err = UTF8_OK; - switch (length) { - case 0: - return INVALID_LEAD; - case 1: - err = utf8::internal::get_sequence_1(it, end, cp); - break; - case 2: - err = utf8::internal::get_sequence_2(it, end, cp); - break; - case 3: - err = utf8::internal::get_sequence_3(it, end, cp); - break; - case 4: - err = utf8::internal::get_sequence_4(it, end, cp); - break; - } - - if (err == UTF8_OK) { - // Decoding succeeded. Now, security checks... - if (utf8::internal::is_code_point_valid(cp)) { - if (!utf8::internal::is_overlong_sequence(cp, length)){ - // Passed! Return here. - code_point = cp; - ++it; - return UTF8_OK; - } - else - err = OVERLONG_SEQUENCE; - } - else - err = INVALID_CODE_POINT; - } - - // Failure branch - restore the original value of the iterator - it = original_it; - return err; - } - - template - inline utf_error validate_next(octet_iterator& it, octet_iterator end) { - uint32_t ignored; - return utf8::internal::validate_next(it, end, ignored); - } - -} // namespace internal - - /// The library API - functions intended to be called by the users - - // Byte order mark - const uint8_t bom[] = {0xef, 0xbb, 0xbf}; - - template - octet_iterator find_invalid(octet_iterator start, octet_iterator end) - { - octet_iterator result = start; - while (result != end) { - utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); - if (err_code != internal::UTF8_OK) - return result; - } - return result; - } - - template - inline bool is_valid(octet_iterator start, octet_iterator end) - { - return (utf8::find_invalid(start, end) == end); - } - - template - inline bool starts_with_bom (octet_iterator it, octet_iterator end) - { - return ( - ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && - ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && - ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) - ); - } - - //Deprecated in release 2.3 - template - inline bool is_bom (octet_iterator it) - { - return ( - (utf8::internal::mask8(*it++)) == bom[0] && - (utf8::internal::mask8(*it++)) == bom[1] && - (utf8::internal::mask8(*it)) == bom[2] - ); - } -} // namespace utf8 - -#endif // header guard - - diff --git a/src/utf8/unchecked.h b/src/utf8/unchecked.h deleted file mode 100644 index 989ccef..0000000 --- a/src/utf8/unchecked.h +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2006 Nemanja Trifunovic - -/* -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 - -#include "core.h" - -namespace utf8 -{ - namespace unchecked - { - template - octet_iterator append(uint32_t cp, octet_iterator result) - { - if (cp < 0x80) // one octet - *(result++) = static_cast(cp); - else if (cp < 0x800) { // two octets - *(result++) = static_cast((cp >> 6) | 0xc0); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - else if (cp < 0x10000) { // three octets - *(result++) = static_cast((cp >> 12) | 0xe0); - *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - else { // four octets - *(result++) = static_cast((cp >> 18) | 0xf0); - *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); - *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - return result; - } - - template - uint32_t next(octet_iterator& it) - { - uint32_t cp = utf8::internal::mask8(*it); - typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); - switch (length) { - case 1: - break; - case 2: - it++; - cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); - break; - case 3: - ++it; - cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); - ++it; - cp += (*it) & 0x3f; - break; - case 4: - ++it; - cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); - ++it; - cp += (utf8::internal::mask8(*it) << 6) & 0xfff; - ++it; - cp += (*it) & 0x3f; - break; - } - ++it; - return cp; - } - - template - uint32_t peek_next(octet_iterator it) - { - return utf8::unchecked::next(it); - } - - template - uint32_t prior(octet_iterator& it) - { - while (utf8::internal::is_trail(*(--it))) ; - octet_iterator temp = it; - return utf8::unchecked::next(temp); - } - - // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) - template - inline uint32_t previous(octet_iterator& it) - { - return utf8::unchecked::prior(it); - } - - template - void advance (octet_iterator& it, distance_type n) - { - for (distance_type i = 0; i < n; ++i) - utf8::unchecked::next(it); - } - - template - typename std::iterator_traits::difference_type - distance (octet_iterator first, octet_iterator last) - { - typename std::iterator_traits::difference_type dist; - for (dist = 0; first < last; ++dist) - utf8::unchecked::next(first); - return dist; - } - - template - octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) - { - while (start != end) { - uint32_t cp = utf8::internal::mask16(*start++); - // Take care of surrogate pairs first - if (utf8::internal::is_lead_surrogate(cp)) { - uint32_t trail_surrogate = utf8::internal::mask16(*start++); - cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; - } - result = utf8::unchecked::append(cp, result); - } - return result; - } - - template - u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) - { - while (start < end) { - uint32_t cp = utf8::unchecked::next(start); - if (cp > 0xffff) { //make a surrogate pair - *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); - *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); - } - else - *result++ = static_cast(cp); - } - return result; - } - - template - octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) - { - while (start != end) - result = utf8::unchecked::append(*(start++), result); - - return result; - } - - template - u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) - { - while (start < end) - (*result++) = utf8::unchecked::next(start); - - return result; - } - - // The iterator class - template - class iterator : public std::iterator { - octet_iterator it; - public: - iterator () {} - explicit iterator (const octet_iterator& octet_it): it(octet_it) {} - // the default "big three" are OK - octet_iterator base () const { return it; } - uint32_t operator * () const - { - octet_iterator temp = it; - return utf8::unchecked::next(temp); - } - bool operator == (const iterator& rhs) const - { - return (it == rhs.it); - } - bool operator != (const iterator& rhs) const - { - return !(operator == (rhs)); - } - iterator& operator ++ () - { - ::std::advance(it, utf8::internal::sequence_length(it)); - return *this; - } - iterator operator ++ (int) - { - iterator temp = *this; - ::std::advance(it, utf8::internal::sequence_length(it)); - return temp; - } - iterator& operator -- () - { - utf8::unchecked::prior(it); - return *this; - } - iterator operator -- (int) - { - iterator temp = *this; - utf8::unchecked::prior(it); - return temp; - } - }; // class iterator - - } // namespace utf8::unchecked -} // namespace utf8 - - -#endif // header guard - diff --git a/src/utils.cpp b/src/utils.cpp index 5e52a82..f977962 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -28,7 +28,7 @@ #include #include "LIEF/utils.hpp" -#include "utf8.h" +#include "LIEF/third-party/utfcpp/utf8.h" namespace LIEF { uint64_t align(uint64_t value, uint64_t align_on) { diff --git a/tests/pe/test_authenticode.py b/tests/pe/test_authenticode.py index 6705827..e4ab66e 100644 --- a/tests/pe/test_authenticode.py +++ b/tests/pe/test_authenticode.py @@ -19,6 +19,9 @@ lief.logging.set_level(lief.logging.LOGGING_LEVEL.INFO) def from_hex(x): return bytes.fromhex(x.replace(":", "")) +def int_from_bytes(x): + return int.from_bytes(x, byteorder="little") + class TestAuthenticode(TestCase): def setUp(self): @@ -125,14 +128,12 @@ class TestAuthenticode(TestCase): pkcs7_sig = lief.PE.Signature.parse(list(sig.raw_der)) self.assertEqual(avast.verify_signature(pkcs7_sig), lief.PE.Signature.VERIFICATION_FLAGS.OK) - def test_json_serialization(self): avast = lief.PE.parse(get_sample("PE/PE32_x86-64_binary_avast-free-antivirus-setup-online.exe")) with open(get_sample("PE/PE32_x86-64_binary_avast-free-antivirus-setup-online-signature.json"), "rb") as f: json_sig = json.load(f) self.assertEqual(json.loads(lief.to_json(avast.signatures[0])), json_sig) - def test_fail(self): # Check bad-signed PE files @@ -152,27 +153,54 @@ class TestAuthenticode(TestCase): self.assertNotEqual(avast_altered.verify_signature(), lief.PE.Signature.VERIFICATION_FLAGS.OK) self.assertNotEqual(avast_altered.signatures[0].check(), lief.PE.Signature.VERIFICATION_FLAGS.OK) - def test_pkcs9_signing_time(self): sig = lief.PE.Signature.parse(get_sample("pkcs7/cert0.p7b")) attr = sig.signers[0].get_attribute(lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_SIGNING_TIME) self.assertEqual(attr.time, [2018, 8, 2, 15, 0, 12]) def test_pkcs9_at_sequence_number(self): - sig = lief.PE.Signature.parse(get_sample("pkcs7/cert10.p7b")) + sig = lief.PE.Signature.parse(get_sample("pkcs7/cert3.p7b")) + nested_sig = sig.signers[0].get_attribute(lief.PE.SIG_ATTRIBUTE_TYPES.MS_SPC_NESTED_SIGN).signature + at_seq_nb = nested_sig.signers[0].get_attribute(lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_AT_SEQUENCE_NUMBER) + self.assertEqual(at_seq_nb.number, 1) - def test_spc_sp_opuse_info(self): - sig = lief.PE.Signature.parse(get_sample("pkcs7/cert10.p7b")) + def test_spc_sp_opus_info(self): sig = lief.PE.Signature.parse(get_sample("pkcs7/cert11.p7b")) + spc = sig.signers[0].get_attribute(lief.PE.SIG_ATTRIBUTE_TYPES.SPC_SP_OPUS_INFO) + + self.assertEqual(spc.program_name, "Slideshow Generator Powertoy for WinXP") + self.assertEqual(spc.more_info, "http://www.microsoft.com/windowsxp") + + sig = lief.PE.Signature.parse(get_sample("pkcs7/cert9.p7b")) + spc = sig.signers[0].get_attribute(lief.PE.SIG_ATTRIBUTE_TYPES.SPC_SP_OPUS_INFO) + self.assertEqual(spc.program_name, "Microsoft Windows") + self.assertEqual(spc.more_info, "http://www.microsoft.com/windows") def test_pkcs9_counter_signature(self): 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] + + 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")) + self.assertEqual(signer.issuer, "C=US, O=Symantec Corporation, CN=Symantec Time Stamping Services CA - G2") + self.assertEqual(signer.digest_algorithm, lief.PE.ALGORITHMS.SHA_1) + self.assertEqual(signer.encryption_algorithm, lief.PE.ALGORITHMS.RSA) + self.assertEqual(signer.encrypted_digest.hex()[:30], "92db1faf4b20293109bcddbb6ed7a3") + self.assertEqual(len(signer.authenticated_attributes), 3) + self.assertEqual(len(signer.unauthenticated_attributes), 0) + + content_type, sig_time, msg_digest = signer.authenticated_attributes + self.assertEqual(content_type.oid, "1.2.840.113549.1.7.1") + self.assertEqual(sig_time.time, [2018, 7, 25, 18, 14, 50]) + self.assertEqual(msg_digest.digest, from_hex("05:ca:7d:34:f0:ef:c2:70:33:4c:f9:90:77:a5:bc:86:6e:46:be:45")) def test_ms_spc_nested_signature(self): sig = lief.PE.Signature.parse(get_sample("pkcs7/cert0.p7b")) attr = sig.signers[0].get_attribute(lief.PE.SIG_ATTRIBUTE_TYPES.MS_SPC_NESTED_SIGN) nested_sig = attr.signature - print(nested_sig) self.assertEqual(nested_sig.version, 1) self.assertEqual(nested_sig.digest_algorithm, lief.PE.ALGORITHMS.SHA_256) @@ -222,6 +250,28 @@ class TestAuthenticode(TestCase): self.assertEqual(cert_ca.verify(cert_signer), lief.PE.x509.VERIFICATION_FLAGS.OK) self.assertEqual(cert_ca.is_trusted_by(ca_bundles), lief.PE.x509.VERIFICATION_FLAGS.BADCERT_NOT_TRUSTED) + def test_rsa_info(self): + avast = lief.PE.parse(get_sample("PE/PE32_x86-64_binary_avast-free-antivirus-setup-online.exe")) + cert_ca, cert_signer = avast.signatures[0].certificates + self.assertEqual(cert_ca.key_type, lief.PE.x509.KEY_TYPES.RSA) + rsa_info = cert_ca.rsa_info + self.assertEqual(rsa_info.key_size, 2048) + self.assertTrue(rsa_info.has_public_key) + self.assertFalse(rsa_info.has_private_key) + + N = int_from_bytes(rsa_info.N) + E = int_from_bytes(rsa_info.E) + D = int_from_bytes(rsa_info.D) + P = int_from_bytes(rsa_info.P) + Q = int_from_bytes(rsa_info.Q) + + self.assertEqual(E, 340287559217796998291003137928097431552) + self.assertEqual(str(N)[:70], "9739755319358115164405180509398652054747121607842183679471640563806368") + self.assertEqual(D, 0) + self.assertEqual(P, 0) + self.assertEqual(Q, 0) + + if __name__ == '__main__': root_logger = logging.getLogger() diff --git a/third-party/frozen-1.0.0.zip b/third-party/frozen-1.0.0.zip deleted file mode 100644 index 731c0da..0000000 Binary files a/third-party/frozen-1.0.0.zip and /dev/null differ diff --git a/third-party/frozen-e6ddc43.zip b/third-party/frozen-e6ddc43.zip new file mode 100644 index 0000000..dcb1c99 Binary files /dev/null and b/third-party/frozen-e6ddc43.zip differ diff --git a/third-party/mbedtls-2.25.0.zip b/third-party/mbedtls-2.25.0.zip new file mode 100644 index 0000000..7b18fc2 Binary files /dev/null and b/third-party/mbedtls-2.25.0.zip differ diff --git a/third-party/mbedtls-2.7.17.zip b/third-party/mbedtls-2.7.17.zip deleted file mode 100644 index e51de06..0000000 Binary files a/third-party/mbedtls-2.7.17.zip and /dev/null differ diff --git a/third-party/melkor-makefile-old-find.patch b/third-party/melkor-makefile-old-find.patch deleted file mode 100644 index 0d6a58d..0000000 --- a/third-party/melkor-makefile-old-find.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/Makefile b/Makefile -index d32d874..1b155b4 100644 ---- a/Makefile -+++ b/Makefile -@@ -49,8 +49,8 @@ envtools: - install: - install $(OUTPUT) $(INSTALLPATH) - clean: -- find $(SRC) -type f -executable -exec rm {} \; -- find $(TEMPL_SRC) -type f -executable -exec rm {} \; -+ find $(SRC) -type f -perm /111 -exec rm {} \; -+ find $(TEMPL_SRC) -type f -perm /111 -exec rm {} \; - rm -f $(TEMPL_SRC)/*.o - rm -f $(TEMPL_SRC)/*.so - rm -f $(SRC)/*.o diff --git a/third-party/pybind11-2.6.0.zip b/third-party/pybind11-2.6.1.zip similarity index 73% rename from third-party/pybind11-2.6.0.zip rename to third-party/pybind11-2.6.1.zip index eac0459..1a7dc0a 100644 Binary files a/third-party/pybind11-2.6.0.zip and b/third-party/pybind11-2.6.1.zip differ diff --git a/third-party/rang-2.1.zip b/third-party/rang-2.1.zip deleted file mode 100644 index d781c09..0000000 Binary files a/third-party/rang-2.1.zip and /dev/null differ diff --git a/third-party/spdlog-1.8.1.zip b/third-party/spdlog-1.8.2.zip similarity index 56% rename from third-party/spdlog-1.8.1.zip rename to third-party/spdlog-1.8.2.zip index 94147ce..d408da8 100644 Binary files a/third-party/spdlog-1.8.1.zip and b/third-party/spdlog-1.8.2.zip differ diff --git a/third-party/utfcpp-3.1.2.zip b/third-party/utfcpp-3.1.2.zip new file mode 100644 index 0000000..4e94f7a Binary files /dev/null and b/third-party/utfcpp-3.1.2.zip differ