Coverage Report

Created: 2026-01-16 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/rdp/parser.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
//! RDP parser
21
//!
22
//! References:
23
//! * rdp-spec: <https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/>
24
//! * t.123-spec: <https://www.itu.int/rec/T-REC-T.123-200701-I/en>
25
//! * t.125-spec: <https://www.itu.int/rec/T-REC-T.125-199802-I/en>
26
//! * x.224-spec: <https://www.itu.int/rec/T-REC-X.224-199511-I/en>
27
//! * x.691-spec: <https://www.itu.int/rec/T-REC-X.691/en>
28
29
use crate::common::nom7::{bits, take_until_and_consume};
30
use crate::rdp::error::RdpError;
31
use crate::rdp::util::{le_slice_to_string, parse_per_length_determinant, utf7_slice_to_string};
32
use crate::rdp::windows;
33
use nom7::bits::streaming::take as take_bits;
34
use nom7::bytes::streaming::{tag, take};
35
use nom7::combinator::{map, map_opt, map_res, opt, verify};
36
use nom7::error::{make_error, ErrorKind};
37
use nom7::multi::length_data;
38
use nom7::number::streaming::{be_u16, be_u8, le_u16, le_u32, le_u8};
39
use nom7::sequence::tuple;
40
use nom7::{Err, IResult};
41
42
/// constrains dimension to a range, per spec
43
/// rdp-spec, section 2.2.1.3.2 Client Core Data
44
4.92k
fn millimeters_to_opt(x: u32) -> Option<u32> {
45
4.92k
    if (10..=10_000).contains(&x) {
46
4.44k
        Some(x)
47
    } else {
48
477
        None
49
    }
50
4.92k
}
51
52
/// constrains desktop scale to a range, per spec
53
/// rdp-spec, section 2.2.1.3.2 Client Core Data
54
1.40k
fn desktop_scale_to_opt(x: u32) -> Option<u32> {
55
1.40k
    if (100..=500).contains(&x) {
56
973
        Some(x)
57
    } else {
58
430
        None
59
    }
60
1.40k
}
61
62
/// constrains device scale to a set of valid values, per spec
63
/// rdp-spec, section 2.2.1.3.2 Client Core Data
64
777
fn device_scale_to_opt(x: u32) -> Option<u32> {
65
777
    if x == 100 || x == 140 || x == 180 {
66
582
        Some(x)
67
    } else {
68
195
        None
69
    }
70
777
}
71
72
// ================
73
74
/// t.123-spec, section 8
75
#[derive(Clone, Debug, PartialEq, Eq)]
76
pub enum TpktVersion {
77
    T123 = 0x3,
78
}
79
80
/// t.123-spec, section 8
81
#[derive(Clone, Debug, PartialEq, Eq)]
82
pub struct T123Tpkt {
83
    pub child: T123TpktChild,
84
}
85
86
/// variants that a t.123 tpkt can hold
87
#[derive(Clone, Debug, PartialEq, Eq)]
88
pub enum T123TpktChild {
89
    X224ConnectionRequest(X224ConnectionRequest),
90
    X224ConnectionConfirm(X224ConnectionConfirm),
91
    Data(X223Data),
92
    Raw(Vec<u8>),
93
}
94
95
// ================
96
97
/// x.224-spec, sections 13.3.3, 13.4.3, 13.7.3
98
#[derive(Clone, Debug, PartialEq, Eq)]
99
pub enum X224Type {
100
    ConnectionConfirm = 0xd,
101
    ConnectionRequest = 0xe,
102
    _Data = 0xf,
103
}
104
105
/// x.224-spec, section 13.3
106
// rdp-spec, section 2.2.1.1
107
#[derive(Clone, Debug, PartialEq, Eq)]
108
pub struct X224ConnectionRequest {
109
    pub cdt: u8,
110
    pub dst_ref: u16,
111
    pub src_ref: u16,
112
    pub class: u8,
113
    pub options: u8,
114
    pub cookie: Option<RdpCookie>,
115
    pub negotiation_request: Option<NegotiationRequest>,
116
    pub data: Vec<u8>,
117
}
118
119
/// rdp-spec, section 2.2.1.1.1
120
#[derive(Clone, Debug, PartialEq, Eq)]
121
pub struct RdpCookie {
122
    pub mstshash: String,
123
}
124
125
/// rdp-spec, sections 2.2.1.1.1, 2.2.1.2.1, 2.2.1.2.2
126
#[derive(Clone, Debug, PartialEq, Eq)]
127
pub enum X224ConnectionRequestType {
128
    NegotiationRequest = 0x1,
129
    NegotiationResponse = 0x2,
130
    NegotiationFailure = 0x3,
131
}
132
133
/// rdp-spec, section 2.2.1.1.1
134
#[derive(Clone, Debug, PartialEq, Eq)]
135
pub struct NegotiationRequest {
136
    pub flags: NegotiationRequestFlags,
137
    pub protocols: ProtocolFlags,
138
}
139
140
// rdp-spec, section 2.2.1.1.1
141
bitflags! {
142
    #[derive(Default)]
143
    pub struct NegotiationRequestFlags: u8 {
144
        const RESTRICTED_ADMIN_MODE_REQUIRED = 0x1;
145
        const REDIRECTED_AUTHENTICATION_MODE_REQUIRED = 0x2;
146
        const CORRELATION_INFO_PRESENT = 0x8;
147
    }
148
}
149
150
/// rdp-spec, section 2.2.1.1.1
151
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
152
pub enum Protocol {
153
    ProtocolRdp = 0x0,
154
    ProtocolSsl = 0x1,
155
    ProtocolHybrid = 0x2,
156
    ProtocolRdsTls = 0x4,
157
    ProtocolHybridEx = 0x8,
158
}
159
160
// rdp-spec, section 2.2.1.1.1
161
bitflags! {
162
    pub struct ProtocolFlags: u32 {
163
        //Protocol::ProtocolRdp is 0 as always supported
164
        //and bitflags crate does not like zero-bit flags
165
        const PROTOCOL_SSL = Protocol::ProtocolSsl as u32;
166
        const PROTOCOL_HYBRID = Protocol::ProtocolHybrid as u32;
167
        const PROTOCOL_RDSTLS = Protocol::ProtocolRdsTls as u32;
168
        const PROTOCOL_HYBRID_EX = Protocol::ProtocolHybridEx as u32;
169
    }
170
}
171
172
/// rdp-spec, section 2.2.1.2
173
/// x.224-spec, section 13.3
174
#[derive(Clone, Debug, PartialEq, Eq)]
175
pub struct X224ConnectionConfirm {
176
    pub cdt: u8,
177
    pub dst_ref: u16,
178
    pub src_ref: u16,
179
    pub class: u8,
180
    pub options: u8,
181
    pub negotiation_from_server: Option<NegotiationFromServer>,
182
}
183
184
/// variants of a server negotiation
185
#[derive(Clone, Debug, PartialEq, Eq)]
186
pub enum NegotiationFromServer {
187
    Response(NegotiationResponse),
188
    Failure(NegotiationFailure),
189
}
190
191
/// rdp-spec, section 2.2.1.1.1
192
#[derive(Clone, Debug, PartialEq, Eq)]
193
pub struct NegotiationResponse {
194
    pub flags: NegotiationResponseFlags,
195
    pub protocol: Protocol,
196
}
197
198
// rdp-spec, section 2.2.1.2.1
199
bitflags! {
200
    #[derive(Default)]
201
    pub struct NegotiationResponseFlags: u8 {
202
        const EXTENDED_CLIENT_DATA_SUPPORTED = 0x1;
203
        const DYNVC_GFX_PROTOCOL_SUPPORTED = 0x2;
204
        const NEGRSP_FLAG_RESERVED = 0x4;
205
        const RESTRICTED_ADMIN_MODE_SUPPORTED = 0x8;
206
        const REDIRECTED_AUTHENTICATION_MODE_SUPPORTED = 0x10;
207
    }
208
}
209
210
/// rdp-spec, section 2.2.1.1.1
211
#[derive(Clone, Debug, PartialEq, Eq)]
212
pub struct NegotiationFailure {
213
    pub code: NegotiationFailureCode,
214
}
215
216
/// rdp-spec, section 2.2.1.2.2
217
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
218
pub enum NegotiationFailureCode {
219
    SslRequiredByServer = 0x1,
220
    SslNotAllowedByServer = 0x2,
221
    SslCertNotOnServer = 0x3,
222
    InconsistentFlags = 0x4,
223
    HybridRequiredByServer = 0x5,
224
    SslWithUserAuthRequiredByServer = 0x6,
225
}
226
227
// ================
228
229
/// x224-spec, section 13.7
230
#[derive(Clone, Debug, PartialEq, Eq)]
231
pub struct X223Data {
232
    pub child: X223DataChild,
233
}
234
235
/// variants that an x.223 data message can hold
236
#[derive(Clone, Debug, PartialEq, Eq)]
237
pub enum X223DataChild {
238
    McsConnectRequest(McsConnectRequest),
239
    McsConnectResponse(McsConnectResponse),
240
    Raw(Vec<u8>),
241
}
242
243
/// t.125-spec, section 7, part 2
244
#[derive(Clone, Debug, PartialEq, Eq)]
245
pub enum T125Type {
246
    T125TypeMcsConnectRequest = 0x65,  // 101
247
    T125TypeMcsConnectResponse = 0x66, // 102
248
}
249
250
/// rdp-spec, section 2.2.1.3.2
251
#[derive(Clone, Debug, PartialEq, Eq)]
252
pub struct McsConnectRequest {
253
    pub children: Vec<McsConnectRequestChild>,
254
}
255
256
/// variants that an mcs connection message can hold
257
#[derive(Clone, Debug, PartialEq, Eq)]
258
pub enum McsConnectRequestChild {
259
    CsClientCore(CsClientCoreData),
260
    CsNet(CsNet),
261
    CsUnknown(CsUnknown),
262
}
263
264
/// rdp-spec, section 2.2.1.3.1
265
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
266
pub enum CsType {
267
    Core = 0xc001,
268
    Net = 0xc003,
269
}
270
271
/// rdp-spec, section 2.2.1.3.2
272
#[derive(Clone, Debug, PartialEq, Eq)]
273
pub struct CsClientCoreData {
274
    pub version: Option<RdpClientVersion>,
275
    pub desktop_width: u16,
276
    pub desktop_height: u16,
277
    pub color_depth: Option<ColorDepth>,
278
    pub sas_sequence: Option<SasSequence>,
279
    pub keyboard_layout: u32, // see windows::lcid_to_string
280
    pub client_build: windows::OperatingSystem,
281
    pub client_name: String,
282
    pub keyboard_type: Option<KeyboardType>,
283
    pub keyboard_subtype: u32,
284
    pub keyboard_function_key: u32,
285
    pub ime_file_name: String,
286
    // optional fields
287
    pub post_beta2_color_depth: Option<PostBeta2ColorDepth>,
288
    pub client_product_id: Option<u16>,
289
    pub serial_number: Option<u32>,
290
    pub high_color_depth: Option<HighColorDepth>,
291
    pub supported_color_depth: Option<SupportedColorDepth>,
292
    pub early_capability_flags: Option<EarlyCapabilityFlags>,
293
    pub client_dig_product_id: Option<String>,
294
    pub connection_hint: Option<ConnectionHint>,
295
    pub server_selected_protocol: Option<ProtocolFlags>,
296
    pub desktop_physical_width: Option<u32>,
297
    pub desktop_physical_height: Option<u32>,
298
    pub desktop_orientation: Option<DesktopOrientation>,
299
    pub desktop_scale_factor: Option<u32>,
300
    pub device_scale_factor: Option<u32>,
301
}
302
303
/// rdp-spec, section 2.2.1.3.2 Client Core Data
304
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
305
#[allow(non_camel_case_types)]
306
pub enum RdpClientVersion {
307
    V4 = 0x80001,
308
    V5_V8_1 = 0x80004,
309
    V10_0 = 0x80005,
310
    V10_1 = 0x80006,
311
    V10_2 = 0x80007,
312
    V10_3 = 0x80008,
313
    V10_4 = 0x80009,
314
    V10_5 = 0x8000a,
315
    V10_6 = 0x8000b,
316
    V10_7 = 0x8000c,
317
}
318
319
/// rdp-spec, section 2.2.1.3.2 Client Core Data
320
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
321
pub enum ColorDepth {
322
    RnsUdColor4Bpp = 0xca00,
323
    RnsUdColor8Bpp = 0xca01,
324
}
325
326
/// rdp-spec, section 2.2.1.3.2 Client Core Data
327
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
328
pub enum SasSequence {
329
    RnsUdSasDel = 0xaa03,
330
}
331
332
// for keyboard layout, see windows::lcid_to_string
333
334
/// rdp-spec, section 2.2.1.3.2 Client Core Data
335
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
336
pub enum KeyboardType {
337
    KbXt = 0x1,
338
    KbIco = 0x2,
339
    KbAt = 0x3,
340
    KbEnhanced = 0x4,
341
    Kb1050 = 0x5,
342
    Kb9140 = 0x6,
343
    KbJapanese = 0x7,
344
}
345
346
/// rdp-spec, section 2.2.1.3.2 Client Core Data
347
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
348
pub enum PostBeta2ColorDepth {
349
    RnsUdColorNotProvided = 0x0,
350
    RnsUdColor4Bpp = 0xca00,
351
    RnsUdColor8Bpp = 0xca01,
352
    RnsUdColor16Bpp555 = 0xca02,
353
    RnsUdColor16Bpp565 = 0xca03,
354
    RnsUdColor24Bpp = 0xca04,
355
}
356
357
/// rdp-spec, section 2.2.1.3.2 Client Core Data
358
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
359
pub enum HighColorDepth {
360
    HighColorNotProvided = 0x0,
361
    HighColor4Bpp = 0x4,
362
    HighColor8Bpp = 0x8,
363
    HighColor15Bpp = 0xf,
364
    HighColor16Bpp = 0x10,
365
    HighColor24Bpp = 0x18,
366
}
367
368
// rdp-spec, section 2.2.1.3.2 Client Core Data
369
bitflags! {
370
    #[derive(Default)]
371
    pub struct SupportedColorDepth: u16 {
372
        const RNS_UD_24_BPP_SUPPORT = 0x1;
373
        const RNS_UD_16_BPP_SUPPORT = 0x2;
374
        const RNS_UD_15_BPP_SUPPORT = 0x4;
375
        const RNS_UD_32_BPP_SUPPORT = 0x8;
376
    }
377
}
378
379
// rdp-spec, section 2.2.1.3.2 Client Core Data
380
bitflags! {
381
    #[derive(Default)]
382
    pub struct EarlyCapabilityFlags: u16 {
383
        const RNS_UD_CS_SUPPORT_ERRINFO_PDF = 0x1;
384
        const RNS_UD_CS_WANT_32BPP_SESSION = 0x2;
385
        const RNS_UD_CS_SUPPORT_STATUSINFO_PDU = 0x4;
386
        const RNS_UD_CS_STRONG_ASYMMETRIC_KEYS = 0x8;
387
        const RNS_UD_CS_UNUSED = 0x10;
388
        const RNS_UD_CS_VALID_CONNECTION_TYPE = 0x20;
389
        const RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU = 0x40;
390
        const RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT = 0x80;
391
        const RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL = 0x100;
392
        const RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE = 0x200;
393
        const RNS_UD_CS_SUPPORT_HEARTBEAT_PDU = 0x400;
394
    }
395
}
396
397
/// rdp-spec, section 2.2.1.3.2 Client Core Data, `connectionType`
398
#[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)]
399
pub enum ConnectionHint {
400
    ConnectionHintNotProvided = 0x0,
401
    ConnectionHintModem = 0x1,
402
    ConnectionHintBroadbandLow = 0x2,
403
    ConnectionHintSatellite = 0x3,
404
    ConnectionHintBroadbandHigh = 0x4,
405
    ConnectionHintWan = 0x5,
406
    ConnectionHintLan = 0x6,
407
    ConnectionHintAutoDetect = 0x7,
408
}
409
410
/// rdp-spec, section 2.2.1.3.2 Client Core Data
411
#[derive(Clone, Copy, Debug, FromPrimitive, PartialEq, Eq)]
412
pub enum DesktopOrientation {
413
    OrientationLandscape = 0,
414
    OrientationPortrait = 90,          // 0x5a
415
    OrientationLandscapeFlipped = 180, // 0xb4
416
    OrientationPortraitFlipped = 270,  // 0x10e
417
}
418
419
/// rdp-spec, section 2.2.1.3.4
420
#[derive(Clone, Debug, PartialEq, Eq)]
421
pub struct CsNet {
422
    pub channels: Vec<String>,
423
}
424
425
/// generic structure
426
/// cf. rdp-spec, section 2.2.1.3.4
427
#[derive(Clone, Debug, PartialEq, Eq)]
428
pub struct CsUnknown {
429
    pub typ: u16,
430
    pub data: Vec<u8>,
431
}
432
433
/// rdp-spec, section 2.2.1.4
434
#[derive(Clone, Debug, PartialEq, Eq)]
435
pub struct McsConnectResponse {}
436
437
// ==================
438
439
/// parser for t.123 and children
440
/// t.123-spec, section 8
441
2.58M
pub fn parse_t123_tpkt(input: &[u8]) -> IResult<&[u8], T123Tpkt, RdpError> {
442
2.58M
    let (i1, _version) = verify(be_u8, |&x| x == TpktVersion::T123 as u8)(input)?;
443
2.57M
    let (i2, _reserved) = be_u8(i1)?;
444
    // less u8, u8, u16
445
2.56M
    let (i3, sz) = map_opt(be_u16, |x: u16| x.checked_sub(4))(i2)?;
446
2.56M
    let (i4, data) = take(sz)(i3)?;
447
448
2.54M
    let opt1: Option<T123TpktChild> = {
449
2.55M
        match opt(parse_x224_connection_request_class_0)(data) {
450
2.54M
            Ok((_remainder, opt)) => opt.map(T123TpktChild::X224ConnectionRequest),
451
8.68k
            Err(e) => return Err(e),
452
        }
453
    };
454
455
2.54M
    let opt2: Option<T123TpktChild> = match opt1 {
456
1.09M
        Some(x) => Some(x),
457
1.44M
        None => match opt(parse_x224_connection_confirm_class_0)(data) {
458
1.44M
            Ok((_remainder, opt)) => opt.map(T123TpktChild::X224ConnectionConfirm),
459
3.08k
            Err(e) => return Err(e),
460
        },
461
    };
462
463
2.53M
    let opt3: Option<T123TpktChild> = match opt2 {
464
2.46M
        Some(x) => Some(x),
465
71.4k
        None => match opt(parse_x223_data_class_0)(data) {
466
45.5k
            Ok((_remainder, opt)) => opt.map(T123TpktChild::Data),
467
25.9k
            Err(e) => return Err(e),
468
        },
469
    };
470
2.51M
    let child: T123TpktChild = match opt3 {
471
2.47M
        Some(x) => x,
472
39.9k
        None => T123TpktChild::Raw(data.to_vec()),
473
    };
474
475
2.51M
    return Ok((i4, T123Tpkt { child }));
476
2.58M
}
477
478
3.99M
fn take_4_4_bits(input: &[u8]) -> IResult<&[u8], (u8, u8), RdpError> {
479
3.99M
    map(be_u8, |b| (b >> 4, b & 0xf))(input)
480
3.99M
}
481
482
2.48M
fn parse_class_options(i: &[u8]) -> IResult<&[u8], (u8, u8)> {
483
2.48M
    bits(
484
2.48M
        tuple((
485
2.48M
            verify(take_bits(4u8), |&x| x <= 4),
486
2.48M
            verify(take_bits(4u8), |&x| x <= 3)
487
        ))
488
2.48M
    )(i)
489
2.48M
}
490
491
/// rdp-spec, section 2.2.1.1
492
2.55M
fn parse_x224_connection_request(input: &[u8]) -> IResult<&[u8], X224ConnectionRequest, RdpError> {
493
2.55M
    let (i1, length) = verify(be_u8, |&x| x != 0xff)(input)?; // 0xff is reserved
494
2.54M
    let (i2, cr_cdt) = take_4_4_bits(i1)?;
495
2.54M
    if cr_cdt.0 != X224Type::ConnectionRequest as u8 {
496
1.43M
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
497
1.11M
    }
498
1.11M
    if !(cr_cdt.1 == 0 || cr_cdt.1 == 1) {
499
352
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
500
1.11M
    }
501
1.11M
    let (i3, dst_ref) = verify(be_u16, |&x| x == 0)(i2)?;
502
1.10M
    let (i4, src_ref) = be_u16(i3)?;
503
1.10M
    let (i5, class_options) = parse_class_options(i4).map_err(Err::convert)?;
504
    // less cr_cdt (u8), dst_ref (u16), src_ref (u16), class_options (u8)
505
1.10M
    if length < 6 {
506
464
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
507
1.10M
    }
508
1.10M
    let i6 = i5;
509
1.10M
    let sz = length - 6;
510
511
    //
512
    // optionally find cookie and/or negotiation request
513
    //
514
515
1.10M
    let (i7, data) = {
516
1.10M
        if sz > 0 {
517
179k
            take(sz)(i6)?
518
        } else {
519
925k
            (i6, &[][..])
520
        }
521
    };
522
523
1.10M
    let (j1, cookie) = {
524
1.10M
        if !data.is_empty() {
525
178k
            match opt(parse_rdp_cookie)(data) {
526
176k
                Ok((remainder, opt)) => (remainder, opt),
527
1.86k
                Err(e) => return Err(e),
528
            }
529
        } else {
530
925k
            (&[][..], None)
531
        }
532
    };
533
534
1.10M
    let (j2, negotiation_request) = {
535
1.10M
        if !j1.is_empty() {
536
176k
            match opt(parse_negotiation_request)(j1) {
537
176k
                Ok((remainder, opt)) => (remainder, opt),
538
586
                Err(e) => return Err(e),
539
            }
540
        } else {
541
925k
            (&[][..], None)
542
        }
543
    };
544
545
1.10M
    return Ok((
546
1.10M
        i7,
547
1.10M
        X224ConnectionRequest {
548
1.10M
            cdt: cr_cdt.1,
549
1.10M
            dst_ref,
550
1.10M
            src_ref,
551
1.10M
            class: class_options.0,
552
1.10M
            options: class_options.1,
553
1.10M
            cookie,
554
1.10M
            negotiation_request,
555
1.10M
            data: j2.to_vec(),
556
1.10M
        },
557
1.10M
    ));
558
2.55M
}
559
560
/// rdp-spec, section 2.2.1.1
561
/// "An X.224 Class 0 Connection Request TPDU, as specified in [X224] section 13.3."
562
2.55M
fn parse_x224_connection_request_class_0(
563
2.55M
    input: &[u8],
564
2.55M
) -> IResult<&[u8], X224ConnectionRequest, RdpError> {
565
2.55M
    let (i1, x224) = parse_x224_connection_request(input)?;
566
1.10M
    if x224.class == 0 && x224.options == 0 {
567
1.09M
        Ok((i1, x224))
568
    } else {
569
4.70k
        Err(Err::Error(RdpError::NotX224Class0Error))
570
    }
571
2.55M
}
572
573
// rdp-spec, section 2.2.1.1.1
574
178k
fn parse_rdp_cookie(i: &[u8]) -> IResult<&[u8], RdpCookie, RdpError> {
575
178k
    let (i, _key) = tag(b"Cookie: ")(i)?;
576
1.32k
    let (i, _name) = tag(b"mstshash=")(i)?;
577
84
    let (i, bytes) = take_until_and_consume(b"\r\n")(i)?;
578
    // let (i, s) = map_res(value!(bytes), std::str::from_utf8)(i)?;
579
61
    let s = std::str::from_utf8(bytes).map_err(|_| Err::Error(make_error(bytes, ErrorKind::MapRes)))?;
580
61
    let cookie = RdpCookie{ mstshash: String::from(s) };
581
61
    Ok((i, cookie))
582
178k
}
583
584
// rdp-spec, section 2.2.1.1.1
585
176k
fn parse_negotiation_request(i: &[u8]) -> IResult<&[u8], NegotiationRequest, RdpError> {
586
176k
    let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationRequest as u8)(i)?;
