[Secdispatch] Re: [saag] Re: Re: draft-yossif-psea-0 2 posted — re-scoped as an EAT token profile (diff)

Mohamad Khalil-Yossif <[email protected]> Thu, 11 Jun 2026 11:43:21 +0300
Newsgroups gmane.ietf.secdispatch,gmane.ietf.saag
Message-ID <[email protected]>
--===============1596498497974503637==
Content-Type: multipart/alternative;
 boundary="----=_NextPart_14786603.206481159137"

------=_NextPart_14786603.206481159137
Content-Type: text/plain;
 charset="utf-8"
Content-Transfer-Encoding: quoted-printable

Songbo, Iman, all,

Songbo =E2=80=94 following up with substance on both of your notes.

On the PSEA suggestions: the processing-model paragraph and the
negative-test table are going into the next revision largely as you
framed them. The invariant you want testable =E2=80=94 a rejected proof
leaves the counter high-water mark, finalized-jti set, chain entry,
ledger, and any approval-bearing result unchanged =E2=80=94 is how the
existing reference verifier already behaves (rejection happens before
any state mutation; counter advance and jti finalization are one
atomic transaction), so it will be stated as a MUST backed by
negative vectors in your failure grouping.

Your offline / server-state boundary holds for PSEA exactly as you
described: signature, action-binding, audience, and user-verification
evidence are offline-checkable; replay (jti / counter high-water
mark), enrollment-active, and revocation are necessarily
verifier-state decisions. "Reject before any approval-bearing state
mutation" as the invariant common to the profiles is the right
conformance boundary.

And so the comparison matrix has both columns =E2=80=94 here is PSEA on the
nine axes you proposed, all of it normative in -02:

- action canonicalization/hash: JCS (RFC 8785) =E2=86=92 SHA-256;
=C2=A0 non-canonical input rejected.
- approver/subject binding: a dedicated hardware-attested device key;
=C2=A0 the profile requires hardware-resident key material with enforced
=C2=A0 user verification, evidenced by a platform attestation chain. It is
=C2=A0 deliberately device- and vendor-agnostic =E2=80=94 any platform that=
 can
=C2=A0 produce that evidence can conform.
- operation/audience binding: psea_tier, psea_op, aud, iss byte-exact
=C2=A0 in the signed claim set; optional signed caller-identity binding.
- replay key: jti plus a per-scope strictly-increasing counter.
- one-time state: counter compare-advance and jti finalization in one
=C2=A0 atomic transaction; replay terminally refused. Same property as
=C2=A0 EP's nonce-consumption, enforced differently.
- trust root: the platform key-attestation chain =E2=80=94 never the operat=
or.
- relying-party result: signed proof token; the highest enforcement
=C2=A0 tier additionally requires a server ACK before execution,
=C2=A0 fail-closed.
- enforcement class: four tiers (P/S/E/A), from passive evidence to
=C2=A0 per-action online fail-closed authorization.
- residual risk: WYSIWYS / display integrity and natural-person
=C2=A0 identity =E2=80=94 both explicitly out of scope, stated in the draft.

Implementation status, in the same terms as the other efforts: a
complete reference implementation across two major mobile platforms
plus a deployed backend verifier, with cross-platform golden vectors
locking the canonicalization byte-for-byte. Canonical vectors are in
Appendix A of -02; a negative-case set in your failure grouping
exists on this side as well =E2=80=94 happy to point you at it for the
vector pass.

Mohamad Khalil-Yossif

On 11/06/2026 11:07:31, Iman Schrock <[email protected]> wrote:
Songbo =E2=80=94
Thank you =E2=80=94 running the vectors yourself is the validation that mat=
ters; reproduction beats assertion, and I'm glad Node and Web agreed on you=
r machine too.
Agreed completely: the offline / server-state split is a conformance bounda=
ry, not an implementation detail, so it gets a first-class row in the matri=
x rather than a footnote. Your phrasing of the invariant =E2=80=94=C2=A0rej=
ect before any approval-bearing state mutation=C2=A0=E2=80=94 is the right =
one to state once in the core section and inherit per profile. And it maps =
to PSEA exactly as you put it: the signed proof can carry or bind the jti /=
 counter / freshness material, but the high-water-mark decision is verifier=
 state on both sides.
