Hash sign a document with Content Signing Service
5 minute read
Use DigiCert Content Signing Service with Content Trust Manager and Cloud Signature Consortium (CSC) APIs to sign a PDF or XML document by hash.
In this workflow, Content Signing Service prepares the document and creates the hash. Content Trust Manager authorizes the signing credential and signs the hash. Content Signing Service then embeds the returned signature into the original document.
Before you begin
Make sure you have:
URLs and variables
The examples use shell variables so you can paste each request into a terminal after setting your own values.
export DCONE_BASE_URL="https://demo.one.digicert.com"
export DTM_BASE_URL="$DCONE_BASE_URL/documentmanager"
export CSS_BASE_URL="http://localhost:8080"
export API_TOKEN="YOUR_API_TOKEN"
export CREDENTIAL_ID="YOUR_CREDENTIAL_ID"
export INPUT_FILE="./sample.pdf"
export OUTPUT_FILE="./sample-signed.pdf"
export TSA_URL="http://ts.quovadisglobal.com/eu"
Use your production DigiCert ONE URL in production. If your Content Signing Service is not running on localhost:8080, update CSS_BASE_URL.
The DigiCert-supplied Postman collection defines the exact Content Signing Service routes for document registration, hash creation, and signature embedding. The examples below use configurable route variables for those local service calls:
export CSS_REGISTER_DOCUMENT_PATH="/api/v1/document"
export CSS_CREATE_HASH_PATH="/api/v1/document/{document_id}"
export CSS_EMBED_SIGNATURE_PATH="/api/v1/document/{document_id}/signature"
If your Postman collection uses different paths, keep the request flow and payloads but replace these path values.
Authentication
For API-token authentication, send the API token with DigiCert ONE requests:
x-api-key: YOUR_API_TOKEN
Content-Type: application/json
For OAuth authentication, send the access token instead:
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
The code samples below use API-token authentication.
Optional: start Content Signing Service
Run Content Signing Service before you register documents or create hashes.
docker volume create --name=content-signing-service-data
docker volume create --name=content-signing-service-logs
docker run -d \
-e API_KEY="$API_TOKEN" \
-e DTM_BASE_URL="$DTM_BASE_URL" \
-v content-signing-service-data:/app/db \
-v content-signing-service-logs:/app/logs \
-p 8080:8080 \
--name content-signing-service \
repo.pkiplatform.digicert.com/dcone/documentmanager/clients/content-signing-service:latest
Workflow
- List signing credentials.
- Get credential information.
- Register the document.
- Generate the document hash.
- Authorize the credential and obtain Signature Activation Data (SAD).
- Sign the hash.
- Embed the signature into the document.
- Download and validate the signed document.
Step 1: List signing credentials
Retrieve the credentials available to your account and choose the credentialID you want to use for signing.
curl --request POST "$DTM_BASE_URL/api/v1/credentials/list" \
--header "x-api-key: $API_TOKEN" \
--header "Content-Type: application/json" \
--data '{}'
Example response:
{
"credentialIDs": [
"d9f6f7f8-1111-2222-3333-0a1b2c3d4e5f"
]
}
Save one value as CREDENTIAL_ID:
export CREDENTIAL_ID="d9f6f7f8-1111-2222-3333-0a1b2c3d4e5f"
Step 2: Get credential information
Retrieve details for the selected credential, including the certificate chain and supported signing algorithms.
curl --request POST "$DTM_BASE_URL/api/v1/credentials/info" \
--header "x-api-key: $API_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"credentialID\": \"$CREDENTIAL_ID\",
\"certificates\": \"chain\",
\"certInfo\": true,
\"authInfo\": true
}"
Example response fields to save:
{
"key": {
"algo": ["1.2.840.113549.1.1.1"],
"len": 3072
},
"cert": {
"certificates": ["BASE64_CERT", "BASE64_INTERMEDIATE", "BASE64_ROOT"]
},
"SCAL": "2",
"multisign": 1
}
Use a signing algorithm supported by the credential. For RSA with SHA-256, the signing algorithm is commonly represented as:
export SIGN_ALGO="1.2.840.113549.1.1.11"
export HASH_ALGO="2.16.840.1.101.3.4.2.1"
Step 3: Register the document
Register the PDF or XML document with Content Signing Service before creating the hash.
For a visible PDF signature, include the signature rectangle and display text. Coordinates are measured in PDF points from the lower-left corner of the page.
REGISTER_URL="$CSS_BASE_URL$CSS_REGISTER_DOCUMENT_PATH"
curl --request POST "$REGISTER_URL" \
--header "Content-Type: application/json" \
--data "{
\"document_type\": \"PDF\",
\"signature_profile\": \"PAdES-B-T\",
\"tsa_url\": \"$TSA_URL\",
\"signature_rectangle\": {
\"page\": 1,
\"x\": 72,
\"y\": 72,
\"w\": 220,
\"h\": 80
},
\"signature_text1\": \"Digitally signed by Example Signer\",
\"signature_text2\": \"Reason: Document approval\",
\"reason\": \"Document approval\",
\"contact\": \"signer@example.com\",
\"type\": \"NOT_CERTIFIED\",
\"preservation_size\": 16384
}"
Example response:
{
"document_id": "8d845ce8-2222-4444-8888-5f9d6b0c12a1"
}
Save the document_id:
export DOCUMENT_ID="8d845ce8-2222-4444-8888-5f9d6b0c12a1"
For XML signing, register the document with XML settings instead of PDF appearance settings:
{
"document_type": "XML",
"signature_profile": "XAdES-B-T",
"canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#",
"xades_signature_type": "ENVELOPED",
"tsa_url": "http://ts.quovadisglobal.com/eu"
}
Step 4: Generate the document hash
Upload the registered document to Content Signing Service. The service prepares the signature container and returns the hash that must be signed.
CREATE_HASH_PATH="${CSS_CREATE_HASH_PATH/\{document_id\}/$DOCUMENT_ID}"
CREATE_HASH_URL="$CSS_BASE_URL$CREATE_HASH_PATH"
curl --request POST "$CREATE_HASH_URL" \
--form "file=@$INPUT_FILE"
Example response:
{
"document_id": "8d845ce8-2222-4444-8888-5f9d6b0c12a1",
"hash": "BASE64_DOCUMENT_HASH",
"hash_algorithm": "2.16.840.1.101.3.4.2.1",
"signing_algorithm": "1.2.840.113549.1.1.11"
}
Save the returned values:
export DOCUMENT_HASH="BASE64_DOCUMENT_HASH"
export HASH_ALGO="2.16.840.1.101.3.4.2.1"
export SIGN_ALGO="1.2.840.113549.1.1.11"
Step 5: Authorize the credential
Authorize the credential to sign the hash. This request starts the Go>Sign Mobile authorization flow.
curl --request POST "$DTM_BASE_URL/api/v1/credential/authorize" \
--header "x-api-key: $API_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"credentialID\": \"$CREDENTIAL_ID\",
\"numSignatures\": 1,
\"hash\": [
\"$DOCUMENT_HASH\"
],
\"description\": \"Sign $INPUT_FILE\"
}"
Approve the authorization request in Go>Sign Mobile.
Example response:
{
"SAD": "BASE64_SIGNATURE_ACTIVATION_DATA",
"expiresIn": 3600
}
Save the SAD:
export SAD="BASE64_SIGNATURE_ACTIVATION_DATA"
Step 6: Sign the hash
Submit the hash, signing algorithm, credential ID, and SAD to generate the digital signature.
curl --request POST "$DTM_BASE_URL/api/v1/signatures/signHash" \
--header "x-api-key: $API_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"credentialID\": \"$CREDENTIAL_ID\",
\"SAD\": \"$SAD\",
\"hash\": [
\"$DOCUMENT_HASH\"
],
\"hashAlgo\": \"$HASH_ALGO\",
\"signAlgo\": \"$SIGN_ALGO\"
}"
Example response:
{
"signatures": [
"BASE64_SIGNATURE_VALUE"
]
}
Save the returned signature:
export SIGNATURE="BASE64_SIGNATURE_VALUE"
Step 7: Embed the signature
Send the signature back to Content Signing Service so it can embed the signature into the prepared document.
EMBED_SIGNATURE_PATH="${CSS_EMBED_SIGNATURE_PATH/\{document_id\}/$DOCUMENT_ID}"
EMBED_SIGNATURE_URL="$CSS_BASE_URL$EMBED_SIGNATURE_PATH"
curl --request POST "$EMBED_SIGNATURE_URL" \
--header "Content-Type: application/json" \
--output "$OUTPUT_FILE" \
--data "{
\"signature\": \"$SIGNATURE\",
\"hash\": \"$DOCUMENT_HASH\",
\"hash_algorithm\": \"$HASH_ALGO\",
\"signing_algorithm\": \"$SIGN_ALGO\",
\"sad\": \"$SAD\"
}"
The response body is the signed PDF or XML document. Save it as your final signed file.
Verify the results
For PDF documents, open the signed file in Adobe Acrobat Reader and verify that the signature is valid.
For XML documents, use an XML signature validation tool that supports your selected XAdES profile.
xmlsec1 --verify "$OUTPUT_FILE"
Next steps
Reauthorization
Go>Sign Mobile authorization remains valid until the configured authorization limit is reached.
| Environment | Authorization limit |
|---|---|
| Demo | 250,000 hashes or 30 days |
| Production | 1,000,000 hashes or 95 days |
After authorization expires, repeat the authorization step before signing more documents.
Demo environment trust
Documents signed in the DigiCert ONE demo environment may appear untrusted because demo certificates are not trusted by default.
To display a trusted signature in Adobe Acrobat Reader, import and trust the demo certificate chain.