From 46fb878f8d875f90fee937e9f478143826d017cd Mon Sep 17 00:00:00 2001 From: "Morten V. Christiansen" Date: Sat, 25 Apr 2026 01:33:16 +0200 Subject: [PATCH] Document Phase 2.5 ownership and concurrency --- PHASE5_RUNBOOK.md | 26 +++++++++++++++++++------- Setup.md | 27 +++++++++++++++++++++++++++ Workplan.md | 19 +++++++++++++++++++ 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/PHASE5_RUNBOOK.md b/PHASE5_RUNBOOK.md index 17e90fb..90f0a9c 100644 --- a/PHASE5_RUNBOOK.md +++ b/PHASE5_RUNBOOK.md @@ -88,6 +88,17 @@ Notes: - Use `--cacert /home/user/chromecard/tls/phase2/ca.crt` for TLS verification in `curl`-based checks. - Raw VM-IP routing is not the validated path for the current prototype. +## Ownership And Concurrency + +- `k_proxy` is authoritative for session state. +- `k_server` is authoritative for the protected counter state. +- Sessions are in-memory only in `k_proxy` and are lost on proxy restart. +- The protected counter is in-memory only in `k_server` and resets on server restart. +- Both services use `ThreadingHTTPServer`. +- `k_proxy` guards its session store with a single process-local lock. +- `k_server` guards counter increments with a single process-local lock. +- Qubes localhost forwarders are transport plumbing only; they are not a source of state authority. + ## Test Flow Use the proxy port that matches the mode you started: @@ -98,7 +109,7 @@ Use the proxy port that matches the mode you started: Create a session (runs auth gate once): ```bash -curl -sS -X POST http://127.0.0.1:/session/login \ +curl -sS --cacert /home/user/chromecard/tls/phase2/ca.crt -X POST https://127.0.0.1:/session/login \ -H 'Content-Type: application/json' \ -d '{"username":"alice"}' ``` @@ -112,30 +123,30 @@ TOKEN='' Check session: ```bash -curl -sS -X POST http://127.0.0.1:/session/status \ +curl -sS --cacert /home/user/chromecard/tls/phase2/ca.crt -X POST https://127.0.0.1:/session/status \ -H "Authorization: Bearer $TOKEN" ``` Call protected resource multiple times (should not require new login): ```bash -curl -sS -X POST http://127.0.0.1:/resource/counter \ +curl -sS --cacert /home/user/chromecard/tls/phase2/ca.crt -X POST https://127.0.0.1:/resource/counter \ -H "Authorization: Bearer $TOKEN" -curl -sS -X POST http://127.0.0.1:/resource/counter \ +curl -sS --cacert /home/user/chromecard/tls/phase2/ca.crt -X POST https://127.0.0.1:/resource/counter \ -H "Authorization: Bearer $TOKEN" ``` Logout/invalidate: ```bash -curl -sS -X POST http://127.0.0.1:/session/logout \ +curl -sS --cacert /home/user/chromecard/tls/phase2/ca.crt -X POST https://127.0.0.1:/session/logout \ -H "Authorization: Bearer $TOKEN" ``` Re-check after logout (should fail with 401): ```bash -curl -i -X POST http://127.0.0.1:/resource/counter \ +curl -i --cacert /home/user/chromecard/tls/phase2/ca.crt -X POST https://127.0.0.1:/resource/counter \ -H "Authorization: Bearer $TOKEN" ``` @@ -143,4 +154,5 @@ curl -i -X POST http://127.0.0.1:/resource/counter \ - This uses card-presence probing, not a full WebAuthn assertion verification path. - Intended as a Phase 5 starter for session semantics and proxy/server behavior. -- For the split-VM chain, the current blocker is not the Python prototype logic; it is refused `qubes.ConnectTCP` forwarding for the chain ports. +- Session and counter state are currently process-local only; restart loses state. +- Upstream trust still relies on a shared static `X-Proxy-Token`. diff --git a/Setup.md b/Setup.md index f914dc9..484ae49 100644 --- a/Setup.md +++ b/Setup.md @@ -277,6 +277,33 @@ Session note (2026-04-25, Phase 2 HTTPS bring-up): - second protected counter call returned value `2` - session status remained valid after reuse +Session note (2026-04-25, Phase 2.5 ownership and concurrency): +- Current prototype state ownership is now explicit: + - `k_proxy` is authoritative for session state + - `k_server` is authoritative for protected resource state + - `k_client` is not authoritative for either session validity or counter/resource state +- Current session model in `k_proxy`: + - server-side in-memory session store only + - opaque bearer token generated by `secrets.token_urlsafe(32)` + - per-session fields are `username` and `expires_at` + - expiry is enforced in `k_proxy`; `k_server` does not validate client sessions directly +- Current resource model in `k_server`: + - in-memory monotonic counter guarded by a lock + - access allowed only when request arrives from `k_proxy` with the expected `X-Proxy-Token` +- Current concurrency model in code: + - both services use `ThreadingHTTPServer` + - `k_proxy` protects session-map mutations and garbage collection with a single lock + - `k_server` protects counter increments with a single lock + - TLS verification and upstream fetches happen outside the session lock in `k_proxy` +- Current runtime assumptions and limits: + - Qubes localhost forwarders are treated as transport plumbing, not as state authorities + - if `k_proxy` restarts, in-memory sessions are lost + - if `k_server` restarts, the in-memory counter resets + - the current shared `X-Proxy-Token` is a prototype trust mechanism, not a final authorization design +- Practical meaning: + - race-free behavior is currently defined for session CRUD and counter increments inside one process per VM + - persistence, distributed session authority, and multi-proxy/multi-server coordination are not implemented yet + Session note (2026-04-25, in-VM forwarding test): - Tested the intended in-VM forwarding path with `qvm-connect-tcp` instead of host-side `qrexec-client-vm`. - Forwarders start and bind locally: diff --git a/Workplan.md b/Workplan.md index 8a33b30..80c13e6 100644 --- a/Workplan.md +++ b/Workplan.md @@ -130,6 +130,25 @@ Next action (2026-04-25): - localhost Qubes forwarders are part of the active runtime model for the two TLS hops - define concurrency assumptions and limits around session store, forwarders, and counter access +Status (2026-04-25): +- Current ownership model is now explicit: + - `k_proxy` is authoritative for session creation, expiry, lookup, and logout + - `k_server` is authoritative for the protected monotonic counter + - `k_client` is a client only; it holds bearer tokens but is not a state authority +- Current validation boundary is explicit: + - `k_proxy` validates bearer tokens against its in-memory session store + - `k_server` trusts only requests that arrive with the configured `X-Proxy-Token` + - `k_server` does not currently validate end-user session tokens directly +- Current concurrency strategy is explicit: + - `k_proxy` uses `ThreadingHTTPServer` plus one lock around the in-memory session map + - `k_server` uses `ThreadingHTTPServer` plus one lock around counter increments + - upstream HTTPS calls from `k_proxy` are made outside the session-store lock +- Current runtime limits are explicit: + - sessions are process-local and disappear on `k_proxy` restart + - counter state is process-local and resets on `k_server` restart + - transport relies on Qubes localhost forwarders `9771` and `9780` +- Phase 2.5 is complete for the current prototype shape. + ## Phase 3: Recover Basic Device Visibility on `k_proxy` (Blocking) 1. Verify physical + USB enumeration path.