Skip to content

seal: nothing holds verified trusted lists at runtime, so the qualification verdict cannot be served #324

Description

@LKSNDRTMLKV

dpp_seal::qualification::qualify takes the verified national lists to consult as an argument. Nothing supplies them at runtime, so the seal route reports origin — who issued the certificate, which needs no list — and cannot report the trusted-list half at all.

Closing that means a node holding verified lists while it is running: fetch the list of trusted lists, verify it against the pinned Official Journal anchor, fetch and verify each national list it points at, and keep the result.

The constraint that shapes it

IssuerStanding::NotListed becomes unsound the moment the cache is incomplete.

Its doc already says so: "this is a statement about the lists that were passed in, not about the Union." That is honest while a caller chooses the lists deliberately. A cache changes the meaning — a caller asking "is this issuer listed?" of a cache that silently holds 26 of 27 lists gets NotListed for a perfectly qualified Estonian provider, and nothing distinguishes that from a genuine miss.

So the cache has to carry its own completeness, and the verdict has to be able to say "this territory could not be checked" separately from "this issuer is not listed". #320 makes that concrete rather than theoretical: Germany's list does not verify at all today, and Germany has one of the larger provider populations.

That is the same fail-closed direction the rest of this workspace takes, and it is the one thing that cannot be retrofitted comfortably — it changes the verdict type.

What the shape has to answer

  • Cold start. A node cannot block boot on 27+ fetches of several MB each. What does the seal route report while the cache is still filling? (Not NotListed.)
  • Refresh. Lists carry NextUpdate; the LOTL does too. Refresh is per-list, not a single global sweep, and a failed refresh must leave the previous good copy in place rather than emptying the entry.
  • Size. The measured population is ~40 MB of XML across the Union, and Germany alone is 5.11 MiB. Parsed and reduced to providers, services, histories and certificates it is far smaller — store the parsed form, not the documents. MAX_TRUSTED_LIST_BYTES is 8 MiB per document and exists for the fetch, not for retention.
  • Where it lives. In memory per process, or persisted? Persisting survives restarts and makes the cold-start question mostly disappear, at the cost of a store and a schema for something already published and signed elsewhere.
  • Anchor freshness. feat(seal): warn when the pinned anchor has been superseded #321 reports when the pinned anchor has been superseded. A cache is where that signal becomes actionable rather than incidental, because it is the thing doing the refreshing.

Why it is not urgent

Nothing can produce a qualified seal here today, so the trusted-list half of the verdict has nothing true to say about our own seals — they are self-issued, and the route reports that already without any list.

It becomes the blocker the moment a QTSP credential exists.

Related

#295 (the verifier this would drive) · #320 (Germany, which forces the uncheckable-territory distinction) · #321 (anchor freshness) · #323 (path verification, which a cache feeds) · the guarded fetch path already exists as trustlist::fetch_trusted_list.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions