Files
fds-os/docs/releases.md
T
2026-09-21 22:29:23 +08:00

168 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Release signatures and verification
[Documentation index](README.md) · [M12 evidence](m12-validation.md)
`fds-release` signs an artifact manifest and verifies its signature and every
listed file. The static ARM executable is included in the base CLI package, so
CLI, development and recovery images can all verify downloads. The workstation
build supplies an x86_64 signer with the same format.
The signing tool has passed host, static ARM and independent OpenSSL acceptance.
The complete frozen-input, versioned local 0.1.0 release passed acceptance;
see [M12 validation](m12-validation.md#final-local-release-acceptance) for its identity
and [Offline rebuilds](reproducible-builds.md) for the workflow.
The examples below describe the working signing interface; they do not identify
a published or hardware-qualified FDS release.
## Build and test the tools
After [bootstrap](getting-started.md), run:
```sh
make signing
make signing-test
```
The workstation executable is
`target/x86_64-unknown-linux-gnu/release/fds-release`. The ARM executable is
`target/aarch64-unknown-linux-musl/release/fds-release`; `make tooling` also
exports it to `out/fds-release`. An ARM file cannot execute directly on the
x86_64 workstation. `make signing-test` runs that file through the project-local
QEMU interpreter as well as testing the host executable.
OpenSSL is a **host test dependency** used as an independent Ed25519
implementation. It is not linked into the FDS verifier. The test creates private
disposable keys under its `out/m12-signing.*` directory, checks exact signatures,
then exercises wrong keys, altered manifests, damaged or missing artifacts,
symlinks, FIFOs, malformed fields and unsafe paths. Test keys are not release
keys.
## Create and retain a signing key
For a local signing identity, choose an existing private directory outside the
checkout and its build output. This example creates a new directory; choose a
different name if it already exists:
```sh
mkdir -m 700 "$HOME/fds-signing"
target/x86_64-unknown-linux-gnu/release/fds-release keygen \
"$HOME/fds-signing/release-01"
```
The command creates `release-01.key` (32 secret bytes, mode 0600) and
`release-01.pub` (the hexadecimal public key). Existing files are never
overwritten. It prints SHA-256 of the decoded 32-byte public key, never the
secret. This fingerprint differs from `sha256sum release-01.pub`, which hashes
the hexadecimal text and its newline. Retain the private key separately from release downloads and source
archives. Anyone who has that key can sign a release under that identity.
If public-key export failed after private-key creation, retain the private file
and export it to a new path:
```sh
target/x86_64-unknown-linux-gnu/release/fds-release public-key \
"$HOME/fds-signing/release-01.key" "$HOME/fds-signing/recovered.pub"
```
Private keys must be regular files owned by the invoking user with no group or
other permissions. The tool rejects symlinks and invalid key lengths. Key
generation uses Linux `getrandom`; temporary seed storage and the signing key
are zeroized when dropped.
## Sign an assembled directory
An assembled release directory must already contain its artifacts and a
`manifest.json` matching the format below. Signing verifies every artifact's
length and hash before creating `manifest.sig`:
```sh
target/x86_64-unknown-linux-gnu/release/fds-release sign \
/path/to/release-directory --key "$HOME/fds-signing/release-01.key"
```
If a signature already exists, use a new release directory. The tool deliberately
does not replace signatures or silently rewrite the manifest. A failed operation
may leave its new output file for inspection; it never declares it verified.
## Verify before using images
Obtain the signer's public key through a channel you already trust, or compare
its fingerprint against a separately authenticated value. A public key included
beside an untrusted download does not establish its identity by itself.
On FDS, including recovery:
```sh
fds-release verify /data/downloads/fds-release --key /data/keys/fds-release.pub
```
On the workstation, use the host executable instead:
```sh
target/x86_64-unknown-linux-gnu/release/fds-release verify \
/path/to/release-directory --key /path/to/trusted-fds-release.pub
```
A successful command reports `VERIFIED FDS/OS 0.1.0`, the number of checked
artifacts, and `Hardware validation: deferred`. Failure returns exit status 2
and an explanation. Keep downloaded images unchanged between verification and
use. Verification covers only files listed in the manifest; unrelated extra
files are not endorsed. The [media writer](media-tools.md) performs its own
image/layout validation and readback checks when writing a cartridge.
These are distribution signatures. The Pi firmware and stage0 currently do not
enforce them at boot, so this is not a secure-boot implementation or a claim
that the hardware has been tested.
## Manifest and signature format
The JSON document has exactly these fields:
```json
{
"format": 1,
"version": "0.1.0",
"source_epoch": 1789909701,
"source_sha256": "<64 lowercase hexadecimal characters>",
"void_commit": "02a3cbc132c3c4a3a9d59e9b98f517af5dd11cd1",
"hardware_validation": "deferred",
"files": [
{
"name": "fds-system-cli-0.1.0.img",
"bytes": 123456,
"sha256": "<64 lowercase hexadecimal characters>"
}
]
}
```
This is a schema illustration, not a usable manifest: the size and hash
placeholders must be replaced with values from the actual artifact. Format 1
accepts the current tool version, a positive source epoch, a 40-character Void
commit, and 1–64 nonempty artifacts. Filenames must be flat safe ASCII names;
paths, duplicates, hidden names, reserved manifest filenames and unknown fields
are rejected. The manifest is bounded to 1 MiB. Files must be regular files,
opened without following symlinks; hashing streams their bytes and checks for
changes during the read.
The signature is Ed25519 over the exact bytes
`FDS/OS release manifest v1` followed by a NUL byte and the raw `manifest.json`
bytes. JSON whitespace is therefore authenticated too. `manifest.sig` contains
128 lowercase hexadecimal characters and a newline. The public-key file contains
64 lowercase hexadecimal characters and a newline. Verification rejects weak
public keys and uses strict signature verification.
The implementation uses locked `ed25519-dalek` 3.0.0 for Ed25519,
`zeroize` 1.9.0 for secret buffers, and the existing SHA-256/JSON crates.
Its locked transitive dependencies provide curve arithmetic, digest and
signature types. Default dalek features are disabled; no asynchronous runtime,
OpenSSL binding or shared target library is added. The dependencies and their
license metadata are recorded in `Cargo.lock` and the cached crate sources.
The build collects their license texts, including build dependencies and
vendored libusb notices, into `/usr/share/licenses/fds-cli/RUST-NOTICES.txt`.
The usage guide is installed at `/usr/share/doc/fds/releases.md` in every profile.
Algorithm interoperability is checked against the
[RFC 8032 test vector](https://www.rfc-editor.org/rfc/rfc8032.html#section-7.1)
and OpenSSL; strict verification follows the
[dalek API](https://docs.rs/ed25519-dalek/3.0.0/ed25519_dalek/struct.VerifyingKey.html).