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

Append MS countersignature certificates to the Authenticode signature certs #21

Merged
merged 5 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion examples/authenticode_dumper.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ int main(int argc, char **argv)
}

printf("Signature count: %lu\n", auth->count);
printf("Signatures: %lu\n", auth->count);

for (size_t i = 0; i < auth->count; ++i)
print_authenticode(auth->signatures[i]);
Expand Down
2 changes: 2 additions & 0 deletions include/authenticode-parser/authenticode.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ typedef struct {
char* digest_alg; /* Name of the digest algorithm used */
ByteArray digest; /* Stored message digest */
CertificateArray* chain; /* Certificate chain of the signer */
CertificateArray* certs; /* All certs stored inside Countersignature, this can be superset
of chain in case of non PKCS9 countersignature*/
} Countersignature;

typedef struct {
Expand Down
47 changes: 5 additions & 42 deletions src/authenticode.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,23 +114,6 @@ static char* parse_program_name(ASN1_TYPE* spcAttr)
return result;
}

/* Parses X509* certs into internal representation and inserts into CertificateArray
* Array is assumed to have enough space to hold all certificates storted in the STACK */
static void parse_certificates(const STACK_OF(X509) * certs, CertificateArray* result)
{
int certCount = sk_X509_num(certs);
int i = 0;
for (; i < certCount; ++i) {
Certificate* cert = certificate_new(sk_X509_value(certs, i));
if (!cert)
break;

/* Write to the result */
result->certs[i] = cert;
}
result->count = i;
}

static void parse_nested_authenticode(PKCS7_SIGNER_INFO* si, AuthenticodeArray* result)
{
STACK_OF(X509_ATTRIBUTE)* attrs = PKCS7_get_attributes(si);
Expand Down Expand Up @@ -190,26 +173,6 @@ static void parse_pkcs9_countersig(PKCS7* p7, Authenticode* auth)
}
}

/* Extracts X509 certificates from MS countersignature and stores them into result */
static void extract_ms_counter_certs(const uint8_t* data, int len, CertificateArray* result)
{
PKCS7* p7 = d2i_PKCS7(NULL, &data, len);
if (!p7)
return;

STACK_OF(X509)* certs = p7->d.sign->cert;
CertificateArray* certArr = certificate_array_new(sk_X509_num(certs));
if (!certArr) {
PKCS7_free(p7);
return;
}
parse_certificates(certs, certArr);
certificate_array_move(result, certArr);
certificate_array_free(certArr);

PKCS7_free(p7);
}

static void parse_ms_countersig(PKCS7* p7, Authenticode* auth)
{
PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(p7), 0);
Expand All @@ -233,14 +196,14 @@ static void parse_ms_countersig(PKCS7* p7, Authenticode* auth)
int len = nested->value.sequence->length;
const uint8_t* data = nested->value.sequence->data;

Countersignature* sig = ms_countersig_new(data, len, si->enc_digest);
if (!sig)
Countersignature* csig = ms_countersig_new(data, len, si->enc_digest);
if (!csig)
return;

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

Expand Down Expand Up @@ -338,7 +301,7 @@ AuthenticodeArray* authenticode_new(const uint8_t* data, int32_t len)
auth->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR;
goto end;
}
parse_certificates(certs, auth->certs);
parse_x509_certificates(certs, auth->certs);

/* Get Signature content that contains the message digest and it's algorithm */
SpcIndirectDataContent* dataContent = get_content(p7data->contents);
Expand Down
98 changes: 98 additions & 0 deletions src/certificate.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,82 @@ Certificate* certificate_new(X509* x509)
return result;
}

