Skip to content

v0.4.0 — read the C2PA 2.x shapes real files use

Choose a tag to compare

@richardwooding richardwooding released this 27 Aug 07:57
· 3 commits to main since this release
2958938

Reads the C2PA 2.x shapes that current writers — OpenAI's and Google's signers among them — actually put in a file, and that the library previously read back empty or as malformed.

Fixed — timestamps in a bare CMS ContentInfo

sigTst and sigTst2 may hold either an RFC 3161 TimeStampResp or a bare CMS ContentInfo. Both descents probed with a two-RawValue struct, which matches any two-element SEQUENCE — including a ContentInfo — so a ContentInfo token was descended into as a response, failed, and was rejected. Read returned a zero SignedAt and Validate recorded timeStamp.mismatch ("malformed timestamp token") for every timestamp of that shape, which is what Google- and OpenAI-signed images carry.

The two shapes are now told apart by their first element (an OID for a ContentInfo, a SEQUENCE for a PKIStatusInfo) in one shared helper used by both call sites.

signingTime also looked only at sigTst, while Validate's extraction already handled sigTst2. A c2pa.claim.v2 signature carries its timestamp only in sigTst2, so Read's SignedAt stayed zero for exactly those files. It now reads either container.

Fixed — claim_generator_info

An array of entries in 1.x, a single entry in 2.x. A c2pa.claim.v2 carries only the 2.x shape and no flat claim_generator, so Info.ClaimGenerator came back empty for every such file. Both shapes are now read.

Added — Info.SoftwareAgent

softwareAgent names the model rather than the signing service (e.g. gpt-image 2.0 on OpenAI's c2pa.created action) and had no field. It is read as the 1.x string, the 2.x inline entry, or a 2.x softwareAgentIndex into the assertion's softwareAgents array, and is assigned per manifest the way ClaimGenerator is, so the two fields always describe the same manifest.

Tests

New fixture testdata/c2pa_2x_openai.png — an OpenAI-generated PNG carrying all three 2.x shapes; reverting the fixes under TestC2PA2xOpenAIFixture reproduces all three symptoms. The timestamp tests unwrap the existing signed fixture's own token to get the bare ContentInfo shape and assert it reaches timeStamp.validated; the remaining cases synthesise CBOR.

No API removals or behaviour changes beyond the above.

Full changelog: v0.3.0...v0.4.0