Appendix: Apple Silicon Trust Cache Format

The internal structure of a trust cache.

Overview

An Image4 manifest brings user-space code into the measured set through two objects: the trust cache object and the restore trust cache object. Each object carries a digest of a trust cache, and the trust cache holds the CDHash of every binary it covers.

A trust cache has a relatively simple structure, with a minimal header followed by an array of fixed-length entries:

TrustCacheEntryFlags ::= ENUMERATION {
    amfid(1),
    remLoBit(64),
    remHiBit(128),
}

TrustCacheEntry ::= SEQUENCE {
    cdHash               UInt8 [20],
    hashType             UInt8,
    TrustCacheEntryFlags UInt8,
    constraintCategory   UInt8,
    reserved             UInt8,
}

TrustCache ::= SEQUENCE {
    version    UInt32,
    uuid       UInt8 [16],
    entryCount UInt32,
    entries    TrustCacheEntry [...],
}

The header is 24 bytes: a 32-bit version, the UUID, and a 32-bit entry count. The entry above is the version 2 entry. A node’s parser also accepts earlier versions, and the entry shrinks with each earlier version: a version 1 entry ends after the flags byte, and a version 0 entry is a bare 20-byte CDHash.

The cryptexctl dump-trust-cache command also dumps this structure. The CDHashes can be compared to a binary by using codesign to extract its CDHash.