How-to guide

Preparing the document

Everything in this chapter happens before the first signature. After it, any change to the AcroForm or the page content is a modification of a signed document, and Adobe says so. The starting point is what a form filler delivers: a filled-in form with text fields and /NeedAppearances true. Three of the real files we have looked at went wrong by skipping one of these five steps.

This is independent of language or library. Every PAdES implementation has to put the same bytes in the same places; how you get them there is up to you.

0.1 Finish the form

In the PDF Fill the fields, then flatten the form, or at the very least make every field read-only (/Ff bit 1). Fields left open under a signature stay editable afterwards as "form filling", which does not break the signature: what a reader sees is then no longer necessarily what was signed.

Flattening removes the fields and draws their appearance streams into the page content. It is the simplest fix and takes the whole class of problems away, including 0.2. Choose read-only instead only when a downstream system has to read the field values back out of the AcroForm.

0.2 Remove /NeedAppearances

In the PDF Delete the entry from the AcroForm dictionary or set it to false. With the flag on true, Adobe Reader regenerates the appearance of every field when the file opens and ignores signed /Sig fields while doing so: the signature is invisible in Acrobat, while validators and other viewers show it (known as PDFBOX-3738). The filled text fields already carry their own /AP /N, so nothing changes visually.

This is the one fix that cannot be applied afterwards without Acrobat flagging the document as changed after signing.

0.3 Create the signature field

In the PDF A field with /FT /Sig, its widget as an /Annot on a page and listed in /AcroForm /Fields, and /SigFlags 3 on the AcroForm (signatures exist, append only). For an invisible signature use /Rect [0 0 0 0]; for a visible one give the widget an appearance stream now, because it is inside the signed byte range.

For several signers, create a field per signer now, or let each signing pass add its own; both work. If you create them up front, read 0.4 for the lock.

0.4 Lock the fields (FieldMDP)

In the PDF Put a lock on the first signature field. When that field is signed, the lock becomes a FieldMDP transform in the /Reference of the signature dictionary: after this signature the existing form fields are frozen. New signature fields, DSS updates and document timestamps stay allowed, which is exactly what an extension to B-LT and B-LTA adds later.

/Lock << /Type /SigFieldLock /Action /All >>

If you created empty signature fields for other signers in 0.3, use /Action /Include /Fields [...] naming only the form fields; /All would lock those empty signature fields too. Do not use a DocMDP certification with /P 1: it forbids the LT and LTA updates as well. If your library cannot set a lock, flattening in 0.1 is the alternative.

0.5 Set up the signature dictionary

In the PDF /Filter /Adobe.PPKLite, /SubFilter /ETSI.CAdES.detached, /M with the claimed signing time, /Contents as a hex string of fixed length, and a /ByteRange that is filled in after writing. Reserve generously: the certificate, its chain and, at B-T, the timestamp token all end up in that same CMS, so 8 to 10 kB is the real need and 32768 is a safe, common choice. Too small cannot be repaired without signing again. B-LT and B-LTA do not grow this field; they add their own revisions, and each document timestamp brings its own /Contents.

What this leaves open

Whatever level you aim for later, the preparation must keep three things possible:

  • Append-only. Every level above B-B is an incremental update. Never "save as" or rewrite the file in between.
  • No DocMDP /P 1. A document timestamp is a new field added to /AcroForm /Fields and to a page's /Annots. A FieldMDP lock on the form fields is no obstacle: it freezes existing fields, not the adding of new ones.
  • Room. The reserved /Contents size from 0.5, and no assumptions about the file ending where it ends now.

Then continue with the flow: the prepared file is the input of step 1.