void attributes_copy(Attributes* dst, Attributes* src)
{
byte_array_init(&dst->country, src->country.data, src->country.len);
byte_array_init(&dst->organization, src->organization.data, src->organization.len);
byte_array_init(
&dst->organizationalUnit, src->organizationalUnit.data, src->organizationalUnit.len);
byte_array_init(&dst->nameQualifier, src->nameQualifier.data, src->nameQualifier.len);
byte_array_init(&dst->state, src->state.data, src->state.len);
byte_array_init(&dst->commonName, src->commonName.data, src->commonName.len);
byte_array_init(&dst->serialNumber, src->serialNumber.data, src->serialNumber.len);
byte_array_init(&dst->locality, src->locality.data, src->locality.len);
byte_array_init(&dst->title, src->title.data, src->title.len);
byte_array_init(&dst->surname, src->surname.data, src->surname.len);
byte_array_init(&dst->givenName, src->givenName.data, src->givenName.len);
byte_array_init(&dst->initials, src->initials.data, src->initials.len);
byte_array_init(&dst->pseudonym, src->pseudonym.data, src->pseudonym.len);
byte_array_init(
&dst->generationQualifier, src->generationQualifier.data, src->generationQualifier.len);
byte_array_init(&dst->emailAddress, src->emailAddress.data, src->emailAddress.len);
}

/* Parses X509* certs into internal representation and inserts into CertificateArray
* Array is assumed to have enough space to hold all certificates storted in the STACK */
void parse_x509_certificates(const STACK_OF(X509) * certs, CertificateArray* result)
{
int certCount = sk_X509_num(certs);
int i = 0;
for (; i < certCount; ++i) {
Certificate* cert = certificate_new(sk_X509_value(certs, i));
if (!cert)
break;

/* Write to the result */
result->certs[i] = cert;
}
result->count = i;
}

/* Creates deep copy of a certificate */
Certificate* certificate_copy(Certificate* cert)
{
if (!cert)
return NULL;

Certificate* result = (Certificate*)calloc(1, sizeof(*result));
if (!result)
return NULL;

result->version = cert->version;
result->issuer = strdup(cert->issuer);
result->subject = strdup(cert->subject);
result->serial = strdup(cert->serial);
result->not_after = cert->not_after;
result->not_before = cert->not_before;
result->sig_alg = strdup(cert->sig_alg);
result->sig_alg_oid = strdup(cert->sig_alg_oid);
result->key_alg = strdup(cert->key_alg);
result->key = strdup(cert->key);
byte_array_init(&result->sha1, cert->sha1.data, cert->sha1.len);
byte_array_init(&result->sha256, cert->sha256.data, cert->sha256.len);
attributes_copy(&result->issuer_attrs, &cert->issuer_attrs);
attributes_copy(&result->subject_attrs, &cert->subject_attrs);

return result;
}

/* Moves certificates from src to dst, returns 0 on success,
* else 1. If error occurs, arguments are unchanged */
int certificate_array_move(CertificateArray* dst, CertificateArray* src)
{
if (!dst || !src)
return 1;

if (!src->certs || !src->count)
return 0;

size_t newCount = dst->count + src->count;

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

/* Copies certificates from src and appends to dst, returns 0 on success,
* else 1. If error occurs, arguments are unchanged */
int certificate_array_append(CertificateArray* dst, CertificateArray* src)
{
if (!dst || !src)
return 1;

if (!src->certs || !src->count)
return 0;

size_t newCount = dst->count + src->count;

Certificate** tmp = (Certificate**)realloc(dst->certs, newCount * sizeof(Certificate*));
if (!tmp)
return 1;

dst->certs = tmp;

for (size_t i = 0; i < src->count; ++i)
dst->certs[i + dst->count] = certificate_copy(src->certs[i]);

dst->count = newCount;

return 0;
}

/* Allocates empty certificate array with reserved space for certCount certs */
CertificateArray* certificate_array_new(int certCount)
{
Expand Down
4 changes: 4 additions & 0 deletions src/certificate.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ extern "C" {
#endif

Certificate* certificate_new(X509* x509);
Certificate* certificate_copy(Certificate* cert);
void certificate_free(Certificate* cert);

void parse_x509_certificates(const STACK_OF(X509) * certs, CertificateArray* result);

CertificateArray* parse_signer_chain(X509* signer_cert, STACK_OF(X509) * certs);
int certificate_array_move(CertificateArray* dst, CertificateArray* src);
int certificate_array_append(CertificateArray* dst, CertificateArray* src);
CertificateArray* certificate_array_new(int certCount);
void certificate_array_free(CertificateArray* arr);

Expand Down
14 changes: 14 additions & 0 deletions src/countersignature.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,9 @@ CountersignatureImpl* ms_countersig_impl_new(const uint8_t* data, long size)
result->funcs = &FUNC_ARRAY_NAME_FOR_IMPL(pkcs7);
result->pkcs7 = p7;
return result;
} else if (p7) {
PKCS7_free(p7);
return NULL;
}

d = data;
Expand Down Expand Up @@ -527,6 +530,16 @@ Countersignature* ms_countersig_new(const uint8_t* data, long size, ASN1_STRING*
}

STACK_OF(X509)* certs = impl->funcs->get_certs(impl);

/* MS Counter signatures (PKCS7/CMS) can have extra certificates that are not part of a chain */
result->certs = certificate_array_new(sk_X509_num(certs));
if (!result->certs) {
result->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR;
goto end;
}

parse_x509_certificates(certs, result->certs);

result->chain = parse_signer_chain(signCert, certs);

/* Imprint == digest */
Expand Down Expand Up @@ -642,6 +655,7 @@ void countersignature_free(Countersignature* sig)
free(sig->digest_alg);
free(sig->digest.data);
certificate_array_free(sig->chain);
certificate_array_free(sig->certs);
free(sig);
}
}
Expand Down
35 changes: 31 additions & 4 deletions tests/integration/test_microsoft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ TEST_F(MicrosoftSignatureTest, SignatureContent)
// Test all certificates of first signature //
ASSERT_TRUE(first_sig->certs);
ASSERT_TRUE(first_sig->certs->certs);
ASSERT_EQ(first_sig->certs->count, 2);
ASSERT_EQ(first_sig->certs->count, 4);

