Skip to content

Commit f51b9d7

Browse files
authored
Updated authenticode parser to latest version (2024-03-02) (#2049)
Upon fixing the latest issue regarding parsing CMS, we figured out we are not properly extracting all certificates from Microsoft countersignatures. This should now properly expose them. Also fixes one memory leak for countersignature parsing.
1 parent a1883ad commit f51b9d7

File tree

5 files changed

+123
-48
lines changed

5 files changed

+123
-48
lines changed

libyara/include/authenticode-parser/authenticode.h

+2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ typedef struct {
124124
char* digest_alg; /* Name of the digest algorithm used */
125125
ByteArray digest; /* Stored message digest */
126126
CertificateArray* chain; /* Certificate chain of the signer */
127+
CertificateArray* certs; /* All certs stored inside Countersignature, this can be superset
128+
of chain in case of non PKCS9 countersignature*/
127129
} Countersignature;
128130

129131
typedef struct {

libyara/modules/pe/authenticode-parser/authenticode.c

+5-48
Original file line numberDiff line numberDiff line change
@@ -114,23 +114,6 @@ static char* parse_program_name(ASN1_TYPE* spcAttr)
114114
return result;
115115
}
116116

117-
/* Parses X509* certs into internal representation and inserts into CertificateArray
118-
* Array is assumed to have enough space to hold all certificates storted in the STACK */
119-
static void parse_certificates(const STACK_OF(X509) * certs, CertificateArray* result)
120-
{
121-
int certCount = sk_X509_num(certs);
122-
int i = 0;
123-
for (; i < certCount; ++i) {
124-
Certificate* cert = certificate_new(sk_X509_value(certs, i));
125-
if (!cert)
126-
break;
127-
128-
/* Write to the result */
129-
result->certs[i] = cert;
130-
}
131-
result->count = i;
132-
}
133-
134117
static void parse_nested_authenticode(PKCS7_SIGNER_INFO* si, AuthenticodeArray* result)
135118
{
136119
STACK_OF(X509_ATTRIBUTE)* attrs = PKCS7_get_attributes(si);
@@ -190,32 +173,6 @@ static void parse_pkcs9_countersig(PKCS7* p7, Authenticode* auth)
190173
}
191174
}
192175

193-
/* Extracts X509 certificates from MS countersignature and stores them into result */
194-
static void extract_ms_counter_certs(const uint8_t* data, int len, CertificateArray* result)
195-
{
196-
PKCS7* p7 = d2i_PKCS7(NULL, &data, len);
197-
if (!p7)
198-
return;
199-
200-
/* We expect SignedData type of PKCS7 */
201-
if (!PKCS7_type_is_signed(p7) || !p7->d.sign) {
202-
PKCS7_free(p7);
203-
return;
204-
}
205-
206-
STACK_OF(X509)* certs = p7->d.sign->cert;
207-
CertificateArray* certArr = certificate_array_new(sk_X509_num(certs));
208-
if (!certArr) {
209-
PKCS7_free(p7);
210-
return;
211-
}
212-
parse_certificates(certs, certArr);
213-
certificate_array_move(result, certArr);
214-
certificate_array_free(certArr);
215-
216-
PKCS7_free(p7);
217-
}
218-
219176
static void parse_ms_countersig(PKCS7* p7, Authenticode* auth)
220177
{
221178
PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(p7), 0);
@@ -239,14 +196,14 @@ static void parse_ms_countersig(PKCS7* p7, Authenticode* auth)
239196
int len = nested->value.sequence->length;
240197
const uint8_t* data = nested->value.sequence->data;
241198

242-
Countersignature* sig = ms_countersig_new(data, len, si->enc_digest);
243-
if (!sig)
199+
Countersignature* csig = ms_countersig_new(data, len, si->enc_digest);
200+
if (!csig)
244201
return;
245202

203+
countersignature_array_insert(auth->countersigs, csig);
246204
/* Because MS TimeStamp countersignature has it's own SET of certificates
247205
* extract it back into parent signature for consistency with PKCS9 */
248-
countersignature_array_insert(auth->countersigs, sig);
249-
extract_ms_counter_certs(data, len, auth->certs);
206+
certificate_array_append(auth->certs, csig->certs);
250207
}
251208
}
252209

