Digital signature verification in PDF
How Constaia verifies the PAdES electronic signature of a PDF: integrity, chain of trust and later changes, the signature object, require_valid_signature and what it doesn't check yet.
Many official certificates are downloaded from an e-government site as a signed PDF: the Spanish sexual offences and criminal record certificates, AEAT and Social Security compliance certificates, the work history report… That signature is the best proof that the document hasn't been touched. Constaia verifies it on every PDF you analyse, at no extra cost and without sending the file to any third party.
What it checks
- That there is a signature. It finds the PDF's electronic signatures (PAdES / CMS) and its revisions.
- Integrity. It recomputes the digest of the signed bytes and compares it with the one inside the signature. If they don't match, the content changed and the signature is broken. Then it verifies the cryptographic signature (RSA, RSA-PSS, ECDSA or Ed25519, with SHA-1 to SHA-512).
- Signer and time. It reads the signer's certificate (name, organisation, issuer, validity) and the signing time: the timestamp's if there is one, otherwise the one declared in the signature. It checks the certificate was valid at that moment.
- Chain of trust. It builds the chain from the signer's certificate to a root authority, verifying every link, and checks that it reaches one on the trust list.
- Later changes. If the PDF has revisions added after signing, it looks at what they add: another signature,
long-term validation data (LTV) or a timestamp don't count; anything else is
document_modified_after_signing.
The PDF metadata is also checked for signs of editing: a known producer (iLovePDF, Smallpdf, Sejda, PDF24, Acrobat,
Word, LibreOffice, Canva, Photoshop…), a modification date much later than the creation date, or a signature
"inherited" from a PDF that was rewritten. If there are signs, you get the edited_suspected warning in warnings and
as a reason with warning.
The signature object
Only present for PDFs (null for images):
{
"status": "valid",
"reasons": ["signature_valid"],
"signer": "SELLO ELECTRONICO DEL MINISTERIO DE JUSTICIA",
"issuer": "AC Sector Público",
"signed_at": "2026-09-28T09:14:03Z",
"trusted": true,
"trust_anchor": "AC RAIZ FNMT-RCM",
"signatures": 1
}| Field | Description |
|---|---|
status | Overall result: valid, invalid, modified, untrusted or missing. |
reasons | Result codes (see the table below). |
signer | Signer's name (certificate CN or, if missing, the organisation). |
issuer | Authority that issued the signer's certificate. |
signed_at | Signing time: the timestamp's if there is one; otherwise the declared one. null if unknown. |
trusted | true if the chain reaches the trust list. |
trust_anchor | Name of the trust-list authority the chain reaches. |
signatures | Number of signatures in the PDF. The other fields refer to the last one. |
Statuses and reasons
status | Reason in verdict.reasons | What it means | Without require_valid_signature | With require_valid_signature |
|---|---|---|---|---|
valid | signature_valid | Intact signature, no later changes, from a trusted issuer. | info | info |
invalid | signature_invalid | The signature is broken: the content doesn't match what was signed or the cryptographic signature is wrong. | error | error |
modified | document_modified_after_signing | The signature is correct, but the PDF was modified afterwards. | warning | error |
untrusted | untrusted_signer | The signature is intact, but the certificate doesn't reach the trust list. | warning | error |
missing | signature_missing | The PDF is not signed. | warning for types that are usually signed (signed_pdf: true); nothing otherwise | error |
Reasons go in verdict.reasons, so they only appear if you send expect. The signature object is always returned.
Requiring a valid signature: require_valid_signature
curl https://api.constaia.com/v1/analyze \
-H "Authorization: Bearer $CONSTAIA_API_KEY" \
-F file=@sexual_offences_certificate.pdf \
-F 'options={
"expect": "es_sexual_offences_certificate",
"checks": { "require_valid_signature": true, "max_age_days": 90 },
"language": "en"
}'With require_valid_signature: true, anything other than signature_valid leads to invalid. A photo, a scan or a
"print to PDF" can never pass: they lose the signature, and the reason is signature_missing with error. Use it
when you only accept the original PDF downloaded from the e-government site; if you accept photos, leave it off and
review the review cases.
Types that are downloaded signed have signed_pdf: true in the catalogue:
es_sexual_offences_certificate, es_criminal_record_certificate, es_work_history,
es_aeat_tax_compliance_certificate, es_social_security_compliance_certificate, es_aeat_census_certificate,
es_aeat_tax_id_card, es_aeat_income_certificate, es_social_security_number_document and mx_rfc_certificate. On
any other PDF the signature is verified too and shown in signature.
Check who signed
A valid, trusted signature proves who signed, not that the document is the one you expect. Compare
signature.signer with the body that should issue it: a PDF correctly signed with someone else's certificate is also
valid.
Trust list
The trust list starts from the Spanish qualified root authorities: AC RAIZ FNMT-RCM, ACCV (ACCVRAIZ1), Firmaprofesional and ANF. Most Spanish public administration certificates chain to them. To complete the chain, Constaia uses the certificates carried in the PDF itself and the intermediate authorities it has configured.
A PDF signed by a provider from another country, or whose chain can't be completed, is untrusted (untrusted_signer)
even if the signature is intact. If you need to accept signatures from other providers, write to
hola@constaia.com.
What it doesn't check yet
Coming soon: revocation (OCSP/CRL)
Constaia does not yet check whether the signer's certificate has been revoked (neither OCSP nor CRL revocation lists). A certificate revoked after issuance, but still within its dates, looks valid.
- No European trusted list (TSL). Only the authorities on Constaia's trust list count as trusted.
- Heuristic change analysis. Revisions added after the signature are inspected, but the PDF's modification permissions (DocMDP) are not fully evaluated.
- No CSV lookup. The secure verification code is validated for format only (
csv_format); Constaia doesn't look it up on the issuer's site. - Original file only. A scan, a photo or a regenerated PDF loses the signature.
edited_suspectedis a signal to review, not proof of fraud.
In test mode
The signature and metadata are not simulated: they are analysed on the file you send, also with ck_test_ keys. An
unsigned PDF of a type with signed_pdf: true gives signature_missing and review. See Test mode.
Next steps
Checks
Reference for every checks option (expiry, issue age, holder age, holder, signature, amounts) and the deterministic NIF, MRZ, IBAN and invoice validations.
Errors
Constaia API error format, every error code by HTTP status, the JavaScript and PHP SDK error classes and which errors are safe to retry.