1use crate::Error;
6use crate::key::Tk;
7use crate::key::exchange::handshake::fourway::{
8 self, AuthenticatorKeyReplayCounter, Config, FourwayHandshakeFrame, SupplicantKeyReplayCounter,
9};
10use crate::key::exchange::{Key, compute_mic_from_buf};
11use crate::key::gtk::Gtk;
12use crate::key::igtk::Igtk;
13use crate::key::ptk::Ptk;
14use crate::key_data::kde;
15use crate::nonce::Nonce;
16use crate::rsna::{
17 Dot11VerifiedKeyFrame, NegotiatedProtection, SecAssocUpdate, UnverifiedKeyData, UpdateSink,
18 derive_key_descriptor_version,
19};
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!(
126 "Unable to process second EAPOL handshake key frame from supplicant: {}",
127 e
128 );
129 State::AwaitingMsg2 { pmk, cfg, anonce, key_replay_counter }
130 }
131 }
132 }
133 unexpected_msg => {
134 error!(
135 "error: {:?}",
136 Error::UnexpectedHandshakeMessage(unexpected_msg.into())
137 );
138 State::AwaitingMsg2 { pmk, cfg, anonce, key_replay_counter }
139 }
140 }
141 }
142 State::AwaitingMsg4 { pmk, ptk, gtk, igtk, cfg, key_replay_counter } => {
143 match process_message_4(
144 update_sink,
145 &cfg,
146 &ptk,
147 >k,
148 &igtk,
149 key_replay_counter,
150 frame,
151 ) {
152 Ok(()) => State::KeysInstalled { pmk, ptk, gtk, igtk, cfg },
153 Err(e) => {
154 error!("error: {}", e);
155 State::AwaitingMsg4 { pmk, ptk, gtk, igtk, cfg, key_replay_counter }
156 }
157 }
158 }
159 other_state => other_state,
160 }
161 }
162
163 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
164 pub fn on_rsna_response_timeout(&self) -> Result<(), Error> {
165 match self {
166 State::AwaitingMsg2 { .. } => Err(Error::EapolHandshakeIncomplete(
167 "Client never responded to EAPOL message 1".to_string(),
168 )),
169 State::AwaitingMsg4 { .. } => Err(Error::EapolHandshakeIncomplete(
170 "Client never responded to EAPOL message 3".to_string(),
171 )),
172 _ => Ok(()),
173 }
174 }
175
176 pub fn ptk(&self) -> Option<Ptk> {
177 match self {
178 State::AwaitingMsg4 { ptk, .. } | State::KeysInstalled { ptk, .. } => Some(ptk.clone()),
179 _ => None,
180 }
181 }
182
183 pub fn gtk(&self) -> Option<Gtk> {
184 match self {
185 State::AwaitingMsg4 { gtk, .. } | State::KeysInstalled { gtk, .. } => Some(gtk.clone()),
186 _ => None,
187 }
188 }
189
190 pub fn igtk(&self) -> Option<Igtk> {
191 match self {
192 State::AwaitingMsg4 { igtk, .. } | State::KeysInstalled { igtk, .. } => igtk.clone(),
193 _ => None,
194 }
195 }
196
197 pub fn destroy(self) -> Config {
198 match self {
199 State::Idle { cfg, .. } => cfg,
200 State::AwaitingMsg2 { cfg, .. } => cfg,
201 State::AwaitingMsg4 { cfg, .. } => cfg,
202 State::KeysInstalled { cfg, .. } => cfg,
203 }
204 }
205}
206
207fn initiate_internal(
208 update_sink: &mut UpdateSink,
209 cfg: &Config,
210 key_replay_counter: AuthenticatorKeyReplayCounter,
211 anonce: &[u8],
212) -> Result<(), anyhow::Error> {
213 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
214 let msg1 = create_message_1(anonce, &protection, key_replay_counter)?;
215 update_sink.push(SecAssocUpdate::TxEapolKeyFrame { frame: msg1, expect_response: true });
216 Ok(())
217}
218
219fn process_message_2<B: SplitByteSlice>(
220 update_sink: &mut UpdateSink,
221 pmk: &[u8],
222 cfg: &Config,
223 anonce: &[u8],
224 key_replay_counter: AuthenticatorKeyReplayCounter,
225 frame: FourwayHandshakeFrame<B>,
226) -> Result<(Ptk, Gtk, Option<Igtk>, AuthenticatorKeyReplayCounter), anyhow::Error> {
227 let ptk = handle_message_2(&pmk[..], &cfg, &anonce[..], key_replay_counter, frame)?;
228 let gtk = cfg
229 .gtk_provider
230 .as_ref()
231 .ok_or_else(|| format_err!("GtkProvider is missing"))?
233 .lock()
234 .get_gtk()
235 .clone();
236 let igtk = match fourway::get_group_mgmt_cipher(&cfg.s_protection, &cfg.a_protection)
237 .map_err(|e| format_err!("group mgmt cipher error: {:?}", e))?
238 {
239 Some(group_mgmt_cipher) => {
240 let igtk_provider = cfg
241 .igtk_provider
242 .as_ref()
243 .ok_or_else(|| format_err!("IgtkProvider is missing"))?
245 .lock();
246 let igtk_provider_cipher = igtk_provider.cipher();
247 if group_mgmt_cipher != igtk_provider_cipher {
248 return Err(format_err!(
250 "wrong IgtkProvider cipher: {:?} != {:?}",
251 group_mgmt_cipher,
252 igtk_provider_cipher
253 ));
254 }
255 Some(igtk_provider.get_igtk())
256 }
257 None => None,
258 };
259 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
260 let key_replay_counter = AuthenticatorKeyReplayCounter::next_after(*key_replay_counter);
261 let msg3 = create_message_3(
262 &cfg,
263 ptk.kck(),
264 ptk.kek(),
265 >k,
266 &igtk,
267 &anonce[..],
268 &protection,
269 key_replay_counter,
270 )?;
271
272 update_sink.push(SecAssocUpdate::TxEapolKeyFrame { frame: msg3, expect_response: true });
273 Ok((ptk, gtk, igtk, key_replay_counter))
274}
275
276fn process_message_4<B: SplitByteSlice>(
277 update_sink: &mut UpdateSink,
278 cfg: &Config,
279 ptk: &Ptk,
280 gtk: &Gtk,
281 igtk: &Option<Igtk>,
282 key_replay_counter: AuthenticatorKeyReplayCounter,
283 frame: FourwayHandshakeFrame<B>,
284) -> Result<(), anyhow::Error> {
285 handle_message_4(cfg, ptk.kck(), key_replay_counter, frame)?;
286 update_sink.push(SecAssocUpdate::Key(Key::Ptk(ptk.clone())));
287 update_sink.push(SecAssocUpdate::Key(Key::Gtk(gtk.clone())));
288 if let Some(igtk) = igtk.as_ref() {
289 update_sink.push(SecAssocUpdate::Key(Key::Igtk(igtk.clone())));
290 }
291 Ok(())
292}
293
294fn create_message_1<B: SplitByteSlice>(
296 anonce: B,
297 protection: &NegotiatedProtection,
298 key_replay_counter: AuthenticatorKeyReplayCounter,
299) -> Result<eapol::KeyFrameBuf, anyhow::Error> {
300 let version = derive_key_descriptor_version(eapol::KeyDescriptor::IEEE802DOT11, protection);
301 let key_info = eapol::KeyInformation(0)
302 .with_key_descriptor_version(version)
303 .with_key_type(eapol::KeyType::PAIRWISE)
304 .with_key_ack(true);
305
306 let key_len = match protection.pairwise.tk_bits() {
307 None => {
308 return Err(format_err!(
309 "unknown cipher used for pairwise key: {:?}",
310 protection.pairwise
311 ));
312 }
313 Some(tk_bits) => tk_bits / 8,
314 };
315 eapol::KeyFrameTx::new(
316 eapol::ProtocolVersion::IEEE802DOT1X2004,
317 eapol::KeyFrameFields::new(
318 eapol::KeyDescriptor::IEEE802DOT11,
319 key_info,
320 key_len,
321 *key_replay_counter,
322 eapol::to_array(&anonce),
323 [0u8; 16], 0, ),
326 vec![],
327 protection.mic_size as usize,
328 )
329 .serialize()
330 .finalize_without_mic()
331 .map_err(|e| e.into())
332}
333
334pub fn handle_message_2<B: SplitByteSlice>(
336 pmk: &[u8],
337 cfg: &Config,
338 anonce: &[u8],
339 key_replay_counter: AuthenticatorKeyReplayCounter,
340 frame: FourwayHandshakeFrame<B>,
341) -> Result<Ptk, anyhow::Error> {
342 let snonce = &frame.unsafe_get_raw().key_frame_fields.key_nonce[..];
345 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
346
347 let ptk = Ptk::new(
348 pmk,
349 &cfg.a_addr,
350 &cfg.s_addr,
351 anonce,
352 snonce,
353 &protection.akm,
354 protection.pairwise.clone(),
355 )?;
356
357 let frame = match frame.get() {
359 Dot11VerifiedKeyFrame::WithUnverifiedMic(unverified_mic) => {
360 match unverified_mic.verify_mic(ptk.kck(), &protection)? {
361 UnverifiedKeyData::Encrypted(_) => {
362 return Err(format_err!("msg2 of 4-Way Handshake must not be encrypted"));
363 }
364 UnverifiedKeyData::NotEncrypted(frame) => frame,
365 }
366 }
367 Dot11VerifiedKeyFrame::WithoutMic(_) => {
368 return Err(format_err!("msg2 of 4-Way Handshake must carry a MIC"));
369 }
370 };
371 ensure!(
372 frame.key_frame_fields.key_replay_counter.get() == *key_replay_counter,
373 "error, expected Supplicant response to message {:?} but was {:?} in msg #2",
374 *key_replay_counter,
375 frame.key_frame_fields.key_replay_counter.get()
376 );
377
378 Ok(ptk)
381}
382
383fn create_message_3(
385 cfg: &Config,
386 kck: &[u8],
387 kek: &[u8],
388 gtk: &Gtk,
389 igtk: &Option<Igtk>,
390 anonce: &[u8],
391 protection: &NegotiatedProtection,
392 key_replay_counter: AuthenticatorKeyReplayCounter,
393) -> Result<eapol::KeyFrameBuf, anyhow::Error> {
394 let mut w = kde::Writer::new();
396 w.write_protection(&cfg.a_protection)?;
397 w.write_gtk(&kde::Gtk::new(gtk.key_id(), kde::GtkInfoTx::BothRxTx, gtk.tk()))?;
398 if let Some(igtk) = igtk.as_ref() {
399 w.write_igtk(&kde::Igtk::new(igtk.key_id, &igtk.ipn, igtk.tk()))?;
400 }
401 let key_data = w.finalize_for_encryption()?;
402 let key_iv = [0u8; 16];
403 let encrypted_key_data =
404 protection.keywrap_algorithm()?.wrap_key(kek, &key_iv, &key_data[..])?;
405
406 let version = derive_key_descriptor_version(eapol::KeyDescriptor::IEEE802DOT11, protection);
408 let key_info = eapol::KeyInformation(0)
409 .with_key_descriptor_version(version)
410 .with_key_type(eapol::KeyType::PAIRWISE)
411 .with_key_ack(true)
412 .with_key_mic(true)
413 .with_install(true)
414 .with_secure(true)
415 .with_encrypted_key_data(true);
416
417 let key_len = match protection.pairwise.tk_bits() {
418 None => {
419 return Err(format_err!(
420 "unknown cipher used for pairwise key: {:?}",
421 protection.pairwise
422 ));
423 }
424 Some(tk_bits) => tk_bits / 8,
425 };
426
427 let msg3 = eapol::KeyFrameTx::new(
428 eapol::ProtocolVersion::IEEE802DOT1X2004,
429 eapol::KeyFrameFields::new(
430 eapol::KeyDescriptor::IEEE802DOT11,
431 key_info,
432 key_len,
433 *key_replay_counter,
434 eapol::to_array(anonce),
435 key_iv,
436 gtk.key_rsc(),
437 ),
438 encrypted_key_data,
439 protection.mic_size as usize,
440 )
441 .serialize();
442
443 let mic = compute_mic_from_buf(kck, &protection, msg3.unfinalized_buf())
444 .map_err(|e| anyhow::Error::from(e))?;
445 msg3.finalize_with_mic(&mic[..]).map_err(|e| e.into())
446}
447
448pub fn handle_message_4<B: SplitByteSlice>(
450 cfg: &Config,
451 kck: &[u8],
452 key_replay_counter: AuthenticatorKeyReplayCounter,
453 frame: FourwayHandshakeFrame<B>,
454) -> Result<(), anyhow::Error> {
455 let protection = NegotiatedProtection::from_protection(&cfg.s_protection)?;
456 let frame = match frame.get() {
457 Dot11VerifiedKeyFrame::WithUnverifiedMic(unverified_mic) => {
458 match unverified_mic.verify_mic(kck, &protection)? {
459 UnverifiedKeyData::Encrypted(_) => {
460 return Err(format_err!("msg4 of 4-Way Handshake must not be encrypted"));
461 }
462 UnverifiedKeyData::NotEncrypted(frame) => frame,
463 }
464 }
465 Dot11VerifiedKeyFrame::WithoutMic(_) => {
466 return Err(format_err!("msg4 of 4-Way Handshake must carry a MIC"));
467 }
468 };
469 ensure!(
470 frame.key_frame_fields.key_replay_counter.get() == *key_replay_counter,
471 "error, expected Supplicant response to message {:?} but was {:?} in msg #4",
472 *key_replay_counter,
473 frame.key_frame_fields.key_replay_counter.get()
474 );
475
476 Ok(())
479}