--- 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.