You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/rust/src/rfb/parser.rs

392 lines
12 KiB
Rust

/* Copyright (C) 2020-2022 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
// Author: Frank Honza <frank.honza@dcso.de>
use std::fmt;
use std::str;
use nom7::bytes::streaming::take;
use nom7::combinator::map_res;
use nom7::number::streaming::*;
use nom7::*;
pub enum RFBGlobalState {
TCServerProtocolVersion,
TCSupportedSecurityTypes,
TCVncChallenge,
TCServerInit,
TCFailureReason,
TSClientProtocolVersion,
TCServerSecurityType,
TSSecurityTypeSelection,
TSVncResponse,
TCSecurityResult,
TSClientInit,
Message
}
impl fmt::Display for RFBGlobalState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
RFBGlobalState::TCServerProtocolVersion => write!(f, "TCServerProtocolVersion"),
RFBGlobalState::TCSupportedSecurityTypes => write!(f, "TCSupportedSecurityTypes"),
RFBGlobalState::TCVncChallenge => write!(f, "TCVncChallenge"),
RFBGlobalState::TCServerInit => write!(f, "TCServerInit"),
RFBGlobalState::TCFailureReason => write!(f, "TCFailureReason"),
RFBGlobalState::TSClientProtocolVersion => write!(f, "TSClientProtocolVersion"),
RFBGlobalState::TSSecurityTypeSelection => write!(f, "TSSecurityTypeSelection"),
RFBGlobalState::TSVncResponse => write!(f, "TSVncResponse"),
RFBGlobalState::TCSecurityResult => write!(f, "TCSecurityResult"),
RFBGlobalState::TCServerSecurityType => write!(f, "TCServerSecurityType"),
RFBGlobalState::TSClientInit => write!(f, "TSClientInit"),
RFBGlobalState::Message => write!(f, "Message")
}
}
}
pub struct ProtocolVersion {
pub major: String,
pub minor: String
}
pub struct SupportedSecurityTypes {
pub number_of_types: u8,
pub types: Vec<u8>
}
pub struct SecurityTypeSelection {
pub security_type: u8
}
pub struct ServerSecurityType {
pub security_type: u32
}
pub struct SecurityResult {
pub status: u32
}
pub struct FailureReason {
pub reason_string: String
}
pub struct VncAuth {
pub secret: Vec<u8>
}
pub struct ClientInit {
pub shared: u8
}
pub struct PixelFormat {
pub bits_per_pixel: u8,
pub depth: u8,
pub big_endian_flag: u8,
pub true_colour_flag: u8,
pub red_max: u16,
pub green_max: u16,
pub blue_max: u16,
pub red_shift: u8,
pub green_shift: u8,
pub blue_shift: u8,
}
pub struct ServerInit {
pub width: u16,
pub height: u16,
pub pixel_format: PixelFormat,
pub name_length: u32,
pub name: Vec<u8>
}
pub fn parse_protocol_version(i: &[u8]) -> IResult<&[u8], ProtocolVersion> {
let (i, _rfb_string) = map_res(take(3_usize), str::from_utf8)(i)?;
let (i, _) = be_u8(i)?;
let (i, major) = map_res(take(3_usize), str::from_utf8)(i)?;
let (i, _) = be_u8(i)?;
let (i, minor) = map_res(take(3_usize), str::from_utf8)(i)?;
let (i, _) = be_u8(i)?;
Ok((i, ProtocolVersion{ major: major.to_string(), minor: minor.to_string(), }))
}
pub fn parse_supported_security_types(i: &[u8]) -> IResult<&[u8], SupportedSecurityTypes> {
let (i, number_of_types) = be_u8(i)?;
let (i, types) = take(number_of_types as usize)(i)?;
Ok((
i,
SupportedSecurityTypes{
number_of_types,
types: types.to_vec()
}
))
}
pub fn parse_server_security_type(i: &[u8]) -> IResult<&[u8], ServerSecurityType> {
let (i, security_type) = be_u32(i)?;
Ok((i, ServerSecurityType{ security_type, }))
}
pub fn parse_vnc_auth(i: &[u8]) -> IResult<&[u8], VncAuth> {
let (i, secret) = take(16_usize)(i)?;
Ok((i, VncAuth { secret: secret.to_vec() }))
}
pub fn parse_security_type_selection(i: &[u8]) -> IResult<&[u8], SecurityTypeSelection> {
let (i, security_type) = be_u8(i)?;
Ok((i, SecurityTypeSelection { security_type }))
}
pub fn parse_security_result(i: &[u8]) -> IResult<&[u8], SecurityResult> {
let (i, status) = be_u32(i)?;
Ok((i, SecurityResult { status }))
}
pub fn parse_failure_reason(i: &[u8]) -> IResult<&[u8], FailureReason> {
let (i, reason_length) = be_u32(i)?;
let (i, reason_string) = map_res(take(reason_length as usize), str::from_utf8)(i)?;
Ok((
i,
FailureReason {
reason_string: reason_string.to_string()
}
))
}
pub fn parse_client_init(i: &[u8]) -> IResult<&[u8], ClientInit> {
let (i, shared) = be_u8(i)?;
Ok((i, ClientInit { shared }))
}
pub fn parse_pixel_format(i: &[u8]) -> IResult<&[u8], PixelFormat> {
let (i, bits_per_pixel) = be_u8(i)?;
let (i, depth) = be_u8(i)?;
let (i, big_endian_flag) = be_u8(i)?;
let (i, true_colour_flag) = be_u8(i)?;
let (i, red_max) = be_u16(i)?;
let (i, green_max) = be_u16(i)?;
let (i, blue_max) = be_u16(i)?;
let (i, red_shift) = be_u8(i)?;
let (i, green_shift) = be_u8(i)?;
let (i, blue_shift) = be_u8(i)?;
let (i, _) = take(3_usize)(i)?;
let format = PixelFormat {
bits_per_pixel,
depth,
big_endian_flag,
true_colour_flag,
red_max,
green_max,
blue_max,
red_shift,
green_shift,
blue_shift,
};
Ok((i, format))
}
pub fn parse_server_init(i: &[u8]) -> IResult<&[u8], ServerInit> {
let (i, width) = be_u16(i)?;
let (i, height) = be_u16(i)?;
let (i, pixel_format) = parse_pixel_format(i)?;
let (i, name_length) = be_u32(i)?;
let (i, name) = take(name_length as usize)(i)?;
let init = ServerInit {
width,
height,
pixel_format,
name_length,
name: name.to_vec()
};
Ok((i, init))
}
#[cfg(test)]
mod tests {
use super::*;
/// Simple test of some valid data.
#[test]
fn test_parse_version() {
let buf = b"RFB 003.008\n";
let result = parse_protocol_version(buf);
match result {
Ok((remainder, message)) => {
// Check the first message.
assert_eq!(message.major, "003");
// And we should have 0 bytes left.
assert_eq!(remainder.len(), 0);
}
Err(Err::Incomplete(_)) => {
panic!("Result should not have been incomplete.");
}
Err(Err::Error(err)) |
Err(Err::Failure(err)) => {
panic!("Result should not be an error: {:?}.", err);
}
}
}
#[test]
fn test_parse_server_init() {
let buf = [
0x05, 0x00, 0x03, 0x20, 0x20, 0x18, 0x00, 0x01,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x10, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
0x61, 0x6e, 0x65, 0x61, 0x67, 0x6c, 0x65, 0x73,
0x40, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
0x73, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e
];
let result = parse_server_init(&buf);
match result {
Ok((remainder, message)) => {
// Check the first message.
assert_eq!(message.width, 1280);
assert_eq!(message.height, 800);
assert_eq!(message.pixel_format.bits_per_pixel, 32);
// And we should have 0 bytes left.
assert_eq!(remainder.len(), 0);
}
Err(Err::Incomplete(_)) => {
panic!("Result should not have been incomplete.");
}
Err(Err::Error(err)) |
Err(Err::Failure(err)) => {
panic!("Result should not be an error: {:?}.", err);
}
}
}
#[test]
fn test_parse_pixel_format() {
let buf = [
0x20, /* Bits per pixel: 32 */
0x18, /* Depth: 24 */
0x00, /* Big endian flag: False */
0x01, /* True color flag: True */
0x00, 0xff, /* Red maximum: 255 */
0x00, 0xff, /* Green maximum: 255 */
0x00, 0xff, /* Blue maximum: 255 */
0x10, /* Red shift: 16 */
0x08, /* Green shift: 8 */
0x00, /* Blue shift: 0 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa0,
];
let result = parse_pixel_format(&buf);
match result {
Ok((remainder, message)) => {
assert_eq!(message.bits_per_pixel, 32);
assert_eq!(message.depth, 24);
assert_eq!(message.big_endian_flag, 0);
assert_eq!(message.true_colour_flag, 1);
assert_eq!(message.red_max, 255);
assert_eq!(message.green_max, 255);
assert_eq!(message.blue_max, 255);
assert_eq!(message.red_shift, 16);
assert_eq!(message.green_shift, 8);
assert_eq!(message.blue_shift, 0);
assert_eq!(remainder.len(), 5);
}
Err(Err::Incomplete(_)) => {
panic!("Result should not have been incomplete.");
}
Err(Err::Error(err)) | Err(Err::Failure(err)) => {
panic!("Result should not be an error: {:?}.", err);
}
}
}
#[test]
fn test_parse_supported_security_types() {
let buf = [
0x01, /* Number of security types: 1 */
0x02, /* Security type: VNC (2) */
0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xa0,
];
let result = parse_supported_security_types(&buf);
match result {
Ok((remainder, message)) => {
assert_eq!(message.number_of_types, 1);
assert_eq!(message.types[0], 2);
assert_eq!(remainder.len(), 19);
}
Err(Err::Incomplete(_)) => {
panic!("Result should not have been incomplete.");
}
Err(Err::Error(err)) | Err(Err::Failure(err)) => {
panic!("Result should not be an error: {:?}.", err);
}
}
}
#[test]
fn test_parse_vnc_auth() {
let buf = [
0x54, 0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a,
0x4e, 0xc5, /* Authentication challenge: 547b7a6f36a154db03a2575c6f2a4ec5 */
0x00, 0x00, 0x00, 0x01, 0xa0,
];
let result = parse_vnc_auth(&buf);
match result {
Ok((remainder, message)) => {
assert_eq!(
hex::encode(message.secret),
"547b7a6f36a154db03a2575c6f2a4ec5"
);
assert_eq!(remainder.len(), 5);
}
Err(Err::Incomplete(_)) => {
panic!("Result should not have been incomplete.");
}
Err(Err::Error(err)) | Err(Err::Failure(err)) => {
panic!("Result should not be an error: {:?}.", err);
}
}
}
#[test]
fn test_parse_client_init() {
let buf = [
0x00, /*Share desktop flag: False*/
0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a, 0x4e,
0xc5, 0x00, 0x00, 0x00, 0x01, 0xa0,
];
let result = parse_client_init(&buf);
match result {
Ok((remainder, message)) => {
assert_eq!(message.shared, 0);
assert_eq!(remainder.len(), 20);
}
Err(Err::Incomplete(_)) => {
panic!("Result should not have been incomplete.");
}
Err(Err::Error(err)) | Err(Err::Failure(err)) => {
panic!("Result should not be an error: {:?}.", err);
}
}
}
}