Remove non-protocol claims and make ledger optional
Move 6 metadata claims (pol_timestamp, inp_classification, exec_time_ms, regulated_domain, model_version, witnessed_by) from registered JWT claims to recommended ext extension keys. Use short key names for spec-defined extensions. Make audit ledger explicitly optional: rename pseudocode parameter from ledger to ect_store, mark architecture diagram ledger layer as optional, add conditional append logic, and soften Audit Ledger Interface language. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1906,8 +1906,8 @@ between the identity layer and the application layer:<a href="#section-3.2-1" cl
|
|||||||
|
|
|
|
||||||
v
|
v
|
||||||
+--------------------------------------------------+
|
+--------------------------------------------------+
|
||||||
| Ledger Layer (Immutable Record) |
|
| Optional: Audit Ledger (Immutable Record) |
|
||||||
| "All ECTs appended to audit ledger" |
|
| "ECTs MAY be appended to an audit ledger" |
|
||||||
+--------------------------------------------------+
|
+--------------------------------------------------+
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
@@ -1978,7 +1978,8 @@ trust domain. WPT verification, if present, per
|
|||||||
evaluated, and what precedent tasks exist.<a href="#section-3.3-7.2.1" class="pilcrow">¶</a></p>
|
evaluated, and what precedent tasks exist.<a href="#section-3.3-7.2.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li id="section-3.3-7.3">
|
<li id="section-3.3-7.3">
|
||||||
<p id="section-3.3-7.3.1">Ledger: Appends the verified ECT to the audit ledger.<a href="#section-3.3-7.3.1" class="pilcrow">¶</a></p>
|
<p id="section-3.3-7.3.1">Ledger (if deployed): Appends the verified ECT to the audit
|
||||||
|
ledger.<a href="#section-3.3-7.3.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
@@ -2329,42 +2330,41 @@ that do not understand extension claims <span class="bcp14">MUST</span> ignore t
|
|||||||
<dd class="break"></dd>
|
<dd class="break"></dd>
|
||||||
</dl>
|
</dl>
|
||||||
<p id="section-4.2.6-2">To avoid key collisions between different domains, extension
|
<p id="section-4.2.6-2">To avoid key collisions between different domains, extension
|
||||||
key names <span class="bcp14">MUST</span> use reverse domain notation (e.g.,
|
key names <span class="bcp14">SHOULD</span> use reverse domain notation (e.g.,
|
||||||
"com.example.custom_field"). Implementations <span class="bcp14">MUST NOT</span> use
|
"com.example.custom_field") to avoid collisions between
|
||||||
unqualified key names within the "ext" object. To prevent
|
independently developed extensions. To prevent abuse and
|
||||||
abuse and excessive token size, the serialized JSON
|
excessive token size, the serialized JSON representation of
|
||||||
representation of the "ext" object <span class="bcp14">SHOULD NOT</span> exceed 4096
|
the "ext" object <span class="bcp14">SHOULD NOT</span> exceed 4096 bytes, and the JSON
|
||||||
bytes, and the JSON nesting depth within the "ext" object
|
nesting depth within the "ext" object <span class="bcp14">SHOULD NOT</span> exceed 5
|
||||||
<span class="bcp14">SHOULD NOT</span> exceed 5 levels. Implementations <span class="bcp14">SHOULD</span> reject
|
levels. Implementations <span class="bcp14">SHOULD</span> reject ECTs whose "ext" claim
|
||||||
ECTs whose "ext" claim exceeds these limits.<a href="#section-4.2.6-2" class="pilcrow">¶</a></p>
|
exceeds these limits.<a href="#section-4.2.6-2" class="pilcrow">¶</a></p>
|
||||||
<p id="section-4.2.6-3">The following extension keys are <span class="bcp14">RECOMMENDED</span> for common use
|
<p id="section-4.2.6-3">The following extension keys are defined by this specification
|
||||||
cases. These are not registered claims; they are carried
|
for common use cases. Because these keys are documented here,
|
||||||
within the "ext" object:<a href="#section-4.2.6-3" class="pilcrow">¶</a></p>
|
they use short names without reverse domain prefixes:<a href="#section-4.2.6-3" class="pilcrow">¶</a></p>
|
||||||
<ul class="normal">
|
<ul class="normal">
|
||||||
<li class="normal" id="section-4.2.6-4.1">
|
<li class="normal" id="section-4.2.6-4.1">
|
||||||
<p id="section-4.2.6-4.1.1">"org.ietf.wimse.exec_time_ms": Integer. Execution duration in
|
<p id="section-4.2.6-4.1.1">"exec_time_ms": Integer. Execution duration in milliseconds.<a href="#section-4.2.6-4.1.1" class="pilcrow">¶</a></p>
|
||||||
milliseconds.<a href="#section-4.2.6-4.1.1" class="pilcrow">¶</a></p>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="normal" id="section-4.2.6-4.2">
|
<li class="normal" id="section-4.2.6-4.2">
|
||||||
<p id="section-4.2.6-4.2.1">"org.ietf.wimse.regulated_domain": String. Regulatory domain
|
<p id="section-4.2.6-4.2.1">"regulated_domain": String. Regulatory domain (e.g.,
|
||||||
(e.g., "medtech", "finance", "military").<a href="#section-4.2.6-4.2.1" class="pilcrow">¶</a></p>
|
"medtech", "finance", "military").<a href="#section-4.2.6-4.2.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li class="normal" id="section-4.2.6-4.3">
|
<li class="normal" id="section-4.2.6-4.3">
|
||||||
<p id="section-4.2.6-4.3.1">"org.ietf.wimse.model_version": String. AI/ML model version.<a href="#section-4.2.6-4.3.1" class="pilcrow">¶</a></p>
|
<p id="section-4.2.6-4.3.1">"model_version": String. AI/ML model version.<a href="#section-4.2.6-4.3.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li class="normal" id="section-4.2.6-4.4">
|
<li class="normal" id="section-4.2.6-4.4">
|
||||||
<p id="section-4.2.6-4.4.1">"org.ietf.wimse.witnessed_by": Array of StringOrURI. Identifiers
|
<p id="section-4.2.6-4.4.1">"witnessed_by": Array of StringOrURI. Identifiers of
|
||||||
of third-party entities that the issuer claims observed the
|
third-party entities that the issuer claims observed the
|
||||||
task. Note: this is self-asserted; for verifiable witness
|
task. Note: this is self-asserted; for verifiable witness
|
||||||
attestation, witnesses should submit independent signed ECTs.<a href="#section-4.2.6-4.4.1" class="pilcrow">¶</a></p>
|
attestation, witnesses should submit independent signed ECTs.<a href="#section-4.2.6-4.4.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li class="normal" id="section-4.2.6-4.5">
|
<li class="normal" id="section-4.2.6-4.5">
|
||||||
<p id="section-4.2.6-4.5.1">"org.ietf.wimse.inp_classification": String. Data sensitivity
|
<p id="section-4.2.6-4.5.1">"inp_classification": String. Data sensitivity classification
|
||||||
classification (e.g., "public", "confidential", "restricted").<a href="#section-4.2.6-4.5.1" class="pilcrow">¶</a></p>
|
(e.g., "public", "confidential", "restricted").<a href="#section-4.2.6-4.5.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li class="normal" id="section-4.2.6-4.6">
|
<li class="normal" id="section-4.2.6-4.6">
|
||||||
<p id="section-4.2.6-4.6.1">"org.ietf.wimse.pol_timestamp": NumericDate. Time at which the
|
<p id="section-4.2.6-4.6.1">"pol_timestamp": NumericDate. Time at which the policy
|
||||||
policy decision was made, if distinct from "iat".<a href="#section-4.2.6-4.6.1" class="pilcrow">¶</a></p>
|
decision was made, if distinct from "iat".<a href="#section-4.2.6-4.6.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
@@ -2401,10 +2401,10 @@ policy decision was made, if distinct from "iat".<a href="#section-4.2.6-4.6.1"
|
|||||||
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
|
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
|
||||||
|
|
||||||
"ext": {
|
"ext": {
|
||||||
"org.ietf.wimse.pol_timestamp": 1772064145,
|
"pol_timestamp": 1772064145,
|
||||||
"org.ietf.wimse.exec_time_ms": 245,
|
"exec_time_ms": 245,
|
||||||
"org.ietf.wimse.regulated_domain": "medtech",
|
"regulated_domain": "medtech",
|
||||||
"org.ietf.wimse.model_version": "clinical-reasoning-v4.2"
|
"model_version": "clinical-reasoning-v4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@@ -2479,8 +2479,8 @@ provides a cryptographically signed record of execution ordering,
|
|||||||
enabling auditors to reconstruct the complete workflow and verify
|
enabling auditors to reconstruct the complete workflow and verify
|
||||||
that required predecessor tasks were recorded before dependent
|
that required predecessor tasks were recorded before dependent
|
||||||
tasks.<a href="#section-6.1-1" class="pilcrow">¶</a></p>
|
tasks.<a href="#section-6.1-1" class="pilcrow">¶</a></p>
|
||||||
<p id="section-6.1-2">DAG validation is performed against the audit ledger, which
|
<p id="section-6.1-2">DAG validation is performed against the ECT store — either an
|
||||||
serves as the authoritative store of previously verified ECTs.<a href="#section-6.1-2" class="pilcrow">¶</a></p>
|
audit ledger or the set of parent ECTs received inline.<a href="#section-6.1-2" class="pilcrow">¶</a></p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div id="validation-rules">
|
<div id="validation-rules">
|
||||||
@@ -2549,14 +2549,14 @@ relationship has been established.<a href="#section-6.2-2.6.1" class="pilcrow">
|
|||||||
<figure id="figure-6">
|
<figure id="figure-6">
|
||||||
<div class="lang-pseudocode sourcecode" id="section-6.3-2.1">
|
<div class="lang-pseudocode sourcecode" id="section-6.3-2.1">
|
||||||
<pre>
|
<pre>
|
||||||
function validate_dag(ect, ledger, clock_skew_tolerance):
|
function validate_dag(ect, ect_store, clock_skew_tolerance):
|
||||||
// Step 1: Uniqueness check
|
// Step 1: Uniqueness check
|
||||||
if ledger.contains(ect.jti, ect.wid):
|
if ect_store.contains(ect.jti, ect.wid):
|
||||||
return error("ECT ID already exists")
|
return error("ECT ID already exists")
|
||||||
|
|
||||||
// Step 2: Parent existence and temporal ordering
|
// Step 2: Parent existence and temporal ordering
|
||||||
for parent_id in ect.par:
|
for parent_id in ect.par:
|
||||||
parent = ledger.get(parent_id)
|
parent = ect_store.get(parent_id)
|
||||||
if parent is null:
|
if parent is null:
|
||||||
return error("Parent task not found: " + parent_id)
|
return error("Parent task not found: " + parent_id)
|
||||||
if parent.iat >= ect.iat + clock_skew_tolerance:
|
if parent.iat >= ect.iat + clock_skew_tolerance:
|
||||||
@@ -2564,14 +2564,14 @@ function validate_dag(ect, ledger, clock_skew_tolerance):
|
|||||||
|
|
||||||
// Step 3: Cycle detection (with traversal limit)
|
// Step 3: Cycle detection (with traversal limit)
|
||||||
visited = set()
|
visited = set()
|
||||||
result = has_cycle(ect.jti, ect.par, ledger, visited,
|
result = has_cycle(ect.jti, ect.par, ect_store, visited,
|
||||||
max_ancestor_limit)
|
max_ancestor_limit)
|
||||||
if result is error or result is true:
|
if result is error or result is true:
|
||||||
return error("Circular dependency or depth limit exceeded")
|
return error("Circular dependency or depth limit exceeded")
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
function has_cycle(target_jti, parent_ids, ledger,
|
function has_cycle(target_jti, parent_ids, ect_store,
|
||||||
visited, max_depth):
|
visited, max_depth):
|
||||||
if visited.size() >= max_depth:
|
if visited.size() >= max_depth:
|
||||||
return error("Maximum ancestor traversal limit exceeded")
|
return error("Maximum ancestor traversal limit exceeded")
|
||||||
@@ -2581,9 +2581,9 @@ function has_cycle(target_jti, parent_ids, ledger,
|
|||||||
if parent_id in visited:
|
if parent_id in visited:
|
||||||
continue
|
continue
|
||||||
visited.add(parent_id)
|
visited.add(parent_id)
|
||||||
parent = ledger.get(parent_id)
|
parent = ect_store.get(parent_id)
|
||||||
if parent is not null:
|
if parent is not null:
|
||||||
result = has_cycle(target_jti, parent.par, ledger,
|
result = has_cycle(target_jti, parent.par, ect_store,
|
||||||
visited, max_depth)
|
visited, max_depth)
|
||||||
if result is error or result is true:
|
if result is error or result is true:
|
||||||
return result
|
return result
|
||||||
@@ -2714,7 +2714,7 @@ fails.<a href="#section-7.1-4" class="pilcrow">¶</a></p>
|
|||||||
<div class="breakable lang-pseudocode sourcecode" id="section-7.2-1.1">
|
<div class="breakable lang-pseudocode sourcecode" id="section-7.2-1.1">
|
||||||
<pre>
|
<pre>
|
||||||
function verify_ect(ect_jws, verifier_id,
|
function verify_ect(ect_jws, verifier_id,
|
||||||
trust_domain_keys, ledger):
|
trust_domain_keys, ect_store):
|
||||||
// Parse JWS
|
// Parse JWS
|
||||||
(header, payload, signature) = parse_jws(ect_jws)
|
(header, payload, signature) = parse_jws(ect_jws)
|
||||||
|
|
||||||
@@ -2775,14 +2775,15 @@ function verify_ect(ect_jws, verifier_id,
|
|||||||
["approved", "rejected", "pending_human_review"]:
|
["approved", "rejected", "pending_human_review"]:
|
||||||
return reject("Invalid pol_decision value")
|
return reject("Invalid pol_decision value")
|
||||||
|
|
||||||
// Validate DAG (against ledger or inline parent ECTs)
|
// Validate DAG (against ECT store or inline parent ECTs)
|
||||||
result = validate_dag(payload, ledger,
|
result = validate_dag(payload, ect_store,
|
||||||
clock_skew_tolerance)
|
clock_skew_tolerance)
|
||||||
if result is error:
|
if result is error:
|
||||||
return reject("DAG validation failed")
|
return reject("DAG validation failed")
|
||||||
|
|
||||||
// All checks passed; append to ledger
|
// All checks passed; record if store is available
|
||||||
ledger.append(payload)
|
if ect_store is not null:
|
||||||
|
ect_store.append(payload)
|
||||||
return accept
|
return accept
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
@@ -2799,14 +2800,14 @@ function verify_ect(ect_jws, verifier_id,
|
|||||||
<h2 id="name-audit-ledger-interface">
|
<h2 id="name-audit-ledger-interface">
|
||||||
<a href="#section-8" class="section-number selfRef">8. </a><a href="#name-audit-ledger-interface" class="section-name selfRef">Audit Ledger Interface</a>
|
<a href="#section-8" class="section-number selfRef">8. </a><a href="#name-audit-ledger-interface" class="section-name selfRef">Audit Ledger Interface</a>
|
||||||
</h2>
|
</h2>
|
||||||
<p id="section-8-1">ECTs are designed to be recorded in an immutable audit ledger for
|
<p id="section-8-1">ECTs <span class="bcp14">MAY</span> be recorded in an immutable audit ledger for compliance
|
||||||
compliance verification and post-hoc analysis. This specification
|
verification and post-hoc analysis. A ledger is <span class="bcp14">RECOMMENDED</span> for
|
||||||
defines required properties for the ledger but does not mandate
|
regulated environments but is not required for point-to-point
|
||||||
a specific storage technology. Implementations <span class="bcp14">MAY</span> use
|
operation. This specification does not mandate a specific storage
|
||||||
append-only logs, databases with cryptographic commitment schemes,
|
technology. Implementations <span class="bcp14">MAY</span> use append-only logs, databases
|
||||||
distributed ledgers, or any storage mechanism that provides the
|
with cryptographic commitment schemes, distributed ledgers, or
|
||||||
required properties.<a href="#section-8-1" class="pilcrow">¶</a></p>
|
any storage mechanism that provides the required properties.<a href="#section-8-1" class="pilcrow">¶</a></p>
|
||||||
<p id="section-8-2">An audit ledger implementation <span class="bcp14">MUST</span> provide:<a href="#section-8-2" class="pilcrow">¶</a></p>
|
<p id="section-8-2">When an audit ledger is deployed, the implementation <span class="bcp14">MUST</span> provide:<a href="#section-8-2" class="pilcrow">¶</a></p>
|
||||||
<ol start="1" type="1" class="normal type-1" id="section-8-3">
|
<ol start="1" type="1" class="normal type-1" id="section-8-3">
|
||||||
<li id="section-8-3.1">
|
<li id="section-8-3.1">
|
||||||
<p id="section-8-3.1.1">Append-only semantics: Once an ECT is recorded, it <span class="bcp14">MUST NOT</span> be
|
<p id="section-8-3.1.1">Append-only semantics: Once an ECT is recorded, it <span class="bcp14">MUST NOT</span> be
|
||||||
@@ -2883,7 +2884,7 @@ Human Release Manager:
|
|||||||
exec_act: approve_release
|
exec_act: approve_release
|
||||||
pol: release_approval_policy pol_decision: approved
|
pol: release_approval_policy pol_decision: approved
|
||||||
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
|
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
|
||||||
ext: {org.ietf.wimse.witnessed_by: [...]} (extension metadata)
|
ext: {witnessed_by: [...]} (extension metadata)
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<figcaption><a href="#figure-8" class="selfRef">Figure 8</a>:
|
<figcaption><a href="#figure-8" class="selfRef">Figure 8</a>:
|
||||||
@@ -3167,7 +3168,7 @@ evaluating the policy).<a href="#section-10.2-1" class="pilcrow">¶</a></p>
|
|||||||
</ul>
|
</ul>
|
||||||
<p id="section-10.2-4">The trustworthiness of ECT claims depends on the trustworthiness
|
<p id="section-10.2-4">The trustworthiness of ECT claims depends on the trustworthiness
|
||||||
of the signing agent. To mitigate single-agent false claims,
|
of the signing agent. To mitigate single-agent false claims,
|
||||||
regulated environments <span class="bcp14">SHOULD</span> use the "org.ietf.wimse.witnessed_by"
|
regulated environments <span class="bcp14">SHOULD</span> use the "witnessed_by"
|
||||||
extension key (carried in "ext") to include independent
|
extension key (carried in "ext") to include independent
|
||||||
third-party observers at critical decision points. However,
|
third-party observers at critical decision points. However,
|
||||||
this value is self-asserted by the ECT issuer: the listed
|
this value is self-asserted by the ECT issuer: the listed
|
||||||
@@ -3181,7 +3182,7 @@ did not participate.<a href="#section-10.2-4" class="pilcrow">¶</a></p>
|
|||||||
<a href="#section-10.2.1" class="section-number selfRef">10.2.1. </a><a href="#name-witness-attestation-model" class="section-name selfRef">Witness Attestation Model</a>
|
<a href="#section-10.2.1" class="section-number selfRef">10.2.1. </a><a href="#name-witness-attestation-model" class="section-name selfRef">Witness Attestation Model</a>
|
||||||
</h4>
|
</h4>
|
||||||
<p id="section-10.2.1-1">To address the self-assertion limitation of the
|
<p id="section-10.2.1-1">To address the self-assertion limitation of the
|
||||||
"org.ietf.wimse.witnessed_by" extension, witnesses <span class="bcp14">SHOULD</span> submit their
|
"witnessed_by" extension, witnesses <span class="bcp14">SHOULD</span> submit their
|
||||||
own independent signed ECTs to the audit ledger attesting to the
|
own independent signed ECTs to the audit ledger attesting to the
|
||||||
observed task. A witness attestation ECT:<a href="#section-10.2.1-1" class="pilcrow">¶</a></p>
|
observed task. A witness attestation ECT:<a href="#section-10.2.1-1" class="pilcrow">¶</a></p>
|
||||||
<ul class="normal">
|
<ul class="normal">
|
||||||
@@ -3201,7 +3202,7 @@ linking the attestation to the original task.<a href="#section-10.2.1-2.3.1" cla
|
|||||||
confirms the observation.<a href="#section-10.2.1-2.4.1" class="pilcrow">¶</a></p>
|
confirms the observation.<a href="#section-10.2.1-2.4.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p id="section-10.2.1-3">When a task's "org.ietf.wimse.witnessed_by" extension lists one or more
|
<p id="section-10.2.1-3">When a task's "witnessed_by" extension lists one or more
|
||||||
witnesses, auditors <span class="bcp14">SHOULD</span> verify that corresponding witness
|
witnesses, auditors <span class="bcp14">SHOULD</span> verify that corresponding witness
|
||||||
attestation ECTs exist in the ledger for each listed witness. A
|
attestation ECTs exist in the ledger for each listed witness. A
|
||||||
mismatch between the extension value and the set of independent
|
mismatch between the extension value and the set of independent
|
||||||
@@ -3353,7 +3354,7 @@ create a false execution history if they control the ledger.<a href="#section-10
|
|||||||
by an entity independent of the workflow agents.<a href="#section-10.8-3.1.1" class="pilcrow">¶</a></p>
|
by an entity independent of the workflow agents.<a href="#section-10.8-3.1.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li class="normal" id="section-10.8-3.2">
|
<li class="normal" id="section-10.8-3.2">
|
||||||
<p id="section-10.8-3.2.1">Witness attestation: Using the "org.ietf.wimse.witnessed_by" extension
|
<p id="section-10.8-3.2.1">Witness attestation: Using the "witnessed_by" extension
|
||||||
key in "ext" to include independent third-party observers.<a href="#section-10.8-3.2.1" class="pilcrow">¶</a></p>
|
key in "ext" to include independent third-party observers.<a href="#section-10.8-3.2.1" class="pilcrow">¶</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li class="normal" id="section-10.8-3.3">
|
<li class="normal" id="section-10.8-3.3">
|
||||||
@@ -4412,7 +4413,7 @@ autonomous agents and human release approval:<a href="#appendix-D.2-1" class="pi
|
|||||||
"pol_decision": "approved",
|
"pol_decision": "approved",
|
||||||
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
|
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
|
||||||
"ext": {
|
"ext": {
|
||||||
"org.ietf.wimse.witnessed_by": [
|
"witnessed_by": [
|
||||||
"spiffe://meddev.example/audit/qa-observer-1"
|
"spiffe://meddev.example/audit/qa-observer-1"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -4423,7 +4424,7 @@ autonomous agents and human release approval:<a href="#appendix-D.2-1" class="pi
|
|||||||
implementation, implementation preceded testing, testing preceded
|
implementation, implementation preceded testing, testing preceded
|
||||||
build, and a human release manager approved the final release.
|
build, and a human release manager approved the final release.
|
||||||
The "ext" object in task 5 carries witness metadata via
|
The "ext" object in task 5 carries witness metadata via
|
||||||
the "org.ietf.wimse.witnessed_by" extension key.<a href="#appendix-D.2-12" class="pilcrow">¶</a></p>
|
the "witnessed_by" extension key.<a href="#appendix-D.2-12" class="pilcrow">¶</a></p>
|
||||||
<div class="alignLeft art-text artwork" id="appendix-D.2-13">
|
<div class="alignLeft art-text artwork" id="appendix-D.2-13">
|
||||||
<pre>
|
<pre>
|
||||||
task-...-0001 (review_requirements_spec)
|
task-...-0001 (review_requirements_spec)
|
||||||
|
|||||||
@@ -292,8 +292,8 @@ between the identity layer and the application layer:
|
|||||||
|
|
|
|
||||||
v
|
v
|
||||||
+--------------------------------------------------+
|
+--------------------------------------------------+
|
||||||
| Ledger Layer (Immutable Record) |
|
| Optional: Audit Ledger (Immutable Record) |
|
||||||
| "All ECTs appended to audit ledger" |
|
| "ECTs MAY be appended to an audit ledger" |
|
||||||
+--------------------------------------------------+
|
+--------------------------------------------------+
|
||||||
~~~
|
~~~
|
||||||
{: #fig-layers title="WIMSE Extension Architecture Layers"}
|
{: #fig-layers title="WIMSE Extension Architecture Layers"}
|
||||||
@@ -345,7 +345,8 @@ The receiving agent (Agent B) verifies in order:
|
|||||||
2. ECT (this extension): Records what Agent A did, what policy was
|
2. ECT (this extension): Records what Agent A did, what policy was
|
||||||
evaluated, and what precedent tasks exist.
|
evaluated, and what precedent tasks exist.
|
||||||
|
|
||||||
3. Ledger: Appends the verified ECT to the audit ledger.
|
3. Ledger (if deployed): Appends the verified ECT to the audit
|
||||||
|
ledger.
|
||||||
|
|
||||||
# Execution Context Token Format {#ect-format}
|
# Execution Context Token Format {#ect-format}
|
||||||
|
|
||||||
@@ -592,32 +593,31 @@ ext:
|
|||||||
that do not understand extension claims MUST ignore them.
|
that do not understand extension claims MUST ignore them.
|
||||||
|
|
||||||
To avoid key collisions between different domains, extension
|
To avoid key collisions between different domains, extension
|
||||||
key names MUST use reverse domain notation (e.g.,
|
key names SHOULD use reverse domain notation (e.g.,
|
||||||
"com.example.custom_field"). Implementations MUST NOT use
|
"com.example.custom_field") to avoid collisions between
|
||||||
unqualified key names within the "ext" object. To prevent
|
independently developed extensions. To prevent abuse and
|
||||||
abuse and excessive token size, the serialized JSON
|
excessive token size, the serialized JSON representation of
|
||||||
representation of the "ext" object SHOULD NOT exceed 4096
|
the "ext" object SHOULD NOT exceed 4096 bytes, and the JSON
|
||||||
bytes, and the JSON nesting depth within the "ext" object
|
nesting depth within the "ext" object SHOULD NOT exceed 5
|
||||||
SHOULD NOT exceed 5 levels. Implementations SHOULD reject
|
levels. Implementations SHOULD reject ECTs whose "ext" claim
|
||||||
ECTs whose "ext" claim exceeds these limits.
|
exceeds these limits.
|
||||||
|
|
||||||
The following extension keys are RECOMMENDED for common use
|
The following extension keys are defined by this specification
|
||||||
cases. These are not registered claims; they are carried
|
for common use cases. Because these keys are documented here,
|
||||||
within the "ext" object:
|
they use short names without reverse domain prefixes:
|
||||||
|
|
||||||
- "org.ietf.wimse.exec\_time\_ms": Integer. Execution duration in
|
- "exec\_time\_ms": Integer. Execution duration in milliseconds.
|
||||||
milliseconds.
|
- "regulated\_domain": String. Regulatory domain (e.g.,
|
||||||
- "org.ietf.wimse.regulated\_domain": String. Regulatory domain
|
"medtech", "finance", "military").
|
||||||
(e.g., "medtech", "finance", "military").
|
- "model\_version": String. AI/ML model version.
|
||||||
- "org.ietf.wimse.model\_version": String. AI/ML model version.
|
- "witnessed\_by": Array of StringOrURI. Identifiers of
|
||||||
- "org.ietf.wimse.witnessed\_by": Array of StringOrURI. Identifiers
|
third-party entities that the issuer claims observed the
|
||||||
of third-party entities that the issuer claims observed the
|
|
||||||
task. Note: this is self-asserted; for verifiable witness
|
task. Note: this is self-asserted; for verifiable witness
|
||||||
attestation, witnesses should submit independent signed ECTs.
|
attestation, witnesses should submit independent signed ECTs.
|
||||||
- "org.ietf.wimse.inp\_classification": String. Data sensitivity
|
- "inp\_classification": String. Data sensitivity classification
|
||||||
classification (e.g., "public", "confidential", "restricted").
|
(e.g., "public", "confidential", "restricted").
|
||||||
- "org.ietf.wimse.pol\_timestamp": NumericDate. Time at which the
|
- "pol\_timestamp": NumericDate. Time at which the policy
|
||||||
policy decision was made, if distinct from "iat".
|
decision was made, if distinct from "iat".
|
||||||
|
|
||||||
## Complete ECT Example
|
## Complete ECT Example
|
||||||
|
|
||||||
@@ -644,10 +644,10 @@ The following is a complete ECT payload example:
|
|||||||
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
|
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
|
||||||
|
|
||||||
"ext": {
|
"ext": {
|
||||||
"org.ietf.wimse.pol_timestamp": 1772064145,
|
"pol_timestamp": 1772064145,
|
||||||
"org.ietf.wimse.exec_time_ms": 245,
|
"exec_time_ms": 245,
|
||||||
"org.ietf.wimse.regulated_domain": "medtech",
|
"regulated_domain": "medtech",
|
||||||
"org.ietf.wimse.model_version": "clinical-reasoning-v4.2"
|
"model_version": "clinical-reasoning-v4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~
|
~~~
|
||||||
@@ -699,8 +699,8 @@ enabling auditors to reconstruct the complete workflow and verify
|
|||||||
that required predecessor tasks were recorded before dependent
|
that required predecessor tasks were recorded before dependent
|
||||||
tasks.
|
tasks.
|
||||||
|
|
||||||
DAG validation is performed against the audit ledger, which
|
DAG validation is performed against the ECT store — either an
|
||||||
serves as the authoritative store of previously verified ECTs.
|
audit ledger or the set of parent ECTs received inline.
|
||||||
|
|
||||||
## Validation Rules
|
## Validation Rules
|
||||||
|
|
||||||
@@ -752,14 +752,14 @@ the following DAG validation steps:
|
|||||||
The following pseudocode describes the DAG validation procedure:
|
The following pseudocode describes the DAG validation procedure:
|
||||||
|
|
||||||
~~~ pseudocode
|
~~~ pseudocode
|
||||||
function validate_dag(ect, ledger, clock_skew_tolerance):
|
function validate_dag(ect, ect_store, clock_skew_tolerance):
|
||||||
// Step 1: Uniqueness check
|
// Step 1: Uniqueness check
|
||||||
if ledger.contains(ect.jti, ect.wid):
|
if ect_store.contains(ect.jti, ect.wid):
|
||||||
return error("ECT ID already exists")
|
return error("ECT ID already exists")
|
||||||
|
|
||||||
// Step 2: Parent existence and temporal ordering
|
// Step 2: Parent existence and temporal ordering
|
||||||
for parent_id in ect.par:
|
for parent_id in ect.par:
|
||||||
parent = ledger.get(parent_id)
|
parent = ect_store.get(parent_id)
|
||||||
if parent is null:
|
if parent is null:
|
||||||
return error("Parent task not found: " + parent_id)
|
return error("Parent task not found: " + parent_id)
|
||||||
if parent.iat >= ect.iat + clock_skew_tolerance:
|
if parent.iat >= ect.iat + clock_skew_tolerance:
|
||||||
@@ -767,14 +767,14 @@ function validate_dag(ect, ledger, clock_skew_tolerance):
|
|||||||
|
|
||||||
// Step 3: Cycle detection (with traversal limit)
|
// Step 3: Cycle detection (with traversal limit)
|
||||||
visited = set()
|
visited = set()
|
||||||
result = has_cycle(ect.jti, ect.par, ledger, visited,
|
result = has_cycle(ect.jti, ect.par, ect_store, visited,
|
||||||
max_ancestor_limit)
|
max_ancestor_limit)
|
||||||
if result is error or result is true:
|
if result is error or result is true:
|
||||||
return error("Circular dependency or depth limit exceeded")
|
return error("Circular dependency or depth limit exceeded")
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
function has_cycle(target_jti, parent_ids, ledger,
|
function has_cycle(target_jti, parent_ids, ect_store,
|
||||||
visited, max_depth):
|
visited, max_depth):
|
||||||
if visited.size() >= max_depth:
|
if visited.size() >= max_depth:
|
||||||
return error("Maximum ancestor traversal limit exceeded")
|
return error("Maximum ancestor traversal limit exceeded")
|
||||||
@@ -784,9 +784,9 @@ function has_cycle(target_jti, parent_ids, ledger,
|
|||||||
if parent_id in visited:
|
if parent_id in visited:
|
||||||
continue
|
continue
|
||||||
visited.add(parent_id)
|
visited.add(parent_id)
|
||||||
parent = ledger.get(parent_id)
|
parent = ect_store.get(parent_id)
|
||||||
if parent is not null:
|
if parent is not null:
|
||||||
result = has_cycle(target_jti, parent.par, ledger,
|
result = has_cycle(target_jti, parent.par, ect_store,
|
||||||
visited, max_depth)
|
visited, max_depth)
|
||||||
if result is error or result is true:
|
if result is error or result is true:
|
||||||
return result
|
return result
|
||||||
@@ -883,7 +883,7 @@ fails.
|
|||||||
|
|
||||||
~~~ pseudocode
|
~~~ pseudocode
|
||||||
function verify_ect(ect_jws, verifier_id,
|
function verify_ect(ect_jws, verifier_id,
|
||||||
trust_domain_keys, ledger):
|
trust_domain_keys, ect_store):
|
||||||
// Parse JWS
|
// Parse JWS
|
||||||
(header, payload, signature) = parse_jws(ect_jws)
|
(header, payload, signature) = parse_jws(ect_jws)
|
||||||
|
|
||||||
@@ -944,29 +944,30 @@ function verify_ect(ect_jws, verifier_id,
|
|||||||
["approved", "rejected", "pending_human_review"]:
|
["approved", "rejected", "pending_human_review"]:
|
||||||
return reject("Invalid pol_decision value")
|
return reject("Invalid pol_decision value")
|
||||||
|
|
||||||
// Validate DAG (against ledger or inline parent ECTs)
|
// Validate DAG (against ECT store or inline parent ECTs)
|
||||||
result = validate_dag(payload, ledger,
|
result = validate_dag(payload, ect_store,
|
||||||
clock_skew_tolerance)
|
clock_skew_tolerance)
|
||||||
if result is error:
|
if result is error:
|
||||||
return reject("DAG validation failed")
|
return reject("DAG validation failed")
|
||||||
|
|
||||||
// All checks passed; append to ledger
|
// All checks passed; record if store is available
|
||||||
ledger.append(payload)
|
if ect_store is not null:
|
||||||
|
ect_store.append(payload)
|
||||||
return accept
|
return accept
|
||||||
~~~
|
~~~
|
||||||
{: #fig-verification title="ECT Verification Pseudocode"}
|
{: #fig-verification title="ECT Verification Pseudocode"}
|
||||||
|
|
||||||
# Audit Ledger Interface {#ledger-interface}
|
# Audit Ledger Interface {#ledger-interface}
|
||||||
|
|
||||||
ECTs are designed to be recorded in an immutable audit ledger for
|
ECTs MAY be recorded in an immutable audit ledger for compliance
|
||||||
compliance verification and post-hoc analysis. This specification
|
verification and post-hoc analysis. A ledger is RECOMMENDED for
|
||||||
defines required properties for the ledger but does not mandate
|
regulated environments but is not required for point-to-point
|
||||||
a specific storage technology. Implementations MAY use
|
operation. This specification does not mandate a specific storage
|
||||||
append-only logs, databases with cryptographic commitment schemes,
|
technology. Implementations MAY use append-only logs, databases
|
||||||
distributed ledgers, or any storage mechanism that provides the
|
with cryptographic commitment schemes, distributed ledgers, or
|
||||||
required properties.
|
any storage mechanism that provides the required properties.
|
||||||
|
|
||||||
An audit ledger implementation MUST provide:
|
When an audit ledger is deployed, the implementation MUST provide:
|
||||||
|
|
||||||
1. Append-only semantics: Once an ECT is recorded, it MUST NOT be
|
1. Append-only semantics: Once an ECT is recorded, it MUST NOT be
|
||||||
modified or deleted.
|
modified or deleted.
|
||||||
@@ -1031,7 +1032,7 @@ Human Release Manager:
|
|||||||
exec_act: approve_release
|
exec_act: approve_release
|
||||||
pol: release_approval_policy pol_decision: approved
|
pol: release_approval_policy pol_decision: approved
|
||||||
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
|
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
|
||||||
ext: {org.ietf.wimse.witnessed_by: [...]} (extension metadata)
|
ext: {witnessed_by: [...]} (extension metadata)
|
||||||
~~~
|
~~~
|
||||||
{: #fig-medtech-sdlc title="Medical Device SDLC Workflow"}
|
{: #fig-medtech-sdlc title="Medical Device SDLC Workflow"}
|
||||||
|
|
||||||
@@ -1222,7 +1223,7 @@ ECTs do not independently verify that:
|
|||||||
|
|
||||||
The trustworthiness of ECT claims depends on the trustworthiness
|
The trustworthiness of ECT claims depends on the trustworthiness
|
||||||
of the signing agent. To mitigate single-agent false claims,
|
of the signing agent. To mitigate single-agent false claims,
|
||||||
regulated environments SHOULD use the "org.ietf.wimse.witnessed_by"
|
regulated environments SHOULD use the "witnessed_by"
|
||||||
extension key (carried in "ext") to include independent
|
extension key (carried in "ext") to include independent
|
||||||
third-party observers at critical decision points. However,
|
third-party observers at critical decision points. However,
|
||||||
this value is self-asserted by the ECT issuer: the listed
|
this value is self-asserted by the ECT issuer: the listed
|
||||||
@@ -1234,7 +1235,7 @@ did not participate.
|
|||||||
### Witness Attestation Model {#witness-attestation-model}
|
### Witness Attestation Model {#witness-attestation-model}
|
||||||
|
|
||||||
To address the self-assertion limitation of the
|
To address the self-assertion limitation of the
|
||||||
"org.ietf.wimse.witnessed_by" extension, witnesses SHOULD submit their
|
"witnessed_by" extension, witnesses SHOULD submit their
|
||||||
own independent signed ECTs to the audit ledger attesting to the
|
own independent signed ECTs to the audit ledger attesting to the
|
||||||
observed task. A witness attestation ECT:
|
observed task. A witness attestation ECT:
|
||||||
|
|
||||||
@@ -1246,7 +1247,7 @@ observed task. A witness attestation ECT:
|
|||||||
- MUST set "pol_decision" to "approved" to indicate the witness
|
- MUST set "pol_decision" to "approved" to indicate the witness
|
||||||
confirms the observation.
|
confirms the observation.
|
||||||
|
|
||||||
When a task's "org.ietf.wimse.witnessed_by" extension lists one or more
|
When a task's "witnessed_by" extension lists one or more
|
||||||
witnesses, auditors SHOULD verify that corresponding witness
|
witnesses, auditors SHOULD verify that corresponding witness
|
||||||
attestation ECTs exist in the ledger for each listed witness. A
|
attestation ECTs exist in the ledger for each listed witness. A
|
||||||
mismatch between the extension value and the set of independent
|
mismatch between the extension value and the set of independent
|
||||||
@@ -1352,7 +1353,7 @@ Mitigations include:
|
|||||||
|
|
||||||
- Independent ledger maintenance: The ledger SHOULD be maintained
|
- Independent ledger maintenance: The ledger SHOULD be maintained
|
||||||
by an entity independent of the workflow agents.
|
by an entity independent of the workflow agents.
|
||||||
- Witness attestation: Using the "org.ietf.wimse.witnessed_by" extension
|
- Witness attestation: Using the "witnessed_by" extension
|
||||||
key in "ext" to include independent third-party observers.
|
key in "ext" to include independent third-party observers.
|
||||||
- Cross-verification: Multiple independent ledger replicas can be
|
- Cross-verification: Multiple independent ledger replicas can be
|
||||||
compared for consistency.
|
compared for consistency.
|
||||||
@@ -1927,7 +1928,7 @@ Task 5 (Human Release Manager Approval):
|
|||||||
"pol_decision": "approved",
|
"pol_decision": "approved",
|
||||||
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
|
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
|
||||||
"ext": {
|
"ext": {
|
||||||
"org.ietf.wimse.witnessed_by": [
|
"witnessed_by": [
|
||||||
"spiffe://meddev.example/audit/qa-observer-1"
|
"spiffe://meddev.example/audit/qa-observer-1"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1938,7 +1939,7 @@ The resulting DAG records the complete SDLC: spec review preceded
|
|||||||
implementation, implementation preceded testing, testing preceded
|
implementation, implementation preceded testing, testing preceded
|
||||||
build, and a human release manager approved the final release.
|
build, and a human release manager approved the final release.
|
||||||
The "ext" object in task 5 carries witness metadata via
|
The "ext" object in task 5 carries witness metadata via
|
||||||
the "org.ietf.wimse.witnessed_by" extension key.
|
the "witnessed_by" extension key.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
task-...-0001 (review_requirements_spec)
|
task-...-0001 (review_requirements_spec)
|
||||||
|
|||||||
@@ -409,8 +409,8 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
|
|
|
|
||||||
v
|
v
|
||||||
+--------------------------------------------------+
|
+--------------------------------------------------+
|
||||||
| Ledger Layer (Immutable Record) |
|
| Optional: Audit Ledger (Immutable Record) |
|
||||||
| "All ECTs appended to audit ledger" |
|
| "ECTs MAY be appended to an audit ledger" |
|
||||||
+--------------------------------------------------+
|
+--------------------------------------------------+
|
||||||
|
|
||||||
Figure 1: WIMSE Extension Architecture Layers
|
Figure 1: WIMSE Extension Architecture Layers
|
||||||
@@ -466,7 +466,8 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
2. ECT (this extension): Records what Agent A did, what policy was
|
2. ECT (this extension): Records what Agent A did, what policy was
|
||||||
evaluated, and what precedent tasks exist.
|
evaluated, and what precedent tasks exist.
|
||||||
|
|
||||||
3. Ledger: Appends the verified ECT to the audit ledger.
|
3. Ledger (if deployed): Appends the verified ECT to the audit
|
||||||
|
ledger.
|
||||||
|
|
||||||
4. Execution Context Token Format
|
4. Execution Context Token Format
|
||||||
|
|
||||||
@@ -497,7 +498,6 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
from other JWT types, consistent with the WIMSE convention for
|
from other JWT types, consistent with the WIMSE convention for
|
||||||
type parameter values.
|
type parameter values.
|
||||||
|
|
||||||
kid: REQUIRED. The key identifier referencing the public key from
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -506,6 +506,7 @@ Nennemann Expires 28 August 2026 [Page 9]
|
|||||||
Internet-Draft WIMSE Execution Context February 2026
|
Internet-Draft WIMSE Execution Context February 2026
|
||||||
|
|
||||||
|
|
||||||
|
kid: REQUIRED. The key identifier referencing the public key from
|
||||||
the agent's WIT [RFC7517]. Used by verifiers to look up the
|
the agent's WIT [RFC7517]. Used by verifiers to look up the
|
||||||
correct public key for signature verification.
|
correct public key for signature verification.
|
||||||
|
|
||||||
@@ -556,7 +557,6 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Nennemann Expires 28 August 2026 [Page 10]
|
Nennemann Expires 28 August 2026 [Page 10]
|
||||||
|
|
||||||
Internet-Draft WIMSE Execution Context February 2026
|
Internet-Draft WIMSE Execution Context February 2026
|
||||||
@@ -734,36 +734,35 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
not understand extension claims MUST ignore them.
|
not understand extension claims MUST ignore them.
|
||||||
|
|
||||||
To avoid key collisions between different domains, extension key
|
To avoid key collisions between different domains, extension key
|
||||||
names MUST use reverse domain notation (e.g.,
|
names SHOULD use reverse domain notation (e.g.,
|
||||||
"com.example.custom_field"). Implementations MUST NOT use
|
"com.example.custom_field") to avoid collisions between independently
|
||||||
unqualified key names within the "ext" object. To prevent abuse and
|
developed extensions. To prevent abuse and excessive token size, the
|
||||||
excessive token size, the serialized JSON representation of the "ext"
|
serialized JSON representation of the "ext" object SHOULD NOT exceed
|
||||||
object SHOULD NOT exceed 4096 bytes, and the JSON nesting depth
|
4096 bytes, and the JSON nesting depth within the "ext" object SHOULD
|
||||||
within the "ext" object SHOULD NOT exceed 5 levels. Implementations
|
NOT exceed 5 levels. Implementations SHOULD reject ECTs whose "ext"
|
||||||
SHOULD reject ECTs whose "ext" claim exceeds these limits.
|
claim exceeds these limits.
|
||||||
|
|
||||||
The following extension keys are RECOMMENDED for common use cases.
|
The following extension keys are defined by this specification for
|
||||||
These are not registered claims; they are carried within the "ext"
|
common use cases. Because these keys are documented here, they use
|
||||||
object:
|
short names without reverse domain prefixes:
|
||||||
|
|
||||||
* "org.ietf.wimse.exec_time_ms": Integer. Execution duration in
|
* "exec_time_ms": Integer. Execution duration in milliseconds.
|
||||||
milliseconds.
|
|
||||||
|
|
||||||
* "org.ietf.wimse.regulated_domain": String. Regulatory domain
|
* "regulated_domain": String. Regulatory domain (e.g., "medtech",
|
||||||
(e.g., "medtech", "finance", "military").
|
"finance", "military").
|
||||||
|
|
||||||
* "org.ietf.wimse.model_version": String. AI/ML model version.
|
* "model_version": String. AI/ML model version.
|
||||||
|
|
||||||
* "org.ietf.wimse.witnessed_by": Array of StringOrURI. Identifiers
|
* "witnessed_by": Array of StringOrURI. Identifiers of third-party
|
||||||
of third-party entities that the issuer claims observed the task.
|
entities that the issuer claims observed the task. Note: this is
|
||||||
Note: this is self-asserted; for verifiable witness attestation,
|
self-asserted; for verifiable witness attestation, witnesses
|
||||||
witnesses should submit independent signed ECTs.
|
should submit independent signed ECTs.
|
||||||
|
|
||||||
* "org.ietf.wimse.inp_classification": String. Data sensitivity
|
* "inp_classification": String. Data sensitivity classification
|
||||||
classification (e.g., "public", "confidential", "restricted").
|
(e.g., "public", "confidential", "restricted").
|
||||||
|
|
||||||
* "org.ietf.wimse.pol_timestamp": NumericDate. Time at which the
|
* "pol_timestamp": NumericDate. Time at which the policy decision
|
||||||
policy decision was made, if distinct from "iat".
|
was made, if distinct from "iat".
|
||||||
|
|
||||||
4.3. Complete ECT Example
|
4.3. Complete ECT Example
|
||||||
|
|
||||||
@@ -781,6 +780,7 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Nennemann Expires 28 August 2026 [Page 14]
|
Nennemann Expires 28 August 2026 [Page 14]
|
||||||
|
|
||||||
Internet-Draft WIMSE Execution Context February 2026
|
Internet-Draft WIMSE Execution Context February 2026
|
||||||
@@ -806,10 +806,10 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
|
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
|
||||||
|
|
||||||
"ext": {
|
"ext": {
|
||||||
"org.ietf.wimse.pol_timestamp": 1772064145,
|
"pol_timestamp": 1772064145,
|
||||||
"org.ietf.wimse.exec_time_ms": 245,
|
"exec_time_ms": 245,
|
||||||
"org.ietf.wimse.regulated_domain": "medtech",
|
"regulated_domain": "medtech",
|
||||||
"org.ietf.wimse.model_version": "clinical-reasoning-v4.2"
|
"model_version": "clinical-reasoning-v4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,8 +865,8 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
auditors to reconstruct the complete workflow and verify that
|
auditors to reconstruct the complete workflow and verify that
|
||||||
required predecessor tasks were recorded before dependent tasks.
|
required predecessor tasks were recorded before dependent tasks.
|
||||||
|
|
||||||
DAG validation is performed against the audit ledger, which serves as
|
DAG validation is performed against the ECT store — either an audit
|
||||||
the authoritative store of previously verified ECTs.
|
ledger or the set of parent ECTs received inline.
|
||||||
|
|
||||||
6.2. Validation Rules
|
6.2. Validation Rules
|
||||||
|
|
||||||
@@ -954,14 +954,14 @@ Nennemann Expires 28 August 2026 [Page 17]
|
|||||||
Internet-Draft WIMSE Execution Context February 2026
|
Internet-Draft WIMSE Execution Context February 2026
|
||||||
|
|
||||||
|
|
||||||
function validate_dag(ect, ledger, clock_skew_tolerance):
|
function validate_dag(ect, ect_store, clock_skew_tolerance):
|
||||||
// Step 1: Uniqueness check
|
// Step 1: Uniqueness check
|
||||||
if ledger.contains(ect.jti, ect.wid):
|
if ect_store.contains(ect.jti, ect.wid):
|
||||||
return error("ECT ID already exists")
|
return error("ECT ID already exists")
|
||||||
|
|
||||||
// Step 2: Parent existence and temporal ordering
|
// Step 2: Parent existence and temporal ordering
|
||||||
for parent_id in ect.par:
|
for parent_id in ect.par:
|
||||||
parent = ledger.get(parent_id)
|
parent = ect_store.get(parent_id)
|
||||||
if parent is null:
|
if parent is null:
|
||||||
return error("Parent task not found: " + parent_id)
|
return error("Parent task not found: " + parent_id)
|
||||||
if parent.iat >= ect.iat + clock_skew_tolerance:
|
if parent.iat >= ect.iat + clock_skew_tolerance:
|
||||||
@@ -969,14 +969,14 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
|
|
||||||
// Step 3: Cycle detection (with traversal limit)
|
// Step 3: Cycle detection (with traversal limit)
|
||||||
visited = set()
|
visited = set()
|
||||||
result = has_cycle(ect.jti, ect.par, ledger, visited,
|
result = has_cycle(ect.jti, ect.par, ect_store, visited,
|
||||||
max_ancestor_limit)
|
max_ancestor_limit)
|
||||||
if result is error or result is true:
|
if result is error or result is true:
|
||||||
return error("Circular dependency or depth limit exceeded")
|
return error("Circular dependency or depth limit exceeded")
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
function has_cycle(target_jti, parent_ids, ledger,
|
function has_cycle(target_jti, parent_ids, ect_store,
|
||||||
visited, max_depth):
|
visited, max_depth):
|
||||||
if visited.size() >= max_depth:
|
if visited.size() >= max_depth:
|
||||||
return error("Maximum ancestor traversal limit exceeded")
|
return error("Maximum ancestor traversal limit exceeded")
|
||||||
@@ -986,9 +986,9 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
if parent_id in visited:
|
if parent_id in visited:
|
||||||
continue
|
continue
|
||||||
visited.add(parent_id)
|
visited.add(parent_id)
|
||||||
parent = ledger.get(parent_id)
|
parent = ect_store.get(parent_id)
|
||||||
if parent is not null:
|
if parent is not null:
|
||||||
result = has_cycle(target_jti, parent.par, ledger,
|
result = has_cycle(target_jti, parent.par, ect_store,
|
||||||
visited, max_depth)
|
visited, max_depth)
|
||||||
if result is error or result is true:
|
if result is error or result is true:
|
||||||
return result
|
return result
|
||||||
@@ -1100,7 +1100,7 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
7.2. Verification Pseudocode
|
7.2. Verification Pseudocode
|
||||||
|
|
||||||
function verify_ect(ect_jws, verifier_id,
|
function verify_ect(ect_jws, verifier_id,
|
||||||
trust_domain_keys, ledger):
|
trust_domain_keys, ect_store):
|
||||||
// Parse JWS
|
// Parse JWS
|
||||||
(header, payload, signature) = parse_jws(ect_jws)
|
(header, payload, signature) = parse_jws(ect_jws)
|
||||||
|
|
||||||
@@ -1169,7 +1169,7 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
["approved", "rejected", "pending_human_review"]:
|
["approved", "rejected", "pending_human_review"]:
|
||||||
return reject("Invalid pol_decision value")
|
return reject("Invalid pol_decision value")
|
||||||
|
|
||||||
// Validate DAG (against ledger or inline parent ECTs)
|
// Validate DAG (against ECT store or inline parent ECTs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1178,28 +1178,29 @@ Nennemann Expires 28 August 2026 [Page 21]
|
|||||||
Internet-Draft WIMSE Execution Context February 2026
|
Internet-Draft WIMSE Execution Context February 2026
|
||||||
|
|
||||||
|
|
||||||
result = validate_dag(payload, ledger,
|
result = validate_dag(payload, ect_store,
|
||||||
clock_skew_tolerance)
|
clock_skew_tolerance)
|
||||||
if result is error:
|
if result is error:
|
||||||
return reject("DAG validation failed")
|
return reject("DAG validation failed")
|
||||||
|
|
||||||
// All checks passed; append to ledger
|
// All checks passed; record if store is available
|
||||||
ledger.append(payload)
|
if ect_store is not null:
|
||||||
|
ect_store.append(payload)
|
||||||
return accept
|
return accept
|
||||||
|
|
||||||
Figure 7: ECT Verification Pseudocode
|
Figure 7: ECT Verification Pseudocode
|
||||||
|
|
||||||
8. Audit Ledger Interface
|
8. Audit Ledger Interface
|
||||||
|
|
||||||
ECTs are designed to be recorded in an immutable audit ledger for
|
ECTs MAY be recorded in an immutable audit ledger for compliance
|
||||||
compliance verification and post-hoc analysis. This specification
|
verification and post-hoc analysis. A ledger is RECOMMENDED for
|
||||||
defines required properties for the ledger but does not mandate a
|
regulated environments but is not required for point-to-point
|
||||||
specific storage technology. Implementations MAY use append-only
|
operation. This specification does not mandate a specific storage
|
||||||
logs, databases with cryptographic commitment schemes, distributed
|
technology. Implementations MAY use append-only logs, databases with
|
||||||
ledgers, or any storage mechanism that provides the required
|
cryptographic commitment schemes, distributed ledgers, or any storage
|
||||||
properties.
|
mechanism that provides the required properties.
|
||||||
|
|
||||||
An audit ledger implementation MUST provide:
|
When an audit ledger is deployed, the implementation MUST provide:
|
||||||
|
|
||||||
1. Append-only semantics: Once an ECT is recorded, it MUST NOT be
|
1. Append-only semantics: Once an ECT is recorded, it MUST NOT be
|
||||||
modified or deleted.
|
modified or deleted.
|
||||||
@@ -1228,7 +1229,6 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Nennemann Expires 28 August 2026 [Page 22]
|
Nennemann Expires 28 August 2026 [Page 22]
|
||||||
|
|
||||||
Internet-Draft WIMSE Execution Context February 2026
|
Internet-Draft WIMSE Execution Context February 2026
|
||||||
@@ -1271,7 +1271,7 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
exec_act: approve_release
|
exec_act: approve_release
|
||||||
pol: release_approval_policy pol_decision: approved
|
pol: release_approval_policy pol_decision: approved
|
||||||
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
|
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
|
||||||
ext: {org.ietf.wimse.witnessed_by: [...]} (extension metadata)
|
ext: {witnessed_by: [...]} (extension metadata)
|
||||||
|
|
||||||
Figure 8: Medical Device SDLC Workflow
|
Figure 8: Medical Device SDLC Workflow
|
||||||
|
|
||||||
@@ -1536,20 +1536,20 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
|
|
||||||
The trustworthiness of ECT claims depends on the trustworthiness of
|
The trustworthiness of ECT claims depends on the trustworthiness of
|
||||||
the signing agent. To mitigate single-agent false claims, regulated
|
the signing agent. To mitigate single-agent false claims, regulated
|
||||||
environments SHOULD use the "org.ietf.wimse.witnessed_by" extension
|
environments SHOULD use the "witnessed_by" extension key (carried in
|
||||||
key (carried in "ext") to include independent third-party observers
|
"ext") to include independent third-party observers at critical
|
||||||
at critical decision points. However, this value is self-asserted by
|
decision points. However, this value is self-asserted by the ECT
|
||||||
the ECT issuer: the listed witnesses do not co-sign the ECT and there
|
issuer: the listed witnesses do not co-sign the ECT and there is no
|
||||||
is no cryptographic evidence within a single ECT that the witnesses
|
cryptographic evidence within a single ECT that the witnesses
|
||||||
actually observed the task. An issuing agent could list witnesses
|
actually observed the task. An issuing agent could list witnesses
|
||||||
that did not participate.
|
that did not participate.
|
||||||
|
|
||||||
10.2.1. Witness Attestation Model
|
10.2.1. Witness Attestation Model
|
||||||
|
|
||||||
To address the self-assertion limitation of the
|
To address the self-assertion limitation of the "witnessed_by"
|
||||||
"org.ietf.wimse.witnessed_by" extension, witnesses SHOULD submit
|
extension, witnesses SHOULD submit their own independent signed ECTs
|
||||||
their own independent signed ECTs to the audit ledger attesting to
|
to the audit ledger attesting to the observed task. A witness
|
||||||
the observed task. A witness attestation ECT:
|
attestation ECT:
|
||||||
|
|
||||||
* MUST set "iss" to the witness's own workload identity.
|
* MUST set "iss" to the witness's own workload identity.
|
||||||
|
|
||||||
@@ -1570,11 +1570,11 @@ Nennemann Expires 28 August 2026 [Page 28]
|
|||||||
Internet-Draft WIMSE Execution Context February 2026
|
Internet-Draft WIMSE Execution Context February 2026
|
||||||
|
|
||||||
|
|
||||||
When a task's "org.ietf.wimse.witnessed_by" extension lists one or
|
When a task's "witnessed_by" extension lists one or more witnesses,
|
||||||
more witnesses, auditors SHOULD verify that corresponding witness
|
auditors SHOULD verify that corresponding witness attestation ECTs
|
||||||
attestation ECTs exist in the ledger for each listed witness. A
|
exist in the ledger for each listed witness. A mismatch between the
|
||||||
mismatch between the extension value and the set of independent
|
extension value and the set of independent witness ECTs in the ledger
|
||||||
witness ECTs in the ledger SHOULD be flagged during audit review.
|
SHOULD be flagged during audit review.
|
||||||
|
|
||||||
This model converts witness attestation from a self-asserted claim to
|
This model converts witness attestation from a self-asserted claim to
|
||||||
a cryptographically verifiable property of the ledger: the witness
|
a cryptographically verifiable property of the ledger: the witness
|
||||||
@@ -1702,9 +1702,8 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
* Independent ledger maintenance: The ledger SHOULD be maintained by
|
* Independent ledger maintenance: The ledger SHOULD be maintained by
|
||||||
an entity independent of the workflow agents.
|
an entity independent of the workflow agents.
|
||||||
|
|
||||||
* Witness attestation: Using the "org.ietf.wimse.witnessed_by"
|
* Witness attestation: Using the "witnessed_by" extension key in
|
||||||
extension key in "ext" to include independent third-party
|
"ext" to include independent third-party observers.
|
||||||
observers.
|
|
||||||
|
|
||||||
* Cross-verification: Multiple independent ledger replicas can be
|
* Cross-verification: Multiple independent ledger replicas can be
|
||||||
compared for consistency.
|
compared for consistency.
|
||||||
@@ -1733,6 +1732,7 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Nennemann Expires 28 August 2026 [Page 31]
|
Nennemann Expires 28 August 2026 [Page 31]
|
||||||
|
|
||||||
Internet-Draft WIMSE Execution Context February 2026
|
Internet-Draft WIMSE Execution Context February 2026
|
||||||
@@ -2611,7 +2611,7 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
"pol_decision": "approved",
|
"pol_decision": "approved",
|
||||||
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
|
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
|
||||||
"ext": {
|
"ext": {
|
||||||
"org.ietf.wimse.witnessed_by": [
|
"witnessed_by": [
|
||||||
"spiffe://meddev.example/audit/qa-observer-1"
|
"spiffe://meddev.example/audit/qa-observer-1"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -2621,7 +2621,7 @@ Internet-Draft WIMSE Execution Context February 2026
|
|||||||
implementation, implementation preceded testing, testing preceded
|
implementation, implementation preceded testing, testing preceded
|
||||||
build, and a human release manager approved the final release. The
|
build, and a human release manager approved the final release. The
|
||||||
"ext" object in task 5 carries witness metadata via the
|
"ext" object in task 5 carries witness metadata via the
|
||||||
"org.ietf.wimse.witnessed_by" extension key.
|
"witnessed_by" extension key.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user