1use crate::recorded_request_stream::RecordedRequestStream;
6use assert_matches::assert_matches;
7use fidl_fuchsia_wlan_mlme::EapolResultCode;
8use fuchsia_sync::Mutex;
9use ieee80211::MacAddr;
10use std::sync::Arc;
11use wlan_common::bss;
12use wlan_common::ie::rsn::cipher::{CIPHER_BIP_CMAC_128, CIPHER_CCMP_128};
13use wlan_common::ie::rsn::rsne;
14use wlan_rsn::Authenticator;
15use wlan_rsn::rsna::{SecAssocUpdate, UpdateSink};
16use zerocopy::IntoBytes;
17use {
18 fidl_fuchsia_wlan_common_security as fidl_wlan_security,
19 fidl_fuchsia_wlan_fullmac as fidl_fullmac, fidl_fuchsia_wlan_mlme as fidl_mlme,
20};
21
22pub fn create_wpa2_authenticator(
24 client_mac_addr: MacAddr,
25 bss_description: &bss::BssDescription,
26 credentials: fidl_wlan_security::WpaCredentials,
27) -> Authenticator {
28 assert_eq!(bss_description.protection(), bss::Protection::Wpa2Personal);
29
30 let advertised_protection_info = get_protection_info(bss_description);
32 let supplicant_protection_info = get_protection_info(bss_description);
33
34 let nonce_rdr = wlan_rsn::nonce::NonceReader::new(&bss_description.bssid.clone().into())
35 .expect("creating nonce reader");
36 let gtk_provider =
37 wlan_rsn::GtkProvider::new(CIPHER_CCMP_128, 1, 0).expect("creating gtk provider");
38
39 let psk = match credentials {
40 fidl_wlan_security::WpaCredentials::Passphrase(passphrase) => {
41 wlan_rsn::psk::compute(passphrase.as_bytes(), &bss_description.ssid)
42 .expect("Could not compute psk")
43 }
44 fidl_wlan_security::WpaCredentials::Psk(psk) => Box::new(psk),
45 _ => panic!("Unsupported credential type"),
46 };
47
48 Authenticator::new_wpa2psk_ccmp128(
49 nonce_rdr,
50 Arc::new(Mutex::new(gtk_provider)),
51 psk,
52 client_mac_addr,
53 supplicant_protection_info,
54 bss_description.bssid.clone().into(),
55 advertised_protection_info,
56 )
57 .expect("Failed to create authenticator")
58}
59
60pub fn create_wpa3_authenticator(
62 client_mac_addr: MacAddr,
63 bss_description: &bss::BssDescription,
64 credentials: fidl_wlan_security::WpaCredentials,
65) -> Authenticator {
66 assert_eq!(bss_description.protection(), bss::Protection::Wpa3Personal);
67
68 let advertised_protection_info = get_protection_info(bss_description);
70 let supplicant_protection_info = get_protection_info(bss_description);
71
72 let password =
73 assert_matches!(credentials, fidl_wlan_security::WpaCredentials::Passphrase(p) => p);
74
75 let nonce_rdr = wlan_rsn::nonce::NonceReader::new(&bss_description.bssid.clone().into())
76 .expect("creating nonce reader");
77 let gtk_provider =
78 wlan_rsn::GtkProvider::new(CIPHER_CCMP_128, 1, 0).expect("creating gtk provider");
79 let igtk_provider =
80 wlan_rsn::IgtkProvider::new(CIPHER_BIP_CMAC_128).expect("error creating IgtkProvider");
81
82 Authenticator::new_wpa3(
83 nonce_rdr,
84 Arc::new(Mutex::new(gtk_provider)),
85 Arc::new(Mutex::new(igtk_provider)),
86 bss_description.ssid.clone(),
87 password,
88 client_mac_addr,
89 supplicant_protection_info.clone(),
90 bss_description.bssid.into(),
91 advertised_protection_info,
92 )
93 .expect("Failed to create authenticator")
94}
95
96pub async fn handle_sae_exchange(
109 authenticator: &mut Authenticator,
110 fullmac_req_stream: &mut RecordedRequestStream,
111 fullmac_ifc_proxy: &fidl_fullmac::WlanFullmacImplIfcProxy,
112) -> UpdateSink {
113 let mut update_sink = UpdateSink::new();
114
115 let supplicant_commit_frame = get_sae_frame_from_test_realm(fullmac_req_stream).await;
117 authenticator
118 .on_sae_frame_rx(&mut update_sink, supplicant_commit_frame)
119 .expect("Failed to send SAE commit frame to authenticator");
120
121 let authenticator_commit_frame = assert_matches!(
124 &update_sink[0], SecAssocUpdate::TxSaeFrame(frame) => frame.clone());
125 let authenticator_confirm_frame = assert_matches!(
126 &update_sink[1], SecAssocUpdate::TxSaeFrame(frame) => frame.clone());
127 update_sink.clear();
128
129 send_sae_frame_to_test_realm(authenticator_commit_frame, fullmac_ifc_proxy).await;
131
132 let supplicant_confirm_frame = get_sae_frame_from_test_realm(fullmac_req_stream).await;
134 authenticator
135 .on_sae_frame_rx(&mut update_sink, supplicant_confirm_frame)
136 .expect("Failed to send SAE confirm frame to authenticator");
137
138 send_sae_frame_to_test_realm(authenticator_confirm_frame, fullmac_ifc_proxy).await;
140
141 update_sink
142}
143
144pub async fn handle_fourway_eapol_handshake(
153 authenticator: &mut Authenticator,
154 frame_to_client: eapol::KeyFrameBuf,
155 bssid: [u8; 6],
156 client_sta_addr: [u8; 6],
157 fullmac_req_stream: &mut RecordedRequestStream,
158 fullmac_ifc_proxy: &fidl_fullmac::WlanFullmacImplIfcProxy,
159) -> UpdateSink {
160 let mut update_sink = UpdateSink::new();
161 let mic_size = authenticator.get_negotiated_protection().mic_size;
162
163 send_eapol_frame_to_test_realm(
164 authenticator,
165 frame_to_client,
166 bssid.clone(),
167 client_sta_addr.clone(),
168 fullmac_ifc_proxy,
169 )
170 .await;
171 let frame_to_auth_data =
172 get_eapol_frame_from_test_realm(bssid.clone(), fullmac_req_stream, fullmac_ifc_proxy).await;
173 let frame_to_auth = eapol::KeyFrameRx::parse(mic_size as usize, &frame_to_auth_data[..])
174 .expect("Could not parse EAPOL key frame");
175 authenticator
176 .on_eapol_frame(&mut update_sink, eapol::Frame::Key(frame_to_auth))
177 .expect("Could not send EAPOL frame to authenticator");
178
179 let frame_to_client = assert_matches!(update_sink.remove(0), SecAssocUpdate::TxEapolKeyFrame { frame, .. } => frame);
180 send_eapol_frame_to_test_realm(
181 authenticator,
182 frame_to_client,
183 bssid.clone(),
184 client_sta_addr.clone(),
185 fullmac_ifc_proxy,
186 )
187 .await;
188 let frame_to_auth_data =
189 get_eapol_frame_from_test_realm(bssid.clone(), fullmac_req_stream, fullmac_ifc_proxy).await;
190 let frame_to_auth = eapol::KeyFrameRx::parse(mic_size as usize, &frame_to_auth_data[..])
191 .expect("Could not parse EAPOL key frame");
192 authenticator
193 .on_eapol_frame(&mut update_sink, eapol::Frame::Key(frame_to_auth))
194 .expect("Could not send EAPOL frame to authenticator");
195
196 update_sink
197}
198
199async fn send_eapol_frame_to_test_realm(
201 authenticator: &mut Authenticator,
202 frame: eapol::KeyFrameBuf,
203 authenticator_addr: [u8; 6],
204 client_addr: [u8; 6],
205 fullmac_ifc_proxy: &fidl_fullmac::WlanFullmacImplIfcProxy,
206) {
207 fullmac_ifc_proxy
208 .eapol_ind(&fidl_fullmac::WlanFullmacImplIfcEapolIndRequest {
209 src_addr: Some(authenticator_addr),
210 dst_addr: Some(client_addr),
211 data: Some(frame.into()),
212 ..Default::default()
213 })
214 .await
215 .expect("Could not send EAPOL ind");
216 let mut update_sink = UpdateSink::new();
217 authenticator
218 .on_eapol_conf(&mut update_sink, EapolResultCode::Success)
219 .expect("Could not send EAPOL conf to authenticator");
220 assert_eq!(update_sink.len(), 0);
221}
222
223async fn get_eapol_frame_from_test_realm(
225 authenticator_addr: [u8; 6],
226 fullmac_req_stream: &mut RecordedRequestStream,
227 fullmac_ifc_proxy: &fidl_fullmac::WlanFullmacImplIfcProxy,
228) -> Vec<u8> {
229 let frame_data = assert_matches!(fullmac_req_stream.next().await,
230 fidl_fullmac::WlanFullmacImpl_Request::EapolTx { payload, responder } => {
231 responder
232 .send()
233 .expect("Failed to respond to EapolTx");
234 payload.data.unwrap()
235 });
236
237 fullmac_ifc_proxy
238 .eapol_conf(&fidl_fullmac::WlanFullmacImplIfcEapolConfRequest {
239 result_code: Some(fidl_fullmac::EapolTxResult::Success),
240 dst_addr: Some(authenticator_addr),
241 ..Default::default()
242 })
243 .await
244 .expect("Could not send EAPOL conf");
245
246 frame_data
247}
248
249fn get_protection_info(bss_description: &bss::BssDescription) -> wlan_rsn::ProtectionInfo {
250 let (_, rsne) = rsne::from_bytes(bss_description.rsne().unwrap()).expect("Could not get RSNE");
251 wlan_rsn::ProtectionInfo::Rsne(rsne)
252}
253
254async fn get_sae_frame_from_test_realm(
255 fullmac_req_stream: &mut RecordedRequestStream,
256) -> fidl_mlme::SaeFrame {
257 let fullmac_sae_frame = assert_matches!(fullmac_req_stream.next().await,
258 fidl_fullmac::WlanFullmacImpl_Request::SaeFrameTx { frame, responder } => {
259 responder
260 .send()
261 .expect("Failed to respond to SaeFrameTx");
262 frame
263 });
264
265 fidl_mlme::SaeFrame {
266 peer_sta_address: fullmac_sae_frame.peer_sta_address.unwrap(),
267 status_code: fullmac_sae_frame.status_code.unwrap(),
268 seq_num: fullmac_sae_frame.seq_num.unwrap(),
269 sae_fields: fullmac_sae_frame.sae_fields.unwrap(),
270 }
271}
272
273async fn send_sae_frame_to_test_realm(
274 frame: fidl_mlme::SaeFrame,
275 fullmac_ifc_proxy: &fidl_fullmac::WlanFullmacImplIfcProxy,
276) {
277 fullmac_ifc_proxy
278 .sae_frame_rx(&fidl_fullmac::SaeFrame {
279 peer_sta_address: Some(frame.peer_sta_address),
280 status_code: Some(frame.status_code),
281 seq_num: Some(frame.seq_num),
282 sae_fields: Some(frame.sae_fields.clone()),
283 ..Default::default()
284 })
285 .await
286 .expect("Could not send authenticator SAE commit frame");
287}