· Xavier Goshi

What a verifier signing its own result proves

A checker that runs on your laptop, holds no key anyone has agreed to trust, and answers to nobody, can sign its own verdict all it likes. The signature proves that the checker said it. Nobody was disputing that.

Where this came up

Verifying a receipt produces two different things that are easy to confuse. One is a cryptographic finding: the signature verifies, or it does not, or it could not be evaluated. The other is what the party doing the checking decides to do about it: accept it, or refuse it under a policy of their own. The second is not a property of the evidence. It is a property of the reader.

Collapse the two and a specific failure follows. A relying party refuses a packet because its own policy requires an anchor the packet does not carry, records that as "verification failed", and passes that on. Downstream, someone reads "verification failed" and concludes the signature was bad. It was not. Nothing in the evidence changed between those two sentences; only the reader did.

The wrong fix

The obvious-looking remedy is to make the emitted result tamper-evident: sign it, so the verdict and the disposition travel together under one signature and cannot be separated. That was my first proposal, and it does not work for the case it was written for.

A standalone offline verifier has no identity that a third party has separately agreed to trust. It is a program the relying party downloaded and ran. Signing its output with a key it generated means: this program, which you are already running and already trusting to tell you the truth, asserts that it said what it said. The signature adds a step and no assurance. Where the relying party does have a separately trusted verifier identity, signing means something — but that is a property of the deployment, not of the checker, and a specification should not assume it.

The second problem is that "the disposition must not be separable by a consumer" is not enforceable. A consumer can read one field of a structured object and ignore the rest. Writing a requirement that no test can check puts a sentence in a specification that does nothing.

What the requirement should actually say

The obligation belongs on emission and on consumption, stated separately, because those are the two points where the distinction can be destroyed:

And the case that started it: when the checker cannot complete the check because it lacks the trust material to do so, that is not a fourth answer. It is the third verification result the profile already requires — not evaluated. Absence of material is not a failure of the material.

How ActaSeal implements it

The emitted result carries the verdict, the disposition, and a trust-material completeness field as one object. The verdict takes exactly three values: CRYPTOGRAPHICALLY_VALID, CRYPTOGRAPHICALLY_INVALID, NOT_EVALUATED. A policy refusal never appears in the verdict field at all, so a consumer reading only that field cannot mistake a refusal for a failed check. Completeness defaults to incomplete; absence is never resolved to complete, because silence about trust material is not evidence that it was sufficient.

What ActaSeal does not implement: the consumption-side obligation, which does not apply to something that only emits, and the integrity-protection clause, because no integrity protection is applied to the emitted result at all. Stating that is the point — an implementation status section that only lists what a project does is advertising.

Where the discussion is

This is being worked out in public, in the IETF SCITT working group, and the wording above is not mine alone — the emission-and-consumption shape came from another implementer correcting my version, and the third-result clarification came from the person who opened the issue.

All notes · actaseal.com