diff --git a/src/stream.rs b/src/stream.rs index 6571520c3..a486302d4 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -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()); + } +}