diff --git a/blog-ect-assurance-levels.md b/blog-ect-assurance-levels.md index f322ede..6494a52 100644 --- a/blog-ect-assurance-levels.md +++ b/blog-ect-assurance-levels.md @@ -19,7 +19,7 @@ ECTs originated as an extension to the IETF WIMSE (Workload Identity in Multi-Sy The key properties: - **Per-task granularity.** One ECT per task, not one per session or per request chain. -- **DAG ordering.** Parent references (`par` claim) create a verifiable execution graph. Fan-out, fan-in, parallel branches — all representable. +- **DAG ordering.** Parent references (`pred` claim) create a verifiable execution graph. Fan-out, fan-in, parallel branches — all representable. - **Data integrity without data exposure.** Input and output hashes (`inp_hash`, `out_hash`) prove what was processed without revealing the data itself. - **Identity-framework agnostic.** ECTs work with WIMSE WIT/WPT, X.509 certificates, OAuth credentials, or plain JWK sets. The spec defines abstract identity binding requirements and concrete profiles for each framework. @@ -121,7 +121,7 @@ A single deployment can use different levels for different workflows. Your inter ## The Upgrade Path -This is arguably the most important design property of the assurance levels: **the payload is the same at every level.** The same `jti`, `iss`, `aud`, `iat`, `exp`, `exec_act`, `par`, `inp_hash`, `out_hash`, and `ext` claims appear in every ECT, whether it's unsigned JSON or a ledger-committed JWS token. +This is arguably the most important design property of the assurance levels: **the payload is the same at every level.** The same `jti`, `iss`, `aud`, `iat`, `exp`, `exec_act`, `pred`, `inp_hash`, `out_hash`, and `ect_ext` claims appear in every ECT, whether it's unsigned JSON or a ledger-committed JWS token. What changes is the envelope and the verification procedure. This means upgrading from L1 to L2 means adding a JWS wrapper around the same payload. Upgrading from L2 to L3 means deploying an audit ledger and adding the ledger recording step after JWS verification. diff --git a/draft-nennemann-wimse-ect.md b/draft-nennemann-wimse-ect.md index 57feaa9..d7fe1f9 100644 --- a/draft-nennemann-wimse-ect.md +++ b/draft-nennemann-wimse-ect.md @@ -32,12 +32,14 @@ normative: RFC9110: informative: + RFC6838: RFC8693: + RFC8725: I-D.ietf-wimse-arch: I-D.ietf-wimse-s2s-protocol: SPIFFE: title: "SPIFFE ID" - target: https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md + target: https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/ date: false OPENTELEMETRY: title: "OpenTelemetry Specification" @@ -49,7 +51,9 @@ informative: I-D.ietf-oauth-transaction-tokens: I-D.oauth-transaction-tokens-for-agents: title: "Transaction Tokens for Agentic AI Systems" - target: https://datatracker.ietf.org/doc/draft-oauth-transaction-tokens-for-agents/ + target: https://datatracker.ietf.org/doc/draft-oauth-transaction-tokens-for-agents-00/ + seriesinfo: + Internet-Draft: draft-oauth-transaction-tokens-for-agents-00 date: 2025 author: - fullname: Vittorio Bertocci @@ -197,21 +201,23 @@ this section. The following standard JWT claims {{RFC7519}} are defined for ECTs: iss: -: RECOMMENDED. StringOrURI. A URI identifying the issuer of the - ECT. The value MUST correspond to the agent's identity as - asserted by its identity credential (see {{identity-binding}}). - In WIMSE deployments, this SHOULD be the workload's SPIFFE ID - in the format `spiffe:///`. Other - deployments MAY use HTTPS URLs, URN:UUID identifiers, or other - URI schemes appropriate to the identity framework in use. The - "iss" claim is REQUIRED for L2 and L3 deployments (see - {{l2-verification}} and {{l3-verification}}). +: OPTIONAL at L1; REQUIRED at L2 and L3. StringOrURI. A URI + identifying the issuer of the ECT. The value MUST correspond + to the agent's identity as asserted by its identity credential + (see {{identity-binding}}). In WIMSE deployments, this SHOULD + be the workload's SPIFFE ID in the format + `spiffe:///`. Other deployments MAY use + HTTPS URLs, URN:UUID identifiers, or other URI schemes + appropriate to the identity framework in use. L1 deployments + are encouraged to include "iss" for consistency but it is not + required. See {{l2-verification}} and {{l3-verification}} for + the L2/L3 verification requirements. aud: : RECOMMENDED. StringOrURI or array of StringOrURI. The intended recipient(s) of the ECT. The "aud" claim SHOULD contain the identifiers of all entities that will verify the ECT. When - an ECT must be verified by both the next agent and the audit + an ECT is to be verified by both the next agent and the audit ledger independently, "aud" MUST be an array containing both identifiers. Each verifier checks that its own identity appears in "aud". The "aud" claim is REQUIRED for L2 and L3 @@ -254,7 +260,10 @@ pred: representing DAG dependencies. Each element MUST be the "jti" value of a previously verified ECT. An empty array indicates a root task with no dependencies. A workflow MAY contain - multiple root tasks. + multiple root tasks. The "pred" claim is always required + (rather than optional with absence meaning "root task") to + simplify validation logic and eliminate ambiguity between a + root task and a claim accidentally omitted. ### Data Integrity Claims {#data-integrity-claims} @@ -275,15 +284,15 @@ out_hash: ### Extension Claims {#extension-claims} -ext: +ect_ext: : OPTIONAL. Object. A general-purpose extension object for domain-specific claims not defined by this specification. Implementations that do not understand extension claims MUST ignore them. Extension key names SHOULD use reverse domain notation (e.g., "com.example.custom_field") to avoid - collisions. The serialized "ext" object MUST NOT exceed + collisions. The serialized "ect_ext" object MUST NOT exceed 4096 bytes and MUST NOT exceed a nesting depth of 5 levels. - Receivers MUST reject ECTs whose "ext" object exceeds these + Receivers MUST reject ECTs whose "ect_ext" object exceeds these limits. ## Complete ECT Payload Example @@ -307,7 +316,7 @@ envelope differs. "inp_hash": "n4bQgYhMfWWaL-qgxVrQFaO_TxsrC4Is0V1sFbDwCgg", "out_hash": "LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564", - "ext": { + "ect_ext": { "com.example.trace_id": "abc123" } } @@ -428,7 +437,15 @@ alg: credential. Implementations MUST support ES256 {{RFC7518}}. The "alg" value MUST NOT be "none". Symmetric algorithms (e.g., HS256, HS384, HS512) MUST NOT be used, as ECTs require - asymmetric signatures for non-repudiation. + asymmetric signatures for non-repudiation. To support algorithm + agility, deployments SHOULD maintain an allowlist of accepted + signing algorithms and SHOULD plan for migration to stronger + algorithms as cryptographic requirements evolve. The algorithm + is signaled in-band via the "alg" header parameter, enabling + verifiers to support multiple algorithms during a transition + period. Deployments SHOULD document their algorithm migration + strategy and SHOULD NOT assume that ES256 will remain + sufficient indefinitely. typ: : REQUIRED. MUST be set to "exec+jwt" to distinguish ECTs from @@ -616,18 +633,23 @@ REQUIRED at L3. 1. Perform all L2 verification steps (steps 1 through 14 of {{l2-verification}}). -2. Submit the ECT to the audit ledger for recording per - {{l3-recording}}. +2. Verify that the ECT has been recorded in the audit ledger by + querying the ledger for the ECT's "jti". If the ECT is + found, verify that the ledger entry's receipt contains a + valid sequence number, ECT hash, and cryptographic commitment + proof. Note: the producing agent is responsible for recording + the ECT per {{l3-recording}}; the verifier checks that + recording has occurred. -3. Verify that the ledger returned a valid receipt containing - the sequence number, ECT hash, and cryptographic commitment - proof. +3. If the ECT is not yet present in the ledger (e.g., due to + asynchronous recording), the verifier MAY retry after a + short delay. If the ledger does not contain the ECT within + the configured timeout, the verifier MUST either reject the + ECT or downgrade to L2 verification per deployment policy. -4. If synchronous recording is required by deployment policy and - the ledger does not return a receipt within the configured - timeout, the agent SHOULD retry with exponential backoff. - If the ledger remains unavailable after a - deployment-configured number of retries, the agent MUST +4. If the ledger is unavailable, the verifier SHOULD retry with + exponential backoff. If the ledger remains unavailable after + a deployment-configured number of retries, the verifier MUST either reject the ECT or downgrade to L2 verification per deployment policy. @@ -668,13 +690,23 @@ following criteria: - Use L3 when regulatory requirements mandate tamper-evident audit trails with cryptographic commitment, or when the - deployment must demonstrate compliance with frameworks such as + deployment needs to demonstrate compliance with frameworks such as FDA 21 CFR Part 11, MiFID II, or the EU AI Act. A deployment MAY use different assurance levels for different workflows within the same infrastructure. When agents at different levels interact, the higher level's verification -requirements apply to the receiving agent. +requirements apply to the receiving agent. Specifically, an +ECT at a higher assurance level MAY reference parent ECTs at a +lower assurance level in its "pred" claim. In this case, the +receiving agent applies its own level's verification to the +current ECT and the parent's level verification to each parent +ECT. For example, an L2 agent receiving an L1 parent ECT +verifies the L1 parent per {{l1-verification}} and its own L2 +ECT per {{l2-verification}}. Whether cross-level parent +references are permitted is a deployment policy decision; +deployments MAY reject ECTs whose parents are below a minimum +assurance level. This specification does not define a level negotiation mechanism. Deployments configure the required assurance level out of band. @@ -817,13 +849,17 @@ subsequent ECT. ## HTTP Error Handling When ECT verification fails during HTTP request processing, the -receiving agent SHOULD respond with HTTP 403 (Forbidden) if the -agent's identity credential is valid but the ECT is invalid, and -HTTP 401 (Unauthorized) if the ECT signature verification fails. -The response body SHOULD include a generic error indicator without -revealing which specific verification step failed. The receiving -agent MUST NOT process the requested action when ECT verification -fails. +receiving agent SHOULD respond with HTTP 403 (Forbidden). This +applies regardless of whether the failure is due to an invalid +ECT payload, a signature verification failure, or a missing ECT +when one is required by deployment policy. HTTP 401 +(Unauthorized) SHOULD NOT be used for ECT failures, as 401 +conventionally indicates that authentication credentials are +missing or invalid and requires a WWW-Authenticate header per +{{RFC9110}}. The response body SHOULD include a generic error +indicator without revealing which specific verification step +failed. The receiving agent MUST NOT process the requested +action when ECT verification fails. # DAG Validation {#dag-validation} @@ -861,12 +897,25 @@ the following DAG validation steps: 4. Acyclicity: Following the chain of parent references MUST NOT lead back to the current ECT's "jti". If a cycle is detected, - the ECT MUST be rejected. + the ECT MUST be rejected. Note: because the Parent Existence + check (step 2) requires that all parents already exist in the + ECT store, and an ECT cannot reference itself or a future ECT, + cycles are prevented by construction. This explicit check + serves as defense in depth against implementation errors or + store corruption. 5. Trust Domain Consistency: Parent tasks SHOULD belong to the same trust domain or to a trust domain with which a federation relationship has been established. +6. Workflow Consistency: When "wid" is present, verifiers SHOULD + validate that the "wid" of each parent ECT matches the "wid" + of the current ECT. Cross-workflow parent references (where + a parent's "wid" differs from the child's "wid") MUST be + rejected unless explicitly permitted by deployment policy. + See also {{collusion-and-false-claims}} for the security + rationale. + To prevent denial-of-service via extremely deep or wide DAGs, implementations SHOULD enforce a maximum ancestor traversal limit (RECOMMENDED: 10000 nodes). If the limit is reached before cycle @@ -1057,7 +1106,8 @@ revoked, the ECT MUST be rejected entirely and the failure MUST be logged. Implementations MUST use established JWS libraries and MUST NOT -implement custom signature verification. +implement custom signature verification. Implementations SHOULD +follow the JWT security best practices defined in {{RFC8725}}. The prohibition of "alg": "none" (see {{l2-verification}}) also serves as defense against level-confusion attacks: an L1 payload @@ -1150,7 +1200,18 @@ higher tolerance and SHOULD document the configured value. ## ECT Size Constraints Implementations SHOULD limit the "pred" array to a maximum of -256 entries. See {{extension-claims}} for "ext" size limits. +256 entries. See {{extension-claims}} for "ect_ext" size limits. + +When ECTs are transported via HTTP headers, the total encoded +size of the Execution-Context header value is subject to +practical limits imposed by HTTP servers and intermediaries. +Many implementations enforce header size limits of 8 KB or 16 KB. +Implementations SHOULD ensure that the total size of an ECT +(including JWS overhead for L2/L3) does not exceed 8 KB when +transported via HTTP header. ECTs that exceed HTTP header size +limits SHOULD be transported in the HTTP request body instead +(see {{l1-transport}} and {{l2-transport}}). Deployments SHOULD +monitor ECT sizes and alert when ECTs approach transport limits. ## Identity Binding Security @@ -1167,7 +1228,7 @@ configurable intervals (RECOMMENDED: no longer than 5 minutes). When identity is bound via X.509 certificates, revocation checking depends on OCSP responder or CRL distribution point availability. -If the revocation source is unreachable, the verifier must decide +If the revocation source is unreachable, the verifier needs to decide whether to accept or reject the ECT. Implementations SHOULD hard-fail for L3 (reject the ECT if revocation status cannot be determined), as L3 workflows require the strongest assurance. @@ -1247,7 +1308,7 @@ the privacy-relevant data but does not increase its scope. Implementations SHOULD minimize the information included in ECTs. The "exec_act" claim SHOULD use structured identifiers (e.g., "process_payment") rather than natural language descriptions. -Extension keys in "ext" ({{extension-claims}}) deserve particular +Extension keys in "ect_ext" ({{extension-claims}}) deserve particular attention: human-readable values risk exposing sensitive operational details. See {{extension-claims}} for guidance on using structured identifiers. @@ -1290,6 +1351,12 @@ cross-workflow correlation. This document requests registration of the following media types in the "Media Types" registry maintained by IANA: +Note: The media type "application/exec+jwt" uses the "+jwt" +structured syntax suffix. While "+jwt" is widely used in +practice, it is not yet a formally registered structured syntax +suffix per {{RFC6838}}. Registration of the "+jwt" suffix is +the subject of ongoing work in the IETF. + ### application/exec+jwt Type name: @@ -1430,7 +1497,7 @@ the "JSON Web Token Claims" registry maintained by IANA: | pred | Predecessor Task Identifiers | IETF | {{exec-claims}} | | inp_hash | Input Data Hash | IETF | {{data-integrity-claims}} | | out_hash | Output Data Hash | IETF | {{data-integrity-claims}} | -| ext | Extension Object | IETF | {{extension-claims}} | +| ect_ext | Extension Object | IETF | {{extension-claims}} | {: #table-claims title="JWT Claims Registrations"} --- back @@ -1698,7 +1765,7 @@ than operational monitoring. OpenTelemetry data is typically controlled by the platform operator and can be modified or deleted without detection. ECTs and distributed traces are complementary: traces provide observability while ECTs provide execution records. -ECTs may reference OpenTelemetry trace identifiers in the "ext" +ECTs may reference OpenTelemetry trace identifiers in the "ect_ext" claim for correlation. ## W3C Provenance Data Model (PROV) @@ -1748,6 +1815,20 @@ agents. ECTs could complement RATS by recording execution context on platforms whose trustworthiness has been established through RATS attestation. +## Emerging Agent Protocol Frameworks +{:numbered="false"} + +Several emerging frameworks address agent-to-agent communication, +including Google's Agent-to-Agent Protocol (A2A), Anthropic's +Model Context Protocol (MCP), and orchestration frameworks such +as LangChain and LangGraph. These frameworks primarily address +agent discovery, message routing, and tool invocation but do not +provide cryptographically verifiable execution records or DAG-based +audit trails. ECTs complement these frameworks by adding an +execution accountability layer: agents communicating via any of +these protocols can produce and verify ECTs to record what was +done, regardless of the communication mechanism used. + # Acknowledgments {:numbered="false"} diff --git a/refimpl/IMPROVEMENTS.md b/refimpl/IMPROVEMENTS.md index 7874fb7..0aab495 100644 --- a/refimpl/IMPROVEMENTS.md +++ b/refimpl/IMPROVEMENTS.md @@ -7,7 +7,7 @@ Suggestions that could make the implementations more robust, spec-strict, or pro ## 1. **Spec alignment** ✅ - **ext size/depth (Section 4.2.7)** - **Done.** Both refimpls reject when serialized `ext` exceeds 4096 bytes or JSON depth exceeds 5 (`ValidateExt` / `validate_ext`). Used in create and verify. + **Done.** Both refimpls reject when serialized `ect_ext` exceeds 4096 bytes or JSON depth exceeds 5 (`ValidateExt` / `validate_ext`). Used in create and verify. - **jti / wid format** **Done.** Optional UUID (RFC 9562) validation: `CreateOptions.ValidateUUIDs` / `VerifyOptions.ValidateUUIDs` (Go), `validate_uuids` (Python). Helpers: `ValidUUID` / `valid_uuid`. @@ -58,3 +58,18 @@ Suggestions that could make the implementations more robust, spec-strict, or pro --- **Summary:** All listed improvements are implemented. For production, also consider: key rotation, WIT integration, and metrics around verify/create latency and error kinds. + +--- + +## 6. **draft-01 migration** (NOT YET IMPLEMENTED) + +The refimpl was built against draft-nennemann-wimse-ect-00. The -01 draft introduced breaking changes that need to be reflected: + +- **Rename `par` to `pred`**: The predecessor claim was renamed. Update struct fields, JSON tags, serialization/deserialization, tests, and testdata. +- **Remove `pol` and `pol_decision`**: Policy claims were removed from the core spec. Deployments should use `ect_ext` for domain-specific claims like policy decisions. +- **Remove `sub`**: The `sub` claim is not part of the ECT specification. Remove from types and examples. +- **Update `typ` default**: Prefer `exec+jwt` over `wimse-exec+jwt`. Both must be accepted for backward compatibility. +- **Add L1 support**: The -01 draft introduces unsigned JSON ECTs (Level 1). The refimpl currently only supports L2 (signed JWS). +- **Add L3 support**: The -01 draft introduces audit ledger requirements for Level 3. The existing in-memory ledger needs hash chain and receipt support. +- **Update `MaxParLength` naming**: Rename to `MaxPredLength` to match the new claim name. +- **Update hash format**: The -01 draft specifies SHA-256 base64url without algorithm prefix (no `sha-256:` prefix), consistent with RFC 9449. diff --git a/refimpl/README.md b/refimpl/README.md index 0f581b1..ea16715 100644 --- a/refimpl/README.md +++ b/refimpl/README.md @@ -1,6 +1,18 @@ # WIMSE Execution Context Tokens — Reference Implementations -This directory contains **reference implementations** of [Execution Context Tokens (ECTs)](../draft-nennemann-wimse-execution-context-00.txt) for the WIMSE (Workload Identity in Multi System Environments) draft. Each refimpl provides ECT creation, verification, DAG validation, and an in-memory audit ledger. +> **Note**: These reference implementations were built against **draft-nennemann-wimse-ect-00**. +> The current draft (**-01**) introduced several claim name changes and structural updates: +> +> | -00 (refimpl) | -01 (current draft) | Notes | +> |---------------|---------------------|-------| +> | `par` | `pred` | Predecessor task IDs | +> | `pol`, `pol_decision` | removed (use `ect_ext`) | Policy claims moved to extension object | +> | `sub` | not defined | Standard JWT claim, not part of ECT spec | +> | `typ: wimse-exec+jwt` | `typ: exec+jwt` (preferred) | Both accepted for backward compat | +> +> The refimpl update to -01 is tracked in IMPROVEMENTS.md. + +This directory contains **reference implementations** of Execution Context Tokens (ECTs) for the WIMSE (Workload Identity in Multi System Environments) draft. Each refimpl provides ECT creation, verification, DAG validation, and an in-memory audit ledger. ## Implementations @@ -11,11 +23,11 @@ This directory contains **reference implementations** of [Execution Context Toke ## Scope (all refimpls) -- **ECT format**: JWT (JWS Compact Serialization) with required/optional claims per the spec (Section 4). -- **Creation**: Build and sign ECTs with ES256; `kid` and `typ: wimse-exec+jwt` in the JOSE header. -- **Verification**: Full Section 7 procedure (parse, typ/alg, key resolution, signature, claims, optional DAG). -- **DAG validation**: Section 6 (uniqueness, parent existence, temporal ordering, acyclicity, parent policy). -- **Ledger**: Interface plus in-memory append-only store (Section 9). +- **ECT format**: JWT (JWS Compact Serialization) with required/optional claims per the spec. +- **Creation**: Build and sign ECTs with ES256; `kid` and `typ` in the JOSE header. +- **Verification**: Full verification procedure (parse, typ/alg, key resolution, signature, claims, optional DAG). +- **DAG validation**: Uniqueness, parent existence, temporal ordering, acyclicity, parent policy. +- **Ledger**: Interface plus in-memory append-only store. No WIT/WPT issuance or full WIMSE stack; refimpls use key resolution only. Suitable for conformance testing and as a template for production integrations. @@ -41,8 +53,8 @@ python3 -m pytest tests/ -v ## Specification -- **Draft**: `draft-nennemann-wimse-execution-context-00` -- **Sections**: 4 (format), 5 (HTTP header), 6 (DAG), 7 (verification), 9 (ledger interface). +- **Current draft**: `draft-nennemann-wimse-ect-01` +- **Refimpl implements**: `-00` claim names (see migration note above) ## License