---
title: "Pinning Time: RFC 3161 and the Date the Author Typed"
description: "How ProvNat learned what 'when' means: one canonical UTC format, a migration that exposed attestation times written by hand, and RFC 3161 timestamp tokens verified against pinned roots."
pubDate: 2026-10-12
author: "Anaiya"
series: "Moonglade Lab Dispatches"
readTime: "5 min read"
heroImage: "/images/blog/provenance-local-lineage.png"
image: "/images/blog/provenance-local-lineage.png"
tags:
  - provenance
  - timestamps
  - rfc-3161
  - engineering
  - trust
audio: "/audio/2026-10-12-pinning-time-rfc-3161-and-the-date-the-author-typed.mp3"
---

A signature tells you who. A hash tells you what. Neither tells you when, and when is the question that settles most disputes.

This dispatch covers the day we discovered that one of our own timestamp fields was recording whatever date the author felt like typing.

## One time format, enforced at the boundary

Before verifying external timestamps, we had to enforce a single representation for recorded time across our own storage layer. Zen set the specification: `YYYY-MM-DDTHH:MM:SSZ`. Strict RFC 3339, UTC, whole seconds, fixed width, so lexicographical string sorting matches chronological order.

A single parser module handles every time boundary. It provides explicit converters for each accepted input format: ASN.1 `GeneralizedTime`, OpenSSL human-readable time output, zoned ISO-8601 strings, and Unix epoch seconds. It rejects sub-second precision rather than silently truncating, and rejects naive datetimes or free-form text outright.

Rounding direction depends on what is being measured:

- **Evidence of existence rounds up.** A statement that bytes existed by time `T` is an upper bound, so fractional seconds round up to the next whole second.
- **Recorded operational events round down,** ensuring a local log entry is never stamped in the future.

## The defect the migration exposed

We migrated the live ProvNat store to the strict format across 670 entities and envelopes. The migration ran idempotently with a mandatory dry-run pass and an automatic pre-migration backup.

That dry run surfaced a structural bug in our ingestion pipeline. The vault sync routine had been copying each Markdown note's frontmatter `date:` and `updated:` strings directly into `created_at`, `updated_at`, and `attested_at`. Frontmatter dates are typed by the author in whatever format they choose.

As a result, an envelope's `attested_at` column was storing a self-reported header string rather than the moment the store recorded the attestation. It was storing a claim about time as if it were a measurement.

In the repaired schema, `attested_at` records the store's own UTC ingestion clock exclusively. Frontmatter dates are preserved separately under an explicit `asserted_time` field: bare `YYYY-MM-DD` dates resolve to `00:00:00Z` of that UTC day, while unparseable strings fall back cleanly without affecting the attestation record.

Whole-second precision also means two envelopes written in the same second share an identical timestamp. Queries for the latest envelope now order deterministically by `(attested_at, rowid)` with dedicated test coverage so tie-breaking never depends on SQLite scan order.

## Time from an independent third party

An RFC 3161 timestamp token issued by an external Time-Stamp Authority (TSA) is the only time evidence in the system that does not originate from our own hardware. Our verification rules enforce five invariants:

- The authoritative timestamp is the token's internal `genTime` field. Any self-reported `tsa_time` string in the JSON sidecar is ignored.
- The token's `messageImprint` digest must match the computed digest of the attested bytes.
- The TSA signature and certificate chain are validated against **pinned** root certificates evaluated at `genTime`, so an older valid token does not fail simply because the TSA's leaf certificate expired months later.
- A valid timestamp token proves that the attested bytes existed no later than `T`. It never alters the validity of the document signature itself; time assurance and signer assurance remain independent.
- Missing dependencies fail toward `indeterminate`. If OpenSSL is unavailable, trust anchors are not installed, or the issuing TSA is not in our pinned manifest, the verifier returns `indeterminate`. Only a token that fails a cryptographic check (mismatched imprint, invalid signature, malformed ASN.1, certificate invalid at `genTime`, or missing `timeStamping` extended key usage) is marked `invalid`. Certificate revocation status is explicitly reported as `not checked`.

The current verifier executes these checks through `openssl ts`. We have a standalone Rust verifier planned, and this test contract defines the exact behavior it must match.

## Accounting for every TSA in rotation

Our signing script rotates across multiple timestamp authorities for resilience. Zen required every authority in that rotation to be explicitly accounted for in our trust store.

A versioned manifest now enumerates every endpoint in the rotation: five primary TSAs, three fallback TSAs, plus rough-time consensus hosts and the local system clock (which are flagged explicitly as non-cryptographic time sources). Eight pinned root certificates cover the cryptographic authorities, including DigiCert, USERTrust, GlobalSign, Certum, QuoVadis, and FreeTSA.

Rather than trusting vendor documentation, we derived the pinned root bundle empirically by validating all 64 historical tokens stored in our vault alongside live probe tokens fetched from each configured endpoint over a canonical test digest.

One authority remains intentionally unpinned: Apple's timestamp root is absent from both the standard Mozilla CA bundle and default Windows certificate stores, so tokens issued by Apple's TSA return `indeterminate` unless an operator explicitly pins that root. Automated regression tests fail if a new endpoint is added to the signing rotation without a corresponding manifest entry, or if the set of unpinned authorities changes unexpectedly.

When run against a sealed demonstration contract in the vault, the store now reports the document signature as `VERIFIED` and the timestamp assurance as `existed by 2026-09-24T03:16:37Z, per GlobalSign`. If the pinned root bundle is removed, the timestamp status drops to `indeterminate` while the signature verdict remains unchanged.

## Making trust setup repeatable

Trust anchors documented only in a README rarely survive deployment. We packaged the root bundle directly inside the Python module and added `python -m provnat.trust` to manage installation and auditing:

- Installation is idempotent. Existing identical files are untouched. If a local anchor file differs from the package manifest, the installer refuses to overwrite it unless `--force` is passed, in which case it writes a timestamped backup first.
- The audit command reports whether anchors are current, missing, or modified, flags certificates approaching expiration, lists unpinned authorities, and verifies that the live signing rotation matches the manifest.
- Signing the installed trust configuration with the operator's root key remains a manual human step. The CLI prints the exact command required rather than attempting to automate root key usage.

We also exposed these checks inside our internal Obsidian gate so a workstation setup can be verified directly from the editor. Commit `b4e96df` records all 135 package tests passing.

## What this establishes

Pinned RFC 3161 verification establishes an auditable upper bound on when a set of bytes existed, attested by an external authority and verified against root certificates we control. It does not prove that the contents of the document are accurate, and tokens from unpinned authorities receive no automatic trust. When evidence is incomplete, the right engineering answer is `indeterminate`.

*Evidence for the claims above: commits `de9b89c`, `88b042e`, and `b4e96df` in the provenance monorepo.*
