Skip to main content

wlan_rsn/key/exchange/handshake/fourway/
mod.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
5mod authenticator;
6mod supplicant;
7
8use crate::key::exchange;
9use crate::key::gtk::{Gtk, GtkProvider};
10use crate::key::igtk::{Igtk, IgtkProvider};
11use crate::key::ptk::Ptk;
12use crate::nonce::NonceReader;
13use crate::rsna::{Dot11VerifiedKeyFrame, NegotiatedProtection, Role, UpdateSink};
14use crate::{Error, ProtectionInfo, rsn_ensure};
15use fuchsia_sync::Mutex;
16use ieee80211::MacAddr;
17use std::ops::Deref;
18use std::sync::Arc;
19use wlan_common::ie::rsn::cipher::Cipher;
20use wlan_common::ie::rsn::rsne::Rsne;
21use wlan_common::ie::rsn::suite_filter::DEFAULT_GROUP_MGMT_CIPHER;
22use wlan_statemachine::StateMachine;
23use zerocopy::SplitByteSlice;
24
25#[derive(Debug, PartialEq)]
26pub enum MessageNumber {
27    Message1 = 1,
28    Message2 = 2,
29    Message3 = 3,
30    Message4 = 4,
31}
32
33/// Represents the current value of an Authenticator's Key Replay Counter
34/// as defined in IEEE 802.11-2016 12.7.2 EAPOL-Key frames.
35#[derive(Debug, Clone, PartialEq, Eq, Copy)]
36pub struct AuthenticatorKeyReplayCounter(u64);
37
38impl Deref for AuthenticatorKeyReplayCounter {
39    type Target = u64;
40
41    fn deref(&self) -> &u64 {
42        &self.0
43    }
44}
45
46impl AuthenticatorKeyReplayCounter {
47    pub fn next_after(key_replay_counter: u64) -> Self {
48        Self(key_replay_counter + 1)
49    }
50}
51
52/// Represents the current value of a Supplicant's Key Replay Counter
53/// as defined in IEEE 802.11-2016 12.7.2 EAPOL-Key frames.
54#[derive(Debug, Clone, Copy)]
55pub struct SupplicantKeyReplayCounter(u64);
56
57impl Deref for SupplicantKeyReplayCounter {
58    type Target = u64;
59
60    fn deref(&self) -> &u64 {
61        &self.0
62    }
63}
64
65impl From<u64> for SupplicantKeyReplayCounter {
66    fn from(a: u64) -> Self {
67        Self(a)
68    }
69}
70
71/// Struct which carries EAPOL key frames which comply with IEEE Std 802.11-2016, 12.7.2 and
72/// IEEE Std 802.11-2016, 12.7.6.
73pub struct FourwayHandshakeFrame<B: SplitByteSlice>(Dot11VerifiedKeyFrame<B>);
74
75impl<B: SplitByteSlice> FourwayHandshakeFrame<B> {
76    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
77    pub fn from_verified(
78        frame: Dot11VerifiedKeyFrame<B>,
79        role: Role,
80        nonce: Option<&[u8]>,
81    ) -> Result<FourwayHandshakeFrame<B>, Error> {
82        // Safe: the raw frame is never exposed outside of this function.
83        let raw_frame = frame.unsafe_get_raw();
84        // Drop messages which were not expected by the configured role.
85        let msg_no = message_number(raw_frame);
86        match role {
87            // Authenticator should only receive message 2 and 4.
88            Role::Authenticator => match msg_no {
89                MessageNumber::Message2 | MessageNumber::Message4 => {}
90                _ => return Err(Error::UnexpectedHandshakeMessage(msg_no.into()).into()),
91            },
92            Role::Supplicant => match msg_no {
93                MessageNumber::Message1 | MessageNumber::Message3 => {}
94                _ => return Err(Error::UnexpectedHandshakeMessage(msg_no.into()).into()),
95            },
96        };
97
98        // Explicit validation based on the frame's message number.
99        match msg_no {
100            MessageNumber::Message1 => validate_message_1(raw_frame),
101            MessageNumber::Message2 => validate_message_2(raw_frame),
102            MessageNumber::Message3 => validate_message_3(raw_frame, nonce),
103            MessageNumber::Message4 => validate_message_4(raw_frame),
104        }?;
105
106        Ok(FourwayHandshakeFrame(frame))
107    }
108
109    pub fn get(self) -> Dot11VerifiedKeyFrame<B> {
110        self.0
111    }
112
113    /// Returns the 4-Way Handshake's message number.
114    fn message_number(&self) -> MessageNumber {
115        // Safe: At this point the frame was validated to be a valid 4-Way Handshake frame.
116        message_number(self.unsafe_get_raw())
117    }
118}
119
120impl<B: SplitByteSlice> std::ops::Deref for FourwayHandshakeFrame<B> {
121    type Target = Dot11VerifiedKeyFrame<B>;
122
123    fn deref(&self) -> &Dot11VerifiedKeyFrame<B> {
124        &self.0
125    }
126}
127
128#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
129pub fn get_group_mgmt_cipher(
130    s_protection: &ProtectionInfo,
131    a_protection: &ProtectionInfo,
132) -> Result<Option<Cipher>, Error> {
133    // IEEE 802.1-2016 12.6.3 - Management frame protection is
134    // negotiated when an AP and non-AP STA set the Management
135    // Frame Protection Capable field to 1 in their respective
136    // RSNEs in the (re)association procedure, ...
137    match (s_protection, a_protection) {
138        (
139            ProtectionInfo::Rsne {
140                rsne:
141                    Rsne {
142                        rsn_capabilities: Some(s_rsn_capabilities),
143                        group_mgmt_cipher_suite: s_group_mgmt_cipher_suite,
144                        ..
145                    },
146                ..
147            },
148            ProtectionInfo::Rsne {
149                rsne:
150                    Rsne {
151                        rsn_capabilities: Some(a_rsn_capabilities),
152                        group_mgmt_cipher_suite: a_group_mgmt_cipher_suite,
153                        ..
154                    },
155                ..
156            },
157        ) => {
158            // Check for invalid bits
159            if !s_rsn_capabilities.mgmt_frame_protection_cap()
160                && s_rsn_capabilities.mgmt_frame_protection_req()
161            {
162                return Err(Error::InvalidClientMgmtFrameProtectionCapabilityBit);
163            }
164            if !a_rsn_capabilities.mgmt_frame_protection_cap()
165                && a_rsn_capabilities.mgmt_frame_protection_req()
166            {
167                return Err(Error::InvalidApMgmtFrameProtectionCapabilityBit);
168            }
169
170            // Check for incompatible capabilities and requirements
171            if s_rsn_capabilities.mgmt_frame_protection_req()
172                && !a_rsn_capabilities.mgmt_frame_protection_cap()
173            {
174                return Err(Error::MgmtFrameProtectionRequiredByClient);
175            }
176            if !s_rsn_capabilities.mgmt_frame_protection_cap()
177                && a_rsn_capabilities.mgmt_frame_protection_req()
178            {
179                return Err(Error::MgmtFrameProtectionRequiredByAp);
180            }
181
182            if s_rsn_capabilities.mgmt_frame_protection_cap()
183                && a_rsn_capabilities.mgmt_frame_protection_cap()
184            {
185                let s_group_mgmt_cipher_suite =
186                    s_group_mgmt_cipher_suite.unwrap_or(DEFAULT_GROUP_MGMT_CIPHER);
187                let a_group_mgmt_cipher_suite =
188                    a_group_mgmt_cipher_suite.unwrap_or(DEFAULT_GROUP_MGMT_CIPHER);
189
190                if s_group_mgmt_cipher_suite != a_group_mgmt_cipher_suite {
191                    return Err(Error::GroupMgmtCipherMismatch(
192                        s_group_mgmt_cipher_suite,
193                        a_group_mgmt_cipher_suite,
194                    ));
195                }
196
197                return Ok(Some(s_group_mgmt_cipher_suite));
198            }
199        }
200        (
201            _,
202            ProtectionInfo::Rsne {
203                rsne: Rsne { rsn_capabilities: Some(a_rsn_capabilities), .. },
204                ..
205            },
206        ) => {
207            if a_rsn_capabilities.mgmt_frame_protection_req() {
208                return Err(Error::MgmtFrameProtectionRequiredByAp);
209            }
210        }
211        (
212            ProtectionInfo::Rsne {
213                rsne: Rsne { rsn_capabilities: Some(s_rsn_capabilities), .. },
214                ..
215            },
216            _,
217        ) => {
218            if s_rsn_capabilities.mgmt_frame_protection_req() {
219                return Err(Error::MgmtFrameProtectionRequiredByClient);
220            }
221        }
222
223        // If management frame protection will not be used or is not required, then we can
224        // safely ignore the supplicant ProtectionInfo
225        (ProtectionInfo::Rsne { rsne: Rsne { rsn_capabilities: None, .. }, .. }, _)
226        | (ProtectionInfo::LegacyWpa(_), _) => {}
227    }
228
229    Ok(None)
230}
231
232#[derive(Debug, Clone)]
233pub struct Config {
234    pub role: Role,
235    pub s_addr: MacAddr,
236    pub s_protection: ProtectionInfo,
237    pub a_addr: MacAddr,
238    pub a_protection: ProtectionInfo,
239    pub nonce_rdr: Arc<NonceReader>,
240    pub gtk_provider: Option<Arc<Mutex<GtkProvider>>>,
241    pub igtk_provider: Option<Arc<Mutex<IgtkProvider>>>,
242    pub pmksa_caching_supported: bool,
243
244    // Private field to ensure Config can only be created by one of Config's
245    // associated functions.
246    _private: (),
247}
248
249impl Config {
250    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
251    pub fn new(
252        role: Role,
253        s_addr: MacAddr,
254        s_protection: ProtectionInfo,
255        a_addr: MacAddr,
256        a_protection: ProtectionInfo,
257        nonce_rdr: Arc<NonceReader>,
258        gtk_provider: Option<Arc<Mutex<GtkProvider>>>,
259        igtk_provider: Option<Arc<Mutex<IgtkProvider>>>,
260        pmksa_caching_supported: bool,
261    ) -> Result<Config, Error> {
262        // Check that the supplicant protection is a subset of the authenticator protection.
263        match (&s_protection, &a_protection) {
264            (
265                ProtectionInfo::Rsne { rsne: s_rsne, .. },
266                ProtectionInfo::Rsne { rsne: a_rsne, .. },
267            ) => {
268                // TODO(https://fxbug.dev/42104575): Replace with ? syntax when
269                // NegotiatedProtection::from_protection no longer returns
270                // anyhow::Error.
271                match s_rsne.is_valid_subset_of(a_rsne) {
272                    Ok(true) => {}
273                    Ok(false) => {
274                        return Err(Error::RsneInvalidSubset(s_rsne.clone(), a_rsne.clone()));
275                    }
276                    Err(e) => return Err(e.into()),
277                };
278            }
279            // TODO(https://fxbug.dev/42149656): Check if the ProtectionInfo::LegacyWpa is a
280            // subset or superset of the other ProtectionInfo
281            (_, ProtectionInfo::LegacyWpa(_)) => {}
282            (ProtectionInfo::LegacyWpa(_), _) => {}
283        }
284
285        // TODO(https://fxbug.dev/42104575): Replace with ? syntax when
286        // NegotiatedProtection::from_protection no longer returns
287        // anyhow::Error.
288        // TODO(https://fxbug.dev/42149659): NegotiatedProtection should take into
289        // account a_protection since the use of management frame
290        // protection cannot be determined from s_protection alone.
291        match NegotiatedProtection::from_protection(&s_protection) {
292            Ok(negotiated_protection) => negotiated_protection,
293            Err(e) => return Err(Error::InvalidSupplicantProtection(format!("{:?}", e))),
294        };
295
296        // Check that both an GtkProvider and IgtkProvider are provided if this configuration
297        // is for an authenticator. An IgtkProvider is only required if management frame
298        // protection is activated by this Config.
299        if role == Role::Authenticator {
300            rsn_ensure!(gtk_provider.is_some(), Error::MissingGtkProvider);
301
302            // TODO(https://fxbug.dev/42149659): NegotiatedProtection should have a group_mgmt_cipher
303            // associated function instead.
304            match get_group_mgmt_cipher(&s_protection, &a_protection)? {
305                Some(group_mgmt_cipher) => match igtk_provider.as_ref() {
306                    None => return Err(Error::MissingIgtkProvider),
307                    Some(igtk_provider) => {
308                        let igtk_provider_cipher = igtk_provider.lock().cipher();
309                        rsn_ensure!(
310                            group_mgmt_cipher == igtk_provider_cipher,
311                            Error::WrongIgtkProviderCipher(group_mgmt_cipher, igtk_provider_cipher),
312                        );
313                    }
314                },
315                None => {}
316            }
317        }
318
319        Ok(Config {
320            role,
321            s_addr,
322            s_protection,
323            a_addr,
324            a_protection,
325            nonce_rdr,
326            gtk_provider,
327            igtk_provider,
328            pmksa_caching_supported,
329            _private: (),
330        })
331    }
332}
333
334impl PartialEq for Config {
335    fn eq(&self, other: &Config) -> bool {
336        self.role == other.role
337            && self.s_addr == other.s_addr
338            && self.s_protection == other.s_protection
339            && self.a_addr == other.a_addr
340            && self.a_protection == other.a_protection
341            && self.pmksa_caching_supported == other.pmksa_caching_supported
342    }
343}
344
345#[derive(Debug, PartialEq)]
346pub enum Fourway {
347    Authenticator(StateMachine<authenticator::State>),
348    Supplicant(StateMachine<supplicant::State>),
349}
350
351impl Fourway {
352    pub fn new(cfg: Config, pmk: Vec<u8>) -> Result<Fourway, anyhow::Error> {
353        let fourway = match &cfg.role {
354            Role::Supplicant => {
355                let state = supplicant::new(cfg, pmk);
356                Fourway::Supplicant(StateMachine::new(state))
357            }
358            Role::Authenticator => {
359                let state = authenticator::new(cfg, pmk);
360                Fourway::Authenticator(StateMachine::new(state))
361            }
362        };
363        Ok(fourway)
364    }
365
366    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
367    pub fn on_eapol_key_frame<B: SplitByteSlice>(
368        &mut self,
369        update_sink: &mut UpdateSink,
370        frame: Dot11VerifiedKeyFrame<B>,
371    ) -> Result<(), Error> {
372        match self {
373            Fourway::Authenticator(state_machine) => {
374                let frame = FourwayHandshakeFrame::from_verified(frame, Role::Authenticator, None)?;
375                state_machine.replace_state(|state| state.on_eapol_key_frame(update_sink, frame));
376                Ok(())
377            }
378            Fourway::Supplicant(state_machine) => {
379                let anonce = state_machine.as_ref().anonce();
380                let frame = FourwayHandshakeFrame::from_verified(frame, Role::Supplicant, anonce)?;
381                state_machine.replace_state(|state| state.on_eapol_key_frame(update_sink, frame));
382                Ok(())
383            }
384        }
385    }
386
387    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
388    pub fn on_rsna_response_timeout(&self) -> Result<(), Error> {
389        match self {
390            Fourway::Authenticator(state_machine) => state_machine.on_rsna_response_timeout(),
391            Fourway::Supplicant(state_machine) => state_machine.on_rsna_response_timeout(),
392        }
393    }
394
395    pub fn ptk(&self) -> Option<Ptk> {
396        match self {
397            Fourway::Authenticator(state_machine) => state_machine.as_ref().ptk(),
398            Fourway::Supplicant(state_machine) => state_machine.as_ref().ptk(),
399        }
400    }
401
402    pub fn gtk(&self) -> Option<Gtk> {
403        match self {
404            Fourway::Authenticator(state_machine) => state_machine.as_ref().gtk(),
405            Fourway::Supplicant(state_machine) => state_machine.as_ref().gtk(),
406        }
407    }
408
409    pub fn igtk(&self) -> Option<Igtk> {
410        match self {
411            Fourway::Authenticator(state_machine) => state_machine.as_ref().igtk(),
412            Fourway::Supplicant(state_machine) => state_machine.as_ref().igtk(),
413        }
414    }
415
416    #[cfg(test)]
417    pub fn get_config(&self) -> Config {
418        match self {
419            Fourway::Supplicant(state_machine) => match state_machine.as_ref() {
420                supplicant::State::AwaitingMsg1 { cfg, .. }
421                | supplicant::State::AwaitingMsg3 { cfg, .. }
422                | supplicant::State::KeysInstalled { cfg, .. } => cfg.clone(),
423            },
424            Fourway::Authenticator(state_machine) => match state_machine.as_ref() {
425                authenticator::State::Idle { cfg, .. }
426                | authenticator::State::AwaitingMsg2 { cfg, .. }
427                | authenticator::State::AwaitingMsg4 { cfg, .. }
428                | authenticator::State::KeysInstalled { cfg, .. } => cfg.clone(),
429            },
430        }
431    }
432
433    pub fn destroy(self) -> exchange::Config {
434        let cfg = match self {
435            Fourway::Supplicant(state_machine) => state_machine.into_state().destroy(),
436            Fourway::Authenticator(state_machine) => state_machine.into_state().destroy(),
437        };
438        exchange::Config::FourWayHandshake(cfg)
439    }
440}
441
442// Verbose and explicit verification of Message 1 to 4 against IEEE Std 802.11-2016, 12.7.6.2.
443
444#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
445fn validate_message_1<B: SplitByteSlice>(frame: &eapol::KeyFrameRx<B>) -> Result<(), Error> {
446    let key_info = frame.key_frame_fields.key_info();
447    // IEEE Std 802.11-2016, 12.7.2 b.4)
448    rsn_ensure!(!key_info.install(), Error::InvalidInstallBitValue(MessageNumber::Message1.into()));
449    // IEEE Std 802.11-2016, 12.7.2 b.5)
450    rsn_ensure!(key_info.key_ack(), Error::InvalidKeyAckBitValue(MessageNumber::Message1.into()));
451    // IEEE Std 802.11-2016, 12.7.2 b.6)
452    rsn_ensure!(!key_info.key_mic(), Error::InvalidKeyMicBitValue(MessageNumber::Message1.into()));
453    // IEEE Std 802.11-2016, 12.7.2 b.7)
454    rsn_ensure!(!key_info.secure(), Error::InvalidSecureBitValue(MessageNumber::Message1.into()));
455    // IEEE Std 802.11-2016, 12.7.2 b.8)
456    rsn_ensure!(!key_info.error(), Error::InvalidErrorBitValue(MessageNumber::Message1.into()));
457    // IEEE Std 802.11-2016, 12.7.2 b.9)
458    rsn_ensure!(!key_info.request(), Error::InvalidRequestBitValue(MessageNumber::Message1.into()));
459    // IEEE Std 802.11-2016, 12.7.2 b.10)
460    rsn_ensure!(
461        !key_info.encrypted_key_data(),
462        Error::InvalidEncryptedKeyDataBitValue(MessageNumber::Message1.into())
463    );
464    // IEEE Std 802.11-2016, 12.7.2 e)
465    rsn_ensure!(
466        !is_zero(&frame.key_frame_fields.key_nonce[..]),
467        Error::InvalidNonce(MessageNumber::Message1.into())
468    );
469    // IEEE Std 802.11-2016, 12.7.2 f)
470    // IEEE Std 802.11-2016, 12.7.6.2
471    rsn_ensure!(
472        is_zero(&frame.key_frame_fields.key_iv[..]),
473        Error::InvalidIv(frame.eapol_fields.version, MessageNumber::Message1.into())
474    );
475    // IEEE Std 802.11-2016, 12.7.2 g)
476    rsn_ensure!(
477        frame.key_frame_fields.key_rsc.get() == 0,
478        Error::InvalidRsc(MessageNumber::Message1.into())
479    );
480
481    // The first message of the Handshake is also required to carry a zeroed MIC.
482    // Some routers however send messages without zeroing out the MIC beforehand.
483    // To ensure compatibility with such routers, the MIC of the first message is
484    // allowed to be set.
485    // This assumption faces no security risk because the message's MIC is only
486    // validated in the Handshake and not in the Supplicant or Authenticator
487    // implementation.
488    Ok(())
489}
490
491#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
492fn validate_message_2<B: SplitByteSlice>(frame: &eapol::KeyFrameRx<B>) -> Result<(), Error> {
493    let key_info = frame.key_frame_fields.key_info();
494    // IEEE Std 802.11-2016, 12.7.2 b.4)
495    rsn_ensure!(!key_info.install(), Error::InvalidInstallBitValue(MessageNumber::Message2.into()));
496    // IEEE Std 802.11-2016, 12.7.2 b.5)
497    rsn_ensure!(!key_info.key_ack(), Error::InvalidKeyAckBitValue(MessageNumber::Message2.into()));
498    // IEEE Std 802.11-2016, 12.7.2 b.6)
499    rsn_ensure!(key_info.key_mic(), Error::InvalidKeyMicBitValue(MessageNumber::Message2.into()));
500    // IEEE Std 802.11-2016, 12.7.2 b.7)
501    rsn_ensure!(!key_info.secure(), Error::InvalidSecureBitValue(MessageNumber::Message2.into()));
502    // IEEE Std 802.11-2016, 12.7.2 b.8)
503    // Error bit only set by Supplicant in MIC failures in SMK derivation.
504    // SMK derivation not yet supported.
505    rsn_ensure!(!key_info.error(), Error::InvalidErrorBitValue(MessageNumber::Message2.into()));
506    // IEEE Std 802.11-2016, 12.7.2 b.9)
507    rsn_ensure!(!key_info.request(), Error::InvalidRequestBitValue(MessageNumber::Message2.into()));
508    // IEEE Std 802.11-2016, 12.7.2 b.10)
509    rsn_ensure!(
510        !key_info.encrypted_key_data(),
511        Error::InvalidEncryptedKeyDataBitValue(MessageNumber::Message2.into())
512    );
513    // IEEE Std 802.11-2016, 12.7.2 e)
514    rsn_ensure!(
515        !is_zero(&frame.key_frame_fields.key_nonce[..]),
516        Error::InvalidNonce(MessageNumber::Message2.into())
517    );
518    // IEEE Std 802.11-2016, 12.7.2 f)
519    // IEEE Std 802.11-2016, 12.7.6.3
520    rsn_ensure!(
521        is_zero(&frame.key_frame_fields.key_iv[..]),
522        Error::InvalidIv(frame.eapol_fields.version, MessageNumber::Message2.into())
523    );
524    // IEEE Std 802.11-2016, 12.7.2 g)
525    rsn_ensure!(
526        frame.key_frame_fields.key_rsc.get() == 0,
527        Error::InvalidRsc(MessageNumber::Message2.into())
528    );
529
530    Ok(())
531}
532
533#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
534fn validate_message_3<B: SplitByteSlice>(
535    frame: &eapol::KeyFrameRx<B>,
536    nonce: Option<&[u8]>,
537) -> Result<(), Error> {
538    let key_info = frame.key_frame_fields.key_info();
539    // IEEE Std 802.11-2016, 12.7.2 b.4)
540    // Install = 0 is only used in key mapping with TKIP and WEP, neither is supported by Fuchsia.
541    rsn_ensure!(key_info.install(), Error::InvalidInstallBitValue(MessageNumber::Message3.into()));
542    // IEEE Std 802.11-2016, 12.7.2 b.5)
543    rsn_ensure!(key_info.key_ack(), Error::InvalidKeyAckBitValue(MessageNumber::Message3.into()));
544    // These bit values are not used by WPA1.
545    if frame.key_frame_fields.descriptor_type != eapol::KeyDescriptor::LEGACY_WPA1 {
546        // IEEE Std 802.11-2016, 12.7.2 b.6)
547        rsn_ensure!(
548            key_info.key_mic(),
549            Error::InvalidKeyMicBitValue(MessageNumber::Message3.into())
550        );
551        // IEEE Std 802.11-2016, 12.7.2 b.7)
552        rsn_ensure!(
553            key_info.secure(),
554            Error::InvalidSecureBitValue(MessageNumber::Message3.into())
555        );
556        // IEEE Std 802.11-2016, 12.7.2 b.10)
557        rsn_ensure!(
558            key_info.encrypted_key_data(),
559            Error::InvalidEncryptedKeyDataBitValue(MessageNumber::Message3.into())
560        );
561    }
562    // IEEE Std 802.11-2016, 12.7.2 b.8)
563    rsn_ensure!(!key_info.error(), Error::InvalidErrorBitValue(MessageNumber::Message3.into()));
564    // IEEE Std 802.11-2016, 12.7.2 b.9)
565    rsn_ensure!(!key_info.request(), Error::InvalidRequestBitValue(MessageNumber::Message3.into()));
566    // IEEE Std 802.11-2016, 12.7.2 e)
567    if let Some(nonce) = nonce {
568        rsn_ensure!(
569            !is_zero(&frame.key_frame_fields.key_nonce[..])
570                && &frame.key_frame_fields.key_nonce[..] == nonce,
571            Error::InvalidNonce(MessageNumber::Message3.into())
572        );
573    }
574    // IEEE Std 802.11-2016, 12.7.2 f)
575    // IEEE Std 802.11-2016, 12.7.6.4
576    // IEEE 802.11-2016 requires a zeroed IV for 802.1X-2004+ and allows random ones for older
577    // protocols. Some APs such as TP-Link violate this requirement and send non-zeroed IVs while
578    // using 802.1X-2004. For compatibility, random IVs are allowed for 802.1X-2004.
579    rsn_ensure!(
580        frame.eapol_fields.version < eapol::ProtocolVersion::IEEE802DOT1X2010
581            || is_zero(&frame.key_frame_fields.key_iv[..]),
582        Error::InvalidIv(frame.eapol_fields.version, MessageNumber::Message3.into())
583    );
584    // IEEE Std 802.11-2016, 12.7.2 i) & j)
585    // Key Data must not be empty.
586    rsn_ensure!(frame.key_data.len() != 0, Error::EmptyKeyData(MessageNumber::Message3.into()));
587
588    Ok(())
589}
590
591#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
592fn validate_message_4<B: SplitByteSlice>(frame: &eapol::KeyFrameRx<B>) -> Result<(), Error> {
593    let key_info = frame.key_frame_fields.key_info();
594    // IEEE Std 802.11-2016, 12.7.2 b.4)
595    rsn_ensure!(!key_info.install(), Error::InvalidInstallBitValue(MessageNumber::Message4.into()));
596    // IEEE Std 802.11-2016, 12.7.2 b.5)
597    rsn_ensure!(!key_info.key_ack(), Error::InvalidKeyAckBitValue(MessageNumber::Message4.into()));
598    // IEEE Std 802.11-2016, 12.7.2 b.6)
599    rsn_ensure!(key_info.key_mic(), Error::InvalidKeyMicBitValue(MessageNumber::Message4.into()));
600    // IEEE Std 802.11-2016, 12.7.2 b.7)
601    rsn_ensure!(key_info.secure(), Error::InvalidSecureBitValue(MessageNumber::Message4.into()));
602    // IEEE Std 802.11-2016, 12.7.2 b.8)
603    // Error bit only set by Supplicant in MIC failures in SMK derivation.
604    // SMK derivation not yet supported.
605    rsn_ensure!(!key_info.error(), Error::InvalidErrorBitValue(MessageNumber::Message4.into()));
606    // IEEE Std 802.11-2016, 12.7.2 b.9)
607    rsn_ensure!(!key_info.request(), Error::InvalidRequestBitValue(MessageNumber::Message4.into()));
608    // IEEE Std 802.11-2016, 12.7.2 b.10)
609    rsn_ensure!(
610        !key_info.encrypted_key_data(),
611        Error::InvalidEncryptedKeyDataBitValue(MessageNumber::Message4.into())
612    );
613    // IEEE Std 802.11-2016, 12.7.2 f)
614    // IEEE Std 802.11-2016, 12.7.6.5
615    rsn_ensure!(
616        is_zero(&frame.key_frame_fields.key_iv[..]),
617        Error::InvalidIv(frame.eapol_fields.version, MessageNumber::Message4.into())
618    );
619    // IEEE Std 802.11-2016, 12.7.2 g)
620    rsn_ensure!(
621        frame.key_frame_fields.key_rsc.get() == 0,
622        Error::InvalidRsc(MessageNumber::Message4.into())
623    );
624
625    Ok(())
626}
627
628fn message_number<B: SplitByteSlice>(rx_frame: &eapol::KeyFrameRx<B>) -> MessageNumber {
629    // IEEE does not specify how to determine a frame's message number in the 4-Way Handshake
630    // sequence. However, it's important to know a frame's message number to do further
631    // validations. To derive the message number the key info field is used.
632    // 4-Way Handshake specific EAPOL Key frame requirements:
633    // IEEE Std 802.11-2016, 12.7.6.1
634
635    // IEEE Std 802.11-2016, 12.7.6.2 & 12.7.6.4
636    // Authenticator requires acknowledgement of all its sent frames.
637    if rx_frame.key_frame_fields.key_info().key_ack() {
638        // Authenticator only sends 1st and 3rd message of the handshake.
639        // IEEE Std 802.11-2016, 12.7.2 b.4)
640        // The third requires key installation while the first one doesn't.
641        if rx_frame.key_frame_fields.key_info().install() {
642            MessageNumber::Message3
643        } else {
644            MessageNumber::Message1
645        }
646    } else {
647        // Supplicant only sends 2nd and 4th message of the handshake.
648        // IEEE Std 802.11-2016, 12.7.2 b.7)
649        // The fourth message is secured while the second one is not.
650        if rx_frame.key_frame_fields.key_info().secure() {
651            MessageNumber::Message4
652        } else {
653            MessageNumber::Message2
654        }
655    }
656}
657
658fn is_zero(slice: &[u8]) -> bool {
659    slice.iter().all(|&x| x == 0)
660}
661
662#[cfg(test)]
663mod tests {
664    use super::*;
665    use crate::rsna::{SecAssocUpdate, test_util};
666    use crate::rsne::RsnCapabilities;
667    use wlan_common::ie::rsn::cipher::{CIPHER_BIP_CMAC_128, CIPHER_BIP_CMAC_256};
668    use wlan_common::ie::wpa::fake_wpa_ies::fake_deprecated_wpa1_vendor_ie;
669
670    #[test]
671    fn correct_value_returned_by_authenticator_key_replay_counter() {
672        let key_replay_counter = AuthenticatorKeyReplayCounter(5);
673        assert_eq!(*key_replay_counter, 5);
674    }
675
676    #[test]
677    fn correct_value_returned_by_supplicant_key_replay_counter() {
678        let key_replay_counter = SupplicantKeyReplayCounter(5);
679        assert_eq!(*key_replay_counter, 5);
680    }
681
682    #[test]
683    fn next_replay_counter_is_next_integer() {
684        let s_key_replay_counter = SupplicantKeyReplayCounter(5);
685        let next_key_replay_counter =
686            AuthenticatorKeyReplayCounter::next_after(*s_key_replay_counter);
687        assert_eq!(*next_key_replay_counter, 6);
688    }
689
690    // Create an Authenticator and Supplicant and performs the entire 4-Way Handshake.
691    #[test]
692    fn test_supplicant_with_authenticator() {
693        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
694
695        // Use arbitrarily chosen key_replay_counter.
696        let msg1 = env.initiate(11.into());
697        assert_eq!(msg1.keyframe().eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2004);
698        let (msg2, _) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
699        assert_eq!(msg2.keyframe().eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2004);
700        let msg3 = env.send_msg2_to_authenticator(msg2.keyframe(), 12.into());
701        assert_eq!(msg3.keyframe().eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2004);
702        let (msg4, s_ptk, s_gtk) = env.send_msg3_to_supplicant(msg3.keyframe(), 12.into());
703        assert_eq!(msg4.keyframe().eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2004);
704        let (a_ptk, a_gtk) = env.send_msg4_to_authenticator(msg4.keyframe(), 13.into());
705
706        // Verify Supplicant and Authenticator derived the same PTK.
707        assert_eq!(s_ptk, a_ptk);
708
709        // Verify Supplicant and Authenticator derived the same GTK and the Key Identifier and
710        // RSC are correct.
711        assert_eq!(s_gtk, a_gtk);
712        assert_eq!(s_gtk.key_id(), 1);
713        assert_eq!(s_gtk.key_rsc(), 3);
714    }
715
716    #[test]
717    fn test_wpa3_handshake_generates_igtk_real_authenticator() {
718        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa3, 1, 754);
719
720        // Use arbitrarily chosen key_replay_counter.
721        let msg1 = env.initiate(11.into());
722        assert_eq!(msg1.keyframe().eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2004);
723        let (msg2, _) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
724        assert_eq!(msg2.keyframe().eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2004);
725        let msg3 = env.send_msg2_to_authenticator(msg2.keyframe(), 12.into());
726        assert_eq!(msg3.keyframe().eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2004);
727        let (msg4, s_ptk, s_gtk) = env.send_msg3_to_supplicant(msg3.keyframe(), 12.into());
728        assert_eq!(msg4.keyframe().eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2004);
729        let (a_ptk, a_gtk) = env.send_msg4_to_authenticator(msg4.keyframe(), 13.into());
730
731        // Finally verify that Supplicant and Authenticator derived the same keys.
732        assert_eq!(s_ptk, a_ptk);
733        assert_eq!(s_gtk, a_gtk);
734        assert_eq!(s_gtk.key_id(), 1);
735        assert_eq!(s_gtk.key_rsc(), 754);
736        assert!(env.supplicant.igtk().is_some());
737        assert_eq!(env.supplicant.igtk(), env.authenticator.igtk());
738    }
739
740    fn run_wpa3_handshake_mock_authenticator(
741        gtk: &[u8],
742        igtk: Option<&[u8]>,
743    ) -> (Ptk, Vec<SecAssocUpdate>) {
744        let anonce = [0xab; 32];
745        let mut supplicant = test_util::make_handshake(
746            test_util::HandshakeKind::Wpa3,
747            super::Role::Supplicant,
748            1,
749            3,
750        );
751        let msg1_buf = test_util::get_wpa3_4whs_msg1(&anonce[..]);
752        let msg1 = msg1_buf.keyframe();
753        let updates = test_util::send_msg_to_fourway(&mut supplicant, msg1, 0.into());
754        let msg2 = test_util::expect_eapol_resp(&updates[..]);
755        let a_ptk =
756            test_util::get_wpa3_ptk(&anonce[..], &msg2.keyframe().key_frame_fields.key_nonce[..]);
757        let msg3_buf = &test_util::get_wpa3_4whs_msg3(&a_ptk, &anonce[..], &gtk[..], igtk);
758        let msg3 = msg3_buf.keyframe();
759        (a_ptk, test_util::send_msg_to_fourway(&mut supplicant, msg3, 0.into()))
760    }
761
762    #[test]
763    fn test_wpa3_handshake_generates_igtk_mock_authenticator() {
764        let gtk = [0xbb; 32];
765        let igtk = [0xcc; 32];
766        let (ptk, updates) = run_wpa3_handshake_mock_authenticator(&gtk[..], Some(&igtk[..]));
767
768        test_util::expect_eapol_resp(&updates[..]);
769        let s_ptk = test_util::expect_reported_ptk(&updates[..]);
770        let s_gtk = test_util::expect_reported_gtk(&updates[..]);
771        let s_igtk = test_util::expect_reported_igtk(&updates[..]);
772        assert_eq!(s_ptk, ptk);
773        assert_eq!(&s_gtk.bytes[..], &gtk[..]);
774        assert_eq!(&s_igtk.igtk[..], &igtk[..]);
775    }
776
777    #[test]
778    fn test_wpa3_handshake_requires_igtk() {
779        let gtk = [0xbb; 32];
780        let (_ptk, updates) = run_wpa3_handshake_mock_authenticator(&gtk[..], None);
781        assert!(
782            test_util::get_eapol_resp(&updates[..]).is_none(),
783            "WPA3 should not send EAPOL msg4 without IGTK"
784        );
785    }
786
787    #[test]
788    fn test_wpa1_handshake() {
789        let pmk = test_util::get_pmk();
790        let cfg = test_util::make_wpa1_fourway_cfg();
791        let mut supplicant = Fourway::new(cfg, pmk).expect("error while creating 4-Way Handshake");
792
793        // We don't have a WPA1 authenticator so we use fake messages.
794        let anonce = [0xab; 32];
795        let msg1_buf = test_util::get_wpa1_4whs_msg1(&anonce[..]);
796        let msg1 = msg1_buf.keyframe();
797        let updates = test_util::send_msg_to_fourway(&mut supplicant, msg1, 0.into());
798        let msg2 = test_util::expect_eapol_resp(&updates[..]);
799        let a_ptk =
800            test_util::get_wpa1_ptk(&anonce[..], &msg2.keyframe().key_frame_fields.key_nonce[..]);
801        let msg3_buf = &test_util::get_wpa1_4whs_msg3(&a_ptk, &anonce[..]);
802        let msg3 = msg3_buf.keyframe();
803        let updates = test_util::send_msg_to_fourway(&mut supplicant, msg3, 0.into());
804
805        // Verify that we completed the exchange and computed the same PTK as our fake AP would.
806        test_util::expect_eapol_resp(&updates[..]);
807        let s_ptk = test_util::expect_reported_ptk(&updates[..]);
808        assert_eq!(s_ptk, a_ptk);
809    }
810
811    #[test]
812    fn test_supplicant_replay_msg3() {
813        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
814
815        // Use arbitrarily chosen key_replay_counter.
816        let msg1 = env.initiate(11.into());
817        let (msg2, _) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
818        let msg3 = env.send_msg2_to_authenticator(msg2.keyframe(), 12.into());
819        let (_, s_ptk, s_gtk) = env.send_msg3_to_supplicant(msg3.keyframe(), 12.into());
820
821        // Replay third message pretending Authenticator did not receive Supplicant's response.
822        let mut update_sink = UpdateSink::default();
823
824        env.send_msg3_to_supplicant_capture_updates(msg3.keyframe(), 12.into(), &mut update_sink);
825        let msg4 = test_util::expect_eapol_resp(&update_sink[..]);
826
827        for update in update_sink {
828            if let SecAssocUpdate::Key(_) = update {
829                panic!("reinstalled key");
830            }
831        }
832
833        // Let Authenticator process 4th message.
834        let (a_ptk, a_gtk) = env.send_msg4_to_authenticator(msg4.keyframe(), 13.into());
835
836        // Finally verify that Supplicant and Authenticator derived the same keys.
837        assert_eq!(s_ptk, a_ptk);
838        assert_eq!(s_gtk, a_gtk);
839    }
840
841    #[test]
842    fn test_supplicant_replay_msg3_different_gtk() {
843        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
844
845        // Use arbitrarily chosen key_replay_counter.
846        let msg1 = env.initiate(11.into());
847        let anonce = msg1.keyframe().key_frame_fields.key_nonce.clone();
848        let (msg2, _) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
849        let msg3 = env.send_msg2_to_authenticator(msg2.keyframe(), 12.into());
850        let (_, s_ptk, s_gtk) = env.send_msg3_to_supplicant(msg3.keyframe(), 12.into());
851
852        // Replay third message pretending Authenticator did not receive Supplicant's response.
853        // Modify GTK to simulate GTK rotation while 4-Way Handshake was in progress.
854        let mut other_gtk = s_gtk.bytes.clone();
855        other_gtk[0] ^= 0xFF;
856        let msg3 = test_util::get_wpa2_4whs_msg3(&s_ptk, &anonce[..], &other_gtk[..], |msg3| {
857            msg3.key_frame_fields.key_replay_counter.set(42);
858        });
859        let mut update_sink = UpdateSink::default();
860        env.send_msg3_to_supplicant_capture_updates(msg3.keyframe(), 13.into(), &mut update_sink);
861
862        // Ensure Supplicant rejected and dropped 3rd message without replying.
863        assert_eq!(update_sink.len(), 0);
864    }
865
866    // First messages of 4-Way Handshake must carry a zeroed IV in all protocol versions.
867
868    #[test]
869    fn test_random_iv_msg1_v1() {
870        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
871
872        let msg1 = env.initiate(1.into());
873        let mut buf = vec![];
874        let mut msg1 = msg1.copy_keyframe_mut(&mut buf);
875        msg1.eapol_fields.version = eapol::ProtocolVersion::IEEE802DOT1X2001;
876        msg1.key_frame_fields.key_iv = [0xFFu8; 16];
877        env.send_msg1_to_supplicant_expect_err(msg1, 1.into());
878    }
879
880    #[test]
881    fn test_random_iv_msg1_v2() {
882        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
883
884        let msg1 = env.initiate(1.into());
885        let mut buf = vec![];
886        let mut msg1 = msg1.copy_keyframe_mut(&mut buf);
887        msg1.eapol_fields.version = eapol::ProtocolVersion::IEEE802DOT1X2004;
888        msg1.key_frame_fields.key_iv = [0xFFu8; 16];
889        env.send_msg1_to_supplicant_expect_err(msg1, 1.into());
890    }
891
892    // EAPOL Key frames can carry a random IV in the third message of the 4-Way Handshake if
893    // protocol version 1, 802.1X-2001, is used. All other protocol versions require a zeroed IV
894    // for the third message of the handshake. Some vendors violate this requirement. For
895    // compatibility, Fuchsia relaxes this requirement and allows random IVs with 802.1X-2004.
896
897    #[test]
898    fn test_random_iv_msg3_v2001() {
899        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
900
901        let msg1 = env.initiate(11.into());
902        let (msg2, ptk) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
903        let msg3 = env.send_msg2_to_authenticator(msg2.keyframe(), 12.into());
904        let mut buf = vec![];
905        let mut msg3 = msg3.copy_keyframe_mut(&mut buf);
906        msg3.eapol_fields.version = eapol::ProtocolVersion::IEEE802DOT1X2001;
907        msg3.key_frame_fields.key_iv = [0xFFu8; 16];
908        env.finalize_key_frame(&mut msg3, Some(ptk.kck()));
909
910        let (msg4, s_ptk, s_gtk) = env.send_msg3_to_supplicant(msg3, 12.into());
911        let (a_ptk, a_gtk) = env.send_msg4_to_authenticator(msg4.keyframe(), 13.into());
912
913        assert_eq!(s_ptk, a_ptk);
914        assert_eq!(s_gtk, a_gtk);
915    }
916
917    #[test]
918    fn test_random_iv_msg3_v2004() {
919        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
920
921        let msg1 = env.initiate(11.into());
922        let (msg2, ptk) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
923        let msg3 = env.send_msg2_to_authenticator(msg2.keyframe(), 12.into());
924        let mut buf = vec![];
925        let mut msg3 = msg3.copy_keyframe_mut(&mut buf);
926        msg3.eapol_fields.version = eapol::ProtocolVersion::IEEE802DOT1X2004;
927        msg3.key_frame_fields.key_iv = [0xFFu8; 16];
928        env.finalize_key_frame(&mut msg3, Some(ptk.kck()));
929
930        let (msg4, s_ptk, s_gtk) = env.send_msg3_to_supplicant(msg3, 12.into());
931        let (a_ptk, a_gtk) = env.send_msg4_to_authenticator(msg4.keyframe(), 13.into());
932
933        assert_eq!(s_ptk, a_ptk);
934        assert_eq!(s_gtk, a_gtk);
935    }
936
937    #[test]
938    fn test_zeroed_iv_msg3_v2004() {
939        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
940
941        let msg1 = env.initiate(11.into());
942        let (msg2, ptk) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
943        let msg3 = env.send_msg2_to_authenticator(msg2.keyframe(), 12.into());
944        let mut buf = vec![];
945        let mut msg3 = msg3.copy_keyframe_mut(&mut buf);
946        msg3.eapol_fields.version = eapol::ProtocolVersion::IEEE802DOT1X2004;
947        msg3.key_frame_fields.key_iv = [0u8; 16];
948        env.finalize_key_frame(&mut msg3, Some(ptk.kck()));
949
950        let (msg4, s_ptk, s_gtk) = env.send_msg3_to_supplicant(msg3, 12.into());
951        let (a_ptk, a_gtk) = env.send_msg4_to_authenticator(msg4.keyframe(), 13.into());
952
953        assert_eq!(s_ptk, a_ptk);
954        assert_eq!(s_gtk, a_gtk);
955    }
956
957    #[test]
958    fn test_random_iv_msg3_v2010() {
959        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
960
961        let msg1 = env.initiate(11.into());
962        let (msg2, ptk) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
963        let msg3 = env.send_msg2_to_authenticator(msg2.keyframe(), 12.into());
964        let mut buf = vec![];
965        let mut msg3 = msg3.copy_keyframe_mut(&mut buf);
966        msg3.eapol_fields.version = eapol::ProtocolVersion::IEEE802DOT1X2010;
967        msg3.key_frame_fields.key_iv = [0xFFu8; 16];
968        env.finalize_key_frame(&mut msg3, Some(ptk.kck()));
969
970        env.send_msg3_to_supplicant_expect_err(msg3, 12.into());
971    }
972
973    fn make_protection_info_with_mfp_parameters(
974        mfp_bits: Option<(bool, bool)>, // Option<(mfpc, mfpr)>
975        group_mgmt_cipher_suite: Option<Cipher>,
976    ) -> ProtectionInfo {
977        ProtectionInfo::from_rsne(Rsne {
978            rsn_capabilities: match mfp_bits {
979                None => None,
980                Some((mfpc, mfpr)) => Some(
981                    RsnCapabilities(0)
982                        .with_mgmt_frame_protection_cap(mfpc)
983                        .with_mgmt_frame_protection_req(mfpr),
984                ),
985            },
986            group_mgmt_cipher_suite,
987            ..Default::default()
988        })
989    }
990
991    fn check_rsne_get_group_mgmt_cipher(
992        s_mfp_bits: Option<(bool, bool)>, // Option<(mfpc, mfpr)>
993        s_cipher: Option<Cipher>,
994        a_mfp_bits: Option<(bool, bool)>, // Option<(mfpc, mfpr)>
995        a_cipher: Option<Cipher>,
996        expected_result: Result<Option<Cipher>, Error>,
997    ) {
998        let s_protection_info = make_protection_info_with_mfp_parameters(s_mfp_bits, s_cipher);
999        let a_protection_info = make_protection_info_with_mfp_parameters(a_mfp_bits, a_cipher);
1000
1001        assert_eq!(get_group_mgmt_cipher(&s_protection_info, &a_protection_info), expected_result);
1002    }
1003
1004    #[test]
1005    fn test_get_group_mgmt_cipher() {
1006        // Check that CIPHER_BIP_CMAC_256 is not DEFAULT_GROUP_MGMT_CIPHER so we can check cases when a
1007        // non-default cipher is specified.
1008        assert!(
1009            CIPHER_BIP_CMAC_256 != DEFAULT_GROUP_MGMT_CIPHER,
1010            "default group mgmt cipher is CIPHER_BIP_CMAC_256"
1011        );
1012
1013        for (s_mfpr, a_mfpr) in vec![(false, false), (false, true), (true, false), (true, true)] {
1014            check_rsne_get_group_mgmt_cipher(
1015                Some((true, s_mfpr)),
1016                None,
1017                Some((true, a_mfpr)),
1018                None,
1019                Ok(Some(DEFAULT_GROUP_MGMT_CIPHER)),
1020            );
1021        }
1022
1023        for (s_mfpr, a_mfpr) in vec![(false, false), (false, true), (true, false), (true, true)] {
1024            check_rsne_get_group_mgmt_cipher(
1025                Some((true, s_mfpr)),
1026                Some(CIPHER_BIP_CMAC_256),
1027                Some((true, a_mfpr)),
1028                Some(CIPHER_BIP_CMAC_256),
1029                Ok(Some(CIPHER_BIP_CMAC_256)),
1030            );
1031        }
1032
1033        for (s_mfpc, a_mfpc) in vec![(false, false), (false, true), (true, false)] {
1034            check_rsne_get_group_mgmt_cipher(
1035                Some((s_mfpc, false)),
1036                Some(CIPHER_BIP_CMAC_128),
1037                Some((a_mfpc, false)),
1038                None,
1039                Ok(None),
1040            );
1041        }
1042
1043        for (s_mfpc, a_mfpc) in vec![(false, false), (false, true), (true, false)] {
1044            check_rsne_get_group_mgmt_cipher(
1045                Some((s_mfpc, false)),
1046                None,
1047                Some((a_mfpc, false)),
1048                None,
1049                Ok(None),
1050            );
1051        }
1052
1053        let s_protection_info = ProtectionInfo::LegacyWpa(fake_deprecated_wpa1_vendor_ie());
1054        let a_protection_info = make_protection_info_with_mfp_parameters(None, None);
1055        assert_eq!(get_group_mgmt_cipher(&s_protection_info, &a_protection_info), Ok(None));
1056
1057        let s_protection_info = make_protection_info_with_mfp_parameters(None, None);
1058        let a_protection_info = ProtectionInfo::LegacyWpa(fake_deprecated_wpa1_vendor_ie());
1059        assert_eq!(get_group_mgmt_cipher(&s_protection_info, &a_protection_info), Ok(None));
1060    }
1061
1062    #[test]
1063    fn test_get_group_mgmt_cipher_errors() {
1064        // Error::Invalid*MgmtFrameProtectionCapabilityBit
1065        check_rsne_get_group_mgmt_cipher(
1066            Some((false, true)),
1067            None,
1068            Some((false, false)),
1069            None,
1070            Err(Error::InvalidClientMgmtFrameProtectionCapabilityBit),
1071        );
1072        check_rsne_get_group_mgmt_cipher(
1073            Some((false, false)),
1074            None,
1075            Some((false, true)),
1076            None,
1077            Err(Error::InvalidApMgmtFrameProtectionCapabilityBit),
1078        );
1079
1080        // Error::MgmtFrameProtectionRequiredByClient
1081        check_rsne_get_group_mgmt_cipher(
1082            Some((true, true)),
1083            None,
1084            Some((false, false)),
1085            None,
1086            Err(Error::MgmtFrameProtectionRequiredByClient),
1087        );
1088        check_rsne_get_group_mgmt_cipher(
1089            Some((true, true)),
1090            None,
1091            None,
1092            None,
1093            Err(Error::MgmtFrameProtectionRequiredByClient),
1094        );
1095        let s_protection_info = make_protection_info_with_mfp_parameters(Some((true, true)), None);
1096        let a_protection_info = ProtectionInfo::LegacyWpa(fake_deprecated_wpa1_vendor_ie());
1097        assert_eq!(
1098            get_group_mgmt_cipher(&s_protection_info, &a_protection_info),
1099            Err(Error::MgmtFrameProtectionRequiredByClient)
1100        );
1101
1102        // Error::MgmtFrameProtectionRequiredByAp
1103        check_rsne_get_group_mgmt_cipher(
1104            Some((false, false)),
1105            None,
1106            Some((true, true)),
1107            None,
1108            Err(Error::MgmtFrameProtectionRequiredByAp),
1109        );
1110        check_rsne_get_group_mgmt_cipher(
1111            None,
1112            None,
1113            Some((true, true)),
1114            None,
1115            Err(Error::MgmtFrameProtectionRequiredByAp),
1116        );
1117        let s_protection_info = ProtectionInfo::LegacyWpa(fake_deprecated_wpa1_vendor_ie());
1118        let a_protection_info = make_protection_info_with_mfp_parameters(Some((true, true)), None);
1119        assert_eq!(
1120            get_group_mgmt_cipher(&s_protection_info, &a_protection_info),
1121            Err(Error::MgmtFrameProtectionRequiredByAp)
1122        );
1123
1124        // Error::GroupMgmtCipherMismatch
1125        check_rsne_get_group_mgmt_cipher(
1126            Some((true, true)),
1127            Some(CIPHER_BIP_CMAC_128),
1128            Some((true, true)),
1129            Some(CIPHER_BIP_CMAC_256),
1130            Err(Error::GroupMgmtCipherMismatch(CIPHER_BIP_CMAC_128, CIPHER_BIP_CMAC_256)),
1131        );
1132        check_rsne_get_group_mgmt_cipher(
1133            Some((true, true)),
1134            Some(CIPHER_BIP_CMAC_256),
1135            Some((true, true)),
1136            None,
1137            Err(Error::GroupMgmtCipherMismatch(CIPHER_BIP_CMAC_256, DEFAULT_GROUP_MGMT_CIPHER)),
1138        );
1139    }
1140}