tsp-ltv
Shared timestamping (RFC 3161) and long-term validation infrastructure for Advanced Electronic Signature (AdES) formats. Provides OCSP, CRL, trust stores, and certificate chain building used by underskrift (PAdES/CAdES), bergshamra (XAdES), and jades (JAdES).
Version 0.4 requires Rust 1.88 and delegates all cryptographic operations and
TLS provider configuration to kryptering 0.5.
Features
- RFC 3161 timestamping — TSA client and pool with failover, TimeStampReq/Resp ASN.1 building and parsing, nonce-based replay protection
- OCSP client (RFC 6960) — request building, response parsing and validation, AIA extension extraction, responder signature verification
- CRL client (RFC 5280) — CRL fetching from distribution points, in-memory caching with configurable grace period, revocation status checking
- Certificate chain building — local pool-based chain construction from unordered intermediates (subject/issuer name matching with signature verification at each link), AIA-based intermediate discovery, configurable recursion depth
- Trust stores — load PEM files/directories, DER, PKCS#7 bundles; typed store sets for signature, timestamp, and SVT validation; chain verification with time validity checking
- X.509 extension validation — BasicConstraints, KeyUsage, ExtendedKeyUsage, role-based validation (end entity, intermediate CA, CRL signer, OCSP responder)
- Revocation checking — concurrent OCSP + CRL with priority-based result merging, configurable timeouts and policies
- Signature verification — RSA PKCS#1 v1.5 (SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, MD5), RSA-PSS, ECDSA (P-256, P-384, P-521 with SHA-1 through SHA-512), Ed25519 for certificate, OCSP, and CRL signature validation
- Algorithm coverage — SHA-1, SHA-224, SHA-256/384/512, SHA3-256/384/512, MD5 digest algorithms with OID mappings
Design
This crate is format-agnostic — it does not know about PDF, XML, or JSON.
Each AdES crate builds its own format-specific embedding (DSS dictionaries for
PAdES, XAdES qualifying properties, JAdES etsiU headers) on top of these
shared clients. Consumer crates typically re-export tsp-ltv modules as thin
facades (e.g. pub use tsp_ltv::trust::*;).
tsp-ltv (this crate)
├── tsp — RFC 3161 TSA client + ASN.1 parsing
├── ltv — OCSP, CRL, chain building, revocation
├── trust — trust stores, chain building from cert pools, chain validation
├── crypto — digest algorithms, signature verification, OID constants
└── der_utils — ASN.1/DER parsing utilities
Used by:
├── underskrift (PAdES/CAdES — adds DSS dictionary embedding)
├── bergshamra (XAdES — adds qualifying property embedding)
└── jades (JAdES — adds etsiU header construction)
Quick start
Add to your Cargo.toml:
[]
= "0.4"
Defaults are tsp, ltv, blocking, rustcrypto, tls-ring, and
legacy-algorithms. To use only a subset:
[]
= { = "0.4", = false, = ["tsp", "rustcrypto", "tls-ring"] }
For crates that only need trust store management and certificate verification (no network operations):
[]
= { = "0.4", = false, = ["rustcrypto"] }
This gives you access to the trust and crypto modules without pulling in
OCSP, CRL, or TSP client dependencies.
Request a timestamp
use ;
let client = new?;
let hash = vec!; // SHA-256 hash of signature value
let token = client.timestamp.await?;
// Multiple TSAs with automatic failover
let pool = from_urls?;
let token = pool.timestamp.await?;
Check certificate revocation
use ;
let ocsp = new?;
let crl = new?;
let config = default;
let status = check_certificate_revocation.await?;
Load trust anchors
use ;
let sig_store = from_pem_file?;
let tsa_store = from_pem_directory?;
let stores = new
.with_sig_store
.with_tsa_store;
Build and verify a certificate chain
use ;
// Load trust anchors
let trust_store = from_pem_file?;
// Build an ordered chain from a leaf and unordered intermediates
let anchor_subjects = trust_anchor_subjects;
let chain = build_chain_from_pool?;
// Verify signatures and time validity
trust_store.verify_chain?;
Feature flags
| Flag | Default | Description |
|---|---|---|
tsp |
yes | RFC 3161 timestamping (requires network) |
ltv |
yes | OCSP/CRL/chain building (implies tsp) |
blocking |
yes | Synchronous API wrappers via tokio::runtime::Runtime::block_on |
rustcrypto |
yes | RustCrypto document provider (exactly one document provider is required) |
aws-lc |
no | AWS-LC document provider |
tls-ring |
yes | ring TLS provider for network-enabled builds |
tls-aws-lc |
no | AWS-LC TLS provider |
fips |
no | Select AWS-LC and require explicit, attested provider initialization |
With default-features = false, the trust, crypto, error, and
der_utils modules are always available, but one document provider still has
to be selected. Exactly one TLS provider is also required whenever tsp (and
therefore ltv) enables networking. Document crypto and TLS are independent;
there is no provider fallback. In FIPS builds, AWS-LC is the document provider
and, when networking is enabled, the only TLS provider. --all-features is
intentionally invalid.
Network clients are built fallibly with net::hardened_http_client() and carry
an AttestedHttpClient; raw reqwest::Client injection is unavailable in
FIPS builds. Non-FIPS callers that deliberately accept the risk must use the
explicitly named unverified_http_client escape hatch.
In FIPS builds, call initialize_backend() before digesting, validation, or
HTTPS client creation. Enabling the feature does not itself certify the
application or deployment.
License
BSD-2-Clause