blob: 3a46a3011a22e22a1ff03788d67be8cdbd003437 [file] [log] [blame] [edit]
// 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 bytes::Bytes;
use crypto_utils;
use integrity;
use integrity::hmac_sha1::HmacSha1;
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.
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_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(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>>> {
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
)
}
}