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:
HoundThe 2021-05-20 13:56:14 +02:00 committed by GitHub
parent 4878585d1a
commit d80009788d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 2078 additions and 1983 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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)

View File

@ -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)

View 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

View 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

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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 structures 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

View File

@ -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

View 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

View File

@ -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

View File

@ -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));
}
/**

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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());
}
}
/**

View File

@ -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;
}
/**

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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();
}

View File

@ -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");

View File

@ -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_);

View File

@ -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; }))