Skip to content

Commit b9cd46d

Browse files
HoundTheplusvic
andauthored
Process Authenticode signatures using authenticode-parser (#1623)
* Import authenticode-parser into Yara. Rewrite PE signature processing using the authenticode-parser. Update bazel OpenSSL dependency to 1.1.1 from 1.1.0 * Forgot to include structs.c * Add Avast to authors and myself to contributors * Set forgotten algorithm_oid * Fix incorrect indentation * Fix race condition when initializing openssl objects * Don't malloc ByteArray with length 0 * Auth. parser update - bug fixes, openssl3.0 support * Update authenticode parser Co-authored-by: Victor M. Alvarez <[email protected]>
1 parent 22fde83 commit b9cd46d

File tree

22 files changed

+2570
-301
lines changed

22 files changed

+2570
-301
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
# Please keep the list sorted.
1010

11+
Avast
1112
Google Inc.
1213
Hilko Bengen <[email protected]>
1314
Joachim Metz <[email protected]>

CONTRIBUTORS

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Antonio Vargas Gonzalez <[email protected]>
3131
Christian Blichmann <[email protected]>
3232
Hilko Bengen <[email protected]>
3333
Joachim Metz <[email protected]>
34+
Karel Hajek <[email protected]>
3435
Karl Hiramoto <[email protected]>
3536
Mike Wiacek <[email protected]>
3637
Shane Huntley <[email protected]>

bazel/yara.bzl

+10
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,16 @@ def yara_library(
194194
"libyara/stream.c",
195195
"libyara/strutils.c",
196196
"libyara/threading.c",
197+
"libyara/include/authenticode-parser/authenticode.h",
198+
"libyara/modules/pe/authenticode-parser/authenticode.c",
199+
"libyara/modules/pe/authenticode-parser/certificate.c",
200+
"libyara/modules/pe/authenticode-parser/certificate.h",
201+
"libyara/modules/pe/authenticode-parser/countersignature.c",
202+
"libyara/modules/pe/authenticode-parser/countersignature.h",
203+
"libyara/modules/pe/authenticode-parser/helper.c",
204+
"libyara/modules/pe/authenticode-parser/helper.h",
205+
"libyara/modules/pe/authenticode-parser/structs.c",
206+
"libyara/modules/pe/authenticode-parser/structs.h",
197207
"libyara/tlshc/tlsh.c",
198208
"libyara/tlshc/tlsh_impl.c",
199209
"libyara/tlshc/tlsh_impl.h",

configure.ac

+2
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ AS_IF([test "x$have_crypto" = "xno"],
332332
])
333333
],
334334
[
335+
build_authenticode_module=true # Authenticode relies on openssl
335336
build_hash_module=true
336337
CFLAGS="$CFLAGS -DHASH_MODULE"
337338
PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE libcrypto"
@@ -351,6 +352,7 @@ AM_CONDITIONAL([UB_SANITIZER], [test x$undefined_behaviour_sanitizer = xtrue])
351352
AM_CONDITIONAL([CUCKOO_MODULE], [test x$build_cuckoo_module = xtrue])
352353
AM_CONDITIONAL([MAGIC_MODULE], [test x$build_magic_module = xtrue])
353354
AM_CONDITIONAL([HASH_MODULE], [test x$build_hash_module = xtrue])
355+
AM_CONDITIONAL([AUTHENTICODE_MODULE], [test x$build_authenticode_module = xtrue])
354356
AM_CONDITIONAL([DOTNET_MODULE], [test x$build_dotnet_module = xtrue])
355357
AM_CONDITIONAL([MACHO_MODULE], [test x$build_macho_module = xtrue])
356358
AM_CONDITIONAL([PB_TESTS_MODULE], [test x$build_pb_tests_module = xtrue])

docs/modules/pe.rst

+115
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,10 @@ Reference
820820
821821
Number of authenticode signatures in the PE.
822822

823+
.. c:type:: is_signed
824+
825+
True if any of the PE signatures is valid.
826+
823827
.. c:type:: signatures
824828
825829
A zero-based array of signature objects, one for each authenticode
@@ -898,6 +902,117 @@ Reference
898902

899903
timestamp >= pe.signatures[n].not_before and timestamp <= pe.signatures[n].not_after
900904

905+
.. c:member:: verified
906+
907+
Boolean, true if signature was sucessfully verified.
908+
909+
.. c:member:: digest_alg
910+
911+
Name of the algorithm used for file digest. Usually "sha1" or "sha256"
912+
913+
.. c:member:: digest
914+
915+
Digest of the file signed in the signature.
916+
917+
.. c:member:: file_digest
918+
919+
Calculated digest using digest_alg of the analysed file.
920+
921+
.. c:member:: number_of_certificates
922+
923+
Number of the certificates stored in the signature, including the ones in countersignatures.
924+
925+
.. c:type:: certificates
926+
927+
A zero-based array of certificates stored in the signature, including the ones in countersignatures.
928+
The members of the certificates are identical to those already explained before, with the same name.
929+
930+
.. c:member:: thumbprint
931+
.. c:member:: issuer
932+
.. c:member:: subject
933+
.. c:member:: version
934+
.. c:member:: algorithm
935+
.. c:member:: serial
936+
.. c:member:: not_before
937+
.. c:member:: not_after
938+
939+
.. c:type:: signer_info
940+
941+
Information about the signature signer.
942+
943+
.. c:member:: program_name
944+
945+
Optional program name stored in the signature.
946+
947+
.. c:member:: digest
948+
949+
Signed digest of the signature.
950+
951+
.. c:member:: digest_alg
952+
953+
Algorithm used for the digest of the signature. Usually "sha1" or "sha256"
954+
955+
.. c:member:: length_of_chain
956+
957+
Number of certificates in the signers chain.
958+
959+
.. c:type:: chain
960+
961+
A zero-based array of certificates in the signers chain. The members of the certificates are
962+
identical to those already explained before, with the same name.
963+
964+
.. c:member:: thumbprint
965+
.. c:member:: issuer
966+
.. c:member:: subject
967+
.. c:member:: version
968+
.. c:member:: algorithm
969+
.. c:member:: serial
970+
.. c:member:: not_before
971+
.. c:member:: not_after
972+
973+
.. c:member:: number_of_countersignatures
974+
975+
Number of the countersignatures of the signature.
976+
977+
.. c:type:: countersignatures
978+
979+
A zero-based array of the countersignatures of the signature.
980+
Almost always it's just single timestamp one.
981+
982+
.. c:member:: verified
983+
984+
Boolean, true if countersignature was sucessfully verified.
985+
986+
.. c:member:: sign_time
987+
988+
Integer - unix time of the timestamp signing time.
989+
990+
.. c:member:: digest
991+
992+
Signed digest of the countersignature.
993+
994+
.. c:member:: digest_alg
995+
996+
Algorithm used for the digest of the countersignature. Usually "sha1" or "sha256"
997+
998+
.. c:member:: length_of_chain
999+
1000+
Number of certificates in the countersigners chain.
1001+
1002+
.. c:type:: chain
1003+
1004+
A zero-based array of certificates in the countersigners chain. The members of the certificates are
1005+
identical to those already explained before, with the same name.
1006+
1007+
.. c:member:: thumbprint
1008+
.. c:member:: issuer
1009+
.. c:member:: subject
1010+
.. c:member:: version
1011+
.. c:member:: algorithm
1012+
.. c:member:: serial
1013+
.. c:member:: not_before
1014+
.. c:member:: not_after
1015+
9011016
.. c:type:: rich_signature
9021017
9031018
Structure containing information about the PE's rich signature as

libyara/Makefile.am

+8
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ MODULES += modules/pb_tests/pb_tests.c
7777
MODULES += modules/pb_tests/pb_tests.pb-c.c
7878
endif
7979

80+
if AUTHENTICODE_MODULE
81+
MODULES += modules/pe/authenticode-parser/authenticode.c
82+
MODULES += modules/pe/authenticode-parser/certificate.c
83+
MODULES += modules/pe/authenticode-parser/helper.c
84+
MODULES += modules/pe/authenticode-parser/countersignature.c
85+
MODULES += modules/pe/authenticode-parser/structs.c
86+
endif
87+
8088
#
8189
# Add your modules here:
8290
#
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/* Copyright (c) 2021 Avast Software
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of
4+
this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights to
6+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7+
of the Software, and to permit persons to whom the Software is furnished to do
8+
so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
SOFTWARE.
20+
*/
21+
22+
#ifndef AUTHENTICODE_PARSER_AUTHENTICODE_H
23+
#define AUTHENTICODE_PARSER_AUTHENTICODE_H
24+
25+
#ifdef __cplusplus
26+
extern "C" {
27+
#endif
28+
29+
#include <stdint.h>
30+
#include <time.h>
31+
32+
/* Signature is valid */
33+
#define AUTHENTICODE_VFY_VALID 0
34+
/* Parsing error (from OpenSSL functions) */
35+
#define AUTHENTICODE_VFY_CANT_PARSE 1
36+
/* Signers certificate is missing */
37+
#define AUTHENTICODE_VFY_NO_SIGNER_CERT 2
38+
/* No digest saved inside the signature */
39+
#define AUTHENTICODE_VFY_DIGEST_MISSING 3
40+
/* Non verification errors - allocations etc. */
41+
#define AUTHENTICODE_VFY_INTERNAL_ERROR 4
42+
/* SignerInfo part of PKCS7 is missing */
43+
#define AUTHENTICODE_VFY_NO_SIGNER_INFO 5
44+
/* PKCS7 doesn't have type of SignedData, can't proceed */
45+
#define AUTHENTICODE_VFY_WRONG_PKCS7_TYPE 6
46+
/* PKCS7 doesn't have corrent content, can't proceed */
47+
#define AUTHENTICODE_VFY_BAD_CONTENT 7
48+
/* Contained and calculated digest don't match */
49+
#define AUTHENTICODE_VFY_INVALID 8
50+
/* Signature hash and file hash doesn't match */
51+
#define AUTHENTICODE_VFY_WRONG_FILE_DIGEST 9
52+
/* Unknown algorithm, can't proceed with verification */
53+
#define AUTHENTICODE_VFY_UNKNOWN_ALGORITHM 10
54+
55+
/* Countersignature is valid */
56+
#define COUNTERSIGNATURE_VFY_VALID 0
57+
/* Parsing error (from OpenSSL functions) */
58+
#define COUNTERSIGNATURE_VFY_CANT_PARSE 1
59+
/* Signers certificate is missing */
60+
#define COUNTERSIGNATURE_VFY_NO_SIGNER_CERT 2
61+
/* Unknown algorithm, can't proceed with verification */
62+
#define COUNTERSIGNATURE_VFY_UNKNOWN_ALGORITHM 3
63+
/* Verification failed, digest mismatch */
64+
#define COUNTERSIGNATURE_VFY_INVALID 4
65+
/* Failed to decrypt countersignature enc_digest for verification */
66+
#define COUNTERSIGNATURE_VFY_CANT_DECRYPT_DIGEST 5
67+
/* No digest saved inside the countersignature */
68+
#define COUNTERSIGNATURE_VFY_DIGEST_MISSING 6
69+
/* Message digest inside countersignature doesn't match signature it countersigns */
70+
#define COUNTERSIGNATURE_VFY_DOESNT_MATCH_SIGNATURE 7
71+
/* Non verification errors - allocations etc. */
72+
#define COUNTERSIGNATURE_VFY_INTERNAL_ERROR 8
73+
/* Time is missing in the timestamp signature */
74+
#define COUNTERSIGNATURE_VFY_TIME_MISSING 9
75+
76+
typedef struct {
77+
uint8_t* data;
78+
int len;
79+
} ByteArray;
80+
81+
typedef struct { /* Various X509 attributes parsed out in raw bytes*/
82+
ByteArray country;
83+
ByteArray organization;
84+
ByteArray organizationalUnit;
85+
ByteArray nameQualifier;
86+
ByteArray state;
87+
ByteArray commonName;
88+
ByteArray serialNumber;
89+
ByteArray locality;
90+
ByteArray title;
91+
ByteArray surname;
92+
ByteArray givenName;
93+
ByteArray initials;
94+
ByteArray pseudonym;
95+
ByteArray generationQualifier;
96+
ByteArray emailAddress;
97+
} Attributes;
98+
99+
typedef struct {
100+
long version; /* Raw version of X509 */
101+
char* issuer; /* Oneline name of Issuer */
102+
char* subject; /* Oneline name of Subject */
103+
char* serial; /* Serial number in format 00:01:02:03:04... */
104+
ByteArray sha1; /* SHA1 of the DER representation of the cert */
105+
ByteArray sha256; /* SHA256 of the DER representation of the cert */
106+
char* key_alg; /* Name of the key algorithm */
107+
char* sig_alg; /* Name of the signature algorithm */
108+
char* sig_alg_oid; /* OID of the signature algorithm */
109+
time_t not_before; /* NotBefore validity */
110+
time_t not_after; /* NotAfter validity */
111+
char* key; /* PEM encoded public key */
112+
Attributes issuer_attrs; /* Parsed X509 Attributes of Issuer */
113+
Attributes subject_attrs; /* Parsed X509 Attributes of Subject */
114+
} Certificate;
115+
116+
typedef struct {
117+
Certificate** certs;
118+
size_t count;
119+
} CertificateArray;
120+
121+
typedef struct {
122+
int verify_flags; /* COUNTERISGNATURE_VFY_ flag */
123+
time_t sign_time; /* Signing time of the timestamp countersignature */
124+
char* digest_alg; /* Name of the digest algorithm used */
125+
ByteArray digest; /* Stored message digest */
126+
CertificateArray* chain; /* Certificate chain of the signer */
127+
} Countersignature;
128+
129+
typedef struct {
130+
Countersignature** counters;
131+
size_t count;
132+
} CountersignatureArray;
133+
134+
typedef struct { /* Represents SignerInfo structure */
135+
ByteArray digest; /* Message Digest of the SignerInfo */
136+
char* digest_alg; /* name of the digest algorithm */
137+
char* program_name; /* Program name stored in SpcOpusInfo structure of Authenticode */
138+
CertificateArray* chain; /* Certificate chain of the signer */
139+
} Signer;
140+
141+
typedef struct {
142+
int verify_flags; /* AUTHENTICODE_VFY_ flag */
143+
int version; /* Raw PKCS7 version */
144+
char* digest_alg; /* name of the digest algorithm */
145+
ByteArray digest; /* File Digest stored in the Signature */
146+
ByteArray file_digest; /* Actual calculated file digest */
147+
Signer* signer; /* SignerInfo information of the Authenticode */
148+
CertificateArray* certs; /* All certificates in the Signature including the ones in timestamp
149+
countersignatures */
150+
CountersignatureArray* countersigs; /* Array of timestamp countersignatures */
151+
} Authenticode;
152+
153+
typedef struct {
154+
Authenticode** signatures;
155+
size_t count;
156+
} AuthenticodeArray;
157+
158+
/**
159+
* @brief Initializes all globals OpenSSl objects we need for parsing, this is not thread-safe and
160+
* needs to be called only once, before any multithreading environment
161+
* https://github.com/openssl/openssl/issues/13524
162+
*/
163+
void initialize_authenticode_parser();
164+
165+
/**
166+
* @brief Constructs AuthenticodeArray from PE file data. Authenticode can
167+
* contains nested Authenticode signatures as its unsigned attribute,
168+
* which can also contain nested signatures. For this reason the function returns
169+
* an Array of parsed Authenticode signatures. Any field of the parsed out
170+
* structures can be NULL, depending on the input data.
171+
* Verification result is stored in verify_flags with the first verification error.
172+
*
173+
* @param pe_data PE binary data
174+
* @param pe_len
175+
* @return AuthenticodeArray*
176+
*/
177+
AuthenticodeArray* parse_authenticode(const uint8_t* pe_data, uint64_t pe_len);
178+
179+
/**
180+
* @brief Constructs AuthenticodeArray from binary data containing Authenticode
181+
* signature. Authenticode can contains nested Authenticode signatures
182+
* as its unsigned attribute, which can also contain nested signatures.
183+
* For this reason the function return an Array of parsed Authenticode signatures.
184+
* Any field of the parsed out structures can be NULL, depending on the input data.
185+
* WARNING: in case of this interface, the file and signature digest comparison is
186+
* up to the library user, as there is no pe data to calculate file digest from.
187+
* Verification result is stored in verify_flags with the first verification error
188+
*
189+
* @param data Binary data containing Authenticode signature
190+
* @param len
191+
* @return AuthenticodeArray*
192+
*/
193+
AuthenticodeArray* authenticode_new(const uint8_t* data, long len);
194+
195+
/**
196+
* @brief Deallocates AuthenticodeArray and all it's allocated members
197+
*
198+
* @param auth
199+
*/
200+
void authenticode_array_free(AuthenticodeArray* auth);
201+
202+
#ifdef __cplusplus
203+
}
204+
#endif
205+
206+
#endif

0 commit comments

Comments
 (0)