Inspect the signer certificate, signing time, and signature coverage for each digital signature in a PDF.
use pdfluent::Document;
fn main() -> pdfluent::Result<()> {
let doc = Document::open("signed.pdf")?;
for sig in doc.signatures() {
println!("Signer: {}", sig.signer_name().unwrap_or("unknown"));
println!("Signed at: {:?}", sig.signing_time());
println!("Covers whole: {}", sig.covers_whole_document());
println!("Cert issuer: {}", sig.certificate()?.issuer());
println!("---");
}
Ok(())
}doc.signatures() returns an iterator over all digital signature fields in the AcroForm.
let doc = Document::open("signed.pdf")?;Each Signature object provides access to the signer name from the certificate, signing time, and field name.
for sig in doc.signatures() {
println!("Field: {}", sig.field_name());
println!("Signer: {}", sig.signer_name().unwrap_or("(unknown)"));
}sig.certificate() returns the end-entity certificate. You can inspect the subject, issuer, serial number, and validity period.
let cert = sig.certificate()?;
println!("Subject: {}", cert.subject());
println!("Issuer: {}", cert.issuer());
println!("Serial: {}", cert.serial_number_hex());
println!("Valid from: {:?}", cert.not_before());
println!("Valid to: {:?}", cert.not_after());The signing time may come from the certificate or from an embedded timestamp token. covers_whole_document checks whether the byte ranges cover the entire file.
println!("Signing time: {:?}", sig.signing_time());
println!("Has timestamp token: {}", sig.has_timestamp_token());
println!("Covers whole document: {}", sig.covers_whole_document());
let (ranges_bytes, total_bytes) = sig.byte_range_coverage(&doc)?;
println!("Covered {}/{} bytes", ranges_bytes, total_bytes);If the byte ranges do not cover the entire file, content was appended after signing. This does not mean the signature is invalid, but it may indicate incremental updates.
if !sig.covers_whole_document() {
println!("Warning: document was modified after signing.");
}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.