Some checks failed
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 7s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 18s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Failing after 1m2s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 2m23s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 3m34s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Failing after 5m9s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 5m7s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 5m20s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 7m46s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 8m20s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (push) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Has been cancelled
wai-app and Create / wai-app · does this change touch it (push) Has been cancelled
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Has been cancelled
wai-audit collector and player integration / does this change touch it (push) Has been cancelled
wai-audit collector and player integration / collector · linux (push) Has been cancelled
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Has been cancelled
WAI operation catalogue / does this change touch it (push) Has been cancelled
WAI operation catalogue / the catalogue and every door · linux (push) Has been cancelled
wai-fleet service / does this change touch it (push) Has been cancelled
wai-fleet service / service · linux (push) Has been cancelled
wai-fleet service / service · macos (push) Has been cancelled
wai-ledger service / does this change touch it (push) Has been cancelled
wai-ledger service / service · linux (push) Has been cancelled
wai-ledger service / service · macos (push) Has been cancelled
wai-quantum for JavaScript / does this change touch it (push) Has been cancelled
wai-quantum for JavaScript / javascript · linux (push) Has been cancelled
wai-quantum studio and desktop / does this change touch it (push) Has been cancelled
wai-quantum studio and desktop / studio · browser (push) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (push) Has been cancelled
wai-quantum studio and desktop / desktop app · linux (push) Has been cancelled
wai-quantum studio and desktop / desktop app · windows (push) Has been cancelled
wai-sink-android native sink library / does this change touch it (push) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Has been cancelled
wai-sink-swift native sink package / does this change touch it (push) Has been cancelled
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Has been cancelled
WAI Studio / does this change touch it (push) Has been cancelled
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
wai-key-proxy / does this change touch it (push) Has been cancelled
wai-key-proxy / proxy · linux (push) Has been cancelled
A .wai file can now be a C2PA asset without changing an envelope byte. extensions/c2pa-binding.md registers the record `wai.asset.c2pa`: a C2PA Manifest Store served beside the object at <cid>.c2pa (application/c2pa, C2PA 2.4 §11.4 and §15.5.3.1; an object's response may name it with Link rel="c2pa-manifest", §15.5.3.2), never inside it, so the object's content hash, its receipts and its head proof stay as they were. http-delivery §8.9 gives the location. The store is live provenance's profile (JUMBF layout, claim, EdDSA COSE claim signature, X.509 chain) with three assertions: c2pa.hash.data over every byte of the envelope with no exclusions and an empty pad (§18.5); c2pa.actions.v2 with the source type the signer states; and science.transaction.wai.envelope, which names the envelope's content hash, its capabilities (a WAI2's in table order) and the JWP group receipt it was delivered under, by link hash (also the name of its rcpt/ file), with that receipt's publisher key. The receipt must be in the labelled payload, whose link hash covers its parent. The manifest identifier is derived from the envelope, the receipt and the claim signer's certificate. A verifier checks the claim and chain (live-provenance §11.2 steps 1-6), the assertions, the identifier, the data hash, the content hash and capabilities, the receipt's link hash, signature and publisher, and the envelope's object receipt under it: seventeen reasons, each with its C2PA §15 code where C2PA gives one. The reference is the c2pa_envelope module of wai-rs (feature c2pa_envelope; writer c2pa_envelope::sign); the corpus is live-conformance/c2pa-envelope/ (stores bound to a WAI1 and to a WAI2 of one picture at two sizes, 27 negatives covering every reason), written from fixed seeds by wai_c2pa_envelope_vectors; c2pa_live_verify.py, the second implementation, now also verifies it: 29 vectors agree, 26 of 26 mutated copies are refused and 17 of 17 weakened verifiers are caught. Fourteen faults planted in the reference (each check of the verification skipped in turn, a legacy receipt, bytes after the envelope, a padded data hash, the identifier without its signer) each fail its tests. The C2PA Rust library (c2pa 0.91.7) reads both good stores beside their envelopes as Trusted with assertion.dataHash.match, and reports assertion.dataHash.mismatch when one envelope byte changes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
63 lines
4.1 KiB
Markdown
63 lines
4.1 KiB
Markdown
# live-conformance/c2pa-envelope — the C2PA binding of a stored envelope
|
|
|
|
The corpus of [`extensions/c2pa-binding.md`](../../extensions/c2pa-binding.md) §9: C2PA Manifest
|
|
Stores beside stored WAI envelopes, each with the JWP group receipt and object receipt its
|
|
verifier is given; the trust anchor every vector is verified under; and what a verifier states of
|
|
each.
|
|
|
|
**Files.** `vectors.json` lists the vectors, each its `name`, `envelope`, `store` (or `null`, a
|
|
store not served), `receipts` (a JSON file of `group`, the group receipt the verifier was given
|
|
for the store's `receipt`, and `object`, the envelope's object receipt, each in jwp-receipts
|
|
§2.4's JSON form or `null`) and `expect`. The good envelopes, their stores and their receipts sit
|
|
as an origin serves them: `objects/<cid>.wai` and, beside it, `objects/<cid>.c2pa` (§5.1). A file
|
|
whose bytes another vector already wrote is named by that vector's path, so a negative holds only
|
|
the files it changed. `anchor.der` is the trust anchor for `c2pa-kp-claimSigning`, and `time` the
|
|
instant *T* (§6.1).
|
|
|
|
**Equivalence.** A conforming verifier given a vector's files, the anchor and *T* reaches the
|
|
outcome `expect` states (§6):
|
|
|
|
- `refuse`: the `reason` of §7 and the C2PA 2.4 §15 code §7 gives it, `c2pa`, `null` where §7
|
|
gives none;
|
|
- `accept`: what §6.3 states: the envelope's `form`, `contentHash` and `capabilities`, the
|
|
`manifestId`, the `sourceType`, the `signer` (the SHA-256 of the claim signer's end-entity
|
|
certificate), the group receipt's link hash (`receipt`) and publisher key (`publisher`), its
|
|
`trackAlias` and `groupId`, and the object receipt's `objectId`, hashes in lowercase
|
|
hexadecimal.
|
|
|
|
**The vectors.**
|
|
|
|
- Good: `wai1-bound`, a store bound to a `WAI1` of one `wai.image.png`, and `wai2-bound`, a store
|
|
bound to a `WAI2` of the same picture at two sizes, each entry with its `id` and `sha256`. Both
|
|
envelopes are objects 0 and 1 of one group receipt in the labelled payload, unmetered.
|
|
- One negative for each reason of §7, and for some reasons more than one; each name says its
|
|
defect.
|
|
|
|
**Provenance.** `wai_c2pa_envelope_vectors gen` writes every file but this one from fixed seeds:
|
|
every key is SHA-256 of a label and no key is one anyone holds; the certificates are issued under
|
|
the corpus's own test anchor; the pictures are gradients the generator draws, written as PNG by
|
|
the packaging corpus's still writer, so each store states the source type `algorithmicMedia`.
|
|
|
|
**Checked by.** `wai_c2pa_envelope_vectors verify` and `tests/c2pa_envelope.rs` in `wai-rs`
|
|
(every file regenerates byte for byte and no other is here; every vector gets its outcome; every
|
|
reason refuses one; §7 lists the reference's codes), and `../c2pa_live_verify.py`, the second
|
|
implementation, written from the extension's text, which also requires every mutated copy of a
|
|
good vector to be refused and every one of its own checks, dropped, to be caught by the corpus.
|
|
|
|
**An independent C2PA validator.** The good vectors' stores were also read with the C2PA Rust
|
|
library (the `c2pa` crate, version 0.91.7, which shares no code with this corpus's reference) on
|
|
2026-11-09, each handed to it as a sidecar with its envelope
|
|
(`Reader::with_manifest_data_and_stream`, the envelope's format given as
|
|
`application/octet-stream`), with `anchor.der` its trust anchor and `c2pa-kp-claimSigning` and
|
|
`id-kp-documentSigning` its accepted extended key usages:
|
|
|
|
- both stores validate against their envelopes, state `Trusted`, with `signingCredential.trusted`,
|
|
`claimSignature.validated`, `claimSignature.insideValidity`, `assertion.hashedURI.match` for
|
|
each of the three assertions, and `assertion.dataHash.match`; the store, the claim, its
|
|
signature, the certificate chain and the data hash over the whole envelope are therefore read
|
|
the same way by an implementation that shares nothing with this one;
|
|
- with one byte of either envelope changed, the library reports `assertion.dataHash.mismatch`,
|
|
the code §7 gives `hard_binding_mismatch`, and the state `Invalid`.
|
|
|
|
The library does not read the WAI assertion or the receipts, which the two implementations
|
|
above check.
|