Coverage Report

Created: 2026-03-31 07:45

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.98k
fn millimeters_to_opt(x: u32) -> Option<u32> {
45
4.98k
    if (10..=10_000).contains(&x) {
46
4.50k
        Some(x)
47
    } else {
48
483
        None
49
    }
50
4.98k
}
51
52
/// constrains desktop scale to a range, per spec
53
/// rdp-spec, section 2.2.1.3.2 Client Core Data
54
1.41k
fn desktop_scale_to_opt(x: u32) -> Option<u32> {
55
1.41k
    if (100..=500).contains(&x) {
56
982
        Some(x)
57
    } else {
58
432
        None
59
    }
60
1.41k
}
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
785
fn device_scale_to_opt(x: u32) -> Option<u32> {
65
785
    if x == 100 || x == 140 || x == 180 {
66
590
        Some(x)
67
    } else {
68
195
        None
69
    }
70
785
}
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.25M
pub fn parse_t123_tpkt(input: &[u8]) -> IResult<&[u8], T123Tpkt, RdpError> {
442
2.25M
    let (i1, _version) = verify(be_u8, |&x| x == TpktVersion::T123 as u8)(input)?;
443
2.25M
    let (i2, _reserved) = be_u8(i1)?;
444
    // less u8, u8, u16
445
2.24M
    let (i3, sz) = map_opt(be_u16, |x: u16| x.checked_sub(4))(i2)?;
446
2.24M
    let (i4, data) = take(sz)(i3)?;
447
448
2.22M
    let opt1: Option<T123TpktChild> = {
449
2.22M
        match opt(parse_x224_connection_request_class_0)(data) {
450
2.22M
            Ok((_remainder, opt)) => opt.map(T123TpktChild::X224ConnectionRequest),
451
4.80k
            Err(e) => return Err(e),
452
        }
453
    };
454
455
2.22M
    let opt2: Option<T123TpktChild> = match opt1 {
456
956k
        Some(x) => Some(x),
457
1.26M
        None => match opt(parse_x224_connection_confirm_class_0)(data) {
458
1.26M
            Ok((_remainder, opt)) => opt.map(T123TpktChild::X224ConnectionConfirm),
459
2.75k
            Err(e) => return Err(e),
460
        },
461
    };
462
463
2.22M
    let opt3: Option<T123TpktChild> = match opt2 {
464
2.16M
        Some(x) => Some(x),
465
60.2k
        None => match opt(parse_x223_data_class_0)(data) {
466
31.0k
            Ok((_remainder, opt)) => opt.map(T123TpktChild::Data),
467
29.1k
            Err(e) => return Err(e),
468
        },
469
    };
470
2.19M
    let child: T123TpktChild = match opt3 {
471
2.16M
        Some(x) => x,
472
24.8k
        None => T123TpktChild::Raw(data.to_vec()),
473
    };
474
475
2.19M
    return Ok((i4, T123Tpkt { child }));
476
2.25M
}
477
478
3.49M
fn take_4_4_bits(input: &[u8]) -> IResult<&[u8], (u8, u8), RdpError> {
479
3.49M
    map(be_u8, |b| (b >> 4, b & 0xf))(input)
480
3.49M
}
481
482
2.17M
fn parse_class_options(i: &[u8]) -> IResult<&[u8], (u8, u8)> {
483
2.17M
    bits(
484
2.17M
        tuple((
485
2.17M
            verify(take_bits(4u8), |&x| x <= 4),
486
2.17M
            verify(take_bits(4u8), |&x| x <= 3)
487
        ))
488
2.17M
    )(i)
489
2.17M
}
490
491
/// rdp-spec, section 2.2.1.1
492
2.22M
fn parse_x224_connection_request(input: &[u8]) -> IResult<&[u8], X224ConnectionRequest, RdpError> {
493
2.22M
    let (i1, length) = verify(be_u8, |&x| x != 0xff)(input)?; // 0xff is reserved
494
2.22M
    let (i2, cr_cdt) = take_4_4_bits(i1)?;
495
2.22M
    if cr_cdt.0 != X224Type::ConnectionRequest as u8 {
496
1.25M
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
497
972k
    }
498
972k
    if !(cr_cdt.1 == 0 || cr_cdt.1 == 1) {
499
319
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
500
972k
    }
501
972k
    let (i3, dst_ref) = verify(be_u16, |&x| x == 0)(i2)?;
502
966k
    let (i4, src_ref) = be_u16(i3)?;
503
966k
    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
964k
    if length < 6 {
506
472
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
507
964k
    }
508
964k
    let i6 = i5;
509
964k
    let sz = length - 6;
510
511
    //
512
    // optionally find cookie and/or negotiation request
513
    //
514
515
963k
    let (i7, data) = {
516
964k
        if sz > 0 {
517
74.1k
            take(sz)(i6)?
518
        } else {
519
889k
            (i6, &[][..])
520
        }
521
    };
522
523
961k
    let (j1, cookie) = {
524
963k
        if !data.is_empty() {
525
73.7k
            match opt(parse_rdp_cookie)(data) {
526
71.7k
                Ok((remainder, opt)) => (remainder, opt),
527
2.03k
                Err(e) => return Err(e),
528
            }
529
        } else {
530
889k
            (&[][..], None)
531
        }
532
    };
533
534
960k
    let (j2, negotiation_request) = {
535
961k
        if !j1.is_empty() {
536
71.6k
            match opt(parse_negotiation_request)(j1) {
537
70.9k
                Ok((remainder, opt)) => (remainder, opt),
538
714
                Err(e) => return Err(e),
539
            }
540
        } else {
541
890k
            (&[][..], None)
542
        }
543
    };
544
545
960k
    return Ok((
546
960k
        i7,
547
960k
        X224ConnectionRequest {
548
960k
            cdt: cr_cdt.1,
549
960k
            dst_ref,
550
960k
            src_ref,
551
960k
            class: class_options.0,
552
960k
            options: class_options.1,
553
960k
            cookie,
554
960k
            negotiation_request,
555
960k
            data: j2.to_vec(),
556
960k
        },
557
960k
    ));
558
2.22M
}
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.22M
fn parse_x224_connection_request_class_0(
563
2.22M
    input: &[u8],
564
2.22M
) -> IResult<&[u8], X224ConnectionRequest, RdpError> {
565
2.22M
    let (i1, x224) = parse_x224_connection_request(input)?;
566
960k
    if x224.class == 0 && x224.options == 0 {
567
956k
        Ok((i1, x224))
568
    } else {
569
4.08k
        Err(Err::Error(RdpError::NotX224Class0Error))
570
    }
571
2.22M
}
572
573
// rdp-spec, section 2.2.1.1.1
574
73.7k
fn parse_rdp_cookie(i: &[u8]) -> IResult<&[u8], RdpCookie, RdpError> {
575
73.7k
    let (i, _key) = tag(b"Cookie: ")(i)?;
576
1.21k
    let (i, _name) = tag(b"mstshash=")(i)?;
577
175
    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
99
    let s = std::str::from_utf8(bytes).map_err(|_| Err::Error(make_error(bytes, ErrorKind::MapRes)))?;
580
99
    let cookie = RdpCookie{ mstshash: String::from(s) };
581
99
    Ok((i, cookie))
582
73.7k
}
583
584
// rdp-spec, section 2.2.1.1.1
585
71.6k
fn parse_negotiation_request(i: &[u8]) -> IResult<&[u8], NegotiationRequest, RdpError> {
586
71.6k
    let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationRequest as u8)(i)?;
