1use crate::client::rsn::Rsna;
6use crate::client::ClientConfig;
7use anyhow::{format_err, Error};
8use fidl_fuchsia_wlan_common as fidl_common;
9use fidl_fuchsia_wlan_mlme::DeviceInfo;
10use wlan_common::bss::BssDescription;
11use wlan_common::ie::rsn::rsne::{self, Rsne};
12use wlan_common::ie::wpa::WpaIe;
13use wlan_common::ie::{self};
14use wlan_common::security::wep::{self, WepKey};
15use wlan_common::security::{wpa, SecurityAuthenticator};
16use wlan_rsn::auth::psk::ToPsk;
17use wlan_rsn::auth::{self};
18use wlan_rsn::nonce::NonceReader;
19use wlan_rsn::{NegotiatedProtection, ProtectionInfo};
20
21#[derive(Debug)]
22pub enum Protection {
23 Open,
24 Wep(WepKey),
25 LegacyWpa(Rsna),
29 Rsna(Rsna),
30}
31
32impl Protection {
33 pub fn rsn_auth_method(&self) -> Option<auth::MethodName> {
34 let rsna = match self {
35 Self::LegacyWpa(rsna) => rsna,
36 Self::Rsna(rsna) => rsna,
37 Self::Wep(_) | Self::Open => {
39 return None;
40 }
41 };
42
43 Some(rsna.supplicant.get_auth_method())
44 }
45}
46
47#[derive(Debug)]
48pub enum ProtectionIe {
49 Rsne(Vec<u8>),
50 VendorIes(Vec<u8>),
51}
52
53#[derive(Clone, Copy, Debug)]
81pub struct SecurityContext<'a, C> {
82 pub security: &'a C,
84 pub device: &'a DeviceInfo,
85 pub security_support: &'a fidl_common::SecuritySupport,
86 pub config: &'a ClientConfig,
87 pub bss: &'a BssDescription,
88}
89
90impl<'a, C> SecurityContext<'a, C> {
91 fn map<U>(&self, subject: &'a U) -> SecurityContext<'a, U> {
93 SecurityContext {
94 security: subject,
95 device: self.device,
96 security_support: self.security_support,
97 config: self.config,
98 bss: self.bss,
99 }
100 }
101}
102
103impl SecurityContext<'_, wpa::Wpa1Credentials> {
104 fn authenticator_supplicant_ie(&self) -> Result<(WpaIe, WpaIe), Error> {
106 let a_wpa_ie = self.bss.wpa_ie()?;
107 if !crate::client::wpa::is_legacy_wpa_compatible(&a_wpa_ie) {
108 return Err(format_err!("Legacy WPA requested but IE is incompatible: {:?}", a_wpa_ie));
109 }
110 let s_wpa_ie = crate::client::wpa::construct_s_wpa(&a_wpa_ie);
111 Ok((a_wpa_ie, s_wpa_ie))
112 }
113
114 fn authentication_config(&self) -> auth::Config {
116 auth::Config::ComputedPsk(self.security.to_psk(&self.bss.ssid).into())
117 }
118}
119
120impl SecurityContext<'_, wpa::Wpa2PersonalCredentials> {
121 fn authenticator_supplicant_rsne(&self) -> Result<(Rsne, Rsne), Error> {
123 let a_rsne_ie = self
124 .bss
125 .rsne()
126 .ok_or_else(|| format_err!("WPA2 requested but RSNE is not present in BSS."))?;
127 let (_, a_rsne) = rsne::from_bytes(a_rsne_ie)
128 .map_err(|error| format_err!("Invalid RSNE IE {:02x?}: {:?}", a_rsne_ie, error))?;
129 let s_rsne = a_rsne.derive_wpa2_s_rsne(self.security_support)?;
130 Ok((a_rsne, s_rsne))
131 }
132
133 fn authentication_config(&self) -> auth::Config {
135 auth::Config::ComputedPsk(self.security.to_psk(&self.bss.ssid).into())
136 }
137}
138
139impl SecurityContext<'_, wpa::Wpa3PersonalCredentials> {
140 fn authenticator_supplicant_rsne(&self) -> Result<(Rsne, Rsne), Error> {
142 let a_rsne_ie = self
143 .bss
144 .rsne()
145 .ok_or_else(|| format_err!("WPA3 requested but RSNE is not present in BSS."))?;
146 let (_, a_rsne) = rsne::from_bytes(a_rsne_ie)
147 .map_err(|error| format_err!("Invalid RSNE IE {:02x?}: {:?}", a_rsne_ie, error))?;
148 let s_rsne = a_rsne.derive_wpa3_s_rsne(self.security_support)?;
149 Ok((a_rsne, s_rsne))
150 }
151
152 fn authentication_config(&self) -> Result<auth::Config, Error> {
154 match self.security {
155 wpa::Wpa3PersonalCredentials::Passphrase(ref passphrase) => {
156 if self.security_support.sae.sme_handler_supported {
158 Ok(auth::Config::Sae {
159 ssid: self.bss.ssid.clone(),
160 password: passphrase.clone().into(),
161 mac: self.device.sta_addr.into(),
162 peer_mac: self.bss.bssid.into(),
163 })
164 } else if self.security_support.sae.driver_handler_supported {
165 Ok(auth::Config::DriverSae { password: passphrase.clone().into() })
166 } else {
167 Err(format_err!(
168 "Failed to generate WPA3 authentication config: no SAE SME nor driver \
169 handler"
170 ))
171 }
172 }
173 }
174 }
175}
176
177impl<'a> TryFrom<SecurityContext<'a, SecurityAuthenticator>> for Protection {
178 type Error = Error;
179
180 fn try_from(context: SecurityContext<'a, SecurityAuthenticator>) -> Result<Self, Self::Error> {
181 match context.security {
182 SecurityAuthenticator::Open => context
183 .bss
184 .is_open()
185 .then(|| Protection::Open)
186 .ok_or_else(|| format_err!("BSS is not configured for open authentication")),
187 SecurityAuthenticator::Wep(authenticator) => context.map(authenticator).try_into(),
188 SecurityAuthenticator::Wpa(wpa) => match wpa {
189 wpa::WpaAuthenticator::Wpa1 { credentials, .. } => {
190 context.map(credentials).try_into()
191 }
192 wpa::WpaAuthenticator::Wpa2 { authentication, .. } => match authentication {
193 wpa::Authentication::Personal(personal) => context.map(personal).try_into(),
194 _ => Err(format_err!("WPA Enterprise is unsupported")),
196 },
197 wpa::WpaAuthenticator::Wpa3 { authentication, .. } => match authentication {
198 wpa::Authentication::Personal(personal) => context.map(personal).try_into(),
199 _ => Err(format_err!("WPA Enterprise is unsupported")),
201 },
202 },
203 }
204 }
205}
206
207impl<'a> TryFrom<SecurityContext<'a, wep::WepAuthenticator>> for Protection {
208 type Error = Error;
209
210 fn try_from(context: SecurityContext<'a, wep::WepAuthenticator>) -> Result<Self, Self::Error> {
211 context
212 .bss
213 .has_wep_configured()
214 .then(|| Protection::Wep(context.security.key.clone()))
215 .ok_or_else(|| format_err!("BSS is not configured for WEP"))
216 }
217}
218
219impl<'a> TryFrom<SecurityContext<'a, wpa::Wpa1Credentials>> for Protection {
220 type Error = Error;
221
222 fn try_from(context: SecurityContext<'a, wpa::Wpa1Credentials>) -> Result<Self, Self::Error> {
223 context
224 .bss
225 .has_wpa1_configured()
226 .then(|| -> Result<_, Self::Error> {
227 let sta_addr = context.device.sta_addr.into();
228 let (a_wpa_ie, s_wpa_ie) = context.authenticator_supplicant_ie()?;
229 let negotiated_protection = NegotiatedProtection::from_legacy_wpa(&s_wpa_ie)?;
230 let supplicant = wlan_rsn::Supplicant::new_wpa_personal(
231 NonceReader::new(&sta_addr)?,
232 context.authentication_config(),
233 sta_addr,
234 ProtectionInfo::LegacyWpa(s_wpa_ie),
235 context.bss.bssid.into(),
236 ProtectionInfo::LegacyWpa(a_wpa_ie),
237 )
238 .map_err(|error| format_err!("Failed to create ESS-SA: {:?}", error))?;
239 Ok(Protection::LegacyWpa(Rsna {
240 negotiated_protection,
241 supplicant: Box::new(supplicant),
242 }))
243 })
244 .transpose()?
245 .ok_or_else(|| format_err!("BSS is not configured for WPA1"))
246 }
247}
248
249impl<'a> TryFrom<SecurityContext<'a, wpa::Wpa2PersonalCredentials>> for Protection {
250 type Error = Error;
251
252 fn try_from(
253 context: SecurityContext<'a, wpa::Wpa2PersonalCredentials>,
254 ) -> Result<Self, Self::Error> {
255 context
256 .bss
257 .has_wpa2_personal_configured()
258 .then(|| -> Result<_, Self::Error> {
259 let sta_addr = context.device.sta_addr.into();
260 let (a_rsne, s_rsne) = context.authenticator_supplicant_rsne()?;
261 let negotiated_protection = NegotiatedProtection::from_rsne(&s_rsne)?;
262 let supplicant = wlan_rsn::Supplicant::new_wpa_personal(
263 NonceReader::new(&sta_addr)?,
264 context.authentication_config(),
265 sta_addr,
266 ProtectionInfo::Rsne(s_rsne),
267 context.bss.bssid.into(),
268 ProtectionInfo::Rsne(a_rsne),
269 )
270 .map_err(|error| format_err!("Failed to creat ESS-SA: {:?}", error))?;
271 Ok(Protection::Rsna(Rsna {
272 negotiated_protection,
273 supplicant: Box::new(supplicant),
274 }))
275 })
276 .transpose()?
277 .ok_or_else(|| format_err!("BSS is not configured for WPA2 Personal"))
278 }
279}
280
281impl<'a> TryFrom<SecurityContext<'a, wpa::Wpa3PersonalCredentials>> for Protection {
282 type Error = Error;
283
284 fn try_from(
285 context: SecurityContext<'a, wpa::Wpa3PersonalCredentials>,
286 ) -> Result<Self, Self::Error> {
287 context
288 .bss
289 .has_wpa3_personal_configured()
290 .then(|| -> Result<_, Self::Error> {
291 let sta_addr = context.device.sta_addr.into();
292 if !context.config.wpa3_supported {
293 return Err(format_err!("WPA3 requested but client does not support WPA3"));
294 }
295 let (a_rsne, s_rsne) = context.authenticator_supplicant_rsne()?;
296 let negotiated_protection = NegotiatedProtection::from_rsne(&s_rsne)?;
297 let supplicant = wlan_rsn::Supplicant::new_wpa_personal(
298 NonceReader::new(&sta_addr)?,
299 context.authentication_config()?,
300 sta_addr,
301 ProtectionInfo::Rsne(s_rsne),
302 context.bss.bssid.into(),
303 ProtectionInfo::Rsne(a_rsne),
304 )
305 .map_err(|error| format_err!("Failed to create ESS-SA: {:?}", error))?;
306 Ok(Protection::Rsna(Rsna {
307 negotiated_protection,
308 supplicant: Box::new(supplicant),
309 }))
310 })
311 .transpose()?
312 .ok_or_else(|| format_err!("BSS is not configured for WPA3 Personal"))
313 }
314}
315
316pub(crate) fn build_protection_ie(protection: &Protection) -> Result<Option<ProtectionIe>, Error> {
321 match protection {
322 Protection::Open | Protection::Wep(_) => Ok(None),
323 Protection::LegacyWpa(rsna) => {
324 let s_protection = rsna.negotiated_protection.to_full_protection();
325 let s_wpa = match s_protection {
326 ProtectionInfo::Rsne(_) => {
327 return Err(format_err!("found RSNE protection inside a WPA1 association..."));
328 }
329 ProtectionInfo::LegacyWpa(wpa) => wpa,
330 };
331 let mut buf = vec![];
332 #[expect(clippy::unwrap_used)]
333 ie::write_wpa1_ie(&mut buf, &s_wpa).unwrap(); Ok(Some(ProtectionIe::VendorIes(buf)))
335 }
336 Protection::Rsna(rsna) => {
337 let s_protection = rsna.negotiated_protection.to_full_protection();
338 let s_rsne = match s_protection {
339 ProtectionInfo::Rsne(rsne) => rsne,
340 ProtectionInfo::LegacyWpa(_) => {
341 return Err(format_err!("found WPA protection inside an RSNA..."));
342 }
343 };
344 let mut buf = Vec::with_capacity(s_rsne.len());
345 #[expect(clippy::unwrap_used)]
349 let () = s_rsne.write_into(&mut buf).unwrap();
350 Ok(Some(ProtectionIe::Rsne(buf)))
351 }
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use super::*;
358 use crate::client::{self};
359 use wlan_common::ie::fake_ies::fake_wpa_ie;
360 use wlan_common::ie::rsn::fake_rsnes::{fake_wpa2_s_rsne, fake_wpa3_s_rsne};
361 use wlan_common::security::wep::{WEP104_KEY_BYTES, WEP40_KEY_BYTES};
362 use wlan_common::security::wpa::credential::PSK_SIZE_BYTES;
363 use wlan_common::test_utils::fake_features::{
364 fake_security_support, fake_security_support_empty,
365 };
366 use wlan_common::{assert_variant, fake_bss_description};
367
368 #[test]
369 fn rsn_auth_method() {
370 let protection = Protection::Open;
372 assert!(protection.rsn_auth_method().is_none());
373
374 let protection = Protection::Wep(WepKey::parse([1; 5]).expect("unable to parse WEP key"));
376 assert!(protection.rsn_auth_method().is_none());
377
378 let protection_info = ProtectionInfo::LegacyWpa(fake_wpa_ie());
380 let negotiated_protection = NegotiatedProtection::from_protection(&protection_info)
381 .expect("could create mocked WPA1 NegotiatedProtection");
382 let protection = Protection::LegacyWpa(Rsna {
383 negotiated_protection,
384 supplicant: Box::new(client::test_utils::mock_psk_supplicant().0),
385 });
386 assert_eq!(protection.rsn_auth_method(), Some(auth::MethodName::Psk));
387
388 let protection_info = ProtectionInfo::Rsne(fake_wpa2_s_rsne());
390 let negotiated_protection = NegotiatedProtection::from_protection(&protection_info)
391 .expect("could create mocked WPA2 NegotiatedProtection");
392 let protection = Protection::Rsna(Rsna {
393 negotiated_protection,
394 supplicant: Box::new(client::test_utils::mock_psk_supplicant().0),
395 });
396 assert_eq!(protection.rsn_auth_method(), Some(auth::MethodName::Psk));
397
398 let protection_info = ProtectionInfo::Rsne(fake_wpa3_s_rsne());
400 let negotiated_protection = NegotiatedProtection::from_protection(&protection_info)
401 .expect("could create mocked WPA3 NegotiatedProtection");
402 let protection = Protection::Rsna(Rsna {
403 negotiated_protection,
404 supplicant: Box::new(client::test_utils::mock_sae_supplicant().0),
405 });
406 assert_eq!(protection.rsn_auth_method(), Some(auth::MethodName::Sae));
407 }
408
409 #[test]
410 fn protection_from_wep40() {
411 let device = crate::test_utils::fake_device_info([1u8; 6].into());
412 let security_support = fake_security_support();
413 let config = Default::default();
414 let bss = fake_bss_description!(Wep);
415 let authenticator = wep::WepAuthenticator { key: WepKey::from([1u8; WEP40_KEY_BYTES]) };
416 let protection = Protection::try_from(SecurityContext {
417 security: &authenticator,
418 device: &device,
419 security_support: &security_support,
420 config: &config,
421 bss: &bss,
422 })
423 .unwrap();
424 assert!(matches!(protection, Protection::Wep(_)));
425 }
426
427 #[test]
428 fn protection_from_wep104() {
429 let device = crate::test_utils::fake_device_info([1u8; 6].into());
430 let security_support = fake_security_support();
431 let config = Default::default();
432 let bss = fake_bss_description!(Wep);
433 let authenticator = wep::WepAuthenticator { key: WepKey::from([1u8; WEP104_KEY_BYTES]) };
434 let protection = Protection::try_from(SecurityContext {
435 security: &authenticator,
436 device: &device,
437 security_support: &security_support,
438 config: &config,
439 bss: &bss,
440 })
441 .unwrap();
442 assert!(matches!(protection, Protection::Wep(_)));
443 }
444
445 #[test]
446 fn protection_from_wpa1_psk() {
447 let device = crate::test_utils::fake_device_info([1u8; 6].into());
448 let security_support = fake_security_support();
449 let config = Default::default();
450 let bss = fake_bss_description!(Wpa1);
451 let credentials = wpa::Wpa1Credentials::Psk([1u8; PSK_SIZE_BYTES].into());
452 let protection = Protection::try_from(SecurityContext {
453 security: &credentials,
454 device: &device,
455 security_support: &security_support,
456 config: &config,
457 bss: &bss,
458 })
459 .unwrap();
460 assert!(matches!(protection, Protection::LegacyWpa(_)));
461 }
462
463 #[test]
464 fn protection_from_wpa2_personal_psk() {
465 let device = crate::test_utils::fake_device_info([1u8; 6].into());
466 let security_support = fake_security_support();
467 let config = Default::default();
468 let bss = fake_bss_description!(Wpa2);
469 let credentials = wpa::Wpa2PersonalCredentials::Psk([1u8; PSK_SIZE_BYTES].into());
470 let protection = Protection::try_from(SecurityContext {
471 security: &credentials,
472 device: &device,
473 security_support: &security_support,
474 config: &config,
475 bss: &bss,
476 })
477 .unwrap();
478 assert!(matches!(protection, Protection::Rsna(_)));
479 }
480
481 #[test]
482 fn protection_from_wpa2_personal_passphrase() {
483 let device = crate::test_utils::fake_device_info([1u8; 6].into());
484 let security_support = fake_security_support();
485 let config = Default::default();
486 let bss = fake_bss_description!(Wpa2);
487 let credentials =
488 wpa::Wpa2PersonalCredentials::Passphrase("password".as_bytes().try_into().unwrap());
489 let protection = Protection::try_from(SecurityContext {
490 security: &credentials,
491 device: &device,
492 security_support: &security_support,
493 config: &config,
494 bss: &bss,
495 })
496 .unwrap();
497 assert!(matches!(protection, Protection::Rsna(_)));
498 }
499
500 #[test]
501 fn protection_from_wpa2_personal_tkip_only_passphrase() {
502 let device = crate::test_utils::fake_device_info([1u8; 6].into());
503 let security_support = fake_security_support();
504 let config = Default::default();
505 let bss = fake_bss_description!(Wpa2TkipOnly);
506 let credentials =
507 wpa::Wpa2PersonalCredentials::Passphrase("password".as_bytes().try_into().unwrap());
508 let protection = Protection::try_from(SecurityContext {
509 security: &credentials,
510 device: &device,
511 security_support: &security_support,
512 config: &config,
513 bss: &bss,
514 })
515 .unwrap();
516 assert!(matches!(protection, Protection::Rsna(_)));
517 }
518
519 #[test]
520 fn protection_from_wpa3_personal_passphrase() {
521 let device = crate::test_utils::fake_device_info([1u8; 6].into());
522 let security_support = fake_security_support();
523 let config = ClientConfig { wpa3_supported: true, ..Default::default() };
524 let bss = fake_bss_description!(Wpa3);
525 let credentials =
526 wpa::Wpa3PersonalCredentials::Passphrase("password".as_bytes().try_into().unwrap());
527 let protection = Protection::try_from(SecurityContext {
528 security: &credentials,
529 device: &device,
530 security_support: &security_support,
531 config: &config,
532 bss: &bss,
533 })
534 .unwrap();
535 assert!(matches!(protection, Protection::Rsna(_)));
536 }
537
538 #[test]
539 fn protection_from_wpa1_passphrase_with_open_bss() {
540 let device = crate::test_utils::fake_device_info([1u8; 6].into());
541 let security_support = fake_security_support();
542 let config = Default::default();
543 let bss = fake_bss_description!(Open);
544 let credentials =
545 wpa::Wpa1Credentials::Passphrase("password".as_bytes().try_into().unwrap());
546 let _ = Protection::try_from(SecurityContext {
547 security: &credentials,
548 device: &device,
549 security_support: &security_support,
550 config: &config,
551 bss: &bss,
552 })
553 .expect_err("incorrectly accepted WPA1 passphrase credentials with open BSS");
554 }
555
556 #[test]
557 fn protection_from_open_authenticator_with_wpa1_bss() {
558 let device = crate::test_utils::fake_device_info([1u8; 6].into());
559 let security_support = fake_security_support();
560 let config = Default::default();
561 let bss = fake_bss_description!(Wpa1);
562 let authenticator = SecurityAuthenticator::Open;
565 let _ = Protection::try_from(SecurityContext {
566 security: &authenticator,
567 device: &device,
568 security_support: &security_support,
569 config: &config,
570 bss: &bss,
571 })
572 .expect_err("incorrectly accepted open authenticator with WPA1 BSS");
573 }
574
575 #[test]
576 fn protection_from_wpa2_personal_passphrase_with_wpa3_bss() {
577 let device = crate::test_utils::fake_device_info([1u8; 6].into());
578 let security_support = fake_security_support();
579 let config = ClientConfig { wpa3_supported: true, ..Default::default() };
580 let bss = fake_bss_description!(Wpa3);
581 let credentials =
582 wpa::Wpa2PersonalCredentials::Passphrase("password".as_bytes().try_into().unwrap());
583 let _ = Protection::try_from(SecurityContext {
584 security: &credentials,
585 device: &device,
586 security_support: &security_support,
587 config: &config,
588 bss: &bss,
589 })
590 .expect_err("incorrectly accepted WPA2 passphrase credentials with WPA3 BSS");
591 }
592
593 #[test]
594 fn wpa1_psk_rsna() {
595 let device = crate::test_utils::fake_device_info([1u8; 6].into());
596 let security_support = fake_security_support();
597 let config = Default::default();
598 let bss = fake_bss_description!(Wpa1);
599 let credentials = wpa::Wpa1Credentials::Psk([1u8; PSK_SIZE_BYTES].into());
600 let context = SecurityContext {
601 security: &credentials,
602 device: &device,
603 security_support: &security_support,
604 config: &config,
605 bss: &bss,
606 };
607 assert!(context.authenticator_supplicant_ie().is_ok());
608 assert!(matches!(context.authentication_config(), auth::Config::ComputedPsk(_)));
609
610 let protection = Protection::try_from(context).unwrap();
611 assert_variant!(protection, Protection::LegacyWpa(rsna) => {
612 assert_eq!(rsna.supplicant.get_auth_method(), auth::MethodName::Psk);
613 });
614 }
615
616 #[test]
617 fn wpa2_personal_psk_rsna() {
618 let device = crate::test_utils::fake_device_info([1u8; 6].into());
619 let security_support = fake_security_support();
620 let config = Default::default();
621 let bss = fake_bss_description!(Wpa2);
622 let credentials = wpa::Wpa2PersonalCredentials::Psk([1u8; PSK_SIZE_BYTES].into());
623 let context = SecurityContext {
624 security: &credentials,
625 device: &device,
626 security_support: &security_support,
627 config: &config,
628 bss: &bss,
629 };
630 assert!(context.authenticator_supplicant_rsne().is_ok());
631 assert!(matches!(context.authentication_config(), auth::Config::ComputedPsk(_)));
632
633 let protection = Protection::try_from(context).unwrap();
634 assert_variant!(protection, Protection::Rsna(rsna) => {
635 assert_eq!(rsna.supplicant.get_auth_method(), auth::MethodName::Psk);
636 });
637 }
638
639 #[test]
640 fn wpa3_personal_passphrase_rsna_sme_auth() {
641 let device = crate::test_utils::fake_device_info([1u8; 6].into());
642 let security_support = fake_security_support();
643 let config = ClientConfig { wpa3_supported: true, ..Default::default() };
644 let bss = fake_bss_description!(Wpa3);
645 let credentials =
646 wpa::Wpa3PersonalCredentials::Passphrase("password".as_bytes().try_into().unwrap());
647 let context = SecurityContext {
648 security: &credentials,
649 device: &device,
650 security_support: &security_support,
651 config: &config,
652 bss: &bss,
653 };
654 assert!(context.authenticator_supplicant_rsne().is_ok());
655 assert!(matches!(context.authentication_config(), Ok(auth::Config::Sae { .. })));
656
657 let protection = Protection::try_from(context).unwrap();
658 assert_variant!(protection, Protection::Rsna(rsna) => {
659 assert_eq!(rsna.supplicant.get_auth_method(), auth::MethodName::Sae);
660 });
661 }
662
663 #[test]
664 fn wpa3_personal_passphrase_rsna_driver_auth() {
665 let device = crate::test_utils::fake_device_info([1u8; 6].into());
666 let mut security_support = fake_security_support_empty();
667 security_support.mfp.supported = true;
668 security_support.sae.driver_handler_supported = true;
669 let config = ClientConfig { wpa3_supported: true, ..Default::default() };
670 let bss = fake_bss_description!(Wpa3);
671 let credentials =
672 wpa::Wpa3PersonalCredentials::Passphrase("password".as_bytes().try_into().unwrap());
673 let context = SecurityContext {
674 security: &credentials,
675 device: &device,
676 security_support: &security_support,
677 config: &config,
678 bss: &bss,
679 };
680 assert!(context.authenticator_supplicant_rsne().is_ok());
681 assert!(matches!(context.authentication_config(), Ok(auth::Config::DriverSae { .. })));
682
683 let protection = Protection::try_from(context).unwrap();
684 assert_variant!(protection, Protection::Rsna(rsna) => {
685 assert_eq!(rsna.supplicant.get_auth_method(), auth::MethodName::Sae);
686 });
687 }
688
689 #[test]
690 fn wpa3_personal_passphrase_prefer_sme_auth() {
691 let device = crate::test_utils::fake_device_info([1u8; 6].into());
692 let mut security_support = fake_security_support_empty();
693 security_support.mfp.supported = true;
694 security_support.sae.driver_handler_supported = true;
695 security_support.sae.sme_handler_supported = true;
696 let config = ClientConfig { wpa3_supported: true, ..Default::default() };
697 let bss = fake_bss_description!(Wpa3);
698 let credentials =
699 wpa::Wpa3PersonalCredentials::Passphrase("password".as_bytes().try_into().unwrap());
700 let context = SecurityContext {
701 security: &credentials,
702 device: &device,
703 security_support: &security_support,
704 config: &config,
705 bss: &bss,
706 };
707 assert!(matches!(context.authentication_config(), Ok(auth::Config::Sae { .. })));
708 }
709
710 #[test]
711 fn wpa3_personal_passphrase_no_security_support_features() {
712 let device = crate::test_utils::fake_device_info([1u8; 6].into());
713 let security_support = fake_security_support_empty();
714 let config = Default::default();
715 let bss = fake_bss_description!(Wpa3);
716 let credentials =
717 wpa::Wpa3PersonalCredentials::Passphrase("password".as_bytes().try_into().unwrap());
718 let context = SecurityContext {
719 security: &credentials,
720 device: &device,
721 security_support: &security_support,
722 config: &config,
723 bss: &bss,
724 };
725 let _ = context
726 .authentication_config()
727 .expect_err("created WPA3 auth config for incompatible device");
728 }
729}