1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45use super::akm::{self, Akm, AKM_EAP};
6use super::cipher::{self, Cipher, CIPHER_BIP_CMAC_128, CIPHER_CCMP_128};
7use crate::ie;
89// IEEE 802.11-2016, 9.4.2.25.2
10// If group data cipher suite field is not included in RSNE, CCMP-128 is the default for
11// non-DMG STA.
12pub const DEFAULT_GROUP_DATA_CIPHER: Cipher = CIPHER_CCMP_128;
1314// IEEE 802.11-2016, 9.4.2.25.2
15// If pairwise cipher suite field is not included in RSNE, CCMP-128 is the default for
16// non-DMG STA.
17pub const DEFAULT_PAIRWISE_CIPHER: [Cipher; 1] = [CIPHER_CCMP_128];
1819// IEEE 802.11-2016, 9.4.2.25.3
20// If akm suite list field is not included in RSNE, suite selector value 00-0F-AC:1
21// (i.e. akm::EAP) is the default.
22pub const DEFAULT_AKM: [Akm; 1] = [AKM_EAP];
2324// IEEE 802.11-2016, 9.4.2.25.2
25// If management frame protection is enabled, and group management cipher suite field is
26// not included in RSNE, BIP-CMAC-128 is the default.
27pub const DEFAULT_GROUP_MGMT_CIPHER: Cipher = CIPHER_BIP_CMAC_128;
2829pub struct SuiteFilter<'a> {
30 known_group_data_ciphers: &'a [u8],
31 known_akms: &'a [u8],
32 known_pairwise_ciphers: &'a [u8],
33 required_group_mgmt_cipher: Option<u8>,
34}
3536impl<'a> SuiteFilter<'a> {
37pub fn is_satisfied(&self, rsne: &ie::rsn::rsne::Rsne) -> bool {
38let group_data_cipher =
39 rsne.group_data_cipher_suite.as_ref().unwrap_or(&DEFAULT_GROUP_DATA_CIPHER);
40let group_data_satisfied = group_data_cipher.has_known_usage()
41 && self.known_group_data_ciphers.contains(&group_data_cipher.suite_type);
4243let akms = if rsne.akm_suites.is_empty() { &DEFAULT_AKM[..] } else { &rsne.akm_suites[..] };
44let akm_satisfied =
45 akms.iter().any(|a| a.has_known_algorithm() && self.known_akms.contains(&a.suite_type));
4647let pairwise_ciphers = if rsne.pairwise_cipher_suites.is_empty() {
48&DEFAULT_PAIRWISE_CIPHER[..]
49 } else {
50&rsne.pairwise_cipher_suites[..]
51 };
52let pairwise_satisfied = pairwise_ciphers
53 .iter()
54 .any(|c| c.has_known_usage() && self.known_pairwise_ciphers.contains(&c.suite_type));
5556let group_mgmt_cipher =
57 rsne.group_mgmt_cipher_suite.as_ref().unwrap_or(&DEFAULT_GROUP_MGMT_CIPHER);
58let group_mgmt_satisfied = self
59.required_group_mgmt_cipher
60 .map(|s| group_mgmt_cipher.suite_type == s)
61 .unwrap_or(true);
6263 group_data_satisfied && akm_satisfied && pairwise_satisfied && group_mgmt_satisfied
64 }
65}
6667/// WFA, WPA1 Spec. 3.1, Chapter 2.1
68pub const WPA1_PERSONAL: SuiteFilter<'_> = SuiteFilter {
69 known_group_data_ciphers: &[cipher::TKIP, cipher::CCMP_128],
70 known_akms: &[akm::PSK],
71 known_pairwise_ciphers: &[cipher::TKIP, cipher::CCMP_128],
72 required_group_mgmt_cipher: None,
73};
7475pub const WPA2_PERSONAL_TKIP_ONLY: SuiteFilter<'_> = SuiteFilter {
76 known_group_data_ciphers: &[cipher::TKIP],
77 known_akms: &[akm::PSK],
78 known_pairwise_ciphers: &[cipher::TKIP],
79 required_group_mgmt_cipher: None,
80};
8182/// IEEE 802.11 2004, Chapter 7.3.2.25.1
83///
84/// Ciphers that encompass different configurations used for WPA2 personal (e.g. base
85/// configuration, configuration that supports BSS fast transition, and configuration
86/// that supports management frame protection)
87pub const WPA2_PERSONAL: SuiteFilter<'_> = SuiteFilter {
88 known_group_data_ciphers: &[cipher::CCMP_128, cipher::TKIP],
89// From observation: In most WPA2 cases, only akm::PSK is included. If FT is enabled,
90 // akm::FT_PSK is also included.
91 // In the case where management frame protection is set to required, akm::PSK is replaced
92 // with akm::PSK_SHA256 (but not when mfp is only set to capable)
93known_akms: &[akm::PSK, akm::FT_PSK, akm::PSK_SHA256],
94// In theory, 256 bit cipher suites (which were added in 802.11ac amendment) could also
95 // be included here and elsewhere. In practice, it's unclear how many APs actually support
96 // it. We'll disallow it for now to keep logic simple because otherwise, we also have
97 // to do the check that pairwise and group keys match.
98 //
99 // TODO(https://fxbug.dev/42104677): deploy metric to measure AKM and cipher use in practice.
100known_pairwise_ciphers: &[cipher::CCMP_128],
101 required_group_mgmt_cipher: None,
102};
103104/// WFA, WPA3 Spec. 1.0, Chapter 3
105pub const WPA3_PERSONAL: SuiteFilter<'_> = SuiteFilter {
106 known_group_data_ciphers: &[cipher::CCMP_128, cipher::TKIP],
107// WPA3 spec doesn't mention Fast BSS Transition, thus akm::FT_SAE is likely not supported.
108 // For some reason, An AP we use for testing provide an option to turn on FT for WPA3 network,
109 // but even then it still uses akm::SAE.
110known_akms: &[akm::SAE],
111 known_pairwise_ciphers: &[cipher::CCMP_128],
112 required_group_mgmt_cipher: None,
113};
114115/// Ciphers that encompass different configurations used for WPA2 enterprise (e.g. base
116/// configuration, configuration that supports BSS fast transition, and configuration
117/// that supports management frame protection)
118pub const WPA2_ENTERPRISE: SuiteFilter<'_> = SuiteFilter {
119 known_group_data_ciphers: &[cipher::CCMP_128],
120// From observation: akm::EAP is included for base WPA2 enterprise configuration. If FT
121 // is enabled, akm::FT_EAP is also included.
122 // In the case where management frame protection is set to required, akm::EAP is replaced
123 // with akm::EAP_SHA256 (but not when mfp is only set to capable).
124known_akms: &[akm::EAP, akm::FT_EAP, akm::EAP_SHA256],
125 known_pairwise_ciphers: &[cipher::CCMP_128],
126 required_group_mgmt_cipher: None,
127};
128129/// WFA, WPA3 Spec. 1.0, Chapter 3
130pub const WPA3_ENTERPRISE_192_BIT: SuiteFilter<'_> = SuiteFilter {
131 known_group_data_ciphers: &[cipher::GCMP_256],
132 known_akms: &[akm::EAP_SUITEB_SHA384],
133 known_pairwise_ciphers: &[cipher::GCMP_256],
134 required_group_mgmt_cipher: Some(cipher::BIP_GMAC_256),
135};
136137#[cfg(test)]
138mod tests {
139use super::*;
140use crate::test_utils::fake_frames::{fake_wpa2_rsne, fake_wpa3_enterprise_192_bit_rsne};
141142#[test]
143fn test_suite_filter() {
144let wpa2_rsne = ie::rsn::rsne::from_bytes(&fake_wpa2_rsne()[..]).unwrap().1;
145assert!(WPA2_PERSONAL.is_satisfied(&wpa2_rsne));
146assert!(!WPA3_PERSONAL.is_satisfied(&wpa2_rsne));
147 }
148149#[test]
150fn test_suite_filter_with_required_group_mgmt() {
151let mut wpa3_ent_rsne =
152 ie::rsn::rsne::from_bytes(&fake_wpa3_enterprise_192_bit_rsne()[..]).unwrap().1;
153assert!(WPA3_ENTERPRISE_192_BIT.is_satisfied(&wpa3_ent_rsne));
154 wpa3_ent_rsne.group_mgmt_cipher_suite = None;
155assert!(!WPA3_ENTERPRISE_192_BIT.is_satisfied(&wpa3_ent_rsne));
156 }
157158#[test]
159fn test_suite_filter_empty_rsne() {
160let rsne = ie::rsn::rsne::Rsne::default();
161assert!(WPA2_ENTERPRISE.is_satisfied(&rsne));
162assert!(!WPA2_PERSONAL.is_satisfied(&rsne));
163 }
164}