aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common/tests/test_handshake.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-23 17:14:26 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-23 17:14:26 +0200
commit339cb427f886a0177014126bb684335837eff067 (patch)
tree5f79dc0df617be66287a06fc4f0c5dcc61ceb167 /packages/meshbay-common/tests/test_handshake.py
parentcd85808c13926c89a97987d320ac26391eae3267 (diff)
downloadmeshbay-339cb427f886a0177014126bb684335837eff067.tar.gz
feat: the node signs its handshake challenge (MNP 3.4)
node_pk in handshake_challenge is now signed over the channel binding and both nonces, so a client can check the node key before a join rather than only at the ack. Both transports; the browser and the QUIC client refuse a wrong signature and treat an absent one as an older node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-common/tests/test_handshake.py')
-rw-r--r--packages/meshbay-common/tests/test_handshake.py20
1 files changed, 20 insertions, 0 deletions
diff --git a/packages/meshbay-common/tests/test_handshake.py b/packages/meshbay-common/tests/test_handshake.py
index 11313aa..ad615a9 100644
--- a/packages/meshbay-common/tests/test_handshake.py
+++ b/packages/meshbay-common/tests/test_handshake.py
@@ -13,6 +13,7 @@ import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.handshake import (
+ CHALLENGE_PREFIX,
HANDSHAKE_PREFIX,
NONCE_LEN,
ROLE_CLIENT,
@@ -20,6 +21,7 @@ from meshbay_common.handshake import (
AuthorizedPeer,
HandshakeError,
authorize_token,
+ challenge_transcript,
handshake_transcript,
make_proof,
quic_binding,
@@ -131,6 +133,24 @@ def test_transcript_is_domain_separated():
).startswith(HANDSHAKE_PREFIX)
+def test_the_challenge_transcript_is_its_own_domain():
+ """
+ MNP 3.4: the node signs the challenge with the same key that signs the ack.
+ The two must never be interchangeable — a challenge signature passed off as
+ an ack signature would authenticate a node that never proved the GEK.
+ """
+ challenge = challenge_transcript(GROUP, NONCE_C, NONCE_S, BINDING)
+ assert challenge.startswith(CHALLENGE_PREFIX)
+ assert challenge != handshake_transcript(ROLE_NODE, GROUP, NONCE_C, NONCE_S, BINDING)
+ for other in (
+ challenge_transcript("other", NONCE_C, NONCE_S, BINDING),
+ challenge_transcript(GROUP, b"x" * 32, NONCE_S, BINDING),
+ challenge_transcript(GROUP, NONCE_C, b"y" * 32, BINDING),
+ challenge_transcript(GROUP, NONCE_C, NONCE_S, BINDING + b"z"),
+ ):
+ assert other != challenge
+
+
def test_client_proof_is_not_a_node_proof():
"""
C3: the node proves itself with the same key over the same connection. Without