How to verify a PAdES signature (step by step)
PAdES verification is five checks tied to the signature's baseline level. What each one does, in order, and how to run all five in a single API call.
Verifying a PAdES signature means running five checks against the signature's own embedded data, in a fixed order — extract, check integrity, build the certificate chain, check revocation, and validate any timestamp. Which of the five actually resolve to a pass depends on the signature's baseline level: a bare B signature has no timestamp to validate; an LTA signature carries an archival timestamp precisely so all five still resolve decades later. Skipping the order matters — a chain check against a certificate that already failed integrity is meaningless.
This is PAdES-specific, not a generic PDF check. The signature lives inside the PDF's own byte structure, so "verifying a PAdES signature" and "verifying a PDF" are the same operation — but knowing the baseline level tells you in advance which of the five checks the signature was built to survive.
The five checks, in order
1. Extract. A PDF can hold more than one PAdES signature — each party in a multi-party contract typically adds their own, in sequence. Each is a separate /Sig dictionary with its own byte range, so extraction has to enumerate all of them before any check runs. Treat a document as having *N* independent results, one per signature, not one result for the file.
2. Integrity. For each signature, recompute the hash over the byte range that was signed and compare it to the value inside the SignedData structure. PDF supports incremental updates, so content can be appended *outside* an earlier signature's byte range without breaking it — a second signature added afterward is normal, not tampering. A change *inside* the range fails this check immediately, and nothing after it runs.
3. Chain. The signing certificate has to build to a trusted root. For an EU-qualified signature, that root sits on a national trusted list indexed by the EU List of Trusted Lists — 31 lists, refreshed daily. A self-signed certificate, or one issued by an authority absent from every trusted list, breaks the chain here and caps the result at AdES or lower, never QES.
4. Revocation. Check the signing certificate against OCSP or a CRL from the issuing authority. This is a live check unless the signature already embeds a revocation response as part of a long-term (LT or LTA) baseline — in which case the response travels with the file and no live lookup is needed to re-verify it later.
5. Timestamp. If the signature carries a trusted timestamp (baseline T and above), confirm it against a qualified TSA. This is what lets a signature stay valid after its certificate expires — the timestamp proves the signature existed before the expiry date, so an expired certificate does not automatically fail the signature. Without a timestamp, a verifier can only say the signature is valid *now*, not that it was valid at signing time.
Baseline level decides what you're checking
PAdES defines four baseline levels, and the level tells you which of the five checks have supporting data already embedded in the file:
- B (basic) — signature, certificate and byte range only. Checks 1–3 run; revocation and timestamp checks depend entirely on live lookups, which may no longer be possible for an old signature.
- T (timestamp) — adds a trusted timestamp at signing time. Check 5 resolves from embedded data.
- LT (long-term) — adds the full revocation data and certificate chain at signing time. Check 4 resolves from embedded data, not a live OCSP call.
- LTA (long-term with archive timestamp) — adds a periodic archival timestamp, re-anchoring the whole signature before the cryptographic algorithms used in it become obsolete.
A signature's signatureFormat reports which level it was built at — PAdES_BASELINE_LT is the common case for contracts meant to stay verifiable for years.
Doing all five in one call
Self-hosting EU DSS (esig/dss) covers this correctly — it is the reference implementation of the ETSI algorithm — but you're on the hook for instantiating a PAdESService, keeping your own LOTL cache refreshed, and decoding Indication/SubIndication output into something readable. A hosted API runs the same five checks and returns the result as one structured report:
``bash curl -X POST https://api.sealium.eu/v1/validate \ -H "Authorization: Bearer slm_live_xxxxxxxxxxxxxxxxxxxx" \ -F "file=@contract.pdf" ``
Each entry in the response's signatures array maps directly onto the five checks:
``json { "signatureId": "id-abc123", "signatureIntact": true, "certValid": true, "revocationOk": true, "timestampValid": true, "indication": "TOTAL_PASSED", "subIndication": null, "signatureLevel": "QES", "signatureFormat": "PAdES_BASELINE_LT" } ``
signatureIntact is check 2, certValid is check 3, revocationOk is check 4, timestampValid is check 5. indication is only TOTAL_PASSED when all four booleans hold; anything else lands in TOTAL_FAILED or INDETERMINATE, with subIndication giving the ETSI reason code. The document itself is processed in memory and never stored — only this report is persisted. The full field list, including the nested certChain and timestamps arrays, is in the API reference. The free tier covers 100 validations a month, no credit card.
Multi-signature PDFs
A contract signed by three parties in sequence produces three SignatureInfo entries, each independently valid or not. A later signer's incremental update doesn't touch an earlier signer's byte range, so an earlier signature failing has no bearing on a later one passing, and vice versa. Report each one on its own terms — validSignaturesCount out of signaturesCount in the response tells you at a glance whether the document is fully signed off or only partially.
FAQ
What does PAdES_BASELINE_LT actually mean for verification? It means checks 3 and 4 (chain and revocation) can resolve from data embedded in the file itself, without a live OCSP or CRL call. That matters for a signature you're re-verifying years after signing, once the original issuing authority's OCSP responder may no longer answer for that certificate.
Is a PAdES signature still valid if the certificate has since expired? Yes, provided the signature carries a trusted timestamp from before the expiry date — that's what check 5 exists to prove. Without a timestamp, an expired certificate leaves the result INDETERMINATE rather than a clean pass or fail, because there's no way to confirm the signature existed while the certificate was still valid.
Does the order of the five checks matter, or can they run in parallel? Integrity has to run first — a signature that fails the byte-range hash check is definitionally not the data that was signed, so a chain or revocation result computed against it is meaningless. Chain, revocation and timestamp can, in principle, run independently of each other once integrity passes.
Can a PAdES signature reach QES without a qualified timestamp? Yes — the timestamp affects long-term validity, not the qualification level itself. signatureLevel reaches QES based on the certificate being qualified and the signing device meeting QSCD requirements; the timestamp is what keeps that QES status checkable after the certificate expires.
Validate your first document free
100 validations a month, every eIDAS format, no credit card. See the full report for one of your own documents in under two minutes.
Start for free