Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}