NAME
PDF::Sign - Sign PDF files with CMS/CAdES signatures and RFC3161 timestamps
VERSION
Version 0.01
SYNOPSIS
use PDF::Sign qw(config :sign :ts);
# or selectively:
use PDF::Sign qw(config :sign); # config prepare_file sign_file cms_sign
use PDF::Sign qw(config :ts); # config prepare_ts ts_file ts_query tsa_fetch
# configure (recommended)
config(
osslcmd => '/usr/local/bin/openssl', # optional, default: 'openssl'
x509_pem => '/path/to/cert.pem',
x509_chain => '/path/to/chain.pem', # optional
privkey_pem => '/path/to/privkey.pem',
tsaserver => 'http://timestamp.digicert.com',
tmpdir => '/tmp',
debug => 0,
);
# sign
my $pdf = PDF::API2->open('input.pdf');
prepare_file($pdf, 0); # 0 = invisible, 1 = visible widget
my $signed = sign_file($pdf);
# timestamp
my $pdf2 = PDF::API2->from_string($signed);
prepare_ts($pdf2);
my $timestamped = ts_file($pdf2);
open(my $fh, '>:raw', 'output.pdf') or die $!;
print $fh $timestamped;
close $fh;
DESCRIPTION
PDF::Sign provides functions to apply CMS/CAdES digital signatures and RFC3161 timestamps to PDF files, producing PAdES-compliant output.
Requires an external openssl binary for signing operations. TSA requests use curl if available, falling back to LWP::UserAgent.
CONFIGURATION
All configuration is done via package variables (our), settable from the calling script:
$PDF::Sign::osslcmd-
Path to the openssl binary. Default:
openssl(from PATH). $PDF::Sign::x509_pem-
Path to the signer certificate PEM file. Required for signing.
$PDF::Sign::x509_chain-
Path to the certificate chain PEM file. Optional.
$PDF::Sign::privkey_pem-
Path to the private key PEM file. Required for signing.
$PDF::Sign::tsaserver-
URL of the TSA server. Default:
http://timestamp.digicert.com. $PDF::Sign::tmpdir-
Directory for temporary files. Default: current working directory.
$PDF::Sign::siglen-
Signature buffer size in bytes. Default: 8192 (1024*8). Increase if signatures are truncated.
$PDF::Sign::debug-
Enable debug output. Default: 0.
FUNCTIONS
config(%args)
Configure PDF::Sign in one call. All keys are optional — only provided keys are updated. Recommended over setting package variables directly.
config(
osslcmd => '/usr/local/bin/openssl',
x509_pem => '/path/to/cert.pem',
x509_chain => '/path/to/chain.pem',
privkey_pem => '/path/to/privkey.pem',
tsaserver => 'http://timestamp.digicert.com',
tmpdir => '/tmp',
siglen => 8192,
debug => 1,
);
If osslcmd is changed, the openssl version is re-detected automatically.
Package variables ($PDF::Sign::x509_pem etc.) still work for backwards compatibility.
prepare_file($pdf, $presign, $reason)
Prepares the AcroForm structure for a CMS/CAdES signature. $presign = 1 adds a visible widget on page 1; $presign = 0 adds an invisible field. $reason is optional.
sign_file($pdf)
Applies the CMS/CAdES signature. Returns the signed PDF as a string.
prepare_ts($pdf)
Prepares the AcroForm structure for a RFC3161 DocTimeStamp. Appends to an existing AcroForm if a signature field already exists.
ts_file($pdf)
Applies the RFC3161 timestamp. Returns the timestamped PDF as a string.
verify_signatures($pdf_path, %args)
Reads and verifies all digital signatures in a PDF file. Returns an arrayref of hashrefs, one per signature field found:
my $sigs = verify_signatures('signed.pdf');
for my $sig (@$sigs) {
printf "Type: %s\n", $sig->{type}; # cms | tsa
printf "SubFilter: %s\n", $sig->{subfilter};
printf "Signer: %s\n", $sig->{signer}; # cms only
printf "Signed at: %s\n", $sig->{signed_at}; # cms only
printf "TSA at: %s\n", $sig->{tsa_at}; # tsa only
printf "Valid: %s\n", $sig->{valid} ? 'YES' : 'NO';
printf "Error: %s\n", $sig->{error} if $sig->{error};
}
Optional args:
verify_signatures('signed.pdf', ca_bundle => '/etc/ssl/certs/ca-bundle.crt');
Without ca_bundle, verification uses -noverify (no CA chain check — cryptographic integrity only). With ca_bundle, full chain verification is performed.
cms_sign(%args)
Low-level: invokes openssl cms to sign a file stream. Args: signer, inkey, in, certfile (optional). Returns raw DER signature bytes.
ts_query(%args)
Low-level: generates a .tsq timestamp query file via openssl ts. Args: in (file to timestamp), out (output .tsq path).
tsa_fetch(%args)
Low-level: sends .tsq to TSA server, returns TimeStampToken DER bytes. Args: tsq (input .tsq path), tsa_url. Uses curl if available, falls back to LWP::UserAgent.
DEPENDENCIES
PDF::API2 or PDF::Builder (one required)
MIME::Base64 (core)
POSIX (core)
External:
opensslbinaryExternal:
curlbinary (optional, falls back to LWP::UserAgent)
AUTHOR
Massimiliano Citterio
Originally inspired by Martin Schuette <info@mschuette.name> (2012) https://mschuette.name/files/pdfsign.pl
LICENSE
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself (GPL/Artistic License).
See http://dev.perl.org/licenses/ for more information.
The original code by Martin Schuette is covered by the BSD 2-Clause License retained in the source.
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 1008:
Non-ASCII character seen before =encoding in '—'. Assuming UTF-8