feat(seal): read and verify EU Trusted Lists - #316
Open
LKSNDRTMLKV wants to merge 7 commits into
Open
LKSNDRTMLKV wants to merge 7 commits into
LKSNDRTMLKV wants to merge 7 commits into
Conversation
Member
Author
|
@coderabbitai review |
|
LKSNDRTMLKV
force-pushed
the
feat/trusted-list-revived
branch
from
September 15, 2026 05:06
79d0082 to
7503b7e
Compare
LKSNDRTMLKV
force-pushed
the
feat/trusted-list-revived
branch
from
September 15, 2026 06:25
7503b7e to
ad247db
Compare
This was referenced Sep 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Revives #294, which GitHub auto-closed when its base branch
feat/seal-evidenced-levelmerged as #292. The work was finished and pushed; nothing was wrong with it except that its PR closed underneath it. Stacked on #312 — retarget tomainbefore that one merges.just checkis green (1121/1121).Why this is stacked rather than independent
It needs
dpp_domain::trusted_listandSealedEnvelope::conformance_level, both new indpp-core0.20.0, so it does not build against the pin onmain. That is the dependency the original note recorded as "blocked on the core repin", and #312 clears it.What it adds
dpp_seal::trustlist—verify_lotlfor the List of Trusted Lists,verify_trusted_listfor a Member State's, plus parsers, fetcher and typed rejections. Nothing calls it yet. This is the reader, not a policy.The trust anchor is an Official Journal notice, not a certificate authority. The LOTL's signing certificates chain to no commercial root — they are published in the OJ C series, which the LOTL names through its own
SchemeInformationURI. There is nothing to walk up to, so the anchor is six SHA-256 digests taken from notice52026XC01944, compiled in with the location, CELEX and pin date beside them. Compiled in and never configuration: an operator who can repoint the anchor can make any list verify.Those six digests are the entire pinned surface. No Member State's certificates live in the repository — they arrive inside a document that has already been verified, so a country joining or rotating needs no code change and no release.
authorisesis a precondition, not a verdict: anyone can copy the genuine certificate into a forgery and pass it, and only the signature separates them. The converse is the sharper half — Finland's list is genuine and correctly signed by Finland, which does not sign the LOTL, and it verifies cleanly with the anchor check disabled. That pair is why both halves exist, and there is a test for each.What reviewers should look at hardest
The recurring operational obligation. The pin must be refreshed when the Commission republishes the notice, and the current signer expires 2027-11-17 — a calendar date, not a discovery. A stale pin fails closed and reads as an outage. The reader carries the early signal (the LOTL's first
SchemeInformationURIentry is the current notice), but nothing acts on it yet.The
xml-secfork. Italy (2.86 MB) and France (2.55 MB) exceed a compile-time node-set ceiling in the published crate and cannot be verified at any configuration — the constant ispub(crate)and the policy knob that looks like it raises the limit is validated against the same number. They miss by four and five nodes, and trusted lists only grow. The fork changes that one constant and nothing else, pinned by rev rather than vendored because the crate is ~66k LOC.Changes made during the revival
A
deny.tomlsource allowance. The sources policy denies git dependencies deliberately — "a git dependency is how unreviewed code enters a build" — so the fork needs an explicit entry. Added with the justification and the exit condition: whenstructured-world/xml-sec#158resolves, the[patch.crates-io]stanza and thedeny.tomlentry go together. The rule still stands for everything else; this one is allowed because the review is a single constant, not because forks are fine.A CHANGELOG entry. The work had none.
One conflict that was a real disagreement, not a textual one. This branch recorded a seal's
conformance_levelas what the bytes carry; #312 records what was requested. Core settles it — the field's doc says it is "a record of what was asked for, not proof of what arrived", and the conformance kit'sseal.misrecorded_levelrule fails an envelope whose stored level disagrees with the request. I kept the request.The concern behind the other version was legitimate and is preserved in the comment: echoing a request could launder a broken
can_produceguard. What actually catches that iscades::evidenced_level, read independently by the drain, which alarms on the disagreement rather than letting either side vouch for itself.Not in this PR
#297 — the mandatory TS 119 612 signature profile from CID (EU) 2025/2164 (one
ds:ReferencewithURI="", exactly oneds:Transforms, exactly two named algorithms) is not asserted. That work lands on top of this, because it edits files this PR creates.