Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add parsing of the PE Authenticode format #902

Merged
merged 59 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
626fd17
init
HoundThe Aug 19, 2020
021bdd5
Some more glue
HoundThe Sep 3, 2020
857814a
Add Certificate processing
HoundThe Sep 4, 2020
9594802
Added ability to get signers cert chain, counter signer chain, restru…
HoundThe Sep 17, 2020
242912b
Solve merge conflicts
HoundThe Sep 18, 2020
fee9f77
Add printing of nested signatures
HoundThe Sep 18, 2020
66d2926
Major refactor
HoundThe Sep 26, 2020
a285c42
Merge remote-tracking branch 'upstream/master' into sig_parser
HoundThe Sep 26, 2020
88f5572
Refactoring, adding details
HoundThe Oct 1, 2020
0c089f6
Refactor
HoundThe Oct 26, 2020
26ab79a
refactor, extending authenticode to return signature abstraciton, res…
HoundThe Nov 10, 2020
11ddfaf
large restructuring, implementing authenticode to general signature i…
HoundThe Nov 14, 2020
d1e0f6c
Merge branch 'master' into sig_parser
HoundThe Nov 14, 2020
3713419
Added prototype of new json format for certificates
HoundThe Nov 23, 2020
010983e
adhere to the code style
HoundThe Nov 26, 2020
82c31dc
commiting forgotten certificate TU
HoundThe Nov 26, 2020
5a0b4c8
Adding copyright header
HoundThe Nov 26, 2020
0db160f
decluttering authenticode interfaces, removing obsolete comments
HoundThe Nov 26, 2020
b3724ed
decluttering authenticode interfaces, removing obsolete comments, upd…
HoundThe Nov 26, 2020
adc1d92
Merge branch 'sig_parser' of github.com:HoundThe/retdec into sig_parser
HoundThe Nov 29, 2020
aceca5f
Merge branch 'master' into sig_parser
HoundThe Nov 29, 2020
2c64333
Remove <filesystem> dependency
HoundThe Nov 29, 2020
92f3e0d
Restructure of ContentInfo parsing, better error checking based on MS…
HoundThe Jan 26, 2021
f8ed27b
Completed parsing of all members of SignedData that are in the specif…
HoundThe Jan 27, 2021
413f060
Complete parsing of all SignerInfo information based on MS specification
HoundThe Jan 28, 2021
cf39983
Added sha1 and sha256 certificate digests
HoundThe Feb 3, 2021
601c157
Finish extraction of all certificate information that was exported in…
HoundThe Feb 3, 2021
bf32724
Improving error handling and proper deallocation
HoundThe Feb 9, 2021
da364b4
Got rid of all leaks
HoundThe Feb 10, 2021
8ad3c12
Added base for MsCounterSignatures and Pkcs9CounterSignatures and the…
HoundThe Feb 14, 2021
7d0279d
Remove fileinfo certificateTable
HoundThe Feb 15, 2021
116dee7
Add more parsed information to the output, Implement plain text output
HoundThe Feb 15, 2021
138bc71
Forgot to add ms_counter_signature files to git
HoundThe Feb 15, 2021
b39169c
Adding better validation and feedback
HoundThe Feb 23, 2021
e785ca3
Add the renamed source files to git
HoundThe Feb 26, 2021
71a171a
Add verification of Pkcs7 signatures and Pkcs9 countersignatures
HoundThe Mar 5, 2021
b6332a8
Implement ms counter signature verification and output of verificatio…
HoundThe Mar 5, 2021
3d41b20
remove non trivial intializers
HoundThe Mar 6, 2021
78fadfa
Polishing verification, adding all certificates to the output, redone…
HoundThe Mar 6, 2021
7d2f509
Improve error handling
HoundThe Mar 10, 2021
c0b3ed5
Fix uninitialized values due to parsing errors
HoundThe Mar 10, 2021
32d7224
Get rid of exceptions
HoundThe Mar 11, 2021
6486b60
Fix more edge cases
HoundThe Mar 26, 2021
33438d6
Add verification if the signed and file hash match, modify the plain …
HoundThe Mar 27, 2021
ed18c3a
Fix unhandled null dereferences and uninitialized branches
HoundThe Mar 29, 2021
cbe6eea
Merge branch 'master' into sig_parser
HoundThe Mar 29, 2021
fd201ba
Remove unnecessary copying
HoundThe Apr 12, 2021
1bbc9dd
Add programName from SpcOpusInfo to the output, remove dead code, add…
HoundThe May 11, 2021
7c102ba
Revert indent, add proper doxygen file comments
HoundThe May 11, 2021
33a266c
Add certificate public key back to output
HoundThe May 14, 2021
bdf4f6e
Remove dots from error messages
HoundThe May 14, 2021
e9ac71d
pkcs7_signature.cpp: fix doxygen
PeterMatula May 18, 2021
d457293
pkcs7_signature.h: fix doxygen
PeterMatula May 18, 2021
84acca9
pkcs9_counter_signature.cpp: fix doxygen
PeterMatula May 18, 2021
75f162a
pkcs9_counter_signature.h: fix doxygen
PeterMatula May 18, 2021
3f0cd9c
pkcs7_signature.cpp: fix doxygen and source
PeterMatula May 18, 2021
da1321f
authenticode_structs.h: fix doxygen
PeterMatula May 18, 2021
80cc5b8
authenticode_structs.cpp: fix doxygen
PeterMatula May 18, 2021
bef8d67
Remove undefined behaviour, set default value of algorithm type
HoundThe May 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
/// @}

/// @name Setters
/// @{
void setSignerCertificateIndex(std::size_t certIndex);
void setCounterSignerCertificateIndex(std::size_t certIndex);
/// @}

/// @name Iterators
/// @{
certificatesIterator begin() const;
certificatesIterator end() const;
/// @}
public:
std::vector<DigitalSignature> signatures;

/// @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
Expand Down
7 changes: 7 additions & 0 deletions src/fileformat/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,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
Expand Down
18 changes: 18 additions & 0 deletions src/fileformat/file_format/pe/authenticode/authenticode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @file src/fileformat/file_format/pe/authenticode/authenticode.cpp
* @brief Class that parses PE Authenticode data
* @copyright (c) 2021 Avast Software, licensed under the MIT license
*/

#include "authenticode.h"

namespace authenticode {
Authenticode::Authenticode(const std::vector<unsigned char>& data)
: pkcs7(data) {}

std::vector<DigitalSignature> Authenticode::getSignatures(const retdec::fileformat::PeFormat* peFile) const
{
return pkcs7.getSignatures(peFile);
}

} // namespace authenticode
42 changes: 42 additions & 0 deletions src/fileformat/file_format/pe/authenticode/authenticode.h
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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 */
HoundThe marked this conversation as resolved.
Show resolved Hide resolved

#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)
95 changes: 95 additions & 0 deletions src/fileformat/file_format/pe/authenticode/authenticode_structs.h
Original file line number Diff line number Diff line change
@@ -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)
Loading