Skip to content

Timestamp Authority

By Romi Fadli, S.Kom. 9 min read Security & Secrets
On this page
A document's fingerprint passing through a clock, signed by a certificate below it, and returning as a time seal stamped on the same document

Timestamp Authority is a Rust service that answers one request with one signed statement: this exact fingerprint of a document existed at this second. It implements RFC 3161 time-stamping for signed PDFs, and it is also a small certificate authority of its own — it issues, stores, and renews the certificate it signs with, publishes revocation information for it, and records every token it has ever produced.

I built it because a digital signature only proves who signed; it does not prove when. A signer's certificate expires after a few years and can be revoked tomorrow, and without trusted evidence of the signing time a reader cannot tell whether a signature was made while the certificate was still good. A timestamp from an independent authority, embedded in the PDF, is that evidence, and it keeps a signature verifiable long after the certificate behind it has gone.

At a glance

Language & frameworkRust, with actix-web, sqlx on PostgreSQL, and OpenSSL's time-stamping engine through its C interface
ArchitectureFlat Layered
Version2.11.2
StatusStable, in production
FormA standalone HTTP service: public time-stamping and revocation endpoints, and an authenticated API for administration
Source codePrivate
What the module is and where it stands.

What it does

A. Stamps a document's fingerprint with the time

A signing application sends a time-stamp request that carries only a hash of the document, never the document itself. The service answers with a signed token that binds that hash to the current time, a unique serial number, and the client's nonce, and the application embeds the token in the PDF next to the signature.

B. Issues and renews its own signing certificate

The certificate that signs every token is created by the service itself, under its own intermediate CA, at the first start. When it nears the end of its validity, the next request renews it before signing, so the service never stamps with an expired certificate and nobody has to remember to replace one.

C. Lets anyone check its certificates

A validator that reads a timestamp years later must be able to trust the certificate that signed it. The service publishes its intermediate CA certificate, a certificate revocation list, and an OCSP responder, all without authentication, at the addresses written into its certificates.

D. Keeps a record of every token

Every response is stored with its time, policy, hash algorithm, document fingerprint, nonce, and the signing certificate's serial number, so any token the service ever issued can be traced back to the request that produced it.

E. Controls administration

Time-stamping and revocation checks are public; revoking a certificate and managing users, roles, and access tokens require a signed token with the right role.

Interface

CapabilityAccess
Time-stamp a hash: an RFC 3161 request in, a signed response outpublic
The intermediate CA's certificate, in DER, at the address certificates point topublic
The certificate revocation listpublic
OCSP, by GET and by POSTpublic
Readiness, covering the database and the root CApublic
Revoke a certificate with an RFC 5280 reasontoken
Log in; manage users, roles, passwords, and access tokenstoken, by role
What the service exposes, and who may use it.

Any RFC 3161 client can use it. Here is the round trip with OpenSSL, against a placeholder host:

bash
openssl ts -query -data contract.pdf -sha256 -cert -out request.tsq
curl -s -H 'Content-Type: application/timestamp-query' \
  --data-binary @request.tsq http://tsa.example.org/ -o response.tsr
openssl ts -reply -in response.tsr -text

Standards

StandardWhat it guarantees here
RFC 3161, Time-Stamp Protocolrequests and tokens that PDF signers and validators already understand
CMS SignedData (RFC 5652)a token signed in the same envelope format as the signature it protects
X.509 v3 and RFC 5280a signing certificate restricted to time-stamping, and a revocation list any validator can read
RFC 6960, OCSPrevocation answers for the signing certificate, by GET or POST
Authority Information Access and CRL Distribution Pointscertificates that tell a validator where to find the issuer and the revocation status
JSON Web Tokens with RS256access tokens for administration, signed with a key the service can rotate
W3C Trace Context and OpenTelemetrytraces, logs, and metrics that continue the caller's trace
The standards the service follows, and what each one guarantees.

Inside

The service follows the same Flat Layered shape as the certificate authority it was branched from: routes, controllers, services, repositories, and helpers side by side, one level deep, with one file per operation — answer a time-stamp request, create the signing certificate, answer an OCSP query, build a revocation list. The two services shared their code up to the point where they branched; the time-stamping engine, the signer's lifecycle, and the token record were built after it, and fixes made later in one were deliberately carried over to the other.

