Skip to content
Signing

Signing

Signing a PDF with UniPDF always goes through model.PdfAppender. The appender writes an incremental update over the original bytes instead of rewriting the file, so earlier revisions survive and a signature that was already on the document keeps validating. One consequence catches people early: the reader you build the appender from needs a seekable source. model.NewPdfAppender returns an error unless the reader was created from something that implements both io.ReadSeeker and io.ReaderAt, such as an *os.File or a *bytes.Reader.

The handler you pass to model.NewPdfSignature decides the signature format. sighandler.NewAdobePKCS7Detached covers ordinary PKCS#7 signing. The NewEtsiPAdES* constructors produce PAdES signatures, which are graded by level.

LevelConstructorWhat it adds over the level above
B-BNewEtsiPAdESLevelBThe signature itself, covering the document.
B-TNewEtsiPAdESLevelTA trusted timestamp from a TSA, evidence of when the signature existed.
B-LTNewEtsiPAdESLevelLTCertificates, CRLs and OCSP responses, written into the document security store so the signature can still be validated once those are no longer reachable online.
B-LTANewEtsiPAdESLevelLT, then NewDocTimeStampA document timestamp over the whole file, which extends the life of the validation data.

Each level is the one before it plus the extra material, so B-LT is also timestamped and B-T is also a valid B-B signature.

B-LTA is the odd one. sighandler.EtsiPAdESLevel defines only LevelB, LevelT and LevelLT, so there’s no constructor to ask for it. You reach B-LTA by signing at B-LT, writing the result, then opening that output with a fresh reader and appender and adding a second signature built from sighandler.NewDocTimeStamp. The pdf_sign_pades_b_lta.go example does exactly that, with an intermediate pass that carries the DSS across via appender.GetDSS and appender2.SetDSS.

Level LT also needs the appender itself. NewEtsiPAdESLevelLT takes one as its last argument, and initializing the signature fails with “appender must not be nil for Level LT signature handler” if it’s missing. ECDSA keys have their own constructors (NewEtsiPAdESLevelBEcdsa and friends) and require PDF 2.0 or later.

The visible mark on the page is a separate concern from the cryptography. annotator.NewSignatureField builds the appearance, and passing a rectangle of zeros gives you a valid signature with nothing drawn.

Worked examples for each of these live in the signature guides.

Last updated on