How-to guides/Digital Signatures

Add a trusted timestamp to a PDF in Rust

Embed an RFC 3161 timestamp token from a Time Stamping Authority into an existing PDF signature.

rust
use pdfluent::{Document, timestamp::{TsaConfig, TimestampOptions}};

fn main() -> pdfluent::Result<()> {
    let mut doc = Document::open("signed.pdf")?;

    let tsa = TsaConfig::new("http://timestamp.digicert.com");
    let opts = TimestampOptions::new(tsa);

    // Add a document-level timestamp signature field
    doc.add_timestamp(&opts)?;
    doc.save("timestamped.pdf")?;
    Ok(())
}
Install:cargo add pdfluentDownload SDK →

Step by step

1

Open the PDF to timestamp

The document may already be signed by a signer, or you may add a standalone timestamp signature field.

rust
let mut doc = Document::open("signed.pdf")?;
2

Configure the TSA endpoint

Provide the URL of a trusted RFC 3161 Time Stamping Authority. Many CAs offer free TSA endpoints.

rust
use pdfluent::timestamp::TsaConfig;

let tsa = TsaConfig::new("http://timestamp.digicert.com")
    .hash_algorithm(pdfluent::digest::HashAlgorithm::Sha256);
3

Build timestamp options

TimestampOptions wraps the TsaConfig and specifies the field name and policy OID if required by the TSA.

rust
use pdfluent::timestamp::TimestampOptions;

let opts = TimestampOptions::new(tsa)
    .field_name("DocTimestamp")
    .policy_oid(None); // None = TSA default policy
4

Request the timestamp and embed it

PDFluent computes the document digest, sends a TSQ to the TSA, receives a TSR, and embeds the RFC 3161 token in a new signature field.

rust
doc.add_timestamp(&opts)?;
5

Save and verify

Save the file and confirm the timestamp token is present.

rust
doc.save("timestamped.pdf")?;

// Verify the timestamp
let doc2 = Document::open("timestamped.pdf")?;
for sig in doc2.signatures() {
    if sig.has_timestamp_token() {
        let ts = sig.timestamp_token()?;
        println!("Timestamp time: {:?}", ts.gen_time());
        println!("TSA: {}", ts.tsa_name().unwrap_or("unknown"));
    }
}

Notes and tips

  • A document-level timestamp (LTV timestamp) provides proof of existence at a point in time even after the signer certificate expires.
  • Some TSA services require HTTP Basic Auth or an API key. Pass credentials with TsaConfig::with_credentials(user, pass).
  • The hash algorithm in the TSQ must be accepted by the TSA. SHA-256 is accepted by all modern TSAs. SHA-1 is deprecated.
  • For long-term validation (LTV), also embed OCSP responses or CRLs for all certificates in the chain with doc.add_ltv_info().

Why PDFluent for this

Pure Rust

No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.

Memory safe

Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.

Runs anywhere

Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.

Frequently asked questions