Digitally Sign and Verify PDF Documents

Digitally sign PDF documents with a 'PKCS#12' keystore and verify their signatures. Signing produces a detached 'PKCS#7' / 'CMS' signature ('adbe.pkcs7.detached') over the document and is applied as an incremental update, so existing signatures remain valid. The cryptography and PDF manipulation are performed by a bundled, pure-'Rust' backend (the 'pdf_signer' crate); no Java runtime, 'OpenSSL', or external command-line tools are required. Visible signature appearances with custom text are supported.


pdfsigner pdfsigner website

CRAN status CRAN downloads License: GPL v3 powered by pdf_signer

pdfsigner is an R package to digitally sign PDF documents with a PKCS#12 keystore and verify their signatures.

The package is powered by a bundled, pure-Rust backend (the pdf_signer crate, wrapped with extendr). It no longer shells out to Java (BatchPDFSignPortable.jar) or Poppler (pdfsig): no Java runtime, OpenSSL, or external command-line tools are required — only a Rust toolchain at install time.

Installation

Requires a Rust toolchain (cargo, rustc) to compile the bundled backend. Install Rust from https://rustup.rs, then:

# install.packages("remotes")
remotes::install_github("StrategicProjects/pdfsigner")

What it does

  • PAdES signatures up to B-LTA via pades_level: "bb" (CAdES signing-certificate-v2), "bt" (+ RFC 3161 signature timestamp), "blt" (+ a /DSS with the certificate chain and CRLs), "blta" (+ a document timestamp over the whole file). Levels "bt"+ need a tsa_url.
  • Incremental updates: signing again appends only, so earlier signatures stay valid — multi-signature is supported.
  • Visible or invisible signatures, with a custom text box + validation link.
  • Cryptographic verification of every signature (re-derives the signed byte range, checks the message digest and the signer's RSA signature).

Usage

sign_pdf()

library(pdfsigner)

sign_pdf(
  pdf_file          = "input.pdf",
  output_file       = "signed.pdf",
  keystore_path     = "keystore.p12",      # or env var KEYSTORE_PATH
  keystore_password = "password",          # or env var KEY_PASSWORD
  signtext          = "Document digitally signed by CastLab",
  validate_link     = "https://castlab.org/validate",
  reason            = "Approval",
  translate         = TRUE,                 # Portuguese date label
  font              = "Arial.ttf",          # embed a TrueType/OpenType font
  image             = "logo.png",           # draw a PNG/JPEG logo in the box
  tsa_url           = "http://timestamp.digicert.com",
  pades_level       = "blta"                # bb | bt | blt | blta
)

A visible signature box is drawn whenever signtext is non-empty; geometry is controlled by page, x, y, width, height, font_size and border. Pass font to embed a TrueType/OpenType font (WinAnsi/Latin-1 glyphs; the default is Helvetica) and image to draw a PNG/JPEG logo in the box. Omit signtext for an invisible signature.

verify_pdf_signature()

result <- verify_pdf_signature("signed.pdf")
length(result)                              # number of signatures
vapply(result, function(s) s$valid, logical(1))
result[[1]]$signer                          # signer distinguished name

Each entry is a named list: valid, signer, chain_trusted, covers_whole_document, signed_len, byte_range, detail.

Pass roots (a PEM file of trusted roots, e.g. the ICP-Brasil AC Raiz set) to validate each signer certificate chain; chain_trusted is then TRUE/FALSE (and NA when no roots are given):

verify_pdf_signature("signed.pdf", roots = "icp-brasil-roots.pem")

TSA / CRL endpoints over HTTPS are supported (the bundled Rust backend is built with its https feature, using rustls).

Generating a test certificate

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
openssl pkcs12 -export -inkey key.pem -in cert.pem -out keystore.p12

Architecture

pdfsigner architecture: the R interface (sign_pdf / verify_pdf_signature) calls the extendr bridge, which links the pure-Rust pdf_signer crate and its vendored dependencies, producing PAdES-signed PDFs and a verification report.

The R functions call a thin extendr bridge that links the pure-Rust pdf_signer crate. Every Rust dependency is vendored under src/rust/vendor.tar.xz so the package builds offline (CRAN policy: SystemRequirements: Cargo, rustc).

License

GPL-3. The bundled pdf_signer crate and its vendored Rust dependencies retain their own licenses.

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.

install.packages("pdfsigner")

0.3.0 by Andre Leite, 21 days ago


https://github.com/StrategicProjects/pdfsigner


Report a bug at https://github.com/StrategicProjects/pdfsigner/issues


Browse source code at https://github.com/cran/pdfsigner


Authors: Andre Leite [aut, cre] , Hugo Vasconcelos [aut] , Diogo Bezerra [aut] , Authors of the vendored Rust crates [ctb, cph] (see inst/AUTHORS for the bundled crates and their licences)


Documentation:   PDF Manual  


GPL-3 license


Suggests testthat

System requirements: Cargo (Rust's package manager), rustc (>= 1.81)


See at CRAN