Getting Started with C2PA Content Credentials in IPWorks LLM


Requirements:
IPWorks LLM

Introduction

IPWorks LLM includes components for attaching C2PA Content Credentials to images and documents and validating credentials embedded in them. The C2PASigner component embeds a signed manifest containing the producer's claims about an asset. The C2PAVerifier component checks the signature and whether the asset still matches the signed manifest, then reports the results of those checks.

This guide shows how to sign a JPEG that an application identifies as generated media, verify the signed file, and read the results. The components also support PNG and PDF assets.

Tip: Download the latest version of IPWorks LLM to follow along.

Step 1: Sign an Asset

To sign an asset, you'll need a JPEG and a PFX certificate containing the private signing key. Use an end-entity certificate with the digitalSignature key usage and an accepted extended key usage, such as the C2PA claim-signing EKU. Replace the sample file paths, password, and application name with your own values.

Create a C2PASigner, identify the input and output files, and set the certificate. Use ClaimGenerator to identify the application creating the manifest. AddAction records the c2pa.created action and identifies the asset as generated media:


using nsoftware.IPWorksLLM;
C2PASigner signer = new C2PASigner();
signer.InputFile = "image.jpg";
signer.OutputFile = "image-signed.jpg";
signer.ClaimGenerator = "MyApp/1.0";
signer.SigningCert = new Certificate(CertStoreTypes.cstPFXFile, "signer.pfx", "password", "*");
signer.AddAction("c2pa.created",
  "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia",
  "MyApp/1.0");
signer.Sign();

Sign builds and signs the manifest, binds it to the asset bytes, and writes the resulting JPEG to OutputFile. The example uses the default SignatureAlgorithm, ES256, so the certificate needs a compatible key.

Use an accurate digital source type for the content you are signing. The value above is for media produced by a generative model. The c2pa.created action requires a digital source type.

Step 2: Verify the Content Credentials

Set InputFile on a C2PAVerifier and call Verify. The component reads the embedded manifests and adds an entry to ValidationResults for each check:


C2PAVerifier verifier = new C2PAVerifier();
verifier.InputFile = "image-signed.jpg";
verifier.Verify();
foreach (C2PAValidationResult result in verifier.ValidationResults)
  Console.WriteLine(result.Severity + " " + result.Code + ": " + result.Explanation);
if (verifier.ActiveManifestIndex >= 0)
{
  C2PAManifest active = verifier.Manifests[verifier.ActiveManifestIndex];
  Console.WriteLine("Claim generator: " + active.ClaimGenerator);
  Console.WriteLine("Signer: " + active.SignerSubject);
}

Manifests contains the manifests found in the file; ActiveManifestIndex selects the one describing its current state. An asset may have earlier manifests associated with its ingredients. If the file cannot be read or has no embedded manifest store, Verify throws an error. An empty store instead leaves ActiveManifestIndex at -1 and reports a validation result.

Step 3: Interpret the Results

Read the individual results rather than treating a completed Verify call as a pass:

Validation code Meaning
claimSignature.validated The claim signature verified against the signing certificate
assertion.dataHash.match The asset matches its signed content binding
assertion.dataHash.mismatch The asset does not match its signed content binding
signingCredential.untrusted The signing certificate does not chain to a trusted anchor

Each result provides a Code, Severity, and Explanation. Your application can use these results to distinguish an altered asset from one signed by a certificate it does not trust. A valid signature and matching content binding support the integrity of the recorded claim; they do not prove that the described creation process actually occurred.

Trust and Production Use

UseC2PATrustList defaults to true, but this build has no bundled C2PA trust-list snapshot. Add the appropriate anchor to TrustedCerts before calling Verify for a private signer; otherwise the certificate reports signingCredential.untrusted. Set UseC2PATrustList to false when the application should use only the anchors it supplies.

C2PASigner supports JPEG, PNG, and PDF files. PDF signing is limited to documents using classic cross-reference tables.

For production credentials, use a certificate that meets the C2PA claim-signing profile and protect its private key. Set TSAURL to request a trusted time stamp. The verifier checks stapled OCSP status when present, but this build does not yet make online revocation requests when CheckRevocation is true.

Conclusion

C2PASigner attaches the recorded claim to an asset, and C2PAVerifier reports whether its signature and content binding remain valid. The credential records the signer's claim; it does not independently prove that the described creation process occurred. To carry a signed source into a derived asset, see Following C2PA Provenance and Configuring Trust.

We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at support@nsoftware.com.