PageSourceSearch

https://opensource.contentauthenticity.org/assets/js/551858a5.686e3267.js

js contentauthenticity.org collected 2026-09-24 08:26:29 UTC 14,932 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkopensource_contentauth_org=globalThis.webpackChunkopensource_contentauth_org||[]).push([[9179],{895:(e,i,t)=>{t.d(i,{Ay:()=>o,RM:()=>r});var n=t(4848),s=t(8453);const r=[];function a(e){const i={a:"a",admonition:"admonition",p:"p",strong:"strong",...(0,s.R)(),...e.components};return(0,n.jsx)(i.admonition,{title:"Warning",type:"warning",children:(0,n.jsxs)(i.p,{children:["Accessing a private key and certificate directly from the file system as shown in these examples is fine during development, but doing so in production is ",(0,n.jsx)(i.strong,{children:"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 ",(0,n.jsx)(i.a,{href:"/docs/signing/prod-cert",children:"Using a certificate in production"}),"."]})})}function o(e={}){const{wrapper:i}={...(0,s.R)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(a,{...e})}):a(e)}},8453:(e,i,t)=>{t.d(i,{R:()=>a,x:()=>o});var n=t(6540);const s={},r=n.createContext(s);function a(e){const i=n.useContext(r);return n.useMemo(function(){return"function"==typeof e?e(i):{...i,...e}},[i,e])}function o(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(r.Provider,{value:i},e.children)}},8896:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>l,contentTitle:()=>c,default:()=>p,frontMatter:()=>o,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"signing/local-signing","title":"Signing with local credentials","description":"Overview","source":"@site/docs/signing/local-signing.mdx","sourceDirName":"signing","slug":"/signing/local-signing","permalink":"/docs/signing/local-signing","draft":false,"unlisted":false,"editUrl":"https://github.com/contentauth/opensource.contentauth.org/edit/main/docs/signing/local-signing.mdx","tags":[],"version":"current","frontMatter":{"id":"local-signing","title":"Signing with local credentials"},"sidebar":"docs","previous":{"title":"Getting a certificate","permalink":"/docs/signing/get-cert"},"next":{"title":"Using a certificate in production","permalink":"/docs/signing/prod-cert"}}');var s=t(4848),r=t(8453),a=t(895);const o={id:"local-signing",title:"Signing with local credentials"},c=void 0,l={},d=[{value:"Overview",id:"overview",level:2},{value:"Signing a manifest",id:"signing-a-manifest",level:2},...a.RM,{value:"Example",id:"example",level:2},{value:"1. Purchase credentials",id:"1-purchase-credentials",level:3},{value:"2. Extract credentials",id:"2-extract-credentials",level:3},{value:"Troubleshooting errors",id:"troubleshooting-errors",level:4},{value:"Extract the key",id:"extract-the-key",level:4},{value:"Extract certificate chain",id:"extract-certificate-chain",level:4},{value:"3. Determine signature algorithm",id:"3-determine-signature-algorithm",level:3},{value:"4. Test with C2PA Tool",id:"4-test-with-c2pa-tool",level:3},{value:"4. Confirm it worked",id:"4-confirm-it-worked",level:3}];function h(e){const i={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",h4:"h4",mdxAdmonitionTitle:"mdxAdmonitionTitle",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h2,{id:"overview",children:"Overview"}),"\n",(0,s.jsx)(i.p,{children:"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."}),"\n",(0,s.jsx)(i.p,{children:"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."}),"\n",(0,s.jsx)(i.h2,{id:"signing-a-manifest",children:"Signing a manifest"}),"\n",(0,s.jsxs)(i.p,{children:["The simplest way to add a C2PA manifest to an asset file and sign it is by using C2PA Tool (",(0,s.jsx)(i.co
1de,{children:"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."]}),"\n",(0,s.jsxs)(i.p,{children:["Similarly, using the Rust SDK, you can ",(0,s.jsx)(i.a,{href:"https://docs.rs/c2pa/latest/c2pa/#adding-a-signed-manifest-to-a-file",children:"add a manifest to an asset file"}),", referencing the certificate and private key file. The ",(0,s.jsx)(i.a,{href:"../sdk-repos/c2pa-js/packages/c2pa-node/",children:"Node.js"}),", ",(0,s.jsx)(i.a,{href:"../sdk-repos/c2pa-python",children:"Python"}),", and ",(0,s.jsx)(i.a,{href:"../sdk-repos/c2pa-cpp",children:"C++"})," libraries can also add and sign a manifest."]}),"\n",(0,s.jsx)(a.Ay,{}),"\n",(0,s.jsx)(i.h2,{id:"example",children:"Example"}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.a,{href:"/docs/signing/get-cert",children:"Getting a certificate"})," provides a general overview of getting a signing certificate from a certificate authority (CA)."]}),"\n",(0,s.jsx)(i.p,{children:"Here is an example of getting signing credentials and then using them with C2PA Tool."}),"\n",(0,s.jsxs)(i.admonition,{type:"note",children:[(0,s.jsx)(i.mdxAdmonitionTitle,{}),(0,s.jsxs)(i.p,{children:["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 ",(0,s.jsx)(i.a,{href:"https://inspect.cr",children:"Inspect tool on Adobe Content Authenticity (Beta)"})," to display your organization name when for signed assets."]})]}),"\n",(0,s.jsx)(i.h3,{id:"1-purchase-credentials",children:"1. Purchase credentials"}),"\n",(0,s.jsxs)(i.p,{children:["Follow the CA's instructions to purchase and download your ",(0,s.jsx)(i.code,{children:".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."]}),"\n",(0,s.jsxs)(i.p,{children:["The rest of this tutorial uses OpenSSL (a set of cryptographic utilities). If OpenSSL is not installed on your system, see ",(0,s.jsx)(i.a,{href:"https://www.openssl.org/source/",children:"OpenSSL"})," for the source distribution or the ",(0,s.jsx)(i.a,{href:"https://wiki.openssl.org/index.php/Binaries",children:"list of unofficial binary distributions"}),"."]}),"\n",(0,s.jsx)(i.h3,{id:"2-extract-credentials",children:"2. Extract credentials"}),"\n",(0,s.jsxs)(i.p,{children:["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.\nUse the commands below to extract the key and certificate chain. If prompted, enter the password that was used to generate the ",(0,s.jsx)(i.code,{children:".pfx"})," file."]}),"\n",(0,s.jsx)(i.admonition,{type:"tip",children:(0,s.jsx)(i.p,{children:"Make sure you are using a recent version of OpenSSL."})}),"\n",(0,s.jsx)(i.h4,{id:"troubleshooting-errors",children:"Troubleshooting errors"}),"\n",(0,s.jsx)(i.p,{children:"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."}),"\n",(0,s.jsxs)(i.p,{children:["For example, the following error message means the ",(0,s.jsx)(i.code,{children:".pfx"})," was encrypted with an older standard:"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"Shrouded Keybag: pbeWithSHA1And3- KeyTripleDES-CBC, Iteration 2000\nPKCS7 Encrypted data: pbeWithSHA1And40BitRC2- CBC, Iteration 2000\nError outputting keys and certificates\n"})}),"\n",(0,s.jsx)(i.h4,{id:"extract-the-key",children:"Extract the key"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-shell",children:"openssl pkcs12 -in mycertfile.pfx -nocerts -out mykey.pem -nodes\n"})}),"\n",(0,s.jsx)(i.admonition,{type:"tip",children:(0,s.jsxs)(i.p,{children:["Check to make sure the above command generated a ",(0,s.jsx)(i.co
1de,{children:".pem"})," file and it's not an empty file."]})}),"\n",(0,s.jsx)(i.h4,{id:"extract-certificate-chain",children:"Extract certificate chain"}),"\n",(0,s.jsxs)(i.p,{children:["For many certificate providers, the ",(0,s.jsx)(i.code,{children:".pfx"})," file contains not just your certificate but the complete certificate trust chain, which you can extract with a command like this:"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-shell",children:"openssl pkcs12 -in mycertfile.pfx -nokeys -out mycerts.pub\n"})}),"\n",(0,s.jsxs)(i.p,{children:["When the ",(0,s.jsx)(i.code,{children:".pfx"})," file does not contain the certificate chain, you can obtain it from your provider."]}),"\n",(0,s.jsx)(i.h3,{id:"3-determine-signature-algorithm",children:"3. Determine signature algorithm"}),"\n",(0,s.jsx)(i.p,{children:"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."}),"\n",(0,s.jsx)(i.p,{children:"You can also enter this OpenSSL command to dump information about the public key used with the certificate:"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-shell",children:"openssl x509 -inform PEM -in mycerts.pub -text\n"})}),"\n",(0,s.jsxs)(i.p,{children:["Where ",(0,s.jsx)(i.code,{children:"mycerts.pub"})," is the file containing the certificate chain from signing certificate to the last certificate before the root CA, concatenated."]}),"\n",(0,s.jsxs)(i.p,{children:["This command produces a text summary of the certificate properties, as shown in the example below. Look for a line containing ",(0,s.jsx)(i.code,{children:"Public Key Algorithm"})," since the public key indicates the signature algorithm used. See the table in ",(0,s.jsx)(i.a,{href:"/docs/signing/get-cert#signature-types",children:"Getting a certificate"})," to determine the corresponding signature type."]}),"\n",(0,s.jsxs)(i.p,{children:["In this example, ",(0,s.jsx)(i.code,{children:"Public Key Algorithm: rsassaPss"}),' corresponds to the "RSASSA-PSS with SHA-256" or ',(0,s.jsx)(i.code,{children:"sha256WithRSAEncryption"})," signature algorithm.  A example snippet of this output looks something like this:"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"Validity\n        Not Before: Jun 10 18:46:28 2022 GMT\n        Not After : Aug 26 18:46:28 2030 GMT\nSubject: C=US, ST=CA, L=Somewhere, O=C2PA Test Signing Cert, OU=FOR TESTING_ONLY, CN=C2PA Signer\nSubject Public Key Info:\n    Public Key Algorithm: rsassaPss\n        Public-Key: (4096 bit)\n        Modulus:\n            ...\n        Exponent: 65537 (0x10001)\n        PSS parameter restrictions:\n            Hash Algorithm: SHA2-256\n            Mask Algorithm: MGF1 with SHA2-256\n            Minimum Salt Length: 32\n            Trailer Field: 0x1 (default)\n"})}),"\n",(0,s.jsx)(i.h3,{id:"4-test-with-c2pa-tool",children:"4. Test with C2PA Tool"}),"\n",(0,s.jsxs)(i.p,{children:["You now have all the needed information to configure C2PA Tool for manifest signing. Edit your ",(0,s.jsx)(i.a,{href:"/docs/sdk-repos/c2patool/docs/manifest",children:"manifest store file"})," to add the following fields that are specific to C2PA Tool:"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-json",children:'"alg": "ps256",\n"private_key": "mykey.pem",\n"sign_cert": "mycerts.pub"\n'})}),"\n",(0,s.jsxs)(i.p,{children:["The ",(0,s.jsx)(i.code,{children:"private_key"})," and ",(0,s.jsx)(i.code,{children:"sign_cert"})," properties must be full paths to the key and certificate chain files generated above."]}),"\n",(0,s.jsxs)(i.p,{children:["You can now use C2PA Tool ",(0,s.jsx)(i.a,{href:"/docs/sdk-repos/c2patool/docs/usage#adding-a-manifest-to-an-asset-file",children:"to add a manifest to an image or other asset file"}),". The command will be something like this:"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"c2patool -m my_manifest.json -o signed_image.jpg my_image.jpg\n"})}),"\n",(0,s.jsxs)(i.p,{children:["The example above uses the information in ",(0,s.jsx)(i.co
1de,{children:"my_manifest.json"})," to add a new manifest to output ",(0,s.jsx)(i.code,{children:"signed_image.jpg"})," using source ",(0,s.jsx)(i.code,{children:"my_image.jpg"}),". The manifest will be signed using the PS256 signature algorithm with private key ",(0,s.jsx)(i.code,{children:"mykey.pem"}),". The manifest will contain the trust chain specified in ",(0,s.jsx)(i.code,{children:"mycerts.pub"}),"."]}),"\n",(0,s.jsx)(i.admonition,{type:"warning",children:(0,s.jsxs)(i.p,{children:["This example accesses the private key and certificate directly from the file system, which is handy during development, but is not secure for production use.  For more information, see ",(0,s.jsx)(i.a,{href:"/docs/signing/prod-cert",children:"Using a certificate in production"}),"."]})}),"\n",(0,s.jsx)(i.h3,{id:"4-confirm-it-worked",children:"4. Confirm it worked"}),"\n",(0,s.jsx)(i.p,{children:"Use C2PA Tool to confirm that you successfully signed the asset. Enter a command like this:"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"c2patool signed_image.jpg \n"})}),"\n",(0,s.jsxs)(i.p,{children:["This command displays the manifest attached to ",(0,s.jsx)(i.code,{children:"signed_image.jpg"})," and should include a section such as this:"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-json",children:'...\n"signature_info": {\n\t"cert_serial_number": "012345678901234567890123456789",\n\t"time": "2023-11-02T17:18:14+00:00"\n},\n\t"label": "urn:uuid:0b9bc2b8-6d66-4258-9fed-694c30abcdef"\n...\n'})}),"\n",(0,s.jsx)(i.admonition,{type:"info",children:(0,s.jsxs)(i.p,{children:["You can also use the ",(0,s.jsx)(i.a,{href:"https://inspect.cr",children:"Inspect tool on Adobe Content Authenticity (Beta)"})," to confirm that your image was signed. If your certificate can't be traced back to a certificate on the ",(0,s.jsx)(i.a,{href:"/docs/conformance/trust-lists",children:"C2PA trust list"}),", it ",(0,s.jsx)(i.a,{href:"/docs/getting-started/inspect#title-and-signing-information",children:"displays the message"}),' "The Content Credential issuer couldn\'t be recognized...."']})})]})}function p(e={}){const{wrapper:i}={...(0,r.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.