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>
This commit is contained in:
2026-02-24 22:51:22 +01:00
commit ea188f1c22
4 changed files with 1867 additions and 0 deletions

63
cbor-variant/README.md Normal file
View File

@@ -0,0 +1,63 @@
# CBOR Serialization of Execution Context Tokens (ECT-CBOR)
**draft-nennemann-wimse-execution-context-cbor-00**
This Internet-Draft defines a CBOR/COSE/CWT serialization of Execution Context Tokens (ECTs) for the WIMSE working group.
## Relationship to the JWT Draft
This document is a **companion** to [draft-nennemann-wimse-execution-context](https://datatracker.ietf.org/doc/draft-nennemann-wimse-execution-context/), which defines the full ECT semantics using JSON/JOSE/JWT serialization.
- **JWT draft**: Normative semantic definition (claims, DAG validation, verification, operational modes, security model)
- **CBOR draft** (this document): CBOR/COSE/CWT serialization mapping, constrained-environment transports (CoAP, MQTT, raw binary)
The two drafts are designed for **independent adoption**: a deployment uses one or the other (or both in mixed-format mode), not both simultaneously for the same token.
## Files
| File | Description |
|------|-------------|
| `draft-nennemann-wimse-execution-context-cbor-00.md` | The complete Internet-Draft in kramdown-rfc format |
| `claim-mapping.md` | Standalone claim mapping reference table |
| `README.md` | This file |
## Building
### Prerequisites
- [kramdown-rfc](https://github.com/cabo/kramdown-rfc) (Ruby gem)
- [xml2rfc](https://xml2rfc.tools.ietf.org/) (Python package)
### Build Commands
```bash
# Install tools (if not already installed)
gem install kramdown-rfc
pip install xml2rfc
# Generate XML from kramdown
kramdown-rfc2629 draft-nennemann-wimse-execution-context-cbor-00.md > draft-nennemann-wimse-execution-context-cbor-00.xml
# Generate text output
xml2rfc draft-nennemann-wimse-execution-context-cbor-00.xml --text
# Generate HTML output
xml2rfc draft-nennemann-wimse-execution-context-cbor-00.xml --html
```
## Key Design Decisions
1. **UUIDs as 16-byte binary** instead of 36-byte hyphenated text (saves 20 bytes per UUID)
2. **`jti`/`cti` as unified token+task ID** — no separate `tid` claim (matching JWT draft)
3. **`pol`/`pol_decision` OPTIONAL** but must be paired (matching JWT draft)
4. **Integer claim keys** (300-316) instead of string claim names
5. **Structured hash arrays** `[alg_id, hash_bytes]` instead of `"algorithm:base64url"` strings
6. **Integer enumerations** for pol_decision (0/1/2) and regulated_domain (0/1/2)
7. **COSE_Sign1** (single signer) matching the JWT variant's JWS Compact Serialization model
8. **~2.8x size reduction** compared to JWT variant (~365 bytes vs ~1006 bytes for a typical ECT)
## Author
Christian Nennemann
Independent Researcher
ietf@nennemann.de

View File

@@ -0,0 +1,111 @@
# ECT Claim Mapping: JWT to CWT
This document provides a standalone reference for mapping JWT claim names from [draft-nennemann-wimse-execution-context](https://datatracker.ietf.org/doc/draft-nennemann-wimse-execution-context/) to CWT integer keys defined in [draft-nennemann-wimse-execution-context-cbor](https://datatracker.ietf.org/doc/draft-nennemann-wimse-execution-context-cbor/).
## Standard CWT Claims (Existing IANA Registry)
| JWT Claim | CWT Key | CBOR Type | Req/Opt | Description | Encoding Notes |
|:---:|:---:|:---|:---:|:---|:---|
| iss | 1 | tstr | REQ | Issuer (SPIFFE ID) | Identical text |
| sub | 2 | tstr | OPT | Subject (= iss) | Identical text |
| aud | 3 | tstr / [+ tstr] | REQ | Audience | Identical text; array for multi-audience |
| exp | 4 | int | REQ | Expiration | Integer epoch seconds (no fractions) |
| iat | 6 | int | REQ | Issued At | Integer epoch seconds (no fractions) |
| jti / cti | 7 | bstr .size 16 | REQ | Token ID / Task ID | UUID as 16-byte binary (not 36-byte text); serves as both token and task identifier |
**Note**: nbf (CWT key 5) is not used in ECTs. The `jti`/`cti` claim serves as both the token identifier (for replay detection) and the task identifier (for DAG parent references in `par`), since each ECT records exactly one task.
## ECT-Specific Claims (New Registrations)
| JWT Claim | CWT Key | CBOR Type | Req/Opt | Description | Encoding Notes |
|:---|:---:|:---|:---:|:---|:---|
| wid | 300 | bstr .size 16 | OPT | Workflow ID | UUID as 16-byte binary |
| exec_act | 301 | tstr | REQ | Action/task type | Identical text |
| par | 302 | [* bstr .size 16] | REQ | Parent ECT IDs | Array of parent cti UUIDs (16-byte binary); empty = root |
| pol | 303 | tstr | OPT | Policy rule ID | Identical text; must be paired with pol_decision |
| pol_decision | 304 | uint (0..2) | OPT | Policy decision | 0=approved, 1=rejected, 2=pending_human_review; must be paired with pol |
| pol_enforcer | 305 | tstr | OPT | Policy enforcer | Identical text (SPIFFE ID) |
| pol_timestamp | 306 | int | OPT | Policy timestamp | Integer epoch seconds |
| inp_hash | 307 | [int, bstr] | OPT | Input data hash | [COSE_alg_id, raw_hash_bytes] |
| out_hash | 308 | [int, bstr] | OPT | Output data hash | [COSE_alg_id, raw_hash_bytes] |
| inp_classification | 309 | tstr | OPT | Input classification | Identical text |
| exec_time_ms | 310 | uint | OPT | Execution time (ms) | Identical integer |
| regulated_domain | 311 | uint (0..2) | OPT | Regulatory domain | 0=medtech, 1=finance, 2=military |
| model_version | 312 | tstr | OPT | AI/ML model version | Identical text |
| witnessed_by | 313 | [+ tstr] | OPT | Witness identities | Identical text array (SPIFFE IDs) |
| compensation_required | 314 | bool | OPT | Compensation flag | CBOR true/false |
| compensation_reason | 315 | tstr | OPT | Compensation reason | Identical text |
| ext | 316 | map { tstr => any } | OPT | Extension map | Keys: reverse domain notation; values: any CBOR |
## Enumeration Mappings
### Policy Decision Values (pol_decision)
| CBOR uint | JWT string | Description |
|:---:|:---|:---|
| 0 | "approved" | Policy evaluation succeeded |
| 1 | "rejected" | Policy evaluation failed |
| 2 | "pending_human_review" | Awaiting human judgment |
### Regulated Domain Values (regulated_domain)
| CBOR uint | JWT string | Description |
|:---:|:---|:---|
| 0 | "medtech" | Medical technology and devices |
| 1 | "finance" | Financial services and trading |
| 2 | "military" | Military and defense |
## Hash Algorithm Mapping
JWT ECTs use the string format `"algorithm:base64url-hash"`. CBOR ECTs use the structured array `[cose_algorithm_id, raw_hash_bytes]`.
| JWT Hash Algorithm String | COSE Algorithm ID | Reference |
|:---|:---:|:---|
| sha-256 | -16 | RFC 9053 |
| sha-384 | -43 | RFC 9053 |
| sha-512 | -44 | RFC 9053 |
## COSE Header Parameters
| JOSE Parameter | COSE Label | CBOR Type | Description |
|:---|:---:|:---|:---|
| alg | 1 | int | Signature algorithm (e.g., -7 = ES256) |
| (content type) | 3 | tstr / uint | "application/wimse-exec+cwt" |
| kid | 4 | bstr | Key identifier from WIT |
| typ | 16 | tstr | "wimse-exec+cwt" |
## Quick Reference: JWT Example to CBOR Diagnostic
### JWT Payload
```json
{
"iss": "spiffe://example.com/agent/clinical",
"aud": "spiffe://example.com/agent/safety",
"iat": 1772064150,
"exp": 1772064750,
"jti": "550e8400-e29b-41d4-a716-446655440001",
"exec_act": "recommend_treatment",
"par": [],
"pol": "clinical_reasoning_policy_v2",
"pol_decision": "approved",
"regulated_domain": "medtech"
}
```
### Equivalent CBOR Diagnostic
```
{
1: "spiffe://example.com/agent/clinical",
3: "spiffe://example.com/agent/safety",
6: 1772064150,
4: 1772064750,
7: h'550e8400e29b41d4a716446655440001',
301: "recommend_treatment",
302: [],
303: "clinical_reasoning_policy_v2",
304: 0,
311: 0
}
```

File diff suppressed because it is too large Load Diff