From ed9fb22ed703db38f9b07c00d17076f90aa4cbc8 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Thu, 13 Aug 2026 04:10:14 +0200 Subject: fix(node)!: remove unauthenticated HTTP file API and TCP transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 11.5.A — findings C1 and C6 (see second-review.md). C1: the per-group HTTP file API bound 0.0.0.0 for every configured group, private ones included, and served two endpoints with no authentication at all: GET /index (full Mesh Group Index) and GET /file/{id} (raw plaintext file via FileResponse). Anyone able to reach the port — LAN, forwarded port, permissive IPv6 — read every private file. This bypassed the entire GEK-proof and node sovereignty layer. Deleted rather than patched: it duplicated MNP without any of its controls. C6: the TCP+TLS chunk server accepted a bare JWT with no GEK proof, leaving a second non-compliant handshake path. Deleted; QUIC remains and will be brought to parity with WebRTC by the unified handshake in 11.5.4. Transport decision recorded in transport/__init__.py: WebRTC/ICE is primary for browser and native clients (the only NAT traversal validated here — 2 ISPs, IPv4 STUN + IPv6, 4G CGNAT); QUIC is kept for LAN, port-forwarded and hub-less group:// access. punch_nat() is a direct-connection helper, not a traversal stack. Also removed server_ssl_context()/client_ssl_context() from tls_cert.py (no remaining callers) and a dead import of the former in quic_server.py. generate_self_signed_cert() stays: QUIC uses it, and the certificate hash is the intended channel-binding anchor for 11.5.6, since QUIC has no DTLS fingerprint to bind the GEK proof to. BREAKING CHANGE: node.toml keys `port` and `http_port` are gone. Regenerate config with `meshbay-node init`. Env var MESHBAY_PORT -> MESHBAY_QUIC_PORT. Tests: 198 passed (209 - 7 test_http_server - 4 test_transport). No other test changed status. Net -1300 lines. Co-Authored-By: Claude Opus 5 --- .../src/meshbay_node/transport/tls_cert.py | 36 +++++----------------- 1 file changed, 8 insertions(+), 28 deletions(-) (limited to 'packages/meshbay-node/src/meshbay_node/transport/tls_cert.py') diff --git a/packages/meshbay-node/src/meshbay_node/transport/tls_cert.py b/packages/meshbay-node/src/meshbay_node/transport/tls_cert.py index 1354ac9..374fd08 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/tls_cert.py +++ b/packages/meshbay-node/src/meshbay_node/transport/tls_cert.py @@ -1,17 +1,18 @@ """ -Self-signed TLS certificate generation for the node. +Self-signed TLS certificate generation for the node's QUIC listener. The cert is used for transport confidentiality only. Node identity is verified via Ed25519 PK (from hub), not TLS cert chain. -Clients connect with ssl.CERT_NONE + verify Ed25519 at the MNP handshake layer. -Certificate is generated once and cached at ~/.config/meshbay/node_tls.pem/.key. +Phase 11.5 note: the certificate hash is also the intended channel-binding anchor for +the QUIC handshake proof (11.5.6), since QUIC has no DTLS fingerprint to bind to. + +Certificate is generated once and cached at ~/.config/meshbay/node_tls.crt/.key. """ import logging import os from pathlib import Path -import ssl import datetime import ipaddress @@ -69,27 +70,6 @@ def generate_self_signed_cert( return cert_path, key_path -def server_ssl_context( - cert_path: Path = DEFAULT_CERT, - key_path: Path = DEFAULT_KEY, -) -> ssl.SSLContext: - """SSL context for the node's TCP server.""" - if not cert_path.exists() or not key_path.exists(): - generate_self_signed_cert(cert_path, key_path) - - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) - ctx.load_cert_chain(certfile=cert_path, keyfile=key_path) - ctx.minimum_version = ssl.TLSVersion.TLSv1_3 - return ctx - - -def client_ssl_context() -> ssl.SSLContext: - """ - SSL context for clients connecting to a node. - CERT_NONE because we verify node identity via Ed25519 PK at the MNP layer. - """ - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - ctx.minimum_version = ssl.TLSVersion.TLSv1_3 - return ctx +# `server_ssl_context()` / `client_ssl_context()` were removed in Phase 11.5 along with +# the TCP+TLS transport they served. QUIC builds its own QuicConfiguration and calls +# generate_self_signed_cert() directly. -- cgit v1.2.3