1use crate::applayer::*;
21use crate::direction::Direction;
22use crate::ike::ipsec_parser::*;
23
24use super::ipsec_parser::IkeV2Transform;
25use crate::ike::ike::{IKEState, IKETransaction, IkeEvent};
26use crate::ike::parser::IsakmpHeader;
27use ipsec_parser::{IkeExchangeType, IkePayloadType, IkeV2Header};
28
29#[derive(Clone, Debug, PartialEq, Eq)]
30#[repr(u8)]
31pub enum IKEV2ConnectionState {
32 Init,
33 InitSASent,
34 InitKESent,
35 InitNonceSent,
36 RespSASent,
37 RespKESent,
38
39 ParsingDone,
40
41 Invalid,
42}
43
44impl IKEV2ConnectionState {
45 pub fn advance(&self, payload: &IkeV2Payload) -> IKEV2ConnectionState {
46 use self::IKEV2ConnectionState::*;
47 match (self, &payload.content) {
48 (&Init, &IkeV2PayloadContent::SA(_)) => InitSASent,
49 (&InitSASent, &IkeV2PayloadContent::KE(_)) => InitKESent,
50 (&InitKESent, &IkeV2PayloadContent::Nonce(_)) => InitNonceSent,
51 (&InitNonceSent, &IkeV2PayloadContent::SA(_)) => RespSASent,
52 (&RespSASent, &IkeV2PayloadContent::KE(_)) => RespKESent,
53 (&RespKESent, &IkeV2PayloadContent::Nonce(_)) => ParsingDone, (&ParsingDone, _) => self.clone(),
55 (_, &IkeV2PayloadContent::Notify(_)) => self.clone(),
56 (_, &IkeV2PayloadContent::Dummy) => self.clone(),
57 (_, _) => Invalid,
58 }
59 }
60}
61
62pub struct Ikev2Container {
63 pub connection_state: IKEV2ConnectionState,
65
66 pub client_transforms: Vec<Vec<IkeV2Transform>>,
68
69 pub alg_enc: IkeTransformEncType,
71 pub alg_auth: IkeTransformAuthType,
73 pub alg_prf: IkeTransformPRFType,
75 pub alg_dh: IkeTransformDHType,
77 pub alg_esn: IkeTransformESNType,
79 pub dh_group: IkeTransformDHType,
81}
82
83impl Default for Ikev2Container {
84 fn default() -> Ikev2Container {
85 Ikev2Container {
86 connection_state: IKEV2ConnectionState::Init,
87 dh_group: IkeTransformDHType::None,
88 client_transforms: Vec::new(),
89 alg_enc: IkeTransformEncType::ENCR_NULL,
90 alg_auth: IkeTransformAuthType::NONE,
91 alg_prf: IkeTransformPRFType::PRF_NULL,
92 alg_dh: IkeTransformDHType::None,
93 alg_esn: IkeTransformESNType::NoESN,
94 }
95 }
96}
97
98pub fn handle_ikev2(
99 state: &mut IKEState, current: &[u8], isakmp_header: IsakmpHeader, direction: Direction,
100) -> AppLayerResult {
101 let hdr = IkeV2Header {
102 init_spi: isakmp_header.init_spi,
103 resp_spi: isakmp_header.resp_spi,
104 next_payload: IkePayloadType(isakmp_header.next_payload),
105 maj_ver: isakmp_header.maj_ver,
106 min_ver: isakmp_header.min_ver,
107 exch_type: IkeExchangeType(isakmp_header.exch_type),
108 flags: isakmp_header.flags,
109 msg_id: isakmp_header.msg_id,
110 length: isakmp_header.length,
111 };
112
113 let mut tx = state.new_tx(direction);
114 tx.ike_version = 2;
115 tx.hdr.ikev2_header = hdr.clone();
118 tx.hdr.spi_initiator = format!("{:016x}", isakmp_header.init_spi);
119 tx.hdr.spi_responder = format!("{:016x}", isakmp_header.resp_spi);
120 tx.hdr.maj_ver = isakmp_header.maj_ver;
121 tx.hdr.min_ver = isakmp_header.min_ver;
122 tx.hdr.msg_id = isakmp_header.msg_id;
123 tx.hdr.flags = isakmp_header.flags;
124 let mut payload_types = Vec::new();
125 let mut errors = 0;
126 let mut notify_types = Vec::new();
127 match parse_ikev2_payload_list(current, hdr.next_payload) {
128 Ok((_, Ok(ref p))) => {
129 for payload in p {
130 payload_types.push(payload.hdr.next_payload_type);
131 match payload.content {
132 IkeV2PayloadContent::Dummy => (),
133 IkeV2PayloadContent::SA(ref prop) => {
134 add_proposals(state, &mut tx, prop, direction);
136 }
138 IkeV2PayloadContent::KE(ref kex) => {
139 SCLogDebug!("KEX {:?}", kex.dh_group);
140 if direction == Direction::ToClient {
141 state.ikev2_container.dh_group = kex.dh_group;
142 }
143 }
144 IkeV2PayloadContent::Nonce(ref _n) => {
145 SCLogDebug!("Nonce: {:?}", _n);
146 }
147 IkeV2PayloadContent::Notify(ref n) => {
148 SCLogDebug!("Notify: {:?}", n);
149 if n.notify_type.is_error() {
150 errors += 1;
151 }
152 notify_types.push(n.notify_type);
153 }
154 _ => {
161 SCLogDebug!("Unknown payload content {:?}", payload.content);
162 }
163 }
164 state.ikev2_container.connection_state =
165 state.ikev2_container.connection_state.advance(payload);
166 tx.payload_types
167 .ikev2_payload_types
168 .append(&mut payload_types);
169 tx.errors = errors;
170 tx.notify_types.append(&mut notify_types);
171 }
172 }
173 _e => {
174 SCLogDebug!("parse_ikev2_payload_with_type: {:?}", _e);
175 }
176 }
177 state.transactions.push(tx);
178 return AppLayerResult::ok();
179}
180
181fn add_proposals(
182 state: &mut IKEState, tx: &mut IKETransaction, prop: &Vec<IkeV2Proposal>, direction: Direction,
183) {
184 for p in prop {
185 let transforms: Vec<IkeV2Transform> = p.transforms.iter().map(|x| x.into()).collect();
186 for xform in &transforms {
188 match *xform {
189 IkeV2Transform::Encryption(
190 IkeTransformEncType::ENCR_DES_IV64
191 | IkeTransformEncType::ENCR_DES
192 | IkeTransformEncType::ENCR_3DES
193 | IkeTransformEncType::ENCR_RC5
194 | IkeTransformEncType::ENCR_IDEA
195 | IkeTransformEncType::ENCR_CAST
196 | IkeTransformEncType::ENCR_BLOWFISH
197 | IkeTransformEncType::ENCR_3IDEA
198 | IkeTransformEncType::ENCR_DES_IV32
199 | IkeTransformEncType::ENCR_NULL,
200 ) => {
201 tx.set_event(IkeEvent::WeakCryptoEnc);
203 }
204 IkeV2Transform::PRF(ref prf) => match *prf {
205 IkeTransformPRFType::PRF_NULL => {
206 SCLogDebug!("'Null' PRF transform proposed");
207 tx.set_event(IkeEvent::InvalidProposal);
208 }
209 IkeTransformPRFType::PRF_HMAC_MD5 | IkeTransformPRFType::PRF_HMAC_SHA1 => {
210 SCLogDebug!("Weak PRF: {:?}", prf);
211 tx.set_event(IkeEvent::WeakCryptoPrf);
212 }
213 _ => (),
214 },
215 IkeV2Transform::Auth(ref auth) => {
216 match *auth {
217 IkeTransformAuthType::NONE => {
218 }
221 IkeTransformAuthType::AUTH_HMAC_MD5_96
222 | IkeTransformAuthType::AUTH_HMAC_SHA1_96
223 | IkeTransformAuthType::AUTH_DES_MAC
224 | IkeTransformAuthType::AUTH_KPDK_MD5
225 | IkeTransformAuthType::AUTH_AES_XCBC_96
226 | IkeTransformAuthType::AUTH_HMAC_MD5_128
227 | IkeTransformAuthType::AUTH_HMAC_SHA1_160 => {
228 SCLogDebug!("Weak auth: {:?}", auth);
229 tx.set_event(IkeEvent::WeakCryptoAuth);
230 }
231 _ => (),
232 }
233 }
234 IkeV2Transform::DH(ref dh) => match *dh {
235 IkeTransformDHType::None => {
236 SCLogDebug!("'None' DH transform proposed");
237 tx.set_event(IkeEvent::InvalidProposal);
238 }
239 IkeTransformDHType::Modp768
240 | IkeTransformDHType::Modp1024
241 | IkeTransformDHType::Modp1024s160
242 | IkeTransformDHType::Modp1536 => {
243 SCLogDebug!("Weak DH: {:?}", dh);
244 tx.set_event(IkeEvent::WeakCryptoDh);
245 }
246 _ => (),
247 },
248 IkeV2Transform::Unknown(_tx_type, _tx_id) => {
249 SCLogDebug!("Unknown proposal: type={:?}, id={}", _tx_type, _tx_id);
250 tx.set_event(IkeEvent::UnknownProposal);
251 }
252 _ => (),
253 }
254 }
255 if !transforms.iter().any(|x| match *x {
257 IkeV2Transform::DH(_) => true,
258 _ => false,
259 }) {
260 SCLogDebug!("No DH transform found");
261 tx.set_event(IkeEvent::WeakCryptoNoDh);
262 }
263 if p.protocol_id == ProtocolID::AH {
265 SCLogDebug!("Proposal uses protocol AH - no confidentiality");
266 tx.set_event(IkeEvent::NoEncryption);
267 }
268 if !transforms.iter().any(|x| match *x {
271 IkeV2Transform::Auth(IkeTransformAuthType::NONE) => false,
272 IkeV2Transform::Auth(_) => true,
273 _ => false,
274 }) && !transforms.iter().any(|x| match *x {
275 IkeV2Transform::Encryption(ref enc) => enc.is_aead(),
276 _ => false,
277 }) {
278 SCLogDebug!("No integrity transform found");
279 tx.set_event(IkeEvent::WeakCryptoNoAuth);
280 }
281 if direction == Direction::ToClient {
283 transforms.iter().for_each(|t| match *t {
284 IkeV2Transform::Encryption(ref e) => {
285 state.ikev2_container.alg_enc = *e;
286 tx.hdr.ikev2_transforms.push(IkeV2Transform::Encryption(*e));
287 }
288 IkeV2Transform::Auth(ref a) => {
289 state.ikev2_container.alg_auth = *a;
290 tx.hdr.ikev2_transforms.push(IkeV2Transform::Auth(*a));
291 }
292 IkeV2Transform::PRF(ref p) => {
293 state.ikev2_container.alg_prf = *p;
294 tx.hdr.ikev2_transforms.push(IkeV2Transform::PRF(*p));
295 }
296 IkeV2Transform::DH(ref dh) => {
297 state.ikev2_container.alg_dh = *dh;
298 tx.hdr.ikev2_transforms.push(IkeV2Transform::DH(*dh));
299 }
300 IkeV2Transform::ESN(ref e) => {
301 state.ikev2_container.alg_esn = *e;
302 tx.hdr.ikev2_transforms.push(IkeV2Transform::ESN(*e));
303 }
304 _ => {}
305 });
306 SCLogDebug!("Selected transforms: {:?}", transforms);
307 } else {
308 SCLogDebug!("Proposed transforms: {:?}", transforms);
309 state.ikev2_container.client_transforms.push(transforms);
310 }
311 }
312}