1use crate::key::Tk;
6use crate::key_data::kde;
7use crate::{Error, rsn_ensure};
8use mundane::bytes;
9use wlan_common::ie::rsn::cipher::Cipher;
10
11#[derive(Debug)]
13pub struct IgtkProvider {
14 key: Box<[u8]>,
15 tk_bytes: usize,
16 cipher: Cipher,
17}
18
19fn generate_random_igtk(len: usize) -> Box<[u8]> {
22 let mut key = vec![0; len];
23 bytes::rand(&mut key[..]);
24 key.into_boxed_slice()
25}
26
27impl IgtkProvider {
28 pub fn new(cipher: Cipher) -> Result<IgtkProvider, anyhow::Error> {
29 let tk_bytes: usize =
30 cipher.tk_bytes().ok_or(Error::IgtkHierarchyUnsupportedCipherError)?.into();
31 Ok(IgtkProvider { key: generate_random_igtk(tk_bytes), cipher, tk_bytes })
32 }
33
34 pub fn cipher(&self) -> Cipher {
35 self.cipher
36 }
37
38 pub fn rotate_key(&mut self) {
39 self.key = generate_random_igtk(self.tk_bytes);
40 }
41
42 pub fn get_igtk(&self) -> Igtk {
43 Igtk { igtk: self.key.to_vec(), key_id: 0, ipn: [0u8; 6], cipher: self.cipher.clone() }
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48pub struct Igtk {
49 pub igtk: Vec<u8>,
50 pub key_id: u16,
51 pub ipn: [u8; 6],
52 pub cipher: Cipher,
53}
54
55impl Igtk {
56 #[allow(clippy::result_large_err, reason = "large Error enum")]
57 pub fn from_kde(element: kde::Igtk, cipher: Cipher) -> Result<Self, Error> {
58 let tk_len: usize =
59 cipher.tk_bytes().ok_or(Error::IgtkHierarchyUnsupportedCipherError)?.into();
60 rsn_ensure!(
62 element.igtk.len() >= tk_len,
63 Error::InvalidKeyLength(element.igtk.len(), tk_len)
64 );
65 Ok(Self { igtk: element.igtk, key_id: element.id, ipn: element.ipn, cipher })
66 }
67}
68
69impl Tk for Igtk {
70 fn tk(&self) -> &[u8] {
71 &self.igtk[..]
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use wlan_common::ie::rsn::suite_filter::DEFAULT_GROUP_MGMT_CIPHER;
79
80 #[test]
81 fn test_igtk_generation() {
82 let mut igtk_provider =
83 IgtkProvider::new(DEFAULT_GROUP_MGMT_CIPHER).expect("failed creating IgtkProvider");
84
85 let first_igtk = igtk_provider.get_igtk().tk().to_vec();
86 for _ in 0..3 {
87 igtk_provider.rotate_key();
88 if first_igtk != igtk_provider.get_igtk().tk().to_vec() {
89 return;
90 }
91 }
92 panic!("IGTK key rotation always generates the same key!");
93 }
94
95 #[test]
96 fn test_igtk_from_kde_validation() {
97 let ipn = [0u8; 6];
99
100 let exact_key = vec![0xaa; 16];
102 let element = kde::Igtk::new(1, &ipn[..], &exact_key[..]);
103 let igtk = Igtk::from_kde(element, DEFAULT_GROUP_MGMT_CIPHER);
104 assert!(igtk.is_ok());
105 let igtk = igtk.unwrap();
106 assert_eq!(igtk.igtk, exact_key);
107
108 let short_key = vec![0xcc; 15];
110 let element = kde::Igtk::new(1, &ipn[..], &short_key[..]);
111 let igtk = Igtk::from_kde(element, DEFAULT_GROUP_MGMT_CIPHER);
112 assert!(igtk.is_err());
113 }
114}