use crate::key::exchange::handshake::fourway::Fourway;
use crate::key::exchange::handshake::group_key::GroupKey;
use crate::key::exchange::{self, Key};
use crate::key::gtk::Gtk;
use crate::key::igtk::Igtk;
use crate::key::ptk::Ptk;
use crate::rsna::{
Dot11VerifiedKeyFrame, NegotiatedProtection, Role, SecAssocStatus, SecAssocUpdate, UpdateSink,
};
use crate::Error;
use fidl_fuchsia_wlan_mlme::EapolResultCode;
use std::collections::HashSet;
use tracing::{error, info};
use wlan_statemachine::StateMachine;
use zerocopy::SplitByteSlice;
const MAX_KEY_FRAME_RETRIES: u32 = 3;
#[derive(Debug)]
enum Pmksa {
Initialized { pmk: Option<Vec<u8>> },
Established { pmk: Vec<u8> },
}
impl Pmksa {
fn reset(self) -> Self {
match self {
Pmksa::Established { pmk } | Pmksa::Initialized { pmk: Some(pmk) } => {
Pmksa::Initialized { pmk: Some(pmk) }
}
_ => Pmksa::Initialized { pmk: None },
}
}
}
#[derive(Debug, PartialEq)]
enum Ptksa {
Uninitialized { cfg: exchange::Config },
Initialized { method: exchange::Method },
Established { method: exchange::Method, ptk: Ptk },
}
impl Ptksa {
fn initialize(self, pmk: Vec<u8>) -> Self {
match self {
Ptksa::Uninitialized { cfg } => match cfg {
exchange::Config::FourWayHandshake(method_cfg) => {
match Fourway::new(method_cfg.clone(), pmk) {
Err(e) => {
error!("error creating 4-Way Handshake from config: {}", e);
Ptksa::Uninitialized {
cfg: exchange::Config::FourWayHandshake(method_cfg),
}
}
Ok(method) => Ptksa::Initialized {
method: exchange::Method::FourWayHandshake(method),
},
}
}
_ => {
panic!("unsupported method for PTKSA: {:?}", cfg);
}
},
other => other,
}
}
fn reset(self) -> Self {
match self {
Ptksa::Uninitialized { cfg } => Ptksa::Uninitialized { cfg },
Ptksa::Initialized { method } | Ptksa::Established { method, .. } => {
Ptksa::Uninitialized { cfg: method.destroy() }
}
}
}
}
#[derive(Debug, PartialEq)]
enum Gtksa {
Uninitialized {
cfg: Option<exchange::Config>,
},
Initialized {
method: Option<exchange::Method>,
},
Established {
method: Option<exchange::Method>,
installed_gtks: HashSet<Gtk>,
},
}
impl Gtksa {
fn initialize(self, kck: &[u8], kek: &[u8]) -> Self {
match self {
Gtksa::Uninitialized { cfg } => match cfg {
None => Gtksa::Initialized { method: None },
Some(exchange::Config::GroupKeyHandshake(method_cfg)) => {
match GroupKey::new(method_cfg.clone(), kck, kek) {
Err(e) => {
error!("error creating Group KeyHandshake from config: {}", e);
Gtksa::Uninitialized {
cfg: Some(exchange::Config::GroupKeyHandshake(method_cfg)),
}
}
Ok(method) => Gtksa::Initialized {
method: Some(exchange::Method::GroupKeyHandshake(method)),
},
}
}
_ => {
panic!("unsupported method for GTKSA: {:?}", cfg);
}
},
other => other,
}
}
fn reset(self) -> Self {
match self {
Gtksa::Uninitialized { cfg } => Gtksa::Uninitialized { cfg },
Gtksa::Initialized { method } | Gtksa::Established { method, .. } => {
Gtksa::Uninitialized { cfg: method.map(|m| m.destroy()) }
}
}
}
}
#[derive(Debug)]
enum Igtksa {
Uninitialized,
Established { installed_igtks: HashSet<Igtk> },
}
impl Igtksa {
fn reset(self) -> Self {
Igtksa::Uninitialized
}
}
#[derive(Debug)]
pub(crate) struct EssSa {
role: Role,
pub negotiated_protection: NegotiatedProtection,
key_replay_counter: u64,
last_key_frame_buf: Option<(u32, eapol::KeyFrameBuf)>,
updates_awaiting_confirm: Option<UpdateSink>,
pmksa: StateMachine<Pmksa>,
ptksa: StateMachine<Ptksa>,
gtksa: StateMachine<Gtksa>,
igtksa: StateMachine<Igtksa>,
}
impl EssSa {
pub fn new(
role: Role,
pmk: Option<Vec<u8>>,
negotiated_protection: NegotiatedProtection,
ptk_exch_cfg: exchange::Config,
gtk_exch_cfg: Option<exchange::Config>,
) -> Result<EssSa, anyhow::Error> {
info!("spawned ESSSA for: {:?}", role);
let rsna = EssSa {
role,
negotiated_protection,
key_replay_counter: 0,
last_key_frame_buf: None,
updates_awaiting_confirm: None,
pmksa: StateMachine::new(Pmksa::Initialized { pmk }),
ptksa: StateMachine::new(Ptksa::Uninitialized { cfg: ptk_exch_cfg }),
gtksa: StateMachine::new(Gtksa::Uninitialized { cfg: gtk_exch_cfg }),
igtksa: StateMachine::new(Igtksa::Uninitialized),
};
Ok(rsna)
}
#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
pub fn initiate(&mut self, update_sink: &mut UpdateSink) -> Result<(), Error> {
match (self.ptksa.as_ref(), self.gtksa.as_ref(), self.igtksa.as_ref()) {
(Ptksa::Uninitialized { .. }, Gtksa::Uninitialized { .. }, Igtksa::Uninitialized) => (),
(Ptksa::Initialized { .. }, Gtksa::Uninitialized { .. }, Igtksa::Uninitialized) => (),
_ => return Err(Error::UnexpectedEsssaInitiation),
};
info!("establishing ESSSA...");
let pmk = match self.pmksa.as_ref() {
Pmksa::Initialized { pmk: Some(pmk) } => Some(pmk.clone()),
_ => None,
};
if let Some(pmk) = pmk {
self.on_pmk_available(update_sink, pmk)
} else {
Ok(())
}
}
pub fn reset_replay_counter(&mut self) {
info!("resetting ESSSA replay counter");
self.key_replay_counter = 0;
}
pub fn reset_security_associations(&mut self) {
info!("resetting ESSSA security associations");
self.pmksa.replace_state(|state| state.reset());
self.ptksa.replace_state(|state| state.reset());
self.gtksa.replace_state(|state| state.reset());
self.igtksa.replace_state(|state| state.reset());
}
fn is_established(&self) -> bool {
match (self.ptksa.as_ref(), self.gtksa.as_ref()) {
(Ptksa::Established { .. }, Gtksa::Established { .. }) => true,
_ => false,
}
}
#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
fn on_key_confirmed(&mut self, update_sink: &mut UpdateSink, key: Key) -> Result<(), Error> {
let was_esssa_established = self.is_established();
match key {
Key::Pmk(pmk) => {
self.pmksa.replace_state(|state| match state {
Pmksa::Initialized { .. } => {
info!("established PMKSA");
update_sink.push(SecAssocUpdate::Status(SecAssocStatus::PmkSaEstablished));
Pmksa::Established { pmk: pmk.clone() }
}
other => {
error!("received PMK with PMK already being established");
other
}
});
self.ptksa.replace_state(|state| state.initialize(pmk));
if let Ptksa::Initialized {
method:
exchange::Method::FourWayHandshake(Fourway::Authenticator(
authenticator_state_machine,
)),
} = self.ptksa.as_mut()
{
authenticator_state_machine
.try_replace_state(|state| {
state.initiate(update_sink, self.key_replay_counter.into())
})
.map(|_state_machine| ())?;
}
}
Key::Ptk(ptk) => {
self.gtksa.replace_state(|state| state.reset().initialize(ptk.kck(), ptk.kek()));
self.ptksa.replace_state(|state| match state {
Ptksa::Initialized { method } => {
info!("established PTKSA");
update_sink.push(SecAssocUpdate::Key(Key::Ptk(ptk.clone())));
Ptksa::Established { method, ptk }
}
Ptksa::Established { method, .. } => {
info!("re-established new PTKSA; invalidating previous one");
info!("(this is likely a result of using a wrong password)");
if was_esssa_established {
update_sink.push(SecAssocUpdate::Key(Key::Ptk(ptk.clone())));
}
Ptksa::Established { method, ptk }
}
other @ Ptksa::Uninitialized { .. } => {
error!("received PTK in unexpected PTKSA state");
other
}
});
}
Key::Gtk(gtk) => {
self.gtksa.replace_state(|state| match state {
Gtksa::Initialized { method } => {
info!("established GTKSA");
let mut installed_gtks = HashSet::default();
installed_gtks.insert(gtk.clone());
update_sink.push(SecAssocUpdate::Key(Key::Gtk(gtk)));
Gtksa::Established { method, installed_gtks }
}
Gtksa::Established { method, mut installed_gtks } => {
info!("re-established new GTKSA; invalidating previous one");
if !installed_gtks.contains(>k) {
installed_gtks.insert(gtk.clone());
update_sink.push(SecAssocUpdate::Key(Key::Gtk(gtk)));
}
Gtksa::Established { method, installed_gtks }
}
Gtksa::Uninitialized { cfg } => {
error!("received GTK in unexpected GTKSA state");
Gtksa::Uninitialized { cfg }
}
});
}
Key::Igtk(igtk) => {
self.igtksa.replace_state(|state| match state {
Igtksa::Uninitialized => {
info!("established IGTKSA");
let mut installed_igtks = HashSet::default();
installed_igtks.insert(igtk.clone());
update_sink.push(SecAssocUpdate::Key(Key::Igtk(igtk)));
Igtksa::Established { installed_igtks }
}
Igtksa::Established { mut installed_igtks } => {
info!("re-established new IGTKSA; invalidating previous one");
if !installed_igtks.contains(&igtk) {
installed_igtks.insert(igtk.clone());
update_sink.push(SecAssocUpdate::Key(Key::Igtk(igtk)));
}
Igtksa::Established { installed_igtks }
}
});
}
_ => {}
};
Ok(())
}
#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
pub fn on_pmk_available(
&mut self,
update_sink: &mut UpdateSink,
pmk: Vec<u8>,
) -> Result<(), Error> {
let mut new_updates = UpdateSink::default();
let result = self.on_key_confirmed(&mut new_updates, Key::Pmk(pmk));
self.push_updates(update_sink, new_updates);
result
}
fn push_updates(&mut self, update_sink: &mut UpdateSink, mut new_updates: UpdateSink) {
if let Some(updates_awaiting_confirm) = &mut self.updates_awaiting_confirm {
updates_awaiting_confirm.append(&mut new_updates);
return;
}
for update in new_updates {
if let SecAssocUpdate::Key(_) = update {
update_sink.push(update);
} else if let Some(updates_awaiting_confirm) = &mut self.updates_awaiting_confirm {
updates_awaiting_confirm.push(update);
} else {
if let SecAssocUpdate::TxEapolKeyFrame { frame, expect_response } = &update {
if *expect_response {
self.last_key_frame_buf = Some((1, frame.clone()));
} else {
self.last_key_frame_buf = None;
}
self.updates_awaiting_confirm.replace(Default::default());
}
update_sink.push(update);
}
}
}
#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
pub fn on_eapol_conf(
&mut self,
update_sink: &mut UpdateSink,
result: EapolResultCode,
) -> Result<(), Error> {
match self.updates_awaiting_confirm.take() {
Some(updates) => match result {
EapolResultCode::Success => {
self.push_updates(update_sink, updates);
Ok(())
}
EapolResultCode::TransmissionFailure => Err(Error::KeyFrameTransmissionFailed),
},
None => {
error!("Ignored unexpected eapol send confirm");
Ok(())
}
}
}
#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
pub fn on_rsna_retransmission_timeout(
&mut self,
update_sink: &mut UpdateSink,
) -> Result<(), Error> {
if let Some(updates) = &self.updates_awaiting_confirm {
return Err(Error::NoKeyFrameTransmissionConfirm(updates.len()));
}
if let Some((attempt, key_frame)) = self.last_key_frame_buf.as_mut() {
*attempt += 1;
if *attempt > MAX_KEY_FRAME_RETRIES {
return Ok(());
}
update_sink.push(SecAssocUpdate::TxEapolKeyFrame {
frame: key_frame.clone(),
expect_response: true,
});
self.updates_awaiting_confirm = Some(Default::default());
}
Ok(())
}
pub fn incomplete_reason(&self) -> Error {
if let Some(updates) = &self.updates_awaiting_confirm {
return Error::NoKeyFrameTransmissionConfirm(updates.len());
}
match self.ptksa.as_ref() {
Ptksa::Uninitialized { .. } => {
return Error::EapolHandshakeIncomplete("PTKSA never initialized".to_string());
}
Ptksa::Initialized { method } | Ptksa::Established { method, .. } => {
if let Err(error) = method.on_rsna_response_timeout() {
return error;
}
}
}
if !matches!(self.gtksa.as_ref(), Gtksa::Established { .. }) {
return Error::EapolHandshakeIncomplete("GTKSA never established".to_string());
}
Error::EapolHandshakeIncomplete("Unexpected timeout while establishing RSNA".to_string())
}
#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
pub fn on_eapol_frame<B: SplitByteSlice>(
&mut self,
update_sink: &mut UpdateSink,
frame: eapol::Frame<B>,
) -> Result<(), Error> {
let on_eapol_key_frame_updates = match frame {
eapol::Frame::Key(key_frame) => {
let mut on_eapol_key_frame_updates = UpdateSink::default();
self.on_eapol_key_frame(&mut on_eapol_key_frame_updates, key_frame)?;
self.last_key_frame_buf.take();
if let Role::Authenticator = self.role {
for update in &on_eapol_key_frame_updates {
if let SecAssocUpdate::TxEapolKeyFrame { frame, .. } = update {
let key_replay_counter =
frame.keyframe().key_frame_fields.key_replay_counter.to_native();
if key_replay_counter <= self.key_replay_counter {
error!("tx EAPOL Key frame uses invalid key replay counter: {:?} ({:?})",
key_replay_counter,
self.key_replay_counter);
}
self.key_replay_counter = key_replay_counter;
}
}
}
on_eapol_key_frame_updates
}
_ => UpdateSink::default(),
};
let was_esssa_established = self.is_established();
let mut new_updates = UpdateSink::default();
for update in on_eapol_key_frame_updates {
match update {
SecAssocUpdate::Key(key) => {
if let Err(e) = self.on_key_confirmed(&mut new_updates, key) {
error!("error while processing key: {}", e);
};
}
_ => new_updates.push(update),
}
}
if !was_esssa_established && self.is_established() {
info!("established ESSSA");
new_updates.push(SecAssocUpdate::Status(SecAssocStatus::EssSaEstablished));
}
self.push_updates(update_sink, new_updates);
Ok(())
}
#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
fn on_eapol_key_frame<B: SplitByteSlice>(
&mut self,
update_sink: &mut UpdateSink,
frame: eapol::KeyFrameRx<B>,
) -> Result<(), Error> {
let verified_frame = match Dot11VerifiedKeyFrame::from_frame(
frame,
&self.role,
&self.negotiated_protection,
self.key_replay_counter,
) {
Err(e @ Error::InvalidKeyReplayCounter(_, _)) => {
info!("Ignoring eapol frame: {}", e);
return Ok(());
}
result => result?,
};
let raw_frame = verified_frame.unsafe_get_raw();
let frame_has_mic = raw_frame.key_frame_fields.key_info().key_mic();
let frame_key_replay_counter = raw_frame.key_frame_fields.key_replay_counter.to_native();
match self.pmksa.as_mut() {
Pmksa::Initialized { .. } => return Ok(()),
Pmksa::Established { .. } => {}
};
let result = if raw_frame.key_frame_fields.key_info().key_type() == eapol::KeyType::PAIRWISE
{
match self.ptksa.as_mut() {
Ptksa::Uninitialized { .. } => Ok(()),
Ptksa::Initialized { method } | Ptksa::Established { method, .. } => {
method.on_eapol_key_frame(update_sink, verified_frame)
}
}
} else if raw_frame.key_frame_fields.key_info().key_type() == eapol::KeyType::GROUP_SMK {
match self.gtksa.as_mut() {
Gtksa::Uninitialized { .. } => Ok(()),
Gtksa::Initialized { method } | Gtksa::Established { method, .. } => match method {
Some(method) => method.on_eapol_key_frame(update_sink, verified_frame),
None => {
error!("received group key EAPOL Key frame with GTK re-keying disabled");
Ok(())
}
},
}
} else {
error!(
"unsupported EAPOL Key frame key type: {:?}",
raw_frame.key_frame_fields.key_info().key_type()
);
Ok(())
};
if frame_has_mic {
if let Role::Supplicant = self.role {
for update in update_sink {
if let SecAssocUpdate::TxEapolKeyFrame { .. } = update {
self.key_replay_counter = frame_key_replay_counter;
break;
}
}
}
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::key::exchange::compute_mic;
use crate::rsna::test_util::expect_eapol_resp;
use crate::rsna::{test_util, AuthStatus};
use crate::{Authenticator, Supplicant};
use wlan_common::assert_variant;
use wlan_common::ie::get_rsn_ie_bytes;
use wlan_common::ie::rsn::fake_wpa2_s_rsne;
const ANONCE: [u8; 32] = [0x1A; 32];
const GTK: [u8; 16] = [0x1B; 16];
const GTK_REKEY: [u8; 16] = [0x1F; 16];
const GTK_REKEY_2: [u8; 16] = [0x2F; 16];
#[test]
fn test_supplicant_with_wpa3_authenticator() {
let mut supplicant = test_util::get_wpa3_supplicant();
let mut authenticator = test_util::get_wpa3_authenticator();
let mut s_updates = vec![];
supplicant.start(&mut s_updates).expect("Failed starting Supplicant");
assert!(s_updates.is_empty(), "{:?}", s_updates);
let result = supplicant.on_sae_handshake_ind(&mut s_updates);
assert!(result.is_ok(), "Supplicant failed to ind SAE handshake");
let s_sae_frame_vec = test_util::expect_sae_frame_vec(&s_updates[..]);
test_util::expect_schedule_sae_timeout(&s_updates[..]);
assert_eq!(s_updates.len(), 2, "{:?}", s_updates);
let mut a_updates = vec![];
for s_sae_frame in s_sae_frame_vec {
let result = authenticator.on_sae_frame_rx(&mut a_updates, s_sae_frame);
assert!(result.is_ok(), "Authenticator failed to rx SAE handshake message");
}
let a_sae_frame_vec = test_util::expect_sae_frame_vec(&a_updates[..]);
test_util::expect_schedule_sae_timeout(&a_updates[..]);
assert_eq!(a_updates.len(), 3, "{:?}", a_updates);
let mut s_updates = vec![];
for a_sae_frame in a_sae_frame_vec {
let result = supplicant.on_sae_frame_rx(&mut s_updates, a_sae_frame);
assert!(result.is_ok(), "Supplicant failed to rx SAE handshake message");
}
let s_sae_frame_vec = test_util::expect_sae_frame_vec(&s_updates[..]);
test_util::expect_schedule_sae_timeout(&s_updates[..]);
test_util::expect_reported_pmk(&s_updates[..]);
test_util::expect_reported_sae_auth_status(&s_updates[..], AuthStatus::Success);
test_util::expect_reported_status(&s_updates[..], SecAssocStatus::PmkSaEstablished);
assert_eq!(s_updates.len(), 5, "{:?}", s_updates);
let mut a_updates = vec![];
for s_sae_frame in s_sae_frame_vec {
let result = authenticator.on_sae_frame_rx(&mut a_updates, s_sae_frame);
assert!(result.is_ok(), "Authenticator failed to rx SAE handshake message");
}
test_util::expect_reported_pmk(&a_updates[..]);
test_util::expect_reported_sae_auth_status(&a_updates[..], AuthStatus::Success);
test_util::expect_reported_status(&a_updates[..], SecAssocStatus::PmkSaEstablished);
let msg1 = test_util::expect_eapol_resp(&a_updates[..]);
authenticator
.on_eapol_conf(&mut a_updates, EapolResultCode::Success)
.expect("Failed eapol conf");
assert_eq!(a_updates.len(), 4, "{:?}", a_updates);
test_eapol_exchange(&mut supplicant, &mut authenticator, Some(msg1), true);
}
#[test]
fn test_supplicant_with_wpa2_authenticator() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut authenticator = test_util::get_wpa2_authenticator();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
test_eapol_exchange(&mut supplicant, &mut authenticator, None, false);
}
#[test]
fn test_replay_first_message() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert!(result.is_ok());
let first_msg2 = expect_eapol_resp(&updates[..]);
let first_fields = first_msg2.keyframe().key_frame_fields;
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(3);
});
assert!(result.is_ok());
let second_msg2 = expect_eapol_resp(&updates[..]);
let second_fields = second_msg2.keyframe().key_frame_fields;
assert_eq!(second_fields.key_replay_counter.to_native(), 3);
assert_eq!(first_fields.key_nonce, second_fields.key_nonce);
}
#[test]
fn test_first_message_does_not_change_replay_counter() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
assert_eq!(0, supplicant.esssa.key_replay_counter);
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(0);
});
assert!(result.is_ok());
expect_eapol_resp(&updates[..]);
assert_eq!(0, supplicant.esssa.key_replay_counter);
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert!(result.is_ok());
expect_eapol_resp(&updates[..]);
assert_eq!(0, supplicant.esssa.key_replay_counter);
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(0);
});
assert!(result.is_ok());
assert_eq!(0, supplicant.esssa.key_replay_counter);
expect_eapol_resp(&updates[..]);
}
#[test]
fn test_zero_key_replay_counter_msg1() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(0);
});
assert!(result.is_ok());
expect_eapol_resp(&updates[..]);
}
#[test]
fn test_nonzero_key_replay_counter_msg1() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert!(result.is_ok());
expect_eapol_resp(&updates[..]);
}
#[test]
fn test_zero_key_replay_counter_lower_msg3_counter() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
assert_eq!(0, supplicant.esssa.key_replay_counter);
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert!(result.is_ok());
assert_eq!(0, supplicant.esssa.key_replay_counter);
let msg2 = expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
let (result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(0);
});
assert!(result.is_ok());
assert_eq!(0, supplicant.esssa.key_replay_counter);
test_util::expect_reported_ptk(&updates[..]);
}
#[test]
fn test_key_replay_counter_updated_after_msg3() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
let mut result;
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
(result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert!(result.is_ok());
let msg2 = expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
(result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(5);
});
assert!(result.is_ok());
assert_eq!(5, supplicant.esssa.key_replay_counter);
test_util::expect_reported_ptk(&updates[..]);
(result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(0);
});
assert!(result.is_ok());
assert_eq!(5, supplicant.esssa.key_replay_counter);
assert!(updates.is_empty(), "{:?}", updates);
supplicant.reset();
updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
assert_eq!(0, supplicant.esssa.key_replay_counter);
let (result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(0);
});
assert!(result.is_ok());
expect_eapol_resp(&updates[..]);
}
#[test]
fn test_key_replay_counter_not_updated_for_invalid_mic_msg3() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
let mut result: Result<(), Error>;
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
(result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert!(result.is_ok());
assert_eq!(0, supplicant.esssa.key_replay_counter);
let msg2 = expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
let msg3 = test_util::get_wpa2_4whs_msg3_with_mic_modifier(
&ptk,
&ANONCE[..],
>K,
|msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(5);
},
|mic| {
mic[0] = mic[0].wrapping_add(1);
},
);
updates = UpdateSink::default();
result = supplicant.on_eapol_frame(&mut updates, eapol::Frame::Key(msg3.keyframe()));
assert!(result.is_ok());
assert_eq!(0, supplicant.esssa.key_replay_counter);
}
#[test]
fn test_zero_key_replay_counter_valid_msg3() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
let mut result;
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
(result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(0);
});
assert!(result.is_ok());
let msg2 = expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
(result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert!(result.is_ok());
test_util::expect_reported_ptk(&updates[..]);
}
#[test]
fn test_zero_key_replay_counter_replayed_msg3() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
let mut result;
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
assert_eq!(0, supplicant.esssa.key_replay_counter);
(result, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(0);
});
assert!(result.is_ok());
let msg2 = expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
(result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(2);
});
assert!(result.is_ok());
assert_eq!(2, supplicant.esssa.key_replay_counter);
test_util::expect_reported_ptk(&updates[..]);
(result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(2);
});
assert!(result.is_ok());
assert_eq!(2, supplicant.esssa.key_replay_counter);
assert!(updates.is_empty(), "{:?}", updates);
(result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(3);
});
assert!(result.is_ok());
assert_eq!(3, supplicant.esssa.key_replay_counter);
assert!(!updates.is_empty());
}
#[test]
fn test_replayed_msg1_ptk_installation_different_anonces() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let (_, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert_eq!(test_util::get_reported_ptk(&updates[..]), None);
let msg2 = expect_eapol_resp(&updates[..]);
let msg2_frame = msg2.keyframe();
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let first_ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
let first_nonce = msg2_frame.key_frame_fields.key_nonce;
let (_, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(2);
msg1.key_frame_fields.key_nonce = [99; 32];
});
assert_eq!(test_util::get_reported_ptk(&updates[..]), None);
let msg2 = expect_eapol_resp(&updates[..]);
let msg2_frame = msg2.keyframe();
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let second_ptk = test_util::get_ptk(&[99; 32][..], &snonce[..]);
let second_nonce = msg2_frame.key_frame_fields.key_nonce;
let (_, updates) = send_fourway_msg3(&mut supplicant, &second_ptk, |msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(3);
msg3.key_frame_fields.key_nonce = [99; 32];
});
let installed_ptk = test_util::expect_reported_ptk(&updates[..]);
assert_ne!(first_nonce, second_nonce);
assert_ne!(&first_ptk, &second_ptk);
assert_eq!(installed_ptk, second_ptk);
}
#[test]
fn test_replayed_msg1_ptk_installation_same_anonces() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let (_, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(1);
});
assert_eq!(test_util::get_reported_ptk(&updates[..]), None);
let msg2 = expect_eapol_resp(&updates[..]);
let msg2_frame = msg2.keyframe();
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let first_ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
let first_nonce = msg2_frame.key_frame_fields.key_nonce;
let (_, updates) = send_fourway_msg1(&mut supplicant, |msg1| {
msg1.key_frame_fields.key_replay_counter.set_from_native(2);
});
assert_eq!(test_util::get_reported_ptk(&updates[..]), None);
let msg2 = expect_eapol_resp(&updates[..]);
let msg2_frame = msg2.keyframe();
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let second_ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
let second_nonce = msg2_frame.key_frame_fields.key_nonce;
let (_, updates) = send_fourway_msg3(&mut supplicant, &second_ptk, |msg3| {
msg3.key_frame_fields.key_replay_counter.set_from_native(3);
});
let installed_ptk = test_util::expect_reported_ptk(&updates[..]);
assert_eq!(first_nonce, second_nonce);
assert_eq!(&first_ptk, &second_ptk);
assert_eq!(installed_ptk, second_ptk);
}
#[test]
fn test_supplicant_wpa2_ccmp128_psk() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let (result, updates) = send_fourway_msg1(&mut supplicant, |_| {});
assert!(result.is_ok());
let msg2_buf = expect_eapol_resp(&updates[..]);
let msg2 = msg2_buf.keyframe();
let s_rsne = fake_wpa2_s_rsne();
let s_rsne_data = get_rsn_ie_bytes(&s_rsne);
assert_eq!({ msg2.eapol_fields.version }, eapol::ProtocolVersion::IEEE802DOT1X2001);
assert_eq!({ msg2.eapol_fields.packet_type }, eapol::PacketType::KEY);
let buf = msg2.to_bytes(false);
assert_eq!(msg2.eapol_fields.packet_body_len.to_native() as usize, buf.len() - 4);
assert_eq!({ msg2.key_frame_fields.descriptor_type }, eapol::KeyDescriptor::IEEE802DOT11);
assert_eq!(msg2.key_frame_fields.key_info(), eapol::KeyInformation(0x010A));
assert_eq!(msg2.key_frame_fields.key_len.to_native(), 0);
assert_eq!(msg2.key_frame_fields.key_replay_counter.to_native(), 1);
assert!(!test_util::is_zero(&msg2.key_frame_fields.key_nonce[..]));
assert!(test_util::is_zero(&msg2.key_frame_fields.key_iv[..]));
assert_eq!(msg2.key_frame_fields.key_rsc.to_native(), 0);
assert!(!test_util::is_zero(&msg2.key_mic[..]));
assert_eq!(msg2.key_mic.len(), test_util::mic_len());
assert_eq!(msg2.key_data.len(), 20);
assert_eq!(&msg2.key_data[..], &s_rsne_data[..]);
let snonce = msg2.key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
let (result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |_| {});
assert!(result.is_ok());
let msg4_buf = expect_eapol_resp(&updates[..]);
let msg4 = msg4_buf.keyframe();
assert_eq!({ msg4.eapol_fields.version }, eapol::ProtocolVersion::IEEE802DOT1X2001);
assert_eq!({ msg4.eapol_fields.packet_type }, eapol::PacketType::KEY);
assert_eq!(msg4.eapol_fields.packet_body_len.to_native() as usize, &msg4_buf[..].len() - 4);
assert_eq!({ msg4.key_frame_fields.descriptor_type }, eapol::KeyDescriptor::IEEE802DOT11);
assert_eq!(msg4.key_frame_fields.key_info(), eapol::KeyInformation(0x030A));
assert_eq!(msg4.key_frame_fields.key_len.to_native(), 0);
assert_eq!(msg4.key_frame_fields.key_replay_counter.to_native(), 2);
assert!(test_util::is_zero(&msg4.key_frame_fields.key_nonce[..]));
assert!(test_util::is_zero(&msg4.key_frame_fields.key_iv[..]));
assert_eq!(msg4.key_frame_fields.key_rsc.to_native(), 0);
assert!(!test_util::is_zero(&msg4.key_mic[..]));
assert_eq!(msg4.key_mic.len(), test_util::mic_len());
assert_eq!(msg4.key_data.len(), 0);
assert!(test_util::is_zero(&msg4.key_data[..]));
let mic = compute_mic(ptk.kck(), &test_util::get_rsne_protection(), &msg4)
.expect("error computing MIC");
assert_eq!(&msg4.key_mic[..], &mic[..]);
let reported_ptk = test_util::expect_reported_ptk(&updates[..]);
assert_eq!(ptk.ptk, reported_ptk.ptk);
let reported_gtk = test_util::expect_reported_gtk(&updates[..]);
assert_eq!(>K[..], &reported_gtk.bytes[..]);
let reported_status =
test_util::expect_reported_status(&updates[..], SecAssocStatus::EssSaEstablished);
assert_eq!(reported_status, SecAssocStatus::EssSaEstablished);
let (result, updates) = send_group_key_msg1(&mut supplicant, &ptk, GTK_REKEY, 3, 3);
assert!(result.is_ok());
let msg2_buf = expect_eapol_resp(&updates[..]);
let msg2 = msg2_buf.keyframe();
assert_eq!({ msg2.eapol_fields.version }, eapol::ProtocolVersion::IEEE802DOT1X2001);
assert_eq!({ msg2.eapol_fields.packet_type }, eapol::PacketType::KEY);
assert_eq!(msg2.eapol_fields.packet_body_len.to_native() as usize, &msg2_buf[..].len() - 4);
assert_eq!({ msg2.key_frame_fields.descriptor_type }, eapol::KeyDescriptor::IEEE802DOT11);
assert_eq!(msg2.key_frame_fields.key_info(), eapol::KeyInformation(0x0302));
assert_eq!(msg2.key_frame_fields.key_len.to_native(), 0);
assert_eq!(msg2.key_frame_fields.key_replay_counter.to_native(), 3);
assert!(test_util::is_zero(&msg2.key_frame_fields.key_nonce[..]));
assert!(test_util::is_zero(&msg2.key_frame_fields.key_iv[..]));
assert_eq!(msg2.key_frame_fields.key_rsc.to_native(), 0);
assert!(!test_util::is_zero(&msg2.key_mic[..]));
assert_eq!(msg2.key_mic.len(), test_util::mic_len());
assert_eq!(msg2.key_data.len(), 0);
assert!(test_util::is_zero(&msg2.key_data[..]));
let mic = compute_mic(ptk.kck(), &test_util::get_rsne_protection(), &msg2)
.expect("error computing MIC");
assert_eq!(&msg2.key_mic[..], &mic[..]);
assert_eq!(test_util::get_reported_ptk(&updates[..]), None);
let reported_gtk = test_util::expect_reported_gtk(&updates[..]);
assert_eq!(>K_REKEY[..], &reported_gtk.bytes[..]);
}
#[test]
fn test_supplicant_no_gtk_reinstallation_from_4way() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let updates = send_fourway_msg1(&mut supplicant, |_| {}).1;
let msg2 = test_util::expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
let _ = send_fourway_msg3(&mut supplicant, &ptk, |_| {});
let (result, updates) = send_group_key_msg1(&mut supplicant, &ptk, GTK, 2, 3);
assert!(result.is_ok());
let msg2 = test_util::expect_eapol_resp(&updates[..]);
let keyframe = msg2.keyframe();
assert_eq!(keyframe.eapol_fields.version, eapol::ProtocolVersion::IEEE802DOT1X2001);
assert_eq!(keyframe.eapol_fields.packet_type, eapol::PacketType::KEY);
assert_eq!(keyframe.eapol_fields.packet_body_len.to_native() as usize, msg2.len() - 4);
assert_eq!(keyframe.key_frame_fields.descriptor_type, eapol::KeyDescriptor::IEEE802DOT11);
assert_eq!(keyframe.key_frame_fields.key_info().0, 0x0302);
assert_eq!(keyframe.key_frame_fields.key_len.to_native(), 0);
assert_eq!(keyframe.key_frame_fields.key_replay_counter.to_native(), 3);
assert!(test_util::is_zero(&keyframe.key_frame_fields.key_nonce[..]));
assert!(test_util::is_zero(&keyframe.key_frame_fields.key_iv[..]));
assert_eq!(keyframe.key_frame_fields.key_rsc.to_native(), 0);
assert!(!test_util::is_zero(&keyframe.key_mic[..]));
assert_eq!(keyframe.key_mic.len(), test_util::mic_len());
assert_eq!(keyframe.key_data.len(), 0);
assert!(test_util::is_zero(&keyframe.key_data[..]));
let mic = compute_mic(ptk.kck(), &test_util::get_rsne_protection(), &keyframe)
.expect("error computing MIC");
assert_eq!(&keyframe.key_mic[..], &mic[..]);
assert_eq!(test_util::get_reported_ptk(&updates[..]), None);
assert_eq!(test_util::get_reported_gtk(&updates[..]), None);
}
#[test]
fn test_supplicant_no_gtk_reinstallation() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let updates = send_fourway_msg1(&mut supplicant, |_| {}).1;
let msg2 = test_util::expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
let _ = send_fourway_msg3(&mut supplicant, &ptk, |_| {});
let (result, updates) = send_group_key_msg1(&mut supplicant, &ptk, GTK_REKEY, 3, 3);
assert!(result.is_ok());
let reported_gtk = test_util::expect_reported_gtk(&updates[..]);
assert_eq!(&reported_gtk.bytes[..], >K_REKEY[..]);
let (result, updates) = send_group_key_msg1(&mut supplicant, &ptk, GTK_REKEY_2, 1, 4);
assert!(result.is_ok(), "{:?}", result);
let reported_gtk = test_util::expect_reported_gtk(&updates[..]);
assert_eq!(&reported_gtk.bytes[..], >K_REKEY_2[..]);
let (result, updates) = send_group_key_msg1(&mut supplicant, &ptk, GTK_REKEY, 3, 5);
assert!(result.is_ok());
assert_eq!(test_util::get_reported_gtk(&updates[..]), None);
}
#[test]
fn test_rsna_retransmission_timeout() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
updates = send_fourway_msg1(&mut supplicant, |_| {}).1;
let msg2 = test_util::expect_eapol_resp(&updates[..]);
updates = vec![];
supplicant
.on_eapol_conf(&mut updates, EapolResultCode::Success)
.expect("Failed to send eapol conf");
assert!(updates.is_empty());
for _ in 1..MAX_KEY_FRAME_RETRIES {
updates = vec![];
supplicant
.on_rsna_retransmission_timeout(&mut updates)
.expect("Failed to send key frame timeout");
let msg2_retry = test_util::expect_eapol_resp(&updates[..]);
supplicant
.on_eapol_conf(&mut updates, EapolResultCode::Success)
.expect("Failed to send eapol conf");
assert_eq!(msg2, msg2_retry);
}
updates = vec![];
assert_variant!(supplicant.on_rsna_retransmission_timeout(&mut updates), Ok(()));
assert!(updates.is_empty(), "{:?}", updates);
}
#[test]
fn test_rsna_retransmission_timeout_retries_reset() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
for _ in 0..3 {
updates = send_fourway_msg1(&mut supplicant, |_| {}).1;
let msg2 = test_util::expect_eapol_resp(&updates[..]);
updates = vec![];
supplicant
.on_eapol_conf(&mut updates, EapolResultCode::Success)
.expect("Failed to send eapol conf");
assert!(updates.is_empty(), "{:?}", updates);
for _ in 1..MAX_KEY_FRAME_RETRIES {
updates = vec![];
supplicant
.on_rsna_retransmission_timeout(&mut updates)
.expect("Failed to send key frame timeout");
let msg2_retry = test_util::expect_eapol_resp(&updates[..]);
supplicant
.on_eapol_conf(&mut updates, EapolResultCode::Success)
.expect("Failed to send eapol conf");
assert_eq!(msg2, msg2_retry);
}
updates = vec![];
assert_variant!(supplicant.on_rsna_retransmission_timeout(&mut updates), Ok(()));
assert!(updates.is_empty(), "{:?}", updates);
}
}
#[test]
fn test_overall_timeout_before_msg1() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
assert_variant!(supplicant.incomplete_reason(), Error::EapolHandshakeNotStarted);
}
#[test]
fn test_overall_timeout_after_msg2() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
(_, updates) = send_fourway_msg1(&mut supplicant, |_| {});
let _msg2 = test_util::expect_eapol_resp(&updates[..]);
updates = vec![];
supplicant
.on_eapol_conf(&mut updates, EapolResultCode::Success)
.expect("Failed to send eapol conf");
assert!(updates.is_empty(), "{:?}", updates);
assert_variant!(supplicant.incomplete_reason(), Error::LikelyWrongCredential);
}
#[test]
fn test_overall_timeout_before_conf() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = UpdateSink::default();
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let msg = test_util::get_wpa2_4whs_msg1(&ANONCE[..], |_| {});
supplicant
.on_eapol_frame(&mut updates, eapol::Frame::Key(msg.keyframe()))
.expect("Failed to send eapol frame");
let _msg2 = test_util::expect_eapol_resp(&updates[..]);
assert_variant!(supplicant.incomplete_reason(), Error::NoKeyFrameTransmissionConfirm(0));
}
#[test]
fn test_rsna_retransmission_timeout_retry_without_conf() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = vec![];
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
updates = send_fourway_msg1(&mut supplicant, |_| {}).1;
let msg2 = test_util::expect_eapol_resp(&updates[..]);
updates = vec![];
supplicant
.on_eapol_conf(&mut updates, EapolResultCode::Success)
.expect("Failed to send eapol conf");
assert!(updates.is_empty(), "{:?}", updates);
updates = vec![];
supplicant
.on_rsna_retransmission_timeout(&mut updates)
.expect("Failed to send key frame timeout");
let msg2_retry = test_util::expect_eapol_resp(&updates[..]);
assert_eq!(msg2, msg2_retry);
updates = vec![];
assert_variant!(
supplicant.on_rsna_retransmission_timeout(&mut updates),
Err(Error::NoKeyFrameTransmissionConfirm(0))
);
}
#[test]
fn test_msg2_out_of_order_conf() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = UpdateSink::default();
let result: Result<(), Error>;
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let msg = test_util::get_wpa2_4whs_msg1(&ANONCE[..], |_| {});
supplicant
.on_eapol_frame(&mut updates, eapol::Frame::Key(msg.keyframe()))
.expect("Failed to send eapol frame");
let msg2 = test_util::expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
(result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |_| {});
result.expect("Failed to send msg3");
assert!(updates.is_empty(), "{:?}", updates);
updates = UpdateSink::default();
supplicant
.on_eapol_conf(&mut updates, EapolResultCode::Success)
.expect("Failed to send eapol conf");
assert_eq!(updates.len(), 3);
test_util::expect_eapol_resp(&updates[..]);
test_util::expect_reported_ptk(&updates[..]);
test_util::expect_reported_gtk(&updates[..]);
supplicant
.on_eapol_conf(&mut updates, EapolResultCode::Success)
.expect("Failed to send eapol conf");
test_util::expect_reported_status(&updates[..], SecAssocStatus::EssSaEstablished);
}
#[test]
fn test_msg2_no_conf() {
let mut supplicant = test_util::get_wpa2_supplicant();
let mut updates = UpdateSink::default();
let result: Result<(), Error>;
supplicant.start(&mut updates).expect("Failed starting Supplicant");
assert_eq!(updates.len(), 1, "{:?}", updates);
test_util::expect_reported_status(&updates[..], SecAssocStatus::PmkSaEstablished);
let msg = test_util::get_wpa2_4whs_msg1(&ANONCE[..], |_| {});
supplicant
.on_eapol_frame(&mut updates, eapol::Frame::Key(msg.keyframe()))
.expect("Failed to send eapol frame");
let msg2 = test_util::expect_eapol_resp(&updates[..]);
let snonce = msg2.keyframe().key_frame_fields.key_nonce;
let ptk = test_util::get_ptk(&ANONCE[..], &snonce[..]);
(result, updates) = send_fourway_msg3(&mut supplicant, &ptk, |_| {});
result.expect("Failed to send msg3");
assert!(updates.is_empty(), "{:?}", updates);
updates = vec![];
assert_variant!(
supplicant.on_rsna_retransmission_timeout(&mut updates),
Err(Error::NoKeyFrameTransmissionConfirm(4))
);
}
fn test_eapol_exchange(
supplicant: &mut Supplicant,
authenticator: &mut Authenticator,
msg1: Option<eapol::KeyFrameBuf>,
wpa3: bool,
) {
let mut a_updates = vec![];
let mut result: Result<(), Error>;
result = authenticator.initiate(&mut a_updates);
assert!(result.is_ok(), "Authenticator failed initiating: {}", result.unwrap_err());
if wpa3 {
assert!(
msg1.is_some(),
"WPA3 EAPOL exchange starting without message constructed immediately after SAE"
);
}
let msg1 = match msg1 {
Some(msg1) => {
assert_eq!(a_updates.len(), 0, "{:?}", a_updates);
msg1
}
None => {
assert_eq!(a_updates.len(), 2);
test_util::expect_reported_status(&a_updates, SecAssocStatus::PmkSaEstablished);
let resp = test_util::expect_eapol_resp(&a_updates[..]);
authenticator
.on_eapol_conf(&mut a_updates, EapolResultCode::Success)
.expect("Failed eapol conf");
resp
}
};
let mut s_updates = vec![];
result = supplicant.on_eapol_frame(&mut s_updates, eapol::Frame::Key(msg1.keyframe()));
assert!(result.is_ok(), "Supplicant failed processing msg #1: {}", result.unwrap_err());
let msg2 = test_util::expect_eapol_resp(&s_updates[..]);
supplicant
.on_eapol_conf(&mut s_updates, EapolResultCode::Success)
.expect("Failed eapol conf");
assert_eq!(s_updates.len(), 1, "{:?}", s_updates);
let mut a_updates = vec![];
result = authenticator.on_eapol_frame(&mut a_updates, eapol::Frame::Key(msg2.keyframe()));
assert!(result.is_ok(), "Authenticator failed processing msg #2: {}", result.unwrap_err());
let msg3 = test_util::expect_eapol_resp(&a_updates[..]);
authenticator
.on_eapol_conf(&mut a_updates, EapolResultCode::Success)
.expect("Failed eapol conf");
assert_eq!(a_updates.len(), 1, "{:?}", a_updates);
let mut s_updates = vec![];
result = supplicant.on_eapol_frame(&mut s_updates, eapol::Frame::Key(msg3.keyframe()));
assert!(result.is_ok(), "Supplicant failed processing msg #3: {}", result.unwrap_err());
let msg4 = test_util::expect_eapol_resp(&s_updates[..]);
let s_ptk = test_util::expect_reported_ptk(&s_updates[..]);
let s_gtk = test_util::expect_reported_gtk(&s_updates[..]);
let s_igtk = if wpa3 {
assert_eq!(s_updates.len(), 4, "{:?}", s_updates);
Some(test_util::expect_reported_igtk(&s_updates[..]))
} else {
assert_eq!(s_updates.len(), 3, "{:?}", s_updates);
None
};
supplicant
.on_eapol_conf(&mut s_updates, EapolResultCode::Success)
.expect("Failed eapol conf");
test_util::expect_reported_status(&s_updates, SecAssocStatus::EssSaEstablished);
let mut a_updates = vec![];
result = authenticator.on_eapol_frame(&mut a_updates, eapol::Frame::Key(msg4.keyframe()));
assert!(result.is_ok(), "Authenticator failed processing msg #4: {}", result.unwrap_err());
let a_ptk = test_util::expect_reported_ptk(&a_updates[..]);
let a_gtk = test_util::expect_reported_gtk(&a_updates[..]);
let a_igtk = if wpa3 {
assert_eq!(a_updates.len(), 4, "{:?}", a_updates);
Some(test_util::expect_reported_igtk(&a_updates[..]))
} else {
assert_eq!(a_updates.len(), 3, "{:?}", a_updates);
None
};
test_util::expect_reported_status(&a_updates, SecAssocStatus::EssSaEstablished);
assert_eq!(a_ptk, s_ptk);
assert_eq!(a_gtk, s_gtk);
assert_eq!(a_igtk, s_igtk);
}
fn send_eapol_conf(supplicant: &mut Supplicant, updates: &mut UpdateSink) -> Result<(), Error> {
let mut sent_frame = false;
for update in &updates[..] {
if let SecAssocUpdate::TxEapolKeyFrame { .. } = update {
sent_frame = true;
}
}
if sent_frame {
supplicant.on_eapol_conf(updates, EapolResultCode::Success)
} else {
Ok(())
}
}
fn send_fourway_msg1<F>(
supplicant: &mut Supplicant,
msg_modifier: F,
) -> (Result<(), Error>, UpdateSink)
where
F: Fn(&mut eapol::KeyFrameTx),
{
let msg = test_util::get_wpa2_4whs_msg1(&ANONCE[..], msg_modifier);
let mut updates = UpdateSink::default();
let result = supplicant.on_eapol_frame(&mut updates, eapol::Frame::Key(msg.keyframe()));
let result = result.and_then(|_| send_eapol_conf(supplicant, &mut updates));
(result, updates)
}
fn send_fourway_msg3<F>(
supplicant: &mut Supplicant,
ptk: &Ptk,
msg_modifier: F,
) -> (Result<(), Error>, UpdateSink)
where
F: Fn(&mut eapol::KeyFrameTx),
{
let msg = test_util::get_wpa2_4whs_msg3(ptk, &ANONCE[..], >K, msg_modifier);
let mut updates = UpdateSink::default();
let result = supplicant.on_eapol_frame(&mut updates, eapol::Frame::Key(msg.keyframe()));
let result = result.and_then(|_| send_eapol_conf(supplicant, &mut updates));
(result, updates)
}
fn send_group_key_msg1(
supplicant: &mut Supplicant,
ptk: &Ptk,
gtk: [u8; 16],
key_id: u8,
key_replay_counter: u64,
) -> (Result<(), Error>, UpdateSink) {
let msg = test_util::get_group_key_hs_msg1(ptk, >k[..], key_id, key_replay_counter);
let mut updates = UpdateSink::default();
let result = supplicant.on_eapol_frame(&mut updates, eapol::Frame::Key(msg.keyframe()));
let result = result.and_then(|_| send_eapol_conf(supplicant, &mut updates));
(result, updates)
}
}