Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ct-verify

Independently verify a Consent Tree evidence pack.

The point of this program is that you do not have to trust Consent Tree.

It makes no network calls of any kind. It does not phone home, it does not fetch the signing key, and it does not ask any Consent Tree service whether a pack is good. Everything it concludes, it concludes from the bytes of the pack you hand it plus a public key you supply yourself.

It is one file, about 500 lines. Read it before you run it. That is not a formality — a verifier you have not read is just another party asking you to take its word for something.

Install

go install github.com/consentree/ct-verify@latest

Or build it yourself, which is the better habit:

git clone https://github.com/consentree/ct-verify
cd ct-verify
go build -o ct-verify .

Use

ct-verify --key <64-hex-public-key> pack.zip

# also check the link to the previous pack in the tenant's chain
ct-verify --key <64-hex> --prev previous-pack.zip pack.zip

# machine-readable
ct-verify --key <64-hex> --json pack.zip

The key

You need the public half of the Ed25519 key the pack was signed with. Consent Tree publishes it here:

SIGNING_KEYS.md, in this repository

Pin it from there — or better, from a copy you took yourself on a date you chose. The running platform will also serve you the key from its own API; treat that as a convenience for a first fetch, never as the authority. If the only place to obtain the key were an endpoint Consent Tree controls, they could serve a forged pack together with the key that verifies it, and your check would pass while proving nothing. A published git history, hosted by a third party, is harder to rewrite quietly.

The key's id is the first 8 hex characters of its SHA-256, so you can confirm the pairing yourself rather than taking it on faith:

printf '<64-hex-public-key>' | xxd -r -p | openssl dgst -sha256 | cut -c1-8

Every pack's manifest.json names the signing_key_id it was signed under. If that does not match your key, ct-verify says so specifically rather than failing with something vague.

What it checks

Check What it establishes
structure the pack contains a manifest, and no file name appears twice
manifest hash the hash that was signed, recomputed two independent ways
file integrity every listed file matches its SHA-256 and nothing unlisted is present
signature a real Ed25519 signature by the key you supplied
timestamp an external RFC 3161 authority saw this content by a given date
chain this pack links to the predecessor it claims

File integrity is checked in both directions on purpose. Confirming only that listed files match would let an extra, unlisted file ride along inside a pack that then reports as verified.

Exit codes

Code Meaning
0 everything that could be checked passed, and everything was checkable
1 at least one check failed
2 the pack or the arguments could not be read
3 nothing failed, but something could not be verified

Exit 3 is deliberate. "I could not check this" and "I checked this and it is wrong" are different facts, and collapsing them is how a verifier ends up reassuring someone it should not. Two common cases both land there:

  • You supplied no key. The signature is reported UNVERIFIED and the verdict is INCOMPLETE. It will not say VERIFIED about a signature it never checked.
  • The pack carries no timestamp token. Anchoring is best-effort in the producer, so an unreachable timestamping authority at generation time leaves the token out — and then nothing independently establishes when the pack was made.

What a clean result does and does not prove

It does prove that the pack's files are exactly the bytes that were signed, that nothing was added or removed, that the signature comes from the holder of the key you supplied, and — where a timestamp is present and verified — that an unrelated authority saw this content by a given date.

It does not prove that the underlying facts are true. A signed pack is a faithful record of what Consent Tree's systems reported. It is not an audit opinion, and Consent Tree does not issue one. It also says nothing about anything the pack does not contain, which is why every pack carries a disclosures.json — present even when there is nothing to disclose.

One implementation note, because it will otherwise look like a bug

The signature is not over the bytes of manifest.json as stored. That file is written indented for humans, while the hash that gets signed is computed over the compact JSON encoding of the same structure. A verifier that simply SHA-256s the file will conclude that every genuine pack is a forgery.

Because that is an interoperability trap rather than a security property, ct-verify computes the hash two independent ways and requires them to agree: by re-marshalling the parsed structure, and by stripping insignificant whitespace from the stored bytes. Those can only disagree if the stored manifest carries something the parsed structure loses — an unknown field, a duplicate key, a different field order — which is itself worth failing on.

Provenance

The canonical source lives alongside the pack producer in Consent Tree's backend repository, where a test builds packs with the real production signing code and runs this binary against them. That test also plants forgeries — edited content, a manifest rewritten to match, an unlisted file added, a listed file removed, a stripped signature, a wrong key, a spliced chain — and requires every one to be rejected. If producer and verifier ever drift apart, it fails there rather than in your terminal.

This repository is the published copy of that tool.

Licence

MIT. Fork it, audit it, rewrite it in another language. A second, independent implementation would be a genuinely good outcome — the claim being made here is checkable, and it should stay that way.

About

Independently verify a Consent Tree evidence pack. No network calls — checking our evidence should not require our cooperation.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages