Skip to main content

Signing manifests

tip

Before reading this page, be sure to read Getting started so you'll have some basic background on public-key infrastructure (PKI) technology, certificates, and signing manifests.

Overview

To sign a C2PA manifest you need an end-entity certificate that complies with the C2PA trust model. Then you can use your private key and public certificates in the signing process. This page walks through an example of obtaining appropriate credentials and then signing a manifest with them using C2PA Tool.

note

Best practices for handling keys and certificates are beyond the scope of this documentation. Always protect your private keys with the highest level of security; for example, never share them through insecure channels such as email.

Some useful references include:

Certificates

Trust lists connect the end-entity certificate that signed a manifest back to the originating root CA. This is accomplished by supplying the subordinate public X.509 certificates forming the trust chain (the public X.509 certificate chain). If those are not supplied, you can use a private credential store to validate the certificate trust chain. If you do not supply a certificate chain or trust list, validators may reject the manifest. See the C2PA specification for more details.

A certificate used to sign C2PA manifests must:

  • Follow the Public Key Infrastructure (PKI) X.509 V3 specification.
  • Have the Key Usage (KU) extension, which must be marked as critical.
  • Assert the digitalSignature bit.
  • Have the Extended Key Usage (EKU) extension. If the Basic Constraints extension is absent or the certificate authority (CA) Boolean is not asserted, the EKU must be non-empty.
    • The anyExtendedKeyUsageEKU field (2.5.29.37.0) must not be present.
    • If the configuration store does not contain a list of EKUs, a certificate that signs C2PA manifests must be valid for the id-kp-emailProtection (1.3.6.1.5.5.7.3.4) purpose and/or the id-kp-documentSigning (1.3.6.1.5.5.7.3.36) purpose.

Test certificates

The CAI SDK does not allow you to use a self-signed certificate to sign a manifest. For development and testing, use the sample certificates provided with the SDK. The Rust library sdk/tests/fixtures/certs/ folder contains certificates and signing keys for many of the supported signature types described below.

Additionally, for convenience, CAI prerelease libraries also provide a subset of test certificates in each repository's tests/fixtures folder. The Node.js library even provides a CreateTestSigner() convenience function to create a local signer instance using the test certificate.

Warning

The test certificates are for use during development and testing only. Do not use them in production!

Although not recommended due to complexity and difficulty, you can create your own certificates for development and testing. Follow the requirements in the C2PA Technical Specification Credential Types and Digital Signatures sections.

Signature types

The following table describes the signature algorithms and signature types that the CAI SDK supports. You must supply credentials (certificates and keys) that correspond to the signing algorithm. Signing/validation will fail if the the supplied credentials don't support the signature type.

Certificate signatureAlgorithmDescriptionRecommended signature typeRFC Reference
ecdsa-with-SHA256ECDSA with SHA-256ES256*RFC 5758 section 3.2
ecdsa-with-SHA384ECDSA with SHA-384ES384*RFC 5758 section 3.2
ecdsa-with-SHA512ECDSA with SHA-512ES512*RFC 5758 section 3.2
sha256WithRSAEncryptionRSASSA-PSS with SHA-256
MGF1 with SHA-256
PS256RFC 8017 appendix A.2.4
sha384WithRSAEncryptionRSASSA-PSS
SHA-384, MGF1 with SHA-384
PS384RFC 8017 appendix A.2.4
sha512WithRSAEncryptionRSASSA-PSS
SHA-512, MGF1 with SHA-512
PS512RFC 8017 appendix A.2.4
id-RSASSA-PSS - ASN1 OID: prime256v1, NIST CURVE: P-256RSA-PSSES256*RFC 5758 section 3.2
id-RSASSA-PSS - ASN1 OID: secp384r1RSA-PSSES384*RFC 5758 section 3.2
id-RSASSA-PSS - ASN1 OID: secp521r1RSA-PSSES512*RFC 5758 section 3.2
id-Ed25519EdDSA (Edwards-Curve DSA) with SHA-512 (SHA-2) and Curve25519Ed25519 instance ONLY.RFC 8410 section 3
info
* ES256, ES384, and ES512 signatures must be in IEEE P1363 format.

The information in this table is based on the C2PA specification Trust Model section. The C2PA specification also covers two other certificates for timestamp responses and OCSP certificate revocation, which are not covered here.

Example

Here is an example of generating a C2PA-compliant set of credentials using GlobalSign certificate authority (CA).

note

GlobalSign is just one of many CAs. For a list of some others, see Getting started.

