wlan_common/ie/rsn/
akm.rs

1// Copyright 2018 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 super::suite_selector;
6use crate::ie::rsn::suite_selector::OUI;
7use crate::organization::Oui;
8use std::fmt;
9
10macro_rules! return_none_if_unknown_algo {
11    ($e:expr) => {
12        if !$e.has_known_algorithm() {
13            return None;
14        }
15    };
16}
17
18// IEEE Std 802.11-2016, 9.4.2.25.3, Table 9-133
19// 0 - Reserved.
20pub const EAP: u8 = 1;
21pub const PSK: u8 = 2;
22pub const FT_EAP: u8 = 3;
23pub const FT_PSK: u8 = 4;
24pub const EAP_SHA256: u8 = 5;
25pub const PSK_SHA256: u8 = 6;
26pub const TDLS: u8 = 7;
27pub const SAE: u8 = 8;
28pub const FT_SAE: u8 = 9;
29pub const AP_PEERKEY: u8 = 10;
30pub const EAP_SUITEB: u8 = 11;
31pub const EAP_SUITEB_SHA384: u8 = 12;
32pub const FT_EAP_SHA384: u8 = 13;
33// 14-255 - Reserved.
34
35// Shorthands for the most commonly constructed akm suites
36pub const AKM_EAP: Akm = Akm::new_dot11(EAP);
37pub const AKM_PSK: Akm = Akm::new_dot11(PSK);
38pub const AKM_FT_PSK: Akm = Akm::new_dot11(FT_PSK);
39pub const AKM_SAE: Akm = Akm::new_dot11(SAE);
40
41#[derive(PartialOrd, PartialEq, Eq, Clone)]
42pub struct Akm {
43    pub oui: Oui,
44    pub suite_type: u8,
45}
46
47impl Akm {
48    /// Creates a new AKM instance for 802.11 specified AKMs.
49    /// See IEEE Std 802.11-2016, 9.4.2.25.3, Table 9-133.
50    pub const fn new_dot11(suite_type: u8) -> Self {
51        Akm { oui: OUI, suite_type }
52    }
53
54    /// Only AKMs specified in IEEE 802.11-2016, 9.4.2.25.4, Table 9-133 have known algorithms.
55    pub fn has_known_algorithm(&self) -> bool {
56        if self.is_reserved() || self.is_vendor_specific() {
57            // Support MSFT PSK for WPA1
58            self.oui == Oui::MSFT && self.suite_type == PSK
59        } else {
60            self.suite_type != 7 && self.suite_type != 10
61        }
62    }
63
64    pub fn is_vendor_specific(&self) -> bool {
65        // IEEE 802.11-2016, 9.4.2.25.4, Table 9-133
66        !self.oui.eq(&OUI)
67    }
68
69    pub fn is_reserved(&self) -> bool {
70        // IEEE 802.11-2016, 9.4.2.25.4, Table 9-133
71        (self.suite_type == 0 || self.suite_type >= 14) && !self.is_vendor_specific()
72    }
73
74    pub fn mic_bytes(&self) -> Option<u16> {
75        return_none_if_unknown_algo!(self);
76
77        // IEEE 802.11-2016, 12.7.3, Table 12-8
78        match self.suite_type {
79            1..=11 => Some(16),
80            12 | 13 => Some(24),
81            _ => None,
82        }
83    }
84
85    pub fn kck_bytes(&self) -> Option<u16> {
86        return_none_if_unknown_algo!(self);
87
88        // IEEE 802.11-2016, 12.7.3, Table 12-8
89        match self.suite_type {
90            1..=11 => Some(16),
91            12 | 13 => Some(24),
92            _ => None,
93        }
94    }
95
96    pub fn kek_bytes(&self) -> Option<u16> {
97        return_none_if_unknown_algo!(self);
98
99        // IEEE 802.11-2016, 12.7.3, Table 12-8
100        match self.suite_type {
101            1..=11 => Some(16),
102            12 | 13 => Some(32),
103            _ => None,
104        }
105    }
106
107    pub fn pmk_bytes(&self) -> Option<u16> {
108        return_none_if_unknown_algo!(self);
109
110        // IEEE 802.11-2016, 12.7.1.3
111        match self.suite_type {
112            1..=11 | 13 => Some(32),
113            12 => Some(48),
114            _ => None,
115        }
116    }
117
118    #[deprecated(note = "use `kck_bytes` instead")]
119    pub fn kck_bits(&self) -> Option<u16> {
120        return_none_if_unknown_algo!(self);
121
122        // IEEE 802.11-2016, 12.7.3, Table 12-8
123        match self.suite_type {
124            1..=11 => Some(128),
125            12 | 13 => Some(192),
126            _ => None,
127        }
128    }
129
130    #[deprecated(note = "use `kek_bytes` instead")]
131    pub fn kek_bits(&self) -> Option<u16> {
132        return_none_if_unknown_algo!(self);
133
134        // IEEE 802.11-2016, 12.7.3, Table 12-8
135        match self.suite_type {
136            1..=11 => Some(128),
137            12 | 13 => Some(256),
138            _ => None,
139        }
140    }
141
142    #[deprecated(note = "use `pmk_bytes` instead")]
143    pub fn pmk_bits(&self) -> Option<u16> {
144        return_none_if_unknown_algo!(self);
145
146        // IEEE 802.11-2016, 12.7.1.3
147        match self.suite_type {
148            1..=11 | 13 => Some(256),
149            12 => Some(384),
150            _ => None,
151        }
152    }
153}
154
155impl suite_selector::Factory for Akm {
156    type Suite = Akm;
157
158    fn new(oui: Oui, suite_type: u8) -> Self::Suite {
159        Akm { oui, suite_type }
160    }
161}
162
163impl fmt::Debug for Akm {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        write!(f, "{:02X}-{:02X}-{:02X}:{}", self.oui[0], self.oui[1], self.oui[2], self.suite_type)
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172
173    #[test]
174    fn test_new_dot11() {
175        let psk = AKM_PSK;
176        assert!(!psk.is_vendor_specific());
177        assert!(psk.has_known_algorithm());
178        assert!(!psk.is_reserved());
179    }
180
181    #[test]
182    fn test_msft_akm() {
183        let psk = Akm { oui: Oui::MSFT, suite_type: PSK };
184        assert!(psk.is_vendor_specific());
185        assert!(psk.has_known_algorithm());
186        assert!(!psk.is_reserved());
187    }
188}