open-standards/wai/live-conformance/c2pa-live/README.md

83 lines
5.9 KiB
Markdown

# live-conformance/c2pa-live — live provenance
The corpus of [`extensions/live-provenance.md`](../../extensions/live-provenance.md) §13: C2PA
2.4 §19 live video streams, each an initialization segment and its segments in the order a
verifier receives them, with, for a room track, the JWP group and object receipts of its
groups; the trust anchor every vector is verified under; and what a verifier states of each.
**Files.** `vectors.json` lists the vectors, each its `name`, `kind` (`track` or `take`),
`init`, `segments` (each a `file` and, for a track, the `group` it came in), `receipts` (a JSON
file of `groups` and `objects` in jwp-receipts §2.4's forms, or `null` for a take) and
`expect`. A file whose bytes another vector already wrote is named by that vector's path, so a
negative that changes one segment holds one file of its own. `anchor.der` is the trust anchor
for `c2pa-kp-claimSigning`, and `time` the instant *T* (§11.1).
**Equivalence.** A conforming verifier given a vector's files, the anchor and *T* reaches the
outcome `expect` states (§11):
- `refuse`: the `reason` of §12, `at` (`init`, `segment k` counting received segments from 0,
or `group g`), and the two C2PA codes §12 gives the reason, `c2pa` (§15's) and `livevideo`
(§19.7's), each `null` where §12 gives none;
- `accept`: the `streamId`, the `sourceType`, the `registration` (the `repository`, the
`treeSize` and the `leafIndex` of the receipt of inclusion) or `null`, and for each segment
(§11.6) its
`sequenceNumber`, its `group` (a track) or `chunk` (a take), its `methods` (`manifest`,
`vsi` or `manifest+vsi`), the active `manifestId`, its number of `chunks`, and its group's
`root` or its take chunk's `chunkHash`, in lowercase hexadecimal.
**The vectors.**
- Good: `camera-manifests` (the per-segment method), `camera-vsi` (the Verifiable Segment
Info method from group 10, the session key rotated at the third segment by a manifest in
it, the receipts' chain restarting under the new key), `avatar-manifests` (a track labelled
machine-made, with its AI disclosure), `composite-manifests` (a compositor's output of the
camera and the avatar: `compositeSynthetic` and the avatar's disclosure), `take-both` (a
take under both methods at once, the device's key as its session key), `camera-failover`
(the camera track, a second packager under its own claim signer taking over at the third
segment, the continuity chain holding across it because the identifiers are derived) and
`camera-registered` (the camera track's initialization segment with its update manifest
and repository receipt; `repositories` in `vectors.json` names the repository and its key).
- One negative for each reason of §12, and for some reasons more than one; each name says its
defect.
**Provenance.** `wai_live_provenance_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 media are the AV1 floor of
`pack-conformance/packs/video-base-01`, its samples cut into chunks of at most 15 frames, each
group one of the floor's pieces, renumbered and retimed across the stream.
**Checked by.** `wai_live_provenance_vectors verify` and `tests/live_provenance.rs` in
`wai-rs` (every file regenerates byte for byte and no other is here; every vector gets its
outcome; every reason refuses one; §12 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.
**An independent C2PA validator.** The corpus's files were also read with the C2PA
command-line tool, version 0.27.22, given `anchor.der` as its trust anchor, on 2026-10-21:
- every good vector's initialization segment validates: state `Trusted`, with
`assertion.bmffHash.match`, `assertion.hashedURI.match`, `claimSignature.validated`,
`claimSignature.insideValidity` and `signingCredential.trusted`. The manifest store, the
claim, its signature, the certificate chain and the BMFF hash over the `moov` are therefore
read the same way by an implementation that shares nothing with this one;
- `camera-registered/init.mp4` validates too, state `Trusted`, its active manifest the update
manifest: the tool reads the ingredient (`ingredient.manifest.validated`) and its validation
results. Before the ingredient carried them it reported `assertion.ingredient.malformed`,
which C2PA 2.4 §18.16.12.4.3 requires; `update-ingredient/init.mp4` is reported
`ingredient.manifest.mismatch`, where this corpus states `update_manifest_invalid`;
`repository-receipt-forged/init.mp4` is reported `Trusted`: the receipt's proof is the
repository's form (§18.27), which the tool does not check;
- `cert-untrusted/init.mp4` is reported `signingCredential.untrusted`, as here;
- `cert-expired/init.mp4` is reported `signingCredential.expired`, a code C2PA 2.4 does not
list; §15.8 names this failure `claimSignature.outsideValidity`, which this corpus states;
- `cert-wrong-eku/init.mp4`, whose end entity is valid for `id-kp-timeStamping` alone, is
reported `Trusted`: the tool's default list of accepted extended key usages includes
time-stamping and OCSP signing. C2PA 2.4 §14.5.1.1 makes a certificate valid for either of
those purposes valid for no other, and §14.5.1.2 requires a claim signer's to hold an EKU of
the validator's configuration, so this corpus refuses it `credential_invalid`;
- the tool reads no media segment: a file that does not begin with `ftyp` is not one it
opens, so it does not verify §19 per-segment manifests, segment-info maps or session keys.
The segments are checked by the two implementations above alone.
The tool reports a claim signature as failed when the end-entity certificate's subject holds
no organization name, which C2PA does not require; the corpus's names all hold one (§4.4).