[GH-ISSUE #4298] [Feature] Report CodeDirectory posture and the full requirement set in inspect_signature #1702

Open
opened 2026-10-16 21:09:15 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 16, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4298

Before submitting

  • I searched the open and closed issues and pull requests for a related proposal.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This request does not include credentials, private samples, or sensitive target data.

Area

Native analysis or decompilation

Current limitation

inspect_signature reports identity fields, one CDHash, a hardened_runtime Boolean, the designated requirement and XML entitlements, but drops the rest of the CodeDirectory posture that codesign -d prints (versions, flags, alternate CodeDirectories, platform identifier, special-slot bindings, the full requirement set, signing times and entitlement encodings). This request asks inspect_signature to report those facts as observed Evidence, and asks whether the direction of closed, unmerged PR #934 is still wanted in this narrower form.

An analyst who asks "was this linker-signed or signed by codesign?", "does this signature force library validation or a restricted dyld policy?", "is this an operating-system binary?", "does the signature carry DER entitlements?" or "is that designated requirement embedded or only implied?" cannot answer from REA today and has to run codesign -dvvvv and codesign -d -r- by hand.

Observations below use REA 6.5.0 (npm rea-agents@6.5.0, tag rea-agents-6.5.0, commit 3b79af28e80785afce9f5998d8f03289402a1847) on macOS 27.0.1 (26A434) arm64 with Xcode 27.0 (27A266a). The cited source files are unchanged on main at d52a488.

Target (self-built unless noted) codesign -d shows The release build reports
codesign -f -s - -o kill,restrict,library ./flg CodeDirectory v=20400 ... flags=0x2a02(adhoc,kill,restrict,library-validation) hardened_runtime: false; no version, no other flags
clang output, never re-signed flags=0x20002(adhoc,linker-signed) hashes=<n>+0, Internal requirements=none, -r- prints # designated => cdhash H"..." designated_requirement: "cdhash H\"...\"", identical in shape to an embedded requirement; nothing marks linker signing
codesign -f -s - -r='designated => identifier "com.example.req" library => anchor apple' ./req designated => identifier "com.example.req" and library => anchor apple only the designated requirement; the library requirement is dropped
codesign -f -s - --digest-algorithm=sha1,sha256 ./alt CandidateCDHash sha1=... and CandidateCDHash sha256=..., Hash choices=sha1,sha256 one CDHash (the SHA-256 one) and hash_algorithms: ["sha1","sha256"]; the SHA-1 CodeDirectory's CDHash is dropped
/bin/ls (stock) Platform identifier=26, Signed Time=Aug 8, 2026 at 1:31:18 PM, Total signatures=1, Chosen signature=1 timestamp: null; no platform identifier; no signature-slot count
codesign -f -s - -o runtime,library --entitlements ent.plist ./ent CodeDirectory v=20500 ... flags=0x12002(adhoc,library-validation,runtime) hashes=2+7; special slots -5 and -7 non-zero; Runtime Version=27.0.0 hardened_runtime: true and the XML entitlements; no slot binding, no DER check, no runtime version

REA inspects a byte copy of the main executable, not the file in its bundle (NativeMacOSProvider.ts L632). On such a copy, codesign's bundle-relative summary lines do not show what the signature binds: for a copy of Stickies' main executable (cp /System/Applications/Stickies.app/Contents/MacOS/Stickies ./Stickies), codesign -d --verbose=4 ./Stickies prints Info.plist=not bound and Sealed Resources=none, while codesign -d --verbose=6 ./Stickies shows non-zero hashes in special slots -1 and -3. The same --verbose=4 command on the executable inside the bundle prints Info.plist entries=31 and Sealed Resources version=2 rules=2 files=0.

When a secure timestamp is present, timestamp holds codesign's locale-formatted display string (for example Mar 13, 2026 at 9:08:10 AM) with no time zone, so it cannot be compared or sorted reliably.

Current behavior, source-cited at the release tag:

  • The parser keeps Identifier, TeamIdentifier, Format, CDHash, Hash choices, Authority, Timestamp and the CodeDirectory line, and from that line extracts only whether the flag list contains runtime (codesign.ts L36-L53, L115-L120).
  • The result schema has no field for any of the facts above (nativeInspection.ts L146-L160).
  • The provider runs codesign -d --verbose=4, codesign -d -r- and codesign -d --entitlements :- (NativeMacOSProvider.ts L594-L618). It keeps only the text after the first designated => match, which also matches codesign's # designated => comment for an implied requirement (L625-L626), and it reads only the XML span of the entitlements output (L1074-L1084). On macOS 27.0.1, codesign warns that the :- form it uses "is deprecated and will not work in a future release".

Use cases

No response

Desired outcome and success criteria

inspect_signature adds observed signing-posture facts to its existing result. Existing fields keep their names and meanings. The new facts describe the same slice the existing fields describe; per-slice reporting of universal files is out of scope here (see Non-goals).

  • CodeDirectories. One entry per CodeDirectory, including alternate CodeDirectories: version (numeric and as displayed), hash type, its CDHash (truncated and full where available), page size, code-slot and special-slot counts, and which entry the system treats as the primary CDHash.
  • Flags. The raw flag value plus decoded names for adhoc, linker-signed, runtime, library-validation, restrict and kill, and any other names codesign prints. Unrecognized bits stay in the result as raw values rather than being dropped.
  • Platform and runtime. The platform identifier when present (absent stays null, not 0) and the hardened-runtime version when present.
  • Special-slot bindings. Whether the Info.plist (slot -1), the resource seal CodeResources (slot -3), XML entitlements (slot -5) and DER entitlements (slot -7) are bound. A slot is bound when its CodeDirectory special-slot hash is non-zero; this is read from the signature itself, not from codesign's Info.plist= or Sealed Resources= summary lines, which describe the file's surroundings and change when the executable is copied out of its bundle. An all-zero hash in an unused slot is reported as unbound, not as a mismatch. Other non-zero special slots are listed by number without an invented meaning.
  • Requirements. Every internal requirement by type (designated, library, host, guest and any other type codesign prints), and for the designated requirement whether it is embedded (explicit) or implied (synthesized by codesign). The existing designated_requirement string stays as is; the new provenance flag is what distinguishes the two cases.
  • Signing time. The secure Timestamp and the unsecured Signed Time as separate fields, each as an ISO 8601 instant with an explicit offset, plus the source string. Missing values stay null. The result labels Signed Time as signer-supplied and unsecured.
  • Entitlement encodings. Whether XML and DER entitlement blobs are present, and whether their decoded values agree. Disagreement or a missing encoding is reported as such, not resolved silently.
  • Signature slots. The number of signature slots and which slot was inspected, as codesign reports them. When more than one slot is present (OS 27 dual-signed code objects), the result names the inspected slot and records that the other slots were not inspected, or reports each slot separately. It never merges facts from different slots.
  • Evidence conventions. Values are observed from codesign output (or an equivalent documented source) and carry provenance for every command. A field codesign does not print stays unknown with a limitation, not false.

Acceptance criteria

  • For codesign -f -s - -i com.example.flg -o kill,restrict,library ./flg on a clang fixture, the result reports CodeDirectory version 0x20400 and flags adhoc, kill, restrict and library-validation with raw value 0x2a02, and runtime is not set.
  • For an unmodified clang -o hello hello.c output, the result reports flags adhoc and linker-signed, zero special slots, no internal requirements, and a designated requirement marked implied (synthesized).
  • For the req fixture above, the result lists both the designated requirement identifier "com.example.req" (marked explicit) and the library requirement anchor apple.
  • For codesign -f -s - --digest-algorithm=sha1,sha256 ./alt, the result lists two CodeDirectories with hash types sha1 and sha256 and both CDHashes printed by codesign -d --verbose=4, and it identifies the SHA-256 CDHash as the primary one.
  • For stock /bin/ls, the result reports a platform identifier equal to codesign's Platform identifier line on the verifier's host (26 on the test host), a secure timestamp of null, and a Signed Time instant whose wall-clock value matches codesign's Signed Time line, labelled unsecured.
  • For the ent fixture (-o runtime,library with an entitlements plist), the result reports CodeDirectory version 0x20500, a runtime version equal to codesign's Runtime Version line on the verifier's host (27.0.0 on the test host), XML and DER entitlements both bound (non-zero hashes in slots -5 and -7) and decoded to equal values, and Info.plist and resources unbound (all-zero hashes in slots -1 and -3).
  • For stock /System/Applications/Stickies.app, the result reports the Info.plist (slot -1) and the resource seal (slot -3) as bound, matching the non-zero hashes codesign -d --verbose=6 prints for those slots, even though codesign -d --verbose=4 on a byte copy of the main executable prints Info.plist=not bound and Sealed Resources=none.
  • Every target above reports one signature slot, inspected slot 1, matching codesign's Total signatures=1 and Chosen signature=1.
  • The existing fields (identifier, cdhashes, hash_algorithms, designated_requirement, entitlements, timestamp, hardened_runtime) are unchanged for every target above, and the CLI and MCP results are equal.

Expected interaction with targets

Read existing files or captured data

Target and scope details (optional)

Affected area

inspect_signature (MCP) and rea inspect-signature (CLI) in the native macOS provider: the codesign capture and parser, the result schema, generated tool documentation, and the signature tests.

Non-goals

  • Embedded launch and library constraints (requested separately).
  • What entitlements mean, and derived static instrumentation constraints (requested separately).
  • Provisioning-profile decoding (requested separately).
  • Notarization tickets, stapling, Gatekeeper assessment and quarantine attributes (requested separately).
  • Per-slice reporting for universal Mach-O files, tracked by open PR #3583 and a separate defect report.
  • Trust evaluation, certificate-chain validation, codesign --verify, and the contents of the sealed-resource manifest.

Verification available so far

I can suggest a sample or manual check

Verification details (optional)

No response

Alternatives considered

  • Parse the SuperBlob bytes in-process. This would work off macOS, but Apple's caveat below says the structure is not API and has changed many times. Using codesign or Code Signing Services output keeps REA aligned with Apple's tools. The request leaves this choice to the implementer as long as unknown structures are reported, not rejected.
  • Keep sending analysts to codesign -dvvvv. That works today, but its output is unversioned display text, the results do not join REA Evidence, and the designated-requirement case shows that a naive text match loses information.

Possible direction

No response

References

Apple documentation (quoted from developer.apple.com):

  • TN3126: Inside Code Signing: Hashes: "The Inside Code Signing technotes discuss code signing details that aren't considered API. The structure of a code signature has changed numerous times in the past and may well change again in the future." "To get information or validate a code signature, use the codesign tool or the Code Signing Services API." "The code may have multiple code directories, each associated with a different hash algorithm." "Slot -1 holds a hash of the Info.plist. Slot -3 holds a hash of the resources. Slot -5 holds a hash of the entitlements." "Slot -5 holds the hash for the legacy property list entitlements, while slot -7 holds the hash for the new-style DER-encoded entitlements."
  • Using the latest code signature format: "Look in the output for a string such as CodeDirectory v=20500. For any value of v less than 20400, you need to re-sign your app."
  • TN3127: Inside Code Signing: Requirements: "The DR is part of the code signature, making it an internal requirement. A signature can have other internal requirements but that feature isn't used in practice."
  • man codesign on macOS 27.0.1: "If the code does not contain an explicit designated requirement, the implied one will be retrieved and written out as a source comment." The same page documents --signature-slot slot ("1 for the first slot, 2 for the second slot").
  • Flag meanings from the LightweightCodeRequirements reference: isAdhocSigned ("contains a code directory and page hashes but no CMS signature", CS_ADHOC), isSignedByLinker ("signed by the linker and not an invocation of codesign", CS_LINKER_SIGNED), isDynamicLinkerPolicyHardened (CS_RESTRICT, "only has effect on main executables"), and isLibraryValidationRequired (CS_REQUIRE_LV).
  • kSecCodeInfoPlatformIdentifier: "If this code was signed as part of an operating system release, the value identifies that release."
  • kSecCodeInfoTime: "a signer is able to omit this date or pre-date it. ... Ad-hoc signatures never have secured signing dates." kSecCodeInfoTimestamp: "the signing date as (securely) certified by a timestamp authority service." Resolving common notarization issues: "the presence of Signed Time in the output indicates the binary doesn't have a secure timestamp."
  • OS 27 dual signatures: kSecCSUsePostQuantumSignature (macOS 27.0+): "When passed to a validation or inspection call on a dual-signed code object, select the post-quantum (PQ) signature slot for validation and information retrieval." kSecCodeInfoTotalSignatures: "the total number of signature slots present on the code object". The Apple pages do not describe the on-disk layout, and no dual-signed sample was found on the test host (every sample printed Total signatures=1), so the acceptance criteria check only the single-slot case and the proposed behavior asks only that multiple slots are never merged or misreported.

Related REA history:

  • Closed, unmerged PR #934 "feat(native): report code-signing posture in inspect_signature" (closed 2026-10-08, with no reason recorded in the thread) decoded CodeDirectory flags with unknown bits kept in hex, slot counts, hash type, platform identifier, runtime version and executable-segment flags. In the same change it added codesign --verify --strict results, sealed-resource details, stapled-ticket detection and derived security facets. This request covers only the observed CodeDirectory and requirement facts, and adds alternate CodeDirectories, the requirement set, explicit-versus-implied designated requirements, both signing times, DER/XML agreement and signature-slot counts. Maintainers: is this narrower direction still wanted, and was #934 closed for its scope or for its approach?
  • Closed issue #3187 recorded that the docs referred to a debugger-attach facet that inspect_signature never returned. Its fix on main corrected the guidance only.
  • Open PR #3583 checks every slice of a signed universal Mach-O. That is slice coverage, not posture fields.
Originally created by @coygeek on GitHub (Oct 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4298 ### Before submitting - [X] I searched the open and closed issues and pull requests for a related proposal. - [X] I understand the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope) must be reviewed before integration; open questions are welcome here. - [X] This request does not include credentials, private samples, or sensitive target data. ### Area Native analysis or decompilation ### Current limitation `inspect_signature` reports identity fields, one CDHash, a `hardened_runtime` Boolean, the designated requirement and XML entitlements, but drops the rest of the CodeDirectory posture that `codesign -d` prints (versions, flags, alternate CodeDirectories, platform identifier, special-slot bindings, the full requirement set, signing times and entitlement encodings). This request asks `inspect_signature` to report those facts as observed Evidence, and asks whether the direction of closed, unmerged PR #934 is still wanted in this narrower form. An analyst who asks "was this linker-signed or signed by `codesign`?", "does this signature force library validation or a restricted dyld policy?", "is this an operating-system binary?", "does the signature carry DER entitlements?" or "is that designated requirement embedded or only implied?" cannot answer from REA today and has to run `codesign -dvvvv` and `codesign -d -r-` by hand. Observations below use REA 6.5.0 (npm `rea-agents@6.5.0`, tag `rea-agents-6.5.0`, commit `3b79af28e80785afce9f5998d8f03289402a1847`) on macOS 27.0.1 (26A434) arm64 with Xcode 27.0 (27A266a). The cited source files are unchanged on main at `d52a488`. | Target (self-built unless noted) | `codesign -d` shows | The release build reports | | --- | --- | --- | | `codesign -f -s - -o kill,restrict,library ./flg` | `CodeDirectory v=20400 ... flags=0x2a02(adhoc,kill,restrict,library-validation)` | `hardened_runtime: false`; no version, no other flags | | `clang` output, never re-signed | `flags=0x20002(adhoc,linker-signed) hashes=<n>+0`, `Internal requirements=none`, `-r-` prints `# designated => cdhash H"..."` | `designated_requirement: "cdhash H\"...\""`, identical in shape to an embedded requirement; nothing marks linker signing | | `codesign -f -s - -r='designated => identifier "com.example.req" library => anchor apple' ./req` | `designated => identifier "com.example.req"` and `library => anchor apple` | only the designated requirement; the library requirement is dropped | | `codesign -f -s - --digest-algorithm=sha1,sha256 ./alt` | `CandidateCDHash sha1=...` and `CandidateCDHash sha256=...`, `Hash choices=sha1,sha256` | one CDHash (the SHA-256 one) and `hash_algorithms: ["sha1","sha256"]`; the SHA-1 CodeDirectory's CDHash is dropped | | `/bin/ls` (stock) | `Platform identifier=26`, `Signed Time=Aug 8, 2026 at 1:31:18 PM`, `Total signatures=1`, `Chosen signature=1` | `timestamp: null`; no platform identifier; no signature-slot count | | `codesign -f -s - -o runtime,library --entitlements ent.plist ./ent` | `CodeDirectory v=20500 ... flags=0x12002(adhoc,library-validation,runtime) hashes=2+7`; special slots `-5` and `-7` non-zero; `Runtime Version=27.0.0` | `hardened_runtime: true` and the XML entitlements; no slot binding, no DER check, no runtime version | REA inspects a byte copy of the main executable, not the file in its bundle ([NativeMacOSProvider.ts L632](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/native/NativeMacOSProvider.ts#L632)). On such a copy, codesign's bundle-relative summary lines do not show what the signature binds: for a copy of Stickies' main executable (`cp /System/Applications/Stickies.app/Contents/MacOS/Stickies ./Stickies`), `codesign -d --verbose=4 ./Stickies` prints `Info.plist=not bound` and `Sealed Resources=none`, while `codesign -d --verbose=6 ./Stickies` shows non-zero hashes in special slots -1 and -3. The same `--verbose=4` command on the executable inside the bundle prints `Info.plist entries=31` and `Sealed Resources version=2 rules=2 files=0`. When a secure timestamp is present, `timestamp` holds codesign's locale-formatted display string (for example `Mar 13, 2026 at 9:08:10 AM`) with no time zone, so it cannot be compared or sorted reliably. Current behavior, source-cited at the release tag: - The parser keeps `Identifier`, `TeamIdentifier`, `Format`, `CDHash`, `Hash choices`, `Authority`, `Timestamp` and the `CodeDirectory` line, and from that line extracts only whether the flag list contains `runtime` ([codesign.ts L36-L53](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/native/parsers/codesign.ts#L36-L53), [L115-L120](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/native/parsers/codesign.ts#L115-L120)). - The result schema has no field for any of the facts above ([nativeInspection.ts L146-L160](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/domain/native/nativeInspection.ts#L146-L160)). - The provider runs `codesign -d --verbose=4`, `codesign -d -r-` and `codesign -d --entitlements :-` ([NativeMacOSProvider.ts L594-L618](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/native/NativeMacOSProvider.ts#L594-L618)). It keeps only the text after the first `designated =>` match, which also matches codesign's `# designated =>` comment for an implied requirement ([L625-L626](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/native/NativeMacOSProvider.ts#L625-L626)), and it reads only the XML span of the entitlements output ([L1074-L1084](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/native/NativeMacOSProvider.ts#L1074-L1084)). On macOS 27.0.1, `codesign` warns that the `:-` form it uses "is deprecated and will not work in a future release". ### Use cases _No response_ ### Desired outcome and success criteria `inspect_signature` adds observed signing-posture facts to its existing result. Existing fields keep their names and meanings. The new facts describe the same slice the existing fields describe; per-slice reporting of universal files is out of scope here (see Non-goals). - **CodeDirectories.** One entry per CodeDirectory, including alternate CodeDirectories: version (numeric and as displayed), hash type, its CDHash (truncated and full where available), page size, code-slot and special-slot counts, and which entry the system treats as the primary CDHash. - **Flags.** The raw flag value plus decoded names for `adhoc`, `linker-signed`, `runtime`, `library-validation`, `restrict` and `kill`, and any other names codesign prints. Unrecognized bits stay in the result as raw values rather than being dropped. - **Platform and runtime.** The platform identifier when present (absent stays `null`, not `0`) and the hardened-runtime version when present. - **Special-slot bindings.** Whether the Info.plist (slot -1), the resource seal `CodeResources` (slot -3), XML entitlements (slot -5) and DER entitlements (slot -7) are bound. A slot is bound when its CodeDirectory special-slot hash is non-zero; this is read from the signature itself, not from codesign's `Info.plist=` or `Sealed Resources=` summary lines, which describe the file's surroundings and change when the executable is copied out of its bundle. An all-zero hash in an unused slot is reported as unbound, not as a mismatch. Other non-zero special slots are listed by number without an invented meaning. - **Requirements.** Every internal requirement by type (designated, library, host, guest and any other type codesign prints), and for the designated requirement whether it is embedded (explicit) or implied (synthesized by codesign). The existing `designated_requirement` string stays as is; the new provenance flag is what distinguishes the two cases. - **Signing time.** The secure `Timestamp` and the unsecured `Signed Time` as separate fields, each as an ISO 8601 instant with an explicit offset, plus the source string. Missing values stay `null`. The result labels `Signed Time` as signer-supplied and unsecured. - **Entitlement encodings.** Whether XML and DER entitlement blobs are present, and whether their decoded values agree. Disagreement or a missing encoding is reported as such, not resolved silently. - **Signature slots.** The number of signature slots and which slot was inspected, as codesign reports them. When more than one slot is present (OS 27 dual-signed code objects), the result names the inspected slot and records that the other slots were not inspected, or reports each slot separately. It never merges facts from different slots. - **Evidence conventions.** Values are observed from codesign output (or an equivalent documented source) and carry provenance for every command. A field codesign does not print stays unknown with a limitation, not `false`. **Acceptance criteria** - [ ] For `codesign -f -s - -i com.example.flg -o kill,restrict,library ./flg` on a `clang` fixture, the result reports CodeDirectory version `0x20400` and flags `adhoc`, `kill`, `restrict` and `library-validation` with raw value `0x2a02`, and `runtime` is not set. - [ ] For an unmodified `clang -o hello hello.c` output, the result reports flags `adhoc` and `linker-signed`, zero special slots, no internal requirements, and a designated requirement marked implied (synthesized). - [ ] For the `req` fixture above, the result lists both the designated requirement `identifier "com.example.req"` (marked explicit) and the library requirement `anchor apple`. - [ ] For `codesign -f -s - --digest-algorithm=sha1,sha256 ./alt`, the result lists two CodeDirectories with hash types `sha1` and `sha256` and both CDHashes printed by `codesign -d --verbose=4`, and it identifies the SHA-256 CDHash as the primary one. - [ ] For stock `/bin/ls`, the result reports a platform identifier equal to codesign's `Platform identifier` line on the verifier's host (`26` on the test host), a secure timestamp of `null`, and a `Signed Time` instant whose wall-clock value matches codesign's `Signed Time` line, labelled unsecured. - [ ] For the `ent` fixture (`-o runtime,library` with an entitlements plist), the result reports CodeDirectory version `0x20500`, a runtime version equal to codesign's `Runtime Version` line on the verifier's host (`27.0.0` on the test host), XML and DER entitlements both bound (non-zero hashes in slots -5 and -7) and decoded to equal values, and Info.plist and resources unbound (all-zero hashes in slots -1 and -3). - [ ] For stock `/System/Applications/Stickies.app`, the result reports the Info.plist (slot -1) and the resource seal (slot -3) as bound, matching the non-zero hashes `codesign -d --verbose=6` prints for those slots, even though `codesign -d --verbose=4` on a byte copy of the main executable prints `Info.plist=not bound` and `Sealed Resources=none`. - [ ] Every target above reports one signature slot, inspected slot 1, matching codesign's `Total signatures=1` and `Chosen signature=1`. - [ ] The existing fields (`identifier`, `cdhashes`, `hash_algorithms`, `designated_requirement`, `entitlements`, `timestamp`, `hardened_runtime`) are unchanged for every target above, and the CLI and MCP results are equal. ### Expected interaction with targets Read existing files or captured data ### Target and scope details (optional) **Affected area** `inspect_signature` (MCP) and `rea inspect-signature` (CLI) in the native macOS provider: the codesign capture and parser, the result schema, generated tool documentation, and the signature tests. **Non-goals** - Embedded launch and library constraints (requested separately). - What entitlements mean, and derived static instrumentation constraints (requested separately). - Provisioning-profile decoding (requested separately). - Notarization tickets, stapling, Gatekeeper assessment and quarantine attributes (requested separately). - Per-slice reporting for universal Mach-O files, tracked by open PR #3583 and a separate defect report. - Trust evaluation, certificate-chain validation, `codesign --verify`, and the contents of the sealed-resource manifest. ### Verification available so far I can suggest a sample or manual check ### Verification details (optional) _No response_ ### Alternatives considered - **Parse the SuperBlob bytes in-process.** This would work off macOS, but Apple's caveat below says the structure is not API and has changed many times. Using codesign or Code Signing Services output keeps REA aligned with Apple's tools. The request leaves this choice to the implementer as long as unknown structures are reported, not rejected. - **Keep sending analysts to `codesign -dvvvv`.** That works today, but its output is unversioned display text, the results do not join REA Evidence, and the designated-requirement case shows that a naive text match loses information. ### Possible direction _No response_ ### References Apple documentation (quoted from developer.apple.com): - [TN3126: Inside Code Signing: Hashes](https://developer.apple.com/documentation/technotes/tn3126-inside-code-signing-hashes): "The *Inside Code Signing* technotes discuss code signing details that aren't considered API. The structure of a code signature has changed numerous times in the past and may well change again in the future." "To get information or validate a code signature, use the `codesign` tool or the Code Signing Services API." "The code may have multiple code directories, each associated with a different hash algorithm." "Slot -1 holds a hash of the `Info.plist`. Slot -3 holds a hash of the resources. Slot -5 holds a hash of the entitlements." "Slot -5 holds the hash for the legacy property list entitlements, while slot -7 holds the hash for the new-style DER-encoded entitlements." - [Using the latest code signature format](https://developer.apple.com/documentation/xcode/using-the-latest-code-signature-format): "Look in the output for a string such as `CodeDirectory v=20500`. For any value of `v` less than `20400`, you need to re-sign your app." - [TN3127: Inside Code Signing: Requirements](https://developer.apple.com/documentation/technotes/tn3127-inside-code-signing-requirements): "The DR is part of the code signature, making it an *internal requirement*. A signature can have other internal requirements but that feature isn't used in practice." - `man codesign` on macOS 27.0.1: "If the code does not contain an explicit designated requirement, the implied one will be retrieved and written out as a source comment." The same page documents `--signature-slot slot` ("1 for the first slot, 2 for the second slot"). - Flag meanings from the LightweightCodeRequirements reference: [isAdhocSigned](https://developer.apple.com/documentation/lightweightcoderequirements/ondiskcodesigningflags/valueset/isadhocsigned) ("contains a code directory and page hashes but no CMS signature", `CS_ADHOC`), [isSignedByLinker](https://developer.apple.com/documentation/lightweightcoderequirements/ondiskcodesigningflags/valueset/issignedbylinker) ("signed by the linker and not an invocation of codesign", `CS_LINKER_SIGNED`), [isDynamicLinkerPolicyHardened](https://developer.apple.com/documentation/lightweightcoderequirements/ondiskcodesigningflags/valueset/isdynamiclinkerpolicyhardened) (`CS_RESTRICT`, "only has effect on main executables"), and [isLibraryValidationRequired](https://developer.apple.com/documentation/lightweightcoderequirements/ondiskcodesigningflags/valueset/islibraryvalidationrequired) (`CS_REQUIRE_LV`). - [kSecCodeInfoPlatformIdentifier](https://developer.apple.com/documentation/security/kseccodeinfoplatformidentifier): "If this code was signed as part of an operating system release, the value identifies that release." - [kSecCodeInfoTime](https://developer.apple.com/documentation/security/kseccodeinfotime): "a signer is able to omit this date or pre-date it. ... Ad-hoc signatures never have secured signing dates." [kSecCodeInfoTimestamp](https://developer.apple.com/documentation/security/kseccodeinfotimestamp): "the signing date as (securely) certified by a timestamp authority service." [Resolving common notarization issues](https://developer.apple.com/documentation/security/resolving-common-notarization-issues): "the presence of `Signed Time` in the output indicates the binary doesn't have a secure timestamp." - OS 27 dual signatures: [kSecCSUsePostQuantumSignature](https://developer.apple.com/documentation/security/seccsflags/usepostquantumsignature) (macOS 27.0+): "When passed to a validation or inspection call on a dual-signed code object, select the post-quantum (PQ) signature slot for validation and information retrieval." [kSecCodeInfoTotalSignatures](https://developer.apple.com/documentation/security/kseccodeinfototalsignatures): "the total number of signature slots present on the code object". The Apple pages do not describe the on-disk layout, and no dual-signed sample was found on the test host (every sample printed `Total signatures=1`), so the acceptance criteria check only the single-slot case and the proposed behavior asks only that multiple slots are never merged or misreported. Related REA history: - Closed, unmerged PR #934 "feat(native): report code-signing posture in inspect_signature" (closed 2026-10-08, with no reason recorded in the thread) decoded CodeDirectory flags with unknown bits kept in hex, slot counts, hash type, platform identifier, runtime version and executable-segment flags. In the same change it added `codesign --verify --strict` results, sealed-resource details, stapled-ticket detection and derived security facets. This request covers only the observed CodeDirectory and requirement facts, and adds alternate CodeDirectories, the requirement set, explicit-versus-implied designated requirements, both signing times, DER/XML agreement and signature-slot counts. Maintainers: is this narrower direction still wanted, and was #934 closed for its scope or for its approach? - Closed issue #3187 recorded that the docs referred to a debugger-attach facet that `inspect_signature` never returned. Its fix on main corrected the guidance only. - Open PR #3583 checks every slice of a signed universal Mach-O. That is slice coverage, not posture fields.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#1702
No description provided.