| // 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::crypto_utils; |
| use crate::integrity::{self, hmac_sha1::HmacSha1}; |
| use crate::keywrap; |
| use crate::suite_selector; |
| use crate::Error; |
| use bytes::Bytes; |
| use failure::{self, ensure}; |
| use std::fmt; |
| |
| macro_rules! return_none_if_unknown_algo { |
| ($e:expr) => { |
| if !$e.has_known_algorithm() { |
| return None; |
| } |
| }; |
| } |
| |
| // IEEE Std 802.11-2016, 9.4.2.25.3, Table 9-133 |
| // 0 - Reserved. |
| pub const EAP: u8 = 1; |
| pub const PSK: u8 = 2; |
| pub const FT_EAP: u8 = 3; |
| pub const FT_PSK: u8 = 4; |
| pub const EAP_SHA256: u8 = 5; |
| pub const PSK_SHA256: u8 = 6; |
| pub const TDLS: u8 = 7; |
| pub const SAE: u8 = 8; |
| pub const FT_SAE: u8 = 9; |
| pub const AP_PEERKEY: u8 = 10; |
| pub const EAP_SUITEB: u8 = 11; |
| pub const EAP_SUITEB_SHA384: u8 = 12; |
| pub const FT_EAP_SHA384: u8 = 13; |
| // 14-255 - Reserved. |
| |
| #[derive(PartialOrd, PartialEq, Clone)] |
| pub struct Akm { |
| pub oui: Bytes, |
| pub suite_type: u8, |
| } |
| |
| impl Akm { |
| /// Only AKMs specified in IEEE 802.11-2016, 9.4.2.25.4, Table 9-133 have known algorithms. |
| pub fn has_known_algorithm(&self) -> bool { |
| if self.is_reserved() || self.is_vendor_specific() { |
| false |
| } else { |
| self.suite_type != 7 && self.suite_type != 10 |
| } |
| } |
| |
| pub fn is_vendor_specific(&self) -> bool { |
| // IEEE 802.11-2016, 9.4.2.25.4, Table 9-133 |
| !&self.oui[..].eq(&suite_selector::OUI) |
| } |
| |
| pub fn is_reserved(&self) -> bool { |
| // IEEE 802.11-2016, 9.4.2.25.4, Table 9-133 |
| (self.suite_type == 0 || self.suite_type >= 14) && !self.is_vendor_specific() |
| } |
| |
| pub fn mic_bytes(&self) -> Option<u16> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.3, Table 12-8 |
| match self.suite_type { |
| 1...11 => Some(16), |
| 12 | 13 => Some(24), |
| _ => None, |
| } |
| } |
| |
| pub fn kck_bytes(&self) -> Option<u16> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.3, Table 12-8 |
| match self.suite_type { |
| 1...11 => Some(16), |
| 12 | 13 => Some(24), |
| _ => None, |
| } |
| } |
| |
| pub fn kek_bytes(&self) -> Option<u16> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.3, Table 12-8 |
| match self.suite_type { |
| 1...11 => Some(16), |
| 12 | 13 => Some(32), |
| _ => None, |
| } |
| } |
| |
| pub fn pmk_bytes(&self) -> Option<u16> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.1.3 |
| match self.suite_type { |
| 1...11 | 13 => Some(32), |
| 12 => Some(48), |
| _ => None, |
| } |
| } |
| |
| #[deprecated(note = "use `kck_bytes` instead")] |
| pub fn kck_bits(&self) -> Option<u16> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.3, Table 12-8 |
| match self.suite_type { |
| 1...11 => Some(128), |
| 12 | 13 => Some(192), |
| _ => None, |
| } |
| } |
| |
| #[deprecated(note = "use `kek_bytes` instead")] |
| pub fn kek_bits(&self) -> Option<u16> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.3, Table 12-8 |
| match self.suite_type { |
| 1...11 => Some(128), |
| 12 | 13 => Some(256), |
| _ => None, |
| } |
| } |
| |
| #[deprecated(note = "use `pmk_bytes` instead")] |
| pub fn pmk_bits(&self) -> Option<u16> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.1.3 |
| match self.suite_type { |
| 1...11 | 13 => Some(256), |
| 12 => Some(384), |
| _ => None, |
| } |
| } |
| |
| pub fn integrity_algorithm(&self) -> Option<Box<integrity::Algorithm>> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.3, Table 12-8 |
| match self.suite_type { |
| 1 | 2 => Some(Box::new(HmacSha1::new())), |
| // TODO(hahnr): Add remaining integrity algorithms. |
| 3...13 => None, |
| _ => None, |
| } |
| } |
| |
| pub fn keywrap_algorithm(&self) -> Option<Box<keywrap::Algorithm>> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.3, Table 12-8 |
| match self.suite_type { |
| 1...13 => Some(Box::new(keywrap::aes::NistAes)), |
| _ => None, |
| } |
| } |
| |
| pub fn prf( |
| &self, |
| k: &[u8], |
| a: &str, |
| b: &[u8], |
| bits: usize, |
| ) -> Option<Result<Vec<u8>, failure::Error>> { |
| return_none_if_unknown_algo!(self); |
| |
| // IEEE 802.11-2016, 12.7.1.2 |
| match self.suite_type { |
| 1...4 | 8 | 9 => Some(crypto_utils::prf(k, a, b, bits)), |
| _ => None, |
| } |
| } |
| } |
| |
| impl suite_selector::Factory for Akm { |
| type Suite = Akm; |
| |
| fn new(oui: Bytes, suite_type: u8) -> Result<Self::Suite, failure::Error> { |
| ensure!(oui.len() == 3, Error::InvalidOuiLength(oui.len())); |
| Ok(Akm { oui, suite_type }) |
| } |
| } |
| |
| impl fmt::Debug for Akm { |
| 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) |
| } |
| } |