Skip to main content

Sign the manifest

Cryptographically sign the C2PA manifest, proving its authenticity and integrity before embedding it into the image. This ensures that any changes to the manifest can be detected, and the signer’s identity is verifiable.

Inputs

  • Manifest data – JSON-formatted manifest string (manifest_json) generated in the previous step.    

  • CSC credentials – Client certificate (cert.pem) and private key (key.pem) that identify the signer.    

  • Credential PIN – Secret PIN used to authorize the signing operation via CSC.

Process

  1. Compute a SHA-256 hash of the manifest JSON.

  2. Send this hash to the CSC API along with the credential PIN to request a Signature Activation Data (SAD) token.

  3. CSC verifies the certificate, key and PIN, then returns a signed hash.

  4. This signed hash is used to create a digital signature over the manifest.

Output

Signed manifest hash – A base64-encoded signed hash returned by CSC. This signed hash is ready to be embedded in the image along with the manifest for final content authenticity verification.

Python example

# This script reads a manifest JSON file, computes its SHA-256 hash, sends it to CSC for #...signing using the client certificate, key, credential ID, and PIN, and prints the signed hash #...(SAD). 

import json  
import hashlib  
import base64  
import getpass  
import requests  
import logging    

# Configure logging  
logging.basicConfig(level=logging.INFO)    

# CSC demo endpoint  
CSC_BASE_URL = 
"https://clientauth.demo.one.digicert.com/documentmanager/csc/v1"  

def get_sad(hash_b64: str, pin: str, credential_id: str, client_cert: str, client_key: str) -> str:      
"""      
Request a Signature Activation Data (SAD) token from CSC for signing a hash.     
"""      
url = f"{CSC_BASE_URL}/credentials/authorize"      
payload = {          
"credentialID": credential_id,          
"PIN": pin,          
"hash": [hash_b64],          
"hashAlgo": "SHA256",          
"numSignatures": 1  
}      
resp = requests.post(          
url,          
json=payload,          
cert=(client_cert, client_key),          
headers={"Content-Type": "application/json"},          
timeout=10      
)      
resp.raise_for_status()      
data = resp.json()      
return data["SAD"
]    
def main():      
print("=== Sign a Manifest with CSC ===\n")  

manifest_file = input("Enter path to manifest JSON file: ").strip()      
client_cert = input("Enter path to client certificate (cert.pem): ").strip()      
client_key = input("Enter path to client key (key.pem): ").strip()      
credential_id = input("Enter your credential ID: ").strip()      
pin = getpass.getpass("Enter your credential PIN: ").strip()  

# Load manifest      
with open(manifest_file, "r") as f:          
manifest_json = f.read()            

# Compute SHA256 hash of manifest      
digest = hashlib.sha256(manifest_json.encode('utf-8')).digest()      
hash_b64 = base64.b64encode(digest).decode('utf-8')      
logging.info(f"SHA256 hash of manifest (base64): {hash_b64}")            

# Request CSC to sign      
signed_hash = get_sad(hash_b64, pin, credential_id, client_cert, client_key)            

print("\n=== Signed Manifest Hash (SAD) ===")      
print(signed_hash)    

if __name__ == "__main__":      
main()