Design decisions

The cryptography is OpenSSL's, and only the decisions are mine. Time-stamping has many fields to get exactly right, and OpenSSL already has a time-stamp response engine that produces them, so I drive that engine through bindings generated for a narrow list of functions instead of assembling the structure by hand. Two values are not left to OpenSSL. The serial number of each token comes from a database sequence of its own, separate from certificate serial numbers, and is handed to the engine through a callback. The time is read once per request from the host's clock, which is kept synchronised with NTP, and handed over the same way, so the time in the token and the time in the record are the same second.

A token must be readable by the tools that will check it. In the first version, a widely used Python PDF-signing library received responses with a status but no token inside. The cause was in how the request reached OpenSSL — the engine was given the original request instead of the adjusted one — and the fix changed four things together: the request is re-encoded before it is passed on, the signing certificate is always included in the response — also when the request does not ask for it — the digest used matches the length of the fingerprint the client sent, and a response that would carry no token fails immediately instead of being returned as if it were an answer.

The chain stops below the root. Each token carries the signing certificate and the intermediate CA, so a validator can build the path, but not the root: the root is a trust anchor that the validator must already hold, and including it only makes every token larger. An early version included it; I removed it again.

The signing certificate is made inside, never requested from outside. The only certificate this service signs tokens with is one it creates itself. Its profile is fixed in code rather than configuration — not a CA, key usage critical and limited to digital signature and non-repudiation, extended key usage critical and limited to time-stamping — because two incidents showed what a profile left loose can do: one certificate was issued without the time-stamping purpose, and an earlier batch was issued as version 1 despite carrying version 3 extensions. The service creates the certificate at the first start, refuses to start if it cannot, and renews it inside the request path before it can expire.

Every token leaves evidence, and the evidence holds no document. The service never receives the document, only its hash, so it can log and store the fingerprint in full without holding anything confidential. Each response is stored with the time, policy, algorithm, fingerprint, nonce, signing certificate, and request id, and each request emits telemetry attributes for non-repudiation — who asked, from where, and what was stamped — with the raw chain of forwarding addresses kept as evidence only. Responses are sent with no-store, because a cached timestamp is a wrong timestamp.

Revocation for the signing certificate works the same way as in the certificate authority. The OCSP responder has a signer of its own, echoes nonces, includes the intermediate CA, and backdates the start of each answer slightly for clients with slow clocks; the revocation list is version 2, built through OpenSSL's C interface. The addresses in every certificate use plain HTTP, because checking revocation over TLS would require checking the TLS certificate first, and the responder's certificate points to its issuer, never to itself.

Trust starts from the root, and operations follow the certificate authority's lessons. The intermediate CA is verified against the root at every start. Administration uses signed tokens with key identifiers and revocable token ids; telemetry goes through OpenTelemetry with delta metrics; readiness requires both the database and the root CA; and migrations travel inside the image, because applying them only to an empty database had left later schema changes out of staging and production.

Specifications

InputsRFC 3161 time-stamp requests carrying a document hash and an optional nonce; OCSP queries and list downloads from any validator
OutputsSigned time-stamp responses, OCSP answers, version 2 revocation lists, and the intermediate CA certificate
TimeThe host's NTP-synchronised clock, read once per request; accuracy of one second
KeysRSA 4096 for the signing certificate and the responder
StoragePostgreSQL, holding every issued token and certificate, with migrations shipped inside the image
Verified withOpenSSL's time-stamp tools and a PDF-signing library that embeds the tokens
Runs asA container image, as a non-root user, with configuration mounted from a volume
What the service takes, returns, and needs.

The certificate authority this service was branched from, which shares its revocation and access design.

The toolkit that applies the service's migrations when a release reaches production.

Where the service's audit attributes, traces, and metrics go once they leave it.

Terms

Timestamp authority
A trusted service that signs a statement that a given piece of data existed at a given time.
Message imprint
The hash of the document that a time-stamp request carries in place of the document itself.
Nonce
A random number a client puts in a request and expects back in the answer, so an old answer cannot be replayed.
Intermediate CA
A certificate authority whose certificate is signed by a root, and which signs the certificates that do the actual work.
OCSP
Online Certificate Status Protocol: a client asks whether one certificate is still valid and receives a signed answer.
Trust anchor
A root certificate a validator already trusts, at which every chain it checks must end.

