blob: 0c82d03a33ea97f9252a720fd58f26af306e6b4a [file] [log] [blame]
// 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.
use crate::integrity;
use crate::key::exchange::{
handshake::group_key::{self, Config, GroupKeyHandshakeFrame},
Key,
};
use crate::key::gtk::Gtk;
use crate::key_data;
use crate::rsna::{KeyFrameKeyDataState, KeyFrameState, SecAssocUpdate, UpdateSink};
use crate::Error;
use bytes::Bytes;
use eapol;
use failure::{self, bail};
#[derive(Debug, PartialEq)]
pub struct Supplicant {
pub cfg: group_key::Config,
pub kck: Bytes,
pub kek: Bytes,
}
impl Supplicant {
// IEEE Std 802.11-2016, 12.7.7.2
pub fn on_eapol_key_frame(
&mut self,
update_sink: &mut UpdateSink,
msg1: GroupKeyHandshakeFrame,
) -> Result<(), failure::Error> {
let frame = match &msg1.get() {
KeyFrameState::UnverifiedMic(unverified) => {
let frame = unverified.verify_mic(&self.kck[..], &self.cfg.akm)?;
frame
}
KeyFrameState::NoMic(_) => bail!("msg1 of Group-Key Handshake must carry a MIC"),
};
// Extract GTK from data.
let mut gtk: Option<key_data::kde::Gtk> = None;
let key_data = match &msg1.get_key_data() {
KeyFrameKeyDataState::Unencrypted(_) => {
bail!("msg1 of Group-Key Handshake must carry encrypted key data")
}
KeyFrameKeyDataState::Encrypted(encrypted) => {
encrypted.decrypt(&self.kek[..], &self.cfg.akm)?
}
};
let elements = key_data::extract_elements(&key_data[..])?;
for ele in elements {
match ele {
key_data::Element::Gtk(_, e) => gtk = Some(e),
_ => {}
}
}
let gtk = match gtk {
None => bail!("GTK KDE not present in key data of Group-Key Handshakes's 1st message"),
Some(gtk) => Gtk::from_gtk(gtk.gtk, gtk.info.key_id(), self.cfg.cipher.clone())?,
};
// Construct second message of handshake.
let msg2 = self.create_message_2(frame)?;
update_sink.push(SecAssocUpdate::TxEapolKeyFrame(msg2));
update_sink.push(SecAssocUpdate::Key(Key::Gtk(gtk)));
Ok(())
}
// IEEE Std 802.11-2016, 12.7.7.3
fn create_message_2(&self, msg1: &eapol::KeyFrame) -> Result<eapol::KeyFrame, failure::Error> {
let mut key_info = eapol::KeyInformation(0);
key_info.set_key_descriptor_version(msg1.key_info.key_descriptor_version());
key_info.set_key_type(msg1.key_info.key_type());
key_info.set_key_mic(true);
key_info.set_secure(true);
let mut msg2 = eapol::KeyFrame {
version: msg1.version,
packet_type: eapol::PacketType::Key as u8,
packet_body_len: 0, // Updated afterwards
descriptor_type: eapol::KeyDescriptor::Ieee802dot11 as u8,
key_info: key_info,
key_len: 0,
key_replay_counter: msg1.key_replay_counter,
key_nonce: [0u8; 32],
key_iv: [0u8; 16],
key_rsc: 0,
key_mic: Bytes::from(vec![0u8; msg1.key_mic.len()]),
key_data_len: 0,
key_data: Bytes::from(vec![]),
};
msg2.update_packet_body_len();
// Update the frame's MIC.
let akm = &self.cfg.akm;
let integrity_alg = akm.integrity_algorithm().ok_or(Error::UnsupportedAkmSuite)?;
let mic_len = akm.mic_bytes().ok_or(Error::UnsupportedAkmSuite)?;
update_mic(&self.kck[..], mic_len, integrity_alg, &mut msg2)?;
Ok(msg2)
}
pub fn destroy(self) -> Config {
self.cfg
}
}
fn update_mic(
kck: &[u8],
mic_len: u16,
alg: Box<integrity::Algorithm>,
frame: &mut eapol::KeyFrame,
) -> Result<(), failure::Error> {
let mut buf = Vec::with_capacity(frame.len());
frame.as_bytes(true, &mut buf);
let written = buf.len();
buf.truncate(written);
let mic = alg.compute(kck, &buf[..])?;
frame.key_mic = Bytes::from(&mic[..mic_len as usize]);
Ok(())
}