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