Skip to content

Verifying evidence

The evidence pack is one self-contained JSON file: records, checkpoints, keys, anchors. obsign verify checks it with no network: the auditor builds the verifier from source and runs it on a machine of their choosing.

Terminal window
cargo run -p obsign-audit-core --example gen_sample -- /tmp/sample
cargo run -p obsign -- verify /tmp/sample/evidence.json \
--trusted-keys /tmp/sample/trusted-keys.json

Tamper with the result and re-run:

Terminal window
sed -i '' 's/"outcome": "deny"/"outcome": "allow"/' /tmp/sample/evidence.json
cargo run -p obsign -- verify /tmp/sample/evidence.json \
--trusted-keys /tmp/sample/trusted-keys.json # exit 1
CodeMeaning
0Proven — verified against keys obtained outside the pack
1Tampered — a record, checkpoint or anchor fails verification
2Execution error
3Consistent but unproven — checked only against the keys the pack itself carries

Exit 3 deserves the emphasis: without --trusted-keys, verification establishes internal consistency only, and the report says so explicitly. A forged pack signed with a made-up key validates itself, so key anchoring has to come from another channel. Exit 0 is reserved for verification against external keys. In a scheduled job, treat exit 3 as a misconfiguration (the trusted-keys file did not reach the verifier), never as a pass.

  1. No record removed, inserted or modified — hash chain, contiguous seq.
  2. No wholesale rewrite — the hash chain alone is not enough: whoever holds the database can recompute everything. The checkpoints, signed with a key outside the writing process (KMS/HSM), close that hole.
  3. No seal spirited away — checkpoints are chained to each other.
  4. What is not proven is said to be so — a record that is consistent but covered by no valid checkpoint is reported, not passed over in silence.

When a checkpoint carries an RFC 3161 anchor, obsign verify re-checks it structurally and reports it. The CMS signature of the timestamp token itself is validated against the TSA certificate with standard tooling (openssl ts -verify), and the report says so instead of passing a structural check off as a cryptographic one.

The auditor’s binary builds from ~31 crates, nearly all of it the cryptography itself (curve25519-dalek, sha2 and their arithmetic support). Argument parsing is hand-rolled; no web framework, no async runtime, no TLS stack. The dependency tree is part of the product: it is what an auditor must read before trusting the verdict.