attested_sealing_time reads the signature timestamp out of a seal and checks two things: the token's own signature, and that its messageImprint covers this signature (EN 319 122-1 clause 5.3). Both were added in #322, and together they mean a token cannot be lifted from another seal.
What is never checked is the timestamp authority's own certificate. Not its validity window at the moment it claims to have stamped, not its chain, not its revocation. A token signed by a certificate that had expired years before genTime is accepted, and so is one signed by a certificate the signer minted themselves.
Why that now decides verdicts
It used to be a reporting question — attestedSealedAt was a field a reader could weigh. #322 made it load-bearing:
SealValidationStatus::of uses judgedAt.attested to decide whether a certificate finding is a failure or an open question. With an attested moment, a certificate outside its window is totalFailed / expired; without one it is indeterminate / outOfBoundsNoPoe. The same for revocation.
So the permissive direction is the problem. Consider a seal whose certificate had expired when it was made — the case the window check exists to catch:
- with no timestamp, the moment is this node's clock, the certificate reads expired now, and the verdict is
outOfBoundsNoPoe: unproven, visible, not dismissed;
- attach a timestamp saying a moment inside the window, signed by any key at all, and the window check passes. The verdict improves to
indeterminate with no sub-indication — the same answer a sound seal gets.
The imprint check does not prevent this: it binds the token to this signature, and anyone who can edit the stored seal can compute that imprint. They cannot steal someone else's token; they can make their own.
What a real check needs
EN 319 102-1's timestamp validation building block wants the token's signing certificate validated at genTime, and Art. 42 makes a qualified timestamp a QTSP service — a Trusted List question about the TSA/QTST service type, which #324 is the prerequisite for.
Those are different amounts of work, and the first is worth having on its own:
- The window — read the TSA certificate's
notBefore/notAfter and refuse a token stamped outside it. Purely local, no list needed, and it removes the self-made-token escalation above for any certificate that is not freshly minted.
- The chain and the list — whether the authority is one anybody trusts. Needs
#324, and until then the honest report is that the time is attested but the attester is unknown, which the seal route's documentation already says.
A wrinkle worth deciding
This node's own local backend runs a self-signed TSA whose certificate says NOT A QUALIFIED TIMESTAMP. Under (1) its tokens still pass — the certificate is valid, it is simply nobody's. Under (2) they would not, and the local development path would have to keep reporting an attested time or every B-T-and-above local seal becomes outOfBoundsNoPoe the moment its certificate ages out. Worth settling before (2), not after.
attested_sealing_timereads the signature timestamp out of a seal and checks two things: the token's own signature, and that itsmessageImprintcovers this signature (EN 319 122-1 clause 5.3). Both were added in#322, and together they mean a token cannot be lifted from another seal.What is never checked is the timestamp authority's own certificate. Not its validity window at the moment it claims to have stamped, not its chain, not its revocation. A token signed by a certificate that had expired years before
genTimeis accepted, and so is one signed by a certificate the signer minted themselves.Why that now decides verdicts
It used to be a reporting question —
attestedSealedAtwas a field a reader could weigh.#322made it load-bearing:SealValidationStatus::ofusesjudgedAt.attestedto decide whether a certificate finding is a failure or an open question. With an attested moment, a certificate outside its window istotalFailed/expired; without one it isindeterminate/outOfBoundsNoPoe. The same for revocation.So the permissive direction is the problem. Consider a seal whose certificate had expired when it was made — the case the window check exists to catch:
outOfBoundsNoPoe: unproven, visible, not dismissed;indeterminatewith no sub-indication — the same answer a sound seal gets.The imprint check does not prevent this: it binds the token to this signature, and anyone who can edit the stored seal can compute that imprint. They cannot steal someone else's token; they can make their own.
What a real check needs
EN 319 102-1's timestamp validation building block wants the token's signing certificate validated at
genTime, and Art. 42 makes a qualified timestamp a QTSP service — a Trusted List question about theTSA/QTSTservice type, which#324is the prerequisite for.Those are different amounts of work, and the first is worth having on its own:
notBefore/notAfterand refuse a token stamped outside it. Purely local, no list needed, and it removes the self-made-token escalation above for any certificate that is not freshly minted.#324, and until then the honest report is that the time is attested but the attester is unknown, which the seal route's documentation already says.A wrinkle worth deciding
This node's own local backend runs a self-signed TSA whose certificate says
NOT A QUALIFIED TIMESTAMP. Under (1) its tokens still pass — the certificate is valid, it is simply nobody's. Under (2) they would not, and the local development path would have to keep reporting an attested time or everyB-T-and-above local seal becomesoutOfBoundsNoPoethe moment its certificate ages out. Worth settling before (2), not after.