587
3.62k
    let (i, flags) = map_opt(le_u8, NegotiationRequestFlags::from_bits)(i)?;
588
    // u8, u8, u16, and u32 give _length of 8
589
3.18k
    let (i, _length) = verify(le_u16, |&x| x == 8)(i)?;
590
955
    let (i, protocols) = map_opt(le_u32, ProtocolFlags::from_bits)(i)?;
591
200
    Ok((i, NegotiationRequest { flags, protocols }))
592
176k
}
593
594
/// rdp-spec, section 2.2.1.2
595
/// x.224-spec, section 13.3
596
1.44M
fn parse_x224_connection_confirm(input: &[u8]) -> IResult<&[u8], X224ConnectionConfirm, RdpError> {
597
1.44M
    let (i1, length) = verify(be_u8, |&x| x != 0xff)(input)?; // 0xff is reserved
598
1.44M
    let (i2, cr_cdt) = take_4_4_bits(i1)?;
599
1.44M
    if cr_cdt.0 != X224Type::ConnectionConfirm as u8 {
600
55.6k
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
601
1.38M
    }
602
1.38M
    if !(cr_cdt.1 == 0 || cr_cdt.1 == 1) {
603
2.76k
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
604
1.38M
    }
605
1.38M
    let (i3, dst_ref) = verify(be_u16, |&x| x == 0)(i2)?;
606
1.37M
    let (i4, src_ref) = be_u16(i3)?;
607
1.37M
    let (i5, class_options) = parse_class_options(i4).map_err(Err::convert)?;
608
609
    // less cr_cdt (u8), dst_ref (u16), src_ref (u16), class_options (u8)
610
1.37M
    if length < 6 {
611
223
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
612
1.37M
    }
613
1.37M
    let i6 = i5;
614
1.37M
    let sz = length - 6;
615
616
    // a negotiation message from the server might be absent (sz == 0)
617
1.37M
    let (i7, negotiation_from_server) = {
618
1.37M
        if sz > 0 {
619
8.94k
            let (i7, data) = take(sz)(i6)?;
620
621
            // it will be one of a response message or a failure message
622
8.54k
            let opt1: Option<NegotiationFromServer> = match opt(parse_negotiation_response)(data) {
623
7.75k
                Ok((_remainder, opt)) => opt.map(NegotiationFromServer::Response),
624
798
                Err(e) => return Err(e),
625
            };
626
7.75k
            let opt2: Option<NegotiationFromServer> = match opt1 {
627
448
                Some(x) => Some(x),
628
7.30k
                None => match opt(parse_negotiation_failure)(data) {
629
6.68k
                    Ok((_remainder, opt)) => opt.map(NegotiationFromServer::Failure),
630
621
                    Err(e) => return Err(e),
631
                },
632
            };
633
7.12k
            (i7, opt2)
634
        } else {
635
1.36M
            (i6, None)
636
        }
637
    };
638
639
1.37M
    return Ok((
640
1.37M
        i7,
641
1.37M
        X224ConnectionConfirm {
642
1.37M
            cdt: cr_cdt.1,
643
1.37M
            dst_ref,
644
1.37M
            src_ref,
645
1.37M
            class: class_options.0,
646
1.37M
            options: class_options.1,
647
1.37M
            negotiation_from_server,
648
1.37M
        },
649
1.37M
    ));
650
1.44M
}
651
652
/// rdp-spec, section 2.2.1.2
653
/// "An X.224 Class 0 Connection Confirm TPDU, as specified in [X224] section 13.4."
654
1.44M
fn parse_x224_connection_confirm_class_0(
655
1.44M
    input: &[u8],
656
1.44M
) -> IResult<&[u8], X224ConnectionConfirm, RdpError> {
657
1.44M
    let (i1, x224) = parse_x224_connection_confirm(input)?;
658
1.37M
    if x224.class == 0 && x224.options == 0 {
659
1.37M
        Ok((i1, x224))
660
    } else {
661
        // x.224, but not a class 0 x.224 message
662
2.45k
        Err(Err::Error(RdpError::NotX224Class0Error))
663
    }
664
1.44M
}
665
666
// rdp-spec, section 2.2.1.1.1
667
8.54k
fn parse_negotiation_response(i: &[u8]) -> IResult<&[u8], NegotiationResponse, RdpError> {
668
8.54k
    let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationResponse as u8)(i)?;
669
2.88k
    let (i, flags) = map_opt(le_u8, NegotiationResponseFlags::from_bits)(i)?;
670
    // u8, u8, u16, and u32 give _length of 8
671
2.45k
    let (i, _length) = verify(le_u16, |&x| x == 8)(i)?;
672
1.60k
    let (i, protocol) = map_opt(le_u32, num::FromPrimitive::from_u32)(i)?;
673
448
    Ok((i, NegotiationResponse { flags, protocol }))
674
8.54k
}
675
676
// rdp-spec, section 2.2.1.1.1
677
7.30k
fn parse_negotiation_failure(i: &[u8]) -> IResult<&[u8], NegotiationFailure, RdpError> {
678
7.30k
    let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationFailure as u8)(i)?;
679
2.12k
    let (i, _flags) = le_u8(i)?;
680
    // u8, u8, u16, and u32 give _length of 8
681
1.93k
    let (i, _length) = verify(le_u16, |&x| x == 8)(i)?;
682
1.19k
    let (i, code) = map_opt(le_u32, num::FromPrimitive::from_u32)(i)?;
683
292
    Ok((i, NegotiationFailure { code }))
684
7.30k
}
685
686
/// x224-spec, section 13.7
687
71.4k
fn parse_x223_data_class_0(input: &[u8]) -> IResult<&[u8], X223Data, RdpError> {
688
36.7k
    fn parser(i: &[u8]) -> IResult<&[u8], (u8, u8, u8)> {
689
36.7k
        bits(
690
36.7k
            tuple((
691
36.7k
                verify(take_bits(4u8), |&x| x == 0xf),
692
36.7k
                verify(take_bits(3u8), |&x| x == 0),
693
36.7k
                verify(take_bits(1u8), |&x| x == 0)
694
            ))
695
36.7k
        )(i)
696
36.7k
    }
697
71.4k
    let (i1, _length) = verify(be_u8, |&x| x == 2)(input)?;
698
36.7k
    let (i2, _dt_x_roa) = parser(i1).map_err(Err::convert)?;
699
31.9k
    let (i3, _eot) = verify(be_u8, |&x| x == 0x80)(i2)?;
700
701
    //
702
    // optionally find exactly one of the child messages
703
    //
704
705
31.1k
    let opt1: Option<X223DataChild> = match opt(parse_mcs_connect)(i3) {
706
5.56k
        Ok((_remainder, opt)) => opt.map(X223DataChild::McsConnectRequest),
707
25.6k
        Err(e) => return Err(e),
708
    };
709
710
5.56k
    let opt2: Option<X223DataChild> = match opt1 {
711
3.84k
        Some(x) => Some(x),
712
1.71k
        None => match opt(parse_mcs_connect_response)(i3) {
713
1.71k
            Ok((_remainder, opt)) => opt.map(X223DataChild::McsConnectResponse),
714
0
            Err(e) => return Err(e),
715
        },
716
    };
717
718
5.56k
    let child: X223DataChild = match opt2 {
719
4.13k
        Some(x) => x,
720
1.42k
        None => X223DataChild::Raw(i3.to_vec()),
721
    };
722
723
5.56k
    return Ok((&[], X223Data { child }));
724
71.4k
}
725
726
/// rdp-spec, section 2.2.1.3.2
727
31.1k
fn parse_mcs_connect(input: &[u8]) -> IResult<&[u8], McsConnectRequest, RdpError> {
728
31.1k
    let (i1, _ber_type) = verify(
729
        le_u8,
730
        // BER: 0b01=application, 0b1=non-primitive, 0b11111
731
30.9k
        |&x| x == 0x7f
732
31.1k
    )(input)?;
733
30.4k
    let (i2, _t125_type) = verify(le_u8, |&x| x
734
30.4k
        == T125Type::T125TypeMcsConnectRequest as u8)(i1)?;
735
736
    // skip to, and consume, H.221 client-to-server key
737
29.2k
    let (i3, _skipped) = take_until_and_consume(b"Duca")(i2)?;
738
739
26.0k
    let (i4, data) = length_data(parse_per_length_determinant)(i3)?;
740
24.4k
    let mut remainder: &[u8] = data;
741
24.4k
    let mut children = Vec::new();
742
743
    // repeatedly attempt to parse optional CsClientCoreData, CsNet, and CsUnknown
744
    // until data buffer is exhausted
745
    loop {
746
41.4k
        remainder = match opt(parse_cs_client_core_data)(remainder) {
747
29.8k
            Ok((rem, o)) => match o {
748
                // found CsClientCoreData
749
10.2k
                Some(core_data) => {
750
10.2k
                    children.push(McsConnectRequestChild::CsClientCore(core_data));
751
10.2k
                    rem
752
                }
753
19.5k
                None => match opt(parse_cs_net)(remainder) {
754
                    // found CsNet
755
18.0k
                    Ok((rem, o)) => match o {
756
1.20k
                        Some(net) => {
757
1.20k
                            children.push(McsConnectRequestChild::CsNet(net));
758
1.20k
                            rem
759
                        }
760
                        None => {
761
16.8k
                            match opt(parse_cs_unknown)(remainder) {
762
                                // was able to parse CsUnknown
763
9.33k
                                Ok((rem, o)) => match o {
764
7.41k
                                    Some(unknown) => {
765
7.41k
                                        children.push(McsConnectRequestChild::CsUnknown(unknown));
766
7.41k
                                        rem
767
                                    }
768
                                    None => {
769
1.91k
                                        break;
770
                                    }
771
                                },
772
7.49k
                                Err(Err::Incomplete(i)) => {
773
7.49k
                                    return Err(Err::Incomplete(i))
774
                                }
775
0
                                Err(Err::Failure(_)) | Err(Err::Error(_)) => break,
776
                            }
777
                        }
778
                    },
779
1.55k
                    Err(Err::Incomplete(i)) => return Err(Err::Incomplete(i)),
780
0
                    Err(Err::Failure(_)) | Err(Err::Error(_)) => break,
781
                },
782
            },
783
11.5k
            Err(Err::Incomplete(i)) => return Err(Err::Incomplete(i)),
784
0
            Err(Err::Failure(_)) | Err(Err::Error(_)) => break,
785
        };
786
18.9k
        if remainder.is_empty() {
787
1.93k
            break;
788
16.9k
        }
789
    }
790
791
3.84k
    return Ok((i4, McsConnectRequest { children }));
792
31.1k
}
793
794
/// rdp-spec, section 2.2.1.3.2
795
41.4k
fn parse_cs_client_core_data(input: &[u8]) -> IResult<&[u8], CsClientCoreData> {
796
41.4k
    let (i1, _typ) = verify(le_u16, |&x| x == CsType::Core as u16)(input)?;
797
    // less u16, u16
798
20.9k
    let (i2, sz) = map_opt(le_u16, |x: u16| x.checked_sub(4))(i1)?;
799
19.9k
    let (i3, data) = take(sz)(i2)?;
800
19.6k
    let (j1, version) = map(le_u32, num::FromPrimitive::from_u32)(data)?;
801
19.4k
    let (j2, desktop_width) = le_u16(j1)?;
802
18.9k
    let (j3, desktop_height) = le_u16(j2)?;
803
18.6k
    let (j4, color_depth) = map(le_u16, num::FromPrimitive::from_u16)(j3)?;
804
18.4k
    let (j5, sas_sequence) = map(le_u16, num::FromPrimitive::from_u16)(j4)?;
805
18.1k
    let (j6, keyboard_layout) = le_u32(j5)?;
806
17.6k
    let (j7, client_build) = map(le_u32, windows::build_number_to_os)(j6)?;
807
17.2k
    let (j8, client_name) = map_res(take(32_usize), le_slice_to_string)(j7)?;
808
12.1k
    let (j9, keyboard_type) = map(le_u32, num::FromPrimitive::from_u32)(j8)?;
809
11.9k
    let (j10, keyboard_subtype) = le_u32(j9)?;
810
11.4k
    let (j11, keyboard_function_key) = le_u32(j10)?;
811
10.8k
    let (j12, ime_file_name) = map_res(take(64_usize), le_slice_to_string)(j11)?;
812
813
    //
814
    // optional fields below (but each requires the previous)
815
    //
816
817
10.2k
    let (j13, post_beta2_color_depth) =
818
10.2k
        match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j12) as IResult<&[u8], _> {
819
10.0k
            Ok((rem, obj)) => (rem, obj),
820
199
            _ => (j12, None),
821
        };
