Skip to content

encryption: seeded deletable keys under apps/, depth rule, state guards - #436

Closed
samgbafa wants to merge 12 commits into
mainfrom
tc1777/n2b-deletable-keys
Closed

samgbafa wants to merge 12 commits into
mainfrom
tc1777/n2b-deletable-keys

Conversation

@samgbafa

@samgbafa samgbafa commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Named keys whose path starts with apps/ are deletable keys with a per-key random seed; every other path is a deterministic key. Served only while [global.encryption_network] named_keys_v1 is on (default off).

  • Path rule: a path whose first segment is exactly apps is apps/<app id>/<name> for a key and apps/<app id>/ for a prefix; apps, apps/<app id> and apps/ are refused in delegations and invocations. App ids match ^[a-z0-9][a-z0-9._-]{0,63}$.
  • Create body { keyPath, deletable }: deletable must equal the kind the path implies (400 key_path_invalid otherwise); unknown fields are refused.
  • Deletable keys: 32-byte seed from the OS random source, sealed with the column key into encryption_network_key.sealed_seed; secret = HKDF(ikm = HKDF-Extract(salt = seed, ikm = network secret), salt = tinycloud.encryption.named-key/v1, info = seeded\n + key URN). Known-answer vectors for both kinds. Seeds open only with the strict unseal; a deletable row that is not deleted and has no seed is a corrupt row.
  • Create, block and unblock run under the network row lock; block and unblock write only while the state is active or blocked and answer 403 key_deleted on a deleted row.
  • Create on a deleted deletable row reuses it with a new seed and keyVersion + 1; a decrypt for another keyVersion answers 403 key_deleted. Per-network and per-apps/<app id>/ (100) caps count deleted rows until they are reused.
  • Public key GET: every path under apps/ answers one 404 key_not_found. The authenticated GET returns kind and state.
  • A SIWE root that grants any ability other than key.block under apps/<app id> needs the app id bound to the SIWE domain and a SIWE scheme that is absent or https (app_id_not_bound); UCAN roots are not checked.
  • Startup refuses key rows under apps/ that are not deletable; the error carries the query that lists them. No data is deleted.
  • Docs: docs/encryption-named-keys.md.

Details: TC-1777

dryrun added 11 commits October 23, 2026 23:20
A key path whose first segment is exactly apps needs three segments for a key and two for a prefix. The kind of a key follows from its path. App ids are validated and can be checked against a host name.

Details: TC-1777
…m public GET under apps/

Deletable keys carry a sealed per-key seed opened only with the strict unseal. Create, block and unblock run under the network row lock and refuse deleted rows. Create reuses a deleted deletable row with a new seed and the next key version. The public GET answers one 404 for every path under apps/. A startup check refuses key rows under apps/ that are not deletable.

Details: TC-1777
… lock waits and startup refusal

Details: TC-1777
@samgbafa

Copy link
Copy Markdown
Contributor Author

APPROVE: see TC-1777 (reviewed exact head 4b1cc83)

@samgbafa

Copy link
Copy Markdown
Contributor Author

APPROVE: see TC-1777 (reviewed exact head 6a94e39)

@samgbafa

Copy link
Copy Markdown
Contributor Author

Included in #438 (merged as 58d4876, which carries the N2b commits of this PR, approved at 6a94e39). Closing as included.
Details: TC-1777

@samgbafa samgbafa closed this Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant