Coverage Report

Created: 2026-05-16 07:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/ike/parser.rs
Line
Count
Source
1
/* Copyright (C) 2020 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 crate::common::to_hex;
19
use core::fmt;
20
use nom7::bytes::streaming::take;
21
use nom7::combinator::{complete, cond, map};
22
use nom7::multi::many0;
23
use nom7::number::streaming::{be_u16, be_u32, be_u64, be_u8};
24
use nom7::{Err, IResult};
25
use std::collections::HashSet;
26
27
// Generic ISAKMP "Container" structs
28
#[repr(u8)]
29
#[derive(Copy, Clone, FromPrimitive)]
30
pub enum ExchangeType {
31
    None = 0,
32
    Base = 1,
33
    IdentityProtection = 2,
34
    AuthenticationOnly = 3,
35
    Aggressive = 4,
36
    Informational = 5,
37
    Transaction = 6,
38
    QuickMode = 32,
39
    NewGroupMode = 33,
40
}
41
42
impl fmt::Display for ExchangeType {
43
730
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44
730
        match self {
45
0
            ExchangeType::Base => write!(f, "Base"),
46
705
            ExchangeType::IdentityProtection => write!(f, "Identity Protection"),
47
0
            ExchangeType::AuthenticationOnly => write!(f, "Authentication Only"),
48
0
            ExchangeType::Aggressive => write!(f, "Aggressive"),
49
0
            ExchangeType::Informational => write!(f, "Informational"),
50
0
            ExchangeType::Transaction => write!(f, "Transaction (Config Mode)"),
51
22
            ExchangeType::QuickMode => write!(f, "Quick Mode"),
52
0
            ExchangeType::NewGroupMode => write!(f, "New Group Mode"),
53
3
            _ => write!(f, "Unknown Exchange Type"),
54
        }
55
730
    }
56
}
57
58
pub struct IsakmpHeader {
59
    pub init_spi: u64,
60
    pub resp_spi: u64,
61
    pub next_payload: u8,
62
    pub maj_ver: u8,
63
    pub min_ver: u8,
64
    pub exch_type: u8,
65
    pub flags: u8,
66
    pub msg_id: u32,
67
    pub length: u32,
68
}
69
70
pub struct IsakmpPayloadHeader {
71
    pub next_payload: u8,
72
    pub _reserved: u8,
73
    pub _payload_length: u16,
74
}
75
76
pub struct IsakmpPayload<'a> {
77
    pub payload_header: IsakmpPayloadHeader,
78
    pub data: &'a [u8],
79
}
80
81
// IKEV1 specific payloads
82
83
// 1 -> Security Association
84
pub struct SecurityAssociationPayload<'a> {
85
    pub domain_of_interpretation: u32,
86
    pub _situation: Option<&'a [u8]>,
87
    pub data: Option<&'a [u8]>,
88
}
89
90
// 2 -> Proposal
91
pub struct ProposalPayload<'a> {
92
    pub _proposal_number: u8,
93
    pub _proposal_type: u8,
94
    pub _spi_size: u8,
95
    pub _number_transforms: u8,
96
    pub _spi: &'a [u8],
97
    pub data: &'a [u8],
98
}
99
100
// 3 -> Transform
101
pub struct TransformPayload<'a> {
102
    pub _transform_number: u8,
103
    pub _transform_type: u8,
104
    pub sa_attributes: &'a [u8],
105
}
106
107
// 4 -> Key Exchange
108
pub struct KeyExchangePayload<'a> {
109
    pub key_exchange_data: &'a [u8],
110
}
111
112
// 5 -> Identification
113
// 6 -> Certificate
114
// 7 -> Certificate Request
115
// 8 -> Hash
116
// 9 -> Signature
117
118
// 10 -> Nonce
119
pub struct NoncePayload<'a> {
120
    pub nonce_data: &'a [u8],
121
}
122
123
// 11 -> Notification
124
// 12 -> Delete
125
126
// 13 -> Vendor ID
127
pub struct VendorPayload<'a> {
128
    pub vendor_id: &'a [u8],
129
}
130
131
// Attributes inside Transform
132
#[derive(Debug, Clone)]
133
pub enum AttributeType {
134
    Unknown = 0,
135
    EncryptionAlgorithm = 1,
136
    HashAlgorithm = 2,
137
    AuthenticationMethod = 3,
138
    GroupDescription = 4,
139
    GroupType = 5,
140
    GroupPrime = 6,
141
    GroupGeneratorOne = 7,
142
    GroupGeneratorTwo = 8,
143
    GroupCurveA = 9,
144
    GroupCurveB = 10,
145
    LifeType = 11,
146
    LifeDuration = 12,
147
    Prf = 13,
148
    KeyLength = 14,
149
    FieldSize = 15,
150
    GroupOrder = 16,
151
}
152
153
impl fmt::Display for AttributeType {
154
38.6k
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155
38.6k
        match self {
156
5.98k
            AttributeType::EncryptionAlgorithm => write!(f, "alg_enc"),
157
5.42k
            AttributeType::HashAlgorithm => write!(f, "alg_hash"),
158
5.10k
            AttributeType::AuthenticationMethod => write!(f, "alg_auth"),
159
5.25k
            AttributeType::GroupDescription => write!(f, "alg_dh"),
160
2
            AttributeType::GroupType => write!(f, "sa_group_type"),
161
0
            AttributeType::GroupPrime => write!(f, "sa_group_prime"),
162
10
            AttributeType::GroupGeneratorOne => write!(f, "sa_group_generator_one"),
163
10
            AttributeType::GroupGeneratorTwo => write!(f, "sa_group_generator_two"),
164
132
            AttributeType::GroupCurveA => write!(f, "sa_group_curve_a"),
165
42
            AttributeType::GroupCurveB => write!(f, "sa_group_curve_b"),
166
5.18k
            AttributeType::LifeType => write!(f, "sa_life_type"),
167
4.97k
            AttributeType::LifeDuration => write!(f, "sa_life_duration"),
168
12
            AttributeType::Prf => write!(f, "alg_prf"),
169
5.76k
            AttributeType::KeyLength => write!(f, "sa_key_length"),
170
2
            AttributeType::FieldSize => write!(f, "sa_field_size"),
171
2
            AttributeType::GroupOrder => write!(f, "sa_group_order"),
172
796
            _ => write!(f, "unknown"),
173
        }
174
38.6k
    }
175
}
176
177
#[derive(Debug, Clone)]
178
pub enum AttributeValue {
179
    // https://www.iana.org/assignments/ipsec-registry/ipsec-registry.xhtml
180
    Unknown,
181
    // Encryption Algorithm
182
    EncDesCbc,
183
    EncIdeaCbc,
184
    EncBlowfishCbc,
185
    EncRc5R16B64Cbc,
186
    EncTripleDesCbc,
187
    EncCastCbc,
188
    EncAesCbc,
189
    EncCamelliaCbc,
190
    // Hash Algorithm
191
    HashMd5,
192
    HashSha,
193
    HashTiger,
194
    HashSha2_256,
195
    HashSha2_384,
196
    HashSha2_512,
197
    // Authentication Method
198
    AuthPreSharedKey,
199
    AuthDssSignatures,
200
    AuthRsaSignatures,
201
    AuthEncryptionWithRsa,
202
    AuthRevisedEncryptionWithRsa,
203
    AuthReserved,
204
    AuthEcdsaSha256,
205
    AuthEcdsaSha384,
206
    AuthEcdsaSha512,
207
    // Group Description
208
    GroupDefault768BitModp,
209
    GroupAlternate1024BitModpGroup,
210
    GroupEc2nOnGp2p155,
211
    GroupEc2nOnGp2p185,
212
    GroupModp1536Bit,
213
    GroupEc2nOverGf2p163,
214
    GroupEc2nOverGf2p283,
215
    GroupEc2nOverGf2p409,
216
    GroupEc2nOverGf2p571,
217
    GroupModp2048Bit,
218
    GroupModp3072Bit,
219
    GroupModp4096Bit,
220
    GroupModp6144Bit,
221
    GroupModp8192Bit,
222
    GroupRandomEcp256,
223
    GroupRandomEcp384,
224
    GroupRandomEcp521,
225
    GroupModp1024With160BitPrime,
226
    GroupModp2048With224BitPrime,
227
    GroupModp2048With256BitPrime,
228
    GroupRandomEcp192,
229
    GroupRandomEcp224,
230
    GroupBrainpoolEcp224,
231
    GroupBrainpoolEcp256,
232
    GroupBrainpoolEcp384,
233
    GroupBrainpoolEcp512,
234
    // Life Type
235
    LifeTypeSeconds,
236
    LifeTypeKilobytes,
237
}
238
239
impl fmt::Display for AttributeValue {
240
19.1k
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
241
19.1k
        write!(f, "{:?}", self)
242
19.1k
    }
243
}
244
245
#[derive(Clone)]
246
pub struct SaAttribute {
247
    pub attribute_format: u8,
248
    pub attribute_type: AttributeType,
249
    pub attribute_value: AttributeValue,
250
    pub numeric_value: Option<u32>,
251
    pub hex_value: Option<String>,
252
}
253
254
275k
pub fn parse_isakmp_header(i: &[u8]) -> IResult<&[u8], IsakmpHeader> {
255
275k
    let (i, init_spi) = be_u64(i)?;
256
275k
    let (i, resp_spi) = be_u64(i)?;
257
275k
    let (i, next_payload) = be_u8(i)?;
258
275k
    let (i, vers_byte) = be_u8(i)?;
259
275k
    let vers = (vers_byte >> 4, vers_byte & 0b1111);
260
275k
    let (i, exch_type) = be_u8(i)?;
261
275k
    let (i, flags) = be_u8(i)?;
262
275k
    let (i, msg_id) = be_u32(i)?;
263
275k
    let (i, length) = be_u32(i)?;
264
274k
    let hdr = IsakmpHeader {
265
274k
        init_spi,
266
274k
        resp_spi,
267
274k
        next_payload,
268
274k
        maj_ver: vers.0,
269
274k
        min_ver: vers.1,
270
274k
        exch_type,
271
274k
        flags,
272
274k
        msg_id,
273
274k
        length,
274
274k
    };
275
274k
    Ok((i, hdr))
276
275k
}
277
278
59.2k
pub fn parse_security_association(i: &[u8]) -> IResult<&[u8], SecurityAssociationPayload<'_>> {
279
59.2k
    let start_i = i;
280
59.2k
    let (i, domain_of_interpretation) = be_u32(i)?;
281
18.8k
    let (i, situation) = cond(domain_of_interpretation == 1, take(4_usize))(i)?;
282
18.6k
    let (i, data) = cond(domain_of_interpretation == 1 && start_i.len() >= 8, |b| {
283
7.83k
        take(start_i.len() - 8)(b)
284
18.6k
    })(i)?;
285
18.6k
    Ok((
286
18.6k
        i,
287
18.6k
        SecurityAssociationPayload {
288
18.6k
            domain_of_interpretation,
289
18.6k
            _situation: situation,
290
18.6k
            data,
291
18.6k
        },
292
18.6k
    ))
293
59.2k
}
294
295
111k
pub fn parse_key_exchange(i: &[u8], length: u16) -> IResult<&[u8], KeyExchangePayload<'_>> {
296
111k
    let (i, key_exchange_data) = take(length as usize)(i)?;
297
111k
    Ok((i, KeyExchangePayload { key_exchange_data }))
298
111k
}
299
300
14.0k
pub fn parse_proposal(i: &[u8]) -> IResult<&[u8], ProposalPayload<'_>> {
301
14.0k
    let start_i = i;
302
14.0k
    let (i, proposal_number) = be_u8(i)?;
303
11.7k
    let (i, proposal_type) = be_u8(i)?;
304
11.2k
    let (i, spi_size) = be_u8(i)?;
305
11.0k
    let (i, number_transforms) = be_u8(i)?;
306
10.7k
    let (i, spi) = take(spi_size as usize)(i)?;
307
9.39k
    let (i, payload_data) = cond((start_i.len() - 4) >= spi_size.into(), |b| {
308
9.39k
        take((start_i.len() - 4) - spi_size as usize)(b)
309
9.39k
    })(i)?;
310
9.39k
    let payload = ProposalPayload {
311
9.39k
        _proposal_number: proposal_number,
312
9.39k
        _proposal_type: proposal_type,
313
9.39k
        _spi_size: spi_size,
314
9.39k
        _number_transforms: number_transforms,
315
9.39k
        _spi: spi,
316
9.39k
        data: payload_data.unwrap_or_default(),
317
9.39k
    };
318
9.39k
    Ok((i, payload))
319
14.0k
}
320
321
1.00M
pub fn parse_transform(i: &[u8], length: u16) -> IResult<&[u8], TransformPayload<'_>> {
322
1.00M
    let (i, transform_number) = be_u8(i)?;
323
987k
    let (i, transform_type) = be_u8(i)?;
324
987k
    let (i, _) = be_u16(i)?;
325
987k
    let (i, payload_data) = cond(length >= 4, |b| take(length - 4)(b))(i)?;
326
987k
    Ok((
327
987k
        i,
328
987k
        TransformPayload {
329
987k
            _transform_number: transform_number,
330
987k
            _transform_type: transform_type,
331
987k
            sa_attributes: payload_data.unwrap_or_default(),
332
987k
        },
333
987k
    ))
334
1.00M
}
335
336
931k
pub fn parse_vendor_id(i: &[u8], length: u16) -> IResult<&[u8], VendorPayload<'_>> {
337
931k
    map(take(length), |v| VendorPayload { vendor_id: v })(i)
338
931k
}
339
340
336k
fn get_attribute_type(v: u16) -> AttributeType {
341
336k
    match v {
342
3.93k
        1 => AttributeType::EncryptionAlgorithm,
343
6.33k
        2 => AttributeType::HashAlgorithm,
344
20.4k
        3 => AttributeType::AuthenticationMethod,
345
48.6k
        4 => AttributeType::GroupDescription,
346
548
        5 => AttributeType::GroupType,
347
761
        6 => AttributeType::GroupPrime,
348
368
        7 => AttributeType::GroupGeneratorOne,
349
1.16k
        8 => AttributeType::GroupGeneratorTwo,
350
3.87k
        9 => AttributeType::GroupCurveA,
351
901
        10 => AttributeType::GroupCurveB,
352
5.46k
        11 => AttributeType::LifeType,
353
1.95k
        12 => AttributeType::LifeDuration,
354
837
        13 => AttributeType::Prf,
355
2.20k
        14 => AttributeType::KeyLength,
356
248
        15 => AttributeType::FieldSize,
357
2.23k
        16 => AttributeType::GroupOrder,
358
236k
        _ => AttributeType::Unknown,
359
    }
360
336k
}
361
362
3.93k
fn get_encryption_algorithm(v: u16) -> AttributeValue {
363
3.93k
    match v {
364
141
        1 => AttributeValue::EncDesCbc,
365
93
        2 => AttributeValue::EncIdeaCbc,
366
241
        3 => AttributeValue::EncBlowfishCbc,
367
7
        4 => AttributeValue::EncRc5R16B64Cbc,
368
1
        5 => AttributeValue::EncTripleDesCbc,
369
2
        6 => AttributeValue::EncCastCbc,
370
1.91k
        7 => AttributeValue::EncAesCbc,
371
223
        8 => AttributeValue::EncCamelliaCbc,
372
1.31k
        _ => AttributeValue::Unknown,
373
    }
374
3.93k
}
375
376
6.33k
fn get_hash_algorithm(v: u16) -> AttributeValue {
377
6.33k
    match v {
378
2
        1 => AttributeValue::HashMd5,
379
1.67k
        2 => AttributeValue::HashSha,
380
2
        3 => AttributeValue::HashTiger,
381
4
        4 => AttributeValue::HashSha2_256,
382
0
        5 => AttributeValue::HashSha2_384,
383
2
        6 => AttributeValue::HashSha2_512,
384
4.64k
        _ => AttributeValue::Unknown,
385
    }
386
6.33k
}
387
388
20.4k
fn get_authentication_method(v: u16) -> AttributeValue {
389
20.4k
    match v {
390
1.98k
        1 => AttributeValue::AuthPreSharedKey,
391
20
        2 => AttributeValue::AuthDssSignatures,
392
172
        3 => AttributeValue::AuthRsaSignatures,
393
12
        4 => AttributeValue::AuthEncryptionWithRsa,
394
18
        5 => AttributeValue::AuthRevisedEncryptionWithRsa,
395
2
        6 => AttributeValue::AuthReserved,
396
3
        7 => AttributeValue::AuthReserved,
397
1
        8 => AttributeValue::AuthReserved,
398
188
        9 => AttributeValue::AuthEcdsaSha256,
399
281
        10 => AttributeValue::AuthEcdsaSha384,
400
3
        11 => AttributeValue::AuthEcdsaSha512,
401
17.7k
        _ => AttributeValue::Unknown,
402
    }
403
20.4k
}
404
405
48.6k
fn get_group_description(v: u16) -> AttributeValue {
406
48.6k
    match v {
407
12
        1 => AttributeValue::GroupDefault768BitModp,
408
1.49k
        2 => AttributeValue::GroupAlternate1024BitModpGroup,
409
1
        3 => AttributeValue::GroupEc2nOnGp2p155,
410
1.90k
        4 => AttributeValue::GroupEc2nOnGp2p185,
411
0
        5 => AttributeValue::GroupModp1536Bit,
412
3
        6 => AttributeValue::GroupEc2nOverGf2p163,
413
0
        7 => AttributeValue::GroupEc2nOverGf2p163,
414
5
        8 => AttributeValue::GroupEc2nOverGf2p283,
415
2
        9 => AttributeValue::GroupEc2nOverGf2p283,
416
1
        10 => AttributeValue::GroupEc2nOverGf2p409,
417
0
        11 => AttributeValue::GroupEc2nOverGf2p409,
418
0
        12 => AttributeValue::GroupEc2nOverGf2p571,
419
0
        13 => AttributeValue::GroupEc2nOverGf2p571,
420
0
        14 => AttributeValue::GroupModp2048Bit,
421
0
        15 => AttributeValue::GroupModp3072Bit,
422
106
        16 => AttributeValue::GroupModp4096Bit,
423
2
        17 => AttributeValue::GroupModp6144Bit,
424
0
        18 => AttributeValue::GroupModp8192Bit,
425
0
        19 => AttributeValue::GroupRandomEcp256,
426
0
        20 => AttributeValue::GroupRandomEcp384,
427
0
        21 => AttributeValue::GroupRandomEcp521,
428
0
        22 => AttributeValue::GroupModp1024With160BitPrime,
429
0
        23 => AttributeValue::GroupModp2048With224BitPrime,
430
0
        24 => AttributeValue::GroupModp2048With256BitPrime,
431
0
        25 => AttributeValue::GroupRandomEcp192,
432
1
        26 => AttributeValue::GroupRandomEcp224,
433
307
        27 => AttributeValue::GroupBrainpoolEcp224,
434
49
        28 => AttributeValue::GroupBrainpoolEcp256,
435
1
        29 => AttributeValue::GroupBrainpoolEcp384,
436
0
        30 => AttributeValue::GroupBrainpoolEcp512,
437
44.7k
        _ => AttributeValue::Unknown,
438
    }
439
48.6k
}
440
441
987k
pub fn parse_sa_attribute(i: &[u8]) -> IResult<&[u8], Vec<SaAttribute>> {
442
1.32M
    fn parse_attribute(i: &[u8]) -> IResult<&[u8], SaAttribute> {
443
1.32M
        let (i, b) = be_u16(i)?;
444
719k
        let format = ((b >> 15) as u8, b & 0x7f_ff);
445
719k
        let (i, attribute_length_or_value) = be_u16(i)?; // depends on format bit) = 1 -> value | 0 -> number of following bytes
446
354k
        let (i, numeric_variable_value) =
447
354k
            cond(format.0 == 0 && attribute_length_or_value == 4, be_u32)(i)?; // interpret as number
448
354k
        let (i, variable_attribute_value) = cond(
449
354k
            format.0 == 0 && attribute_length_or_value != 4,
450
354k
            take(attribute_length_or_value),
451
354k
        )(i)?;
452
336k
        let attr = SaAttribute {
453
336k
            attribute_format: format.0,
454
336k
            attribute_type: get_attribute_type(format.1),
455
336k
            attribute_value: match format.1 {
456
3.93k
                1 => get_encryption_algorithm(attribute_length_or_value),
457
6.33k
                2 => get_hash_algorithm(attribute_length_or_value),
458
20.4k
                3 => get_authentication_method(attribute_length_or_value),
459
48.6k
                4 => get_group_description(attribute_length_or_value),
460
5.46k
                11 => match attribute_length_or_value {
461
1.62k
                    1 => AttributeValue::LifeTypeSeconds,
462
3
                    2 => AttributeValue::LifeTypeKilobytes,
463
3.83k
                    _ => AttributeValue::Unknown,
464
                },
465
251k
                _ => AttributeValue::Unknown,
466
            },
467
336k
            numeric_value: match format.0 {
468
58.9k
                1 => Some(attribute_length_or_value as u32),
469
277k
                0 => numeric_variable_value,
470
0
                _ => None,
471
            },
472
336k
            hex_value: match format.0 {
473
277k
                0 => variable_attribute_value
474
277k
                    .map(to_hex),
475
58.9k
                _ => None,
476
            },
477
        };
478
336k
        Ok((i, attr))
479
1.32M
    }
480
987k
    many0(complete(parse_attribute))(i)
481
987k
}
482
483
66.2k
pub fn parse_nonce(i: &[u8], length: u16) -> IResult<&[u8], NoncePayload<'_>> {
484
66.2k
    map(take(length), |v| NoncePayload { nonce_data: v })(i)
485
66.2k
}
486
487
132k
pub fn parse_ikev1_payload_list(i: &[u8]) -> IResult<&[u8], Vec<IsakmpPayload<'_>>> {
488
4.06M
    fn parse_payload(i: &[u8]) -> IResult<&[u8], IsakmpPayload<'_>> {
489
4.06M
        let (i, next_payload) = be_u8(i)?;
490
4.02M
        let (i, reserved) = be_u8(i)?;
491
4.01M
        let (i, payload_length) = be_u16(i)?;
492
3.99M
        let (i, payload_data) = cond(payload_length >= 4, |b| take(payload_length - 4)(b))(i)?;
493
3.92M
        Ok((
494
3.92M
            i,
495
3.92M
            IsakmpPayload {
496
3.92M
                payload_header: IsakmpPayloadHeader {
497
3.92M
                    next_payload,
498
3.92M
                    _reserved: reserved,
499
3.92M
                    _payload_length: payload_length,
500
3.92M
                },
501
3.92M
                data: payload_data.unwrap_or_default(),
502
3.92M
            },
503
3.92M
        ))
504
4.06M
    }
505
132k
    many0(complete(parse_payload))(i)
506
132k
}
507
508
#[derive(FromPrimitive, Debug)]
509
pub enum IsakmpPayloadType {
510
    None = 0,
511
    SecurityAssociation = 1,
512
    Proposal = 2,
513
    Transform = 3,
514
    KeyExchange = 4,
515
    Identification = 5,
516
    Certificate = 6,
517
    CertificateRequest = 7,
518
    Hash = 8,
519
    Signature = 9,
520
    Nonce = 10,
521
    Notification = 11,
522
    Delete = 12,
523
    VendorID = 13,
524
    SaKekPayload = 15,
525
    SaTekPayload = 16,
526
    KeyDownload = 17,
527
    SequenceNumber = 18,
528
    ProofOfPossession = 19,
529
    NatDiscovery = 20,
530
    NatOriginalAddress = 21,
531
    GroupAssociatedPolicy = 22,
532
}
533
534
impl fmt::Display for IsakmpPayloadType {
535
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
536
0
        write!(f, "{:?}", self)
537
0
    }
538
}
539
540
3.60M
pub fn parse_payload(
541
3.60M
    payload_type: u8, data: &[u8], data_length: u16, domain_of_interpretation: &mut Option<u32>,
542
3.60M
    key_exchange: &mut Vec<u8>, nonce: &mut Vec<u8>, transforms: &mut Vec<Vec<SaAttribute>>,
543
3.60M
    vendor_ids: &mut Vec<String>, payload_types: &mut HashSet<u8>,
544
3.60M
) -> Result<(), ()> {
545
3.60M
    payload_types.insert(payload_type);
546
547
3.60M
    let element = num::FromPrimitive::from_u8(payload_type);
548
3.00M
    match element {
549
        Some(IsakmpPayloadType::SecurityAssociation) => {
550
59.2k
            if parse_security_association_payload(
551
59.2k
                data,
552
59.2k
                data_length,
553
59.2k
                domain_of_interpretation,
554
59.2k
                key_exchange,
555
59.2k
                nonce,
556
59.2k
                transforms,
557
59.2k
                vendor_ids,
558
59.2k
                payload_types,
559
59.2k
            ).is_err() {
560
                SCLogDebug!("Error parsing SecurityAssociation");
561
41.5k
                return Err(());
562
17.7k
            }
563
17.7k
            Ok(())
564
        }
565
        Some(IsakmpPayloadType::Proposal) => {
566
14.0k
            if parse_proposal_payload(
567
14.0k
                data,
568
14.0k
                data_length,
569
14.0k
                domain_of_interpretation,
570
14.0k
                key_exchange,
571
14.0k
                nonce,
572
14.0k
                transforms,
573
14.0k
                vendor_ids,
574
14.0k
                payload_types,
575
14.0k
            ).is_err() {
576
                SCLogDebug!("Error parsing Proposal");
577
5.12k
                return Err(());
578
8.94k
            }
579
8.94k
            Ok(())
580
        }
581
        Some(IsakmpPayloadType::Transform) => {
582
1.00M
            if let Ok((_rem, payload)) = parse_transform(data, data_length) {
583
987k
                if let Ok((_, attribute_list)) = parse_sa_attribute(payload.sa_attributes) {
584
987k
                    transforms.push(attribute_list);
585
987k
                }
586
13.5k
            }
587
1.00M
            Ok(())
588
        }
589
        Some(IsakmpPayloadType::KeyExchange) => {
590
111k
            let res = parse_key_exchange(data, data_length);
591
111k
            if let Ok((_rem, payload)) = res {
592
111k
                *key_exchange = Vec::from(payload.key_exchange_data);
593
111k
            }
594
111k
            Ok(())
595
        }
596
        Some(IsakmpPayloadType::Nonce) => {
597
66.2k
            let res = parse_nonce(data, data_length);
598
66.2k
            if let Ok((_rem, payload)) = res {
599
66.2k
                *nonce = Vec::from(payload.nonce_data);
600
66.2k
            }
601
66.2k
            Ok(())
602
        }
603
        Some(IsakmpPayloadType::VendorID) => {
604
931k
            let res = parse_vendor_id(data, data_length);
605
931k
            if let Ok((_rem, payload)) = res {
606
931k
                vendor_ids.push(to_hex(payload.vendor_id));
607
931k
            }
608
931k
            Ok(())
609
        }
610
1.41M
        _ => Ok(()),
611
    }
612
3.60M
}
613
614
14.0k
fn parse_proposal_payload(
615
14.0k
    data: &[u8], data_length: u16, domain_of_interpretation: &mut Option<u32>,
616
14.0k
    key_exchange: &mut Vec<u8>, nonce: &mut Vec<u8>, transforms: &mut Vec<Vec<SaAttribute>>,
617
14.0k
    vendor_ids: &mut Vec<String>, payload_types: &mut HashSet<u8>,
618
14.0k
) -> Result<(), ()> {
619
14.0k
    match parse_proposal(&data[0..data_length as usize]) {
620
9.39k
        Ok((_rem, payload)) => {
621
9.39k
            let mut cur_payload_type = IsakmpPayloadType::Transform as u8;
622
9.39k
            match parse_ikev1_payload_list(payload.data) {
623
9.39k
                Ok((_, payload_list)) => {
624
84.6k
                    for isakmp_payload in payload_list {
625
75.6k
                        if parse_payload(
626
75.6k
                            cur_payload_type,
627
75.6k
                            isakmp_payload.data,
628
75.6k
                            isakmp_payload.data.len() as u16,
629
75.6k
                            domain_of_interpretation,
630
75.6k
                            key_exchange,
631
75.6k
                            nonce,
632
75.6k
                            transforms,
633
75.6k
                            vendor_ids,
634
75.6k
                            payload_types,
635
75.6k
                        ).is_err() {
636
                            SCLogDebug!("Error parsing transform payload");
637
445
                            return Err(());
638
75.2k
                        }
639
75.2k
                        cur_payload_type = isakmp_payload.payload_header.next_payload;
640
                    }
641
8.94k
                    Ok(())
642
                }
643
                Err(Err::Incomplete(_)) => {
644
                    SCLogDebug!("Incomplete data parsing payload list");
645
0
                    Err(())
646
                }
647
                Err(_) => {
648
                    SCLogDebug!("Error parsing payload list");
649
0
                    Err(())
650
                }
651
            }
652
        }
653
        Err(Err::Incomplete(_)) => {
654
            SCLogDebug!("Incomplete data");
655
4.68k
            Err(())
656
        }
657
0
        Err(_) => Err(()),
658
    }
659
14.0k
}
660
661
59.2k
fn parse_security_association_payload(
662
59.2k
    data: &[u8], data_length: u16, domain_of_interpretation: &mut Option<u32>,
663
59.2k
    key_exchange: &mut Vec<u8>, nonce: &mut Vec<u8>, transforms: &mut Vec<Vec<SaAttribute>>,
664
59.2k
    vendor_ids: &mut Vec<String>, payload_types: &mut HashSet<u8>,
665
59.2k
) -> Result<(), ()> {
666
59.2k
    match parse_security_association(&data[0..data_length as usize]) {
667
18.6k
        Ok((_rem, payload)) => {
668
18.6k
            *domain_of_interpretation = Some(payload.domain_of_interpretation);
669
18.6k
            if payload.domain_of_interpretation == 1 {
670
                // 1 is assigned to IPsec DOI
671
7.83k
                let mut cur_payload_type = IsakmpPayloadType::Proposal as u8;
672
7.83k
                if let Some(p_data) = payload.data {
673
7.83k
                    match parse_ikev1_payload_list(p_data) {
674
7.83k
                        Ok((_, payload_list)) => {
675
45.2k
                            for isakmp_payload in payload_list {
676
38.3k
                                if parse_payload(
677
38.3k
                                    cur_payload_type,
678
38.3k
                                    isakmp_payload.data,
679
38.3k
                                    isakmp_payload.data.len() as u16,
680
38.3k
                                    domain_of_interpretation,
681
38.3k
                                    key_exchange,
682
38.3k
                                    nonce,
683
38.3k
                                    transforms,
684
38.3k
                                    vendor_ids,
685
38.3k
                                    payload_types,
686
38.3k
                                ).is_err() {
687
                                    SCLogDebug!("Error parsing proposal payload");
688
852
                                    return Err(());
689
37.4k
                                }
690
37.4k
                                cur_payload_type = isakmp_payload.payload_header.next_payload;
691
                            }
692
                        }
693
                        Err(Err::Incomplete(_)) => {
694
                            SCLogDebug!("Incomplete data parsing payload list");
695
0
                            return Err(());
696
                        }
697
                        Err(_) => {
698
                            SCLogDebug!("Error parsing payload list");
699
0
                            return Err(());
700
                        }
701
                    }
702
0
                }
703
10.7k
            }
704
17.7k
            Ok(())
705
        }
706
        Err(Err::Incomplete(_)) => {
707
            SCLogDebug!("Incomplete data");
708
40.6k
            Err(())
709
        }
710
0
        Err(_) => Err(()),
711
    }
712
59.2k
}