[Docs/Code] TLS: Fingerprint-Confirm-Flow fehlt (Doc/Code-Drift) #14

Closed
opened 2026-08-24 14:58:35 +00:00 by ARIA · 1 comment
Owner

Doc/Code-Drift bei TLS. docs/09 §9.4 (Zeile ~57) behauptet: "self-signed → user confirms fingerprint on first pair, like a SSH host key". Das gibt es im Code nicht.

app/shared/src/commonMain/kotlin/iris/net/GatewayClient.kt:82-86 baut einen Default-OkHttpClient (kein sslSocketFactory, kein CertificatePinner, kein hostnameVerifier). Konsequenz:

  • LAN ohne TLS: egal.
  • Domain + gültiges CA-Zert: funktioniert out of the box.
  • Domain + self-signed Zert: Default-Client lehnt ab, es gibt KEIN Fingerprint-Confirm-UI. User müsste das Zert in den System-Trust-Store installieren.

Vorschlag (beides, nicht beides):

  • Entweder §9.4 umschreiben (Fingerprint-Confirm-Satz streichen) auf das, was der Code tut.
  • Oder den Confirm-Flow bauen, damit self-signed Zerts nutzbar sind.

Akzeptanz:

  • Doku und Code stimmen überein
  • Falls Confirm-Flow gebaut: self-signed Zert wird beim ersten Pairing per Fingerprint bestätigt und gepinnt
Doc/Code-Drift bei TLS. docs/09 §9.4 (Zeile ~57) behauptet: "self-signed → user confirms fingerprint on first pair, like a SSH host key". Das gibt es im Code nicht. app/shared/src/commonMain/kotlin/iris/net/GatewayClient.kt:82-86 baut einen Default-OkHttpClient (kein sslSocketFactory, kein CertificatePinner, kein hostnameVerifier). Konsequenz: - LAN ohne TLS: egal. - Domain + gültiges CA-Zert: funktioniert out of the box. - Domain + self-signed Zert: Default-Client lehnt ab, es gibt KEIN Fingerprint-Confirm-UI. User müsste das Zert in den System-Trust-Store installieren. Vorschlag (beides, nicht beides): - Entweder §9.4 umschreiben (Fingerprint-Confirm-Satz streichen) auf das, was der Code tut. - Oder den Confirm-Flow bauen, damit self-signed Zerts nutzbar sind. Akzeptanz: - Doku und Code stimmen überein - Falls Confirm-Flow gebaut: self-signed Zert wird beim ersten Pairing per Fingerprint bestätigt und gepinnt
ARIA added the bug label 2026-08-24 15:00:01 +00:00
ARIA self-assigned this 2026-08-24 15:00:18 +00:00
Author
Owner

Fixed by building the Confirm-Flow (commit 597a280). Self-signed gateway certs are now usable:

  • TlsPinning.kt: PinningTrustManager wraps the platform default trust manager — a rejected cert is accepted only when its SHA-256 fingerprint matches the user-confirmed pin; anything else fails with TlsFingerprintRequired (hostname verification still applies, so the cert needs a SAN for the URL host).
  • Pin stored in SecureStore.pinnedCertFingerprint (EncryptedSharedPreferences / desktop settings.json), wiped on forget().
  • GatewayClient: pinning socket factory on the shared client (all legs inherit it), new terminal State.TlsConfirmRequired, unwraps the nested exception in connect loop / watchdog / SSE / poll / testHello.
  • UI: ConnectScreen shows a "Confirm gateway certificate" dialog with the fingerprint ("Confirm & pin" re-runs the connect); a changed cert re-triggers the dialog, like a changed SSH host key.
  • Docs: §9.4 now describes the real flow (incl. SAN requirement), gap-table item 6 → implemented, setup.md note updated.
  • Tests: TlsPinningTest + TlsPinningIntegrationTest (real TLS handshake: unpinned → confirm data, pinned → 200). Full suites green (88 desktop + 83 Android host tests).

Live E2E verified on the phone: first pair against a self-signed IRIS_HTTP_CERT gateway → fingerprint dialog → confirm → chat works; auto-reconnect after a gateway restart uses the stored pin.

Fixed by building the Confirm-Flow (commit 597a280). Self-signed gateway certs are now usable: - `TlsPinning.kt`: `PinningTrustManager` wraps the platform default trust manager — a rejected cert is accepted only when its SHA-256 fingerprint matches the user-confirmed pin; anything else fails with `TlsFingerprintRequired` (hostname verification still applies, so the cert needs a SAN for the URL host). - Pin stored in `SecureStore.pinnedCertFingerprint` (EncryptedSharedPreferences / desktop settings.json), wiped on forget(). - `GatewayClient`: pinning socket factory on the shared client (all legs inherit it), new terminal `State.TlsConfirmRequired`, unwraps the nested exception in connect loop / watchdog / SSE / poll / testHello. - UI: ConnectScreen shows a "Confirm gateway certificate" dialog with the fingerprint ("Confirm & pin" re-runs the connect); a changed cert re-triggers the dialog, like a changed SSH host key. - Docs: §9.4 now describes the real flow (incl. SAN requirement), gap-table item 6 → implemented, setup.md note updated. - Tests: `TlsPinningTest` + `TlsPinningIntegrationTest` (real TLS handshake: unpinned → confirm data, pinned → 200). Full suites green (88 desktop + 83 Android host tests). Live E2E verified on the phone: first pair against a self-signed `IRIS_HTTP_CERT` gateway → fingerprint dialog → confirm → chat works; auto-reconnect after a gateway restart uses the stored pin.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ARIA/iris_x_hermes#14