1use super::Element;
6use crate::ProtectionInfo;
7use bitfield::bitfield;
8use nom::bytes::streaming::take;
9use nom::combinator::{eof, map};
10use nom::error::{Error, ErrorKind};
11use nom::number::streaming::{le_u16, le_u8};
12use nom::sequence::terminated;
13use nom::{IResult, Parser};
14use wlan_common::append::{BufferTooSmall, TrackedAppend, VecCursor};
15use wlan_common::ie::{wpa, write_wpa1_ie};
16use wlan_common::organization::Oui;
17
18pub const TYPE: u8 = 0xDD;
19const PADDING_DATA_LEN: u8 = 0;
20const HDR_LEN: usize = 6;
21const HDR_OUI_TYPE_LEN: usize = 4;
23
24const GTK_DATA_TYPE: u8 = 1;
26const IGTK_DATA_TYPE: u8 = 9;
27
28const GTK_FIXED_LEN: usize = 2;
31
32const IGTK_IPN_LEN: usize = 6;
33const IGTK_FIXED_LEN: usize = 2 + IGTK_IPN_LEN;
34
35#[derive(Default, Debug, PartialEq)]
37pub struct Header {
38 pub type_: u8,
39 pub len: u8,
40 pub oui: Oui,
41 pub data_type: u8,
42}
43
44impl Header {
45 pub fn new(type_: u8, len: u8, oui: &[u8], data_type: u8) -> Header {
46 let mut oui_buf = [0u8; 3];
47 oui_buf.copy_from_slice(oui);
48 Header { type_, len, data_type, oui: Oui::new(oui_buf), ..Default::default() }
49 }
50
51 pub fn new_dot11(data_type: u8, data_len: usize) -> Header {
52 Header { type_: TYPE, len: (HDR_OUI_TYPE_LEN + data_len) as u8, data_type, oui: Oui::DOT11 }
53 }
54
55 fn data_len(&self) -> usize {
56 if self.len < 4 {
57 0
58 } else {
59 (self.len as usize) - 4
60 }
61 }
62}
63
64pub enum GtkInfoTx {
66 _OnlyRx = 0,
67 BothRxTx = 1,
68}
69
70bitfield! {
72 pub struct GtkInfo(u8);
73 impl Debug;
74 pub key_id, set_key_id: 1, 0;
75 pub tx, set_tx: 2, 2;
76 pub value, _: 7,0;
78}
79
80impl PartialEq for GtkInfo {
81 fn eq(&self, other: &Self) -> bool {
82 self.0 == other.0
83 }
84}
85
86#[derive(Debug, PartialEq)]
89pub struct Gtk {
90 pub info: GtkInfo,
91 pub gtk: Box<[u8]>,
93}
94
95impl Gtk {
96 pub fn new(key_id: u8, tx: GtkInfoTx, gtk: &[u8]) -> Self {
97 let mut gtk_info = GtkInfo(0);
98 gtk_info.set_key_id(key_id);
99 gtk_info.set_tx(tx as u8);
100 Self { info: gtk_info, gtk: gtk.into() }
101 }
102
103 pub fn len(&self) -> usize {
105 GTK_FIXED_LEN + self.gtk.len()
106 }
107}
108
109#[derive(Debug, PartialEq)]
112pub struct Igtk {
113 pub id: u16,
114 pub ipn: [u8; IGTK_IPN_LEN],
116 pub igtk: Vec<u8>,
117}
118
119impl Igtk {
120 pub fn new(id: u16, ipn: &[u8], igtk: &[u8]) -> Self {
121 let mut ipn_buf = [0u8; IGTK_IPN_LEN];
122 ipn_buf.copy_from_slice(ipn);
123 Self { id, ipn: ipn_buf, igtk: igtk.to_vec() }
124 }
125
126 pub fn len(&self) -> usize {
127 IGTK_FIXED_LEN + self.igtk.len()
128 }
129}
130
131pub fn parse(i0: &[u8]) -> IResult<&[u8], Element> {
132 if i0.len() <= 1 {
134 return Ok((&i0[i0.len()..], Element::Padding));
135 }
136
137 let data_len = i0[1];
139 if data_len == PADDING_DATA_LEN {
140 return parse_padding(&i0[1..]);
141 }
142
143 let (i1, hdr) = parse_header(i0)?;
145 let (i2, bytes) = take(hdr.data_len()).parse(i1)?;
146 match hdr.oui {
147 Oui::DOT11 => match hdr.data_type {
148 GTK_DATA_TYPE => {
149 let (_, gtk) = parse_gtk(hdr.data_len()).parse(bytes)?;
150 Ok((i2, Element::Gtk(hdr, gtk)))
151 }
152 IGTK_DATA_TYPE => {
153 let (_, gtk) = parse_igtk(hdr.data_len()).parse(bytes)?;
154 Ok((i2, Element::Igtk(hdr, gtk)))
155 }
156 _ => Ok((i2, Element::UnsupportedKde(hdr))),
157 },
158 Oui::MSFT if hdr.data_type == wpa::VENDOR_SPECIFIC_TYPE => {
161 let (_, wpa) = wpa::from_bytes(&bytes[..])?;
162 Ok((i2, Element::LegacyWpa1(wpa)))
163 }
164 _ => Ok((i2, Element::UnsupportedKde(hdr))),
165 }
166}
167
168fn parse_header(input: &[u8]) -> IResult<&[u8], Header> {
169 map((le_u8, le_u8, take(3usize), le_u8), |(header_type, length, oui, data_type)| {
170 Header::new(header_type, length, oui, data_type)
171 })
172 .parse(input)
173}
174
175fn parse_padding(input: &[u8]) -> IResult<&[u8], Element> {
176 if input.iter().all(|&x| x == 0) {
177 Ok((&[], Element::Padding))
178 } else {
179 Err(nom::Err::Error(Error::new(input, ErrorKind::Eof)))
182 }
183}
184
185fn parse_gtk<'a>(data_len: usize) -> impl Parser<&'a [u8], Output = Gtk, Error = Error<&'a [u8]>> {
186 map(
187 terminated(
188 (
189 map(le_u8::<&'a [u8], Error<_>>, GtkInfo),
190 take(1usize),
191 take(data_len - 2),
192 ),
193 eof,
194 ),
195 |(info, _reserved, gtk)| Gtk { info, gtk: Vec::from(gtk).into_boxed_slice() },
196 )
197}
198
199fn parse_igtk<'a>(
200 data_len: usize,
201) -> impl Parser<&'a [u8], Output = Igtk, Error = Error<&'a [u8]>> {
202 map(
203 terminated(
204 (le_u16::<&'a [u8], Error<_>>, take(IGTK_IPN_LEN), take(data_len - IGTK_FIXED_LEN)),
205 eof,
206 ),
207 |(id, ipn, igtk)| Igtk::new(id, ipn, igtk),
208 )
209}
210
211pub struct Writer<A> {
213 buf: A,
214}
215
216impl Writer<VecCursor> {
217 pub fn new() -> Self {
218 Self { buf: VecCursor::new() }
219 }
220}
221
222impl<A: TrackedAppend> Writer<A> {
223 #[cfg(test)]
224 pub fn new_with(buf: A) -> Self {
225 Self { buf }
226 }
227
228 pub fn write_protection(&mut self, protection: &ProtectionInfo) -> Result<(), BufferTooSmall> {
229 match protection {
230 ProtectionInfo::Rsne(rsne) => rsne.write_into(&mut self.buf),
231 ProtectionInfo::LegacyWpa(wpa) => write_wpa1_ie(&mut self.buf, wpa),
232 }
233 }
234
235 fn write_kde_hdr(&mut self, hdr: Header) -> Result<(), BufferTooSmall> {
236 if !self.buf.can_append(HDR_LEN) {
237 return Err(BufferTooSmall);
238 }
239 self.buf.append_byte(hdr.type_)?;
240 self.buf.append_byte(hdr.len)?;
241 self.buf.append_bytes(&hdr.oui[..])?;
242 self.buf.append_byte(hdr.data_type)?;
243 Ok(())
244 }
245
246 pub fn write_gtk(&mut self, gtk_kde: &Gtk) -> Result<(), BufferTooSmall> {
247 if !self.buf.can_append(HDR_LEN + gtk_kde.len()) {
248 return Err(BufferTooSmall);
249 }
250 let hdr = Header::new_dot11(GTK_DATA_TYPE, gtk_kde.len());
252 self.write_kde_hdr(hdr)?;
253
254 self.buf.append_byte(gtk_kde.info.value())?;
256 self.buf.append_byte(0)?;
257 self.buf.append_bytes(>k_kde.gtk[..])?;
258 Ok(())
259 }
260
261 pub fn write_igtk(&mut self, igtk_kde: &Igtk) -> Result<(), BufferTooSmall> {
262 if !self.buf.can_append(HDR_LEN + igtk_kde.len()) {
263 return Err(BufferTooSmall);
264 }
265 let hdr = Header::new_dot11(IGTK_DATA_TYPE, igtk_kde.len());
267 self.write_kde_hdr(hdr)?;
268
269 self.buf.append_bytes(&igtk_kde.id.to_le_bytes())?;
271 self.buf.append_bytes(&igtk_kde.ipn[..])?;
272 self.buf.append_bytes(&igtk_kde.igtk[..])?;
273 Ok(())
274 }
275
276 pub fn finalize_for_encryption(mut self) -> Result<A, BufferTooSmall> {
277 let written = self.buf.bytes_appended();
282 let padding_len =
283 if written < 16 { 16 - written } else { ((written + 7) / 8) * 8 - written };
284 if !self.buf.can_append(padding_len) {
285 return Err(BufferTooSmall);
286 }
287
288 if padding_len != 0 {
289 self.buf.append_byte(TYPE)?;
290 self.buf.append_bytes_zeroed(padding_len - 1)?;
291 }
292 Ok(self.buf)
293 }
294
295 pub fn finalize_for_plaintext(self) -> Result<A, BufferTooSmall> {
296 Ok(self.buf)
297 }
298}
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303 use crate::key_data::extract_elements;
304 use wlan_common::assert_variant;
305 use wlan_common::test_utils::FixedSizedTestBuffer;
306
307 fn write_and_extract_padding(gtk_len: usize) -> Vec<u8> {
308 let mut w = Writer::new();
309 w.write_gtk(&Gtk::new(2, GtkInfoTx::BothRxTx, &vec![2; gtk_len]))
310 .expect("failure writing GTK KDE");
311 w.finalize_for_encryption()
312 .expect("failure finializing key data")
313 .into_vec()
314 .split_off(HDR_LEN + GTK_FIXED_LEN + gtk_len)
315 }
316
317 #[test]
318 fn test_padding_min_length() {
319 let buf = write_and_extract_padding(0);
320 assert_eq!(buf, vec![TYPE, 0, 0, 0, 0, 0, 0, 0]);
321
322 let buf = write_and_extract_padding(5);
323 assert_eq!(buf, vec![TYPE, 0, 0]);
324
325 let buf = write_and_extract_padding(7);
326 assert_eq!(buf, vec![TYPE]);
327 }
328
329 #[test]
330 fn test_no_padding_expected_for_plaintext() {
331 let mut w = Writer::new();
332 w.write_gtk(&Gtk::new(2, GtkInfoTx::BothRxTx, &[2; 2])).expect("failure writing GTK KDE");
333 let buf = w.finalize_for_plaintext().expect("failure finalizing key data");
334 assert_eq!(
335 &buf[..],
336 &[
337 TYPE,
339 8,
340 0x00,
341 0x0F,
342 0xAC,
343 GTK_DATA_TYPE,
344 0b0000_0110,
345 0,
346 2,
347 2
348 ][..]
349 );
350 }
351
352 #[test]
353 fn test_no_padding() {
354 let buf = write_and_extract_padding(8);
355 assert_eq!(buf, vec![]);
356 }
357
358 #[test]
359 fn test_padding_multiple_8() {
360 let buf = write_and_extract_padding(9);
361 assert_eq!(buf, vec![TYPE, 0, 0, 0, 0, 0, 0]);
362
363 let buf = write_and_extract_padding(16);
364 assert_eq!(buf, vec![]);
365 }
366
367 #[test]
368 fn test_write_read_gtk_with_padding() {
369 let mut w = Writer::new();
371 w.write_gtk(&Gtk::new(2, GtkInfoTx::BothRxTx, &[24; 5])).expect("failure writing GTK KDE");
372 let buf = w.finalize_for_encryption().expect("failure finializing key data");
373 #[rustfmt::skip]
374 assert_eq!(&buf[..], &[
375 TYPE, 11, 0x00, 0x0F, 0xAC, GTK_DATA_TYPE, 0b0000_0110, 0, 24, 24, 24, 24, 24,
377 TYPE, 0, 0,
379 ][..]);
380
381 let result = extract_elements(&buf[..]);
383 assert!(result.is_ok(), "Error: {:?}", result);
384 let mut elements = result.unwrap();
385 assert_eq!(elements.len(), 2);
386
387 assert_variant!(elements.remove(0), Element::Gtk(hdr, kde) => {
388 assert_eq!(hdr, Header { type_: 0xDD, len: 11, oui: Oui::DOT11, data_type: 1 });
389 assert_eq!(kde, Gtk { info: GtkInfo(6), gtk: Box::new([24; 5]) });
390 });
391 assert_variant!(elements.remove(0), Element::Padding);
392 }
393
394 #[test]
395 fn test_write_read_igtk() {
396 let igtk = Igtk::new(10, &[11; 6], &[22; 2]);
397 let mut w = Writer::new();
399 w.write_igtk(&igtk).expect("failure writing IGTK KDE");
400 let buf = w.finalize_for_encryption().expect("failure finializing key data");
401 #[rustfmt::skip]
402 assert_eq!(&buf[..], &[
403 TYPE, 14, 0x00, 0x0F, 0xAC, IGTK_DATA_TYPE, 10, 0, 11,11,11,11,11,11,22,22
404 ][..]);
405
406 let result = extract_elements(&buf[..]);
408 assert!(result.is_ok(), "Error: {:?}", result);
409 let mut elements = result.unwrap();
410 assert_eq!(elements.len(), 1);
411
412 assert_variant!(elements.remove(0), Element::Igtk(hdr, kde) => {
413 assert_eq!(hdr, Header {
414 type_: 0xDD, len: 14, oui: Oui::DOT11, data_type: IGTK_DATA_TYPE
415 });
416 assert_eq!(kde, igtk);
417 });
418 }
419
420 #[test]
421 fn test_write_gtk_too_small_buffer() {
422 Writer::new_with(FixedSizedTestBuffer::new(10))
423 .write_gtk(&Gtk::new(2, GtkInfoTx::BothRxTx, &[24; 5]))
424 .expect_err("expected failure writing GTK KDE");
425 }
426
427 #[test]
428 fn test_write_gtk_sufficient_fixed_buffer() {
429 Writer::new_with(FixedSizedTestBuffer::new(13))
430 .write_gtk(&Gtk::new(2, GtkInfoTx::BothRxTx, &[24; 5]))
431 .expect("expected success writing GTK KDE");
432 }
433
434 #[test]
435 fn test_create_gtk_element() {
436 let gtk = Gtk::new(1, GtkInfoTx::_OnlyRx, &[24; 16][..]);
437 assert_eq!(gtk.info.key_id(), 1);
438 assert_eq!(gtk.info.tx(), 0);
439 assert_eq!(>k.gtk[..], &[24; 16][..]);
440 }
441
442 #[test]
443 fn test_gtk_len() {
444 let gtk_kde = Gtk { info: GtkInfo(0), gtk: Box::new([]) };
445 assert_eq!(gtk_kde.len(), 2);
446
447 let gtk_kde = Gtk { info: GtkInfo(0), gtk: Box::new([0; 16]) };
448 assert_eq!(gtk_kde.len(), 18);
449
450 let gtk_kde = Gtk { info: GtkInfo(0), gtk: Box::new([0; 8]) };
451 assert_eq!(gtk_kde.len(), 10);
452
453 let gtk_kde = Gtk { info: GtkInfo(0), gtk: Box::new([0; 4]) };
454 assert_eq!(gtk_kde.len(), 6);
455
456 let gtk_kde = Gtk { info: GtkInfo(0), gtk: Box::new([0; 32]) };
457 assert_eq!(gtk_kde.len(), 34);
458 }
459}