wlan_common/ie/rsn/
cipher.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_usage {
11    ($e:expr) => {
12        if !$e.has_known_usage() {
13            return None;
14        }
15    };
16}
17
18// IEEE Std 802.11-2016, 9.4.2.25.2, Table 9-131
19pub const GROUP_CIPHER_SUITE: u8 = 0;
20pub const WEP_40: u8 = 1;
21pub const TKIP: u8 = 2;
22// 3 - Reserved.
23pub const CCMP_128: u8 = 4;
24pub const WEP_104: u8 = 5;
25pub const BIP_CMAC_128: u8 = 6;
26pub const GROUP_ADDRESSED_TRAFFIC_NOT_ALLOWED: u8 = 7;
27pub const GCMP_128: u8 = 8;
28pub const GCMP_256: u8 = 9;
29pub const CCMP_256: u8 = 10;
30pub const BIP_GMAC_128: u8 = 11;
31pub const BIP_GMAC_256: u8 = 12;
32pub const BIP_CMAC_256: u8 = 13;
33// 14-255 - Reserved.
34
35// Shorthands for the most commonly constructed ciphers
36pub const CIPHER_TKIP: Cipher = Cipher::new_dot11(TKIP);
37pub const CIPHER_CCMP_128: Cipher = Cipher::new_dot11(CCMP_128);
38pub const CIPHER_BIP_CMAC_128: Cipher = Cipher::new_dot11(BIP_CMAC_128);
39pub const CIPHER_GCMP_256: Cipher = Cipher::new_dot11(GCMP_256);
40pub const CIPHER_BIP_CMAC_256: Cipher = Cipher::new_dot11(BIP_CMAC_256);
41
42#[derive(PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
43pub struct Cipher {
44    pub oui: Oui,
45    pub suite_type: u8,
46}
47
48impl Cipher {
49    /// Creates a new AKM instance for 802.11 specified AKMs.
50    /// See IEEE Std 802.11-2016, 9.4.2.25.2, Table 9-131
51    pub const fn new_dot11(suite_type: u8) -> Self {
52        Cipher { oui: OUI, suite_type }
53    }
54
55    /// Reserved and vendor specific cipher suites have no known usage and require special
56    /// treatments.
57    pub fn has_known_usage(&self) -> bool {
58        if self.is_vendor_specific() {
59            // Support MSFT TKIP/CCMP for WPA1
60            self.oui == Oui::MSFT && (self.suite_type == TKIP || self.suite_type == CCMP_128)
61        } else {
62            !self.is_reserved()
63        }
64    }
65
66    pub fn is_vendor_specific(&self) -> bool {
67        // IEEE 802.11-2016, 9.4.2.25.2, Table 9-131
68        !self.oui.eq(&OUI)
69    }
70
71    pub fn is_reserved(&self) -> bool {
72        // IEEE 802.11-2016, 9.4.2.25.2, Table 9-131
73        (self.suite_type == 3 || self.suite_type >= 14) && !self.is_vendor_specific()
74    }
75
76    pub fn is_enhanced(&self) -> bool {
77        // IEEE Std 802.11-2016, 4.3.8
78        if !self.has_known_usage() {
79            false
80        } else {
81            match self.suite_type {
82                GROUP_CIPHER_SUITE | WEP_40 | WEP_104 | GROUP_ADDRESSED_TRAFFIC_NOT_ALLOWED => {
83                    false
84                }
85                _ => true,
86            }
87        }
88    }
89
90    pub fn supports_gtk(&self) -> Option<bool> {
91        return_none_if_unknown_usage!(self);
92
93        // IEEE 802.11-2016, 9.4.2.25.2, Table 9-132
94        match self.suite_type {
95            1..=5 | 8..=10 => Some(true),
96            0 | 6 | 11..=13 => Some(false),
97            _ => None,
98        }
99    }
100
101    pub fn supports_ptk(&self) -> Option<bool> {
102        return_none_if_unknown_usage!(self);
103
104        // IEEE 802.11-2016, 9.4.2.25.2, Table 9-132
105        match self.suite_type {
106            0 | 2..=4 | 8..=10 => Some(true),
107            1 | 5 | 6 | 11..=13 => Some(false),
108            _ => None,
109        }
110    }
111
112    pub fn supports_igtk(&self) -> Option<bool> {
113        return_none_if_unknown_usage!(self);
114
115        // IEEE 802.11-2016, 9.4.2.25.2, Table 9-132
116        match self.suite_type {
117            6 | 11..=13 => Some(true),
118            0 | 1..=5 | 8..=10 => Some(false),
119            _ => None,
120        }
121    }
122
123    pub fn tk_bytes(&self) -> Option<u8> {
124        return_none_if_unknown_usage!(self);
125
126        // IEEE 802.11-2016, 12.7.2, Table 12-4
127        match self.suite_type {
128            1 => Some(5),
129            5 => Some(13),
130            4 | 6 | 8 | 11 => Some(16),
131            2 | 9 | 10 | 12 | 13 => Some(32),
132            _ => None,
133        }
134    }
135
136    pub fn tk_bits(&self) -> Option<u16> {
137        self.tk_bytes().map(|x| 8 * u16::from(x))
138    }
139}
140
141impl suite_selector::Factory for Cipher {
142    type Suite = Cipher;
143
144    fn new(oui: Oui, suite_type: u8) -> Self::Suite {
145        Cipher { oui, suite_type }
146    }
147}
148
149impl fmt::Debug for Cipher {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        write!(f, "{:02X}-{:02X}-{:02X}:{}", self.oui[0], self.oui[1], self.oui[2], self.suite_type)
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn test_new_dot11() {
161        let ccmp = CIPHER_CCMP_128;
162        assert!(!ccmp.is_vendor_specific());
163        assert!(ccmp.has_known_usage());
164        assert!(ccmp.is_enhanced());
165        assert!(!ccmp.is_reserved());
166    }
167}