Commit Graph

4 Commits

Author SHA1 Message Date
Morten V. Christiansen 592af0c314 Guard against cross-server token replay in _verify_assertion_token
_verify_assertion_token now takes expected_host and rejects any token
whose bundle["host"] does not match — closing the cross-server replay
path where a token issued for server-a could have passed on server-b.

ServerState gains protected_host (default 127.0.0.1); k_server exposes
--protected-host CLI flag so operators declare which host they protect.

New abuse tests (unit + round-trip):
  test_cross_server_replay_rejected
  test_cross_server_replay_case_insensitive
  test_roundtrip_cross_server_replay_rejected
  test_roundtrip_cross_server_replay_accepted_on_correct_server

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 23:57:28 +02:00
Morten V. Christiansen 4b719a0846 Switch token binding from per-request URL+method to domain-level host+nonce
Challenge is now SHA256(host|nonce) instead of SHA256(url|method|nonce).
A single card interaction authorises access to any path and method on the
gated domain, which is the intended granularity. Tests updated accordingly:
path/method rejection cases replaced with domain-level and tampered-host cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 23:52:48 +02:00
Morten V. Christiansen 3fc40fc395 Implement per-request FIDO2 token binding across all components
Each request to a gated endpoint now triggers a fresh FIDO2 assertion.
Challenge = SHA256(url|method|nonce) — bound to the specific resource.
The self-contained assertion bundle lets the server verify independently
without calling back to the phone.

- fido2_ops.dart: GetAssertionResult gains clientDataJson; getAssertion
  accepts optional challenge override
- proxy_service.dart: _handleAuthGetToken accepts {url,method,nonce},
  derives challenge, runs card assertion, returns b64url bundle
- filter_proxy.dart: _getAuthToken(uri, method) generates nonce and
  passes binding fields to Component 2
- component3/phone.go: stateless GetTokenForRequest(url, method) —
  no session caching, no expiry, one card touch per request
- component3/proxy.go: use GetTokenForRequest
- component3/main.go: remove --user flag (Component 2 picks enrolled user)
- k_server_app.py: _verify_assertion_token() — verifies path+method
  match, challenge claim, and ECDSA-P256 signature; accepts both
  legacy X-Proxy-Token and new Bearer assertion tokens

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:01:23 +02:00
Morten V. Christiansen 83a6382270 Initial commit: chromecard workspace snapshot
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 22:06:14 +02:00