I would like to propose separating the build, packaging and signing of the MultiOS-USB binaries currently committed to the repo in the ./binaries/ directory.
The goal would be to support three use cases:
- A maintainer-signed "ready-to-roll" archive with pre-built and signed binaries, as today.
- An unsigned "ready-to-roll" archive with pre-built, but unsigned binaries for users who want to sign the binaries themselves.
- A reproducible build-from-source workflow for downstream projects (e.g. Linux distributions) or users who prefer to build everything from source.
For the second use case, as well as for locally built binaries from the third use case, multios-usb.sh should be extended to accept a signing key and sign the required binaries locally during installation.
Motivation
This follows up on the discussion in #46.
As discussed there (#46 (comment)), the current binaries are not reproducible because the cryptographic signing step to enable Secure Boot changes their contents. Separating signing from the build would allow the underlying binaries to remain reproducible while retaining Secure Boot support.
Proposed solution
1. Replace the committed binaries with a reproducible build process
Instead of keeping the currently generated binaries committed to the repository, the preferred solution would be to add a Makefile (with a build script as an alternative) that can obtain and build the necessary components from their respective GitLab/upstream sources, or download binaries where building from source is not applicable.
The exact source revisions should be pinned to ensure reproducibility; Git submodules could be one way of achieving this.
Ideally, a clean checkout plus a make build (or running the build script) should be sufficient to build all required (then still unsigned) binaries.
2. Add a signing target
The Makefile should also provide a sign target which allows both users who build from source and the maintainer to easily sign the previously reproducibly built binaries using a signing key provided to the build process by the user, packager, or maintainer.
Ideally, calling make sign should be sufficient to sign all required EFI binaries. For the maintainer, this should reproduce the current signing process and produce the signed binaries that are currently distributed in the ./binaries/ directory.
3. Add a packaging target
The Makefile should provide a package target that creates MultiOS-USB release archives. These archives could then be uploaded as GitHub release assets and would therefore remain the convenient "ready to roll" options for users who don't want to build from source.
- If
make sign has not been called before, make package would create release archives that contain the reproducibly built, but unsigned binaries. When uploaded to GitHub, this matches use case 2 above.
- If the maintainer has called
make sign beforehand, the release archives would contain the same binaries, but with the maintainer's signature. When uploaded to GitHub, this matches use case 1 above.
Both the signed and unsigned release archives could then be distributed alongside each other.
4. Support signing at installation time
When building from source without calling make sign, or when downloading the pre-built but unsigned archive from GitHub, users would initially have MultiOS-USB with unsigned EFI binaries, which cannot be used with Secure Boot until those binaries are signed.
multios-usb.sh should therefore detect unsigned binaries and fail unless the user either provides a signing key to sign them during installation or explicitly opts out of Secure Boot support.
Conceptually:
# Use the pre-built and signed release archive, as before.
./multios-usb.sh /dev/sdX
# Sign the EFI binaries during installation using the provided key.
./multios-usb.sh --key /path/to/private-key /dev/sdX
# Explicitly disable Secure Boot support and leave the EFI binaries unsigned.
./multios-usb.sh --no-secure-boot /dev/sdX
The exact CLI and key format are open for discussion.
The private key should only be used for the signing operation and must not be copied to the resulting USB device.
Reasoning
This not only allows for reproducibility, but separates reproducibility from signing: the binary contents can be independently reproduced and verified, while signing can happen later according to the requirements of the maintainer, user, or downstream distribution.
The basic motivation is probably already clear from the discussion in #46; if desired, I can elaborate further on the security and supply-chain implications in a follow-up.
Notes
In principle, the build and runtime signing changes could be implemented independently. The build, signing and packaging workflow provided by the Makefile could be introduced first, while support for signing pre-built unsigned binaries at installation time could be added to multios-usb.sh later. Until then, users who do not want to use the maintainer-signed binaries would have to build MultiOS-USB from source and run make sign themselves.
This approach would also allow users and downstream projects to establish their own Secure Boot trust chain rather than relying exclusively on a project-wide signing key.
I believe this would provide a clean way to retain the current "just download and use it" experience while adding proper reproducibility and giving both users and downstreams control over the signing step.
I would like to propose separating the build, packaging and signing of the MultiOS-USB binaries currently committed to the repo in the
./binaries/directory.The goal would be to support three use cases:
For the second use case, as well as for locally built binaries from the third use case,
multios-usb.shshould be extended to accept a signing key and sign the required binaries locally during installation.Motivation
This follows up on the discussion in #46.
As discussed there (#46 (comment)), the current binaries are not reproducible because the cryptographic signing step to enable Secure Boot changes their contents. Separating signing from the build would allow the underlying binaries to remain reproducible while retaining Secure Boot support.
Proposed solution
1. Replace the committed binaries with a reproducible build process
Instead of keeping the currently generated binaries committed to the repository, the preferred solution would be to add a
Makefile(with a build script as an alternative) that can obtain and build the necessary components from their respective GitLab/upstream sources, or download binaries where building from source is not applicable.The exact source revisions should be pinned to ensure reproducibility; Git submodules could be one way of achieving this.
Ideally, a clean checkout plus a
make build(or running the build script) should be sufficient to build all required (then still unsigned) binaries.2. Add a signing target
The
Makefileshould also provide asigntarget which allows both users who build from source and the maintainer to easily sign the previously reproducibly built binaries using a signing key provided to the build process by the user, packager, or maintainer.Ideally, calling
make signshould be sufficient to sign all required EFI binaries. For the maintainer, this should reproduce the current signing process and produce the signed binaries that are currently distributed in the./binaries/directory.3. Add a packaging target
The
Makefileshould provide apackagetarget that creates MultiOS-USB release archives. These archives could then be uploaded as GitHub release assets and would therefore remain the convenient "ready to roll" options for users who don't want to build from source.make signhas not been called before,make packagewould create release archives that contain the reproducibly built, but unsigned binaries. When uploaded to GitHub, this matches use case 2 above.make signbeforehand, the release archives would contain the same binaries, but with the maintainer's signature. When uploaded to GitHub, this matches use case 1 above.Both the signed and unsigned release archives could then be distributed alongside each other.
4. Support signing at installation time
When building from source without calling
make sign, or when downloading the pre-built but unsigned archive from GitHub, users would initially have MultiOS-USB with unsigned EFI binaries, which cannot be used with Secure Boot until those binaries are signed.multios-usb.shshould therefore detect unsigned binaries and fail unless the user either provides a signing key to sign them during installation or explicitly opts out of Secure Boot support.Conceptually:
The exact CLI and key format are open for discussion.
The private key should only be used for the signing operation and must not be copied to the resulting USB device.
Reasoning
This not only allows for reproducibility, but separates reproducibility from signing: the binary contents can be independently reproduced and verified, while signing can happen later according to the requirements of the maintainer, user, or downstream distribution.
The basic motivation is probably already clear from the discussion in #46; if desired, I can elaborate further on the security and supply-chain implications in a follow-up.
Notes
In principle, the build and runtime signing changes could be implemented independently. The build, signing and packaging workflow provided by the
Makefilecould be introduced first, while support for signing pre-built unsigned binaries at installation time could be added tomultios-usb.shlater. Until then, users who do not want to use the maintainer-signed binaries would have to build MultiOS-USB from source and runmake signthemselves.This approach would also allow users and downstream projects to establish their own Secure Boot trust chain rather than relying exclusively on a project-wide signing key.
I believe this would provide a clean way to retain the current "just download and use it" experience while adding proper reproducibility and giving both users and downstreams control over the signing step.