| Internet-Draft | OASNT-CAID | July 2026 |
| Thallapelly | Expires 25 January 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 25 January 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.¶
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. 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 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.¶
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).¶
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.¶
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.¶