blob: ebfa59680394ec19ebaa93e2557517bcc60d4782 [file] [log] [blame]
// 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.
#![allow(dead_code)]
use auth::{config, psk};
use bytes::Bytes;
use crypto_utils;
use futures::Future;
use integrity;
use keywrap;
use std::fmt;
use suite_selector;
use {Error, Result};
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.
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.
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_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,
}
}
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,
}
}
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(integrity::HmacSha1128)),
// 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,
}
}
/// Returns `None` if there is no known authentication method associated with this AKM.
/// Else, returns a `Result` which indicates an error if the given `config` is incompatible with
/// the AKM, or succeeds if the authentication method was successfully created.
pub fn auth_method(
&self, config: config::Config,
) -> Option<Result<Box<Future<Item = Vec<u8>, Error = Error>>>> {
return_none_if_unknown_algo!(self);
// IEEE 802.11-2016, 9.4.2.25.3, Table 9-133
match self.suite_type {
2 => Some(match config {
// TODO(hahnr): Due to a compiler bug we cannot use `.map` on the newly created PSK,
// and instead must manually map the result to a boxed Future.
config::Config::Psk(c) => match psk::new(c) {
Ok(psk) => Ok(Box::new(psk)),
Err(e) => Err(e),
},
_ => Err(Error::IncompatibleConfig(config, "PSK".to_string())),
}),
_ => None,
}
}
pub fn prf(&self, k: &[u8], a: &str, b: &[u8], bits: usize) -> Option<Result<Vec<u8>>> {
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> {
if oui.len() != 3 {
Err(Error::InvalidOuiLength(oui.len()))
} else {
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
)
}
}