| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use crate::suite_selector; |
| use crate::Error; |
| use bytes::Bytes; |
| use failure::{self, ensure}; |
| use std::fmt; |
| |
| macro_rules! return_none_if_unknown_usage { |
| ($e:expr) => { |
| if !$e.has_known_usage() { |
| return None; |
| } |
| }; |
| } |
| |
| // IEEE Std 802.11-2016, 9.4.2.25.2, Table 9-131 |
| pub const GROUP_CIPHER_SUITE: u8 = 0; |
| pub const WEP_40: u8 = 1; |
| pub const TKIP: u8 = 2; |
| // 3 - Reserved. |
| pub const CCMP_128: u8 = 4; |
| pub const WEP_104: u8 = 5; |
| pub const BIP_CMAC_128: u8 = 6; |
| pub const GROUP_ADDRESSED_TRAFFIC_NOT_ALLOWED: u8 = 7; |
| pub const GCMP_128: u8 = 8; |
| pub const GCMP_256: u8 = 9; |
| pub const CCMP_256: u8 = 10; |
| pub const BIP_GMAC_128: u8 = 11; |
| pub const BIP_GMAC_256: u8 = 12; |
| pub const BIP_CMAC_256: u8 = 13; |
| // 14-255 - Reserved. |
| |
| #[derive(PartialOrd, PartialEq, Clone)] |
| pub struct Cipher { |
| pub oui: Bytes, |
| pub suite_type: u8, |
| } |
| |
| impl Cipher { |
| /// Reserved and vendor specific cipher suites have no known usage and require special |
| /// treatments. |
| pub fn has_known_usage(&self) -> bool { |
| !self.is_reserved() && !self.is_vendor_specific() |
| } |
| |
| pub fn is_vendor_specific(&self) -> bool { |
| // IEEE 802.11-2016, 9.4.2.25.2, Table 9-131 |
| !&self.oui[..].eq(&suite_selector::OUI) |
| } |
| |
| pub fn is_reserved(&self) -> bool { |
| // IEEE 802.11-2016, 9.4.2.25.2, Table 9-131 |
| (self.suite_type == 3 || self.suite_type >= 14) && !self.is_vendor_specific() |
| } |
| |
| pub fn is_enhanced(&self) -> bool { |
| // IEEE Std 802.11-2016, 4.3.8 |
| if !self.has_known_usage() { |
| false |
| } else { |
| match self.suite_type { |
| GROUP_CIPHER_SUITE | WEP_40 | WEP_104 | GROUP_ADDRESSED_TRAFFIC_NOT_ALLOWED => { |
| false |
| } |
| _ => true, |
| } |
| } |
| } |
| |
| pub fn supports_gtk(&self) -> Option<bool> { |
| return_none_if_unknown_usage!(self); |
| |
| // IEEE 802.11-2016, 9.4.2.25.2, Table 9-132 |
| match self.suite_type { |
| 1...5 | 8...10 => Some(true), |
| 0 | 6 | 11...13 => Some(false), |
| _ => None, |
| } |
| } |
| |
| pub fn supports_ptk(&self) -> Option<bool> { |
| return_none_if_unknown_usage!(self); |
| |
| // IEEE 802.11-2016, 9.4.2.25.2, Table 9-132 |
| match self.suite_type { |
| 0 | 2...4 | 8...10 => Some(true), |
| 1 | 5 | 6 | 11...13 => Some(false), |
| _ => None, |
| } |
| } |
| |
| pub fn supports_igtk(&self) -> Option<bool> { |
| return_none_if_unknown_usage!(self); |
| |
| // IEEE 802.11-2016, 9.4.2.25.2, Table 9-132 |
| match self.suite_type { |
| 6 | 11...13 => Some(true), |
| 0 | 1...5 | 8...10 => Some(false), |
| _ => None, |
| } |
| } |
| |
| pub fn tk_bytes(&self) -> Option<usize> { |
| return_none_if_unknown_usage!(self); |
| |
| // IEEE 802.11-2016, 12.7.2, Table 12-4 |
| match self.suite_type { |
| 1 => Some(5), |
| 5 => Some(13), |
| 4 | 6 | 8 | 11 => Some(16), |
| 2 | 9 | 10 | 12 | 13 => Some(32), |
| _ => None, |
| } |
| } |
| |
| #[deprecated(note = "use `tk_bytes` instead")] |
| pub fn tk_bits(&self) -> Option<u16> { |
| return_none_if_unknown_usage!(self); |
| |
| // IEEE 802.11-2016, 12.7.2, Table 12-4 |
| match self.suite_type { |
| 1 => Some(40), |
| 5 => Some(104), |
| 4 | 6 | 8 | 11 => Some(128), |
| 2 | 9 | 10 | 12 | 13 => Some(256), |
| _ => None, |
| } |
| } |
| } |
| |
| impl suite_selector::Factory for Cipher { |
| type Suite = Cipher; |
| |
| fn new(oui: Bytes, suite_type: u8) -> Result<Self::Suite, failure::Error> { |
| ensure!(oui.len() == 3, Error::InvalidOuiLength(oui.len())); |
| Ok(Cipher { oui, suite_type }) |
| } |
| } |
| |
| impl fmt::Debug for Cipher { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| write!(f, "{:02X}-{:02X}-{:02X}:{}", self.oui[0], self.oui[1], self.oui[2], self.suite_type) |
| } |
| } |