]> git.cameronkatri.com Git - trustcache.git/commitdiff
Add support for new version 2 trustcaches main
authorCameron Katri <me@cameronkatri.com>
Thu, 16 Jun 2022 14:17:00 +0000 (10:17 -0400)
committerCameron Katri <me@cameronkatri.com>
Thu, 16 Jun 2022 14:21:50 +0000 (10:21 -0400)
Thanks to Linus Henze for reversing the new format
https://gist.github.com/LinusHenze/4cd5d7ef057a144cda7234e2c247c056

.gitignore
README.txt
append.c
cache_from_tree.c
create.c
info.c
remove.c
trustcache.1
trustcache.c
trustcache.h

index 2ee8367d53752f7be5a152cd55e6e4923e6e9845..9e8345a3981c9b58814dd201e455e564b15e8398 100644 (file)
@@ -3,3 +3,5 @@ a.out
 *.bin
 trustcache
 .vscode
+*.tc
+linux-sysroot
index 12da2b39b47443b5a78f906b0f22239de216a1b7..3f81ef88afdb221fc964922ecfbdf65a2a846be5 100644 (file)
@@ -28,15 +28,16 @@ DESCRIPTION
              Create a trustcache at outfile.  Each Mach-O found in the
              specified inputs will be scanned for a code signature and hashed.
              Any malformed or unsigned Mach-O will be ignored.  Each slice of
-             a FAT binary will have its hash included.  Versions 0 and 1 are
-             supported, if not specified, 1 is assumed.  If uuid is specified,
-             that will be used instead of a randomly generated one.
+             a FAT binary will have its hash included.  Versions 0, 1, and 2
+             are supported, if not specified, 1 is assumed.  If uuid is
+             specified, that will be used instead of a randomly generated one.
 
      info [-c] [-h] [-e entrynum] file
              Print information about file.  The output for each hash will be
-             in the format:
+             in one of these formats:
 
                    <cdhash> <flags> [<hash_type>]
+                   <cdhash> <flags> [<hash_type>] [<category>]
 
              If the -c is given, only the hashes will be printed.  If -h is
              given, only the header will be printed.  If entrynum is
@@ -57,4 +58,4 @@ HISTORY
      The trustcache utility was written by Cameron Katri
      <me@cameronkatri.com>.
 
-FreeBSD 14.0-CURRENT             May 19, 2022             FreeBSD 14.0-CURRENT
+FreeBSD 14.0-CURRENT             June 16, 2022            FreeBSD 14.0-CURRENT
index 5bc468d9146e4155f9d78a105650384ca237d3c8..fc0cb85e41873de94fd6e3924239868ff624990c 100644 (file)
--- a/append.c
+++ b/append.c
@@ -54,9 +54,10 @@ tcappend(int argc, char **argv)
        uuid_t uuid;
        const char *errstr = NULL;
        uint8_t flags = 0;
+       uint16_t category = 0;
 
        int ch;
-       while ((ch = getopt(argc, argv, "u:f:")) != -1) {
+       while ((ch = getopt(argc, argv, "u:f:c:")) != -1) {
                switch (ch) {
                        case 'u':
                                if (strlen(optarg) == 1 && *optarg == '0') {
@@ -75,6 +76,13 @@ tcappend(int argc, char **argv)
                                        exit(1);
                                }
                                break;
+                       case 'c':
+                               category = strtonum(optarg, 0, UINT16_MAX, &errstr);
+                               if (errstr != NULL) {
+                                       fprintf(stderr, "category number is %s: %s\n", errstr, optarg);
+                                       exit(1);
+                               }
+                               break;
                }
        }
 
@@ -98,10 +106,14 @@ tcappend(int argc, char **argv)
                                append.hashes = calloc(1, sizeof(trust_cache_hash0));
                                for (size_t j = 0; j < CS_CDHASH_LEN; j++)
                                        sscanf(argv[i] + 2 * j, "%02hhx", &append.hashes[0][j]);
-                       } else {
+                       } else if (append.version == 1) {
                                append.entries = calloc(1, sizeof(struct trust_cache_entry1));
                                for (size_t j = 0; j < CS_CDHASH_LEN; j++)
                                        sscanf(argv[i] + 2 * j, "%02hhx", &append.entries[0].cdhash[j]);
+                       } else if (append.version == 2) {
+                               append.entries2 = calloc(1, sizeof(struct trust_cache_entry2));
+                               for (size_t j = 0; j < CS_CDHASH_LEN; j++)
+                                       sscanf(argv[i] + 2 * j, "%02hhx", &append.entries2[0].cdhash[j]);
                        }
                } else {
                        append = cache_from_tree(argv[i], cache.version);
@@ -122,15 +134,27 @@ tcappend(int argc, char **argv)
                                cache.entries[cache.num_entries + j].flags = flags != 0 ? flags : append.entries[j].flags;
                                memcpy(cache.entries[cache.num_entries + j].cdhash, append.entries[j].cdhash, CS_CDHASH_LEN);
                        }
