apple-codesign 0.29.0

Pure Rust interface to code signing on Apple platforms
Documentation
.. _apple_codesign_gatekeeper:

======================
A Primer on Gatekeeper
======================

*Gatekeeper* is the name Apple gives to a set of technologies that enforce
application execution policies at the operating system level. Essentially,
Gatekeeper answers the question *is this software allowed to run*.

When Gatekeeper runs, it performs a *security assessment* against the
binary and the currently configured system policies from the system policy
database (see ``man syspolicyd``). If the binary fails to meet the requirements,
Gatekeeper prevents the binary from running.

The ``spctl`` Tool
==================

The ``spctl`` program distributed with macOS allows you to query and
manipulate the assessment policies.

If you run ``sudo spctl --list``, it will print a list of rules.  e.g.::

    $ sudo spctl --list
    8[Apple System] P20 allow lsopen
            anchor apple
    3[Apple System] P20 allow execute
            anchor apple
    2[Apple Installer] P20 allow install
            anchor apple generic and certificate 1[subject.CN] = "Apple Software Update Certification Authority"
    17[Testflight] P10 allow execute
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.1] exists and certificate leaf[field.1.2.840.113635.100.6.1.25.1] exists
    10[Mac App Store] P10 allow install
            anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.10] exists
    5[Mac App Store] P10 allow install
            anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.10] exists
    4[Mac App Store] P10 allow execute
            anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9] exists
    16[Notarized Developer ID] P5 allow lsopen
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and notarized
    12[Notarized Developer ID] P5 allow install
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and (certificate leaf[field.1.2.840.113635.100.6.1.14] or certificate leaf[field.1.2.840.113635.100.6.1.13]) and notarized
    11[Notarized Developer ID] P5 allow execute
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and notarized
    9[Developer ID] P4 allow lsopen
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and legacy
    7[Developer ID] P4 allow install
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and (certificate leaf[field.1.2.840.113635.100.6.1.14] or certificate leaf[field.1.2.840.113635.100.6.1.13]) and legacy
    6[Developer ID] P4 allow execute
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and (certificate leaf[timestamp.1.2.840.113635.100.6.1.33] absent or certificate leaf[timestamp.1.2.840.113635.100.6.1.33] < timestamp "20190408000000Z")
    2718[GKE] P0 allow lsopen [(gke)]
            cdhash H"975d9247503b596784dd8a9665fd3ff43eb7722f"
    2717[GKE] P0 allow execute [(gke)]
            cdhash H"cf782d6467be86b73a83d86cd6d8c9f87d9d9ce5"
    ...
    18[GKE] P0 allow lsopen [(gke)]
            cdhash H"cf5f88b3b2ff4d8612aabb915f6d1f712e16b6f2"
    15[Unnotarized Developer ID] P0 deny lsopen
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists
    14[Unnotarized Developer ID] P0 deny install
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and (certificate leaf[field.1.2.840.113635.100.6.1.14] or certificate leaf[field.1.2.840.113635.100.6.1.13])
    13[Unnotarized Developer ID] P0 deny execute
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and (certificate leaf[timestamp.1.2.840.113635.100.6.1.33] exists and certificate leaf[timestamp.1.2.840.113635.100.6.1.33] >= timestamp "20190408000000Z")
    ```

The first line of each item identifies the policy. The second line is a
*code requirement language expression*. This is a DSL that compiles to a
binary expression tree for representing a test to perform against a binary.
See ``man csreq`` for more.

Some of these expressions are pretty straightforward. For example,
the following entry says to allow executing a binary with a code signature
whose *code directory* hash is ``cf782d6467be86b73a83d86cd6d8c9f87d9d9ce5``::

    2717[GKE] P0 allow execute [(gke)]
            cdhash H"cf782d6467be86b73a83d86cd6d8c9f87d9d9ce5"

The *code directory* refers to a data structure within the code
signature that contains (among other things) content digests of the binary. The
hash/digest of the code directory itself is effectively a chained digest to the
actual binary content and theoretically a unique way of identifying a binary. So
``cdhash H"cf782d6467be86b73a83d86cd6d8c9f87d9d9ce5"`` is a very convoluted
way of saying *allow this specific binary (specified by its content hash)
to execute*.

Other rules are more interesting. For example::

    11[Notarized Developer ID] P5 allow execute
            anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists
            and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and notarized

We see the description (``Notarized Developer ID``) but what does that
expression mean?

Well, first this expression parses into a tree. We won't attempt to format
the tree here. But essentially the following conditions must ``all`` be true:

* ``anchor apple generic``
* ``certificate 1[field.1.2.840.113635.100.6.2.6] exists``
* ``certificate leaf[field.1.2.840.113635.100.6.1.13] exists``
* ``notarized``

``anchor apple generic`` and ``notarized`` are essentially special expressions
that expand to mean *the certificate signing chain leads back to an Apple
root certificate authority (CA)* and *there is a supplemental code signature
from Apple that can only come from Apple's notarization service*.

But what about those ``certificate`` expressions? That
``certificate <position>[field.*]`` syntax essentially says *the code signature
certificate at ``<position>`` in the certificate chain has an X.509 certificate
extension with OID ``X``* (where ``X`` is a value like ``A.B.C.D.E.F``).

This is all pretty low level. But essentially X.509 certificates can have
a series of *extensions* that further describe the certificate. Apple code
signing uses these extensions to convey metadata about the certificate. And
since code signing certificates are signed, whoever signed those certificates
is effectively also approving of whatever is conveyed by the extensions
within.

But what do these extensions actually mean? Running ``rcodesign x509-oids``
may give us some help::

    $ rcodesign x509-oids`
    ...
    Code Signing Certificate Extension OIDs
    ...
    1.2.840.113635.100.6.1.13       DeveloperIdApplication
    ...
    Certificate Authority Certificate Extension OIDs
    ...
    1.2.840.113635.100.6.2.6        DeveloperId

We see ``1.2.840.113635.100.6.2.6`` is the OID of an extension on
certificate authorities indicating they act as the *Apple Developer
ID* certificate authority. We also see that ``1.2.840.113635.100.6.1.13``
is the OID of an extension saying the certificate acts as a code signing
certificate for *applications* associated with an *Apple Developer ID*.

So, what this expression translates to is essentially:

* Trust code signatures whose certificate signing chain leads back to an
  Apple CA.
* The signer of the code signing certificate must have the extension that
  identifies it as the *Apple Developer ID* certificate authority.
* The code signing certificate itself must have the extension that says
  it is an *Apple Developer ID* for use with *application* signing.
* The binary is *notarized*.

In simple terms, this is saying *allow execution of binaries that
were signed by a Developer ID code signing certificate which was signed
by Apple's Developer ID certificate authority and are also notarized*.