diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-28 15:48:04 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-28 15:48:04 +0200 |
| commit | 5330896c0e8023053d4cd15961b2ae0482686ca6 (patch) | |
| tree | e20b35069d4a7a87b1271e9063adb6a5c8e1b157 /packages/meshbay-node | |
| parent | 0584daa4b77048712c42fa113e77efdd31fc0336 (diff) | |
| download | meshbay-5330896c0e8023053d4cd15961b2ae0482686ca6.tar.gz | |
fix: refuse an unsigned handshake challenge
Every node the 4.0 floor admits signs its challenge, and one without a
channel binding could not complete the proof anyway, so a missing
signature is refused like a wrong one (browser and QUIC client).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/transport/quic_client.py | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/transport/quic_client.py b/packages/meshbay-node/src/meshbay_node/transport/quic_client.py index 8f3fb74..d548103 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/quic_client.py +++ b/packages/meshbay-node/src/meshbay_node/transport/quic_client.py @@ -212,16 +212,19 @@ class QuicChunkClient: "session — refusing to handshake without channel binding") binding = quic_binding(self._peer_cert_der) - # MNP 3.4: a signed challenge proves the node key before we send anything - # else. A wrong signature is refused; an absent one is an older node. - if reply.get("sig"): - try: - Ed25519PublicKey.from_public_bytes( - base64.b64decode(reply.get("node_pk", "")) - ).verify(base64.b64decode(reply["sig"]), challenge_transcript( - self._group_id, nonce_c, nonce_s, binding)) - except Exception as exc: - raise ConnectionError(f"Node challenge signature invalid: {exc}") from exc + # A signed challenge proves the node key before we send anything else. + # Every node we can reach signs (the floor is 4.0, signing is 3.4), and + # one without a certificate to bind could not complete the proof anyway, + # so a missing signature is refused like a wrong one. + if not reply.get("sig"): + raise ConnectionError("Node challenge is not signed") + try: + Ed25519PublicKey.from_public_bytes( + base64.b64decode(reply.get("node_pk", "")) + ).verify(base64.b64decode(reply["sig"]), challenge_transcript( + self._group_id, nonce_c, nonce_s, binding)) + except Exception as exc: + raise ConnectionError(f"Node challenge signature invalid: {exc}") from exc self._proto._send(self._ctrl_stream, { "type": MNP.HANDSHAKE_RESPONSE, |