Secure Binaries
fnc deliverables are verified by SHA256 checksum—and it is the SHA256 file that is signed. Working under the premise that SHA256 checksums cannot be forged, this signing process creates a chain of trust. To wit, if the signature matches, then the checksums must be the same checksums that were signed on the build box. And if the checksums match, then it follows that the tarball is the same set of files that were archived and hashed on said build machine.
The caveat is that to seed this chain of trust, initially, the public key must
be trusted; but how can you be sure that your copy of the key hasn't been
interdicted and used to sign a forged set of files, thus rendering you with a
verifiable, albeit ¬fnc
, tarball? The fact that just 56 base-64 encoded
characters constitute the key means that it is small and easily accessible. We
have, therefore, made it widely available in locations that have a very high
likelihood of being under our control—this website, the canonical fnc fossil
source code repository, and our own DNS server, for example—which facilitates
public key validation. Further, at any point in time, the current
public key—and the next for the following fnc release—are in the source tree,
having been committed to the repository's blockchain—a traceable and
unfalsifiable historical record. In addition, each signed deliverable is linked
via technote to its corresponding signed checksum. Such dissemination
increases the difficulty for threat agents to intercept public key retrievals,
and decreases the risk that any such attempt would go undetected, thus
mitigating this attack vector.
Signing Process
The following details how release tarballs of fnc's binaries,
documentation, and source code are signed and published, which is performed by
running the release.sh
script comprising the below steps. Although the
example demonstrates an OpenBSD release build, the process is identical on
macOS and Linux except for the use of OpenBSD's sha256
(1) counterparts:
gsha256sum --tag
and sha256sum --tag
on macOS and Linux, respectively. The
--tag
option is needed because signify
(1) expects BSD-style checksums.
The $uname
and $version
variables correspond, respectively, to the build
machine as reported by uname
(1) and the release being published.
- In the root of a clean fnc work tree, build the latest version with both
clang
(1) andgcc
(1) to confirm compilation is warning and error free:fossil update $version make clean CC="ccache egcc" make -j4 make clean CC="ccache clang" make -j4
strip
(1) the binary:strip src/fnc
- Create tarball of the binary and manual page:
mkdir fnc-$version && cp src/fnc{.1,} fnc-$version/ tar zcvf fnc$version-$uname.tar.gz fnc-$version
- Compute the SHA256 checksum of the tarball:
sha256 fnc$version-$uname.tar.gz > fnc$version-$uname.tar.gz.SHA256
- Sign checksum and write the signature to file:
signify -Ses $private_key -m fnc$version-$uname.tar.gz.SHA256
- Move the tarball and signature file to the repository's unversioned
downloadable content:
mv fnc$version-$uname.tar.gz* dl/
- Update and sync release artifacts:
fossil uv add dl/fnc$version-$uname* fossil uv sync -v
- Commit a technote with the signed checksum linked to the tarball:
fossil wiki create "signed checksum: [/uv/dl/fnc$version-$uname.tar.gz|fnc$version-$uname.tar.gz]" \ -M plain -t now --technote-tags $version fnc$version-$uname.tar.gz.SHA256.sig
◆ n.b. The release.sh
script is run on all supported platforms to produce
binary and source tarballs. In the latter case, however, steps 1–3 are replaced
with fossil update $version && make release
.