Signing PDFs with PAdES levels
A PAdES (PDF Advanced Electronic Signatures) baseline level determines how much validation material a signature carries, which in turn determines how long it stays verifiable. Higher levels embed timestamps and, eventually, revocation data so the signature can be validated long after the signing certificate expires. This guide shows how to select a baseline level and how to choose the signature container format.
Common use cases include:
- Producing PAdES B-T signatures with a trusted timestamp for legal documents
- Meeting regulatory requirements for long-term validation and archival
- Choosing between the PAdES and classic CMS container formats
How Nutrient helps
Nutrient Java SDK handles the PAdES baseline levels and container formats behind a single property each. The SDK handles:
- Building the CMS/PKCS#7 signature container to the selected baseline profile
- Requesting and embedding RFC 3161 timestamps for B-T and above
- Embedding validation material for the long-term levels
- Writing the signature into the PDF using an incremental update
Baseline levels
The SignatureLevel enumeration selects the target profile:
PadesBaselineB— A basic signature. This is the default.PadesBaselineT— Adds a trusted timestamp. Requires a configured timestamp.PadesBaselineLT— Adds long-term validation material (certificates and revocation data). Requires the PAdES format and network access to revocation services.PadesBaselineLTA— Adds a document timestamp on top of B-LT for archival.
Complete implementation
This example produces a PAdES B-T signature and a classic CMS signature:
package io.nutrient.Sample;
import io.nutrient.sdk.*;import io.nutrient.sdk.enums.*;import io.nutrient.sdk.signing.*;
public class DigitalSignatures {Create the main method as the sample entry point:
public static void main(String[] args) {Producing a PAdES B-T signature
Set setLevel(SignatureLevel.PadesBaselineT) and configure a timestamp to produce a B-T signature.
In this sample:
Document.open("input.pdf")opens the PDF before signing.setLevel(SignatureLevel.PadesBaselineT)selects the B-T baseline profile.TimestampConfigurationsets the timestamp authority (TSA) endpoint, which B-T requires.sign(document, outputPath, options)applies the timestamped signature.
The timestamp proves the signature existed at a specific point in time, even after the certificate expires:
try (Signature signer = new Signature(); Document document = Document.open("input.pdf")) { DigitalSignatureOptions options = new DigitalSignatureOptions(); options.setCertificatePath("certificate.pfx"); options.setCertificatePassword("Nutrient answers all your document needs"); options.setSignerName("Legal Department"); options.setReason("Contract Execution"); options.setLevel(SignatureLevel.PadesBaselineT);
TimestampConfiguration timestamp = new TimestampConfiguration(); timestamp.setServerUrl("http://timestamp.digicert.com"); options.setTimestamp(timestamp);
signer.sign(document, "output_pades_t.pdf", options); } catch (Exception e) { System.err.println("Error creating PAdES B-T signature: " + e.getMessage()); }Choosing the container format
The SignatureFormat enumeration selects the signature container:
Pades— The PAdES profile (ETSI.CAdES.detached). This is the default and the one the baseline levels build on.Cms— The classic CMS container (adbe.pkcs7.detached) for compatibility with tools that expect the legacy format.
Set setFormat(SignatureFormat.Cms) to produce a classic CMS signature.
In this sample:
Document.open("input.pdf")opens the PDF before signing.setFormat(SignatureFormat.Cms)selects the classic CMS container.sign(document, outputPath, options)applies the signature.
try (Signature signer = new Signature(); Document document = Document.open("input.pdf")) { DigitalSignatureOptions options = new DigitalSignatureOptions(); options.setCertificatePath("certificate.pfx"); options.setCertificatePassword("Nutrient answers all your document needs"); options.setSignerName("Legal Department"); options.setReason("Contract Execution"); options.setFormat(SignatureFormat.Cms);
signer.sign(document, "output_signed_cms.pdf", options); } catch (Exception e) { System.err.println("Error creating CMS signature: " + e.getMessage()); } }}Conclusion
Use this workflow to control the baseline level and format of a signature:
- Open the document using try-with-resources for automatic resource cleanup.
- Configure
DigitalSignatureOptionswith certificate credentials and signing metadata. - Select the baseline profile with
setLevel()and theSignatureLevelenumeration. - Configure a
TimestampConfigurationfor B-T and above — these levels require a trusted timestamp. - Use
PadesBaselineLTorPadesBaselineLTAwhen you need long-term validation, keeping in mind these levels require the PAdES format and network access to revocation services. - Select the container format with
setFormat()and theSignatureFormatenumeration. - Use
SignatureFormat.Cmsonly for compatibility with tools that expect the legacyadbe.pkcs7.detachedcontainer; otherwise, keep the default PAdES format.
For related signing workflows, refer to the Java SDK guides.