+               } else if (append.version == 2) {
+                       if ((cache.entries2 = realloc(cache.entries, sizeof(struct trust_cache_entry2) *
+                                                       (cache.num_entries + append.num_entries))) == NULL)
+                               exit(1);
+                       for (uint32_t j = 0; j < append.num_entries; j++) {
+                               cache.entries2[cache.num_entries + j].hash_type = append.entries[j].hash_type;
+                               cache.entries2[cache.num_entries + j].flags = flags != 0 ? flags : append.entries[j].flags;
+                               cache.entries2[cache.num_entries + j].category = category != 0 ? category : append.entries2[j].category;
+                               memcpy(cache.entries2[cache.num_entries + j].cdhash, append.entries2[j].cdhash, CS_CDHASH_LEN);
+                       }
                }
                free(append.hashes);
                cache.num_entries += append.num_entries;
        }
 
-       if (cache.version == 1)
-               qsort(cache.entries, cache.num_entries, sizeof(*cache.entries), ent_cmp);
-       else if (cache.version == 0)
+       if (cache.version == 0)
                qsort(cache.hashes, cache.num_entries, sizeof(*cache.hashes), hash_cmp);
+       else if (cache.version == 1)
+               qsort(cache.entries, cache.num_entries, sizeof(*cache.entries), ent_cmp);
+       else if (cache.version == 2)
+               qsort(cache.entries, cache.num_entries, sizeof(*cache.entries2), ent_cmp);
 
        switch (keepuuid) {
                case 0:
index 610653c7743c4e0fe4e992ec0e03e2399709c6d0..723fbac3b85f83e4d09d1294f9b3d00ed52cb017 100644 (file)
@@ -60,6 +60,12 @@ tccallback(const char *path, const struct stat *sb, __attribute__((unused)) int
                        cache.entries[cache.num_entries].hash_type = c.h[i].hash_type;
                        cache.entries[cache.num_entries].flags = 0;
                        memcpy(cache.entries[cache.num_entries].cdhash, c.h[i].cdhash, CS_CDHASH_LEN);
+               } else if (cache.version == 2) {
+                       if ((cache.entries2 = realloc(cache.entries, sizeof(struct trust_cache_entry2) * (cache.num_entries + 1))) == NULL)
+                               exit(1);
+                       cache.entries2[cache.num_entries].hash_type = c.h[i].hash_type;
+                       cache.entries2[cache.num_entries].category = 0;
+                       memcpy(cache.entries2[cache.num_entries].cdhash, c.h[i].cdhash, CS_CDHASH_LEN);
                }
                cache.num_entries++;
        }
index c88abc48c8feb8cf220cd939473e89678adea867..7c73a05b3233c16490b10a8cb676fe7ac58a5602 100644 (file)
--- a/create.c
+++ b/create.c
@@ -56,7 +56,7 @@ tccreate(int argc, char **argv)
                                        fprintf(stderr, "Failed to parse %s as a UUID\n", optarg);
                                break;
                        case 'v':
-                               if (strlen(optarg) != 1 || (optarg[0] != '0' && optarg[0] != '1')) {
+                               if (strlen(optarg) != 1 || (optarg[0] != '0' && optarg[0] != '1' && optarg[0] != '2')) {
                                        fprintf(stderr, "Unsupported trustcache version %s\n", optarg);
                                        return 1;
                                }
@@ -64,6 +64,8 @@ tccreate(int argc, char **argv)
                                        cache.version = 0;
                                else if (optarg[0] == '1')
                                        cache.version = 1;
+                               else if (optarg[0] == '2')
+                                       cache.version = 2;
                                break;
                }
        }
@@ -92,15 +94,27 @@ tccreate(int argc, char **argv)
                                cache.entries[cache.num_entries + j].flags = append.entries[j].flags;
                                memcpy(cache.entries[cache.num_entries + j].cdhash, append.entries[j].cdhash, CS_CDHASH_LEN);
                        }
