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

Releases & verification

Releases live on the GitHub Releases page. Each is cut from a v* git tag by the release workflow. It builds every artifact reproducibly, hashes it, and signs the manifest.

What a release contains

  • Fourteen firmware images: rs-key-<tag>-<flavor>.uf2. Every published image requires a physical touch; the no-touch test builds are never released (a signed presence-bypass asset would remove the consent gate):

    flavorflagsuse
    defaulttouchthe normal build; start here
    pqc+ advertise-pqcadvertises ML-DSA-65 and ML-DSA-44 in getInfo (breaks old Firefox)
    fips+ fips-profilethe locked FIPS-style policy (guides/fips.md)
    fips-pqc+ both
    strong-pin+ strong-pin6-code-point PIN floor + trivial-PIN block (build.md, threat-model.md)
    strong-pin-pqc+ both
    always-uv+ always-uvbakes CTAP 2.1 alwaysUv on: user verification (a PIN) for every operation, U2F disabled. Set a PIN after flashing (build.md)
    always-uv-pqc+ both
    strict-up+ strict-upnot spec-conformant: a touch on every assertion, so a WebAuthn allowCredentials login asks for two touches (build.md). Pick it only if you want that stricter stance
    strict-up-pqc+ both
    display+ displayexperimental trusted-display build (Waveshare RP2350-Touch-LCD-2.8, guides/display.md)
    2mbFLASH_SIZE=2M KVMAIN=896K2 MB boards (Seeed XIAO RP2350, Waveshare RP2350-Zero-CM)
    16mbFLASH_SIZE=16M16 MB boards (e.g. TenStar RP2350-USB)
    strict-config+ strict-configthe historical strict admin-write posture: config writes stay presence/PIN-gated and the ungated transport writes are refused (build.md, threat-model.md). The default build is now the permissive full-ykman admin surface

    All fourteen present the default RS-Key USB identity (0x1209:0x0001). For the YubiKey-interop identity, build VIDPID=Yubikey5 yourself (build.md).

  • SHA256SUMS: a checksum for every image and the SBOM.

  • SHA256SUMS.cosign.bundle: a keyless cosign signature of SHA256SUMS (sigstore/Fulcio; the signer is the reusable build workflow’s GitHub OIDC identity, release-build.yml, see the verify step below; logged in Rekor).

  • rs-key-<tag>-sbom.cdx.json: a CycloneDX software bill of materials for the firmware’s dependency tree.

The images are UNSIGNED for secure boot. The cosign signature attests who built them, not the boot seal. On a secure-boot device you seal an image with your own key before flashing. nix run .#flash does it, or see production.md. The reproducibility claim is about the unsigned payload (a seal is signer-specific and not reproducible by a third party).

Verify a download

Grab the images you want plus SHA256SUMS and SHA256SUMS.cosign.bundle.

# 1. the checksums file is authentic (keyless cosign — needs cosign >= 2.0)
#    The signer is the *reusable* build workflow (release-build.yml), not the
#    thin release.yml caller: a workflow_call job's OIDC identity is its own
#    job_workflow_ref, so that is what the Fulcio cert's SAN carries.
cosign verify-blob \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity-regexp '^https://github\.com/TheMaxMur/RS-Key/\.github/workflows/release-build\.yml@refs/tags/v.*' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  SHA256SUMS

# 2. the images match the (now-trusted) checksums
sha256sum -c SHA256SUMS

Both must pass. Step 1 proves SHA256SUMS was produced by this repo’s release workflow; step 2 ties each .uf2 (and the SBOM) to it.

Verify the build is reproducible

The images are bit-for-bit reproducible per platform, per flake.lock, so you can rebuild them yourself and compare (no need to trust the published binary):

git checkout <tag>
nix build .#firmware              # the default flavor (others: .#firmware-fips, …)
sha256sum result/firmware.uf2     # compare against SHA256SUMS for rs-key-<tag>-default.uf2

A match on Linux reproduces the CI-built artifact exactly. (Cross-platform identity, macOS vs Linux, is not guaranteed; the canonical bytes are the Linux ones the workflow publishes.)