Ask Anvil

Answers to questions about automating PDFs, e-signatures, Webforms, and other paperwork problems.
E-signatures
Categories

How do I add a certificate-based digital signature to a PDF in Python?

Use pyHanko (pip install pyHanko). Load your certificate and private key from a PKCS#12 file (.p12 or .pfx), open the PDF with an incremental writer, and sign:

from pyhanko.sign import signers
from pyhanko.sign.fields import SigFieldSpec
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter

signer = signers.SimpleSigner.load_pkcs12(
    pfx_file="signer.p12", passphrase=b"changeit"
)

with open("contract.pdf", "rb") as inf:
    w = IncrementalPdfFileWriter(inf)
    meta = signers.PdfSignatureMetadata(
        field_name="Signature1",
        reason="Approved",
        location="San Francisco, CA",
    )
    pdf_signer = signers.PdfSigner(
        meta,
        signer=signer,
        new_field_spec=SigFieldSpec("Signature1", box=(50, 50, 250, 100)),
    )
    with open("contract-signed.pdf", "wb") as outf:
        pdf_signer.sign_pdf(w, output=outf)

For local testing, OpenSSL can make a self-signed certificate and bundle it into a .p12:

openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem \
  -days 365 -subj "/CN=Test Signer"
openssl pkcs12 -export -inkey key.pem -in cert.pem -out signer.p12 -passout pass:changeit

What the code does

IncrementalPdfFileWriter appends the signature to the end of the file as an incremental update instead of rewriting it. The original bytes stay untouched, which is what you want if the PDF already carries other signatures.

SigFieldSpec creates a new signature field named Signature1 on the first page, drawn inside the box (lower-left x, lower-left y, upper-right x, upper-right y, in PDF points). Leave out box and you get an invisible signature: the field still exists, it just has no visible widget. If the PDF already has an empty signature field, pass its name as field_name and drop new_field_spec.

Reason and location are optional strings written into the signature dictionary.

Check that it worked

pyHanko can validate the result. Since the test certificate is self-signed, tell the validator to trust it explicitly:

from asn1crypto import pem, x509
from pyhanko.pdf_utils.reader import PdfFileReader
from pyhanko.sign.validation import validate_pdf_signature
from pyhanko_certvalidator import ValidationContext

with open("cert.pem", "rb") as f:
    _, _, der = pem.unarmor(f.read())
vc = ValidationContext(trust_roots=[x509.Certificate.load(der)])

with open("contract-signed.pdf", "rb") as f:
    sig = PdfFileReader(f).embedded_signatures[0]
    status = validate_pdf_signature(sig, vc)
    print(status.intact, status.valid, status.trusted)  # True True True

intact means the signed bytes have not changed, valid means the cryptographic signature checks out, and trusted means the certificate chains to a root you trust. Change a single byte inside the signed range and intact flips to False.

Caveats

A self-signed certificate still proves the file was not modified, but nobody else's software trusts it by default, which is why the check above had to add it as a trust root by hand. Adobe Acrobat and Reader trust signatures that chain to the Adobe Approved Trust List (AATL), so for signatures that validate in Acrobat without any setup on the recipient's side, use a certificate issued by a CA on that list.

The signing time pyHanko records comes from the signer's own clock. If the document has to stand up years later, add an RFC 3161 timestamp from a trusted timestamping authority by passing a timestamper:

from pyhanko.sign import timestamps

pdf_signer = signers.PdfSigner(
    meta,
    signer=signer,
    timestamper=timestamps.HTTPTimeStamper("https://your-tsa.example.com"),
)

Finally, a certificate-based digital signature answers "was this file changed, and which key signed it." It does not, on its own, capture a person's consent to sign or an audit trail of how they were identified. If you are collecting signatures from customers or employees, you still need that workflow layer on top, whether you build it or use an e-signature service.

Back to All Questions

The fastest way to build software for documents

Anvil Document SDK is a comprehensive toolbox for product teams launching document flows where PDF filling, signing, and complex conditional scenarios are necessary.
Explore Anvil
Anvil Webforms
Marketing Mode