Codesigning on Darwin

On aarch64-darwin, all binaries must be codesigned. When binaries are compiled on the target machine, they’re signed automatically. How/when is this performed when downloading from the binary cache, though? I grepped Nixpkgs source but can’t find anything to the effect of doing it for every binary…

Now that I think about it, the “all binaries must be codesigned” point may be false? Or, at the very least, I’m misunderstanding things. For example, when someone installs Nix, the Nix binary isn’t codesigned… but it seemingly would have to be?

(Whenever I say codesigned I mean ad-hoc codesigned.)

It is done at build time, not after substituting. For this we have some extra hacks:

Thanks for the info, I found the postFixup hook but it seems like it was only used in a few packages.

I’m a bit confused, though: so when do binaries downloaded from the binary cache get signed (since an ad-hoc signature is per machine)?

Yes, the strip and install_name_tool wrappers make sure things are signed when the toolchain relies on these tools.

What we currently have to do is more or less equivalent to a binary / object file checksum, apparently, so we can substitute signed executables and dylibs.

@thefloweringash will probably know more about the details

That’s interesting. I’m curious as to how exactly that works, since on aarch64-darwin, all binaries need to be code signed by at least an ad-hoc signature.

I think this Ask Different answer explains what you mean:

So, I guess ad-hoc signatures aren’t per-machine.

(Side note: is “substituting” referring to when derivation results are downloaded from a cache?)

In nixpkgs there are wrappers wherever signatures are required. As already mentioned in the thread, this includes strip and install_name_tool which rewrite the binaries and would otherwise invalidate the signature. There’s also a wrapper around ld, which is the main place that signatures are created, and is essential for ./configure scripts which will often compile and run things as part of their checks. The exact logic is in the bintools-wrapper: build-support/bintools-wrapper/default.nix

The autoSignDarwinBinariesHook is a blunt instrument that adds signatures to everything that looks like MachO file in the outputs. In general it shouldn’t be required: either the wrappers should add correct signatures, or binary packages should already have appropriate signatures.

I think the situation be simplified to some degree by upgrading cctools-port to the latest version, which has its own implementation of ad-hoc signatures.

Indeed. As far as I understand they’re an identity for the binary for whenever macOS wants to record additional permissions like firewall or user documents access. Requiring all binaries to be signed obsoletes the system-wide detached signature database.