That convergence =E2=80=94 one invariant, two attestation tiers, enforced i=
n the same place =E2=80=94 is what makes the dispatch question concrete rat=
her than asserted. Send the off-list nits whenever; I'll fold them in with =
the skeleton.
Iman,

On Thu, Jun 11, 2026 at 12:46 AM Songbo Bu <[email protected] [mailto:ki=
[email protected]]> wrote:

Hi Iman,

Thanks, this split is useful.

I took a quick look at the new signoff vectors and ran the signoff
conformance runner. The current shape matches the verifier boundary
you describe: 9 vectors, 8 reject cases, all at the offline assertion
layer, with the Node and Web Crypto verifiers agreeing.

One thing I would make explicit in the survey matrix is that the
offline/server-state split is not just an implementation detail; it is
a conformance boundary:

- verifier-state boundary: an offline assertion verifier can reject
structural, cryptographic, action-binding, audience, and UV failures;
replay / one-time consumption, enrollment-active, and revocation
freshness require server-state or ledger-side evaluation.

That maps cleanly to PSEA too. The signed proof can carry or bind the
jti/counter/freshness material, but the high-water mark decision is
still verifier state. So I would treat "reject before approval-bearing
state mutation" as the common invariant across both profiles.

I'll take a closer pass over the actual vectors and send concrete nits
off-list once the survey skeleton lands.

Best,
Songbo Bu

On Thu, 11 Jun 2026 00:38:02 -0700, Iman Schrock <[email protected] [m=
ailto:[email protected]]> wrote:
> Songbo =E2=80=94
>
> The processing-model + negative-test-table framing is the
> right call, and the decision-matrix axes you list are exactly the compari=
son
> I'd want too =E2=80=94 formats will differ, the verifier decision shouldn=
't.
>
> Two concrete things from my side:
>
> - I just
> published EP's Class-A signoff negative vectors as a tagged battery,
> grouped on your failure classes =E2=80=94 structural, cryptographic,
> action-binding, operation/audience, lifecycle/UV =E2=80=94 and run throug=
h two
> independent verifiers. It's a starting table for the pass you offered;
> please shred it. One honest scope line I drew, which I think matters for
> the survey: I split OFFLINE assertion checks (crypto, action- binding,
> audience, UV) from SERVER-STATE checks (replay / one-time consumption =E2=
=80=94
> the nonce is our global consumption key =E2=80=94 and enrollment-active).=
 A
> relying party verifying an EP receipt offline gets the former; the latter
> live at the consume/ledger step. PSEA's counter/jti high-water-mark
> invariant is the same idea on your side.
>
> - Here's
> EP filled into your matrix, as a strawman for the joint note:
>
> - action
> canonicalization/hash: JCS (RFC 8785) of the action object =E2=86=92 SHA-=
256
> context hash; non-canonical input MUST be rejected.
>
> - approver/subject
> binding: device-bound approver key (Class A, WebAuthn P-256); approver_id
> resolved via a signed Approver Directory.
>
> - operation/audience
> binding: action_hash + policy ref + initiator in the signed context;
> WebAuthn rp_id for the relying party.
>
> - replay
> key: 128-bit CSPRNG nonce, globally unique =E2=80=94 it IS the consumptio=
n key.
>
> - one-time
> state: consumed at most once, globally; replay across
> sessions/operators/time terminally refused.
>
> - trust
> root: the signed Approver Directory; MUST NOT default to the EP operator.
>
> - relying-party
> result: the offline-verifiable Trust Receipt (signed authorization +
> consumption record + Merkle anchor).
>
> - enforcement
> class: Class A device-bound (recommended) vs Class C operator-custodied
> (legacy, weaker); execution-side enforcement is the strongest deployment
> class.
>
> - residual
> risk: presentation attack / WYSIWYS, and key-revocation timing =E2=80=94 =
both
> stated, neither claimed solved.
>
> The two profiles land on different rows only at assurance
> tier (your dedicated-hardware attestation vs. our commodity authenticator=
) and
> scope (we add enrollment + separation of duties). Same decision matrix.
>
> I'll fold this into the survey skeleton I'm roughing out and
> send the whole thing off-list for you and Mohamad to edit.
>
> On Thu, Jun 11, 2026 at 12:24 AM Songbo Bu <[email protected] [mailto:=
[email protected]]> wrote:
>
> Hi Mohamad, Iman, all,
>
> Thanks, Mohamad. And Iman, that is a useful data point.
>
> For PSEA, my first pass would be to make the verifier-side text more
>
> like a processing model, plus a small set of negative verifier cases.
>
> That seems more useful to implementers than adding another long
>
> requirements list.
>
> For the processing model, something along these lines:
>
> > On receipt of a proof submission, the Verifier treats the signed proof,=
 the submitted action payload, enrollment state, and replay state as one at=
