Evidence an auditor can verify
Every batch of telemetry bitcollector produces is signed on the host that produced it and
chained to the batch before it, and the host keeps a byte-identical copy. That is what lets
someone else β your auditor, not us β check the evidence offline, and be told exactly which
batch is wrong when one is.
This page covers the chain, how to verify a spool yourself, the one attacker it does not stop, and how long evidence stays on the host. For what the agent collects and how to run it, start at the bitcollector overview.
The evidence chainβ
This is the part that makes the data defensible rather than merely useful.
Every batch carries an ECDSA attestation over the whole envelope, hash-chained to the previous batch. A local spool on the host holds bytes byte-identical to what was POSTed to Cert-IX. So the copy you keep and the copy we received are the same bytes, and both are signed by a key that was generated on your host and never leaves it.
Your auditor verifies it without usβ
# 1. Export the trust anchor β the agent's enrolment PUBLIC key.
# --out must be OUTSIDE the data directory.
bitcollector export-pubkey --data-dir /var/lib/bitcollector --out /tmp/enrolment.pub.pem
# 2. Verify the spool. Pass the DIRECTORY, not a file list.
bitcollector verify --input /var/lib/bitcollector/attested --pubkey /tmp/enrolment.pub.pem
[VALID] batch 0 (batch-1785095415100718111, agent=e5efd43f-β¦, seq=0)
[VALID] batch 1 (batch-1785095418211672665, agent=e5efd43f-β¦, seq=1)
[VALID] batch 2 (batch-1785095466180395769, agent=e5efd43f-β¦, seq=2)
[VALID] batch 3 (batch-1785095515907595299, agent=e5efd43f-β¦, seq=3)
[CHAIN] intact
[RANGE] observed attested seq range [0,3]
SUMMARY: 4/4 batches valid β all checks passed
verify requires no network access and no Cert-IX access. Not "works offline as a
convenience" β it is the point. Evidence that can only be checked by asking the vendor who
produced it is not evidence. export-pubkey exists so the trust anchor itself comes off
your host rather than from us.
export-pubkey also prints the key's SHA-256 fingerprint. That is the same value each batch
carries as key_fingerprint, so the key file is bound to the evidence you hold. Verify with
the wrong key and every batch is reported [INVALID] with an explicit
key_fingerprint mismatch line β a mismatched trust anchor can never be confused with
tampered evidence.
A modified batch is caught and namedβ
Change a single byte of a spooled batch and re-run verify:
[INVALID] batch 4 (batch-1785095515907595299, agent=e5efd43f-β¦, seq=4)
- attestation verification failed: attest: payload_hash mismatch: attestation
claims 9f2cβ¦, canonical bytes hash to 4ab1β¦
Modification, deletion, reordering and duplication are all detected, and the exact seq is
named. Every line of every input file is accounted for in a census you can check against
wc -lc, so "reported batches + skipped lines" can never quietly describe a different file
than the one on disk.
Exit codesβ
verify exits with a stable code an audit pipeline can branch on:
| Code | Meaning |
|---|---|
0 | Everything checked out β authentic, unmodified, unbroken sequence. |
1 | At least one batch failed verification, or an input was refused. Treat as a finding, not a tooling error. |
2 | Every batch is individually authentic, but the sequence is wrong β one is missing, duplicated or out of order. |
3 | Nothing was verified β bad usage, no --pubkey, unreadable path, empty input. Fix the invocation; this is not a verdict about your evidence. |
Do not use a shell glob for a rotated spool. cat batches-*.ndjson | bitcollector verify
sorts lexicographically, so batches-10 comes before batches-7, and genuine, untampered
evidence is reported as a broken chain (exit 2). Pass the directory instead β
verify then reads the files in numeric order.
The honest limitβ
agent.key can forge a chainThe attestation key lives on the host, in the agent's data directory. It proves the batch was produced by that agent identity and has not been altered since. It does not protect against an attacker who has already achieved root on the host and can read the private key β such an attacker can sign a chain of their own choosing.
We state this rather than hide it. Closing it requires enrolment-time fingerprint escrow
off-host, which is not in this release. Protect agent.key accordingly: it is 0600 in a
0700 directory, and that is a boundary worth monitoring.
Local evidence retentionβ
The attested spool is your copy of the evidence. It lives under the agent data directory
(0700 directory, 0600 files):
spool:
enabled: true
path: attested
max_file_size_mb: 50 # rotation threshold, NOT a hard cap
max_files: 10
max_age_days: 30
max_files Γ max(max_file_size_mb, largest single batch) β not max_files Γ max_file_size_mb. A single batch larger than the threshold is written whole (evidence
completeness beats the size cap) and the file rotates immediately afterwards. Size the disk
for the largest batch a busy host can produce; the agent warns whenever it writes an
oversized one.
max_age_days is the storage-limitation bound the size caps cannot express (GDPR Art. 5(1)(e)):
with only max_files, a quiet host keeps evidence forever while a busy one keeps a couple of
hours of it.
Next stepsβ
- bitcollector overview β what it collects, and what it costs to run.
- Privacy and local accounts β the defaults that decide what ends up in the evidence in the first place.
- Verifying your downloads β the other verification: proving the binary that produced the evidence. A different key, and a separate check.
Was this page helpful?