fnc

Verified Builds
Login

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.

  1. In the root of a clean fnc work tree, build the latest version with both clang(1) and gcc(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
    
  2. strip(1) the binary:
    strip src/fnc
    
  3. 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
    
  4. Compute the SHA256 checksum of the tarball:
    sha256 fnc$version-$uname.tar.gz > fnc$version-$uname.tar.gz.SHA256
    
  5. Sign checksum and write the signature to file:
    signify -Ses $private_key -m fnc$version-$uname.tar.gz.SHA256
    
  6. Move the tarball and signature file to the repository's unversioned downloadable content:
    mv fnc$version-$uname.tar.gz* dl/
    
  7. Update and sync release artifacts:
    fossil uv add dl/fnc$version-$uname*
    fossil uv sync -v
    
  8. 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.