wlan_rsn/key/exchange/handshake/fourway/
authenticator.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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    /// If [`self`] is in [`State::Idle`], then this function will push a
76    /// [`SecAssocUpdate::TxEapolKeyFrame`] into [`update_sink`] and result [`self`]. Otherwise,
77    /// [`self`] is dropped and an [`Error`] is returned.
78    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                // Safe since the frame is only used for deriving the message number.
111                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                    &gtk,
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        // TODO(https://fxbug.dev/42104575): Replace with Error::MissingGtkProvider
232        .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                // TODO(https://fxbug.dev/42104575): Replace with Error::MissingIgtkProvider
244                .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                // TODO(https://fxbug.dev/42104575): Replace with Error::WrongIgtkProviderCipher
249                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        &gtk,
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
294// IEEE Std 802.11-2016, 12.7.6.2
295fn 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], // iv
324            0,         // rsc
325        ),
326        vec![],
327        protection.mic_size as usize,
328    )
329    .serialize()
330    .finalize_without_mic()
331    .map_err(|e| e.into())
332}
333
334// IEEE Std 802.11-2016, 12.7.6.3
335pub 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    // Safe: The nonce must be accessed to compute the PTK. The frame will still be fully verified
343    // before accessing any of its fields.
344    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    // PTK was computed, verify the frame's MIC.
358    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    // TODO(hahnr): Key data must carry RSNE. Verify.
379
380    Ok(ptk)
381}
382
383// IEEE Std 802.11-2016, 12.7.6.4
384fn 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    // Construct key data which contains the Beacon's RSNE and a GTK KDE.
395    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    // Construct message.
407    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
448// IEEE Std 802.11-2016, 12.7.6.5
449pub 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    // Note: The message's integrity was already verified by low layers.
477
478    Ok(())
479}