@@ -344,7 +301,7 @@ AuthenticodeArray* authenticode_new(const uint8_t* data, int32_t len)
344301
auth->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR;
345302
goto end;
346303
}
347-
parse_certificates(certs, auth->certs);
304+
parse_x509_certificates(certs, auth->certs);
348305

349306
/* Get Signature content that contains the message digest and it's algorithm */
350307
SpcIndirectDataContent* dataContent = get_content(p7data->contents);

libyara/modules/pe/authenticode-parser/certificate.c

+98
Original file line numberDiff line numberDiff line change
@@ -330,10 +330,82 @@ Certificate* certificate_new(X509* x509)
330330
return result;
331331
}
332332

333+
void attributes_copy(Attributes* dst, Attributes* src)
334+
{
335+
byte_array_init(&dst->country, src->country.data, src->country.len);
336+
byte_array_init(&dst->organization, src->organization.data, src->organization.len);
337+
byte_array_init(
338+
&dst->organizationalUnit, src->organizationalUnit.data, src->organizationalUnit.len);
339+
byte_array_init(&dst->nameQualifier, src->nameQualifier.data, src->nameQualifier.len);
340+
byte_array_init(&dst->state, src->state.data, src->state.len);
341+
byte_array_init(&dst->commonName, src->commonName.data, src->commonName.len);
342+
byte_array_init(&dst->serialNumber, src->serialNumber.data, src->serialNumber.len);
343+
byte_array_init(&dst->locality, src->locality.data, src->locality.len);
344+
byte_array_init(&dst->title, src->title.data, src->title.len);
345+
byte_array_init(&dst->surname, src->surname.data, src->surname.len);
346+
byte_array_init(&dst->givenName, src->givenName.data, src->givenName.len);
347+
byte_array_init(&dst->initials, src->initials.data, src->initials.len);
348+
byte_array_init(&dst->pseudonym, src->pseudonym.data, src->pseudonym.len);
349+
byte_array_init(
350+
&dst->generationQualifier, src->generationQualifier.data, src->generationQualifier.len);
351+
byte_array_init(&dst->emailAddress, src->emailAddress.data, src->emailAddress.len);
352+
}
353+
354+
/* Parses X509* certs into internal representation and inserts into CertificateArray
355+
* Array is assumed to have enough space to hold all certificates storted in the STACK */
356+
void parse_x509_certificates(const STACK_OF(X509) * certs, CertificateArray* result)
357+
{
358+
int certCount = sk_X509_num(certs);
359+
int i = 0;
360+
for (; i < certCount; ++i) {
361+
Certificate* cert = certificate_new(sk_X509_value(certs, i));
362+
if (!cert)
363+
break;
364+
365+
/* Write to the result */
366+
result->certs[i] = cert;
367+
}
368+
result->count = i;
369+
}
370+
371+
/* Creates deep copy of a certificate */
372+
Certificate* certificate_copy(Certificate* cert)
373+
{
374+
if (!cert)
375+
return NULL;
376+
377+
Certificate* result = (Certificate*)calloc(1, sizeof(*result));
378+
if (!result)
379+
return NULL;
380+
381+
result->version = cert->version;
382+
result->issuer = cert->issuer ? strdup(cert->issuer) : NULL;
383+
result->subject = cert->subject ? strdup(cert->subject) : NULL;
384+
result->serial = cert->serial ? strdup(cert->serial) : NULL;
385+
result->not_after = cert->not_after;
386+
result->not_before = cert->not_before;
387+
result->sig_alg = cert->sig_alg ? strdup(cert->sig_alg) : NULL;
388+
result->sig_alg_oid = cert->sig_alg_oid ? strdup(cert->sig_alg_oid) : NULL;
389+
result->key_alg = cert->key_alg ? strdup(cert->key_alg) : NULL;
390+
result->key = cert->key ? strdup(cert->key) : NULL;
391+
byte_array_init(&result->sha1, cert->sha1.data, cert->sha1.len);
392+
byte_array_init(&result->sha256, cert->sha256.data, cert->sha256.len);
393+
attributes_copy(&result->issuer_attrs, &cert->issuer_attrs);
394+
attributes_copy(&result->subject_attrs, &cert->subject_attrs);
395+
396+
return result;
397+
}
398+
333399
/* Moves certificates from src to dst, returns 0 on success,
334400
* else 1. If error occurs, arguments are unchanged */
335401
int certificate_array_move(CertificateArray* dst, CertificateArray* src)
336402
{
403+
if (!dst || !src)
404+
return 1;
405+
406+
if (!src->certs || !src->count)
407+
return 0;
408+
337409
size_t newCount = dst->count + src->count;
338410

339411
Certificate** tmp = (Certificate**)realloc(dst->certs, newCount * sizeof(Certificate*));
@@ -354,6 +426,32 @@ int certificate_array_move(CertificateArray* dst, CertificateArray* src)
354426
return 0;
355427
}
356428

