Why compare a provenance statement's subject digest against the bytes you installed?
answer
- signature versus relevance
- which artifact is this about?
- genuine statement, wrong file
- hash locally, match a subject
- names are metadata, digests are content
basics
~20 sA signature proves the statement is authentic, not that it describes your file. The subject digest is the only field tying a statement to specific bytes, so without hashing what you installed, a genuine statement about a different build still passes.
solid answer
~50 sThe signature and the subject digest answer different questions. The signature says the statement is authentic and came from an identity you recognise; the `subject` entry says *which artifact* the claims are about, as a `{name, digest}` pair. If a consumer verifies the signature, reads the builder and source out of the predicate, and never hashes the file it is actually going to install, then any authentic statement about any build from that producer satisfies the check. Picture a point-of-sale application pulling a payment library: the publisher's real provenance for release 4.2.0 travels alongside a package substituted somewhere on the distribution path. Every field a lazy verifier looks at is genuine. Only the hash disagrees, and only if someone computes it. So the rule is: hash the artifact you will run, require that hash to equal the digest of a subject in the statement, and match on the digest rather than on the name or version.
code
json · 14 lines{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "Acme.Payments.4.2.0.nupkg",
"digest": { "sha256": "9f2c...c41" }
}
],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildDefinition": { "...": "..." },
"runDetails": { "...": "..." }
}
}go deeper
Remember that verification includes hashing the file you downloaded and finding that hash in the statement's subject list. A green signature check on its own is not verification.
Explain that the signature establishes authenticity while the subject digest establishes relevance, and describe the failure where a genuine statement is replayed against a substituted artifact.
Show where in a real delivery path you would compute the hash, and be able to explain what repackaging, re-tagging or unpacking does to the binding you thought you had.
Be ready to argue how far down the path verification should reach, and what it costs to move the check closer to the moment of use across many teams.
## Two different claims in one document An in-toto statement has four parts: `_type` (the statement format), `subject` (a list of `{name, digest}` entries), `predicateType` (a URI naming the kind of claim) and `predicate` (the claim itself — for build provenance, the build definition and run details). The statement is carried in a signed envelope, and the signature is computed over the payload separately from the payload's own contents. That separation is exactly why the digest comparison matters. The signature answers **"is this document genuine?"**. The `subject` answers **"which artifact is this document about?"**. A verifier that only ever asks the first question has proven a document is genuine without ever establishing it is *relevant*. ## The failure in practice Consider a desktop point-of-sale application that takes a payment library from a public package feed. The publisher genuinely does the right things: hermetic-ish build, signed provenance, published alongside each release. The integrating team wires up verification and it goes green on every build. Now something on the distribution path serves a different package file under the same name and version — a compromised mirror, a poisoned cache, an internal proxy an insider can write to. The attacker does not need to forge anything: they reuse the publisher's real, correctly signed statement for 4.2.0 verbatim. What does the verifier see? - Signature: valid. Nothing was tampered with in the statement. - Builder identity: the publisher's real build system. Matches expectations. - Source repository and revision: the publisher's real repository at the real release commit. Matches. - Entry point: the publisher's real release build. Matches. - Subject digest: **does not match the bytes on disk** — and this is the only field that would have said so. If the team never hashed the installed file, every check it performed passed on a package the publisher never produced. The money moves through that library. ## Why name and version matching is not a substitute The `name` field in a subject is a convenience label. Names and version strings are metadata: they are chosen by whoever assembles the package and can be reproduced by anyone. A digest is content-addressed — it is derived from the bytes and cannot be reused for different bytes without breaking. Matching a statement to an artifact by name is the same class of mistake as trusting a mutable label instead of content; matching by digest is the fix. A practical consequence: when a statement lists **several subjects** — a build that emitted a binary, a container image and a checksum file, for example — the consumer must locate the subject whose *digest* equals its artifact's hash, not the one whose name looks familiar. "A subject with my name exists" is not the check. "A subject with my digest exists" is. ## Where the hash must be taken Over the bytes that will actually be used. If you download an archive, verify it, then unpack and rebuild something before shipping, the thing you verified is not the thing you run — the binding stops at the point where the bytes change. Verification is worth the most when it happens as close as possible to the moment of use, on the artifact in the form it will be used in, because everything between the check and the use is unverified path. ## How to talk about it The sentence an interviewer is listening for is roughly: *the signature makes the document trustworthy, the subject digest makes it relevant, and you need both.* Then name the failure mode concretely: a genuine attestation for a different artifact. Candidates who can describe that scenario have understood why provenance verification is a comparison and not a boolean returned by a signature library. ## Related traps - **"The registry told me the digest."** A digest reported by the same channel that delivered the artifact is not independent evidence; compute it yourself over the local file. - **"The statement was attached to the artifact, so it must describe it."** Attachment is a discovery convenience. Co-location is not a cryptographic binding — the digest is. - **"Verification passed, so the code is fine."** A matched digest proves the bytes are the ones the builder produced. It says nothing about what those bytes do.
- The statement lists three subjects. How do you decide which one applies to you?By digest, never by name. Hash the artifact you hold and require that hash to appear as the digest of some subject in the list. A build that emits several outputs legitimately lists them all; picking the entry whose name looks right and reading its digest as authoritative reverses the comparison and defeats the point.
- Why is matching on package name and version not enough?Names and versions are labels chosen by whoever assembled the package, and they can be reproduced for different bytes at will. A digest is derived from the content, so it cannot be reattached to other content. Matching on a label means an attacker who controls the file but not the statement still passes.
- You verified a downloaded archive, then repackaged it before deployment. What happened to the guarantee?It ended at the repackaging step. The digest bound the statement to the archive as downloaded; the artifact you deploy is different bytes that nothing has vouched for. Either verify as close to the point of use as possible, or produce and sign your own statement for the repackaged output so the chain continues.
saying these in an interview costs you the question
- Assumes a valid signature means the right artifact
- Matches the statement to the artifact by name and version
- Trusts a digest reported by the delivery channel itself
- Says co-locating the attestation with the file is the binding
- Thinks a matching digest also proves the code is safe