sawp_ike/
lib.rs

1//! An Internet Key Exchange (IKE) v1 and v2 parser.
2//!
3//! Given bytes and a [`sawp::parser::Direction`], it will attempt to parse the bytes
4//! and return a [`Message`]. The parser will inform the caller about errors if no
5//! message is returned and warnings if it was parsed but had nonstandard or erroneous
6//! data (see [`sawp::parser::Parse`] for details on possible return types).
7//!
8//! This parser keeps state for the current session so it is expected to create one
9//! parser per session.
10//!
11//! The following references were used to create this module:
12//!
13//! [ISAKMP](https://www.rfc-editor.org/rfc/rfc2408.html)
14//!
15//! [IKE v1](https://www.rfc-editor.org/rfc/rfc2409.html)
16//!
17//! [IKE v2 Fibre Channel](https://www.rfc-editor.org/rfc/rfc4595.html)
18//!
19//! [IKE v2](https://www.rfc-editor.org/rfc/rfc7296.html)
20//!
21//! [Group Key Management using IKEv2](https://datatracker.ietf.org/doc/draft-yeung-g-ikev2)
22//!
23//! # Example
24//! ```
25//! use sawp::parser::{Direction, Parse};
26//! use sawp::error::Error;
27//! use sawp::error::ErrorKind;
28//! use sawp_ike::{Ike, Message};
29//!
30//! fn parse_bytes(input: &[u8]) -> std::result::Result<&[u8], Error> {
31//!     let ike = Ike::default();
32//!     let mut bytes = input;
33//!     while bytes.len() > 0 {
34//!         // If we know that this is a request or response, change the Direction
35//!         // for a more accurate parsing
36//!         match ike.parse(bytes, Direction::Unknown) {
37//!             // The parser succeeded and returned the remaining bytes and the parsed ike message
38//!             Ok((rest, Some(message))) => {
39//!                 println!("IKE message: {:?}", message);
40//!                 bytes = rest;
41//!             }
42//!             // The parser recognized that this might be ike and made some progress,
43//!             // but more bytes are needed to parse a full message
44//!             Ok((rest, None)) => return Ok(rest),
45//!             // The parser was unable to determine whether this was ike or not and more
46//!             // bytes are needed
47//!             Err(Error { kind: ErrorKind::Incomplete(_) }) => return Ok(bytes),
48//!             // The parser determined that this was not ike
49//!             Err(e) => return Err(e)
50//!         }
51//!     }
52//!
53//!     Ok(bytes)
54//! }
55//! ```
56
57#![deny(clippy::integer_arithmetic)]
58
59pub mod header;
60pub mod payloads;
61
62use header::{Header, IkeFlags, HEADER_LEN};
63use payloads::{Payload, PayloadType};
64
65use sawp::error::Result;
66use sawp::parser::{Direction, Parse};
67use sawp::probe::Probe;
68use sawp::protocol::Protocol;
69use sawp_flags::{BitFlags, Flag, Flags};
70
71/// FFI structs and Accessors
72#[cfg(feature = "ffi")]
73mod ffi;
74
75#[cfg(feature = "ffi")]
76use sawp_ffi::GenerateFFI;
77
78use nom::bytes::streaming::{tag, take};
79use nom::combinator::opt;
80use nom::number::streaming::be_u32;
81use nom::sequence::tuple;
82
83type IResult<'a, O> = nom::IResult<&'a [u8], O, sawp::error::NomError<&'a [u8]>>;
84
85/// Classes of errors that can be returned by this parser.
86#[repr(u16)]
87#[derive(Clone, Copy, Debug, PartialEq, Eq, BitFlags)]
88pub enum ErrorFlags {
89    /// Unknown Exchange number
90    UnknownExchange = 0b0000_0000_0000_0001,
91    /// Unknown Payload number
92    UnknownPayload = 0b0000_0000_0000_0010,
93    /// Found a payload in an invalid location
94    InvalidPayload = 0b0000_0000_0000_0100,
95    /// Known payload found which we have no parser for
96    UnimplementedPayload = 0b0000_0000_0000_1000,
97    /// Message ID was nonzero in an initiation message
98    NonZeroMessageIdInInit = 0b0000_0000_0001_0000,
99    /// Responder SPI was nonzero in an initiation message
100    NonZeroResponderSpiInInit = 0b0000_0000_0010_0000,
101    /// Responder SPI was not set in a response message
102    ZeroResponderSpiInResponse = 0b0000_0000_0100_0000,
103    /// Non-Zero reserved field found
104    NonZeroReserved = 0b0000_0000_1000_0000,
105    /// Invalid length in a payload
106    ///
107    /// Typically indicative of a length which is too short to accomodate the generic payload
108    /// header
109    InvalidLength = 0b0000_0001_0000_0000,
110    /// Header flags were invalid.
111    ///
112    /// Either a nonexistant flag bit was set or both IKEv1 and IKEv2 flags were set at the same
113    /// time.
114    InvalidFlags = 0b0000_0010_0000_0000,
115}
116
117impl ErrorFlags {
118    fn flatten(input: &[Flags<Self, u16>]) -> Flags<Self, u16> {
119        input.iter().fold(Self::none(), |acc, e| acc | *e)
120    }
121}
122
123/// The parsed message.
124///
125/// [`Message::Ike`] is a parsed IKE v1 or v2 message.
126///
127/// [`Message::Esp`] is an encapsulated security payload. These are seen when the
128/// encrypted communications are sent over UDP on the same 5-tuple as the IKE messages, typically on port 4500.
129/// When IKE operates over TCP, no ESP will be parsed as they encrypted data is sent without a
130/// transport layer (i.e. layer 3 Ethernet header followed by encrypted payload).
131#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
132#[cfg_attr(feature = "ffi", sawp_ffi(prefix = "sawp_ike"))]
133#[derive(Debug, PartialEq, Eq)]
134pub enum Message {
135    /// An IKE payload
136    Ike(IkeMessage),
137    /// Encapsulating Security Payload
138    Esp(EspMessage),
139}
140
141/// The parsed IKEv1 or v2 message
142#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
143#[cfg_attr(feature = "ffi", sawp_ffi(prefix = "sawp_ike"))]
144#[derive(Debug, PartialEq, Eq)]
145pub struct IkeMessage {
146    /// The header
147    pub header: Header,
148    /// The array of payloads following the header
149    pub payloads: Vec<Payload>,
150    /// Encrypted Data, if IKEv1 and ENCRYPTED flag is set
151    pub encrypted_data: Vec<u8>,
152    /// Errors encountered while parsing
153    #[cfg_attr(feature = "ffi", sawp_ffi(flag = "u16"))]
154    pub error_flags: Flags<ErrorFlags>,
155}
156
157/// If UDP encapsulation is present, the metadata associated with it is parsed.
158///
159/// The full encrypted payload, tail padding, and integrity check is not parsed.
160#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
161#[cfg_attr(feature = "ffi", sawp_ffi(prefix = "sawp_ike"))]
162#[derive(Debug, PartialEq, Eq)]
163pub struct EspMessage {
164    pub spi: u32,
165    pub sequence: u32,
166}
167
168/// Parser handle.
169///
170/// # Notes
171/// The parser assumes one parser per session as it stores session state. A given session should
172/// re-use the same parser as more data is made available and each session should have its own
173/// parser.
174///
175/// # FFI SAFETY
176/// This type is not [`Sync`] and this must be considered in FFI uses. This struct may be sent from
177/// one thread to another but it may not be shared between threads without locking access. In C++
178/// this means a std::shared_ptr<Ike> is not enough! std::mutex or other locking primitives must be
179/// used to ensure data races do not occur.
180#[derive(Debug, Default)]
181pub struct Ike {
182    // On port 4500 ESP payloads are encapsulated in UDP but on port 500 they are not.
183    // When UDP encapsulation for ESP is present IKE payloads are prefixed with 4 octets
184    // 0x00 to differentiate them from ESP.
185    //
186    // When an IKE payload was prefixed with 0x00 we should treat any seen packets without
187    // it as ESP payloads. When IKE was not prefixed with 0x00 then all packets should
188    // be IKE. As such we have 3 states - ESP encapsulation present (Some(true)), ESP
189    // encapsulation not present (Some(false)), and not yet determined (None).
190    saw_udp_encapsulation: std::cell::Cell<Option<bool>>,
191}
192
193impl Probe<'_> for Ike {}
194
195impl Protocol<'_> for Ike {
196    type Message = Message;
197
198    fn name() -> &'static str {
199        "ike"
200    }
201}
202
203impl<'a> Parse<'a> for Ike {
204    fn parse(
205        &self,
206        input: &'a [u8],
207        _direction: Direction,
208    ) -> Result<(&'a [u8], Option<Self::Message>)> {
209        let input = match self.saw_udp_encapsulation.get() {
210            // Previously saw encapsulation
211            Some(true) => {
212                let (input, non_esp_marker) = opt(tag(b"\x00\x00\x00\x00"))(input)?;
213                if non_esp_marker.is_some() {
214                    // marker present, must be IKE. Continue
215                    input
216                } else {
217                    let (input, (spi, sequence)) = tuple((be_u32, be_u32))(input)?;
218                    return Ok((input, Some(Message::Esp(EspMessage { spi, sequence }))));
219                }
220            }
221            // Previously saw no encapsulation
222            Some(false) => {
223                // Parse like normal
224                input
225            }
226            // Not yet determined
227            None => {
228                let (input, non_esp_marker) = opt(tag(b"\x00\x00\x00\x00"))(input)?;
229                self.saw_udp_encapsulation
230                    .set(Some(non_esp_marker.is_some()));
231                input
232            }
233        };
234
235        let (input, (header, header_error_flags)) = Header::parse(input)?;
236
237        // subtracting HEADER_LEN is safe, length verified in Header::parse
238        let (input, mut payload_input) = take(header.length.saturating_sub(HEADER_LEN))(input)?;
239
240        let mut next_payload = header.next_payload;
241        let mut payloads = Vec::new();
242        let mut payload_error_flags = ErrorFlags::none();
243
244        if header.major_version == 1 && header.flags.contains(IkeFlags::ENCRYPTED) {
245            let message = Message::Ike(IkeMessage {
246                header,
247                payloads: Vec::new(),
248                encrypted_data: payload_input.to_vec(),
249                error_flags: ErrorFlags::none(),
250            });
251            return Ok((input, Some(message)));
252        }
253
254        let parse = if header.major_version == 1 {
255            Payload::parse_v1
256        } else {
257            Payload::parse_v2
258        };
259
260        // While we have a next payload and they are not encrypted
261        // In the case of encryption, all the payloads are encrypted and
262        // are inside the encrypted data block.
263        while next_payload != PayloadType::NoNextPayload {
264            let should_early_break = next_payload == PayloadType::EncryptedAndAuthenticated
265                || next_payload == PayloadType::EncryptedAndAuthenticatedFragment;
266            let (tmp_payload_input, (payload, errors)) = parse(payload_input, next_payload)?;
267            // We need _payload_input as an interim variable until de structuring assignments are
268            // supported in our MSRV rust version
269            payload_input = tmp_payload_input;
270            next_payload = payload.next_payload;
271            payloads.push(payload);
272            payload_error_flags |= errors;
273
274            if should_early_break {
275                break;
276            }
277        }
278
279        let error_flags = header_error_flags | payload_error_flags;
280
281        let message = Message::Ike(IkeMessage {
282            header,
283            payloads,
284            encrypted_data: Vec::with_capacity(0),
285            error_flags,
286        });
287
288        Ok((input, Some(message)))
289    }
290}