diff --git a/docs/getting-started.mdx b/docs/getting-started.mdx index 3f1ab5ae..8fe6a85c 100644 --- a/docs/getting-started.mdx +++ b/docs/getting-started.mdx @@ -76,53 +76,18 @@ A signed digital certificate verifies the authenticity of an entity, such as a s ## Signing and certificates -Once you initially attach a manifest to an asset, it has information about the origin of the asset, such as the name of the tool that created it (for example, Photoshop) and your name as the _actor_ who created or modified it. Each time someone edits or updates the asset using a tool that supports CAI, it adds a new manifest with the actions taken and the certificate of the tool/site; this becomes the _active manifest_, which then references any prior manifests as ingredients. +A manifest attached to an asset contains information about the origin of the asset, such as the name of the tool that created it (for example, Photoshop) and the name of the _actor_ who created or modified it. Then editing the asset using a supporting tool or site adds a new manifest (indicating the actions taken) that is signed with the certificate of the tool/site; this becomes the _active manifest_, which then references any prior manifests as ingredients. -Each manifest is digitally signed with the application's or client's credentials. To make validation of the credentials possible, the manifest also includes the signing certificate chain. The "chain" of certificates starts with the certificate from the last tool that signed the manifest (known as the "end-entity") followed by the certificate that signed it, and so on, back to the original CA issuer. In other words, a user knows they can trust that the manifest is valid because there is a "trust chain" that goes back to a trusted root certificate authority. That's why you need to acquire a security certificate from a legitimate certificate authority. +Each manifest is digitally signed with the application's or client's credentials. To enable validation of the credentials, the manifest also includes the signing certificate chain. The "chain" of certificates starts with the certificate from the last tool that signed the manifest (known as the "end-entity") followed by the certificate that signed it, and so on, back to the original CA issuer on the trust list. A user can trust that the manifest is valid because there is a "trust chain" that goes back to a trusted root certificate authority. That's why you need to acquire a security certificate from a legitimate certificate authority. In practice, to use a certificate with the CAI SDK, follow this process: 1. Purchase security credentials (certificate and key) from a certificate authority. Either email protection or document signing certificates are valid. -2. Extract the certificate by using a tool such as OpenSSL. You could also host the certificate in a secure environment like a hardware security module (HSM). -3. Use one of the supporting CAI libraries or C2PA Tool to sign manifests using the certificate. +2. Extract the certificate by using a tool such as OpenSSL (for use during development). In production, you should host the private key in a secure environment like a hardware security module (HSM). +3. Use one of the supporting CAI libraries or C2PA Tool to sign manifests using the certificate and your private key. -:::tip -For a short tutorial example, see [Signing manifests](manifest/signing-manifests.md). For more information on how to get and use a signing certificate in production, see [Getting and using a signing certificate](prod-cert.mdx). -::: - -### Getting a security certificate - -To create or modify Content Credentials, you must have a valid security certificate and key that conform to the requirements laid out in the [C2PA specification Trust Model section](https://c2pa.org/specifications/specifications/1.4/specs/C2PA_Specification.html#_trust_model). - -You must purchase a X.509 v3 security certificate from a certificate authority (CA). There are many CAs that issue certificates. Some of the most popular ones are: - -- GlobalSign: [S/MIME email signing](https://shop.globalsign.com/en/secure-email), [document signing](https://shop.globalsign.com/en/document-signing) -- IdenTrust: [S/MIME email signing](https://www.identrust.com/digital-certificates/secure-email-smime), [document signing](https://www.identrust.com/digital-certificates/document-signing) -- Comodo Cybersecurity: [S/MIME email signing cert](https://ssl.comodoca.com/s-mime), [document signing cert](https://ssl.comodoca.com/document-signing-certificates) -- Digicert: [S/MIME email signing cert](https://www.digicert.com/tls-ssl/secure-email-smime-certificates), [document signing cert](https://www.digicert.com/signing/document-signing-certificates) - -The above list is for reference only; inclusion does not imply endorsement by CAI or Adobe, Inc. - -When you purchase a certificate, you must select at least one of the extended key usage (EKU) fields that specify what the certificate can be used for: **email protection** and **document signing**. Applications that use the CAI SDK won't accept the certificate unless it has one of these EKUs. - -### Extracting the certificate - -To work with the certificate, you need to extract it. When the CAI SDK adds Content Credentials to an asset, it incorporates the certificate (including the associated public key) into the manifest. - -:::info Important -The _private key_ associated with the certificate is extremely sensitive. Always treat it with the highest security to ensure your credentials are not compromised. If someone does obtain your private key, they will be able to sign C2PA manifests and other content on your behalf without your consent. -::: - -### Using the certificate to sign a manifest - -The simplest way to add a C2PA manifest to an asset file is by using C2PA Tool (`c2patool`). You can run C2PA Tool tool manually from the command line (for example, during development) and more generally from any executable program that can call out to the shell, such as a Node.js application as shown in the [c2patool Node.js service example](c2pa-node-example/). - -The prerelease libraries for [Node.js](c2pa-node/), [Python](c2pa-python/), and [C++/C](c2pa-c/) can also add and sign a manifest. - -Similarly, using the Rust SDK, you can [add a manifest to an asset file](https://docs.rs/c2pa/latest/c2pa/#example-adding-a-manifest-to-a-file), referencing the certificate and private key file. For a simple example of creating and signing a manifest from a C program, see the [c2c2pa repository](https://github.com/contentauth/c2c2pa). - -:::warning Warning -Accessing a private key and certificate directly from the file system is fine during development, but doing so in production may be insecure. Instead use a Key Management Service (KMS) or a hardware security module (HSM) to access the certificate and key; for example as show in the [C2PA Python Example](https://github.com/contentauth/c2pa-python-example). +:::info +For more information on getting and using certificates, see [Signing and certificates](signing/signing-certs.md). ::: ### Verify known certificate list diff --git a/docs/manifest/signing-manifests.md b/docs/manifest/signing-manifests.md deleted file mode 100644 index 2934d3e0..00000000 --- a/docs/manifest/signing-manifests.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -id: signing-manifests -title: Signing manifests ---- - -:::tip -Before reading this page, be sure to read [Getting started](../getting-started.mdx) 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: -- [Key Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html#storage) from the Open Worldwide Application Security Project (OWASP). -- [Key Management Guidelines](https://csrc.nist.gov/Projects/Key-Management/Key-Management-Guidelines) from the National Institute of Standards and Technology, US Department of Commerce. -- [Protect your private keys](https://www.ncsc.gov.uk/collection/in-house-public-key-infrastructure/pki-principles/protect-your-private-keys) from the UK National Cyber Security Centre. -:::note - -## 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](https://github.com/contentauth/c2pa-rs/tree/main/sdk/tests/fixtures/certs) contains certificates and signing keys for many of the supported signature types [described below](#signature-types). - -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()`](https://github.com/contentauth/c2pa-node/blob/main/docs/README.md#createtestsigner) convenience function to create a local signer instance using the test certificate. - -:::warning 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](https://c2pa.org/specifications/specifications/1.4/specs/C2PA_Specification.html#_credential_types) and [Digital Signatures](https://c2pa.org/specifications/specifications/1.4/specs/C2PA_Specification.html#_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 `signatureAlgorithm` | Description | Recommended signature type | RFC Reference | -| -------------------------------- | ------------ | -------------------------- | ------------- | -| `ecdsa-with-SHA256` | ECDSA with SHA-256 | ES256* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | -| `ecdsa-with-SHA384` | ECDSA with SHA-384 | ES384* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | -| `ecdsa-with-SHA512` | ECDSA with SHA-512 | ES512* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | -| `sha256WithRSAEncryption` | RSASSA-PSS with SHA-256
MGF1 with SHA-256| PS256 | [RFC 8017 appendix A.2.4](https://www.rfc-editor.org/rfc/rfc8017.html#appendix-A.2.4) | -| `sha384WithRSAEncryption` | RSASSA-PSS
SHA-384, MGF1 with SHA-384 | PS384 | [RFC 8017 appendix A.2.4](https://www.rfc-editor.org/rfc/rfc8017.html#appendix-A.2.4) | -| `sha512WithRSAEncryption` | RSASSA-PSS
SHA-512, MGF1 with SHA-512 | PS512 | [RFC 8017 appendix A.2.4](https://www.rfc-editor.org/rfc/rfc8017.html#appendix-A.2.4) | -| `id-RSASSA-PSS` - ASN1 OID: prime256v1, NIST CURVE: P-256 | RSA-PSS| ES256* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | -| `id-RSASSA-PSS` - ASN1 OID: secp384r1 | RSA-PSS| ES384* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | -| `id-RSASSA-PSS` - ASN1 OID: secp521r1 | RSA-PSS| ES512* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | -| `id-Ed25519` | EdDSA (Edwards-Curve DSA) with SHA-512 (SHA-2) and Curve25519 | Ed25519 instance ONLY.| [RFC 8410 section 3](https://www.rfc-editor.org/rfc/rfc8410.html#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](https://c2pa.org/specifications/specifications/1.4/specs/C2PA_Specification.html#_trust_model). 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](http://globalsign.com/) certificate authority (CA). - -:::note -GlobalSign is just one of many CAs. For a list of some others, see [Getting started](../getting-started.mdx#getting-a-security-certificate). -:::note - -Credential management is a complex topic and different for every organization. See [above](#overview) for links to best practices. - -### Step 1: Purchase credentials - -This example uses a [PersonSign1](https://shop.globalsign.com/en/secure-email) 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 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](https://verify.contentauthenticity.org/) 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](https://www.openssl.org/source/) for the source distribution or the [list of unofficial binary distributions](https://wiki.openssl.org/index.php/Binaries). - -### 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. -:::tip - -#### 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 - -```shell -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](#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. - -```shell -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: - -```shell -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](../c2patool/docs/manifest.md) to have the following content: - -```json -"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](../c2patool/docs/usage.md#adding-a-manifest-to-an-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`. - -:::warning -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](../c2pa-python-example/readme.md). -::: - -### 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: - -```json -... -"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](https://contentcredentials.org/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. -::: diff --git a/docs/prod-cert-redirect.mdx b/docs/prod-cert-redirect.mdx new file mode 100644 index 00000000..38b0158a --- /dev/null +++ b/docs/prod-cert-redirect.mdx @@ -0,0 +1,10 @@ +--- +id: prod-cert +title: Redirect +--- + +import { Redirect } from '@docusaurus/router'; + + + +This page will be redirected to `https://opensource.contentauthenticity.org/docs/signing/prod-cert`. diff --git a/docs/prod-cert.mdx b/docs/prod-cert.mdx deleted file mode 100644 index 82c8c412..00000000 --- a/docs/prod-cert.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- -id: prod-cert -title: Getting and using a signing certificate ---- - -## Overview - -For convenience, C2PA Tool, the Rust library, and the CAI prerelease libraries include one or more [test certificates](manifest/signing-manifests.md#test-certificates) and private keys for use during development, typically in the `tests/fixtures` directory. While these test certificates and keys are useful during development and testing, for production deployment you must use your own private key and certificate. - -Certificates and private keys are often stored on a hardware security module (HSM), a physical device that attaches directly to a computer or server and is used to securely manage and perform operations on cryptographic keys. A Key Management Service (KMS) is software used to manage keys in a networked environment. A KMS can be connected to a HSM for extra security. For example, the [Python example application](c2pa-python-example/readme.md) uses [AWS KMS](https://aws.amazon.com/kms/). - -## Purchasing a certificate - -To create or modify Content Credentials, you must have a valid X.509 v3 security certificate and key that conform to the requirements laid out in the [C2PA specification](https://c2pa.org/specifications/specifications/2.0/specs/C2PA_Specification.html#x509_certificates). You must purchase a certificate from a certificate authority (CA). There are many CAs; some popular ones are listed in [Getting started](getting-started.mdx#getting-a-security-certificate). - -When you purchase a certificate, you must select at least one of the extended key usage (EKU) fields that specify what the certificate can be used for: **email protection** and **document signing**. Applications that use the CAI SDK won't accept the certificate unless it has one of these EKUs. - -The process to purchase a certificate and key is different for each CA: You might be able to simply click a "Buy" button on the CA's website. Or your can make your own key and use it to create a certificate signing request (CSR) that you send to the CA (see below). Regardless of the process, what you get back is a signed certificate that you use to create a certificate chain. - -The certificate chain starts with the certificate from the last tool that signed the manifest (known as the "end-entity") followed by the certificate that signed it, and so on, back to the original CA issuer. This enables a validating application to determine that the manifest is valid because the certificate chain goes back to a trusted root certificate authority. - -### Certificate signing requests (CSRs) - -A CSR is just an unsigned certificate that's a template for the certificate that you're requesting. The CA creates a new certificate with the parameters specified in the CSR, and signs it with their root certificate, which makes it a valid certificate. - -A CSR comprises a public key, as well as ["distinguished name" information](https://knowledge.digicert.com/general-information/what-is-a-distinguished-name) that identifies the individual or organization requesting the certificate. The distinguished name includes a common name, organization, city, state, country, and e-mail address. Not all of these fields are required and will vary depending with the assurance level of the desired certificate. - -:::tip -For the C2PA [Verify tool](https://verify.contentauthenticity.org/) to display your organization name in the Content Credentials, your CSR must include the "O" or Organization Name attribute in the distinguished name information. See [below](#organization-name) for details. -::: - -You sign the CSR with your private key; this proves to the CA that you have control of the private key that corresponds to the public key included in the CSR. Once the requested information in a CSR passes a vetting process and domain control is established, the CA may sign the public key to indicate that it can be publicly trusted. - -### Types of certificates - -CAs offer a variety of different kinds of certificates (links below are to [Digicert](https://www.digicert.com), but there are many other CAs): - -- The simplest and least expensive option is an [S/MIME email certificate](https://www.digicert.com/tls-ssl/compare-secure-email-smime-certificates). -- Other options, such as [document signing certificate](https://www.digicert.com/signing/compare-document-signing-certificates) require more rigor (like proving your identity) and cost more. - -### Organization name - -If you want the C2PA [Verify tool](https://verify.contentauthenticity.org/) to display your organization name in the Content Credentials, your certificate must include the "O" or [Organization Name attribute](https://www.alvestrand.no/objectid/2.5.4.10.html) (OID value 2.5.4.10) in the distinguished name information. The CA may require some validation steps to prove you are part of that organization (details vary by CA). - -## The C2PA Python example - -The [c2pa-python-example](c2pa-python-example/readme.md) app provides an example of constructing a certificate signing request (CSR) and of using a certificate in a way suitable for a production environment. diff --git a/docs/signing-manifests-redirect.mdx b/docs/signing-manifests-redirect.mdx index 6c67a005..c29b2b39 100644 --- a/docs/signing-manifests-redirect.mdx +++ b/docs/signing-manifests-redirect.mdx @@ -5,6 +5,6 @@ title: Redirect import { Redirect } from '@docusaurus/router'; - + This page will be redirected to `https://opensource.contentauthenticity.org/docs/manifest/signing-manifests`. diff --git a/docs/signing/get-cert.md b/docs/signing/get-cert.md new file mode 100644 index 00000000..54e928a4 --- /dev/null +++ b/docs/signing/get-cert.md @@ -0,0 +1,90 @@ +--- +id: get-cert +title: Getting a signing certificate +--- + +:::note Important +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. +::: + +To sign manifest claims, you must have an X.509 v3 security certificate and key that conform to the requirements laid out in the [C2PA specification](https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#x509_certificates). + +## Certificate authorities (CAs) + +You must purchase a signing certificate from a certificate authority (CA). There are many CAs that issue certificates. Some popular ones include: + +- GlobalSign: [S/MIME email signing](https://shop.globalsign.com/en/secure-email), [document signing](https://shop.globalsign.com/en/document-signing) +- IdenTrust: [S/MIME email signing](https://www.identrust.com/digital-certificates/secure-email-smime), [document signing](https://www.identrust.com/digital-certificates/document-signing) +- Comodo Cybersecurity: [S/MIME email signing cert](https://ssl.comodoca.com/s-mime), [document signing cert](https://ssl.comodoca.com/document-signing-certificates) +- Digicert: [S/MIME email signing cert](https://www.digicert.com/tls-ssl/secure-email-smime-certificates), [document signing cert](https://www.digicert.com/signing/document-signing-certificates) + +The above list is for reference only; inclusion does not imply endorsement by CAI or Adobe, Inc. + +### Types of certificates + +CAs offer a variety of different types of certificates (links below are to [Digicert](https://www.digicert.com), but most CAs offer these types of certificates): + +- The simplest and least expensive option is an [S/MIME email certificate](https://www.digicert.com/tls-ssl/compare-secure-email-smime-certificates). +- Other options, such as [document signing certificate](https://www.digicert.com/signing/compare-document-signing-certificates) require more rigor (like proving your identity) and cost more. + +### Purchasing a certificate + +The process to purchase a certificate and key is different for each CA: You might be able to simply click a "Buy" button on the CA's website. Or your can make your own key and use it to create a certificate signing request (CSR) that you send to the CA. Regardless of the process, what you get back is a signed certificate that you use to create a certificate chain. + +The certificate chain starts with the certificate from the last tool that signed the manifest (known as the "end-entity") followed by the certificate that signed it, and so on, back to the original CA issuer. This enables a validating application to determine that the manifest is valid because the certificate chain goes back to a trusted root certificate authority. + +### Certificate signing requests (CSRs) + +A CSR is just an unsigned certificate that's a template for the certificate that you're requesting. The CA creates a new certificate with the parameters specified in the CSR, and signs it with their root certificate, which makes it a valid certificate. + +A CSR comprises a public key, as well as ["distinguished name" information](https://knowledge.digicert.com/general-information/what-is-a-distinguished-name) that identifies the individual or organization requesting the certificate. The distinguished name includes a common name, organization, city, state, country, and e-mail address. Not all of these fields are required and will vary depending with the assurance level of the desired certificate. + +:::tip +For the C2PA [Verify tool](https://verify.contentauthenticity.org/) to display your organization name in the Content Credentials, your CSR must include the "O" or Organization Name attribute in the distinguished name information. +::: + +You sign the CSR with your private key; this proves to the CA that you have control of the private key that corresponds to the public key included in the CSR. Once the requested information in a CSR passes a vetting process and domain control is established, the CA may sign the public key to indicate that it can be publicly trusted. + +## Certificate requirements + +A signing certificate and key (credentials) must conform to the requirements in the [C2PA specification X.509 Certificates section](https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#x509_certificates); specifically, it 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. + +### Extended key usage (EKU) fields + +You must select at least one of the extended key usage (EKU) fields that specify what the certificate can be used for: **email protection** and **document signing**. Applications that use the CAI SDK won't accept the certificate unless it has one of these EKUs. + +### Organization name + +If you want the C2PA [Verify tool](https://verify.contentauthenticity.org/) to display your organization name in the Content Credentials, your certificate must include the "O" or [Organization Name attribute](https://www.alvestrand.no/objectid/2.5.4.10.html) (OID value 2.5.4.10) in the distinguished name information. The CA may require some validation steps to prove you are part of that organization (details vary by CA). + +### Signature types + +The following table describes the signature algorithms and types that the CAI SDK supports. You must supply credentials (certificates and keys) that correspond to the signing algorithm (`signatureAlgorithm`). Signing/validation will fail if the the supplied credentials don't support the signature type. + +This table is provided for convenience, and is based on information in the [C2PA specification](https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#x509_certificates). The specification is authoritative; refer to it for more details. The C2PA specification also covers two other certificates for timestamp responses and OCSP certificate revocation, which are not covered here. + +| Certificate `signatureAlgorithm` | Description | Recommended signature type | RFC Reference | +| -------------------------------- | ------------ | -------------------------- | ------------- | +| `ecdsa-with-SHA256` | ECDSA with SHA-256 | ES256\* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | +| `ecdsa-with-SHA384` | ECDSA with SHA-384 | ES384\* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | +| `ecdsa-with-SHA512` | ECDSA with SHA-512 | ES512\* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | +| `sha256WithRSAEncryption` | RSASSA-PSS with SHA-256
MGF1 with SHA-256 | PS256 | [RFC 8017 appendix A.2.4](https://www.rfc-editor.org/rfc/rfc8017.html#appendix-A.2.4) | +| `sha384WithRSAEncryption` | RSASSA-PSS
SHA-384, MGF1 with SHA-384 | PS384 | [RFC 8017 appendix A.2.4](https://www.rfc-editor.org/rfc/rfc8017.html#appendix-A.2.4) | +| `sha512WithRSAEncryption` | RSASSA-PSS
SHA-512, MGF1 with SHA-512 | PS512 | [RFC 8017 appendix A.2.4](https://www.rfc-editor.org/rfc/rfc8017.html#appendix-A.2.4) | +| `id-RSASSA-PSS` - ASN1 OID: prime256v1, NIST CURVE: P-256 | RSA-PSS | ES256\* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | +| `id-RSASSA-PSS` - ASN1 OID: secp384r1 | RSA-PSS | ES384\* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | +| `id-RSASSA-PSS` - ASN1 OID: secp521r1 | RSA-PSS | ES512\* | [RFC 5758 section 3.2](https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) | +| `id-Ed25519` | EdDSA (Edwards-Curve DSA) with SHA-512 (SHA-2) and Curve25519 | Ed25519 instance ONLY. | [RFC 8410 section 3](https://www.rfc-editor.org/rfc/rfc8410.html#section-3) | + +* ES256, ES384, and ES512 signatures must be in IEEE P1363 format. + + + + diff --git a/docs/signing/index.md b/docs/signing/index.md new file mode 100644 index 00000000..9ad8a156 --- /dev/null +++ b/docs/signing/index.md @@ -0,0 +1,19 @@ +--- +id: signing-and-certs +title: Signing and certificates +--- + +:::tip +Be sure to read [Getting started](getting-started.mdx#signing-and-certificates) for some basic background on public-key infrastructure (PKI) technology, certificates, and signing manifests. +::: + +As you're developing an application that uses the CAI SDK, there are three ways to sign manifest claims, depending on where you are in your development process: +1. **Initial prototyping and development**: Use the test certificates and keys included with the SDK libraries to sign claims. These certs and keys are provided for convenience, but aren't valid for actual signing. For more information, see [Using test certificates](test-certs.md). +1. **Local/internal testing**: Once your code is working with the test certs and keys, you can move on to: + - [Purchase your own certificate](get-cert.md) from a certificate authority (CA). + - Change your application to [use the certificate and key *locally*](local-signing.md) (directly from the file system) to sign manifest claims; however, this is NOT safe in production. +1. **Production testing/deployment**: To secure your private key for use in a publicly-accessible production application, store it in a hardware security module (HSM) or key management service (KMS) where your application can access it securely . + +:::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. +::: diff --git a/docs/signing/local-signing.md b/docs/signing/local-signing.md new file mode 100644 index 00000000..03c26db3 --- /dev/null +++ b/docs/signing/local-signing.md @@ -0,0 +1,161 @@ +--- +id: local-signing +title: Signing with local credentials +--- + +## Overview + +To sign a claim in a C2PA manifest you need an end-entity certificate that complies with the C2PA trust model. Then you can use your private key with the certificate to sign it. + +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. + +## Signing a manifest + +The simplest way to add a C2PA manifest to an asset file and sign it is by using C2PA Tool (`c2patool`). You can run C2PA Tool manually from the command line (for example, during development) and more generally from any executable program that can call out to the shell, such as a Node.js application as shown in the [c2patool Node.js service example](../c2pa-node-example). + +Similarly, using the Rust SDK, you can [add a manifest to an asset file](https://docs.rs/c2pa/latest/c2pa/#example-adding-a-manifest-to-a-file), referencing the certificate and private key file. The prerelease libraries for [Node.js](../c2pa-node), [Python](../c2pa-python), and [C++/C](../c2pa-c) can also add and sign a manifest. + +:::warning Warning +Accessing a private key and certificate directly from the file system is fine during development, but doing so in production is not secure. Instead use a Key Management Service (KMS) or a hardware security module (HSM) to access the certificate and key; For more information, see [Using a certificate in production](prod-cert.mdx). +::: + +## Example + +[Getting a certificate](get-cert.md) provides a general overview of getting a signing certificate from a certificate authority (CA). + +Here is an example of getting signing credentials using [GlobalSign](http://globalsign.com/) certificate authority (CA) and then using them with C2PA Tool. GlobalSign is just one of many CAs. For a list of some others, see [Getting a security certificate](get-cert.md#certificate-authorities-cas). + +:::note +This example uses an inexpensive personal certificate, which is fine for development and testing, but in production, an enterprise certificate is strongly recommended. An enterprise certificate is required for [Verify](https://verify.contentauthenticity.org/) to display your organization name when for signed assets. +::: + +### 1. Purchase credentials + +The following is an example of using a [PersonSign1](https://shop.globalsign.com/en/secure-email) certificate from GlobalSign that contains KU and EKU values required to sign C2PA manifests. + +Follow the CA's 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. + +The rest of this tutorial uses OpenSSL (a set of cryptographic utilities). If OpenSSL is not installed on your system, see [OpenSSL](https://www.openssl.org/source/) for the source distribution or the [list of unofficial binary distributions](https://wiki.openssl.org/index.php/Binaries). + +### 2. Extract credentials + +To work with the certificate, you need to extract it. When the CAI SDK adds Content Credentials to an asset, it incorporates the certificate (including the associated public key) into the manifest. +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. + +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 + +```shell +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](#troubleshooting-errors) above. +::: + +#### Extract certificate chain + +For many certificate providers, the `.pfx` file contains not just your certificate but the complete certificate trust chain, which you can extract with a command like this: + +```shell +openssl pkcs12 -in mycertfile.pfx -nokeys -out mycerts.pub +``` + +When the `.pfx` file does not contain the certificate chain, you can obtain it from your provider. + +### 3. Determine signature algorithm + +To use the credentials extracted above you must know the signature types they support. Typically, you'll already know this information or the certificate provider will provide it. + +You can also enter this OpenSSL command to dump information about the public key used with the certificate: + +```shell +openssl x509 -inform PEM -in mycerts.pub -text +``` + +Where `mycerts.pub` is the file containing the certificate chain from signing certificate to the last certificate before the root CA, concatenated. + +This command produces a text summary of the certificate properties, as shown in the example below. Look for a line containing `Public Key Algorithm` since the public key indicates the signature algorithm used. See the table in [Getting a certificate](get-cert.md#signature-types) to determine the corresponding signature type. + +For this example with a certificate issued by GlobalSign, `Public Key Algorithm: rsassaPss` corresponds to the "RSASSA-PSS with SHA-256" or `sha256WithRSAEncryption` signature algorithm. A example snippet of this output looks something like this: + +``` +Validity + Not Before: Jun 10 18:46:28 2022 GMT + Not After : Aug 26 18:46:28 2030 GMT +Subject: C=US, ST=CA, L=Somewhere, O=C2PA Test Signing Cert, OU=FOR TESTING_ONLY, CN=C2PA Signer +Subject Public Key Info: + Public Key Algorithm: rsassaPss + Public-Key: (4096 bit) + Modulus: + ... + Exponent: 65537 (0x10001) + PSS parameter restrictions: + Hash Algorithm: SHA2-256 + Mask Algorithm: MGF1 with SHA2-256 + Minimum Salt Length: 32 + Trailer Field: 0x1 (default) +``` + +### 4. Test with C2PA Tool + +You now have all the needed information to configure C2PA Tool for manifest signing. Edit your [manifest store file](../c2patool/docs/manifest.md) to add the following fields that are specific to C2PA Tool: + +```json +"alg": "ps256", +"private_key": "mykey.pem", +"sign_cert": "mycerts.pub" +``` + +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](../c2patool/docs/usage.md#adding-a-manifest-to-an-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.pub`. + +:::warning +This example accesses the private key and certificate directly from the file system, which is fine during development, but is not secure for production use. For more information, see [Using a certificate in production](prod-cert.mdx). +::: + +### 4. 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: + +```json +... +"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](https://contentcredentials.org/verify) to confirm that your image was signed, but if you used a personal certificate (not an organization certificate) then [Verify won't show the organization name](get-cert.md#organization-name) and if your certificate is not on the [known certificate list](../trust-list.mdx), Verify [displays the message](../verify.mdx#title-and-signing-information) "The Content Credential issuer couldn't be recognized...." +::: diff --git a/docs/signing/prod-cert.mdx b/docs/signing/prod-cert.mdx new file mode 100644 index 00000000..2065b087 --- /dev/null +++ b/docs/signing/prod-cert.mdx @@ -0,0 +1,31 @@ +--- +id: prod-cert +title: Using a signing certificate in production +--- + +Accessing a private key and certificate [directly from the local file system](local-signing.md) is fine during development, but doing so in production is not secure. Instead use one or both of: + +- A **key management service** (KMS), to securely store and manage cryptographic keys, including generation, storage, rotation, and revocation. Popular KMS providers include [Amazon KMS](https://aws.amazon.com/kms/), [Google Cloud Key Management](https://cloud.google.com/security/products/security-key-management), and [Azure Key Vault](https://azure.microsoft.com/en-us/products/key-vault). +- A **hardware security module** (HSM), a physical device that attaches directly to a server to securely manage and perform operations on cryptographic keys. + +## Best practices + +:::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 for handling keys and certificates include: + +- [Key Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html#storage) from the Open Worldwide Application Security Project (OWASP). +- [Key Management Guidelines](https://csrc.nist.gov/Projects/Key-Management/Key-Management-Guidelines) from the National Institute of Standards and Technology, US Department of Commerce. +- [Protect your private keys](https://www.ncsc.gov.uk/collection/in-house-public-key-infrastructure/pki-principles/protect-your-private-keys) from the UK National Cyber Security Centre. + +## Pre-production steps + +Because using a KMS can be complex, you may want to start by using a local "mock" service (such as LocalStack for Amazon KMS) as illustrated in the [c2pa-python-example](c2pa-python-example/readme.md#using-localstack). Doing this enables you to test your code before you set up a production KMS. + +You can also create a self-signed certificate for development purposes. The resulting manifests signed with this certificate won't be trusted, but you can use it to run the application to see how it works before purchasing a real certificate from a CA. + +## The C2PA Python example + +The [c2pa-python-example](c2pa-python-example/readme.md) app provides an example of constructing a certificate signing request (CSR) and of using [Amazon KMS](https://aws.amazon.com/kms/). diff --git a/docs/signing/test-certs.md b/docs/signing/test-certs.md new file mode 100644 index 00000000..1488061c --- /dev/null +++ b/docs/signing/test-certs.md @@ -0,0 +1,20 @@ +--- +id: test-certs +title: Using test certificates +--- + +The CAI SDK does not allow you to use a self-signed certificate to sign a manifest. + +For initial development and testing, the SDK provides example *test certificates* and private keys: +- The [Rust library `sdk/tests/fixtures/certs/` folder](https://github.com/contentauth/c2pa-rs/tree/main/sdk/tests/fixtures/certs) contains certificates and signing keys for many of the supported [signature types](get-cert.md#signature-types). +- The prerelease libraries (Node.js, Python, and C++) provide a subset of test certificates in each repository's `tests/fixtures` folder. The Node.js library even provides a [`CreateTestSigner()`](https://github.com/contentauth/c2pa-node/blob/main/docs/README.md#createtestsigner) convenience function to create a local signer instance using the test certificate. + +:::warning Warning +While these test credentials are useful during development, you must [get your own certificate](get-cert.md) and use your own private key for production deployment. +::: + +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 [X.509 Certificates](https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#x509_certificates) and [Digital Signatures](https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_digital_signatures) sections. + +For manifest claims signed with one of the test certificates, the C2PA Verify tool will display the message "The Content Credential issuer couldn't be recognized." See [Using the Verify tool](../verify.mdx#signing-information) for more information. + + diff --git a/docs/verify.mdx b/docs/verify.mdx index 14874770..b144a01c 100644 --- a/docs/verify.mdx +++ b/docs/verify.mdx @@ -166,9 +166,9 @@ For example, suppose you downloaded a file from Adobe Stock and renamed it `my_s } ``` -**Signing information** +#### Signing information -If the Content Credential was signed by a certificate that is NOT on the [known certificate list](verify-known-cert-list), such as the CAI test certificate in the SDK, then Verify displays "Unrecognized" at the top of this section with this notice: +If the Content Credential was signed by a certificate that is NOT on the [known certificate list](verify-known-cert-list), such as one of the SDK's [test certificates](signing/test-certs.md), then Verify displays "Unrecognized" at the top of this section with this notice: import verify_unknown_source from '../static/img/verify-cc-unknown-source.png'; @@ -177,7 +177,11 @@ import verify_unknown_source from '../static/img/verify-cc-unknown-source.png'; style={{ width: '283px', display: 'block', margin: '10px auto' }} /> -However, if the Content Credential was signed by a certificate on the [known certificate list](verify-known-cert-list), then this section displays the name of the issuer of the claim signature from the `signature_info.issuer` property in the active manifest, as shown in the example snippet below. It shows the organization name only if the signing certificate includes the "O" or [Organization Name attribute](https://www.alvestrand.no/objectid/2.5.4.10.html) (OID value 2.5.4.10) in the certificate's distinguished name information. +However, if the Content Credential was signed by a certificate on the [known certificate list](verify-known-cert-list), then this section displays the name of the issuer of the claim signature from the `signature_info.issuer` property in the active manifest, as shown in the example snippet below. + +:::note +This section shows the organization name only if the signing certificate includes the "O" or [Organization Name attribute](https://www.alvestrand.no/objectid/2.5.4.10.html) (OID value 2.5.4.10) in the certificate's distinguished name information. +::: For signers on the known certificate list, this section also displays the time of the claim signature from the `signature_info.time` property in the active manifest, as shown in the example snippet below. The date is converted from UTC to the local time zone. diff --git a/sidebars.js b/sidebars.js index 8d13b2fb..b813eba8 100644 --- a/sidebars.js +++ b/sidebars.js @@ -12,6 +12,11 @@ const sidebars = { link: { type: 'doc', id: 'getting-started' }, collapsed: true, items: [ + { + type: 'doc', + label: 'FAQs', + id: 'faqs', + }, { type: 'doc', id: 'verify', @@ -40,10 +45,6 @@ const sidebars = { type: 'doc', id: 'manifest/manifest-validation', }, - { - type: 'doc', - id: 'manifest/signing-manifests', - }, { type: 'doc', id: 'manifest/manifest-examples', @@ -60,7 +61,6 @@ const sidebars = { }, ], }, - { type: 'category', label: 'C2PA Tool', @@ -111,7 +111,6 @@ const sidebars = { collapsed: true, items: jsSdkSidebar.docs, }, - { type: 'category', label: 'Prerelease libraries', @@ -209,7 +208,6 @@ const sidebars = { }, ], }, - { type: 'category', label: 'Rust library', @@ -249,19 +247,32 @@ const sidebars = { ], }, { - type: 'doc', - label: 'Getting and using a certificate', - id: 'prod-cert', - }, - { - type: 'doc', - label: 'FAQs', - id: 'faqs', - }, - { - type: 'doc', - label: 'Community resources', - id: 'community-resources', + type: 'category', + label: 'Signing and certificates', + link: { type: 'doc', id: 'signing/signing-and-certs' }, + collapsed: true, + items: [ + { + type: 'doc', + label: 'Using test certificates', + id: 'signing/test-certs', + }, + { + type: 'doc', + label: 'Getting a certificate', + id: 'signing/get-cert', + }, + { + type: 'doc', + label: 'Signing with local credentials', + id: 'signing/local-signing', + }, + { + type: 'doc', + label: 'Using a certificate in production', + id: 'signing/prod-cert', + }, + ], }, { type: 'category', @@ -325,9 +336,17 @@ const sidebars = { ], }, { - type: 'doc', - label: 'Task planning & roadmap', - id: 'roadmap', + type: 'category', + label: 'Community resources', + link: { type: 'doc', id: 'community-resources' }, + collapsed: true, + items: [ + { + type: 'doc', + label: 'Task planning & roadmap', + id: 'roadmap', + }, + ], }, ], };