Zum Hauptinhalt springen
Version: Next 🚧

Verifying your downloads

bits binaries run on your hosts with privileged visibility, and bitcollector produces the evidence you and your auditor rely on. Evidence is only ever as trustworthy as the instrument that produced it.

So before you install anything, you should be able to prove exactly which bytes you are about to run. This page shows you how, using published tools only, offline.

If any check fails

Do not install the binary. Do not "try the download again and hope". Keep the files, and email [email protected] with the release version and the failing command's output.

What ships with every release​

FileWhat it is
bitcollector-<os>-<arch>The binary itself
bitcollector-<os>-<arch>.sbom.jsonCycloneDX SBOM — everything inside that binary
bitcollector-<os>-<arch>.sigCosign signature bundle over those exact bytes
bitcollector-<os>-<arch>.attCosign attestation binding the SBOM to those exact bytes
SHA256SUMSChecksums of every file above
SHA256SUMS.sigCosign signature over SHA256SUMS
release-provenance.jsonCommit, Go toolchain and platforms the release was built from

bitscanner, bitenforcer and bitmapper releases have the same layout, with their own name in place of bitcollector. All four products are signed with the same release key, so one key check covers the whole family — and a key that changed between two of them would be a reason to stop, not to update your copy.

Step 0 — get the tools​

You need cosign v3 or newer, and sha256sum (part of coreutils; on macOS, shasum -a 256 or brew install coreutils).

cosign version

Step 1 — get the public key, and check it is the right key​

Download the release signing key beside the release directory, not into it:

# from the directory that CONTAINS your release directory
# DNS route — works from a CLI and inside CI. The HTTPS copy of this key is
# currently behind a bot challenge, so `curl` cannot fetch it; see the note below.
dig +short TXT _cosign-key.cert-ix.com | tr -d '"' | sed 's/.*key=//' \
| base64 -d | openssl pkey -pubin -inform DER -out cosign.pub
Put the key next to the release, not inside it

verify-release.sh treats every file inside a release directory as something that should be signed. Dropping cosign.pub in there makes it report an unaccounted-for file — which reads exactly like a tampered release, but is not one. Keep the key one level up. For the same reason, pass it by absolute path: the script changes into the release directory, so a relative --key cosign.pub stops resolving and the failure it prints is indistinguishable from a bad signature.

→ cosign.pub

Do not skip this. This is the check that makes the rest mean anything.

An attacker who can replace a binary on our website can replace the public key sitting next to it. Verification would then pass — against their key. You would run their binary and get a green tick.

A signature check is only worth the trust anchor behind it. Confirm the key fingerprint from a second, independent source before you trust it. That is the whole point of the next few lines, and it is the step most verification instructions leave out.

The fingerprint​

Compute the fingerprint of the key you downloaded:

# The robust form: SHA-256 of the DER-encoded public key.
# Independent of PEM whitespace, so copy-paste through a browser cannot change it.
openssl pkey -pubin -in cosign.pub -outform DER | sha256sum

It must be exactly:

552839f6b1b1eb0934557e1886326c7270584fa602fbf56f84754a98be3de822

If you would rather hash the file as-is:

sha256sum cosign.pub
# 150eacccc1bc26a83c746a1e441b0b0bdc8104c3ef07efd75c62deb5b069f914

That second value covers the exact bytes of the published file, newline included, so it only matches if you downloaded the file rather than pasting its contents.

The key itself is short enough to read. This is the whole of it:

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPA6gi66NIBXbSwYS3CL16Ien3sho
wCNOR8dRivdd07SQWto107QMDelUKMeebJQHSlOchNO4PJSWjCcrsUYb5w==
-----END PUBLIC KEY-----

It is an ECDSA P-256 (prime256v1) public key. You can confirm that yourself:

openssl pkey -pubin -in cosign.pub -text -noout | head -2
# Public-Key: (256 bit)

Second sources for the fingerprint​

Do not take the fingerprint from the same page that served you the key, if you can avoid it. Cross-check it against at least one of:

  • A DNS record, served by different infrastructure from this website. The same fingerprint is published as a TXT record at _cosign.cert-ix.com, and one command checks it: dig +short TXT _cosign.cert-ix.com. This is the cross-check worth doing, because an attacker who has taken over this web server would have to take over our DNS as well to make the two agree — different systems, different credentials. If they disagree, stop: do not run the binaries, and write to [email protected].
  • Your Cert-IX contact, out of band. Ask your account or security contact to read the fingerprint back to you over a channel that is not this website — a phone call, a signed email from [email protected], or your existing support channel.
  • A key you already have. If you verified a previous bits release, compare against the key you kept. A release key that changes without an announcement is a reason to stop and ask, not a reason to update your copy.

