|
| 1 | +# CAP-01 - Capability Grammar |
| 2 | + |
| 3 | +<details> |
| 4 | + <summary>Metadata</summary> |
| 5 | + <dl> |
| 6 | + <dt>Status:</dt><dd>Draft</dd> |
| 7 | + <dt>Edition:</dt><dd>2025-09-02</dd> |
| 8 | + <dt>Extends:</dt><dd>-</dd> |
| 9 | + <dt>Updates:</dt><dd>-</dd> |
| 10 | + <dt>Obsoletes:</dt><dd>-</dd> |
| 11 | + <dt>Depends on:</dt><dd>SIGCHAIN-01, RSC-01, PRIVACY-01</dd> |
| 12 | + </dl> |
| 13 | +</details> |
| 14 | + |
| 15 | +## Abstract |
| 16 | + |
| 17 | +CAP-01 defines the portable, verifiable capability model used by Polykey to express delegated authority. It specifies the structure and semantics of Grants (capability tokens) and Presentations (ephemeral proofs of capability), including verbs, resource addressing, binding constraints, attenuation, and revocation. CAP-01 ensures capabilities are composable, attenuable (never broadened), and safely enforceable at CEPs (Capability Enforcement Points), producing settlement-grade receipts (RSC-01). |
| 18 | + |
| 19 | +## Terminology |
| 20 | + |
| 21 | +- Principal (P): Originator of authority; issues a Grant to a Subject. |
| 22 | +- Subject (S): Holder that exercises the capability by creating a Presentation. |
| 23 | +- Resource (R): Target of the action; may host a native CEP (CEP(R)). |
| 24 | +- CEP: Capability Enforcement Point at P/S/R that verifies Presentations and enforces capabilities (writes the Access PoAR). |
| 25 | +- Grant (G): A signed, portable capability issued by P to S. |
| 26 | +- Presentation (Π): An ephemeral, proof-of-possession token created by S that references a Grant with context and channel binding. Not stored on-chain. |
| 27 | +- Bind: Binding constraints inside a Grant that restrict its use (audience, purpose, time, context, etc.). |
| 28 | +- Attenuation: Narrowing a capability when delegating; derived Grants must be a subset of their parent capability. |
| 29 | +- Verification (Σ): The verification handshake at the enforcing CEP. `Σ = verify(Π, G, Bind, Channel, TTL, Attenuation?, Lease?)` |
| 30 | +- Lease: The upstream authority relationship to a non-native SoA; referenced via leaseRef in PoAR (RSC-01). |
| 31 | +- PoAR: Proof-of-Action receipt written by the enforcing CEP (RSC-01). |
| 32 | + |
| 33 | +## Overview and Goals |
| 34 | + |
| 35 | +CAP-01 provides: |
| 36 | + |
| 37 | +- A minimal, expressive grammar for capabilities (verbs over resources with constraints). |
| 38 | +- A binding system (Bind) to tie capability use to audience, purpose, context, and time. |
| 39 | +- A safe delegation model: capabilities can be attenuated and re-delegated without ever broadening power. |
| 40 | +- A secure, ephemeral Presentation that is resistant to theft and replay (PoP + channel binding). |
| 41 | +- Clear interoperability with CEP enforcement and receipt minting (RSC-01). |
| 42 | + |
| 43 | +Design goals: |
| 44 | + |
| 45 | +- Portable: Grants and Presentations are verifiable across boundaries. |
| 46 | +- Minimal: Core fields are few and clearly defined; extensions via vocabularies. |
| 47 | +- Attenuable: Derived Grants must shrink authority; verifiable at enforcement. |
| 48 | +- Secure by default: Holder-of-key + channel binding; short TTLs for Presentations. |
| 49 | +- Receipt-ready: CEPS capture a bind_snapshot in PoAR. |
| 50 | + |
| 51 | +## Verbs and Resources |
| 52 | + |
| 53 | +### Verb grammar |
| 54 | + |
| 55 | +Verbs are strings, recommended namespaced for clarity: |
| 56 | + |
| 57 | +- Format: namespace:verb or domain:action |
| 58 | + - Examples: |
| 59 | + - deploy:to_env |
| 60 | + - access:open |
| 61 | + - energy:curtail |
| 62 | + - secret:read, secret:derive |
| 63 | + - data:export, model:infer |
| 64 | + |
| 65 | +Verb semantics must be documented in a public or private registry (with versioned definitions). TAP profiles may whitelist verb sets per domain. |
| 66 | + |
| 67 | +### Resource addressing |
| 68 | + |
| 69 | +Resources are URIs or URI-like identifiers with scheme-specific rules: |
| 70 | + |
| 71 | +- `k8s://ns/prod` |
| 72 | +- `door:building-12:lock-3` |
| 73 | +- `meter:utility:site-42` |
| 74 | +- `api:https://api.vendor.com/path` |
| 75 | +- `vault:secret://org/team/service/key-id` |
| 76 | + |
| 77 | +TAP profiles may restrict acceptable schemes per domain and verb. |
| 78 | + |
| 79 | +## Grant Structure and Rules |
| 80 | + |
| 81 | +A Grant is a signed claim on P's sigchain that authorizes S to perform actions (verbs) on resources, subject to Bind constraints. |
| 82 | + |
| 83 | +Required fields: |
| 84 | + |
| 85 | +- id: opaque identifier (hash of canonicalized claim) |
| 86 | +- type: "grant" |
| 87 | +- issuer: DID of P |
| 88 | +- subject: DID of S |
| 89 | +- action: verb (string) |
| 90 | +- resource: resource URI |
| 91 | +- bind: Bind object (Section 5) |
| 92 | +- expiry: timestamp (notAfter) |
| 93 | +- prev: previous claim hash (sigchain link) |
| 94 | +- sig: signature by issuer's key |
| 95 | + |
| 96 | +Normative rules: |
| 97 | + |
| 98 | +- Grants MUST be written on the issuer's (P's) sigchain. |
| 99 | +- expiry MUST be present and enforced; Presentations beyond expiry are invalid. |
| 100 | +- action/resource MUST be specific; wildcards SHOULD be avoided unless constrained by Bind. |
| 101 | +- bind MUST be enforceable by CEPs and included in the PoAR bind_snapshot. |
| 102 | +- A Grant MAY be revoked (Section 8). |
| 103 | + |
| 104 | +Minimal JSON skeleton: |
| 105 | + |
| 106 | +```json |
| 107 | +{ |
| 108 | + "type": "grant", |
| 109 | + "id": "hash(...)", |
| 110 | + "issuer": "did:pk:P", |
| 111 | + "subject": "did:pk:S", |
| 112 | + "action": "deploy:to_env", |
| 113 | + "resource": "k8s://ns/prod", |
| 114 | + "bind": { ... }, |
| 115 | + "expiry": "2025-09-10T10:00:00Z", |
| 116 | + "prev": "hash(prev)", |
| 117 | + "sig": "..." |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +Bind constrains how a capability may be exercised. CEPs MUST enforce Bind and include a bind_snapshot in PoAR. |
| 122 | + |
| 123 | +Recommended fields: |
| 124 | + |
| 125 | +- audience: list of DIDs of acceptable enforcers (e.g., ["did:pk:P","did:pk:R"]) |
| 126 | +- purpose: semantic hash or descriptor of intent (e.g., hash of artifact H, “door-visit-123”) |
| 127 | +- context: structured k/v describing runtime context (e.g., `{"pod":"runner-xyz","ns":"ci"}`) |
| 128 | +- time_window: `{ notBefore, notAfter }` narrower than Grant expiry |
| 129 | +- ttl: maximum Presentation TTL (e.g., "120s") |
| 130 | +- maxUses: optional counter for total uses (enforced by CEP capable of maintaining state) |
| 131 | +- geofence / net: optional constraints (e.g., CIDR, region, location) |
| 132 | + |
| 133 | +Subset rule (for attenuation, Section 6): child.bind MUST be a subset (narrower or equal) of parent.bind on every dimension (audience, purpose scope, time, ttl, etc.). |
| 134 | + |
| 135 | +```json |
| 136 | +"bind": { |
| 137 | + "audience": ["did:pk:P"], |
| 138 | + "purpose": "sha256:artifact-H", |
| 139 | + "context": { "ns": "prod", "app": "web" }, |
| 140 | + "time_window": { "notBefore": "2025-09-10T09:00:00Z", "notAfter": "2025-09-10T10:00:00Z" }, |
| 141 | + "ttl": "120s" |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +## Attenuation and Delegation |
| 146 | + |
| 147 | +A capability MAY be delegated by S to S2 by issuing a derived Grant on the delegator's sigchain, provided: |
| 148 | + |
| 149 | +- The derived Grant's action/resource are identical or narrower (subset). |
| 150 | +- The derived Grant's bind is a subset of the parent Grant's bind on all dimensions. |
| 151 | +- The chain of custody (P → S → S2) is provable via sigchains. |
| 152 | +- No broadening: delegation MUST NOT increase the set of allowed enforcers, time, scope, or resource coverage. |
| 153 | + |
| 154 | +Normative subset checks (examples): |
| 155 | + |
| 156 | +- `time_window.child` ⊆ `time_window.parent` |
| 157 | +- `audience.child` ⊆ `audience.parent` |
| 158 | +- `ttl.child` ≤ `ttl.parent` |
| 159 | +- `resource.child` narrower (e.g., specific door vs building-wide) |
| 160 | +- `purpose.child` equals or narrower (e.g., same artifact hash or a stricter descriptor) |
| 161 | + |
| 162 | +CEPs SHOULD verify chain attenuation if presented with a chain (Grant_ref may include a chain; otherwise, single-hop P→S is verified). |
| 163 | + |
| 164 | +## Presentation |
| 165 | + |
| 166 | +A Presentation is an ephemeral proof by S that it holds a Grant and is using it now, in this context, on this channel. Presentations are NOT written to sigchains. |
| 167 | + |
| 168 | +Required fields: |
| 169 | +- grant_ref: hash of Grant (or terminal of a chain) |
| 170 | +- holder: DID of S |
| 171 | +- pop_sig: signature by S’s private key over the presentation payload |
| 172 | +- channelBinding: exporter-derived key for the live TLS/mTLS session (or equivalent) |
| 173 | +- ctx: runtime context (subset of bind.context) |
| 174 | +- ttl: small (e.g., 120s) |
| 175 | +- nonce: unique value to prevent replay |
| 176 | + |
| 177 | +Normative rules: |
| 178 | +- Presentations MUST be bound to holder’s key (PoP) and to the transport/session (channelBinding). |
| 179 | +- Presentation ttl MUST be enforced by CEPs. |
| 180 | +- Presentations MUST include binding to Grant_ref and context; CEPs MUST check bind subset. |
| 181 | +- CEPs MUST reject Presentations beyond Grant expiry or outside bind.time_window. |
| 182 | + |
| 183 | +Minimal JSON skeleton (often conveyed as a signed JWT/DSSE): |
| 184 | +``` |
| 185 | +{ |
| 186 | + "type": "presentation", |
| 187 | + "grant_ref": "hash(G)", |
| 188 | + "holder": "did:pk:S", |
| 189 | + "channelBinding": "base64url(exporter)", |
| 190 | + "ctx": { "ns": "ci", "pod": "runner-xyz" }, |
| 191 | + "ttl": "120s", |
| 192 | + "nonce": "uuid-...", |
| 193 | + "pop_sig": "sig_by_S" |
| 194 | +} |
| 195 | +``` |
| 196 | + |
| 197 | +## 8. Revocation and rotation |
| 198 | + |
| 199 | +### 8.1 Revocation |
| 200 | +A Grant MAY be revoked by its issuer with a signed revocation claim on P’s sigchain: |
| 201 | +- type: "revoke", target: grant_id/hash(G), reason(optional), time, sig |
| 202 | +- CEPs MUST check for revocation before enforcing. |
| 203 | +- ViewReceipts SHOULD include knowledge of revocation state at time of action (via bind_snapshot + revocation check in PoAR). |
| 204 | + |
| 205 | +### 8.2 Rotation |
| 206 | +For secret-bound flows (PS-BA/SS-BA), upstream leases and secrets MUST be rotated per TAP policy. PoAR includes leaseRef (freshness proof). Rotation receipts may be recorded per SIGCHAIN-01 (optional). |
| 207 | + |
| 208 | +## 9. CEP enforcement (normative algorithm) |
| 209 | + |
| 210 | +Given a Presentation p from S and an asserted Grant G: |
| 211 | +1) Verify issuer signature of G (P’s sigchain), subject DID, action/resource. |
| 212 | +2) Check expiry and revocation of G. |
| 213 | +3) Verify Presentation: |
| 214 | + - pop_sig by holder S |
| 215 | + - channelBinding matches live session (mTLS/DPoP) |
| 216 | + - ttl within bind.ttl and current time within bind.time_window |
| 217 | + - ctx consistent and bind subset satisfied |
| 218 | +4) If Grant is a derived chain: verify attenuation (child bind/resource/action ⊆ parent). |
| 219 | +5) If enforcement passes, enforce per placement/mode and write PoAR: |
| 220 | + - Include bind_snapshot (canonical copy of bind at enforcement), cepRef, exposureMode, time_source, requestDigest (if mediate). |
| 221 | + - Deliver PoAR to S. |
| 222 | +6) If any check fails, mint DenyReceipt with reason_code and deliver to S. |
| 223 | + |
| 224 | +## 10. Security considerations |
| 225 | + |
| 226 | +- Holder-of-key (PoP) + channel binding prevent token theft and replay. |
| 227 | +- Presentations MUST be short-lived; CEPs SHOULD reject stale nonces (optional stateful defense). |
| 228 | +- Bind MUST be enforced; failure to snapshot bind in PoAR weakens auditability. |
| 229 | +- Delegation MUST be attenuating; TAP SHOULD disallow broadening by policy. |
| 230 | +- Reveal is dangerous; exposureMode="reveal" MUST follow strict TAP guardrails (tiny ttl/scope, dual-control, immediate revoke/rotate). |
| 231 | +- Privacy: Do not include raw PII in Grants/Presentations; use DIDs and contextual claims; ViewReceipts handle selective disclosure. |
| 232 | + |
| 233 | +## 11. Examples (JSON) |
| 234 | + |
| 235 | +Grant (P → S; deploy to prod for artifact H) |
| 236 | +``` |
| 237 | +{ |
| 238 | + "type": "grant", |
| 239 | + "id": "hash(G)", |
| 240 | + "issuer": "did:pk:cmcdragonkai", |
| 241 | + "subject": "did:pk:ci-runner-prod-01", |
| 242 | + "action": "deploy:to_env", |
| 243 | + "resource": "k8s://ns/prod", |
| 244 | + "bind": { |
| 245 | + "audience": ["did:pk:cmcdragonkai"], |
| 246 | + "purpose": "sha256:artifact-H", |
| 247 | + "context": { "ns": "prod", "app": "web" }, |
| 248 | + "time_window": { "notBefore": "2025-09-10T09:00:00Z", "notAfter": "2025-09-10T10:00:00Z" }, |
| 249 | + "ttl": "120s" |
| 250 | + }, |
| 251 | + "expiry": "2025-09-10T10:00:00Z", |
| 252 | + "prev": "hash(prev)", |
| 253 | + "sig": "..." |
| 254 | +} |
| 255 | +``` |
| 256 | + |
| 257 | +Presentation (S → CEP) |
| 258 | + |
| 259 | +``` |
| 260 | +{ |
| 261 | + "type": "presentation", |
| 262 | + "grant_ref": "hash(G)", |
| 263 | + "holder": "did:pk:ci-runner-prod-01", |
| 264 | + "channelBinding": "base64url(exporter)", |
| 265 | + "ctx": { "ns": "prod", "pod": "runner-xyz" }, |
| 266 | + "ttl": "120s", |
| 267 | + "nonce": "b1b2c3-...", |
| 268 | + "pop_sig": "..." |
| 269 | +} |
| 270 | +``` |
| 271 | + |
| 272 | +## Revision history |
| 273 | + |
| 274 | +- 2025-09-02: Initial draft edition (holder-of-key + channel binding; Bind subset rules; attenuation; revocation; CEP enforcement algorithm; examples). |
| 275 | + |
| 276 | +Notes: |
| 277 | + |
| 278 | +- Registries (verbs, resource schemes) MAY be maintained as content-addressed vocabularies; TAP profiles SHOULD reference accepted vocab ids. |
| 279 | +- RSC-01 specifies how bind_snapshot, cepRef, exposureMode, leaseRef, and requestDigest appear in PoAR. |
| 280 | +- SIGCHAIN-01 and STORAGE-01 specify durability/archival; PRIVACY-01 covers ViewReceipts/redactions/crypto-erasure. |
0 commit comments