Signature Timestamps
Attach an RFC-3161 signature timestamp over http or https with pure-Rust TLS, add auth, or plug your own TSA client
An RFC-3161 timestamp binds your signature to a moment in time attested by a trusted Time-Stamp
Authority (TSA), independent of the signer's own clock. It proves the signature existed before a
given instant — the foundation of every PAdES profile above B-B and of
long-term validation. Attach one with the builder's .timestamp(...).
use mudrit_pdfsign::prelude::*;
let cfg = SignConfig::builder()
.place("F", [350, 60, 560, 160])?
.timestamp(Timestamp::url("http://timestamp.comodoca.com"))
.build();
let signed = sign_pdf(&pdf, &signer, &cfg)?;The built-in TSA
Timestamp::url(...) uses the bundled UrlTimestamper, which speaks to both http:// and
https:// authorities. TLS is pure-Rust (rustls) — no
OpenSSL, no system libraries — so an https TSA works out of the box on every platform.
.timestamp(Timestamp::url("http://timestamp.comodoca.com")) // plain http
.timestamp(Timestamp::url("https://tsa.company.com/tsr")) // https via rustlsIf you don't set a TSA but a profile requires one, the SDK falls back to DEFAULT_TSA_URL
(http://timestamp.comodoca.com) — for example PAdES B-T auto-uses it
when no explicit source is given.
Authenticated ("protected") TSAs
A protected TSA is configured by chaining auth onto Timestamp::url(...). All three combine with
http or https:
| Method | Header sent |
|---|---|
.basic_auth("user", "pass") | Authorization: Basic … |
.bearer("token") | Authorization: Bearer … |
.header("X-Api-Key", "…") | any custom request header (call it repeatedly for several) |
.timestamp(Timestamp::url("https://tsa.company.com/tsr").basic_auth("user", "pass")) // https + Basic
.timestamp(Timestamp::url("https://tsa.company.com/tsr").bearer("my-token")) // https + Bearer
.timestamp(Timestamp::url("https://tsa.company.com/tsr").header("X-Api-Key", "…")) // https + headerCredentials are never printed — UrlTimestamper's Debug shows only the URL and whether auth is
set, so a config logged for diagnostics can't leak a token or password.
The Timestamp options
| Variant | Meaning |
|---|---|
Timestamp::None (default) | No timestamp. The signature is valid but carries no trusted time. |
Timestamp::url(url) | The built-in TSA (http/https + optional .basic_auth / .bearer / .header). |
Timestamp::custom(t) | Your own Timestamper — mutual-TLS, a proxy, or any non-standard flow. |
Auto-sized placeholders make one extra fetch
With SigSize::Auto (the default) the SDK measures the real TSA token size to reserve exactly the
right /Contents space — one extra timestamp fetch, but no extra key or PIN operation. Use
SigSize::Fixed(n) if you want a single round-trip.
Custom TSA client
For anything the built-in doesn't cover — a mutual-TLS client certificate, an outbound
proxy, or a vendor-specific handshake — implement the Timestamper trait with your own HTTP
client and pass it via Timestamp::custom.
The contract is a single method. The SDK builds the RFC-3161 TimeStampReq (DER, content-type
application/timestamp-query) and hands it to you; you POST it however you like and return the raw
TimeStampResp (DER) exactly as the TSA replied. The SDK then extracts the token and verifies
it commits to this request — the token's messageImprint must match, and any nonce it carries
must echo the one the SDK sent — so a stale or mismatched response is rejected, never embedded.
use mudrit_pdfsign::prelude::*;
struct MyTsa { /* client, client-cert, proxy, … */ }
impl Timestamper for MyTsa {
fn timestamp(&self, request: &[u8]) -> Result<Vec<u8>> {
// POST `request` (a DER TimeStampReq) with your own client — reqwest/ureq, mTLS, proxy …
// and return the raw response body (a DER TimeStampResp).
todo!()
}
}
let cfg = SignConfig::builder()
.place("F", [350, 60, 560, 160])?
.timestamp(Timestamp::custom(MyTsa { /* … */ }))
.build();You only handle transport. Request construction, nonce generation, token extraction, and the
imprint/nonce checks stay inside the SDK — your Timestamper is just the network hop, so a broken
or malicious TSA response can't slip a bad timestamp into the document.
Next
Signature Appearance
Everything the visible signature can show — render modes, graphics, layout, colours, fonts, Unicode shaping, borders, fields, labels and templates
Long-Term Validation
Embed the certificate chain, CRLs, and OCSP responses in a DSS so a signature validates long after signing — online or fully offline