From d9f519e91581686466fa625fa4edb61341dbe886 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 22 Sep 2026 13:18:45 +0800 Subject: [PATCH] KeyExchange: signed_version, the server's signature over its version The echo catches an advertisement lowered in the clear only once a tagged frame arrives, so the initiator's first frame has already gone out under the lower version by then. A server that signs its version instead sets bit 255 of the ephemeral X25519 key inside the signed keys[0] and puts sign("rdkx-ver" || key || version LE) here. RFC 7748 masks that bit, so the box opens as before on either side, and a legacy server, whose keys are canonical, never sets it. A client that sees the bit, or the field, verifies before trusting the version, so the pair settles it at the handshake rather than one frame pair later. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns --- protos/rendezvous.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protos/rendezvous.proto b/protos/rendezvous.proto index fe0ef637a..f126714a8 100644 --- a/protos/rendezvous.proto +++ b/protos/rendezvous.proto @@ -238,6 +238,9 @@ message KeyExchange { // From the server: the newest key exchange version it speaks. From the client: the version it // picked, the highest both speak. Absent, i.e. 0, is the original scheme. uint32 version = 2; + // Server signature of "rdkx-ver" || on-wire ephemeral public key || little-endian uint32 version. + // Bit 255 of the signed X25519 public key requires this field; legacy keys leave it clear. + bytes signed_version = 3; } message HealthCheck {