Skip to content

Nothing checks the conformance level a seal actually came back at #290

Description

@LKSNDRTMLKV

The seal request names a conformance level. Nothing checks what came back.

level_for_profile() classifies the configured signature_profile string, and the boot gate compares that configuration against the backend's advertised capabilities. Neither reads the returned CMS. A provider that silently returns CAdES_BASELINE_T when asked for LT — a client enabled for the wrong profile, a plan change, a provider-side default — produces a seal that looks correct in every record this node keeps, and stops verifying when the signing certificate expires, years after the passport was retention-locked.

That is precisely the failure SealConformanceLevel's own documentation describes as uncorrectable.

crates/dpp-seal/src/cades.rs already parses the CMS SignedData down to its single signer and certificate. It has everything needed.

What the levels are distinguished by

From ETSI EN 319 122-1 clause 6.1 and Table 1 (CAdES baseline). Read the table with a table-aware extractor — a plain layout extraction detaches the value columns from their rows and silently misattributes them.

Level Distinguishing material
B-B none of the below
B-T signature-time-stamp unsigned attribute (id-aa-signatureTimeStampToken, OID 1.2.840.113549.1.9.16.2.14) — shall be present at B-T and above, * at B-B
B-LT B-T material, plus the "revocation values in long-term validation" service shall be provided — i.e. SignedData.crls populated (crls.crl or crls.other, the latter carrying OCSP)
B-LTA B-LT material, plus the archive-time-stamp-v3 unsigned attribute

Two traps worth writing into the code comments:

  • The legacy attributes are forbidden, not required, at LT. certificate-values, revocation-values, complete-certificate-references and complete-revocation-references are shall not be present at B-LT and B-LTA (cardinality 0). Looking for them as evidence of LT finds the opposite of what it means. At B-LT the validation material lives in SignedData.certificates and SignedData.crls.
  • SignedData.certificates does not discriminate. It is shall be present at every level, B-B included.

What to build

A cades::evidenced_level(seal_der) -> Option<SealConformanceLevel> reporting the highest level whose distinguishing material is present.

Name and document it as a floor, not a verdict. Full conformance to a baseline level requires many more rows of Table 1 (signing-time shall be present, content-type shall be id-data, the ESS signing-certificate SPO, and so on). This function establishes that the material for a level is there, not that the seal conforms. It belongs in the same register as the rest of that module — reported, never verified — and the module doc already makes that distinction the reason it exists as a separate module.

Then:

  • Expose it on SealResponse beside the requested level, as evidencedConformanceLevel, so an auditor sees request and bytes side by side. Same shape as sealedPayloadHash versus the validator's extracted message digest: this node states both and says which is which.
  • Log a warning at drain time when the evidenced level is below the requested one. Not an error — the seal is bought and the row should not retry — but a node that has been quietly buying the wrong thing should say so on the first occurrence, not on the first expiry.
  • The local backend is a ready-made fixture: sign_detached sets unsigned_attrs: None, so it must classify as BaselineB and never higher.

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