| Internet-Draft | OASNT-CAID | August 2026 |
| Thallapelly | Expires 6 February 2027 | [Page] |
This document profiles OASNT tokens for consumption by executor-side processing models. It fixes one normative derivation of a Canonical Action Identifier (CAID) from the OASNT action digest, so that every executor checks the same derivation rather than each integration defining its own, and it specifies the semantics of the token's named-human binding, including a subject-to-enrollment check whose absence this profile makes a refusal.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 6 February 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
[I-D.thallapelly-oasnt] (hereafter "the core document") defines the OASNT token: a compact JWS in which a hardware-bound device key attests that a specific human authorized one specific action, with the disclosure the human was shown bound into the signature. The core document deliberately stops at the token. It does not define how an executor, having decided to admit evidence of several kinds, identifies the action that evidence authorizes.¶
Executor-side processing models such as [I-D.schrock-action-evidence-boundary] work in terms of a Canonical Action Identifier: a value the executor derives for the effect it is about to perform and matches against the identifiers derived from admissible evidence. Left unspecified, that derivation would be reinvented by every executor-to-OASNT integration, and two integrations that disagreed on any detail would disagree silently.¶
This document fixes the derivation once. It also specifies the named-human binding of the token: what a validated token asserts about the human it names, the subject-to-enrollment check a verifier is required to make, and what the binding deliberately does not assert.¶
This profile is written from a running implementation. The subject verification requirement in Section 5 exists because implementing this profile exposed its absence; see Section 6.3.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
"The core document" refers to [I-D.thallapelly-oasnt]. "Action",
"canonical action", "disclosure", and the claim names adg, dsp, rqf,
sub, and cnf have the meanings the core document gives them.¶
"Effect" refers to the concrete operation an executor is about to perform, in the executor's own representation.¶
caid = "oasnt:caid:" version ":" digest version = 1*DIGIT digest = 43base64url-char base64url-char = ALPHA / DIGIT / "-" / "_"¶
A CAID is an opaque octet string. It is not a URI under [RFC3986], it MUST NOT be dereferenced, and no registration of the leading literal is requested or implied. A CAID identifies an action within OASNT; Section 6.4 states the consequence for executors that also hold evidence under other profiles.¶
This document defines version 1.¶
For an action with type T and parameters P, the version 1 CAID is:¶
CAID(T, P) = "oasnt:caid:1:" || BASE64URL(SHA-256(canonical-action(T, P)))¶
where canonical-action is the canonical action encoding of the core
document, under its escaping rules and its UTF-8-octet key ordering;
SHA-256 is [RFC6234]; and BASE64URL is the URL-safe alphabet of
[RFC4648] without padding, yielding exactly 43 characters.¶
The digest octets are, by construction, identical to the value of the
adg claim of an OASNT token minted for the same action. A conforming
derivation therefore has two equivalent forms:¶
Recomputed. Derive from a representation of the action the deriving
party itself holds, by computing the canonical action encoding and its
digest. This is the form an executor uses for its effect, and the form a
verifier that recomputed adg during token validation uses for the
evidence.¶
Carried. Prefix the adg value of a validated token. This form is
only meaningful after the token's signature has verified under an
enrolled key, and it carries only the strength of that signature: it
proves what the device signed, not what the executor is about to do. A
carried value that is not exactly 43 characters of the base64url
alphabet MUST be refused rather than prefixed.¶
Every CAID comparison in Section 4 is an octet-string equality. Nothing is ever parsed out of a CAID.¶
Version 1 pins the canonicalization rules of the core document as of this writing: the escaping of structural delimiters and the UTF-8-octet key ordering. Any change to those rules is a new version, never a silent change under the same one.¶
Because the version participates in the octet-string comparison, identifiers derived under different versions never compare equal. A version mismatch therefore manifests as an ordinary CAID mismatch and fails closed. No version negotiation exists or is needed.¶
An executor admitting an OASNT token as evidence for an effect MUST proceed as follows.¶
Validate the token as the core document's verification procedure
requires, with the single-use boundary of Section 4.1
observed: the executor MUST establish that the core document's replay
condition is satisfiable, that jti is present and has not been seen,
without yet recording it as seen. A token that fails validation yields
no CAID and no further processing.¶
Derive CAID-effect from the executor's own representation of the
effect it is about to perform, using the recomputed form of
Section 3.2. The executor MUST NOT construct CAID-effect from any
value carried in the token or supplied by the party presenting it.¶
Derive CAID-evidence from the validated token: the recomputed form
where the validator recomputed adg against an expected action, the
carried form otherwise.¶
The evidence identifies the effect only if CAID-effect and
CAID-evidence are equal as octet strings. Any other outcome, including
a refused carried derivation in step 3, MUST be treated as a refusal
(caid-mismatch) and MUST NOT be downgraded to a warning.¶
Note that step 2 makes the comparison self-strengthening: equality between
a self-derived CAID-effect and a carried-basis CAID-evidence is itself
a recomputation of the token's adg against the executor's view of the
effect. The carried basis is weak only where matching does not happen, for
example when a CAID is stored or forwarded for audit without being
compared; such a value retains only signature strength and MUST be marked
as carried wherever that distinction is visible.¶
The core document requires that jti be present and not have been seen
before. That condition is checked during step 1, but the token's single use
MUST NOT be recorded as spent until the comparison of step 4 has succeeded
and the executor is committed to performing the effect.¶
Consuming earlier is a defect with a specific shape. An executor that spends
jti while validating, and then refuses caid-mismatch at step 4, has
destroyed a valid authorization for an effect that never occurred. The
approver's evidence is gone, the effect did not happen, and the only
remedy is a fresh human approval. A party able to induce a mismatch, by
presenting the token against a near-miss effect, can therefore burn
authorizations at will, converting an integrity refusal into a denial of
service against the human in the loop.¶
Executors MUST therefore evaluate validity and policy sufficiency
separately from consumption, and MUST release any provisional reservation
when a refusal is returned for any reason, including caid-mismatch. The
practical shape is a reservation taken atomically before verification and
either committed on full acceptance or released on refusal; this profile
does not require that mechanism, only the property. A refusal MUST NOT
consume.¶
This applies to every refusal reachable after step 1, not only
caid-mismatch, and it composes with the group semantics of the
enforcement profile: a refused token likewise leaves its group unconsumed.¶
The core document records, at enrollment, a subject identifier bound to
the enrolled key, and requires the sub claim in every token. This
profile makes the linkage load-bearing. A token validated under this
profile asserts:¶
the subject recorded at enrollment and named by sub, in control of the
enrolled hardware-bound key identified by cnf.jkt, approved the specific
action identified by the CAID, having been shown the disclosure whose
digest dsp carries, on a device whose runtime integrity was assessed as
the int claim reports.¶
A verifier operating under this profile MUST refuse a token
(sub-mismatch) when sub is absent, is not a string, or is not equal to
the subject identifier recorded at enrollment for the key that verified
the signature.¶
This check is REQUIRED. Without it, a token signed by one enrolled key may assert any subject whatsoever: every cryptographic check passes, the key is authorized, and the named human is fiction. Section 6.3 records the implementation experience behind this requirement.¶
The binding deliberately asserts nothing beyond the statement above. In particular:¶
It is not a per-signature user-verification ceremony. The approval step precedes the signature; no claim attests a biometric or knowledge-factor ceremony for each individual signature. A relying party that requires per-signature user verification composes it alongside this profile; this profile will not fold it into the core semantics.¶
It does not assert comprehension or legal consent. A valid dsp proves
which octets were displayed and signed, not that they were understood.
This limit is inherited from the core document unchanged.¶
It does not strengthen the int claim. A device-asserted integrity
verdict retains exactly the limits the core document states.¶
The interoperability property this profile buys is deliberately fragile in
one direction: two implementations that disagree on any canonicalization
detail, escaping, ordering, or version, produce disjoint CAID spaces and
refuse each other's identifiers. The failure mode of divergence is
caid-mismatch, which denies. Nothing about the construction can turn a
divergence into an acceptance.¶
The carried form of Section 3.2 is a convenience for parties that cannot recompute, and it is exactly as strong as the signature over the token that carried it. The matching procedure of Section 4 restores recomputation strength wherever it is actually applied. Deployments SHOULD treat an unmatched carried CAID, for example in logs or forwarded evidence, as a claim by the device rather than a fact about any effect.¶
The reference implementation, prior to this profile, validated enrollment,
signature, thumbprint, freshness, replay, all three bindings, and the
integrity claim, and did not compare sub against the enrollment record.
A token signed by an enrolled key claiming a different subject passed
every check. The defect was found while implementing this profile's
named-human semantics, was fixed by the refusal Section 5.2
requires, and is now exercised by a published refusal vector (the
named-human substitution case in the implementation's adversarial corpus,
and Appendix A).¶
The lesson generalizes: the named-human binding is precisely as strong as
the weakest link between sub, the enrollment record, and the key. A
deployment that enrolls keys without recording a verified subject
identifier has nothing for this check to bind, and the assertion of
Section 5 silently degrades to "some enrolled key approved this".
Enrollment procedures SHOULD therefore verify the subject identifier they
record.¶
The fixed leading literal exists so that an OASNT-derived identifier can never be confused with an identifier derived by another evidence profile that also feeds an executor. Executors handling multiple evidence profiles SHOULD treat the full octet string, prefix included, as the identifier and compare nothing shorter.¶
The consequence is worth stating plainly: a CAID under this profile identifies an action within OASNT, and it is not a join key across evidence profiles. Another profile that derives its identifier over a different preimage of the same logical action produces a different digest under a different prefix, and no octet-string comparison between the two ever succeeds, by design and fail-closed. An executor holding an OASNT token and a non-OASNT authorization record for the same action therefore cannot join them by comparing identifiers. It derives an identifier under each profile separately, from its own representation of the effect, and joins on that representation.¶
This document defines an OASNT-specific derivation and namespace. The term Canonical Action Identifier originates in executor-side processing models ([I-D.schrock-action-evidence-boundary]), and a general CAID framework with its own action object, canonicalization, and identifier syntax is defined in [I-D.schrock-canonical-action-identifier]. Identifiers derived under this document are not wire-compatible with identifiers derived under that framework and never compare equal to them; the two coexist by the same rule this section states for evidence profiles generally.¶
This document has no IANA actions. The literal oasnt:caid: is a fixed
string defined by this document; it is not a URI scheme, not a URN
namespace, and no registration is requested.¶
The derivation vectors below are byte-reproducible: they are generated
from the shipped canonicalization by docs/ietf/caid/gen-vectors-caid.mjs
in the implementation repository, and unlike the signature vectors of the
core document they involve no randomness. The named-human refusal vector
involves an ECDSA signature and is verified rather than compared.¶
Action type payment.transfer, parameters amount=100.00, payee=acct_9.¶
canonical action payment.transfer|amount=100.00&payee=acct_9 adg YlHp3M4JIWFPPZIVAwAmYOBOMfUyb2bjE6ve3AD2iaQ CAID oasnt:caid:1:YlHp3M4JIWFPPZIVAwAmYOBOMfUyb2bjE6ve3AD2iaQ¶
This vector is deterministic: any conforming implementation reproduces these exact octets.¶
The evidence above is presented for a different effect: amount=9000.00,
payee=acct_EVIL.¶
executing canonical action payment.transfer|amount=9000.00&payee=acct_EVIL CAID-effect oasnt:caid:1:EWy_PVFw3FxdZIk6AEpEJ5HxhAsCJQnSq7P1jPHg6gc CAID-evidence oasnt:caid:1:YlHp3M4JIWFPPZIVAwAmYOBOMfUyb2bjE6ve3AD2iaQ¶
The octet strings differ; the outcome is a refusal (caid-mismatch).¶
The single parameter (a, b&c=d) and the parameter set (a, b),
(c, d) canonicalize identically if the escaping rules of the core
document are ignored, and must not under them.¶
canonical, single parameter payment.transfer|a=b\&c\=d CAID oasnt:caid:1:4u_wRl1BAfeJRhqTs268VI1_kCw03xEah5PmylQOd1M canonical, two parameters payment.transfer|a=b&c=d CAID oasnt:caid:1:YE3P-GAUpmAvZdKvqezf1RBMlLCdpt0e0deVj5vBrps¶
The octet strings differ, and differ only because the escaping is
applied. Presenting evidence for either action against the other as the
effect refuses (caid-mismatch) at the CAID layer, rather than
surfacing an adg error.¶
Each of the following values MUST be refused by the carried form of the derivation rather than prefixed:¶
"" (empty) "short" (wrong length) 42 or 44 characters of the base64url alphabet (wrong length) 43 characters ending in "=" (padding) any character outside ALPHA / DIGIT / "-" / "_"¶
A token signed by the core document's published test key, with every claim
valid except sub, which names mallory while enrollment records
agent-1 for the key. Verification refuses with sub-mismatch and no
other reason. The signature is not byte-reproducible; regenerate and
verify with the tool named above.¶
RFC Editor: please remove this section before publication.¶
Since -00:¶
Section 6.4 now states that a CAID identifies an action within OASNT and is not a join key across evidence profiles, with the consequence for executors holding evidence under several profiles. Raised in executor-implementer review.¶
New derivation vector P2b: a CAID mismatch between two parameter sets
that canonicalize identically unless the escaping rules are applied,
refusing at the CAID layer rather than as an adg error.¶
Section 6.4 cites [I-D.schrock-canonical-action-identifier] as the general CAID framework and states that identifiers under this document are an OASNT-specific derivation and namespace, not wire-compatible with identifiers derived under that framework.¶
Section 4 step 1 and the new Section 4.1 state that the
replay condition is checked but the token's single use MUST NOT be
recorded as spent until the step-4 comparison succeeds. As published,
-00 permitted an executor to consume jti during validation and then
refuse caid-mismatch, destroying a valid authorization for an effect
that never occurred and allowing an induced mismatch to burn approvals.
A refusal MUST NOT consume. Raised in executor-implementer review.¶
The composition questions raised by Iman Schrock on the WIMSE mailing
list, in particular whether the adg-to-CAID derivation should be fixed
normatively or left to each executor adapter, prompted this profile. His
executor-implementer review of the -00 text contributed the
cross-profile observation now stated in Section 6.4, the shape
of the escaping vector in Appendix A, and the single-use ordering defect
corrected in Section 4.1, a case where the published text
permitted an executor to consume an authorization while refusing the
effect it authorized.¶