+               } else if (append.version == 2) {
+                       if ((cache.entries2 = realloc(cache.entries2, sizeof(struct trust_cache_entry2) *
+                                                       (cache.num_entries + append.num_entries))) == NULL)
+                               exit(1);
+                       for (uint32_t j = 0; j < append.num_entries; j++) {
+                               cache.entries2[cache.num_entries + j].hash_type = append.entries2[j].hash_type;
+                               cache.entries2[cache.num_entries + j].flags = append.entries2[j].flags;
+                               cache.entries2[cache.num_entries + j].category = append.entries2[j].category;
+                               memcpy(cache.entries2[cache.num_entries + j].cdhash, append.entries2[j].cdhash, CS_CDHASH_LEN);
+                       }
                }
                free(append.hashes);
                cache.num_entries += append.num_entries;
        }
 
-       if (cache.version == 1)
-               qsort(cache.entries, cache.num_entries, sizeof(*cache.entries), ent_cmp);
-       else if (cache.version == 0)
+       if (cache.version == 0)
                qsort(cache.hashes, cache.num_entries, sizeof(*cache.hashes), hash_cmp);
+       else if (cache.version == 1)
+               qsort(cache.entries, cache.num_entries, sizeof(*cache.entries), ent_cmp);
+       else if (cache.version == 2)
+               qsort(cache.entries, cache.num_entries, sizeof(*cache.entries2), ent_cmp);
 
        if (writetrustcache(cache, argv[0]) == -1)
                return 1;
diff --git a/info.c b/info.c
index 4f74d62d9f0b94286789538531610cd06c60a548..b4249b11c5bc2305c54b063118657a065b824d8f 100644 (file)
--- a/info.c
+++ b/info.c
@@ -77,8 +77,10 @@ tcinfo(int argc, char **argv)
                        for (uint32_t i = 0; i < cache.num_entries; i++) {
                                if (cache.version == 0)
                                        print_hash(cache.hashes[i], true);
-                               else
+                               else if (cache.version == 1)
                                        print_hash(cache.entries[i].cdhash, true);
+                               else if (cache.version == 2)
+                                       print_hash(cache.entries2[i].cdhash, true);
                        }
                        goto done;
                }
@@ -87,10 +89,12 @@ tcinfo(int argc, char **argv)
                                fprintf(stderr, "no entry %i\n", entrynum);
                                exit(1);
                        }
-                       if (cache.version == 1) {
-                               print_entry(cache.entries[entrynum - 1]);
-                       } else if (cache.version == 0) {
+                       if (cache.version == 0) {
                                print_hash(cache.hashes[entrynum - 1], true);
+                       } else if (cache.version == 1) {
+                               print_entry(cache.entries[entrynum - 1]);
+                       } else if (cache.version == 2) {
+                               print_entry2(cache.entries2[entrynum - 1]);
                        }
                } else {
                        print_entries(cache);
@@ -121,6 +125,8 @@ print_entries(struct trust_cache cache)
                        print_hash(cache.hashes[i], true);
                else if (cache.version == 1)
                        print_entry(cache.entries[i]);
+               else if (cache.version == 2)
+                       print_entry2(cache.entries2[i]);
        }
 }
 
@@ -150,6 +156,32 @@ print_entry(struct trust_cache_entry1 entry)
        printf("[%i]\n", entry.hash_type);
 }
 
+void
+print_entry2(struct trust_cache_entry2 entry)
+{
+       print_hash(entry.cdhash, false);
+
+       switch (entry.flags) {
+               case CS_TRUST_CACHE_AMFID:
+                       printf(" CS_TRUST_CACHE_AMFID ");
+                       break;
+               case CS_TRUST_CACHE_ANE:
+                       printf(" CS_TRUST_CACHE_ANE ");
+                       break;
+               case CS_TRUST_CACHE_AMFID|CS_TRUST_CACHE_ANE:
+                       printf(" CS_TRUST_CACHE_AMFID|CS_TRUST_CACHE_ANE ");
+                       break;
+               case 0:
+                       printf(" [none] ");
+                       break;
+               default:
+                       printf(" [%i] ", entry.flags);
+                       break;
+       }
+
+       printf("[%i] [%i]\n", entry.hash_type, entry.category);
+}
+
 void
 print_hash(uint8_t cdhash[CS_CDHASH_LEN], bool newline)
 {
index 5f31848eacd2dba8674c0344742278a873eefe05..4f30f8a176598c7ebc70b6960e145fd622b595fd 100644 (file)
--- a/remove.c
+++ b/remove.c
@@ -89,6 +89,13 @@ tcremove(int argc, char **argv)
                                        numremoved++;
                                        continue;
                                }