822
823
10.2k
    let (j14, client_product_id) = match post_beta2_color_depth {
824
1.18k
        None => (j13, None),
825
9.11k
        Some(_) => match opt(le_u16)(j13) as IResult<&[u8], _> {
826
8.91k
            Ok((rem, obj)) => (rem, obj),
827
195
            _ => (j13, None),
828
        },
829
    };
830
831
10.2k
    let (j15, serial_number) = match client_product_id {
832
1.37k
        None => (j14, None),
833
8.91k
        Some(_) => match opt(le_u32)(j14) as IResult<&[u8], _> {
834
8.68k
            Ok((rem, obj)) => (rem, obj),
835
230
            _ => (j14, None),
836
        },
837
    };
838
839
10.2k
    let (j16, high_color_depth) = match serial_number {
840
1.60k
        None => (j15, None),
841
        Some(_) => {
842
8.68k
            match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j15) as IResult<&[u8], _> {
843
7.73k
                Ok((rem, obj)) => (rem, obj),
844
953
                _ => (j15, None),
845
            }
846
        }
847
    };
848
849
10.2k
    let (j17, supported_color_depth) = match high_color_depth {
850
3.27k
        None => (j16, None),
851
        Some(_) => {
852
7.01k
            match opt(map_opt(le_u16, SupportedColorDepth::from_bits))(j16) as IResult<&[u8], _> {
853
6.82k
                Ok((rem, obj)) => (rem, obj),
854
194
                _ => (j16, None),
855
            }
856
        }
857
    };
