aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2022-06-16 10:17:00 -0400
committerCameron Katri <me@cameronkatri.com>2022-06-16 10:21:50 -0400
commit9ef2c4a87d6fa816639b610313b67b98e983388a (patch)
treef3c5d259a3e0b87c5301ddf23b3185b4de9fbe9f
parent6a5be2524f0d31a601687e8b5d09b9af92848dac (diff)
downloadtrustcache-9ef2c4a87d6fa816639b610313b67b98e983388a.tar.gz
trustcache-9ef2c4a87d6fa816639b610313b67b98e983388a.tar.zst
trustcache-9ef2c4a87d6fa816639b610313b67b98e983388a.zip
Add support for new version 2 trustcachesHEADmain
Thanks to Linus Henze for reversing the new format https://gist.github.com/LinusHenze/4cd5d7ef057a144cda7234e2c247c056
-rw-r--r--.gitignore2
-rw-r--r--README.txt11
-rw-r--r--append.c34
-rw-r--r--cache_from_tree.c6
-rw-r--r--create.c22
-rw-r--r--info.c40
-rw-r--r--remove.c7
-rw-r--r--trustcache.17
-rw-r--r--trustcache.c6
-rw-r--r--trustcache.h11
10 files changed, 124 insertions, 22 deletions
diff --git a/.gitignore b/.gitignore
index 2ee8367..9e8345a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,5 @@ a.out
*.bin
trustcache
.vscode
+*.tc
+linux-sysroot
diff --git a/README.txt b/README.txt
index 12da2b3..3f81ef8 100644
--- a/README.txt
+++ b/README.txt
@@ -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
diff --git a/append.c b/append.c
index 5bc468d..fc0cb85 100644
--- 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:
diff --git a/cache_from_tree.c b/cache_from_tree.c
index 610653c..723fbac 100644
--- a/cache_from_tree.c
+++ b/cache_from_tree.c
@@ -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++;
}
diff --git a/create.c b/create.c
index c88abc4..7c73a05 100644
--- 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 4f74d62..b4249b1 100644
--- 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]);
}
}
@@ -151,6 +157,32 @@ print_entry(struct trust_cache_entry1 entry)
}
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)
{
for (size_t j = 0; j < CS_CDHASH_LEN; j++) {
diff --git a/remove.c b/remove.c
index 5f31848..4f30f8a 100644
--- 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++;
}
diff --git a/trustcache.1 b/trustcache.1
index 68ec6e5..f5aaf5f 100644
--- a/trustcache.1
+++ b/trustcache.1
@@ -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
diff --git a/trustcache.c b/trustcache.c
index cb6c7b0..f9de404 100644
--- a/trustcache.c
+++ b/trustcache.c
@@ -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);
diff --git a/trustcache.h b/trustcache.h
index 3b1696a..2ac1746 100644
--- a/trustcache.h
+++ b/trustcache.h
@@ -17,11 +17,18 @@
#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