Checking a download
Every release is signed with the owner's update key, and every file a release names carries its size and its sha256 in the release's signed manifest. A farm's gateway checks all of this by itself, every time, before it installs anything — the index's signature, then the manifest's, then each file's size and sha256 before the file is opened. You never have to do any of it. This page is for when you want to anyway.
The two public keys
Both are minisign (Ed25519) public keys, and both are trusted. The active key signs releases today; the standby key is there for a rotation, and a signature it made is as good as one the active key made. Each line is the key's role, its id, and the key itself — the key is what minisign -P takes.
active DD364E0F9D121FFEactive DD364E0F9D121FFE RWT+HxKdD0423VAY/wmWcH/dvTrWnHtKwmF9OqqYJg99paXSojCmvW3vstandby 9B39867E55AAA26Fstandby 9B39867E55AAA26F RWRvoqpVfoY5m/v7/9zPXc+ryHGRtfSNLbiL8VT0lotalxs2+DJv3K5M
What the commands below are about
- Component
- farm
- Version
- 1.1.0
That is an example, because this address named no release. A release's own page links here with the release and the file filled in, and then every command below is exact, down to the file name. You can also write it yourself: /verify/?c=farm&v=1.1.0&file=farm-gateway-linux-amd64.
Windows
Get minisign
scoop install minisign Or download a Windows build from https://github.com/jedisct1/minisign/releases — typed out rather than linked, because this site loads nothing from anyone else.
1. Download the release's manifest and its signature
Invoke-WebRequest -UseBasicParsing 'https://releases.thefairm.fr/farm/1.1.0/release.json' -OutFile 'release.json'; Invoke-WebRequest -UseBasicParsing 'https://releases.thefairm.fr/farm/1.1.0/release.json.minisig' -OutFile 'release.json.minisig'2. Check the manifest's signature
minisign -Vm release.json -P 'RWT+HxKdD0423VAY/wmWcH/dvTrWnHtKwmF9OqqYJg99paXSojCmvW3v' That must say Signature and comment signature verified, and the trusted comment it prints must read exactly:
component=farm version=1.1.0 file=release.json
Read that line. The signature alone only says the file was signed by the owner; the trusted comment is what says it was signed as this file, of this version, of this component — so a good signature cannot be moved from one release to another.
If the active key fails, try the standby key before concluding anything — a rotation means today's releases are signed by the other one:
minisign -Vm release.json -P 'RWRvoqpVfoY5m/v7/9zPXc+ryHGRtfSNLbiL8VT0lotalxs2+DJv3K5M'If both fail, stop: do not open the files. Nothing the owner published is in front of you.
3. Check the file's sha256 against the manifest
The manifest is signed and now checked, so the sha256 it gives for a file is the owner's. Download the file:
Invoke-WebRequest -UseBasicParsing 'https://releases.thefairm.fr/farm/1.1.0/farm-gateway-windows-amd64.exe' -OutFile 'farm-gateway-windows-amd64.exe' Then this one line prints match or MISMATCH. It hashes the file you downloaded and compares it with the sha256 the manifest gives for that artifact, by name:
if ((Get-FileHash -Algorithm SHA256 'farm-gateway-windows-amd64.exe').Hash -eq ((Get-Content -Raw release.json | ConvertFrom-Json).artifacts | Where-Object { $_.name -eq 'farm-gateway-windows-amd64.exe' }).sha256) { 'match' } else { 'MISMATCH' }The manifest is read as JSON rather than searched as text, because the feed's contract promises its fields and promises nothing about how it is spaced. Whatever reads it looks up one string; it verifies nothing.
The same for the index
index.json is the signed list of a component's releases — it is what says which versions exist, and your farm refuses one that is expired or older than the last it accepted. Its signature is checked the same way:
Invoke-WebRequest -UseBasicParsing 'https://releases.thefairm.fr/farm/index.json' -OutFile 'index.json'; Invoke-WebRequest -UseBasicParsing 'https://releases.thefairm.fr/farm/index.json.minisig' -OutFile 'index.json.minisig'minisign -Vm index.json -P 'RWT+HxKdD0423VAY/wmWcH/dvTrWnHtKwmF9OqqYJg99paXSojCmvW3v' The trusted comment reads version=index, not a version number:
component=farm version=index file=index.json
The standby key is minisign -Vm index.json -P 'RWRvoqpVfoY5m/v7/9zPXc+ryHGRtfSNLbiL8VT0lotalxs2+DJv3K5M'. There is no sha256 step for the index: nothing published carries a hash of it, so its signature is the whole of its authenticity.
macOS
Get minisign
brew install minisign1. Download the release's manifest and its signature
curl -fsSL 'https://releases.thefairm.fr/farm/1.1.0/release.json' -o 'release.json' && curl -fsSL 'https://releases.thefairm.fr/farm/1.1.0/release.json.minisig' -o 'release.json.minisig'2. Check the manifest's signature
minisign -Vm release.json -P 'RWT+HxKdD0423VAY/wmWcH/dvTrWnHtKwmF9OqqYJg99paXSojCmvW3v' That must say Signature and comment signature verified, and the trusted comment it prints must read exactly:
component=farm version=1.1.0 file=release.json
Read that line. The signature alone only says the file was signed by the owner; the trusted comment is what says it was signed as this file, of this version, of this component — so a good signature cannot be moved from one release to another.
If the active key fails, try the standby key before concluding anything — a rotation means today's releases are signed by the other one:
minisign -Vm release.json -P 'RWRvoqpVfoY5m/v7/9zPXc+ryHGRtfSNLbiL8VT0lotalxs2+DJv3K5M'If both fail, stop: do not open the files. Nothing the owner published is in front of you.
3. Check the file's sha256 against the manifest
The manifest is signed and now checked, so the sha256 it gives for a file is the owner's. Download the file:
curl -fsSL 'https://releases.thefairm.fr/farm/1.1.0/farm-gateway-darwin-universal' -o 'farm-gateway-darwin-universal' Then this one line prints match or MISMATCH. It hashes the file you downloaded and compares it with the sha256 the manifest gives for that artifact, by name:
test "$(shasum -a 256 'farm-gateway-darwin-universal' | cut -d' ' -f1)" = "$(python3 -c 'import json,sys;print(next(a["sha256"] for a in json.load(open("release.json"))["artifacts"] if a["name"]==sys.argv[1]))' 'farm-gateway-darwin-universal')" && echo match || echo MISMATCHThe manifest is read as JSON rather than searched as text, because the feed's contract promises its fields and promises nothing about how it is spaced. Whatever reads it looks up one string; it verifies nothing.
The same for the index
index.json is the signed list of a component's releases — it is what says which versions exist, and your farm refuses one that is expired or older than the last it accepted. Its signature is checked the same way:
curl -fsSL 'https://releases.thefairm.fr/farm/index.json' -o 'index.json' && curl -fsSL 'https://releases.thefairm.fr/farm/index.json.minisig' -o 'index.json.minisig'minisign -Vm index.json -P 'RWT+HxKdD0423VAY/wmWcH/dvTrWnHtKwmF9OqqYJg99paXSojCmvW3v' The trusted comment reads version=index, not a version number:
component=farm version=index file=index.json
The standby key is minisign -Vm index.json -P 'RWRvoqpVfoY5m/v7/9zPXc+ryHGRtfSNLbiL8VT0lotalxs2+DJv3K5M'. There is no sha256 step for the index: nothing published carries a hash of it, so its signature is the whole of its authenticity.
Linux
Get minisign
sudo apt install minisign1. Download the release's manifest and its signature
curl -fsSL 'https://releases.thefairm.fr/farm/1.1.0/release.json' -o 'release.json' && curl -fsSL 'https://releases.thefairm.fr/farm/1.1.0/release.json.minisig' -o 'release.json.minisig'2. Check the manifest's signature
minisign -Vm release.json -P 'RWT+HxKdD0423VAY/wmWcH/dvTrWnHtKwmF9OqqYJg99paXSojCmvW3v' That must say Signature and comment signature verified, and the trusted comment it prints must read exactly:
component=farm version=1.1.0 file=release.json
Read that line. The signature alone only says the file was signed by the owner; the trusted comment is what says it was signed as this file, of this version, of this component — so a good signature cannot be moved from one release to another.
If the active key fails, try the standby key before concluding anything — a rotation means today's releases are signed by the other one:
minisign -Vm release.json -P 'RWRvoqpVfoY5m/v7/9zPXc+ryHGRtfSNLbiL8VT0lotalxs2+DJv3K5M'If both fail, stop: do not open the files. Nothing the owner published is in front of you.
3. Check the file's sha256 against the manifest
The manifest is signed and now checked, so the sha256 it gives for a file is the owner's. Download the file:
curl -fsSL 'https://releases.thefairm.fr/farm/1.1.0/farm-gateway-linux-amd64' -o 'farm-gateway-linux-amd64' Then this one line prints match or MISMATCH. It hashes the file you downloaded and compares it with the sha256 the manifest gives for that artifact, by name:
test "$(sha256sum 'farm-gateway-linux-amd64' | cut -d' ' -f1)" = "$(python3 -c 'import json,sys;print(next(a["sha256"] for a in json.load(open("release.json"))["artifacts"] if a["name"]==sys.argv[1]))' 'farm-gateway-linux-amd64')" && echo match || echo MISMATCHThe manifest is read as JSON rather than searched as text, because the feed's contract promises its fields and promises nothing about how it is spaced. Whatever reads it looks up one string; it verifies nothing.
The same for the index
index.json is the signed list of a component's releases — it is what says which versions exist, and your farm refuses one that is expired or older than the last it accepted. Its signature is checked the same way:
curl -fsSL 'https://releases.thefairm.fr/farm/index.json' -o 'index.json' && curl -fsSL 'https://releases.thefairm.fr/farm/index.json.minisig' -o 'index.json.minisig'minisign -Vm index.json -P 'RWT+HxKdD0423VAY/wmWcH/dvTrWnHtKwmF9OqqYJg99paXSojCmvW3v' The trusted comment reads version=index, not a version number:
component=farm version=index file=index.json
The standby key is minisign -Vm index.json -P 'RWRvoqpVfoY5m/v7/9zPXc+ryHGRtfSNLbiL8VT0lotalxs2+DJv3K5M'. There is no sha256 step for the index: nothing published carries a hash of it, so its signature is the whole of its authenticity.