Skip to content

Sign a PDF with a PAdES baseline signature (moved)

The signing walkthrough that used to be on this page is now superseded. Use the canonical recipe instead:

Sign a PDF with PAdES B-B, then extend to PAdES B-T

An earlier version of this page said the high-level Document::setSignature()save() path was not wired and threw NotImplementedException. That is no longer true. The high-level path now writes a real signature.

Document::setSignature($cert, SignatureLevel::PAdES_B_B)->save() (and the equivalent output() / getPdfData()) writes a /Sig field with a /ByteRange and a Distinguished Encoding Rules (DER)-encoded Cryptographic Message Syntax (CMS) SignedData object in the signature dictionary Contents entry. That is the structure ISO 32000-2 §12.8 specifies for the ETSI.CAdES.detached SubFilter. The result is CMS-verifiable: a standard CMS/PKCS#7 (Public-Key Cryptography Standards #7) verifier parses and checks it.

  • B-B — the Core level — is produced directly through this path.
  • B-T adds one RFC 3161 signature-time-stamp when you pass a TsaClient on the same call.
  • B-LT / B-LTA are reachable through the same high-level path (setSignature($cert, SignatureLevel::PAdES_B_LTA, $tsaClient)->save()) when the Pro and Enterprise packages are installed; without them, the call fails closed instead of writing a partial long-term revision. Encrypted documents also fail closed for B-LT/B-LTA.

The lower-level NextPDF\Security\Signature\DigitalSigner path is still supported. The canonical recipe below walks through it end to end. The high-level path is a thin convenience over the same signing engine. The integration suite exercises both paths and produces a real, parseable CMS object.

U-1 caveat (scope of the claim). “CMS-verifiable” means the produced object is a well-formed CMS SignedData per RFC 5652 and ISO 32000-2 §12.8. It is not an assertion of ETSI EN 319 142-1 baseline-profile conformance or legal validity. The baseline-levels part of that standard is not in the verification corpus; the B-T signature-time-stamp requirement was checked against ETSI EN 319 122-1 §5.3 with RFC 3161, RFC 5652, RFC 5816, and ISO 32000-2 §12.8. B-LT/B-LTA produce the long-term-validation structure (a DSS dictionary plus a DocTimeStamp revision); they are not advertised as profile-conformance-tested. An independent validator determines conformance and legal validity.

The structural facts the old page asserted about the on-disk artifact remain correct. The replacement recipe restates them with evidence:

  • The signature value is stored in the signature dictionary Contents entry (ISO 32000-2 §12.8.1).
  • The digest is computed over the ByteRange and excludes the signature value itself (ISO 32000-2 §12.8.1).

This page does not assert that any resulting signature is legally valid. Legal validity depends on the certificate, its trust anchor, and the verifier’s policy. All of those live outside this library.