+                       } else if (cache.version == 2) {
+                               if (memcmp(cache.entries2[j].cdhash, hash, CS_CDHASH_LEN) == 0) {
+                                       memmove(&cache.entries2[j], &cache.entries2[j + 1], (cache.num_entries - j - 1) * sizeof(struct trust_cache_entry2));
+                                       cache.num_entries--;
+                                       numremoved++;
+                                       continue;
+                               }
                        }
                        j++;
                }
index 68ec6e5e014afee8c9268e6b255d382a502ff8ba..f5aaf5f8cbfd2dd7338bdbf612d590a5d5d58116 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd May 19, 2022
+.Dd June 16, 2022
 .Dt TRUSTCACHE 1
 .Os
 .Sh NAME
@@ -95,7 +95,7 @@ Each Mach-O found in the specified inputs will be scanned for
 a code signature and hashed.
 Any malformed or unsigned Mach-O will be ignored.
 Each slice of a FAT binary will have its hash included.
-Versions 0 and 1 are supported, if not specified, 1 is assumed.
+Versions 0, 1, and 2 are supported, if not specified, 1 is assumed.
 If
 .Ar uuid
 is specified, that will be used instead of a randomly generated one.
@@ -108,9 +108,10 @@ is specified, that will be used instead of a randomly generated one.
 .Xc
 Print information about
 .Ar file .
-The output for each hash will be in the format:
+The output for each hash will be in one of these formats:
 .Pp
 .Dl <cdhash> <flags> [<hash_type>]
+.Dl <cdhash> <flags> [<hash_type>] [<category>]
 .Pp
 If the
 .Fl c
index cb6c7b0e1565afc9c71752503a4217af584ad42d..f9de404b321e2ca2b91774ff02f0df55965bbe2d 100644 (file)
@@ -91,6 +91,10 @@ opentrustcache(const char *path)
                if ((cache.entries = calloc(cache.num_entries, sizeof(struct trust_cache_entry1))) == NULL)
                        exit(EX_OSERR);
                fread(cache.entries, sizeof(struct trust_cache_entry1), cache.num_entries, f);
+       } else if (cache.version == 2) {
+               if ((cache.entries = calloc(cache.num_entries, sizeof(struct trust_cache_entry2))) == NULL)
+                       exit(EX_OSERR);
+               fread(cache.entries, sizeof(struct trust_cache_entry2), cache.num_entries, f);
        } else {
                fprintf(stderr, "%s: Unsupported version %i\n", path, cache.version);
                exit(1);
@@ -120,6 +124,8 @@ writetrustcache(struct trust_cache cache, const char *path)
                        fwrite(&cache.hashes[i], sizeof(trust_cache_hash0), 1, f);
                else if (cache.version == 1)
                        fwrite(&cache.entries[i], sizeof(struct trust_cache_entry1), 1, f);
+               else if (cache.version == 2)
+                       fwrite(&cache.entries2[i], sizeof(struct trust_cache_entry2), 1, f);
        }
 
        fclose(f);
index 3b1696acce08e12c93bea0f22de5a8a50f77df22..2ac17462f898e2b487ea37d3c20e80c0615ad6a6 100644 (file)
 #include "machoparse/cs_blobs.h"
 #include "uuid/uuid.h"
 
+struct trust_cache_entry2 {
+       uint8_t cdhash[CS_CDHASH_LEN];
+       uint8_t hash_type;
+       uint8_t flags;
+       uint16_t category;
+} __attribute__((__packed__));
+
 struct trust_cache_entry1 {
        uint8_t cdhash[CS_CDHASH_LEN];
        uint8_t hash_type;
        uint8_t flags;
-};
+} __attribute__((__packed__));
 
 typedef uint8_t trust_cache_hash0[CS_CDHASH_LEN];
 
@@ -30,6 +37,7 @@ struct trust_cache {
        uuid_t uuid;
        uint32_t num_entries;
        union {
+               struct trust_cache_entry2 *entries2;
                struct trust_cache_entry1 *entries;
                trust_cache_hash0 *hashes;
        };
@@ -54,6 +62,7 @@ int hash_cmp(const void * vp1, const void * vp2);
 void print_header(struct trust_cache cache);
 void print_hash(uint8_t cdhash[CS_CDHASH_LEN], bool newline);
 void print_entry(struct trust_cache_entry1 entry);
+void print_entry2(struct trust_cache_entry2 entry);
 void print_entries(struct trust_cache cache);
 
 #endif