Reproducible build and binary signing

405 Views Asked by At

I'm developing an open source project and I have been working on making the builds reproducible so that my users can compare the checksums of the binaries that I distribute with their own builds (if they were to build the project with/from the source code).

Unfortunately, new versions of Windows and MacOS use code signing in order to check binaries and prevent their execution if they aren't signed (I'm aware that there are ways to override this and execute the binary anyways, but this is not user friendly).

I'd like to sign the binaries that I distribute so that my users can run them without any problems. But I'm not sure if that is possible to do while also keeping the reproducible builds.

For a build to be reproducible, the end user must have all the tools / source code required to build the project and, once compiled, the end result should be the same bit-a-bit binary compared to the one that I'm distributing. But that would mean that I'd have to distribute the private key / cert used to sign the binary, which is not a good idea for multiple reasons.

Is there a way to have both reproducible builds and signed binaries?

2

There are 2 best solutions below

0
William Entriken On

Here is a general approach for creating reproducible signed builds for open source.

Create your "sign binaries" script as follows:

  1. Compile project
  2. Make a checksum of the project's signing preimage
  3. Compare the checksum to the file SIGNING_CHECKSUM

If there is a match:

  1. Use the signature in SIGNING_SIGNATURE to build the package
  2. Verify that SIGNING_SIGNATURE was signed by SIGNING_PUBLIC_KEY

If there is not a match:

  1. Save the checksum to the file SIGNING_CHECKSUM
  2. Use the local signing key to sign the binary
  3. Save the signature to the file SIGNING_SIGNATURE
  4. Verify that SIGNING_SIGNATURE was signed by SIGNING_PUBLIC_KEY

End result is that anybody can reproducibly build the untampered source code. Anybody can edit the source code and reproducibly build the binary so long as the modifications to not modify the signing preimage. And only the developer with access to the signing key is able to sign new releases.

0
Emmanuel Bourg On

It's possible to make reproducible signatures for Windows binaries using Jsign (disclaimer: I'm the author). When signing a binary the signature is exported into a separate file which is meant to be distributed along with the source code of the version released. When the build is executed another time by someone else, Jsign detects the detached signature, and instead of signing the binary it injects the detached signature into the binary file. If the build is reproducible, the binary has the same hash and the signature will be valid.

For example, when the new release is built for the first time, Jsign is invoked with the --detached parameter:

jsign --keystore keystore.p12 --storepass secret --alias test --detached application-1.0.exe

This will sign application-1.0.exe and create an application-1.0.sig file containing the signature. The signature file can be checked into the source repository. The next time the build is executed, the same jsign command is invoked and the content of application-1.0.sig is injected into application-1.0.exe, recreating the exact same binary built initially. Once the signature file is created no access to the private key is necessary, so anyone can recreate the same binary as the original developer.

This process is used by the Apache Tomcat project to make its Windows releases digitally signed and reproducible.