blob: 1cd94e64873978e3d2870fe4bce4bb93052e29f4 [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.
use bytes::Bytes;
use failure::bail;
use wlan_rsn::{
akm, cipher,
rsne::{RsnCapabilities, Rsne},
NegotiatedRsne, OUI,
};
fn make_cipher(suite_type: u8) -> cipher::Cipher {
cipher::Cipher { oui: Bytes::from(&OUI[..]), suite_type }
}
fn make_akm(suite_type: u8) -> akm::Akm {
akm::Akm { oui: Bytes::from(&OUI[..]), suite_type }
}
fn make_rsne(data: Option<u8>, pairwise: Vec<u8>, akms: Vec<u8>) -> Rsne {
let mut rsne = Rsne::new();
rsne.group_data_cipher_suite = data.map(make_cipher);
rsne.pairwise_cipher_suites = pairwise.into_iter().map(make_cipher).collect();
rsne.akm_suites = akms.into_iter().map(make_akm).collect();
rsne.rsn_capabilities = Some(RsnCapabilities(0));
rsne
}
/// Verify that supplicant RSNE is a valid NegotiatedRsne, and is a subset of authenticator RSNE
pub fn is_valid_rsne_subset(s_rsne: &Rsne, a_rsne: &Rsne) -> Result<bool, failure::Error> {
let s_caps = s_rsne.rsn_capabilities.as_ref().unwrap_or(&RsnCapabilities(0));
let s_mgmt_req = s_caps.mgmt_frame_protection_req();
let s_mgmt_cap = s_caps.mgmt_frame_protection_cap();
let a_caps = a_rsne.rsn_capabilities.as_ref().unwrap_or(&RsnCapabilities(0));
let a_mgmt_req = a_caps.mgmt_frame_protection_req();
let a_mgmt_cap = a_caps.mgmt_frame_protection_cap();
// IEEE Std 802.11-2016, 12.6.3, Table 12-2
match (a_mgmt_cap, a_mgmt_req, s_mgmt_cap, s_mgmt_req) {
(true, _, false, true) => bail!("supplicant RSNE has invalid mgmt frame protection"),
(false, true, true, _) => bail!("authenticator RSNE has invalid mgmt frame protection"),
(true, true, false, false) => return Ok(false),
(false, false, true, true) => return Ok(false),
// the remaining cases fall into either of these buckets:
// 1 - spec mentions that "The AP may associate with the STA"
// 2 - it's not covered in the spec, which means presumably we can ignore it. For example,
// if AP/client is not management frame protection capable, then it probably doesn't
// matter whether the opposite party advertises an invalid setting
_ => (),
}
let neg_rsne = NegotiatedRsne::from_rsne(&s_rsne)?;
Ok(a_rsne.group_data_cipher_suite.iter().any(|c| *c == neg_rsne.group_data)
&& a_rsne.pairwise_cipher_suites.iter().any(|c| *c == neg_rsne.pairwise)
&& a_rsne.akm_suites.iter().any(|c| *c == neg_rsne.akm))
}
pub fn create_wpa2_psk_rsne() -> Rsne {
// Note: TKIP is legacy and considered insecure. Only allow CCMP usage for group and pairwise
// ciphers.
make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wpa2_psk_rsne_bytes() {
// Compliant with IEEE Std 802.11-2016, 9.4.2.25.
let expected: Vec<u8> = vec![
0x30, 0x14, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04,
0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x00,
];
let rsne = create_wpa2_psk_rsne();
let mut actual = Vec::with_capacity(rsne.len());
rsne.as_bytes(&mut actual);
assert_eq!(&expected[..], &actual[..]);
}
#[test]
fn test_valid_rsne() {
let s_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let a_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
assert!(is_valid_rsne_subset(&s_rsne, &a_rsne).expect("expect Ok result"));
}
#[test]
fn test_supplicant_rsne_has_too_many_suites() {
let s_rsne =
make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::EAP, akm::PSK]);
let a_rsne =
make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::EAP, akm::PSK]);
let result = is_valid_rsne_subset(&s_rsne, &a_rsne);
assert!(result.is_err());
assert!(format!("{:?}", result.unwrap_err()).contains("InvalidNegotiatedRsne"));
}
#[test]
fn test_supplicant_missing_required_mpfc() {
let mut s_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
s_rsne.rsn_capabilities = Some(RsnCapabilities(0));
let mut a_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let mut rsn_cap = RsnCapabilities(0);
rsn_cap.set_mgmt_frame_protection_req(true);
rsn_cap.set_mgmt_frame_protection_cap(true);
a_rsne.rsn_capabilities = Some(rsn_cap);
assert!(!is_valid_rsne_subset(&s_rsne, &a_rsne).expect("expect Ok result"));
}
#[test]
fn test_authenticator_missing_required_mpfc() {
let mut s_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let mut rsn_cap = RsnCapabilities(0);
rsn_cap.set_mgmt_frame_protection_req(true);
rsn_cap.set_mgmt_frame_protection_cap(true);
s_rsne.rsn_capabilities = Some(rsn_cap);
let a_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
assert!(!is_valid_rsne_subset(&s_rsne, &a_rsne).expect("expect Ok result"));
}
#[test]
fn test_supplicant_has_invalid_mgmt_frame_protection_fields() {
let mut s_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let mut rsn_cap = RsnCapabilities(0);
rsn_cap.set_mgmt_frame_protection_req(true);
rsn_cap.set_mgmt_frame_protection_cap(false);
s_rsne.rsn_capabilities = Some(rsn_cap);
// AP only cares about client's invalid setting if AP is mgmt frame protection capable
let mut a_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let mut rsn_cap = RsnCapabilities(0);
rsn_cap.set_mgmt_frame_protection_cap(true);
a_rsne.rsn_capabilities = Some(rsn_cap);
let result = is_valid_rsne_subset(&s_rsne, &a_rsne);
assert!(result.is_err());
assert_eq!(
format!("{}", result.unwrap_err()),
"supplicant RSNE has invalid mgmt frame protection"
)
}
#[test]
fn test_authenticator_has_invalid_mgmt_frame_protection_fields() {
// client only cares about AP's invalid setting if client is mgmt frame protection capable
let mut s_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let mut rsn_cap = RsnCapabilities(0);
rsn_cap.set_mgmt_frame_protection_cap(true);
s_rsne.rsn_capabilities = Some(rsn_cap);
let mut a_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let mut rsn_cap = RsnCapabilities(0);
rsn_cap.set_mgmt_frame_protection_req(true);
rsn_cap.set_mgmt_frame_protection_cap(false);
a_rsne.rsn_capabilities = Some(rsn_cap);
let result = is_valid_rsne_subset(&s_rsne, &a_rsne);
assert!(result.is_err());
assert_eq!(
format!("{}", result.unwrap_err()),
"authenticator RSNE has invalid mgmt frame protection"
)
}
#[test]
fn test_rsne_unsupported_group_data_cipher() {
let s_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let a_rsne = make_rsne(Some(cipher::GCMP_256), vec![cipher::CCMP_128], vec![akm::PSK]);
assert!(!is_valid_rsne_subset(&s_rsne, &a_rsne).expect("expect Ok result"));
}
#[test]
fn test_rsne_unsupported_pairwise_cipher() {
let s_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let a_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::BIP_CMAC_256], vec![akm::PSK]);
assert!(!is_valid_rsne_subset(&s_rsne, &a_rsne).expect("expect Ok result"));
}
#[test]
fn test_rsne_unsupported_akm() {
let s_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::PSK]);
let a_rsne = make_rsne(Some(cipher::CCMP_128), vec![cipher::CCMP_128], vec![akm::EAP]);
assert!(!is_valid_rsne_subset(&s_rsne, &a_rsne).expect("expect Ok result"));
}
}