Sign a PDF with a PKCS#12 certificate. PDFluent writes a conforming ISO 32000 signature that Adobe Acrobat, Preview, and other viewers can verify.
use pdfluent::{PdfDocument, PdfSigner, SignatureOptions};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut doc = PdfDocument::open("contract.pdf")?;
let cert = std::fs::read("signing_cert.p12")?;
let signer = PdfSigner::from_pkcs12(&cert, "p12_password")?;
signer.sign(
&mut doc,
SignatureOptions::default()
.reason("Approved by legal team")
.location("Amsterdam, NL"),
)?;
doc.save("contract_signed.pdf")?;
println!("Document signed successfully");
Ok(())
}Add the pdfluent crate to Cargo.toml.
[dependencies]
pdfluent = "0.9"Read the .p12 or .pfx certificate file and create a PdfSigner. The certificate must include the private key.
use pdfluent::PdfSigner;
let cert_bytes = std::fs::read("my_cert.p12")?;
let signer = PdfSigner::from_pkcs12(&cert_bytes, "your_p12_password")?;Set the reason, location, and contact info. These appear in the signature panel in PDF viewers.
use pdfluent::SignatureOptions;
let opts = SignatureOptions::default()
.reason("I approve the content of this document")
.location("Amsterdam, NL")
.contact_info("[email protected]")
.signature_field_name("Signature1");Add a visible signature box on a specific page and position. Skip this step for invisible signatures.
use pdfluent::{Rect, SignatureAppearance};
let appearance = SignatureAppearance::default()
.page(0)
.rect(Rect::new(350.0, 50.0, 550.0, 110.0))
.text("Signed by: Jasper de Winter");
let opts = opts.appearance(appearance);Call sign() then save(). The output file contains the cryptographic signature bytes embedded in the PDF structure.
signer.sign(&mut doc, opts)?;
doc.save("contract_signed.pdf")?;
println!("Signed. Verify with: pdfluent verify contract_signed.pdf");No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.
Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.
Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.