]> git.ipfire.org Git - people/ms/suricata.git/blame - rust/src/ike/ike.rs
ikev1: rename ikev2 to common ike
[people/ms/suricata.git] / rust / src / ike / ike.rs
CommitLineData
2f5834cd 1/* Copyright (C) 2017-2020 Open Information Security Foundation
c99b9462
PC
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// written by Pierre Chifflier <chifflier@wzdftpd.net>
19
ecdf9f6b 20use crate::ike::ipsec_parser::*;
21use crate::ike::state::IKEConnectionState;
42e5065a
JI
22use crate::core;
23use crate::core::{AppProto,Flow,ALPROTO_UNKNOWN,ALPROTO_FAILED,STREAM_TOSERVER,STREAM_TOCLIENT};
2f5834cd 24use crate::applayer::{self, *};
c99b9462
PC
25use std;
26use std::ffi::{CStr,CString};
27
13b73997 28use nom;
c99b9462
PC
29
30#[repr(u32)]
ecdf9f6b 31pub enum IkeEvent {
c99b9462
PC
32 MalformedData = 0,
33 NoEncryption,
34 WeakCryptoEnc,
35 WeakCryptoPRF,
36 WeakCryptoDH,
37 WeakCryptoAuth,
38 WeakCryptoNoDH,
39 WeakCryptoNoAuth,
40 InvalidProposal,
41 UnknownProposal,
42}
43
ecdf9f6b 44impl IkeEvent {
45 fn from_i32(value: i32) -> Option<IkeEvent> {
fb016416 46 match value {
ecdf9f6b 47 0 => Some(IkeEvent::MalformedData),
48 1 => Some(IkeEvent::NoEncryption),
49 2 => Some(IkeEvent::WeakCryptoEnc),
50 3 => Some(IkeEvent::WeakCryptoPRF),
51 4 => Some(IkeEvent::WeakCryptoDH),
52 5 => Some(IkeEvent::WeakCryptoAuth),
53 6 => Some(IkeEvent::WeakCryptoNoDH),
54 7 => Some(IkeEvent::WeakCryptoNoAuth),
55 8 => Some(IkeEvent::InvalidProposal),
56 9 => Some(IkeEvent::UnknownProposal),
fb016416
JL
57 _ => None,
58 }
59 }
60}
61
ecdf9f6b 62pub struct IKEState {
c99b9462 63 /// List of transactions for this session
ecdf9f6b 64 transactions: Vec<IKETransaction>,
c99b9462 65
c99b9462
PC
66 /// tx counter for assigning incrementing id's to tx's
67 tx_id: u64,
68
69 /// The connection state
ecdf9f6b 70 connection_state: IKEConnectionState,
c99b9462
PC
71
72 /// The transforms proposed by the initiator
73 pub client_transforms : Vec<Vec<IkeV2Transform>>,
74
75 /// The transforms selected by the responder
76 pub server_transforms : Vec<Vec<IkeV2Transform>>,
77
78 /// The encryption algorithm selected by the responder
79 pub alg_enc: IkeTransformEncType,
80 /// The authentication algorithm selected by the responder
81 pub alg_auth: IkeTransformAuthType,
82 /// The PRF algorithm selected by the responder
83 pub alg_prf: IkeTransformPRFType,
84 /// The Diffie-Hellman algorithm selected by the responder
85 pub alg_dh: IkeTransformDHType,
86 /// The extended sequence numbers parameter selected by the responder
87 pub alg_esn: IkeTransformESNType,
88
89 /// The Diffie-Hellman group from the server KE message, if present.
90 pub dh_group: IkeTransformDHType,
91
92}
93
94#[derive(Debug)]
ecdf9f6b 95pub struct IKETransaction {
96 /// The IKE reference ID
c99b9462
PC
97 pub xid: u64,
98
99 pub hdr: IkeV2Header,
100
d9434628
PC
101 pub payload_types: Vec<IkePayloadType>,
102 pub notify_types: Vec<NotifyType>,
103
104 /// IKEv2 errors seen during exchange
105 pub errors: u32,
106
c99b9462
PC
107 /// The internal transaction id
108 id: u64,
109
110 /// The detection engine state, if present
111 de_state: Option<*mut core::DetectEngineState>,
112
113 /// The events associated with this transaction
114 events: *mut core::AppLayerDecoderEvents,
115
e0f75157 116 tx_data: applayer::AppLayerTxData,
c99b9462
PC
117}
118
119
120
ecdf9f6b 121impl IKEState {
122 pub fn new() -> IKEState {
123 IKEState{
c99b9462 124 transactions: Vec::new(),
c99b9462 125 tx_id: 0,
ecdf9f6b 126 connection_state: IKEConnectionState::Init,
c99b9462
PC
127 dh_group: IkeTransformDHType::None,
128 client_transforms: Vec::new(),
129 server_transforms: Vec::new(),
130 alg_enc: IkeTransformEncType::ENCR_NULL,
131 alg_auth: IkeTransformAuthType::NONE,
132 alg_prf: IkeTransformPRFType::PRF_NULL,
133 alg_dh: IkeTransformDHType::None,
134 alg_esn: IkeTransformESNType::NoESN,
135 }
136 }
137}
138
ecdf9f6b 139impl IKEState {
140 /// Parse an IKE request message
c99b9462
PC
141 ///
142 /// Returns The number of messages parsed, or -1 on error
ae10a92b 143 fn parse(&mut self, i: &[u8], direction: u8) -> i32 {
c99b9462 144 match parse_ikev2_header(i) {
13b73997 145 Ok((rem,ref hdr)) => {
c99b9462
PC
146 if rem.len() == 0 && hdr.length == 28 {
147 return 1;
148 }
149 // Rule 0: check version
150 if hdr.maj_ver != 2 || hdr.min_ver != 0 {
ecdf9f6b 151 self.set_event(IkeEvent::MalformedData);
bf66948a 152 return -1;
c99b9462
PC
153 }
154 if hdr.init_spi == 0 {
ecdf9f6b 155 self.set_event(IkeEvent::MalformedData);
c99b9462
PC
156 return -1;
157 }
158 // only analyse IKE_SA, other payloads are encrypted
159 if hdr.exch_type != IkeExchangeType::IKE_SA_INIT {
160 return 0;
161 }
162 let mut tx = self.new_tx();
163 // use init_spi as transaction identifier
164 tx.xid = hdr.init_spi;
165 tx.hdr = (*hdr).clone();
f90733fe
PC
166 self.transactions.push(tx);
167 let mut payload_types = Vec::new();
168 let mut errors = 0;
169 let mut notify_types = Vec::new();
c99b9462 170 match parse_ikev2_payload_list(rem,hdr.next_payload) {
13b73997 171 Ok((_,Ok(ref p))) => {
c99b9462 172 for payload in p {
f90733fe 173 payload_types.push(payload.hdr.next_payload_type);
c99b9462
PC
174 match payload.content {
175 IkeV2PayloadContent::Dummy => (),
176 IkeV2PayloadContent::SA(ref prop) => {
ecdf9f6b 177 // if hdr.flags & IKE_FLAG_INITIATOR != 0 {
c99b9462
PC
178 self.add_proposals(prop, direction);
179 // }
180 },
181 IkeV2PayloadContent::KE(ref kex) => {
182 SCLogDebug!("KEX {:?}", kex.dh_group);
183 if direction == STREAM_TOCLIENT {
184 self.dh_group = kex.dh_group;
185 }
186 },
187 IkeV2PayloadContent::Nonce(ref n) => {
188 SCLogDebug!("Nonce: {:?}", n);
189 },
190 IkeV2PayloadContent::Notify(ref n) => {
191 SCLogDebug!("Notify: {:?}", n);
d9434628 192 if n.notify_type.is_error() {
f90733fe 193 errors += 1;
d9434628 194 }
f90733fe 195 notify_types.push(n.notify_type);
c99b9462
PC
196 },
197 // XXX CertificateRequest
198 // XXX Certificate
199 // XXX Authentication
200 // XXX TSi
201 // XXX TSr
202 // XXX IDr
203 _ => {
bf66948a 204 SCLogDebug!("Unknown payload content {:?}", payload.content);
c99b9462
PC
205 },
206 }
207 self.connection_state = self.connection_state.advance(payload);
f90733fe
PC
208 if let Some(tx) = self.transactions.last_mut() {
209 // borrow back tx to update it
210 tx.payload_types.append(&mut payload_types);
211 tx.errors = errors;
212 tx.notify_types.append(&mut notify_types);
213 }
c99b9462
PC
214 };
215 },
ecdf9f6b 216 e => { SCLogDebug!("parse_ike_payload_with_type: {:?}",e); () },
c99b9462 217 }
c99b9462
PC
218 1
219 },
13b73997 220 Err(nom::Err::Incomplete(_)) => {
ecdf9f6b 221 SCLogDebug!("Insufficient data while parsing IKE data");
222 self.set_event(IkeEvent::MalformedData);
c99b9462
PC
223 -1
224 },
13b73997 225 Err(_) => {
ecdf9f6b 226 SCLogDebug!("Error while parsing IKE data");
227 self.set_event(IkeEvent::MalformedData);
c99b9462
PC
228 -1
229 },
230 }
231 }
232
233 fn free(&mut self) {
234 // All transactions are freed when the `transactions` object is freed.
235 // But let's be explicit
236 self.transactions.clear();
237 }
238
ecdf9f6b 239 fn new_tx(&mut self) -> IKETransaction {
c99b9462 240 self.tx_id += 1;
ecdf9f6b 241 IKETransaction::new(self.tx_id)
c99b9462
PC
242 }
243
ecdf9f6b 244 fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&IKETransaction> {
c99b9462
PC
245 self.transactions.iter().find(|&tx| tx.id == tx_id + 1)
246 }
247
248 fn free_tx(&mut self, tx_id: u64) {
249 let tx = self.transactions.iter().position(|ref tx| tx.id == tx_id + 1);
250 debug_assert!(tx != None);
251 if let Some(idx) = tx {
252 let _ = self.transactions.remove(idx);
253 }
254 }
255
256 /// Set an event. The event is set on the most recent transaction.
ecdf9f6b 257 fn set_event(&mut self, event: IkeEvent) {
c99b9462
PC
258 if let Some(tx) = self.transactions.last_mut() {
259 let ev = event as u8;
260 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
f90733fe
PC
261 } else {
262 SCLogDebug!("IKEv2: trying to set event {} on non-existing transaction", event as u32);
c99b9462
PC
263 }
264 }
265
266 fn add_proposals(&mut self, prop: &Vec<IkeV2Proposal>, direction: u8) {
267 for ref p in prop {
268 let transforms : Vec<IkeV2Transform> = p.transforms.iter().map(|x| x.into()).collect();
269 // Rule 1: warn on weak or unknown transforms
270 for xform in &transforms {
271 match *xform {
272 IkeV2Transform::Encryption(ref enc) => {
273 match *enc {
274 IkeTransformEncType::ENCR_DES_IV64 |
275 IkeTransformEncType::ENCR_DES |
276 IkeTransformEncType::ENCR_3DES |
277 IkeTransformEncType::ENCR_RC5 |
278 IkeTransformEncType::ENCR_IDEA |
279 IkeTransformEncType::ENCR_CAST |
280 IkeTransformEncType::ENCR_BLOWFISH |
281 IkeTransformEncType::ENCR_3IDEA |
282 IkeTransformEncType::ENCR_DES_IV32 |
283 IkeTransformEncType::ENCR_NULL => {
284 SCLogDebug!("Weak Encryption: {:?}", enc);
285 // XXX send event only if direction == STREAM_TOCLIENT ?
ecdf9f6b 286 self.set_event(IkeEvent::WeakCryptoEnc);
c99b9462
PC
287 },
288 _ => (),
289 }
290 },
291 IkeV2Transform::PRF(ref prf) => {
292 match *prf {
293 IkeTransformPRFType::PRF_NULL => {
294 SCLogDebug!("'Null' PRF transform proposed");
ecdf9f6b 295 self.set_event(IkeEvent::InvalidProposal);
c99b9462
PC
296 },
297 IkeTransformPRFType::PRF_HMAC_MD5 |
298 IkeTransformPRFType::PRF_HMAC_SHA1 => {
299 SCLogDebug!("Weak PRF: {:?}", prf);
ecdf9f6b 300 self.set_event(IkeEvent::WeakCryptoPRF);
c99b9462
PC
301 },
302 _ => (),
303 }
304 },
305 IkeV2Transform::Auth(ref auth) => {
306 match *auth {
307 IkeTransformAuthType::NONE => {
308 // Note: this could be expected with an AEAD encription alg.
309 // See rule 4
310 ()
311 },
312 IkeTransformAuthType::AUTH_HMAC_MD5_96 |
313 IkeTransformAuthType::AUTH_HMAC_SHA1_96 |
314 IkeTransformAuthType::AUTH_DES_MAC |
315 IkeTransformAuthType::AUTH_KPDK_MD5 |
316 IkeTransformAuthType::AUTH_AES_XCBC_96 |
317 IkeTransformAuthType::AUTH_HMAC_MD5_128 |
318 IkeTransformAuthType::AUTH_HMAC_SHA1_160 => {
319 SCLogDebug!("Weak auth: {:?}", auth);
ecdf9f6b 320 self.set_event(IkeEvent::WeakCryptoAuth);
c99b9462
PC
321 },
322 _ => (),
323 }
324 },
325 IkeV2Transform::DH(ref dh) => {
326 match *dh {
327 IkeTransformDHType::None => {
328 SCLogDebug!("'None' DH transform proposed");
ecdf9f6b 329 self.set_event(IkeEvent::InvalidProposal);
c99b9462
PC
330 },
331 IkeTransformDHType::Modp768 |
332 IkeTransformDHType::Modp1024 |
333 IkeTransformDHType::Modp1024s160 |
334 IkeTransformDHType::Modp1536 => {
335 SCLogDebug!("Weak DH: {:?}", dh);
ecdf9f6b 336 self.set_event(IkeEvent::WeakCryptoDH);
c99b9462
PC
337 },
338 _ => (),
339 }
340 },
341 IkeV2Transform::Unknown(tx_type,tx_id) => {
342 SCLogDebug!("Unknown proposal: type={:?}, id={}", tx_type, tx_id);
ecdf9f6b 343 self.set_event(IkeEvent::UnknownProposal);
c99b9462
PC
344 },
345 _ => (),
346 }
347 }
348 // Rule 2: check if no DH was proposed
349 if ! transforms.iter().any(|x| {
350 match *x {
351 IkeV2Transform::DH(_) => true,
352 _ => false
353 }
354 })
355 {
356 SCLogDebug!("No DH transform found");
ecdf9f6b 357 self.set_event(IkeEvent::WeakCryptoNoDH);
c99b9462
PC
358 }
359 // Rule 3: check if proposing AH ([RFC7296] section 3.3.1)
360 if p.protocol_id == ProtocolID::AH {
361 SCLogDebug!("Proposal uses protocol AH - no confidentiality");
ecdf9f6b 362 self.set_event(IkeEvent::NoEncryption);
c99b9462
PC
363 }
364 // Rule 4: lack of integrity is accepted only if using an AEAD proposal
365 // Look if no auth was proposed, including if proposal is Auth::None
366 if ! transforms.iter().any(|x| {
367 match *x {
368 IkeV2Transform::Auth(IkeTransformAuthType::NONE) => false,
369 IkeV2Transform::Auth(_) => true,
370 _ => false,
371 }
372 })
373 {
374 if ! transforms.iter().any(|x| {
375 match *x {
376 IkeV2Transform::Encryption(ref enc) => enc.is_aead(),
377 _ => false
378 }
379 }) {
380 SCLogDebug!("No integrity transform found");
ecdf9f6b 381 self.set_event(IkeEvent::WeakCryptoNoAuth);
c99b9462
PC
382 }
383 }
384 // Finally
385 if direction == STREAM_TOCLIENT {
386 transforms.iter().for_each(|t|
387 match *t {
388 IkeV2Transform::Encryption(ref e) => self.alg_enc = *e,
389 IkeV2Transform::Auth(ref a) => self.alg_auth = *a,
390 IkeV2Transform::PRF(ref p) => self.alg_prf = *p,
391 IkeV2Transform::DH(ref dh) => self.alg_dh = *dh,
392 IkeV2Transform::ESN(ref e) => self.alg_esn = *e,
393 _ => (),
394 });
395 SCLogDebug!("Selected transforms: {:?}", transforms);
396 self.server_transforms.push(transforms);
397 } else {
398 SCLogDebug!("Proposed transforms: {:?}", transforms);
399 self.client_transforms.push(transforms);
400 }
401 }
402 }
403}
404
ecdf9f6b 405impl IKETransaction {
406 pub fn new(id: u64) -> IKETransaction {
407 IKETransaction {
c99b9462
PC
408 xid: 0,
409 hdr: IkeV2Header {
410 init_spi: 0,
411 resp_spi: 0,
412 next_payload: IkePayloadType::NoNextPayload,
413 maj_ver: 0,
414 min_ver: 0,
415 exch_type: IkeExchangeType(0),
416 flags: 0,
417 msg_id: 0,
418 length: 0,
419 },
d9434628
PC
420 payload_types: Vec::new(),
421 notify_types: Vec::new(),
422 errors: 0,
c99b9462
PC
423 id: id,
424 de_state: None,
425 events: std::ptr::null_mut(),
e0f75157 426 tx_data: applayer::AppLayerTxData::new(),
c99b9462
PC
427 }
428 }
429
430 fn free(&mut self) {
431 if self.events != std::ptr::null_mut() {
432 core::sc_app_layer_decoder_events_free_events(&mut self.events);
433 }
083908f3
VJ
434 if let Some(state) = self.de_state {
435 core::sc_detect_engine_state_free(state);
436 }
c99b9462
PC
437 }
438}
439
ecdf9f6b 440impl Drop for IKETransaction {
c99b9462
PC
441 fn drop(&mut self) {
442 self.free();
443 }
444}
445
ecdf9f6b 446/// Returns *mut IKEState
c99b9462 447#[no_mangle]
ecdf9f6b 448pub extern "C" fn rs_ike_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void {
449 let state = IKEState::new();
c99b9462
PC
450 let boxed = Box::new(state);
451 return unsafe{std::mem::transmute(boxed)};
452}
453
454/// Params:
ecdf9f6b 455/// - state: *mut IKEState as void pointer
c99b9462 456#[no_mangle]
ecdf9f6b 457pub extern "C" fn rs_ike_state_free(state: *mut std::os::raw::c_void) {
c99b9462 458 // Just unbox...
ecdf9f6b 459 let mut ike_state: Box<IKEState> = unsafe{std::mem::transmute(state)};
460 ike_state.free();
c99b9462
PC
461}
462
463#[no_mangle]
ecdf9f6b 464pub extern "C" fn rs_ike_parse_request(_flow: *const core::Flow,
3f6624bf
VJ
465 state: *mut std::os::raw::c_void,
466 _pstate: *mut std::os::raw::c_void,
bf1bd407 467 input: *const u8,
c99b9462 468 input_len: u32,
3f6624bf 469 _data: *const std::os::raw::c_void,
44d3f264 470 _flags: u8) -> AppLayerResult {
c99b9462 471 let buf = build_slice!(input,input_len as usize);
ecdf9f6b 472 let state = cast_pointer!(state,IKEState);
44d3f264
VJ
473 if state.parse(buf, STREAM_TOSERVER) < 0 {
474 return AppLayerResult::err();
3bcf948a 475 }
44d3f264 476 return AppLayerResult::ok();
c99b9462
PC
477}
478
479#[no_mangle]
ecdf9f6b 480pub extern "C" fn rs_ike_parse_response(_flow: *const core::Flow,
3f6624bf
VJ
481 state: *mut std::os::raw::c_void,
482 pstate: *mut std::os::raw::c_void,
bf1bd407 483 input: *const u8,
c99b9462 484 input_len: u32,
3f6624bf 485 _data: *const std::os::raw::c_void,
44d3f264 486 _flags: u8) -> AppLayerResult {
c99b9462 487 let buf = build_slice!(input,input_len as usize);
ecdf9f6b 488 let state = cast_pointer!(state,IKEState);
c99b9462 489 let res = state.parse(buf, STREAM_TOCLIENT);
ecdf9f6b 490 if state.connection_state == IKEConnectionState::ParsingDone {
c99b9462
PC
491 unsafe{
492 AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION |
493 APP_LAYER_PARSER_NO_REASSEMBLY |
494 APP_LAYER_PARSER_BYPASS_READY)
495 };
496 }
3bcf948a 497 if res < 0 {
44d3f264 498 return AppLayerResult::err();
3bcf948a 499 }
44d3f264 500 return AppLayerResult::ok();
c99b9462
PC
501}
502
503#[no_mangle]
ecdf9f6b 504pub extern "C" fn rs_ike_state_get_tx(state: *mut std::os::raw::c_void,
bf1bd407 505 tx_id: u64)
3f6624bf 506 -> *mut std::os::raw::c_void
c99b9462 507{
ecdf9f6b 508 let state = cast_pointer!(state,IKEState);
c99b9462
PC
509 match state.get_tx_by_id(tx_id) {
510 Some(tx) => unsafe{std::mem::transmute(tx)},
511 None => std::ptr::null_mut(),
512 }
513}
514
515#[no_mangle]
ecdf9f6b 516pub extern "C" fn rs_ike_state_get_tx_count(state: *mut std::os::raw::c_void)
bf1bd407 517 -> u64
c99b9462 518{
ecdf9f6b 519 let state = cast_pointer!(state,IKEState);
c99b9462
PC
520 state.tx_id
521}
522
523#[no_mangle]
ecdf9f6b 524pub extern "C" fn rs_ike_state_tx_free(state: *mut std::os::raw::c_void,
bf1bd407 525 tx_id: u64)
c99b9462 526{
ecdf9f6b 527 let state = cast_pointer!(state,IKEState);
c99b9462
PC
528 state.free_tx(tx_id);
529}
530
c99b9462 531#[no_mangle]
ecdf9f6b 532pub extern "C" fn rs_ike_state_progress_completion_status(
533 _direction: u8)
534 -> std::os::raw::c_int
535{
536 return 1;
537}
538
539#[no_mangle]
540pub extern "C" fn rs_ike_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void,
bf1bd407 541 _direction: u8)
3f6624bf 542 -> std::os::raw::c_int
c99b9462
PC
543{
544 1
545}
546
c99b9462 547#[no_mangle]
ecdf9f6b 548pub extern "C" fn rs_ike_state_set_tx_detect_state(
3f6624bf
VJ
549 tx: *mut std::os::raw::c_void,
550 de_state: &mut core::DetectEngineState) -> std::os::raw::c_int
c99b9462 551{
ecdf9f6b 552 let tx = cast_pointer!(tx,IKETransaction);
c99b9462
PC
553 tx.de_state = Some(de_state);
554 0
555}
556
557#[no_mangle]
ecdf9f6b 558pub extern "C" fn rs_ike_state_get_tx_detect_state(
3f6624bf 559 tx: *mut std::os::raw::c_void)
c99b9462
PC
560 -> *mut core::DetectEngineState
561{
ecdf9f6b 562 let tx = cast_pointer!(tx,IKETransaction);
c99b9462
PC
563 match tx.de_state {
564 Some(ds) => ds,
565 None => std::ptr::null_mut(),
566 }
567}
568
569
570#[no_mangle]
ecdf9f6b 571pub extern "C" fn rs_ike_state_get_events(tx: *mut std::os::raw::c_void)
c99b9462
PC
572 -> *mut core::AppLayerDecoderEvents
573{
ecdf9f6b 574 let tx = cast_pointer!(tx, IKETransaction);
d568e7fa 575 return tx.events;
c99b9462
PC
576}
577
fb016416 578#[no_mangle]
ecdf9f6b 579pub extern "C" fn rs_ike_state_get_event_info_by_id(event_id: std::os::raw::c_int,
fb016416
JL
580 event_name: *mut *const std::os::raw::c_char,
581 event_type: *mut core::AppLayerEventType)
582 -> i8
583{
ecdf9f6b 584 if let Some(e) = IkeEvent::from_i32(event_id as i32) {
fb016416 585 let estr = match e {
ecdf9f6b 586 IkeEvent::MalformedData => { "malformed_data\0" },
587 IkeEvent::NoEncryption => { "no_encryption\0" },
588 IkeEvent::WeakCryptoEnc => { "weak_crypto_enc\0" },
589 IkeEvent::WeakCryptoPRF => { "weak_crypto_prf\0" },
590 IkeEvent::WeakCryptoDH => { "weak_crypto_dh\0" },
591 IkeEvent::WeakCryptoAuth => { "weak_crypto_auth\0" },
592 IkeEvent::WeakCryptoNoDH => { "weak_crypto_nodh\0" },
593 IkeEvent::WeakCryptoNoAuth => { "weak_crypto_noauth\0" },
594 IkeEvent::InvalidProposal => { "invalid_proposal\0" },
595 IkeEvent::UnknownProposal => { "unknown_proposal\0" },
fb016416
JL
596 };
597 unsafe{
598 *event_name = estr.as_ptr() as *const std::os::raw::c_char;
599 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
600 };
601 0
602 } else {
603 -1
604 }
605}
606
c99b9462 607#[no_mangle]
ecdf9f6b 608pub extern "C" fn rs_ike_state_get_event_info(event_name: *const std::os::raw::c_char,
3f6624bf 609 event_id: *mut std::os::raw::c_int,
c99b9462 610 event_type: *mut core::AppLayerEventType)
3f6624bf 611 -> std::os::raw::c_int
c99b9462
PC
612{
613 if event_name == std::ptr::null() { return -1; }
614 let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
615 let event = match c_event_name.to_str() {
616 Ok(s) => {
617 match s {
ecdf9f6b 618 "malformed_data" => IkeEvent::MalformedData as i32,
619 "no_encryption" => IkeEvent::NoEncryption as i32,
620 "weak_crypto_enc" => IkeEvent::WeakCryptoEnc as i32,
621 "weak_crypto_prf" => IkeEvent::WeakCryptoPRF as i32,
622 "weak_crypto_auth" => IkeEvent::WeakCryptoAuth as i32,
623 "weak_crypto_dh" => IkeEvent::WeakCryptoDH as i32,
624 "weak_crypto_nodh" => IkeEvent::WeakCryptoNoDH as i32,
625 "weak_crypto_noauth" => IkeEvent::WeakCryptoNoAuth as i32,
626 "invalid_proposal" => IkeEvent::InvalidProposal as i32,
627 "unknown_proposal" => IkeEvent::UnknownProposal as i32,
c99b9462
PC
628 _ => -1, // unknown event
629 }
630 },
631 Err(_) => -1, // UTF-8 conversion failed
632 };
633 unsafe{
634 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
3f6624bf 635 *event_id = event as std::os::raw::c_int;
c99b9462
PC
636 };
637 0
638}
639
ecdf9f6b 640static mut ALPROTO_IKE : AppProto = ALPROTO_UNKNOWN;
c99b9462
PC
641
642#[no_mangle]
ecdf9f6b 643pub extern "C" fn rs_ike_probing_parser(_flow: *const Flow,
422e4892 644 _direction: u8,
bf1bd407 645 input:*const u8, input_len: u32,
422e4892
VJ
646 _rdir: *mut u8) -> AppProto
647{
c99b9462 648 let slice = build_slice!(input,input_len as usize);
ecdf9f6b 649 let alproto = unsafe{ ALPROTO_IKE };
c99b9462 650 match parse_ikev2_header(slice) {
13b73997 651 Ok((_, ref hdr)) => {
c99b9462
PC
652 if hdr.maj_ver != 2 || hdr.min_ver != 0 {
653 SCLogDebug!("ipsec_probe: could be ipsec, but with unsupported/invalid version {}.{}",
654 hdr.maj_ver, hdr.min_ver);
655 return unsafe{ALPROTO_FAILED};
656 }
657 if hdr.exch_type.0 < 34 || hdr.exch_type.0 > 37 {
658 SCLogDebug!("ipsec_probe: could be ipsec, but with unsupported/invalid exchange type {}",
659 hdr.exch_type.0);
660 return unsafe{ALPROTO_FAILED};
661 }
662 if hdr.length as usize != slice.len() {
663 SCLogDebug!("ipsec_probe: could be ipsec, but length does not match");
664 return unsafe{ALPROTO_FAILED};
665 }
666 return alproto;
667 },
13b73997 668 Err(nom::Err::Incomplete(_)) => {
c99b9462
PC
669 return ALPROTO_UNKNOWN;
670 },
13b73997 671 Err(_) => {
c99b9462
PC
672 return unsafe{ALPROTO_FAILED};
673 },
674 }
675}
676
ecdf9f6b 677export_tx_data_get!(rs_ike_get_tx_data, IKETransaction);
e0f75157 678
ecdf9f6b 679const PARSER_NAME : &'static [u8] = b"ike\0";
c99b9462
PC
680
681#[no_mangle]
ecdf9f6b 682pub unsafe extern "C" fn rs_register_ike_parser() {
c99b9462
PC
683 let default_port = CString::new("500").unwrap();
684 let parser = RustParser {
fb016416
JL
685 name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
686 default_port : default_port.as_ptr(),
687 ipproto : core::IPPROTO_UDP,
ecdf9f6b 688 probe_ts : Some(rs_ike_probing_parser),
689 probe_tc : Some(rs_ike_probing_parser),
fb016416
JL
690 min_depth : 0,
691 max_depth : 16,
ecdf9f6b 692 state_new : rs_ike_state_new,
693 state_free : rs_ike_state_free,
694 tx_free : rs_ike_state_tx_free,
695 parse_ts : rs_ike_parse_request,
696 parse_tc : rs_ike_parse_response,
697 get_tx_count : rs_ike_state_get_tx_count,
698 get_tx : rs_ike_state_get_tx,
efc9a7a3
VJ
699 tx_comp_st_ts : 1,
700 tx_comp_st_tc : 1,
ecdf9f6b 701 tx_get_progress : rs_ike_tx_get_alstate_progress,
702 get_de_state : rs_ike_state_get_tx_detect_state,
703 set_de_state : rs_ike_state_set_tx_detect_state,
704 get_events : Some(rs_ike_state_get_events),
705 get_eventinfo : Some(rs_ike_state_get_event_info),
706 get_eventinfo_byid : Some(rs_ike_state_get_event_info_by_id),
fb016416
JL
707 localstorage_new : None,
708 localstorage_free : None,
fb016416
JL
709 get_files : None,
710 get_tx_iterator : None,
ecdf9f6b 711 get_tx_data : rs_ike_get_tx_data,
5665fc83 712 apply_tx_config : None,
3036ec4d 713 flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS,
4da0d9bd 714 truncate : None,
c99b9462
PC
715 };
716
717 let ip_proto_str = CString::new("udp").unwrap();
718 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
719 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
720 // store the allocated ID for the probe function
ecdf9f6b 721 ALPROTO_IKE = alproto;
c99b9462
PC
722 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
723 let _ = AppLayerRegisterParser(&parser, alproto);
724 }
725 } else {
ecdf9f6b 726 SCLogDebug!("Protocol detector and parser disabled for IKE.");
c99b9462
PC
727 }
728}
729
730
731#[cfg(test)]
732mod tests {
ecdf9f6b 733 use super::IKEState;
c99b9462
PC
734
735 #[test]
ecdf9f6b 736 fn test_ike_parse_request_valid() {
737 // A UDP IKE v4 request, in client mode
c99b9462
PC
738 const REQ : &[u8] = &[
739 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
740 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
741 0x00, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
743 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
744 0x18, 0x57, 0xab, 0xc3, 0x4a, 0x5f, 0x2c, 0xfe
745 ];
746
ecdf9f6b 747 let mut state = IKEState::new();
c99b9462
PC
748 assert_eq!(1, state.parse(REQ, 0));
749 }
750}