/src/suricata7/rust/src/rdp/util.rs
Line | Count | Source |
1 | | /* Copyright (C) 2019 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | // Author: Zach Kelly <zach.kelly@lmco.com> |
19 | | |
20 | | use crate::rdp::error::RdpError; |
21 | | use byteorder::ReadBytesExt; |
22 | | use memchr::memchr; |
23 | | use nom7::{Err, IResult, Needed}; |
24 | | use std::io::Cursor; |
25 | | use widestring::U16CString; |
26 | | |
27 | | /// converts a raw u8 slice of little-endian wide chars into a String |
28 | 30.7k | pub fn le_slice_to_string(input: &[u8]) -> Result<String, Box<dyn std::error::Error>> { |
29 | 30.7k | let mut vec = Vec::new(); |
30 | 30.7k | let mut cursor = Cursor::new(input); |
31 | 309k | while let Ok(x) = cursor.read_u16::<byteorder::LittleEndian>() { |
32 | 301k | if x == 0 { |
33 | 23.2k | break; |
34 | 278k | } |
35 | 278k | vec.push(x); |
36 | | } |
37 | 30.7k | match U16CString::new(vec) { |
38 | 30.7k | Ok(x) => match x.to_string() { |
39 | 29.8k | Ok(x) => Ok(x), |
40 | 910 | Err(e) => Err(e.into()), |
41 | | }, |
42 | 0 | Err(e) => Err(e.into()), |
43 | | } |
44 | 30.7k | } |
45 | | |
46 | | /// converts a raw u8 slice of null-padded utf7 chars into a String, dropping the nulls |
47 | 1.79k | pub fn utf7_slice_to_string(input: &[u8]) -> Result<String, Box<dyn std::error::Error>> { |
48 | 1.79k | let s = match memchr(b'\0', input) { |
49 | 1.07k | Some(end) => &input[..end], |
50 | 717 | None => input, |
51 | | }; |
52 | 1.79k | match std::str::from_utf8(s) { |
53 | 1.50k | Ok(s) => Ok(String::from(s)), |
54 | 291 | Err(e) => Err(e.into()), |
55 | | } |
56 | 1.79k | } |
57 | | |
58 | | /// parses a PER length determinant, to determine the length of the data following |
59 | | /// x.691-spec: section 10.9 |
60 | 28.6k | pub fn parse_per_length_determinant(input: &[u8]) -> IResult<&[u8], u32, RdpError> { |
61 | 28.6k | if input.is_empty() { |
62 | | // need a single byte to begin length determination |
63 | 301 | Err(Err::Incomplete(Needed::new(1))) |
64 | | } else { |
65 | 28.3k | let bit7 = input[0] >> 7; |
66 | 28.3k | match bit7 { |
67 | | 0b0 => { |
68 | | // byte starts with 0b0. Length stored in the lower 7 bits of the current byte |
69 | 17.2k | let length = input[0] as u32 & 0x7f; |
70 | 17.2k | Ok((&input[1..], length)) |
71 | | } |
72 | | _ => { |
73 | 11.1k | let bit6 = (input[0] >> 6) & 0x1; |
74 | 11.1k | match bit6 { |
75 | | 0b0 => { |
76 | | // byte starts with 0b10. Length stored in the remaining 6 bits and the next byte |
77 | 10.6k | if input.len() < 2 { |
78 | 197 | Err(Err::Incomplete(Needed::new(2))) |
79 | | } else { |
80 | 10.4k | let length = ((input[0] as u32 & 0x3f) << 8) | input[1] as u32; |
81 | 10.4k | Ok((&input[2..], length)) |
82 | | } |
83 | | } |
84 | | _ => { |
85 | | // byte starts with 0b11. Without an example to confirm 16K+ lengths are properly |
86 | | // handled, leaving this branch unimplemented |
87 | 492 | Err(Err::Error(RdpError::UnimplementedLengthDeterminant)) |
88 | | } |
89 | | } |
90 | | } |
91 | | } |
92 | | } |
93 | 28.6k | } |
94 | | |
95 | | #[cfg(test)] |
96 | | mod tests { |
97 | | use super::*; |
98 | | use crate::rdp::error::RdpError; |
99 | | use nom7::Needed; |
100 | | |
101 | | #[test] |
102 | | fn test_le_string_abc() { |
103 | | let abc = &[0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00]; |
104 | | assert_eq!(String::from("ABC"), le_slice_to_string(abc).unwrap()); |
105 | | } |
106 | | |
107 | | #[test] |
108 | | fn test_le_string_empty() { |
109 | | let empty = &[]; |
110 | | assert_eq!(String::from(""), le_slice_to_string(empty).unwrap()); |
111 | | } |
112 | | |
113 | | #[test] |
114 | | fn test_le_string_invalid() { |
115 | | let not_utf16le = &[0x00, 0xd8, 0x01, 0x00]; |
116 | | assert!(le_slice_to_string(not_utf16le).is_err()); |
117 | | } |
118 | | |
119 | | #[test] |
120 | | fn test_utf7_string_abc() { |
121 | | let abc = &[0x41, 0x42, 0x43, 0x00, 0x00]; |
122 | | assert_eq!(String::from("ABC"), utf7_slice_to_string(abc).unwrap()); |
123 | | } |
124 | | |
125 | | #[test] |
126 | | fn test_utf7_string_empty() { |
127 | | let empty = &[]; |
128 | | assert_eq!(String::from(""), utf7_slice_to_string(empty).unwrap()); |
129 | | } |
130 | | |
131 | | #[test] |
132 | | fn test_utf7_string_invalid() { |
133 | | let not_utf7 = &[0x80]; |
134 | | assert!(utf7_slice_to_string(not_utf7).is_err()); |
135 | | } |
136 | | |
137 | | #[test] |
138 | | fn test_length_single_length() { |
139 | | let bytes = &[0x28]; |
140 | | assert_eq!(Ok((&[][..], 0x28)), parse_per_length_determinant(bytes)); |
141 | | } |
142 | | |
143 | | #[test] |
144 | | fn test_length_double_length() { |
145 | | let bytes = &[0x81, 0x28]; |
146 | | assert_eq!(Ok((&[][..], 0x128)), parse_per_length_determinant(bytes)); |
147 | | } |
148 | | |
149 | | #[test] |
150 | | fn test_length_single_length_incomplete() { |
151 | | let bytes = &[]; |
152 | | assert_eq!( |
153 | | Err(Err::Incomplete(Needed::new(1))), |
154 | | parse_per_length_determinant(bytes) |
155 | | ) |
156 | | } |
157 | | |
158 | | #[test] |
159 | | fn test_length_16k_unimplemented() { |
160 | | let bytes = &[0xc0]; |
161 | | assert_eq!( |
162 | | Err(Err::Error(RdpError::UnimplementedLengthDeterminant)), |
163 | | parse_per_length_determinant(bytes) |
164 | | ) |
165 | | } |
166 | | |
167 | | #[test] |
168 | | fn test_length_double_length_incomplete() { |
169 | | let bytes = &[0x81]; |
170 | | assert_eq!( |
171 | | Err(Err::Incomplete(Needed::new(2))), |
172 | | parse_per_length_determinant(bytes) |
173 | | ) |
174 | | } |
175 | | } |