1use crate::key::exchange::handshake::fourway::{
6 self, AuthenticatorKeyReplayCounter, Config, FourwayHandshakeFrame, SupplicantKeyReplayCounter,
7};
8use crate::key::exchange::{compute_mic_from_buf, Key};
9use crate::key::gtk::Gtk;
10use crate::key::igtk::Igtk;
11use crate::key::ptk::Ptk;
12use crate::key::Tk;
13use crate::key_data::kde;
14use crate::nonce::Nonce;
15use crate::rsna::{
16 derive_key_descriptor_version, Dot11VerifiedKeyFrame, NegotiatedProtection, SecAssocUpdate,
17 UnverifiedKeyData, UpdateSink,
18};
19use crate::Error;
20use anyhow::{ensure, format_err};
21use log::{error, warn};
22use std::fmt;
23use zerocopy::SplitByteSlice;
24
25#[derive(Debug, PartialEq)]
26pub enum State {
27 Idle {
28 pmk: Vec<u8>,
29 cfg: Config,
30 },
31 AwaitingMsg2 {
32 pmk: Vec<u8>,
33 cfg: Config,
34 anonce: Nonce,
35 key_replay_counter: AuthenticatorKeyReplayCounter,
36 },
37 AwaitingMsg4 {
38 pmk: Vec<u8>,
39 ptk: Ptk,
40 gtk: Gtk,
41 igtk: Option<Igtk>,
42 cfg: Config,
43 key_replay_counter: AuthenticatorKeyReplayCounter,
44 },
45 KeysInstalled {
46 pmk: Vec<u8>,
47 ptk: Ptk,
48 gtk: Gtk,
49 igtk: Option<Igtk>,
50 cfg: Config,
51 },
52}
53
54impl fmt::Display for State {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(
57 f,
58 "{}",
59 match self {
60 State::Idle { .. } => "Idle",
61 State::AwaitingMsg2 { .. } => "AwaitingMsg2",
62 State::AwaitingMsg4 { .. } => "AwaitingMsg4",
63 State::KeysInstalled { .. } => "KeysInstalled",
64 }
65 )
66 }
67}
68
69pub fn new(cfg: Config, pmk: Vec<u8>) -> State {
70 State::Idle { pmk, cfg }
71}
72
73impl State {
74 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
75 pub fn initiate(
79 self,
80 update_sink: &mut UpdateSink,
81 s_key_replay_counter: SupplicantKeyReplayCounter,
82 ) -> Result<Self, Error> {
83 let key_replay_counter = AuthenticatorKeyReplayCounter::next_after(*s_key_replay_counter);
84 match self {
85 State::Idle { cfg, pmk } => {
86 let anonce = cfg.nonce_rdr.next();
87 match initiate_internal(update_sink, &cfg, key_replay_counter, &anonce[..]) {
88 Ok(()) => Ok(State::AwaitingMsg2 { anonce, cfg, pmk, key_replay_counter }),
89 Err(e) => Err(Error::GenericError(format!("{}", e))),
90 }
91 }
92 other_state => Err(Error::GenericError(format!(
93 "Failed to initiate Authenticator, currently in {} state",
94 other_state
95 ))),
96 }
97 }
98
99 pub fn on_eapol_key_frame<B: SplitByteSlice>(
100 self,
101 update_sink: &mut UpdateSink,
102 frame: FourwayHandshakeFrame<B>,
103 ) -> Self {
104 match self {
105 State::Idle { cfg, pmk } => {
106 error!("received EAPOL Key frame before initiate 4-Way Handshake");
107 State::Idle { cfg, pmk }
108 }
109 State::AwaitingMsg2 { pmk, cfg, anonce, key_replay_counter } => {
110 match frame.message_number() {
112 fourway::MessageNumber::Message2 => {
113 match process_message_2(
114 update_sink,
115 &pmk[..],
116 &cfg,
117 &anonce[..],
118 key_replay_counter,
119 frame,
120 ) {
121 Ok((ptk, gtk, igtk, key_replay_counter)) => {
122 State::AwaitingMsg4 { pmk, ptk, gtk, igtk, cfg, key_replay_counter }
123 }
124 Err(e) => {
125 warn!("Unable to process second EAPOL handshake key frame from supplicant: {}", e);
126 State::AwaitingMsg2 { pmk, cfg, anonce, key_replay_counter }
127 }
128 }
129 }
130 unexpected_msg => {
131 error!(
132 "error: {:?}",
133 Error::UnexpectedHandshakeMessage(unexpected_msg.into())
134 );
135 State::AwaitingMsg2 { pmk, cfg, anonce, key_replay_counter }
136 }
137 }
138 }
139 State::AwaitingMsg4 { pmk, ptk, gtk, igtk, cfg, key_replay_counter } => {
140 match process_message_4(
141 update_sink,
142 &cfg,
143 &ptk,
144 >k,
145 &igtk,
146 key_replay_counter,
147 frame,
148 ) {
149 Ok(()) => State::KeysInstalled { pmk, ptk, gtk, igtk, cfg },
150 Err(e) => {
151 error!("error: {}", e);
152 State::AwaitingMsg4 { pmk, ptk, gtk, igtk, cfg, key_replay_counter }
153 }
154 }
155 }
156 other_state => other_state,
157 }
158 }
159
160 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
161 pub fn on_rsna_response_timeout(&self) -> Result<(), Error> {
162 match self {
163 State::AwaitingMsg2 { .. } => Err(Error::EapolHandshakeIncomplete(
164 "Client never responded to EAPOL message 1".to_string(),
165 )),
166 State::AwaitingMsg4 { .. } => Err(Error::EapolHandshakeIncomplete(
167 "Client never responded to EAPOL message 3".to_string(),
168 )),
169 _ => Ok(()),
170 }
171 }
172
173 pub fn ptk(&self) -> Option<Ptk> {
174 match self {
175 State::AwaitingMsg4 { ptk, .. } | State::KeysInstalled { ptk, .. } => Some(ptk.clone()),
176 _ => None,
177 }
178 }
179
180 pub fn gtk(&self) -> Option<Gtk> {
181 match self {
182 State::AwaitingMsg4 { gtk, .. } | State::KeysInstalled { gtk, .. } => Some(gtk.clone()),
183 _ => None,
184 }
185 }
186
187 pub fn igtk(&self) -> Option<Igtk> {
188 match self {
189 State::AwaitingMsg4 { igtk, .. } | State::KeysInstalled { igtk, .. } => igtk.clone(),
190 _ => None,
191 }
192 }
193
194 pub fn destroy(self) -> Config {
195 match self {
196 State::Idle { cfg, .. } => cfg,
197 State::AwaitingMsg2 { cfg, .. } => cfg,
198 State::AwaitingMsg4 { cfg, .. } => cfg,
199 State::KeysInstalled { cfg, .. } => cfg,
200 }
201 }
202}
203
204fn initiate_internal(
205 update_sink: &mut UpdateSink,
206 cfg: &Config,
207 key_replay_counter: AuthenticatorKeyReplayCounter,
208 anonce: &[u8],
209) -> Result<(), anyhow::Error> {
210 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
211 let msg1 = create_message_1(anonce, &protection, key_replay_counter)?;
212 update_sink.push(SecAssocUpdate::TxEapolKeyFrame { frame: msg1, expect_response: true });
213 Ok(())
214}
215
216fn process_message_2<B: SplitByteSlice>(
217 update_sink: &mut UpdateSink,
218 pmk: &[u8],
219 cfg: &Config,
220 anonce: &[u8],
221 key_replay_counter: AuthenticatorKeyReplayCounter,
222 frame: FourwayHandshakeFrame<B>,
223) -> Result<(Ptk, Gtk, Option<Igtk>, AuthenticatorKeyReplayCounter), anyhow::Error> {
224 let ptk = handle_message_2(&pmk[..], &cfg, &anonce[..], key_replay_counter, frame)?;
225 let gtk = cfg
226 .gtk_provider
227 .as_ref()
228 .ok_or_else(|| format_err!("GtkProvider is missing"))?
230 .lock()
231 .unwrap()
232 .get_gtk()
233 .clone();
234 let igtk = match fourway::get_group_mgmt_cipher(&cfg.s_protection, &cfg.a_protection)
235 .map_err(|e| format_err!("group mgmt cipher error: {:?}", e))?
236 {
237 Some(group_mgmt_cipher) => {
238 let igtk_provider = cfg
239 .igtk_provider
240 .as_ref()
241 .ok_or_else(|| format_err!("IgtkProvider is missing"))?
243 .lock()
244 .unwrap();
245 let igtk_provider_cipher = igtk_provider.cipher();
246 if group_mgmt_cipher != igtk_provider_cipher {
247 return Err(format_err!(
249 "wrong IgtkProvider cipher: {:?} != {:?}",
250 group_mgmt_cipher,
251 igtk_provider_cipher
252 ));
253 }
254 Some(igtk_provider.get_igtk())
255 }
256 None => None,
257 };
258 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
259 let key_replay_counter = AuthenticatorKeyReplayCounter::next_after(*key_replay_counter);
260 let msg3 = create_message_3(
261 &cfg,
262 ptk.kck(),
263 ptk.kek(),
264 >k,
265 &igtk,
266 &anonce[..],
267 &protection,
268 key_replay_counter,
269 )?;
270
271 update_sink.push(SecAssocUpdate::TxEapolKeyFrame { frame: msg3, expect_response: true });
272 Ok((ptk, gtk, igtk, key_replay_counter))
273}
274
275fn process_message_4<B: SplitByteSlice>(
276 update_sink: &mut UpdateSink,
277 cfg: &Config,
278 ptk: &Ptk,
279 gtk: &Gtk,
280 igtk: &Option<Igtk>,
281 key_replay_counter: AuthenticatorKeyReplayCounter,
282 frame: FourwayHandshakeFrame<B>,
283) -> Result<(), anyhow::Error> {
284 handle_message_4(cfg, ptk.kck(), key_replay_counter, frame)?;
285 update_sink.push(SecAssocUpdate::Key(Key::Ptk(ptk.clone())));
286 update_sink.push(SecAssocUpdate::Key(Key::Gtk(gtk.clone())));
287 if let Some(igtk) = igtk.as_ref() {
288 update_sink.push(SecAssocUpdate::Key(Key::Igtk(igtk.clone())));
289 }
290 Ok(())
291}
292
293fn create_message_1<B: SplitByteSlice>(
295 anonce: B,
296 protection: &NegotiatedProtection,
297 key_replay_counter: AuthenticatorKeyReplayCounter,
298) -> Result<eapol::KeyFrameBuf, anyhow::Error> {
299 let version = derive_key_descriptor_version(eapol::KeyDescriptor::IEEE802DOT11, protection);
300 let key_info = eapol::KeyInformation(0)
301 .with_key_descriptor_version(version)
302 .with_key_type(eapol::KeyType::PAIRWISE)
303 .with_key_ack(true);
304
305 let key_len = match protection.pairwise.tk_bits() {
306 None => {
307 return Err(format_err!(
308 "unknown cipher used for pairwise key: {:?}",
309 protection.pairwise
310 ))
311 }
312 Some(tk_bits) => tk_bits / 8,
313 };
314 eapol::KeyFrameTx::new(
315 eapol::ProtocolVersion::IEEE802DOT1X2004,
316 eapol::KeyFrameFields::new(
317 eapol::KeyDescriptor::IEEE802DOT11,
318 key_info,
319 key_len,
320 *key_replay_counter,
321 eapol::to_array(&anonce),
322 [0u8; 16], 0, ),
325 vec![],
326 protection.mic_size as usize,
327 )
328 .serialize()
329 .finalize_without_mic()
330 .map_err(|e| e.into())
331}
332
333pub fn handle_message_2<B: SplitByteSlice>(
335 pmk: &[u8],
336 cfg: &Config,
337 anonce: &[u8],
338 key_replay_counter: AuthenticatorKeyReplayCounter,
339 frame: FourwayHandshakeFrame<B>,
340) -> Result<Ptk, anyhow::Error> {
341 let snonce = &frame.unsafe_get_raw().key_frame_fields.key_nonce[..];
344 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
345
346 let ptk = Ptk::new(
347 pmk,
348 &cfg.a_addr,
349 &cfg.s_addr,
350 anonce,
351 snonce,
352 &protection.akm,
353 protection.pairwise.clone(),
354 )?;
355
356 let frame = match frame.get() {
358 Dot11VerifiedKeyFrame::WithUnverifiedMic(unverified_mic) => {
359 match unverified_mic.verify_mic(ptk.kck(), &protection)? {
360 UnverifiedKeyData::Encrypted(_) => {
361 return Err(format_err!("msg2 of 4-Way Handshake must not be encrypted"))
362 }
363 UnverifiedKeyData::NotEncrypted(frame) => frame,
364 }
365 }
366 Dot11VerifiedKeyFrame::WithoutMic(_) => {
367 return Err(format_err!("msg2 of 4-Way Handshake must carry a MIC"))
368 }
369 };
370 ensure!(
371 frame.key_frame_fields.key_replay_counter.to_native() == *key_replay_counter,
372 "error, expected Supplicant response to message {:?} but was {:?} in msg #2",
373 *key_replay_counter,
374 frame.key_frame_fields.key_replay_counter.to_native()
375 );
376
377 Ok(ptk)
380}
381
382fn create_message_3(
384 cfg: &Config,
385 kck: &[u8],
386 kek: &[u8],
387 gtk: &Gtk,
388 igtk: &Option<Igtk>,
389 anonce: &[u8],
390 protection: &NegotiatedProtection,
391 key_replay_counter: AuthenticatorKeyReplayCounter,
392) -> Result<eapol::KeyFrameBuf, anyhow::Error> {
393 let mut w = kde::Writer::new();
395 w.write_protection(&cfg.a_protection)?;
396 w.write_gtk(&kde::Gtk::new(gtk.key_id(), kde::GtkInfoTx::BothRxTx, gtk.tk()))?;
397 if let Some(igtk) = igtk.as_ref() {
398 w.write_igtk(&kde::Igtk::new(igtk.key_id, &igtk.ipn, igtk.tk()))?;
399 }
400 let key_data = w.finalize_for_encryption()?;
401 let key_iv = [0u8; 16];
402 let encrypted_key_data =
403 protection.keywrap_algorithm()?.wrap_key(kek, &key_iv, &key_data[..])?;
404
405 let version = derive_key_descriptor_version(eapol::KeyDescriptor::IEEE802DOT11, protection);
407 let key_info = eapol::KeyInformation(0)
408 .with_key_descriptor_version(version)
409 .with_key_type(eapol::KeyType::PAIRWISE)
410 .with_key_ack(true)
411 .with_key_mic(true)
412 .with_install(true)
413 .with_secure(true)
414 .with_encrypted_key_data(true);
415
416 let key_len = match protection.pairwise.tk_bits() {
417 None => {
418 return Err(format_err!(
419 "unknown cipher used for pairwise key: {:?}",
420 protection.pairwise
421 ))
422 }
423 Some(tk_bits) => tk_bits / 8,
424 };
425
426 let msg3 = eapol::KeyFrameTx::new(
427 eapol::ProtocolVersion::IEEE802DOT1X2004,
428 eapol::KeyFrameFields::new(
429 eapol::KeyDescriptor::IEEE802DOT11,
430 key_info,
431 key_len,
432 *key_replay_counter,
433 eapol::to_array(anonce),
434 key_iv,
435 gtk.key_rsc(),
436 ),
437 encrypted_key_data,
438 protection.mic_size as usize,
439 )
440 .serialize();
441
442 let mic = compute_mic_from_buf(kck, &protection, msg3.unfinalized_buf())
443 .map_err(|e| anyhow::Error::from(e))?;
444 msg3.finalize_with_mic(&mic[..]).map_err(|e| e.into())
445}
446
447pub fn handle_message_4<B: SplitByteSlice>(
449 cfg: &Config,
450 kck: &[u8],
451 key_replay_counter: AuthenticatorKeyReplayCounter,
452 frame: FourwayHandshakeFrame<B>,
453) -> Result<(), anyhow::Error> {
454 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
455 let frame = match frame.get() {
456 Dot11VerifiedKeyFrame::WithUnverifiedMic(unverified_mic) => {
457 match unverified_mic.verify_mic(kck, &protection)? {
458 UnverifiedKeyData::Encrypted(_) => {
459 return Err(format_err!("msg4 of 4-Way Handshake must not be encrypted"))
460 }
461 UnverifiedKeyData::NotEncrypted(frame) => frame,
462 }
463 }
464 Dot11VerifiedKeyFrame::WithoutMic(_) => {
465 return Err(format_err!("msg4 of 4-Way Handshake must carry a MIC"))
466 }
467 };
468 ensure!(
469 frame.key_frame_fields.key_replay_counter.to_native() == *key_replay_counter,
470 "error, expected Supplicant response to message {:?} but was {:?} in msg #4",
471 *key_replay_counter,
472 frame.key_frame_fields.key_replay_counter.to_native()
473 );
474
475 Ok(())
478}