Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Supply chain

How a downloaded RS-Key release proves it came from this source tree, was built by this project’s CI, and pulls in only reviewed dependencies. And how you verify each claim yourself.

No private keys are involved here. The build provenance is keyless (sigstore/Fulcio, signed against this workflow’s GitHub OIDC identity, recorded in the public Rekor transparency log). The only signing key in the project is the secure-boot key. That is a different thing entirely. It seals an image so the RP2350 bootrom will run it. It has nothing to do with the supply chain. See production.md for that.

What every release carries

LayerArtifactWhat it proves
Reproducible buildthe 11 .uf2 flavorsthe binary is a pure function of the source at the tag. Anyone can rebuild it
Repro gate(CI, blocking)the release job fails if any flavor doesn’t rebuild bit-identical, so a non-reproducible image is never published
Checksums + signatureSHA256SUMS + SHA256SUMS.cosign.bundlethe hashes were signed by this repo’s release workflow (keyless cosign)
Build provenancea GitHub attestation (not a release file)which reusable workflow, at which commit, on which runner built each .uf2. SLSA v1 Build L3, keyless via attest-build-provenance
SBOMrs-key-<tag>-sbom.cdx.jsonthe CycloneDX bill of materials for the firmware crate
Dependency auditsupply-chain/ (in-repo)every dependency is covered by an imported audit or a recorded exemption (cargo-vet)

Verifying a download

1. Reproducible build

Rebuild from the tagged source and compare. This is the strongest check, because it needs no trust in the publisher at all:

git checkout <tag>
nix build .#firmware            # or .#firmware-pqc, .#firmware-fips, …
sha256sum result/firmware.uf2   # compare against SHA256SUMS

CI already enforces this: the release job rebuilds all eleven flavors with nix build --rebuild and fails on any bit-level difference before publishing.

2. Checksum signature (keyless cosign)

cosign verify-blob \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity-regexp '^https://github.com/TheMaxMur/RS-Key/\.github/workflows/release-build\.yml@.*$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  SHA256SUMS
sha256sum -c SHA256SUMS          # then check the artifacts against it

The certificate identity is release-build.yml, not release.yml: cosign runs inside the reusable builder. Sigstore stamps the cert with the reusable workflow’s identity (job_workflow_ref).

3. Build provenance (GitHub attestation)

gh attestation verify rs-key-<tag>-default.uf2 \
  --repo TheMaxMur/RS-Key \
  --signer-workflow TheMaxMur/RS-Key/.github/workflows/release-build.yml

This confirms the .uf2 was built by the release-build.yml reusable workflow in this repo. The attestation records the workflow, commit and runner, so a hand-built upload won’t verify. Pinning --signer-workflow to the reusable builder is the SLSA Build L3 check: it proves a specific, trusted workflow produced the artifact, not merely that something in the repo did. (Dropping --signer-workflow still verifies an attestation exists for this repo, a weaker Build-L2-style check.) The provenance is a GitHub attestation (Sigstore-signed, logged in Rekor) kept in the attestation API rather than as a release asset, so it stays available even though the published release is immutable.

Dependency review — cargo-vet

cargo-deny already blocks bad licenses and known advisories. cargo-vet answers a different question (has anyone actually reviewed this crate’s code?) by requiring every dependency to be covered by a recorded audit.

The audit set lives in supply-chain/: imported audits from Mozilla, Google, ISRG and Zcash, plus our own exemptions for everything they don’t cover. The gate runs in check.sh:

nix develop -c cargo vet --locked

Honest scope. RS-Key is an embedded tree: embassy, the RP2350 HAL, defmt and many RustCrypto crates are not in the big organizations’ audit sets, so they are recorded as exemptions (grandfathered in, not yet line-reviewed). The point isn’t that every line is audited. It’s that a new, unreviewed crate cannot enter the tree silently. It fails cargo vet until it’s audited, imported, or explicitly exempted. To see the current state and shrink the exemption list:

nix develop -c cargo vet              # what's audited vs exempted
nix develop -c cargo vet suggest      # diffs to review next

The host tools/tui workspace is separate and not yet under cargo-vet. It is covered by Dependabot and cargo-deny.

Transparency-log monitoring

The Rekor log that backs every signature above is tamper-evident, not tamper-proof: it records misuse, but only if someone looks. A scheduled workflow, rekor-monitor.yml, does the looking. Every hour it runs sigstore/rekor-monitor and files a GitHub issue listing any Rekor entry signed as an RS-Key GitHub-Actions identity (any …/RS-Key/.github/workflows/* subject under the GitHub OIDC issuer).

This is the detection half that complements the verification above: the attestations prove a legitimate release is genuine, while the monitor surfaces an illegitimate signature, one made with our identity by something we didn’t run (a compromised OIDC token, repo, or runner). Each real release adds a couple of expected entries from release-build.yml, so a known issue or two per release is normal. The alarm is an entry you don’t recognise.

What’s deliberately not here

  • No cargo-vet of a fully line-reviewed tree. See the honest scope above.
  • No image encryption / signed-for-boot release artifacts. The published .uf2s are unsigned for secure boot by design. You seal them with your own key (production.md). The signatures on this page attest the build, not the boot.

See also: releases.md for the release index, and COMPLIANCE.md for the licensing posture.