summaryrefslogtreecommitdiffstats
path: root/docs/meshbay-draft-v5.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/meshbay-draft-v5.md')
-rw-r--r--docs/meshbay-draft-v5.md41
1 files changed, 29 insertions, 12 deletions
diff --git a/docs/meshbay-draft-v5.md b/docs/meshbay-draft-v5.md
index 0d64b0c..9e1ddb3 100644
--- a/docs/meshbay-draft-v5.md
+++ b/docs/meshbay-draft-v5.md
@@ -1,6 +1,6 @@
# MeshBay — Architecture Draft v5
-> Status: Phase 11.5 (security remediation) largely complete — see `devel-phases-next.md`.
+> Status: **Phase 11.5 (security remediation) complete.** See `devel-phases-next.md`.
> Supersedes `meshbay-draft-v4.md`. Sections not restated here are unchanged from v4.
>
> v5 exists because the second security review (`second-review.md`, 2026-08-13) found
@@ -58,7 +58,7 @@ This replaces the informal assurances scattered through v4 §4.2.x and §13.
| Chat content is unreadable | ✅ | ❌ H3 | ❌ plaintext at rest until Phase 15 | ❌ | ✅ |
| File index is unreadable | ✅ | ❌ H3 | ❌ | ❌ | ✅ |
| Content cannot be modified | ✅ | ✅ | ❌ by design | ✅ | ✅ |
-| Node cannot be impersonated | ✅ | ⚠️ pending 11.5.8 pinning | — | ✅ | ✅ |
+| Node cannot be impersonated | ✅ | ✅ | — | ✅ | ✅ |
| Client code integrity | ❌ **T3, accepted** | ❌ T3 | ✅ | ✅ | ✅ |
| Node content authority | ✅ | ✅ | ✅ sovereign | ✅ | ✅ |
@@ -89,7 +89,7 @@ means "end-to-end" here describes *client ↔ node*, never *client ↔ client*.
| Listener | Role | Status |
|---|---|---|
| **WebRTC DataChannel** (aiortc) | Primary, browser **and** native clients | Unified handshake enforced |
-| **QUIC** (aioquic) | LAN, port-forwarded, hub-less `group://` | Authorization shared; **GEK proof pending** |
+| **QUIC** (aioquic) | LAN, port-forwarded, hub-less `group://` | Unified handshake enforced |
| ~~TCP + TLS 1.3~~ | — | **Removed** (C6) |
| ~~HTTP file API~~ | — | **Removed** (C1) |
@@ -147,7 +147,7 @@ a missing fingerprint silently degraded it to nonce-only, dropping MitM detectio
| Transport | Anchor |
|---|---|
| WebRTC | both DTLS certificate fingerprints |
-| QUIC | SHA-256 of the server certificate — **unproven**, see 11.5.6. An RFC 5705 exporter would be stronger; aioquic does not currently expose one |
+| QUIC | SHA-256 of the server certificate. aioquic exposes no RFC 5705 exporter; the client's access to the peer certificate is a guarded private attribute, and on a **resumed** session — which carries no certificate — the anchor travels with the session ticket |
### 4.3 Authorization rules
@@ -163,8 +163,8 @@ with its long-term key. Previously the client received an unverifiable `node_pk`
trusted `is_node_admin` from whoever answered — so a peer that had hijacked signaling
could serve a forged index, forged chat history and forged permissions.
-**Still open (11.5.8):** the client verifies the signature but does not yet *pin* the
-key, so a substituted node is caught only by its lack of the GEK.
+The client also **pins** `pk_node` per node on first use (11.5.8) and refuses a changed
+key outright, with a deliberate reset path in Settings for a legitimate rotation.
---
@@ -308,18 +308,35 @@ format.
## 9. Open items
+**Phase 11.5 is complete.** All six critical and all seven high findings from
+`second-review.md` are closed, bounded, or deferred by explicit decision.
+
+### Closed since this document was drafted
+
+| # | Item | Closed by |
+|---|---|---|
+| **C6** | GEK proof on the QUIC path | QUIC now runs the same challenge/response as WebRTC — client nonce, role-bound transcript, GEK proof, and the node proving itself with a GEK proof plus an Ed25519 signature |
+| 11.5.6 | QUIC channel-binding anchor | Certificate hash. Server reads its own certificate from disk; the client's access to the peer certificate is guarded and fails loudly if aioquic moves it. **A resumed TLS session carries no certificate**, so the anchor travels with the session ticket — sound, because the ticket is derived from the handshake where the certificate was presented |
+| 11.5.8 | `pk_node` TOFU pinning | Pinned per `node_id` on first handshake; a change is **refused**, with a deliberate reset in Settings |
+| **M8** | Node announce proof-of-possession | Announcer signs `meshbay:node_announce:{user_id}:{pk_node}:{timestamp}`; re-announcing updates in place |
+
+### Still open
+
| # | Item | Status |
|---|---|---|
-| **C6** | GEK proof on the QUIC path | **Open** — authorization shared, proof pending. A forged token still injects chat over QUIC |
-| 11.5.6 | QUIC channel-binding anchor | Unproven — certificate hash vs RFC 5705 exporter |
-| 11.5.8 | `pk_node` TOFU pinning | Open |
-| 11.5.10 | Node announce proof-of-possession | Open |
-| **H3** | Hub key substitution | **Open** — fixed by Phase 12.1 safety numbers |
-| C4 | Remote keypair bundles | Bounded; closes in Phase 13.3 |
+| **H3** | Hub key substitution | **Open** — the last unfixed finding. The hub is the public-key directory, so it can be handed the GEK at invite time. Fixed by Phase 12.1 safety numbers |
+| C4 | Remote keypair bundles | Bounded (4 pre-proof fetches, audited); closes in Phase 13.3 when the native client stops storing them remotely |
| — | Chat encryption (Sender Keys) | Phase 15. Distribution must be **pairwise to identity keys**, never GEK-derived |
| — | Chat attachments | Plaintext on the node; decide in Phase 15.7 |
| **T3** | Hub serves the SPA | **Accepted permanently** (D1) |
+### Scope note on pinning
+
+With C6 closed, `pk_node` pinning is defence in depth rather than the primary control: a
+substituted node already fails the GEK proof. Pinning covers the case where an attacker
+*holds* the group key — an ex-member, or a leaked GEK — and swaps the node underneath,
+which the proof alone cannot distinguish from the genuine node.
+
### Sender Keys — scope correction
Sender Keys protects chat from someone holding the node's disk who is **not** a group