Credential management is a complex topic and different for every organization. See above for links to best practices.

Step 1: Purchase credentials

This example uses a PersonSign1 certificate from GlobalSign that contains KU and EKU values required to sign C2PA manifests.

Follow the instructions to purchase and download your .pfx file. This file is a PKCS12 container that holds your certificate chain and private signing key. Other certificate providers may have alternate ways of providing your private key and certificate and may include only the end-entity certificate and so you must manually download the rest of the certificate chain.

Warning

This example uses an inexpensive personal certificate, which is fine for development and testing, but for production use an enterprise certificate is strongly recommended. An enterprise certificate is required for Verify to display your organization name when for signed assets.

The rest of this tutorial uses OpenSSL (a set of cryptographic utilities). If OpenSSL is not installed on your system, see OpenSSL for the source distribution or the list of unofficial binary distributions.

Step 2: Extract the certificate and key

Use the commands below to extract the key and certificate chain. If prompted, enter the password that was used to generate the .pfx file.

tip

Make sure you are using a recent version of OpenSSL.

Troubleshooting errors

In this step, OpenSSL may report errors when extracting the key or certificate chain. In many cases, if OpenSSL generates the output file, you can ignore the messages. However, in some cases you may need to add -legacy to the command for it to work properly.

For example, the following error message means the .pfx was encrypted with an older standard:

Shrouded Keybag: pbeWithSHA1And3- KeyTripleDES-CBC, Iteration 2000
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2- CBC, Iteration 2000
Error outputting keys and certificates

Extract the key

openssl pkcs12 -in mycertfile.pfx -nocerts -out mykey.pem -nodes
tip

Check to make sure the above command generated a .pem file and it's not an empty file. For more information, see Troubleshooting errors above.

Extract the certificate chain

For many certificate providers, the .pfx file contains not just your certificate but the complete certificate trust chain. When the .pfx file does not contain the certificate chain, you can obtain it from your provider.

openssl pkcs12 -in mycertfile.pfx -nokeys -out mycerts.pem

Using credentials with C2PA Tool

To use the credentials extracted above you must know the signature types they support. Typically, this information is available from your certificate provider. If it is not, enter this OpenSSL command to dump certificate information:

openssl x509 -inform PEM -in mycerts.pem -text

This command produces a text summary of the certificate properties, as shown in the example below. Look for a line containing Signature Algorithm. See the table above to determine the corresponding signature type. For this example with a certificate issued by GlobalSign, Signature Algorithm: sha256WithRSAEncryption corresponds to the PS256 signature type.

Certificate:
Data:
Version: 3 (0x2)
Serial Number:
73:0d:01:c3:04:06:62:e4:60:0a:0b:0c
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = BE, O = GlobalSign nv-sa, CN = GlobalSign GCC R3 PersonalSign 1 CA 2020
Validity
Not Before: Oct 13 13:33:02 2022 GMT
Not After : Oct 14 13:33:02 2023 GMT
Subject: CN = someuser@someemail.com, emailAddress = someuser@someemail.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
.
.
.

You now have all the needed information to configure C2PA Tool for manifest signing. Edit your manifest store file to have the following content:

"alg": "ps256",
"private_key": "mykey.pem",
"sign_cert": "mycerts.pem"

The private_key and sign_cert properties must be full paths to the key and certificate chain files generated above.

You can now use C2PA Tool to add a manifest to an image or other asset file. The command will be something like this:

c2patool -m my_manifest.json -o signed_image.jpg my_image.jpg

The example above uses the information in my_manifest.json to add a new manifest to output signed_image.jpg using source my_image.jpg. The manifest will be signed using the PS256 signature algorithm with private key mykey.pem. The manifest will contain the trust chain specified in mycerts.pem.

danger

This example accesses the private key and certificate directly from the file system, which is fine during development, but in production may not be secure. Instead, in a production application, use a hardware security module (HSM) or a Key Management Service (KMS); for example as show in the C2PA Python Example.

Confirm it worked

Use C2PA Tool to confirm that you successfully signed the asset. Enter a command like this:

c2patool signed_image.jpg 

This command displays the manifest attached to signed_image.jpg and should include a section such as this:

...
"signature_info": {
"cert_serial_number": "012345678901234567890123456789",
"time": "2023-11-02T17:18:14+00:00"
},
"label": "urn:uuid:0b9bc2b8-6d66-4258-9fed-694c30abcdef"
...
info

You can also use Verify to confirm that your image was signed, but if you used a personal certificate (not an organization certificate) then Verify won't show detailed information about the credential used.