stream: refuse a key exchange version set_negotiated_key does not know

Version 1 is matched explicitly and any other picked version is an
error, so adding a version without its arm here fails instead of
running as version 1. WebRTC takes only version 0, as both handshakes
already require.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns
This commit is contained in:
rustdesk
2026-09-23 13:20:36 +08:00
co-authored by Claude Opus 5.5
parent cbc8772d4a
commit cee8cf3dc3
+34 -13
View File
@@ -1,4 +1,4 @@
use crate::{config, tcp, websocket, ResultType};
use crate::{bail, config, tcp, websocket, ResultType};
#[cfg(feature = "webrtc")]
use crate::webrtc;
use sodiumoxide::crypto::secretbox::Key;
@@ -81,8 +81,8 @@ impl Stream {
}
/// The stream key for the key exchange version in `t.picked`: version 0 is `set_key`, and
/// later versions derive one key per direction from the transcript. `is_initiator` is the
/// side that sent the sealed key.
/// version 1 derives one key per direction from the transcript. Any other version is refused
/// rather than run as one of these. `is_initiator` is the side that sent the sealed key.
#[inline]
pub fn set_negotiated_key(
&mut self,
@@ -90,18 +90,18 @@ impl Stream {
is_initiator: bool,
t: &tcp::KxTranscript,
) -> ResultType<()> {
if t.picked == 0 {
self.set_key(key);
return Ok(());
}
match self {
#[cfg(feature = "webrtc")]
Stream::WebRTC(s) => {
s.set_key(key);
match t.picked {
0 => {
self.set_key(key);
Ok(())
}
Stream::WebSocket(s) => s.set_key_split(key, is_initiator, t),
Stream::Tcp(s) => s.set_key_split(key, is_initiator, t),
1 => match self {
#[cfg(feature = "webrtc")]
Stream::WebRTC(_) => bail!("key exchange version 1 does not apply to WebRTC"),
Stream::WebSocket(s) => s.set_key_split(key, is_initiator, t),
Stream::Tcp(s) => s.set_key_split(key, is_initiator, t),
},
v => bail!("unsupported key exchange version {}", v),
}
}
@@ -313,3 +313,24 @@ impl Drop for Stream {
self.close_webrtc();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_set_negotiated_key_refuses_unknown_versions() {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let mut stream = Stream::from(TcpStream::connect(addr).await.unwrap(), addr);
let t = |picked| tcp::KxTranscript {
initiator_pk: &[1u8; 32],
responder_pk: &[2u8; 32],
advertised: 1,
picked,
};
let mut set = |picked| stream.set_negotiated_key(Key([0u8; 32]), true, &t(picked));
assert!(set(2).is_err());
assert!(set(1).is_ok());
}
}