mirror of
https://github.com/avast/retdec.git
synced 2025-03-09 00:41:24 +00:00
Add parsing of the PE Authenticode format (#902)
* init * Some more glue * Add Certificate processing * Added ability to get signers cert chain, counter signer chain, restructuring start * Solve merge conflicts * Add printing of nested signatures * Major refactor * Refactoring, adding details * Refactor * refactor, extending authenticode to return signature abstraciton, restructuing certificate table to accept new Authenticode content * large restructuring, implementing authenticode to general signature inteface * Added prototype of new json format for certificates * adhere to the code style * commiting forgotten certificate TU * Adding copyright header * decluttering authenticode interfaces, removing obsolete comments * decluttering authenticode interfaces, removing obsolete comments, updating copyright * Remove <filesystem> dependency * Restructure of ContentInfo parsing, better error checking based on MS Authenticode spec * Completed parsing of all members of SignedData that are in the specification, added exception handler in pe_format * Complete parsing of all SignerInfo information based on MS specification * Added sha1 and sha256 certificate digests * Finish extraction of all certificate information that was exported in existing fileinfo impl * Improving error handling and proper deallocation * Got rid of all leaks * Added base for MsCounterSignatures and Pkcs9CounterSignatures and their chain + signing time * Remove fileinfo certificateTable * Add more parsed information to the output, Implement plain text output * Forgot to add ms_counter_signature files to git * Adding better validation and feedback * Add the renamed source files to git * Add verification of Pkcs7 signatures and Pkcs9 countersignatures * Implement ms counter signature verification and output of verification warnings * remove non trivial intializers * Polishing verification, adding all certificates to the output, redone chain bulding * Improve error handling * Fix uninitialized values due to parsing errors * Get rid of exceptions * Fix more edge cases * Add verification if the signed and file hash match, modify the plain and json output * Fix unhandled null dereferences and uninitialized branches * Remove unnecessary copying * Add programName from SpcOpusInfo to the output, remove dead code, add missing newlines, fix windows build * Revert indent, add proper doxygen file comments * Add certificate public key back to output * Remove dots from error messages * pkcs7_signature.cpp: fix doxygen * pkcs7_signature.h: fix doxygen * pkcs9_counter_signature.cpp: fix doxygen * pkcs9_counter_signature.h: fix doxygen * pkcs7_signature.cpp: fix doxygen and source * authenticode_structs.h: fix doxygen * authenticode_structs.cpp: fix doxygen * Remove undefined behaviour, set default value of algorithm type Co-authored-by: Karel Hájek <karel.hajek@avast.com> Co-authored-by: Peter Matula <p3t3r.matula@gmail.com>
This commit is contained in:
parent
4878585d1a
commit
d80009788d
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file include/retdec/fileformat/types/certificate_table/certificate.h
|
||||
* @brief Class for one certificate.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef RETDEC_FILEFORMAT_TYPES_CERTIFICATE_TABLE_CERTIFICATE_H
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file include/retdec/fileformat/types/certificate_table/certificate_table.h
|
||||
* @brief Class for certificate table.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef RETDEC_FILEFORMAT_TYPES_CERTIFICATE_TABLE_CERTIFICATE_TABLE_H
|
||||
@ -14,51 +14,47 @@
|
||||
namespace retdec {
|
||||
namespace fileformat {
|
||||
|
||||
struct Signer
|
||||
{
|
||||
std::vector<Certificate> chain;
|
||||
/*
|
||||
"A countersignature, since it has type SignerInfo, can itself
|
||||
contain a countersignature attribute. Thus it is possible to
|
||||
construct arbitrarily long series of countersignatures.""
|
||||
https://tools.ietf.org/html/rfc2985
|
||||
*/
|
||||
std::string signingTime; /* Timestamp counter signatures will have this set */
|
||||
std::string digest;
|
||||
std::string digestAlgorithm;
|
||||
std::vector<std::string> warnings; /* warning messages about the content validity */
|
||||
std::vector<Signer> counterSigners;
|
||||
};
|
||||
|
||||
/* naming - "Signature" was already taken by unpackers */
|
||||
struct DigitalSignature
|
||||
{
|
||||
std::string fileDigest;
|
||||
std::string signedDigest;
|
||||
std::string digestAlgorithm;
|
||||
std::string programName;
|
||||
std::vector<Certificate> certificates;
|
||||
std::vector<std::string> warnings; /* warning messages about the content validity */
|
||||
Signer signer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Table of certificates
|
||||
* Currently PE - Authenticode specific structure (PKCS7)
|
||||
*/
|
||||
class CertificateTable
|
||||
{
|
||||
private:
|
||||
using certificatesIterator = std::vector<Certificate>::const_iterator;
|
||||
/// flag indicating whether signer is present
|
||||
bool hasSigner = false;
|
||||
/// flag indicating whether counter signer is present
|
||||
bool hasCounterSigner = false;
|
||||
/// index of certificate of the signer
|
||||
std::size_t signerIndex = 0;
|
||||
/// index of certificate of the counter-signer
|
||||
std::size_t counterSignerIndex = 0;
|
||||
/// stored certificates
|
||||
std::vector<Certificate> certificates;
|
||||
public:
|
||||
/// @name Getters
|
||||
/// @{
|
||||
std::size_t getNumberOfCertificates() const;
|
||||
std::size_t getSignerCertificateIndex() const;
|
||||
std::size_t getCounterSignerCertificateIndex() const;
|
||||
const Certificate* getCertificate(std::size_t certIndex) const;
|
||||
/// @}
|
||||
public:
|
||||
std::vector<DigitalSignature> signatures;
|
||||
|
||||
/// @name Setters
|
||||
/// @{
|
||||
void setSignerCertificateIndex(std::size_t certIndex);
|
||||
void setCounterSignerCertificateIndex(std::size_t certIndex);
|
||||
/// @}
|
||||
|
||||
/// @name Iterators
|
||||
/// @{
|
||||
certificatesIterator begin() const;
|
||||
certificatesIterator end() const;
|
||||
/// @}
|
||||
|
||||
/// @name Other methods
|
||||
/// @{
|
||||
bool hasSignerCertificate() const;
|
||||
bool hasCounterSignerCertificate() const;
|
||||
void addCertificate(const Certificate &certificate);
|
||||
bool empty() const;
|
||||
/// @}
|
||||
CertificateTable(std::vector<DigitalSignature> signatures);
|
||||
CertificateTable() = default;
|
||||
std::size_t signatureCount() const { return signatures.size(); }
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
} // namespace fileformat
|
||||
|
@ -71,6 +71,13 @@ add_library(fileformat STATIC
|
||||
types/tls_info/tls_info.cpp
|
||||
file_format/pe/pe_format.cpp
|
||||
file_format/pe/pe_dll_list.cpp
|
||||
file_format/pe/authenticode/authenticode.cpp
|
||||
file_format/pe/authenticode/pkcs9_counter_signature.cpp
|
||||
file_format/pe/authenticode/ms_counter_signature.cpp
|
||||
file_format/pe/authenticode/pkcs7_signature.cpp
|
||||
file_format/pe/authenticode/x509_certificate.cpp
|
||||
file_format/pe/authenticode/helper.cpp
|
||||
file_format/pe/authenticode/authenticode_structs.cpp
|
||||
file_format/coff/coff_format.cpp
|
||||
file_format/intel_hex/intel_hex_parser/intel_hex_tokenizer.cpp
|
||||
file_format/intel_hex/intel_hex_parser/intel_hex_parser.cpp
|
||||
|
18
src/fileformat/file_format/pe/authenticode/authenticode.cpp
Normal file
18
src/fileformat/file_format/pe/authenticode/authenticode.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/authenticode.cpp
|
||||
* @brief Class that parses PE Authenticode data
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "authenticode.h"
|
||||
|
||||
namespace authenticode {
|
||||
Authenticode::Authenticode(const std::vector<unsigned char>& data)
|
||||
: pkcs7(data) {}
|
||||
|
||||
std::vector<DigitalSignature> Authenticode::getSignatures(const retdec::fileformat::PeFormat* peFile) const
|
||||
{
|
||||
return pkcs7.getSignatures(peFile);
|
||||
}
|
||||
|
||||
} // namespace authenticode
|
42
src/fileformat/file_format/pe/authenticode/authenticode.h
Normal file
42
src/fileformat/file_format/pe/authenticode/authenticode.h
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/authenticode.h
|
||||
* @brief Class that parses PE Authenticode data
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
|
||||
#include "authenticode_structs.h"
|
||||
#include "pkcs7_signature.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ocsp.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
|
||||
using retdec::fileformat::DigitalSignature;
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
class Authenticode
|
||||
{
|
||||
private:
|
||||
Pkcs7Signature pkcs7;
|
||||
|
||||
public:
|
||||
Authenticode(const std::vector<unsigned char>& data);
|
||||
std::vector<DigitalSignature> getSignatures(const retdec::fileformat::PeFormat* peFile) const;
|
||||
};
|
||||
|
||||
} // namespace authenticode
|
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/authenticode_structs.cpp
|
||||
* @brief Defines custom OpenSSL objects and functions
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
* @author Marek Milkovič - metthal
|
||||
*/
|
||||
|
||||
/* Author #Metthal */
|
||||
|
||||
#include "authenticode_structs.h"
|
||||
|
||||
/*
|
||||
These are types from "Windows Authenticode Portable Executable Signature Format"
|
||||
https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx
|
||||
Some of them are changed a little bit because the documentation did not reflect the reality
|
||||
*/
|
||||
|
||||
ASN1_CHOICE(SpcString) = {
|
||||
ASN1_IMP_OPT(SpcString, value.unicode, ASN1_BMPSTRING, 0),
|
||||
ASN1_IMP_OPT(SpcString, value.ascii, ASN1_IA5STRING, 1)
|
||||
} ASN1_CHOICE_END(SpcString)
|
||||
|
||||
ASN1_SEQUENCE(SpcSerializedObject) = {
|
||||
ASN1_SIMPLE(SpcSerializedObject, classId, ASN1_OCTET_STRING),
|
||||
ASN1_SIMPLE(SpcSerializedObject, serializedData, ASN1_OCTET_STRING)
|
||||
} ASN1_SEQUENCE_END(SpcSerializedObject)
|
||||
|
||||
ASN1_CHOICE(SpcLink) = {
|
||||
ASN1_IMP_OPT(SpcLink, value.url, ASN1_IA5STRING, 0),
|
||||
ASN1_IMP_OPT(SpcLink, value.moniker, SpcSerializedObject, 1),
|
||||
ASN1_EXP_OPT(SpcLink, value.file, SpcString, 2)
|
||||
} ASN1_CHOICE_END(SpcLink)
|
||||
|
||||
ASN1_SEQUENCE(SpcAttributeTypeAndOptionalValue) = {
|
||||
ASN1_SIMPLE(SpcAttributeTypeAndOptionalValue, type, ASN1_OBJECT),
|
||||
ASN1_OPT(SpcAttributeTypeAndOptionalValue, value, ASN1_ANY)
|
||||
} ASN1_SEQUENCE_END(SpcAttributeTypeAndOptionalValue)
|
||||
|
||||
ASN1_SEQUENCE(SpcPeImageData) = {
|
||||
ASN1_SIMPLE(SpcPeImageData, flags, ASN1_BIT_STRING),
|
||||
ASN1_EXP_OPT(SpcPeImageData, file, SpcLink, 0)
|
||||
} ASN1_SEQUENCE_END(SpcPeImageData)
|
||||
|
||||
ASN1_SEQUENCE(AlgorithmIdentifier) = {
|
||||
ASN1_SIMPLE(AlgorithmIdentifier, algorithm, ASN1_OBJECT),
|
||||
ASN1_OPT(AlgorithmIdentifier, parameters, ASN1_ANY)
|
||||
} ASN1_SEQUENCE_END(AlgorithmIdentifier)
|
||||
|
||||
ASN1_SEQUENCE(DigestInfo) = {
|
||||
ASN1_SIMPLE(DigestInfo, digestAlgorithm, AlgorithmIdentifier),
|
||||
ASN1_SIMPLE(DigestInfo, digest, ASN1_OCTET_STRING)
|
||||
} ASN1_SEQUENCE_END(DigestInfo)
|
||||
|
||||
ASN1_SEQUENCE(SpcIndirectDataContent) = {
|
||||
ASN1_SIMPLE(SpcIndirectDataContent, data, SpcAttributeTypeAndOptionalValue),
|
||||
ASN1_SIMPLE(SpcIndirectDataContent, messageDigest, DigestInfo)
|
||||
} ASN1_SEQUENCE_END(SpcIndirectDataContent)
|
||||
|
||||
ASN1_SEQUENCE(SpcSpOpusInfo) = {
|
||||
ASN1_EXP_OPT(SpcSpOpusInfo, programName, SpcString, 0),
|
||||
ASN1_EXP_OPT(SpcSpOpusInfo, moreInfo, SpcLink, 1)
|
||||
} ASN1_SEQUENCE_END(SpcSpOpusInfo)
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(SpcString)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(SpcSerializedObject)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(SpcLink)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(SpcAttributeTypeAndOptionalValue)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(SpcPeImageData)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(AlgorithmIdentifier)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(DigestInfo)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(SpcIndirectDataContent)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(SpcSpOpusInfo)
|
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/authenticode_structs.h
|
||||
* @brief Declares custom OpenSSL objects and functions
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
* @author Marek Milkovič - metthal
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
/*
|
||||
These are types from "Windows Authenticode Portable Executable Signature Format"
|
||||
https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx
|
||||
Some of them are changed a little bit because the documentation did not reflect the reality
|
||||
*/
|
||||
struct SpcString
|
||||
{
|
||||
int type;
|
||||
union {
|
||||
ASN1_BMPSTRING* unicode;
|
||||
ASN1_IA5STRING* ascii;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct SpcSerializedObject
|
||||
{
|
||||
ASN1_OCTET_STRING* classId;
|
||||
ASN1_OCTET_STRING* serializedData;
|
||||
};
|
||||
|
||||
struct SpcLink
|
||||
{
|
||||
int type;
|
||||
union {
|
||||
ASN1_IA5STRING* url;
|
||||
SpcSerializedObject* moniker;
|
||||
SpcString* file;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct SpcAttributeTypeAndOptionalValue
|
||||
{
|
||||
ASN1_OBJECT* type;
|
||||
ASN1_TYPE* value;
|
||||
};
|
||||
|
||||
struct SpcPeImageData
|
||||
{
|
||||
ASN1_BIT_STRING* flags;
|
||||
SpcLink* file;
|
||||
};
|
||||
|
||||
struct AlgorithmIdentifier
|
||||
{
|
||||
ASN1_OBJECT* algorithm;
|
||||
ASN1_TYPE* parameters;
|
||||
};
|
||||
|
||||
struct DigestInfo
|
||||
{
|
||||
AlgorithmIdentifier* digestAlgorithm;
|
||||
ASN1_OCTET_STRING* digest;
|
||||
};
|
||||
|
||||
struct SpcIndirectDataContent
|
||||
{
|
||||
SpcAttributeTypeAndOptionalValue* data;
|
||||
DigestInfo* messageDigest;
|
||||
};
|
||||
|
||||
struct SpcContentInfo
|
||||
{
|
||||
ASN1_OBJECT* contentType;
|
||||
SpcIndirectDataContent* content;
|
||||
};
|
||||
struct SpcSpOpusInfo
|
||||
{
|
||||
SpcString* programName;
|
||||
SpcLink* moreInfo;
|
||||
};
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(SpcString)
|
||||
DECLARE_ASN1_FUNCTIONS(SpcSerializedObject)
|
||||
DECLARE_ASN1_FUNCTIONS(SpcLink)
|
||||
DECLARE_ASN1_FUNCTIONS(SpcAttributeTypeAndOptionalValue)
|
||||
DECLARE_ASN1_FUNCTIONS(SpcPeImageData)
|
||||
DECLARE_ASN1_FUNCTIONS(AlgorithmIdentifier)
|
||||
DECLARE_ASN1_FUNCTIONS(DigestInfo)
|
||||
DECLARE_ASN1_FUNCTIONS(SpcIndirectDataContent)
|
||||
DECLARE_ASN1_FUNCTIONS(SpcSpOpusInfo)
|
||||
DECLARE_ASN1_FUNCTIONS(SpcContentInfo)
|
113
src/fileformat/file_format/pe/authenticode/helper.cpp
Normal file
113
src/fileformat/file_format/pe/authenticode/helper.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/helper.cpp
|
||||
* @brief Helper functions used for Authenticode components
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "helper.h"
|
||||
#include <sstream>
|
||||
namespace authenticode {
|
||||
|
||||
std::string parsePublicKey(BIO* bio)
|
||||
{
|
||||
std::string key;
|
||||
std::vector<char> tmp(100);
|
||||
|
||||
BIO_gets(bio, tmp.data(), 100);
|
||||
if (std::string(tmp.data()) != "-----BEGIN PUBLIC KEY-----\n") {
|
||||
return key;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
BIO_gets(bio, tmp.data(), 100);
|
||||
if (std::string(tmp.data()) == "-----END PUBLIC KEY-----\n") {
|
||||
break;
|
||||
}
|
||||
|
||||
key += tmp.data();
|
||||
key.erase(key.length() - 1, 1); // Remove last character (whitespace)
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/* Calculates md digest type from data, result is a written into
|
||||
digest that has to be large enough to accomodate whole digest */
|
||||
void calculateDigest(const EVP_MD* md, const std::uint8_t* data, int len, std::uint8_t* digest)
|
||||
{
|
||||
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
|
||||
EVP_DigestInit_ex(mdctx, md, NULL);
|
||||
EVP_DigestUpdate(mdctx, data, len);
|
||||
EVP_DigestFinal_ex(mdctx, digest, NULL);
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
}
|
||||
|
||||
std::string bytesToHexString(const std::uint8_t* in, int len)
|
||||
{
|
||||
const std::uint8_t* end = in + len;
|
||||
std::ostringstream oss;
|
||||
for (; in != end; ++in)
|
||||
oss << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << static_cast<int>(*in);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string parseDateTime(const ASN1_TIME* dateTime)
|
||||
{
|
||||
if (ASN1_TIME_check(dateTime) == 0)
|
||||
return {};
|
||||
|
||||
BIO* memBio = BIO_new(BIO_s_mem());
|
||||
ASN1_TIME_print(memBio, dateTime);
|
||||
|
||||
BUF_MEM* bioMemPtr;
|
||||
BIO_ctrl(memBio, BIO_C_GET_BUF_MEM_PTR, 0, reinterpret_cast<char*>(&bioMemPtr));
|
||||
|
||||
std::string result(bioMemPtr->data, bioMemPtr->length);
|
||||
BIO_free_all(memBio);
|
||||
return result;
|
||||
}
|
||||
std::string serialToString(ASN1_INTEGER* serial)
|
||||
{
|
||||
BIGNUM* bignum = ASN1_INTEGER_to_BN(serial, nullptr);
|
||||
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
BN_print(bio, bignum);
|
||||
auto data_len = BIO_number_written(bio);
|
||||
|
||||
std::vector<char> result(data_len);
|
||||
BIO_read(bio, static_cast<void*>(result.data()), data_len);
|
||||
|
||||
BIO_free_all(bio);
|
||||
BN_free(bignum);
|
||||
return { result.begin(), result.end() };
|
||||
}
|
||||
|
||||
std::string X509NameToString(X509_NAME* name)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
|
||||
auto str_size = BIO_number_written(bio);
|
||||
|
||||
std::string result(str_size, '\0');
|
||||
BIO_read(bio, (void*)result.data(), result.size());
|
||||
BIO_free_all(bio);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* If PKCS7 cannot be created it throws otherwise returns valid pointer */
|
||||
PKCS7* getPkcs7(const std::vector<unsigned char>& input)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio || BIO_reset(bio) != 1 ||
|
||||
BIO_write(bio, input.data(), static_cast<int>(input.size())) != static_cast<std::int64_t>(input.size())) {
|
||||
BIO_free(bio);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PKCS7* pkcs7 = d2i_PKCS7_bio(bio, nullptr);
|
||||
|
||||
BIO_free(bio);
|
||||
return pkcs7;
|
||||
}
|
||||
|
||||
} // namespace authenticode
|
30
src/fileformat/file_format/pe/authenticode/helper.h
Normal file
30
src/fileformat/file_format/pe/authenticode/helper.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/helper.h
|
||||
* @brief Helper functions used for Authenticode components
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "authenticode_structs.h"
|
||||
#include "x509_certificate.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ocsp.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
std::string bytesToHexString(const std::uint8_t* in, int len);
|
||||
std::string parsePublicKey(BIO* bio);
|
||||
std::string serialToString(ASN1_INTEGER* serial);
|
||||
std::string X509NameToString(X509_NAME* name);
|
||||
std::string parseDateTime(const ASN1_TIME* dateTime);
|
||||
PKCS7* getPkcs7(const std::vector<unsigned char>& input);
|
||||
void calculateDigest(const EVP_MD* md, const std::uint8_t* data, int len, std::uint8_t* digest);
|
||||
|
||||
} // namespace authenticode
|
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/ms_counter_signature.cpp
|
||||
* @brief Representation of MsCounterSignature
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "ms_counter_signature.h"
|
||||
#include "x509_certificate.h"
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
MsCounterSignature::MsCounterSignature(const std::vector<std::uint8_t>& data)
|
||||
: pkcs7(nullptr, PKCS7_free), tstInfo(nullptr, TS_TST_INFO_free), signers(nullptr, sk_X509_free)
|
||||
{
|
||||
pkcs7.reset(getPkcs7(data));
|
||||
if (!pkcs7) {
|
||||
return;
|
||||
}
|
||||
|
||||
tstInfo.reset(PKCS7_to_TS_TST_INFO(pkcs7.get()));
|
||||
if (!tstInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ASN1_TIME* raw_time = TS_TST_INFO_get_time(tstInfo.get());
|
||||
|
||||
if (raw_time) {
|
||||
signTime = parseDateTime(raw_time);
|
||||
}
|
||||
signers.reset(PKCS7_get0_signers(pkcs7.get(), pkcs7->d.sign->cert, 0));
|
||||
auto signerCount = sk_X509_num(signers.get());
|
||||
if (signerCount != 1) {
|
||||
return;
|
||||
}
|
||||
certs = pkcs7->d.sign->cert;
|
||||
signCert = sk_X509_value(signers.get(), 0);
|
||||
imprint = TS_TST_INFO_get_msg_imprint(tstInfo.get());
|
||||
|
||||
X509_ALGOR* digest_algo = TS_MSG_IMPRINT_get_algo(imprint);
|
||||
digestAlgorithm = OBJ_obj2nid(digest_algo->algorithm);
|
||||
|
||||
ASN1_STRING* raw_digest = TS_MSG_IMPRINT_get_msg(imprint);
|
||||
messageDigest = std::vector<std::uint8_t>(raw_digest->data, raw_digest->data + raw_digest->length);
|
||||
}
|
||||
|
||||
std::vector<std::string> MsCounterSignature::verify(const std::vector<std::uint8_t>& sig_enc_content) const
|
||||
{
|
||||
std::vector<std::string> warnings;
|
||||
|
||||
if (!pkcs7) {
|
||||
warnings.emplace_back("Couldn't parse signature");
|
||||
return warnings;
|
||||
}
|
||||
|
||||
if (messageDigest.empty()) {
|
||||
warnings.emplace_back("Failed to verify the counter-signature, no message digest");
|
||||
return warnings;
|
||||
}
|
||||
|
||||
const EVP_MD* md = EVP_get_digestbynid(digestAlgorithm);
|
||||
if (!md) {
|
||||
warnings.emplace_back("Unknown digest algorithm");
|
||||
return warnings;
|
||||
}
|
||||
std::uint8_t digest[EVP_MAX_MD_SIZE] = { 0 };
|
||||
calculateDigest(md, sig_enc_content.data(), sig_enc_content.size(), digest);
|
||||
|
||||
int md_len = EVP_MD_size(md);
|
||||
if (std::memcmp(digest, messageDigest.data(), md_len)) {
|
||||
warnings.emplace_back("Failed to verify the signature with counter-signature");
|
||||
}
|
||||
|
||||
TS_VERIFY_CTX* ctx = TS_VERIFY_CTX_new();
|
||||
X509_STORE* store = X509_STORE_new();
|
||||
TS_VERIFY_CTX_init(ctx);
|
||||
|
||||
TS_VERIFY_CTX_set_flags(ctx, TS_VFY_VERSION | TS_VFY_IMPRINT);
|
||||
TS_VERIFY_CTX_set_store(ctx, store);
|
||||
TS_VERIFY_CTS_set_certs(ctx, pkcs7->d.sign->cert);
|
||||
TS_VERIFY_CTX_set_imprint(ctx, digest, md_len);
|
||||
|
||||
bool is_valid = TS_RESP_verify_token(ctx, pkcs7.get()) == 1;
|
||||
|
||||
/* VERIFY_CTX_free tries to free these, we don't want that */
|
||||
TS_VERIFY_CTX_set_imprint(ctx, nullptr, 0);
|
||||
TS_VERIFY_CTS_set_certs(ctx, nullptr);
|
||||
|
||||
TS_VERIFY_CTX_free(ctx);
|
||||
|
||||
if (!is_valid) {
|
||||
warnings.emplace_back("Failed to verify the counter-signature");
|
||||
}
|
||||
|
||||
/* Verify signature with PKCS7_signatureVerify
|
||||
because TS_RESP_verify_token tries to verify
|
||||
chain and without trust anchors it fails */
|
||||
BIO* p7bio = PKCS7_dataInit(pkcs7.get(), NULL);
|
||||
|
||||
char buf[4096];
|
||||
/* We now have to 'read' from p7bio to calculate digests etc. */
|
||||
while (BIO_read(p7bio, buf, sizeof(buf)) > 0)
|
||||
continue;
|
||||
|
||||
STACK_OF(PKCS7_SIGNER_INFO)* sinfos = PKCS7_get_signer_info(pkcs7.get());
|
||||
PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(sinfos, 0);
|
||||
|
||||
is_valid = PKCS7_signatureVerify(p7bio, pkcs7.get(), si, const_cast<X509*>(signCert)) == 1;
|
||||
if (!is_valid) {
|
||||
warnings.emplace_back("Failed to verify the counter-signature");
|
||||
}
|
||||
|
||||
BIO_free_all(p7bio);
|
||||
return warnings;
|
||||
}
|
||||
|
||||
} // namespace authenticode
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/ms_counter_signature.h
|
||||
* @brief Representation of MsCounterSignature
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "helper.h"
|
||||
|
||||
#include <memory>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
class MsCounterSignature
|
||||
{
|
||||
std::unique_ptr<PKCS7, decltype(&PKCS7_free)> pkcs7;
|
||||
std::unique_ptr<TS_TST_INFO, decltype(&TS_TST_INFO_free)> tstInfo;
|
||||
std::unique_ptr<STACK_OF(X509), decltype(&sk_X509_free)> signers;
|
||||
TS_MSG_IMPRINT* imprint = nullptr;
|
||||
|
||||
public:
|
||||
const X509* signCert = nullptr;
|
||||
const STACK_OF(X509)* certs = nullptr;
|
||||
|
||||
std::string signTime;
|
||||
std::vector<std::uint8_t> messageDigest;
|
||||
int digestAlgorithm = 0;
|
||||
|
||||
std::vector<std::string> verify(const std::vector<std::uint8_t>& sig_enc_content) const;
|
||||
MsCounterSignature(const std::vector<std::uint8_t>& data);
|
||||
};
|
||||
|
||||
} // namespace authenticode
|
622
src/fileformat/file_format/pe/authenticode/pkcs7_signature.cpp
Normal file
622
src/fileformat/file_format/pe/authenticode/pkcs7_signature.cpp
Normal file
@ -0,0 +1,622 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/pkcs7_signature.cpp
|
||||
* @brief Class wrapper above openssl Pkcs7
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "pkcs7_signature.h"
|
||||
#include "helper.h"
|
||||
#include "x509_certificate.h"
|
||||
#include <algorithm>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <string>
|
||||
|
||||
using namespace retdec::fileformat;
|
||||
|
||||
static const int NID_spc_nested_signature =
|
||||
OBJ_create("1.3.6.1.4.1.311.2.4.1", "spcNestedSignature", "SPC_NESTED_SIGNATURE (Authenticode)");
|
||||
static const int NID_spc_ms_countersignature =
|
||||
OBJ_create("1.3.6.1.4.1.311.3.3.1", "spcMsCountersignature", "SPC_MICROSOFT_COUNTERSIGNATURE (Authenticode)");
|
||||
static const int NID_spc_indirect_data =
|
||||
OBJ_create("1.3.6.1.4.1.311.2.1.4", "spcIndirectData", "SPC_INDIRECT_DATA (Authenticode)");
|
||||
static const int NID_spc_sp_opus_info_objid =
|
||||
OBJ_create("1.3.6.1.4.1.311.2.1.12)", "SPC_SP_OPUS_INFO_OBJID", "SPC_SP_OPUS_INFO_OBJID (Authenticode)");
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
/* naming is hard */
|
||||
static std::vector<Certificate> convertToFileformatCertChain(std::vector<X509Certificate> chain)
|
||||
{
|
||||
std::vector<Certificate> fileformat_chain;
|
||||
for (auto&& cert : chain) {
|
||||
fileformat_chain.push_back(cert.createCertificate());
|
||||
}
|
||||
return fileformat_chain;
|
||||
}
|
||||
|
||||
Pkcs7Signature::ContentInfo::ContentInfo(const PKCS7* contents)
|
||||
{
|
||||
/*
|
||||
ContentInfo ::= SEQUENCE {
|
||||
contentType ContentType,
|
||||
content
|
||||
[0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
|
||||
ContentType ::= OBJECT IDENTIFIER
|
||||
// contentType must be set to SPC_INDIRECT_DATA_OBJID (1.3.6.1.4.1.311.2.1.4)
|
||||
SpcIndirectDataContent ::= SEQUENCE {
|
||||
data SpcAttributeTypeAndOptionalValue,
|
||||
messageDigest DigestInfo
|
||||
} --#public—
|
||||
SpcAttributeTypeAndOptionalValue ::= SEQUENCE {
|
||||
type ObjectID,
|
||||
value [0] EXPLICIT ANY OPTIONAL
|
||||
}
|
||||
DigestInfo ::= SEQUENCE {
|
||||
digestAlgorithm AlgorithmIdentifier,
|
||||
digest OCTETSTRING
|
||||
}
|
||||
AlgorithmIdentifier ::= SEQUENCE {
|
||||
algorithm ObjectID,
|
||||
parameters [0] EXPLICIT ANY OPTIONAL
|
||||
}
|
||||
*/
|
||||
if (!contents) {
|
||||
return;
|
||||
}
|
||||
|
||||
contentType = OBJ_obj2nid(contents->type);
|
||||
|
||||
if (contentType != NID_spc_indirect_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = contents->d.other->value.sequence->length;
|
||||
const unsigned char* data = contents->d.other->value.sequence->data;
|
||||
|
||||
auto* spcContent = SpcIndirectDataContent_new();
|
||||
if (!spcContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
d2i_SpcIndirectDataContent(&spcContent, &data, len);
|
||||
if (!spcContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
digest = bytesToHexString(spcContent->messageDigest->digest->data, spcContent->messageDigest->digest->length);
|
||||
|
||||
digestAlgorithm = OBJ_obj2nid(spcContent->messageDigest->digestAlgorithm->algorithm);
|
||||
|
||||
SpcIndirectDataContent_free(spcContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parses out bytes into a PKCS7 and other objects that are stored inside (countersignatures etc.)
|
||||
*
|
||||
* @param input
|
||||
*/
|
||||
Pkcs7Signature::Pkcs7Signature(const std::vector<std::uint8_t>& input) noexcept
|
||||
: pkcs7(nullptr, PKCS7_free)
|
||||
{
|
||||
/*
|
||||
SignedData ::= SEQUENCE {
|
||||
version Version, (Must be 1)
|
||||
digestAlgorithms DigestAlgorithmIdentifiers,
|
||||
contentInfo ContentInfo,
|
||||
certificates
|
||||
[0] IMPLICIT ExtendedCertificatesAndCertificates
|
||||
OPTIONAL,
|
||||
Crls
|
||||
[1] IMPLICIT CertificateRevocationLists OPTIONAL, (Not used in AC)
|
||||
signerInfos SignerInfos }
|
||||
|
||||
DigestAlgorithmIdentifiers ::= (1 structure for each signer)
|
||||
SET OF DigestAlgorithmIdentifier
|
||||
|
||||
ContentInfo ::= SEQUENCE {
|
||||
contentType ContentType,
|
||||
content (Must be SpcIndirectDataContent)
|
||||
[0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
|
||||
|
||||
ContentType ::= OBJECT IDENTIFIER
|
||||
SignerInfos ::= SET OF SignerInfo (Only one signer is supported)
|
||||
|
||||
Source for the parsing constraints is in the MS Authenticode spec
|
||||
https://www.symbolcrash.com/wp-content/uploads/2019/02/Authenticode_PE-1.pdf
|
||||
*/
|
||||
pkcs7.reset(getPkcs7(input));
|
||||
|
||||
if (!pkcs7) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Authenticode uses SignedData Pkcs7 type, check if that complies */
|
||||
if (!PKCS7_type_is_signed(pkcs7)) {
|
||||
return;
|
||||
}
|
||||
|
||||
STACK_OF(X509_ALGOR)* algos = pkcs7->d.sign->md_algs;
|
||||
/* Must be exactly 1 signer and for each signer there is one algorithm */
|
||||
int alg_count = sk_X509_ALGOR_num(algos);
|
||||
for (int i = 0; i < alg_count; i++) {
|
||||
contentDigestAlgorithms.emplace_back(OBJ_obj2nid(sk_X509_ALGOR_value(algos, i)->algorithm));
|
||||
}
|
||||
|
||||
/* Parse the content info */
|
||||
contentInfo.emplace(pkcs7->d.sign->contents);
|
||||
|
||||
ASN1_INTEGER_get_uint64(&version, pkcs7->d.sign->version);
|
||||
|
||||
/* Parse the certificate data into internal structures */
|
||||
const STACK_OF(X509)* certs = pkcs7->d.sign->cert;
|
||||
|
||||
int cert_count = sk_X509_num(certs);
|
||||
for (size_t i = 0; i < cert_count; i++) {
|
||||
X509Certificate cert(sk_X509_value(certs, i));
|
||||
certificates.push_back(cert);
|
||||
}
|
||||
|
||||
STACK_OF(PKCS7_SIGNER_INFO)* signer_infos = PKCS7_get_signer_info(pkcs7.get());
|
||||
if (signer_infos && sk_PKCS7_SIGNER_INFO_num(signer_infos) > 0) {
|
||||
signerInfo.emplace(pkcs7.get(), sk_PKCS7_SIGNER_INFO_value(signer_infos, 0), certs);
|
||||
}
|
||||
}
|
||||
|
||||
Pkcs7Signature::SignerInfo::SignerInfo(const PKCS7* pkcs7, const PKCS7_SIGNER_INFO* si_info, const STACK_OF(X509)* raw_certs)
|
||||
: raw_signers(nullptr, sk_X509_free), sinfo(si_info)
|
||||
{
|
||||
/*
|
||||
SignerInfo ::= SEQUENCE {
|
||||
version Version,
|
||||
issuerAndSerialNumber IssuerAndSerialNumber,
|
||||
digestAlgorithm DigestAlgorithmIdentifier,
|
||||
authenticatedAttributes
|
||||
[0] IMPLICIT Attributes OPTIONAL,
|
||||
digestEncryptionAlgorithm
|
||||
DigestEncryptionAlgorithmIdentifier,
|
||||
encryptedDigest EncryptedDigest,
|
||||
unauthenticatedAttributes
|
||||
[1] IMPLICIT Attributes OPTIONAL }
|
||||
IssuerAndSerialNumber ::= SEQUENCE {
|
||||
issuer Name,
|
||||
serialNumber CertificateSerialNumber }
|
||||
EncryptedDigest ::= OCTET STRING
|
||||
*/
|
||||
/*
|
||||
"Because Authenticode signatures support only one signer,"
|
||||
https://www.symbolcrash.com/wp-content/uploads/2019/02/Authenticode_PE-1.pdf page 7
|
||||
*/
|
||||
|
||||
X509_ALGOR* digestAlgo = si_info->digest_alg;
|
||||
X509_ALGOR* digestEncryptAlgo = si_info->digest_enc_alg;
|
||||
|
||||
digestAlgorithm = OBJ_obj2nid(digestAlgo->algorithm);
|
||||
digestEncryptAlgorithm = OBJ_obj2nid(digestEncryptAlgo->algorithm);
|
||||
|
||||
encryptDigest = std::vector<std::uint8_t>(si_info->enc_digest->data,
|
||||
si_info->enc_digest->data + si_info->enc_digest->length);
|
||||
|
||||
ASN1_INTEGER_get_uint64(&version, si_info->version);
|
||||
/* Version has to be equal to 1 */
|
||||
|
||||
serial = serialToString(si_info->issuer_and_serial->serial);
|
||||
issuer = X509NameToString(si_info->issuer_and_serial->issuer);
|
||||
|
||||
parseUnauthAttrs(si_info, raw_certs);
|
||||
parseAuthAttrs(si_info);
|
||||
|
||||
/* Get the signer certificate */
|
||||
raw_signers.reset(PKCS7_get0_signers(const_cast<PKCS7*>(pkcs7), const_cast<STACK_OF(X509)*>(raw_certs), 0));
|
||||
|
||||
if (!raw_signers) {
|
||||
return;
|
||||
}
|
||||
|
||||
int signers_count = sk_X509_num(raw_signers.get());
|
||||
/* This by logic shouldn't happen as above we established there is single SignerInfo,
|
||||
but I am not completely sure so I'll keep it here for a while */
|
||||
if (signers_count != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
signerCert = sk_X509_value(raw_signers.get(), 0);
|
||||
if (!signerCert) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
void Pkcs7Signature::SignerInfo::parseAuthAttrs(const PKCS7_SIGNER_INFO* si_info)
|
||||
{
|
||||
for (int j = 0; j < sk_X509_ATTRIBUTE_num(si_info->auth_attr); ++j) {
|
||||
X509_ATTRIBUTE* attr = sk_X509_ATTRIBUTE_value(si_info->auth_attr, j);
|
||||
ASN1_TYPE* attr_type = X509_ATTRIBUTE_get0_type(attr, 0);
|
||||
ASN1_OBJECT* attr_object = X509_ATTRIBUTE_get0_object(attr);
|
||||
|
||||
if (!attr_object || !attr_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto attr_object_nid = OBJ_obj2nid(attr_object);
|
||||
char buf[100]; /* 100 should be more than enough for any oid - openssl docs */
|
||||
if (attr_object_nid == NID_pkcs9_contentType) {
|
||||
/*
|
||||
ContentType ::= OBJECT IDENTIFIER
|
||||
*/
|
||||
OBJ_obj2txt(buf, 100, attr_type->value.object, 0);
|
||||
contentType = std::string(buf, buf + strlen(buf));
|
||||
}
|
||||
else if (attr_object_nid == NID_pkcs9_messageDigest) {
|
||||
/*
|
||||
MessageDigest ::= OCTET STRING
|
||||
*/
|
||||
messageDigest = bytesToHexString(attr_type->value.asn1_string->data, attr_type->value.asn1_string->length);
|
||||
}
|
||||
else if (attr_object_nid == NID_spc_sp_opus_info_objid) {
|
||||
/*
|
||||
SpcSpOpusInfo ::= SEQUENCE {
|
||||
programName [0] EXPLICIT SpcString OPTIONAL,
|
||||
moreInfo [1] EXPLICIT SpcLink OPTIONAL,
|
||||
} --#public--
|
||||
*/
|
||||
spcInfo = SpcSpOpusInfo((const unsigned char*)attr_type->value.sequence->data, attr_type->value.sequence->length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pkcs7Signature::SignerInfo::parseUnauthAttrs(const PKCS7_SIGNER_INFO* si_info, const STACK_OF(X509)* raw_certs)
|
||||
{
|
||||
for (int j = 0; j < sk_X509_ATTRIBUTE_num(si_info->unauth_attr); ++j) {
|
||||
X509_ATTRIBUTE* attr = sk_X509_ATTRIBUTE_value(si_info->unauth_attr, j);
|
||||
ASN1_TYPE* attr_type = X509_ATTRIBUTE_get0_type(attr, 0);
|
||||
ASN1_OBJECT* attr_object = X509_ATTRIBUTE_get0_object(attr);
|
||||
if (!attr_object) {
|
||||
continue;
|
||||
}
|
||||
auto attr_object_nid = OBJ_obj2nid(attr_object);
|
||||
|
||||
if (attr_object_nid == NID_spc_nested_signature) {
|
||||
std::vector<std::uint8_t> nested_sig_data(attr_type->value.sequence->data,
|
||||
attr_type->value.sequence->data + attr_type->value.sequence->length);
|
||||
|
||||
nestedSignatures.emplace_back(nested_sig_data);
|
||||
}
|
||||
else if (attr_object_nid == NID_pkcs9_countersignature) {
|
||||
std::vector<std::uint8_t> countersig_data(attr_type->value.sequence->data,
|
||||
attr_type->value.sequence->data + attr_type->value.sequence->length);
|
||||
|
||||
counterSignatures.emplace_back(countersig_data, raw_certs);
|
||||
}
|
||||
else if (attr_object_nid == NID_spc_ms_countersignature) {
|
||||
std::vector<std::uint8_t> countersig_data(attr_type->value.sequence->data,
|
||||
attr_type->value.sequence->data + attr_type->value.sequence->length);
|
||||
|
||||
msCounterSignatures.emplace_back(countersig_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const PKCS7_SIGNER_INFO* Pkcs7Signature::SignerInfo::getSignerInfo() const
|
||||
{
|
||||
return sinfo;
|
||||
}
|
||||
|
||||
Pkcs7Signature::SpcSpOpusInfo::SpcSpOpusInfo(const unsigned char* data, int len) noexcept
|
||||
{
|
||||
/*
|
||||
SpcSpOpusInfo ::= SEQUENCE {
|
||||
programName [0] EXPLICIT SpcString OPTIONAL,
|
||||
moreInfo [1] EXPLICIT SpcLink OPTIONAL,
|
||||
} --#public--
|
||||
|
||||
SpcLink ::= CHOICE {
|
||||
url [0] IMPLICIT IA5STRING,
|
||||
moniker [1] IMPLICIT SpcSerializedObject,
|
||||
file [2] EXPLICIT SpcString
|
||||
} --#public--
|
||||
|
||||
SpcString ::= CHOICE {
|
||||
unicode [0] IMPLICIT BMPSTRING,
|
||||
ascii [1] IMPLICIT IA5STRING
|
||||
}
|
||||
*/
|
||||
::SpcSpOpusInfo* spcInfo = SpcSpOpusInfo_new();
|
||||
if (!spcInfo) {
|
||||
return;
|
||||
}
|
||||
d2i_SpcSpOpusInfo(&spcInfo, &data, len);
|
||||
if (!spcInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spcInfo->programName) {
|
||||
/* name is ascii string or utf16 string */
|
||||
if (spcInfo->programName->type) {
|
||||
programName = std::string(spcInfo->programName->value.ascii->data, spcInfo->programName->value.ascii->data + spcInfo->programName->value.ascii->length);
|
||||
}
|
||||
else {
|
||||
unsigned char* data = nullptr;
|
||||
int len = ASN1_STRING_to_UTF8(&data, spcInfo->programName->value.unicode);
|
||||
if (len >= 0) {
|
||||
programName = std::string(data, data + len);
|
||||
OPENSSL_free(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
SpcSpOpusInfo_free(spcInfo);
|
||||
}
|
||||
|
||||
const X509* Pkcs7Signature::SignerInfo::getSignerCert() const
|
||||
{
|
||||
return signerCert;
|
||||
}
|
||||
|
||||
/* verifies if signature complies with specification rules,
|
||||
for each broken rule, create a message in this->warnings */
|
||||
std::vector<std::string> Pkcs7Signature::verify(const std::string& fileDigest) const
|
||||
{
|
||||
/* Check if signature is correctly parsed and complies with the spec:
|
||||
- [x] Version is equal to 1
|
||||
- [x] contentDigestAlgorithms contain single algorithm
|
||||
- [x] SignedData and SignerInfo digestAlgorithm match
|
||||
- [x] contentInfo contains PE hash, hashing algorithm and SpcIndirectDataOid
|
||||
- [x] SignerInfo contains signer cert
|
||||
- [x] Authenticated attributes contains all the necessary information:
|
||||
- [x] ContentType with PKCS9 MessageDigest OID value
|
||||
- [x] MessageDigest contains correct hash value of PKCS7 SignedData
|
||||
- [x] SpcSpOpusInfo
|
||||
- [x] Decrypted encryptedDigest math calculated hash of authenticated attributes
|
||||
- [x] fileDigest match the signature digest
|
||||
*/
|
||||
std::vector<std::string> warnings;
|
||||
|
||||
/* Verification of the signature SignedData contents */
|
||||
if (!pkcs7) { // no sense to continue
|
||||
warnings.emplace_back("Couldn't parse the Pkcs7 signature");
|
||||
return warnings;
|
||||
}
|
||||
|
||||
if (!PKCS7_type_is_signed(pkcs7)) {
|
||||
warnings.emplace_back("Invalid PKCS#7 type, expected SignedData");
|
||||
}
|
||||
|
||||
if (version != 1) {
|
||||
warnings.emplace_back("Signature version is: " + std::to_string(version) + ", expected 1");
|
||||
}
|
||||
|
||||
if (contentDigestAlgorithms.size() != 1) {
|
||||
warnings.emplace_back("Invalid number of DigestAlgorithmIdentifiers: " + std::to_string(contentDigestAlgorithms.size()) + " - expected 1");
|
||||
}
|
||||
|
||||
if (contentInfo) {
|
||||
if (contentInfo->contentType != NID_spc_indirect_data) {
|
||||
warnings.emplace_back("Wrong contentInfo contentType");
|
||||
}
|
||||
else if (contentInfo->digest.empty()) {
|
||||
warnings.emplace_back("Signature digest is missing");
|
||||
}
|
||||
else {
|
||||
if (fileDigest != contentInfo->digest) {
|
||||
warnings.emplace_back("Signature digest doesn't match the file digest");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnings.emplace_back("Couldn't get contentInfo");
|
||||
}
|
||||
|
||||
if (signerInfo) {
|
||||
if (!signerInfo->getSignerCert()) {
|
||||
warnings.emplace_back("Signing cert is missing");
|
||||
}
|
||||
if (signerInfo->version != 1) {
|
||||
warnings.emplace_back("SignerInfo version is: " + std::to_string(signerInfo->version) + ", expected 1");
|
||||
}
|
||||
if (contentDigestAlgorithms.size() > 0 && signerInfo->digestAlgorithm != contentDigestAlgorithms[0]) {
|
||||
warnings.emplace_back("SignedData digest algorithm and signerInfo digest algorithm don't match");
|
||||
}
|
||||
if (signerInfo->encryptDigest.empty()) {
|
||||
warnings.emplace_back("Encrypted digest is empty");
|
||||
}
|
||||
|
||||
// verify auth attrs existence
|
||||
if (!signerInfo->spcInfo) {
|
||||
warnings.emplace_back("Couldn't get SpcSpOpusInfo");
|
||||
}
|
||||
if (signerInfo->messageDigest.empty()) {
|
||||
warnings.emplace_back("Couldn't get SignerInfo message digest");
|
||||
}
|
||||
if (signerInfo->contentType.empty()) {
|
||||
warnings.emplace_back("Missing correct SignerInfo contentType");
|
||||
}
|
||||
if (!signerInfo->encryptDigest.empty() && signerInfo->getSignerCert() && contentInfo && pkcs7->d.sign->contents->d.data) {
|
||||
/* Verify the signer hash and it's encryptedDigest */
|
||||
const auto* data_ptr = pkcs7->d.sign->contents->d.other->value.sequence->data;
|
||||
long data_len = pkcs7->d.sign->contents->d.other->value.sequence->length;
|
||||
if (version == 1) {
|
||||
int pclass = 0, ptag = 0;
|
||||
ASN1_get_object(&data_ptr, &data_len, &ptag, &pclass, data_len);
|
||||
}
|
||||
|
||||
BIO* content_bio = BIO_new_mem_buf(data_ptr, data_len);
|
||||
BIO* p7bio = PKCS7_dataInit(pkcs7.get(), content_bio);
|
||||
|
||||
char buf[4096];
|
||||
/* We now have to 'read' from p7bio to calculate digests etc. */
|
||||
while (BIO_read(p7bio, buf, sizeof(buf)) > 0)
|
||||
continue;
|
||||
|
||||
bool is_valid = PKCS7_signatureVerify(p7bio, pkcs7.get(), const_cast<PKCS7_SIGNER_INFO*>(signerInfo->getSignerInfo()), const_cast<X509*>(signerInfo->getSignerCert())) == 1;
|
||||
if (!is_valid) {
|
||||
warnings.emplace_back("Signature isn't valid");
|
||||
}
|
||||
|
||||
BIO_free_all(p7bio);
|
||||
}
|
||||
else {
|
||||
warnings.emplace_back("Signature isn't valid");
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnings.emplace_back("Couldn't get SignerInfo");
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the digest using selected hash algorithm.
|
||||
* @param peFile PE file with the signature.
|
||||
* @return Hex string of hash.
|
||||
*
|
||||
* Function assumes the contentInfo is correctly parsed
|
||||
*/
|
||||
std::string Pkcs7Signature::calculateFileDigest(const retdec::fileformat::PeFormat* peFile) const
|
||||
{
|
||||
if (!peFile) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const EVP_MD* algorithm = EVP_get_digestbynid(contentInfo->digestAlgorithm);
|
||||
if (!algorithm) {
|
||||
return {};
|
||||
}
|
||||
EVP_MD_CTX* ctx = EVP_MD_CTX_create();
|
||||
|
||||
if (EVP_DigestInit(ctx, algorithm) != 1) // 1 == success
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto digestRanges = peFile->getDigestRanges();
|
||||
for (const auto& range : digestRanges) {
|
||||
const std::uint8_t* data = std::get<0>(range);
|
||||
std::size_t size = std::get<1>(range);
|
||||
|
||||
if (EVP_DigestUpdate(ctx, data, size) != 1) // 1 == success
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> hash(EVP_MD_size(algorithm));
|
||||
if (EVP_DigestFinal(ctx, hash.data(), nullptr) != 1) {
|
||||
return {};
|
||||
}
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
|
||||
return bytesToHexString(hash.data(), EVP_MD_size(algorithm));
|
||||
}
|
||||
|
||||
std::vector<DigitalSignature> Pkcs7Signature::getSignatures(const retdec::fileformat::PeFormat* peFile) const
|
||||
{
|
||||
std::vector<DigitalSignature> signatures;
|
||||
|
||||
CertificateProcessor processor;
|
||||
|
||||
std::string fileDigest;
|
||||
|
||||
DigitalSignature signature;
|
||||
if (contentInfo.has_value()) {
|
||||
signature.signedDigest = contentInfo->digest;
|
||||
signature.digestAlgorithm = OBJ_nid2ln(contentInfo->digestAlgorithm);
|
||||
fileDigest = calculateFileDigest(peFile);
|
||||
}
|
||||
|
||||
signature.fileDigest = fileDigest;
|
||||
signature.warnings = verify(fileDigest);
|
||||
signature.certificates = getAllCertificates();
|
||||
|
||||
/* No signer would mean, we have pretty much nothing */
|
||||
if (!signerInfo.has_value()) {
|
||||
signatures.push_back(signature);
|
||||
return signatures;
|
||||
}
|
||||
|
||||
if (signerInfo.has_value() && signerInfo->spcInfo.has_value()) {
|
||||
signature.programName = signerInfo->spcInfo->programName;
|
||||
}
|
||||
|
||||
const SignerInfo& signInfo = signerInfo.value();
|
||||
STACK_OF(X509)* certs = pkcs7->d.sign->cert;
|
||||
|
||||
const X509* signer_cert = signInfo.getSignerCert();
|
||||
Signer signer;
|
||||
if (signer_cert) {
|
||||
std::vector<X509Certificate> chain = processor.getChain(signer_cert, certs);
|
||||
auto fileformat_chain = convertToFileformatCertChain(chain);
|
||||
signer.chain = fileformat_chain;
|
||||
}
|
||||
signer.digest = signInfo.messageDigest;
|
||||
signer.digestAlgorithm = OBJ_nid2ln(signInfo.digestAlgorithm);
|
||||
|
||||
signature.signer = signer;
|
||||
|
||||
for (auto&& counterSig : signInfo.counterSignatures) {
|
||||
CertificateProcessor processor;
|
||||
auto certChain = processor.getChain(counterSig.signerCert, certs);
|
||||
auto fileformatCertChain = convertToFileformatCertChain(certChain);
|
||||
|
||||
Signer counterSigner;
|
||||
counterSigner.chain = fileformatCertChain;
|
||||
counterSigner.signingTime = counterSig.signTime,
|
||||
counterSigner.digest = bytesToHexString(counterSig.messageDigest.data(),
|
||||
counterSig.messageDigest.size()),
|
||||
counterSigner.digestAlgorithm = OBJ_nid2ln(counterSig.digestAlgorithm),
|
||||
counterSigner.warnings = counterSig.verify(signerInfo->encryptDigest),
|
||||
counterSigner.counterSigners = std::vector<Signer>();
|
||||
|
||||
signature.signer.counterSigners.push_back(counterSigner);
|
||||
}
|
||||
|
||||
for (auto&& counterSig : signInfo.msCounterSignatures) {
|
||||
CertificateProcessor processor;
|
||||
auto certChain = processor.getChain(counterSig.signCert, counterSig.certs);
|
||||
auto fileformatCertChain = convertToFileformatCertChain(certChain);
|
||||
|
||||
Signer counterSigner;
|
||||
counterSigner.chain = fileformatCertChain;
|
||||
counterSigner.signingTime = counterSig.signTime,
|
||||
counterSigner.digest = bytesToHexString(counterSig.messageDigest.data(),
|
||||
counterSig.messageDigest.size()),
|
||||
counterSigner.digestAlgorithm = OBJ_nid2ln(counterSig.digestAlgorithm),
|
||||
counterSigner.warnings = counterSig.verify(signerInfo->encryptDigest),
|
||||
counterSigner.counterSigners = std::vector<Signer>();
|
||||
|
||||
signature.signer.counterSigners.push_back(counterSigner);
|
||||
}
|
||||
|
||||
signatures.push_back(signature);
|
||||
|
||||
for (auto&& nestedPkcs7 : signInfo.nestedSignatures) {
|
||||
auto nestedSigs = nestedPkcs7.getSignatures(peFile);
|
||||
signatures.insert(signatures.end(), nestedSigs.begin(), nestedSigs.end());
|
||||
}
|
||||
|
||||
return signatures;
|
||||
}
|
||||
|
||||
/* Returns all certificate, including counter signature, excluding nested signatures */
|
||||
std::vector<Certificate> Pkcs7Signature::getAllCertificates() const
|
||||
{
|
||||
std::vector<X509Certificate> all_x509certs = certificates;
|
||||
|
||||
if (!signerInfo.has_value()) {
|
||||
return convertToFileformatCertChain(all_x509certs);
|
||||
}
|
||||
|
||||
// ms counter signatures have their own collection, add them
|
||||
for (auto&& counterSig : signerInfo->msCounterSignatures) {
|
||||
int cert_count = sk_X509_num(counterSig.certs);
|
||||
for (int i = 0; i < cert_count; i++) {
|
||||
all_x509certs.emplace_back(sk_X509_value(counterSig.certs, i));
|
||||
}
|
||||
}
|
||||
|
||||
return convertToFileformatCertChain(all_x509certs);
|
||||
}
|
||||
} // namespace authenticode
|
124
src/fileformat/file_format/pe/authenticode/pkcs7_signature.h
Normal file
124
src/fileformat/file_format/pe/authenticode/pkcs7_signature.h
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/pkcs7_signature.h
|
||||
* @brief Class wrapper above openssl Pkcs7
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "authenticode_structs.h"
|
||||
#include "helper.h"
|
||||
#include "retdec/fileformat/file_format/pe/pe_format.h"
|
||||
#include "retdec/fileformat/types/certificate_table/certificate.h"
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
#include "x509_certificate.h"
|
||||
#include "pkcs9_counter_signature.h"
|
||||
#include "ms_counter_signature.h"
|
||||
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ocsp.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <cstring>
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
class Pkcs7Signature
|
||||
{
|
||||
struct SpcSpOpusInfo
|
||||
{
|
||||
SpcSpOpusInfo(const unsigned char* data, int len) noexcept;
|
||||
std::string programName; /* utf-8 */
|
||||
};
|
||||
struct ContentInfo
|
||||
{
|
||||
int contentType = 0;
|
||||
int digestAlgorithm = 0;
|
||||
std::string digest;
|
||||
|
||||
ContentInfo(const PKCS7* pkcs7);
|
||||
};
|
||||
class SignerInfo
|
||||
{
|
||||
private:
|
||||
void parseUnauthAttrs(const PKCS7_SIGNER_INFO* si_info, const STACK_OF(X509)* raw_certs);
|
||||
void parseAuthAttrs(const PKCS7_SIGNER_INFO* si_info);
|
||||
|
||||
std::unique_ptr<STACK_OF(X509), decltype(&sk_X509_free)> raw_signers;
|
||||
const X509* signerCert = nullptr;
|
||||
const PKCS7_SIGNER_INFO* sinfo = nullptr;
|
||||
|
||||
public:
|
||||
std::uint64_t version = 0;
|
||||
|
||||
std::string serial;
|
||||
std::string issuer;
|
||||
std::string contentType;
|
||||
std::string messageDigest;
|
||||
std::optional<SpcSpOpusInfo> spcInfo;
|
||||
|
||||
int digestAlgorithm = 0; /* Must be identical to SignedData::digestAlgorithm */
|
||||
int digestEncryptAlgorithm = 0;
|
||||
|
||||
std::vector<std::uint8_t> encryptDigest;
|
||||
std::vector<Pkcs7Signature> nestedSignatures;
|
||||
std::vector<Pkcs9CounterSignature> counterSignatures;
|
||||
std::vector<MsCounterSignature> msCounterSignatures;
|
||||
|
||||
const X509* getSignerCert() const;
|
||||
const PKCS7_SIGNER_INFO* getSignerInfo() const;
|
||||
auto operator=(const SignerInfo&) = delete;
|
||||
SignerInfo(const SignerInfo&) = delete;
|
||||
|
||||
SignerInfo& operator=(SignerInfo&&) noexcept = default;
|
||||
SignerInfo(SignerInfo&&) noexcept = default;
|
||||
|
||||
SignerInfo(const PKCS7* pkcs7, const PKCS7_SIGNER_INFO* si_info, const STACK_OF(X509)* raw_certs);
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<PKCS7, decltype(&PKCS7_free)> pkcs7;
|
||||
|
||||
std::string calculateFileDigest(const retdec::fileformat::PeFormat* peFile) const;
|
||||
std::vector<Certificate> getAllCertificates() const;
|
||||
std::vector<std::string> verify(const std::string& fileDigest) const;
|
||||
|
||||
public:
|
||||
std::uint64_t version = 0;
|
||||
std::optional<ContentInfo> contentInfo;
|
||||
std::optional<SignerInfo> signerInfo;
|
||||
|
||||
std::vector<int> contentDigestAlgorithms;
|
||||
std::vector<X509Certificate> certificates; /* typically no root certificates, timestamp may include root one */
|
||||
|
||||
std::vector<retdec::fileformat::DigitalSignature> getSignatures(const retdec::fileformat::PeFormat* peFile) const;
|
||||
|
||||
Pkcs7Signature& operator=(const Pkcs7Signature&) = delete;
|
||||
Pkcs7Signature(const Pkcs7Signature&) = delete;
|
||||
|
||||
Pkcs7Signature& operator=(Pkcs7Signature&&) noexcept = default;
|
||||
Pkcs7Signature(Pkcs7Signature&&) noexcept = default;
|
||||
|
||||
Pkcs7Signature(const std::vector<std::uint8_t>& input) noexcept;
|
||||
};
|
||||
|
||||
} // namespace authenticode
|
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/pkcs9_counter_signature.cpp
|
||||
* @brief Class that wraps openssl pkcs9 information.
|
||||
* @copyright (c) 2020 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "pkcs9_counter_signature.h"
|
||||
#include "authenticode_structs.h"
|
||||
#include <openssl/objects.h>
|
||||
namespace authenticode {
|
||||
|
||||
/* PKCS7 stores all certificates for the signer and counter signers, we need to pass the certs */
|
||||
Pkcs9CounterSignature::Pkcs9CounterSignature(std::vector<std::uint8_t>& data, const STACK_OF(X509)* certificates)
|
||||
: sinfo(nullptr, PKCS7_SIGNER_INFO_free)
|
||||
{
|
||||
/*
|
||||
counterSignature ATTRIBUTE ::= {
|
||||
WITH SYNTAX SignerInfo
|
||||
ID pkcs-9-at-counterSignature
|
||||
}
|
||||
*/
|
||||
const unsigned char* data_ptr = data.data();
|
||||
sinfo.reset(d2i_PKCS7_SIGNER_INFO(nullptr, &data_ptr, data.size()));
|
||||
if (!sinfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
digestAlgorithm = OBJ_obj2nid(sinfo->digest_alg->algorithm);
|
||||
|
||||
/* get the signer certificate of this counter signatures */
|
||||
signerCert = X509_find_by_issuer_and_serial(const_cast<STACK_OF(X509)*>(certificates),
|
||||
sinfo->issuer_and_serial->issuer, sinfo->issuer_and_serial->serial);
|
||||
|
||||
if (!signerCert) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sk_X509_ATTRIBUTE_num(sinfo->auth_attr); ++i) {
|
||||
X509_ATTRIBUTE* attribute = sk_X509_ATTRIBUTE_value(sinfo->auth_attr, i);
|
||||
ASN1_OBJECT* attribute_object = X509_ATTRIBUTE_get0_object(attribute);
|
||||
ASN1_TYPE* attr_type = X509_ATTRIBUTE_get0_type(attribute, 0);
|
||||
/*
|
||||
Note 2 - A countersignature, since it has type SignerInfo, can itself
|
||||
contain a countersignature attribute. Thus it is possible to
|
||||
construct arbitrarily long series of countersignatures.
|
||||
*/
|
||||
if (OBJ_obj2nid(attribute_object) == NID_pkcs9_countersignature) {
|
||||
auto data = std::vector<std::uint8_t>(attr_type->value.octet_string->data,
|
||||
attr_type->value.octet_string->data + attr_type->value.octet_string->length);
|
||||
counterSignatures.emplace_back(data, certificates);
|
||||
}
|
||||
else if (OBJ_obj2nid(attribute_object) == NID_pkcs9_contentType) {
|
||||
contentType = OBJ_nid2sn(NID_pkcs9_contentType);
|
||||
}
|
||||
|
||||
/* Signing Time (1.2.840.113549.1.9.5) is set to the UTC time of timestamp generation time. */
|
||||
else if (OBJ_obj2nid(attribute_object) == NID_pkcs9_signingTime) {
|
||||
signTime = parseDateTime(attr_type->value.utctime);
|
||||
}
|
||||
/*
|
||||
Message Digest (1.2.840.113549.1.9.4) is set to the hash value of the SignerInfo structure's
|
||||
encryptedDigest value. The hash algorithm that is used to calculate the hash value is the same
|
||||
as that specified in the SignerInfo structure’s digestAlgorithm value of the timestamp.
|
||||
|
||||
MessageDigest ::= OCTET STRING
|
||||
*/
|
||||
else if (OBJ_obj2nid(attribute_object) == NID_pkcs9_messageDigest) {
|
||||
messageDigest = std::vector<std::uint8_t>(attr_type->value.octet_string->data,
|
||||
attr_type->value.octet_string->data + attr_type->value.octet_string->length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Pkcs9CounterSignature::verify(const std::vector<uint8_t>& sig_enc_content) const
|
||||
{
|
||||
std::vector<std::string> warnings;
|
||||
if (!sinfo) {
|
||||
warnings.emplace_back("Couldn't parse counter-signature.");
|
||||
return warnings;
|
||||
}
|
||||
|
||||
if (!signerCert) {
|
||||
warnings.emplace_back("No counter-signature certificate");
|
||||
return warnings;
|
||||
}
|
||||
|
||||
if (contentType.empty()) {
|
||||
warnings.emplace_back("Missing pkcs9 contentType");
|
||||
}
|
||||
|
||||
std::uint8_t* data = nullptr;
|
||||
auto len = ASN1_item_i2d((ASN1_VALUE*)sinfo->auth_attr, &data, ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
|
||||
|
||||
const EVP_MD* md = EVP_get_digestbyobj(sinfo->digest_alg->algorithm);
|
||||
if (!md) {
|
||||
warnings.emplace_back("Unknown digest algorithm");
|
||||
return warnings;
|
||||
}
|
||||
std::uint8_t digest[EVP_MAX_MD_SIZE] = { 0 };
|
||||
calculateDigest(md, data, len, digest);
|
||||
free(data);
|
||||
|
||||
std::uint8_t* enc_data = sinfo->enc_digest->data;
|
||||
int enc_len = sinfo->enc_digest->length;
|
||||
|
||||
auto pkey = X509_get0_pubkey(signerCert);
|
||||
auto ctx = EVP_PKEY_CTX_new(pkey, nullptr);
|
||||
|
||||
std::size_t dec_len = 65536;
|
||||
std::vector<std::uint8_t> dec_data(dec_len);
|
||||
|
||||
EVP_PKEY_verify_recover_init(ctx);
|
||||
bool is_recovered = EVP_PKEY_verify_recover(ctx, dec_data.data(), &dec_len, enc_data, enc_len) == 1;
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
|
||||
if (is_recovered) {
|
||||
int md_len = EVP_MD_size(md);
|
||||
/* compare the encrypted digest and calculated digest */
|
||||
bool is_valid = false;
|
||||
|
||||
/* Sometimes signed data contains DER encoded DigestInfo structure which
|
||||
contains hash of authenticated attributes but other times it is just purely
|
||||
hash and I don't think there's other way to distinguish it but only based on
|
||||
the length of data we get */
|
||||
|
||||
if (md_len == dec_len) {
|
||||
is_valid = !std::memcmp(digest, dec_data.data(), md_len);
|
||||
}
|
||||
else {
|
||||
const std::uint8_t* data_ptr = dec_data.data();
|
||||
DigestInfo* digest_info = d2i_DigestInfo(nullptr, &data_ptr, dec_len);
|
||||
is_valid = !std::memcmp(digest_info->digest->data, digest, md_len);
|
||||
DigestInfo_free(digest_info);
|
||||
}
|
||||
if (!is_valid) {
|
||||
warnings.emplace_back("Failed to verify the counter-signature");
|
||||
}
|
||||
} else {
|
||||
warnings.emplace_back("Couldn't decrypt the digest");
|
||||
}
|
||||
|
||||
/* compare the saved, now verified digest attribute with the signature that it counter signs */
|
||||
if (messageDigest.empty()) {
|
||||
warnings.emplace_back("Message digest is missing");
|
||||
}
|
||||
else {
|
||||
std::memset(digest, 0, EVP_MAX_MD_SIZE);
|
||||
|
||||
calculateDigest(md, sig_enc_content.data(), sig_enc_content.size(), digest);
|
||||
if (std::memcmp(digest, messageDigest.data(), messageDigest.size())) {
|
||||
warnings.emplace_back("Failed to verify the signature with counter-signature");
|
||||
}
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
} // namespace authenticode
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/pkcs9_counter_signature.h
|
||||
* @brief Class that wraps openssl pkcs9 information.
|
||||
* @copyright (c) 2020 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "authenticode_structs.h"
|
||||
#include "x509_certificate.h"
|
||||
#include "helper.h"
|
||||
|
||||
#include <memory>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ocsp.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
class Pkcs9CounterSignature
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<PKCS7_SIGNER_INFO, decltype(&PKCS7_SIGNER_INFO_free)> sinfo;
|
||||
|
||||
public:
|
||||
const X509* signerCert = nullptr;
|
||||
|
||||
std::string contentType;
|
||||
std::string signTime;
|
||||
std::vector<std::uint8_t> messageDigest;
|
||||
int digestAlgorithm = 0;
|
||||
std::vector<Pkcs9CounterSignature> counterSignatures;
|
||||
|
||||
std::vector<std::string> verify(const std::vector<uint8_t>& sig_enc_content) const;
|
||||
Pkcs9CounterSignature(std::vector<std::uint8_t>& data, const STACK_OF(X509)* certificates);
|
||||
};
|
||||
|
||||
} // namespace authenticode
|
247
src/fileformat/file_format/pe/authenticode/x509_certificate.cpp
Normal file
247
src/fileformat/file_format/pe/authenticode/x509_certificate.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/x509_certificate.h
|
||||
* @brief Class that wraps openssl x509 certificate information.
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "x509_certificate.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
#include <string>
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
X509Certificate::X509Certificate(const X509* cert)
|
||||
: cert(cert) {}
|
||||
|
||||
std::string X509Certificate::getSerialNumber() const
|
||||
{
|
||||
ASN1_INTEGER* serial_number_asn1 = X509_get_serialNumber(const_cast<X509*>(cert));
|
||||
BIGNUM* bignum = ASN1_INTEGER_to_BN(serial_number_asn1, nullptr);
|
||||
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
BN_print(bio, bignum);
|
||||
auto data_len = BIO_number_written(bio);
|
||||
|
||||
std::vector<char> result(data_len);
|
||||
BIO_read(bio, static_cast<void*>(result.data()), data_len);
|
||||
BIO_free_all(bio);
|
||||
BN_free(bignum);
|
||||
return { result.begin(), result.end() };
|
||||
}
|
||||
|
||||
std::string X509Certificate::getSignatureAlgorithm() const
|
||||
{
|
||||
auto algo = X509_get0_tbs_sigalg(cert);
|
||||
char name[256] = { '\0' };
|
||||
OBJ_obj2txt(name, 255, algo->algorithm, 0);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string X509Certificate::getValidSince() const
|
||||
{
|
||||
return parseDateTime(X509_get_notBefore(cert));
|
||||
}
|
||||
|
||||
std::string X509Certificate::getValidUntil() const
|
||||
{
|
||||
return parseDateTime(X509_get_notAfter(cert));
|
||||
}
|
||||
|
||||
std::string X509Certificate::getPem() const
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
PEM_write_bio_X509(bio, const_cast<X509*>(cert));
|
||||
auto data_len = BIO_number_written(bio);
|
||||
|
||||
std::vector<char> result(data_len);
|
||||
BIO_read(bio, static_cast<void*>(result.data()), data_len);
|
||||
return { result.begin(), result.end() };
|
||||
}
|
||||
|
||||
Certificate::Attributes parseAttributes(X509_NAME* raw)
|
||||
{
|
||||
Certificate::Attributes attributes;
|
||||
|
||||
std::size_t numEntries = X509_NAME_entry_count(raw);
|
||||
for (std::size_t i = 0; i < numEntries; ++i) {
|
||||
auto nameEntry = X509_NAME_get_entry(raw, int(i));
|
||||
auto valueObj = X509_NAME_ENTRY_get_data(nameEntry);
|
||||
|
||||
std::string key = OBJ_nid2sn(
|
||||
OBJ_obj2nid(X509_NAME_ENTRY_get_object(nameEntry)));
|
||||
std::string value = std::string(
|
||||
reinterpret_cast<const char*>(valueObj->data),
|
||||
valueObj->length);
|
||||
|
||||
if (key == "C")
|
||||
attributes.country = value;
|
||||
else if (key == "O")
|
||||
attributes.organization = value;
|
||||
else if (key == "OU")
|
||||
attributes.organizationalUnit = value;
|
||||
else if (key == "dnQualifier")
|
||||
attributes.nameQualifier = value;
|
||||
else if (key == "ST")
|
||||
attributes.state = value;
|
||||
else if (key == "CN")
|
||||
attributes.commonName = value;
|
||||
else if (key == "serialNumber")
|
||||
attributes.serialNumber = value;
|
||||
else if (key == "L")
|
||||
attributes.locality = value;
|
||||
else if (key == "title")
|
||||
attributes.title = value;
|
||||
else if (key == "SN")
|
||||
attributes.surname = value;
|
||||
else if (key == "GN")
|
||||
attributes.givenName = value;
|
||||
else if (key == "initials")
|
||||
attributes.initials = value;
|
||||
else if (key == "pseudonym")
|
||||
attributes.pseudonym = value;
|
||||
else if (key == "generationQualifier")
|
||||
attributes.generationQualifier = value;
|
||||
else if (key == "emailAddress")
|
||||
attributes.emailAddress = value;
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
Certificate::Attributes X509Certificate::getSubject() const
|
||||
{
|
||||
return parseAttributes(X509_get_subject_name(cert));
|
||||
}
|
||||
Certificate::Attributes X509Certificate::getIssuer() const
|
||||
{
|
||||
return parseAttributes(X509_get_issuer_name(cert));
|
||||
}
|
||||
|
||||
std::string X509Certificate::getPublicKey() const
|
||||
{
|
||||
std::uint8_t* data = nullptr;
|
||||
EVP_PKEY* pkey = X509_get0_pubkey(cert);
|
||||
BIO* memBio = BIO_new(BIO_s_mem());
|
||||
PEM_write_bio_PUBKEY(memBio, pkey);
|
||||
|
||||
std::string result(parsePublicKey(memBio));
|
||||
BIO_free_all(memBio);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string X509Certificate::getPublicKeyAlgorithm() const
|
||||
{
|
||||
const EVP_PKEY* pkey = X509_get0_pubkey(cert);
|
||||
if (!pkey) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
return OBJ_nid2sn(EVP_PKEY_base_id(pkey));
|
||||
}
|
||||
|
||||
std::string X509Certificate::getSha1() const
|
||||
{
|
||||
const int sha1_length = 20;
|
||||
std::uint8_t sha1_bytes[sha1_length];
|
||||
|
||||
std::uint8_t* data = nullptr;
|
||||
int len = i2d_X509(const_cast<X509*>(cert), &data);
|
||||
|
||||
const EVP_MD* md = EVP_sha1();
|
||||
calculateDigest(md, data, len, sha1_bytes);
|
||||
|
||||
free(data);
|
||||
return bytesToHexString(sha1_bytes, sha1_length);
|
||||
}
|
||||
std::string X509Certificate::getSha256() const
|
||||
{
|
||||
const int sha256_length = 32;
|
||||
std::uint8_t sha256_bytes[sha256_length];
|
||||
|
||||
std::uint8_t* data = nullptr;
|
||||
int len = i2d_X509(const_cast<X509*>(cert), &data);
|
||||
|
||||
const EVP_MD* md = EVP_sha256();
|
||||
calculateDigest(md, data, len, sha256_bytes);
|
||||
|
||||
free(data);
|
||||
return bytesToHexString(sha256_bytes, sha256_length);
|
||||
}
|
||||
|
||||
int X509Certificate::getVersion() const
|
||||
{
|
||||
return X509_get_version(cert);
|
||||
}
|
||||
|
||||
std::string X509Certificate::getRawSubject() const
|
||||
{
|
||||
return X509NameToString(X509_get_subject_name(cert));
|
||||
}
|
||||
|
||||
std::string X509Certificate::getRawIssuer() const
|
||||
{
|
||||
return X509NameToString(X509_get_issuer_name(cert));
|
||||
}
|
||||
|
||||
Certificate X509Certificate::createCertificate() const
|
||||
{
|
||||
Certificate out_cert;
|
||||
out_cert.issuerRaw = getRawIssuer();
|
||||
out_cert.subjectRaw = getRawSubject();
|
||||
out_cert.issuer = getIssuer();
|
||||
out_cert.subject = getSubject();
|
||||
out_cert.publicKey = getPublicKey();
|
||||
out_cert.publicKeyAlgo = getPublicKeyAlgorithm();
|
||||
out_cert.signatureAlgo = getSignatureAlgorithm();
|
||||
out_cert.serialNumber = getSerialNumber();
|
||||
out_cert.sha1Digest = getSha1();
|
||||
out_cert.sha256Digest = getSha256();
|
||||
out_cert.validSince = getValidSince();
|
||||
out_cert.validUntil = getValidUntil();
|
||||
return out_cert;
|
||||
}
|
||||
|
||||
CertificateProcessor::CertificateProcessor()
|
||||
: trust_store(nullptr, X509_STORE_free),
|
||||
ctx(nullptr, X509_STORE_CTX_free)
|
||||
{
|
||||
trust_store.reset(X509_STORE_new());
|
||||
ctx.reset(X509_STORE_CTX_new());
|
||||
}
|
||||
|
||||
std::vector<X509Certificate> CertificateProcessor::getChain(const X509* signer, const STACK_OF(X509)* all_certs)
|
||||
{
|
||||
std::vector<X509Certificate> certificates;
|
||||
|
||||
if (!signer) {
|
||||
return certificates;
|
||||
}
|
||||
|
||||
X509_STORE_CTX_init(ctx.get(), trust_store.get(), const_cast<X509*>(signer), const_cast<STACK_OF(X509)*>(all_certs));
|
||||
bool is_valid = X509_verify_cert(ctx.get()) == 1;
|
||||
STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(ctx.get());
|
||||
|
||||
|
||||
int cert_cnt = sk_X509_num(chain);
|
||||
for (int i = 0; i < cert_cnt; i++) {
|
||||
certificates.emplace_back(sk_X509_value(chain, i));
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
const X509_STORE* CertificateProcessor::getStore() const
|
||||
{
|
||||
return trust_store.get();
|
||||
}
|
||||
} // namespace authenticode
|
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file src/fileformat/file_format/pe/authenticode/x509_certificate.h
|
||||
* @brief Class that wraps openssl x509 certificate information.
|
||||
* @copyright (c) 2020 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "retdec/fileformat/types/certificate_table/certificate.h"
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
#include "helper.h"
|
||||
|
||||
#include <memory>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ocsp.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <openssl/x509_vfy.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
|
||||
using retdec::fileformat::Certificate;
|
||||
|
||||
namespace authenticode {
|
||||
|
||||
class X509Certificate
|
||||
{ /* Can't name it X509 due to the collisions with openssl*/
|
||||
private:
|
||||
const X509* cert = nullptr;
|
||||
|
||||
public:
|
||||
X509Certificate(const X509* cert);
|
||||
X509Certificate() = default;
|
||||
|
||||
int getVersion() const;
|
||||
std::string getValidUntil() const;
|
||||
std::string getValidSince() const;
|
||||
std::string getRawSubject() const;
|
||||
std::string getRawIssuer() const;
|
||||
std::string getSerialNumber() const;
|
||||
std::string getSignatureAlgorithm() const;
|
||||
std::string getPublicKey() const;
|
||||
std::string getPublicKeyAlgorithm() const;
|
||||
std::string getPem() const;
|
||||
std::string getSignature() const;
|
||||
std::string getSha1() const;
|
||||
std::string getSha256() const;
|
||||
Certificate::Attributes getSubject() const;
|
||||
Certificate::Attributes getIssuer() const;
|
||||
Certificate createCertificate() const;
|
||||
};
|
||||
|
||||
class CertificateProcessor
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<X509_STORE, decltype(&X509_STORE_free)> trust_store;
|
||||
std::unique_ptr<X509_STORE_CTX, decltype(&X509_STORE_CTX_free)> ctx;
|
||||
|
||||
public:
|
||||
std::vector<X509Certificate> chain;
|
||||
|
||||
CertificateProcessor();
|
||||
|
||||
std::vector<X509Certificate> getChain(const X509* cert, const STACK_OF(X509)* all_certs);
|
||||
const X509_STORE* getStore() const;
|
||||
};
|
||||
|
||||
} // namespace authenticode
|
@ -6,17 +6,17 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <new>
|
||||
#include <regex>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include "authenticode/authenticode.h"
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
#include "retdec/utils/container.h"
|
||||
#include "retdec/utils/conversion.h"
|
||||
#include "retdec/utils/scope_exit.h"
|
||||
@ -503,296 +503,12 @@ Symbol::UsageType getSymbolUsageType(std::uint8_t storageClass, std::uint8_t com
|
||||
return Symbol::UsageType::UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the digest using selected hash algorithm.
|
||||
* @param peFile PE file with the signature.
|
||||
* @param algorithm Algorithm to use.
|
||||
* @return Hex string of hash.
|
||||
*/
|
||||
std::string calculateDigest(
|
||||
const retdec::fileformat::PeFormat* peFile,
|
||||
const EVP_MD* algorithm)
|
||||
{
|
||||
EVP_MD_CTX* ctx = EVP_MD_CTX_create();
|
||||
|
||||
if (EVP_DigestInit(ctx, algorithm) != 1) // 1 == success
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto digestRanges = peFile->getDigestRanges();
|
||||
for (const auto& range : digestRanges)
|
||||
{
|
||||
const std::uint8_t* data = std::get<0>(range);
|
||||
std::size_t size = std::get<1>(range);
|
||||
|
||||
if (EVP_DigestUpdate(ctx, data, size) != 1) // 1 == success
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> hash(EVP_MD_size(algorithm));
|
||||
if (EVP_DigestFinal(ctx, hash.data(), nullptr) != 1)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
|
||||
std::string ret;
|
||||
retdec::utils::bytesToHexString(hash, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies signature of PE file using PKCS7.
|
||||
* @param peFile PE file with the signature.
|
||||
* @param p7 PKCS7 structure.
|
||||
* @return @c true if signature is valid, otherwise @c false.
|
||||
*/
|
||||
bool verifySignature(const retdec::fileformat::PeFormat* peFile, PKCS7 *p7)
|
||||
{
|
||||
// At first, verify that there are data in place where Microsoft Code
|
||||
// Signing should be present
|
||||
if (!p7->d.sign->contents->d.other)
|
||||
return false;
|
||||
|
||||
// We need this because PKCS7_verify() looks up algorithms and without this,
|
||||
// tables are empty
|
||||
OpenSSL_add_all_algorithms();
|
||||
SCOPE_EXIT {
|
||||
EVP_cleanup();
|
||||
};
|
||||
|
||||
// First, check whether the hash written in ContentInfo matches the hash of the whole file
|
||||
auto contentInfoPtr = p7->d.sign->contents->d.other->value.sequence->data;
|
||||
auto contentInfoLen = p7->d.sign->contents->d.other->value.sequence->length;
|
||||
std::vector<std::uint8_t> contentInfoData(contentInfoPtr, contentInfoPtr + contentInfoLen);
|
||||
auto contentInfo = Asn1Item::parse(contentInfoData);
|
||||
if (contentInfo == nullptr)
|
||||
return false;
|
||||
if (!contentInfo->isSequence())
|
||||
return false;
|
||||
|
||||
auto digest = std::static_pointer_cast<Asn1Sequence>(contentInfo)->getElement(1);
|
||||
if (digest == nullptr || !digest->isSequence())
|
||||
return false;
|
||||
|
||||
auto digestSeq = std::static_pointer_cast<Asn1Sequence>(digest);
|
||||
if (digestSeq->getNumberOfElements() != 2)
|
||||
return false;
|
||||
|
||||
auto digestAlgo = digestSeq->getElement(0);
|
||||
auto digestValue = digestSeq->getElement(1);
|
||||
if (!digestAlgo->isSequence() || !digestValue->isOctetString())
|
||||
return false;
|
||||
|
||||
auto digestAlgoSeq = std::static_pointer_cast<Asn1Sequence>(digestAlgo);
|
||||
if (digestAlgoSeq->getNumberOfElements() == 0)
|
||||
return false;
|
||||
|
||||
auto digestAlgoOID = digestAlgoSeq->getElement(0);
|
||||
if (!digestAlgoOID->isObject())
|
||||
return false;
|
||||
|
||||
auto digestAlgoOIDStr = std::static_pointer_cast<Asn1Object>(digestAlgoOID)->getIdentifier();
|
||||
|
||||
const EVP_MD* algorithm = nullptr;
|
||||
if (digestAlgoOIDStr == DigestAlgorithmOID_Sha1)
|
||||
algorithm = EVP_sha1();
|
||||
else if (digestAlgoOIDStr == DigestAlgorithmOID_Sha256)
|
||||
algorithm = EVP_sha256();
|
||||
else if (digestAlgoOIDStr == DigestAlgorithmOID_Md5)
|
||||
algorithm = EVP_md5();
|
||||
else
|
||||
{
|
||||
EVP_cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto storedHash = std::static_pointer_cast<Asn1OctetString>(digestValue)->getString();
|
||||
auto calculatedHash = calculateDigest(peFile, algorithm);
|
||||
if (storedHash != calculatedHash)
|
||||
{
|
||||
EVP_cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto contentData = contentInfo->getContentData();
|
||||
auto contentBio = std::unique_ptr<BIO, decltype(&BIO_free)>(
|
||||
BIO_new_mem_buf(contentData.data(), contentData.size()), &BIO_free);
|
||||
auto emptyTrustStore = std::unique_ptr<X509_STORE, decltype(&X509_STORE_free)>(X509_STORE_new(), &X509_STORE_free);
|
||||
if (PKCS7_verify(p7, p7->d.sign->cert, emptyTrustStore.get(), contentBio.get(), nullptr, PKCS7_NOVERIFY) == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
decltype(auto) managedPtr(T* ptr, Deleter deleter)
|
||||
{
|
||||
return std::unique_ptr<T, Deleter>(ptr, deleter);
|
||||
}
|
||||
|
||||
std::string parseDateTime(ASN1_TIME* dateTime)
|
||||
{
|
||||
if (ASN1_TIME_check(dateTime) == 0)
|
||||
return {};
|
||||
|
||||
auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free);
|
||||
ASN1_TIME_print(memBio.get(), dateTime);
|
||||
|
||||
BUF_MEM* bioMemPtr;
|
||||
BIO_ctrl(memBio.get(), BIO_C_GET_BUF_MEM_PTR, 0, reinterpret_cast<char*>(&bioMemPtr));
|
||||
|
||||
return std::string(bioMemPtr->data, bioMemPtr->length);
|
||||
}
|
||||
|
||||
std::string parsePublicKey(BIO *bio)
|
||||
{
|
||||
std::string key;
|
||||
std::vector<char> tmp(100);
|
||||
|
||||
BIO_gets(bio, tmp.data(), 100);
|
||||
if(std::string(tmp.data()) != "-----BEGIN PUBLIC KEY-----\n")
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
BIO_gets(bio, tmp.data(), 100);
|
||||
if(std::string(tmp.data()) == "-----END PUBLIC KEY-----\n")
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
key += tmp.data();
|
||||
key.erase(key.length() - 1, 1); // Remove last character (whitespace)
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
void parseAttributes(Certificate::Attributes *attributes, X509_NAME *raw)
|
||||
{
|
||||
std::size_t numEntries = X509_NAME_entry_count(raw);
|
||||
for(std::size_t i = 0; i < numEntries; ++i)
|
||||
{
|
||||
auto nameEntry = X509_NAME_get_entry(raw, int(i));
|
||||
auto valueObj = X509_NAME_ENTRY_get_data(nameEntry);
|
||||
|
||||
std::string key = OBJ_nid2sn(
|
||||
OBJ_obj2nid(X509_NAME_ENTRY_get_object(nameEntry))
|
||||
);
|
||||
std::string value = std::string(
|
||||
reinterpret_cast<const char*>(valueObj->data),
|
||||
valueObj->length
|
||||
);
|
||||
|
||||
if (key == "C") attributes->country = value;
|
||||
else if (key == "O") attributes->organization = value;
|
||||
else if (key == "OU") attributes->organizationalUnit = value;
|
||||
else if (key == "dnQualifier") attributes->nameQualifier = value;
|
||||
else if (key == "ST") attributes->state = value;
|
||||
else if (key == "CN") attributes->commonName = value;
|
||||
else if (key == "serialNumber") attributes->serialNumber = value;
|
||||
else if (key == "L") attributes->locality = value;
|
||||
else if (key == "title") attributes->title = value;
|
||||
else if (key == "SN") attributes->surname = value;
|
||||
else if (key == "GN") attributes->givenName = value;
|
||||
else if (key == "initials") attributes->initials = value;
|
||||
else if (key == "pseudonym") attributes->pseudonym = value;
|
||||
else if (key == "generationQualifier") attributes->generationQualifier = value;
|
||||
else if (key == "emailAddress") attributes->emailAddress = value;
|
||||
}
|
||||
}
|
||||
|
||||
retdec::fileformat::Certificate x509toCert(X509* cert)
|
||||
{
|
||||
Certificate c;
|
||||
|
||||
c.validSince = parseDateTime(X509_get_notBefore(cert));
|
||||
c.validUntil = parseDateTime(X509_get_notAfter(cert));
|
||||
|
||||
if (auto pubKey = managedPtr(X509_get_pubkey(cert), &EVP_PKEY_free))
|
||||
{
|
||||
auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free);
|
||||
PEM_write_bio_PUBKEY(memBio.get(), pubKey.get());
|
||||
c.publicKey = parsePublicKey(memBio.get());
|
||||
c.publicKeyAlgo = OBJ_nid2sn(EVP_PKEY_base_id(pubKey.get()));
|
||||
}
|
||||
|
||||
c.signatureAlgo = OBJ_nid2sn(X509_get_signature_nid(cert));
|
||||
|
||||
if (auto sn = X509_get_serialNumber(cert))
|
||||
{
|
||||
retdec::utils::bytesToHexString(
|
||||
sn->data,
|
||||
sn->length,
|
||||
c.serialNumber,
|
||||
0,
|
||||
0,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (auto subjectName = X509_get_subject_name(cert))
|
||||
{
|
||||
auto subjectNameOneline = managedPtr(
|
||||
X509_NAME_oneline(subjectName, nullptr, 0),
|
||||
&free
|
||||
);
|
||||
c.subjectRaw = subjectNameOneline.get();
|
||||
|
||||
parseAttributes(&c.subject, subjectName);
|
||||
}
|
||||
|
||||
if (auto issuerName = X509_get_issuer_name(cert))
|
||||
{
|
||||
auto issuerNameOneline = managedPtr(
|
||||
X509_NAME_oneline(issuerName, nullptr, 0),
|
||||
&free
|
||||
);
|
||||
c.issuerRaw = issuerNameOneline.get();
|
||||
|
||||
parseAttributes(&c.issuer, issuerName);
|
||||
}
|
||||
|
||||
std::vector<char> tmp(0x2000);
|
||||
auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free);
|
||||
|
||||
i2d_X509_bio(memBio.get(), cert);
|
||||
std::size_t certLen = BIO_read(memBio.get(), tmp.data(), int(tmp.size()));
|
||||
tmp.resize(certLen);
|
||||
|
||||
std::vector<std::uint8_t> sha1Bytes(
|
||||
SHA_DIGEST_LENGTH),
|
||||
sha256Bytes(SHA256_DIGEST_LENGTH
|
||||
);
|
||||
SHA1(reinterpret_cast<const unsigned char*>(
|
||||
tmp.data()),
|
||||
tmp.size(),
|
||||
sha1Bytes.data()
|
||||
);
|
||||
SHA256(reinterpret_cast<const unsigned char*>(
|
||||
tmp.data()),
|
||||
tmp.size(),
|
||||
sha256Bytes.data()
|
||||
);
|
||||
|
||||
retdec::utils::bytesToHexString(sha1Bytes, c.sha1Digest, 0, 0, false);
|
||||
retdec::utils::bytesToHexString(
|
||||
sha256Bytes,
|
||||
c.sha256Digest,
|
||||
0,
|
||||
0,
|
||||
false
|
||||
);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
@ -2076,169 +1792,16 @@ void PeFormat::loadResources()
|
||||
*/
|
||||
void PeFormat::loadCertificates()
|
||||
{
|
||||
const auto &securityDir = file->securityDir();
|
||||
if(securityDir.calcNumberOfCertificates() == 0)
|
||||
{
|
||||
const auto& securityDir = file->securityDir();
|
||||
if (securityDir.calcNumberOfCertificates() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We always take the first one, there are no additional certificate tables in PE
|
||||
// We always take the first one, there might be more WIN_CERT structures tho
|
||||
auto certBytes = securityDir.getCertificate(0);
|
||||
auto certSize = certBytes.size();
|
||||
PKCS7 *p7 = NULL;
|
||||
BIO *bio;
|
||||
|
||||
// Create the BIO object and extract certificate from it
|
||||
if((bio = BIO_new(BIO_s_mem())) != NULL)
|
||||
{
|
||||
if(BIO_reset(bio) == 1)
|
||||
{
|
||||
if(BIO_write(bio, certBytes.data(), certSize) == certSize)
|
||||
{
|
||||
p7 = d2i_PKCS7_bio(bio, nullptr);
|
||||
}
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
// Make sure that the PKCS7 structure is valid
|
||||
if(!p7)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//// Make sure that the PKCS7 data is valid
|
||||
if(!PKCS7_type_is_signed(p7))
|
||||
{
|
||||
PKCS7_free(p7);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find signer of the application and store its serial number.
|
||||
X509 *signerCert = nullptr;
|
||||
X509 *counterSignerCert = nullptr;
|
||||
|
||||
STACK_OF(X509) *certs = p7->d.sign->cert;
|
||||
STACK_OF(X509) *signers = PKCS7_get0_signers(p7, certs, 0);
|
||||
|
||||
SCOPE_EXIT {
|
||||
if (signers != nullptr)
|
||||
sk_X509_free(signers);
|
||||
};
|
||||
|
||||
if(sk_X509_num(signers) > 0)
|
||||
{
|
||||
signerCert = sk_X509_value(signers, 0);
|
||||
}
|
||||
|
||||
// Try to find countersigner if it exists and store its serial number.
|
||||
STACK_OF(PKCS7_SIGNER_INFO) *sinfos = PKCS7_get_signer_info(p7);
|
||||
if(sk_PKCS7_SIGNER_INFO_num(sinfos) > 0)
|
||||
{
|
||||
PKCS7_SIGNER_INFO *sinfo = sk_PKCS7_SIGNER_INFO_value(sinfos, 0);
|
||||
|
||||
// Counter-signer is stored as unsigned attribute and there is no other way to get it but manual parsing
|
||||
ASN1_TYPE *counterSig = PKCS7_get_attribute(sinfo, NID_pkcs9_countersignature);
|
||||
if(counterSig)
|
||||
{
|
||||
auto bio = std::unique_ptr<BIO, decltype(&BIO_free)>(BIO_new_mem_buf(counterSig->value.sequence->data, counterSig->value.sequence->length), &BIO_free);
|
||||
PKCS7_SIGNER_INFO *counterSinfo = reinterpret_cast<PKCS7_SIGNER_INFO*>(ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS7_SIGNER_INFO), bio.get(), nullptr));
|
||||
if(counterSinfo)
|
||||
{
|
||||
// From SignerInfo, we get only issuer, but we can lookup by issuer in all certificates and get original counter-signer
|
||||
counterSignerCert = X509_find_by_issuer_and_serial(certs, counterSinfo->issuer_and_serial->issuer, counterSinfo->issuer_and_serial->serial);
|
||||
}
|
||||
ASN1_item_free(reinterpret_cast<ASN1_VALUE*>(counterSinfo), ASN1_ITEM_rptr(PKCS7_SIGNER_INFO));
|
||||
}
|
||||
}
|
||||
|
||||
// If we have no signer and countersigner, there must be something really bad
|
||||
if(!signerCert && !counterSignerCert)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Now that we know there is at least a signer or counter-signer, we can
|
||||
// verify the signature. Do not try to verify the signature before
|
||||
// verifying that there is at least a signer or counter-signer as 'p7' is
|
||||
// empty in that case (#87).
|
||||
signatureVerified = verifySignature(this, p7);
|
||||
|
||||
// Create hash table with key-value pair as subject-X509 certificate so we can easily lookup certificates by their subject name
|
||||
std::unordered_map<std::string, X509*> subjectToCert;
|
||||
for(int j = 0; j < sk_X509_num(certs); ++j)
|
||||
{
|
||||
X509 *xcert = sk_X509_value(certs, j);
|
||||
auto subjectPtr = X509_NAME_oneline(X509_get_subject_name(xcert), nullptr, 0);
|
||||
std::string subject = subjectPtr;
|
||||
subjectToCert[subject] = xcert;
|
||||
OPENSSL_free(subjectPtr);
|
||||
}
|
||||
|
||||
// Start with signer certificate which will be always first and continue with its issuer name and use previously constructed hash table to
|
||||
// reconstruct chain of certificates
|
||||
// When we hit the last certificate in the chain and there is counter-signer, try to reconstruct its chain
|
||||
X509* xcert = nullptr;
|
||||
bool counterChain = false;
|
||||
std::string nextIssuer;
|
||||
if(signerCert)
|
||||
{
|
||||
auto nextIssuerPtr = X509_NAME_oneline(X509_get_subject_name(signerCert), nullptr, 0);
|
||||
nextIssuer = nextIssuerPtr;
|
||||
OPENSSL_free(nextIssuerPtr);
|
||||
}
|
||||
|
||||
// Continue while we have next issuer to process, or there is counter-signer certificate and we haven't processed him yet
|
||||
while(!nextIssuer.empty() || (!counterChain && counterSignerCert))
|
||||
{
|
||||
// Find next issuer in the hash table
|
||||
auto itr = subjectToCert.find(nextIssuer);
|
||||
if(itr == subjectToCert.end())
|
||||
{
|
||||
// If we haven't processed counter-signer chain yet and there is counter-signer certificate
|
||||
if(!counterChain && counterSignerCert)
|
||||
{
|
||||
auto nextIssuerPtr = X509_NAME_oneline(X509_get_subject_name(counterSignerCert), nullptr, 0);
|
||||
nextIssuer = nextIssuerPtr;
|
||||
counterChain = true;
|
||||
OPENSSL_free(nextIssuerPtr);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Remove certificate from the hash table so we can't get into infinite loops
|
||||
else
|
||||
{
|
||||
xcert = itr->second;
|
||||
subjectToCert.erase(itr);
|
||||
}
|
||||
|
||||
if(!certificateTable)
|
||||
{
|
||||
certificateTable = new CertificateTable();
|
||||
}
|
||||
|
||||
Certificate cert = x509toCert(xcert);
|
||||
certificateTable->addCertificate(cert);
|
||||
|
||||
// Check if we are at signer or counter-signer certificate and let the certificate table known indices.
|
||||
if(xcert == signerCert)
|
||||
{
|
||||
certificateTable->setSignerCertificateIndex(certificateTable->getNumberOfCertificates() - 1);
|
||||
}
|
||||
else if(xcert == counterSignerCert)
|
||||
{
|
||||
certificateTable->setCounterSignerCertificateIndex(certificateTable->getNumberOfCertificates() - 1);
|
||||
}
|
||||
|
||||
// Continue with next issuer
|
||||
nextIssuer = cert.getRawIssuer();
|
||||
}
|
||||
|
||||
PKCS7_free(p7);
|
||||
authenticode::Authenticode authenticode(certBytes);
|
||||
|
||||
certificateTable = new CertificateTable(authenticode.getSignatures(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file src/fileformat/types/certificate_table/certificate.cpp
|
||||
* @brief Class for one certificate.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
* @copyright (c) 2020 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include <unordered_map>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file src/fileformat/types/certificate_table/certificate_table.cpp
|
||||
* @brief Class for certificate table.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
* @copyright (c) 2021 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
@ -9,126 +9,15 @@
|
||||
namespace retdec {
|
||||
namespace fileformat {
|
||||
|
||||
/**
|
||||
* Get number of certificates
|
||||
* @return Number of certificates
|
||||
*/
|
||||
std::size_t CertificateTable::getNumberOfCertificates() const
|
||||
{
|
||||
return certificates.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index of the certificate of the signer
|
||||
* @return Index of the signer's certificate
|
||||
*/
|
||||
std::size_t CertificateTable::getSignerCertificateIndex() const
|
||||
{
|
||||
return signerIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index of the certificate of the counter-signer. Returned value should not be used without prior checking
|
||||
* of whether the table has counter-signer certificate.
|
||||
* @return Index of the counter-signer's certificate
|
||||
*/
|
||||
std::size_t CertificateTable::getCounterSignerCertificateIndex() const
|
||||
{
|
||||
return counterSignerIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get selected certificate
|
||||
* @param certIndex Index of selected certificate (indexed from 0)
|
||||
* @return Pointer to selected certificate or @c nullptr if certificate index is invalid
|
||||
*/
|
||||
const Certificate* CertificateTable::getCertificate(std::size_t certIndex) const
|
||||
{
|
||||
return (certIndex < getNumberOfCertificates()) ? &certificates[certIndex] : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set signer certificate index
|
||||
* @param certIndex Index of the signer certificate
|
||||
*/
|
||||
void CertificateTable::setSignerCertificateIndex(std::size_t certIndex)
|
||||
{
|
||||
if(certIndex >= getNumberOfCertificates())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hasSigner = true;
|
||||
signerIndex = certIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set counter-signer certificate index
|
||||
* @param certIndex Index of the counter-signer certificate
|
||||
*/
|
||||
void CertificateTable::setCounterSignerCertificateIndex(std::size_t certIndex)
|
||||
{
|
||||
if(certIndex >= getNumberOfCertificates())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hasCounterSigner = true;
|
||||
counterSignerIndex = certIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get begin certificates iterator
|
||||
* @return Begin certificates iterator
|
||||
*/
|
||||
CertificateTable::certificatesIterator CertificateTable::begin() const
|
||||
{
|
||||
return certificates.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get end certificates iterator
|
||||
* @return End certificates iterator
|
||||
*/
|
||||
CertificateTable::certificatesIterator CertificateTable::end() const
|
||||
{
|
||||
return certificates.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether certificate table has signer certificate
|
||||
* @return @c true if has signer, otherwise @c false.
|
||||
*/
|
||||
bool CertificateTable::hasSignerCertificate() const
|
||||
{
|
||||
return hasSigner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether certificate table has counter-signer certificate
|
||||
* @return @c true if has counter-signer, otherwise @c false.
|
||||
*/
|
||||
bool CertificateTable::hasCounterSignerCertificate() const
|
||||
{
|
||||
return hasCounterSigner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add certificate
|
||||
* @param certificate Certificate which will be added
|
||||
*/
|
||||
void CertificateTable::addCertificate(const Certificate& certificate)
|
||||
{
|
||||
certificates.push_back(certificate);
|
||||
}
|
||||
|
||||
CertificateTable::CertificateTable(std::vector<DigitalSignature> signatures)
|
||||
: signatures(signatures) {}
|
||||
/**
|
||||
* Check if certificate table is empty
|
||||
* @return @c true if table does not contain any certificates, @c false otherwise
|
||||
*/
|
||||
bool CertificateTable::empty() const
|
||||
{
|
||||
return !getNumberOfCertificates();
|
||||
return signatures.empty();
|
||||
}
|
||||
|
||||
} // namespace fileformat
|
||||
|
@ -9,7 +9,6 @@ add_executable(fileinfo
|
||||
file_detector/pe_detector.cpp
|
||||
file_detector/raw_data_detector.cpp
|
||||
file_information/file_information.cpp
|
||||
file_information/file_information_types/certificate_table.cpp
|
||||
file_information/file_information_types/data_directory.cpp
|
||||
file_information/file_information_types/dotnet_info.cpp
|
||||
file_information/file_information_types/dynamic_section/dynamic_entry.cpp
|
||||
@ -66,7 +65,6 @@ add_executable(fileinfo
|
||||
file_presentation/getters/iterative_getter/iterative_distribution_getter/version_info_string_table_plain_getter.cpp
|
||||
file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.cpp
|
||||
file_presentation/getters/iterative_getter/iterative_getter.cpp
|
||||
file_presentation/getters/iterative_getter/iterative_simple_getter/certificate_table_plain_getter.cpp
|
||||
file_presentation/getters/iterative_getter/iterative_simple_getter/iterative_simple_getter.cpp
|
||||
file_presentation/getters/iterative_getter/iterative_subtitle_getter/anomalies_json_getter.cpp
|
||||
file_presentation/getters/iterative_getter/iterative_subtitle_getter/data_directory_json_getter.cpp
|
||||
|
@ -211,7 +211,11 @@ void FileDetector::getCertificates()
|
||||
{
|
||||
if (fileParser->isSignaturePresent())
|
||||
fileInfo.setSignatureVerified(fileParser->isSignatureVerified());
|
||||
fileInfo.setCertificateTable(fileParser->getCertificateTable());
|
||||
|
||||
// const CertificateTable* certificateTable = fileParser->getCertificateTable());
|
||||
if (fileParser->getCertificateTable()) {
|
||||
fileInfo.setCertificateTable(fileParser->getCertificateTable());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "retdec/common/address.h"
|
||||
#include "fileinfo/file_information/file_information.h"
|
||||
@ -1654,460 +1655,6 @@ bool FileInformation::hasResourceTableRecords() const
|
||||
return resourceTable.hasRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of stored certificates
|
||||
* @return Number of stored certificates
|
||||
*/
|
||||
std::size_t FileInformation::getNumberOfStoredCertificates() const
|
||||
{
|
||||
return certificateTable.getNumberOfCertificates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index of the certificate of the counter-signer. Returned value should not be used without prior checking
|
||||
* of whether the table has counter-signer certificate.
|
||||
* @return Index of the counter-signer's certificate
|
||||
*/
|
||||
std::size_t FileInformation::getCertificateTableSignerCertificateIndex() const
|
||||
{
|
||||
return certificateTable.getSignerCertificateIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date since when is certificate valid
|
||||
* @return Date since when is certificate valid
|
||||
*/
|
||||
std::size_t FileInformation::getCertificateTableCounterSignerCertificateIndex() const
|
||||
{
|
||||
return certificateTable.getCounterSignerCertificateIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date since when is certificate valid
|
||||
* @param index Index of selected certificate from table (indexed from 0)
|
||||
* @return Date since when is certificate valid
|
||||
*/
|
||||
std::string FileInformation::getCertificateValidSince(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateValidSince(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date until when is certificate valid
|
||||
* @param index Index of selected certificate from table (indexed from 0)
|
||||
* @return Date until when is certificate valid
|
||||
*/
|
||||
std::string FileInformation::getCertificateValidUntil(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateValidUntil(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate public key
|
||||
* @param index Index of selected certificate from table (indexed from 0)
|
||||
* @return Public key
|
||||
*/
|
||||
std::string FileInformation::getCertificatePublicKey(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificatePublicKey(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate public key algorithm
|
||||
* @param index Index of selected certificate from table (indexed from 0)
|
||||
* @return Public key algorithm
|
||||
*/
|
||||
std::string FileInformation::getCertificatePublicKeyAlgorithm(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificatePublicKeyAlgorithm(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate signature algorithm
|
||||
* @param index Index of selected certificate from table (indexed from 0)
|
||||
* @return Signature algorithm
|
||||
*/
|
||||
std::string FileInformation::getCertificateSignatureAlgorithm(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSignatureAlgorithm(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate serial number
|
||||
* @param index Index of selected certificate from table (indexed from 0)
|
||||
* @return Serial number
|
||||
*/
|
||||
std::string FileInformation::getCertificateSerialNumber(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSerialNumber(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate SHA1 digest
|
||||
* @param index Index of selected certificate from table (indexed from 0)
|
||||
* @return SHA1 digest
|
||||
*/
|
||||
std::string FileInformation::getCertificateSha1Digest(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSha1Digest(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate SHA256 digest
|
||||
* @param index Index of selected certificate from table (indexed from 0)
|
||||
* @return SHA256 digest
|
||||
*/
|
||||
std::string FileInformation::getCertificateSha256Digest(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSha256Digest(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Issuer of selected certificate
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerRawStr(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerRaw(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Subject of selected certificate
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectRawStr(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectRaw(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer country
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Country of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerCountry(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerCountry(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer organization
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Organization of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerOrganization(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerOrganization(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer organizational unit
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Organizational unit of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerOrganizationalUnit(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerOrganizationalUnit(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer name qualifier
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Name qualifier of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerNameQualifier(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerNameQualifier(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer state
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return State of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerState(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerState(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer common name
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Common name of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerCommonName(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerCommonName(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer serial number
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Serial number of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerSerialNumber(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerSerialNumber(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer locality
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Locality of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerLocality(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerLocality(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer title
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Title of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerTitle(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerTitle(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer surname
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Surname of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerSurname(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerSurname(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer given name
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Given name of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerGivenName(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerGivenName(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer initials
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Initials of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerInitials(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerInitials(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer pseudonym
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Pseudonym of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerPseudonym(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerPseudonym(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer generation qualifier
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Generation qualifier of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerGenerationQualifier(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerGenerationQualifier(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer email address
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Email address of selected certificate issuer
|
||||
*/
|
||||
std::string FileInformation::getCertificateIssuerEmailAddress(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateIssuerEmailAddress(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject country
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Country of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectCountry(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectCountry(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject organization
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Organization of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectOrganization(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectOrganization(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject organizational unit
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Organizational unit of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectOrganizationalUnit(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectOrganizationalUnit(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject name qualifier
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Name qualifier of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectNameQualifier(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectNameQualifier(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject state
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return State of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectState(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectState(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject common name
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Common name of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectCommonName(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectCommonName(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject serial number
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Serial number of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectSerialNumber(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectSerialNumber(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject locality
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Locality of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectLocality(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectLocality(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject title
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Title of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectTitle(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectTitle(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject surname
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Surname of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectSurname(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectSurname(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject given name
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Given name of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectGivenName(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectGivenName(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject initials
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Initials of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectInitials(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectInitials(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject pseudonym
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Pseudonym of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectPseudonym(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectPseudonym(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject generation qualifier
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Generation qualifier of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectGenerationQualifier(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectGenerationQualifier(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject email address
|
||||
* @param index Index of selected certificate (indexed from 0)
|
||||
* @return Email address of selected certificate subject
|
||||
*/
|
||||
std::string FileInformation::getCertificateSubjectEmailAddress(std::size_t index) const
|
||||
{
|
||||
return certificateTable.getCertificateSubjectEmailAddress(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there are any records in certificate table
|
||||
* @return @c true if certificate table is not empty, @c false otherwise
|
||||
*/
|
||||
bool FileInformation::hasCertificateTableRecords() const
|
||||
{
|
||||
return certificateTable.hasRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there is signer certificate
|
||||
* @return @c true if there is signer certificate, @c false otherwise
|
||||
*/
|
||||
bool FileInformation::hasCertificateTableSignerCertificate() const
|
||||
{
|
||||
return certificateTable.hasSignerCertificate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there is counter-signer certificate
|
||||
* @return @c true if there is counter-signer certificate, @c false otherwise
|
||||
*/
|
||||
bool FileInformation::hasCertificateTableCounterSignerCertificate() const
|
||||
{
|
||||
return certificateTable.hasCounterSignerCertificate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get start address of raw data of TLS
|
||||
@ -4295,9 +3842,9 @@ void FileInformation::setStrings(const std::vector<retdec::fileformat::String> *
|
||||
* Set certificate table
|
||||
* @param sTable Information about certificate table
|
||||
*/
|
||||
void FileInformation::setCertificateTable(const retdec::fileformat::CertificateTable *sTable)
|
||||
void FileInformation::setCertificateTable(const retdec::fileformat::CertificateTable* sTable)
|
||||
{
|
||||
certificateTable.setTable(sTable);
|
||||
certificateTable = sTable;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,7 +49,6 @@ class FileInformation
|
||||
ImportTable importTable; ///< information about imports
|
||||
ExportTable exportTable; ///< information about exports
|
||||
ResourceTable resourceTable; ///< information about resources in input file
|
||||
CertificateTable certificateTable; ///< information about certificates
|
||||
TlsInfo tlsInfo; ///< information about thread-local storage
|
||||
ElfCore elfCoreInfo; ///< information about ELF core files
|
||||
LoaderInfo loaderInfo; ///< information about loaded image
|
||||
@ -70,6 +69,7 @@ class FileInformation
|
||||
std::vector<std::pair<std::string,std::string>> anomalies; ///< detected anomalies
|
||||
|
||||
public:
|
||||
const retdec::fileformat::CertificateTable* certificateTable = nullptr; ///< information about signatures
|
||||
retdec::cpdetect::ToolInformation toolInfo; ///< detected tools
|
||||
std::vector<std::string> messages; ///< error, warning and other messages
|
||||
|
||||
@ -279,56 +279,6 @@ class FileInformation
|
||||
bool hasResourceTableRecords() const;
|
||||
/// @}
|
||||
|
||||
/// @name Getters of @a certificateTable
|
||||
/// @{
|
||||
std::size_t getNumberOfStoredCertificates() const;
|
||||
std::size_t getCertificateTableSignerCertificateIndex() const;
|
||||
std::size_t getCertificateTableCounterSignerCertificateIndex() const;
|
||||
std::string getCertificateValidSince(std::size_t index) const;
|
||||
std::string getCertificateValidUntil(std::size_t index) const;
|
||||
std::string getCertificatePublicKey(std::size_t index) const;
|
||||
std::string getCertificatePublicKeyAlgorithm(std::size_t index) const;
|
||||
std::string getCertificateSignatureAlgorithm(std::size_t index) const;
|
||||
std::string getCertificateSerialNumber(std::size_t index) const;
|
||||
std::string getCertificateSha1Digest(std::size_t index) const;
|
||||
std::string getCertificateSha256Digest(std::size_t index) const;
|
||||
std::string getCertificateIssuerRawStr(std::size_t index) const;
|
||||
std::string getCertificateSubjectRawStr(std::size_t index) const;
|
||||
std::string getCertificateIssuerCountry(std::size_t index) const;
|
||||
std::string getCertificateIssuerOrganization(std::size_t index) const;
|
||||
std::string getCertificateIssuerOrganizationalUnit(std::size_t index) const;
|
||||
std::string getCertificateIssuerNameQualifier(std::size_t index) const;
|
||||
std::string getCertificateIssuerState(std::size_t index) const;
|
||||
std::string getCertificateIssuerCommonName(std::size_t index) const;
|
||||
std::string getCertificateIssuerSerialNumber(std::size_t index) const;
|
||||
std::string getCertificateIssuerLocality(std::size_t index) const;
|
||||
std::string getCertificateIssuerTitle(std::size_t index) const;
|
||||
std::string getCertificateIssuerSurname(std::size_t index) const;
|
||||
std::string getCertificateIssuerGivenName(std::size_t index) const;
|
||||
std::string getCertificateIssuerInitials(std::size_t index) const;
|
||||
std::string getCertificateIssuerPseudonym(std::size_t index) const;
|
||||
std::string getCertificateIssuerGenerationQualifier(std::size_t index) const;
|
||||
std::string getCertificateIssuerEmailAddress(std::size_t index) const;
|
||||
std::string getCertificateSubjectCountry(std::size_t index) const;
|
||||
std::string getCertificateSubjectOrganization(std::size_t index) const;
|
||||
std::string getCertificateSubjectOrganizationalUnit(std::size_t index) const;
|
||||
std::string getCertificateSubjectNameQualifier(std::size_t index) const;
|
||||
std::string getCertificateSubjectState(std::size_t index) const;
|
||||
std::string getCertificateSubjectCommonName(std::size_t index) const;
|
||||
std::string getCertificateSubjectSerialNumber(std::size_t index) const;
|
||||
std::string getCertificateSubjectLocality(std::size_t index) const;
|
||||
std::string getCertificateSubjectTitle(std::size_t index) const;
|
||||
std::string getCertificateSubjectSurname(std::size_t index) const;
|
||||
std::string getCertificateSubjectGivenName(std::size_t index) const;
|
||||
std::string getCertificateSubjectInitials(std::size_t index) const;
|
||||
std::string getCertificateSubjectPseudonym(std::size_t index) const;
|
||||
std::string getCertificateSubjectGenerationQualifier(std::size_t index) const;
|
||||
std::string getCertificateSubjectEmailAddress(std::size_t index) const;
|
||||
bool hasCertificateTableRecords() const;
|
||||
bool hasCertificateTableSignerCertificate() const;
|
||||
bool hasCertificateTableCounterSignerCertificate() const;
|
||||
/// @}
|
||||
|
||||
/// @name Getters of @a TLS information
|
||||
/// @{
|
||||
std::string getTlsRawDataStartAddrStr(std::ios_base &(* format)(std::ios_base &)) const;
|
||||
|
@ -1,517 +0,0 @@
|
||||
/**
|
||||
* @file src/fileinfo/file_information/file_information_types/certificate_table.cpp
|
||||
* @brief Certificate table.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "fileinfo/file_information/file_information_types/certificate_table.h"
|
||||
|
||||
namespace retdec {
|
||||
namespace fileinfo {
|
||||
|
||||
/**
|
||||
* Get number of certificates in table
|
||||
* @return Number of certificates in table
|
||||
*/
|
||||
std::size_t CertificateTable::getNumberOfCertificates() const
|
||||
{
|
||||
return table ? table->getNumberOfCertificates() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index of the certificate of the signer
|
||||
* @return Index of the signer's certificate
|
||||
*/
|
||||
std::size_t CertificateTable::getSignerCertificateIndex() const
|
||||
{
|
||||
return table ? table->getSignerCertificateIndex() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index of the certificate of the counter-signer. Returned value should not be used without prior checking
|
||||
* of whether the table has counter-signer certificate.
|
||||
* @return Index of the counter-signer's certificate
|
||||
*/
|
||||
std::size_t CertificateTable::getCounterSignerCertificateIndex() const
|
||||
{
|
||||
return table ? table->getCounterSignerCertificateIndex() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date since when is certificate valid
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return Date since when is certificate valid
|
||||
*/
|
||||
std::string CertificateTable::getCertificateValidSince(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getValidSince() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date until when is certificate valid
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return Date until when is certificate valid
|
||||
*/
|
||||
std::string CertificateTable::getCertificateValidUntil(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getValidUntil() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate public key
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return Public key
|
||||
*/
|
||||
std::string CertificateTable::getCertificatePublicKey(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getPublicKey() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate public key algorithm
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return Public key algorithm
|
||||
*/
|
||||
std::string CertificateTable::getCertificatePublicKeyAlgorithm(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getPublicKeyAlgorithm() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate signature algorithm
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return Signature algorithm
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSignatureAlgorithm(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSignatureAlgorithm() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate serial number
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return Serial number
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSerialNumber(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSerialNumber() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate SHA1 digest
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return SHA1 digest
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSha1Digest(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSha1Digest() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate SHA256 digest
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return SHA256 digest
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSha256Digest(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSha256Digest() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return Certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectRaw(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getRawSubject() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer
|
||||
* @param position Index of selected certificate from table (indexed from 0)
|
||||
* @return Certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerRaw(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getRawIssuer() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer country
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Country of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerCountry(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().country : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer organization
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Organization of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerOrganization(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().organization : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer organizational unit
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Organizational unit of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerOrganizationalUnit(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().organizationalUnit : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer name qualifier
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Name qualifier of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerNameQualifier(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().nameQualifier : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer state
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return State of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerState(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().state : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer common name
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Common name of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerCommonName(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().commonName : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer serial number
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Serial number of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerSerialNumber(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().serialNumber : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer locality
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Locality of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerLocality(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().locality : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer title
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Title of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerTitle(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().title : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer surname
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Surname of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerSurname(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().surname : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer given name
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Given name of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerGivenName(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().givenName : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer initials
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Initials of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerInitials(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().initials : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer pseudonym
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Pseudonym of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerPseudonym(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().pseudonym : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer generation qualifier
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Generation qualifier of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerGenerationQualifier(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().generationQualifier : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate issuer email address
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Email address of selected certificate issuer
|
||||
*/
|
||||
std::string CertificateTable::getCertificateIssuerEmailAddress(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getIssuer().emailAddress : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject country
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Country of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectCountry(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().country : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject organization
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Organization of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectOrganization(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().organization : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject organizational unit
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Organizational unit of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectOrganizationalUnit(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().organizationalUnit : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject name qualifier
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Name qualifier of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectNameQualifier(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().nameQualifier : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject state
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return State of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectState(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().state : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject common name
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Common name of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectCommonName(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().commonName : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject serial number
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Serial number of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectSerialNumber(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().serialNumber : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject locality
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Locality of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectLocality(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().locality : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject title
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Title of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectTitle(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().title : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject surname
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Surname of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectSurname(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().surname : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject given name
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Given name of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectGivenName(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().givenName : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject initials
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Initials of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectInitials(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().initials : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject pseudonym
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Pseudonym of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectPseudonym(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().pseudonym : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject generation qualifier
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Generation qualifier of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectGenerationQualifier(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().generationQualifier : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certificate subject email address
|
||||
* @param position Index of selected certificate (indexed from 0)
|
||||
* @return Email address of selected certificate subject
|
||||
*/
|
||||
std::string CertificateTable::getCertificateSubjectEmailAddress(std::size_t position) const
|
||||
{
|
||||
const auto *record = table ? table->getCertificate(position) : nullptr;
|
||||
return record ? record->getSubject().emailAddress : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Set certificate table data
|
||||
* @param certificateTable Instance of class with original information about certificate table
|
||||
*/
|
||||
void CertificateTable::setTable(const retdec::fileformat::CertificateTable *certificateTable)
|
||||
{
|
||||
table = certificateTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there are any certificates
|
||||
* @return @c true if there are some certificates, @c false otherwise
|
||||
*/
|
||||
bool CertificateTable::hasRecords() const
|
||||
{
|
||||
return table ? !table->empty() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there is signer certificate
|
||||
* @return @c true if there is signer certificate, @c false otherwise
|
||||
*/
|
||||
bool CertificateTable::hasSignerCertificate() const
|
||||
{
|
||||
return table ? table->hasSignerCertificate() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there is counter-signer certificate
|
||||
* @return @c true if there is counter-signer certificate, @c false otherwise
|
||||
*/
|
||||
bool CertificateTable::hasCounterSignerCertificate() const
|
||||
{
|
||||
return table ? table->hasCounterSignerCertificate() : false;
|
||||
}
|
||||
|
||||
} // namespace fileinfo
|
||||
} // namespace retdec
|
@ -1,86 +0,0 @@
|
||||
/**
|
||||
* @file src/fileinfo/file_information/file_information_types/certificate_table.h
|
||||
* @brief Certificate table.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef FILEINFO_FILE_INFORMATION_FILE_INFORMATION_TYPES_CERTIFICATE_TABLE_H
|
||||
#define FILEINFO_FILE_INFORMATION_FILE_INFORMATION_TYPES_CERTIFICATE_TABLE_H
|
||||
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
|
||||
namespace retdec {
|
||||
namespace fileinfo {
|
||||
|
||||
/**
|
||||
* Class for certificate table
|
||||
*/
|
||||
class CertificateTable
|
||||
{
|
||||
private:
|
||||
const retdec::fileformat::CertificateTable *table = nullptr;
|
||||
public:
|
||||
/// @name Getters
|
||||
/// @{
|
||||
std::size_t getNumberOfCertificates() const;
|
||||
std::size_t getSignerCertificateIndex() const;
|
||||
std::size_t getCounterSignerCertificateIndex() const;
|
||||
std::string getCertificateValidSince(std::size_t position) const;
|
||||
std::string getCertificateValidUntil(std::size_t position) const;
|
||||
std::string getCertificatePublicKey(std::size_t position) const;
|
||||
std::string getCertificatePublicKeyAlgorithm(std::size_t position) const;
|
||||
std::string getCertificateSignatureAlgorithm(std::size_t position) const;
|
||||
std::string getCertificateSerialNumber(std::size_t position) const;
|
||||
std::string getCertificateSha1Digest(std::size_t position) const;
|
||||
std::string getCertificateSha256Digest(std::size_t position) const;
|
||||
std::string getCertificateSubjectRaw(std::size_t position) const;
|
||||
std::string getCertificateIssuerRaw(std::size_t position) const;
|
||||
std::string getCertificateIssuerCountry(std::size_t position) const;
|
||||
std::string getCertificateIssuerOrganization(std::size_t position) const;
|
||||
std::string getCertificateIssuerOrganizationalUnit(std::size_t position) const;
|
||||
std::string getCertificateIssuerNameQualifier(std::size_t position) const;
|
||||
std::string getCertificateIssuerState(std::size_t position) const;
|
||||
std::string getCertificateIssuerCommonName(std::size_t position) const;
|
||||
std::string getCertificateIssuerSerialNumber(std::size_t position) const;
|
||||
std::string getCertificateIssuerLocality(std::size_t position) const;
|
||||
std::string getCertificateIssuerTitle(std::size_t position) const;
|
||||
std::string getCertificateIssuerSurname(std::size_t position) const;
|
||||
std::string getCertificateIssuerGivenName(std::size_t position) const;
|
||||
std::string getCertificateIssuerInitials(std::size_t position) const;
|
||||
std::string getCertificateIssuerPseudonym(std::size_t position) const;
|
||||
std::string getCertificateIssuerGenerationQualifier(std::size_t position) const;
|
||||
std::string getCertificateIssuerEmailAddress(std::size_t position) const;
|
||||
std::string getCertificateSubjectCountry(std::size_t position) const;
|
||||
std::string getCertificateSubjectOrganization(std::size_t position) const;
|
||||
std::string getCertificateSubjectOrganizationalUnit(std::size_t position) const;
|
||||
std::string getCertificateSubjectNameQualifier(std::size_t position) const;
|
||||
std::string getCertificateSubjectState(std::size_t position) const;
|
||||
std::string getCertificateSubjectCommonName(std::size_t position) const;
|
||||
std::string getCertificateSubjectSerialNumber(std::size_t position) const;
|
||||
std::string getCertificateSubjectLocality(std::size_t position) const;
|
||||
std::string getCertificateSubjectTitle(std::size_t position) const;
|
||||
std::string getCertificateSubjectSurname(std::size_t position) const;
|
||||
std::string getCertificateSubjectGivenName(std::size_t position) const;
|
||||
std::string getCertificateSubjectInitials(std::size_t position) const;
|
||||
std::string getCertificateSubjectPseudonym(std::size_t position) const;
|
||||
std::string getCertificateSubjectGenerationQualifier(std::size_t position) const;
|
||||
std::string getCertificateSubjectEmailAddress(std::size_t position) const;
|
||||
/// @}
|
||||
|
||||
/// @name Setters
|
||||
/// @{
|
||||
void setTable(const retdec::fileformat::CertificateTable *certificateTable);
|
||||
/// @}
|
||||
|
||||
/// @name Other methods
|
||||
/// @{
|
||||
bool hasRecords() const;
|
||||
bool hasSignerCertificate() const;
|
||||
bool hasCounterSignerCertificate() const;
|
||||
/// @}
|
||||
};
|
||||
|
||||
} // namespace fileinfo
|
||||
} // namespace retdec
|
||||
|
||||
#endif
|
@ -7,7 +7,6 @@
|
||||
#ifndef FILEINFO_FILE_INFORMATION_FILE_INFORMATION_TYPES_FILE_INFORMATION_TYPES_H
|
||||
#define FILEINFO_FILE_INFORMATION_FILE_INFORMATION_TYPES_FILE_INFORMATION_TYPES_H
|
||||
|
||||
#include "fileinfo/file_information/file_information_types/certificate_table.h"
|
||||
#include "fileinfo/file_information/file_information_types/data_directory.h"
|
||||
#include "fileinfo/file_information/file_information_types/dotnet_info.h"
|
||||
#include "fileinfo/file_information/file_information_types/dynamic_section/dynamic_section.h"
|
||||
|
@ -1,117 +0,0 @@
|
||||
/**
|
||||
* @file src/fileinfo/file_presentation/getters/iterative_getter/iterative_simple_getter/certificate_table_plain_getter.cpp
|
||||
* @brief Methods of CertificateTablePlainGetter class.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "retdec/utils/conversion.h"
|
||||
#include "retdec/utils/string.h"
|
||||
#include "retdec/fileformat/utils/conversions.h"
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_simple_getter/certificate_table_plain_getter.h"
|
||||
|
||||
using namespace retdec::utils;
|
||||
using namespace retdec::fileformat;
|
||||
|
||||
namespace retdec {
|
||||
namespace fileinfo {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param fileInfo Information about file
|
||||
*/
|
||||
CertificateTablePlainGetter::CertificateTablePlainGetter(FileInformation &fileInfo) : IterativeSimpleGetter(fileInfo)
|
||||
{
|
||||
numberOfStructures = 1;
|
||||
numberOfStoredRecords.push_back(fileinfo.getNumberOfStoredCertificates());
|
||||
numberOfExtraElements.push_back(0);
|
||||
title = "Certificate table";
|
||||
elementHeader = "Certificate";
|
||||
commonHeaderElements.push_back("Subject name : ");
|
||||
commonHeaderElements.push_back("Subject organization: ");
|
||||
commonHeaderElements.push_back("Subject : ");
|
||||
commonHeaderElements.push_back("Issuer name : ");
|
||||
commonHeaderElements.push_back("Issuer organization : ");
|
||||
commonHeaderElements.push_back("Issuer : ");
|
||||
commonHeaderElements.push_back("Public key algorithm: ");
|
||||
commonHeaderElements.push_back("Signature algorithm : ");
|
||||
commonHeaderElements.push_back("Serial number : ");
|
||||
commonHeaderElements.push_back("Valid since : ");
|
||||
commonHeaderElements.push_back("Valid until : ");
|
||||
commonHeaderElements.push_back("SHA1 : ");
|
||||
commonHeaderElements.push_back("SHA256 : ");
|
||||
}
|
||||
|
||||
std::size_t CertificateTablePlainGetter::getBasicInfo(std::size_t structIndex, std::vector<std::string> &desc, std::vector<std::string> &info) const
|
||||
{
|
||||
if(structIndex >= numberOfStructures || !fileinfo.hasCertificateTableRecords())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
desc.clear();
|
||||
info.clear();
|
||||
|
||||
desc.push_back("Number of certificates : ");
|
||||
desc.push_back("Signer certificate index : ");
|
||||
desc.push_back("Counter-signer certificate index: ");
|
||||
info.push_back(std::to_string(fileinfo.getNumberOfStoredCertificates()));
|
||||
if(fileinfo.hasCertificateTableSignerCertificate())
|
||||
{
|
||||
info.push_back(std::to_string(fileinfo.getCertificateTableSignerCertificateIndex()));
|
||||
}
|
||||
else
|
||||
{
|
||||
info.push_back("");
|
||||
}
|
||||
if(fileinfo.hasCertificateTableCounterSignerCertificate())
|
||||
{
|
||||
info.push_back(std::to_string(fileinfo.getCertificateTableCounterSignerCertificateIndex()));
|
||||
}
|
||||
else
|
||||
{
|
||||
info.push_back("");
|
||||
}
|
||||
|
||||
return info.size();
|
||||
}
|
||||
|
||||
bool CertificateTablePlainGetter::getRecord(std::size_t structIndex, std::size_t recIndex, std::vector<std::string> &record) const
|
||||
{
|
||||
if(structIndex >= numberOfStructures || recIndex >= numberOfStoredRecords[structIndex])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
record.clear();
|
||||
record.push_back(replaceNonprintableChars(fileinfo.getCertificateSubjectCommonName(recIndex)));
|
||||
record.push_back(replaceNonprintableChars(fileinfo.getCertificateSubjectOrganization(recIndex)));
|
||||
record.push_back(fileinfo.getCertificateSubjectRawStr(recIndex));
|
||||
record.push_back(replaceNonprintableChars(fileinfo.getCertificateIssuerCommonName(recIndex)));
|
||||
record.push_back(replaceNonprintableChars(fileinfo.getCertificateIssuerOrganization(recIndex)));
|
||||
record.push_back(fileinfo.getCertificateIssuerRawStr(recIndex));
|
||||
record.push_back(fileinfo.getCertificatePublicKeyAlgorithm(recIndex));
|
||||
record.push_back(fileinfo.getCertificateSignatureAlgorithm(recIndex));
|
||||
record.push_back(fileinfo.getCertificateSerialNumber(recIndex));
|
||||
record.push_back(fileinfo.getCertificateValidSince(recIndex));
|
||||
record.push_back(fileinfo.getCertificateValidUntil(recIndex));
|
||||
record.push_back(fileinfo.getCertificateSha1Digest(recIndex));
|
||||
record.push_back(fileinfo.getCertificateSha256Digest(recIndex));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CertificateTablePlainGetter::getFlags(std::size_t structIndex, std::size_t recIndex, std::string &flagsValue, std::vector<std::string> &desc) const
|
||||
{
|
||||
if(structIndex >= numberOfStructures || recIndex >= numberOfStoredRecords[structIndex])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
flagsValue.clear();
|
||||
desc.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fileinfo
|
||||
} // namespace retdec
|
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* @file src/fileinfo/file_presentation/getters/iterative_getter/iterative_simple_getter/certificate_table_plain_getter.h
|
||||
* @brief Definition of CertificateTablePlainGetter class.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef FILEINFO_FILE_PRESENTATION_GETTERS_ITERATIVE_GETTER_ITERATIVE_SIMPLE_GETTER_CERTIFICATE_TABLE_PLAIN_GETTER_H
|
||||
#define FILEINFO_FILE_PRESENTATION_GETTERS_ITERATIVE_GETTER_ITERATIVE_SIMPLE_GETTER_CERTIFICATE_TABLE_PLAIN_GETTER_H
|
||||
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_simple_getter/iterative_simple_getter.h"
|
||||
|
||||
namespace retdec {
|
||||
namespace fileinfo {
|
||||
|
||||
/**
|
||||
* Getter for certificate table
|
||||
*/
|
||||
class CertificateTablePlainGetter : public IterativeSimpleGetter
|
||||
{
|
||||
public:
|
||||
CertificateTablePlainGetter(FileInformation &fileInfo);
|
||||
|
||||
virtual std::size_t getBasicInfo(std::size_t structIndex, std::vector<std::string> &desc, std::vector<std::string> &info) const override;
|
||||
virtual bool getRecord(std::size_t structIndex, std::size_t recIndex, std::vector<std::string> &record) const override;
|
||||
virtual bool getFlags(std::size_t structIndex, std::size_t recIndex, std::string &flagsValue, std::vector<std::string> &desc) const override;
|
||||
};
|
||||
|
||||
} // namespace fileinfo
|
||||
} // namespace retdec
|
||||
|
||||
#endif
|
@ -27,10 +27,10 @@
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/symbol_tables_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/tls_info_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_simple_getter/certificate_table_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/version_info_language_table_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/version_info_string_table_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/iterative_getter/iterative_simple_getter/iterative_simple_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/simple_getter/basic_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/simple_getter/dotnet_plain_getter.h"
|
||||
#include "fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.h"
|
||||
|
@ -4,6 +4,7 @@
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
#include "retdec/utils/conversion.h"
|
||||
#include "retdec/utils/string.h"
|
||||
#include "retdec/utils/io/log.h"
|
||||
@ -387,129 +388,62 @@ void JsonPresentation::presentLoaderInfo(Writer& writer) const
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Present information about certificates into certificate table
|
||||
*/
|
||||
void JsonPresentation::presentCertificates(Writer& writer) const
|
||||
void WriteCertificateChain(JsonPresentation::Writer& writer, const std::vector<Certificate>& certificates)
|
||||
{
|
||||
if(!fileinfo.hasCertificateTableRecords())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.String("certificateTable");
|
||||
writer.StartObject();
|
||||
|
||||
// Basic info.
|
||||
serializeString(
|
||||
writer,
|
||||
"numberOfCertificates",
|
||||
std::to_string(fileinfo.getNumberOfStoredCertificates()));
|
||||
if (fileinfo.hasCertificateTableSignerCertificate())
|
||||
{
|
||||
serializeString(
|
||||
writer,
|
||||
"signerCertificateIndex",
|
||||
std::to_string(fileinfo.getCertificateTableSignerCertificateIndex()));
|
||||
}
|
||||
if (fileinfo.hasCertificateTableCounterSignerCertificate())
|
||||
{
|
||||
serializeString(
|
||||
writer,
|
||||
"counterSignerCertificateIndex",
|
||||
std::to_string(fileinfo.getCertificateTableCounterSignerCertificateIndex()));
|
||||
}
|
||||
|
||||
writer.String("certificates");
|
||||
writer.StartArray();
|
||||
for(std::size_t i = 0; i < fileinfo.getNumberOfStoredCertificates(); ++i)
|
||||
for (auto&& cert : certificates)
|
||||
{
|
||||
writer.StartObject();
|
||||
|
||||
serializeString(
|
||||
writer,
|
||||
"index",
|
||||
std::to_string(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"validSince",
|
||||
fileinfo.getCertificateValidSince(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"validUntil",
|
||||
fileinfo.getCertificateValidUntil(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"publicKey",
|
||||
fileinfo.getCertificatePublicKey(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"publicKeyAlgorithm",
|
||||
fileinfo.getCertificatePublicKeyAlgorithm(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"signatureAlgorithm",
|
||||
fileinfo.getCertificateSignatureAlgorithm(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"serialNumber",
|
||||
fileinfo.getCertificateSerialNumber(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"issuer",
|
||||
fileinfo.getCertificateIssuerRawStr(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"subject",
|
||||
fileinfo.getCertificateSubjectRawStr(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"sha1",
|
||||
fileinfo.getCertificateSha1Digest(i));
|
||||
serializeString(
|
||||
writer,
|
||||
"sha256",
|
||||
fileinfo.getCertificateSha256Digest(i));
|
||||
serializeString(writer, "subject", cert.getRawSubject());
|
||||
serializeString(writer, "issuer", cert.getRawIssuer());
|
||||
serializeString(writer, "serialNumber", cert.getSerialNumber());
|
||||
serializeString(writer, "publicKeyAlgorithm", cert.getPublicKeyAlgorithm());
|
||||
serializeString(writer, "signatureAlgorithm", cert.getSignatureAlgorithm());;
|
||||
serializeString(writer, "validSince", cert.getValidSince());
|
||||
serializeString(writer, "validUntil", cert.getValidUntil());
|
||||
serializeString(writer, "sha1", cert.getSha1Digest());
|
||||
serializeString(writer, "sha256", cert.getSha256Digest());
|
||||
serializeString(writer, "publicKey", cert.getPublicKey());
|
||||
|
||||
writer.String("attributes");
|
||||
writer.StartObject();
|
||||
|
||||
writer.String("issuer");
|
||||
writer.StartObject();
|
||||
serializeString(writer, "country", fileinfo.getCertificateIssuerCountry(i));
|
||||
serializeString(writer, "organization", fileinfo.getCertificateIssuerOrganization(i));
|
||||
serializeString(writer, "organizationalUnit", fileinfo.getCertificateIssuerOrganizationalUnit(i));
|
||||
serializeString(writer, "nameQualifier", fileinfo.getCertificateIssuerNameQualifier(i));
|
||||
serializeString(writer, "state", fileinfo.getCertificateIssuerState(i));
|
||||
serializeString(writer, "commonName", fileinfo.getCertificateIssuerCommonName(i));
|
||||
serializeString(writer, "serialNumber", fileinfo.getCertificateIssuerSerialNumber(i));
|
||||
serializeString(writer, "locality", fileinfo.getCertificateIssuerLocality(i));
|
||||
serializeString(writer, "title", fileinfo.getCertificateIssuerTitle(i));
|
||||
serializeString(writer, "surname", fileinfo.getCertificateIssuerSurname(i));
|
||||
serializeString(writer, "givenName", fileinfo.getCertificateIssuerGivenName(i));
|
||||
serializeString(writer, "initials", fileinfo.getCertificateIssuerInitials(i));
|
||||
serializeString(writer, "pseudonym", fileinfo.getCertificateIssuerPseudonym(i));
|
||||
serializeString(writer, "generationQualifier", fileinfo.getCertificateIssuerGenerationQualifier(i));
|
||||
serializeString(writer, "emailAddress", fileinfo.getCertificateIssuerEmailAddress(i));
|
||||
writer.EndObject();
|
||||
|
||||
writer.String("subject");
|
||||
writer.StartObject();
|
||||
serializeString(writer, "country", fileinfo.getCertificateSubjectCountry(i));
|
||||
serializeString(writer, "organization", fileinfo.getCertificateSubjectOrganization(i));
|
||||
serializeString(writer, "organizationalUnit", fileinfo.getCertificateSubjectOrganizationalUnit(i));
|
||||
serializeString(writer, "nameQualifier", fileinfo.getCertificateSubjectNameQualifier(i));
|
||||
serializeString(writer, "state", fileinfo.getCertificateSubjectState(i));
|
||||
serializeString(writer, "commonName", fileinfo.getCertificateSubjectCommonName(i));
|
||||
serializeString(writer, "serialNumber", fileinfo.getCertificateSubjectSerialNumber(i));
|
||||
serializeString(writer, "locality", fileinfo.getCertificateSubjectLocality(i));
|
||||
serializeString(writer, "title", fileinfo.getCertificateSubjectTitle(i));
|
||||
serializeString(writer, "surname", fileinfo.getCertificateSubjectSurname(i));
|
||||
serializeString(writer, "givenName", fileinfo.getCertificateSubjectGivenName(i));
|
||||
serializeString(writer, "initials", fileinfo.getCertificateSubjectInitials(i));
|
||||
serializeString(writer, "pseudonym", fileinfo.getCertificateSubjectPseudonym(i));
|
||||
serializeString(writer, "generationQualifier", fileinfo.getCertificateSubjectGenerationQualifier(i));
|
||||
serializeString(writer, "emailAddress", fileinfo.getCertificateSubjectEmailAddress(i));
|
||||
serializeString(writer, "country", cert.getSubject().country);
|
||||
serializeString(writer, "organization", cert.getSubject().organization);
|
||||
serializeString(writer, "organizationalUnit", cert.getSubject().organizationalUnit);
|
||||
serializeString(writer, "nameQualifier", cert.getSubject().nameQualifier);
|
||||
serializeString(writer, "state", cert.getSubject().state);
|
||||
serializeString(writer, "commonName", cert.getSubject().commonName);
|
||||
serializeString(writer, "serialNumber", cert.getSubject().serialNumber);
|
||||
serializeString(writer, "locality", cert.getSubject().locality);
|
||||
serializeString(writer, "title", cert.getSubject().title);
|
||||
serializeString(writer, "surname", cert.getSubject().surname);
|
||||
serializeString(writer, "givenName", cert.getSubject().givenName);
|
||||
serializeString(writer, "initials", cert.getSubject().initials);
|
||||
serializeString(writer, "pseudonym", cert.getSubject().pseudonym);
|
||||
serializeString(writer, "generationQualifier", cert.getSubject().generationQualifier);
|
||||
serializeString(writer, "emailAddress", cert.getSubject().emailAddress);
|
||||
writer.EndObject();
|
||||
|
||||
writer.String("issuer");
|
||||
writer.StartObject();
|
||||
serializeString(writer, "country", cert.getIssuer().country);
|
||||
serializeString(writer, "organization", cert.getIssuer().organization);
|
||||
serializeString(writer, "organizationalUnit", cert.getIssuer().organizationalUnit);
|
||||
serializeString(writer, "nameQualifier", cert.getIssuer().nameQualifier);
|
||||
serializeString(writer, "state", cert.getIssuer().state);
|
||||
serializeString(writer, "commonName", cert.getIssuer().commonName);
|
||||
serializeString(writer, "serialNumber", cert.getIssuer().serialNumber);
|
||||
serializeString(writer, "locality", cert.getIssuer().locality);
|
||||
serializeString(writer, "title", cert.getIssuer().title);
|
||||
serializeString(writer, "surname", cert.getIssuer().surname);
|
||||
serializeString(writer, "givenName", cert.getIssuer().givenName);
|
||||
serializeString(writer, "initials", cert.getIssuer().initials);
|
||||
serializeString(writer, "pseudonym", cert.getIssuer().pseudonym);
|
||||
serializeString(writer, "generationQualifier", cert.getIssuer().generationQualifier);
|
||||
serializeString(writer, "emailAddress", cert.getIssuer().emailAddress);
|
||||
writer.EndObject();
|
||||
|
||||
writer.EndObject();
|
||||
@ -517,7 +451,83 @@ void JsonPresentation::presentCertificates(Writer& writer) const
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
|
||||
void WriteSigner(JsonPresentation::Writer& writer, const Signer& signer)
|
||||
{
|
||||
writer.StartObject();
|
||||
writer.String("warnings");
|
||||
writer.StartArray();
|
||||
for (auto&& warn : signer.warnings) {
|
||||
writer.String(warn);
|
||||
}
|
||||
writer.EndArray();
|
||||
|
||||
serializeString(writer, "signTime", signer.signingTime);
|
||||
|
||||
serializeString(writer, "digest", signer.digest);
|
||||
|
||||
serializeString(writer, "digestAlgorithm", signer.digestAlgorithm);
|
||||
|
||||
writer.String("chain");
|
||||
WriteCertificateChain(writer, signer.chain);
|
||||
|
||||
writer.String("counterSigners");
|
||||
writer.StartArray();
|
||||
for (auto&& csigner : signer.counterSigners) {
|
||||
WriteSigner(writer, csigner);
|
||||
}
|
||||
writer.EndArray();
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
void WriteSignature(JsonPresentation::Writer& writer, const DigitalSignature& signature)
|
||||
{
|
||||
writer.StartObject();
|
||||
writer.String("warnings");
|
||||
writer.StartArray();
|
||||
for (auto&& warn : signature.warnings) {
|
||||
writer.String(warn);
|
||||
}
|
||||
writer.EndArray();
|
||||
|
||||
serializeString(writer, "digestAlgorithm", signature.digestAlgorithm);
|
||||
serializeString(writer, "fileDigest", signature.fileDigest);
|
||||
serializeString(writer, "signedDigest", signature.signedDigest);
|
||||
serializeString(writer, "programName", signature.programName);
|
||||
|
||||
writer.String("allCertificates");
|
||||
WriteCertificateChain(writer, signature.certificates);
|
||||
|
||||
writer.String("signer");
|
||||
WriteSigner(writer, signature.signer);
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Present information about certificates into certificate table
|
||||
*/
|
||||
void JsonPresentation::presentCertificates(Writer& writer) const
|
||||
{
|
||||
|
||||
if(!fileinfo.certificateTable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.String("digitalSignatures");
|
||||
writer.StartObject();
|
||||
writer.Key("numberOfSignatures");
|
||||
writer.Int64(fileinfo.certificateTable->signatures.size());
|
||||
writer.String("signatures");
|
||||
writer.StartArray();
|
||||
for (auto&& signature : fileinfo.certificateTable->signatures)
|
||||
{
|
||||
WriteSignature(writer, signature);
|
||||
}
|
||||
writer.EndArray();
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include "retdec/fileformat/types/certificate_table/certificate.h"
|
||||
#include "retdec/fileformat/types/certificate_table/certificate_table.h"
|
||||
#include "retdec/utils/string.h"
|
||||
#include "retdec/utils/io/log.h"
|
||||
#include "retdec/utils/version.h"
|
||||
@ -11,6 +13,7 @@
|
||||
#include "fileinfo/file_presentation/getters/format.h"
|
||||
#include "fileinfo/file_presentation/getters/plain_getters.h"
|
||||
#include "fileinfo/file_presentation/plain_presentation.h"
|
||||
#include <string>
|
||||
|
||||
using namespace retdec::utils;
|
||||
using namespace retdec::utils::io;
|
||||
@ -710,6 +713,76 @@ void PlainPresentation::presentCore() const
|
||||
}
|
||||
}
|
||||
|
||||
static void printCertificate(const Certificate& cert, int indent)
|
||||
{
|
||||
Log::info() << std::string(indent, ' ') << "Subject: " << cert.getRawSubject() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Issuer: " << cert.getRawIssuer() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Serial: " << cert.getSerialNumber() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "SHA1: " << cert.getSha1Digest() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "SHA256: " << cert.getSha256Digest() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Valid since: " << cert.getValidSince() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Valid until: " << cert.getValidUntil() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Signature Algorithm: " << cert.getSignatureAlgorithm() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Public Key Algorithm: " << cert.getPublicKeyAlgorithm() << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Public key: " << cert.getPublicKey() << ":\n";
|
||||
}
|
||||
|
||||
static void printCertificateChain(const std::vector<Certificate>& certs, int indent)
|
||||
{
|
||||
for (int idx = 0; idx < certs.size(); idx++) {
|
||||
Log::info() << std::string(indent, ' ') << "Certificate #" << idx << "\n";
|
||||
printCertificate(certs[idx], indent + 4);
|
||||
Log::info() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void printSigner(const Signer& signer, int indent)
|
||||
{
|
||||
|
||||
Log::info() << std::string(indent, ' ') << "Digest Algorithm: " << signer.digestAlgorithm << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Digest: " << signer.digest << "\n";
|
||||
if (!signer.signingTime.empty()) {
|
||||
Log::info() << std::string(indent, ' ') << "Signing time: " << signer.signingTime << "\n";
|
||||
}
|
||||
|
||||
printCertificateChain(signer.chain, indent);
|
||||
|
||||
for (int idx = 0; idx < signer.counterSigners.size(); idx++) {
|
||||
Log::info() << std::string(indent, ' ') << "Countersigner #" << idx << ":\n";
|
||||
printSigner(signer.counterSigners[idx], indent + 4);
|
||||
Log::info() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void printSignature(const DigitalSignature& signature, int indent)
|
||||
{
|
||||
Log::info() << std::string(indent, ' ') << "Digest Algorithm: " << signature.digestAlgorithm << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Signed Digest: " << signature.signedDigest << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "File Digest: " << signature.fileDigest << "\n";
|
||||
Log::info() << std::string(indent, ' ') << "Program Name: " << signature.programName << "\n";
|
||||
|
||||
Log::info() << std::string(indent, ' ') << "Signer:\n";
|
||||
printSigner(signature.signer, indent + 4);
|
||||
Log::info() << "\n";
|
||||
}
|
||||
|
||||
void PlainPresentation::presentSignatures() const
|
||||
{
|
||||
const CertificateTable* table = fileinfo.certificateTable;
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
Log::info() << "Digital Signatures:\n";
|
||||
int indent = 4;
|
||||
Log::info() << std::string(indent, ' ') << "Signature count: " << table->signatureCount() << "\n";
|
||||
|
||||
for (int idx = 0; idx < table->signatureCount(); idx++) {
|
||||
Log::info() << std::string(indent, ' ') << "Signature #" << idx << ":\n";
|
||||
printSignature(table->signatures[idx], indent + 4);
|
||||
Log::info() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool PlainPresentation::present()
|
||||
{
|
||||
if(verbose)
|
||||
@ -795,8 +868,8 @@ bool PlainPresentation::present()
|
||||
}
|
||||
Log::info() << replaceNonasciiChars(manifest);
|
||||
}
|
||||
presentSignatures();
|
||||
|
||||
presentIterativeSimple(CertificateTablePlainGetter(fileinfo));
|
||||
presentSimple(DotnetPlainGetter(fileinfo), false, ".NET Information");
|
||||
presentDotnetClasses();
|
||||
presentSimple(VisualBasicPlainGetter(fileinfo), false, "Visual Basic Information");
|
||||
|
@ -34,6 +34,7 @@ class PlainPresentation : public FilePresentation
|
||||
void presentVisualBasicObjects() const;
|
||||
void presentNotes() const;
|
||||
void presentCore() const;
|
||||
void presentSignatures() const;
|
||||
/// @}
|
||||
public:
|
||||
PlainPresentation(FileInformation &fileinfo_, bool verbose_, bool explanatory_);
|
||||
|
@ -51,7 +51,7 @@ namespace PeLib
|
||||
inStream_w.seekg(uiOffset, std::ios::beg);
|
||||
|
||||
std::vector<unsigned char> vCertDirectory(uiSize);
|
||||
inStream_w.read(reinterpret_cast<char*>(vCertDirectory.data()), uiSize);
|
||||
inStream_w.read(reinterpret_cast<char*>(vCertDirectory.data()), uiSize); // reads the whole directory
|
||||
|
||||
// Verify zeroed certificates (00002edec5247488029b2cc69568dda90714eeed8de0d84f1488635196b7e708)
|
||||
if (std::all_of(vCertDirectory.begin(), vCertDirectory.end(), [](unsigned char item) { return item == 0; }))
|
||||
|
Loading…
x
Reference in New Issue
Block a user