wlan_common/ie/rsn/
suite_filter.rsuse super::akm::{self, Akm, AKM_EAP};
use super::cipher::{self, Cipher, CIPHER_BIP_CMAC_128, CIPHER_CCMP_128};
use crate::ie;
pub const DEFAULT_GROUP_DATA_CIPHER: Cipher = CIPHER_CCMP_128;
pub const DEFAULT_PAIRWISE_CIPHER: [Cipher; 1] = [CIPHER_CCMP_128];
pub const DEFAULT_AKM: [Akm; 1] = [AKM_EAP];
pub const DEFAULT_GROUP_MGMT_CIPHER: Cipher = CIPHER_BIP_CMAC_128;
pub struct SuiteFilter<'a> {
known_group_data_ciphers: &'a [u8],
known_akms: &'a [u8],
known_pairwise_ciphers: &'a [u8],
required_group_mgmt_cipher: Option<u8>,
}
impl<'a> SuiteFilter<'a> {
pub fn is_satisfied(&self, rsne: &ie::rsn::rsne::Rsne) -> bool {
let group_data_cipher =
rsne.group_data_cipher_suite.as_ref().unwrap_or(&DEFAULT_GROUP_DATA_CIPHER);
let group_data_satisfied = group_data_cipher.has_known_usage()
&& self.known_group_data_ciphers.iter().any(|s| group_data_cipher.suite_type == *s);
let akms = if rsne.akm_suites.is_empty() { &DEFAULT_AKM[..] } else { &rsne.akm_suites[..] };
let akm_satisfied = akms
.iter()
.any(|a| a.has_known_algorithm() && self.known_akms.iter().any(|s| a.suite_type == *s));
let pairwise_ciphers = if rsne.pairwise_cipher_suites.is_empty() {
&DEFAULT_PAIRWISE_CIPHER[..]
} else {
&rsne.pairwise_cipher_suites[..]
};
let pairwise_satisfied = pairwise_ciphers.iter().any(|c| {
c.has_known_usage() && self.known_pairwise_ciphers.iter().any(|s| c.suite_type == *s)
});
let group_mgmt_cipher =
rsne.group_mgmt_cipher_suite.as_ref().unwrap_or(&DEFAULT_GROUP_MGMT_CIPHER);
let group_mgmt_satisfied = self
.required_group_mgmt_cipher
.map(|s| group_mgmt_cipher.suite_type == s)
.unwrap_or(true);
group_data_satisfied && akm_satisfied && pairwise_satisfied && group_mgmt_satisfied
}
}
pub const WPA1_PERSONAL: SuiteFilter<'_> = SuiteFilter {
known_group_data_ciphers: &[cipher::TKIP, cipher::CCMP_128],
known_akms: &[akm::PSK],
known_pairwise_ciphers: &[cipher::TKIP, cipher::CCMP_128],
required_group_mgmt_cipher: None,
};
pub const WPA2_PERSONAL_TKIP_ONLY: SuiteFilter<'_> = SuiteFilter {
known_group_data_ciphers: &[cipher::TKIP],
known_akms: &[akm::PSK],
known_pairwise_ciphers: &[cipher::TKIP],
required_group_mgmt_cipher: None,
};
pub const WPA2_PERSONAL: SuiteFilter<'_> = SuiteFilter {
known_group_data_ciphers: &[cipher::CCMP_128, cipher::TKIP],
known_akms: &[akm::PSK, akm::FT_PSK, akm::PSK_SHA256],
known_pairwise_ciphers: &[cipher::CCMP_128],
required_group_mgmt_cipher: None,
};
pub const WPA3_PERSONAL: SuiteFilter<'_> = SuiteFilter {
known_group_data_ciphers: &[cipher::CCMP_128, cipher::TKIP],
known_akms: &[akm::SAE],
known_pairwise_ciphers: &[cipher::CCMP_128],
required_group_mgmt_cipher: None,
};
pub const WPA2_ENTERPRISE: SuiteFilter<'_> = SuiteFilter {
known_group_data_ciphers: &[cipher::CCMP_128],
known_akms: &[akm::EAP, akm::FT_EAP, akm::EAP_SHA256],
known_pairwise_ciphers: &[cipher::CCMP_128],
required_group_mgmt_cipher: None,
};
pub const WPA3_ENTERPRISE_192_BIT: SuiteFilter<'_> = SuiteFilter {
known_group_data_ciphers: &[cipher::GCMP_256],
known_akms: &[akm::EAP_SUITEB_SHA384],
known_pairwise_ciphers: &[cipher::GCMP_256],
required_group_mgmt_cipher: Some(cipher::BIP_GMAC_256),
};
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::fake_frames::{fake_wpa2_rsne, fake_wpa3_enterprise_192_bit_rsne};
#[test]
fn test_suite_filter() {
let wpa2_rsne = ie::rsn::rsne::from_bytes(&fake_wpa2_rsne()[..]).unwrap().1;
assert!(WPA2_PERSONAL.is_satisfied(&wpa2_rsne));
assert!(!WPA3_PERSONAL.is_satisfied(&wpa2_rsne));
}
#[test]
fn test_suite_filter_with_required_group_mgmt() {
let mut wpa3_ent_rsne =
ie::rsn::rsne::from_bytes(&fake_wpa3_enterprise_192_bit_rsne()[..]).unwrap().1;
assert!(WPA3_ENTERPRISE_192_BIT.is_satisfied(&wpa3_ent_rsne));
wpa3_ent_rsne.group_mgmt_cipher_suite = None;
assert!(!WPA3_ENTERPRISE_192_BIT.is_satisfied(&wpa3_ent_rsne));
}
#[test]
fn test_suite_filter_empty_rsne() {
let rsne = ie::rsn::rsne::Rsne::default();
assert!(WPA2_ENTERPRISE.is_satisfied(&rsne));
assert!(!WPA2_PERSONAL.is_satisfied(&rsne));
}
}