/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 | } |