5.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Repository policy
CR_SDK_CK-main/is the firmware SDK source tree. Treat it as read-only. Do not add or edit files there.- All host-side scripts live at the workspace root (
/home/user/chromecard). Setup.mdandWorkplan.mdare the canonical living docs. After each meaningful execution step, updateSetup.mdfor environment/runtime state andWorkplan.mdfor phase progress and next blocking action.
Running tests
# Python unit tests (no VMs or card required, 122 tests)
python3 -m unittest tests/test_k_proxy.py
# Playwright browser regression (requires services running and forwarded portal)
PORTAL_BASE_URL=http://127.0.0.1:18766 npm run test:k-client
# Split-VM end-to-end regression helper (runs from host via SSH into k_client)
./phase5_chain_regression.sh
./phase5_chain_regression.sh --interactive-card --expect-auth-mode fido2_assertion
Probing the card (on k_proxy)
python3 /home/user/chromecard/fido2_probe.py --list
python3 /home/user/chromecard/fido2_probe.py --json
python3 /home/user/chromecard/raw_ctap_probe.py info
python3 /home/user/chromecard/raw_ctap_probe.py make-credential --rp-id localhost
python3 /home/user/chromecard/webauthn_local_demo.py # opens http://localhost:8765
Generating TLS certificates
python3 generate_phase2_certs.py
# Writes tls/phase2/ca.crt, k_proxy.crt/.key, k_server.crt/.key
Starting services (split-VM shape)
k_server VM:
python3 /home/user/chromecard/k_server_app.py \
--host 127.0.0.1 --port 8780 \
--proxy-token dev-proxy-token \
--tls-certfile /home/user/chromecard/tls/phase2/k_server.crt \
--tls-keyfile /home/user/chromecard/tls/phase2/k_server.key
k_proxy VM:
qvm-connect-tcp 9780:k_server:8780
python3 /home/user/chromecard/k_proxy_app.py \
--host 127.0.0.1 --port 8771 --session-ttl 300 \
--server-base-url https://127.0.0.1:9780 \
--server-ca-file /home/user/chromecard/tls/phase2/ca.crt \
--proxy-token dev-proxy-token \
--tls-certfile /home/user/chromecard/tls/phase2/k_proxy.crt \
--tls-keyfile /home/user/chromecard/tls/phase2/k_proxy.key
# Add --auth-mode fido2-direct for real CTAP2 (default is probe mode)
k_client VM:
qvm-connect-tcp 9771:k_proxy:8771
python3 /home/user/chromecard/k_client_portal.py \
--proxy-base-url https://127.0.0.1:9771
# Browser demo page at http://127.0.0.1:8766
Files are deployed to VMs via scp <file> <host>:~ and run via ssh <host> <cmd>.
Architecture
Qubes 3-VM topology: k_client → k_proxy → k_server, each a Debian 13 AppVM.
Inter-VM transport uses qvm-connect-tcp localhost forwarding (not raw VM-IP routing). Validated chain:
k_client localhost:9771→k_proxy:8771k_proxy localhost:9780→k_server:8780
k_proxy_app.py — session gateway and FIDO2 auth bridge. Two auth modes:
probe(default): validates card presence by subprocess-callingfido2_probe.py --jsonfido2-direct: performs real CTAP2makeCredential/getAssertionagainst the physical card viapython-fido2; auto-detects the FIDO hidraw device
ProxyState holds all server-side state: in-memory session store (guarded by one lock), enrollment DB (JSON file), and an UpstreamPool of persistent TLS connections to k_server. Sessions are lost on restart.
k_server_app.py — protected resource backend. Exposes a monotonic counter behind X-Proxy-Token auth. Counter state is in-memory only; resets on restart. Lock guards counter increments.
k_client_portal.py — thin browser-facing portal in k_client. Delegates all auth and resource calls to k_proxy. Holds only a local preferred username; enrollment and session state live in k_proxy.
FIDO2 transport: Card communicates over USB HID (CTAPHID) on /dev/hidraw0 (FIDO interface, usage page 0xF1D0). /dev/hidraw1 is a separate vendor HID interface. If the card re-enumerates, k_proxy auto-detects the correct node. If CTAPHID stops responding, a full USB power cycle is the recovery path.
CardEmulator (tests/card_emulator.py) — software emulator of the card for unit tests. Implements make_credential/get_assertion with real P-256 crypto; user_confirms=False simulates card rejection. Wire it into tests by patching _with_direct_ctap2 and _drop_direct_device on ProxyState. See the module docstring for the exact patch pattern.
Key enrollment endpoints on k_proxy: POST /enroll/register, GET /enroll/status, POST /enroll/update, POST /enroll/delete, GET /enroll/list. Usernames are normalized to lowercase, 3–32 chars [a-z0-9._-].
Key session endpoints on k_proxy: POST /session/login, POST /session/status, POST /session/logout, POST /resource/counter.
Known limits and blockers
- Concurrency ceiling on the browser-facing forwarded path is ~10 in-flight requests; higher fan-out triggers Qubes vchan failures (
xs_transaction_start: No space left on device). - If CTAPHID
INITpackets get no reply after a card reattach, a full USB power cycle recovers the transport. CR_SDK_CK-mainis missing role directories (mvp,setup,components,samples) required for the firmware build/flash flow (./scripts/build_flash_mvp.sh).westandnrfjprogmust also be installed.- Phases 7 (firmware build) and 9 (phone-wireless transport) are externally gated.