]> git.ipfire.org Git - people/ms/suricata.git/blob - rust/src/ike/ike.rs
f445e815817f2c9f52a0f2a142d678340f79f89c
[people/ms/suricata.git] / rust / src / ike / ike.rs
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 // Author: Frank Honza <frank.honza@dcso.de>
19
20 extern crate ipsec_parser;
21 use self::ipsec_parser::*;
22
23 use crate::applayer;
24 use crate::applayer::*;
25 use crate::core::{self, *};
26 use crate::ike::ikev1::{handle_ikev1, IkeV1Header, Ikev1Container};
27 use crate::ike::ikev2::{handle_ikev2, Ikev2Container};
28 use crate::ike::parser::*;
29 use nom;
30 use std;
31 use std::collections::HashSet;
32 use std::ffi::CString;
33
34 #[derive(AppLayerEvent)]
35 pub enum IkeEvent {
36 MalformedData,
37 NoEncryption,
38 WeakCryptoEnc,
39 WeakCryptoPrf,
40 WeakCryptoDh,
41 WeakCryptoAuth,
42 WeakCryptoNoDh,
43 WeakCryptoNoAuth,
44 InvalidProposal,
45 UnknownProposal,
46 PayloadExtraData,
47 MultipleServerProposal,
48 }
49
50 pub struct IkeHeaderWrapper {
51 pub spi_initiator: String,
52 pub spi_responder: String,
53 pub maj_ver: u8,
54 pub min_ver: u8,
55 pub msg_id: u32,
56 pub flags: u8,
57 pub ikev1_transforms: Vec<Vec<SaAttribute>>,
58 pub ikev2_transforms: Vec<IkeV2Transform>,
59 pub ikev1_header: IkeV1Header,
60 pub ikev2_header: IkeV2Header,
61 }
62
63 impl IkeHeaderWrapper {
64 pub fn new() -> IkeHeaderWrapper {
65 IkeHeaderWrapper {
66 spi_initiator: String::new(),
67 spi_responder: String::new(),
68 maj_ver: 0,
69 min_ver: 0,
70 msg_id: 0,
71 flags: 0,
72 ikev1_transforms: Vec::new(),
73 ikev2_transforms: Vec::new(),
74 ikev1_header: IkeV1Header::default(),
75 ikev2_header: IkeV2Header {
76 init_spi: 0,
77 resp_spi: 0,
78 next_payload: IkePayloadType::NoNextPayload,
79 maj_ver: 0,
80 min_ver: 0,
81 exch_type: IkeExchangeType(0),
82 flags: 0,
83 msg_id: 0,
84 length: 0,
85 },
86 }
87 }
88 }
89
90 #[derive(Default)]
91 pub struct IkePayloadWrapper {
92 pub ikev1_payload_types: Option<HashSet<u8>>,
93 pub ikev2_payload_types: Vec<IkePayloadType>,
94 }
95
96 pub struct IKETransaction {
97 tx_id: u64,
98
99 pub ike_version: u8,
100 pub hdr: IkeHeaderWrapper,
101 pub payload_types: IkePayloadWrapper,
102 pub notify_types: Vec<NotifyType>,
103
104 /// errors seen during exchange
105 pub errors: u32,
106
107 logged: LoggerFlags,
108 de_state: Option<*mut core::DetectEngineState>,
109 events: *mut core::AppLayerDecoderEvents,
110 tx_data: applayer::AppLayerTxData,
111 }
112
113 impl IKETransaction {
114 pub fn new() -> IKETransaction {
115 IKETransaction {
116 tx_id: 0,
117 ike_version: 0,
118 hdr: IkeHeaderWrapper::new(),
119 payload_types: Default::default(),
120 notify_types: vec![],
121 logged: LoggerFlags::new(),
122 de_state: None,
123 events: std::ptr::null_mut(),
124 tx_data: applayer::AppLayerTxData::new(),
125 errors: 0,
126 }
127 }
128
129 pub fn free(&mut self) {
130 if !self.events.is_null() {
131 core::sc_app_layer_decoder_events_free_events(&mut self.events);
132 }
133 if let Some(state) = self.de_state {
134 core::sc_detect_engine_state_free(state);
135 }
136 }
137
138 /// Set an event.
139 pub fn set_event(&mut self, event: IkeEvent) {
140 let ev = event as u8;
141 core::sc_app_layer_decoder_events_set_event_raw(&mut self.events, ev);
142 }
143 }
144
145 impl Drop for IKETransaction {
146 fn drop(&mut self) {
147 self.free();
148 }
149 }
150
151 #[derive(Default)]
152 pub struct IKEState {
153 tx_id: u64,
154 pub transactions: Vec<IKETransaction>,
155
156 pub ikev1_container: Ikev1Container,
157 pub ikev2_container: Ikev2Container,
158 }
159
160 impl IKEState {
161 // Free a transaction by ID.
162 fn free_tx(&mut self, tx_id: u64) {
163 let tx = self
164 .transactions
165 .iter()
166 .position(|tx| tx.tx_id == tx_id + 1);
167 debug_assert!(tx != None);
168 if let Some(idx) = tx {
169 let _ = self.transactions.remove(idx);
170 }
171 }
172
173 pub fn get_tx(&mut self, tx_id: u64) -> Option<&mut IKETransaction> {
174 for tx in &mut self.transactions {
175 if tx.tx_id == tx_id + 1 {
176 return Some(tx);
177 }
178 }
179 return None;
180 }
181
182 pub fn new_tx(&mut self) -> IKETransaction {
183 let mut tx = IKETransaction::new();
184 self.tx_id += 1;
185 tx.tx_id = self.tx_id;
186 return tx;
187 }
188
189 /// Set an event. The event is set on the most recent transaction.
190 pub fn set_event(&mut self, event: IkeEvent) {
191 if let Some(tx) = self.transactions.last_mut() {
192 let ev = event as u8;
193 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
194 } else {
195 SCLogDebug!(
196 "IKE: trying to set event {} on non-existing transaction",
197 event as u32
198 );
199 }
200 }
201
202 fn handle_input(&mut self, input: &[u8], direction: Direction) -> AppLayerResult {
203 // We're not interested in empty requests.
204 if input.len() == 0 {
205 return AppLayerResult::ok();
206 }
207
208 let mut current = input;
209 match parse_isakmp_header(current) {
210 Ok((rem, isakmp_header)) => {
211 current = rem;
212
213 if isakmp_header.maj_ver != 1 && isakmp_header.maj_ver != 2 {
214 SCLogDebug!("Unsupported ISAKMP major_version");
215 return AppLayerResult::err();
216 }
217
218 if isakmp_header.maj_ver == 1 {
219 handle_ikev1(self, current, isakmp_header, direction);
220 } else if isakmp_header.maj_ver == 2 {
221 handle_ikev2(self, current, isakmp_header, direction);
222 } else {
223 return AppLayerResult::err();
224 }
225 return AppLayerResult::ok(); // todo either remove outer loop or check header length-field if we have completely read everything
226 }
227 Err(nom::Err::Incomplete(_)) => {
228 SCLogDebug!("Insufficient data while parsing IKE");
229 return AppLayerResult::err();
230 }
231 Err(_) => {
232 SCLogDebug!("Error while parsing IKE packet");
233 return AppLayerResult::err();
234 }
235 }
236 }
237
238 fn tx_iterator(
239 &mut self, min_tx_id: u64, state: &mut u64,
240 ) -> Option<(&IKETransaction, u64, bool)> {
241 let mut index = *state as usize;
242 let len = self.transactions.len();
243
244 while index < len {
245 let tx = &self.transactions[index];
246 if tx.tx_id < min_tx_id + 1 {
247 index += 1;
248 continue;
249 }
250 *state = index as u64;
251
252 return Some((tx, tx.tx_id - 1, (len - index) > 1));
253 }
254
255 return None;
256 }
257 }
258
259 /// Probe to see if this input looks like a request or response.
260 fn probe(input: &[u8], direction: Direction, rdir: *mut u8) -> bool {
261 match parse_isakmp_header(input) {
262 Ok((_, isakmp_header)) => {
263 if isakmp_header.maj_ver == 1 {
264 if isakmp_header.resp_spi == 0 && direction != Direction::ToServer {
265 unsafe {
266 *rdir = Direction::ToServer.into();
267 }
268 }
269 return true;
270 } else if isakmp_header.maj_ver == 2 {
271 if isakmp_header.min_ver != 0 {
272 SCLogDebug!(
273 "ipsec_probe: could be ipsec, but with unsupported/invalid version {}.{}",
274 isakmp_header.maj_ver,
275 isakmp_header.min_ver
276 );
277 return false;
278 }
279 if isakmp_header.exch_type < 34 || isakmp_header.exch_type > 37 {
280 SCLogDebug!("ipsec_probe: could be ipsec, but with unsupported/invalid exchange type {}",
281 isakmp_header.exch_type);
282 return false;
283 }
284 if isakmp_header.length as usize != input.len() {
285 SCLogDebug!("ipsec_probe: could be ipsec, but length does not match");
286 return false;
287 }
288
289 if isakmp_header.resp_spi == 0 && direction != Direction::ToServer {
290 unsafe {
291 *rdir = Direction::ToServer.into();
292 }
293 }
294 return true;
295 }
296
297 return false;
298 }
299 Err(_) => return false,
300 }
301 }
302
303 // C exports.
304 export_tx_get_detect_state!(rs_ike_tx_get_detect_state, IKETransaction);
305 export_tx_set_detect_state!(rs_ike_tx_set_detect_state, IKETransaction);
306
307 /// C entry point for a probing parser.
308 #[no_mangle]
309 pub unsafe extern "C" fn rs_ike_probing_parser(
310 _flow: *const Flow, direction: u8, input: *const u8, input_len: u32, rdir: *mut u8,
311 ) -> AppProto {
312 if input_len < 28 {
313 // at least the ISAKMP_HEADER must be there, not ALPROTO_UNKNOWN because over UDP
314 return ALPROTO_FAILED;
315 }
316
317 if !input.is_null() {
318 let slice = build_slice!(input, input_len as usize);
319 if probe(slice, direction.into(), rdir) {
320 return ALPROTO_IKE;
321 }
322 }
323 return ALPROTO_FAILED;
324 }
325
326 #[no_mangle]
327 pub extern "C" fn rs_ike_state_new(
328 _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
329 ) -> *mut std::os::raw::c_void {
330 let state = IKEState::default();
331 let boxed = Box::new(state);
332 return Box::into_raw(boxed) as *mut _;
333 }
334
335 #[no_mangle]
336 pub unsafe extern "C" fn rs_ike_state_free(state: *mut std::os::raw::c_void) {
337 // Just unbox...
338 std::mem::drop(Box::from_raw(state as *mut IKEState));
339 }
340
341 #[no_mangle]
342 pub unsafe extern "C" fn rs_ike_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
343 let state = cast_pointer!(state, IKEState);
344 state.free_tx(tx_id);
345 }
346
347 #[no_mangle]
348 pub unsafe extern "C" fn rs_ike_parse_request(
349 _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
350 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
351 ) -> AppLayerResult {
352 let state = cast_pointer!(state, IKEState);
353 let buf = build_slice!(input, input_len as usize);
354
355 return state.handle_input(buf, Direction::ToServer);
356 }
357
358 #[no_mangle]
359 pub unsafe extern "C" fn rs_ike_parse_response(
360 _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
361 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
362 ) -> AppLayerResult {
363 let state = cast_pointer!(state, IKEState);
364 let buf = build_slice!(input, input_len as usize);
365 return state.handle_input(buf, Direction::ToClient);
366 }
367
368 #[no_mangle]
369 pub unsafe extern "C" fn rs_ike_state_get_tx(
370 state: *mut std::os::raw::c_void, tx_id: u64,
371 ) -> *mut std::os::raw::c_void {
372 let state = cast_pointer!(state, IKEState);
373 match state.get_tx(tx_id) {
374 Some(tx) => {
375 return tx as *const _ as *mut _;
376 }
377 None => {
378 return std::ptr::null_mut();
379 }
380 }
381 }
382
383 #[no_mangle]
384 pub unsafe extern "C" fn rs_ike_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
385 let state = cast_pointer!(state, IKEState);
386 return state.tx_id;
387 }
388
389 #[no_mangle]
390 pub extern "C" fn rs_ike_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int {
391 // This parser uses 1 to signal transaction completion status.
392 return 1;
393 }
394
395 #[no_mangle]
396 pub extern "C" fn rs_ike_tx_get_alstate_progress(
397 _tx: *mut std::os::raw::c_void, _direction: u8,
398 ) -> std::os::raw::c_int {
399 return 1;
400 }
401
402 #[no_mangle]
403 pub unsafe extern "C" fn rs_ike_tx_get_logged(
404 _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void,
405 ) -> u32 {
406 let tx = cast_pointer!(tx, IKETransaction);
407 return tx.logged.get();
408 }
409
410 #[no_mangle]
411 pub unsafe extern "C" fn rs_ike_tx_set_logged(
412 _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, logged: u32,
413 ) {
414 let tx = cast_pointer!(tx, IKETransaction);
415 tx.logged.set(logged);
416 }
417
418 #[no_mangle]
419 pub unsafe extern "C" fn rs_ike_state_get_events(
420 tx: *mut std::os::raw::c_void,
421 ) -> *mut core::AppLayerDecoderEvents {
422 let tx = cast_pointer!(tx, IKETransaction);
423 return tx.events;
424 }
425
426 static mut ALPROTO_IKE : AppProto = ALPROTO_UNKNOWN;
427
428 #[no_mangle]
429 pub unsafe extern "C" fn rs_ike_state_get_tx_iterator(
430 _ipproto: u8, _alproto: AppProto, state: *mut std::os::raw::c_void, min_tx_id: u64,
431 _max_tx_id: u64, istate: &mut u64,
432 ) -> applayer::AppLayerGetTxIterTuple {
433 let state = cast_pointer!(state, IKEState);
434 match state.tx_iterator(min_tx_id, istate) {
435 Some((tx, out_tx_id, has_next)) => {
436 let c_tx = tx as *const _ as *mut _;
437 let ires = applayer::AppLayerGetTxIterTuple::with_values(c_tx, out_tx_id, has_next);
438 return ires;
439 }
440 None => {
441 return applayer::AppLayerGetTxIterTuple::not_found();
442 }
443 }
444 }
445
446 // Parser name as a C style string.
447 const PARSER_NAME: &'static [u8] = b"ike\0";
448 const PARSER_ALIAS: &'static [u8] = b"ikev2\0";
449
450 export_tx_data_get!(rs_ike_get_tx_data, IKETransaction);
451
452 #[no_mangle]
453 pub unsafe extern "C" fn rs_ike_register_parser() {
454 let default_port = CString::new("500").unwrap();
455 let parser = RustParser {
456 name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
457 default_port : default_port.as_ptr(),
458 ipproto : core::IPPROTO_UDP,
459 probe_ts : Some(rs_ike_probing_parser),
460 probe_tc : Some(rs_ike_probing_parser),
461 min_depth : 0,
462 max_depth : 16,
463 state_new : rs_ike_state_new,
464 state_free : rs_ike_state_free,
465 tx_free : rs_ike_state_tx_free,
466 parse_ts : rs_ike_parse_request,
467 parse_tc : rs_ike_parse_response,
468 get_tx_count : rs_ike_state_get_tx_count,
469 get_tx : rs_ike_state_get_tx,
470 tx_comp_st_ts : 1,
471 tx_comp_st_tc : 1,
472 tx_get_progress : rs_ike_tx_get_alstate_progress,
473 get_de_state : rs_ike_tx_get_detect_state,
474 set_de_state : rs_ike_tx_set_detect_state,
475 get_events : Some(rs_ike_state_get_events),
476 get_eventinfo : Some(IkeEvent::get_event_info),
477 get_eventinfo_byid : Some(IkeEvent::get_event_info_by_id),
478 localstorage_new : None,
479 localstorage_free : None,
480 get_files : None,
481 get_tx_iterator : None,
482 get_tx_data : rs_ike_get_tx_data,
483 apply_tx_config : None,
484 flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS,
485 truncate : None,
486 };
487
488 let ip_proto_str = CString::new("udp").unwrap();
489
490 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
491 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
492 ALPROTO_IKE = alproto;
493 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
494 let _ = AppLayerRegisterParser(&parser, alproto);
495 }
496
497 AppLayerRegisterParserAlias(
498 PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
499 PARSER_ALIAS.as_ptr() as *const std::os::raw::c_char,
500 );
501 SCLogDebug!("Rust IKE parser registered.");
502 } else {
503 SCLogDebug!("Protocol detector and parser disabled for IKE.");
504 }
505 }