From 7735bf86ee7d9a05ca13654698c668ea31514f7c Mon Sep 17 00:00:00 2001 From: chuks <891251+chuks@users.noreply.github.com> Date: Sat, 1 Aug 2026 10:42:00 -0700 Subject: [PATCH 1/2] =?UTF-8?q?spec:=20note=20the=20interaction=20of=20MAX?= =?UTF-8?q?=5FPROOF=5FBUNDLE=5FBYTES=20and=20chain=20depth=20(=C2=A75.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation only; no protocol, wire-format, or fixture change. alpha.16 raised MAX_DELEGATION_CHAIN_DEPTH to 8, which brings a deep chain's wire size close to MAX_PROOF_BUNDLE_BYTES. The two are independent ceilings that can bind near the same point: a chain within the depth limit can still exceed the byte limit when hops carry many scopes or several resource_path constraints, and the decoder then rejects it for size (reported as the existing invalid status) before depth is evaluated, not as chain_too_deep. Added a §5.1 guidance note so operators budget for worst-case per-certificate content, not depth alone, and updated the existing alpha.16 "Input bounds" changelog bullet to match. Signed-off-by: chuks <891251+chuks@users.noreply.github.com> --- CHANGELOG.md | 2 +- SPEC.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c4c6d..2dc9ab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ The "resource-bound authority" release: delegations can now name *where* a scope - **`resource_path` constraint** (SPEC §5.7.2, §5.7.3): binds a delegation to an opaque `resource_id` (exact byte equality, never dereferenced or normalized) and an optional `path_prefix` under segment-boundary matching — deliberately a prefix, not a glob. Absolute logical POSIX-style path model with dot-segments, backslashes, and empty interior segments rejected outright; percent-encoding does not exist in the path model, and post-verification path transformation is forbidden. NFC pre-normalization is the issuer's obligation; the verifier compares bytes exactly (a mixed-form pair fails closed; byte identity, not visual identity, is the boundary). Chain evaluation is conjunctive: effective authority can stay the same or narrow but never widen (a child may carry a broader prefix on the same resource and still verify, gaining nothing because every upstream constraint still applies), and jointly unsatisfiable constraint sets — different resources, or same-resource prefixes that don't nest — must be rejected at issuance (decoders still accept them; verification fails closed). - **Resource-identifier profiles** (SPEC §5.7.4, `docs/RESOURCE_PROFILES.md`): the shared recipes that make an opaque `resource_id` interoperable. Git profile v1 (repository identity — never a branch, commit, or checkout; renames and transfers fail closed) with known-answer and negative vectors. Profiles for platform-owned resources are authored by the platforms themselves and linked when published. - **Extension-constraint `params`** (SPEC §5.7.1, §17.7): parameterized extension constraints are now representable in signed certificates under a restricted, cross-language-deterministic value model. Type-only extension constraints serialize exactly as before; existing signed certs remain byte-stable. Closes the wire-format limitation documented in alpha.15. -- **Input bounds** (SPEC §5.1): `MAX_PROOF_BUNDLE_BYTES` (128 KiB, enforced before parsing), `MAX_JSON_NESTING_DEPTH`, and per-cert scope/constraint count and length limits. Violations route to the existing `invalid` status. +- **Input bounds** (SPEC §5.1): `MAX_PROOF_BUNDLE_BYTES` (128 KiB, applied to the received wire representation and enforced before parsing), `MAX_JSON_NESTING_DEPTH`, and per-cert scope/constraint count and length limits. Violations route to the existing `invalid` status. §5.1 also notes that the byte ceiling and `MAX_DELEGATION_CHAIN_DEPTH` are independent and can bind near the same point: a chain within the depth limit can still be rejected for exceeding `MAX_PROOF_BUNDLE_BYTES` before depth is evaluated, so operational depth choices should budget for worst-case per-certificate content. - **Conformance suite** grows from 63 to 79 canonical vectors: 16 new verify-kind fixtures (14 `resource_path` accept/deny/unverifiable/narrowing/escape/traversal/percent-literal/root/trailing-slash/whole-resource/unsatisfiable-pair, 1 extension-`params`, 1 depth-8), with `reject_chain_too_deep` regenerated at depth 9. Byte-identical across all five SDKs. - **`VerifierContext` resource fields** (SPEC §5.16): `RequestedResourceID`, `RequestedPath`, `HasResource`, with the standard fail-closed absence semantics. - **Confinement guidance** (SPEC §15.7): a verified `resource_path` is lexical authorization, not filesystem confinement. Stated as normative properties rather than a prescribed mechanism: the deployment states its concurrent-mutation attacker model; a confinement or policy refusal leaves no operation-created effect inside or outside the boundary (with identity-safe cleanup that never touches objects a concurrent principal substituted); execution causes no effect outside the boundary; write atomicity is a separate contract; and refusal tests must attribute effects to the operation rather than assert blanket snapshot equality. Descriptor-relative traversal is the illustrative mechanism, not a mandate. diff --git a/SPEC.md b/SPEC.md index 6427f0f..e00a6d3 100644 --- a/SPEC.md +++ b/SPEC.md @@ -107,6 +107,8 @@ All structures are JSON objects serialized in canonical form (see §6). **Depth ceiling semantics.** `MAX_DELEGATION_CHAIN_DEPTH` is the protocol ceiling — a wire-determinism and denial-of-service bound, not a cryptographic limit. Principals who want shorter chains bound them per-delegation; a future canonical `max_delegation_depth` constraint is planned for that purpose. (The ceiling was 3 through v1.0.0-alpha.15; multi-hop agent topologies motivated raising it to 8.) +**Interaction of size and depth limits (guidance).** `MAX_PROOF_BUNDLE_BYTES` and `MAX_DELEGATION_CHAIN_DEPTH` are independent ceilings. The byte limit applies to the received wire representation and is enforced before parsing or verification. Bundle size grows with both chain depth and per-certificate content, including scopes and constraints, so a chain within the depth ceiling can still exceed the byte ceiling. In that case, the decoder rejects the bundle for exceeding `MAX_PROOF_BUNDLE_BYTES` before chain depth is evaluated; verification entry points report the violation using the existing `invalid` status rather than `chain_too_deep`. Deployments choosing an operational chain-depth limit SHOULD budget for worst-case per-certificate content, not depth alone. + ### 5.2 HybridPublicKey Every public key in the protocol is a pair: one Ed25519 component and one ML-DSA-65 component. Canonical JSON form (keys in lex order): From d0b959a5c2eb65cf53fecbd2effba5d9990d735b Mon Sep 17 00:00:00 2001 From: chuks <891251+chuks@users.noreply.github.com> Date: Sat, 1 Aug 2026 11:01:03 -0700 Subject: [PATCH 2/2] =?UTF-8?q?spec:=20make=20the=20=C2=A75.1=20size/depth?= =?UTF-8?q?=20note=20cross-SDK=20accurate=20on=20result=20behavior?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The paragraph said "verification entry points report the violation using the existing invalid status," which over-generalizes: the Go, TypeScript, Python, and Rust wire decoders reject oversized input as a decode error, and their verifier APIs take an already-decoded bundle and never observe the wire size; only a wire-facing verification surface (the C ABI) maps the decode failure to an invalid result. Reworded to attribute the rejection to the wire decoder and scope the invalid-status statement to wire-facing verification surfaces. Also changed "worst-case per-certificate content" to "maximum expected per-certificate content," which is the operationally useful budget. Documentation only. Signed-off-by: chuks <891251+chuks@users.noreply.github.com> --- CHANGELOG.md | 2 +- SPEC.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dc9ab2..af3142e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ The "resource-bound authority" release: delegations can now name *where* a scope - **`resource_path` constraint** (SPEC §5.7.2, §5.7.3): binds a delegation to an opaque `resource_id` (exact byte equality, never dereferenced or normalized) and an optional `path_prefix` under segment-boundary matching — deliberately a prefix, not a glob. Absolute logical POSIX-style path model with dot-segments, backslashes, and empty interior segments rejected outright; percent-encoding does not exist in the path model, and post-verification path transformation is forbidden. NFC pre-normalization is the issuer's obligation; the verifier compares bytes exactly (a mixed-form pair fails closed; byte identity, not visual identity, is the boundary). Chain evaluation is conjunctive: effective authority can stay the same or narrow but never widen (a child may carry a broader prefix on the same resource and still verify, gaining nothing because every upstream constraint still applies), and jointly unsatisfiable constraint sets — different resources, or same-resource prefixes that don't nest — must be rejected at issuance (decoders still accept them; verification fails closed). - **Resource-identifier profiles** (SPEC §5.7.4, `docs/RESOURCE_PROFILES.md`): the shared recipes that make an opaque `resource_id` interoperable. Git profile v1 (repository identity — never a branch, commit, or checkout; renames and transfers fail closed) with known-answer and negative vectors. Profiles for platform-owned resources are authored by the platforms themselves and linked when published. - **Extension-constraint `params`** (SPEC §5.7.1, §17.7): parameterized extension constraints are now representable in signed certificates under a restricted, cross-language-deterministic value model. Type-only extension constraints serialize exactly as before; existing signed certs remain byte-stable. Closes the wire-format limitation documented in alpha.15. -- **Input bounds** (SPEC §5.1): `MAX_PROOF_BUNDLE_BYTES` (128 KiB, applied to the received wire representation and enforced before parsing), `MAX_JSON_NESTING_DEPTH`, and per-cert scope/constraint count and length limits. Violations route to the existing `invalid` status. §5.1 also notes that the byte ceiling and `MAX_DELEGATION_CHAIN_DEPTH` are independent and can bind near the same point: a chain within the depth limit can still be rejected for exceeding `MAX_PROOF_BUNDLE_BYTES` before depth is evaluated, so operational depth choices should budget for worst-case per-certificate content. +- **Input bounds** (SPEC §5.1): `MAX_PROOF_BUNDLE_BYTES` (128 KiB, applied to the received wire representation and enforced before parsing), `MAX_JSON_NESTING_DEPTH`, and per-cert scope/constraint count and length limits. Violations route to the existing `invalid` status. §5.1 also notes that the byte ceiling and `MAX_DELEGATION_CHAIN_DEPTH` are independent and can bind near the same point: a chain within the depth limit can still be rejected by the wire decoder for exceeding `MAX_PROOF_BUNDLE_BYTES` before depth is evaluated, so operational depth choices should budget for the deployment's maximum expected per-certificate content. - **Conformance suite** grows from 63 to 79 canonical vectors: 16 new verify-kind fixtures (14 `resource_path` accept/deny/unverifiable/narrowing/escape/traversal/percent-literal/root/trailing-slash/whole-resource/unsatisfiable-pair, 1 extension-`params`, 1 depth-8), with `reject_chain_too_deep` regenerated at depth 9. Byte-identical across all five SDKs. - **`VerifierContext` resource fields** (SPEC §5.16): `RequestedResourceID`, `RequestedPath`, `HasResource`, with the standard fail-closed absence semantics. - **Confinement guidance** (SPEC §15.7): a verified `resource_path` is lexical authorization, not filesystem confinement. Stated as normative properties rather than a prescribed mechanism: the deployment states its concurrent-mutation attacker model; a confinement or policy refusal leaves no operation-created effect inside or outside the boundary (with identity-safe cleanup that never touches objects a concurrent principal substituted); execution causes no effect outside the boundary; write atomicity is a separate contract; and refusal tests must attribute effects to the operation rather than assert blanket snapshot equality. Descriptor-relative traversal is the illustrative mechanism, not a mandate. diff --git a/SPEC.md b/SPEC.md index e00a6d3..4ad238c 100644 --- a/SPEC.md +++ b/SPEC.md @@ -107,7 +107,7 @@ All structures are JSON objects serialized in canonical form (see §6). **Depth ceiling semantics.** `MAX_DELEGATION_CHAIN_DEPTH` is the protocol ceiling — a wire-determinism and denial-of-service bound, not a cryptographic limit. Principals who want shorter chains bound them per-delegation; a future canonical `max_delegation_depth` constraint is planned for that purpose. (The ceiling was 3 through v1.0.0-alpha.15; multi-hop agent topologies motivated raising it to 8.) -**Interaction of size and depth limits (guidance).** `MAX_PROOF_BUNDLE_BYTES` and `MAX_DELEGATION_CHAIN_DEPTH` are independent ceilings. The byte limit applies to the received wire representation and is enforced before parsing or verification. Bundle size grows with both chain depth and per-certificate content, including scopes and constraints, so a chain within the depth ceiling can still exceed the byte ceiling. In that case, the decoder rejects the bundle for exceeding `MAX_PROOF_BUNDLE_BYTES` before chain depth is evaluated; verification entry points report the violation using the existing `invalid` status rather than `chain_too_deep`. Deployments choosing an operational chain-depth limit SHOULD budget for worst-case per-certificate content, not depth alone. +**Interaction of size and depth limits (guidance).** `MAX_PROOF_BUNDLE_BYTES` and `MAX_DELEGATION_CHAIN_DEPTH` are independent ceilings. The byte limit applies to the received wire representation and is enforced before parsing or verification. Bundle size grows with both chain depth and per-certificate content, including scopes and constraints, so a chain within the depth ceiling can still exceed the byte ceiling. In that case, the wire decoder rejects the bundle for exceeding `MAX_PROOF_BUNDLE_BYTES` before chain depth is evaluated. A wire-facing verification surface that represents decode failures as a verification result uses the existing `invalid` status, not `chain_too_deep`. Deployments choosing an operational chain-depth limit SHOULD budget for their maximum expected per-certificate content, not depth alone. ### 5.2 HybridPublicKey