858
859
10.2k
    let (j18, early_capability_flags) = match supported_color_depth {
860
3.76k
        None => (j17, None),
861
        Some(_) => {
862
6.52k
            match opt(map_opt(le_u16, EarlyCapabilityFlags::from_bits))(j17) as IResult<&[u8], _>
863
            {
864
6.33k
                Ok((rem, obj)) => (rem, obj),
865
194
                _ => (j17, None),
866
            }
867
        }
868
    };
869
870
10.2k
    let (j19, client_dig_product_id) = match early_capability_flags {
871
4.39k
        None => (j18, None),
872
        Some(_) => {
873
5.90k
            match opt(map_res(take(64usize), le_slice_to_string))(j18) as IResult<&[u8], _> {
874
5.70k
                Ok((rem, obj)) => (rem, obj),
875
198
                _ => (j18, None),
876
            }
877
        }
878
    };
879
880
10.2k
    let (j20, connection_hint) = match client_dig_product_id {
881
5.22k
        None => (j19, None),
882
        Some(_) => {
883
5.07k
            match opt(map_opt(le_u8, num::FromPrimitive::from_u8))(j19) as IResult<&[u8], _> {
884
5.00k
                Ok((rem, obj)) => (rem, obj),
885
63
                _ => (j19, None),
886
            }
887
        }
888
    };
889
890
10.2k
    let (j21, pad) = match connection_hint {
891
6.33k
        None => (j20, None),
892
3.96k
        Some(_) => match opt(take(1usize))(j20) as IResult<&[u8], _> {
893
3.67k
            Ok((rem, obj)) => (rem, obj),
894
285
            _ => (j20, None),
895
        },
896
    };
897
898
10.2k
    let (j22, server_selected_protocol) = match pad {
899
6.61k
        None => (j21, None),
900
        Some(_) => {
901
3.67k
            match opt(map_opt(le_u32, ProtocolFlags::from_bits))(j21) as IResult<&[u8], _> {
902
3.45k
                Ok((rem, obj)) => (rem, obj),
903
219
                _ => (j21, None),
904
            }
905
        }
906
    };
907
908
10.2k
    let (j23, desktop_physical_width) = match server_selected_protocol {
909
7.28k
        None => (j22, None),
910
3.01k
        Some(_) => match opt(map_opt(le_u32, millimeters_to_opt))(j22) as IResult<&[u8], _> {
911
2.68k
            Ok((rem, obj)) => (rem, obj),
912
334
            _ => (j22, None),
913
        },
914
    };
915
916
10.2k
    let (j24, desktop_physical_height) = match desktop_physical_width {
917
7.85k
        None => (j23, None),
918
2.43k
        Some(_) => match opt(map_opt(le_u32, millimeters_to_opt))(j23) as IResult<&[u8], _> {
919
2.24k
            Ok((rem, obj)) => (rem, obj),
920
194
            _ => (j23, None),
921
        },
922
    };
