From db9d8e52c8dff02f713ae63d8c7a54309e3ec51a Mon Sep 17 00:00:00 2001
From: Christian Nennemann
10.2. Self-Assertion Limitation
+10.3. Organizational Prerequisites
@@ -2290,14 +2295,15 @@ hash algorithm identifier MUST be a lowercase value f IANA Named Information Hash Algorithm Registry (e.g., "sha-256", "sha-384", "sha-512"). Implementations MUST support "sha-256" and SHOULD use "sha-256" unless a stronger algorithm is -required. The hash MUST be computed over the raw octets of the -input data.¶ +required. Implementations MUST NOT accept hash algorithms +weaker than SHA-256 (e.g., MD5, SHA-1). The hash MUST be +computed over the raw octets of the input data.¶OPTIONAL. String. A cryptographic hash of the output data, -using the same format as "inp_hash".¶
+using the same format and algorithm requirements as "inp_hash".¶OPTIONAL. Array of StringOrURI. Identifiers of third-party -entities that observed or attested to the execution of this -task. When present, each element SHOULD use SPIFFE ID format. -In regulated environments, implementations SHOULD use witness -attestation for critical decision points to mitigate the risk -of single-agent false claims.¶
+entities that the issuing agent claims observed or attested to +the execution of this task. When present, each element SHOULD +use SPIFFE ID format. Note that this claim is self-asserted by +the ECT issuer; witnesses listed here do not co-sign this ECT. +For stronger assurance, witnesses SHOULD submit independent +signed ECTs to the ledger attesting to their observation (see +Section 10.2.1). In regulated environments, +implementations SHOULD use witness attestation for critical +decision points to mitigate the risk of single-agent false +claims. See also Section 10.2 for the security +implications of self-asserted witness claims.¶OPTIONAL. String. A human-readable reason for the compensation action. MUST be present if "compensation_required" is true. +Values SHOULD use structured identifiers (e.g., +"policy_violation_in_parent_trade") rather than free-form text +to minimize the risk of embedding sensitive information. See +Section 11.2 for privacy guidance. If "compensation_reason" is present, "compensation_required" MUST be true.¶
@@ -2402,7 +2418,12 @@ that do not understand extension claims MUST ignore tTo avoid key collisions between different domains, extension key names MUST use reverse domain notation (e.g., "com.example.custom_field"). Implementations MUST NOT use -unqualified key names within the "ext" object.¶
+unqualified key names within the "ext" object. To prevent +abuse and excessive token size, the serialized JSON +representation of the "ext" object SHOULD NOT exceed 4096 +bytes, and the JSON nesting depth within the "ext" object +SHOULD NOT exceed 5 levels. Implementations SHOULD reject +ECTs whose "ext" claim exceeds these limits.¶ @@ -2597,14 +2618,19 @@ function validate_dag(ect, ledger, clock_skew_tolerance): if parent.iat >= ect.iat + clock_skew_tolerance: return error("Parent task not earlier than current") - // Step 3: Cycle detection + // Step 3: Cycle detection (with traversal limit) visited = set() - if has_cycle(ect.tid, ect.par, ledger, visited): - return error("Circular dependency detected") + result = has_cycle(ect.tid, ect.par, ledger, visited, + max_ancestor_limit) + if result is error or result is true: + return error("Circular dependency or depth limit exceeded") return success -function has_cycle(target_tid, parent_ids, ledger, visited): +function has_cycle(target_tid, parent_ids, ledger, visited, + max_depth): + if visited.size() >= max_depth: + return error("Maximum ancestor traversal limit exceeded") for parent_id in parent_ids: if parent_id == target_tid: return true @@ -2613,8 +2639,10 @@ function has_cycle(target_tid, parent_ids, ledger, visited): visited.add(parent_id) parent = ledger.get(parent_id) if parent is not null: - if has_cycle(target_tid, parent.par, ledger, visited): - return true + result = has_cycle(target_tid, parent.par, ledger, + visited, max_depth) + if result is error or result is true: + return result return false @@ -2626,7 +2654,11 @@ function has_cycle(target_tid, parent_ids, ledger, visited): current task's parents. The complexity is O(V) where V is the number of ancestor nodes reachable from the current task's parent references. For typical workflows with shallow DAGs, this is -efficient. Implementations SHOULD cache cycle detection results +efficient. 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 detection completes, the ECT SHOULD be +rejected. Implementations SHOULD cache cycle detection results for previously verified tasks to avoid redundant traversals.¶ @@ -2665,43 +2697,52 @@ public key from a WIT within the trust domain.[RFC7515] Section 5.2.¶Verify the "alg" header parameter matches the algorithm in the -corresponding WIT.¶
+Verify that the signing key identified by "kid" has not been +revoked within the trust domain. Implementations MUST check +the key's revocation status using the trust domain's key +lifecycle mechanism (e.g., certificate revocation list, OCSP, +or SPIFFE trust bundle updates).¶
Verify the "iss" claim matches the "sub" claim of the WIT -associated with the "kid" public key.¶
+Verify the "alg" header parameter matches the algorithm in the +corresponding WIT.¶
Verify the "aud" claim contains the verifier's own workload +
Verify the "iss" claim matches the "sub" claim of the WIT +associated with the "kid" public key.¶
+Verify the "aud" claim contains the verifier's own workload identity. When "aud" is an array, it is sufficient that the verifier's identity appears as one element; the presence of other audience values does not cause verification failure. When the verifier is the audit ledger, the ledger's own -identity MUST appear in "aud".¶
-Verify the "exp" claim indicates the ECT has not expired.¶
+identity MUST appear in "aud".¶Verify the "iat" claim is not unreasonably far in the past -(implementation-specific threshold, RECOMMENDED maximum of -15 minutes).¶
+Verify the "exp" claim indicates the ECT has not expired.¶
Verify all required claims ("jti", "tid", "exec_act", "par", -"pol", "pol_decision") are present and well-formed.¶
+Verify the "iat" claim is not unreasonably far in the past +(implementation-specific threshold, RECOMMENDED maximum of +15 minutes) and is not unreasonably far in the future +(RECOMMENDED: no more than 30 seconds ahead of the +verifier's current time, to account for clock skew).¶
Verify "pol_decision" is one of "approved", "rejected", or -"pending_human_review".¶
+Verify all required claims ("jti", "tid", "exec_act", "par", +"pol", "pol_decision") are present and well-formed.¶
Perform DAG validation per Section 6.¶
+Verify "pol_decision" is one of "approved", "rejected", or +"pending_human_review".¶
If all checks pass, the ECT MUST be appended to the audit -ledger.¶
+ +If all checks pass, the ECT MUST be appended to the audit +ledger.¶
If any verification step fails, the ECT MUST be rejected and the @@ -2749,6 +2790,10 @@ function verify_ect(ect_jws, verifier_id, signature, public_key): return reject("Invalid signature") + // Verify key not revoked + if is_key_revoked(header.kid, trust_domain_keys): + return reject("Signing key has been revoked") + // Verify algorithm alignment wit = get_wit_for_key(header.kid) if header.alg != wit.alg: @@ -2766,9 +2811,11 @@ function verify_ect(ect_jws, verifier_id, if payload.exp < current_time(): return reject("ECT has expired") - // Verify iat freshness + // Verify iat freshness (not too old, not in the future) if payload.iat < current_time() - max_age_threshold: return reject("ECT issued too long ago") + if payload.iat > current_time() + clock_skew_tolerance: + return reject("ECT issued in the future") // Verify required claims for claim in ["jti", "tid", "exec_act", "par", @@ -2879,7 +2926,10 @@ workflow agents to reduce the risk of collusion.¶
+payload takes precedence. Implementations SHOULD validate that +convenience index fields match the corresponding values in the +JWS payload at write time to prevent desynchronization between +the authoritative JWS and the indexed fields.¶ @@ -3223,7 +3273,49 @@ evaluating the policy).¶ of the signing agent. To mitigate single-agent false claims, regulated environments SHOULD use the "witnessed_by" mechanism to include independent third-party observers at critical decision -points.¶ +points. However, the "witnessed_by" claim is self-asserted by +the ECT issuer: the listed witnesses do not co-sign the ECT and +there is no cryptographic proof within a single ECT that the +witnesses actually observed the task. An issuing agent could +list witnesses that did not participate.¶ +To address the self-assertion limitation of the "witnessed_by" +claim, witnesses SHOULD submit their own independent signed ECTs +to the audit ledger attesting to the observed task. A witness +attestation ECT:¶
+MUST set "iss" to the witness's own workload identity.¶
+MUST set "exec_act" to "witness_attestation" (or a domain- +specific equivalent).¶
+MUST include the observed task's "tid" in the "par" array, +linking the attestation to the original task.¶
+MUST set "pol_decision" to "approved" to indicate the witness +confirms the observation.¶
+When a task's "witnessed_by" claim lists one or more witnesses, +auditors SHOULD verify that corresponding witness attestation +ECTs exist in the ledger for each listed witness. A mismatch +between the "witnessed_by" list and the set of independent witness +ECTs in the ledger SHOULD be flagged during audit review.¶
+This model converts witness attestation from a self-asserted claim +to a cryptographically verifiable property of the ledger: the +witness independently signs their own ECT using their own key, +and the ledger records both the original task ECT and the witness +attestation ECTs.¶
+If signature verification fails, the ECT MUST be rejected entirely -and the failure MUST be logged.¶
+revoked within the trust domain (see step 6 in +Section 7).¶ +If signature verification fails or if the signing key has been +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.¶
@@ -3402,9 +3496,14 @@ Clock skew between agents can lead to incorrect ordering judgments. Implementations SHOULD use synchronized time sources (e.g., NTP) and SHOULD allow a configurable clock skew tolerance (RECOMMENDED: 30 seconds).¶ -The temporal ordering check in DAG validation incorporates the +
Cross-organizational deployments where agents span multiple trust +domains with independent time sources MAY require a higher clock +skew tolerance. Deployments using trust domain federation SHOULD +document their configured clock skew tolerance value and SHOULD +ensure all participating trust domains agree on a common tolerance.¶
+The temporal ordering check in DAG validation incorporates the clock skew tolerance to account for minor clock differences -between agents.¶
+between agents.¶ECTs with many parent tasks or large extension objects can increase HTTP header size. Implementations SHOULD limit the "par" -array to a reasonable size and SHOULD set maximum size limits for -the "ext" object to prevent abuse.¶
+array to a maximum of 256 entries. Workflows requiring more +parent references SHOULD introduce intermediate aggregation +tasks. The "ext" object SHOULD NOT exceed 4096 bytes when +serialized as JSON and SHOULD NOT exceed a nesting depth of +5 levels (see also Section 4.2.8).¶The "compensation_reason" claim (Section 4.2.7) +deserves particular attention: because it is human-readable and +may describe the circumstances of a failure or policy violation, +it risks exposing sensitive operational details. Implementations +SHOULD use short, structured reason codes (e.g., +"policy_violation_in_parent_trade") rather than free-form +natural language explanations. Implementers SHOULD review +"compensation_reason" values for potential information leakage +before deploying to production.¶