Browse code

Add support for signatures without unauthAttr section and add more dbg msgs

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.

Andrew authored on 2018/09/01 03:02:40
Showing 2 changed files
... ...
@@ -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);