587
2.99k
    let (i, flags) = map_opt(le_u8, NegotiationRequestFlags::from_bits)(i)?;
588
    // u8, u8, u16, and u32 give _length of 8
589
2.51k
    let (i, _length) = verify(le_u16, |&x| x == 8)(i)?;
590
1.12k
    let (i, protocols) = map_opt(le_u32, ProtocolFlags::from_bits)(i)?;
591
265
    Ok((i, NegotiationRequest { flags, protocols }))
592
71.6k
}
593
594
/// rdp-spec, section 2.2.1.2
595
/// x.224-spec, section 13.3
596
1.26M
fn parse_x224_connection_confirm(input: &[u8]) -> IResult<&[u8], X224ConnectionConfirm, RdpError> {
597
1.26M
    let (i1, length) = verify(be_u8, |&x| x != 0xff)(input)?; // 0xff is reserved
598
1.26M
    let (i2, cr_cdt) = take_4_4_bits(i1)?;
599
1.26M
    if cr_cdt.0 != X224Type::ConnectionConfirm as u8 {
600
54.2k
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
601
1.21M
    }
602
1.21M
    if !(cr_cdt.1 == 0 || cr_cdt.1 == 1) {
603
562
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
604
1.21M
    }
605
1.21M
    let (i3, dst_ref) = verify(be_u16, |&x| x == 0)(i2)?;
606
1.21M
    let (i4, src_ref) = be_u16(i3)?;
607
1.20M
    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.20M
    if length < 6 {
611
235
        return Err(Err::Error(make_error(i1, ErrorKind::Verify)));
612
1.20M
    }
613
1.20M
    let i6 = i5;
614
1.20M
    let sz = length - 6;
615
616
    // a negotiation message from the server might be absent (sz == 0)
617
1.20M
    let (i7, negotiation_from_server) = {
618
1.20M
        if sz > 0 {
619
7.90k
            let (i7, data) = take(sz)(i6)?;
620
621
            // it will be one of a response message or a failure message
622
7.54k
            let opt1: Option<NegotiationFromServer> = match opt(parse_negotiation_response)(data) {
623
6.64k
                Ok((_remainder, opt)) => opt.map(NegotiationFromServer::Response),
624
899
                Err(e) => return Err(e),
625
            };
626
6.64k
            let opt2: Option<NegotiationFromServer> = match opt1 {
627
458
                Some(x) => Some(x),
628
6.18k
                None => match opt(parse_negotiation_failure)(data) {
629
5.54k
                    Ok((_remainder, opt)) => opt.map(NegotiationFromServer::Failure),
630
645
                    Err(e) => return Err(e),
631
                },
632
            };
633
6.00k
            (i7, opt2)
634
        } else {
635
1.20M
            (i6, None)
636
        }
637
    };
638
639
1.20M
    return Ok((
640
1.20M
        i7,
641
1.20M
        X224ConnectionConfirm {
642
1.20M
            cdt: cr_cdt.1,
643
1.20M
            dst_ref,
644
1.20M
            src_ref,
645
1.20M
            class: class_options.0,
646
1.20M
            options: class_options.1,
647
1.20M
            negotiation_from_server,
648
1.20M
        },
649
1.20M
    ));
650
1.26M
}
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.26M
fn parse_x224_connection_confirm_class_0(
655
1.26M
    input: &[u8],
656
1.26M
) -> IResult<&[u8], X224ConnectionConfirm, RdpError> {
657
1.26M
    let (i1, x224) = parse_x224_connection_confirm(input)?;
658
1.20M
    if x224.class == 0 && x224.options == 0 {
659
1.20M
        Ok((i1, x224))
660
    } else {
661
        // x.224, but not a class 0 x.224 message
662
2.27k
        Err(Err::Error(RdpError::NotX224Class0Error))
663
    }
664
1.26M
}
665
666
// rdp-spec, section 2.2.1.1.1
667
7.54k
fn parse_negotiation_response(i: &[u8]) -> IResult<&[u8], NegotiationResponse, RdpError> {
668
7.54k
    let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationResponse as u8)(i)?;
669
2.76k
    let (i, flags) = map_opt(le_u8, NegotiationResponseFlags::from_bits)(i)?;
670
    // u8, u8, u16, and u32 give _length of 8
671
2.34k
    let (i, _length) = verify(le_u16, |&x| x == 8)(i)?;
672
1.42k
    let (i, protocol) = map_opt(le_u32, num::FromPrimitive::from_u32)(i)?;
673
458
    Ok((i, NegotiationResponse { flags, protocol }))
674
7.54k
}
675
676
// rdp-spec, section 2.2.1.1.1
677
6.18k
fn parse_negotiation_failure(i: &[u8]) -> IResult<&[u8], NegotiationFailure, RdpError> {
678
6.18k
    let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationFailure as u8)(i)?;
679
2.09k
    let (i, _flags) = le_u8(i)?;
680
    // u8, u8, u16, and u32 give _length of 8
681
1.90k
    let (i, _length) = verify(le_u16, |&x| x == 8)(i)?;
682
1.18k
    let (i, code) = map_opt(le_u32, num::FromPrimitive::from_u32)(i)?;
683
283
    Ok((i, NegotiationFailure { code }))
684
6.18k
}
685
686
/// x224-spec, section 13.7
687
60.2k
fn parse_x223_data_class_0(input: &[u8]) -> IResult<&[u8], X223Data, RdpError> {
688
38.7k
    fn parser(i: &[u8]) -> IResult<&[u8], (u8, u8, u8)> {
689
38.7k
        bits(
690
38.7k
            tuple((
691
38.7k
                verify(take_bits(4u8), |&x| x == 0xf),
692
38.7k
                verify(take_bits(3u8), |&x| x == 0),
693
38.7k
                verify(take_bits(1u8), |&x| x == 0)
694
            ))
695
38.7k
        )(i)
696
38.7k
    }
697
60.2k
    let (i1, _length) = verify(be_u8, |&x| x == 2)(input)?;
698
38.7k
    let (i2, _dt_x_roa) = parser(i1).map_err(Err::convert)?;
699
35.7k
    let (i3, _eot) = verify(be_u8, |&x| x == 0x80)(i2)?;
700
701
    //
702
    // optionally find exactly one of the child messages
703
    //
704
705
35.1k
    let opt1: Option<X223DataChild> = match opt(parse_mcs_connect)(i3) {
706
6.22k
        Ok((_remainder, opt)) => opt.map(X223DataChild::McsConnectRequest),
707
28.9k
        Err(e) => return Err(e),
708
    };
709
710
6.22k
    let opt2: Option<X223DataChild> = match opt1 {
711
4.01k
        Some(x) => Some(x),
712
2.21k
        None => match opt(parse_mcs_connect_response)(i3) {
713
2.21k
            Ok((_remainder, opt)) => opt.map(X223DataChild::McsConnectResponse),
714
0
            Err(e) => return Err(e),
715
        },
716
    };
717
718
6.22k
    let child: X223DataChild = match opt2 {
719
4.31k
        Some(x) => x,
720
1.91k
        None => X223DataChild::Raw(i3.to_vec()),
721
    };
722
723
6.22k
    return Ok((&[], X223Data { child }));
724
60.2k
}
725
726
/// rdp-spec, section 2.2.1.3.2
727
35.1k
fn parse_mcs_connect(input: &[u8]) -> IResult<&[u8], McsConnectRequest, RdpError> {
728
35.1k
    let (i1, _ber_type) = verify(
729
        le_u8,
730
        // BER: 0b01=application, 0b1=non-primitive, 0b11111
731
34.9k
        |&x| x == 0x7f
732
35.1k
    )(input)?;
733
34.2k
    let (i2, _t125_type) = verify(le_u8, |&x| x
734
34.2k
        == T125Type::T125TypeMcsConnectRequest as u8)(i1)?;
735
736
    // skip to, and consume, H.221 client-to-server key
737
33.1k
    let (i3, _skipped) = take_until_and_consume(b"Duca")(i2)?;
738
739
29.4k
    let (i4, data) = length_data(parse_per_length_determinant)(i3)?;
740
27.2k
    let mut remainder: &[u8] = data;
741
27.2k
    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
47.2k
        remainder = match opt(parse_cs_client_core_data)(remainder) {
747
33.1k
            Ok((rem, o)) => match o {
748
                // found CsClientCoreData
749
11.1k
                Some(core_data) => {
750
11.1k
                    children.push(McsConnectRequestChild::CsClientCore(core_data));
751
11.1k
                    rem
752
                }
753
22.0k
                None => match opt(parse_cs_net)(remainder) {
754
                    // found CsNet
755
20.5k
                    Ok((rem, o)) => match o {
756
1.21k
                        Some(net) => {
757
1.21k
                            children.push(McsConnectRequestChild::CsNet(net));
758
1.21k
                            rem
759
                        }
760
                        None => {
761
19.3k
                            match opt(parse_cs_unknown)(remainder) {
762
                                // was able to parse CsUnknown
763
11.6k
                                Ok((rem, o)) => match o {
764
9.50k
                                    Some(unknown) => {
765
9.50k
                                        children.push(McsConnectRequestChild::CsUnknown(unknown));
766
9.50k
                                        rem
767
                                    }
768
                                    None => {
769
2.14k
                                        break;
770
                                    }
771
                                },
772
7.71k
                                Err(Err::Incomplete(i)) => {
773
7.71k
                                    return Err(Err::Incomplete(i))
774
                                }
775
0
                                Err(Err::Failure(_)) | Err(Err::Error(_)) => break,
776
                            }
777
                        }
778
                    },
779
1.45k
                    Err(Err::Incomplete(i)) => return Err(Err::Incomplete(i)),
780
0
                    Err(Err::Failure(_)) | Err(Err::Error(_)) => break,
781
                },
782
            },
783
14.0k
            Err(Err::Incomplete(i)) => return Err(Err::Incomplete(i)),
784
0
            Err(Err::Failure(_)) | Err(Err::Error(_)) => break,
785
        };
786
21.8k
        if remainder.is_empty() {
787
1.87k
            break;
788
19.9k
        }
789
    }
790
791
4.01k
    return Ok((i4, McsConnectRequest { children }));
792
35.1k
}
793
794
/// rdp-spec, section 2.2.1.3.2
795
47.2k
fn parse_cs_client_core_data(input: &[u8]) -> IResult<&[u8], CsClientCoreData> {
796
47.2k
    let (i1, _typ) = verify(le_u16, |&x| x == CsType::Core as u16)(input)?;
797
    // less u16, u16
798
24.3k
    let (i2, sz) = map_opt(le_u16, |x: u16| x.checked_sub(4))(i1)?;
799
23.2k
    let (i3, data) = take(sz)(i2)?;
800
22.7k
    let (j1, version) = map(le_u32, num::FromPrimitive::from_u32)(data)?;
801
22.5k
    let (j2, desktop_width) = le_u16(j1)?;
802
22.0k
    let (j3, desktop_height) = le_u16(j2)?;
803
21.3k
    let (j4, color_depth) = map(le_u16, num::FromPrimitive::from_u16)(j3)?;
804
21.1k
    let (j5, sas_sequence) = map(le_u16, num::FromPrimitive::from_u16)(j4)?;
805
20.7k
    let (j6, keyboard_layout) = le_u32(j5)?;
806
20.2k
    let (j7, client_build) = map(le_u32, windows::build_number_to_os)(j6)?;
807
19.8k
    let (j8, client_name) = map_res(take(32_usize), le_slice_to_string)(j7)?;
808
13.0k
    let (j9, keyboard_type) = map(le_u32, num::FromPrimitive::from_u32)(j8)?;
809
12.8k
    let (j10, keyboard_subtype) = le_u32(j9)?;
810
12.3k
    let (j11, keyboard_function_key) = le_u32(j10)?;
811
11.7k
    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
11.1k
    let (j13, post_beta2_color_depth) =
818
11.1k
        match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j12) as IResult<&[u8], _> {
819
10.9k
            Ok((rem, obj)) => (rem, obj),
820
201
            _ => (j12, None),
821
        };
822
823
11.1k
    let (j14, client_product_id) = match post_beta2_color_depth {
824
1.21k
        None => (j13, None),
825
9.90k
        Some(_) => match opt(le_u16)(j13) as IResult<&[u8], _> {
826
9.70k
            Ok((rem, obj)) => (rem, obj),
827
195
            _ => (j13, None),
828
        },
829
    };
830
831
11.1k
    let (j15, serial_number) = match client_product_id {
832
1.40k
        None => (j14, None),
833
9.70k
        Some(_) => match opt(le_u32)(j14) as IResult<&[u8], _> {
834
8.90k
            Ok((rem, obj)) => (rem, obj),
835
807
            _ => (j14, None),
836
        },
837
    };
838
839
11.1k
    let (j16, high_color_depth) = match serial_number {
840
2.21k
        None => (j15, None),
841
        Some(_) => {
842
8.90k
            match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j15) as IResult<&[u8], _> {
843
7.70k
                Ok((rem, obj)) => (rem, obj),
844
1.19k
                _ => (j15, None),
845
            }
846
        }
847
    };
848
849
11.1k
    let (j17, supported_color_depth) = match high_color_depth {
850
4.15k
        None => (j16, None),
851
        Some(_) => {
852
6.95k
            match opt(map_opt(le_u16, SupportedColorDepth::from_bits))(j16) as IResult<&[u8], _> {
853
6.76k
                Ok((rem, obj)) => (rem, obj),
854
194
                _ => (j16, None),
855
            }
856
        }
857
    };
858
859
11.1k
    let (j18, early_capability_flags) = match supported_color_depth {
860
4.65k
        None => (j17, None),
861
        Some(_) => {
862
6.45k
            match opt(map_opt(le_u16, EarlyCapabilityFlags::from_bits))(j17) as IResult<&[u8], _>
863
            {
864
6.26k
                Ok((rem, obj)) => (rem, obj),
865
195
                _ => (j17, None),
866
            }
867
        }
868
    };
869
870
11.1k
    let (j19, client_dig_product_id) = match early_capability_flags {
871
5.28k
        None => (j18, None),
872
        Some(_) => {
873
5.82k
            match opt(map_res(take(64usize), le_slice_to_string))(j18) as IResult<&[u8], _> {
874
5.63k
                Ok((rem, obj)) => (rem, obj),
875
199
                _ => (j18, None),
876
            }
877
        }
878
    };
879
880
11.1k
    let (j20, connection_hint) = match client_dig_product_id {
881
6.05k
        None => (j19, None),
882
        Some(_) => {
883
5.05k
            match opt(map_opt(le_u8, num::FromPrimitive::from_u8))(j19) as IResult<&[u8], _> {
884
4.99k
                Ok((rem, obj)) => (rem, obj),
885
63
                _ => (j19, None),
886
            }
887
        }
888
    };
889
890
11.1k
    let (j21, pad) = match connection_hint {
891
7.14k
        None => (j20, None),
892
3.97k
        Some(_) => match opt(take(1usize))(j20) as IResult<&[u8], _> {
893
3.71k
            Ok((rem, obj)) => (rem, obj),
894
258
            _ => (j20, None),
895
        },
896
    };
897
898
11.1k
    let (j22, server_selected_protocol) = match pad {
899
7.40k
        None => (j21, None),
900
        Some(_) => {
901
3.71k
            match opt(map_opt(le_u32, ProtocolFlags::from_bits))(j21) as IResult<&[u8], _> {
902
3.48k
                Ok((rem, obj)) => (rem, obj),
903
226
                _ => (j21, None),
904
            }
905
        }
906
    };
907
908
11.1k
    let (j23, desktop_physical_width) = match server_selected_protocol {
909
8.07k
        None => (j22, None),
910
3.04k
        Some(_) => match opt(map_opt(le_u32, millimeters_to_opt))(j22) as IResult<&[u8], _> {
911
2.71k
            Ok((rem, obj)) => (rem, obj),
912
330
            _ => (j22, None),
913
        },
914
    };
915
916
11.1k
    let (j24, desktop_physical_height) = match desktop_physical_width {
917
8.64k
        None => (j23, None),
918
2.46k
        Some(_) => match opt(map_opt(le_u32, millimeters_to_opt))(j23) as IResult<&[u8], _> {
919
2.27k
            Ok((rem, obj)) => (rem, obj),
920
194
            _ => (j23, None),
921
        },
922
    };
923
924
11.1k
    let (j25, desktop_orientation) = match desktop_physical_height {
925
9.08k
        None => (j24, None),
926
        Some(_) => {
927
2.03k
            match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j24) as IResult<&[u8], _> {
928
1.82k
                Ok((rem, obj)) => (rem, obj),
929
214
                _ => (j24, None),
930
            }
931
        }
932
    };
933
934
11.1k
    let (j26, desktop_scale_factor) = match desktop_orientation {
935
9.50k
        None => (j25, None),
936
1.60k
        Some(_) => match opt(map_opt(le_u32, desktop_scale_to_opt))(j25) as IResult<&[u8], _> {
937
1.41k
            Ok((rem, obj)) => (rem, obj),
938
195
            _ => (j25, None),
939
        },
940
    };
941
942
11.1k
    let (_j27, device_scale_factor) = match desktop_scale_factor {
943
10.1k
        None => (j26, None),
944
982
        Some(_) => match opt(map_opt(le_u32, device_scale_to_opt))(j26) as IResult<&[u8], _> {
945
785
            Ok((rem, obj)) => (rem, obj),
946
197
            _ => (j26, None),
947
        },
948
    };
949
950
11.1k
    return Ok((
951
11.1k
        i3,
952
11.1k
        CsClientCoreData {
953
11.1k
            version,
954
11.1k
            desktop_width,
955
11.1k
            desktop_height,
956
11.1k
            color_depth,
957
11.1k
            sas_sequence,
958
11.1k
            keyboard_layout,
959
11.1k
            client_build,
960
11.1k
            client_name,
961
11.1k
            keyboard_type,
962
11.1k
            keyboard_subtype,
963
11.1k
            keyboard_function_key,
964
11.1k
            ime_file_name,
965
11.1k
            post_beta2_color_depth,
966
11.1k
            client_product_id,
967
11.1k
            serial_number,
968
11.1k
            high_color_depth,
969
11.1k
            supported_color_depth,
970
11.1k
            early_capability_flags,
971
11.1k
            client_dig_product_id,
972
11.1k
            connection_hint,
973
11.1k
            server_selected_protocol,
974
11.1k
            desktop_physical_width,
975
11.1k
            desktop_physical_height,
976
11.1k
            desktop_orientation,
977
11.1k
            desktop_scale_factor,
978
11.1k
            device_scale_factor,
979
11.1k
        },
980
11.1k
    ));
981
47.2k
}
982
983
/// rdp-spec, section 2.2.1.3.4
984
22.0k
fn parse_cs_net(input: &[u8]) -> IResult<&[u8], CsNet> {
985
22.0k
    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.24k
    let (i2, sz) = map_opt(le_u16, |x: u16| x.checked_sub(8))(i1)?;
988
2.79k
    let (i3, count) = le_u32(i2)?;
989
2.56k
    let (i4, data) = take(sz)(i3)?;
990
991
2.29k
    let mut remainder: &[u8] = data;
992
2.29k
    let mut channels = Vec::new();
993
994
2.52k
    for _index in 0..count {
995
        // a channel name is 8 bytes, section 2.2.1.3.4.1
996
2.52k
        let (j1, name) = map_res(take(8_usize), utf7_slice_to_string)(remainder)?;
997
1.70k
        channels.push(name);
998
        // options (u32) are discarded for now
999
1.70k
        let (j2, _options) = le_u32(j1)?;
1000
1.44k
        remainder = j2;
1001
    }
1002
1003
1.21k
    return Ok((i4, CsNet { channels }));
1004
22.0k
}
1005
1006
// generic CS structure parse
1007
// cf. rdp-spec, section 2.2.1.3.4
1008
19.3k
fn parse_cs_unknown(i: &[u8]) -> IResult<&[u8], CsUnknown> {
1009
19.3k
    let (i, typ) = map_opt(le_u16, |x| {
1010
19.3k
        let opt: Option<CsType> = num::FromPrimitive::from_u16(x);
1011
19.3k
        match opt {
1012
            // an unknown type must not be present in CsType
1013
1.59k
            Some(_) => None,
1014
17.7k
            None => Some(x),
1015
        }
1016
19.3k
    })(i)?;
1017
    // less u16, u16
1018
17.7k
    let (i, sz) = map_opt(le_u16, |x: u16| x.checked_sub(4))(i)?;
1019
15.3k
    let (i, data) = take(sz)(i)?;
1020
9.50k
    Ok((i, CsUnknown { typ, data: data.to_vec() }))
1021
19.3k
}
1022
1023
// rdp-spec, section 2.2.1.4
1024
2.21k
fn parse_mcs_connect_response(i: &[u8]) -> IResult<&[u8], McsConnectResponse, RdpError> {
1025
2.21k
    let (i, _ber_type) = verify(
1026
        le_u8,
1027
        // BER: 0b01=application, 0b1=non-primitive, 0b11111
1028
2.21k
        |&x| x == 0x7f)(i)?;
1029
1.58k
    let (i, _t125_type) = verify(le_u8, |&x| x == T125Type::T125TypeMcsConnectResponse as u8)(i)?;
1030
299
    Ok((i, McsConnectResponse {}))
1031
2.21k
}
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
}