mirror of
https://github.com/QuasarApp/LIEF.git
synced 2025-04-26 04:14:33 +00:00
Update doc & tests
This commit is contained in:
parent
53ce0cd7d4
commit
bdf1264df9
@ -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
|
||||
|
@ -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}
|
||||
|
@ -110,6 +110,13 @@ void create<Section>(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<uint8_t>& data = sec.padding();
|
||||
return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
},
|
||||
"Section padding content as bytes")
|
||||
|
||||
.def("__eq__", &Section::operator==)
|
||||
.def("__ne__", &Section::operator!=)
|
||||
.def("__hash__",
|
||||
|
@ -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"
|
||||
|
@ -34,9 +34,19 @@ using setter_t = void (ContentType::*)(T);
|
||||
|
||||
template<>
|
||||
void create<ContentType>(py::module& m) {
|
||||
py::class_<ContentType, Attribute>(m, "ContentType")
|
||||
py::class_<ContentType, Attribute>(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 <https://tools.ietf.org/html/rfc2985>`_
|
||||
|
||||
.. 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) {
|
||||
|
@ -34,12 +34,20 @@ using setter_t = void (GenericType::*)(T);
|
||||
|
||||
template<>
|
||||
void create<GenericType>(py::module& m) {
|
||||
py::class_<GenericType, Attribute>(m, "GenericType")
|
||||
py::class_<GenericType, Attribute>(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<uint8_t>& raw = type.raw_content();
|
||||
return py::bytes(reinterpret_cast<const char*>(raw.data()), raw.size());
|
||||
},
|
||||
"Original DER blob of the attribute")
|
||||
|
||||
.def("__hash__",
|
||||
[] (const GenericType& obj) {
|
||||
|
@ -34,9 +34,21 @@ using setter_t = void (MsSpcNestedSignature::*)(T);
|
||||
|
||||
template<>
|
||||
void create<MsSpcNestedSignature>(py::module& m) {
|
||||
py::class_<MsSpcNestedSignature, Attribute>(m, "MsSpcNestedSignature")
|
||||
py::class_<MsSpcNestedSignature, Attribute>(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__",
|
||||
|
@ -34,9 +34,30 @@ using setter_t = void (MsSpcStatementType::*)(T);
|
||||
|
||||
template<>
|
||||
void create<MsSpcStatementType>(py::module& m) {
|
||||
py::class_<MsSpcStatementType, Attribute>(m, "MsSpcStatementType")
|
||||
py::class_<MsSpcStatementType, Attribute>(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 <http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx>`_
|
||||
|
||||
.. 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) {
|
||||
|
@ -34,9 +34,29 @@ using setter_t = void (PKCS9AtSequenceNumber::*)(T);
|
||||
|
||||
template<>
|
||||
void create<PKCS9AtSequenceNumber>(py::module& m) {
|
||||
py::class_<PKCS9AtSequenceNumber, Attribute>(m, "PKCS9AtSequenceNumber")
|
||||
py::class_<PKCS9AtSequenceNumber, Attribute>(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 <https://tools.ietf.org/html/rfc2985>`_
|
||||
|
||||
.. 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) {
|
||||
|
@ -34,9 +34,24 @@ using setter_t = void (PKCS9CounterSignature::*)(T);
|
||||
|
||||
template<>
|
||||
void create<PKCS9CounterSignature>(py::module& m) {
|
||||
py::class_<PKCS9CounterSignature, Attribute>(m, "PKCS9CounterSignature")
|
||||
py::class_<PKCS9CounterSignature, Attribute>(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 <https://tools.ietf.org/html/rfc2985>`_
|
||||
|
||||
.. 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) {
|
||||
|
@ -34,19 +34,38 @@ using setter_t = void (PKCS9MessageDigest::*)(T);
|
||||
|
||||
template<>
|
||||
void create<PKCS9MessageDigest>(py::module& m) {
|
||||
py::class_<PKCS9MessageDigest, Attribute>(m, "PKCS9MessageDigest")
|
||||
py::class_<PKCS9MessageDigest, Attribute>(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 <https://tools.ietf.org/html/rfc2985>`_
|
||||
|
||||
.. 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<uint8_t>& data = digest.digest();
|
||||
return py::bytes(reinterpret_cast<const char*>(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);
|
||||
}
|
||||
|
||||
|
@ -34,9 +34,29 @@ using setter_t = void (PKCS9SigningTime::*)(T);
|
||||
|
||||
template<>
|
||||
void create<PKCS9SigningTime>(py::module& m) {
|
||||
py::class_<PKCS9SigningTime, Attribute>(m, "PKCS9SigningTime")
|
||||
py::class_<PKCS9SigningTime, Attribute>(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 <https://tools.ietf.org/html/rfc2985>`_
|
||||
|
||||
.. 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) {
|
||||
|
@ -34,16 +34,28 @@ using setter_t = void (SpcSpOpusInfo::*)(T);
|
||||
|
||||
template<>
|
||||
void create<SpcSpOpusInfo>(py::module& m) {
|
||||
py::class_<SpcSpOpusInfo, Attribute>(m, "SpcSpOpusInfo")
|
||||
py::class_<SpcSpOpusInfo, Attribute>(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 <http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx>`_
|
||||
|
||||
.. 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) {
|
||||
|
@ -33,17 +33,14 @@ using setter_t = void (Attribute::*)(T);
|
||||
|
||||
template<>
|
||||
void create<Attribute>(py::module& m) {
|
||||
py::class_<Attribute, Object>(m, "Attribute")
|
||||
py::class_<Attribute, Object>(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();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,50 @@ using setter_t = void (ContentInfo::*)(T);
|
||||
template<>
|
||||
void create<ContentInfo>(py::module& m) {
|
||||
|
||||
py::class_<ContentInfo, LIEF::Object>(m, "ContentInfo")
|
||||
py::class_<ContentInfo, LIEF::Object>(m, "ContentInfo",
|
||||
R"delim(
|
||||
ContentInfo as described in the `RFC 2315 <https://tools.ietf.org/html/rfc2315#section-7>`_
|
||||
|
||||
.. 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<ContentInfo>(py::module& m) {
|
||||
const std::vector<uint8_t>& dg = info.digest();
|
||||
return py::bytes(reinterpret_cast<const char*>(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) {
|
||||
|
93
api/python/PE/objects/signature/pyRsaInfo.cpp
Normal file
93
api/python/PE/objects/signature/pyRsaInfo.cpp
Normal file
@ -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 <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "LIEF/PE/signature/RsaInfo.hpp"
|
||||
|
||||
#include "pyPE.hpp"
|
||||
|
||||
namespace LIEF {
|
||||
namespace PE {
|
||||
|
||||
template<class T>
|
||||
using getter_t = T (RsaInfo::*)(void) const;
|
||||
|
||||
template<class T>
|
||||
using setter_t = void (RsaInfo::*)(T);
|
||||
|
||||
|
||||
template<>
|
||||
void create<RsaInfo>(py::module& m) {
|
||||
|
||||
py::class_<RsaInfo>(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<uint8_t>& data = info.N();
|
||||
return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
},
|
||||
"RSA public modulus (in bytes)")
|
||||
|
||||
.def_property_readonly("E",
|
||||
[] (const RsaInfo& info) {
|
||||
const std::vector<uint8_t>& data = info.E();
|
||||
return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
}, "RSA public exponent (in bytes)")
|
||||
|
||||
.def_property_readonly("D",
|
||||
[] (const RsaInfo& info) {
|
||||
const std::vector<uint8_t>& data = info.D();
|
||||
return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
}, "RSA private exponent (in bytes)")
|
||||
|
||||
.def_property_readonly("P",
|
||||
[] (const RsaInfo& info) {
|
||||
const std::vector<uint8_t>& data = info.P();
|
||||
return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
}, "First prime factor (in bytes)")
|
||||
|
||||
.def_property_readonly("Q",
|
||||
[] (const RsaInfo& info) {
|
||||
const std::vector<uint8_t>& data = info.Q();
|
||||
return py::bytes(reinterpret_cast<const char*>(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());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -105,14 +105,35 @@ void create<Signature>(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<uint8_t>& raw = sig.raw_der();
|
||||
return py::bytes(reinterpret_cast<const char*>(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__",
|
||||
|
@ -34,7 +34,24 @@ using setter_t = void (SignerInfo::*)(T);
|
||||
template<>
|
||||
void create<SignerInfo>(py::module& m) {
|
||||
|
||||
py::class_<SignerInfo, LIEF::Object>(m, "SignerInfo")
|
||||
py::class_<SignerInfo, LIEF::Object>(m, "SignerInfo",
|
||||
R"delim(
|
||||
SignerInfo as described in the `RFC 2315 #Section 9.2 <https://tools.ietf.org/html/rfc2315#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<SignerInfo>(py::module& m) {
|
||||
const std::vector<uint8_t>& data = info.serial_number();
|
||||
return py::bytes(reinterpret_cast<const char*>(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",
|
||||
|
@ -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<x509>(py::module& m) {
|
||||
|
||||
py::class_<x509, LIEF::Object> cls_x509(m, "x509");
|
||||
py::class_<x509, LIEF::Object> cls_x509(m, "x509", "Interface over a x509 certificate");
|
||||
|
||||
LIEF::enum_<x509::VERIFICATION_FLAGS>(cls_x509, "VERIFICATION_FLAGS", py::arithmetic(),
|
||||
"Verification flags associated with " RST_METH_REF(lief.PE.x509.verify) "")
|
||||
@ -62,6 +63,15 @@ void create<x509>(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_<x509::KEY_TYPES>(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::certificates_t(*)(const std::string&)>(&x509::parse),
|
||||
@ -90,12 +100,10 @@ void create<x509>(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<x509>(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<x509>(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::VERIFICATION_FLAGS(x509::*)(const x509&) const>(&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__",
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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
|
||||
****
|
||||
|
||||
|
@ -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`
|
||||
|
@ -58,11 +58,12 @@ class LIEF_API Section : public LIEF::Section {
|
||||
// LIEF::Section implementation
|
||||
// ============================
|
||||
virtual std::vector<uint8_t> content(void) const override;
|
||||
|
||||
//! Content of the section's padding
|
||||
inline const std::vector<uint8_t>& 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;
|
||||
|
@ -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
|
||||
|
@ -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<uint8_t>;
|
||||
using bignum_wrapper_t = std::vector<uint8_t>; ///< 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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -49,7 +49,7 @@ class LIEF_API MsSpcStatementType : public Attribute {
|
||||
virtual std::unique_ptr<Attribute> 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 {
|
||||
|
@ -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<x509>;
|
||||
|
||||
//! 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<uint8_t>& 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<RsaInfo> rsa_info() const;
|
||||
|
||||
|
@ -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 <iomanip>
|
||||
#include <sstream>
|
||||
@ -172,7 +172,7 @@ std::u16string BinaryStream::peek_u16string(void) const {
|
||||
|
||||
size_t count = 0;
|
||||
do {
|
||||
c = this->peek<char16_t>(off);
|
||||
c = this->peek_conv<char16_t>(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<size_t>(-1u)) {
|
||||
return this->peek_u16string();
|
||||
}
|
||||
const char16_t* raw = this->peek_array<char16_t>(this->pos(), length, /* check */false);
|
||||
std::unique_ptr<char16_t[]> raw = this->peek_conv_array<char16_t>(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 {
|
||||
|
@ -18,6 +18,7 @@ void swap_endian(T *v) {
|
||||
template void swap_endian<uint16_t>(uint16_t *v);
|
||||
template void swap_endian<uint32_t>(uint32_t *v);
|
||||
template void swap_endian<uint64_t>(uint64_t *v);
|
||||
template void swap_endian<char16_t>(char16_t *v);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -20,17 +20,19 @@ RsaInfo::RsaInfo(const RsaInfo::rsa_ctx_handle ctx) {
|
||||
const mbedtls_rsa_context* pctx = reinterpret_cast<const mbedtls_rsa_context*>(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<RsaInfo::rsa_ctx_handle>(local_ctx);
|
||||
}
|
||||
|
||||
RsaInfo::RsaInfo(const RsaInfo& other)
|
||||
{
|
||||
if (other) {
|
||||
if (other.ctx_ != nullptr) {
|
||||
const mbedtls_rsa_context* octx = reinterpret_cast<const mbedtls_rsa_context*>(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<RsaInfo::rsa_ctx_handle>(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<mbedtls_rsa_context*>(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<mbedtls_rsa_context*>(this->ctx_);
|
||||
mbedtls_rsa_free(lctx);
|
||||
delete lctx;
|
||||
|
@ -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<std::string> 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<char>(length);
|
||||
if (str == nullptr) {
|
||||
|
||||
if (not stream.can_read<char16_t>(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");
|
||||
|
@ -182,8 +182,7 @@ x509::KEY_TYPES x509::key_type() const {
|
||||
|
||||
std::unique_ptr<RsaInfo> 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<RsaInfo>{new RsaInfo{rsa_ctx}};
|
||||
}
|
||||
return nullptr;
|
||||
|
34
src/utf8.h
34
src/utf8.h
@ -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
|
@ -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 <stdexcept>
|
||||
|
||||
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 <typename octet_iterator>
|
||||
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<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
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 <typename octet_iterator, typename output_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return utf8::next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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 <typename octet_iterator, typename distance_type>
|
||||
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 octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::next(first, last);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
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<uint16_t>(trail_surrogate));
|
||||
}
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
}
|
||||
// Lone trail surrogate
|
||||
else if (utf8::internal::is_trail_surrogate(cp))
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
result = utf8::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
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<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
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 <typename octet_iterator>
|
||||
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
|
||||
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
|
||||
|
||||
|
329
src/utf8/core.h
329
src/utf8/core.h
@ -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 <iterator>
|
||||
|
||||
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<typename octet_type>
|
||||
inline uint8_t mask8(octet_type oc)
|
||||
{
|
||||
return static_cast<uint8_t>(0xff & oc);
|
||||
}
|
||||
template<typename u16_type>
|
||||
inline uint16_t mask16(u16_type oc)
|
||||
{
|
||||
return static_cast<uint16_t>(0xffff & oc);
|
||||
}
|
||||
template<typename octet_type>
|
||||
inline bool is_trail(octet_type oc)
|
||||
{
|
||||
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_lead_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_trail_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u32>
|
||||
inline bool is_code_point_valid(u32 cp)
|
||||
{
|
||||
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline typename std::iterator_traits<octet_iterator>::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 <typename octet_difference_type>
|
||||
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 <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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<octet_iterator>::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 <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
inline bool is_valid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
return (utf8::find_invalid(start, end) == end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
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
|
||||
|
||||
|
@ -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 <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it)
|
||||
{
|
||||
uint32_t cp = utf8::internal::mask8(*it);
|
||||
typename std::iterator_traits<octet_iterator>::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 <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it)
|
||||
{
|
||||
return utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
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 <typename octet_iterator>
|
||||
inline uint32_t previous(octet_iterator& it)
|
||||
{
|
||||
return utf8::unchecked::prior(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n)
|
||||
{
|
||||
for (distance_type i = 0; i < n; ++i)
|
||||
utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::unchecked::next(first);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
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 <typename u16bit_iterator, typename octet_iterator>
|
||||
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<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::unchecked::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
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 <typename octet_iterator>
|
||||
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
|
||||
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
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
|
||||
#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) {
|
||||
|
@ -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()
|
||||
|
BIN
third-party/frozen-1.0.0.zip
vendored
BIN
third-party/frozen-1.0.0.zip
vendored
Binary file not shown.
BIN
third-party/frozen-e6ddc43.zip
vendored
Normal file
BIN
third-party/frozen-e6ddc43.zip
vendored
Normal file
Binary file not shown.
BIN
third-party/mbedtls-2.25.0.zip
vendored
Normal file
BIN
third-party/mbedtls-2.25.0.zip
vendored
Normal file
Binary file not shown.
BIN
third-party/mbedtls-2.7.17.zip
vendored
BIN
third-party/mbedtls-2.7.17.zip
vendored
Binary file not shown.
15
third-party/melkor-makefile-old-find.patch
vendored
15
third-party/melkor-makefile-old-find.patch
vendored
@ -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
|
Binary file not shown.
BIN
third-party/rang-2.1.zip
vendored
BIN
third-party/rang-2.1.zip
vendored
Binary file not shown.
Binary file not shown.
BIN
third-party/utfcpp-3.1.2.zip
vendored
Normal file
BIN
third-party/utfcpp-3.1.2.zip
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user