c2patool is a command line tool for working with C2PA manifests. Currently, the tool supports:
image/jpeg
image/png
You can install c2patool on Mac and Linux via Homebrew:
shell
brew tap contentauth/tools
brew install c2patool
If you have Rust installed, you can build c2patool from source:
shell
git clone git@github.com:contentauth/c2patool.git
cargo build
Writing or previewing a manifest requires you to provide a manifest definition, which is a JSON data structure
that describes the manifest data. The JSON schema for this file is available at schemas/manifest-definition.json
.
Note: Any file references specified will be relative to the location of the manifest definition file.
You should be able to test creating your own manifests using pre-built certificates supplied with this tool. However, if you want to create your own official certificates, please reference the section titled "Creating and using an X.509 certificate".
Note: You can check out this repository locally to run the example code below.
Invoking the tool with a path to an asset will output a JSON report of the manifests contained in the file.
shell
c2patool image.jpg
The -d
option will output a detailed JSON report of the internal C2PA structure.
shell
c2patool image.jpg -d
If a path to a JSON manifest definition file is given, the tool will generate a new manifest using the values given in the definition. This will print the report to stdout.
```shell
c2patool sample/test.json
c2patool sample/test.json > report.json ```
The manifest definition can also be passed on the command line as a string using the -c
or --config
option:
shell
c2patool -c '{"assertions": [{"label": "org.contentauth.test", "data": {"name": "Jane Doe"}}]}'
You can add C2PA data to a file by passing a manifest definition JSON file together with a path to a supported file extension (e.g. PNG) specified by the output (-o
) flag.
If the output file already exists, any C2PA data in that file will be replaced and the asset maintained. If the output doesn't exist and a parent file is available, the parent will be copied to the output and the C2PA data will be added.
When using a JSON file, the parent file can be specified by passing -p
or --parent
with the path to the file. This allows using the same manifest definition with different parent assets.
If you are not changing an asset and just adding C2PA data, use an existing output file and no parent. Note that this will replace any existing C2PA data in the existing output file. For instance:
shell
c2patool sample/test.json -o existing.jpg
If you have edited an asset and want to add C2PA data to it, pass the original as the parent and put the edited file at the output location to have the C2PA data added.
shell
c2patool sample/test.json -p original.jpg -o image-with-c2pa.jpg
Before you can add a manifest, you need to create an X.509 certificate. You can specify the path to the cert files in the following configuration fields:
private_key
sign_cert
If you are using a signing algorithm other than the default ps256
, you will need to specify it in alg
, which can be set to one of the following:
ps256
ps384
ps512
es256
es384
es512
ed25519
The specified algorithm must be compatible with values of private_key
and sign_cert
.
The key and cert can also be placed in the environment variables C2PA_PRIVATE_KEY
and C2PA_PUB_CERT
. These two variables are used to set the private key and public certificates. For example, to sign with es256 signatures using the content of a private key file and certificate file, you would run:
shell
set C2PA_PRIVATE_KEY=$(cat my_es256_private_key)
set C2PA_PUB_CERT=$(cat my_es256_certs)
Both the private_key
and sign_cert
should be in PEM format. The sign_cert
should contain a PEM certificate chain starting for the end-entity certificate used to sign the claim ending with the intermediate certificate before the root CA certificate. See the "sample" folder for example certificates.
To create your own temporary files for testing, you can execute the following command:
shell
openssl req -new -newkey rsa:4096
-sigopt rsa_padding_mode:pss \
-days 180 \
-extensions v3_ca \
-addext "keyUsage = digitalSignature" \
-addext "extendedKeyUsage = emailProtection" \
-nodes -x509 -keyout private.key -out certs.pem -sha256
Note: You may have need to update your openssl
version if the above command does not work. You will likely need version 3.0 or later. You can check the version that is installed by typing openssl version
.
c2patool can also timestamp the signature data that is embedded. This is useful for validating an asset when the embedded certificates have expired. If the config has a ta_url set, c2patool will attempt to timestamp the signature using the TA service at the provided URL. The TA must be RFC3161 compliant. Example TA setting:
ta_url=http://timestamp.digicert.com
The Configuration file is a JSON formatted file with a .json extension:
The schema for this type is as follows:
json
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://ns.adobe.com/cai/claim-definition/v1",
"type": "object",
"description": "Definition format for claim created with c2patool",
"examples": [
{
"vendor": "myvendor",
"claim_generator": "MyApp/0.1",
"parent": "image.jpg",
"ingredients": [],
"assertions": [
{
"label": "my.assertion",
"data": {
"any_tag": "whatever I want"
}
}
],
"alg": "es256",
"private_key": "es256_private.key",
"sign_cert": "es256_certs.pem",
"ta_url": "http://timestamp.digicert.com"
}
],
"required": [
"assertions",
],
"properties": {
"vendor": {
"type": "string",
"description": "Typically an Internet domain name (without the TLD) for the vendor (i.e. `adobe`, `nytimes`)"
},
"claim_generator": {
"type": "string",
"description": "A UserAgent string that will let a user know what software/hardware/system produced this Manifest - names should not contain spaces (defaults to c2patool)"
},
"title": {
"type": "string",
"description": "A human-readable string to be displayed as the tile for this Manifest (defaults to embedded file name)"
},
"credentials": {
"type": "object",
"description": "An array of W3C verifiable credentials objects defined in the c2pa assertion specification. Section 7"
},
"parent": {
"type": "string",
"format": "Local file system path",
"description": "A file path to the source image that was modified by this Manifest (if any)"
},
"Ingredients": {
"type": "array of string",
"format": "Array of local file system paths",
"description": "File paths to images that were used to modify the image referenced by this Manifest (if any)"
},
"assertions": {
"type": "object",
"description": "Objects with label, and data - standard c2pa labels must match values as defined in the c2pa assertion specification"
},
"alg": {
"type": "string",
"format": "Local file system path",
"description": "Signing algorithm: one of [ ps256 | ps384 | ps512 | es256 | es384 | es512 | ed25519]"
},
"ta_url": {
"type": "string",
"format": "http URL",
"description": "A URL to an RFC3161 compliant Time Stamp Authority"
},
"private_key": {
"type": "string",
"format": "Local file system path",
"description": "File path to a private key file"
},
"sign_cert": {
"type": "string",
"format": "Local file system path",
"description": "File path to signing cert file"
},
"base_path": {
"type": "string",
"format": "Local file system path",
"description": "File path to a folder to use as the base for relative paths in config"
},
},
"additionalProperties": false
}