Skip to content

lan-tls: the pod's LAN API over TLS, pinning, HTTPS-only - #41

Merged
wardviaene merged 4 commits into
mainfrom
lan-tls
Oct 16, 2026
Merged

wardviaene merged 4 commits into
mainfrom
lan-tls

Conversation

@wardviaene

@wardviaene wardviaene commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Client side of benchpod-firmware#55 (LAN API over TLS on 8443, firmware 3.9.3).

  • Transport (internal/tcpclient/tls.go): default port 8080 now tries TLS on 8443 first and falls back to plaintext only when 8443 refuses and nothing is pinned (old firmware keeps working); :8443 is TLS only; other ports and the USB network adapter (10.237.0.0/16) stay plaintext. --tls auto|on|off (BENCHPOD_TLS).
  • Trust: the pod certificate's SHA-256 is pinned on first use in ~/.config/benchpod-cli/known_pods.json (shared with the SDK); a different one is an error naming both fingerprints and benchpod lan-tls trust. --tls-ca (BENCHPOD_TLS_CA) verifies chain + name instead.
  • Commands: benchpod lan-tls [show [--pem]], https-only on|off, regenerate, set-cert --cert --key (checked locally, uploaded as OTA target tls, pin updated), trust [--sha256], forget.
  • README: Connection, LAN TLS section, command reference, global flags (docs coverage test passes).

Unit tests: dial plan, TOFU + mismatch + re-trust against a local TLS server, cert/key check. HW-tested, see below.

🤖 Generated with Claude Code

Hardware test (benchpod-a1f6f2, 2026-10-16, Ethernet + USB, no Wi-Fi)

  • TLS 1.2 on 8443, EC P-256 cert generated on first boot (CN/SAN ok). Full handshake 0.46 s (RSA 2048: 1.07 s), resumed ~20 ms (tickets + cache, added after the first run).
  • Heap ~22 KB per TLS session; third session reset; heap back on close.
  • set-cert EC + RSA (persist across reboot), regenerate, trust/forget, --tls-ca, pin mismatch: OK. Fixed: listener went dark after set-cert (rebind refused); now swapped in place.
  • HTTPS-only: on over plaintext; then plaintext 8080 on Ethernet reset, TLS + USB fine, persists across reboot, mDNS https_only=1; off over TLS, USB link and console; changes over plaintext Ethernet refused.
  • SDK e2e over TLS 84/0 (51 s), MCP e2e 7/0. Not tested: the cloud link with this build (a1f6f2 is not registered).

wardviaene and others added 4 commits October 16, 2026 10:41
Port 8443 is TLS only; the default port 8080 tries TLS on 8443 first and falls back to
plaintext only when 8443 refuses (firmware without LAN TLS) and nothing is pinned for the pod.
Other ports and the USB network adapter (10.237.0.0/16) stay plaintext. The pod's certificate
SHA-256 is pinned on first use in known_pods.json next to the CLI config; a different one is a
PinMismatchError. TLSCAFile verifies against given roots instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
benchpod lan-tls [show [--pem]] | https-only on|off | regenerate | set-cert --cert --key |
trust [--sha256] | forget, for the pod's LAN API over TLS (firmware 3.9.3+). set-cert checks
the pair here, uploads it as OTA target "tls" and updates the pin; regenerate updates the pin
from the reply. --tls auto|on|off (BENCHPOD_TLS) and --tls-ca (BENCHPOD_TLS_CA) pick the
transport and the trust. README: Connection, LAN TLS section, reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A full handshake costs the pod ~0.46 s; with the session cache later connections in the same
process resume in ~35 ms (HW: 476 ms, then 44/36/32 ms). TestTLSResumesOnThePod runs against a pod
when BENCHPOD_TLS_HW_ADDR is set. The rotation test's server disables tickets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each benchpod run is a new process, so every run paid the pod's full TLS handshake: 0.48 s per
command against 0.01 s plaintext (HW, a1f6f2). The ticket and its session state are saved in
tls_sessions.json next to the pins (0600, dropped after the pod's one-hour ticket lifetime, and
whenever a pin changes); later runs resume: 0.04-0.05 s per command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wardviaene
wardviaene marked this pull request as ready for review October 16, 2026 16:49
@wardviaene
wardviaene merged commit 4c53e33 into main Oct 16, 2026
2 checks passed
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