1use crate::key::exchange::handshake::fourway::{self, Config, FourwayHandshakeFrame};
6use crate::key::exchange::{compute_mic_from_buf, Key};
7use crate::key::gtk::Gtk;
8use crate::key::igtk::Igtk;
9use crate::key::ptk::Ptk;
10use crate::key::Tk;
11use crate::key_data::kde;
12use crate::nonce::Nonce;
13use crate::rsna::{
14 Dot11VerifiedKeyFrame, IgtkSupport, NegotiatedProtection, ProtectionType, SecAssocUpdate,
15 UnverifiedKeyData, UpdateSink,
16};
17use crate::{key_data, Error, ProtectionInfo};
18use anyhow::{ensure, format_err};
19use eapol::KeyFrameBuf;
20use log::error;
21use zerocopy::SplitByteSlice;
22
23fn handle_message_1<B: SplitByteSlice>(
25 cfg: &Config,
26 pmk: &[u8],
27 snonce: &[u8],
28 msg1: FourwayHandshakeFrame<B>,
29) -> Result<(KeyFrameBuf, Ptk, Nonce), anyhow::Error> {
30 let frame = match msg1.get() {
31 Dot11VerifiedKeyFrame::WithUnverifiedMic(_) => {
33 return Err(format_err!("msg1 of 4-Way Handshake cannot carry a MIC"))
34 }
35 Dot11VerifiedKeyFrame::WithoutMic(frame) => frame,
36 };
37 let anonce = frame.key_frame_fields.key_nonce;
38 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
39
40 let pairwise = protection.pairwise.clone();
41 let ptk =
42 Ptk::new(pmk, &cfg.a_addr, &cfg.s_addr, &anonce[..], snonce, &protection.akm, pairwise)?;
43 let msg2 = create_message_2(cfg, ptk.kck(), &protection, &frame, &snonce[..])?;
44
45 Ok((msg2, ptk, anonce))
46}
47
48fn create_message_2<B: SplitByteSlice>(
50 cfg: &Config,
51 kck: &[u8],
52 protection: &NegotiatedProtection,
53 msg1: &eapol::KeyFrameRx<B>,
54 snonce: &[u8],
55) -> Result<KeyFrameBuf, anyhow::Error> {
56 let key_info = eapol::KeyInformation(0)
57 .with_key_descriptor_version(msg1.key_frame_fields.key_info().key_descriptor_version())
58 .with_key_type(msg1.key_frame_fields.key_info().key_type())
59 .with_key_mic(true);
60
61 let mut w = kde::Writer::new();
62 w.write_protection(&cfg.s_protection)?;
63 let key_data = w.finalize_for_plaintext()?.into();
64
65 let msg2 = eapol::KeyFrameTx::new(
66 msg1.eapol_fields.version,
67 eapol::KeyFrameFields::new(
68 msg1.key_frame_fields.descriptor_type,
69 key_info,
70 0,
71 msg1.key_frame_fields.key_replay_counter.to_native(),
72 eapol::to_array(snonce),
73 [0u8; 16], 0, ),
76 key_data,
77 msg1.key_mic.len(),
78 )
79 .serialize();
80
81 let mic = compute_mic_from_buf(kck, &protection, msg2.unfinalized_buf())
82 .map_err(|e| anyhow::Error::from(e))?;
83 msg2.finalize_with_mic(&mic[..]).map_err(|e| e.into())
84}
85
86fn handle_message_3<B: SplitByteSlice>(
90 cfg: &Config,
91 kck: &[u8],
92 kek: &[u8],
93 msg3: FourwayHandshakeFrame<B>,
94) -> Result<(KeyFrameBuf, Option<Gtk>, Option<Igtk>), anyhow::Error> {
95 let negotiated_protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
96 let (frame, key_data_elements) = match msg3.get() {
97 Dot11VerifiedKeyFrame::WithUnverifiedMic(unverified_mic) => {
98 match unverified_mic.verify_mic(kck, &negotiated_protection)? {
99 UnverifiedKeyData::Encrypted(encrypted) => {
100 let key_data = encrypted.decrypt(kek, &negotiated_protection)?;
101 (key_data.0, key_data::extract_elements(&key_data.1[..])?)
102 }
103 UnverifiedKeyData::NotEncrypted(keyframe) => {
104 match negotiated_protection.protection_type {
105 ProtectionType::LegacyWpa1 => {
106 let elements = key_data::extract_elements(&keyframe.key_data[..])?;
109 (keyframe, elements)
110 }
111 _ => {
112 return Err(format_err!(
113 "msg3 of 4-Way Handshake must carry encrypted key data"
114 ))
115 }
116 }
117 }
118 }
119 }
120 Dot11VerifiedKeyFrame::WithoutMic(_) => {
121 return Err(format_err!("msg3 of 4-Way Handshake must carry a MIC"))
122 }
123 };
124 let mut gtk: Option<key_data::kde::Gtk> = None;
125 let mut igtk: Option<Igtk> = None;
126 let mut protection: Option<ProtectionInfo> = None;
127 #[allow(clippy::collection_is_never_read)]
128 let mut _second_protection: Option<ProtectionInfo> = None;
129 for element in key_data_elements {
130 match (element, &protection) {
131 (key_data::Element::Gtk(_, e), _) => gtk = Some(e),
132 (key_data::Element::Igtk(_, e), _) => {
133 igtk = Some(Igtk::from_kde(e, negotiated_protection.group_mgmt_cipher()))
134 }
135 (key_data::Element::Rsne(e), None) => protection = Some(ProtectionInfo::Rsne(e)),
136 (key_data::Element::Rsne(e), Some(_)) => {
137 _second_protection = Some(ProtectionInfo::Rsne(e))
138 }
139 (key_data::Element::LegacyWpa1(e), None) => {
140 protection = Some(ProtectionInfo::LegacyWpa(e))
141 }
142 _ => (),
143 }
144 }
145 match (igtk.is_some(), negotiated_protection.igtk_support()) {
146 (true, IgtkSupport::Unsupported) | (false, IgtkSupport::Required) => {
147 return Err(format_err!(Error::InvalidKeyDataContent));
148 }
149 _ => (),
150 }
151
152 let msg4 = match protection {
154 Some(protection) => {
155 ensure!(&protection == &cfg.a_protection, Error::InvalidKeyDataProtection);
156 create_message_4(&negotiated_protection, kck, &frame)?
157 }
158 None => return Err(format_err!(Error::InvalidKeyDataContent)),
159 };
160 match gtk {
161 Some(gtk) => {
162 let rsc = frame.key_frame_fields.key_rsc.to_native();
163 Ok((
164 msg4,
165 Some(Gtk::from_bytes(
166 gtk.gtk,
167 negotiated_protection.group_data,
168 gtk.info.key_id(),
169 rsc,
170 )?),
171 igtk,
172 ))
173 }
174 None if negotiated_protection.protection_type == ProtectionType::LegacyWpa1 => {
176 Ok((msg4, None, None))
177 }
178 None => return Err(format_err!(Error::InvalidKeyDataContent)),
179 }
180}
181
182fn create_message_4<B: SplitByteSlice>(
184 protection: &NegotiatedProtection,
185 kck: &[u8],
186 msg3: &eapol::KeyFrameRx<B>,
187) -> Result<KeyFrameBuf, anyhow::Error> {
188 let secure_bit = msg3.key_frame_fields.descriptor_type != eapol::KeyDescriptor::LEGACY_WPA1;
191 let key_info = eapol::KeyInformation(0)
192 .with_key_descriptor_version(msg3.key_frame_fields.key_info().key_descriptor_version())
193 .with_key_type(msg3.key_frame_fields.key_info().key_type())
194 .with_key_mic(true)
195 .with_secure(secure_bit);
196
197 let msg4 = eapol::KeyFrameTx::new(
198 msg3.eapol_fields.version,
199 eapol::KeyFrameFields::new(
200 msg3.key_frame_fields.descriptor_type,
201 key_info,
202 0,
203 msg3.key_frame_fields.key_replay_counter.to_native(),
204 [0u8; 32], [0u8; 16], 0, ),
208 vec![],
209 msg3.key_mic.len(),
210 )
211 .serialize();
212
213 let mic = compute_mic_from_buf(kck, &protection, msg4.unfinalized_buf())
214 .map_err(|e| anyhow::Error::from(e))?;
215 msg4.finalize_with_mic(&mic[..]).map_err(|e| e.into())
216}
217
218#[derive(Debug, PartialEq)]
219pub enum State {
220 AwaitingMsg1 { pmk: Vec<u8>, cfg: Config, snonce: Nonce },
221 AwaitingMsg3 { pmk: Vec<u8>, ptk: Ptk, snonce: Nonce, anonce: Nonce, cfg: Config },
222 KeysInstalled { pmk: Vec<u8>, ptk: Ptk, gtk: Option<Gtk>, igtk: Option<Igtk>, cfg: Config },
223}
224
225pub fn new(cfg: Config, pmk: Vec<u8>) -> State {
226 let snonce = cfg.nonce_rdr.next();
227 State::AwaitingMsg1 { pmk, cfg, snonce }
228}
229
230impl State {
231 pub fn on_eapol_key_frame<B: SplitByteSlice>(
232 self,
233 update_sink: &mut UpdateSink,
234 frame: FourwayHandshakeFrame<B>,
235 ) -> Self {
236 match self {
237 State::AwaitingMsg1 { pmk, cfg, snonce } => match frame.message_number() {
238 fourway::MessageNumber::Message1 => {
239 match handle_message_1(&cfg, &pmk[..], &snonce[..], frame) {
240 Err(e) => {
241 error!("error: {}", e);
242 return State::AwaitingMsg1 { pmk, cfg, snonce };
245 }
246 Ok((msg2, ptk, anonce)) => {
247 update_sink.push(SecAssocUpdate::TxEapolKeyFrame {
248 frame: msg2,
249 expect_response: true,
250 });
251 State::AwaitingMsg3 { pmk, ptk, cfg, snonce, anonce }
252 }
253 }
254 }
255 unexpected_msg => {
256 error!("error: {}", Error::UnexpectedHandshakeMessage(unexpected_msg.into()));
257 State::AwaitingMsg1 { pmk, cfg, snonce }
259 }
260 },
261 State::AwaitingMsg3 { pmk, ptk, cfg, snonce, anonce: expected_anonce, .. } => {
262 match frame.message_number() {
263 fourway::MessageNumber::Message1 => {
265 let actual_anonce = frame.unsafe_get_raw().key_frame_fields.key_nonce;
287 let snonce = if expected_anonce != actual_anonce {
288 cfg.nonce_rdr.next()
289 } else {
290 snonce
291 };
292 State::AwaitingMsg1 { pmk, cfg, snonce }
293 .on_eapol_key_frame(update_sink, frame)
294 }
295 fourway::MessageNumber::Message3 => {
298 match handle_message_3(&cfg, ptk.kck(), ptk.kek(), frame) {
299 Err(e) => {
300 error!("error: {}", e);
301 State::AwaitingMsg1 { pmk, cfg, snonce }
304 }
305 Ok((msg4, gtk, igtk)) => {
306 update_sink.push(SecAssocUpdate::TxEapolKeyFrame {
307 frame: msg4,
308 expect_response: false,
309 });
310 update_sink.push(SecAssocUpdate::Key(Key::Ptk(ptk.clone())));
311 if let Some(gtk) = gtk.as_ref() {
312 update_sink.push(SecAssocUpdate::Key(Key::Gtk(gtk.clone())))
313 }
314 if let Some(igtk) = igtk.as_ref() {
315 update_sink.push(SecAssocUpdate::Key(Key::Igtk(igtk.clone())))
316 }
317 State::KeysInstalled { pmk, ptk, gtk, igtk, cfg }
318 }
319 }
320 }
321 unexpected_msg => {
322 error!(
323 "error: {}",
324 Error::UnexpectedHandshakeMessage(unexpected_msg.into())
325 );
326 State::AwaitingMsg1 { pmk, cfg, snonce }
328 }
329 }
330 }
331 State::KeysInstalled {
332 ref ptk,
333 gtk: ref expected_gtk,
334 igtk: ref expected_igtk,
335 ref cfg,
336 ..
337 } => {
338 match frame.message_number() {
339 fourway::MessageNumber::Message3 => {
343 match handle_message_3(cfg, ptk.kck(), ptk.kek(), frame) {
344 Err(e) => error!("error: {}", e),
345 Ok((msg4, gtk, igtk)) => {
352 let gtk_unchanged = match (gtk, expected_gtk) {
353 (None, None) => true,
354 (Some(ref gtk_val), Some(expected_gtk_val)) => {
355 gtk_val.eq_tk(expected_gtk_val)
356 }
357 _ => false,
358 };
359 let igtk_unchanged = match (igtk, expected_igtk) {
360 (None, None) => true,
361 (Some(ref igtk_val), Some(expected_igtk_val)) => {
362 igtk_val.eq_tk(expected_igtk_val)
363 }
364 _ => false,
365 };
366
367 if gtk_unchanged && igtk_unchanged {
368 update_sink.push(SecAssocUpdate::TxEapolKeyFrame {
369 frame: msg4,
370 expect_response: false,
371 });
372 } else {
373 error!("error: GTK or IGTK differs in replayed 3rd message");
374 }
378 }
379 };
380 }
381 unexpected_msg => {
382 error!(
383 "ignoring message {:?}; 4-Way Handshake already completed",
384 unexpected_msg
385 );
386 }
387 };
388
389 self
390 }
391 }
392 }
393
394 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
395 pub fn on_rsna_response_timeout(&self) -> Result<(), Error> {
396 match self {
397 State::AwaitingMsg1 { .. } => Err(Error::EapolHandshakeNotStarted),
398 State::AwaitingMsg3 { .. } => Err(Error::LikelyWrongCredential),
399 State::KeysInstalled { .. } => Ok(()),
400 }
401 }
402
403 pub fn anonce(&self) -> Option<&[u8]> {
404 match self {
405 State::AwaitingMsg1 { .. } => None,
406 State::AwaitingMsg3 { anonce, .. } => Some(&anonce[..]),
407 State::KeysInstalled { .. } => None,
408 }
409 }
410
411 pub fn ptk(&self) -> Option<Ptk> {
412 match self {
413 State::AwaitingMsg3 { ptk, .. } => Some(ptk.clone()),
414 State::KeysInstalled { ptk, .. } => Some(ptk.clone()),
415 _ => None,
416 }
417 }
418
419 pub fn gtk(&self) -> Option<Gtk> {
420 match self {
421 State::KeysInstalled { gtk, .. } => gtk.clone(),
422 _ => None,
423 }
424 }
425
426 pub fn igtk(&self) -> Option<Igtk> {
427 match self {
428 State::KeysInstalled { igtk, .. } => igtk.clone(),
429 _ => None,
430 }
431 }
432
433 pub fn destroy(self) -> fourway::Config {
434 match self {
435 State::AwaitingMsg1 { cfg, .. } => cfg,
436 State::AwaitingMsg3 { cfg, .. } => cfg,
437 State::KeysInstalled { cfg, .. } => cfg,
438 }
439 }
440}