| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| mod authenticator; |
| mod supplicant; |
| |
| use crate::crypto_utils::nonce::NonceReader; |
| use crate::key::{exchange, gtk::GtkProvider}; |
| use crate::rsna::{ |
| KeyFrameKeyDataState, KeyFrameState, NegotiatedRsne, Role, SecAssocUpdate, UpdateSink, |
| VerifiedKeyFrame, |
| }; |
| use crate::rsne::Rsne; |
| use crate::state_machine::StateMachine; |
| use crate::Error; |
| use eapol; |
| use failure::{self, bail, ensure}; |
| use std::sync::{Arc, Mutex}; |
| |
| #[derive(Debug, PartialEq)] |
| pub enum MessageNumber { |
| Message1 = 1, |
| Message2 = 2, |
| Message3 = 3, |
| Message4 = 4, |
| } |
| |
| // Struct which carries EAPOL key frames which comply with IEEE Std 802.11-2016, 12.7.2 and |
| // IEEE Std 802.11-2016, 12.7.6. |
| pub struct FourwayHandshakeFrame<'a> { |
| frame: &'a eapol::KeyFrame, |
| } |
| |
| impl<'a> FourwayHandshakeFrame<'a> { |
| pub fn from_verified( |
| valid_frame: VerifiedKeyFrame<'a>, |
| role: Role, |
| nonce: Option<&[u8]>, |
| ) -> Result<FourwayHandshakeFrame<'a>, failure::Error> { |
| // Safe since the frame will be wrapped again in a `KeyFrameState` when being accessed. |
| let frame = valid_frame.get().unsafe_get_raw(); |
| |
| // Drop messages which were not expected by the configured role. |
| let msg_no = message_number(frame); |
| match role { |
| // Authenticator should only receive message 2 and 4. |
| Role::Authenticator => match msg_no { |
| MessageNumber::Message2 | MessageNumber::Message4 => {} |
| _ => bail!(Error::Unexpected4WayHandshakeMessage(msg_no)), |
| }, |
| Role::Supplicant => match msg_no { |
| MessageNumber::Message1 | MessageNumber::Message3 => {} |
| _ => bail!(Error::Unexpected4WayHandshakeMessage(msg_no)), |
| }, |
| }; |
| |
| // Explicit validation based on the frame's message number. |
| let msg_no = message_number(frame); |
| match msg_no { |
| MessageNumber::Message1 => validate_message_1(frame), |
| MessageNumber::Message2 => validate_message_2(frame), |
| MessageNumber::Message3 => validate_message_3(frame, nonce), |
| MessageNumber::Message4 => validate_message_4(frame), |
| }?; |
| |
| Ok(FourwayHandshakeFrame { frame }) |
| } |
| |
| pub fn get(&self) -> KeyFrameState<'a> { |
| KeyFrameState::from_frame(self.frame) |
| } |
| |
| pub fn get_key_data(&self) -> KeyFrameKeyDataState<'a> { |
| KeyFrameKeyDataState::from_frame(self.frame) |
| } |
| } |
| |
| #[derive(Debug, Clone)] |
| pub struct Config { |
| pub role: Role, |
| pub s_addr: [u8; 6], |
| pub s_rsne: Rsne, |
| pub a_addr: [u8; 6], |
| pub a_rsne: Rsne, |
| pub nonce_rdr: Arc<NonceReader>, |
| pub gtk_provider: Option<Arc<Mutex<GtkProvider>>>, |
| } |
| |
| impl Config { |
| pub fn new( |
| role: Role, |
| s_addr: [u8; 6], |
| s_rsne: Rsne, |
| a_addr: [u8; 6], |
| a_rsne: Rsne, |
| nonce_rdr: Arc<NonceReader>, |
| gtk_provider: Option<Arc<Mutex<GtkProvider>>>, |
| ) -> Result<Config, failure::Error> { |
| ensure!(role != Role::Authenticator || gtk_provider.is_some(), "GtkProvider is missing"); |
| ensure!(NegotiatedRsne::from_rsne(&s_rsne).is_ok(), "invalid s_rsne"); |
| |
| Ok(Config { role, s_addr, s_rsne, a_addr, a_rsne, nonce_rdr, gtk_provider }) |
| } |
| } |
| |
| impl PartialEq for Config { |
| fn eq(&self, other: &Config) -> bool { |
| self.role == other.role |
| && self.s_addr == other.s_addr |
| && self.s_rsne == other.s_rsne |
| && self.a_addr == other.a_addr |
| && self.a_rsne == other.a_rsne |
| } |
| } |
| |
| #[derive(Debug, PartialEq)] |
| pub enum Fourway { |
| Authenticator(StateMachine<authenticator::State>), |
| Supplicant(StateMachine<supplicant::State>), |
| } |
| |
| impl Fourway { |
| pub fn new(cfg: Config, pmk: Vec<u8>) -> Result<Fourway, failure::Error> { |
| let fourway = match &cfg.role { |
| Role::Supplicant => { |
| let state = supplicant::new(cfg, pmk); |
| Fourway::Supplicant(StateMachine::new(state)) |
| } |
| Role::Authenticator => { |
| let state = authenticator::new(cfg, pmk); |
| Fourway::Authenticator(StateMachine::new(state)) |
| } |
| }; |
| Ok(fourway) |
| } |
| |
| pub fn initiate( |
| &mut self, |
| update_sink: &mut Vec<SecAssocUpdate>, |
| key_replay_counter: u64, |
| ) -> Result<(), failure::Error> { |
| match self { |
| Fourway::Authenticator(state_machine) => { |
| state_machine |
| .replace_state(|state| state.initiate(update_sink, key_replay_counter)); |
| Ok(()) |
| } |
| // TODO(hahnr): Supplicant cannot initiate yet. |
| _ => Ok(()), |
| } |
| } |
| |
| pub fn on_eapol_key_frame( |
| &mut self, |
| update_sink: &mut UpdateSink, |
| key_replay_counter: u64, |
| frame: VerifiedKeyFrame, |
| ) -> Result<(), failure::Error> { |
| match self { |
| Fourway::Authenticator(state_machine) => { |
| let frame = FourwayHandshakeFrame::from_verified(frame, Role::Authenticator, None)?; |
| state_machine.replace_state(|state| { |
| state.on_eapol_key_frame(update_sink, key_replay_counter, frame) |
| }); |
| Ok(()) |
| } |
| Fourway::Supplicant(state_machine) => { |
| let anonce = state_machine.state().anonce(); |
| let frame = FourwayHandshakeFrame::from_verified(frame, Role::Supplicant, anonce)?; |
| state_machine.replace_state(|state| state.on_eapol_key_frame(update_sink, frame)); |
| Ok(()) |
| } |
| } |
| } |
| |
| pub fn destroy(self) -> exchange::Config { |
| let cfg = match self { |
| Fourway::Supplicant(state_machine) => state_machine.into_state().destroy(), |
| Fourway::Authenticator(state_machine) => state_machine.into_state().destroy(), |
| }; |
| exchange::Config::FourWayHandshake(cfg) |
| } |
| } |
| |
| // Verbose and explicit verification of Message 1 to 4 against IEEE Std 802.11-2016, 12.7.6.2. |
| |
| fn validate_message_1(frame: &eapol::KeyFrame) -> Result<(), failure::Error> { |
| // IEEE Std 802.11-2016, 12.7.2 b.4) |
| ensure!(!frame.key_info.install(), Error::InvalidInstallBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.5) |
| ensure!(frame.key_info.key_ack(), Error::InvalidKeyAckBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.6) |
| ensure!(!frame.key_info.key_mic(), Error::InvalidKeyMicBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.7) |
| ensure!(!frame.key_info.secure(), Error::InvalidSecureBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.8) |
| ensure!(!frame.key_info.error(), Error::InvalidErrorBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.9) |
| ensure!(!frame.key_info.request(), Error::InvalidRequestBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.10) |
| ensure!( |
| !frame.key_info.encrypted_key_data(), |
| Error::InvalidEncryptedKeyDataBitValue(message_number(frame)) |
| ); |
| // IEEE Std 802.11-2016, 12.7.2 e) |
| ensure!(!is_zero(&frame.key_nonce[..]), Error::InvalidNonce(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 f) |
| // IEEE Std 802.11-2016, 12.7.6.2 |
| ensure!(is_zero(&frame.key_iv[..]), Error::InvalidIv(frame.version, message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 g) |
| ensure!(frame.key_rsc == 0, Error::InvalidRsc(message_number(frame))); |
| |
| // The first message of the Handshake is also required to carry a zeroed MIC. |
| // Some routers however send messages without zeroing out the MIC beforehand. |
| // To ensure compatibility with such routers, the MIC of the first message is |
| // allowed to be set. |
| // This assumption faces no security risk because the message's MIC is only |
| // validated in the Handshake and not in the Supplicant or Authenticator |
| // implementation. |
| Ok(()) |
| } |
| |
| fn validate_message_2(frame: &eapol::KeyFrame) -> Result<(), failure::Error> { |
| // IEEE Std 802.11-2016, 12.7.2 b.4) |
| ensure!(!frame.key_info.install(), Error::InvalidInstallBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.5) |
| ensure!(!frame.key_info.key_ack(), Error::InvalidKeyAckBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.6) |
| ensure!(frame.key_info.key_mic(), Error::InvalidKeyMicBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.7) |
| ensure!(!frame.key_info.secure(), Error::InvalidSecureBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.8) |
| // Error bit only set by Supplicant in MIC failures in SMK derivation. |
| // SMK derivation not yet supported. |
| ensure!(!frame.key_info.error(), Error::InvalidErrorBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.9) |
| ensure!(!frame.key_info.request(), Error::InvalidRequestBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.10) |
| ensure!( |
| !frame.key_info.encrypted_key_data(), |
| Error::InvalidEncryptedKeyDataBitValue(message_number(frame)) |
| ); |
| // IEEE Std 802.11-2016, 12.7.2 e) |
| ensure!(!is_zero(&frame.key_nonce[..]), Error::InvalidNonce(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 f) |
| // IEEE Std 802.11-2016, 12.7.6.3 |
| ensure!(is_zero(&frame.key_iv[..]), Error::InvalidIv(frame.version, message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 g) |
| ensure!(frame.key_rsc == 0, Error::InvalidRsc(message_number(frame))); |
| |
| Ok(()) |
| } |
| |
| fn validate_message_3(frame: &eapol::KeyFrame, nonce: Option<&[u8]>) -> Result<(), failure::Error> { |
| // IEEE Std 802.11-2016, 12.7.2 b.4) |
| // Install = 0 is only used in key mapping with TKIP and WEP, neither is supported by Fuchsia. |
| ensure!(frame.key_info.install(), Error::InvalidInstallBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.5) |
| ensure!(frame.key_info.key_ack(), Error::InvalidKeyAckBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.6) |
| ensure!(frame.key_info.key_mic(), Error::InvalidKeyMicBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.7) |
| ensure!(frame.key_info.secure(), Error::InvalidSecureBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.8) |
| ensure!(!frame.key_info.error(), Error::InvalidErrorBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.9) |
| ensure!(!frame.key_info.request(), Error::InvalidRequestBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.10) |
| ensure!( |
| frame.key_info.encrypted_key_data(), |
| Error::InvalidEncryptedKeyDataBitValue(message_number(frame)) |
| ); |
| // IEEE Std 802.11-2016, 12.7.2 e) |
| if let Some(nonce) = nonce { |
| ensure!( |
| !is_zero(&frame.key_nonce[..]) && &frame.key_nonce[..] == nonce, |
| Error::InvalidNonce(message_number(frame)) |
| ); |
| } |
| // IEEE Std 802.11-2016, 12.7.2 f) |
| // IEEE Std 802.11-2016, 12.7.6.4 |
| // IEEE 802.11-2016 requires a zeroed IV for 802.1X-2004+ and allows random ones for older |
| // protocols. Some APs such as TP-Link violate this requirement and send non-zeroed IVs while |
| // using 802.1X-2004. For compatibility, random IVs are allowed for 802.1X-2004. |
| ensure!( |
| frame.version < eapol::ProtocolVersion::Ieee802dot1x2010 as u8 |
| || is_zero(&frame.key_iv[..]), |
| Error::InvalidIv(frame.version, message_number(frame)) |
| ); |
| // IEEE Std 802.11-2016, 12.7.2 i) & j) |
| // Key Data must not be empty. |
| ensure!(frame.key_data_len != 0, Error::EmptyKeyData(message_number(frame))); |
| |
| Ok(()) |
| } |
| |
| fn validate_message_4(frame: &eapol::KeyFrame) -> Result<(), failure::Error> { |
| // IEEE Std 802.11-2016, 12.7.2 b.4) |
| ensure!(!frame.key_info.install(), Error::InvalidInstallBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.5) |
| ensure!(!frame.key_info.key_ack(), Error::InvalidKeyAckBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.6) |
| ensure!(frame.key_info.key_mic(), Error::InvalidKeyMicBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.7) |
| ensure!(frame.key_info.secure(), Error::InvalidSecureBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.8) |
| // Error bit only set by Supplicant in MIC failures in SMK derivation. |
| // SMK derivation not yet supported. |
| ensure!(!frame.key_info.error(), Error::InvalidErrorBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.9) |
| ensure!(!frame.key_info.request(), Error::InvalidRequestBitValue(message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 b.10) |
| ensure!( |
| !frame.key_info.encrypted_key_data(), |
| Error::InvalidEncryptedKeyDataBitValue(message_number(frame)) |
| ); |
| // IEEE Std 802.11-2016, 12.7.2 f) |
| // IEEE Std 802.11-2016, 12.7.6.5 |
| ensure!(is_zero(&frame.key_iv[..]), Error::InvalidIv(frame.version, message_number(frame))); |
| // IEEE Std 802.11-2016, 12.7.2 g) |
| ensure!(frame.key_rsc == 0, Error::InvalidRsc(message_number(frame))); |
| |
| Ok(()) |
| } |
| |
| fn message_number(rx_frame: &eapol::KeyFrame) -> MessageNumber { |
| // IEEE does not specify how to determine a frame's message number in the 4-Way Handshake |
| // sequence. However, it's important to know a frame's message number to do further |
| // validations. To derive the message number the key info field is used. |
| // 4-Way Handshake specific EAPOL Key frame requirements: |
| // IEEE Std 802.11-2016, 12.7.6.1 |
| |
| // IEEE Std 802.11-2016, 12.7.6.2 & 12.7.6.4 |
| // Authenticator requires acknowledgement of all its sent frames. |
| if rx_frame.key_info.key_ack() { |
| // Authenticator only sends 1st and 3rd message of the handshake. |
| // IEEE Std 802.11-2016, 12.7.2 b.4) |
| // The third requires key installation while the first one doesn't. |
| if rx_frame.key_info.install() { |
| MessageNumber::Message3 |
| } else { |
| MessageNumber::Message1 |
| } |
| } else { |
| // Supplicant only sends 2nd and 4th message of the handshake. |
| // IEEE Std 802.11-2016, 12.7.2 b.7) |
| // The fourth message is secured while the second one is not. |
| if rx_frame.key_info.secure() { |
| MessageNumber::Message4 |
| } else { |
| MessageNumber::Message2 |
| } |
| } |
| } |
| |
| fn is_zero(slice: &[u8]) -> bool { |
| slice.iter().all(|&x| x == 0) |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use crate::rsna::test_util; |
| |
| // Create an Authenticator and Supplicant and perfoms the entire 4-Way Handshake. |
| #[test] |
| fn test_supplicant_with_authenticator() { |
| let mut env = test_util::FourwayTestEnv::new(); |
| |
| // Use arbitrarily chosen key_replay_counter. |
| let msg1 = env.initiate(12); |
| let (msg2, s_ptk) = env.send_msg1_to_supplicant(msg1, 12); |
| let (msg3, a_ptk) = env.send_msg2_to_authenticator(msg2, 12, 13); |
| let (msg4, s_gtk) = env.send_msg3_to_supplicant(msg3, 13); |
| let a_gtk = env.send_msg4_to_authenticator(msg4, 13); |
| |
| // Finally verify that Supplicant and Authenticator derived the same keys. |
| assert_eq!(s_ptk, a_ptk); |
| assert_eq!(s_gtk, a_gtk); |
| } |
| |
| // First messages of 4-Way Handshake must carry a zeroed IV in all protocol versions. |
| |
| #[test] |
| fn test_random_iv_msg1_v1() { |
| let mut env = test_util::FourwayTestEnv::new(); |
| |
| let mut msg1 = env.initiate(1); |
| msg1.version = 1; |
| msg1.key_iv = [0xFFu8; 16]; |
| env.send_msg1_to_supplicant_expect_err(msg1, 1); |
| } |
| |
| #[test] |
| fn test_random_iv_msg1_v2() { |
| let mut env = test_util::FourwayTestEnv::new(); |
| |
| let mut msg1 = env.initiate(1); |
| msg1.version = 2; |
| msg1.key_iv = [0xFFu8; 16]; |
| env.send_msg1_to_supplicant_expect_err(msg1, 1); |
| } |
| |
| // EAPOL Key frames can carry a random IV in the third message of the 4-Way Handshake if |
| // protocol version 1, 802.1X-2001, is used. All other protocol versions require a zeroed IV |
| // for the third message of the handshake. Some vendors violate this requirement. For |
| // compatibility, Fuchsia relaxes this requirement and allows random IVs with 802.1X-2004. |
| |
| #[test] |
| fn test_random_iv_msg3_v1() { |
| let mut env = test_util::FourwayTestEnv::new(); |
| |
| let msg1 = env.initiate(12); |
| let (msg2, s_ptk) = env.send_msg1_to_supplicant(msg1, 12); |
| let (mut msg3, a_ptk) = env.send_msg2_to_authenticator(msg2, 12, 13); |
| msg3.version = 1; |
| msg3.key_iv = [0xFFu8; 16]; |
| msg3 = test_util::finalize_key_frame(msg3, Some(a_ptk.kck())); |
| |
| let (msg4, s_gtk) = env.send_msg3_to_supplicant(msg3, 13); |
| let a_gtk = env.send_msg4_to_authenticator(msg4, 13); |
| |
| assert_eq!(s_ptk, a_ptk); |
| assert_eq!(s_gtk, a_gtk); |
| } |
| |
| #[test] |
| fn test_random_iv_msg3_v2() { |
| let mut env = test_util::FourwayTestEnv::new(); |
| |
| let msg1 = env.initiate(12); |
| let (msg2, s_ptk) = env.send_msg1_to_supplicant(msg1, 12); |
| let (mut msg3, a_ptk) = env.send_msg2_to_authenticator(msg2, 12, 13); |
| msg3.version = 2; |
| msg3.key_iv = [0xFFu8; 16]; |
| msg3 = test_util::finalize_key_frame(msg3, Some(a_ptk.kck())); |
| |
| let (msg4, s_gtk) = env.send_msg3_to_supplicant(msg3, 13); |
| let a_gtk = env.send_msg4_to_authenticator(msg4, 13); |
| |
| assert_eq!(s_ptk, a_ptk); |
| assert_eq!(s_gtk, a_gtk); |
| } |
| |
| #[test] |
| fn test_zeroed_iv_msg3_v2() { |
| let mut env = test_util::FourwayTestEnv::new(); |
| |
| let msg1 = env.initiate(12); |
| let (msg2, s_ptk) = env.send_msg1_to_supplicant(msg1, 12); |
| let (mut msg3, a_ptk) = env.send_msg2_to_authenticator(msg2, 12, 13); |
| msg3.version = 2; |
| msg3.key_iv = [0u8; 16]; |
| msg3 = test_util::finalize_key_frame(msg3, Some(a_ptk.kck())); |
| |
| let (msg4, s_gtk) = env.send_msg3_to_supplicant(msg3, 13); |
| let a_gtk = env.send_msg4_to_authenticator(msg4, 13); |
| |
| assert_eq!(s_ptk, a_ptk); |
| assert_eq!(s_gtk, a_gtk); |
| } |
| |
| #[test] |
| fn test_random_iv_msg3_v3() { |
| let mut env = test_util::FourwayTestEnv::new(); |
| |
| let msg1 = env.initiate(12); |
| let (msg2, _) = env.send_msg1_to_supplicant(msg1, 12); |
| let (mut msg3, a_ptk) = env.send_msg2_to_authenticator(msg2, 12, 13); |
| msg3.version = 3; |
| msg3.key_iv = [0xFFu8; 16]; |
| msg3 = test_util::finalize_key_frame(msg3, Some(a_ptk.kck())); |
| |
| env.send_msg3_to_supplicant_expect_err(msg3, 13); |
| } |
| } |