Remove duplicate RFC 2119/8174 refs and add compiled output
Remove RFC 2119 and RFC 8174 from normative YAML block since the BCP 14 boilerplate directive adds them automatically, causing duplicate reference warnings. Rebuild draft with zero warnings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ number:
|
||||
date:
|
||||
v: 3
|
||||
area: "Security"
|
||||
workgroup: "WIMSE"
|
||||
keyword:
|
||||
- execution context
|
||||
- workload identity
|
||||
@@ -23,9 +24,8 @@ author:
|
||||
email: ietf@nennemann.de
|
||||
|
||||
normative:
|
||||
RFC2119:
|
||||
RFC8174:
|
||||
RFC7515:
|
||||
RFC7517:
|
||||
RFC7519:
|
||||
RFC7518:
|
||||
RFC9562:
|
||||
@@ -35,7 +35,6 @@ normative:
|
||||
|
||||
informative:
|
||||
RFC3552:
|
||||
RFC7517:
|
||||
RFC8693:
|
||||
RFC9421:
|
||||
I-D.ni-wimse-ai-agent-identity:
|
||||
@@ -150,7 +149,7 @@ accountability. WIMSE authenticates agents; this extension records
|
||||
what they did, in what order, and what policy was evaluated.
|
||||
|
||||
As identified in {{I-D.ni-wimse-ai-agent-identity}}, call context
|
||||
in agentic workflows must always be visible and preserved. ECTs
|
||||
in agentic workflows needs to be visible and preserved. ECTs
|
||||
provide a mechanism to address this requirement with cryptographic
|
||||
assurances.
|
||||
|
||||
@@ -409,12 +408,39 @@ iss:
|
||||
|
||||
sub:
|
||||
: OPTIONAL. StringOrURI. The subject of the ECT. When present,
|
||||
MUST equal the "iss" claim.
|
||||
MUST equal the "iss" claim. This claim is included for
|
||||
compatibility with JWT libraries and frameworks that expect a
|
||||
"sub" claim to be present.
|
||||
|
||||
aud:
|
||||
: REQUIRED. StringOrURI or array of StringOrURI. The intended
|
||||
recipient(s) of the ECT. Typically the next agent in the
|
||||
workflow or the ledger endpoint.
|
||||
recipient(s) of the ECT. Because ECTs serve as both inter-agent
|
||||
messages and audit records, the "aud" claim SHOULD contain the
|
||||
identifiers of all entities that will verify the ECT. In
|
||||
practice this means:
|
||||
|
||||
* **Point-to-point delivery**: when an ECT is sent from one
|
||||
agent to a single next agent, "aud" contains that agent's
|
||||
workload identity. The receiving agent verifies the ECT and
|
||||
forwards it to the ledger on behalf of the issuer.
|
||||
|
||||
* **Direct-to-ledger submission**: when an ECT is submitted
|
||||
directly to the audit ledger (e.g., after a join or at
|
||||
workflow completion), "aud" contains the ledger's identity.
|
||||
|
||||
* **Multi-audience**: when an ECT must be verified by both the
|
||||
next agent and the ledger independently, "aud" MUST be an
|
||||
array containing both identifiers (e.g.,
|
||||
\["spiffe://example.com/agent/next",
|
||||
"spiffe://example.com/system/ledger"\]). Each verifier checks
|
||||
that its own identity appears in the array.
|
||||
|
||||
In multi-parent (join) scenarios where a task depends on ECTs
|
||||
from multiple parent agents, the joining agent creates a new ECT
|
||||
with the parent task IDs in "par". The "aud" of this new ECT
|
||||
is set according to the rules above based on where the ECT will
|
||||
be delivered — it is independent of the "aud" values in the
|
||||
parent ECTs.
|
||||
|
||||
iat:
|
||||
: REQUIRED. NumericDate. The time at which the ECT was issued.
|
||||
@@ -427,9 +453,16 @@ exp:
|
||||
to limit the replay window while allowing for reasonable clock
|
||||
skew and processing time.
|
||||
|
||||
The standard JWT "nbf" (Not Before) claim is not used in ECTs
|
||||
because ECTs record completed actions and are valid immediately
|
||||
upon issuance.
|
||||
|
||||
jti:
|
||||
: OPTIONAL. String. A unique identifier for the ECT, useful for
|
||||
additional replay detection.
|
||||
: REQUIRED. String. A unique identifier for the ECT in UUID
|
||||
format {{RFC9562}}. Used for replay detection: receivers MUST
|
||||
reject ECTs whose "jti" has already been seen within the
|
||||
expiration window. The "jti" value MUST be unique across all
|
||||
ECTs issued by the same agent.
|
||||
|
||||
### Execution Context Claims {#exec-claims}
|
||||
|
||||
@@ -474,7 +507,26 @@ pol:
|
||||
|
||||
pol_decision:
|
||||
: REQUIRED. String. The result of the policy evaluation. MUST
|
||||
be one of: "approved", "rejected", or "pending_human_review".
|
||||
be one of the values registered in the ECT Policy Decision
|
||||
Values registry ({{pol-decision-registry}}). Initial values
|
||||
are:
|
||||
|
||||
* "approved": The policy evaluation succeeded and the task
|
||||
was authorized to proceed.
|
||||
|
||||
* "rejected": The policy evaluation failed. A "rejected" ECT
|
||||
MUST still be appended to the audit ledger for accountability.
|
||||
An ECT with "pol_decision" of "rejected" MAY appear as a
|
||||
parent in the "par" array of a subsequent ECT, but only for
|
||||
compensation, rollback, or remediation tasks. Agents MUST
|
||||
NOT proceed with normal workflow execution based on a parent
|
||||
ECT whose "pol_decision" is "rejected".
|
||||
|
||||
* "pending_human_review": The policy evaluation requires human
|
||||
judgment before proceeding. Agents MUST NOT proceed with
|
||||
dependent tasks until a subsequent ECT from a human reviewer
|
||||
records an "approved" decision referencing this task as a
|
||||
parent.
|
||||
|
||||
pol_enforcer:
|
||||
: OPTIONAL. StringOrURI. The identity of the entity (system or
|
||||
@@ -495,12 +547,17 @@ inp_hash:
|
||||
: OPTIONAL. String. A cryptographic hash of the input data,
|
||||
formatted as "hash-algorithm:base64url-encoded-hash" (e.g.,
|
||||
"sha-256:n4bQgYhMfWWaL-qgxVrQFaO\_TxsrC4Is0V1sFbDwCgg"). The
|
||||
hash algorithm identifier SHOULD be "sha-256". The hash MUST be
|
||||
hash algorithm identifier MUST be a lowercase value from the
|
||||
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. 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.
|
||||
|
||||
out_hash:
|
||||
: 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".
|
||||
|
||||
inp_classification:
|
||||
: OPTIONAL. String. The data sensitivity classification of the
|
||||
@@ -516,8 +573,8 @@ exec_time_ms:
|
||||
|
||||
regulated_domain:
|
||||
: OPTIONAL. String. The regulatory domain applicable to this
|
||||
task. Values are drawn from an extensible set; initial values
|
||||
include "medtech", "finance", and "military".
|
||||
task. Values MUST be registered in the ECT Regulated Domain
|
||||
Values registry ({{regulated-domain-registry}}).
|
||||
|
||||
model_version:
|
||||
: OPTIONAL. String. The version identifier of the AI or ML model
|
||||
@@ -527,11 +584,17 @@ model_version:
|
||||
|
||||
witnessed_by:
|
||||
: 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
|
||||
{{witness-attestation-model}}). In regulated environments,
|
||||
implementations SHOULD use witness attestation for critical
|
||||
decision points to mitigate the risk of single-agent false
|
||||
claims. See also {{self-assertion-limitation}} for the security
|
||||
implications of self-asserted witness claims.
|
||||
|
||||
### Compensation Claims {#compensation-claims}
|
||||
|
||||
@@ -542,6 +605,12 @@ compensation_required:
|
||||
compensation_reason:
|
||||
: 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
|
||||
{{data-minimization}} for privacy guidance.
|
||||
If "compensation_reason" is present, "compensation_required"
|
||||
MUST be true.
|
||||
|
||||
Note: compensation ECTs reference historical parent tasks via the
|
||||
"par" claim. The referenced parent ECTs may have passed their own
|
||||
@@ -554,14 +623,17 @@ ledger.
|
||||
ext:
|
||||
: OPTIONAL. Object. An extension object for domain-specific
|
||||
claims not defined by this specification. Implementations
|
||||
that do not understand extension claims SHOULD ignore them.
|
||||
To avoid key collisions between different domains, extension
|
||||
key names SHOULD use reverse domain notation (e.g.,
|
||||
"com.example.custom_field").
|
||||
that do not understand extension claims MUST ignore them.
|
||||
|
||||
The "ext" claim is a generic extension mechanism; it is not
|
||||
registered in the IANA JWT Claims registry because its semantics
|
||||
depend on the domain-specific claims within it.
|
||||
To 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. 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.
|
||||
|
||||
## Complete ECT Example
|
||||
|
||||
@@ -574,6 +646,7 @@ The following is a complete ECT payload example:
|
||||
"aud": "spiffe://example.com/agent/safety",
|
||||
"iat": 1772064150,
|
||||
"exp": 1772064750,
|
||||
"jti": "7f3a8b2c-d1e4-4f56-9a0b-c3d4e5f6a7b8",
|
||||
|
||||
"wid": "a0b1c2d3-e4f5-6789-abcd-ef0123456789",
|
||||
"tid": "550e8400-e29b-41d4-a716-446655440001",
|
||||
@@ -627,6 +700,14 @@ When multiple parent tasks contribute context to a single request,
|
||||
multiple Execution-Context header field lines MAY be included, each
|
||||
carrying a separate ECT in JWS Compact Serialization format.
|
||||
|
||||
When a receiver processes multiple Execution-Context headers, it
|
||||
MUST individually verify each ECT per the procedure in
|
||||
{{verification}}. If any single ECT fails verification, the
|
||||
receiver MUST reject the entire request. The set of verified
|
||||
parent task IDs across all received ECTs represents the complete
|
||||
set of parent dependencies available for the receiving agent's
|
||||
subsequent ECT.
|
||||
|
||||
# DAG Validation {#dag-validation}
|
||||
|
||||
## Overview
|
||||
@@ -653,17 +734,30 @@ the following DAG validation steps:
|
||||
recorded in the ledger. If any parent task is not found, the
|
||||
ECT MUST be rejected.
|
||||
|
||||
3. Temporal Ordering: The "iat" value of every parent task MUST be
|
||||
less than the "iat" value of the current task plus a
|
||||
3. Temporal Ordering: The "iat" value of every parent task MUST
|
||||
NOT be greater than the "iat" value of the current task plus a
|
||||
configurable clock skew tolerance (RECOMMENDED: 30 seconds).
|
||||
If any parent task has an "iat" that violates this constraint,
|
||||
the ECT MUST be rejected.
|
||||
That is, for each parent: `parent.iat < child.iat +
|
||||
clock_skew_tolerance`. The tolerance accounts for clock skew
|
||||
between agents; it does not guarantee strict causal ordering
|
||||
from timestamps alone. Causal ordering is primarily enforced
|
||||
by the DAG structure (parent existence in the ledger), not by
|
||||
timestamps. If any parent task violates this constraint, the
|
||||
ECT MUST be rejected.
|
||||
|
||||
4. Acyclicity: Following the chain of parent references MUST NOT
|
||||
lead back to the current task's "tid". If a cycle is detected,
|
||||
the ECT MUST be rejected.
|
||||
|
||||
5. Trust Domain Consistency: Parent tasks SHOULD belong to the
|
||||
5. Parent Policy Decision: If any parent task has a "pol_decision"
|
||||
of "rejected" or "pending_human_review", the current task's
|
||||
"exec_act" MUST indicate a compensation, rollback, remediation,
|
||||
or human review action. Implementations MUST NOT accept an ECT
|
||||
representing normal workflow continuation when a parent's
|
||||
"pol_decision" is not "approved", unless the current ECT has
|
||||
"compensation_required" set to true.
|
||||
|
||||
6. 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.
|
||||
|
||||
@@ -685,14 +779,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
|
||||
@@ -701,8 +800,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
|
||||
~~~
|
||||
{: #fig-dag-validation title="DAG Validation Pseudocode"}
|
||||
@@ -711,7 +812,11 @@ The cycle detection traverses the ancestor graph rooted at the
|
||||
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.
|
||||
|
||||
# Signature and Token Verification {#verification}
|
||||
@@ -735,30 +840,42 @@ verification steps in order:
|
||||
5. Retrieve the public key identified by "kid" and verify the JWS
|
||||
signature per {{RFC7515}} Section 5.2.
|
||||
|
||||
6. Verify the "alg" header parameter matches the algorithm in the
|
||||
6. 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).
|
||||
|
||||
7. Verify the "alg" header parameter matches the algorithm in the
|
||||
corresponding WIT.
|
||||
|
||||
7. Verify the "iss" claim matches the "sub" claim of the WIT
|
||||
8. Verify the "iss" claim matches the "sub" claim of the WIT
|
||||
associated with the "kid" public key.
|
||||
|
||||
8. Verify the "aud" claim contains the verifier's own workload
|
||||
identity or an expected recipient identifier.
|
||||
9. 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".
|
||||
|
||||
9. Verify the "exp" claim indicates the ECT has not expired.
|
||||
10. Verify the "exp" claim indicates the ECT has not expired.
|
||||
|
||||
10. Verify the "iat" claim is not unreasonably far in the past
|
||||
11. Verify the "iat" claim is not unreasonably far in the past
|
||||
(implementation-specific threshold, RECOMMENDED maximum of
|
||||
15 minutes).
|
||||
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).
|
||||
|
||||
11. Verify all required claims ("tid", "exec_act", "par", "pol",
|
||||
"pol_decision") are present and well-formed.
|
||||
12. Verify all required claims ("jti", "tid", "exec_act", "par",
|
||||
"pol", "pol_decision") are present and well-formed.
|
||||
|
||||
12. Verify "pol_decision" is one of "approved", "rejected", or
|
||||
13. Verify "pol_decision" is one of "approved", "rejected", or
|
||||
"pending_human_review".
|
||||
|
||||
13. Perform DAG validation per {{dag-validation}}.
|
||||
14. Perform DAG validation per {{dag-validation}}.
|
||||
|
||||
14. If all checks pass, the ECT MUST be appended to the audit
|
||||
15. 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
|
||||
@@ -766,6 +883,15 @@ failure MUST be logged for audit purposes. Error messages
|
||||
SHOULD NOT reveal whether specific parent task IDs exist in the
|
||||
ledger, to prevent information disclosure.
|
||||
|
||||
When ECT verification fails during HTTP request processing, the
|
||||
receiving agent SHOULD respond with HTTP 403 (Forbidden) if the
|
||||
WIT and WPT are 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.
|
||||
|
||||
## Verification Pseudocode
|
||||
|
||||
~~~ pseudocode
|
||||
@@ -791,6 +917,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:
|
||||
@@ -808,12 +938,14 @@ 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 ["tid", "exec_act", "par",
|
||||
for claim in ["jti", "tid", "exec_act", "par",
|
||||
"pol", "pol_decision"]:
|
||||
if claim not in payload:
|
||||
return reject("Missing required claim: " + claim)
|
||||
@@ -890,7 +1022,10 @@ The "ect_jws" field contains the full JWS Compact Serialization
|
||||
and is the authoritative record. The other fields ("agent_id",
|
||||
"action", "parents") are convenience indexes derived from the
|
||||
ECT payload; if they disagree with the JWS payload, the JWS
|
||||
payload takes precedence.
|
||||
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.
|
||||
|
||||
# Use Cases {#use-cases}
|
||||
|
||||
@@ -901,8 +1036,8 @@ include additional domain-specific requirements beyond the scope
|
||||
of this specification.
|
||||
|
||||
Note: task identifiers in this section are abbreviated for
|
||||
readability. In production, all "tid" values MUST be UUIDs per
|
||||
{{RFC9562}}.
|
||||
readability. In production, all "tid" values are required to be
|
||||
UUIDs per {{exec-claims}}.
|
||||
|
||||
## Medical Device SDLC Workflow
|
||||
|
||||
@@ -1059,7 +1194,7 @@ violation discovery to remediation.
|
||||
|
||||
## Autonomous Logistics Coordination
|
||||
|
||||
In a logistics workflow, multiple compliance checks must complete
|
||||
In a logistics workflow, multiple compliance checks complete
|
||||
before shipment commitment. The DAG structure records that all
|
||||
required checks were completed:
|
||||
|
||||
@@ -1113,7 +1248,7 @@ The following threat actors are considered:
|
||||
- Time manipulator: An entity attempting to manipulate timestamps
|
||||
to alter perceived execution ordering.
|
||||
|
||||
## Self-Assertion Limitation
|
||||
## Self-Assertion Limitation {#self-assertion-limitation}
|
||||
|
||||
ECTs are self-asserted by the executing agent. The agent claims
|
||||
what it did, and this claim is signed with its private key. A
|
||||
@@ -1132,7 +1267,38 @@ The trustworthiness of ECT claims depends on the trustworthiness
|
||||
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.
|
||||
|
||||
### Witness Attestation Model {#witness-attestation-model}
|
||||
|
||||
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.
|
||||
|
||||
## Organizational Prerequisites
|
||||
|
||||
@@ -1156,10 +1322,12 @@ ECTs MUST be signed with the agent's private key using JWS
|
||||
specified in the agent's WIT. Receivers MUST verify the ECT
|
||||
signature against the WIT public key before processing any
|
||||
claims. Receivers MUST verify that the signing key has not been
|
||||
revoked within the trust domain.
|
||||
revoked within the trust domain (see step 6 in
|
||||
{{verification}}).
|
||||
|
||||
If signature verification fails, the ECT MUST be rejected entirely
|
||||
and the failure MUST be logged.
|
||||
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.
|
||||
@@ -1176,9 +1344,9 @@ The DAG structure provides additional replay protection: an ECT
|
||||
referencing parent tasks that already have a recorded child task
|
||||
with the same action can be flagged as a potential replay.
|
||||
|
||||
Implementations SHOULD maintain a cache of recently-seen "jti"
|
||||
values (when present) to detect replayed ECTs within the
|
||||
expiration window.
|
||||
Implementations MUST maintain a cache of recently-seen "jti"
|
||||
values to detect replayed ECTs within the expiration window.
|
||||
An ECT with a duplicate "jti" value MUST be rejected.
|
||||
|
||||
## Man-in-the-Middle Protection
|
||||
|
||||
@@ -1254,6 +1422,12 @@ judgments. Implementations SHOULD use synchronized time sources
|
||||
(e.g., NTP) and SHOULD allow a configurable clock skew tolerance
|
||||
(RECOMMENDED: 30 seconds).
|
||||
|
||||
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.
|
||||
@@ -1262,8 +1436,11 @@ 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 {{extension-claims}}).
|
||||
|
||||
# Privacy Considerations
|
||||
|
||||
@@ -1285,7 +1462,7 @@ ECTs are designed to NOT reveal:
|
||||
- Proprietary algorithms or intellectual property
|
||||
- Personally identifiable information (PII)
|
||||
|
||||
## Data Minimization
|
||||
## Data Minimization {#data-minimization}
|
||||
|
||||
Implementations SHOULD minimize the information included in ECTs.
|
||||
The "exec_act" claim SHOULD use structured identifiers (e.g.,
|
||||
@@ -1293,6 +1470,16 @@ The "exec_act" claim SHOULD use structured identifiers (e.g.,
|
||||
The "pol" claim SHOULD reference policy identifiers rather than
|
||||
embedding policy content.
|
||||
|
||||
The "compensation_reason" claim ({{compensation-claims}})
|
||||
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.
|
||||
|
||||
## Storage and Access Control
|
||||
|
||||
ECTs stored in audit ledgers SHOULD be access-controlled so that
|
||||
@@ -1408,8 +1595,39 @@ the "JSON Web Token Claims" registry maintained by IANA:
|
||||
| model_version | AI/ML Model Version | IETF | {{operational-claims}} |
|
||||
| compensation_required | Compensation Flag | IETF | {{compensation-claims}} |
|
||||
| compensation_reason | Compensation Reason | IETF | {{compensation-claims}} |
|
||||
| ext | Extension Object | IETF | {{extension-claims}} |
|
||||
{: #table-claims title="JWT Claims Registrations"}
|
||||
|
||||
## ECT Policy Decision Values Registry {#pol-decision-registry}
|
||||
|
||||
This document establishes the "ECT Policy Decision Values"
|
||||
registry under the "JSON Web Token (JWT)" group. Registration
|
||||
policy is Specification Required per {{!RFC8126}}.
|
||||
|
||||
The initial contents of the registry are:
|
||||
|
||||
| Value | Description | Change Controller | Reference |
|
||||
|:---:|:---|:---:|:---:|
|
||||
| approved | Policy evaluation succeeded | IETF | {{policy-claims}} |
|
||||
| rejected | Policy evaluation failed | IETF | {{policy-claims}} |
|
||||
| pending_human_review | Awaiting human judgment | IETF | {{policy-claims}} |
|
||||
{: #table-pol-decision title="ECT Policy Decision Values"}
|
||||
|
||||
## ECT Regulated Domain Values Registry {#regulated-domain-registry}
|
||||
|
||||
This document establishes the "ECT Regulated Domain Values"
|
||||
registry under the "JSON Web Token (JWT)" group. Registration
|
||||
policy is Specification Required per {{!RFC8126}}.
|
||||
|
||||
The initial contents of the registry are:
|
||||
|
||||
| Value | Description | Change Controller | Reference |
|
||||
|:---:|:---|:---:|:---:|
|
||||
| medtech | Medical technology and devices | IETF | {{operational-claims}} |
|
||||
| finance | Financial services and trading | IETF | {{operational-claims}} |
|
||||
| military | Military and defense | IETF | {{operational-claims}} |
|
||||
{: #table-regulated-domain title="ECT Regulated Domain Values"}
|
||||
|
||||
--- back
|
||||
|
||||
# Related Work
|
||||
@@ -1499,10 +1717,11 @@ use cases are distinct.
|
||||
## Minimal Implementation
|
||||
{:numbered="false"}
|
||||
|
||||
A minimal conforming implementation should:
|
||||
A minimal conforming implementation needs to:
|
||||
|
||||
1. Create JWTs with all required claims ("iss", "aud", "iat",
|
||||
"exp", "tid", "exec_act", "par", "pol", "pol_decision").
|
||||
"exp", "jti", "tid", "exec_act", "par", "pol",
|
||||
"pol_decision").
|
||||
2. Sign ECTs with the agent's private key using an algorithm
|
||||
matching the WIT (ES256 recommended).
|
||||
3. Verify ECT signatures against WIT public keys.
|
||||
@@ -1536,10 +1755,11 @@ A minimal conforming implementation should:
|
||||
## Interoperability
|
||||
{:numbered="false"}
|
||||
|
||||
Implementations should use established JWT/JWS libraries (JOSE)
|
||||
for token creation and verification. Custom cryptographic
|
||||
implementations should not be used. Implementations should be
|
||||
tested against multiple JWT libraries to ensure interoperability.
|
||||
Implementations are expected to use established JWT/JWS libraries
|
||||
(JOSE) for token creation and verification. Custom cryptographic
|
||||
implementations are strongly discouraged. Implementations are
|
||||
expected to be tested against multiple JWT libraries to ensure
|
||||
interoperability.
|
||||
|
||||
# Regulatory Compliance Mapping
|
||||
{:numbered="false"}
|
||||
|
||||
Reference in New Issue
Block a user