diff --git a/src/common.rs b/src/common.rs index 6fb43da1c..81d632889 100644 --- a/src/common.rs +++ b/src/common.rs @@ -2103,6 +2103,8 @@ async fn key_exchange(conn: &mut Stream, key: &str, log_on_success: bool) -> Res let their_pk_b = get_pk(&their_pk_b) .context("Wrong their public length in key exchange")?; // The signed X25519 high bit marks servers that sign their parameters. + // X25519 ignores that bit, so old clients use the key unchanged; keep + // the bytes as signed, since the transcript and KxParams carry them so. if their_pk_b[31] & 0x80 != 0 || !ex.signed_params.is_empty() { let params = sign::verify(&ex.signed_params, &rs_pk) .ok() @@ -2120,11 +2122,11 @@ async fn key_exchange(conn: &mut Stream, key: &str, log_on_success: bool) -> Res } let (asymmetric_value, symmetric_value, key) = create_symmetric_key_msg(their_pk_b); - let version = hbb_common::tcp::kx_version_for(ex.version); + let picked = hbb_common::tcp::kx_version_for(ex.version); let mut msg_out = RendezvousMessage::new(); msg_out.set_key_exchange(KeyExchange { keys: vec![asymmetric_value.clone(), symmetric_value], - version, + version: picked, ..Default::default() }); timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??; @@ -2135,7 +2137,7 @@ async fn key_exchange(conn: &mut Stream, key: &str, log_on_success: bool) -> Res initiator_pk: &asymmetric_value, responder_pk: &their_pk_b, advertised: ex.version, - picked: version, + picked, }, )?; if log_on_success { diff --git a/src/server.rs b/src/server.rs index 6384d88e0..88341631b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -314,8 +314,9 @@ async fn identity_handshake(stream: &mut Stream, secure: bool) -> ResultType<()> )?; if pk.kx_version > advertised { bail!( - "Handshake failed: key exchange version {} not offered", - pk.kx_version + "Handshake failed: key exchange version {} not offered, {} was", + pk.kx_version, + advertised ); } stream.set_negotiated_key(