Skip to content
Signature

Signature

Signing a PDF in UniPDF is an incremental update. model.PdfAppender copies the original bytes through untouched and appends a new revision containing the signature, so the digest the signature covers stays valid and any earlier signature keeps verifying. That is the reason signing never goes through PdfWriter: a writer rebuilds the file, which invalidates every signature already in it.

Four objects are involved, and it helps to know which one owns what.

appender, err := model.NewPdfAppender(reader)

handler, err := sighandler.NewAdobePKCS7Detached(privateKey, cert)

signature := model.NewPdfSignature(handler)
signature.SetName("Jane Doe")
signature.SetReason("Approval")
signature.SetDate(time.Now(), "")
if err := signature.Initialize(); err != nil {
    return err
}

field, err := annotator.NewSignatureField(signature, lines, opts)
field.T = core.MakeString("Approval signature")

if err := appender.Sign(1, field); err != nil {
    return err
}
return appender.WriteToFile(outputPath)

The handler holds the key and decides the cryptography: which /SubFilter is written, how the digest is computed, and how much space /Contents needs. The signature dictionary holds the metadata a reader displays, name, reason, location and date, plus the certificate chain in /Cert for the handlers that use it. The field is the visible part: a widget annotation with an appearance stream, a rectangle and a page. The appender ties them together and produces the bytes.

Ordering matters in two places. signature.Initialize() must run before the appender writes, because that is what asks the handler to reserve space for the signature, and it is where a handler built without a private key fails. And PdfAppender.Write can only be called once, so a second signature means writing, reopening the result, and starting again.

Choosing a handler

Handler/SubFilterUse it for
sighandler.NewAdobePKCS7Detachedadbe.pkcs7.detachedThe default choice. The signing certificate and signing time travel inside the PKCS#7 blob.
sighandler.NewAdobePKCS7DetachedEcdsaadbe.pkcs7.detachedAn EC key. Defined by PDF 2.0; see ECDSA.
sighandler.NewAdobeX509RSASHA1adbe.x509.rsa_sha1Older readers, or when the chain has to sit in /Cert. Defaults to SHA-1.
sighandler.NewAdobeX509RSASHA1CustomWithOptsadbe.x509.rsa_sha1Signing by a remote service or an HSM, through a SignFunc. Set Algorithm for SHA-256; the default is SHA-1.
sighandler.NewEtsiPAdESLevelB and friendsETSI.CAdES.detachedPAdES baseline conformance, up to LTA.
sighandler.NewDocTimeStampWithOptsETSI.RFC3161A document timestamp rather than an identity signature. Set SignatureSize to fit the TSA’s token.
sighandler.NewDocMDPHandlerwraps anotherCertifying a document with a modification policy.

Every constructor also accepts nil for the key and certificate, which produces a validation-only handler. PdfReader.ValidateSignatures picks the first handler in the list whose /Filter and /SubFilter match, so order the list from most specific to least.

Appearance

A signature does not have to be visible. Building the field with model.NewPdfFieldSignature and a zero-sized Rect skips the appearance entirely, which is what a document timestamp wants. When it should be visible, annotator.NewSignatureField builds the appearance stream from a slice of annotator.SignatureLine and a annotator.SignatureFieldOpts, and the styling is entirely independent of the signature: nothing in the box is read back from the signature dictionary. PdfAppender.SignWithAppearance is the alternative that draws the box from the signature’s name, date, reason and location.

One PdfSignature can back several fields on several pages. Field names must still be unique, and Sign only auto-names by page number, so set field.T yourself whenever a document gets more than one signature widget.

Validation

PdfReader.ValidateSignatures checks integrity only: the bytes match the signature under the certificate embedded in the file. It does not say who signed, and a self-signed certificate under any name passes. To decide whether the signer is someone you trust, call ValidateSignaturesWithOpts with your own trust roots. See Validating Signer Trust and Revocation.

Neither check says how much of the file was signed. Content appended after a signature leaves it intact and trusted, so check the coverage fields on the result too. See Checking What a Signature Covers.

Where to look

The guides are grouped the same way as the signature examples, one section per folder.

SectionCovers
SigningSigning with a key you hold: PKCS12, PEM chains, ECDSA keys, generated keys, timestamps, new pages, second signatures, encrypted files and reading back earlier revisions.
AppearanceThe visible signature box, with text, an image, or text generated from the signature.
External signingKeys you do not hold: a remote service, AWS KMS, Google Cloud KMS, GlobalSign DSS and HSMs.
PAdESThe PAdES baseline levels, B-B through B-LTA.
DocMDPCertifying a document with a modification policy.
ValidationIntegrity checks, signer trust and revocation, ByteRange coverage, and timestamps.
Long-term validationEmbedding certificates, OCSP responses and CRLs so signatures stay verifiable.
Last updated on