1use crate::key::exchange::handshake::group_key::{self, Config, GroupKeyHandshakeFrame};
6use crate::key::exchange::{compute_mic_from_buf, Key};
7use crate::key::gtk::Gtk;
8use crate::key::igtk::Igtk;
9use crate::key_data::kde::GtkInfoTx;
10use crate::rsna::{
11 Dot11VerifiedKeyFrame, IgtkSupport, ProtectionType, SecAssocUpdate, UnverifiedKeyData,
12 UpdateSink,
13};
14use crate::{format_rsn_err, key_data, Error};
15use bytes::Bytes;
16use eapol::KeyFrameBuf;
17use zerocopy::SplitByteSlice;
18
19#[derive(Debug, PartialEq)]
21pub struct Supplicant {
22 pub cfg: group_key::Config,
23 pub kck: Bytes,
24 pub kek: Bytes,
25}
26
27impl Supplicant {
28 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
30 pub fn on_eapol_key_frame<B: SplitByteSlice>(
31 &mut self,
32 update_sink: &mut UpdateSink,
33 msg1: GroupKeyHandshakeFrame<B>,
34 ) -> Result<(), Error> {
35 let (frame, key_data) = match msg1.get() {
36 Dot11VerifiedKeyFrame::WithUnverifiedMic(unverified_mic) => {
37 match unverified_mic.verify_mic(&self.kck[..], &self.cfg.protection)? {
38 UnverifiedKeyData::Encrypted(encrypted) => {
39 encrypted.decrypt(&self.kek[..], &self.cfg.protection)?
40 }
41 UnverifiedKeyData::NotEncrypted(keyframe) => {
42 match self.cfg.protection.protection_type {
43 ProtectionType::LegacyWpa1 => {
44 let algorithm = &self.cfg.protection.keywrap_algorithm()?;
48 let key_data = algorithm.unwrap_key(
49 &self.kek[..],
50 &keyframe.key_frame_fields.key_iv,
51 &keyframe.key_data[..],
52 )?;
53 (keyframe, key_data)
54 }
55 _ => {
56 return Err(format_rsn_err!(
57 "msg1 of Group-Key Handshake must carry encrypted key data"
58 ))
59 }
60 }
61 }
62 }
63 }
64 Dot11VerifiedKeyFrame::WithoutMic(_) => {
65 return Err(format_rsn_err!("msg1 of Group-Key Handshake must carry a MIC"))
66 }
67 };
68
69 let (gtk, igtk) = self.extract_key_data(&frame, &key_data[..])?;
71
72 match (igtk.is_some(), self.cfg.protection.igtk_support()) {
73 (true, IgtkSupport::Unsupported) | (false, IgtkSupport::Required) => {
74 return Err(Error::InvalidKeyDataContent);
75 }
76 _ => (),
77 }
78
79 let msg2 = self.create_message_2(&frame)?;
81 update_sink.push(SecAssocUpdate::TxEapolKeyFrame { frame: msg2, expect_response: false });
82 update_sink.push(SecAssocUpdate::Key(Key::Gtk(gtk)));
83 if let Some(igtk) = igtk {
84 update_sink.push(SecAssocUpdate::Key(Key::Igtk(igtk)));
85 }
86
87 Ok(())
88 }
89
90 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
91 fn extract_key_data<B: SplitByteSlice>(
92 &self,
93 frame: &eapol::KeyFrameRx<B>,
94 key_data: &[u8],
95 ) -> Result<(Gtk, Option<Igtk>), Error> {
96 let (gtk, igtk) = match self.cfg.protection.protection_type {
97 ProtectionType::LegacyWpa1 => {
98 let key_id = frame.key_frame_fields.key_info().legacy_wpa1_key_id() as u8;
99 (key_data::kde::Gtk::new(key_id, GtkInfoTx::BothRxTx, key_data), None)
100 }
101 _ => {
102 let mut gtk = None;
103 let mut igtk = None;
104 for element in key_data::extract_elements(key_data)? {
105 match element {
106 key_data::Element::Gtk(_, e) => gtk = Some(e),
107 key_data::Element::Igtk(_, e) => igtk = Some(e),
108 _ => (),
109 }
110 }
111 (
112 gtk.ok_or(format_rsn_err!(
113 "GTK KDE not present in key data of Group-Key Handshakes's 1st message"
114 ))?,
115 igtk,
116 )
117 }
118 };
119
120 let key_rsc = frame.key_frame_fields.key_rsc.to_native();
121 Ok((
122 Gtk::from_bytes(
123 gtk.gtk,
124 self.cfg.protection.group_data.clone(),
125 gtk.info.key_id(),
126 key_rsc,
127 )?,
128 igtk.map(|element| Igtk::from_kde(element, self.cfg.protection.group_mgmt_cipher())),
129 ))
130 }
131
132 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
134 fn create_message_2<B: SplitByteSlice>(
135 &self,
136 msg1: &eapol::KeyFrameRx<B>,
137 ) -> Result<KeyFrameBuf, Error> {
138 let mut key_info = eapol::KeyInformation(0)
139 .with_key_descriptor_version(msg1.key_frame_fields.key_info().key_descriptor_version())
140 .with_key_type(msg1.key_frame_fields.key_info().key_type())
141 .with_key_mic(true)
142 .with_secure(true);
143
144 if msg1.key_frame_fields.descriptor_type == eapol::KeyDescriptor::LEGACY_WPA1 {
145 key_info = key_info
146 .with_legacy_wpa1_key_id(msg1.key_frame_fields.key_info().legacy_wpa1_key_id());
147 }
148
149 let msg2 = eapol::KeyFrameTx::new(
150 msg1.eapol_fields.version,
151 eapol::KeyFrameFields::new(
152 msg1.key_frame_fields.descriptor_type,
153 key_info,
154 0,
155 msg1.key_frame_fields.key_replay_counter.to_native(),
156 [0u8; 32], [0u8; 16], 0, ),
160 vec![],
161 self.cfg.protection.akm.mic_bytes().ok_or(Error::UnsupportedAkmSuite)? as usize,
162 )
163 .serialize();
164 let mic =
165 compute_mic_from_buf(&self.kck[..], &self.cfg.protection, msg2.unfinalized_buf())?;
166 msg2.finalize_with_mic(&mic[..]).map_err(|e| e.into())
167 }
168
169 pub fn destroy(self) -> Config {
170 self.cfg
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177 use crate::key::exchange::handshake::group_key::GroupKey;
178 use crate::key_data::kde;
179 use crate::rsna::{test_util, NegotiatedProtection, Role};
180 use lazy_static::lazy_static;
181 use wlan_common::big_endian::BigEndianU64;
182 use wlan_common::ie::rsn::cipher::{Cipher, CIPHER_BIP_CMAC_128, CIPHER_CCMP_128, TKIP};
183 use wlan_common::organization::Oui;
184
185 lazy_static! {
186 static ref GTK: Box<[u8]> = vec![3; 16].into_boxed_slice();
187 static ref WPA1_GTK: Box<[u8]> = vec![3; 32].into_boxed_slice();
188 }
189
190 const KCK: [u8; 16] = [1; 16];
191 const KEK: [u8; 16] = [2; 16];
192 const IGTK: [u8; 16] = [4; 16];
193 const GTK_RSC: u64 = 81234;
194 const GTK_KEY_ID: u8 = 2;
195 const IGTK_IPN: [u8; 6] = [0xab; 6];
196 const IGTK_KEY_ID: u16 = 4;
197
198 fn make_verified<B: SplitByteSlice>(
199 key_frame: eapol::KeyFrameRx<B>,
200 role: Role,
201 protection: &NegotiatedProtection,
202 ) -> Result<Dot11VerifiedKeyFrame<B>, Error> {
203 Dot11VerifiedKeyFrame::from_frame(key_frame, &role, protection, 0)
204 }
205
206 enum Msg1Config {
207 Wpa2,
208 Wpa3,
209 }
210
211 fn fake_msg1(protection_type: Msg1Config) -> eapol::KeyFrameBuf {
212 let mut w = kde::Writer::new();
213 w.write_gtk(&kde::Gtk::new(GTK_KEY_ID, kde::GtkInfoTx::BothRxTx, >K[..]))
214 .expect("error writing GTK KDE");
215 if let Msg1Config::Wpa3 = &protection_type {
216 w.write_igtk(&kde::Igtk::new(IGTK_KEY_ID, &IGTK_IPN[..], &IGTK[..]))
217 .expect("error writing IGTK KDE");
218 }
219 let key_data = w.finalize_for_encryption().expect("error finalizing key data");
220 let encrypted_key_data =
221 test_util::encrypt_key_data(&KEK[..], &test_util::get_rsne_protection(), &key_data[..]);
222
223 let mut key_info = eapol::KeyInformation::default();
224 key_info.set_key_ack(true);
225 key_info.set_key_mic(true);
226 key_info.set_secure(true);
227 key_info.set_encrypted_key_data(true);
228 key_info.set_key_descriptor_version(match &protection_type {
229 Msg1Config::Wpa2 => 2,
230 Msg1Config::Wpa3 => 0,
231 });
232 let mut key_frame_fields: eapol::KeyFrameFields = Default::default();
233 key_frame_fields.set_key_info(key_info);
234 key_frame_fields.key_rsc = BigEndianU64::from_native(GTK_RSC);
235 key_frame_fields.descriptor_type = eapol::KeyDescriptor::IEEE802DOT11;
236 let key_frame = eapol::KeyFrameTx::new(
237 eapol::ProtocolVersion::IEEE802DOT1X2004,
238 key_frame_fields,
239 encrypted_key_data,
240 16,
241 )
242 .serialize();
243 let protection = match &protection_type {
244 Msg1Config::Wpa2 => test_util::get_rsne_protection(),
245 Msg1Config::Wpa3 => test_util::get_wpa3_protection(),
246 };
247 let mic = compute_mic_from_buf(&KCK[..], &protection, key_frame.unfinalized_buf())
248 .expect("error updating MIC");
249 key_frame.finalize_with_mic(&mic[..]).expect("error finalizing keyframe")
250 }
251
252 fn fake_gtk() -> Gtk {
253 Gtk::from_bytes(GTK.clone(), CIPHER_CCMP_128, GTK_KEY_ID, GTK_RSC)
254 .expect("error creating expected GTK")
255 }
256
257 fn fake_igtk() -> Igtk {
258 Igtk {
259 igtk: IGTK.to_vec(),
260 ipn: IGTK_IPN,
261 key_id: IGTK_KEY_ID,
262 cipher: CIPHER_BIP_CMAC_128,
263 }
264 }
265
266 fn fake_msg1_wpa1_deprecated() -> eapol::KeyFrameBuf {
267 let encrypted_key_data =
268 test_util::encrypt_key_data(&KEK[..], &test_util::get_wpa1_protection(), &WPA1_GTK[..]);
269
270 let mut key_frame_fields: eapol::KeyFrameFields = Default::default();
271 key_frame_fields.set_key_info(
272 eapol::KeyInformation::default()
273 .with_key_descriptor_version(1)
274 .with_legacy_wpa1_key_id(GTK_KEY_ID as u16)
275 .with_key_ack(true)
276 .with_key_mic(true)
277 .with_secure(true),
278 );
279 key_frame_fields.key_rsc = BigEndianU64::from_native(GTK_RSC);
280 key_frame_fields.descriptor_type = eapol::KeyDescriptor::LEGACY_WPA1;
281 let key_frame = eapol::KeyFrameTx::new(
282 eapol::ProtocolVersion::IEEE802DOT1X2001,
283 key_frame_fields,
284 encrypted_key_data,
285 16,
286 )
287 .serialize();
288 let mic = compute_mic_from_buf(
289 &KCK[..],
290 &test_util::get_wpa1_protection(),
291 key_frame.unfinalized_buf(),
292 )
293 .expect("error updating MIC");
294 key_frame.finalize_with_mic(&mic[..]).expect("error finalizing keyframe")
295 }
296
297 fn fake_gtk_wpa1() -> Gtk {
298 Gtk::from_bytes(
299 WPA1_GTK.clone(),
300 Cipher { oui: Oui::MSFT, suite_type: TKIP },
301 GTK_KEY_ID,
302 GTK_RSC,
303 )
304 .expect("error creating expected GTK")
305 }
306
307 #[test]
308 fn full_supplicant_test() {
309 let protection = test_util::get_rsne_protection();
310 let mut handshake = GroupKey::new(
311 Config { role: Role::Supplicant, protection: protection.clone() },
312 &KCK[..],
313 &KEK[..],
314 )
315 .expect("error creating Group Key Handshake");
316
317 let mut update_sink = UpdateSink::default();
319 let msg1 = fake_msg1(Msg1Config::Wpa2);
320 let keyframe = msg1.keyframe();
321 let msg1_verified = make_verified(keyframe, Role::Supplicant, &protection)
322 .expect("error verifying group frame");
323 handshake
324 .on_eapol_key_frame(&mut update_sink, msg1_verified)
325 .expect("error processing msg1 of Group Key Handshake");
326
327 let actual_gtk = test_util::expect_reported_gtk(&update_sink);
329 let expected_gtk = fake_gtk();
330 assert_eq!(actual_gtk, expected_gtk);
331 }
332
333 #[test]
334 fn full_wpa3_supplicant_test() {
335 let protection = test_util::get_wpa3_protection();
336 let mut handshake = GroupKey::new(
337 Config { role: Role::Supplicant, protection: protection.clone() },
338 &KCK[..],
339 &KEK[..],
340 )
341 .expect("error creating Group Key Handshake");
342
343 let mut update_sink = UpdateSink::default();
345 let msg1 = fake_msg1(Msg1Config::Wpa3);
346 let keyframe = msg1.keyframe();
347 let msg1_verified = make_verified(keyframe, Role::Supplicant, &protection)
348 .expect("error verifying group frame");
349 handshake
350 .on_eapol_key_frame(&mut update_sink, msg1_verified)
351 .expect("error processing msg1 of Group Key Handshake");
352
353 let actual_gtk = test_util::expect_reported_gtk(&update_sink);
355 let expected_gtk = fake_gtk();
356 assert_eq!(actual_gtk, expected_gtk);
357 let actual_igtk = test_util::expect_reported_igtk(&update_sink);
358 let expected_igtk = fake_igtk();
359 assert_eq!(actual_igtk, expected_igtk);
360 }
361
362 #[test]
363 fn full_wpa1_supplicant_test() {
364 let protection = test_util::get_wpa1_protection();
365 let mut handshake = GroupKey::new(
366 Config { role: Role::Supplicant, protection: protection.clone() },
367 &KCK[..],
368 &KEK[..],
369 )
370 .expect("error creating Group Key Handshake");
371
372 let mut update_sink = UpdateSink::default();
374 let msg1 = fake_msg1_wpa1_deprecated();
375 let keyframe = msg1.keyframe();
376 let msg1_verified = make_verified(keyframe, Role::Supplicant, &protection)
377 .expect("error verifying group frame");
378 handshake
379 .on_eapol_key_frame(&mut update_sink, msg1_verified)
380 .expect("error processing msg1 of Group Key Handshake");
381
382 let actual_gtk = test_util::expect_reported_gtk(&update_sink);
384 let expected_gtk = fake_gtk_wpa1();
385 assert_eq!(actual_gtk, expected_gtk);
386 }
387}