AEGISCONTROL

Verify an AEGIS artefact without running AEGIS

Every published release ships an independent verifier written in Rust — a second implementation that shares no code with AEGIS — with the specification corpus and a SHA256SUMS manifest. Checking a receipt, a SCITT capsule or an inclusion proof needs those and nothing else.

The repository is private. Release assets, including the verifier binary, are downloadable by people with read access; links into the repository return 404 for everyone else. That is a limit of the current distribution, not of the verification: nothing in it asks you to trust AEGIS. Publishing the verifier crate (deliberately unpublished so far) or the repository is the owner's decision, and the day either happens nothing on this page changes except who can click the links.

Latest release on GitHub · sha256sum --check SHA256SUMS · aegis-verify vectors canonical-vectors.json


aegis-control/.github/actions/verify

Check an AEGIS receipt, capsule or inclusion proof in your own CI, without running AEGIS and without trusting whoever gave you the artefact.

That last clause is the whole point. AEGIS signs what it does; this is the other side of the transaction. It runs a second implementation of the verification — a Rust binary that shares no code with AEGIS — over whatever you hand it.

What it checks

Inputs Question it answers
artifact + signature + keys Is this receipt genuinely signed by the key it names?
capsule + scitt-keys Is this SCITT capsule what it claims to be?
inclusion-proof Is this entry really in the log?

Before any of them, it replays the RFC 8785 canonicalisation corpus against the verifier itself. That matters more than it looks: a verifier that has drifted accepts things, and a clean pass from one would be worse than no check at all.

If you pass none of the three, the action fails. A step that checks nothing and reports green is how a verification gate quietly stops being one.

Checking a capsule

This is the one a holder outside the issuing organisation uses.

- uses: Oshinsu/aegis-control/.github/actions/verify@main
  with:
    release: v0.15.0
    capsule: ./receipt.cose
    scitt-keys: ./scitt-keys.cbor

where scitt-keys.cbor came from the issuer's own well-known endpoint:

curl -sfo scitt-keys.cbor https://aegis.example/.well-known/scitt-keys

Four things are checked, and each depends on the last having held:

  1. the bytes decode as a tagged COSE_Sign1, using coset and ciborium — third-party libraries, not the encoder that produced the envelope;
  2. the protected header carries what draft-mih-scitt-agent-action-capsule-02 §3.1 requires, and nothing outside its closed capsule_* claim set;
  3. the Ed25519 signature verifies over a Sig_structure the verifier rebuilds itself, rather than over anything the producer said it signed;
  4. capsule_id is the digest of the capsule that carries it, recomputed with an independent RFC 8785 implementation.

Prefer scitt-keys over capsule-key. Taking the key from the issuer's published key set is a different claim from taking it from the same party that handed you the capsule, and it is the stronger one. Passing both is refused: two sources for one key is a way to check against the wrong one and not notice.

Getting the verifier

Two ways, and they are not equivalent.

A pinned releaserelease: v0.15.0. The binary is downloaded and checked against the SHA256SUMS published beside it, so you do not have to trust the transport. Linux x86_64 only; on any other runner this fails rather than silently building instead, because a caller who asked for a pinned artefact should not be handed a compiled one without being told.

A build from source — the default. Three sources, in order of preference:

  1. a verifier/ directory already in your workspace (verifier-path, or detected automatically) — no network, no credentials;
  2. a clone of this repository — needs token while it stays private;
  3. cargo install aegis-verify — not yet; the crate is deliberately unpublished.

Building trusts whatever ref resolves to when the job runs. Pinning a release does not. Prefer the release.

The limitation worth stating

This repository is private. An action in a private repository can be used only from repositories that can read it, and cloning the verifier needs a token. So "anyone can check an AEGIS receipt" is not true today — what is true is that anyone with read access can, and that nothing about the checking depends on trusting AEGIS.

The path out is not more code here. It is publishing the verifier (verifier/Cargo.toml carries publish = false on purpose — that is the owner's decision, not a side effect of a build), or making the repository public. On the day either happens, nothing in this action changes.

Examples

Verify a signed receipt and its place in the log, from a workspace checkout:

- uses: actions/checkout@v5
- uses: ./.github/actions/verify
  with:
    artifact: ${{ runner.temp }}/receipt.json
    signature: ${{ runner.temp }}/receipt.sig.json
    keys: ${{ runner.temp }}/keys.json
    inclusion-proof: ${{ runner.temp }}/proof.json

From another repository, against a pinned release:

- uses: Oshinsu/aegis-control/.github/actions/verify@main
  with:
    release: v0.15.0
    token: ${{ secrets.AEGIS_READ_TOKEN }}
    artifact: ./receipt.json
    signature: ./receipt.sig.json
    keys: ./keys.json

What it does not do

It does not verify the signature over a tree head — that is a separate call with artifact, kept separate so a caller knows which of the two failed. It does not fetch anything from a transparency service; you fetch, it checks, and keeping those apart means the action never decides which URL to trust on your behalf. And it does not tell you whether a decision was right: it tells you the record of that decision is authentic and unaltered, which is a narrower claim and the only one cryptography can make.