923
924
10.2k
    let (j25, desktop_orientation) = match desktop_physical_height {
925
8.28k
        None => (j24, None),
926
        Some(_) => {
927
2.00k
            match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j24) as IResult<&[u8], _> {
928
1.80k
                Ok((rem, obj)) => (rem, obj),
929
201
                _ => (j24, None),
930
            }
931
        }
932
    };
933
934
10.2k
    let (j26, desktop_scale_factor) = match desktop_orientation {
935
8.69k
        None => (j25, None),
936
1.59k
        Some(_) => match opt(map_opt(le_u32, desktop_scale_to_opt))(j25) as IResult<&[u8], _> {
937
1.40k
            Ok((rem, obj)) => (rem, obj),
938
195
            _ => (j25, None),
939
        },
940
    };
941
942
10.2k
    let (_j27, device_scale_factor) = match desktop_scale_factor {
943
9.32k
        None => (j26, None),
944
973
        Some(_) => match opt(map_opt(le_u32, device_scale_to_opt))(j26) as IResult<&[u8], _> {
945
777
            Ok((rem, obj)) => (rem, obj),
946
196
            _ => (j26, None),
947
        },
948
    };
949
950
10.2k
    return Ok((
951
10.2k
        i3,
952
10.2k
        CsClientCoreData {
953
10.2k
            version,
954
10.2k
            desktop_width,
955
10.2k
            desktop_height,
956
10.2k
            color_depth,
957
10.2k
            sas_sequence,
958
10.2k
            keyboard_layout,
959
10.2k
            client_build,
960
10.2k
            client_name,
961
10.2k
            keyboard_type,
962
10.2k
            keyboard_subtype,
963
10.2k
            keyboard_function_key,
964
10.2k
            ime_file_name,
965
10.2k
            post_beta2_color_depth,
966
10.2k
            client_product_id,
967
10.2k
            serial_number,
968
10.2k
            high_color_depth,
969
10.2k
            supported_color_depth,
970
10.2k
            early_capability_flags,
971
10.2k
            client_dig_product_id,
972
10.2k
            connection_hint,
973
10.2k
            server_selected_protocol,
974
10.2k
            desktop_physical_width,
975
10.2k
            desktop_physical_height,
976
10.2k
            desktop_orientation,
977
10.2k
            desktop_scale_factor,
978
10.2k
            device_scale_factor,
979
10.2k
        },
980
10.2k
    ));
