c2pa: an assertion to add to the output’s
C2PA manifest before you deliver it. It carries the signed
receipt, so anyone who reads the manifest can verify the license decision without asking you.
You stay the C2PA claim signer for your own output. The receipt inside the assertion is signed by
Reflections, so it verifies independently of your signature.
Bind the receipt to your signer
A receipt is public, so anyone can copy the assertion into a manifest for other content. To stop that, sendc2pa_signer when you create the generation:
thumbprint is sha256: and the lowercase hex SHA-256 of the DER encoding of the end-entity
certificate that will sign the output’s C2PA claim. Reflections signs it as tlp.c2pa_signer as
given, without checking it against a certificate. A verifier that reads the manifest compares it
with the certificate that signed the manifest and can reject a mismatch; a mismatch can also mean
a rotated or misdeclared certificate. Without
it, the assertion proves a decision was made, not that this file is the one decided
(TLP-RCP-16). Rotate the certificate only for
outputs submitted after the change: the thumbprint is fixed in each receipt.
The assertion
ai.reflections.license is an entity-specific assertion label, in the reverse-domain form C2PA
uses for assertions outside its own c2pa. namespace. Copy c2pa from the generation as it is:
put label in the assertion’s label and data in its data. Your C2PA library encodes data as
CBOR when it writes the manifest.
The generation returns c2pa only when decision is allow: in the create response for images,
text and speech up to 60 seconds, and in generation.allowed or
generation.released for outputs decided later.
It is null otherwise.
Where it sits in the manifest
Add two assertions to the manifest you sign for the output:- A
c2pa.actionsassertion with ac2pa.createdaction whosedigitalSourceTypeis the IPTC term for generated media,http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia. This says the output was made by a model. Tools that write C2PA 2.x manifests use the labelc2pa.actions.v2; the action and the source type are the same. - The
ai.reflections.licenseassertion, exactly as the generation returned it.
disclosure obligation, and deliver.
Embedding the manifest changes the file’s bytes, so the delivered file’s SHA-256 differs from the
receipt’s
artifact_sha256. Verification finds the receipt by the manifest when it survives.
Fingerprint lookup, for a file whose manifest a platform stripped, is planned; until then, keep the
receipt ID with the file. A fingerprint never exists for an attested output, because Reflections
did not receive its bytes.Reading it
A verifier that findsai.reflections.license in a manifest:
- Validates the manifest with its C2PA tool, which proves the file is what the claim signer signed.
- Verifies
data.receiptagainst the JWKS, as described in Receipt. - Compares
tlp.c2pa_signer.thumbprint, when present, with the SHA-256 of the claim signer certificate’s DER, and rejects the assertion when they differ. A receipt without it is unbound. - Reads the live status at
GET /v1/receipts/{receipt_id}, or opensdata.verify_url.
manifest to
POST /v1/verifications. The result reports the
claim signer, whether the assertion is present, whether its signature is valid, and the receipt.
Manifest verification is planned: neither mode reads a manifest yet, so a verifier checks the
signer binding itself.
Related
Embedding provenance
Writing the assertion and the disclosure label with common C2PA tools.
C2PA in the Standard
Manifest and assertion placement, and soft bindings.