If no unauthenticatedAttributes sections exist, the code will now judge
validity based on whether the code signing certificate is valid at the
time of the scan.
... | ... |
@@ -545,6 +545,12 @@ static int asn1_get_rsa_pubkey(fmap_t *map, const void **asn1data, unsigned int |
545 | 545 |
#define ASN1_GET_X509_CERT_ERROR 1 |
546 | 546 |
#define ASN1_GET_X509_UNRECOVERABLE_ERROR 2 |
547 | 547 |
|
548 |
+/* Parse the asn1data associated with an x509 certificate and add the cert |
|
549 |
+ * to the crtmgr other if it doesn't already exist in master or other. |
|
550 |
+ * ASN1_GET_X509_CERT_ERROR will be returned in the case that an invalid x509 |
|
551 |
+ * certificate is encountered but asn1data and size are suitable for continued |
|
552 |
+ * signature parsing. ASN1_GET_X509_UNRECOVERABLE_ERROR will be returned in |
|
553 |
+ * the case where asn1data and size are not suitable for continued use. */ |
|
548 | 554 |
static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, crtmgr *master, crtmgr *other) { |
549 | 555 |
struct cli_asn1 crt, tbs, obj; |
550 | 556 |
unsigned int avail, tbssize, issuersize; |
... | ... |
@@ -604,20 +610,28 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, |
604 | 604 |
break; |
605 | 605 |
} |
606 | 606 |
|
607 |
- if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, ASN1_TYPE_SEQUENCE)) /* issuer */ |
|
607 |
+ if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, ASN1_TYPE_SEQUENCE)) { /* issuer */ |
|
608 |
+ cli_dbgmsg("asn1_get_x509: expected SEQUENCE when parsing cert issuer\n"); |
|
608 | 609 |
break; |
610 |
+ } |
|
609 | 611 |
issuer = obj.content; |
610 | 612 |
issuersize = obj.size; |
611 | 613 |
|
612 |
- if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, ASN1_TYPE_SEQUENCE)) /* validity */ |
|
614 |
+ if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, ASN1_TYPE_SEQUENCE)) { /* validity */ |
|
615 |
+ cli_dbgmsg("asn1_get_x509: expected SEQUENCE when parsing cert validity\n"); |
|
613 | 616 |
break; |
617 |
+ } |
|
614 | 618 |
avail = obj.size; |
615 | 619 |
next = obj.content; |
616 | 620 |
|
617 |
- if(asn1_get_time(map, &next, &avail, &x509.not_before)) /* notBefore */ |
|
621 |
+ if(asn1_get_time(map, &next, &avail, &x509.not_before)) { /* notBefore */ |
|
622 |
+ cli_dbgmsg("asn1_get_x509: unable to extract the notBefore time\n"); |
|
618 | 623 |
break; |
619 |
- if(asn1_get_time(map, &next, &avail, &x509.not_after)) /* notAfter */ |
|
624 |
+ } |
|
625 |
+ if(asn1_get_time(map, &next, &avail, &x509.not_after)) { /* notAfter */ |
|
626 |
+ cli_dbgmsg("asn1_get_x509: unable to extract the notAfter time\n"); |
|
620 | 627 |
break; |
628 |
+ } |
|
621 | 629 |
if(x509.not_before >= x509.not_after) { |
622 | 630 |
cli_dbgmsg("asn1_get_x509: bad validity\n"); |
623 | 631 |
break; |
... | ... |
@@ -627,8 +641,10 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, |
627 | 627 |
break; |
628 | 628 |
} |
629 | 629 |
|
630 |
- if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, ASN1_TYPE_SEQUENCE)) /* subject */ |
|
630 |
+ if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, ASN1_TYPE_SEQUENCE)) { /* subject */ |
|
631 |
+ cli_dbgmsg("asn1_get_x509: expected SEQUENCE when parsing cert subject\n"); |
|
631 | 632 |
break; |
633 |
+ } |
|
632 | 634 |
if(map_raw(map, obj.content, obj.size, x509.raw_subject)) |
633 | 635 |
break; |
634 | 636 |
if(map_sha1(map, obj.content, obj.size, x509.subject)) |
... | ... |
@@ -794,8 +810,10 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, |
794 | 794 |
x509.codeSign = x509.timeSign = 1; |
795 | 795 |
} |
796 | 796 |
} |
797 |
- if(tbs.size) |
|
797 |
+ if(tbs.size) { |
|
798 |
+ cli_dbgmsg("asn1_get_x509: An error occurred when parsing x509 extensions\n"); |
|
798 | 799 |
break; |
800 |
+ } |
|
799 | 801 |
|
800 | 802 |
|
801 | 803 |
if(crtmgr_lookup(master, &x509) || crtmgr_lookup(other, &x509)) { |
... | ... |
@@ -813,13 +831,15 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, |
813 | 813 |
break; |
814 | 814 |
|
815 | 815 |
if(hashtype1 != hashtype2) { |
816 |
- cli_dbgmsg("asn1_get_x509: found conflicting rsa hash types\n"); |
|
816 |
+ cli_dbgmsg("asn1_get_x509: found conflicting RSA hash types\n"); |
|
817 | 817 |
break; |
818 | 818 |
} |
819 | 819 |
x509.hashtype = hashtype1; |
820 | 820 |
|
821 |
- if(asn1_expect_objtype(map, tbs.next, &crt.size, &obj, ASN1_TYPE_BIT_STRING)) /* signature */ |
|
821 |
+ if(asn1_expect_objtype(map, tbs.next, &crt.size, &obj, ASN1_TYPE_BIT_STRING)) { /* signature */ |
|
822 |
+ cli_dbgmsg("asn1_get_x509: Failed to parse x509 signature BIT STRING\n"); |
|
822 | 823 |
break; |
824 |
+ } |
|
823 | 825 |
if(obj.size > 513) { |
824 | 826 |
cli_dbgmsg("asn1_get_x509: signature too long\n"); |
825 | 827 |
break; |
... | ... |
@@ -839,8 +859,10 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, |
839 | 839 |
|
840 | 840 |
if((x509.hashtype == CLI_SHA1RSA && map_sha1(map, tbsdata, tbssize, x509.tbshash)) || \ |
841 | 841 |
(x509.hashtype == CLI_MD5RSA && map_md5(map, tbsdata, tbssize, x509.tbshash)) || \ |
842 |
- (x509.hashtype == CLI_SHA256RSA && map_sha256(map, tbsdata, tbssize, x509.tbshash))) |
|
842 |
+ (x509.hashtype == CLI_SHA256RSA && map_sha256(map, tbsdata, tbssize, x509.tbshash))) { |
|
843 |
+ cli_dbgmsg("asn1_get_x509: Unsupported hashtype or hash computation failed\n"); |
|
843 | 844 |
break; |
845 |
+ } |
|
844 | 846 |
|
845 | 847 |
if(crtmgr_add(other, &x509)) |
846 | 848 |
break; |
... | ... |
@@ -1092,12 +1114,21 @@ static int asn1_parse_mscat(fmap_t *map, size_t offset, unsigned int size, crtmg |
1092 | 1092 |
|
1093 | 1093 |
if(parent) { |
1094 | 1094 |
if (parent->isBlacklisted) { |
1095 |
+ // NOTE: In this case, parent is a blacklist entry |
|
1096 |
+ // in cmgr for this certificate, not a blacklist |
|
1097 |
+ // entry for this certificate's parent |
|
1095 | 1098 |
isBlacklisted = 1; |
1096 | 1099 |
cli_dbgmsg("asn1_parse_mscat: Authenticode certificate %s is revoked. Flagging sample as virus.\n", (parent->name ? parent->name : "(no name)")); |
1100 |
+ |
|
1101 |
+ // TODO In this case cmgr already has a blacklisted |
|
1102 |
+ // cert for this x509, so I don't think we need to |
|
1103 |
+ // continue on below and try to add it to cmgr |
|
1097 | 1104 |
} |
1098 | 1105 |
|
1106 |
+ // TODO Why is this done? |
|
1099 | 1107 |
x509->codeSign &= parent->codeSign; |
1100 | 1108 |
x509->timeSign &= parent->timeSign; |
1109 |
+ |
|
1101 | 1110 |
if(crtmgr_add(cmgr, x509)) { |
1102 | 1111 |
cli_dbgmsg("asn1_parse_mscat: adding x509 cert to crtmgr failed\n"); |
1103 | 1112 |
break; |
... | ... |
@@ -1431,9 +1462,29 @@ static int asn1_parse_mscat(fmap_t *map, size_t offset, unsigned int size, crtmg |
1431 | 1431 |
message = asn1.content; |
1432 | 1432 |
message_size = asn1.size; |
1433 | 1433 |
|
1434 |
+ cli_dbgmsg("asn1_parse_mscat: authenticatedAttributes successfully parsed and verified\n"); |
|
1435 |
+ |
|
1436 |
+ /* We need to verify the time validity of the certificate. If a |
|
1437 |
+ * signature has a time-stamping countersignature, then we just need to |
|
1438 |
+ * verify that countersignature. Otherwise, we should determine |
|
1439 |
+ * whether the signing certificate is still valid (time-based, since at |
|
1440 |
+ * this point in the code no matching blacklist rules fired). */ |
|
1441 |
+ |
|
1434 | 1442 |
if(!size) { |
1435 |
- cli_dbgmsg("asn1_parse_mscat: countersignature is missing\n"); |
|
1436 |
- break; |
|
1443 |
+ time_t now; |
|
1444 |
+ |
|
1445 |
+ cli_dbgmsg("asn1_parse_mscat: unauthenticatedAttributes section is missing\n"); |
|
1446 |
+ |
|
1447 |
+ // No countersignature, so judge validity based on time |
|
1448 |
+ now = time(NULL); |
|
1449 |
+ |
|
1450 |
+ if(now < x509->not_before || now > x509->not_after) { |
|
1451 |
+ cli_dbgmsg("asn1_parse_mscat: no countersignature and signing certificate has expired\n"); |
|
1452 |
+ break; |
|
1453 |
+ } |
|
1454 |
+ |
|
1455 |
+ cli_dbgmsg("asn1_parse_mscat: no countersignature but the signing certificate is still valid\n"); |
|
1456 |
+ return 0; |
|
1437 | 1457 |
} |
1438 | 1458 |
|
1439 | 1459 |
if(size && asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa1)) { /* unauthenticatedAttributes */ |
... | ... |
@@ -1758,7 +1809,7 @@ static int asn1_parse_mscat(fmap_t *map, size_t offset, unsigned int size, crtmg |
1758 | 1758 |
cli_dbgmsg("asn1_parse_mscat: nested signatures detected but parsing them is not currently supported\n"); |
1759 | 1759 |
} |
1760 | 1760 |
|
1761 |
- cli_dbgmsg("asn1_parse_mscat: catalog successfully parsed\n"); |
|
1761 |
+ cli_dbgmsg("asn1_parse_mscat: unauthenticatedAttributes successfully parsed\n"); |
|
1762 | 1762 |
|
1763 | 1763 |
if (isBlacklisted) { |
1764 | 1764 |
return 1; |
... | ... |
@@ -221,54 +221,74 @@ static int crtmgr_rsa_verify(cli_crt *x509, mp_int *sig, cli_crt_hashtype hashty |
221 | 221 |
} |
222 | 222 |
|
223 | 223 |
do { |
224 |
- if(MAX(keylen, siglen) - MIN(keylen, siglen) > 1) |
|
224 |
+ if(MAX(keylen, siglen) - MIN(keylen, siglen) > 1) { |
|
225 |
+ cli_dbgmsg("crtmgr_rsa_verify: keylen and siglen differ by more than one\n"); |
|
225 | 226 |
break; |
227 |
+ } |
|
226 | 228 |
if((ret = mp_exptmod(sig, &x509->e, &x509->n, &x))) { |
227 | 229 |
cli_warnmsg("crtmgr_rsa_verify: verification failed: mp_exptmod failed with %d\n", ret); |
228 | 230 |
break; |
229 | 231 |
} |
230 |
- if(mp_unsigned_bin_size(&x) != keylen - 1) |
|
232 |
+ if(mp_unsigned_bin_size(&x) != keylen - 1){ |
|
233 |
+ cli_dbgmsg("crtmgr_rsa_verify: keylen-1 doesn't match expected size of exptmod result\n"); |
|
231 | 234 |
break; |
232 |
- if(mp_unsigned_bin_size(&x) > sizeof(d)) |
|
235 |
+ } |
|
236 |
+ if(mp_unsigned_bin_size(&x) > sizeof(d)) { |
|
237 |
+ cli_dbgmsg("crtmgr_rsa_verify: exptmod result would overrun working buffer\n"); |
|
233 | 238 |
break; |
239 |
+ } |
|
234 | 240 |
if((ret = mp_to_unsigned_bin(&x, d))) { |
235 | 241 |
cli_warnmsg("crtmgr_rsa_verify: mp_unsigned_bin_size failed with %d\n", ret); |
236 | 242 |
break; |
237 | 243 |
} |
238 |
- if(*d != 1) /* block type 1 */ |
|
244 |
+ if(*d != 1) {/* block type 1 */ |
|
245 |
+ cli_dbgmsg("crtmgr_rsa_verify: expected block type 1 at d[0]\n"); |
|
239 | 246 |
break; |
247 |
+ } |
|
240 | 248 |
|
241 | 249 |
keylen -= 1; /* 0xff padding */ |
242 | 250 |
for(j=1; j<keylen-2; j++) |
243 | 251 |
if(d[j] != 0xff) |
244 | 252 |
break; |
245 |
- if(j == keylen - 2) |
|
253 |
+ if(j == keylen - 2) { |
|
254 |
+ cli_dbgmsg("crtmgr_rsa_verify: only encountered 0xFF padding parsing cert\n"); |
|
246 | 255 |
break; |
247 |
- if(d[j] != 0) /* 0x00 separator */ |
|
256 |
+ } |
|
257 |
+ if(d[j] != 0) { /* 0x00 separator */ |
|
258 |
+ cli_dbgmsg("crtmgr_rsa_verify: expected 0x00 separator\n"); |
|
248 | 259 |
break; |
260 |
+ } |
|
249 | 261 |
|
250 | 262 |
j++; |
251 | 263 |
keylen -= j; /* asn1 size */ |
252 | 264 |
|
253 |
- if(keylen < hashlen) |
|
265 |
+ if(keylen < hashlen) { |
|
266 |
+ cli_dbgmsg("crtmgr_rsa_verify: encountered keylen less than hashlen\n"); |
|
254 | 267 |
break; |
268 |
+ } |
|
255 | 269 |
if(keylen > hashlen) { |
256 | 270 |
/* hash is asn1 der encoded */ |
257 | 271 |
/* SEQ { SEQ { OID, NULL }, OCTET STRING */ |
258 |
- if(keylen < 2 || d[j] != 0x30 || d[j+1] + 2 != keylen) |
|
272 |
+ if(keylen < 2 || d[j] != 0x30 || d[j+1] + 2 != keylen) { |
|
273 |
+ cli_dbgmsg("crtmgr_rsa_verify: unexpected hash to be ASN1 DER encoded\n"); |
|
259 | 274 |
break; |
275 |
+ } |
|
260 | 276 |
keylen -= 2; |
261 | 277 |
j+=2; |
262 | 278 |
|
263 |
- if(keylen <2 || d[j] != 0x30) |
|
279 |
+ if(keylen <2 || d[j] != 0x30) { |
|
280 |
+ cli_dbgmsg("crtmgr_rsa_verify: expected SEQUENCE at beginning of cert AlgorithmIdentifier\n"); |
|
264 | 281 |
break; |
282 |
+ } |
|
265 | 283 |
|
266 | 284 |
objlen = d[j+1]; |
267 | 285 |
|
268 | 286 |
keylen -= 2; |
269 | 287 |
j+=2; |
270 |
- if(keylen < objlen) |
|
288 |
+ if(keylen < objlen) { |
|
289 |
+ cli_dbgmsg("crtmgr_rsa_verify: key length mismatch in ASN1 DER hash encoding\n"); |
|
271 | 290 |
break; |
291 |
+ } |
|
272 | 292 |
if(objlen == 9) { |
273 | 293 |
// Check for OID type indicating a length of 5, OID_sha1, and the NULL type/value |
274 | 294 |
if(hashtype != CLI_SHA1RSA || memcmp(&d[j], "\x06\x05" OID_sha1 "\x05\x00", 9)) { |
... | ... |
@@ -307,15 +327,25 @@ static int crtmgr_rsa_verify(cli_crt *x509, mp_int *sig, cli_crt_hashtype hashty |
307 | 307 |
|
308 | 308 |
keylen -= objlen; |
309 | 309 |
j += objlen; |
310 |
- if(keylen < 2 || d[j] != 0x04 || d[j+1] != hashlen) |
|
310 |
+ if(keylen < 2 || d[j] != 0x04 || d[j+1] != hashlen) { |
|
311 |
+ cli_dbgmsg("crtmgr_rsa_verify: hash length mismatch in ASN1 DER hash encoding\n"); |
|
311 | 312 |
break; |
313 |
+ } |
|
312 | 314 |
keylen -= 2; |
313 | 315 |
j+=2; |
314 |
- if(keylen != hashlen) |
|
316 |
+ if(keylen != hashlen) { |
|
317 |
+ cli_dbgmsg("crtmgr_rsa_verify: extra data in the ASN1 DER hash encoding\n"); |
|
315 | 318 |
break; |
319 |
+ } |
|
316 | 320 |
} |
317 |
- if(memcmp(&d[j], refhash, hashlen)) |
|
321 |
+ if(memcmp(&d[j], refhash, hashlen)) { |
|
322 |
+ // This is a common error case if we are using crtmgr_rsa_verify to |
|
323 |
+ // determine whether we've found the right issuer certificate based |
|
324 |
+ // (as is done by crtmgr_verify_crt). If we are pretty sure that |
|
325 |
+ // x509 is the correct cert to use for verification, then this |
|
326 |
+ // case is more of a concern. |
|
318 | 327 |
break; |
328 |
+ } |
|
319 | 329 |
|
320 | 330 |
mp_clear(&x); |
321 | 331 |
return 0; |
... | ... |
@@ -326,7 +356,10 @@ static int crtmgr_rsa_verify(cli_crt *x509, mp_int *sig, cli_crt_hashtype hashty |
326 | 326 |
return 1; |
327 | 327 |
} |
328 | 328 |
|
329 |
- |
|
329 |
+/* For a given cli_crt, returns an existing blacklisted cert in crtmgr if one |
|
330 |
+ * is present. Otherwise returns a pointer to the signer x509 certificate if |
|
331 |
+ * one is found in the crtmgr and it's signature can be validated (NULL is |
|
332 |
+ * returned otherwise.) */ |
|
330 | 333 |
cli_crt *crtmgr_verify_crt(crtmgr *m, cli_crt *x509) { |
331 | 334 |
cli_crt *i = m->crts, *best = NULL; |
332 | 335 |
int score = 0; |
... | ... |
@@ -334,6 +367,13 @@ cli_crt *crtmgr_verify_crt(crtmgr *m, cli_crt *x509) { |
334 | 334 |
for (i = m->crts; i; i = i->next) { |
335 | 335 |
if (!memcmp(i->subject, x509->subject, sizeof(i->subject)) && |
336 | 336 |
!memcmp(i->serial, x509->serial, sizeof(i->serial))) { |
337 |
+ |
|
338 |
+ // TODO Shouldn't we compare public keys in this case as well? I'd |
|
339 |
+ // think that it's the public key that really makes a certificate |
|
340 |
+ // unique (not subject/serial). Otherwise, you could have malware |
|
341 |
+ // use the subject/serial from a popular company's cert and if we |
|
342 |
+ // blacklisted that it would cause FPs on the popular software. |
|
343 |
+ |
|
337 | 344 |
if (i->isBlacklisted) |
338 | 345 |
return i; |
339 | 346 |
} |
... | ... |
@@ -366,12 +406,12 @@ cli_crt *crtmgr_verify_pkcs7(crtmgr *m, const uint8_t *issuer, const uint8_t *se |
366 | 366 |
return NULL; |
367 | 367 |
} |
368 | 368 |
if((ret = mp_init(&sig))) { |
369 |
- cli_errmsg("crtmgr_verify_pkcs7: mp_init failed with %d\n", ret); |
|
369 |
+ cli_dbgmsg("crtmgr_verify_pkcs7: mp_init failed with %d\n", ret); |
|
370 | 370 |
return NULL; |
371 | 371 |
} |
372 | 372 |
|
373 | 373 |
if((ret=mp_read_unsigned_bin(&sig, signature, signature_len))) { |
374 |
- cli_warnmsg("crtmgr_verify_pkcs7: mp_read_unsigned_bin failed with %d\n", ret); |
|
374 |
+ cli_dbgmsg("crtmgr_verify_pkcs7: mp_read_unsigned_bin failed with %d\n", ret); |
|
375 | 375 |
return NULL; |
376 | 376 |
} |
377 | 377 |
|
... | ... |
@@ -381,9 +421,11 @@ cli_crt *crtmgr_verify_pkcs7(crtmgr *m, const uint8_t *issuer, const uint8_t *se |
381 | 381 |
if(vrfytype == VRFY_TIME && !i->timeSign) |
382 | 382 |
continue; |
383 | 383 |
if(!memcmp(i->issuer, issuer, sizeof(i->issuer)) && |
384 |
- !memcmp(i->serial, serial, sizeof(i->serial)) && |
|
385 |
- !crtmgr_rsa_verify(i, &sig, hashtype, refhash)) { |
|
386 |
- break; |
|
384 |
+ !memcmp(i->serial, serial, sizeof(i->serial))) { |
|
385 |
+ if(!crtmgr_rsa_verify(i, &sig, hashtype, refhash)) { |
|
386 |
+ break; |
|
387 |
+ } |
|
388 |
+ cli_dbgmsg("crtmgr_verify_pkcs7: found cert with matching issuer and serial but RSA verification failed\n"); |
|
387 | 389 |
} |
388 | 390 |
} |
389 | 391 |
mp_clear(&sig); |