Files
ietf-wimse-ect-cbor/cbor-variant/draft-nennemann-wimse-execution-context-cbor-00.md
Christian Nennemann ea188f1c22 Add CBOR/COSE/CWT serialization of WIMSE Execution Context Tokens
Companion I-D to draft-nennemann-wimse-execution-context defining
ECT semantics mapped to CBOR encoding, COSE_Sign1 signing, and CWT
claims for constrained devices and non-HTTP transports (CoAP, MQTT,
raw binary). Aligned with JWT draft changes: jti/cti as unified
token+task ID (no separate tid), pol/pol_decision optional but paired.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 22:51:22 +01:00

1340 lines
45 KiB
Markdown

---
title: "CBOR Serialization of Execution Context Tokens for Distributed Agentic Workflows"
abbrev: "WIMSE ECT-CBOR"
category: std
docname: draft-nennemann-wimse-execution-context-cbor-00
submissiontype: IETF
number:
date:
v: 3
area: "Security"
workgroup: "WIMSE"
keyword:
- execution context
- workload identity
- agentic workflows
- CBOR
- COSE
- CWT
- constrained environments
- audit trail
- compliance
author:
-
fullname: Christian Nennemann
organization: Independent Researcher
email: ietf@nennemann.de
normative:
RFC8392:
RFC8610:
RFC8949:
RFC9052:
RFC9053:
RFC9338:
RFC9562:
RFC9596:
I-D.ietf-wimse-arch:
I-D.ietf-wimse-s2s-protocol:
I-D.nennemann-wimse-execution-context:
title: "Execution Context Tokens for Distributed Agentic Workflows"
target: https://datatracker.ietf.org/doc/draft-nennemann-wimse-execution-context/
date: 2026-02
author:
- name: Christian Nennemann
org: Independent Researcher
informative:
RFC3552:
RFC7252:
RFC8126:
RFC8613:
RFC9110:
RFC9147:
RFC9421:
RFC9528:
I-D.ni-wimse-ai-agent-identity:
I-D.ietf-scitt-architecture:
I-D.ietf-suit-manifest:
SPIFFE:
title: "Secure Production Identity Framework for Everyone (SPIFFE)"
target: https://spiffe.io/docs/latest/spiffe-about/overview/
date: false
EU-AI-ACT:
title: "Regulation (EU) 2024/1689 of the European Parliament and of the Council laying down harmonised rules on artificial intelligence (Artificial Intelligence Act)"
target: https://eur-lex.europa.eu/eli/reg/2024/1689
date: 2024-06-13
author:
- org: European Parliament and Council of the European Union
FDA-21CFR11:
title: "Title 21, Code of Federal Regulations, Part 11: Electronic Records; Electronic Signatures"
target: https://www.ecfr.gov/current/title-21/chapter-I/subchapter-A/part-11
date: false
author:
- org: U.S. Food and Drug Administration
DORA:
title: "Regulation (EU) 2022/2554 on digital operational resilience for the financial sector (DORA)"
target: https://eur-lex.europa.eu/eli/reg/2022/2554
date: 2022-12-14
author:
- org: European Parliament and Council of the European Union
EU-MDR:
title: "Regulation (EU) 2017/745 on medical devices (MDR)"
target: https://eur-lex.europa.eu/eli/reg/2017/745
date: 2017-04-05
author:
- org: European Parliament and Council of the European Union
MQTT:
title: "MQTT Version 5.0"
target: https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
date: 2019-03-07
author:
- org: OASIS
EAT:
title: "The Entity Attestation Token (EAT)"
target: https://datatracker.ietf.org/doc/draft-ietf-rats-eat/
date: false
author:
- name: Laurence Lundblade
- name: Giridhar Mandyam
- name: Jeremy O'Donoghue
- name: Carl Wallace
--- abstract
This document defines a CBOR/COSE/CWT serialization of Execution
Context Tokens (ECTs) for distributed agentic workflows in regulated
environments. The companion document,
draft-nennemann-wimse-execution-context, defines the full ECT
semantics using JSON/JOSE/JWT serialization. This specification
maps those semantics to CBOR (RFC 8949) encoding, COSE
(RFC 9052) signing structures, and CWT (RFC 8392) claims,
targeting constrained devices, non-HTTP transports (CoAP, MQTT,
Layer 2 protocols), and bandwidth-sensitive deployments. The CBOR
serialization preserves all ECT semantics including DAG-structured
task dependency ordering, policy evaluation recording, and
compliance state tracking while using COSE_Sign1 signatures and
integer-keyed CWT claims for compact representation.
--- middle
# Introduction
## Motivation
The companion specification
{{I-D.nennemann-wimse-execution-context}} defines Execution Context
Tokens (ECTs) as an extension to the WIMSE architecture
{{I-D.ietf-wimse-arch}} for recording task execution, DAG-structured
dependency ordering, and policy evaluation outcomes in regulated
agentic workflows. That specification uses JSON Web Tokens (JWT)
with JSON Object Signing and Encryption (JOSE) serialization, which
is well suited for HTTP-based deployments.
However, many deployment scenarios require a more compact
serialization:
- **Constrained IoT agents**: Medical devices, industrial
controllers, and edge computing nodes operating under tight memory
and bandwidth budgets benefit from binary encoding.
- **Non-HTTP transports**: Agent-to-agent communication over CoAP
{{RFC7252}}, MQTT {{MQTT}}, or Layer 2 protocols cannot efficiently
carry JSON-encoded tokens.
- **Bandwidth-sensitive environments**: Satellite links, low-power
wide-area networks, and cellular IoT backhaul incur significant
cost per byte.
CBOR {{RFC8949}} provides a binary encoding that is substantially
more compact than JSON for the same semantic content. COSE
{{RFC9052}} provides equivalent signing and encryption operations to
JOSE. CWT {{RFC8392}} provides a CBOR-based claim structure
equivalent to JWT. Together, these standards enable a CBOR-native
ECT serialization that achieves approximately 3x size reduction
compared to the JWT variant while preserving identical semantics.
## Scope
This document defines **only** the CBOR/COSE/CWT serialization
mapping for ECTs. The following are defined in the companion JWT
specification {{I-D.nennemann-wimse-execution-context}} and apply
identically to CBOR-serialized ECTs:
- ECT claim semantics and processing rules
- DAG validation algorithm (parent existence, temporal ordering,
cycle detection, policy decision propagation, trust domain
consistency)
- Verification procedure (all 15 steps, adapted for COSE in
{{verification}})
- Operational modes (point-to-point, deferred ledger, full ledger)
- Audit ledger interface requirements
- Security model and threat analysis
- Privacy considerations
Implementers MUST read the companion JWT specification for the
complete semantic definition. This document covers:
- COSE header parameter mapping ({{cose-header}})
- CWT claim key assignments ({{claim-mapping}})
- CDDL schema for ECT-CBOR payloads ({{cddl-schema}})
- COSE_Sign1 structure ({{cose-structure}})
- Transport mechanisms for CoAP, MQTT, HTTP, and raw binary
({{transport}})
- COSE-specific verification steps ({{verification}})
- Size comparison with the JWT variant ({{size-comparison}})
## Terminology
This document reuses all terminology defined in
{{I-D.nennemann-wimse-execution-context}} Section 2. Additionally:
CWT:
: CBOR Web Token {{RFC8392}}, the CBOR equivalent of JWT.
COSE:
: CBOR Object Signing and Encryption {{RFC9052}}, the CBOR
equivalent of JOSE.
COSE_Sign1:
: A COSE structure for a message with a single signer
{{RFC9052}} Section 4.2.
CDDL:
: Concise Data Definition Language {{RFC8610}}, used to define
CBOR data structures.
# Conventions and Definitions
{::boilerplate bcp14-tagged}
# COSE Header Parameters {#cose-header}
The COSE protected header for an ECT-CBOR token MUST contain the
following parameters:
alg (label 1):
: REQUIRED. The COSE algorithm identifier for the digital
signature. Implementations MUST support ES256 (COSE algorithm
identifier -7) {{RFC9053}}. The algorithm MUST be an asymmetric
signature algorithm. Symmetric MAC algorithms MUST NOT be used,
as ECTs require asymmetric signatures for non-repudiation. The
algorithm MUST match the algorithm in the agent's corresponding
WIT.
content type (label 3):
: REQUIRED. MUST be set to the string "application/wimse-exec+cwt"
or the equivalent CoAP Content-Format number once assigned.
Identifies the payload as a CBOR-serialized ECT.
kid (label 4):
: REQUIRED. Key identifier referencing the public key from the
agent's WIT. Encoded as bstr. Used by verifiers to look up the
correct public key for signature verification.
typ (label 16):
: REQUIRED. MUST be set to "wimse-exec+cwt". Distinguishes
ECT-CBOR tokens from other CWT types, per {{RFC9596}}.
ECTs MUST use the COSE_Sign1 structure (single signer) defined in
{{RFC9052}} Section 4.2. The COSE_Sign (multi-signer) structure
MUST NOT be used, consistent with the single-agent-signs model of
the JWT variant.
The unprotected header bucket MUST be empty. All header parameters
MUST be placed in the protected header to ensure integrity
protection.
Example protected header in CBOR diagnostic notation:
~~~cbor-diag
{
/ alg / 1: -7, / ES256 /
/ content type / 3: "application/wimse-exec+cwt",
/ kid / 4: h'6167656e742d612d6b65792d323032362d3032',
/ typ / 16: "wimse-exec+cwt"
}
~~~
{: #fig-cose-header title="ECT COSE Protected Header Example"}
# CWT Claim Mapping {#claim-mapping}
This section defines the complete mapping from JWT claim names used
in {{I-D.nennemann-wimse-execution-context}} to CBOR integer keys
used in the CWT payload.
## Standard CWT Claims
The following claims reuse existing CWT claim keys from the IANA
"CBOR Web Token (CWT) Claims" registry {{RFC8392}}:
| JWT Claim | CWT Key | CBOR Type | Description |
|:---:|:---:|:---|:---|
| iss | 1 | tstr | Issuer (SPIFFE ID) |
| sub | 2 | tstr | Subject (MUST equal iss when present) |
| aud | 3 | tstr / \[+ tstr\] | Audience |
| exp | 4 | int | Expiration (epoch seconds) |
| iat | 6 | int | Issued At (epoch seconds) |
| cti | 7 | bstr .size 16 | CWT ID / Task ID (UUID as 16-byte binary) |
{: #table-standard-claims title="Standard CWT Claim Mapping"}
The nbf (Not Before) claim (CWT key 5) is not used in ECTs, as ECTs
record completed actions.
### CWT ID Encoding {#cti-encoding}
The CWT ID (cti, key 7) is the CWT equivalent of the JWT jti claim.
In the companion JWT specification, jti serves as both the token
identifier (for replay detection) and the task identifier (for DAG
parent references in par). Since each ECT represents exactly one
task, a separate task identifier is not needed.
In the CBOR variant, cti MUST be encoded as a 16-byte binary string
containing the UUID in network byte order per {{RFC9562}} Section 4.
This saves 20 bytes per token. When wid is present, uniqueness of
cti is scoped to the workflow; when wid is absent, uniqueness MUST
be enforced globally across the ECT store.
Implementations MAY additionally apply CBOR tag 37 to explicitly
mark the value as a UUID.
### Timestamp Encoding
Timestamps (exp key 4, iat key 6) use the CWT NumericDate format:
integer seconds since the Unix epoch (1970-01-01T00:00:00Z). This
is semantically identical to JWT NumericDate but without fractional
seconds. Implementations MAY use CBOR tag 1 (epoch-based date/time)
to explicitly tag timestamp values.
## ECT-Specific Claims {#ect-claims}
The following claim keys are defined by this specification for
ECT-specific claims. These keys are requested for registration in
the "CBOR Web Token (CWT) Claims" registry (see {{iana}}).
| JWT Claim | CWT Key | CBOR Type | Req/Opt | Description |
|:---|:---:|:---|:---:|:---|
| wid | 300 | bstr .size 16 | OPT | Workflow ID (UUID binary) |
| exec_act | 301 | tstr | REQ | Action/task type identifier |
| par | 302 | \[* bstr .size 16\] | REQ | Parent ECT cti UUIDs |
| pol | 303 | tstr | OPT | Policy rule identifier |
| pol_decision | 304 | uint | OPT | Policy decision enum |
| pol_enforcer | 305 | tstr | OPT | Policy enforcer identity |
| pol_timestamp | 306 | int | OPT | Policy decision timestamp |
| inp_hash | 307 | \[int, bstr\] | OPT | Input hash \[alg_id, hash\] |
| out_hash | 308 | \[int, bstr\] | OPT | Output hash \[alg_id, hash\] |
| inp_classification | 309 | tstr | OPT | Input data classification |
| exec_time_ms | 310 | uint | OPT | Execution duration (ms) |
| regulated_domain | 311 | uint | OPT | Regulatory domain enum |
| model_version | 312 | tstr | OPT | AI/ML model version |
| witnessed_by | 313 | \[+ tstr\] | OPT | Witness SPIFFE IDs |
| compensation_required | 314 | bool | OPT | Compensation flag |
| compensation_reason | 315 | tstr | OPT | Compensation reason ID |
| ext | 316 | map | OPT | Extension map |
{: #table-ect-claims title="ECT-Specific CWT Claim Mapping"}
The Req/Opt column indicates whether the claim is REQUIRED or
OPTIONAL, matching the designations in
{{I-D.nennemann-wimse-execution-context}}.
The pol (key 303) and pol_decision (key 304) claims are OPTIONAL but
MUST be paired: if one is present, the other MUST also be present.
When both are absent, the ECT records task execution without a
policy checkpoint. Regulated deployments SHOULD include policy
claims on all ECTs to maintain complete audit trails.
The par claim (key 302) contains the cti values of previously
verified parent ECTs. Since cti serves as both the token identifier
and the task identifier, par entries reference cti values directly.
## Design Decisions
### UUIDs as Binary {#uuid-binary}
In the JWT variant, UUIDs (jti, wid, par entries) are encoded as
hyphenated text strings (e.g., "550e8400-e29b-41d4-a716-
446655440001"), consuming 36 bytes per UUID. In the CBOR variant,
UUIDs MUST be encoded as 16-byte binary strings (bstr .size 16) in
network byte order per {{RFC9562}} Section 4. This saves 20 bytes
per UUID.
For the par claim (key 302), each entry is the cti (16-byte binary
UUID) of a previously verified parent ECT. An empty par array
indicates a root task, identical to the JWT variant semantics.
Implementations MAY use CBOR tag 37 ({{RFC9562}}) to explicitly tag
UUID values. Receivers MUST accept UUID values both with and
without tag 37.
### Hash Encoding {#hash-encoding}
In the JWT variant, hash values use the string format
"algorithm:base64url-encoded-hash" (e.g.,
"sha-256:n4bQgYhM..."). In the CBOR variant, hash values
(inp_hash key 307, out_hash key 308) use a structured two-element
CBOR array:
~~~cbor-diag
[hash_algorithm_id, hash_bytes]
~~~
Where:
- hash_algorithm_id is the integer algorithm identifier from the
IANA "COSE Algorithms" registry. For SHA-256, this is -16.
- hash_bytes is the raw hash value as a binary string (bstr).
This structured encoding is more compact (no base64url overhead)
and type-safe (integer algorithm identifiers prevent string
parsing ambiguity).
Example (SHA-256 hash):
~~~cbor-diag
/ inp_hash / 307: [-16, h'9f86d081884c7d659a2feaa0c55ad015
a3bf4f1b2b0b822cd15d6c15b0f00a08']
~~~
Implementations MUST support SHA-256 (algorithm ID -16). Hash
algorithms weaker than SHA-256 MUST NOT be accepted.
### Policy Decision Enumeration {#pol-decision-enum}
In the JWT variant, pol_decision uses string values. In the CBOR
variant, pol_decision (key 304) uses unsigned integer enumeration
for compactness:
| Integer Value | JWT String Value | Description |
|:---:|:---|:---|
| 0 | approved | Policy evaluation succeeded |
| 1 | rejected | Policy evaluation failed |
| 2 | pending_human_review | Awaiting human judgment |
{: #table-pol-decision title="Policy Decision Enumeration"}
The processing rules are identical to the JWT variant: rejected ECTs
MUST still be appended to the ledger, and rejected parents may only
feed compensation, rollback, or remediation tasks.
### Regulated Domain Enumeration {#regulated-domain-enum}
In the JWT variant, regulated_domain uses string values. In the
CBOR variant, regulated_domain (key 311) uses unsigned integer
enumeration:
| Integer Value | JWT String Value | Description |
|:---:|:---|:---|
| 0 | medtech | Medical technology and devices |
| 1 | finance | Financial services and trading |
| 2 | military | Military and defense |
{: #table-regulated-domain title="Regulated Domain Enumeration"}
### Extension Map
The ext claim (key 316) is a CBOR map with text string keys in
reverse domain notation (e.g., "com.example.custom_field"),
identical to the JWT variant. Values MAY be any CBOR type. The
serialized ext map SHOULD NOT exceed 4096 bytes. Map nesting depth
SHOULD NOT exceed 5 levels. Unknown extensions MUST be ignored by
receivers.
# CDDL Schema {#cddl-schema}
The following CDDL {{RFC8610}} schema defines the structure of an
ECT-CBOR payload:
~~~cddl
ect-cbor-payload = {
; === Standard CWT claims ===
1 => tstr, ; iss - Issuer (SPIFFE ID)
? 2 => tstr, ; sub - Subject (= iss)
3 => tstr / [+ tstr], ; aud - Audience
4 => epoch-time, ; exp - Expiration
6 => epoch-time, ; iat - Issued At
7 => bstr .size 16, ; cti - CWT/Task ID (UUID)
; === Execution Context claims ===
? 300 => bstr .size 16, ; wid - Workflow ID (UUID)
301 => tstr, ; exec_act - Action type
302 => [* bstr .size 16], ; par - Parent ECT cti UUIDs
; === Optional policy claims (must be paired) ===
? 303 => tstr, ; pol - Policy rule ID
? 304 => pol-decision, ; pol_decision
? 305 => tstr, ; pol_enforcer
? 306 => epoch-time, ; pol_timestamp
; === Optional data integrity ===
? 307 => hash-entry, ; inp_hash
? 308 => hash-entry, ; out_hash
? 309 => tstr, ; inp_classification
; === Optional metadata ===
? 310 => uint, ; exec_time_ms
? 311 => regulated-domain, ; regulated_domain
? 312 => tstr, ; model_version
? 313 => [+ tstr], ; witnessed_by
? 314 => bool, ; compensation_required
? 315 => tstr, ; compensation_reason
? 316 => { + tstr => any }, ; ext
}
; Policy decision: 0=approved, 1=rejected,
; 2=pending_human_review
pol-decision = 0..2
; Regulated domain: 0=medtech, 1=finance, 2=military
regulated-domain = 0..2
; Hash entry: [algorithm_id, hash_bytes]
; algorithm_id from COSE Algorithms registry (e.g., -16 = SHA-256)
hash-entry = [int, bstr]
; epoch-time is integer seconds since Unix epoch
epoch-time = int
~~~
{: #fig-cddl title="CDDL Schema for ECT-CBOR Payload"}
The COSE_Sign1 wrapper structure is defined in {{cose-structure}}.
# COSE_Sign1 Structure {#cose-structure}
An ECT-CBOR token is a COSE_Sign1 message {{RFC9052}} Section 4.2
with the following structure:
~~~cddl
ECT-COSE = COSE_Sign1_Tagged
COSE_Sign1_Tagged = #6.18(COSE_Sign1)
COSE_Sign1 = [
protected: bstr, ; Serialized protected header map
unprotected: {}, ; MUST be empty
payload: bstr, ; Serialized ECT-CBOR claims map
signature: bstr ; Digital signature
]
~~~
{: #fig-cose-structure title="COSE_Sign1 Structure for ECT-CBOR"}
The components are:
protected:
: The CBOR-serialized protected header map as defined in
{{cose-header}}. Encoded as a bstr wrapping the CBOR map.
unprotected:
: MUST be an empty map. No unprotected header parameters are
permitted for ECTs. All parameters reside in the protected bucket
to ensure integrity.
payload:
: The CBOR-serialized ECT claims map conforming to the CDDL schema
in {{cddl-schema}}. Encoded as a bstr.
signature:
: The digital signature computed per {{RFC9052}} Section 4.4. For
ES256, this is a 64-byte value containing the (r, s) pair in
fixed-length encoding.
The Sig_structure for computing the signature is per {{RFC9052}}
Section 4.4:
~~~cddl
Sig_structure = [
context: "Signature1",
body_protected: bstr, ; Serialized protected header
external_aad: bstr, ; Empty bstr (h'') unless transport-bound
payload: bstr ; Serialized ECT claims map
]
~~~
{: #fig-sig-structure title="Sig_structure for ECT Signature Computation"}
External Additional Authenticated Data (external_aad) is an empty
byte string unless the ECT is bound to a transport-layer context
(e.g., OSCORE {{RFC8613}}). When transport binding is used, the
binding mechanism MUST be documented.
# Transport Mechanisms {#transport}
## HTTP Transport {#http-transport}
When ECT-CBOR tokens are transported over HTTP, the same
Execution-Context header field defined in
{{I-D.nennemann-wimse-execution-context}} is used. The header value
is the Base64url-encoded COSE_Sign1 byte sequence (without padding).
Receivers can distinguish JWT and CBOR ECTs by examining the first
bytes of the decoded value:
- JWT ECTs begin with the byte 0x7B (ASCII '{'), as the decoded
JWS header starts with a JSON object.
- CBOR ECTs begin with the byte 0xD2 (CBOR tag 18 for
COSE_Sign1_Tagged) or 0x84 (CBOR array of length 4 for an
untagged COSE_Sign1).
Implementations that support both formats MUST perform this
detection. Implementations that support only one format MAY reject
tokens in the unsupported format.
Example:
~~~
GET /api/safety-check HTTP/1.1
Host: safety-agent.example.com
Workload-Identity: eyJhbGci...WIT...
Workload-Proof-Token: eyJhbGci...WPT...
Execution-Context: 0oRYJ6QBJgMeYXBwbGljYXRp...CBOR-ECT...
~~~
{: #fig-http-cbor title="HTTP Request with CBOR ECT"}
When multiple parent tasks contribute context, multiple
Execution-Context header field lines MAY be included, each carrying
either a JWT or CBOR ECT. Receivers MUST individually verify each
ECT regardless of its serialization format.
## CoAP Transport {#coap-transport}
For CoAP {{RFC7252}} deployments, ECT-CBOR tokens are carried using
one of the following mechanisms:
### CoAP Option
A new CoAP Option is defined:
| Number | Name | Format |
|:---:|:---|:---|
| TBD1 | Execution-Context | opaque |
{: #table-coap-option title="CoAP Option for ECT-CBOR"}
The option value is the raw COSE_Sign1 byte sequence (not
Base64url-encoded). CoAP's binary-native transport eliminates the
need for text encoding.
When the ECT exceeds the CoAP option size limit, implementations
SHOULD use CoAP block-wise transfer {{?RFC7959}} or carry the ECT
in the request payload with the Content-Format set to
application/wimse-exec+cwt (see {{iana}}).
### Content-Format
The CoAP Content-Format identifier for ECT-CBOR is registered in
{{iana}}. When ECTs are carried in the CoAP payload body rather
than an option, the Content-Format MUST be set to the registered
identifier for application/wimse-exec+cwt.
### Transport Security
CoAP-based ECT transport MUST use DTLS 1.3 {{RFC9147}}, OSCORE
{{RFC8613}}, or EDHOC {{RFC9528}} for transport security. ECT
signatures provide message-level security, but transport-layer
confidentiality and integrity are still REQUIRED.
## MQTT Transport {#mqtt-transport}
For MQTT {{MQTT}} deployments, ECT-CBOR tokens MAY be carried as:
1. **MQTT User Property**: The property name is "Execution-Context"
and the value is the Base64-encoded COSE_Sign1 byte sequence.
Multiple Execution-Context properties MAY be included for
multiple parent ECTs.
2. **Payload envelope**: The ECT is embedded within the MQTT
application payload as a CBOR-encoded field. The envelope
structure is application-defined.
MQTT transport MUST use TLS for transport security. MQTT User
Properties are not encrypted by the MQTT protocol itself; ECT
signatures provide message-level integrity but not confidentiality
of claim values.
## Raw Binary Transport {#binary-transport}
For Layer 2, fieldbus, or other non-IP protocols, ECT-CBOR tokens
can be embedded directly as COSE_Sign1 byte sequences. The framing
format is:
~~~
+----------------+------------------------------+
| Length (2 or 4 | COSE_Sign1 bytes |
| bytes, network | |
| byte order) | |
+----------------+------------------------------+
~~~
{: #fig-binary-framing title="Binary Transport Framing"}
Implementations MUST use 2-byte length for ECTs up to 65535 bytes
and 4-byte length for larger ECTs. The length field encodes the
number of bytes in the COSE_Sign1 structure that follows.
Multiple ECTs (for multiple parent tasks) are concatenated using
this framing.
# Verification Procedure {#verification}
The verification procedure for ECT-CBOR tokens follows the 15-step
procedure defined in {{I-D.nennemann-wimse-execution-context}}
Section "Signature and Token Verification", with the following
COSE-specific adaptations for the initial steps:
1. **Parse COSE_Sign1**: Decode the COSE_Sign1 structure per
{{RFC9052}} Section 4.4. Extract the protected header,
payload, and signature. If the input begins with CBOR tag 18,
strip the tag and process the inner array.
2. **Verify content type**: The protected header parameter content
type (label 3) MUST be present and MUST be
"application/wimse-exec+cwt" or the equivalent registered CoAP
Content-Format number.
3. **Verify alg**: The protected header parameter alg (label 1)
MUST be present and MUST be an asymmetric signature algorithm.
Symmetric MAC algorithms and absent/null values MUST be
rejected.
4. **Verify kid**: The protected header parameter kid (label 4)
MUST reference a known, valid public key from a WIT within the
trust domain.
5. **Verify signature**: Retrieve the public key identified by kid
and verify the COSE_Sign1 signature per {{RFC9052}}
Section 4.4, constructing the Sig_structure as defined in
{{cose-structure}}.
6. **Verify key not revoked**: Identical to the JWT variant.
7. **Verify algorithm alignment**: The alg parameter MUST match the
algorithm in the corresponding WIT.
8. **Verify issuer**: Decode the payload. The iss claim (key 1)
MUST match the sub claim of the WIT associated with the kid
public key.
9. **Verify audience**: The aud claim (key 3) MUST contain the
verifier's own workload identity.
10. **Verify expiration**: The exp claim (key 4) MUST indicate the
ECT has not expired.
11. **Verify iat freshness**: The iat claim (key 6) MUST NOT be
unreasonably far in the past (RECOMMENDED: 15 minutes) and MUST
NOT be in the future beyond clock skew tolerance (RECOMMENDED:
30 seconds).
12. **Verify required claims**: The cti (key 7), exec_act
(key 301), and par (key 302) claims MUST all be present and
well-formed per the CDDL schema in {{cddl-schema}}.
13. **Verify policy claims**: If pol (key 303) or pol_decision
(key 304) is present, verify that both are present and that
pol_decision is 0, 1, or 2.
14. **Perform DAG validation**: Per the DAG validation rules in
{{I-D.nennemann-wimse-execution-context}}. When comparing task
IDs across JWT and CBOR ECTs in a mixed-format deployment, UUID
comparison MUST be performed at the binary level (converting
text UUIDs to 16-byte binary for comparison).
15. **Store ECT**: If all checks pass and an audit ledger is
available, the ECT SHOULD be appended.
Error handling follows the same rules as the JWT variant.
Verification failures MUST be logged. Error messages SHOULD NOT
reveal whether specific parent task IDs exist in the ledger.
# Audit Ledger Considerations {#ledger}
The audit ledger interface defined in
{{I-D.nennemann-wimse-execution-context}} applies to CBOR ECTs.
The ledger entry structure carries the raw COSE_Sign1 bytes instead
of the JWS compact serialization:
~~~cbor-diag
{
"ledger_sequence": 42,
"ect_jti": h'550e8400e29b41d4a716446655440001',
"agent_id": "spiffe://example.com/agent/clinical",
"action": "recommend_treatment",
"parents": [],
"ect_cose": h'd28443a10126a058...full COSE_Sign1 bytes...',
"signature_verified": true,
"verification_timestamp": 1(1772064151),
"stored_timestamp": 1(1772064151)
}
~~~
{: #fig-ledger-entry title="Ledger Entry for CBOR ECT"}
The ect_cose field is the authoritative record. Convenience fields
(agent_id, action, parents) are indexes; if they disagree with the
COSE_Sign1 payload, the COSE_Sign1 content takes precedence.
Ledgers that store both JWT and CBOR ECTs SHOULD include a format
discriminator field. Alternatively, the format can be detected from
the raw bytes: JWT ECTs (JWS compact serialization) are
ASCII-printable text with period separators, while CBOR ECTs begin
with CBOR-encoded bytes (tag 18 = 0xD2, or array header 0x84).
# Size Comparison {#size-comparison}
The following comparison uses the "Complete ECT Example" from
{{I-D.nennemann-wimse-execution-context}} Section 4.8 as the
reference payload. This example contains: iss, sub, aud, iat, exp,
jti, wid, exec_act, par (empty), pol, pol_decision,
pol_enforcer, pol_timestamp, inp_hash, out_hash,
inp_classification, exec_time_ms, regulated_domain, model_version,
and witnessed_by.
## JWT Variant Size
| Component | Estimated Bytes |
|:---|---:|
| JOSE header (JSON) | ~70 |
| Payload (JSON) | ~620 |
| ES256 signature (raw) | 64 |
| Base64url encoding overhead (~33%) | ~250 |
| Period separators | 2 |
| **Total (JWS Compact)** | **~1006** |
{: #table-jwt-size title="JWT ECT Size Estimate"}
## CBOR Variant Size
| Component | Estimated Bytes |
|:---|---:|
| Protected header (CBOR) | ~55 |
| Payload (CBOR) | ~240 |
| ES256 signature (raw) | 64 |
| COSE_Sign1 array framing | ~6 |
| **Total (COSE_Sign1)** | **~365** |
{: #table-cbor-size title="CBOR ECT Size Estimate"}
## Analysis
The CBOR variant achieves approximately **2.8x size reduction**
compared to the JWT variant. Key savings come from:
- **Integer claim keys** vs. string claim names: ~100 bytes saved
across all claims.
- **Binary UUIDs** (16 bytes each) vs. hyphenated text UUIDs (36
bytes each): ~60 bytes saved across jti, wid, and par entries.
- **Binary hash values** vs. base64url-encoded hash strings: ~22
bytes saved per hash (two hashes = ~44 bytes).
- **Integer enumerations** vs. string values for pol_decision and
regulated_domain: ~15 bytes saved.
- **No Base64url encoding**: COSE_Sign1 is a native binary format,
eliminating the ~33% overhead of Base64url encoding required for
JWS Compact Serialization when carried in binary transports
(CoAP, MQTT payload, raw binary).
When transported over HTTP (which requires Base64url encoding of
the COSE_Sign1 bytes), the size advantage is reduced but still
significant (~2x reduction).
# Security Considerations
The security considerations in
{{I-D.nennemann-wimse-execution-context}} apply in full to
CBOR-serialized ECTs. This section addresses additional
considerations specific to the CBOR/COSE serialization.
## CBOR Canonicalization
CBOR allows multiple valid encodings of the same data (e.g.,
different integer widths, indefinite-length encoding). To ensure
consistent hashing and signature verification:
- ECT payloads SHOULD use deterministic CBOR encoding as defined in
{{RFC8949}} Section 4.2 (Core Deterministic Encoding
Requirements).
- Implementations MUST NOT reject ECTs solely because the payload
uses a non-preferred but valid CBOR encoding, provided the
COSE_Sign1 signature verifies correctly.
- The protected header MUST use deterministic encoding, as it is
included in the Sig_structure for signature computation.
## COSE Algorithm Agility
The same algorithm constraints as the JWT variant apply: symmetric
algorithms MUST NOT be used, and the absence of an algorithm
identifier MUST be rejected. Implementations SHOULD support
algorithm agility by accepting any COSE asymmetric signature
algorithm registered in the IANA "COSE Algorithms" registry, subject
to local policy on minimum security strength.
## CoAP Transport Security
When ECTs are transported over CoAP, transport security MUST be
provided by DTLS 1.3 {{RFC9147}}, OSCORE {{RFC8613}}, or EDHOC
{{RFC9528}}. CoAP without transport security MUST NOT be used for
ECT transport, even though ECT signatures provide message-level
integrity. Transport security provides confidentiality of claim
values (ECT signatures do not encrypt the payload).
## MQTT Transport Security
When ECTs are transported over MQTT, TLS MUST be used for the MQTT
connection. MQTT User Properties are transmitted in cleartext within
the MQTT protocol layer; TLS provides the necessary confidentiality.
ECT signatures ensure integrity and non-repudiation independent of
the transport.
## Binary Transport Security
For raw binary transports ({{binary-transport}}), ECT signatures
provide message-level integrity and authenticity. However,
transport-layer integrity mechanisms (checksums, MACs, link-layer
encryption) are RECOMMENDED as defense in depth. Without transport
security, claim values are transmitted in cleartext.
## Mixed-Format Deployments
In deployments where some agents produce JWT ECTs and others produce
CBOR ECTs within the same workflow:
- DAG validation MUST compare ECT identifiers (jti/cti) at the
binary UUID level. Text UUID representations MUST be converted
to 16-byte binary before comparison.
- Hash values MUST be compared at the raw byte level. The JWT
base64url-encoded hash MUST be decoded before comparison with
the CBOR binary hash.
- Policy decision values MUST be compared semantically: the JWT
string "approved" is equivalent to the CBOR integer 0, "rejected"
to 1, and "pending_human_review" to 2.
- Audit ledgers MUST support both formats and SHOULD normalize
comparison operations to a common representation.
# Privacy Considerations
The privacy considerations in
{{I-D.nennemann-wimse-execution-context}} apply identically to
CBOR-serialized ECTs. CBOR's binary encoding does not change the
privacy properties: the same claims are present, carrying the same
information, encoded differently.
Implementers should note that CBOR's compact encoding does not
provide confidentiality. The binary format may create a false sense
of obscurity, but CBOR-encoded data is trivially decoded by anyone
with access to the byte stream. ECT claim values SHOULD be
protected in transit via transport-layer encryption (TLS, DTLS,
OSCORE) and at rest via storage encryption.
# IANA Considerations {#iana}
## Media Type Registration
This document requests registration of the following media type
in the "Media Types" registry maintained by IANA:
Type name:
: application
Subtype name:
: wimse-exec+cwt
Required parameters:
: none
Optional parameters:
: none
Encoding considerations:
: binary; an ECT-CBOR is a COSE_Sign1 structure containing a
CBOR-encoded payload.
Security considerations:
: See the Security Considerations section of this document.
Interoperability considerations:
: none
Published specification:
: This document
Applications that use this media type:
: Applications that implement regulated agentic workflows requiring
execution context tracing and audit trails in constrained or
binary-transport environments.
Additional information:
: Magic number(s): none
File extension(s): none
Macintosh file type code(s): none
Person and email address to contact for further information:
: Christian Nennemann, ietf@nennemann.de
Intended usage:
: COMMON
Restrictions on usage:
: none
Author:
: Christian Nennemann
Change controller:
: IETF
## CoAP Content-Format Registration
This document requests registration of the following Content-Format
in the "CoAP Content-Formats" registry maintained by IANA:
| Media Type | Encoding | ID |
|:---|:---|:---:|
| application/wimse-exec+cwt | - | TBD2 |
{: #table-content-format title="CoAP Content-Format Registration"}
## CoAP Option Number Registration
This document requests registration of the following CoAP Option
in the "CoAP Option Numbers" registry maintained by IANA:
| Number | Name | Reference |
|:---:|:---|:---|
| TBD1 | Execution-Context | This document |
{: #table-coap-option-reg title="CoAP Option Registration"}
## CWT Claims Registration {#cwt-claims-registration}
This document requests registration of the following claims in the
"CBOR Web Token (CWT) Claims" registry maintained by IANA:
| Claim Name | Claim Key | Claim Value Type | Change Controller | Reference |
|:---|:---:|:---|:---:|:---|
| wid | 300 | bstr | IETF | {{ect-claims}} |
| exec_act | 301 | tstr | IETF | {{ect-claims}} |
| par | 302 | array | IETF | {{ect-claims}} |
| pol | 303 | tstr | IETF | {{ect-claims}} |
| pol_decision | 304 | uint | IETF | {{ect-claims}} |
| pol_enforcer | 305 | tstr | IETF | {{ect-claims}} |
| pol_timestamp | 306 | int | IETF | {{ect-claims}} |
| inp_hash | 307 | array | IETF | {{ect-claims}} |
| out_hash | 308 | array | IETF | {{ect-claims}} |
| inp_classification | 309 | tstr | IETF | {{ect-claims}} |
| exec_time_ms | 310 | uint | IETF | {{ect-claims}} |
| regulated_domain | 311 | uint | IETF | {{ect-claims}} |
| model_version | 312 | tstr | IETF | {{ect-claims}} |
| witnessed_by | 313 | array | IETF | {{ect-claims}} |
| compensation_required | 314 | true/false | IETF | {{ect-claims}} |
| compensation_reason | 315 | tstr | IETF | {{ect-claims}} |
| ext | 316 | map | IETF | {{ect-claims}} |
{: #table-cwt-claims-reg title="CWT Claims Registrations"}
## ECT-CBOR Policy Decision Values Registry {#cbor-pol-decision-registry}
This document establishes the "ECT-CBOR Policy Decision Values"
registry. Registration policy is Specification Required per
{{!RFC8126}}.
The initial contents of the registry are:
| Integer Value | Description | Change Controller | Reference |
|:---:|:---|:---:|:---|
| 0 | Policy evaluation succeeded (approved) | IETF | {{pol-decision-enum}} |
| 1 | Policy evaluation failed (rejected) | IETF | {{pol-decision-enum}} |
| 2 | Awaiting human judgment (pending_human_review) | IETF | {{pol-decision-enum}} |
{: #table-pol-decision-reg title="ECT-CBOR Policy Decision Values"}
## ECT-CBOR Regulated Domain Values Registry {#cbor-regulated-domain-registry}
This document establishes the "ECT-CBOR Regulated Domain Values"
registry. Registration policy is Specification Required per
{{!RFC8126}}.
The initial contents of the registry are:
| Integer Value | Description | Change Controller | Reference |
|:---:|:---|:---:|:---|
| 0 | Medical technology and devices (medtech) | IETF | {{regulated-domain-enum}} |
| 1 | Financial services and trading (finance) | IETF | {{regulated-domain-enum}} |
| 2 | Military and defense (military) | IETF | {{regulated-domain-enum}} |
{: #table-regulated-domain-reg title="ECT-CBOR Regulated Domain Values"}
--- back
# Related Work
{:numbered="false"}
## CWT and JWT Relationship
{:numbered="false"}
CBOR Web Token (CWT) {{RFC8392}} is the CBOR analog of JSON Web
Token (JWT) {{?RFC7519}}. CWT reuses the JWT claim semantics with
integer keys instead of string names and CBOR encoding instead of
JSON. This document follows the same pattern: ECT-CBOR reuses the
ECT-JWT claim semantics with CBOR-native encoding.
## COSE and JOSE Relationship
{:numbered="false"}
COSE {{RFC9052}} is the CBOR analog of JOSE {{?RFC7515}}. COSE
provides equivalent signing (COSE_Sign, COSE_Sign1), MAC
(COSE_Mac, COSE_Mac0), and encryption (COSE_Encrypt, COSE_Encrypt0)
operations. ECT-CBOR uses COSE_Sign1, the single-signer structure,
matching the JWS Compact Serialization (single signature) used by
ECT-JWT.
## Entity Attestation Token (EAT)
{:numbered="false"}
The Entity Attestation Token (EAT) {{EAT}} uses CWT as its base
and defines claims for hardware and software attestation. EAT and
ECT-CBOR share the CWT foundation and could potentially be
integrated: an EAT providing device attestation could carry ECT
claims to combine hardware trust with execution accountability.
Future work may define an EAT profile for ECT-CBOR.
## SUIT Manifests
{:numbered="false"}
The Software Update for IoT (SUIT) manifest
{{I-D.ietf-suit-manifest}} uses CBOR/COSE for secure firmware
update descriptions in constrained environments. SUIT and ECT-CBOR
target overlapping deployment environments (constrained IoT devices)
and share the CBOR/COSE toolchain. An agentic workflow that
includes firmware update tasks could use SUIT manifests for the
update payload and ECT-CBOR for the execution accountability record.
## SCITT Integration
{:numbered="false"}
As noted in {{I-D.nennemann-wimse-execution-context}}, ECTs can
integrate with the Supply Chain Integrity, Transparency and Trust
(SCITT) architecture {{I-D.ietf-scitt-architecture}}. SCITT uses
COSE_Sign1 as its signing structure, making ECT-CBOR a natural fit
for SCITT integration: ECT-CBOR tokens can be submitted to SCITT
Transparency Services as COSE_Sign1 signed statements without
format conversion.
# Examples
{:numbered="false"}
## Example 1: Simple Two-Agent Workflow
{:numbered="false"}
Agent A executes a data retrieval task and sends the ECT to Agent B.
ECT COSE Protected Header (CBOR diagnostic notation):
~~~cbor-diag
{
/ alg / 1: -7, / ES256 /
/ content type / 3: "application/wimse-exec+cwt",
/ kid / 4: h'6167656e742d612d6b65792d323032362d3032',
/ typ / 16: "wimse-exec+cwt"
}
~~~
ECT Payload (CBOR diagnostic notation):
~~~cbor-diag
{
/ iss / 1: "spiffe://example.com/agent/data-retrieval",
/ sub / 2: "spiffe://example.com/agent/data-retrieval",
/ aud / 3: "spiffe://example.com/agent/validator",
/ exp / 4: 1772064750,
/ iat / 6: 1772064150,
/ cti / 7: h'550e8400e29b41d4a716446655440001',
/ wid / 300: h'b1c2d3e4f5a67890bcdef01234567890',
/ exec_act / 301: "fetch_patient_data",
/ par / 302: [],
/ pol / 303: "clinical_data_access_policy_v1",
/ pol_decision / 304: 0, / approved /
/ inp_hash / 307: [-16,
h'9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'],
/ out_hash / 308: [-16,
h'2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'],
/ exec_time_ms / 310: 142,
/ regulated_domain / 311: 0 / medtech /
}
~~~
Agent B receives the ECT, verifies it, executes a validation task,
and creates its own ECT:
~~~cbor-diag
{
/ iss / 1: "spiffe://example.com/agent/validator",
/ sub / 2: "spiffe://example.com/agent/validator",
/ aud / 3: "spiffe://example.com/system/ledger",
/ exp / 4: 1772064760,
/ iat / 6: 1772064160,
/ cti / 7: h'550e8400e29b41d4a716446655440002',
/ wid / 300: h'b1c2d3e4f5a67890bcdef01234567890',
/ exec_act / 301: "validate_safety",
/ par / 302: [h'550e8400e29b41d4a716446655440001'],
/ pol / 303: "safety_validation_policy_v2",
/ pol_decision / 304: 0, / approved /
/ exec_time_ms / 310: 89,
/ regulated_domain / 311: 0 / medtech /
}
~~~
The resulting DAG:
~~~
task 550e...0001 (fetch_patient_data)
|
v
task 550e...0002 (validate_safety)
~~~
Approximate COSE_Sign1 structure (hex, abbreviated):
~~~
d2 -- Tag 18 (COSE_Sign1_Tagged)
84 -- Array(4)
58 37 -- bstr(55) - protected header
a4 01 26 03 78 1e ... -- {1: -7, 3: "application/...", ...}
a0 -- {} - empty unprotected header
58 c8 -- bstr(200) - payload
b0 01 78 28 ... -- {1: "spiffe://...", ...}
58 40 -- bstr(64) - signature
<64 bytes ES256 sig>
~~~
## Example 2: Medical Device SDLC (Tasks 1 and 5)
{:numbered="false"}
Task 1 (Spec Review Agent) payload:
~~~cbor-diag
{
/ iss / 1: "spiffe://meddev.example/agent/spec-reviewer",
/ sub / 2: "spiffe://meddev.example/agent/spec-reviewer",
/ aud / 3: "spiffe://meddev.example/agent/code-gen",
/ exp / 4: 1772064750,
/ iat / 6: 1772064150,
/ cti / 7: h'a1b2c3d4000100000000000000000001',
/ wid / 300: h'c2d3e4f5a6b78901cdef012345678901',
/ exec_act / 301: "review_requirements_spec",
/ par / 302: [],
/ pol / 303: "spec_review_policy_v2",
/ pol_decision / 304: 0, / approved /
/ inp_hash / 307: [-16,
h'9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'],
/ out_hash / 308: [-16,
h'2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'],
/ regulated_domain / 311: 0, / medtech /
/ model_version / 312: "spec-review-v3.1"
}
~~~
Task 5 (Human Release Manager Approval) payload:
~~~cbor-diag
{
/ iss / 1: "spiffe://meddev.example/human/release-mgr-42",
/ sub / 2: "spiffe://meddev.example/human/release-mgr-42",
/ aud / 3: "spiffe://meddev.example/system/ledger",
/ exp / 4: 1772065110,
/ iat / 6: 1772064510,
/ cti / 7: h'a1b2c3d4000100000000000000000005',
/ wid / 300: h'c2d3e4f5a6b78901cdef012345678901',
/ exec_act / 301: "approve_release",
/ par / 302: [h'a1b2c3d4000100000000000000000004'],
/ pol / 303: "release_approval_policy",
/ pol_decision / 304: 0, / approved /
/ pol_enforcer / 305:
"spiffe://meddev.example/human/release-mgr-42",
/ witnessed_by / 313: [
"spiffe://meddev.example/audit/qa-observer-1"
],
/ regulated_domain / 311: 0 / medtech /
}
~~~
The five-task DAG:
~~~
task ...-0001 (review_requirements_spec)
|
v
task ...-0002 (implement_module)
|
v
task ...-0003 (execute_test_suite)
|
v
task ...-0004 (build_release_artifact)
|
v
task ...-0005 (approve_release) [human, witnessed]
~~~
## Example 3: Parallel Execution with Join
{:numbered="false"}
A financial trading workflow where two tasks execute in parallel
and a third task depends on both:
~~~
task ...-0001 (assess_risk)
| \
v v
task ...-0002 task ...-0003
(check (verify
compliance) liquidity)
| /
v v
task ...-0004 (execute_trade)
~~~
Task 004 ECT payload (CBOR diagnostic notation):
~~~cbor-diag
{
/ iss / 1: "spiffe://bank.example/agent/execution",
/ sub / 2: "spiffe://bank.example/agent/execution",
/ aud / 3: "spiffe://bank.example/system/ledger",
/ exp / 4: 1772064850,
/ iat / 6: 1772064250,
/ cti / 7: h'f1e2d3c4000400000000000000000004',
/ wid / 300: h'd3e4f5a6b7c89012def0123456789012',
/ exec_act / 301: "execute_trade",
/ par / 302: [
h'f1e2d3c4000200000000000000000002',
h'f1e2d3c4000300000000000000000003'
],
/ pol / 303: "trade_execution_policy_v3",
/ pol_decision / 304: 0, / approved /
/ regulated_domain / 311: 1 / finance /
}
~~~
The par array with two entries records that both compliance checking
and liquidity verification were completed before trade execution.
# Acknowledgments
{:numbered="false"}
The author thanks the WIMSE working group for their foundational
work on workload identity in multi-system environments. The
concepts of Workload Identity Tokens and Workload Proof Tokens
provide the identity foundation upon which execution context
tracing is built.
The CBOR, COSE, and CWT communities have built an excellent
constrained-environment security stack that this document builds
upon.