//**************************//
// Check the 1. certificate //
Expand Down Expand Up @@ -149,6 +149,26 @@ TEST_F(MicrosoftSignatureTest, SignatureContent)
0x21, 0xc5, 0x7b, 0xc6, 0x7f, 0x73};
EXPECT_TRUE(std::memcmp(second_cert_sha1, cert->sha1.data, 20) == 0);

//**************************//
// Check the 3. certificate //
cert = first_sig->certs->certs[1];
ASSERT_TRUE(cert->sha1.data);
ASSERT_EQ(cert->sha1.len, 20);
unsigned char third_cert_sha1[20] = {0x9a, 0xb3, 0xfa, 0x0a, 0x1a, 0xdb, 0xcf,
0x46, 0xb1, 0xee, 0xce, 0x7b, 0x9f, 0x93,
0xe8, 0xa7, 0x75, 0x42, 0xf2, 0x0c};
EXPECT_TRUE(std::memcmp(second_cert_sha1, cert->sha1.data, 20) == 0);

//**************************//
// Check the 4. certificate //
cert = first_sig->certs->certs[1];
ASSERT_TRUE(cert->sha1.data);
ASSERT_EQ(cert->sha1.len, 20);
unsigned char fourth_cert_sha1[20] = {0x2a, 0xa7, 0x52, 0xfe, 0x64, 0xc4, 0x9a,
0xbe, 0x82, 0x91, 0x3c, 0x46, 0x35, 0x29,
0xcf, 0x10, 0xff, 0x2f, 0x04, 0xee};
EXPECT_TRUE(std::memcmp(second_cert_sha1, cert->sha1.data, 20) == 0);

//**************************//
// Check the Counter signature //
const Countersignature *countersig = first_sig->countersigs->counters[0];
Expand Down Expand Up @@ -226,15 +246,22 @@ TEST_F(MicrosoftSignatureTest, SignatureContent)

EXPECT_EQ(cert->version, 2);
EXPECT_STREQ(
cert->subject, "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Time-Stamp PCA 2010");
cert->subject,
"/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Time-Stamp PCA 2010");
EXPECT_STREQ(
cert->issuer,
"/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Root Certificate Authority 2010");
"/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Root Certificate "
"Authority 2010");
EXPECT_EQ(cert->not_after, 1751406415);
EXPECT_EQ(cert->not_before, 1278020215);
EXPECT_STREQ(
cert->key,
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQAB");
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/"
"X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/"
"FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FUsc+"
"TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wGPmd/"
"9WbAA5ZEfu/QS/"
"1u5ZrKsajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQAB");
EXPECT_STREQ(cert->serial, "61:09:81:2a:00:00:00:00:00:02");
EXPECT_STREQ(cert->sig_alg, "sha256WithRSAEncryption");
EXPECT_STREQ(cert->key_alg, "rsaEncryption");
Expand Down