Specify candidate signed time samples and trust lifecycle
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a09cbc-910e-77a0-b336-3130194350b3
This commit is contained in:
parent
8f2d17ae06
commit
7af595b2cc
7 changed files with 299 additions and 0 deletions
23
specs/protected-header-v0.1.schema.json
Normal file
23
specs/protected-header-v0.1.schema.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "protected-header-v0.1 review candidate v0.1",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"alg",
|
||||
"kid",
|
||||
"typ"
|
||||
],
|
||||
"properties": {
|
||||
"alg": {
|
||||
"const": "ES256"
|
||||
},
|
||||
"kid": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}(?![\\s\\S])"
|
||||
},
|
||||
"typ": {
|
||||
"const": "railiance-clock-sample-v0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -198,3 +198,6 @@ dependencies, not placeholders to bypass while shipping.
|
|||
- Authenticated NTP option for infrastructure review (not v0.1 wire protocol): https://www.rfc-editor.org/rfc/rfc8915
|
||||
- Corporate domain time: https://learn.microsoft.com/en-us/windows-server/networking/windows-time-service/how-the-windows-time-service-works
|
||||
- Internal ownership links: ../docs/ecosystem.md.
|
||||
|
||||
Detailed wire/trust review candidate: [sample profile](sample-profile-v0.1.md).
|
||||
This supplies proposed field/encoding choices; owner admission remains RCLK-WP-0002.
|
||||
|
|
|
|||
148
specs/sample-profile-v0.1.md
Normal file
148
specs/sample-profile-v0.1.md
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
# Time sample profile — review candidate v0.1
|
||||
|
||||
Status: proposed under RCLK-WP-0002-T02/T03, 2026-09-14. No trust owner has
|
||||
adopted this profile. It refines the base specification for review; conflicting
|
||||
or unresolved requirements prevent implementation admission.
|
||||
|
||||
## Transport and signature candidate
|
||||
|
||||
HTTPS POST `/v1/time-samples` accepts the request schema, at most 1 KiB of UTF-8
|
||||
JSON, and returns at most 8 KiB of ASCII JWS Compact Serialization with
|
||||
`Content-Type: application/jose`. No redirects, compression or detached payloads.
|
||||
Set `Cache-Control: no-store` on responses. HTTP failure, wrong media type,
|
||||
oversize or an unsigned error never establishes time. No bearer credential is
|
||||
needed by this candidate sample request; endpoint access/exposure remains an
|
||||
owner decision. TLS validation must already work through an admitted path.
|
||||
|
||||
Choose JWS Compact Serialization as the candidate envelope: its protected header
|
||||
and exact payload bytes are covered by the signature. Verify the original encoded
|
||||
segments; never parse and reserialize before signature verification.
|
||||
[Envelope standard: RFC 7515](https://www.rfc-editor.org/rfc/rfc7515).
|
||||
|
||||
Candidate algorithm is `ES256`, restricted to P-256 keys and SHA-256, with the
|
||||
JWS 64-byte R||S signature encoding. Use a maintained JOSE/crypto library, never
|
||||
handwritten ECDSA. Owner/library compatibility review is still required.
|
||||
[Algorithm definition: RFC 7518 §3.4](https://www.rfc-editor.org/rfc/rfc7518#section-3.4).
|
||||
|
||||
Protected header contains exactly `alg`, `kid`, and
|
||||
`typ: railiance-clock-sample-v0.1`. This typ is an application discriminator,
|
||||
not a registered media type. Reject all other headers, including embedded keys,
|
||||
remote key URLs, `crit`, and alternate payload encoding. No algorithm negotiation,
|
||||
`none`, MAC profile, or token/key reuse. `kid` selects only within the locally
|
||||
admitted authority/environment trust binding, never a global key search.
|
||||
|
||||
JSON is UTF-8 without BOM, duplicate member names, nonfinite numbers or trailing
|
||||
content. Enforce these at decoding, before a JSON Schema validator loses lexical
|
||||
information. Limit nesting to 4. Base64url segments are unpadded, canonical and
|
||||
nonempty; decoding and re-encoding must match. Fixed signatures decode to 64 bytes.
|
||||
The signature binds bytes, so JSON member ordering is not a security ambiguity;
|
||||
no additional JSON canonicalization scheme is required. Unknown fields/versions
|
||||
are refused rather than interpreted through a newer schema silently.
|
||||
|
||||
## Fields, units and correlation
|
||||
|
||||
See the adjacent request, sample and protected-header schemas. The sample schema
|
||||
applies to the decoded authenticated payload, not to the JWS envelope.
|
||||
|
||||
- `profile` fixes wire semantics; `authority_id` and `environment` must equal
|
||||
locally configured expectations and the outstanding request.
|
||||
- `nonce` is 32 random bytes encoded as 43 base64url characters. The requester
|
||||
generates it with a cryptographic RNG. Schema length alone cannot prove entropy
|
||||
or canonical encoding; the decoder must also verify those requirements.
|
||||
- `epoch` is an opaque continuity identifier. A UUID-shaped label is not a
|
||||
monotonic generation, a freshness proof, or rollback authorization.
|
||||
- `policy_id` names an immutable owner-adopted policy revision. Unknown revisions
|
||||
are refused. The policy fixes leap handling, quality/error model, timer model,
|
||||
trust freshness and local lifetime/RTT limits.
|
||||
- `receive_unix_ns` and `send_unix_ns` are decimal strings of nonnegative signed
|
||||
64-bit POSIX nanoseconds since 1970-01-01T00:00:00Z. `error_ns` is a nonnegative
|
||||
bound covering server send-time error, including acquisition resolution and
|
||||
health observation aging. `max_age_ns` is a positive lifetime ceiling measured
|
||||
from client request send, not from eventual response receipt.
|
||||
- `quality` is `bounded` for candidate usable samples. No unhealthy sample with
|
||||
a fabricated numeric bound is permitted. Diagnostics are a separate response.
|
||||
A signed `bounded` assertion still requires the locally admitted policy/model.
|
||||
|
||||
All decimal values must be <= 9223372036854775807, with no sign, exponent, decimal
|
||||
point or leading zeros. Schema checks lexical shape only; implementations must
|
||||
check numerical limits, send >= receive, and checked arithmetic separately.
|
||||
There is no JWT `exp` evaluated against a misaligned local wall clock.
|
||||
|
||||
POSIX nanoseconds do not encode a distinct leap second. This profile therefore
|
||||
cannot claim protected use during a leap ambiguity: the admitted policy must
|
||||
specify detection, exclusion and reacquisition behavior before deployment.
|
||||
Ordinary RFC3339 display is derived from the accepted interval; display precision
|
||||
is not an accuracy claim. Local timezone display conversion is separate.
|
||||
|
||||
## Acceptance sequence and lifetime
|
||||
|
||||
1. Before sending, require admitted transport/key/policy context and a supported
|
||||
clock domain. Store nonce, request fields and monotonic send instant. Bound
|
||||
outstanding requests and local timeout; limits come from local policy.
|
||||
2. At receipt, capture monotonic receive time, reject domain/suspend changes and
|
||||
expired requests, enforce envelope/JSON limits, select the pinned key and verify
|
||||
signature/type/algorithm. Do not trust payload values until verification.
|
||||
3. Validate the authenticated payload schema and semantic limits; match nonce,
|
||||
authority/environment/profile, policy and continuity. Atomically retire the
|
||||
nonce before installing the mapping. Only one response wins. Failed/expired
|
||||
exchanges retire their nonce and retry with a new one. Resource exhaustion
|
||||
may deny service but must never result in accepting a weaker sample.
|
||||
4. Obtain conservative real elapsed bounds [Rmin,Rmax] from the reviewed timer
|
||||
model. Accept the server-send error bound e only under admitted health policy.
|
||||
At receipt use L=s3-e and U=s3+e+Rmax, as in the base specification. Checked
|
||||
arithmetic must reject underflow/overflow. Server processing is not subtracted.
|
||||
5. Age limits count conservative elapsed time since request send, including transit,
|
||||
verification and any later processing. The smallest local, signed, trust and
|
||||
policy lifetime limit applies. A slow response cannot restart the age budget.
|
||||
Require the upper bound on age to be strictly below the applicable limit.
|
||||
6. At each read, propagate from the receipt anchor by reviewed elapsed bounds
|
||||
[Dmin,Dmax]: [L+Dmin,U+Dmax]. Check interval width, age, trust, continuity and
|
||||
lifecycle before returning usable. The API does not execute a protected action;
|
||||
consumers still check validity and action binding at the side effect.
|
||||
|
||||
Arithmetic example, synthetic only: s3=1000000000 ns, e=2000000 ns and
|
||||
Rmax=20000000 ns yield [998000000,1022000000]. A later elapsed interval
|
||||
[9990000,10010000] yields [1007990000,1032010000]. These numbers establish no
|
||||
production oscillator, RTT, uncertainty or freshness threshold.
|
||||
|
||||
No protected holdover is admitted initially. Repeated reads of a live mapping
|
||||
still require a proven bounded timer/lifecycle model and its finite age policy.
|
||||
The schema alone cannot prove any of these operational assumptions.
|
||||
|
||||
## Trust, epoch and restart rules
|
||||
|
||||
The trust owner must supply an authoritative binding of authority/environment,
|
||||
key ID, algorithm/public key, policy revision and validity/revocation state.
|
||||
A signed sample cannot supply its own trust admission. Protected verification
|
||||
requires independently admitted current trust evidence; if its freshness/validity
|
||||
cannot be established with the available bootstrap context, return untrusted.
|
||||
No use of the sample being evaluated to bootstrap its own key validity.
|
||||
|
||||
Owner review must name the actual trust delivery/revocation mechanism and prove
|
||||
its operation with wrong OS time. Until that exists, only isolated fixtures are
|
||||
possible. HTTPS that cannot validate remains a bootstrap failure; never disable
|
||||
certificate checks to obtain the first sample.
|
||||
|
||||
Rotation requires the new key binding to be admitted before use. Revoke all
|
||||
cached mappings signed by a revoked key; an old nonce/signature or code rollback
|
||||
cannot restore it. Require a fresh exchange after process restart or epoch change.
|
||||
Persisted rollback floors must have owner-approved integrity/recovery semantics.
|
||||
If a new interval is wholly older than a trustworthy prior lower bound, refuse;
|
||||
an overlapping interval does not prove continuity. Missing/corrupted persistent
|
||||
state, restored VM snapshots or unknown epoch changes require reviewed recovery,
|
||||
not automatic floor reset. The concrete storage/recovery design is still open.
|
||||
|
||||
## Review evidence still required
|
||||
|
||||
T02: signing library/custody compatibility; native trust bootstrap/revocation and
|
||||
rotation; authoritative key bindings; epoch/floor recovery; leap policy adoption.
|
||||
T03: measured server error model; Linux/Windows/WSL timer and suspend detection;
|
||||
verified age/width thresholds; delayed/asymmetric path and arithmetic tests.
|
||||
T04: consumer-specific validity boundaries, atomic consume/check-to-use and audit
|
||||
attribution, including wrong-principal/tenant negatives.
|
||||
|
||||
Schema fixtures test structural rejection only. They are unsigned, synthetic and
|
||||
not a cryptographic, native transport, lifecycle or UTC-quality acceptance proof.
|
||||
Future conformance must include duplicate JSON keys, noncanonical base64url,
|
||||
wrong JWS key/algorithm/header, bad signature, replay, unknown policy, numerical
|
||||
overflow, stale trust, delayed replies and suspend during verification.
|
||||
29
specs/time-request-v0.1.schema.json
Normal file
29
specs/time-request-v0.1.schema.json
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "time-request-v0.1 review candidate v0.1",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"profile",
|
||||
"authority_id",
|
||||
"environment",
|
||||
"nonce"
|
||||
],
|
||||
"properties": {
|
||||
"profile": {
|
||||
"const": "railiance-clock-v0.1"
|
||||
},
|
||||
"authority_id": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}(?![\\s\\S])"
|
||||
},
|
||||
"environment": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}(?![\\s\\S])"
|
||||
},
|
||||
"nonce": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9_-]{43}(?![\\s\\S])"
|
||||
}
|
||||
}
|
||||
}
|
||||
63
specs/time-sample-v0.1.schema.json
Normal file
63
specs/time-sample-v0.1.schema.json
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "time-sample-v0.1 review candidate v0.1",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"profile",
|
||||
"authority_id",
|
||||
"environment",
|
||||
"nonce",
|
||||
"epoch",
|
||||
"policy_id",
|
||||
"receive_unix_ns",
|
||||
"send_unix_ns",
|
||||
"error_ns",
|
||||
"max_age_ns",
|
||||
"quality"
|
||||
],
|
||||
"properties": {
|
||||
"profile": {
|
||||
"const": "railiance-clock-v0.1"
|
||||
},
|
||||
"authority_id": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}(?![\\s\\S])"
|
||||
},
|
||||
"environment": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}(?![\\s\\S])"
|
||||
},
|
||||
"nonce": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9_-]{43}(?![\\s\\S])"
|
||||
},
|
||||
"epoch": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}(?![\\s\\S])"
|
||||
},
|
||||
"policy_id": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}(?![\\s\\S])"
|
||||
},
|
||||
"receive_unix_ns": {
|
||||
"type": "string",
|
||||
"pattern": "^(0|[1-9][0-9]{0,18})(?![\\s\\S])"
|
||||
},
|
||||
"send_unix_ns": {
|
||||
"type": "string",
|
||||
"pattern": "^(0|[1-9][0-9]{0,18})(?![\\s\\S])"
|
||||
},
|
||||
"error_ns": {
|
||||
"type": "string",
|
||||
"pattern": "^(0|[1-9][0-9]{0,18})(?![\\s\\S])"
|
||||
},
|
||||
"max_age_ns": {
|
||||
"type": "string",
|
||||
"pattern": "^[1-9][0-9]{0,18}(?![\\s\\S])"
|
||||
},
|
||||
"quality": {
|
||||
"const": "bounded"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
specs/unsigned-fixtures.json
Normal file
26
specs/unsigned-fixtures.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"request": {
|
||||
"profile": "railiance-clock-v0.1",
|
||||
"authority_id": "fixture-authority",
|
||||
"environment": "isolated-test",
|
||||
"nonce": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
},
|
||||
"header": {
|
||||
"alg": "ES256",
|
||||
"kid": "fixture-key",
|
||||
"typ": "railiance-clock-sample-v0.1"
|
||||
},
|
||||
"sample": {
|
||||
"profile": "railiance-clock-v0.1",
|
||||
"authority_id": "fixture-authority",
|
||||
"environment": "isolated-test",
|
||||
"nonce": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||
"epoch": "fixture-epoch",
|
||||
"policy_id": "fixture-policy-1",
|
||||
"receive_unix_ns": "999000000",
|
||||
"send_unix_ns": "1000000000",
|
||||
"error_ns": "2000000",
|
||||
"max_age_ns": "100000000",
|
||||
"quality": "bounded"
|
||||
}
|
||||
}
|
||||
|
|
@ -64,3 +64,10 @@ Review started 2026-09-14: `docs/identity-and-utc-review.md` pins the IAM/layer
|
|||
source baseline, separates actors/workloads/permissions/Ansible artifacts, and
|
||||
identifies source-selection, leap and error-bound gates. Owner assent and measured
|
||||
policy remain pending; no review task is complete from the proposal alone.
|
||||
|
||||
Sample/trust candidate added: `specs/sample-profile-v0.1.md`, three closed
|
||||
JSON schemas and unsigned fixtures. Schema validation: three positive fixtures
|
||||
and twenty structural negatives; no crypto/lifecycle/UTC acceptance claimed.
|
||||
Trust delivery, measured timer/error policy, leap and rollback recovery remain
|
||||
owner review gates. Custodian response 03014307-20b6-47d3-81f4-7f12fcaed014
|
||||
confirms discovery only and does not close admission tasks.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue