Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/quic/frames.rs
Line
Count
Source
1
/* Copyright (C) 2021 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
use super::error::QuicError;
19
use super::quic::QUIC_MAX_CRYPTO_FRAG_LEN;
20
use crate::ja4::*;
21
use crate::quic::parser::quic_var_uint;
22
use nom7::bytes::complete::take;
23
use nom7::combinator::{all_consuming, complete};
24
use nom7::multi::{count, many0};
25
use nom7::number::complete::{be_u16, be_u32, be_u8, le_u16, le_u32};
26
use nom7::sequence::pair;
27
use nom7::IResult;
28
use num::FromPrimitive;
29
use std::fmt;
30
use tls_parser::TlsMessage::Handshake;
31
use tls_parser::TlsMessageHandshake::{ClientHello, ServerHello};
32
use tls_parser::{
33
    parse_tls_extensions, parse_tls_message_handshake, TlsCipherSuiteID, TlsExtension,
34
    TlsExtensionType, TlsMessage,
35
};
36
37
/// Tuple of StreamTag and offset
38
type TagOffset = (StreamTag, u32);
39
40
/// Tuple of StreamTag and value
41
type TagValue = (StreamTag, Vec<u8>);
42
43
#[derive(Debug, PartialEq)]
44
pub(crate) struct Stream {
45
    pub fin: bool,
46
    pub stream_id: Vec<u8>,
47
    pub offset: Vec<u8>,
48
    pub tags: Option<Vec<TagValue>>,
49
}
50
51
#[repr(u32)]
52
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
53
pub(crate) enum StreamTag {
54
    Aead = 0x41454144,
55
    Ccrt = 0x43435254,
56
    Ccs = 0x43435300,
57
    Cetv = 0x43455456,
58
    Cfcw = 0x43464357,
59
    Chlo = 0x43484c4f,
60
    Copt = 0x434f5054,
61
    Csct = 0x43534354,
62
    Ctim = 0x4354494d,
63
    Icsl = 0x4943534c,
64
    Irtt = 0x49525454,
65
    Kexs = 0x4b455853,
66
    Mids = 0x4d494453,
67
    Mspc = 0x4d535043,
68
    Nonc = 0x4e4f4e43,
69
    Nonp = 0x4e4f4e50,
70
    Pad = 0x50414400,
71
    Pdmd = 0x50444d44,
72
    Pubs = 0x50554253,
73
    Scid = 0x53434944,
74
    Scls = 0x53434c53,
75
    Sfcw = 0x53464357,
76
    Smhl = 0x534d484c,
77
    Sni = 0x534e4900,
78
    Sno = 0x534e4f00,
79
    Stk = 0x53544b00,
80
    Tcid = 0x54434944,
81
    Uaid = 0x55414944,
82
    Ver = 0x56455200,
83
    Xlct = 0x584c4354,
84
}
85
86
impl fmt::Display for StreamTag {
87
36.5k
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88
36.5k
        write!(
89
36.5k
            f,
90
36.5k
            "{}",
91
36.5k
            match self {
92
2.02k
                StreamTag::Aead => "AEAD",
93
1.02k
                StreamTag::Ccrt => "CCRT",
94
827
                StreamTag::Ccs => "CCS",
95
194
                StreamTag::Cetv => "CETV",
96
985
                StreamTag::Cfcw => "CFCW",
97
211
                StreamTag::Chlo => "CHLO",
98
9.94k
                StreamTag::Copt => "COPT",
99
3.78k
                StreamTag::Csct => "CSCT",
100
194
                StreamTag::Ctim => "CTIM",
101
824
                StreamTag::Icsl => "ICSL",
102
825
                StreamTag::Irtt => "IRTT",
103
867
                StreamTag::Kexs => "KEXS",
104
824
                StreamTag::Mids => "MIDS",
105
194
                StreamTag::Mspc => "MSPC",
106
820
                StreamTag::Nonc => "NONC",
107
824
                StreamTag::Nonp => "NONP",
108
824
                StreamTag::Pad => "PAD",
109
825
                StreamTag::Pdmd => "PDMD",
110
809
                StreamTag::Pubs => "PUBS",
111
810
                StreamTag::Scid => "SCID",
112
956
                StreamTag::Scls => "SCLS",
113
824
                StreamTag::Sfcw => "SFCW",
114
830
                StreamTag::Smhl => "SMHL",
115
1.41k
                StreamTag::Sni => "SNI",
116
833
                StreamTag::Sno => "SNO",
117
809
                StreamTag::Stk => "STK",
118
824
                StreamTag::Tcid => "TCID",
119
836
                StreamTag::Uaid => "UAID",
120
824
                StreamTag::Ver => "VER",
121
809
                StreamTag::Xlct => "XLCT",
122
            }
123
        )
124
36.5k
    }
125
}
126
127
#[derive(Debug, PartialEq)]
128
pub(crate) struct Ack {
129
    pub largest_acknowledged: u64,
130
    pub ack_delay: u64,
131
    pub ack_range_count: u64,
132
    pub first_ack_range: u64,
133
}
134
135
#[derive(Debug, PartialEq)]
136
pub(crate) struct Crypto {
137
    pub ciphers: Vec<TlsCipherSuiteID>,
138
    // We remap the Vec<TlsExtension> from tls_parser::parse_tls_extensions because of
139
    // the lifetime of TlsExtension due to references to the slice used for parsing
140
    pub extv: Vec<QuicTlsExtension>,
141
    pub ja3: Option<String>,
142
    pub ja4: Option<JA4>,
143
}
144
145
#[derive(Debug, PartialEq)]
146
pub(crate) struct CryptoFrag {
147
    pub offset: u64,
148
    pub length: u64,
149
    pub data: Vec<u8>,
150
}
151
152
#[derive(Debug, PartialEq)]
153
pub(crate) enum Frame {
154
    Padding,
155
    Ping,
156
    Ack(Ack),
157
    // this is more than a crypto frame : it contains a fully parsed tls hello
158
    Crypto(Crypto),
159
    // this is a regular quic crypto frame : they can be reassembled
160
    // in order to parse a tls hello
161
    CryptoFrag(CryptoFrag),
162
    Stream(Stream),
163
    Unknown(Vec<u8>),
164
}
165
166
168k
fn parse_padding_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> {
167
    // nom take_while: cannot infer type for type parameter `Error` declared on the function `take_while`
168
168k
    let mut offset = 0;
169
833k
    while offset < input.len() {
170
807k
        if input[offset] != 0 {
171
142k
            break;
172
665k
        }
173
665k
        offset += 1;
174
    }
175
168k
    return Ok((&input[offset..], Frame::Padding));
176
168k
}
177
178
45.0k
fn parse_ack_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> {
179
45.0k
    let (rest, largest_acknowledged) = quic_var_uint(input)?;
180
44.0k
    let (rest, ack_delay) = quic_var_uint(rest)?;
181
44.0k
    let (rest, ack_range_count) = quic_var_uint(rest)?;
182
43.5k
    let (mut rest, first_ack_range) = quic_var_uint(rest)?;
183
184
43.5k
    for _ in 0..ack_range_count {
185
        //RFC9000 section 19.3.1.  ACK Ranges
186
37.9k
        let (rest1, _gap) = quic_var_uint(rest)?;
187
37.6k
        let (rest1, _ack_range_length) = quic_var_uint(rest1)?;
188
37.4k
        rest = rest1;
189
    }
190
191
42.9k
    Ok((
192
42.9k
        rest,
193
42.9k
        Frame::Ack(Ack {
194
42.9k
            largest_acknowledged,
195
42.9k
            ack_delay,
196
42.9k
            ack_range_count,
197
42.9k
            first_ack_range,
198
42.9k
        }),
199
42.9k
    ))
200
45.0k
}
201
202
1.07k
fn parse_ack3_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> {
203
1.07k
    let (rest, ack) = parse_ack_frame(input)?;
204
1.00k
    let (rest, _ect0_count) = quic_var_uint(rest)?;
205
997
    let (rest, _ect1_count) = quic_var_uint(rest)?;
206
991
    let (rest, _ecn_count) = quic_var_uint(rest)?;
207
975
    Ok((rest, ack))
208
1.07k
}
209
210
#[derive(Clone, Debug, PartialEq, Eq)]
211
pub struct QuicTlsExtension {
212
    pub etype: TlsExtensionType,
213
    pub values: Vec<Vec<u8>>,
214
}
215
216
35.9k
fn quic_tls_ja3_client_extends(ja3: &mut String, exts: Vec<TlsExtension>) {
217
35.9k
    ja3.push(',');
218
35.9k
    let mut dash = false;
219
1.31M
    for e in &exts {
220
1.28M
        if let TlsExtension::EllipticCurves(x) = e {
221
358k
            for ec in x {
222
357k
                if dash {
223
357k
                    ja3.push('-');
224
357k
                } else {
225
503
                    dash = true;
226
503
                }
227
357k
                ja3.push_str(&ec.0.to_string());
228
            }
229
1.27M
        }
230
    }
231
35.9k
    ja3.push(',');
232
35.9k
    dash = false;
233
1.31M
    for e in &exts {
234
1.28M
        if let TlsExtension::EcPointFormats(x) = e {
235
110k
            for ec in *x {
236
108k
                if dash {
237
107k
                    ja3.push('-');
238
107k
                } else {
239
918
                    dash = true;
240
918
                }
241
108k
                ja3.push_str(&ec.to_string());
242
            }
243
1.27M
        }
244
    }
245
35.9k
}
246
247
// get interesting stuff out of parsed tls extensions
248
48.0k
fn quic_get_tls_extensions(
249
48.0k
    input: Option<&[u8]>, ja3: &mut String, mut ja4: Option<&mut JA4>, client: bool,
250
48.0k
) -> Vec<QuicTlsExtension> {
251
48.0k
    let mut extv = Vec::new();
252
48.0k
    if let Some(extr) = input {
253
40.4k
        if let Ok((_, exts)) = parse_tls_extensions(extr) {
254
40.4k
            let mut dash = false;
255
1.81M
            for e in &exts {
256
1.77M
                let etype = TlsExtensionType::from(e);
257
1.77M
                if dash {
258
1.75M
                    ja3.push('-');
259
1.75M
                } else {
260
22.8k
                    dash = true;
261
22.8k
                }
262
1.77M
                ja3.push_str(&u16::from(etype).to_string());
263
1.77M
                if let Some(ref mut ja4) = ja4 {
264
1.28M
                    ja4.add_extension(etype)
265
498k
                }
266
1.77M
                let mut values = Vec::new();
267
1.77M
                match e {
268
2.75k
                    TlsExtension::SupportedVersions(x) => {
269
369k
                        for version in x {
270
367k
                            let mut value = Vec::new();
271
367k
                            value.extend_from_slice(version.to_string().as_bytes());
272
367k
                            values.push(value);
273
367k
                            if let Some(ref mut ja4) = ja4 {
274
145k
                                ja4.set_tls_version(*version);
275
221k
                            }
276
                        }
277
                    }
278
1.27M
                    TlsExtension::SNI(x) => {
279
1.41M
                        for sni in x {
280
143k
                            let mut value = Vec::new();
281
143k
                            value.extend_from_slice(sni.1);
282
143k
                            values.push(value);
283
143k
                        }
284
                    }
285
892
                    TlsExtension::SignatureAlgorithms(x) => {
286
504k
                        for sigalgo in x {
287
503k
                            let mut value = Vec::new();
288
503k
                            value.extend_from_slice(sigalgo.to_string().as_bytes());
289
503k
                            values.push(value);
290
503k
                            if let Some(ref mut ja4) = ja4 {
291
477k
                                ja4.add_signature_algorithm(*sigalgo)
292
25.9k
                            }
293
                        }
294
                    }
295
3.58k
                    TlsExtension::ALPN(x) => {
296
3.58k
                        if !x.is_empty() {
297
3.19k
                            if let Some(ref mut ja4) = ja4 {
298
3.17k
                                ja4.set_alpn(x[0]);
299
3.17k
                            }
300
394
                        }
301
340k
                        for alpn in x {
302
337k
                            let mut value = Vec::new();
303
337k
                            value.extend_from_slice(alpn);
304
337k
                            values.push(value);
305
337k
                        }
306
                    }
307
499k
                    _ => {}
308
                }
309
1.77M
                extv.push(QuicTlsExtension { etype, values })
310
            }
311
40.4k
            if client {
312
35.9k
                quic_tls_ja3_client_extends(ja3, exts);
313
35.9k
            }
314
0
        }
315
7.67k
    }
316
48.0k
    return extv;
317
48.0k
}
318
319
56.5k
fn parse_quic_handshake(msg: TlsMessage) -> Option<Frame> {
320
56.5k
    if let Handshake(hs) = msg {
321
56.5k
        match hs {
322
42.7k
            ClientHello(ch) => {
323
42.7k
                let mut ja3 = String::with_capacity(256);
324
42.7k
                ja3.push_str(&u16::from(ch.version).to_string());
325
42.7k
                ja3.push(',');
326
42.7k
                let mut ja4 = JA4::new();
327
42.7k
                ja4.set_quic();
328
42.7k
                let mut dash = false;
329
4.47M
                for c in &ch.ciphers {
330
4.43M
                    if dash {
331
4.42M
                        ja3.push('-');
332
4.42M
                    } else {
333
12.8k
                        dash = true;
334
12.8k
                    }
335
4.43M
                    ja3.push_str(&u16::from(*c).to_string());
336
4.43M
                    ja4.add_cipher_suite(*c);
337
                }
338
42.7k
                ja3.push(',');
339
42.7k
                let ciphers = ch.ciphers;
340
42.7k
                let extv = quic_get_tls_extensions(ch.ext, &mut ja3, Some(&mut ja4), true);
341
                return Some(Frame::Crypto(Crypto {
342
42.7k
                    ciphers,
343
42.7k
                    extv,
344
42.7k
                    ja3: if cfg!(feature = "ja3") {
345
42.7k
                        Some(ja3)
346
                    } else {
347
0
                        None
348
                    },
349
42.7k
                    ja4: if cfg!(feature = "ja4") {
350
42.7k
                        Some(ja4)
351
                    } else {
352
0
                        None
353
                    },
354
                }));
355
            }
356
5.34k
            ServerHello(sh) => {
357
5.34k
                let mut ja3 = String::with_capacity(256);
358
5.34k
                ja3.push_str(&u16::from(sh.version).to_string());
359
5.34k
                ja3.push(',');
360
5.34k
                ja3.push_str(&u16::from(sh.cipher).to_string());
361
5.34k
                ja3.push(',');
362
5.34k
                let ciphers = vec![sh.cipher];
363
5.34k
                let extv = quic_get_tls_extensions(sh.ext, &mut ja3, None, false);
364
                return Some(Frame::Crypto(Crypto {
365
5.34k
                    ciphers,
366
5.34k
                    extv,
367
5.34k
                    ja3: if cfg!(feature = "ja3") {
368
5.34k
                        Some(ja3)
369
                    } else {
370
0
                        None
371
                    },
372
5.34k
                    ja4: None,
373
                }));
374
            }
375
8.48k
            _ => {}
376
        }
377
0
    }
378
8.48k
    return None;
379
56.5k
}
380
381
152k
fn parse_crypto_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> {
382
152k
    let (rest, offset) = quic_var_uint(input)?;
383
152k
    let (rest, length) = quic_var_uint(rest)?;
384
152k
    let (rest, data) = take(length as usize)(rest)?;
385
386
152k
    if offset > 0 {
387
54.4k
        return Ok((
388
54.4k
            rest,
389
54.4k
            Frame::CryptoFrag(CryptoFrag {
390
54.4k
                offset,
391
54.4k
                length,
392
54.4k
                data: data.to_vec(),
393
54.4k
            }),
394
54.4k
        ));
395
97.7k
    }
396
    // if we have offset 0, try quick path : parse directly
397
97.7k
    match parse_tls_message_handshake(data) {
398
47.3k
        Ok((_, msg)) => {
399
47.3k
            if let Some(c) = parse_quic_handshake(msg) {
400
47.2k
                return Ok((rest, c));
401
124
            }
402
        }
403
        Err(nom7::Err::Incomplete(_)) => {
404
            // offset 0 but incomplete : save it as a fragment for later reassembly
405
50.2k
            return Ok((
406
50.2k
                rest,
407
50.2k
                Frame::CryptoFrag(CryptoFrag {
408
50.2k
                    offset,
409
50.2k
                    length,
410
50.2k
                    data: data.to_vec(),
411
50.2k
                }),
412
50.2k
            ));
413
        }
414
157
        _ => {}
415
    }
416
281
    return Err(nom7::Err::Error(QuicError::InvalidPacket));
417
152k
}
418
419
134k
fn parse_tag(input: &[u8]) -> IResult<&[u8], StreamTag, QuicError> {
420
134k
    let (rest, tag) = be_u32(input)?;
421
422
106k
    let tag = StreamTag::from_u32(tag).ok_or(nom7::Err::Error(QuicError::StreamTagNoMatch(tag)))?;
423
424
79.8k
    Ok((rest, tag))
425
134k
}
426
427
65.4k
fn parse_tag_and_offset(input: &[u8]) -> IResult<&[u8], TagOffset, QuicError> {
428
65.4k
    pair(parse_tag, le_u32)(input)
429
65.4k
}
430
431
68.8k
fn parse_crypto_stream(input: &[u8]) -> IResult<&[u8], Vec<TagValue>, QuicError> {
432
    // [message tag][number of tag entries: N][pad][[tag][end offset], ...N][value data]
433
68.8k
    let (rest, _message_tag) = parse_tag(input)?;
434
435
18.9k
    let (rest, num_entries) = le_u16(rest)?;
436
18.3k
    let (rest, _padding) = take(2usize)(rest)?;
437
438
17.7k
    let (rest, tags_offset) = count(complete(parse_tag_and_offset), num_entries.into())(rest)?;
439
440
    // Convert (Tag, Offset) to (Tag, Value)
441
12.5k
    let mut tags = Vec::new();
442
12.5k
    let mut previous_offset = 0;
443
12.5k
    let mut rest = rest;
444
59.6k
    for (tag, offset) in tags_offset {
445
        // offsets should be increasing
446
48.6k
        let value_len = offset
447
48.6k
            .checked_sub(previous_offset)
448
48.6k
            .ok_or(nom7::Err::Error(QuicError::InvalidPacket))?;
449
48.3k
        let (new_rest, value) = take(value_len)(rest)?;
450
451
47.1k
        previous_offset = offset;
452
47.1k
        rest = new_rest;
453
454
47.1k
        tags.push((tag, value.to_vec()))
455
    }
456
457
10.9k
    Ok((rest, tags))
458
68.8k
}
459
460
46.5k
fn parse_stream_frame(input: &[u8], frame_ty: u8) -> IResult<&[u8], Frame, QuicError> {
461
    // 0b1_f_d_ooo_ss
462
46.5k
    let fin = frame_ty & 0x40 == 0x40;
463
46.5k
    let has_data_length = frame_ty & 0x20 == 0x20;
464
465
46.5k
    let offset_hdr_length = {
466
46.5k
        let mut offset_length = (frame_ty & 0x1c) >> 2;
467
46.5k
        if offset_length != 0 {
468
36.8k
            offset_length += 1;
469
36.8k
        }
470
46.5k
        offset_length
471
    };
472
473
46.5k
    let stream_id_hdr_length = usize::from((frame_ty & 0x03) + 1);
474
475
46.5k
    let (rest, stream_id) = take(stream_id_hdr_length)(input)?;
476
46.1k
    let (rest, offset) = take(offset_hdr_length)(rest)?;
477
478
44.8k
    let (rest, data_length) = if has_data_length {
479
14.4k
        let (rest, data_length) = be_u16(rest)?;
480
481
14.2k
        (rest, usize::from(data_length))
482
    } else {
483
30.3k
        (rest, rest.len())
484
    };
485
486
44.6k
    let (rest, stream_data) = take(data_length)(rest)?;
487
488
44.1k
    let tags = if let Ok((_, tags)) = all_consuming(parse_crypto_stream)(stream_data) {
489
7.03k
        Some(tags)
490
    } else {
491
37.0k
        None
492
    };
493
494
44.1k
    Ok((
495
44.1k
        rest,
496
44.1k
        Frame::Stream(Stream {
497
44.1k
            fin,
498
44.1k
            stream_id: stream_id.to_vec(),
499
44.1k
            offset: offset.to_vec(),
500
44.1k
            tags,
501
44.1k
        }),
502
44.1k
    ))
503
46.5k
}
504
505
26.2k
fn parse_crypto_stream_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> {
506
26.2k
    let (rest, _offset) = quic_var_uint(input)?;
507
25.8k
    let (rest, data_length) = quic_var_uint(rest)?;
508
25.8k
    if data_length > u32::MAX as u64 {
509
886
        return Err(nom7::Err::Error(QuicError::Unhandled));
510
24.9k
    }
511
24.9k
    let (rest, stream_data) = take(data_length as u32)(rest)?;
512
513
24.7k
    let tags = if let Ok((_, tags)) = all_consuming(parse_crypto_stream)(stream_data) {
514
1.82k
        Some(tags)
515
    } else {
516
22.8k
        None
517
    };
518
519
24.7k
    Ok((
520
24.7k
        rest,
521
24.7k
        Frame::Stream(Stream {
522
24.7k
            fin: false,
523
24.7k
            stream_id: Vec::new(),
524
24.7k
            offset: Vec::new(),
525
24.7k
            tags,
526
24.7k
        }),
527
24.7k
    ))
528
26.2k
}
529
530
impl Frame {
531
2.03M
    fn decode_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> {
532
2.03M
        let (rest, frame_ty) = be_u8(input)?;
533
534
        // Special frame types
535
752k
        let (rest, value) = if frame_ty & 0x80 == 0x80 {
536
            // STREAM
537
46.5k
            parse_stream_frame(rest, frame_ty)?
538
        } else {
539
705k
            match frame_ty {
540
168k
                0x00 => parse_padding_frame(rest)?,
541
171k
                0x01 => (rest, Frame::Ping),
542
44.0k
                0x02 => parse_ack_frame(rest)?,
543
1.07k
                0x03 => parse_ack3_frame(rest)?,
544
152k
                0x06 => parse_crypto_frame(rest)?,
545
26.2k
                0x08 => parse_crypto_stream_frame(rest)?,
546
141k
                _ => ([].as_ref(), Frame::Unknown(rest.to_vec())),
547
            }
548
        };
549
550
745k
        Ok((rest, value))
551
2.03M
    }
552
553
1.28M
    pub(crate) fn decode_frames<'a>(
554
1.28M
        input: &'a [u8], past_frag: &'a [u8], past_fraglen: u32,
555
1.28M
    ) -> IResult<&'a [u8], Vec<Frame>, QuicError> {
556
1.28M
        let (rest, mut frames) = all_consuming(many0(complete(Frame::decode_frame)))(input)?;
557
558
        // we use the already seen past fragment data
559
1.27M
        let mut crypto_max_size = past_frag.len() as u64;
560
1.27M
        let mut crypto_total_size = 0;
561
        // reassemble crypto fragments : first find total size
562
1.98M
        for f in &frames {
563
705k
            if let Frame::CryptoFrag(c) = f {
564
101k
                if crypto_max_size < c.offset + c.length {
565
22.7k
                    crypto_max_size = c.offset + c.length;
566
78.2k
                }
567
101k
                crypto_total_size += c.length;
568
604k
            }
569
        }
570
1.27M
        if crypto_max_size > 0 && crypto_max_size < QUIC_MAX_CRYPTO_FRAG_LEN {
571
            // we have some, and no gaps from offset 0
572
430k
            let mut d = vec![0; crypto_max_size as usize];
573
430k
            d[..past_frag.len()].clone_from_slice(past_frag);
574
774k
            for f in &frames {
575
344k
                if let Frame::CryptoFrag(c) = f {
576
82.4k
                    d[c.offset as usize..(c.offset + c.length) as usize].clone_from_slice(&c.data);
577
262k
                }
578
            }
579
            // check that we have enough data, some new data, and data for the first byte
580
430k
            if crypto_total_size + past_fraglen as u64 >= crypto_max_size && crypto_total_size > 0 {
581
28.0k
                match parse_tls_message_handshake(&d) {
582
9.24k
                    Ok((_, msg)) => {
583
9.24k
                        if let Some(c) = parse_quic_handshake(msg) {
584
887
                            // add a parsed crypto frame
585
887
                            frames.push(c);
586
8.35k
                        }
587
                    }
588
14.6k
                    Err(nom7::Err::Incomplete(_)) => {
589
14.6k
                        // this means the current packet does not have all the hanshake data yet
590
14.6k
                        let frag = CryptoFrag {
591
14.6k
                            offset: crypto_total_size + past_fraglen as u64,
592
14.6k
                            length: d.len() as u64,
593
14.6k
                            data: d.to_vec(),
594
14.6k
                        };
595
14.6k
                        frames.push(Frame::CryptoFrag(frag));
596
14.6k
                    }
597
4.06k
                    _ => {}
598
                }
599
402k
            } else {
600
402k
                // pass in offset the number of bytes set in data
601
402k
                let frag = CryptoFrag {
602
402k
                    offset: crypto_total_size + past_fraglen as u64,
603
402k
                    length: d.len() as u64,
604
402k
                    data: d.to_vec(),
605
402k
                };
606
402k
                frames.push(Frame::CryptoFrag(frag));
607
402k
            }
608
849k
        } else if crypto_max_size >= QUIC_MAX_CRYPTO_FRAG_LEN {
609
4.69k
            // just notice the engine that we have a big crypto fragment without supplying data
610
4.69k
            let frag = CryptoFrag {
611
4.69k
                offset: 0,
612
4.69k
                length: crypto_max_size,
613
4.69k
                data: Vec::new(),
614
4.69k
            };
615
4.69k
            frames.push(Frame::CryptoFrag(frag));
616
844k
        }
617
618
1.27M
        Ok((rest, frames))
619
1.28M
    }
620
}