LC_CODE_SIGNATURE gives the file offset and size of the signature in
__LINKEDIT. Its structures are big-endian, whatever the file’s byte order.
The layouts are in <kern/cs_blobs.h>.
The super blob
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 4 | magic | 0xFADE0CC0, CSMAGIC_EMBEDDED_SIGNATURE. |
| 4 | 4 | length | The whole structure’s size. |
| 8 | 4 | count | Number of blobs. |
| 12 | 8 each | index | type and offset of each blob, 4 bytes each, offset from the start of this structure. |
Each blob starts with a 4-byte magic number and a 4-byte length.
| Type | Meaning | Magic |
|---|---|---|
| 0 | Code directory | 0xFADE0C02 |
| 2 | Requirements | 0xFADE0C01 |
| 5 | Entitlements | 0xFADE7171 |
| 7 | DER entitlements | 0xFADE7172 |
| 8, 9, 10, 11 | Launch constraints (self, parent, responsible), library constraint | 0xFADE8181 |
0x1000 to 0x1004 | Alternative code directories | 0xFADE0C02 |
0x10000 | CMS signature | 0xFADE0B01 |
0x10002 | Notarisation ticket |
The code directory
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 4 | magic | 0xFADE0C02. |
| 4 | 4 | length | Size of this blob. |
| 8 | 4 | version | Which of the later fields exist. |
| 12 | 4 | flags | The flags, below. |
| 16 | 4 | hashOffset | Offset of hash slot 0, from the start of this blob. |
| 20 | 4 | identOffset | Offset of the identifier string. |
| 24 | 4 | nSpecialSlots | Number of special slots, at negative indexes. |
| 28 | 4 | nCodeSlots | Number of ordinary (page) slots. |
| 32 | 4 | codeLimit | How much of the file is signed. |
| 36 | 1 | hashSize | Bytes in each hash. |
| 37 | 1 | hashType | 1 SHA-1, 2 SHA-256, 3 SHA-256 truncated to 20 bytes, 4 SHA-384. |
| 38 | 1 | platform | Platform identifier; 0 if not a platform binary. |
| 39 | 1 | pageSize | log2 of the page size; 0 means the whole file is one page. |
| 40 | 4 | spare2 | Unused. |
| 44 | 4 | scatterOffset | From version 0x20100. |
| 48 | 4 | teamOffset | From 0x20200: the team identifier string. |
| 52 | 4 | spare3 | From 0x20300. |
| 56 | 8 | codeLimit64 | From 0x20300: the code limit, for files over 4 GB. |
| 64 | 8 each | execSegBase, execSegLimit, execSegFlags | From 0x20400: the executable segment and its flags (main binary, debugger, JIT and others). |
| 88 | 4 each | runtime, preEncryptOffset | From 0x20500. |
| 96 | 1, 1, 2 | linkageHashType, linkageApplicationType, linkageApplicationSubType | From 0x20600. |
| 100 | 4 each | linkageOffset, linkageSize | From 0x20600. |
The hash slots lie around hashOffset: slot 0 is the first page of the
file, and -1, -2 and so on are the special items, in the
order of the table of types above (-1 Info.plist, -2
requirements, -3 resource directory, -4 application, -5
entitlements, -7 DER entitlements). A slot of all zeros means that item
is not present.
Flags: 0x2 ad hoc, 0x4 get-task-allow, 0x100 hard,
0x200 kill, 0x400 check expiration, 0x800
restrict, 0x1000 enforcement, 0x2000 library validation,
0x10000 hardened runtime, 0x20000 linker-signed. Others are
in the header.
Requirements
The requirements are a blob with magic 0xFADE0C01 and a list of a
4-byte type (3 designated requirement, 1 host, 2 guest, 4 library, 5 plug-in) and a
4-byte offset, then for each a requirement blob with magic
0xFADE0C00. A requirement’s body is a kind (1) and an expression: a
stream of 32-bit opcodes in big-endian order, in a language that codesign prints as
text.
| Opcode | Meaning | Printed |
|---|---|---|
| 0 | never | never |
| 1 | always | always |
| 2 | identifier | identifier "..." |
| 3 | Apple’s anchor | anchor apple |
| 4 | certificate hash | certificate leaf = H"..." |
| 5 | Info.plist value | info[key] = value |
| 6, 7 | and, or | a and b, a or b |
| 8 | code hash | cdhash H"..." |
| 9 | not | ! a |
| 10 | Info.plist field | info[key] = value |
| 11 | certificate field | certificate leaf[subject.CN] = value |
| 12 | certificate trusted | certificate 1 trusted |
| 13 | any trusted anchor | anchor trusted |
| 14 | certificate extension field | certificate leaf[field.1.2.3] |
| 15 | generic Apple anchor | anchor apple generic |
| 16 | entitlement | entitlement[key] = value |
| 17 | certificate policy | certificate leaf[policy.1.2.3] |
| 18 | named anchor | anchor apple name |
| 19 | named code | |
| 20 | platform | platform = n |
| 21 | notarised | notarized |
| 22 | certificate date field | certificate leaf[timestamp.1.2.3] |
| 23 | legacy | legacy |
Certificate slots are written as an integer: 0 is the leaf certificate, −1 the root, and other numbers count from the leaf. A match in a field uses an operation number then, usually, a value: 0 exists, 1 equal, 2 contains, 3 begins with, 4 ends with, 5 less than, 6 greater than, 7 at most, 8 at least, 9 to 13 date comparisons, 14 absent.
Strings and hashes are stored as a 4-byte length, the bytes, and padding to 4 bytes. Expressions are stored in prefix order: a binary operator’s opcode comes before its two operands.
Entitlements
Blob type 5, magic 0xFADE7171, is an XML property list of the
entitlements after the 8-byte header. Blob type 7, magic 0xFADE7172, is
the same entitlements in DER, an ASN.1 form.
CMS signature
Blob type 0x10000, magic 0xFADE0B01, wraps a CMS
(PKCS #7) signature over the code directories. An empty wrapper of just the 8-byte
header belongs to a signature with no signing certificate (an ad hoc signature).