Technologies covered

  • Rust
  • PostgreSQL
  • OpenTelemetry
  • OCSP
  • X.509

About the author

Photo of Romi Fadli

Romi Fadli, S.Kom.

Solution Architect · Backend Engineer · Embedded Systems

In my day job I work as a solution architect. I design the system, lead the team that builds it — quality assurance, backend developers, a UI developer, DevOps and DevSecOps — and write the most critical modules myself, such as a certificate authority, a long-term PDF signer, and the core API of a personnel system.

I work across the whole stack that a running system actually needs. On the hardware side that means PCB design, microcontrollers, and embedded firmware — including RISC-V boards running FreeRTOS and Embassy, speaking MQTT over mutually authenticated TLS on a microcontroller with 64 KB of SRAM.

Most of my day-to-day work is software: Rust backends and API modules built on Clean Architecture, an OAuth2/OpenID Connect authorization server written from scratch, PAdES document signing, and certificate authorities — root CAs, timestamping authorities, and OCSP responders. I also build the frontends that sit on top of them.

Running all of that means infrastructure: Docker Compose stacks, networking, Mikrotik and RADIUS, observability with OpenTelemetry, and a steady habit of writing command-line tools and utilities for Linux when the existing ones do not fit.

Share

Enjoyed this?

Get an email when a new article is published.

Referenced by

A central core holding people, organisations, documents, and certificates, connected to eight surrounding services for storage, addresses, certificates, timestamps, the root, signing, thumbnails, and face challenges

The Laravel core of a document-signing platform: it owns users, identities, organisations, client systems, documents and their signed versions, stamps, and certificates, and orchestrates the services that sign, timestamp, render, and store — without ever holding a file.

9 min read Read more →
A locked offline host holding the root key, a signed revocation list crossing an air gap to a small publisher server, which serves the root certificate and the list to a validator

A tiny publish-only service that keeps a root CA reachable without making it touchable: it serves the root certificate and its revocation list, while the root key and every signature stay on an offline host — reusable by any project with its own CA.

7 min read Read more →
A signed PDF with a QR stamp, wrapped in four nested frames for the signature, its timestamp, the embedded validation data, and the archive timestamp

A Python service that signs PDFs to PAdES B-LTA with a visible stamp — embedding the timestamp, certificates, and revocation proof, then an archive timestamp — so signatures stay verifiable long after their certificates expire, and verifies signed PDFs.

10 min read Read more →
A purple root circle linked to a blue and an orange intermediate circle, which lead to a signed document with a green seal and to a clock.

Aurograf

DevOps

The digital signature platform of the City Government of South Tangerang: signers prove who they are, sign PDFs to PAdES B-LTA with certificates from the platform's own authorities, and anyone can verify the result — version 2, which I designed, built and operate.

10 min read Read more →

Related Articles

A memory chip holding a key, circled by refresh arrows, beside a browser window where a signature stamp is being dragged into place on a PDF page

The Vue browser application of a document-signing platform: sessions held in memory and renewed by one queued refresh, PKCE sign-in, stamps placed precisely on PDF pages, identity checks with a face challenge, client consent, and role-based administration.

10 min read Read more →
A central core holding people, organisations, documents, and certificates, connected to eight surrounding services for storage, addresses, certificates, timestamps, the root, signing, thumbnails, and face challenges

The Laravel core of a document-signing platform: it owns users, identities, organisations, client systems, documents and their signed versions, stamps, and certificates, and orchestrates the services that sign, timestamp, render, and store — without ever holding a file.

9 min read Read more →
A signed PDF with a QR stamp, wrapped in four nested frames for the signature, its timestamp, the embedded validation data, and the archive timestamp

A Python service that signs PDFs to PAdES B-LTA with a visible stamp — embedding the timestamp, certificates, and revocation proof, then an archive timestamp — so signatures stay verifiable long after their certificates expire, and verifies signed PDFs.

10 min read Read more →