# PD4ML PDF Signing

PD4ML PDF Signing adds digital signatures to existing PDF files, from Java code or from the command line. The signature is appended as an incremental update: every byte of the original file stays unchanged, and the signature field, the CMS signature and an optional visible appearance are written after it. The private key can come from a PKCS#12 keystore, a PKCS#11 hardware token or HSM, or a cloud KMS.

{% hint style="version" %}
Available from **PD4ML v4.1.1**, in the `com.pd4ml.pdf.sign` package. It uses BouncyCastle (`bcprov`/`bcpkix`) for the cryptography, so the BouncyCastle jars must be on the classpath.
{% endhint %}

## What you can do with it

- **Sign a PDF** with an invisible signature, or with a visible signature widget showing a stamp image (PNG/JPEG), caption text, or both, at a given page and rectangle.
- **Use the key where it lives**: a PKCS#12 (`.p12`/`.pfx`) file, a PKCS#11 token or HSM (the key never leaves the token), or a cloud KMS through the one-method `RemoteSigner` interface (API only, not in the command-line tool).
- **Certify a document** (DocMDP) at one of three levels: no changes allowed, form filling allowed, or form filling and annotations allowed. Only the first signature on a document can certify it.
- **Co-sign**: add further signatures to an already signed, uncertified document, each in its own signature field.
- **Add an RFC 3161 timestamp** from a TSA, with optional HTTP Basic Auth.
- **Add long-term validation (PAdES-LT)**: embed the certificate chain and OCSP responses and/or CRLs in a `/DSS` dictionary, right after signing or later, on a PDF signed by this tool or by any other PAdES-compliant signer.
- **Choose the digest**: SHA-256 (default), SHA-384 or SHA-512; RSA or ECDSA follows from the certificate's key type.
- **List the signature fields** of a PDF with their status, signer data and certification level.

## Quick start

Sign a PDF with a PKCS#12 key, a visible signature on the first page and a timestamp:

```java
import com.pd4ml.pdf.sign.*;
import java.io.File;

CertificateUtils.SigningIdentity identity =
        CertificateUtils.loadFromPkcs12(new File("signer.p12"), "changeit".toCharArray());

SigningOptions options = new SigningOptions()
        .setReason("Approved")
        .setSignerName("Jane Doe")
        .setTsaUrl("http://timestamp.digicert.com")
        .setVisibleSignatureOptions(new VisibleSignatureOptions()
                .setPage(0)                       // zero-based
                .setRectangle(36, 36, 220, 70)    // llx, lly, width, height in points
                .setVisibleText("Jane Doe"));

new PdfSigner().sign(new File("in.pdf"), new File("out.pdf"), identity, options);
```

Every failure is reported as a single checked `PdfSigningException`.

The same from the command line, with long-term validation added in the same call (on Windows, separate the classpath entries with `;`):

```bash
java -cp "pd4ml.jar:bouncycastle-runtime-1.84.jar" com.pd4ml.pdf.sign.cli.PdfSignCli sign in.pdf out.pdf \
     --p12=signer.p12 --password=changeit --reason=Approved --signer="Jane Doe" \
     --tsa=http://timestamp.digicert.com --visible --page=0 --rect=36,36,220,70 --text="Jane Doe" \
     --ltv
```

## When to use it

Use PD4ML PDF Signing when a finished PDF needs a digital signature, a certification or long-term validation data. The other PDF tools prepare documents; signing is normally the last step.

| Tool | Use it to |
|---|---|
| [PD4ML PDF COS](pd4ml-pdf-cos) | read, inspect, query and modify PDF objects; the foundation the other tools are built on |
| [PD4ML PDF Merge](pd4ml-pdf-merge) | combine page ranges from several PDFs into one |
| [PD4ML PDF Optimizer](pd4ml-pdf-optimizer) | make existing PDFs smaller |
| [PD4ML PDF XFDF](pd4ml-pdf-xfdf) | import and export form field values and annotations as XFDF |

A signature covers the exact bytes of the file as it was signed. Merge and the optimizer write a new file rather than an incremental update on top of the old one, so merge and optimize first, then sign. An encrypted input PDF is refused: the signer can read encrypted files but cannot write back into them. LTV data is added as a further incremental update and does not touch the signature.

## In this section

- [PD4ML PDF COS/Signing API - Programmer's Manual](pd4ml-pdf-signing/pd4ml-signing-manual): how a signature is applied, `PdfSigner`, `SigningOptions` and `VisibleSignatureOptions`, key sources, DocMDP certification, placeholder sizing, timestamps, PAdES-LT, error messages and thread safety.
- [Examples](pd4ml-pdf-signing/pd4ml-signing-examples): 18 runnable use-case classes, from a minimal invisible signature to PKCS#11, cloud KMS, co-signing and LTV on a PDF signed elsewhere.
- [pdfsigncli - Command-Line Reference](pd4ml-pdf-signing/pd4signcli-reference): the `inspect`, `fields`, `sign` and `ltv` commands, all options, exit codes and troubleshooting.
- [Javadoc for `com.pd4ml.pdf.sign`](https://pd4ml.com/javadoc/com/pd4ml/pdf/sign/package-summary.html): the API reference.
