Skip to main content

wlan_rsn/rsna/
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
5use crate::integrity::{self, integrity_algorithm};
6use crate::key::exchange::Key;
7use crate::keywrap::{self, keywrap_algorithm};
8
9use crate::{Error, ProtectionInfo, rsn_ensure};
10use anyhow::{anyhow, ensure};
11use fidl_fuchsia_wlan_mlme::SaeFrame;
12use wlan_common::ie::RsnxeOctet1;
13use wlan_common::ie::rsn::akm::Akm;
14use wlan_common::ie::rsn::cipher::{CIPHER_BIP_CMAC_128, Cipher, GROUP_CIPHER_SUITE, TKIP};
15use wlan_common::ie::rsn::rsne::{RsnCapabilities, Rsne};
16use wlan_common::ie::wpa::WpaIe;
17
18use zerocopy::SplitByteSlice;
19
20pub mod esssa;
21#[cfg(test)]
22pub mod test_util;
23
24#[derive(Debug, Clone, PartialEq)]
25pub enum ProtectionType {
26    LegacyWpa1,
27    Rsne,
28}
29
30#[derive(Debug)]
31pub enum IgtkSupport {
32    Unsupported,
33    Capable,
34    Required,
35}
36
37#[derive(Debug, Clone, PartialEq)]
38pub struct NegotiatedProtection {
39    pub group_data: Cipher,
40    pub pairwise: Cipher,
41    pub group_mgmt: Option<Cipher>,
42    pub akm: Akm,
43    pub mic_size: u16,
44    pub protection_type: ProtectionType,
45    // Some networks carry RSN capabilities.
46    // To construct a valid RSNE, these capabilities must be tracked.
47    caps: Option<RsnCapabilities>,
48    pub rsnxe: Option<RsnxeOctet1>,
49}
50
51impl NegotiatedProtection {
52    pub fn from_protection(protection: &ProtectionInfo) -> Result<Self, anyhow::Error> {
53        match protection {
54            ProtectionInfo::Rsne { rsne, rsnxe } => Self::from_rsne(rsne, *rsnxe),
55            ProtectionInfo::LegacyWpa(wpa) => Self::from_legacy_wpa(wpa),
56        }
57    }
58
59    fn key_descriptor_version(&self) -> u16 {
60        let key_descriptor_type = match self.protection_type {
61            ProtectionType::LegacyWpa1 => eapol::KeyDescriptor::LEGACY_WPA1,
62            ProtectionType::Rsne => eapol::KeyDescriptor::IEEE802DOT11,
63        };
64        derive_key_descriptor_version(key_descriptor_type, self)
65    }
66
67    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
68    pub fn integrity_algorithm(&self) -> Result<Box<dyn integrity::Algorithm>, Error> {
69        integrity_algorithm(self.key_descriptor_version(), &self.akm)
70            .ok_or(Error::UnknownIntegrityAlgorithm)
71    }
72
73    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
74    pub fn keywrap_algorithm(&self) -> Result<Box<dyn keywrap::Algorithm>, Error> {
75        keywrap_algorithm(self.key_descriptor_version(), &self.akm)
76            .ok_or(Error::UnknownKeywrapAlgorithm)
77    }
78
79    /// Validates this RSNE contains only one of each cipher type and only one AKM with
80    /// a defined number of MIC bytes, and produces a corresponding negotiated protection scheme.
81    pub fn from_rsne(rsne: &Rsne, rsnxe: Option<RsnxeOctet1>) -> Result<Self, anyhow::Error> {
82        rsne.ensure_valid_s_rsne()
83            .map_err(|e| anyhow!(e).context(Error::InvalidNegotiatedProtection))?;
84
85        // The following assignments will all succeed because ensure_valid_s_rsne() did
86        // not return a Result::Err.
87        let group_data = rsne.group_data_cipher_suite.as_ref().unwrap();
88        let pairwise = &rsne.pairwise_cipher_suites[0];
89        let akm = &rsne.akm_suites[0];
90        let mic_size = akm.mic_bytes();
91        let mic_size = mic_size.unwrap();
92
93        Ok(Self {
94            group_data: group_data.clone(),
95            pairwise: pairwise.clone(),
96            group_mgmt: rsne.group_mgmt_cipher_suite.clone(),
97            akm: akm.clone(),
98            mic_size,
99            protection_type: ProtectionType::Rsne,
100            caps: rsne.rsn_capabilities.clone(),
101            rsnxe,
102        })
103    }
104
105    /// Validates that this WPA1 element contains only one of each cipher type and one AKM, and
106    /// produces a corresponding negotiated protection scheme.
107    pub fn from_legacy_wpa(wpa: &WpaIe) -> Result<Self, anyhow::Error> {
108        ensure!(wpa.unicast_cipher_list.len() == 1, Error::InvalidNegotiatedProtection);
109        ensure!(wpa.akm_list.len() == 1, Error::InvalidNegotiatedProtection);
110        let akm = wpa.akm_list[0].clone();
111        let mic_size = akm.mic_bytes().ok_or(Error::InvalidNegotiatedProtection)?;
112        let group_data = wpa.multicast_cipher.clone();
113        let pairwise = wpa.unicast_cipher_list[0].clone();
114        Ok(Self {
115            group_data,
116            pairwise,
117            group_mgmt: None,
118            akm,
119            mic_size,
120            protection_type: ProtectionType::LegacyWpa1,
121            caps: None,
122            rsnxe: None,
123        })
124    }
125
126    /// Converts this NegotiatedProtection into a ProtectionInfo that may be written into 802.11
127    /// frames.
128    pub fn to_full_protection(&self) -> ProtectionInfo {
129        match self.protection_type {
130            ProtectionType::Rsne => ProtectionInfo::Rsne {
131                rsne: Rsne {
132                    group_data_cipher_suite: Some(self.group_data.clone()),
133                    pairwise_cipher_suites: vec![self.pairwise.clone()],
134                    group_mgmt_cipher_suite: self.group_mgmt.clone(),
135                    akm_suites: vec![self.akm.clone()],
136                    rsn_capabilities: self.caps.clone(),
137                    ..Default::default()
138                },
139                rsnxe: self.rsnxe,
140            },
141            ProtectionType::LegacyWpa1 => ProtectionInfo::LegacyWpa(WpaIe {
142                multicast_cipher: self.group_data.clone(),
143                unicast_cipher_list: vec![self.pairwise.clone()],
144                akm_list: vec![self.akm.clone()],
145            }),
146        }
147    }
148
149    pub fn igtk_support(&self) -> IgtkSupport {
150        match &self.caps {
151            Some(caps) => {
152                if caps.mgmt_frame_protection_req() {
153                    IgtkSupport::Required
154                } else if caps.mgmt_frame_protection_cap() {
155                    IgtkSupport::Capable
156                } else {
157                    IgtkSupport::Unsupported
158                }
159            }
160            None => IgtkSupport::Unsupported,
161        }
162    }
163
164    pub fn group_mgmt_cipher(&self) -> Cipher {
165        // IEEE Std. 802.11-2016 9.4.2.25.2: BIP_CMAC_128 is the default if not specified.
166        self.group_mgmt.clone().unwrap_or(CIPHER_BIP_CMAC_128)
167    }
168}
169
170/// Wraps an EAPOL key frame to enforces successful decryption before the frame can be used.
171pub struct EncryptedKeyData<B: SplitByteSlice>(eapol::KeyFrameRx<B>);
172
173impl<B: SplitByteSlice> EncryptedKeyData<B> {
174    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
175    /// Yields a tuple of the captured EAPOL Key frame and its decrypted key data if encryption
176    /// was successful. Otherwise, an Error is returned.
177    pub fn decrypt(
178        self,
179        kek: &[u8],
180        protection: &NegotiatedProtection,
181    ) -> Result<(eapol::KeyFrameRx<B>, Vec<u8>), Error> {
182        let key_data = protection.keywrap_algorithm()?.unwrap_key(
183            kek,
184            &self.0.key_frame_fields.key_iv,
185            &self.0.key_data[..],
186        )?;
187        Ok((self.0, key_data))
188    }
189}
190
191/// Wraps an EAPOL key frame to enforce successful MIC verification before the frame can be used.
192#[derive(Debug)]
193pub struct WithUnverifiedMic<B: SplitByteSlice>(eapol::KeyFrameRx<B>);
194
195impl<B: SplitByteSlice> WithUnverifiedMic<B> {
196    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
197    /// Yields the captured EAPOL Key frame if the MIC was successfully verified.
198    /// The Key frame is wrapped to enforce decryption of potentially encrypted key data.
199    /// Returns an Error if the MIC is invalid.
200    pub fn verify_mic(
201        self,
202        kck: &[u8],
203        protection: &NegotiatedProtection,
204    ) -> Result<UnverifiedKeyData<B>, Error> {
205        // IEEE Std 802.11-2016, 12.7.2 h)
206        // IEEE Std 802.11-2016, 12.7.2 b.6)
207        let mic_bytes = protection.akm.mic_bytes().ok_or(Error::UnsupportedAkmSuite)?;
208        rsn_ensure!(self.0.key_mic.len() == mic_bytes as usize, Error::InvalidMicSize);
209
210        // If a MIC is set but the PTK was not yet derived, the MIC cannot be verified.
211        let buf = self.0.to_bytes(true);
212        let valid_mic =
213            protection.integrity_algorithm()?.verify(kck, &buf[..], &self.0.key_mic[..]);
214        rsn_ensure!(valid_mic, Error::InvalidMic);
215
216        if self.0.key_frame_fields.key_info().encrypted_key_data() {
217            Ok(UnverifiedKeyData::Encrypted(EncryptedKeyData(self.0)))
218        } else {
219            Ok(UnverifiedKeyData::NotEncrypted(self.0))
220        }
221    }
222}
223
224/// Carries an EAPOL Key frame and requires MIC verification if the MIC bit of the frame's info
225/// field is set.
226pub enum UnverifiedKeyData<B: SplitByteSlice> {
227    Encrypted(EncryptedKeyData<B>),
228    NotEncrypted(eapol::KeyFrameRx<B>),
229}
230
231/// EAPOL Key frames carried in this struct comply with IEEE Std 802.11-2016, 12.7.2.
232/// Neither the Key Frame's MIC nor its key data were verified at this point.
233#[derive(Debug)]
234pub enum Dot11VerifiedKeyFrame<B: SplitByteSlice> {
235    WithUnverifiedMic(WithUnverifiedMic<B>),
236    WithoutMic(eapol::KeyFrameRx<B>),
237}
238
239impl<B: SplitByteSlice> Dot11VerifiedKeyFrame<B> {
240    // [`key_replay_counter`] is the current value of the Key Replay Counter[1] in either the
241    // Supplicant or Authenticator. The Supplicant initializes its Key Replay Counter to 0 and
242    // updates the counter to the counter value contained in each valid message from the
243    // Authenticator. The Authenticator initializes its Key Replay Counter to 0 and updates
244    // the counter to the counter value contained in each message the Authenticator sends.
245    //
246    // [1]: IEEE 802.11-2016 12.7.2 EAPOL-Key frames
247    #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
248    pub fn from_frame(
249        frame: eapol::KeyFrameRx<B>,
250        role: &Role,
251        protection: &NegotiatedProtection,
252        key_replay_counter: u64,
253    ) -> Result<Dot11VerifiedKeyFrame<B>, Error> {
254        let sender = match role {
255            Role::Supplicant => Role::Authenticator,
256            Role::Authenticator => Role::Supplicant,
257        };
258
259        // IEEE Std 802.11-2016, 12.7.2 a)
260        // IEEE Std 802.1X-2010, 11.9
261        let key_descriptor = match frame.key_frame_fields.descriptor_type {
262            eapol::KeyDescriptor::IEEE802DOT11 => eapol::KeyDescriptor::IEEE802DOT11,
263            eapol::KeyDescriptor::LEGACY_WPA1
264                if protection.protection_type == ProtectionType::LegacyWpa1 =>
265            {
266                eapol::KeyDescriptor::LEGACY_WPA1
267            }
268            eapol::KeyDescriptor::RC4 => {
269                return Err(Error::InvalidKeyDescriptor(
270                    frame.key_frame_fields.descriptor_type,
271                    eapol::KeyDescriptor::IEEE802DOT11,
272                )
273                .into());
274            }
275            // Invalid value.
276            _ => {
277                return Err(Error::UnsupportedKeyDescriptor(
278                    frame.key_frame_fields.descriptor_type,
279                )
280                .into());
281            }
282        };
283
284        // IEEE Std 802.11-2016, 12.7.2 b.1)
285        let frame_key_descriptor_version =
286            frame.key_frame_fields.key_info().key_descriptor_version();
287        let expected_version = derive_key_descriptor_version(key_descriptor, protection);
288        rsn_ensure!(
289            frame_key_descriptor_version == expected_version,
290            Error::UnsupportedKeyDescriptorVersion(frame_key_descriptor_version)
291        );
292
293        // IEEE Std 802.11-2016, 12.7.2 b.2)
294        // IEEE Std 802.11-2016, 12.7.2 b.4)
295        match frame.key_frame_fields.key_info().key_type() {
296            eapol::KeyType::PAIRWISE => {}
297            eapol::KeyType::GROUP_SMK => {
298                // IEEE Std 802.11-2016, 12.7.2 b.4 ii)
299                rsn_ensure!(
300                    !frame.key_frame_fields.key_info().install(),
301                    Error::InvalidInstallBitGroupSmkHandshake
302                );
303            }
304        };
305
306        // IEEE Std 802.11-2016, 12.7.2 b.5)
307        if let Role::Supplicant = sender {
308            rsn_ensure!(
309                !frame.key_frame_fields.key_info().key_ack(),
310                Error::InvalidKeyAckBitSupplicant
311            );
312        }
313
314        // IEEE Std 802.11-2016, 12.7.2 b.6)
315        // IEEE Std 802.11-2016, 12.7.2 b.7)
316        // MIC and Secure bit depend on specific key-exchange methods and can not be verified now.
317        // More specifically, there are frames which can carry a MIC or secure bit but are required
318        // to compute the PTK and/or GTK and thus cannot be verified up-front.
319
320        // IEEE Std 802.11-2016, 12.7.2 b.8)
321        if let Role::Authenticator = sender {
322            rsn_ensure!(
323                !frame.key_frame_fields.key_info().error(),
324                Error::InvalidErrorBitAuthenticator
325            );
326        }
327
328        // IEEE Std 802.11-2016, 12.7.2 b.9)
329        if let Role::Authenticator = sender {
330            rsn_ensure!(
331                !frame.key_frame_fields.key_info().request(),
332                Error::InvalidRequestBitAuthenticator
333            );
334        }
335
336        // IEEE Std 802.11-2016, 12.7.2 b.10)
337        // Encrypted key data is validated at the end once all other validations succeeded.
338
339        // IEEE Std 802.11-2016, 12.7.2 b.11)
340        rsn_ensure!(
341            !frame.key_frame_fields.key_info().smk_message(),
342            Error::SmkHandshakeNotSupported
343        );
344
345        // IEEE Std 802.11-2016, 12.7.2 c)
346        match frame.key_frame_fields.key_info().key_type() {
347            eapol::KeyType::PAIRWISE => match sender {
348                // IEEE is somewhat vague on what is expected from the frame's key_len field.
349                // IEEE Std 802.11-2016, 12.7.2 c) requires the key_len to match the PTK's
350                // length, while all handshakes defined in IEEE such as
351                // 4-Way Handshake (12.7.6.3) and Group Key Handshake (12.7.7.3) explicitly require
352                // a value of 0 for frames sent by the Supplicant.
353                // Not all vendors follow the latter requirement, such as Apple with iOS.
354                // To improve interoperability, a value of 0 or the pairwise temporal key length is
355                // allowed for frames sent by the Supplicant.
356                Role::Supplicant if frame.key_frame_fields.key_len.get() != 0 => {
357                    let tk_len =
358                        protection.pairwise.tk_bytes().ok_or(Error::UnsupportedCipherSuite)?;
359                    rsn_ensure!(
360                        frame.key_frame_fields.key_len.get() == u16::from(tk_len),
361                        Error::InvalidKeyLength(
362                            frame.key_frame_fields.key_len.get().into(),
363                            tk_len.into()
364                        )
365                    );
366                }
367                // Authenticator must use the pairwise cipher's key length.
368                Role::Authenticator => {
369                    let tk_len: usize =
370                        protection.pairwise.tk_bytes().ok_or(Error::UnsupportedCipherSuite)?.into();
371                    rsn_ensure!(
372                        usize::from(frame.key_frame_fields.key_len.get()) == tk_len,
373                        Error::InvalidKeyLength(
374                            frame.key_frame_fields.key_len.get().into(),
375                            tk_len
376                        )
377                    );
378                }
379                _ => {}
380            },
381            // IEEE Std 802.11-2016, 12.7.2 c) does not specify the expected value for frames
382            // involved in exchanging the GTK. Thus, leave validation and enforcement of this
383            // requirement to the selected key exchange method.
384            eapol::KeyType::GROUP_SMK => {}
385        };
386
387        if key_replay_counter > 0 {
388            match sender {
389                // Supplicant responds to messages from the Authenticator with the same
390                // key replay counter.
391                Role::Supplicant => {
392                    rsn_ensure!(
393                        frame.key_frame_fields.key_replay_counter.get() >= key_replay_counter,
394                        Error::InvalidKeyReplayCounter(
395                            frame.key_frame_fields.key_replay_counter.get(),
396                            key_replay_counter
397                        )
398                    );
399                }
400                // Authenticator must send messages with a strictly larger key replay counter.
401                //
402                // TODO(b/310698434): This logic only runs upon receipt of messages. It seems
403                // that an Authenticator should actually verify the current Key Replay Counter
404                // is equal to the Key Replay Counter value received.
405                Role::Authenticator => {
406                    rsn_ensure!(
407                        frame.key_frame_fields.key_replay_counter.get() > key_replay_counter,
408                        Error::InvalidKeyReplayCounter(
409                            frame.key_frame_fields.key_replay_counter.get(),
410                            key_replay_counter
411                        )
412                    );
413                }
414            }
415        }
416
417        // IEEE Std 802.11-2016, 12.7.2
418        // Encrypted Key Data bit requires MIC bit to be set for all 802.11 handshakes.
419        if frame.key_frame_fields.key_info().encrypted_key_data() {
420            rsn_ensure!(
421                frame.key_frame_fields.key_info().key_mic(),
422                Error::InvalidMicBitForEncryptedKeyData
423            );
424        }
425
426        // IEEE Std 802.11-2016, 12.7.2, e)
427        // Validation is specific for the selected key exchange method.
428
429        // IEEE Std 802.11-2016, 12.7.2, f)
430        // Validation is specific for the selected key exchange method.
431
432        // IEEE Std 802.11-2016, 12.7.2, g)
433        // Validation is specific for the selected key exchange method.
434
435        // IEEE Std 802.11-2016, 12.7.2 h)
436        // IEEE Std 802.11-2016, 12.7.2 b.6)
437        // See explanation for IEEE Std 802.11-2016, 12.7.2 b.7) why the MIC cannot be verified
438        // here.
439
440        // IEEE Std 802.11-2016, 12.7.2 i) & j)
441        // IEEE Std 802.11-2016, 12.7.2 b.10)
442        // Validation is enforced by KeyFrame parser.
443
444        if frame.key_frame_fields.key_info().key_mic() {
445            Ok(Dot11VerifiedKeyFrame::WithUnverifiedMic(WithUnverifiedMic(frame)))
446        } else {
447            Ok(Dot11VerifiedKeyFrame::WithoutMic(frame))
448        }
449    }
450
451    /// CAUTION: Returns the underlying frame without verifying its MIC or encrypted key data if
452    /// either one is present.
453    /// Only use this if you know what you are doing.
454    pub fn unsafe_get_raw(&self) -> &eapol::KeyFrameRx<B> {
455        match self {
456            Dot11VerifiedKeyFrame::WithUnverifiedMic(WithUnverifiedMic(frame)) => frame,
457            Dot11VerifiedKeyFrame::WithoutMic(frame) => frame,
458        }
459    }
460}
461
462/// IEEE Std 802.11-2016, 12.7.2 b.1)
463/// Key Descriptor Version is based on the negotiated AKM, Pairwise- and Group Cipher suite.
464pub fn derive_key_descriptor_version(
465    key_descriptor_type: eapol::KeyDescriptor,
466    protection: &NegotiatedProtection,
467) -> u16 {
468    let akm = &protection.akm;
469    let pairwise = &protection.pairwise;
470
471    if !akm.has_known_algorithm() || !pairwise.has_known_usage() {
472        return 0;
473    }
474
475    match akm.suite_type {
476        1 | 2 => match key_descriptor_type {
477            eapol::KeyDescriptor::RC4 => match pairwise.suite_type {
478                TKIP | GROUP_CIPHER_SUITE => 1,
479                _ => 0,
480            },
481            eapol::KeyDescriptor::IEEE802DOT11 | eapol::KeyDescriptor::LEGACY_WPA1 => {
482                if pairwise.suite_type == TKIP || pairwise.suite_type == GROUP_CIPHER_SUITE {
483                    1
484                } else if pairwise.is_enhanced() || protection.group_data.is_enhanced() {
485                    2
486                } else {
487                    0
488                }
489            }
490            _ => 0,
491        },
492        // Interestingly, IEEE 802.11 does not specify any pairwise- or group cipher
493        // requirements for these AKMs.
494        3..=6 => 3,
495        _ => 0,
496    }
497}
498
499#[derive(Debug, Clone, Copy, PartialEq)]
500pub enum Role {
501    Authenticator,
502    Supplicant,
503}
504
505#[derive(Debug, PartialEq, Clone, Copy)]
506pub enum SecAssocStatus {
507    WrongPassword,
508    PmkSaEstablished,
509    EssSaEstablished,
510}
511
512#[derive(Debug, PartialEq, Clone, Copy)]
513pub enum AuthRejectedReason {
514    /// Unable to generate a PMK with the peer.
515    AuthFailed,
516    /// The peer never responded or sent too many invalid responses.
517    TooManyRetries,
518    /// Association took too long, and the PMKSA has expired.
519    PmksaExpired,
520}
521
522#[derive(Debug, PartialEq, Clone, Copy)]
523pub enum AuthStatus {
524    Success,
525    Rejected(AuthRejectedReason),
526    InternalError,
527}
528
529#[derive(Debug, PartialEq, Clone)]
530pub enum SecAssocUpdate {
531    TxEapolKeyFrame {
532        frame: eapol::KeyFrameBuf,
533        // Indicates whether we expect that our peer in the EAPOL exchange will send us a
534        // response to this frame. If so, we must also schedule a timeout for the response.
535        expect_response: bool,
536    },
537    Key(Key),
538    Status(SecAssocStatus),
539    // These values are used to handle SAE exchanges.
540    TxSaeFrame(SaeFrame),
541    SaeAuthStatus(AuthStatus),
542    ScheduleSaeTimeout(u64),
543    // Values used to handle OWE exchanges.
544    TxOwePublicKey {
545        group_id: u16,
546        key: Vec<u8>,
547    },
548}
549
550pub type UpdateSink = Vec<SecAssocUpdate>;
551
552#[cfg(test)]
553mod tests {
554    use super::*;
555    use assert_matches::assert_matches;
556    use wlan_common::ie::rsn::akm::{self, AKM_PSK};
557    use wlan_common::ie::rsn::cipher::{self, CIPHER_CCMP_128, CIPHER_GCMP_256};
558    use wlan_common::ie::rsn::fake_wpa2_s_rsne;
559    use zerocopy::byteorder::big_endian::U16;
560
561    #[test]
562    fn test_negotiated_protection_from_rsne() {
563        let rsne = Rsne {
564            group_data_cipher_suite: Some(CIPHER_GCMP_256),
565            pairwise_cipher_suites: vec![CIPHER_CCMP_128],
566            akm_suites: vec![AKM_PSK],
567            ..Default::default()
568        };
569        NegotiatedProtection::from_rsne(&rsne, None)
570            .expect("error, could not create negotiated RSNE");
571
572        let rsne = Rsne::wpa3_rsne();
573        NegotiatedProtection::from_rsne(&rsne, None)
574            .expect("error, could not create negotiated RSNE");
575
576        let rsne = Rsne {
577            pairwise_cipher_suites: vec![CIPHER_CCMP_128],
578            akm_suites: vec![AKM_PSK],
579            ..Default::default()
580        };
581        NegotiatedProtection::from_rsne(&rsne, None).expect_err("error, created negotiated RSNE");
582
583        let rsne = Rsne {
584            group_data_cipher_suite: Some(CIPHER_CCMP_128),
585            akm_suites: vec![AKM_PSK],
586            ..Default::default()
587        };
588        NegotiatedProtection::from_rsne(&rsne, None).expect_err("error, created negotiated RSNE");
589
590        let rsne = Rsne {
591            group_data_cipher_suite: Some(CIPHER_CCMP_128),
592            pairwise_cipher_suites: vec![CIPHER_CCMP_128],
593            ..Default::default()
594        };
595        NegotiatedProtection::from_rsne(&rsne, None).expect_err("error, created negotiated RSNE");
596    }
597
598    // IEEE requires the key length to be zeroed in the 4-Way Handshake but some vendors send the
599    // pairwise cipher's key length instead. The requirement was relaxed to improve
600    // interoperability,
601    #[test]
602    fn test_supplicant_sends_zeroed_and_non_zeroed_key_length() {
603        let protection = NegotiatedProtection::from_rsne(&fake_wpa2_s_rsne(), None)
604            .expect("could not derive negotiated RSNE");
605        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
606
607        // Use arbitrarily chosen key_replay_counter.
608        let msg1 = env.initiate(11.into());
609        let (msg2_base, ptk) = env.send_msg1_to_supplicant(msg1.keyframe(), 11.into());
610
611        // IEEE 802.11 compliant key length.
612        let mut buf = vec![];
613        let mut msg2 = msg2_base.copy_keyframe_mut(&mut buf);
614        msg2.key_frame_fields.key_len = U16::new(0);
615        env.finalize_key_frame(&mut msg2, Some(ptk.kck()));
616        let result = Dot11VerifiedKeyFrame::from_frame(msg2, &Role::Authenticator, &protection, 12);
617        assert!(result.is_ok(), "failed verifying message: {}", result.unwrap_err());
618
619        // Use CCMP-128 key length. Not officially IEEE 802.11 compliant but relaxed for
620        // interoperability.
621        let mut buf = vec![];
622        let mut msg2 = msg2_base.copy_keyframe_mut(&mut buf);
623        msg2.key_frame_fields.key_len = U16::new(16);
624        env.finalize_key_frame(&mut msg2, Some(ptk.kck()));
625        let result = Dot11VerifiedKeyFrame::from_frame(msg2, &Role::Authenticator, &protection, 12);
626        assert!(result.is_ok(), "failed verifying message: {}", result.unwrap_err());
627    }
628
629    // Fuchsia requires EAPOL frames sent from the Supplicant to contain a key length of either 0 or
630    // the PTK's length.
631    #[test]
632    fn test_supplicant_sends_random_key_length() {
633        let mut env = test_util::FourwayTestEnv::new(test_util::HandshakeKind::Wpa2, 1, 3);
634
635        // Use arbitrarily chosen key_replay_counter.
636        let msg1 = env.initiate(12.into());
637        let (msg2, ptk) = env.send_msg1_to_supplicant(msg1.keyframe(), 12.into());
638        let mut buf = vec![];
639        let mut msg2 = msg2.copy_keyframe_mut(&mut buf);
640
641        msg2.key_frame_fields.key_len = U16::new(29);
642        env.finalize_key_frame(&mut msg2, Some(ptk.kck()));
643
644        let protection = NegotiatedProtection::from_rsne(&fake_wpa2_s_rsne(), None)
645            .expect("could not derive negotiated RSNE");
646        let result = Dot11VerifiedKeyFrame::from_frame(msg2, &Role::Authenticator, &protection, 12);
647        assert!(result.is_err(), "successfully verified illegal message");
648    }
649
650    #[test]
651    fn test_to_rsne() {
652        let rsne = Rsne::wpa2_rsne();
653        let negotiated_protection = NegotiatedProtection::from_rsne(&rsne, None)
654            .expect("error, could not create negotiated RSNE")
655            .to_full_protection();
656        assert_matches!(negotiated_protection, ProtectionInfo::Rsne { rsne: actual_protection, rsnxe: None } => {
657            assert_eq!(actual_protection, rsne);
658        });
659    }
660
661    #[test]
662    fn test_to_rsne_with_rsnxe() {
663        let rsne = Rsne::wpa3_rsne();
664        let rsnxe = Some(RsnxeOctet1(0x20));
665        let protection = ProtectionInfo::Rsne { rsne: rsne.clone(), rsnxe };
666        let negotiated_protection = NegotiatedProtection::from_protection(&protection)
667            .expect("error, could not create negotiated RSNE")
668            .to_full_protection();
669        assert_eq!(negotiated_protection, protection);
670    }
671
672    #[test]
673    fn test_to_legacy_wpa() {
674        let wpa_ie = make_wpa(Some(cipher::TKIP), vec![cipher::TKIP], vec![akm::PSK]);
675        let negotiated_protection = NegotiatedProtection::from_legacy_wpa(&wpa_ie)
676            .expect("error, could not create negotiated WPA")
677            .to_full_protection();
678        assert_matches!(negotiated_protection, ProtectionInfo::LegacyWpa(actual_protection) => {
679            assert_eq!(actual_protection, wpa_ie);
680        });
681    }
682
683    #[test]
684    fn test_igtk_support() {
685        // Standard WPA3 RSNE requires MFP.
686        let rsne = Rsne::wpa3_rsne();
687        let negotiated_protection =
688            NegotiatedProtection::from_rsne(&rsne, None).expect("Could not create negotiated RSNE");
689        assert_matches!(negotiated_protection.igtk_support(), IgtkSupport::Required);
690        assert_eq!(negotiated_protection.group_mgmt_cipher(), CIPHER_BIP_CMAC_128);
691
692        // Mixed mode RSNE is compatible with MFP.
693        let mut rsne = Rsne::wpa3_rsne();
694        rsne.rsn_capabilities.replace(RsnCapabilities(0).with_mgmt_frame_protection_cap(true));
695        let negotiated_protection =
696            NegotiatedProtection::from_rsne(&rsne, None).expect("Could not create negotiated RSNE");
697        assert_matches!(negotiated_protection.igtk_support(), IgtkSupport::Capable);
698
699        // WPA2 RSNE doesn't support MFP.
700        let rsne = Rsne::wpa2_rsne();
701        let negotiated_protection =
702            NegotiatedProtection::from_rsne(&rsne, None).expect("Could not create negotiated RSNE");
703        assert_matches!(negotiated_protection.igtk_support(), IgtkSupport::Unsupported);
704    }
705
706    #[test]
707    fn test_default_igtk_cipher() {
708        let mut rsne = Rsne::wpa3_rsne();
709        rsne.group_mgmt_cipher_suite.take(); // Default to BIP_CMAC_128.
710        let negotiated_protection =
711            NegotiatedProtection::from_rsne(&rsne, None).expect("Could not create negotiated RSNE");
712        assert_matches!(negotiated_protection.igtk_support(), IgtkSupport::Required);
713        assert_eq!(negotiated_protection.group_mgmt_cipher(), CIPHER_BIP_CMAC_128);
714    }
715
716    fn make_wpa(unicast: Option<u8>, multicast: Vec<u8>, akms: Vec<u8>) -> WpaIe {
717        WpaIe {
718            multicast_cipher: unicast
719                .map(cipher::Cipher::new_dot11)
720                .expect("failed to make wpa ie!"),
721            unicast_cipher_list: multicast.into_iter().map(cipher::Cipher::new_dot11).collect(),
722            akm_list: akms.into_iter().map(akm::Akm::new_dot11).collect(),
723        }
724    }
725}