429+
/* Copies certificates from src and appends to dst, returns 0 on success,
430+
* else 1. If error occurs, arguments are unchanged */
431+
int certificate_array_append(CertificateArray* dst, CertificateArray* src)
432+
{
433+
if (!dst || !src)
434+
return 1;
435+
436+
if (!src->certs || !src->count)
437+
return 0;
438+
439+
size_t newCount = dst->count + src->count;
440+
441+
Certificate** tmp = (Certificate**)realloc(dst->certs, newCount * sizeof(Certificate*));
442+
if (!tmp)
443+
return 1;
444+
445+
dst->certs = tmp;
446+
447+
for (size_t i = 0; i < src->count; ++i)
448+
dst->certs[i + dst->count] = certificate_copy(src->certs[i]);
449+
450+
dst->count = newCount;
451+
452+
return 0;
453+
}
454+
357455
/* Allocates empty certificate array with reserved space for certCount certs */
358456
CertificateArray* certificate_array_new(int certCount)
359457
{

libyara/modules/pe/authenticode-parser/certificate.h

+4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@ extern "C" {
3131
#endif
3232

3333
Certificate* certificate_new(X509* x509);
34+
Certificate* certificate_copy(Certificate* cert);
3435
void certificate_free(Certificate* cert);
3536

37+
void parse_x509_certificates(const STACK_OF(X509) * certs, CertificateArray* result);
38+
3639
CertificateArray* parse_signer_chain(X509* signer_cert, STACK_OF(X509) * certs);
3740
int certificate_array_move(CertificateArray* dst, CertificateArray* src);
41+
int certificate_array_append(CertificateArray* dst, CertificateArray* src);
3842
CertificateArray* certificate_array_new(int certCount);
3943
void certificate_array_free(CertificateArray* arr);
4044

libyara/modules/pe/authenticode-parser/countersignature.c

+14
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,9 @@ CountersignatureImpl* ms_countersig_impl_new(const uint8_t* data, long size)
456456
result->funcs = &FUNC_ARRAY_NAME_FOR_IMPL(pkcs7);
457457
result->pkcs7 = p7;
458458
return result;
459+
} else if (p7) {
460+
PKCS7_free(p7);
461+
return NULL;
459462
}
460463

461464
d = data;
@@ -526,6 +529,16 @@ Countersignature* ms_countersig_new(const uint8_t* data, long size, ASN1_STRING*
526529
}
527530

528531
STACK_OF(X509)* certs = impl->funcs->get_certs(impl);
532+
533+
/* MS Counter signatures (PKCS7/CMS) can have extra certificates that are not part of a chain */
534+
result->certs = certificate_array_new(sk_X509_num(certs));
535+
if (!result->certs) {
536+
result->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR;
537+
goto end;
538+
}
539+
540+
parse_x509_certificates(certs, result->certs);
541+
529542
result->chain = parse_signer_chain(signCert, certs);
530543

531544
/* Imprint == digest */
@@ -641,6 +654,7 @@ void countersignature_free(Countersignature* sig)
641654
free(sig->digest_alg);
642655
free(sig->digest.data);
643656
certificate_array_free(sig->chain);
657+
certificate_array_free(sig->certs);
644658
free(sig);
645659
}
646660
}

0 commit comments

Comments
 (0)