PDFPipe

Signatures, encryption and attachments / Digital signature fields

Adding a digital signature field to a PDF

A form field holding a cryptographic signature over the file, which proves who signed it and that nothing has changed since.

Where this API stands

This is not something a renderer emits. It is applied to a finished file by a step that comes after rendering, so the honest answer is about where the boundary falls. This API creates no /AcroForm, no signature field and no signature dictionary, and it does not sign. There is nothing in the options that touches any of this, and signing during rendering would not be the right design anyway: a signature covers the final bytes of the file, so it has to be applied after every other step. What is worth knowing is the interaction with the one security feature this API does have. Password protection is applied as an incremental update after rendering, and applying it to a file that is already signed invalidates the signature, because the bytes covered by /ByteRange have changed.

What the standard requires

The requirements as a checker enforces them, rather than as a procurement document paraphrases them. A file satisfies all of these or it satisfies none of them.

  • An /AcroForm in the catalogue with a signature field in /Fields, whose widget annotation places the visible appearance on a page.
  • A signature dictionary with /ByteRange covering the whole file except the signature itself, and /Contents holding the detached signature in that gap.
  • /SubFilter naming the signature format, in practice adbe.pkcs7.detached or ETSI.CAdES.detached for a PAdES signature.
  • A signing certificate that chains to a trust anchor the verifier recognises, which is the part that decides whether the signature shows as valid or as valid-but-untrusted.
  • Signature Field Lock or a DocMDP entry if the signature is meant to restrict what can be changed afterwards, because a plain approval signature does not.

Who asks for this

Contracts, regulatory filings, anything where a party has to be able to prove the document they hold is the document that was sent. In the EU, qualified electronic signatures under eIDAS carry specific legal weight, which is why the requirement usually arrives with a specific certificate type attached rather than as a general request for signing.

What it looks like in a file

The concrete form of the thing being described, so you can recognise it in a document you have been handed rather than only in a specification.

text
% The signature dictionary. /ByteRange covers the file in two runs,
% skipping the gap where /Contents sits, because a signature cannot
% cover itself.

<<
  /Type /Sig
  /Filter /Adobe.PPKLite
  /SubFilter /ETSI.CAdES.detached
  /ByteRange [0 74821 92205 3184]
  /Contents <308206...>          % detached signature, hex, in the gap
  /M (D:20260908T142211+05'30')
  /Reason (Approved for issue)
>>

What to do about it

Sign after rendering, as the last step or as close to it as the pipeline allows, and never modify the file afterwards. Open-source options include the DSS library from the European Commission, which handles PAdES properly, and pyHanko in Python. Commercial signing services will do it over an API if you would rather not hold the key. If you need both a password and a signature, apply the password first and sign the encrypted file, not the other way round.

How to check a file rather than assume

Acrobat's signature panel is the reference implementation for how a signature will be perceived, because it is what most recipients use. The EU DSS demonstration validator checks a signature against the European Trusted Lists and reports the qualification level, which is the answer if eIDAS is the reason you are signing. `pdfsig` from Poppler gives a quick command line check of the signature and the certificate chain.

The mistake people make here

Doing anything to the file after signing. Adding metadata, linearizing, applying a password, or merging the document into a bundle all change the bytes and break the signature. The break is silent in the sense that nothing errors: the file opens fine and the signature panel says the document has been altered, which is exactly what you were trying to prove had not happened.

Frequently asked

Does this API produce Digital signature fields?

A step after rendering. This API creates no /AcroForm, no signature field and no signature dictionary, and it does not sign. There is nothing in the options that touches any of this, and signing during rendering would not be the right design anyway: a signature covers the final bytes of the file, so it has to be applied after every other step. What is worth knowing is the interaction with the one security feature this API does have. Password protection is applied as an incremental update after rendering, and applying it to a file that is already signed invalidates the signature, because the bytes covered by /ByteRange have changed.

Can I turn on the pdf_a option and be done?

No. The option writes an XMP packet declaring PDF/A-1b into the document catalogue, and the render response comes back carrying a warning that says in as many words that this is best-effort and that full conformance requires tagged structure and an embedded ICC profile. It is a claim written into the file, not a certificate earned by it, and a validator checks the claim against the bytes. Read the warning array in the response rather than taking the absence of an error as a pass.

Should I convert before rendering or after?

After, always. A conformance converter rewrites colour, embeds profiles, sets boxes and stamps metadata on a finished PDF. Trying to satisfy a conformance target from the source side means guessing at what the converter would have done, and the guesses that go wrong are expensive: flattening transparency you did not need to flatten changes what the page looks like.

Standards this one is confused with

The neighbours that matter are the ones people mistake for this, not the ones that sort next to it.

Conformance is decided after a file exists. Render the document, then check it, then convert only what the checker actually flags.