diff --git a/src/protocol.rs b/src/protocol.rs index f93bb9b..93a0817 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -273,6 +273,9 @@ pub fn decode(input: &[u8]) -> Result { if input.len() < end { bail!("truncated packet body"); } + if input.len() > end { + bail!("trailing packet bytes"); + } Ok(Packet { header, body: input[HEADER_LEN..end].to_vec(), diff --git a/tests/protocol_auth.rs b/tests/protocol_auth.rs index 169bd8f..41d1820 100644 --- a/tests/protocol_auth.rs +++ b/tests/protocol_auth.rs @@ -58,6 +58,21 @@ fn encrypted_packet_round_trips() { assert_eq!(plain, b"hello"); } +#[test] +fn packet_decode_rejects_truncated_or_trailing_datagrams() { + let packet = + protocol::encode_plain(PacketKind::Ping, crypto::random_16(), 1, 0, b"hello").unwrap(); + + let truncated = &packet[..packet.len() - 1]; + let err = protocol::decode(truncated).unwrap_err(); + assert!(err.to_string().contains("truncated packet body")); + + let mut trailing = packet.clone(); + trailing.extend_from_slice(b"junk"); + let err = protocol::decode(&trailing).unwrap_err(); + assert!(err.to_string().contains("trailing packet bytes")); +} + #[test] fn plaintext_packet_never_decrypts_as_authenticated_body() { let key = crypto::random_32();