omic authorization decision. The Verifier first validates the signed token =
and then uses only claims from the verified payload, together with server-s=
ide enrollment and replay state, to evaluate the proof. Before any counter =
advance, ledger write, acknowledgement signing, or success-bearing Attestat=
ion Result, the Verifier canonicalizes the submitted actionPayload, recompu=
tes the payload hash, and compares it byte-for-byte with the signed psea_pa=
yload_hash. Any mismatch, missing required signed claim, stale freshness va=
lue, replayed jti/counter, inactive enrollment state, or failed cross-repla=
y binding is a non-approval outcome.
>
> I would then group failures into a small negative-test table rather
>
> than leave them spread across the document:
>
> - structural / cryptographic: wrong profile, unsupported alg, bad
>
> signature, unrecognized critical header;
>
> - action-binding: missing actionPayload, payload-hash mismatch,
>
> non-canonical payload, or psea_payload_hash encoding mismatch;
>
> - cross-replay: psea_tier, psea_op, aud, iss, or psea_caller_package
>
> not matching the expected operation context;
>
> - freshness / replay: expired proof, implausible iat, wrong eat_nonce,
>
> reused jti, or non-increasing counter;
>
> - lifecycle / trust gate: enrollment not active, revoked/suspended
>
> key, or user-verification evidence insufficient for the required
>
> assurance level;
>
> - optional chain layer: psea_chain_prev mismatch when that layer is enabl=
ed.
>
> The key point I would make testable is that all of those failures have
>
> the same security effect: the verifier rejects before any state
>
> mutation that could make the proof look consumed or approved. In
>
> test-vector terms, a rejected proof should leave the counter
>
> high-water mark, finalized-jti set, chain entry, approval ledger, and
>
> approval-bearing Attestation Result unchanged or absent.
>
> For Iman's draft, I think the useful comparison is not whether the
>
> token formats are identical, but whether the verifier decision
>
> matrices line up: action canonicalization/hash, approver or subject
>
> binding, operation/audience binding, replay key, one-time state, trust
>
> root, relying-party result, enforcement class, and residual risk. I
>
> can take a pass over that next, especially around Class A signoff
>
> negative vectors and deployment-class claims.
>
> Best,
>
> Songbo Bu
>
> --
>
> Iman Schrock
> Founder & CEO
>
> EMILIA Protocol | Trust Before High-Risk Action
> Eye warns. EP verifies. Signoff owns.
>
> [emiliaprotocol.ai [http://emiliaprotocol.ai]](http://emiliaprotocol.ai [=
http://emiliaprotocol.ai]) | GitHub
> [email protected] [mailto:[email protected]]



--

Iman Schrock
Founder & CEO

EMILIA Protocol | Trust Before High-Risk Action
Eye warns. EP verifies. Signoff owns.

emiliaprotocol.ai [http://emiliaprotocol.ai] | GitHub
[email protected] [mailto:[email protected]]
------=_NextPart_14786603.206481159137
Content-Type: text/html;
 charset="utf-8"
Content-Transfer-Encoding: quoted-printable

<div id=3D"__MailbirdStyleContent" style=3D"font-size: 10pt;font-family: Ca=
scadia Code;color: #1A1A1A;text-align: left" dir=3D"ltr"><div><span style=
=3D"font-size: 13.3333px">Songbo, Iman, all,</span></div><div><span style=
=3D"font-size: 13.3333px"><br></span></div><div><span style=3D"font-size: 1=
3.3333px">Songbo =E2=80=94 following up with substance on both of your note=
s.</span></div><div><span style=3D"font-size: 13.3333px"><br></span></div><=
div><span style=3D"font-size: 13.3333px">On the PSEA suggestions: the proce=
ssing-model paragraph and the</span></div><div><span style=3D"font-size: 13=
.3333px">negative-test table are going into the next revision largely as yo=
u</span></div><div><span style=3D"font-size: 13.3333px">framed them. The in=
variant you want testable =E2=80=94 a rejected proof</span></div><div><span=
 style=3D"font-size: 13.3333px">leaves the counter high-water mark, finaliz=
ed-jti set, chain entry,</span></div><div><span style=3D"font-size: 13.3333=
px">ledger, and any approval-bearing result unchanged =E2=80=94 is how the<=
/span></div><div><span style=3D"font-size: 13.3333px">existing reference ve=
rifier already behaves (rejection happens before</span></div><div><span sty=
le=3D"font-size: 13.3333px">any state mutation; counter advance and jti fin=
alization are one</span></div><div><span style=3D"font-size: 13.3333px">ato=
mic transaction), so it will be stated as a MUST backed by</span></div><div=
><span style=3D"font-size: 13.3333px">negative vectors in your failure grou=
ping.</span></div><div><span style=3D"font-size: 13.3333px"><br></span></di=
v><div><span style=3D"font-size: 13.3333px">Your offline / server-state bou=
ndary holds for PSEA exactly as you</span></div><div><span style=3D"font-si=
ze: 13.3333px">described: signature, action-binding, audience, and user-ver=
ification</span></div><div><span style=3D"font-size: 13.3333px">evidence ar=
e offline-checkable; replay (jti / counter high-water</span></div><div><spa=
n style=3D"font-size: 13.3333px">mark), enrollment-active, and revocation a=
re necessarily</span></div><div><span style=3D"font-size: 13.3333px">verifi=
er-state decisions. "Reject before any approval-bearing state</span></div><=
div><span style=3D"font-size: 13.3333px">mutation" as the invariant common =
to the profiles is the right</span></div><div><span style=3D"font-size: 13.=
3333px">conformance boundary.</span></div><div><span style=3D"font-size: 13=
.3333px"><br></span></div><div><span style=3D"font-size: 13.3333px">And so =
the comparison matrix has both columns =E2=80=94 here is PSEA on the</span>=
</div><div><span style=3D"font-size: 13.3333px">nine axes you proposed, all=
 of it normative in -02:</span></div><div><span style=3D"font-size: 13.3333=
px"><br></span></div><div><span style=3D"font-size: 13.3333px">- action can=
onicalization/hash: JCS (RFC 8785) =E2=86=92 SHA-256;</span></div><div><spa=
n style=3D"font-size: 13.3333px">&nbsp; non-canonical input rejected.</span=
></div><div><span style=3D"font-size: 13.3333px">- approver/subject binding=
: a dedicated hardware-attested device key;</span></div><div><span style=3D=
"font-size: 13.3333px">&nbsp; the profile requires hardware-resident key ma=
terial with enforced</span></div><div><span style=3D"font-size: 13.3333px">=
&nbsp; user verification, evidenced by a platform attestation chain. It is<=
/span></div><div><span style=3D"font-size: 13.3333px">&nbsp; deliberately d=
evice- and vendor-agnostic =E2=80=94 any platform that can</span></div><div=
><span style=3D"font-size: 13.3333px">&nbsp; produce that evidence can conf=
orm.</span></div><div><span style=3D"font-size: 13.3333px">- operation/audi=
ence binding: psea_tier, psea_op, aud, iss byte-exact</span></div><div><spa=
n style=3D"font-size: 13.3333px">&nbsp; in the signed claim set; optional s=
igned caller-identity binding.</span></div><div><span style=3D"font-size: 1=
3.3333px">- replay key: jti plus a per-scope strictly-increasing counter.</=
span></div><div><span style=3D"font-size: 13.3333px">- one-time state: coun=
ter compare-advance and jti finalization in one</span></div><div><span styl=
e=3D"font-size: 13.3333px">&nbsp; atomic transaction; replay terminally ref=
used. Same property as</span></div><div><span style=3D"font-size: 13.3333px=
">&nbsp; EP's nonce-consumption, enforced differently.</span></div><div><sp=
an style=3D"font-size: 13.3333px">- trust root: the platform key-attestatio=
n chain =E2=80=94 never the operator.</span></div><div><span style=3D"font-=
size: 13.3333px">- relying-party result: signed proof token; the highest en=
forcement</span></div><div><span style=3D"font-size: 13.3333px">&nbsp; tier=
 additionally requires a server ACK before execution,</span></div><div><spa=
n style=3D"font-size: 13.3333px">&nbsp; fail-closed.</span></div><div><span=
 style=3D"font-size: 13.3333px">- enforcement class: four tiers (P/S/E/A), =
from passive evidence to</span></div><div><span style=3D"font-size: 13.3333=
px">&nbsp; per-action online fail-closed authorization.</span></div><div><s=
pan style=3D"font-size: 13.3333px">- residual risk: WYSIWYS / display integ=
rity and natural-person</span></div><div><span style=3D"font-size: 13.3333p=
x">&nbsp; identity =E2=80=94 both explicitly out of scope, stated in the dr=
aft.</span></div><div><span style=3D"font-size: 13.3333px"><br></span></div=
><div><span style=3D"font-size: 13.3333px">Implementation status, in the sa=
me terms as the other efforts: a</span></div><div><span style=3D"font-size:=
 13.3333px">complete reference implementation across two major mobile platf=
orms</span></div><div><span style=3D"font-size: 13.3333px">plus a deployed =
backend verifier, with cross-platform golden vectors</span></div><div><span=
 style=3D"font-size: 13.3333px">locking the canonicalization byte-for-byte.=
 Canonical vectors are in</span></div><div><span style=3D"font-size: 13.333=
3px">Appendix A of -02; a negative-case set in your failure grouping</span>=
</div><div><span style=3D"font-size: 13.3333px">exists on this side as well=
 =E2=80=94 happy to point you at it for the</span></div><div><span style=3D=
"font-size: 13.3333px">vector pass.</span></div><div><span style=3D"font-si=
ze: 13.3333px"><br></span></div><div><span style=3D"font-size: 13.3333px">M=
ohamad Khalil-Yossif</span></div><div><br></div><div class=3D"mb_sig"></div>
                                        
                                        <blockquote class=3D"history_contai=
ner" type=3D"cite" style=3D"border-left-style: solid;border-width: 1px;marg=
in-top: 20px;margin-left: 0px;padding-left: 10px;min-width: 500px">
                        <p style=3D"color: #AAAAAA; margin-top: 10px;">On 1=
1/06/2026 11:07:31, Iman Schrock &lt;[email protected]&gt; wrote:</p><=
div style=3D"font-family:Arial,Helvetica,sans-serif"><div dir=3D"ltr"><div =
style=3D"font-size: 12pt;text-decoration-style: solid;direction: ltr;margin=
: 0px;font-family: Aptos,Arial,Helvetica,sans-serif;color: rgb(0,0,0)">Song=
bo =E2=80=94</div><div style=3D"font-size: 12pt;text-decoration-style: soli=
d;margin: 0px;font-family: Aptos,Arial,Helvetica,sans-serif;color: rgb(0,0,=
0)">Thank you =E2=80=94 running the vectors yourself is the validation that=
 matters; reproduction beats assertion, and I'm glad Node and Web agreed on=
 your machine too.</div><div style=3D"font-size: 12pt;text-decoration-style=
: solid;margin: 0px;font-family: Aptos,Arial,Helvetica,sans-serif;color: rg=
b(0,0,0)">Agreed completely: the offline / server-state split is a conforma=
nce boundary, not an implementation detail, so it gets a first-class row in=
 the matrix rather than a footnote. Your phrasing of the invariant =E2=80=
=94<span class=3D"gmail-Apple-converted-space">&nbsp;</span><i>reject befor=
e any approval-bearing state mutation</i>&nbsp;=E2=80=94 is the right one t=
o state once in the core section and inherit per profile. And it maps to PS=
EA exactly as you put it: the signed proof can carry or bind the jti / coun=
ter / freshness material, but the high-water-mark decision is verifier stat=
e on both sides.</div><div style=3D"font-size: 12pt;text-decoration-style: =
solid;margin: 0px;font-family: Aptos,Arial,Helvetica,sans-serif;color: rgb(=
0,0,0)">That convergence =E2=80=94 one invariant, two attestation tiers, en=
forced in the same place =E2=80=94 is what makes the dispatch question conc=
rete rather than asserted. Send the off-list nits whenever; I'll fold them =
in with the skeleton.</div><div style=3D"font-size: 12pt;text-decoration-st=
yle: solid;margin: 0px;font-family: Aptos,Arial,Helvetica,sans-serif;color:=
 rgb(0,0,0)">Iman,</div></div><br><div class=3D"gmail_quote gmail_quote_con=
tainer"><div dir=3D"ltr" class=3D"gmail_attr">On Thu, Jun 11, 2026 at 12:46=
=E2=80=AFAM Songbo Bu &lt;<a href=3D"mailto:[email protected]">king34760=
[email protected]</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0px 0px 0px 0.8ex;border-left: 1px solid rgb(204,204,204);paddi=
ng-left: 1ex;min-width: 500px">Hi Iman,<br>
<br>
Thanks, this split is useful.<br>
<br>
I took a quick look at the new signoff vectors and ran the signoff<br>
conformance runner. The current shape matches the verifier boundary<br>
you describe: 9 vectors, 8 reject cases, all at the offline assertion<br>
layer, with the Node and Web Crypto verifiers agreeing.<br>
<br>
One thing I would make explicit in the survey matrix is that the<br>
offline/server-state split is not just an implementation detail; it is<br>
a conformance boundary:<br>
<br>
- verifier-state boundary: an offline assertion verifier can reject<br>
structural, cryptographic, action-binding, audience, and UV failures;<br>
replay / one-time consumption, enrollment-active, and revocation<br>
freshness require server-state or ledger-side evaluation.<br>
<br>
That maps cleanly to PSEA too. The signed proof can carry or bind the<br>
jti/counter/freshness material, but the high-water mark decision is<br>
still verifier state. So I would treat "reject before approval-bearing<br>
state mutation" as the common invariant across both profiles.<br>
<br>
I'll take a closer pass over the actual vectors and send concrete nits<br>
off-list once the survey skeleton lands.<br>
<br>
Best,<br>
Songbo Bu<br>
<br>
On Thu, 11 Jun 2026 00:38:02 -0700, Iman Schrock &lt;<a href=3D"mailto:team=
@emiliaprotocol.ai" target=3D"_blank">[email protected]</a>&gt; wrote:=
<br>
&gt; Songbo =E2=80=94<br>
&gt;<br>
&gt; The processing-model + negative-test-table framing is the<br>
&gt; right call, and the decision-matrix axes you list are exactly the comp=
arison<br>
&gt; I'd want too =E2=80=94 formats will differ, the verifier decision shou=
ldn't.<br>
&gt;<br>
&gt; Two concrete things from my side:<br>
&gt;<br>
&gt; - I just<br>
&gt; published EP's Class-A signoff negative vectors as a tagged battery,<b=
r>
&gt; grouped on your failure classes =E2=80=94 structural, cryptographic,<b=
r>
&gt; action-binding, operation/audience, lifecycle/UV =E2=80=94 and run thr=
ough two<br>
&gt; independent verifiers. It's a starting table for the pass you offered;=
<br>
&gt; please shred it. One honest scope line I drew, which I think matters f=
or<br>
&gt; the survey: I split OFFLINE assertion checks (crypto, action- binding,=
<br>
&gt; audience, UV) from SERVER-STATE checks (replay / one-time consumption =
=E2=80=94<br>
&gt; the nonce is our global consumption key =E2=80=94 and enrollment-activ=
e). A<br>
&gt; relying party verifying an EP receipt offline gets the former; the lat=
ter<br>
&gt; live at the consume/ledger step. PSEA's counter/jti high-water-mark<br>
&gt; invariant is the same idea on your side.<br>
&gt;<br>
&gt; - Here's<br>
&gt; EP filled into your matrix, as a strawman for the joint note:<br>
&gt;<br>
&gt; - action<br>
&gt; canonicalization/hash: JCS (RFC 8785) of the action object =E2=86=92 S=
HA-256<br>
&gt; context hash; non-canonical input MUST be rejected.<br>
&gt;<br>
&gt; - approver/subject<br>
&gt; binding: device-bound approver key (Class A, WebAuthn P-256); approver=
_id<br>
&gt; resolved via a signed Approver Directory.<br>
&gt;<br>
&gt; - operation/audience<br>
&gt; binding: action_hash + policy ref + initiator in the signed context;<b=
r>
&gt; WebAuthn rp_id for the relying party.<br>
&gt;<br>
&gt; - replay<br>
&gt; key: 128-bit CSPRNG nonce, globally unique =E2=80=94 it IS the consump=
tion key.<br>
&gt;<br>
&gt; - one-time<br>
&gt; state: consumed at most once, globally; replay across<br>
&gt; sessions/operators/time terminally refused.<br>
&gt;<br>
&gt; - trust<br>
&gt; root: the signed Approver Directory; MUST NOT default to the EP operat=
or.<br>
&gt;<br>
&gt; - relying-party<br>
&gt; result: the offline-verifiable Trust Receipt (signed authorization +<b=
r>
&gt; consumption record + Merkle anchor).<br>
&gt;<br>
&gt; - enforcement<br>
&gt; class: Class A device-bound (recommended) vs Class C operator-custodie=
d<br>
&gt; (legacy, weaker); execution-side enforcement is the strongest deployme=
nt<br>
&gt; class.<br>
&gt;<br>
&gt; - residual<br>
&gt; risk: presentation attack / WYSIWYS, and key-revocation timing =E2=80=
=94 both<br>
&gt; stated, neither claimed solved.<br>
&gt;<br>
&gt; The two profiles land on different rows only at assurance<br>
&gt; tier (your dedicated-hardware attestation vs. our commodity authentica=
tor) and<br>
&gt; scope (we add enrollment + separation of duties). Same decision matrix=
.<br>
&gt;<br>
&gt; I'll fold this into the survey skeleton I'm roughing out and<br>
&gt; send the whole thing off-list for you and Mohamad to edit.<br>
&gt;<br>
&gt; On Thu, Jun 11, 2026 at 12:24=E2=80=AFAM Songbo Bu &lt;<a href=3D"mail=
to:[email protected]" target=3D"_blank">[email protected]</a>&gt; wro=
te:<br>
&gt;<br>
&gt; Hi Mohamad, Iman, all,<br>
&gt;<br>
&gt; Thanks, Mohamad. And Iman, that is a useful data point.<br>
&gt;<br>
&gt; For PSEA, my first pass would be to make the verifier-side text more<b=
r>
&gt;<br>
&gt; like a processing model, plus a small set of negative verifier cases.<=
br>
&gt;<br>
&gt; That seems more useful to implementers than adding another long<br>
&gt;<br>
&gt; requirements list.<br>
&gt;<br>
&gt; For the processing model, something along these lines:<br>
&gt;<br>
&gt; &gt; On receipt of a proof submission, the Verifier treats the signed =
proof, the submitted action payload, enrollment state, and replay state as =
one atomic authorization decision. The Verifier first validates the signed =
token and then uses only claims from the verified payload, together with se=
rver-side enrollment and replay state, to evaluate the proof. Before any co=
unter advance, ledger write, acknowledgement signing, or success-bearing At=
testation Result, the Verifier canonicalizes the submitted actionPayload, r=
ecomputes the payload hash, and compares it byte-for-byte with the signed p=
sea_payload_hash. Any mismatch, missing required signed claim, stale freshn=
ess value, replayed jti/counter, inactive enrollment state, or failed cross=
-replay binding is a non-approval outcome.<br>
&gt;<br>
&gt; I would then group failures into a small negative-test table rather<br>
&gt;<br>
&gt; than leave them spread across the document:<br>
&gt;<br>
&gt; - structural / cryptographic: wrong profile, unsupported alg, bad<br>
&gt;<br>
&gt; signature, unrecognized critical header;<br>
&gt;<br>
&gt; - action-binding: missing actionPayload, payload-hash mismatch,<br>
&gt;<br>
&gt; non-canonical payload, or psea_payload_hash encoding mismatch;<br>
&gt;<br>
&gt; - cross-replay: psea_tier, psea_op, aud, iss, or psea_caller_package<b=
r>
&gt;<br>
&gt; not matching the expected operation context;<br>
&gt;<br>
&gt; - freshness / replay: expired proof, implausible iat, wrong eat_nonce,=
<br>
&gt;<br>
&gt; reused jti, or non-increasing counter;<br>
&gt;<br>
&gt; - lifecycle / trust gate: enrollment not active, revoked/suspended<br>
&gt;<br>
&gt; key, or user-verification evidence insufficient for the required<br>
&gt;<br>
&gt; assurance level;<br>
&gt;<br>
&gt; - optional chain layer: psea_chain_prev mismatch when that layer is en=
abled.<br>
&gt;<br>
&gt; The key point I would make testable is that all of those failures have=
<br>
&gt;<br>
&gt; the same security effect: the verifier rejects before any state<br>
&gt;<br>
&gt; mutation that could make the proof look consumed or approved. In<br>
&gt;<br>
&gt; test-vector terms, a rejected proof should leave the counter<br>
&gt;<br>
&gt; high-water mark, finalized-jti set, chain entry, approval ledger, and<=
br>
&gt;<br>
&gt; approval-bearing Attestation Result unchanged or absent.<br>
&gt;<br>
&gt; For Iman's draft, I think the useful comparison is not whether the<br>
&gt;<br>
&gt; token formats are identical, but whether the verifier decision<br>
&gt;<br>
&gt; matrices line up: action canonicalization/hash, approver or subject<br>
&gt;<br>
&gt; binding, operation/audience binding, replay key, one-time state, trust=
<br>
&gt;<br>
&gt; root, relying-party result, enforcement class, and residual risk. I<br>
&gt;<br>
&gt; can take a pass over that next, especially around Class A signoff<br>
&gt;<br>
&gt; negative vectors and deployment-class claims.<br>
&gt;<br>
&gt; Best,<br>
&gt;<br>
&gt; Songbo Bu<br>
&gt;<br>
&gt; --<br>
&gt;<br>
&gt; Iman Schrock<br>
&gt; Founder &amp; CEO<br>
&gt;<br>
&gt; EMILIA Protocol | Trust Before High-Risk Action<br>
&gt; Eye warns. EP verifies. Signoff owns.<br>
&gt;<br>
&gt; [<a href=3D"http://emiliaprotocol.ai" rel=3D"noreferrer" target=3D"_bl=
ank">emiliaprotocol.ai</a>](<a href=3D"http://emiliaprotocol.ai" rel=3D"nor=
eferrer" target=3D"_blank">http://emiliaprotocol.ai</a>) | GitHub<br>
&gt; <a href=3D"mailto:[email protected]" target=3D"_blank">team@emili=
aprotocol.ai</a><br>
</blockquote></div><div><br clear=3D"all"></div><div><br></div><span class=
=3D"gmail_signature_prefix">-- </span><br><div dir=3D"ltr" class=3D"gmail_s=
ignature"><div dir=3D"ltr">Iman Schrock<br>Founder &amp; CEO<br><br>EMILIA =
Protocol | Trust Before High-Risk Action<br>Eye warns. EP verifies. Signoff=
 owns.<br><br><a href=3D"http://emiliaprotocol.ai" target=3D"_blank">emilia=
protocol.ai</a> | GitHub<br><a href=3D"mailto:[email protected]" targe=
t=3D"_blank">[email protected]</a></div></div>
</div></blockquote></div>
------=_NextPart_14786603.206481159137--


--===============1596498497974503637==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline

X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KU2VjZGlzcGF0
Y2ggbWFpbGluZyBsaXN0IC0tIHNlY2Rpc3BhdGNoQGlldGYub3JnClRvIHVuc3Vic2NyaWJlIHNl
bmQgYW4gZW1haWwgdG8gc2VjZGlzcGF0Y2gtbGVhdmVAaWV0Zi5vcmcK

--===============1596498497974503637==--