Time Anchor Trust Roots
This guide defines the minimal, deterministic bundle format Stella Ops uses to distribute the trust roots that validate time tokens (Roughtime and RFC 3161) in sealed, air-gapped deployments. It is written for operators who package the offline kit and for engineers wiring the AirGap Time service.
For the API that consumes these roots, see AirGap Time API. For the broader staleness and time-anchor model, see Staleness and time.
Artefacts
- JSON schema:
docs/modules/airgap/schemas/time-anchor-schema.json - Trust roots bundle (sample):
docs/modules/airgap/schemas/time-anchor-trust-roots.json
Bundle format (time-anchor-trust-roots.json)
{
"version": 1,
"roughtime": [
{
"name": "stellaops-test-roughtime",
"publicKeyBase64": "BASE64_ED25519_PUBLIC_KEY",
"validFrom": "2025-01-01T00:00:00Z",
"validTo": "2026-01-01T00:00:00Z"
}
],
"rfc3161": [
{
"name": "stellaops-test-tsa",
"certificatePem": "-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----",
"validFrom": "2025-01-01T00:00:00Z",
"validTo": "2026-01-01T00:00:00Z",
"fingerprintSha256": "HEX_SHA256"
}
]
}
- All times are UTC, ISO 8601.
- Fields are deterministic; the only variability is the number of entries per list.
- Consumers must reject expired roots and enforce a matching token format (Roughtime vs. RFC 3161).
Usage guidance
- Ship the bundle with the air-gapped deployment alongside the time-anchor schema.
- Configure the AirGap Time service to load roots from a sealed path; never fetch them over the network.
- In production, the AirGap Time service verifies anchors only against the sealed, configured roots from
AirGap:TrustRootFile(or an equivalent store). It rejects request-body fields that attempt to supply a replacement root. - Rotate by bumping
version, adding new entries, and settingvalidFrom/validTo; keep prior roots until all deployments have rolled over.
Local harness overrides
These switches relax verification for local development and automated tests only. They must stay disabled in any sealed production deployment.
AirGap:AllowRequestSuppliedTrustRoots=trueenables request-body trust roots, and only when the host environment isDevelopmentorTesting. The override exists for deterministic local and API harnesses that need throwaway roots. Production requests fail withrequest-supplied-trust-roots-disabledrather than honour body-supplied roots.AirGap:AllowUntrustedAnchors=trueis a separate local/testing bypass for parser-only anchor flows. It must not be enabled in sealed production.
Generating a throwaway dev root
To exercise the verification path end-to-end before production roots are issued:
- Generate an Ed25519 key pair for Roughtime:
openssl genpkey -algorithm Ed25519 -out rtime-dev.pem openssl pkey -in rtime-dev.pem -pubout -out rtime-dev.pub - Base64-encode the public key (
base64 -w0 rtime-dev.pub), place the value intopublicKeyBase64, and set a short validity window. - Point
AirGap:TrustRootFileat your edited bundle and setAirGap:AllowUntrustedAnchors=true(dev only).
Production readiness checklist
- Replace sample values with production Roughtime public keys and TSA certificates once issued by the security team.
- Add regression tests in
StellaOps.AirGap.Time.Teststhat load the bundle and validate sample tokens once real roots are present.
