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