981
41.4k
}
982
983
/// rdp-spec, section 2.2.1.3.4
984
19.5k
fn parse_cs_net(input: &[u8]) -> IResult<&[u8], CsNet> {
985
19.5k
    let (i1, _typ) = verify(le_u16, |&x| x == CsType::Net as u16)(input)?;
986
    // less _typ (u16), this length indicator (u16), count (u32)
987
3.19k
    let (i2, sz) = map_opt(le_u16, |x: u16| x.checked_sub(8))(i1)?;
988
2.76k
    let (i3, count) = le_u32(i2)?;
989
2.53k
    let (i4, data) = take(sz)(i3)?;
990
991
2.28k
    let mut remainder: &[u8] = data;
992
2.28k
    let mut channels = Vec::new();
993
994
2.35k
    for _index in 0..count {
995
        // a channel name is 8 bytes, section 2.2.1.3.4.1
996
2.35k
        let (j1, name) = map_res(take(8_usize), utf7_slice_to_string)(remainder)?;
997
1.65k
        channels.push(name);
998
        // options (u32) are discarded for now
999
1.65k
        let (j2, _options) = le_u32(j1)?;
1000
1.27k
        remainder = j2;
1001
    }
1002
1003
1.20k
    return Ok((i4, CsNet { channels }));
1004
19.5k
}
1005
1006
// generic CS structure parse
1007
// cf. rdp-spec, section 2.2.1.3.4
1008
16.8k
fn parse_cs_unknown(i: &[u8]) -> IResult<&[u8], CsUnknown> {
1009
16.8k
    let (i, typ) = map_opt(le_u16, |x| {
1010
16.8k
        let opt: Option<CsType> = num::FromPrimitive::from_u16(x);
1011
16.8k
        match opt {
1012
            // an unknown type must not be present in CsType
1013
1.37k
            Some(_) => None,
1014
15.4k
            None => Some(x),
1015
        }
1016
16.8k
    })(i)?;
1017
    // less u16, u16
1018
15.4k
    let (i, sz) = map_opt(le_u16, |x: u16| x.checked_sub(4))(i)?;
1019
13.1k
    let (i, data) = take(sz)(i)?;
1020
7.41k
    Ok((i, CsUnknown { typ, data: data.to_vec() }))
1021
16.8k
}
1022
1023
// rdp-spec, section 2.2.1.4
1024
1.71k
fn parse_mcs_connect_response(i: &[u8]) -> IResult<&[u8], McsConnectResponse, RdpError> {
1025
1.71k
    let (i, _ber_type) = verify(
1026
        le_u8,
1027
        // BER: 0b01=application, 0b1=non-primitive, 0b11111
1028
1.71k
        |&x| x == 0x7f)(i)?;
1029
1.21k
    let (i, _t125_type) = verify(le_u8, |&x| x == T125Type::T125TypeMcsConnectResponse as u8)(i)?;
1030
283
    Ok((i, McsConnectResponse {}))
1031
1.71k
}
1032
1033
#[cfg(test)]
1034
mod tests_cookie_21182 {
1035
    use crate::rdp::parser::*;
1036
1037
    static BYTES: [u8; 37] = [
1038
        0x03, 0x00, 0x00, 0x25, 0x20, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6f, 0x6b,
1039
        0x69, 0x65, 0x3a, 0x20, 0x6d, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3d, 0x75, 0x73,
1040
        0x65, 0x72, 0x31, 0x32, 0x33, 0x0d, 0x0a,
1041
    ];
1042
1043
    #[test]
1044
    fn test_t123_x224_cookie() {
1045
        let t123_bytes = &BYTES[..];
1046
        let t123_tpkt: T123Tpkt = T123Tpkt {
1047
            child: T123TpktChild::X224ConnectionRequest(X224ConnectionRequest {
1048
                cdt: 0,
1049
                dst_ref: 0,
1050
                src_ref: 0,
1051
                class: 0,
1052
                options: 0,
1053
                cookie: Some(RdpCookie {
1054
                    mstshash: String::from("user123"),
1055
                }),
1056
                negotiation_request: None,
1057
                data: Vec::new(),
1058
            }),
1059
        };
1060
        assert_eq!(Ok((&[][..], t123_tpkt)), parse_t123_tpkt(t123_bytes));
1061
    }
1062
}
1063
1064
#[cfg(test)]
1065
mod tests_negotiate_49350 {
1066
    use crate::rdp::parser::*;
1067
1068
    static BYTES: [u8; 20] = [
1069
        0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00,
1070
        0x00, 0x00, 0x00, 0x00, 0xff,
1071
    ];
1072
    static TPKT_BEGIN: usize = 0;
1073
    static X224_BEGIN: usize = TPKT_BEGIN + 4;
1074
    static NEG_REQ_BEGIN: usize = X224_BEGIN + 7;
1075
    static NEG_REQ_END: usize = NEG_REQ_BEGIN + 8;
1076
    static X224_END: usize = NEG_REQ_END;
1077
    static TPKT_END: usize = X224_END;
1078
    static PADDING_BEGIN: usize = TPKT_END;
1079
1080
    #[test]
1081
    fn test_t123_x224_negotiate() {
1082
        let t123_bytes = &BYTES[TPKT_BEGIN..];
1083
        let t123_tpkt: T123Tpkt = T123Tpkt {
1084
            child: T123TpktChild::X224ConnectionRequest(X224ConnectionRequest {
1085
                cdt: 0,
1086
                dst_ref: 0,
1087
                src_ref: 0,
1088
                class: 0,
1089
                options: 0,
1090
                cookie: None,
1091
                negotiation_request: Some(NegotiationRequest {
1092
                    flags: NegotiationRequestFlags::empty(),
1093
                    protocols: ProtocolFlags { bits: Protocol::ProtocolRdp as u32 },
1094
                }),
1095
                data: Vec::new(),
1096
            }),
1097
        };
1098
        assert_eq!(
1099
            Ok((&BYTES[PADDING_BEGIN..][..], t123_tpkt)),
1100
            parse_t123_tpkt(t123_bytes)
1101
        )
1102
    }
1103
}
1104
1105
#[cfg(test)]
1106
#[allow(clippy::vec_init_then_push)]
1107
mod tests_core_49350 {
1108
    use crate::rdp::parser::*;
1109
1110
    static BYTES: [u8; 429] = [
1111
        0x03, 0x00, 0x01, 0xac, 0x02, 0xf0, 0x80, 0x7f, 0x65, 0x82, 0x01, 0xa0, 0x04, 0x01, 0x01,
1112
        0x04, 0x01, 0x01, 0x01, 0x01, 0xff, 0x30, 0x19, 0x02, 0x01, 0x22, 0x02, 0x01, 0x02, 0x02,
1113
        0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff,
1114
        0x02, 0x01, 0x02, 0x30, 0x19, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02,
1115
        0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x20, 0x02, 0x01, 0x02,
1116
        0x30, 0x1c, 0x02, 0x02, 0xff, 0xff, 0x02, 0x02, 0xfc, 0x17, 0x02, 0x02, 0xff, 0xff, 0x02,
1117
        0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff, 0x02, 0x01, 0x02,
1118
        0x04, 0x82, 0x01, 0x3f, 0x00, 0x05, 0x00, 0x14, 0x7c, 0x00, 0x01, 0x81, 0x36, 0x00, 0x08,
1119
        0x00, 0x10, 0x00, 0x01, 0xc0, 0x00, 0x44, 0x75, 0x63, 0x61, 0x81, 0x28, 0x01, 0xc0, 0xd8,
1120
        0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x05, 0x00, 0x03, 0x01, 0xca, 0x03, 0xaa, 0x09, 0x04,
1121
        0x00, 0x00, 0x71, 0x17, 0x00, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00, 0x45,
1122
        0x00, 0x52, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
1123
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1124
        0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1125
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1126
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1127
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1128
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xca, 0x01, 0x00, 0x00, 0x00,
1129
        0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1130
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1131
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1132
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1133
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1134
        0x00, 0x00, 0x00, 0x04, 0xc0, 0x0c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1135
        0x02, 0xc0, 0x0c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x38,
1136
        0x00, 0x04, 0x00, 0x00, 0x00, 0x72, 0x64, 0x70, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
1137
        0x80, 0x80, 0x72, 0x64, 0x70, 0x73, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64,
1138
        0x72, 0x64, 0x79, 0x6e, 0x76, 0x63, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x63, 0x6c, 0x69, 0x70,
1139
        0x72, 0x64, 0x72, 0x00, 0x00, 0x00, 0xa0, 0xc0, 0xff,
1140
    ];
1141
    static TPKT_BEGIN: usize = 0;
1142
    static X223_BEGIN: usize = TPKT_BEGIN + 4;
1143
    static MCS_CONNECT_BEGIN: usize = X223_BEGIN + 3;
1144
    static MCS_CONNECT_END: usize = MCS_CONNECT_BEGIN + 421;
1145
    static X223_END: usize = MCS_CONNECT_END;
1146
    static TPKT_END: usize = X223_END;
1147
    static PADDING_BEGIN: usize = TPKT_END;
1148
1149
    #[test]
1150
    fn test_t123_x223_connect_core() {
1151
        let t123_bytes = &BYTES[TPKT_BEGIN..];
1152
        let core_data = CsClientCoreData {
1153
            version: Some(RdpClientVersion::V5_V8_1),
1154
            desktop_width: 1280,
1155
            desktop_height: 768,
1156
            color_depth: Some(ColorDepth::RnsUdColor8Bpp),
1157
            sas_sequence: Some(SasSequence::RnsUdSasDel),
1158
            keyboard_layout: 0x409,
1159
            client_build: windows::OperatingSystem {
1160
                build: windows::Build::Vista_6001,
1161
                suffix: windows::Suffix::Sp1,
1162
            },
1163
            client_name: String::from("SERVER-XYZ"),
1164
            keyboard_type: Some(KeyboardType::KbEnhanced),
1165
            keyboard_subtype: 0,
1166
            keyboard_function_key: 12,
1167
            ime_file_name: String::from(""),
1168
            post_beta2_color_depth: Some(PostBeta2ColorDepth::RnsUdColor8Bpp),
1169
            client_product_id: Some(1),
1170
            serial_number: Some(0),
1171
            high_color_depth: Some(HighColorDepth::HighColor8Bpp),
1172
            supported_color_depth: Some(
1173
                SupportedColorDepth::RNS_UD_15_BPP_SUPPORT
1174
                    | SupportedColorDepth::RNS_UD_16_BPP_SUPPORT
1175
                    | SupportedColorDepth::RNS_UD_24_BPP_SUPPORT
1176
                    | SupportedColorDepth::RNS_UD_32_BPP_SUPPORT,
1177
            ),
1178
            early_capability_flags: Some(
1179
                EarlyCapabilityFlags::RNS_UD_CS_SUPPORT_ERRINFO_PDF
1180
                    | EarlyCapabilityFlags::RNS_UD_CS_STRONG_ASYMMETRIC_KEYS,
1181
            ),
1182
            client_dig_product_id: Some(String::from("")),
1183
            connection_hint: Some(ConnectionHint::ConnectionHintNotProvided),
1184
            server_selected_protocol: Some(ProtocolFlags { bits: Protocol::ProtocolRdp as u32 }),
1185
            desktop_physical_width: None,
1186
            desktop_physical_height: None,
1187
            desktop_orientation: None,
1188
            desktop_scale_factor: None,
1189
            device_scale_factor: None,
1190
        };
1191
        let mut children = Vec::new();
1192
        children.push(McsConnectRequestChild::CsClientCore(core_data));
1193
        children.push(McsConnectRequestChild::CsUnknown(CsUnknown {
1194
            typ: 0xc004,
1195
            data: BYTES[0x160..0x160 + 0x8].to_vec(),
1196
        }));
1197
        children.push(McsConnectRequestChild::CsUnknown(CsUnknown {
1198
            typ: 0xc002,
1199
            data: BYTES[0x16c..0x16c + 0x8].to_vec(),
1200
        }));
1201
        let mut channels = Vec::new();
1202
        channels.push(String::from("rdpdr"));
1203
        channels.push(String::from("rdpsnd"));
1204
        channels.push(String::from("drdynvc"));
1205
        channels.push(String::from("cliprdr"));
1206
        children.push(McsConnectRequestChild::CsNet(CsNet { channels }));
1207
        let t123_tpkt: T123Tpkt = T123Tpkt {
1208
            child: T123TpktChild::Data(X223Data {
1209
                child: X223DataChild::McsConnectRequest(McsConnectRequest { children }),
1210
            }),
1211
        };
1212
        assert_eq!(
1213
            Ok((&BYTES[PADDING_BEGIN..][..], t123_tpkt)),
1214
            parse_t123_tpkt(t123_bytes)
1215
        );
1216
    }
1217
}
1218
1219
#[cfg(test)]
1220
mod tests_x223_response_49350 {
1221
    use crate::rdp::parser::*;
1222
1223
    // changed offset 9 from 0x65 to 0x66 so it is no longer an mcs connect
1224
    static BYTES: [u8; 9] = [0x03, 0x00, 0x00, 0x09, 0x02, 0xf0, 0x80, 0x7f, 0x66];
1225
1226
    #[test]
1227
    fn test_x223_response() {
1228
        let t123_bytes = &BYTES[..];
1229
        assert_eq!(
1230
            Ok((
1231
                &[][..],
1232
                T123Tpkt {
1233
                    child: T123TpktChild::Data(X223Data {
1234
                        child: X223DataChild::McsConnectResponse(McsConnectResponse {}),
1235
                    })
1236
                }
1237
            )),
1238
            parse_t123_tpkt(t123_bytes)
1239
        )
1240
    }
1241
}
1242
1243
#[cfg(test)]
1244
mod tests_t123_raw_49350 {
1245
    use crate::rdp::parser::*;
1246
1247
    // changed offset 4 from 0x02 to 0x03 so it is no longer an X223 data object
1248
    static BYTES: [u8; 9] = [0x03, 0x00, 0x00, 0x09, 0x03, 0xf0, 0x80, 0x7f, 0x65];
1249
1250
    #[test]
1251
    fn test_t123_raw() {
1252
        let t123_bytes = &BYTES[..];
1253
        assert_eq!(
1254
            Ok((
1255
                &[][..],
1256
                T123Tpkt {
1257
                    child: T123TpktChild::Raw(BYTES[4..].to_vec())
1258
                }
1259
            )),
1260
            parse_t123_tpkt(t123_bytes)
1261
        )
1262
    }
1263
}
1264
1265
#[cfg(test)]
1266
mod tests_x224_raw_49350 {
1267
    use crate::rdp::parser::*;
1268
1269
    // changed offset 11 from 0x01 to 0x02 so it is not a known X224 payload type
1270
    static BYTES: [u8; 19] = [
1271
        0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00,
1272
        0x00, 0x00, 0x00, 0x00,
1273
    ];
1274
1275
    #[test]
1276
    fn test_x224_raw() {
1277
        let t123_bytes = &BYTES[..];
1278
        assert_eq!(
1279
            Ok((
1280
                &[][..],
1281
                T123Tpkt {
1282
                    child: T123TpktChild::X224ConnectionRequest(X224ConnectionRequest {
1283
                        cdt: 0,
1284
                        dst_ref: 0,
1285
                        src_ref: 0,
1286
                        class: 0,
1287
                        options: 0,
1288
                        cookie: None,
1289
                        negotiation_request: None,
1290
                        data: BYTES[11..].to_vec(),
1291
                    })
1292
                }
1293
            )),
1294
            parse_t123_tpkt(t123_bytes)
1295
        )
1296
    }
1297
}
1298
1299
#[cfg(test)]
1300
mod tests_x223_raw_49350 {
1301
    use crate::rdp::parser::*;
1302
1303
    // changed offset 9 from 0x65 to 0xff so it is no longer an mcs connect
1304
    static BYTES: [u8; 9] = [0x03, 0x00, 0x00, 0x09, 0x02, 0xf0, 0x80, 0x7f, 0xff];
1305
1306
    #[test]
1307
    fn test_x223_raw() {
1308
        let t123_bytes = &BYTES[..];
1309
        assert_eq!(
1310
            Ok((
1311
                &[][..],
1312
                T123Tpkt {
1313
                    child: T123TpktChild::Data(X223Data {
1314
                        child: X223DataChild::Raw(BYTES[7..].to_vec()),
1315
                    })
1316
                }
1317
            )),
1318
            parse_t123_tpkt(t123_bytes)
1319
        )
1320
    }
1321
}
1322
1323
#[cfg(test)]
1324
mod tests_negotiate_incomplete_49350 {
1325
    use crate::rdp::parser::*;
1326
    use nom7::Needed;
1327
1328
    static BYTES: [u8; 19] = [
1329
        0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00,
1330
        0x00, 0x00, 0x00, 0x00,
1331
    ];
1332
    static TPKT_BEGIN: usize = 0;
1333
    static X224_BEGIN: usize = TPKT_BEGIN + 4;
1334
    static NEG_REQ_BEGIN: usize = X224_BEGIN + 7;
1335
    static NEG_REQ_END: usize = NEG_REQ_BEGIN + 8;
1336
    static X224_END: usize = NEG_REQ_END;
1337
    static TPKT_END: usize = X224_END;
1338
1339
    #[test]
1340
    fn test_t123_incomplete() {
1341
        let t123_bytes = &BYTES[TPKT_BEGIN..TPKT_END - 1];
1342
        assert_eq!(
1343
            // fails: map_opt!(i2, be_u16, |x: u16| x.checked_sub(4))?
1344
            Err(Err::Incomplete(Needed::new(1))),
1345
            parse_t123_tpkt(t123_bytes)
1346
        )
1347
    }
1348
1349
    #[test]
1350
    fn test_x224_incomplete() {
1351
        let x224_bytes = &BYTES[X224_BEGIN..X224_END - 1];
1352
        assert_eq!(
1353
            // fails: expr_opt!(i5, length.checked_sub(6))?
1354
            // not counting a u8 length read, which was also successful
1355
            Err(Err::Incomplete(Needed::new( 1))),
1356
            parse_x224_connection_request_class_0(x224_bytes)
1357
        )
1358
    }
1359
1360
    #[test]
1361
    fn test_negotiate_incomplete() {
1362
        let neg_req_bytes = &BYTES[NEG_REQ_BEGIN..NEG_REQ_END - 1];
1363
        assert_eq!(
1364
            // fails: map_opt!(le_u32, num::FromPrimitive::from_u32)?
1365
            Err(Err::Incomplete(Needed::new(1))),
1366
            parse_negotiation_request(neg_req_bytes)
1367
        )
1368
    }
1369
}
1370
1371
#[cfg(test)]
1372
mod tests_core_incomplete_49350 {
1373
    use crate::rdp::parser::*;
1374
    use nom7::Needed;
1375
1376
    static BYTES: [u8; 428] = [
1377
        0x03, 0x00, 0x01, 0xac, 0x02, 0xf0, 0x80, 0x7f, 0x65, 0x82, 0x01, 0xa0, 0x04, 0x01, 0x01,
1378
        0x04, 0x01, 0x01, 0x01, 0x01, 0xff, 0x30, 0x19, 0x02, 0x01, 0x22, 0x02, 0x01, 0x02, 0x02,
1379
        0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff,
1380
        0x02, 0x01, 0x02, 0x30, 0x19, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02,
1381
        0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x20, 0x02, 0x01, 0x02,
1382
        0x30, 0x1c, 0x02, 0x02, 0xff, 0xff, 0x02, 0x02, 0xfc, 0x17, 0x02, 0x02, 0xff, 0xff, 0x02,
1383
        0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff, 0x02, 0x01, 0x02,
1384
        0x04, 0x82, 0x01, 0x3f, 0x00, 0x05, 0x00, 0x14, 0x7c, 0x00, 0x01, 0x81, 0x36, 0x00, 0x08,
1385
        0x00, 0x10, 0x00, 0x01, 0xc0, 0x00, 0x44, 0x75, 0x63, 0x61, 0x81, 0x28, 0x01, 0xc0, 0xd8,
1386
        0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x05, 0x00, 0x03, 0x01, 0xca, 0x03, 0xaa, 0x09, 0x04,
1387
        0x00, 0x00, 0x71, 0x17, 0x00, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00, 0x45,
1388
        0x00, 0x52, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
1389
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1390
        0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1391
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1392
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1393
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1394
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xca, 0x01, 0x00, 0x00, 0x00,
1395
        0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1396
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1397
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1398
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1399
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1400
        0x00, 0x00, 0x00, 0x04, 0xc0, 0x0c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1401
        0x02, 0xc0, 0x0c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x38,
1402
        0x00, 0x04, 0x00, 0x00, 0x00, 0x72, 0x64, 0x70, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
1403
        0x80, 0x80, 0x72, 0x64, 0x70, 0x73, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64,
1404
        0x72, 0x64, 0x79, 0x6e, 0x76, 0x63, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x63, 0x6c, 0x69, 0x70,
1405
        0x72, 0x64, 0x72, 0x00, 0x00, 0x00, 0xa0, 0xc0,
1406
    ];
1407
    static X223_BEGIN: usize = 4;
1408
    static MCS_CONNECT_BEGIN: usize = X223_BEGIN + 3;
1409
    static MCS_CONNECT_END: usize = MCS_CONNECT_BEGIN + 421;
1410
    static _X223_END: usize = MCS_CONNECT_END;
1411
1412
    #[test]
1413
    fn test_x223_incomplete() {
1414
        let x223_bytes = &BYTES[X223_BEGIN..X223_BEGIN + 2];
1415
        assert_eq!(
1416
            // fails: verify!(i2, be_u8, |x| x == 0x80)?
1417
            Err(Err::Incomplete(Needed::new(1))),
1418
            parse_x223_data_class_0(x223_bytes)
1419
        )
1420
    }
1421
1422
    #[test]
1423
    fn test_connect_incomplete() {
1424
        let connect_bytes = &BYTES[MCS_CONNECT_BEGIN..MCS_CONNECT_END - 1];
1425
        assert_eq!(
1426
            // fails: length_data!(i3, parse_per_length_determinant)?
1427
            // which reads the length (2) but not the full data (0x128)
1428
            Err(Err::Incomplete(Needed::new(1))),
1429
            parse_mcs_connect(connect_bytes)
1430
        )
1431
    }
1432
}