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