Once you have confirmed the fingerprint, keep your copy of the key and reuse it. The value of a trust anchor comes from it not changing.

Step 2 — verify the checksum manifest first​

Order matters. Verify the signature over SHA256SUMS before you trust any checksum inside it — an unsigned checksum file proves nothing, because whoever can replace a binary can replace a plain checksum list just as easily.

cosign verify-blob --key cosign.pub --bundle SHA256SUMS.sig \
--insecure-ignore-tlog=true SHA256SUMS

Expected output:

WARNING: Skipping tlog verification is an insecure practice that lacks transparency and
auditability verification for the blob.
Verified OK
That warning is expected — here is exactly what it means

Cert-IX is a sovereign EU platform and operates no public Sigstore transparency log. Signatures are key-based. Without --insecure-ignore-tlog=true, cosign v3 looks for a transparency-log entry that intentionally does not exist and reports "no signatures found".

The flag does not weaken the signature check itself. What it does mean is that you get no independent, append-only record that this signature ever existed — so the fingerprint cross-check in Step 1 is doing work that a transparency log would otherwise do for you. That is the trade, stated plainly.

Step 3 — verify every file matches its checksum​

sha256sum -c SHA256SUMS

Step 4 — verify the binary you are about to install​

cosign verify-blob --key cosign.pub --bundle bitcollector-linux-amd64.sig \
--insecure-ignore-tlog=true bitcollector-linux-amd64

Step 5 — verify the SBOM really describes these bytes​

cosign verify-blob-attestation --key cosign.pub --bundle bitcollector-linux-amd64.att \
--type cyclonedx --insecure-ignore-tlog=true bitcollector-linux-amd64

The SBOM is how you know what is inside the collector that will produce your evidence. A binary whose attestation does not match its bytes is a binary whose contents you cannot enumerate.

The whole thing in one command​

Cert-IX ships the same verification script it runs against its own releases before publishing, at ci/verify-release.sh in the repository:

./verify-release.sh "$PWD/bitcollector-release" "$PWD/cosign.pub"
[verify-release] verifying the signature over SHA256SUMS
[verify-release] SHA256SUMS signature OK
[verify-release] verifying checksums of every artefact
[verify-release] all checksums OK
[verify-release] bitcollector-darwin-amd64 signature OK
[verify-release] bitcollector-darwin-amd64 SBOM attestation OK
[verify-release] bitcollector-darwin-arm64 signature OK
[verify-release] bitcollector-darwin-arm64 SBOM attestation OK
[verify-release] bitcollector-linux-amd64 signature OK
[verify-release] bitcollector-linux-amd64 SBOM attestation OK
[verify-release] bitcollector-linux-arm64 signature OK
[verify-release] bitcollector-linux-arm64 SBOM attestation OK
[verify-release] bitcollector-windows-amd64.exe signature OK
[verify-release] bitcollector-windows-amd64.exe SBOM attestation OK
[verify-release] VERIFIED: 5 binary/binaries, checksums, and signatures all valid
[verify-release] built from commit 8819759 with go1.25.12
OK: 5 verified

Exit code 0 and a line reading OK: <n> verified means every binary is authentic and intact. Anything else means do not install.

Pass absolute paths

The script changes into the release directory before it starts work, so a relative path to the public key stops resolving and every signature check fails with:

[verify-release] REFUSED: the signature over SHA256SUMS is NOT valid for this key.

That refusal reads exactly like a tampered release. If you see it, re-run with absolute paths ("$PWD/cosign.pub") before you conclude anything — and if it still fails with an absolute path, then treat it as real and contact [email protected].

Two details worth noticing, because they are the difference between a check and a ritual:

  • It reports a count. A verification that finds nothing to check must not report success, so the script refuses when the directory holds no binaries, and it prints how many it actually verified.
  • It refuses on a missing signature. An unsigned binary sitting in a signed release is exactly what a supply-chain attack looks like, so the script fails rather than skipping it.

What the signature proves today​

Be precise about this, because "signed" is often heard as more than it is.

What it proves: these exact bytes were produced by the Cert-IX release pipeline and signed by the holder of the key whose fingerprint you checked in Step 1, and they have not changed since. Combined with SHA256SUMS and the SBOM attestation, you can enumerate what is inside the binary and be sure the enumeration matches the bytes.

