wlan_sme/client/
wpa.rs

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.
4
5use wlan_common::ie::rsn::{akm, cipher};
6use wlan_common::ie::wpa::WpaIe;
7use wlan_common::organization::Oui;
8
9/// According to the WiFi Alliance WPA standard (2004), only TKIP support is required. We allow
10/// CCMP if the AP requests it.
11/// Only supported AKM is PSK
12pub fn is_legacy_wpa_compatible(a_wpa: &WpaIe) -> bool {
13    let multicast_supported = a_wpa.multicast_cipher.has_known_usage()
14        && (a_wpa.multicast_cipher.suite_type == cipher::TKIP
15            || a_wpa.multicast_cipher.suite_type == cipher::CCMP_128);
16    let unicast_supported = a_wpa.unicast_cipher_list.iter().any(|c| {
17        c.has_known_usage() && (c.suite_type == cipher::TKIP || c.suite_type == cipher::CCMP_128)
18    });
19    let akm_supported =
20        a_wpa.akm_list.iter().any(|a| a.has_known_algorithm() && a.suite_type == akm::PSK);
21    multicast_supported && unicast_supported && akm_supported
22}
23
24/// Construct a supplicant WPA1 IE with:
25/// The same multicast and unicast ciphers as the AP WPA1 IE
26/// PSK as the AKM
27pub fn construct_s_wpa(a_wpa: &WpaIe) -> WpaIe {
28    // Use CCMP if supported, otherwise default to TKIP.
29    let unicast_cipher = if a_wpa
30        .unicast_cipher_list
31        .iter()
32        .any(|c| c.has_known_usage() && c.suite_type == cipher::CCMP_128)
33    {
34        cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::CCMP_128 }
35    } else {
36        cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::TKIP }
37    };
38    WpaIe {
39        multicast_cipher: a_wpa.multicast_cipher,
40        unicast_cipher_list: vec![unicast_cipher],
41        akm_list: vec![akm::Akm { oui: Oui::MSFT, suite_type: akm::PSK }],
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::test_utils;
49
50    #[test]
51    fn test_incompatible_multicast_cipher() {
52        let mut a_wpa = test_utils::make_wpa1_ie();
53        a_wpa.multicast_cipher = cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::WEP_40 };
54        assert!(!is_legacy_wpa_compatible(&a_wpa));
55    }
56
57    #[test]
58    fn test_incompatible_unicast_cipher() {
59        let mut a_wpa = test_utils::make_wpa1_ie();
60        a_wpa.unicast_cipher_list =
61            vec![cipher::Cipher { oui: Oui::DOT11, suite_type: cipher::WEP_40 }];
62        assert!(!is_legacy_wpa_compatible(&a_wpa));
63    }
64
65    #[test]
66    fn test_incompatible_akm() {
67        let mut a_wpa = test_utils::make_wpa1_ie();
68        a_wpa.akm_list = vec![akm::Akm { oui: Oui::DOT11, suite_type: akm::EAP }];
69        assert!(!is_legacy_wpa_compatible(&a_wpa));
70    }
71
72    #[test]
73    fn get_supplicant_ie_tkip() {
74        let mut a_wpa = test_utils::make_wpa1_ie();
75        a_wpa.unicast_cipher_list =
76            vec![cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::TKIP }];
77        let s_wpa = construct_s_wpa(&a_wpa);
78        assert_eq!(
79            s_wpa.unicast_cipher_list,
80            vec![cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::TKIP }]
81        );
82    }
83
84    #[test]
85    fn get_supplicant_ie_ccmp() {
86        let mut a_wpa = test_utils::make_wpa1_ie();
87        a_wpa.unicast_cipher_list = vec![
88            cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::TKIP },
89            cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::CCMP_128 },
90        ];
91        let s_wpa = construct_s_wpa(&a_wpa);
92        assert_eq!(
93            s_wpa.unicast_cipher_list,
94            vec![cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::CCMP_128 }]
95        );
96    }
97
98    #[test]
99    fn test_no_unicast_cipher() {
100        let mut a_wpa = test_utils::make_wpa1_ie();
101        a_wpa.unicast_cipher_list = vec![];
102        assert!(!is_legacy_wpa_compatible(&a_wpa));
103    }
104
105    #[test]
106    fn test_no_akm() {
107        let mut a_wpa = test_utils::make_wpa1_ie();
108        a_wpa.akm_list = vec![];
109        assert!(!is_legacy_wpa_compatible(&a_wpa));
110    }
111}