golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.32k stars 17.58k forks source link

proposal: cmd/internal/codesign: Extend mach-O codesigning with entitlements #59522

Open oxisto opened 1 year ago

oxisto commented 1 year ago

Hi everyone,

Not sure if this is would actually need to be a proposal, since it only changes an internal API but I would like to extend the functionality of the cmd/internal/codesign package. Currently, it only performs basic codesigning of (macOS) mach-O binaries. However, on macOS, the code signing process also includes additional meta-data, for example so called entitlements. I would like to extent the currently code signing code to make it possible to create Go binaries with entititlements (and possibly other code signing features).

One could argue, that for such use-cases codesign should or can be used. While this is true, there are two points that speak in favour:

  1. The Go pipeline is already there; so why not extend it to include more advanced features? The code signing process seemed pretty stable over the last years, so not much maintenance should be expected
  2. While you can use codesign in the final steps of preparing an executable, it is cumbersome to use in go test. A good example for such a workaround is the current way tests are working in delve for the (slightly broken) native Go frontend. An external Go script is compiling the test binary and signs it with codesign, making in-place debugging very hard.

I already made myself familiar with the code in cmd/internal/codesign and would like to implement these changes in a PR.

I have not yet discussed how to actually read the entitlements (maybe from an ENV?), I would like to focus on extending the code sign functionality first.

prattmic commented 1 year ago

cc @golang/compiler @cherrymui

prattmic commented 1 year ago

cmd/internal/codesign is an internal package used by the Go command and Go linker. Is it your intention to extend the Go command to allow adding additional entitlements to binaries built through the go command? Or are you using this package in a separate project outside of the go toolchain?

oxisto commented 1 year ago

cmd/internal/codesign is an internal package used by the Go command and Go linker. Is it your intention to extend the Go command to allow adding additional entitlements to binaries built through the go command? Or are you using this package in a separate project outside of the go toolchain?

My intention would be to extend the Go command / linker.

prattmic commented 1 year ago

Thanks for the clarification. I think that this should stay in the proposal process, as it will need to add flags to the Go toolchain.

cherrymui commented 1 year ago

Could you propose the command line interface that the user would use? As discussed above, cmd/internal/codesign is an internal ABI and is less important, as long as the implementation is not too complex.

A good example for such a workaround is the current way tests are working in delve for the (slightly broken) native Go frontend.

Could you give more detail about the difficulties in this? That would probably be helpful to design a workflow to solve the user's problem.

Thanks.

oxisto commented 1 year ago

Could you propose the command line interface that the user would use?

I could imagine several ways to do it. Each one has some pros and cons:

Option 1: Linker flag

Adding a linker flag like -entitlements would solve most of the issues I guess. Then we could do something like go test -ldflags="-entitlements file.plist" which would look for the plist file and embed its content as entitlements.

I am not quite sure, if this would work with go install? But this is maybe less of a priority.

Option 2: Environment variable

This would give us either the option to specify a file or even the XML directly as a GOMACHOENTITLEMENTS variable.

Option 3: Somehow embed entitlements in code

This would be a real nice option, maybe embedding them into a comment somehow, but I fear that this would change too much and would need to tackle other areas of Go that I don't want to touch.

As discussed above, cmd/internal/codesign is an internal ABI and is less important, as long as the implementation is not too complex.

That's good to hear. The initial prototype exploration I did does not seem to complex. Basically, we need to add one more Blob for the entitlement, add additional hashes to the end of the CodeDirectory and adjust sizes/offsets correctly. The tricky part is to actually get the entitlements from the user to the codesign package. At first glance, adding a field like entitlements (or similar) to the Link structure of cmd/link/internal/ld seemed the best way, as all the machoXXX functions can access this.

A good example for such a workaround is the current way tests are working in delve for the (slightly broken) native Go frontend.

Could you give more detail about the difficulties in this? That would probably be helpful to design a workflow to solve the user's problem.

The way it works is basically that delve uses a make.go file that executes a go run test command with the -exec option, which in turn executes a little script that does execute's macOS native codesign + launches the executable. One of the major drawbacks is that this only works in the command-line and not when debugging (e.g. with delve itself and/or vscode). It is also a major workaround.

Similarly, go install also does not work out of the box because as far as I know there is not way to execute the additional codesign command after "installation"/building.

Thanks.

oxisto commented 1 year ago

I have a working prototype of this (at least the core signing, without the interface to the user), I might submit this in the following days and then wait for the proposal decision. We still need to work out which of the options discussed above would work best then.

gopherbot commented 1 year ago

Change https://go.dev/cl/484495 mentions this issue: cmd/internal/codesign: Support embedding entitlements on mach-o