What it does not prove, stated honestly:

  • The signing key currently lives on the build host, protected as a file with a passphrase held outside version control. It is not in a hardware security module. So the signature proves "this is the binary that build produced" — it does not prove that the build host itself was uncompromised at signing time.
  • There is no transparency log. You cannot consult an independent append-only record to see whether a signature for some other binary was ever issued under this key.

Both of those are why the reproducible build below matters, and why the fingerprint cross-check in Step 1 is not optional.

Rebuilding the binary yourself​

You do not have to take our word for what is in the binary — you can rebuild it and compare. bits releases are reproducible: the same commit, built with the same Go toolchain, produces byte-identical output.

Start from release-provenance.json, which records exactly what the release was built from:

{
"service": "bitcollector",
"version": "0.1.0-ga",
"commit": "8819759",
"go_toolchain": "go1.25.12",
"source_date_epoch": 1786277293,
"build_time": "2026-08-09T12:08:13Z",
"platforms": ["linux/amd64", "linux/arm64", "darwin/amd64", "darwin/arm64", "windows/amd64"],
"reproducible": true,
"signed": true
}

With the source and the toolchain named there:

git checkout <commit from release-provenance.json>

SOURCE_DATE_EPOCH=<source_date_epoch from release-provenance.json>
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath \
-ldflags="-s -w -buildid= \
-X main.version=<version> \
-X main.buildTime=$(date -u -d @$SOURCE_DATE_EPOCH +%Y-%m-%dT%H:%M:%SZ) \
-X main.gitCommit=<commit>" \
-o bitcollector-linux-amd64 ./cmd/bitcollector

sha256sum bitcollector-linux-amd64 # must equal the value in SHA256SUMS

A matching hash means the published binary contains nothing that is not in the source you just read.

Current releases​

All four bits are published, and all four are signed with the same key — the one whose fingerprint you checked in Step 1. One key check covers the family.

ProductVersionCommitToolchainPlatforms
bitcollector0.1.0-ga8819759go1.25.12linux amd64/arm64, macOS amd64/arm64, Windows amd64
bitscanner0.1.3-ga7db3d4cgo1.25.12linux amd64/arm64
bitenforcer0.1.0-ga4c6ce93go1.25.12linux amd64/arm64
bitmapper0.1.0-ga64ebc64go1.25.12linux amd64

The platform columns are not all the same, and the differences are deliberate. Where a platform is missing it is because the agent would not do its job there, not because the build was forgotten. Each product page gives the reason:

ProductWhat is withheld, and why
bitcollectorNothing. It ships on all five — platforms
bitscannerNo macOS/Windows: its neighbour and route readers are Linux implementations, and an empty neighbour table would read as a quiet segment — platforms
bitenforcerNo macOS/Windows: its whole surface is iptables/sysctl/systemd/SELinux, so a build there would report every module NOT EXAMINED — platforms
bitmapperLinux amd64 only: capture needs a compiled-in libpcap, so it cannot be cross-compiled. Windows builds but has never been run there, so it is withheld as a testing gap — platforms
Verify the version you actually downloaded

The commits above are what the current releases were built from. release-provenance.json inside your release directory is the authoritative record for that directory — check it against the table rather than assuming, and the binary itself prints the same values from the bytes you are about to run. If the three disagree, stop and write to [email protected].

The command is not the same on all four binaries. Use the one for the binary you have:

BinaryCommand that prints its version
bitcollectorbitcollector --version
bitscannerbitscanner version
bitenforcerbitenforcer version
bitmapperbitmapper version

Please use exactly these spellings, because the wrong one does not simply print an error:

  • On bitcollector up to and including 0.1.0-ga, bitcollector version is not a version command. The argument is ignored and the binary starts the agent — it creates its identity key under the data directory and begins collecting. If you ran it, stop the process and delete the data directory (/var/lib/bitcollector unless you changed it) before enrolling the host for real. bitcollector --version prints and exits, and always has.
  • On bitscanner, bitenforcer and bitmapper, --version is not a flag they have; the command fails with unknown flag: --version. That one is harmless, just unhelpful.

The binaries and their signing key are on the downloads page. The steps above work offline against whatever release directory you have, so you can verify on a machine that never touches our website.

Next steps​

  • bitcollector — what it collects, and how its evidence chain is verified (a different key, and a separate check).
  • bitenforcer — what v1 does and does not do.
  • bits overview — start here if you arrived at this page first.

War diese Seite hilfreich?